aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNarayan Kamath <narayan@google.com>2012-11-02 10:59:05 +0000
committerXiaotao Duan <xiaotao@google.com>2012-11-07 14:17:48 -0800
commitc981c48f5bc9aefeffc0bcb0cc3934c2fae179dd (patch)
tree54d1c7d66098154c1d7c5bd414394ef4cf255810
parent63f67d748682b46d58be31235a0a2d64d81b998c (diff)
downloadeigen-kitkat-release.tar.gz
Added a README.android and a MODULE_LICENSE_MPL2 file. Added empty Android.mk and CleanSpec.mk to optimize Android build. Non MPL2 license code is disabled in ./Eigen/src/Core/util/NonMPL2.h. Trying to include such files will lead to an error. Change-Id: I0e148b7c3e83999bcc4dfaa5809d33bfac2aac32
-rw-r--r--Android.mk16
-rw-r--r--CMakeLists.txt378
-rw-r--r--COPYING.BSD26
-rw-r--r--COPYING.GPL674
-rw-r--r--COPYING.LGPL165
-rw-r--r--COPYING.MINPACK52
-rw-r--r--COPYING.MPL2373
-rw-r--r--COPYING.README15
-rw-r--r--CTestConfig.cmake13
-rw-r--r--CTestCustom.cmake.in4
-rw-r--r--CleanSpec.mk52
-rw-r--r--Eigen/Array11
-rw-r--r--Eigen/CMakeLists.txt19
-rw-r--r--Eigen/Cholesky32
-rw-r--r--Eigen/CholmodSupport45
-rw-r--r--Eigen/Core366
-rw-r--r--Eigen/Dense7
-rw-r--r--Eigen/Eigen2
-rw-r--r--Eigen/Eigen2Support82
-rw-r--r--Eigen/Eigenvalues46
-rw-r--r--Eigen/Geometry63
-rw-r--r--Eigen/Householder23
-rw-r--r--Eigen/IterativeLinearSolvers40
-rw-r--r--Eigen/Jacobi26
-rw-r--r--Eigen/LU41
-rw-r--r--Eigen/LeastSquares32
-rw-r--r--Eigen/OrderingMethods23
-rw-r--r--Eigen/PaStiXSupport46
-rw-r--r--Eigen/PardisoSupport30
-rw-r--r--Eigen/QR45
-rw-r--r--Eigen/QtAlignedMalloc34
-rw-r--r--Eigen/SVD37
-rw-r--r--Eigen/Sparse23
-rw-r--r--Eigen/SparseCholesky30
-rw-r--r--Eigen/SparseCore66
-rw-r--r--Eigen/StdDeque27
-rw-r--r--Eigen/StdList26
-rw-r--r--Eigen/StdVector27
-rw-r--r--Eigen/SuperLUSupport59
-rw-r--r--Eigen/UmfPackSupport36
-rw-r--r--Eigen/src/CMakeLists.txt7
-rw-r--r--Eigen/src/Cholesky/CMakeLists.txt6
-rw-r--r--Eigen/src/Cholesky/LDLT.h592
-rw-r--r--Eigen/src/Cholesky/LLT.h488
-rw-r--r--Eigen/src/Cholesky/LLT_MKL.h102
-rw-r--r--Eigen/src/CholmodSupport/CMakeLists.txt6
-rw-r--r--Eigen/src/CholmodSupport/CholmodSupport.h579
-rw-r--r--Eigen/src/Core/Array.h308
-rw-r--r--Eigen/src/Core/ArrayBase.h228
-rw-r--r--Eigen/src/Core/ArrayWrapper.h240
-rw-r--r--Eigen/src/Core/Assign.h583
-rw-r--r--Eigen/src/Core/Assign_MKL.h224
-rw-r--r--Eigen/src/Core/BandMatrix.h334
-rw-r--r--Eigen/src/Core/Block.h357
-rw-r--r--Eigen/src/Core/BooleanRedux.h138
-rw-r--r--Eigen/src/Core/CMakeLists.txt10
-rw-r--r--Eigen/src/Core/CommaInitializer.h139
-rw-r--r--Eigen/src/Core/CwiseBinaryOp.h229
-rw-r--r--Eigen/src/Core/CwiseNullaryOp.h864
-rw-r--r--Eigen/src/Core/CwiseUnaryOp.h126
-rw-r--r--Eigen/src/Core/CwiseUnaryView.h135
-rw-r--r--Eigen/src/Core/DenseBase.h533
-rw-r--r--Eigen/src/Core/DenseCoeffsBase.h754
-rw-r--r--Eigen/src/Core/DenseStorage.h303
-rw-r--r--Eigen/src/Core/Diagonal.h236
-rw-r--r--Eigen/src/Core/DiagonalMatrix.h295
-rw-r--r--Eigen/src/Core/DiagonalProduct.h123
-rw-r--r--Eigen/src/Core/Dot.h261
-rw-r--r--Eigen/src/Core/EigenBase.h160
-rw-r--r--Eigen/src/Core/Flagged.h140
-rw-r--r--Eigen/src/Core/ForceAlignedAccess.h146
-rw-r--r--Eigen/src/Core/Functors.h989
-rw-r--r--Eigen/src/Core/Fuzzy.h150
-rw-r--r--Eigen/src/Core/GeneralProduct.h613
-rw-r--r--Eigen/src/Core/GenericPacketMath.h328
-rw-r--r--Eigen/src/Core/GlobalFunctions.h103
-rw-r--r--Eigen/src/Core/IO.h249
-rw-r--r--Eigen/src/Core/Map.h192
-rw-r--r--Eigen/src/Core/MapBase.h242
-rw-r--r--Eigen/src/Core/MathFunctions.h842
-rw-r--r--Eigen/src/Core/Matrix.h405
-rw-r--r--Eigen/src/Core/MatrixBase.h511
-rw-r--r--Eigen/src/Core/NestByValue.h111
-rw-r--r--Eigen/src/Core/NoAlias.h125
-rw-r--r--Eigen/src/Core/NumTraits.h147
-rw-r--r--Eigen/src/Core/PermutationMatrix.h687
-rw-r--r--Eigen/src/Core/PlainObjectBase.h767
-rw-r--r--Eigen/src/Core/Product.h98
-rw-r--r--Eigen/src/Core/ProductBase.h278
-rw-r--r--Eigen/src/Core/Random.h152
-rw-r--r--Eigen/src/Core/Redux.h406
-rw-r--r--Eigen/src/Core/Replicate.h177
-rw-r--r--Eigen/src/Core/ReturnByValue.h88
-rw-r--r--Eigen/src/Core/Reverse.h224
-rw-r--r--Eigen/src/Core/Select.h162
-rw-r--r--Eigen/src/Core/SelfAdjointView.h314
-rw-r--r--Eigen/src/Core/SelfCwiseBinaryOp.h194
-rw-r--r--Eigen/src/Core/SolveTriangular.h260
-rw-r--r--Eigen/src/Core/StableNorm.h179
-rw-r--r--Eigen/src/Core/Stride.h108
-rw-r--r--Eigen/src/Core/Swap.h126
-rw-r--r--Eigen/src/Core/Transpose.h414
-rw-r--r--Eigen/src/Core/Transpositions.h436
-rw-r--r--Eigen/src/Core/TriangularMatrix.h827
-rw-r--r--Eigen/src/Core/VectorBlock.h284
-rw-r--r--Eigen/src/Core/VectorwiseOp.h598
-rw-r--r--Eigen/src/Core/Visitor.h237
-rw-r--r--Eigen/src/Core/arch/AltiVec/CMakeLists.txt6
-rw-r--r--Eigen/src/Core/arch/AltiVec/Complex.h217
-rw-r--r--Eigen/src/Core/arch/AltiVec/PacketMath.h498
-rw-r--r--Eigen/src/Core/arch/CMakeLists.txt4
-rw-r--r--Eigen/src/Core/arch/Default/CMakeLists.txt6
-rw-r--r--Eigen/src/Core/arch/Default/Settings.h49
-rw-r--r--Eigen/src/Core/arch/NEON/CMakeLists.txt6
-rw-r--r--Eigen/src/Core/arch/NEON/Complex.h259
-rw-r--r--Eigen/src/Core/arch/NEON/PacketMath.h424
-rw-r--r--Eigen/src/Core/arch/SSE/CMakeLists.txt6
-rw-r--r--Eigen/src/Core/arch/SSE/Complex.h436
-rw-r--r--Eigen/src/Core/arch/SSE/MathFunctions.h384
-rw-r--r--Eigen/src/Core/arch/SSE/PacketMath.h632
-rw-r--r--Eigen/src/Core/products/CMakeLists.txt6
-rw-r--r--Eigen/src/Core/products/CoeffBasedProduct.h441
-rw-r--r--Eigen/src/Core/products/GeneralBlockPanelKernel.h1319
-rw-r--r--Eigen/src/Core/products/GeneralMatrixMatrix.h428
-rw-r--r--Eigen/src/Core/products/GeneralMatrixMatrixTriangular.h214
-rw-r--r--Eigen/src/Core/products/GeneralMatrixMatrixTriangular_MKL.h146
-rw-r--r--Eigen/src/Core/products/GeneralMatrixMatrix_MKL.h118
-rw-r--r--Eigen/src/Core/products/GeneralMatrixVector.h548
-rw-r--r--Eigen/src/Core/products/GeneralMatrixVector_MKL.h131
-rw-r--r--Eigen/src/Core/products/Parallelizer.h159
-rw-r--r--Eigen/src/Core/products/SelfadjointMatrixMatrix.h416
-rw-r--r--Eigen/src/Core/products/SelfadjointMatrixMatrix_MKL.h295
-rw-r--r--Eigen/src/Core/products/SelfadjointMatrixVector.h274
-rw-r--r--Eigen/src/Core/products/SelfadjointMatrixVector_MKL.h114
-rw-r--r--Eigen/src/Core/products/SelfadjointProduct.h125
-rw-r--r--Eigen/src/Core/products/SelfadjointRank2Update.h93
-rw-r--r--Eigen/src/Core/products/TriangularMatrixMatrix.h403
-rw-r--r--Eigen/src/Core/products/TriangularMatrixMatrix_MKL.h309
-rw-r--r--Eigen/src/Core/products/TriangularMatrixVector.h338
-rw-r--r--Eigen/src/Core/products/TriangularMatrixVector_MKL.h247
-rw-r--r--Eigen/src/Core/products/TriangularSolverMatrix.h317
-rw-r--r--Eigen/src/Core/products/TriangularSolverMatrix_MKL.h155
-rw-r--r--Eigen/src/Core/products/TriangularSolverVector.h139
-rw-r--r--Eigen/src/Core/util/BlasUtil.h264
-rw-r--r--Eigen/src/Core/util/CMakeLists.txt6
-rw-r--r--Eigen/src/Core/util/Constants.h431
-rw-r--r--Eigen/src/Core/util/DisableStupidWarnings.h40
-rw-r--r--Eigen/src/Core/util/ForwardDeclarations.h298
-rw-r--r--Eigen/src/Core/util/MKL_support.h109
-rw-r--r--Eigen/src/Core/util/Macros.h410
-rw-r--r--Eigen/src/Core/util/Memory.h952
-rw-r--r--Eigen/src/Core/util/Meta.h231
-rw-r--r--Eigen/src/Core/util/NonMPL2.h6
-rw-r--r--Eigen/src/Core/util/ReenableStupidWarnings.h14
-rw-r--r--Eigen/src/Core/util/StaticAssert.h205
-rw-r--r--Eigen/src/Core/util/XprHelper.h447
-rw-r--r--Eigen/src/Eigen2Support/Block.h126
-rw-r--r--Eigen/src/Eigen2Support/CMakeLists.txt8
-rw-r--r--Eigen/src/Eigen2Support/Cwise.h192
-rw-r--r--Eigen/src/Eigen2Support/CwiseOperators.h298
-rw-r--r--Eigen/src/Eigen2Support/Geometry/AlignedBox.h159
-rw-r--r--Eigen/src/Eigen2Support/Geometry/All.h115
-rw-r--r--Eigen/src/Eigen2Support/Geometry/AngleAxis.h214
-rw-r--r--Eigen/src/Eigen2Support/Geometry/CMakeLists.txt6
-rw-r--r--Eigen/src/Eigen2Support/Geometry/Hyperplane.h254
-rw-r--r--Eigen/src/Eigen2Support/Geometry/ParametrizedLine.h141
-rw-r--r--Eigen/src/Eigen2Support/Geometry/Quaternion.h495
-rw-r--r--Eigen/src/Eigen2Support/Geometry/Rotation2D.h145
-rw-r--r--Eigen/src/Eigen2Support/Geometry/RotationBase.h123
-rw-r--r--Eigen/src/Eigen2Support/Geometry/Scaling.h167
-rw-r--r--Eigen/src/Eigen2Support/Geometry/Transform.h786
-rw-r--r--Eigen/src/Eigen2Support/Geometry/Translation.h184
-rw-r--r--Eigen/src/Eigen2Support/LU.h120
-rw-r--r--Eigen/src/Eigen2Support/Lazy.h71
-rw-r--r--Eigen/src/Eigen2Support/LeastSquares.h170
-rw-r--r--Eigen/src/Eigen2Support/Macros.h20
-rw-r--r--Eigen/src/Eigen2Support/MathFunctions.h57
-rw-r--r--Eigen/src/Eigen2Support/Memory.h45
-rw-r--r--Eigen/src/Eigen2Support/Meta.h75
-rw-r--r--Eigen/src/Eigen2Support/Minor.h117
-rw-r--r--Eigen/src/Eigen2Support/QR.h67
-rw-r--r--Eigen/src/Eigen2Support/SVD.h638
-rw-r--r--Eigen/src/Eigen2Support/TriangularSolver.h42
-rw-r--r--Eigen/src/Eigen2Support/VectorBlock.h94
-rw-r--r--Eigen/src/Eigenvalues/CMakeLists.txt6
-rw-r--r--Eigen/src/Eigenvalues/ComplexEigenSolver.h319
-rw-r--r--Eigen/src/Eigenvalues/ComplexSchur.h396
-rw-r--r--Eigen/src/Eigenvalues/ComplexSchur_MKL.h94
-rw-r--r--Eigen/src/Eigenvalues/EigenSolver.h579
-rw-r--r--Eigen/src/Eigenvalues/GeneralizedSelfAdjointEigenSolver.h227
-rw-r--r--Eigen/src/Eigenvalues/HessenbergDecomposition.h373
-rw-r--r--Eigen/src/Eigenvalues/MatrixBaseEigenvalues.h159
-rw-r--r--Eigen/src/Eigenvalues/RealSchur.h464
-rw-r--r--Eigen/src/Eigenvalues/RealSchur_MKL.h83
-rw-r--r--Eigen/src/Eigenvalues/SelfAdjointEigenSolver.h789
-rw-r--r--Eigen/src/Eigenvalues/SelfAdjointEigenSolver_MKL.h92
-rw-r--r--Eigen/src/Eigenvalues/Tridiagonalization.h557
-rw-r--r--Eigen/src/Geometry/AlignedBox.h375
-rw-r--r--Eigen/src/Geometry/AngleAxis.h230
-rw-r--r--Eigen/src/Geometry/CMakeLists.txt8
-rw-r--r--Eigen/src/Geometry/EulerAngles.h84
-rw-r--r--Eigen/src/Geometry/Homogeneous.h307
-rw-r--r--Eigen/src/Geometry/Hyperplane.h269
-rw-r--r--Eigen/src/Geometry/OrthoMethods.h218
-rw-r--r--Eigen/src/Geometry/ParametrizedLine.h195
-rw-r--r--Eigen/src/Geometry/Quaternion.h778
-rw-r--r--Eigen/src/Geometry/Rotation2D.h154
-rw-r--r--Eigen/src/Geometry/RotationBase.h206
-rw-r--r--Eigen/src/Geometry/Scaling.h166
-rw-r--r--Eigen/src/Geometry/Transform.h1440
-rw-r--r--Eigen/src/Geometry/Translation.h206
-rw-r--r--Eigen/src/Geometry/Umeyama.h172
-rw-r--r--Eigen/src/Geometry/arch/CMakeLists.txt6
-rw-r--r--Eigen/src/Geometry/arch/Geometry_SSE.h115
-rw-r--r--Eigen/src/Householder/BlockHouseholder.h68
-rw-r--r--Eigen/src/Householder/CMakeLists.txt6
-rw-r--r--Eigen/src/Householder/Householder.h168
-rw-r--r--Eigen/src/Householder/HouseholderSequence.h441
-rw-r--r--Eigen/src/IterativeLinearSolvers/BasicPreconditioners.h149
-rw-r--r--Eigen/src/IterativeLinearSolvers/BiCGSTAB.h254
-rw-r--r--Eigen/src/IterativeLinearSolvers/CMakeLists.txt6
-rw-r--r--Eigen/src/IterativeLinearSolvers/ConjugateGradient.h251
-rw-r--r--Eigen/src/IterativeLinearSolvers/IncompleteLUT.h466
-rw-r--r--Eigen/src/IterativeLinearSolvers/IterativeSolverBase.h254
-rw-r--r--Eigen/src/Jacobi/CMakeLists.txt6
-rw-r--r--Eigen/src/Jacobi/Jacobi.h420
-rw-r--r--Eigen/src/LU/CMakeLists.txt8
-rw-r--r--Eigen/src/LU/Determinant.h101
-rw-r--r--Eigen/src/LU/FullPivLU.h736
-rw-r--r--Eigen/src/LU/Inverse.h396
-rw-r--r--Eigen/src/LU/PartialPivLU.h498
-rw-r--r--Eigen/src/LU/PartialPivLU_MKL.h85
-rw-r--r--Eigen/src/LU/arch/CMakeLists.txt6
-rw-r--r--Eigen/src/LU/arch/Inverse_SSE.h329
-rw-r--r--Eigen/src/OrderingMethods/Amd.h439
-rw-r--r--Eigen/src/OrderingMethods/CMakeLists.txt6
-rw-r--r--Eigen/src/PaStiXSupport/CMakeLists.txt6
-rw-r--r--Eigen/src/PaStiXSupport/PaStiXSupport.h742
-rw-r--r--Eigen/src/PardisoSupport/CMakeLists.txt6
-rw-r--r--Eigen/src/PardisoSupport/PardisoSupport.h614
-rw-r--r--Eigen/src/QR/CMakeLists.txt6
-rw-r--r--Eigen/src/QR/ColPivHouseholderQR.h520
-rw-r--r--Eigen/src/QR/ColPivHouseholderQR_MKL.h98
-rw-r--r--Eigen/src/QR/FullPivHouseholderQR.h594
-rw-r--r--Eigen/src/QR/HouseholderQR.h343
-rw-r--r--Eigen/src/QR/HouseholderQR_MKL.h69
-rw-r--r--Eigen/src/SVD/CMakeLists.txt6
-rw-r--r--Eigen/src/SVD/JacobiSVD.h867
-rw-r--r--Eigen/src/SVD/JacobiSVD_MKL.h92
-rw-r--r--Eigen/src/SVD/UpperBidiagonalization.h148
-rw-r--r--Eigen/src/SparseCholesky/CMakeLists.txt6
-rw-r--r--Eigen/src/SparseCholesky/SimplicialCholesky.h873
-rw-r--r--Eigen/src/SparseCore/AmbiVector.h371
-rw-r--r--Eigen/src/SparseCore/CMakeLists.txt6
-rw-r--r--Eigen/src/SparseCore/CompressedStorage.h233
-rw-r--r--Eigen/src/SparseCore/ConservativeSparseSparseProduct.h245
-rw-r--r--Eigen/src/SparseCore/CoreIterators.h61
-rw-r--r--Eigen/src/SparseCore/MappedSparseMatrix.h179
-rw-r--r--Eigen/src/SparseCore/SparseAssign.h0
-rw-r--r--Eigen/src/SparseCore/SparseBlock.h387
-rw-r--r--Eigen/src/SparseCore/SparseCwiseBinaryOp.h324
-rw-r--r--Eigen/src/SparseCore/SparseCwiseUnaryOp.h163
-rw-r--r--Eigen/src/SparseCore/SparseDenseProduct.h300
-rw-r--r--Eigen/src/SparseCore/SparseDiagonalProduct.h184
-rw-r--r--Eigen/src/SparseCore/SparseDot.h94
-rw-r--r--Eigen/src/SparseCore/SparseFuzzy.h26
-rw-r--r--Eigen/src/SparseCore/SparseMatrix.h1116
-rw-r--r--Eigen/src/SparseCore/SparseMatrixBase.h458
-rw-r--r--Eigen/src/SparseCore/SparsePermutation.h148
-rw-r--r--Eigen/src/SparseCore/SparseProduct.h186
-rw-r--r--Eigen/src/SparseCore/SparseRedux.h45
-rw-r--r--Eigen/src/SparseCore/SparseSelfAdjointView.h480
-rw-r--r--Eigen/src/SparseCore/SparseSparseProductWithPruning.h149
-rw-r--r--Eigen/src/SparseCore/SparseTranspose.h61
-rw-r--r--Eigen/src/SparseCore/SparseTriangularView.h164
-rw-r--r--Eigen/src/SparseCore/SparseUtil.h173
-rw-r--r--Eigen/src/SparseCore/SparseVector.h398
-rw-r--r--Eigen/src/SparseCore/SparseView.h98
-rw-r--r--Eigen/src/SparseCore/TriangularSolver.h334
-rw-r--r--Eigen/src/StlSupport/CMakeLists.txt6
-rw-r--r--Eigen/src/StlSupport/StdDeque.h134
-rw-r--r--Eigen/src/StlSupport/StdList.h114
-rw-r--r--Eigen/src/StlSupport/StdVector.h126
-rw-r--r--Eigen/src/StlSupport/details.h84
-rw-r--r--Eigen/src/SuperLUSupport/CMakeLists.txt6
-rw-r--r--Eigen/src/SuperLUSupport/SuperLUSupport.h1025
-rw-r--r--Eigen/src/UmfPackSupport/CMakeLists.txt6
-rw-r--r--Eigen/src/UmfPackSupport/UmfPackSupport.h431
-rw-r--r--Eigen/src/misc/CMakeLists.txt6
-rw-r--r--Eigen/src/misc/Image.h84
-rw-r--r--Eigen/src/misc/Kernel.h81
-rw-r--r--Eigen/src/misc/Solve.h76
-rw-r--r--Eigen/src/misc/SparseSolve.h111
-rw-r--r--Eigen/src/misc/blas.h658
-rw-r--r--Eigen/src/plugins/ArrayCwiseBinaryOps.h199
-rw-r--r--Eigen/src/plugins/ArrayCwiseUnaryOps.h202
-rw-r--r--Eigen/src/plugins/BlockMethods.h580
-rw-r--r--Eigen/src/plugins/CMakeLists.txt6
-rw-r--r--Eigen/src/plugins/CommonCwiseBinaryOps.h46
-rw-r--r--Eigen/src/plugins/CommonCwiseUnaryOps.h172
-rw-r--r--Eigen/src/plugins/MatrixCwiseBinaryOps.h126
-rw-r--r--Eigen/src/plugins/MatrixCwiseUnaryOps.h67
-rw-r--r--INSTALL35
-rw-r--r--MODULE_LICENSE_MPL20
-rw-r--r--README.android13
-rw-r--r--bench/BenchSparseUtil.h149
-rw-r--r--bench/BenchTimer.h187
-rw-r--r--bench/BenchUtil.h92
-rw-r--r--bench/README.txt55
-rw-r--r--bench/basicbench.cxxlist28
-rw-r--r--bench/basicbenchmark.cpp35
-rw-r--r--bench/basicbenchmark.h63
-rw-r--r--bench/benchBlasGemm.cpp219
-rw-r--r--bench/benchCholesky.cpp142
-rw-r--r--bench/benchEigenSolver.cpp212
-rw-r--r--bench/benchFFT.cpp115
-rw-r--r--bench/benchVecAdd.cpp135
-rw-r--r--bench/bench_gemm.cpp271
-rwxr-xr-xbench/bench_multi_compilers.sh28
-rw-r--r--bench/bench_norm.cpp345
-rw-r--r--bench/bench_reverse.cpp84
-rw-r--r--bench/bench_sum.cpp18
-rwxr-xr-xbench/bench_unrolling12
-rw-r--r--bench/benchmark.cpp39
-rw-r--r--bench/benchmarkSlice.cpp38
-rw-r--r--bench/benchmarkX.cpp36
-rw-r--r--bench/benchmarkXcwise.cpp35
-rwxr-xr-xbench/benchmark_suite18
-rw-r--r--bench/btl/CMakeLists.txt104
-rw-r--r--bench/btl/COPYING340
-rw-r--r--bench/btl/README154
-rw-r--r--bench/btl/actions/action_aat_product.hh145
-rw-r--r--bench/btl/actions/action_ata_product.hh145
-rw-r--r--bench/btl/actions/action_atv_product.hh134
-rw-r--r--bench/btl/actions/action_axpby.hh127
-rw-r--r--bench/btl/actions/action_axpy.hh139
-rw-r--r--bench/btl/actions/action_cholesky.hh128
-rw-r--r--bench/btl/actions/action_ger.hh128
-rw-r--r--bench/btl/actions/action_hessenberg.hh233
-rw-r--r--bench/btl/actions/action_lu_decomp.hh124
-rw-r--r--bench/btl/actions/action_lu_solve.hh136
-rw-r--r--bench/btl/actions/action_matrix_matrix_product.hh150
-rw-r--r--bench/btl/actions/action_matrix_matrix_product_bis.hh152
-rw-r--r--bench/btl/actions/action_matrix_vector_product.hh153
-rw-r--r--bench/btl/actions/action_partial_lu.hh125
-rw-r--r--bench/btl/actions/action_rot.hh116
-rw-r--r--bench/btl/actions/action_symv.hh139
-rw-r--r--bench/btl/actions/action_syr2.hh133
-rw-r--r--bench/btl/actions/action_trisolve.hh137
-rw-r--r--bench/btl/actions/action_trisolve_matrix.hh165
-rw-r--r--bench/btl/actions/action_trmm.hh165
-rw-r--r--bench/btl/actions/basic_actions.hh21
-rw-r--r--bench/btl/cmake/FindACML.cmake49
-rw-r--r--bench/btl/cmake/FindATLAS.cmake39
-rw-r--r--bench/btl/cmake/FindBlitz.cmake40
-rw-r--r--bench/btl/cmake/FindCBLAS.cmake34
-rw-r--r--bench/btl/cmake/FindGMM.cmake17
-rw-r--r--bench/btl/cmake/FindGOTO.cmake15
-rw-r--r--bench/btl/cmake/FindGOTO2.cmake25
-rw-r--r--bench/btl/cmake/FindMKL.cmake65
-rw-r--r--bench/btl/cmake/FindMTL4.cmake31
-rw-r--r--bench/btl/cmake/FindPackageHandleStandardArgs.cmake60
-rw-r--r--bench/btl/cmake/FindTvmet.cmake32
-rw-r--r--bench/btl/cmake/MacroOptionalAddSubdirectory.cmake31
-rw-r--r--bench/btl/data/CMakeLists.txt32
-rw-r--r--bench/btl/data/action_settings.txt19
-rw-r--r--bench/btl/data/gnuplot_common_settings.hh87
-rwxr-xr-xbench/btl/data/go_mean58
-rw-r--r--bench/btl/data/mean.cxx182
-rw-r--r--bench/btl/data/mk_gnuplot_script.sh68
-rw-r--r--bench/btl/data/mk_mean_script.sh52
-rwxr-xr-xbench/btl/data/mk_new_gnuplot.sh54
-rw-r--r--bench/btl/data/perlib_plot_settings.txt16
-rw-r--r--bench/btl/data/regularize.cxx131
-rw-r--r--bench/btl/data/smooth.cxx198
-rwxr-xr-xbench/btl/data/smooth_all.sh68
-rw-r--r--bench/btl/generic_bench/bench.hh168
-rw-r--r--bench/btl/generic_bench/bench_parameter.hh53
-rw-r--r--bench/btl/generic_bench/btl.hh247
-rw-r--r--bench/btl/generic_bench/init/init_function.hh54
-rw-r--r--bench/btl/generic_bench/init/init_matrix.hh64
-rw-r--r--bench/btl/generic_bench/init/init_vector.hh37
-rw-r--r--bench/btl/generic_bench/static/bench_static.hh80
-rw-r--r--bench/btl/generic_bench/static/intel_bench_fixed_size.hh66
-rw-r--r--bench/btl/generic_bench/static/static_size_generator.hh57
-rw-r--r--bench/btl/generic_bench/timers/STL_perf_analyzer.hh82
-rw-r--r--bench/btl/generic_bench/timers/STL_timer.hh78
-rw-r--r--bench/btl/generic_bench/timers/mixed_perf_analyzer.hh73
-rw-r--r--bench/btl/generic_bench/timers/portable_perf_analyzer.hh103
-rw-r--r--bench/btl/generic_bench/timers/portable_perf_analyzer_old.hh134
-rwxr-xr-xbench/btl/generic_bench/timers/portable_timer.hh145
-rw-r--r--bench/btl/generic_bench/timers/x86_perf_analyzer.hh108
-rw-r--r--bench/btl/generic_bench/timers/x86_timer.hh246
-rw-r--r--bench/btl/generic_bench/utils/size_lin_log.hh70
-rw-r--r--bench/btl/generic_bench/utils/size_log.hh54
-rw-r--r--bench/btl/generic_bench/utils/utilities.h90
-rw-r--r--bench/btl/generic_bench/utils/xy_file.hh75
-rw-r--r--bench/btl/libs/BLAS/CMakeLists.txt60
-rw-r--r--bench/btl/libs/BLAS/blas.h675
-rw-r--r--bench/btl/libs/BLAS/blas_interface.hh83
-rw-r--r--bench/btl/libs/BLAS/blas_interface_impl.hh151
-rw-r--r--bench/btl/libs/BLAS/c_interface_base.h73
-rw-r--r--bench/btl/libs/BLAS/main.cpp73
-rw-r--r--bench/btl/libs/STL/CMakeLists.txt2
-rw-r--r--bench/btl/libs/STL/STL_interface.hh244
-rw-r--r--bench/btl/libs/STL/main.cpp42
-rw-r--r--bench/btl/libs/blitz/CMakeLists.txt17
-rw-r--r--bench/btl/libs/blitz/blitz_LU_solve_interface.hh192
-rw-r--r--bench/btl/libs/blitz/blitz_interface.hh147
-rw-r--r--bench/btl/libs/blitz/btl_blitz.cpp51
-rw-r--r--bench/btl/libs/blitz/btl_tiny_blitz.cpp38
-rw-r--r--bench/btl/libs/blitz/tiny_blitz_interface.hh106
-rw-r--r--bench/btl/libs/eigen2/CMakeLists.txt19
-rw-r--r--bench/btl/libs/eigen2/btl_tiny_eigen2.cpp46
-rw-r--r--bench/btl/libs/eigen2/eigen2_interface.hh168
-rw-r--r--bench/btl/libs/eigen2/main_adv.cpp44
-rw-r--r--bench/btl/libs/eigen2/main_linear.cpp34
-rw-r--r--bench/btl/libs/eigen2/main_matmat.cpp35
-rw-r--r--bench/btl/libs/eigen2/main_vecmat.cpp36
-rw-r--r--bench/btl/libs/eigen3/CMakeLists.txt65
-rw-r--r--bench/btl/libs/eigen3/btl_tiny_eigen3.cpp46
-rw-r--r--bench/btl/libs/eigen3/eigen3_interface.hh240
-rw-r--r--bench/btl/libs/eigen3/main_adv.cpp44
-rw-r--r--bench/btl/libs/eigen3/main_linear.cpp35
-rw-r--r--bench/btl/libs/eigen3/main_matmat.cpp35
-rw-r--r--bench/btl/libs/eigen3/main_vecmat.cpp36
-rw-r--r--bench/btl/libs/gmm/CMakeLists.txt6
-rw-r--r--bench/btl/libs/gmm/gmm_LU_solve_interface.hh192
-rw-r--r--bench/btl/libs/gmm/gmm_interface.hh144
-rw-r--r--bench/btl/libs/gmm/main.cpp51
-rw-r--r--bench/btl/libs/mtl4/.kdbgrc.main12
-rw-r--r--bench/btl/libs/mtl4/CMakeLists.txt6
-rw-r--r--bench/btl/libs/mtl4/main.cpp46
-rw-r--r--bench/btl/libs/mtl4/mtl4_LU_solve_interface.hh192
-rw-r--r--bench/btl/libs/mtl4/mtl4_interface.hh144
-rw-r--r--bench/btl/libs/tvmet/CMakeLists.txt6
-rw-r--r--bench/btl/libs/tvmet/main.cpp40
-rw-r--r--bench/btl/libs/tvmet/tvmet_interface.hh104
-rw-r--r--bench/btl/libs/ublas/CMakeLists.txt7
-rw-r--r--bench/btl/libs/ublas/main.cpp44
-rw-r--r--bench/btl/libs/ublas/ublas_interface.hh141
-rw-r--r--bench/check_cache_queries.cpp101
-rw-r--r--bench/eig33.cpp196
-rw-r--r--bench/geometry.cpp126
-rw-r--r--bench/product_threshold.cpp143
-rw-r--r--bench/quat_slerp.cpp247
-rw-r--r--bench/quatmul.cpp47
-rw-r--r--bench/sparse_cholesky.cpp216
-rw-r--r--bench/sparse_dense_product.cpp187
-rw-r--r--bench/sparse_lu.cpp132
-rw-r--r--bench/sparse_product.cpp323
-rw-r--r--bench/sparse_randomsetter.cpp125
-rw-r--r--bench/sparse_setter.cpp485
-rw-r--r--bench/sparse_transpose.cpp104
-rw-r--r--bench/sparse_trisolver.cpp220
-rw-r--r--bench/spbench/CMakeLists.txt65
-rw-r--r--bench/spbench/spbenchsolver.cpp90
-rw-r--r--bench/spbench/spbenchsolver.h533
-rw-r--r--bench/spmv.cpp233
-rw-r--r--bench/vdw_new.cpp56
-rw-r--r--blas/BandTriangularSolver.h97
-rw-r--r--blas/CMakeLists.txt57
-rw-r--r--blas/README.txt9
-rw-r--r--blas/chbmv.f310
-rw-r--r--blas/chpmv.f272
-rw-r--r--blas/chpr.f220
-rw-r--r--blas/chpr2.f255
-rw-r--r--blas/common.h140
-rw-r--r--blas/complex_double.cpp20
-rw-r--r--blas/complex_single.cpp20
-rw-r--r--blas/complexdots.f43
-rw-r--r--blas/ctbmv.f366
-rw-r--r--blas/ctpmv.f329
-rw-r--r--blas/ctpsv.f332
-rw-r--r--blas/double.cpp19
-rw-r--r--blas/drotm.f147
-rw-r--r--blas/drotmg.f206
-rw-r--r--blas/dsbmv.f304
-rw-r--r--blas/dspmv.f265
-rw-r--r--blas/dspr.f202
-rw-r--r--blas/dspr2.f233
-rw-r--r--blas/dtbmv.f335
-rw-r--r--blas/dtpmv.f293
-rw-r--r--blas/dtpsv.f296
-rw-r--r--blas/level1_cplx_impl.h127
-rw-r--r--blas/level1_impl.h164
-rw-r--r--blas/level1_real_impl.h100
-rw-r--r--blas/level2_cplx_impl.h270
-rw-r--r--blas/level2_impl.h457
-rw-r--r--blas/level2_real_impl.h210
-rw-r--r--blas/level3_impl.h632
-rw-r--r--blas/lsame.f85
-rw-r--r--blas/single.cpp19
-rw-r--r--blas/srotm.f148
-rw-r--r--blas/srotmg.f208
-rw-r--r--blas/ssbmv.f306
-rw-r--r--blas/sspmv.f265
-rw-r--r--blas/sspr.f202
-rw-r--r--blas/sspr2.f233
-rw-r--r--blas/stbmv.f335
-rw-r--r--blas/stpmv.f293
-rw-r--r--blas/stpsv.f296
-rw-r--r--blas/testing/CMakeLists.txt40
-rw-r--r--blas/testing/cblat1.f681
-rw-r--r--blas/testing/cblat2.dat35
-rw-r--r--blas/testing/cblat2.f3241
-rw-r--r--blas/testing/cblat3.dat23
-rw-r--r--blas/testing/cblat3.f3439
-rw-r--r--blas/testing/dblat1.f769
-rw-r--r--blas/testing/dblat2.dat34
-rw-r--r--blas/testing/dblat2.f3138
-rw-r--r--blas/testing/dblat3.dat20
-rw-r--r--blas/testing/dblat3.f2823
-rwxr-xr-xblas/testing/runblastest.sh45
-rw-r--r--blas/testing/sblat1.f769
-rw-r--r--blas/testing/sblat2.dat34
-rw-r--r--blas/testing/sblat2.f3138
-rw-r--r--blas/testing/sblat3.dat20
-rw-r--r--blas/testing/sblat3.f2823
-rw-r--r--blas/testing/zblat1.f681
-rw-r--r--blas/testing/zblat2.dat35
-rw-r--r--blas/testing/zblat2.f3249
-rw-r--r--blas/testing/zblat3.dat23
-rw-r--r--blas/testing/zblat3.f3445
-rw-r--r--blas/xerbla.cpp23
-rw-r--r--blas/zhbmv.f310
-rw-r--r--blas/zhpmv.f272
-rw-r--r--blas/zhpr.f220
-rw-r--r--blas/zhpr2.f255
-rw-r--r--blas/ztbmv.f366
-rw-r--r--blas/ztpmv.f329
-rw-r--r--blas/ztpsv.f332
-rw-r--r--cmake/CMakeDetermineVSServicePack.cmake103
-rw-r--r--cmake/EigenConfigureTesting.cmake79
-rw-r--r--cmake/EigenDetermineOSVersion.cmake46
-rw-r--r--cmake/EigenTesting.cmake477
-rw-r--r--cmake/FindAdolc.cmake20
-rw-r--r--cmake/FindBLAS.cmake419
-rw-r--r--cmake/FindCholmod.cmake80
-rw-r--r--cmake/FindEigen2.cmake80
-rw-r--r--cmake/FindEigen3.cmake81
-rw-r--r--cmake/FindFFTW.cmake119
-rw-r--r--cmake/FindGLEW.cmake105
-rw-r--r--cmake/FindGMP.cmake21
-rw-r--r--cmake/FindGSL.cmake170
-rw-r--r--cmake/FindGoogleHash.cmake23
-rw-r--r--cmake/FindLAPACK.cmake273
-rw-r--r--cmake/FindMPFR.cmake83
-rw-r--r--cmake/FindMetis.cmake24
-rw-r--r--cmake/FindPastix.cmake25
-rw-r--r--cmake/FindScotch.cmake24
-rw-r--r--cmake/FindStandardMathLibrary.cmake64
-rw-r--r--cmake/FindSuperLU.cmake25
-rw-r--r--cmake/FindUmfpack.cmake50
-rw-r--r--cmake/RegexUtils.cmake19
-rw-r--r--cmake/language_support.cmake64
-rw-r--r--debug/gdb/__init__.py1
-rw-r--r--debug/gdb/printers.py208
-rw-r--r--debug/msvc/eigen_autoexp_part.dat295
-rw-r--r--demos/CMakeLists.txt13
-rw-r--r--demos/mandelbrot/CMakeLists.txt21
-rw-r--r--demos/mandelbrot/README10
-rw-r--r--demos/mandelbrot/mandelbrot.cpp213
-rw-r--r--demos/mandelbrot/mandelbrot.h71
-rw-r--r--demos/mix_eigen_and_c/README9
-rw-r--r--demos/mix_eigen_and_c/binary_library.cpp185
-rw-r--r--demos/mix_eigen_and_c/binary_library.h71
-rw-r--r--demos/mix_eigen_and_c/example.c65
-rw-r--r--demos/opengl/CMakeLists.txt20
-rw-r--r--demos/opengl/README13
-rw-r--r--demos/opengl/camera.cpp264
-rw-r--r--demos/opengl/camera.h118
-rw-r--r--demos/opengl/gpuhelper.cpp126
-rw-r--r--demos/opengl/gpuhelper.h207
-rw-r--r--demos/opengl/icosphere.cpp120
-rw-r--r--demos/opengl/icosphere.h30
-rw-r--r--demos/opengl/quaternion_demo.cpp656
-rw-r--r--demos/opengl/quaternion_demo.h114
-rw-r--r--demos/opengl/trackball.cpp59
-rw-r--r--demos/opengl/trackball.h42
-rw-r--r--doc/A05_PortingFrom2To3.dox319
-rw-r--r--doc/A10_Eigen2SupportModes.dox101
-rw-r--r--doc/AsciiQuickReference.txt170
-rw-r--r--doc/B01_Experimental.dox55
-rw-r--r--doc/C00_QuickStartGuide.dox99
-rw-r--r--doc/C01_TutorialMatrixClass.dox284
-rw-r--r--doc/C02_TutorialMatrixArithmetic.dox229
-rw-r--r--doc/C03_TutorialArrayClass.dox205
-rw-r--r--doc/C04_TutorialBlockOperations.dox239
-rw-r--r--doc/C05_TutorialAdvancedInitialization.dox172
-rw-r--r--doc/C06_TutorialLinearAlgebra.dox269
-rw-r--r--doc/C07_TutorialReductionsVisitorsBroadcasting.dox273
-rw-r--r--doc/C08_TutorialGeometry.dox251
-rw-r--r--doc/C09_TutorialSparse.dox455
-rw-r--r--doc/C10_TutorialMapClass.dox96
-rw-r--r--doc/CMakeLists.txt78
-rw-r--r--doc/D01_StlContainers.dox65
-rw-r--r--doc/D03_WrongStackAlignment.dox56
-rw-r--r--doc/D07_PassingByValue.dox40
-rw-r--r--doc/D09_StructHavingEigenMembers.dox198
-rw-r--r--doc/D11_UnalignedArrayAssert.dox121
-rw-r--r--doc/Doxyfile.in1484
-rw-r--r--doc/Eigen_Silly_Professor_64x64.pngbin0 -> 8355 bytes
-rw-r--r--doc/I00_CustomizingEigen.dox191
-rw-r--r--doc/I01_TopicLazyEvaluation.dox65
-rw-r--r--doc/I02_HiPerformance.dox128
-rw-r--r--doc/I03_InsideEigenExample.dox500
-rw-r--r--doc/I05_FixedSizeVectorizable.dox38
-rw-r--r--doc/I06_TopicEigenExpressionTemplates.dox12
-rw-r--r--doc/I07_TopicScalarTypes.dox12
-rw-r--r--doc/I08_Resizing.dox11
-rw-r--r--doc/I09_Vectorization.dox9
-rw-r--r--doc/I10_Assertions.dox13
-rw-r--r--doc/I11_Aliasing.dox214
-rw-r--r--doc/I12_ClassHierarchy.dox133
-rw-r--r--doc/I13_FunctionsTakingEigenTypes.dox188
-rw-r--r--doc/I14_PreprocessorDirectives.dox112
-rw-r--r--doc/I15_StorageOrders.dox89
-rw-r--r--doc/I16_TemplateKeyword.dox136
-rw-r--r--doc/Overview.dox60
-rw-r--r--doc/QuickReference.dox737
-rw-r--r--doc/SparseQuickReference.dox198
-rw-r--r--doc/TopicLinearAlgebraDecompositions.dox260
-rw-r--r--doc/TopicMultithreading.dox46
-rw-r--r--doc/TutorialSparse_example_details.dox4
-rw-r--r--doc/UsingIntelMKL.dox168
-rw-r--r--doc/eigendoxy.css911
-rw-r--r--doc/eigendoxy_footer.html.in5
-rw-r--r--doc/eigendoxy_header.html.in14
-rw-r--r--doc/eigendoxy_tabs.css59
-rw-r--r--doc/examples/.krazy2
-rw-r--r--doc/examples/CMakeLists.txt20
-rw-r--r--doc/examples/DenseBase_middleCols_int.cpp15
-rw-r--r--doc/examples/DenseBase_middleRows_int.cpp15
-rw-r--r--doc/examples/DenseBase_template_int_middleCols.cpp15
-rw-r--r--doc/examples/DenseBase_template_int_middleRows.cpp15
-rw-r--r--doc/examples/MatrixBase_cwise_const.cpp18
-rw-r--r--doc/examples/QuickStart_example.cpp14
-rw-r--r--doc/examples/QuickStart_example2_dynamic.cpp15
-rw-r--r--doc/examples/QuickStart_example2_fixed.cpp15
-rw-r--r--doc/examples/TemplateKeyword_flexible.cpp22
-rw-r--r--doc/examples/TemplateKeyword_simple.cpp20
-rw-r--r--doc/examples/TutorialLinAlgComputeTwice.cpp23
-rw-r--r--doc/examples/TutorialLinAlgExComputeSolveError.cpp14
-rw-r--r--doc/examples/TutorialLinAlgExSolveColPivHouseholderQR.cpp17
-rw-r--r--doc/examples/TutorialLinAlgExSolveLDLT.cpp16
-rw-r--r--doc/examples/TutorialLinAlgInverseDeterminant.cpp16
-rw-r--r--doc/examples/TutorialLinAlgRankRevealing.cpp20
-rw-r--r--doc/examples/TutorialLinAlgSVDSolve.cpp15
-rw-r--r--doc/examples/TutorialLinAlgSelfAdjointEigenSolver.cpp18
-rw-r--r--doc/examples/TutorialLinAlgSetThreshold.cpp16
-rw-r--r--doc/examples/Tutorial_ArrayClass_accessors.cpp24
-rw-r--r--doc/examples/Tutorial_ArrayClass_addition.cpp23
-rw-r--r--doc/examples/Tutorial_ArrayClass_cwise_other.cpp19
-rw-r--r--doc/examples/Tutorial_ArrayClass_interop.cpp22
-rw-r--r--doc/examples/Tutorial_ArrayClass_interop_matrix.cpp26
-rw-r--r--doc/examples/Tutorial_ArrayClass_mult.cpp16
-rw-r--r--doc/examples/Tutorial_BlockOperations_block_assignment.cpp18
-rw-r--r--doc/examples/Tutorial_BlockOperations_colrow.cpp17
-rw-r--r--doc/examples/Tutorial_BlockOperations_corner.cpp17
-rw-r--r--doc/examples/Tutorial_BlockOperations_print_block.cpp20
-rw-r--r--doc/examples/Tutorial_BlockOperations_vector.cpp14
-rw-r--r--doc/examples/Tutorial_PartialLU_solve.cpp18
-rw-r--r--doc/examples/Tutorial_ReductionsVisitorsBroadcasting_broadcast_1nn.cpp24
-rw-r--r--doc/examples/Tutorial_ReductionsVisitorsBroadcasting_broadcast_simple.cpp21
-rw-r--r--doc/examples/Tutorial_ReductionsVisitorsBroadcasting_broadcast_simple_rowwise.cpp20
-rw-r--r--doc/examples/Tutorial_ReductionsVisitorsBroadcasting_colwise.cpp13
-rw-r--r--doc/examples/Tutorial_ReductionsVisitorsBroadcasting_maxnorm.cpp20
-rw-r--r--doc/examples/Tutorial_ReductionsVisitorsBroadcasting_reductions_bool.cpp21
-rw-r--r--doc/examples/Tutorial_ReductionsVisitorsBroadcasting_reductions_norm.cpp28
-rw-r--r--doc/examples/Tutorial_ReductionsVisitorsBroadcasting_rowwise.cpp13
-rw-r--r--doc/examples/Tutorial_ReductionsVisitorsBroadcasting_visitors.cpp26
-rw-r--r--doc/examples/Tutorial_simple_example_dynamic_size.cpp22
-rw-r--r--doc/examples/Tutorial_simple_example_fixed_size.cpp15
-rw-r--r--doc/examples/class_Block.cpp27
-rw-r--r--doc/examples/class_CwiseBinaryOp.cpp18
-rw-r--r--doc/examples/class_CwiseUnaryOp.cpp19
-rw-r--r--doc/examples/class_CwiseUnaryOp_ptrfun.cpp20
-rw-r--r--doc/examples/class_FixedBlock.cpp27
-rw-r--r--doc/examples/class_FixedVectorBlock.cpp27
-rw-r--r--doc/examples/class_VectorBlock.cpp27
-rw-r--r--doc/examples/function_taking_eigenbase.cpp18
-rw-r--r--doc/examples/tut_arithmetic_add_sub.cpp22
-rw-r--r--doc/examples/tut_arithmetic_dot_cross.cpp15
-rw-r--r--doc/examples/tut_arithmetic_matrix_mul.cpp19
-rw-r--r--doc/examples/tut_arithmetic_redux_basic.cpp16
-rw-r--r--doc/examples/tut_arithmetic_scalar_mul_div.cpp17
-rw-r--r--doc/examples/tut_matrix_coefficient_accessors.cpp18
-rw-r--r--doc/examples/tut_matrix_resize.cpp18
-rw-r--r--doc/examples/tut_matrix_resize_fixed_size.cpp12
-rw-r--r--doc/snippets/.krazy2
-rw-r--r--doc/snippets/AngleAxis_mimic_euler.cpp5
-rw-r--r--doc/snippets/CMakeLists.txt30
-rw-r--r--doc/snippets/ColPivHouseholderQR_solve.cpp8
-rw-r--r--doc/snippets/ComplexEigenSolver_compute.cpp16
-rw-r--r--doc/snippets/ComplexEigenSolver_eigenvalues.cpp4
-rw-r--r--doc/snippets/ComplexEigenSolver_eigenvectors.cpp4
-rw-r--r--doc/snippets/ComplexSchur_compute.cpp6
-rw-r--r--doc/snippets/ComplexSchur_matrixT.cpp4
-rw-r--r--doc/snippets/ComplexSchur_matrixU.cpp4
-rw-r--r--doc/snippets/Cwise_abs.cpp2
-rw-r--r--doc/snippets/Cwise_abs2.cpp2
-rw-r--r--doc/snippets/Cwise_acos.cpp2
-rw-r--r--doc/snippets/Cwise_boolean_and.cpp2
-rw-r--r--doc/snippets/Cwise_boolean_or.cpp2
-rw-r--r--doc/snippets/Cwise_cos.cpp2
-rw-r--r--doc/snippets/Cwise_cube.cpp2
-rw-r--r--doc/snippets/Cwise_equal_equal.cpp2
-rw-r--r--doc/snippets/Cwise_exp.cpp2
-rw-r--r--doc/snippets/Cwise_greater.cpp2
-rw-r--r--doc/snippets/Cwise_greater_equal.cpp2
-rw-r--r--doc/snippets/Cwise_inverse.cpp2
-rw-r--r--doc/snippets/Cwise_less.cpp2
-rw-r--r--doc/snippets/Cwise_less_equal.cpp2
-rw-r--r--doc/snippets/Cwise_log.cpp2
-rw-r--r--doc/snippets/Cwise_max.cpp2
-rw-r--r--doc/snippets/Cwise_min.cpp2
-rw-r--r--doc/snippets/Cwise_minus.cpp2
-rw-r--r--doc/snippets/Cwise_minus_equal.cpp3
-rw-r--r--doc/snippets/Cwise_not_equal.cpp2
-rw-r--r--doc/snippets/Cwise_plus.cpp2
-rw-r--r--doc/snippets/Cwise_plus_equal.cpp3
-rw-r--r--doc/snippets/Cwise_pow.cpp2
-rw-r--r--doc/snippets/Cwise_product.cpp4
-rw-r--r--doc/snippets/Cwise_quotient.cpp2
-rw-r--r--doc/snippets/Cwise_sin.cpp2
-rw-r--r--doc/snippets/Cwise_slash_equal.cpp3
-rw-r--r--doc/snippets/Cwise_sqrt.cpp2
-rw-r--r--doc/snippets/Cwise_square.cpp2
-rw-r--r--doc/snippets/Cwise_tan.cpp2
-rw-r--r--doc/snippets/Cwise_times_equal.cpp3
-rw-r--r--doc/snippets/DenseBase_LinSpaced.cpp2
-rw-r--r--doc/snippets/DenseBase_LinSpaced_seq.cpp2
-rw-r--r--doc/snippets/DenseBase_setLinSpaced.cpp3
-rw-r--r--doc/snippets/DirectionWise_replicate.cpp4
-rw-r--r--doc/snippets/DirectionWise_replicate_int.cpp4
-rw-r--r--doc/snippets/EigenSolver_EigenSolver_MatrixType.cpp16
-rw-r--r--doc/snippets/EigenSolver_compute.cpp6
-rw-r--r--doc/snippets/EigenSolver_eigenvalues.cpp4
-rw-r--r--doc/snippets/EigenSolver_eigenvectors.cpp4
-rw-r--r--doc/snippets/EigenSolver_pseudoEigenvectors.cpp9
-rw-r--r--doc/snippets/FullPivHouseholderQR_solve.cpp8
-rw-r--r--doc/snippets/FullPivLU_image.cpp9
-rw-r--r--doc/snippets/FullPivLU_kernel.cpp7
-rw-r--r--doc/snippets/FullPivLU_solve.cpp11
-rw-r--r--doc/snippets/HessenbergDecomposition_compute.cpp6
-rw-r--r--doc/snippets/HessenbergDecomposition_matrixH.cpp8
-rw-r--r--doc/snippets/HessenbergDecomposition_packedMatrix.cpp9
-rw-r--r--doc/snippets/HouseholderQR_solve.cpp9
-rw-r--r--doc/snippets/HouseholderSequence_HouseholderSequence.cpp31
-rw-r--r--doc/snippets/IOFormat.cpp14
-rw-r--r--doc/snippets/JacobiSVD_basic.cpp9
-rw-r--r--doc/snippets/Jacobi_makeGivens.cpp6
-rw-r--r--doc/snippets/Jacobi_makeJacobi.cpp8
-rw-r--r--doc/snippets/LLT_example.cpp12
-rw-r--r--doc/snippets/LLT_solve.cpp8
-rw-r--r--doc/snippets/Map_general_stride.cpp5
-rw-r--r--doc/snippets/Map_inner_stride.cpp5
-rw-r--r--doc/snippets/Map_outer_stride.cpp3
-rw-r--r--doc/snippets/Map_placement_new.cpp5
-rw-r--r--doc/snippets/Map_simple.cpp3
-rw-r--r--doc/snippets/MatrixBase_adjoint.cpp3
-rw-r--r--doc/snippets/MatrixBase_all.cpp7
-rw-r--r--doc/snippets/MatrixBase_array.cpp4
-rw-r--r--doc/snippets/MatrixBase_array_const.cpp4
-rw-r--r--doc/snippets/MatrixBase_asDiagonal.cpp1
-rw-r--r--doc/snippets/MatrixBase_block_int_int.cpp5
-rw-r--r--doc/snippets/MatrixBase_block_int_int_int_int.cpp5
-rw-r--r--doc/snippets/MatrixBase_bottomLeftCorner_int_int.cpp6
-rw-r--r--doc/snippets/MatrixBase_bottomRightCorner_int_int.cpp6
-rw-r--r--doc/snippets/MatrixBase_bottomRows_int.cpp6
-rw-r--r--doc/snippets/MatrixBase_cast.cpp3
-rw-r--r--doc/snippets/MatrixBase_col.cpp3
-rw-r--r--doc/snippets/MatrixBase_colwise.cpp5
-rw-r--r--doc/snippets/MatrixBase_computeInverseAndDetWithCheck.cpp13
-rw-r--r--doc/snippets/MatrixBase_computeInverseWithCheck.cpp11
-rw-r--r--doc/snippets/MatrixBase_cwiseAbs.cpp4
-rw-r--r--doc/snippets/MatrixBase_cwiseAbs2.cpp4
-rw-r--r--doc/snippets/MatrixBase_cwiseEqual.cpp7
-rw-r--r--doc/snippets/MatrixBase_cwiseInverse.cpp4
-rw-r--r--doc/snippets/MatrixBase_cwiseMax.cpp2
-rw-r--r--doc/snippets/MatrixBase_cwiseMin.cpp2
-rw-r--r--doc/snippets/MatrixBase_cwiseNotEqual.cpp7
-rw-r--r--doc/snippets/MatrixBase_cwiseProduct.cpp4
-rw-r--r--doc/snippets/MatrixBase_cwiseQuotient.cpp2
-rw-r--r--doc/snippets/MatrixBase_cwiseSqrt.cpp2
-rw-r--r--doc/snippets/MatrixBase_diagonal.cpp4
-rw-r--r--doc/snippets/MatrixBase_diagonal_int.cpp5
-rw-r--r--doc/snippets/MatrixBase_diagonal_template_int.cpp5
-rw-r--r--doc/snippets/MatrixBase_eigenvalues.cpp3
-rw-r--r--doc/snippets/MatrixBase_end_int.cpp5
-rw-r--r--doc/snippets/MatrixBase_eval.cpp12
-rw-r--r--doc/snippets/MatrixBase_extract.cpp13
-rw-r--r--doc/snippets/MatrixBase_fixedBlock_int_int.cpp5
-rw-r--r--doc/snippets/MatrixBase_identity.cpp1
-rw-r--r--doc/snippets/MatrixBase_identity_int_int.cpp1
-rw-r--r--doc/snippets/MatrixBase_inverse.cpp3
-rw-r--r--doc/snippets/MatrixBase_isDiagonal.cpp6
-rw-r--r--doc/snippets/MatrixBase_isIdentity.cpp5
-rw-r--r--doc/snippets/MatrixBase_isOnes.cpp5
-rw-r--r--doc/snippets/MatrixBase_isOrthogonal.cpp6
-rw-r--r--doc/snippets/MatrixBase_isUnitary.cpp5
-rw-r--r--doc/snippets/MatrixBase_isZero.cpp5
-rw-r--r--doc/snippets/MatrixBase_leftCols_int.cpp6
-rw-r--r--doc/snippets/MatrixBase_marked.cpp14
-rw-r--r--doc/snippets/MatrixBase_noalias.cpp3
-rw-r--r--doc/snippets/MatrixBase_ones.cpp2
-rw-r--r--doc/snippets/MatrixBase_ones_int.cpp2
-rw-r--r--doc/snippets/MatrixBase_ones_int_int.cpp1
-rw-r--r--doc/snippets/MatrixBase_operatorNorm.cpp3
-rw-r--r--doc/snippets/MatrixBase_part.cpp13
-rw-r--r--doc/snippets/MatrixBase_prod.cpp3
-rw-r--r--doc/snippets/MatrixBase_random.cpp1
-rw-r--r--doc/snippets/MatrixBase_random_int.cpp1
-rw-r--r--doc/snippets/MatrixBase_random_int_int.cpp1
-rw-r--r--doc/snippets/MatrixBase_replicate.cpp4
-rw-r--r--doc/snippets/MatrixBase_replicate_int_int.cpp4
-rw-r--r--doc/snippets/MatrixBase_reverse.cpp8
-rw-r--r--doc/snippets/MatrixBase_rightCols_int.cpp6
-rw-r--r--doc/snippets/MatrixBase_row.cpp3
-rw-r--r--doc/snippets/MatrixBase_rowwise.cpp5
-rw-r--r--doc/snippets/MatrixBase_segment_int_int.cpp5
-rw-r--r--doc/snippets/MatrixBase_select.cpp6
-rw-r--r--doc/snippets/MatrixBase_set.cpp13
-rw-r--r--doc/snippets/MatrixBase_setIdentity.cpp3
-rw-r--r--doc/snippets/MatrixBase_setOnes.cpp3
-rw-r--r--doc/snippets/MatrixBase_setRandom.cpp3
-rw-r--r--doc/snippets/MatrixBase_setZero.cpp3
-rw-r--r--doc/snippets/MatrixBase_start_int.cpp5
-rw-r--r--doc/snippets/MatrixBase_template_int_bottomRows.cpp6
-rw-r--r--doc/snippets/MatrixBase_template_int_end.cpp5
-rw-r--r--doc/snippets/MatrixBase_template_int_int_bottomLeftCorner.cpp6
-rw-r--r--doc/snippets/MatrixBase_template_int_int_bottomRightCorner.cpp6
-rw-r--r--doc/snippets/MatrixBase_template_int_int_topLeftCorner.cpp6
-rw-r--r--doc/snippets/MatrixBase_template_int_int_topRightCorner.cpp6
-rw-r--r--doc/snippets/MatrixBase_template_int_leftCols.cpp6
-rw-r--r--doc/snippets/MatrixBase_template_int_rightCols.cpp6
-rw-r--r--doc/snippets/MatrixBase_template_int_segment.cpp5
-rw-r--r--doc/snippets/MatrixBase_template_int_start.cpp5
-rw-r--r--doc/snippets/MatrixBase_template_int_topRows.cpp6
-rw-r--r--doc/snippets/MatrixBase_topLeftCorner_int_int.cpp6
-rw-r--r--doc/snippets/MatrixBase_topRightCorner_int_int.cpp6
-rw-r--r--doc/snippets/MatrixBase_topRows_int.cpp6
-rw-r--r--doc/snippets/MatrixBase_transpose.cpp8
-rw-r--r--doc/snippets/MatrixBase_zero.cpp2
-rw-r--r--doc/snippets/MatrixBase_zero_int.cpp2
-rw-r--r--doc/snippets/MatrixBase_zero_int_int.cpp1
-rw-r--r--doc/snippets/Matrix_resize_NoChange_int.cpp3
-rw-r--r--doc/snippets/Matrix_resize_int.cpp6
-rw-r--r--doc/snippets/Matrix_resize_int_NoChange.cpp3
-rw-r--r--doc/snippets/Matrix_resize_int_int.cpp9
-rw-r--r--doc/snippets/Matrix_setConstant_int.cpp3
-rw-r--r--doc/snippets/Matrix_setConstant_int_int.cpp3
-rw-r--r--doc/snippets/Matrix_setIdentity_int_int.cpp3
-rw-r--r--doc/snippets/Matrix_setOnes_int.cpp3
-rw-r--r--doc/snippets/Matrix_setOnes_int_int.cpp3
-rw-r--r--doc/snippets/Matrix_setRandom_int.cpp3
-rw-r--r--doc/snippets/Matrix_setRandom_int_int.cpp3
-rw-r--r--doc/snippets/Matrix_setZero_int.cpp3
-rw-r--r--doc/snippets/Matrix_setZero_int_int.cpp3
-rw-r--r--doc/snippets/PartialPivLU_solve.cpp7
-rw-r--r--doc/snippets/PartialRedux_count.cpp3
-rw-r--r--doc/snippets/PartialRedux_maxCoeff.cpp3
-rw-r--r--doc/snippets/PartialRedux_minCoeff.cpp3
-rw-r--r--doc/snippets/PartialRedux_norm.cpp3
-rw-r--r--doc/snippets/PartialRedux_prod.cpp3
-rw-r--r--doc/snippets/PartialRedux_squaredNorm.cpp3
-rw-r--r--doc/snippets/PartialRedux_sum.cpp3
-rw-r--r--doc/snippets/RealSchur_RealSchur_MatrixType.cpp10
-rw-r--r--doc/snippets/RealSchur_compute.cpp6
-rw-r--r--doc/snippets/SelfAdjointEigenSolver_SelfAdjointEigenSolver.cpp7
-rw-r--r--doc/snippets/SelfAdjointEigenSolver_SelfAdjointEigenSolver_MatrixType.cpp17
-rw-r--r--doc/snippets/SelfAdjointEigenSolver_SelfAdjointEigenSolver_MatrixType2.cpp16
-rw-r--r--doc/snippets/SelfAdjointEigenSolver_compute_MatrixType.cpp7
-rw-r--r--doc/snippets/SelfAdjointEigenSolver_compute_MatrixType2.cpp9
-rw-r--r--doc/snippets/SelfAdjointEigenSolver_eigenvalues.cpp4
-rw-r--r--doc/snippets/SelfAdjointEigenSolver_eigenvectors.cpp4
-rw-r--r--doc/snippets/SelfAdjointEigenSolver_operatorInverseSqrt.cpp9
-rw-r--r--doc/snippets/SelfAdjointEigenSolver_operatorSqrt.cpp8
-rw-r--r--doc/snippets/SelfAdjointView_eigenvalues.cpp3
-rw-r--r--doc/snippets/SelfAdjointView_operatorNorm.cpp3
-rw-r--r--doc/snippets/TopicAliasing_block.cpp7
-rw-r--r--doc/snippets/TopicAliasing_block_correct.cpp7
-rw-r--r--doc/snippets/TopicAliasing_cwise.cpp20
-rw-r--r--doc/snippets/TopicAliasing_mult1.cpp4
-rw-r--r--doc/snippets/TopicAliasing_mult2.cpp10
-rw-r--r--doc/snippets/TopicAliasing_mult3.cpp4
-rw-r--r--doc/snippets/TopicStorageOrders_example.cpp18
-rw-r--r--doc/snippets/Tridiagonalization_Tridiagonalization_MatrixType.cpp9
-rw-r--r--doc/snippets/Tridiagonalization_compute.cpp9
-rw-r--r--doc/snippets/Tridiagonalization_decomposeInPlace.cpp10
-rw-r--r--doc/snippets/Tridiagonalization_diagonal.cpp13
-rw-r--r--doc/snippets/Tridiagonalization_householderCoefficients.cpp6
-rw-r--r--doc/snippets/Tridiagonalization_packedMatrix.cpp8
-rw-r--r--doc/snippets/Tutorial_AdvancedInitialization_Block.cpp5
-rw-r--r--doc/snippets/Tutorial_AdvancedInitialization_CommaTemporary.cpp4
-rw-r--r--doc/snippets/Tutorial_AdvancedInitialization_Join.cpp11
-rw-r--r--doc/snippets/Tutorial_AdvancedInitialization_LinSpaced.cpp7
-rw-r--r--doc/snippets/Tutorial_AdvancedInitialization_ThreeWays.cpp20
-rw-r--r--doc/snippets/Tutorial_AdvancedInitialization_Zero.cpp13
-rw-r--r--doc/snippets/Tutorial_Map_rowmajor.cpp7
-rw-r--r--doc/snippets/Tutorial_Map_using.cpp21
-rw-r--r--doc/snippets/Tutorial_commainit_01.cpp5
-rw-r--r--doc/snippets/Tutorial_commainit_01b.cpp5
-rw-r--r--doc/snippets/Tutorial_commainit_02.cpp7
-rw-r--r--doc/snippets/Tutorial_solve_matrix_inverse.cpp6
-rw-r--r--doc/snippets/Tutorial_solve_multiple_rhs.cpp10
-rw-r--r--doc/snippets/Tutorial_solve_reuse_decomposition.cpp13
-rw-r--r--doc/snippets/Tutorial_solve_singular.cpp9
-rw-r--r--doc/snippets/Tutorial_solve_triangular.cpp8
-rw-r--r--doc/snippets/Tutorial_solve_triangular_inplace.cpp6
-rw-r--r--doc/snippets/Vectorwise_reverse.cpp10
-rw-r--r--doc/snippets/class_FullPivLU.cpp16
-rw-r--r--doc/snippets/compile_snippet.cpp.in12
-rw-r--r--doc/snippets/tut_arithmetic_redux_minmax.cpp12
-rw-r--r--doc/snippets/tut_arithmetic_transpose_aliasing.cpp5
-rw-r--r--doc/snippets/tut_arithmetic_transpose_conjugate.cpp12
-rw-r--r--doc/snippets/tut_arithmetic_transpose_inplace.cpp6
-rw-r--r--doc/snippets/tut_matrix_assignment_resizing.cpp5
-rw-r--r--doc/special_examples/CMakeLists.txt20
-rw-r--r--doc/special_examples/Tutorial_sparse_example.cpp32
-rw-r--r--doc/special_examples/Tutorial_sparse_example_details.cpp44
-rw-r--r--doc/tutorial.cpp62
-rw-r--r--eigen3.pc.in6
-rw-r--r--failtest/CMakeLists.txt37
-rw-r--r--failtest/block_nonconst_ctor_on_const_xpr_0.cpp15
-rw-r--r--failtest/block_nonconst_ctor_on_const_xpr_1.cpp15
-rw-r--r--failtest/block_nonconst_ctor_on_const_xpr_2.cpp16
-rw-r--r--failtest/block_on_const_type_actually_const_0.cpp16
-rw-r--r--failtest/block_on_const_type_actually_const_1.cpp16
-rw-r--r--failtest/const_qualified_block_method_retval_0.cpp15
-rw-r--r--failtest/const_qualified_block_method_retval_1.cpp15
-rw-r--r--failtest/const_qualified_diagonal_method_retval.cpp15
-rw-r--r--failtest/const_qualified_transpose_method_retval.cpp15
-rw-r--r--failtest/diagonal_nonconst_ctor_on_const_xpr.cpp15
-rw-r--r--failtest/diagonal_on_const_type_actually_const.cpp16
-rw-r--r--failtest/failtest_sanity_check.cpp5
-rw-r--r--failtest/map_nonconst_ctor_on_const_ptr_0.cpp15
-rw-r--r--failtest/map_nonconst_ctor_on_const_ptr_1.cpp15
-rw-r--r--failtest/map_nonconst_ctor_on_const_ptr_2.cpp15
-rw-r--r--failtest/map_nonconst_ctor_on_const_ptr_3.cpp15
-rw-r--r--failtest/map_nonconst_ctor_on_const_ptr_4.cpp15
-rw-r--r--failtest/map_on_const_type_actually_const_0.cpp15
-rw-r--r--failtest/map_on_const_type_actually_const_1.cpp15
-rw-r--r--failtest/transpose_nonconst_ctor_on_const_xpr.cpp15
-rw-r--r--failtest/transpose_on_const_type_actually_const.cpp16
-rw-r--r--lapack/CMakeLists.txt374
-rw-r--r--lapack/cholesky.cpp72
-rw-r--r--lapack/complex_double.cpp17
-rw-r--r--lapack/complex_single.cpp17
-rw-r--r--lapack/double.cpp17
-rw-r--r--lapack/eigenvalues.cpp79
-rw-r--r--lapack/lapack_common.h23
-rw-r--r--lapack/lu.cpp89
-rw-r--r--lapack/single.cpp17
-rw-r--r--scripts/CMakeLists.txt6
-rwxr-xr-xscripts/buildtests.in22
-rwxr-xr-xscripts/check.in21
-rwxr-xr-xscripts/debug.in3
-rw-r--r--scripts/eigen_gen_credits.cpp232
-rw-r--r--scripts/eigen_gen_docs22
-rwxr-xr-xscripts/release.in3
-rw-r--r--scripts/relicense.py69
-rw-r--r--signature_of_eigen3_matrix_library1
-rw-r--r--test/CMakeLists.txt243
-rw-r--r--test/adjoint.cpp141
-rw-r--r--test/array.cpp303
-rw-r--r--test/array_for_matrix.cpp205
-rw-r--r--test/array_replicate.cpp70
-rw-r--r--test/array_reverse.cpp128
-rw-r--r--test/bandmatrix.cpp74
-rw-r--r--test/basicstuff.cpp215
-rw-r--r--test/bicgstab.cpp30
-rw-r--r--test/block.cpp222
-rw-r--r--test/cholesky.cpp310
-rw-r--r--test/cholmod_support.cpp56
-rw-r--r--test/commainitializer.cpp46
-rw-r--r--test/conjugate_gradient.cpp30
-rw-r--r--test/conservative_resize.cpp114
-rw-r--r--test/corners.cpp98
-rw-r--r--test/cwiseop.cpp165
-rw-r--r--test/determinant.cpp67
-rw-r--r--test/diagonal.cpp83
-rw-r--r--test/diagonalmatrices.cpp94
-rw-r--r--test/dontalign.cpp63
-rw-r--r--test/dynalloc.cpp133
-rw-r--r--test/eigen2/CMakeLists.txt60
-rw-r--r--test/eigen2/eigen2_adjoint.cpp101
-rw-r--r--test/eigen2/eigen2_alignedbox.cpp60
-rw-r--r--test/eigen2/eigen2_array.cpp142
-rw-r--r--test/eigen2/eigen2_basicstuff.cpp108
-rw-r--r--test/eigen2/eigen2_bug_132.cpp26
-rw-r--r--test/eigen2/eigen2_cholesky.cpp113
-rw-r--r--test/eigen2/eigen2_commainitializer.cpp46
-rw-r--r--test/eigen2/eigen2_cwiseop.cpp158
-rw-r--r--test/eigen2/eigen2_determinant.cpp61
-rw-r--r--test/eigen2/eigen2_dynalloc.cpp131
-rw-r--r--test/eigen2/eigen2_eigensolver.cpp146
-rw-r--r--test/eigen2/eigen2_first_aligned.cpp49
-rw-r--r--test/eigen2/eigen2_geometry.cpp431
-rw-r--r--test/eigen2/eigen2_geometry_with_eigen2_prefix.cpp434
-rw-r--r--test/eigen2/eigen2_hyperplane.cpp126
-rw-r--r--test/eigen2/eigen2_inverse.cpp63
-rw-r--r--test/eigen2/eigen2_linearstructure.cpp84
-rw-r--r--test/eigen2/eigen2_lu.cpp122
-rw-r--r--test/eigen2/eigen2_map.cpp114
-rw-r--r--test/eigen2/eigen2_meta.cpp60
-rw-r--r--test/eigen2/eigen2_miscmatrices.cpp48
-rw-r--r--test/eigen2/eigen2_mixingtypes.cpp77
-rw-r--r--test/eigen2/eigen2_newstdvector.cpp149
-rw-r--r--test/eigen2/eigen2_nomalloc.cpp63
-rw-r--r--test/eigen2/eigen2_packetmath.cpp132
-rw-r--r--test/eigen2/eigen2_parametrizedline.cpp62
-rw-r--r--test/eigen2/eigen2_prec_inverse_4x4.cpp84
-rw-r--r--test/eigen2/eigen2_product_large.cpp45
-rw-r--r--test/eigen2/eigen2_product_small.cpp22
-rw-r--r--test/eigen2/eigen2_qr.cpp69
-rw-r--r--test/eigen2/eigen2_qtvector.cpp158
-rw-r--r--test/eigen2/eigen2_regression.cpp136
-rw-r--r--test/eigen2/eigen2_sizeof.cpp31
-rw-r--r--test/eigen2/eigen2_smallvectors.cpp42
-rw-r--r--test/eigen2/eigen2_sparse_basic.cpp317
-rw-r--r--test/eigen2/eigen2_sparse_product.cpp115
-rw-r--r--test/eigen2/eigen2_sparse_solvers.cpp200
-rw-r--r--test/eigen2/eigen2_sparse_vector.cpp84
-rw-r--r--test/eigen2/eigen2_stdvector.cpp148
-rw-r--r--test/eigen2/eigen2_submatrices.cpp148
-rw-r--r--test/eigen2/eigen2_sum.cpp71
-rw-r--r--test/eigen2/eigen2_svd.cpp87
-rw-r--r--test/eigen2/eigen2_swap.cpp83
-rw-r--r--test/eigen2/eigen2_triangular.cpp158
-rw-r--r--test/eigen2/eigen2_unalignedassert.cpp116
-rw-r--r--test/eigen2/eigen2_visitor.cpp116
-rw-r--r--test/eigen2/gsl_helper.h175
-rw-r--r--test/eigen2/main.h399
-rw-r--r--test/eigen2/product.h132
-rwxr-xr-xtest/eigen2/runtest.sh28
-rw-r--r--test/eigen2/sparse.h154
-rw-r--r--test/eigen2/testsuite.cmake197
-rw-r--r--test/eigen2support.cpp64
-rw-r--r--test/eigensolver_complex.cpp115
-rw-r--r--test/eigensolver_generic.cpp115
-rw-r--r--test/eigensolver_selfadjoint.cpp146
-rw-r--r--test/exceptions.cpp109
-rw-r--r--test/first_aligned.cpp51
-rw-r--r--test/geo_alignedbox.cpp171
-rw-r--r--test/geo_eulerangles.cpp54
-rw-r--r--test/geo_homogeneous.cpp103
-rw-r--r--test/geo_hyperplane.cpp157
-rw-r--r--test/geo_orthomethods.cpp121
-rw-r--r--test/geo_parametrizedline.cpp105
-rw-r--r--test/geo_quaternion.cpp255
-rw-r--r--test/geo_transformations.cpp487
-rw-r--r--test/hessenberg.cpp62
-rw-r--r--test/householder.cpp123
-rw-r--r--test/integer_types.cpp161
-rw-r--r--test/inverse.cpp102
-rw-r--r--test/jacobi.cpp81
-rw-r--r--test/jacobisvd.cpp350
-rw-r--r--test/linearstructure.cpp83
-rw-r--r--test/lu.cpp207
-rw-r--r--test/main.h472
-rw-r--r--test/map.cpp144
-rw-r--r--test/mapstaticmethods.cpp173
-rw-r--r--test/mapstride.cpp146
-rw-r--r--test/meta.cpp76
-rw-r--r--test/miscmatrices.cpp48
-rw-r--r--test/mixingtypes.cpp132
-rw-r--r--test/nesting_ops.cpp41
-rw-r--r--test/nomalloc.cpp174
-rw-r--r--test/nullary.cpp123
-rw-r--r--test/packetmath.cpp345
-rw-r--r--test/pardiso_support.cpp29
-rw-r--r--test/pastix_support.cpp44
-rw-r--r--test/permutationmatrices.cpp117
-rw-r--r--test/prec_inverse_4x4.cpp68
-rw-r--r--test/product.h143
-rw-r--r--test/product_extra.cpp148
-rw-r--r--test/product_large.cpp64
-rw-r--r--test/product_mmtr.cpp65
-rw-r--r--test/product_notemporary.cpp138
-rw-r--r--test/product_selfadjoint.cpp81
-rw-r--r--test/product_small.cpp50
-rw-r--r--test/product_symm.cpp96
-rw-r--r--test/product_syrk.cpp98
-rw-r--r--test/product_trmm.cpp108
-rw-r--r--test/product_trmv.cpp89
-rw-r--r--test/product_trsolve.cpp93
-rw-r--r--test/qr.cpp126
-rw-r--r--test/qr_colpivoting.cpp150
-rw-r--r--test/qr_fullpivoting.cpp132
-rw-r--r--test/qtvector.cpp158
-rw-r--r--test/redux.cpp158
-rw-r--r--test/resize.cpp41
-rwxr-xr-xtest/runtest.sh20
-rw-r--r--test/schur_complex.cpp74
-rw-r--r--test/schur_real.cpp93
-rw-r--r--test/selfadjoint.cpp62
-rw-r--r--test/simplicial_cholesky.cpp40
-rw-r--r--test/sizeof.cpp34
-rw-r--r--test/sizeoverflow.cpp66
-rw-r--r--test/smallvectors.cpp67
-rw-r--r--test/sparse.h182
-rw-r--r--test/sparse_basic.cpp395
-rw-r--r--test/sparse_permutations.cpp187
-rw-r--r--test/sparse_product.cpp204
-rw-r--r--test/sparse_solver.h309
-rw-r--r--test/sparse_solvers.cpp112
-rw-r--r--test/sparse_vector.cpp91
-rw-r--r--test/stable_norm.cpp110
-rw-r--r--test/stddeque.cpp132
-rw-r--r--test/stdlist.cpp132
-rw-r--r--test/stdvector.cpp148
-rw-r--r--test/stdvector_overload.cpp161
-rw-r--r--test/superlu_support.cpp22
-rw-r--r--test/swap.cpp83
-rw-r--r--test/testsuite.cmake229
-rw-r--r--test/triangular.cpp235
-rw-r--r--test/umeyama.cpp183
-rw-r--r--test/umfpack_support.cpp31
-rw-r--r--test/unalignedassert.cpp127
-rw-r--r--test/unalignedcount.cpp44
-rw-r--r--test/upperbidiagonalization.cpp41
-rw-r--r--test/vectorization_logic.cpp235
-rw-r--r--test/vectorwiseop.cpp172
-rw-r--r--test/visitor.cpp118
-rw-r--r--test/zerosized.cpp59
-rw-r--r--unsupported/CMakeLists.txt7
-rw-r--r--unsupported/Eigen/AdolcForward156
-rw-r--r--unsupported/Eigen/AlignedVector3189
-rw-r--r--unsupported/Eigen/AutoDiff40
-rw-r--r--unsupported/Eigen/BVH95
-rw-r--r--unsupported/Eigen/CMakeLists.txt11
-rw-r--r--unsupported/Eigen/FFT418
-rw-r--r--unsupported/Eigen/IterativeSolvers40
-rw-r--r--unsupported/Eigen/KroneckerProduct26
-rw-r--r--unsupported/Eigen/MPRealSupport148
-rw-r--r--unsupported/Eigen/MatrixFunctions380
-rw-r--r--unsupported/Eigen/MoreVectorization16
-rw-r--r--unsupported/Eigen/NonLinearOptimization134
-rw-r--r--unsupported/Eigen/NumericalDiff56
-rw-r--r--unsupported/Eigen/OpenGLSupport317
-rw-r--r--unsupported/Eigen/Polynomials133
-rw-r--r--unsupported/Eigen/Skyline31
-rw-r--r--unsupported/Eigen/SparseExtra47
-rw-r--r--unsupported/Eigen/Splines31
-rw-r--r--unsupported/Eigen/src/AutoDiff/AutoDiffJacobian.h83
-rw-r--r--unsupported/Eigen/src/AutoDiff/AutoDiffScalar.h632
-rw-r--r--unsupported/Eigen/src/AutoDiff/AutoDiffVector.h220
-rw-r--r--unsupported/Eigen/src/AutoDiff/CMakeLists.txt6
-rw-r--r--unsupported/Eigen/src/BVH/BVAlgorithms.h293
-rw-r--r--unsupported/Eigen/src/BVH/CMakeLists.txt6
-rw-r--r--unsupported/Eigen/src/BVH/KdBVH.h222
-rw-r--r--unsupported/Eigen/src/CMakeLists.txt13
-rw-r--r--unsupported/Eigen/src/FFT/CMakeLists.txt6
-rw-r--r--unsupported/Eigen/src/FFT/ei_fftw_impl.h261
-rw-r--r--unsupported/Eigen/src/FFT/ei_kissfft_impl.h418
-rw-r--r--unsupported/Eigen/src/IterativeSolvers/CMakeLists.txt6
-rw-r--r--unsupported/Eigen/src/IterativeSolvers/ConstrainedConjGrad.h189
-rw-r--r--unsupported/Eigen/src/IterativeSolvers/GMRES.h379
-rw-r--r--unsupported/Eigen/src/IterativeSolvers/IncompleteLU.h113
-rw-r--r--unsupported/Eigen/src/IterativeSolvers/IterationController.h157
-rw-r--r--unsupported/Eigen/src/IterativeSolvers/Scaling.h185
-rw-r--r--unsupported/Eigen/src/KroneckerProduct/CMakeLists.txt6
-rw-r--r--unsupported/Eigen/src/KroneckerProduct/KroneckerTensorProduct.h157
-rw-r--r--unsupported/Eigen/src/MatrixFunctions/CMakeLists.txt6
-rw-r--r--unsupported/Eigen/src/MatrixFunctions/MatrixExponential.h454
-rw-r--r--unsupported/Eigen/src/MatrixFunctions/MatrixFunction.h590
-rw-r--r--unsupported/Eigen/src/MatrixFunctions/MatrixFunctionAtomic.h131
-rw-r--r--unsupported/Eigen/src/MatrixFunctions/MatrixLogarithm.h495
-rw-r--r--unsupported/Eigen/src/MatrixFunctions/MatrixSquareRoot.h484
-rw-r--r--unsupported/Eigen/src/MatrixFunctions/StemFunction.h105
-rw-r--r--unsupported/Eigen/src/MoreVectorization/CMakeLists.txt6
-rw-r--r--unsupported/Eigen/src/MoreVectorization/MathFunctions.h95
-rw-r--r--unsupported/Eigen/src/NonLinearOptimization/CMakeLists.txt6
-rw-r--r--unsupported/Eigen/src/NonLinearOptimization/HybridNonLinearSolver.h596
-rw-r--r--unsupported/Eigen/src/NonLinearOptimization/LevenbergMarquardt.h644
-rw-r--r--unsupported/Eigen/src/NonLinearOptimization/chkder.h62
-rw-r--r--unsupported/Eigen/src/NonLinearOptimization/covar.h69
-rw-r--r--unsupported/Eigen/src/NonLinearOptimization/dogleg.h104
-rw-r--r--unsupported/Eigen/src/NonLinearOptimization/fdjac1.h76
-rw-r--r--unsupported/Eigen/src/NonLinearOptimization/lmpar.h294
-rw-r--r--unsupported/Eigen/src/NonLinearOptimization/qrsolv.h91
-rw-r--r--unsupported/Eigen/src/NonLinearOptimization/r1mpyq.h30
-rw-r--r--unsupported/Eigen/src/NonLinearOptimization/r1updt.h99
-rw-r--r--unsupported/Eigen/src/NonLinearOptimization/rwupdt.h49
-rw-r--r--unsupported/Eigen/src/NumericalDiff/CMakeLists.txt6
-rw-r--r--unsupported/Eigen/src/NumericalDiff/NumericalDiff.h128
-rw-r--r--unsupported/Eigen/src/Polynomials/CMakeLists.txt6
-rw-r--r--unsupported/Eigen/src/Polynomials/Companion.h275
-rw-r--r--unsupported/Eigen/src/Polynomials/PolynomialSolver.h386
-rw-r--r--unsupported/Eigen/src/Polynomials/PolynomialUtils.h141
-rw-r--r--unsupported/Eigen/src/Skyline/CMakeLists.txt6
-rw-r--r--unsupported/Eigen/src/Skyline/SkylineInplaceLU.h352
-rw-r--r--unsupported/Eigen/src/Skyline/SkylineMatrix.h862
-rw-r--r--unsupported/Eigen/src/Skyline/SkylineMatrixBase.h212
-rw-r--r--unsupported/Eigen/src/Skyline/SkylineProduct.h295
-rw-r--r--unsupported/Eigen/src/Skyline/SkylineStorage.h259
-rw-r--r--unsupported/Eigen/src/Skyline/SkylineUtil.h89
-rw-r--r--unsupported/Eigen/src/SparseExtra/BlockOfDynamicSparseMatrix.h114
-rw-r--r--unsupported/Eigen/src/SparseExtra/CMakeLists.txt6
-rw-r--r--unsupported/Eigen/src/SparseExtra/DynamicSparseMatrix.h357
-rw-r--r--unsupported/Eigen/src/SparseExtra/MarketIO.h273
-rw-r--r--unsupported/Eigen/src/SparseExtra/MatrixMarketIterator.h221
-rw-r--r--unsupported/Eigen/src/SparseExtra/RandomSetter.h327
-rw-r--r--unsupported/Eigen/src/Splines/CMakeLists.txt6
-rw-r--r--unsupported/Eigen/src/Splines/Spline.h464
-rw-r--r--unsupported/Eigen/src/Splines/SplineFitting.h159
-rw-r--r--unsupported/Eigen/src/Splines/SplineFwd.h86
-rw-r--r--unsupported/README.txt50
-rw-r--r--unsupported/doc/CMakeLists.txt4
-rw-r--r--unsupported/doc/Doxyfile.in1460
-rw-r--r--unsupported/doc/Overview.dox22
-rw-r--r--unsupported/doc/examples/BVH_Example.cpp52
-rw-r--r--unsupported/doc/examples/CMakeLists.txt22
-rw-r--r--unsupported/doc/examples/FFT.cpp118
-rw-r--r--unsupported/doc/examples/MatrixExponential.cpp16
-rw-r--r--unsupported/doc/examples/MatrixFunction.cpp23
-rw-r--r--unsupported/doc/examples/MatrixLogarithm.cpp15
-rw-r--r--unsupported/doc/examples/MatrixSine.cpp20
-rw-r--r--unsupported/doc/examples/MatrixSinh.cpp20
-rw-r--r--unsupported/doc/examples/MatrixSquareRoot.cpp16
-rw-r--r--unsupported/doc/examples/PolynomialSolver1.cpp53
-rw-r--r--unsupported/doc/examples/PolynomialUtils1.cpp20
-rw-r--r--unsupported/doc/snippets/CMakeLists.txt28
-rw-r--r--unsupported/test/BVH.cpp222
-rw-r--r--unsupported/test/CMakeLists.txt87
-rw-r--r--unsupported/test/FFT.cpp2
-rw-r--r--unsupported/test/FFTW.cpp265
-rw-r--r--unsupported/test/NonLinearOptimization.cpp1861
-rw-r--r--unsupported/test/NumericalDiff.cpp114
-rw-r--r--unsupported/test/alignedvector3.cpp59
-rw-r--r--unsupported/test/autodiff.cpp172
-rw-r--r--unsupported/test/forward_adolc.cpp143
-rw-r--r--unsupported/test/gmres.cpp33
-rw-r--r--unsupported/test/kronecker_product.cpp179
-rw-r--r--unsupported/test/matrix_exponential.cpp149
-rw-r--r--unsupported/test/matrix_function.cpp194
-rw-r--r--unsupported/test/matrix_square_root.cpp62
-rwxr-xr-xunsupported/test/mpreal/dlmalloc.c5703
-rwxr-xr-xunsupported/test/mpreal/dlmalloc.h562
-rw-r--r--unsupported/test/mpreal/mpreal.cpp597
-rw-r--r--unsupported/test/mpreal/mpreal.h2735
-rw-r--r--unsupported/test/mpreal_support.cpp64
-rw-r--r--unsupported/test/openglsupport.cpp337
-rw-r--r--unsupported/test/polynomialsolver.cpp217
-rw-r--r--unsupported/test/polynomialutils.cpp113
-rw-r--r--unsupported/test/sparse_extra.cpp149
-rw-r--r--unsupported/test/splines.cpp240
1249 files changed, 199617 insertions, 0 deletions
diff --git a/Android.mk b/Android.mk
new file mode 100644
index 000000000..4078ec1b8
--- /dev/null
+++ b/Android.mk
@@ -0,0 +1,16 @@
+# Copyright (C) 2012 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# This empty file is here solely for the purpose of optimizing the Android build
+# Please keep it there, and empty, thanks.
diff --git a/CMakeLists.txt b/CMakeLists.txt
new file mode 100644
index 000000000..3ba310a27
--- /dev/null
+++ b/CMakeLists.txt
@@ -0,0 +1,378 @@
+project(Eigen)
+
+cmake_minimum_required(VERSION 2.6.2)
+
+# guard against in-source builds
+
+if(${CMAKE_SOURCE_DIR} STREQUAL ${CMAKE_BINARY_DIR})
+ message(FATAL_ERROR "In-source builds not allowed. Please make a new directory (called a build directory) and run CMake from there. You may need to remove CMakeCache.txt. ")
+endif()
+
+# guard against bad build-type strings
+
+if (NOT CMAKE_BUILD_TYPE)
+ set(CMAKE_BUILD_TYPE "Release")
+endif()
+
+string(TOLOWER "${CMAKE_BUILD_TYPE}" cmake_build_type_tolower)
+if( NOT cmake_build_type_tolower STREQUAL "debug"
+ AND NOT cmake_build_type_tolower STREQUAL "release"
+ AND NOT cmake_build_type_tolower STREQUAL "relwithdebinfo")
+ message(FATAL_ERROR "Unknown build type \"${CMAKE_BUILD_TYPE}\". Allowed values are Debug, Release, RelWithDebInfo (case-insensitive).")
+endif()
+
+
+#############################################################################
+# retrieve version infomation #
+#############################################################################
+
+# automatically parse the version number
+file(READ "${PROJECT_SOURCE_DIR}/Eigen/src/Core/util/Macros.h" _eigen_version_header)
+string(REGEX MATCH "define[ \t]+EIGEN_WORLD_VERSION[ \t]+([0-9]+)" _eigen_world_version_match "${_eigen_version_header}")
+set(EIGEN_WORLD_VERSION "${CMAKE_MATCH_1}")
+string(REGEX MATCH "define[ \t]+EIGEN_MAJOR_VERSION[ \t]+([0-9]+)" _eigen_major_version_match "${_eigen_version_header}")
+set(EIGEN_MAJOR_VERSION "${CMAKE_MATCH_1}")
+string(REGEX MATCH "define[ \t]+EIGEN_MINOR_VERSION[ \t]+([0-9]+)" _eigen_minor_version_match "${_eigen_version_header}")
+set(EIGEN_MINOR_VERSION "${CMAKE_MATCH_1}")
+set(EIGEN_VERSION_NUMBER ${EIGEN_WORLD_VERSION}.${EIGEN_MAJOR_VERSION}.${EIGEN_MINOR_VERSION})
+
+# if the mercurial program is absent, this will leave the EIGEN_HG_CHANGESET string empty,
+# but won't stop CMake.
+execute_process(COMMAND hg tip -R ${CMAKE_SOURCE_DIR} OUTPUT_VARIABLE EIGEN_HGTIP_OUTPUT)
+execute_process(COMMAND hg branch -R ${CMAKE_SOURCE_DIR} OUTPUT_VARIABLE EIGEN_BRANCH_OUTPUT)
+
+# if this is the default (aka development) branch, extract the mercurial changeset number from the hg tip output...
+if(EIGEN_BRANCH_OUTPUT MATCHES "default")
+string(REGEX MATCH "^changeset: *[0-9]*:([0-9;a-f]+).*" EIGEN_HG_CHANGESET_MATCH "${EIGEN_HGTIP_OUTPUT}")
+set(EIGEN_HG_CHANGESET "${CMAKE_MATCH_1}")
+endif(EIGEN_BRANCH_OUTPUT MATCHES "default")
+#...and show it next to the version number
+if(EIGEN_HG_CHANGESET)
+ set(EIGEN_VERSION "${EIGEN_VERSION_NUMBER} (mercurial changeset ${EIGEN_HG_CHANGESET})")
+else(EIGEN_HG_CHANGESET)
+ set(EIGEN_VERSION "${EIGEN_VERSION_NUMBER}")
+endif(EIGEN_HG_CHANGESET)
+
+
+include(CheckCXXCompilerFlag)
+
+set(CMAKE_MODULE_PATH ${PROJECT_SOURCE_DIR}/cmake)
+
+#############################################################################
+# find how to link to the standard libraries #
+#############################################################################
+
+find_package(StandardMathLibrary)
+
+
+set(EIGEN_TEST_CUSTOM_LINKER_FLAGS "" CACHE STRING "Additional linker flags when linking unit tests.")
+set(EIGEN_TEST_CUSTOM_CXX_FLAGS "" CACHE STRING "Additional compiler flags when compiling unit tests.")
+
+set(EIGEN_STANDARD_LIBRARIES_TO_LINK_TO "")
+
+if(NOT STANDARD_MATH_LIBRARY_FOUND)
+
+ message(FATAL_ERROR
+ "Can't link to the standard math library. Please report to the Eigen developers, telling them about your platform.")
+
+else()
+
+ if(EIGEN_STANDARD_LIBRARIES_TO_LINK_TO)
+ set(EIGEN_STANDARD_LIBRARIES_TO_LINK_TO "${EIGEN_STANDARD_LIBRARIES_TO_LINK_TO} ${STANDARD_MATH_LIBRARY}")
+ else()
+ set(EIGEN_STANDARD_LIBRARIES_TO_LINK_TO "${STANDARD_MATH_LIBRARY}")
+ endif()
+
+endif()
+
+if(EIGEN_STANDARD_LIBRARIES_TO_LINK_TO)
+ message(STATUS "Standard libraries to link to explicitly: ${EIGEN_STANDARD_LIBRARIES_TO_LINK_TO}")
+else()
+ message(STATUS "Standard libraries to link to explicitly: none")
+endif()
+
+option(EIGEN_BUILD_BTL "Build benchmark suite" OFF)
+if(NOT WIN32)
+ option(EIGEN_BUILD_PKGCONFIG "Build pkg-config .pc file for Eigen" ON)
+endif(NOT WIN32)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+option(EIGEN_SPLIT_LARGE_TESTS "Split large tests into smaller executables" ON)
+
+option(EIGEN_DEFAULT_TO_ROW_MAJOR "Use row-major as default matrix storage order" OFF)
+if(EIGEN_DEFAULT_TO_ROW_MAJOR)
+ add_definitions("-DEIGEN_DEFAULT_TO_ROW_MAJOR")
+endif()
+
+add_definitions("-DEIGEN_PERMANENTLY_DISABLE_STUPID_WARNINGS")
+
+set(EIGEN_TEST_MAX_SIZE "320" CACHE STRING "Maximal matrix/vector size, default is 320")
+
+if(CMAKE_COMPILER_IS_GNUCXX)
+ set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wnon-virtual-dtor -Wno-long-long -ansi -Wundef -Wcast-align -Wchar-subscripts -Wall -W -Wpointer-arith -Wwrite-strings -Wformat-security -fexceptions -fno-check-new -fno-common -fstrict-aliasing")
+ set(CMAKE_CXX_FLAGS_DEBUG "-g3")
+ set(CMAKE_CXX_FLAGS_RELEASE "-g0 -O2")
+
+ check_cxx_compiler_flag("-Wno-variadic-macros" COMPILER_SUPPORT_WNOVARIADICMACRO)
+ if(COMPILER_SUPPORT_WNOVARIADICMACRO)
+ set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-variadic-macros")
+ endif()
+
+ check_cxx_compiler_flag("-Wextra" COMPILER_SUPPORT_WEXTRA)
+ if(COMPILER_SUPPORT_WEXTRA)
+ set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wextra")
+ endif()
+
+ set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -pedantic")
+
+ option(EIGEN_TEST_SSE2 "Enable/Disable SSE2 in tests/examples" OFF)
+ if(EIGEN_TEST_SSE2)
+ set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -msse2")
+ message(STATUS "Enabling SSE2 in tests/examples")
+ endif()
+
+ option(EIGEN_TEST_SSE3 "Enable/Disable SSE3 in tests/examples" OFF)
+ if(EIGEN_TEST_SSE3)
+ set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -msse3")
+ message(STATUS "Enabling SSE3 in tests/examples")
+ endif()
+
+ option(EIGEN_TEST_SSSE3 "Enable/Disable SSSE3 in tests/examples" OFF)
+ if(EIGEN_TEST_SSSE3)
+ set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -mssse3")
+ message(STATUS "Enabling SSSE3 in tests/examples")
+ endif()
+
+ option(EIGEN_TEST_SSE4_1 "Enable/Disable SSE4.1 in tests/examples" OFF)
+ if(EIGEN_TEST_SSE4_1)
+ set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -msse4.1")
+ message(STATUS "Enabling SSE4.1 in tests/examples")
+ endif()
+
+ option(EIGEN_TEST_SSE4_2 "Enable/Disable SSE4.2 in tests/examples" OFF)
+ if(EIGEN_TEST_SSE4_2)
+ set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -msse4.2")
+ message(STATUS "Enabling SSE4.2 in tests/examples")
+ endif()
+
+ option(EIGEN_TEST_ALTIVEC "Enable/Disable AltiVec in tests/examples" OFF)
+ if(EIGEN_TEST_ALTIVEC)
+ set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -maltivec -mabi=altivec")
+ message(STATUS "Enabling AltiVec in tests/examples")
+ endif()
+
+ option(EIGEN_TEST_NEON "Enable/Disable Neon in tests/examples" OFF)
+ if(EIGEN_TEST_NEON)
+ set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -mfpu=neon -mcpu=cortex-a8")
+ message(STATUS "Enabling NEON in tests/examples")
+ endif()
+
+ check_cxx_compiler_flag("-fopenmp" COMPILER_SUPPORT_OPENMP)
+ if(COMPILER_SUPPORT_OPENMP)
+ option(EIGEN_TEST_OPENMP "Enable/Disable OpenMP in tests/examples" OFF)
+ if(EIGEN_TEST_OPENMP)
+ set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fopenmp")
+ message(STATUS "Enabling OpenMP in tests/examples")
+ endif()
+ endif()
+
+endif(CMAKE_COMPILER_IS_GNUCXX)
+
+if(MSVC)
+ # C4127 - conditional expression is constant
+ # C4714 - marked as __forceinline not inlined (I failed to deactivate it selectively)
+ # We can disable this warning in the unit tests since it is clear that it occurs
+ # because we are oftentimes returning objects that have a destructor or may
+ # throw exceptions - in particular in the unit tests we are throwing extra many
+ # exceptions to cover indexing errors.
+ # C4505 - unreferenced local function has been removed (impossible to deactive selectively)
+ set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /EHsc /wd4127 /wd4505 /wd4714")
+
+ # replace all /Wx by /W4
+ string(REGEX REPLACE "/W[0-9]" "/W4" CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}")
+
+ check_cxx_compiler_flag("/openmp" COMPILER_SUPPORT_OPENMP)
+ if(COMPILER_SUPPORT_OPENMP)
+ option(EIGEN_TEST_OPENMP "Enable/Disable OpenMP in tests/examples" OFF)
+ if(EIGEN_TEST_OPENMP)
+ set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /openmp")
+ message(STATUS "Enabling OpenMP in tests/examples")
+ endif()
+ endif()
+
+ option(EIGEN_TEST_SSE2 "Enable/Disable SSE2 in tests/examples" OFF)
+ if(EIGEN_TEST_SSE2)
+ if(NOT CMAKE_CL_64)
+ # arch is not supported on 64 bit systems, SSE is enabled automatically.
+ set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /arch:SSE2")
+ endif(NOT CMAKE_CL_64)
+ message(STATUS "Enabling SSE2 in tests/examples")
+ endif(EIGEN_TEST_SSE2)
+endif(MSVC)
+
+option(EIGEN_TEST_NO_EXPLICIT_VECTORIZATION "Disable explicit vectorization in tests/examples" OFF)
+option(EIGEN_TEST_X87 "Force using X87 instructions. Implies no vectorization." OFF)
+option(EIGEN_TEST_32BIT "Force generating 32bit code." OFF)
+
+if(EIGEN_TEST_X87)
+ set(EIGEN_TEST_NO_EXPLICIT_VECTORIZATION ON)
+ if(CMAKE_COMPILER_IS_GNUCXX)
+ set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -mfpmath=387")
+ message(STATUS "Forcing use of x87 instructions in tests/examples")
+ else()
+ message(STATUS "EIGEN_TEST_X87 ignored on your compiler")
+ endif()
+endif()
+
+if(EIGEN_TEST_32BIT)
+ if(CMAKE_COMPILER_IS_GNUCXX)
+ set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -m32")
+ message(STATUS "Forcing generation of 32-bit code in tests/examples")
+ else()
+ message(STATUS "EIGEN_TEST_32BIT ignored on your compiler")
+ endif()
+endif()
+
+if(EIGEN_TEST_NO_EXPLICIT_VECTORIZATION)
+ add_definitions(-DEIGEN_DONT_VECTORIZE=1)
+ message(STATUS "Disabling vectorization in tests/examples")
+endif()
+
+option(EIGEN_TEST_NO_EXPLICIT_ALIGNMENT "Disable explicit alignment (hence vectorization) in tests/examples" OFF)
+if(EIGEN_TEST_NO_EXPLICIT_ALIGNMENT)
+ add_definitions(-DEIGEN_DONT_ALIGN=1)
+ message(STATUS "Disabling alignment in tests/examples")
+endif()
+
+option(EIGEN_TEST_C++0x "Enables all C++0x features." OFF)
+
+include_directories(${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_BINARY_DIR})
+
+# the user modifiable install path for header files
+set(EIGEN_INCLUDE_INSTALL_DIR ${EIGEN_INCLUDE_INSTALL_DIR} CACHE PATH "The directory where we install the header files (optional)")
+
+# set the internal install path for header files which depends on wether the user modifiable
+# EIGEN_INCLUDE_INSTALL_DIR has been set by the user or not.
+if(EIGEN_INCLUDE_INSTALL_DIR)
+ set(INCLUDE_INSTALL_DIR
+ ${EIGEN_INCLUDE_INSTALL_DIR}
+ CACHE INTERNAL
+ "The directory where we install the header files (internal)"
+ )
+else()
+ set(INCLUDE_INSTALL_DIR
+ "${CMAKE_INSTALL_PREFIX}/include/eigen3"
+ CACHE INTERNAL
+ "The directory where we install the header files (internal)"
+ )
+endif()
+
+# similar to set_target_properties but append the property instead of overwriting it
+macro(ei_add_target_property target prop value)
+
+ get_target_property(previous ${target} ${prop})
+ # if the property wasn't previously set, ${previous} is now "previous-NOTFOUND" which cmake allows catching with plain if()
+ if(NOT previous)
+ set(previous "")
+ endif(NOT previous)
+ set_target_properties(${target} PROPERTIES ${prop} "${previous} ${value}")
+endmacro(ei_add_target_property)
+
+install(FILES
+ signature_of_eigen3_matrix_library
+ DESTINATION ${INCLUDE_INSTALL_DIR} COMPONENT Devel
+ )
+
+if(EIGEN_BUILD_PKGCONFIG)
+ SET(path_separator ":")
+ STRING(REPLACE ${path_separator} ";" pkg_config_libdir_search "$ENV{PKG_CONFIG_LIBDIR}")
+ message(STATUS "searching for 'pkgconfig' directory in PKG_CONFIG_LIBDIR ( $ENV{PKG_CONFIG_LIBDIR} ), ${CMAKE_INSTALL_PREFIX}/share, and ${CMAKE_INSTALL_PREFIX}/lib")
+ FIND_PATH(pkg_config_libdir pkgconfig ${pkg_config_libdir_search} ${CMAKE_INSTALL_PREFIX}/share ${CMAKE_INSTALL_PREFIX}/lib ${pkg_config_libdir_search})
+ if(pkg_config_libdir)
+ SET(pkg_config_install_dir ${pkg_config_libdir})
+ message(STATUS "found ${pkg_config_libdir}/pkgconfig" )
+ else(pkg_config_libdir)
+ SET(pkg_config_install_dir ${CMAKE_INSTALL_PREFIX}/share)
+ message(STATUS "pkgconfig not found; installing in ${pkg_config_install_dir}" )
+ endif(pkg_config_libdir)
+
+ configure_file(eigen3.pc.in eigen3.pc)
+ install(FILES ${CMAKE_CURRENT_BINARY_DIR}/eigen3.pc
+ DESTINATION ${pkg_config_install_dir}/pkgconfig
+ )
+endif(EIGEN_BUILD_PKGCONFIG)
+
+add_subdirectory(Eigen)
+
+add_subdirectory(doc EXCLUDE_FROM_ALL)
+
+include(EigenConfigureTesting)
+# fixme, not sure this line is still needed:
+enable_testing() # must be called from the root CMakeLists, see man page
+
+
+if(EIGEN_LEAVE_TEST_IN_ALL_TARGET)
+ add_subdirectory(test) # can't do EXCLUDE_FROM_ALL here, breaks CTest
+else()
+ add_subdirectory(test EXCLUDE_FROM_ALL)
+endif()
+
+if(EIGEN_LEAVE_TEST_IN_ALL_TARGET)
+ add_subdirectory(blas)
+ add_subdirectory(lapack)
+else()
+ add_subdirectory(blas EXCLUDE_FROM_ALL)
+ add_subdirectory(lapack EXCLUDE_FROM_ALL)
+endif()
+
+add_subdirectory(unsupported)
+
+add_subdirectory(demos EXCLUDE_FROM_ALL)
+
+# must be after test and unsupported, for configuring buildtests.in
+add_subdirectory(scripts EXCLUDE_FROM_ALL)
+
+# TODO: consider also replacing EIGEN_BUILD_BTL by a custom target "make btl"?
+if(EIGEN_BUILD_BTL)
+ add_subdirectory(bench/btl EXCLUDE_FROM_ALL)
+endif(EIGEN_BUILD_BTL)
+
+if(NOT WIN32)
+ add_subdirectory(bench/spbench EXCLUDE_FROM_ALL)
+endif(NOT WIN32)
+
+ei_testing_print_summary()
+
+message(STATUS "")
+message(STATUS "Configured Eigen ${EIGEN_VERSION_NUMBER}")
+message(STATUS "")
+
+option(EIGEN_FAILTEST "Enable failtests." OFF)
+if(EIGEN_FAILTEST)
+ add_subdirectory(failtest)
+endif()
+
+string(TOLOWER "${CMAKE_GENERATOR}" cmake_generator_tolower)
+if(cmake_generator_tolower MATCHES "makefile")
+ message(STATUS "Some things you can do now:")
+ message(STATUS "--------------+--------------------------------------------------------------")
+ message(STATUS "Command | Description")
+ message(STATUS "--------------+--------------------------------------------------------------")
+ message(STATUS "make install | Install to ${CMAKE_INSTALL_PREFIX}. To change that:")
+ message(STATUS " | cmake . -DCMAKE_INSTALL_PREFIX=yourpath")
+ message(STATUS " | Eigen headers will then be installed to:")
+ message(STATUS " | ${INCLUDE_INSTALL_DIR}")
+ message(STATUS " | To install Eigen headers to a separate location, do:")
+ message(STATUS " | cmake . -DEIGEN_INCLUDE_INSTALL_DIR=yourpath")
+ message(STATUS "make doc | Generate the API documentation, requires Doxygen & LaTeX")
+ message(STATUS "make check | Build and run the unit-tests. Read this page:")
+ message(STATUS " | http://eigen.tuxfamily.org/index.php?title=Tests")
+ message(STATUS "make blas | Build BLAS library (not the same thing as Eigen)")
+ message(STATUS "--------------+--------------------------------------------------------------")
+else()
+ message(STATUS "To build/run the unit tests, read this page:")
+ message(STATUS " http://eigen.tuxfamily.org/index.php?title=Tests")
+endif()
+
+message(STATUS "")
diff --git a/COPYING.BSD b/COPYING.BSD
new file mode 100644
index 000000000..11971ffe2
--- /dev/null
+++ b/COPYING.BSD
@@ -0,0 +1,26 @@
+/*
+ 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.
+*/ \ No newline at end of file
diff --git a/COPYING.GPL b/COPYING.GPL
new file mode 100644
index 000000000..94a9ed024
--- /dev/null
+++ b/COPYING.GPL
@@ -0,0 +1,674 @@
+ GNU GENERAL PUBLIC LICENSE
+ Version 3, 29 June 2007
+
+ Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+ Preamble
+
+ The GNU General Public License is a free, copyleft license for
+software and other kinds of works.
+
+ The licenses for most software and other practical works are designed
+to take away your freedom to share and change the works. By contrast,
+the GNU General Public License is intended to guarantee your freedom to
+share and change all versions of a program--to make sure it remains free
+software for all its users. We, the Free Software Foundation, use the
+GNU General Public License for most of our software; it applies also to
+any other work released this way by its authors. You can apply it to
+your programs, too.
+
+ When we speak of free software, we are referring to freedom, not
+price. Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+them if you wish), that you receive source code or can get it if you
+want it, that you can change the software or use pieces of it in new
+free programs, and that you know you can do these things.
+
+ To protect your rights, we need to prevent others from denying you
+these rights or asking you to surrender the rights. Therefore, you have
+certain responsibilities if you distribute copies of the software, or if
+you modify it: responsibilities to respect the freedom of others.
+
+ For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must pass on to the recipients the same
+freedoms that you received. You must make sure that they, too, receive
+or can get the source code. And you must show them these terms so they
+know their rights.
+
+ Developers that use the GNU GPL protect your rights with two steps:
+(1) assert copyright on the software, and (2) offer you this License
+giving you legal permission to copy, distribute and/or modify it.
+
+ For the developers' and authors' protection, the GPL clearly explains
+that there is no warranty for this free software. For both users' and
+authors' sake, the GPL requires that modified versions be marked as
+changed, so that their problems will not be attributed erroneously to
+authors of previous versions.
+
+ Some devices are designed to deny users access to install or run
+modified versions of the software inside them, although the manufacturer
+can do so. This is fundamentally incompatible with the aim of
+protecting users' freedom to change the software. The systematic
+pattern of such abuse occurs in the area of products for individuals to
+use, which is precisely where it is most unacceptable. Therefore, we
+have designed this version of the GPL to prohibit the practice for those
+products. If such problems arise substantially in other domains, we
+stand ready to extend this provision to those domains in future versions
+of the GPL, as needed to protect the freedom of users.
+
+ Finally, every program is threatened constantly by software patents.
+States should not allow patents to restrict development and use of
+software on general-purpose computers, but in those that do, we wish to
+avoid the special danger that patents applied to a free program could
+make it effectively proprietary. To prevent this, the GPL assures that
+patents cannot be used to render the program non-free.
+
+ The precise terms and conditions for copying, distribution and
+modification follow.
+
+ TERMS AND CONDITIONS
+
+ 0. Definitions.
+
+ "This License" refers to version 3 of the GNU General Public License.
+
+ "Copyright" also means copyright-like laws that apply to other kinds of
+works, such as semiconductor masks.
+
+ "The Program" refers to any copyrightable work licensed under this
+License. Each licensee is addressed as "you". "Licensees" and
+"recipients" may be individuals or organizations.
+
+ To "modify" a work means to copy from or adapt all or part of the work
+in a fashion requiring copyright permission, other than the making of an
+exact copy. The resulting work is called a "modified version" of the
+earlier work or a work "based on" the earlier work.
+
+ A "covered work" means either the unmodified Program or a work based
+on the Program.
+
+ To "propagate" a work means to do anything with it that, without
+permission, would make you directly or secondarily liable for
+infringement under applicable copyright law, except executing it on a
+computer or modifying a private copy. Propagation includes copying,
+distribution (with or without modification), making available to the
+public, and in some countries other activities as well.
+
+ To "convey" a work means any kind of propagation that enables other
+parties to make or receive copies. Mere interaction with a user through
+a computer network, with no transfer of a copy, is not conveying.
+
+ An interactive user interface displays "Appropriate Legal Notices"
+to the extent that it includes a convenient and prominently visible
+feature that (1) displays an appropriate copyright notice, and (2)
+tells the user that there is no warranty for the work (except to the
+extent that warranties are provided), that licensees may convey the
+work under this License, and how to view a copy of this License. If
+the interface presents a list of user commands or options, such as a
+menu, a prominent item in the list meets this criterion.
+
+ 1. Source Code.
+
+ The "source code" for a work means the preferred form of the work
+for making modifications to it. "Object code" means any non-source
+form of a work.
+
+ A "Standard Interface" means an interface that either is an official
+standard defined by a recognized standards body, or, in the case of
+interfaces specified for a particular programming language, one that
+is widely used among developers working in that language.
+
+ The "System Libraries" of an executable work include anything, other
+than the work as a whole, that (a) is included in the normal form of
+packaging a Major Component, but which is not part of that Major
+Component, and (b) serves only to enable use of the work with that
+Major Component, or to implement a Standard Interface for which an
+implementation is available to the public in source code form. A
+"Major Component", in this context, means a major essential component
+(kernel, window system, and so on) of the specific operating system
+(if any) on which the executable work runs, or a compiler used to
+produce the work, or an object code interpreter used to run it.
+
+ The "Corresponding Source" for a work in object code form means all
+the source code needed to generate, install, and (for an executable
+work) run the object code and to modify the work, including scripts to
+control those activities. However, it does not include the work's
+System Libraries, or general-purpose tools or generally available free
+programs which are used unmodified in performing those activities but
+which are not part of the work. For example, Corresponding Source
+includes interface definition files associated with source files for
+the work, and the source code for shared libraries and dynamically
+linked subprograms that the work is specifically designed to require,
+such as by intimate data communication or control flow between those
+subprograms and other parts of the work.
+
+ The Corresponding Source need not include anything that users
+can regenerate automatically from other parts of the Corresponding
+Source.
+
+ The Corresponding Source for a work in source code form is that
+same work.
+
+ 2. Basic Permissions.
+
+ All rights granted under this License are granted for the term of
+copyright on the Program, and are irrevocable provided the stated
+conditions are met. This License explicitly affirms your unlimited
+permission to run the unmodified Program. The output from running a
+covered work is covered by this License only if the output, given its
+content, constitutes a covered work. This License acknowledges your
+rights of fair use or other equivalent, as provided by copyright law.
+
+ You may make, run and propagate covered works that you do not
+convey, without conditions so long as your license otherwise remains
+in force. You may convey covered works to others for the sole purpose
+of having them make modifications exclusively for you, or provide you
+with facilities for running those works, provided that you comply with
+the terms of this License in conveying all material for which you do
+not control copyright. Those thus making or running the covered works
+for you must do so exclusively on your behalf, under your direction
+and control, on terms that prohibit them from making any copies of
+your copyrighted material outside their relationship with you.
+
+ Conveying under any other circumstances is permitted solely under
+the conditions stated below. Sublicensing is not allowed; section 10
+makes it unnecessary.
+
+ 3. Protecting Users' Legal Rights From Anti-Circumvention Law.
+
+ No covered work shall be deemed part of an effective technological
+measure under any applicable law fulfilling obligations under article
+11 of the WIPO copyright treaty adopted on 20 December 1996, or
+similar laws prohibiting or restricting circumvention of such
+measures.
+
+ When you convey a covered work, you waive any legal power to forbid
+circumvention of technological measures to the extent such circumvention
+is effected by exercising rights under this License with respect to
+the covered work, and you disclaim any intention to limit operation or
+modification of the work as a means of enforcing, against the work's
+users, your or third parties' legal rights to forbid circumvention of
+technological measures.
+
+ 4. Conveying Verbatim Copies.
+
+ You may convey verbatim copies of the Program's source code as you
+receive it, in any medium, provided that you conspicuously and
+appropriately publish on each copy an appropriate copyright notice;
+keep intact all notices stating that this License and any
+non-permissive terms added in accord with section 7 apply to the code;
+keep intact all notices of the absence of any warranty; and give all
+recipients a copy of this License along with the Program.
+
+ You may charge any price or no price for each copy that you convey,
+and you may offer support or warranty protection for a fee.
+
+ 5. Conveying Modified Source Versions.
+
+ You may convey a work based on the Program, or the modifications to
+produce it from the Program, in the form of source code under the
+terms of section 4, provided that you also meet all of these conditions:
+
+ a) The work must carry prominent notices stating that you modified
+ it, and giving a relevant date.
+
+ b) The work must carry prominent notices stating that it is
+ released under this License and any conditions added under section
+ 7. This requirement modifies the requirement in section 4 to
+ "keep intact all notices".
+
+ c) You must license the entire work, as a whole, under this
+ License to anyone who comes into possession of a copy. This
+ License will therefore apply, along with any applicable section 7
+ additional terms, to the whole of the work, and all its parts,
+ regardless of how they are packaged. This License gives no
+ permission to license the work in any other way, but it does not
+ invalidate such permission if you have separately received it.
+
+ d) If the work has interactive user interfaces, each must display
+ Appropriate Legal Notices; however, if the Program has interactive
+ interfaces that do not display Appropriate Legal Notices, your
+ work need not make them do so.
+
+ A compilation of a covered work with other separate and independent
+works, which are not by their nature extensions of the covered work,
+and which are not combined with it such as to form a larger program,
+in or on a volume of a storage or distribution medium, is called an
+"aggregate" if the compilation and its resulting copyright are not
+used to limit the access or legal rights of the compilation's users
+beyond what the individual works permit. Inclusion of a covered work
+in an aggregate does not cause this License to apply to the other
+parts of the aggregate.
+
+ 6. Conveying Non-Source Forms.
+
+ You may convey a covered work in object code form under the terms
+of sections 4 and 5, provided that you also convey the
+machine-readable Corresponding Source under the terms of this License,
+in one of these ways:
+
+ a) Convey the object code in, or embodied in, a physical product
+ (including a physical distribution medium), accompanied by the
+ Corresponding Source fixed on a durable physical medium
+ customarily used for software interchange.
+
+ b) Convey the object code in, or embodied in, a physical product
+ (including a physical distribution medium), accompanied by a
+ written offer, valid for at least three years and valid for as
+ long as you offer spare parts or customer support for that product
+ model, to give anyone who possesses the object code either (1) a
+ copy of the Corresponding Source for all the software in the
+ product that is covered by this License, on a durable physical
+ medium customarily used for software interchange, for a price no
+ more than your reasonable cost of physically performing this
+ conveying of source, or (2) access to copy the
+ Corresponding Source from a network server at no charge.
+
+ c) Convey individual copies of the object code with a copy of the
+ written offer to provide the Corresponding Source. This
+ alternative is allowed only occasionally and noncommercially, and
+ only if you received the object code with such an offer, in accord
+ with subsection 6b.
+
+ d) Convey the object code by offering access from a designated
+ place (gratis or for a charge), and offer equivalent access to the
+ Corresponding Source in the same way through the same place at no
+ further charge. You need not require recipients to copy the
+ Corresponding Source along with the object code. If the place to
+ copy the object code is a network server, the Corresponding Source
+ may be on a different server (operated by you or a third party)
+ that supports equivalent copying facilities, provided you maintain
+ clear directions next to the object code saying where to find the
+ Corresponding Source. Regardless of what server hosts the
+ Corresponding Source, you remain obligated to ensure that it is
+ available for as long as needed to satisfy these requirements.
+
+ e) Convey the object code using peer-to-peer transmission, provided
+ you inform other peers where the object code and Corresponding
+ Source of the work are being offered to the general public at no
+ charge under subsection 6d.
+
+ A separable portion of the object code, whose source code is excluded
+from the Corresponding Source as a System Library, need not be
+included in conveying the object code work.
+
+ A "User Product" is either (1) a "consumer product", which means any
+tangible personal property which is normally used for personal, family,
+or household purposes, or (2) anything designed or sold for incorporation
+into a dwelling. In determining whether a product is a consumer product,
+doubtful cases shall be resolved in favor of coverage. For a particular
+product received by a particular user, "normally used" refers to a
+typical or common use of that class of product, regardless of the status
+of the particular user or of the way in which the particular user
+actually uses, or expects or is expected to use, the product. A product
+is a consumer product regardless of whether the product has substantial
+commercial, industrial or non-consumer uses, unless such uses represent
+the only significant mode of use of the product.
+
+ "Installation Information" for a User Product means any methods,
+procedures, authorization keys, or other information required to install
+and execute modified versions of a covered work in that User Product from
+a modified version of its Corresponding Source. The information must
+suffice to ensure that the continued functioning of the modified object
+code is in no case prevented or interfered with solely because
+modification has been made.
+
+ If you convey an object code work under this section in, or with, or
+specifically for use in, a User Product, and the conveying occurs as
+part of a transaction in which the right of possession and use of the
+User Product is transferred to the recipient in perpetuity or for a
+fixed term (regardless of how the transaction is characterized), the
+Corresponding Source conveyed under this section must be accompanied
+by the Installation Information. But this requirement does not apply
+if neither you nor any third party retains the ability to install
+modified object code on the User Product (for example, the work has
+been installed in ROM).
+
+ The requirement to provide Installation Information does not include a
+requirement to continue to provide support service, warranty, or updates
+for a work that has been modified or installed by the recipient, or for
+the User Product in which it has been modified or installed. Access to a
+network may be denied when the modification itself materially and
+adversely affects the operation of the network or violates the rules and
+protocols for communication across the network.
+
+ Corresponding Source conveyed, and Installation Information provided,
+in accord with this section must be in a format that is publicly
+documented (and with an implementation available to the public in
+source code form), and must require no special password or key for
+unpacking, reading or copying.
+
+ 7. Additional Terms.
+
+ "Additional permissions" are terms that supplement the terms of this
+License by making exceptions from one or more of its conditions.
+Additional permissions that are applicable to the entire Program shall
+be treated as though they were included in this License, to the extent
+that they are valid under applicable law. If additional permissions
+apply only to part of the Program, that part may be used separately
+under those permissions, but the entire Program remains governed by
+this License without regard to the additional permissions.
+
+ When you convey a copy of a covered work, you may at your option
+remove any additional permissions from that copy, or from any part of
+it. (Additional permissions may be written to require their own
+removal in certain cases when you modify the work.) You may place
+additional permissions on material, added by you to a covered work,
+for which you have or can give appropriate copyright permission.
+
+ Notwithstanding any other provision of this License, for material you
+add to a covered work, you may (if authorized by the copyright holders of
+that material) supplement the terms of this License with terms:
+
+ a) Disclaiming warranty or limiting liability differently from the
+ terms of sections 15 and 16 of this License; or
+
+ b) Requiring preservation of specified reasonable legal notices or
+ author attributions in that material or in the Appropriate Legal
+ Notices displayed by works containing it; or
+
+ c) Prohibiting misrepresentation of the origin of that material, or
+ requiring that modified versions of such material be marked in
+ reasonable ways as different from the original version; or
+
+ d) Limiting the use for publicity purposes of names of licensors or
+ authors of the material; or
+
+ e) Declining to grant rights under trademark law for use of some
+ trade names, trademarks, or service marks; or
+
+ f) Requiring indemnification of licensors and authors of that
+ material by anyone who conveys the material (or modified versions of
+ it) with contractual assumptions of liability to the recipient, for
+ any liability that these contractual assumptions directly impose on
+ those licensors and authors.
+
+ All other non-permissive additional terms are considered "further
+restrictions" within the meaning of section 10. If the Program as you
+received it, or any part of it, contains a notice stating that it is
+governed by this License along with a term that is a further
+restriction, you may remove that term. If a license document contains
+a further restriction but permits relicensing or conveying under this
+License, you may add to a covered work material governed by the terms
+of that license document, provided that the further restriction does
+not survive such relicensing or conveying.
+
+ If you add terms to a covered work in accord with this section, you
+must place, in the relevant source files, a statement of the
+additional terms that apply to those files, or a notice indicating
+where to find the applicable terms.
+
+ Additional terms, permissive or non-permissive, may be stated in the
+form of a separately written license, or stated as exceptions;
+the above requirements apply either way.
+
+ 8. Termination.
+
+ You may not propagate or modify a covered work except as expressly
+provided under this License. Any attempt otherwise to propagate or
+modify it is void, and will automatically terminate your rights under
+this License (including any patent licenses granted under the third
+paragraph of section 11).
+
+ However, if you cease all violation of this License, then your
+license from a particular copyright holder is reinstated (a)
+provisionally, unless and until the copyright holder explicitly and
+finally terminates your license, and (b) permanently, if the copyright
+holder fails to notify you of the violation by some reasonable means
+prior to 60 days after the cessation.
+
+ Moreover, your license from a particular copyright holder is
+reinstated permanently if the copyright holder notifies you of the
+violation by some reasonable means, this is the first time you have
+received notice of violation of this License (for any work) from that
+copyright holder, and you cure the violation prior to 30 days after
+your receipt of the notice.
+
+ Termination of your rights under this section does not terminate the
+licenses of parties who have received copies or rights from you under
+this License. If your rights have been terminated and not permanently
+reinstated, you do not qualify to receive new licenses for the same
+material under section 10.
+
+ 9. Acceptance Not Required for Having Copies.
+
+ You are not required to accept this License in order to receive or
+run a copy of the Program. Ancillary propagation of a covered work
+occurring solely as a consequence of using peer-to-peer transmission
+to receive a copy likewise does not require acceptance. However,
+nothing other than this License grants you permission to propagate or
+modify any covered work. These actions infringe copyright if you do
+not accept this License. Therefore, by modifying or propagating a
+covered work, you indicate your acceptance of this License to do so.
+
+ 10. Automatic Licensing of Downstream Recipients.
+
+ Each time you convey a covered work, the recipient automatically
+receives a license from the original licensors, to run, modify and
+propagate that work, subject to this License. You are not responsible
+for enforcing compliance by third parties with this License.
+
+ An "entity transaction" is a transaction transferring control of an
+organization, or substantially all assets of one, or subdividing an
+organization, or merging organizations. If propagation of a covered
+work results from an entity transaction, each party to that
+transaction who receives a copy of the work also receives whatever
+licenses to the work the party's predecessor in interest had or could
+give under the previous paragraph, plus a right to possession of the
+Corresponding Source of the work from the predecessor in interest, if
+the predecessor has it or can get it with reasonable efforts.
+
+ You may not impose any further restrictions on the exercise of the
+rights granted or affirmed under this License. For example, you may
+not impose a license fee, royalty, or other charge for exercise of
+rights granted under this License, and you may not initiate litigation
+(including a cross-claim or counterclaim in a lawsuit) alleging that
+any patent claim is infringed by making, using, selling, offering for
+sale, or importing the Program or any portion of it.
+
+ 11. Patents.
+
+ A "contributor" is a copyright holder who authorizes use under this
+License of the Program or a work on which the Program is based. The
+work thus licensed is called the contributor's "contributor version".
+
+ A contributor's "essential patent claims" are all patent claims
+owned or controlled by the contributor, whether already acquired or
+hereafter acquired, that would be infringed by some manner, permitted
+by this License, of making, using, or selling its contributor version,
+but do not include claims that would be infringed only as a
+consequence of further modification of the contributor version. For
+purposes of this definition, "control" includes the right to grant
+patent sublicenses in a manner consistent with the requirements of
+this License.
+
+ Each contributor grants you a non-exclusive, worldwide, royalty-free
+patent license under the contributor's essential patent claims, to
+make, use, sell, offer for sale, import and otherwise run, modify and
+propagate the contents of its contributor version.
+
+ In the following three paragraphs, a "patent license" is any express
+agreement or commitment, however denominated, not to enforce a patent
+(such as an express permission to practice a patent or covenant not to
+sue for patent infringement). To "grant" such a patent license to a
+party means to make such an agreement or commitment not to enforce a
+patent against the party.
+
+ If you convey a covered work, knowingly relying on a patent license,
+and the Corresponding Source of the work is not available for anyone
+to copy, free of charge and under the terms of this License, through a
+publicly available network server or other readily accessible means,
+then you must either (1) cause the Corresponding Source to be so
+available, or (2) arrange to deprive yourself of the benefit of the
+patent license for this particular work, or (3) arrange, in a manner
+consistent with the requirements of this License, to extend the patent
+license to downstream recipients. "Knowingly relying" means you have
+actual knowledge that, but for the patent license, your conveying the
+covered work in a country, or your recipient's use of the covered work
+in a country, would infringe one or more identifiable patents in that
+country that you have reason to believe are valid.
+
+ If, pursuant to or in connection with a single transaction or
+arrangement, you convey, or propagate by procuring conveyance of, a
+covered work, and grant a patent license to some of the parties
+receiving the covered work authorizing them to use, propagate, modify
+or convey a specific copy of the covered work, then the patent license
+you grant is automatically extended to all recipients of the covered
+work and works based on it.
+
+ A patent license is "discriminatory" if it does not include within
+the scope of its coverage, prohibits the exercise of, or is
+conditioned on the non-exercise of one or more of the rights that are
+specifically granted under this License. You may not convey a covered
+work if you are a party to an arrangement with a third party that is
+in the business of distributing software, under which you make payment
+to the third party based on the extent of your activity of conveying
+the work, and under which the third party grants, to any of the
+parties who would receive the covered work from you, a discriminatory
+patent license (a) in connection with copies of the covered work
+conveyed by you (or copies made from those copies), or (b) primarily
+for and in connection with specific products or compilations that
+contain the covered work, unless you entered into that arrangement,
+or that patent license was granted, prior to 28 March 2007.
+
+ Nothing in this License shall be construed as excluding or limiting
+any implied license or other defenses to infringement that may
+otherwise be available to you under applicable patent law.
+
+ 12. No Surrender of Others' Freedom.
+
+ If conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot convey a
+covered work so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you may
+not convey it at all. For example, if you agree to terms that obligate you
+to collect a royalty for further conveying from those to whom you convey
+the Program, the only way you could satisfy both those terms and this
+License would be to refrain entirely from conveying the Program.
+
+ 13. Use with the GNU Affero General Public License.
+
+ Notwithstanding any other provision of this License, you have
+permission to link or combine any covered work with a work licensed
+under version 3 of the GNU Affero General Public License into a single
+combined work, and to convey the resulting work. The terms of this
+License will continue to apply to the part which is the covered work,
+but the special requirements of the GNU Affero General Public License,
+section 13, concerning interaction through a network will apply to the
+combination as such.
+
+ 14. Revised Versions of this License.
+
+ The Free Software Foundation may publish revised and/or new versions of
+the GNU General Public License from time to time. Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+ Each version is given a distinguishing version number. If the
+Program specifies that a certain numbered version of the GNU General
+Public License "or any later version" applies to it, you have the
+option of following the terms and conditions either of that numbered
+version or of any later version published by the Free Software
+Foundation. If the Program does not specify a version number of the
+GNU General Public License, you may choose any version ever published
+by the Free Software Foundation.
+
+ If the Program specifies that a proxy can decide which future
+versions of the GNU General Public License can be used, that proxy's
+public statement of acceptance of a version permanently authorizes you
+to choose that version for the Program.
+
+ Later license versions may give you additional or different
+permissions. However, no additional obligations are imposed on any
+author or copyright holder as a result of your choosing to follow a
+later version.
+
+ 15. Disclaimer of Warranty.
+
+ THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
+APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
+HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
+OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
+THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
+IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
+ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+ 16. Limitation of Liability.
+
+ IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
+THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
+GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
+USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
+DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
+PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
+EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
+SUCH DAMAGES.
+
+ 17. Interpretation of Sections 15 and 16.
+
+ If the disclaimer of warranty and limitation of liability provided
+above cannot be given local legal effect according to their terms,
+reviewing courts shall apply local law that most closely approximates
+an absolute waiver of all civil liability in connection with the
+Program, unless a warranty or assumption of liability accompanies a
+copy of the Program in return for a fee.
+
+ END OF TERMS AND CONDITIONS
+
+ How to Apply These Terms to Your New Programs
+
+ If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+ To do so, attach the following notices to the program. It is safest
+to attach them to the start of each source file to most effectively
+state the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+ <one line to give the program's name and a brief idea of what it does.>
+ Copyright (C) <year> <name of author>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+Also add information on how to contact you by electronic and paper mail.
+
+ If the program does terminal interaction, make it output a short
+notice like this when it starts in an interactive mode:
+
+ <program> Copyright (C) <year> <name of author>
+ This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+ This is free software, and you are welcome to redistribute it
+ under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License. Of course, your program's commands
+might be different; for a GUI interface, you would use an "about box".
+
+ You should also get your employer (if you work as a programmer) or school,
+if any, to sign a "copyright disclaimer" for the program, if necessary.
+For more information on this, and how to apply and follow the GNU GPL, see
+<http://www.gnu.org/licenses/>.
+
+ The GNU General Public License does not permit incorporating your program
+into proprietary programs. If your program is a subroutine library, you
+may consider it more useful to permit linking proprietary applications with
+the library. If this is what you want to do, use the GNU Lesser General
+Public License instead of this License. But first, please read
+<http://www.gnu.org/philosophy/why-not-lgpl.html>.
diff --git a/COPYING.LGPL b/COPYING.LGPL
new file mode 100644
index 000000000..0e4fa8aaf
--- /dev/null
+++ b/COPYING.LGPL
@@ -0,0 +1,165 @@
+ GNU LESSER GENERAL PUBLIC LICENSE
+ Version 3, 29 June 2007
+
+ Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+
+ This version of the GNU Lesser General Public License incorporates
+the terms and conditions of version 3 of the GNU General Public
+License, supplemented by the additional permissions listed below.
+
+ 0. Additional Definitions.
+
+ As used herein, "this License" refers to version 3 of the GNU Lesser
+General Public License, and the "GNU GPL" refers to version 3 of the GNU
+General Public License.
+
+ "The Library" refers to a covered work governed by this License,
+other than an Application or a Combined Work as defined below.
+
+ An "Application" is any work that makes use of an interface provided
+by the Library, but which is not otherwise based on the Library.
+Defining a subclass of a class defined by the Library is deemed a mode
+of using an interface provided by the Library.
+
+ A "Combined Work" is a work produced by combining or linking an
+Application with the Library. The particular version of the Library
+with which the Combined Work was made is also called the "Linked
+Version".
+
+ The "Minimal Corresponding Source" for a Combined Work means the
+Corresponding Source for the Combined Work, excluding any source code
+for portions of the Combined Work that, considered in isolation, are
+based on the Application, and not on the Linked Version.
+
+ The "Corresponding Application Code" for a Combined Work means the
+object code and/or source code for the Application, including any data
+and utility programs needed for reproducing the Combined Work from the
+Application, but excluding the System Libraries of the Combined Work.
+
+ 1. Exception to Section 3 of the GNU GPL.
+
+ You may convey a covered work under sections 3 and 4 of this License
+without being bound by section 3 of the GNU GPL.
+
+ 2. Conveying Modified Versions.
+
+ If you modify a copy of the Library, and, in your modifications, a
+facility refers to a function or data to be supplied by an Application
+that uses the facility (other than as an argument passed when the
+facility is invoked), then you may convey a copy of the modified
+version:
+
+ a) under this License, provided that you make a good faith effort to
+ ensure that, in the event an Application does not supply the
+ function or data, the facility still operates, and performs
+ whatever part of its purpose remains meaningful, or
+
+ b) under the GNU GPL, with none of the additional permissions of
+ this License applicable to that copy.
+
+ 3. Object Code Incorporating Material from Library Header Files.
+
+ The object code form of an Application may incorporate material from
+a header file that is part of the Library. You may convey such object
+code under terms of your choice, provided that, if the incorporated
+material is not limited to numerical parameters, data structure
+layouts and accessors, or small macros, inline functions and templates
+(ten or fewer lines in length), you do both of the following:
+
+ a) Give prominent notice with each copy of the object code that the
+ Library is used in it and that the Library and its use are
+ covered by this License.
+
+ b) Accompany the object code with a copy of the GNU GPL and this license
+ document.
+
+ 4. Combined Works.
+
+ You may convey a Combined Work under terms of your choice that,
+taken together, effectively do not restrict modification of the
+portions of the Library contained in the Combined Work and reverse
+engineering for debugging such modifications, if you also do each of
+the following:
+
+ a) Give prominent notice with each copy of the Combined Work that
+ the Library is used in it and that the Library and its use are
+ covered by this License.
+
+ b) Accompany the Combined Work with a copy of the GNU GPL and this license
+ document.
+
+ c) For a Combined Work that displays copyright notices during
+ execution, include the copyright notice for the Library among
+ these notices, as well as a reference directing the user to the
+ copies of the GNU GPL and this license document.
+
+ d) Do one of the following:
+
+ 0) Convey the Minimal Corresponding Source under the terms of this
+ License, and the Corresponding Application Code in a form
+ suitable for, and under terms that permit, the user to
+ recombine or relink the Application with a modified version of
+ the Linked Version to produce a modified Combined Work, in the
+ manner specified by section 6 of the GNU GPL for conveying
+ Corresponding Source.
+
+ 1) Use a suitable shared library mechanism for linking with the
+ Library. A suitable mechanism is one that (a) uses at run time
+ a copy of the Library already present on the user's computer
+ system, and (b) will operate properly with a modified version
+ of the Library that is interface-compatible with the Linked
+ Version.
+
+ e) Provide Installation Information, but only if you would otherwise
+ be required to provide such information under section 6 of the
+ GNU GPL, and only to the extent that such information is
+ necessary to install and execute a modified version of the
+ Combined Work produced by recombining or relinking the
+ Application with a modified version of the Linked Version. (If
+ you use option 4d0, the Installation Information must accompany
+ the Minimal Corresponding Source and Corresponding Application
+ Code. If you use option 4d1, you must provide the Installation
+ Information in the manner specified by section 6 of the GNU GPL
+ for conveying Corresponding Source.)
+
+ 5. Combined Libraries.
+
+ You may place library facilities that are a work based on the
+Library side by side in a single library together with other library
+facilities that are not Applications and are not covered by this
+License, and convey such a combined library under terms of your
+choice, if you do both of the following:
+
+ a) Accompany the combined library with a copy of the same work based
+ on the Library, uncombined with any other library facilities,
+ conveyed under the terms of this License.
+
+ b) Give prominent notice with the combined library that part of it
+ is a work based on the Library, and explaining where to find the
+ accompanying uncombined form of the same work.
+
+ 6. Revised Versions of the GNU Lesser General Public License.
+
+ The Free Software Foundation may publish revised and/or new versions
+of the GNU Lesser General Public License from time to time. Such new
+versions will be similar in spirit to the present version, but may
+differ in detail to address new problems or concerns.
+
+ Each version is given a distinguishing version number. If the
+Library as you received it specifies that a certain numbered version
+of the GNU Lesser General Public License "or any later version"
+applies to it, you have the option of following the terms and
+conditions either of that published version or of any later version
+published by the Free Software Foundation. If the Library as you
+received it does not specify a version number of the GNU Lesser
+General Public License, you may choose any version of the GNU Lesser
+General Public License ever published by the Free Software Foundation.
+
+ If the Library as you received it specifies that a proxy can decide
+whether future versions of the GNU Lesser General Public License shall
+apply, that proxy's public statement of acceptance of any version is
+permanent authorization for you to choose that version for the
+Library.
diff --git a/COPYING.MINPACK b/COPYING.MINPACK
new file mode 100644
index 000000000..11d8a9a6c
--- /dev/null
+++ b/COPYING.MINPACK
@@ -0,0 +1,52 @@
+Minpack Copyright Notice (1999) University of Chicago. All rights reserved
+
+Redistribution and use in source and binary forms, with or
+without modification, are permitted provided that the
+following conditions are met:
+
+1. Redistributions of source code must retain the above
+copyright notice, this list of conditions and the following
+disclaimer.
+
+2. 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.
+
+3. The end-user documentation included with the
+redistribution, if any, must include the following
+acknowledgment:
+
+ "This product includes software developed by the
+ University of Chicago, as Operator of Argonne National
+ Laboratory.
+
+Alternately, this acknowledgment may appear in the software
+itself, if and wherever such third-party acknowledgments
+normally appear.
+
+4. WARRANTY DISCLAIMER. THE SOFTWARE IS SUPPLIED "AS IS"
+WITHOUT WARRANTY OF ANY KIND. THE COPYRIGHT HOLDER, THE
+UNITED STATES, THE UNITED STATES DEPARTMENT OF ENERGY, AND
+THEIR EMPLOYEES: (1) DISCLAIM ANY WARRANTIES, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO ANY IMPLIED WARRANTIES
+OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, TITLE
+OR NON-INFRINGEMENT, (2) DO NOT ASSUME ANY LEGAL LIABILITY
+OR RESPONSIBILITY FOR THE ACCURACY, COMPLETENESS, OR
+USEFULNESS OF THE SOFTWARE, (3) DO NOT REPRESENT THAT USE OF
+THE SOFTWARE WOULD NOT INFRINGE PRIVATELY OWNED RIGHTS, (4)
+DO NOT WARRANT THAT THE SOFTWARE WILL FUNCTION
+UNINTERRUPTED, THAT IT IS ERROR-FREE OR THAT ANY ERRORS WILL
+BE CORRECTED.
+
+5. LIMITATION OF LIABILITY. IN NO EVENT WILL THE COPYRIGHT
+HOLDER, THE UNITED STATES, THE UNITED STATES DEPARTMENT OF
+ENERGY, OR THEIR EMPLOYEES: BE LIABLE FOR ANY INDIRECT,
+INCIDENTAL, CONSEQUENTIAL, SPECIAL OR PUNITIVE DAMAGES OF
+ANY KIND OR NATURE, INCLUDING BUT NOT LIMITED TO LOSS OF
+PROFITS OR LOSS OF DATA, FOR ANY REASON WHATSOEVER, WHETHER
+SUCH LIABILITY IS ASSERTED ON THE BASIS OF CONTRACT, TORT
+(INCLUDING NEGLIGENCE OR STRICT LIABILITY), OR OTHERWISE,
+EVEN IF ANY OF SAID PARTIES HAS BEEN WARNED OF THE
+POSSIBILITY OF SUCH LOSS OR DAMAGES.
+
diff --git a/COPYING.MPL2 b/COPYING.MPL2
new file mode 100644
index 000000000..14e2f777f
--- /dev/null
+++ b/COPYING.MPL2
@@ -0,0 +1,373 @@
+Mozilla Public License Version 2.0
+==================================
+
+1. Definitions
+--------------
+
+1.1. "Contributor"
+ means each individual or legal entity that creates, contributes to
+ the creation of, or owns Covered Software.
+
+1.2. "Contributor Version"
+ means the combination of the Contributions of others (if any) used
+ by a Contributor and that particular Contributor's Contribution.
+
+1.3. "Contribution"
+ means Covered Software of a particular Contributor.
+
+1.4. "Covered Software"
+ means Source Code Form to which the initial Contributor has attached
+ the notice in Exhibit A, the Executable Form of such Source Code
+ Form, and Modifications of such Source Code Form, in each case
+ including portions thereof.
+
+1.5. "Incompatible With Secondary Licenses"
+ means
+
+ (a) that the initial Contributor has attached the notice described
+ in Exhibit B to the Covered Software; or
+
+ (b) that the Covered Software was made available under the terms of
+ version 1.1 or earlier of the License, but not also under the
+ terms of a Secondary License.
+
+1.6. "Executable Form"
+ means any form of the work other than Source Code Form.
+
+1.7. "Larger Work"
+ means a work that combines Covered Software with other material, in
+ a separate file or files, that is not Covered Software.
+
+1.8. "License"
+ means this document.
+
+1.9. "Licensable"
+ means having the right to grant, to the maximum extent possible,
+ whether at the time of the initial grant or subsequently, any and
+ all of the rights conveyed by this License.
+
+1.10. "Modifications"
+ means any of the following:
+
+ (a) any file in Source Code Form that results from an addition to,
+ deletion from, or modification of the contents of Covered
+ Software; or
+
+ (b) any new file in Source Code Form that contains any Covered
+ Software.
+
+1.11. "Patent Claims" of a Contributor
+ means any patent claim(s), including without limitation, method,
+ process, and apparatus claims, in any patent Licensable by such
+ Contributor that would be infringed, but for the grant of the
+ License, by the making, using, selling, offering for sale, having
+ made, import, or transfer of either its Contributions or its
+ Contributor Version.
+
+1.12. "Secondary License"
+ means either the GNU General Public License, Version 2.0, the GNU
+ Lesser General Public License, Version 2.1, the GNU Affero General
+ Public License, Version 3.0, or any later versions of those
+ licenses.
+
+1.13. "Source Code Form"
+ means the form of the work preferred for making modifications.
+
+1.14. "You" (or "Your")
+ means an individual or a legal entity exercising rights under this
+ License. For legal entities, "You" includes any entity that
+ controls, is controlled by, or is under common control with You. For
+ purposes of this definition, "control" means (a) the power, direct
+ or indirect, to cause the direction or management of such entity,
+ whether by contract or otherwise, or (b) ownership of more than
+ fifty percent (50%) of the outstanding shares or beneficial
+ ownership of such entity.
+
+2. License Grants and Conditions
+--------------------------------
+
+2.1. Grants
+
+Each Contributor hereby grants You a world-wide, royalty-free,
+non-exclusive license:
+
+(a) under intellectual property rights (other than patent or trademark)
+ Licensable by such Contributor to use, reproduce, make available,
+ modify, display, perform, distribute, and otherwise exploit its
+ Contributions, either on an unmodified basis, with Modifications, or
+ as part of a Larger Work; and
+
+(b) under Patent Claims of such Contributor to make, use, sell, offer
+ for sale, have made, import, and otherwise transfer either its
+ Contributions or its Contributor Version.
+
+2.2. Effective Date
+
+The licenses granted in Section 2.1 with respect to any Contribution
+become effective for each Contribution on the date the Contributor first
+distributes such Contribution.
+
+2.3. Limitations on Grant Scope
+
+The licenses granted in this Section 2 are the only rights granted under
+this License. No additional rights or licenses will be implied from the
+distribution or licensing of Covered Software under this License.
+Notwithstanding Section 2.1(b) above, no patent license is granted by a
+Contributor:
+
+(a) for any code that a Contributor has removed from Covered Software;
+ or
+
+(b) for infringements caused by: (i) Your and any other third party's
+ modifications of Covered Software, or (ii) the combination of its
+ Contributions with other software (except as part of its Contributor
+ Version); or
+
+(c) under Patent Claims infringed by Covered Software in the absence of
+ its Contributions.
+
+This License does not grant any rights in the trademarks, service marks,
+or logos of any Contributor (except as may be necessary to comply with
+the notice requirements in Section 3.4).
+
+2.4. Subsequent Licenses
+
+No Contributor makes additional grants as a result of Your choice to
+distribute the Covered Software under a subsequent version of this
+License (see Section 10.2) or under the terms of a Secondary License (if
+permitted under the terms of Section 3.3).
+
+2.5. Representation
+
+Each Contributor represents that the Contributor believes its
+Contributions are its original creation(s) or it has sufficient rights
+to grant the rights to its Contributions conveyed by this License.
+
+2.6. Fair Use
+
+This License is not intended to limit any rights You have under
+applicable copyright doctrines of fair use, fair dealing, or other
+equivalents.
+
+2.7. Conditions
+
+Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted
+in Section 2.1.
+
+3. Responsibilities
+-------------------
+
+3.1. Distribution of Source Form
+
+All distribution of Covered Software in Source Code Form, including any
+Modifications that You create or to which You contribute, must be under
+the terms of this License. You must inform recipients that the Source
+Code Form of the Covered Software is governed by the terms of this
+License, and how they can obtain a copy of this License. You may not
+attempt to alter or restrict the recipients' rights in the Source Code
+Form.
+
+3.2. Distribution of Executable Form
+
+If You distribute Covered Software in Executable Form then:
+
+(a) such Covered Software must also be made available in Source Code
+ Form, as described in Section 3.1, and You must inform recipients of
+ the Executable Form how they can obtain a copy of such Source Code
+ Form by reasonable means in a timely manner, at a charge no more
+ than the cost of distribution to the recipient; and
+
+(b) You may distribute such Executable Form under the terms of this
+ License, or sublicense it under different terms, provided that the
+ license for the Executable Form does not attempt to limit or alter
+ the recipients' rights in the Source Code Form under this License.
+
+3.3. Distribution of a Larger Work
+
+You may create and distribute a Larger Work under terms of Your choice,
+provided that You also comply with the requirements of this License for
+the Covered Software. If the Larger Work is a combination of Covered
+Software with a work governed by one or more Secondary Licenses, and the
+Covered Software is not Incompatible With Secondary Licenses, this
+License permits You to additionally distribute such Covered Software
+under the terms of such Secondary License(s), so that the recipient of
+the Larger Work may, at their option, further distribute the Covered
+Software under the terms of either this License or such Secondary
+License(s).
+
+3.4. Notices
+
+You may not remove or alter the substance of any license notices
+(including copyright notices, patent notices, disclaimers of warranty,
+or limitations of liability) contained within the Source Code Form of
+the Covered Software, except that You may alter any license notices to
+the extent required to remedy known factual inaccuracies.
+
+3.5. Application of Additional Terms
+
+You may choose to offer, and to charge a fee for, warranty, support,
+indemnity or liability obligations to one or more recipients of Covered
+Software. However, You may do so only on Your own behalf, and not on
+behalf of any Contributor. You must make it absolutely clear that any
+such warranty, support, indemnity, or liability obligation is offered by
+You alone, and You hereby agree to indemnify every Contributor for any
+liability incurred by such Contributor as a result of warranty, support,
+indemnity or liability terms You offer. You may include additional
+disclaimers of warranty and limitations of liability specific to any
+jurisdiction.
+
+4. Inability to Comply Due to Statute or Regulation
+---------------------------------------------------
+
+If it is impossible for You to comply with any of the terms of this
+License with respect to some or all of the Covered Software due to
+statute, judicial order, or regulation then You must: (a) comply with
+the terms of this License to the maximum extent possible; and (b)
+describe the limitations and the code they affect. Such description must
+be placed in a text file included with all distributions of the Covered
+Software under this License. Except to the extent prohibited by statute
+or regulation, such description must be sufficiently detailed for a
+recipient of ordinary skill to be able to understand it.
+
+5. Termination
+--------------
+
+5.1. The rights granted under this License will terminate automatically
+if You fail to comply with any of its terms. However, if You become
+compliant, then the rights granted under this License from a particular
+Contributor are reinstated (a) provisionally, unless and until such
+Contributor explicitly and finally terminates Your grants, and (b) on an
+ongoing basis, if such Contributor fails to notify You of the
+non-compliance by some reasonable means prior to 60 days after You have
+come back into compliance. Moreover, Your grants from a particular
+Contributor are reinstated on an ongoing basis if such Contributor
+notifies You of the non-compliance by some reasonable means, this is the
+first time You have received notice of non-compliance with this License
+from such Contributor, and You become compliant prior to 30 days after
+Your receipt of the notice.
+
+5.2. If You initiate litigation against any entity by asserting a patent
+infringement claim (excluding declaratory judgment actions,
+counter-claims, and cross-claims) alleging that a Contributor Version
+directly or indirectly infringes any patent, then the rights granted to
+You by any and all Contributors for the Covered Software under Section
+2.1 of this License shall terminate.
+
+5.3. In the event of termination under Sections 5.1 or 5.2 above, all
+end user license agreements (excluding distributors and resellers) which
+have been validly granted by You or Your distributors under this License
+prior to termination shall survive termination.
+
+************************************************************************
+* *
+* 6. Disclaimer of Warranty *
+* ------------------------- *
+* *
+* Covered Software is provided under this License on an "as is" *
+* basis, without warranty of any kind, either expressed, implied, or *
+* statutory, including, without limitation, warranties that the *
+* Covered Software is free of defects, merchantable, fit for a *
+* particular purpose or non-infringing. The entire risk as to the *
+* quality and performance of the Covered Software is with You. *
+* Should any Covered Software prove defective in any respect, You *
+* (not any Contributor) assume the cost of any necessary servicing, *
+* repair, or correction. This disclaimer of warranty constitutes an *
+* essential part of this License. No use of any Covered Software is *
+* authorized under this License except under this disclaimer. *
+* *
+************************************************************************
+
+************************************************************************
+* *
+* 7. Limitation of Liability *
+* -------------------------- *
+* *
+* Under no circumstances and under no legal theory, whether tort *
+* (including negligence), contract, or otherwise, shall any *
+* Contributor, or anyone who distributes Covered Software as *
+* permitted above, be liable to You for any direct, indirect, *
+* special, incidental, or consequential damages of any character *
+* including, without limitation, damages for lost profits, loss of *
+* goodwill, work stoppage, computer failure or malfunction, or any *
+* and all other commercial damages or losses, even if such party *
+* shall have been informed of the possibility of such damages. This *
+* limitation of liability shall not apply to liability for death or *
+* personal injury resulting from such party's negligence to the *
+* extent applicable law prohibits such limitation. Some *
+* jurisdictions do not allow the exclusion or limitation of *
+* incidental or consequential damages, so this exclusion and *
+* limitation may not apply to You. *
+* *
+************************************************************************
+
+8. Litigation
+-------------
+
+Any litigation relating to this License may be brought only in the
+courts of a jurisdiction where the defendant maintains its principal
+place of business and such litigation shall be governed by laws of that
+jurisdiction, without reference to its conflict-of-law provisions.
+Nothing in this Section shall prevent a party's ability to bring
+cross-claims or counter-claims.
+
+9. Miscellaneous
+----------------
+
+This License represents the complete agreement concerning the subject
+matter hereof. If any provision of this License is held to be
+unenforceable, such provision shall be reformed only to the extent
+necessary to make it enforceable. Any law or regulation which provides
+that the language of a contract shall be construed against the drafter
+shall not be used to construe this License against a Contributor.
+
+10. Versions of the License
+---------------------------
+
+10.1. New Versions
+
+Mozilla Foundation is the license steward. Except as provided in Section
+10.3, no one other than the license steward has the right to modify or
+publish new versions of this License. Each version will be given a
+distinguishing version number.
+
+10.2. Effect of New Versions
+
+You may distribute the Covered Software under the terms of the version
+of the License under which You originally received the Covered Software,
+or under the terms of any subsequent version published by the license
+steward.
+
+10.3. Modified Versions
+
+If you create software not governed by this License, and you want to
+create a new license for such software, you may create and use a
+modified version of this License if you rename the license and remove
+any references to the name of the license steward (except to note that
+such modified license differs from this License).
+
+10.4. Distributing Source Code Form that is Incompatible With Secondary
+Licenses
+
+If You choose to distribute Source Code Form that is Incompatible With
+Secondary Licenses under the terms of this version of the License, the
+notice described in Exhibit B of this License must be attached.
+
+Exhibit A - Source Code Form License Notice
+-------------------------------------------
+
+ This Source Code Form is subject to the terms of the Mozilla Public
+ License, v. 2.0. If a copy of the MPL was not distributed with this
+ file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+If it is not possible or desirable to put the notice in a particular
+file, then You may include the notice in a location (such as a LICENSE
+file in a relevant directory) where a recipient would be likely to look
+for such a notice.
+
+You may add additional accurate notices of copyright ownership.
+
+Exhibit B - "Incompatible With Secondary Licenses" Notice
+---------------------------------------------------------
+
+ This Source Code Form is "Incompatible With Secondary Licenses", as
+ defined by the Mozilla Public License, v. 2.0.
diff --git a/COPYING.README b/COPYING.README
new file mode 100644
index 000000000..1d706784d
--- /dev/null
+++ b/COPYING.README
@@ -0,0 +1,15 @@
+Eigen is primarily MPL2 licensed. See COPYING.MPL2 and these links:
+ http://www.mozilla.org/MPL/2.0/
+ http://www.mozilla.org/MPL/2.0/FAQ.html
+
+Some files contain third-party code under BSD or LGPL licenses, whence the other
+COPYING.* files here.
+
+If you want to guarantee that the Eigen code that you are #including is licensed
+under the MPL2 and possibly more permissive licenses (like BSD), #define this
+preprocessor symbol:
+ EIGEN_MPL2_ONLY
+For example, with most compilers, you could add this to your project CXXFLAGS:
+ -DEIGEN_MPL2_ONLY
+This will cause a compilation error to be generated if you #include any code that is
+LGPL licensed.
diff --git a/CTestConfig.cmake b/CTestConfig.cmake
new file mode 100644
index 000000000..a5a4eb012
--- /dev/null
+++ b/CTestConfig.cmake
@@ -0,0 +1,13 @@
+## This file should be placed in the root directory of your project.
+## Then modify the CMakeLists.txt file in the root directory of your
+## project to incorporate the testing dashboard.
+## # The following are required to uses Dart and the Cdash dashboard
+## ENABLE_TESTING()
+## INCLUDE(CTest)
+set(CTEST_PROJECT_NAME "Eigen")
+set(CTEST_NIGHTLY_START_TIME "00:00:00 UTC")
+
+set(CTEST_DROP_METHOD "http")
+set(CTEST_DROP_SITE "manao.inria.fr")
+set(CTEST_DROP_LOCATION "/CDash/submit.php?project=Eigen")
+set(CTEST_DROP_SITE_CDASH TRUE)
diff --git a/CTestCustom.cmake.in b/CTestCustom.cmake.in
new file mode 100644
index 000000000..3b2bacaa0
--- /dev/null
+++ b/CTestCustom.cmake.in
@@ -0,0 +1,4 @@
+
+## A tribute to Dynamic!
+set(CTEST_CUSTOM_MAXIMUM_NUMBER_OF_WARNINGS "33331")
+set(CTEST_CUSTOM_MAXIMUM_NUMBER_OF_ERRORS "33331")
diff --git a/CleanSpec.mk b/CleanSpec.mk
new file mode 100644
index 000000000..a9baf343e
--- /dev/null
+++ b/CleanSpec.mk
@@ -0,0 +1,52 @@
+# Copyright (C) 2007 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+# If you don't need to do a full clean build but would like to touch
+# a file or delete some intermediate files, add a clean step to the end
+# of the list. These steps will only be run once, if they haven't been
+# run before.
+#
+# E.g.:
+# $(call add-clean-step, touch -c external/sqlite/sqlite3.h)
+# $(call add-clean-step, rm -rf $(PRODUCT_OUT)/obj/STATIC_LIBRARIES/libz_intermediates)
+#
+# Always use "touch -c" and "rm -f" or "rm -rf" to gracefully deal with
+# files that are missing or have been moved.
+#
+# Use $(PRODUCT_OUT) to get to the "out/target/product/blah/" directory.
+# Use $(OUT_DIR) to refer to the "out" directory.
+#
+# If you need to re-do something that's already mentioned, just copy
+# the command and add it to the bottom of the list. E.g., if a change
+# that you made last week required touching a file and a change you
+# made today requires touching the same file, just copy the old
+# touch step and add it to the end of the list.
+#
+# ************************************************
+# NEWER CLEAN STEPS MUST BE AT THE END OF THE LIST
+# ************************************************
+
+# For example:
+#$(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/APPS/AndroidTests_intermediates)
+#$(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/JAVA_LIBRARIES/core_intermediates)
+#$(call add-clean-step, find $(OUT_DIR) -type f -name "IGTalkSession*" -print0 | xargs -0 rm -f)
+#$(call add-clean-step, rm -rf $(PRODUCT_OUT)/data/*)
+
+# ************************************************
+# NEWER CLEAN STEPS MUST BE AT THE END OF THE LIST
+# ************************************************
+
+# This empty file is here solely for the purpose of optimizing the Android build
+# Please keep it there, and empty, thanks.
diff --git a/Eigen/Array b/Eigen/Array
new file mode 100644
index 000000000..3d004fb69
--- /dev/null
+++ b/Eigen/Array
@@ -0,0 +1,11 @@
+#ifndef EIGEN_ARRAY_MODULE_H
+#define EIGEN_ARRAY_MODULE_H
+
+// include Core first to handle Eigen2 support macros
+#include "Core"
+
+#ifndef EIGEN2_SUPPORT
+ #error The Eigen/Array header does no longer exist in Eigen3. All that functionality has moved to Eigen/Core.
+#endif
+
+#endif // EIGEN_ARRAY_MODULE_H
diff --git a/Eigen/CMakeLists.txt b/Eigen/CMakeLists.txt
new file mode 100644
index 000000000..a92dd6f6c
--- /dev/null
+++ b/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
+ )
+
+add_subdirectory(src)
diff --git a/Eigen/Cholesky b/Eigen/Cholesky
new file mode 100644
index 000000000..f727f5d89
--- /dev/null
+++ b/Eigen/Cholesky
@@ -0,0 +1,32 @@
+#ifndef EIGEN_CHOLESKY_MODULE_H
+#define EIGEN_CHOLESKY_MODULE_H
+
+#include "Core"
+
+#include "src/Core/util/DisableStupidWarnings.h"
+
+/** \defgroup Cholesky_Module Cholesky module
+ *
+ *
+ *
+ * This module provides two variants of the Cholesky decomposition for selfadjoint (hermitian) matrices.
+ * Those decompositions are accessible via the following MatrixBase methods:
+ * - MatrixBase::llt(),
+ * - MatrixBase::ldlt()
+ *
+ * \code
+ * #include <Eigen/Cholesky>
+ * \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"
+#endif
+
+#include "src/Core/util/ReenableStupidWarnings.h"
+
+#endif // EIGEN_CHOLESKY_MODULE_H
+/* vim: set filetype=cpp et sw=2 ts=2 ai: */
diff --git a/Eigen/CholmodSupport b/Eigen/CholmodSupport
new file mode 100644
index 000000000..745b884e7
--- /dev/null
+++ b/Eigen/CholmodSupport
@@ -0,0 +1,45 @@
+#ifndef EIGEN_CHOLMODSUPPORT_MODULE_H
+#define EIGEN_CHOLMODSUPPORT_MODULE_H
+
+#include "SparseCore"
+
+#include "src/Core/util/DisableStupidWarnings.h"
+
+extern "C" {
+ #include <cholmod.h>
+}
+
+/** \ingroup Support_modules
+ * \defgroup CholmodSupport_Module CholmodSupport module
+ *
+ * This module provides an interface to the Cholmod library which is part of the <a href="http://www.cise.ufl.edu/research/sparse/SuiteSparse/">suitesparse</a> 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 <Eigen/CholmodSupport>
+ * \endcode
+ *
+ * In order to use this module, the cholmod headers must be accessible from the include paths, and your binary must be linked to the cholmod library and its dependencies.
+ * The dependencies depend on how cholmod has been compiled.
+ * For a cmake based project, you can use our FindCholmod.cmake module to help you in this task.
+ *
+ */
+
+#include "src/misc/Solve.h"
+#include "src/misc/SparseSolve.h"
+
+#include "src/CholmodSupport/CholmodSupport.h"
+
+
+#include "src/Core/util/ReenableStupidWarnings.h"
+
+#endif // EIGEN_CHOLMODSUPPORT_MODULE_H
+
diff --git a/Eigen/Core b/Eigen/Core
new file mode 100644
index 000000000..d48017022
--- /dev/null
+++ b/Eigen/Core
@@ -0,0 +1,366 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra.
+//
+// Copyright (C) 2008 Gael Guennebaud <gael.guennebaud@inria.fr>
+// Copyright (C) 2007-2011 Benoit Jacob <jacob.benoit.1@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 EIGEN_CORE_H
+#define EIGEN_CORE_H
+
+// first thing Eigen does: stop the compiler from committing suicide
+#include "src/Core/util/DisableStupidWarnings.h"
+
+// 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.
+#include "src/Core/util/Macros.h"
+
+#include <complex>
+
+// this include file manages BLAS and MKL related macros
+// and inclusion of their respective header files
+#include "src/Core/util/MKL_support.h"
+
+// if alignment is disabled, then disable vectorization. Note: EIGEN_ALIGN is the proper check, it takes into
+// account both the user's will (EIGEN_DONT_ALIGN) and our own platform checks
+#if !EIGEN_ALIGN
+ #ifndef EIGEN_DONT_VECTORIZE
+ #define EIGEN_DONT_VECTORIZE
+ #endif
+#endif
+
+#ifdef _MSC_VER
+ #include <malloc.h> // for _aligned_malloc -- need it regardless of whether vectorization is enabled
+ #if (_MSC_VER >= 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)
+ #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__) || EIGEN_GNUC_AT_LEAST(4,2) )
+ #define EIGEN_SSE2_ON_NON_MSVC_BUT_NOT_OLD_GCC
+ #endif
+#endif
+
+#ifndef EIGEN_DONT_VECTORIZE
+
+ #if defined (EIGEN_SSE2_ON_NON_MSVC_BUT_NOT_OLD_GCC) || defined(EIGEN_SSE2_ON_MSVC_2008_OR_LATER)
+
+ // Defines symbols for compile-time detection of which instructions are
+ // used.
+ // EIGEN_VECTORIZE_YY is defined if and only if the instruction set YY is used
+ #define EIGEN_VECTORIZE
+ #define EIGEN_VECTORIZE_SSE
+ #define EIGEN_VECTORIZE_SSE2
+
+ // Detect sse3/ssse3/sse4:
+ // gcc and icc defines __SSE3__, ...
+ // there is no way to know about this on msvc. You can define EIGEN_VECTORIZE_SSE* if you
+ // want to force the use of those instructions with msvc.
+ #ifdef __SSE3__
+ #define EIGEN_VECTORIZE_SSE3
+ #endif
+ #ifdef __SSSE3__
+ #define EIGEN_VECTORIZE_SSSE3
+ #endif
+ #ifdef __SSE4_1__
+ #define EIGEN_VECTORIZE_SSE4_1
+ #endif
+ #ifdef __SSE4_2__
+ #define EIGEN_VECTORIZE_SSE4_2
+ #endif
+
+ // include files
+
+ // This extern "C" works around a MINGW-w64 compilation issue
+ // https://sourceforge.net/tracker/index.php?func=detail&aid=3018394&group_id=202880&atid=983354
+ // In essence, intrin.h is included by windows.h and also declares intrinsics (just as emmintrin.h etc. below do).
+ // However, intrin.h uses an extern "C" declaration, and g++ thus complains of duplicate declarations
+ // with conflicting linkage. The linkage for intrinsics doesn't matter, but at that stage the compiler doesn't know;
+ // so, to avoid compile errors when windows.h is included after Eigen/Core, ensure intrinsics are extern "C" here too.
+ // notice that since these are C headers, the extern "C" is theoretically needed anyways.
+ extern "C" {
+ #include <emmintrin.h>
+ #include <xmmintrin.h>
+ #ifdef EIGEN_VECTORIZE_SSE3
+ #include <pmmintrin.h>
+ #endif
+ #ifdef EIGEN_VECTORIZE_SSSE3
+ #include <tmmintrin.h>
+ #endif
+ #ifdef EIGEN_VECTORIZE_SSE4_1
+ #include <smmintrin.h>
+ #endif
+ #ifdef EIGEN_VECTORIZE_SSE4_2
+ #include <nmmintrin.h>
+ #endif
+ } // end extern "C"
+ #elif defined __ALTIVEC__
+ #define EIGEN_VECTORIZE
+ #define EIGEN_VECTORIZE_ALTIVEC
+ #include <altivec.h>
+ // We need to #undef all these ugly tokens defined in <altivec.h>
+ // => use __vector instead of vector
+ #undef bool
+ #undef vector
+ #undef pixel
+ #elif defined __ARM_NEON__
+ #define EIGEN_VECTORIZE
+ #define EIGEN_VECTORIZE_NEON
+ #include <arm_neon.h>
+ #endif
+#endif
+
+#if (defined _OPENMP) && (!defined EIGEN_DONT_PARALLELIZE)
+ #define EIGEN_HAS_OPENMP
+#endif
+
+#ifdef EIGEN_HAS_OPENMP
+#include <omp.h>
+#endif
+
+// MSVC for windows mobile does not have the errno.h file
+#if !(defined(_MSC_VER) && defined(_WIN32_WCE)) && !defined(__ARMCC_VERSION)
+#define EIGEN_HAS_ERRNO
+#endif
+
+#ifdef EIGEN_HAS_ERRNO
+#include <cerrno>
+#endif
+#include <cstddef>
+#include <cstdlib>
+#include <cmath>
+#include <cassert>
+#include <functional>
+#include <iosfwd>
+#include <cstring>
+#include <string>
+#include <limits>
+#include <climits> // for CHAR_BIT
+// for min/max:
+#include <algorithm>
+
+// for outputting debug info
+#ifdef EIGEN_DEBUG_ASSIGN
+#include <iostream>
+#endif
+
+// required for __cpuid, needs to be included after cmath
+#if defined(_MSC_VER) && (defined(_M_IX86)||defined(_M_X64))
+ #include <intrin.h>
+#endif
+
+#if defined(_CPPUNWIND) || defined(__EXCEPTIONS)
+ #define EIGEN_EXCEPTIONS
+#endif
+
+#ifdef EIGEN_EXCEPTIONS
+ #include <new>
+#endif
+
+/** \brief Namespace containing all symbols from the %Eigen library. */
+namespace Eigen {
+
+inline static const char *SimdInstructionSetsInUse(void) {
+#if 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";
+#elif defined(EIGEN_VECTORIZE_SSSE3)
+ return "SSE, SSE2, SSE3, SSSE3";
+#elif defined(EIGEN_VECTORIZE_SSE3)
+ return "SSE, SSE2, SSE3";
+#elif defined(EIGEN_VECTORIZE_SSE2)
+ return "SSE, SSE2";
+#elif defined(EIGEN_VECTORIZE_ALTIVEC)
+ return "AltiVec";
+#elif defined(EIGEN_VECTORIZE_NEON)
+ return "ARM NEON";
+#else
+ return "None";
+#endif
+}
+
+} // 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
+#endif
+
+#ifdef EIGEN2_SUPPORT
+#undef minor
+#endif
+
+// 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
+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
+ * and much more...
+ *
+ * \code
+ * #include <Eigen/Core>
+ * \endcode
+ */
+
+/** \defgroup Support_modules Support modules [category]
+ * Category of modules which add support for external libraries.
+ */
+
+#include "src/Core/util/Constants.h"
+#include "src/Core/util/ForwardDeclarations.h"
+#include "src/Core/util/Meta.h"
+#include "src/Core/util/XprHelper.h"
+#include "src/Core/util/StaticAssert.h"
+#include "src/Core/util/Memory.h"
+
+#include "src/Core/NumTraits.h"
+#include "src/Core/MathFunctions.h"
+#include "src/Core/GenericPacketMath.h"
+
+#if 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/AltiVec/PacketMath.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/Complex.h"
+#endif
+
+#include "src/Core/arch/Default/Settings.h"
+
+#include "src/Core/Functors.h"
+#include "src/Core/DenseCoeffsBase.h"
+#include "src/Core/DenseBase.h"
+#include "src/Core/MatrixBase.h"
+#include "src/Core/EigenBase.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/util/BlasUtil.h"
+#include "src/Core/DenseStorage.h"
+#include "src/Core/NestByValue.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/CwiseBinaryOp.h"
+#include "src/Core/CwiseUnaryOp.h"
+#include "src/Core/CwiseNullaryOp.h"
+#include "src/Core/CwiseUnaryView.h"
+#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/Map.h"
+#include "src/Core/Block.h"
+#include "src/Core/VectorBlock.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/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/products/GeneralMatrixVector.h"
+#include "src/Core/products/GeneralMatrixMatrix.h"
+#include "src/Core/SolveTriangular.h"
+#include "src/Core/products/GeneralMatrixMatrixTriangular.h"
+#include "src/Core/products/SelfadjointMatrixVector.h"
+#include "src/Core/products/SelfadjointMatrixMatrix.h"
+#include "src/Core/products/SelfadjointProduct.h"
+#include "src/Core/products/SelfadjointRank2Update.h"
+#include "src/Core/products/TriangularMatrixVector.h"
+#include "src/Core/products/TriangularMatrixMatrix.h"
+#include "src/Core/products/TriangularSolverMatrix.h"
+#include "src/Core/products/TriangularSolverVector.h"
+#include "src/Core/BandMatrix.h"
+
+#include "src/Core/BooleanRedux.h"
+#include "src/Core/Select.h"
+#include "src/Core/VectorwiseOp.h"
+#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"
+#endif // EIGEN_USE_BLAS
+
+#ifdef EIGEN_USE_MKL_VML
+#include "src/Core/Assign_MKL.h"
+#endif
+
+#include "src/Core/GlobalFunctions.h"
+
+#include "src/Core/util/ReenableStupidWarnings.h"
+
+#ifdef EIGEN2_SUPPORT
+#include "Eigen2Support"
+#endif
+
+#endif // EIGEN_CORE_H
diff --git a/Eigen/Dense b/Eigen/Dense
new file mode 100644
index 000000000..5768910bd
--- /dev/null
+++ b/Eigen/Dense
@@ -0,0 +1,7 @@
+#include "Core"
+#include "LU"
+#include "Cholesky"
+#include "QR"
+#include "SVD"
+#include "Geometry"
+#include "Eigenvalues"
diff --git a/Eigen/Eigen b/Eigen/Eigen
new file mode 100644
index 000000000..19b40ea4e
--- /dev/null
+++ b/Eigen/Eigen
@@ -0,0 +1,2 @@
+#include "Dense"
+//#include "Sparse"
diff --git a/Eigen/Eigen2Support b/Eigen/Eigen2Support
new file mode 100644
index 000000000..36156d29a
--- /dev/null
+++ b/Eigen/Eigen2Support
@@ -0,0 +1,82 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra.
+//
+// Copyright (C) 2009 Gael Guennebaud <gael.guennebaud@inria.fr>
+//
+// This Source Code Form is subject to the terms of the Mozilla
+// Public License v. 2.0. If a copy of the MPL was not distributed
+// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+#ifndef EIGEN2SUPPORT_H
+#define EIGEN2SUPPORT_H
+
+#if (!defined(EIGEN2_SUPPORT)) || (!defined(EIGEN_CORE_H))
+#error Eigen2 support must be enabled by defining EIGEN2_SUPPORT before including any Eigen header
+#endif
+
+#include "src/Core/util/DisableStupidWarnings.h"
+
+/** \ingroup Support_modules
+ * \defgroup Eigen2Support_Module Eigen2 support module
+ * This module provides a couple of deprecated functions improving the compatibility with Eigen2.
+ *
+ * To use it, define EIGEN2_SUPPORT before including any Eigen header
+ * \code
+ * #define EIGEN2_SUPPORT
+ * \endcode
+ *
+ */
+
+#include "src/Eigen2Support/Macros.h"
+#include "src/Eigen2Support/Memory.h"
+#include "src/Eigen2Support/Meta.h"
+#include "src/Eigen2Support/Lazy.h"
+#include "src/Eigen2Support/Cwise.h"
+#include "src/Eigen2Support/CwiseOperators.h"
+#include "src/Eigen2Support/TriangularSolver.h"
+#include "src/Eigen2Support/Block.h"
+#include "src/Eigen2Support/VectorBlock.h"
+#include "src/Eigen2Support/Minor.h"
+#include "src/Eigen2Support/MathFunctions.h"
+
+
+#include "src/Core/util/ReenableStupidWarnings.h"
+
+// Eigen2 used to include iostream
+#include<iostream>
+
+#define EIGEN_USING_MATRIX_TYPEDEFS_FOR_TYPE_AND_SIZE(TypeSuffix, SizeSuffix) \
+using Eigen::Matrix##SizeSuffix##TypeSuffix; \
+using Eigen::Vector##SizeSuffix##TypeSuffix; \
+using Eigen::RowVector##SizeSuffix##TypeSuffix;
+
+#define EIGEN_USING_MATRIX_TYPEDEFS_FOR_TYPE(TypeSuffix) \
+EIGEN_USING_MATRIX_TYPEDEFS_FOR_TYPE_AND_SIZE(TypeSuffix, 2) \
+EIGEN_USING_MATRIX_TYPEDEFS_FOR_TYPE_AND_SIZE(TypeSuffix, 3) \
+EIGEN_USING_MATRIX_TYPEDEFS_FOR_TYPE_AND_SIZE(TypeSuffix, 4) \
+EIGEN_USING_MATRIX_TYPEDEFS_FOR_TYPE_AND_SIZE(TypeSuffix, X) \
+
+#define EIGEN_USING_MATRIX_TYPEDEFS \
+EIGEN_USING_MATRIX_TYPEDEFS_FOR_TYPE(i) \
+EIGEN_USING_MATRIX_TYPEDEFS_FOR_TYPE(f) \
+EIGEN_USING_MATRIX_TYPEDEFS_FOR_TYPE(d) \
+EIGEN_USING_MATRIX_TYPEDEFS_FOR_TYPE(cf) \
+EIGEN_USING_MATRIX_TYPEDEFS_FOR_TYPE(cd)
+
+#define USING_PART_OF_NAMESPACE_EIGEN \
+EIGEN_USING_MATRIX_TYPEDEFS \
+using Eigen::Matrix; \
+using Eigen::MatrixBase; \
+using Eigen::ei_random; \
+using Eigen::ei_real; \
+using Eigen::ei_imag; \
+using Eigen::ei_conj; \
+using Eigen::ei_abs; \
+using Eigen::ei_abs2; \
+using Eigen::ei_sqrt; \
+using Eigen::ei_exp; \
+using Eigen::ei_log; \
+using Eigen::ei_sin; \
+using Eigen::ei_cos;
+
+#endif // EIGEN2SUPPORT_H
diff --git a/Eigen/Eigenvalues b/Eigen/Eigenvalues
new file mode 100644
index 000000000..af99ccd1f
--- /dev/null
+++ b/Eigen/Eigenvalues
@@ -0,0 +1,46 @@
+#ifndef EIGEN_EIGENVALUES_MODULE_H
+#define EIGEN_EIGENVALUES_MODULE_H
+
+#include "Core"
+
+#include "src/Core/util/DisableStupidWarnings.h"
+
+#include "Cholesky"
+#include "Jacobi"
+#include "Householder"
+#include "LU"
+#include "Geometry"
+
+/** \defgroup Eigenvalues_Module Eigenvalues module
+ *
+ *
+ *
+ * This module mainly provides various eigenvalue solvers.
+ * This module also provides some MatrixBase methods, including:
+ * - MatrixBase::eigenvalues(),
+ * - MatrixBase::operatorNorm()
+ *
+ * \code
+ * #include <Eigen/Eigenvalues>
+ * \endcode
+ */
+
+#include "src/Eigenvalues/Tridiagonalization.h"
+#include "src/Eigenvalues/RealSchur.h"
+#include "src/Eigenvalues/EigenSolver.h"
+#include "src/Eigenvalues/SelfAdjointEigenSolver.h"
+#include "src/Eigenvalues/GeneralizedSelfAdjointEigenSolver.h"
+#include "src/Eigenvalues/HessenbergDecomposition.h"
+#include "src/Eigenvalues/ComplexSchur.h"
+#include "src/Eigenvalues/ComplexEigenSolver.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"
+#endif
+
+#include "src/Core/util/ReenableStupidWarnings.h"
+
+#endif // EIGEN_EIGENVALUES_MODULE_H
+/* vim: set filetype=cpp et sw=2 ts=2 ai: */
diff --git a/Eigen/Geometry b/Eigen/Geometry
new file mode 100644
index 000000000..efd9d4504
--- /dev/null
+++ b/Eigen/Geometry
@@ -0,0 +1,63 @@
+#ifndef EIGEN_GEOMETRY_MODULE_H
+#define EIGEN_GEOMETRY_MODULE_H
+
+#include "Core"
+
+#include "src/Core/util/DisableStupidWarnings.h"
+
+#include "SVD"
+#include "LU"
+#include <limits>
+
+#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 <Eigen/Geometry>
+ * \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/Eigen/Householder b/Eigen/Householder
new file mode 100644
index 000000000..6e348db5c
--- /dev/null
+++ b/Eigen/Householder
@@ -0,0 +1,23 @@
+#ifndef EIGEN_HOUSEHOLDER_MODULE_H
+#define EIGEN_HOUSEHOLDER_MODULE_H
+
+#include "Core"
+
+#include "src/Core/util/DisableStupidWarnings.h"
+
+/** \defgroup Householder_Module Householder module
+ * This module provides Householder transformations.
+ *
+ * \code
+ * #include <Eigen/Householder>
+ * \endcode
+ */
+
+#include "src/Householder/Householder.h"
+#include "src/Householder/HouseholderSequence.h"
+#include "src/Householder/BlockHouseholder.h"
+
+#include "src/Core/util/ReenableStupidWarnings.h"
+
+#endif // EIGEN_HOUSEHOLDER_MODULE_H
+/* vim: set filetype=cpp et sw=2 ts=2 ai: */
diff --git a/Eigen/IterativeLinearSolvers b/Eigen/IterativeLinearSolvers
new file mode 100644
index 000000000..315c2dd1e
--- /dev/null
+++ b/Eigen/IterativeLinearSolvers
@@ -0,0 +1,40 @@
+#ifndef EIGEN_ITERATIVELINEARSOLVERS_MODULE_H
+#define EIGEN_ITERATIVELINEARSOLVERS_MODULE_H
+
+#include "SparseCore"
+#include "OrderingMethods"
+
+#include "src/Core/util/DisableStupidWarnings.h"
+
+/** \ingroup Sparse_modules
+ * \defgroup IterativeLinearSolvers_Module IterativeLinearSolvers module
+ *
+ * This module currently provides iterative methods to solve problems of the form \c A \c x = \c b, where \c A is a squared matrix, usually very large and sparse.
+ * Those solvers are accessible via the following classes:
+ * - ConjugateGradient for selfadjoint (hermitian) matrices,
+ * - BiCGSTAB for general square matrices.
+ *
+ * These iterative solvers are associated with some preconditioners:
+ * - IdentityPreconditioner - not really useful
+ * - DiagonalPreconditioner - also called JAcobi preconditioner, work very well on diagonal dominant matrices.
+ * - IncompleteILUT - incomplete LU factorization with dual thresholding
+ *
+ * Such problems can also be solved using the direct sparse decomposition modules: SparseCholesky, CholmodSupport, UmfPackSupport, SuperLUSupport.
+ *
+ * \code
+ * #include <Eigen/IterativeLinearSolvers>
+ * \endcode
+ */
+
+#include "src/misc/Solve.h"
+#include "src/misc/SparseSolve.h"
+
+#include "src/IterativeLinearSolvers/IterativeSolverBase.h"
+#include "src/IterativeLinearSolvers/BasicPreconditioners.h"
+#include "src/IterativeLinearSolvers/ConjugateGradient.h"
+#include "src/IterativeLinearSolvers/BiCGSTAB.h"
+#include "src/IterativeLinearSolvers/IncompleteLUT.h"
+
+#include "src/Core/util/ReenableStupidWarnings.h"
+
+#endif // EIGEN_ITERATIVELINEARSOLVERS_MODULE_H
diff --git a/Eigen/Jacobi b/Eigen/Jacobi
new file mode 100644
index 000000000..ba8a4dc36
--- /dev/null
+++ b/Eigen/Jacobi
@@ -0,0 +1,26 @@
+#ifndef EIGEN_JACOBI_MODULE_H
+#define EIGEN_JACOBI_MODULE_H
+
+#include "Core"
+
+#include "src/Core/util/DisableStupidWarnings.h"
+
+/** \defgroup Jacobi_Module Jacobi module
+ * This module provides Jacobi and Givens rotations.
+ *
+ * \code
+ * #include <Eigen/Jacobi>
+ * \endcode
+ *
+ * In addition to listed classes, it defines the two following MatrixBase methods to apply a Jacobi or Givens rotation:
+ * - MatrixBase::applyOnTheLeft()
+ * - MatrixBase::applyOnTheRight().
+ */
+
+#include "src/Jacobi/Jacobi.h"
+
+#include "src/Core/util/ReenableStupidWarnings.h"
+
+#endif // EIGEN_JACOBI_MODULE_H
+/* vim: set filetype=cpp et sw=2 ts=2 ai: */
+
diff --git a/Eigen/LU b/Eigen/LU
new file mode 100644
index 000000000..db5795504
--- /dev/null
+++ b/Eigen/LU
@@ -0,0 +1,41 @@
+#ifndef EIGEN_LU_MODULE_H
+#define EIGEN_LU_MODULE_H
+
+#include "Core"
+
+#include "src/Core/util/DisableStupidWarnings.h"
+
+/** \defgroup LU_Module LU module
+ * This module includes %LU decomposition and related notions such as matrix inversion and determinant.
+ * This module defines the following MatrixBase methods:
+ * - MatrixBase::inverse()
+ * - MatrixBase::determinant()
+ *
+ * \code
+ * #include <Eigen/LU>
+ * \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"
+#endif
+#include "src/LU/Determinant.h"
+#include "src/LU/Inverse.h"
+
+#if defined EIGEN_VECTORIZE_SSE
+ #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
+/* vim: set filetype=cpp et sw=2 ts=2 ai: */
diff --git a/Eigen/LeastSquares b/Eigen/LeastSquares
new file mode 100644
index 000000000..35137c25d
--- /dev/null
+++ b/Eigen/LeastSquares
@@ -0,0 +1,32 @@
+#ifndef EIGEN_REGRESSION_MODULE_H
+#define EIGEN_REGRESSION_MODULE_H
+
+#ifndef EIGEN2_SUPPORT
+#error LeastSquares is only available in Eigen2 support mode (define EIGEN2_SUPPORT)
+#endif
+
+// exclude from normal eigen3-only documentation
+#ifdef EIGEN2_SUPPORT
+
+#include "Core"
+
+#include "src/Core/util/DisableStupidWarnings.h"
+
+#include "Eigenvalues"
+#include "Geometry"
+
+/** \defgroup LeastSquares_Module LeastSquares module
+ * This module provides linear regression and related features.
+ *
+ * \code
+ * #include <Eigen/LeastSquares>
+ * \endcode
+ */
+
+#include "src/Eigen2Support/LeastSquares.h"
+
+#include "src/Core/util/ReenableStupidWarnings.h"
+
+#endif // EIGEN2_SUPPORT
+
+#endif // EIGEN_REGRESSION_MODULE_H
diff --git a/Eigen/OrderingMethods b/Eigen/OrderingMethods
new file mode 100644
index 000000000..1e2d87452
--- /dev/null
+++ b/Eigen/OrderingMethods
@@ -0,0 +1,23 @@
+#ifndef EIGEN_ORDERINGMETHODS_MODULE_H
+#define EIGEN_ORDERINGMETHODS_MODULE_H
+
+#include "SparseCore"
+
+#include "src/Core/util/DisableStupidWarnings.h"
+
+/** \ingroup Sparse_modules
+ * \defgroup OrderingMethods_Module OrderingMethods module
+ *
+ * This module is currently for internal use only.
+ *
+ *
+ * \code
+ * #include <Eigen/OrderingMethods>
+ * \endcode
+ */
+
+#include "src/OrderingMethods/Amd.h"
+
+#include "src/Core/util/ReenableStupidWarnings.h"
+
+#endif // EIGEN_ORDERINGMETHODS_MODULE_H
diff --git a/Eigen/PaStiXSupport b/Eigen/PaStiXSupport
new file mode 100644
index 000000000..7c616ee5e
--- /dev/null
+++ b/Eigen/PaStiXSupport
@@ -0,0 +1,46 @@
+#ifndef EIGEN_PASTIXSUPPORT_MODULE_H
+#define EIGEN_PASTIXSUPPORT_MODULE_H
+
+#include "SparseCore"
+
+#include "src/Core/util/DisableStupidWarnings.h"
+
+#include <complex.h>
+extern "C" {
+#include <pastix_nompi.h>
+#include <pastix.h>
+}
+
+#ifdef complex
+#undef complex
+#endif
+
+/** \ingroup Support_modules
+ * \defgroup PaStiXSupport_Module PaStiXSupport module
+ *
+ * This module provides an interface to the <a href="http://pastix.gforge.inria.fr/">PaSTiX</a> 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 <Eigen/PaStiXSupport>
+ * \endcode
+ *
+ * In order to use this module, the PaSTiX headers must be accessible from the include paths, and your binary must be linked to the PaSTiX library and its dependencies.
+ * The dependencies depend on how PaSTiX has been compiled.
+ * For a cmake based project, you can use our FindPaSTiX.cmake module to help you in this task.
+ *
+ */
+
+#include "src/misc/Solve.h"
+#include "src/misc/SparseSolve.h"
+
+#include "src/PaStiXSupport/PaStiXSupport.h"
+
+
+#include "src/Core/util/ReenableStupidWarnings.h"
+
+#endif // EIGEN_PASTIXSUPPORT_MODULE_H
diff --git a/Eigen/PardisoSupport b/Eigen/PardisoSupport
new file mode 100644
index 000000000..99330ce7a
--- /dev/null
+++ b/Eigen/PardisoSupport
@@ -0,0 +1,30 @@
+#ifndef EIGEN_PARDISOSUPPORT_MODULE_H
+#define EIGEN_PARDISOSUPPORT_MODULE_H
+
+#include "SparseCore"
+
+#include "src/Core/util/DisableStupidWarnings.h"
+
+#include <mkl_pardiso.h>
+
+#include <unsupported/Eigen/SparseExtra>
+
+/** \ingroup Support_modules
+ * \defgroup PardisoSupport_Module PardisoSupport module
+ *
+ * This module brings support for the Intel(R) MKL PARDISO direct sparse solvers.
+ *
+ * \code
+ * #include <Eigen/PardisoSupport>
+ * \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/Eigen/QR b/Eigen/QR
new file mode 100644
index 000000000..ac5b02693
--- /dev/null
+++ b/Eigen/QR
@@ -0,0 +1,45 @@
+#ifndef EIGEN_QR_MODULE_H
+#define EIGEN_QR_MODULE_H
+
+#include "Core"
+
+#include "src/Core/util/DisableStupidWarnings.h"
+
+#include "Cholesky"
+#include "Jacobi"
+#include "Householder"
+
+/** \defgroup QR_Module QR module
+ *
+ *
+ *
+ * This module provides various QR decompositions
+ * This module also provides some MatrixBase methods, including:
+ * - MatrixBase::qr(),
+ *
+ * \code
+ * #include <Eigen/QR>
+ * \endcode
+ */
+
+#include "src/misc/Solve.h"
+#include "src/QR/HouseholderQR.h"
+#include "src/QR/FullPivHouseholderQR.h"
+#include "src/QR/ColPivHouseholderQR.h"
+#ifdef EIGEN_USE_LAPACKE
+#include "src/QR/HouseholderQR_MKL.h"
+#include "src/QR/ColPivHouseholderQR_MKL.h"
+#endif
+
+#ifdef EIGEN2_SUPPORT
+#include "src/Eigen2Support/QR.h"
+#endif
+
+#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/Eigen/QtAlignedMalloc b/Eigen/QtAlignedMalloc
new file mode 100644
index 000000000..46f7d83b7
--- /dev/null
+++ b/Eigen/QtAlignedMalloc
@@ -0,0 +1,34 @@
+
+#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(size_t size)
+{
+ return Eigen::internal::aligned_malloc(size);
+}
+
+void qFree(void *ptr)
+{
+ Eigen::internal::aligned_free(ptr);
+}
+
+void *qRealloc(void *ptr, size_t size)
+{
+ void* newPtr = Eigen::internal::aligned_malloc(size);
+ 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/Eigen/SVD b/Eigen/SVD
new file mode 100644
index 000000000..fd310017a
--- /dev/null
+++ b/Eigen/SVD
@@ -0,0 +1,37 @@
+#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 <Eigen/SVD>
+ * \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/Eigen/Sparse b/Eigen/Sparse
new file mode 100644
index 000000000..2d1757172
--- /dev/null
+++ b/Eigen/Sparse
@@ -0,0 +1,23 @@
+#ifndef EIGEN_SPARSE_MODULE_H
+#define EIGEN_SPARSE_MODULE_H
+
+/** \defgroup Sparse_modules Sparse modules
+ *
+ * Meta-module including all related modules:
+ * - SparseCore
+ * - OrderingMethods
+ * - SparseCholesky
+ * - IterativeLinearSolvers
+ *
+ * \code
+ * #include <Eigen/Sparse>
+ * \endcode
+ */
+
+#include "SparseCore"
+#include "OrderingMethods"
+#include "SparseCholesky"
+#include "IterativeLinearSolvers"
+
+#endif // EIGEN_SPARSE_MODULE_H
+
diff --git a/Eigen/SparseCholesky b/Eigen/SparseCholesky
new file mode 100644
index 000000000..5f82742f7
--- /dev/null
+++ b/Eigen/SparseCholesky
@@ -0,0 +1,30 @@
+#ifndef EIGEN_SPARSECHOLESKY_MODULE_H
+#define EIGEN_SPARSECHOLESKY_MODULE_H
+
+#include "SparseCore"
+
+#include "src/Core/util/DisableStupidWarnings.h"
+
+/** \ingroup Sparse_modules
+ * \defgroup SparseCholesky_Module SparseCholesky module
+ *
+ * This module currently provides two variants of the direct sparse Cholesky decomposition for selfadjoint (hermitian) matrices.
+ * Those decompositions are accessible via the following classes:
+ * - SimplicialLLt,
+ * - SimplicialLDLt
+ *
+ * Such problems can also be solved using the ConjugateGradient solver from the IterativeLinearSolvers module.
+ *
+ * \code
+ * #include <Eigen/SparseCholesky>
+ * \endcode
+ */
+
+#include "src/misc/Solve.h"
+#include "src/misc/SparseSolve.h"
+
+#include "src/SparseCholesky/SimplicialCholesky.h"
+
+#include "src/Core/util/ReenableStupidWarnings.h"
+
+#endif // EIGEN_SPARSECHOLESKY_MODULE_H
diff --git a/Eigen/SparseCore b/Eigen/SparseCore
new file mode 100644
index 000000000..41d28c928
--- /dev/null
+++ b/Eigen/SparseCore
@@ -0,0 +1,66 @@
+#ifndef EIGEN_SPARSECORE_MODULE_H
+#define EIGEN_SPARSECORE_MODULE_H
+
+#include "Core"
+
+#include "src/Core/util/DisableStupidWarnings.h"
+
+#include <vector>
+#include <map>
+#include <cstdlib>
+#include <cstring>
+#include <algorithm>
+
+/** \ingroup Sparse_modules
+ * \defgroup SparseCore_Module SparseCore module
+ *
+ * This module provides a sparse matrix representation, and basic associatd matrix manipulations
+ * and operations.
+ *
+ * See the \ref TutorialSparse "Sparse tutorial"
+ *
+ * \code
+ * #include <Eigen/SparseCore>
+ * \endcode
+ *
+ * This module depends on: Core.
+ */
+
+namespace Eigen {
+
+/** The type used to identify a general sparse storage. */
+struct Sparse {};
+
+}
+
+#include "src/SparseCore/SparseUtil.h"
+#include "src/SparseCore/SparseMatrixBase.h"
+#include "src/SparseCore/CompressedStorage.h"
+#include "src/SparseCore/AmbiVector.h"
+#include "src/SparseCore/SparseMatrix.h"
+#include "src/SparseCore/MappedSparseMatrix.h"
+#include "src/SparseCore/SparseVector.h"
+#include "src/SparseCore/CoreIterators.h"
+#include "src/SparseCore/SparseBlock.h"
+#include "src/SparseCore/SparseTranspose.h"
+#include "src/SparseCore/SparseCwiseUnaryOp.h"
+#include "src/SparseCore/SparseCwiseBinaryOp.h"
+#include "src/SparseCore/SparseDot.h"
+#include "src/SparseCore/SparsePermutation.h"
+#include "src/SparseCore/SparseAssign.h"
+#include "src/SparseCore/SparseRedux.h"
+#include "src/SparseCore/SparseFuzzy.h"
+#include "src/SparseCore/ConservativeSparseSparseProduct.h"
+#include "src/SparseCore/SparseSparseProductWithPruning.h"
+#include "src/SparseCore/SparseProduct.h"
+#include "src/SparseCore/SparseDenseProduct.h"
+#include "src/SparseCore/SparseDiagonalProduct.h"
+#include "src/SparseCore/SparseTriangularView.h"
+#include "src/SparseCore/SparseSelfAdjointView.h"
+#include "src/SparseCore/TriangularSolver.h"
+#include "src/SparseCore/SparseView.h"
+
+#include "src/Core/util/ReenableStupidWarnings.h"
+
+#endif // EIGEN_SPARSECORE_MODULE_H
+
diff --git a/Eigen/StdDeque b/Eigen/StdDeque
new file mode 100644
index 000000000..f27234778
--- /dev/null
+++ b/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 <gael.guennebaud@inria.fr>
+// Copyright (C) 2009 Hauke Heibel <hauke.heibel@googlemail.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_STDDEQUE_MODULE_H
+#define EIGEN_STDDEQUE_MODULE_H
+
+#include "Core"
+#include <deque>
+
+#if (defined(_MSC_VER) && defined(_WIN64)) /* MSVC auto aligns 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/Eigen/StdList b/Eigen/StdList
new file mode 100644
index 000000000..225c1e18f
--- /dev/null
+++ b/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 <hauke.heibel@googlemail.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_STDLIST_MODULE_H
+#define EIGEN_STDLIST_MODULE_H
+
+#include "Core"
+#include <list>
+
+#if (defined(_MSC_VER) && defined(_WIN64)) /* MSVC auto aligns 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/Eigen/StdVector b/Eigen/StdVector
new file mode 100644
index 000000000..6b22627f6
--- /dev/null
+++ b/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 <gael.guennebaud@inria.fr>
+// Copyright (C) 2009 Hauke Heibel <hauke.heibel@googlemail.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_STDVECTOR_MODULE_H
+#define EIGEN_STDVECTOR_MODULE_H
+
+#include "Core"
+#include <vector>
+
+#if (defined(_MSC_VER) && defined(_WIN64)) /* MSVC auto aligns 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/Eigen/SuperLUSupport b/Eigen/SuperLUSupport
new file mode 100644
index 000000000..575e14fbc
--- /dev/null
+++ b/Eigen/SuperLUSupport
@@ -0,0 +1,59 @@
+#ifndef EIGEN_SUPERLUSUPPORT_MODULE_H
+#define EIGEN_SUPERLUSUPPORT_MODULE_H
+
+#include "SparseCore"
+
+#include "src/Core/util/DisableStupidWarnings.h"
+
+#ifdef EMPTY
+#define EIGEN_EMPTY_WAS_ALREADY_DEFINED
+#endif
+
+typedef int int_t;
+#include <slu_Cnames.h>
+#include <supermatrix.h>
+#include <slu_util.h>
+
+// 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 <a href="http://crd-legacy.lbl.gov/~xiaoye/SuperLU/">SuperLU</a> library.
+ * It provides the following factorization class:
+ * - class SuperLU: a supernodal sequential LU factorization.
+ * - class SuperILU: a supernodal sequential incomplete LU factorization (to be used as a preconditioner for iterative methods).
+ *
+ * \warning When including this module, you have to use SUPERLU_EMPTY instead of EMPTY which is no longer defined because it is too polluting.
+ *
+ * \code
+ * #include <Eigen/SuperLUSupport>
+ * \endcode
+ *
+ * In order to use this module, the superlu headers must be accessible from the include paths, and your binary must be linked to the superlu library and its dependencies.
+ * The dependencies depend on how superlu has been compiled.
+ * For a cmake based project, you can use our FindSuperLU.cmake module to help you in this task.
+ *
+ */
+
+#include "src/misc/Solve.h"
+#include "src/misc/SparseSolve.h"
+
+#include "src/SuperLUSupport/SuperLUSupport.h"
+
+
+#include "src/Core/util/ReenableStupidWarnings.h"
+
+#endif // EIGEN_SUPERLUSUPPORT_MODULE_H
diff --git a/Eigen/UmfPackSupport b/Eigen/UmfPackSupport
new file mode 100644
index 000000000..984f64a84
--- /dev/null
+++ b/Eigen/UmfPackSupport
@@ -0,0 +1,36 @@
+#ifndef EIGEN_UMFPACKSUPPORT_MODULE_H
+#define EIGEN_UMFPACKSUPPORT_MODULE_H
+
+#include "SparseCore"
+
+#include "src/Core/util/DisableStupidWarnings.h"
+
+extern "C" {
+#include <umfpack.h>
+}
+
+/** \ingroup Support_modules
+ * \defgroup UmfPackSupport_Module UmfPackSupport module
+ *
+ * This module provides an interface to the UmfPack library which is part of the <a href="http://www.cise.ufl.edu/research/sparse/SuiteSparse/">suitesparse</a> package.
+ * It provides the following factorization class:
+ * - class UmfPackLU: a multifrontal sequential LU factorization.
+ *
+ * \code
+ * #include <Eigen/UmfPackSupport>
+ * \endcode
+ *
+ * In order to use this module, the umfpack headers must be accessible from the include paths, and your binary must be linked to the umfpack library and its dependencies.
+ * The dependencies depend on how umfpack has been compiled.
+ * For a cmake based project, you can use our FindUmfPack.cmake module to help you in this task.
+ *
+ */
+
+#include "src/misc/Solve.h"
+#include "src/misc/SparseSolve.h"
+
+#include "src/UmfPackSupport/UmfPackSupport.h"
+
+#include "src/Core/util/ReenableStupidWarnings.h"
+
+#endif // EIGEN_UMFPACKSUPPORT_MODULE_H
diff --git a/Eigen/src/CMakeLists.txt b/Eigen/src/CMakeLists.txt
new file mode 100644
index 000000000..c326f374d
--- /dev/null
+++ b/Eigen/src/CMakeLists.txt
@@ -0,0 +1,7 @@
+file(GLOB Eigen_src_subdirectories "*")
+escape_string_as_regex(ESCAPED_CMAKE_CURRENT_SOURCE_DIR "${CMAKE_CURRENT_SOURCE_DIR}")
+foreach(f ${Eigen_src_subdirectories})
+ if(NOT f MATCHES "\\.txt" AND NOT f MATCHES "${ESCAPED_CMAKE_CURRENT_SOURCE_DIR}/[.].+" )
+ add_subdirectory(${f})
+ endif()
+endforeach()
diff --git a/Eigen/src/Cholesky/CMakeLists.txt b/Eigen/src/Cholesky/CMakeLists.txt
new file mode 100644
index 000000000..d01488b41
--- /dev/null
+++ b/Eigen/src/Cholesky/CMakeLists.txt
@@ -0,0 +1,6 @@
+FILE(GLOB Eigen_Cholesky_SRCS "*.h")
+
+INSTALL(FILES
+ ${Eigen_Cholesky_SRCS}
+ DESTINATION ${INCLUDE_INSTALL_DIR}/Eigen/src/Cholesky COMPONENT Devel
+ )
diff --git a/Eigen/src/Cholesky/LDLT.h b/Eigen/src/Cholesky/LDLT.h
new file mode 100644
index 000000000..68e54b1d4
--- /dev/null
+++ b/Eigen/src/Cholesky/LDLT.h
@@ -0,0 +1,592 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra.
+//
+// Copyright (C) 2008-2011 Gael Guennebaud <gael.guennebaud@inria.fr>
+// Copyright (C) 2009 Keir Mierle <mierle@gmail.com>
+// Copyright (C) 2009 Benoit Jacob <jacob.benoit.1@gmail.com>
+// Copyright (C) 2011 Timothy E. Holy <tim.holy@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 EIGEN_LDLT_H
+#define EIGEN_LDLT_H
+
+namespace Eigen {
+
+namespace internal {
+template<typename MatrixType, int UpLo> struct LDLT_Traits;
+}
+
+/** \ingroup Cholesky_Module
+ *
+ * \class LDLT
+ *
+ * \brief Robust Cholesky decomposition of a matrix with pivoting
+ *
+ * \param MatrixType the type of the matrix of which to compute the LDL^T Cholesky decomposition
+ * \param UpLo the triangular part that will be used for the decompositon: Lower (default) or Upper.
+ * The other triangular part won't be read.
+ *
+ * Perform a robust Cholesky decomposition of a positive semidefinite or negative semidefinite
+ * matrix \f$ A \f$ such that \f$ A = P^TLDL^*P \f$, where P is a permutation matrix, L
+ * is lower triangular with a unit diagonal and D is a diagonal matrix.
+ *
+ * The decomposition uses pivoting to ensure stability, so that L will have
+ * zeros in the bottom right rank(A) - n submatrix. Avoiding the square root
+ * on D also stabilizes the computation.
+ *
+ * Remember that Cholesky decompositions are not rank-revealing. Also, do not use a Cholesky
+ * decomposition to determine whether a system of equations has a solution.
+ *
+ * \sa MatrixBase::ldlt(), class LLT
+ */
+template<typename _MatrixType, int _UpLo> class LDLT
+{
+ public:
+ typedef _MatrixType MatrixType;
+ 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<typename MatrixType::Scalar>::Real RealScalar;
+ typedef typename MatrixType::Index Index;
+ typedef Matrix<Scalar, RowsAtCompileTime, 1, Options, MaxRowsAtCompileTime, 1> TmpMatrixType;
+
+ typedef Transpositions<RowsAtCompileTime, MaxRowsAtCompileTime> TranspositionType;
+ typedef PermutationMatrix<RowsAtCompileTime, MaxRowsAtCompileTime> PermutationType;
+
+ typedef internal::LDLT_Traits<MatrixType,UpLo> Traits;
+
+ /** \brief Default Constructor.
+ *
+ * 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(), m_isInitialized(false) {}
+
+ /** \brief Default Constructor with memory preallocation
+ *
+ * Like the default constructor but with preallocation of the internal data
+ * according to the specified problem \a size.
+ * \sa LDLT()
+ */
+ LDLT(Index size)
+ : m_matrix(size, size),
+ m_transpositions(size),
+ m_temporary(size),
+ m_isInitialized(false)
+ {}
+
+ /** \brief Constructor with decomposition
+ *
+ * This calculates the decomposition for the input \a matrix.
+ * \sa LDLT(Index size)
+ */
+ LDLT(const MatrixType& matrix)
+ : m_matrix(matrix.rows(), matrix.cols()),
+ m_transpositions(matrix.rows()),
+ m_temporary(matrix.rows()),
+ m_isInitialized(false)
+ {
+ compute(matrix);
+ }
+
+ /** Clear any existing decomposition
+ * \sa rankUpdate(w,sigma)
+ */
+ void setZero()
+ {
+ m_isInitialized = false;
+ }
+
+ /** \returns a view of the upper triangular matrix U */
+ inline typename Traits::MatrixU matrixU() const
+ {
+ eigen_assert(m_isInitialized && "LDLT is not initialized.");
+ return Traits::getU(m_matrix);
+ }
+
+ /** \returns a view of the lower triangular matrix L */
+ inline typename Traits::MatrixL matrixL() const
+ {
+ eigen_assert(m_isInitialized && "LDLT is not initialized.");
+ return Traits::getL(m_matrix);
+ }
+
+ /** \returns the permutation matrix P as a transposition sequence.
+ */
+ inline const TranspositionType& transpositionsP() const
+ {
+ eigen_assert(m_isInitialized && "LDLT is not initialized.");
+ return m_transpositions;
+ }
+
+ /** \returns the coefficients of the diagonal matrix D */
+ inline Diagonal<const MatrixType> vectorD() const
+ {
+ eigen_assert(m_isInitialized && "LDLT is not initialized.");
+ return m_matrix.diagonal();
+ }
+
+ /** \returns true if the matrix is positive (semidefinite) */
+ inline bool isPositive() const
+ {
+ eigen_assert(m_isInitialized && "LDLT is not initialized.");
+ return m_sign == 1;
+ }
+
+ #ifdef EIGEN2_SUPPORT
+ inline bool isPositiveDefinite() const
+ {
+ return isPositive();
+ }
+ #endif
+
+ /** \returns true if the matrix is negative (semidefinite) */
+ inline bool isNegative(void) const
+ {
+ eigen_assert(m_isInitialized && "LDLT is not initialized.");
+ return m_sign == -1;
+ }
+
+ /** \returns a solution x of \f$ A x = b \f$ using the current decomposition of A.
+ *
+ * This function also supports in-place solves using the syntax <tt>x = decompositionObject.solve(x)</tt> .
+ *
+ * \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$,
+ * \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()
+ */
+ template<typename Rhs>
+ inline const internal::solve_retval<LDLT, Rhs>
+ solve(const MatrixBase<Rhs>& 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<LDLT, Rhs>(*this, b.derived());
+ }
+
+ #ifdef EIGEN2_SUPPORT
+ template<typename OtherDerived, typename ResultType>
+ bool solve(const MatrixBase<OtherDerived>& b, ResultType *result) const
+ {
+ *result = this->solve(b);
+ return true;
+ }
+ #endif
+
+ template<typename Derived>
+ bool solveInPlace(MatrixBase<Derived> &bAndX) const;
+
+ LDLT& compute(const MatrixType& matrix);
+
+ template <typename Derived>
+ LDLT& rankUpdate(const MatrixBase<Derived>& w,RealScalar alpha=1);
+
+ /** \returns the internal LDLT decomposition matrix
+ *
+ * TODO: document the storage layout
+ */
+ inline const MatrixType& matrixLDLT() const
+ {
+ eigen_assert(m_isInitialized && "LDLT is not initialized.");
+ return m_matrix;
+ }
+
+ MatrixType reconstructedMatrix() const;
+
+ inline Index rows() const { return m_matrix.rows(); }
+ inline Index cols() const { return m_matrix.cols(); }
+
+ /** \brief Reports whether previous computation was successful.
+ *
+ * \returns \c Success if computation was succesful,
+ * \c NumericalIssue if the matrix.appears to be negative.
+ */
+ ComputationInfo info() const
+ {
+ eigen_assert(m_isInitialized && "LDLT is not initialized.");
+ return Success;
+ }
+
+ protected:
+
+ /** \internal
+ * Used to compute and store the Cholesky decomposition A = L D L^* = U^* D U.
+ * The strict upper part is used during the decomposition, the strict lower
+ * part correspond to the coefficients of L (its diagonal is equal to 1 and
+ * is not stored), and the diagonal entries correspond to D.
+ */
+ MatrixType m_matrix;
+ TranspositionType m_transpositions;
+ TmpMatrixType m_temporary;
+ int m_sign;
+ bool m_isInitialized;
+};
+
+namespace internal {
+
+template<int UpLo> struct ldlt_inplace;
+
+template<> struct ldlt_inplace<Lower>
+{
+ template<typename MatrixType, typename TranspositionType, typename Workspace>
+ static bool unblocked(MatrixType& mat, TranspositionType& transpositions, Workspace& temp, int* sign=0)
+ {
+ typedef typename MatrixType::Scalar Scalar;
+ typedef typename MatrixType::RealScalar RealScalar;
+ typedef typename MatrixType::Index Index;
+ eigen_assert(mat.rows()==mat.cols());
+ const Index size = mat.rows();
+
+ if (size <= 1)
+ {
+ transpositions.setIdentity();
+ if(sign)
+ *sign = real(mat.coeff(0,0))>0 ? 1:-1;
+ return true;
+ }
+
+ RealScalar cutoff(0), biggest_in_corner;
+
+ for (Index k = 0; k < size; ++k)
+ {
+ // Find largest diagonal element
+ Index index_of_biggest_in_corner;
+ biggest_in_corner = mat.diagonal().tail(size-k).cwiseAbs().maxCoeff(&index_of_biggest_in_corner);
+ index_of_biggest_in_corner += k;
+
+ if(k == 0)
+ {
+ // The biggest overall is the point of reference to which further diagonals
+ // are compared; if any diagonal is negligible compared
+ // to the largest overall, the algorithm bails.
+ cutoff = abs(NumTraits<Scalar>::epsilon() * biggest_in_corner);
+
+ if(sign)
+ *sign = real(mat.diagonal().coeff(index_of_biggest_in_corner)) > 0 ? 1 : -1;
+ }
+
+ // Finish early if the matrix is not full rank.
+ if(biggest_in_corner < cutoff)
+ {
+ for(Index i = k; i < size; i++) transpositions.coeffRef(i) = i;
+ break;
+ }
+
+ transpositions.coeffRef(k) = index_of_biggest_in_corner;
+ if(k != index_of_biggest_in_corner)
+ {
+ // apply the transposition while taking care to consider only
+ // the lower triangular part
+ Index s = size-index_of_biggest_in_corner-1; // trailing size after the biggest element
+ 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<index_of_biggest_in_corner;++i)
+ {
+ Scalar tmp = mat.coeffRef(i,k);
+ mat.coeffRef(i,k) = conj(mat.coeffRef(index_of_biggest_in_corner,i));
+ mat.coeffRef(index_of_biggest_in_corner,i) = conj(tmp);
+ }
+ if(NumTraits<Scalar>::IsComplex)
+ mat.coeffRef(index_of_biggest_in_corner,k) = conj(mat.coeff(index_of_biggest_in_corner,k));
+ }
+
+ // partition the matrix:
+ // A00 | - | -
+ // lu = A10 | A11 | -
+ // A20 | A21 | A22
+ Index rs = size - k - 1;
+ Block<MatrixType,Dynamic,1> A21(mat,k+1,k,rs,1);
+ Block<MatrixType,1,Dynamic> A10(mat,k,0,1,k);
+ Block<MatrixType,Dynamic,Dynamic> A20(mat,k+1,0,rs,k);
+
+ if(k>0)
+ {
+ temp.head(k) = mat.diagonal().head(k).asDiagonal() * A10.adjoint();
+ mat.coeffRef(k,k) -= (A10 * temp.head(k)).value();
+ if(rs>0)
+ A21.noalias() -= A20 * temp.head(k);
+ }
+ if((rs>0) && (abs(mat.coeffRef(k,k)) > cutoff))
+ A21 /= mat.coeffRef(k,k);
+ }
+
+ return true;
+ }
+
+ // Reference for the algorithm: Davis and Hager, "Multiple Rank
+ // Modifications of a Sparse Cholesky Factorization" (Algorithm 1)
+ // Trivial rearrangements of their computations (Timothy E. Holy)
+ // allow their algorithm to work for rank-1 updates even if the
+ // original matrix is not of full rank.
+ // Here only rank-1 updates are implemented, to reduce the
+ // requirement for intermediate storage and improve accuracy
+ template<typename MatrixType, typename WDerived>
+ static bool updateInPlace(MatrixType& mat, MatrixBase<WDerived>& w, typename MatrixType::RealScalar sigma=1)
+ {
+ using internal::isfinite;
+ typedef typename MatrixType::Scalar Scalar;
+ typedef typename MatrixType::RealScalar RealScalar;
+ typedef typename MatrixType::Index Index;
+
+ const Index size = mat.rows();
+ eigen_assert(mat.cols() == size && w.size()==size);
+
+ RealScalar alpha = 1;
+
+ // Apply the update
+ for (Index j = 0; j < size; j++)
+ {
+ // Check for termination due to an original decomposition of low-rank
+ if (!(isfinite)(alpha))
+ break;
+
+ // Update the diagonal terms
+ RealScalar dj = real(mat.coeff(j,j));
+ Scalar wj = w.coeff(j);
+ RealScalar swj2 = sigma*abs2(wj);
+ RealScalar gamma = dj*alpha + swj2;
+
+ mat.coeffRef(j,j) += swj2/alpha;
+ alpha += swj2/dj;
+
+
+ // Update the terms of L
+ Index rs = size-j-1;
+ w.tail(rs) -= wj * mat.col(j).tail(rs);
+ if(gamma != 0)
+ mat.col(j).tail(rs) += (sigma*conj(wj)/gamma)*w.tail(rs);
+ }
+ return true;
+ }
+
+ template<typename MatrixType, typename TranspositionType, typename Workspace, typename WType>
+ static bool update(MatrixType& mat, const TranspositionType& transpositions, Workspace& tmp, const WType& w, typename MatrixType::RealScalar sigma=1)
+ {
+ // Apply the permutation to the input w
+ tmp = transpositions * w;
+
+ return ldlt_inplace<Lower>::updateInPlace(mat,tmp,sigma);
+ }
+};
+
+template<> struct ldlt_inplace<Upper>
+{
+ template<typename MatrixType, typename TranspositionType, typename Workspace>
+ static EIGEN_STRONG_INLINE bool unblocked(MatrixType& mat, TranspositionType& transpositions, Workspace& temp, int* sign=0)
+ {
+ Transpose<MatrixType> matt(mat);
+ return ldlt_inplace<Lower>::unblocked(matt, transpositions, temp, sign);
+ }
+
+ template<typename MatrixType, typename TranspositionType, typename Workspace, typename WType>
+ static EIGEN_STRONG_INLINE bool update(MatrixType& mat, TranspositionType& transpositions, Workspace& tmp, WType& w, typename MatrixType::RealScalar sigma=1)
+ {
+ Transpose<MatrixType> matt(mat);
+ return ldlt_inplace<Lower>::update(matt, transpositions, tmp, w.conjugate(), sigma);
+ }
+};
+
+template<typename MatrixType> struct LDLT_Traits<MatrixType,Lower>
+{
+ typedef const TriangularView<const MatrixType, UnitLower> MatrixL;
+ typedef const TriangularView<const typename MatrixType::AdjointReturnType, UnitUpper> MatrixU;
+ static inline MatrixL getL(const MatrixType& m) { return m; }
+ static inline MatrixU getU(const MatrixType& m) { return m.adjoint(); }
+};
+
+template<typename MatrixType> struct LDLT_Traits<MatrixType,Upper>
+{
+ typedef const TriangularView<const typename MatrixType::AdjointReturnType, UnitLower> MatrixL;
+ typedef const TriangularView<const MatrixType, UnitUpper> MatrixU;
+ static inline MatrixL getL(const MatrixType& m) { return m.adjoint(); }
+ static inline MatrixU getU(const MatrixType& m) { return m; }
+};
+
+} // end namespace internal
+
+/** Compute / recompute the LDLT decomposition A = L D L^* = U^* D U of \a matrix
+ */
+template<typename MatrixType, int _UpLo>
+LDLT<MatrixType,_UpLo>& LDLT<MatrixType,_UpLo>::compute(const MatrixType& a)
+{
+ eigen_assert(a.rows()==a.cols());
+ const Index size = a.rows();
+
+ m_matrix = a;
+
+ m_transpositions.resize(size);
+ m_isInitialized = false;
+ m_temporary.resize(size);
+
+ internal::ldlt_inplace<UpLo>::unblocked(m_matrix, m_transpositions, m_temporary, &m_sign);
+
+ m_isInitialized = true;
+ return *this;
+}
+
+/** Update the LDLT decomposition: given A = L D L^T, efficiently compute the decomposition of A + sigma w w^T.
+ * \param w a vector to be incorporated into the decomposition.
+ * \param sigma a scalar, +1 for updates and -1 for "downdates," which correspond to removing previously-added column vectors. Optional; default value is +1.
+ * \sa setZero()
+ */
+template<typename MatrixType, int _UpLo>
+template<typename Derived>
+LDLT<MatrixType,_UpLo>& LDLT<MatrixType,_UpLo>::rankUpdate(const MatrixBase<Derived>& w,typename NumTraits<typename MatrixType::Scalar>::Real sigma)
+{
+ const Index size = w.rows();
+ if (m_isInitialized)
+ {
+ eigen_assert(m_matrix.rows()==size);
+ }
+ else
+ {
+ m_matrix.resize(size,size);
+ m_matrix.setZero();
+ m_transpositions.resize(size);
+ for (Index i = 0; i < size; i++)
+ m_transpositions.coeffRef(i) = i;
+ m_temporary.resize(size);
+ m_sign = sigma>=0 ? 1 : -1;
+ m_isInitialized = true;
+ }
+
+ internal::ldlt_inplace<UpLo>::update(m_matrix, m_transpositions, m_temporary, w, sigma);
+
+ return *this;
+}
+
+namespace internal {
+template<typename _MatrixType, int _UpLo, typename Rhs>
+struct solve_retval<LDLT<_MatrixType,_UpLo>, Rhs>
+ : solve_retval_base<LDLT<_MatrixType,_UpLo>, Rhs>
+{
+ typedef LDLT<_MatrixType,_UpLo> LDLTType;
+ EIGEN_MAKE_SOLVE_HELPERS(LDLTType,Rhs)
+
+ template<typename Dest> void evalTo(Dest& dst) const
+ {
+ 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::Scalar Scalar;
+ typedef typename LDLTType::RealScalar RealScalar;
+ const Diagonal<const MatrixType> vectorD = dec().vectorD();
+ RealScalar tolerance = (max)(vectorD.array().abs().maxCoeff() * NumTraits<Scalar>::epsilon(),
+ RealScalar(1) / NumTraits<RealScalar>::highest()); // motivated by LAPACK's xGELSS
+ for (Index i = 0; i < vectorD.size(); ++i) {
+ if(abs(vectorD(i)) > tolerance)
+ dst.row(i) /= vectorD(i);
+ else
+ dst.row(i).setZero();
+ }
+
+ // dst = L^-T (D^-1 L^-1 P b)
+ dec().matrixU().solveInPlace(dst);
+
+ // dst = P^-1 (L^-T D^-1 L^-1 P b) = A^-1 b
+ dst = dec().transpositionsP().transpose() * dst;
+ }
+};
+}
+
+/** \internal use x = ldlt_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.
+ *
+ * \sa LDLT::solve(), MatrixBase::ldlt()
+ */
+template<typename MatrixType,int _UpLo>
+template<typename Derived>
+bool LDLT<MatrixType,_UpLo>::solveInPlace(MatrixBase<Derived> &bAndX) const
+{
+ eigen_assert(m_isInitialized && "LDLT is not initialized.");
+ const Index size = m_matrix.rows();
+ eigen_assert(size == bAndX.rows());
+
+ bAndX = this->solve(bAndX);
+
+ return true;
+}
+
+/** \returns the matrix represented by the decomposition,
+ * i.e., it returns the product: P^T L D L^* P.
+ * This function is provided for debug purpose. */
+template<typename MatrixType, int _UpLo>
+MatrixType LDLT<MatrixType,_UpLo>::reconstructedMatrix() const
+{
+ eigen_assert(m_isInitialized && "LDLT is not initialized.");
+ const Index size = m_matrix.rows();
+ MatrixType res(size,size);
+
+ // P
+ res.setIdentity();
+ res = transpositionsP() * res;
+ // L^* P
+ res = matrixU() * res;
+ // D(L^*P)
+ res = vectorD().asDiagonal() * res;
+ // L(DL^*P)
+ res = matrixL() * res;
+ // P^T (LDL^*P)
+ res = transpositionsP().transpose() * res;
+
+ return res;
+}
+
+/** \cholesky_module
+ * \returns the Cholesky decomposition with full pivoting without square root of \c *this
+ */
+template<typename MatrixType, unsigned int UpLo>
+inline const LDLT<typename SelfAdjointView<MatrixType, UpLo>::PlainObject, UpLo>
+SelfAdjointView<MatrixType, UpLo>::ldlt() const
+{
+ return LDLT<PlainObject,UpLo>(m_matrix);
+}
+
+/** \cholesky_module
+ * \returns the Cholesky decomposition with full pivoting without square root of \c *this
+ */
+template<typename Derived>
+inline const LDLT<typename MatrixBase<Derived>::PlainObject>
+MatrixBase<Derived>::ldlt() const
+{
+ return LDLT<PlainObject>(derived());
+}
+
+} // end namespace Eigen
+
+#endif // EIGEN_LDLT_H
diff --git a/Eigen/src/Cholesky/LLT.h b/Eigen/src/Cholesky/LLT.h
new file mode 100644
index 000000000..41d14e532
--- /dev/null
+++ b/Eigen/src/Cholesky/LLT.h
@@ -0,0 +1,488 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra.
+//
+// Copyright (C) 2008 Gael Guennebaud <gael.guennebaud@inria.fr>
+//
+// This Source Code Form is subject to the terms of the Mozilla
+// Public License v. 2.0. If a copy of the MPL was not distributed
+// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+#ifndef EIGEN_LLT_H
+#define EIGEN_LLT_H
+
+namespace Eigen {
+
+namespace internal{
+template<typename MatrixType, int UpLo> struct LLT_Traits;
+}
+
+/** \ingroup Cholesky_Module
+ *
+ * \class LLT
+ *
+ * \brief Standard Cholesky decomposition (LL^T) of a matrix and associated features
+ *
+ * \param MatrixType the type of the matrix of which we are computing the LL^T Cholesky decomposition
+ * \param UpLo the triangular part that will be used for the decompositon: Lower (default) or Upper.
+ * The other triangular part won't be read.
+ *
+ * This class performs a LL^T Cholesky decomposition of a symmetric, positive definite
+ * matrix A such that A = LL^* = U^*U, where L is lower triangular.
+ *
+ * While the Cholesky decomposition is particularly useful to solve selfadjoint problems like D^*D x = b,
+ * for that purpose, we recommend the Cholesky decomposition without square root which is more stable
+ * and even faster. Nevertheless, this standard Cholesky decomposition remains useful in many other
+ * situations like generalised eigen problems with hermitian matrices.
+ *
+ * Remember that Cholesky decompositions are not rank-revealing. This LLT decomposition is only stable on positive definite matrices,
+ * use LDLT instead for the semidefinite case. Also, do not use a Cholesky decomposition to determine whether a system of equations
+ * has a solution.
+ *
+ * Example: \include LLT_example.cpp
+ * Output: \verbinclude LLT_example.out
+ *
+ * \sa MatrixBase::llt(), class LDLT
+ */
+ /* HEY THIS DOX IS DISABLED BECAUSE THERE's A BUG EITHER HERE OR IN LDLT ABOUT THAT (OR BOTH)
+ * Note that during the decomposition, only the upper triangular part of A is considered. Therefore,
+ * the strict lower part does not have to store correct values.
+ */
+template<typename _MatrixType, int _UpLo> class LLT
+{
+ public:
+ typedef _MatrixType MatrixType;
+ enum {
+ RowsAtCompileTime = MatrixType::RowsAtCompileTime,
+ ColsAtCompileTime = MatrixType::ColsAtCompileTime,
+ Options = MatrixType::Options,
+ MaxColsAtCompileTime = MatrixType::MaxColsAtCompileTime
+ };
+ typedef typename MatrixType::Scalar Scalar;
+ typedef typename NumTraits<typename MatrixType::Scalar>::Real RealScalar;
+ typedef typename MatrixType::Index Index;
+
+ enum {
+ PacketSize = internal::packet_traits<Scalar>::size,
+ AlignmentMask = int(PacketSize)-1,
+ UpLo = _UpLo
+ };
+
+ typedef internal::LLT_Traits<MatrixType,UpLo> Traits;
+
+ /**
+ * \brief Default Constructor.
+ *
+ * The default constructor is useful in cases in which the user intends to
+ * perform decompositions via LLT::compute(const MatrixType&).
+ */
+ LLT() : m_matrix(), m_isInitialized(false) {}
+
+ /** \brief Default Constructor with memory preallocation
+ *
+ * Like the default constructor but with preallocation of the internal data
+ * according to the specified problem \a size.
+ * \sa LLT()
+ */
+ LLT(Index size) : m_matrix(size, size),
+ m_isInitialized(false) {}
+
+ LLT(const MatrixType& matrix)
+ : m_matrix(matrix.rows(), matrix.cols()),
+ m_isInitialized(false)
+ {
+ compute(matrix);
+ }
+
+ /** \returns a view of the upper triangular matrix U */
+ inline typename Traits::MatrixU matrixU() const
+ {
+ eigen_assert(m_isInitialized && "LLT is not initialized.");
+ return Traits::getU(m_matrix);
+ }
+
+ /** \returns a view of the lower triangular matrix L */
+ inline typename Traits::MatrixL matrixL() const
+ {
+ eigen_assert(m_isInitialized && "LLT is not initialized.");
+ return Traits::getL(m_matrix);
+ }
+
+ /** \returns the solution x of \f$ A x = b \f$ using the current decomposition of A.
+ *
+ * Since this LLT class assumes anyway that the matrix A is invertible, the solution
+ * theoretically exists and is unique regardless of b.
+ *
+ * Example: \include LLT_solve.cpp
+ * Output: \verbinclude LLT_solve.out
+ *
+ * \sa solveInPlace(), MatrixBase::llt()
+ */
+ template<typename Rhs>
+ inline const internal::solve_retval<LLT, Rhs>
+ solve(const MatrixBase<Rhs>& 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<LLT, Rhs>(*this, b.derived());
+ }
+
+ #ifdef EIGEN2_SUPPORT
+ template<typename OtherDerived, typename ResultType>
+ bool solve(const MatrixBase<OtherDerived>& b, ResultType *result) const
+ {
+ *result = this->solve(b);
+ return true;
+ }
+
+ bool isPositiveDefinite() const { return true; }
+ #endif
+
+ template<typename Derived>
+ void solveInPlace(MatrixBase<Derived> &bAndX) const;
+
+ LLT& compute(const MatrixType& matrix);
+
+ /** \returns the LLT decomposition matrix
+ *
+ * TODO: document the storage layout
+ */
+ inline const MatrixType& matrixLLT() const
+ {
+ eigen_assert(m_isInitialized && "LLT is not initialized.");
+ return m_matrix;
+ }
+
+ MatrixType reconstructedMatrix() const;
+
+
+ /** \brief Reports whether previous computation was successful.
+ *
+ * \returns \c Success if computation was succesful,
+ * \c NumericalIssue if the matrix.appears to be negative.
+ */
+ ComputationInfo info() const
+ {
+ eigen_assert(m_isInitialized && "LLT is not initialized.");
+ return m_info;
+ }
+
+ inline Index rows() const { return m_matrix.rows(); }
+ inline Index cols() const { return m_matrix.cols(); }
+
+ template<typename VectorType>
+ LLT rankUpdate(const VectorType& vec, const RealScalar& sigma = 1);
+
+ protected:
+ /** \internal
+ * Used to compute and store L
+ * The strict upper part is not used and even not initialized.
+ */
+ MatrixType m_matrix;
+ bool m_isInitialized;
+ ComputationInfo m_info;
+};
+
+namespace internal {
+
+template<typename Scalar, int UpLo> struct llt_inplace;
+
+template<typename MatrixType, typename VectorType>
+static typename MatrixType::Index llt_rank_update_lower(MatrixType& mat, const VectorType& vec, const typename MatrixType::RealScalar& sigma)
+{
+ typedef typename MatrixType::Scalar Scalar;
+ typedef typename MatrixType::RealScalar RealScalar;
+ typedef typename MatrixType::Index Index;
+ typedef typename MatrixType::ColXpr ColXpr;
+ typedef typename internal::remove_all<ColXpr>::type ColXprCleaned;
+ typedef typename ColXprCleaned::SegmentReturnType ColXprSegment;
+ typedef Matrix<Scalar,Dynamic,1> TempVectorType;
+ typedef typename TempVectorType::SegmentReturnType TempVecSegment;
+
+ int n = mat.cols();
+ eigen_assert(mat.rows()==n && vec.size()==n);
+
+ TempVectorType temp;
+
+ if(sigma>0)
+ {
+ // This version is based on Givens rotations.
+ // It is faster than the other one below, but only works for updates,
+ // i.e., for sigma > 0
+ temp = sqrt(sigma) * vec;
+
+ for(int i=0; i<n; ++i)
+ {
+ JacobiRotation<Scalar> g;
+ g.makeGivens(mat(i,i), -temp(i), &mat(i,i));
+
+ int rs = n-i-1;
+ if(rs>0)
+ {
+ ColXprSegment x(mat.col(i).tail(rs));
+ TempVecSegment y(temp.tail(rs));
+ apply_rotation_in_the_plane(x, y, g);
+ }
+ }
+ }
+ else
+ {
+ temp = vec;
+ RealScalar beta = 1;
+ for(int j=0; j<n; ++j)
+ {
+ RealScalar Ljj = real(mat.coeff(j,j));
+ RealScalar dj = abs2(Ljj);
+ Scalar wj = temp.coeff(j);
+ RealScalar swj2 = sigma*abs2(wj);
+ RealScalar gamma = dj*beta + swj2;
+
+ RealScalar x = dj + swj2/beta;
+ if (x<=RealScalar(0))
+ return j;
+ RealScalar nLjj = sqrt(x);
+ mat.coeffRef(j,j) = nLjj;
+ beta += swj2/dj;
+
+ // Update the terms of L
+ Index rs = n-j-1;
+ if(rs)
+ {
+ temp.tail(rs) -= (wj/Ljj) * mat.col(j).tail(rs);
+ if(gamma != 0)
+ mat.col(j).tail(rs) = (nLjj/Ljj) * mat.col(j).tail(rs) + (nLjj * sigma*conj(wj)/gamma)*temp.tail(rs);
+ }
+ }
+ }
+ return -1;
+}
+
+template<typename Scalar> struct llt_inplace<Scalar, Lower>
+{
+ typedef typename NumTraits<Scalar>::Real RealScalar;
+ template<typename MatrixType>
+ static typename MatrixType::Index unblocked(MatrixType& mat)
+ {
+ typedef typename MatrixType::Index Index;
+
+ eigen_assert(mat.rows()==mat.cols());
+ const Index size = mat.rows();
+ for(Index k = 0; k < size; ++k)
+ {
+ Index rs = size-k-1; // remaining size
+
+ Block<MatrixType,Dynamic,1> A21(mat,k+1,k,rs,1);
+ Block<MatrixType,1,Dynamic> A10(mat,k,0,1,k);
+ Block<MatrixType,Dynamic,Dynamic> A20(mat,k+1,0,rs,k);
+
+ RealScalar x = real(mat.coeff(k,k));
+ if (k>0) x -= A10.squaredNorm();
+ if (x<=RealScalar(0))
+ return k;
+ mat.coeffRef(k,k) = x = sqrt(x);
+ if (k>0 && rs>0) A21.noalias() -= A20 * A10.adjoint();
+ if (rs>0) A21 *= RealScalar(1)/x;
+ }
+ return -1;
+ }
+
+ template<typename MatrixType>
+ static typename MatrixType::Index blocked(MatrixType& m)
+ {
+ typedef typename MatrixType::Index Index;
+ eigen_assert(m.rows()==m.cols());
+ Index size = m.rows();
+ if(size<32)
+ return unblocked(m);
+
+ Index blockSize = size/8;
+ blockSize = (blockSize/16)*16;
+ blockSize = (std::min)((std::max)(blockSize,Index(8)), Index(128));
+
+ for (Index k=0; k<size; k+=blockSize)
+ {
+ // partition the matrix:
+ // A00 | - | -
+ // lu = A10 | A11 | -
+ // A20 | A21 | A22
+ Index bs = (std::min)(blockSize, size-k);
+ Index rs = size - k - bs;
+ Block<MatrixType,Dynamic,Dynamic> A11(m,k, k, bs,bs);
+ Block<MatrixType,Dynamic,Dynamic> A21(m,k+bs,k, rs,bs);
+ Block<MatrixType,Dynamic,Dynamic> A22(m,k+bs,k+bs,rs,rs);
+
+ Index ret;
+ if((ret=unblocked(A11))>=0) return k+ret;
+ if(rs>0) A11.adjoint().template triangularView<Upper>().template solveInPlace<OnTheRight>(A21);
+ if(rs>0) A22.template selfadjointView<Lower>().rankUpdate(A21,-1); // bottleneck
+ }
+ return -1;
+ }
+
+ template<typename MatrixType, typename VectorType>
+ static typename MatrixType::Index rankUpdate(MatrixType& mat, const VectorType& vec, const RealScalar& sigma)
+ {
+ return Eigen::internal::llt_rank_update_lower(mat, vec, sigma);
+ }
+};
+
+template<typename Scalar> struct llt_inplace<Scalar, Upper>
+{
+ typedef typename NumTraits<Scalar>::Real RealScalar;
+
+ template<typename MatrixType>
+ static EIGEN_STRONG_INLINE typename MatrixType::Index unblocked(MatrixType& mat)
+ {
+ Transpose<MatrixType> matt(mat);
+ return llt_inplace<Scalar, Lower>::unblocked(matt);
+ }
+ template<typename MatrixType>
+ static EIGEN_STRONG_INLINE typename MatrixType::Index blocked(MatrixType& mat)
+ {
+ Transpose<MatrixType> matt(mat);
+ return llt_inplace<Scalar, Lower>::blocked(matt);
+ }
+ template<typename MatrixType, typename VectorType>
+ static typename MatrixType::Index rankUpdate(MatrixType& mat, const VectorType& vec, const RealScalar& sigma)
+ {
+ Transpose<MatrixType> matt(mat);
+ return llt_inplace<Scalar, Lower>::rankUpdate(matt, vec.conjugate(), sigma);
+ }
+};
+
+template<typename MatrixType> struct LLT_Traits<MatrixType,Lower>
+{
+ typedef const TriangularView<const MatrixType, Lower> MatrixL;
+ typedef const TriangularView<const typename MatrixType::AdjointReturnType, Upper> MatrixU;
+ static inline MatrixL getL(const MatrixType& m) { return m; }
+ static inline MatrixU getU(const MatrixType& m) { return m.adjoint(); }
+ static bool inplace_decomposition(MatrixType& m)
+ { return llt_inplace<typename MatrixType::Scalar, Lower>::blocked(m)==-1; }
+};
+
+template<typename MatrixType> struct LLT_Traits<MatrixType,Upper>
+{
+ typedef const TriangularView<const typename MatrixType::AdjointReturnType, Lower> MatrixL;
+ typedef const TriangularView<const MatrixType, Upper> MatrixU;
+ static inline MatrixL getL(const MatrixType& m) { return m.adjoint(); }
+ static inline MatrixU getU(const MatrixType& m) { return m; }
+ static bool inplace_decomposition(MatrixType& m)
+ { return llt_inplace<typename MatrixType::Scalar, Upper>::blocked(m)==-1; }
+};
+
+} // end namespace internal
+
+/** Computes / recomputes the Cholesky decomposition A = LL^* = U^*U of \a matrix
+ *
+ * \returns a reference to *this
+ *
+ * Example: \include TutorialLinAlgComputeTwice.cpp
+ * Output: \verbinclude TutorialLinAlgComputeTwice.out
+ */
+template<typename MatrixType, int _UpLo>
+LLT<MatrixType,_UpLo>& LLT<MatrixType,_UpLo>::compute(const MatrixType& a)
+{
+ eigen_assert(a.rows()==a.cols());
+ const Index size = a.rows();
+ m_matrix.resize(size, size);
+ m_matrix = a;
+
+ m_isInitialized = true;
+ bool ok = Traits::inplace_decomposition(m_matrix);
+ m_info = ok ? Success : NumericalIssue;
+
+ return *this;
+}
+
+/** Performs a rank one update (or dowdate) of the current decomposition.
+ * If A = LL^* before the rank one update,
+ * then after it we have LL^* = A + sigma * v v^* where \a v must be a vector
+ * of same dimension.
+ */
+template<typename _MatrixType, int _UpLo>
+template<typename VectorType>
+LLT<_MatrixType,_UpLo> LLT<_MatrixType,_UpLo>::rankUpdate(const VectorType& v, const RealScalar& sigma)
+{
+ EIGEN_STATIC_ASSERT_VECTOR_ONLY(VectorType);
+ eigen_assert(v.size()==m_matrix.cols());
+ eigen_assert(m_isInitialized);
+ if(internal::llt_inplace<typename MatrixType::Scalar, UpLo>::rankUpdate(m_matrix,v,sigma)>=0)
+ m_info = NumericalIssue;
+ else
+ m_info = Success;
+
+ return *this;
+}
+
+namespace internal {
+template<typename _MatrixType, int UpLo, typename Rhs>
+struct solve_retval<LLT<_MatrixType, UpLo>, Rhs>
+ : solve_retval_base<LLT<_MatrixType, UpLo>, Rhs>
+{
+ typedef LLT<_MatrixType,UpLo> LLTType;
+ EIGEN_MAKE_SOLVE_HELPERS(LLTType,Rhs)
+
+ template<typename Dest> void evalTo(Dest& dst) const
+ {
+ dst = rhs();
+ dec().solveInPlace(dst);
+ }
+};
+}
+
+/** \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.
+ *
+ * \sa LLT::solve(), MatrixBase::llt()
+ */
+template<typename MatrixType, int _UpLo>
+template<typename Derived>
+void LLT<MatrixType,_UpLo>::solveInPlace(MatrixBase<Derived> &bAndX) const
+{
+ eigen_assert(m_isInitialized && "LLT is not initialized.");
+ eigen_assert(m_matrix.rows()==bAndX.rows());
+ matrixL().solveInPlace(bAndX);
+ matrixU().solveInPlace(bAndX);
+}
+
+/** \returns the matrix represented by the decomposition,
+ * i.e., it returns the product: L L^*.
+ * This function is provided for debug purpose. */
+template<typename MatrixType, int _UpLo>
+MatrixType LLT<MatrixType,_UpLo>::reconstructedMatrix() const
+{
+ eigen_assert(m_isInitialized && "LLT is not initialized.");
+ return matrixL() * matrixL().adjoint().toDenseMatrix();
+}
+
+/** \cholesky_module
+ * \returns the LLT decomposition of \c *this
+ */
+template<typename Derived>
+inline const LLT<typename MatrixBase<Derived>::PlainObject>
+MatrixBase<Derived>::llt() const
+{
+ return LLT<PlainObject>(derived());
+}
+
+/** \cholesky_module
+ * \returns the LLT decomposition of \c *this
+ */
+template<typename MatrixType, unsigned int UpLo>
+inline const LLT<typename SelfAdjointView<MatrixType, UpLo>::PlainObject, UpLo>
+SelfAdjointView<MatrixType, UpLo>::llt() const
+{
+ return LLT<PlainObject,UpLo>(m_matrix);
+}
+
+} // end namespace Eigen
+
+#endif // EIGEN_LLT_H
diff --git a/Eigen/src/Cholesky/LLT_MKL.h b/Eigen/src/Cholesky/LLT_MKL.h
new file mode 100644
index 000000000..64daa445c
--- /dev/null
+++ b/Eigen/src/Cholesky/LLT_MKL.h
@@ -0,0 +1,102 @@
+/*
+ Copyright (c) 2011, Intel Corporation. All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without modification,
+ are permitted provided that the following conditions are met:
+
+ * Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+ * Neither the name of Intel Corporation nor the names of its contributors may
+ be used to endorse or promote products derived from this software without
+ specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+ ********************************************************************************
+ * Content : Eigen bindings to Intel(R) MKL
+ * LLt decomposition based on LAPACKE_?potrf function.
+ ********************************************************************************
+*/
+
+#ifndef EIGEN_LLT_MKL_H
+#define EIGEN_LLT_MKL_H
+
+#include "Eigen/src/Core/util/MKL_support.h"
+#include <iostream>
+
+namespace Eigen {
+
+namespace internal {
+
+template<typename Scalar> struct mkl_llt;
+
+#define EIGEN_MKL_LLT(EIGTYPE, MKLTYPE, MKLPREFIX) \
+template<> struct mkl_llt<EIGTYPE> \
+{ \
+ template<typename MatrixType> \
+ static inline typename MatrixType::Index potrf(MatrixType& m, char uplo) \
+ { \
+ lapack_int matrix_order; \
+ lapack_int size, lda, info, StorageOrder; \
+ EIGTYPE* a; \
+ eigen_assert(m.rows()==m.cols()); \
+ /* Set up parameters for ?potrf */ \
+ size = m.rows(); \
+ StorageOrder = MatrixType::Flags&RowMajorBit?RowMajor:ColMajor; \
+ matrix_order = StorageOrder==RowMajor ? LAPACK_ROW_MAJOR : LAPACK_COL_MAJOR; \
+ a = &(m.coeffRef(0,0)); \
+ lda = m.outerStride(); \
+\
+ info = LAPACKE_##MKLPREFIX##potrf( matrix_order, uplo, size, (MKLTYPE*)a, lda ); \
+ info = (info==0) ? Success : NumericalIssue; \
+ return info; \
+ } \
+}; \
+template<> struct llt_inplace<EIGTYPE, Lower> \
+{ \
+ template<typename MatrixType> \
+ static typename MatrixType::Index blocked(MatrixType& m) \
+ { \
+ return mkl_llt<EIGTYPE>::potrf(m, 'L'); \
+ } \
+ template<typename MatrixType, typename VectorType> \
+ static typename MatrixType::Index rankUpdate(MatrixType& mat, const VectorType& vec, const typename MatrixType::RealScalar& sigma) \
+ { return Eigen::internal::llt_rank_update_lower(mat, vec, sigma); } \
+}; \
+template<> struct llt_inplace<EIGTYPE, Upper> \
+{ \
+ template<typename MatrixType> \
+ static typename MatrixType::Index blocked(MatrixType& m) \
+ { \
+ return mkl_llt<EIGTYPE>::potrf(m, 'U'); \
+ } \
+ template<typename MatrixType, typename VectorType> \
+ static typename MatrixType::Index rankUpdate(MatrixType& mat, const VectorType& vec, const typename MatrixType::RealScalar& sigma) \
+ { \
+ Transpose<MatrixType> matt(mat); \
+ return llt_inplace<EIGTYPE, Lower>::rankUpdate(matt, vec.conjugate(), sigma); \
+ } \
+};
+
+EIGEN_MKL_LLT(double, double, d)
+EIGEN_MKL_LLT(float, float, s)
+EIGEN_MKL_LLT(dcomplex, MKL_Complex16, z)
+EIGEN_MKL_LLT(scomplex, MKL_Complex8, c)
+
+} // end namespace internal
+
+} // end namespace Eigen
+
+#endif // EIGEN_LLT_MKL_H
diff --git a/Eigen/src/CholmodSupport/CMakeLists.txt b/Eigen/src/CholmodSupport/CMakeLists.txt
new file mode 100644
index 000000000..814dfa613
--- /dev/null
+++ b/Eigen/src/CholmodSupport/CMakeLists.txt
@@ -0,0 +1,6 @@
+FILE(GLOB Eigen_CholmodSupport_SRCS "*.h")
+
+INSTALL(FILES
+ ${Eigen_CholmodSupport_SRCS}
+ DESTINATION ${INCLUDE_INSTALL_DIR}/Eigen/src/CholmodSupport COMPONENT Devel
+ )
diff --git a/Eigen/src/CholmodSupport/CholmodSupport.h b/Eigen/src/CholmodSupport/CholmodSupport.h
new file mode 100644
index 000000000..37f142150
--- /dev/null
+++ b/Eigen/src/CholmodSupport/CholmodSupport.h
@@ -0,0 +1,579 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra.
+//
+// Copyright (C) 2008-2010 Gael Guennebaud <gael.guennebaud@inria.fr>
+//
+// This Source Code Form is subject to the terms of the Mozilla
+// Public License v. 2.0. If a copy of the MPL was not distributed
+// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+#ifndef EIGEN_CHOLMODSUPPORT_H
+#define EIGEN_CHOLMODSUPPORT_H
+
+namespace Eigen {
+
+namespace internal {
+
+template<typename Scalar, typename CholmodType>
+void cholmod_configure_matrix(CholmodType& mat)
+{
+ if (internal::is_same<Scalar,float>::value)
+ {
+ mat.xtype = CHOLMOD_REAL;
+ mat.dtype = CHOLMOD_SINGLE;
+ }
+ else if (internal::is_same<Scalar,double>::value)
+ {
+ mat.xtype = CHOLMOD_REAL;
+ mat.dtype = CHOLMOD_DOUBLE;
+ }
+ else if (internal::is_same<Scalar,std::complex<float> >::value)
+ {
+ mat.xtype = CHOLMOD_COMPLEX;
+ mat.dtype = CHOLMOD_SINGLE;
+ }
+ else if (internal::is_same<Scalar,std::complex<double> >::value)
+ {
+ mat.xtype = CHOLMOD_COMPLEX;
+ mat.dtype = CHOLMOD_DOUBLE;
+ }
+ else
+ {
+ eigen_assert(false && "Scalar type not supported by CHOLMOD");
+ }
+}
+
+} // namespace internal
+
+/** Wraps the Eigen sparse matrix \a mat into a Cholmod sparse matrix object.
+ * Note that the data are shared.
+ */
+template<typename _Scalar, int _Options, typename _Index>
+cholmod_sparse viewAsCholmod(SparseMatrix<_Scalar,_Options,_Index>& mat)
+{
+ typedef SparseMatrix<_Scalar,_Options,_Index> MatrixType;
+ cholmod_sparse res;
+ res.nzmax = mat.nonZeros();
+ res.nrow = mat.rows();;
+ res.ncol = mat.cols();
+ res.p = mat.outerIndexPtr();
+ res.i = mat.innerIndexPtr();
+ res.x = mat.valuePtr();
+ res.sorted = 1;
+ if(mat.isCompressed())
+ {
+ res.packed = 1;
+ }
+ else
+ {
+ res.packed = 0;
+ res.nz = mat.innerNonZeroPtr();
+ }
+
+ res.dtype = 0;
+ res.stype = -1;
+
+ if (internal::is_same<_Index,int>::value)
+ {
+ res.itype = CHOLMOD_INT;
+ }
+ else
+ {
+ eigen_assert(false && "Index type different than int is not supported yet");
+ }
+
+ // setup res.xtype
+ internal::cholmod_configure_matrix<_Scalar>(res);
+
+ res.stype = 0;
+
+ return res;
+}
+
+template<typename _Scalar, int _Options, typename _Index>
+const cholmod_sparse viewAsCholmod(const SparseMatrix<_Scalar,_Options,_Index>& mat)
+{
+ cholmod_sparse res = viewAsCholmod(mat.const_cast_derived());
+ return res;
+}
+
+/** Returns a view of the Eigen sparse matrix \a mat as Cholmod sparse matrix.
+ * The data are not copied but shared. */
+template<typename _Scalar, int _Options, typename _Index, unsigned int UpLo>
+cholmod_sparse viewAsCholmod(const SparseSelfAdjointView<SparseMatrix<_Scalar,_Options,_Index>, UpLo>& mat)
+{
+ cholmod_sparse res = viewAsCholmod(mat.matrix().const_cast_derived());
+
+ if(UpLo==Upper) res.stype = 1;
+ if(UpLo==Lower) res.stype = -1;
+
+ return res;
+}
+
+/** Returns a view of the Eigen \b dense matrix \a mat as Cholmod dense matrix.
+ * The data are not copied but shared. */
+template<typename Derived>
+cholmod_dense viewAsCholmod(MatrixBase<Derived>& mat)
+{
+ EIGEN_STATIC_ASSERT((internal::traits<Derived>::Flags&RowMajorBit)==0,THIS_METHOD_IS_ONLY_FOR_COLUMN_MAJOR_MATRICES);
+ typedef typename Derived::Scalar Scalar;
+
+ cholmod_dense res;
+ res.nrow = mat.rows();
+ res.ncol = mat.cols();
+ res.nzmax = res.nrow * res.ncol;
+ res.d = Derived::IsVectorAtCompileTime ? mat.derived().size() : mat.derived().outerStride();
+ res.x = mat.derived().data();
+ res.z = 0;
+
+ internal::cholmod_configure_matrix<Scalar>(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<typename Scalar, int Flags, typename Index>
+MappedSparseMatrix<Scalar,Flags,Index> viewAsEigen(cholmod_sparse& cm)
+{
+ return MappedSparseMatrix<Scalar,Flags,Index>
+ (cm.nrow, cm.ncol, reinterpret_cast<Index*>(cm.p)[cm.ncol],
+ reinterpret_cast<Index*>(cm.p), reinterpret_cast<Index*>(cm.i),reinterpret_cast<Scalar*>(cm.x) );
+}
+
+enum CholmodMode {
+ CholmodAuto, CholmodSimplicialLLt, CholmodSupernodalLLt, CholmodLDLt
+};
+
+
+/** \ingroup CholmodSupport_Module
+ * \class CholmodBase
+ * \brief The base class for the direct Cholesky factorization of Cholmod
+ * \sa class CholmodSupernodalLLT, class CholmodSimplicialLDLT, class CholmodSimplicialLLT
+ */
+template<typename _MatrixType, int _UpLo, typename Derived>
+class CholmodBase : internal::noncopyable
+{
+ public:
+ typedef _MatrixType MatrixType;
+ enum { UpLo = _UpLo };
+ typedef typename MatrixType::Scalar Scalar;
+ typedef typename MatrixType::RealScalar RealScalar;
+ typedef MatrixType CholMatrixType;
+ typedef typename MatrixType::Index Index;
+
+ public:
+
+ CholmodBase()
+ : m_cholmodFactor(0), m_info(Success), m_isInitialized(false)
+ {
+ cholmod_start(&m_cholmod);
+ }
+
+ CholmodBase(const MatrixType& matrix)
+ : m_cholmodFactor(0), m_info(Success), m_isInitialized(false)
+ {
+ cholmod_start(&m_cholmod);
+ compute(matrix);
+ }
+
+ ~CholmodBase()
+ {
+ if(m_cholmodFactor)
+ cholmod_free_factor(&m_cholmodFactor, &m_cholmod);
+ cholmod_finish(&m_cholmod);
+ }
+
+ inline Index cols() const { return m_cholmodFactor->n; }
+ inline Index rows() const { return m_cholmodFactor->n; }
+
+ Derived& derived() { return *static_cast<Derived*>(this); }
+ const Derived& derived() const { return *static_cast<const Derived*>(this); }
+
+ /** \brief Reports whether previous computation was successful.
+ *
+ * \returns \c Success if computation was succesful,
+ * \c NumericalIssue if the matrix.appears to be negative.
+ */
+ ComputationInfo info() const
+ {
+ eigen_assert(m_isInitialized && "Decomposition is not initialized.");
+ return m_info;
+ }
+
+ /** Computes the sparse Cholesky decomposition of \a matrix */
+ Derived& compute(const MatrixType& matrix)
+ {
+ analyzePattern(matrix);
+ factorize(matrix);
+ return derived();
+ }
+
+ /** \returns the solution x of \f$ A x = b \f$ using the current decomposition of A.
+ *
+ * \sa compute()
+ */
+ template<typename Rhs>
+ inline const internal::solve_retval<CholmodBase, Rhs>
+ solve(const MatrixBase<Rhs>& 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<CholmodBase, Rhs>(*this, b.derived());
+ }
+
+ /** \returns the solution x of \f$ A x = b \f$ using the current decomposition of A.
+ *
+ * \sa compute()
+ */
+ template<typename Rhs>
+ inline const internal::sparse_solve_retval<CholmodBase, Rhs>
+ solve(const SparseMatrixBase<Rhs>& 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<CholmodBase, Rhs>(*this, b.derived());
+ }
+
+ /** Performs a symbolic decomposition on the sparcity of \a matrix.
+ *
+ * This function is particularly useful when solving for several problems having the same structure.
+ *
+ * \sa factorize()
+ */
+ void analyzePattern(const MatrixType& matrix)
+ {
+ if(m_cholmodFactor)
+ {
+ cholmod_free_factor(&m_cholmodFactor, &m_cholmod);
+ m_cholmodFactor = 0;
+ }
+ cholmod_sparse A = viewAsCholmod(matrix.template selfadjointView<UpLo>());
+ m_cholmodFactor = cholmod_analyze(&A, &m_cholmod);
+
+ this->m_isInitialized = true;
+ this->m_info = Success;
+ m_analysisIsOk = true;
+ m_factorizationIsOk = false;
+ }
+
+ /** Performs a numeric decomposition of \a matrix
+ *
+ * The given matrix must has the same sparcity than the matrix on which the symbolic decomposition has been performed.
+ *
+ * \sa analyzePattern()
+ */
+ void factorize(const MatrixType& matrix)
+ {
+ eigen_assert(m_analysisIsOk && "You must first call analyzePattern()");
+ cholmod_sparse A = viewAsCholmod(matrix.template selfadjointView<UpLo>());
+ cholmod_factorize(&A, m_cholmodFactor, &m_cholmod);
+
+ this->m_info = Success;
+ m_factorizationIsOk = true;
+ }
+
+ /** Returns a reference to the Cholmod's configuration structure to get a full control over the performed operations.
+ * See the Cholmod user guide for details. */
+ cholmod_common& cholmod() { return m_cholmod; }
+
+ #ifndef EIGEN_PARSED_BY_DOXYGEN
+ /** \internal */
+ template<typename Rhs,typename Dest>
+ void _solve(const MatrixBase<Rhs> &b, MatrixBase<Dest> &dest) const
+ {
+ eigen_assert(m_factorizationIsOk && "The decomposition is not in a valid state for solving, you must first call either compute() or symbolic()/numeric()");
+ const Index size = m_cholmodFactor->n;
+ eigen_assert(size==b.rows());
+
+ // note: cd stands for Cholmod Dense
+ cholmod_dense b_cd = viewAsCholmod(b.const_cast_derived());
+ cholmod_dense* x_cd = cholmod_solve(CHOLMOD_A, m_cholmodFactor, &b_cd, &m_cholmod);
+ if(!x_cd)
+ {
+ this->m_info = NumericalIssue;
+ }
+ // TODO optimize this copy by swapping when possible (be carreful with alignment, etc.)
+ dest = Matrix<Scalar,Dest::RowsAtCompileTime,Dest::ColsAtCompileTime>::Map(reinterpret_cast<Scalar*>(x_cd->x),b.rows(),b.cols());
+ cholmod_free_dense(&x_cd, &m_cholmod);
+ }
+
+ /** \internal */
+ template<typename RhsScalar, int RhsOptions, typename RhsIndex, typename DestScalar, int DestOptions, typename DestIndex>
+ void _solve(const SparseMatrix<RhsScalar,RhsOptions,RhsIndex> &b, SparseMatrix<DestScalar,DestOptions,DestIndex> &dest) const
+ {
+ eigen_assert(m_factorizationIsOk && "The decomposition is not in a valid state for solving, you must first call either compute() or symbolic()/numeric()");
+ const Index size = m_cholmodFactor->n;
+ eigen_assert(size==b.rows());
+
+ // note: cs stands for Cholmod Sparse
+ cholmod_sparse b_cs = viewAsCholmod(b);
+ cholmod_sparse* x_cs = cholmod_spsolve(CHOLMOD_A, m_cholmodFactor, &b_cs, &m_cholmod);
+ if(!x_cs)
+ {
+ this->m_info = NumericalIssue;
+ }
+ // TODO optimize this copy by swapping when possible (be carreful with alignment, etc.)
+ dest = viewAsEigen<DestScalar,DestOptions,DestIndex>(*x_cs);
+ cholmod_free_sparse(&x_cs, &m_cholmod);
+ }
+ #endif // EIGEN_PARSED_BY_DOXYGEN
+
+ template<typename Stream>
+ void dumpMemory(Stream& s)
+ {}
+
+ protected:
+ mutable cholmod_common m_cholmod;
+ cholmod_factor* m_cholmodFactor;
+ mutable ComputationInfo m_info;
+ bool m_isInitialized;
+ int m_factorizationIsOk;
+ int m_analysisIsOk;
+};
+
+/** \ingroup CholmodSupport_Module
+ * \class CholmodSimplicialLLT
+ * \brief A simplicial direct Cholesky (LLT) factorization and solver based on Cholmod
+ *
+ * This class allows to solve for A.X = B sparse linear problems via a simplicial LL^T Cholesky factorization
+ * using the Cholmod library.
+ * This simplicial variant is equivalent to Eigen's built-in SimplicialLLT class. Thefore, it has little practical interest.
+ * The sparse matrix A must be selfajoint and positive definite. The vectors or matrices
+ * X and B can be either dense or sparse.
+ *
+ * \tparam _MatrixType the type of the sparse matrix A, it must be a SparseMatrix<>
+ * \tparam _UpLo the triangular part that will be used for the computations. It can be Lower
+ * or Upper. Default is Lower.
+ *
+ * This class supports all kind of SparseMatrix<>: row or column major; upper, lower, or both; compressed or non compressed.
+ *
+ * \sa \ref TutorialSparseDirectSolvers, class CholmodSupernodalLLT, class SimplicialLLT
+ */
+template<typename _MatrixType, int _UpLo = Lower>
+class CholmodSimplicialLLT : public CholmodBase<_MatrixType, _UpLo, CholmodSimplicialLLT<_MatrixType, _UpLo> >
+{
+ typedef CholmodBase<_MatrixType, _UpLo, CholmodSimplicialLLT> Base;
+ using Base::m_cholmod;
+
+ public:
+
+ typedef _MatrixType MatrixType;
+
+ CholmodSimplicialLLT() : Base() { init(); }
+
+ CholmodSimplicialLLT(const MatrixType& matrix) : Base()
+ {
+ init();
+ compute(matrix);
+ }
+
+ ~CholmodSimplicialLLT() {}
+ protected:
+ void init()
+ {
+ m_cholmod.final_asis = 0;
+ m_cholmod.supernodal = CHOLMOD_SIMPLICIAL;
+ m_cholmod.final_ll = 1;
+ }
+};
+
+
+/** \ingroup CholmodSupport_Module
+ * \class CholmodSimplicialLDLT
+ * \brief A simplicial direct Cholesky (LDLT) factorization and solver based on Cholmod
+ *
+ * This class allows to solve for A.X = B sparse linear problems via a simplicial LDL^T Cholesky factorization
+ * using the Cholmod library.
+ * This simplicial variant is equivalent to Eigen's built-in SimplicialLDLT class. Thefore, it has little practical interest.
+ * The sparse matrix A must be selfajoint and positive definite. The vectors or matrices
+ * X and B can be either dense or sparse.
+ *
+ * \tparam _MatrixType the type of the sparse matrix A, it must be a SparseMatrix<>
+ * \tparam _UpLo the triangular part that will be used for the computations. It can be Lower
+ * or Upper. Default is Lower.
+ *
+ * This class supports all kind of SparseMatrix<>: row or column major; upper, lower, or both; compressed or non compressed.
+ *
+ * \sa \ref TutorialSparseDirectSolvers, class CholmodSupernodalLLT, class SimplicialLDLT
+ */
+template<typename _MatrixType, int _UpLo = Lower>
+class CholmodSimplicialLDLT : public CholmodBase<_MatrixType, _UpLo, CholmodSimplicialLDLT<_MatrixType, _UpLo> >
+{
+ typedef CholmodBase<_MatrixType, _UpLo, CholmodSimplicialLDLT> Base;
+ using Base::m_cholmod;
+
+ public:
+
+ typedef _MatrixType MatrixType;
+
+ CholmodSimplicialLDLT() : Base() { init(); }
+
+ CholmodSimplicialLDLT(const MatrixType& matrix) : Base()
+ {
+ init();
+ compute(matrix);
+ }
+
+ ~CholmodSimplicialLDLT() {}
+ protected:
+ void init()
+ {
+ m_cholmod.final_asis = 1;
+ m_cholmod.supernodal = CHOLMOD_SIMPLICIAL;
+ }
+};
+
+/** \ingroup CholmodSupport_Module
+ * \class CholmodSupernodalLLT
+ * \brief A supernodal Cholesky (LLT) factorization and solver based on Cholmod
+ *
+ * This class allows to solve for A.X = B sparse linear problems via a supernodal LL^T Cholesky factorization
+ * using the Cholmod library.
+ * This supernodal variant performs best on dense enough problems, e.g., 3D FEM, or very high order 2D FEM.
+ * The sparse matrix A must be selfajoint and positive definite. The vectors or matrices
+ * X and B can be either dense or sparse.
+ *
+ * \tparam _MatrixType the type of the sparse matrix A, it must be a SparseMatrix<>
+ * \tparam _UpLo the triangular part that will be used for the computations. It can be Lower
+ * or Upper. Default is Lower.
+ *
+ * This class supports all kind of SparseMatrix<>: row or column major; upper, lower, or both; compressed or non compressed.
+ *
+ * \sa \ref TutorialSparseDirectSolvers
+ */
+template<typename _MatrixType, int _UpLo = Lower>
+class CholmodSupernodalLLT : public CholmodBase<_MatrixType, _UpLo, CholmodSupernodalLLT<_MatrixType, _UpLo> >
+{
+ typedef CholmodBase<_MatrixType, _UpLo, CholmodSupernodalLLT> Base;
+ using Base::m_cholmod;
+
+ public:
+
+ typedef _MatrixType MatrixType;
+
+ CholmodSupernodalLLT() : Base() { init(); }
+
+ CholmodSupernodalLLT(const MatrixType& matrix) : Base()
+ {
+ init();
+ compute(matrix);
+ }
+
+ ~CholmodSupernodalLLT() {}
+ protected:
+ void init()
+ {
+ m_cholmod.final_asis = 1;
+ m_cholmod.supernodal = CHOLMOD_SUPERNODAL;
+ }
+};
+
+/** \ingroup CholmodSupport_Module
+ * \class CholmodDecomposition
+ * \brief A general Cholesky factorization and solver based on Cholmod
+ *
+ * This class allows to solve for A.X = B sparse linear problems via a LL^T or LDL^T Cholesky factorization
+ * using the Cholmod library. The sparse matrix A must be selfajoint and positive definite. The vectors or matrices
+ * X and B can be either dense or sparse.
+ *
+ * This variant permits to change the underlying Cholesky method at runtime.
+ * On the other hand, it does not provide access to the result of the factorization.
+ * The default is to let Cholmod automatically choose between a simplicial and supernodal factorization.
+ *
+ * \tparam _MatrixType the type of the sparse matrix A, it must be a SparseMatrix<>
+ * \tparam _UpLo the triangular part that will be used for the computations. It can be Lower
+ * or Upper. Default is Lower.
+ *
+ * This class supports all kind of SparseMatrix<>: row or column major; upper, lower, or both; compressed or non compressed.
+ *
+ * \sa \ref TutorialSparseDirectSolvers
+ */
+template<typename _MatrixType, int _UpLo = Lower>
+class CholmodDecomposition : public CholmodBase<_MatrixType, _UpLo, CholmodDecomposition<_MatrixType, _UpLo> >
+{
+ typedef CholmodBase<_MatrixType, _UpLo, CholmodDecomposition> Base;
+ using Base::m_cholmod;
+
+ public:
+
+ typedef _MatrixType MatrixType;
+
+ CholmodDecomposition() : Base() { init(); }
+
+ CholmodDecomposition(const MatrixType& matrix) : Base()
+ {
+ init();
+ compute(matrix);
+ }
+
+ ~CholmodDecomposition() {}
+
+ void setMode(CholmodMode mode)
+ {
+ switch(mode)
+ {
+ case CholmodAuto:
+ m_cholmod.final_asis = 1;
+ m_cholmod.supernodal = CHOLMOD_AUTO;
+ break;
+ case CholmodSimplicialLLt:
+ m_cholmod.final_asis = 0;
+ m_cholmod.supernodal = CHOLMOD_SIMPLICIAL;
+ m_cholmod.final_ll = 1;
+ break;
+ case CholmodSupernodalLLt:
+ m_cholmod.final_asis = 1;
+ m_cholmod.supernodal = CHOLMOD_SUPERNODAL;
+ break;
+ case CholmodLDLt:
+ m_cholmod.final_asis = 1;
+ m_cholmod.supernodal = CHOLMOD_SIMPLICIAL;
+ break;
+ default:
+ break;
+ }
+ }
+ protected:
+ void init()
+ {
+ m_cholmod.final_asis = 1;
+ m_cholmod.supernodal = CHOLMOD_AUTO;
+ }
+};
+
+namespace internal {
+
+template<typename _MatrixType, int _UpLo, typename Derived, typename Rhs>
+struct solve_retval<CholmodBase<_MatrixType,_UpLo,Derived>, Rhs>
+ : solve_retval_base<CholmodBase<_MatrixType,_UpLo,Derived>, Rhs>
+{
+ typedef CholmodBase<_MatrixType,_UpLo,Derived> Dec;
+ EIGEN_MAKE_SOLVE_HELPERS(Dec,Rhs)
+
+ template<typename Dest> void evalTo(Dest& dst) const
+ {
+ dec()._solve(rhs(),dst);
+ }
+};
+
+template<typename _MatrixType, int _UpLo, typename Derived, typename Rhs>
+struct sparse_solve_retval<CholmodBase<_MatrixType,_UpLo,Derived>, Rhs>
+ : sparse_solve_retval_base<CholmodBase<_MatrixType,_UpLo,Derived>, Rhs>
+{
+ typedef CholmodBase<_MatrixType,_UpLo,Derived> Dec;
+ EIGEN_MAKE_SPARSE_SOLVE_HELPERS(Dec,Rhs)
+
+ template<typename Dest> void evalTo(Dest& dst) const
+ {
+ dec()._solve(rhs(),dst);
+ }
+};
+
+} // end namespace internal
+
+} // end namespace Eigen
+
+#endif // EIGEN_CHOLMODSUPPORT_H
diff --git a/Eigen/src/Core/Array.h b/Eigen/src/Core/Array.h
new file mode 100644
index 000000000..aaa389978
--- /dev/null
+++ b/Eigen/src/Core/Array.h
@@ -0,0 +1,308 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra.
+//
+// Copyright (C) 2009 Gael Guennebaud <gael.guennebaud@inria.fr>
+//
+// This Source Code Form is subject to the terms of the Mozilla
+// Public License v. 2.0. If a copy of the MPL was not distributed
+// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+#ifndef EIGEN_ARRAY_H
+#define EIGEN_ARRAY_H
+
+namespace Eigen {
+
+/** \class Array
+ * \ingroup Core_Module
+ *
+ * \brief General-purpose arrays with easy API for coefficient-wise operations
+ *
+ * The %Array class is very similar to the Matrix class. It provides
+ * general-purpose one- and two-dimensional arrays. The difference between the
+ * %Array and the %Matrix class is primarily in the API: the API for the
+ * %Array class provides easy access to coefficient-wise operations, while the
+ * API for the %Matrix class provides easy access to linear-algebra
+ * operations.
+ *
+ * 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.
+ *
+ * \sa \ref TutorialArrayClass, \ref TopicClassHierarchy
+ */
+namespace internal {
+template<typename _Scalar, int _Rows, int _Cols, int _Options, int _MaxRows, int _MaxCols>
+struct traits<Array<_Scalar, _Rows, _Cols, _Options, _MaxRows, _MaxCols> > : traits<Matrix<_Scalar, _Rows, _Cols, _Options, _MaxRows, _MaxCols> >
+{
+ typedef ArrayXpr XprKind;
+ typedef ArrayBase<Array<_Scalar, _Rows, _Cols, _Options, _MaxRows, _MaxCols> > XprBase;
+};
+}
+
+template<typename _Scalar, int _Rows, int _Cols, int _Options, int _MaxRows, int _MaxCols>
+class Array
+ : public PlainObjectBase<Array<_Scalar, _Rows, _Cols, _Options, _MaxRows, _MaxCols> >
+{
+ public:
+
+ typedef PlainObjectBase<Array> Base;
+ EIGEN_DENSE_PUBLIC_INTERFACE(Array)
+
+ enum { Options = _Options };
+ typedef typename Base::PlainObject PlainObject;
+
+ protected:
+ template <typename Derived, typename OtherDerived, bool IsVector>
+ friend struct internal::conservative_resize_like_impl;
+
+ using Base::m_storage;
+
+ public:
+
+ using Base::base;
+ using Base::coeff;
+ using Base::coeffRef;
+
+ /**
+ * 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=.
+ */
+ template<typename OtherDerived>
+ EIGEN_STRONG_INLINE Array& operator=(const EigenBase<OtherDerived> &other)
+ {
+ return Base::operator=(other);
+ }
+
+ /** 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),
+ * it will be initialized.
+ *
+ * Note that copying a row-vector into a vector (and conversely) is allowed.
+ * The resizing, if any, is then done in the appropriate way so that row-vectors
+ * remain row-vectors and vectors remain vectors.
+ */
+ template<typename OtherDerived>
+ EIGEN_STRONG_INLINE Array& operator=(const ArrayBase<OtherDerived>& other)
+ {
+ return Base::_set(other);
+ }
+
+ /** This is a special case of the templated operator=. Its purpose is to
+ * prevent a default operator= from hiding the templated operator=.
+ */
+ EIGEN_STRONG_INLINE Array& operator=(const Array& other)
+ {
+ return Base::_set(other);
+ }
+
+ /** Default constructor.
+ *
+ * For fixed-size matrices, does nothing.
+ *
+ * For dynamic-size matrices, creates an empty matrix of size 0. Does not allocate any array. Such a matrix
+ * is called a null matrix. This constructor is the unique way to create null matrices: resizing
+ * a matrix to 0 is not supported.
+ *
+ * \sa resize(Index,Index)
+ */
+ EIGEN_STRONG_INLINE explicit Array() : Base()
+ {
+ Base::_check_template_params();
+ EIGEN_INITIALIZE_BY_ZERO_IF_THAT_OPTION_IS_ENABLED
+ }
+
+#ifndef EIGEN_PARSED_BY_DOXYGEN
+ // FIXME is it still needed ??
+ /** \internal */
+ Array(internal::constructor_without_unaligned_array_assert)
+ : Base(internal::constructor_without_unaligned_array_assert())
+ {
+ Base::_check_template_params();
+ EIGEN_INITIALIZE_BY_ZERO_IF_THAT_OPTION_IS_ENABLED
+ }
+#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)
+ {
+ Base::_check_template_params();
+ EIGEN_STATIC_ASSERT_VECTOR_ONLY(Array)
+ eigen_assert(dim >= 0);
+ eigen_assert(SizeAtCompileTime == Dynamic || SizeAtCompileTime == dim);
+ EIGEN_INITIALIZE_BY_ZERO_IF_THAT_OPTION_IS_ENABLED
+ }
+
+ #ifndef EIGEN_PARSED_BY_DOXYGEN
+ template<typename T0, typename T1>
+ EIGEN_STRONG_INLINE Array(const T0& x, const T1& y)
+ {
+ Base::_check_template_params();
+ this->template _init2<T0,T1>(x, y);
+ }
+ #else
+ /** 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. */
+ Array(Index rows, Index cols);
+ /** constructs an initialized 2D vector with given coefficients */
+ Array(const Scalar& x, const Scalar& y);
+ #endif
+
+ /** constructs an initialized 3D vector with given coefficients */
+ EIGEN_STRONG_INLINE Array(const Scalar& x, const Scalar& y, const Scalar& z)
+ {
+ Base::_check_template_params();
+ EIGEN_STATIC_ASSERT_VECTOR_SPECIFIC_SIZE(Array, 3)
+ m_storage.data()[0] = x;
+ m_storage.data()[1] = y;
+ m_storage.data()[2] = z;
+ }
+ /** constructs an initialized 4D vector with given coefficients */
+ EIGEN_STRONG_INLINE Array(const Scalar& x, const Scalar& y, const Scalar& z, const Scalar& w)
+ {
+ Base::_check_template_params();
+ EIGEN_STATIC_ASSERT_VECTOR_SPECIFIC_SIZE(Array, 4)
+ m_storage.data()[0] = x;
+ m_storage.data()[1] = y;
+ m_storage.data()[2] = z;
+ m_storage.data()[3] = w;
+ }
+
+ explicit Array(const Scalar *data);
+
+ /** Constructor copying the value of the expression \a other */
+ template<typename OtherDerived>
+ EIGEN_STRONG_INLINE Array(const ArrayBase<OtherDerived>& other)
+ : Base(other.rows() * other.cols(), other.rows(), other.cols())
+ {
+ Base::_check_template_params();
+ Base::_set_noalias(other);
+ }
+ /** Copy constructor */
+ 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<typename OtherDerived>
+ EIGEN_STRONG_INLINE Array(const ReturnByValue<OtherDerived>& other)
+ {
+ Base::_check_template_params();
+ Base::resize(other.rows(), other.cols());
+ other.evalTo(*this);
+ }
+
+ /** \sa MatrixBase::operator=(const EigenBase<OtherDerived>&) */
+ template<typename OtherDerived>
+ EIGEN_STRONG_INLINE Array(const EigenBase<OtherDerived> &other)
+ : Base(other.derived().rows() * other.derived().cols(), other.derived().rows(), other.derived().cols())
+ {
+ Base::_check_template_params();
+ Base::resize(other.rows(), other.cols());
+ *this = other;
+ }
+
+ /** Override MatrixBase::swap() since for dynamic-sized matrices of same type it is enough to swap the
+ * data pointers.
+ */
+ template<typename OtherDerived>
+ void swap(ArrayBase<OtherDerived> const & other)
+ { this->_swap(other.derived()); }
+
+ inline Index innerStride() const { return 1; }
+ inline Index outerStride() const { return this->innerSize(); }
+
+ #ifdef EIGEN_ARRAY_PLUGIN
+ #include EIGEN_ARRAY_PLUGIN
+ #endif
+
+ private:
+
+ template<typename MatrixType, typename OtherDerived, bool SwapPointers>
+ friend struct internal::matrix_swap_impl;
+};
+
+/** \defgroup arraytypedefs Global array typedefs
+ * \ingroup Core_Module
+ *
+ * Eigen defines several typedef shortcuts for most common 1D and 2D array types.
+ *
+ * The general patterns are the following:
+ *
+ * \c ArrayRowsColsType where \c Rows and \c Cols can be \c 2,\c 3,\c 4 for fixed size square matrices or \c X for dynamic size,
+ * and where \c Type can be \c i for integer, \c f for float, \c d for double, \c cf for complex float, \c cd
+ * for complex double.
+ *
+ * For example, \c Array33d is a fixed-size 3x3 array type of doubles, and \c ArrayXXf is a dynamic-size matrix of floats.
+ *
+ * There are also \c ArraySizeType which are self-explanatory. For example, \c Array4cf is
+ * a fixed-size 1D array of 4 complex floats.
+ *
+ * \sa class Array
+ */
+
+#define EIGEN_MAKE_ARRAY_TYPEDEFS(Type, TypeSuffix, Size, SizeSuffix) \
+/** \ingroup arraytypedefs */ \
+typedef Array<Type, Size, Size> Array##SizeSuffix##SizeSuffix##TypeSuffix; \
+/** \ingroup arraytypedefs */ \
+typedef Array<Type, Size, 1> Array##SizeSuffix##TypeSuffix;
+
+#define EIGEN_MAKE_ARRAY_FIXED_TYPEDEFS(Type, TypeSuffix, Size) \
+/** \ingroup arraytypedefs */ \
+typedef Array<Type, Size, Dynamic> Array##Size##X##TypeSuffix; \
+/** \ingroup arraytypedefs */ \
+typedef Array<Type, Dynamic, Size> Array##X##Size##TypeSuffix;
+
+#define EIGEN_MAKE_ARRAY_TYPEDEFS_ALL_SIZES(Type, TypeSuffix) \
+EIGEN_MAKE_ARRAY_TYPEDEFS(Type, TypeSuffix, 2, 2) \
+EIGEN_MAKE_ARRAY_TYPEDEFS(Type, TypeSuffix, 3, 3) \
+EIGEN_MAKE_ARRAY_TYPEDEFS(Type, TypeSuffix, 4, 4) \
+EIGEN_MAKE_ARRAY_TYPEDEFS(Type, TypeSuffix, Dynamic, X) \
+EIGEN_MAKE_ARRAY_FIXED_TYPEDEFS(Type, TypeSuffix, 2) \
+EIGEN_MAKE_ARRAY_FIXED_TYPEDEFS(Type, TypeSuffix, 3) \
+EIGEN_MAKE_ARRAY_FIXED_TYPEDEFS(Type, TypeSuffix, 4)
+
+EIGEN_MAKE_ARRAY_TYPEDEFS_ALL_SIZES(int, i)
+EIGEN_MAKE_ARRAY_TYPEDEFS_ALL_SIZES(float, f)
+EIGEN_MAKE_ARRAY_TYPEDEFS_ALL_SIZES(double, d)
+EIGEN_MAKE_ARRAY_TYPEDEFS_ALL_SIZES(std::complex<float>, cf)
+EIGEN_MAKE_ARRAY_TYPEDEFS_ALL_SIZES(std::complex<double>, cd)
+
+#undef EIGEN_MAKE_ARRAY_TYPEDEFS_ALL_SIZES
+#undef EIGEN_MAKE_ARRAY_TYPEDEFS
+
+#undef EIGEN_MAKE_ARRAY_TYPEDEFS_LARGE
+
+#define EIGEN_USING_ARRAY_TYPEDEFS_FOR_TYPE_AND_SIZE(TypeSuffix, SizeSuffix) \
+using Eigen::Matrix##SizeSuffix##TypeSuffix; \
+using Eigen::Vector##SizeSuffix##TypeSuffix; \
+using Eigen::RowVector##SizeSuffix##TypeSuffix;
+
+#define EIGEN_USING_ARRAY_TYPEDEFS_FOR_TYPE(TypeSuffix) \
+EIGEN_USING_ARRAY_TYPEDEFS_FOR_TYPE_AND_SIZE(TypeSuffix, 2) \
+EIGEN_USING_ARRAY_TYPEDEFS_FOR_TYPE_AND_SIZE(TypeSuffix, 3) \
+EIGEN_USING_ARRAY_TYPEDEFS_FOR_TYPE_AND_SIZE(TypeSuffix, 4) \
+EIGEN_USING_ARRAY_TYPEDEFS_FOR_TYPE_AND_SIZE(TypeSuffix, X) \
+
+#define EIGEN_USING_ARRAY_TYPEDEFS \
+EIGEN_USING_ARRAY_TYPEDEFS_FOR_TYPE(i) \
+EIGEN_USING_ARRAY_TYPEDEFS_FOR_TYPE(f) \
+EIGEN_USING_ARRAY_TYPEDEFS_FOR_TYPE(d) \
+EIGEN_USING_ARRAY_TYPEDEFS_FOR_TYPE(cf) \
+EIGEN_USING_ARRAY_TYPEDEFS_FOR_TYPE(cd)
+
+} // end namespace Eigen
+
+#endif // EIGEN_ARRAY_H
diff --git a/Eigen/src/Core/ArrayBase.h b/Eigen/src/Core/ArrayBase.h
new file mode 100644
index 000000000..004b117c9
--- /dev/null
+++ b/Eigen/src/Core/ArrayBase.h
@@ -0,0 +1,228 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra.
+//
+// Copyright (C) 2009 Gael Guennebaud <gael.guennebaud@inria.fr>
+//
+// This Source Code Form is subject to the terms of the Mozilla
+// Public License v. 2.0. If a copy of the MPL was not distributed
+// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+#ifndef EIGEN_ARRAYBASE_H
+#define EIGEN_ARRAYBASE_H
+
+namespace Eigen {
+
+template<typename ExpressionType> class MatrixWrapper;
+
+/** \class ArrayBase
+ * \ingroup Core_Module
+ *
+ * \brief Base class for all 1D and 2D array, and related expressions
+ *
+ * An array is similar to a dense vector or matrix. While matrices are mathematical
+ * objects with well defined linear algebra operators, an array is just a collection
+ * of scalar values arranged in a one or two dimensionnal fashion. As the main consequence,
+ * all operations applied to an array are performed coefficient wise. Furthermore,
+ * arrays support scalar math functions of the c++ standard library (e.g., std::sin(x)), and convenient
+ * constructors allowing to easily write generic code working for both scalar values
+ * and arrays.
+ *
+ * This class is the base that is inherited by all array expression types.
+ *
+ * \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.
+ *
+ * \sa class MatrixBase, \ref TopicClassHierarchy
+ */
+template<typename Derived> class ArrayBase
+ : public DenseBase<Derived>
+{
+ public:
+#ifndef EIGEN_PARSED_BY_DOXYGEN
+ /** The base class for a given storage type. */
+ typedef ArrayBase StorageBaseType;
+
+ typedef ArrayBase Eigen_BaseClassForSpecializationOfGlobalMathFuncImpl;
+
+ using internal::special_scalar_op_base<Derived,typename internal::traits<Derived>::Scalar,
+ typename NumTraits<typename internal::traits<Derived>::Scalar>::Real>::operator*;
+
+ typedef typename internal::traits<Derived>::StorageKind StorageKind;
+ typedef typename internal::traits<Derived>::Index Index;
+ typedef typename internal::traits<Derived>::Scalar Scalar;
+ typedef typename internal::packet_traits<Scalar>::type PacketScalar;
+ typedef typename NumTraits<Scalar>::Real RealScalar;
+
+ typedef DenseBase<Derived> Base;
+ using Base::RowsAtCompileTime;
+ using Base::ColsAtCompileTime;
+ using Base::SizeAtCompileTime;
+ using Base::MaxRowsAtCompileTime;
+ using Base::MaxColsAtCompileTime;
+ using Base::MaxSizeAtCompileTime;
+ using Base::IsVectorAtCompileTime;
+ using Base::Flags;
+ using Base::CoeffReadCost;
+
+ using Base::derived;
+ using Base::const_cast_derived;
+ using Base::rows;
+ using Base::cols;
+ using Base::size;
+ using Base::coeff;
+ using Base::coeffRef;
+ using Base::lazyAssign;
+ using Base::operator=;
+ using Base::operator+=;
+ using Base::operator-=;
+ using Base::operator*=;
+ using Base::operator/=;
+
+ typedef typename Base::CoeffReturnType CoeffReturnType;
+
+#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<typename internal::traits<Derived>::Scalar,
+ internal::traits<Derived>::RowsAtCompileTime,
+ internal::traits<Derived>::ColsAtCompileTime,
+ AutoAlign | (internal::traits<Derived>::Flags&RowMajorBit ? RowMajor : ColMajor),
+ internal::traits<Derived>::MaxRowsAtCompileTime,
+ internal::traits<Derived>::MaxColsAtCompileTime
+ > PlainObject;
+
+
+ /** \internal Represents a matrix with all coefficients equal to one another*/
+ typedef CwiseNullaryOp<internal::scalar_constant_op<Scalar>,Derived> ConstantReturnType;
+#endif // not EIGEN_PARSED_BY_DOXYGEN
+
+#define EIGEN_CURRENT_STORAGE_BASE_CLASS Eigen::ArrayBase
+# include "../plugins/CommonCwiseUnaryOps.h"
+# include "../plugins/MatrixCwiseUnaryOps.h"
+# include "../plugins/ArrayCwiseUnaryOps.h"
+# include "../plugins/CommonCwiseBinaryOps.h"
+# include "../plugins/MatrixCwiseBinaryOps.h"
+# include "../plugins/ArrayCwiseBinaryOps.h"
+# ifdef EIGEN_ARRAYBASE_PLUGIN
+# include EIGEN_ARRAYBASE_PLUGIN
+# endif
+#undef EIGEN_CURRENT_STORAGE_BASE_CLASS
+
+ /** Special case of the template operator=, in order to prevent the compiler
+ * from generating a default operator= (issue hit with g++ 4.1)
+ */
+ Derived& operator=(const ArrayBase& other)
+ {
+ return internal::assign_selector<Derived,Derived>::run(derived(), other.derived());
+ }
+
+ Derived& operator+=(const Scalar& scalar)
+ { return *this = derived() + scalar; }
+ Derived& operator-=(const Scalar& scalar)
+ { return *this = derived() - scalar; }
+
+ template<typename OtherDerived>
+ Derived& operator+=(const ArrayBase<OtherDerived>& other);
+ template<typename OtherDerived>
+ Derived& operator-=(const ArrayBase<OtherDerived>& other);
+
+ template<typename OtherDerived>
+ Derived& operator*=(const ArrayBase<OtherDerived>& other);
+
+ template<typename OtherDerived>
+ Derived& operator/=(const ArrayBase<OtherDerived>& other);
+
+ public:
+ ArrayBase<Derived>& array() { return *this; }
+ const ArrayBase<Derived>& array() const { return *this; }
+
+ /** \returns an \link MatrixBase Matrix \endlink expression of this array
+ * \sa MatrixBase::array() */
+ MatrixWrapper<Derived> matrix() { return derived(); }
+ const MatrixWrapper<const Derived> matrix() const { return derived(); }
+
+// template<typename Dest>
+// inline void evalTo(Dest& dst) const { dst = matrix(); }
+
+ protected:
+ ArrayBase() : Base() {}
+
+ private:
+ explicit ArrayBase(Index);
+ ArrayBase(Index,Index);
+ template<typename OtherDerived> explicit ArrayBase(const ArrayBase<OtherDerived>&);
+ protected:
+ // mixing arrays and matrices is not legal
+ template<typename OtherDerived> Derived& operator+=(const MatrixBase<OtherDerived>& )
+ {EIGEN_STATIC_ASSERT(std::ptrdiff_t(sizeof(typename OtherDerived::Scalar))==-1,YOU_CANNOT_MIX_ARRAYS_AND_MATRICES); return *this;}
+ // mixing arrays and matrices is not legal
+ template<typename OtherDerived> Derived& operator-=(const MatrixBase<OtherDerived>& )
+ {EIGEN_STATIC_ASSERT(std::ptrdiff_t(sizeof(typename OtherDerived::Scalar))==-1,YOU_CANNOT_MIX_ARRAYS_AND_MATRICES); return *this;}
+};
+
+/** replaces \c *this by \c *this - \a other.
+ *
+ * \returns a reference to \c *this
+ */
+template<typename Derived>
+template<typename OtherDerived>
+EIGEN_STRONG_INLINE Derived &
+ArrayBase<Derived>::operator-=(const ArrayBase<OtherDerived> &other)
+{
+ SelfCwiseBinaryOp<internal::scalar_difference_op<Scalar>, Derived, OtherDerived> tmp(derived());
+ tmp = other.derived();
+ return derived();
+}
+
+/** replaces \c *this by \c *this + \a other.
+ *
+ * \returns a reference to \c *this
+ */
+template<typename Derived>
+template<typename OtherDerived>
+EIGEN_STRONG_INLINE Derived &
+ArrayBase<Derived>::operator+=(const ArrayBase<OtherDerived>& other)
+{
+ SelfCwiseBinaryOp<internal::scalar_sum_op<Scalar>, Derived, OtherDerived> tmp(derived());
+ tmp = other.derived();
+ return derived();
+}
+
+/** replaces \c *this by \c *this * \a other coefficient wise.
+ *
+ * \returns a reference to \c *this
+ */
+template<typename Derived>
+template<typename OtherDerived>
+EIGEN_STRONG_INLINE Derived &
+ArrayBase<Derived>::operator*=(const ArrayBase<OtherDerived>& other)
+{
+ SelfCwiseBinaryOp<internal::scalar_product_op<Scalar>, Derived, OtherDerived> tmp(derived());
+ tmp = other.derived();
+ return derived();
+}
+
+/** replaces \c *this by \c *this / \a other coefficient wise.
+ *
+ * \returns a reference to \c *this
+ */
+template<typename Derived>
+template<typename OtherDerived>
+EIGEN_STRONG_INLINE Derived &
+ArrayBase<Derived>::operator/=(const ArrayBase<OtherDerived>& other)
+{
+ SelfCwiseBinaryOp<internal::scalar_quotient_op<Scalar>, Derived, OtherDerived> tmp(derived());
+ tmp = other.derived();
+ return derived();
+}
+
+} // end namespace Eigen
+
+#endif // EIGEN_ARRAYBASE_H
diff --git a/Eigen/src/Core/ArrayWrapper.h b/Eigen/src/Core/ArrayWrapper.h
new file mode 100644
index 000000000..87af7fda9
--- /dev/null
+++ b/Eigen/src/Core/ArrayWrapper.h
@@ -0,0 +1,240 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra.
+//
+// Copyright (C) 2009-2010 Gael Guennebaud <gael.guennebaud@inria.fr>
+//
+// This Source Code Form is subject to the terms of the Mozilla
+// Public License v. 2.0. If a copy of the MPL was not distributed
+// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+#ifndef EIGEN_ARRAYWRAPPER_H
+#define EIGEN_ARRAYWRAPPER_H
+
+namespace Eigen {
+
+/** \class ArrayWrapper
+ * \ingroup Core_Module
+ *
+ * \brief Expression of a mathematical vector or matrix as an array object
+ *
+ * This class is the return type of MatrixBase::array(), and most of the time
+ * this is the only way it is use.
+ *
+ * \sa MatrixBase::array(), class MatrixWrapper
+ */
+
+namespace internal {
+template<typename ExpressionType>
+struct traits<ArrayWrapper<ExpressionType> >
+ : public traits<typename remove_all<typename ExpressionType::Nested>::type >
+{
+ typedef ArrayXpr XprKind;
+};
+}
+
+template<typename ExpressionType>
+class ArrayWrapper : public ArrayBase<ArrayWrapper<ExpressionType> >
+{
+ public:
+ typedef ArrayBase<ArrayWrapper> Base;
+ EIGEN_DENSE_PUBLIC_INTERFACE(ArrayWrapper)
+ EIGEN_INHERIT_ASSIGNMENT_OPERATORS(ArrayWrapper)
+
+ typedef typename internal::conditional<
+ internal::is_lvalue<ExpressionType>::value,
+ Scalar,
+ const Scalar
+ >::type ScalarWithConstIfNotLvalue;
+
+ typedef typename internal::nested<ExpressionType>::type NestedExpressionType;
+
+ inline ArrayWrapper(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(); }
+
+ inline ScalarWithConstIfNotLvalue* data() { return m_expression.data(); }
+ inline const Scalar* data() const { return m_expression.data(); }
+
+ inline CoeffReturnType coeff(Index row, Index col) const
+ {
+ return m_expression.coeff(row, col);
+ }
+
+ inline Scalar& coeffRef(Index row, Index col)
+ {
+ return m_expression.const_cast_derived().coeffRef(row, col);
+ }
+
+ inline const Scalar& coeffRef(Index row, Index col) const
+ {
+ return m_expression.const_cast_derived().coeffRef(row, col);
+ }
+
+ inline CoeffReturnType coeff(Index index) const
+ {
+ return m_expression.coeff(index);
+ }
+
+ inline Scalar& coeffRef(Index index)
+ {
+ return m_expression.const_cast_derived().coeffRef(index);
+ }
+
+ inline const Scalar& coeffRef(Index index) const
+ {
+ return m_expression.const_cast_derived().coeffRef(index);
+ }
+
+ template<int LoadMode>
+ inline const PacketScalar packet(Index row, Index col) const
+ {
+ return m_expression.template packet<LoadMode>(row, col);
+ }
+
+ template<int LoadMode>
+ inline void writePacket(Index row, Index col, const PacketScalar& x)
+ {
+ m_expression.const_cast_derived().template writePacket<LoadMode>(row, col, x);
+ }
+
+ template<int LoadMode>
+ inline const PacketScalar packet(Index index) const
+ {
+ return m_expression.template packet<LoadMode>(index);
+ }
+
+ template<int LoadMode>
+ inline void writePacket(Index index, const PacketScalar& x)
+ {
+ m_expression.const_cast_derived().template writePacket<LoadMode>(index, x);
+ }
+
+ template<typename Dest>
+ inline void evalTo(Dest& dst) const { dst = m_expression; }
+
+ const typename internal::remove_all<NestedExpressionType>::type&
+ nestedExpression() const
+ {
+ return m_expression;
+ }
+
+ protected:
+ NestedExpressionType m_expression;
+};
+
+/** \class MatrixWrapper
+ * \ingroup Core_Module
+ *
+ * \brief Expression of an array as a mathematical vector or matrix
+ *
+ * This class is the return type of ArrayBase::matrix(), and most of the time
+ * this is the only way it is use.
+ *
+ * \sa MatrixBase::matrix(), class ArrayWrapper
+ */
+
+namespace internal {
+template<typename ExpressionType>
+struct traits<MatrixWrapper<ExpressionType> >
+ : public traits<typename remove_all<typename ExpressionType::Nested>::type >
+{
+ typedef MatrixXpr XprKind;
+};
+}
+
+template<typename ExpressionType>
+class MatrixWrapper : public MatrixBase<MatrixWrapper<ExpressionType> >
+{
+ public:
+ typedef MatrixBase<MatrixWrapper<ExpressionType> > Base;
+ EIGEN_DENSE_PUBLIC_INTERFACE(MatrixWrapper)
+ EIGEN_INHERIT_ASSIGNMENT_OPERATORS(MatrixWrapper)
+
+ typedef typename internal::conditional<
+ internal::is_lvalue<ExpressionType>::value,
+ Scalar,
+ const Scalar
+ >::type ScalarWithConstIfNotLvalue;
+
+ typedef typename internal::nested<ExpressionType>::type NestedExpressionType;
+
+ inline MatrixWrapper(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(); }
+
+ inline ScalarWithConstIfNotLvalue* data() { return m_expression.data(); }
+ inline const Scalar* data() const { return m_expression.data(); }
+
+ inline CoeffReturnType coeff(Index row, Index col) const
+ {
+ return m_expression.coeff(row, col);
+ }
+
+ inline Scalar& coeffRef(Index row, Index col)
+ {
+ return m_expression.const_cast_derived().coeffRef(row, col);
+ }
+
+ inline const Scalar& coeffRef(Index row, Index col) const
+ {
+ return m_expression.derived().coeffRef(row, col);
+ }
+
+ inline CoeffReturnType coeff(Index index) const
+ {
+ return m_expression.coeff(index);
+ }
+
+ inline Scalar& coeffRef(Index index)
+ {
+ return m_expression.const_cast_derived().coeffRef(index);
+ }
+
+ inline const Scalar& coeffRef(Index index) const
+ {
+ return m_expression.const_cast_derived().coeffRef(index);
+ }
+
+ template<int LoadMode>
+ inline const PacketScalar packet(Index row, Index col) const
+ {
+ return m_expression.template packet<LoadMode>(row, col);
+ }
+
+ template<int LoadMode>
+ inline void writePacket(Index row, Index col, const PacketScalar& x)
+ {
+ m_expression.const_cast_derived().template writePacket<LoadMode>(row, col, x);
+ }
+
+ template<int LoadMode>
+ inline const PacketScalar packet(Index index) const
+ {
+ return m_expression.template packet<LoadMode>(index);
+ }
+
+ template<int LoadMode>
+ inline void writePacket(Index index, const PacketScalar& x)
+ {
+ m_expression.const_cast_derived().template writePacket<LoadMode>(index, x);
+ }
+
+ const typename internal::remove_all<NestedExpressionType>::type&
+ nestedExpression() const
+ {
+ return m_expression;
+ }
+
+ protected:
+ NestedExpressionType m_expression;
+};
+
+} // end namespace Eigen
+
+#endif // EIGEN_ARRAYWRAPPER_H
diff --git a/Eigen/src/Core/Assign.h b/Eigen/src/Core/Assign.h
new file mode 100644
index 000000000..cd29a88f0
--- /dev/null
+++ b/Eigen/src/Core/Assign.h
@@ -0,0 +1,583 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra.
+//
+// Copyright (C) 2007 Michael Olbrich <michael.olbrich@gmx.net>
+// Copyright (C) 2006-2010 Benoit Jacob <jacob.benoit.1@gmail.com>
+// Copyright (C) 2008 Gael Guennebaud <gael.guennebaud@inria.fr>
+//
+// This Source Code Form is subject to the terms of the Mozilla
+// Public License v. 2.0. If 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 <typename Derived, typename OtherDerived>
+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<typename Derived::Scalar>::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<typename Derived1, typename Derived2, int Index, int Stop>
+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<Derived1, Derived2, Index+1, Stop>::run(dst, src);
+ }
+};
+
+template<typename Derived1, typename Derived2, int Stop>
+struct assign_DefaultTraversal_CompleteUnrolling<Derived1, Derived2, Stop, Stop>
+{
+ static EIGEN_STRONG_INLINE void run(Derived1 &, const Derived2 &) {}
+};
+
+template<typename Derived1, typename Derived2, int Index, int Stop>
+struct assign_DefaultTraversal_InnerUnrolling
+{
+ static EIGEN_STRONG_INLINE void run(Derived1 &dst, const Derived2 &src, int outer)
+ {
+ dst.copyCoeffByOuterInner(outer, Index, src);
+ assign_DefaultTraversal_InnerUnrolling<Derived1, Derived2, Index+1, Stop>::run(dst, src, outer);
+ }
+};
+
+template<typename Derived1, typename Derived2, int Stop>
+struct assign_DefaultTraversal_InnerUnrolling<Derived1, Derived2, Stop, Stop>
+{
+ static EIGEN_STRONG_INLINE void run(Derived1 &, const Derived2 &, int) {}
+};
+
+/***********************
+*** Linear traversal ***
+***********************/
+
+template<typename Derived1, typename Derived2, int Index, int Stop>
+struct assign_LinearTraversal_CompleteUnrolling
+{
+ static EIGEN_STRONG_INLINE void run(Derived1 &dst, const Derived2 &src)
+ {
+ dst.copyCoeff(Index, src);
+ assign_LinearTraversal_CompleteUnrolling<Derived1, Derived2, Index+1, Stop>::run(dst, src);
+ }
+};
+
+template<typename Derived1, typename Derived2, int Stop>
+struct assign_LinearTraversal_CompleteUnrolling<Derived1, Derived2, Stop, Stop>
+{
+ static EIGEN_STRONG_INLINE void run(Derived1 &, const Derived2 &) {}
+};
+
+/**************************
+*** Inner vectorization ***
+**************************/
+
+template<typename Derived1, typename Derived2, int Index, int Stop>
+struct assign_innervec_CompleteUnrolling
+{
+ enum {
+ outer = Index / Derived1::InnerSizeAtCompileTime,
+ inner = Index % Derived1::InnerSizeAtCompileTime,
+ JointAlignment = assign_traits<Derived1,Derived2>::JointAlignment
+ };
+
+ static EIGEN_STRONG_INLINE void run(Derived1 &dst, const Derived2 &src)
+ {
+ dst.template copyPacketByOuterInner<Derived2, Aligned, JointAlignment>(outer, inner, src);
+ assign_innervec_CompleteUnrolling<Derived1, Derived2,
+ Index+packet_traits<typename Derived1::Scalar>::size, Stop>::run(dst, src);
+ }
+};
+
+template<typename Derived1, typename Derived2, int Stop>
+struct assign_innervec_CompleteUnrolling<Derived1, Derived2, Stop, Stop>
+{
+ static EIGEN_STRONG_INLINE void run(Derived1 &, const Derived2 &) {}
+};
+
+template<typename Derived1, typename Derived2, int Index, int Stop>
+struct assign_innervec_InnerUnrolling
+{
+ static EIGEN_STRONG_INLINE void run(Derived1 &dst, const Derived2 &src, int outer)
+ {
+ dst.template copyPacketByOuterInner<Derived2, Aligned, Aligned>(outer, Index, src);
+ assign_innervec_InnerUnrolling<Derived1, Derived2,
+ Index+packet_traits<typename Derived1::Scalar>::size, Stop>::run(dst, src, outer);
+ }
+};
+
+template<typename Derived1, typename Derived2, int Stop>
+struct assign_innervec_InnerUnrolling<Derived1, Derived2, Stop, Stop>
+{
+ static EIGEN_STRONG_INLINE void run(Derived1 &, const Derived2 &, int) {}
+};
+
+/***************************************************************************
+* Part 3 : implementation of all cases
+***************************************************************************/
+
+template<typename Derived1, typename Derived2,
+ int Traversal = assign_traits<Derived1, Derived2>::Traversal,
+ int Unrolling = assign_traits<Derived1, Derived2>::Unrolling,
+ int Version = Specialized>
+struct assign_impl;
+
+/************************
+*** Default traversal ***
+************************/
+
+template<typename Derived1, typename Derived2, int Unrolling, int Version>
+struct assign_impl<Derived1, Derived2, InvalidTraversal, Unrolling, Version>
+{
+ static inline void run(Derived1 &, const Derived2 &) { }
+};
+
+template<typename Derived1, typename Derived2, int Version>
+struct assign_impl<Derived1, Derived2, DefaultTraversal, NoUnrolling, Version>
+{
+ 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<typename Derived1, typename Derived2, int Version>
+struct assign_impl<Derived1, Derived2, DefaultTraversal, CompleteUnrolling, Version>
+{
+ static EIGEN_STRONG_INLINE void run(Derived1 &dst, const Derived2 &src)
+ {
+ assign_DefaultTraversal_CompleteUnrolling<Derived1, Derived2, 0, Derived1::SizeAtCompileTime>
+ ::run(dst, src);
+ }
+};
+
+template<typename Derived1, typename Derived2, int Version>
+struct assign_impl<Derived1, Derived2, DefaultTraversal, InnerUnrolling, Version>
+{
+ 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<Derived1, Derived2, 0, Derived1::InnerSizeAtCompileTime>
+ ::run(dst, src, outer);
+ }
+};
+
+/***********************
+*** Linear traversal ***
+***********************/
+
+template<typename Derived1, typename Derived2, int Version>
+struct assign_impl<Derived1, Derived2, LinearTraversal, NoUnrolling, Version>
+{
+ 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<typename Derived1, typename Derived2, int Version>
+struct assign_impl<Derived1, Derived2, LinearTraversal, CompleteUnrolling, Version>
+{
+ static EIGEN_STRONG_INLINE void run(Derived1 &dst, const Derived2 &src)
+ {
+ assign_LinearTraversal_CompleteUnrolling<Derived1, Derived2, 0, Derived1::SizeAtCompileTime>
+ ::run(dst, src);
+ }
+};
+
+/**************************
+*** Inner vectorization ***
+**************************/
+
+template<typename Derived1, typename Derived2, int Version>
+struct assign_impl<Derived1, Derived2, InnerVectorizedTraversal, NoUnrolling, Version>
+{
+ 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<typename Derived1::Scalar>::size;
+ for(Index outer = 0; outer < outerSize; ++outer)
+ for(Index inner = 0; inner < innerSize; inner+=packetSize)
+ dst.template copyPacketByOuterInner<Derived2, Aligned, Aligned>(outer, inner, src);
+ }
+};
+
+template<typename Derived1, typename Derived2, int Version>
+struct assign_impl<Derived1, Derived2, InnerVectorizedTraversal, CompleteUnrolling, Version>
+{
+ static EIGEN_STRONG_INLINE void run(Derived1 &dst, const Derived2 &src)
+ {
+ assign_innervec_CompleteUnrolling<Derived1, Derived2, 0, Derived1::SizeAtCompileTime>
+ ::run(dst, src);
+ }
+};
+
+template<typename Derived1, typename Derived2, int Version>
+struct assign_impl<Derived1, Derived2, InnerVectorizedTraversal, InnerUnrolling, Version>
+{
+ 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<Derived1, Derived2, 0, Derived1::InnerSizeAtCompileTime>
+ ::run(dst, src, outer);
+ }
+};
+
+/***************************
+*** Linear vectorization ***
+***************************/
+
+template <bool IsAligned = false>
+struct unaligned_assign_impl
+{
+ template <typename Derived, typename OtherDerived>
+ static EIGEN_STRONG_INLINE void run(const Derived&, OtherDerived&, typename Derived::Index, typename Derived::Index) {}
+};
+
+template <>
+struct unaligned_assign_impl<false>
+{
+ // MSVC must not inline this functions. If it does, it fails to optimize the
+ // packet access path.
+#ifdef _MSC_VER
+ template <typename Derived, typename OtherDerived>
+ static EIGEN_DONT_INLINE void run(const Derived& src, OtherDerived& dst, typename Derived::Index start, typename Derived::Index end)
+#else
+ template <typename Derived, typename OtherDerived>
+ 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<typename Derived1, typename Derived2, int Version>
+struct assign_impl<Derived1, Derived2, LinearVectorizedTraversal, NoUnrolling, Version>
+{
+ typedef typename Derived1::Index Index;
+ static EIGEN_STRONG_INLINE void run(Derived1 &dst, const Derived2 &src)
+ {
+ const Index size = dst.size();
+ typedef packet_traits<typename Derived1::Scalar> PacketTraits;
+ enum {
+ packetSize = PacketTraits::size,
+ dstAlignment = PacketTraits::AlignedOnScalar ? Aligned : int(assign_traits<Derived1,Derived2>::DstIsAligned) ,
+ srcAlignment = assign_traits<Derived1,Derived2>::JointAlignment
+ };
+ const Index alignedStart = assign_traits<Derived1,Derived2>::DstIsAligned ? 0
+ : internal::first_aligned(&dst.coeffRef(0), size);
+ const Index alignedEnd = alignedStart + ((size-alignedStart)/packetSize)*packetSize;
+
+ unaligned_assign_impl<assign_traits<Derived1,Derived2>::DstIsAligned!=0>::run(src,dst,0,alignedStart);
+
+ for(Index index = alignedStart; index < alignedEnd; index += packetSize)
+ {
+ dst.template copyPacket<Derived2, dstAlignment, srcAlignment>(index, src);
+ }
+
+ unaligned_assign_impl<>::run(src,dst,alignedEnd,size);
+ }
+};
+
+template<typename Derived1, typename Derived2, int Version>
+struct assign_impl<Derived1, Derived2, LinearVectorizedTraversal, CompleteUnrolling, Version>
+{
+ typedef typename Derived1::Index Index;
+ static EIGEN_STRONG_INLINE void run(Derived1 &dst, const Derived2 &src)
+ {
+ enum { size = Derived1::SizeAtCompileTime,
+ packetSize = packet_traits<typename Derived1::Scalar>::size,
+ alignedSize = (size/packetSize)*packetSize };
+
+ assign_innervec_CompleteUnrolling<Derived1, Derived2, 0, alignedSize>::run(dst, src);
+ assign_DefaultTraversal_CompleteUnrolling<Derived1, Derived2, alignedSize, size>::run(dst, src);
+ }
+};
+
+/**************************
+*** Slice vectorization ***
+***************************/
+
+template<typename Derived1, typename Derived2, int Version>
+struct assign_impl<Derived1, Derived2, SliceVectorizedTraversal, NoUnrolling, Version>
+{
+ typedef typename Derived1::Index Index;
+ static inline void run(Derived1 &dst, const Derived2 &src)
+ {
+ typedef packet_traits<typename Derived1::Scalar> PacketTraits;
+ enum {
+ packetSize = PacketTraits::size,
+ alignable = PacketTraits::AlignedOnScalar,
+ dstAlignment = alignable ? Aligned : int(assign_traits<Derived1,Derived2>::DstIsAligned) ,
+ srcAlignment = assign_traits<Derived1,Derived2>::JointAlignment
+ };
+ 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) || assign_traits<Derived1,Derived2>::DstIsAligned) ? 0
+ : internal::first_aligned(&dst.coeffRef(0,0), 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<alignedStart ; ++inner)
+ dst.copyCoeffByOuterInner(outer, inner, src);
+
+ // do the vectorizable part of the assignment
+ for(Index inner = alignedStart; inner<alignedEnd; inner+=packetSize)
+ dst.template copyPacketByOuterInner<Derived2, dstAlignment, Unaligned>(outer, inner, src);
+
+ // do the non-vectorizable part of the assignment
+ for(Index inner = alignedEnd; inner<innerSize ; ++inner)
+ dst.copyCoeffByOuterInner(outer, inner, src);
+
+ alignedStart = std::min<Index>((alignedStart+alignedStep)%packetSize, innerSize);
+ }
+ }
+};
+
+} // end namespace internal
+
+/***************************************************************************
+* Part 4 : implementation of DenseBase methods
+***************************************************************************/
+
+template<typename Derived>
+template<typename OtherDerived>
+EIGEN_STRONG_INLINE Derived& DenseBase<Derived>
+ ::lazyAssign(const DenseBase<OtherDerived>& other)
+{
+ enum{
+ SameType = internal::is_same<typename Derived::Scalar,typename OtherDerived::Scalar>::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<Derived, OtherDerived>::debug();
+#endif
+ eigen_assert(rows() == other.rows() && cols() == other.cols());
+ internal::assign_impl<Derived, OtherDerived, int(SameType) ? int(internal::assign_traits<Derived, OtherDerived>::Traversal)
+ : int(InvalidTraversal)>::run(derived(),other.derived());
+#ifndef EIGEN_NO_DEBUG
+ checkTransposeAliasing(other.derived());
+#endif
+ return derived();
+}
+
+namespace internal {
+
+template<typename Derived, typename OtherDerived,
+ bool EvalBeforeAssigning = (int(OtherDerived::Flags) & EvalBeforeAssigningBit) != 0,
+ bool NeedToTranspose = Derived::IsVectorAtCompileTime
+ && OtherDerived::IsVectorAtCompileTime
+ && ((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<typename Derived, typename OtherDerived>
+struct assign_selector<Derived,OtherDerived,false,false> {
+ static EIGEN_STRONG_INLINE Derived& run(Derived& dst, const OtherDerived& other) { return dst.lazyAssign(other.derived()); }
+};
+template<typename Derived, typename OtherDerived>
+struct assign_selector<Derived,OtherDerived,true,false> {
+ static EIGEN_STRONG_INLINE Derived& run(Derived& dst, const OtherDerived& other) { return dst.lazyAssign(other.eval()); }
+};
+template<typename Derived, typename OtherDerived>
+struct assign_selector<Derived,OtherDerived,false,true> {
+ static EIGEN_STRONG_INLINE Derived& run(Derived& dst, const OtherDerived& other) { return dst.lazyAssign(other.transpose()); }
+};
+template<typename Derived, typename OtherDerived>
+struct assign_selector<Derived,OtherDerived,true,true> {
+ static EIGEN_STRONG_INLINE Derived& run(Derived& dst, const OtherDerived& other) { return dst.lazyAssign(other.transpose().eval()); }
+};
+
+} // end namespace internal
+
+template<typename Derived>
+template<typename OtherDerived>
+EIGEN_STRONG_INLINE Derived& DenseBase<Derived>::operator=(const DenseBase<OtherDerived>& other)
+{
+ return internal::assign_selector<Derived,OtherDerived>::run(derived(), other.derived());
+}
+
+template<typename Derived>
+EIGEN_STRONG_INLINE Derived& DenseBase<Derived>::operator=(const DenseBase& other)
+{
+ return internal::assign_selector<Derived,Derived>::run(derived(), other.derived());
+}
+
+template<typename Derived>
+EIGEN_STRONG_INLINE Derived& MatrixBase<Derived>::operator=(const MatrixBase& other)
+{
+ return internal::assign_selector<Derived,Derived>::run(derived(), other.derived());
+}
+
+template<typename Derived>
+template <typename OtherDerived>
+EIGEN_STRONG_INLINE Derived& MatrixBase<Derived>::operator=(const DenseBase<OtherDerived>& other)
+{
+ return internal::assign_selector<Derived,OtherDerived>::run(derived(), other.derived());
+}
+
+template<typename Derived>
+template <typename OtherDerived>
+EIGEN_STRONG_INLINE Derived& MatrixBase<Derived>::operator=(const EigenBase<OtherDerived>& other)
+{
+ other.derived().evalTo(derived());
+ return derived();
+}
+
+template<typename Derived>
+template<typename OtherDerived>
+EIGEN_STRONG_INLINE Derived& MatrixBase<Derived>::operator=(const ReturnByValue<OtherDerived>& other)
+{
+ other.evalTo(derived());
+ return derived();
+}
+
+} // end namespace Eigen
+
+#endif // EIGEN_ASSIGN_H
diff --git a/Eigen/src/Core/Assign_MKL.h b/Eigen/src/Core/Assign_MKL.h
new file mode 100644
index 000000000..428c6367b
--- /dev/null
+++ b/Eigen/src/Core/Assign_MKL.h
@@ -0,0 +1,224 @@
+/*
+ Copyright (c) 2011, Intel Corporation. All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without modification,
+ are permitted provided that the following conditions are met:
+
+ * Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+ * Neither the name of Intel Corporation nor the names of its contributors may
+ be used to endorse or promote products derived from this software without
+ specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+ ********************************************************************************
+ * Content : Eigen bindings to Intel(R) MKL
+ * MKL VML support for coefficient-wise unary Eigen expressions like a=b.sin()
+ ********************************************************************************
+*/
+
+#ifndef EIGEN_ASSIGN_VML_H
+#define EIGEN_ASSIGN_VML_H
+
+namespace Eigen {
+
+namespace internal {
+
+template<typename Op> struct vml_call
+{ enum { IsSupported = 0 }; };
+
+template<typename Dst, typename Src, typename UnaryOp>
+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<UnaryOp>::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<typename Derived1, typename Derived2, typename UnaryOp, int Traversal, int Unrolling,
+ int VmlTraversal = vml_assign_traits<Derived1, Derived2, UnaryOp>::Traversal >
+struct vml_assign_impl
+ : assign_impl<Derived1, Eigen::CwiseUnaryOp<UnaryOp, Derived2>,Traversal,Unrolling,BuiltIn>
+{
+};
+
+template<typename Derived1, typename Derived2, typename UnaryOp, int Traversal, int Unrolling>
+struct vml_assign_impl<Derived1, Derived2, UnaryOp, Traversal, Unrolling, InnerVectorizedTraversal>
+{
+ typedef typename Derived1::Scalar Scalar;
+ typedef typename Derived1::Index Index;
+ static inline void run(Derived1& dst, const CwiseUnaryOp<UnaryOp, Derived2>& src)
+ {
+ // in case we want to (or have to) skip VML at runtime we can call:
+ // assign_impl<Derived1,Eigen::CwiseUnaryOp<UnaryOp, Derived2>,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<UnaryOp>::run(src.functor(), innerSize, src_ptr, dst_ptr );
+ }
+ }
+};
+
+template<typename Derived1, typename Derived2, typename UnaryOp, int Traversal, int Unrolling>
+struct vml_assign_impl<Derived1, Derived2, UnaryOp, Traversal, Unrolling, LinearVectorizedTraversal>
+{
+ static inline void run(Derived1& dst, const CwiseUnaryOp<UnaryOp, Derived2>& src)
+ {
+ // in case we want to (or have to) skip VML at runtime we can call:
+ // assign_impl<Derived1,Eigen::CwiseUnaryOp<UnaryOp, Derived2>,Traversal,Unrolling,BuiltIn>::run(dst,src);
+ vml_call<UnaryOp>::run(src.functor(), dst.size(), src.nestedExpression().data(), dst.data() );
+ }
+};
+
+// Macroses
+
+#define EIGEN_MKL_VML_SPECIALIZE_ASSIGN(TRAVERSAL,UNROLLING) \
+ template<typename Derived1, typename Derived2, typename UnaryOp> \
+ struct assign_impl<Derived1, Eigen::CwiseUnaryOp<UnaryOp, Derived2>, TRAVERSAL, UNROLLING, Specialized> { \
+ static inline void run(Derived1 &dst, const Eigen::CwiseUnaryOp<UnaryOp, Derived2> &src) { \
+ vml_assign_impl<Derived1,Derived2,UnaryOp,TRAVERSAL,UNROLLING>::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<EIGENTYPE> > { \
+ enum { IsSupported = 1 }; \
+ static inline void run( const scalar_##EIGENOP##_op<EIGENTYPE>& /*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<EIGENTYPE> > { \
+ enum { IsSupported = 1 }; \
+ static inline void run( const scalar_##EIGENOP##_op<EIGENTYPE>& /*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<EIGENTYPE> > { \
+ enum { IsSupported = 1 }; \
+ static inline void run( const scalar_##EIGENOP##_op<EIGENTYPE>& func, \
+ int size, const EIGENTYPE* src, EIGENTYPE* dst) { \
+ EIGENTYPE exponent = func.m_exponent; \
+ MKL_INT64 vmlMode = EIGEN_MKL_VML_MODE; \
+ VMLOP(&size, (const VMLTYPE*)src, (const VMLTYPE*)&exponent, \
+ (VMLTYPE*)dst, &vmlMode); \
+ } \
+ };
+
+#define EIGEN_MKL_VML_DECLARE_UNARY_CALLS_REAL(EIGENOP, VMLOP) \
+ EIGEN_MKL_VML_DECLARE_UNARY_CALL(EIGENOP, vs##VMLOP, float, float) \
+ EIGEN_MKL_VML_DECLARE_UNARY_CALL(EIGENOP, vd##VMLOP, double, double)
+
+#define EIGEN_MKL_VML_DECLARE_UNARY_CALLS_COMPLEX(EIGENOP, VMLOP) \
+ EIGEN_MKL_VML_DECLARE_UNARY_CALL(EIGENOP, vc##VMLOP, scomplex, MKL_Complex8) \
+ EIGEN_MKL_VML_DECLARE_UNARY_CALL(EIGENOP, vz##VMLOP, dcomplex, MKL_Complex16)
+
+#define EIGEN_MKL_VML_DECLARE_UNARY_CALLS(EIGENOP, VMLOP) \
+ EIGEN_MKL_VML_DECLARE_UNARY_CALLS_REAL(EIGENOP, VMLOP) \
+ EIGEN_MKL_VML_DECLARE_UNARY_CALLS_COMPLEX(EIGENOP, VMLOP)
+
+
+#define EIGEN_MKL_VML_DECLARE_UNARY_CALLS_REAL_LA(EIGENOP, VMLOP) \
+ EIGEN_MKL_VML_DECLARE_UNARY_CALL_LA(EIGENOP, vms##VMLOP, float, float) \
+ EIGEN_MKL_VML_DECLARE_UNARY_CALL_LA(EIGENOP, vmd##VMLOP, double, double)
+
+#define EIGEN_MKL_VML_DECLARE_UNARY_CALLS_COMPLEX_LA(EIGENOP, VMLOP) \
+ EIGEN_MKL_VML_DECLARE_UNARY_CALL_LA(EIGENOP, vmc##VMLOP, scomplex, MKL_Complex8) \
+ EIGEN_MKL_VML_DECLARE_UNARY_CALL_LA(EIGENOP, vmz##VMLOP, dcomplex, MKL_Complex16)
+
+#define EIGEN_MKL_VML_DECLARE_UNARY_CALLS_LA(EIGENOP, VMLOP) \
+ EIGEN_MKL_VML_DECLARE_UNARY_CALLS_REAL_LA(EIGENOP, VMLOP) \
+ EIGEN_MKL_VML_DECLARE_UNARY_CALLS_COMPLEX_LA(EIGENOP, VMLOP)
+
+
+EIGEN_MKL_VML_DECLARE_UNARY_CALLS_LA(sin, Sin)
+EIGEN_MKL_VML_DECLARE_UNARY_CALLS_LA(asin, Asin)
+EIGEN_MKL_VML_DECLARE_UNARY_CALLS_LA(cos, Cos)
+EIGEN_MKL_VML_DECLARE_UNARY_CALLS_LA(acos, Acos)
+EIGEN_MKL_VML_DECLARE_UNARY_CALLS_LA(tan, Tan)
+//EIGEN_MKL_VML_DECLARE_UNARY_CALLS(abs, Abs)
+EIGEN_MKL_VML_DECLARE_UNARY_CALLS_LA(exp, Exp)
+EIGEN_MKL_VML_DECLARE_UNARY_CALLS_LA(log, Ln)
+EIGEN_MKL_VML_DECLARE_UNARY_CALLS_LA(sqrt, Sqrt)
+
+EIGEN_MKL_VML_DECLARE_UNARY_CALLS_REAL(square, Sqr)
+
+// The vm*powx functions are not avaibale in the windows version of MKL.
+#ifdef _WIN32
+EIGEN_MKL_VML_DECLARE_POW_CALL(pow, vmspowx_, float, float)
+EIGEN_MKL_VML_DECLARE_POW_CALL(pow, vmdpowx_, double, double)
+EIGEN_MKL_VML_DECLARE_POW_CALL(pow, vmcpowx_, scomplex, MKL_Complex8)
+EIGEN_MKL_VML_DECLARE_POW_CALL(pow, vmzpowx_, dcomplex, MKL_Complex16)
+#endif
+
+} // end namespace internal
+
+} // end namespace Eigen
+
+#endif // EIGEN_ASSIGN_VML_H
diff --git a/Eigen/src/Core/BandMatrix.h b/Eigen/src/Core/BandMatrix.h
new file mode 100644
index 000000000..ffd7fe8b3
--- /dev/null
+++ b/Eigen/src/Core/BandMatrix.h
@@ -0,0 +1,334 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra.
+//
+// Copyright (C) 2009 Gael Guennebaud <gael.guennebaud@inria.fr>
+//
+// This Source Code Form is subject to the terms of the Mozilla
+// Public License v. 2.0. If a copy of the MPL was not distributed
+// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+#ifndef EIGEN_BANDMATRIX_H
+#define EIGEN_BANDMATRIX_H
+
+namespace Eigen {
+
+namespace internal {
+
+template<typename Derived>
+class BandMatrixBase : public EigenBase<Derived>
+{
+ public:
+
+ enum {
+ Flags = internal::traits<Derived>::Flags,
+ CoeffReadCost = internal::traits<Derived>::CoeffReadCost,
+ RowsAtCompileTime = internal::traits<Derived>::RowsAtCompileTime,
+ ColsAtCompileTime = internal::traits<Derived>::ColsAtCompileTime,
+ MaxRowsAtCompileTime = internal::traits<Derived>::MaxRowsAtCompileTime,
+ MaxColsAtCompileTime = internal::traits<Derived>::MaxColsAtCompileTime,
+ Supers = internal::traits<Derived>::Supers,
+ Subs = internal::traits<Derived>::Subs,
+ Options = internal::traits<Derived>::Options
+ };
+ typedef typename internal::traits<Derived>::Scalar Scalar;
+ typedef Matrix<Scalar,RowsAtCompileTime,ColsAtCompileTime> DenseMatrixType;
+ typedef typename DenseMatrixType::Index Index;
+ typedef typename internal::traits<Derived>::CoefficientsType CoefficientsType;
+ typedef EigenBase<Derived> Base;
+
+ protected:
+ enum {
+ DataRowsAtCompileTime = ((Supers!=Dynamic) && (Subs!=Dynamic))
+ ? 1 + Supers + Subs
+ : Dynamic,
+ SizeAtCompileTime = EIGEN_SIZE_MIN_PREFER_DYNAMIC(RowsAtCompileTime,ColsAtCompileTime)
+ };
+
+ public:
+
+ using Base::derived;
+ using Base::rows;
+ using Base::cols;
+
+ /** \returns the number of super diagonals */
+ inline Index supers() const { return derived().supers(); }
+
+ /** \returns the number of sub diagonals */
+ inline Index subs() const { return derived().subs(); }
+
+ /** \returns an expression of the underlying coefficient matrix */
+ inline const CoefficientsType& coeffs() const { return derived().coeffs(); }
+
+ /** \returns an expression of the underlying coefficient matrix */
+ inline CoefficientsType& coeffs() { return derived().coeffs(); }
+
+ /** \returns a vector expression of the \a i -th column,
+ * only the meaningful part is returned.
+ * \warning the internal storage must be column major. */
+ inline Block<CoefficientsType,Dynamic,1> col(Index i)
+ {
+ EIGEN_STATIC_ASSERT((Options&RowMajor)==0,THIS_METHOD_IS_ONLY_FOR_COLUMN_MAJOR_MATRICES);
+ Index start = 0;
+ Index len = coeffs().rows();
+ if (i<=supers())
+ {
+ start = supers()-i;
+ len = (std::min)(rows(),std::max<Index>(0,coeffs().rows() - (supers()-i)));
+ }
+ else if (i>=rows()-subs())
+ len = std::max<Index>(0,coeffs().rows() - (i + 1 - rows() + subs()));
+ return Block<CoefficientsType,Dynamic,1>(coeffs(), start, i, len, 1);
+ }
+
+ /** \returns a vector expression of the main diagonal */
+ inline Block<CoefficientsType,1,SizeAtCompileTime> diagonal()
+ { return Block<CoefficientsType,1,SizeAtCompileTime>(coeffs(),supers(),0,1,(std::min)(rows(),cols())); }
+
+ /** \returns a vector expression of the main diagonal (const version) */
+ inline const Block<const CoefficientsType,1,SizeAtCompileTime> diagonal() const
+ { return Block<const CoefficientsType,1,SizeAtCompileTime>(coeffs(),supers(),0,1,(std::min)(rows(),cols())); }
+
+ template<int Index> struct DiagonalIntReturnType {
+ enum {
+ ReturnOpposite = (Options&SelfAdjoint) && (((Index)>0 && Supers==0) || ((Index)<0 && Subs==0)),
+ Conjugate = ReturnOpposite && NumTraits<Scalar>::IsComplex,
+ ActualIndex = ReturnOpposite ? -Index : Index,
+ DiagonalSize = (RowsAtCompileTime==Dynamic || ColsAtCompileTime==Dynamic)
+ ? Dynamic
+ : (ActualIndex<0
+ ? EIGEN_SIZE_MIN_PREFER_DYNAMIC(ColsAtCompileTime, RowsAtCompileTime + ActualIndex)
+ : EIGEN_SIZE_MIN_PREFER_DYNAMIC(RowsAtCompileTime, ColsAtCompileTime - ActualIndex))
+ };
+ typedef Block<CoefficientsType,1, DiagonalSize> BuildType;
+ typedef typename internal::conditional<Conjugate,
+ CwiseUnaryOp<internal::scalar_conjugate_op<Scalar>,BuildType >,
+ BuildType>::type Type;
+ };
+
+ /** \returns a vector expression of the \a N -th sub or super diagonal */
+ template<int N> inline typename DiagonalIntReturnType<N>::Type diagonal()
+ {
+ return typename DiagonalIntReturnType<N>::BuildType(coeffs(), supers()-N, (std::max)(0,N), 1, diagonalLength(N));
+ }
+
+ /** \returns a vector expression of the \a N -th sub or super diagonal */
+ template<int N> inline const typename DiagonalIntReturnType<N>::Type diagonal() const
+ {
+ return typename DiagonalIntReturnType<N>::BuildType(coeffs(), supers()-N, (std::max)(0,N), 1, diagonalLength(N));
+ }
+
+ /** \returns a vector expression of the \a i -th sub or super diagonal */
+ inline Block<CoefficientsType,1,Dynamic> diagonal(Index i)
+ {
+ eigen_assert((i<0 && -i<=subs()) || (i>=0 && i<=supers()));
+ return Block<CoefficientsType,1,Dynamic>(coeffs(), supers()-i, std::max<Index>(0,i), 1, diagonalLength(i));
+ }
+
+ /** \returns a vector expression of the \a i -th sub or super diagonal */
+ inline const Block<const CoefficientsType,1,Dynamic> diagonal(Index i) const
+ {
+ eigen_assert((i<0 && -i<=subs()) || (i>=0 && i<=supers()));
+ return Block<const CoefficientsType,1,Dynamic>(coeffs(), supers()-i, std::max<Index>(0,i), 1, diagonalLength(i));
+ }
+
+ template<typename Dest> inline void evalTo(Dest& dst) const
+ {
+ dst.resize(rows(),cols());
+ dst.setZero();
+ dst.diagonal() = diagonal();
+ for (Index i=1; i<=supers();++i)
+ dst.diagonal(i) = diagonal(i);
+ for (Index i=1; i<=subs();++i)
+ dst.diagonal(-i) = diagonal(-i);
+ }
+
+ DenseMatrixType toDenseMatrix() const
+ {
+ DenseMatrixType res(rows(),cols());
+ evalTo(res);
+ return res;
+ }
+
+ protected:
+
+ inline Index diagonalLength(Index i) const
+ { return i<0 ? (std::min)(cols(),rows()+i) : (std::min)(rows(),cols()-i); }
+};
+
+/**
+ * \class BandMatrix
+ * \ingroup Core_Module
+ *
+ * \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.
+ *
+ * \sa class TridiagonalMatrix
+ */
+
+template<typename _Scalar, int _Rows, int _Cols, int _Supers, int _Subs, int _Options>
+struct traits<BandMatrix<_Scalar,_Rows,_Cols,_Supers,_Subs,_Options> >
+{
+ typedef _Scalar Scalar;
+ typedef Dense StorageKind;
+ typedef DenseIndex Index;
+ enum {
+ CoeffReadCost = NumTraits<Scalar>::ReadCost,
+ RowsAtCompileTime = _Rows,
+ ColsAtCompileTime = _Cols,
+ MaxRowsAtCompileTime = _Rows,
+ MaxColsAtCompileTime = _Cols,
+ Flags = LvalueBit,
+ Supers = _Supers,
+ Subs = _Subs,
+ Options = _Options,
+ DataRowsAtCompileTime = ((Supers!=Dynamic) && (Subs!=Dynamic)) ? 1 + Supers + Subs : Dynamic
+ };
+ typedef Matrix<Scalar,DataRowsAtCompileTime,ColsAtCompileTime,Options&RowMajor?RowMajor:ColMajor> CoefficientsType;
+};
+
+template<typename _Scalar, int Rows, int Cols, int Supers, int Subs, int Options>
+class BandMatrix : public BandMatrixBase<BandMatrix<_Scalar,Rows,Cols,Supers,Subs,Options> >
+{
+ public:
+
+ typedef typename internal::traits<BandMatrix>::Scalar Scalar;
+ typedef typename internal::traits<BandMatrix>::Index Index;
+ typedef typename internal::traits<BandMatrix>::CoefficientsType CoefficientsType;
+
+ 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)
+ {
+ }
+
+ /** \returns the number of columns */
+ inline Index rows() const { return m_rows.value(); }
+
+ /** \returns the number of rows */
+ inline Index cols() const { return m_coeffs.cols(); }
+
+ /** \returns the number of super diagonals */
+ inline Index supers() const { return m_supers.value(); }
+
+ /** \returns the number of sub diagonals */
+ inline Index subs() const { return m_subs.value(); }
+
+ inline const CoefficientsType& coeffs() const { return m_coeffs; }
+ inline CoefficientsType& coeffs() { return m_coeffs; }
+
+ protected:
+
+ CoefficientsType m_coeffs;
+ internal::variable_if_dynamic<Index, Rows> m_rows;
+ internal::variable_if_dynamic<Index, Supers> m_supers;
+ internal::variable_if_dynamic<Index, Subs> m_subs;
+};
+
+template<typename _CoefficientsType,int _Rows, int _Cols, int _Supers, int _Subs,int _Options>
+class BandMatrixWrapper;
+
+template<typename _CoefficientsType,int _Rows, int _Cols, int _Supers, int _Subs,int _Options>
+struct traits<BandMatrixWrapper<_CoefficientsType,_Rows,_Cols,_Supers,_Subs,_Options> >
+{
+ typedef typename _CoefficientsType::Scalar Scalar;
+ typedef typename _CoefficientsType::StorageKind StorageKind;
+ typedef typename _CoefficientsType::Index Index;
+ enum {
+ CoeffReadCost = internal::traits<_CoefficientsType>::CoeffReadCost,
+ RowsAtCompileTime = _Rows,
+ ColsAtCompileTime = _Cols,
+ MaxRowsAtCompileTime = _Rows,
+ MaxColsAtCompileTime = _Cols,
+ Flags = LvalueBit,
+ Supers = _Supers,
+ Subs = _Subs,
+ Options = _Options,
+ DataRowsAtCompileTime = ((Supers!=Dynamic) && (Subs!=Dynamic)) ? 1 + Supers + Subs : Dynamic
+ };
+ typedef _CoefficientsType CoefficientsType;
+};
+
+template<typename _CoefficientsType,int _Rows, int _Cols, int _Supers, int _Subs,int _Options>
+class BandMatrixWrapper : public BandMatrixBase<BandMatrixWrapper<_CoefficientsType,_Rows,_Cols,_Supers,_Subs,_Options> >
+{
+ public:
+
+ typedef typename internal::traits<BandMatrixWrapper>::Scalar Scalar;
+ typedef typename internal::traits<BandMatrixWrapper>::CoefficientsType CoefficientsType;
+ typedef typename internal::traits<BandMatrixWrapper>::Index Index;
+
+ 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)
+ {
+ EIGEN_UNUSED_VARIABLE(cols);
+ //internal::assert(coeffs.cols()==cols() && (supers()+subs()+1)==coeffs.rows());
+ }
+
+ /** \returns the number of columns */
+ inline Index rows() const { return m_rows.value(); }
+
+ /** \returns the number of rows */
+ inline Index cols() const { return m_coeffs.cols(); }
+
+ /** \returns the number of super diagonals */
+ inline Index supers() const { return m_supers.value(); }
+
+ /** \returns the number of sub diagonals */
+ inline Index subs() const { return m_subs.value(); }
+
+ inline const CoefficientsType& coeffs() const { return m_coeffs; }
+
+ protected:
+
+ const CoefficientsType& m_coeffs;
+ internal::variable_if_dynamic<Index, _Rows> m_rows;
+ internal::variable_if_dynamic<Index, _Supers> m_supers;
+ internal::variable_if_dynamic<Index, _Subs> m_subs;
+};
+
+/**
+ * \class TridiagonalMatrix
+ * \ingroup Core_Module
+ *
+ * \brief Represents a tridiagonal matrix with a compact banded storage
+ *
+ * \param _Scalar Numeric type, i.e. float, double, int
+ * \param Size Number of rows and cols, or \b Dynamic
+ * \param _Options Can be 0 or \b SelfAdjoint
+ *
+ * \sa class BandMatrix
+ */
+template<typename Scalar, int Size, int Options>
+class TridiagonalMatrix : public BandMatrix<Scalar,Size,Size,Options&SelfAdjoint?0:1,1,Options|RowMajor>
+{
+ typedef BandMatrix<Scalar,Size,Size,Options&SelfAdjoint?0:1,1,Options|RowMajor> Base;
+ typedef typename Base::Index Index;
+ public:
+ 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>(); }
+ inline const typename Base::template DiagonalIntReturnType<1>::Type super() const
+ { return Base::template diagonal<1>(); }
+ inline typename Base::template DiagonalIntReturnType<-1>::Type sub()
+ { return Base::template diagonal<-1>(); }
+ inline const typename Base::template DiagonalIntReturnType<-1>::Type sub() const
+ { return Base::template diagonal<-1>(); }
+ protected:
+};
+
+} // end namespace internal
+
+} // end namespace Eigen
+
+#endif // EIGEN_BANDMATRIX_H
diff --git a/Eigen/src/Core/Block.h b/Eigen/src/Core/Block.h
new file mode 100644
index 000000000..5f29cb3d1
--- /dev/null
+++ b/Eigen/src/Core/Block.h
@@ -0,0 +1,357 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra.
+//
+// Copyright (C) 2008 Gael Guennebaud <gael.guennebaud@inria.fr>
+// Copyright (C) 2006-2010 Benoit Jacob <jacob.benoit.1@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 EIGEN_BLOCK_H
+#define EIGEN_BLOCK_H
+
+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)
+ * \param _DirectAccessStatus \internal used for partial specialization
+ *
+ * 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<int,int>(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<typename XprType, int BlockRows, int BlockCols, bool InnerPanel, bool HasDirectAccess>
+struct traits<Block<XprType, BlockRows, BlockCols, InnerPanel, HasDirectAccess> > : traits<XprType>
+{
+ typedef typename traits<XprType>::Scalar Scalar;
+ typedef typename traits<XprType>::StorageKind StorageKind;
+ typedef typename traits<XprType>::XprKind XprKind;
+ typedef typename nested<XprType>::type XprTypeNested;
+ typedef typename remove_reference<XprTypeNested>::type _XprTypeNested;
+ enum{
+ MatrixRows = traits<XprType>::RowsAtCompileTime,
+ MatrixCols = traits<XprType>::ColsAtCompileTime,
+ RowsAtCompileTime = MatrixRows == 0 ? 0 : BlockRows,
+ ColsAtCompileTime = MatrixCols == 0 ? 0 : BlockCols,
+ MaxRowsAtCompileTime = BlockRows==0 ? 0
+ : RowsAtCompileTime != Dynamic ? int(RowsAtCompileTime)
+ : int(traits<XprType>::MaxRowsAtCompileTime),
+ MaxColsAtCompileTime = BlockCols==0 ? 0
+ : ColsAtCompileTime != Dynamic ? int(ColsAtCompileTime)
+ : int(traits<XprType>::MaxColsAtCompileTime),
+ XprTypeIsRowMajor = (int(traits<XprType>::Flags)&RowMajorBit) != 0,
+ IsRowMajor = (MaxRowsAtCompileTime==1&&MaxColsAtCompileTime!=1) ? 1
+ : (MaxColsAtCompileTime==1&&MaxRowsAtCompileTime!=1) ? 0
+ : XprTypeIsRowMajor,
+ HasSameStorageOrderAsXprType = (IsRowMajor == XprTypeIsRowMajor),
+ InnerSize = IsRowMajor ? int(ColsAtCompileTime) : int(RowsAtCompileTime),
+ InnerStrideAtCompileTime = HasSameStorageOrderAsXprType
+ ? int(inner_stride_at_compile_time<XprType>::ret)
+ : int(outer_stride_at_compile_time<XprType>::ret),
+ OuterStrideAtCompileTime = HasSameStorageOrderAsXprType
+ ? int(outer_stride_at_compile_time<XprType>::ret)
+ : int(inner_stride_at_compile_time<XprType>::ret),
+ MaskPacketAccessBit = (InnerSize == Dynamic || (InnerSize % packet_traits<Scalar>::size) == 0)
+ && (InnerStrideAtCompileTime == 1)
+ ? PacketAccessBit : 0,
+ MaskAlignedBit = (InnerPanel && (OuterStrideAtCompileTime!=Dynamic) && (((OuterStrideAtCompileTime * int(sizeof(Scalar))) % 16) == 0)) ? AlignedBit : 0,
+ FlagsLinearAccessBit = (RowsAtCompileTime == 1 || ColsAtCompileTime == 1) ? LinearAccessBit : 0,
+ FlagsLvalueBit = is_lvalue<XprType>::value ? LvalueBit : 0,
+ FlagsRowMajorBit = IsRowMajor ? RowMajorBit : 0,
+ Flags0 = traits<XprType>::Flags & ( (HereditaryBits & ~RowMajorBit) |
+ DirectAccessBit |
+ MaskPacketAccessBit |
+ MaskAlignedBit),
+ Flags = Flags0 | FlagsLinearAccessBit | FlagsLvalueBit | FlagsRowMajorBit
+ };
+};
+}
+
+template<typename XprType, int BlockRows, int BlockCols, bool InnerPanel, bool HasDirectAccess> class Block
+ : public internal::dense_xpr_base<Block<XprType, BlockRows, BlockCols, InnerPanel, HasDirectAccess> >::type
+{
+ public:
+
+ typedef typename internal::dense_xpr_base<Block>::type Base;
+ EIGEN_DENSE_PUBLIC_INTERFACE(Block)
+
+ class InnerIterator;
+
+ /** Column or Row constructor
+ */
+ inline Block(XprType& xpr, Index i)
+ : m_xpr(xpr),
+ // It is a row if and only if BlockRows==1 and BlockCols==XprType::ColsAtCompileTime,
+ // and it is a column if and only if BlockRows==XprType::RowsAtCompileTime and BlockCols==1,
+ // all other cases are invalid.
+ // The case a 1x1 matrix seems ambiguous, but the result is the same anyway.
+ 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())
+ {
+ eigen_assert( (i>=0) && (
+ ((BlockRows==1) && (BlockCols==XprType::ColsAtCompileTime) && i<xpr.rows())
+ ||((BlockRows==XprType::RowsAtCompileTime) && (BlockCols==1) && i<xpr.cols())));
+ }
+
+ /** Fixed-size constructor
+ */
+ inline Block(XprType& xpr, Index startRow, Index startCol)
+ : m_xpr(xpr), m_startRow(startRow), m_startCol(startCol),
+ m_blockRows(BlockRows), m_blockCols(BlockCols)
+ {
+ EIGEN_STATIC_ASSERT(RowsAtCompileTime!=Dynamic && ColsAtCompileTime!=Dynamic,THIS_METHOD_IS_ONLY_FOR_FIXED_SIZE)
+ eigen_assert(startRow >= 0 && BlockRows >= 1 && startRow + BlockRows <= xpr.rows()
+ && startCol >= 0 && BlockCols >= 1 && startCol + BlockCols <= xpr.cols());
+ }
+
+ /** Dynamic-size constructor
+ */
+ inline Block(XprType& xpr,
+ Index startRow, Index startCol,
+ Index blockRows, Index blockCols)
+ : m_xpr(xpr), m_startRow(startRow), m_startCol(startCol),
+ m_blockRows(blockRows), m_blockCols(blockCols)
+ {
+ eigen_assert((RowsAtCompileTime==Dynamic || RowsAtCompileTime==blockRows)
+ && (ColsAtCompileTime==Dynamic || ColsAtCompileTime==blockCols));
+ eigen_assert(startRow >= 0 && blockRows >= 0 && startRow + blockRows <= xpr.rows()
+ && startCol >= 0 && blockCols >= 0 && startCol + blockCols <= xpr.cols());
+ }
+
+ EIGEN_INHERIT_ASSIGNMENT_OPERATORS(Block)
+
+ inline Index rows() const { return m_blockRows.value(); }
+ inline Index cols() const { return m_blockCols.value(); }
+
+ inline Scalar& coeffRef(Index row, Index col)
+ {
+ EIGEN_STATIC_ASSERT_LVALUE(XprType)
+ return m_xpr.const_cast_derived()
+ .coeffRef(row + m_startRow.value(), col + m_startCol.value());
+ }
+
+ inline const Scalar& coeffRef(Index row, Index col) const
+ {
+ return m_xpr.derived()
+ .coeffRef(row + m_startRow.value(), col + m_startCol.value());
+ }
+
+ EIGEN_STRONG_INLINE const CoeffReturnType coeff(Index row, Index col) const
+ {
+ return m_xpr.coeff(row + m_startRow.value(), col + m_startCol.value());
+ }
+
+ inline Scalar& coeffRef(Index index)
+ {
+ EIGEN_STATIC_ASSERT_LVALUE(XprType)
+ return m_xpr.const_cast_derived()
+ .coeffRef(m_startRow.value() + (RowsAtCompileTime == 1 ? 0 : index),
+ m_startCol.value() + (RowsAtCompileTime == 1 ? index : 0));
+ }
+
+ inline const Scalar& coeffRef(Index index) const
+ {
+ return m_xpr.const_cast_derived()
+ .coeffRef(m_startRow.value() + (RowsAtCompileTime == 1 ? 0 : index),
+ m_startCol.value() + (RowsAtCompileTime == 1 ? index : 0));
+ }
+
+ inline const CoeffReturnType coeff(Index index) const
+ {
+ return m_xpr
+ .coeff(m_startRow.value() + (RowsAtCompileTime == 1 ? 0 : index),
+ m_startCol.value() + (RowsAtCompileTime == 1 ? index : 0));
+ }
+
+ template<int LoadMode>
+ inline PacketScalar packet(Index row, Index col) const
+ {
+ return m_xpr.template packet<Unaligned>
+ (row + m_startRow.value(), col + m_startCol.value());
+ }
+
+ template<int LoadMode>
+ inline void writePacket(Index row, Index col, const PacketScalar& x)
+ {
+ m_xpr.const_cast_derived().template writePacket<Unaligned>
+ (row + m_startRow.value(), col + m_startCol.value(), x);
+ }
+
+ template<int LoadMode>
+ inline PacketScalar packet(Index index) const
+ {
+ return m_xpr.template packet<Unaligned>
+ (m_startRow.value() + (RowsAtCompileTime == 1 ? 0 : index),
+ m_startCol.value() + (RowsAtCompileTime == 1 ? index : 0));
+ }
+
+ template<int LoadMode>
+ inline void writePacket(Index index, const PacketScalar& x)
+ {
+ m_xpr.const_cast_derived().template writePacket<Unaligned>
+ (m_startRow.value() + (RowsAtCompileTime == 1 ? 0 : index),
+ m_startCol.value() + (RowsAtCompileTime == 1 ? index : 0), x);
+ }
+
+ #ifdef EIGEN_PARSED_BY_DOXYGEN
+ /** \sa MapBase::data() */
+ inline const Scalar* data() const;
+ inline Index innerStride() const;
+ inline Index outerStride() const;
+ #endif
+
+ const typename internal::remove_all<typename XprType::Nested>::type& nestedExpression() const
+ {
+ return m_xpr;
+ }
+
+ Index startRow() const
+ {
+ return m_startRow.value();
+ }
+
+ Index startCol() const
+ {
+ return m_startCol.value();
+ }
+
+ protected:
+
+ const typename XprType::Nested m_xpr;
+ const internal::variable_if_dynamic<Index, XprType::RowsAtCompileTime == 1 ? 0 : Dynamic> m_startRow;
+ const internal::variable_if_dynamic<Index, XprType::ColsAtCompileTime == 1 ? 0 : Dynamic> m_startCol;
+ const internal::variable_if_dynamic<Index, RowsAtCompileTime> m_blockRows;
+ const internal::variable_if_dynamic<Index, ColsAtCompileTime> m_blockCols;
+};
+
+/** \internal */
+template<typename XprType, int BlockRows, int BlockCols, bool InnerPanel>
+class Block<XprType,BlockRows,BlockCols, InnerPanel,true>
+ : public MapBase<Block<XprType, BlockRows, BlockCols, InnerPanel, true> >
+{
+ public:
+
+ typedef MapBase<Block> Base;
+ EIGEN_DENSE_PUBLIC_INTERFACE(Block)
+
+ EIGEN_INHERIT_ASSIGNMENT_OPERATORS(Block)
+
+ /** Column or Row constructor
+ */
+ inline Block(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)),
+ BlockRows==1 ? 1 : xpr.rows(),
+ BlockCols==1 ? 1 : xpr.cols()),
+ m_xpr(xpr)
+ {
+ eigen_assert( (i>=0) && (
+ ((BlockRows==1) && (BlockCols==XprType::ColsAtCompileTime) && i<xpr.rows())
+ ||((BlockRows==XprType::RowsAtCompileTime) && (BlockCols==1) && i<xpr.cols())));
+ init();
+ }
+
+ /** Fixed-size constructor
+ */
+ inline Block(XprType& xpr, Index startRow, Index startCol)
+ : Base(internal::const_cast_ptr(&xpr.coeffRef(startRow,startCol))), m_xpr(xpr)
+ {
+ eigen_assert(startRow >= 0 && BlockRows >= 1 && startRow + BlockRows <= xpr.rows()
+ && startCol >= 0 && BlockCols >= 1 && startCol + BlockCols <= xpr.cols());
+ init();
+ }
+
+ /** Dynamic-size constructor
+ */
+ inline Block(XprType& xpr,
+ Index startRow, Index startCol,
+ Index blockRows, Index blockCols)
+ : Base(internal::const_cast_ptr(&xpr.coeffRef(startRow,startCol)), blockRows, blockCols),
+ m_xpr(xpr)
+ {
+ eigen_assert((RowsAtCompileTime==Dynamic || RowsAtCompileTime==blockRows)
+ && (ColsAtCompileTime==Dynamic || ColsAtCompileTime==blockCols));
+ eigen_assert(startRow >= 0 && blockRows >= 0 && startRow + blockRows <= xpr.rows()
+ && startCol >= 0 && blockCols >= 0 && startCol + blockCols <= xpr.cols());
+ init();
+ }
+
+ const typename internal::remove_all<typename XprType::Nested>::type& nestedExpression() const
+ {
+ return m_xpr;
+ }
+
+ /** \sa MapBase::innerStride() */
+ inline Index innerStride() const
+ {
+ return internal::traits<Block>::HasSameStorageOrderAsXprType
+ ? m_xpr.innerStride()
+ : m_xpr.outerStride();
+ }
+
+ /** \sa MapBase::outerStride() */
+ inline Index outerStride() const
+ {
+ return m_outerStride;
+ }
+
+ #ifndef __SUNPRO_CC
+ // FIXME sunstudio is not friendly with the above friend...
+ // META-FIXME there is no 'friend' keyword around here. Is this obsolete?
+ protected:
+ #endif
+
+ #ifndef EIGEN_PARSED_BY_DOXYGEN
+ /** \internal used by allowAligned() */
+ inline Block(XprType& xpr, const Scalar* data, Index blockRows, Index blockCols)
+ : Base(data, blockRows, blockCols), m_xpr(xpr)
+ {
+ init();
+ }
+ #endif
+
+ protected:
+ void init()
+ {
+ m_outerStride = internal::traits<Block>::HasSameStorageOrderAsXprType
+ ? m_xpr.outerStride()
+ : m_xpr.innerStride();
+ }
+
+ typename XprType::Nested m_xpr;
+ Index m_outerStride;
+};
+
+} // end namespace Eigen
+
+#endif // EIGEN_BLOCK_H
diff --git a/Eigen/src/Core/BooleanRedux.h b/Eigen/src/Core/BooleanRedux.h
new file mode 100644
index 000000000..57efd8e69
--- /dev/null
+++ b/Eigen/src/Core/BooleanRedux.h
@@ -0,0 +1,138 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra.
+//
+// Copyright (C) 2008 Gael Guennebaud <gael.guennebaud@inria.fr>
+//
+// This Source Code Form is subject to the terms of the Mozilla
+// Public License v. 2.0. If a copy of the MPL was not distributed
+// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+#ifndef EIGEN_ALLANDANY_H
+#define EIGEN_ALLANDANY_H
+
+namespace Eigen {
+
+namespace internal {
+
+template<typename Derived, int UnrollCount>
+struct all_unroller
+{
+ enum {
+ col = (UnrollCount-1) / Derived::RowsAtCompileTime,
+ row = (UnrollCount-1) % Derived::RowsAtCompileTime
+ };
+
+ static inline bool run(const Derived &mat)
+ {
+ return all_unroller<Derived, UnrollCount-1>::run(mat) && mat.coeff(row, col);
+ }
+};
+
+template<typename Derived>
+struct all_unroller<Derived, 1>
+{
+ static inline bool run(const Derived &mat) { return mat.coeff(0, 0); }
+};
+
+template<typename Derived>
+struct all_unroller<Derived, Dynamic>
+{
+ static inline bool run(const Derived &) { return false; }
+};
+
+template<typename Derived, int UnrollCount>
+struct any_unroller
+{
+ enum {
+ col = (UnrollCount-1) / Derived::RowsAtCompileTime,
+ row = (UnrollCount-1) % Derived::RowsAtCompileTime
+ };
+
+ static inline bool run(const Derived &mat)
+ {
+ return any_unroller<Derived, UnrollCount-1>::run(mat) || mat.coeff(row, col);
+ }
+};
+
+template<typename Derived>
+struct any_unroller<Derived, 1>
+{
+ static inline bool run(const Derived &mat) { return mat.coeff(0, 0); }
+};
+
+template<typename Derived>
+struct any_unroller<Derived, Dynamic>
+{
+ static inline bool run(const Derived &) { return false; }
+};
+
+} // end namespace internal
+
+/** \returns true if all coefficients are true
+ *
+ * Example: \include MatrixBase_all.cpp
+ * Output: \verbinclude MatrixBase_all.out
+ *
+ * \sa any(), Cwise::operator<()
+ */
+template<typename Derived>
+inline bool DenseBase<Derived>::all() const
+{
+ enum {
+ unroll = SizeAtCompileTime != Dynamic
+ && CoeffReadCost != Dynamic
+ && NumTraits<Scalar>::AddCost != Dynamic
+ && SizeAtCompileTime * (CoeffReadCost + NumTraits<Scalar>::AddCost) <= EIGEN_UNROLLING_LIMIT
+ };
+ if(unroll)
+ return internal::all_unroller<Derived,
+ unroll ? int(SizeAtCompileTime) : Dynamic
+ >::run(derived());
+ else
+ {
+ for(Index j = 0; j < cols(); ++j)
+ for(Index i = 0; i < rows(); ++i)
+ if (!coeff(i, j)) return false;
+ return true;
+ }
+}
+
+/** \returns true if at least one coefficient is true
+ *
+ * \sa all()
+ */
+template<typename Derived>
+inline bool DenseBase<Derived>::any() const
+{
+ enum {
+ unroll = SizeAtCompileTime != Dynamic
+ && CoeffReadCost != Dynamic
+ && NumTraits<Scalar>::AddCost != Dynamic
+ && SizeAtCompileTime * (CoeffReadCost + NumTraits<Scalar>::AddCost) <= EIGEN_UNROLLING_LIMIT
+ };
+ if(unroll)
+ return internal::any_unroller<Derived,
+ unroll ? int(SizeAtCompileTime) : Dynamic
+ >::run(derived());
+ else
+ {
+ for(Index j = 0; j < cols(); ++j)
+ for(Index i = 0; i < rows(); ++i)
+ if (coeff(i, j)) return true;
+ return false;
+ }
+}
+
+/** \returns the number of coefficients which evaluate to true
+ *
+ * \sa all(), any()
+ */
+template<typename Derived>
+inline typename DenseBase<Derived>::Index DenseBase<Derived>::count() const
+{
+ return derived().template cast<bool>().template cast<Index>().sum();
+}
+
+} // end namespace Eigen
+
+#endif // EIGEN_ALLANDANY_H
diff --git a/Eigen/src/Core/CMakeLists.txt b/Eigen/src/Core/CMakeLists.txt
new file mode 100644
index 000000000..2346fc2bb
--- /dev/null
+++ b/Eigen/src/Core/CMakeLists.txt
@@ -0,0 +1,10 @@
+FILE(GLOB Eigen_Core_SRCS "*.h")
+
+INSTALL(FILES
+ ${Eigen_Core_SRCS}
+ DESTINATION ${INCLUDE_INSTALL_DIR}/Eigen/src/Core COMPONENT Devel
+ )
+
+ADD_SUBDIRECTORY(products)
+ADD_SUBDIRECTORY(util)
+ADD_SUBDIRECTORY(arch)
diff --git a/Eigen/src/Core/CommaInitializer.h b/Eigen/src/Core/CommaInitializer.h
new file mode 100644
index 000000000..4adce6414
--- /dev/null
+++ b/Eigen/src/Core/CommaInitializer.h
@@ -0,0 +1,139 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra.
+//
+// Copyright (C) 2008 Gael Guennebaud <gael.guennebaud@inria.fr>
+// Copyright (C) 2006-2008 Benoit Jacob <jacob.benoit.1@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 EIGEN_COMMAINITIALIZER_H
+#define EIGEN_COMMAINITIALIZER_H
+
+namespace Eigen {
+
+/** \class CommaInitializer
+ * \ingroup Core_Module
+ *
+ * \brief Helper class used by the comma initializer operator
+ *
+ * This class is internally used to implement the comma initializer feature. It is
+ * 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()
+ */
+template<typename XprType>
+struct CommaInitializer
+{
+ typedef typename XprType::Scalar Scalar;
+ typedef typename XprType::Index Index;
+
+ inline CommaInitializer(XprType& xpr, const Scalar& s)
+ : m_xpr(xpr), m_row(0), m_col(1), m_currentBlockRows(1)
+ {
+ m_xpr.coeffRef(0,0) = s;
+ }
+
+ template<typename OtherDerived>
+ inline CommaInitializer(XprType& xpr, const DenseBase<OtherDerived>& other)
+ : m_xpr(xpr), m_row(0), m_col(other.cols()), m_currentBlockRows(other.rows())
+ {
+ m_xpr.block(0, 0, other.rows(), other.cols()) = other;
+ }
+
+ /* inserts a scalar value in the target matrix */
+ CommaInitializer& operator,(const Scalar& s)
+ {
+ if (m_col==m_xpr.cols())
+ {
+ m_row+=m_currentBlockRows;
+ m_col = 0;
+ m_currentBlockRows = 1;
+ eigen_assert(m_row<m_xpr.rows()
+ && "Too many rows passed to comma initializer (operator<<)");
+ }
+ eigen_assert(m_col<m_xpr.cols()
+ && "Too many coefficients passed to comma initializer (operator<<)");
+ eigen_assert(m_currentBlockRows==1);
+ m_xpr.coeffRef(m_row, m_col++) = s;
+ return *this;
+ }
+
+ /* inserts a matrix expression in the target matrix */
+ template<typename OtherDerived>
+ CommaInitializer& operator,(const DenseBase<OtherDerived>& other)
+ {
+ if (m_col==m_xpr.cols())
+ {
+ m_row+=m_currentBlockRows;
+ m_col = 0;
+ m_currentBlockRows = other.rows();
+ eigen_assert(m_row+m_currentBlockRows<=m_xpr.rows()
+ && "Too many rows passed to comma initializer (operator<<)");
+ }
+ eigen_assert(m_col<m_xpr.cols()
+ && "Too many coefficients passed to comma initializer (operator<<)");
+ eigen_assert(m_currentBlockRows==other.rows());
+ if (OtherDerived::SizeAtCompileTime != Dynamic)
+ m_xpr.template block<OtherDerived::RowsAtCompileTime != Dynamic ? OtherDerived::RowsAtCompileTime : 1,
+ OtherDerived::ColsAtCompileTime != Dynamic ? OtherDerived::ColsAtCompileTime : 1>
+ (m_row, m_col) = other;
+ else
+ m_xpr.block(m_row, m_col, other.rows(), other.cols()) = other;
+ m_col += other.cols();
+ return *this;
+ }
+
+ inline ~CommaInitializer()
+ {
+ eigen_assert((m_row+m_currentBlockRows) == m_xpr.rows()
+ && m_col == m_xpr.cols()
+ && "Too few coefficients passed to comma initializer (operator<<)");
+ }
+
+ /** \returns the built matrix once all its coefficients have been set.
+ * Calling finished is 100% optional. Its purpose is to write expressions
+ * like this:
+ * \code
+ * quaternion.fromRotationMatrix((Matrix3f() << axis0, axis1, axis2).finished());
+ * \endcode
+ */
+ inline XprType& finished() { return m_xpr; }
+
+ XprType& m_xpr; // target expression
+ Index m_row; // current row id
+ Index m_col; // current col id
+ Index m_currentBlockRows; // current block height
+};
+
+/** \anchor MatrixBaseCommaInitRef
+ * Convenient operator to set the coefficients of a matrix.
+ *
+ * The coefficients must be provided in a row major order and exactly match
+ * the size of the matrix. Otherwise an assertion is raised.
+ *
+ * Example: \include MatrixBase_set.cpp
+ * Output: \verbinclude MatrixBase_set.out
+ *
+ * \sa CommaInitializer::finished(), class CommaInitializer
+ */
+template<typename Derived>
+inline CommaInitializer<Derived> DenseBase<Derived>::operator<< (const Scalar& s)
+{
+ return CommaInitializer<Derived>(*static_cast<Derived*>(this), s);
+}
+
+/** \sa operator<<(const Scalar&) */
+template<typename Derived>
+template<typename OtherDerived>
+inline CommaInitializer<Derived>
+DenseBase<Derived>::operator<<(const DenseBase<OtherDerived>& other)
+{
+ return CommaInitializer<Derived>(*static_cast<Derived *>(this), other);
+}
+
+} // end namespace Eigen
+
+#endif // EIGEN_COMMAINITIALIZER_H
diff --git a/Eigen/src/Core/CwiseBinaryOp.h b/Eigen/src/Core/CwiseBinaryOp.h
new file mode 100644
index 000000000..1b93af31b
--- /dev/null
+++ b/Eigen/src/Core/CwiseBinaryOp.h
@@ -0,0 +1,229 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra.
+//
+// Copyright (C) 2008-2009 Gael Guennebaud <gael.guennebaud@inria.fr>
+// Copyright (C) 2006-2008 Benoit Jacob <jacob.benoit.1@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 EIGEN_CWISE_BINARY_OP_H
+#define EIGEN_CWISE_BINARY_OP_H
+
+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<OtherDerived> &,const CustomBinaryOp &) const, class CwiseUnaryOp, class CwiseNullaryOp
+ */
+
+namespace internal {
+template<typename BinaryOp, typename Lhs, typename Rhs>
+struct traits<CwiseBinaryOp<BinaryOp, Lhs, Rhs> >
+{
+ // we must not inherit from traits<Lhs> since it has
+ // the potential to cause problems with MSVC
+ typedef typename remove_all<Lhs>::type Ancestor;
+ typedef typename traits<Ancestor>::XprKind XprKind;
+ enum {
+ RowsAtCompileTime = traits<Ancestor>::RowsAtCompileTime,
+ ColsAtCompileTime = traits<Ancestor>::ColsAtCompileTime,
+ MaxRowsAtCompileTime = traits<Ancestor>::MaxRowsAtCompileTime,
+ MaxColsAtCompileTime = traits<Ancestor>::MaxColsAtCompileTime
+ };
+
+ // even though we require Lhs and Rhs to have the same scalar type (see CwiseBinaryOp constructor),
+ // we still want to handle the case when the result type is different.
+ typedef typename result_of<
+ BinaryOp(
+ typename Lhs::Scalar,
+ typename Rhs::Scalar
+ )
+ >::type Scalar;
+ typedef typename promote_storage_type<typename traits<Lhs>::StorageKind,
+ typename traits<Rhs>::StorageKind>::ret StorageKind;
+ typedef typename promote_index_type<typename traits<Lhs>::Index,
+ typename traits<Rhs>::Index>::type Index;
+ typedef typename Lhs::Nested LhsNested;
+ typedef typename Rhs::Nested RhsNested;
+ typedef typename remove_reference<LhsNested>::type _LhsNested;
+ typedef typename remove_reference<RhsNested>::type _RhsNested;
+ enum {
+ LhsCoeffReadCost = _LhsNested::CoeffReadCost,
+ RhsCoeffReadCost = _RhsNested::CoeffReadCost,
+ LhsFlags = _LhsNested::Flags,
+ RhsFlags = _RhsNested::Flags,
+ SameType = is_same<typename _LhsNested::Scalar,typename _RhsNested::Scalar>::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<BinaryOp>::PacketAccess && StorageOrdersAgree && SameType ? PacketAccessBit : 0)
+ )
+ )
+ ),
+ Flags = (Flags0 & ~RowMajorBit) | (LhsFlags & RowMajorBit),
+ CoeffReadCost = LhsCoeffReadCost + RhsCoeffReadCost + functor_traits<BinaryOp>::Cost
+ };
+};
+} // 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_allows_mixing_real_and_complex<BINOP>::ret \
+ ? int(internal::is_same<typename NumTraits<LHS>::Real, typename NumTraits<RHS>::Real>::value) \
+ : int(internal::is_same<LHS, RHS>::value)), \
+ YOU_MIXED_DIFFERENT_NUMERIC_TYPES__YOU_NEED_TO_USE_THE_CAST_METHOD_OF_MATRIXBASE_TO_CAST_NUMERIC_TYPES_EXPLICITLY)
+
+template<typename BinaryOp, typename Lhs, typename Rhs, typename StorageKind>
+class CwiseBinaryOpImpl;
+
+template<typename BinaryOp, typename Lhs, typename Rhs>
+class CwiseBinaryOp : internal::no_assignment_operator,
+ public CwiseBinaryOpImpl<
+ BinaryOp, Lhs, Rhs,
+ typename internal::promote_storage_type<typename internal::traits<Lhs>::StorageKind,
+ typename internal::traits<Rhs>::StorageKind>::ret>
+{
+ public:
+
+ typedef typename CwiseBinaryOpImpl<
+ BinaryOp, Lhs, Rhs,
+ typename internal::promote_storage_type<typename internal::traits<Lhs>::StorageKind,
+ typename internal::traits<Rhs>::StorageKind>::ret>::Base Base;
+ EIGEN_GENERIC_PUBLIC_INTERFACE(CwiseBinaryOp)
+
+ typedef typename internal::nested<Lhs>::type LhsNested;
+ typedef typename internal::nested<Rhs>::type RhsNested;
+ typedef typename internal::remove_reference<LhsNested>::type _LhsNested;
+ typedef typename internal::remove_reference<RhsNested>::type _RhsNested;
+
+ EIGEN_STRONG_INLINE CwiseBinaryOp(const Lhs& lhs, const Rhs& rhs, const BinaryOp& func = BinaryOp())
+ : m_lhs(lhs), m_rhs(rhs), m_functor(func)
+ {
+ EIGEN_CHECK_BINARY_COMPATIBILIY(BinaryOp,typename Lhs::Scalar,typename Rhs::Scalar);
+ // require the sizes to match
+ EIGEN_STATIC_ASSERT_SAME_MATRIX_SIZE(Lhs, Rhs)
+ eigen_assert(lhs.rows() == rhs.rows() && lhs.cols() == rhs.cols());
+ }
+
+ EIGEN_STRONG_INLINE Index rows() const {
+ // return the fixed size type if available to enable compile time optimizations
+ if (internal::traits<typename internal::remove_all<LhsNested>::type>::RowsAtCompileTime==Dynamic)
+ return m_rhs.rows();
+ else
+ return m_lhs.rows();
+ }
+ EIGEN_STRONG_INLINE Index cols() const {
+ // return the fixed size type if available to enable compile time optimizations
+ if (internal::traits<typename internal::remove_all<LhsNested>::type>::ColsAtCompileTime==Dynamic)
+ return m_rhs.cols();
+ else
+ return m_lhs.cols();
+ }
+
+ /** \returns the left hand side nested expression */
+ const _LhsNested& lhs() const { return m_lhs; }
+ /** \returns the right hand side nested expression */
+ const _RhsNested& rhs() const { return m_rhs; }
+ /** \returns the functor representing the binary operation */
+ const BinaryOp& functor() const { return m_functor; }
+
+ protected:
+ LhsNested m_lhs;
+ RhsNested m_rhs;
+ const BinaryOp m_functor;
+};
+
+template<typename BinaryOp, typename Lhs, typename Rhs>
+class CwiseBinaryOpImpl<BinaryOp, Lhs, Rhs, Dense>
+ : public internal::dense_xpr_base<CwiseBinaryOp<BinaryOp, Lhs, Rhs> >::type
+{
+ typedef CwiseBinaryOp<BinaryOp, Lhs, Rhs> Derived;
+ public:
+
+ typedef typename internal::dense_xpr_base<CwiseBinaryOp<BinaryOp, Lhs, Rhs> >::type Base;
+ EIGEN_DENSE_PUBLIC_INTERFACE( Derived )
+
+ EIGEN_STRONG_INLINE const Scalar coeff(Index row, Index col) const
+ {
+ return derived().functor()(derived().lhs().coeff(row, col),
+ derived().rhs().coeff(row, col));
+ }
+
+ template<int LoadMode>
+ EIGEN_STRONG_INLINE PacketScalar packet(Index row, Index col) const
+ {
+ return derived().functor().packetOp(derived().lhs().template packet<LoadMode>(row, col),
+ derived().rhs().template packet<LoadMode>(row, col));
+ }
+
+ EIGEN_STRONG_INLINE const Scalar coeff(Index index) const
+ {
+ return derived().functor()(derived().lhs().coeff(index),
+ derived().rhs().coeff(index));
+ }
+
+ template<int LoadMode>
+ EIGEN_STRONG_INLINE PacketScalar packet(Index index) const
+ {
+ return derived().functor().packetOp(derived().lhs().template packet<LoadMode>(index),
+ derived().rhs().template packet<LoadMode>(index));
+ }
+};
+
+/** replaces \c *this by \c *this - \a other.
+ *
+ * \returns a reference to \c *this
+ */
+template<typename Derived>
+template<typename OtherDerived>
+EIGEN_STRONG_INLINE Derived &
+MatrixBase<Derived>::operator-=(const MatrixBase<OtherDerived> &other)
+{
+ SelfCwiseBinaryOp<internal::scalar_difference_op<Scalar>, Derived, OtherDerived> tmp(derived());
+ tmp = other.derived();
+ return derived();
+}
+
+/** replaces \c *this by \c *this + \a other.
+ *
+ * \returns a reference to \c *this
+ */
+template<typename Derived>
+template<typename OtherDerived>
+EIGEN_STRONG_INLINE Derived &
+MatrixBase<Derived>::operator+=(const MatrixBase<OtherDerived>& other)
+{
+ SelfCwiseBinaryOp<internal::scalar_sum_op<Scalar>, Derived, OtherDerived> tmp(derived());
+ tmp = other.derived();
+ return derived();
+}
+
+} // end namespace Eigen
+
+#endif // EIGEN_CWISE_BINARY_OP_H
diff --git a/Eigen/src/Core/CwiseNullaryOp.h b/Eigen/src/Core/CwiseNullaryOp.h
new file mode 100644
index 000000000..2635a62b0
--- /dev/null
+++ b/Eigen/src/Core/CwiseNullaryOp.h
@@ -0,0 +1,864 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra.
+//
+// Copyright (C) 2008-2010 Gael Guennebaud <gael.guennebaud@inria.fr>
+//
+// This Source Code Form is subject to the terms of the Mozilla
+// Public License v. 2.0. If a copy of the MPL was not distributed
+// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+#ifndef EIGEN_CWISE_NULLARY_OP_H
+#define EIGEN_CWISE_NULLARY_OP_H
+
+namespace Eigen {
+
+/** \class CwiseNullaryOp
+ * \ingroup Core_Module
+ *
+ * \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
+ *
+ * This class represents an expression of a generic nullary operator.
+ * It is the return type of the Ones(), Zero(), Constant(), Identity() and Random() methods,
+ * and most of the time this is the only way it is used.
+ *
+ * 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()
+ */
+
+namespace internal {
+template<typename NullaryOp, typename PlainObjectType>
+struct traits<CwiseNullaryOp<NullaryOp, PlainObjectType> > : traits<PlainObjectType>
+{
+ enum {
+ Flags = (traits<PlainObjectType>::Flags
+ & ( HereditaryBits
+ | (functor_has_linear_access<NullaryOp>::ret ? LinearAccessBit : 0)
+ | (functor_traits<NullaryOp>::PacketAccess ? PacketAccessBit : 0)))
+ | (functor_traits<NullaryOp>::IsRepeatable ? 0 : EvalBeforeNestingBit),
+ CoeffReadCost = functor_traits<NullaryOp>::Cost
+ };
+};
+}
+
+template<typename NullaryOp, typename PlainObjectType>
+class CwiseNullaryOp : internal::no_assignment_operator,
+ public internal::dense_xpr_base< CwiseNullaryOp<NullaryOp, PlainObjectType> >::type
+{
+ public:
+
+ typedef typename internal::dense_xpr_base<CwiseNullaryOp>::type Base;
+ EIGEN_DENSE_PUBLIC_INTERFACE(CwiseNullaryOp)
+
+ CwiseNullaryOp(Index rows, Index cols, const NullaryOp& func = NullaryOp())
+ : m_rows(rows), m_cols(cols), m_functor(func)
+ {
+ eigen_assert(rows >= 0
+ && (RowsAtCompileTime == Dynamic || RowsAtCompileTime == rows)
+ && cols >= 0
+ && (ColsAtCompileTime == Dynamic || ColsAtCompileTime == cols));
+ }
+
+ EIGEN_STRONG_INLINE Index rows() const { return m_rows.value(); }
+ EIGEN_STRONG_INLINE Index cols() const { return m_cols.value(); }
+
+ EIGEN_STRONG_INLINE const Scalar coeff(Index rows, Index cols) const
+ {
+ return m_functor(rows, cols);
+ }
+
+ template<int LoadMode>
+ EIGEN_STRONG_INLINE PacketScalar packet(Index row, Index col) const
+ {
+ return m_functor.packetOp(row, col);
+ }
+
+ EIGEN_STRONG_INLINE const Scalar coeff(Index index) const
+ {
+ return m_functor(index);
+ }
+
+ template<int LoadMode>
+ EIGEN_STRONG_INLINE PacketScalar packet(Index index) const
+ {
+ return m_functor.packetOp(index);
+ }
+
+ /** \returns the functor representing the nullary operation */
+ const NullaryOp& functor() const { return m_functor; }
+
+ protected:
+ const internal::variable_if_dynamic<Index, RowsAtCompileTime> m_rows;
+ const internal::variable_if_dynamic<Index, ColsAtCompileTime> m_cols;
+ const NullaryOp m_functor;
+};
+
+
+/** \returns an expression of a matrix defined by a custom functor \a func
+ *
+ * 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,
+ * 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.
+ *
+ * \sa class CwiseNullaryOp
+ */
+template<typename Derived>
+template<typename CustomNullaryOp>
+EIGEN_STRONG_INLINE const CwiseNullaryOp<CustomNullaryOp, Derived>
+DenseBase<Derived>::NullaryExpr(Index rows, Index cols, const CustomNullaryOp& func)
+{
+ return CwiseNullaryOp<CustomNullaryOp, Derived>(rows, cols, func);
+}
+
+/** \returns an expression of a matrix defined by a custom functor \a func
+ *
+ * The parameter \a size is the size of the returned vector.
+ * Must be compatible with this MatrixBase type.
+ *
+ * \only_for_vectors
+ *
+ * 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 Zero() should be used
+ * instead.
+ *
+ * The template parameter \a CustomNullaryOp is the type of the functor.
+ *
+ * \sa class CwiseNullaryOp
+ */
+template<typename Derived>
+template<typename CustomNullaryOp>
+EIGEN_STRONG_INLINE const CwiseNullaryOp<CustomNullaryOp, Derived>
+DenseBase<Derived>::NullaryExpr(Index size, const CustomNullaryOp& func)
+{
+ EIGEN_STATIC_ASSERT_VECTOR_ONLY(Derived)
+ if(RowsAtCompileTime == 1) return CwiseNullaryOp<CustomNullaryOp, Derived>(1, size, func);
+ else return CwiseNullaryOp<CustomNullaryOp, Derived>(size, 1, func);
+}
+
+/** \returns an expression of a matrix defined by a custom functor \a func
+ *
+ * This variant is only for fixed-size DenseBase types. For dynamic-size types, you
+ * need to use the variants taking size arguments.
+ *
+ * The template parameter \a CustomNullaryOp is the type of the functor.
+ *
+ * \sa class CwiseNullaryOp
+ */
+template<typename Derived>
+template<typename CustomNullaryOp>
+EIGEN_STRONG_INLINE const CwiseNullaryOp<CustomNullaryOp, Derived>
+DenseBase<Derived>::NullaryExpr(const CustomNullaryOp& func)
+{
+ return CwiseNullaryOp<CustomNullaryOp, Derived>(RowsAtCompileTime, ColsAtCompileTime, func);
+}
+
+/** \returns an expression of a constant matrix of value \a value
+ *
+ * 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 rows and \a cols as arguments, so Zero() should be used
+ * instead.
+ *
+ * The template parameter \a CustomNullaryOp is the type of the functor.
+ *
+ * \sa class CwiseNullaryOp
+ */
+template<typename Derived>
+EIGEN_STRONG_INLINE const typename DenseBase<Derived>::ConstantReturnType
+DenseBase<Derived>::Constant(Index rows, Index cols, const Scalar& value)
+{
+ return DenseBase<Derived>::NullaryExpr(rows, cols, internal::scalar_constant_op<Scalar>(value));
+}
+
+/** \returns an expression of a constant matrix of value \a value
+ *
+ * The parameter \a size is the size of the returned vector.
+ * Must be compatible with this DenseBase type.
+ *
+ * \only_for_vectors
+ *
+ * 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 Zero() should be used
+ * instead.
+ *
+ * The template parameter \a CustomNullaryOp is the type of the functor.
+ *
+ * \sa class CwiseNullaryOp
+ */
+template<typename Derived>
+EIGEN_STRONG_INLINE const typename DenseBase<Derived>::ConstantReturnType
+DenseBase<Derived>::Constant(Index size, const Scalar& value)
+{
+ return DenseBase<Derived>::NullaryExpr(size, internal::scalar_constant_op<Scalar>(value));
+}
+
+/** \returns an expression of a constant matrix of value \a value
+ *
+ * This variant is only for fixed-size DenseBase types. For dynamic-size types, you
+ * need to use the variants taking size arguments.
+ *
+ * The template parameter \a CustomNullaryOp is the type of the functor.
+ *
+ * \sa class CwiseNullaryOp
+ */
+template<typename Derived>
+EIGEN_STRONG_INLINE const typename DenseBase<Derived>::ConstantReturnType
+DenseBase<Derived>::Constant(const Scalar& value)
+{
+ EIGEN_STATIC_ASSERT_FIXED_SIZE(Derived)
+ return DenseBase<Derived>::NullaryExpr(RowsAtCompileTime, ColsAtCompileTime, internal::scalar_constant_op<Scalar>(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
+ *
+ * \sa setLinSpaced(Index,const Scalar&,const Scalar&), LinSpaced(Index,Scalar,Scalar), CwiseNullaryOp
+ */
+template<typename Derived>
+EIGEN_STRONG_INLINE const typename DenseBase<Derived>::SequentialLinSpacedReturnType
+DenseBase<Derived>::LinSpaced(Sequential_t, Index size, const Scalar& low, const Scalar& high)
+{
+ EIGEN_STATIC_ASSERT_VECTOR_ONLY(Derived)
+ return DenseBase<Derived>::NullaryExpr(size, internal::linspaced_op<Scalar,false>(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.
+ */
+template<typename Derived>
+EIGEN_STRONG_INLINE const typename DenseBase<Derived>::SequentialLinSpacedReturnType
+DenseBase<Derived>::LinSpaced(Sequential_t, const Scalar& low, const Scalar& high)
+{
+ EIGEN_STATIC_ASSERT_VECTOR_ONLY(Derived)
+ EIGEN_STATIC_ASSERT_FIXED_SIZE(Derived)
+ return DenseBase<Derived>::NullaryExpr(Derived::SizeAtCompileTime, internal::linspaced_op<Scalar,false>(low,high,Derived::SizeAtCompileTime));
+}
+
+/**
+ * \brief Sets a linearly space vector.
+ *
+ * The function generates 'size' equally spaced values in the closed interval [low,high].
+ * When size is set to 1, a vector of length 1 containing 'high' is returned.
+ *
+ * \only_for_vectors
+ *
+ * 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
+ */
+template<typename Derived>
+EIGEN_STRONG_INLINE const typename DenseBase<Derived>::RandomAccessLinSpacedReturnType
+DenseBase<Derived>::LinSpaced(Index size, const Scalar& low, const Scalar& high)
+{
+ EIGEN_STATIC_ASSERT_VECTOR_ONLY(Derived)
+ return DenseBase<Derived>::NullaryExpr(size, internal::linspaced_op<Scalar,true>(low,high,size));
+}
+
+/**
+ * \copydoc DenseBase::LinSpaced(Index, const Scalar&, const Scalar&)
+ * Special version for fixed size types which does not require the size parameter.
+ */
+template<typename Derived>
+EIGEN_STRONG_INLINE const typename DenseBase<Derived>::RandomAccessLinSpacedReturnType
+DenseBase<Derived>::LinSpaced(const Scalar& low, const Scalar& high)
+{
+ EIGEN_STATIC_ASSERT_VECTOR_ONLY(Derived)
+ EIGEN_STATIC_ASSERT_FIXED_SIZE(Derived)
+ return DenseBase<Derived>::NullaryExpr(Derived::SizeAtCompileTime, internal::linspaced_op<Scalar,true>(low,high,Derived::SizeAtCompileTime));
+}
+
+/** \returns true if all coefficients in this matrix are approximately equal to \a value, to within precision \a prec */
+template<typename Derived>
+bool DenseBase<Derived>::isApproxToConstant
+(const Scalar& value, RealScalar prec) const
+{
+ for(Index j = 0; j < cols(); ++j)
+ for(Index i = 0; i < rows(); ++i)
+ if(!internal::isApprox(this->coeff(i, j), value, prec))
+ return false;
+ return true;
+}
+
+/** This is just an alias for isApproxToConstant().
+ *
+ * \returns true if all coefficients in this matrix are approximately equal to \a value, to within precision \a prec */
+template<typename Derived>
+bool DenseBase<Derived>::isConstant
+(const Scalar& value, RealScalar prec) const
+{
+ return isApproxToConstant(value, prec);
+}
+
+/** Alias for setConstant(): sets all coefficients in this expression to \a value.
+ *
+ * \sa setConstant(), Constant(), class CwiseNullaryOp
+ */
+template<typename Derived>
+EIGEN_STRONG_INLINE void DenseBase<Derived>::fill(const Scalar& value)
+{
+ setConstant(value);
+}
+
+/** Sets all coefficients in this expression to \a value.
+ *
+ * \sa fill(), setConstant(Index,const Scalar&), setConstant(Index,Index,const Scalar&), setZero(), setOnes(), Constant(), class CwiseNullaryOp, setZero(), setOnes()
+ */
+template<typename Derived>
+EIGEN_STRONG_INLINE Derived& DenseBase<Derived>::setConstant(const Scalar& value)
+{
+ return derived() = Constant(rows(), cols(), value);
+}
+
+/** Resizes to the given \a size, and sets all coefficients in this expression to the given \a value.
+ *
+ * \only_for_vectors
+ *
+ * Example: \include Matrix_setConstant_int.cpp
+ * Output: \verbinclude Matrix_setConstant_int.out
+ *
+ * \sa MatrixBase::setConstant(const Scalar&), setConstant(Index,Index,const Scalar&), class CwiseNullaryOp, MatrixBase::Constant(const Scalar&)
+ */
+template<typename Derived>
+EIGEN_STRONG_INLINE Derived&
+PlainObjectBase<Derived>::setConstant(Index size, const Scalar& value)
+{
+ resize(size);
+ return setConstant(value);
+}
+
+/** Resizes to the given size, and sets all coefficients in this expression to the given \a value.
+ *
+ * \param rows the new number of rows
+ * \param cols the new number of columns
+ * \param value the value to which all coefficients are set
+ *
+ * Example: \include Matrix_setConstant_int_int.cpp
+ * Output: \verbinclude Matrix_setConstant_int_int.out
+ *
+ * \sa MatrixBase::setConstant(const Scalar&), setConstant(Index,const Scalar&), class CwiseNullaryOp, MatrixBase::Constant(const Scalar&)
+ */
+template<typename Derived>
+EIGEN_STRONG_INLINE Derived&
+PlainObjectBase<Derived>::setConstant(Index rows, Index cols, const Scalar& value)
+{
+ resize(rows, cols);
+ return setConstant(value);
+}
+
+/**
+ * \brief Sets a linearly space vector.
+ *
+ * The function generates 'size' equally spaced values in the closed interval [low,high].
+ * When size is set to 1, a vector of length 1 containing 'high' is returned.
+ *
+ * \only_for_vectors
+ *
+ * Example: \include DenseBase_setLinSpaced.cpp
+ * Output: \verbinclude DenseBase_setLinSpaced.out
+ *
+ * \sa CwiseNullaryOp
+ */
+template<typename Derived>
+EIGEN_STRONG_INLINE Derived& DenseBase<Derived>::setLinSpaced(Index size, const Scalar& low, const Scalar& high)
+{
+ EIGEN_STATIC_ASSERT_VECTOR_ONLY(Derived)
+ return derived() = Derived::NullaryExpr(size, internal::linspaced_op<Scalar,false>(low,high,size));
+}
+
+/**
+ * \brief Sets a linearly space vector.
+ *
+ * The function fill *this with equally spaced values in the closed interval [low,high].
+ * When size is set to 1, a vector of length 1 containing 'high' is returned.
+ *
+ * \only_for_vectors
+ *
+ * \sa setLinSpaced(Index, const Scalar&, const Scalar&), CwiseNullaryOp
+ */
+template<typename Derived>
+EIGEN_STRONG_INLINE Derived& DenseBase<Derived>::setLinSpaced(const Scalar& low, const Scalar& high)
+{
+ EIGEN_STATIC_ASSERT_VECTOR_ONLY(Derived)
+ return setLinSpaced(size(), low, high);
+}
+
+// zero:
+
+/** \returns an expression of a zero matrix.
+ *
+ * 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,
+ * it is redundant to pass \a rows and \a cols as arguments, so Zero() should be used
+ * instead.
+ *
+ * Example: \include MatrixBase_zero_int_int.cpp
+ * Output: \verbinclude MatrixBase_zero_int_int.out
+ *
+ * \sa Zero(), Zero(Index)
+ */
+template<typename Derived>
+EIGEN_STRONG_INLINE const typename DenseBase<Derived>::ConstantReturnType
+DenseBase<Derived>::Zero(Index rows, Index cols)
+{
+ return Constant(rows, cols, Scalar(0));
+}
+
+/** \returns an expression of a zero vector.
+ *
+ * The parameter \a size is the size of the returned vector.
+ * Must be compatible with this MatrixBase type.
+ *
+ * \only_for_vectors
+ *
+ * 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 Zero() should be used
+ * instead.
+ *
+ * Example: \include MatrixBase_zero_int.cpp
+ * Output: \verbinclude MatrixBase_zero_int.out
+ *
+ * \sa Zero(), Zero(Index,Index)
+ */
+template<typename Derived>
+EIGEN_STRONG_INLINE const typename DenseBase<Derived>::ConstantReturnType
+DenseBase<Derived>::Zero(Index size)
+{
+ return Constant(size, Scalar(0));
+}
+
+/** \returns an expression of a fixed-size zero matrix or vector.
+ *
+ * This variant is only for fixed-size MatrixBase types. For dynamic-size types, you
+ * need to use the variants taking size arguments.
+ *
+ * Example: \include MatrixBase_zero.cpp
+ * Output: \verbinclude MatrixBase_zero.out
+ *
+ * \sa Zero(Index), Zero(Index,Index)
+ */
+template<typename Derived>
+EIGEN_STRONG_INLINE const typename DenseBase<Derived>::ConstantReturnType
+DenseBase<Derived>::Zero()
+{
+ return Constant(Scalar(0));
+}
+
+/** \returns true if *this is approximately equal to the zero matrix,
+ * within the precision given by \a prec.
+ *
+ * Example: \include MatrixBase_isZero.cpp
+ * Output: \verbinclude MatrixBase_isZero.out
+ *
+ * \sa class CwiseNullaryOp, Zero()
+ */
+template<typename Derived>
+bool DenseBase<Derived>::isZero(RealScalar prec) const
+{
+ for(Index j = 0; j < cols(); ++j)
+ for(Index i = 0; i < rows(); ++i)
+ if(!internal::isMuchSmallerThan(this->coeff(i, j), static_cast<Scalar>(1), prec))
+ return false;
+ return true;
+}
+
+/** Sets all coefficients in this expression to zero.
+ *
+ * Example: \include MatrixBase_setZero.cpp
+ * Output: \verbinclude MatrixBase_setZero.out
+ *
+ * \sa class CwiseNullaryOp, Zero()
+ */
+template<typename Derived>
+EIGEN_STRONG_INLINE Derived& DenseBase<Derived>::setZero()
+{
+ return setConstant(Scalar(0));
+}
+
+/** Resizes to the given \a size, and sets all coefficients in this expression to zero.
+ *
+ * \only_for_vectors
+ *
+ * Example: \include Matrix_setZero_int.cpp
+ * Output: \verbinclude Matrix_setZero_int.out
+ *
+ * \sa DenseBase::setZero(), setZero(Index,Index), class CwiseNullaryOp, DenseBase::Zero()
+ */
+template<typename Derived>
+EIGEN_STRONG_INLINE Derived&
+PlainObjectBase<Derived>::setZero(Index size)
+{
+ resize(size);
+ return setConstant(Scalar(0));
+}
+
+/** Resizes to the given size, and sets all coefficients in this expression to zero.
+ *
+ * \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
+ *
+ * \sa DenseBase::setZero(), setZero(Index), class CwiseNullaryOp, DenseBase::Zero()
+ */
+template<typename Derived>
+EIGEN_STRONG_INLINE Derived&
+PlainObjectBase<Derived>::setZero(Index rows, Index cols)
+{
+ resize(rows, cols);
+ return setConstant(Scalar(0));
+}
+
+// ones:
+
+/** \returns an expression of a matrix where all coefficients equal one.
+ *
+ * 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,
+ * it is redundant to pass \a rows and \a cols as arguments, so Ones() should be used
+ * instead.
+ *
+ * Example: \include MatrixBase_ones_int_int.cpp
+ * Output: \verbinclude MatrixBase_ones_int_int.out
+ *
+ * \sa Ones(), Ones(Index), isOnes(), class Ones
+ */
+template<typename Derived>
+EIGEN_STRONG_INLINE const typename DenseBase<Derived>::ConstantReturnType
+DenseBase<Derived>::Ones(Index rows, Index cols)
+{
+ return Constant(rows, cols, Scalar(1));
+}
+
+/** \returns an expression of a vector where all coefficients equal one.
+ *
+ * The parameter \a size is the size of the returned vector.
+ * Must be compatible with this MatrixBase type.
+ *
+ * \only_for_vectors
+ *
+ * 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 Ones() should be used
+ * instead.
+ *
+ * Example: \include MatrixBase_ones_int.cpp
+ * Output: \verbinclude MatrixBase_ones_int.out
+ *
+ * \sa Ones(), Ones(Index,Index), isOnes(), class Ones
+ */
+template<typename Derived>
+EIGEN_STRONG_INLINE const typename DenseBase<Derived>::ConstantReturnType
+DenseBase<Derived>::Ones(Index size)
+{
+ return Constant(size, Scalar(1));
+}
+
+/** \returns an expression of a fixed-size matrix or vector where all coefficients equal one.
+ *
+ * This variant is only for fixed-size MatrixBase types. For dynamic-size types, you
+ * need to use the variants taking size arguments.
+ *
+ * Example: \include MatrixBase_ones.cpp
+ * Output: \verbinclude MatrixBase_ones.out
+ *
+ * \sa Ones(Index), Ones(Index,Index), isOnes(), class Ones
+ */
+template<typename Derived>
+EIGEN_STRONG_INLINE const typename DenseBase<Derived>::ConstantReturnType
+DenseBase<Derived>::Ones()
+{
+ return Constant(Scalar(1));
+}
+
+/** \returns true if *this is approximately equal to the matrix where all coefficients
+ * are equal to 1, within the precision given by \a prec.
+ *
+ * Example: \include MatrixBase_isOnes.cpp
+ * Output: \verbinclude MatrixBase_isOnes.out
+ *
+ * \sa class CwiseNullaryOp, Ones()
+ */
+template<typename Derived>
+bool DenseBase<Derived>::isOnes
+(RealScalar prec) const
+{
+ return isApproxToConstant(Scalar(1), prec);
+}
+
+/** Sets all coefficients in this expression to one.
+ *
+ * Example: \include MatrixBase_setOnes.cpp
+ * Output: \verbinclude MatrixBase_setOnes.out
+ *
+ * \sa class CwiseNullaryOp, Ones()
+ */
+template<typename Derived>
+EIGEN_STRONG_INLINE Derived& DenseBase<Derived>::setOnes()
+{
+ return setConstant(Scalar(1));
+}
+
+/** Resizes to the given \a size, and sets all coefficients in this expression to one.
+ *
+ * \only_for_vectors
+ *
+ * Example: \include Matrix_setOnes_int.cpp
+ * Output: \verbinclude Matrix_setOnes_int.out
+ *
+ * \sa MatrixBase::setOnes(), setOnes(Index,Index), class CwiseNullaryOp, MatrixBase::Ones()
+ */
+template<typename Derived>
+EIGEN_STRONG_INLINE Derived&
+PlainObjectBase<Derived>::setOnes(Index size)
+{
+ resize(size);
+ return setConstant(Scalar(1));
+}
+
+/** Resizes to the given size, and sets all coefficients in this expression to one.
+ *
+ * \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
+ *
+ * \sa MatrixBase::setOnes(), setOnes(Index), class CwiseNullaryOp, MatrixBase::Ones()
+ */
+template<typename Derived>
+EIGEN_STRONG_INLINE Derived&
+PlainObjectBase<Derived>::setOnes(Index rows, Index cols)
+{
+ resize(rows, cols);
+ return setConstant(Scalar(1));
+}
+
+// Identity:
+
+/** \returns an expression of the identity matrix (not necessarily square).
+ *
+ * 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,
+ * it is redundant to pass \a rows and \a cols as arguments, so Identity() should be used
+ * instead.
+ *
+ * Example: \include MatrixBase_identity_int_int.cpp
+ * Output: \verbinclude MatrixBase_identity_int_int.out
+ *
+ * \sa Identity(), setIdentity(), isIdentity()
+ */
+template<typename Derived>
+EIGEN_STRONG_INLINE const typename MatrixBase<Derived>::IdentityReturnType
+MatrixBase<Derived>::Identity(Index rows, Index cols)
+{
+ return DenseBase<Derived>::NullaryExpr(rows, cols, internal::scalar_identity_op<Scalar>());
+}
+
+/** \returns an expression of the identity matrix (not necessarily square).
+ *
+ * This variant is only for fixed-size MatrixBase types. For dynamic-size types, you
+ * need to use the variant taking size arguments.
+ *
+ * Example: \include MatrixBase_identity.cpp
+ * Output: \verbinclude MatrixBase_identity.out
+ *
+ * \sa Identity(Index,Index), setIdentity(), isIdentity()
+ */
+template<typename Derived>
+EIGEN_STRONG_INLINE const typename MatrixBase<Derived>::IdentityReturnType
+MatrixBase<Derived>::Identity()
+{
+ EIGEN_STATIC_ASSERT_FIXED_SIZE(Derived)
+ return MatrixBase<Derived>::NullaryExpr(RowsAtCompileTime, ColsAtCompileTime, internal::scalar_identity_op<Scalar>());
+}
+
+/** \returns true if *this is approximately equal to the identity matrix
+ * (not necessarily square),
+ * within the precision given by \a prec.
+ *
+ * Example: \include MatrixBase_isIdentity.cpp
+ * Output: \verbinclude MatrixBase_isIdentity.out
+ *
+ * \sa class CwiseNullaryOp, Identity(), Identity(Index,Index), setIdentity()
+ */
+template<typename Derived>
+bool MatrixBase<Derived>::isIdentity
+(RealScalar prec) const
+{
+ 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<Scalar>(1), prec))
+ return false;
+ }
+ else
+ {
+ if(!internal::isMuchSmallerThan(this->coeff(i, j), static_cast<RealScalar>(1), prec))
+ return false;
+ }
+ }
+ }
+ return true;
+}
+
+namespace internal {
+
+template<typename Derived, bool Big = (Derived::SizeAtCompileTime>=16)>
+struct setIdentity_impl
+{
+ static EIGEN_STRONG_INLINE Derived& run(Derived& m)
+ {
+ return m = Derived::Identity(m.rows(), m.cols());
+ }
+};
+
+template<typename Derived>
+struct setIdentity_impl<Derived, true>
+{
+ typedef typename Derived::Index Index;
+ static EIGEN_STRONG_INLINE Derived& run(Derived& m)
+ {
+ m.setZero();
+ const Index size = (std::min)(m.rows(), m.cols());
+ for(Index i = 0; i < size; ++i) m.coeffRef(i,i) = typename Derived::Scalar(1);
+ return m;
+ }
+};
+
+} // end namespace internal
+
+/** Writes the identity expression (not necessarily square) into *this.
+ *
+ * Example: \include MatrixBase_setIdentity.cpp
+ * Output: \verbinclude MatrixBase_setIdentity.out
+ *
+ * \sa class CwiseNullaryOp, Identity(), Identity(Index,Index), isIdentity()
+ */
+template<typename Derived>
+EIGEN_STRONG_INLINE Derived& MatrixBase<Derived>::setIdentity()
+{
+ return internal::setIdentity_impl<Derived>::run(derived());
+}
+
+/** \brief Resizes to the given size, and writes the identity expression (not necessarily square) into *this.
+ *
+ * \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
+ *
+ * \sa MatrixBase::setIdentity(), class CwiseNullaryOp, MatrixBase::Identity()
+ */
+template<typename Derived>
+EIGEN_STRONG_INLINE Derived& MatrixBase<Derived>::setIdentity(Index rows, Index cols)
+{
+ derived().resize(rows, cols);
+ return setIdentity();
+}
+
+/** \returns an expression of the i-th unit (basis) vector.
+ *
+ * \only_for_vectors
+ *
+ * \sa MatrixBase::Unit(Index), MatrixBase::UnitX(), MatrixBase::UnitY(), MatrixBase::UnitZ(), MatrixBase::UnitW()
+ */
+template<typename Derived>
+EIGEN_STRONG_INLINE const typename MatrixBase<Derived>::BasisReturnType MatrixBase<Derived>::Unit(Index size, Index i)
+{
+ EIGEN_STATIC_ASSERT_VECTOR_ONLY(Derived)
+ return BasisReturnType(SquareMatrixType::Identity(size,size), i);
+}
+
+/** \returns an expression of the i-th unit (basis) vector.
+ *
+ * \only_for_vectors
+ *
+ * This variant is for fixed-size vector only.
+ *
+ * \sa MatrixBase::Unit(Index,Index), MatrixBase::UnitX(), MatrixBase::UnitY(), MatrixBase::UnitZ(), MatrixBase::UnitW()
+ */
+template<typename Derived>
+EIGEN_STRONG_INLINE const typename MatrixBase<Derived>::BasisReturnType MatrixBase<Derived>::Unit(Index i)
+{
+ EIGEN_STATIC_ASSERT_VECTOR_ONLY(Derived)
+ return BasisReturnType(SquareMatrixType::Identity(),i);
+}
+
+/** \returns an expression of the X axis unit vector (1{,0}^*)
+ *
+ * \only_for_vectors
+ *
+ * \sa MatrixBase::Unit(Index,Index), MatrixBase::Unit(Index), MatrixBase::UnitY(), MatrixBase::UnitZ(), MatrixBase::UnitW()
+ */
+template<typename Derived>
+EIGEN_STRONG_INLINE const typename MatrixBase<Derived>::BasisReturnType MatrixBase<Derived>::UnitX()
+{ return Derived::Unit(0); }
+
+/** \returns an expression of the Y axis unit vector (0,1{,0}^*)
+ *
+ * \only_for_vectors
+ *
+ * \sa MatrixBase::Unit(Index,Index), MatrixBase::Unit(Index), MatrixBase::UnitY(), MatrixBase::UnitZ(), MatrixBase::UnitW()
+ */
+template<typename Derived>
+EIGEN_STRONG_INLINE const typename MatrixBase<Derived>::BasisReturnType MatrixBase<Derived>::UnitY()
+{ return Derived::Unit(1); }
+
+/** \returns an expression of the Z axis unit vector (0,0,1{,0}^*)
+ *
+ * \only_for_vectors
+ *
+ * \sa MatrixBase::Unit(Index,Index), MatrixBase::Unit(Index), MatrixBase::UnitY(), MatrixBase::UnitZ(), MatrixBase::UnitW()
+ */
+template<typename Derived>
+EIGEN_STRONG_INLINE const typename MatrixBase<Derived>::BasisReturnType MatrixBase<Derived>::UnitZ()
+{ return Derived::Unit(2); }
+
+/** \returns an expression of the W axis unit vector (0,0,0,1)
+ *
+ * \only_for_vectors
+ *
+ * \sa MatrixBase::Unit(Index,Index), MatrixBase::Unit(Index), MatrixBase::UnitY(), MatrixBase::UnitZ(), MatrixBase::UnitW()
+ */
+template<typename Derived>
+EIGEN_STRONG_INLINE const typename MatrixBase<Derived>::BasisReturnType MatrixBase<Derived>::UnitW()
+{ return Derived::Unit(3); }
+
+} // end namespace Eigen
+
+#endif // EIGEN_CWISE_NULLARY_OP_H
diff --git a/Eigen/src/Core/CwiseUnaryOp.h b/Eigen/src/Core/CwiseUnaryOp.h
new file mode 100644
index 000000000..063355ae5
--- /dev/null
+++ b/Eigen/src/Core/CwiseUnaryOp.h
@@ -0,0 +1,126 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra.
+//
+// Copyright (C) 2008-2010 Gael Guennebaud <gael.guennebaud@inria.fr>
+// Copyright (C) 2006-2008 Benoit Jacob <jacob.benoit.1@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 EIGEN_CWISE_UNARY_OP_H
+#define EIGEN_CWISE_UNARY_OP_H
+
+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<typename UnaryOp, typename XprType>
+struct traits<CwiseUnaryOp<UnaryOp, XprType> >
+ : traits<XprType>
+{
+ typedef typename result_of<
+ UnaryOp(typename XprType::Scalar)
+ >::type Scalar;
+ typedef typename XprType::Nested XprTypeNested;
+ typedef typename remove_reference<XprTypeNested>::type _XprTypeNested;
+ enum {
+ Flags = _XprTypeNested::Flags & (
+ HereditaryBits | LinearAccessBit | AlignedBit
+ | (functor_traits<UnaryOp>::PacketAccess ? PacketAccessBit : 0)),
+ CoeffReadCost = _XprTypeNested::CoeffReadCost + functor_traits<UnaryOp>::Cost
+ };
+};
+}
+
+template<typename UnaryOp, typename XprType, typename StorageKind>
+class CwiseUnaryOpImpl;
+
+template<typename UnaryOp, typename XprType>
+class CwiseUnaryOp : internal::no_assignment_operator,
+ public CwiseUnaryOpImpl<UnaryOp, XprType, typename internal::traits<XprType>::StorageKind>
+{
+ public:
+
+ typedef typename CwiseUnaryOpImpl<UnaryOp, XprType,typename internal::traits<XprType>::StorageKind>::Base Base;
+ EIGEN_GENERIC_PUBLIC_INTERFACE(CwiseUnaryOp)
+
+ inline 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(); }
+
+ /** \returns the functor representing the unary operation */
+ const UnaryOp& functor() const { return m_functor; }
+
+ /** \returns the nested expression */
+ const typename internal::remove_all<typename XprType::Nested>::type&
+ nestedExpression() const { return m_xpr; }
+
+ /** \returns the nested expression */
+ typename internal::remove_all<typename XprType::Nested>::type&
+ nestedExpression() { return m_xpr.const_cast_derived(); }
+
+ protected:
+ typename XprType::Nested 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<typename UnaryOp, typename XprType>
+class CwiseUnaryOpImpl<UnaryOp,XprType,Dense>
+ : public internal::dense_xpr_base<CwiseUnaryOp<UnaryOp, XprType> >::type
+{
+ public:
+
+ typedef CwiseUnaryOp<UnaryOp, XprType> Derived;
+ typedef typename internal::dense_xpr_base<CwiseUnaryOp<UnaryOp, XprType> >::type Base;
+ EIGEN_DENSE_PUBLIC_INTERFACE(Derived)
+
+ EIGEN_STRONG_INLINE const Scalar coeff(Index row, Index col) const
+ {
+ return derived().functor()(derived().nestedExpression().coeff(row, col));
+ }
+
+ template<int LoadMode>
+ EIGEN_STRONG_INLINE PacketScalar packet(Index row, Index col) const
+ {
+ return derived().functor().packetOp(derived().nestedExpression().template packet<LoadMode>(row, col));
+ }
+
+ EIGEN_STRONG_INLINE const Scalar coeff(Index index) const
+ {
+ return derived().functor()(derived().nestedExpression().coeff(index));
+ }
+
+ template<int LoadMode>
+ EIGEN_STRONG_INLINE PacketScalar packet(Index index) const
+ {
+ return derived().functor().packetOp(derived().nestedExpression().template packet<LoadMode>(index));
+ }
+};
+
+} // end namespace Eigen
+
+#endif // EIGEN_CWISE_UNARY_OP_H
diff --git a/Eigen/src/Core/CwiseUnaryView.h b/Eigen/src/Core/CwiseUnaryView.h
new file mode 100644
index 000000000..66f73a950
--- /dev/null
+++ b/Eigen/src/Core/CwiseUnaryView.h
@@ -0,0 +1,135 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra.
+//
+// Copyright (C) 2009-2010 Gael Guennebaud <gael.guennebaud@inria.fr>
+//
+// This Source Code Form is subject to the terms of the Mozilla
+// Public License v. 2.0. If a copy of the MPL was not distributed
+// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+#ifndef EIGEN_CWISE_UNARY_VIEW_H
+#define EIGEN_CWISE_UNARY_VIEW_H
+
+namespace Eigen {
+
+/** \class CwiseUnaryView
+ * \ingroup Core_Module
+ *
+ * \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<typename ViewOp, typename MatrixType>
+struct traits<CwiseUnaryView<ViewOp, MatrixType> >
+ : traits<MatrixType>
+{
+ typedef typename result_of<
+ ViewOp(typename traits<MatrixType>::Scalar)
+ >::type Scalar;
+ typedef typename MatrixType::Nested MatrixTypeNested;
+ typedef typename remove_all<MatrixTypeNested>::type _MatrixTypeNested;
+ enum {
+ Flags = (traits<_MatrixTypeNested>::Flags & (HereditaryBits | LvalueBit | LinearAccessBit | DirectAccessBit)),
+ CoeffReadCost = traits<_MatrixTypeNested>::CoeffReadCost + functor_traits<ViewOp>::Cost,
+ MatrixTypeInnerStride = inner_stride_at_compile_time<MatrixType>::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
+ InnerStrideAtCompileTime = MatrixTypeInnerStride == Dynamic
+ ? int(Dynamic)
+ : int(MatrixTypeInnerStride)
+ * int(sizeof(typename traits<MatrixType>::Scalar) / sizeof(Scalar)),
+ OuterStrideAtCompileTime = outer_stride_at_compile_time<MatrixType>::ret
+ };
+};
+}
+
+template<typename ViewOp, typename MatrixType, typename StorageKind>
+class CwiseUnaryViewImpl;
+
+template<typename ViewOp, typename MatrixType>
+class CwiseUnaryView : internal::no_assignment_operator,
+ public CwiseUnaryViewImpl<ViewOp, MatrixType, typename internal::traits<MatrixType>::StorageKind>
+{
+ public:
+
+ typedef typename CwiseUnaryViewImpl<ViewOp, MatrixType,typename internal::traits<MatrixType>::StorageKind>::Base Base;
+ EIGEN_GENERIC_PUBLIC_INTERFACE(CwiseUnaryView)
+
+ inline CwiseUnaryView(const MatrixType& mat, const ViewOp& func = ViewOp())
+ : m_matrix(mat), m_functor(func) {}
+
+ EIGEN_INHERIT_ASSIGNMENT_OPERATORS(CwiseUnaryView)
+
+ EIGEN_STRONG_INLINE Index rows() const { return m_matrix.rows(); }
+ EIGEN_STRONG_INLINE Index cols() const { return m_matrix.cols(); }
+
+ /** \returns the functor representing unary operation */
+ const ViewOp& functor() const { return m_functor; }
+
+ /** \returns the nested expression */
+ const typename internal::remove_all<typename MatrixType::Nested>::type&
+ nestedExpression() const { return m_matrix; }
+
+ /** \returns the nested expression */
+ typename internal::remove_all<typename MatrixType::Nested>::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<MatrixType>::type m_matrix;
+ ViewOp m_functor;
+};
+
+template<typename ViewOp, typename MatrixType>
+class CwiseUnaryViewImpl<ViewOp,MatrixType,Dense>
+ : public internal::dense_xpr_base< CwiseUnaryView<ViewOp, MatrixType> >::type
+{
+ public:
+
+ typedef CwiseUnaryView<ViewOp, MatrixType> Derived;
+ typedef typename internal::dense_xpr_base< CwiseUnaryView<ViewOp, MatrixType> >::type Base;
+
+ EIGEN_DENSE_PUBLIC_INTERFACE(Derived)
+
+ inline Index innerStride() const
+ {
+ return derived().nestedExpression().innerStride() * sizeof(typename internal::traits<MatrixType>::Scalar) / sizeof(Scalar);
+ }
+
+ inline Index outerStride() const
+ {
+ return derived().nestedExpression().outerStride();
+ }
+
+ 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
+
+#endif // EIGEN_CWISE_UNARY_VIEW_H
diff --git a/Eigen/src/Core/DenseBase.h b/Eigen/src/Core/DenseBase.h
new file mode 100644
index 000000000..1cc0314ef
--- /dev/null
+++ b/Eigen/src/Core/DenseBase.h
@@ -0,0 +1,533 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra.
+//
+// Copyright (C) 2007-2010 Benoit Jacob <jacob.benoit.1@gmail.com>
+// Copyright (C) 2008-2010 Gael Guennebaud <gael.guennebaud@inria.fr>
+//
+// This Source Code Form is subject to the terms of the Mozilla
+// Public License v. 2.0. If a copy of the MPL was not distributed
+// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+#ifndef EIGEN_DENSEBASE_H
+#define EIGEN_DENSEBASE_H
+
+namespace Eigen {
+
+/** \class DenseBase
+ * \ingroup Core_Module
+ *
+ * \brief Base class for all dense matrices, vectors, and arrays
+ *
+ * This class is the base that is inherited by all dense objects (matrix, vector, arrays,
+ * and related expression types). The common Eigen API for dense objects is contained in this class.
+ *
+ * \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.
+ *
+ * \sa \ref TopicClassHierarchy
+ */
+template<typename Derived> class DenseBase
+#ifndef EIGEN_PARSED_BY_DOXYGEN
+ : public internal::special_scalar_op_base<Derived,typename internal::traits<Derived>::Scalar,
+ typename NumTraits<typename internal::traits<Derived>::Scalar>::Real>
+#else
+ : public DenseCoeffsBase<Derived>
+#endif // not EIGEN_PARSED_BY_DOXYGEN
+{
+ public:
+ using internal::special_scalar_op_base<Derived,typename internal::traits<Derived>::Scalar,
+ typename NumTraits<typename internal::traits<Derived>::Scalar>::Real>::operator*;
+
+ class InnerIterator;
+
+ typedef typename internal::traits<Derived>::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<Derived>::Index Index;
+
+ typedef typename internal::traits<Derived>::Scalar Scalar;
+ typedef typename internal::packet_traits<Scalar>::type PacketScalar;
+ typedef typename NumTraits<Scalar>::Real RealScalar;
+
+ typedef DenseCoeffsBase<Derived> Base;
+ using Base::derived;
+ using Base::const_cast_derived;
+ using Base::rows;
+ using Base::cols;
+ using Base::size;
+ using Base::rowIndexByOuterInner;
+ 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;
+ using Base::y;
+ using Base::z;
+ using Base::w;
+ using Base::stride;
+ using Base::innerStride;
+ using Base::outerStride;
+ using Base::rowStride;
+ using Base::colStride;
+ typedef typename Base::CoeffReturnType CoeffReturnType;
+
+ enum {
+
+ RowsAtCompileTime = internal::traits<Derived>::RowsAtCompileTime,
+ /**< The number of rows at compile-time. This is just a copy of the value provided
+ * by the \a Derived type. If a value is not known at compile-time,
+ * it is set to the \a Dynamic constant.
+ * \sa MatrixBase::rows(), MatrixBase::cols(), ColsAtCompileTime, SizeAtCompileTime */
+
+ ColsAtCompileTime = internal::traits<Derived>::ColsAtCompileTime,
+ /**< The number of columns at compile-time. This is just a copy of the value provided
+ * by the \a Derived type. If a value is not known at compile-time,
+ * it is set to the \a Dynamic constant.
+ * \sa MatrixBase::rows(), MatrixBase::cols(), RowsAtCompileTime, SizeAtCompileTime */
+
+
+ SizeAtCompileTime = (internal::size_at_compile_time<internal::traits<Derived>::RowsAtCompileTime,
+ internal::traits<Derived>::ColsAtCompileTime>::ret),
+ /**< This is equal to the number of coefficients, i.e. the number of
+ * rows times the number of columns, or to \a Dynamic if this is not
+ * known at compile-time. \sa RowsAtCompileTime, ColsAtCompileTime */
+
+ MaxRowsAtCompileTime = internal::traits<Derived>::MaxRowsAtCompileTime,
+ /**< This value is equal to the maximum possible number of rows that this expression
+ * might have. If this expression might have an arbitrarily high number of rows,
+ * this value is set to \a Dynamic.
+ *
+ * This value is useful to know when evaluating an expression, in order to determine
+ * whether it is possible to avoid doing a dynamic memory allocation.
+ *
+ * \sa RowsAtCompileTime, MaxColsAtCompileTime, MaxSizeAtCompileTime
+ */
+
+ MaxColsAtCompileTime = internal::traits<Derived>::MaxColsAtCompileTime,
+ /**< This value is equal to the maximum possible number of columns that this expression
+ * might have. If this expression might have an arbitrarily high number of columns,
+ * this value is set to \a Dynamic.
+ *
+ * This value is useful to know when evaluating an expression, in order to determine
+ * whether it is possible to avoid doing a dynamic memory allocation.
+ *
+ * \sa ColsAtCompileTime, MaxRowsAtCompileTime, MaxSizeAtCompileTime
+ */
+
+ MaxSizeAtCompileTime = (internal::size_at_compile_time<internal::traits<Derived>::MaxRowsAtCompileTime,
+ internal::traits<Derived>::MaxColsAtCompileTime>::ret),
+ /**< This value is equal to the maximum possible number of coefficients that this expression
+ * might have. If this expression might have an arbitrarily high number of coefficients,
+ * this value is set to \a Dynamic.
+ *
+ * This value is useful to know when evaluating an expression, in order to determine
+ * whether it is possible to avoid doing a dynamic memory allocation.
+ *
+ * \sa SizeAtCompileTime, MaxRowsAtCompileTime, MaxColsAtCompileTime
+ */
+
+ IsVectorAtCompileTime = internal::traits<Derived>::MaxRowsAtCompileTime == 1
+ || internal::traits<Derived>::MaxColsAtCompileTime == 1,
+ /**< This is set to true if either the number of rows or the number of
+ * columns is known at compile-time to be equal to 1. Indeed, in that case,
+ * we are dealing with a column-vector (if there is only one column) or with
+ * a row-vector (if there is only one row). */
+
+ Flags = internal::traits<Derived>::Flags,
+ /**< This stores expression \ref flags flags which may or may not be inherited by new expressions
+ * constructed from this one. See the \ref flags "list of flags".
+ */
+
+ IsRowMajor = int(Flags) & RowMajorBit, /**< True if this expression has row-major storage order. */
+
+ InnerSizeAtCompileTime = int(IsVectorAtCompileTime) ? int(SizeAtCompileTime)
+ : int(IsRowMajor) ? int(ColsAtCompileTime) : int(RowsAtCompileTime),
+
+ CoeffReadCost = internal::traits<Derived>::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<Derived>::ret,
+ OuterStrideAtCompileTime = internal::outer_stride_at_compile_time<Derived>::ret
+ };
+
+ enum { ThisConstantIsPrivateInPlainObjectBase };
+
+ /** \returns the number of nonzero coefficients which is in practice the number
+ * of stored coefficients. */
+ inline Index nonZeros() const { return size(); }
+ /** \returns true if either the number of rows or the number of columns is equal to 1.
+ * In other words, this function returns
+ * \code rows()==1 || cols()==1 \endcode
+ * \sa rows(), cols(), IsVectorAtCompileTime. */
+
+ /** \returns the outer size.
+ *
+ * \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. */
+ Index outerSize() const
+ {
+ return IsVectorAtCompileTime ? 1
+ : int(IsRowMajor) ? this->rows() : this->cols();
+ }
+
+ /** \returns the inner size.
+ *
+ * \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. */
+ Index innerSize() const
+ {
+ return IsVectorAtCompileTime ? this->size()
+ : int(IsRowMajor) ? this->cols() : this->rows();
+ }
+
+ /** Only plain matrices/arrays, not expressions, may be resized; therefore the only useful resize methods are
+ * 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 size)
+ {
+ EIGEN_ONLY_USED_FOR_DEBUG(size);
+ eigen_assert(size == this->size()
+ && "DenseBase::resize() does not actually allow to resize.");
+ }
+ /** Only plain matrices/arrays, not expressions, may be resized; therefore the only useful resize methods are
+ * 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 rows, Index 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<internal::scalar_constant_op<Scalar>,Derived> ConstantReturnType;
+ /** \internal Represents a vector with linearly spaced coefficients that allows sequential access only. */
+ typedef CwiseNullaryOp<internal::linspaced_op<Scalar,false>,Derived> SequentialLinSpacedReturnType;
+ /** \internal Represents a vector with linearly spaced coefficients that allows random access. */
+ typedef CwiseNullaryOp<internal::linspaced_op<Scalar,true>,Derived> RandomAccessLinSpacedReturnType;
+ /** \internal the return type of MatrixBase::eigenvalues() */
+ typedef Matrix<typename NumTraits<typename internal::traits<Derived>::Scalar>::Real, internal::traits<Derived>::ColsAtCompileTime, 1> EigenvaluesReturnType;
+
+#endif // not EIGEN_PARSED_BY_DOXYGEN
+
+ /** Copies \a other into *this. \returns a reference to *this. */
+ template<typename OtherDerived>
+ Derived& operator=(const DenseBase<OtherDerived>& other);
+
+ /** Special case of the template operator=, in order to prevent the compiler
+ * from generating a default operator= (issue hit with g++ 4.1)
+ */
+ Derived& operator=(const DenseBase& other);
+
+ template<typename OtherDerived>
+ Derived& operator=(const EigenBase<OtherDerived> &other);
+
+ template<typename OtherDerived>
+ Derived& operator+=(const EigenBase<OtherDerived> &other);
+
+ template<typename OtherDerived>
+ Derived& operator-=(const EigenBase<OtherDerived> &other);
+
+ template<typename OtherDerived>
+ Derived& operator=(const ReturnByValue<OtherDerived>& func);
+
+#ifndef EIGEN_PARSED_BY_DOXYGEN
+ /** Copies \a other into *this without evaluating other. \returns a reference to *this. */
+ template<typename OtherDerived>
+ Derived& lazyAssign(const DenseBase<OtherDerived>& other);
+#endif // not EIGEN_PARSED_BY_DOXYGEN
+
+ CommaInitializer<Derived> operator<< (const Scalar& s);
+
+ template<unsigned int Added,unsigned int Removed>
+ const Flagged<Derived, Added, Removed> flagged() const;
+
+ template<typename OtherDerived>
+ CommaInitializer<Derived> operator<< (const DenseBase<OtherDerived>& other);
+
+ Eigen::Transpose<Derived> transpose();
+ typedef const Transpose<const Derived> ConstTransposeReturnType;
+ ConstTransposeReturnType transpose() const;
+ void transposeInPlace();
+#ifndef EIGEN_NO_DEBUG
+ protected:
+ template<typename OtherDerived>
+ void checkTransposeAliasing(const OtherDerived& other) const;
+ public:
+#endif
+
+ typedef VectorBlock<Derived> SegmentReturnType;
+ typedef const VectorBlock<const Derived> ConstSegmentReturnType;
+ template<int Size> struct FixedSegmentReturnType { typedef VectorBlock<Derived, Size> Type; };
+ template<int Size> struct ConstFixedSegmentReturnType { typedef const VectorBlock<const Derived, Size> Type; };
+
+ // Note: The "DenseBase::" prefixes are added to help MSVC9 to match these declarations with the later implementations.
+ SegmentReturnType segment(Index start, Index size);
+ typename DenseBase::ConstSegmentReturnType segment(Index start, Index size) const;
+
+ SegmentReturnType head(Index size);
+ typename DenseBase::ConstSegmentReturnType head(Index size) const;
+
+ SegmentReturnType tail(Index size);
+ typename DenseBase::ConstSegmentReturnType tail(Index size) const;
+
+ template<int Size> typename FixedSegmentReturnType<Size>::Type head();
+ template<int Size> typename ConstFixedSegmentReturnType<Size>::Type head() const;
+
+ template<int Size> typename FixedSegmentReturnType<Size>::Type tail();
+ template<int Size> typename ConstFixedSegmentReturnType<Size>::Type tail() const;
+
+ template<int Size> typename FixedSegmentReturnType<Size>::Type segment(Index start);
+ template<int Size> typename ConstFixedSegmentReturnType<Size>::Type segment(Index start) const;
+
+ static const ConstantReturnType
+ Constant(Index rows, Index cols, const Scalar& value);
+ static const ConstantReturnType
+ Constant(Index size, const Scalar& value);
+ static const ConstantReturnType
+ Constant(const Scalar& value);
+
+ static const SequentialLinSpacedReturnType
+ LinSpaced(Sequential_t, Index size, const Scalar& low, const Scalar& high);
+ static const RandomAccessLinSpacedReturnType
+ LinSpaced(Index size, const Scalar& low, const Scalar& high);
+ static const SequentialLinSpacedReturnType
+ LinSpaced(Sequential_t, const Scalar& low, const Scalar& high);
+ static const RandomAccessLinSpacedReturnType
+ LinSpaced(const Scalar& low, const Scalar& high);
+
+ template<typename CustomNullaryOp>
+ static const CwiseNullaryOp<CustomNullaryOp, Derived>
+ NullaryExpr(Index rows, Index cols, const CustomNullaryOp& func);
+ template<typename CustomNullaryOp>
+ static const CwiseNullaryOp<CustomNullaryOp, Derived>
+ NullaryExpr(Index size, const CustomNullaryOp& func);
+ template<typename CustomNullaryOp>
+ static const CwiseNullaryOp<CustomNullaryOp, Derived>
+ 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<typename OtherDerived>
+ bool isApprox(const DenseBase<OtherDerived>& other,
+ RealScalar prec = NumTraits<Scalar>::dummy_precision()) const;
+ bool isMuchSmallerThan(const RealScalar& other,
+ RealScalar prec = NumTraits<Scalar>::dummy_precision()) const;
+ template<typename OtherDerived>
+ bool isMuchSmallerThan(const DenseBase<OtherDerived>& other,
+ RealScalar prec = NumTraits<Scalar>::dummy_precision()) const;
+
+ bool isApproxToConstant(const Scalar& value, RealScalar prec = NumTraits<Scalar>::dummy_precision()) const;
+ bool isConstant(const Scalar& value, RealScalar prec = NumTraits<Scalar>::dummy_precision()) const;
+ bool isZero(RealScalar prec = NumTraits<Scalar>::dummy_precision()) const;
+ bool isOnes(RealScalar prec = NumTraits<Scalar>::dummy_precision()) const;
+
+ inline Derived& operator*=(const Scalar& other);
+ inline Derived& operator/=(const Scalar& other);
+
+ typedef typename internal::add_const_on_value_type<typename internal::eval<Derived>::type>::type EvalReturnType;
+ /** \returns the matrix or vector obtained by evaluating this expression.
+ *
+ * Notice that in the case of a plain matrix or vector (not an expression) this function just returns
+ * a const reference, in order to avoid a useless copy.
+ */
+ EIGEN_STRONG_INLINE EvalReturnType eval() const
+ {
+ // Even though MSVC does not honor strong inlining when the return type
+ // is a dynamic matrix, we desperately need strong inlining for fixed
+ // size types on MSVC.
+ return typename internal::eval<Derived>::type(derived());
+ }
+
+ /** swaps *this with the expression \a other.
+ *
+ */
+ template<typename OtherDerived>
+ void swap(const DenseBase<OtherDerived>& other,
+ int = OtherDerived::ThisConstantIsPrivateInPlainObjectBase)
+ {
+ SwapWrapper<Derived>(derived()).lazyAssign(other.derived());
+ }
+
+ /** swaps *this with the matrix or array \a other.
+ *
+ */
+ template<typename OtherDerived>
+ void swap(PlainObjectBase<OtherDerived>& other)
+ {
+ SwapWrapper<Derived>(derived()).lazyAssign(other.derived());
+ }
+
+
+ inline const NestByValue<Derived> nestByValue() const;
+ inline const ForceAlignedAccess<Derived> forceAlignedAccess() const;
+ inline ForceAlignedAccess<Derived> forceAlignedAccess();
+ template<bool Enable> inline const typename internal::conditional<Enable,ForceAlignedAccess<Derived>,Derived&>::type forceAlignedAccessIf() const;
+ template<bool Enable> inline typename internal::conditional<Enable,ForceAlignedAccess<Derived>,Derived&>::type forceAlignedAccessIf();
+
+ Scalar sum() const;
+ Scalar mean() const;
+ Scalar trace() const;
+
+ Scalar prod() const;
+
+ typename internal::traits<Derived>::Scalar minCoeff() const;
+ typename internal::traits<Derived>::Scalar maxCoeff() const;
+
+ template<typename IndexType>
+ typename internal::traits<Derived>::Scalar minCoeff(IndexType* row, IndexType* col) const;
+ template<typename IndexType>
+ typename internal::traits<Derived>::Scalar maxCoeff(IndexType* row, IndexType* col) const;
+ template<typename IndexType>
+ typename internal::traits<Derived>::Scalar minCoeff(IndexType* index) const;
+ template<typename IndexType>
+ typename internal::traits<Derived>::Scalar maxCoeff(IndexType* index) const;
+
+ template<typename BinaryOp>
+ typename internal::result_of<BinaryOp(typename internal::traits<Derived>::Scalar)>::type
+ redux(const BinaryOp& func) const;
+
+ template<typename Visitor>
+ void visit(Visitor& func) const;
+
+ inline const WithFormat<Derived> format(const IOFormat& fmt) const;
+
+ /** \returns the unique coefficient of a 1x1 expression */
+ CoeffReturnType value() const
+ {
+ EIGEN_STATIC_ASSERT_SIZE_1x1(Derived)
+ eigen_assert(this->rows() == 1 && this->cols() == 1);
+ return derived().coeff(0,0);
+ }
+
+/////////// Array module ///////////
+
+ bool all(void) const;
+ bool any(void) const;
+ Index count() const;
+
+ typedef VectorwiseOp<Derived, Horizontal> RowwiseReturnType;
+ typedef const VectorwiseOp<const Derived, Horizontal> ConstRowwiseReturnType;
+ typedef VectorwiseOp<Derived, Vertical> ColwiseReturnType;
+ typedef const VectorwiseOp<const Derived, Vertical> ConstColwiseReturnType;
+
+ ConstRowwiseReturnType rowwise() const;
+ RowwiseReturnType rowwise();
+ ConstColwiseReturnType colwise() const;
+ ColwiseReturnType colwise();
+
+ static const CwiseNullaryOp<internal::scalar_random_op<Scalar>,Derived> Random(Index rows, Index cols);
+ static const CwiseNullaryOp<internal::scalar_random_op<Scalar>,Derived> Random(Index size);
+ static const CwiseNullaryOp<internal::scalar_random_op<Scalar>,Derived> Random();
+
+ template<typename ThenDerived,typename ElseDerived>
+ const Select<Derived,ThenDerived,ElseDerived>
+ select(const DenseBase<ThenDerived>& thenMatrix,
+ const DenseBase<ElseDerived>& elseMatrix) const;
+
+ template<typename ThenDerived>
+ inline const Select<Derived,ThenDerived, typename ThenDerived::ConstantReturnType>
+ select(const DenseBase<ThenDerived>& thenMatrix, typename ThenDerived::Scalar elseScalar) const;
+
+ template<typename ElseDerived>
+ inline const Select<Derived, typename ElseDerived::ConstantReturnType, ElseDerived >
+ select(typename ElseDerived::Scalar thenScalar, const DenseBase<ElseDerived>& elseMatrix) const;
+
+ template<int p> RealScalar lpNorm() const;
+
+ template<int RowFactor, int ColFactor>
+ const Replicate<Derived,RowFactor,ColFactor> replicate() const;
+ const Replicate<Derived,Dynamic,Dynamic> replicate(Index rowFacor,Index colFactor) const;
+
+ typedef Reverse<Derived, BothDirections> ReverseReturnType;
+ typedef const Reverse<const Derived, BothDirections> ConstReverseReturnType;
+ ReverseReturnType reverse();
+ ConstReverseReturnType reverse() const;
+ void reverseInPlace();
+
+#define EIGEN_CURRENT_STORAGE_BASE_CLASS Eigen::DenseBase
+# include "../plugins/BlockMethods.h"
+# ifdef EIGEN_DENSEBASE_PLUGIN
+# include EIGEN_DENSEBASE_PLUGIN
+# endif
+#undef EIGEN_CURRENT_STORAGE_BASE_CLASS
+
+#ifdef EIGEN2_SUPPORT
+
+ Block<Derived> corner(CornerType type, Index cRows, Index cCols);
+ const Block<Derived> corner(CornerType type, Index cRows, Index cCols) const;
+ template<int CRows, int CCols>
+ Block<Derived, CRows, CCols> corner(CornerType type);
+ template<int CRows, int CCols>
+ const Block<Derived, CRows, CCols> corner(CornerType type) const;
+
+#endif // EIGEN2_SUPPORT
+
+
+ // disable the use of evalTo for dense objects with a nice compilation error
+ template<typename Dest> inline void evalTo(Dest& ) const
+ {
+ EIGEN_STATIC_ASSERT((internal::is_same<Dest,void>::value),THE_EVAL_EVALTO_FUNCTION_SHOULD_NEVER_BE_CALLED_FOR_DENSE_OBJECTS);
+ }
+
+ protected:
+ /** Default constructor. Do nothing. */
+ 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
+ */
+#ifdef EIGEN_INTERNAL_DEBUGGING
+ EIGEN_STATIC_ASSERT((EIGEN_IMPLIES(MaxRowsAtCompileTime==1 && MaxColsAtCompileTime!=1, int(IsRowMajor))
+ && EIGEN_IMPLIES(MaxColsAtCompileTime==1 && MaxRowsAtCompileTime!=1, int(!IsRowMajor))),
+ INVALID_STORAGE_ORDER_FOR_THIS_VECTOR_EXPRESSION)
+#endif
+ }
+
+ private:
+ explicit DenseBase(int);
+ DenseBase(int,int);
+ template<typename OtherDerived> explicit DenseBase(const DenseBase<OtherDerived>&);
+};
+
+} // end namespace Eigen
+
+#endif // EIGEN_DENSEBASE_H
diff --git a/Eigen/src/Core/DenseCoeffsBase.h b/Eigen/src/Core/DenseCoeffsBase.h
new file mode 100644
index 000000000..72704c2d7
--- /dev/null
+++ b/Eigen/src/Core/DenseCoeffsBase.h
@@ -0,0 +1,754 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra.
+//
+// Copyright (C) 2006-2010 Benoit Jacob <jacob.benoit.1@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 EIGEN_DENSECOEFFSBASE_H
+#define EIGEN_DENSECOEFFSBASE_H
+
+namespace Eigen {
+
+namespace internal {
+template<typename T> struct add_const_on_value_type_if_arithmetic
+{
+ typedef typename conditional<is_arithmetic<T>::value, T, typename add_const_on_value_type<T>::type>::type type;
+};
+}
+
+/** \brief Base class providing read-only coefficient access to matrices and arrays.
+ * \ingroup Core_Module
+ * \tparam Derived Type of the derived class
+ * \tparam #ReadOnlyAccessors Constant indicating read-only access
+ *
+ * This class defines the \c operator() \c const function and friends, which can be used to read specific
+ * entries of a matrix or array.
+ *
+ * \sa DenseCoeffsBase<Derived, WriteAccessors>, DenseCoeffsBase<Derived, DirectAccessors>,
+ * \ref TopicClassHierarchy
+ */
+template<typename Derived>
+class DenseCoeffsBase<Derived,ReadOnlyAccessors> : public EigenBase<Derived>
+{
+ public:
+ typedef typename internal::traits<Derived>::StorageKind StorageKind;
+ typedef typename internal::traits<Derived>::Index Index;
+ typedef typename internal::traits<Derived>::Scalar Scalar;
+ typedef typename internal::packet_traits<Scalar>::type PacketScalar;
+
+ // Explanation for this CoeffReturnType typedef.
+ // - This is the return type of the coeff() method.
+ // - The LvalueBit means exactly that we can offer a coeffRef() method, which means exactly that we can get references
+ // to coeffs, which means exactly that we can have coeff() return a const reference (as opposed to returning a value).
+ // - The is_artihmetic check is required since "const int", "const double", etc. will cause warnings on some systems
+ // while the declaration of "const T", where T is a non arithmetic type does not. Always returning "const Scalar&" is
+ // not possible, since the underlying expressions might not offer a valid address the reference could be referring to.
+ typedef typename internal::conditional<bool(internal::traits<Derived>::Flags&LvalueBit),
+ const Scalar&,
+ typename internal::conditional<internal::is_arithmetic<Scalar>::value, Scalar, const Scalar>::type
+ >::type CoeffReturnType;
+
+ typedef typename internal::add_const_on_value_type_if_arithmetic<
+ typename internal::packet_traits<Scalar>::type
+ >::type PacketReturnType;
+
+ typedef EigenBase<Derived> Base;
+ using Base::rows;
+ using Base::cols;
+ using Base::size;
+ using Base::derived;
+
+ EIGEN_STRONG_INLINE Index rowIndexByOuterInner(Index outer, Index inner) const
+ {
+ return int(Derived::RowsAtCompileTime) == 1 ? 0
+ : int(Derived::ColsAtCompileTime) == 1 ? inner
+ : int(Derived::Flags)&RowMajorBit ? outer
+ : inner;
+ }
+
+ EIGEN_STRONG_INLINE Index colIndexByOuterInner(Index outer, Index inner) const
+ {
+ return int(Derived::ColsAtCompileTime) == 1 ? 0
+ : int(Derived::RowsAtCompileTime) == 1 ? inner
+ : int(Derived::Flags)&RowMajorBit ? inner
+ : outer;
+ }
+
+ /** Short version: don't use this function, use
+ * \link operator()(Index,Index) const \endlink instead.
+ *
+ * Long version: this function is similar to
+ * \link operator()(Index,Index) const \endlink, but without the assertion.
+ * Use this for limiting the performance cost of debugging code when doing
+ * repeated coefficient access. Only use this when it is guaranteed that the
+ * parameters \a row and \a col are in range.
+ *
+ * If EIGEN_INTERNAL_DEBUGGING is defined, an assertion will be made, making this
+ * function equivalent to \link operator()(Index,Index) const \endlink.
+ *
+ * \sa operator()(Index,Index) const, coeffRef(Index,Index), coeff(Index) const
+ */
+ 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);
+ }
+
+ EIGEN_STRONG_INLINE CoeffReturnType coeffByOuterInner(Index outer, Index inner) const
+ {
+ return coeff(rowIndexByOuterInner(outer, inner),
+ colIndexByOuterInner(outer, inner));
+ }
+
+ /** \returns the coefficient at given the given row and column.
+ *
+ * \sa operator()(Index,Index), operator[](Index)
+ */
+ 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);
+ }
+
+ /** Short version: don't use this function, use
+ * \link operator[](Index) const \endlink instead.
+ *
+ * Long version: this function is similar to
+ * \link operator[](Index) const \endlink, but without the assertion.
+ * Use this for limiting the performance cost of debugging code when doing
+ * repeated coefficient access. Only use this when it is guaranteed that the
+ * parameter \a index is in range.
+ *
+ * If EIGEN_INTERNAL_DEBUGGING is defined, an assertion will be made, making this
+ * function equivalent to \link operator[](Index) const \endlink.
+ *
+ * \sa operator[](Index) const, coeffRef(Index), coeff(Index,Index) const
+ */
+
+ EIGEN_STRONG_INLINE CoeffReturnType
+ coeff(Index index) const
+ {
+ eigen_internal_assert(index >= 0 && index < size());
+ return derived().coeff(index);
+ }
+
+
+ /** \returns the coefficient at given index.
+ *
+ * This method is allowed only for vector expressions, and for matrix expressions having the LinearAccessBit.
+ *
+ * \sa operator[](Index), operator()(Index,Index) const, x() const, y() const,
+ * z() const, w() const
+ */
+
+ 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);
+ }
+
+ /** \returns the coefficient at given index.
+ *
+ * This is synonymous to operator[](Index) const.
+ *
+ * This method is allowed only for vector expressions, and for matrix expressions having the LinearAccessBit.
+ *
+ * \sa operator[](Index), operator()(Index,Index) const, x() const, y() const,
+ * z() const, w() const
+ */
+
+ EIGEN_STRONG_INLINE CoeffReturnType
+ operator()(Index index) const
+ {
+ eigen_assert(index >= 0 && index < size());
+ return derived().coeff(index);
+ }
+
+ /** equivalent to operator[](0). */
+
+ EIGEN_STRONG_INLINE CoeffReturnType
+ x() const { return (*this)[0]; }
+
+ /** equivalent to operator[](1). */
+
+ EIGEN_STRONG_INLINE CoeffReturnType
+ y() const { return (*this)[1]; }
+
+ /** equivalent to operator[](2). */
+
+ EIGEN_STRONG_INLINE CoeffReturnType
+ z() const { return (*this)[2]; }
+
+ /** equivalent to operator[](3). */
+
+ EIGEN_STRONG_INLINE CoeffReturnType
+ w() const { return (*this)[3]; }
+
+ /** \internal
+ * \returns the packet of coefficients starting at the given row and column. 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<int LoadMode>
+ 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<LoadMode>(row,col);
+ }
+
+
+ /** \internal */
+ template<int LoadMode>
+ EIGEN_STRONG_INLINE PacketReturnType packetByOuterInner(Index outer, Index inner) const
+ {
+ return packet<LoadMode>(rowIndexByOuterInner(outer, inner),
+ colIndexByOuterInner(outer, inner));
+ }
+
+ /** \internal
+ * \returns the packet of coefficients starting at the given index. 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<int LoadMode>
+ EIGEN_STRONG_INLINE PacketReturnType packet(Index index) const
+ {
+ eigen_internal_assert(index >= 0 && index < size());
+ return derived().template packet<LoadMode>(index);
+ }
+
+ protected:
+ // explanation: DenseBase is doing "using ..." on the methods from DenseCoeffsBase.
+ // But some methods are only available in the DirectAccess case.
+ // So we add dummy methods here with these names, so that "using... " doesn't fail.
+ // It's not private so that the child class DenseBase can access them, and it's not public
+ // either since it's an implementation detail, so has to be protected.
+ void coeffRef();
+ void coeffRefByOuterInner();
+ void writePacket();
+ void writePacketByOuterInner();
+ void copyCoeff();
+ void copyCoeffByOuterInner();
+ void copyPacket();
+ void copyPacketByOuterInner();
+ void stride();
+ void innerStride();
+ void outerStride();
+ void rowStride();
+ void colStride();
+};
+
+/** \brief Base class providing read/write coefficient access to matrices and arrays.
+ * \ingroup Core_Module
+ * \tparam Derived Type of the derived class
+ * \tparam #WriteAccessors Constant indicating read/write access
+ *
+ * This class defines the non-const \c operator() function and friends, which can be used to write specific
+ * entries of a matrix or array. This class inherits DenseCoeffsBase<Derived, ReadOnlyAccessors> which
+ * defines the const variant for reading specific entries.
+ *
+ * \sa DenseCoeffsBase<Derived, DirectAccessors>, \ref TopicClassHierarchy
+ */
+template<typename Derived>
+class DenseCoeffsBase<Derived, WriteAccessors> : public DenseCoeffsBase<Derived, ReadOnlyAccessors>
+{
+ public:
+
+ typedef DenseCoeffsBase<Derived, ReadOnlyAccessors> Base;
+
+ typedef typename internal::traits<Derived>::StorageKind StorageKind;
+ typedef typename internal::traits<Derived>::Index Index;
+ typedef typename internal::traits<Derived>::Scalar Scalar;
+ typedef typename internal::packet_traits<Scalar>::type PacketScalar;
+ typedef typename NumTraits<Scalar>::Real RealScalar;
+
+ using Base::coeff;
+ using Base::rows;
+ using Base::cols;
+ using Base::size;
+ using Base::derived;
+ using Base::rowIndexByOuterInner;
+ using Base::colIndexByOuterInner;
+ using Base::operator[];
+ using Base::operator();
+ using Base::x;
+ using Base::y;
+ using Base::z;
+ using Base::w;
+
+ /** Short version: don't use this function, use
+ * \link operator()(Index,Index) \endlink instead.
+ *
+ * Long version: this function is similar to
+ * \link operator()(Index,Index) \endlink, but without the assertion.
+ * Use this for limiting the performance cost of debugging code when doing
+ * repeated coefficient access. Only use this when it is guaranteed that the
+ * parameters \a row and \a col are in range.
+ *
+ * If EIGEN_INTERNAL_DEBUGGING is defined, an assertion will be made, making this
+ * function equivalent to \link operator()(Index,Index) \endlink.
+ *
+ * \sa operator()(Index,Index), coeff(Index, Index) const, coeffRef(Index)
+ */
+ EIGEN_STRONG_INLINE Scalar& coeffRef(Index row, Index col)
+ {
+ eigen_internal_assert(row >= 0 && row < rows()
+ && col >= 0 && col < cols());
+ return derived().coeffRef(row, col);
+ }
+
+ EIGEN_STRONG_INLINE Scalar&
+ coeffRefByOuterInner(Index outer, Index inner)
+ {
+ return coeffRef(rowIndexByOuterInner(outer, inner),
+ colIndexByOuterInner(outer, inner));
+ }
+
+ /** \returns a reference to the coefficient at given the given row and column.
+ *
+ * \sa operator[](Index)
+ */
+
+ EIGEN_STRONG_INLINE Scalar&
+ operator()(Index row, Index col)
+ {
+ eigen_assert(row >= 0 && row < rows()
+ && col >= 0 && col < cols());
+ return derived().coeffRef(row, col);
+ }
+
+
+ /** Short version: don't use this function, use
+ * \link operator[](Index) \endlink instead.
+ *
+ * Long version: this function is similar to
+ * \link operator[](Index) \endlink, but without the assertion.
+ * Use this for limiting the performance cost of debugging code when doing
+ * repeated coefficient access. Only use this when it is guaranteed that the
+ * parameters \a row and \a col are in range.
+ *
+ * If EIGEN_INTERNAL_DEBUGGING is defined, an assertion will be made, making this
+ * function equivalent to \link operator[](Index) \endlink.
+ *
+ * \sa operator[](Index), coeff(Index) const, coeffRef(Index,Index)
+ */
+
+ EIGEN_STRONG_INLINE Scalar&
+ coeffRef(Index index)
+ {
+ eigen_internal_assert(index >= 0 && index < size());
+ return derived().coeffRef(index);
+ }
+
+ /** \returns a reference to the coefficient at given index.
+ *
+ * This method is allowed only for vector expressions, and for matrix expressions having the LinearAccessBit.
+ *
+ * \sa operator[](Index) const, operator()(Index,Index), x(), y(), z(), w()
+ */
+
+ EIGEN_STRONG_INLINE Scalar&
+ operator[](Index index)
+ {
+ #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().coeffRef(index);
+ }
+
+ /** \returns a reference to the coefficient at given index.
+ *
+ * This is synonymous to operator[](Index).
+ *
+ * This method is allowed only for vector expressions, and for matrix expressions having the LinearAccessBit.
+ *
+ * \sa operator[](Index) const, operator()(Index,Index), x(), y(), z(), w()
+ */
+
+ EIGEN_STRONG_INLINE Scalar&
+ operator()(Index index)
+ {
+ eigen_assert(index >= 0 && index < size());
+ return derived().coeffRef(index);
+ }
+
+ /** equivalent to operator[](0). */
+
+ EIGEN_STRONG_INLINE Scalar&
+ x() { return (*this)[0]; }
+
+ /** equivalent to operator[](1). */
+
+ 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<int StoreMode>
+ EIGEN_STRONG_INLINE void writePacket
+ (Index row, Index col, const typename internal::packet_traits<Scalar>::type& x)
+ {
+ eigen_internal_assert(row >= 0 && row < rows()
+ && col >= 0 && col < cols());
+ derived().template writePacket<StoreMode>(row,col,x);
+ }
+
+
+ /** \internal */
+ template<int StoreMode>
+ EIGEN_STRONG_INLINE void writePacketByOuterInner
+ (Index outer, Index inner, const typename internal::packet_traits<Scalar>::type& x)
+ {
+ writePacket<StoreMode>(rowIndexByOuterInner(outer, inner),
+ colIndexByOuterInner(outer, inner),
+ x);
+ }
+
+ /** \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<int StoreMode>
+ EIGEN_STRONG_INLINE void writePacket
+ (Index index, const typename internal::packet_traits<Scalar>::type& x)
+ {
+ eigen_internal_assert(index >= 0 && index < size());
+ derived().template writePacket<StoreMode>(index,x);
+ }
+
+#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<typename OtherDerived>
+ EIGEN_STRONG_INLINE void copyCoeff(Index row, Index col, const DenseBase<OtherDerived>& 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<typename OtherDerived>
+ EIGEN_STRONG_INLINE void copyCoeff(Index index, const DenseBase<OtherDerived>& other)
+ {
+ eigen_internal_assert(index >= 0 && index < size());
+ derived().coeffRef(index) = other.derived().coeff(index);
+ }
+
+
+ template<typename OtherDerived>
+ EIGEN_STRONG_INLINE void copyCoeffByOuterInner(Index outer, Index inner, const DenseBase<OtherDerived>& 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<typename OtherDerived, int StoreMode, int LoadMode>
+ EIGEN_STRONG_INLINE void copyPacket(Index row, Index col, const DenseBase<OtherDerived>& other)
+ {
+ eigen_internal_assert(row >= 0 && row < rows()
+ && col >= 0 && col < cols());
+ derived().template writePacket<StoreMode>(row, col,
+ other.derived().template packet<LoadMode>(row, col));
+ }
+
+ /** \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<typename OtherDerived, int StoreMode, int LoadMode>
+ EIGEN_STRONG_INLINE void copyPacket(Index index, const DenseBase<OtherDerived>& other)
+ {
+ eigen_internal_assert(index >= 0 && index < size());
+ derived().template writePacket<StoreMode>(index,
+ other.derived().template packet<LoadMode>(index));
+ }
+
+ /** \internal */
+ template<typename OtherDerived, int StoreMode, int LoadMode>
+ EIGEN_STRONG_INLINE void copyPacketByOuterInner(Index outer, Index inner, const DenseBase<OtherDerived>& other)
+ {
+ 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);
+ }
+#endif
+
+};
+
+/** \brief Base class providing direct read-only coefficient access to matrices and arrays.
+ * \ingroup Core_Module
+ * \tparam Derived Type of the derived class
+ * \tparam #DirectAccessors Constant indicating direct access
+ *
+ * This class defines functions to work with strides which can be used to access entries directly. This class
+ * inherits DenseCoeffsBase<Derived, ReadOnlyAccessors> which defines functions to access entries read-only using
+ * \c operator() .
+ *
+ * \sa \ref TopicClassHierarchy
+ */
+template<typename Derived>
+class DenseCoeffsBase<Derived, DirectAccessors> : public DenseCoeffsBase<Derived, ReadOnlyAccessors>
+{
+ public:
+
+ typedef DenseCoeffsBase<Derived, ReadOnlyAccessors> Base;
+ typedef typename internal::traits<Derived>::Index Index;
+ typedef typename internal::traits<Derived>::Scalar Scalar;
+ typedef typename NumTraits<Scalar>::Real RealScalar;
+
+ using Base::rows;
+ using Base::cols;
+ using Base::size;
+ using Base::derived;
+
+ /** \returns the pointer increment between two consecutive elements within a slice in the inner direction.
+ *
+ * \sa outerStride(), rowStride(), colStride()
+ */
+ inline Index innerStride() const
+ {
+ return derived().innerStride();
+ }
+
+ /** \returns the pointer increment between two consecutive inner slices (for example, between two consecutive columns
+ * in a column-major matrix).
+ *
+ * \sa innerStride(), rowStride(), colStride()
+ */
+ inline Index outerStride() const
+ {
+ return derived().outerStride();
+ }
+
+ // FIXME shall we remove it ?
+ inline Index stride() const
+ {
+ return Derived::IsVectorAtCompileTime ? innerStride() : outerStride();
+ }
+
+ /** \returns the pointer increment between two consecutive rows.
+ *
+ * \sa innerStride(), outerStride(), colStride()
+ */
+ inline Index rowStride() const
+ {
+ return Derived::IsRowMajor ? outerStride() : innerStride();
+ }
+
+ /** \returns the pointer increment between two consecutive columns.
+ *
+ * \sa innerStride(), outerStride(), rowStride()
+ */
+ inline Index colStride() const
+ {
+ return Derived::IsRowMajor ? innerStride() : outerStride();
+ }
+};
+
+/** \brief Base class providing direct read/write coefficient access to matrices and arrays.
+ * \ingroup Core_Module
+ * \tparam Derived Type of the derived class
+ * \tparam #DirectWriteAccessors Constant indicating direct access
+ *
+ * This class defines functions to work with strides which can be used to access entries directly. This class
+ * inherits DenseCoeffsBase<Derived, WriteAccessors> which defines functions to access entries read/write using
+ * \c operator().
+ *
+ * \sa \ref TopicClassHierarchy
+ */
+template<typename Derived>
+class DenseCoeffsBase<Derived, DirectWriteAccessors>
+ : public DenseCoeffsBase<Derived, WriteAccessors>
+{
+ public:
+
+ typedef DenseCoeffsBase<Derived, WriteAccessors> Base;
+ typedef typename internal::traits<Derived>::Index Index;
+ typedef typename internal::traits<Derived>::Scalar Scalar;
+ typedef typename NumTraits<Scalar>::Real RealScalar;
+
+ using Base::rows;
+ using Base::cols;
+ using Base::size;
+ using Base::derived;
+
+ /** \returns the pointer increment between two consecutive elements within a slice in the inner direction.
+ *
+ * \sa outerStride(), rowStride(), colStride()
+ */
+ inline Index innerStride() const
+ {
+ return derived().innerStride();
+ }
+
+ /** \returns the pointer increment between two consecutive inner slices (for example, between two consecutive columns
+ * in a column-major matrix).
+ *
+ * \sa innerStride(), rowStride(), colStride()
+ */
+ inline Index outerStride() const
+ {
+ return derived().outerStride();
+ }
+
+ // FIXME shall we remove it ?
+ inline Index stride() const
+ {
+ return Derived::IsVectorAtCompileTime ? innerStride() : outerStride();
+ }
+
+ /** \returns the pointer increment between two consecutive rows.
+ *
+ * \sa innerStride(), outerStride(), colStride()
+ */
+ inline Index rowStride() const
+ {
+ return Derived::IsRowMajor ? outerStride() : innerStride();
+ }
+
+ /** \returns the pointer increment between two consecutive columns.
+ *
+ * \sa innerStride(), outerStride(), rowStride()
+ */
+ inline Index colStride() const
+ {
+ return Derived::IsRowMajor ? innerStride() : outerStride();
+ }
+};
+
+namespace internal {
+
+template<typename Derived, bool JustReturnZero>
+struct first_aligned_impl
+{
+ static inline typename Derived::Index run(const Derived&)
+ { return 0; }
+};
+
+template<typename Derived>
+struct first_aligned_impl<Derived, false>
+{
+ static inline typename Derived::Index run(const Derived& m)
+ {
+ return internal::first_aligned(&m.const_cast_derived().coeffRef(0,0), m.size());
+ }
+};
+
+/** \internal \returns the index of the first element of the array that is well aligned for vectorization.
+ *
+ * There is also the variant first_aligned(const Scalar*, Integer) defined in Memory.h. See it for more
+ * documentation.
+ */
+template<typename Derived>
+static inline typename Derived::Index first_aligned(const Derived& m)
+{
+ return first_aligned_impl
+ <Derived, (Derived::Flags & AlignedBit) || !(Derived::Flags & DirectAccessBit)>
+ ::run(m);
+}
+
+template<typename Derived, bool HasDirectAccess = has_direct_access<Derived>::ret>
+struct inner_stride_at_compile_time
+{
+ enum { ret = traits<Derived>::InnerStrideAtCompileTime };
+};
+
+template<typename Derived>
+struct inner_stride_at_compile_time<Derived, false>
+{
+ enum { ret = 0 };
+};
+
+template<typename Derived, bool HasDirectAccess = has_direct_access<Derived>::ret>
+struct outer_stride_at_compile_time
+{
+ enum { ret = traits<Derived>::OuterStrideAtCompileTime };
+};
+
+template<typename Derived>
+struct outer_stride_at_compile_time<Derived, false>
+{
+ enum { ret = 0 };
+};
+
+} // end namespace internal
+
+} // end namespace Eigen
+
+#endif // EIGEN_DENSECOEFFSBASE_H
diff --git a/Eigen/src/Core/DenseStorage.h b/Eigen/src/Core/DenseStorage.h
new file mode 100644
index 000000000..1fc2daf2c
--- /dev/null
+++ b/Eigen/src/Core/DenseStorage.h
@@ -0,0 +1,303 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra.
+//
+// Copyright (C) 2008 Gael Guennebaud <gael.guennebaud@inria.fr>
+// Copyright (C) 2006-2009 Benoit Jacob <jacob.benoit.1@gmail.com>
+// Copyright (C) 2010 Hauke Heibel <hauke.heibel@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 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 {};
+
+/** \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 <typename T, int Size, int MatrixOrArrayOptions,
+ int Alignment = (MatrixOrArrayOptions&DontAlign) ? 0
+ : (((Size*sizeof(T))%16)==0) ? 16
+ : 0 >
+struct plain_array
+{
+ T array[Size];
+ plain_array() {}
+ plain_array(constructor_without_unaligned_array_assert) {}
+};
+
+#ifdef EIGEN_DISABLE_UNALIGNED_ARRAY_ASSERT
+ #define EIGEN_MAKE_UNALIGNED_ARRAY_ASSERT(sizemask)
+#else
+ #define EIGEN_MAKE_UNALIGNED_ARRAY_ASSERT(sizemask) \
+ eigen_assert((reinterpret_cast<size_t>(array) & sizemask) == 0 \
+ && "this assertion is explained here: " \
+ "http://eigen.tuxfamily.org/dox-devel/TopicUnalignedArrayAssert.html" \
+ " **** READ THIS WEB PAGE !!! ****");
+#endif
+
+template <typename T, int Size, int MatrixOrArrayOptions>
+struct plain_array<T, Size, MatrixOrArrayOptions, 16>
+{
+ EIGEN_USER_ALIGN16 T array[Size];
+ plain_array() { EIGEN_MAKE_UNALIGNED_ARRAY_ASSERT(0xf) }
+ plain_array(constructor_without_unaligned_array_assert) {}
+};
+
+template <typename T, int MatrixOrArrayOptions, int Alignment>
+struct plain_array<T, 0, MatrixOrArrayOptions, Alignment>
+{
+ 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<typename T, int Size, int _Rows, int _Cols, int _Options> class DenseStorage;
+
+// purely fixed-size matrix
+template<typename T, int Size, int _Rows, int _Cols, int _Options> class DenseStorage
+{
+ internal::plain_array<T,Size,_Options> m_data;
+ public:
+ inline explicit DenseStorage() {}
+ inline DenseStorage(internal::constructor_without_unaligned_array_assert)
+ : m_data(internal::constructor_without_unaligned_array_assert()) {}
+ inline DenseStorage(DenseIndex,DenseIndex,DenseIndex) {}
+ inline void swap(DenseStorage& other) { std::swap(m_data,other.m_data); }
+ static inline DenseIndex rows(void) {return _Rows;}
+ static inline DenseIndex cols(void) {return _Cols;}
+ inline void conservativeResize(DenseIndex,DenseIndex,DenseIndex) {}
+ inline void resize(DenseIndex,DenseIndex,DenseIndex) {}
+ inline const T *data() const { return m_data.array; }
+ inline T *data() { return m_data.array; }
+};
+
+// null matrix
+template<typename T, int _Rows, int _Cols, int _Options> class DenseStorage<T, 0, _Rows, _Cols, _Options>
+{
+ public:
+ inline explicit DenseStorage() {}
+ inline DenseStorage(internal::constructor_without_unaligned_array_assert) {}
+ inline DenseStorage(DenseIndex,DenseIndex,DenseIndex) {}
+ inline void swap(DenseStorage& ) {}
+ static inline DenseIndex rows(void) {return _Rows;}
+ static inline DenseIndex cols(void) {return _Cols;}
+ inline void conservativeResize(DenseIndex,DenseIndex,DenseIndex) {}
+ inline void resize(DenseIndex,DenseIndex,DenseIndex) {}
+ inline const T *data() const { return 0; }
+ inline T *data() { return 0; }
+};
+
+// more specializations for null matrices; these are necessary to resolve ambiguities
+template<typename T, int _Options> class DenseStorage<T, 0, Dynamic, Dynamic, _Options>
+: public DenseStorage<T, 0, 0, 0, _Options> { };
+
+template<typename T, int _Rows, int _Options> class DenseStorage<T, 0, _Rows, Dynamic, _Options>
+: public DenseStorage<T, 0, 0, 0, _Options> { };
+
+template<typename T, int _Cols, int _Options> class DenseStorage<T, 0, Dynamic, _Cols, _Options>
+: public DenseStorage<T, 0, 0, 0, _Options> { };
+
+// dynamic-size matrix with fixed-size storage
+template<typename T, int Size, int _Options> class DenseStorage<T, Size, Dynamic, Dynamic, _Options>
+{
+ internal::plain_array<T,Size,_Options> m_data;
+ DenseIndex m_rows;
+ DenseIndex m_cols;
+ public:
+ inline explicit DenseStorage() : m_rows(0), m_cols(0) {}
+ inline DenseStorage(internal::constructor_without_unaligned_array_assert)
+ : m_data(internal::constructor_without_unaligned_array_assert()), m_rows(0), m_cols(0) {}
+ inline DenseStorage(DenseIndex, DenseIndex rows, DenseIndex cols) : m_rows(rows), m_cols(cols) {}
+ inline 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); }
+ inline DenseIndex rows(void) const {return m_rows;}
+ inline DenseIndex cols(void) const {return m_cols;}
+ inline void conservativeResize(DenseIndex, DenseIndex rows, DenseIndex cols) { m_rows = rows; m_cols = cols; }
+ inline void resize(DenseIndex, DenseIndex rows, DenseIndex cols) { m_rows = rows; m_cols = cols; }
+ inline const T *data() const { return m_data.array; }
+ inline T *data() { return m_data.array; }
+};
+
+// dynamic-size matrix with fixed-size storage and fixed width
+template<typename T, int Size, int _Cols, int _Options> class DenseStorage<T, Size, Dynamic, _Cols, _Options>
+{
+ internal::plain_array<T,Size,_Options> m_data;
+ DenseIndex m_rows;
+ public:
+ inline explicit DenseStorage() : m_rows(0) {}
+ inline DenseStorage(internal::constructor_without_unaligned_array_assert)
+ : m_data(internal::constructor_without_unaligned_array_assert()), m_rows(0) {}
+ inline DenseStorage(DenseIndex, DenseIndex rows, DenseIndex) : m_rows(rows) {}
+ inline void swap(DenseStorage& other) { std::swap(m_data,other.m_data); std::swap(m_rows,other.m_rows); }
+ inline DenseIndex rows(void) const {return m_rows;}
+ inline DenseIndex cols(void) const {return _Cols;}
+ inline void conservativeResize(DenseIndex, DenseIndex rows, DenseIndex) { m_rows = rows; }
+ inline void resize(DenseIndex, DenseIndex rows, DenseIndex) { m_rows = rows; }
+ inline const T *data() const { return m_data.array; }
+ inline T *data() { return m_data.array; }
+};
+
+// dynamic-size matrix with fixed-size storage and fixed height
+template<typename T, int Size, int _Rows, int _Options> class DenseStorage<T, Size, _Rows, Dynamic, _Options>
+{
+ internal::plain_array<T,Size,_Options> m_data;
+ DenseIndex m_cols;
+ public:
+ inline explicit DenseStorage() : m_cols(0) {}
+ inline DenseStorage(internal::constructor_without_unaligned_array_assert)
+ : m_data(internal::constructor_without_unaligned_array_assert()), m_cols(0) {}
+ inline DenseStorage(DenseIndex, DenseIndex, DenseIndex cols) : m_cols(cols) {}
+ inline void swap(DenseStorage& other) { std::swap(m_data,other.m_data); std::swap(m_cols,other.m_cols); }
+ inline DenseIndex rows(void) const {return _Rows;}
+ inline DenseIndex cols(void) const {return m_cols;}
+ inline void conservativeResize(DenseIndex, DenseIndex, DenseIndex cols) { m_cols = cols; }
+ inline void resize(DenseIndex, DenseIndex, DenseIndex cols) { m_cols = cols; }
+ inline const T *data() const { return m_data.array; }
+ inline T *data() { return m_data.array; }
+};
+
+// purely dynamic matrix.
+template<typename T, int _Options> class DenseStorage<T, Dynamic, Dynamic, Dynamic, _Options>
+{
+ T *m_data;
+ DenseIndex m_rows;
+ DenseIndex m_cols;
+ public:
+ inline explicit DenseStorage() : m_data(0), m_rows(0), m_cols(0) {}
+ inline DenseStorage(internal::constructor_without_unaligned_array_assert)
+ : m_data(0), m_rows(0), m_cols(0) {}
+ inline DenseStorage(DenseIndex size, DenseIndex rows, DenseIndex cols)
+ : m_data(internal::conditional_aligned_new_auto<T,(_Options&DontAlign)==0>(size)), m_rows(rows), m_cols(cols)
+ { EIGEN_INTERNAL_DENSE_STORAGE_CTOR_PLUGIN }
+ inline ~DenseStorage() { internal::conditional_aligned_delete_auto<T,(_Options&DontAlign)==0>(m_data, m_rows*m_cols); }
+ inline 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); }
+ inline DenseIndex rows(void) const {return m_rows;}
+ inline DenseIndex cols(void) const {return m_cols;}
+ inline void conservativeResize(DenseIndex size, DenseIndex rows, DenseIndex cols)
+ {
+ m_data = internal::conditional_aligned_realloc_new_auto<T,(_Options&DontAlign)==0>(m_data, size, m_rows*m_cols);
+ m_rows = rows;
+ m_cols = cols;
+ }
+ void resize(DenseIndex size, DenseIndex rows, DenseIndex cols)
+ {
+ if(size != m_rows*m_cols)
+ {
+ internal::conditional_aligned_delete_auto<T,(_Options&DontAlign)==0>(m_data, m_rows*m_cols);
+ if (size)
+ m_data = internal::conditional_aligned_new_auto<T,(_Options&DontAlign)==0>(size);
+ else
+ m_data = 0;
+ EIGEN_INTERNAL_DENSE_STORAGE_CTOR_PLUGIN
+ }
+ m_rows = rows;
+ m_cols = cols;
+ }
+ inline const T *data() const { return m_data; }
+ inline T *data() { return m_data; }
+};
+
+// matrix with dynamic width and fixed height (so that matrix has dynamic size).
+template<typename T, int _Rows, int _Options> class DenseStorage<T, Dynamic, _Rows, Dynamic, _Options>
+{
+ T *m_data;
+ DenseIndex m_cols;
+ public:
+ inline explicit DenseStorage() : m_data(0), m_cols(0) {}
+ inline DenseStorage(internal::constructor_without_unaligned_array_assert) : m_data(0), m_cols(0) {}
+ inline DenseStorage(DenseIndex size, DenseIndex, DenseIndex cols) : m_data(internal::conditional_aligned_new_auto<T,(_Options&DontAlign)==0>(size)), m_cols(cols)
+ { EIGEN_INTERNAL_DENSE_STORAGE_CTOR_PLUGIN }
+ inline ~DenseStorage() { internal::conditional_aligned_delete_auto<T,(_Options&DontAlign)==0>(m_data, _Rows*m_cols); }
+ inline void swap(DenseStorage& other) { std::swap(m_data,other.m_data); std::swap(m_cols,other.m_cols); }
+ static inline DenseIndex rows(void) {return _Rows;}
+ inline DenseIndex cols(void) const {return m_cols;}
+ inline void conservativeResize(DenseIndex size, DenseIndex, DenseIndex cols)
+ {
+ m_data = internal::conditional_aligned_realloc_new_auto<T,(_Options&DontAlign)==0>(m_data, size, _Rows*m_cols);
+ m_cols = cols;
+ }
+ EIGEN_STRONG_INLINE void resize(DenseIndex size, DenseIndex, DenseIndex cols)
+ {
+ if(size != _Rows*m_cols)
+ {
+ internal::conditional_aligned_delete_auto<T,(_Options&DontAlign)==0>(m_data, _Rows*m_cols);
+ if (size)
+ m_data = internal::conditional_aligned_new_auto<T,(_Options&DontAlign)==0>(size);
+ else
+ m_data = 0;
+ EIGEN_INTERNAL_DENSE_STORAGE_CTOR_PLUGIN
+ }
+ m_cols = cols;
+ }
+ inline const T *data() const { return m_data; }
+ inline T *data() { return m_data; }
+};
+
+// matrix with dynamic height and fixed width (so that matrix has dynamic size).
+template<typename T, int _Cols, int _Options> class DenseStorage<T, Dynamic, Dynamic, _Cols, _Options>
+{
+ T *m_data;
+ DenseIndex m_rows;
+ public:
+ inline explicit DenseStorage() : m_data(0), m_rows(0) {}
+ inline DenseStorage(internal::constructor_without_unaligned_array_assert) : m_data(0), m_rows(0) {}
+ inline DenseStorage(DenseIndex size, DenseIndex rows, DenseIndex) : m_data(internal::conditional_aligned_new_auto<T,(_Options&DontAlign)==0>(size)), m_rows(rows)
+ { EIGEN_INTERNAL_DENSE_STORAGE_CTOR_PLUGIN }
+ inline ~DenseStorage() { internal::conditional_aligned_delete_auto<T,(_Options&DontAlign)==0>(m_data, _Cols*m_rows); }
+ inline void swap(DenseStorage& other) { std::swap(m_data,other.m_data); std::swap(m_rows,other.m_rows); }
+ inline DenseIndex rows(void) const {return m_rows;}
+ static inline DenseIndex cols(void) {return _Cols;}
+ inline void conservativeResize(DenseIndex size, DenseIndex rows, DenseIndex)
+ {
+ m_data = internal::conditional_aligned_realloc_new_auto<T,(_Options&DontAlign)==0>(m_data, size, m_rows*_Cols);
+ m_rows = rows;
+ }
+ EIGEN_STRONG_INLINE void resize(DenseIndex size, DenseIndex rows, DenseIndex)
+ {
+ if(size != m_rows*_Cols)
+ {
+ internal::conditional_aligned_delete_auto<T,(_Options&DontAlign)==0>(m_data, _Cols*m_rows);
+ if (size)
+ m_data = internal::conditional_aligned_new_auto<T,(_Options&DontAlign)==0>(size);
+ else
+ m_data = 0;
+ EIGEN_INTERNAL_DENSE_STORAGE_CTOR_PLUGIN
+ }
+ m_rows = rows;
+ }
+ inline const T *data() const { return m_data; }
+ inline T *data() { return m_data; }
+};
+
+} // end namespace Eigen
+
+#endif // EIGEN_MATRIX_H
diff --git a/Eigen/src/Core/Diagonal.h b/Eigen/src/Core/Diagonal.h
new file mode 100644
index 000000000..16261968a
--- /dev/null
+++ b/Eigen/src/Core/Diagonal.h
@@ -0,0 +1,236 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra.
+//
+// Copyright (C) 2007-2009 Benoit Jacob <jacob.benoit.1@gmail.com>
+// Copyright (C) 2009-2010 Gael Guennebaud <gael.guennebaud@inria.fr>
+//
+// This Source Code Form is subject to the terms of the Mozilla
+// Public License v. 2.0. If a copy of the MPL was not distributed
+// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+#ifndef EIGEN_DIAGONAL_H
+#define EIGEN_DIAGONAL_H
+
+namespace Eigen {
+
+/** \class Diagonal
+ * \ingroup Core_Module
+ *
+ * \brief Expression of a diagonal/subdiagonal/superdiagonal in a matrix
+ *
+ * \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.
+ *
+ * The matrix is not required to be square.
+ *
+ * This class represents an expression of the main diagonal, or any sub/super diagonal
+ * of a square matrix. It is the return type of MatrixBase::diagonal() and MatrixBase::diagonal(Index) and most of the
+ * time this is the only way it is used.
+ *
+ * \sa MatrixBase::diagonal(), MatrixBase::diagonal(Index)
+ */
+
+namespace internal {
+template<typename MatrixType, int DiagIndex>
+struct traits<Diagonal<MatrixType,DiagIndex> >
+ : traits<MatrixType>
+{
+ typedef typename nested<MatrixType>::type MatrixTypeNested;
+ typedef typename remove_reference<MatrixTypeNested>::type _MatrixTypeNested;
+ typedef typename MatrixType::StorageKind StorageKind;
+ enum {
+ RowsAtCompileTime = (int(DiagIndex) == Dynamic || int(MatrixType::SizeAtCompileTime) == Dynamic) ? Dynamic
+ : (EIGEN_PLAIN_ENUM_MIN(MatrixType::RowsAtCompileTime - EIGEN_PLAIN_ENUM_MAX(-DiagIndex, 0),
+ MatrixType::ColsAtCompileTime - EIGEN_PLAIN_ENUM_MAX( DiagIndex, 0))),
+ ColsAtCompileTime = 1,
+ MaxRowsAtCompileTime = int(MatrixType::MaxSizeAtCompileTime) == Dynamic ? Dynamic
+ : DiagIndex == Dynamic ? EIGEN_SIZE_MIN_PREFER_FIXED(MatrixType::MaxRowsAtCompileTime,
+ MatrixType::MaxColsAtCompileTime)
+ : (EIGEN_PLAIN_ENUM_MIN(MatrixType::MaxRowsAtCompileTime - EIGEN_PLAIN_ENUM_MAX(-DiagIndex, 0),
+ MatrixType::MaxColsAtCompileTime - EIGEN_PLAIN_ENUM_MAX( DiagIndex, 0))),
+ MaxColsAtCompileTime = 1,
+ MaskLvalueBit = is_lvalue<MatrixType>::value ? LvalueBit : 0,
+ Flags = (unsigned int)_MatrixTypeNested::Flags & (HereditaryBits | LinearAccessBit | MaskLvalueBit | DirectAccessBit) & ~RowMajorBit,
+ CoeffReadCost = _MatrixTypeNested::CoeffReadCost,
+ MatrixTypeOuterStride = outer_stride_at_compile_time<MatrixType>::ret,
+ InnerStrideAtCompileTime = MatrixTypeOuterStride == Dynamic ? Dynamic : MatrixTypeOuterStride+1,
+ OuterStrideAtCompileTime = 0
+ };
+};
+}
+
+template<typename MatrixType, int DiagIndex> class Diagonal
+ : public internal::dense_xpr_base< Diagonal<MatrixType,DiagIndex> >::type
+{
+ public:
+
+ typedef typename internal::dense_xpr_base<Diagonal>::type Base;
+ EIGEN_DENSE_PUBLIC_INTERFACE(Diagonal)
+
+ inline Diagonal(MatrixType& matrix, Index index = DiagIndex) : m_matrix(matrix), m_index(index) {}
+
+ EIGEN_INHERIT_ASSIGNMENT_OPERATORS(Diagonal)
+
+ 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()); }
+
+ inline Index cols() const { return 1; }
+
+ inline Index innerStride() const
+ {
+ return m_matrix.outerStride() + 1;
+ }
+
+ inline Index outerStride() const
+ {
+ return 0;
+ }
+
+ typedef typename internal::conditional<
+ internal::is_lvalue<MatrixType>::value,
+ Scalar,
+ const Scalar
+ >::type ScalarWithConstIfNotLvalue;
+
+ inline ScalarWithConstIfNotLvalue* data() { return &(m_matrix.const_cast_derived().coeffRef(rowOffset(), colOffset())); }
+ inline const Scalar* data() const { return &(m_matrix.const_cast_derived().coeffRef(rowOffset(), colOffset())); }
+
+ inline Scalar& coeffRef(Index row, Index)
+ {
+ EIGEN_STATIC_ASSERT_LVALUE(MatrixType)
+ return m_matrix.const_cast_derived().coeffRef(row+rowOffset(), row+colOffset());
+ }
+
+ inline const Scalar& coeffRef(Index row, Index) const
+ {
+ return m_matrix.const_cast_derived().coeffRef(row+rowOffset(), row+colOffset());
+ }
+
+ inline CoeffReturnType coeff(Index row, Index) const
+ {
+ return m_matrix.coeff(row+rowOffset(), row+colOffset());
+ }
+
+ inline Scalar& coeffRef(Index index)
+ {
+ EIGEN_STATIC_ASSERT_LVALUE(MatrixType)
+ return m_matrix.const_cast_derived().coeffRef(index+rowOffset(), index+colOffset());
+ }
+
+ inline const Scalar& coeffRef(Index index) const
+ {
+ return m_matrix.const_cast_derived().coeffRef(index+rowOffset(), index+colOffset());
+ }
+
+ inline CoeffReturnType coeff(Index index) const
+ {
+ return m_matrix.coeff(index+rowOffset(), index+colOffset());
+ }
+
+ const typename internal::remove_all<typename MatrixType::Nested>::type&
+ nestedExpression() const
+ {
+ return m_matrix;
+ }
+
+ int index() const
+ {
+ return m_index.value();
+ }
+
+ protected:
+ typename MatrixType::Nested m_matrix;
+ const internal::variable_if_dynamic<Index, DiagIndex> m_index;
+
+ private:
+ // some compilers may fail to optimize std::max etc in case of compile-time constants...
+ EIGEN_STRONG_INLINE Index absDiagIndex() const { return m_index.value()>0 ? m_index.value() : -m_index.value(); }
+ EIGEN_STRONG_INLINE Index rowOffset() const { return m_index.value()>0 ? 0 : -m_index.value(); }
+ 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
+ template<int LoadMode> typename MatrixType::PacketReturnType packet(Index) const;
+ template<int LoadMode> typename MatrixType::PacketReturnType packet(Index,Index) const;
+};
+
+/** \returns an expression of the main diagonal of the matrix \c *this
+ *
+ * \c *this is not required to be square.
+ *
+ * Example: \include MatrixBase_diagonal.cpp
+ * Output: \verbinclude MatrixBase_diagonal.out
+ *
+ * \sa class Diagonal */
+template<typename Derived>
+inline typename MatrixBase<Derived>::DiagonalReturnType
+MatrixBase<Derived>::diagonal()
+{
+ return derived();
+}
+
+/** This is the const version of diagonal(). */
+template<typename Derived>
+inline const typename MatrixBase<Derived>::ConstDiagonalReturnType
+MatrixBase<Derived>::diagonal() const
+{
+ return ConstDiagonalReturnType(derived());
+}
+
+/** \returns an expression of the \a DiagIndex-th sub or super diagonal of the matrix \c *this
+ *
+ * \c *this is not required to be square.
+ *
+ * The template parameter \a DiagIndex represent a super diagonal if \a DiagIndex > 0
+ * and a sub diagonal otherwise. \a DiagIndex == 0 is equivalent to the main diagonal.
+ *
+ * Example: \include MatrixBase_diagonal_int.cpp
+ * Output: \verbinclude MatrixBase_diagonal_int.out
+ *
+ * \sa MatrixBase::diagonal(), class Diagonal */
+template<typename Derived>
+inline typename MatrixBase<Derived>::template DiagonalIndexReturnType<Dynamic>::Type
+MatrixBase<Derived>::diagonal(Index index)
+{
+ return typename DiagonalIndexReturnType<Dynamic>::Type(derived(), index);
+}
+
+/** This is the const version of diagonal(Index). */
+template<typename Derived>
+inline typename MatrixBase<Derived>::template ConstDiagonalIndexReturnType<Dynamic>::Type
+MatrixBase<Derived>::diagonal(Index index) const
+{
+ return typename ConstDiagonalIndexReturnType<Dynamic>::Type(derived(), index);
+}
+
+/** \returns an expression of the \a DiagIndex-th sub or super diagonal of the matrix \c *this
+ *
+ * \c *this is not required to be square.
+ *
+ * The template parameter \a DiagIndex represent a super diagonal if \a DiagIndex > 0
+ * and a sub diagonal otherwise. \a DiagIndex == 0 is equivalent to the main diagonal.
+ *
+ * Example: \include MatrixBase_diagonal_template_int.cpp
+ * Output: \verbinclude MatrixBase_diagonal_template_int.out
+ *
+ * \sa MatrixBase::diagonal(), class Diagonal */
+template<typename Derived>
+template<int Index>
+inline typename MatrixBase<Derived>::template DiagonalIndexReturnType<Index>::Type
+MatrixBase<Derived>::diagonal()
+{
+ return derived();
+}
+
+/** This is the const version of diagonal<int>(). */
+template<typename Derived>
+template<int Index>
+inline typename MatrixBase<Derived>::template ConstDiagonalIndexReturnType<Index>::Type
+MatrixBase<Derived>::diagonal() const
+{
+ return derived();
+}
+
+} // end namespace Eigen
+
+#endif // EIGEN_DIAGONAL_H
diff --git a/Eigen/src/Core/DiagonalMatrix.h b/Eigen/src/Core/DiagonalMatrix.h
new file mode 100644
index 000000000..88190da68
--- /dev/null
+++ b/Eigen/src/Core/DiagonalMatrix.h
@@ -0,0 +1,295 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra.
+//
+// Copyright (C) 2009 Gael Guennebaud <gael.guennebaud@inria.fr>
+// Copyright (C) 2007-2009 Benoit Jacob <jacob.benoit.1@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 EIGEN_DIAGONALMATRIX_H
+#define EIGEN_DIAGONALMATRIX_H
+
+namespace Eigen {
+
+#ifndef EIGEN_PARSED_BY_DOXYGEN
+template<typename Derived>
+class DiagonalBase : public EigenBase<Derived>
+{
+ public:
+ typedef typename internal::traits<Derived>::DiagonalVectorType DiagonalVectorType;
+ typedef typename DiagonalVectorType::Scalar Scalar;
+ typedef typename internal::traits<Derived>::StorageKind StorageKind;
+ typedef typename internal::traits<Derived>::Index Index;
+
+ enum {
+ RowsAtCompileTime = DiagonalVectorType::SizeAtCompileTime,
+ ColsAtCompileTime = DiagonalVectorType::SizeAtCompileTime,
+ MaxRowsAtCompileTime = DiagonalVectorType::MaxSizeAtCompileTime,
+ MaxColsAtCompileTime = DiagonalVectorType::MaxSizeAtCompileTime,
+ IsVectorAtCompileTime = 0,
+ Flags = 0
+ };
+
+ typedef Matrix<Scalar, RowsAtCompileTime, ColsAtCompileTime, 0, MaxRowsAtCompileTime, MaxColsAtCompileTime> DenseMatrixType;
+ typedef DenseMatrixType DenseType;
+ typedef DiagonalMatrix<Scalar,DiagonalVectorType::SizeAtCompileTime,DiagonalVectorType::MaxSizeAtCompileTime> PlainObject;
+
+ inline const Derived& derived() const { return *static_cast<const Derived*>(this); }
+ inline Derived& derived() { return *static_cast<Derived*>(this); }
+
+ DenseMatrixType toDenseMatrix() const { return derived(); }
+ template<typename DenseDerived>
+ void evalTo(MatrixBase<DenseDerived> &other) const;
+ template<typename DenseDerived>
+ void addTo(MatrixBase<DenseDerived> &other) const
+ { other.diagonal() += diagonal(); }
+ template<typename DenseDerived>
+ void subTo(MatrixBase<DenseDerived> &other) const
+ { other.diagonal() -= diagonal(); }
+
+ inline const DiagonalVectorType& diagonal() const { return derived().diagonal(); }
+ inline DiagonalVectorType& diagonal() { return derived().diagonal(); }
+
+ inline Index rows() const { return diagonal().size(); }
+ inline Index cols() const { return diagonal().size(); }
+
+ template<typename MatrixDerived>
+ const DiagonalProduct<MatrixDerived, Derived, OnTheLeft>
+ operator*(const MatrixBase<MatrixDerived> &matrix) const;
+
+ inline const DiagonalWrapper<const CwiseUnaryOp<internal::scalar_inverse_op<Scalar>, const DiagonalVectorType> >
+ inverse() const
+ {
+ return diagonal().cwiseInverse();
+ }
+
+ #ifdef EIGEN2_SUPPORT
+ template<typename OtherDerived>
+ bool isApprox(const DiagonalBase<OtherDerived>& other, typename NumTraits<Scalar>::Real precision = NumTraits<Scalar>::dummy_precision()) const
+ {
+ return diagonal().isApprox(other.diagonal(), precision);
+ }
+ template<typename OtherDerived>
+ bool isApprox(const MatrixBase<OtherDerived>& other, typename NumTraits<Scalar>::Real precision = NumTraits<Scalar>::dummy_precision()) const
+ {
+ return toDenseMatrix().isApprox(other, precision);
+ }
+ #endif
+};
+
+template<typename Derived>
+template<typename DenseDerived>
+void DiagonalBase<Derived>::evalTo(MatrixBase<DenseDerived> &other) const
+{
+ other.setZero();
+ other.diagonal() = diagonal();
+}
+#endif
+
+/** \class DiagonalMatrix
+ * \ingroup Core_Module
+ *
+ * \brief Represents a diagonal matrix with its storage
+ *
+ * \param _Scalar the type of coefficients
+ * \param SizeAtCompileTime the dimension of the matrix, or Dynamic
+ * \param MaxSizeAtCompileTime the dimension of the matrix, or Dynamic. This parameter is optional and defaults
+ * to SizeAtCompileTime. Most of the time, you do not need to specify it.
+ *
+ * \sa class DiagonalWrapper
+ */
+
+namespace internal {
+template<typename _Scalar, int SizeAtCompileTime, int MaxSizeAtCompileTime>
+struct traits<DiagonalMatrix<_Scalar,SizeAtCompileTime,MaxSizeAtCompileTime> >
+ : traits<Matrix<_Scalar,SizeAtCompileTime,SizeAtCompileTime,0,MaxSizeAtCompileTime,MaxSizeAtCompileTime> >
+{
+ typedef Matrix<_Scalar,SizeAtCompileTime,1,0,MaxSizeAtCompileTime,1> DiagonalVectorType;
+ typedef Dense StorageKind;
+ typedef DenseIndex Index;
+ enum {
+ Flags = LvalueBit
+ };
+};
+}
+template<typename _Scalar, int SizeAtCompileTime, int MaxSizeAtCompileTime>
+class DiagonalMatrix
+ : public DiagonalBase<DiagonalMatrix<_Scalar,SizeAtCompileTime,MaxSizeAtCompileTime> >
+{
+ public:
+ #ifndef EIGEN_PARSED_BY_DOXYGEN
+ typedef typename internal::traits<DiagonalMatrix>::DiagonalVectorType DiagonalVectorType;
+ typedef const DiagonalMatrix& Nested;
+ typedef _Scalar Scalar;
+ typedef typename internal::traits<DiagonalMatrix>::StorageKind StorageKind;
+ typedef typename internal::traits<DiagonalMatrix>::Index Index;
+ #endif
+
+ protected:
+
+ DiagonalVectorType m_diagonal;
+
+ public:
+
+ /** const version of diagonal(). */
+ inline const DiagonalVectorType& diagonal() const { return m_diagonal; }
+ /** \returns a reference to the stored vector of diagonal coefficients. */
+ inline DiagonalVectorType& diagonal() { return m_diagonal; }
+
+ /** Default constructor without initialization */
+ inline DiagonalMatrix() {}
+
+ /** Constructs a diagonal matrix with given dimension */
+ inline DiagonalMatrix(Index dim) : m_diagonal(dim) {}
+
+ /** 2D constructor. */
+ inline DiagonalMatrix(const Scalar& x, const Scalar& y) : m_diagonal(x,y) {}
+
+ /** 3D constructor. */
+ inline DiagonalMatrix(const Scalar& x, const Scalar& y, const Scalar& z) : m_diagonal(x,y,z) {}
+
+ /** Copy constructor. */
+ template<typename OtherDerived>
+ inline DiagonalMatrix(const DiagonalBase<OtherDerived>& other) : m_diagonal(other.diagonal()) {}
+
+ #ifndef EIGEN_PARSED_BY_DOXYGEN
+ /** copy constructor. prevent a default copy constructor from hiding the other templated constructor */
+ inline DiagonalMatrix(const DiagonalMatrix& other) : m_diagonal(other.diagonal()) {}
+ #endif
+
+ /** generic constructor from expression of the diagonal coefficients */
+ template<typename OtherDerived>
+ explicit inline DiagonalMatrix(const MatrixBase<OtherDerived>& other) : m_diagonal(other)
+ {}
+
+ /** Copy operator. */
+ template<typename OtherDerived>
+ DiagonalMatrix& operator=(const DiagonalBase<OtherDerived>& other)
+ {
+ m_diagonal = other.diagonal();
+ return *this;
+ }
+
+ #ifndef EIGEN_PARSED_BY_DOXYGEN
+ /** This is a special case of the templated operator=. Its purpose is to
+ * prevent a default operator= from hiding the templated operator=.
+ */
+ DiagonalMatrix& operator=(const DiagonalMatrix& other)
+ {
+ m_diagonal = other.diagonal();
+ return *this;
+ }
+ #endif
+
+ /** Resizes to given size. */
+ inline void resize(Index size) { m_diagonal.resize(size); }
+ /** Sets all coefficients to zero. */
+ inline void setZero() { m_diagonal.setZero(); }
+ /** Resizes and sets all coefficients to zero. */
+ inline void setZero(Index size) { m_diagonal.setZero(size); }
+ /** Sets this matrix to be the identity matrix of the current size. */
+ inline void setIdentity() { m_diagonal.setOnes(); }
+ /** Sets this matrix to be the identity matrix of the given size. */
+ inline void setIdentity(Index size) { m_diagonal.setOnes(size); }
+};
+
+/** \class DiagonalWrapper
+ * \ingroup Core_Module
+ *
+ * \brief Expression of a diagonal matrix
+ *
+ * \param _DiagonalVectorType the type of the vector of diagonal coefficients
+ *
+ * This class is an expression of a diagonal matrix, but not storing its own vector of diagonal coefficients,
+ * instead wrapping an existing vector expression. It is the return type of MatrixBase::asDiagonal()
+ * and most of the time this is the only way that it is used.
+ *
+ * \sa class DiagonalMatrix, class DiagonalBase, MatrixBase::asDiagonal()
+ */
+
+namespace internal {
+template<typename _DiagonalVectorType>
+struct traits<DiagonalWrapper<_DiagonalVectorType> >
+{
+ typedef _DiagonalVectorType DiagonalVectorType;
+ typedef typename DiagonalVectorType::Scalar Scalar;
+ typedef typename DiagonalVectorType::Index Index;
+ typedef typename DiagonalVectorType::StorageKind StorageKind;
+ enum {
+ RowsAtCompileTime = DiagonalVectorType::SizeAtCompileTime,
+ ColsAtCompileTime = DiagonalVectorType::SizeAtCompileTime,
+ MaxRowsAtCompileTime = DiagonalVectorType::SizeAtCompileTime,
+ MaxColsAtCompileTime = DiagonalVectorType::SizeAtCompileTime,
+ Flags = traits<DiagonalVectorType>::Flags & LvalueBit
+ };
+};
+}
+
+template<typename _DiagonalVectorType>
+class DiagonalWrapper
+ : public DiagonalBase<DiagonalWrapper<_DiagonalVectorType> >, internal::no_assignment_operator
+{
+ public:
+ #ifndef EIGEN_PARSED_BY_DOXYGEN
+ typedef _DiagonalVectorType DiagonalVectorType;
+ typedef DiagonalWrapper Nested;
+ #endif
+
+ /** Constructor from expression of diagonal coefficients to wrap. */
+ inline DiagonalWrapper(DiagonalVectorType& diagonal) : m_diagonal(diagonal) {}
+
+ /** \returns a const reference to the wrapped expression of diagonal coefficients. */
+ const DiagonalVectorType& diagonal() const { return m_diagonal; }
+
+ protected:
+ typename DiagonalVectorType::Nested m_diagonal;
+};
+
+/** \returns a pseudo-expression of a diagonal matrix with *this as vector of diagonal coefficients
+ *
+ * \only_for_vectors
+ *
+ * Example: \include MatrixBase_asDiagonal.cpp
+ * Output: \verbinclude MatrixBase_asDiagonal.out
+ *
+ * \sa class DiagonalWrapper, class DiagonalMatrix, diagonal(), isDiagonal()
+ **/
+template<typename Derived>
+inline const DiagonalWrapper<const Derived>
+MatrixBase<Derived>::asDiagonal() const
+{
+ return derived();
+}
+
+/** \returns true if *this is approximately equal to a diagonal matrix,
+ * within the precision given by \a prec.
+ *
+ * Example: \include MatrixBase_isDiagonal.cpp
+ * Output: \verbinclude MatrixBase_isDiagonal.out
+ *
+ * \sa asDiagonal()
+ */
+template<typename Derived>
+bool MatrixBase<Derived>::isDiagonal(RealScalar prec) const
+{
+ if(cols() != rows()) return false;
+ RealScalar maxAbsOnDiagonal = static_cast<RealScalar>(-1);
+ for(Index j = 0; j < cols(); ++j)
+ {
+ RealScalar absOnDiagonal = internal::abs(coeff(j,j));
+ if(absOnDiagonal > maxAbsOnDiagonal) maxAbsOnDiagonal = absOnDiagonal;
+ }
+ for(Index j = 0; j < cols(); ++j)
+ for(Index i = 0; i < j; ++i)
+ {
+ if(!internal::isMuchSmallerThan(coeff(i, j), maxAbsOnDiagonal, prec)) return false;
+ if(!internal::isMuchSmallerThan(coeff(j, i), maxAbsOnDiagonal, prec)) return false;
+ }
+ return true;
+}
+
+} // end namespace Eigen
+
+#endif // EIGEN_DIAGONALMATRIX_H
diff --git a/Eigen/src/Core/DiagonalProduct.h b/Eigen/src/Core/DiagonalProduct.h
new file mode 100644
index 000000000..598c6b3e1
--- /dev/null
+++ b/Eigen/src/Core/DiagonalProduct.h
@@ -0,0 +1,123 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra.
+//
+// Copyright (C) 2008 Gael Guennebaud <gael.guennebaud@inria.fr>
+// Copyright (C) 2007-2009 Benoit Jacob <jacob.benoit.1@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 EIGEN_DIAGONALPRODUCT_H
+#define EIGEN_DIAGONALPRODUCT_H
+
+namespace Eigen {
+
+namespace internal {
+template<typename MatrixType, typename DiagonalType, int ProductOrder>
+struct traits<DiagonalProduct<MatrixType, DiagonalType, ProductOrder> >
+ : traits<MatrixType>
+{
+ typedef typename scalar_product_traits<typename MatrixType::Scalar, typename DiagonalType::Scalar>::ReturnType Scalar;
+ enum {
+ RowsAtCompileTime = MatrixType::RowsAtCompileTime,
+ ColsAtCompileTime = MatrixType::ColsAtCompileTime,
+ MaxRowsAtCompileTime = MatrixType::MaxRowsAtCompileTime,
+ MaxColsAtCompileTime = MatrixType::MaxColsAtCompileTime,
+
+ _StorageOrder = MatrixType::Flags & RowMajorBit ? RowMajor : ColMajor,
+ _PacketOnDiag = !((int(_StorageOrder) == RowMajor && int(ProductOrder) == OnTheLeft)
+ ||(int(_StorageOrder) == ColMajor && int(ProductOrder) == OnTheRight)),
+ _SameTypes = is_same<typename MatrixType::Scalar, typename DiagonalType::Scalar>::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::Flags)&PacketAccessBit))),
+ _Vectorizable = bool(int(MatrixType::Flags)&PacketAccessBit) && _SameTypes && ((!_PacketOnDiag) || (bool(int(DiagonalType::Flags)&PacketAccessBit))),
+
+ Flags = (HereditaryBits & (unsigned int)(MatrixType::Flags)) | (_Vectorizable ? PacketAccessBit : 0),
+ CoeffReadCost = NumTraits<Scalar>::MulCost + MatrixType::CoeffReadCost + DiagonalType::DiagonalVectorType::CoeffReadCost
+ };
+};
+}
+
+template<typename MatrixType, typename DiagonalType, int ProductOrder>
+class DiagonalProduct : internal::no_assignment_operator,
+ public MatrixBase<DiagonalProduct<MatrixType, DiagonalType, ProductOrder> >
+{
+ public:
+
+ typedef MatrixBase<DiagonalProduct> 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()));
+ }
+
+ inline Index rows() const { return m_matrix.rows(); }
+ inline Index cols() const { return m_matrix.cols(); }
+
+ const Scalar coeff(Index row, Index col) const
+ {
+ return m_diagonal.diagonal().coeff(ProductOrder == OnTheLeft ? row : col) * m_matrix.coeff(row, col);
+ }
+
+ template<int LoadMode>
+ 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<LoadMode>(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());
+ }
+
+ protected:
+ template<int LoadMode>
+ EIGEN_STRONG_INLINE PacketScalar packet_impl(Index row, Index col, Index id, internal::true_type) const
+ {
+ return internal::pmul(m_matrix.template packet<LoadMode>(row, col),
+ internal::pset1<PacketScalar>(m_diagonal.diagonal().coeff(id)));
+ }
+
+ template<int LoadMode>
+ 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)) ? Aligned : Unaligned
+ };
+ return internal::pmul(m_matrix.template packet<LoadMode>(row, col),
+ m_diagonal.diagonal().template packet<DiagonalVectorPacketLoadMode>(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<typename Derived>
+template<typename DiagonalDerived>
+inline const DiagonalProduct<Derived, DiagonalDerived, OnTheRight>
+MatrixBase<Derived>::operator*(const DiagonalBase<DiagonalDerived> &diagonal) const
+{
+ return DiagonalProduct<Derived, DiagonalDerived, OnTheRight>(derived(), diagonal.derived());
+}
+
+/** \returns the diagonal matrix product of \c *this by the matrix \a matrix.
+ */
+template<typename DiagonalDerived>
+template<typename MatrixDerived>
+inline const DiagonalProduct<MatrixDerived, DiagonalDerived, OnTheLeft>
+DiagonalBase<DiagonalDerived>::operator*(const MatrixBase<MatrixDerived> &matrix) const
+{
+ return DiagonalProduct<MatrixDerived, DiagonalDerived, OnTheLeft>(matrix.derived(), derived());
+}
+
+} // end namespace Eigen
+
+#endif // EIGEN_DIAGONALPRODUCT_H
diff --git a/Eigen/src/Core/Dot.h b/Eigen/src/Core/Dot.h
new file mode 100644
index 000000000..ae9274e36
--- /dev/null
+++ b/Eigen/src/Core/Dot.h
@@ -0,0 +1,261 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra.
+//
+// Copyright (C) 2006-2008, 2010 Benoit Jacob <jacob.benoit.1@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 EIGEN_DOT_H
+#define EIGEN_DOT_H
+
+namespace Eigen {
+
+namespace internal {
+
+// helper function for dot(). The problem is that if we put that in the body of dot(), then upon calling dot
+// with mismatched types, the compiler emits errors about failing to instantiate cwiseProduct BEFORE
+// looking at the static assertions. Thus this is a trick to get better compile errors.
+template<typename T, typename U,
+// the NeedToTranspose condition here is taken straight from Assign.h
+ bool NeedToTranspose = T::IsVectorAtCompileTime
+ && U::IsVectorAtCompileTime
+ && ((int(T::RowsAtCompileTime) == 1 && int(U::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(T::ColsAtCompileTime) == 1 && int(U::RowsAtCompileTime) == 1))
+>
+struct dot_nocheck
+{
+ typedef typename scalar_product_traits<typename traits<T>::Scalar,typename traits<U>::Scalar>::ReturnType ResScalar;
+ static inline ResScalar run(const MatrixBase<T>& a, const MatrixBase<U>& b)
+ {
+ return a.template binaryExpr<scalar_conj_product_op<typename traits<T>::Scalar,typename traits<U>::Scalar> >(b).sum();
+ }
+};
+
+template<typename T, typename U>
+struct dot_nocheck<T, U, true>
+{
+ typedef typename scalar_product_traits<typename traits<T>::Scalar,typename traits<U>::Scalar>::ReturnType ResScalar;
+ static inline ResScalar run(const MatrixBase<T>& a, const MatrixBase<U>& b)
+ {
+ return a.transpose().template binaryExpr<scalar_conj_product_op<typename traits<T>::Scalar,typename traits<U>::Scalar> >(b).sum();
+ }
+};
+
+} // end namespace internal
+
+/** \returns the dot product of *this with other.
+ *
+ * \only_for_vectors
+ *
+ * \note If the scalar type is complex numbers, then this function returns the hermitian
+ * (sesquilinear) dot product, conjugate-linear in the first variable and linear in the
+ * second variable.
+ *
+ * \sa squaredNorm(), norm()
+ */
+template<typename Derived>
+template<typename OtherDerived>
+typename internal::scalar_product_traits<typename internal::traits<Derived>::Scalar,typename internal::traits<OtherDerived>::Scalar>::ReturnType
+MatrixBase<Derived>::dot(const MatrixBase<OtherDerived>& other) const
+{
+ EIGEN_STATIC_ASSERT_VECTOR_ONLY(Derived)
+ EIGEN_STATIC_ASSERT_VECTOR_ONLY(OtherDerived)
+ EIGEN_STATIC_ASSERT_SAME_VECTOR_SIZE(Derived,OtherDerived)
+ typedef internal::scalar_conj_product_op<Scalar,typename OtherDerived::Scalar> func;
+ EIGEN_CHECK_BINARY_COMPATIBILIY(func,Scalar,typename OtherDerived::Scalar);
+
+ eigen_assert(size() == other.size());
+
+ return internal::dot_nocheck<Derived,OtherDerived>::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<typename Derived>
+template<typename OtherDerived>
+typename internal::traits<Derived>::Scalar
+MatrixBase<Derived>::eigen2_dot(const MatrixBase<OtherDerived>& 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<Scalar, typename OtherDerived::Scalar>::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<OtherDerived,Derived>::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()
+ */
+template<typename Derived>
+EIGEN_STRONG_INLINE typename NumTraits<typename internal::traits<Derived>::Scalar>::Real MatrixBase<Derived>::squaredNorm() const
+{
+ return internal::real((*this).cwiseAbs2().sum());
+}
+
+/** \returns, for vectors, the \em l2 norm of \c *this, and for matrices the Frobenius norm.
+ * 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()
+ */
+template<typename Derived>
+inline typename NumTraits<typename internal::traits<Derived>::Scalar>::Real MatrixBase<Derived>::norm() const
+{
+ return internal::sqrt(squaredNorm());
+}
+
+/** \returns an expression of the quotient of *this by its own norm.
+ *
+ * \only_for_vectors
+ *
+ * \sa norm(), normalize()
+ */
+template<typename Derived>
+inline const typename MatrixBase<Derived>::PlainObject
+MatrixBase<Derived>::normalized() const
+{
+ typedef typename internal::nested<Derived>::type Nested;
+ typedef typename internal::remove_reference<Nested>::type _Nested;
+ _Nested n(derived());
+ return n / n.norm();
+}
+
+/** Normalizes the vector, i.e. divides it by its own norm.
+ *
+ * \only_for_vectors
+ *
+ * \sa norm(), normalized()
+ */
+template<typename Derived>
+inline void MatrixBase<Derived>::normalize()
+{
+ *this /= norm();
+}
+
+//---------- implementation of other norms ----------
+
+namespace internal {
+
+template<typename Derived, int p>
+struct lpNorm_selector
+{
+ typedef typename NumTraits<typename traits<Derived>::Scalar>::Real RealScalar;
+ static inline RealScalar run(const MatrixBase<Derived>& m)
+ {
+ return pow(m.cwiseAbs().array().pow(p).sum(), RealScalar(1)/p);
+ }
+};
+
+template<typename Derived>
+struct lpNorm_selector<Derived, 1>
+{
+ static inline typename NumTraits<typename traits<Derived>::Scalar>::Real run(const MatrixBase<Derived>& m)
+ {
+ return m.cwiseAbs().sum();
+ }
+};
+
+template<typename Derived>
+struct lpNorm_selector<Derived, 2>
+{
+ static inline typename NumTraits<typename traits<Derived>::Scalar>::Real run(const MatrixBase<Derived>& m)
+ {
+ return m.norm();
+ }
+};
+
+template<typename Derived>
+struct lpNorm_selector<Derived, Infinity>
+{
+ static inline typename NumTraits<typename traits<Derived>::Scalar>::Real run(const MatrixBase<Derived>& m)
+ {
+ 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.
+ *
+ * \sa norm()
+ */
+template<typename Derived>
+template<int p>
+inline typename NumTraits<typename internal::traits<Derived>::Scalar>::Real
+MatrixBase<Derived>::lpNorm() const
+{
+ return internal::lpNorm_selector<Derived, p>::run(*this);
+}
+
+//---------- implementation of isOrthogonal / isUnitary ----------
+
+/** \returns true if *this is approximately orthogonal to \a other,
+ * within the precision given by \a prec.
+ *
+ * Example: \include MatrixBase_isOrthogonal.cpp
+ * Output: \verbinclude MatrixBase_isOrthogonal.out
+ */
+template<typename Derived>
+template<typename OtherDerived>
+bool MatrixBase<Derived>::isOrthogonal
+(const MatrixBase<OtherDerived>& other, RealScalar prec) const
+{
+ typename internal::nested<Derived,2>::type nested(derived());
+ typename internal::nested<OtherDerived,2>::type otherNested(other.derived());
+ return internal::abs2(nested.dot(otherNested)) <= prec * prec * nested.squaredNorm() * otherNested.squaredNorm();
+}
+
+/** \returns true if *this is approximately an unitary matrix,
+ * within the precision given by \a prec. In the case where the \a Scalar
+ * type is real numbers, a unitary matrix is an orthogonal matrix, whence the name.
+ *
+ * \note This can be used to check whether a family of vectors forms an orthonormal basis.
+ * Indeed, \c m.isUnitary() returns true if and only if the columns (equivalently, the rows) of m form an
+ * orthonormal basis.
+ *
+ * Example: \include MatrixBase_isUnitary.cpp
+ * Output: \verbinclude MatrixBase_isUnitary.out
+ */
+template<typename Derived>
+bool MatrixBase<Derived>::isUnitary(RealScalar prec) const
+{
+ typename Derived::Nested nested(derived());
+ for(Index i = 0; i < cols(); ++i)
+ {
+ if(!internal::isApprox(nested.col(i).squaredNorm(), static_cast<RealScalar>(1), prec))
+ return false;
+ for(Index j = 0; j < i; ++j)
+ if(!internal::isMuchSmallerThan(nested.col(i).dot(nested.col(j)), static_cast<Scalar>(1), prec))
+ return false;
+ }
+ return true;
+}
+
+} // end namespace Eigen
+
+#endif // EIGEN_DOT_H
diff --git a/Eigen/src/Core/EigenBase.h b/Eigen/src/Core/EigenBase.h
new file mode 100644
index 000000000..0bbd28bec
--- /dev/null
+++ b/Eigen/src/Core/EigenBase.h
@@ -0,0 +1,160 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra.
+//
+// Copyright (C) 2009 Benoit Jacob <jacob.benoit.1@gmail.com>
+// Copyright (C) 2009 Gael Guennebaud <gael.guennebaud@inria.fr>
+//
+// This Source Code Form is subject to the terms of the Mozilla
+// Public License v. 2.0. If a copy of the MPL was not distributed
+// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+#ifndef EIGEN_EIGENBASE_H
+#define EIGEN_EIGENBASE_H
+
+namespace Eigen {
+
+/** Common base class for all classes T such that MatrixBase has an operator=(T) and a constructor MatrixBase(T).
+ *
+ * In other words, an EigenBase object is an object that can be copied into a MatrixBase.
+ *
+ * Besides MatrixBase-derived classes, this also includes special matrix classes such as diagonal matrices, etc.
+ *
+ * Notice that this class is trivial, it is only used to disambiguate overloaded functions.
+ *
+ * \sa \ref TopicClassHierarchy
+ */
+template<typename Derived> struct EigenBase
+{
+// typedef typename internal::plain_matrix_type<Derived>::type PlainObject;
+
+ typedef typename internal::traits<Derived>::StorageKind StorageKind;
+ typedef typename internal::traits<Derived>::Index Index;
+
+ /** \returns a reference to the derived object */
+ Derived& derived() { return *static_cast<Derived*>(this); }
+ /** \returns a const reference to the derived object */
+ const Derived& derived() const { return *static_cast<const Derived*>(this); }
+
+ inline Derived& const_cast_derived() const
+ { return *static_cast<Derived*>(const_cast<EigenBase*>(this)); }
+ inline const Derived& const_derived() const
+ { return *static_cast<const Derived*>(this); }
+
+ /** \returns the number of rows. \sa cols(), RowsAtCompileTime */
+ inline Index rows() const { return derived().rows(); }
+ /** \returns the number of columns. \sa rows(), ColsAtCompileTime*/
+ inline Index cols() const { return derived().cols(); }
+ /** \returns the number of coefficients, which is rows()*cols().
+ * \sa rows(), cols(), SizeAtCompileTime. */
+ inline Index size() const { return rows() * cols(); }
+
+ /** \internal Don't use it, but do the equivalent: \code dst = *this; \endcode */
+ template<typename Dest> inline void evalTo(Dest& dst) const
+ { derived().evalTo(dst); }
+
+ /** \internal Don't use it, but do the equivalent: \code dst += *this; \endcode */
+ template<typename Dest> inline void addTo(Dest& dst) const
+ {
+ // This is the default implementation,
+ // derived class can reimplement it in a more optimized way.
+ typename Dest::PlainObject res(rows(),cols());
+ evalTo(res);
+ dst += res;
+ }
+
+ /** \internal Don't use it, but do the equivalent: \code dst -= *this; \endcode */
+ template<typename Dest> inline void subTo(Dest& dst) const
+ {
+ // This is the default implementation,
+ // derived class can reimplement it in a more optimized way.
+ typename Dest::PlainObject res(rows(),cols());
+ evalTo(res);
+ dst -= res;
+ }
+
+ /** \internal Don't use it, but do the equivalent: \code dst.applyOnTheRight(*this); \endcode */
+ template<typename Dest> inline void applyThisOnTheRight(Dest& dst) const
+ {
+ // This is the default implementation,
+ // derived class can reimplement it in a more optimized way.
+ dst = dst * this->derived();
+ }
+
+ /** \internal Don't use it, but do the equivalent: \code dst.applyOnTheLeft(*this); \endcode */
+ template<typename Dest> inline void applyThisOnTheLeft(Dest& dst) const
+ {
+ // This is the default implementation,
+ // derived class can reimplement it in a more optimized way.
+ dst = this->derived() * dst;
+ }
+
+};
+
+/***************************************************************************
+* Implementation of matrix base methods
+***************************************************************************/
+
+/** \brief Copies the generic expression \a other into *this.
+ *
+ * \details The expression must provide a (templated) evalTo(Derived& dst) const
+ * function which does the actual job. In practice, this allows any user to write
+ * its own special matrix without having to modify MatrixBase
+ *
+ * \returns a reference to *this.
+ */
+template<typename Derived>
+template<typename OtherDerived>
+Derived& DenseBase<Derived>::operator=(const EigenBase<OtherDerived> &other)
+{
+ other.derived().evalTo(derived());
+ return derived();
+}
+
+template<typename Derived>
+template<typename OtherDerived>
+Derived& DenseBase<Derived>::operator+=(const EigenBase<OtherDerived> &other)
+{
+ other.derived().addTo(derived());
+ return derived();
+}
+
+template<typename Derived>
+template<typename OtherDerived>
+Derived& DenseBase<Derived>::operator-=(const EigenBase<OtherDerived> &other)
+{
+ other.derived().subTo(derived());
+ return derived();
+}
+
+/** replaces \c *this by \c *this * \a other.
+ *
+ * \returns a reference to \c *this
+ */
+template<typename Derived>
+template<typename OtherDerived>
+inline Derived&
+MatrixBase<Derived>::operator*=(const EigenBase<OtherDerived> &other)
+{
+ other.derived().applyThisOnTheRight(derived());
+ return derived();
+}
+
+/** replaces \c *this by \c *this * \a other. It is equivalent to MatrixBase::operator*=() */
+template<typename Derived>
+template<typename OtherDerived>
+inline void MatrixBase<Derived>::applyOnTheRight(const EigenBase<OtherDerived> &other)
+{
+ other.derived().applyThisOnTheRight(derived());
+}
+
+/** replaces \c *this by \c *this * \a other. */
+template<typename Derived>
+template<typename OtherDerived>
+inline void MatrixBase<Derived>::applyOnTheLeft(const EigenBase<OtherDerived> &other)
+{
+ other.derived().applyThisOnTheLeft(derived());
+}
+
+} // end namespace Eigen
+
+#endif // EIGEN_EIGENBASE_H
diff --git a/Eigen/src/Core/Flagged.h b/Eigen/src/Core/Flagged.h
new file mode 100644
index 000000000..1f2955fc1
--- /dev/null
+++ b/Eigen/src/Core/Flagged.h
@@ -0,0 +1,140 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra.
+//
+// Copyright (C) 2008 Benoit Jacob <jacob.benoit.1@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 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<typename ExpressionType, unsigned int Added, unsigned int Removed>
+struct traits<Flagged<ExpressionType, Added, Removed> > : traits<ExpressionType>
+{
+ enum { Flags = (ExpressionType::Flags | Added) & ~Removed };
+};
+}
+
+template<typename ExpressionType, unsigned int Added, unsigned int Removed> class Flagged
+ : public MatrixBase<Flagged<ExpressionType, Added, Removed> >
+{
+ public:
+
+ typedef MatrixBase<Flagged> Base;
+
+ EIGEN_DENSE_PUBLIC_INTERFACE(Flagged)
+ typedef typename internal::conditional<internal::must_nest_by_value<ExpressionType>::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<int LoadMode>
+ inline const PacketScalar packet(Index row, Index col) const
+ {
+ return m_matrix.template packet<LoadMode>(row, col);
+ }
+
+ template<int LoadMode>
+ inline void writePacket(Index row, Index col, const PacketScalar& x)
+ {
+ m_matrix.const_cast_derived().template writePacket<LoadMode>(row, col, x);
+ }
+
+ template<int LoadMode>
+ inline const PacketScalar packet(Index index) const
+ {
+ return m_matrix.template packet<LoadMode>(index);
+ }
+
+ template<int LoadMode>
+ inline void writePacket(Index index, const PacketScalar& x)
+ {
+ m_matrix.const_cast_derived().template writePacket<LoadMode>(index, x);
+ }
+
+ const ExpressionType& _expression() const { return m_matrix; }
+
+ template<typename OtherDerived>
+ typename ExpressionType::PlainObject solveTriangular(const MatrixBase<OtherDerived>& other) const;
+
+ template<typename OtherDerived>
+ void solveTriangularInPlace(const MatrixBase<OtherDerived>& 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<typename Derived>
+template<unsigned int Added,unsigned int Removed>
+inline const Flagged<Derived, Added, Removed>
+DenseBase<Derived>::flagged() const
+{
+ return derived();
+}
+
+} // end namespace Eigen
+
+#endif // EIGEN_FLAGGED_H
diff --git a/Eigen/src/Core/ForceAlignedAccess.h b/Eigen/src/Core/ForceAlignedAccess.h
new file mode 100644
index 000000000..807c7a293
--- /dev/null
+++ b/Eigen/src/Core/ForceAlignedAccess.h
@@ -0,0 +1,146 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra.
+//
+// Copyright (C) 2009-2010 Gael Guennebaud <gael.guennebaud@inria.fr>
+//
+// This Source Code Form is subject to the terms of the Mozilla
+// Public License v. 2.0. If a copy of the MPL was not distributed
+// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+#ifndef EIGEN_FORCEALIGNEDACCESS_H
+#define EIGEN_FORCEALIGNEDACCESS_H
+
+namespace Eigen {
+
+/** \class ForceAlignedAccess
+ * \ingroup Core_Module
+ *
+ * \brief Enforce aligned packet loads and stores regardless of what is requested
+ *
+ * \param ExpressionType the type of the object of which we are forcing aligned packet access
+ *
+ * This class is the return type of MatrixBase::forceAlignedAccess()
+ * and most of the time this is the only way it is used.
+ *
+ * \sa MatrixBase::forceAlignedAccess()
+ */
+
+namespace internal {
+template<typename ExpressionType>
+struct traits<ForceAlignedAccess<ExpressionType> > : public traits<ExpressionType>
+{};
+}
+
+template<typename ExpressionType> class ForceAlignedAccess
+ : public internal::dense_xpr_base< ForceAlignedAccess<ExpressionType> >::type
+{
+ public:
+
+ typedef typename internal::dense_xpr_base<ForceAlignedAccess>::type Base;
+ EIGEN_DENSE_PUBLIC_INTERFACE(ForceAlignedAccess)
+
+ 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(); }
+
+ inline const CoeffReturnType coeff(Index row, Index col) const
+ {
+ return m_expression.coeff(row, col);
+ }
+
+ inline Scalar& coeffRef(Index row, Index col)
+ {
+ return m_expression.const_cast_derived().coeffRef(row, col);
+ }
+
+ inline const CoeffReturnType coeff(Index index) const
+ {
+ return m_expression.coeff(index);
+ }
+
+ inline Scalar& coeffRef(Index index)
+ {
+ return m_expression.const_cast_derived().coeffRef(index);
+ }
+
+ template<int LoadMode>
+ inline const PacketScalar packet(Index row, Index col) const
+ {
+ return m_expression.template packet<Aligned>(row, col);
+ }
+
+ template<int LoadMode>
+ inline void writePacket(Index row, Index col, const PacketScalar& x)
+ {
+ m_expression.const_cast_derived().template writePacket<Aligned>(row, col, x);
+ }
+
+ template<int LoadMode>
+ inline const PacketScalar packet(Index index) const
+ {
+ return m_expression.template packet<Aligned>(index);
+ }
+
+ template<int LoadMode>
+ inline void writePacket(Index index, const PacketScalar& x)
+ {
+ m_expression.const_cast_derived().template writePacket<Aligned>(index, x);
+ }
+
+ operator const ExpressionType&() const { return m_expression; }
+
+ protected:
+ const ExpressionType& m_expression;
+
+ private:
+ ForceAlignedAccess& operator=(const ForceAlignedAccess&);
+};
+
+/** \returns an expression of *this with forced aligned access
+ * \sa forceAlignedAccessIf(),class ForceAlignedAccess
+ */
+template<typename Derived>
+inline const ForceAlignedAccess<Derived>
+MatrixBase<Derived>::forceAlignedAccess() const
+{
+ return ForceAlignedAccess<Derived>(derived());
+}
+
+/** \returns an expression of *this with forced aligned access
+ * \sa forceAlignedAccessIf(), class ForceAlignedAccess
+ */
+template<typename Derived>
+inline ForceAlignedAccess<Derived>
+MatrixBase<Derived>::forceAlignedAccess()
+{
+ return ForceAlignedAccess<Derived>(derived());
+}
+
+/** \returns an expression of *this with forced aligned access if \a Enable is true.
+ * \sa forceAlignedAccess(), class ForceAlignedAccess
+ */
+template<typename Derived>
+template<bool Enable>
+inline typename internal::add_const_on_value_type<typename internal::conditional<Enable,ForceAlignedAccess<Derived>,Derived&>::type>::type
+MatrixBase<Derived>::forceAlignedAccessIf() const
+{
+ return derived();
+}
+
+/** \returns an expression of *this with forced aligned access if \a Enable is true.
+ * \sa forceAlignedAccess(), class ForceAlignedAccess
+ */
+template<typename Derived>
+template<bool Enable>
+inline typename internal::conditional<Enable,ForceAlignedAccess<Derived>,Derived&>::type
+MatrixBase<Derived>::forceAlignedAccessIf()
+{
+ return derived();
+}
+
+} // end namespace Eigen
+
+#endif // EIGEN_FORCEALIGNEDACCESS_H
diff --git a/Eigen/src/Core/Functors.h b/Eigen/src/Core/Functors.h
new file mode 100644
index 000000000..278c46c6b
--- /dev/null
+++ b/Eigen/src/Core/Functors.h
@@ -0,0 +1,989 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra.
+//
+// Copyright (C) 2008-2010 Gael Guennebaud <gael.guennebaud@inria.fr>
+//
+// This Source Code Form is subject to the terms of the Mozilla
+// Public License v. 2.0. If 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<typename Scalar> 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<typename Packet>
+ EIGEN_STRONG_INLINE const Packet packetOp(const Packet& a, const Packet& b) const
+ { return internal::padd(a,b); }
+ template<typename Packet>
+ EIGEN_STRONG_INLINE const Scalar predux(const Packet& a) const
+ { return internal::predux(a); }
+};
+template<typename Scalar>
+struct functor_traits<scalar_sum_op<Scalar> > {
+ enum {
+ Cost = NumTraits<Scalar>::AddCost,
+ PacketAccess = packet_traits<Scalar>::HasAdd
+ };
+};
+
+/** \internal
+ * \brief Template functor to compute the product of two scalars
+ *
+ * \sa class CwiseBinaryOp, Cwise::operator*(), class VectorwiseOp, MatrixBase::redux()
+ */
+template<typename LhsScalar,typename RhsScalar> struct scalar_product_op {
+ enum {
+ // TODO vectorize mixed product
+ Vectorizable = is_same<LhsScalar,RhsScalar>::value && packet_traits<LhsScalar>::HasMul && packet_traits<RhsScalar>::HasMul
+ };
+ typedef typename scalar_product_traits<LhsScalar,RhsScalar>::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<typename Packet>
+ EIGEN_STRONG_INLINE const Packet packetOp(const Packet& a, const Packet& b) const
+ { return internal::pmul(a,b); }
+ template<typename Packet>
+ EIGEN_STRONG_INLINE const result_type predux(const Packet& a) const
+ { return internal::predux_mul(a); }
+};
+template<typename LhsScalar,typename RhsScalar>
+struct functor_traits<scalar_product_op<LhsScalar,RhsScalar> > {
+ enum {
+ Cost = (NumTraits<LhsScalar>::MulCost + NumTraits<RhsScalar>::MulCost)/2, // rough estimate!
+ PacketAccess = scalar_product_op<LhsScalar,RhsScalar>::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<typename LhsScalar,typename RhsScalar> struct scalar_conj_product_op {
+
+ enum {
+ Conj = NumTraits<LhsScalar>::IsComplex
+ };
+
+ typedef typename scalar_product_traits<LhsScalar,RhsScalar>::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<LhsScalar,RhsScalar,Conj,false>().pmul(a,b); }
+
+ template<typename Packet>
+ EIGEN_STRONG_INLINE const Packet packetOp(const Packet& a, const Packet& b) const
+ { return conj_helper<Packet,Packet,Conj,false>().pmul(a,b); }
+};
+template<typename LhsScalar,typename RhsScalar>
+struct functor_traits<scalar_conj_product_op<LhsScalar,RhsScalar> > {
+ enum {
+ Cost = NumTraits<LhsScalar>::MulCost,
+ PacketAccess = internal::is_same<LhsScalar, RhsScalar>::value && packet_traits<LhsScalar>::HasMul
+ };
+};
+
+/** \internal
+ * \brief Template functor to compute the min of two scalars
+ *
+ * \sa class CwiseBinaryOp, MatrixBase::cwiseMin, class VectorwiseOp, MatrixBase::minCoeff()
+ */
+template<typename Scalar> 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<typename Packet>
+ EIGEN_STRONG_INLINE const Packet packetOp(const Packet& a, const Packet& b) const
+ { return internal::pmin(a,b); }
+ template<typename Packet>
+ EIGEN_STRONG_INLINE const Scalar predux(const Packet& a) const
+ { return internal::predux_min(a); }
+};
+template<typename Scalar>
+struct functor_traits<scalar_min_op<Scalar> > {
+ enum {
+ Cost = NumTraits<Scalar>::AddCost,
+ PacketAccess = packet_traits<Scalar>::HasMin
+ };
+};
+
+/** \internal
+ * \brief Template functor to compute the max of two scalars
+ *
+ * \sa class CwiseBinaryOp, MatrixBase::cwiseMax, class VectorwiseOp, MatrixBase::maxCoeff()
+ */
+template<typename Scalar> 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<typename Packet>
+ EIGEN_STRONG_INLINE const Packet packetOp(const Packet& a, const Packet& b) const
+ { return internal::pmax(a,b); }
+ template<typename Packet>
+ EIGEN_STRONG_INLINE const Scalar predux(const Packet& a) const
+ { return internal::predux_max(a); }
+};
+template<typename Scalar>
+struct functor_traits<scalar_max_op<Scalar> > {
+ enum {
+ Cost = NumTraits<Scalar>::AddCost,
+ PacketAccess = packet_traits<Scalar>::HasMax
+ };
+};
+
+/** \internal
+ * \brief Template functor to compute the hypot of two scalars
+ *
+ * \sa MatrixBase::stableNorm(), class Redux
+ */
+template<typename Scalar> struct scalar_hypot_op {
+ EIGEN_EMPTY_STRUCT_CTOR(scalar_hypot_op)
+// typedef typename NumTraits<Scalar>::Real result_type;
+ EIGEN_STRONG_INLINE const Scalar operator() (const Scalar& _x, const Scalar& _y) const
+ {
+ using std::max;
+ using std::min;
+ Scalar p = (max)(_x, _y);
+ Scalar q = (min)(_x, _y);
+ Scalar qp = q/p;
+ return p * sqrt(Scalar(1) + qp*qp);
+ }
+};
+template<typename Scalar>
+struct functor_traits<scalar_hypot_op<Scalar> > {
+ enum { Cost = 5 * NumTraits<Scalar>::MulCost, PacketAccess=0 };
+};
+
+/** \internal
+ * \brief Template functor to compute the pow of two scalars
+ */
+template<typename Scalar, typename OtherScalar> struct scalar_binary_pow_op {
+ EIGEN_EMPTY_STRUCT_CTOR(scalar_binary_pow_op)
+ inline Scalar operator() (const Scalar& a, const OtherScalar& b) const { return internal::pow(a, b); }
+};
+template<typename Scalar, typename OtherScalar>
+struct functor_traits<scalar_binary_pow_op<Scalar,OtherScalar> > {
+ enum { Cost = 5 * NumTraits<Scalar>::MulCost, PacketAccess = false };
+};
+
+// other binary functors:
+
+/** \internal
+ * \brief Template functor to compute the difference of two scalars
+ *
+ * \sa class CwiseBinaryOp, MatrixBase::operator-
+ */
+template<typename Scalar> 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<typename Packet>
+ EIGEN_STRONG_INLINE const Packet packetOp(const Packet& a, const Packet& b) const
+ { return internal::psub(a,b); }
+};
+template<typename Scalar>
+struct functor_traits<scalar_difference_op<Scalar> > {
+ enum {
+ Cost = NumTraits<Scalar>::AddCost,
+ PacketAccess = packet_traits<Scalar>::HasSub
+ };
+};
+
+/** \internal
+ * \brief Template functor to compute the quotient of two scalars
+ *
+ * \sa class CwiseBinaryOp, Cwise::operator/()
+ */
+template<typename Scalar> struct scalar_quotient_op {
+ EIGEN_EMPTY_STRUCT_CTOR(scalar_quotient_op)
+ EIGEN_STRONG_INLINE const Scalar operator() (const Scalar& a, const Scalar& b) const { return a / b; }
+ template<typename Packet>
+ EIGEN_STRONG_INLINE const Packet packetOp(const Packet& a, const Packet& b) const
+ { return internal::pdiv(a,b); }
+};
+template<typename Scalar>
+struct functor_traits<scalar_quotient_op<Scalar> > {
+ enum {
+ Cost = 2 * NumTraits<Scalar>::MulCost,
+ PacketAccess = packet_traits<Scalar>::HasDiv
+ };
+};
+
+/** \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<scalar_boolean_and_op> {
+ enum {
+ Cost = NumTraits<bool>::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<scalar_boolean_or_op> {
+ enum {
+ Cost = NumTraits<bool>::AddCost,
+ PacketAccess = false
+ };
+};
+
+// unary functors:
+
+/** \internal
+ * \brief Template functor to compute the opposite of a scalar
+ *
+ * \sa class CwiseUnaryOp, MatrixBase::operator-
+ */
+template<typename Scalar> struct scalar_opposite_op {
+ EIGEN_EMPTY_STRUCT_CTOR(scalar_opposite_op)
+ EIGEN_STRONG_INLINE const Scalar operator() (const Scalar& a) const { return -a; }
+ template<typename Packet>
+ EIGEN_STRONG_INLINE const Packet packetOp(const Packet& a) const
+ { return internal::pnegate(a); }
+};
+template<typename Scalar>
+struct functor_traits<scalar_opposite_op<Scalar> >
+{ enum {
+ Cost = NumTraits<Scalar>::AddCost,
+ PacketAccess = packet_traits<Scalar>::HasNegate };
+};
+
+/** \internal
+ * \brief Template functor to compute the absolute value of a scalar
+ *
+ * \sa class CwiseUnaryOp, Cwise::abs
+ */
+template<typename Scalar> struct scalar_abs_op {
+ EIGEN_EMPTY_STRUCT_CTOR(scalar_abs_op)
+ typedef typename NumTraits<Scalar>::Real result_type;
+ EIGEN_STRONG_INLINE const result_type operator() (const Scalar& a) const { return internal::abs(a); }
+ template<typename Packet>
+ EIGEN_STRONG_INLINE const Packet packetOp(const Packet& a) const
+ { return internal::pabs(a); }
+};
+template<typename Scalar>
+struct functor_traits<scalar_abs_op<Scalar> >
+{
+ enum {
+ Cost = NumTraits<Scalar>::AddCost,
+ PacketAccess = packet_traits<Scalar>::HasAbs
+ };
+};
+
+/** \internal
+ * \brief Template functor to compute the squared absolute value of a scalar
+ *
+ * \sa class CwiseUnaryOp, Cwise::abs2
+ */
+template<typename Scalar> struct scalar_abs2_op {
+ EIGEN_EMPTY_STRUCT_CTOR(scalar_abs2_op)
+ typedef typename NumTraits<Scalar>::Real result_type;
+ EIGEN_STRONG_INLINE const result_type operator() (const Scalar& a) const { return internal::abs2(a); }
+ template<typename Packet>
+ EIGEN_STRONG_INLINE const Packet packetOp(const Packet& a) const
+ { return internal::pmul(a,a); }
+};
+template<typename Scalar>
+struct functor_traits<scalar_abs2_op<Scalar> >
+{ enum { Cost = NumTraits<Scalar>::MulCost, PacketAccess = packet_traits<Scalar>::HasAbs2 }; };
+
+/** \internal
+ * \brief Template functor to compute the conjugate of a complex value
+ *
+ * \sa class CwiseUnaryOp, MatrixBase::conjugate()
+ */
+template<typename Scalar> struct scalar_conjugate_op {
+ EIGEN_EMPTY_STRUCT_CTOR(scalar_conjugate_op)
+ EIGEN_STRONG_INLINE const Scalar operator() (const Scalar& a) const { return internal::conj(a); }
+ template<typename Packet>
+ EIGEN_STRONG_INLINE const Packet packetOp(const Packet& a) const { return internal::pconj(a); }
+};
+template<typename Scalar>
+struct functor_traits<scalar_conjugate_op<Scalar> >
+{
+ enum {
+ Cost = NumTraits<Scalar>::IsComplex ? NumTraits<Scalar>::AddCost : 0,
+ PacketAccess = packet_traits<Scalar>::HasConj
+ };
+};
+
+/** \internal
+ * \brief Template functor to cast a scalar to another type
+ *
+ * \sa class CwiseUnaryOp, MatrixBase::cast()
+ */
+template<typename Scalar, typename NewType>
+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<Scalar, NewType>(a); }
+};
+template<typename Scalar, typename NewType>
+struct functor_traits<scalar_cast_op<Scalar,NewType> >
+{ enum { Cost = is_same<Scalar, NewType>::value ? 0 : NumTraits<NewType>::AddCost, PacketAccess = false }; };
+
+/** \internal
+ * \brief Template functor to extract the real part of a complex
+ *
+ * \sa class CwiseUnaryOp, MatrixBase::real()
+ */
+template<typename Scalar>
+struct scalar_real_op {
+ EIGEN_EMPTY_STRUCT_CTOR(scalar_real_op)
+ typedef typename NumTraits<Scalar>::Real result_type;
+ EIGEN_STRONG_INLINE result_type operator() (const Scalar& a) const { return internal::real(a); }
+};
+template<typename Scalar>
+struct functor_traits<scalar_real_op<Scalar> >
+{ enum { Cost = 0, PacketAccess = false }; };
+
+/** \internal
+ * \brief Template functor to extract the imaginary part of a complex
+ *
+ * \sa class CwiseUnaryOp, MatrixBase::imag()
+ */
+template<typename Scalar>
+struct scalar_imag_op {
+ EIGEN_EMPTY_STRUCT_CTOR(scalar_imag_op)
+ typedef typename NumTraits<Scalar>::Real result_type;
+ EIGEN_STRONG_INLINE result_type operator() (const Scalar& a) const { return internal::imag(a); }
+};
+template<typename Scalar>
+struct functor_traits<scalar_imag_op<Scalar> >
+{ 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<typename Scalar>
+struct scalar_real_ref_op {
+ EIGEN_EMPTY_STRUCT_CTOR(scalar_real_ref_op)
+ typedef typename NumTraits<Scalar>::Real result_type;
+ EIGEN_STRONG_INLINE result_type& operator() (const Scalar& a) const { return internal::real_ref(*const_cast<Scalar*>(&a)); }
+};
+template<typename Scalar>
+struct functor_traits<scalar_real_ref_op<Scalar> >
+{ 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<typename Scalar>
+struct scalar_imag_ref_op {
+ EIGEN_EMPTY_STRUCT_CTOR(scalar_imag_ref_op)
+ typedef typename NumTraits<Scalar>::Real result_type;
+ EIGEN_STRONG_INLINE result_type& operator() (const Scalar& a) const { return internal::imag_ref(*const_cast<Scalar*>(&a)); }
+};
+template<typename Scalar>
+struct functor_traits<scalar_imag_ref_op<Scalar> >
+{ enum { Cost = 0, PacketAccess = false }; };
+
+/** \internal
+ *
+ * \brief Template functor to compute the exponential of a scalar
+ *
+ * \sa class CwiseUnaryOp, Cwise::exp()
+ */
+template<typename Scalar> struct scalar_exp_op {
+ EIGEN_EMPTY_STRUCT_CTOR(scalar_exp_op)
+ inline const Scalar operator() (const Scalar& a) const { return internal::exp(a); }
+ typedef typename packet_traits<Scalar>::type Packet;
+ inline Packet packetOp(const Packet& a) const { return internal::pexp(a); }
+};
+template<typename Scalar>
+struct functor_traits<scalar_exp_op<Scalar> >
+{ enum { Cost = 5 * NumTraits<Scalar>::MulCost, PacketAccess = packet_traits<Scalar>::HasExp }; };
+
+/** \internal
+ *
+ * \brief Template functor to compute the logarithm of a scalar
+ *
+ * \sa class CwiseUnaryOp, Cwise::log()
+ */
+template<typename Scalar> struct scalar_log_op {
+ EIGEN_EMPTY_STRUCT_CTOR(scalar_log_op)
+ inline const Scalar operator() (const Scalar& a) const { return internal::log(a); }
+ typedef typename packet_traits<Scalar>::type Packet;
+ inline Packet packetOp(const Packet& a) const { return internal::plog(a); }
+};
+template<typename Scalar>
+struct functor_traits<scalar_log_op<Scalar> >
+{ enum { Cost = 5 * NumTraits<Scalar>::MulCost, PacketAccess = packet_traits<Scalar>::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() away 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<typename Scalar>
+struct scalar_multiple_op {
+ typedef typename packet_traits<Scalar>::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<Packet>(m_other)); }
+ typename add_const_on_value_type<typename NumTraits<Scalar>::Nested>::type m_other;
+};
+template<typename Scalar>
+struct functor_traits<scalar_multiple_op<Scalar> >
+{ enum { Cost = NumTraits<Scalar>::MulCost, PacketAccess = packet_traits<Scalar>::HasMul }; };
+
+template<typename Scalar1, typename Scalar2>
+struct scalar_multiple2_op {
+ typedef typename scalar_product_traits<Scalar1,Scalar2>::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<typename NumTraits<Scalar2>::Nested>::type m_other;
+};
+template<typename Scalar1,typename Scalar2>
+struct functor_traits<scalar_multiple2_op<Scalar1,Scalar2> >
+{ enum { Cost = NumTraits<Scalar1>::MulCost, PacketAccess = false }; };
+
+template<typename Scalar, bool IsInteger>
+struct scalar_quotient1_impl {
+ typedef typename packet_traits<Scalar>::type Packet;
+ // FIXME default copy constructors seems bugged with std::complex<>
+ EIGEN_STRONG_INLINE scalar_quotient1_impl(const scalar_quotient1_impl& other) : m_other(other.m_other) { }
+ EIGEN_STRONG_INLINE scalar_quotient1_impl(const Scalar& other) : m_other(static_cast<Scalar>(1) / 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<Packet>(m_other)); }
+ const Scalar m_other;
+};
+template<typename Scalar>
+struct functor_traits<scalar_quotient1_impl<Scalar,false> >
+{ enum { Cost = NumTraits<Scalar>::MulCost, PacketAccess = packet_traits<Scalar>::HasMul }; };
+
+template<typename Scalar>
+struct scalar_quotient1_impl<Scalar,true> {
+ // FIXME default copy constructors seems bugged with std::complex<>
+ EIGEN_STRONG_INLINE scalar_quotient1_impl(const scalar_quotient1_impl& other) : m_other(other.m_other) { }
+ EIGEN_STRONG_INLINE scalar_quotient1_impl(const Scalar& other) : m_other(other) {}
+ EIGEN_STRONG_INLINE Scalar operator() (const Scalar& a) const { return a / m_other; }
+ typename add_const_on_value_type<typename NumTraits<Scalar>::Nested>::type m_other;
+};
+template<typename Scalar>
+struct functor_traits<scalar_quotient1_impl<Scalar,true> >
+{ enum { Cost = 2 * NumTraits<Scalar>::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<typename Scalar>
+struct scalar_quotient1_op : scalar_quotient1_impl<Scalar, NumTraits<Scalar>::IsInteger > {
+ EIGEN_STRONG_INLINE scalar_quotient1_op(const Scalar& other)
+ : scalar_quotient1_impl<Scalar, NumTraits<Scalar>::IsInteger >(other) {}
+};
+template<typename Scalar>
+struct functor_traits<scalar_quotient1_op<Scalar> >
+: functor_traits<scalar_quotient1_impl<Scalar, NumTraits<Scalar>::IsInteger> >
+{};
+
+// nullary functors
+
+template<typename Scalar>
+struct scalar_constant_op {
+ typedef typename packet_traits<Scalar>::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<typename Index>
+ EIGEN_STRONG_INLINE const Scalar operator() (Index, Index = 0) const { return m_other; }
+ template<typename Index>
+ EIGEN_STRONG_INLINE const Packet packetOp(Index, Index = 0) const { return internal::pset1<Packet>(m_other); }
+ const Scalar m_other;
+};
+template<typename Scalar>
+struct functor_traits<scalar_constant_op<Scalar> >
+// FIXME replace this packet test by a safe one
+{ enum { Cost = 1, PacketAccess = packet_traits<Scalar>::Vectorizable, IsRepeatable = true }; };
+
+template<typename Scalar> struct scalar_identity_op {
+ EIGEN_EMPTY_STRUCT_CTOR(scalar_identity_op)
+ template<typename Index>
+ EIGEN_STRONG_INLINE const Scalar operator() (Index row, Index col) const { return row==col ? Scalar(1) : Scalar(0); }
+};
+template<typename Scalar>
+struct functor_traits<scalar_identity_op<Scalar> >
+{ enum { Cost = NumTraits<Scalar>::AddCost, PacketAccess = false, IsRepeatable = true }; };
+
+template <typename Scalar, bool RandomAccess> struct linspaced_op_impl;
+
+// linear access for packet ops:
+// 1) initialization
+// base = [low, ..., low] + ([step, ..., step] * [-size, ..., 0])
+// 2) each step
+// base += [size*step, ..., size*step]
+template <typename Scalar>
+struct linspaced_op_impl<Scalar,false>
+{
+ typedef typename packet_traits<Scalar>::type Packet;
+
+ linspaced_op_impl(Scalar low, Scalar step) :
+ m_low(low), m_step(step),
+ m_packetStep(pset1<Packet>(packet_traits<Scalar>::size*step)),
+ m_base(padd(pset1<Packet>(low),pmul(pset1<Packet>(step),plset<Scalar>(-packet_traits<Scalar>::size)))) {}
+
+ template<typename Index>
+ EIGEN_STRONG_INLINE const Scalar operator() (Index i) const { return m_low+i*m_step; }
+ template<typename Index>
+ 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 <typename Scalar>
+struct linspaced_op_impl<Scalar,true>
+{
+ typedef typename packet_traits<Scalar>::type Packet;
+
+ linspaced_op_impl(Scalar low, Scalar step) :
+ m_low(low), m_step(step),
+ m_lowPacket(pset1<Packet>(m_low)), m_stepPacket(pset1<Packet>(m_step)), m_interPacket(plset<Scalar>(0)) {}
+
+ template<typename Index>
+ EIGEN_STRONG_INLINE const Scalar operator() (Index i) const { return m_low+i*m_step; }
+
+ template<typename Index>
+ EIGEN_STRONG_INLINE const Packet packetOp(Index i) const
+ { return internal::padd(m_lowPacket, pmul(m_stepPacket, padd(pset1<Packet>(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 <typename Scalar, bool RandomAccess = true> struct linspaced_op;
+template <typename Scalar, bool RandomAccess> struct functor_traits< linspaced_op<Scalar,RandomAccess> >
+{ enum { Cost = 1, PacketAccess = packet_traits<Scalar>::HasSetLinear, IsRepeatable = true }; };
+template <typename Scalar, bool RandomAccess> struct linspaced_op
+{
+ typedef typename packet_traits<Scalar>::type Packet;
+ linspaced_op(Scalar low, Scalar high, int num_steps) : impl((num_steps==1 ? high : low), (num_steps==1 ? Scalar() : (high-low)/(num_steps-1))) {}
+
+ template<typename Index>
+ 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<typename Index>
+ EIGEN_STRONG_INLINE const Scalar operator() (Index row, Index col) const
+ {
+ eigen_assert(col==0 || row==0);
+ return impl(col + row);
+ }
+
+ template<typename Index>
+ 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<typename Index>
+ 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<Scalar,RandomAccess> 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<typename Functor> struct functor_has_linear_access { enum { ret = 1 }; };
+template<typename Scalar> struct functor_has_linear_access<scalar_identity_op<Scalar> > { enum { ret = 0 }; };
+
+// in CwiseBinaryOp, we require the Lhs and Rhs to have the same scalar type, except for multiplication
+// where we only require them to have the same _real_ scalar type so one may multiply, say, float by complex<float>.
+// FIXME move this to functor_traits adding a functor_default
+template<typename Functor> struct functor_allows_mixing_real_and_complex { enum { ret = 0 }; };
+template<typename LhsScalar,typename RhsScalar> struct functor_allows_mixing_real_and_complex<scalar_product_op<LhsScalar,RhsScalar> > { enum { ret = 1 }; };
+template<typename LhsScalar,typename RhsScalar> struct functor_allows_mixing_real_and_complex<scalar_conj_product_op<LhsScalar,RhsScalar> > { 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<typename Scalar>
+struct scalar_add_op {
+ typedef typename packet_traits<Scalar>::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<Packet>(m_other)); }
+ const Scalar m_other;
+};
+template<typename Scalar>
+struct functor_traits<scalar_add_op<Scalar> >
+{ enum { Cost = NumTraits<Scalar>::AddCost, PacketAccess = packet_traits<Scalar>::HasAdd }; };
+
+/** \internal
+ * \brief Template functor to compute the square root of a scalar
+ * \sa class CwiseUnaryOp, Cwise::sqrt()
+ */
+template<typename Scalar> struct scalar_sqrt_op {
+ EIGEN_EMPTY_STRUCT_CTOR(scalar_sqrt_op)
+ inline const Scalar operator() (const Scalar& a) const { return internal::sqrt(a); }
+ typedef typename packet_traits<Scalar>::type Packet;
+ inline Packet packetOp(const Packet& a) const { return internal::psqrt(a); }
+};
+template<typename Scalar>
+struct functor_traits<scalar_sqrt_op<Scalar> >
+{ enum {
+ Cost = 5 * NumTraits<Scalar>::MulCost,
+ PacketAccess = packet_traits<Scalar>::HasSqrt
+ };
+};
+
+/** \internal
+ * \brief Template functor to compute the cosine of a scalar
+ * \sa class CwiseUnaryOp, ArrayBase::cos()
+ */
+template<typename Scalar> struct scalar_cos_op {
+ EIGEN_EMPTY_STRUCT_CTOR(scalar_cos_op)
+ inline Scalar operator() (const Scalar& a) const { return internal::cos(a); }
+ typedef typename packet_traits<Scalar>::type Packet;
+ inline Packet packetOp(const Packet& a) const { return internal::pcos(a); }
+};
+template<typename Scalar>
+struct functor_traits<scalar_cos_op<Scalar> >
+{
+ enum {
+ Cost = 5 * NumTraits<Scalar>::MulCost,
+ PacketAccess = packet_traits<Scalar>::HasCos
+ };
+};
+
+/** \internal
+ * \brief Template functor to compute the sine of a scalar
+ * \sa class CwiseUnaryOp, ArrayBase::sin()
+ */
+template<typename Scalar> struct scalar_sin_op {
+ EIGEN_EMPTY_STRUCT_CTOR(scalar_sin_op)
+ inline const Scalar operator() (const Scalar& a) const { return internal::sin(a); }
+ typedef typename packet_traits<Scalar>::type Packet;
+ inline Packet packetOp(const Packet& a) const { return internal::psin(a); }
+};
+template<typename Scalar>
+struct functor_traits<scalar_sin_op<Scalar> >
+{
+ enum {
+ Cost = 5 * NumTraits<Scalar>::MulCost,
+ PacketAccess = packet_traits<Scalar>::HasSin
+ };
+};
+
+
+/** \internal
+ * \brief Template functor to compute the tan of a scalar
+ * \sa class CwiseUnaryOp, ArrayBase::tan()
+ */
+template<typename Scalar> struct scalar_tan_op {
+ EIGEN_EMPTY_STRUCT_CTOR(scalar_tan_op)
+ inline const Scalar operator() (const Scalar& a) const { return internal::tan(a); }
+ typedef typename packet_traits<Scalar>::type Packet;
+ inline Packet packetOp(const Packet& a) const { return internal::ptan(a); }
+};
+template<typename Scalar>
+struct functor_traits<scalar_tan_op<Scalar> >
+{
+ enum {
+ Cost = 5 * NumTraits<Scalar>::MulCost,
+ PacketAccess = packet_traits<Scalar>::HasTan
+ };
+};
+
+/** \internal
+ * \brief Template functor to compute the arc cosine of a scalar
+ * \sa class CwiseUnaryOp, ArrayBase::acos()
+ */
+template<typename Scalar> struct scalar_acos_op {
+ EIGEN_EMPTY_STRUCT_CTOR(scalar_acos_op)
+ inline const Scalar operator() (const Scalar& a) const { return internal::acos(a); }
+ typedef typename packet_traits<Scalar>::type Packet;
+ inline Packet packetOp(const Packet& a) const { return internal::pacos(a); }
+};
+template<typename Scalar>
+struct functor_traits<scalar_acos_op<Scalar> >
+{
+ enum {
+ Cost = 5 * NumTraits<Scalar>::MulCost,
+ PacketAccess = packet_traits<Scalar>::HasACos
+ };
+};
+
+/** \internal
+ * \brief Template functor to compute the arc sine of a scalar
+ * \sa class CwiseUnaryOp, ArrayBase::asin()
+ */
+template<typename Scalar> struct scalar_asin_op {
+ EIGEN_EMPTY_STRUCT_CTOR(scalar_asin_op)
+ inline const Scalar operator() (const Scalar& a) const { return internal::asin(a); }
+ typedef typename packet_traits<Scalar>::type Packet;
+ inline Packet packetOp(const Packet& a) const { return internal::pasin(a); }
+};
+template<typename Scalar>
+struct functor_traits<scalar_asin_op<Scalar> >
+{
+ enum {
+ Cost = 5 * NumTraits<Scalar>::MulCost,
+ PacketAccess = packet_traits<Scalar>::HasASin
+ };
+};
+
+/** \internal
+ * \brief Template functor to raise a scalar to a power
+ * \sa class CwiseUnaryOp, Cwise::pow
+ */
+template<typename Scalar>
+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 internal::pow(a, m_exponent); }
+ const Scalar m_exponent;
+};
+template<typename Scalar>
+struct functor_traits<scalar_pow_op<Scalar> >
+{ enum { Cost = 5 * NumTraits<Scalar>::MulCost, PacketAccess = false }; };
+
+/** \internal
+ * \brief Template functor to compute the quotient between a scalar and array entries.
+ * \sa class CwiseUnaryOp, Cwise::inverse()
+ */
+template<typename Scalar>
+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<typename Packet>
+ inline const Packet packetOp(const Packet& a) const
+ { return internal::pdiv(pset1<Packet>(m_other),a); }
+ Scalar m_other;
+};
+
+/** \internal
+ * \brief Template functor to compute the inverse of a scalar
+ * \sa class CwiseUnaryOp, Cwise::inverse()
+ */
+template<typename Scalar>
+struct scalar_inverse_op {
+ EIGEN_EMPTY_STRUCT_CTOR(scalar_inverse_op)
+ inline Scalar operator() (const Scalar& a) const { return Scalar(1)/a; }
+ template<typename Packet>
+ inline const Packet packetOp(const Packet& a) const
+ { return internal::pdiv(pset1<Packet>(Scalar(1)),a); }
+};
+template<typename Scalar>
+struct functor_traits<scalar_inverse_op<Scalar> >
+{ enum { Cost = NumTraits<Scalar>::MulCost, PacketAccess = packet_traits<Scalar>::HasDiv }; };
+
+/** \internal
+ * \brief Template functor to compute the square of a scalar
+ * \sa class CwiseUnaryOp, Cwise::square()
+ */
+template<typename Scalar>
+struct scalar_square_op {
+ EIGEN_EMPTY_STRUCT_CTOR(scalar_square_op)
+ inline Scalar operator() (const Scalar& a) const { return a*a; }
+ template<typename Packet>
+ inline const Packet packetOp(const Packet& a) const
+ { return internal::pmul(a,a); }
+};
+template<typename Scalar>
+struct functor_traits<scalar_square_op<Scalar> >
+{ enum { Cost = NumTraits<Scalar>::MulCost, PacketAccess = packet_traits<Scalar>::HasMul }; };
+
+/** \internal
+ * \brief Template functor to compute the cube of a scalar
+ * \sa class CwiseUnaryOp, Cwise::cube()
+ */
+template<typename Scalar>
+struct scalar_cube_op {
+ EIGEN_EMPTY_STRUCT_CTOR(scalar_cube_op)
+ inline Scalar operator() (const Scalar& a) const { return a*a*a; }
+ template<typename Packet>
+ inline const Packet packetOp(const Packet& a) const
+ { return internal::pmul(a,pmul(a,a)); }
+};
+template<typename Scalar>
+struct functor_traits<scalar_cube_op<Scalar> >
+{ enum { Cost = 2*NumTraits<Scalar>::MulCost, PacketAccess = packet_traits<Scalar>::HasMul }; };
+
+// default functor traits for STL functors:
+
+template<typename T>
+struct functor_traits<std::multiplies<T> >
+{ enum { Cost = NumTraits<T>::MulCost, PacketAccess = false }; };
+
+template<typename T>
+struct functor_traits<std::divides<T> >
+{ enum { Cost = NumTraits<T>::MulCost, PacketAccess = false }; };
+
+template<typename T>
+struct functor_traits<std::plus<T> >
+{ enum { Cost = NumTraits<T>::AddCost, PacketAccess = false }; };
+
+template<typename T>
+struct functor_traits<std::minus<T> >
+{ enum { Cost = NumTraits<T>::AddCost, PacketAccess = false }; };
+
+template<typename T>
+struct functor_traits<std::negate<T> >
+{ enum { Cost = NumTraits<T>::AddCost, PacketAccess = false }; };
+
+template<typename T>
+struct functor_traits<std::logical_or<T> >
+{ enum { Cost = 1, PacketAccess = false }; };
+
+template<typename T>
+struct functor_traits<std::logical_and<T> >
+{ enum { Cost = 1, PacketAccess = false }; };
+
+template<typename T>
+struct functor_traits<std::logical_not<T> >
+{ enum { Cost = 1, PacketAccess = false }; };
+
+template<typename T>
+struct functor_traits<std::greater<T> >
+{ enum { Cost = 1, PacketAccess = false }; };
+
+template<typename T>
+struct functor_traits<std::less<T> >
+{ enum { Cost = 1, PacketAccess = false }; };
+
+template<typename T>
+struct functor_traits<std::greater_equal<T> >
+{ enum { Cost = 1, PacketAccess = false }; };
+
+template<typename T>
+struct functor_traits<std::less_equal<T> >
+{ enum { Cost = 1, PacketAccess = false }; };
+
+template<typename T>
+struct functor_traits<std::equal_to<T> >
+{ enum { Cost = 1, PacketAccess = false }; };
+
+template<typename T>
+struct functor_traits<std::not_equal_to<T> >
+{ enum { Cost = 1, PacketAccess = false }; };
+
+template<typename T>
+struct functor_traits<std::binder2nd<T> >
+{ enum { Cost = functor_traits<T>::Cost, PacketAccess = false }; };
+
+template<typename T>
+struct functor_traits<std::binder1st<T> >
+{ enum { Cost = functor_traits<T>::Cost, PacketAccess = false }; };
+
+template<typename T>
+struct functor_traits<std::unary_negate<T> >
+{ enum { Cost = 1 + functor_traits<T>::Cost, PacketAccess = false }; };
+
+template<typename T>
+struct functor_traits<std::binary_negate<T> >
+{ enum { Cost = 1 + functor_traits<T>::Cost, PacketAccess = false }; };
+
+#ifdef EIGEN_STDEXT_SUPPORT
+
+template<typename T0,typename T1>
+struct functor_traits<std::project1st<T0,T1> >
+{ enum { Cost = 0, PacketAccess = false }; };
+
+template<typename T0,typename T1>
+struct functor_traits<std::project2nd<T0,T1> >
+{ enum { Cost = 0, PacketAccess = false }; };
+
+template<typename T0,typename T1>
+struct functor_traits<std::select2nd<std::pair<T0,T1> > >
+{ enum { Cost = 0, PacketAccess = false }; };
+
+template<typename T0,typename T1>
+struct functor_traits<std::select1st<std::pair<T0,T1> > >
+{ enum { Cost = 0, PacketAccess = false }; };
+
+template<typename T0,typename T1>
+struct functor_traits<std::unary_compose<T0,T1> >
+{ enum { Cost = functor_traits<T0>::Cost + functor_traits<T1>::Cost, PacketAccess = false }; };
+
+template<typename T0,typename T1,typename T2>
+struct functor_traits<std::binary_compose<T0,T1,T2> >
+{ enum { Cost = functor_traits<T0>::Cost + functor_traits<T1>::Cost + functor_traits<T2>::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/Eigen/src/Core/Fuzzy.h b/Eigen/src/Core/Fuzzy.h
new file mode 100644
index 000000000..d74edcfdb
--- /dev/null
+++ b/Eigen/src/Core/Fuzzy.h
@@ -0,0 +1,150 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra.
+//
+// Copyright (C) 2006-2008 Benoit Jacob <jacob.benoit.1@gmail.com>
+// Copyright (C) 2008 Gael Guennebaud <gael.guennebaud@inria.fr>
+//
+// This Source Code Form is subject to the terms of the Mozilla
+// Public License v. 2.0. If a copy of the MPL was not distributed
+// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+#ifndef EIGEN_FUZZY_H
+#define EIGEN_FUZZY_H
+
+namespace Eigen {
+
+namespace internal
+{
+
+template<typename Derived, typename OtherDerived, bool is_integer = NumTraits<typename Derived::Scalar>::IsInteger>
+struct isApprox_selector
+{
+ static bool run(const Derived& x, const OtherDerived& y, typename Derived::RealScalar prec)
+ {
+ using std::min;
+ typename internal::nested<Derived,2>::type nested(x);
+ typename internal::nested<OtherDerived,2>::type otherNested(y);
+ return (nested - otherNested).cwiseAbs2().sum() <= prec * prec * (min)(nested.cwiseAbs2().sum(), otherNested.cwiseAbs2().sum());
+ }
+};
+
+template<typename Derived, typename OtherDerived>
+struct isApprox_selector<Derived, OtherDerived, true>
+{
+ static bool run(const Derived& x, const OtherDerived& y, typename Derived::RealScalar)
+ {
+ return x.matrix() == y.matrix();
+ }
+};
+
+template<typename Derived, typename OtherDerived, bool is_integer = NumTraits<typename Derived::Scalar>::IsInteger>
+struct isMuchSmallerThan_object_selector
+{
+ static bool run(const Derived& x, const OtherDerived& y, typename Derived::RealScalar prec)
+ {
+ return x.cwiseAbs2().sum() <= abs2(prec) * y.cwiseAbs2().sum();
+ }
+};
+
+template<typename Derived, typename OtherDerived>
+struct isMuchSmallerThan_object_selector<Derived, OtherDerived, true>
+{
+ static bool run(const Derived& x, const OtherDerived&, typename Derived::RealScalar)
+ {
+ return x.matrix() == Derived::Zero(x.rows(), x.cols()).matrix();
+ }
+};
+
+template<typename Derived, bool is_integer = NumTraits<typename Derived::Scalar>::IsInteger>
+struct isMuchSmallerThan_scalar_selector
+{
+ static bool run(const Derived& x, const typename Derived::RealScalar& y, typename Derived::RealScalar prec)
+ {
+ return x.cwiseAbs2().sum() <= abs2(prec * y);
+ }
+};
+
+template<typename Derived>
+struct isMuchSmallerThan_scalar_selector<Derived, true>
+{
+ static bool run(const Derived& x, const typename Derived::RealScalar&, typename Derived::RealScalar)
+ {
+ return x.matrix() == Derived::Zero(x.rows(), x.cols()).matrix();
+ }
+};
+
+} // end namespace internal
+
+
+/** \returns \c true if \c *this is approximately equal to \a other, within the precision
+ * determined by \a prec.
+ *
+ * \note The fuzzy compares are done multiplicatively. Two vectors \f$ v \f$ and \f$ w \f$
+ * are considered to be approximately equal within precision \f$ p \f$ if
+ * \f[ \Vert v - w \Vert \leqslant p\,\min(\Vert v\Vert, \Vert w\Vert). \f]
+ * For matrices, the comparison is done using the Hilbert-Schmidt norm (aka Frobenius norm
+ * L2 norm).
+ *
+ * \note Because of the multiplicativeness of this comparison, one can't use this function
+ * to check whether \c *this is approximately equal to the zero matrix or vector.
+ * Indeed, \c isApprox(zero) returns false unless \c *this itself is exactly the zero matrix
+ * or vector. If you want to test whether \c *this is zero, use internal::isMuchSmallerThan(const
+ * RealScalar&, RealScalar) instead.
+ *
+ * \sa internal::isMuchSmallerThan(const RealScalar&, RealScalar) const
+ */
+template<typename Derived>
+template<typename OtherDerived>
+bool DenseBase<Derived>::isApprox(
+ const DenseBase<OtherDerived>& other,
+ RealScalar prec
+) const
+{
+ return internal::isApprox_selector<Derived, OtherDerived>::run(derived(), other.derived(), prec);
+}
+
+/** \returns \c true if the norm of \c *this is much smaller than \a other,
+ * within the precision determined by \a prec.
+ *
+ * \note The fuzzy compares are done multiplicatively. A vector \f$ v \f$ is
+ * considered to be much smaller than \f$ x \f$ within precision \f$ p \f$ if
+ * \f[ \Vert v \Vert \leqslant p\,\vert x\vert. \f]
+ *
+ * For matrices, the comparison is done using the Hilbert-Schmidt norm. For this reason,
+ * the value of the reference scalar \a other should come from the Hilbert-Schmidt norm
+ * of a reference matrix of same dimensions.
+ *
+ * \sa isApprox(), isMuchSmallerThan(const DenseBase<OtherDerived>&, RealScalar) const
+ */
+template<typename Derived>
+bool DenseBase<Derived>::isMuchSmallerThan(
+ const typename NumTraits<Scalar>::Real& other,
+ RealScalar prec
+) const
+{
+ return internal::isMuchSmallerThan_scalar_selector<Derived>::run(derived(), other, prec);
+}
+
+/** \returns \c true if the norm of \c *this is much smaller than the norm of \a other,
+ * within the precision determined by \a prec.
+ *
+ * \note The fuzzy compares are done multiplicatively. A vector \f$ v \f$ is
+ * considered to be much smaller than a vector \f$ w \f$ within precision \f$ p \f$ if
+ * \f[ \Vert v \Vert \leqslant p\,\Vert w\Vert. \f]
+ * For matrices, the comparison is done using the Hilbert-Schmidt norm.
+ *
+ * \sa isApprox(), isMuchSmallerThan(const RealScalar&, RealScalar) const
+ */
+template<typename Derived>
+template<typename OtherDerived>
+bool DenseBase<Derived>::isMuchSmallerThan(
+ const DenseBase<OtherDerived>& other,
+ RealScalar prec
+) const
+{
+ return internal::isMuchSmallerThan_object_selector<Derived, OtherDerived>::run(derived(), other.derived(), prec);
+}
+
+} // end namespace Eigen
+
+#endif // EIGEN_FUZZY_H
diff --git a/Eigen/src/Core/GeneralProduct.h b/Eigen/src/Core/GeneralProduct.h
new file mode 100644
index 000000000..bfc2a67b1
--- /dev/null
+++ b/Eigen/src/Core/GeneralProduct.h
@@ -0,0 +1,613 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra.
+//
+// Copyright (C) 2006-2008 Benoit Jacob <jacob.benoit.1@gmail.com>
+// Copyright (C) 2008-2011 Gael Guennebaud <gael.guennebaud@inria.fr>
+//
+// This Source Code Form is subject to the terms of the Mozilla
+// Public License v. 2.0. If 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<OtherDerived>&)
+ */
+template<typename Lhs, typename Rhs, int ProductType = internal::product_type<Lhs,Rhs>::value>
+class GeneralProduct;
+
+enum {
+ Large = 2,
+ Small = 3
+};
+
+namespace internal {
+
+template<int Rows, int Cols, int Depth> struct product_type_selector;
+
+template<int Size, int MaxSize> struct product_size_category
+{
+ enum { is_large = MaxSize == Dynamic ||
+ Size >= EIGEN_CACHEFRIENDLY_PRODUCT_THRESHOLD,
+ value = is_large ? Large
+ : Size == 1 ? 1
+ : Small
+ };
+};
+
+template<typename Lhs, typename Rhs> struct product_type
+{
+ typedef typename remove_all<Lhs>::type _Lhs;
+ typedef typename remove_all<Rhs>::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<Rows,MaxRows>::value,
+ cols_select = product_size_category<Cols,MaxCols>::value,
+ depth_select = product_size_category<Depth,MaxDepth>::value
+ };
+ typedef product_type_selector<rows_select, cols_select, depth_select> 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<int M, int N> struct product_type_selector<M,N,1> { enum { ret = OuterProduct }; };
+template<int Depth> 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<Small,1, Small> { enum { ret = CoeffBasedProductMode }; };
+template<> struct product_type_selector<1, Small,Small> { enum { ret = CoeffBasedProductMode }; };
+template<> struct product_type_selector<Small,Small,Small> { enum { ret = CoeffBasedProductMode }; };
+template<> struct product_type_selector<Small, Small, 1> { enum { ret = LazyCoeffBasedProductMode }; };
+template<> struct product_type_selector<Small, Large, 1> { enum { ret = LazyCoeffBasedProductMode }; };
+template<> struct product_type_selector<Large, Small, 1> { 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<Large,1, Small> { enum { ret = CoeffBasedProductMode }; };
+template<> struct product_type_selector<Large,1, Large> { enum { ret = GemvProduct }; };
+template<> struct product_type_selector<Small,1, Large> { enum { ret = CoeffBasedProductMode }; };
+template<> struct product_type_selector<Small,Small,Large> { enum { ret = GemmProduct }; };
+template<> struct product_type_selector<Large,Small,Large> { enum { ret = GemmProduct }; };
+template<> struct product_type_selector<Small,Large,Large> { enum { ret = GemmProduct }; };
+template<> struct product_type_selector<Large,Large,Large> { enum { ret = GemmProduct }; };
+template<> struct product_type_selector<Large,Small,Small> { enum { ret = GemmProduct }; };
+template<> struct product_type_selector<Small,Large,Small> { enum { ret = GemmProduct }; };
+template<> struct product_type_selector<Large,Large,Small> { 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<Lhs,Rhs>::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<OtherDerived>&)
+ */
+template<typename Lhs, typename Rhs, int ProductType>
+struct ProductReturnType
+{
+ // TODO use the nested type to reduce instanciations ????
+// typedef typename internal::nested<Lhs,Rhs::ColsAtCompileTime>::type LhsNested;
+// typedef typename internal::nested<Rhs,Lhs::RowsAtCompileTime>::type RhsNested;
+
+ typedef GeneralProduct<Lhs/*Nested*/, Rhs/*Nested*/, ProductType> Type;
+};
+
+template<typename Lhs, typename Rhs>
+struct ProductReturnType<Lhs,Rhs,CoeffBasedProductMode>
+{
+ typedef typename internal::nested<Lhs, Rhs::ColsAtCompileTime, typename internal::plain_matrix_type<Lhs>::type >::type LhsNested;
+ typedef typename internal::nested<Rhs, Lhs::RowsAtCompileTime, typename internal::plain_matrix_type<Rhs>::type >::type RhsNested;
+ typedef CoeffBasedProduct<LhsNested, RhsNested, EvalBeforeAssigningBit | EvalBeforeNestingBit> Type;
+};
+
+template<typename Lhs, typename Rhs>
+struct ProductReturnType<Lhs,Rhs,LazyCoeffBasedProductMode>
+{
+ typedef typename internal::nested<Lhs, Rhs::ColsAtCompileTime, typename internal::plain_matrix_type<Lhs>::type >::type LhsNested;
+ typedef typename internal::nested<Rhs, Lhs::RowsAtCompileTime, typename internal::plain_matrix_type<Rhs>::type >::type RhsNested;
+ typedef CoeffBasedProduct<LhsNested, RhsNested, NestByRefBit> Type;
+};
+
+// this is a workaround for sun CC
+template<typename Lhs, typename Rhs>
+struct LazyProductReturnType : public ProductReturnType<Lhs,Rhs,LazyCoeffBasedProductMode>
+{};
+
+/***********************************************************************
+* 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<MatrixType,1,1> with: operator=(Scalar x);
+
+namespace internal {
+
+template<typename Lhs, typename Rhs>
+struct traits<GeneralProduct<Lhs,Rhs,InnerProduct> >
+ : traits<Matrix<typename scalar_product_traits<typename Lhs::Scalar, typename Rhs::Scalar>::ReturnType,1,1> >
+{};
+
+}
+
+template<typename Lhs, typename Rhs>
+class GeneralProduct<Lhs, Rhs, InnerProduct>
+ : internal::no_assignment_operator,
+ public Matrix<typename internal::scalar_product_traits<typename Lhs::Scalar, typename Rhs::Scalar>::ReturnType,1,1>
+{
+ typedef Matrix<typename internal::scalar_product_traits<typename Lhs::Scalar, typename Rhs::Scalar>::ReturnType,1,1> Base;
+ public:
+ GeneralProduct(const Lhs& lhs, const Rhs& rhs)
+ {
+ EIGEN_STATIC_ASSERT((internal::is_same<typename Lhs::RealScalar, typename Rhs::RealScalar>::value),
+ YOU_MIXED_DIFFERENT_NUMERIC_TYPES__YOU_NEED_TO_USE_THE_CAST_METHOD_OF_MATRIXBASE_TO_CAST_NUMERIC_TYPES_EXPLICITLY)
+
+ Base::coeffRef(0,0) = (lhs.transpose().cwiseProduct(rhs)).sum();
+ }
+
+ /** Convertion to scalar */
+ operator const typename Base::Scalar() const {
+ return Base::coeff(0,0);
+ }
+};
+
+/***********************************************************************
+* Implementation of Outer Vector Vector Product
+***********************************************************************/
+
+namespace internal {
+template<int StorageOrder> struct outer_product_selector;
+
+template<typename Lhs, typename Rhs>
+struct traits<GeneralProduct<Lhs,Rhs,OuterProduct> >
+ : traits<ProductBase<GeneralProduct<Lhs,Rhs,OuterProduct>, Lhs, Rhs> >
+{};
+
+}
+
+template<typename Lhs, typename Rhs>
+class GeneralProduct<Lhs, Rhs, OuterProduct>
+ : public ProductBase<GeneralProduct<Lhs,Rhs,OuterProduct>, Lhs, Rhs>
+{
+ public:
+ EIGEN_PRODUCT_PUBLIC_INTERFACE(GeneralProduct)
+
+ GeneralProduct(const Lhs& lhs, const Rhs& rhs) : Base(lhs,rhs)
+ {
+ EIGEN_STATIC_ASSERT((internal::is_same<typename Lhs::RealScalar, typename Rhs::RealScalar>::value),
+ YOU_MIXED_DIFFERENT_NUMERIC_TYPES__YOU_NEED_TO_USE_THE_CAST_METHOD_OF_MATRIXBASE_TO_CAST_NUMERIC_TYPES_EXPLICITLY)
+ }
+
+ template<typename Dest> void scaleAndAddTo(Dest& dest, Scalar alpha) const
+ {
+ internal::outer_product_selector<(int(Dest::Flags)&RowMajorBit) ? RowMajor : ColMajor>::run(*this, dest, alpha);
+ }
+};
+
+namespace internal {
+
+template<> struct outer_product_selector<ColMajor> {
+ template<typename ProductType, typename Dest>
+ static EIGEN_DONT_INLINE void run(const ProductType& prod, Dest& dest, typename ProductType::Scalar alpha) {
+ typedef typename Dest::Index Index;
+ // FIXME make sure lhs is sequentially stored
+ // FIXME not very good if rhs is real and lhs complex while alpha is real too
+ const Index cols = dest.cols();
+ for (Index j=0; j<cols; ++j)
+ dest.col(j) += (alpha * prod.rhs().coeff(j)) * prod.lhs();
+ }
+};
+
+template<> struct outer_product_selector<RowMajor> {
+ template<typename ProductType, typename Dest>
+ static EIGEN_DONT_INLINE void run(const ProductType& prod, Dest& dest, typename ProductType::Scalar alpha) {
+ typedef typename Dest::Index Index;
+ // FIXME make sure rhs is sequentially stored
+ // FIXME not very good if lhs is real and rhs complex while alpha is real too
+ const Index rows = dest.rows();
+ for (Index i=0; i<rows; ++i)
+ dest.row(i) += (alpha * prod.lhs().coeff(i)) * prod.rhs();
+ }
+};
+
+} // end namespace internal
+
+/***********************************************************************
+* 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<typename Lhs, typename Rhs>
+struct traits<GeneralProduct<Lhs,Rhs,GemvProduct> >
+ : traits<ProductBase<GeneralProduct<Lhs,Rhs,GemvProduct>, Lhs, Rhs> >
+{};
+
+template<int Side, int StorageOrder, bool BlasCompatible>
+struct gemv_selector;
+
+} // end namespace internal
+
+template<typename Lhs, typename Rhs>
+class GeneralProduct<Lhs, Rhs, GemvProduct>
+ : public ProductBase<GeneralProduct<Lhs,Rhs,GemvProduct>, Lhs, Rhs>
+{
+ public:
+ EIGEN_PRODUCT_PUBLIC_INTERFACE(GeneralProduct)
+
+ typedef typename Lhs::Scalar LhsScalar;
+ typedef typename Rhs::Scalar RhsScalar;
+
+ GeneralProduct(const Lhs& lhs, const Rhs& rhs) : Base(lhs,rhs)
+ {
+// EIGEN_STATIC_ASSERT((internal::is_same<typename Lhs::Scalar, typename Rhs::Scalar>::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<int(Side)==OnTheRight,_LhsNested,_RhsNested>::type MatrixType;
+
+ template<typename Dest> void scaleAndAddTo(Dest& dst, Scalar alpha) const
+ {
+ eigen_assert(m_lhs.rows() == dst.rows() && m_rhs.cols() == dst.cols());
+ internal::gemv_selector<Side,(int(MatrixType::Flags)&RowMajorBit) ? RowMajor : ColMajor,
+ bool(internal::blas_traits<MatrixType>::HasUsableDirectAccess)>::run(*this, dst, alpha);
+ }
+};
+
+namespace internal {
+
+// The vector is on the left => transposition
+template<int StorageOrder, bool BlasCompatible>
+struct gemv_selector<OnTheLeft,StorageOrder,BlasCompatible>
+{
+ template<typename ProductType, typename Dest>
+ static void run(const ProductType& prod, Dest& dest, typename ProductType::Scalar alpha)
+ {
+ Transpose<Dest> destT(dest);
+ enum { OtherStorageOrder = StorageOrder == RowMajor ? ColMajor : RowMajor };
+ gemv_selector<OnTheRight,OtherStorageOrder,BlasCompatible>
+ ::run(GeneralProduct<Transpose<const typename ProductType::_RhsNested>,Transpose<const typename ProductType::_LhsNested>, GemvProduct>
+ (prod.rhs().transpose(), prod.lhs().transpose()), destT, alpha);
+ }
+};
+
+template<typename Scalar,int Size,int MaxSize,bool Cond> struct gemv_static_vector_if;
+
+template<typename Scalar,int Size,int MaxSize>
+struct gemv_static_vector_if<Scalar,Size,MaxSize,false>
+{
+ EIGEN_STRONG_INLINE Scalar* data() { eigen_internal_assert(false && "should never be called"); return 0; }
+};
+
+template<typename Scalar,int Size>
+struct gemv_static_vector_if<Scalar,Size,Dynamic,true>
+{
+ EIGEN_STRONG_INLINE Scalar* data() { return 0; }
+};
+
+template<typename Scalar,int Size,int MaxSize>
+struct gemv_static_vector_if<Scalar,Size,MaxSize,true>
+{
+ #if EIGEN_ALIGN_STATICALLY
+ internal::plain_array<Scalar,EIGEN_SIZE_MIN_PREFER_FIXED(Size,MaxSize),0> 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<Scalar>::Vectorizable,
+ PacketSize = internal::packet_traits<Scalar>::size
+ };
+ internal::plain_array<Scalar,EIGEN_SIZE_MIN_PREFER_FIXED(Size,MaxSize)+(ForceAlignment?PacketSize:0),0> m_data;
+ EIGEN_STRONG_INLINE Scalar* data() {
+ return ForceAlignment
+ ? reinterpret_cast<Scalar*>((reinterpret_cast<size_t>(m_data.array) & ~(size_t(15))) + 16)
+ : m_data.array;
+ }
+ #endif
+};
+
+template<> struct gemv_selector<OnTheRight,ColMajor,true>
+{
+ template<typename ProductType, typename Dest>
+ static inline void run(const ProductType& prod, Dest& dest, typename ProductType::Scalar alpha)
+ {
+ typedef typename ProductType::Index Index;
+ typedef typename ProductType::LhsScalar LhsScalar;
+ typedef typename ProductType::RhsScalar RhsScalar;
+ typedef typename ProductType::Scalar ResScalar;
+ typedef typename ProductType::RealScalar RealScalar;
+ typedef typename ProductType::ActualLhsType ActualLhsType;
+ typedef typename ProductType::ActualRhsType ActualRhsType;
+ typedef typename ProductType::LhsBlasTraits LhsBlasTraits;
+ typedef typename ProductType::RhsBlasTraits RhsBlasTraits;
+ typedef Map<Matrix<ResScalar,Dynamic,1>, Aligned> MappedDest;
+
+ ActualLhsType actualLhs = LhsBlasTraits::extract(prod.lhs());
+ ActualRhsType actualRhs = RhsBlasTraits::extract(prod.rhs());
+
+ ResScalar actualAlpha = alpha * LhsBlasTraits::extractScalarFactor(prod.lhs())
+ * RhsBlasTraits::extractScalarFactor(prod.rhs());
+
+ enum {
+ // FIXME find a way to allow an inner stride on the result if packet_traits<Scalar>::size==1
+ // on, the other hand it is good for the cache to pack the vector anyways...
+ EvalToDestAtCompileTime = Dest::InnerStrideAtCompileTime==1,
+ ComplexByReal = (NumTraits<LhsScalar>::IsComplex) && (!NumTraits<RhsScalar>::IsComplex),
+ MightCannotUseDest = (Dest::InnerStrideAtCompileTime!=1) || ComplexByReal
+ };
+
+ gemv_static_vector_if<ResScalar,Dest::SizeAtCompileTime,Dest::MaxSizeAtCompileTime,MightCannotUseDest> static_dest;
+
+ bool alphaIsCompatible = (!ComplexByReal) || (imag(actualAlpha)==RealScalar(0));
+ bool evalToDest = EvalToDestAtCompileTime && alphaIsCompatible;
+
+ RhsScalar compatibleAlpha = get_factor<ResScalar,RhsScalar>::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
+ <Index,LhsScalar,ColMajor,LhsBlasTraits::NeedToConjugate,RhsScalar,RhsBlasTraits::NeedToConjugate>::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<OnTheRight,RowMajor,true>
+{
+ template<typename ProductType, typename Dest>
+ static void run(const ProductType& prod, Dest& dest, typename ProductType::Scalar alpha)
+ {
+ typedef typename ProductType::LhsScalar LhsScalar;
+ typedef typename ProductType::RhsScalar RhsScalar;
+ typedef typename ProductType::Scalar ResScalar;
+ typedef typename ProductType::Index Index;
+ typedef typename ProductType::ActualLhsType ActualLhsType;
+ typedef typename ProductType::ActualRhsType ActualRhsType;
+ typedef typename ProductType::_ActualRhsType _ActualRhsType;
+ typedef typename ProductType::LhsBlasTraits LhsBlasTraits;
+ typedef typename ProductType::RhsBlasTraits RhsBlasTraits;
+
+ typename add_const<ActualLhsType>::type actualLhs = LhsBlasTraits::extract(prod.lhs());
+ typename add_const<ActualRhsType>::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<Scalar>::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<RhsScalar,_ActualRhsType::SizeAtCompileTime,_ActualRhsType::MaxSizeAtCompileTime,!DirectlyUseRhs> static_rhs;
+
+ ei_declare_aligned_stack_constructed_variable(RhsScalar,actualRhsPtr,actualRhs.size(),
+ DirectlyUseRhs ? const_cast<RhsScalar*>(actualRhs.data()) : static_rhs.data());
+
+ if(!DirectlyUseRhs)
+ {
+ #ifdef EIGEN_DENSE_STORAGE_CTOR_PLUGIN
+ int size = actualRhs.size();
+ EIGEN_DENSE_STORAGE_CTOR_PLUGIN
+ #endif
+ Map<typename _ActualRhsType::PlainObject>(actualRhsPtr, actualRhs.size()) = actualRhs;
+ }
+
+ general_matrix_vector_product
+ <Index,LhsScalar,RowMajor,LhsBlasTraits::NeedToConjugate,RhsScalar,RhsBlasTraits::NeedToConjugate>::run(
+ actualLhs.rows(), actualLhs.cols(),
+ actualLhs.data(), actualLhs.outerStride(),
+ actualRhsPtr, 1,
+ dest.data(), dest.innerStride(),
+ actualAlpha);
+ }
+};
+
+template<> struct gemv_selector<OnTheRight,ColMajor,false>
+{
+ template<typename ProductType, typename Dest>
+ static void run(const ProductType& prod, Dest& dest, typename ProductType::Scalar alpha)
+ {
+ typedef typename Dest::Index Index;
+ // TODO makes sure dest is sequentially stored in memory, otherwise use a temp
+ const Index size = prod.rhs().rows();
+ for(Index k=0; k<size; ++k)
+ dest += (alpha*prod.rhs().coeff(k)) * prod.lhs().col(k);
+ }
+};
+
+template<> struct gemv_selector<OnTheRight,RowMajor,false>
+{
+ template<typename ProductType, typename Dest>
+ static void run(const ProductType& prod, Dest& dest, typename ProductType::Scalar alpha)
+ {
+ typedef typename Dest::Index Index;
+ // TODO makes sure rhs is sequentially stored in memory, otherwise use a temp
+ const Index rows = prod.rows();
+ for(Index i=0; i<rows; ++i)
+ dest.coeffRef(i) += alpha * (prod.lhs().row(i).cwiseProduct(prod.rhs().transpose())).sum();
+ }
+};
+
+} // end namespace internal
+
+/***************************************************************************
+* Implementation of matrix base methods
+***************************************************************************/
+
+/** \returns the matrix product of \c *this and \a other.
+ *
+ * \note If instead of the matrix product you want the coefficient-wise product, see Cwise::operator*().
+ *
+ * \sa lazyProduct(), operator*=(const MatrixBase&), Cwise::operator*()
+ */
+template<typename Derived>
+template<typename OtherDerived>
+inline const typename ProductReturnType<Derived, OtherDerived>::Type
+MatrixBase<Derived>::operator*(const MatrixBase<OtherDerived> &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<Derived,OtherDerived>::debug();
+#endif
+ return typename ProductReturnType<Derived,OtherDerived>::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<typename Derived>
+template<typename OtherDerived>
+const typename LazyProductReturnType<Derived,OtherDerived>::Type
+MatrixBase<Derived>::lazyProduct(const MatrixBase<OtherDerived> &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<Derived,OtherDerived>::Type(derived(), other.derived());
+}
+
+} // end namespace Eigen
+
+#endif // EIGEN_PRODUCT_H
diff --git a/Eigen/src/Core/GenericPacketMath.h b/Eigen/src/Core/GenericPacketMath.h
new file mode 100644
index 000000000..858fb243e
--- /dev/null
+++ b/Eigen/src/Core/GenericPacketMath.h
@@ -0,0 +1,328 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra.
+//
+// Copyright (C) 2008 Gael Guennebaud <gael.guennebaud@inria.fr>
+// Copyright (C) 2006-2008 Benoit Jacob <jacob.benoit.1@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 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<typename T> 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<typename Packet> inline Packet
+padd(const Packet& a,
+ const Packet& b) { return a+b; }
+
+/** \internal \returns a - b (coeff-wise) */
+template<typename Packet> inline Packet
+psub(const Packet& a,
+ const Packet& b) { return a-b; }
+
+/** \internal \returns -a (coeff-wise) */
+template<typename Packet> inline Packet
+pnegate(const Packet& a) { return -a; }
+
+/** \internal \returns conj(a) (coeff-wise) */
+template<typename Packet> inline Packet
+pconj(const Packet& a) { return conj(a); }
+
+/** \internal \returns a * b (coeff-wise) */
+template<typename Packet> inline Packet
+pmul(const Packet& a,
+ const Packet& b) { return a*b; }
+
+/** \internal \returns a / b (coeff-wise) */
+template<typename Packet> 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<typename Packet> 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<typename Packet> 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<typename Packet> inline Packet
+pabs(const Packet& a) { return abs(a); }
+
+/** \internal \returns the bitwise and of \a a and \a b */
+template<typename Packet> inline Packet
+pand(const Packet& a, const Packet& b) { return a & b; }
+
+/** \internal \returns the bitwise or of \a a and \a b */
+template<typename Packet> inline Packet
+por(const Packet& a, const Packet& b) { return a | b; }
+
+/** \internal \returns the bitwise xor of \a a and \a b */
+template<typename Packet> inline Packet
+pxor(const Packet& a, const Packet& b) { return a ^ b; }
+
+/** \internal \returns the bitwise andnot of \a a and \a b */
+template<typename Packet> 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<typename Packet> inline Packet
+pload(const typename unpacket_traits<Packet>::type* from) { return *from; }
+
+/** \internal \returns a packet version of \a *from, (un-aligned load) */
+template<typename Packet> inline Packet
+ploadu(const typename unpacket_traits<Packet>::type* from) { return *from; }
+
+/** \internal \returns a packet with elements of \a *from duplicated, e.g.: (from[0],from[0],from[1],from[1]) */
+template<typename Packet> inline Packet
+ploaddup(const typename unpacket_traits<Packet>::type* from) { return *from; }
+
+/** \internal \returns a packet with constant coefficients \a a, e.g.: (a,a,a,a) */
+template<typename Packet> inline Packet
+pset1(const typename unpacket_traits<Packet>::type& a) { return a; }
+
+/** \internal \brief Returns a packet with coefficients (a,a+1,...,a+packet_size-1). */
+template<typename Scalar> inline typename packet_traits<Scalar>::type
+plset(const Scalar& a) { return a; }
+
+/** \internal copy the packet \a from to \a *to, \a to must be 16 bytes aligned */
+template<typename Scalar, typename Packet> inline void pstore(Scalar* to, const Packet& from)
+{ (*to) = from; }
+
+/** \internal copy the packet \a from to \a *to, (un-aligned store) */
+template<typename Scalar, typename Packet> inline void pstoreu(Scalar* to, const Packet& from)
+{ (*to) = from; }
+
+/** \internal tries to do cache prefetching of \a addr */
+template<typename Scalar> inline void prefetch(const Scalar* addr)
+{
+#if !defined(_MSC_VER)
+__builtin_prefetch(addr);
+#endif
+}
+
+/** \internal \returns the first element of a packet */
+template<typename Packet> inline typename unpacket_traits<Packet>::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<typename Packet> inline Packet
+preduxp(const Packet* vecs) { return vecs[0]; }
+
+/** \internal \returns the sum of the elements of \a a*/
+template<typename Packet> inline typename unpacket_traits<Packet>::type predux(const Packet& a)
+{ return a; }
+
+/** \internal \returns the product of the elements of \a a*/
+template<typename Packet> inline typename unpacket_traits<Packet>::type predux_mul(const Packet& a)
+{ return a; }
+
+/** \internal \returns the min of the elements of \a a*/
+template<typename Packet> inline typename unpacket_traits<Packet>::type predux_min(const Packet& a)
+{ return a; }
+
+/** \internal \returns the max of the elements of \a a*/
+template<typename Packet> inline typename unpacket_traits<Packet>::type predux_max(const Packet& a)
+{ return a; }
+
+/** \internal \returns the reversed elements of \a a*/
+template<typename Packet> inline Packet preverse(const Packet& a)
+{ return a; }
+
+
+/** \internal \returns \a a with real and imaginary part flipped (for complex type only) */
+template<typename Packet> inline Packet pcplxflip(const Packet& a)
+{ return Packet(imag(a),real(a)); }
+
+/**************************
+* Special math functions
+***************************/
+
+/** \internal \returns the sine of \a a (coeff-wise) */
+template<typename Packet> EIGEN_DECLARE_FUNCTION_ALLOWING_MULTIPLE_DEFINITIONS
+Packet psin(const Packet& a) { return sin(a); }
+
+/** \internal \returns the cosine of \a a (coeff-wise) */
+template<typename Packet> EIGEN_DECLARE_FUNCTION_ALLOWING_MULTIPLE_DEFINITIONS
+Packet pcos(const Packet& a) { return cos(a); }
+
+/** \internal \returns the tan of \a a (coeff-wise) */
+template<typename Packet> EIGEN_DECLARE_FUNCTION_ALLOWING_MULTIPLE_DEFINITIONS
+Packet ptan(const Packet& a) { return tan(a); }
+
+/** \internal \returns the arc sine of \a a (coeff-wise) */
+template<typename Packet> EIGEN_DECLARE_FUNCTION_ALLOWING_MULTIPLE_DEFINITIONS
+Packet pasin(const Packet& a) { return asin(a); }
+
+/** \internal \returns the arc cosine of \a a (coeff-wise) */
+template<typename Packet> EIGEN_DECLARE_FUNCTION_ALLOWING_MULTIPLE_DEFINITIONS
+Packet pacos(const Packet& a) { return acos(a); }
+
+/** \internal \returns the exp of \a a (coeff-wise) */
+template<typename Packet> EIGEN_DECLARE_FUNCTION_ALLOWING_MULTIPLE_DEFINITIONS
+Packet pexp(const Packet& a) { return exp(a); }
+
+/** \internal \returns the log of \a a (coeff-wise) */
+template<typename Packet> EIGEN_DECLARE_FUNCTION_ALLOWING_MULTIPLE_DEFINITIONS
+Packet plog(const Packet& a) { return log(a); }
+
+/** \internal \returns the square-root of \a a (coeff-wise) */
+template<typename Packet> EIGEN_DECLARE_FUNCTION_ALLOWING_MULTIPLE_DEFINITIONS
+Packet psqrt(const Packet& a) { 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<typename Packet>
+inline void pstore1(typename unpacket_traits<Packet>::type* to, const typename unpacket_traits<Packet>::type& a)
+{
+ pstore(to, pset1<Packet>(a));
+}
+
+/** \internal \returns a * b + c (coeff-wise) */
+template<typename Packet> 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<typename Packet, int LoadMode>
+inline Packet ploadt(const typename unpacket_traits<Packet>::type* from)
+{
+ if(LoadMode == Aligned)
+ return pload<Packet>(from);
+ else
+ return ploadu<Packet>(from);
+}
+
+/** \internal copy the packet \a from to \a *to.
+ * If StoreMode equals #Aligned, \a to must be 16 bytes aligned */
+template<typename Scalar, typename Packet, int LoadMode>
+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<int Offset,typename PacketType>
+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 \a Offset last elements
+ * of \a first and packet_size minus \a Offset first elements of \a second */
+template<int Offset,typename PacketType>
+inline void palign(PacketType& first, const PacketType& second)
+{
+ palign_impl<Offset,PacketType>::run(first,second);
+}
+
+/***************************************************************************
+* Fast complex products (GCC generates a function call which is very slow)
+***************************************************************************/
+
+template<> inline std::complex<float> pmul(const std::complex<float>& a, const std::complex<float>& b)
+{ return std::complex<float>(real(a)*real(b) - imag(a)*imag(b), imag(a)*real(b) + real(a)*imag(b)); }
+
+template<> inline std::complex<double> pmul(const std::complex<double>& a, const std::complex<double>& b)
+{ return std::complex<double>(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/Eigen/src/Core/GlobalFunctions.h b/Eigen/src/Core/GlobalFunctions.h
new file mode 100644
index 000000000..e63726c47
--- /dev/null
+++ b/Eigen/src/Core/GlobalFunctions.h
@@ -0,0 +1,103 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra.
+//
+// Copyright (C) 2010 Gael Guennebaud <gael.guennebaud@inria.fr>
+// Copyright (C) 2010 Benoit Jacob <jacob.benoit.1@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 EIGEN_GLOBAL_FUNCTIONS_H
+#define EIGEN_GLOBAL_FUNCTIONS_H
+
+#define EIGEN_ARRAY_DECLARE_GLOBAL_STD_UNARY(NAME,FUNCTOR) \
+ template<typename Derived> \
+ inline const Eigen::CwiseUnaryOp<Eigen::internal::FUNCTOR<typename Derived::Scalar>, const Derived> \
+ NAME(const Eigen::ArrayBase<Derived>& x) { \
+ return x.derived(); \
+ }
+
+#define EIGEN_ARRAY_DECLARE_GLOBAL_EIGEN_UNARY(NAME,FUNCTOR) \
+ \
+ template<typename Derived> \
+ struct NAME##_retval<ArrayBase<Derived> > \
+ { \
+ typedef const Eigen::CwiseUnaryOp<Eigen::internal::FUNCTOR<typename Derived::Scalar>, const Derived> type; \
+ }; \
+ template<typename Derived> \
+ struct NAME##_impl<ArrayBase<Derived> > \
+ { \
+ static inline typename NAME##_retval<ArrayBase<Derived> >::type run(const Eigen::ArrayBase<Derived>& x) \
+ { \
+ return x.derived(); \
+ } \
+ };
+
+
+namespace std
+{
+ EIGEN_ARRAY_DECLARE_GLOBAL_STD_UNARY(real,scalar_real_op)
+ EIGEN_ARRAY_DECLARE_GLOBAL_STD_UNARY(imag,scalar_imag_op)
+ EIGEN_ARRAY_DECLARE_GLOBAL_STD_UNARY(sin,scalar_sin_op)
+ EIGEN_ARRAY_DECLARE_GLOBAL_STD_UNARY(cos,scalar_cos_op)
+ EIGEN_ARRAY_DECLARE_GLOBAL_STD_UNARY(asin,scalar_asin_op)
+ EIGEN_ARRAY_DECLARE_GLOBAL_STD_UNARY(acos,scalar_acos_op)
+ EIGEN_ARRAY_DECLARE_GLOBAL_STD_UNARY(tan,scalar_tan_op)
+ EIGEN_ARRAY_DECLARE_GLOBAL_STD_UNARY(exp,scalar_exp_op)
+ EIGEN_ARRAY_DECLARE_GLOBAL_STD_UNARY(log,scalar_log_op)
+ EIGEN_ARRAY_DECLARE_GLOBAL_STD_UNARY(abs,scalar_abs_op)
+ EIGEN_ARRAY_DECLARE_GLOBAL_STD_UNARY(sqrt,scalar_sqrt_op)
+
+ template<typename Derived>
+ inline const Eigen::CwiseUnaryOp<Eigen::internal::scalar_pow_op<typename Derived::Scalar>, const Derived>
+ pow(const Eigen::ArrayBase<Derived>& x, const typename Derived::Scalar& exponent) {
+ return x.derived().pow(exponent);
+ }
+
+ template<typename Derived>
+ inline const Eigen::CwiseBinaryOp<Eigen::internal::scalar_binary_pow_op<typename Derived::Scalar, typename Derived::Scalar>, const Derived, const Derived>
+ pow(const Eigen::ArrayBase<Derived>& x, const Eigen::ArrayBase<Derived>& exponents)
+ {
+ return Eigen::CwiseBinaryOp<Eigen::internal::scalar_binary_pow_op<typename Derived::Scalar, typename Derived::Scalar>, const Derived, const Derived>(
+ x.derived(),
+ exponents.derived()
+ );
+ }
+}
+
+namespace Eigen
+{
+ /**
+ * \brief Component-wise division of a scalar by array elements.
+ **/
+ template <typename Derived>
+ inline const Eigen::CwiseUnaryOp<Eigen::internal::scalar_inverse_mult_op<typename Derived::Scalar>, const Derived>
+ operator/(typename Derived::Scalar s, const Eigen::ArrayBase<Derived>& a)
+ {
+ return Eigen::CwiseUnaryOp<Eigen::internal::scalar_inverse_mult_op<typename Derived::Scalar>, const Derived>(
+ a.derived(),
+ Eigen::internal::scalar_inverse_mult_op<typename Derived::Scalar>(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(sin,scalar_sin_op)
+ EIGEN_ARRAY_DECLARE_GLOBAL_EIGEN_UNARY(cos,scalar_cos_op)
+ EIGEN_ARRAY_DECLARE_GLOBAL_EIGEN_UNARY(asin,scalar_asin_op)
+ EIGEN_ARRAY_DECLARE_GLOBAL_EIGEN_UNARY(acos,scalar_acos_op)
+ EIGEN_ARRAY_DECLARE_GLOBAL_EIGEN_UNARY(tan,scalar_tan_op)
+ EIGEN_ARRAY_DECLARE_GLOBAL_EIGEN_UNARY(exp,scalar_exp_op)
+ EIGEN_ARRAY_DECLARE_GLOBAL_EIGEN_UNARY(log,scalar_log_op)
+ EIGEN_ARRAY_DECLARE_GLOBAL_EIGEN_UNARY(abs,scalar_abs_op)
+ EIGEN_ARRAY_DECLARE_GLOBAL_EIGEN_UNARY(abs2,scalar_abs2_op)
+ EIGEN_ARRAY_DECLARE_GLOBAL_EIGEN_UNARY(sqrt,scalar_sqrt_op)
+ }
+}
+
+// TODO: cleanly disable those functions that are not supported on Array (internal::real_ref, internal::random, internal::isApprox...)
+
+#endif // EIGEN_GLOBAL_FUNCTIONS_H
diff --git a/Eigen/src/Core/IO.h b/Eigen/src/Core/IO.h
new file mode 100644
index 000000000..cc8e18a00
--- /dev/null
+++ b/Eigen/src/Core/IO.h
@@ -0,0 +1,249 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra.
+//
+// Copyright (C) 2006-2008 Benoit Jacob <jacob.benoit.1@gmail.com>
+// Copyright (C) 2008 Gael Guennebaud <gael.guennebaud@inria.fr>
+//
+// This Source Code Form is subject to the terms of the Mozilla
+// Public License v. 2.0. If a copy of the MPL was not distributed
+// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+#ifndef EIGEN_IO_H
+#define EIGEN_IO_H
+
+namespace Eigen {
+
+enum { DontAlignCols = 1 };
+enum { StreamPrecision = -1,
+ FullPrecision = -2 };
+
+namespace internal {
+template<typename Derived>
+std::ostream & print_matrix(std::ostream & s, const Derived& _m, const IOFormat& fmt);
+}
+
+/** \class IOFormat
+ * \ingroup Core_Module
+ *
+ * \brief Stores a set of parameters controlling the way matrices are printed
+ *
+ * List of available parameters:
+ * - \b precision number of digits for floating point values, or one of the special constants \c StreamPrecision and \c FullPrecision.
+ * The default is the special value \c StreamPrecision which means to use the
+ * stream's own precision setting, as set for instance using \c cout.precision(3). The other special value
+ * \c FullPrecision means that the number of digits will be computed to match the full precision of each floating-point
+ * type.
+ * - \b flags an OR-ed combination of flags, the default value is 0, the only currently available flag is \c DontAlignCols which
+ * allows to disable the alignment of columns, resulting in faster code.
+ * - \b coeffSeparator string printed between two coefficients of the same row
+ * - \b rowSeparator string printed between two rows
+ * - \b rowPrefix string printed at the beginning of each row
+ * - \b rowSuffix string printed at the end of each row
+ * - \b matPrefix string printed at the beginning of the matrix
+ * - \b matSuffix string printed at the end of the matrix
+ *
+ * Example: \include IOFormat.cpp
+ * Output: \verbinclude IOFormat.out
+ *
+ * \sa DenseBase::format(), class WithFormat
+ */
+struct IOFormat
+{
+ /** Default contructor, 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="",
+ const std::string& _matPrefix="", const std::string& _matSuffix="")
+ : matPrefix(_matPrefix), matSuffix(_matSuffix), rowPrefix(_rowPrefix), rowSuffix(_rowSuffix), rowSeparator(_rowSeparator),
+ coeffSeparator(_coeffSeparator), precision(_precision), flags(_flags)
+ {
+ rowSpacer = "";
+ int i = int(matSuffix.length())-1;
+ while (i>=0 && matSuffix[i]!='\n')
+ {
+ rowSpacer += ' ';
+ i--;
+ }
+ }
+ std::string matPrefix, matSuffix;
+ std::string rowPrefix, rowSuffix, rowSeparator, rowSpacer;
+ std::string coeffSeparator;
+ int precision;
+ int flags;
+};
+
+/** \class WithFormat
+ * \ingroup Core_Module
+ *
+ * \brief Pseudo expression providing matrix output with given format
+ *
+ * \param 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()
+ * and most of the time this is the only way it is used.
+ *
+ * See class IOFormat for some examples.
+ *
+ * \sa DenseBase::format(), class IOFormat
+ */
+template<typename ExpressionType>
+class WithFormat
+{
+ public:
+
+ WithFormat(const ExpressionType& matrix, const IOFormat& format)
+ : m_matrix(matrix), m_format(format)
+ {}
+
+ friend std::ostream & operator << (std::ostream & s, const WithFormat& wf)
+ {
+ return internal::print_matrix(s, wf.m_matrix.eval(), wf.m_format);
+ }
+
+ protected:
+ const 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<typename Derived>
+inline const WithFormat<Derived>
+DenseBase<Derived>::format(const IOFormat& fmt) const
+{
+ return WithFormat<Derived>(derived(), fmt);
+}
+
+namespace internal {
+
+template<typename Scalar, bool IsInteger>
+struct significant_decimals_default_impl
+{
+ typedef typename NumTraits<Scalar>::Real RealScalar;
+ static inline int run()
+ {
+ using std::ceil;
+ return cast<RealScalar,int>(ceil(-log(NumTraits<RealScalar>::epsilon())/log(RealScalar(10))));
+ }
+};
+
+template<typename Scalar>
+struct significant_decimals_default_impl<Scalar, true>
+{
+ static inline int run()
+ {
+ return 0;
+ }
+};
+
+template<typename Scalar>
+struct significant_decimals_impl
+ : significant_decimals_default_impl<Scalar, NumTraits<Scalar>::IsInteger>
+{};
+
+/** \internal
+ * print the matrix \a _m to the output stream \a s using the output format \a fmt */
+template<typename Derived>
+std::ostream & print_matrix(std::ostream & s, const Derived& _m, const IOFormat& fmt)
+{
+ if(_m.size() == 0)
+ {
+ s << fmt.matPrefix << fmt.matSuffix;
+ return s;
+ }
+
+ typename Derived::Nested m = _m;
+ typedef typename Derived::Scalar Scalar;
+ typedef typename Derived::Index Index;
+
+ Index width = 0;
+
+ std::streamsize explicit_precision;
+ if(fmt.precision == StreamPrecision)
+ {
+ explicit_precision = 0;
+ }
+ else if(fmt.precision == FullPrecision)
+ {
+ if (NumTraits<Scalar>::IsInteger)
+ {
+ explicit_precision = 0;
+ }
+ else
+ {
+ explicit_precision = significant_decimals_impl<Scalar>::run();
+ }
+ }
+ else
+ {
+ explicit_precision = fmt.precision;
+ }
+
+ bool align_cols = !(fmt.flags & DontAlignCols);
+ if(align_cols)
+ {
+ // compute the largest width
+ for(Index j = 1; j < m.cols(); ++j)
+ for(Index i = 0; i < m.rows(); ++i)
+ {
+ std::stringstream sstr;
+ if(explicit_precision) sstr.precision(explicit_precision);
+ sstr << m.coeff(i,j);
+ width = std::max<Index>(width, Index(sstr.str().length()));
+ }
+ }
+ std::streamsize old_precision = 0;
+ if(explicit_precision) old_precision = s.precision(explicit_precision);
+ s << fmt.matPrefix;
+ for(Index i = 0; i < m.rows(); ++i)
+ {
+ if (i)
+ s << fmt.rowSpacer;
+ s << fmt.rowPrefix;
+ if(width) s.width(width);
+ s << m.coeff(i, 0);
+ for(Index j = 1; j < m.cols(); ++j)
+ {
+ s << fmt.coeffSeparator;
+ if (width) s.width(width);
+ s << m.coeff(i, j);
+ }
+ s << fmt.rowSuffix;
+ if( i < m.rows() - 1)
+ s << fmt.rowSeparator;
+ }
+ s << fmt.matSuffix;
+ if(explicit_precision) s.precision(old_precision);
+ return s;
+}
+
+} // end namespace internal
+
+/** \relates DenseBase
+ *
+ * Outputs the matrix, to the given stream.
+ *
+ * If you wish to print the matrix with a format different than the default, use DenseBase::format().
+ *
+ * It is also possible to change the default format by defining EIGEN_DEFAULT_IO_FORMAT before including Eigen headers.
+ * If not defined, this will automatically be defined to Eigen::IOFormat(), that is the Eigen::IOFormat with default parameters.
+ *
+ * \sa DenseBase::format()
+ */
+template<typename Derived>
+std::ostream & operator <<
+(std::ostream & s,
+ const DenseBase<Derived> & m)
+{
+ return internal::print_matrix(s, m.eval(), EIGEN_DEFAULT_IO_FORMAT);
+}
+
+} // end namespace Eigen
+
+#endif // EIGEN_IO_H
diff --git a/Eigen/src/Core/Map.h b/Eigen/src/Core/Map.h
new file mode 100644
index 000000000..15a19226e
--- /dev/null
+++ b/Eigen/src/Core/Map.h
@@ -0,0 +1,192 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra.
+//
+// Copyright (C) 2007-2010 Benoit Jacob <jacob.benoit.1@gmail.com>
+// Copyright (C) 2008 Gael Guennebaud <gael.guennebaud@inria.fr>
+//
+// This Source Code Form is subject to the terms of the Mozilla
+// Public License v. 2.0. If a copy of the MPL was not distributed
+// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+#ifndef EIGEN_MAP_H
+#define EIGEN_MAP_H
+
+namespace Eigen {
+
+/** \class Map
+ * \ingroup Core_Module
+ *
+ * \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.
+ * 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.
+ * The type passed here must be a specialization of the Stride template, see examples below.
+ *
+ * This class represents a matrix or vector expression mapping an existing array of data.
+ * It can be used to let Eigen interface without any overhead with non-Eigen data structures,
+ * such as plain C arrays or structures from other libraries. By default, it assumes that the
+ * data is laid out contiguously in memory. You can however override this by explicitly specifying
+ * inner and outer strides.
+ *
+ * Here's an example of simply mapping a contiguous array as a \ref TopicStorageOrders "column-major" matrix:
+ * \include Map_simple.cpp
+ * Output: \verbinclude Map_simple.out
+ *
+ * If you need to map non-contiguous arrays, you can do so by specifying strides:
+ *
+ * Here's an example of mapping an array as a vector, specifying an inner stride, that is, the pointer
+ * increment between two consecutive coefficients. Here, we're specifying the inner stride as a compile-time
+ * fixed value.
+ * \include Map_inner_stride.cpp
+ * Output: \verbinclude Map_inner_stride.out
+ *
+ * Here's an example of mapping an array while specifying an outer stride. Here, since we're mapping
+ * as a column-major matrix, 'outer stride' means the pointer increment between two consecutive columns.
+ * Here, we're specifying the outer stride as a runtime parameter. Note that here \c OuterStride<> is
+ * a short version of \c OuterStride<Dynamic> because the default template parameter of OuterStride
+ * is \c Dynamic
+ * \include Map_outer_stride.cpp
+ * Output: \verbinclude Map_outer_stride.out
+ *
+ * For more details and for an example of specifying both an inner and an outer stride, see class Stride.
+ *
+ * \b Tip: to change the array of data mapped by a Map object, you can use the C++
+ * placement new syntax:
+ *
+ * Example: \include Map_placement_new.cpp
+ * Output: \verbinclude Map_placement_new.out
+ *
+ * This class is the return type of PlainObjectBase::Map() but can also be used directly.
+ *
+ * \sa PlainObjectBase::Map(), \ref TopicStorageOrders
+ */
+
+namespace internal {
+template<typename PlainObjectType, int MapOptions, typename StrideType>
+struct traits<Map<PlainObjectType, MapOptions, StrideType> >
+ : public traits<PlainObjectType>
+{
+ typedef traits<PlainObjectType> 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<int>(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<PlainObjectType>::value ? int(Flags2) : (int(Flags2) & ~LvalueBit),
+ Flags = KeepsPacketAccess ? int(Flags3) : (int(Flags3) & ~PacketAccessBit)
+ };
+private:
+ enum { Options }; // Expressions don't have Options
+};
+}
+
+template<typename PlainObjectType, int MapOptions, typename StrideType> class Map
+ : public MapBase<Map<PlainObjectType, MapOptions, StrideType> >
+{
+ public:
+
+ typedef MapBase<Map> Base;
+ 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<PointerType>(ptr); }
+#else
+ typedef PointerType PointerArgType;
+ inline PointerType cast_to_pointer_type(PointerArgType ptr) { return ptr; }
+#endif
+
+ inline Index innerStride() const
+ {
+ return StrideType::InnerStrideAtCompileTime != 0 ? m_stride.inner() : 1;
+ }
+
+ inline Index outerStride() const
+ {
+ return StrideType::OuterStrideAtCompileTime != 0 ? m_stride.outer()
+ : IsVectorAtCompileTime ? this->size()
+ : int(Flags)&RowMajorBit ? this->cols()
+ : this->rows();
+ }
+
+ /** Constructor in the fixed-size case.
+ *
+ * \param data pointer to the array to map
+ * \param stride optional Stride object, passing the strides.
+ */
+ inline Map(PointerArgType data, const StrideType& stride = StrideType())
+ : Base(cast_to_pointer_type(data)), m_stride(stride)
+ {
+ PlainObjectType::Base::_check_template_params();
+ }
+
+ /** Constructor in the dynamic-size vector case.
+ *
+ * \param data pointer to the array to map
+ * \param size the size of the vector expression
+ * \param stride optional Stride object, passing the strides.
+ */
+ inline Map(PointerArgType data, Index size, const StrideType& stride = StrideType())
+ : Base(cast_to_pointer_type(data), size), m_stride(stride)
+ {
+ PlainObjectType::Base::_check_template_params();
+ }
+
+ /** Constructor in the dynamic-size matrix case.
+ *
+ * \param data pointer to the array to map
+ * \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 data, Index rows, Index cols, const StrideType& stride = StrideType())
+ : Base(cast_to_pointer_type(data), rows, cols), m_stride(stride)
+ {
+ PlainObjectType::Base::_check_template_params();
+ }
+
+ EIGEN_INHERIT_ASSIGNMENT_OPERATORS(Map)
+
+ protected:
+ StrideType m_stride;
+};
+
+template<typename _Scalar, int _Rows, int _Cols, int _Options, int _MaxRows, int _MaxCols>
+inline Array<_Scalar, _Rows, _Cols, _Options, _MaxRows, _MaxCols>
+ ::Array(const Scalar *data)
+{
+ this->_set_noalias(Eigen::Map<const Array>(data));
+}
+
+template<typename _Scalar, int _Rows, int _Cols, int _Options, int _MaxRows, int _MaxCols>
+inline Matrix<_Scalar, _Rows, _Cols, _Options, _MaxRows, _MaxCols>
+ ::Matrix(const Scalar *data)
+{
+ this->_set_noalias(Eigen::Map<const Matrix>(data));
+}
+
+} // end namespace Eigen
+
+#endif // EIGEN_MAP_H
diff --git a/Eigen/src/Core/MapBase.h b/Eigen/src/Core/MapBase.h
new file mode 100644
index 000000000..a388d61ea
--- /dev/null
+++ b/Eigen/src/Core/MapBase.h
@@ -0,0 +1,242 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra.
+//
+// Copyright (C) 2007-2010 Benoit Jacob <jacob.benoit.1@gmail.com>
+// Copyright (C) 2008 Gael Guennebaud <gael.guennebaud@inria.fr>
+//
+// This Source Code Form is subject to the terms of the Mozilla
+// Public License v. 2.0. If a copy of the MPL was not distributed
+// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+#ifndef EIGEN_MAPBASE_H
+#define EIGEN_MAPBASE_H
+
+#define EIGEN_STATIC_ASSERT_INDEX_BASED_ACCESS(Derived) \
+ EIGEN_STATIC_ASSERT((int(internal::traits<Derived>::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
+ *
+ * \brief Base class for Map and Block expression with direct access
+ *
+ * \sa class Map, class Block
+ */
+template<typename Derived> class MapBase<Derived, ReadOnlyAccessors>
+ : public internal::dense_xpr_base<Derived>::type
+{
+ public:
+
+ typedef typename internal::dense_xpr_base<Derived>::type Base;
+ enum {
+ RowsAtCompileTime = internal::traits<Derived>::RowsAtCompileTime,
+ ColsAtCompileTime = internal::traits<Derived>::ColsAtCompileTime,
+ SizeAtCompileTime = Base::SizeAtCompileTime
+ };
+
+ typedef typename internal::traits<Derived>::StorageKind StorageKind;
+ typedef typename internal::traits<Derived>::Index Index;
+ typedef typename internal::traits<Derived>::Scalar Scalar;
+ typedef typename internal::packet_traits<Scalar>::type PacketScalar;
+ typedef typename NumTraits<Scalar>::Real RealScalar;
+ typedef typename internal::conditional<
+ bool(internal::is_lvalue<Derived>::value),
+ Scalar *,
+ const Scalar *>::type
+ PointerType;
+
+ using Base::derived;
+// using Base::RowsAtCompileTime;
+// using Base::ColsAtCompileTime;
+// using Base::SizeAtCompileTime;
+ using Base::MaxRowsAtCompileTime;
+ using Base::MaxColsAtCompileTime;
+ using Base::MaxSizeAtCompileTime;
+ using Base::IsVectorAtCompileTime;
+ using Base::Flags;
+ using Base::IsRowMajor;
+
+ using Base::rows;
+ using Base::cols;
+ using Base::size;
+ using Base::coeff;
+ using Base::coeffRef;
+ using Base::lazyAssign;
+ using Base::eval;
+
+ using Base::innerStride;
+ using Base::outerStride;
+ using Base::rowStride;
+ using Base::colStride;
+
+ // bug 217 - compile error on ICC 11.1
+ using Base::operator=;
+
+ typedef typename Base::CoeffReturnType CoeffReturnType;
+
+ inline Index rows() const { return m_rows.value(); }
+ inline Index cols() const { return m_cols.value(); }
+
+ /** Returns a pointer to the first coefficient of the matrix or vector.
+ *
+ * \note When addressing this data, make sure to honor the strides returned by innerStride() and outerStride().
+ *
+ * \sa innerStride(), outerStride()
+ */
+ inline const Scalar* data() const { return m_data; }
+
+ inline const Scalar& coeff(Index row, Index col) const
+ {
+ return m_data[col * colStride() + row * rowStride()];
+ }
+
+ inline const Scalar& coeff(Index index) const
+ {
+ EIGEN_STATIC_ASSERT_INDEX_BASED_ACCESS(Derived)
+ return m_data[index * innerStride()];
+ }
+
+ inline const Scalar& coeffRef(Index row, Index col) const
+ {
+ return this->m_data[col * colStride() + row * rowStride()];
+ }
+
+ inline const Scalar& coeffRef(Index index) const
+ {
+ EIGEN_STATIC_ASSERT_INDEX_BASED_ACCESS(Derived)
+ return this->m_data[index * innerStride()];
+ }
+
+ template<int LoadMode>
+ inline PacketScalar packet(Index row, Index col) const
+ {
+ return internal::ploadt<PacketScalar, LoadMode>
+ (m_data + (col * colStride() + row * rowStride()));
+ }
+
+ template<int LoadMode>
+ inline PacketScalar packet(Index index) const
+ {
+ EIGEN_STATIC_ASSERT_INDEX_BASED_ACCESS(Derived)
+ return internal::ploadt<PacketScalar, LoadMode>(m_data + index * innerStride());
+ }
+
+ inline MapBase(PointerType data) : m_data(data), m_rows(RowsAtCompileTime), m_cols(ColsAtCompileTime)
+ {
+ EIGEN_STATIC_ASSERT_FIXED_SIZE(Derived)
+ checkSanity();
+ }
+
+ inline MapBase(PointerType data, Index size)
+ : m_data(data),
+ m_rows(RowsAtCompileTime == Dynamic ? size : Index(RowsAtCompileTime)),
+ m_cols(ColsAtCompileTime == Dynamic ? size : Index(ColsAtCompileTime))
+ {
+ EIGEN_STATIC_ASSERT_VECTOR_ONLY(Derived)
+ eigen_assert(size >= 0);
+ eigen_assert(data == 0 || SizeAtCompileTime == Dynamic || SizeAtCompileTime == size);
+ checkSanity();
+ }
+
+ inline MapBase(PointerType data, Index rows, Index cols)
+ : m_data(data), m_rows(rows), m_cols(cols)
+ {
+ eigen_assert( (data == 0)
+ || ( rows >= 0 && (RowsAtCompileTime == Dynamic || RowsAtCompileTime == rows)
+ && cols >= 0 && (ColsAtCompileTime == Dynamic || ColsAtCompileTime == cols)));
+ checkSanity();
+ }
+
+ protected:
+
+ void checkSanity() const
+ {
+ EIGEN_STATIC_ASSERT(EIGEN_IMPLIES(internal::traits<Derived>::Flags&PacketAccessBit,
+ internal::inner_stride_at_compile_time<Derived>::ret==1),
+ PACKET_ACCESS_REQUIRES_TO_HAVE_INNER_STRIDE_FIXED_TO_1);
+ eigen_assert(EIGEN_IMPLIES(internal::traits<Derived>::Flags&AlignedBit, (size_t(m_data) % 16) == 0)
+ && "data is not aligned");
+ }
+
+ PointerType m_data;
+ const internal::variable_if_dynamic<Index, RowsAtCompileTime> m_rows;
+ const internal::variable_if_dynamic<Index, ColsAtCompileTime> m_cols;
+};
+
+template<typename Derived> class MapBase<Derived, WriteAccessors>
+ : public MapBase<Derived, ReadOnlyAccessors>
+{
+ public:
+
+ typedef MapBase<Derived, ReadOnlyAccessors> Base;
+
+ typedef typename Base::Scalar Scalar;
+ typedef typename Base::PacketScalar PacketScalar;
+ typedef typename Base::Index Index;
+ typedef typename Base::PointerType PointerType;
+
+ using Base::derived;
+ using Base::rows;
+ using Base::cols;
+ using Base::size;
+ using Base::coeff;
+ using Base::coeffRef;
+
+ using Base::innerStride;
+ using Base::outerStride;
+ using Base::rowStride;
+ using Base::colStride;
+
+ typedef typename internal::conditional<
+ internal::is_lvalue<Derived>::value,
+ Scalar,
+ const Scalar
+ >::type ScalarWithConstIfNotLvalue;
+
+ inline const Scalar* data() const { return this->m_data; }
+ inline ScalarWithConstIfNotLvalue* data() { return this->m_data; } // no const-cast here so non-const-correct code will give a compile error
+
+ inline ScalarWithConstIfNotLvalue& coeffRef(Index row, Index col)
+ {
+ return this->m_data[col * colStride() + row * rowStride()];
+ }
+
+ inline ScalarWithConstIfNotLvalue& coeffRef(Index index)
+ {
+ EIGEN_STATIC_ASSERT_INDEX_BASED_ACCESS(Derived)
+ return this->m_data[index * innerStride()];
+ }
+
+ template<int StoreMode>
+ inline void writePacket(Index row, Index col, const PacketScalar& x)
+ {
+ internal::pstoret<Scalar, PacketScalar, StoreMode>
+ (this->m_data + (col * colStride() + row * rowStride()), x);
+ }
+
+ template<int StoreMode>
+ inline void writePacket(Index index, const PacketScalar& x)
+ {
+ EIGEN_STATIC_ASSERT_INDEX_BASED_ACCESS(Derived)
+ internal::pstoret<Scalar, PacketScalar, StoreMode>
+ (this->m_data + index * innerStride(), x);
+ }
+
+ explicit inline MapBase(PointerType data) : Base(data) {}
+ inline MapBase(PointerType data, Index size) : Base(data, size) {}
+ inline MapBase(PointerType data, Index rows, Index cols) : Base(data, rows, cols) {}
+
+ Derived& operator=(const MapBase& other)
+ {
+ Base::Base::operator=(other);
+ return derived();
+ }
+
+ using Base::Base::operator=;
+};
+
+} // end namespace Eigen
+
+#endif // EIGEN_MAPBASE_H
diff --git a/Eigen/src/Core/MathFunctions.h b/Eigen/src/Core/MathFunctions.h
new file mode 100644
index 000000000..05e913f2f
--- /dev/null
+++ b/Eigen/src/Core/MathFunctions.h
@@ -0,0 +1,842 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra.
+//
+// Copyright (C) 2006-2010 Benoit Jacob <jacob.benoit.1@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 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<T>::type is a typedef for it.
+ * - otherwise, global_math_functions_filtering_base<T>::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<Derived>.
+ * So we must make sure to use sin_impl<ArrayBase<Derived> > and not sin_impl<Derived>, 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<typename T, typename dummy = void>
+struct global_math_functions_filtering_base
+{
+ typedef T type;
+};
+
+template<typename T> struct always_void { typedef void type; };
+
+template<typename T>
+struct global_math_functions_filtering_base
+ <T,
+ typename always_void<typename T::Eigen_BaseClassForSpecializationOfGlobalMathFuncImpl>::type
+ >
+{
+ typedef typename T::Eigen_BaseClassForSpecializationOfGlobalMathFuncImpl type;
+};
+
+#define EIGEN_MATHFUNC_IMPL(func, scalar) func##_impl<typename global_math_functions_filtering_base<scalar>::type>
+#define EIGEN_MATHFUNC_RETVAL(func, scalar) typename func##_retval<typename global_math_functions_filtering_base<scalar>::type>::type
+
+
+/****************************************************************************
+* Implementation of real *
+****************************************************************************/
+
+template<typename Scalar>
+struct real_impl
+{
+ typedef typename NumTraits<Scalar>::Real RealScalar;
+ static inline RealScalar run(const Scalar& x)
+ {
+ return x;
+ }
+};
+
+template<typename RealScalar>
+struct real_impl<std::complex<RealScalar> >
+{
+ static inline RealScalar run(const std::complex<RealScalar>& x)
+ {
+ using std::real;
+ return real(x);
+ }
+};
+
+template<typename Scalar>
+struct real_retval
+{
+ typedef typename NumTraits<Scalar>::Real type;
+};
+
+template<typename Scalar>
+inline EIGEN_MATHFUNC_RETVAL(real, Scalar) real(const Scalar& x)
+{
+ return EIGEN_MATHFUNC_IMPL(real, Scalar)::run(x);
+}
+
+/****************************************************************************
+* Implementation of imag *
+****************************************************************************/
+
+template<typename Scalar>
+struct imag_impl
+{
+ typedef typename NumTraits<Scalar>::Real RealScalar;
+ static inline RealScalar run(const Scalar&)
+ {
+ return RealScalar(0);
+ }
+};
+
+template<typename RealScalar>
+struct imag_impl<std::complex<RealScalar> >
+{
+ static inline RealScalar run(const std::complex<RealScalar>& x)
+ {
+ using std::imag;
+ return imag(x);
+ }
+};
+
+template<typename Scalar>
+struct imag_retval
+{
+ typedef typename NumTraits<Scalar>::Real type;
+};
+
+template<typename Scalar>
+inline EIGEN_MATHFUNC_RETVAL(imag, Scalar) imag(const Scalar& x)
+{
+ return EIGEN_MATHFUNC_IMPL(imag, Scalar)::run(x);
+}
+
+/****************************************************************************
+* Implementation of real_ref *
+****************************************************************************/
+
+template<typename Scalar>
+struct real_ref_impl
+{
+ typedef typename NumTraits<Scalar>::Real RealScalar;
+ static inline RealScalar& run(Scalar& x)
+ {
+ return reinterpret_cast<RealScalar*>(&x)[0];
+ }
+ static inline const RealScalar& run(const Scalar& x)
+ {
+ return reinterpret_cast<const RealScalar*>(&x)[0];
+ }
+};
+
+template<typename Scalar>
+struct real_ref_retval
+{
+ typedef typename NumTraits<Scalar>::Real & type;
+};
+
+template<typename Scalar>
+inline typename add_const_on_value_type< EIGEN_MATHFUNC_RETVAL(real_ref, Scalar) >::type real_ref(const Scalar& x)
+{
+ return real_ref_impl<Scalar>::run(x);
+}
+
+template<typename Scalar>
+inline EIGEN_MATHFUNC_RETVAL(real_ref, Scalar) real_ref(Scalar& x)
+{
+ return EIGEN_MATHFUNC_IMPL(real_ref, Scalar)::run(x);
+}
+
+/****************************************************************************
+* Implementation of imag_ref *
+****************************************************************************/
+
+template<typename Scalar, bool IsComplex>
+struct imag_ref_default_impl
+{
+ typedef typename NumTraits<Scalar>::Real RealScalar;
+ static inline RealScalar& run(Scalar& x)
+ {
+ return reinterpret_cast<RealScalar*>(&x)[1];
+ }
+ static inline const RealScalar& run(const Scalar& x)
+ {
+ return reinterpret_cast<RealScalar*>(&x)[1];
+ }
+};
+
+template<typename Scalar>
+struct imag_ref_default_impl<Scalar, false>
+{
+ static inline Scalar run(Scalar&)
+ {
+ return Scalar(0);
+ }
+ static inline const Scalar run(const Scalar&)
+ {
+ return Scalar(0);
+ }
+};
+
+template<typename Scalar>
+struct imag_ref_impl : imag_ref_default_impl<Scalar, NumTraits<Scalar>::IsComplex> {};
+
+template<typename Scalar>
+struct imag_ref_retval
+{
+ typedef typename NumTraits<Scalar>::Real & type;
+};
+
+template<typename Scalar>
+inline typename add_const_on_value_type< EIGEN_MATHFUNC_RETVAL(imag_ref, Scalar) >::type imag_ref(const Scalar& x)
+{
+ return imag_ref_impl<Scalar>::run(x);
+}
+
+template<typename Scalar>
+inline EIGEN_MATHFUNC_RETVAL(imag_ref, Scalar) imag_ref(Scalar& x)
+{
+ return EIGEN_MATHFUNC_IMPL(imag_ref, Scalar)::run(x);
+}
+
+/****************************************************************************
+* Implementation of conj *
+****************************************************************************/
+
+template<typename Scalar>
+struct conj_impl
+{
+ static inline Scalar run(const Scalar& x)
+ {
+ return x;
+ }
+};
+
+template<typename RealScalar>
+struct conj_impl<std::complex<RealScalar> >
+{
+ static inline std::complex<RealScalar> run(const std::complex<RealScalar>& x)
+ {
+ using std::conj;
+ return conj(x);
+ }
+};
+
+template<typename Scalar>
+struct conj_retval
+{
+ typedef Scalar type;
+};
+
+template<typename Scalar>
+inline EIGEN_MATHFUNC_RETVAL(conj, Scalar) conj(const Scalar& x)
+{
+ return EIGEN_MATHFUNC_IMPL(conj, Scalar)::run(x);
+}
+
+/****************************************************************************
+* Implementation of abs *
+****************************************************************************/
+
+template<typename Scalar>
+struct abs_impl
+{
+ typedef typename NumTraits<Scalar>::Real RealScalar;
+ static inline RealScalar run(const Scalar& x)
+ {
+ using std::abs;
+ return abs(x);
+ }
+};
+
+template<typename Scalar>
+struct abs_retval
+{
+ typedef typename NumTraits<Scalar>::Real type;
+};
+
+template<typename Scalar>
+inline EIGEN_MATHFUNC_RETVAL(abs, Scalar) abs(const Scalar& x)
+{
+ return EIGEN_MATHFUNC_IMPL(abs, Scalar)::run(x);
+}
+
+/****************************************************************************
+* Implementation of abs2 *
+****************************************************************************/
+
+template<typename Scalar>
+struct abs2_impl
+{
+ typedef typename NumTraits<Scalar>::Real RealScalar;
+ static inline RealScalar run(const Scalar& x)
+ {
+ return x*x;
+ }
+};
+
+template<typename RealScalar>
+struct abs2_impl<std::complex<RealScalar> >
+{
+ static inline RealScalar run(const std::complex<RealScalar>& x)
+ {
+ return real(x)*real(x) + imag(x)*imag(x);
+ }
+};
+
+template<typename Scalar>
+struct abs2_retval
+{
+ typedef typename NumTraits<Scalar>::Real type;
+};
+
+template<typename Scalar>
+inline EIGEN_MATHFUNC_RETVAL(abs2, Scalar) abs2(const Scalar& x)
+{
+ return EIGEN_MATHFUNC_IMPL(abs2, Scalar)::run(x);
+}
+
+/****************************************************************************
+* Implementation of norm1 *
+****************************************************************************/
+
+template<typename Scalar, bool IsComplex>
+struct norm1_default_impl
+{
+ typedef typename NumTraits<Scalar>::Real RealScalar;
+ static inline RealScalar run(const Scalar& x)
+ {
+ return abs(real(x)) + abs(imag(x));
+ }
+};
+
+template<typename Scalar>
+struct norm1_default_impl<Scalar, false>
+{
+ static inline Scalar run(const Scalar& x)
+ {
+ return abs(x);
+ }
+};
+
+template<typename Scalar>
+struct norm1_impl : norm1_default_impl<Scalar, NumTraits<Scalar>::IsComplex> {};
+
+template<typename Scalar>
+struct norm1_retval
+{
+ typedef typename NumTraits<Scalar>::Real type;
+};
+
+template<typename Scalar>
+inline EIGEN_MATHFUNC_RETVAL(norm1, Scalar) norm1(const Scalar& x)
+{
+ return EIGEN_MATHFUNC_IMPL(norm1, Scalar)::run(x);
+}
+
+/****************************************************************************
+* Implementation of hypot *
+****************************************************************************/
+
+template<typename Scalar>
+struct hypot_impl
+{
+ typedef typename NumTraits<Scalar>::Real RealScalar;
+ static inline RealScalar run(const Scalar& x, const Scalar& y)
+ {
+ using std::max;
+ using std::min;
+ RealScalar _x = abs(x);
+ RealScalar _y = abs(y);
+ RealScalar p = (max)(_x, _y);
+ RealScalar q = (min)(_x, _y);
+ RealScalar qp = q/p;
+ return p * sqrt(RealScalar(1) + qp*qp);
+ }
+};
+
+template<typename Scalar>
+struct hypot_retval
+{
+ typedef typename NumTraits<Scalar>::Real type;
+};
+
+template<typename Scalar>
+inline EIGEN_MATHFUNC_RETVAL(hypot, Scalar) hypot(const Scalar& x, const Scalar& y)
+{
+ return EIGEN_MATHFUNC_IMPL(hypot, Scalar)::run(x, y);
+}
+
+/****************************************************************************
+* Implementation of cast *
+****************************************************************************/
+
+template<typename OldType, typename NewType>
+struct cast_impl
+{
+ static inline NewType run(const OldType& x)
+ {
+ return static_cast<NewType>(x);
+ }
+};
+
+// here, for once, we're plainly returning NewType: we don't want cast to do weird things.
+
+template<typename OldType, typename NewType>
+inline NewType cast(const OldType& x)
+{
+ return cast_impl<OldType, NewType>::run(x);
+}
+
+/****************************************************************************
+* Implementation of sqrt *
+****************************************************************************/
+
+template<typename Scalar, bool IsInteger>
+struct sqrt_default_impl
+{
+ static inline Scalar run(const Scalar& x)
+ {
+ using std::sqrt;
+ return sqrt(x);
+ }
+};
+
+template<typename Scalar>
+struct sqrt_default_impl<Scalar, true>
+{
+ static inline Scalar run(const Scalar&)
+ {
+#ifdef EIGEN2_SUPPORT
+ eigen_assert(!NumTraits<Scalar>::IsInteger);
+#else
+ EIGEN_STATIC_ASSERT_NON_INTEGER(Scalar)
+#endif
+ return Scalar(0);
+ }
+};
+
+template<typename Scalar>
+struct sqrt_impl : sqrt_default_impl<Scalar, NumTraits<Scalar>::IsInteger> {};
+
+template<typename Scalar>
+struct sqrt_retval
+{
+ typedef Scalar type;
+};
+
+template<typename Scalar>
+inline EIGEN_MATHFUNC_RETVAL(sqrt, Scalar) sqrt(const Scalar& x)
+{
+ return EIGEN_MATHFUNC_IMPL(sqrt, Scalar)::run(x);
+}
+
+/****************************************************************************
+* Implementation of standard unary real functions (exp, log, sin, cos, ... *
+****************************************************************************/
+
+// This macro instanciate all the necessary template mechanism which is common to all unary real functions.
+#define EIGEN_MATHFUNC_STANDARD_REAL_UNARY(NAME) \
+ template<typename Scalar, bool IsInteger> struct NAME##_default_impl { \
+ static inline Scalar run(const Scalar& x) { using std::NAME; return NAME(x); } \
+ }; \
+ template<typename Scalar> struct NAME##_default_impl<Scalar, true> { \
+ static inline Scalar run(const Scalar&) { \
+ EIGEN_STATIC_ASSERT_NON_INTEGER(Scalar) \
+ return Scalar(0); \
+ } \
+ }; \
+ template<typename Scalar> struct NAME##_impl \
+ : NAME##_default_impl<Scalar, NumTraits<Scalar>::IsInteger> \
+ {}; \
+ template<typename Scalar> struct NAME##_retval { typedef Scalar type; }; \
+ template<typename Scalar> \
+ inline EIGEN_MATHFUNC_RETVAL(NAME, Scalar) NAME(const Scalar& x) { \
+ return EIGEN_MATHFUNC_IMPL(NAME, Scalar)::run(x); \
+ }
+
+EIGEN_MATHFUNC_STANDARD_REAL_UNARY(exp)
+EIGEN_MATHFUNC_STANDARD_REAL_UNARY(log)
+EIGEN_MATHFUNC_STANDARD_REAL_UNARY(sin)
+EIGEN_MATHFUNC_STANDARD_REAL_UNARY(cos)
+EIGEN_MATHFUNC_STANDARD_REAL_UNARY(tan)
+EIGEN_MATHFUNC_STANDARD_REAL_UNARY(asin)
+EIGEN_MATHFUNC_STANDARD_REAL_UNARY(acos)
+
+/****************************************************************************
+* Implementation of atan2 *
+****************************************************************************/
+
+template<typename Scalar, bool IsInteger>
+struct atan2_default_impl
+{
+ typedef Scalar retval;
+ static inline Scalar run(const Scalar& x, const Scalar& y)
+ {
+ using std::atan2;
+ return atan2(x, y);
+ }
+};
+
+template<typename Scalar>
+struct atan2_default_impl<Scalar, true>
+{
+ static inline Scalar run(const Scalar&, const Scalar&)
+ {
+ EIGEN_STATIC_ASSERT_NON_INTEGER(Scalar)
+ return Scalar(0);
+ }
+};
+
+template<typename Scalar>
+struct atan2_impl : atan2_default_impl<Scalar, NumTraits<Scalar>::IsInteger> {};
+
+template<typename Scalar>
+struct atan2_retval
+{
+ typedef Scalar type;
+};
+
+template<typename Scalar>
+inline EIGEN_MATHFUNC_RETVAL(atan2, Scalar) atan2(const Scalar& x, const Scalar& y)
+{
+ return EIGEN_MATHFUNC_IMPL(atan2, Scalar)::run(x, y);
+}
+
+/****************************************************************************
+* Implementation of pow *
+****************************************************************************/
+
+template<typename Scalar, bool IsInteger>
+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<typename Scalar>
+struct pow_default_impl<Scalar, true>
+{
+ static inline Scalar run(Scalar x, Scalar y)
+ {
+ Scalar res(1);
+ eigen_assert(!NumTraits<Scalar>::IsSigned || y >= 0);
+ if(y & 1) res *= x;
+ y >>= 1;
+ while(y)
+ {
+ x *= x;
+ if(y&1) res *= x;
+ y >>= 1;
+ }
+ return res;
+ }
+};
+
+template<typename Scalar>
+struct pow_impl : pow_default_impl<Scalar, NumTraits<Scalar>::IsInteger> {};
+
+template<typename Scalar>
+struct pow_retval
+{
+ typedef Scalar type;
+};
+
+template<typename Scalar>
+inline EIGEN_MATHFUNC_RETVAL(pow, Scalar) pow(const Scalar& x, const Scalar& y)
+{
+ return EIGEN_MATHFUNC_IMPL(pow, Scalar)::run(x, y);
+}
+
+/****************************************************************************
+* Implementation of random *
+****************************************************************************/
+
+template<typename Scalar,
+ bool IsComplex,
+ bool IsInteger>
+struct random_default_impl {};
+
+template<typename Scalar>
+struct random_impl : random_default_impl<Scalar, NumTraits<Scalar>::IsComplex, NumTraits<Scalar>::IsInteger> {};
+
+template<typename Scalar>
+struct random_retval
+{
+ typedef Scalar type;
+};
+
+template<typename Scalar> inline EIGEN_MATHFUNC_RETVAL(random, Scalar) random(const Scalar& x, const Scalar& y);
+template<typename Scalar> inline EIGEN_MATHFUNC_RETVAL(random, Scalar) random();
+
+template<typename Scalar>
+struct random_default_impl<Scalar, false, false>
+{
+ 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<Scalar>::IsSigned ? -1 : 0), Scalar(1));
+ }
+};
+
+enum {
+ floor_log2_terminate,
+ floor_log2_move_up,
+ floor_log2_move_down,
+ floor_log2_bogus
+};
+
+template<unsigned int n, int lower, int upper> 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<unsigned int n,
+ int lower = 0,
+ int upper = sizeof(unsigned int) * CHAR_BIT - 1,
+ int selector = floor_log2_selector<n, lower, upper>::value>
+struct floor_log2 {};
+
+template<unsigned int n, int lower, int upper>
+struct floor_log2<n, lower, upper, floor_log2_move_down>
+{
+ enum { value = floor_log2<n, lower, floor_log2_selector<n, lower, upper>::middle>::value };
+};
+
+template<unsigned int n, int lower, int upper>
+struct floor_log2<n, lower, upper, floor_log2_move_up>
+{
+ enum { value = floor_log2<n, floor_log2_selector<n, lower, upper>::middle, upper>::value };
+};
+
+template<unsigned int n, int lower, int upper>
+struct floor_log2<n, lower, upper, floor_log2_terminate>
+{
+ enum { value = (n >= ((unsigned int)(1) << (lower+1))) ? lower+1 : lower };
+};
+
+template<unsigned int n, int lower, int upper>
+struct floor_log2<n, lower, upper, floor_log2_bogus>
+{
+ // no value, error at compile time
+};
+
+template<typename Scalar>
+struct random_default_impl<Scalar, false, true>
+{
+ typedef typename NumTraits<Scalar>::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<Scalar>::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))
+ };
+ Scalar x = Scalar(std::rand() >> shift);
+ Scalar offset = NumTraits<Scalar>::IsSigned ? Scalar(1 << (rand_bits-1)) : Scalar(0);
+ return x - offset;
+#endif
+ }
+};
+
+template<typename Scalar>
+struct random_default_impl<Scalar, true, false>
+{
+ 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<Scalar>::Real RealScalar;
+ return Scalar(random<RealScalar>(), random<RealScalar>());
+ }
+};
+
+template<typename Scalar>
+inline EIGEN_MATHFUNC_RETVAL(random, Scalar) random(const Scalar& x, const Scalar& y)
+{
+ return EIGEN_MATHFUNC_IMPL(random, Scalar)::run(x, y);
+}
+
+template<typename Scalar>
+inline EIGEN_MATHFUNC_RETVAL(random, Scalar) random()
+{
+ return EIGEN_MATHFUNC_IMPL(random, Scalar)::run();
+}
+
+/****************************************************************************
+* Implementation of fuzzy comparisons *
+****************************************************************************/
+
+template<typename Scalar,
+ bool IsComplex,
+ bool IsInteger>
+struct scalar_fuzzy_default_impl {};
+
+template<typename Scalar>
+struct scalar_fuzzy_default_impl<Scalar, false, false>
+{
+ typedef typename NumTraits<Scalar>::Real RealScalar;
+ template<typename OtherScalar>
+ static inline bool isMuchSmallerThan(const Scalar& x, const OtherScalar& y, const RealScalar& prec)
+ {
+ return abs(x) <= abs(y) * prec;
+ }
+ static inline bool isApprox(const Scalar& x, const Scalar& y, const RealScalar& prec)
+ {
+ using std::min;
+ 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<typename Scalar>
+struct scalar_fuzzy_default_impl<Scalar, false, true>
+{
+ typedef typename NumTraits<Scalar>::Real RealScalar;
+ template<typename OtherScalar>
+ 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<typename Scalar>
+struct scalar_fuzzy_default_impl<Scalar, true, false>
+{
+ typedef typename NumTraits<Scalar>::Real RealScalar;
+ template<typename OtherScalar>
+ static inline bool isMuchSmallerThan(const Scalar& x, const OtherScalar& y, const RealScalar& prec)
+ {
+ return abs2(x) <= abs2(y) * prec * prec;
+ }
+ static inline bool isApprox(const Scalar& x, const Scalar& y, const RealScalar& prec)
+ {
+ using std::min;
+ return abs2(x - y) <= (min)(abs2(x), abs2(y)) * prec * prec;
+ }
+};
+
+template<typename Scalar>
+struct scalar_fuzzy_impl : scalar_fuzzy_default_impl<Scalar, NumTraits<Scalar>::IsComplex, NumTraits<Scalar>::IsInteger> {};
+
+template<typename Scalar, typename OtherScalar>
+inline bool isMuchSmallerThan(const Scalar& x, const OtherScalar& y,
+ typename NumTraits<Scalar>::Real precision = NumTraits<Scalar>::dummy_precision())
+{
+ return scalar_fuzzy_impl<Scalar>::template isMuchSmallerThan<OtherScalar>(x, y, precision);
+}
+
+template<typename Scalar>
+inline bool isApprox(const Scalar& x, const Scalar& y,
+ typename NumTraits<Scalar>::Real precision = NumTraits<Scalar>::dummy_precision())
+{
+ return scalar_fuzzy_impl<Scalar>::isApprox(x, y, precision);
+}
+
+template<typename Scalar>
+inline bool isApproxOrLessThan(const Scalar& x, const Scalar& y,
+ typename NumTraits<Scalar>::Real precision = NumTraits<Scalar>::dummy_precision())
+{
+ return scalar_fuzzy_impl<Scalar>::isApproxOrLessThan(x, y, precision);
+}
+
+/******************************************
+*** The special case of the bool type ***
+******************************************/
+
+template<> struct random_impl<bool>
+{
+ static inline bool run()
+ {
+ return random<int>(0,1)==0 ? false : true;
+ }
+};
+
+template<> struct scalar_fuzzy_impl<bool>
+{
+ typedef bool RealScalar;
+
+ template<typename OtherScalar>
+ 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;
+ }
+
+};
+
+/****************************************************************************
+* Special functions *
+****************************************************************************/
+
+// std::isfinite is non standard, so let's define our own version,
+// even though it is not very efficient.
+template<typename T> bool (isfinite)(const T& x)
+{
+ return x<NumTraits<T>::highest() && x>NumTraits<T>::lowest();
+}
+
+} // end namespace internal
+
+} // end namespace Eigen
+
+#endif // EIGEN_MATHFUNCTIONS_H
diff --git a/Eigen/src/Core/Matrix.h b/Eigen/src/Core/Matrix.h
new file mode 100644
index 000000000..99160b591
--- /dev/null
+++ b/Eigen/src/Core/Matrix.h
@@ -0,0 +1,405 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra.
+//
+// Copyright (C) 2006-2010 Benoit Jacob <jacob.benoit.1@gmail.com>
+// Copyright (C) 2008-2009 Gael Guennebaud <gael.guennebaud@inria.fr>
+//
+// This Source Code Form is subject to the terms of the Mozilla
+// Public License v. 2.0. If a copy of the MPL was not distributed
+// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+#ifndef EIGEN_MATRIX_H
+#define EIGEN_MATRIX_H
+
+namespace Eigen {
+
+/** \class Matrix
+ * \ingroup Core_Module
+ *
+ * \brief The matrix class, also used for vectors and row-vectors
+ *
+ * The %Matrix class is the work-horse for all \em dense (\ref dense "note") matrices and vectors within Eigen.
+ * Vectors are matrices with one column, and row-vectors are matrices with one row.
+ *
+ * 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<float>.
+ * User defined sclar 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
+ * \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.
+ * \tparam _MaxRows Maximum number of rows. Defaults to \a _Rows (\ref maxrows "note").
+ * \tparam _MaxCols Maximum number of columns. Defaults to \a _Cols (\ref maxrows "note").
+ *
+ * Eigen provides a number of typedefs covering the usual cases. Here are some examples:
+ *
+ * \li \c Matrix2d is a 2x2 square matrix of doubles (\c Matrix<double, 2, 2>)
+ * \li \c Vector4f is a vector of 4 floats (\c Matrix<float, 4, 1>)
+ * \li \c RowVector3i is a row-vector of 3 ints (\c Matrix<int, 1, 3>)
+ *
+ * \li \c MatrixXf is a dynamic-size matrix of floats (\c Matrix<float, Dynamic, Dynamic>)
+ * \li \c VectorXf is a dynamic-size vector of floats (\c Matrix<float, Dynamic, 1>)
+ *
+ * \li \c Matrix2Xf is a partially fixed-size (dynamic-size) matrix of floats (\c Matrix<float, 2, Dynamic>)
+ * \li \c MatrixX3d is a partially dynamic-size (fixed-size) matrix of double (\c Matrix<double, Dynamic, 3>)
+ *
+ * See \link matrixtypedefs this page \endlink for a complete list of predefined \em %Matrix and \em Vector typedefs.
+ *
+ * You can access elements of vectors and matrices using normal subscripting:
+ *
+ * \code
+ * Eigen::VectorXd v(10);
+ * v[0] = 0.1;
+ * v[1] = 0.2;
+ * v(0) = 0.3;
+ * v(1) = 0.4;
+ *
+ * Eigen::MatrixXi m(10, 10);
+ * m(0, 1) = 1;
+ * m(0, 2) = 2;
+ * m(0, 3) = 3;
+ * \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.
+ *
+ * <i><b>Some notes:</b></i>
+ *
+ * <dl>
+ * <dt><b>\anchor dense Dense versus sparse:</b></dt>
+ * <dd>This %Matrix class handles dense, not sparse matrices and vectors. For sparse matrices and vectors, see the Sparse module.
+ *
+ * Dense matrices and vectors are plain usual arrays of coefficients. All the coefficients are stored, in an ordinary contiguous array.
+ * This is unlike Sparse matrices and vectors where the coefficients are stored as a list of nonzero coefficients.</dd>
+ *
+ * <dt><b>\anchor fixedsize Fixed-size versus dynamic-size:</b></dt>
+ * <dd>Fixed-size means that the numbers of rows and columns are known are compile-time. In this case, Eigen allocates the array
+ * of coefficients as a fixed-size array, as a class member. This makes sense for very small matrices, typically up to 4x4, sometimes up
+ * to 16x16. Larger matrices should be declared as dynamic-size even if one happens to know their size at compile-time.
+ *
+ * Dynamic-size means that the numbers of rows or columns are not necessarily known at compile-time. In this case they are runtime
+ * variables, and the array of coefficients is allocated dynamically on the heap.
+ *
+ * Note that \em dense matrices, be they Fixed-size or Dynamic-size, <em>do not</em> expand dynamically in the sense of a std::map.
+ * If you want this behavior, see the Sparse module.</dd>
+ *
+ * <dt><b>\anchor maxrows _MaxRows and _MaxCols:</b></dt>
+ * <dd>In most cases, one just leaves these parameters to the default values.
+ * These parameters mean the maximum size of rows and columns that the matrix may have. They are useful in cases
+ * when the exact numbers of rows and columns are not known are compile-time, but it is known at compile-time that they cannot
+ * exceed a certain value. This happens when taking dynamic-size blocks inside fixed-size matrices: in this case _MaxRows and _MaxCols
+ * are the dimensions of the original matrix, while _Rows and _Cols are Dynamic.</dd>
+ * </dl>
+ *
+ * \see MatrixBase for the majority of the API methods for matrices, \ref TopicClassHierarchy,
+ * \ref TopicStorageOrders
+ */
+
+namespace internal {
+template<typename _Scalar, int _Rows, int _Cols, int _Options, int _MaxRows, int _MaxCols>
+struct traits<Matrix<_Scalar, _Rows, _Cols, _Options, _MaxRows, _MaxCols> >
+{
+ 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<Scalar>::ReadCost,
+ Options = _Options,
+ InnerStrideAtCompileTime = 1,
+ OuterStrideAtCompileTime = (Options&RowMajor) ? ColsAtCompileTime : RowsAtCompileTime
+ };
+};
+}
+
+template<typename _Scalar, int _Rows, int _Cols, int _Options, int _MaxRows, int _MaxCols>
+class Matrix
+ : public PlainObjectBase<Matrix<_Scalar, _Rows, _Cols, _Options, _MaxRows, _MaxCols> >
+{
+ public:
+
+ /** \brief Base class typedef.
+ * \sa PlainObjectBase
+ */
+ typedef PlainObjectBase<Matrix> Base;
+
+ enum { Options = _Options };
+
+ EIGEN_DENSE_PUBLIC_INTERFACE(Matrix)
+
+ typedef typename Base::PlainObject PlainObject;
+
+ using Base::base;
+ using Base::coeffRef;
+
+ /**
+ * \brief Assigns matrices to each other.
+ *
+ * \note This is a special case of the templated operator=. Its purpose is
+ * to prevent a default operator= from hiding the templated operator=.
+ *
+ * \callgraph
+ */
+ EIGEN_STRONG_INLINE Matrix& operator=(const Matrix& other)
+ {
+ return Base::_set(other);
+ }
+
+ /** \internal
+ * \brief 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),
+ * it will be initialized.
+ *
+ * Note that copying a row-vector into a vector (and conversely) is allowed.
+ * The resizing, if any, is then done in the appropriate way so that row-vectors
+ * remain row-vectors and vectors remain vectors.
+ */
+ template<typename OtherDerived>
+ EIGEN_STRONG_INLINE Matrix& operator=(const MatrixBase<OtherDerived>& other)
+ {
+ return Base::_set(other);
+ }
+
+ /* Here, doxygen failed to copy the brief information when using \copydoc */
+
+ /**
+ * \brief Copies the generic expression \a other into *this.
+ * \copydetails DenseBase::operator=(const EigenBase<OtherDerived> &other)
+ */
+ template<typename OtherDerived>
+ EIGEN_STRONG_INLINE Matrix& operator=(const EigenBase<OtherDerived> &other)
+ {
+ return Base::operator=(other);
+ }
+
+ template<typename OtherDerived>
+ EIGEN_STRONG_INLINE Matrix& operator=(const ReturnByValue<OtherDerived>& func)
+ {
+ return Base::operator=(func);
+ }
+
+ /** \brief Default constructor.
+ *
+ * For fixed-size matrices, does nothing.
+ *
+ * For dynamic-size matrices, creates an empty matrix of size 0. Does not allocate any array. Such a matrix
+ * is called a null matrix. This constructor is the unique way to create null matrices: resizing
+ * a matrix to 0 is not supported.
+ *
+ * \sa resize(Index,Index)
+ */
+ EIGEN_STRONG_INLINE explicit Matrix() : Base()
+ {
+ Base::_check_template_params();
+ EIGEN_INITIALIZE_BY_ZERO_IF_THAT_OPTION_IS_ENABLED
+ }
+
+ // FIXME is it still needed
+ Matrix(internal::constructor_without_unaligned_array_assert)
+ : Base(internal::constructor_without_unaligned_array_assert())
+ { Base::_check_template_params(); EIGEN_INITIALIZE_BY_ZERO_IF_THAT_OPTION_IS_ENABLED }
+
+ /** \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)
+ {
+ Base::_check_template_params();
+ EIGEN_STATIC_ASSERT_VECTOR_ONLY(Matrix)
+ eigen_assert(dim >= 0);
+ eigen_assert(SizeAtCompileTime == Dynamic || SizeAtCompileTime == dim);
+ EIGEN_INITIALIZE_BY_ZERO_IF_THAT_OPTION_IS_ENABLED
+ }
+
+ #ifndef EIGEN_PARSED_BY_DOXYGEN
+ template<typename T0, typename T1>
+ EIGEN_STRONG_INLINE Matrix(const T0& x, const T1& y)
+ {
+ Base::_check_template_params();
+ Base::template _init2<T0,T1>(x, y);
+ }
+ #else
+ /** \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(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_STRONG_INLINE Matrix(const Scalar& x, const Scalar& y, const Scalar& z)
+ {
+ Base::_check_template_params();
+ EIGEN_STATIC_ASSERT_VECTOR_SPECIFIC_SIZE(Matrix, 3)
+ m_storage.data()[0] = x;
+ m_storage.data()[1] = y;
+ m_storage.data()[2] = z;
+ }
+ /** \brief Constructs an initialized 4D vector with given coefficients */
+ EIGEN_STRONG_INLINE Matrix(const Scalar& x, const Scalar& y, const Scalar& z, const Scalar& w)
+ {
+ Base::_check_template_params();
+ EIGEN_STATIC_ASSERT_VECTOR_SPECIFIC_SIZE(Matrix, 4)
+ m_storage.data()[0] = x;
+ m_storage.data()[1] = y;
+ m_storage.data()[2] = z;
+ m_storage.data()[3] = w;
+ }
+
+ explicit Matrix(const Scalar *data);
+
+ /** \brief Constructor copying the value of the expression \a other */
+ template<typename OtherDerived>
+ EIGEN_STRONG_INLINE Matrix(const MatrixBase<OtherDerived>& 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<Scalar, typename OtherDerived::Scalar>::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<typename OtherDerived>
+ EIGEN_STRONG_INLINE Matrix(const ReturnByValue<OtherDerived>& other)
+ {
+ Base::_check_template_params();
+ Base::resize(other.rows(), other.cols());
+ other.evalTo(*this);
+ }
+
+ /** \brief Copy constructor for generic expressions.
+ * \sa MatrixBase::operator=(const EigenBase<OtherDerived>&)
+ */
+ template<typename OtherDerived>
+ EIGEN_STRONG_INLINE Matrix(const EigenBase<OtherDerived> &other)
+ : Base(other.derived().rows() * other.derived().cols(), other.derived().rows(), other.derived().cols())
+ {
+ Base::_check_template_params();
+ Base::resize(other.rows(), other.cols());
+ // 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<typename OtherDerived>
+ void swap(MatrixBase<OtherDerived> const & other)
+ { this->_swap(other.derived()); }
+
+ inline Index innerStride() const { return 1; }
+ inline Index outerStride() const { return this->innerSize(); }
+
+ /////////// Geometry module ///////////
+
+ template<typename OtherDerived>
+ explicit Matrix(const RotationBase<OtherDerived,ColsAtCompileTime>& r);
+ template<typename OtherDerived>
+ Matrix& operator=(const RotationBase<OtherDerived,ColsAtCompileTime>& r);
+
+ #ifdef EIGEN2_SUPPORT
+ template<typename OtherDerived>
+ explicit Matrix(const eigen2_RotationBase<OtherDerived,ColsAtCompileTime>& r);
+ template<typename OtherDerived>
+ Matrix& operator=(const eigen2_RotationBase<OtherDerived,ColsAtCompileTime>& r);
+ #endif
+
+ // allow to extend Matrix outside Eigen
+ #ifdef EIGEN_MATRIX_PLUGIN
+ #include EIGEN_MATRIX_PLUGIN
+ #endif
+
+ protected:
+ template <typename Derived, typename OtherDerived, bool IsVector>
+ friend struct internal::conservative_resize_like_impl;
+
+ using Base::m_storage;
+};
+
+/** \defgroup matrixtypedefs Global matrix typedefs
+ *
+ * \ingroup Core_Module
+ *
+ * Eigen defines several typedef shortcuts for most common matrix and vector types.
+ *
+ * The general patterns are the following:
+ *
+ * \c MatrixSizeType where \c Size can be \c 2,\c 3,\c 4 for fixed size square matrices or \c X for dynamic size,
+ * and where \c Type can be \c i for integer, \c f for float, \c d for double, \c cf for complex float, \c cd
+ * for complex double.
+ *
+ * For example, \c Matrix3d is a fixed-size 3x3 matrix type of doubles, and \c MatrixXf is a dynamic-size matrix of floats.
+ *
+ * There are also \c VectorSizeType and \c RowVectorSizeType which are self-explanatory. For example, \c Vector4cf is
+ * a fixed-size vector of 4 complex floats.
+ *
+ * \sa class Matrix
+ */
+
+#define EIGEN_MAKE_TYPEDEFS(Type, TypeSuffix, Size, SizeSuffix) \
+/** \ingroup matrixtypedefs */ \
+typedef Matrix<Type, Size, Size> Matrix##SizeSuffix##TypeSuffix; \
+/** \ingroup matrixtypedefs */ \
+typedef Matrix<Type, Size, 1> Vector##SizeSuffix##TypeSuffix; \
+/** \ingroup matrixtypedefs */ \
+typedef Matrix<Type, 1, Size> RowVector##SizeSuffix##TypeSuffix;
+
+#define EIGEN_MAKE_FIXED_TYPEDEFS(Type, TypeSuffix, Size) \
+/** \ingroup matrixtypedefs */ \
+typedef Matrix<Type, Size, Dynamic> Matrix##Size##X##TypeSuffix; \
+/** \ingroup matrixtypedefs */ \
+typedef Matrix<Type, Dynamic, Size> Matrix##X##Size##TypeSuffix;
+
+#define EIGEN_MAKE_TYPEDEFS_ALL_SIZES(Type, TypeSuffix) \
+EIGEN_MAKE_TYPEDEFS(Type, TypeSuffix, 2, 2) \
+EIGEN_MAKE_TYPEDEFS(Type, TypeSuffix, 3, 3) \
+EIGEN_MAKE_TYPEDEFS(Type, TypeSuffix, 4, 4) \
+EIGEN_MAKE_TYPEDEFS(Type, TypeSuffix, Dynamic, X) \
+EIGEN_MAKE_FIXED_TYPEDEFS(Type, TypeSuffix, 2) \
+EIGEN_MAKE_FIXED_TYPEDEFS(Type, TypeSuffix, 3) \
+EIGEN_MAKE_FIXED_TYPEDEFS(Type, TypeSuffix, 4)
+
+EIGEN_MAKE_TYPEDEFS_ALL_SIZES(int, i)
+EIGEN_MAKE_TYPEDEFS_ALL_SIZES(float, f)
+EIGEN_MAKE_TYPEDEFS_ALL_SIZES(double, d)
+EIGEN_MAKE_TYPEDEFS_ALL_SIZES(std::complex<float>, cf)
+EIGEN_MAKE_TYPEDEFS_ALL_SIZES(std::complex<double>, cd)
+
+#undef EIGEN_MAKE_TYPEDEFS_ALL_SIZES
+#undef EIGEN_MAKE_TYPEDEFS
+#undef EIGEN_MAKE_FIXED_TYPEDEFS
+
+} // end namespace Eigen
+
+#endif // EIGEN_MATRIX_H
diff --git a/Eigen/src/Core/MatrixBase.h b/Eigen/src/Core/MatrixBase.h
new file mode 100644
index 000000000..c1e0ed132
--- /dev/null
+++ b/Eigen/src/Core/MatrixBase.h
@@ -0,0 +1,511 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra.
+//
+// Copyright (C) 2006-2009 Benoit Jacob <jacob.benoit.1@gmail.com>
+// Copyright (C) 2008 Gael Guennebaud <gael.guennebaud@inria.fr>
+//
+// This Source Code Form is subject to the terms of the Mozilla
+// Public License v. 2.0. If a copy of the MPL was not distributed
+// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+#ifndef EIGEN_MATRIXBASE_H
+#define EIGEN_MATRIXBASE_H
+
+namespace Eigen {
+
+/** \class MatrixBase
+ * \ingroup Core_Module
+ *
+ * \brief Base class for all dense matrices, vectors, and expressions
+ *
+ * This class is the base that is inherited by all matrix, vector, and related expression
+ * types. Most of the Eigen API is contained in this class, and its base classes. Other important
+ * classes for the Eigen API are Matrix, and VectorwiseOp.
+ *
+ * Note that some methods are defined in other modules such as the \ref LU_Module LU module
+ * for all functions related to matrix inversions.
+ *
+ * \tparam Derived is the derived type, e.g. a matrix type, or an expression, etc.
+ *
+ * When writing a function taking Eigen objects as argument, if you want your function
+ * to take as argument any matrix, vector, or expression, just let it take a
+ * MatrixBase argument. As an example, here is a function printFirstRow which, given
+ * a matrix, vector, or expression \a x, prints the first row of \a x.
+ *
+ * \code
+ template<typename Derived>
+ void printFirstRow(const Eigen::MatrixBase<Derived>& x)
+ {
+ cout << x.row(0) << endl;
+ }
+ * \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.
+ *
+ * \sa \ref TopicClassHierarchy
+ */
+template<typename Derived> class MatrixBase
+ : public DenseBase<Derived>
+{
+ public:
+#ifndef EIGEN_PARSED_BY_DOXYGEN
+ typedef MatrixBase StorageBaseType;
+ typedef typename internal::traits<Derived>::StorageKind StorageKind;
+ typedef typename internal::traits<Derived>::Index Index;
+ typedef typename internal::traits<Derived>::Scalar Scalar;
+ typedef typename internal::packet_traits<Scalar>::type PacketScalar;
+ typedef typename NumTraits<Scalar>::Real RealScalar;
+
+ typedef DenseBase<Derived> Base;
+ using Base::RowsAtCompileTime;
+ using Base::ColsAtCompileTime;
+ using Base::SizeAtCompileTime;
+ using Base::MaxRowsAtCompileTime;
+ using Base::MaxColsAtCompileTime;
+ using Base::MaxSizeAtCompileTime;
+ using Base::IsVectorAtCompileTime;
+ using Base::Flags;
+ using Base::CoeffReadCost;
+
+ using Base::derived;
+ using Base::const_cast_derived;
+ using Base::rows;
+ using Base::cols;
+ using Base::size;
+ using Base::coeff;
+ using Base::coeffRef;
+ using Base::lazyAssign;
+ using Base::eval;
+ using Base::operator+=;
+ using Base::operator-=;
+ using Base::operator*=;
+ using Base::operator/=;
+
+ typedef typename Base::CoeffReturnType CoeffReturnType;
+ typedef typename Base::ConstTransposeReturnType ConstTransposeReturnType;
+ typedef typename Base::RowXpr RowXpr;
+ typedef typename Base::ColXpr ColXpr;
+#endif // not EIGEN_PARSED_BY_DOXYGEN
+
+
+
+#ifndef EIGEN_PARSED_BY_DOXYGEN
+ /** type of the equivalent square matrix */
+ typedef Matrix<Scalar,EIGEN_SIZE_MAX(RowsAtCompileTime,ColsAtCompileTime),
+ EIGEN_SIZE_MAX(RowsAtCompileTime,ColsAtCompileTime)> SquareMatrixType;
+#endif // not EIGEN_PARSED_BY_DOXYGEN
+
+ /** \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()); }
+
+ /** \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<typename internal::traits<Derived>::Scalar,
+ internal::traits<Derived>::RowsAtCompileTime,
+ internal::traits<Derived>::ColsAtCompileTime,
+ AutoAlign | (internal::traits<Derived>::Flags&RowMajorBit ? RowMajor : ColMajor),
+ internal::traits<Derived>::MaxRowsAtCompileTime,
+ internal::traits<Derived>::MaxColsAtCompileTime
+ > PlainObject;
+
+#ifndef EIGEN_PARSED_BY_DOXYGEN
+ /** \internal Represents a matrix with all coefficients equal to one another*/
+ typedef CwiseNullaryOp<internal::scalar_constant_op<Scalar>,Derived> ConstantReturnType;
+ /** \internal the return type of MatrixBase::adjoint() */
+ typedef typename internal::conditional<NumTraits<Scalar>::IsComplex,
+ CwiseUnaryOp<internal::scalar_conjugate_op<Scalar>, ConstTransposeReturnType>,
+ ConstTransposeReturnType
+ >::type AdjointReturnType;
+ /** \internal Return type of eigenvalues() */
+ typedef Matrix<std::complex<RealScalar>, internal::traits<Derived>::ColsAtCompileTime, 1, ColMajor> EigenvaluesReturnType;
+ /** \internal the return type of identity */
+ typedef CwiseNullaryOp<internal::scalar_identity_op<Scalar>,Derived> IdentityReturnType;
+ /** \internal the return type of unit vectors */
+ typedef Block<const CwiseNullaryOp<internal::scalar_identity_op<Scalar>, SquareMatrixType>,
+ internal::traits<Derived>::RowsAtCompileTime,
+ internal::traits<Derived>::ColsAtCompileTime> BasisReturnType;
+#endif // not EIGEN_PARSED_BY_DOXYGEN
+
+#define EIGEN_CURRENT_STORAGE_BASE_CLASS Eigen::MatrixBase
+# include "../plugins/CommonCwiseUnaryOps.h"
+# include "../plugins/CommonCwiseBinaryOps.h"
+# include "../plugins/MatrixCwiseUnaryOps.h"
+# include "../plugins/MatrixCwiseBinaryOps.h"
+# ifdef EIGEN_MATRIXBASE_PLUGIN
+# include EIGEN_MATRIXBASE_PLUGIN
+# endif
+#undef EIGEN_CURRENT_STORAGE_BASE_CLASS
+
+ /** Special case of the template operator=, in order to prevent the compiler
+ * from generating a default operator= (issue hit with g++ 4.1)
+ */
+ Derived& operator=(const MatrixBase& other);
+
+ // We cannot inherit here via Base::operator= since it is causing
+ // trouble with MSVC.
+
+ template <typename OtherDerived>
+ Derived& operator=(const DenseBase<OtherDerived>& other);
+
+ template <typename OtherDerived>
+ Derived& operator=(const EigenBase<OtherDerived>& other);
+
+ template<typename OtherDerived>
+ Derived& operator=(const ReturnByValue<OtherDerived>& other);
+
+#ifndef EIGEN_PARSED_BY_DOXYGEN
+ template<typename ProductDerived, typename Lhs, typename Rhs>
+ Derived& lazyAssign(const ProductBase<ProductDerived, Lhs,Rhs>& other);
+#endif // not EIGEN_PARSED_BY_DOXYGEN
+
+ template<typename OtherDerived>
+ Derived& operator+=(const MatrixBase<OtherDerived>& other);
+ template<typename OtherDerived>
+ Derived& operator-=(const MatrixBase<OtherDerived>& other);
+
+ template<typename OtherDerived>
+ const typename ProductReturnType<Derived,OtherDerived>::Type
+ operator*(const MatrixBase<OtherDerived> &other) const;
+
+ template<typename OtherDerived>
+ const typename LazyProductReturnType<Derived,OtherDerived>::Type
+ lazyProduct(const MatrixBase<OtherDerived> &other) const;
+
+ template<typename OtherDerived>
+ Derived& operator*=(const EigenBase<OtherDerived>& other);
+
+ template<typename OtherDerived>
+ void applyOnTheLeft(const EigenBase<OtherDerived>& other);
+
+ template<typename OtherDerived>
+ void applyOnTheRight(const EigenBase<OtherDerived>& other);
+
+ template<typename DiagonalDerived>
+ const DiagonalProduct<Derived, DiagonalDerived, OnTheRight>
+ operator*(const DiagonalBase<DiagonalDerived> &diagonal) const;
+
+ template<typename OtherDerived>
+ typename internal::scalar_product_traits<typename internal::traits<Derived>::Scalar,typename internal::traits<OtherDerived>::Scalar>::ReturnType
+ dot(const MatrixBase<OtherDerived>& other) const;
+
+ #ifdef EIGEN2_SUPPORT
+ template<typename OtherDerived>
+ Scalar eigen2_dot(const MatrixBase<OtherDerived>& other) const;
+ #endif
+
+ RealScalar squaredNorm() const;
+ RealScalar norm() const;
+ RealScalar stableNorm() const;
+ RealScalar blueNorm() const;
+ RealScalar hypotNorm() const;
+ const PlainObject normalized() const;
+ void normalize();
+
+ const AdjointReturnType adjoint() const;
+ void adjointInPlace();
+
+ typedef Diagonal<Derived> DiagonalReturnType;
+ DiagonalReturnType diagonal();
+ typedef const Diagonal<const Derived> ConstDiagonalReturnType;
+ const ConstDiagonalReturnType diagonal() const;
+
+ template<int Index> struct DiagonalIndexReturnType { typedef Diagonal<Derived,Index> Type; };
+ template<int Index> struct ConstDiagonalIndexReturnType { typedef const Diagonal<const Derived,Index> Type; };
+
+ template<int Index> typename DiagonalIndexReturnType<Index>::Type diagonal();
+ template<int Index> typename ConstDiagonalIndexReturnType<Index>::Type diagonal() const;
+
+ // Note: The "MatrixBase::" prefixes are added to help MSVC9 to match these declarations with the later implementations.
+ // On the other hand they confuse MSVC8...
+ #if (defined _MSC_VER) && (_MSC_VER >= 1500) // 2008 or later
+ typename MatrixBase::template DiagonalIndexReturnType<Dynamic>::Type diagonal(Index index);
+ typename MatrixBase::template ConstDiagonalIndexReturnType<Dynamic>::Type diagonal(Index index) const;
+ #else
+ typename DiagonalIndexReturnType<Dynamic>::Type diagonal(Index index);
+ typename ConstDiagonalIndexReturnType<Dynamic>::Type diagonal(Index index) const;
+ #endif
+
+ #ifdef EIGEN2_SUPPORT
+ template<unsigned int Mode> typename internal::eigen2_part_return_type<Derived, Mode>::type part();
+ template<unsigned int Mode> const typename internal::eigen2_part_return_type<Derived, Mode>::type part() const;
+
+ // huuuge hack. make Eigen2's matrix.part<Diagonal>() 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<template<typename T, int n> class U>
+ const DiagonalWrapper<ConstDiagonalReturnType> part() const
+ { return diagonal().asDiagonal(); }
+ #endif // EIGEN2_SUPPORT
+
+ template<unsigned int Mode> struct TriangularViewReturnType { typedef TriangularView<Derived, Mode> Type; };
+ template<unsigned int Mode> struct ConstTriangularViewReturnType { typedef const TriangularView<const Derived, Mode> Type; };
+
+ template<unsigned int Mode> typename TriangularViewReturnType<Mode>::Type triangularView();
+ template<unsigned int Mode> typename ConstTriangularViewReturnType<Mode>::Type triangularView() const;
+
+ template<unsigned int UpLo> struct SelfAdjointViewReturnType { typedef SelfAdjointView<Derived, UpLo> Type; };
+ template<unsigned int UpLo> struct ConstSelfAdjointViewReturnType { typedef const SelfAdjointView<const Derived, UpLo> Type; };
+
+ template<unsigned int UpLo> typename SelfAdjointViewReturnType<UpLo>::Type selfadjointView();
+ template<unsigned int UpLo> typename ConstSelfAdjointViewReturnType<UpLo>::Type selfadjointView() const;
+
+ const SparseView<Derived> sparseView(const Scalar& m_reference = Scalar(0),
+ typename NumTraits<Scalar>::Real m_epsilon = NumTraits<Scalar>::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();
+
+ const DiagonalWrapper<const Derived> asDiagonal() const;
+ const PermutationWrapper<const Derived> asPermutation() const;
+
+ Derived& setIdentity();
+ Derived& setIdentity(Index rows, Index cols);
+
+ bool isIdentity(RealScalar prec = NumTraits<Scalar>::dummy_precision()) const;
+ bool isDiagonal(RealScalar prec = NumTraits<Scalar>::dummy_precision()) const;
+
+ bool isUpperTriangular(RealScalar prec = NumTraits<Scalar>::dummy_precision()) const;
+ bool isLowerTriangular(RealScalar prec = NumTraits<Scalar>::dummy_precision()) const;
+
+ template<typename OtherDerived>
+ bool isOrthogonal(const MatrixBase<OtherDerived>& other,
+ RealScalar prec = NumTraits<Scalar>::dummy_precision()) const;
+ bool isUnitary(RealScalar prec = NumTraits<Scalar>::dummy_precision()) const;
+
+ /** \returns true if each coefficients of \c *this and \a other are all exactly equal.
+ * \warning When using floating point scalar values you probably should rather use a
+ * fuzzy comparison such as isApprox()
+ * \sa isApprox(), operator!= */
+ template<typename OtherDerived>
+ inline bool operator==(const MatrixBase<OtherDerived>& 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.
+ * \warning When using floating point scalar values you probably should rather use a
+ * fuzzy comparison such as isApprox()
+ * \sa isApprox(), operator== */
+ template<typename OtherDerived>
+ inline bool operator!=(const MatrixBase<OtherDerived>& other) const
+ { return cwiseNotEqual(other).any(); }
+
+ NoAlias<Derived,Eigen::MatrixBase > noalias();
+
+ inline const ForceAlignedAccess<Derived> forceAlignedAccess() const;
+ inline ForceAlignedAccess<Derived> forceAlignedAccess();
+ template<bool Enable> inline typename internal::add_const_on_value_type<typename internal::conditional<Enable,ForceAlignedAccess<Derived>,Derived&>::type>::type forceAlignedAccessIf() const;
+ template<bool Enable> inline typename internal::conditional<Enable,ForceAlignedAccess<Derived>,Derived&>::type forceAlignedAccessIf();
+
+ Scalar trace() const;
+
+/////////// Array module ///////////
+
+ template<int p> RealScalar lpNorm() const;
+
+ MatrixBase<Derived>& matrix() { return *this; }
+ const MatrixBase<Derived>& matrix() const { return *this; }
+
+ /** \returns an \link ArrayBase Array \endlink expression of this matrix
+ * \sa ArrayBase::matrix() */
+ ArrayWrapper<Derived> array() { return derived(); }
+ const ArrayWrapper<const Derived> array() const { return derived(); }
+
+/////////// LU module ///////////
+
+ const FullPivLU<PlainObject> fullPivLu() const;
+ const PartialPivLU<PlainObject> partialPivLu() const;
+
+ #if EIGEN2_SUPPORT_STAGE < STAGE20_RESOLVE_API_CONFLICTS
+ const LU<PlainObject> lu() const;
+ #endif
+
+ #ifdef EIGEN2_SUPPORT
+ const LU<PlainObject> eigen2_lu() const;
+ #endif
+
+ #if EIGEN2_SUPPORT_STAGE > STAGE20_RESOLVE_API_CONFLICTS
+ const PartialPivLU<PlainObject> lu() const;
+ #endif
+
+ #ifdef EIGEN2_SUPPORT
+ template<typename ResultType>
+ void computeInverse(MatrixBase<ResultType> *result) const {
+ *result = this->inverse();
+ }
+ #endif
+
+ const internal::inverse_impl<Derived> inverse() const;
+ template<typename ResultType>
+ void computeInverseAndDetWithCheck(
+ ResultType& inverse,
+ typename ResultType::Scalar& determinant,
+ bool& invertible,
+ const RealScalar& absDeterminantThreshold = NumTraits<Scalar>::dummy_precision()
+ ) const;
+ template<typename ResultType>
+ void computeInverseWithCheck(
+ ResultType& inverse,
+ bool& invertible,
+ const RealScalar& absDeterminantThreshold = NumTraits<Scalar>::dummy_precision()
+ ) const;
+ Scalar determinant() const;
+
+/////////// Cholesky module ///////////
+
+ const LLT<PlainObject> llt() const;
+ const LDLT<PlainObject> ldlt() const;
+
+/////////// QR module ///////////
+
+ const HouseholderQR<PlainObject> householderQr() const;
+ const ColPivHouseholderQR<PlainObject> colPivHouseholderQr() const;
+ const FullPivHouseholderQR<PlainObject> fullPivHouseholderQr() const;
+
+ #ifdef EIGEN2_SUPPORT
+ const QR<PlainObject> qr() const;
+ #endif
+
+ EigenvaluesReturnType eigenvalues() const;
+ RealScalar operatorNorm() const;
+
+/////////// SVD module ///////////
+
+ JacobiSVD<PlainObject> jacobiSvd(unsigned int computationOptions = 0) const;
+
+ #ifdef EIGEN2_SUPPORT
+ SVD<PlainObject> svd() const;
+ #endif
+
+/////////// Geometry module ///////////
+
+ #ifndef EIGEN_PARSED_BY_DOXYGEN
+ /// \internal helper struct to form the return type of the cross product
+ template<typename OtherDerived> struct cross_product_return_type {
+ typedef typename internal::scalar_product_traits<typename internal::traits<Derived>::Scalar,typename internal::traits<OtherDerived>::Scalar>::ReturnType Scalar;
+ typedef Matrix<Scalar,MatrixBase::RowsAtCompileTime,MatrixBase::ColsAtCompileTime> type;
+ };
+ #endif // EIGEN_PARSED_BY_DOXYGEN
+ template<typename OtherDerived>
+ typename cross_product_return_type<OtherDerived>::type
+ cross(const MatrixBase<OtherDerived>& other) const;
+ template<typename OtherDerived>
+ PlainObject cross3(const MatrixBase<OtherDerived>& other) const;
+ PlainObject unitOrthogonal(void) const;
+ Matrix<Scalar,3,1> eulerAngles(Index a0, Index a1, Index a2) const;
+
+ #if EIGEN2_SUPPORT_STAGE > STAGE20_RESOLVE_API_CONFLICTS
+ ScalarMultipleReturnType operator*(const UniformScaling<Scalar>& s) const;
+ // put this as separate enum value to work around possible GCC 4.3 bug (?)
+ enum { HomogeneousReturnTypeDirection = ColsAtCompileTime==1?Vertical:Horizontal };
+ typedef Homogeneous<Derived, HomogeneousReturnTypeDirection> HomogeneousReturnType;
+ HomogeneousReturnType homogeneous() const;
+ #endif
+
+ enum {
+ SizeMinusOne = SizeAtCompileTime==Dynamic ? Dynamic : SizeAtCompileTime-1
+ };
+ typedef Block<const Derived,
+ internal::traits<Derived>::ColsAtCompileTime==1 ? SizeMinusOne : 1,
+ internal::traits<Derived>::ColsAtCompileTime==1 ? 1 : SizeMinusOne> ConstStartMinusOne;
+ typedef CwiseUnaryOp<internal::scalar_quotient1_op<typename internal::traits<Derived>::Scalar>,
+ const ConstStartMinusOne > HNormalizedReturnType;
+
+ const HNormalizedReturnType hnormalized() const;
+
+////////// Householder module ///////////
+
+ void makeHouseholderInPlace(Scalar& tau, RealScalar& beta);
+ template<typename EssentialPart>
+ void makeHouseholder(EssentialPart& essential,
+ Scalar& tau, RealScalar& beta) const;
+ template<typename EssentialPart>
+ void applyHouseholderOnTheLeft(const EssentialPart& essential,
+ const Scalar& tau,
+ Scalar* workspace);
+ template<typename EssentialPart>
+ void applyHouseholderOnTheRight(const EssentialPart& essential,
+ const Scalar& tau,
+ Scalar* workspace);
+
+///////// Jacobi module /////////
+
+ template<typename OtherScalar>
+ void applyOnTheLeft(Index p, Index q, const JacobiRotation<OtherScalar>& j);
+ template<typename OtherScalar>
+ void applyOnTheRight(Index p, Index q, const JacobiRotation<OtherScalar>& j);
+
+///////// MatrixFunctions module /////////
+
+ typedef typename internal::stem_function<Scalar>::type StemFunction;
+ const MatrixExponentialReturnValue<Derived> exp() const;
+ const MatrixFunctionReturnValue<Derived> matrixFunction(StemFunction f) const;
+ const MatrixFunctionReturnValue<Derived> cosh() const;
+ const MatrixFunctionReturnValue<Derived> sinh() const;
+ const MatrixFunctionReturnValue<Derived> cos() const;
+ const MatrixFunctionReturnValue<Derived> sin() const;
+ const MatrixSquareRootReturnValue<Derived> sqrt() const;
+ const MatrixLogarithmReturnValue<Derived> log() const;
+
+#ifdef EIGEN2_SUPPORT
+ template<typename ProductDerived, typename Lhs, typename Rhs>
+ Derived& operator+=(const Flagged<ProductBase<ProductDerived, Lhs,Rhs>, 0,
+ EvalBeforeAssigningBit>& other);
+
+ template<typename ProductDerived, typename Lhs, typename Rhs>
+ Derived& operator-=(const Flagged<ProductBase<ProductDerived, Lhs,Rhs>, 0,
+ EvalBeforeAssigningBit>& other);
+
+ /** \deprecated because .lazy() is deprecated
+ * Overloaded for cache friendly product evaluation */
+ template<typename OtherDerived>
+ Derived& lazyAssign(const Flagged<OtherDerived, 0, EvalBeforeAssigningBit>& other)
+ { return lazyAssign(other._expression()); }
+
+ template<unsigned int Added>
+ const Flagged<Derived, Added, 0> marked() const;
+ const Flagged<Derived, 0, EvalBeforeAssigningBit> lazy() const;
+
+ inline const Cwise<Derived> cwise() const;
+ inline Cwise<Derived> cwise();
+
+ VectorBlock<Derived> start(Index size);
+ const VectorBlock<const Derived> start(Index size) const;
+ VectorBlock<Derived> end(Index size);
+ const VectorBlock<const Derived> end(Index size) const;
+ template<int Size> VectorBlock<Derived,Size> start();
+ template<int Size> const VectorBlock<const Derived,Size> start() const;
+ template<int Size> VectorBlock<Derived,Size> end();
+ template<int Size> const VectorBlock<const Derived,Size> end() const;
+
+ Minor<Derived> minor(Index row, Index col);
+ const Minor<Derived> minor(Index row, Index col) const;
+#endif
+
+ protected:
+ MatrixBase() : Base() {}
+
+ private:
+ explicit MatrixBase(int);
+ MatrixBase(int,int);
+ template<typename OtherDerived> explicit MatrixBase(const MatrixBase<OtherDerived>&);
+ protected:
+ // mixing arrays and matrices is not legal
+ template<typename OtherDerived> Derived& operator+=(const ArrayBase<OtherDerived>& )
+ {EIGEN_STATIC_ASSERT(std::ptrdiff_t(sizeof(typename OtherDerived::Scalar))==-1,YOU_CANNOT_MIX_ARRAYS_AND_MATRICES); return *this;}
+ // mixing arrays and matrices is not legal
+ template<typename OtherDerived> Derived& operator-=(const ArrayBase<OtherDerived>& )
+ {EIGEN_STATIC_ASSERT(std::ptrdiff_t(sizeof(typename OtherDerived::Scalar))==-1,YOU_CANNOT_MIX_ARRAYS_AND_MATRICES); return *this;}
+};
+
+} // end namespace Eigen
+
+#endif // EIGEN_MATRIXBASE_H
diff --git a/Eigen/src/Core/NestByValue.h b/Eigen/src/Core/NestByValue.h
new file mode 100644
index 000000000..a893b1761
--- /dev/null
+++ b/Eigen/src/Core/NestByValue.h
@@ -0,0 +1,111 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra.
+//
+// Copyright (C) 2008 Gael Guennebaud <gael.guennebaud@inria.fr>
+// Copyright (C) 2006-2008 Benoit Jacob <jacob.benoit.1@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 EIGEN_NESTBYVALUE_H
+#define EIGEN_NESTBYVALUE_H
+
+namespace Eigen {
+
+/** \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
+ *
+ * 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<typename ExpressionType>
+struct traits<NestByValue<ExpressionType> > : public traits<ExpressionType>
+{};
+}
+
+template<typename ExpressionType> class NestByValue
+ : public internal::dense_xpr_base< NestByValue<ExpressionType> >::type
+{
+ public:
+
+ typedef typename internal::dense_xpr_base<NestByValue>::type Base;
+ EIGEN_DENSE_PUBLIC_INTERFACE(NestByValue)
+
+ 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(); }
+
+ inline const CoeffReturnType coeff(Index row, Index col) const
+ {
+ return m_expression.coeff(row, col);
+ }
+
+ inline Scalar& coeffRef(Index row, Index col)
+ {
+ return m_expression.const_cast_derived().coeffRef(row, col);
+ }
+
+ inline const CoeffReturnType coeff(Index index) const
+ {
+ return m_expression.coeff(index);
+ }
+
+ inline Scalar& coeffRef(Index index)
+ {
+ return m_expression.const_cast_derived().coeffRef(index);
+ }
+
+ template<int LoadMode>
+ inline const PacketScalar packet(Index row, Index col) const
+ {
+ return m_expression.template packet<LoadMode>(row, col);
+ }
+
+ template<int LoadMode>
+ inline void writePacket(Index row, Index col, const PacketScalar& x)
+ {
+ m_expression.const_cast_derived().template writePacket<LoadMode>(row, col, x);
+ }
+
+ template<int LoadMode>
+ inline const PacketScalar packet(Index index) const
+ {
+ return m_expression.template packet<LoadMode>(index);
+ }
+
+ template<int LoadMode>
+ inline void writePacket(Index index, const PacketScalar& x)
+ {
+ m_expression.const_cast_derived().template writePacket<LoadMode>(index, x);
+ }
+
+ operator const ExpressionType&() const { return m_expression; }
+
+ protected:
+ const ExpressionType m_expression;
+};
+
+/** \returns an expression of the temporary version of *this.
+ */
+template<typename Derived>
+inline const NestByValue<Derived>
+DenseBase<Derived>::nestByValue() const
+{
+ return NestByValue<Derived>(derived());
+}
+
+} // end namespace Eigen
+
+#endif // EIGEN_NESTBYVALUE_H
diff --git a/Eigen/src/Core/NoAlias.h b/Eigen/src/Core/NoAlias.h
new file mode 100644
index 000000000..ecb3fa285
--- /dev/null
+++ b/Eigen/src/Core/NoAlias.h
@@ -0,0 +1,125 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra.
+//
+// Copyright (C) 2009 Gael Guennebaud <gael.guennebaud@inria.fr>
+//
+// This Source Code Form is subject to the terms of the Mozilla
+// Public License v. 2.0. If a copy of the MPL was not distributed
+// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+#ifndef EIGEN_NOALIAS_H
+#define EIGEN_NOALIAS_H
+
+namespace Eigen {
+
+/** \class NoAlias
+ * \ingroup Core_Module
+ *
+ * \brief Pseudo expression providing an operator = assuming no aliasing
+ *
+ * \param 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.
+ * More precisely it alloas to bypass the EvalBeforeAssignBit flag of the source expression.
+ * It is the return type of MatrixBase::noalias()
+ * and most of the time this is the only way it is used.
+ *
+ * \sa MatrixBase::noalias()
+ */
+template<typename ExpressionType, template <typename> class StorageBase>
+class NoAlias
+{
+ typedef typename ExpressionType::Scalar Scalar;
+ public:
+ NoAlias(ExpressionType& expression) : m_expression(expression) {}
+
+ /** Behaves like MatrixBase::lazyAssign(other)
+ * \sa MatrixBase::lazyAssign() */
+ template<typename OtherDerived>
+ EIGEN_STRONG_INLINE ExpressionType& operator=(const StorageBase<OtherDerived>& other)
+ { return internal::assign_selector<ExpressionType,OtherDerived,false>::run(m_expression,other.derived()); }
+
+ /** \sa MatrixBase::operator+= */
+ template<typename OtherDerived>
+ EIGEN_STRONG_INLINE ExpressionType& operator+=(const StorageBase<OtherDerived>& other)
+ {
+ typedef SelfCwiseBinaryOp<internal::scalar_sum_op<Scalar>, ExpressionType, OtherDerived> SelfAdder;
+ SelfAdder tmp(m_expression);
+ typedef typename internal::nested<OtherDerived>::type OtherDerivedNested;
+ typedef typename internal::remove_all<OtherDerivedNested>::type _OtherDerivedNested;
+ internal::assign_selector<SelfAdder,_OtherDerivedNested,false>::run(tmp,OtherDerivedNested(other.derived()));
+ return m_expression;
+ }
+
+ /** \sa MatrixBase::operator-= */
+ template<typename OtherDerived>
+ EIGEN_STRONG_INLINE ExpressionType& operator-=(const StorageBase<OtherDerived>& other)
+ {
+ typedef SelfCwiseBinaryOp<internal::scalar_difference_op<Scalar>, ExpressionType, OtherDerived> SelfAdder;
+ SelfAdder tmp(m_expression);
+ typedef typename internal::nested<OtherDerived>::type OtherDerivedNested;
+ typedef typename internal::remove_all<OtherDerivedNested>::type _OtherDerivedNested;
+ internal::assign_selector<SelfAdder,_OtherDerivedNested,false>::run(tmp,OtherDerivedNested(other.derived()));
+ return m_expression;
+ }
+
+#ifndef EIGEN_PARSED_BY_DOXYGEN
+ template<typename ProductDerived, typename Lhs, typename Rhs>
+ EIGEN_STRONG_INLINE ExpressionType& operator+=(const ProductBase<ProductDerived, Lhs,Rhs>& other)
+ { other.derived().addTo(m_expression); return m_expression; }
+
+ template<typename ProductDerived, typename Lhs, typename Rhs>
+ EIGEN_STRONG_INLINE ExpressionType& operator-=(const ProductBase<ProductDerived, Lhs,Rhs>& other)
+ { other.derived().subTo(m_expression); return m_expression; }
+
+ template<typename Lhs, typename Rhs, int NestingFlags>
+ EIGEN_STRONG_INLINE ExpressionType& operator+=(const CoeffBasedProduct<Lhs,Rhs,NestingFlags>& other)
+ { return m_expression.derived() += CoeffBasedProduct<Lhs,Rhs,NestByRefBit>(other.lhs(), other.rhs()); }
+
+ template<typename Lhs, typename Rhs, int NestingFlags>
+ EIGEN_STRONG_INLINE ExpressionType& operator-=(const CoeffBasedProduct<Lhs,Rhs,NestingFlags>& other)
+ { return m_expression.derived() -= CoeffBasedProduct<Lhs,Rhs,NestByRefBit>(other.lhs(), other.rhs()); }
+#endif
+
+ protected:
+ ExpressionType& m_expression;
+};
+
+/** \returns a pseudo expression of \c *this with an operator= assuming
+ * no aliasing between \c *this and the source expression.
+ *
+ * More precisely, noalias() allows to bypass the EvalBeforeAssignBit flag.
+ * Currently, even though several expressions may alias, only product
+ * expressions have this flag. Therefore, noalias() is only usefull when
+ * the source expression contains a matrix product.
+ *
+ * Here are some examples where noalias is usefull:
+ * \code
+ * D.noalias() = A * B;
+ * D.noalias() += A.transpose() * B;
+ * D.noalias() -= 2 * A * B.adjoint();
+ * \endcode
+ *
+ * On the other hand the following example will lead to a \b wrong result:
+ * \code
+ * A.noalias() = A * B;
+ * \endcode
+ * because the result matrix A is also an operand of the matrix product. Therefore,
+ * there is no alternative than evaluating A * B in a temporary, that is the default
+ * behavior when you write:
+ * \code
+ * A = A * B;
+ * \endcode
+ *
+ * \sa class NoAlias
+ */
+template<typename Derived>
+NoAlias<Derived,MatrixBase> MatrixBase<Derived>::noalias()
+{
+ return derived();
+}
+
+} // end namespace Eigen
+
+#endif // EIGEN_NOALIAS_H
diff --git a/Eigen/src/Core/NumTraits.h b/Eigen/src/Core/NumTraits.h
new file mode 100644
index 000000000..c94ef026b
--- /dev/null
+++ b/Eigen/src/Core/NumTraits.h
@@ -0,0 +1,147 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra.
+//
+// Copyright (C) 2006-2010 Benoit Jacob <jacob.benoit.1@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 EIGEN_NUMTRAITS_H
+#define EIGEN_NUMTRAITS_H
+
+namespace Eigen {
+
+/** \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
+ *
+ * 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<U> then \a 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,
+ * 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 \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
+ * type, and to 0 otherwise.
+ * \li An enum value \a IsInteger. It is equal to \c 1 if \a T is an integer type such as \c int,
+ * and to \c 0 otherwise.
+ * \li Enum values ReadCost, AddCost and MulCost representing a rough estimate of the number of CPU cycles needed
+ * to by move / add / mul instructions respectively, assuming the data is already stored in CPU registers.
+ * Stay vague here. No need to do architecture-specific stuff.
+ * \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 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.
+ */
+
+template<typename T> struct GenericNumTraits
+{
+ enum {
+ IsInteger = std::numeric_limits<T>::is_integer,
+ IsSigned = std::numeric_limits<T>::is_signed,
+ IsComplex = 0,
+ RequireInitialization = internal::is_arithmetic<T>::value ? 0 : 1,
+ ReadCost = 1,
+ AddCost = 1,
+ MulCost = 1
+ };
+
+ typedef T Real;
+ typedef typename internal::conditional<
+ IsInteger,
+ typename internal::conditional<sizeof(T)<=2, float, double>::type,
+ T
+ >::type NonInteger;
+ typedef T Nested;
+
+ static inline Real epsilon() { return std::numeric_limits<T>::epsilon(); }
+ 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<T>::max)(); }
+ static inline T lowest() { return IsInteger ? (std::numeric_limits<T>::min)() : (-(std::numeric_limits<T>::max)()); }
+
+#ifdef EIGEN2_SUPPORT
+ enum {
+ HasFloatingPoint = !IsInteger
+ };
+ typedef NonInteger FloatingPoint;
+#endif
+};
+
+template<typename T> struct NumTraits : GenericNumTraits<T>
+{};
+
+template<> struct NumTraits<float>
+ : GenericNumTraits<float>
+{
+ static inline float dummy_precision() { return 1e-5f; }
+};
+
+template<> struct NumTraits<double> : GenericNumTraits<double>
+{
+ static inline double dummy_precision() { return 1e-12; }
+};
+
+template<> struct NumTraits<long double>
+ : GenericNumTraits<long double>
+{
+ static inline long double dummy_precision() { return 1e-15l; }
+};
+
+template<typename _Real> struct NumTraits<std::complex<_Real> >
+ : GenericNumTraits<std::complex<_Real> >
+{
+ typedef _Real Real;
+ enum {
+ IsComplex = 1,
+ RequireInitialization = NumTraits<_Real>::RequireInitialization,
+ ReadCost = 2 * NumTraits<_Real>::ReadCost,
+ AddCost = 2 * NumTraits<Real>::AddCost,
+ MulCost = 4 * NumTraits<Real>::MulCost + 2 * NumTraits<Real>::AddCost
+ };
+
+ static inline Real epsilon() { return NumTraits<Real>::epsilon(); }
+ static inline Real dummy_precision() { return NumTraits<Real>::dummy_precision(); }
+};
+
+template<typename Scalar, int Rows, int Cols, int Options, int MaxRows, int MaxCols>
+struct NumTraits<Array<Scalar, Rows, Cols, Options, MaxRows, MaxCols> >
+{
+ typedef Array<Scalar, Rows, Cols, Options, MaxRows, MaxCols> ArrayType;
+ typedef typename NumTraits<Scalar>::Real RealScalar;
+ typedef Array<RealScalar, Rows, Cols, Options, MaxRows, MaxCols> Real;
+ typedef typename NumTraits<Scalar>::NonInteger NonIntegerScalar;
+ typedef Array<NonIntegerScalar, Rows, Cols, Options, MaxRows, MaxCols> NonInteger;
+ typedef ArrayType & Nested;
+
+ enum {
+ IsComplex = NumTraits<Scalar>::IsComplex,
+ IsInteger = NumTraits<Scalar>::IsInteger,
+ IsSigned = NumTraits<Scalar>::IsSigned,
+ RequireInitialization = 1,
+ ReadCost = ArrayType::SizeAtCompileTime==Dynamic ? Dynamic : ArrayType::SizeAtCompileTime * NumTraits<Scalar>::ReadCost,
+ AddCost = ArrayType::SizeAtCompileTime==Dynamic ? Dynamic : ArrayType::SizeAtCompileTime * NumTraits<Scalar>::AddCost,
+ MulCost = ArrayType::SizeAtCompileTime==Dynamic ? Dynamic : ArrayType::SizeAtCompileTime * NumTraits<Scalar>::MulCost
+ };
+};
+
+} // end namespace Eigen
+
+#endif // EIGEN_NUMTRAITS_H
diff --git a/Eigen/src/Core/PermutationMatrix.h b/Eigen/src/Core/PermutationMatrix.h
new file mode 100644
index 000000000..bc29f8142
--- /dev/null
+++ b/Eigen/src/Core/PermutationMatrix.h
@@ -0,0 +1,687 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra.
+//
+// Copyright (C) 2009 Benoit Jacob <jacob.benoit.1@gmail.com>
+// Copyright (C) 2009-2011 Gael Guennebaud <gael.guennebaud@inria.fr>
+//
+// This Source Code Form is subject to the terms of the Mozilla
+// Public License v. 2.0. If a copy of the MPL was not distributed
+// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+#ifndef EIGEN_PERMUTATIONMATRIX_H
+#define EIGEN_PERMUTATIONMATRIX_H
+
+namespace Eigen {
+
+template<int RowCol,typename IndicesType,typename MatrixType, typename StorageKind> class PermutedImpl;
+
+/** \class PermutationBase
+ * \ingroup Core_Module
+ *
+ * \brief Base class for permutations
+ *
+ * \param Derived the derived class
+ *
+ * This class is the base class for all expressions representing a permutation matrix,
+ * internally stored as a vector of integers.
+ * The convention followed here is that if \f$ \sigma \f$ is a permutation, the corresponding permutation matrix
+ * \f$ P_\sigma \f$ is such that if \f$ (e_1,\ldots,e_p) \f$ is the canonical basis, we have:
+ * \f[ P_\sigma(e_i) = e_{\sigma(i)}. \f]
+ * This convention ensures that for any two permutations \f$ \sigma, \tau \f$, we have:
+ * \f[ P_{\sigma\circ\tau} = P_\sigma P_\tau. \f]
+ *
+ * Permutation matrices are square and invertible.
+ *
+ * Notice that in addition to the member functions and operators listed here, there also are non-member
+ * operator* to multiply any kind of permutation object with any kind of matrix expression (MatrixBase)
+ * on either side.
+ *
+ * \sa class PermutationMatrix, class PermutationWrapper
+ */
+
+namespace internal {
+
+template<typename PermutationType, typename MatrixType, int Side, bool Transposed=false>
+struct permut_matrix_product_retval;
+template<typename PermutationType, typename MatrixType, int Side, bool Transposed=false>
+struct permut_sparsematrix_product_retval;
+enum PermPermProduct_t {PermPermProduct};
+
+} // end namespace internal
+
+template<typename Derived>
+class PermutationBase : public EigenBase<Derived>
+{
+ typedef internal::traits<Derived> Traits;
+ typedef EigenBase<Derived> Base;
+ public:
+
+ #ifndef EIGEN_PARSED_BY_DOXYGEN
+ 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<Scalar,RowsAtCompileTime,ColsAtCompileTime,0,MaxRowsAtCompileTime,MaxColsAtCompileTime>
+ DenseMatrixType;
+ typedef PermutationMatrix<IndicesType::SizeAtCompileTime,IndicesType::MaxSizeAtCompileTime,Index>
+ PlainPermutationType;
+ using Base::derived;
+ #endif
+
+ /** Copies the other permutation into *this */
+ template<typename OtherDerived>
+ Derived& operator=(const PermutationBase<OtherDerived>& other)
+ {
+ indices() = other.indices();
+ return derived();
+ }
+
+ /** Assignment from the Transpositions \a tr */
+ template<typename OtherDerived>
+ Derived& operator=(const TranspositionsBase<OtherDerived>& tr)
+ {
+ setIdentity(tr.size());
+ for(Index k=size()-1; k>=0; --k)
+ applyTranspositionOnTheRight(k,tr.coeff(k));
+ return derived();
+ }
+
+ #ifndef EIGEN_PARSED_BY_DOXYGEN
+ /** This is a special case of the templated operator=. Its purpose is to
+ * prevent a default operator= from hiding the templated operator=.
+ */
+ Derived& operator=(const PermutationBase& other)
+ {
+ indices() = other.indices();
+ return derived();
+ }
+ #endif
+
+ /** \returns the number of rows */
+ inline Index rows() const { return indices().size(); }
+
+ /** \returns the number of columns */
+ inline Index cols() const { return indices().size(); }
+
+ /** \returns the size of a side of the respective square matrix, i.e., the number of indices */
+ inline Index size() const { return indices().size(); }
+
+ #ifndef EIGEN_PARSED_BY_DOXYGEN
+ template<typename DenseDerived>
+ void evalTo(MatrixBase<DenseDerived>& other) const
+ {
+ other.setZero();
+ for (int i=0; i<rows();++i)
+ other.coeffRef(indices().coeff(i),i) = typename DenseDerived::Scalar(1);
+ }
+ #endif
+
+ /** \returns a Matrix object initialized from this permutation matrix. Notice that it
+ * is inefficient to return this Matrix object by value. For efficiency, favor using
+ * the Matrix constructor taking EigenBase objects.
+ */
+ DenseMatrixType toDenseMatrix() const
+ {
+ return derived();
+ }
+
+ /** const version of indices(). */
+ const IndicesType& indices() const { return derived().indices(); }
+ /** \returns a reference to the stored array representing the permutation. */
+ IndicesType& indices() { return derived().indices(); }
+
+ /** Resizes to given size.
+ */
+ inline void resize(Index size)
+ {
+ indices().resize(size);
+ }
+
+ /** Sets *this to be the identity permutation matrix */
+ void setIdentity()
+ {
+ for(Index i = 0; i < size(); ++i)
+ indices().coeffRef(i) = i;
+ }
+
+ /** Sets *this to be the identity permutation matrix of given size.
+ */
+ void setIdentity(Index size)
+ {
+ resize(size);
+ setIdentity();
+ }
+
+ /** Multiplies *this by the transposition \f$(ij)\f$ on the left.
+ *
+ * \returns a reference to *this.
+ *
+ * \warning This is much slower than applyTranspositionOnTheRight(int,int):
+ * this has linear complexity and requires a lot of branching.
+ *
+ * \sa applyTranspositionOnTheRight(int,int)
+ */
+ Derived& applyTranspositionOnTheLeft(Index i, Index j)
+ {
+ eigen_assert(i>=0 && j>=0 && i<size() && j<size());
+ for(Index k = 0; k < size(); ++k)
+ {
+ if(indices().coeff(k) == i) indices().coeffRef(k) = j;
+ else if(indices().coeff(k) == j) indices().coeffRef(k) = i;
+ }
+ return derived();
+ }
+
+ /** Multiplies *this by the transposition \f$(ij)\f$ on the right.
+ *
+ * \returns a reference to *this.
+ *
+ * This is a fast operation, it only consists in swapping two indices.
+ *
+ * \sa applyTranspositionOnTheLeft(int,int)
+ */
+ Derived& applyTranspositionOnTheRight(Index i, Index j)
+ {
+ eigen_assert(i>=0 && j>=0 && i<size() && j<size());
+ std::swap(indices().coeffRef(i), indices().coeffRef(j));
+ return derived();
+ }
+
+ /** \returns the inverse permutation matrix.
+ *
+ * \note \note_try_to_help_rvo
+ */
+ inline Transpose<PermutationBase> inverse() const
+ { return derived(); }
+ /** \returns the tranpose permutation matrix.
+ *
+ * \note \note_try_to_help_rvo
+ */
+ inline Transpose<PermutationBase> transpose() const
+ { return derived(); }
+
+ /**** multiplication helpers to hopefully get RVO ****/
+
+
+#ifndef EIGEN_PARSED_BY_DOXYGEN
+ protected:
+ template<typename OtherDerived>
+ void assignTranspose(const PermutationBase<OtherDerived>& other)
+ {
+ for (int i=0; i<rows();++i) indices().coeffRef(other.indices().coeff(i)) = i;
+ }
+ template<typename Lhs,typename Rhs>
+ void assignProduct(const Lhs& lhs, const Rhs& rhs)
+ {
+ eigen_assert(lhs.cols() == rhs.rows());
+ for (int i=0; i<rows();++i) indices().coeffRef(i) = lhs.indices().coeff(rhs.indices().coeff(i));
+ }
+#endif
+
+ public:
+
+ /** \returns the product permutation matrix.
+ *
+ * \note \note_try_to_help_rvo
+ */
+ template<typename Other>
+ inline PlainPermutationType operator*(const PermutationBase<Other>& other) const
+ { return PlainPermutationType(internal::PermPermProduct, derived(), other.derived()); }
+
+ /** \returns the product of a permutation with another inverse permutation.
+ *
+ * \note \note_try_to_help_rvo
+ */
+ template<typename Other>
+ inline PlainPermutationType operator*(const Transpose<PermutationBase<Other> >& 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
+ */
+ template<typename Other> friend
+ inline PlainPermutationType operator*(const Transpose<PermutationBase<Other> >& other, const PermutationBase& perm)
+ { return PlainPermutationType(internal::PermPermProduct, other.eval(), perm); }
+
+ protected:
+
+};
+
+/** \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
+ *
+ * This class represents a permutation matrix, internally stored as a vector of integers.
+ *
+ * \sa class PermutationBase, class PermutationWrapper, class DiagonalMatrix
+ */
+
+namespace internal {
+template<int SizeAtCompileTime, int MaxSizeAtCompileTime, typename IndexType>
+struct traits<PermutationMatrix<SizeAtCompileTime, MaxSizeAtCompileTime, IndexType> >
+ : traits<Matrix<IndexType,SizeAtCompileTime,SizeAtCompileTime,0,MaxSizeAtCompileTime,MaxSizeAtCompileTime> >
+{
+ typedef IndexType Index;
+ typedef Matrix<IndexType, SizeAtCompileTime, 1, 0, MaxSizeAtCompileTime, 1> IndicesType;
+};
+}
+
+template<int SizeAtCompileTime, int MaxSizeAtCompileTime, typename IndexType>
+class PermutationMatrix : public PermutationBase<PermutationMatrix<SizeAtCompileTime, MaxSizeAtCompileTime, IndexType> >
+{
+ typedef PermutationBase<PermutationMatrix> Base;
+ typedef internal::traits<PermutationMatrix> Traits;
+ public:
+
+ #ifndef EIGEN_PARSED_BY_DOXYGEN
+ typedef typename Traits::IndicesType IndicesType;
+ #endif
+
+ inline PermutationMatrix()
+ {}
+
+ /** Constructs an uninitialized permutation matrix of given size.
+ */
+ inline PermutationMatrix(int size) : m_indices(size)
+ {}
+
+ /** Copy constructor. */
+ template<typename OtherDerived>
+ inline PermutationMatrix(const PermutationBase<OtherDerived>& other)
+ : m_indices(other.indices()) {}
+
+ #ifndef EIGEN_PARSED_BY_DOXYGEN
+ /** Standard copy constructor. Defined only to prevent a default copy constructor
+ * from hiding the other templated constructor */
+ inline PermutationMatrix(const PermutationMatrix& other) : m_indices(other.indices()) {}
+ #endif
+
+ /** Generic constructor from expression of the indices. The indices
+ * array has the meaning that the permutations sends each integer i to indices[i].
+ *
+ * \warning It is your responsibility to check that the indices array that you passes actually
+ * describes a permutation, i.e., each value between 0 and n-1 occurs exactly once, where n is the
+ * array's size.
+ */
+ template<typename Other>
+ explicit inline PermutationMatrix(const MatrixBase<Other>& indices) : m_indices(indices)
+ {}
+
+ /** Convert the Transpositions \a tr to a permutation matrix */
+ template<typename Other>
+ explicit PermutationMatrix(const TranspositionsBase<Other>& tr)
+ : m_indices(tr.size())
+ {
+ *this = tr;
+ }
+
+ /** Copies the other permutation into *this */
+ template<typename Other>
+ PermutationMatrix& operator=(const PermutationBase<Other>& other)
+ {
+ m_indices = other.indices();
+ return *this;
+ }
+
+ /** Assignment from the Transpositions \a tr */
+ template<typename Other>
+ PermutationMatrix& operator=(const TranspositionsBase<Other>& tr)
+ {
+ return Base::operator=(tr.derived());
+ }
+
+ #ifndef EIGEN_PARSED_BY_DOXYGEN
+ /** This is a special case of the templated operator=. Its purpose is to
+ * prevent a default operator= from hiding the templated operator=.
+ */
+ PermutationMatrix& operator=(const PermutationMatrix& other)
+ {
+ m_indices = other.m_indices;
+ return *this;
+ }
+ #endif
+
+ /** const version of indices(). */
+ const IndicesType& indices() const { return m_indices; }
+ /** \returns a reference to the stored array representing the permutation. */
+ IndicesType& indices() { return m_indices; }
+
+
+ /**** multiplication helpers to hopefully get RVO ****/
+
+#ifndef EIGEN_PARSED_BY_DOXYGEN
+ template<typename Other>
+ PermutationMatrix(const Transpose<PermutationBase<Other> >& other)
+ : m_indices(other.nestedPermutation().size())
+ {
+ for (int i=0; i<m_indices.size();++i) m_indices.coeffRef(other.nestedPermutation().indices().coeff(i)) = i;
+ }
+ template<typename Lhs,typename Rhs>
+ PermutationMatrix(internal::PermPermProduct_t, const Lhs& lhs, const Rhs& rhs)
+ : m_indices(lhs.indices().size())
+ {
+ Base::assignProduct(lhs,rhs);
+ }
+#endif
+
+ protected:
+
+ IndicesType m_indices;
+};
+
+
+namespace internal {
+template<int SizeAtCompileTime, int MaxSizeAtCompileTime, typename IndexType, int _PacketAccess>
+struct traits<Map<PermutationMatrix<SizeAtCompileTime, MaxSizeAtCompileTime, IndexType>,_PacketAccess> >
+ : traits<Matrix<IndexType,SizeAtCompileTime,SizeAtCompileTime,0,MaxSizeAtCompileTime,MaxSizeAtCompileTime> >
+{
+ typedef IndexType Index;
+ typedef Map<const Matrix<IndexType, SizeAtCompileTime, 1, 0, MaxSizeAtCompileTime, 1>, _PacketAccess> IndicesType;
+};
+}
+
+template<int SizeAtCompileTime, int MaxSizeAtCompileTime, typename IndexType, int _PacketAccess>
+class Map<PermutationMatrix<SizeAtCompileTime, MaxSizeAtCompileTime, IndexType>,_PacketAccess>
+ : public PermutationBase<Map<PermutationMatrix<SizeAtCompileTime, MaxSizeAtCompileTime, IndexType>,_PacketAccess> >
+{
+ typedef PermutationBase<Map> Base;
+ typedef internal::traits<Map> Traits;
+ public:
+
+ #ifndef EIGEN_PARSED_BY_DOXYGEN
+ typedef typename Traits::IndicesType IndicesType;
+ typedef typename IndicesType::Scalar Index;
+ #endif
+
+ inline Map(const Index* indices)
+ : m_indices(indices)
+ {}
+
+ inline Map(const Index* indices, Index size)
+ : m_indices(indices,size)
+ {}
+
+ /** Copies the other permutation into *this */
+ template<typename Other>
+ Map& operator=(const PermutationBase<Other>& other)
+ { return Base::operator=(other.derived()); }
+
+ /** Assignment from the Transpositions \a tr */
+ template<typename Other>
+ Map& operator=(const TranspositionsBase<Other>& tr)
+ { return Base::operator=(tr.derived()); }
+
+ #ifndef EIGEN_PARSED_BY_DOXYGEN
+ /** This is a special case of the templated operator=. Its purpose is to
+ * prevent a default operator= from hiding the templated operator=.
+ */
+ Map& operator=(const Map& other)
+ {
+ m_indices = other.m_indices;
+ return *this;
+ }
+ #endif
+
+ /** const version of indices(). */
+ const IndicesType& indices() const { return m_indices; }
+ /** \returns a reference to the stored array representing the permutation. */
+ IndicesType& indices() { return m_indices; }
+
+ protected:
+
+ 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<typename _IndicesType> class TranspositionsWrapper;
+namespace internal {
+template<typename _IndicesType>
+struct traits<PermutationWrapper<_IndicesType> >
+{
+ typedef PermutationStorage StorageKind;
+ typedef typename _IndicesType::Scalar Scalar;
+ typedef typename _IndicesType::Scalar Index;
+ typedef _IndicesType IndicesType;
+ enum {
+ RowsAtCompileTime = _IndicesType::SizeAtCompileTime,
+ ColsAtCompileTime = _IndicesType::SizeAtCompileTime,
+ MaxRowsAtCompileTime = IndicesType::MaxRowsAtCompileTime,
+ MaxColsAtCompileTime = IndicesType::MaxColsAtCompileTime,
+ Flags = 0,
+ CoeffReadCost = _IndicesType::CoeffReadCost
+ };
+};
+}
+
+template<typename _IndicesType>
+class PermutationWrapper : public PermutationBase<PermutationWrapper<_IndicesType> >
+{
+ typedef PermutationBase<PermutationWrapper> Base;
+ typedef internal::traits<PermutationWrapper> Traits;
+ public:
+
+ #ifndef EIGEN_PARSED_BY_DOXYGEN
+ typedef typename Traits::IndicesType IndicesType;
+ #endif
+
+ inline PermutationWrapper(const IndicesType& indices)
+ : m_indices(indices)
+ {}
+
+ /** const version of indices(). */
+ const typename internal::remove_all<typename IndicesType::Nested>::type&
+ indices() const { return m_indices; }
+
+ protected:
+
+ typename IndicesType::Nested m_indices;
+};
+
+/** \returns the matrix with the permutation applied to the columns.
+ */
+template<typename Derived, typename PermutationDerived>
+inline const internal::permut_matrix_product_retval<PermutationDerived, Derived, OnTheRight>
+operator*(const MatrixBase<Derived>& matrix,
+ const PermutationBase<PermutationDerived> &permutation)
+{
+ return internal::permut_matrix_product_retval
+ <PermutationDerived, Derived, OnTheRight>
+ (permutation.derived(), matrix.derived());
+}
+
+/** \returns the matrix with the permutation applied to the rows.
+ */
+template<typename Derived, typename PermutationDerived>
+inline const internal::permut_matrix_product_retval
+ <PermutationDerived, Derived, OnTheLeft>
+operator*(const PermutationBase<PermutationDerived> &permutation,
+ const MatrixBase<Derived>& matrix)
+{
+ return internal::permut_matrix_product_retval
+ <PermutationDerived, Derived, OnTheLeft>
+ (permutation.derived(), matrix.derived());
+}
+
+namespace internal {
+
+template<typename PermutationType, typename MatrixType, int Side, bool Transposed>
+struct traits<permut_matrix_product_retval<PermutationType, MatrixType, Side, Transposed> >
+{
+ typedef typename MatrixType::PlainObject ReturnType;
+};
+
+template<typename PermutationType, typename MatrixType, int Side, bool Transposed>
+struct permut_matrix_product_retval
+ : public ReturnByValue<permut_matrix_product_retval<PermutationType, MatrixType, Side, Transposed> >
+{
+ typedef typename remove_all<typename MatrixType::Nested>::type MatrixTypeNestedCleaned;
+
+ permut_matrix_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<typename Dest> inline void evalTo(Dest& dst) const
+ {
+ const int n = Side==OnTheLeft ? rows() : cols();
+
+ if(is_same<MatrixTypeNestedCleaned,Dest>::value && extract_data(dst) == extract_data(m_matrix))
+ {
+ // apply the permutation inplace
+ Matrix<bool,PermutationType::RowsAtCompileTime,1,0,PermutationType::MaxRowsAtCompileTime> mask(m_permutation.size());
+ mask.fill(false);
+ int r = 0;
+ while(r < m_permutation.size())
+ {
+ // search for the next seed
+ while(r<m_permutation.size() && mask[r]) r++;
+ if(r>=m_permutation.size())
+ break;
+ // we got one, let's follow it until we are back to the seed
+ int k0 = r++;
+ int kPrev = k0;
+ mask.coeffRef(k0) = true;
+ for(int k=m_permutation.indices().coeff(k0); k!=k0; k=m_permutation.indices().coeff(k))
+ {
+ Block<Dest, Side==OnTheLeft ? 1 : Dest::RowsAtCompileTime, Side==OnTheRight ? 1 : Dest::ColsAtCompileTime>(dst, k)
+ .swap(Block<Dest, Side==OnTheLeft ? 1 : Dest::RowsAtCompileTime, Side==OnTheRight ? 1 : Dest::ColsAtCompileTime>
+ (dst,((Side==OnTheLeft) ^ Transposed) ? k0 : kPrev));
+
+ mask.coeffRef(k) = true;
+ kPrev = k;
+ }
+ }
+ }
+ else
+ {
+ for(int i = 0; i < n; ++i)
+ {
+ Block<Dest, Side==OnTheLeft ? 1 : Dest::RowsAtCompileTime, Side==OnTheRight ? 1 : Dest::ColsAtCompileTime>
+ (dst, ((Side==OnTheLeft) ^ Transposed) ? m_permutation.indices().coeff(i) : i)
+
+ =
+
+ Block<const MatrixTypeNestedCleaned,Side==OnTheLeft ? 1 : MatrixType::RowsAtCompileTime,Side==OnTheRight ? 1 : MatrixType::ColsAtCompileTime>
+ (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<typename Derived>
+struct traits<Transpose<PermutationBase<Derived> > >
+ : traits<Derived>
+{};
+
+} // end namespace internal
+
+template<typename Derived>
+class Transpose<PermutationBase<Derived> >
+ : public EigenBase<Transpose<PermutationBase<Derived> > >
+{
+ typedef Derived PermutationType;
+ typedef typename PermutationType::IndicesType IndicesType;
+ typedef typename PermutationType::PlainPermutationType PlainPermutationType;
+ public:
+
+ #ifndef EIGEN_PARSED_BY_DOXYGEN
+ typedef internal::traits<PermutationType> Traits;
+ typedef typename Derived::DenseMatrixType DenseMatrixType;
+ enum {
+ Flags = Traits::Flags,
+ CoeffReadCost = Traits::CoeffReadCost,
+ RowsAtCompileTime = Traits::RowsAtCompileTime,
+ ColsAtCompileTime = Traits::ColsAtCompileTime,
+ MaxRowsAtCompileTime = Traits::MaxRowsAtCompileTime,
+ MaxColsAtCompileTime = Traits::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<typename DenseDerived>
+ void evalTo(MatrixBase<DenseDerived>& other) const
+ {
+ other.setZero();
+ for (int i=0; i<rows();++i)
+ other.coeffRef(i, m_permutation.indices().coeff(i)) = typename DenseDerived::Scalar(1);
+ }
+ #endif
+
+ /** \return the equivalent permutation matrix */
+ PlainPermutationType eval() const { return *this; }
+
+ DenseMatrixType toDenseMatrix() const { return *this; }
+
+ /** \returns the matrix with the inverse permutation applied to the columns.
+ */
+ template<typename OtherDerived> friend
+ inline const internal::permut_matrix_product_retval<PermutationType, OtherDerived, OnTheRight, true>
+ operator*(const MatrixBase<OtherDerived>& matrix, const Transpose& trPerm)
+ {
+ return internal::permut_matrix_product_retval<PermutationType, OtherDerived, OnTheRight, true>(trPerm.m_permutation, matrix.derived());
+ }
+
+ /** \returns the matrix with the inverse permutation applied to the rows.
+ */
+ template<typename OtherDerived>
+ inline const internal::permut_matrix_product_retval<PermutationType, OtherDerived, OnTheLeft, true>
+ operator*(const MatrixBase<OtherDerived>& matrix) const
+ {
+ return internal::permut_matrix_product_retval<PermutationType, OtherDerived, OnTheLeft, true>(m_permutation, matrix.derived());
+ }
+
+ const PermutationType& nestedPermutation() const { return m_permutation; }
+
+ protected:
+ const PermutationType& m_permutation;
+};
+
+template<typename Derived>
+const PermutationWrapper<const Derived> MatrixBase<Derived>::asPermutation() const
+{
+ return derived();
+}
+
+} // end namespace Eigen
+
+#endif // EIGEN_PERMUTATIONMATRIX_H
diff --git a/Eigen/src/Core/PlainObjectBase.h b/Eigen/src/Core/PlainObjectBase.h
new file mode 100644
index 000000000..71c74309a
--- /dev/null
+++ b/Eigen/src/Core/PlainObjectBase.h
@@ -0,0 +1,767 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra.
+//
+// Copyright (C) 2008-2009 Gael Guennebaud <gael.guennebaud@inria.fr>
+// Copyright (C) 2006-2008 Benoit Jacob <jacob.benoit.1@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 EIGEN_DENSESTORAGEBASE_H
+#define EIGEN_DENSESTORAGEBASE_H
+
+#ifdef EIGEN_INITIALIZE_MATRICES_BY_ZERO
+# define EIGEN_INITIALIZE_BY_ZERO_IF_THAT_OPTION_IS_ENABLED for(int i=0;i<base().size();++i) coeffRef(i)=Scalar(0);
+#else
+# define EIGEN_INITIALIZE_BY_ZERO_IF_THAT_OPTION_IS_ENABLED
+#endif
+
+namespace Eigen {
+
+namespace internal {
+
+template<typename Index>
+EIGEN_ALWAYS_INLINE void check_rows_cols_for_overflow(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
+ bool error = (rows < 0 || cols < 0) ? true
+ : (rows == 0 || cols == 0) ? false
+ : (rows > max_index / cols);
+ if (error)
+ throw_std_bad_alloc();
+}
+
+template <typename Derived, typename OtherDerived = Derived, bool IsVector = bool(Derived::IsVectorAtCompileTime)> struct conservative_resize_like_impl;
+
+template<typename MatrixTypeA, typename MatrixTypeB, bool SwapPointers> struct matrix_swap_impl;
+
+} // end namespace internal
+
+/** \class PlainObjectBase
+ * \brief %Dense storage base class for matrices and arrays.
+ *
+ * This class can be extended with the help of the plugin mechanism described on the page
+ * \ref TopicCustomizingEigen by defining the preprocessor symbol \c EIGEN_PLAINOBJECTBASE_PLUGIN.
+ *
+ * \sa \ref TopicClassHierarchy
+ */
+#ifdef EIGEN_PARSED_BY_DOXYGEN
+namespace internal {
+
+// this is a warkaround to doxygen not being able to understand the inheritence logic
+// when it is hidden by the dense_xpr_base helper struct.
+template<typename Derived> struct dense_xpr_base_dispatcher_for_doxygen;// : public MatrixBase<Derived> {};
+/** This class is just a workaround for Doxygen and it does not not actually exist. */
+template<typename _Scalar, int _Rows, int _Cols, int _Options, int _MaxRows, int _MaxCols>
+struct dense_xpr_base_dispatcher_for_doxygen<Matrix<_Scalar, _Rows, _Cols, _Options, _MaxRows, _MaxCols> >
+ : public MatrixBase<Matrix<_Scalar, _Rows, _Cols, _Options, _MaxRows, _MaxCols> > {};
+/** This class is just a workaround for Doxygen and it does not not actually exist. */
+template<typename _Scalar, int _Rows, int _Cols, int _Options, int _MaxRows, int _MaxCols>
+struct dense_xpr_base_dispatcher_for_doxygen<Array<_Scalar, _Rows, _Cols, _Options, _MaxRows, _MaxCols> >
+ : public ArrayBase<Array<_Scalar, _Rows, _Cols, _Options, _MaxRows, _MaxCols> > {};
+
+} // namespace internal
+
+template<typename Derived>
+class PlainObjectBase : public internal::dense_xpr_base_dispatcher_for_doxygen<Derived>
+#else
+template<typename Derived>
+class PlainObjectBase : public internal::dense_xpr_base<Derived>::type
+#endif
+{
+ public:
+ enum { Options = internal::traits<Derived>::Options };
+ typedef typename internal::dense_xpr_base<Derived>::type Base;
+
+ typedef typename internal::traits<Derived>::StorageKind StorageKind;
+ typedef typename internal::traits<Derived>::Index Index;
+ typedef typename internal::traits<Derived>::Scalar Scalar;
+ typedef typename internal::packet_traits<Scalar>::type PacketScalar;
+ typedef typename NumTraits<Scalar>::Real RealScalar;
+ typedef Derived DenseType;
+
+ using Base::RowsAtCompileTime;
+ using Base::ColsAtCompileTime;
+ using Base::SizeAtCompileTime;
+ using Base::MaxRowsAtCompileTime;
+ using Base::MaxColsAtCompileTime;
+ using Base::MaxSizeAtCompileTime;
+ using Base::IsVectorAtCompileTime;
+ using Base::Flags;
+
+ template<typename PlainObjectType, int MapOptions, typename StrideType> friend class Eigen::Map;
+ friend class Eigen::Map<Derived, Unaligned>;
+ typedef Eigen::Map<Derived, Unaligned> MapType;
+ friend class Eigen::Map<const Derived, Unaligned>;
+ typedef const Eigen::Map<const Derived, Unaligned> ConstMapType;
+ friend class Eigen::Map<Derived, Aligned>;
+ typedef Eigen::Map<Derived, Aligned> AlignedMapType;
+ friend class Eigen::Map<const Derived, Aligned>;
+ typedef const Eigen::Map<const Derived, Aligned> ConstAlignedMapType;
+ template<typename StrideType> struct StridedMapType { typedef Eigen::Map<Derived, Unaligned, StrideType> type; };
+ template<typename StrideType> struct StridedConstMapType { typedef Eigen::Map<const Derived, Unaligned, StrideType> type; };
+ template<typename StrideType> struct StridedAlignedMapType { typedef Eigen::Map<Derived, Aligned, StrideType> type; };
+ template<typename StrideType> struct StridedConstAlignedMapType { typedef Eigen::Map<const Derived, Aligned, StrideType> type; };
+
+ protected:
+ DenseStorage<Scalar, Base::MaxSizeAtCompileTime, Base::RowsAtCompileTime, Base::ColsAtCompileTime, Options> m_storage;
+
+ public:
+ enum { NeedsToAlign = SizeAtCompileTime != Dynamic && (internal::traits<Derived>::Flags & AlignedBit) != 0 };
+ EIGEN_MAKE_ALIGNED_OPERATOR_NEW_IF(NeedsToAlign)
+
+ Base& base() { return *static_cast<Base*>(this); }
+ const Base& base() const { return *static_cast<const Base*>(this); }
+
+ EIGEN_STRONG_INLINE Index rows() const { return m_storage.rows(); }
+ EIGEN_STRONG_INLINE Index cols() const { return m_storage.cols(); }
+
+ EIGEN_STRONG_INLINE const Scalar& coeff(Index row, Index col) const
+ {
+ if(Flags & RowMajorBit)
+ return m_storage.data()[col + row * m_storage.cols()];
+ else // column-major
+ return m_storage.data()[row + col * m_storage.rows()];
+ }
+
+ EIGEN_STRONG_INLINE const Scalar& coeff(Index index) const
+ {
+ return m_storage.data()[index];
+ }
+
+ EIGEN_STRONG_INLINE Scalar& coeffRef(Index row, Index col)
+ {
+ if(Flags & RowMajorBit)
+ return m_storage.data()[col + row * m_storage.cols()];
+ else // column-major
+ return m_storage.data()[row + col * m_storage.rows()];
+ }
+
+ EIGEN_STRONG_INLINE Scalar& coeffRef(Index index)
+ {
+ return m_storage.data()[index];
+ }
+
+ EIGEN_STRONG_INLINE const Scalar& coeffRef(Index row, Index col) const
+ {
+ if(Flags & RowMajorBit)
+ return m_storage.data()[col + row * m_storage.cols()];
+ else // column-major
+ return m_storage.data()[row + col * m_storage.rows()];
+ }
+
+ EIGEN_STRONG_INLINE const Scalar& coeffRef(Index index) const
+ {
+ return m_storage.data()[index];
+ }
+
+ /** \internal */
+ template<int LoadMode>
+ EIGEN_STRONG_INLINE PacketScalar packet(Index row, Index col) const
+ {
+ return internal::ploadt<PacketScalar, LoadMode>
+ (m_storage.data() + (Flags & RowMajorBit
+ ? col + row * m_storage.cols()
+ : row + col * m_storage.rows()));
+ }
+
+ /** \internal */
+ template<int LoadMode>
+ EIGEN_STRONG_INLINE PacketScalar packet(Index index) const
+ {
+ return internal::ploadt<PacketScalar, LoadMode>(m_storage.data() + index);
+ }
+
+ /** \internal */
+ template<int StoreMode>
+ EIGEN_STRONG_INLINE void writePacket(Index row, Index col, const PacketScalar& x)
+ {
+ internal::pstoret<Scalar, PacketScalar, StoreMode>
+ (m_storage.data() + (Flags & RowMajorBit
+ ? col + row * m_storage.cols()
+ : row + col * m_storage.rows()), x);
+ }
+
+ /** \internal */
+ template<int StoreMode>
+ EIGEN_STRONG_INLINE void writePacket(Index index, const PacketScalar& x)
+ {
+ internal::pstoret<Scalar, PacketScalar, StoreMode>(m_storage.data() + index, x);
+ }
+
+ /** \returns a const pointer to the data array of this matrix */
+ 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()
+ { return m_storage.data(); }
+
+ /** Resizes \c *this to a \a rows x \a cols matrix.
+ *
+ * This method is intended for dynamic-size matrices, although it is legal to call it on any
+ * matrix as long as fixed dimensions are left unchanged. If you only want to change the number
+ * of rows and/or of columns, you can use resize(NoChange_t, Index), resize(Index, NoChange_t).
+ *
+ * If the current number of coefficients of \c *this exactly matches the
+ * product \a rows * \a cols, then no memory allocation is performed and
+ * the current values are left unchanged. In all other cases, including
+ * shrinking, the data is reallocated and all previous values are lost.
+ *
+ * Example: \include Matrix_resize_int_int.cpp
+ * Output: \verbinclude Matrix_resize_int_int.out
+ *
+ * \sa resize(Index) for vectors, resize(NoChange_t, Index), resize(Index, NoChange_t)
+ */
+ EIGEN_STRONG_INLINE void resize(Index rows, Index cols)
+ {
+ #ifdef EIGEN_INITIALIZE_MATRICES_BY_ZERO
+ internal::check_rows_cols_for_overflow(rows, cols);
+ Index size = rows*cols;
+ bool size_changed = size != this->size();
+ m_storage.resize(size, rows, cols);
+ if(size_changed) EIGEN_INITIALIZE_BY_ZERO_IF_THAT_OPTION_IS_ENABLED
+ #else
+ internal::check_rows_cols_for_overflow(rows, cols);
+ m_storage.resize(rows*cols, rows, cols);
+ #endif
+ }
+
+ /** Resizes \c *this to a vector of length \a size
+ *
+ * \only_for_vectors. This method does not work for
+ * partially dynamic matrices when the static dimension is anything other
+ * than 1. For example it will not work with Matrix<double, 2, Dynamic>.
+ *
+ * Example: \include Matrix_resize_int.cpp
+ * Output: \verbinclude Matrix_resize_int.out
+ *
+ * \sa resize(Index,Index), resize(NoChange_t, Index), resize(Index, NoChange_t)
+ */
+ inline void resize(Index size)
+ {
+ EIGEN_STATIC_ASSERT_VECTOR_ONLY(PlainObjectBase)
+ eigen_assert(SizeAtCompileTime == Dynamic || SizeAtCompileTime == size);
+ #ifdef EIGEN_INITIALIZE_MATRICES_BY_ZERO
+ bool size_changed = size != this->size();
+ #endif
+ if(RowsAtCompileTime == 1)
+ m_storage.resize(size, 1, size);
+ else
+ m_storage.resize(size, size, 1);
+ #ifdef EIGEN_INITIALIZE_MATRICES_BY_ZERO
+ if(size_changed) EIGEN_INITIALIZE_BY_ZERO_IF_THAT_OPTION_IS_ENABLED
+ #endif
+ }
+
+ /** Resizes the matrix, changing only the number of columns. For the parameter of type NoChange_t, just pass the special value \c NoChange
+ * as in the example below.
+ *
+ * Example: \include Matrix_resize_NoChange_int.cpp
+ * Output: \verbinclude Matrix_resize_NoChange_int.out
+ *
+ * \sa resize(Index,Index)
+ */
+ inline void resize(NoChange_t, Index cols)
+ {
+ 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
+ * as in the example below.
+ *
+ * Example: \include Matrix_resize_int_NoChange.cpp
+ * Output: \verbinclude Matrix_resize_int_NoChange.out
+ *
+ * \sa resize(Index,Index)
+ */
+ inline void resize(Index rows, NoChange_t)
+ {
+ resize(rows, cols());
+ }
+
+ /** Resizes \c *this to have the same dimensions as \a other.
+ * Takes care of doing all the checking that's needed.
+ *
+ * Note that copying a row-vector into a vector (and conversely) is allowed.
+ * The resizing, if any, is then done in the appropriate way so that row-vectors
+ * remain row-vectors and vectors remain vectors.
+ */
+ template<typename OtherDerived>
+ EIGEN_STRONG_INLINE void resizeLike(const EigenBase<OtherDerived>& _other)
+ {
+ const OtherDerived& other = _other.derived();
+ internal::check_rows_cols_for_overflow(other.rows(), other.cols());
+ const Index othersize = other.rows()*other.cols();
+ if(RowsAtCompileTime == 1)
+ {
+ eigen_assert(other.rows() == 1 || other.cols() == 1);
+ resize(1, othersize);
+ }
+ else if(ColsAtCompileTime == 1)
+ {
+ eigen_assert(other.rows() == 1 || other.cols() == 1);
+ resize(othersize, 1);
+ }
+ else resize(other.rows(), other.cols());
+ }
+
+ /** Resizes the matrix to \a rows x \a cols while leaving old values untouched.
+ *
+ * The method is intended for matrices of dynamic size. If you only want to change the number
+ * of rows and/or of columns, you can use conservativeResize(NoChange_t, Index) or
+ * conservativeResize(Index, NoChange_t).
+ *
+ * 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 rows, Index cols)
+ {
+ internal::conservative_resize_like_impl<Derived>::run(*this, rows, cols);
+ }
+
+ /** Resizes the matrix to \a rows x \a cols while leaving old values untouched.
+ *
+ * As opposed to conservativeResize(Index rows, Index cols), this version leaves
+ * the number of columns unchanged.
+ *
+ * In case the matrix is growing, new rows will be uninitialized.
+ */
+ EIGEN_STRONG_INLINE void conservativeResize(Index rows, NoChange_t)
+ {
+ // Note: see the comment in conservativeResize(Index,Index)
+ conservativeResize(rows, cols());
+ }
+
+ /** Resizes the matrix to \a rows x \a cols while leaving old values untouched.
+ *
+ * As opposed to conservativeResize(Index rows, Index cols), this version leaves
+ * the number of rows unchanged.
+ *
+ * In case the matrix is growing, new columns will be uninitialized.
+ */
+ EIGEN_STRONG_INLINE void conservativeResize(NoChange_t, Index cols)
+ {
+ // Note: see the comment in conservativeResize(Index,Index)
+ conservativeResize(rows(), cols);
+ }
+
+ /** Resizes the vector to \a size while retaining old values.
+ *
+ * \only_for_vectors. This method does not work for
+ * partially dynamic matrices when the static dimension is anything other
+ * than 1. For example it will not work with Matrix<double, 2, Dynamic>.
+ *
+ * When values are appended, they will be uninitialized.
+ */
+ EIGEN_STRONG_INLINE void conservativeResize(Index size)
+ {
+ internal::conservative_resize_like_impl<Derived>::run(*this, size);
+ }
+
+ /** Resizes the matrix to \a rows x \a cols of \c other, while leaving old values untouched.
+ *
+ * The method is intended for matrices of dynamic size. If you only want to change the number
+ * of rows and/or of columns, you can use conservativeResize(NoChange_t, Index) or
+ * conservativeResize(Index, NoChange_t).
+ *
+ * Matrices are resized relative to the top-left element. In case values need to be
+ * appended to the matrix they will copied from \c other.
+ */
+ template<typename OtherDerived>
+ EIGEN_STRONG_INLINE void conservativeResizeLike(const DenseBase<OtherDerived>& other)
+ {
+ internal::conservative_resize_like_impl<Derived,OtherDerived>::run(*this, other);
+ }
+
+ /** This is a special case of the templated operator=. Its purpose is to
+ * prevent a default operator= from hiding the templated operator=.
+ */
+ EIGEN_STRONG_INLINE Derived& operator=(const PlainObjectBase& other)
+ {
+ return _set(other);
+ }
+
+ /** \sa MatrixBase::lazyAssign() */
+ template<typename OtherDerived>
+ EIGEN_STRONG_INLINE Derived& lazyAssign(const DenseBase<OtherDerived>& other)
+ {
+ _resize_to_match(other);
+ return Base::lazyAssign(other.derived());
+ }
+
+ template<typename OtherDerived>
+ EIGEN_STRONG_INLINE Derived& operator=(const ReturnByValue<OtherDerived>& func)
+ {
+ resize(func.rows(), func.cols());
+ return Base::operator=(func);
+ }
+
+ EIGEN_STRONG_INLINE explicit PlainObjectBase() : m_storage()
+ {
+// _check_template_params();
+// EIGEN_INITIALIZE_BY_ZERO_IF_THAT_OPTION_IS_ENABLED
+ }
+
+#ifndef EIGEN_PARSED_BY_DOXYGEN
+ // FIXME is it still needed ?
+ /** \internal */
+ PlainObjectBase(internal::constructor_without_unaligned_array_assert)
+ : m_storage(internal::constructor_without_unaligned_array_assert())
+ {
+// _check_template_params(); EIGEN_INITIALIZE_BY_ZERO_IF_THAT_OPTION_IS_ENABLED
+ }
+#endif
+
+ EIGEN_STRONG_INLINE PlainObjectBase(Index size, Index rows, Index cols)
+ : m_storage(size, rows, cols)
+ {
+// _check_template_params();
+// EIGEN_INITIALIZE_BY_ZERO_IF_THAT_OPTION_IS_ENABLED
+ }
+
+ /** \copydoc MatrixBase::operator=(const EigenBase<OtherDerived>&)
+ */
+ template<typename OtherDerived>
+ EIGEN_STRONG_INLINE Derived& operator=(const EigenBase<OtherDerived> &other)
+ {
+ _resize_to_match(other);
+ Base::operator=(other.derived());
+ return this->derived();
+ }
+
+ /** \sa MatrixBase::operator=(const EigenBase<OtherDerived>&) */
+ template<typename OtherDerived>
+ EIGEN_STRONG_INLINE PlainObjectBase(const EigenBase<OtherDerived> &other)
+ : m_storage(other.derived().rows() * other.derived().cols(), other.derived().rows(), other.derived().cols())
+ {
+ _check_template_params();
+ internal::check_rows_cols_for_overflow(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.
+ *
+ * \see class Map
+ */
+ //@{
+ static inline ConstMapType Map(const Scalar* data)
+ { return ConstMapType(data); }
+ static inline MapType Map(Scalar* data)
+ { return MapType(data); }
+ static inline ConstMapType Map(const Scalar* data, Index size)
+ { return ConstMapType(data, size); }
+ static inline MapType Map(Scalar* data, Index size)
+ { return MapType(data, size); }
+ static inline ConstMapType Map(const Scalar* data, Index rows, Index cols)
+ { return ConstMapType(data, rows, cols); }
+ static inline MapType Map(Scalar* data, Index rows, Index cols)
+ { return MapType(data, rows, cols); }
+
+ static inline ConstAlignedMapType MapAligned(const Scalar* data)
+ { return ConstAlignedMapType(data); }
+ static inline AlignedMapType MapAligned(Scalar* data)
+ { return AlignedMapType(data); }
+ static inline ConstAlignedMapType MapAligned(const Scalar* data, Index size)
+ { return ConstAlignedMapType(data, size); }
+ static inline AlignedMapType MapAligned(Scalar* data, Index size)
+ { return AlignedMapType(data, size); }
+ static inline ConstAlignedMapType MapAligned(const Scalar* data, Index rows, Index cols)
+ { return ConstAlignedMapType(data, rows, cols); }
+ static inline AlignedMapType MapAligned(Scalar* data, Index rows, Index cols)
+ { return AlignedMapType(data, rows, cols); }
+
+ template<int Outer, int Inner>
+ static inline typename StridedConstMapType<Stride<Outer, Inner> >::type Map(const Scalar* data, const Stride<Outer, Inner>& stride)
+ { return typename StridedConstMapType<Stride<Outer, Inner> >::type(data, stride); }
+ template<int Outer, int Inner>
+ static inline typename StridedMapType<Stride<Outer, Inner> >::type Map(Scalar* data, const Stride<Outer, Inner>& stride)
+ { return typename StridedMapType<Stride<Outer, Inner> >::type(data, stride); }
+ template<int Outer, int Inner>
+ static inline typename StridedConstMapType<Stride<Outer, Inner> >::type Map(const Scalar* data, Index size, const Stride<Outer, Inner>& stride)
+ { return typename StridedConstMapType<Stride<Outer, Inner> >::type(data, size, stride); }
+ template<int Outer, int Inner>
+ static inline typename StridedMapType<Stride<Outer, Inner> >::type Map(Scalar* data, Index size, const Stride<Outer, Inner>& stride)
+ { return typename StridedMapType<Stride<Outer, Inner> >::type(data, size, stride); }
+ template<int Outer, int Inner>
+ static inline typename StridedConstMapType<Stride<Outer, Inner> >::type Map(const Scalar* data, Index rows, Index cols, const Stride<Outer, Inner>& stride)
+ { return typename StridedConstMapType<Stride<Outer, Inner> >::type(data, rows, cols, stride); }
+ template<int Outer, int Inner>
+ static inline typename StridedMapType<Stride<Outer, Inner> >::type Map(Scalar* data, Index rows, Index cols, const Stride<Outer, Inner>& stride)
+ { return typename StridedMapType<Stride<Outer, Inner> >::type(data, rows, cols, stride); }
+
+ template<int Outer, int Inner>
+ static inline typename StridedConstAlignedMapType<Stride<Outer, Inner> >::type MapAligned(const Scalar* data, const Stride<Outer, Inner>& stride)
+ { return typename StridedConstAlignedMapType<Stride<Outer, Inner> >::type(data, stride); }
+ template<int Outer, int Inner>
+ static inline typename StridedAlignedMapType<Stride<Outer, Inner> >::type MapAligned(Scalar* data, const Stride<Outer, Inner>& stride)
+ { return typename StridedAlignedMapType<Stride<Outer, Inner> >::type(data, stride); }
+ template<int Outer, int Inner>
+ static inline typename StridedConstAlignedMapType<Stride<Outer, Inner> >::type MapAligned(const Scalar* data, Index size, const Stride<Outer, Inner>& stride)
+ { return typename StridedConstAlignedMapType<Stride<Outer, Inner> >::type(data, size, stride); }
+ template<int Outer, int Inner>
+ static inline typename StridedAlignedMapType<Stride<Outer, Inner> >::type MapAligned(Scalar* data, Index size, const Stride<Outer, Inner>& stride)
+ { return typename StridedAlignedMapType<Stride<Outer, Inner> >::type(data, size, stride); }
+ template<int Outer, int Inner>
+ static inline typename StridedConstAlignedMapType<Stride<Outer, Inner> >::type MapAligned(const Scalar* data, Index rows, Index cols, const Stride<Outer, Inner>& stride)
+ { return typename StridedConstAlignedMapType<Stride<Outer, Inner> >::type(data, rows, cols, stride); }
+ template<int Outer, int Inner>
+ static inline typename StridedAlignedMapType<Stride<Outer, Inner> >::type MapAligned(Scalar* data, Index rows, Index cols, const Stride<Outer, Inner>& stride)
+ { return typename StridedAlignedMapType<Stride<Outer, Inner> >::type(data, rows, cols, stride); }
+ //@}
+
+ using Base::setConstant;
+ Derived& setConstant(Index size, const Scalar& value);
+ Derived& setConstant(Index rows, Index cols, const Scalar& value);
+
+ using Base::setZero;
+ Derived& setZero(Index size);
+ Derived& setZero(Index rows, Index cols);
+
+ using Base::setOnes;
+ Derived& setOnes(Index size);
+ Derived& setOnes(Index rows, Index cols);
+
+ using Base::setRandom;
+ Derived& setRandom(Index size);
+ Derived& setRandom(Index rows, Index cols);
+
+ #ifdef EIGEN_PLAINOBJECTBASE_PLUGIN
+ #include EIGEN_PLAINOBJECTBASE_PLUGIN
+ #endif
+
+ protected:
+ /** \internal Resizes *this in preparation for assigning \a other to it.
+ * Takes care of doing all the checking that's needed.
+ *
+ * Note that copying a row-vector into a vector (and conversely) is allowed.
+ * The resizing, if any, is then done in the appropriate way so that row-vectors
+ * remain row-vectors and vectors remain vectors.
+ */
+ template<typename OtherDerived>
+ EIGEN_STRONG_INLINE void _resize_to_match(const EigenBase<OtherDerived>& other)
+ {
+ #ifdef EIGEN_NO_AUTOMATIC_RESIZING
+ eigen_assert((this->size()==0 || (IsVectorAtCompileTime ? (this->size() == other.size())
+ : (rows() == other.rows() && cols() == other.cols())))
+ && "Size mismatch. Automatic resizing is disabled because EIGEN_NO_AUTOMATIC_RESIZING is defined");
+ #else
+ resizeLike(other);
+ #endif
+ }
+
+ /**
+ * \brief 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),
+ * it will be initialized.
+ *
+ * Note that copying a row-vector into a vector (and conversely) is allowed.
+ * The resizing, if any, is then done in the appropriate way so that row-vectors
+ * remain row-vectors and vectors remain vectors.
+ *
+ * \sa operator=(const MatrixBase<OtherDerived>&), _set_noalias()
+ *
+ * \internal
+ */
+ template<typename OtherDerived>
+ EIGEN_STRONG_INLINE Derived& _set(const DenseBase<OtherDerived>& other)
+ {
+ _set_selector(other.derived(), typename internal::conditional<static_cast<bool>(int(OtherDerived::Flags) & EvalBeforeAssigningBit), internal::true_type, internal::false_type>::type());
+ return this->derived();
+ }
+
+ template<typename OtherDerived>
+ EIGEN_STRONG_INLINE void _set_selector(const OtherDerived& other, const internal::true_type&) { _set_noalias(other.eval()); }
+
+ template<typename OtherDerived>
+ 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<OtherDerived>&), _set()
+ */
+ template<typename OtherDerived>
+ EIGEN_STRONG_INLINE Derived& _set_noalias(const DenseBase<OtherDerived>& other)
+ {
+ // I don't think we need this resize call since the lazyAssign will anyways resize
+ // and lazyAssign will be called by the assign selector.
+ //_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<Derived,OtherDerived,false>::run(this->derived(), other.derived());
+ }
+
+ template<typename T0, typename T1>
+ EIGEN_STRONG_INLINE void _init2(Index rows, Index cols, typename internal::enable_if<Base::SizeAtCompileTime!=2,T0>::type* = 0)
+ {
+ EIGEN_STATIC_ASSERT(bool(NumTraits<T0>::IsInteger) &&
+ bool(NumTraits<T1>::IsInteger),
+ FLOATING_POINT_ARGUMENT_PASSED__INTEGER_WAS_EXPECTED)
+ eigen_assert(rows >= 0 && (RowsAtCompileTime == Dynamic || RowsAtCompileTime == rows)
+ && cols >= 0 && (ColsAtCompileTime == Dynamic || ColsAtCompileTime == cols));
+ internal::check_rows_cols_for_overflow(rows, cols);
+ m_storage.resize(rows*cols,rows,cols);
+ EIGEN_INITIALIZE_BY_ZERO_IF_THAT_OPTION_IS_ENABLED
+ }
+ template<typename T0, typename T1>
+ EIGEN_STRONG_INLINE void _init2(const Scalar& x, const Scalar& y, typename internal::enable_if<Base::SizeAtCompileTime==2,T0>::type* = 0)
+ {
+ EIGEN_STATIC_ASSERT_VECTOR_SPECIFIC_SIZE(PlainObjectBase, 2)
+ m_storage.data()[0] = x;
+ m_storage.data()[1] = y;
+ }
+
+ template<typename MatrixTypeA, typename MatrixTypeB, bool SwapPointers>
+ 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.
+ */
+ template<typename OtherDerived>
+ void _swap(DenseBase<OtherDerived> const & other)
+ {
+ enum { SwapPointers = internal::is_same<Derived, OtherDerived>::value && Base::SizeAtCompileTime==Dynamic };
+ internal::matrix_swap_impl<Derived, OtherDerived, bool(SwapPointers)>::run(this->derived(), other.const_cast_derived());
+ }
+
+ public:
+#ifndef EIGEN_PARSED_BY_DOXYGEN
+ static EIGEN_STRONG_INLINE void _check_template_params()
+ {
+ EIGEN_STATIC_ASSERT((EIGEN_IMPLIES(MaxRowsAtCompileTime==1 && MaxColsAtCompileTime!=1, (Options&RowMajor)==RowMajor)
+ && EIGEN_IMPLIES(MaxColsAtCompileTime==1 && MaxRowsAtCompileTime!=1, (Options&RowMajor)==0)
+ && ((RowsAtCompileTime == Dynamic) || (RowsAtCompileTime >= 0))
+ && ((ColsAtCompileTime == Dynamic) || (ColsAtCompileTime >= 0))
+ && ((MaxRowsAtCompileTime == Dynamic) || (MaxRowsAtCompileTime >= 0))
+ && ((MaxColsAtCompileTime == Dynamic) || (MaxColsAtCompileTime >= 0))
+ && (MaxRowsAtCompileTime == RowsAtCompileTime || RowsAtCompileTime==Dynamic)
+ && (MaxColsAtCompileTime == ColsAtCompileTime || ColsAtCompileTime==Dynamic)
+ && (Options & (DontAlign|RowMajor)) == Options),
+ INVALID_MATRIX_TEMPLATE_PARAMETERS)
+ }
+#endif
+
+private:
+ enum { ThisConstantIsPrivateInPlainObjectBase };
+};
+
+template <typename Derived, typename OtherDerived, bool IsVector>
+struct internal::conservative_resize_like_impl
+{
+ typedef typename Derived::Index Index;
+ static void run(DenseBase<Derived>& _this, Index rows, Index cols)
+ {
+ if (_this.rows() == rows && _this.cols() == cols) return;
+ EIGEN_STATIC_ASSERT_DYNAMIC_SIZE(Derived)
+
+ if ( ( Derived::IsRowMajor && _this.cols() == cols) || // row-major and we change only the number of rows
+ (!Derived::IsRowMajor && _this.rows() == rows) ) // column-major and we change only the number of columns
+ {
+ internal::check_rows_cols_for_overflow(rows, cols);
+ _this.derived().m_storage.conservativeResize(rows*cols,rows,cols);
+ }
+ else
+ {
+ // 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());
+ tmp.block(0,0,common_rows,common_cols) = _this.block(0,0,common_rows,common_cols);
+ _this.derived().swap(tmp);
+ }
+ }
+
+ static void run(DenseBase<Derived>& _this, const DenseBase<OtherDerived>& other)
+ {
+ if (_this.rows() == other.rows() && _this.cols() == other.cols()) return;
+
+ // Note: Here is space for improvement. Basically, for conservativeResize(Index,Index),
+ // neither RowsAtCompileTime or ColsAtCompileTime must be Dynamic. If only one of the
+ // dimensions is dynamic, one could use either conservativeResize(Index rows, NoChange_t) or
+ // conservativeResize(NoChange_t, Index cols). For these methods new static asserts like
+ // EIGEN_STATIC_ASSERT_DYNAMIC_ROWS and EIGEN_STATIC_ASSERT_DYNAMIC_COLS would be good.
+ EIGEN_STATIC_ASSERT_DYNAMIC_SIZE(Derived)
+ EIGEN_STATIC_ASSERT_DYNAMIC_SIZE(OtherDerived)
+
+ if ( ( Derived::IsRowMajor && _this.cols() == other.cols()) || // row-major and we change only the number of rows
+ (!Derived::IsRowMajor && _this.rows() == other.rows()) ) // column-major and we change only the number of columns
+ {
+ const Index new_rows = other.rows() - _this.rows();
+ const Index new_cols = other.cols() - _this.cols();
+ _this.derived().m_storage.conservativeResize(other.size(),other.rows(),other.cols());
+ if (new_rows>0)
+ _this.bottomRightCorner(new_rows, other.cols()) = other.bottomRows(new_rows);
+ else if (new_cols>0)
+ _this.bottomRightCorner(other.rows(), new_cols) = other.rightCols(new_cols);
+ }
+ else
+ {
+ // 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());
+ tmp.block(0,0,common_rows,common_cols) = _this.block(0,0,common_rows,common_cols);
+ _this.derived().swap(tmp);
+ }
+ }
+};
+
+namespace internal {
+
+template <typename Derived, typename OtherDerived>
+struct conservative_resize_like_impl<Derived,OtherDerived,true>
+{
+ typedef typename Derived::Index Index;
+ static void run(DenseBase<Derived>& _this, Index size)
+ {
+ const Index new_rows = Derived::RowsAtCompileTime==1 ? 1 : size;
+ const Index new_cols = Derived::RowsAtCompileTime==1 ? size : 1;
+ _this.derived().m_storage.conservativeResize(size,new_rows,new_cols);
+ }
+
+ static void run(DenseBase<Derived>& _this, const DenseBase<OtherDerived>& other)
+ {
+ if (_this.rows() == other.rows() && _this.cols() == other.cols()) return;
+
+ const Index num_new_elements = other.size() - _this.size();
+
+ const Index new_rows = Derived::RowsAtCompileTime==1 ? 1 : other.rows();
+ const Index new_cols = Derived::RowsAtCompileTime==1 ? other.cols() : 1;
+ _this.derived().m_storage.conservativeResize(other.size(),new_rows,new_cols);
+
+ if (num_new_elements > 0)
+ _this.tail(num_new_elements) = other.tail(num_new_elements);
+ }
+};
+
+template<typename MatrixTypeA, typename MatrixTypeB, bool SwapPointers>
+struct matrix_swap_impl
+{
+ static inline void run(MatrixTypeA& a, MatrixTypeB& b)
+ {
+ a.base().swap(b);
+ }
+};
+
+template<typename MatrixTypeA, typename MatrixTypeB>
+struct matrix_swap_impl<MatrixTypeA, MatrixTypeB, true>
+{
+ static inline void run(MatrixTypeA& a, MatrixTypeB& b)
+ {
+ static_cast<typename MatrixTypeA::Base&>(a).m_storage.swap(static_cast<typename MatrixTypeB::Base&>(b).m_storage);
+ }
+};
+
+} // end namespace internal
+
+} // end namespace Eigen
+
+#endif // EIGEN_DENSESTORAGEBASE_H
diff --git a/Eigen/src/Core/Product.h b/Eigen/src/Core/Product.h
new file mode 100644
index 000000000..30aa8943b
--- /dev/null
+++ b/Eigen/src/Core/Product.h
@@ -0,0 +1,98 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra.
+//
+// Copyright (C) 2008-2011 Gael Guennebaud <gael.guennebaud@inria.fr>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public
+// License, v. 2.0. If 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
+
+template<typename Lhs, typename Rhs> class Product;
+template<typename Lhs, typename Rhs, typename StorageKind> class ProductImpl;
+
+/** \class Product
+ * \ingroup Core_Module
+ *
+ * \brief Expression of the product of two arbitrary matrices or vectors
+ *
+ * \param Lhs the type of the left-hand side expression
+ * \param Rhs the type of the right-hand side expression
+ *
+ * This class represents an expression of the product of two arbitrary matrices.
+ *
+ */
+
+namespace internal {
+template<typename Lhs, typename Rhs>
+struct traits<Product<Lhs, Rhs> >
+{
+ typedef MatrixXpr XprKind;
+ typedef typename remove_all<Lhs>::type LhsCleaned;
+ typedef typename remove_all<Rhs>::type RhsCleaned;
+ typedef typename scalar_product_traits<typename traits<LhsCleaned>::Scalar, typename traits<RhsCleaned>::Scalar>::ReturnType Scalar;
+ typedef typename promote_storage_type<typename traits<LhsCleaned>::StorageKind,
+ typename traits<RhsCleaned>::StorageKind>::ret StorageKind;
+ typedef typename promote_index_type<typename traits<LhsCleaned>::Index,
+ typename traits<RhsCleaned>::Index>::type Index;
+ enum {
+ RowsAtCompileTime = LhsCleaned::RowsAtCompileTime,
+ ColsAtCompileTime = RhsCleaned::ColsAtCompileTime,
+ MaxRowsAtCompileTime = LhsCleaned::MaxRowsAtCompileTime,
+ MaxColsAtCompileTime = RhsCleaned::MaxColsAtCompileTime,
+ Flags = (MaxRowsAtCompileTime==1 ? RowMajorBit : 0), // TODO should be no storage order
+ CoeffReadCost = 0 // TODO CoeffReadCost should not be part of the expression traits
+ };
+};
+} // end namespace internal
+
+
+template<typename Lhs, typename Rhs>
+class Product : public ProductImpl<Lhs,Rhs,typename internal::promote_storage_type<typename internal::traits<Lhs>::StorageKind,
+ typename internal::traits<Rhs>::StorageKind>::ret>
+{
+ public:
+
+ typedef typename ProductImpl<
+ Lhs, Rhs,
+ typename internal::promote_storage_type<typename Lhs::StorageKind,
+ typename Rhs::StorageKind>::ret>::Base Base;
+ EIGEN_GENERIC_PUBLIC_INTERFACE(Product)
+
+ typedef typename Lhs::Nested LhsNested;
+ typedef typename Rhs::Nested RhsNested;
+ typedef typename internal::remove_all<LhsNested>::type LhsNestedCleaned;
+ typedef typename internal::remove_all<RhsNested>::type RhsNestedCleaned;
+
+ 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");
+ }
+
+ inline Index rows() const { return m_lhs.rows(); }
+ inline Index cols() const { return m_rhs.cols(); }
+
+ const LhsNestedCleaned& lhs() const { return m_lhs; }
+ const RhsNestedCleaned& rhs() const { return m_rhs; }
+
+ protected:
+
+ const LhsNested m_lhs;
+ const RhsNested m_rhs;
+};
+
+template<typename Lhs, typename Rhs>
+class ProductImpl<Lhs,Rhs,Dense> : public internal::dense_xpr_base<Product<Lhs,Rhs> >::type
+{
+ typedef Product<Lhs, Rhs> Derived;
+ public:
+
+ typedef typename internal::dense_xpr_base<Product<Lhs, Rhs> >::type Base;
+ EIGEN_DENSE_PUBLIC_INTERFACE(Derived)
+};
+
+#endif // EIGEN_PRODUCT_H
diff --git a/Eigen/src/Core/ProductBase.h b/Eigen/src/Core/ProductBase.h
new file mode 100644
index 000000000..ec12e5c9f
--- /dev/null
+++ b/Eigen/src/Core/ProductBase.h
@@ -0,0 +1,278 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra.
+//
+// Copyright (C) 2009-2010 Gael Guennebaud <gael.guennebaud@inria.fr>
+//
+// This Source Code Form is subject to the terms of the Mozilla
+// Public License v. 2.0. If 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<typename Derived, typename _Lhs, typename _Rhs>
+struct traits<ProductBase<Derived,_Lhs,_Rhs> >
+{
+ typedef MatrixXpr XprKind;
+ typedef typename remove_all<_Lhs>::type Lhs;
+ typedef typename remove_all<_Rhs>::type Rhs;
+ typedef typename scalar_product_traits<typename Lhs::Scalar, typename Rhs::Scalar>::ReturnType Scalar;
+ typedef typename promote_storage_type<typename traits<Lhs>::StorageKind,
+ typename traits<Rhs>::StorageKind>::ret StorageKind;
+ typedef typename promote_index_type<typename traits<Lhs>::Index,
+ typename traits<Rhs>::Index>::type Index;
+ enum {
+ RowsAtCompileTime = traits<Lhs>::RowsAtCompileTime,
+ ColsAtCompileTime = traits<Rhs>::ColsAtCompileTime,
+ MaxRowsAtCompileTime = traits<Lhs>::MaxRowsAtCompileTime,
+ MaxColsAtCompileTime = traits<Rhs>::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<Derived, Lhs, Rhs > 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<typename Derived, typename Lhs, typename Rhs>
+class ProductBase : public MatrixBase<Derived>
+{
+ public:
+ typedef MatrixBase<Derived> Base;
+ EIGEN_DENSE_PUBLIC_INTERFACE(ProductBase)
+
+ typedef typename Lhs::Nested LhsNested;
+ typedef typename internal::remove_all<LhsNested>::type _LhsNested;
+ typedef internal::blas_traits<_LhsNested> LhsBlasTraits;
+ typedef typename LhsBlasTraits::DirectLinearAccessType ActualLhsType;
+ typedef typename internal::remove_all<ActualLhsType>::type _ActualLhsType;
+ typedef typename internal::traits<Lhs>::Scalar LhsScalar;
+
+ typedef typename Rhs::Nested RhsNested;
+ typedef typename internal::remove_all<RhsNested>::type _RhsNested;
+ typedef internal::blas_traits<_RhsNested> RhsBlasTraits;
+ typedef typename RhsBlasTraits::DirectLinearAccessType ActualRhsType;
+ typedef typename internal::remove_all<ActualRhsType>::type _ActualRhsType;
+ typedef typename internal::traits<Rhs>::Scalar RhsScalar;
+
+ // Diagonal of a product: no need to evaluate the arguments because they are going to be evaluated only once
+ typedef CoeffBasedProduct<LhsNested, RhsNested, 0> FullyLazyCoeffBaseProductType;
+
+ public:
+
+ typedef typename Base::PlainObject PlainObject;
+
+ ProductBase(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");
+ }
+
+ inline Index rows() const { return m_lhs.rows(); }
+ inline Index cols() const { return m_rhs.cols(); }
+
+ template<typename Dest>
+ inline void evalTo(Dest& dst) const { dst.setZero(); scaleAndAddTo(dst,Scalar(1)); }
+
+ template<typename Dest>
+ inline void addTo(Dest& dst) const { scaleAndAddTo(dst,Scalar(1)); }
+
+ template<typename Dest>
+ inline void subTo(Dest& dst) const { scaleAndAddTo(dst,Scalar(-1)); }
+
+ template<typename Dest>
+ inline void scaleAndAddTo(Dest& dst,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<const FullyLazyCoeffBaseProductType,0> diagonal() const
+ { return FullyLazyCoeffBaseProductType(m_lhs, m_rhs); }
+
+ template<int Index>
+ const Diagonal<FullyLazyCoeffBaseProductType,Index> diagonal() const
+ { return FullyLazyCoeffBaseProductType(m_lhs, m_rhs); }
+
+ const Diagonal<FullyLazyCoeffBaseProductType,Dynamic> 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<Scalar,1,1> 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<Scalar,1,1> 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<typename Lhs, typename Rhs, int Mode, int N, typename PlainObject>
+struct nested<GeneralProduct<Lhs,Rhs,Mode>, N, PlainObject>
+{
+ typedef PlainObject const& type;
+};
+}
+
+template<typename NestedProduct>
+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<typename Derived,typename Lhs,typename Rhs>
+const ScaledProduct<Derived>
+operator*(const ProductBase<Derived,Lhs,Rhs>& prod, typename Derived::Scalar x)
+{ return ScaledProduct<Derived>(prod.derived(), x); }
+
+template<typename Derived,typename Lhs,typename Rhs>
+typename internal::enable_if<!internal::is_same<typename Derived::Scalar,typename Derived::RealScalar>::value,
+ const ScaledProduct<Derived> >::type
+operator*(const ProductBase<Derived,Lhs,Rhs>& prod, typename Derived::RealScalar x)
+{ return ScaledProduct<Derived>(prod.derived(), x); }
+
+
+template<typename Derived,typename Lhs,typename Rhs>
+const ScaledProduct<Derived>
+operator*(typename Derived::Scalar x,const ProductBase<Derived,Lhs,Rhs>& prod)
+{ return ScaledProduct<Derived>(prod.derived(), x); }
+
+template<typename Derived,typename Lhs,typename Rhs>
+typename internal::enable_if<!internal::is_same<typename Derived::Scalar,typename Derived::RealScalar>::value,
+ const ScaledProduct<Derived> >::type
+operator*(typename Derived::RealScalar x,const ProductBase<Derived,Lhs,Rhs>& prod)
+{ return ScaledProduct<Derived>(prod.derived(), x); }
+
+namespace internal {
+template<typename NestedProduct>
+struct traits<ScaledProduct<NestedProduct> >
+ : traits<ProductBase<ScaledProduct<NestedProduct>,
+ typename NestedProduct::_LhsNested,
+ typename NestedProduct::_RhsNested> >
+{
+ typedef typename traits<NestedProduct>::StorageKind StorageKind;
+};
+}
+
+template<typename NestedProduct>
+class ScaledProduct
+ : public ProductBase<ScaledProduct<NestedProduct>,
+ typename NestedProduct::_LhsNested,
+ typename NestedProduct::_RhsNested>
+{
+ public:
+ typedef ProductBase<ScaledProduct<NestedProduct>,
+ 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, Scalar x)
+ : Base(prod.lhs(),prod.rhs()), m_prod(prod), m_alpha(x) {}
+
+ template<typename Dest>
+ inline void evalTo(Dest& dst) const { dst.setZero(); scaleAndAddTo(dst, Scalar(1)); }
+
+ template<typename Dest>
+ inline void addTo(Dest& dst) const { scaleAndAddTo(dst, Scalar(1)); }
+
+ template<typename Dest>
+ inline void subTo(Dest& dst) const { scaleAndAddTo(dst, Scalar(-1)); }
+
+ template<typename Dest>
+ inline void scaleAndAddTo(Dest& dst,Scalar alpha) const { m_prod.derived().scaleAndAddTo(dst,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<typename Derived>
+template<typename ProductDerived, typename Lhs, typename Rhs>
+Derived& MatrixBase<Derived>::lazyAssign(const ProductBase<ProductDerived, Lhs,Rhs>& other)
+{
+ other.derived().evalTo(derived());
+ return derived();
+}
+
+} // end namespace Eigen
+
+#endif // EIGEN_PRODUCTBASE_H
diff --git a/Eigen/src/Core/Random.h b/Eigen/src/Core/Random.h
new file mode 100644
index 000000000..a9f7f4346
--- /dev/null
+++ b/Eigen/src/Core/Random.h
@@ -0,0 +1,152 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra.
+//
+// Copyright (C) 2008 Gael Guennebaud <gael.guennebaud@inria.fr>
+//
+// This Source Code Form is subject to the terms of the Mozilla
+// Public License v. 2.0. If a copy of the MPL was not distributed
+// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+#ifndef EIGEN_RANDOM_H
+#define EIGEN_RANDOM_H
+
+namespace Eigen {
+
+namespace internal {
+
+template<typename Scalar> struct scalar_random_op {
+ EIGEN_EMPTY_STRUCT_CTOR(scalar_random_op)
+ template<typename Index>
+ inline const Scalar operator() (Index, Index = 0) const { return random<Scalar>(); }
+};
+
+template<typename Scalar>
+struct functor_traits<scalar_random_op<Scalar> >
+{ enum { Cost = 5 * NumTraits<Scalar>::MulCost, PacketAccess = false, IsRepeatable = false }; };
+
+} // end namespace internal
+
+/** \returns a random matrix expression
+ *
+ * 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,
+ * 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
+ *
+ * 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.
+ *
+ * \sa MatrixBase::setRandom(), MatrixBase::Random(Index), MatrixBase::Random()
+ */
+template<typename Derived>
+inline const CwiseNullaryOp<internal::scalar_random_op<typename internal::traits<Derived>::Scalar>, Derived>
+DenseBase<Derived>::Random(Index rows, Index cols)
+{
+ return NullaryExpr(rows, cols, internal::scalar_random_op<Scalar>());
+}
+
+/** \returns a random vector expression
+ *
+ * The parameter \a size is the size of the returned vector.
+ * Must be compatible with this MatrixBase type.
+ *
+ * \only_for_vectors
+ *
+ * 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
+ * instead.
+ *
+ * Example: \include MatrixBase_random_int.cpp
+ * Output: \verbinclude MatrixBase_random_int.out
+ *
+ * This expression has the "evaluate before nesting" flag so that it will be evaluated into
+ * 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()
+ */
+template<typename Derived>
+inline const CwiseNullaryOp<internal::scalar_random_op<typename internal::traits<Derived>::Scalar>, Derived>
+DenseBase<Derived>::Random(Index size)
+{
+ return NullaryExpr(size, internal::scalar_random_op<Scalar>());
+}
+
+/** \returns a fixed-size random matrix or vector expression
+ *
+ * This variant is only for fixed-size MatrixBase types. For dynamic-size types, you
+ * need to use the variants taking size arguments.
+ *
+ * Example: \include MatrixBase_random.cpp
+ * Output: \verbinclude MatrixBase_random.out
+ *
+ * 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.
+ *
+ * \sa MatrixBase::setRandom(), MatrixBase::Random(Index,Index), MatrixBase::Random(Index)
+ */
+template<typename Derived>
+inline const CwiseNullaryOp<internal::scalar_random_op<typename internal::traits<Derived>::Scalar>, Derived>
+DenseBase<Derived>::Random()
+{
+ return NullaryExpr(RowsAtCompileTime, ColsAtCompileTime, internal::scalar_random_op<Scalar>());
+}
+
+/** Sets all coefficients in this expression to random values.
+ *
+ * Example: \include MatrixBase_setRandom.cpp
+ * Output: \verbinclude MatrixBase_setRandom.out
+ *
+ * \sa class CwiseNullaryOp, setRandom(Index), setRandom(Index,Index)
+ */
+template<typename Derived>
+inline Derived& DenseBase<Derived>::setRandom()
+{
+ return *this = Random(rows(), cols());
+}
+
+/** Resizes to the given \a size, and sets all coefficients in this expression to random values.
+ *
+ * \only_for_vectors
+ *
+ * Example: \include Matrix_setRandom_int.cpp
+ * Output: \verbinclude Matrix_setRandom_int.out
+ *
+ * \sa MatrixBase::setRandom(), setRandom(Index,Index), class CwiseNullaryOp, MatrixBase::Random()
+ */
+template<typename Derived>
+EIGEN_STRONG_INLINE Derived&
+PlainObjectBase<Derived>::setRandom(Index size)
+{
+ resize(size);
+ return setRandom();
+}
+
+/** Resizes to the given size, and sets all coefficients in this expression to random values.
+ *
+ * \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()
+ */
+template<typename Derived>
+EIGEN_STRONG_INLINE Derived&
+PlainObjectBase<Derived>::setRandom(Index rows, Index cols)
+{
+ resize(rows, cols);
+ return setRandom();
+}
+
+} // end namespace Eigen
+
+#endif // EIGEN_RANDOM_H
diff --git a/Eigen/src/Core/Redux.h b/Eigen/src/Core/Redux.h
new file mode 100644
index 000000000..b7ce7c658
--- /dev/null
+++ b/Eigen/src/Core/Redux.h
@@ -0,0 +1,406 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra.
+//
+// Copyright (C) 2008 Gael Guennebaud <gael.guennebaud@inria.fr>
+// Copyright (C) 2006-2008 Benoit Jacob <jacob.benoit.1@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 EIGEN_REDUX_H
+#define EIGEN_REDUX_H
+
+namespace Eigen {
+
+namespace internal {
+
+// TODO
+// * implement other kind of vectorization
+// * factorize code
+
+/***************************************************************************
+* Part 1 : the logic deciding a strategy for vectorization and unrolling
+***************************************************************************/
+
+template<typename Func, typename Derived>
+struct redux_traits
+{
+public:
+ enum {
+ PacketSize = packet_traits<typename Derived::Scalar>::size,
+ InnerMaxSize = int(Derived::IsRowMajor)
+ ? Derived::MaxColsAtCompileTime
+ : Derived::MaxRowsAtCompileTime
+ };
+
+ enum {
+ MightVectorize = (int(Derived::Flags)&ActualPacketAccessBit)
+ && (functor_traits<Func>::PacketAccess),
+ MayLinearVectorize = MightVectorize && (int(Derived::Flags)&LinearAccessBit),
+ MaySliceVectorize = MightVectorize && int(InnerMaxSize)>=3*PacketSize
+ };
+
+public:
+ enum {
+ Traversal = int(MayLinearVectorize) ? int(LinearVectorizedTraversal)
+ : int(MaySliceVectorize) ? int(SliceVectorizedTraversal)
+ : int(DefaultTraversal)
+ };
+
+public:
+ enum {
+ Cost = ( Derived::SizeAtCompileTime == Dynamic
+ || Derived::CoeffReadCost == Dynamic
+ || (Derived::SizeAtCompileTime!=1 && functor_traits<Func>::Cost == Dynamic)
+ ) ? Dynamic
+ : Derived::SizeAtCompileTime * Derived::CoeffReadCost
+ + (Derived::SizeAtCompileTime-1) * functor_traits<Func>::Cost,
+ UnrollingLimit = EIGEN_UNROLLING_LIMIT * (int(Traversal) == int(DefaultTraversal) ? 1 : int(PacketSize))
+ };
+
+public:
+ enum {
+ Unrolling = Cost != Dynamic && Cost <= UnrollingLimit
+ ? CompleteUnrolling
+ : NoUnrolling
+ };
+};
+
+/***************************************************************************
+* Part 2 : unrollers
+***************************************************************************/
+
+/*** no vectorization ***/
+
+template<typename Func, typename Derived, int Start, int Length>
+struct redux_novec_unroller
+{
+ enum {
+ HalfLength = Length/2
+ };
+
+ typedef typename Derived::Scalar Scalar;
+
+ static EIGEN_STRONG_INLINE Scalar run(const Derived &mat, const Func& func)
+ {
+ return func(redux_novec_unroller<Func, Derived, Start, HalfLength>::run(mat,func),
+ redux_novec_unroller<Func, Derived, Start+HalfLength, Length-HalfLength>::run(mat,func));
+ }
+};
+
+template<typename Func, typename Derived, int Start>
+struct redux_novec_unroller<Func, Derived, Start, 1>
+{
+ enum {
+ outer = Start / Derived::InnerSizeAtCompileTime,
+ inner = Start % Derived::InnerSizeAtCompileTime
+ };
+
+ typedef typename Derived::Scalar Scalar;
+
+ static EIGEN_STRONG_INLINE Scalar run(const Derived &mat, const Func&)
+ {
+ return mat.coeffByOuterInner(outer, inner);
+ }
+};
+
+// This is actually dead code and will never be called. It is required
+// to prevent false warnings regarding failed inlining though
+// for 0 length run() will never be called at all.
+template<typename Func, typename Derived, int Start>
+struct redux_novec_unroller<Func, Derived, Start, 0>
+{
+ typedef typename Derived::Scalar Scalar;
+ static EIGEN_STRONG_INLINE Scalar run(const Derived&, const Func&) { return Scalar(); }
+};
+
+/*** vectorization ***/
+
+template<typename Func, typename Derived, int Start, int Length>
+struct redux_vec_unroller
+{
+ enum {
+ PacketSize = packet_traits<typename Derived::Scalar>::size,
+ HalfLength = Length/2
+ };
+
+ typedef typename Derived::Scalar Scalar;
+ typedef typename packet_traits<Scalar>::type PacketScalar;
+
+ static EIGEN_STRONG_INLINE PacketScalar run(const Derived &mat, const Func& func)
+ {
+ return func.packetOp(
+ redux_vec_unroller<Func, Derived, Start, HalfLength>::run(mat,func),
+ redux_vec_unroller<Func, Derived, Start+HalfLength, Length-HalfLength>::run(mat,func) );
+ }
+};
+
+template<typename Func, typename Derived, int Start>
+struct redux_vec_unroller<Func, Derived, Start, 1>
+{
+ enum {
+ index = Start * packet_traits<typename Derived::Scalar>::size,
+ outer = index / int(Derived::InnerSizeAtCompileTime),
+ inner = index % int(Derived::InnerSizeAtCompileTime),
+ alignment = (Derived::Flags & AlignedBit) ? Aligned : Unaligned
+ };
+
+ typedef typename Derived::Scalar Scalar;
+ typedef typename packet_traits<Scalar>::type PacketScalar;
+
+ static EIGEN_STRONG_INLINE PacketScalar run(const Derived &mat, const Func&)
+ {
+ return mat.template packetByOuterInner<alignment>(outer, inner);
+ }
+};
+
+/***************************************************************************
+* Part 3 : implementation of all cases
+***************************************************************************/
+
+template<typename Func, typename Derived,
+ int Traversal = redux_traits<Func, Derived>::Traversal,
+ int Unrolling = redux_traits<Func, Derived>::Unrolling
+>
+struct redux_impl;
+
+template<typename Func, typename Derived>
+struct redux_impl<Func, Derived, DefaultTraversal, NoUnrolling>
+{
+ typedef typename Derived::Scalar Scalar;
+ typedef typename Derived::Index Index;
+ 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;
+ res = mat.coeffByOuterInner(0, 0);
+ for(Index i = 1; i < mat.innerSize(); ++i)
+ res = func(res, mat.coeffByOuterInner(0, i));
+ for(Index i = 1; i < mat.outerSize(); ++i)
+ for(Index j = 0; j < mat.innerSize(); ++j)
+ res = func(res, mat.coeffByOuterInner(i, j));
+ return res;
+ }
+};
+
+template<typename Func, typename Derived>
+struct redux_impl<Func,Derived, DefaultTraversal, CompleteUnrolling>
+ : public redux_novec_unroller<Func,Derived, 0, Derived::SizeAtCompileTime>
+{};
+
+template<typename Func, typename Derived>
+struct redux_impl<Func, Derived, LinearVectorizedTraversal, NoUnrolling>
+{
+ typedef typename Derived::Scalar Scalar;
+ typedef typename packet_traits<Scalar>::type PacketScalar;
+ typedef typename Derived::Index Index;
+
+ 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<Scalar>::size;
+ const Index alignedStart = internal::first_aligned(mat);
+ enum {
+ alignment = bool(Derived::Flags & DirectAccessBit) || bool(Derived::Flags & AlignedBit)
+ ? Aligned : Unaligned
+ };
+ const Index alignedSize2 = ((size-alignedStart)/(2*packetSize))*(2*packetSize);
+ const Index alignedSize = ((size-alignedStart)/(packetSize))*(packetSize);
+ const Index alignedEnd2 = alignedStart + alignedSize2;
+ const Index alignedEnd = alignedStart + alignedSize;
+ Scalar res;
+ if(alignedSize)
+ {
+ PacketScalar packet_res0 = mat.template packet<alignment>(alignedStart);
+ if(alignedSize>packetSize) // we have at least two packets to partly unroll the loop
+ {
+ PacketScalar packet_res1 = mat.template packet<alignment>(alignedStart+packetSize);
+ for(Index index = alignedStart + 2*packetSize; index < alignedEnd2; index += 2*packetSize)
+ {
+ packet_res0 = func.packetOp(packet_res0, mat.template packet<alignment>(index));
+ packet_res1 = func.packetOp(packet_res1, mat.template packet<alignment>(index+packetSize));
+ }
+
+ packet_res0 = func.packetOp(packet_res0,packet_res1);
+ if(alignedEnd>alignedEnd2)
+ packet_res0 = func.packetOp(packet_res0, mat.template packet<alignment>(alignedEnd2));
+ }
+ res = func.predux(packet_res0);
+
+ for(Index index = 0; index < alignedStart; ++index)
+ res = func(res,mat.coeff(index));
+
+ for(Index index = alignedEnd; index < size; ++index)
+ res = func(res,mat.coeff(index));
+ }
+ else // too small to vectorize anything.
+ // since this is dynamic-size hence inefficient anyway for such small sizes, don't try to optimize.
+ {
+ res = mat.coeff(0);
+ for(Index index = 1; index < size; ++index)
+ res = func(res,mat.coeff(index));
+ }
+
+ return res;
+ }
+};
+
+template<typename Func, typename Derived>
+struct redux_impl<Func, Derived, SliceVectorizedTraversal, NoUnrolling>
+{
+ typedef typename Derived::Scalar Scalar;
+ typedef typename packet_traits<Scalar>::type PacketScalar;
+ typedef typename Derived::Index Index;
+
+ 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<Scalar>::size
+ };
+ const Index packetedInnerSize = ((innerSize)/packetSize)*packetSize;
+ Scalar res;
+ if(packetedInnerSize)
+ {
+ PacketScalar packet_res = mat.template packet<Unaligned>(0,0);
+ for(Index j=0; j<outerSize; ++j)
+ for(Index i=(j==0?packetSize:0); i<packetedInnerSize; i+=Index(packetSize))
+ packet_res = func.packetOp(packet_res, mat.template packetByOuterInner<Unaligned>(j,i));
+
+ res = func.predux(packet_res);
+ for(Index j=0; j<outerSize; ++j)
+ for(Index i=packetedInnerSize; i<innerSize; ++i)
+ res = func(res, mat.coeffByOuterInner(j,i));
+ }
+ else // too small to vectorize anything.
+ // since this is dynamic-size hence inefficient anyway for such small sizes, don't try to optimize.
+ {
+ res = redux_impl<Func, Derived, DefaultTraversal, NoUnrolling>::run(mat, func);
+ }
+
+ return res;
+ }
+};
+
+template<typename Func, typename Derived>
+struct redux_impl<Func, Derived, LinearVectorizedTraversal, CompleteUnrolling>
+{
+ typedef typename Derived::Scalar Scalar;
+ typedef typename packet_traits<Scalar>::type PacketScalar;
+ enum {
+ PacketSize = packet_traits<Scalar>::size,
+ Size = Derived::SizeAtCompileTime,
+ VectorizedSize = (Size / PacketSize) * PacketSize
+ };
+ 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<Func, Derived, 0, Size / PacketSize>::run(mat,func));
+ if (VectorizedSize != Size)
+ res = func(res,redux_novec_unroller<Func, Derived, VectorizedSize, Size-VectorizedSize>::run(mat,func));
+ return res;
+ }
+};
+
+} // end namespace internal
+
+/***************************************************************************
+* Part 4 : public API
+***************************************************************************/
+
+
+/** \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.
+ *
+ * \sa DenseBase::sum(), DenseBase::minCoeff(), DenseBase::maxCoeff(), MatrixBase::colwise(), MatrixBase::rowwise()
+ */
+template<typename Derived>
+template<typename Func>
+EIGEN_STRONG_INLINE typename internal::result_of<Func(typename internal::traits<Derived>::Scalar)>::type
+DenseBase<Derived>::redux(const Func& func) const
+{
+ typedef typename internal::remove_all<typename Derived::Nested>::type ThisNested;
+ return internal::redux_impl<Func, ThisNested>
+ ::run(derived(), func);
+}
+
+/** \returns the minimum of all coefficients of *this
+ */
+template<typename Derived>
+EIGEN_STRONG_INLINE typename internal::traits<Derived>::Scalar
+DenseBase<Derived>::minCoeff() const
+{
+ return this->redux(Eigen::internal::scalar_min_op<Scalar>());
+}
+
+/** \returns the maximum of all coefficients of *this
+ */
+template<typename Derived>
+EIGEN_STRONG_INLINE typename internal::traits<Derived>::Scalar
+DenseBase<Derived>::maxCoeff() const
+{
+ return this->redux(Eigen::internal::scalar_max_op<Scalar>());
+}
+
+/** \returns the sum of all coefficients of *this
+ *
+ * \sa trace(), prod(), mean()
+ */
+template<typename Derived>
+EIGEN_STRONG_INLINE typename internal::traits<Derived>::Scalar
+DenseBase<Derived>::sum() const
+{
+ if(SizeAtCompileTime==0 || (SizeAtCompileTime==Dynamic && size()==0))
+ return Scalar(0);
+ return this->redux(Eigen::internal::scalar_sum_op<Scalar>());
+}
+
+/** \returns the mean of all coefficients of *this
+*
+* \sa trace(), prod(), sum()
+*/
+template<typename Derived>
+EIGEN_STRONG_INLINE typename internal::traits<Derived>::Scalar
+DenseBase<Derived>::mean() const
+{
+ return Scalar(this->redux(Eigen::internal::scalar_sum_op<Scalar>())) / Scalar(this->size());
+}
+
+/** \returns the product of all coefficients of *this
+ *
+ * Example: \include MatrixBase_prod.cpp
+ * Output: \verbinclude MatrixBase_prod.out
+ *
+ * \sa sum(), mean(), trace()
+ */
+template<typename Derived>
+EIGEN_STRONG_INLINE typename internal::traits<Derived>::Scalar
+DenseBase<Derived>::prod() const
+{
+ if(SizeAtCompileTime==0 || (SizeAtCompileTime==Dynamic && size()==0))
+ return Scalar(1);
+ return this->redux(Eigen::internal::scalar_product_op<Scalar>());
+}
+
+/** \returns the trace of \c *this, i.e. the sum of the coefficients on the main diagonal.
+ *
+ * \c *this can be any matrix, not necessarily square.
+ *
+ * \sa diagonal(), sum()
+ */
+template<typename Derived>
+EIGEN_STRONG_INLINE typename internal::traits<Derived>::Scalar
+MatrixBase<Derived>::trace() const
+{
+ return derived().diagonal().sum();
+}
+
+} // end namespace Eigen
+
+#endif // EIGEN_REDUX_H
diff --git a/Eigen/src/Core/Replicate.h b/Eigen/src/Core/Replicate.h
new file mode 100644
index 000000000..b61fdc29e
--- /dev/null
+++ b/Eigen/src/Core/Replicate.h
@@ -0,0 +1,177 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra.
+//
+// Copyright (C) 2009-2010 Gael Guennebaud <gael.guennebaud@inria.fr>
+//
+// This Source Code Form is subject to the terms of the Mozilla
+// Public License v. 2.0. If a copy of the MPL was not distributed
+// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+#ifndef EIGEN_REPLICATE_H
+#define EIGEN_REPLICATE_H
+
+namespace Eigen {
+
+/**
+ * \class Replicate
+ * \ingroup Core_Module
+ *
+ * \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<typename MatrixType,int RowFactor,int ColFactor>
+struct traits<Replicate<MatrixType,RowFactor,ColFactor> >
+ : traits<MatrixType>
+{
+ typedef typename MatrixType::Scalar Scalar;
+ typedef typename traits<MatrixType>::StorageKind StorageKind;
+ typedef typename traits<MatrixType>::XprKind XprKind;
+ enum {
+ Factor = (RowFactor==Dynamic || ColFactor==Dynamic) ? Dynamic : RowFactor*ColFactor
+ };
+ typedef typename nested<MatrixType,Factor>::type MatrixTypeNested;
+ typedef typename remove_reference<MatrixTypeNested>::type _MatrixTypeNested;
+ enum {
+ RowsAtCompileTime = RowFactor==Dynamic || int(MatrixType::RowsAtCompileTime)==Dynamic
+ ? Dynamic
+ : RowFactor * MatrixType::RowsAtCompileTime,
+ ColsAtCompileTime = ColFactor==Dynamic || int(MatrixType::ColsAtCompileTime)==Dynamic
+ ? Dynamic
+ : ColFactor * MatrixType::ColsAtCompileTime,
+ //FIXME we don't propagate the max sizes !!!
+ MaxRowsAtCompileTime = RowsAtCompileTime,
+ MaxColsAtCompileTime = ColsAtCompileTime,
+ 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
+ };
+};
+}
+
+template<typename MatrixType,int RowFactor,int ColFactor> class Replicate
+ : public internal::dense_xpr_base< Replicate<MatrixType,RowFactor,ColFactor> >::type
+{
+ typedef typename internal::traits<Replicate>::MatrixTypeNested MatrixTypeNested;
+ typedef typename internal::traits<Replicate>::_MatrixTypeNested _MatrixTypeNested;
+ public:
+
+ typedef typename internal::dense_xpr_base<Replicate>::type Base;
+ EIGEN_DENSE_PUBLIC_INTERFACE(Replicate)
+
+ template<typename OriginalMatrixType>
+ inline explicit Replicate(const OriginalMatrixType& matrix)
+ : m_matrix(matrix), m_rowFactor(RowFactor), m_colFactor(ColFactor)
+ {
+ EIGEN_STATIC_ASSERT((internal::is_same<typename internal::remove_const<MatrixType>::type,OriginalMatrixType>::value),
+ THE_MATRIX_OR_EXPRESSION_THAT_YOU_PASSED_DOES_NOT_HAVE_THE_EXPECTED_TYPE)
+ eigen_assert(RowFactor!=Dynamic && ColFactor!=Dynamic);
+ }
+
+ template<typename OriginalMatrixType>
+ inline Replicate(const OriginalMatrixType& matrix, Index rowFactor, Index colFactor)
+ : m_matrix(matrix), m_rowFactor(rowFactor), m_colFactor(colFactor)
+ {
+ EIGEN_STATIC_ASSERT((internal::is_same<typename internal::remove_const<MatrixType>::type,OriginalMatrixType>::value),
+ THE_MATRIX_OR_EXPRESSION_THAT_YOU_PASSED_DOES_NOT_HAVE_THE_EXPECTED_TYPE)
+ }
+
+ inline Index rows() const { return m_matrix.rows() * m_rowFactor.value(); }
+ inline Index cols() const { return m_matrix.cols() * m_colFactor.value(); }
+
+ inline Scalar coeff(Index row, Index col) const
+ {
+ // try to avoid using modulo; this is a pure optimization strategy
+ const Index actual_row = internal::traits<MatrixType>::RowsAtCompileTime==1 ? 0
+ : RowFactor==1 ? row
+ : row%m_matrix.rows();
+ const Index actual_col = internal::traits<MatrixType>::ColsAtCompileTime==1 ? 0
+ : ColFactor==1 ? col
+ : col%m_matrix.cols();
+
+ return m_matrix.coeff(actual_row, actual_col);
+ }
+ template<int LoadMode>
+ inline PacketScalar packet(Index row, Index col) const
+ {
+ const Index actual_row = internal::traits<MatrixType>::RowsAtCompileTime==1 ? 0
+ : RowFactor==1 ? row
+ : row%m_matrix.rows();
+ const Index actual_col = internal::traits<MatrixType>::ColsAtCompileTime==1 ? 0
+ : ColFactor==1 ? col
+ : col%m_matrix.cols();
+
+ return m_matrix.template packet<LoadMode>(actual_row, actual_col);
+ }
+
+ const _MatrixTypeNested& nestedExpression() const
+ {
+ return m_matrix;
+ }
+
+ protected:
+ MatrixTypeNested m_matrix;
+ const internal::variable_if_dynamic<Index, RowFactor> m_rowFactor;
+ const internal::variable_if_dynamic<Index, ColFactor> m_colFactor;
+};
+
+/**
+ * \return an expression of the replication of \c *this
+ *
+ * Example: \include MatrixBase_replicate.cpp
+ * Output: \verbinclude MatrixBase_replicate.out
+ *
+ * \sa VectorwiseOp::replicate(), DenseBase::replicate(Index,Index), class Replicate
+ */
+template<typename Derived>
+template<int RowFactor, int ColFactor>
+inline const Replicate<Derived,RowFactor,ColFactor>
+DenseBase<Derived>::replicate() const
+{
+ return Replicate<Derived,RowFactor,ColFactor>(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<int,int>(), class Replicate
+ */
+template<typename Derived>
+inline const Replicate<Derived,Dynamic,Dynamic>
+DenseBase<Derived>::replicate(Index rowFactor,Index colFactor) const
+{
+ return Replicate<Derived,Dynamic,Dynamic>(derived(),rowFactor,colFactor);
+}
+
+/**
+ * \return an expression of the replication of each column (or row) of \c *this
+ *
+ * Example: \include DirectionWise_replicate_int.cpp
+ * Output: \verbinclude DirectionWise_replicate_int.out
+ *
+ * \sa VectorwiseOp::replicate(), DenseBase::replicate(), class Replicate
+ */
+template<typename ExpressionType, int Direction>
+const typename VectorwiseOp<ExpressionType,Direction>::ReplicateReturnType
+VectorwiseOp<ExpressionType,Direction>::replicate(Index factor) const
+{
+ return typename VectorwiseOp<ExpressionType,Direction>::ReplicateReturnType
+ (_expression(),Direction==Vertical?factor:1,Direction==Horizontal?factor:1);
+}
+
+} // end namespace Eigen
+
+#endif // EIGEN_REPLICATE_H
diff --git a/Eigen/src/Core/ReturnByValue.h b/Eigen/src/Core/ReturnByValue.h
new file mode 100644
index 000000000..613912ffa
--- /dev/null
+++ b/Eigen/src/Core/ReturnByValue.h
@@ -0,0 +1,88 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra.
+//
+// Copyright (C) 2009-2010 Gael Guennebaud <gael.guennebaud@inria.fr>
+// Copyright (C) 2009-2010 Benoit Jacob <jacob.benoit.1@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 EIGEN_RETURNBYVALUE_H
+#define EIGEN_RETURNBYVALUE_H
+
+namespace Eigen {
+
+/** \class ReturnByValue
+ * \ingroup Core_Module
+ *
+ */
+
+namespace internal {
+
+template<typename Derived>
+struct traits<ReturnByValue<Derived> >
+ : public traits<typename traits<Derived>::ReturnType>
+{
+ enum {
+ // We're disabling the DirectAccess because e.g. the constructor of
+ // the Block-with-DirectAccess expression requires to have a coeffRef method.
+ // Also, we don't want to have to implement the stride stuff.
+ Flags = (traits<typename traits<Derived>::ReturnType>::Flags
+ | EvalBeforeNestingBit) & ~DirectAccessBit
+ };
+};
+
+/* The ReturnByValue object doesn't even have a coeff() method.
+ * So the only way that nesting it in an expression can work, is by evaluating it into a plain matrix.
+ * 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 ??
+ */
+template<typename Derived,int n,typename PlainObject>
+struct nested<ReturnByValue<Derived>, n, PlainObject>
+{
+ typedef typename traits<Derived>::ReturnType type;
+};
+
+} // end namespace internal
+
+template<typename Derived> class ReturnByValue
+ : public internal::dense_xpr_base< ReturnByValue<Derived> >::type
+{
+ public:
+ typedef typename internal::traits<Derived>::ReturnType ReturnType;
+
+ typedef typename internal::dense_xpr_base<ReturnByValue>::type Base;
+ EIGEN_DENSE_PUBLIC_INTERFACE(ReturnByValue)
+
+ template<typename Dest>
+ inline void evalTo(Dest& dst) const
+ { static_cast<const Derived*>(this)->evalTo(dst); }
+ inline Index rows() const { return static_cast<const Derived*>(this)->rows(); }
+ inline Index cols() const { return static_cast<const Derived*>(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
+ class Unusable{
+ Unusable(const Unusable&) {}
+ Unusable& operator=(const Unusable&) {return *this;}
+ };
+ const Unusable& coeff(Index) const { return *reinterpret_cast<const Unusable*>(this); }
+ const Unusable& coeff(Index,Index) const { return *reinterpret_cast<const Unusable*>(this); }
+ Unusable& coeffRef(Index) { return *reinterpret_cast<Unusable*>(this); }
+ Unusable& coeffRef(Index,Index) { return *reinterpret_cast<Unusable*>(this); }
+#endif
+};
+
+template<typename Derived>
+template<typename OtherDerived>
+Derived& DenseBase<Derived>::operator=(const ReturnByValue<OtherDerived>& other)
+{
+ other.evalTo(derived());
+ return derived();
+}
+
+} // end namespace Eigen
+
+#endif // EIGEN_RETURNBYVALUE_H
diff --git a/Eigen/src/Core/Reverse.h b/Eigen/src/Core/Reverse.h
new file mode 100644
index 000000000..e30ae3d28
--- /dev/null
+++ b/Eigen/src/Core/Reverse.h
@@ -0,0 +1,224 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra.
+//
+// Copyright (C) 2006-2008 Benoit Jacob <jacob.benoit.1@gmail.com>
+// Copyright (C) 2009 Ricard Marxer <email@ricardmarxer.com>
+// Copyright (C) 2009-2010 Gael Guennebaud <gael.guennebaud@inria.fr>
+//
+// This Source Code Form is subject to the terms of the Mozilla
+// Public License v. 2.0. If 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<typename MatrixType, int Direction>
+struct traits<Reverse<MatrixType, Direction> >
+ : traits<MatrixType>
+{
+ typedef typename MatrixType::Scalar Scalar;
+ typedef typename traits<MatrixType>::StorageKind StorageKind;
+ typedef typename traits<MatrixType>::XprKind XprKind;
+ typedef typename nested<MatrixType>::type MatrixTypeNested;
+ typedef typename remove_reference<MatrixTypeNested>::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<typename PacketScalar, bool ReversePacket> struct reverse_packet_cond
+{
+ static inline PacketScalar run(const PacketScalar& x) { return preverse(x); }
+};
+
+template<typename PacketScalar> struct reverse_packet_cond<PacketScalar,false>
+{
+ static inline PacketScalar run(const PacketScalar& x) { return x; }
+};
+
+} // end namespace internal
+
+template<typename MatrixType, int Direction> class Reverse
+ : public internal::dense_xpr_base< Reverse<MatrixType, Direction> >::type
+{
+ public:
+
+ typedef typename internal::dense_xpr_base<Reverse>::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<Scalar>::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<PacketScalar,ReversePacket> 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<int LoadMode>
+ inline const PacketScalar packet(Index row, Index col) const
+ {
+ return reverse_packet::run(m_matrix.template packet<LoadMode>(
+ ReverseRow ? m_matrix.rows() - row - OffsetRow : row,
+ ReverseCol ? m_matrix.cols() - col - OffsetCol : col));
+ }
+
+ template<int LoadMode>
+ inline void writePacket(Index row, Index col, const PacketScalar& x)
+ {
+ m_matrix.const_cast_derived().template writePacket<LoadMode>(
+ ReverseRow ? m_matrix.rows() - row - OffsetRow : row,
+ ReverseCol ? m_matrix.cols() - col - OffsetCol : col,
+ reverse_packet::run(x));
+ }
+
+ template<int LoadMode>
+ inline const PacketScalar packet(Index index) const
+ {
+ return internal::preverse(m_matrix.template packet<LoadMode>( m_matrix.size() - index - PacketSize ));
+ }
+
+ template<int LoadMode>
+ inline void writePacket(Index index, const PacketScalar& x)
+ {
+ m_matrix.const_cast_derived().template writePacket<LoadMode>(m_matrix.size() - index - PacketSize, internal::preverse(x));
+ }
+
+ const typename internal::remove_all<typename MatrixType::Nested>::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<typename Derived>
+inline typename DenseBase<Derived>::ReverseReturnType
+DenseBase<Derived>::reverse()
+{
+ return derived();
+}
+
+/** This is the const version of reverse(). */
+template<typename Derived>
+inline const typename DenseBase<Derived>::ConstReverseReturnType
+DenseBase<Derived>::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<typename Derived>
+inline void DenseBase<Derived>::reverseInPlace()
+{
+ derived() = derived().reverse().eval();
+}
+
+} // end namespace Eigen
+
+#endif // EIGEN_REVERSE_H
diff --git a/Eigen/src/Core/Select.h b/Eigen/src/Core/Select.h
new file mode 100644
index 000000000..2bf6e91d0
--- /dev/null
+++ b/Eigen/src/Core/Select.h
@@ -0,0 +1,162 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra.
+//
+// Copyright (C) 2008-2010 Gael Guennebaud <gael.guennebaud@inria.fr>
+//
+// This Source Code Form is subject to the terms of the Mozilla
+// Public License v. 2.0. If a copy of the MPL was not distributed
+// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+#ifndef EIGEN_SELECT_H
+#define EIGEN_SELECT_H
+
+namespace Eigen {
+
+/** \class Select
+ * \ingroup Core_Module
+ *
+ * \brief Expression of a coefficient wise version of the C++ ternary operator ?:
+ *
+ * \param ConditionMatrixType the type of the \em condition expression which must be a boolean matrix
+ * \param ThenMatrixType the type of the \em then expression
+ * \param ElseMatrixType the type of the \em else expression
+ *
+ * This class represents an expression of a coefficient wise version of the C++ ternary operator ?:.
+ * It is the return type of DenseBase::select() and most of the time this is the only way it is used.
+ *
+ * \sa DenseBase::select(const DenseBase<ThenDerived>&, const DenseBase<ElseDerived>&) const
+ */
+
+namespace internal {
+template<typename ConditionMatrixType, typename ThenMatrixType, typename ElseMatrixType>
+struct traits<Select<ConditionMatrixType, ThenMatrixType, ElseMatrixType> >
+ : traits<ThenMatrixType>
+{
+ typedef typename traits<ThenMatrixType>::Scalar Scalar;
+ typedef Dense StorageKind;
+ typedef typename traits<ThenMatrixType>::XprKind XprKind;
+ typedef typename ConditionMatrixType::Nested ConditionMatrixNested;
+ typedef typename ThenMatrixType::Nested ThenMatrixNested;
+ typedef typename ElseMatrixType::Nested ElseMatrixNested;
+ enum {
+ RowsAtCompileTime = ConditionMatrixType::RowsAtCompileTime,
+ ColsAtCompileTime = ConditionMatrixType::ColsAtCompileTime,
+ MaxRowsAtCompileTime = ConditionMatrixType::MaxRowsAtCompileTime,
+ MaxColsAtCompileTime = ConditionMatrixType::MaxColsAtCompileTime,
+ Flags = (unsigned int)ThenMatrixType::Flags & ElseMatrixType::Flags & HereditaryBits,
+ CoeffReadCost = traits<typename remove_all<ConditionMatrixNested>::type>::CoeffReadCost
+ + EIGEN_SIZE_MAX(traits<typename remove_all<ThenMatrixNested>::type>::CoeffReadCost,
+ traits<typename remove_all<ElseMatrixNested>::type>::CoeffReadCost)
+ };
+};
+}
+
+template<typename ConditionMatrixType, typename ThenMatrixType, typename ElseMatrixType>
+class Select : internal::no_assignment_operator,
+ public internal::dense_xpr_base< Select<ConditionMatrixType, ThenMatrixType, ElseMatrixType> >::type
+{
+ public:
+
+ typedef typename internal::dense_xpr_base<Select>::type Base;
+ EIGEN_DENSE_PUBLIC_INTERFACE(Select)
+
+ Select(const ConditionMatrixType& conditionMatrix,
+ const ThenMatrixType& thenMatrix,
+ const ElseMatrixType& elseMatrix)
+ : m_condition(conditionMatrix), m_then(thenMatrix), m_else(elseMatrix)
+ {
+ eigen_assert(m_condition.rows() == m_then.rows() && m_condition.rows() == m_else.rows());
+ eigen_assert(m_condition.cols() == m_then.cols() && m_condition.cols() == m_else.cols());
+ }
+
+ Index rows() const { return m_condition.rows(); }
+ Index cols() const { return m_condition.cols(); }
+
+ const Scalar coeff(Index i, Index j) const
+ {
+ if (m_condition.coeff(i,j))
+ return m_then.coeff(i,j);
+ else
+ return m_else.coeff(i,j);
+ }
+
+ const Scalar coeff(Index i) const
+ {
+ if (m_condition.coeff(i))
+ return m_then.coeff(i);
+ else
+ return m_else.coeff(i);
+ }
+
+ const ConditionMatrixType& conditionMatrix() const
+ {
+ return m_condition;
+ }
+
+ const ThenMatrixType& thenMatrix() const
+ {
+ return m_then;
+ }
+
+ const ElseMatrixType& elseMatrix() const
+ {
+ return m_else;
+ }
+
+ protected:
+ typename ConditionMatrixType::Nested m_condition;
+ typename ThenMatrixType::Nested m_then;
+ typename ElseMatrixType::Nested m_else;
+};
+
+
+/** \returns a matrix where each coefficient (i,j) is equal to \a thenMatrix(i,j)
+ * if \c *this(i,j), and \a elseMatrix(i,j) otherwise.
+ *
+ * Example: \include MatrixBase_select.cpp
+ * Output: \verbinclude MatrixBase_select.out
+ *
+ * \sa class Select
+ */
+template<typename Derived>
+template<typename ThenDerived,typename ElseDerived>
+inline const Select<Derived,ThenDerived,ElseDerived>
+DenseBase<Derived>::select(const DenseBase<ThenDerived>& thenMatrix,
+ const DenseBase<ElseDerived>& elseMatrix) const
+{
+ return Select<Derived,ThenDerived,ElseDerived>(derived(), thenMatrix.derived(), elseMatrix.derived());
+}
+
+/** Version of DenseBase::select(const DenseBase&, const DenseBase&) with
+ * the \em else expression being a scalar value.
+ *
+ * \sa DenseBase::select(const DenseBase<ThenDerived>&, const DenseBase<ElseDerived>&) const, class Select
+ */
+template<typename Derived>
+template<typename ThenDerived>
+inline const Select<Derived,ThenDerived, typename ThenDerived::ConstantReturnType>
+DenseBase<Derived>::select(const DenseBase<ThenDerived>& thenMatrix,
+ typename ThenDerived::Scalar elseScalar) const
+{
+ return Select<Derived,ThenDerived,typename ThenDerived::ConstantReturnType>(
+ derived(), thenMatrix.derived(), ThenDerived::Constant(rows(),cols(),elseScalar));
+}
+
+/** Version of DenseBase::select(const DenseBase&, const DenseBase&) with
+ * the \em then expression being a scalar value.
+ *
+ * \sa DenseBase::select(const DenseBase<ThenDerived>&, const DenseBase<ElseDerived>&) const, class Select
+ */
+template<typename Derived>
+template<typename ElseDerived>
+inline const Select<Derived, typename ElseDerived::ConstantReturnType, ElseDerived >
+DenseBase<Derived>::select(typename ElseDerived::Scalar thenScalar,
+ const DenseBase<ElseDerived>& elseMatrix) const
+{
+ return Select<Derived,typename ElseDerived::ConstantReturnType,ElseDerived>(
+ derived(), ElseDerived::Constant(rows(),cols(),thenScalar), elseMatrix.derived());
+}
+
+} // end namespace Eigen
+
+#endif // EIGEN_SELECT_H
diff --git a/Eigen/src/Core/SelfAdjointView.h b/Eigen/src/Core/SelfAdjointView.h
new file mode 100644
index 000000000..82cc4da73
--- /dev/null
+++ b/Eigen/src/Core/SelfAdjointView.h
@@ -0,0 +1,314 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra.
+//
+// Copyright (C) 2009 Gael Guennebaud <gael.guennebaud@inria.fr>
+//
+// This Source Code Form is subject to the terms of the Mozilla
+// Public License v. 2.0. If 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<typename MatrixType, unsigned int UpLo>
+struct traits<SelfAdjointView<MatrixType, UpLo> > : traits<MatrixType>
+{
+ typedef typename nested<MatrixType>::type MatrixTypeNested;
+ typedef typename remove_all<MatrixTypeNested>::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 <typename Lhs, int LhsMode, bool LhsIsVector,
+ typename Rhs, int RhsMode, bool RhsIsVector>
+struct SelfadjointProductMatrix;
+
+// FIXME could also be called SelfAdjointWrapper to be consistent with DiagonalWrapper ??
+template<typename MatrixType, unsigned int UpLo> class SelfAdjointView
+ : public TriangularBase<SelfAdjointView<MatrixType, UpLo> >
+{
+ public:
+
+ typedef TriangularBase<SelfAdjointView> Base;
+ typedef typename internal::traits<SelfAdjointView>::MatrixTypeNested MatrixTypeNested;
+ typedef typename internal::traits<SelfAdjointView>::MatrixTypeNestedCleaned MatrixTypeNestedCleaned;
+
+ /** \brief The type of coefficients in this matrix */
+ typedef typename internal::traits<SelfAdjointView>::Scalar Scalar;
+
+ typedef typename MatrixType::Index Index;
+
+ enum {
+ Mode = internal::traits<SelfAdjointView>::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<MatrixTypeNestedCleaned*>(&m_matrix); }
+
+ /** Efficient self-adjoint matrix times vector/matrix product */
+ template<typename OtherDerived>
+ SelfadjointProductMatrix<MatrixType,Mode,false,OtherDerived,0,OtherDerived::IsVectorAtCompileTime>
+ operator*(const MatrixBase<OtherDerived>& rhs) const
+ {
+ return SelfadjointProductMatrix
+ <MatrixType,Mode,false,OtherDerived,0,OtherDerived::IsVectorAtCompileTime>
+ (m_matrix, rhs.derived());
+ }
+
+ /** Efficient vector/matrix times self-adjoint matrix product */
+ template<typename OtherDerived> friend
+ SelfadjointProductMatrix<OtherDerived,0,OtherDerived::IsVectorAtCompileTime,MatrixType,Mode,false>
+ operator*(const MatrixBase<OtherDerived>& lhs, const SelfAdjointView& rhs)
+ {
+ return SelfadjointProductMatrix
+ <OtherDerived,0,OtherDerived::IsVectorAtCompileTime,MatrixType,Mode,false>
+ (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<DerivedU>&, Scalar)
+ */
+ template<typename DerivedU, typename DerivedV>
+ SelfAdjointView& rankUpdate(const MatrixBase<DerivedU>& u, const MatrixBase<DerivedV>& v, 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<DerivedU>&, const MatrixBase<DerivedV>&, Scalar)
+ */
+ template<typename DerivedU>
+ SelfAdjointView& rankUpdate(const MatrixBase<DerivedU>& u, Scalar alpha = Scalar(1));
+
+/////////// Cholesky module ///////////
+
+ const LLT<PlainObject, UpLo> llt() const;
+ const LDLT<PlainObject, UpLo> ldlt() const;
+
+/////////// Eigenvalue module ///////////
+
+ /** Real part of #Scalar */
+ typedef typename NumTraits<Scalar>::Real RealScalar;
+ /** Return type of eigenvalues() */
+ typedef Matrix<RealScalar, internal::traits<MatrixType>::ColsAtCompileTime, 1> EigenvaluesReturnType;
+
+ EigenvaluesReturnType eigenvalues() const;
+ RealScalar operatorNorm() const;
+
+ #ifdef EIGEN2_SUPPORT
+ template<typename OtherDerived>
+ SelfAdjointView& operator=(const MatrixBase<OtherDerived>& other)
+ {
+ enum {
+ OtherPart = UpLo == Upper ? StrictlyLower : StrictlyUpper
+ };
+ m_matrix.const_cast_derived().template triangularView<UpLo>() = other;
+ m_matrix.const_cast_derived().template triangularView<OtherPart>() = other.adjoint();
+ return *this;
+ }
+ template<typename OtherMatrixType, unsigned int OtherMode>
+ SelfAdjointView& operator=(const TriangularView<OtherMatrixType, OtherMode>& other)
+ {
+ enum {
+ OtherPart = UpLo == Upper ? StrictlyLower : StrictlyUpper
+ };
+ m_matrix.const_cast_derived().template triangularView<UpLo>() = other.toDenseMatrix();
+ m_matrix.const_cast_derived().template triangularView<OtherPart>() = other.toDenseMatrix().adjoint();
+ return *this;
+ }
+ #endif
+
+ protected:
+ MatrixTypeNested m_matrix;
+};
+
+
+// template<typename OtherDerived, typename MatrixType, unsigned int UpLo>
+// internal::selfadjoint_matrix_product_returntype<OtherDerived,SelfAdjointView<MatrixType,UpLo> >
+// operator*(const MatrixBase<OtherDerived>& lhs, const SelfAdjointView<MatrixType,UpLo>& rhs)
+// {
+// return internal::matrix_selfadjoint_product_returntype<OtherDerived,SelfAdjointView<MatrixType,UpLo> >(lhs.derived(),rhs);
+// }
+
+// selfadjoint to dense matrix
+
+namespace internal {
+
+template<typename Derived1, typename Derived2, int UnrollCount, bool ClearOpposite>
+struct triangular_assignment_selector<Derived1, Derived2, (SelfAdjoint|Upper), UnrollCount, ClearOpposite>
+{
+ enum {
+ col = (UnrollCount-1) / Derived1::RowsAtCompileTime,
+ row = (UnrollCount-1) % Derived1::RowsAtCompileTime
+ };
+
+ static inline void run(Derived1 &dst, const Derived2 &src)
+ {
+ triangular_assignment_selector<Derived1, Derived2, (SelfAdjoint|Upper), UnrollCount-1, ClearOpposite>::run(dst, src);
+
+ if(row == col)
+ dst.coeffRef(row, col) = real(src.coeff(row, col));
+ else if(row < col)
+ dst.coeffRef(col, row) = conj(dst.coeffRef(row, col) = src.coeff(row, col));
+ }
+};
+
+template<typename Derived1, typename Derived2, bool ClearOpposite>
+struct triangular_assignment_selector<Derived1, Derived2, SelfAdjoint|Upper, 0, ClearOpposite>
+{
+ static inline void run(Derived1 &, const Derived2 &) {}
+};
+
+template<typename Derived1, typename Derived2, int UnrollCount, bool ClearOpposite>
+struct triangular_assignment_selector<Derived1, Derived2, (SelfAdjoint|Lower), UnrollCount, ClearOpposite>
+{
+ enum {
+ col = (UnrollCount-1) / Derived1::RowsAtCompileTime,
+ row = (UnrollCount-1) % Derived1::RowsAtCompileTime
+ };
+
+ static inline void run(Derived1 &dst, const Derived2 &src)
+ {
+ triangular_assignment_selector<Derived1, Derived2, (SelfAdjoint|Lower), UnrollCount-1, ClearOpposite>::run(dst, src);
+
+ if(row == col)
+ dst.coeffRef(row, col) = real(src.coeff(row, col));
+ else if(row > col)
+ dst.coeffRef(col, row) = conj(dst.coeffRef(row, col) = src.coeff(row, col));
+ }
+};
+
+template<typename Derived1, typename Derived2, bool ClearOpposite>
+struct triangular_assignment_selector<Derived1, Derived2, SelfAdjoint|Lower, 0, ClearOpposite>
+{
+ static inline void run(Derived1 &, const Derived2 &) {}
+};
+
+template<typename Derived1, typename Derived2, bool ClearOpposite>
+struct triangular_assignment_selector<Derived1, Derived2, SelfAdjoint|Upper, Dynamic, ClearOpposite>
+{
+ 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) = conj(dst.coeff(i,j));
+ }
+ dst.copyCoeff(j, j, src);
+ }
+ }
+};
+
+template<typename Derived1, typename Derived2, bool ClearOpposite>
+struct triangular_assignment_selector<Derived1, Derived2, SelfAdjoint|Lower, Dynamic, ClearOpposite>
+{
+ 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) = conj(dst.coeff(i,j));
+ }
+ dst.copyCoeff(i, i, src);
+ }
+ }
+};
+
+} // end namespace internal
+
+/***************************************************************************
+* Implementation of MatrixBase methods
+***************************************************************************/
+
+template<typename Derived>
+template<unsigned int UpLo>
+typename MatrixBase<Derived>::template ConstSelfAdjointViewReturnType<UpLo>::Type
+MatrixBase<Derived>::selfadjointView() const
+{
+ return derived();
+}
+
+template<typename Derived>
+template<unsigned int UpLo>
+typename MatrixBase<Derived>::template SelfAdjointViewReturnType<UpLo>::Type
+MatrixBase<Derived>::selfadjointView()
+{
+ return derived();
+}
+
+} // end namespace Eigen
+
+#endif // EIGEN_SELFADJOINTMATRIX_H
diff --git a/Eigen/src/Core/SelfCwiseBinaryOp.h b/Eigen/src/Core/SelfCwiseBinaryOp.h
new file mode 100644
index 000000000..0caf2bab1
--- /dev/null
+++ b/Eigen/src/Core/SelfCwiseBinaryOp.h
@@ -0,0 +1,194 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra.
+//
+// Copyright (C) 2009-2010 Gael Guennebaud <gael.guennebaud@inria.fr>
+//
+// This Source Code Form is subject to the terms of the Mozilla
+// Public License v. 2.0. If 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<typename BinaryOp, typename Lhs, typename Rhs>
+struct traits<SelfCwiseBinaryOp<BinaryOp,Lhs,Rhs> >
+ : traits<CwiseBinaryOp<BinaryOp,Lhs,Rhs> >
+{
+ enum {
+ // Note that it is still a good idea to preserve the DirectAccessBit
+ // so that assign can correctly align the data.
+ Flags = traits<CwiseBinaryOp<BinaryOp,Lhs,Rhs> >::Flags | (Lhs::Flags&DirectAccessBit) | (Lhs::Flags&LvalueBit),
+ OuterStrideAtCompileTime = Lhs::OuterStrideAtCompileTime,
+ InnerStrideAtCompileTime = Lhs::InnerStrideAtCompileTime
+ };
+};
+}
+
+template<typename BinaryOp, typename Lhs, typename Rhs> class SelfCwiseBinaryOp
+ : public internal::dense_xpr_base< SelfCwiseBinaryOp<BinaryOp, Lhs, Rhs> >::type
+{
+ public:
+
+ typedef typename internal::dense_xpr_base<SelfCwiseBinaryOp>::type Base;
+ EIGEN_DENSE_PUBLIC_INTERFACE(SelfCwiseBinaryOp)
+
+ typedef typename internal::packet_traits<Scalar>::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<typename OtherDerived>
+ void copyCoeff(Index row, Index col, const DenseBase<OtherDerived>& 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<typename OtherDerived>
+ void copyCoeff(Index index, const DenseBase<OtherDerived>& 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<typename OtherDerived, int StoreMode, int LoadMode>
+ void copyPacket(Index row, Index col, const DenseBase<OtherDerived>& other)
+ {
+ OtherDerived& _other = other.const_cast_derived();
+ eigen_internal_assert(row >= 0 && row < rows()
+ && col >= 0 && col < cols());
+ m_matrix.template writePacket<StoreMode>(row, col,
+ m_functor.packetOp(m_matrix.template packet<StoreMode>(row, col),_other.template packet<LoadMode>(row, col)) );
+ }
+
+ template<typename OtherDerived, int StoreMode, int LoadMode>
+ void copyPacket(Index index, const DenseBase<OtherDerived>& other)
+ {
+ OtherDerived& _other = other.const_cast_derived();
+ eigen_internal_assert(index >= 0 && index < m_matrix.size());
+ m_matrix.template writePacket<StoreMode>(index,
+ m_functor.packetOp(m_matrix.template packet<StoreMode>(index),_other.template packet<LoadMode>(index)) );
+ }
+
+ // reimplement lazyAssign to handle complex *= real
+ // see CwiseBinaryOp ctor for details
+ template<typename RhsDerived>
+ EIGEN_STRONG_INLINE SelfCwiseBinaryOp& lazyAssign(const DenseBase<RhsDerived>& 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<SelfCwiseBinaryOp, RhsDerived>::debug();
+ #endif
+ eigen_assert(rows() == rhs.rows() && cols() == rhs.cols());
+ internal::assign_impl<SelfCwiseBinaryOp, RhsDerived>::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<Rhs>::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<typename Derived>
+inline Derived& DenseBase<Derived>::operator*=(const Scalar& other)
+{
+ typedef typename Derived::PlainObject PlainObject;
+ SelfCwiseBinaryOp<internal::scalar_product_op<Scalar>, Derived, typename PlainObject::ConstantReturnType> tmp(derived());
+ tmp = PlainObject::Constant(rows(),cols(),other);
+ return derived();
+}
+
+template<typename Derived>
+inline Derived& DenseBase<Derived>::operator/=(const Scalar& other)
+{
+ typedef typename internal::conditional<NumTraits<Scalar>::IsInteger,
+ internal::scalar_quotient_op<Scalar>,
+ internal::scalar_product_op<Scalar> >::type BinOp;
+ typedef typename Derived::PlainObject PlainObject;
+ SelfCwiseBinaryOp<BinOp, Derived, typename PlainObject::ConstantReturnType> tmp(derived());
+ tmp = PlainObject::Constant(rows(),cols(), NumTraits<Scalar>::IsInteger ? other : Scalar(1)/other);
+ return derived();
+}
+
+} // end namespace Eigen
+
+#endif // EIGEN_SELFCWISEBINARYOP_H
diff --git a/Eigen/src/Core/SolveTriangular.h b/Eigen/src/Core/SolveTriangular.h
new file mode 100644
index 000000000..ef17f288e
--- /dev/null
+++ b/Eigen/src/Core/SolveTriangular.h
@@ -0,0 +1,260 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra.
+//
+// Copyright (C) 2008-2009 Gael Guennebaud <gael.guennebaud@inria.fr>
+//
+// This Source Code Form is subject to the terms of the Mozilla
+// Public License v. 2.0. If a copy of the MPL was not distributed
+// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+#ifndef EIGEN_SOLVETRIANGULAR_H
+#define EIGEN_SOLVETRIANGULAR_H
+
+namespace Eigen {
+
+namespace internal {
+
+// Forward declarations:
+// The following two routines are implemented in the products/TriangularSolver*.h files
+template<typename LhsScalar, typename RhsScalar, typename Index, int Side, int Mode, bool Conjugate, int StorageOrder>
+struct triangular_solve_vector;
+
+template <typename Scalar, typename Index, int Side, int Mode, bool Conjugate, int TriStorageOrder, int OtherStorageOrder>
+struct triangular_solve_matrix;
+
+// small helper struct extracting some traits on the underlying solver operation
+template<typename Lhs, typename Rhs, int Side>
+class trsolve_traits
+{
+ private:
+ enum {
+ RhsIsVectorAtCompileTime = (Side==OnTheLeft ? Rhs::ColsAtCompileTime : Rhs::RowsAtCompileTime)==1
+ };
+ public:
+ enum {
+ Unrolling = (RhsIsVectorAtCompileTime && Rhs::SizeAtCompileTime != Dynamic && Rhs::SizeAtCompileTime <= 8)
+ ? CompleteUnrolling : NoUnrolling,
+ RhsVectors = RhsIsVectorAtCompileTime ? 1 : Dynamic
+ };
+};
+
+template<typename Lhs, typename Rhs,
+ int Side, // can be OnTheLeft/OnTheRight
+ int Mode, // can be Upper/Lower | UnitDiag
+ int Unrolling = trsolve_traits<Lhs,Rhs,Side>::Unrolling,
+ int RhsVectors = trsolve_traits<Lhs,Rhs,Side>::RhsVectors
+ >
+struct triangular_solver_selector;
+
+template<typename Lhs, typename Rhs, int Side, int Mode>
+struct triangular_solver_selector<Lhs,Rhs,Side,Mode,NoUnrolling,1>
+{
+ typedef typename Lhs::Scalar LhsScalar;
+ typedef typename Rhs::Scalar RhsScalar;
+ typedef blas_traits<Lhs> LhsProductTraits;
+ typedef typename LhsProductTraits::ExtractType ActualLhsType;
+ typedef Map<Matrix<RhsScalar,Dynamic,1>, Aligned> MappedRhs;
+ static void run(const Lhs& lhs, Rhs& rhs)
+ {
+ ActualLhsType actualLhs = LhsProductTraits::extract(lhs);
+
+ // FIXME find a way to allow an inner stride if packet_traits<Scalar>::size==1
+
+ bool useRhsDirectly = Rhs::InnerStrideAtCompileTime==1 || rhs.innerStride()==1;
+
+ ei_declare_aligned_stack_constructed_variable(RhsScalar,actualRhs,rhs.size(),
+ (useRhsDirectly ? rhs.data() : 0));
+
+ if(!useRhsDirectly)
+ MappedRhs(actualRhs,rhs.size()) = rhs;
+
+ triangular_solve_vector<LhsScalar, RhsScalar, typename Lhs::Index, Side, Mode, LhsProductTraits::NeedToConjugate,
+ (int(Lhs::Flags) & RowMajorBit) ? RowMajor : ColMajor>
+ ::run(actualLhs.cols(), actualLhs.data(), actualLhs.outerStride(), actualRhs);
+
+ if(!useRhsDirectly)
+ rhs = MappedRhs(actualRhs, rhs.size());
+ }
+};
+
+// the rhs is a matrix
+template<typename Lhs, typename Rhs, int Side, int Mode>
+struct triangular_solver_selector<Lhs,Rhs,Side,Mode,NoUnrolling,Dynamic>
+{
+ typedef typename Rhs::Scalar Scalar;
+ typedef typename Rhs::Index Index;
+ typedef blas_traits<Lhs> LhsProductTraits;
+ typedef typename LhsProductTraits::DirectLinearAccessType ActualLhsType;
+
+ static void run(const Lhs& lhs, Rhs& rhs)
+ {
+ typename internal::add_const_on_value_type<ActualLhsType>::type actualLhs = LhsProductTraits::extract(lhs);
+
+ const Index size = lhs.rows();
+ const Index othersize = Side==OnTheLeft? rhs.cols() : rhs.rows();
+
+ typedef internal::gemm_blocking_space<(Rhs::Flags&RowMajorBit) ? RowMajor : ColMajor,Scalar,Scalar,
+ Rhs::MaxRowsAtCompileTime, Rhs::MaxColsAtCompileTime, Lhs::MaxRowsAtCompileTime,4> BlockingType;
+
+ BlockingType blocking(rhs.rows(), rhs.cols(), size);
+
+ triangular_solve_matrix<Scalar,Index,Side,Mode,LhsProductTraits::NeedToConjugate,(int(Lhs::Flags) & RowMajorBit) ? RowMajor : ColMajor,
+ (Rhs::Flags&RowMajorBit) ? RowMajor : ColMajor>
+ ::run(size, othersize, &actualLhs.coeffRef(0,0), actualLhs.outerStride(), &rhs.coeffRef(0,0), rhs.outerStride(), blocking);
+ }
+};
+
+/***************************************************************************
+* meta-unrolling implementation
+***************************************************************************/
+
+template<typename Lhs, typename Rhs, int Mode, int Index, int Size,
+ bool Stop = Index==Size>
+struct triangular_solver_unroller;
+
+template<typename Lhs, typename Rhs, int Mode, int Index, int Size>
+struct triangular_solver_unroller<Lhs,Rhs,Mode,Index,Size,false> {
+ enum {
+ IsLower = ((Mode&Lower)==Lower),
+ I = IsLower ? Index : Size - Index - 1,
+ S = IsLower ? 0 : I+1
+ };
+ static void run(const Lhs& lhs, Rhs& rhs)
+ {
+ if (Index>0)
+ rhs.coeffRef(I) -= lhs.row(I).template segment<Index>(S).transpose()
+ .cwiseProduct(rhs.template segment<Index>(S)).sum();
+
+ if(!(Mode & UnitDiag))
+ rhs.coeffRef(I) /= lhs.coeff(I,I);
+
+ triangular_solver_unroller<Lhs,Rhs,Mode,Index+1,Size>::run(lhs,rhs);
+ }
+};
+
+template<typename Lhs, typename Rhs, int Mode, int Index, int Size>
+struct triangular_solver_unroller<Lhs,Rhs,Mode,Index,Size,true> {
+ static void run(const Lhs&, Rhs&) {}
+};
+
+template<typename Lhs, typename Rhs, int Mode>
+struct triangular_solver_selector<Lhs,Rhs,OnTheLeft,Mode,CompleteUnrolling,1> {
+ static void run(const Lhs& lhs, Rhs& rhs)
+ { triangular_solver_unroller<Lhs,Rhs,Mode,0,Rhs::SizeAtCompileTime>::run(lhs,rhs); }
+};
+
+template<typename Lhs, typename Rhs, int Mode>
+struct triangular_solver_selector<Lhs,Rhs,OnTheRight,Mode,CompleteUnrolling,1> {
+ static void run(const Lhs& lhs, Rhs& rhs)
+ {
+ Transpose<const Lhs> trLhs(lhs);
+ Transpose<Rhs> trRhs(rhs);
+
+ triangular_solver_unroller<Transpose<const Lhs>,Transpose<Rhs>,
+ ((Mode&Upper)==Upper ? Lower : Upper) | (Mode&UnitDiag),
+ 0,Rhs::SizeAtCompileTime>::run(trLhs,trRhs);
+ }
+};
+
+} // end namespace internal
+
+/***************************************************************************
+* TriangularView methods
+***************************************************************************/
+
+/** "in-place" version of TriangularView::solve() where the result is written in \a other
+ *
+ * \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.
+ *
+ * See TriangularView:solve() for the details.
+ */
+template<typename MatrixType, unsigned int Mode>
+template<int Side, typename OtherDerived>
+void TriangularView<MatrixType,Mode>::solveInPlace(const MatrixBase<OtherDerived>& _other) const
+{
+ OtherDerived& other = _other.const_cast_derived();
+ eigen_assert( cols() == rows() && ((Side==OnTheLeft && cols() == other.rows()) || (Side==OnTheRight && cols() == other.cols())) );
+ eigen_assert((!(Mode & ZeroDiag)) && bool(Mode & (Upper|Lower)));
+
+ enum { copy = internal::traits<OtherDerived>::Flags & RowMajorBit && OtherDerived::IsVectorAtCompileTime };
+ typedef typename internal::conditional<copy,
+ typename internal::plain_matrix_type_column_major<OtherDerived>::type, OtherDerived&>::type OtherCopy;
+ OtherCopy otherCopy(other);
+
+ internal::triangular_solver_selector<MatrixType, typename internal::remove_reference<OtherCopy>::type,
+ Side, Mode>::run(nestedExpression(), otherCopy);
+
+ if (copy)
+ other = otherCopy;
+}
+
+/** \returns the product of the inverse of \c *this with \a other, \a *this being triangular.
+ *
+ * This function computes the inverse-matrix matrix product inverse(\c *this) * \a other if
+ * \a Side==OnTheLeft (the default), or the right-inverse-multiply \a other * inverse(\c *this) if
+ * \a Side==OnTheRight.
+ *
+ * The matrix \c *this must be triangular and invertible (i.e., all the coefficients of the
+ * diagonal must be non zero). It works as a forward (resp. backward) substitution if \c *this
+ * is an upper (resp. lower) triangular matrix.
+ *
+ * Example: \include MatrixBase_marked.cpp
+ * Output: \verbinclude MatrixBase_marked.out
+ *
+ * This function returns an expression of the inverse-multiply and can works in-place if it is assigned
+ * to the same matrix or vector \a other.
+ *
+ * For users coming from BLAS, this function (and more specifically solveInPlace()) offer
+ * all the operations supported by the \c *TRSV and \c *TRSM BLAS routines.
+ *
+ * \sa TriangularView::solveInPlace()
+ */
+template<typename Derived, unsigned int Mode>
+template<int Side, typename Other>
+const internal::triangular_solve_retval<Side,TriangularView<Derived,Mode>,Other>
+TriangularView<Derived,Mode>::solve(const MatrixBase<Other>& other) const
+{
+ return internal::triangular_solve_retval<Side,TriangularView,Other>(*this, other.derived());
+}
+
+namespace internal {
+
+
+template<int Side, typename TriangularType, typename Rhs>
+struct traits<triangular_solve_retval<Side, TriangularType, Rhs> >
+{
+ typedef typename internal::plain_matrix_type_column_major<Rhs>::type ReturnType;
+};
+
+template<int Side, typename TriangularType, typename Rhs> struct triangular_solve_retval
+ : public ReturnByValue<triangular_solve_retval<Side, TriangularType, Rhs> >
+{
+ typedef typename remove_all<typename Rhs::Nested>::type RhsNestedCleaned;
+ typedef ReturnByValue<triangular_solve_retval> Base;
+ typedef typename Base::Index Index;
+
+ triangular_solve_retval(const TriangularType& tri, const Rhs& rhs)
+ : m_triangularMatrix(tri), m_rhs(rhs)
+ {}
+
+ inline Index rows() const { return m_rhs.rows(); }
+ inline Index cols() const { return m_rhs.cols(); }
+
+ template<typename Dest> inline void evalTo(Dest& dst) const
+ {
+ if(!(is_same<RhsNestedCleaned,Dest>::value && extract_data(dst) == extract_data(m_rhs)))
+ dst = m_rhs;
+ m_triangularMatrix.template solveInPlace<Side>(dst);
+ }
+
+ protected:
+ const TriangularType& m_triangularMatrix;
+ typename Rhs::Nested m_rhs;
+};
+
+} // namespace internal
+
+} // end namespace Eigen
+
+#endif // EIGEN_SOLVETRIANGULAR_H
diff --git a/Eigen/src/Core/StableNorm.h b/Eigen/src/Core/StableNorm.h
new file mode 100644
index 000000000..d8bf7db70
--- /dev/null
+++ b/Eigen/src/Core/StableNorm.h
@@ -0,0 +1,179 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra.
+//
+// Copyright (C) 2009 Gael Guennebaud <gael.guennebaud@inria.fr>
+//
+// This Source Code Form is subject to the terms of the Mozilla
+// Public License v. 2.0. If a copy of the MPL was not distributed
+// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+#ifndef EIGEN_STABLENORM_H
+#define EIGEN_STABLENORM_H
+
+namespace Eigen {
+
+namespace internal {
+template<typename ExpressionType, typename Scalar>
+inline void stable_norm_kernel(const ExpressionType& bl, Scalar& ssq, Scalar& scale, Scalar& invScale)
+{
+ Scalar max = bl.cwiseAbs().maxCoeff();
+ if (max>scale)
+ {
+ ssq = ssq * abs2(scale/max);
+ scale = max;
+ invScale = Scalar(1)/scale;
+ }
+ // TODO if the max is much much smaller than the current scale,
+ // then we can neglect this sub vector
+ ssq += (bl*invScale).squaredNorm();
+}
+}
+
+/** \returns the \em l2 norm of \c *this avoiding underflow and overflow.
+ * This version use a blockwise two passes algorithm:
+ * 1 - find the absolute largest coefficient \c s
+ * 2 - compute \f$ s \Vert \frac{*this}{s} \Vert \f$ in a standard way
+ *
+ * For architecture/scalar types supporting vectorization, this version
+ * is faster than blueNorm(). Otherwise the blueNorm() is much faster.
+ *
+ * \sa norm(), blueNorm(), hypotNorm()
+ */
+template<typename Derived>
+inline typename NumTraits<typename internal::traits<Derived>::Scalar>::Real
+MatrixBase<Derived>::stableNorm() const
+{
+ using std::min;
+ const Index blockSize = 4096;
+ RealScalar scale(0);
+ RealScalar invScale(1);
+ RealScalar ssq(0); // sum of square
+ enum {
+ Alignment = (int(Flags)&DirectAccessBit) || (int(Flags)&AlignedBit) ? 1 : 0
+ };
+ Index n = size();
+ Index bi = internal::first_aligned(derived());
+ if (bi>0)
+ internal::stable_norm_kernel(this->head(bi), ssq, scale, invScale);
+ for (; bi<n; bi+=blockSize)
+ internal::stable_norm_kernel(this->segment(bi,(min)(blockSize, n - bi)).template forceAlignedAccessIf<Alignment>(), ssq, scale, invScale);
+ return scale * internal::sqrt(ssq);
+}
+
+/** \returns the \em l2 norm of \c *this using the Blue's algorithm.
+ * A Portable Fortran Program to Find the Euclidean Norm of a Vector,
+ * ACM TOMS, Vol 4, Issue 1, 1978.
+ *
+ * For architecture/scalar types without vectorization, this version
+ * is much faster than stableNorm(). Otherwise the stableNorm() is faster.
+ *
+ * \sa norm(), stableNorm(), hypotNorm()
+ */
+template<typename Derived>
+inline typename NumTraits<typename internal::traits<Derived>::Scalar>::Real
+MatrixBase<Derived>::blueNorm() const
+{
+ using std::pow;
+ using std::min;
+ using std::max;
+ static Index nmax = -1;
+ static RealScalar b1, b2, s1m, s2m, overfl, rbig, relerr;
+ if(nmax <= 0)
+ {
+ int nbig, ibeta, it, iemin, iemax, iexp;
+ RealScalar abig, eps;
+ // This program calculates the machine-dependent constants
+ // bl, b2, slm, s2m, relerr overfl, nmax
+ // from the "basic" machine-dependent numbers
+ // nbig, ibeta, it, iemin, iemax, rbig.
+ // The following define the basic machine-dependent constants.
+ // For portability, the PORT subprograms "ilmaeh" and "rlmach"
+ // are used. For any specific computer, each of the assignment
+ // statements can be replaced
+ nbig = (std::numeric_limits<Index>::max)(); // largest integer
+ ibeta = std::numeric_limits<RealScalar>::radix; // base for floating-point numbers
+ it = std::numeric_limits<RealScalar>::digits; // number of base-beta digits in mantissa
+ iemin = std::numeric_limits<RealScalar>::min_exponent; // minimum exponent
+ iemax = std::numeric_limits<RealScalar>::max_exponent; // maximum exponent
+ rbig = (std::numeric_limits<RealScalar>::max)(); // largest floating-point number
+
+ iexp = -((1-iemin)/2);
+ b1 = RealScalar(pow(RealScalar(ibeta),RealScalar(iexp))); // lower boundary of midrange
+ iexp = (iemax + 1 - it)/2;
+ b2 = RealScalar(pow(RealScalar(ibeta),RealScalar(iexp))); // upper boundary of midrange
+
+ iexp = (2-iemin)/2;
+ s1m = RealScalar(pow(RealScalar(ibeta),RealScalar(iexp))); // scaling factor for lower range
+ iexp = - ((iemax+it)/2);
+ s2m = RealScalar(pow(RealScalar(ibeta),RealScalar(iexp))); // scaling factor for upper range
+
+ overfl = rbig*s2m; // overflow boundary for abig
+ eps = RealScalar(pow(double(ibeta), 1-it));
+ relerr = internal::sqrt(eps); // tolerance for neglecting asml
+ abig = RealScalar(1.0/eps - 1.0);
+ if (RealScalar(nbig)>abig) nmax = int(abig); // largest safe n
+ else nmax = nbig;
+ }
+ Index n = size();
+ RealScalar ab2 = b2 / RealScalar(n);
+ RealScalar asml = RealScalar(0);
+ RealScalar amed = RealScalar(0);
+ RealScalar abig = RealScalar(0);
+ for(Index j=0; j<n; ++j)
+ {
+ RealScalar ax = internal::abs(coeff(j));
+ if(ax > ab2) abig += internal::abs2(ax*s2m);
+ else if(ax < b1) asml += internal::abs2(ax*s1m);
+ else amed += internal::abs2(ax);
+ }
+ if(abig > RealScalar(0))
+ {
+ abig = internal::sqrt(abig);
+ if(abig > overfl)
+ {
+ eigen_assert(false && "overflow");
+ return rbig;
+ }
+ if(amed > RealScalar(0))
+ {
+ abig = abig/s2m;
+ amed = internal::sqrt(amed);
+ }
+ else
+ return abig/s2m;
+ }
+ else if(asml > RealScalar(0))
+ {
+ if (amed > RealScalar(0))
+ {
+ abig = internal::sqrt(amed);
+ amed = internal::sqrt(asml) / s1m;
+ }
+ else
+ return internal::sqrt(asml)/s1m;
+ }
+ else
+ return internal::sqrt(amed);
+ asml = (min)(abig, amed);
+ abig = (max)(abig, amed);
+ if(asml <= abig*relerr)
+ return abig;
+ else
+ return abig * internal::sqrt(RealScalar(1) + internal::abs2(asml/abig));
+}
+
+/** \returns the \em l2 norm of \c *this avoiding undeflow and overflow.
+ * This version use a concatenation of hypot() calls, and it is very slow.
+ *
+ * \sa norm(), stableNorm()
+ */
+template<typename Derived>
+inline typename NumTraits<typename internal::traits<Derived>::Scalar>::Real
+MatrixBase<Derived>::hypotNorm() const
+{
+ return this->cwiseAbs().redux(internal::scalar_hypot_op<RealScalar>());
+}
+
+} // end namespace Eigen
+
+#endif // EIGEN_STABLENORM_H
diff --git a/Eigen/src/Core/Stride.h b/Eigen/src/Core/Stride.h
new file mode 100644
index 000000000..1e3f5fe9f
--- /dev/null
+++ b/Eigen/src/Core/Stride.h
@@ -0,0 +1,108 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra.
+//
+// Copyright (C) 2010 Benoit Jacob <jacob.benoit.1@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 EIGEN_STRIDE_H
+#define EIGEN_STRIDE_H
+
+namespace Eigen {
+
+/** \class Stride
+ * \ingroup Core_Module
+ *
+ * \brief Holds strides information for Map
+ *
+ * This class holds the strides information for mapping arrays with strides with class Map.
+ *
+ * It holds two values: the inner stride and the outer stride.
+ *
+ * The inner stride is the pointer increment between two consecutive entries within a given row of a
+ * row-major matrix or within a given column of a column-major matrix.
+ *
+ * The outer stride is the pointer increment between two consecutive rows of a row-major matrix or
+ * between two consecutive columns of a column-major matrix.
+ *
+ * These two values can be passed either at compile-time as template parameters, or at runtime as
+ * arguments to the constructor.
+ *
+ * Indeed, this class takes two template parameters:
+ * \param _OuterStrideAtCompileTime the outer stride, or Dynamic if you want to specify it at runtime.
+ * \param _InnerStrideAtCompileTime the inner stride, or Dynamic if you want to specify it at runtime.
+ *
+ * Here is an example:
+ * \include Map_general_stride.cpp
+ * Output: \verbinclude Map_general_stride.out
+ *
+ * \sa class InnerStride, class OuterStride, \ref TopicStorageOrders
+ */
+template<int _OuterStrideAtCompileTime, int _InnerStrideAtCompileTime>
+class Stride
+{
+ public:
+ typedef DenseIndex Index;
+ enum {
+ InnerStrideAtCompileTime = _InnerStrideAtCompileTime,
+ OuterStrideAtCompileTime = _OuterStrideAtCompileTime
+ };
+
+ /** Default constructor, for use when strides are fixed at compile time */
+ Stride()
+ : m_outer(OuterStrideAtCompileTime), m_inner(InnerStrideAtCompileTime)
+ {
+ eigen_assert(InnerStrideAtCompileTime != Dynamic && OuterStrideAtCompileTime != Dynamic);
+ }
+
+ /** Constructor allowing to pass the strides at runtime */
+ Stride(Index outerStride, Index innerStride)
+ : m_outer(outerStride), m_inner(innerStride)
+ {
+ eigen_assert(innerStride>=0 && outerStride>=0);
+ }
+
+ /** Copy constructor */
+ Stride(const Stride& other)
+ : m_outer(other.outer()), m_inner(other.inner())
+ {}
+
+ /** \returns the outer stride */
+ inline Index outer() const { return m_outer.value(); }
+ /** \returns the inner stride */
+ inline Index inner() const { return m_inner.value(); }
+
+ protected:
+ internal::variable_if_dynamic<Index, OuterStrideAtCompileTime> m_outer;
+ internal::variable_if_dynamic<Index, InnerStrideAtCompileTime> m_inner;
+};
+
+/** \brief Convenience specialization of Stride to specify only an inner stride
+ * See class Map for some examples */
+template<int Value = Dynamic>
+class InnerStride : public Stride<0, Value>
+{
+ typedef Stride<0, Value> Base;
+ public:
+ typedef DenseIndex Index;
+ InnerStride() : Base() {}
+ InnerStride(Index v) : Base(0, v) {}
+};
+
+/** \brief Convenience specialization of Stride to specify only an outer stride
+ * See class Map for some examples */
+template<int Value = Dynamic>
+class OuterStride : public Stride<Value, 0>
+{
+ typedef Stride<Value, 0> Base;
+ public:
+ typedef DenseIndex Index;
+ OuterStride() : Base() {}
+ OuterStride(Index v) : Base(v,0) {}
+};
+
+} // end namespace Eigen
+
+#endif // EIGEN_STRIDE_H
diff --git a/Eigen/src/Core/Swap.h b/Eigen/src/Core/Swap.h
new file mode 100644
index 000000000..fd73cf3ad
--- /dev/null
+++ b/Eigen/src/Core/Swap.h
@@ -0,0 +1,126 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra.
+//
+// Copyright (C) 2006-2008 Benoit Jacob <jacob.benoit.1@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 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<typename ExpressionType>
+struct traits<SwapWrapper<ExpressionType> > : traits<ExpressionType> {};
+}
+
+template<typename ExpressionType> class SwapWrapper
+ : public internal::dense_xpr_base<SwapWrapper<ExpressionType> >::type
+{
+ public:
+
+ typedef typename internal::dense_xpr_base<SwapWrapper>::type Base;
+ EIGEN_DENSE_PUBLIC_INTERFACE(SwapWrapper)
+ typedef typename internal::packet_traits<Scalar>::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<ExpressionType>::value,
+ Scalar,
+ const Scalar
+ >::type ScalarWithConstIfNotLvalue;
+
+ inline ScalarWithConstIfNotLvalue* data() { return m_expression.data(); }
+ inline const Scalar* data() const { return m_expression.data(); }
+
+ inline Scalar& coeffRef(Index row, Index col)
+ {
+ return m_expression.const_cast_derived().coeffRef(row, col);
+ }
+
+ inline Scalar& coeffRef(Index index)
+ {
+ return m_expression.const_cast_derived().coeffRef(index);
+ }
+
+ inline Scalar& coeffRef(Index row, Index col) const
+ {
+ return m_expression.coeffRef(row, col);
+ }
+
+ inline Scalar& coeffRef(Index index) const
+ {
+ return m_expression.coeffRef(index);
+ }
+
+ template<typename OtherDerived>
+ void copyCoeff(Index row, Index col, const DenseBase<OtherDerived>& other)
+ {
+ OtherDerived& _other = other.const_cast_derived();
+ eigen_internal_assert(row >= 0 && row < rows()
+ && col >= 0 && col < cols());
+ Scalar tmp = m_expression.coeff(row, col);
+ m_expression.coeffRef(row, col) = _other.coeff(row, col);
+ _other.coeffRef(row, col) = tmp;
+ }
+
+ template<typename OtherDerived>
+ void copyCoeff(Index index, const DenseBase<OtherDerived>& 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<typename OtherDerived, int StoreMode, int LoadMode>
+ void copyPacket(Index row, Index col, const DenseBase<OtherDerived>& other)
+ {
+ OtherDerived& _other = other.const_cast_derived();
+ eigen_internal_assert(row >= 0 && row < rows()
+ && col >= 0 && col < cols());
+ Packet tmp = m_expression.template packet<StoreMode>(row, col);
+ m_expression.template writePacket<StoreMode>(row, col,
+ _other.template packet<LoadMode>(row, col)
+ );
+ _other.template writePacket<LoadMode>(row, col, tmp);
+ }
+
+ template<typename OtherDerived, int StoreMode, int LoadMode>
+ void copyPacket(Index index, const DenseBase<OtherDerived>& other)
+ {
+ OtherDerived& _other = other.const_cast_derived();
+ eigen_internal_assert(index >= 0 && index < m_expression.size());
+ Packet tmp = m_expression.template packet<StoreMode>(index);
+ m_expression.template writePacket<StoreMode>(index,
+ _other.template packet<LoadMode>(index)
+ );
+ _other.template writePacket<LoadMode>(index, tmp);
+ }
+
+ ExpressionType& expression() const { return m_expression; }
+
+ protected:
+ ExpressionType& m_expression;
+};
+
+} // end namespace Eigen
+
+#endif // EIGEN_SWAP_H
diff --git a/Eigen/src/Core/Transpose.h b/Eigen/src/Core/Transpose.h
new file mode 100644
index 000000000..045a1cce6
--- /dev/null
+++ b/Eigen/src/Core/Transpose.h
@@ -0,0 +1,414 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra.
+//
+// Copyright (C) 2006-2008 Benoit Jacob <jacob.benoit.1@gmail.com>
+// Copyright (C) 2009-2010 Gael Guennebaud <gael.guennebaud@inria.fr>
+//
+// This Source Code Form is subject to the terms of the Mozilla
+// Public License v. 2.0. If a copy of the MPL was not distributed
+// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+#ifndef EIGEN_TRANSPOSE_H
+#define EIGEN_TRANSPOSE_H
+
+namespace Eigen {
+
+/** \class Transpose
+ * \ingroup Core_Module
+ *
+ * \brief Expression of the transpose of a matrix
+ *
+ * \param MatrixType the type of the object of which we are taking the transpose
+ *
+ * This class represents an expression of the transpose of a matrix.
+ * It is the return type of MatrixBase::transpose() and MatrixBase::adjoint()
+ * and most of the time this is the only way it is used.
+ *
+ * \sa MatrixBase::transpose(), MatrixBase::adjoint()
+ */
+
+namespace internal {
+template<typename MatrixType>
+struct traits<Transpose<MatrixType> > : traits<MatrixType>
+{
+ typedef typename MatrixType::Scalar Scalar;
+ typedef typename nested<MatrixType>::type MatrixTypeNested;
+ typedef typename remove_reference<MatrixTypeNested>::type MatrixTypeNestedPlain;
+ typedef typename traits<MatrixType>::StorageKind StorageKind;
+ typedef typename traits<MatrixType>::XprKind XprKind;
+ enum {
+ RowsAtCompileTime = MatrixType::ColsAtCompileTime,
+ ColsAtCompileTime = MatrixType::RowsAtCompileTime,
+ MaxRowsAtCompileTime = MatrixType::MaxColsAtCompileTime,
+ MaxColsAtCompileTime = MatrixType::MaxRowsAtCompileTime,
+ FlagsLvalueBit = is_lvalue<MatrixType>::value ? LvalueBit : 0,
+ Flags0 = MatrixTypeNestedPlain::Flags & ~(LvalueBit | NestByRefBit),
+ Flags1 = Flags0 | FlagsLvalueBit,
+ Flags = Flags1 ^ RowMajorBit,
+ CoeffReadCost = MatrixTypeNestedPlain::CoeffReadCost,
+ InnerStrideAtCompileTime = inner_stride_at_compile_time<MatrixType>::ret,
+ OuterStrideAtCompileTime = outer_stride_at_compile_time<MatrixType>::ret
+ };
+};
+}
+
+template<typename MatrixType, typename StorageKind> class TransposeImpl;
+
+template<typename MatrixType> class Transpose
+ : public TransposeImpl<MatrixType,typename internal::traits<MatrixType>::StorageKind>
+{
+ public:
+
+ typedef typename TransposeImpl<MatrixType,typename internal::traits<MatrixType>::StorageKind>::Base Base;
+ EIGEN_GENERIC_PUBLIC_INTERFACE(Transpose)
+
+ inline Transpose(MatrixType& matrix) : m_matrix(matrix) {}
+
+ EIGEN_INHERIT_ASSIGNMENT_OPERATORS(Transpose)
+
+ inline Index rows() const { return m_matrix.cols(); }
+ inline Index cols() const { return m_matrix.rows(); }
+
+ /** \returns the nested expression */
+ const typename internal::remove_all<typename MatrixType::Nested>::type&
+ nestedExpression() const { return m_matrix; }
+
+ /** \returns the nested expression */
+ typename internal::remove_all<typename MatrixType::Nested>::type&
+ nestedExpression() { return m_matrix.const_cast_derived(); }
+
+ protected:
+ typename MatrixType::Nested m_matrix;
+};
+
+namespace internal {
+
+template<typename MatrixType, bool HasDirectAccess = has_direct_access<MatrixType>::ret>
+struct TransposeImpl_base
+{
+ typedef typename dense_xpr_base<Transpose<MatrixType> >::type type;
+};
+
+template<typename MatrixType>
+struct TransposeImpl_base<MatrixType, false>
+{
+ typedef typename dense_xpr_base<Transpose<MatrixType> >::type type;
+};
+
+} // end namespace internal
+
+template<typename MatrixType> class TransposeImpl<MatrixType,Dense>
+ : public internal::TransposeImpl_base<MatrixType>::type
+{
+ public:
+
+ typedef typename internal::TransposeImpl_base<MatrixType>::type Base;
+ EIGEN_DENSE_PUBLIC_INTERFACE(Transpose<MatrixType>)
+
+ inline Index innerStride() const { return derived().nestedExpression().innerStride(); }
+ inline Index outerStride() const { return derived().nestedExpression().outerStride(); }
+
+ typedef typename internal::conditional<
+ internal::is_lvalue<MatrixType>::value,
+ Scalar,
+ const Scalar
+ >::type ScalarWithConstIfNotLvalue;
+
+ inline ScalarWithConstIfNotLvalue* data() { return derived().nestedExpression().data(); }
+ inline const Scalar* data() const { return derived().nestedExpression().data(); }
+
+ inline ScalarWithConstIfNotLvalue& coeffRef(Index row, Index col)
+ {
+ EIGEN_STATIC_ASSERT_LVALUE(MatrixType)
+ return derived().nestedExpression().const_cast_derived().coeffRef(col, row);
+ }
+
+ inline ScalarWithConstIfNotLvalue& coeffRef(Index index)
+ {
+ EIGEN_STATIC_ASSERT_LVALUE(MatrixType)
+ return derived().nestedExpression().const_cast_derived().coeffRef(index);
+ }
+
+ inline const Scalar& coeffRef(Index row, Index col) const
+ {
+ return derived().nestedExpression().coeffRef(col, row);
+ }
+
+ inline const Scalar& coeffRef(Index index) const
+ {
+ return derived().nestedExpression().coeffRef(index);
+ }
+
+ inline CoeffReturnType coeff(Index row, Index col) const
+ {
+ return derived().nestedExpression().coeff(col, row);
+ }
+
+ inline CoeffReturnType coeff(Index index) const
+ {
+ return derived().nestedExpression().coeff(index);
+ }
+
+ template<int LoadMode>
+ inline const PacketScalar packet(Index row, Index col) const
+ {
+ return derived().nestedExpression().template packet<LoadMode>(col, row);
+ }
+
+ template<int LoadMode>
+ inline void writePacket(Index row, Index col, const PacketScalar& x)
+ {
+ derived().nestedExpression().const_cast_derived().template writePacket<LoadMode>(col, row, x);
+ }
+
+ template<int LoadMode>
+ inline const PacketScalar packet(Index index) const
+ {
+ return derived().nestedExpression().template packet<LoadMode>(index);
+ }
+
+ template<int LoadMode>
+ inline void writePacket(Index index, const PacketScalar& x)
+ {
+ derived().nestedExpression().const_cast_derived().template writePacket<LoadMode>(index, x);
+ }
+};
+
+/** \returns an expression of the transpose of *this.
+ *
+ * Example: \include MatrixBase_transpose.cpp
+ * Output: \verbinclude MatrixBase_transpose.out
+ *
+ * \warning If you want to replace a matrix by its own transpose, do \b NOT do this:
+ * \code
+ * m = m.transpose(); // bug!!! caused by aliasing effect
+ * \endcode
+ * Instead, use the transposeInPlace() method:
+ * \code
+ * m.transposeInPlace();
+ * \endcode
+ * which gives Eigen good opportunities for optimization, or alternatively you can also do:
+ * \code
+ * m = m.transpose().eval();
+ * \endcode
+ *
+ * \sa transposeInPlace(), adjoint() */
+template<typename Derived>
+inline Transpose<Derived>
+DenseBase<Derived>::transpose()
+{
+ return derived();
+}
+
+/** This is the const version of transpose().
+ *
+ * Make sure you read the warning for transpose() !
+ *
+ * \sa transposeInPlace(), adjoint() */
+template<typename Derived>
+inline const typename DenseBase<Derived>::ConstTransposeReturnType
+DenseBase<Derived>::transpose() const
+{
+ return ConstTransposeReturnType(derived());
+}
+
+/** \returns an expression of the adjoint (i.e. conjugate transpose) of *this.
+ *
+ * Example: \include MatrixBase_adjoint.cpp
+ * Output: \verbinclude MatrixBase_adjoint.out
+ *
+ * \warning If you want to replace a matrix by its own adjoint, do \b NOT do this:
+ * \code
+ * m = m.adjoint(); // bug!!! caused by aliasing effect
+ * \endcode
+ * Instead, use the adjointInPlace() method:
+ * \code
+ * m.adjointInPlace();
+ * \endcode
+ * which gives Eigen good opportunities for optimization, or alternatively you can also do:
+ * \code
+ * m = m.adjoint().eval();
+ * \endcode
+ *
+ * \sa adjointInPlace(), transpose(), conjugate(), class Transpose, class internal::scalar_conjugate_op */
+template<typename Derived>
+inline const typename MatrixBase<Derived>::AdjointReturnType
+MatrixBase<Derived>::adjoint() const
+{
+ return this->transpose(); // in the complex case, the .conjugate() is be implicit here
+ // due to implicit conversion to return type
+}
+
+/***************************************************************************
+* "in place" transpose implementation
+***************************************************************************/
+
+namespace internal {
+
+template<typename MatrixType,
+ bool IsSquare = (MatrixType::RowsAtCompileTime == MatrixType::ColsAtCompileTime) && MatrixType::RowsAtCompileTime!=Dynamic>
+struct inplace_transpose_selector;
+
+template<typename MatrixType>
+struct inplace_transpose_selector<MatrixType,true> { // square matrix
+ static void run(MatrixType& m) {
+ m.template triangularView<StrictlyUpper>().swap(m.transpose());
+ }
+};
+
+template<typename MatrixType>
+struct inplace_transpose_selector<MatrixType,false> { // non square matrix
+ static void run(MatrixType& m) {
+ if (m.rows()==m.cols())
+ m.template triangularView<StrictlyUpper>().swap(m.transpose());
+ else
+ m = m.transpose().eval();
+ }
+};
+
+} // end namespace internal
+
+/** This is the "in place" version of transpose(): it replaces \c *this by its own transpose.
+ * Thus, doing
+ * \code
+ * m.transposeInPlace();
+ * \endcode
+ * has the same effect on m as doing
+ * \code
+ * m = m.transpose().eval();
+ * \endcode
+ * and is faster and also safer because in the latter line of code, forgetting the eval() results
+ * in a bug caused by aliasing.
+ *
+ * Notice however that this method is only useful if you want to replace a matrix by its own transpose.
+ * If you just need the transpose of a matrix, use transpose().
+ *
+ * \note if the matrix is not square, then \c *this must be a resizable matrix.
+ *
+ * \sa transpose(), adjoint(), adjointInPlace() */
+template<typename Derived>
+inline void DenseBase<Derived>::transposeInPlace()
+{
+ internal::inplace_transpose_selector<Derived>::run(derived());
+}
+
+/***************************************************************************
+* "in place" adjoint implementation
+***************************************************************************/
+
+/** This is the "in place" version of adjoint(): it replaces \c *this by its own transpose.
+ * Thus, doing
+ * \code
+ * m.adjointInPlace();
+ * \endcode
+ * has the same effect on m as doing
+ * \code
+ * m = m.adjoint().eval();
+ * \endcode
+ * and is faster and also safer because in the latter line of code, forgetting the eval() results
+ * in a bug caused by aliasing.
+ *
+ * Notice however that this method is only useful if you want to replace a matrix by its own adjoint.
+ * If you just need the adjoint of a matrix, use adjoint().
+ *
+ * \note if the matrix is not square, then \c *this must be a resizable matrix.
+ *
+ * \sa transpose(), adjoint(), transposeInPlace() */
+template<typename Derived>
+inline void MatrixBase<Derived>::adjointInPlace()
+{
+ derived() = adjoint().eval();
+}
+
+#ifndef EIGEN_NO_DEBUG
+
+// The following is to detect aliasing problems in most common cases.
+
+namespace internal {
+
+template<typename BinOp,typename NestedXpr,typename Rhs>
+struct blas_traits<SelfCwiseBinaryOp<BinOp,NestedXpr,Rhs> >
+ : blas_traits<NestedXpr>
+{
+ typedef SelfCwiseBinaryOp<BinOp,NestedXpr,Rhs> XprType;
+ static inline const XprType extract(const XprType& x) { return x; }
+};
+
+template<bool DestIsTransposed, typename OtherDerived>
+struct check_transpose_aliasing_compile_time_selector
+{
+ enum { ret = bool(blas_traits<OtherDerived>::IsTransposed) != DestIsTransposed };
+};
+
+template<bool DestIsTransposed, typename BinOp, typename DerivedA, typename DerivedB>
+struct check_transpose_aliasing_compile_time_selector<DestIsTransposed,CwiseBinaryOp<BinOp,DerivedA,DerivedB> >
+{
+ enum { ret = bool(blas_traits<DerivedA>::IsTransposed) != DestIsTransposed
+ || bool(blas_traits<DerivedB>::IsTransposed) != DestIsTransposed
+ };
+};
+
+template<typename Scalar, bool DestIsTransposed, typename OtherDerived>
+struct check_transpose_aliasing_run_time_selector
+{
+ static bool run(const Scalar* dest, const OtherDerived& src)
+ {
+ return (bool(blas_traits<OtherDerived>::IsTransposed) != DestIsTransposed) && (dest!=0 && dest==(Scalar*)extract_data(src));
+ }
+};
+
+template<typename Scalar, bool DestIsTransposed, typename BinOp, typename DerivedA, typename DerivedB>
+struct check_transpose_aliasing_run_time_selector<Scalar,DestIsTransposed,CwiseBinaryOp<BinOp,DerivedA,DerivedB> >
+{
+ static bool run(const Scalar* dest, const CwiseBinaryOp<BinOp,DerivedA,DerivedB>& src)
+ {
+ return ((blas_traits<DerivedA>::IsTransposed != DestIsTransposed) && (dest!=0 && dest==(Scalar*)extract_data(src.lhs())))
+ || ((blas_traits<DerivedB>::IsTransposed != DestIsTransposed) && (dest!=0 && dest==(Scalar*)extract_data(src.rhs())));
+ }
+};
+
+// the following selector, checkTransposeAliasing_impl, based on MightHaveTransposeAliasing,
+// is because when the condition controlling the assert is known at compile time, ICC emits a warning.
+// This is actually a good warning: in expressions that don't have any transposing, the condition is
+// known at compile time to be false, and using that, we can avoid generating the code of the assert again
+// and again for all these expressions that don't need it.
+
+template<typename Derived, typename OtherDerived,
+ bool MightHaveTransposeAliasing
+ = check_transpose_aliasing_compile_time_selector
+ <blas_traits<Derived>::IsTransposed,OtherDerived>::ret
+ >
+struct checkTransposeAliasing_impl
+{
+ static void run(const Derived& dst, const OtherDerived& other)
+ {
+ eigen_assert((!check_transpose_aliasing_run_time_selector
+ <typename Derived::Scalar,blas_traits<Derived>::IsTransposed,OtherDerived>
+ ::run(extract_data(dst), other))
+ && "aliasing detected during tranposition, use transposeInPlace() "
+ "or evaluate the rhs into a temporary using .eval()");
+
+ }
+};
+
+template<typename Derived, typename OtherDerived>
+struct checkTransposeAliasing_impl<Derived, OtherDerived, false>
+{
+ static void run(const Derived&, const OtherDerived&)
+ {
+ }
+};
+
+} // end namespace internal
+
+template<typename Derived>
+template<typename OtherDerived>
+void DenseBase<Derived>::checkTransposeAliasing(const OtherDerived& other) const
+{
+ internal::checkTransposeAliasing_impl<Derived, OtherDerived>::run(derived(), other);
+}
+#endif
+
+} // end namespace Eigen
+
+#endif // EIGEN_TRANSPOSE_H
diff --git a/Eigen/src/Core/Transpositions.h b/Eigen/src/Core/Transpositions.h
new file mode 100644
index 000000000..2cd268a5f
--- /dev/null
+++ b/Eigen/src/Core/Transpositions.h
@@ -0,0 +1,436 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra.
+//
+// Copyright (C) 2010-2011 Gael Guennebaud <gael.guennebaud@inria.fr>
+//
+// This Source Code Form is subject to the terms of the Mozilla
+// Public License v. 2.0. If a copy of the MPL was not distributed
+// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+#ifndef EIGEN_TRANSPOSITIONS_H
+#define EIGEN_TRANSPOSITIONS_H
+
+namespace Eigen {
+
+/** \class Transpositions
+ * \ingroup Core_Module
+ *
+ * \brief Represents a sequence of transpositions (row/column interchange)
+ *
+ * \param SizeAtCompileTime the number of transpositions, or Dynamic
+ * \param MaxSizeAtCompileTime the maximum number of transpositions, or Dynamic. This optional parameter defaults to SizeAtCompileTime. Most of the time, you should not have to specify it.
+ *
+ * This class represents a permutation transformation as a sequence of \em n transpositions
+ * \f$[T_{n-1} \ldots T_{i} \ldots T_{0}]\f$. It is internally stored as a vector of integers \c indices.
+ * Each transposition \f$ T_{i} \f$ applied on the left of a matrix (\f$ T_{i} M\f$) interchanges
+ * the rows \c i and \c indices[i] of the matrix \c M.
+ * A transposition applied on the right (e.g., \f$ M T_{i}\f$) yields a column interchange.
+ *
+ * Compared to the class PermutationMatrix, such a sequence of transpositions is what is
+ * computed during a decomposition with pivoting, and it is faster when applying the permutation in-place.
+ *
+ * To apply a sequence of transpositions to a matrix, simply use the operator * as in the following example:
+ * \code
+ * Transpositions tr;
+ * MatrixXf mat;
+ * mat = tr * mat;
+ * \endcode
+ * In this example, we detect that the matrix appears on both side, and so the transpositions
+ * are applied in-place without any temporary or extra copy.
+ *
+ * \sa class PermutationMatrix
+ */
+
+namespace internal {
+template<typename TranspositionType, typename MatrixType, int Side, bool Transposed=false> struct transposition_matrix_product_retval;
+}
+
+template<typename Derived>
+class TranspositionsBase
+{
+ typedef internal::traits<Derived> Traits;
+
+ public:
+
+ typedef typename Traits::IndicesType IndicesType;
+ typedef typename IndicesType::Scalar Index;
+
+ Derived& derived() { return *static_cast<Derived*>(this); }
+ const Derived& derived() const { return *static_cast<const Derived*>(this); }
+
+ /** Copies the \a other transpositions into \c *this */
+ template<typename OtherDerived>
+ Derived& operator=(const TranspositionsBase<OtherDerived>& other)
+ {
+ indices() = other.indices();
+ return derived();
+ }
+
+ #ifndef EIGEN_PARSED_BY_DOXYGEN
+ /** This is a special case of the templated operator=. Its purpose is to
+ * prevent a default operator= from hiding the templated operator=.
+ */
+ Derived& operator=(const TranspositionsBase& other)
+ {
+ indices() = other.indices();
+ return derived();
+ }
+ #endif
+
+ /** \returns the number of transpositions */
+ inline Index size() const { return indices().size(); }
+
+ /** Direct access to the underlying index vector */
+ inline const Index& coeff(Index i) const { return indices().coeff(i); }
+ /** Direct access to the underlying index vector */
+ inline Index& coeffRef(Index i) { return indices().coeffRef(i); }
+ /** Direct access to the underlying index vector */
+ inline const Index& operator()(Index i) const { return indices()(i); }
+ /** Direct access to the underlying index vector */
+ inline Index& operator()(Index i) { return indices()(i); }
+ /** Direct access to the underlying index vector */
+ inline const Index& operator[](Index i) const { return indices()(i); }
+ /** Direct access to the underlying index vector */
+ inline Index& operator[](Index i) { return indices()(i); }
+
+ /** const version of indices(). */
+ const IndicesType& indices() const { return derived().indices(); }
+ /** \returns a reference to the stored array representing the transpositions. */
+ IndicesType& indices() { return derived().indices(); }
+
+ /** Resizes to given size. */
+ inline void resize(int size)
+ {
+ indices().resize(size);
+ }
+
+ /** Sets \c *this to represents an identity transformation */
+ void setIdentity()
+ {
+ for(int i = 0; i < indices().size(); ++i)
+ coeffRef(i) = i;
+ }
+
+ // FIXME: do we want such methods ?
+ // might be usefull when the target matrix expression is complex, e.g.:
+ // object.matrix().block(..,..,..,..) = trans * object.matrix().block(..,..,..,..);
+ /*
+ template<typename MatrixType>
+ void applyForwardToRows(MatrixType& mat) const
+ {
+ for(Index k=0 ; k<size() ; ++k)
+ if(m_indices(k)!=k)
+ mat.row(k).swap(mat.row(m_indices(k)));
+ }
+
+ template<typename MatrixType>
+ void applyBackwardToRows(MatrixType& mat) const
+ {
+ for(Index k=size()-1 ; k>=0 ; --k)
+ if(m_indices(k)!=k)
+ mat.row(k).swap(mat.row(m_indices(k)));
+ }
+ */
+
+ /** \returns the inverse transformation */
+ inline Transpose<TranspositionsBase> inverse() const
+ { return Transpose<TranspositionsBase>(derived()); }
+
+ /** \returns the tranpose transformation */
+ inline Transpose<TranspositionsBase> transpose() const
+ { return Transpose<TranspositionsBase>(derived()); }
+
+ protected:
+};
+
+namespace internal {
+template<int SizeAtCompileTime, int MaxSizeAtCompileTime, typename IndexType>
+struct traits<Transpositions<SizeAtCompileTime,MaxSizeAtCompileTime,IndexType> >
+{
+ typedef IndexType Index;
+ typedef Matrix<Index, SizeAtCompileTime, 1, 0, MaxSizeAtCompileTime, 1> IndicesType;
+};
+}
+
+template<int SizeAtCompileTime, int MaxSizeAtCompileTime, typename IndexType>
+class Transpositions : public TranspositionsBase<Transpositions<SizeAtCompileTime,MaxSizeAtCompileTime,IndexType> >
+{
+ typedef internal::traits<Transpositions> Traits;
+ public:
+
+ typedef TranspositionsBase<Transpositions> Base;
+ typedef typename Traits::IndicesType IndicesType;
+ typedef typename IndicesType::Scalar Index;
+
+ inline Transpositions() {}
+
+ /** Copy constructor. */
+ template<typename OtherDerived>
+ inline Transpositions(const TranspositionsBase<OtherDerived>& other)
+ : m_indices(other.indices()) {}
+
+ #ifndef EIGEN_PARSED_BY_DOXYGEN
+ /** Standard copy constructor. Defined only to prevent a default copy constructor
+ * from hiding the other templated constructor */
+ inline Transpositions(const Transpositions& other) : m_indices(other.indices()) {}
+ #endif
+
+ /** Generic constructor from expression of the transposition indices. */
+ template<typename Other>
+ explicit inline Transpositions(const MatrixBase<Other>& indices) : m_indices(indices)
+ {}
+
+ /** Copies the \a other transpositions into \c *this */
+ template<typename OtherDerived>
+ Transpositions& operator=(const TranspositionsBase<OtherDerived>& other)
+ {
+ return Base::operator=(other);
+ }
+
+ #ifndef EIGEN_PARSED_BY_DOXYGEN
+ /** This is a special case of the templated operator=. Its purpose is to
+ * prevent a default operator= from hiding the templated operator=.
+ */
+ Transpositions& operator=(const Transpositions& other)
+ {
+ m_indices = other.m_indices;
+ return *this;
+ }
+ #endif
+
+ /** Constructs an uninitialized permutation matrix of given size.
+ */
+ inline Transpositions(Index size) : m_indices(size)
+ {}
+
+ /** const version of indices(). */
+ const IndicesType& indices() const { return m_indices; }
+ /** \returns a reference to the stored array representing the transpositions. */
+ IndicesType& indices() { return m_indices; }
+
+ protected:
+
+ IndicesType m_indices;
+};
+
+
+namespace internal {
+template<int SizeAtCompileTime, int MaxSizeAtCompileTime, typename IndexType, int _PacketAccess>
+struct traits<Map<Transpositions<SizeAtCompileTime,MaxSizeAtCompileTime,IndexType>,_PacketAccess> >
+{
+ typedef IndexType Index;
+ typedef Map<const Matrix<Index,SizeAtCompileTime,1,0,MaxSizeAtCompileTime,1>, _PacketAccess> IndicesType;
+};
+}
+
+template<int SizeAtCompileTime, int MaxSizeAtCompileTime, typename IndexType, int PacketAccess>
+class Map<Transpositions<SizeAtCompileTime,MaxSizeAtCompileTime,IndexType>,PacketAccess>
+ : public TranspositionsBase<Map<Transpositions<SizeAtCompileTime,MaxSizeAtCompileTime,IndexType>,PacketAccess> >
+{
+ typedef internal::traits<Map> Traits;
+ public:
+
+ typedef TranspositionsBase<Map> Base;
+ typedef typename Traits::IndicesType IndicesType;
+ typedef typename IndicesType::Scalar Index;
+
+ inline Map(const Index* indices)
+ : m_indices(indices)
+ {}
+
+ inline Map(const Index* indices, Index size)
+ : m_indices(indices,size)
+ {}
+
+ /** Copies the \a other transpositions into \c *this */
+ template<typename OtherDerived>
+ Map& operator=(const TranspositionsBase<OtherDerived>& other)
+ {
+ return Base::operator=(other);
+ }
+
+ #ifndef EIGEN_PARSED_BY_DOXYGEN
+ /** This is a special case of the templated operator=. Its purpose is to
+ * prevent a default operator= from hiding the templated operator=.
+ */
+ Map& operator=(const Map& other)
+ {
+ m_indices = other.m_indices;
+ return *this;
+ }
+ #endif
+
+ /** const version of indices(). */
+ const IndicesType& indices() const { return m_indices; }
+
+ /** \returns a reference to the stored array representing the transpositions. */
+ IndicesType& indices() { return m_indices; }
+
+ protected:
+
+ IndicesType m_indices;
+};
+
+namespace internal {
+template<typename _IndicesType>
+struct traits<TranspositionsWrapper<_IndicesType> >
+{
+ typedef typename _IndicesType::Scalar Index;
+ typedef _IndicesType IndicesType;
+};
+}
+
+template<typename _IndicesType>
+class TranspositionsWrapper
+ : public TranspositionsBase<TranspositionsWrapper<_IndicesType> >
+{
+ typedef internal::traits<TranspositionsWrapper> Traits;
+ public:
+
+ typedef TranspositionsBase<TranspositionsWrapper> Base;
+ typedef typename Traits::IndicesType IndicesType;
+ typedef typename IndicesType::Scalar Index;
+
+ inline TranspositionsWrapper(IndicesType& indices)
+ : m_indices(indices)
+ {}
+
+ /** Copies the \a other transpositions into \c *this */
+ template<typename OtherDerived>
+ TranspositionsWrapper& operator=(const TranspositionsBase<OtherDerived>& other)
+ {
+ return Base::operator=(other);
+ }
+
+ #ifndef EIGEN_PARSED_BY_DOXYGEN
+ /** This is a special case of the templated operator=. Its purpose is to
+ * prevent a default operator= from hiding the templated operator=.
+ */
+ TranspositionsWrapper& operator=(const TranspositionsWrapper& other)
+ {
+ m_indices = other.m_indices;
+ return *this;
+ }
+ #endif
+
+ /** const version of indices(). */
+ const IndicesType& indices() const { return m_indices; }
+
+ /** \returns a reference to the stored array representing the transpositions. */
+ IndicesType& indices() { return m_indices; }
+
+ protected:
+
+ const typename IndicesType::Nested m_indices;
+};
+
+/** \returns the \a matrix with the \a transpositions applied to the columns.
+ */
+template<typename Derived, typename TranspositionsDerived>
+inline const internal::transposition_matrix_product_retval<TranspositionsDerived, Derived, OnTheRight>
+operator*(const MatrixBase<Derived>& matrix,
+ const TranspositionsBase<TranspositionsDerived> &transpositions)
+{
+ return internal::transposition_matrix_product_retval
+ <TranspositionsDerived, Derived, OnTheRight>
+ (transpositions.derived(), matrix.derived());
+}
+
+/** \returns the \a matrix with the \a transpositions applied to the rows.
+ */
+template<typename Derived, typename TranspositionDerived>
+inline const internal::transposition_matrix_product_retval
+ <TranspositionDerived, Derived, OnTheLeft>
+operator*(const TranspositionsBase<TranspositionDerived> &transpositions,
+ const MatrixBase<Derived>& matrix)
+{
+ return internal::transposition_matrix_product_retval
+ <TranspositionDerived, Derived, OnTheLeft>
+ (transpositions.derived(), matrix.derived());
+}
+
+namespace internal {
+
+template<typename TranspositionType, typename MatrixType, int Side, bool Transposed>
+struct traits<transposition_matrix_product_retval<TranspositionType, MatrixType, Side, Transposed> >
+{
+ typedef typename MatrixType::PlainObject ReturnType;
+};
+
+template<typename TranspositionType, typename MatrixType, int Side, bool Transposed>
+struct transposition_matrix_product_retval
+ : public ReturnByValue<transposition_matrix_product_retval<TranspositionType, MatrixType, Side, Transposed> >
+{
+ typedef typename remove_all<typename MatrixType::Nested>::type MatrixTypeNestedCleaned;
+ typedef typename TranspositionType::Index Index;
+
+ transposition_matrix_product_retval(const TranspositionType& tr, const MatrixType& matrix)
+ : m_transpositions(tr), m_matrix(matrix)
+ {}
+
+ inline int rows() const { return m_matrix.rows(); }
+ inline int cols() const { return m_matrix.cols(); }
+
+ template<typename Dest> inline void evalTo(Dest& dst) const
+ {
+ const int size = m_transpositions.size();
+ Index j = 0;
+
+ if(!(is_same<MatrixTypeNestedCleaned,Dest>::value && extract_data(dst) == extract_data(m_matrix)))
+ dst = m_matrix;
+
+ for(int k=(Transposed?size-1:0) ; Transposed?k>=0:k<size ; Transposed?--k:++k)
+ if((j=m_transpositions.coeff(k))!=k)
+ {
+ if(Side==OnTheLeft)
+ dst.row(k).swap(dst.row(j));
+ else if(Side==OnTheRight)
+ dst.col(k).swap(dst.col(j));
+ }
+ }
+
+ protected:
+ const TranspositionType& m_transpositions;
+ typename MatrixType::Nested m_matrix;
+};
+
+} // end namespace internal
+
+/* Template partial specialization for transposed/inverse transpositions */
+
+template<typename TranspositionsDerived>
+class Transpose<TranspositionsBase<TranspositionsDerived> >
+{
+ typedef TranspositionsDerived TranspositionType;
+ typedef typename TranspositionType::IndicesType IndicesType;
+ public:
+
+ Transpose(const TranspositionType& t) : m_transpositions(t) {}
+
+ inline int size() const { return m_transpositions.size(); }
+
+ /** \returns the \a matrix with the inverse transpositions applied to the columns.
+ */
+ template<typename Derived> friend
+ inline const internal::transposition_matrix_product_retval<TranspositionType, Derived, OnTheRight, true>
+ operator*(const MatrixBase<Derived>& matrix, const Transpose& trt)
+ {
+ return internal::transposition_matrix_product_retval<TranspositionType, Derived, OnTheRight, true>(trt.m_transpositions, matrix.derived());
+ }
+
+ /** \returns the \a matrix with the inverse transpositions applied to the rows.
+ */
+ template<typename Derived>
+ inline const internal::transposition_matrix_product_retval<TranspositionType, Derived, OnTheLeft, true>
+ operator*(const MatrixBase<Derived>& matrix) const
+ {
+ return internal::transposition_matrix_product_retval<TranspositionType, Derived, OnTheLeft, true>(m_transpositions, matrix.derived());
+ }
+
+ protected:
+ const TranspositionType& m_transpositions;
+};
+
+} // end namespace Eigen
+
+#endif // EIGEN_TRANSPOSITIONS_H
diff --git a/Eigen/src/Core/TriangularMatrix.h b/Eigen/src/Core/TriangularMatrix.h
new file mode 100644
index 000000000..de9540063
--- /dev/null
+++ b/Eigen/src/Core/TriangularMatrix.h
@@ -0,0 +1,827 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra.
+//
+// Copyright (C) 2008 Benoit Jacob <jacob.benoit.1@gmail.com>
+// Copyright (C) 2008-2009 Gael Guennebaud <gael.guennebaud@inria.fr>
+//
+// This Source Code Form is subject to the terms of the Mozilla
+// Public License v. 2.0. If 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<int Side, typename TriangularType, typename Rhs> struct triangular_solve_retval;
+
+}
+
+/** \internal
+ *
+ * \class TriangularBase
+ * \ingroup Core_Module
+ *
+ * \brief Base class for triangular part in a matrix
+ */
+template<typename Derived> class TriangularBase : public EigenBase<Derived>
+{
+ public:
+
+ enum {
+ Mode = internal::traits<Derived>::Mode,
+ CoeffReadCost = internal::traits<Derived>::CoeffReadCost,
+ RowsAtCompileTime = internal::traits<Derived>::RowsAtCompileTime,
+ ColsAtCompileTime = internal::traits<Derived>::ColsAtCompileTime,
+ MaxRowsAtCompileTime = internal::traits<Derived>::MaxRowsAtCompileTime,
+ MaxColsAtCompileTime = internal::traits<Derived>::MaxColsAtCompileTime
+ };
+ typedef typename internal::traits<Derived>::Scalar Scalar;
+ typedef typename internal::traits<Derived>::StorageKind StorageKind;
+ typedef typename internal::traits<Derived>::Index Index;
+ typedef typename internal::traits<Derived>::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<typename Other>
+ 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<const Derived*>(this); }
+ inline Derived& derived() { return *static_cast<Derived*>(this); }
+ #endif // not EIGEN_PARSED_BY_DOXYGEN
+
+ template<typename DenseDerived>
+ void evalTo(MatrixBase<DenseDerived> &other) const;
+ template<typename DenseDerived>
+ void evalToLazy(MatrixBase<DenseDerived> &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<cols() && row>=0 && row<rows());
+ const int mode = int(Mode) & ~SelfAdjoint;
+ EIGEN_ONLY_USED_FOR_DEBUG(mode);
+ eigen_assert((mode==Upper && col>=row)
+ || (mode==Lower && col<=row)
+ || ((mode==StrictlyUpper || mode==UnitUpper) && col>row)
+ || ((mode==StrictlyLower || mode==UnitLower) && col<row));
+ }
+
+ #ifdef EIGEN_INTERNAL_DEBUGGING
+ void check_coordinates_internal(Index row, Index col) const
+ {
+ check_coordinates(row, col);
+ }
+ #else
+ void check_coordinates_internal(Index , Index ) const {}
+ #endif
+
+};
+
+/** \class TriangularView
+ * \ingroup Core_Module
+ *
+ * \brief Base class for triangular part in a matrix
+ *
+ * \param MatrixType the type of the object in which we are taking the triangular part
+ * \param Mode the kind of triangular matrix expression to construct. Can be #Upper,
+ * #Lower, #UnitUpper, #UnitLower, #StrictlyUpper, or #StrictlyLower.
+ * This is in fact a bit field; it must have either #Upper or #Lower,
+ * and additionnaly it may have #UnitDiag or #ZeroDiag or neither.
+ *
+ * This class represents a triangular part of a matrix, not necessarily square. Strictly speaking, for rectangular
+ * matrices one should speak of "trapezoid" parts. This class is the return type
+ * of MatrixBase::triangularView() and most of the time this is the only way it is used.
+ *
+ * \sa MatrixBase::triangularView()
+ */
+namespace internal {
+template<typename MatrixType, unsigned int _Mode>
+struct traits<TriangularView<MatrixType, _Mode> > : traits<MatrixType>
+{
+ typedef typename nested<MatrixType>::type MatrixTypeNested;
+ typedef typename remove_reference<MatrixTypeNested>::type MatrixTypeNestedNonRef;
+ typedef typename remove_all<MatrixTypeNested>::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<int Mode, bool LhsIsTriangular,
+ typename Lhs, bool LhsIsVector,
+ typename Rhs, bool RhsIsVector>
+struct TriangularProduct;
+
+template<typename _MatrixType, unsigned int _Mode> class TriangularView
+ : public TriangularBase<TriangularView<_MatrixType, _Mode> >
+{
+ public:
+
+ typedef TriangularBase<TriangularView> Base;
+ typedef typename internal::traits<TriangularView>::Scalar Scalar;
+
+ typedef _MatrixType MatrixType;
+ typedef typename internal::traits<TriangularView>::DenseMatrixType DenseMatrixType;
+ typedef DenseMatrixType PlainObject;
+
+ protected:
+ typedef typename internal::traits<TriangularView>::MatrixTypeNested MatrixTypeNested;
+ typedef typename internal::traits<TriangularView>::MatrixTypeNestedNonRef MatrixTypeNestedNonRef;
+ typedef typename internal::traits<TriangularView>::MatrixTypeNestedCleaned MatrixTypeNestedCleaned;
+
+ typedef typename internal::remove_all<typename MatrixType::ConjugateReturnType>::type MatrixConjugateReturnType;
+
+ public:
+ using Base::evalToLazy;
+
+
+ typedef typename internal::traits<TriangularView>::StorageKind StorageKind;
+ typedef typename internal::traits<TriangularView>::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<typename Other> TriangularView& operator+=(const DenseBase<Other>& other) { return *this = m_matrix + other.derived(); }
+ /** \sa MatrixBase::operator-=() */
+ template<typename Other> TriangularView& operator-=(const DenseBase<Other>& other) { return *this = m_matrix - other.derived(); }
+ /** \sa MatrixBase::operator*=() */
+ TriangularView& operator*=(const typename internal::traits<MatrixType>::Scalar& other) { return *this = m_matrix * other; }
+ /** \sa MatrixBase::operator/=() */
+ TriangularView& operator/=(const typename internal::traits<MatrixType>::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<MatrixTypeNestedCleaned*>(&m_matrix); }
+
+ /** Assigns a triangular matrix to a triangular part of a dense matrix */
+ template<typename OtherDerived>
+ TriangularView& operator=(const TriangularBase<OtherDerived>& other);
+
+ template<typename OtherDerived>
+ TriangularView& operator=(const MatrixBase<OtherDerived>& other);
+
+ TriangularView& operator=(const TriangularView& other)
+ { return *this = other.nestedExpression(); }
+
+ template<typename OtherDerived>
+ void lazyAssign(const TriangularBase<OtherDerived>& other);
+
+ template<typename OtherDerived>
+ void lazyAssign(const MatrixBase<OtherDerived>& other);
+
+ /** \sa MatrixBase::conjugate() */
+ inline TriangularView<MatrixConjugateReturnType,Mode> conjugate()
+ { return m_matrix.conjugate(); }
+ /** \sa MatrixBase::conjugate() const */
+ inline const TriangularView<MatrixConjugateReturnType,Mode> conjugate() const
+ { return m_matrix.conjugate(); }
+
+ /** \sa MatrixBase::adjoint() const */
+ inline const TriangularView<const typename MatrixType::AdjointReturnType,TransposeMode> adjoint() const
+ { return m_matrix.adjoint(); }
+
+ /** \sa MatrixBase::transpose() */
+ inline TriangularView<Transpose<MatrixType>,TransposeMode> transpose()
+ {
+ EIGEN_STATIC_ASSERT_LVALUE(MatrixType)
+ return m_matrix.const_cast_derived().transpose();
+ }
+ /** \sa MatrixBase::transpose() const */
+ inline const TriangularView<Transpose<MatrixType>,TransposeMode> transpose() const
+ {
+ return m_matrix.transpose();
+ }
+
+ /** Efficient triangular matrix times vector/matrix product */
+ template<typename OtherDerived>
+ TriangularProduct<Mode,true,MatrixType,false,OtherDerived, OtherDerived::IsVectorAtCompileTime>
+ operator*(const MatrixBase<OtherDerived>& rhs) const
+ {
+ return TriangularProduct
+ <Mode,true,MatrixType,false,OtherDerived,OtherDerived::IsVectorAtCompileTime>
+ (m_matrix, rhs.derived());
+ }
+
+ /** Efficient vector/matrix times triangular matrix product */
+ template<typename OtherDerived> friend
+ TriangularProduct<Mode,false,OtherDerived,OtherDerived::IsVectorAtCompileTime,MatrixType,false>
+ operator*(const MatrixBase<OtherDerived>& lhs, const TriangularView& rhs)
+ {
+ return TriangularProduct
+ <Mode,false,OtherDerived,OtherDerived::IsVectorAtCompileTime,MatrixType,false>
+ (lhs.derived(),rhs.m_matrix);
+ }
+
+ #ifdef EIGEN2_SUPPORT
+ template<typename OtherDerived>
+ struct eigen2_product_return_type
+ {
+ typedef typename TriangularView<MatrixType,Mode>::DenseMatrixType DenseMatrixType;
+ typedef typename OtherDerived::PlainObject::DenseType OtherPlainObject;
+ typedef typename ProductReturnType<DenseMatrixType, OtherPlainObject>::Type ProdRetType;
+ typedef typename ProdRetType::PlainObject type;
+ };
+ template<typename OtherDerived>
+ const typename eigen2_product_return_type<OtherDerived>::type
+ operator*(const EigenBase<OtherDerived>& rhs) const
+ {
+ typename OtherDerived::PlainObject::DenseType rhsPlainObject;
+ rhs.evalTo(rhsPlainObject);
+ return this->toDenseMatrix() * rhsPlainObject;
+ }
+ template<typename OtherMatrixType>
+ bool isApprox(const TriangularView<OtherMatrixType, Mode>& other, typename NumTraits<Scalar>::Real precision = NumTraits<Scalar>::dummy_precision()) const
+ {
+ return this->toDenseMatrix().isApprox(other.toDenseMatrix(), precision);
+ }
+ template<typename OtherDerived>
+ bool isApprox(const MatrixBase<OtherDerived>& other, typename NumTraits<Scalar>::Real precision = NumTraits<Scalar>::dummy_precision()) const
+ {
+ return this->toDenseMatrix().isApprox(other, precision);
+ }
+ #endif // EIGEN2_SUPPORT
+
+ template<int Side, typename Other>
+ inline const internal::triangular_solve_retval<Side,TriangularView, Other>
+ solve(const MatrixBase<Other>& other) const;
+
+ template<int Side, typename OtherDerived>
+ void solveInPlace(const MatrixBase<OtherDerived>& other) const;
+
+ template<typename Other>
+ inline const internal::triangular_solve_retval<OnTheLeft,TriangularView, Other>
+ solve(const MatrixBase<Other>& other) const
+ { return solve<OnTheLeft>(other); }
+
+ template<typename OtherDerived>
+ void solveInPlace(const MatrixBase<OtherDerived>& other) const
+ { return solveInPlace<OnTheLeft>(other); }
+
+ const SelfAdjointView<MatrixTypeNestedNonRef,Mode> selfadjointView() const
+ {
+ EIGEN_STATIC_ASSERT((Mode&UnitDiag)==0,PROGRAMMING_ERROR);
+ return SelfAdjointView<MatrixTypeNestedNonRef,Mode>(m_matrix);
+ }
+ SelfAdjointView<MatrixTypeNestedNonRef,Mode> selfadjointView()
+ {
+ EIGEN_STATIC_ASSERT((Mode&UnitDiag)==0,PROGRAMMING_ERROR);
+ return SelfAdjointView<MatrixTypeNestedNonRef,Mode>(m_matrix);
+ }
+
+ template<typename OtherDerived>
+ void swap(TriangularBase<OtherDerived> const & other)
+ {
+ TriangularView<SwapWrapper<MatrixType>,Mode>(const_cast<MatrixType&>(m_matrix)).lazyAssign(other.derived());
+ }
+
+ template<typename OtherDerived>
+ void swap(MatrixBase<OtherDerived> const & other)
+ {
+ SwapWrapper<MatrixType> swaper(const_cast<MatrixType&>(m_matrix));
+ TriangularView<SwapWrapper<MatrixType>,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<typename ProductDerived, typename Lhs, typename Rhs>
+ EIGEN_STRONG_INLINE TriangularView& operator=(const ProductBase<ProductDerived, Lhs,Rhs>& other)
+ {
+ setZero();
+ return assignProduct(other,1);
+ }
+
+ template<typename ProductDerived, typename Lhs, typename Rhs>
+ EIGEN_STRONG_INLINE TriangularView& operator+=(const ProductBase<ProductDerived, Lhs,Rhs>& other)
+ {
+ return assignProduct(other,1);
+ }
+
+ template<typename ProductDerived, typename Lhs, typename Rhs>
+ EIGEN_STRONG_INLINE TriangularView& operator-=(const ProductBase<ProductDerived, Lhs,Rhs>& other)
+ {
+ return assignProduct(other,-1);
+ }
+
+
+ template<typename ProductDerived>
+ EIGEN_STRONG_INLINE TriangularView& operator=(const ScaledProduct<ProductDerived>& other)
+ {
+ setZero();
+ return assignProduct(other,other.alpha());
+ }
+
+ template<typename ProductDerived>
+ EIGEN_STRONG_INLINE TriangularView& operator+=(const ScaledProduct<ProductDerived>& other)
+ {
+ return assignProduct(other,other.alpha());
+ }
+
+ template<typename ProductDerived>
+ EIGEN_STRONG_INLINE TriangularView& operator-=(const ScaledProduct<ProductDerived>& other)
+ {
+ return assignProduct(other,-other.alpha());
+ }
+
+ protected:
+
+ template<typename ProductDerived, typename Lhs, typename Rhs>
+ EIGEN_STRONG_INLINE TriangularView& assignProduct(const ProductBase<ProductDerived, Lhs,Rhs>& prod, const Scalar& alpha);
+
+ MatrixTypeNested m_matrix;
+};
+
+/***************************************************************************
+* Implementation of triangular evaluation/assignment
+***************************************************************************/
+
+namespace internal {
+
+template<typename Derived1, typename Derived2, unsigned int Mode, int UnrollCount, bool ClearOpposite>
+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<Derived1, Derived2, Mode, UnrollCount-1, ClearOpposite>::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<typename Derived1, typename Derived2, unsigned int Mode, bool ClearOpposite>
+struct triangular_assignment_selector<Derived1, Derived2, Mode, 0, ClearOpposite>
+{
+ static inline void run(Derived1 &, const Derived2 &) {}
+};
+
+template<typename Derived1, typename Derived2, bool ClearOpposite>
+struct triangular_assignment_selector<Derived1, Derived2, Upper, Dynamic, ClearOpposite>
+{
+ 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<typename Derived1, typename Derived2, bool ClearOpposite>
+struct triangular_assignment_selector<Derived1, Derived2, Lower, Dynamic, ClearOpposite>
+{
+ 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<typename Derived1::Scalar>(0);
+ }
+ }
+};
+
+template<typename Derived1, typename Derived2, bool ClearOpposite>
+struct triangular_assignment_selector<Derived1, Derived2, StrictlyUpper, Dynamic, ClearOpposite>
+{
+ 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; i < dst.rows(); ++i)
+ dst.coeffRef(i, j) = 0;
+ }
+ }
+};
+
+template<typename Derived1, typename Derived2, bool ClearOpposite>
+struct triangular_assignment_selector<Derived1, Derived2, StrictlyLower, Dynamic, ClearOpposite>
+{
+ 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<typename Derived1::Scalar>(0);
+ }
+ }
+};
+
+template<typename Derived1, typename Derived2, bool ClearOpposite>
+struct triangular_assignment_selector<Derived1, Derived2, UnitUpper, Dynamic, ClearOpposite>
+{
+ 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<typename Derived1, typename Derived2, bool ClearOpposite>
+struct triangular_assignment_selector<Derived1, Derived2, UnitLower, Dynamic, ClearOpposite>
+{
+ 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<typename MatrixType, unsigned int Mode>
+template<typename OtherDerived>
+inline TriangularView<MatrixType, Mode>&
+TriangularView<MatrixType, Mode>::operator=(const MatrixBase<OtherDerived>& other)
+{
+ if(OtherDerived::Flags & EvalBeforeAssigningBit)
+ {
+ typename internal::plain_matrix_type<OtherDerived>::type other_evaluated(other.rows(), other.cols());
+ other_evaluated.template triangularView<Mode>().lazyAssign(other.derived());
+ lazyAssign(other_evaluated);
+ }
+ else
+ lazyAssign(other.derived());
+ return *this;
+}
+
+// FIXME should we keep that possibility
+template<typename MatrixType, unsigned int Mode>
+template<typename OtherDerived>
+void TriangularView<MatrixType, Mode>::lazyAssign(const MatrixBase<OtherDerived>& other)
+{
+ enum {
+ unroll = MatrixType::SizeAtCompileTime != Dynamic
+ && internal::traits<OtherDerived>::CoeffReadCost != Dynamic
+ && MatrixType::SizeAtCompileTime*internal::traits<OtherDerived>::CoeffReadCost/2 <= EIGEN_UNROLLING_LIMIT
+ };
+ eigen_assert(m_matrix.rows() == other.rows() && m_matrix.cols() == other.cols());
+
+ internal::triangular_assignment_selector
+ <MatrixType, OtherDerived, int(Mode),
+ unroll ? int(MatrixType::SizeAtCompileTime) : Dynamic,
+ false // do not change the opposite triangular part
+ >::run(m_matrix.const_cast_derived(), other.derived());
+}
+
+
+
+template<typename MatrixType, unsigned int Mode>
+template<typename OtherDerived>
+inline TriangularView<MatrixType, Mode>&
+TriangularView<MatrixType, Mode>::operator=(const TriangularBase<OtherDerived>& other)
+{
+ eigen_assert(Mode == int(OtherDerived::Mode));
+ if(internal::traits<OtherDerived>::Flags & EvalBeforeAssigningBit)
+ {
+ typename OtherDerived::DenseMatrixType other_evaluated(other.rows(), other.cols());
+ other_evaluated.template triangularView<Mode>().lazyAssign(other.derived().nestedExpression());
+ lazyAssign(other_evaluated);
+ }
+ else
+ lazyAssign(other.derived().nestedExpression());
+ return *this;
+}
+
+template<typename MatrixType, unsigned int Mode>
+template<typename OtherDerived>
+void TriangularView<MatrixType, Mode>::lazyAssign(const TriangularBase<OtherDerived>& other)
+{
+ enum {
+ unroll = MatrixType::SizeAtCompileTime != Dynamic
+ && internal::traits<OtherDerived>::CoeffReadCost != Dynamic
+ && MatrixType::SizeAtCompileTime * internal::traits<OtherDerived>::CoeffReadCost / 2
+ <= EIGEN_UNROLLING_LIMIT
+ };
+ eigen_assert(m_matrix.rows() == other.rows() && m_matrix.cols() == other.cols());
+
+ internal::triangular_assignment_selector
+ <MatrixType, OtherDerived, int(Mode),
+ unroll ? int(MatrixType::SizeAtCompileTime) : Dynamic,
+ false // preserve the opposite triangular part
+ >::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<typename Derived>
+template<typename DenseDerived>
+void TriangularBase<Derived>::evalTo(MatrixBase<DenseDerived> &other) const
+{
+ if(internal::traits<Derived>::Flags & EvalBeforeAssigningBit)
+ {
+ typename internal::plain_matrix_type<Derived>::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<typename Derived>
+template<typename DenseDerived>
+void TriangularBase<Derived>::evalToLazy(MatrixBase<DenseDerived> &other) const
+{
+ enum {
+ unroll = DenseDerived::SizeAtCompileTime != Dynamic
+ && internal::traits<Derived>::CoeffReadCost != Dynamic
+ && DenseDerived::SizeAtCompileTime * internal::traits<Derived>::CoeffReadCost / 2
+ <= EIGEN_UNROLLING_LIMIT
+ };
+ other.derived().resize(this->rows(), this->cols());
+
+ internal::triangular_assignment_selector
+ <DenseDerived, typename internal::traits<Derived>::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<typename MatrixType, unsigned int Mode>
+struct eigen2_part_return_type
+{
+ typedef TriangularView<MatrixType, Mode> type;
+};
+
+template<typename MatrixType>
+struct eigen2_part_return_type<MatrixType, SelfAdjoint>
+{
+ typedef SelfAdjointView<MatrixType, Upper> type;
+};
+}
+
+/** \deprecated use MatrixBase::triangularView() */
+template<typename Derived>
+template<unsigned int Mode>
+const typename internal::eigen2_part_return_type<Derived, Mode>::type MatrixBase<Derived>::part() const
+{
+ return derived();
+}
+
+/** \deprecated use MatrixBase::triangularView() */
+template<typename Derived>
+template<unsigned int Mode>
+typename internal::eigen2_part_return_type<Derived, Mode>::type MatrixBase<Derived>::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<typename Derived>
+template<unsigned int Mode>
+typename MatrixBase<Derived>::template TriangularViewReturnType<Mode>::Type
+MatrixBase<Derived>::triangularView()
+{
+ return derived();
+}
+
+/** This is the const version of MatrixBase::triangularView() */
+template<typename Derived>
+template<unsigned int Mode>
+typename MatrixBase<Derived>::template ConstTriangularViewReturnType<Mode>::Type
+MatrixBase<Derived>::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<typename Derived>
+bool MatrixBase<Derived>::isUpperTriangular(RealScalar prec) const
+{
+ RealScalar maxAbsOnUpperPart = static_cast<RealScalar>(-1);
+ for(Index j = 0; j < cols(); ++j)
+ {
+ Index maxi = (std::min)(j, rows()-1);
+ for(Index i = 0; i <= maxi; ++i)
+ {
+ RealScalar absValue = internal::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(internal::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<typename Derived>
+bool MatrixBase<Derived>::isLowerTriangular(RealScalar prec) const
+{
+ RealScalar maxAbsOnLowerPart = static_cast<RealScalar>(-1);
+ for(Index j = 0; j < cols(); ++j)
+ for(Index i = j; i < rows(); ++i)
+ {
+ RealScalar absValue = internal::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(internal::abs(coeff(i, j)) > threshold) return false;
+ }
+ return true;
+}
+
+} // end namespace Eigen
+
+#endif // EIGEN_TRIANGULARMATRIX_H
diff --git a/Eigen/src/Core/VectorBlock.h b/Eigen/src/Core/VectorBlock.h
new file mode 100644
index 000000000..6f4effca0
--- /dev/null
+++ b/Eigen/src/Core/VectorBlock.h
@@ -0,0 +1,284 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra.
+//
+// Copyright (C) 2008-2010 Gael Guennebaud <gael.guennebaud@inria.fr>
+// Copyright (C) 2006-2008 Benoit Jacob <jacob.benoit.1@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 EIGEN_VECTORBLOCK_H
+#define EIGEN_VECTORBLOCK_H
+
+namespace Eigen {
+
+/** \class VectorBlock
+ * \ingroup Core_Module
+ *
+ * \brief Expression of a fixed-size or dynamic-size sub-vector
+ *
+ * \param VectorType the type of the object in which we are taking a sub-vector
+ * \param Size size of the sub-vector we are taking at compile time (optional)
+ *
+ * This class represents an expression of either a fixed-size or dynamic-size sub-vector.
+ * It is the return type of DenseBase::segment(Index,Index) and DenseBase::segment<int>(Index) and
+ * most of the time this is the only way it is used.
+ *
+ * However, if you want to directly maniputate sub-vector 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_VectorBlock.cpp
+ * Output: \verbinclude class_VectorBlock.out
+ *
+ * \note Even though this expression has dynamic size, in the case where \a VectorType
+ * 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_FixedVectorBlock.cpp
+ * Output: \verbinclude class_FixedVectorBlock.out
+ *
+ * \sa class Block, DenseBase::segment(Index,Index,Index,Index), DenseBase::segment(Index,Index)
+ */
+
+namespace internal {
+template<typename VectorType, int Size>
+struct traits<VectorBlock<VectorType, Size> >
+ : public traits<Block<VectorType,
+ traits<VectorType>::Flags & RowMajorBit ? 1 : Size,
+ traits<VectorType>::Flags & RowMajorBit ? Size : 1> >
+{
+};
+}
+
+template<typename VectorType, int Size> class VectorBlock
+ : public Block<VectorType,
+ internal::traits<VectorType>::Flags & RowMajorBit ? 1 : Size,
+ internal::traits<VectorType>::Flags & RowMajorBit ? Size : 1>
+{
+ typedef Block<VectorType,
+ internal::traits<VectorType>::Flags & RowMajorBit ? 1 : Size,
+ internal::traits<VectorType>::Flags & RowMajorBit ? Size : 1> Base;
+ enum {
+ IsColVector = !(internal::traits<VectorType>::Flags & RowMajorBit)
+ };
+ public:
+ EIGEN_DENSE_PUBLIC_INTERFACE(VectorBlock)
+
+ using Base::operator=;
+
+ /** Dynamic-size constructor
+ */
+ inline VectorBlock(VectorType& vector, Index start, Index size)
+ : Base(vector,
+ IsColVector ? start : 0, IsColVector ? 0 : start,
+ IsColVector ? size : 1, IsColVector ? 1 : size)
+ {
+ EIGEN_STATIC_ASSERT_VECTOR_ONLY(VectorBlock);
+ }
+
+ /** Fixed-size constructor
+ */
+ inline VectorBlock(VectorType& vector, Index start)
+ : Base(vector, IsColVector ? start : 0, IsColVector ? 0 : start)
+ {
+ EIGEN_STATIC_ASSERT_VECTOR_ONLY(VectorBlock);
+ }
+};
+
+
+/** \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 size 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)
+ */
+template<typename Derived>
+inline typename DenseBase<Derived>::SegmentReturnType
+DenseBase<Derived>::segment(Index start, Index size)
+{
+ EIGEN_STATIC_ASSERT_VECTOR_ONLY(Derived)
+ return SegmentReturnType(derived(), start, size);
+}
+
+/** This is the const version of segment(Index,Index).*/
+template<typename Derived>
+inline typename DenseBase<Derived>::ConstSegmentReturnType
+DenseBase<Derived>::segment(Index start, Index size) const
+{
+ EIGEN_STATIC_ASSERT_VECTOR_ONLY(Derived)
+ return ConstSegmentReturnType(derived(), start, size);
+}
+
+/** \returns a dynamic-size expression of the first coefficients of *this.
+ *
+ * \only_for_vectors
+ *
+ * \param size the number of coefficients in the block
+ *
+ * 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)
+ */
+template<typename Derived>
+inline typename DenseBase<Derived>::SegmentReturnType
+DenseBase<Derived>::head(Index size)
+{
+ EIGEN_STATIC_ASSERT_VECTOR_ONLY(Derived)
+ return SegmentReturnType(derived(), 0, size);
+}
+
+/** This is the const version of head(Index).*/
+template<typename Derived>
+inline typename DenseBase<Derived>::ConstSegmentReturnType
+DenseBase<Derived>::head(Index size) const
+{
+ EIGEN_STATIC_ASSERT_VECTOR_ONLY(Derived)
+ return ConstSegmentReturnType(derived(), 0, size);
+}
+
+/** \returns a dynamic-size expression of the last coefficients of *this.
+ *
+ * \only_for_vectors
+ *
+ * \param size the number of coefficients in the block
+ *
+ * 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)
+ */
+template<typename Derived>
+inline typename DenseBase<Derived>::SegmentReturnType
+DenseBase<Derived>::tail(Index size)
+{
+ EIGEN_STATIC_ASSERT_VECTOR_ONLY(Derived)
+ return SegmentReturnType(derived(), this->size() - size, size);
+}
+
+/** This is the const version of tail(Index).*/
+template<typename Derived>
+inline typename DenseBase<Derived>::ConstSegmentReturnType
+DenseBase<Derived>::tail(Index size) const
+{
+ EIGEN_STATIC_ASSERT_VECTOR_ONLY(Derived)
+ return ConstSegmentReturnType(derived(), this->size() - size, size);
+}
+
+/** \returns a fixed-size expression of a segment (i.e. a vector block) in \c *this
+ *
+ * \only_for_vectors
+ *
+ * The template parameter \a Size is the number of coefficients in the block
+ *
+ * \param start the index of the first element of the sub-vector
+ *
+ * Example: \include MatrixBase_template_int_segment.cpp
+ * Output: \verbinclude MatrixBase_template_int_segment.out
+ *
+ * \sa class Block
+ */
+template<typename Derived>
+template<int Size>
+inline typename DenseBase<Derived>::template FixedSegmentReturnType<Size>::Type
+DenseBase<Derived>::segment(Index start)
+{
+ EIGEN_STATIC_ASSERT_VECTOR_ONLY(Derived)
+ return typename FixedSegmentReturnType<Size>::Type(derived(), start);
+}
+
+/** This is the const version of segment<int>(Index).*/
+template<typename Derived>
+template<int Size>
+inline typename DenseBase<Derived>::template ConstFixedSegmentReturnType<Size>::Type
+DenseBase<Derived>::segment(Index start) const
+{
+ EIGEN_STATIC_ASSERT_VECTOR_ONLY(Derived)
+ return typename ConstFixedSegmentReturnType<Size>::Type(derived(), start);
+}
+
+/** \returns a fixed-size expression of the first coefficients of *this.
+ *
+ * \only_for_vectors
+ *
+ * The template parameter \a Size is the number of coefficients in the block
+ *
+ * Example: \include MatrixBase_template_int_start.cpp
+ * Output: \verbinclude MatrixBase_template_int_start.out
+ *
+ * \sa class Block
+ */
+template<typename Derived>
+template<int Size>
+inline typename DenseBase<Derived>::template FixedSegmentReturnType<Size>::Type
+DenseBase<Derived>::head()
+{
+ EIGEN_STATIC_ASSERT_VECTOR_ONLY(Derived)
+ return typename FixedSegmentReturnType<Size>::Type(derived(), 0);
+}
+
+/** This is the const version of head<int>().*/
+template<typename Derived>
+template<int Size>
+inline typename DenseBase<Derived>::template ConstFixedSegmentReturnType<Size>::Type
+DenseBase<Derived>::head() const
+{
+ EIGEN_STATIC_ASSERT_VECTOR_ONLY(Derived)
+ return typename ConstFixedSegmentReturnType<Size>::Type(derived(), 0);
+}
+
+/** \returns a fixed-size expression of the last coefficients of *this.
+ *
+ * \only_for_vectors
+ *
+ * The template parameter \a Size is the number of coefficients in the block
+ *
+ * Example: \include MatrixBase_template_int_end.cpp
+ * Output: \verbinclude MatrixBase_template_int_end.out
+ *
+ * \sa class Block
+ */
+template<typename Derived>
+template<int Size>
+inline typename DenseBase<Derived>::template FixedSegmentReturnType<Size>::Type
+DenseBase<Derived>::tail()
+{
+ EIGEN_STATIC_ASSERT_VECTOR_ONLY(Derived)
+ return typename FixedSegmentReturnType<Size>::Type(derived(), size() - Size);
+}
+
+/** This is the const version of tail<int>.*/
+template<typename Derived>
+template<int Size>
+inline typename DenseBase<Derived>::template ConstFixedSegmentReturnType<Size>::Type
+DenseBase<Derived>::tail() const
+{
+ EIGEN_STATIC_ASSERT_VECTOR_ONLY(Derived)
+ return typename ConstFixedSegmentReturnType<Size>::Type(derived(), size() - Size);
+}
+
+} // end namespace Eigen
+
+#endif // EIGEN_VECTORBLOCK_H
diff --git a/Eigen/src/Core/VectorwiseOp.h b/Eigen/src/Core/VectorwiseOp.h
new file mode 100644
index 000000000..862c0f336
--- /dev/null
+++ b/Eigen/src/Core/VectorwiseOp.h
@@ -0,0 +1,598 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra.
+//
+// Copyright (C) 2008-2010 Gael Guennebaud <gael.guennebaud@inria.fr>
+// Copyright (C) 2006-2008 Benoit Jacob <jacob.benoit.1@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 EIGEN_PARTIAL_REDUX_H
+#define EIGEN_PARTIAL_REDUX_H
+
+namespace Eigen {
+
+/** \class PartialReduxExpr
+ * \ingroup Core_Module
+ *
+ * \brief Generic expression of a partially reduxed matrix
+ *
+ * \tparam MatrixType the type of the matrix we are applying the redux operation
+ * \tparam MemberOp type of the member functor
+ * \tparam Direction indicates the direction of the redux (#Vertical or #Horizontal)
+ *
+ * This class represents an expression of a partial redux operator of a matrix.
+ * It is the return type of some VectorwiseOp functions,
+ * and most of the time this is the only way it is used.
+ *
+ * \sa class VectorwiseOp
+ */
+
+template< typename MatrixType, typename MemberOp, int Direction>
+class PartialReduxExpr;
+
+namespace internal {
+template<typename MatrixType, typename MemberOp, int Direction>
+struct traits<PartialReduxExpr<MatrixType, MemberOp, Direction> >
+ : traits<MatrixType>
+{
+ typedef typename MemberOp::result_type Scalar;
+ typedef typename traits<MatrixType>::StorageKind StorageKind;
+ typedef typename traits<MatrixType>::XprKind XprKind;
+ typedef typename MatrixType::Scalar InputScalar;
+ typedef typename nested<MatrixType>::type MatrixTypeNested;
+ typedef typename remove_all<MatrixTypeNested>::type _MatrixTypeNested;
+ enum {
+ RowsAtCompileTime = Direction==Vertical ? 1 : MatrixType::RowsAtCompileTime,
+ ColsAtCompileTime = Direction==Horizontal ? 1 : MatrixType::ColsAtCompileTime,
+ MaxRowsAtCompileTime = Direction==Vertical ? 1 : MatrixType::MaxRowsAtCompileTime,
+ MaxColsAtCompileTime = Direction==Horizontal ? 1 : MatrixType::MaxColsAtCompileTime,
+ Flags0 = (unsigned int)_MatrixTypeNested::Flags & HereditaryBits,
+ Flags = (Flags0 & ~RowMajorBit) | (RowsAtCompileTime == 1 ? RowMajorBit : 0),
+ TraversalSize = Direction==Vertical ? RowsAtCompileTime : ColsAtCompileTime
+ };
+ #if EIGEN_GNUC_AT_LEAST(3,4)
+ typedef typename MemberOp::template Cost<InputScalar,int(TraversalSize)> CostOpType;
+ #else
+ typedef typename MemberOp::template Cost<InputScalar,TraversalSize> CostOpType;
+ #endif
+ enum {
+ CoeffReadCost = TraversalSize * traits<_MatrixTypeNested>::CoeffReadCost + int(CostOpType::value)
+ };
+};
+}
+
+template< typename MatrixType, typename MemberOp, int Direction>
+class PartialReduxExpr : internal::no_assignment_operator,
+ public internal::dense_xpr_base< PartialReduxExpr<MatrixType, MemberOp, Direction> >::type
+{
+ public:
+
+ typedef typename internal::dense_xpr_base<PartialReduxExpr>::type Base;
+ EIGEN_DENSE_PUBLIC_INTERFACE(PartialReduxExpr)
+ typedef typename internal::traits<PartialReduxExpr>::MatrixTypeNested MatrixTypeNested;
+ typedef typename internal::traits<PartialReduxExpr>::_MatrixTypeNested _MatrixTypeNested;
+
+ PartialReduxExpr(const MatrixType& mat, const MemberOp& func = MemberOp())
+ : m_matrix(mat), m_functor(func) {}
+
+ Index rows() const { return (Direction==Vertical ? 1 : m_matrix.rows()); }
+ Index cols() const { return (Direction==Horizontal ? 1 : m_matrix.cols()); }
+
+ EIGEN_STRONG_INLINE const Scalar coeff(Index i, Index j) const
+ {
+ if (Direction==Vertical)
+ return m_functor(m_matrix.col(j));
+ else
+ return m_functor(m_matrix.row(i));
+ }
+
+ const Scalar coeff(Index index) const
+ {
+ if (Direction==Vertical)
+ return m_functor(m_matrix.col(index));
+ else
+ return m_functor(m_matrix.row(index));
+ }
+
+ protected:
+ MatrixTypeNested m_matrix;
+ const MemberOp m_functor;
+};
+
+#define EIGEN_MEMBER_FUNCTOR(MEMBER,COST) \
+ template <typename ResultType> \
+ struct member_##MEMBER { \
+ EIGEN_EMPTY_STRUCT_CTOR(member_##MEMBER) \
+ typedef ResultType result_type; \
+ template<typename Scalar, int Size> struct Cost \
+ { enum { value = COST }; }; \
+ template<typename XprType> \
+ EIGEN_STRONG_INLINE ResultType operator()(const XprType& mat) const \
+ { return mat.MEMBER(); } \
+ }
+
+namespace internal {
+
+EIGEN_MEMBER_FUNCTOR(squaredNorm, Size * NumTraits<Scalar>::MulCost + (Size-1)*NumTraits<Scalar>::AddCost);
+EIGEN_MEMBER_FUNCTOR(norm, (Size+5) * NumTraits<Scalar>::MulCost + (Size-1)*NumTraits<Scalar>::AddCost);
+EIGEN_MEMBER_FUNCTOR(stableNorm, (Size+5) * NumTraits<Scalar>::MulCost + (Size-1)*NumTraits<Scalar>::AddCost);
+EIGEN_MEMBER_FUNCTOR(blueNorm, (Size+5) * NumTraits<Scalar>::MulCost + (Size-1)*NumTraits<Scalar>::AddCost);
+EIGEN_MEMBER_FUNCTOR(hypotNorm, (Size-1) * functor_traits<scalar_hypot_op<Scalar> >::Cost );
+EIGEN_MEMBER_FUNCTOR(sum, (Size-1)*NumTraits<Scalar>::AddCost);
+EIGEN_MEMBER_FUNCTOR(mean, (Size-1)*NumTraits<Scalar>::AddCost + NumTraits<Scalar>::MulCost);
+EIGEN_MEMBER_FUNCTOR(minCoeff, (Size-1)*NumTraits<Scalar>::AddCost);
+EIGEN_MEMBER_FUNCTOR(maxCoeff, (Size-1)*NumTraits<Scalar>::AddCost);
+EIGEN_MEMBER_FUNCTOR(all, (Size-1)*NumTraits<Scalar>::AddCost);
+EIGEN_MEMBER_FUNCTOR(any, (Size-1)*NumTraits<Scalar>::AddCost);
+EIGEN_MEMBER_FUNCTOR(count, (Size-1)*NumTraits<Scalar>::AddCost);
+EIGEN_MEMBER_FUNCTOR(prod, (Size-1)*NumTraits<Scalar>::MulCost);
+
+
+template <typename BinaryOp, typename Scalar>
+struct member_redux {
+ typedef typename result_of<
+ BinaryOp(Scalar)
+ >::type result_type;
+ template<typename _Scalar, int Size> struct Cost
+ { enum { value = (Size-1) * functor_traits<BinaryOp>::Cost }; };
+ member_redux(const BinaryOp func) : m_functor(func) {}
+ template<typename Derived>
+ inline result_type operator()(const DenseBase<Derived>& mat) const
+ { return mat.redux(m_functor); }
+ const BinaryOp m_functor;
+};
+}
+
+/** \class VectorwiseOp
+ * \ingroup Core_Module
+ *
+ * \brief Pseudo expression providing partial reduction operations
+ *
+ * \param ExpressionType the type of the object on which to do partial reductions
+ * \param Direction indicates the direction of the redux (#Vertical or #Horizontal)
+ *
+ * This class represents a pseudo expression with partial reduction features.
+ * It is the return type of DenseBase::colwise() and DenseBase::rowwise()
+ * and most of the time this is the only way it is used.
+ *
+ * Example: \include MatrixBase_colwise.cpp
+ * Output: \verbinclude MatrixBase_colwise.out
+ *
+ * \sa DenseBase::colwise(), DenseBase::rowwise(), class PartialReduxExpr
+ */
+template<typename ExpressionType, int Direction> class VectorwiseOp
+{
+ public:
+
+ typedef typename ExpressionType::Scalar Scalar;
+ typedef typename ExpressionType::RealScalar RealScalar;
+ typedef typename ExpressionType::Index Index;
+ typedef typename internal::conditional<internal::must_nest_by_value<ExpressionType>::ret,
+ ExpressionType, ExpressionType&>::type ExpressionTypeNested;
+ typedef typename internal::remove_all<ExpressionTypeNested>::type ExpressionTypeNestedCleaned;
+
+ template<template<typename _Scalar> class Functor,
+ typename Scalar=typename internal::traits<ExpressionType>::Scalar> struct ReturnType
+ {
+ typedef PartialReduxExpr<ExpressionType,
+ Functor<Scalar>,
+ Direction
+ > Type;
+ };
+
+ template<typename BinaryOp> struct ReduxReturnType
+ {
+ typedef PartialReduxExpr<ExpressionType,
+ internal::member_redux<BinaryOp,typename internal::traits<ExpressionType>::Scalar>,
+ Direction
+ > Type;
+ };
+
+ enum {
+ IsVertical = (Direction==Vertical) ? 1 : 0,
+ IsHorizontal = (Direction==Horizontal) ? 1 : 0
+ };
+
+ protected:
+
+ /** \internal
+ * \returns the i-th subvector according to the \c Direction */
+ typedef typename internal::conditional<Direction==Vertical,
+ typename ExpressionType::ColXpr,
+ typename ExpressionType::RowXpr>::type SubVector;
+ SubVector subVector(Index i)
+ {
+ return SubVector(m_matrix.derived(),i);
+ }
+
+ /** \internal
+ * \returns the number of subvectors in the direction \c Direction */
+ Index subVectors() const
+ { return Direction==Vertical?m_matrix.cols():m_matrix.rows(); }
+
+ template<typename OtherDerived> struct ExtendedType {
+ typedef Replicate<OtherDerived,
+ Direction==Vertical ? 1 : ExpressionType::RowsAtCompileTime,
+ Direction==Horizontal ? 1 : ExpressionType::ColsAtCompileTime> Type;
+ };
+
+ /** \internal
+ * Replicates a vector to match the size of \c *this */
+ template<typename OtherDerived>
+ typename ExtendedType<OtherDerived>::Type
+ extendedTo(const DenseBase<OtherDerived>& other) const
+ {
+ EIGEN_STATIC_ASSERT(EIGEN_IMPLIES(Direction==Vertical, OtherDerived::MaxColsAtCompileTime==1),
+ YOU_PASSED_A_ROW_VECTOR_BUT_A_COLUMN_VECTOR_WAS_EXPECTED)
+ EIGEN_STATIC_ASSERT(EIGEN_IMPLIES(Direction==Horizontal, OtherDerived::MaxRowsAtCompileTime==1),
+ YOU_PASSED_A_COLUMN_VECTOR_BUT_A_ROW_VECTOR_WAS_EXPECTED)
+ return typename ExtendedType<OtherDerived>::Type
+ (other.derived(),
+ Direction==Vertical ? 1 : m_matrix.rows(),
+ Direction==Horizontal ? 1 : m_matrix.cols());
+ }
+
+ public:
+
+ inline VectorwiseOp(ExpressionType& matrix) : m_matrix(matrix) {}
+
+ /** \internal */
+ inline const ExpressionType& _expression() const { return m_matrix; }
+
+ /** \returns a row or column vector expression of \c *this reduxed by \a func
+ *
+ * The template parameter \a BinaryOp is the type of the functor
+ * of the custom redux operator. Note that func must be an associative operator.
+ *
+ * \sa class VectorwiseOp, DenseBase::colwise(), DenseBase::rowwise()
+ */
+ template<typename BinaryOp>
+ const typename ReduxReturnType<BinaryOp>::Type
+ redux(const BinaryOp& func = BinaryOp()) const
+ { return typename ReduxReturnType<BinaryOp>::Type(_expression(), func); }
+
+ /** \returns a row (or column) vector expression of the smallest coefficient
+ * of each column (or row) of the referenced expression.
+ *
+ * Example: \include PartialRedux_minCoeff.cpp
+ * Output: \verbinclude PartialRedux_minCoeff.out
+ *
+ * \sa DenseBase::minCoeff() */
+ const typename ReturnType<internal::member_minCoeff>::Type minCoeff() const
+ { return _expression(); }
+
+ /** \returns a row (or column) vector expression of the largest coefficient
+ * of each column (or row) of the referenced expression.
+ *
+ * Example: \include PartialRedux_maxCoeff.cpp
+ * Output: \verbinclude PartialRedux_maxCoeff.out
+ *
+ * \sa DenseBase::maxCoeff() */
+ const typename ReturnType<internal::member_maxCoeff>::Type maxCoeff() const
+ { return _expression(); }
+
+ /** \returns a row (or column) vector expression of the squared norm
+ * of each column (or row) of the referenced expression.
+ *
+ * Example: \include PartialRedux_squaredNorm.cpp
+ * Output: \verbinclude PartialRedux_squaredNorm.out
+ *
+ * \sa DenseBase::squaredNorm() */
+ const typename ReturnType<internal::member_squaredNorm,RealScalar>::Type squaredNorm() const
+ { return _expression(); }
+
+ /** \returns a row (or column) vector expression of the norm
+ * of each column (or row) of the referenced expression.
+ *
+ * Example: \include PartialRedux_norm.cpp
+ * Output: \verbinclude PartialRedux_norm.out
+ *
+ * \sa DenseBase::norm() */
+ const typename ReturnType<internal::member_norm,RealScalar>::Type norm() const
+ { return _expression(); }
+
+
+ /** \returns a row (or column) vector expression of the norm
+ * of each column (or row) of the referenced expression, using
+ * blue's algorithm.
+ *
+ * \sa DenseBase::blueNorm() */
+ const typename ReturnType<internal::member_blueNorm,RealScalar>::Type blueNorm() const
+ { return _expression(); }
+
+
+ /** \returns a row (or column) vector expression of the norm
+ * of each column (or row) of the referenced expression, avoiding
+ * underflow and overflow.
+ *
+ * \sa DenseBase::stableNorm() */
+ const typename ReturnType<internal::member_stableNorm,RealScalar>::Type stableNorm() const
+ { return _expression(); }
+
+
+ /** \returns a row (or column) vector expression of the norm
+ * of each column (or row) of the referenced expression, avoiding
+ * underflow and overflow using a concatenation of hypot() calls.
+ *
+ * \sa DenseBase::hypotNorm() */
+ const typename ReturnType<internal::member_hypotNorm,RealScalar>::Type hypotNorm() const
+ { return _expression(); }
+
+ /** \returns a row (or column) vector expression of the sum
+ * of each column (or row) of the referenced expression.
+ *
+ * Example: \include PartialRedux_sum.cpp
+ * Output: \verbinclude PartialRedux_sum.out
+ *
+ * \sa DenseBase::sum() */
+ const typename ReturnType<internal::member_sum>::Type sum() const
+ { return _expression(); }
+
+ /** \returns a row (or column) vector expression of the mean
+ * of each column (or row) of the referenced expression.
+ *
+ * \sa DenseBase::mean() */
+ const typename ReturnType<internal::member_mean>::Type mean() const
+ { return _expression(); }
+
+ /** \returns a row (or column) vector expression representing
+ * whether \b all coefficients of each respective column (or row) are \c true.
+ *
+ * \sa DenseBase::all() */
+ const typename ReturnType<internal::member_all>::Type all() const
+ { return _expression(); }
+
+ /** \returns a row (or column) vector expression representing
+ * whether \b at \b least one coefficient of each respective column (or row) is \c true.
+ *
+ * \sa DenseBase::any() */
+ const typename ReturnType<internal::member_any>::Type any() const
+ { return _expression(); }
+
+ /** \returns a row (or column) vector expression representing
+ * the number of \c true coefficients of each respective column (or row).
+ *
+ * Example: \include PartialRedux_count.cpp
+ * Output: \verbinclude PartialRedux_count.out
+ *
+ * \sa DenseBase::count() */
+ const PartialReduxExpr<ExpressionType, internal::member_count<Index>, Direction> count() const
+ { return _expression(); }
+
+ /** \returns a row (or column) vector expression of the product
+ * of each column (or row) of the referenced expression.
+ *
+ * Example: \include PartialRedux_prod.cpp
+ * Output: \verbinclude PartialRedux_prod.out
+ *
+ * \sa DenseBase::prod() */
+ const typename ReturnType<internal::member_prod>::Type prod() const
+ { return _expression(); }
+
+
+ /** \returns a matrix expression
+ * where each column (or row) are reversed.
+ *
+ * Example: \include Vectorwise_reverse.cpp
+ * Output: \verbinclude Vectorwise_reverse.out
+ *
+ * \sa DenseBase::reverse() */
+ const Reverse<ExpressionType, Direction> reverse() const
+ { return Reverse<ExpressionType, Direction>( _expression() ); }
+
+ typedef Replicate<ExpressionType,Direction==Vertical?Dynamic:1,Direction==Horizontal?Dynamic:1> ReplicateReturnType;
+ const ReplicateReturnType replicate(Index factor) const;
+
+ /**
+ * \return an expression of the replication of each column (or row) of \c *this
+ *
+ * Example: \include DirectionWise_replicate.cpp
+ * Output: \verbinclude DirectionWise_replicate.out
+ *
+ * \sa VectorwiseOp::replicate(Index), DenseBase::replicate(), class Replicate
+ */
+ // NOTE implemented here because of sunstudio's compilation errors
+ template<int Factor> const Replicate<ExpressionType,(IsVertical?Factor:1),(IsHorizontal?Factor:1)>
+ replicate(Index factor = Factor) const
+ {
+ return Replicate<ExpressionType,Direction==Vertical?Factor:1,Direction==Horizontal?Factor:1>
+ (_expression(),Direction==Vertical?factor:1,Direction==Horizontal?factor:1);
+ }
+
+/////////// Artithmetic operators ///////////
+
+ /** Copies the vector \a other to each subvector of \c *this */
+ template<typename OtherDerived>
+ ExpressionType& operator=(const DenseBase<OtherDerived>& other)
+ {
+ EIGEN_STATIC_ASSERT_VECTOR_ONLY(OtherDerived)
+ EIGEN_STATIC_ASSERT_SAME_XPR_KIND(ExpressionType, OtherDerived)
+ //eigen_assert((m_matrix.isNull()) == (other.isNull())); FIXME
+ return const_cast<ExpressionType&>(m_matrix = extendedTo(other.derived()));
+ }
+
+ /** Adds the vector \a other to each subvector of \c *this */
+ template<typename OtherDerived>
+ ExpressionType& operator+=(const DenseBase<OtherDerived>& other)
+ {
+ EIGEN_STATIC_ASSERT_VECTOR_ONLY(OtherDerived)
+ EIGEN_STATIC_ASSERT_SAME_XPR_KIND(ExpressionType, OtherDerived)
+ return const_cast<ExpressionType&>(m_matrix += extendedTo(other.derived()));
+ }
+
+ /** Substracts the vector \a other to each subvector of \c *this */
+ template<typename OtherDerived>
+ ExpressionType& operator-=(const DenseBase<OtherDerived>& other)
+ {
+ EIGEN_STATIC_ASSERT_VECTOR_ONLY(OtherDerived)
+ EIGEN_STATIC_ASSERT_SAME_XPR_KIND(ExpressionType, OtherDerived)
+ return const_cast<ExpressionType&>(m_matrix -= extendedTo(other.derived()));
+ }
+
+ /** Multiples each subvector of \c *this by the vector \a other */
+ template<typename OtherDerived>
+ ExpressionType& operator*=(const DenseBase<OtherDerived>& other)
+ {
+ EIGEN_STATIC_ASSERT_VECTOR_ONLY(OtherDerived)
+ EIGEN_STATIC_ASSERT_ARRAYXPR(ExpressionType)
+ EIGEN_STATIC_ASSERT_SAME_XPR_KIND(ExpressionType, OtherDerived)
+ m_matrix *= extendedTo(other.derived());
+ return const_cast<ExpressionType&>(m_matrix);
+ }
+
+ /** Divides each subvector of \c *this by the vector \a other */
+ template<typename OtherDerived>
+ ExpressionType& operator/=(const DenseBase<OtherDerived>& other)
+ {
+ EIGEN_STATIC_ASSERT_VECTOR_ONLY(OtherDerived)
+ EIGEN_STATIC_ASSERT_ARRAYXPR(ExpressionType)
+ EIGEN_STATIC_ASSERT_SAME_XPR_KIND(ExpressionType, OtherDerived)
+ m_matrix /= extendedTo(other.derived());
+ return const_cast<ExpressionType&>(m_matrix);
+ }
+
+ /** Returns the expression of the sum of the vector \a other to each subvector of \c *this */
+ template<typename OtherDerived> EIGEN_STRONG_INLINE
+ CwiseBinaryOp<internal::scalar_sum_op<Scalar>,
+ const ExpressionTypeNestedCleaned,
+ const typename ExtendedType<OtherDerived>::Type>
+ operator+(const DenseBase<OtherDerived>& other) const
+ {
+ EIGEN_STATIC_ASSERT_VECTOR_ONLY(OtherDerived)
+ EIGEN_STATIC_ASSERT_SAME_XPR_KIND(ExpressionType, OtherDerived)
+ return m_matrix + extendedTo(other.derived());
+ }
+
+ /** Returns the expression of the difference between each subvector of \c *this and the vector \a other */
+ template<typename OtherDerived>
+ CwiseBinaryOp<internal::scalar_difference_op<Scalar>,
+ const ExpressionTypeNestedCleaned,
+ const typename ExtendedType<OtherDerived>::Type>
+ operator-(const DenseBase<OtherDerived>& other) const
+ {
+ EIGEN_STATIC_ASSERT_VECTOR_ONLY(OtherDerived)
+ EIGEN_STATIC_ASSERT_SAME_XPR_KIND(ExpressionType, OtherDerived)
+ return m_matrix - extendedTo(other.derived());
+ }
+
+ /** Returns the expression where each subvector is the product of the vector \a other
+ * by the corresponding subvector of \c *this */
+ template<typename OtherDerived> EIGEN_STRONG_INLINE
+ CwiseBinaryOp<internal::scalar_product_op<Scalar>,
+ const ExpressionTypeNestedCleaned,
+ const typename ExtendedType<OtherDerived>::Type>
+ operator*(const DenseBase<OtherDerived>& other) const
+ {
+ EIGEN_STATIC_ASSERT_VECTOR_ONLY(OtherDerived)
+ EIGEN_STATIC_ASSERT_ARRAYXPR(ExpressionType)
+ EIGEN_STATIC_ASSERT_SAME_XPR_KIND(ExpressionType, OtherDerived)
+ return m_matrix * extendedTo(other.derived());
+ }
+
+ /** Returns the expression where each subvector is the quotient of the corresponding
+ * subvector of \c *this by the vector \a other */
+ template<typename OtherDerived>
+ CwiseBinaryOp<internal::scalar_quotient_op<Scalar>,
+ const ExpressionTypeNestedCleaned,
+ const typename ExtendedType<OtherDerived>::Type>
+ operator/(const DenseBase<OtherDerived>& other) const
+ {
+ EIGEN_STATIC_ASSERT_VECTOR_ONLY(OtherDerived)
+ EIGEN_STATIC_ASSERT_ARRAYXPR(ExpressionType)
+ EIGEN_STATIC_ASSERT_SAME_XPR_KIND(ExpressionType, OtherDerived)
+ return m_matrix / extendedTo(other.derived());
+ }
+
+/////////// Geometry module ///////////
+
+ #if EIGEN2_SUPPORT_STAGE > STAGE20_RESOLVE_API_CONFLICTS
+ Homogeneous<ExpressionType,Direction> homogeneous() const;
+ #endif
+
+ typedef typename ExpressionType::PlainObject CrossReturnType;
+ template<typename OtherDerived>
+ const CrossReturnType cross(const MatrixBase<OtherDerived>& other) const;
+
+ enum {
+ HNormalized_Size = Direction==Vertical ? internal::traits<ExpressionType>::RowsAtCompileTime
+ : internal::traits<ExpressionType>::ColsAtCompileTime,
+ HNormalized_SizeMinusOne = HNormalized_Size==Dynamic ? Dynamic : HNormalized_Size-1
+ };
+ typedef Block<const ExpressionType,
+ Direction==Vertical ? int(HNormalized_SizeMinusOne)
+ : int(internal::traits<ExpressionType>::RowsAtCompileTime),
+ Direction==Horizontal ? int(HNormalized_SizeMinusOne)
+ : int(internal::traits<ExpressionType>::ColsAtCompileTime)>
+ HNormalized_Block;
+ typedef Block<const ExpressionType,
+ Direction==Vertical ? 1 : int(internal::traits<ExpressionType>::RowsAtCompileTime),
+ Direction==Horizontal ? 1 : int(internal::traits<ExpressionType>::ColsAtCompileTime)>
+ HNormalized_Factors;
+ typedef CwiseBinaryOp<internal::scalar_quotient_op<typename internal::traits<ExpressionType>::Scalar>,
+ const HNormalized_Block,
+ const Replicate<HNormalized_Factors,
+ Direction==Vertical ? HNormalized_SizeMinusOne : 1,
+ Direction==Horizontal ? HNormalized_SizeMinusOne : 1> >
+ HNormalizedReturnType;
+
+ const HNormalizedReturnType hnormalized() const;
+
+ protected:
+ ExpressionTypeNested m_matrix;
+};
+
+/** \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
+ */
+template<typename Derived>
+inline const typename DenseBase<Derived>::ConstColwiseReturnType
+DenseBase<Derived>::colwise() const
+{
+ return derived();
+}
+
+/** \returns a writable VectorwiseOp wrapper of *this providing additional partial reduction operations
+ *
+ * \sa rowwise(), class VectorwiseOp, \ref TutorialReductionsVisitorsBroadcasting
+ */
+template<typename Derived>
+inline typename DenseBase<Derived>::ColwiseReturnType
+DenseBase<Derived>::colwise()
+{
+ return derived();
+}
+
+/** \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
+ */
+template<typename Derived>
+inline const typename DenseBase<Derived>::ConstRowwiseReturnType
+DenseBase<Derived>::rowwise() const
+{
+ return derived();
+}
+
+/** \returns a writable VectorwiseOp wrapper of *this providing additional partial reduction operations
+ *
+ * \sa colwise(), class VectorwiseOp, \ref TutorialReductionsVisitorsBroadcasting
+ */
+template<typename Derived>
+inline typename DenseBase<Derived>::RowwiseReturnType
+DenseBase<Derived>::rowwise()
+{
+ return derived();
+}
+
+} // end namespace Eigen
+
+#endif // EIGEN_PARTIAL_REDUX_H
diff --git a/Eigen/src/Core/Visitor.h b/Eigen/src/Core/Visitor.h
new file mode 100644
index 000000000..916bfd096
--- /dev/null
+++ b/Eigen/src/Core/Visitor.h
@@ -0,0 +1,237 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra.
+//
+// Copyright (C) 2008 Gael Guennebaud <gael.guennebaud@inria.fr>
+//
+// This Source Code Form is subject to the terms of the Mozilla
+// Public License v. 2.0. If a copy of the MPL was not distributed
+// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+#ifndef EIGEN_VISITOR_H
+#define EIGEN_VISITOR_H
+
+namespace Eigen {
+
+namespace internal {
+
+template<typename Visitor, typename Derived, int UnrollCount>
+struct visitor_impl
+{
+ enum {
+ col = (UnrollCount-1) / Derived::RowsAtCompileTime,
+ row = (UnrollCount-1) % Derived::RowsAtCompileTime
+ };
+
+ static inline void run(const Derived &mat, Visitor& visitor)
+ {
+ visitor_impl<Visitor, Derived, UnrollCount-1>::run(mat, visitor);
+ visitor(mat.coeff(row, col), row, col);
+ }
+};
+
+template<typename Visitor, typename Derived>
+struct visitor_impl<Visitor, Derived, 1>
+{
+ static inline void run(const Derived &mat, Visitor& visitor)
+ {
+ return visitor.init(mat.coeff(0, 0), 0, 0);
+ }
+};
+
+template<typename Visitor, typename Derived>
+struct visitor_impl<Visitor, Derived, Dynamic>
+{
+ typedef typename Derived::Index Index;
+ static inline void run(const Derived& mat, Visitor& visitor)
+ {
+ visitor.init(mat.coeff(0,0), 0, 0);
+ for(Index i = 1; i < mat.rows(); ++i)
+ visitor(mat.coeff(i, 0), i, 0);
+ for(Index j = 1; j < mat.cols(); ++j)
+ for(Index i = 0; i < mat.rows(); ++i)
+ visitor(mat.coeff(i, j), i, j);
+ }
+};
+
+} // end namespace internal
+
+/** Applies the visitor \a visitor to the whole coefficients of the matrix or vector.
+ *
+ * The template parameter \a Visitor is the type of the visitor and provides the following interface:
+ * \code
+ * struct MyVisitor {
+ * // called for the first coefficient
+ * void init(const Scalar& value, Index i, Index j);
+ * // called for all other coefficients
+ * void operator() (const Scalar& value, Index i, Index j);
+ * };
+ * \endcode
+ *
+ * \note compared to one or two \em for \em loops, visitors offer automatic
+ * unrolling for small fixed size matrix.
+ *
+ * \sa minCoeff(Index*,Index*), maxCoeff(Index*,Index*), DenseBase::redux()
+ */
+template<typename Derived>
+template<typename Visitor>
+void DenseBase<Derived>::visit(Visitor& visitor) const
+{
+ enum { unroll = SizeAtCompileTime != Dynamic
+ && CoeffReadCost != Dynamic
+ && (SizeAtCompileTime == 1 || internal::functor_traits<Visitor>::Cost != Dynamic)
+ && SizeAtCompileTime * CoeffReadCost + (SizeAtCompileTime-1) * internal::functor_traits<Visitor>::Cost
+ <= EIGEN_UNROLLING_LIMIT };
+ return internal::visitor_impl<Visitor, Derived,
+ unroll ? int(SizeAtCompileTime) : Dynamic
+ >::run(derived(), visitor);
+}
+
+namespace internal {
+
+/** \internal
+ * \brief Base class to implement min and max visitors
+ */
+template <typename Derived>
+struct coeff_visitor
+{
+ typedef typename Derived::Index Index;
+ typedef typename Derived::Scalar Scalar;
+ Index row, col;
+ Scalar res;
+ inline void init(const Scalar& value, Index i, Index j)
+ {
+ res = value;
+ row = i;
+ col = j;
+ }
+};
+
+/** \internal
+ * \brief Visitor computing the min coefficient with its value and coordinates
+ *
+ * \sa DenseBase::minCoeff(Index*, Index*)
+ */
+template <typename Derived>
+struct min_coeff_visitor : coeff_visitor<Derived>
+{
+ typedef typename Derived::Index Index;
+ typedef typename Derived::Scalar Scalar;
+ void operator() (const Scalar& value, Index i, Index j)
+ {
+ if(value < this->res)
+ {
+ this->res = value;
+ this->row = i;
+ this->col = j;
+ }
+ }
+};
+
+template<typename Scalar>
+struct functor_traits<min_coeff_visitor<Scalar> > {
+ enum {
+ Cost = NumTraits<Scalar>::AddCost
+ };
+};
+
+/** \internal
+ * \brief Visitor computing the max coefficient with its value and coordinates
+ *
+ * \sa DenseBase::maxCoeff(Index*, Index*)
+ */
+template <typename Derived>
+struct max_coeff_visitor : coeff_visitor<Derived>
+{
+ typedef typename Derived::Index Index;
+ typedef typename Derived::Scalar Scalar;
+ void operator() (const Scalar& value, Index i, Index j)
+ {
+ if(value > this->res)
+ {
+ this->res = value;
+ this->row = i;
+ this->col = j;
+ }
+ }
+};
+
+template<typename Scalar>
+struct functor_traits<max_coeff_visitor<Scalar> > {
+ enum {
+ Cost = NumTraits<Scalar>::AddCost
+ };
+};
+
+} // end namespace internal
+
+/** \returns the minimum of all coefficients of *this
+ * and puts in *row and *col its location.
+ *
+ * \sa DenseBase::minCoeff(Index*), DenseBase::maxCoeff(Index*,Index*), DenseBase::visitor(), DenseBase::minCoeff()
+ */
+template<typename Derived>
+template<typename IndexType>
+typename internal::traits<Derived>::Scalar
+DenseBase<Derived>::minCoeff(IndexType* row, IndexType* col) const
+{
+ internal::min_coeff_visitor<Derived> minVisitor;
+ this->visit(minVisitor);
+ *row = minVisitor.row;
+ if (col) *col = minVisitor.col;
+ return minVisitor.res;
+}
+
+/** \returns the minimum of all coefficients of *this
+ * and puts in *index its location.
+ *
+ * \sa DenseBase::minCoeff(IndexType*,IndexType*), DenseBase::maxCoeff(IndexType*,IndexType*), DenseBase::visitor(), DenseBase::minCoeff()
+ */
+template<typename Derived>
+template<typename IndexType>
+typename internal::traits<Derived>::Scalar
+DenseBase<Derived>::minCoeff(IndexType* index) const
+{
+ EIGEN_STATIC_ASSERT_VECTOR_ONLY(Derived)
+ internal::min_coeff_visitor<Derived> minVisitor;
+ this->visit(minVisitor);
+ *index = (RowsAtCompileTime==1) ? minVisitor.col : minVisitor.row;
+ return minVisitor.res;
+}
+
+/** \returns the maximum of all coefficients of *this
+ * and puts in *row and *col its location.
+ *
+ * \sa DenseBase::minCoeff(IndexType*,IndexType*), DenseBase::visitor(), DenseBase::maxCoeff()
+ */
+template<typename Derived>
+template<typename IndexType>
+typename internal::traits<Derived>::Scalar
+DenseBase<Derived>::maxCoeff(IndexType* row, IndexType* col) const
+{
+ internal::max_coeff_visitor<Derived> maxVisitor;
+ this->visit(maxVisitor);
+ *row = maxVisitor.row;
+ if (col) *col = maxVisitor.col;
+ return maxVisitor.res;
+}
+
+/** \returns the maximum of all coefficients of *this
+ * and puts in *index its location.
+ *
+ * \sa DenseBase::maxCoeff(IndexType*,IndexType*), DenseBase::minCoeff(IndexType*,IndexType*), DenseBase::visitor(), DenseBase::maxCoeff()
+ */
+template<typename Derived>
+template<typename IndexType>
+typename internal::traits<Derived>::Scalar
+DenseBase<Derived>::maxCoeff(IndexType* index) const
+{
+ EIGEN_STATIC_ASSERT_VECTOR_ONLY(Derived)
+ internal::max_coeff_visitor<Derived> maxVisitor;
+ this->visit(maxVisitor);
+ *index = (RowsAtCompileTime==1) ? maxVisitor.col : maxVisitor.row;
+ return maxVisitor.res;
+}
+
+} // end namespace Eigen
+
+#endif // EIGEN_VISITOR_H
diff --git a/Eigen/src/Core/arch/AltiVec/CMakeLists.txt b/Eigen/src/Core/arch/AltiVec/CMakeLists.txt
new file mode 100644
index 000000000..9f8d2e9c4
--- /dev/null
+++ b/Eigen/src/Core/arch/AltiVec/CMakeLists.txt
@@ -0,0 +1,6 @@
+FILE(GLOB Eigen_Core_arch_AltiVec_SRCS "*.h")
+
+INSTALL(FILES
+ ${Eigen_Core_arch_AltiVec_SRCS}
+ DESTINATION ${INCLUDE_INSTALL_DIR}/Eigen/src/Core/arch/AltiVec COMPONENT Devel
+)
diff --git a/Eigen/src/Core/arch/AltiVec/Complex.h b/Eigen/src/Core/arch/AltiVec/Complex.h
new file mode 100644
index 000000000..68d9a2bff
--- /dev/null
+++ b/Eigen/src/Core/arch/AltiVec/Complex.h
@@ -0,0 +1,217 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra.
+//
+// Copyright (C) 2010 Gael Guennebaud <gael.guennebaud@inria.fr>
+//
+// This Source Code Form is subject to the terms of the Mozilla
+// Public License v. 2.0. If 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<std::complex<float> > : 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<Packet2cf> { typedef std::complex<float> type; enum {size=2}; };
+
+template<> EIGEN_STRONG_INLINE Packet2cf pset1<Packet2cf>(const std::complex<float>& 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<Packet4f>((const float *)&from);
+ else
+ res.v = ploadu<Packet4f>((const float *)&from);
+ res.v = vec_perm(res.v, res.v, p16uc_PSET_HI);
+ return res;
+}
+
+template<> EIGEN_STRONG_INLINE Packet2cf padd<Packet2cf>(const Packet2cf& a, const Packet2cf& b) { return Packet2cf(vec_add(a.v,b.v)); }
+template<> EIGEN_STRONG_INLINE Packet2cf psub<Packet2cf>(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<Packet2cf>(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 <Packet2cf>(const Packet2cf& a, const Packet2cf& b) { return Packet2cf(vec_and(a.v,b.v)); }
+template<> EIGEN_STRONG_INLINE Packet2cf por <Packet2cf>(const Packet2cf& a, const Packet2cf& b) { return Packet2cf(vec_or(a.v,b.v)); }
+template<> EIGEN_STRONG_INLINE Packet2cf pxor <Packet2cf>(const Packet2cf& a, const Packet2cf& b) { return Packet2cf(vec_xor(a.v,b.v)); }
+template<> EIGEN_STRONG_INLINE Packet2cf pandnot<Packet2cf>(const Packet2cf& a, const Packet2cf& b) { return Packet2cf(vec_and(a.v, vec_nor(b.v,b.v))); }
+
+template<> EIGEN_STRONG_INLINE Packet2cf pload <Packet2cf>(const std::complex<float>* from) { EIGEN_DEBUG_ALIGNED_LOAD return Packet2cf(pload<Packet4f>((const float*)from)); }
+template<> EIGEN_STRONG_INLINE Packet2cf ploadu<Packet2cf>(const std::complex<float>* from) { EIGEN_DEBUG_UNALIGNED_LOAD return Packet2cf(ploadu<Packet4f>((const float*)from)); }
+
+template<> EIGEN_STRONG_INLINE Packet2cf ploaddup<Packet2cf>(const std::complex<float>* from)
+{
+ return pset1<Packet2cf>(*from);
+}
+
+template<> EIGEN_STRONG_INLINE void pstore <std::complex<float> >(std::complex<float> * to, const Packet2cf& from) { EIGEN_DEBUG_ALIGNED_STORE pstore((float*)to, from.v); }
+template<> EIGEN_STRONG_INLINE void pstoreu<std::complex<float> >(std::complex<float> * to, const Packet2cf& from) { EIGEN_DEBUG_UNALIGNED_STORE pstoreu((float*)to, from.v); }
+
+template<> EIGEN_STRONG_INLINE void prefetch<std::complex<float> >(const std::complex<float> * addr) { vec_dstt((float *)addr, DST_CTRL(2,2,32), DST_CHAN); }
+
+template<> EIGEN_STRONG_INLINE std::complex<float> pfirst<Packet2cf>(const Packet2cf& a)
+{
+ std::complex<float> 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<float> predux<Packet2cf>(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<Packet2cf>(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<float> predux_mul<Packet2cf>(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<int Offset>
+struct palign_impl<Offset,Packet2cf>
+{
+ 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<Packet2cf, Packet2cf, false,true>
+{
+ 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<Packet2cf, Packet2cf, true,false>
+{
+ 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<Packet2cf, Packet2cf, true,true>
+{
+ 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<Packet2cf>(const Packet2cf& a, const Packet2cf& b)
+{
+ // TODO optimize it for AltiVec
+ Packet2cf res = conj_helper<Packet2cf,Packet2cf,false,true>().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<Packet2cf>(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/Eigen/src/Core/arch/AltiVec/PacketMath.h b/Eigen/src/Core/arch/AltiVec/PacketMath.h
new file mode 100644
index 000000000..75de19311
--- /dev/null
+++ b/Eigen/src/Core/arch/AltiVec/PacketMath.h
@@ -0,0 +1,498 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra.
+//
+// Copyright (C) 2008 Konstantinos Margaritis <markos@codex.gr>
+//
+// This Source Code Form is subject to the terms of the Mozilla
+// Public License v. 2.0. If 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<Packet4f>(X)
+
+#define _EIGEN_DECLARE_CONST_Packet4f_FROM_INT(NAME,X) \
+ Packet4f p4f_##NAME = vreinterpretq_f32_u32(pset1<int>(X))
+
+#define _EIGEN_DECLARE_CONST_Packet4i(NAME,X) \
+ Packet4i p4i_##NAME = pset1<Packet4i>(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<float> : 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<int> : default_packet_traits
+{
+ typedef Packet4i type;
+ enum {
+ // FIXME check the Has*
+ Vectorizable = 1,
+ AlignedOnScalar = 1,
+ size=4
+ };
+};
+
+template<> struct unpacket_traits<Packet4f> { typedef float type; enum {size=4}; };
+template<> struct unpacket_traits<Packet4i> { 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<Packet4f>(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<Packet4i>(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<float>(const float& a) { return vec_add(pset1<Packet4f>(a), p4f_COUNTDOWN); }
+template<> EIGEN_STRONG_INLINE Packet4i plset<int>(const int& a) { return vec_add(pset1<Packet4i>(a), p4i_COUNTDOWN); }
+
+template<> EIGEN_STRONG_INLINE Packet4f padd<Packet4f>(const Packet4f& a, const Packet4f& b) { return vec_add(a,b); }
+template<> EIGEN_STRONG_INLINE Packet4i padd<Packet4i>(const Packet4i& a, const Packet4i& b) { return vec_add(a,b); }
+
+template<> EIGEN_STRONG_INLINE Packet4f psub<Packet4f>(const Packet4f& a, const Packet4f& b) { return vec_sub(a,b); }
+template<> EIGEN_STRONG_INLINE Packet4i psub<Packet4i>(const Packet4i& a, const Packet4i& b) { return vec_sub(a,b); }
+
+template<> EIGEN_STRONG_INLINE Packet4f pnegate(const Packet4f& a) { return psub<Packet4f>(p4f_ZERO, a); }
+template<> EIGEN_STRONG_INLINE Packet4i pnegate(const Packet4i& a) { return psub<Packet4i>(p4i_ZERO, a); }
+
+template<> EIGEN_STRONG_INLINE Packet4f pmul<Packet4f>(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<Packet4i>(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<Packet4f>(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<Packet4i>(const Packet4i& /*a*/, const Packet4i& /*b*/)
+{ eigen_assert(false && "packet integer division are not supported by AltiVec");
+ return pset1<Packet4i>(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<Packet4f>(const Packet4f& a, const Packet4f& b) { return vec_min(a, b); }
+template<> EIGEN_STRONG_INLINE Packet4i pmin<Packet4i>(const Packet4i& a, const Packet4i& b) { return vec_min(a, b); }
+
+template<> EIGEN_STRONG_INLINE Packet4f pmax<Packet4f>(const Packet4f& a, const Packet4f& b) { return vec_max(a, b); }
+template<> EIGEN_STRONG_INLINE Packet4i pmax<Packet4i>(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<Packet4f>(const Packet4f& a, const Packet4f& b) { return vec_and(a, b); }
+template<> EIGEN_STRONG_INLINE Packet4i pand<Packet4i>(const Packet4i& a, const Packet4i& b) { return vec_and(a, b); }
+
+template<> EIGEN_STRONG_INLINE Packet4f por<Packet4f>(const Packet4f& a, const Packet4f& b) { return vec_or(a, b); }
+template<> EIGEN_STRONG_INLINE Packet4i por<Packet4i>(const Packet4i& a, const Packet4i& b) { return vec_or(a, b); }
+
+template<> EIGEN_STRONG_INLINE Packet4f pxor<Packet4f>(const Packet4f& a, const Packet4f& b) { return vec_xor(a, b); }
+template<> EIGEN_STRONG_INLINE Packet4i pxor<Packet4i>(const Packet4i& a, const Packet4i& b) { return vec_xor(a, b); }
+
+template<> EIGEN_STRONG_INLINE Packet4f pandnot<Packet4f>(const Packet4f& a, const Packet4f& b) { return vec_and(a, vec_nor(b, b)); }
+template<> EIGEN_STRONG_INLINE Packet4i pandnot<Packet4i>(const Packet4i& a, const Packet4i& b) { return vec_and(a, vec_nor(b, b)); }
+
+template<> EIGEN_STRONG_INLINE Packet4f pload<Packet4f>(const float* from) { EIGEN_DEBUG_ALIGNED_LOAD return vec_ld(0, from); }
+template<> EIGEN_STRONG_INLINE Packet4i pload<Packet4i>(const int* from) { EIGEN_DEBUG_ALIGNED_LOAD return vec_ld(0, from); }
+
+template<> EIGEN_STRONG_INLINE Packet4f ploadu<Packet4f>(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<Packet4i>(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<Packet4f>(const float* from)
+{
+ Packet4f p;
+ if((ptrdiff_t(&from) % 16) == 0) p = pload<Packet4f>(from);
+ else p = ploadu<Packet4f>(from);
+ return vec_perm(p, p, p16uc_DUPLICATE);
+}
+template<> EIGEN_STRONG_INLINE Packet4i ploaddup<Packet4i>(const int* from)
+{
+ Packet4i p;
+ if((ptrdiff_t(&from) % 16) == 0) p = pload<Packet4i>(from);
+ else p = ploadu<Packet4i>(from);
+ return vec_perm(p, p, p16uc_DUPLICATE);
+}
+
+template<> EIGEN_STRONG_INLINE void pstore<float>(float* to, const Packet4f& from) { EIGEN_DEBUG_ALIGNED_STORE vec_st(from, 0, to); }
+template<> EIGEN_STRONG_INLINE void pstore<int>(int* to, const Packet4i& from) { EIGEN_DEBUG_ALIGNED_STORE vec_st(from, 0, to); }
+
+template<> EIGEN_STRONG_INLINE void pstoreu<float>(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>(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<float>(const float* addr) { vec_dstt(addr, DST_CTRL(2,2,32), DST_CHAN); }
+template<> EIGEN_STRONG_INLINE void prefetch<int>(const int* addr) { vec_dstt(addr, DST_CTRL(2,2,32), DST_CHAN); }
+
+template<> EIGEN_STRONG_INLINE float pfirst<Packet4f>(const Packet4f& a) { float EIGEN_ALIGN16 x[4]; vec_st(a, 0, x); return x[0]; }
+template<> EIGEN_STRONG_INLINE int pfirst<Packet4i>(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<Packet4f>(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<Packet4f>(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<Packet4i>(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<Packet4i>(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<Packet4f>(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<Packet4i>(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<Packet4f>(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<Packet4i>(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<Packet4f>(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<Packet4i>(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<int Offset>
+struct palign_impl<Offset,Packet4f>
+{
+ static EIGEN_STRONG_INLINE void run(Packet4f& first, const Packet4f& second)
+ {
+ if (Offset!=0)
+ first = vec_sld(first, second, Offset*4);
+ }
+};
+
+template<int Offset>
+struct palign_impl<Offset,Packet4i>
+{
+ 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/Eigen/src/Core/arch/CMakeLists.txt b/Eigen/src/Core/arch/CMakeLists.txt
new file mode 100644
index 000000000..8456dec15
--- /dev/null
+++ b/Eigen/src/Core/arch/CMakeLists.txt
@@ -0,0 +1,4 @@
+ADD_SUBDIRECTORY(SSE)
+ADD_SUBDIRECTORY(AltiVec)
+ADD_SUBDIRECTORY(NEON)
+ADD_SUBDIRECTORY(Default)
diff --git a/Eigen/src/Core/arch/Default/CMakeLists.txt b/Eigen/src/Core/arch/Default/CMakeLists.txt
new file mode 100644
index 000000000..339c091d1
--- /dev/null
+++ b/Eigen/src/Core/arch/Default/CMakeLists.txt
@@ -0,0 +1,6 @@
+FILE(GLOB Eigen_Core_arch_Default_SRCS "*.h")
+
+INSTALL(FILES
+ ${Eigen_Core_arch_Default_SRCS}
+ DESTINATION ${INCLUDE_INSTALL_DIR}/Eigen/src/Core/arch/Default COMPONENT Devel
+)
diff --git a/Eigen/src/Core/arch/Default/Settings.h b/Eigen/src/Core/arch/Default/Settings.h
new file mode 100644
index 000000000..097373c84
--- /dev/null
+++ b/Eigen/src/Core/arch/Default/Settings.h
@@ -0,0 +1,49 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra.
+//
+// Copyright (C) 2008-2010 Gael Guennebaud <gael.guennebaud@inria.fr>
+// Copyright (C) 2006-2008 Benoit Jacob <jacob.benoit.1@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/.
+
+
+/* All the parameters defined in this file can be specialized in the
+ * architecture specific files, and/or by the user.
+ * More to come... */
+
+#ifndef EIGEN_DEFAULT_SETTINGS_H
+#define EIGEN_DEFAULT_SETTINGS_H
+
+/** Defines the maximal loop size to enable meta unrolling of loops.
+ * Note that the value here is expressed in Eigen's own notion of "number of FLOPS",
+ * it does not correspond to the number of iterations or the number of instructions
+ */
+#ifndef EIGEN_UNROLLING_LIMIT
+#define EIGEN_UNROLLING_LIMIT 100
+#endif
+
+/** Defines the threshold between a "small" and a "large" matrix.
+ * This threshold is mainly used to select the proper product implementation.
+ */
+#ifndef EIGEN_CACHEFRIENDLY_PRODUCT_THRESHOLD
+#define EIGEN_CACHEFRIENDLY_PRODUCT_THRESHOLD 8
+#endif
+
+/** Defines the maximal width of the blocks used in the triangular product and solver
+ * for vectors (level 2 blas xTRMV and xTRSV). The default is 8.
+ */
+#ifndef EIGEN_TUNE_TRIANGULAR_PANEL_WIDTH
+#define EIGEN_TUNE_TRIANGULAR_PANEL_WIDTH 8
+#endif
+
+
+/** Defines the default number of registers available for that architecture.
+ * Currently it must be 8 or 16. Other values will fail.
+ */
+#ifndef EIGEN_ARCH_DEFAULT_NUMBER_OF_REGISTERS
+#define EIGEN_ARCH_DEFAULT_NUMBER_OF_REGISTERS 8
+#endif
+
+#endif // EIGEN_DEFAULT_SETTINGS_H
diff --git a/Eigen/src/Core/arch/NEON/CMakeLists.txt b/Eigen/src/Core/arch/NEON/CMakeLists.txt
new file mode 100644
index 000000000..fd4d4af50
--- /dev/null
+++ b/Eigen/src/Core/arch/NEON/CMakeLists.txt
@@ -0,0 +1,6 @@
+FILE(GLOB Eigen_Core_arch_NEON_SRCS "*.h")
+
+INSTALL(FILES
+ ${Eigen_Core_arch_NEON_SRCS}
+ DESTINATION ${INCLUDE_INSTALL_DIR}/Eigen/src/Core/arch/NEON COMPONENT Devel
+)
diff --git a/Eigen/src/Core/arch/NEON/Complex.h b/Eigen/src/Core/arch/NEON/Complex.h
new file mode 100644
index 000000000..795b4be73
--- /dev/null
+++ b/Eigen/src/Core/arch/NEON/Complex.h
@@ -0,0 +1,259 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra.
+//
+// Copyright (C) 2010 Gael Guennebaud <gael.guennebaud@inria.fr>
+//
+// This Source Code Form is subject to the terms of the Mozilla
+// Public License v. 2.0. If 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<std::complex<float> > : 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<Packet2cf> { typedef std::complex<float> type; enum {size=2}; };
+
+template<> EIGEN_STRONG_INLINE Packet2cf pset1<Packet2cf>(const std::complex<float>& from)
+{
+ float32x2_t r64;
+ r64 = vld1_f32((float *)&from);
+
+ return Packet2cf(vcombine_f32(r64, r64));
+}
+
+template<> EIGEN_STRONG_INLINE Packet2cf padd<Packet2cf>(const Packet2cf& a, const Packet2cf& b) { return Packet2cf(padd<Packet4f>(a.v,b.v)); }
+template<> EIGEN_STRONG_INLINE Packet2cf psub<Packet2cf>(const Packet2cf& a, const Packet2cf& b) { return Packet2cf(psub<Packet4f>(a.v,b.v)); }
+template<> EIGEN_STRONG_INLINE Packet2cf pnegate(const Packet2cf& a) { return Packet2cf(pnegate<Packet4f>(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<Packet2cf>(const Packet2cf& a, const Packet2cf& b)
+{
+ Packet4f v1, v2;
+ float32x2_t a_lo, a_hi;
+
+ // 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.
+ a_lo = vrev64_f32(vget_low_f32(v2));
+ a_hi = vrev64_f32(vget_high_f32(v2));
+ v2 = vcombine_f32(a_lo, a_hi);
+ // Add and return the result
+ return Packet2cf(vaddq_f32(v1, v2));
+}
+
+template<> EIGEN_STRONG_INLINE Packet2cf pand <Packet2cf>(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 <Packet2cf>(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 <Packet2cf>(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<Packet2cf>(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<Packet2cf>(const std::complex<float>* from) { EIGEN_DEBUG_ALIGNED_LOAD return Packet2cf(pload<Packet4f>((const float*)from)); }
+template<> EIGEN_STRONG_INLINE Packet2cf ploadu<Packet2cf>(const std::complex<float>* from) { EIGEN_DEBUG_UNALIGNED_LOAD return Packet2cf(ploadu<Packet4f>((const float*)from)); }
+
+template<> EIGEN_STRONG_INLINE Packet2cf ploaddup<Packet2cf>(const std::complex<float>* from) { return pset1<Packet2cf>(*from); }
+
+template<> EIGEN_STRONG_INLINE void pstore <std::complex<float> >(std::complex<float> * to, const Packet2cf& from) { EIGEN_DEBUG_ALIGNED_STORE pstore((float*)to, from.v); }
+template<> EIGEN_STRONG_INLINE void pstoreu<std::complex<float> >(std::complex<float> * to, const Packet2cf& from) { EIGEN_DEBUG_UNALIGNED_STORE pstoreu((float*)to, from.v); }
+
+template<> EIGEN_STRONG_INLINE void prefetch<std::complex<float> >(const std::complex<float> * addr) { __pld((float *)addr); }
+
+template<> EIGEN_STRONG_INLINE std::complex<float> pfirst<Packet2cf>(const Packet2cf& a)
+{
+ std::complex<float> 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<Packet2cf>(const Packet2cf& a)
+{
+ return Packet2cf(vrev64q_f32(a.v));
+}
+
+template<> EIGEN_STRONG_INLINE std::complex<float> predux<Packet2cf>(const Packet2cf& a)
+{
+ float32x2_t a1, a2;
+ std::complex<float> 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<Packet2cf>(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<float> predux_mul<Packet2cf>(const Packet2cf& a)
+{
+ float32x2_t a1, a2, v1, v2, prod;
+ std::complex<float> 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<int Offset>
+struct palign_impl<Offset,Packet2cf>
+{
+ 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<Packet2cf, Packet2cf, false,true>
+{
+ 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<Packet2cf, Packet2cf, true,false>
+{
+ 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<Packet2cf, Packet2cf, true,true>
+{
+ 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<Packet2cf>(const Packet2cf& a, const Packet2cf& b)
+{
+ // TODO optimize it for AltiVec
+ Packet2cf res = conj_helper<Packet2cf,Packet2cf,false,true>().pmul(a,b);
+ Packet4f s, rev_s;
+ float32x2_t a_lo, a_hi;
+
+ // this computes the norm
+ s = vmulq_f32(b.v, b.v);
+ a_lo = vrev64_f32(vget_low_f32(s));
+ a_hi = vrev64_f32(vget_high_f32(s));
+ rev_s = vcombine_f32(a_lo, a_hi);
+
+ return Packet2cf(pdiv(res.v, vaddq_f32(s,rev_s)));
+}
+
+} // end namespace internal
+
+} // end namespace Eigen
+
+#endif // EIGEN_COMPLEX_NEON_H
diff --git a/Eigen/src/Core/arch/NEON/PacketMath.h b/Eigen/src/Core/arch/NEON/PacketMath.h
new file mode 100644
index 000000000..a20250f7c
--- /dev/null
+++ b/Eigen/src/Core/arch/NEON/PacketMath.h
@@ -0,0 +1,424 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra.
+//
+// Copyright (C) 2008-2009 Gael Guennebaud <gael.guennebaud@inria.fr>
+// Copyright (C) 2010 Konstantinos Margaritis <markos@codex.gr>
+// 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<Packet4f>(X)
+
+#define _EIGEN_DECLARE_CONST_Packet4f_FROM_INT(NAME,X) \
+ const Packet4f p4f_##NAME = vreinterpretq_f32_u32(pset1<int>(X))
+
+#define _EIGEN_DECLARE_CONST_Packet4i(NAME,X) \
+ const Packet4i p4i_##NAME = pset1<Packet4i>(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
+
+#ifndef __pld
+#define __pld(x) asm volatile ( " pld [%[addr]]\n" :: [addr] "r" (x) : "cc" );
+#endif
+
+template<> struct packet_traits<float> : 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<int> : 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<Packet4f> { typedef float type; enum {size=4}; };
+template<> struct unpacket_traits<Packet4i> { typedef int type; enum {size=4}; };
+
+template<> EIGEN_STRONG_INLINE Packet4f pset1<Packet4f>(const float& from) { return vdupq_n_f32(from); }
+template<> EIGEN_STRONG_INLINE Packet4i pset1<Packet4i>(const int& from) { return vdupq_n_s32(from); }
+
+template<> EIGEN_STRONG_INLINE Packet4f plset<float>(const float& a)
+{
+ Packet4f countdown = EIGEN_INIT_NEON_PACKET4(0, 1, 2, 3);
+ return vaddq_f32(pset1<Packet4f>(a), countdown);
+}
+template<> EIGEN_STRONG_INLINE Packet4i plset<int>(const int& a)
+{
+ Packet4i countdown = EIGEN_INIT_NEON_PACKET4(0, 1, 2, 3);
+ return vaddq_s32(pset1<Packet4i>(a), countdown);
+}
+
+template<> EIGEN_STRONG_INLINE Packet4f padd<Packet4f>(const Packet4f& a, const Packet4f& b) { return vaddq_f32(a,b); }
+template<> EIGEN_STRONG_INLINE Packet4i padd<Packet4i>(const Packet4i& a, const Packet4i& b) { return vaddq_s32(a,b); }
+
+template<> EIGEN_STRONG_INLINE Packet4f psub<Packet4f>(const Packet4f& a, const Packet4f& b) { return vsubq_f32(a,b); }
+template<> EIGEN_STRONG_INLINE Packet4i psub<Packet4i>(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 pmul<Packet4f>(const Packet4f& a, const Packet4f& b) { return vmulq_f32(a,b); }
+template<> EIGEN_STRONG_INLINE Packet4i pmul<Packet4i>(const Packet4i& a, const Packet4i& b) { return vmulq_s32(a,b); }
+
+template<> EIGEN_STRONG_INLINE Packet4f pdiv<Packet4f>(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<Packet4i>(const Packet4i& /*a*/, const Packet4i& /*b*/)
+{ eigen_assert(false && "packet integer division are not supported by NEON");
+ return pset1<Packet4i>(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<Packet4f>(const Packet4f& a, const Packet4f& b) { return vminq_f32(a,b); }
+template<> EIGEN_STRONG_INLINE Packet4i pmin<Packet4i>(const Packet4i& a, const Packet4i& b) { return vminq_s32(a,b); }
+
+template<> EIGEN_STRONG_INLINE Packet4f pmax<Packet4f>(const Packet4f& a, const Packet4f& b) { return vmaxq_f32(a,b); }
+template<> EIGEN_STRONG_INLINE Packet4i pmax<Packet4i>(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<Packet4f>(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<Packet4i>(const Packet4i& a, const Packet4i& b) { return vandq_s32(a,b); }
+
+template<> EIGEN_STRONG_INLINE Packet4f por<Packet4f>(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<Packet4i>(const Packet4i& a, const Packet4i& b) { return vorrq_s32(a,b); }
+
+template<> EIGEN_STRONG_INLINE Packet4f pxor<Packet4f>(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<Packet4i>(const Packet4i& a, const Packet4i& b) { return veorq_s32(a,b); }
+
+template<> EIGEN_STRONG_INLINE Packet4f pandnot<Packet4f>(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<Packet4i>(const Packet4i& a, const Packet4i& b) { return vbicq_s32(a,b); }
+
+template<> EIGEN_STRONG_INLINE Packet4f pload<Packet4f>(const float* from) { EIGEN_DEBUG_ALIGNED_LOAD return vld1q_f32(from); }
+template<> EIGEN_STRONG_INLINE Packet4i pload<Packet4i>(const int* from) { EIGEN_DEBUG_ALIGNED_LOAD return vld1q_s32(from); }
+
+template<> EIGEN_STRONG_INLINE Packet4f ploadu<Packet4f>(const float* from) { EIGEN_DEBUG_UNALIGNED_LOAD return vld1q_f32(from); }
+template<> EIGEN_STRONG_INLINE Packet4i ploadu<Packet4i>(const int* from) { EIGEN_DEBUG_UNALIGNED_LOAD return vld1q_s32(from); }
+
+template<> EIGEN_STRONG_INLINE Packet4f ploaddup<Packet4f>(const float* from)
+{
+ float32x2_t lo, hi;
+ lo = vdup_n_f32(*from);
+ hi = vdup_n_f32(*(from+1));
+ return vcombine_f32(lo, hi);
+}
+template<> EIGEN_STRONG_INLINE Packet4i ploaddup<Packet4i>(const int* from)
+{
+ int32x2_t lo, hi;
+ lo = vdup_n_s32(*from);
+ hi = vdup_n_s32(*(from+1));
+ return vcombine_s32(lo, hi);
+}
+
+template<> EIGEN_STRONG_INLINE void pstore<float>(float* to, const Packet4f& from) { EIGEN_DEBUG_ALIGNED_STORE vst1q_f32(to, from); }
+template<> EIGEN_STRONG_INLINE void pstore<int>(int* to, const Packet4i& from) { EIGEN_DEBUG_ALIGNED_STORE vst1q_s32(to, from); }
+
+template<> EIGEN_STRONG_INLINE void pstoreu<float>(float* to, const Packet4f& from) { EIGEN_DEBUG_UNALIGNED_STORE vst1q_f32(to, from); }
+template<> EIGEN_STRONG_INLINE void pstoreu<int>(int* to, const Packet4i& from) { EIGEN_DEBUG_UNALIGNED_STORE vst1q_s32(to, from); }
+
+template<> EIGEN_STRONG_INLINE void prefetch<float>(const float* addr) { __pld(addr); }
+template<> EIGEN_STRONG_INLINE void prefetch<int>(const int* addr) { __pld(addr); }
+
+// FIXME only store the 2 first elements ?
+template<> EIGEN_STRONG_INLINE float pfirst<Packet4f>(const Packet4f& a) { float EIGEN_ALIGN16 x[4]; vst1q_f32(x, a); return x[0]; }
+template<> EIGEN_STRONG_INLINE int pfirst<Packet4i>(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<Packet4f>(const Packet4f& a)
+{
+ float32x2_t a_lo, a_hi, sum;
+ float s[2];
+
+ a_lo = vget_low_f32(a);
+ a_hi = vget_high_f32(a);
+ sum = vpadd_f32(a_lo, a_hi);
+ sum = vpadd_f32(sum, sum);
+ vst1_f32(s, sum);
+
+ return s[0];
+}
+
+template<> EIGEN_STRONG_INLINE Packet4f preduxp<Packet4f>(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<Packet4i>(const Packet4i& a)
+{
+ int32x2_t a_lo, a_hi, sum;
+ int32_t s[2];
+
+ a_lo = vget_low_s32(a);
+ a_hi = vget_high_s32(a);
+ sum = vpadd_s32(a_lo, a_hi);
+ sum = vpadd_s32(sum, sum);
+ vst1_s32(s, sum);
+
+ return s[0];
+}
+
+template<> EIGEN_STRONG_INLINE Packet4i preduxp<Packet4i>(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<Packet4f>(const Packet4f& a)
+{
+ float32x2_t a_lo, a_hi, prod;
+ float s[2];
+
+ // 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));
+ vst1_f32(s, prod);
+
+ return s[0];
+}
+template<> EIGEN_STRONG_INLINE int predux_mul<Packet4i>(const Packet4i& a)
+{
+ int32x2_t a_lo, a_hi, prod;
+ int32_t s[2];
+
+ // 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));
+ vst1_s32(s, prod);
+
+ return s[0];
+}
+
+// min
+template<> EIGEN_STRONG_INLINE float predux_min<Packet4f>(const Packet4f& a)
+{
+ float32x2_t a_lo, a_hi, min;
+ float s[2];
+
+ a_lo = vget_low_f32(a);
+ a_hi = vget_high_f32(a);
+ min = vpmin_f32(a_lo, a_hi);
+ min = vpmin_f32(min, min);
+ vst1_f32(s, min);
+
+ return s[0];
+}
+template<> EIGEN_STRONG_INLINE int predux_min<Packet4i>(const Packet4i& a)
+{
+ int32x2_t a_lo, a_hi, min;
+ int32_t s[2];
+
+ a_lo = vget_low_s32(a);
+ a_hi = vget_high_s32(a);
+ min = vpmin_s32(a_lo, a_hi);
+ min = vpmin_s32(min, min);
+ vst1_s32(s, min);
+
+ return s[0];
+}
+
+// max
+template<> EIGEN_STRONG_INLINE float predux_max<Packet4f>(const Packet4f& a)
+{
+ float32x2_t a_lo, a_hi, max;
+ float s[2];
+
+ a_lo = vget_low_f32(a);
+ a_hi = vget_high_f32(a);
+ max = vpmax_f32(a_lo, a_hi);
+ max = vpmax_f32(max, max);
+ vst1_f32(s, max);
+
+ return s[0];
+}
+template<> EIGEN_STRONG_INLINE int predux_max<Packet4i>(const Packet4i& a)
+{
+ int32x2_t a_lo, a_hi, max;
+ int32_t s[2];
+
+ a_lo = vget_low_s32(a);
+ a_hi = vget_high_s32(a);
+ max = vpmax_s32(a_lo, a_hi);
+ max = vpmax_s32(max, max);
+ vst1_s32(s, max);
+
+ return s[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<Offset,Type>\
+{\
+ 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/Eigen/src/Core/arch/SSE/CMakeLists.txt b/Eigen/src/Core/arch/SSE/CMakeLists.txt
new file mode 100644
index 000000000..46ea7cc62
--- /dev/null
+++ b/Eigen/src/Core/arch/SSE/CMakeLists.txt
@@ -0,0 +1,6 @@
+FILE(GLOB Eigen_Core_arch_SSE_SRCS "*.h")
+
+INSTALL(FILES
+ ${Eigen_Core_arch_SSE_SRCS}
+ DESTINATION ${INCLUDE_INSTALL_DIR}/Eigen/src/Core/arch/SSE COMPONENT Devel
+)
diff --git a/Eigen/src/Core/arch/SSE/Complex.h b/Eigen/src/Core/arch/SSE/Complex.h
new file mode 100644
index 000000000..12df98775
--- /dev/null
+++ b/Eigen/src/Core/arch/SSE/Complex.h
@@ -0,0 +1,436 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra.
+//
+// Copyright (C) 2010 Gael Guennebaud <gael.guennebaud@inria.fr>
+//
+// This Source Code Form is subject to the terms of the Mozilla
+// Public License v. 2.0. If a copy of the MPL was not distributed
+// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+#ifndef EIGEN_COMPLEX_SSE_H
+#define EIGEN_COMPLEX_SSE_H
+
+namespace Eigen {
+
+namespace internal {
+
+//---------- float ----------
+struct Packet2cf
+{
+ EIGEN_STRONG_INLINE Packet2cf() {}
+ EIGEN_STRONG_INLINE explicit Packet2cf(const __m128& a) : v(a) {}
+ __m128 v;
+};
+
+template<> struct packet_traits<std::complex<float> > : 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<Packet2cf> { typedef std::complex<float> type; enum {size=2}; };
+
+template<> EIGEN_STRONG_INLINE Packet2cf padd<Packet2cf>(const Packet2cf& a, const Packet2cf& b) { return Packet2cf(_mm_add_ps(a.v,b.v)); }
+template<> EIGEN_STRONG_INLINE Packet2cf psub<Packet2cf>(const Packet2cf& a, const Packet2cf& b) { return Packet2cf(_mm_sub_ps(a.v,b.v)); }
+template<> EIGEN_STRONG_INLINE Packet2cf pnegate(const Packet2cf& a)
+{
+ const __m128 mask = _mm_castsi128_ps(_mm_setr_epi32(0x80000000,0x80000000,0x80000000,0x80000000));
+ return Packet2cf(_mm_xor_ps(a.v,mask));
+}
+template<> EIGEN_STRONG_INLINE Packet2cf pconj(const Packet2cf& a)
+{
+ const __m128 mask = _mm_castsi128_ps(_mm_setr_epi32(0x00000000,0x80000000,0x00000000,0x80000000));
+ return Packet2cf(_mm_xor_ps(a.v,mask));
+}
+
+template<> EIGEN_STRONG_INLINE Packet2cf pmul<Packet2cf>(const Packet2cf& a, const Packet2cf& b)
+{
+ // TODO optimize it for SSE3 and 4
+ #ifdef EIGEN_VECTORIZE_SSE3
+ return Packet2cf(_mm_addsub_ps(_mm_mul_ps(_mm_moveldup_ps(a.v), b.v),
+ _mm_mul_ps(_mm_movehdup_ps(a.v),
+ vec4f_swizzle1(b.v, 1, 0, 3, 2))));
+// return Packet2cf(_mm_addsub_ps(_mm_mul_ps(vec4f_swizzle1(a.v, 0, 0, 2, 2), b.v),
+// _mm_mul_ps(vec4f_swizzle1(a.v, 1, 1, 3, 3),
+// vec4f_swizzle1(b.v, 1, 0, 3, 2))));
+ #else
+ const __m128 mask = _mm_castsi128_ps(_mm_setr_epi32(0x80000000,0x00000000,0x80000000,0x00000000));
+ return Packet2cf(_mm_add_ps(_mm_mul_ps(vec4f_swizzle1(a.v, 0, 0, 2, 2), b.v),
+ _mm_xor_ps(_mm_mul_ps(vec4f_swizzle1(a.v, 1, 1, 3, 3),
+ vec4f_swizzle1(b.v, 1, 0, 3, 2)), mask)));
+ #endif
+}
+
+template<> EIGEN_STRONG_INLINE Packet2cf pand <Packet2cf>(const Packet2cf& a, const Packet2cf& b) { return Packet2cf(_mm_and_ps(a.v,b.v)); }
+template<> EIGEN_STRONG_INLINE Packet2cf por <Packet2cf>(const Packet2cf& a, const Packet2cf& b) { return Packet2cf(_mm_or_ps(a.v,b.v)); }
+template<> EIGEN_STRONG_INLINE Packet2cf pxor <Packet2cf>(const Packet2cf& a, const Packet2cf& b) { return Packet2cf(_mm_xor_ps(a.v,b.v)); }
+template<> EIGEN_STRONG_INLINE Packet2cf pandnot<Packet2cf>(const Packet2cf& a, const Packet2cf& b) { return Packet2cf(_mm_andnot_ps(a.v,b.v)); }
+
+template<> EIGEN_STRONG_INLINE Packet2cf pload <Packet2cf>(const std::complex<float>* from) { EIGEN_DEBUG_ALIGNED_LOAD return Packet2cf(pload<Packet4f>(&real_ref(*from))); }
+template<> EIGEN_STRONG_INLINE Packet2cf ploadu<Packet2cf>(const std::complex<float>* from) { EIGEN_DEBUG_UNALIGNED_LOAD return Packet2cf(ploadu<Packet4f>(&real_ref(*from))); }
+
+template<> EIGEN_STRONG_INLINE Packet2cf pset1<Packet2cf>(const std::complex<float>& from)
+{
+ Packet2cf res;
+ #if EIGEN_GNUC_AT_MOST(4,2)
+ // workaround annoying "may be used uninitialized in this function" warning with gcc 4.2
+ res.v = _mm_loadl_pi(_mm_set1_ps(0.0f), reinterpret_cast<const __m64*>(&from));
+ #else
+ res.v = _mm_loadl_pi(res.v, (const __m64*)&from);
+ #endif
+ return Packet2cf(_mm_movelh_ps(res.v,res.v));
+}
+
+template<> EIGEN_STRONG_INLINE Packet2cf ploaddup<Packet2cf>(const std::complex<float>* from) { return pset1<Packet2cf>(*from); }
+
+template<> EIGEN_STRONG_INLINE void pstore <std::complex<float> >(std::complex<float> * to, const Packet2cf& from) { EIGEN_DEBUG_ALIGNED_STORE pstore(&real_ref(*to), from.v); }
+template<> EIGEN_STRONG_INLINE void pstoreu<std::complex<float> >(std::complex<float> * to, const Packet2cf& from) { EIGEN_DEBUG_UNALIGNED_STORE pstoreu(&real_ref(*to), from.v); }
+
+template<> EIGEN_STRONG_INLINE void prefetch<std::complex<float> >(const std::complex<float> * addr) { _mm_prefetch((const char*)(addr), _MM_HINT_T0); }
+
+template<> EIGEN_STRONG_INLINE std::complex<float> pfirst<Packet2cf>(const Packet2cf& a)
+{
+ #if EIGEN_GNUC_AT_MOST(4,3)
+ // Workaround gcc 4.2 ICE - this is not performance wise ideal, but who cares...
+ // This workaround also fix invalid code generation with gcc 4.3
+ EIGEN_ALIGN16 std::complex<float> res[2];
+ _mm_store_ps((float*)res, a.v);
+ return res[0];
+ #else
+ std::complex<float> res;
+ _mm_storel_pi((__m64*)&res, a.v);
+ return res;
+ #endif
+}
+
+template<> EIGEN_STRONG_INLINE Packet2cf preverse(const Packet2cf& a) { return Packet2cf(_mm_castpd_ps(preverse(_mm_castps_pd(a.v)))); }
+
+template<> EIGEN_STRONG_INLINE std::complex<float> predux<Packet2cf>(const Packet2cf& a)
+{
+ return pfirst(Packet2cf(_mm_add_ps(a.v, _mm_movehl_ps(a.v,a.v))));
+}
+
+template<> EIGEN_STRONG_INLINE Packet2cf preduxp<Packet2cf>(const Packet2cf* vecs)
+{
+ return Packet2cf(_mm_add_ps(_mm_movelh_ps(vecs[0].v,vecs[1].v), _mm_movehl_ps(vecs[1].v,vecs[0].v)));
+}
+
+template<> EIGEN_STRONG_INLINE std::complex<float> predux_mul<Packet2cf>(const Packet2cf& a)
+{
+ return pfirst(pmul(a, Packet2cf(_mm_movehl_ps(a.v,a.v))));
+}
+
+template<int Offset>
+struct palign_impl<Offset,Packet2cf>
+{
+ static EIGEN_STRONG_INLINE void run(Packet2cf& first, const Packet2cf& second)
+ {
+ if (Offset==1)
+ {
+ first.v = _mm_movehl_ps(first.v, first.v);
+ first.v = _mm_movelh_ps(first.v, second.v);
+ }
+ }
+};
+
+template<> struct conj_helper<Packet2cf, Packet2cf, false,true>
+{
+ 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
+ {
+ #ifdef EIGEN_VECTORIZE_SSE3
+ return internal::pmul(a, pconj(b));
+ #else
+ const __m128 mask = _mm_castsi128_ps(_mm_setr_epi32(0x00000000,0x80000000,0x00000000,0x80000000));
+ return Packet2cf(_mm_add_ps(_mm_xor_ps(_mm_mul_ps(vec4f_swizzle1(a.v, 0, 0, 2, 2), b.v), mask),
+ _mm_mul_ps(vec4f_swizzle1(a.v, 1, 1, 3, 3),
+ vec4f_swizzle1(b.v, 1, 0, 3, 2))));
+ #endif
+ }
+};
+
+template<> struct conj_helper<Packet2cf, Packet2cf, true,false>
+{
+ 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
+ {
+ #ifdef EIGEN_VECTORIZE_SSE3
+ return internal::pmul(pconj(a), b);
+ #else
+ const __m128 mask = _mm_castsi128_ps(_mm_setr_epi32(0x00000000,0x80000000,0x00000000,0x80000000));
+ return Packet2cf(_mm_add_ps(_mm_mul_ps(vec4f_swizzle1(a.v, 0, 0, 2, 2), b.v),
+ _mm_xor_ps(_mm_mul_ps(vec4f_swizzle1(a.v, 1, 1, 3, 3),
+ vec4f_swizzle1(b.v, 1, 0, 3, 2)), mask)));
+ #endif
+ }
+};
+
+template<> struct conj_helper<Packet2cf, Packet2cf, true,true>
+{
+ 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
+ {
+ #ifdef EIGEN_VECTORIZE_SSE3
+ return pconj(internal::pmul(a, b));
+ #else
+ const __m128 mask = _mm_castsi128_ps(_mm_setr_epi32(0x00000000,0x80000000,0x00000000,0x80000000));
+ return Packet2cf(_mm_sub_ps(_mm_xor_ps(_mm_mul_ps(vec4f_swizzle1(a.v, 0, 0, 2, 2), b.v), mask),
+ _mm_mul_ps(vec4f_swizzle1(a.v, 1, 1, 3, 3),
+ vec4f_swizzle1(b.v, 1, 0, 3, 2))));
+ #endif
+ }
+};
+
+template<> struct conj_helper<Packet4f, Packet2cf, false,false>
+{
+ EIGEN_STRONG_INLINE Packet2cf pmadd(const Packet4f& x, const Packet2cf& y, const Packet2cf& c) const
+ { return padd(c, pmul(x,y)); }
+
+ EIGEN_STRONG_INLINE Packet2cf pmul(const Packet4f& x, const Packet2cf& y) const
+ { return Packet2cf(Eigen::internal::pmul(x, y.v)); }
+};
+
+template<> struct conj_helper<Packet2cf, Packet4f, false,false>
+{
+ EIGEN_STRONG_INLINE Packet2cf pmadd(const Packet2cf& x, const Packet4f& y, const Packet2cf& c) const
+ { return padd(c, pmul(x,y)); }
+
+ EIGEN_STRONG_INLINE Packet2cf pmul(const Packet2cf& x, const Packet4f& y) const
+ { return Packet2cf(Eigen::internal::pmul(x.v, y)); }
+};
+
+template<> EIGEN_STRONG_INLINE Packet2cf pdiv<Packet2cf>(const Packet2cf& a, const Packet2cf& b)
+{
+ // TODO optimize it for SSE3 and 4
+ Packet2cf res = conj_helper<Packet2cf,Packet2cf,false,true>().pmul(a,b);
+ __m128 s = _mm_mul_ps(b.v,b.v);
+ return Packet2cf(_mm_div_ps(res.v,_mm_add_ps(s,_mm_castsi128_ps(_mm_shuffle_epi32(_mm_castps_si128(s), 0xb1)))));
+}
+
+EIGEN_STRONG_INLINE Packet2cf pcplxflip/*<Packet2cf>*/(const Packet2cf& x)
+{
+ return Packet2cf(vec4f_swizzle1(x.v, 1, 0, 3, 2));
+}
+
+
+//---------- double ----------
+struct Packet1cd
+{
+ EIGEN_STRONG_INLINE Packet1cd() {}
+ EIGEN_STRONG_INLINE explicit Packet1cd(const __m128d& a) : v(a) {}
+ __m128d v;
+};
+
+template<> struct packet_traits<std::complex<double> > : default_packet_traits
+{
+ typedef Packet1cd type;
+ enum {
+ Vectorizable = 1,
+ AlignedOnScalar = 0,
+ size = 1,
+
+ HasAdd = 1,
+ HasSub = 1,
+ HasMul = 1,
+ HasDiv = 1,
+ HasNegate = 1,
+ HasAbs = 0,
+ HasAbs2 = 0,
+ HasMin = 0,
+ HasMax = 0,
+ HasSetLinear = 0
+ };
+};
+
+template<> struct unpacket_traits<Packet1cd> { typedef std::complex<double> type; enum {size=1}; };
+
+template<> EIGEN_STRONG_INLINE Packet1cd padd<Packet1cd>(const Packet1cd& a, const Packet1cd& b) { return Packet1cd(_mm_add_pd(a.v,b.v)); }
+template<> EIGEN_STRONG_INLINE Packet1cd psub<Packet1cd>(const Packet1cd& a, const Packet1cd& b) { return Packet1cd(_mm_sub_pd(a.v,b.v)); }
+template<> EIGEN_STRONG_INLINE Packet1cd pnegate(const Packet1cd& a) { return Packet1cd(pnegate(a.v)); }
+template<> EIGEN_STRONG_INLINE Packet1cd pconj(const Packet1cd& a)
+{
+ const __m128d mask = _mm_castsi128_pd(_mm_set_epi32(0x80000000,0x0,0x0,0x0));
+ return Packet1cd(_mm_xor_pd(a.v,mask));
+}
+
+template<> EIGEN_STRONG_INLINE Packet1cd pmul<Packet1cd>(const Packet1cd& a, const Packet1cd& b)
+{
+ // TODO optimize it for SSE3 and 4
+ #ifdef EIGEN_VECTORIZE_SSE3
+ return Packet1cd(_mm_addsub_pd(_mm_mul_pd(vec2d_swizzle1(a.v, 0, 0), b.v),
+ _mm_mul_pd(vec2d_swizzle1(a.v, 1, 1),
+ vec2d_swizzle1(b.v, 1, 0))));
+ #else
+ const __m128d mask = _mm_castsi128_pd(_mm_set_epi32(0x0,0x0,0x80000000,0x0));
+ return Packet1cd(_mm_add_pd(_mm_mul_pd(vec2d_swizzle1(a.v, 0, 0), b.v),
+ _mm_xor_pd(_mm_mul_pd(vec2d_swizzle1(a.v, 1, 1),
+ vec2d_swizzle1(b.v, 1, 0)), mask)));
+ #endif
+}
+
+template<> EIGEN_STRONG_INLINE Packet1cd pand <Packet1cd>(const Packet1cd& a, const Packet1cd& b) { return Packet1cd(_mm_and_pd(a.v,b.v)); }
+template<> EIGEN_STRONG_INLINE Packet1cd por <Packet1cd>(const Packet1cd& a, const Packet1cd& b) { return Packet1cd(_mm_or_pd(a.v,b.v)); }
+template<> EIGEN_STRONG_INLINE Packet1cd pxor <Packet1cd>(const Packet1cd& a, const Packet1cd& b) { return Packet1cd(_mm_xor_pd(a.v,b.v)); }
+template<> EIGEN_STRONG_INLINE Packet1cd pandnot<Packet1cd>(const Packet1cd& a, const Packet1cd& b) { return Packet1cd(_mm_andnot_pd(a.v,b.v)); }
+
+// FIXME force unaligned load, this is a temporary fix
+template<> EIGEN_STRONG_INLINE Packet1cd pload <Packet1cd>(const std::complex<double>* from)
+{ EIGEN_DEBUG_ALIGNED_LOAD return Packet1cd(pload<Packet2d>((const double*)from)); }
+template<> EIGEN_STRONG_INLINE Packet1cd ploadu<Packet1cd>(const std::complex<double>* from)
+{ EIGEN_DEBUG_UNALIGNED_LOAD return Packet1cd(ploadu<Packet2d>((const double*)from)); }
+template<> EIGEN_STRONG_INLINE Packet1cd pset1<Packet1cd>(const std::complex<double>& from)
+{ /* here we really have to use unaligned loads :( */ return ploadu<Packet1cd>(&from); }
+
+template<> EIGEN_STRONG_INLINE Packet1cd ploaddup<Packet1cd>(const std::complex<double>* from) { return pset1<Packet1cd>(*from); }
+
+// FIXME force unaligned store, this is a temporary fix
+template<> EIGEN_STRONG_INLINE void pstore <std::complex<double> >(std::complex<double> * to, const Packet1cd& from) { EIGEN_DEBUG_ALIGNED_STORE pstore((double*)to, from.v); }
+template<> EIGEN_STRONG_INLINE void pstoreu<std::complex<double> >(std::complex<double> * to, const Packet1cd& from) { EIGEN_DEBUG_UNALIGNED_STORE pstoreu((double*)to, from.v); }
+
+template<> EIGEN_STRONG_INLINE void prefetch<std::complex<double> >(const std::complex<double> * addr) { _mm_prefetch((const char*)(addr), _MM_HINT_T0); }
+
+template<> EIGEN_STRONG_INLINE std::complex<double> pfirst<Packet1cd>(const Packet1cd& a)
+{
+ EIGEN_ALIGN16 double res[2];
+ _mm_store_pd(res, a.v);
+ return std::complex<double>(res[0],res[1]);
+}
+
+template<> EIGEN_STRONG_INLINE Packet1cd preverse(const Packet1cd& a) { return a; }
+
+template<> EIGEN_STRONG_INLINE std::complex<double> predux<Packet1cd>(const Packet1cd& a)
+{
+ return pfirst(a);
+}
+
+template<> EIGEN_STRONG_INLINE Packet1cd preduxp<Packet1cd>(const Packet1cd* vecs)
+{
+ return vecs[0];
+}
+
+template<> EIGEN_STRONG_INLINE std::complex<double> predux_mul<Packet1cd>(const Packet1cd& a)
+{
+ return pfirst(a);
+}
+
+template<int Offset>
+struct palign_impl<Offset,Packet1cd>
+{
+ static EIGEN_STRONG_INLINE void run(Packet1cd& /*first*/, const Packet1cd& /*second*/)
+ {
+ // FIXME is it sure we never have to align a Packet1cd?
+ // Even though a std::complex<double> has 16 bytes, it is not necessarily aligned on a 16 bytes boundary...
+ }
+};
+
+template<> struct conj_helper<Packet1cd, Packet1cd, false,true>
+{
+ EIGEN_STRONG_INLINE Packet1cd pmadd(const Packet1cd& x, const Packet1cd& y, const Packet1cd& c) const
+ { return padd(pmul(x,y),c); }
+
+ EIGEN_STRONG_INLINE Packet1cd pmul(const Packet1cd& a, const Packet1cd& b) const
+ {
+ #ifdef EIGEN_VECTORIZE_SSE3
+ return internal::pmul(a, pconj(b));
+ #else
+ const __m128d mask = _mm_castsi128_pd(_mm_set_epi32(0x80000000,0x0,0x0,0x0));
+ return Packet1cd(_mm_add_pd(_mm_xor_pd(_mm_mul_pd(vec2d_swizzle1(a.v, 0, 0), b.v), mask),
+ _mm_mul_pd(vec2d_swizzle1(a.v, 1, 1),
+ vec2d_swizzle1(b.v, 1, 0))));
+ #endif
+ }
+};
+
+template<> struct conj_helper<Packet1cd, Packet1cd, true,false>
+{
+ EIGEN_STRONG_INLINE Packet1cd pmadd(const Packet1cd& x, const Packet1cd& y, const Packet1cd& c) const
+ { return padd(pmul(x,y),c); }
+
+ EIGEN_STRONG_INLINE Packet1cd pmul(const Packet1cd& a, const Packet1cd& b) const
+ {
+ #ifdef EIGEN_VECTORIZE_SSE3
+ return internal::pmul(pconj(a), b);
+ #else
+ const __m128d mask = _mm_castsi128_pd(_mm_set_epi32(0x80000000,0x0,0x0,0x0));
+ return Packet1cd(_mm_add_pd(_mm_mul_pd(vec2d_swizzle1(a.v, 0, 0), b.v),
+ _mm_xor_pd(_mm_mul_pd(vec2d_swizzle1(a.v, 1, 1),
+ vec2d_swizzle1(b.v, 1, 0)), mask)));
+ #endif
+ }
+};
+
+template<> struct conj_helper<Packet1cd, Packet1cd, true,true>
+{
+ EIGEN_STRONG_INLINE Packet1cd pmadd(const Packet1cd& x, const Packet1cd& y, const Packet1cd& c) const
+ { return padd(pmul(x,y),c); }
+
+ EIGEN_STRONG_INLINE Packet1cd pmul(const Packet1cd& a, const Packet1cd& b) const
+ {
+ #ifdef EIGEN_VECTORIZE_SSE3
+ return pconj(internal::pmul(a, b));
+ #else
+ const __m128d mask = _mm_castsi128_pd(_mm_set_epi32(0x80000000,0x0,0x0,0x0));
+ return Packet1cd(_mm_sub_pd(_mm_xor_pd(_mm_mul_pd(vec2d_swizzle1(a.v, 0, 0), b.v), mask),
+ _mm_mul_pd(vec2d_swizzle1(a.v, 1, 1),
+ vec2d_swizzle1(b.v, 1, 0))));
+ #endif
+ }
+};
+
+template<> struct conj_helper<Packet2d, Packet1cd, false,false>
+{
+ EIGEN_STRONG_INLINE Packet1cd pmadd(const Packet2d& x, const Packet1cd& y, const Packet1cd& c) const
+ { return padd(c, pmul(x,y)); }
+
+ EIGEN_STRONG_INLINE Packet1cd pmul(const Packet2d& x, const Packet1cd& y) const
+ { return Packet1cd(Eigen::internal::pmul(x, y.v)); }
+};
+
+template<> struct conj_helper<Packet1cd, Packet2d, false,false>
+{
+ EIGEN_STRONG_INLINE Packet1cd pmadd(const Packet1cd& x, const Packet2d& y, const Packet1cd& c) const
+ { return padd(c, pmul(x,y)); }
+
+ EIGEN_STRONG_INLINE Packet1cd pmul(const Packet1cd& x, const Packet2d& y) const
+ { return Packet1cd(Eigen::internal::pmul(x.v, y)); }
+};
+
+template<> EIGEN_STRONG_INLINE Packet1cd pdiv<Packet1cd>(const Packet1cd& a, const Packet1cd& b)
+{
+ // TODO optimize it for SSE3 and 4
+ Packet1cd res = conj_helper<Packet1cd,Packet1cd,false,true>().pmul(a,b);
+ __m128d s = _mm_mul_pd(b.v,b.v);
+ return Packet1cd(_mm_div_pd(res.v, _mm_add_pd(s,_mm_shuffle_pd(s, s, 0x1))));
+}
+
+EIGEN_STRONG_INLINE Packet1cd pcplxflip/*<Packet1cd>*/(const Packet1cd& x)
+{
+ return Packet1cd(preverse(x.v));
+}
+
+} // end namespace internal
+
+} // end namespace Eigen
+
+#endif // EIGEN_COMPLEX_SSE_H
diff --git a/Eigen/src/Core/arch/SSE/MathFunctions.h b/Eigen/src/Core/arch/SSE/MathFunctions.h
new file mode 100644
index 000000000..3f41a4e26
--- /dev/null
+++ b/Eigen/src/Core/arch/SSE/MathFunctions.h
@@ -0,0 +1,384 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra.
+//
+// Copyright (C) 2007 Julien Pommier
+// Copyright (C) 2009 Gael Guennebaud <gael.guennebaud@inria.fr>
+//
+// This Source Code Form is subject to the terms of the Mozilla
+// Public License v. 2.0. If a copy of the MPL was not distributed
+// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+/* The sin, cos, exp, and log functions of this file come from
+ * Julien Pommier's sse math library: http://gruntthepeon.free.fr/ssemath/
+ */
+
+#ifndef EIGEN_MATH_FUNCTIONS_SSE_H
+#define EIGEN_MATH_FUNCTIONS_SSE_H
+
+namespace Eigen {
+
+namespace internal {
+
+template<> EIGEN_DEFINE_FUNCTION_ALLOWING_MULTIPLE_DEFINITIONS EIGEN_UNUSED
+Packet4f plog<Packet4f>(const Packet4f& _x)
+{
+ Packet4f x = _x;
+ _EIGEN_DECLARE_CONST_Packet4f(1 , 1.0f);
+ _EIGEN_DECLARE_CONST_Packet4f(half, 0.5f);
+ _EIGEN_DECLARE_CONST_Packet4i(0x7f, 0x7f);
+
+ _EIGEN_DECLARE_CONST_Packet4f_FROM_INT(inv_mant_mask, ~0x7f800000);
+
+ /* the smallest non denormalized float number */
+ _EIGEN_DECLARE_CONST_Packet4f_FROM_INT(min_norm_pos, 0x00800000);
+
+ /* natural logarithm computed for 4 simultaneous float
+ return NaN for x <= 0
+ */
+ _EIGEN_DECLARE_CONST_Packet4f(cephes_SQRTHF, 0.707106781186547524f);
+ _EIGEN_DECLARE_CONST_Packet4f(cephes_log_p0, 7.0376836292E-2f);
+ _EIGEN_DECLARE_CONST_Packet4f(cephes_log_p1, - 1.1514610310E-1f);
+ _EIGEN_DECLARE_CONST_Packet4f(cephes_log_p2, 1.1676998740E-1f);
+ _EIGEN_DECLARE_CONST_Packet4f(cephes_log_p3, - 1.2420140846E-1f);
+ _EIGEN_DECLARE_CONST_Packet4f(cephes_log_p4, + 1.4249322787E-1f);
+ _EIGEN_DECLARE_CONST_Packet4f(cephes_log_p5, - 1.6668057665E-1f);
+ _EIGEN_DECLARE_CONST_Packet4f(cephes_log_p6, + 2.0000714765E-1f);
+ _EIGEN_DECLARE_CONST_Packet4f(cephes_log_p7, - 2.4999993993E-1f);
+ _EIGEN_DECLARE_CONST_Packet4f(cephes_log_p8, + 3.3333331174E-1f);
+ _EIGEN_DECLARE_CONST_Packet4f(cephes_log_q1, -2.12194440e-4f);
+ _EIGEN_DECLARE_CONST_Packet4f(cephes_log_q2, 0.693359375f);
+
+
+ Packet4i emm0;
+
+ Packet4f invalid_mask = _mm_cmple_ps(x, _mm_setzero_ps());
+
+ x = pmax(x, p4f_min_norm_pos); /* cut off denormalized stuff */
+ emm0 = _mm_srli_epi32(_mm_castps_si128(x), 23);
+
+ /* keep only the fractional part */
+ x = _mm_and_ps(x, p4f_inv_mant_mask);
+ x = _mm_or_ps(x, p4f_half);
+
+ emm0 = _mm_sub_epi32(emm0, p4i_0x7f);
+ Packet4f e = padd(_mm_cvtepi32_ps(emm0), p4f_1);
+
+ /* part2:
+ if( x < SQRTHF ) {
+ e -= 1;
+ x = x + x - 1.0;
+ } else { x = x - 1.0; }
+ */
+ Packet4f mask = _mm_cmplt_ps(x, p4f_cephes_SQRTHF);
+ Packet4f tmp = _mm_and_ps(x, mask);
+ x = psub(x, p4f_1);
+ e = psub(e, _mm_and_ps(p4f_1, mask));
+ x = padd(x, tmp);
+
+ Packet4f x2 = pmul(x,x);
+ Packet4f x3 = pmul(x2,x);
+
+ Packet4f y, y1, y2;
+ y = pmadd(p4f_cephes_log_p0, x, p4f_cephes_log_p1);
+ y1 = pmadd(p4f_cephes_log_p3, x, p4f_cephes_log_p4);
+ y2 = pmadd(p4f_cephes_log_p6, x, p4f_cephes_log_p7);
+ y = pmadd(y , x, p4f_cephes_log_p2);
+ y1 = pmadd(y1, x, p4f_cephes_log_p5);
+ y2 = pmadd(y2, x, p4f_cephes_log_p8);
+ y = pmadd(y, x3, y1);
+ y = pmadd(y, x3, y2);
+ y = pmul(y, x3);
+
+ y1 = pmul(e, p4f_cephes_log_q1);
+ tmp = pmul(x2, p4f_half);
+ y = padd(y, y1);
+ x = psub(x, tmp);
+ y2 = pmul(e, p4f_cephes_log_q2);
+ x = padd(x, y);
+ x = padd(x, y2);
+ return _mm_or_ps(x, invalid_mask); // negative arg will be NAN
+}
+
+template<> EIGEN_DEFINE_FUNCTION_ALLOWING_MULTIPLE_DEFINITIONS EIGEN_UNUSED
+Packet4f pexp<Packet4f>(const Packet4f& _x)
+{
+ Packet4f x = _x;
+ _EIGEN_DECLARE_CONST_Packet4f(1 , 1.0f);
+ _EIGEN_DECLARE_CONST_Packet4f(half, 0.5f);
+ _EIGEN_DECLARE_CONST_Packet4i(0x7f, 0x7f);
+
+
+ _EIGEN_DECLARE_CONST_Packet4f(exp_hi, 88.3762626647950f);
+ _EIGEN_DECLARE_CONST_Packet4f(exp_lo, -88.3762626647949f);
+
+ _EIGEN_DECLARE_CONST_Packet4f(cephes_LOG2EF, 1.44269504088896341f);
+ _EIGEN_DECLARE_CONST_Packet4f(cephes_exp_C1, 0.693359375f);
+ _EIGEN_DECLARE_CONST_Packet4f(cephes_exp_C2, -2.12194440e-4f);
+
+ _EIGEN_DECLARE_CONST_Packet4f(cephes_exp_p0, 1.9875691500E-4f);
+ _EIGEN_DECLARE_CONST_Packet4f(cephes_exp_p1, 1.3981999507E-3f);
+ _EIGEN_DECLARE_CONST_Packet4f(cephes_exp_p2, 8.3334519073E-3f);
+ _EIGEN_DECLARE_CONST_Packet4f(cephes_exp_p3, 4.1665795894E-2f);
+ _EIGEN_DECLARE_CONST_Packet4f(cephes_exp_p4, 1.6666665459E-1f);
+ _EIGEN_DECLARE_CONST_Packet4f(cephes_exp_p5, 5.0000001201E-1f);
+
+ Packet4f tmp = _mm_setzero_ps(), fx;
+ Packet4i emm0;
+
+ // clamp x
+ x = pmax(pmin(x, p4f_exp_hi), p4f_exp_lo);
+
+ /* express exp(x) as exp(g + n*log(2)) */
+ fx = pmadd(x, p4f_cephes_LOG2EF, p4f_half);
+
+ /* how to perform a floorf with SSE: just below */
+ emm0 = _mm_cvttps_epi32(fx);
+ tmp = _mm_cvtepi32_ps(emm0);
+ /* if greater, substract 1 */
+ Packet4f mask = _mm_cmpgt_ps(tmp, fx);
+ mask = _mm_and_ps(mask, p4f_1);
+ fx = psub(tmp, mask);
+
+ tmp = pmul(fx, p4f_cephes_exp_C1);
+ Packet4f z = pmul(fx, p4f_cephes_exp_C2);
+ x = psub(x, tmp);
+ x = psub(x, z);
+
+ z = pmul(x,x);
+
+ Packet4f y = p4f_cephes_exp_p0;
+ y = pmadd(y, x, p4f_cephes_exp_p1);
+ y = pmadd(y, x, p4f_cephes_exp_p2);
+ y = pmadd(y, x, p4f_cephes_exp_p3);
+ y = pmadd(y, x, p4f_cephes_exp_p4);
+ y = pmadd(y, x, p4f_cephes_exp_p5);
+ y = pmadd(y, z, x);
+ y = padd(y, p4f_1);
+
+ // build 2^n
+ emm0 = _mm_cvttps_epi32(fx);
+ emm0 = _mm_add_epi32(emm0, p4i_0x7f);
+ emm0 = _mm_slli_epi32(emm0, 23);
+ return pmul(y, _mm_castsi128_ps(emm0));
+}
+
+/* evaluation of 4 sines at onces, using SSE2 intrinsics.
+
+ The code is the exact rewriting of the cephes sinf function.
+ Precision is excellent as long as x < 8192 (I did not bother to
+ take into account the special handling they have for greater values
+ -- it does not return garbage for arguments over 8192, though, but
+ the extra precision is missing).
+
+ Note that it is such that sinf((float)M_PI) = 8.74e-8, which is the
+ surprising but correct result.
+*/
+
+template<> EIGEN_DEFINE_FUNCTION_ALLOWING_MULTIPLE_DEFINITIONS EIGEN_UNUSED
+Packet4f psin<Packet4f>(const Packet4f& _x)
+{
+ Packet4f x = _x;
+ _EIGEN_DECLARE_CONST_Packet4f(1 , 1.0f);
+ _EIGEN_DECLARE_CONST_Packet4f(half, 0.5f);
+
+ _EIGEN_DECLARE_CONST_Packet4i(1, 1);
+ _EIGEN_DECLARE_CONST_Packet4i(not1, ~1);
+ _EIGEN_DECLARE_CONST_Packet4i(2, 2);
+ _EIGEN_DECLARE_CONST_Packet4i(4, 4);
+
+ _EIGEN_DECLARE_CONST_Packet4f_FROM_INT(sign_mask, 0x80000000);
+
+ _EIGEN_DECLARE_CONST_Packet4f(minus_cephes_DP1,-0.78515625f);
+ _EIGEN_DECLARE_CONST_Packet4f(minus_cephes_DP2, -2.4187564849853515625e-4f);
+ _EIGEN_DECLARE_CONST_Packet4f(minus_cephes_DP3, -3.77489497744594108e-8f);
+ _EIGEN_DECLARE_CONST_Packet4f(sincof_p0, -1.9515295891E-4f);
+ _EIGEN_DECLARE_CONST_Packet4f(sincof_p1, 8.3321608736E-3f);
+ _EIGEN_DECLARE_CONST_Packet4f(sincof_p2, -1.6666654611E-1f);
+ _EIGEN_DECLARE_CONST_Packet4f(coscof_p0, 2.443315711809948E-005f);
+ _EIGEN_DECLARE_CONST_Packet4f(coscof_p1, -1.388731625493765E-003f);
+ _EIGEN_DECLARE_CONST_Packet4f(coscof_p2, 4.166664568298827E-002f);
+ _EIGEN_DECLARE_CONST_Packet4f(cephes_FOPI, 1.27323954473516f); // 4 / M_PI
+
+ Packet4f xmm1, xmm2 = _mm_setzero_ps(), xmm3, sign_bit, y;
+
+ Packet4i emm0, emm2;
+ sign_bit = x;
+ /* take the absolute value */
+ x = pabs(x);
+
+ /* take the modulo */
+
+ /* extract the sign bit (upper one) */
+ sign_bit = _mm_and_ps(sign_bit, p4f_sign_mask);
+
+ /* scale by 4/Pi */
+ y = pmul(x, p4f_cephes_FOPI);
+
+ /* store the integer part of y in mm0 */
+ emm2 = _mm_cvttps_epi32(y);
+ /* j=(j+1) & (~1) (see the cephes sources) */
+ emm2 = _mm_add_epi32(emm2, p4i_1);
+ emm2 = _mm_and_si128(emm2, p4i_not1);
+ y = _mm_cvtepi32_ps(emm2);
+ /* get the swap sign flag */
+ emm0 = _mm_and_si128(emm2, p4i_4);
+ emm0 = _mm_slli_epi32(emm0, 29);
+ /* get the polynom selection mask
+ there is one polynom for 0 <= x <= Pi/4
+ and another one for Pi/4<x<=Pi/2
+
+ Both branches will be computed.
+ */
+ emm2 = _mm_and_si128(emm2, p4i_2);
+ emm2 = _mm_cmpeq_epi32(emm2, _mm_setzero_si128());
+
+ Packet4f swap_sign_bit = _mm_castsi128_ps(emm0);
+ Packet4f poly_mask = _mm_castsi128_ps(emm2);
+ sign_bit = _mm_xor_ps(sign_bit, swap_sign_bit);
+
+ /* The magic pass: "Extended precision modular arithmetic"
+ x = ((x - y * DP1) - y * DP2) - y * DP3; */
+ xmm1 = pmul(y, p4f_minus_cephes_DP1);
+ xmm2 = pmul(y, p4f_minus_cephes_DP2);
+ xmm3 = pmul(y, p4f_minus_cephes_DP3);
+ x = padd(x, xmm1);
+ x = padd(x, xmm2);
+ x = padd(x, xmm3);
+
+ /* Evaluate the first polynom (0 <= x <= Pi/4) */
+ y = p4f_coscof_p0;
+ Packet4f z = _mm_mul_ps(x,x);
+
+ y = pmadd(y, z, p4f_coscof_p1);
+ y = pmadd(y, z, p4f_coscof_p2);
+ y = pmul(y, z);
+ y = pmul(y, z);
+ Packet4f tmp = pmul(z, p4f_half);
+ y = psub(y, tmp);
+ y = padd(y, p4f_1);
+
+ /* Evaluate the second polynom (Pi/4 <= x <= 0) */
+
+ Packet4f y2 = p4f_sincof_p0;
+ y2 = pmadd(y2, z, p4f_sincof_p1);
+ y2 = pmadd(y2, z, p4f_sincof_p2);
+ y2 = pmul(y2, z);
+ y2 = pmul(y2, x);
+ y2 = padd(y2, x);
+
+ /* select the correct result from the two polynoms */
+ y2 = _mm_and_ps(poly_mask, y2);
+ y = _mm_andnot_ps(poly_mask, y);
+ y = _mm_or_ps(y,y2);
+ /* update the sign */
+ return _mm_xor_ps(y, sign_bit);
+}
+
+/* almost the same as psin */
+template<> EIGEN_DEFINE_FUNCTION_ALLOWING_MULTIPLE_DEFINITIONS EIGEN_UNUSED
+Packet4f pcos<Packet4f>(const Packet4f& _x)
+{
+ Packet4f x = _x;
+ _EIGEN_DECLARE_CONST_Packet4f(1 , 1.0f);
+ _EIGEN_DECLARE_CONST_Packet4f(half, 0.5f);
+
+ _EIGEN_DECLARE_CONST_Packet4i(1, 1);
+ _EIGEN_DECLARE_CONST_Packet4i(not1, ~1);
+ _EIGEN_DECLARE_CONST_Packet4i(2, 2);
+ _EIGEN_DECLARE_CONST_Packet4i(4, 4);
+
+ _EIGEN_DECLARE_CONST_Packet4f(minus_cephes_DP1,-0.78515625f);
+ _EIGEN_DECLARE_CONST_Packet4f(minus_cephes_DP2, -2.4187564849853515625e-4f);
+ _EIGEN_DECLARE_CONST_Packet4f(minus_cephes_DP3, -3.77489497744594108e-8f);
+ _EIGEN_DECLARE_CONST_Packet4f(sincof_p0, -1.9515295891E-4f);
+ _EIGEN_DECLARE_CONST_Packet4f(sincof_p1, 8.3321608736E-3f);
+ _EIGEN_DECLARE_CONST_Packet4f(sincof_p2, -1.6666654611E-1f);
+ _EIGEN_DECLARE_CONST_Packet4f(coscof_p0, 2.443315711809948E-005f);
+ _EIGEN_DECLARE_CONST_Packet4f(coscof_p1, -1.388731625493765E-003f);
+ _EIGEN_DECLARE_CONST_Packet4f(coscof_p2, 4.166664568298827E-002f);
+ _EIGEN_DECLARE_CONST_Packet4f(cephes_FOPI, 1.27323954473516f); // 4 / M_PI
+
+ Packet4f xmm1, xmm2 = _mm_setzero_ps(), xmm3, y;
+ Packet4i emm0, emm2;
+
+ x = pabs(x);
+
+ /* scale by 4/Pi */
+ y = pmul(x, p4f_cephes_FOPI);
+
+ /* get the integer part of y */
+ emm2 = _mm_cvttps_epi32(y);
+ /* j=(j+1) & (~1) (see the cephes sources) */
+ emm2 = _mm_add_epi32(emm2, p4i_1);
+ emm2 = _mm_and_si128(emm2, p4i_not1);
+ y = _mm_cvtepi32_ps(emm2);
+
+ emm2 = _mm_sub_epi32(emm2, p4i_2);
+
+ /* get the swap sign flag */
+ emm0 = _mm_andnot_si128(emm2, p4i_4);
+ emm0 = _mm_slli_epi32(emm0, 29);
+ /* get the polynom selection mask */
+ emm2 = _mm_and_si128(emm2, p4i_2);
+ emm2 = _mm_cmpeq_epi32(emm2, _mm_setzero_si128());
+
+ Packet4f sign_bit = _mm_castsi128_ps(emm0);
+ Packet4f poly_mask = _mm_castsi128_ps(emm2);
+
+ /* The magic pass: "Extended precision modular arithmetic"
+ x = ((x - y * DP1) - y * DP2) - y * DP3; */
+ xmm1 = pmul(y, p4f_minus_cephes_DP1);
+ xmm2 = pmul(y, p4f_minus_cephes_DP2);
+ xmm3 = pmul(y, p4f_minus_cephes_DP3);
+ x = padd(x, xmm1);
+ x = padd(x, xmm2);
+ x = padd(x, xmm3);
+
+ /* Evaluate the first polynom (0 <= x <= Pi/4) */
+ y = p4f_coscof_p0;
+ Packet4f z = pmul(x,x);
+
+ y = pmadd(y,z,p4f_coscof_p1);
+ y = pmadd(y,z,p4f_coscof_p2);
+ y = pmul(y, z);
+ y = pmul(y, z);
+ Packet4f tmp = _mm_mul_ps(z, p4f_half);
+ y = psub(y, tmp);
+ y = padd(y, p4f_1);
+
+ /* Evaluate the second polynom (Pi/4 <= x <= 0) */
+ Packet4f y2 = p4f_sincof_p0;
+ y2 = pmadd(y2, z, p4f_sincof_p1);
+ y2 = pmadd(y2, z, p4f_sincof_p2);
+ y2 = pmul(y2, z);
+ y2 = pmadd(y2, x, x);
+
+ /* select the correct result from the two polynoms */
+ y2 = _mm_and_ps(poly_mask, y2);
+ y = _mm_andnot_ps(poly_mask, y);
+ y = _mm_or_ps(y,y2);
+
+ /* update the sign */
+ return _mm_xor_ps(y, sign_bit);
+}
+
+// This is based on Quake3's fast inverse square root.
+// For detail see here: http://www.beyond3d.com/content/articles/8/
+template<> EIGEN_DEFINE_FUNCTION_ALLOWING_MULTIPLE_DEFINITIONS EIGEN_UNUSED
+Packet4f psqrt<Packet4f>(const Packet4f& _x)
+{
+ Packet4f half = pmul(_x, pset1<Packet4f>(.5f));
+
+ /* select only the inverse sqrt of non-zero inputs */
+ Packet4f non_zero_mask = _mm_cmpgt_ps(_x, pset1<Packet4f>(std::numeric_limits<float>::epsilon()));
+ Packet4f x = _mm_and_ps(non_zero_mask, _mm_rsqrt_ps(_x));
+
+ x = pmul(x, psub(pset1<Packet4f>(1.5f), pmul(half, pmul(x,x))));
+ return pmul(_x,x);
+}
+
+} // end namespace internal
+
+} // end namespace Eigen
+
+#endif // EIGEN_MATH_FUNCTIONS_SSE_H
diff --git a/Eigen/src/Core/arch/SSE/PacketMath.h b/Eigen/src/Core/arch/SSE/PacketMath.h
new file mode 100644
index 000000000..10d918219
--- /dev/null
+++ b/Eigen/src/Core/arch/SSE/PacketMath.h
@@ -0,0 +1,632 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra.
+//
+// Copyright (C) 2008-2009 Gael Guennebaud <gael.guennebaud@inria.fr>
+//
+// This Source Code Form is subject to the terms of the Mozilla
+// Public License v. 2.0. If a copy of the MPL was not distributed
+// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+#ifndef EIGEN_PACKET_MATH_SSE_H
+#define EIGEN_PACKET_MATH_SSE_H
+
+namespace Eigen {
+
+namespace internal {
+
+#ifndef EIGEN_CACHEFRIENDLY_PRODUCT_THRESHOLD
+#define EIGEN_CACHEFRIENDLY_PRODUCT_THRESHOLD 8
+#endif
+
+#ifndef EIGEN_ARCH_DEFAULT_NUMBER_OF_REGISTERS
+#define EIGEN_ARCH_DEFAULT_NUMBER_OF_REGISTERS (2*sizeof(void*))
+#endif
+
+typedef __m128 Packet4f;
+typedef __m128i Packet4i;
+typedef __m128d Packet2d;
+
+template<> struct is_arithmetic<__m128> { enum { value = true }; };
+template<> struct is_arithmetic<__m128i> { enum { value = true }; };
+template<> struct is_arithmetic<__m128d> { enum { value = true }; };
+
+#define vec4f_swizzle1(v,p,q,r,s) \
+ (_mm_castsi128_ps(_mm_shuffle_epi32( _mm_castps_si128(v), ((s)<<6|(r)<<4|(q)<<2|(p)))))
+
+#define vec4i_swizzle1(v,p,q,r,s) \
+ (_mm_shuffle_epi32( v, ((s)<<6|(r)<<4|(q)<<2|(p))))
+
+#define vec2d_swizzle1(v,p,q) \
+ (_mm_castsi128_pd(_mm_shuffle_epi32( _mm_castpd_si128(v), ((q*2+1)<<6|(q*2)<<4|(p*2+1)<<2|(p*2)))))
+
+#define vec4f_swizzle2(a,b,p,q,r,s) \
+ (_mm_shuffle_ps( (a), (b), ((s)<<6|(r)<<4|(q)<<2|(p))))
+
+#define vec4i_swizzle2(a,b,p,q,r,s) \
+ (_mm_castps_si128( (_mm_shuffle_ps( _mm_castsi128_ps(a), _mm_castsi128_ps(b), ((s)<<6|(r)<<4|(q)<<2|(p))))))
+
+#define _EIGEN_DECLARE_CONST_Packet4f(NAME,X) \
+ const Packet4f p4f_##NAME = pset1<Packet4f>(X)
+
+#define _EIGEN_DECLARE_CONST_Packet4f_FROM_INT(NAME,X) \
+ const Packet4f p4f_##NAME = _mm_castsi128_ps(pset1<Packet4i>(X))
+
+#define _EIGEN_DECLARE_CONST_Packet4i(NAME,X) \
+ const Packet4i p4i_##NAME = pset1<Packet4i>(X)
+
+
+template<> struct packet_traits<float> : default_packet_traits
+{
+ typedef Packet4f type;
+ enum {
+ Vectorizable = 1,
+ AlignedOnScalar = 1,
+ size=4,
+
+ HasDiv = 1,
+ HasSin = EIGEN_FAST_MATH,
+ HasCos = EIGEN_FAST_MATH,
+ HasLog = 1,
+ HasExp = 1,
+ HasSqrt = 1
+ };
+};
+template<> struct packet_traits<double> : default_packet_traits
+{
+ typedef Packet2d type;
+ enum {
+ Vectorizable = 1,
+ AlignedOnScalar = 1,
+ size=2,
+
+ HasDiv = 1
+ };
+};
+template<> struct packet_traits<int> : default_packet_traits
+{
+ typedef Packet4i type;
+ enum {
+ // FIXME check the Has*
+ Vectorizable = 1,
+ AlignedOnScalar = 1,
+ size=4
+ };
+};
+
+template<> struct unpacket_traits<Packet4f> { typedef float type; enum {size=4}; };
+template<> struct unpacket_traits<Packet2d> { typedef double type; enum {size=2}; };
+template<> struct unpacket_traits<Packet4i> { typedef int type; enum {size=4}; };
+
+#if defined(_MSC_VER) && (_MSC_VER==1500)
+// Workaround MSVC 9 internal compiler error.
+// TODO: It has been detected with win64 builds (amd64), so let's check whether it also happens in 32bits+SSE mode
+// TODO: let's check whether there does not exist a better fix, like adding a pset0() function. (it crashed on pset1(0)).
+template<> EIGEN_STRONG_INLINE Packet4f pset1<Packet4f>(const float& from) { return _mm_set_ps(from,from,from,from); }
+template<> EIGEN_STRONG_INLINE Packet2d pset1<Packet2d>(const double& from) { return _mm_set_pd(from,from); }
+template<> EIGEN_STRONG_INLINE Packet4i pset1<Packet4i>(const int& from) { return _mm_set_epi32(from,from,from,from); }
+#else
+template<> EIGEN_STRONG_INLINE Packet4f pset1<Packet4f>(const float& from) { return _mm_set1_ps(from); }
+template<> EIGEN_STRONG_INLINE Packet2d pset1<Packet2d>(const double& from) { return _mm_set1_pd(from); }
+template<> EIGEN_STRONG_INLINE Packet4i pset1<Packet4i>(const int& from) { return _mm_set1_epi32(from); }
+#endif
+
+template<> EIGEN_STRONG_INLINE Packet4f plset<float>(const float& a) { return _mm_add_ps(pset1<Packet4f>(a), _mm_set_ps(3,2,1,0)); }
+template<> EIGEN_STRONG_INLINE Packet2d plset<double>(const double& a) { return _mm_add_pd(pset1<Packet2d>(a),_mm_set_pd(1,0)); }
+template<> EIGEN_STRONG_INLINE Packet4i plset<int>(const int& a) { return _mm_add_epi32(pset1<Packet4i>(a),_mm_set_epi32(3,2,1,0)); }
+
+template<> EIGEN_STRONG_INLINE Packet4f padd<Packet4f>(const Packet4f& a, const Packet4f& b) { return _mm_add_ps(a,b); }
+template<> EIGEN_STRONG_INLINE Packet2d padd<Packet2d>(const Packet2d& a, const Packet2d& b) { return _mm_add_pd(a,b); }
+template<> EIGEN_STRONG_INLINE Packet4i padd<Packet4i>(const Packet4i& a, const Packet4i& b) { return _mm_add_epi32(a,b); }
+
+template<> EIGEN_STRONG_INLINE Packet4f psub<Packet4f>(const Packet4f& a, const Packet4f& b) { return _mm_sub_ps(a,b); }
+template<> EIGEN_STRONG_INLINE Packet2d psub<Packet2d>(const Packet2d& a, const Packet2d& b) { return _mm_sub_pd(a,b); }
+template<> EIGEN_STRONG_INLINE Packet4i psub<Packet4i>(const Packet4i& a, const Packet4i& b) { return _mm_sub_epi32(a,b); }
+
+template<> EIGEN_STRONG_INLINE Packet4f pnegate(const Packet4f& a)
+{
+ const Packet4f mask = _mm_castsi128_ps(_mm_setr_epi32(0x80000000,0x80000000,0x80000000,0x80000000));
+ return _mm_xor_ps(a,mask);
+}
+template<> EIGEN_STRONG_INLINE Packet2d pnegate(const Packet2d& a)
+{
+ const Packet2d mask = _mm_castsi128_pd(_mm_setr_epi32(0x0,0x80000000,0x0,0x80000000));
+ return _mm_xor_pd(a,mask);
+}
+template<> EIGEN_STRONG_INLINE Packet4i pnegate(const Packet4i& a)
+{
+ return psub(_mm_setr_epi32(0,0,0,0), a);
+}
+
+template<> EIGEN_STRONG_INLINE Packet4f pmul<Packet4f>(const Packet4f& a, const Packet4f& b) { return _mm_mul_ps(a,b); }
+template<> EIGEN_STRONG_INLINE Packet2d pmul<Packet2d>(const Packet2d& a, const Packet2d& b) { return _mm_mul_pd(a,b); }
+template<> EIGEN_STRONG_INLINE Packet4i pmul<Packet4i>(const Packet4i& a, const Packet4i& b)
+{
+#ifdef EIGEN_VECTORIZE_SSE4_1
+ return _mm_mullo_epi32(a,b);
+#else
+ // this version is slightly faster than 4 scalar products
+ return vec4i_swizzle1(
+ vec4i_swizzle2(
+ _mm_mul_epu32(a,b),
+ _mm_mul_epu32(vec4i_swizzle1(a,1,0,3,2),
+ vec4i_swizzle1(b,1,0,3,2)),
+ 0,2,0,2),
+ 0,2,1,3);
+#endif
+}
+
+template<> EIGEN_STRONG_INLINE Packet4f pdiv<Packet4f>(const Packet4f& a, const Packet4f& b) { return _mm_div_ps(a,b); }
+template<> EIGEN_STRONG_INLINE Packet2d pdiv<Packet2d>(const Packet2d& a, const Packet2d& b) { return _mm_div_pd(a,b); }
+template<> EIGEN_STRONG_INLINE Packet4i pdiv<Packet4i>(const Packet4i& /*a*/, const Packet4i& /*b*/)
+{ eigen_assert(false && "packet integer division are not supported by SSE");
+ return pset1<Packet4i>(0);
+}
+
+// for some weird raisons, it has to be overloaded for packet of integers
+template<> EIGEN_STRONG_INLINE Packet4i pmadd(const Packet4i& a, const Packet4i& b, const Packet4i& c) { return padd(pmul(a,b), c); }
+
+template<> EIGEN_STRONG_INLINE Packet4f pmin<Packet4f>(const Packet4f& a, const Packet4f& b) { return _mm_min_ps(a,b); }
+template<> EIGEN_STRONG_INLINE Packet2d pmin<Packet2d>(const Packet2d& a, const Packet2d& b) { return _mm_min_pd(a,b); }
+template<> EIGEN_STRONG_INLINE Packet4i pmin<Packet4i>(const Packet4i& a, const Packet4i& b)
+{
+ // after some bench, this version *is* faster than a scalar implementation
+ Packet4i mask = _mm_cmplt_epi32(a,b);
+ return _mm_or_si128(_mm_and_si128(mask,a),_mm_andnot_si128(mask,b));
+}
+
+template<> EIGEN_STRONG_INLINE Packet4f pmax<Packet4f>(const Packet4f& a, const Packet4f& b) { return _mm_max_ps(a,b); }
+template<> EIGEN_STRONG_INLINE Packet2d pmax<Packet2d>(const Packet2d& a, const Packet2d& b) { return _mm_max_pd(a,b); }
+template<> EIGEN_STRONG_INLINE Packet4i pmax<Packet4i>(const Packet4i& a, const Packet4i& b)
+{
+ // after some bench, this version *is* faster than a scalar implementation
+ Packet4i mask = _mm_cmpgt_epi32(a,b);
+ return _mm_or_si128(_mm_and_si128(mask,a),_mm_andnot_si128(mask,b));
+}
+
+template<> EIGEN_STRONG_INLINE Packet4f pand<Packet4f>(const Packet4f& a, const Packet4f& b) { return _mm_and_ps(a,b); }
+template<> EIGEN_STRONG_INLINE Packet2d pand<Packet2d>(const Packet2d& a, const Packet2d& b) { return _mm_and_pd(a,b); }
+template<> EIGEN_STRONG_INLINE Packet4i pand<Packet4i>(const Packet4i& a, const Packet4i& b) { return _mm_and_si128(a,b); }
+
+template<> EIGEN_STRONG_INLINE Packet4f por<Packet4f>(const Packet4f& a, const Packet4f& b) { return _mm_or_ps(a,b); }
+template<> EIGEN_STRONG_INLINE Packet2d por<Packet2d>(const Packet2d& a, const Packet2d& b) { return _mm_or_pd(a,b); }
+template<> EIGEN_STRONG_INLINE Packet4i por<Packet4i>(const Packet4i& a, const Packet4i& b) { return _mm_or_si128(a,b); }
+
+template<> EIGEN_STRONG_INLINE Packet4f pxor<Packet4f>(const Packet4f& a, const Packet4f& b) { return _mm_xor_ps(a,b); }
+template<> EIGEN_STRONG_INLINE Packet2d pxor<Packet2d>(const Packet2d& a, const Packet2d& b) { return _mm_xor_pd(a,b); }
+template<> EIGEN_STRONG_INLINE Packet4i pxor<Packet4i>(const Packet4i& a, const Packet4i& b) { return _mm_xor_si128(a,b); }
+
+template<> EIGEN_STRONG_INLINE Packet4f pandnot<Packet4f>(const Packet4f& a, const Packet4f& b) { return _mm_andnot_ps(a,b); }
+template<> EIGEN_STRONG_INLINE Packet2d pandnot<Packet2d>(const Packet2d& a, const Packet2d& b) { return _mm_andnot_pd(a,b); }
+template<> EIGEN_STRONG_INLINE Packet4i pandnot<Packet4i>(const Packet4i& a, const Packet4i& b) { return _mm_andnot_si128(a,b); }
+
+template<> EIGEN_STRONG_INLINE Packet4f pload<Packet4f>(const float* from) { EIGEN_DEBUG_ALIGNED_LOAD return _mm_load_ps(from); }
+template<> EIGEN_STRONG_INLINE Packet2d pload<Packet2d>(const double* from) { EIGEN_DEBUG_ALIGNED_LOAD return _mm_load_pd(from); }
+template<> EIGEN_STRONG_INLINE Packet4i pload<Packet4i>(const int* from) { EIGEN_DEBUG_ALIGNED_LOAD return _mm_load_si128(reinterpret_cast<const Packet4i*>(from)); }
+
+#if defined(_MSC_VER)
+ template<> EIGEN_STRONG_INLINE Packet4f ploadu<Packet4f>(const float* from) {
+ EIGEN_DEBUG_UNALIGNED_LOAD
+ #if (_MSC_VER==1600)
+ // NOTE Some version of MSVC10 generates bad code when using _mm_loadu_ps
+ // (i.e., it does not generate an unaligned load!!
+ // TODO On most architectures this version should also be faster than a single _mm_loadu_ps
+ // so we could also enable it for MSVC08 but first we have to make this later does not generate crap when doing so...
+ __m128 res = _mm_loadl_pi(_mm_set1_ps(0.0f), (const __m64*)(from));
+ res = _mm_loadh_pi(res, (const __m64*)(from+2));
+ return res;
+ #else
+ return _mm_loadu_ps(from);
+ #endif
+ }
+ template<> EIGEN_STRONG_INLINE Packet2d ploadu<Packet2d>(const double* from) { EIGEN_DEBUG_UNALIGNED_LOAD return _mm_loadu_pd(from); }
+ template<> EIGEN_STRONG_INLINE Packet4i ploadu<Packet4i>(const int* from) { EIGEN_DEBUG_UNALIGNED_LOAD return _mm_loadu_si128(reinterpret_cast<const Packet4i*>(from)); }
+#else
+// Fast unaligned loads. Note that here we cannot directly use intrinsics: this would
+// require pointer casting to incompatible pointer types and leads to invalid code
+// because of the strict aliasing rule. The "dummy" stuff are required to enforce
+// a correct instruction dependency.
+// TODO: do the same for MSVC (ICC is compatible)
+// NOTE: with the code below, MSVC's compiler crashes!
+
+#if defined(__GNUC__) && defined(__i386__)
+ // bug 195: gcc/i386 emits weird x87 fldl/fstpl instructions for _mm_load_sd
+ #define EIGEN_AVOID_CUSTOM_UNALIGNED_LOADS 1
+#elif defined(__clang__)
+ // bug 201: Segfaults in __mm_loadh_pd with clang 2.8
+ #define EIGEN_AVOID_CUSTOM_UNALIGNED_LOADS 1
+#else
+ #define EIGEN_AVOID_CUSTOM_UNALIGNED_LOADS 0
+#endif
+
+template<> EIGEN_STRONG_INLINE Packet4f ploadu<Packet4f>(const float* from)
+{
+ EIGEN_DEBUG_UNALIGNED_LOAD
+#if EIGEN_AVOID_CUSTOM_UNALIGNED_LOADS
+ return _mm_loadu_ps(from);
+#else
+ __m128d res;
+ res = _mm_load_sd((const double*)(from)) ;
+ res = _mm_loadh_pd(res, (const double*)(from+2)) ;
+ return _mm_castpd_ps(res);
+#endif
+}
+template<> EIGEN_STRONG_INLINE Packet2d ploadu<Packet2d>(const double* from)
+{
+ EIGEN_DEBUG_UNALIGNED_LOAD
+#if EIGEN_AVOID_CUSTOM_UNALIGNED_LOADS
+ return _mm_loadu_pd(from);
+#else
+ __m128d res;
+ res = _mm_load_sd(from) ;
+ res = _mm_loadh_pd(res,from+1);
+ return res;
+#endif
+}
+template<> EIGEN_STRONG_INLINE Packet4i ploadu<Packet4i>(const int* from)
+{
+ EIGEN_DEBUG_UNALIGNED_LOAD
+#if EIGEN_AVOID_CUSTOM_UNALIGNED_LOADS
+ return _mm_loadu_si128(reinterpret_cast<const Packet4i*>(from));
+#else
+ __m128d res;
+ res = _mm_load_sd((const double*)(from)) ;
+ res = _mm_loadh_pd(res, (const double*)(from+2)) ;
+ return _mm_castpd_si128(res);
+#endif
+}
+#endif
+
+template<> EIGEN_STRONG_INLINE Packet4f ploaddup<Packet4f>(const float* from)
+{
+ return vec4f_swizzle1(_mm_castpd_ps(_mm_load_sd(reinterpret_cast<const double*>(from))), 0, 0, 1, 1);
+}
+template<> EIGEN_STRONG_INLINE Packet2d ploaddup<Packet2d>(const double* from)
+{ return pset1<Packet2d>(from[0]); }
+template<> EIGEN_STRONG_INLINE Packet4i ploaddup<Packet4i>(const int* from)
+{
+ Packet4i tmp;
+ tmp = _mm_loadl_epi64(reinterpret_cast<const Packet4i*>(from));
+ return vec4i_swizzle1(tmp, 0, 0, 1, 1);
+}
+
+template<> EIGEN_STRONG_INLINE void pstore<float>(float* to, const Packet4f& from) { EIGEN_DEBUG_ALIGNED_STORE _mm_store_ps(to, from); }
+template<> EIGEN_STRONG_INLINE void pstore<double>(double* to, const Packet2d& from) { EIGEN_DEBUG_ALIGNED_STORE _mm_store_pd(to, from); }
+template<> EIGEN_STRONG_INLINE void pstore<int>(int* to, const Packet4i& from) { EIGEN_DEBUG_ALIGNED_STORE _mm_store_si128(reinterpret_cast<Packet4i*>(to), from); }
+
+template<> EIGEN_STRONG_INLINE void pstoreu<double>(double* to, const Packet2d& from) {
+ EIGEN_DEBUG_UNALIGNED_STORE
+ _mm_storel_pd((to), from);
+ _mm_storeh_pd((to+1), from);
+}
+template<> EIGEN_STRONG_INLINE void pstoreu<float>(float* to, const Packet4f& from) { EIGEN_DEBUG_UNALIGNED_STORE pstoreu(reinterpret_cast<double*>(to), _mm_castps_pd(from)); }
+template<> EIGEN_STRONG_INLINE void pstoreu<int>(int* to, const Packet4i& from) { EIGEN_DEBUG_UNALIGNED_STORE pstoreu(reinterpret_cast<double*>(to), _mm_castsi128_pd(from)); }
+
+// some compilers might be tempted to perform multiple moves instead of using a vector path.
+template<> EIGEN_STRONG_INLINE void pstore1<Packet4f>(float* to, const float& a)
+{
+ Packet4f pa = _mm_set_ss(a);
+ pstore(to, vec4f_swizzle1(pa,0,0,0,0));
+}
+// some compilers might be tempted to perform multiple moves instead of using a vector path.
+template<> EIGEN_STRONG_INLINE void pstore1<Packet2d>(double* to, const double& a)
+{
+ Packet2d pa = _mm_set_sd(a);
+ pstore(to, vec2d_swizzle1(pa,0,0));
+}
+
+template<> EIGEN_STRONG_INLINE void prefetch<float>(const float* addr) { _mm_prefetch((const char*)(addr), _MM_HINT_T0); }
+template<> EIGEN_STRONG_INLINE void prefetch<double>(const double* addr) { _mm_prefetch((const char*)(addr), _MM_HINT_T0); }
+template<> EIGEN_STRONG_INLINE void prefetch<int>(const int* addr) { _mm_prefetch((const char*)(addr), _MM_HINT_T0); }
+
+#if defined(_MSC_VER) && defined(_WIN64) && !defined(__INTEL_COMPILER)
+// The temporary variable fixes an internal compilation error in vs <= 2008 and a wrong-result bug in vs 2010
+// Direct of the struct members fixed bug #62.
+template<> EIGEN_STRONG_INLINE float pfirst<Packet4f>(const Packet4f& a) { return a.m128_f32[0]; }
+template<> EIGEN_STRONG_INLINE double pfirst<Packet2d>(const Packet2d& a) { return a.m128d_f64[0]; }
+template<> EIGEN_STRONG_INLINE int pfirst<Packet4i>(const Packet4i& a) { int x = _mm_cvtsi128_si32(a); return x; }
+#elif defined(_MSC_VER) && !defined(__INTEL_COMPILER)
+// The temporary variable fixes an internal compilation error in vs <= 2008 and a wrong-result bug in vs 2010
+template<> EIGEN_STRONG_INLINE float pfirst<Packet4f>(const Packet4f& a) { float x = _mm_cvtss_f32(a); return x; }
+template<> EIGEN_STRONG_INLINE double pfirst<Packet2d>(const Packet2d& a) { double x = _mm_cvtsd_f64(a); return x; }
+template<> EIGEN_STRONG_INLINE int pfirst<Packet4i>(const Packet4i& a) { int x = _mm_cvtsi128_si32(a); return x; }
+#else
+template<> EIGEN_STRONG_INLINE float pfirst<Packet4f>(const Packet4f& a) { return _mm_cvtss_f32(a); }
+template<> EIGEN_STRONG_INLINE double pfirst<Packet2d>(const Packet2d& a) { return _mm_cvtsd_f64(a); }
+template<> EIGEN_STRONG_INLINE int pfirst<Packet4i>(const Packet4i& a) { return _mm_cvtsi128_si32(a); }
+#endif
+
+template<> EIGEN_STRONG_INLINE Packet4f preverse(const Packet4f& a)
+{ return _mm_shuffle_ps(a,a,0x1B); }
+template<> EIGEN_STRONG_INLINE Packet2d preverse(const Packet2d& a)
+{ return _mm_shuffle_pd(a,a,0x1); }
+template<> EIGEN_STRONG_INLINE Packet4i preverse(const Packet4i& a)
+{ return _mm_shuffle_epi32(a,0x1B); }
+
+
+template<> EIGEN_STRONG_INLINE Packet4f pabs(const Packet4f& a)
+{
+ const Packet4f mask = _mm_castsi128_ps(_mm_setr_epi32(0x7FFFFFFF,0x7FFFFFFF,0x7FFFFFFF,0x7FFFFFFF));
+ return _mm_and_ps(a,mask);
+}
+template<> EIGEN_STRONG_INLINE Packet2d pabs(const Packet2d& a)
+{
+ const Packet2d mask = _mm_castsi128_pd(_mm_setr_epi32(0xFFFFFFFF,0x7FFFFFFF,0xFFFFFFFF,0x7FFFFFFF));
+ return _mm_and_pd(a,mask);
+}
+template<> EIGEN_STRONG_INLINE Packet4i pabs(const Packet4i& a)
+{
+ #ifdef EIGEN_VECTORIZE_SSSE3
+ return _mm_abs_epi32(a);
+ #else
+ Packet4i aux = _mm_srai_epi32(a,31);
+ return _mm_sub_epi32(_mm_xor_si128(a,aux),aux);
+ #endif
+}
+
+EIGEN_STRONG_INLINE void punpackp(Packet4f* vecs)
+{
+ vecs[1] = _mm_castsi128_ps(_mm_shuffle_epi32(_mm_castps_si128(vecs[0]), 0x55));
+ vecs[2] = _mm_castsi128_ps(_mm_shuffle_epi32(_mm_castps_si128(vecs[0]), 0xAA));
+ vecs[3] = _mm_castsi128_ps(_mm_shuffle_epi32(_mm_castps_si128(vecs[0]), 0xFF));
+ vecs[0] = _mm_castsi128_ps(_mm_shuffle_epi32(_mm_castps_si128(vecs[0]), 0x00));
+}
+
+#ifdef EIGEN_VECTORIZE_SSE3
+// TODO implement SSE2 versions as well as integer versions
+template<> EIGEN_STRONG_INLINE Packet4f preduxp<Packet4f>(const Packet4f* vecs)
+{
+ return _mm_hadd_ps(_mm_hadd_ps(vecs[0], vecs[1]),_mm_hadd_ps(vecs[2], vecs[3]));
+}
+template<> EIGEN_STRONG_INLINE Packet2d preduxp<Packet2d>(const Packet2d* vecs)
+{
+ return _mm_hadd_pd(vecs[0], vecs[1]);
+}
+// SSSE3 version:
+// EIGEN_STRONG_INLINE Packet4i preduxp(const Packet4i* vecs)
+// {
+// return _mm_hadd_epi32(_mm_hadd_epi32(vecs[0], vecs[1]),_mm_hadd_epi32(vecs[2], vecs[3]));
+// }
+
+template<> EIGEN_STRONG_INLINE float predux<Packet4f>(const Packet4f& a)
+{
+ Packet4f tmp0 = _mm_hadd_ps(a,a);
+ return pfirst(_mm_hadd_ps(tmp0, tmp0));
+}
+
+template<> EIGEN_STRONG_INLINE double predux<Packet2d>(const Packet2d& a) { return pfirst(_mm_hadd_pd(a, a)); }
+
+// SSSE3 version:
+// EIGEN_STRONG_INLINE float predux(const Packet4i& a)
+// {
+// Packet4i tmp0 = _mm_hadd_epi32(a,a);
+// return pfirst(_mm_hadd_epi32(tmp0, tmp0));
+// }
+#else
+// SSE2 versions
+template<> EIGEN_STRONG_INLINE float predux<Packet4f>(const Packet4f& a)
+{
+ Packet4f tmp = _mm_add_ps(a, _mm_movehl_ps(a,a));
+ return pfirst(_mm_add_ss(tmp, _mm_shuffle_ps(tmp,tmp, 1)));
+}
+template<> EIGEN_STRONG_INLINE double predux<Packet2d>(const Packet2d& a)
+{
+ return pfirst(_mm_add_sd(a, _mm_unpackhi_pd(a,a)));
+}
+
+template<> EIGEN_STRONG_INLINE Packet4f preduxp<Packet4f>(const Packet4f* vecs)
+{
+ Packet4f tmp0, tmp1, tmp2;
+ tmp0 = _mm_unpacklo_ps(vecs[0], vecs[1]);
+ tmp1 = _mm_unpackhi_ps(vecs[0], vecs[1]);
+ tmp2 = _mm_unpackhi_ps(vecs[2], vecs[3]);
+ tmp0 = _mm_add_ps(tmp0, tmp1);
+ tmp1 = _mm_unpacklo_ps(vecs[2], vecs[3]);
+ tmp1 = _mm_add_ps(tmp1, tmp2);
+ tmp2 = _mm_movehl_ps(tmp1, tmp0);
+ tmp0 = _mm_movelh_ps(tmp0, tmp1);
+ return _mm_add_ps(tmp0, tmp2);
+}
+
+template<> EIGEN_STRONG_INLINE Packet2d preduxp<Packet2d>(const Packet2d* vecs)
+{
+ return _mm_add_pd(_mm_unpacklo_pd(vecs[0], vecs[1]), _mm_unpackhi_pd(vecs[0], vecs[1]));
+}
+#endif // SSE3
+
+template<> EIGEN_STRONG_INLINE int predux<Packet4i>(const Packet4i& a)
+{
+ Packet4i tmp = _mm_add_epi32(a, _mm_unpackhi_epi64(a,a));
+ return pfirst(tmp) + pfirst(_mm_shuffle_epi32(tmp, 1));
+}
+
+template<> EIGEN_STRONG_INLINE Packet4i preduxp<Packet4i>(const Packet4i* vecs)
+{
+ Packet4i tmp0, tmp1, tmp2;
+ tmp0 = _mm_unpacklo_epi32(vecs[0], vecs[1]);
+ tmp1 = _mm_unpackhi_epi32(vecs[0], vecs[1]);
+ tmp2 = _mm_unpackhi_epi32(vecs[2], vecs[3]);
+ tmp0 = _mm_add_epi32(tmp0, tmp1);
+ tmp1 = _mm_unpacklo_epi32(vecs[2], vecs[3]);
+ tmp1 = _mm_add_epi32(tmp1, tmp2);
+ tmp2 = _mm_unpacklo_epi64(tmp0, tmp1);
+ tmp0 = _mm_unpackhi_epi64(tmp0, tmp1);
+ return _mm_add_epi32(tmp0, tmp2);
+}
+
+// Other reduction functions:
+
+// mul
+template<> EIGEN_STRONG_INLINE float predux_mul<Packet4f>(const Packet4f& a)
+{
+ Packet4f tmp = _mm_mul_ps(a, _mm_movehl_ps(a,a));
+ return pfirst(_mm_mul_ss(tmp, _mm_shuffle_ps(tmp,tmp, 1)));
+}
+template<> EIGEN_STRONG_INLINE double predux_mul<Packet2d>(const Packet2d& a)
+{
+ return pfirst(_mm_mul_sd(a, _mm_unpackhi_pd(a,a)));
+}
+template<> EIGEN_STRONG_INLINE int predux_mul<Packet4i>(const Packet4i& a)
+{
+ // after some experiments, it is seems this is the fastest way to implement it
+ // for GCC (eg., reusing pmul is very slow !)
+ // TODO try to call _mm_mul_epu32 directly
+ 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<Packet4f>(const Packet4f& a)
+{
+ Packet4f tmp = _mm_min_ps(a, _mm_movehl_ps(a,a));
+ return pfirst(_mm_min_ss(tmp, _mm_shuffle_ps(tmp,tmp, 1)));
+}
+template<> EIGEN_STRONG_INLINE double predux_min<Packet2d>(const Packet2d& a)
+{
+ return pfirst(_mm_min_sd(a, _mm_unpackhi_pd(a,a)));
+}
+template<> EIGEN_STRONG_INLINE int predux_min<Packet4i>(const Packet4i& a)
+{
+ // after some experiments, it is seems this is the fastest way to implement it
+ // for GCC (eg., it does not like using std::min after the pstore !!)
+ EIGEN_ALIGN16 int aux[4];
+ pstore(aux, a);
+ register int aux0 = aux[0]<aux[1] ? aux[0] : aux[1];
+ register int aux2 = aux[2]<aux[3] ? aux[2] : aux[3];
+ return aux0<aux2 ? aux0 : aux2;
+}
+
+// max
+template<> EIGEN_STRONG_INLINE float predux_max<Packet4f>(const Packet4f& a)
+{
+ Packet4f tmp = _mm_max_ps(a, _mm_movehl_ps(a,a));
+ return pfirst(_mm_max_ss(tmp, _mm_shuffle_ps(tmp,tmp, 1)));
+}
+template<> EIGEN_STRONG_INLINE double predux_max<Packet2d>(const Packet2d& a)
+{
+ return pfirst(_mm_max_sd(a, _mm_unpackhi_pd(a,a)));
+}
+template<> EIGEN_STRONG_INLINE int predux_max<Packet4i>(const Packet4i& a)
+{
+ // after some experiments, it is seems this is the fastest way to implement it
+ // for GCC (eg., it does not like using std::min after the pstore !!)
+ EIGEN_ALIGN16 int aux[4];
+ pstore(aux, a);
+ register int aux0 = aux[0]>aux[1] ? aux[0] : aux[1];
+ register int aux2 = aux[2]>aux[3] ? aux[2] : aux[3];
+ return aux0>aux2 ? aux0 : aux2;
+}
+
+#if (defined __GNUC__)
+// template <> EIGEN_STRONG_INLINE Packet4f pmadd(const Packet4f& a, const Packet4f& b, const Packet4f& c)
+// {
+// Packet4f res = b;
+// asm("mulps %[a], %[b] \n\taddps %[c], %[b]" : [b] "+x" (res) : [a] "x" (a), [c] "x" (c));
+// return res;
+// }
+// EIGEN_STRONG_INLINE Packet4i _mm_alignr_epi8(const Packet4i& a, const Packet4i& b, const int i)
+// {
+// Packet4i res = a;
+// asm("palignr %[i], %[a], %[b] " : [b] "+x" (res) : [a] "x" (a), [i] "i" (i));
+// return res;
+// }
+#endif
+
+#ifdef EIGEN_VECTORIZE_SSSE3
+// SSSE3 versions
+template<int Offset>
+struct palign_impl<Offset,Packet4f>
+{
+ static EIGEN_STRONG_INLINE void run(Packet4f& first, const Packet4f& second)
+ {
+ if (Offset!=0)
+ first = _mm_castsi128_ps(_mm_alignr_epi8(_mm_castps_si128(second), _mm_castps_si128(first), Offset*4));
+ }
+};
+
+template<int Offset>
+struct palign_impl<Offset,Packet4i>
+{
+ static EIGEN_STRONG_INLINE void run(Packet4i& first, const Packet4i& second)
+ {
+ if (Offset!=0)
+ first = _mm_alignr_epi8(second,first, Offset*4);
+ }
+};
+
+template<int Offset>
+struct palign_impl<Offset,Packet2d>
+{
+ static EIGEN_STRONG_INLINE void run(Packet2d& first, const Packet2d& second)
+ {
+ if (Offset==1)
+ first = _mm_castsi128_pd(_mm_alignr_epi8(_mm_castpd_si128(second), _mm_castpd_si128(first), 8));
+ }
+};
+#else
+// SSE2 versions
+template<int Offset>
+struct palign_impl<Offset,Packet4f>
+{
+ static EIGEN_STRONG_INLINE void run(Packet4f& first, const Packet4f& second)
+ {
+ if (Offset==1)
+ {
+ first = _mm_move_ss(first,second);
+ first = _mm_castsi128_ps(_mm_shuffle_epi32(_mm_castps_si128(first),0x39));
+ }
+ else if (Offset==2)
+ {
+ first = _mm_movehl_ps(first,first);
+ first = _mm_movelh_ps(first,second);
+ }
+ else if (Offset==3)
+ {
+ first = _mm_move_ss(first,second);
+ first = _mm_shuffle_ps(first,second,0x93);
+ }
+ }
+};
+
+template<int Offset>
+struct palign_impl<Offset,Packet4i>
+{
+ static EIGEN_STRONG_INLINE void run(Packet4i& first, const Packet4i& second)
+ {
+ if (Offset==1)
+ {
+ first = _mm_castps_si128(_mm_move_ss(_mm_castsi128_ps(first),_mm_castsi128_ps(second)));
+ first = _mm_shuffle_epi32(first,0x39);
+ }
+ else if (Offset==2)
+ {
+ first = _mm_castps_si128(_mm_movehl_ps(_mm_castsi128_ps(first),_mm_castsi128_ps(first)));
+ first = _mm_castps_si128(_mm_movelh_ps(_mm_castsi128_ps(first),_mm_castsi128_ps(second)));
+ }
+ else if (Offset==3)
+ {
+ first = _mm_castps_si128(_mm_move_ss(_mm_castsi128_ps(first),_mm_castsi128_ps(second)));
+ first = _mm_castps_si128(_mm_shuffle_ps(_mm_castsi128_ps(first),_mm_castsi128_ps(second),0x93));
+ }
+ }
+};
+
+template<int Offset>
+struct palign_impl<Offset,Packet2d>
+{
+ static EIGEN_STRONG_INLINE void run(Packet2d& first, const Packet2d& second)
+ {
+ if (Offset==1)
+ {
+ first = _mm_castps_pd(_mm_movehl_ps(_mm_castpd_ps(first),_mm_castpd_ps(first)));
+ first = _mm_castps_pd(_mm_movelh_ps(_mm_castpd_ps(first),_mm_castpd_ps(second)));
+ }
+ }
+};
+#endif
+
+} // end namespace internal
+
+} // end namespace Eigen
+
+#endif // EIGEN_PACKET_MATH_SSE_H
diff --git a/Eigen/src/Core/products/CMakeLists.txt b/Eigen/src/Core/products/CMakeLists.txt
new file mode 100644
index 000000000..21fc94ae3
--- /dev/null
+++ b/Eigen/src/Core/products/CMakeLists.txt
@@ -0,0 +1,6 @@
+FILE(GLOB Eigen_Core_Product_SRCS "*.h")
+
+INSTALL(FILES
+ ${Eigen_Core_Product_SRCS}
+ DESTINATION ${INCLUDE_INSTALL_DIR}/Eigen/src/Core/products COMPONENT Devel
+ )
diff --git a/Eigen/src/Core/products/CoeffBasedProduct.h b/Eigen/src/Core/products/CoeffBasedProduct.h
new file mode 100644
index 000000000..403d25fa9
--- /dev/null
+++ b/Eigen/src/Core/products/CoeffBasedProduct.h
@@ -0,0 +1,441 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra.
+//
+// Copyright (C) 2006-2008 Benoit Jacob <jacob.benoit.1@gmail.com>
+// Copyright (C) 2008-2010 Gael Guennebaud <gael.guennebaud@inria.fr>
+//
+// This Source Code Form is subject to the terms of the Mozilla
+// Public License v. 2.0. If 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<int Traversal, int UnrollingIndex, typename Lhs, typename Rhs, typename RetScalar>
+struct product_coeff_impl;
+
+template<int StorageOrder, int UnrollingIndex, typename Lhs, typename Rhs, typename Packet, int LoadMode>
+struct product_packet_impl;
+
+template<typename LhsNested, typename RhsNested, int NestingFlags>
+struct traits<CoeffBasedProduct<LhsNested,RhsNested,NestingFlags> >
+{
+ typedef MatrixXpr XprKind;
+ typedef typename remove_all<LhsNested>::type _LhsNested;
+ typedef typename remove_all<RhsNested>::type _RhsNested;
+ typedef typename scalar_product_traits<typename _LhsNested::Scalar, typename _RhsNested::Scalar>::ReturnType Scalar;
+ typedef typename promote_storage_type<typename traits<_LhsNested>::StorageKind,
+ typename traits<_RhsNested>::StorageKind>::ret StorageKind;
+ typedef typename promote_index_type<typename traits<_LhsNested>::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<typename _LhsNested::Scalar,typename _RhsNested::Scalar>::value,
+
+ CanVectorizeRhs = RhsRowMajor && (RhsFlags & PacketAccessBit)
+ && (ColsAtCompileTime == Dynamic
+ || ( (ColsAtCompileTime % packet_traits<Scalar>::size) == 0
+ && (RhsFlags&AlignedBit)
+ )
+ ),
+
+ CanVectorizeLhs = (!LhsRowMajor) && (LhsFlags & PacketAccessBit)
+ && (RowsAtCompileTime == Dynamic
+ || ( (RowsAtCompileTime % packet_traits<Scalar>::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 * (NumTraits<Scalar>::MulCost + LhsCoeffReadCost + RhsCoeffReadCost)
+ + (InnerSize - 1) * NumTraits<Scalar>::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<Scalar>::size == 0)
+ };
+};
+
+} // end namespace internal
+
+template<typename LhsNested, typename RhsNested, int NestingFlags>
+class CoeffBasedProduct
+ : internal::no_assignment_operator,
+ public MatrixBase<CoeffBasedProduct<LhsNested, RhsNested, NestingFlags> >
+{
+ public:
+
+ typedef MatrixBase<CoeffBasedProduct> Base;
+ EIGEN_DENSE_PUBLIC_INTERFACE(CoeffBasedProduct)
+ typedef typename Base::PlainObject PlainObject;
+
+ private:
+
+ typedef typename internal::traits<CoeffBasedProduct>::_LhsNested _LhsNested;
+ typedef typename internal::traits<CoeffBasedProduct>::_RhsNested _RhsNested;
+
+ enum {
+ PacketSize = internal::packet_traits<Scalar>::size,
+ InnerSize = internal::traits<CoeffBasedProduct>::InnerSize,
+ Unroll = CoeffReadCost != Dynamic && CoeffReadCost <= EIGEN_UNROLLING_LIMIT,
+ CanVectorizeInner = internal::traits<CoeffBasedProduct>::CanVectorizeInner
+ };
+
+ typedef internal::product_coeff_impl<CanVectorizeInner ? InnerVectorizedTraversal : DefaultTraversal,
+ Unroll ? InnerSize-1 : Dynamic,
+ _LhsNested, _RhsNested, Scalar> ScalarCoeffImpl;
+
+ typedef CoeffBasedProduct<LhsNested,RhsNested,NestByRefBit> LazyCoeffBasedProductType;
+
+ public:
+
+ inline CoeffBasedProduct(const CoeffBasedProduct& other)
+ : Base(), m_lhs(other.m_lhs), m_rhs(other.m_rhs)
+ {}
+
+ template<typename Lhs, typename Rhs>
+ 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<T>.
+ EIGEN_STATIC_ASSERT((internal::is_same<typename Lhs::RealScalar, typename Rhs::RealScalar>::value),
+ YOU_MIXED_DIFFERENT_NUMERIC_TYPES__YOU_NEED_TO_USE_THE_CAST_METHOD_OF_MATRIXBASE_TO_CAST_NUMERIC_TYPES_EXPLICITLY)
+ eigen_assert(lhs.cols() == rhs.rows()
+ && "invalid matrix product"
+ && "if you wanted a coeff-wise or a dot product use the respective explicit functions");
+ }
+
+ 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<int LoadMode>
+ EIGEN_STRONG_INLINE const PacketScalar packet(Index row, Index col) const
+ {
+ PacketScalar res;
+ internal::product_packet_impl<Flags&RowMajorBit ? RowMajor : ColMajor,
+ Unroll ? InnerSize-1 : Dynamic,
+ _LhsNested, _RhsNested, PacketScalar, LoadMode>
+ ::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<const LazyCoeffBasedProductType,0> diagonal() const
+ { return reinterpret_cast<const LazyCoeffBasedProductType&>(*this); }
+
+ template<int DiagonalIndex>
+ const Diagonal<const LazyCoeffBasedProductType,DiagonalIndex> diagonal() const
+ { return reinterpret_cast<const LazyCoeffBasedProductType&>(*this); }
+
+ const Diagonal<const LazyCoeffBasedProductType,Dynamic> diagonal(Index index) const
+ { return reinterpret_cast<const LazyCoeffBasedProductType&>(*this).diagonal(index); }
+
+ protected:
+ typename internal::add_const_on_value_type<LhsNested>::type m_lhs;
+ typename internal::add_const_on_value_type<RhsNested>::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<typename Lhs, typename Rhs, int N, typename PlainObject>
+struct nested<CoeffBasedProduct<Lhs,Rhs,EvalBeforeNestingBit|EvalBeforeAssigningBit>, N, PlainObject>
+{
+ typedef PlainObject const& type;
+};
+
+/***************************************************************************
+* Normal product .coeff() implementation (with meta-unrolling)
+***************************************************************************/
+
+/**************************************
+*** Scalar path - no vectorization ***
+**************************************/
+
+template<int UnrollingIndex, typename Lhs, typename Rhs, typename RetScalar>
+struct product_coeff_impl<DefaultTraversal, UnrollingIndex, Lhs, Rhs, RetScalar>
+{
+ 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<DefaultTraversal, UnrollingIndex-1, Lhs, Rhs, RetScalar>::run(row, col, lhs, rhs, res);
+ res += lhs.coeff(row, UnrollingIndex) * rhs.coeff(UnrollingIndex, col);
+ }
+};
+
+template<typename Lhs, typename Rhs, typename RetScalar>
+struct product_coeff_impl<DefaultTraversal, 0, Lhs, Rhs, RetScalar>
+{
+ 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<typename Lhs, typename Rhs, typename RetScalar>
+struct product_coeff_impl<DefaultTraversal, Dynamic, Lhs, Rhs, RetScalar>
+{
+ typedef typename Lhs::Index Index;
+ static EIGEN_STRONG_INLINE void run(Index row, Index col, const Lhs& lhs, const Rhs& rhs, RetScalar& res)
+ {
+ eigen_assert(lhs.cols()>0 && "you are using a non initialized matrix");
+ res = lhs.coeff(row, 0) * rhs.coeff(0, col);
+ for(Index i = 1; i < lhs.cols(); ++i)
+ res += lhs.coeff(row, i) * rhs.coeff(i, col);
+ }
+};
+
+/*******************************************
+*** Scalar path with inner vectorization ***
+*******************************************/
+
+template<int UnrollingIndex, typename Lhs, typename Rhs, typename Packet>
+struct product_coeff_vectorized_unroller
+{
+ typedef typename Lhs::Index Index;
+ enum { PacketSize = packet_traits<typename Lhs::Scalar>::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<UnrollingIndex-PacketSize, Lhs, Rhs, Packet>::run(row, col, lhs, rhs, pres);
+ pres = padd(pres, pmul( lhs.template packet<Aligned>(row, UnrollingIndex) , rhs.template packet<Aligned>(UnrollingIndex, col) ));
+ }
+};
+
+template<typename Lhs, typename Rhs, typename Packet>
+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<Aligned>(row, 0) , rhs.template packet<Aligned>(0, col));
+ }
+};
+
+template<int UnrollingIndex, typename Lhs, typename Rhs, typename RetScalar>
+struct product_coeff_impl<InnerVectorizedTraversal, UnrollingIndex, Lhs, Rhs, RetScalar>
+{
+ typedef typename Lhs::PacketScalar Packet;
+ typedef typename Lhs::Index Index;
+ enum { PacketSize = packet_traits<typename Lhs::Scalar>::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<UnrollingIndex+1-PacketSize, Lhs, Rhs, Packet>::run(row, col, lhs, rhs, pres);
+ product_coeff_impl<DefaultTraversal,UnrollingIndex,Lhs,Rhs,RetScalar>::run(row, col, lhs, rhs, res);
+ res = predux(pres);
+ }
+};
+
+template<typename Lhs, typename Rhs, int LhsRows = Lhs::RowsAtCompileTime, int RhsCols = Rhs::ColsAtCompileTime>
+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<Matrix>
+template<typename Lhs, typename Rhs, int RhsCols>
+struct product_coeff_vectorized_dyn_selector<Lhs,Rhs,1,RhsCols>
+{
+ 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<typename Lhs, typename Rhs, int LhsRows>
+struct product_coeff_vectorized_dyn_selector<Lhs,Rhs,LhsRows,1>
+{
+ 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<typename Lhs, typename Rhs>
+struct product_coeff_vectorized_dyn_selector<Lhs,Rhs,1,1>
+{
+ 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<typename Lhs, typename Rhs, typename RetScalar>
+struct product_coeff_impl<InnerVectorizedTraversal, Dynamic, Lhs, Rhs, RetScalar>
+{
+ 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<Lhs,Rhs>::run(row, col, lhs, rhs, res);
+ }
+};
+
+/*******************
+*** Packet path ***
+*******************/
+
+template<int UnrollingIndex, typename Lhs, typename Rhs, typename Packet, int LoadMode>
+struct product_packet_impl<RowMajor, UnrollingIndex, Lhs, Rhs, Packet, LoadMode>
+{
+ 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<RowMajor, UnrollingIndex-1, Lhs, Rhs, Packet, LoadMode>::run(row, col, lhs, rhs, res);
+ res = pmadd(pset1<Packet>(lhs.coeff(row, UnrollingIndex)), rhs.template packet<LoadMode>(UnrollingIndex, col), res);
+ }
+};
+
+template<int UnrollingIndex, typename Lhs, typename Rhs, typename Packet, int LoadMode>
+struct product_packet_impl<ColMajor, UnrollingIndex, Lhs, Rhs, Packet, LoadMode>
+{
+ 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<ColMajor, UnrollingIndex-1, Lhs, Rhs, Packet, LoadMode>::run(row, col, lhs, rhs, res);
+ res = pmadd(lhs.template packet<LoadMode>(row, UnrollingIndex), pset1<Packet>(rhs.coeff(UnrollingIndex, col)), res);
+ }
+};
+
+template<typename Lhs, typename Rhs, typename Packet, int LoadMode>
+struct product_packet_impl<RowMajor, 0, Lhs, Rhs, Packet, LoadMode>
+{
+ 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<Packet>(lhs.coeff(row, 0)),rhs.template packet<LoadMode>(0, col));
+ }
+};
+
+template<typename Lhs, typename Rhs, typename Packet, int LoadMode>
+struct product_packet_impl<ColMajor, 0, Lhs, Rhs, Packet, LoadMode>
+{
+ 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<LoadMode>(row, 0), pset1<Packet>(rhs.coeff(0, col)));
+ }
+};
+
+template<typename Lhs, typename Rhs, typename Packet, int LoadMode>
+struct product_packet_impl<RowMajor, Dynamic, Lhs, Rhs, Packet, LoadMode>
+{
+ typedef typename Lhs::Index Index;
+ static EIGEN_STRONG_INLINE void run(Index row, Index col, const Lhs& lhs, const Rhs& rhs, Packet& res)
+ {
+ eigen_assert(lhs.cols()>0 && "you are using a non initialized matrix");
+ res = pmul(pset1<Packet>(lhs.coeff(row, 0)),rhs.template packet<LoadMode>(0, col));
+ for(Index i = 1; i < lhs.cols(); ++i)
+ res = pmadd(pset1<Packet>(lhs.coeff(row, i)), rhs.template packet<LoadMode>(i, col), res);
+ }
+};
+
+template<typename Lhs, typename Rhs, typename Packet, int LoadMode>
+struct product_packet_impl<ColMajor, Dynamic, Lhs, Rhs, Packet, LoadMode>
+{
+ typedef typename Lhs::Index Index;
+ static EIGEN_STRONG_INLINE void run(Index row, Index col, const Lhs& lhs, const Rhs& rhs, Packet& res)
+ {
+ eigen_assert(lhs.cols()>0 && "you are using a non initialized matrix");
+ res = pmul(lhs.template packet<LoadMode>(row, 0), pset1<Packet>(rhs.coeff(0, col)));
+ for(Index i = 1; i < lhs.cols(); ++i)
+ res = pmadd(lhs.template packet<LoadMode>(row, i), pset1<Packet>(rhs.coeff(i, col)), res);
+ }
+};
+
+} // end namespace internal
+
+} // end namespace Eigen
+
+#endif // EIGEN_COEFFBASED_PRODUCT_H
diff --git a/Eigen/src/Core/products/GeneralBlockPanelKernel.h b/Eigen/src/Core/products/GeneralBlockPanelKernel.h
new file mode 100644
index 000000000..5eb03c98c
--- /dev/null
+++ b/Eigen/src/Core/products/GeneralBlockPanelKernel.h
@@ -0,0 +1,1319 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra.
+//
+// Copyright (C) 2008-2009 Gael Guennebaud <gael.guennebaud@inria.fr>
+//
+// This Source Code Form is subject to the terms of the Mozilla
+// Public License v. 2.0. If 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<typename _LhsScalar, typename _RhsScalar, bool _ConjLhs=false, bool _ConjRhs=false>
+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<typename LhsScalar, typename RhsScalar, int KcFactor>
+void computeProductBlockingSizes(std::ptrdiff_t& k, std::ptrdiff_t& m, std::ptrdiff_t& 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<LhsScalar,RhsScalar> Traits;
+ enum {
+ kdiv = KcFactor * 2 * Traits::nr
+ * Traits::RhsProgress * sizeof(RhsScalar),
+ mr = gebp_traits<LhsScalar,RhsScalar>::mr,
+ mr_mask = (0xffffffff/mr)*mr
+ };
+
+ manage_caching_sizes(GetAction, &l1, &l2);
+ k = std::min<std::ptrdiff_t>(k, l1/kdiv);
+ std::ptrdiff_t _m = k>0 ? l2/(4 * sizeof(LhsScalar) * k) : 0;
+ if(_m<m) m = _m & mr_mask;
+}
+
+template<typename LhsScalar, typename RhsScalar>
+inline void computeProductBlockingSizes(std::ptrdiff_t& k, std::ptrdiff_t& m, std::ptrdiff_t& n)
+{
+ computeProductBlockingSizes<LhsScalar,RhsScalar,1>(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<typename CJ, typename A, typename B, typename C, typename T> 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<typename CJ, typename T> struct gebp_madd_selector<CJ,T,T,T,T> {
+ 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<typename CJ, typename A, typename B, typename C, typename T>
+ EIGEN_STRONG_INLINE void gebp_madd(const CJ& cj, A& a, B& b, C& c, T& t)
+ {
+ gebp_madd_selector<CJ,A,B,C,T>::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<typename _LhsScalar, typename _RhsScalar, bool _ConjLhs, bool _ConjRhs>
+class gebp_traits
+{
+public:
+ typedef _LhsScalar LhsScalar;
+ typedef _RhsScalar RhsScalar;
+ typedef typename scalar_product_traits<LhsScalar, RhsScalar>::ReturnType ResScalar;
+
+ enum {
+ ConjLhs = _ConjLhs,
+ ConjRhs = _ConjRhs,
+ Vectorizable = packet_traits<LhsScalar>::Vectorizable && packet_traits<RhsScalar>::Vectorizable,
+ LhsPacketSize = Vectorizable ? packet_traits<LhsScalar>::size : 1,
+ RhsPacketSize = Vectorizable ? packet_traits<RhsScalar>::size : 1,
+ ResPacketSize = Vectorizable ? packet_traits<ResScalar>::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<LhsScalar>::type _LhsPacket;
+ typedef typename packet_traits<RhsScalar>::type _RhsPacket;
+ typedef typename packet_traits<ResScalar>::type _ResPacket;
+
+ typedef typename conditional<Vectorizable,_LhsPacket,LhsScalar>::type LhsPacket;
+ typedef typename conditional<Vectorizable,_RhsPacket,RhsScalar>::type RhsPacket;
+ typedef typename conditional<Vectorizable,_ResPacket,ResScalar>::type ResPacket;
+
+ typedef ResPacket AccPacket;
+
+ EIGEN_STRONG_INLINE void initAcc(AccPacket& p)
+ {
+ p = pset1<ResPacket>(ResScalar(0));
+ }
+
+ EIGEN_STRONG_INLINE void unpackRhs(DenseIndex n, const RhsScalar* rhs, RhsScalar* b)
+ {
+ for(DenseIndex k=0; k<n; k++)
+ pstore1<RhsPacket>(&b[k*RhsPacketSize], rhs[k]);
+ }
+
+ EIGEN_STRONG_INLINE void loadRhs(const RhsScalar* b, RhsPacket& dest) const
+ {
+ dest = pload<RhsPacket>(b);
+ }
+
+ EIGEN_STRONG_INLINE void loadLhs(const LhsScalar* a, LhsPacket& dest) const
+ {
+ dest = pload<LhsPacket>(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<LhsScalar,RhsScalar,ConjLhs,ConjRhs> cj;
+// conj_helper<LhsPacket,RhsPacket,ConjLhs,ConjRhs> pcj;
+};
+
+template<typename RealScalar, bool _ConjLhs>
+class gebp_traits<std::complex<RealScalar>, RealScalar, _ConjLhs, false>
+{
+public:
+ typedef std::complex<RealScalar> LhsScalar;
+ typedef RealScalar RhsScalar;
+ typedef typename scalar_product_traits<LhsScalar, RhsScalar>::ReturnType ResScalar;
+
+ enum {
+ ConjLhs = _ConjLhs,
+ ConjRhs = false,
+ Vectorizable = packet_traits<LhsScalar>::Vectorizable && packet_traits<RhsScalar>::Vectorizable,
+ LhsPacketSize = Vectorizable ? packet_traits<LhsScalar>::size : 1,
+ RhsPacketSize = Vectorizable ? packet_traits<RhsScalar>::size : 1,
+ ResPacketSize = Vectorizable ? packet_traits<ResScalar>::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<LhsScalar>::type _LhsPacket;
+ typedef typename packet_traits<RhsScalar>::type _RhsPacket;
+ typedef typename packet_traits<ResScalar>::type _ResPacket;
+
+ typedef typename conditional<Vectorizable,_LhsPacket,LhsScalar>::type LhsPacket;
+ typedef typename conditional<Vectorizable,_RhsPacket,RhsScalar>::type RhsPacket;
+ typedef typename conditional<Vectorizable,_ResPacket,ResScalar>::type ResPacket;
+
+ typedef ResPacket AccPacket;
+
+ EIGEN_STRONG_INLINE void initAcc(AccPacket& p)
+ {
+ p = pset1<ResPacket>(ResScalar(0));
+ }
+
+ EIGEN_STRONG_INLINE void unpackRhs(DenseIndex n, const RhsScalar* rhs, RhsScalar* b)
+ {
+ for(DenseIndex k=0; k<n; k++)
+ pstore1<RhsPacket>(&b[k*RhsPacketSize], rhs[k]);
+ }
+
+ EIGEN_STRONG_INLINE void loadRhs(const RhsScalar* b, RhsPacket& dest) const
+ {
+ dest = pload<RhsPacket>(b);
+ }
+
+ EIGEN_STRONG_INLINE void loadLhs(const LhsScalar* a, LhsPacket& dest) const
+ {
+ dest = pload<LhsPacket>(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<Vectorizable,true_type,false_type>::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<ResPacket,ResPacket,ConjLhs,false> cj;
+};
+
+template<typename RealScalar, bool _ConjLhs, bool _ConjRhs>
+class gebp_traits<std::complex<RealScalar>, std::complex<RealScalar>, _ConjLhs, _ConjRhs >
+{
+public:
+ typedef std::complex<RealScalar> Scalar;
+ typedef std::complex<RealScalar> LhsScalar;
+ typedef std::complex<RealScalar> RhsScalar;
+ typedef std::complex<RealScalar> ResScalar;
+
+ enum {
+ ConjLhs = _ConjLhs,
+ ConjRhs = _ConjRhs,
+ Vectorizable = packet_traits<RealScalar>::Vectorizable
+ && packet_traits<Scalar>::Vectorizable,
+ RealPacketSize = Vectorizable ? packet_traits<RealScalar>::size : 1,
+ ResPacketSize = Vectorizable ? packet_traits<ResScalar>::size : 1,
+
+ nr = 2,
+ mr = 2 * ResPacketSize,
+ WorkSpaceFactor = Vectorizable ? 2*nr*RealPacketSize : nr,
+
+ LhsProgress = ResPacketSize,
+ RhsProgress = Vectorizable ? 2*ResPacketSize : 1
+ };
+
+ typedef typename packet_traits<RealScalar>::type RealPacket;
+ typedef typename packet_traits<Scalar>::type ScalarPacket;
+ struct DoublePacket
+ {
+ RealPacket first;
+ RealPacket second;
+ };
+
+ typedef typename conditional<Vectorizable,RealPacket, Scalar>::type LhsPacket;
+ typedef typename conditional<Vectorizable,DoublePacket,Scalar>::type RhsPacket;
+ typedef typename conditional<Vectorizable,ScalarPacket,Scalar>::type ResPacket;
+ typedef typename conditional<Vectorizable,DoublePacket,Scalar>::type AccPacket;
+
+ EIGEN_STRONG_INLINE void initAcc(Scalar& p) { p = Scalar(0); }
+
+ EIGEN_STRONG_INLINE void initAcc(DoublePacket& p)
+ {
+ p.first = pset1<RealPacket>(RealScalar(0));
+ p.second = pset1<RealPacket>(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<n; k++)
+ {
+ if(Vectorizable)
+ {
+ pstore1<RealPacket>((RealScalar*)&b[k*ResPacketSize*2+0], real(rhs[k]));
+ pstore1<RealPacket>((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<RealPacket>((const RealScalar*)b);
+ dest.second = pload<RealPacket>((const RealScalar*)(b+ResPacketSize));
+ }
+
+ // nothing special here
+ EIGEN_STRONG_INLINE void loadLhs(const LhsScalar* a, LhsPacket& dest) const
+ {
+ dest = pload<LhsPacket>((const typename unpacket_traits<LhsPacket>::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<LhsScalar,RhsScalar,ConjLhs,ConjRhs> cj;
+};
+
+template<typename RealScalar, bool _ConjRhs>
+class gebp_traits<RealScalar, std::complex<RealScalar>, false, _ConjRhs >
+{
+public:
+ typedef std::complex<RealScalar> Scalar;
+ typedef RealScalar LhsScalar;
+ typedef Scalar RhsScalar;
+ typedef Scalar ResScalar;
+
+ enum {
+ ConjLhs = false,
+ ConjRhs = _ConjRhs,
+ Vectorizable = packet_traits<RealScalar>::Vectorizable
+ && packet_traits<Scalar>::Vectorizable,
+ LhsPacketSize = Vectorizable ? packet_traits<LhsScalar>::size : 1,
+ RhsPacketSize = Vectorizable ? packet_traits<RhsScalar>::size : 1,
+ ResPacketSize = Vectorizable ? packet_traits<ResScalar>::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<LhsScalar>::type _LhsPacket;
+ typedef typename packet_traits<RhsScalar>::type _RhsPacket;
+ typedef typename packet_traits<ResScalar>::type _ResPacket;
+
+ typedef typename conditional<Vectorizable,_LhsPacket,LhsScalar>::type LhsPacket;
+ typedef typename conditional<Vectorizable,_RhsPacket,RhsScalar>::type RhsPacket;
+ typedef typename conditional<Vectorizable,_ResPacket,ResScalar>::type ResPacket;
+
+ typedef ResPacket AccPacket;
+
+ EIGEN_STRONG_INLINE void initAcc(AccPacket& p)
+ {
+ p = pset1<ResPacket>(ResScalar(0));
+ }
+
+ EIGEN_STRONG_INLINE void unpackRhs(DenseIndex n, const RhsScalar* rhs, RhsScalar* b)
+ {
+ for(DenseIndex k=0; k<n; k++)
+ pstore1<RhsPacket>(&b[k*RhsPacketSize], rhs[k]);
+ }
+
+ EIGEN_STRONG_INLINE void loadRhs(const RhsScalar* b, RhsPacket& dest) const
+ {
+ dest = pload<RhsPacket>(b);
+ }
+
+ EIGEN_STRONG_INLINE void loadLhs(const LhsScalar* a, LhsPacket& dest) const
+ {
+ dest = ploaddup<LhsPacket>(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<Vectorizable,true_type,false_type>::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<ResPacket,ResPacket,false,ConjRhs> 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<typename LhsScalar, typename RhsScalar, typename Index, int mr, int nr, bool ConjugateLhs, bool ConjugateRhs>
+struct gebp_kernel
+{
+ typedef gebp_traits<LhsScalar,RhsScalar,ConjugateLhs,ConjugateRhs> 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 EIGEN_FLATTEN_ATTRIB
+ void operator()(ResScalar* res, Index resStride, const LhsScalar* blockA, const RhsScalar* blockB, Index rows, Index depth, Index cols, ResScalar alpha,
+ Index strideA=-1, Index strideB=-1, Index offsetA=0, Index offsetB=0, RhsScalar* unpackedB = 0)
+ {
+ Traits traits;
+
+ if(strideA==-1) strideA = depth;
+ if(strideB==-1) strideB = depth;
+ conj_helper<LhsScalar,RhsScalar,ConjugateLhs,ConjugateRhs> cj;
+// conj_helper<LhsPacket,RhsPacket,ConjugateLhs,ConjugateRhs> 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<RhsScalar*>(blockB - strideB * nr * RhsProgress);
+
+ // loops on each micro vertical panel of rhs (depth x nr)
+ for(Index j2=0; j2<packet_cols; j2+=nr)
+ {
+ traits.unpackRhs(depth*nr,&blockB[j2*strideB+offsetB*nr],unpackedB);
+
+ // loops on each largest micro horizontal panel of lhs (mr x depth)
+ // => 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<peeled_mc; i+=mr)
+ {
+ const LhsScalar* blA = &blockA[i*strideA+offsetA*mr];
+ prefetch(&blA[0]);
+
+ // gets res block as register
+ AccPacket C0, C1, C2, C3, C4, C5, C6, C7;
+ traits.initAcc(C0);
+ traits.initAcc(C1);
+ if(nr==4) traits.initAcc(C2);
+ if(nr==4) traits.initAcc(C3);
+ traits.initAcc(C4);
+ traits.initAcc(C5);
+ if(nr==4) traits.initAcc(C6);
+ if(nr==4) traits.initAcc(C7);
+
+ ResScalar* r0 = &res[(j2+0)*resStride + i];
+ ResScalar* r1 = r0 + resStride;
+ ResScalar* r2 = r1 + resStride;
+ ResScalar* r3 = r2 + resStride;
+
+ prefetch(r0+16);
+ prefetch(r1+16);
+ prefetch(r2+16);
+ prefetch(r3+16);
+
+ // performs "inner" product
+ // TODO let's check wether the folowing peeled loop could not be
+ // optimized via optimal prefetching from one loop to the other
+ const RhsScalar* blB = unpackedB;
+ for(Index k=0; k<peeled_kc; k+=4)
+ {
+ if(nr==2)
+ {
+ LhsPacket A0, A1;
+ RhsPacket B_0;
+ RhsPacket T0;
+
+EIGEN_ASM_COMMENT("mybegin2");
+ traits.loadLhs(&blA[0*LhsProgress], A0);
+ traits.loadLhs(&blA[1*LhsProgress], A1);
+ traits.loadRhs(&blB[0*RhsProgress], B_0);
+ traits.madd(A0,B_0,C0,T0);
+ traits.madd(A1,B_0,C4,B_0);
+ traits.loadRhs(&blB[1*RhsProgress], B_0);
+ traits.madd(A0,B_0,C1,T0);
+ traits.madd(A1,B_0,C5,B_0);
+
+ traits.loadLhs(&blA[2*LhsProgress], A0);
+ traits.loadLhs(&blA[3*LhsProgress], A1);
+ traits.loadRhs(&blB[2*RhsProgress], B_0);
+ traits.madd(A0,B_0,C0,T0);
+ traits.madd(A1,B_0,C4,B_0);
+ traits.loadRhs(&blB[3*RhsProgress], B_0);
+ traits.madd(A0,B_0,C1,T0);
+ traits.madd(A1,B_0,C5,B_0);
+
+ traits.loadLhs(&blA[4*LhsProgress], A0);
+ traits.loadLhs(&blA[5*LhsProgress], A1);
+ traits.loadRhs(&blB[4*RhsProgress], B_0);
+ traits.madd(A0,B_0,C0,T0);
+ traits.madd(A1,B_0,C4,B_0);
+ traits.loadRhs(&blB[5*RhsProgress], B_0);
+ traits.madd(A0,B_0,C1,T0);
+ traits.madd(A1,B_0,C5,B_0);
+
+ traits.loadLhs(&blA[6*LhsProgress], A0);
+ traits.loadLhs(&blA[7*LhsProgress], A1);
+ traits.loadRhs(&blB[6*RhsProgress], B_0);
+ traits.madd(A0,B_0,C0,T0);
+ traits.madd(A1,B_0,C4,B_0);
+ traits.loadRhs(&blB[7*RhsProgress], B_0);
+ traits.madd(A0,B_0,C1,T0);
+ traits.madd(A1,B_0,C5,B_0);
+EIGEN_ASM_COMMENT("myend");
+ }
+ else
+ {
+EIGEN_ASM_COMMENT("mybegin4");
+ LhsPacket A0, A1;
+ RhsPacket B_0, B1, B2, B3;
+ RhsPacket T0;
+
+ traits.loadLhs(&blA[0*LhsProgress], A0);
+ traits.loadLhs(&blA[1*LhsProgress], A1);
+ traits.loadRhs(&blB[0*RhsProgress], B_0);
+ traits.loadRhs(&blB[1*RhsProgress], B1);
+
+ traits.madd(A0,B_0,C0,T0);
+ traits.loadRhs(&blB[2*RhsProgress], B2);
+ traits.madd(A1,B_0,C4,B_0);
+ traits.loadRhs(&blB[3*RhsProgress], B3);
+ traits.loadRhs(&blB[4*RhsProgress], B_0);
+ traits.madd(A0,B1,C1,T0);
+ traits.madd(A1,B1,C5,B1);
+ traits.loadRhs(&blB[5*RhsProgress], B1);
+ traits.madd(A0,B2,C2,T0);
+ traits.madd(A1,B2,C6,B2);
+ traits.loadRhs(&blB[6*RhsProgress], B2);
+ traits.madd(A0,B3,C3,T0);
+ traits.loadLhs(&blA[2*LhsProgress], A0);
+ traits.madd(A1,B3,C7,B3);
+ traits.loadLhs(&blA[3*LhsProgress], A1);
+ traits.loadRhs(&blB[7*RhsProgress], B3);
+ traits.madd(A0,B_0,C0,T0);
+ traits.madd(A1,B_0,C4,B_0);
+ traits.loadRhs(&blB[8*RhsProgress], B_0);
+ traits.madd(A0,B1,C1,T0);
+ traits.madd(A1,B1,C5,B1);
+ traits.loadRhs(&blB[9*RhsProgress], B1);
+ traits.madd(A0,B2,C2,T0);
+ traits.madd(A1,B2,C6,B2);
+ traits.loadRhs(&blB[10*RhsProgress], B2);
+ traits.madd(A0,B3,C3,T0);
+ traits.loadLhs(&blA[4*LhsProgress], A0);
+ traits.madd(A1,B3,C7,B3);
+ traits.loadLhs(&blA[5*LhsProgress], A1);
+ traits.loadRhs(&blB[11*RhsProgress], B3);
+
+ traits.madd(A0,B_0,C0,T0);
+ traits.madd(A1,B_0,C4,B_0);
+ traits.loadRhs(&blB[12*RhsProgress], B_0);
+ traits.madd(A0,B1,C1,T0);
+ traits.madd(A1,B1,C5,B1);
+ traits.loadRhs(&blB[13*RhsProgress], B1);
+ traits.madd(A0,B2,C2,T0);
+ traits.madd(A1,B2,C6,B2);
+ traits.loadRhs(&blB[14*RhsProgress], B2);
+ traits.madd(A0,B3,C3,T0);
+ traits.loadLhs(&blA[6*LhsProgress], A0);
+ traits.madd(A1,B3,C7,B3);
+ traits.loadLhs(&blA[7*LhsProgress], A1);
+ traits.loadRhs(&blB[15*RhsProgress], B3);
+ traits.madd(A0,B_0,C0,T0);
+ traits.madd(A1,B_0,C4,B_0);
+ traits.madd(A0,B1,C1,T0);
+ traits.madd(A1,B1,C5,B1);
+ traits.madd(A0,B2,C2,T0);
+ traits.madd(A1,B2,C6,B2);
+ traits.madd(A0,B3,C3,T0);
+ traits.madd(A1,B3,C7,B3);
+ }
+
+ blB += 4*nr*RhsProgress;
+ blA += 4*mr;
+ }
+ // process remaining peeled loop
+ for(Index k=peeled_kc; k<depth; k++)
+ {
+ if(nr==2)
+ {
+ LhsPacket A0, A1;
+ RhsPacket B_0;
+ RhsPacket T0;
+
+ traits.loadLhs(&blA[0*LhsProgress], A0);
+ traits.loadLhs(&blA[1*LhsProgress], A1);
+ traits.loadRhs(&blB[0*RhsProgress], B_0);
+ traits.madd(A0,B_0,C0,T0);
+ traits.madd(A1,B_0,C4,B_0);
+ traits.loadRhs(&blB[1*RhsProgress], B_0);
+ traits.madd(A0,B_0,C1,T0);
+ traits.madd(A1,B_0,C5,B_0);
+ }
+ else
+ {
+ LhsPacket A0, A1;
+ RhsPacket B_0, B1, B2, B3;
+ RhsPacket T0;
+
+ traits.loadLhs(&blA[0*LhsProgress], A0);
+ traits.loadLhs(&blA[1*LhsProgress], A1);
+ traits.loadRhs(&blB[0*RhsProgress], B_0);
+ traits.loadRhs(&blB[1*RhsProgress], B1);
+
+ traits.madd(A0,B_0,C0,T0);
+ traits.loadRhs(&blB[2*RhsProgress], B2);
+ traits.madd(A1,B_0,C4,B_0);
+ traits.loadRhs(&blB[3*RhsProgress], B3);
+ traits.madd(A0,B1,C1,T0);
+ traits.madd(A1,B1,C5,B1);
+ traits.madd(A0,B2,C2,T0);
+ traits.madd(A1,B2,C6,B2);
+ traits.madd(A0,B3,C3,T0);
+ traits.madd(A1,B3,C7,B3);
+ }
+
+ blB += nr*RhsProgress;
+ blA += mr;
+ }
+
+ if(nr==4)
+ {
+ ResPacket R0, R1, R2, R3, R4, R5, R6;
+ ResPacket alphav = pset1<ResPacket>(alpha);
+
+ R0 = ploadu<ResPacket>(r0);
+ R1 = ploadu<ResPacket>(r1);
+ R2 = ploadu<ResPacket>(r2);
+ R3 = ploadu<ResPacket>(r3);
+ R4 = ploadu<ResPacket>(r0 + ResPacketSize);
+ R5 = ploadu<ResPacket>(r1 + ResPacketSize);
+ R6 = ploadu<ResPacket>(r2 + ResPacketSize);
+ traits.acc(C0, alphav, R0);
+ pstoreu(r0, R0);
+ R0 = ploadu<ResPacket>(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<ResPacket>(alpha);
+
+ R0 = ploadu<ResPacket>(r0);
+ R1 = ploadu<ResPacket>(r1);
+ R4 = ploadu<ResPacket>(r0 + ResPacketSize);
+ traits.acc(C0, alphav, R0);
+ pstoreu(r0, R0);
+ R0 = ploadu<ResPacket>(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<peeled_kc; k+=4)
+ {
+ if(nr==2)
+ {
+ LhsPacket A0;
+ RhsPacket B_0, B1;
+
+ traits.loadLhs(&blA[0*LhsProgress], A0);
+ traits.loadRhs(&blB[0*RhsProgress], B_0);
+ traits.loadRhs(&blB[1*RhsProgress], B1);
+ traits.madd(A0,B_0,C0,B_0);
+ traits.loadRhs(&blB[2*RhsProgress], B_0);
+ traits.madd(A0,B1,C1,B1);
+ traits.loadLhs(&blA[1*LhsProgress], A0);
+ traits.loadRhs(&blB[3*RhsProgress], B1);
+ traits.madd(A0,B_0,C0,B_0);
+ traits.loadRhs(&blB[4*RhsProgress], B_0);
+ traits.madd(A0,B1,C1,B1);
+ traits.loadLhs(&blA[2*LhsProgress], A0);
+ traits.loadRhs(&blB[5*RhsProgress], B1);
+ traits.madd(A0,B_0,C0,B_0);
+ traits.loadRhs(&blB[6*RhsProgress], B_0);
+ traits.madd(A0,B1,C1,B1);
+ traits.loadLhs(&blA[3*LhsProgress], A0);
+ traits.loadRhs(&blB[7*RhsProgress], B1);
+ traits.madd(A0,B_0,C0,B_0);
+ traits.madd(A0,B1,C1,B1);
+ }
+ else
+ {
+ LhsPacket A0;
+ RhsPacket B_0, B1, B2, B3;
+
+ traits.loadLhs(&blA[0*LhsProgress], A0);
+ traits.loadRhs(&blB[0*RhsProgress], B_0);
+ traits.loadRhs(&blB[1*RhsProgress], B1);
+
+ traits.madd(A0,B_0,C0,B_0);
+ traits.loadRhs(&blB[2*RhsProgress], B2);
+ traits.loadRhs(&blB[3*RhsProgress], B3);
+ traits.loadRhs(&blB[4*RhsProgress], B_0);
+ traits.madd(A0,B1,C1,B1);
+ traits.loadRhs(&blB[5*RhsProgress], B1);
+ traits.madd(A0,B2,C2,B2);
+ traits.loadRhs(&blB[6*RhsProgress], B2);
+ traits.madd(A0,B3,C3,B3);
+ traits.loadLhs(&blA[1*LhsProgress], A0);
+ traits.loadRhs(&blB[7*RhsProgress], B3);
+ traits.madd(A0,B_0,C0,B_0);
+ traits.loadRhs(&blB[8*RhsProgress], B_0);
+ traits.madd(A0,B1,C1,B1);
+ traits.loadRhs(&blB[9*RhsProgress], B1);
+ traits.madd(A0,B2,C2,B2);
+ traits.loadRhs(&blB[10*RhsProgress], B2);
+ traits.madd(A0,B3,C3,B3);
+ traits.loadLhs(&blA[2*LhsProgress], A0);
+ traits.loadRhs(&blB[11*RhsProgress], B3);
+
+ traits.madd(A0,B_0,C0,B_0);
+ traits.loadRhs(&blB[12*RhsProgress], B_0);
+ traits.madd(A0,B1,C1,B1);
+ traits.loadRhs(&blB[13*RhsProgress], B1);
+ traits.madd(A0,B2,C2,B2);
+ traits.loadRhs(&blB[14*RhsProgress], B2);
+ traits.madd(A0,B3,C3,B3);
+
+ traits.loadLhs(&blA[3*LhsProgress], A0);
+ traits.loadRhs(&blB[15*RhsProgress], B3);
+ traits.madd(A0,B_0,C0,B_0);
+ traits.madd(A0,B1,C1,B1);
+ traits.madd(A0,B2,C2,B2);
+ traits.madd(A0,B3,C3,B3);
+ }
+
+ blB += nr*4*RhsProgress;
+ blA += 4*LhsProgress;
+ }
+ // process remaining peeled loop
+ for(Index k=peeled_kc; k<depth; k++)
+ {
+ if(nr==2)
+ {
+ LhsPacket A0;
+ RhsPacket B_0, B1;
+
+ traits.loadLhs(&blA[0*LhsProgress], A0);
+ traits.loadRhs(&blB[0*RhsProgress], B_0);
+ traits.loadRhs(&blB[1*RhsProgress], B1);
+ traits.madd(A0,B_0,C0,B_0);
+ traits.madd(A0,B1,C1,B1);
+ }
+ else
+ {
+ LhsPacket A0;
+ RhsPacket B_0, B1, B2, B3;
+
+ traits.loadLhs(&blA[0*LhsProgress], A0);
+ traits.loadRhs(&blB[0*RhsProgress], B_0);
+ traits.loadRhs(&blB[1*RhsProgress], B1);
+ traits.loadRhs(&blB[2*RhsProgress], B2);
+ traits.loadRhs(&blB[3*RhsProgress], B3);
+
+ traits.madd(A0,B_0,C0,B_0);
+ traits.madd(A0,B1,C1,B1);
+ traits.madd(A0,B2,C2,B2);
+ traits.madd(A0,B3,C3,B3);
+ }
+
+ blB += nr*RhsProgress;
+ blA += LhsProgress;
+ }
+
+ ResPacket R0, R1, R2, R3;
+ ResPacket alphav = pset1<ResPacket>(alpha);
+
+ ResScalar* r0 = &res[(j2+0)*resStride + i];
+ ResScalar* r1 = r0 + resStride;
+ ResScalar* r2 = r1 + resStride;
+ ResScalar* r3 = r2 + resStride;
+
+ R0 = ploadu<ResPacket>(r0);
+ R1 = ploadu<ResPacket>(r1);
+ if(nr==4) R2 = ploadu<ResPacket>(r2);
+ if(nr==4) R3 = ploadu<ResPacket>(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<rows; i++)
+ {
+ const LhsScalar* blA = &blockA[i*strideA+offsetA];
+ prefetch(&blA[0]);
+
+ // gets a 1 x nr res block as registers
+ ResScalar C0(0), C1(0), C2(0), C3(0);
+ // TODO directly use blockB ???
+ const RhsScalar* blB = &blockB[j2*strideB+offsetB*nr];
+ for(Index k=0; k<depth; k++)
+ {
+ if(nr==2)
+ {
+ LhsScalar A0;
+ RhsScalar B_0, B1;
+
+ A0 = blA[k];
+ B_0 = blB[0];
+ B1 = blB[1];
+ MADD(cj,A0,B_0,C0,B_0);
+ MADD(cj,A0,B1,C1,B1);
+ }
+ else
+ {
+ LhsScalar A0;
+ RhsScalar B_0, B1, B2, B3;
+
+ A0 = blA[k];
+ B_0 = blB[0];
+ B1 = blB[1];
+ B2 = blB[2];
+ B3 = blB[3];
+
+ MADD(cj,A0,B_0,C0,B_0);
+ MADD(cj,A0,B1,C1,B1);
+ MADD(cj,A0,B2,C2,B2);
+ MADD(cj,A0,B3,C3,B3);
+ }
+
+ blB += nr;
+ }
+ res[(j2+0)*resStride + i] += alpha*C0;
+ res[(j2+1)*resStride + i] += alpha*C1;
+ if(nr==4) res[(j2+2)*resStride + i] += alpha*C2;
+ if(nr==4) res[(j2+3)*resStride + i] += alpha*C3;
+ }
+ }
+ // process remaining rhs/res columns one at a time
+ // => do the same but with nr==1
+ for(Index j2=packet_cols; j2<cols; j2++)
+ {
+ // unpack B
+ traits.unpackRhs(depth, &blockB[j2*strideB+offsetB], unpackedB);
+
+ for(Index i=0; i<peeled_mc; i+=mr)
+ {
+ const LhsScalar* blA = &blockA[i*strideA+offsetA*mr];
+ prefetch(&blA[0]);
+
+ // TODO move the res loads to the stores
+
+ // get res block as registers
+ AccPacket C0, C4;
+ traits.initAcc(C0);
+ traits.initAcc(C4);
+
+ const RhsScalar* blB = unpackedB;
+ for(Index k=0; k<depth; k++)
+ {
+ LhsPacket A0, A1;
+ RhsPacket B_0;
+ RhsPacket T0;
+
+ traits.loadLhs(&blA[0*LhsProgress], A0);
+ traits.loadLhs(&blA[1*LhsProgress], A1);
+ traits.loadRhs(&blB[0*RhsProgress], B_0);
+ traits.madd(A0,B_0,C0,T0);
+ traits.madd(A1,B_0,C4,B_0);
+
+ blB += RhsProgress;
+ blA += 2*LhsProgress;
+ }
+ ResPacket R0, R4;
+ ResPacket alphav = pset1<ResPacket>(alpha);
+
+ ResScalar* r0 = &res[(j2+0)*resStride + i];
+
+ R0 = ploadu<ResPacket>(r0);
+ R4 = ploadu<ResPacket>(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<depth; k++)
+ {
+ LhsPacket A0;
+ RhsPacket B_0;
+ traits.loadLhs(blA, A0);
+ traits.loadRhs(blB, B_0);
+ traits.madd(A0, B_0, C0, B_0);
+ blB += RhsProgress;
+ blA += LhsProgress;
+ }
+
+ ResPacket alphav = pset1<ResPacket>(alpha);
+ ResPacket R0 = ploadu<ResPacket>(&res[(j2+0)*resStride + i]);
+ traits.acc(C0, alphav, R0);
+ pstoreu(&res[(j2+0)*resStride + i], R0);
+ }
+ for(Index i=peeled_mc2; i<rows; i++)
+ {
+ const LhsScalar* blA = &blockA[i*strideA+offsetA];
+ prefetch(&blA[0]);
+
+ // gets a 1 x 1 res block as registers
+ ResScalar C0(0);
+ // FIXME directly use blockB ??
+ const RhsScalar* blB = &blockB[j2*strideB+offsetB];
+ for(Index k=0; k<depth; k++)
+ {
+ LhsScalar A0 = blA[k];
+ RhsScalar B_0 = blB[k];
+ MADD(cj, A0, B_0, C0, B_0);
+ }
+ res[(j2+0)*resStride + i] += alpha*C0;
+ }
+ }
+ }
+};
+
+#undef CJMADD
+
+// pack a block of the lhs
+// The traversal is as follow (mr==4):
+// 0 4 8 12 ...
+// 1 5 9 13 ...
+// 2 6 10 14 ...
+// 3 7 11 15 ...
+//
+// 16 20 24 28 ...
+// 17 21 25 29 ...
+// 18 22 26 30 ...
+// 19 23 27 31 ...
+//
+// 32 33 34 35 ...
+// 36 36 38 39 ...
+template<typename Scalar, typename Index, int Pack1, int Pack2, int StorageOrder, bool Conjugate, bool PanelMode>
+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)
+ {
+ typedef typename packet_traits<Scalar>::type Packet;
+ enum { PacketSize = packet_traits<Scalar>::size };
+
+ EIGEN_ASM_COMMENT("EIGEN PRODUCT PACK LHS");
+ eigen_assert(((!PanelMode) && stride==0 && offset==0) || (PanelMode && stride>=depth && offset<=stride));
+ eigen_assert( (StorageOrder==RowMajor) || ((Pack1%PacketSize)==0 && Pack1<=4*PacketSize) );
+ conj_if<NumTraits<Scalar>::IsComplex && Conjugate> cj;
+ const_blas_data_mapper<Scalar, Index, StorageOrder> lhs(_lhs,lhsStride);
+ Index count = 0;
+ Index peeled_mc = (rows/Pack1)*Pack1;
+ for(Index i=0; i<peeled_mc; i+=Pack1)
+ {
+ if(PanelMode) count += Pack1 * offset;
+
+ if(StorageOrder==ColMajor)
+ {
+ for(Index k=0; k<depth; k++)
+ {
+ Packet A, B, C, D;
+ if(Pack1>=1*PacketSize) A = ploadu<Packet>(&lhs(i+0*PacketSize, k));
+ if(Pack1>=2*PacketSize) B = ploadu<Packet>(&lhs(i+1*PacketSize, k));
+ if(Pack1>=3*PacketSize) C = ploadu<Packet>(&lhs(i+2*PacketSize, k));
+ if(Pack1>=4*PacketSize) D = ploadu<Packet>(&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<depth; k++)
+ {
+ // TODO add a vectorized transpose here
+ Index w=0;
+ for(; w<Pack1-3; w+=4)
+ {
+ Scalar a(cj(lhs(i+w+0, k))),
+ b(cj(lhs(i+w+1, k))),
+ c(cj(lhs(i+w+2, k))),
+ d(cj(lhs(i+w+3, k)));
+ blockA[count++] = a;
+ blockA[count++] = b;
+ blockA[count++] = c;
+ blockA[count++] = d;
+ }
+ if(Pack1%4)
+ for(;w<Pack1;++w)
+ blockA[count++] = cj(lhs(i+w, k));
+ }
+ }
+ if(PanelMode) count += Pack1 * (stride-offset-depth);
+ }
+ if(rows-peeled_mc>=Pack2)
+ {
+ if(PanelMode) count += Pack2*offset;
+ for(Index k=0; k<depth; k++)
+ for(Index w=0; w<Pack2; w++)
+ blockA[count++] = cj(lhs(peeled_mc+w, k));
+ if(PanelMode) count += Pack2 * (stride-offset-depth);
+ peeled_mc += Pack2;
+ }
+ for(Index i=peeled_mc; i<rows; i++)
+ {
+ if(PanelMode) count += offset;
+ for(Index k=0; k<depth; k++)
+ blockA[count++] = cj(lhs(i, k));
+ if(PanelMode) count += (stride-offset-depth);
+ }
+ }
+};
+
+// copy a complete panel of the rhs
+// this version is optimized for column major matrices
+// The traversal order is as follow: (nr==4):
+// 0 1 2 3 12 13 14 15 24 27
+// 4 5 6 7 16 17 18 19 25 28
+// 8 9 10 11 20 21 22 23 26 29
+// . . . . . . . . . .
+template<typename Scalar, typename Index, int nr, bool Conjugate, bool PanelMode>
+struct gemm_pack_rhs<Scalar, Index, nr, ColMajor, Conjugate, PanelMode>
+{
+ typedef typename packet_traits<Scalar>::type Packet;
+ enum { PacketSize = packet_traits<Scalar>::size };
+ EIGEN_DONT_INLINE void operator()(Scalar* blockB, const Scalar* rhs, Index rhsStride, Index depth, Index cols,
+ Index stride=0, Index offset=0)
+ {
+ EIGEN_ASM_COMMENT("EIGEN PRODUCT PACK RHS COLMAJOR");
+ eigen_assert(((!PanelMode) && stride==0 && offset==0) || (PanelMode && stride>=depth && offset<=stride));
+ conj_if<NumTraits<Scalar>::IsComplex && Conjugate> cj;
+ Index packet_cols = (cols/nr) * nr;
+ Index count = 0;
+ for(Index j2=0; j2<packet_cols; j2+=nr)
+ {
+ // skip what we have before
+ if(PanelMode) count += nr * offset;
+ const Scalar* b0 = &rhs[(j2+0)*rhsStride];
+ const Scalar* b1 = &rhs[(j2+1)*rhsStride];
+ const Scalar* b2 = &rhs[(j2+2)*rhsStride];
+ const Scalar* b3 = &rhs[(j2+3)*rhsStride];
+ for(Index k=0; k<depth; k++)
+ {
+ blockB[count+0] = cj(b0[k]);
+ blockB[count+1] = cj(b1[k]);
+ if(nr==4) blockB[count+2] = cj(b2[k]);
+ if(nr==4) blockB[count+3] = cj(b3[k]);
+ count += nr;
+ }
+ // skip what we have after
+ if(PanelMode) count += nr * (stride-offset-depth);
+ }
+
+ // copy the remaining columns one at a time (nr==1)
+ for(Index j2=packet_cols; j2<cols; ++j2)
+ {
+ if(PanelMode) count += offset;
+ const Scalar* b0 = &rhs[(j2+0)*rhsStride];
+ for(Index k=0; k<depth; k++)
+ {
+ blockB[count] = cj(b0[k]);
+ count += 1;
+ }
+ if(PanelMode) count += (stride-offset-depth);
+ }
+ }
+};
+
+// this version is optimized for row major matrices
+template<typename Scalar, typename Index, int nr, bool Conjugate, bool PanelMode>
+struct gemm_pack_rhs<Scalar, Index, nr, RowMajor, Conjugate, PanelMode>
+{
+ enum { PacketSize = packet_traits<Scalar>::size };
+ EIGEN_DONT_INLINE void operator()(Scalar* blockB, const Scalar* rhs, Index rhsStride, Index depth, Index cols,
+ Index stride=0, Index offset=0)
+ {
+ EIGEN_ASM_COMMENT("EIGEN PRODUCT PACK RHS ROWMAJOR");
+ eigen_assert(((!PanelMode) && stride==0 && offset==0) || (PanelMode && stride>=depth && offset<=stride));
+ conj_if<NumTraits<Scalar>::IsComplex && Conjugate> cj;
+ Index packet_cols = (cols/nr) * nr;
+ Index count = 0;
+ for(Index j2=0; j2<packet_cols; j2+=nr)
+ {
+ // skip what we have before
+ if(PanelMode) count += nr * offset;
+ for(Index k=0; k<depth; k++)
+ {
+ const Scalar* b0 = &rhs[k*rhsStride + j2];
+ blockB[count+0] = cj(b0[0]);
+ blockB[count+1] = cj(b0[1]);
+ if(nr==4) blockB[count+2] = cj(b0[2]);
+ if(nr==4) blockB[count+3] = cj(b0[3]);
+ count += nr;
+ }
+ // skip what we have after
+ if(PanelMode) count += nr * (stride-offset-depth);
+ }
+ // copy the remaining columns one at a time (nr==1)
+ for(Index j2=packet_cols; j2<cols; ++j2)
+ {
+ if(PanelMode) count += offset;
+ const Scalar* b0 = &rhs[j2];
+ for(Index k=0; k<depth; k++)
+ {
+ blockB[count] = cj(b0[k*rhsStride]);
+ count += 1;
+ }
+ if(PanelMode) count += stride-offset-depth;
+ }
+ }
+};
+
+} // end namespace internal
+
+/** \returns the currently set level 1 cpu cache size (in bytes) used to estimate the ideal blocking size parameters.
+ * \sa setCpuCacheSize */
+inline std::ptrdiff_t l1CacheSize()
+{
+ std::ptrdiff_t l1, l2;
+ internal::manage_caching_sizes(GetAction, &l1, &l2);
+ return l1;
+}
+
+/** \returns the currently set level 2 cpu cache size (in bytes) used to estimate the ideal blocking size parameters.
+ * \sa setCpuCacheSize */
+inline std::ptrdiff_t l2CacheSize()
+{
+ std::ptrdiff_t l1, l2;
+ internal::manage_caching_sizes(GetAction, &l1, &l2);
+ return l2;
+}
+
+/** Set the cpu L1 and L2 cache sizes (in bytes).
+ * These values are use to adjust the size of the blocks
+ * for the algorithms working per blocks.
+ *
+ * \sa computeProductBlockingSizes */
+inline void setCpuCacheSizes(std::ptrdiff_t l1, std::ptrdiff_t l2)
+{
+ internal::manage_caching_sizes(SetAction, &l1, &l2);
+}
+
+} // end namespace Eigen
+
+#endif // EIGEN_GENERAL_BLOCK_PANEL_H
diff --git a/Eigen/src/Core/products/GeneralMatrixMatrix.h b/Eigen/src/Core/products/GeneralMatrixMatrix.h
new file mode 100644
index 000000000..73a465ec5
--- /dev/null
+++ b/Eigen/src/Core/products/GeneralMatrixMatrix.h
@@ -0,0 +1,428 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra.
+//
+// Copyright (C) 2008-2009 Gael Guennebaud <gael.guennebaud@inria.fr>
+//
+// This Source Code Form is subject to the terms of the Mozilla
+// Public License v. 2.0. If 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<typename _LhsScalar, typename _RhsScalar> 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<Index,LhsScalar,LhsStorageOrder,ConjugateLhs,RhsScalar,RhsStorageOrder,ConjugateRhs,RowMajor>
+{
+ typedef typename scalar_product_traits<LhsScalar, RhsScalar>::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<RhsScalar,LhsScalar>& blocking,
+ GemmParallelInfo<Index>* info = 0)
+ {
+ // transpose the product such that the result is column major
+ general_matrix_matrix_product<Index,
+ RhsScalar, RhsStorageOrder==RowMajor ? ColMajor : RowMajor, ConjugateRhs,
+ LhsScalar, LhsStorageOrder==RowMajor ? ColMajor : RowMajor, ConjugateLhs,
+ ColMajor>
+ ::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<Index,LhsScalar,LhsStorageOrder,ConjugateLhs,RhsScalar,RhsStorageOrder,ConjugateRhs,ColMajor>
+{
+typedef typename scalar_product_traits<LhsScalar, RhsScalar>::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<LhsScalar,RhsScalar>& blocking,
+ GemmParallelInfo<Index>* info = 0)
+{
+ const_blas_data_mapper<LhsScalar, Index, LhsStorageOrder> lhs(_lhs,lhsStride);
+ const_blas_data_mapper<RhsScalar, Index, RhsStorageOrder> rhs(_rhs,rhsStride);
+
+ typedef gebp_traits<LhsScalar,RhsScalar> 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<LhsScalar, Index, Traits::mr, Traits::LhsProgress, LhsStorageOrder> pack_lhs;
+ gemm_pack_rhs<RhsScalar, Index, Traits::nr, RhsStorageOrder> pack_rhs;
+ gebp_kernel<LhsScalar, RhsScalar, Index, Traits::mr, Traits::nr, ConjugateLhs, ConjugateRhs> 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<depth; k+=kc)
+ {
+ const Index actual_kc = (std::min)(k+kc,depth)-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; shift<threads; ++shift)
+ {
+ Index j = (tid+shift)%threads;
+
+ // At this point we have to make sure that B'_j has been updated by the thread j,
+ // we use testAndSetOrdered to mimic a volatile access.
+ // However, no need to wait for the B' part which has been updated by the current thread!
+ if(shift>0)
+ 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<rows; i+=mc)
+ {
+ const Index actual_mc = (std::min)(i+mc,rows)-i;
+
+ // pack A_i,k to A'
+ pack_lhs(blockA, &lhs(i,k), lhsStride, actual_kc, actual_mc);
+
+ // C_i += A' * B'
+ gebp(res+i, resStride, blockA, blockB, actual_mc, actual_kc, cols, alpha, -1,-1,0,0, w);
+ }
+
+ // Release all the sub blocks B'_j of B' for the current thread,
+ // i.e., we simply decrement the number of users by 1
+ for(Index j=0; j<threads; ++j)
+ #pragma omp atomic
+ --(info[j].users);
+ }
+ }
+ else
+#endif // EIGEN_HAS_OPENMP
+ {
+ EIGEN_UNUSED_VARIABLE(info);
+
+ // this is the sequential version!
+ std::size_t sizeA = kc*mc;
+ std::size_t sizeB = kc*cols;
+ std::size_t sizeW = kc*Traits::WorkSpaceFactor;
+
+ ei_declare_aligned_stack_constructed_variable(LhsScalar, blockA, sizeA, blocking.blockA());
+ ei_declare_aligned_stack_constructed_variable(RhsScalar, blockB, sizeB, blocking.blockB());
+ ei_declare_aligned_stack_constructed_variable(RhsScalar, blockW, sizeW, blocking.blockW());
+
+ // For each horizontal panel of the rhs, and corresponding panel of the lhs...
+ // (==GEMM_VAR1)
+ for(Index k2=0; k2<depth; k2+=kc)
+ {
+ const Index actual_kc = (std::min)(k2+kc,depth)-k2;
+
+ // OK, here we have selected one horizontal panel of rhs and one vertical panel of lhs.
+ // => 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<rows; i2+=mc)
+ {
+ const Index actual_mc = (std::min)(i2+mc,rows)-i2;
+
+ // We pack the lhs's block into a sequential chunk of memory (L1 caching)
+ // Note that this block will be read a very high number of times, which is equal to the number of
+ // micro vertical panel of the large rhs's panel (e.g., cols/4 times).
+ pack_lhs(blockA, &lhs(i2,k2), lhsStride, actual_kc, actual_mc);
+
+ // Everything is packed, we can now call the block * panel kernel:
+ gebp(res+i2, resStride, blockA, blockB, actual_mc, actual_kc, cols, alpha, -1, -1, 0, 0, blockW);
+
+ }
+ }
+ }
+}
+
+};
+
+/*********************************************************************************
+* Specialization of GeneralProduct<> for "large" GEMM, i.e.,
+* implementation of the high level wrapper to general_matrix_matrix_product
+**********************************************************************************/
+
+template<typename Lhs, typename Rhs>
+struct traits<GeneralProduct<Lhs,Rhs,GemmProduct> >
+ : traits<ProductBase<GeneralProduct<Lhs,Rhs,GemmProduct>, Lhs, Rhs> >
+{};
+
+template<typename Scalar, typename Index, typename Gemm, typename Lhs, typename Rhs, typename Dest, typename BlockingType>
+struct gemm_functor
+{
+ gemm_functor(const Lhs& lhs, const Rhs& rhs, Dest& dest, 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<Index>* 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<int StorageOrder, typename LhsScalar, typename RhsScalar, int MaxRows, int MaxCols, int MaxDepth, int KcFactor=1,
+bool FiniteAtCompileTime = MaxRows!=Dynamic && MaxCols!=Dynamic && MaxDepth != Dynamic> class gemm_blocking_space;
+
+template<typename _LhsScalar, typename _RhsScalar>
+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<int StorageOrder, typename _LhsScalar, typename _RhsScalar, int MaxRows, int MaxCols, int MaxDepth, int KcFactor>
+class gemm_blocking_space<StorageOrder,_LhsScalar,_RhsScalar,MaxRows, MaxCols, MaxDepth, KcFactor, true>
+ : public level3_blocking<
+ typename conditional<StorageOrder==RowMajor,_RhsScalar,_LhsScalar>::type,
+ typename conditional<StorageOrder==RowMajor,_LhsScalar,_RhsScalar>::type>
+{
+ enum {
+ Transpose = StorageOrder==RowMajor,
+ ActualRows = Transpose ? MaxCols : MaxRows,
+ ActualCols = Transpose ? MaxRows : MaxCols
+ };
+ typedef typename conditional<Transpose,_RhsScalar,_LhsScalar>::type LhsScalar;
+ typedef typename conditional<Transpose,_LhsScalar,_RhsScalar>::type RhsScalar;
+ typedef gebp_traits<LhsScalar,RhsScalar> 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<int StorageOrder, typename _LhsScalar, typename _RhsScalar, int MaxRows, int MaxCols, int MaxDepth, int KcFactor>
+class gemm_blocking_space<StorageOrder,_LhsScalar,_RhsScalar,MaxRows, MaxCols, MaxDepth, KcFactor, false>
+ : public level3_blocking<
+ typename conditional<StorageOrder==RowMajor,_RhsScalar,_LhsScalar>::type,
+ typename conditional<StorageOrder==RowMajor,_LhsScalar,_RhsScalar>::type>
+{
+ enum {
+ Transpose = StorageOrder==RowMajor
+ };
+ typedef typename conditional<Transpose,_RhsScalar,_LhsScalar>::type LhsScalar;
+ typedef typename conditional<Transpose,_LhsScalar,_RhsScalar>::type RhsScalar;
+ typedef gebp_traits<LhsScalar,RhsScalar> 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<LhsScalar,RhsScalar,KcFactor>(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<LhsScalar>(m_sizeA);
+ }
+
+ void allocateB()
+ {
+ if(this->m_blockB==0)
+ this->m_blockB = aligned_new<RhsScalar>(m_sizeB);
+ }
+
+ void allocateW()
+ {
+ if(this->m_blockW==0)
+ this->m_blockW = aligned_new<RhsScalar>(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<typename Lhs, typename Rhs>
+class GeneralProduct<Lhs, Rhs, GemmProduct>
+ : public ProductBase<GeneralProduct<Lhs,Rhs,GemmProduct>, 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)
+ {
+ typedef internal::scalar_product_op<LhsScalar,RhsScalar> BinOp;
+ EIGEN_CHECK_BINARY_COMPATIBILIY(BinOp,LhsScalar,RhsScalar);
+ }
+
+ template<typename Dest> void scaleAndAddTo(Dest& dst, Scalar alpha) const
+ {
+ eigen_assert(dst.rows()==m_lhs.rows() && dst.cols()==m_rhs.cols());
+
+ typename internal::add_const_on_value_type<ActualLhsType>::type lhs = LhsBlasTraits::extract(m_lhs);
+ typename internal::add_const_on_value_type<ActualRhsType>::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/Eigen/src/Core/products/GeneralMatrixMatrixTriangular.h b/Eigen/src/Core/products/GeneralMatrixMatrixTriangular.h
new file mode 100644
index 000000000..432d3a9dc
--- /dev/null
+++ b/Eigen/src/Core/products/GeneralMatrixMatrixTriangular.h
@@ -0,0 +1,214 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra.
+//
+// Copyright (C) 2009-2010 Gael Guennebaud <gael.guennebaud@inria.fr>
+//
+// This Source Code Form is subject to the terms of the Mozilla
+// Public License v. 2.0. If a copy of the MPL was not distributed
+// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+#ifndef EIGEN_GENERAL_MATRIX_MATRIX_TRIANGULAR_H
+#define EIGEN_GENERAL_MATRIX_MATRIX_TRIANGULAR_H
+
+namespace Eigen {
+
+namespace internal {
+
+/**********************************************************************
+* This file implements a general A * B product while
+* evaluating only one triangular part of the product.
+* This is more general version of self adjoint product (C += A A^T)
+* as the level 3 SYRK Blas routine.
+**********************************************************************/
+
+// forward declarations (defined at the end of this file)
+template<typename LhsScalar, typename RhsScalar, typename Index, int mr, int nr, bool ConjLhs, bool ConjRhs, int UpLo>
+struct tribb_kernel;
+
+/* Optimized matrix-matrix product evaluating only one triangular half */
+template <typename Index,
+ typename LhsScalar, int LhsStorageOrder, bool ConjugateLhs,
+ typename RhsScalar, int RhsStorageOrder, bool ConjugateRhs,
+ int ResStorageOrder, int UpLo, int Version = Specialized>
+struct general_matrix_matrix_triangular_product;
+
+// as usual if the result is row major => we transpose the product
+template <typename Index, typename LhsScalar, int LhsStorageOrder, bool ConjugateLhs,
+ typename RhsScalar, int RhsStorageOrder, bool ConjugateRhs, int UpLo, int Version>
+struct general_matrix_matrix_triangular_product<Index,LhsScalar,LhsStorageOrder,ConjugateLhs,RhsScalar,RhsStorageOrder,ConjugateRhs,RowMajor,UpLo,Version>
+{
+ typedef typename scalar_product_traits<LhsScalar, RhsScalar>::ReturnType ResScalar;
+ static EIGEN_STRONG_INLINE void run(Index size, Index depth,const LhsScalar* lhs, Index lhsStride,
+ const RhsScalar* rhs, Index rhsStride, ResScalar* res, Index resStride, ResScalar alpha)
+ {
+ general_matrix_matrix_triangular_product<Index,
+ RhsScalar, RhsStorageOrder==RowMajor ? ColMajor : RowMajor, ConjugateRhs,
+ LhsScalar, LhsStorageOrder==RowMajor ? ColMajor : RowMajor, ConjugateLhs,
+ ColMajor, UpLo==Lower?Upper:Lower>
+ ::run(size,depth,rhs,rhsStride,lhs,lhsStride,res,resStride,alpha);
+ }
+};
+
+template <typename Index, typename LhsScalar, int LhsStorageOrder, bool ConjugateLhs,
+ typename RhsScalar, int RhsStorageOrder, bool ConjugateRhs, int UpLo, int Version>
+struct general_matrix_matrix_triangular_product<Index,LhsScalar,LhsStorageOrder,ConjugateLhs,RhsScalar,RhsStorageOrder,ConjugateRhs,ColMajor,UpLo,Version>
+{
+ typedef typename scalar_product_traits<LhsScalar, RhsScalar>::ReturnType ResScalar;
+ static EIGEN_STRONG_INLINE void run(Index size, Index depth,const LhsScalar* _lhs, Index lhsStride,
+ const RhsScalar* _rhs, Index rhsStride, ResScalar* res, Index resStride, ResScalar alpha)
+ {
+ const_blas_data_mapper<LhsScalar, Index, LhsStorageOrder> lhs(_lhs,lhsStride);
+ const_blas_data_mapper<RhsScalar, Index, RhsStorageOrder> rhs(_rhs,rhsStride);
+
+ typedef gebp_traits<LhsScalar,RhsScalar> Traits;
+
+ Index kc = depth; // cache block size along the K direction
+ Index mc = size; // cache block size along the M direction
+ Index nc = size; // cache block size along the N direction
+ computeProductBlockingSizes<LhsScalar,RhsScalar>(kc, mc, nc);
+ // !!! mc must be a multiple of nr:
+ if(mc > Traits::nr)
+ mc = (mc/Traits::nr)*Traits::nr;
+
+ std::size_t sizeW = kc*Traits::WorkSpaceFactor;
+ std::size_t sizeB = sizeW + kc*size;
+ ei_declare_aligned_stack_constructed_variable(LhsScalar, blockA, kc*mc, 0);
+ ei_declare_aligned_stack_constructed_variable(RhsScalar, allocatedBlockB, sizeB, 0);
+ RhsScalar* blockB = allocatedBlockB + sizeW;
+
+ gemm_pack_lhs<LhsScalar, Index, Traits::mr, Traits::LhsProgress, LhsStorageOrder> pack_lhs;
+ gemm_pack_rhs<RhsScalar, Index, Traits::nr, RhsStorageOrder> pack_rhs;
+ gebp_kernel <LhsScalar, RhsScalar, Index, Traits::mr, Traits::nr, ConjugateLhs, ConjugateRhs> gebp;
+ tribb_kernel<LhsScalar, RhsScalar, Index, Traits::mr, Traits::nr, ConjugateLhs, ConjugateRhs, UpLo> sybb;
+
+ for(Index k2=0; k2<depth; k2+=kc)
+ {
+ const Index actual_kc = (std::min)(k2+kc,depth)-k2;
+
+ // note that the actual rhs is the transpose/adjoint of mat
+ pack_rhs(blockB, &rhs(k2,0), rhsStride, actual_kc, size);
+
+ for(Index i2=0; i2<size; i2+=mc)
+ {
+ const Index actual_mc = (std::min)(i2+mc,size)-i2;
+
+ pack_lhs(blockA, &lhs(i2, k2), lhsStride, actual_kc, actual_mc);
+
+ // the selected actual_mc * size panel of res is split into three different part:
+ // 1 - before the diagonal => processed with gebp or skipped
+ // 2 - the actual_mc x actual_mc symmetric block => processed with a special kernel
+ // 3 - after the diagonal => processed with gebp or skipped
+ if (UpLo==Lower)
+ gebp(res+i2, resStride, blockA, blockB, actual_mc, actual_kc, (std::min)(size,i2), alpha,
+ -1, -1, 0, 0, allocatedBlockB);
+
+ sybb(res+resStride*i2 + i2, resStride, blockA, blockB + actual_kc*i2, actual_mc, actual_kc, alpha, allocatedBlockB);
+
+ if (UpLo==Upper)
+ {
+ Index j2 = i2+actual_mc;
+ gebp(res+resStride*j2+i2, resStride, blockA, blockB+actual_kc*j2, actual_mc, actual_kc, (std::max)(Index(0), size-j2), alpha,
+ -1, -1, 0, 0, allocatedBlockB);
+ }
+ }
+ }
+ }
+};
+
+// Optimized packed Block * packed Block product kernel evaluating only one given triangular part
+// This kernel is built on top of the gebp kernel:
+// - the current destination block is processed per panel of actual_mc x BlockSize
+// where BlockSize is set to the minimal value allowing gebp to be as fast as possible
+// - then, as usual, each panel is split into three parts along the diagonal,
+// the sub blocks above and below the diagonal are processed as usual,
+// while the triangular block overlapping the diagonal is evaluated into a
+// small temporary buffer which is then accumulated into the result using a
+// triangular traversal.
+template<typename LhsScalar, typename RhsScalar, typename Index, int mr, int nr, bool ConjLhs, bool ConjRhs, int UpLo>
+struct tribb_kernel
+{
+ typedef gebp_traits<LhsScalar,RhsScalar,ConjLhs,ConjRhs> Traits;
+ typedef typename Traits::ResScalar ResScalar;
+
+ enum {
+ BlockSize = EIGEN_PLAIN_ENUM_MAX(mr,nr)
+ };
+ void operator()(ResScalar* res, Index resStride, const LhsScalar* blockA, const RhsScalar* blockB, Index size, Index depth, ResScalar alpha, RhsScalar* workspace)
+ {
+ gebp_kernel<LhsScalar, RhsScalar, Index, mr, nr, ConjLhs, ConjRhs> gebp_kernel;
+ Matrix<ResScalar,BlockSize,BlockSize,ColMajor> buffer;
+
+ // let's process the block per panel of actual_mc x BlockSize,
+ // again, each is split into three parts, etc.
+ for (Index j=0; j<size; j+=BlockSize)
+ {
+ Index actualBlockSize = std::min<Index>(BlockSize,size - j);
+ const RhsScalar* actual_b = blockB+j*depth;
+
+ if(UpLo==Upper)
+ gebp_kernel(res+j*resStride, resStride, blockA, actual_b, j, depth, actualBlockSize, alpha,
+ -1, -1, 0, 0, workspace);
+
+ // selfadjoint micro block
+ {
+ Index i = j;
+ buffer.setZero();
+ // 1 - apply the kernel on the temporary buffer
+ gebp_kernel(buffer.data(), BlockSize, blockA+depth*i, actual_b, actualBlockSize, depth, actualBlockSize, alpha,
+ -1, -1, 0, 0, workspace);
+ // 2 - triangular accumulation
+ for(Index j1=0; j1<actualBlockSize; ++j1)
+ {
+ ResScalar* r = res + (j+j1)*resStride + i;
+ for(Index i1=UpLo==Lower ? j1 : 0;
+ UpLo==Lower ? i1<actualBlockSize : i1<=j1; ++i1)
+ r[i1] += buffer(i1,j1);
+ }
+ }
+
+ if(UpLo==Lower)
+ {
+ Index i = j+actualBlockSize;
+ gebp_kernel(res+j*resStride+i, resStride, blockA+depth*i, actual_b, size-i, depth, actualBlockSize, alpha,
+ -1, -1, 0, 0, workspace);
+ }
+ }
+ }
+};
+
+} // end namespace internal
+
+// high level API
+
+template<typename MatrixType, unsigned int UpLo>
+template<typename ProductDerived, typename _Lhs, typename _Rhs>
+TriangularView<MatrixType,UpLo>& TriangularView<MatrixType,UpLo>::assignProduct(const ProductBase<ProductDerived, _Lhs,_Rhs>& prod, const Scalar& alpha)
+{
+ typedef typename internal::remove_all<typename ProductDerived::LhsNested>::type Lhs;
+ typedef internal::blas_traits<Lhs> LhsBlasTraits;
+ typedef typename LhsBlasTraits::DirectLinearAccessType ActualLhs;
+ typedef typename internal::remove_all<ActualLhs>::type _ActualLhs;
+ typename internal::add_const_on_value_type<ActualLhs>::type actualLhs = LhsBlasTraits::extract(prod.lhs());
+
+ typedef typename internal::remove_all<typename ProductDerived::RhsNested>::type Rhs;
+ typedef internal::blas_traits<Rhs> RhsBlasTraits;
+ typedef typename RhsBlasTraits::DirectLinearAccessType ActualRhs;
+ typedef typename internal::remove_all<ActualRhs>::type _ActualRhs;
+ typename internal::add_const_on_value_type<ActualRhs>::type actualRhs = RhsBlasTraits::extract(prod.rhs());
+
+ typename ProductDerived::Scalar actualAlpha = alpha * LhsBlasTraits::extractScalarFactor(prod.lhs().derived()) * RhsBlasTraits::extractScalarFactor(prod.rhs().derived());
+
+ internal::general_matrix_matrix_triangular_product<Index,
+ typename Lhs::Scalar, _ActualLhs::Flags&RowMajorBit ? RowMajor : ColMajor, LhsBlasTraits::NeedToConjugate,
+ typename Rhs::Scalar, _ActualRhs::Flags&RowMajorBit ? RowMajor : ColMajor, RhsBlasTraits::NeedToConjugate,
+ MatrixType::Flags&RowMajorBit ? RowMajor : ColMajor, UpLo>
+ ::run(m_matrix.cols(), actualLhs.cols(),
+ &actualLhs.coeffRef(0,0), actualLhs.outerStride(), &actualRhs.coeffRef(0,0), actualRhs.outerStride(),
+ const_cast<Scalar*>(m_matrix.data()), m_matrix.outerStride(), actualAlpha);
+
+ return *this;
+}
+
+} // end namespace Eigen
+
+#endif // EIGEN_GENERAL_MATRIX_MATRIX_TRIANGULAR_H
diff --git a/Eigen/src/Core/products/GeneralMatrixMatrixTriangular_MKL.h b/Eigen/src/Core/products/GeneralMatrixMatrixTriangular_MKL.h
new file mode 100644
index 000000000..3deed068e
--- /dev/null
+++ b/Eigen/src/Core/products/GeneralMatrixMatrixTriangular_MKL.h
@@ -0,0 +1,146 @@
+/*
+ Copyright (c) 2011, Intel Corporation. All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without modification,
+ are permitted provided that the following conditions are met:
+
+ * Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+ * Neither the name of Intel Corporation nor the names of its contributors may
+ be used to endorse or promote products derived from this software without
+ specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+ ********************************************************************************
+ * Content : Eigen bindings to Intel(R) MKL
+ * Level 3 BLAS SYRK/HERK implementation.
+ ********************************************************************************
+*/
+
+#ifndef EIGEN_GENERAL_MATRIX_MATRIX_TRIANGULAR_MKL_H
+#define EIGEN_GENERAL_MATRIX_MATRIX_TRIANGULAR_MKL_H
+
+namespace Eigen {
+
+namespace internal {
+
+template <typename Index, typename Scalar, int AStorageOrder, bool ConjugateA, int ResStorageOrder, int UpLo>
+struct general_matrix_matrix_rankupdate :
+ general_matrix_matrix_triangular_product<
+ Index,Scalar,AStorageOrder,ConjugateA,Scalar,AStorageOrder,ConjugateA,ResStorageOrder,UpLo,BuiltIn> {};
+
+
+// try to go to BLAS specialization
+#define EIGEN_MKL_RANKUPDATE_SPECIALIZE(Scalar) \
+template <typename Index, int LhsStorageOrder, bool ConjugateLhs, \
+ int RhsStorageOrder, bool ConjugateRhs, int UpLo> \
+struct general_matrix_matrix_triangular_product<Index,Scalar,LhsStorageOrder,ConjugateLhs, \
+ Scalar,RhsStorageOrder,ConjugateRhs,ColMajor,UpLo,Specialized> { \
+ static EIGEN_STRONG_INLINE void run(Index size, Index depth,const Scalar* lhs, Index lhsStride, \
+ const Scalar* rhs, Index rhsStride, Scalar* res, Index resStride, Scalar alpha) \
+ { \
+ if (lhs==rhs) { \
+ general_matrix_matrix_rankupdate<Index,Scalar,LhsStorageOrder,ConjugateLhs,ColMajor,UpLo> \
+ ::run(size,depth,lhs,lhsStride,rhs,rhsStride,res,resStride,alpha); \
+ } else { \
+ general_matrix_matrix_triangular_product<Index, \
+ Scalar, LhsStorageOrder, ConjugateLhs, \
+ Scalar, RhsStorageOrder, ConjugateRhs, \
+ ColMajor, UpLo, BuiltIn> \
+ ::run(size,depth,lhs,lhsStride,rhs,rhsStride,res,resStride,alpha); \
+ } \
+ } \
+};
+
+EIGEN_MKL_RANKUPDATE_SPECIALIZE(double)
+//EIGEN_MKL_RANKUPDATE_SPECIALIZE(dcomplex)
+EIGEN_MKL_RANKUPDATE_SPECIALIZE(float)
+//EIGEN_MKL_RANKUPDATE_SPECIALIZE(scomplex)
+
+// SYRK for float/double
+#define EIGEN_MKL_RANKUPDATE_R(EIGTYPE, MKLTYPE, MKLFUNC) \
+template <typename Index, int AStorageOrder, bool ConjugateA, int UpLo> \
+struct general_matrix_matrix_rankupdate<Index,EIGTYPE,AStorageOrder,ConjugateA,ColMajor,UpLo> { \
+ enum { \
+ IsLower = (UpLo&Lower) == Lower, \
+ LowUp = IsLower ? Lower : Upper, \
+ conjA = ((AStorageOrder==ColMajor) && ConjugateA) ? 1 : 0 \
+ }; \
+ static EIGEN_STRONG_INLINE void run(Index size, Index depth,const EIGTYPE* lhs, Index lhsStride, \
+ const EIGTYPE* rhs, Index rhsStride, EIGTYPE* res, Index resStride, EIGTYPE alpha) \
+ { \
+ /* typedef Matrix<EIGTYPE, Dynamic, Dynamic, RhsStorageOrder> MatrixRhs;*/ \
+\
+ MKL_INT lda=lhsStride, ldc=resStride, n=size, k=depth; \
+ char uplo=(IsLower) ? 'L' : 'U', trans=(AStorageOrder==RowMajor) ? 'T':'N'; \
+ MKLTYPE alpha_, beta_; \
+\
+/* Set alpha_ & beta_ */ \
+ assign_scalar_eig2mkl<MKLTYPE, EIGTYPE>(alpha_, alpha); \
+ assign_scalar_eig2mkl<MKLTYPE, EIGTYPE>(beta_, EIGTYPE(1)); \
+ MKLFUNC(&uplo, &trans, &n, &k, &alpha_, lhs, &lda, &beta_, res, &ldc); \
+ } \
+};
+
+// HERK for complex data
+#define EIGEN_MKL_RANKUPDATE_C(EIGTYPE, MKLTYPE, RTYPE, MKLFUNC) \
+template <typename Index, int AStorageOrder, bool ConjugateA, int UpLo> \
+struct general_matrix_matrix_rankupdate<Index,EIGTYPE,AStorageOrder,ConjugateA,ColMajor,UpLo> { \
+ enum { \
+ IsLower = (UpLo&Lower) == Lower, \
+ LowUp = IsLower ? Lower : Upper, \
+ conjA = (((AStorageOrder==ColMajor) && ConjugateA) || ((AStorageOrder==RowMajor) && !ConjugateA)) ? 1 : 0 \
+ }; \
+ static EIGEN_STRONG_INLINE void run(Index size, Index depth,const EIGTYPE* lhs, Index lhsStride, \
+ const EIGTYPE* rhs, Index rhsStride, EIGTYPE* res, Index resStride, EIGTYPE alpha) \
+ { \
+ typedef Matrix<EIGTYPE, Dynamic, Dynamic, AStorageOrder> MatrixType; \
+\
+ MKL_INT lda=lhsStride, ldc=resStride, n=size, k=depth; \
+ char uplo=(IsLower) ? 'L' : 'U', trans=(AStorageOrder==RowMajor) ? 'C':'N'; \
+ RTYPE alpha_, beta_; \
+ const EIGTYPE* a_ptr; \
+\
+/* Set alpha_ & beta_ */ \
+/* assign_scalar_eig2mkl<MKLTYPE, EIGTYPE>(alpha_, alpha); */\
+/* assign_scalar_eig2mkl<MKLTYPE, EIGTYPE>(beta_, EIGTYPE(1));*/ \
+ alpha_ = alpha.real(); \
+ beta_ = 1.0; \
+/* Copy with conjugation in some cases*/ \
+ MatrixType a; \
+ if (conjA) { \
+ Map<const MatrixType, 0, OuterStride<> > mapA(lhs,n,k,OuterStride<>(lhsStride)); \
+ a = mapA.conjugate(); \
+ lda = a.outerStride(); \
+ a_ptr = a.data(); \
+ } else a_ptr=lhs; \
+ MKLFUNC(&uplo, &trans, &n, &k, &alpha_, (MKLTYPE*)a_ptr, &lda, &beta_, (MKLTYPE*)res, &ldc); \
+ } \
+};
+
+
+EIGEN_MKL_RANKUPDATE_R(double, double, dsyrk)
+EIGEN_MKL_RANKUPDATE_R(float, float, ssyrk)
+
+//EIGEN_MKL_RANKUPDATE_C(dcomplex, MKL_Complex16, double, zherk)
+//EIGEN_MKL_RANKUPDATE_C(scomplex, MKL_Complex8, double, cherk)
+
+
+} // end namespace internal
+
+} // end namespace Eigen
+
+#endif // EIGEN_GENERAL_MATRIX_MATRIX_TRIANGULAR_MKL_H
diff --git a/Eigen/src/Core/products/GeneralMatrixMatrix_MKL.h b/Eigen/src/Core/products/GeneralMatrixMatrix_MKL.h
new file mode 100644
index 000000000..060af328e
--- /dev/null
+++ b/Eigen/src/Core/products/GeneralMatrixMatrix_MKL.h
@@ -0,0 +1,118 @@
+/*
+ Copyright (c) 2011, Intel Corporation. All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without modification,
+ are permitted provided that the following conditions are met:
+
+ * Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+ * Neither the name of Intel Corporation nor the names of its contributors may
+ be used to endorse or promote products derived from this software without
+ specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+ ********************************************************************************
+ * Content : Eigen bindings to Intel(R) MKL
+ * General matrix-matrix product functionality based on ?GEMM.
+ ********************************************************************************
+*/
+
+#ifndef EIGEN_GENERAL_MATRIX_MATRIX_MKL_H
+#define EIGEN_GENERAL_MATRIX_MATRIX_MKL_H
+
+namespace Eigen {
+
+namespace internal {
+
+/**********************************************************************
+* This file implements general matrix-matrix multiplication using BLAS
+* gemm function via partial specialization of
+* general_matrix_matrix_product::run(..) method for float, double,
+* std::complex<float> and std::complex<double> types
+**********************************************************************/
+
+// gemm specialization
+
+#define GEMM_SPECIALIZATION(EIGTYPE, EIGPREFIX, MKLTYPE, MKLPREFIX) \
+template< \
+ typename Index, \
+ int LhsStorageOrder, bool ConjugateLhs, \
+ int RhsStorageOrder, bool ConjugateRhs> \
+struct general_matrix_matrix_product<Index,EIGTYPE,LhsStorageOrder,ConjugateLhs,EIGTYPE,RhsStorageOrder,ConjugateRhs,ColMajor> \
+{ \
+static void run(Index rows, Index cols, Index depth, \
+ const EIGTYPE* _lhs, Index lhsStride, \
+ const EIGTYPE* _rhs, Index rhsStride, \
+ EIGTYPE* res, Index resStride, \
+ EIGTYPE alpha, \
+ level3_blocking<EIGTYPE, EIGTYPE>& /*blocking*/, \
+ GemmParallelInfo<Index>* /*info = 0*/) \
+{ \
+ using std::conj; \
+\
+ char transa, transb; \
+ MKL_INT m, n, k, lda, ldb, ldc; \
+ const EIGTYPE *a, *b; \
+ MKLTYPE alpha_, beta_; \
+ MatrixX##EIGPREFIX a_tmp, b_tmp; \
+ EIGTYPE myone(1);\
+\
+/* Set transpose options */ \
+ transa = (LhsStorageOrder==RowMajor) ? ((ConjugateLhs) ? 'C' : 'T') : 'N'; \
+ transb = (RhsStorageOrder==RowMajor) ? ((ConjugateRhs) ? 'C' : 'T') : 'N'; \
+\
+/* Set m, n, k */ \
+ m = (MKL_INT)rows; \
+ n = (MKL_INT)cols; \
+ k = (MKL_INT)depth; \
+\
+/* Set alpha_ & beta_ */ \
+ assign_scalar_eig2mkl(alpha_, alpha); \
+ assign_scalar_eig2mkl(beta_, myone); \
+\
+/* Set lda, ldb, ldc */ \
+ lda = (MKL_INT)lhsStride; \
+ ldb = (MKL_INT)rhsStride; \
+ ldc = (MKL_INT)resStride; \
+\
+/* Set a, b, c */ \
+ if ((LhsStorageOrder==ColMajor) && (ConjugateLhs)) { \
+ Map<const MatrixX##EIGPREFIX, 0, OuterStride<> > lhs(_lhs,m,k,OuterStride<>(lhsStride)); \
+ a_tmp = lhs.conjugate(); \
+ a = a_tmp.data(); \
+ lda = a_tmp.outerStride(); \
+ } else a = _lhs; \
+\
+ if ((RhsStorageOrder==ColMajor) && (ConjugateRhs)) { \
+ Map<const MatrixX##EIGPREFIX, 0, OuterStride<> > rhs(_rhs,k,n,OuterStride<>(rhsStride)); \
+ b_tmp = rhs.conjugate(); \
+ b = b_tmp.data(); \
+ ldb = b_tmp.outerStride(); \
+ } else b = _rhs; \
+\
+ MKLPREFIX##gemm(&transa, &transb, &m, &n, &k, &alpha_, (const MKLTYPE*)a, &lda, (const MKLTYPE*)b, &ldb, &beta_, (MKLTYPE*)res, &ldc); \
+}};
+
+GEMM_SPECIALIZATION(double, d, double, d)
+GEMM_SPECIALIZATION(float, f, float, s)
+GEMM_SPECIALIZATION(dcomplex, cd, MKL_Complex16, z)
+GEMM_SPECIALIZATION(scomplex, cf, MKL_Complex8, c)
+
+} // end namespase internal
+
+} // end namespace Eigen
+
+#endif // EIGEN_GENERAL_MATRIX_MATRIX_MKL_H
diff --git a/Eigen/src/Core/products/GeneralMatrixVector.h b/Eigen/src/Core/products/GeneralMatrixVector.h
new file mode 100644
index 000000000..ba1f73957
--- /dev/null
+++ b/Eigen/src/Core/products/GeneralMatrixVector.h
@@ -0,0 +1,548 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra.
+//
+// Copyright (C) 2008-2009 Gael Guennebaud <gael.guennebaud@inria.fr>
+//
+// This Source Code Form is subject to the terms of the Mozilla
+// Public License v. 2.0. If a copy of the MPL was not distributed
+// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+#ifndef EIGEN_GENERAL_MATRIX_VECTOR_H
+#define EIGEN_GENERAL_MATRIX_VECTOR_H
+
+namespace Eigen {
+
+namespace internal {
+
+/* Optimized col-major matrix * vector product:
+ * This algorithm processes 4 columns at onces that allows to both reduce
+ * the number of load/stores of the result by a factor 4 and to reduce
+ * the instruction dependency. Moreover, we know that all bands have the
+ * same alignment pattern.
+ *
+ * Mixing type logic: C += alpha * A * B
+ * | A | B |alpha| comments
+ * |real |cplx |cplx | no vectorization
+ * |real |cplx |real | alpha is converted to a cplx when calling the run function, no vectorization
+ * |cplx |real |cplx | invalid, the caller has to do tmp: = A * B; C += alpha*tmp
+ * |cplx |real |real | optimal case, vectorization possible via real-cplx mul
+ */
+template<typename Index, typename LhsScalar, bool ConjugateLhs, typename RhsScalar, bool ConjugateRhs, int Version>
+struct general_matrix_vector_product<Index,LhsScalar,ColMajor,ConjugateLhs,RhsScalar,ConjugateRhs,Version>
+{
+typedef typename scalar_product_traits<LhsScalar, RhsScalar>::ReturnType ResScalar;
+
+enum {
+ Vectorizable = packet_traits<LhsScalar>::Vectorizable && packet_traits<RhsScalar>::Vectorizable
+ && int(packet_traits<LhsScalar>::size)==int(packet_traits<RhsScalar>::size),
+ LhsPacketSize = Vectorizable ? packet_traits<LhsScalar>::size : 1,
+ RhsPacketSize = Vectorizable ? packet_traits<RhsScalar>::size : 1,
+ ResPacketSize = Vectorizable ? packet_traits<ResScalar>::size : 1
+};
+
+typedef typename packet_traits<LhsScalar>::type _LhsPacket;
+typedef typename packet_traits<RhsScalar>::type _RhsPacket;
+typedef typename packet_traits<ResScalar>::type _ResPacket;
+
+typedef typename conditional<Vectorizable,_LhsPacket,LhsScalar>::type LhsPacket;
+typedef typename conditional<Vectorizable,_RhsPacket,RhsScalar>::type RhsPacket;
+typedef typename conditional<Vectorizable,_ResPacket,ResScalar>::type ResPacket;
+
+EIGEN_DONT_INLINE static void run(
+ Index rows, Index cols,
+ const LhsScalar* lhs, Index lhsStride,
+ const RhsScalar* rhs, Index rhsIncr,
+ ResScalar* res, Index
+ #ifdef EIGEN_INTERNAL_DEBUGGING
+ resIncr
+ #endif
+ , RhsScalar alpha)
+{
+ eigen_internal_assert(resIncr==1);
+ #ifdef _EIGEN_ACCUMULATE_PACKETS
+ #error _EIGEN_ACCUMULATE_PACKETS has already been defined
+ #endif
+ #define _EIGEN_ACCUMULATE_PACKETS(A0,A13,A2) \
+ pstore(&res[j], \
+ padd(pload<ResPacket>(&res[j]), \
+ padd( \
+ padd(pcj.pmul(EIGEN_CAT(ploa , A0)<LhsPacket>(&lhs0[j]), ptmp0), \
+ pcj.pmul(EIGEN_CAT(ploa , A13)<LhsPacket>(&lhs1[j]), ptmp1)), \
+ padd(pcj.pmul(EIGEN_CAT(ploa , A2)<LhsPacket>(&lhs2[j]), ptmp2), \
+ pcj.pmul(EIGEN_CAT(ploa , A13)<LhsPacket>(&lhs3[j]), ptmp3)) )))
+
+ conj_helper<LhsScalar,RhsScalar,ConjugateLhs,ConjugateRhs> cj;
+ conj_helper<LhsPacket,RhsPacket,ConjugateLhs,ConjugateRhs> pcj;
+ if(ConjugateRhs)
+ alpha = conj(alpha);
+
+ enum { AllAligned = 0, EvenAligned, FirstAligned, NoneAligned };
+ const Index columnsAtOnce = 4;
+ const Index peels = 2;
+ const Index LhsPacketAlignedMask = LhsPacketSize-1;
+ const Index ResPacketAlignedMask = ResPacketSize-1;
+ const Index PeelAlignedMask = ResPacketSize*peels-1;
+ const Index size = rows;
+
+ // How many coeffs of the result do we have to skip to be aligned.
+ // Here we assume data are at least aligned on the base scalar type.
+ Index alignedStart = internal::first_aligned(res,size);
+ Index alignedSize = ResPacketSize>1 ? alignedStart + ((size-alignedStart) & ~ResPacketAlignedMask) : 0;
+ const Index peeledSize = peels>1 ? alignedStart + ((alignedSize-alignedStart) & ~PeelAlignedMask) : alignedStart;
+
+ const Index alignmentStep = LhsPacketSize>1 ? (LhsPacketSize - lhsStride % LhsPacketSize) & LhsPacketAlignedMask : 0;
+ Index alignmentPattern = alignmentStep==0 ? AllAligned
+ : alignmentStep==(LhsPacketSize/2) ? EvenAligned
+ : FirstAligned;
+
+ // we cannot assume the first element is aligned because of sub-matrices
+ const Index lhsAlignmentOffset = internal::first_aligned(lhs,size);
+
+ // find how many columns do we have to skip to be aligned with the result (if possible)
+ Index skipColumns = 0;
+ // if the data cannot be aligned (TODO add some compile time tests when possible, e.g. for floats)
+ if( (size_t(lhs)%sizeof(LhsScalar)) || (size_t(res)%sizeof(ResScalar)) )
+ {
+ alignedSize = 0;
+ alignedStart = 0;
+ }
+ else if (LhsPacketSize>1)
+ {
+ eigen_internal_assert(size_t(lhs+lhsAlignmentOffset)%sizeof(LhsPacket)==0 || size<LhsPacketSize);
+
+ while (skipColumns<LhsPacketSize &&
+ alignedStart != ((lhsAlignmentOffset + alignmentStep*skipColumns)%LhsPacketSize))
+ ++skipColumns;
+ if (skipColumns==LhsPacketSize)
+ {
+ // nothing can be aligned, no need to skip any column
+ alignmentPattern = NoneAligned;
+ skipColumns = 0;
+ }
+ else
+ {
+ skipColumns = (std::min)(skipColumns,cols);
+ // note that the skiped columns are processed later.
+ }
+
+ eigen_internal_assert( (alignmentPattern==NoneAligned)
+ || (skipColumns + columnsAtOnce >= cols)
+ || LhsPacketSize > size
+ || (size_t(lhs+alignedStart+lhsStride*skipColumns)%sizeof(LhsPacket))==0);
+ }
+ else if(Vectorizable)
+ {
+ alignedStart = 0;
+ alignedSize = size;
+ alignmentPattern = AllAligned;
+ }
+
+ Index offset1 = (FirstAligned && alignmentStep==1?3:1);
+ Index offset3 = (FirstAligned && alignmentStep==1?1:3);
+
+ Index columnBound = ((cols-skipColumns)/columnsAtOnce)*columnsAtOnce + skipColumns;
+ for (Index i=skipColumns; i<columnBound; i+=columnsAtOnce)
+ {
+ RhsPacket ptmp0 = pset1<RhsPacket>(alpha*rhs[i*rhsIncr]),
+ ptmp1 = pset1<RhsPacket>(alpha*rhs[(i+offset1)*rhsIncr]),
+ ptmp2 = pset1<RhsPacket>(alpha*rhs[(i+2)*rhsIncr]),
+ ptmp3 = pset1<RhsPacket>(alpha*rhs[(i+offset3)*rhsIncr]);
+
+ // this helps a lot generating better binary code
+ const LhsScalar *lhs0 = lhs + i*lhsStride, *lhs1 = lhs + (i+offset1)*lhsStride,
+ *lhs2 = lhs + (i+2)*lhsStride, *lhs3 = lhs + (i+offset3)*lhsStride;
+
+ if (Vectorizable)
+ {
+ /* explicit vectorization */
+ // process initial unaligned coeffs
+ for (Index j=0; j<alignedStart; ++j)
+ {
+ res[j] = cj.pmadd(lhs0[j], pfirst(ptmp0), res[j]);
+ res[j] = cj.pmadd(lhs1[j], pfirst(ptmp1), res[j]);
+ res[j] = cj.pmadd(lhs2[j], pfirst(ptmp2), res[j]);
+ res[j] = cj.pmadd(lhs3[j], pfirst(ptmp3), res[j]);
+ }
+
+ if (alignedSize>alignedStart)
+ {
+ switch(alignmentPattern)
+ {
+ case AllAligned:
+ for (Index j = alignedStart; j<alignedSize; j+=ResPacketSize)
+ _EIGEN_ACCUMULATE_PACKETS(d,d,d);
+ break;
+ case EvenAligned:
+ for (Index j = alignedStart; j<alignedSize; j+=ResPacketSize)
+ _EIGEN_ACCUMULATE_PACKETS(d,du,d);
+ break;
+ case FirstAligned:
+ if(peels>1)
+ {
+ LhsPacket A00, A01, A02, A03, A10, A11, A12, A13;
+ ResPacket T0, T1;
+
+ A01 = pload<LhsPacket>(&lhs1[alignedStart-1]);
+ A02 = pload<LhsPacket>(&lhs2[alignedStart-2]);
+ A03 = pload<LhsPacket>(&lhs3[alignedStart-3]);
+
+ for (Index j = alignedStart; j<peeledSize; j+=peels*ResPacketSize)
+ {
+ A11 = pload<LhsPacket>(&lhs1[j-1+LhsPacketSize]); palign<1>(A01,A11);
+ A12 = pload<LhsPacket>(&lhs2[j-2+LhsPacketSize]); palign<2>(A02,A12);
+ A13 = pload<LhsPacket>(&lhs3[j-3+LhsPacketSize]); palign<3>(A03,A13);
+
+ A00 = pload<LhsPacket>(&lhs0[j]);
+ A10 = pload<LhsPacket>(&lhs0[j+LhsPacketSize]);
+ T0 = pcj.pmadd(A00, ptmp0, pload<ResPacket>(&res[j]));
+ T1 = pcj.pmadd(A10, ptmp0, pload<ResPacket>(&res[j+ResPacketSize]));
+
+ T0 = pcj.pmadd(A01, ptmp1, T0);
+ A01 = pload<LhsPacket>(&lhs1[j-1+2*LhsPacketSize]); palign<1>(A11,A01);
+ T0 = pcj.pmadd(A02, ptmp2, T0);
+ A02 = pload<LhsPacket>(&lhs2[j-2+2*LhsPacketSize]); palign<2>(A12,A02);
+ T0 = pcj.pmadd(A03, ptmp3, T0);
+ pstore(&res[j],T0);
+ A03 = pload<LhsPacket>(&lhs3[j-3+2*LhsPacketSize]); palign<3>(A13,A03);
+ T1 = pcj.pmadd(A11, ptmp1, T1);
+ T1 = pcj.pmadd(A12, ptmp2, T1);
+ T1 = pcj.pmadd(A13, ptmp3, T1);
+ pstore(&res[j+ResPacketSize],T1);
+ }
+ }
+ for (Index j = peeledSize; j<alignedSize; j+=ResPacketSize)
+ _EIGEN_ACCUMULATE_PACKETS(d,du,du);
+ break;
+ default:
+ for (Index j = alignedStart; j<alignedSize; j+=ResPacketSize)
+ _EIGEN_ACCUMULATE_PACKETS(du,du,du);
+ break;
+ }
+ }
+ } // end explicit vectorization
+
+ /* process remaining coeffs (or all if there is no explicit vectorization) */
+ for (Index j=alignedSize; j<size; ++j)
+ {
+ res[j] = cj.pmadd(lhs0[j], pfirst(ptmp0), res[j]);
+ res[j] = cj.pmadd(lhs1[j], pfirst(ptmp1), res[j]);
+ res[j] = cj.pmadd(lhs2[j], pfirst(ptmp2), res[j]);
+ res[j] = cj.pmadd(lhs3[j], pfirst(ptmp3), res[j]);
+ }
+ }
+
+ // process remaining first and last columns (at most columnsAtOnce-1)
+ Index end = cols;
+ Index start = columnBound;
+ do
+ {
+ for (Index k=start; k<end; ++k)
+ {
+ RhsPacket ptmp0 = pset1<RhsPacket>(alpha*rhs[k*rhsIncr]);
+ const LhsScalar* lhs0 = lhs + k*lhsStride;
+
+ if (Vectorizable)
+ {
+ /* explicit vectorization */
+ // process first unaligned result's coeffs
+ for (Index j=0; j<alignedStart; ++j)
+ res[j] += cj.pmul(lhs0[j], pfirst(ptmp0));
+ // process aligned result's coeffs
+ if ((size_t(lhs0+alignedStart)%sizeof(LhsPacket))==0)
+ for (Index i = alignedStart;i<alignedSize;i+=ResPacketSize)
+ pstore(&res[i], pcj.pmadd(ploadu<LhsPacket>(&lhs0[i]), ptmp0, pload<ResPacket>(&res[i])));
+ else
+ for (Index i = alignedStart;i<alignedSize;i+=ResPacketSize)
+ pstore(&res[i], pcj.pmadd(ploadu<LhsPacket>(&lhs0[i]), ptmp0, pload<ResPacket>(&res[i])));
+ }
+
+ // process remaining scalars (or all if no explicit vectorization)
+ for (Index i=alignedSize; i<size; ++i)
+ res[i] += cj.pmul(lhs0[i], pfirst(ptmp0));
+ }
+ if (skipColumns)
+ {
+ start = 0;
+ end = skipColumns;
+ skipColumns = 0;
+ }
+ else
+ break;
+ } while(Vectorizable);
+ #undef _EIGEN_ACCUMULATE_PACKETS
+}
+};
+
+/* Optimized row-major matrix * vector product:
+ * This algorithm processes 4 rows at onces that allows to both reduce
+ * the number of load/stores of the result by a factor 4 and to reduce
+ * the instruction dependency. Moreover, we know that all bands have the
+ * same alignment pattern.
+ *
+ * Mixing type logic:
+ * - alpha is always a complex (or converted to a complex)
+ * - no vectorization
+ */
+template<typename Index, typename LhsScalar, bool ConjugateLhs, typename RhsScalar, bool ConjugateRhs, int Version>
+struct general_matrix_vector_product<Index,LhsScalar,RowMajor,ConjugateLhs,RhsScalar,ConjugateRhs,Version>
+{
+typedef typename scalar_product_traits<LhsScalar, RhsScalar>::ReturnType ResScalar;
+
+enum {
+ Vectorizable = packet_traits<LhsScalar>::Vectorizable && packet_traits<RhsScalar>::Vectorizable
+ && int(packet_traits<LhsScalar>::size)==int(packet_traits<RhsScalar>::size),
+ LhsPacketSize = Vectorizable ? packet_traits<LhsScalar>::size : 1,
+ RhsPacketSize = Vectorizable ? packet_traits<RhsScalar>::size : 1,
+ ResPacketSize = Vectorizable ? packet_traits<ResScalar>::size : 1
+};
+
+typedef typename packet_traits<LhsScalar>::type _LhsPacket;
+typedef typename packet_traits<RhsScalar>::type _RhsPacket;
+typedef typename packet_traits<ResScalar>::type _ResPacket;
+
+typedef typename conditional<Vectorizable,_LhsPacket,LhsScalar>::type LhsPacket;
+typedef typename conditional<Vectorizable,_RhsPacket,RhsScalar>::type RhsPacket;
+typedef typename conditional<Vectorizable,_ResPacket,ResScalar>::type ResPacket;
+
+EIGEN_DONT_INLINE static void run(
+ Index rows, Index cols,
+ const LhsScalar* lhs, Index lhsStride,
+ const RhsScalar* rhs, Index rhsIncr,
+ ResScalar* res, Index resIncr,
+ ResScalar alpha)
+{
+ EIGEN_UNUSED_VARIABLE(rhsIncr);
+ eigen_internal_assert(rhsIncr==1);
+ #ifdef _EIGEN_ACCUMULATE_PACKETS
+ #error _EIGEN_ACCUMULATE_PACKETS has already been defined
+ #endif
+
+ #define _EIGEN_ACCUMULATE_PACKETS(A0,A13,A2) {\
+ RhsPacket b = pload<RhsPacket>(&rhs[j]); \
+ ptmp0 = pcj.pmadd(EIGEN_CAT(ploa,A0) <LhsPacket>(&lhs0[j]), b, ptmp0); \
+ ptmp1 = pcj.pmadd(EIGEN_CAT(ploa,A13)<LhsPacket>(&lhs1[j]), b, ptmp1); \
+ ptmp2 = pcj.pmadd(EIGEN_CAT(ploa,A2) <LhsPacket>(&lhs2[j]), b, ptmp2); \
+ ptmp3 = pcj.pmadd(EIGEN_CAT(ploa,A13)<LhsPacket>(&lhs3[j]), b, ptmp3); }
+
+ conj_helper<LhsScalar,RhsScalar,ConjugateLhs,ConjugateRhs> cj;
+ conj_helper<LhsPacket,RhsPacket,ConjugateLhs,ConjugateRhs> pcj;
+
+ enum { AllAligned=0, EvenAligned=1, FirstAligned=2, NoneAligned=3 };
+ const Index rowsAtOnce = 4;
+ const Index peels = 2;
+ const Index RhsPacketAlignedMask = RhsPacketSize-1;
+ const Index LhsPacketAlignedMask = LhsPacketSize-1;
+ const Index PeelAlignedMask = RhsPacketSize*peels-1;
+ const Index depth = cols;
+
+ // How many coeffs of the result do we have to skip to be aligned.
+ // Here we assume data are at least aligned on the base scalar type
+ // if that's not the case then vectorization is discarded, see below.
+ Index alignedStart = internal::first_aligned(rhs, depth);
+ Index alignedSize = RhsPacketSize>1 ? alignedStart + ((depth-alignedStart) & ~RhsPacketAlignedMask) : 0;
+ const Index peeledSize = peels>1 ? alignedStart + ((alignedSize-alignedStart) & ~PeelAlignedMask) : alignedStart;
+
+ const Index alignmentStep = LhsPacketSize>1 ? (LhsPacketSize - lhsStride % LhsPacketSize) & LhsPacketAlignedMask : 0;
+ Index alignmentPattern = alignmentStep==0 ? AllAligned
+ : alignmentStep==(LhsPacketSize/2) ? EvenAligned
+ : FirstAligned;
+
+ // we cannot assume the first element is aligned because of sub-matrices
+ const Index lhsAlignmentOffset = internal::first_aligned(lhs,depth);
+
+ // find how many rows do we have to skip to be aligned with rhs (if possible)
+ Index skipRows = 0;
+ // if the data cannot be aligned (TODO add some compile time tests when possible, e.g. for floats)
+ if( (sizeof(LhsScalar)!=sizeof(RhsScalar)) || (size_t(lhs)%sizeof(LhsScalar)) || (size_t(rhs)%sizeof(RhsScalar)) )
+ {
+ alignedSize = 0;
+ alignedStart = 0;
+ }
+ else if (LhsPacketSize>1)
+ {
+ eigen_internal_assert(size_t(lhs+lhsAlignmentOffset)%sizeof(LhsPacket)==0 || depth<LhsPacketSize);
+
+ while (skipRows<LhsPacketSize &&
+ alignedStart != ((lhsAlignmentOffset + alignmentStep*skipRows)%LhsPacketSize))
+ ++skipRows;
+ if (skipRows==LhsPacketSize)
+ {
+ // nothing can be aligned, no need to skip any column
+ alignmentPattern = NoneAligned;
+ skipRows = 0;
+ }
+ else
+ {
+ skipRows = (std::min)(skipRows,Index(rows));
+ // note that the skiped columns are processed later.
+ }
+ eigen_internal_assert( alignmentPattern==NoneAligned
+ || LhsPacketSize==1
+ || (skipRows + rowsAtOnce >= rows)
+ || LhsPacketSize > depth
+ || (size_t(lhs+alignedStart+lhsStride*skipRows)%sizeof(LhsPacket))==0);
+ }
+ else if(Vectorizable)
+ {
+ alignedStart = 0;
+ alignedSize = depth;
+ alignmentPattern = AllAligned;
+ }
+
+ Index offset1 = (FirstAligned && alignmentStep==1?3:1);
+ Index offset3 = (FirstAligned && alignmentStep==1?1:3);
+
+ Index rowBound = ((rows-skipRows)/rowsAtOnce)*rowsAtOnce + skipRows;
+ for (Index i=skipRows; i<rowBound; i+=rowsAtOnce)
+ {
+ EIGEN_ALIGN16 ResScalar tmp0 = ResScalar(0);
+ ResScalar tmp1 = ResScalar(0), tmp2 = ResScalar(0), tmp3 = ResScalar(0);
+
+ // this helps the compiler generating good binary code
+ const LhsScalar *lhs0 = lhs + i*lhsStride, *lhs1 = lhs + (i+offset1)*lhsStride,
+ *lhs2 = lhs + (i+2)*lhsStride, *lhs3 = lhs + (i+offset3)*lhsStride;
+
+ if (Vectorizable)
+ {
+ /* explicit vectorization */
+ ResPacket ptmp0 = pset1<ResPacket>(ResScalar(0)), ptmp1 = pset1<ResPacket>(ResScalar(0)),
+ ptmp2 = pset1<ResPacket>(ResScalar(0)), ptmp3 = pset1<ResPacket>(ResScalar(0));
+
+ // process initial unaligned coeffs
+ // FIXME this loop get vectorized by the compiler !
+ for (Index j=0; j<alignedStart; ++j)
+ {
+ RhsScalar b = rhs[j];
+ tmp0 += cj.pmul(lhs0[j],b); tmp1 += cj.pmul(lhs1[j],b);
+ tmp2 += cj.pmul(lhs2[j],b); tmp3 += cj.pmul(lhs3[j],b);
+ }
+
+ if (alignedSize>alignedStart)
+ {
+ switch(alignmentPattern)
+ {
+ case AllAligned:
+ for (Index j = alignedStart; j<alignedSize; j+=RhsPacketSize)
+ _EIGEN_ACCUMULATE_PACKETS(d,d,d);
+ break;
+ case EvenAligned:
+ for (Index j = alignedStart; j<alignedSize; j+=RhsPacketSize)
+ _EIGEN_ACCUMULATE_PACKETS(d,du,d);
+ break;
+ case FirstAligned:
+ if (peels>1)
+ {
+ /* Here we proccess 4 rows with with two peeled iterations to hide
+ * tghe overhead of unaligned loads. Moreover unaligned loads are handled
+ * using special shift/move operations between the two aligned packets
+ * overlaping the desired unaligned packet. This is *much* more efficient
+ * than basic unaligned loads.
+ */
+ LhsPacket A01, A02, A03, A11, A12, A13;
+ A01 = pload<LhsPacket>(&lhs1[alignedStart-1]);
+ A02 = pload<LhsPacket>(&lhs2[alignedStart-2]);
+ A03 = pload<LhsPacket>(&lhs3[alignedStart-3]);
+
+ for (Index j = alignedStart; j<peeledSize; j+=peels*RhsPacketSize)
+ {
+ RhsPacket b = pload<RhsPacket>(&rhs[j]);
+ A11 = pload<LhsPacket>(&lhs1[j-1+LhsPacketSize]); palign<1>(A01,A11);
+ A12 = pload<LhsPacket>(&lhs2[j-2+LhsPacketSize]); palign<2>(A02,A12);
+ A13 = pload<LhsPacket>(&lhs3[j-3+LhsPacketSize]); palign<3>(A03,A13);
+
+ ptmp0 = pcj.pmadd(pload<LhsPacket>(&lhs0[j]), b, ptmp0);
+ ptmp1 = pcj.pmadd(A01, b, ptmp1);
+ A01 = pload<LhsPacket>(&lhs1[j-1+2*LhsPacketSize]); palign<1>(A11,A01);
+ ptmp2 = pcj.pmadd(A02, b, ptmp2);
+ A02 = pload<LhsPacket>(&lhs2[j-2+2*LhsPacketSize]); palign<2>(A12,A02);
+ ptmp3 = pcj.pmadd(A03, b, ptmp3);
+ A03 = pload<LhsPacket>(&lhs3[j-3+2*LhsPacketSize]); palign<3>(A13,A03);
+
+ b = pload<RhsPacket>(&rhs[j+RhsPacketSize]);
+ ptmp0 = pcj.pmadd(pload<LhsPacket>(&lhs0[j+LhsPacketSize]), b, ptmp0);
+ ptmp1 = pcj.pmadd(A11, b, ptmp1);
+ ptmp2 = pcj.pmadd(A12, b, ptmp2);
+ ptmp3 = pcj.pmadd(A13, b, ptmp3);
+ }
+ }
+ for (Index j = peeledSize; j<alignedSize; j+=RhsPacketSize)
+ _EIGEN_ACCUMULATE_PACKETS(d,du,du);
+ break;
+ default:
+ for (Index j = alignedStart; j<alignedSize; j+=RhsPacketSize)
+ _EIGEN_ACCUMULATE_PACKETS(du,du,du);
+ break;
+ }
+ tmp0 += predux(ptmp0);
+ tmp1 += predux(ptmp1);
+ tmp2 += predux(ptmp2);
+ tmp3 += predux(ptmp3);
+ }
+ } // end explicit vectorization
+
+ // process remaining coeffs (or all if no explicit vectorization)
+ // FIXME this loop get vectorized by the compiler !
+ for (Index j=alignedSize; j<depth; ++j)
+ {
+ RhsScalar b = rhs[j];
+ tmp0 += cj.pmul(lhs0[j],b); tmp1 += cj.pmul(lhs1[j],b);
+ tmp2 += cj.pmul(lhs2[j],b); tmp3 += cj.pmul(lhs3[j],b);
+ }
+ res[i*resIncr] += alpha*tmp0;
+ res[(i+offset1)*resIncr] += alpha*tmp1;
+ res[(i+2)*resIncr] += alpha*tmp2;
+ res[(i+offset3)*resIncr] += alpha*tmp3;
+ }
+
+ // process remaining first and last rows (at most columnsAtOnce-1)
+ Index end = rows;
+ Index start = rowBound;
+ do
+ {
+ for (Index i=start; i<end; ++i)
+ {
+ EIGEN_ALIGN16 ResScalar tmp0 = ResScalar(0);
+ ResPacket ptmp0 = pset1<ResPacket>(tmp0);
+ const LhsScalar* lhs0 = lhs + i*lhsStride;
+ // process first unaligned result's coeffs
+ // FIXME this loop get vectorized by the compiler !
+ for (Index j=0; j<alignedStart; ++j)
+ tmp0 += cj.pmul(lhs0[j], rhs[j]);
+
+ if (alignedSize>alignedStart)
+ {
+ // process aligned rhs coeffs
+ if ((size_t(lhs0+alignedStart)%sizeof(LhsPacket))==0)
+ for (Index j = alignedStart;j<alignedSize;j+=RhsPacketSize)
+ ptmp0 = pcj.pmadd(pload<LhsPacket>(&lhs0[j]), pload<RhsPacket>(&rhs[j]), ptmp0);
+ else
+ for (Index j = alignedStart;j<alignedSize;j+=RhsPacketSize)
+ ptmp0 = pcj.pmadd(ploadu<LhsPacket>(&lhs0[j]), pload<RhsPacket>(&rhs[j]), ptmp0);
+ tmp0 += predux(ptmp0);
+ }
+
+ // process remaining scalars
+ // FIXME this loop get vectorized by the compiler !
+ for (Index j=alignedSize; j<depth; ++j)
+ tmp0 += cj.pmul(lhs0[j], rhs[j]);
+ res[i*resIncr] += alpha*tmp0;
+ }
+ if (skipRows)
+ {
+ start = 0;
+ end = skipRows;
+ skipRows = 0;
+ }
+ else
+ break;
+ } while(Vectorizable);
+
+ #undef _EIGEN_ACCUMULATE_PACKETS
+}
+};
+
+} // end namespace internal
+
+} // end namespace Eigen
+
+#endif // EIGEN_GENERAL_MATRIX_VECTOR_H
diff --git a/Eigen/src/Core/products/GeneralMatrixVector_MKL.h b/Eigen/src/Core/products/GeneralMatrixVector_MKL.h
new file mode 100644
index 000000000..e9de6af3e
--- /dev/null
+++ b/Eigen/src/Core/products/GeneralMatrixVector_MKL.h
@@ -0,0 +1,131 @@
+/*
+ Copyright (c) 2011, Intel Corporation. All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without modification,
+ are permitted provided that the following conditions are met:
+
+ * Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+ * Neither the name of Intel Corporation nor the names of its contributors may
+ be used to endorse or promote products derived from this software without
+ specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+ ********************************************************************************
+ * Content : Eigen bindings to Intel(R) MKL
+ * General matrix-vector product functionality based on ?GEMV.
+ ********************************************************************************
+*/
+
+#ifndef EIGEN_GENERAL_MATRIX_VECTOR_MKL_H
+#define EIGEN_GENERAL_MATRIX_VECTOR_MKL_H
+
+namespace Eigen {
+
+namespace internal {
+
+/**********************************************************************
+* This file implements general matrix-vector multiplication using BLAS
+* gemv function via partial specialization of
+* general_matrix_vector_product::run(..) method for float, double,
+* std::complex<float> and std::complex<double> types
+**********************************************************************/
+
+// gemv specialization
+
+template<typename Index, typename LhsScalar, int LhsStorageOrder, bool ConjugateLhs, typename RhsScalar, bool ConjugateRhs>
+struct general_matrix_vector_product_gemv :
+ general_matrix_vector_product<Index,LhsScalar,LhsStorageOrder,ConjugateLhs,RhsScalar,ConjugateRhs,BuiltIn> {};
+
+#define EIGEN_MKL_GEMV_SPECIALIZE(Scalar) \
+template<typename Index, bool ConjugateLhs, bool ConjugateRhs> \
+struct general_matrix_vector_product<Index,Scalar,ColMajor,ConjugateLhs,Scalar,ConjugateRhs,Specialized> { \
+static EIGEN_DONT_INLINE void run( \
+ Index rows, Index cols, \
+ const Scalar* lhs, Index lhsStride, \
+ const Scalar* rhs, Index rhsIncr, \
+ Scalar* res, Index resIncr, Scalar alpha) \
+{ \
+ if (ConjugateLhs) { \
+ general_matrix_vector_product<Index,Scalar,ColMajor,ConjugateLhs,Scalar,ConjugateRhs,BuiltIn>::run( \
+ rows, cols, lhs, lhsStride, rhs, rhsIncr, res, resIncr, alpha); \
+ } else { \
+ general_matrix_vector_product_gemv<Index,Scalar,ColMajor,ConjugateLhs,Scalar,ConjugateRhs>::run( \
+ rows, cols, lhs, lhsStride, rhs, rhsIncr, res, resIncr, alpha); \
+ } \
+} \
+}; \
+template<typename Index, bool ConjugateLhs, bool ConjugateRhs> \
+struct general_matrix_vector_product<Index,Scalar,RowMajor,ConjugateLhs,Scalar,ConjugateRhs,Specialized> { \
+static EIGEN_DONT_INLINE void run( \
+ Index rows, Index cols, \
+ const Scalar* lhs, Index lhsStride, \
+ const Scalar* rhs, Index rhsIncr, \
+ Scalar* res, Index resIncr, Scalar alpha) \
+{ \
+ general_matrix_vector_product_gemv<Index,Scalar,RowMajor,ConjugateLhs,Scalar,ConjugateRhs>::run( \
+ rows, cols, lhs, lhsStride, rhs, rhsIncr, res, resIncr, alpha); \
+} \
+}; \
+
+EIGEN_MKL_GEMV_SPECIALIZE(double)
+EIGEN_MKL_GEMV_SPECIALIZE(float)
+EIGEN_MKL_GEMV_SPECIALIZE(dcomplex)
+EIGEN_MKL_GEMV_SPECIALIZE(scomplex)
+
+#define EIGEN_MKL_GEMV_SPECIALIZATION(EIGTYPE,MKLTYPE,MKLPREFIX) \
+template<typename Index, int LhsStorageOrder, bool ConjugateLhs, bool ConjugateRhs> \
+struct general_matrix_vector_product_gemv<Index,EIGTYPE,LhsStorageOrder,ConjugateLhs,EIGTYPE,ConjugateRhs> \
+{ \
+typedef Matrix<EIGTYPE,Dynamic,1,ColMajor> GEMVVector;\
+\
+static EIGEN_DONT_INLINE void run( \
+ Index rows, Index cols, \
+ const EIGTYPE* lhs, Index lhsStride, \
+ const EIGTYPE* rhs, Index rhsIncr, \
+ EIGTYPE* res, Index resIncr, EIGTYPE alpha) \
+{ \
+ MKL_INT m=rows, n=cols, lda=lhsStride, incx=rhsIncr, incy=resIncr; \
+ MKLTYPE alpha_, beta_; \
+ const EIGTYPE *x_ptr, myone(1); \
+ char trans=(LhsStorageOrder==ColMajor) ? 'N' : (ConjugateLhs) ? 'C' : 'T'; \
+ if (LhsStorageOrder==RowMajor) { \
+ m=cols; \
+ n=rows; \
+ }\
+ assign_scalar_eig2mkl(alpha_, alpha); \
+ assign_scalar_eig2mkl(beta_, myone); \
+ GEMVVector x_tmp; \
+ if (ConjugateRhs) { \
+ Map<const GEMVVector, 0, InnerStride<> > map_x(rhs,cols,1,InnerStride<>(incx)); \
+ x_tmp=map_x.conjugate(); \
+ x_ptr=x_tmp.data(); \
+ incx=1; \
+ } else x_ptr=rhs; \
+ MKLPREFIX##gemv(&trans, &m, &n, &alpha_, (const MKLTYPE*)lhs, &lda, (const MKLTYPE*)x_ptr, &incx, &beta_, (MKLTYPE*)res, &incy); \
+}\
+};
+
+EIGEN_MKL_GEMV_SPECIALIZATION(double, double, d)
+EIGEN_MKL_GEMV_SPECIALIZATION(float, float, s)
+EIGEN_MKL_GEMV_SPECIALIZATION(dcomplex, MKL_Complex16, z)
+EIGEN_MKL_GEMV_SPECIALIZATION(scomplex, MKL_Complex8, c)
+
+} // end namespase internal
+
+} // end namespace Eigen
+
+#endif // EIGEN_GENERAL_MATRIX_VECTOR_MKL_H
diff --git a/Eigen/src/Core/products/Parallelizer.h b/Eigen/src/Core/products/Parallelizer.h
new file mode 100644
index 000000000..5c3e9b7ac
--- /dev/null
+++ b/Eigen/src/Core/products/Parallelizer.h
@@ -0,0 +1,159 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra.
+//
+// Copyright (C) 2010 Gael Guennebaud <gael.guennebaud@inria.fr>
+//
+// This Source Code Form is subject to the terms of the Mozilla
+// Public License v. 2.0. If a copy of the MPL was not distributed
+// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+#ifndef EIGEN_PARALLELIZER_H
+#define EIGEN_PARALLELIZER_H
+
+namespace Eigen {
+
+namespace internal {
+
+/** \internal */
+inline void manage_multi_threading(Action action, int* v)
+{
+ static EIGEN_UNUSED int m_maxThreads = -1;
+
+ if(action==SetAction)
+ {
+ eigen_internal_assert(v!=0);
+ m_maxThreads = *v;
+ }
+ else if(action==GetAction)
+ {
+ eigen_internal_assert(v!=0);
+ #ifdef EIGEN_HAS_OPENMP
+ if(m_maxThreads>0)
+ *v = m_maxThreads;
+ else
+ *v = omp_get_max_threads();
+ #else
+ *v = 1;
+ #endif
+ }
+ else
+ {
+ eigen_internal_assert(false);
+ }
+}
+
+}
+
+/** Must be call first when calling Eigen from multiple threads */
+inline void initParallel()
+{
+ int nbt;
+ internal::manage_multi_threading(GetAction, &nbt);
+ std::ptrdiff_t l1, l2;
+ internal::manage_caching_sizes(GetAction, &l1, &l2);
+}
+
+/** \returns the max number of threads reserved for Eigen
+ * \sa setNbThreads */
+inline int nbThreads()
+{
+ int ret;
+ internal::manage_multi_threading(GetAction, &ret);
+ return ret;
+}
+
+/** Sets the max number of threads reserved for Eigen
+ * \sa nbThreads */
+inline void setNbThreads(int v)
+{
+ internal::manage_multi_threading(SetAction, &v);
+}
+
+namespace internal {
+
+template<typename Index> struct GemmParallelInfo
+{
+ GemmParallelInfo() : sync(-1), users(0), rhs_start(0), rhs_length(0) {}
+
+ int volatile sync;
+ int volatile users;
+
+ Index rhs_start;
+ Index rhs_length;
+};
+
+template<bool Condition, typename Functor, typename Index>
+void parallelize_gemm(const Functor& func, Index rows, Index cols, bool transpose)
+{
+ // TODO when EIGEN_USE_BLAS is defined,
+ // we should still enable OMP for other scalar types
+#if !(defined (EIGEN_HAS_OPENMP)) || defined (EIGEN_USE_BLAS)
+ // FIXME the transpose variable is only needed to properly split
+ // the matrix product when multithreading is enabled. This is a temporary
+ // fix to support row-major destination matrices. This whole
+ // parallelizer mechanism has to be redisigned anyway.
+ EIGEN_UNUSED_VARIABLE(transpose);
+ func(0,rows, 0,cols);
+#else
+
+ // Dynamically check whether we should enable or disable OpenMP.
+ // The conditions are:
+ // - the max number of threads we can create is greater than 1
+ // - we are not already in a parallel code
+ // - the sizes are large enough
+
+ // 1- are we already in a parallel session?
+ // FIXME omp_get_num_threads()>1 only works for openmp, what if the user does not use openmp?
+ if((!Condition) || (omp_get_num_threads()>1))
+ return func(0,rows, 0,cols);
+
+ Index size = transpose ? cols : rows;
+
+ // 2- compute the maximal number of threads from the size of the product:
+ // FIXME this has to be fine tuned
+ Index max_threads = std::max<Index>(1,size / 32);
+
+ // 3 - compute the number of threads we are going to use
+ Index threads = std::min<Index>(nbThreads(), max_threads);
+
+ if(threads==1)
+ return func(0,rows, 0,cols);
+
+ Eigen::initParallel();
+ func.initParallelSession();
+
+ if(transpose)
+ std::swap(rows,cols);
+
+ Index blockCols = (cols / threads) & ~Index(0x3);
+ Index blockRows = (rows / threads) & ~Index(0x7);
+
+ GemmParallelInfo<Index>* info = new GemmParallelInfo<Index>[threads];
+
+ #pragma omp parallel for schedule(static,1) num_threads(threads)
+ for(Index i=0; i<threads; ++i)
+ {
+ Index r0 = i*blockRows;
+ Index actualBlockRows = (i+1==threads) ? rows-r0 : blockRows;
+
+ Index c0 = i*blockCols;
+ Index actualBlockCols = (i+1==threads) ? cols-c0 : blockCols;
+
+ info[i].rhs_start = c0;
+ info[i].rhs_length = actualBlockCols;
+
+ if(transpose)
+ func(0, cols, r0, actualBlockRows, info);
+ else
+ func(r0, actualBlockRows, 0,cols, info);
+ }
+
+ delete[] info;
+#endif
+}
+
+} // end namespace internal
+
+} // end namespace Eigen
+
+#endif // EIGEN_PARALLELIZER_H
diff --git a/Eigen/src/Core/products/SelfadjointMatrixMatrix.h b/Eigen/src/Core/products/SelfadjointMatrixMatrix.h
new file mode 100644
index 000000000..48209636e
--- /dev/null
+++ b/Eigen/src/Core/products/SelfadjointMatrixMatrix.h
@@ -0,0 +1,416 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra.
+//
+// Copyright (C) 2009 Gael Guennebaud <gael.guennebaud@inria.fr>
+//
+// This Source Code Form is subject to the terms of the Mozilla
+// Public License v. 2.0. If a copy of the MPL was not distributed
+// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+#ifndef EIGEN_SELFADJOINT_MATRIX_MATRIX_H
+#define EIGEN_SELFADJOINT_MATRIX_MATRIX_H
+
+namespace Eigen {
+
+namespace internal {
+
+// pack a selfadjoint block diagonal for use with the gebp_kernel
+template<typename Scalar, typename Index, int Pack1, int Pack2, int StorageOrder>
+struct symm_pack_lhs
+{
+ template<int BlockRows> inline
+ void pack(Scalar* blockA, const const_blas_data_mapper<Scalar,Index,StorageOrder>& lhs, Index cols, Index i, Index& count)
+ {
+ // normal copy
+ for(Index k=0; k<i; k++)
+ for(Index w=0; w<BlockRows; w++)
+ blockA[count++] = lhs(i+w,k); // normal
+ // symmetric copy
+ Index h = 0;
+ for(Index k=i; k<i+BlockRows; k++)
+ {
+ for(Index w=0; w<h; w++)
+ blockA[count++] = conj(lhs(k, i+w)); // transposed
+
+ blockA[count++] = real(lhs(k,k)); // real (diagonal)
+
+ for(Index w=h+1; w<BlockRows; w++)
+ blockA[count++] = lhs(i+w, k); // normal
+ ++h;
+ }
+ // transposed copy
+ for(Index k=i+BlockRows; k<cols; k++)
+ for(Index w=0; w<BlockRows; w++)
+ blockA[count++] = conj(lhs(k, i+w)); // transposed
+ }
+ void operator()(Scalar* blockA, const Scalar* _lhs, Index lhsStride, Index cols, Index rows)
+ {
+ const_blas_data_mapper<Scalar,Index,StorageOrder> lhs(_lhs,lhsStride);
+ Index count = 0;
+ Index peeled_mc = (rows/Pack1)*Pack1;
+ for(Index i=0; i<peeled_mc; i+=Pack1)
+ {
+ pack<Pack1>(blockA, lhs, cols, i, count);
+ }
+
+ if(rows-peeled_mc>=Pack2)
+ {
+ pack<Pack2>(blockA, lhs, cols, peeled_mc, count);
+ peeled_mc += Pack2;
+ }
+
+ // do the same with mr==1
+ for(Index i=peeled_mc; i<rows; i++)
+ {
+ for(Index k=0; k<i; k++)
+ blockA[count++] = lhs(i, k); // normal
+
+ blockA[count++] = real(lhs(i, i)); // real (diagonal)
+
+ for(Index k=i+1; k<cols; k++)
+ blockA[count++] = conj(lhs(k, i)); // transposed
+ }
+ }
+};
+
+template<typename Scalar, typename Index, int nr, int StorageOrder>
+struct symm_pack_rhs
+{
+ enum { PacketSize = packet_traits<Scalar>::size };
+ void operator()(Scalar* blockB, const Scalar* _rhs, Index rhsStride, Index rows, Index cols, Index k2)
+ {
+ Index end_k = k2 + rows;
+ Index count = 0;
+ const_blas_data_mapper<Scalar,Index,StorageOrder> rhs(_rhs,rhsStride);
+ Index packet_cols = (cols/nr)*nr;
+
+ // first part: normal case
+ for(Index j2=0; j2<k2; j2+=nr)
+ {
+ for(Index k=k2; k<end_k; k++)
+ {
+ blockB[count+0] = rhs(k,j2+0);
+ blockB[count+1] = rhs(k,j2+1);
+ if (nr==4)
+ {
+ blockB[count+2] = rhs(k,j2+2);
+ blockB[count+3] = rhs(k,j2+3);
+ }
+ count += nr;
+ }
+ }
+
+ // second part: diagonal block
+ for(Index j2=k2; j2<(std::min)(k2+rows,packet_cols); j2+=nr)
+ {
+ // again we can split vertically in three different parts (transpose, symmetric, normal)
+ // transpose
+ for(Index k=k2; k<j2; k++)
+ {
+ blockB[count+0] = conj(rhs(j2+0,k));
+ blockB[count+1] = conj(rhs(j2+1,k));
+ if (nr==4)
+ {
+ blockB[count+2] = conj(rhs(j2+2,k));
+ blockB[count+3] = conj(rhs(j2+3,k));
+ }
+ count += nr;
+ }
+ // symmetric
+ Index h = 0;
+ for(Index k=j2; k<j2+nr; k++)
+ {
+ // normal
+ for (Index w=0 ; w<h; ++w)
+ blockB[count+w] = rhs(k,j2+w);
+
+ blockB[count+h] = real(rhs(k,k));
+
+ // transpose
+ for (Index w=h+1 ; w<nr; ++w)
+ blockB[count+w] = conj(rhs(j2+w,k));
+ count += nr;
+ ++h;
+ }
+ // normal
+ for(Index k=j2+nr; k<end_k; k++)
+ {
+ blockB[count+0] = rhs(k,j2+0);
+ blockB[count+1] = rhs(k,j2+1);
+ if (nr==4)
+ {
+ blockB[count+2] = rhs(k,j2+2);
+ blockB[count+3] = rhs(k,j2+3);
+ }
+ count += nr;
+ }
+ }
+
+ // third part: transposed
+ for(Index j2=k2+rows; j2<packet_cols; j2+=nr)
+ {
+ for(Index k=k2; k<end_k; k++)
+ {
+ blockB[count+0] = conj(rhs(j2+0,k));
+ blockB[count+1] = conj(rhs(j2+1,k));
+ if (nr==4)
+ {
+ blockB[count+2] = conj(rhs(j2+2,k));
+ blockB[count+3] = conj(rhs(j2+3,k));
+ }
+ count += nr;
+ }
+ }
+
+ // copy the remaining columns one at a time (=> the same with nr==1)
+ for(Index j2=packet_cols; j2<cols; ++j2)
+ {
+ // transpose
+ Index half = (std::min)(end_k,j2);
+ for(Index k=k2; k<half; k++)
+ {
+ blockB[count] = conj(rhs(j2,k));
+ count += 1;
+ }
+
+ if(half==j2 && half<k2+rows)
+ {
+ blockB[count] = real(rhs(j2,j2));
+ count += 1;
+ }
+ else
+ half--;
+
+ // normal
+ for(Index k=half+1; k<k2+rows; k++)
+ {
+ blockB[count] = rhs(k,j2);
+ count += 1;
+ }
+ }
+ }
+};
+
+/* Optimized selfadjoint matrix * matrix (_SYMM) product built on top of
+ * the general matrix matrix product.
+ */
+template <typename Scalar, typename Index,
+ int LhsStorageOrder, bool LhsSelfAdjoint, bool ConjugateLhs,
+ int RhsStorageOrder, bool RhsSelfAdjoint, bool ConjugateRhs,
+ int ResStorageOrder>
+struct product_selfadjoint_matrix;
+
+template <typename Scalar, typename Index,
+ int LhsStorageOrder, bool LhsSelfAdjoint, bool ConjugateLhs,
+ int RhsStorageOrder, bool RhsSelfAdjoint, bool ConjugateRhs>
+struct product_selfadjoint_matrix<Scalar,Index,LhsStorageOrder,LhsSelfAdjoint,ConjugateLhs, RhsStorageOrder,RhsSelfAdjoint,ConjugateRhs,RowMajor>
+{
+
+ static EIGEN_STRONG_INLINE void run(
+ Index rows, Index cols,
+ const Scalar* lhs, Index lhsStride,
+ const Scalar* rhs, Index rhsStride,
+ Scalar* res, Index resStride,
+ Scalar alpha)
+ {
+ product_selfadjoint_matrix<Scalar, Index,
+ EIGEN_LOGICAL_XOR(RhsSelfAdjoint,RhsStorageOrder==RowMajor) ? ColMajor : RowMajor,
+ RhsSelfAdjoint, NumTraits<Scalar>::IsComplex && EIGEN_LOGICAL_XOR(RhsSelfAdjoint,ConjugateRhs),
+ EIGEN_LOGICAL_XOR(LhsSelfAdjoint,LhsStorageOrder==RowMajor) ? ColMajor : RowMajor,
+ LhsSelfAdjoint, NumTraits<Scalar>::IsComplex && EIGEN_LOGICAL_XOR(LhsSelfAdjoint,ConjugateLhs),
+ ColMajor>
+ ::run(cols, rows, rhs, rhsStride, lhs, lhsStride, res, resStride, alpha);
+ }
+};
+
+template <typename Scalar, typename Index,
+ int LhsStorageOrder, bool ConjugateLhs,
+ int RhsStorageOrder, bool ConjugateRhs>
+struct product_selfadjoint_matrix<Scalar,Index,LhsStorageOrder,true,ConjugateLhs, RhsStorageOrder,false,ConjugateRhs,ColMajor>
+{
+
+ static EIGEN_DONT_INLINE void run(
+ Index rows, Index cols,
+ const Scalar* _lhs, Index lhsStride,
+ const Scalar* _rhs, Index rhsStride,
+ Scalar* res, Index resStride,
+ Scalar alpha)
+ {
+ Index size = rows;
+
+ const_blas_data_mapper<Scalar, Index, LhsStorageOrder> lhs(_lhs,lhsStride);
+ const_blas_data_mapper<Scalar, Index, RhsStorageOrder> rhs(_rhs,rhsStride);
+
+ typedef gebp_traits<Scalar,Scalar> Traits;
+
+ Index kc = size; // cache block size along the K direction
+ Index mc = rows; // cache block size along the M direction
+ Index nc = cols; // cache block size along the N direction
+ computeProductBlockingSizes<Scalar,Scalar>(kc, mc, nc);
+ // kc must smaller than mc
+ kc = (std::min)(kc,mc);
+
+ std::size_t sizeW = kc*Traits::WorkSpaceFactor;
+ std::size_t sizeB = sizeW + kc*cols;
+ ei_declare_aligned_stack_constructed_variable(Scalar, blockA, kc*mc, 0);
+ ei_declare_aligned_stack_constructed_variable(Scalar, allocatedBlockB, sizeB, 0);
+ Scalar* blockB = allocatedBlockB + sizeW;
+
+ gebp_kernel<Scalar, Scalar, Index, Traits::mr, Traits::nr, ConjugateLhs, ConjugateRhs> gebp_kernel;
+ symm_pack_lhs<Scalar, Index, Traits::mr, Traits::LhsProgress, LhsStorageOrder> pack_lhs;
+ gemm_pack_rhs<Scalar, Index, Traits::nr,RhsStorageOrder> pack_rhs;
+ gemm_pack_lhs<Scalar, Index, Traits::mr, Traits::LhsProgress, LhsStorageOrder==RowMajor?ColMajor:RowMajor, true> pack_lhs_transposed;
+
+ for(Index k2=0; k2<size; k2+=kc)
+ {
+ const Index actual_kc = (std::min)(k2+kc,size)-k2;
+
+ // we have selected one row panel of rhs and one column panel of lhs
+ // pack rhs's panel into a sequential chunk of memory
+ // and expand each coeff to a constant packet for further reuse
+ pack_rhs(blockB, &rhs(k2,0), rhsStride, actual_kc, cols);
+
+ // the select lhs's panel has to be split in three different parts:
+ // 1 - the transposed panel above the diagonal block => transposed packed copy
+ // 2 - the diagonal block => special packed copy
+ // 3 - the panel below the diagonal block => generic packed copy
+ for(Index i2=0; i2<k2; i2+=mc)
+ {
+ const Index actual_mc = (std::min)(i2+mc,k2)-i2;
+ // transposed packed copy
+ pack_lhs_transposed(blockA, &lhs(k2, i2), lhsStride, actual_kc, actual_mc);
+
+ gebp_kernel(res+i2, resStride, blockA, blockB, actual_mc, actual_kc, cols, alpha);
+ }
+ // the block diagonal
+ {
+ const Index actual_mc = (std::min)(k2+kc,size)-k2;
+ // symmetric packed copy
+ pack_lhs(blockA, &lhs(k2,k2), lhsStride, actual_kc, actual_mc);
+
+ gebp_kernel(res+k2, resStride, blockA, blockB, actual_mc, actual_kc, cols, alpha);
+ }
+
+ for(Index i2=k2+kc; i2<size; i2+=mc)
+ {
+ const Index actual_mc = (std::min)(i2+mc,size)-i2;
+ gemm_pack_lhs<Scalar, Index, Traits::mr, Traits::LhsProgress, LhsStorageOrder,false>()
+ (blockA, &lhs(i2, k2), lhsStride, actual_kc, actual_mc);
+
+ gebp_kernel(res+i2, resStride, blockA, blockB, actual_mc, actual_kc, cols, alpha);
+ }
+ }
+ }
+};
+
+// matrix * selfadjoint product
+template <typename Scalar, typename Index,
+ int LhsStorageOrder, bool ConjugateLhs,
+ int RhsStorageOrder, bool ConjugateRhs>
+struct product_selfadjoint_matrix<Scalar,Index,LhsStorageOrder,false,ConjugateLhs, RhsStorageOrder,true,ConjugateRhs,ColMajor>
+{
+
+ static EIGEN_DONT_INLINE void run(
+ Index rows, Index cols,
+ const Scalar* _lhs, Index lhsStride,
+ const Scalar* _rhs, Index rhsStride,
+ Scalar* res, Index resStride,
+ Scalar alpha)
+ {
+ Index size = cols;
+
+ const_blas_data_mapper<Scalar, Index, LhsStorageOrder> lhs(_lhs,lhsStride);
+
+ typedef gebp_traits<Scalar,Scalar> Traits;
+
+ Index kc = size; // cache block size along the K direction
+ Index mc = rows; // cache block size along the M direction
+ Index nc = cols; // cache block size along the N direction
+ computeProductBlockingSizes<Scalar,Scalar>(kc, mc, nc);
+ std::size_t sizeW = kc*Traits::WorkSpaceFactor;
+ std::size_t sizeB = sizeW + kc*cols;
+ ei_declare_aligned_stack_constructed_variable(Scalar, blockA, kc*mc, 0);
+ ei_declare_aligned_stack_constructed_variable(Scalar, allocatedBlockB, sizeB, 0);
+ Scalar* blockB = allocatedBlockB + sizeW;
+
+ gebp_kernel<Scalar, Scalar, Index, Traits::mr, Traits::nr, ConjugateLhs, ConjugateRhs> gebp_kernel;
+ gemm_pack_lhs<Scalar, Index, Traits::mr, Traits::LhsProgress, LhsStorageOrder> pack_lhs;
+ symm_pack_rhs<Scalar, Index, Traits::nr,RhsStorageOrder> pack_rhs;
+
+ for(Index k2=0; k2<size; k2+=kc)
+ {
+ const Index actual_kc = (std::min)(k2+kc,size)-k2;
+
+ pack_rhs(blockB, _rhs, rhsStride, actual_kc, cols, k2);
+
+ // => GEPP
+ for(Index i2=0; i2<rows; i2+=mc)
+ {
+ const Index actual_mc = (std::min)(i2+mc,rows)-i2;
+ pack_lhs(blockA, &lhs(i2, k2), lhsStride, actual_kc, actual_mc);
+
+ gebp_kernel(res+i2, resStride, blockA, blockB, actual_mc, actual_kc, cols, alpha);
+ }
+ }
+ }
+};
+
+} // end namespace internal
+
+/***************************************************************************
+* Wrapper to product_selfadjoint_matrix
+***************************************************************************/
+
+namespace internal {
+template<typename Lhs, int LhsMode, typename Rhs, int RhsMode>
+struct traits<SelfadjointProductMatrix<Lhs,LhsMode,false,Rhs,RhsMode,false> >
+ : traits<ProductBase<SelfadjointProductMatrix<Lhs,LhsMode,false,Rhs,RhsMode,false>, Lhs, Rhs> >
+{};
+}
+
+template<typename Lhs, int LhsMode, typename Rhs, int RhsMode>
+struct SelfadjointProductMatrix<Lhs,LhsMode,false,Rhs,RhsMode,false>
+ : public ProductBase<SelfadjointProductMatrix<Lhs,LhsMode,false,Rhs,RhsMode,false>, Lhs, Rhs >
+{
+ EIGEN_PRODUCT_PUBLIC_INTERFACE(SelfadjointProductMatrix)
+
+ SelfadjointProductMatrix(const Lhs& lhs, const Rhs& rhs) : Base(lhs,rhs) {}
+
+ enum {
+ LhsIsUpper = (LhsMode&(Upper|Lower))==Upper,
+ LhsIsSelfAdjoint = (LhsMode&SelfAdjoint)==SelfAdjoint,
+ RhsIsUpper = (RhsMode&(Upper|Lower))==Upper,
+ RhsIsSelfAdjoint = (RhsMode&SelfAdjoint)==SelfAdjoint
+ };
+
+ template<typename Dest> void scaleAndAddTo(Dest& dst, Scalar alpha) const
+ {
+ eigen_assert(dst.rows()==m_lhs.rows() && dst.cols()==m_rhs.cols());
+
+ typename internal::add_const_on_value_type<ActualLhsType>::type lhs = LhsBlasTraits::extract(m_lhs);
+ typename internal::add_const_on_value_type<ActualRhsType>::type rhs = RhsBlasTraits::extract(m_rhs);
+
+ Scalar actualAlpha = alpha * LhsBlasTraits::extractScalarFactor(m_lhs)
+ * RhsBlasTraits::extractScalarFactor(m_rhs);
+
+ internal::product_selfadjoint_matrix<Scalar, Index,
+ EIGEN_LOGICAL_XOR(LhsIsUpper,
+ internal::traits<Lhs>::Flags &RowMajorBit) ? RowMajor : ColMajor, LhsIsSelfAdjoint,
+ NumTraits<Scalar>::IsComplex && EIGEN_LOGICAL_XOR(LhsIsUpper,bool(LhsBlasTraits::NeedToConjugate)),
+ EIGEN_LOGICAL_XOR(RhsIsUpper,
+ internal::traits<Rhs>::Flags &RowMajorBit) ? RowMajor : ColMajor, RhsIsSelfAdjoint,
+ NumTraits<Scalar>::IsComplex && EIGEN_LOGICAL_XOR(RhsIsUpper,bool(RhsBlasTraits::NeedToConjugate)),
+ internal::traits<Dest>::Flags&RowMajorBit ? RowMajor : ColMajor>
+ ::run(
+ lhs.rows(), rhs.cols(), // sizes
+ &lhs.coeffRef(0,0), lhs.outerStride(), // lhs info
+ &rhs.coeffRef(0,0), rhs.outerStride(), // rhs info
+ &dst.coeffRef(0,0), dst.outerStride(), // result info
+ actualAlpha // alpha
+ );
+ }
+};
+
+} // end namespace Eigen
+
+#endif // EIGEN_SELFADJOINT_MATRIX_MATRIX_H
diff --git a/Eigen/src/Core/products/SelfadjointMatrixMatrix_MKL.h b/Eigen/src/Core/products/SelfadjointMatrixMatrix_MKL.h
new file mode 100644
index 000000000..4e5c4125c
--- /dev/null
+++ b/Eigen/src/Core/products/SelfadjointMatrixMatrix_MKL.h
@@ -0,0 +1,295 @@
+/*
+ Copyright (c) 2011, Intel Corporation. All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without modification,
+ are permitted provided that the following conditions are met:
+
+ * Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+ * Neither the name of Intel Corporation nor the names of its contributors may
+ be used to endorse or promote products derived from this software without
+ specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+ ********************************************************************************
+ * Content : Eigen bindings to Intel(R) MKL
+ * Self adjoint matrix * matrix product functionality based on ?SYMM/?HEMM.
+ ********************************************************************************
+*/
+
+#ifndef EIGEN_SELFADJOINT_MATRIX_MATRIX_MKL_H
+#define EIGEN_SELFADJOINT_MATRIX_MATRIX_MKL_H
+
+namespace Eigen {
+
+namespace internal {
+
+
+/* Optimized selfadjoint matrix * matrix (?SYMM/?HEMM) product */
+
+#define EIGEN_MKL_SYMM_L(EIGTYPE, MKLTYPE, EIGPREFIX, MKLPREFIX) \
+template <typename Index, \
+ int LhsStorageOrder, bool ConjugateLhs, \
+ int RhsStorageOrder, bool ConjugateRhs> \
+struct product_selfadjoint_matrix<EIGTYPE,Index,LhsStorageOrder,true,ConjugateLhs,RhsStorageOrder,false,ConjugateRhs,ColMajor> \
+{\
+\
+ static EIGEN_DONT_INLINE void run( \
+ Index rows, Index cols, \
+ const EIGTYPE* _lhs, Index lhsStride, \
+ const EIGTYPE* _rhs, Index rhsStride, \
+ EIGTYPE* res, Index resStride, \
+ EIGTYPE alpha) \
+ { \
+ char side='L', uplo='L'; \
+ MKL_INT m, n, lda, ldb, ldc; \
+ const EIGTYPE *a, *b; \
+ MKLTYPE alpha_, beta_; \
+ MatrixX##EIGPREFIX b_tmp; \
+ EIGTYPE myone(1);\
+\
+/* Set transpose options */ \
+/* Set m, n, k */ \
+ m = (MKL_INT)rows; \
+ n = (MKL_INT)cols; \
+\
+/* Set alpha_ & beta_ */ \
+ assign_scalar_eig2mkl(alpha_, alpha); \
+ assign_scalar_eig2mkl(beta_, myone); \
+\
+/* Set lda, ldb, ldc */ \
+ lda = (MKL_INT)lhsStride; \
+ ldb = (MKL_INT)rhsStride; \
+ ldc = (MKL_INT)resStride; \
+\
+/* Set a, b, c */ \
+ if (LhsStorageOrder==RowMajor) uplo='U'; \
+ a = _lhs; \
+\
+ if (RhsStorageOrder==RowMajor) { \
+ Map<const MatrixX##EIGPREFIX, 0, OuterStride<> > rhs(_rhs,n,m,OuterStride<>(rhsStride)); \
+ b_tmp = rhs.adjoint(); \
+ b = b_tmp.data(); \
+ ldb = b_tmp.outerStride(); \
+ } else b = _rhs; \
+\
+ MKLPREFIX##symm(&side, &uplo, &m, &n, &alpha_, (const MKLTYPE*)a, &lda, (const MKLTYPE*)b, &ldb, &beta_, (MKLTYPE*)res, &ldc); \
+\
+ } \
+};
+
+
+#define EIGEN_MKL_HEMM_L(EIGTYPE, MKLTYPE, EIGPREFIX, MKLPREFIX) \
+template <typename Index, \
+ int LhsStorageOrder, bool ConjugateLhs, \
+ int RhsStorageOrder, bool ConjugateRhs> \
+struct product_selfadjoint_matrix<EIGTYPE,Index,LhsStorageOrder,true,ConjugateLhs,RhsStorageOrder,false,ConjugateRhs,ColMajor> \
+{\
+ static EIGEN_DONT_INLINE void run( \
+ Index rows, Index cols, \
+ const EIGTYPE* _lhs, Index lhsStride, \
+ const EIGTYPE* _rhs, Index rhsStride, \
+ EIGTYPE* res, Index resStride, \
+ EIGTYPE alpha) \
+ { \
+ char side='L', uplo='L'; \
+ MKL_INT m, n, lda, ldb, ldc; \
+ const EIGTYPE *a, *b; \
+ MKLTYPE alpha_, beta_; \
+ MatrixX##EIGPREFIX b_tmp; \
+ Matrix<EIGTYPE, Dynamic, Dynamic, LhsStorageOrder> a_tmp; \
+ EIGTYPE myone(1); \
+\
+/* Set transpose options */ \
+/* Set m, n, k */ \
+ m = (MKL_INT)rows; \
+ n = (MKL_INT)cols; \
+\
+/* Set alpha_ & beta_ */ \
+ assign_scalar_eig2mkl(alpha_, alpha); \
+ assign_scalar_eig2mkl(beta_, myone); \
+\
+/* Set lda, ldb, ldc */ \
+ lda = (MKL_INT)lhsStride; \
+ ldb = (MKL_INT)rhsStride; \
+ ldc = (MKL_INT)resStride; \
+\
+/* Set a, b, c */ \
+ if (((LhsStorageOrder==ColMajor) && ConjugateLhs) || ((LhsStorageOrder==RowMajor) && (!ConjugateLhs))) { \
+ Map<const Matrix<EIGTYPE, Dynamic, Dynamic, LhsStorageOrder>, 0, OuterStride<> > lhs(_lhs,m,m,OuterStride<>(lhsStride)); \
+ a_tmp = lhs.conjugate(); \
+ a = a_tmp.data(); \
+ lda = a_tmp.outerStride(); \
+ } else a = _lhs; \
+ if (LhsStorageOrder==RowMajor) uplo='U'; \
+\
+ if (RhsStorageOrder==ColMajor && (!ConjugateRhs)) { \
+ b = _rhs; } \
+ else { \
+ if (RhsStorageOrder==ColMajor && ConjugateRhs) { \
+ Map<const MatrixX##EIGPREFIX, 0, OuterStride<> > rhs(_rhs,m,n,OuterStride<>(rhsStride)); \
+ b_tmp = rhs.conjugate(); \
+ } else \
+ if (ConjugateRhs) { \
+ Map<const MatrixX##EIGPREFIX, 0, OuterStride<> > rhs(_rhs,n,m,OuterStride<>(rhsStride)); \
+ b_tmp = rhs.adjoint(); \
+ } else { \
+ Map<const MatrixX##EIGPREFIX, 0, OuterStride<> > rhs(_rhs,n,m,OuterStride<>(rhsStride)); \
+ b_tmp = rhs.transpose(); \
+ } \
+ b = b_tmp.data(); \
+ ldb = b_tmp.outerStride(); \
+ } \
+\
+ MKLPREFIX##hemm(&side, &uplo, &m, &n, &alpha_, (const MKLTYPE*)a, &lda, (const MKLTYPE*)b, &ldb, &beta_, (MKLTYPE*)res, &ldc); \
+\
+ } \
+};
+
+EIGEN_MKL_SYMM_L(double, double, d, d)
+EIGEN_MKL_SYMM_L(float, float, f, s)
+EIGEN_MKL_HEMM_L(dcomplex, MKL_Complex16, cd, z)
+EIGEN_MKL_HEMM_L(scomplex, MKL_Complex8, cf, c)
+
+
+/* Optimized matrix * selfadjoint matrix (?SYMM/?HEMM) product */
+
+#define EIGEN_MKL_SYMM_R(EIGTYPE, MKLTYPE, EIGPREFIX, MKLPREFIX) \
+template <typename Index, \
+ int LhsStorageOrder, bool ConjugateLhs, \
+ int RhsStorageOrder, bool ConjugateRhs> \
+struct product_selfadjoint_matrix<EIGTYPE,Index,LhsStorageOrder,false,ConjugateLhs,RhsStorageOrder,true,ConjugateRhs,ColMajor> \
+{\
+\
+ static EIGEN_DONT_INLINE void run( \
+ Index rows, Index cols, \
+ const EIGTYPE* _lhs, Index lhsStride, \
+ const EIGTYPE* _rhs, Index rhsStride, \
+ EIGTYPE* res, Index resStride, \
+ EIGTYPE alpha) \
+ { \
+ char side='R', uplo='L'; \
+ MKL_INT m, n, lda, ldb, ldc; \
+ const EIGTYPE *a, *b; \
+ MKLTYPE alpha_, beta_; \
+ MatrixX##EIGPREFIX b_tmp; \
+ EIGTYPE myone(1);\
+\
+/* Set m, n, k */ \
+ m = (MKL_INT)rows; \
+ n = (MKL_INT)cols; \
+\
+/* Set alpha_ & beta_ */ \
+ assign_scalar_eig2mkl(alpha_, alpha); \
+ assign_scalar_eig2mkl(beta_, myone); \
+\
+/* Set lda, ldb, ldc */ \
+ lda = (MKL_INT)rhsStride; \
+ ldb = (MKL_INT)lhsStride; \
+ ldc = (MKL_INT)resStride; \
+\
+/* Set a, b, c */ \
+ if (RhsStorageOrder==RowMajor) uplo='U'; \
+ a = _rhs; \
+\
+ if (LhsStorageOrder==RowMajor) { \
+ Map<const MatrixX##EIGPREFIX, 0, OuterStride<> > lhs(_lhs,n,m,OuterStride<>(rhsStride)); \
+ b_tmp = lhs.adjoint(); \
+ b = b_tmp.data(); \
+ ldb = b_tmp.outerStride(); \
+ } else b = _lhs; \
+\
+ MKLPREFIX##symm(&side, &uplo, &m, &n, &alpha_, (const MKLTYPE*)a, &lda, (const MKLTYPE*)b, &ldb, &beta_, (MKLTYPE*)res, &ldc); \
+\
+ } \
+};
+
+
+#define EIGEN_MKL_HEMM_R(EIGTYPE, MKLTYPE, EIGPREFIX, MKLPREFIX) \
+template <typename Index, \
+ int LhsStorageOrder, bool ConjugateLhs, \
+ int RhsStorageOrder, bool ConjugateRhs> \
+struct product_selfadjoint_matrix<EIGTYPE,Index,LhsStorageOrder,false,ConjugateLhs,RhsStorageOrder,true,ConjugateRhs,ColMajor> \
+{\
+ static EIGEN_DONT_INLINE void run( \
+ Index rows, Index cols, \
+ const EIGTYPE* _lhs, Index lhsStride, \
+ const EIGTYPE* _rhs, Index rhsStride, \
+ EIGTYPE* res, Index resStride, \
+ EIGTYPE alpha) \
+ { \
+ char side='R', uplo='L'; \
+ MKL_INT m, n, lda, ldb, ldc; \
+ const EIGTYPE *a, *b; \
+ MKLTYPE alpha_, beta_; \
+ MatrixX##EIGPREFIX b_tmp; \
+ Matrix<EIGTYPE, Dynamic, Dynamic, RhsStorageOrder> a_tmp; \
+ EIGTYPE myone(1); \
+\
+/* Set m, n, k */ \
+ m = (MKL_INT)rows; \
+ n = (MKL_INT)cols; \
+\
+/* Set alpha_ & beta_ */ \
+ assign_scalar_eig2mkl(alpha_, alpha); \
+ assign_scalar_eig2mkl(beta_, myone); \
+\
+/* Set lda, ldb, ldc */ \
+ lda = (MKL_INT)rhsStride; \
+ ldb = (MKL_INT)lhsStride; \
+ ldc = (MKL_INT)resStride; \
+\
+/* Set a, b, c */ \
+ if (((RhsStorageOrder==ColMajor) && ConjugateRhs) || ((RhsStorageOrder==RowMajor) && (!ConjugateRhs))) { \
+ Map<const Matrix<EIGTYPE, Dynamic, Dynamic, RhsStorageOrder>, 0, OuterStride<> > rhs(_rhs,n,n,OuterStride<>(rhsStride)); \
+ a_tmp = rhs.conjugate(); \
+ a = a_tmp.data(); \
+ lda = a_tmp.outerStride(); \
+ } else a = _rhs; \
+ if (RhsStorageOrder==RowMajor) uplo='U'; \
+\
+ if (LhsStorageOrder==ColMajor && (!ConjugateLhs)) { \
+ b = _lhs; } \
+ else { \
+ if (LhsStorageOrder==ColMajor && ConjugateLhs) { \
+ Map<const MatrixX##EIGPREFIX, 0, OuterStride<> > lhs(_lhs,m,n,OuterStride<>(lhsStride)); \
+ b_tmp = lhs.conjugate(); \
+ } else \
+ if (ConjugateLhs) { \
+ Map<const MatrixX##EIGPREFIX, 0, OuterStride<> > lhs(_lhs,n,m,OuterStride<>(lhsStride)); \
+ b_tmp = lhs.adjoint(); \
+ } else { \
+ Map<const MatrixX##EIGPREFIX, 0, OuterStride<> > lhs(_lhs,n,m,OuterStride<>(lhsStride)); \
+ b_tmp = lhs.transpose(); \
+ } \
+ b = b_tmp.data(); \
+ ldb = b_tmp.outerStride(); \
+ } \
+\
+ MKLPREFIX##hemm(&side, &uplo, &m, &n, &alpha_, (const MKLTYPE*)a, &lda, (const MKLTYPE*)b, &ldb, &beta_, (MKLTYPE*)res, &ldc); \
+ } \
+};
+
+EIGEN_MKL_SYMM_R(double, double, d, d)
+EIGEN_MKL_SYMM_R(float, float, f, s)
+EIGEN_MKL_HEMM_R(dcomplex, MKL_Complex16, cd, z)
+EIGEN_MKL_HEMM_R(scomplex, MKL_Complex8, cf, c)
+
+} // end namespace internal
+
+} // end namespace Eigen
+
+#endif // EIGEN_SELFADJOINT_MATRIX_MATRIX_MKL_H
diff --git a/Eigen/src/Core/products/SelfadjointMatrixVector.h b/Eigen/src/Core/products/SelfadjointMatrixVector.h
new file mode 100644
index 000000000..c3145c69a
--- /dev/null
+++ b/Eigen/src/Core/products/SelfadjointMatrixVector.h
@@ -0,0 +1,274 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra.
+//
+// Copyright (C) 2008-2009 Gael Guennebaud <gael.guennebaud@inria.fr>
+//
+// This Source Code Form is subject to the terms of the Mozilla
+// Public License v. 2.0. If a copy of the MPL was not distributed
+// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+#ifndef EIGEN_SELFADJOINT_MATRIX_VECTOR_H
+#define EIGEN_SELFADJOINT_MATRIX_VECTOR_H
+
+namespace Eigen {
+
+namespace internal {
+
+/* Optimized selfadjoint matrix * vector product:
+ * This algorithm processes 2 columns at onces that allows to both reduce
+ * the number of load/stores of the result by a factor 2 and to reduce
+ * the instruction dependency.
+ */
+
+template<typename Scalar, typename Index, int StorageOrder, int UpLo, bool ConjugateLhs, bool ConjugateRhs, int Version=Specialized>
+struct selfadjoint_matrix_vector_product;
+
+template<typename Scalar, typename Index, int StorageOrder, int UpLo, bool ConjugateLhs, bool ConjugateRhs, int Version>
+struct selfadjoint_matrix_vector_product
+
+{
+static EIGEN_DONT_INLINE void run(
+ Index size,
+ const Scalar* lhs, Index lhsStride,
+ const Scalar* _rhs, Index rhsIncr,
+ Scalar* res,
+ Scalar alpha)
+{
+ typedef typename packet_traits<Scalar>::type Packet;
+ typedef typename NumTraits<Scalar>::Real RealScalar;
+ const Index PacketSize = sizeof(Packet)/sizeof(Scalar);
+
+ enum {
+ IsRowMajor = StorageOrder==RowMajor ? 1 : 0,
+ IsLower = UpLo == Lower ? 1 : 0,
+ FirstTriangular = IsRowMajor == IsLower
+ };
+
+ conj_helper<Scalar,Scalar,NumTraits<Scalar>::IsComplex && EIGEN_LOGICAL_XOR(ConjugateLhs, IsRowMajor), ConjugateRhs> cj0;
+ conj_helper<Scalar,Scalar,NumTraits<Scalar>::IsComplex && EIGEN_LOGICAL_XOR(ConjugateLhs, !IsRowMajor), ConjugateRhs> cj1;
+ conj_helper<Scalar,Scalar,NumTraits<Scalar>::IsComplex, ConjugateRhs> cjd;
+
+ conj_helper<Packet,Packet,NumTraits<Scalar>::IsComplex && EIGEN_LOGICAL_XOR(ConjugateLhs, IsRowMajor), ConjugateRhs> pcj0;
+ conj_helper<Packet,Packet,NumTraits<Scalar>::IsComplex && EIGEN_LOGICAL_XOR(ConjugateLhs, !IsRowMajor), ConjugateRhs> pcj1;
+
+ Scalar cjAlpha = ConjugateRhs ? conj(alpha) : alpha;
+
+ // FIXME this copy is now handled outside product_selfadjoint_vector, so it could probably be removed.
+ // if the rhs is not sequentially stored in memory we copy it to a temporary buffer,
+ // this is because we need to extract packets
+ ei_declare_aligned_stack_constructed_variable(Scalar,rhs,size,rhsIncr==1 ? const_cast<Scalar*>(_rhs) : 0);
+ if (rhsIncr!=1)
+ {
+ const Scalar* it = _rhs;
+ for (Index i=0; i<size; ++i, it+=rhsIncr)
+ rhs[i] = *it;
+ }
+
+ Index bound = (std::max)(Index(0),size-8) & 0xfffffffe;
+ if (FirstTriangular)
+ bound = size - bound;
+
+ for (Index j=FirstTriangular ? bound : 0;
+ j<(FirstTriangular ? size : bound);j+=2)
+ {
+ register const Scalar* EIGEN_RESTRICT A0 = lhs + j*lhsStride;
+ register const Scalar* EIGEN_RESTRICT A1 = lhs + (j+1)*lhsStride;
+
+ Scalar t0 = cjAlpha * rhs[j];
+ Packet ptmp0 = pset1<Packet>(t0);
+ Scalar t1 = cjAlpha * rhs[j+1];
+ Packet ptmp1 = pset1<Packet>(t1);
+
+ Scalar t2(0);
+ Packet ptmp2 = pset1<Packet>(t2);
+ Scalar t3(0);
+ Packet ptmp3 = pset1<Packet>(t3);
+
+ size_t starti = FirstTriangular ? 0 : j+2;
+ size_t endi = FirstTriangular ? j : size;
+ size_t alignedStart = (starti) + internal::first_aligned(&res[starti], endi-starti);
+ size_t alignedEnd = alignedStart + ((endi-alignedStart)/(PacketSize))*(PacketSize);
+
+ // TODO make sure this product is a real * complex and that the rhs is properly conjugated if needed
+ res[j] += cjd.pmul(internal::real(A0[j]), t0);
+ res[j+1] += cjd.pmul(internal::real(A1[j+1]), t1);
+ if(FirstTriangular)
+ {
+ res[j] += cj0.pmul(A1[j], t1);
+ t3 += cj1.pmul(A1[j], rhs[j]);
+ }
+ else
+ {
+ res[j+1] += cj0.pmul(A0[j+1],t0);
+ t2 += cj1.pmul(A0[j+1], rhs[j+1]);
+ }
+
+ for (size_t i=starti; i<alignedStart; ++i)
+ {
+ res[i] += t0 * A0[i] + t1 * A1[i];
+ t2 += conj(A0[i]) * rhs[i];
+ t3 += conj(A1[i]) * rhs[i];
+ }
+ // Yes this an optimization for gcc 4.3 and 4.4 (=> huge speed up)
+ // gcc 4.2 does this optimization automatically.
+ const Scalar* EIGEN_RESTRICT a0It = A0 + alignedStart;
+ const Scalar* EIGEN_RESTRICT a1It = A1 + alignedStart;
+ const Scalar* EIGEN_RESTRICT rhsIt = rhs + alignedStart;
+ Scalar* EIGEN_RESTRICT resIt = res + alignedStart;
+ for (size_t i=alignedStart; i<alignedEnd; i+=PacketSize)
+ {
+ Packet A0i = ploadu<Packet>(a0It); a0It += PacketSize;
+ Packet A1i = ploadu<Packet>(a1It); a1It += PacketSize;
+ Packet Bi = ploadu<Packet>(rhsIt); rhsIt += PacketSize; // FIXME should be aligned in most cases
+ Packet Xi = pload <Packet>(resIt);
+
+ Xi = pcj0.pmadd(A0i,ptmp0, pcj0.pmadd(A1i,ptmp1,Xi));
+ ptmp2 = pcj1.pmadd(A0i, Bi, ptmp2);
+ ptmp3 = pcj1.pmadd(A1i, Bi, ptmp3);
+ pstore(resIt,Xi); resIt += PacketSize;
+ }
+ for (size_t i=alignedEnd; i<endi; i++)
+ {
+ res[i] += cj0.pmul(A0[i], t0) + cj0.pmul(A1[i],t1);
+ t2 += cj1.pmul(A0[i], rhs[i]);
+ t3 += cj1.pmul(A1[i], rhs[i]);
+ }
+
+ res[j] += alpha * (t2 + predux(ptmp2));
+ res[j+1] += alpha * (t3 + predux(ptmp3));
+ }
+ for (Index j=FirstTriangular ? 0 : bound;j<(FirstTriangular ? bound : size);j++)
+ {
+ register const Scalar* EIGEN_RESTRICT A0 = lhs + j*lhsStride;
+
+ Scalar t1 = cjAlpha * rhs[j];
+ Scalar t2(0);
+ // TODO make sure this product is a real * complex and that the rhs is properly conjugated if needed
+ res[j] += cjd.pmul(internal::real(A0[j]), t1);
+ for (Index i=FirstTriangular ? 0 : j+1; i<(FirstTriangular ? j : size); i++)
+ {
+ res[i] += cj0.pmul(A0[i], t1);
+ t2 += cj1.pmul(A0[i], rhs[i]);
+ }
+ res[j] += alpha * t2;
+ }
+}
+};
+
+} // end namespace internal
+
+/***************************************************************************
+* Wrapper to product_selfadjoint_vector
+***************************************************************************/
+
+namespace internal {
+template<typename Lhs, int LhsMode, typename Rhs>
+struct traits<SelfadjointProductMatrix<Lhs,LhsMode,false,Rhs,0,true> >
+ : traits<ProductBase<SelfadjointProductMatrix<Lhs,LhsMode,false,Rhs,0,true>, Lhs, Rhs> >
+{};
+}
+
+template<typename Lhs, int LhsMode, typename Rhs>
+struct SelfadjointProductMatrix<Lhs,LhsMode,false,Rhs,0,true>
+ : public ProductBase<SelfadjointProductMatrix<Lhs,LhsMode,false,Rhs,0,true>, Lhs, Rhs >
+{
+ EIGEN_PRODUCT_PUBLIC_INTERFACE(SelfadjointProductMatrix)
+
+ enum {
+ LhsUpLo = LhsMode&(Upper|Lower)
+ };
+
+ SelfadjointProductMatrix(const Lhs& lhs, const Rhs& rhs) : Base(lhs,rhs) {}
+
+ template<typename Dest> void scaleAndAddTo(Dest& dest, Scalar alpha) const
+ {
+ typedef typename Dest::Scalar ResScalar;
+ typedef typename Base::RhsScalar RhsScalar;
+ typedef Map<Matrix<ResScalar,Dynamic,1>, Aligned> MappedDest;
+
+ eigen_assert(dest.rows()==m_lhs.rows() && dest.cols()==m_rhs.cols());
+
+ typename internal::add_const_on_value_type<ActualLhsType>::type lhs = LhsBlasTraits::extract(m_lhs);
+ typename internal::add_const_on_value_type<ActualRhsType>::type rhs = RhsBlasTraits::extract(m_rhs);
+
+ Scalar actualAlpha = alpha * LhsBlasTraits::extractScalarFactor(m_lhs)
+ * RhsBlasTraits::extractScalarFactor(m_rhs);
+
+ enum {
+ EvalToDest = (Dest::InnerStrideAtCompileTime==1),
+ UseRhs = (_ActualRhsType::InnerStrideAtCompileTime==1)
+ };
+
+ internal::gemv_static_vector_if<ResScalar,Dest::SizeAtCompileTime,Dest::MaxSizeAtCompileTime,!EvalToDest> static_dest;
+ internal::gemv_static_vector_if<RhsScalar,_ActualRhsType::SizeAtCompileTime,_ActualRhsType::MaxSizeAtCompileTime,!UseRhs> static_rhs;
+
+ ei_declare_aligned_stack_constructed_variable(ResScalar,actualDestPtr,dest.size(),
+ EvalToDest ? dest.data() : static_dest.data());
+
+ ei_declare_aligned_stack_constructed_variable(RhsScalar,actualRhsPtr,rhs.size(),
+ UseRhs ? const_cast<RhsScalar*>(rhs.data()) : static_rhs.data());
+
+ if(!EvalToDest)
+ {
+ #ifdef EIGEN_DENSE_STORAGE_CTOR_PLUGIN
+ int size = dest.size();
+ EIGEN_DENSE_STORAGE_CTOR_PLUGIN
+ #endif
+ MappedDest(actualDestPtr, dest.size()) = dest;
+ }
+
+ if(!UseRhs)
+ {
+ #ifdef EIGEN_DENSE_STORAGE_CTOR_PLUGIN
+ int size = rhs.size();
+ EIGEN_DENSE_STORAGE_CTOR_PLUGIN
+ #endif
+ Map<typename _ActualRhsType::PlainObject>(actualRhsPtr, rhs.size()) = rhs;
+ }
+
+
+ internal::selfadjoint_matrix_vector_product<Scalar, Index, (internal::traits<_ActualLhsType>::Flags&RowMajorBit) ? RowMajor : ColMajor, int(LhsUpLo), bool(LhsBlasTraits::NeedToConjugate), bool(RhsBlasTraits::NeedToConjugate)>::run
+ (
+ lhs.rows(), // size
+ &lhs.coeffRef(0,0), lhs.outerStride(), // lhs info
+ actualRhsPtr, 1, // rhs info
+ actualDestPtr, // result info
+ actualAlpha // scale factor
+ );
+
+ if(!EvalToDest)
+ dest = MappedDest(actualDestPtr, dest.size());
+ }
+};
+
+namespace internal {
+template<typename Lhs, typename Rhs, int RhsMode>
+struct traits<SelfadjointProductMatrix<Lhs,0,true,Rhs,RhsMode,false> >
+ : traits<ProductBase<SelfadjointProductMatrix<Lhs,0,true,Rhs,RhsMode,false>, Lhs, Rhs> >
+{};
+}
+
+template<typename Lhs, typename Rhs, int RhsMode>
+struct SelfadjointProductMatrix<Lhs,0,true,Rhs,RhsMode,false>
+ : public ProductBase<SelfadjointProductMatrix<Lhs,0,true,Rhs,RhsMode,false>, Lhs, Rhs >
+{
+ EIGEN_PRODUCT_PUBLIC_INTERFACE(SelfadjointProductMatrix)
+
+ enum {
+ RhsUpLo = RhsMode&(Upper|Lower)
+ };
+
+ SelfadjointProductMatrix(const Lhs& lhs, const Rhs& rhs) : Base(lhs,rhs) {}
+
+ template<typename Dest> void scaleAndAddTo(Dest& dest, Scalar alpha) const
+ {
+ // let's simply transpose the product
+ Transpose<Dest> destT(dest);
+ SelfadjointProductMatrix<Transpose<const Rhs>, int(RhsUpLo)==Upper ? Lower : Upper, false,
+ Transpose<const Lhs>, 0, true>(m_rhs.transpose(), m_lhs.transpose()).scaleAndAddTo(destT, alpha);
+ }
+};
+
+} // end namespace Eigen
+
+#endif // EIGEN_SELFADJOINT_MATRIX_VECTOR_H
diff --git a/Eigen/src/Core/products/SelfadjointMatrixVector_MKL.h b/Eigen/src/Core/products/SelfadjointMatrixVector_MKL.h
new file mode 100644
index 000000000..f88d483b6
--- /dev/null
+++ b/Eigen/src/Core/products/SelfadjointMatrixVector_MKL.h
@@ -0,0 +1,114 @@
+/*
+ Copyright (c) 2011, Intel Corporation. All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without modification,
+ are permitted provided that the following conditions are met:
+
+ * Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+ * Neither the name of Intel Corporation nor the names of its contributors may
+ be used to endorse or promote products derived from this software without
+ specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+ ********************************************************************************
+ * Content : Eigen bindings to Intel(R) MKL
+ * Selfadjoint matrix-vector product functionality based on ?SYMV/HEMV.
+ ********************************************************************************
+*/
+
+#ifndef EIGEN_SELFADJOINT_MATRIX_VECTOR_MKL_H
+#define EIGEN_SELFADJOINT_MATRIX_VECTOR_MKL_H
+
+namespace Eigen {
+
+namespace internal {
+
+/**********************************************************************
+* This file implements selfadjoint matrix-vector multiplication using BLAS
+**********************************************************************/
+
+// symv/hemv specialization
+
+template<typename Scalar, typename Index, int StorageOrder, int UpLo, bool ConjugateLhs, bool ConjugateRhs>
+struct selfadjoint_matrix_vector_product_symv :
+ selfadjoint_matrix_vector_product<Scalar,Index,StorageOrder,UpLo,ConjugateLhs,ConjugateRhs,BuiltIn> {};
+
+#define EIGEN_MKL_SYMV_SPECIALIZE(Scalar) \
+template<typename Index, int StorageOrder, int UpLo, bool ConjugateLhs, bool ConjugateRhs> \
+struct selfadjoint_matrix_vector_product<Scalar,Index,StorageOrder,UpLo,ConjugateLhs,ConjugateRhs,Specialized> { \
+static EIGEN_DONT_INLINE void run( \
+ Index size, const Scalar* lhs, Index lhsStride, \
+ const Scalar* _rhs, Index rhsIncr, Scalar* res, Scalar alpha) { \
+ enum {\
+ IsColMajor = StorageOrder==ColMajor \
+ }; \
+ if (IsColMajor == ConjugateLhs) {\
+ selfadjoint_matrix_vector_product<Scalar,Index,StorageOrder,UpLo,ConjugateLhs,ConjugateRhs,BuiltIn>::run( \
+ size, lhs, lhsStride, _rhs, rhsIncr, res, alpha); \
+ } else {\
+ selfadjoint_matrix_vector_product_symv<Scalar,Index,StorageOrder,UpLo,ConjugateLhs,ConjugateRhs>::run( \
+ size, lhs, lhsStride, _rhs, rhsIncr, res, alpha); \
+ }\
+ } \
+}; \
+
+EIGEN_MKL_SYMV_SPECIALIZE(double)
+EIGEN_MKL_SYMV_SPECIALIZE(float)
+EIGEN_MKL_SYMV_SPECIALIZE(dcomplex)
+EIGEN_MKL_SYMV_SPECIALIZE(scomplex)
+
+#define EIGEN_MKL_SYMV_SPECIALIZATION(EIGTYPE,MKLTYPE,MKLFUNC) \
+template<typename Index, int StorageOrder, int UpLo, bool ConjugateLhs, bool ConjugateRhs> \
+struct selfadjoint_matrix_vector_product_symv<EIGTYPE,Index,StorageOrder,UpLo,ConjugateLhs,ConjugateRhs> \
+{ \
+typedef Matrix<EIGTYPE,Dynamic,1,ColMajor> SYMVVector;\
+\
+static EIGEN_DONT_INLINE void run( \
+Index size, const EIGTYPE* lhs, Index lhsStride, \
+const EIGTYPE* _rhs, Index rhsIncr, EIGTYPE* res, EIGTYPE alpha) \
+{ \
+ enum {\
+ IsRowMajor = StorageOrder==RowMajor ? 1 : 0, \
+ IsLower = UpLo == Lower ? 1 : 0 \
+ }; \
+ MKL_INT n=size, lda=lhsStride, incx=rhsIncr, incy=1; \
+ MKLTYPE alpha_, beta_; \
+ const EIGTYPE *x_ptr, myone(1); \
+ char uplo=(IsRowMajor) ? (IsLower ? 'U' : 'L') : (IsLower ? 'L' : 'U'); \
+ assign_scalar_eig2mkl(alpha_, alpha); \
+ assign_scalar_eig2mkl(beta_, myone); \
+ SYMVVector x_tmp; \
+ if (ConjugateRhs) { \
+ Map<const SYMVVector, 0, InnerStride<> > map_x(_rhs,size,1,InnerStride<>(incx)); \
+ x_tmp=map_x.conjugate(); \
+ x_ptr=x_tmp.data(); \
+ incx=1; \
+ } else x_ptr=_rhs; \
+ MKLFUNC(&uplo, &n, &alpha_, (const MKLTYPE*)lhs, &lda, (const MKLTYPE*)x_ptr, &incx, &beta_, (MKLTYPE*)res, &incy); \
+}\
+};
+
+EIGEN_MKL_SYMV_SPECIALIZATION(double, double, dsymv)
+EIGEN_MKL_SYMV_SPECIALIZATION(float, float, ssymv)
+EIGEN_MKL_SYMV_SPECIALIZATION(dcomplex, MKL_Complex16, zhemv)
+EIGEN_MKL_SYMV_SPECIALIZATION(scomplex, MKL_Complex8, chemv)
+
+} // end namespace internal
+
+} // end namespace Eigen
+
+#endif // EIGEN_SELFADJOINT_MATRIX_VECTOR_MKL_H
diff --git a/Eigen/src/Core/products/SelfadjointProduct.h b/Eigen/src/Core/products/SelfadjointProduct.h
new file mode 100644
index 000000000..6a55f3d77
--- /dev/null
+++ b/Eigen/src/Core/products/SelfadjointProduct.h
@@ -0,0 +1,125 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra.
+//
+// Copyright (C) 2009 Gael Guennebaud <gael.guennebaud@inria.fr>
+//
+// This Source Code Form is subject to the terms of the Mozilla
+// Public License v. 2.0. If a copy of the MPL was not distributed
+// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+#ifndef EIGEN_SELFADJOINT_PRODUCT_H
+#define EIGEN_SELFADJOINT_PRODUCT_H
+
+/**********************************************************************
+* This file implements a self adjoint product: C += A A^T updating only
+* half of the selfadjoint matrix C.
+* It corresponds to the level 3 SYRK and level 2 SYR Blas routines.
+**********************************************************************/
+
+namespace Eigen {
+
+template<typename Scalar, typename Index, int StorageOrder, int UpLo, bool ConjLhs, bool ConjRhs>
+struct selfadjoint_rank1_update;
+
+template<typename Scalar, typename Index, int UpLo, bool ConjLhs, bool ConjRhs>
+struct selfadjoint_rank1_update<Scalar,Index,ColMajor,UpLo,ConjLhs,ConjRhs>
+{
+ static void run(Index size, Scalar* mat, Index stride, const Scalar* vec, Scalar alpha)
+ {
+ internal::conj_if<ConjRhs> cj;
+ typedef Map<const Matrix<Scalar,Dynamic,1> > OtherMap;
+ typedef typename internal::conditional<ConjLhs,typename OtherMap::ConjugateReturnType,const OtherMap&>::type ConjRhsType;
+ for (Index i=0; i<size; ++i)
+ {
+ Map<Matrix<Scalar,Dynamic,1> >(mat+stride*i+(UpLo==Lower ? i : 0), (UpLo==Lower ? size-i : (i+1)))
+ += (alpha * cj(vec[i])) * ConjRhsType(OtherMap(vec+(UpLo==Lower ? i : 0),UpLo==Lower ? size-i : (i+1)));
+ }
+ }
+};
+
+template<typename Scalar, typename Index, int UpLo, bool ConjLhs, bool ConjRhs>
+struct selfadjoint_rank1_update<Scalar,Index,RowMajor,UpLo,ConjLhs,ConjRhs>
+{
+ static void run(Index size, Scalar* mat, Index stride, const Scalar* vec, Scalar alpha)
+ {
+ selfadjoint_rank1_update<Scalar,Index,ColMajor,UpLo==Lower?Upper:Lower,ConjRhs,ConjLhs>::run(size,mat,stride,vec,alpha);
+ }
+};
+
+template<typename MatrixType, typename OtherType, int UpLo, bool OtherIsVector = OtherType::IsVectorAtCompileTime>
+struct selfadjoint_product_selector;
+
+template<typename MatrixType, typename OtherType, int UpLo>
+struct selfadjoint_product_selector<MatrixType,OtherType,UpLo,true>
+{
+ static void run(MatrixType& mat, const OtherType& other, typename MatrixType::Scalar alpha)
+ {
+ typedef typename MatrixType::Scalar Scalar;
+ typedef typename MatrixType::Index Index;
+ typedef internal::blas_traits<OtherType> OtherBlasTraits;
+ typedef typename OtherBlasTraits::DirectLinearAccessType ActualOtherType;
+ typedef typename internal::remove_all<ActualOtherType>::type _ActualOtherType;
+ typename internal::add_const_on_value_type<ActualOtherType>::type actualOther = OtherBlasTraits::extract(other.derived());
+
+ Scalar actualAlpha = alpha * OtherBlasTraits::extractScalarFactor(other.derived());
+
+ enum {
+ StorageOrder = (internal::traits<MatrixType>::Flags&RowMajorBit) ? RowMajor : ColMajor,
+ UseOtherDirectly = _ActualOtherType::InnerStrideAtCompileTime==1
+ };
+ internal::gemv_static_vector_if<Scalar,OtherType::SizeAtCompileTime,OtherType::MaxSizeAtCompileTime,!UseOtherDirectly> static_other;
+
+ ei_declare_aligned_stack_constructed_variable(Scalar, actualOtherPtr, other.size(),
+ (UseOtherDirectly ? const_cast<Scalar*>(actualOther.data()) : static_other.data()));
+
+ if(!UseOtherDirectly)
+ Map<typename _ActualOtherType::PlainObject>(actualOtherPtr, actualOther.size()) = actualOther;
+
+ selfadjoint_rank1_update<Scalar,Index,StorageOrder,UpLo,
+ OtherBlasTraits::NeedToConjugate && NumTraits<Scalar>::IsComplex,
+ (!OtherBlasTraits::NeedToConjugate) && NumTraits<Scalar>::IsComplex>
+ ::run(other.size(), mat.data(), mat.outerStride(), actualOtherPtr, actualAlpha);
+ }
+};
+
+template<typename MatrixType, typename OtherType, int UpLo>
+struct selfadjoint_product_selector<MatrixType,OtherType,UpLo,false>
+{
+ static void run(MatrixType& mat, const OtherType& other, typename MatrixType::Scalar alpha)
+ {
+ typedef typename MatrixType::Scalar Scalar;
+ typedef typename MatrixType::Index Index;
+ typedef internal::blas_traits<OtherType> OtherBlasTraits;
+ typedef typename OtherBlasTraits::DirectLinearAccessType ActualOtherType;
+ typedef typename internal::remove_all<ActualOtherType>::type _ActualOtherType;
+ typename internal::add_const_on_value_type<ActualOtherType>::type actualOther = OtherBlasTraits::extract(other.derived());
+
+ Scalar actualAlpha = alpha * OtherBlasTraits::extractScalarFactor(other.derived());
+
+ enum { IsRowMajor = (internal::traits<MatrixType>::Flags&RowMajorBit) ? 1 : 0 };
+
+ internal::general_matrix_matrix_triangular_product<Index,
+ Scalar, _ActualOtherType::Flags&RowMajorBit ? RowMajor : ColMajor, OtherBlasTraits::NeedToConjugate && NumTraits<Scalar>::IsComplex,
+ Scalar, _ActualOtherType::Flags&RowMajorBit ? ColMajor : RowMajor, (!OtherBlasTraits::NeedToConjugate) && NumTraits<Scalar>::IsComplex,
+ MatrixType::Flags&RowMajorBit ? RowMajor : ColMajor, UpLo>
+ ::run(mat.cols(), actualOther.cols(),
+ &actualOther.coeffRef(0,0), actualOther.outerStride(), &actualOther.coeffRef(0,0), actualOther.outerStride(),
+ mat.data(), mat.outerStride(), actualAlpha);
+ }
+};
+
+// high level API
+
+template<typename MatrixType, unsigned int UpLo>
+template<typename DerivedU>
+SelfAdjointView<MatrixType,UpLo>& SelfAdjointView<MatrixType,UpLo>
+::rankUpdate(const MatrixBase<DerivedU>& u, Scalar alpha)
+{
+ selfadjoint_product_selector<MatrixType,DerivedU,UpLo>::run(_expression().const_cast_derived(), u.derived(), alpha);
+
+ return *this;
+}
+
+} // end namespace Eigen
+
+#endif // EIGEN_SELFADJOINT_PRODUCT_H
diff --git a/Eigen/src/Core/products/SelfadjointRank2Update.h b/Eigen/src/Core/products/SelfadjointRank2Update.h
new file mode 100644
index 000000000..57a98cc2d
--- /dev/null
+++ b/Eigen/src/Core/products/SelfadjointRank2Update.h
@@ -0,0 +1,93 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra.
+//
+// Copyright (C) 2009 Gael Guennebaud <gael.guennebaud@inria.fr>
+//
+// This Source Code Form is subject to the terms of the Mozilla
+// Public License v. 2.0. If a copy of the MPL was not distributed
+// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+#ifndef EIGEN_SELFADJOINTRANK2UPTADE_H
+#define EIGEN_SELFADJOINTRANK2UPTADE_H
+
+namespace Eigen {
+
+namespace internal {
+
+/* Optimized selfadjoint matrix += alpha * uv' + conj(alpha)*vu'
+ * It corresponds to the Level2 syr2 BLAS routine
+ */
+
+template<typename Scalar, typename Index, typename UType, typename VType, int UpLo>
+struct selfadjoint_rank2_update_selector;
+
+template<typename Scalar, typename Index, typename UType, typename VType>
+struct selfadjoint_rank2_update_selector<Scalar,Index,UType,VType,Lower>
+{
+ static void run(Scalar* mat, Index stride, const UType& u, const VType& v, Scalar alpha)
+ {
+ const Index size = u.size();
+ for (Index i=0; i<size; ++i)
+ {
+ Map<Matrix<Scalar,Dynamic,1> >(mat+stride*i+i, size-i) +=
+ (conj(alpha) * conj(u.coeff(i))) * v.tail(size-i)
+ + (alpha * conj(v.coeff(i))) * u.tail(size-i);
+ }
+ }
+};
+
+template<typename Scalar, typename Index, typename UType, typename VType>
+struct selfadjoint_rank2_update_selector<Scalar,Index,UType,VType,Upper>
+{
+ static void run(Scalar* mat, Index stride, const UType& u, const VType& v, Scalar alpha)
+ {
+ const Index size = u.size();
+ for (Index i=0; i<size; ++i)
+ Map<Matrix<Scalar,Dynamic,1> >(mat+stride*i, i+1) +=
+ (conj(alpha) * conj(u.coeff(i))) * v.head(i+1)
+ + (alpha * conj(v.coeff(i))) * u.head(i+1);
+ }
+};
+
+template<bool Cond, typename T> struct conj_expr_if
+ : conditional<!Cond, const T&,
+ CwiseUnaryOp<scalar_conjugate_op<typename traits<T>::Scalar>,T> > {};
+
+} // end namespace internal
+
+template<typename MatrixType, unsigned int UpLo>
+template<typename DerivedU, typename DerivedV>
+SelfAdjointView<MatrixType,UpLo>& SelfAdjointView<MatrixType,UpLo>
+::rankUpdate(const MatrixBase<DerivedU>& u, const MatrixBase<DerivedV>& v, Scalar alpha)
+{
+ typedef internal::blas_traits<DerivedU> UBlasTraits;
+ typedef typename UBlasTraits::DirectLinearAccessType ActualUType;
+ typedef typename internal::remove_all<ActualUType>::type _ActualUType;
+ typename internal::add_const_on_value_type<ActualUType>::type actualU = UBlasTraits::extract(u.derived());
+
+ typedef internal::blas_traits<DerivedV> VBlasTraits;
+ typedef typename VBlasTraits::DirectLinearAccessType ActualVType;
+ typedef typename internal::remove_all<ActualVType>::type _ActualVType;
+ typename internal::add_const_on_value_type<ActualVType>::type actualV = VBlasTraits::extract(v.derived());
+
+ // If MatrixType is row major, then we use the routine for lower triangular in the upper triangular case and
+ // vice versa, and take the complex conjugate of all coefficients and vector entries.
+
+ enum { IsRowMajor = (internal::traits<MatrixType>::Flags&RowMajorBit) ? 1 : 0 };
+ Scalar actualAlpha = alpha * UBlasTraits::extractScalarFactor(u.derived())
+ * internal::conj(VBlasTraits::extractScalarFactor(v.derived()));
+ if (IsRowMajor)
+ actualAlpha = internal::conj(actualAlpha);
+
+ internal::selfadjoint_rank2_update_selector<Scalar, Index,
+ typename internal::remove_all<typename internal::conj_expr_if<IsRowMajor ^ UBlasTraits::NeedToConjugate,_ActualUType>::type>::type,
+ typename internal::remove_all<typename internal::conj_expr_if<IsRowMajor ^ VBlasTraits::NeedToConjugate,_ActualVType>::type>::type,
+ (IsRowMajor ? int(UpLo==Upper ? Lower : Upper) : UpLo)>
+ ::run(_expression().const_cast_derived().data(),_expression().outerStride(),actualU,actualV,actualAlpha);
+
+ return *this;
+}
+
+} // end namespace Eigen
+
+#endif // EIGEN_SELFADJOINTRANK2UPTADE_H
diff --git a/Eigen/src/Core/products/TriangularMatrixMatrix.h b/Eigen/src/Core/products/TriangularMatrixMatrix.h
new file mode 100644
index 000000000..92cba66f6
--- /dev/null
+++ b/Eigen/src/Core/products/TriangularMatrixMatrix.h
@@ -0,0 +1,403 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra.
+//
+// Copyright (C) 2009 Gael Guennebaud <gael.guennebaud@inria.fr>
+//
+// This Source Code Form is subject to the terms of the Mozilla
+// Public License v. 2.0. If a copy of the MPL was not distributed
+// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+#ifndef EIGEN_TRIANGULAR_MATRIX_MATRIX_H
+#define EIGEN_TRIANGULAR_MATRIX_MATRIX_H
+
+namespace Eigen {
+
+namespace internal {
+
+// template<typename Scalar, int mr, int StorageOrder, bool Conjugate, int Mode>
+// struct gemm_pack_lhs_triangular
+// {
+// Matrix<Scalar,mr,mr,
+// void operator()(Scalar* blockA, const EIGEN_RESTRICT Scalar* _lhs, int lhsStride, int depth, int rows)
+// {
+// conj_if<NumTraits<Scalar>::IsComplex && Conjugate> cj;
+// const_blas_data_mapper<Scalar, StorageOrder> lhs(_lhs,lhsStride);
+// int count = 0;
+// const int peeled_mc = (rows/mr)*mr;
+// for(int i=0; i<peeled_mc; i+=mr)
+// {
+// for(int k=0; k<depth; k++)
+// for(int w=0; w<mr; w++)
+// blockA[count++] = cj(lhs(i+w, k));
+// }
+// for(int i=peeled_mc; i<rows; i++)
+// {
+// for(int k=0; k<depth; k++)
+// blockA[count++] = cj(lhs(i, k));
+// }
+// }
+// };
+
+/* Optimized triangular matrix * matrix (_TRMM++) product built on top of
+ * the general matrix matrix product.
+ */
+template <typename Scalar, typename Index,
+ int Mode, bool LhsIsTriangular,
+ int LhsStorageOrder, bool ConjugateLhs,
+ int RhsStorageOrder, bool ConjugateRhs,
+ int ResStorageOrder, int Version = Specialized>
+struct product_triangular_matrix_matrix;
+
+template <typename Scalar, typename Index,
+ int Mode, bool LhsIsTriangular,
+ int LhsStorageOrder, bool ConjugateLhs,
+ int RhsStorageOrder, bool ConjugateRhs, int Version>
+struct product_triangular_matrix_matrix<Scalar,Index,Mode,LhsIsTriangular,
+ LhsStorageOrder,ConjugateLhs,
+ RhsStorageOrder,ConjugateRhs,RowMajor,Version>
+{
+ static EIGEN_STRONG_INLINE void run(
+ Index rows, Index cols, Index depth,
+ const Scalar* lhs, Index lhsStride,
+ const Scalar* rhs, Index rhsStride,
+ Scalar* res, Index resStride,
+ Scalar alpha, level3_blocking<Scalar,Scalar>& blocking)
+ {
+ product_triangular_matrix_matrix<Scalar, Index,
+ (Mode&(UnitDiag|ZeroDiag)) | ((Mode&Upper) ? Lower : Upper),
+ (!LhsIsTriangular),
+ RhsStorageOrder==RowMajor ? ColMajor : RowMajor,
+ ConjugateRhs,
+ LhsStorageOrder==RowMajor ? ColMajor : RowMajor,
+ ConjugateLhs,
+ ColMajor>
+ ::run(cols, rows, depth, rhs, rhsStride, lhs, lhsStride, res, resStride, alpha, blocking);
+ }
+};
+
+// implements col-major += alpha * op(triangular) * op(general)
+template <typename Scalar, typename Index, int Mode,
+ int LhsStorageOrder, bool ConjugateLhs,
+ int RhsStorageOrder, bool ConjugateRhs, int Version>
+struct product_triangular_matrix_matrix<Scalar,Index,Mode,true,
+ LhsStorageOrder,ConjugateLhs,
+ RhsStorageOrder,ConjugateRhs,ColMajor,Version>
+{
+
+ typedef gebp_traits<Scalar,Scalar> Traits;
+ enum {
+ SmallPanelWidth = 2 * EIGEN_PLAIN_ENUM_MAX(Traits::mr,Traits::nr),
+ IsLower = (Mode&Lower) == Lower,
+ SetDiag = (Mode&(ZeroDiag|UnitDiag)) ? 0 : 1
+ };
+
+ static EIGEN_DONT_INLINE void run(
+ Index _rows, Index _cols, Index _depth,
+ const Scalar* _lhs, Index lhsStride,
+ const Scalar* _rhs, Index rhsStride,
+ Scalar* res, Index resStride,
+ Scalar alpha, level3_blocking<Scalar,Scalar>& blocking)
+ {
+ // strip zeros
+ Index diagSize = (std::min)(_rows,_depth);
+ Index rows = IsLower ? _rows : diagSize;
+ Index depth = IsLower ? diagSize : _depth;
+ Index cols = _cols;
+
+ const_blas_data_mapper<Scalar, Index, LhsStorageOrder> lhs(_lhs,lhsStride);
+ const_blas_data_mapper<Scalar, Index, RhsStorageOrder> rhs(_rhs,rhsStride);
+
+ Index kc = blocking.kc(); // cache block size along the K direction
+ Index mc = (std::min)(rows,blocking.mc()); // cache block size along the M direction
+
+ std::size_t sizeA = kc*mc;
+ std::size_t sizeB = kc*cols;
+ std::size_t sizeW = kc*Traits::WorkSpaceFactor;
+
+ ei_declare_aligned_stack_constructed_variable(Scalar, blockA, sizeA, blocking.blockA());
+ ei_declare_aligned_stack_constructed_variable(Scalar, blockB, sizeB, blocking.blockB());
+ ei_declare_aligned_stack_constructed_variable(Scalar, blockW, sizeW, blocking.blockW());
+
+ Matrix<Scalar,SmallPanelWidth,SmallPanelWidth,LhsStorageOrder> triangularBuffer;
+ triangularBuffer.setZero();
+ if((Mode&ZeroDiag)==ZeroDiag)
+ triangularBuffer.diagonal().setZero();
+ else
+ triangularBuffer.diagonal().setOnes();
+
+ gebp_kernel<Scalar, Scalar, Index, Traits::mr, Traits::nr, ConjugateLhs, ConjugateRhs> gebp_kernel;
+ gemm_pack_lhs<Scalar, Index, Traits::mr, Traits::LhsProgress, LhsStorageOrder> pack_lhs;
+ gemm_pack_rhs<Scalar, Index, Traits::nr,RhsStorageOrder> pack_rhs;
+
+ for(Index k2=IsLower ? depth : 0;
+ IsLower ? k2>0 : k2<depth;
+ IsLower ? k2-=kc : k2+=kc)
+ {
+ Index actual_kc = (std::min)(IsLower ? k2 : depth-k2, kc);
+ Index actual_k2 = IsLower ? k2-actual_kc : k2;
+
+ // align blocks with the end of the triangular part for trapezoidal lhs
+ if((!IsLower)&&(k2<rows)&&(k2+actual_kc>rows))
+ {
+ actual_kc = rows-k2;
+ k2 = k2+actual_kc-kc;
+ }
+
+ pack_rhs(blockB, &rhs(actual_k2,0), rhsStride, actual_kc, cols);
+
+ // the selected lhs's panel has to be split in three different parts:
+ // 1 - the part which is zero => skip it
+ // 2 - the diagonal block => special kernel
+ // 3 - the dense panel below (lower case) or above (upper case) the diagonal block => GEPP
+
+ // the block diagonal, if any:
+ if(IsLower || actual_k2<rows)
+ {
+ // for each small vertical panels of lhs
+ for (Index k1=0; k1<actual_kc; k1+=SmallPanelWidth)
+ {
+ Index actualPanelWidth = std::min<Index>(actual_kc-k1, SmallPanelWidth);
+ Index lengthTarget = IsLower ? actual_kc-k1-actualPanelWidth : k1;
+ Index startBlock = actual_k2+k1;
+ Index blockBOffset = k1;
+
+ // => GEBP with the micro triangular block
+ // The trick is to pack this micro block while filling the opposite triangular part with zeros.
+ // To this end we do an extra triangular copy to a small temporary buffer
+ for (Index k=0;k<actualPanelWidth;++k)
+ {
+ if (SetDiag)
+ triangularBuffer.coeffRef(k,k) = lhs(startBlock+k,startBlock+k);
+ for (Index i=IsLower ? k+1 : 0; IsLower ? i<actualPanelWidth : i<k; ++i)
+ triangularBuffer.coeffRef(i,k) = lhs(startBlock+i,startBlock+k);
+ }
+ pack_lhs(blockA, triangularBuffer.data(), triangularBuffer.outerStride(), actualPanelWidth, actualPanelWidth);
+
+ gebp_kernel(res+startBlock, resStride, blockA, blockB, actualPanelWidth, actualPanelWidth, cols, alpha,
+ actualPanelWidth, actual_kc, 0, blockBOffset, blockW);
+
+ // GEBP with remaining micro panel
+ if (lengthTarget>0)
+ {
+ Index startTarget = IsLower ? actual_k2+k1+actualPanelWidth : actual_k2;
+
+ pack_lhs(blockA, &lhs(startTarget,startBlock), lhsStride, actualPanelWidth, lengthTarget);
+
+ gebp_kernel(res+startTarget, resStride, blockA, blockB, lengthTarget, actualPanelWidth, cols, alpha,
+ actualPanelWidth, actual_kc, 0, blockBOffset, blockW);
+ }
+ }
+ }
+ // the part below (lower case) or above (upper case) the diagonal => GEPP
+ {
+ Index start = IsLower ? k2 : 0;
+ Index end = IsLower ? rows : (std::min)(actual_k2,rows);
+ for(Index i2=start; i2<end; i2+=mc)
+ {
+ const Index actual_mc = (std::min)(i2+mc,end)-i2;
+ gemm_pack_lhs<Scalar, Index, Traits::mr,Traits::LhsProgress, LhsStorageOrder,false>()
+ (blockA, &lhs(i2, actual_k2), lhsStride, actual_kc, actual_mc);
+
+ gebp_kernel(res+i2, resStride, blockA, blockB, actual_mc, actual_kc, cols, alpha, -1, -1, 0, 0, blockW);
+ }
+ }
+ }
+ }
+};
+
+// implements col-major += alpha * op(general) * op(triangular)
+template <typename Scalar, typename Index, int Mode,
+ int LhsStorageOrder, bool ConjugateLhs,
+ int RhsStorageOrder, bool ConjugateRhs, int Version>
+struct product_triangular_matrix_matrix<Scalar,Index,Mode,false,
+ LhsStorageOrder,ConjugateLhs,
+ RhsStorageOrder,ConjugateRhs,ColMajor,Version>
+{
+ typedef gebp_traits<Scalar,Scalar> Traits;
+ enum {
+ SmallPanelWidth = EIGEN_PLAIN_ENUM_MAX(Traits::mr,Traits::nr),
+ IsLower = (Mode&Lower) == Lower,
+ SetDiag = (Mode&(ZeroDiag|UnitDiag)) ? 0 : 1
+ };
+
+ static EIGEN_DONT_INLINE void run(
+ Index _rows, Index _cols, Index _depth,
+ const Scalar* _lhs, Index lhsStride,
+ const Scalar* _rhs, Index rhsStride,
+ Scalar* res, Index resStride,
+ Scalar alpha, level3_blocking<Scalar,Scalar>& blocking)
+ {
+ // strip zeros
+ Index diagSize = (std::min)(_cols,_depth);
+ Index rows = _rows;
+ Index depth = IsLower ? _depth : diagSize;
+ Index cols = IsLower ? diagSize : _cols;
+
+ const_blas_data_mapper<Scalar, Index, LhsStorageOrder> lhs(_lhs,lhsStride);
+ const_blas_data_mapper<Scalar, Index, RhsStorageOrder> rhs(_rhs,rhsStride);
+
+ Index kc = blocking.kc(); // cache block size along the K direction
+ Index mc = (std::min)(rows,blocking.mc()); // cache block size along the M direction
+
+ std::size_t sizeA = kc*mc;
+ std::size_t sizeB = kc*cols;
+ std::size_t sizeW = kc*Traits::WorkSpaceFactor;
+
+ ei_declare_aligned_stack_constructed_variable(Scalar, blockA, sizeA, blocking.blockA());
+ ei_declare_aligned_stack_constructed_variable(Scalar, blockB, sizeB, blocking.blockB());
+ ei_declare_aligned_stack_constructed_variable(Scalar, blockW, sizeW, blocking.blockW());
+
+ Matrix<Scalar,SmallPanelWidth,SmallPanelWidth,RhsStorageOrder> triangularBuffer;
+ triangularBuffer.setZero();
+ if((Mode&ZeroDiag)==ZeroDiag)
+ triangularBuffer.diagonal().setZero();
+ else
+ triangularBuffer.diagonal().setOnes();
+
+ gebp_kernel<Scalar, Scalar, Index, Traits::mr, Traits::nr, ConjugateLhs, ConjugateRhs> gebp_kernel;
+ gemm_pack_lhs<Scalar, Index, Traits::mr, Traits::LhsProgress, LhsStorageOrder> pack_lhs;
+ gemm_pack_rhs<Scalar, Index, Traits::nr,RhsStorageOrder> pack_rhs;
+ gemm_pack_rhs<Scalar, Index, Traits::nr,RhsStorageOrder,false,true> pack_rhs_panel;
+
+ for(Index k2=IsLower ? 0 : depth;
+ IsLower ? k2<depth : k2>0;
+ IsLower ? k2+=kc : k2-=kc)
+ {
+ Index actual_kc = (std::min)(IsLower ? depth-k2 : k2, kc);
+ Index actual_k2 = IsLower ? k2 : k2-actual_kc;
+
+ // align blocks with the end of the triangular part for trapezoidal rhs
+ if(IsLower && (k2<cols) && (actual_k2+actual_kc>cols))
+ {
+ actual_kc = cols-k2;
+ k2 = actual_k2 + actual_kc - kc;
+ }
+
+ // remaining size
+ Index rs = IsLower ? (std::min)(cols,actual_k2) : cols - k2;
+ // size of the triangular part
+ Index ts = (IsLower && actual_k2>=cols) ? 0 : actual_kc;
+
+ Scalar* geb = blockB+ts*ts;
+
+ pack_rhs(geb, &rhs(actual_k2,IsLower ? 0 : k2), rhsStride, actual_kc, rs);
+
+ // pack the triangular part of the rhs padding the unrolled blocks with zeros
+ if(ts>0)
+ {
+ for (Index j2=0; j2<actual_kc; j2+=SmallPanelWidth)
+ {
+ Index actualPanelWidth = std::min<Index>(actual_kc-j2, SmallPanelWidth);
+ Index actual_j2 = actual_k2 + j2;
+ Index panelOffset = IsLower ? j2+actualPanelWidth : 0;
+ Index panelLength = IsLower ? actual_kc-j2-actualPanelWidth : j2;
+ // general part
+ pack_rhs_panel(blockB+j2*actual_kc,
+ &rhs(actual_k2+panelOffset, actual_j2), rhsStride,
+ panelLength, actualPanelWidth,
+ actual_kc, panelOffset);
+
+ // append the triangular part via a temporary buffer
+ for (Index j=0;j<actualPanelWidth;++j)
+ {
+ if (SetDiag)
+ triangularBuffer.coeffRef(j,j) = rhs(actual_j2+j,actual_j2+j);
+ for (Index k=IsLower ? j+1 : 0; IsLower ? k<actualPanelWidth : k<j; ++k)
+ triangularBuffer.coeffRef(k,j) = rhs(actual_j2+k,actual_j2+j);
+ }
+
+ pack_rhs_panel(blockB+j2*actual_kc,
+ triangularBuffer.data(), triangularBuffer.outerStride(),
+ actualPanelWidth, actualPanelWidth,
+ actual_kc, j2);
+ }
+ }
+
+ for (Index i2=0; i2<rows; i2+=mc)
+ {
+ const Index actual_mc = (std::min)(mc,rows-i2);
+ pack_lhs(blockA, &lhs(i2, actual_k2), lhsStride, actual_kc, actual_mc);
+
+ // triangular kernel
+ if(ts>0)
+ {
+ for (Index j2=0; j2<actual_kc; j2+=SmallPanelWidth)
+ {
+ Index actualPanelWidth = std::min<Index>(actual_kc-j2, SmallPanelWidth);
+ Index panelLength = IsLower ? actual_kc-j2 : j2+actualPanelWidth;
+ Index blockOffset = IsLower ? j2 : 0;
+
+ gebp_kernel(res+i2+(actual_k2+j2)*resStride, resStride,
+ blockA, blockB+j2*actual_kc,
+ actual_mc, panelLength, actualPanelWidth,
+ alpha,
+ actual_kc, actual_kc, // strides
+ blockOffset, blockOffset,// offsets
+ blockW); // workspace
+ }
+ }
+ gebp_kernel(res+i2+(IsLower ? 0 : k2)*resStride, resStride,
+ blockA, geb, actual_mc, actual_kc, rs,
+ alpha,
+ -1, -1, 0, 0, blockW);
+ }
+ }
+ }
+};
+
+/***************************************************************************
+* Wrapper to product_triangular_matrix_matrix
+***************************************************************************/
+
+template<int Mode, bool LhsIsTriangular, typename Lhs, typename Rhs>
+struct traits<TriangularProduct<Mode,LhsIsTriangular,Lhs,false,Rhs,false> >
+ : traits<ProductBase<TriangularProduct<Mode,LhsIsTriangular,Lhs,false,Rhs,false>, Lhs, Rhs> >
+{};
+
+} // end namespace internal
+
+template<int Mode, bool LhsIsTriangular, typename Lhs, typename Rhs>
+struct TriangularProduct<Mode,LhsIsTriangular,Lhs,false,Rhs,false>
+ : public ProductBase<TriangularProduct<Mode,LhsIsTriangular,Lhs,false,Rhs,false>, Lhs, Rhs >
+{
+ EIGEN_PRODUCT_PUBLIC_INTERFACE(TriangularProduct)
+
+ TriangularProduct(const Lhs& lhs, const Rhs& rhs) : Base(lhs,rhs) {}
+
+ template<typename Dest> void scaleAndAddTo(Dest& dst, Scalar alpha) const
+ {
+ typename internal::add_const_on_value_type<ActualLhsType>::type lhs = LhsBlasTraits::extract(m_lhs);
+ typename internal::add_const_on_value_type<ActualRhsType>::type rhs = RhsBlasTraits::extract(m_rhs);
+
+ Scalar actualAlpha = alpha * LhsBlasTraits::extractScalarFactor(m_lhs)
+ * RhsBlasTraits::extractScalarFactor(m_rhs);
+
+ typedef internal::gemm_blocking_space<(Dest::Flags&RowMajorBit) ? RowMajor : ColMajor,Scalar,Scalar,
+ Lhs::MaxRowsAtCompileTime, Rhs::MaxColsAtCompileTime, Lhs::MaxColsAtCompileTime,4> BlockingType;
+
+ enum { IsLower = (Mode&Lower) == Lower };
+ Index stripedRows = ((!LhsIsTriangular) || (IsLower)) ? lhs.rows() : (std::min)(lhs.rows(),lhs.cols());
+ Index stripedCols = ((LhsIsTriangular) || (!IsLower)) ? rhs.cols() : (std::min)(rhs.cols(),rhs.rows());
+ Index stripedDepth = LhsIsTriangular ? ((!IsLower) ? lhs.cols() : (std::min)(lhs.cols(),lhs.rows()))
+ : ((IsLower) ? rhs.rows() : (std::min)(rhs.rows(),rhs.cols()));
+
+ BlockingType blocking(stripedRows, stripedCols, stripedDepth);
+
+ internal::product_triangular_matrix_matrix<Scalar, Index,
+ Mode, LhsIsTriangular,
+ (internal::traits<_ActualLhsType>::Flags&RowMajorBit) ? RowMajor : ColMajor, LhsBlasTraits::NeedToConjugate,
+ (internal::traits<_ActualRhsType>::Flags&RowMajorBit) ? RowMajor : ColMajor, RhsBlasTraits::NeedToConjugate,
+ (internal::traits<Dest >::Flags&RowMajorBit) ? RowMajor : ColMajor>
+ ::run(
+ stripedRows, stripedCols, stripedDepth, // sizes
+ &lhs.coeffRef(0,0), lhs.outerStride(), // lhs info
+ &rhs.coeffRef(0,0), rhs.outerStride(), // rhs info
+ &dst.coeffRef(0,0), dst.outerStride(), // result info
+ actualAlpha, blocking
+ );
+ }
+};
+
+} // end namespace Eigen
+
+#endif // EIGEN_TRIANGULAR_MATRIX_MATRIX_H
diff --git a/Eigen/src/Core/products/TriangularMatrixMatrix_MKL.h b/Eigen/src/Core/products/TriangularMatrixMatrix_MKL.h
new file mode 100644
index 000000000..8173da5bb
--- /dev/null
+++ b/Eigen/src/Core/products/TriangularMatrixMatrix_MKL.h
@@ -0,0 +1,309 @@
+/*
+ Copyright (c) 2011, Intel Corporation. All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without modification,
+ are permitted provided that the following conditions are met:
+
+ * Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+ * Neither the name of Intel Corporation nor the names of its contributors may
+ be used to endorse or promote products derived from this software without
+ specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+ ********************************************************************************
+ * Content : Eigen bindings to Intel(R) MKL
+ * Triangular matrix * matrix product functionality based on ?TRMM.
+ ********************************************************************************
+*/
+
+#ifndef EIGEN_TRIANGULAR_MATRIX_MATRIX_MKL_H
+#define EIGEN_TRIANGULAR_MATRIX_MATRIX_MKL_H
+
+namespace Eigen {
+
+namespace internal {
+
+
+template <typename Scalar, typename Index,
+ int Mode, bool LhsIsTriangular,
+ int LhsStorageOrder, bool ConjugateLhs,
+ int RhsStorageOrder, bool ConjugateRhs,
+ int ResStorageOrder>
+struct product_triangular_matrix_matrix_trmm :
+ product_triangular_matrix_matrix<Scalar,Index,Mode,
+ LhsIsTriangular,LhsStorageOrder,ConjugateLhs,
+ RhsStorageOrder, ConjugateRhs, ResStorageOrder, BuiltIn> {};
+
+
+// try to go to BLAS specialization
+#define EIGEN_MKL_TRMM_SPECIALIZE(Scalar, LhsIsTriangular) \
+template <typename Index, int Mode, \
+ int LhsStorageOrder, bool ConjugateLhs, \
+ int RhsStorageOrder, bool ConjugateRhs> \
+struct product_triangular_matrix_matrix<Scalar,Index, Mode, LhsIsTriangular, \
+ LhsStorageOrder,ConjugateLhs, RhsStorageOrder,ConjugateRhs,ColMajor,Specialized> { \
+ static inline void run(Index _rows, Index _cols, Index _depth, const Scalar* _lhs, Index lhsStride,\
+ const Scalar* _rhs, Index rhsStride, Scalar* res, Index resStride, Scalar alpha) { \
+ product_triangular_matrix_matrix_trmm<Scalar,Index,Mode, \
+ LhsIsTriangular,LhsStorageOrder,ConjugateLhs, \
+ RhsStorageOrder, ConjugateRhs, ColMajor>::run( \
+ _rows, _cols, _depth, _lhs, lhsStride, _rhs, rhsStride, res, resStride, alpha); \
+ } \
+};
+
+EIGEN_MKL_TRMM_SPECIALIZE(double, true)
+EIGEN_MKL_TRMM_SPECIALIZE(double, false)
+EIGEN_MKL_TRMM_SPECIALIZE(dcomplex, true)
+EIGEN_MKL_TRMM_SPECIALIZE(dcomplex, false)
+EIGEN_MKL_TRMM_SPECIALIZE(float, true)
+EIGEN_MKL_TRMM_SPECIALIZE(float, false)
+EIGEN_MKL_TRMM_SPECIALIZE(scomplex, true)
+EIGEN_MKL_TRMM_SPECIALIZE(scomplex, false)
+
+// implements col-major += alpha * op(triangular) * op(general)
+#define EIGEN_MKL_TRMM_L(EIGTYPE, MKLTYPE, EIGPREFIX, MKLPREFIX) \
+template <typename Index, int Mode, \
+ int LhsStorageOrder, bool ConjugateLhs, \
+ int RhsStorageOrder, bool ConjugateRhs> \
+struct product_triangular_matrix_matrix_trmm<EIGTYPE,Index,Mode,true, \
+ LhsStorageOrder,ConjugateLhs,RhsStorageOrder,ConjugateRhs,ColMajor> \
+{ \
+ enum { \
+ IsLower = (Mode&Lower) == Lower, \
+ SetDiag = (Mode&(ZeroDiag|UnitDiag)) ? 0 : 1, \
+ IsUnitDiag = (Mode&UnitDiag) ? 1 : 0, \
+ IsZeroDiag = (Mode&ZeroDiag) ? 1 : 0, \
+ LowUp = IsLower ? Lower : Upper, \
+ conjA = ((LhsStorageOrder==ColMajor) && ConjugateLhs) ? 1 : 0 \
+ }; \
+\
+ static EIGEN_DONT_INLINE void run( \
+ Index _rows, Index _cols, Index _depth, \
+ const EIGTYPE* _lhs, Index lhsStride, \
+ const EIGTYPE* _rhs, Index rhsStride, \
+ EIGTYPE* res, Index resStride, \
+ EIGTYPE alpha) \
+ { \
+ Index diagSize = (std::min)(_rows,_depth); \
+ Index rows = IsLower ? _rows : diagSize; \
+ Index depth = IsLower ? diagSize : _depth; \
+ Index cols = _cols; \
+\
+ typedef Matrix<EIGTYPE, Dynamic, Dynamic, LhsStorageOrder> MatrixLhs; \
+ typedef Matrix<EIGTYPE, Dynamic, Dynamic, RhsStorageOrder> MatrixRhs; \
+\
+/* Non-square case - doesn't fit to MKL ?TRMM. Fall to default triangular product or call MKL ?GEMM*/ \
+ if (rows != depth) { \
+\
+ int nthr = mkl_domain_get_max_threads(MKL_BLAS); \
+\
+ if (((nthr==1) && (((std::max)(rows,depth)-diagSize)/(double)diagSize < 0.5))) { \
+ /* Most likely no benefit to call TRMM or GEMM from MKL*/ \
+ product_triangular_matrix_matrix<EIGTYPE,Index,Mode,true, \
+ LhsStorageOrder,ConjugateLhs, RhsStorageOrder, ConjugateRhs, ColMajor, BuiltIn>::run( \
+ _rows, _cols, _depth, _lhs, lhsStride, _rhs, rhsStride, res, resStride, alpha); \
+ /*std::cout << "TRMM_L: A is not square! Go to Eigen TRMM implementation!\n";*/ \
+ } else { \
+ /* Make sense to call GEMM */ \
+ Map<const MatrixLhs, 0, OuterStride<> > lhsMap(_lhs,rows,depth,OuterStride<>(lhsStride)); \
+ MatrixLhs aa_tmp=lhsMap.template triangularView<Mode>(); \
+ MKL_INT aStride = aa_tmp.outerStride(); \
+ gemm_blocking_space<ColMajor,EIGTYPE,EIGTYPE,Dynamic,Dynamic,Dynamic> blocking(_rows,_cols,_depth); \
+ general_matrix_matrix_product<Index,EIGTYPE,LhsStorageOrder,ConjugateLhs,EIGTYPE,RhsStorageOrder,ConjugateRhs,ColMajor>::run( \
+ rows, cols, depth, aa_tmp.data(), aStride, _rhs, rhsStride, res, resStride, alpha, blocking, 0); \
+\
+ /*std::cout << "TRMM_L: A is not square! Go to MKL GEMM implementation! " << nthr<<" \n";*/ \
+ } \
+ return; \
+ } \
+ char side = 'L', transa, uplo, diag = 'N'; \
+ EIGTYPE *b; \
+ const EIGTYPE *a; \
+ MKL_INT m, n, lda, ldb; \
+ MKLTYPE alpha_; \
+\
+/* Set alpha_*/ \
+ assign_scalar_eig2mkl<MKLTYPE, EIGTYPE>(alpha_, alpha); \
+\
+/* Set m, n */ \
+ m = (MKL_INT)diagSize; \
+ n = (MKL_INT)cols; \
+\
+/* Set trans */ \
+ transa = (LhsStorageOrder==RowMajor) ? ((ConjugateLhs) ? 'C' : 'T') : 'N'; \
+\
+/* Set b, ldb */ \
+ Map<const MatrixRhs, 0, OuterStride<> > rhs(_rhs,depth,cols,OuterStride<>(rhsStride)); \
+ MatrixX##EIGPREFIX b_tmp; \
+\
+ if (ConjugateRhs) b_tmp = rhs.conjugate(); else b_tmp = rhs; \
+ b = b_tmp.data(); \
+ ldb = b_tmp.outerStride(); \
+\
+/* Set uplo */ \
+ uplo = IsLower ? 'L' : 'U'; \
+ if (LhsStorageOrder==RowMajor) uplo = (uplo == 'L') ? 'U' : 'L'; \
+/* Set a, lda */ \
+ Map<const MatrixLhs, 0, OuterStride<> > lhs(_lhs,rows,depth,OuterStride<>(lhsStride)); \
+ MatrixLhs a_tmp; \
+\
+ if ((conjA!=0) || (SetDiag==0)) { \
+ if (conjA) a_tmp = lhs.conjugate(); else a_tmp = lhs; \
+ if (IsZeroDiag) \
+ a_tmp.diagonal().setZero(); \
+ else if (IsUnitDiag) \
+ a_tmp.diagonal().setOnes();\
+ a = a_tmp.data(); \
+ lda = a_tmp.outerStride(); \
+ } else { \
+ a = _lhs; \
+ lda = lhsStride; \
+ } \
+ /*std::cout << "TRMM_L: A is square! Go to MKL TRMM implementation! \n";*/ \
+/* call ?trmm*/ \
+ MKLPREFIX##trmm(&side, &uplo, &transa, &diag, &m, &n, &alpha_, (const MKLTYPE*)a, &lda, (MKLTYPE*)b, &ldb); \
+\
+/* Add op(a_triangular)*b into res*/ \
+ Map<MatrixX##EIGPREFIX, 0, OuterStride<> > res_tmp(res,rows,cols,OuterStride<>(resStride)); \
+ res_tmp=res_tmp+b_tmp; \
+ } \
+};
+
+EIGEN_MKL_TRMM_L(double, double, d, d)
+EIGEN_MKL_TRMM_L(dcomplex, MKL_Complex16, cd, z)
+EIGEN_MKL_TRMM_L(float, float, f, s)
+EIGEN_MKL_TRMM_L(scomplex, MKL_Complex8, cf, c)
+
+// implements col-major += alpha * op(general) * op(triangular)
+#define EIGEN_MKL_TRMM_R(EIGTYPE, MKLTYPE, EIGPREFIX, MKLPREFIX) \
+template <typename Index, int Mode, \
+ int LhsStorageOrder, bool ConjugateLhs, \
+ int RhsStorageOrder, bool ConjugateRhs> \
+struct product_triangular_matrix_matrix_trmm<EIGTYPE,Index,Mode,false, \
+ LhsStorageOrder,ConjugateLhs,RhsStorageOrder,ConjugateRhs,ColMajor> \
+{ \
+ enum { \
+ IsLower = (Mode&Lower) == Lower, \
+ SetDiag = (Mode&(ZeroDiag|UnitDiag)) ? 0 : 1, \
+ IsUnitDiag = (Mode&UnitDiag) ? 1 : 0, \
+ IsZeroDiag = (Mode&ZeroDiag) ? 1 : 0, \
+ LowUp = IsLower ? Lower : Upper, \
+ conjA = ((RhsStorageOrder==ColMajor) && ConjugateRhs) ? 1 : 0 \
+ }; \
+\
+ static EIGEN_DONT_INLINE void run( \
+ Index _rows, Index _cols, Index _depth, \
+ const EIGTYPE* _lhs, Index lhsStride, \
+ const EIGTYPE* _rhs, Index rhsStride, \
+ EIGTYPE* res, Index resStride, \
+ EIGTYPE alpha) \
+ { \
+ Index diagSize = (std::min)(_cols,_depth); \
+ Index rows = _rows; \
+ Index depth = IsLower ? _depth : diagSize; \
+ Index cols = IsLower ? diagSize : _cols; \
+\
+ typedef Matrix<EIGTYPE, Dynamic, Dynamic, LhsStorageOrder> MatrixLhs; \
+ typedef Matrix<EIGTYPE, Dynamic, Dynamic, RhsStorageOrder> MatrixRhs; \
+\
+/* Non-square case - doesn't fit to MKL ?TRMM. Fall to default triangular product or call MKL ?GEMM*/ \
+ if (cols != depth) { \
+\
+ int nthr = mkl_domain_get_max_threads(MKL_BLAS); \
+\
+ if ((nthr==1) && (((std::max)(cols,depth)-diagSize)/(double)diagSize < 0.5)) { \
+ /* Most likely no benefit to call TRMM or GEMM from MKL*/ \
+ product_triangular_matrix_matrix<EIGTYPE,Index,Mode,false, \
+ LhsStorageOrder,ConjugateLhs, RhsStorageOrder, ConjugateRhs, ColMajor, BuiltIn>::run( \
+ _rows, _cols, _depth, _lhs, lhsStride, _rhs, rhsStride, res, resStride, alpha); \
+ /*std::cout << "TRMM_R: A is not square! Go to Eigen TRMM implementation!\n";*/ \
+ } else { \
+ /* Make sense to call GEMM */ \
+ Map<const MatrixRhs, 0, OuterStride<> > rhsMap(_rhs,depth,cols, OuterStride<>(rhsStride)); \
+ MatrixRhs aa_tmp=rhsMap.template triangularView<Mode>(); \
+ MKL_INT aStride = aa_tmp.outerStride(); \
+ gemm_blocking_space<ColMajor,EIGTYPE,EIGTYPE,Dynamic,Dynamic,Dynamic> blocking(_rows,_cols,_depth); \
+ general_matrix_matrix_product<Index,EIGTYPE,LhsStorageOrder,ConjugateLhs,EIGTYPE,RhsStorageOrder,ConjugateRhs,ColMajor>::run( \
+ rows, cols, depth, _lhs, lhsStride, aa_tmp.data(), aStride, res, resStride, alpha, blocking, 0); \
+\
+ /*std::cout << "TRMM_R: A is not square! Go to MKL GEMM implementation! " << nthr<<" \n";*/ \
+ } \
+ return; \
+ } \
+ char side = 'R', transa, uplo, diag = 'N'; \
+ EIGTYPE *b; \
+ const EIGTYPE *a; \
+ MKL_INT m, n, lda, ldb; \
+ MKLTYPE alpha_; \
+\
+/* Set alpha_*/ \
+ assign_scalar_eig2mkl<MKLTYPE, EIGTYPE>(alpha_, alpha); \
+\
+/* Set m, n */ \
+ m = (MKL_INT)rows; \
+ n = (MKL_INT)diagSize; \
+\
+/* Set trans */ \
+ transa = (RhsStorageOrder==RowMajor) ? ((ConjugateRhs) ? 'C' : 'T') : 'N'; \
+\
+/* Set b, ldb */ \
+ Map<const MatrixLhs, 0, OuterStride<> > lhs(_lhs,rows,depth,OuterStride<>(lhsStride)); \
+ MatrixX##EIGPREFIX b_tmp; \
+\
+ if (ConjugateLhs) b_tmp = lhs.conjugate(); else b_tmp = lhs; \
+ b = b_tmp.data(); \
+ ldb = b_tmp.outerStride(); \
+\
+/* Set uplo */ \
+ uplo = IsLower ? 'L' : 'U'; \
+ if (RhsStorageOrder==RowMajor) uplo = (uplo == 'L') ? 'U' : 'L'; \
+/* Set a, lda */ \
+ Map<const MatrixRhs, 0, OuterStride<> > rhs(_rhs,depth,cols, OuterStride<>(rhsStride)); \
+ MatrixRhs a_tmp; \
+\
+ if ((conjA!=0) || (SetDiag==0)) { \
+ if (conjA) a_tmp = rhs.conjugate(); else a_tmp = rhs; \
+ if (IsZeroDiag) \
+ a_tmp.diagonal().setZero(); \
+ else if (IsUnitDiag) \
+ a_tmp.diagonal().setOnes();\
+ a = a_tmp.data(); \
+ lda = a_tmp.outerStride(); \
+ } else { \
+ a = _rhs; \
+ lda = rhsStride; \
+ } \
+ /*std::cout << "TRMM_R: A is square! Go to MKL TRMM implementation! \n";*/ \
+/* call ?trmm*/ \
+ MKLPREFIX##trmm(&side, &uplo, &transa, &diag, &m, &n, &alpha_, (const MKLTYPE*)a, &lda, (MKLTYPE*)b, &ldb); \
+\
+/* Add op(a_triangular)*b into res*/ \
+ Map<MatrixX##EIGPREFIX, 0, OuterStride<> > res_tmp(res,rows,cols,OuterStride<>(resStride)); \
+ res_tmp=res_tmp+b_tmp; \
+ } \
+};
+
+EIGEN_MKL_TRMM_R(double, double, d, d)
+EIGEN_MKL_TRMM_R(dcomplex, MKL_Complex16, cd, z)
+EIGEN_MKL_TRMM_R(float, float, f, s)
+EIGEN_MKL_TRMM_R(scomplex, MKL_Complex8, cf, c)
+
+} // end namespace internal
+
+} // end namespace Eigen
+
+#endif // EIGEN_TRIANGULAR_MATRIX_MATRIX_MKL_H
diff --git a/Eigen/src/Core/products/TriangularMatrixVector.h b/Eigen/src/Core/products/TriangularMatrixVector.h
new file mode 100644
index 000000000..b1c10c201
--- /dev/null
+++ b/Eigen/src/Core/products/TriangularMatrixVector.h
@@ -0,0 +1,338 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra.
+//
+// Copyright (C) 2009 Gael Guennebaud <gael.guennebaud@inria.fr>
+//
+// This Source Code Form is subject to the terms of the Mozilla
+// Public License v. 2.0. If a copy of the MPL was not distributed
+// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+#ifndef EIGEN_TRIANGULARMATRIXVECTOR_H
+#define EIGEN_TRIANGULARMATRIXVECTOR_H
+
+namespace Eigen {
+
+namespace internal {
+
+template<typename Index, int Mode, typename LhsScalar, bool ConjLhs, typename RhsScalar, bool ConjRhs, int StorageOrder, int Version=Specialized>
+struct triangular_matrix_vector_product;
+
+template<typename Index, int Mode, typename LhsScalar, bool ConjLhs, typename RhsScalar, bool ConjRhs, int Version>
+struct triangular_matrix_vector_product<Index,Mode,LhsScalar,ConjLhs,RhsScalar,ConjRhs,ColMajor,Version>
+{
+ typedef typename scalar_product_traits<LhsScalar, RhsScalar>::ReturnType ResScalar;
+ enum {
+ IsLower = ((Mode&Lower)==Lower),
+ HasUnitDiag = (Mode & UnitDiag)==UnitDiag,
+ HasZeroDiag = (Mode & ZeroDiag)==ZeroDiag
+ };
+ static EIGEN_DONT_INLINE void run(Index _rows, Index _cols, const LhsScalar* _lhs, Index lhsStride,
+ const RhsScalar* _rhs, Index rhsIncr, ResScalar* _res, Index resIncr, ResScalar alpha)
+ {
+ static const Index PanelWidth = EIGEN_TUNE_TRIANGULAR_PANEL_WIDTH;
+ Index size = (std::min)(_rows,_cols);
+ Index rows = IsLower ? _rows : (std::min)(_rows,_cols);
+ Index cols = IsLower ? (std::min)(_rows,_cols) : _cols;
+
+ typedef Map<const Matrix<LhsScalar,Dynamic,Dynamic,ColMajor>, 0, OuterStride<> > LhsMap;
+ const LhsMap lhs(_lhs,rows,cols,OuterStride<>(lhsStride));
+ typename conj_expr_if<ConjLhs,LhsMap>::type cjLhs(lhs);
+
+ typedef Map<const Matrix<RhsScalar,Dynamic,1>, 0, InnerStride<> > RhsMap;
+ const RhsMap rhs(_rhs,cols,InnerStride<>(rhsIncr));
+ typename conj_expr_if<ConjRhs,RhsMap>::type cjRhs(rhs);
+
+ typedef Map<Matrix<ResScalar,Dynamic,1> > ResMap;
+ ResMap res(_res,rows);
+
+ for (Index pi=0; pi<size; pi+=PanelWidth)
+ {
+ Index actualPanelWidth = (std::min)(PanelWidth, size-pi);
+ for (Index k=0; k<actualPanelWidth; ++k)
+ {
+ Index i = pi + k;
+ Index s = IsLower ? ((HasUnitDiag||HasZeroDiag) ? i+1 : i ) : pi;
+ Index r = IsLower ? actualPanelWidth-k : k+1;
+ if ((!(HasUnitDiag||HasZeroDiag)) || (--r)>0)
+ res.segment(s,r) += (alpha * cjRhs.coeff(i)) * cjLhs.col(i).segment(s,r);
+ if (HasUnitDiag)
+ res.coeffRef(i) += alpha * cjRhs.coeff(i);
+ }
+ Index r = IsLower ? rows - pi - actualPanelWidth : pi;
+ if (r>0)
+ {
+ Index s = IsLower ? pi+actualPanelWidth : 0;
+ general_matrix_vector_product<Index,LhsScalar,ColMajor,ConjLhs,RhsScalar,ConjRhs,BuiltIn>::run(
+ r, actualPanelWidth,
+ &lhs.coeffRef(s,pi), lhsStride,
+ &rhs.coeffRef(pi), rhsIncr,
+ &res.coeffRef(s), resIncr, alpha);
+ }
+ }
+ if((!IsLower) && cols>size)
+ {
+ general_matrix_vector_product<Index,LhsScalar,ColMajor,ConjLhs,RhsScalar,ConjRhs>::run(
+ rows, cols-size,
+ &lhs.coeffRef(0,size), lhsStride,
+ &rhs.coeffRef(size), rhsIncr,
+ _res, resIncr, alpha);
+ }
+ }
+};
+
+template<typename Index, int Mode, typename LhsScalar, bool ConjLhs, typename RhsScalar, bool ConjRhs,int Version>
+struct triangular_matrix_vector_product<Index,Mode,LhsScalar,ConjLhs,RhsScalar,ConjRhs,RowMajor,Version>
+{
+ typedef typename scalar_product_traits<LhsScalar, RhsScalar>::ReturnType ResScalar;
+ enum {
+ IsLower = ((Mode&Lower)==Lower),
+ HasUnitDiag = (Mode & UnitDiag)==UnitDiag,
+ HasZeroDiag = (Mode & ZeroDiag)==ZeroDiag
+ };
+ static void run(Index _rows, Index _cols, const LhsScalar* _lhs, Index lhsStride,
+ const RhsScalar* _rhs, Index rhsIncr, ResScalar* _res, Index resIncr, ResScalar alpha)
+ {
+ static const Index PanelWidth = EIGEN_TUNE_TRIANGULAR_PANEL_WIDTH;
+ Index diagSize = (std::min)(_rows,_cols);
+ Index rows = IsLower ? _rows : diagSize;
+ Index cols = IsLower ? diagSize : _cols;
+
+ typedef Map<const Matrix<LhsScalar,Dynamic,Dynamic,RowMajor>, 0, OuterStride<> > LhsMap;
+ const LhsMap lhs(_lhs,rows,cols,OuterStride<>(lhsStride));
+ typename conj_expr_if<ConjLhs,LhsMap>::type cjLhs(lhs);
+
+ typedef Map<const Matrix<RhsScalar,Dynamic,1> > RhsMap;
+ const RhsMap rhs(_rhs,cols);
+ typename conj_expr_if<ConjRhs,RhsMap>::type cjRhs(rhs);
+
+ typedef Map<Matrix<ResScalar,Dynamic,1>, 0, InnerStride<> > ResMap;
+ ResMap res(_res,rows,InnerStride<>(resIncr));
+
+ for (Index pi=0; pi<diagSize; pi+=PanelWidth)
+ {
+ Index actualPanelWidth = (std::min)(PanelWidth, diagSize-pi);
+ for (Index k=0; k<actualPanelWidth; ++k)
+ {
+ Index i = pi + k;
+ Index s = IsLower ? pi : ((HasUnitDiag||HasZeroDiag) ? i+1 : i);
+ Index r = IsLower ? k+1 : actualPanelWidth-k;
+ if ((!(HasUnitDiag||HasZeroDiag)) || (--r)>0)
+ res.coeffRef(i) += alpha * (cjLhs.row(i).segment(s,r).cwiseProduct(cjRhs.segment(s,r).transpose())).sum();
+ if (HasUnitDiag)
+ res.coeffRef(i) += alpha * cjRhs.coeff(i);
+ }
+ Index r = IsLower ? pi : cols - pi - actualPanelWidth;
+ if (r>0)
+ {
+ Index s = IsLower ? 0 : pi + actualPanelWidth;
+ general_matrix_vector_product<Index,LhsScalar,RowMajor,ConjLhs,RhsScalar,ConjRhs,BuiltIn>::run(
+ actualPanelWidth, r,
+ &lhs.coeffRef(pi,s), lhsStride,
+ &rhs.coeffRef(s), rhsIncr,
+ &res.coeffRef(pi), resIncr, alpha);
+ }
+ }
+ if(IsLower && rows>diagSize)
+ {
+ general_matrix_vector_product<Index,LhsScalar,RowMajor,ConjLhs,RhsScalar,ConjRhs>::run(
+ rows-diagSize, cols,
+ &lhs.coeffRef(diagSize,0), lhsStride,
+ &rhs.coeffRef(0), rhsIncr,
+ &res.coeffRef(diagSize), resIncr, alpha);
+ }
+ }
+};
+
+/***************************************************************************
+* Wrapper to product_triangular_vector
+***************************************************************************/
+
+template<int Mode, bool LhsIsTriangular, typename Lhs, typename Rhs>
+struct traits<TriangularProduct<Mode,LhsIsTriangular,Lhs,false,Rhs,true> >
+ : traits<ProductBase<TriangularProduct<Mode,LhsIsTriangular,Lhs,false,Rhs,true>, Lhs, Rhs> >
+{};
+
+template<int Mode, bool LhsIsTriangular, typename Lhs, typename Rhs>
+struct traits<TriangularProduct<Mode,LhsIsTriangular,Lhs,true,Rhs,false> >
+ : traits<ProductBase<TriangularProduct<Mode,LhsIsTriangular,Lhs,true,Rhs,false>, Lhs, Rhs> >
+{};
+
+
+template<int StorageOrder>
+struct trmv_selector;
+
+} // end namespace internal
+
+template<int Mode, typename Lhs, typename Rhs>
+struct TriangularProduct<Mode,true,Lhs,false,Rhs,true>
+ : public ProductBase<TriangularProduct<Mode,true,Lhs,false,Rhs,true>, Lhs, Rhs >
+{
+ EIGEN_PRODUCT_PUBLIC_INTERFACE(TriangularProduct)
+
+ TriangularProduct(const Lhs& lhs, const Rhs& rhs) : Base(lhs,rhs) {}
+
+ template<typename Dest> void scaleAndAddTo(Dest& dst, Scalar alpha) const
+ {
+ eigen_assert(dst.rows()==m_lhs.rows() && dst.cols()==m_rhs.cols());
+
+ internal::trmv_selector<(int(internal::traits<Lhs>::Flags)&RowMajorBit) ? RowMajor : ColMajor>::run(*this, dst, alpha);
+ }
+};
+
+template<int Mode, typename Lhs, typename Rhs>
+struct TriangularProduct<Mode,false,Lhs,true,Rhs,false>
+ : public ProductBase<TriangularProduct<Mode,false,Lhs,true,Rhs,false>, Lhs, Rhs >
+{
+ EIGEN_PRODUCT_PUBLIC_INTERFACE(TriangularProduct)
+
+ TriangularProduct(const Lhs& lhs, const Rhs& rhs) : Base(lhs,rhs) {}
+
+ template<typename Dest> void scaleAndAddTo(Dest& dst, Scalar alpha) const
+ {
+ eigen_assert(dst.rows()==m_lhs.rows() && dst.cols()==m_rhs.cols());
+
+ typedef TriangularProduct<(Mode & (UnitDiag|ZeroDiag)) | ((Mode & Lower) ? Upper : Lower),true,Transpose<const Rhs>,false,Transpose<const Lhs>,true> TriangularProductTranspose;
+ Transpose<Dest> dstT(dst);
+ internal::trmv_selector<(int(internal::traits<Rhs>::Flags)&RowMajorBit) ? ColMajor : RowMajor>::run(
+ TriangularProductTranspose(m_rhs.transpose(),m_lhs.transpose()), dstT, alpha);
+ }
+};
+
+namespace internal {
+
+// TODO: find a way to factorize this piece of code with gemv_selector since the logic is exactly the same.
+
+template<> struct trmv_selector<ColMajor>
+{
+ template<int Mode, typename Lhs, typename Rhs, typename Dest>
+ static void run(const TriangularProduct<Mode,true,Lhs,false,Rhs,true>& prod, Dest& dest, typename TriangularProduct<Mode,true,Lhs,false,Rhs,true>::Scalar alpha)
+ {
+ typedef TriangularProduct<Mode,true,Lhs,false,Rhs,true> ProductType;
+ 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<Matrix<ResScalar,Dynamic,1>, Aligned> MappedDest;
+
+ typename internal::add_const_on_value_type<ActualLhsType>::type actualLhs = LhsBlasTraits::extract(prod.lhs());
+ typename internal::add_const_on_value_type<ActualRhsType>::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<Scalar>::size==1
+ // on, the other hand it is good for the cache to pack the vector anyways...
+ EvalToDestAtCompileTime = Dest::InnerStrideAtCompileTime==1,
+ ComplexByReal = (NumTraits<LhsScalar>::IsComplex) && (!NumTraits<RhsScalar>::IsComplex),
+ MightCannotUseDest = (Dest::InnerStrideAtCompileTime!=1) || ComplexByReal
+ };
+
+ gemv_static_vector_if<ResScalar,Dest::SizeAtCompileTime,Dest::MaxSizeAtCompileTime,MightCannotUseDest> static_dest;
+
+ bool alphaIsCompatible = (!ComplexByReal) || (imag(actualAlpha)==RealScalar(0));
+ bool evalToDest = EvalToDestAtCompileTime && alphaIsCompatible;
+
+ RhsScalar compatibleAlpha = get_factor<ResScalar,RhsScalar>::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;
+ }
+
+ internal::triangular_matrix_vector_product
+ <Index,Mode,
+ LhsScalar, LhsBlasTraits::NeedToConjugate,
+ RhsScalar, RhsBlasTraits::NeedToConjugate,
+ ColMajor>
+ ::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 trmv_selector<RowMajor>
+{
+ template<int Mode, typename Lhs, typename Rhs, typename Dest>
+ static void run(const TriangularProduct<Mode,true,Lhs,false,Rhs,true>& prod, Dest& dest, typename TriangularProduct<Mode,true,Lhs,false,Rhs,true>::Scalar alpha)
+ {
+ typedef TriangularProduct<Mode,true,Lhs,false,Rhs,true> ProductType;
+ 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<ActualLhsType>::type actualLhs = LhsBlasTraits::extract(prod.lhs());
+ typename add_const<ActualRhsType>::type actualRhs = RhsBlasTraits::extract(prod.rhs());
+
+ ResScalar actualAlpha = alpha * LhsBlasTraits::extractScalarFactor(prod.lhs())
+ * RhsBlasTraits::extractScalarFactor(prod.rhs());
+
+ enum {
+ DirectlyUseRhs = _ActualRhsType::InnerStrideAtCompileTime==1
+ };
+
+ gemv_static_vector_if<RhsScalar,_ActualRhsType::SizeAtCompileTime,_ActualRhsType::MaxSizeAtCompileTime,!DirectlyUseRhs> static_rhs;
+
+ ei_declare_aligned_stack_constructed_variable(RhsScalar,actualRhsPtr,actualRhs.size(),
+ DirectlyUseRhs ? const_cast<RhsScalar*>(actualRhs.data()) : static_rhs.data());
+
+ if(!DirectlyUseRhs)
+ {
+ #ifdef EIGEN_DENSE_STORAGE_CTOR_PLUGIN
+ int size = actualRhs.size();
+ EIGEN_DENSE_STORAGE_CTOR_PLUGIN
+ #endif
+ Map<typename _ActualRhsType::PlainObject>(actualRhsPtr, actualRhs.size()) = actualRhs;
+ }
+
+ internal::triangular_matrix_vector_product
+ <Index,Mode,
+ LhsScalar, LhsBlasTraits::NeedToConjugate,
+ RhsScalar, RhsBlasTraits::NeedToConjugate,
+ RowMajor>
+ ::run(actualLhs.rows(),actualLhs.cols(),
+ actualLhs.data(),actualLhs.outerStride(),
+ actualRhsPtr,1,
+ dest.data(),dest.innerStride(),
+ actualAlpha);
+ }
+};
+
+} // end namespace internal
+
+} // end namespace Eigen
+
+#endif // EIGEN_TRIANGULARMATRIXVECTOR_H
diff --git a/Eigen/src/Core/products/TriangularMatrixVector_MKL.h b/Eigen/src/Core/products/TriangularMatrixVector_MKL.h
new file mode 100644
index 000000000..3589b8c5e
--- /dev/null
+++ b/Eigen/src/Core/products/TriangularMatrixVector_MKL.h
@@ -0,0 +1,247 @@
+/*
+ Copyright (c) 2011, Intel Corporation. All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without modification,
+ are permitted provided that the following conditions are met:
+
+ * Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+ * Neither the name of Intel Corporation nor the names of its contributors may
+ be used to endorse or promote products derived from this software without
+ specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+ ********************************************************************************
+ * Content : Eigen bindings to Intel(R) MKL
+ * Triangular matrix-vector product functionality based on ?TRMV.
+ ********************************************************************************
+*/
+
+#ifndef EIGEN_TRIANGULAR_MATRIX_VECTOR_MKL_H
+#define EIGEN_TRIANGULAR_MATRIX_VECTOR_MKL_H
+
+namespace Eigen {
+
+namespace internal {
+
+/**********************************************************************
+* This file implements triangular matrix-vector multiplication using BLAS
+**********************************************************************/
+
+// trmv/hemv specialization
+
+template<typename Index, int Mode, typename LhsScalar, bool ConjLhs, typename RhsScalar, bool ConjRhs, int StorageOrder>
+struct triangular_matrix_vector_product_trmv :
+ triangular_matrix_vector_product<Index,Mode,LhsScalar,ConjLhs,RhsScalar,ConjRhs,StorageOrder,BuiltIn> {};
+
+#define EIGEN_MKL_TRMV_SPECIALIZE(Scalar) \
+template<typename Index, int Mode, bool ConjLhs, bool ConjRhs> \
+struct triangular_matrix_vector_product<Index,Mode,Scalar,ConjLhs,Scalar,ConjRhs,ColMajor,Specialized> { \
+ static EIGEN_DONT_INLINE void run(Index _rows, Index _cols, const Scalar* _lhs, Index lhsStride, \
+ const Scalar* _rhs, Index rhsIncr, Scalar* _res, Index resIncr, Scalar alpha) { \
+ triangular_matrix_vector_product_trmv<Index,Mode,Scalar,ConjLhs,Scalar,ConjRhs,ColMajor>::run( \
+ _rows, _cols, _lhs, lhsStride, _rhs, rhsIncr, _res, resIncr, alpha); \
+ } \
+}; \
+template<typename Index, int Mode, bool ConjLhs, bool ConjRhs> \
+struct triangular_matrix_vector_product<Index,Mode,Scalar,ConjLhs,Scalar,ConjRhs,RowMajor,Specialized> { \
+ static EIGEN_DONT_INLINE void run(Index _rows, Index _cols, const Scalar* _lhs, Index lhsStride, \
+ const Scalar* _rhs, Index rhsIncr, Scalar* _res, Index resIncr, Scalar alpha) { \
+ triangular_matrix_vector_product_trmv<Index,Mode,Scalar,ConjLhs,Scalar,ConjRhs,RowMajor>::run( \
+ _rows, _cols, _lhs, lhsStride, _rhs, rhsIncr, _res, resIncr, alpha); \
+ } \
+};
+
+EIGEN_MKL_TRMV_SPECIALIZE(double)
+EIGEN_MKL_TRMV_SPECIALIZE(float)
+EIGEN_MKL_TRMV_SPECIALIZE(dcomplex)
+EIGEN_MKL_TRMV_SPECIALIZE(scomplex)
+
+// implements col-major: res += alpha * op(triangular) * vector
+#define EIGEN_MKL_TRMV_CM(EIGTYPE, MKLTYPE, EIGPREFIX, MKLPREFIX) \
+template<typename Index, int Mode, bool ConjLhs, bool ConjRhs> \
+struct triangular_matrix_vector_product_trmv<Index,Mode,EIGTYPE,ConjLhs,EIGTYPE,ConjRhs,ColMajor> { \
+ enum { \
+ IsLower = (Mode&Lower) == Lower, \
+ SetDiag = (Mode&(ZeroDiag|UnitDiag)) ? 0 : 1, \
+ IsUnitDiag = (Mode&UnitDiag) ? 1 : 0, \
+ IsZeroDiag = (Mode&ZeroDiag) ? 1 : 0, \
+ LowUp = IsLower ? Lower : Upper \
+ }; \
+ static EIGEN_DONT_INLINE void run(Index _rows, Index _cols, const EIGTYPE* _lhs, Index lhsStride, \
+ const EIGTYPE* _rhs, Index rhsIncr, EIGTYPE* _res, Index resIncr, EIGTYPE alpha, level3_blocking<EIGTYPE,EIGTYPE>& blocking) \
+ { \
+ if (ConjLhs || IsZeroDiag) { \
+ triangular_matrix_vector_product<Index,Mode,EIGTYPE,ConjLhs,EIGTYPE,ConjRhs,ColMajor,BuiltIn>::run( \
+ _rows, _cols, _lhs, lhsStride, _rhs, rhsIncr, _res, resIncr, alpha, blocking); \
+ return; \
+ }\
+ Index size = (std::min)(_rows,_cols); \
+ Index rows = IsLower ? _rows : size; \
+ Index cols = IsLower ? size : _cols; \
+\
+ typedef VectorX##EIGPREFIX VectorRhs; \
+ EIGTYPE *x, *y;\
+\
+/* Set x*/ \
+ Map<const VectorRhs, 0, InnerStride<> > rhs(_rhs,cols,InnerStride<>(rhsIncr)); \
+ VectorRhs x_tmp; \
+ if (ConjRhs) x_tmp = rhs.conjugate(); else x_tmp = rhs; \
+ x = x_tmp.data(); \
+\
+/* Square part handling */\
+\
+ char trans, uplo, diag; \
+ MKL_INT m, n, lda, incx, incy; \
+ EIGTYPE const *a; \
+ MKLTYPE alpha_, beta_; \
+ assign_scalar_eig2mkl<MKLTYPE, EIGTYPE>(alpha_, alpha); \
+ assign_scalar_eig2mkl<MKLTYPE, EIGTYPE>(beta_, EIGTYPE(1)); \
+\
+/* Set m, n */ \
+ n = (MKL_INT)size; \
+ lda = lhsStride; \
+ incx = 1; \
+ incy = resIncr; \
+\
+/* Set uplo, trans and diag*/ \
+ trans = 'N'; \
+ uplo = IsLower ? 'L' : 'U'; \
+ diag = IsUnitDiag ? 'U' : 'N'; \
+\
+/* call ?TRMV*/ \
+ MKLPREFIX##trmv(&uplo, &trans, &diag, &n, (const MKLTYPE*)_lhs, &lda, (MKLTYPE*)x, &incx); \
+\
+/* Add op(a_tr)rhs into res*/ \
+ MKLPREFIX##axpy(&n, &alpha_,(const MKLTYPE*)x, &incx, (MKLTYPE*)_res, &incy); \
+/* Non-square case - doesn't fit to MKL ?TRMV. Fall to default triangular product*/ \
+ if (size<(std::max)(rows,cols)) { \
+ typedef Matrix<EIGTYPE, Dynamic, Dynamic> MatrixLhs; \
+ if (ConjRhs) x_tmp = rhs.conjugate(); else x_tmp = rhs; \
+ x = x_tmp.data(); \
+ if (size<rows) { \
+ y = _res + size*resIncr; \
+ a = _lhs + size; \
+ m = rows-size; \
+ n = size; \
+ } \
+ else { \
+ x += size; \
+ y = _res; \
+ a = _lhs + size*lda; \
+ m = size; \
+ n = cols-size; \
+ } \
+ MKLPREFIX##gemv(&trans, &m, &n, &alpha_, (const MKLTYPE*)a, &lda, (const MKLTYPE*)x, &incx, &beta_, (MKLTYPE*)y, &incy); \
+ } \
+ } \
+};
+
+EIGEN_MKL_TRMV_CM(double, double, d, d)
+EIGEN_MKL_TRMV_CM(dcomplex, MKL_Complex16, cd, z)
+EIGEN_MKL_TRMV_CM(float, float, f, s)
+EIGEN_MKL_TRMV_CM(scomplex, MKL_Complex8, cf, c)
+
+// implements row-major: res += alpha * op(triangular) * vector
+#define EIGEN_MKL_TRMV_RM(EIGTYPE, MKLTYPE, EIGPREFIX, MKLPREFIX) \
+template<typename Index, int Mode, bool ConjLhs, bool ConjRhs> \
+struct triangular_matrix_vector_product_trmv<Index,Mode,EIGTYPE,ConjLhs,EIGTYPE,ConjRhs,RowMajor> { \
+ enum { \
+ IsLower = (Mode&Lower) == Lower, \
+ SetDiag = (Mode&(ZeroDiag|UnitDiag)) ? 0 : 1, \
+ IsUnitDiag = (Mode&UnitDiag) ? 1 : 0, \
+ IsZeroDiag = (Mode&ZeroDiag) ? 1 : 0, \
+ LowUp = IsLower ? Lower : Upper \
+ }; \
+ static EIGEN_DONT_INLINE void run(Index _rows, Index _cols, const EIGTYPE* _lhs, Index lhsStride, \
+ const EIGTYPE* _rhs, Index rhsIncr, EIGTYPE* _res, Index resIncr, EIGTYPE alpha, level3_blocking<EIGTYPE,EIGTYPE>& blocking) \
+ { \
+ if (IsZeroDiag) { \
+ triangular_matrix_vector_product<Index,Mode,EIGTYPE,ConjLhs,EIGTYPE,ConjRhs,RowMajor,BuiltIn>::run( \
+ _rows, _cols, _lhs, lhsStride, _rhs, rhsIncr, _res, resIncr, alpha, blocking); \
+ return; \
+ }\
+ Index size = (std::min)(_rows,_cols); \
+ Index rows = IsLower ? _rows : size; \
+ Index cols = IsLower ? size : _cols; \
+\
+ typedef VectorX##EIGPREFIX VectorRhs; \
+ EIGTYPE *x, *y;\
+\
+/* Set x*/ \
+ Map<const VectorRhs, 0, InnerStride<> > rhs(_rhs,cols,InnerStride<>(rhsIncr)); \
+ VectorRhs x_tmp; \
+ if (ConjRhs) x_tmp = rhs.conjugate(); else x_tmp = rhs; \
+ x = x_tmp.data(); \
+\
+/* Square part handling */\
+\
+ char trans, uplo, diag; \
+ MKL_INT m, n, lda, incx, incy; \
+ EIGTYPE const *a; \
+ MKLTYPE alpha_, beta_; \
+ assign_scalar_eig2mkl<MKLTYPE, EIGTYPE>(alpha_, alpha); \
+ assign_scalar_eig2mkl<MKLTYPE, EIGTYPE>(beta_, EIGTYPE(1)); \
+\
+/* Set m, n */ \
+ n = (MKL_INT)size; \
+ lda = lhsStride; \
+ incx = 1; \
+ incy = resIncr; \
+\
+/* Set uplo, trans and diag*/ \
+ trans = ConjLhs ? 'C' : 'T'; \
+ uplo = IsLower ? 'U' : 'L'; \
+ diag = IsUnitDiag ? 'U' : 'N'; \
+\
+/* call ?TRMV*/ \
+ MKLPREFIX##trmv(&uplo, &trans, &diag, &n, (const MKLTYPE*)_lhs, &lda, (MKLTYPE*)x, &incx); \
+\
+/* Add op(a_tr)rhs into res*/ \
+ MKLPREFIX##axpy(&n, &alpha_,(const MKLTYPE*)x, &incx, (MKLTYPE*)_res, &incy); \
+/* Non-square case - doesn't fit to MKL ?TRMV. Fall to default triangular product*/ \
+ if (size<(std::max)(rows,cols)) { \
+ typedef Matrix<EIGTYPE, Dynamic, Dynamic> MatrixLhs; \
+ if (ConjRhs) x_tmp = rhs.conjugate(); else x_tmp = rhs; \
+ x = x_tmp.data(); \
+ if (size<rows) { \
+ y = _res + size*resIncr; \
+ a = _lhs + size*lda; \
+ m = rows-size; \
+ n = size; \
+ } \
+ else { \
+ x += size; \
+ y = _res; \
+ a = _lhs + size; \
+ m = size; \
+ n = cols-size; \
+ } \
+ MKLPREFIX##gemv(&trans, &n, &m, &alpha_, (const MKLTYPE*)a, &lda, (const MKLTYPE*)x, &incx, &beta_, (MKLTYPE*)y, &incy); \
+ } \
+ } \
+};
+
+EIGEN_MKL_TRMV_RM(double, double, d, d)
+EIGEN_MKL_TRMV_RM(dcomplex, MKL_Complex16, cd, z)
+EIGEN_MKL_TRMV_RM(float, float, f, s)
+EIGEN_MKL_TRMV_RM(scomplex, MKL_Complex8, cf, c)
+
+} // end namespase internal
+
+} // end namespace Eigen
+
+#endif // EIGEN_TRIANGULAR_MATRIX_VECTOR_MKL_H
diff --git a/Eigen/src/Core/products/TriangularSolverMatrix.h b/Eigen/src/Core/products/TriangularSolverMatrix.h
new file mode 100644
index 000000000..a49ea3183
--- /dev/null
+++ b/Eigen/src/Core/products/TriangularSolverMatrix.h
@@ -0,0 +1,317 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra.
+//
+// Copyright (C) 2009 Gael Guennebaud <gael.guennebaud@inria.fr>
+//
+// This Source Code Form is subject to the terms of the Mozilla
+// Public License v. 2.0. If a copy of the MPL was not distributed
+// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+#ifndef EIGEN_TRIANGULAR_SOLVER_MATRIX_H
+#define EIGEN_TRIANGULAR_SOLVER_MATRIX_H
+
+namespace Eigen {
+
+namespace internal {
+
+// if the rhs is row major, let's transpose the product
+template <typename Scalar, typename Index, int Side, int Mode, bool Conjugate, int TriStorageOrder>
+struct triangular_solve_matrix<Scalar,Index,Side,Mode,Conjugate,TriStorageOrder,RowMajor>
+{
+ static EIGEN_DONT_INLINE void run(
+ Index size, Index cols,
+ const Scalar* tri, Index triStride,
+ Scalar* _other, Index otherStride,
+ level3_blocking<Scalar,Scalar>& blocking)
+ {
+ triangular_solve_matrix<
+ Scalar, Index, Side==OnTheLeft?OnTheRight:OnTheLeft,
+ (Mode&UnitDiag) | ((Mode&Upper) ? Lower : Upper),
+ NumTraits<Scalar>::IsComplex && Conjugate,
+ TriStorageOrder==RowMajor ? ColMajor : RowMajor, ColMajor>
+ ::run(size, cols, tri, triStride, _other, otherStride, blocking);
+ }
+};
+
+/* Optimized triangular solver with multiple right hand side and the triangular matrix on the left
+ */
+template <typename Scalar, typename Index, int Mode, bool Conjugate, int TriStorageOrder>
+struct triangular_solve_matrix<Scalar,Index,OnTheLeft,Mode,Conjugate,TriStorageOrder,ColMajor>
+{
+ static EIGEN_DONT_INLINE void run(
+ Index size, Index otherSize,
+ const Scalar* _tri, Index triStride,
+ Scalar* _other, Index otherStride,
+ level3_blocking<Scalar,Scalar>& blocking)
+ {
+ Index cols = otherSize;
+ const_blas_data_mapper<Scalar, Index, TriStorageOrder> tri(_tri,triStride);
+ blas_data_mapper<Scalar, Index, ColMajor> other(_other,otherStride);
+
+ typedef gebp_traits<Scalar,Scalar> Traits;
+ enum {
+ SmallPanelWidth = EIGEN_PLAIN_ENUM_MAX(Traits::mr,Traits::nr),
+ IsLower = (Mode&Lower) == Lower
+ };
+
+ Index kc = blocking.kc(); // cache block size along the K direction
+ Index mc = (std::min)(size,blocking.mc()); // cache block size along the M direction
+
+ std::size_t sizeA = kc*mc;
+ std::size_t sizeB = kc*cols;
+ std::size_t sizeW = kc*Traits::WorkSpaceFactor;
+
+ ei_declare_aligned_stack_constructed_variable(Scalar, blockA, sizeA, blocking.blockA());
+ ei_declare_aligned_stack_constructed_variable(Scalar, blockB, sizeB, blocking.blockB());
+ ei_declare_aligned_stack_constructed_variable(Scalar, blockW, sizeW, blocking.blockW());
+
+ conj_if<Conjugate> conj;
+ gebp_kernel<Scalar, Scalar, Index, Traits::mr, Traits::nr, Conjugate, false> gebp_kernel;
+ gemm_pack_lhs<Scalar, Index, Traits::mr, Traits::LhsProgress, TriStorageOrder> pack_lhs;
+ gemm_pack_rhs<Scalar, Index, Traits::nr, ColMajor, false, true> pack_rhs;
+
+ // the goal here is to subdivise the Rhs panels such that we keep some cache
+ // coherence when accessing the rhs elements
+ std::ptrdiff_t l1, l2;
+ manage_caching_sizes(GetAction, &l1, &l2);
+ Index subcols = cols>0 ? l2/(4 * sizeof(Scalar) * otherStride) : 0;
+ subcols = std::max<Index>((subcols/Traits::nr)*Traits::nr, Traits::nr);
+
+ for(Index k2=IsLower ? 0 : size;
+ IsLower ? k2<size : k2>0;
+ IsLower ? k2+=kc : k2-=kc)
+ {
+ const Index actual_kc = (std::min)(IsLower ? size-k2 : k2, kc);
+
+ // We have selected and packed a big horizontal panel R1 of rhs. Let B be the packed copy of this panel,
+ // and R2 the remaining part of rhs. The corresponding vertical panel of lhs is split into
+ // A11 (the triangular part) and A21 the remaining rectangular part.
+ // Then the high level algorithm is:
+ // - B = R1 => general block copy (done during the next step)
+ // - R1 = A11^-1 B => tricky part
+ // - update B from the new R1 => actually this has to be performed continuously during the above step
+ // - R2 -= A21 * B => GEPP
+
+ // The tricky part: compute R1 = A11^-1 B while updating B from R1
+ // The idea is to split A11 into multiple small vertical panels.
+ // Each panel can be split into a small triangular part T1k which is processed without optimization,
+ // and the remaining small part T2k which is processed using gebp with appropriate block strides
+ for(Index j2=0; j2<cols; j2+=subcols)
+ {
+ Index actual_cols = (std::min)(cols-j2,subcols);
+ // for each small vertical panels [T1k^T, T2k^T]^T of lhs
+ for (Index k1=0; k1<actual_kc; k1+=SmallPanelWidth)
+ {
+ Index actualPanelWidth = std::min<Index>(actual_kc-k1, SmallPanelWidth);
+ // tr solve
+ for (Index k=0; k<actualPanelWidth; ++k)
+ {
+ // TODO write a small kernel handling this (can be shared with trsv)
+ Index i = IsLower ? k2+k1+k : k2-k1-k-1;
+ Index s = IsLower ? k2+k1 : i+1;
+ Index rs = actualPanelWidth - k - 1; // remaining size
+
+ Scalar a = (Mode & UnitDiag) ? Scalar(1) : Scalar(1)/conj(tri(i,i));
+ for (Index j=j2; j<j2+actual_cols; ++j)
+ {
+ if (TriStorageOrder==RowMajor)
+ {
+ Scalar b(0);
+ const Scalar* l = &tri(i,s);
+ Scalar* r = &other(s,j);
+ for (Index i3=0; i3<k; ++i3)
+ b += conj(l[i3]) * r[i3];
+
+ other(i,j) = (other(i,j) - b)*a;
+ }
+ else
+ {
+ Index s = IsLower ? i+1 : i-rs;
+ Scalar b = (other(i,j) *= a);
+ Scalar* r = &other(s,j);
+ const Scalar* l = &tri(s,i);
+ for (Index i3=0;i3<rs;++i3)
+ r[i3] -= b * conj(l[i3]);
+ }
+ }
+ }
+
+ Index lengthTarget = actual_kc-k1-actualPanelWidth;
+ Index startBlock = IsLower ? k2+k1 : k2-k1-actualPanelWidth;
+ Index blockBOffset = IsLower ? k1 : lengthTarget;
+
+ // update the respective rows of B from other
+ pack_rhs(blockB+actual_kc*j2, &other(startBlock,j2), otherStride, actualPanelWidth, actual_cols, actual_kc, blockBOffset);
+
+ // GEBP
+ if (lengthTarget>0)
+ {
+ Index startTarget = IsLower ? k2+k1+actualPanelWidth : k2-actual_kc;
+
+ pack_lhs(blockA, &tri(startTarget,startBlock), triStride, actualPanelWidth, lengthTarget);
+
+ gebp_kernel(&other(startTarget,j2), otherStride, blockA, blockB+actual_kc*j2, lengthTarget, actualPanelWidth, actual_cols, Scalar(-1),
+ actualPanelWidth, actual_kc, 0, blockBOffset, blockW);
+ }
+ }
+ }
+
+ // R2 -= A21 * B => GEPP
+ {
+ Index start = IsLower ? k2+kc : 0;
+ Index end = IsLower ? size : k2-kc;
+ for(Index i2=start; i2<end; i2+=mc)
+ {
+ const Index actual_mc = (std::min)(mc,end-i2);
+ if (actual_mc>0)
+ {
+ pack_lhs(blockA, &tri(i2, IsLower ? k2 : k2-kc), triStride, actual_kc, actual_mc);
+
+ gebp_kernel(_other+i2, otherStride, blockA, blockB, actual_mc, actual_kc, cols, Scalar(-1), -1, -1, 0, 0, blockW);
+ }
+ }
+ }
+ }
+ }
+};
+
+/* Optimized triangular solver with multiple left hand sides and the trinagular matrix on the right
+ */
+template <typename Scalar, typename Index, int Mode, bool Conjugate, int TriStorageOrder>
+struct triangular_solve_matrix<Scalar,Index,OnTheRight,Mode,Conjugate,TriStorageOrder,ColMajor>
+{
+ static EIGEN_DONT_INLINE void run(
+ Index size, Index otherSize,
+ const Scalar* _tri, Index triStride,
+ Scalar* _other, Index otherStride,
+ level3_blocking<Scalar,Scalar>& blocking)
+ {
+ Index rows = otherSize;
+ const_blas_data_mapper<Scalar, Index, TriStorageOrder> rhs(_tri,triStride);
+ blas_data_mapper<Scalar, Index, ColMajor> lhs(_other,otherStride);
+
+ typedef gebp_traits<Scalar,Scalar> Traits;
+ enum {
+ RhsStorageOrder = TriStorageOrder,
+ SmallPanelWidth = EIGEN_PLAIN_ENUM_MAX(Traits::mr,Traits::nr),
+ IsLower = (Mode&Lower) == Lower
+ };
+
+ Index kc = blocking.kc(); // cache block size along the K direction
+ Index mc = (std::min)(rows,blocking.mc()); // cache block size along the M direction
+
+ std::size_t sizeA = kc*mc;
+ std::size_t sizeB = kc*size;
+ std::size_t sizeW = kc*Traits::WorkSpaceFactor;
+
+ ei_declare_aligned_stack_constructed_variable(Scalar, blockA, sizeA, blocking.blockA());
+ ei_declare_aligned_stack_constructed_variable(Scalar, blockB, sizeB, blocking.blockB());
+ ei_declare_aligned_stack_constructed_variable(Scalar, blockW, sizeW, blocking.blockW());
+
+ conj_if<Conjugate> conj;
+ gebp_kernel<Scalar,Scalar, Index, Traits::mr, Traits::nr, false, Conjugate> gebp_kernel;
+ gemm_pack_rhs<Scalar, Index, Traits::nr,RhsStorageOrder> pack_rhs;
+ gemm_pack_rhs<Scalar, Index, Traits::nr,RhsStorageOrder,false,true> pack_rhs_panel;
+ gemm_pack_lhs<Scalar, Index, Traits::mr, Traits::LhsProgress, ColMajor, false, true> pack_lhs_panel;
+
+ for(Index k2=IsLower ? size : 0;
+ IsLower ? k2>0 : k2<size;
+ IsLower ? k2-=kc : k2+=kc)
+ {
+ const Index actual_kc = (std::min)(IsLower ? k2 : size-k2, kc);
+ Index actual_k2 = IsLower ? k2-actual_kc : k2 ;
+
+ Index startPanel = IsLower ? 0 : k2+actual_kc;
+ Index rs = IsLower ? actual_k2 : size - actual_k2 - actual_kc;
+ Scalar* geb = blockB+actual_kc*actual_kc;
+
+ if (rs>0) pack_rhs(geb, &rhs(actual_k2,startPanel), triStride, actual_kc, rs);
+
+ // triangular packing (we only pack the panels off the diagonal,
+ // neglecting the blocks overlapping the diagonal
+ {
+ for (Index j2=0; j2<actual_kc; j2+=SmallPanelWidth)
+ {
+ Index actualPanelWidth = std::min<Index>(actual_kc-j2, SmallPanelWidth);
+ Index actual_j2 = actual_k2 + j2;
+ Index panelOffset = IsLower ? j2+actualPanelWidth : 0;
+ Index panelLength = IsLower ? actual_kc-j2-actualPanelWidth : j2;
+
+ if (panelLength>0)
+ pack_rhs_panel(blockB+j2*actual_kc,
+ &rhs(actual_k2+panelOffset, actual_j2), triStride,
+ panelLength, actualPanelWidth,
+ actual_kc, panelOffset);
+ }
+ }
+
+ for(Index i2=0; i2<rows; i2+=mc)
+ {
+ const Index actual_mc = (std::min)(mc,rows-i2);
+
+ // triangular solver kernel
+ {
+ // for each small block of the diagonal (=> vertical panels of rhs)
+ for (Index j2 = IsLower
+ ? (actual_kc - ((actual_kc%SmallPanelWidth) ? Index(actual_kc%SmallPanelWidth)
+ : Index(SmallPanelWidth)))
+ : 0;
+ IsLower ? j2>=0 : j2<actual_kc;
+ IsLower ? j2-=SmallPanelWidth : j2+=SmallPanelWidth)
+ {
+ Index actualPanelWidth = std::min<Index>(actual_kc-j2, SmallPanelWidth);
+ Index absolute_j2 = actual_k2 + j2;
+ Index panelOffset = IsLower ? j2+actualPanelWidth : 0;
+ Index panelLength = IsLower ? actual_kc - j2 - actualPanelWidth : j2;
+
+ // GEBP
+ if(panelLength>0)
+ {
+ gebp_kernel(&lhs(i2,absolute_j2), otherStride,
+ blockA, blockB+j2*actual_kc,
+ actual_mc, panelLength, actualPanelWidth,
+ Scalar(-1),
+ actual_kc, actual_kc, // strides
+ panelOffset, panelOffset, // offsets
+ blockW); // workspace
+ }
+
+ // unblocked triangular solve
+ for (Index k=0; k<actualPanelWidth; ++k)
+ {
+ Index j = IsLower ? absolute_j2+actualPanelWidth-k-1 : absolute_j2+k;
+
+ Scalar* r = &lhs(i2,j);
+ for (Index k3=0; k3<k; ++k3)
+ {
+ Scalar b = conj(rhs(IsLower ? j+1+k3 : absolute_j2+k3,j));
+ Scalar* a = &lhs(i2,IsLower ? j+1+k3 : absolute_j2+k3);
+ for (Index i=0; i<actual_mc; ++i)
+ r[i] -= a[i] * b;
+ }
+ Scalar b = (Mode & UnitDiag) ? Scalar(1) : Scalar(1)/conj(rhs(j,j));
+ for (Index i=0; i<actual_mc; ++i)
+ r[i] *= b;
+ }
+
+ // pack the just computed part of lhs to A
+ pack_lhs_panel(blockA, _other+absolute_j2*otherStride+i2, otherStride,
+ actualPanelWidth, actual_mc,
+ actual_kc, j2);
+ }
+ }
+
+ if (rs>0)
+ gebp_kernel(_other+i2+startPanel*otherStride, otherStride, blockA, geb,
+ actual_mc, actual_kc, rs, Scalar(-1),
+ -1, -1, 0, 0, blockW);
+ }
+ }
+ }
+};
+
+} // end namespace internal
+
+} // end namespace Eigen
+
+#endif // EIGEN_TRIANGULAR_SOLVER_MATRIX_H
diff --git a/Eigen/src/Core/products/TriangularSolverMatrix_MKL.h b/Eigen/src/Core/products/TriangularSolverMatrix_MKL.h
new file mode 100644
index 000000000..a4f508b2e
--- /dev/null
+++ b/Eigen/src/Core/products/TriangularSolverMatrix_MKL.h
@@ -0,0 +1,155 @@
+/*
+ Copyright (c) 2011, Intel Corporation. All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without modification,
+ are permitted provided that the following conditions are met:
+
+ * Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+ * Neither the name of Intel Corporation nor the names of its contributors may
+ be used to endorse or promote products derived from this software without
+ specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+ ********************************************************************************
+ * Content : Eigen bindings to Intel(R) MKL
+ * Triangular matrix * matrix product functionality based on ?TRMM.
+ ********************************************************************************
+*/
+
+#ifndef EIGEN_TRIANGULAR_SOLVER_MATRIX_MKL_H
+#define EIGEN_TRIANGULAR_SOLVER_MATRIX_MKL_H
+
+namespace Eigen {
+
+namespace internal {
+
+// implements LeftSide op(triangular)^-1 * general
+#define EIGEN_MKL_TRSM_L(EIGTYPE, MKLTYPE, MKLPREFIX) \
+template <typename Index, int Mode, bool Conjugate, int TriStorageOrder> \
+struct triangular_solve_matrix<EIGTYPE,Index,OnTheLeft,Mode,Conjugate,TriStorageOrder,ColMajor> \
+{ \
+ enum { \
+ IsLower = (Mode&Lower) == Lower, \
+ IsUnitDiag = (Mode&UnitDiag) ? 1 : 0, \
+ IsZeroDiag = (Mode&ZeroDiag) ? 1 : 0, \
+ conjA = ((TriStorageOrder==ColMajor) && Conjugate) ? 1 : 0 \
+ }; \
+ static EIGEN_DONT_INLINE void run( \
+ Index size, Index otherSize, \
+ const EIGTYPE* _tri, Index triStride, \
+ EIGTYPE* _other, Index otherStride, level3_blocking<EIGTYPE,EIGTYPE>& /*blocking*/) \
+ { \
+ MKL_INT m = size, n = otherSize, lda, ldb; \
+ char side = 'L', uplo, diag='N', transa; \
+ /* Set alpha_ */ \
+ MKLTYPE alpha; \
+ EIGTYPE myone(1); \
+ assign_scalar_eig2mkl(alpha, myone); \
+ ldb = otherStride;\
+\
+ const EIGTYPE *a; \
+/* Set trans */ \
+ transa = (TriStorageOrder==RowMajor) ? ((Conjugate) ? 'C' : 'T') : 'N'; \
+/* Set uplo */ \
+ uplo = IsLower ? 'L' : 'U'; \
+ if (TriStorageOrder==RowMajor) uplo = (uplo == 'L') ? 'U' : 'L'; \
+/* Set a, lda */ \
+ typedef Matrix<EIGTYPE, Dynamic, Dynamic, TriStorageOrder> MatrixTri; \
+ Map<const MatrixTri, 0, OuterStride<> > tri(_tri,size,size,OuterStride<>(triStride)); \
+ MatrixTri a_tmp; \
+\
+ if (conjA) { \
+ a_tmp = tri.conjugate(); \
+ a = a_tmp.data(); \
+ lda = a_tmp.outerStride(); \
+ } else { \
+ a = _tri; \
+ lda = triStride; \
+ } \
+ if (IsUnitDiag) diag='U'; \
+/* call ?trsm*/ \
+ MKLPREFIX##trsm(&side, &uplo, &transa, &diag, &m, &n, &alpha, (const MKLTYPE*)a, &lda, (MKLTYPE*)_other, &ldb); \
+ } \
+};
+
+EIGEN_MKL_TRSM_L(double, double, d)
+EIGEN_MKL_TRSM_L(dcomplex, MKL_Complex16, z)
+EIGEN_MKL_TRSM_L(float, float, s)
+EIGEN_MKL_TRSM_L(scomplex, MKL_Complex8, c)
+
+
+// implements RightSide general * op(triangular)^-1
+#define EIGEN_MKL_TRSM_R(EIGTYPE, MKLTYPE, MKLPREFIX) \
+template <typename Index, int Mode, bool Conjugate, int TriStorageOrder> \
+struct triangular_solve_matrix<EIGTYPE,Index,OnTheRight,Mode,Conjugate,TriStorageOrder,ColMajor> \
+{ \
+ enum { \
+ IsLower = (Mode&Lower) == Lower, \
+ IsUnitDiag = (Mode&UnitDiag) ? 1 : 0, \
+ IsZeroDiag = (Mode&ZeroDiag) ? 1 : 0, \
+ conjA = ((TriStorageOrder==ColMajor) && Conjugate) ? 1 : 0 \
+ }; \
+ static EIGEN_DONT_INLINE void run( \
+ Index size, Index otherSize, \
+ const EIGTYPE* _tri, Index triStride, \
+ EIGTYPE* _other, Index otherStride, level3_blocking<EIGTYPE,EIGTYPE>& /*blocking*/) \
+ { \
+ MKL_INT m = otherSize, n = size, lda, ldb; \
+ char side = 'R', uplo, diag='N', transa; \
+ /* Set alpha_ */ \
+ MKLTYPE alpha; \
+ EIGTYPE myone(1); \
+ assign_scalar_eig2mkl(alpha, myone); \
+ ldb = otherStride;\
+\
+ const EIGTYPE *a; \
+/* Set trans */ \
+ transa = (TriStorageOrder==RowMajor) ? ((Conjugate) ? 'C' : 'T') : 'N'; \
+/* Set uplo */ \
+ uplo = IsLower ? 'L' : 'U'; \
+ if (TriStorageOrder==RowMajor) uplo = (uplo == 'L') ? 'U' : 'L'; \
+/* Set a, lda */ \
+ typedef Matrix<EIGTYPE, Dynamic, Dynamic, TriStorageOrder> MatrixTri; \
+ Map<const MatrixTri, 0, OuterStride<> > tri(_tri,size,size,OuterStride<>(triStride)); \
+ MatrixTri a_tmp; \
+\
+ if (conjA) { \
+ a_tmp = tri.conjugate(); \
+ a = a_tmp.data(); \
+ lda = a_tmp.outerStride(); \
+ } else { \
+ a = _tri; \
+ lda = triStride; \
+ } \
+ if (IsUnitDiag) diag='U'; \
+/* call ?trsm*/ \
+ MKLPREFIX##trsm(&side, &uplo, &transa, &diag, &m, &n, &alpha, (const MKLTYPE*)a, &lda, (MKLTYPE*)_other, &ldb); \
+ /*std::cout << "TRMS_L specialization!\n";*/ \
+ } \
+};
+
+EIGEN_MKL_TRSM_R(double, double, d)
+EIGEN_MKL_TRSM_R(dcomplex, MKL_Complex16, z)
+EIGEN_MKL_TRSM_R(float, float, s)
+EIGEN_MKL_TRSM_R(scomplex, MKL_Complex8, c)
+
+
+} // end namespace internal
+
+} // end namespace Eigen
+
+#endif // EIGEN_TRIANGULAR_SOLVER_MATRIX_MKL_H
diff --git a/Eigen/src/Core/products/TriangularSolverVector.h b/Eigen/src/Core/products/TriangularSolverVector.h
new file mode 100644
index 000000000..ce4d10088
--- /dev/null
+++ b/Eigen/src/Core/products/TriangularSolverVector.h
@@ -0,0 +1,139 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra.
+//
+// Copyright (C) 2008-2010 Gael Guennebaud <gael.guennebaud@inria.fr>
+//
+// This Source Code Form is subject to the terms of the Mozilla
+// Public License v. 2.0. If a copy of the MPL was not distributed
+// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+#ifndef EIGEN_TRIANGULAR_SOLVER_VECTOR_H
+#define EIGEN_TRIANGULAR_SOLVER_VECTOR_H
+
+namespace Eigen {
+
+namespace internal {
+
+template<typename LhsScalar, typename RhsScalar, typename Index, int Mode, bool Conjugate, int StorageOrder>
+struct triangular_solve_vector<LhsScalar, RhsScalar, Index, OnTheRight, Mode, Conjugate, StorageOrder>
+{
+ static void run(Index size, const LhsScalar* _lhs, Index lhsStride, RhsScalar* rhs)
+ {
+ triangular_solve_vector<LhsScalar,RhsScalar,Index,OnTheLeft,
+ ((Mode&Upper)==Upper ? Lower : Upper) | (Mode&UnitDiag),
+ Conjugate,StorageOrder==RowMajor?ColMajor:RowMajor
+ >::run(size, _lhs, lhsStride, rhs);
+ }
+};
+
+// forward and backward substitution, row-major, rhs is a vector
+template<typename LhsScalar, typename RhsScalar, typename Index, int Mode, bool Conjugate>
+struct triangular_solve_vector<LhsScalar, RhsScalar, Index, OnTheLeft, Mode, Conjugate, RowMajor>
+{
+ enum {
+ IsLower = ((Mode&Lower)==Lower)
+ };
+ static void run(Index size, const LhsScalar* _lhs, Index lhsStride, RhsScalar* rhs)
+ {
+ typedef Map<const Matrix<LhsScalar,Dynamic,Dynamic,RowMajor>, 0, OuterStride<> > LhsMap;
+ const LhsMap lhs(_lhs,size,size,OuterStride<>(lhsStride));
+ typename internal::conditional<
+ Conjugate,
+ const CwiseUnaryOp<typename internal::scalar_conjugate_op<LhsScalar>,LhsMap>,
+ const LhsMap&>
+ ::type cjLhs(lhs);
+ static const Index PanelWidth = EIGEN_TUNE_TRIANGULAR_PANEL_WIDTH;
+ for(Index pi=IsLower ? 0 : size;
+ IsLower ? pi<size : pi>0;
+ IsLower ? pi+=PanelWidth : pi-=PanelWidth)
+ {
+ Index actualPanelWidth = (std::min)(IsLower ? size - pi : pi, PanelWidth);
+
+ Index r = IsLower ? pi : size - pi; // remaining size
+ if (r > 0)
+ {
+ // let's directly call the low level product function because:
+ // 1 - it is faster to compile
+ // 2 - it is slighlty faster at runtime
+ Index startRow = IsLower ? pi : pi-actualPanelWidth;
+ Index startCol = IsLower ? 0 : pi;
+
+ general_matrix_vector_product<Index,LhsScalar,RowMajor,Conjugate,RhsScalar,false>::run(
+ actualPanelWidth, r,
+ &lhs.coeffRef(startRow,startCol), lhsStride,
+ rhs + startCol, 1,
+ rhs + startRow, 1,
+ RhsScalar(-1));
+ }
+
+ for(Index k=0; k<actualPanelWidth; ++k)
+ {
+ Index i = IsLower ? pi+k : pi-k-1;
+ Index s = IsLower ? pi : i+1;
+ if (k>0)
+ rhs[i] -= (cjLhs.row(i).segment(s,k).transpose().cwiseProduct(Map<const Matrix<RhsScalar,Dynamic,1> >(rhs+s,k))).sum();
+
+ if(!(Mode & UnitDiag))
+ rhs[i] /= cjLhs(i,i);
+ }
+ }
+ }
+};
+
+// forward and backward substitution, column-major, rhs is a vector
+template<typename LhsScalar, typename RhsScalar, typename Index, int Mode, bool Conjugate>
+struct triangular_solve_vector<LhsScalar, RhsScalar, Index, OnTheLeft, Mode, Conjugate, ColMajor>
+{
+ enum {
+ IsLower = ((Mode&Lower)==Lower)
+ };
+ static void run(Index size, const LhsScalar* _lhs, Index lhsStride, RhsScalar* rhs)
+ {
+ typedef Map<const Matrix<LhsScalar,Dynamic,Dynamic,ColMajor>, 0, OuterStride<> > LhsMap;
+ const LhsMap lhs(_lhs,size,size,OuterStride<>(lhsStride));
+ typename internal::conditional<Conjugate,
+ const CwiseUnaryOp<typename internal::scalar_conjugate_op<LhsScalar>,LhsMap>,
+ const LhsMap&
+ >::type cjLhs(lhs);
+ static const Index PanelWidth = EIGEN_TUNE_TRIANGULAR_PANEL_WIDTH;
+
+ for(Index pi=IsLower ? 0 : size;
+ IsLower ? pi<size : pi>0;
+ IsLower ? pi+=PanelWidth : pi-=PanelWidth)
+ {
+ Index actualPanelWidth = (std::min)(IsLower ? size - pi : pi, PanelWidth);
+ Index startBlock = IsLower ? pi : pi-actualPanelWidth;
+ Index endBlock = IsLower ? pi + actualPanelWidth : 0;
+
+ for(Index k=0; k<actualPanelWidth; ++k)
+ {
+ Index i = IsLower ? pi+k : pi-k-1;
+ if(!(Mode & UnitDiag))
+ rhs[i] /= cjLhs.coeff(i,i);
+
+ Index r = actualPanelWidth - k - 1; // remaining size
+ Index s = IsLower ? i+1 : i-r;
+ if (r>0)
+ Map<Matrix<RhsScalar,Dynamic,1> >(rhs+s,r) -= rhs[i] * cjLhs.col(i).segment(s,r);
+ }
+ Index r = IsLower ? size - endBlock : startBlock; // remaining size
+ if (r > 0)
+ {
+ // let's directly call the low level product function because:
+ // 1 - it is faster to compile
+ // 2 - it is slighlty faster at runtime
+ general_matrix_vector_product<Index,LhsScalar,ColMajor,Conjugate,RhsScalar,false>::run(
+ r, actualPanelWidth,
+ &lhs.coeffRef(endBlock,startBlock), lhsStride,
+ rhs+startBlock, 1,
+ rhs+endBlock, 1, RhsScalar(-1));
+ }
+ }
+ }
+};
+
+} // end namespace internal
+
+} // end namespace Eigen
+
+#endif // EIGEN_TRIANGULAR_SOLVER_VECTOR_H
diff --git a/Eigen/src/Core/util/BlasUtil.h b/Eigen/src/Core/util/BlasUtil.h
new file mode 100644
index 000000000..91496651c
--- /dev/null
+++ b/Eigen/src/Core/util/BlasUtil.h
@@ -0,0 +1,264 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra.
+//
+// Copyright (C) 2009-2010 Gael Guennebaud <gael.guennebaud@inria.fr>
+//
+// This Source Code Form is subject to the terms of the Mozilla
+// Public License v. 2.0. If a copy of the MPL was not distributed
+// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+#ifndef EIGEN_BLASUTIL_H
+#define EIGEN_BLASUTIL_H
+
+// This file contains many lightweight helper classes used to
+// implement and control fast level 2 and level 3 BLAS-like routines.
+
+namespace Eigen {
+
+namespace internal {
+
+// forward declarations
+template<typename LhsScalar, typename RhsScalar, typename Index, int mr, int nr, bool ConjugateLhs=false, bool ConjugateRhs=false>
+struct gebp_kernel;
+
+template<typename Scalar, typename Index, int nr, int StorageOrder, bool Conjugate = false, bool PanelMode=false>
+struct gemm_pack_rhs;
+
+template<typename Scalar, typename Index, int Pack1, int Pack2, int StorageOrder, bool Conjugate = false, bool PanelMode = false>
+struct gemm_pack_lhs;
+
+template<
+ typename Index,
+ typename LhsScalar, int LhsStorageOrder, bool ConjugateLhs,
+ typename RhsScalar, int RhsStorageOrder, bool ConjugateRhs,
+ int ResStorageOrder>
+struct general_matrix_matrix_product;
+
+template<typename Index, typename LhsScalar, int LhsStorageOrder, bool ConjugateLhs, typename RhsScalar, bool ConjugateRhs, int Version=Specialized>
+struct general_matrix_vector_product;
+
+
+template<bool Conjugate> struct conj_if;
+
+template<> struct conj_if<true> {
+ template<typename T>
+ inline T operator()(const T& x) { return conj(x); }
+ template<typename T>
+ inline T pconj(const T& x) { return internal::pconj(x); }
+};
+
+template<> struct conj_if<false> {
+ template<typename T>
+ inline const T& operator()(const T& x) { return x; }
+ template<typename T>
+ inline const T& pconj(const T& x) { return x; }
+};
+
+template<typename Scalar> struct conj_helper<Scalar,Scalar,false,false>
+{
+ EIGEN_STRONG_INLINE Scalar pmadd(const Scalar& x, const Scalar& y, const Scalar& c) const { return internal::pmadd(x,y,c); }
+ EIGEN_STRONG_INLINE Scalar pmul(const Scalar& x, const Scalar& y) const { return internal::pmul(x,y); }
+};
+
+template<typename RealScalar> struct conj_helper<std::complex<RealScalar>, std::complex<RealScalar>, false,true>
+{
+ typedef std::complex<RealScalar> Scalar;
+ EIGEN_STRONG_INLINE Scalar pmadd(const Scalar& x, const Scalar& y, const Scalar& c) const
+ { return c + pmul(x,y); }
+
+ EIGEN_STRONG_INLINE Scalar pmul(const Scalar& x, const Scalar& y) const
+ { return Scalar(real(x)*real(y) + imag(x)*imag(y), imag(x)*real(y) - real(x)*imag(y)); }
+};
+
+template<typename RealScalar> struct conj_helper<std::complex<RealScalar>, std::complex<RealScalar>, true,false>
+{
+ typedef std::complex<RealScalar> Scalar;
+ EIGEN_STRONG_INLINE Scalar pmadd(const Scalar& x, const Scalar& y, const Scalar& c) const
+ { return c + pmul(x,y); }
+
+ EIGEN_STRONG_INLINE Scalar pmul(const Scalar& x, const Scalar& y) const
+ { return Scalar(real(x)*real(y) + imag(x)*imag(y), real(x)*imag(y) - imag(x)*real(y)); }
+};
+
+template<typename RealScalar> struct conj_helper<std::complex<RealScalar>, std::complex<RealScalar>, true,true>
+{
+ typedef std::complex<RealScalar> Scalar;
+ EIGEN_STRONG_INLINE Scalar pmadd(const Scalar& x, const Scalar& y, const Scalar& c) const
+ { return c + pmul(x,y); }
+
+ EIGEN_STRONG_INLINE Scalar pmul(const Scalar& x, const Scalar& y) const
+ { return Scalar(real(x)*real(y) - imag(x)*imag(y), - real(x)*imag(y) - imag(x)*real(y)); }
+};
+
+template<typename RealScalar,bool Conj> struct conj_helper<std::complex<RealScalar>, RealScalar, Conj,false>
+{
+ typedef std::complex<RealScalar> Scalar;
+ EIGEN_STRONG_INLINE Scalar pmadd(const Scalar& x, const RealScalar& y, const Scalar& c) const
+ { return padd(c, pmul(x,y)); }
+ EIGEN_STRONG_INLINE Scalar pmul(const Scalar& x, const RealScalar& y) const
+ { return conj_if<Conj>()(x)*y; }
+};
+
+template<typename RealScalar,bool Conj> struct conj_helper<RealScalar, std::complex<RealScalar>, false,Conj>
+{
+ typedef std::complex<RealScalar> Scalar;
+ EIGEN_STRONG_INLINE Scalar pmadd(const RealScalar& x, const Scalar& y, const Scalar& c) const
+ { return padd(c, pmul(x,y)); }
+ EIGEN_STRONG_INLINE Scalar pmul(const RealScalar& x, const Scalar& y) const
+ { return x*conj_if<Conj>()(y); }
+};
+
+template<typename From,typename To> struct get_factor {
+ static EIGEN_STRONG_INLINE To run(const From& x) { return x; }
+};
+
+template<typename Scalar> struct get_factor<Scalar,typename NumTraits<Scalar>::Real> {
+ static EIGEN_STRONG_INLINE typename NumTraits<Scalar>::Real run(const Scalar& x) { return real(x); }
+};
+
+// Lightweight helper class to access matrix coefficients.
+// Yes, this is somehow redundant with Map<>, but this version is much much lighter,
+// and so I hope better compilation performance (time and code quality).
+template<typename Scalar, typename Index, int StorageOrder>
+class blas_data_mapper
+{
+ public:
+ blas_data_mapper(Scalar* data, Index stride) : m_data(data), m_stride(stride) {}
+ EIGEN_STRONG_INLINE Scalar& operator()(Index i, Index j)
+ { return m_data[StorageOrder==RowMajor ? j + i*m_stride : i + j*m_stride]; }
+ protected:
+ Scalar* EIGEN_RESTRICT m_data;
+ Index m_stride;
+};
+
+// lightweight helper class to access matrix coefficients (const version)
+template<typename Scalar, typename Index, int StorageOrder>
+class const_blas_data_mapper
+{
+ public:
+ const_blas_data_mapper(const Scalar* data, Index stride) : m_data(data), m_stride(stride) {}
+ EIGEN_STRONG_INLINE const Scalar& operator()(Index i, Index j) const
+ { return m_data[StorageOrder==RowMajor ? j + i*m_stride : i + j*m_stride]; }
+ protected:
+ const Scalar* EIGEN_RESTRICT m_data;
+ Index m_stride;
+};
+
+
+/* Helper class to analyze the factors of a Product expression.
+ * In particular it allows to pop out operator-, scalar multiples,
+ * and conjugate */
+template<typename XprType> struct blas_traits
+{
+ typedef typename traits<XprType>::Scalar Scalar;
+ typedef const XprType& ExtractType;
+ typedef XprType _ExtractType;
+ enum {
+ IsComplex = NumTraits<Scalar>::IsComplex,
+ IsTransposed = false,
+ NeedToConjugate = false,
+ HasUsableDirectAccess = ( (int(XprType::Flags)&DirectAccessBit)
+ && ( bool(XprType::IsVectorAtCompileTime)
+ || int(inner_stride_at_compile_time<XprType>::ret) == 1)
+ ) ? 1 : 0
+ };
+ typedef typename conditional<bool(HasUsableDirectAccess),
+ ExtractType,
+ typename _ExtractType::PlainObject
+ >::type DirectLinearAccessType;
+ static inline ExtractType extract(const XprType& x) { return x; }
+ static inline const Scalar extractScalarFactor(const XprType&) { return Scalar(1); }
+};
+
+// pop conjugate
+template<typename Scalar, typename NestedXpr>
+struct blas_traits<CwiseUnaryOp<scalar_conjugate_op<Scalar>, NestedXpr> >
+ : blas_traits<NestedXpr>
+{
+ typedef blas_traits<NestedXpr> Base;
+ typedef CwiseUnaryOp<scalar_conjugate_op<Scalar>, NestedXpr> XprType;
+ typedef typename Base::ExtractType ExtractType;
+
+ enum {
+ IsComplex = NumTraits<Scalar>::IsComplex,
+ NeedToConjugate = Base::NeedToConjugate ? 0 : IsComplex
+ };
+ static inline ExtractType extract(const XprType& x) { return Base::extract(x.nestedExpression()); }
+ static inline Scalar extractScalarFactor(const XprType& x) { return conj(Base::extractScalarFactor(x.nestedExpression())); }
+};
+
+// pop scalar multiple
+template<typename Scalar, typename NestedXpr>
+struct blas_traits<CwiseUnaryOp<scalar_multiple_op<Scalar>, NestedXpr> >
+ : blas_traits<NestedXpr>
+{
+ typedef blas_traits<NestedXpr> Base;
+ typedef CwiseUnaryOp<scalar_multiple_op<Scalar>, NestedXpr> XprType;
+ typedef typename Base::ExtractType ExtractType;
+ static inline ExtractType extract(const XprType& x) { return Base::extract(x.nestedExpression()); }
+ static inline Scalar extractScalarFactor(const XprType& x)
+ { return x.functor().m_other * Base::extractScalarFactor(x.nestedExpression()); }
+};
+
+// pop opposite
+template<typename Scalar, typename NestedXpr>
+struct blas_traits<CwiseUnaryOp<scalar_opposite_op<Scalar>, NestedXpr> >
+ : blas_traits<NestedXpr>
+{
+ typedef blas_traits<NestedXpr> Base;
+ typedef CwiseUnaryOp<scalar_opposite_op<Scalar>, NestedXpr> XprType;
+ typedef typename Base::ExtractType ExtractType;
+ static inline ExtractType extract(const XprType& x) { return Base::extract(x.nestedExpression()); }
+ static inline Scalar extractScalarFactor(const XprType& x)
+ { return - Base::extractScalarFactor(x.nestedExpression()); }
+};
+
+// pop/push transpose
+template<typename NestedXpr>
+struct blas_traits<Transpose<NestedXpr> >
+ : blas_traits<NestedXpr>
+{
+ typedef typename NestedXpr::Scalar Scalar;
+ typedef blas_traits<NestedXpr> Base;
+ typedef Transpose<NestedXpr> XprType;
+ typedef Transpose<const typename Base::_ExtractType> ExtractType; // const to get rid of a compile error; anyway blas traits are only used on the RHS
+ typedef Transpose<const typename Base::_ExtractType> _ExtractType;
+ typedef typename conditional<bool(Base::HasUsableDirectAccess),
+ ExtractType,
+ typename ExtractType::PlainObject
+ >::type DirectLinearAccessType;
+ enum {
+ IsTransposed = Base::IsTransposed ? 0 : 1
+ };
+ static inline ExtractType extract(const XprType& x) { return Base::extract(x.nestedExpression()); }
+ static inline Scalar extractScalarFactor(const XprType& x) { return Base::extractScalarFactor(x.nestedExpression()); }
+};
+
+template<typename T>
+struct blas_traits<const T>
+ : blas_traits<T>
+{};
+
+template<typename T, bool HasUsableDirectAccess=blas_traits<T>::HasUsableDirectAccess>
+struct extract_data_selector {
+ static const typename T::Scalar* run(const T& m)
+ {
+ return blas_traits<T>::extract(m).data();
+ }
+};
+
+template<typename T>
+struct extract_data_selector<T,false> {
+ static typename T::Scalar* run(const T&) { return 0; }
+};
+
+template<typename T> const typename T::Scalar* extract_data(const T& m)
+{
+ return extract_data_selector<T>::run(m);
+}
+
+} // end namespace internal
+
+} // end namespace Eigen
+
+#endif // EIGEN_BLASUTIL_H
diff --git a/Eigen/src/Core/util/CMakeLists.txt b/Eigen/src/Core/util/CMakeLists.txt
new file mode 100644
index 000000000..a1e2e521f
--- /dev/null
+++ b/Eigen/src/Core/util/CMakeLists.txt
@@ -0,0 +1,6 @@
+FILE(GLOB Eigen_Core_util_SRCS "*.h")
+
+INSTALL(FILES
+ ${Eigen_Core_util_SRCS}
+ DESTINATION ${INCLUDE_INSTALL_DIR}/Eigen/src/Core/util COMPONENT Devel
+ )
diff --git a/Eigen/src/Core/util/Constants.h b/Eigen/src/Core/util/Constants.h
new file mode 100644
index 000000000..3fd45e84f
--- /dev/null
+++ b/Eigen/src/Core/util/Constants.h
@@ -0,0 +1,431 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra.
+//
+// Copyright (C) 2008-2009 Gael Guennebaud <gael.guennebaud@inria.fr>
+// Copyright (C) 2007-2009 Benoit Jacob <jacob.benoit.1@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 EIGEN_CONSTANTS_H
+#define EIGEN_CONSTANTS_H
+
+namespace Eigen {
+
+/** This value means that a quantity is not known at compile-time, and that instead the value is
+ * stored in some runtime variable.
+ *
+ * Changing the value of Dynamic breaks the ABI, as Dynamic is often used as a template parameter for Matrix.
+ */
+const int Dynamic = -1;
+
+/** This value means +Infinity; it is currently used only as the p parameter to MatrixBase::lpNorm<int>().
+ * The value Infinity there means the L-infinity norm.
+ */
+const int Infinity = -1;
+
+/** \defgroup flags Flags
+ * \ingroup Core_Module
+ *
+ * These are the possible bits which can be OR'ed to constitute the flags of a matrix or
+ * expression.
+ *
+ * It is important to note that these flags are a purely compile-time notion. They are a compile-time property of
+ * an expression type, implemented as enum's. They are not stored in memory at runtime, and they do not incur any
+ * runtime overhead.
+ *
+ * \sa MatrixBase::Flags
+ */
+
+/** \ingroup flags
+ *
+ * for a matrix, this means that the storage order is row-major.
+ * If this bit is not set, the storage order is column-major.
+ * For an expression, this determines the storage order of
+ * the matrix created by evaluation of that expression.
+ * \sa \ref TopicStorageOrders */
+const unsigned int RowMajorBit = 0x1;
+
+/** \ingroup flags
+ *
+ * means the expression should be evaluated by the calling expression */
+const unsigned int EvalBeforeNestingBit = 0x2;
+
+/** \ingroup flags
+ *
+ * means the expression should be evaluated before any assignment */
+const unsigned int EvalBeforeAssigningBit = 0x4;
+
+/** \ingroup flags
+ *
+ * Short version: means the expression might be vectorized
+ *
+ * Long version: means that the coefficients can be handled by packets
+ * and start at a memory location whose alignment meets the requirements
+ * of the present CPU architecture for optimized packet access. In the fixed-size
+ * case, there is the additional condition that it be possible to access all the
+ * coefficients by packets (this implies the requirement that the size be a multiple of 16 bytes,
+ * and that any nontrivial strides don't break the alignment). In the dynamic-size case,
+ * there is no such condition on the total size and strides, so it might not be possible to access
+ * all coeffs by packets.
+ *
+ * \note This bit can be set regardless of whether vectorization is actually enabled.
+ * To check for actual vectorizability, see \a ActualPacketAccessBit.
+ */
+const unsigned int PacketAccessBit = 0x8;
+
+#ifdef EIGEN_VECTORIZE
+/** \ingroup flags
+ *
+ * If vectorization is enabled (EIGEN_VECTORIZE is defined) this constant
+ * is set to the value \a PacketAccessBit.
+ *
+ * If vectorization is not enabled (EIGEN_VECTORIZE is not defined) this constant
+ * is set to the value 0.
+ */
+const unsigned int ActualPacketAccessBit = PacketAccessBit;
+#else
+const unsigned int ActualPacketAccessBit = 0x0;
+#endif
+
+/** \ingroup flags
+ *
+ * Short version: means the expression can be seen as 1D vector.
+ *
+ * Long version: means that one can access the coefficients
+ * of this expression by coeff(int), and coeffRef(int) in the case of a lvalue expression. These
+ * index-based access methods are guaranteed
+ * to not have to do any runtime computation of a (row, col)-pair from the index, so that it
+ * is guaranteed that whenever it is available, index-based access is at least as fast as
+ * (row,col)-based access. Expressions for which that isn't possible don't have the LinearAccessBit.
+ *
+ * If both PacketAccessBit and LinearAccessBit are set, then the
+ * packets of this expression can be accessed by packet(int), and writePacket(int) in the case of a
+ * lvalue expression.
+ *
+ * Typically, all vector expressions have the LinearAccessBit, but there is one exception:
+ * Product expressions don't have it, because it would be troublesome for vectorization, even when the
+ * Product is a vector expression. Thus, vector Product expressions allow index-based coefficient access but
+ * not index-based packet access, so they don't have the LinearAccessBit.
+ */
+const unsigned int LinearAccessBit = 0x10;
+
+/** \ingroup flags
+ *
+ * Means the expression has a coeffRef() method, i.e. is writable as its individual coefficients are directly addressable.
+ * This rules out read-only expressions.
+ *
+ * Note that DirectAccessBit and LvalueBit are mutually orthogonal, as there are examples of expression having one but note
+ * the other:
+ * \li writable expressions that don't have a very simple memory layout as a strided array, have LvalueBit but not DirectAccessBit
+ * \li Map-to-const expressions, for example Map<const Matrix>, have DirectAccessBit but not LvalueBit
+ *
+ * Expressions having LvalueBit also have their coeff() method returning a const reference instead of returning a new value.
+ */
+const unsigned int LvalueBit = 0x20;
+
+/** \ingroup flags
+ *
+ * Means that the underlying array of coefficients can be directly accessed as a plain strided array. The memory layout
+ * of the array of coefficients must be exactly the natural one suggested by rows(), cols(),
+ * outerStride(), innerStride(), and the RowMajorBit. This rules out expressions such as Diagonal, whose coefficients,
+ * though referencable, do not have such a regular memory layout.
+ *
+ * See the comment on LvalueBit for an explanation of how LvalueBit and DirectAccessBit are mutually orthogonal.
+ */
+const unsigned int DirectAccessBit = 0x40;
+
+/** \ingroup flags
+ *
+ * means the first coefficient packet is guaranteed to be aligned */
+const unsigned int AlignedBit = 0x80;
+
+const unsigned int NestByRefBit = 0x100;
+
+// list of flags that are inherited by default
+const unsigned int HereditaryBits = RowMajorBit
+ | EvalBeforeNestingBit
+ | EvalBeforeAssigningBit;
+
+/** \defgroup enums Enumerations
+ * \ingroup Core_Module
+ *
+ * Various enumerations used in %Eigen. Many of these are used as template parameters.
+ */
+
+/** \ingroup enums
+ * Enum containing possible values for the \p Mode parameter of
+ * MatrixBase::selfadjointView() and MatrixBase::triangularView(). */
+enum {
+ /** View matrix as a lower triangular matrix. */
+ Lower=0x1,
+ /** View matrix as an upper triangular matrix. */
+ Upper=0x2,
+ /** %Matrix has ones on the diagonal; to be used in combination with #Lower or #Upper. */
+ UnitDiag=0x4,
+ /** %Matrix has zeros on the diagonal; to be used in combination with #Lower or #Upper. */
+ ZeroDiag=0x8,
+ /** View matrix as a lower triangular matrix with ones on the diagonal. */
+ UnitLower=UnitDiag|Lower,
+ /** View matrix as an upper triangular matrix with ones on the diagonal. */
+ UnitUpper=UnitDiag|Upper,
+ /** View matrix as a lower triangular matrix with zeros on the diagonal. */
+ StrictlyLower=ZeroDiag|Lower,
+ /** View matrix as an upper triangular matrix with zeros on the diagonal. */
+ StrictlyUpper=ZeroDiag|Upper,
+ /** Used in BandMatrix and SelfAdjointView to indicate that the matrix is self-adjoint. */
+ SelfAdjoint=0x10,
+ /** Used to support symmetric, non-selfadjoint, complex matrices. */
+ Symmetric=0x20
+};
+
+/** \ingroup enums
+ * Enum for indicating whether an object is aligned or not. */
+enum {
+ /** Object is not correctly aligned for vectorization. */
+ Unaligned=0,
+ /** Object is aligned for vectorization. */
+ Aligned=1
+};
+
+/** \ingroup enums
+ * Enum used by DenseBase::corner() in Eigen2 compatibility mode. */
+// FIXME after the corner() API change, this was not needed anymore, except by AlignedBox
+// TODO: find out what to do with that. Adapt the AlignedBox API ?
+enum CornerType { TopLeft, TopRight, BottomLeft, BottomRight };
+
+/** \ingroup enums
+ * Enum containing possible values for the \p Direction parameter of
+ * Reverse, PartialReduxExpr and VectorwiseOp. */
+enum DirectionType {
+ /** For Reverse, all columns are reversed;
+ * for PartialReduxExpr and VectorwiseOp, act on columns. */
+ Vertical,
+ /** For Reverse, all rows are reversed;
+ * for PartialReduxExpr and VectorwiseOp, act on rows. */
+ Horizontal,
+ /** For Reverse, both rows and columns are reversed;
+ * not used for PartialReduxExpr and VectorwiseOp. */
+ BothDirections
+};
+
+/** \internal \ingroup enums
+ * Enum to specify how to traverse the entries of a matrix. */
+enum {
+ /** \internal Default traversal, no vectorization, no index-based access */
+ DefaultTraversal,
+ /** \internal No vectorization, use index-based access to have only one for loop instead of 2 nested loops */
+ LinearTraversal,
+ /** \internal Equivalent to a slice vectorization for fixed-size matrices having good alignment
+ * and good size */
+ InnerVectorizedTraversal,
+ /** \internal Vectorization path using a single loop plus scalar loops for the
+ * unaligned boundaries */
+ LinearVectorizedTraversal,
+ /** \internal Generic vectorization path using one vectorized loop per row/column with some
+ * scalar loops to handle the unaligned boundaries */
+ SliceVectorizedTraversal,
+ /** \internal Special case to properly handle incompatible scalar types or other defecting cases*/
+ InvalidTraversal
+};
+
+/** \internal \ingroup enums
+ * Enum to specify whether to unroll loops when traversing over the entries of a matrix. */
+enum {
+ /** \internal Do not unroll loops. */
+ NoUnrolling,
+ /** \internal Unroll only the inner loop, but not the outer loop. */
+ InnerUnrolling,
+ /** \internal Unroll both the inner and the outer loop. If there is only one loop,
+ * because linear traversal is used, then unroll that loop. */
+ CompleteUnrolling
+};
+
+/** \internal \ingroup enums
+ * Enum to specify whether to use the default (built-in) implementation or the specialization. */
+enum {
+ Specialized,
+ BuiltIn
+};
+
+/** \ingroup enums
+ * Enum containing possible values for the \p _Options template parameter of
+ * Matrix, Array and BandMatrix. */
+enum {
+ /** Storage order is column major (see \ref TopicStorageOrders). */
+ ColMajor = 0,
+ /** Storage order is row major (see \ref TopicStorageOrders). */
+ RowMajor = 0x1, // it is only a coincidence that this is equal to RowMajorBit -- don't rely on that
+ /** \internal Align the matrix itself if it is vectorizable fixed-size */
+ AutoAlign = 0,
+ /** \internal Don't require alignment for the matrix itself (the array of coefficients, if dynamically allocated, may still be requested to be aligned) */ // FIXME --- clarify the situation
+ DontAlign = 0x2
+};
+
+/** \ingroup enums
+ * Enum for specifying whether to apply or solve on the left or right. */
+enum {
+ /** Apply transformation on the left. */
+ OnTheLeft = 1,
+ /** Apply transformation on the right. */
+ OnTheRight = 2
+};
+
+/* the following used to be written as:
+ *
+ * struct NoChange_t {};
+ * namespace {
+ * EIGEN_UNUSED NoChange_t NoChange;
+ * }
+ *
+ * on the ground that it feels dangerous to disambiguate overloaded functions on enum/integer types.
+ * However, this leads to "variable declared but never referenced" warnings on Intel Composer XE,
+ * and we do not know how to get rid of them (bug 450).
+ */
+
+enum NoChange_t { NoChange };
+enum Sequential_t { Sequential };
+enum Default_t { Default };
+
+/** \internal \ingroup enums
+ * Used in AmbiVector. */
+enum {
+ IsDense = 0,
+ IsSparse
+};
+
+/** \ingroup enums
+ * Used as template parameter in DenseCoeffBase and MapBase to indicate
+ * which accessors should be provided. */
+enum AccessorLevels {
+ /** Read-only access via a member function. */
+ ReadOnlyAccessors,
+ /** Read/write access via member functions. */
+ WriteAccessors,
+ /** Direct read-only access to the coefficients. */
+ DirectAccessors,
+ /** Direct read/write access to the coefficients. */
+ DirectWriteAccessors
+};
+
+/** \ingroup enums
+ * Enum with options to give to various decompositions. */
+enum DecompositionOptions {
+ /** \internal Not used (meant for LDLT?). */
+ Pivoting = 0x01,
+ /** \internal Not used (meant for LDLT?). */
+ NoPivoting = 0x02,
+ /** Used in JacobiSVD to indicate that the square matrix U is to be computed. */
+ ComputeFullU = 0x04,
+ /** Used in JacobiSVD to indicate that the thin matrix U is to be computed. */
+ ComputeThinU = 0x08,
+ /** Used in JacobiSVD to indicate that the square matrix V is to be computed. */
+ ComputeFullV = 0x10,
+ /** Used in JacobiSVD to indicate that the thin matrix V is to be computed. */
+ ComputeThinV = 0x20,
+ /** Used in SelfAdjointEigenSolver and GeneralizedSelfAdjointEigenSolver to specify
+ * that only the eigenvalues are to be computed and not the eigenvectors. */
+ EigenvaluesOnly = 0x40,
+ /** Used in SelfAdjointEigenSolver and GeneralizedSelfAdjointEigenSolver to specify
+ * that both the eigenvalues and the eigenvectors are to be computed. */
+ ComputeEigenvectors = 0x80,
+ /** \internal */
+ EigVecMask = EigenvaluesOnly | ComputeEigenvectors,
+ /** Used in GeneralizedSelfAdjointEigenSolver to indicate that it should
+ * solve the generalized eigenproblem \f$ Ax = \lambda B x \f$. */
+ Ax_lBx = 0x100,
+ /** Used in GeneralizedSelfAdjointEigenSolver to indicate that it should
+ * solve the generalized eigenproblem \f$ ABx = \lambda x \f$. */
+ ABx_lx = 0x200,
+ /** Used in GeneralizedSelfAdjointEigenSolver to indicate that it should
+ * solve the generalized eigenproblem \f$ BAx = \lambda x \f$. */
+ BAx_lx = 0x400,
+ /** \internal */
+ GenEigMask = Ax_lBx | ABx_lx | BAx_lx
+};
+
+/** \ingroup enums
+ * Possible values for the \p QRPreconditioner template parameter of JacobiSVD. */
+enum QRPreconditioners {
+ /** Do not specify what is to be done if the SVD of a non-square matrix is asked for. */
+ NoQRPreconditioner,
+ /** Use a QR decomposition without pivoting as the first step. */
+ HouseholderQRPreconditioner,
+ /** Use a QR decomposition with column pivoting as the first step. */
+ ColPivHouseholderQRPreconditioner,
+ /** Use a QR decomposition with full pivoting as the first step. */
+ FullPivHouseholderQRPreconditioner
+};
+
+#ifdef Success
+#error The preprocessor symbol 'Success' is defined, possibly by the X11 header file X.h
+#endif
+
+/** \ingroup enums
+ * Enum for reporting the status of a computation. */
+enum ComputationInfo {
+ /** Computation was successful. */
+ Success = 0,
+ /** The provided data did not satisfy the prerequisites. */
+ NumericalIssue = 1,
+ /** Iterative procedure did not converge. */
+ NoConvergence = 2,
+ /** The inputs are invalid, or the algorithm has been improperly called.
+ * When assertions are enabled, such errors trigger an assert. */
+ InvalidInput = 3
+};
+
+/** \ingroup enums
+ * Enum used to specify how a particular transformation is stored in a matrix.
+ * \sa Transform, Hyperplane::transform(). */
+enum TransformTraits {
+ /** Transformation is an isometry. */
+ Isometry = 0x1,
+ /** Transformation is an affine transformation stored as a (Dim+1)^2 matrix whose last row is
+ * assumed to be [0 ... 0 1]. */
+ Affine = 0x2,
+ /** Transformation is an affine transformation stored as a (Dim) x (Dim+1) matrix. */
+ AffineCompact = 0x10 | Affine,
+ /** Transformation is a general projective transformation stored as a (Dim+1)^2 matrix. */
+ Projective = 0x20
+};
+
+/** \internal \ingroup enums
+ * Enum used to choose between implementation depending on the computer architecture. */
+namespace Architecture
+{
+ enum Type {
+ Generic = 0x0,
+ SSE = 0x1,
+ AltiVec = 0x2,
+#if defined EIGEN_VECTORIZE_SSE
+ Target = SSE
+#elif defined EIGEN_VECTORIZE_ALTIVEC
+ Target = AltiVec
+#else
+ Target = Generic
+#endif
+ };
+}
+
+/** \internal \ingroup enums
+ * Enum used as template parameter in GeneralProduct. */
+enum { CoeffBasedProductMode, LazyCoeffBasedProductMode, OuterProduct, InnerProduct, GemvProduct, GemmProduct };
+
+/** \internal \ingroup enums
+ * Enum used in experimental parallel implementation. */
+enum Action {GetAction, SetAction};
+
+/** The type used to identify a dense storage. */
+struct Dense {};
+
+/** The type used to identify a matrix expression */
+struct MatrixXpr {};
+
+/** The type used to identify an array expression */
+struct ArrayXpr {};
+
+} // end namespace Eigen
+
+#endif // EIGEN_CONSTANTS_H
diff --git a/Eigen/src/Core/util/DisableStupidWarnings.h b/Eigen/src/Core/util/DisableStupidWarnings.h
new file mode 100644
index 000000000..6a0bf0629
--- /dev/null
+++ b/Eigen/src/Core/util/DisableStupidWarnings.h
@@ -0,0 +1,40 @@
+#ifndef EIGEN_WARNINGS_DISABLED
+#define EIGEN_WARNINGS_DISABLED
+
+#ifdef _MSC_VER
+ // 4100 - unreferenced formal parameter (occurred e.g. in aligned_allocator::destroy(pointer p))
+ // 4101 - unreferenced local variable
+ // 4127 - conditional expression is constant
+ // 4181 - qualifier applied to reference type ignored
+ // 4211 - nonstandard extension used : redefined extern to static
+ // 4244 - 'argument' : conversion from 'type1' to 'type2', possible loss of data
+ // 4273 - QtAlignedMalloc, inconsistent DLL linkage
+ // 4324 - structure was padded due to declspec(align())
+ // 4512 - assignment operator could not be generated
+ // 4522 - 'class' : multiple assignment operators specified
+ // 4700 - uninitialized local variable 'xyz' used
+ // 4717 - 'function' : recursive on all control paths, function will cause runtime stack overflow
+ #ifndef EIGEN_PERMANENTLY_DISABLE_STUPID_WARNINGS
+ #pragma warning( push )
+ #endif
+ #pragma warning( disable : 4100 4101 4127 4181 4211 4244 4273 4324 4512 4522 4700 4717 )
+#elif defined __INTEL_COMPILER
+ // 2196 - routine is both "inline" and "noinline" ("noinline" assumed)
+ // ICC 12 generates this warning even without any inline keyword, when defining class methods 'inline' i.e. inside of class body
+ // typedef that may be a reference type.
+ // 279 - controlling expression is constant
+ // ICC 12 generates this warning on assert(constant_expression_depending_on_template_params) and frankly this is a legitimate use case.
+ #ifndef EIGEN_PERMANENTLY_DISABLE_STUPID_WARNINGS
+ #pragma warning push
+ #endif
+ #pragma warning disable 2196 279
+#elif defined __clang__
+ // -Wconstant-logical-operand - warning: use of logical && with constant operand; switch to bitwise & or remove constant
+ // this is really a stupid warning as it warns on compile-time expressions involving enums
+ #ifndef EIGEN_PERMANENTLY_DISABLE_STUPID_WARNINGS
+ #pragma clang diagnostic push
+ #endif
+ #pragma clang diagnostic ignored "-Wconstant-logical-operand"
+#endif
+
+#endif // not EIGEN_WARNINGS_DISABLED
diff --git a/Eigen/src/Core/util/ForwardDeclarations.h b/Eigen/src/Core/util/ForwardDeclarations.h
new file mode 100644
index 000000000..bcdfe3914
--- /dev/null
+++ b/Eigen/src/Core/util/ForwardDeclarations.h
@@ -0,0 +1,298 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra.
+//
+// Copyright (C) 2007-2010 Benoit Jacob <jacob.benoit.1@gmail.com>
+// Copyright (C) 2008-2009 Gael Guennebaud <gael.guennebaud@inria.fr>
+//
+// This Source Code Form is subject to the terms of the Mozilla
+// Public License v. 2.0. If a copy of the MPL was not distributed
+// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+#ifndef EIGEN_FORWARDDECLARATIONS_H
+#define EIGEN_FORWARDDECLARATIONS_H
+
+namespace Eigen {
+namespace internal {
+
+template<typename T> struct traits;
+
+// here we say once and for all that traits<const T> == traits<T>
+// When constness must affect traits, it has to be constness on template parameters on which T itself depends.
+// For example, traits<Map<const T> > != traits<Map<T> >, but
+// traits<const Map<T> > == traits<Map<T> >
+template<typename T> struct traits<const T> : traits<T> {};
+
+template<typename Derived> struct has_direct_access
+{
+ enum { ret = (traits<Derived>::Flags & DirectAccessBit) ? 1 : 0 };
+};
+
+template<typename Derived> struct accessors_level
+{
+ enum { has_direct_access = (traits<Derived>::Flags & DirectAccessBit) ? 1 : 0,
+ has_write_access = (traits<Derived>::Flags & LvalueBit) ? 1 : 0,
+ value = has_direct_access ? (has_write_access ? DirectWriteAccessors : DirectAccessors)
+ : (has_write_access ? WriteAccessors : ReadOnlyAccessors)
+ };
+};
+
+} // end namespace internal
+
+template<typename T> struct NumTraits;
+
+template<typename Derived> struct EigenBase;
+template<typename Derived> class DenseBase;
+template<typename Derived> class PlainObjectBase;
+
+
+template<typename Derived,
+ int Level = internal::accessors_level<Derived>::value >
+class DenseCoeffsBase;
+
+template<typename _Scalar, int _Rows, int _Cols,
+ int _Options = AutoAlign |
+#if defined(__GNUC__) && __GNUC__==3 && __GNUC_MINOR__==4
+ // workaround a bug in at least gcc 3.4.6
+ // the innermost ?: ternary operator is misparsed. We write it slightly
+ // differently and this makes gcc 3.4.6 happy, but it's ugly.
+ // The error would only show up with EIGEN_DEFAULT_TO_ROW_MAJOR is defined
+ // (when EIGEN_DEFAULT_MATRIX_STORAGE_ORDER_OPTION is RowMajor)
+ ( (_Rows==1 && _Cols!=1) ? RowMajor
+ : !(_Cols==1 && _Rows!=1) ? EIGEN_DEFAULT_MATRIX_STORAGE_ORDER_OPTION
+ : ColMajor ),
+#else
+ ( (_Rows==1 && _Cols!=1) ? RowMajor
+ : (_Cols==1 && _Rows!=1) ? ColMajor
+ : EIGEN_DEFAULT_MATRIX_STORAGE_ORDER_OPTION ),
+#endif
+ int _MaxRows = _Rows,
+ int _MaxCols = _Cols
+> class Matrix;
+
+template<typename Derived> class MatrixBase;
+template<typename Derived> class ArrayBase;
+
+template<typename ExpressionType, unsigned int Added, unsigned int Removed> class Flagged;
+template<typename ExpressionType, template <typename> class StorageBase > class NoAlias;
+template<typename ExpressionType> class NestByValue;
+template<typename ExpressionType> class ForceAlignedAccess;
+template<typename ExpressionType> class SwapWrapper;
+
+template<typename XprType, int BlockRows=Dynamic, int BlockCols=Dynamic, bool InnerPanel = false,
+ bool HasDirectAccess = internal::has_direct_access<XprType>::ret> class Block;
+
+template<typename MatrixType, int Size=Dynamic> class VectorBlock;
+template<typename MatrixType> class Transpose;
+template<typename MatrixType> class Conjugate;
+template<typename NullaryOp, typename MatrixType> class CwiseNullaryOp;
+template<typename UnaryOp, typename MatrixType> class CwiseUnaryOp;
+template<typename ViewOp, typename MatrixType> class CwiseUnaryView;
+template<typename BinaryOp, typename Lhs, typename Rhs> class CwiseBinaryOp;
+template<typename BinOp, typename Lhs, typename Rhs> class SelfCwiseBinaryOp;
+template<typename Derived, typename Lhs, typename Rhs> class ProductBase;
+template<typename Lhs, typename Rhs, int Mode> class GeneralProduct;
+template<typename Lhs, typename Rhs, int NestingFlags> class CoeffBasedProduct;
+
+template<typename Derived> class DiagonalBase;
+template<typename _DiagonalVectorType> class DiagonalWrapper;
+template<typename _Scalar, int SizeAtCompileTime, int MaxSizeAtCompileTime=SizeAtCompileTime> class DiagonalMatrix;
+template<typename MatrixType, typename DiagonalType, int ProductOrder> class DiagonalProduct;
+template<typename MatrixType, int Index = 0> class Diagonal;
+template<int SizeAtCompileTime, int MaxSizeAtCompileTime = SizeAtCompileTime, typename IndexType=int> class PermutationMatrix;
+template<int SizeAtCompileTime, int MaxSizeAtCompileTime = SizeAtCompileTime, typename IndexType=int> class Transpositions;
+template<typename Derived> class PermutationBase;
+template<typename Derived> class TranspositionsBase;
+template<typename _IndicesType> class PermutationWrapper;
+template<typename _IndicesType> class TranspositionsWrapper;
+
+template<typename Derived,
+ int Level = internal::accessors_level<Derived>::has_write_access ? WriteAccessors : ReadOnlyAccessors
+> class MapBase;
+template<int InnerStrideAtCompileTime, int OuterStrideAtCompileTime> class Stride;
+template<typename MatrixType, int MapOptions=Unaligned, typename StrideType = Stride<0,0> > class Map;
+
+template<typename Derived> class TriangularBase;
+template<typename MatrixType, unsigned int Mode> class TriangularView;
+template<typename MatrixType, unsigned int Mode> class SelfAdjointView;
+template<typename MatrixType> class SparseView;
+template<typename ExpressionType> class WithFormat;
+template<typename MatrixType> struct CommaInitializer;
+template<typename Derived> class ReturnByValue;
+template<typename ExpressionType> class ArrayWrapper;
+template<typename ExpressionType> class MatrixWrapper;
+
+namespace internal {
+template<typename DecompositionType, typename Rhs> struct solve_retval_base;
+template<typename DecompositionType, typename Rhs> struct solve_retval;
+template<typename DecompositionType> struct kernel_retval_base;
+template<typename DecompositionType> struct kernel_retval;
+template<typename DecompositionType> struct image_retval_base;
+template<typename DecompositionType> struct image_retval;
+} // end namespace internal
+
+namespace internal {
+template<typename _Scalar, int Rows=Dynamic, int Cols=Dynamic, int Supers=Dynamic, int Subs=Dynamic, int Options=0> class BandMatrix;
+}
+
+namespace internal {
+template<typename Lhs, typename Rhs> struct product_type;
+}
+
+template<typename Lhs, typename Rhs,
+ int ProductType = internal::product_type<Lhs,Rhs>::value>
+struct ProductReturnType;
+
+// this is a workaround for sun CC
+template<typename Lhs, typename Rhs> struct LazyProductReturnType;
+
+namespace internal {
+
+// Provides scalar/packet-wise product and product with accumulation
+// with optional conjugation of the arguments.
+template<typename LhsScalar, typename RhsScalar, bool ConjLhs=false, bool ConjRhs=false> struct conj_helper;
+
+template<typename Scalar> struct scalar_sum_op;
+template<typename Scalar> struct scalar_difference_op;
+template<typename LhsScalar,typename RhsScalar> struct scalar_conj_product_op;
+template<typename Scalar> struct scalar_quotient_op;
+template<typename Scalar> struct scalar_opposite_op;
+template<typename Scalar> struct scalar_conjugate_op;
+template<typename Scalar> struct scalar_real_op;
+template<typename Scalar> struct scalar_imag_op;
+template<typename Scalar> struct scalar_abs_op;
+template<typename Scalar> struct scalar_abs2_op;
+template<typename Scalar> struct scalar_sqrt_op;
+template<typename Scalar> struct scalar_exp_op;
+template<typename Scalar> struct scalar_log_op;
+template<typename Scalar> struct scalar_cos_op;
+template<typename Scalar> struct scalar_sin_op;
+template<typename Scalar> struct scalar_acos_op;
+template<typename Scalar> struct scalar_asin_op;
+template<typename Scalar> struct scalar_tan_op;
+template<typename Scalar> struct scalar_pow_op;
+template<typename Scalar> struct scalar_inverse_op;
+template<typename Scalar> struct scalar_square_op;
+template<typename Scalar> struct scalar_cube_op;
+template<typename Scalar, typename NewType> struct scalar_cast_op;
+template<typename Scalar> struct scalar_multiple_op;
+template<typename Scalar> struct scalar_quotient1_op;
+template<typename Scalar> struct scalar_min_op;
+template<typename Scalar> struct scalar_max_op;
+template<typename Scalar> struct scalar_random_op;
+template<typename Scalar> struct scalar_add_op;
+template<typename Scalar> struct scalar_constant_op;
+template<typename Scalar> struct scalar_identity_op;
+
+template<typename LhsScalar,typename RhsScalar=LhsScalar> struct scalar_product_op;
+template<typename LhsScalar,typename RhsScalar> struct scalar_multiple2_op;
+
+} // end namespace internal
+
+struct IOFormat;
+
+// Array module
+template<typename _Scalar, int _Rows, int _Cols,
+ int _Options = AutoAlign |
+#if defined(__GNUC__) && __GNUC__==3 && __GNUC_MINOR__==4
+ // workaround a bug in at least gcc 3.4.6
+ // the innermost ?: ternary operator is misparsed. We write it slightly
+ // differently and this makes gcc 3.4.6 happy, but it's ugly.
+ // The error would only show up with EIGEN_DEFAULT_TO_ROW_MAJOR is defined
+ // (when EIGEN_DEFAULT_MATRIX_STORAGE_ORDER_OPTION is RowMajor)
+ ( (_Rows==1 && _Cols!=1) ? RowMajor
+ : !(_Cols==1 && _Rows!=1) ? EIGEN_DEFAULT_MATRIX_STORAGE_ORDER_OPTION
+ : ColMajor ),
+#else
+ ( (_Rows==1 && _Cols!=1) ? RowMajor
+ : (_Cols==1 && _Rows!=1) ? ColMajor
+ : EIGEN_DEFAULT_MATRIX_STORAGE_ORDER_OPTION ),
+#endif
+ int _MaxRows = _Rows, int _MaxCols = _Cols> class Array;
+template<typename ConditionMatrixType, typename ThenMatrixType, typename ElseMatrixType> class Select;
+template<typename MatrixType, typename BinaryOp, int Direction> class PartialReduxExpr;
+template<typename ExpressionType, int Direction> class VectorwiseOp;
+template<typename MatrixType,int RowFactor,int ColFactor> class Replicate;
+template<typename MatrixType, int Direction = BothDirections> class Reverse;
+
+template<typename MatrixType> class FullPivLU;
+template<typename MatrixType> class PartialPivLU;
+namespace internal {
+template<typename MatrixType> struct inverse_impl;
+}
+template<typename MatrixType> class HouseholderQR;
+template<typename MatrixType> class ColPivHouseholderQR;
+template<typename MatrixType> class FullPivHouseholderQR;
+template<typename MatrixType, int QRPreconditioner = ColPivHouseholderQRPreconditioner> class JacobiSVD;
+template<typename MatrixType, int UpLo = Lower> class LLT;
+template<typename MatrixType, int UpLo = Lower> class LDLT;
+template<typename VectorsType, typename CoeffsType, int Side=OnTheLeft> class HouseholderSequence;
+template<typename Scalar> class JacobiRotation;
+
+// Geometry module:
+template<typename Derived, int _Dim> class RotationBase;
+template<typename Lhs, typename Rhs> class Cross;
+template<typename Derived> class QuaternionBase;
+template<typename Scalar> class Rotation2D;
+template<typename Scalar> class AngleAxis;
+template<typename Scalar,int Dim> class Translation;
+
+#ifdef EIGEN2_SUPPORT
+template<typename Derived, int _Dim> class eigen2_RotationBase;
+template<typename Lhs, typename Rhs> class eigen2_Cross;
+template<typename Scalar> class eigen2_Quaternion;
+template<typename Scalar> class eigen2_Rotation2D;
+template<typename Scalar> class eigen2_AngleAxis;
+template<typename Scalar,int Dim> class eigen2_Transform;
+template <typename _Scalar, int _AmbientDim> class eigen2_ParametrizedLine;
+template <typename _Scalar, int _AmbientDim> class eigen2_Hyperplane;
+template<typename Scalar,int Dim> class eigen2_Translation;
+template<typename Scalar,int Dim> class eigen2_Scaling;
+#endif
+
+#if EIGEN2_SUPPORT_STAGE < STAGE20_RESOLVE_API_CONFLICTS
+template<typename Scalar> class Quaternion;
+template<typename Scalar,int Dim> class Transform;
+template <typename _Scalar, int _AmbientDim> class ParametrizedLine;
+template <typename _Scalar, int _AmbientDim> class Hyperplane;
+template<typename Scalar,int Dim> class Scaling;
+#endif
+
+#if EIGEN2_SUPPORT_STAGE > STAGE20_RESOLVE_API_CONFLICTS
+template<typename Scalar, int Options = AutoAlign> class Quaternion;
+template<typename Scalar,int Dim,int Mode,int _Options=AutoAlign> class Transform;
+template <typename _Scalar, int _AmbientDim, int Options=AutoAlign> class ParametrizedLine;
+template <typename _Scalar, int _AmbientDim, int Options=AutoAlign> class Hyperplane;
+template<typename Scalar> class UniformScaling;
+template<typename MatrixType,int Direction> class Homogeneous;
+#endif
+
+// MatrixFunctions module
+template<typename Derived> struct MatrixExponentialReturnValue;
+template<typename Derived> class MatrixFunctionReturnValue;
+template<typename Derived> class MatrixSquareRootReturnValue;
+template<typename Derived> class MatrixLogarithmReturnValue;
+
+namespace internal {
+template <typename Scalar>
+struct stem_function
+{
+ typedef std::complex<typename NumTraits<Scalar>::Real> ComplexScalar;
+ typedef ComplexScalar type(ComplexScalar, int);
+};
+}
+
+
+#ifdef EIGEN2_SUPPORT
+template<typename ExpressionType> class Cwise;
+template<typename MatrixType> class Minor;
+template<typename MatrixType> class LU;
+template<typename MatrixType> class QR;
+template<typename MatrixType> class SVD;
+namespace internal {
+template<typename MatrixType, unsigned int Mode> struct eigen2_part_return_type;
+}
+#endif
+
+} // end namespace Eigen
+
+#endif // EIGEN_FORWARDDECLARATIONS_H
diff --git a/Eigen/src/Core/util/MKL_support.h b/Eigen/src/Core/util/MKL_support.h
new file mode 100644
index 000000000..1e6e355d6
--- /dev/null
+++ b/Eigen/src/Core/util/MKL_support.h
@@ -0,0 +1,109 @@
+/*
+ Copyright (c) 2011, Intel Corporation. All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without modification,
+ are permitted provided that the following conditions are met:
+
+ * Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+ * Neither the name of Intel Corporation nor the names of its contributors may
+ be used to endorse or promote products derived from this software without
+ specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+ ********************************************************************************
+ * Content : Eigen bindings to Intel(R) MKL
+ * Include file with common MKL declarations
+ ********************************************************************************
+*/
+
+#ifndef EIGEN_MKL_SUPPORT_H
+#define EIGEN_MKL_SUPPORT_H
+
+#ifdef EIGEN_USE_MKL_ALL
+ #ifndef EIGEN_USE_BLAS
+ #define EIGEN_USE_BLAS
+ #endif
+ #ifndef EIGEN_USE_LAPACKE
+ #define EIGEN_USE_LAPACKE
+ #endif
+ #ifndef EIGEN_USE_MKL_VML
+ #define EIGEN_USE_MKL_VML
+ #endif
+#endif
+
+#ifdef EIGEN_USE_LAPACKE_STRICT
+ #define EIGEN_USE_LAPACKE
+#endif
+
+#if defined(EIGEN_USE_BLAS) || defined(EIGEN_USE_LAPACKE) || defined(EIGEN_USE_MKL_VML)
+ #define EIGEN_USE_MKL
+#endif
+
+#if defined EIGEN_USE_MKL
+
+#include <mkl.h>
+#include <mkl_lapacke.h>
+#define EIGEN_MKL_VML_THRESHOLD 128
+
+namespace Eigen {
+
+typedef std::complex<double> dcomplex;
+typedef std::complex<float> scomplex;
+
+namespace internal {
+
+template<typename MKLType, typename EigenType>
+static inline void assign_scalar_eig2mkl(MKLType& mklScalar, const EigenType& eigenScalar) {
+ mklScalar=eigenScalar;
+}
+
+template<typename MKLType, typename EigenType>
+static inline void assign_conj_scalar_eig2mkl(MKLType& mklScalar, const EigenType& eigenScalar) {
+ mklScalar=eigenScalar;
+}
+
+template <>
+inline void assign_scalar_eig2mkl<MKL_Complex16,dcomplex>(MKL_Complex16& mklScalar, const dcomplex& eigenScalar) {
+ mklScalar.real=eigenScalar.real();
+ mklScalar.imag=eigenScalar.imag();
+}
+
+template <>
+inline void assign_scalar_eig2mkl<MKL_Complex8,scomplex>(MKL_Complex8& mklScalar, const scomplex& eigenScalar) {
+ mklScalar.real=eigenScalar.real();
+ mklScalar.imag=eigenScalar.imag();
+}
+
+template <>
+inline void assign_conj_scalar_eig2mkl<MKL_Complex16,dcomplex>(MKL_Complex16& mklScalar, const dcomplex& eigenScalar) {
+ mklScalar.real=eigenScalar.real();
+ mklScalar.imag=-eigenScalar.imag();
+}
+
+template <>
+inline void assign_conj_scalar_eig2mkl<MKL_Complex8,scomplex>(MKL_Complex8& mklScalar, const scomplex& eigenScalar) {
+ mklScalar.real=eigenScalar.real();
+ mklScalar.imag=-eigenScalar.imag();
+}
+
+} // end namespace internal
+
+} // end namespace Eigen
+
+#endif
+
+#endif // EIGEN_MKL_SUPPORT_H
diff --git a/Eigen/src/Core/util/Macros.h b/Eigen/src/Core/util/Macros.h
new file mode 100644
index 000000000..d973a6837
--- /dev/null
+++ b/Eigen/src/Core/util/Macros.h
@@ -0,0 +1,410 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra.
+//
+// Copyright (C) 2008-2010 Gael Guennebaud <gael.guennebaud@inria.fr>
+// Copyright (C) 2006-2008 Benoit Jacob <jacob.benoit.1@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 EIGEN_MACROS_H
+#define EIGEN_MACROS_H
+
+#define EIGEN_WORLD_VERSION 3
+#define EIGEN_MAJOR_VERSION 1
+#define EIGEN_MINOR_VERSION 1
+
+#define EIGEN_VERSION_AT_LEAST(x,y,z) (EIGEN_WORLD_VERSION>x || (EIGEN_WORLD_VERSION>=x && \
+ (EIGEN_MAJOR_VERSION>y || (EIGEN_MAJOR_VERSION>=y && \
+ EIGEN_MINOR_VERSION>=z))))
+#ifdef __GNUC__
+ #define EIGEN_GNUC_AT_LEAST(x,y) ((__GNUC__==x && __GNUC_MINOR__>=y) || __GNUC__>x)
+#else
+ #define EIGEN_GNUC_AT_LEAST(x,y) 0
+#endif
+
+#ifdef __GNUC__
+ #define EIGEN_GNUC_AT_MOST(x,y) ((__GNUC__==x && __GNUC_MINOR__<=y) || __GNUC__<x)
+#else
+ #define EIGEN_GNUC_AT_MOST(x,y) 0
+#endif
+
+#if EIGEN_GNUC_AT_MOST(4,3) && !defined(__clang__)
+ // see bug 89
+ #define EIGEN_SAFE_TO_USE_STANDARD_ASSERT_MACRO 0
+#else
+ #define EIGEN_SAFE_TO_USE_STANDARD_ASSERT_MACRO 1
+#endif
+
+#if defined(__GNUC__) && (__GNUC__ <= 3)
+#define EIGEN_GCC3_OR_OLDER 1
+#else
+#define EIGEN_GCC3_OR_OLDER 0
+#endif
+
+// 16 byte alignment is only useful for vectorization. Since it affects the ABI, we need to enable
+// 16 byte alignment on all platforms where vectorization might be enabled. In theory we could always
+// enable alignment, but it can be a cause of problems on some platforms, so we just disable it in
+// certain common platform (compiler+architecture combinations) to avoid these problems.
+// Only static alignment is really problematic (relies on nonstandard compiler extensions that don't
+// work everywhere, for example don't work on GCC/ARM), try to keep heap alignment even
+// when we have to disable static alignment.
+#if defined(__GNUC__) && !(defined(__i386__) || defined(__x86_64__) || defined(__powerpc__) || defined(__ppc__) || defined(__ia64__))
+#define EIGEN_GCC_AND_ARCH_DOESNT_WANT_STACK_ALIGNMENT 1
+#else
+#define EIGEN_GCC_AND_ARCH_DOESNT_WANT_STACK_ALIGNMENT 0
+#endif
+
+// static alignment is completely disabled with GCC 3, Sun Studio, and QCC/QNX
+#if !EIGEN_GCC_AND_ARCH_DOESNT_WANT_STACK_ALIGNMENT \
+ && !EIGEN_GCC3_OR_OLDER \
+ && !defined(__SUNPRO_CC) \
+ && !defined(__QNXNTO__)
+ #define EIGEN_ARCH_WANTS_STACK_ALIGNMENT 1
+#else
+ #define EIGEN_ARCH_WANTS_STACK_ALIGNMENT 0
+#endif
+
+#ifdef EIGEN_DONT_ALIGN
+ #ifndef EIGEN_DONT_ALIGN_STATICALLY
+ #define EIGEN_DONT_ALIGN_STATICALLY
+ #endif
+ #define EIGEN_ALIGN 0
+#else
+ #define EIGEN_ALIGN 1
+#endif
+
+// EIGEN_ALIGN_STATICALLY is the true test whether we want to align arrays on the stack or not. It takes into account both the user choice to explicitly disable
+// alignment (EIGEN_DONT_ALIGN_STATICALLY) and the architecture config (EIGEN_ARCH_WANTS_STACK_ALIGNMENT). Henceforth, only EIGEN_ALIGN_STATICALLY should be used.
+#if EIGEN_ARCH_WANTS_STACK_ALIGNMENT && !defined(EIGEN_DONT_ALIGN_STATICALLY)
+ #define EIGEN_ALIGN_STATICALLY 1
+#else
+ #define EIGEN_ALIGN_STATICALLY 0
+ #ifndef EIGEN_DISABLE_UNALIGNED_ARRAY_ASSERT
+ #define EIGEN_DISABLE_UNALIGNED_ARRAY_ASSERT
+ #endif
+#endif
+
+#ifdef EIGEN_DEFAULT_TO_ROW_MAJOR
+#define EIGEN_DEFAULT_MATRIX_STORAGE_ORDER_OPTION RowMajor
+#else
+#define EIGEN_DEFAULT_MATRIX_STORAGE_ORDER_OPTION ColMajor
+#endif
+
+#ifndef EIGEN_DEFAULT_DENSE_INDEX_TYPE
+#define EIGEN_DEFAULT_DENSE_INDEX_TYPE std::ptrdiff_t
+#endif
+
+/** Allows to disable some optimizations which might affect the accuracy of the result.
+ * Such optimization are enabled by default, and set EIGEN_FAST_MATH to 0 to disable them.
+ * They currently include:
+ * - single precision Cwise::sin() and Cwise::cos() when SSE vectorization is enabled.
+ */
+#ifndef EIGEN_FAST_MATH
+#define EIGEN_FAST_MATH 1
+#endif
+
+#define EIGEN_DEBUG_VAR(x) std::cerr << #x << " = " << x << std::endl;
+
+// concatenate two tokens
+#define EIGEN_CAT2(a,b) a ## b
+#define EIGEN_CAT(a,b) EIGEN_CAT2(a,b)
+
+// convert a token to a string
+#define EIGEN_MAKESTRING2(a) #a
+#define EIGEN_MAKESTRING(a) EIGEN_MAKESTRING2(a)
+
+#if EIGEN_GNUC_AT_LEAST(4,1) && !defined(__clang__) && !defined(__INTEL_COMPILER)
+#define EIGEN_FLATTEN_ATTRIB __attribute__((flatten))
+#else
+#define EIGEN_FLATTEN_ATTRIB
+#endif
+
+// EIGEN_STRONG_INLINE is a stronger version of the inline, using __forceinline on MSVC,
+// but it still doesn't use GCC's always_inline. This is useful in (common) situations where MSVC needs forceinline
+// but GCC is still doing fine with just inline.
+#if (defined _MSC_VER) || (defined __INTEL_COMPILER)
+#define EIGEN_STRONG_INLINE __forceinline
+#else
+#define EIGEN_STRONG_INLINE inline
+#endif
+
+// EIGEN_ALWAYS_INLINE is the stronget, it has the effect of making the function inline and adding every possible
+// attribute to maximize inlining. This should only be used when really necessary: in particular,
+// it uses __attribute__((always_inline)) on GCC, which most of the time is useless and can severely harm compile times.
+// FIXME with the always_inline attribute,
+// gcc 3.4.x reports the following compilation error:
+// Eval.h:91: sorry, unimplemented: inlining failed in call to 'const Eigen::Eval<Derived> Eigen::MatrixBase<Scalar, Derived>::eval() const'
+// : function body not available
+#if EIGEN_GNUC_AT_LEAST(4,0)
+#define EIGEN_ALWAYS_INLINE __attribute__((always_inline)) inline
+#else
+#define EIGEN_ALWAYS_INLINE EIGEN_STRONG_INLINE
+#endif
+
+#if (defined __GNUC__)
+#define EIGEN_DONT_INLINE __attribute__((noinline))
+#elif (defined _MSC_VER)
+#define EIGEN_DONT_INLINE __declspec(noinline)
+#else
+#define EIGEN_DONT_INLINE
+#endif
+
+// this macro allows to get rid of linking errors about multiply defined functions.
+// - static is not very good because it prevents definitions from different object files to be merged.
+// So static causes the resulting linked executable to be bloated with multiple copies of the same function.
+// - inline is not perfect either as it unwantedly hints the compiler toward inlining the function.
+#define EIGEN_DECLARE_FUNCTION_ALLOWING_MULTIPLE_DEFINITIONS
+#define EIGEN_DEFINE_FUNCTION_ALLOWING_MULTIPLE_DEFINITIONS inline
+
+#ifdef NDEBUG
+# ifndef EIGEN_NO_DEBUG
+# define EIGEN_NO_DEBUG
+# endif
+#endif
+
+// eigen_plain_assert is where we implement the workaround for the assert() bug in GCC <= 4.3, see bug 89
+#ifdef EIGEN_NO_DEBUG
+ #define eigen_plain_assert(x)
+#else
+ #if EIGEN_SAFE_TO_USE_STANDARD_ASSERT_MACRO
+ namespace Eigen {
+ namespace internal {
+ inline bool copy_bool(bool b) { return b; }
+ }
+ }
+ #define eigen_plain_assert(x) assert(x)
+ #else
+ // work around bug 89
+ #include <cstdlib> // for abort
+ #include <iostream> // for std::cerr
+
+ namespace Eigen {
+ namespace internal {
+ // trivial function copying a bool. Must be EIGEN_DONT_INLINE, so we implement it after including Eigen headers.
+ // see bug 89.
+ namespace {
+ EIGEN_DONT_INLINE bool copy_bool(bool b) { return b; }
+ }
+ inline void assert_fail(const char *condition, const char *function, const char *file, int line)
+ {
+ std::cerr << "assertion failed: " << condition << " in function " << function << " at " << file << ":" << line << std::endl;
+ abort();
+ }
+ }
+ }
+ #define eigen_plain_assert(x) \
+ do { \
+ if(!Eigen::internal::copy_bool(x)) \
+ Eigen::internal::assert_fail(EIGEN_MAKESTRING(x), __PRETTY_FUNCTION__, __FILE__, __LINE__); \
+ } while(false)
+ #endif
+#endif
+
+// eigen_assert can be overridden
+#ifndef eigen_assert
+#define eigen_assert(x) eigen_plain_assert(x)
+#endif
+
+#ifdef EIGEN_INTERNAL_DEBUGGING
+#define eigen_internal_assert(x) eigen_assert(x)
+#else
+#define eigen_internal_assert(x)
+#endif
+
+#ifdef EIGEN_NO_DEBUG
+#define EIGEN_ONLY_USED_FOR_DEBUG(x) (void)x
+#else
+#define EIGEN_ONLY_USED_FOR_DEBUG(x)
+#endif
+
+#ifndef EIGEN_NO_DEPRECATED_WARNING
+ #if (defined __GNUC__)
+ #define EIGEN_DEPRECATED __attribute__((deprecated))
+ #elif (defined _MSC_VER)
+ #define EIGEN_DEPRECATED __declspec(deprecated)
+ #else
+ #define EIGEN_DEPRECATED
+ #endif
+#else
+ #define EIGEN_DEPRECATED
+#endif
+
+#if (defined __GNUC__)
+#define EIGEN_UNUSED __attribute__((unused))
+#else
+#define EIGEN_UNUSED
+#endif
+
+// Suppresses 'unused variable' warnings.
+#define EIGEN_UNUSED_VARIABLE(var) (void)var;
+
+#if !defined(EIGEN_ASM_COMMENT) && (defined __GNUC__)
+#define EIGEN_ASM_COMMENT(X) asm("#" X)
+#else
+#define EIGEN_ASM_COMMENT(X)
+#endif
+
+/* EIGEN_ALIGN_TO_BOUNDARY(n) forces data to be n-byte aligned. This is used to satisfy SIMD requirements.
+ * However, we do that EVEN if vectorization (EIGEN_VECTORIZE) is disabled,
+ * so that vectorization doesn't affect binary compatibility.
+ *
+ * If we made alignment depend on whether or not EIGEN_VECTORIZE is defined, it would be impossible to link
+ * vectorized and non-vectorized code.
+ */
+#if (defined __GNUC__) || (defined __PGI) || (defined __IBMCPP__) || (defined __ARMCC_VERSION)
+ #define EIGEN_ALIGN_TO_BOUNDARY(n) __attribute__((aligned(n)))
+#elif (defined _MSC_VER)
+ #define EIGEN_ALIGN_TO_BOUNDARY(n) __declspec(align(n))
+#elif (defined __SUNPRO_CC)
+ // FIXME not sure about this one:
+ #define EIGEN_ALIGN_TO_BOUNDARY(n) __attribute__((aligned(n)))
+#else
+ #error Please tell me what is the equivalent of __attribute__((aligned(n))) for your compiler
+#endif
+
+#define EIGEN_ALIGN16 EIGEN_ALIGN_TO_BOUNDARY(16)
+
+#if EIGEN_ALIGN_STATICALLY
+#define EIGEN_USER_ALIGN_TO_BOUNDARY(n) EIGEN_ALIGN_TO_BOUNDARY(n)
+#define EIGEN_USER_ALIGN16 EIGEN_ALIGN16
+#else
+#define EIGEN_USER_ALIGN_TO_BOUNDARY(n)
+#define EIGEN_USER_ALIGN16
+#endif
+
+#ifdef EIGEN_DONT_USE_RESTRICT_KEYWORD
+ #define EIGEN_RESTRICT
+#endif
+#ifndef EIGEN_RESTRICT
+ #define EIGEN_RESTRICT __restrict
+#endif
+
+#ifndef EIGEN_STACK_ALLOCATION_LIMIT
+#define EIGEN_STACK_ALLOCATION_LIMIT 20000
+#endif
+
+#ifndef EIGEN_DEFAULT_IO_FORMAT
+#ifdef EIGEN_MAKING_DOCS
+// format used in Eigen's documentation
+// needed to define it here as escaping characters in CMake add_definition's argument seems very problematic.
+#define EIGEN_DEFAULT_IO_FORMAT Eigen::IOFormat(3, 0, " ", "\n", "", "")
+#else
+#define EIGEN_DEFAULT_IO_FORMAT Eigen::IOFormat()
+#endif
+#endif
+
+// just an empty macro !
+#define EIGEN_EMPTY
+
+#if defined(_MSC_VER) && (!defined(__INTEL_COMPILER))
+#define EIGEN_INHERIT_ASSIGNMENT_EQUAL_OPERATOR(Derived) \
+ using Base::operator =;
+#else
+#define EIGEN_INHERIT_ASSIGNMENT_EQUAL_OPERATOR(Derived) \
+ using Base::operator =; \
+ EIGEN_STRONG_INLINE Derived& operator=(const Derived& other) \
+ { \
+ Base::operator=(other); \
+ return *this; \
+ }
+#endif
+
+#define EIGEN_INHERIT_ASSIGNMENT_OPERATORS(Derived) \
+ EIGEN_INHERIT_ASSIGNMENT_EQUAL_OPERATOR(Derived)
+
+/**
+* Just a side note. Commenting within defines works only by documenting
+* behind the object (via '!<'). Comments cannot be multi-line and thus
+* we have these extra long lines. What is confusing doxygen over here is
+* that we use '\' and basically have a bunch of typedefs with their
+* documentation in a single line.
+**/
+
+#define EIGEN_GENERIC_PUBLIC_INTERFACE(Derived) \
+ typedef typename Eigen::internal::traits<Derived>::Scalar Scalar; /*!< \brief Numeric type, e.g. float, double, int or std::complex<float>. */ \
+ typedef typename Eigen::NumTraits<Scalar>::Real RealScalar; /*!< \brief The underlying numeric type for composed scalar types. \details In cases where Scalar is e.g. std::complex<T>, T were corresponding to RealScalar. */ \
+ typedef typename Base::CoeffReturnType CoeffReturnType; /*!< \brief The return type for coefficient access. \details Depending on whether the object allows direct coefficient access (e.g. for a MatrixXd), this type is either 'const Scalar&' or simply 'Scalar' for objects that do not allow direct coefficient access. */ \
+ typedef typename Eigen::internal::nested<Derived>::type Nested; \
+ typedef typename Eigen::internal::traits<Derived>::StorageKind StorageKind; \
+ typedef typename Eigen::internal::traits<Derived>::Index Index; \
+ enum { RowsAtCompileTime = Eigen::internal::traits<Derived>::RowsAtCompileTime, \
+ ColsAtCompileTime = Eigen::internal::traits<Derived>::ColsAtCompileTime, \
+ Flags = Eigen::internal::traits<Derived>::Flags, \
+ CoeffReadCost = Eigen::internal::traits<Derived>::CoeffReadCost, \
+ SizeAtCompileTime = Base::SizeAtCompileTime, \
+ MaxSizeAtCompileTime = Base::MaxSizeAtCompileTime, \
+ IsVectorAtCompileTime = Base::IsVectorAtCompileTime };
+
+
+#define EIGEN_DENSE_PUBLIC_INTERFACE(Derived) \
+ typedef typename Eigen::internal::traits<Derived>::Scalar Scalar; /*!< \brief Numeric type, e.g. float, double, int or std::complex<float>. */ \
+ typedef typename Eigen::NumTraits<Scalar>::Real RealScalar; /*!< \brief The underlying numeric type for composed scalar types. \details In cases where Scalar is e.g. std::complex<T>, T were corresponding to RealScalar. */ \
+ typedef typename Base::PacketScalar PacketScalar; \
+ typedef typename Base::CoeffReturnType CoeffReturnType; /*!< \brief The return type for coefficient access. \details Depending on whether the object allows direct coefficient access (e.g. for a MatrixXd), this type is either 'const Scalar&' or simply 'Scalar' for objects that do not allow direct coefficient access. */ \
+ typedef typename Eigen::internal::nested<Derived>::type Nested; \
+ typedef typename Eigen::internal::traits<Derived>::StorageKind StorageKind; \
+ typedef typename Eigen::internal::traits<Derived>::Index Index; \
+ enum { RowsAtCompileTime = Eigen::internal::traits<Derived>::RowsAtCompileTime, \
+ ColsAtCompileTime = Eigen::internal::traits<Derived>::ColsAtCompileTime, \
+ MaxRowsAtCompileTime = Eigen::internal::traits<Derived>::MaxRowsAtCompileTime, \
+ MaxColsAtCompileTime = Eigen::internal::traits<Derived>::MaxColsAtCompileTime, \
+ Flags = Eigen::internal::traits<Derived>::Flags, \
+ CoeffReadCost = Eigen::internal::traits<Derived>::CoeffReadCost, \
+ SizeAtCompileTime = Base::SizeAtCompileTime, \
+ MaxSizeAtCompileTime = Base::MaxSizeAtCompileTime, \
+ IsVectorAtCompileTime = Base::IsVectorAtCompileTime }; \
+ using Base::derived; \
+ using Base::const_cast_derived;
+
+
+#define EIGEN_PLAIN_ENUM_MIN(a,b) (((int)a <= (int)b) ? (int)a : (int)b)
+#define EIGEN_PLAIN_ENUM_MAX(a,b) (((int)a >= (int)b) ? (int)a : (int)b)
+
+// EIGEN_SIZE_MIN_PREFER_DYNAMIC gives the min between compile-time sizes. 0 has absolute priority, followed by 1,
+// followed by Dynamic, followed by other finite values. The reason for giving Dynamic the priority over
+// finite values is that min(3, Dynamic) should be Dynamic, since that could be anything between 0 and 3.
+#define EIGEN_SIZE_MIN_PREFER_DYNAMIC(a,b) (((int)a == 0 || (int)b == 0) ? 0 \
+ : ((int)a == 1 || (int)b == 1) ? 1 \
+ : ((int)a == Dynamic || (int)b == Dynamic) ? Dynamic \
+ : ((int)a <= (int)b) ? (int)a : (int)b)
+
+// EIGEN_SIZE_MIN_PREFER_FIXED is a variant of EIGEN_SIZE_MIN_PREFER_DYNAMIC comparing MaxSizes. The difference is that finite values
+// now have priority over Dynamic, so that min(3, Dynamic) gives 3. Indeed, whatever the actual value is
+// (between 0 and 3), it is not more than 3.
+#define EIGEN_SIZE_MIN_PREFER_FIXED(a,b) (((int)a == 0 || (int)b == 0) ? 0 \
+ : ((int)a == 1 || (int)b == 1) ? 1 \
+ : ((int)a == Dynamic && (int)b == Dynamic) ? Dynamic \
+ : ((int)a == Dynamic) ? (int)b \
+ : ((int)b == Dynamic) ? (int)a \
+ : ((int)a <= (int)b) ? (int)a : (int)b)
+
+// see EIGEN_SIZE_MIN_PREFER_DYNAMIC. No need for a separate variant for MaxSizes here.
+#define EIGEN_SIZE_MAX(a,b) (((int)a == Dynamic || (int)b == Dynamic) ? Dynamic \
+ : ((int)a >= (int)b) ? (int)a : (int)b)
+
+#define EIGEN_LOGICAL_XOR(a,b) (((a) || (b)) && !((a) && (b)))
+
+#define EIGEN_IMPLIES(a,b) (!(a) || (b))
+
+#define EIGEN_MAKE_CWISE_BINARY_OP(METHOD,FUNCTOR) \
+ template<typename OtherDerived> \
+ EIGEN_STRONG_INLINE const CwiseBinaryOp<FUNCTOR<Scalar>, const Derived, const OtherDerived> \
+ (METHOD)(const EIGEN_CURRENT_STORAGE_BASE_CLASS<OtherDerived> &other) const \
+ { \
+ return CwiseBinaryOp<FUNCTOR<Scalar>, const Derived, const OtherDerived>(derived(), other.derived()); \
+ }
+
+// the expression type of a cwise product
+#define EIGEN_CWISE_PRODUCT_RETURN_TYPE(LHS,RHS) \
+ CwiseBinaryOp< \
+ internal::scalar_product_op< \
+ typename internal::traits<LHS>::Scalar, \
+ typename internal::traits<RHS>::Scalar \
+ >, \
+ const LHS, \
+ const RHS \
+ >
+
+#endif // EIGEN_MACROS_H
diff --git a/Eigen/src/Core/util/Memory.h b/Eigen/src/Core/util/Memory.h
new file mode 100644
index 000000000..6e06ace44
--- /dev/null
+++ b/Eigen/src/Core/util/Memory.h
@@ -0,0 +1,952 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra.
+//
+// Copyright (C) 2008-2010 Gael Guennebaud <gael.guennebaud@inria.fr>
+// Copyright (C) 2008-2009 Benoit Jacob <jacob.benoit.1@gmail.com>
+// Copyright (C) 2009 Kenneth Riddile <kfriddile@yahoo.com>
+// Copyright (C) 2010 Hauke Heibel <hauke.heibel@gmail.com>
+// Copyright (C) 2010 Thomas Capricelli <orzel@freehackers.org>
+//
+// This Source Code Form is subject to the terms of the Mozilla
+// Public License v. 2.0. If a copy of the MPL was not distributed
+// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+
+/*****************************************************************************
+*** Platform checks for aligned malloc functions ***
+*****************************************************************************/
+
+#ifndef EIGEN_MEMORY_H
+#define EIGEN_MEMORY_H
+
+// On 64-bit systems, glibc's malloc returns 16-byte-aligned pointers, see:
+// http://www.gnu.org/s/libc/manual/html_node/Aligned-Memory-Blocks.html
+// This is true at least since glibc 2.8.
+// This leaves the question how to detect 64-bit. According to this document,
+// http://gcc.fyxm.net/summit/2003/Porting%20to%2064%20bit.pdf
+// page 114, "[The] LP64 model [...] is used by all 64-bit UNIX ports" so it's indeed
+// quite safe, at least within the context of glibc, to equate 64-bit with LP64.
+#if defined(__GLIBC__) && ((__GLIBC__>=2 && __GLIBC_MINOR__ >= 8) || __GLIBC__>2) \
+ && defined(__LP64__)
+ #define EIGEN_GLIBC_MALLOC_ALREADY_ALIGNED 1
+#else
+ #define EIGEN_GLIBC_MALLOC_ALREADY_ALIGNED 0
+#endif
+
+// FreeBSD 6 seems to have 16-byte aligned malloc
+// See http://svn.freebsd.org/viewvc/base/stable/6/lib/libc/stdlib/malloc.c?view=markup
+// FreeBSD 7 seems to have 16-byte aligned malloc except on ARM and MIPS architectures
+// See http://svn.freebsd.org/viewvc/base/stable/7/lib/libc/stdlib/malloc.c?view=markup
+#if defined(__FreeBSD__) && !defined(__arm__) && !defined(__mips__)
+ #define EIGEN_FREEBSD_MALLOC_ALREADY_ALIGNED 1
+#else
+ #define EIGEN_FREEBSD_MALLOC_ALREADY_ALIGNED 0
+#endif
+
+#if defined(__APPLE__) \
+ || defined(_WIN64) \
+ || EIGEN_GLIBC_MALLOC_ALREADY_ALIGNED \
+ || EIGEN_FREEBSD_MALLOC_ALREADY_ALIGNED
+ #define EIGEN_MALLOC_ALREADY_ALIGNED 1
+#else
+ #define EIGEN_MALLOC_ALREADY_ALIGNED 0
+#endif
+
+#if ((defined __QNXNTO__) || (defined _GNU_SOURCE) || ((defined _XOPEN_SOURCE) && (_XOPEN_SOURCE >= 600))) \
+ && (defined _POSIX_ADVISORY_INFO) && (_POSIX_ADVISORY_INFO > 0)
+ #define EIGEN_HAS_POSIX_MEMALIGN 1
+#else
+ #define EIGEN_HAS_POSIX_MEMALIGN 0
+#endif
+
+#ifdef EIGEN_VECTORIZE_SSE
+ #define EIGEN_HAS_MM_MALLOC 1
+#else
+ #define EIGEN_HAS_MM_MALLOC 0
+#endif
+
+namespace Eigen {
+
+namespace internal {
+
+inline void throw_std_bad_alloc()
+{
+ #ifdef EIGEN_EXCEPTIONS
+ throw std::bad_alloc();
+ #else
+ std::size_t huge = -1;
+ new int[huge];
+ #endif
+}
+
+/*****************************************************************************
+*** Implementation of handmade aligned functions ***
+*****************************************************************************/
+
+/* ----- Hand made implementations of aligned malloc/free and realloc ----- */
+
+/** \internal Like malloc, but the returned pointer is guaranteed to be 16-byte aligned.
+ * Fast, but wastes 16 additional bytes of memory. Does not throw any exception.
+ */
+inline void* handmade_aligned_malloc(size_t size)
+{
+ void *original = std::malloc(size+16);
+ if (original == 0) return 0;
+ void *aligned = reinterpret_cast<void*>((reinterpret_cast<size_t>(original) & ~(size_t(15))) + 16);
+ *(reinterpret_cast<void**>(aligned) - 1) = original;
+ return aligned;
+}
+
+/** \internal Frees memory allocated with handmade_aligned_malloc */
+inline void handmade_aligned_free(void *ptr)
+{
+ if (ptr) std::free(*(reinterpret_cast<void**>(ptr) - 1));
+}
+
+/** \internal
+ * \brief Reallocates aligned memory.
+ * Since we know that our handmade version is based on std::realloc
+ * we can use std::realloc to implement efficient reallocation.
+ */
+inline void* handmade_aligned_realloc(void* ptr, size_t size, size_t = 0)
+{
+ if (ptr == 0) return handmade_aligned_malloc(size);
+ void *original = *(reinterpret_cast<void**>(ptr) - 1);
+ original = std::realloc(original,size+16);
+ if (original == 0) return 0;
+ void *aligned = reinterpret_cast<void*>((reinterpret_cast<size_t>(original) & ~(size_t(15))) + 16);
+ *(reinterpret_cast<void**>(aligned) - 1) = original;
+ return aligned;
+}
+
+/*****************************************************************************
+*** Implementation of generic aligned realloc (when no realloc can be used)***
+*****************************************************************************/
+
+void* aligned_malloc(size_t size);
+void aligned_free(void *ptr);
+
+/** \internal
+ * \brief Reallocates aligned memory.
+ * Allows reallocation with aligned ptr types. This implementation will
+ * always create a new memory chunk and copy the old data.
+ */
+inline void* generic_aligned_realloc(void* ptr, size_t size, size_t old_size)
+{
+ if (ptr==0)
+ return aligned_malloc(size);
+
+ if (size==0)
+ {
+ aligned_free(ptr);
+ return 0;
+ }
+
+ void* newptr = aligned_malloc(size);
+ if (newptr == 0)
+ {
+ #ifdef EIGEN_HAS_ERRNO
+ errno = ENOMEM; // according to the standard
+ #endif
+ return 0;
+ }
+
+ if (ptr != 0)
+ {
+ std::memcpy(newptr, ptr, (std::min)(size,old_size));
+ aligned_free(ptr);
+ }
+
+ return newptr;
+}
+
+/*****************************************************************************
+*** Implementation of portable aligned versions of malloc/free/realloc ***
+*****************************************************************************/
+
+#ifdef EIGEN_NO_MALLOC
+inline void check_that_malloc_is_allowed()
+{
+ eigen_assert(false && "heap allocation is forbidden (EIGEN_NO_MALLOC is defined)");
+}
+#elif defined EIGEN_RUNTIME_NO_MALLOC
+inline bool is_malloc_allowed_impl(bool update, bool new_value = false)
+{
+ static bool value = true;
+ if (update == 1)
+ value = new_value;
+ return value;
+}
+inline bool is_malloc_allowed() { return is_malloc_allowed_impl(false); }
+inline bool set_is_malloc_allowed(bool new_value) { return is_malloc_allowed_impl(true, new_value); }
+inline void check_that_malloc_is_allowed()
+{
+ eigen_assert(is_malloc_allowed() && "heap allocation is forbidden (EIGEN_RUNTIME_NO_MALLOC is defined and g_is_malloc_allowed is false)");
+}
+#else
+inline void check_that_malloc_is_allowed()
+{}
+#endif
+
+/** \internal Allocates \a size bytes. The returned pointer is guaranteed to have 16 bytes alignment.
+ * On allocation error, the returned pointer is null, and std::bad_alloc is thrown.
+ */
+inline void* aligned_malloc(size_t size)
+{
+ check_that_malloc_is_allowed();
+
+ void *result;
+ #if !EIGEN_ALIGN
+ result = std::malloc(size);
+ #elif EIGEN_MALLOC_ALREADY_ALIGNED
+ result = std::malloc(size);
+ #elif EIGEN_HAS_POSIX_MEMALIGN
+ if(posix_memalign(&result, 16, size)) result = 0;
+ #elif EIGEN_HAS_MM_MALLOC
+ result = _mm_malloc(size, 16);
+ #elif (defined _MSC_VER)
+ result = _aligned_malloc(size, 16);
+ #else
+ result = handmade_aligned_malloc(size);
+ #endif
+
+ if(!result && size)
+ throw_std_bad_alloc();
+
+ return result;
+}
+
+/** \internal Frees memory allocated with aligned_malloc. */
+inline void aligned_free(void *ptr)
+{
+ #if !EIGEN_ALIGN
+ std::free(ptr);
+ #elif EIGEN_MALLOC_ALREADY_ALIGNED
+ std::free(ptr);
+ #elif EIGEN_HAS_POSIX_MEMALIGN
+ std::free(ptr);
+ #elif EIGEN_HAS_MM_MALLOC
+ _mm_free(ptr);
+ #elif defined(_MSC_VER)
+ _aligned_free(ptr);
+ #else
+ handmade_aligned_free(ptr);
+ #endif
+}
+
+/**
+* \internal
+* \brief Reallocates an aligned block of memory.
+* \throws std::bad_alloc on allocation failure
+**/
+inline void* aligned_realloc(void *ptr, size_t new_size, size_t old_size)
+{
+ EIGEN_UNUSED_VARIABLE(old_size);
+
+ void *result;
+#if !EIGEN_ALIGN
+ result = std::realloc(ptr,new_size);
+#elif EIGEN_MALLOC_ALREADY_ALIGNED
+ result = std::realloc(ptr,new_size);
+#elif EIGEN_HAS_POSIX_MEMALIGN
+ result = generic_aligned_realloc(ptr,new_size,old_size);
+#elif EIGEN_HAS_MM_MALLOC
+ // The defined(_mm_free) is just here to verify that this MSVC version
+ // implements _mm_malloc/_mm_free based on the corresponding _aligned_
+ // functions. This may not always be the case and we just try to be safe.
+ #if defined(_MSC_VER) && defined(_mm_free)
+ result = _aligned_realloc(ptr,new_size,16);
+ #else
+ result = generic_aligned_realloc(ptr,new_size,old_size);
+ #endif
+#elif defined(_MSC_VER)
+ result = _aligned_realloc(ptr,new_size,16);
+#else
+ result = handmade_aligned_realloc(ptr,new_size,old_size);
+#endif
+
+ if (!result && new_size)
+ throw_std_bad_alloc();
+
+ return result;
+}
+
+/*****************************************************************************
+*** Implementation of conditionally aligned functions ***
+*****************************************************************************/
+
+/** \internal Allocates \a size bytes. If Align is true, then the returned ptr is 16-byte-aligned.
+ * On allocation error, the returned pointer is null, and a std::bad_alloc is thrown.
+ */
+template<bool Align> inline void* conditional_aligned_malloc(size_t size)
+{
+ return aligned_malloc(size);
+}
+
+template<> inline void* conditional_aligned_malloc<false>(size_t size)
+{
+ check_that_malloc_is_allowed();
+
+ void *result = std::malloc(size);
+ if(!result && size)
+ throw_std_bad_alloc();
+ return result;
+}
+
+/** \internal Frees memory allocated with conditional_aligned_malloc */
+template<bool Align> inline void conditional_aligned_free(void *ptr)
+{
+ aligned_free(ptr);
+}
+
+template<> inline void conditional_aligned_free<false>(void *ptr)
+{
+ std::free(ptr);
+}
+
+template<bool Align> inline void* conditional_aligned_realloc(void* ptr, size_t new_size, size_t old_size)
+{
+ return aligned_realloc(ptr, new_size, old_size);
+}
+
+template<> inline void* conditional_aligned_realloc<false>(void* ptr, size_t new_size, size_t)
+{
+ return std::realloc(ptr, new_size);
+}
+
+/*****************************************************************************
+*** Construction/destruction of array elements ***
+*****************************************************************************/
+
+/** \internal Constructs the elements of an array.
+ * The \a size parameter tells on how many objects to call the constructor of T.
+ */
+template<typename T> inline T* construct_elements_of_array(T *ptr, size_t size)
+{
+ for (size_t i=0; i < size; ++i) ::new (ptr + i) T;
+ return ptr;
+}
+
+/** \internal Destructs the elements of an array.
+ * The \a size parameters tells on how many objects to call the destructor of T.
+ */
+template<typename T> inline void destruct_elements_of_array(T *ptr, size_t size)
+{
+ // always destruct an array starting from the end.
+ if(ptr)
+ while(size) ptr[--size].~T();
+}
+
+/*****************************************************************************
+*** Implementation of aligned new/delete-like functions ***
+*****************************************************************************/
+
+template<typename T>
+EIGEN_ALWAYS_INLINE void check_size_for_overflow(size_t size)
+{
+ if(size > size_t(-1) / sizeof(T))
+ throw_std_bad_alloc();
+}
+
+/** \internal Allocates \a size objects of type T. The returned pointer is guaranteed to have 16 bytes alignment.
+ * On allocation error, the returned pointer is undefined, but a std::bad_alloc is thrown.
+ * The default constructor of T is called.
+ */
+template<typename T> inline T* aligned_new(size_t size)
+{
+ check_size_for_overflow<T>(size);
+ T *result = reinterpret_cast<T*>(aligned_malloc(sizeof(T)*size));
+ return construct_elements_of_array(result, size);
+}
+
+template<typename T, bool Align> inline T* conditional_aligned_new(size_t size)
+{
+ check_size_for_overflow<T>(size);
+ T *result = reinterpret_cast<T*>(conditional_aligned_malloc<Align>(sizeof(T)*size));
+ return construct_elements_of_array(result, size);
+}
+
+/** \internal Deletes objects constructed with aligned_new
+ * The \a size parameters tells on how many objects to call the destructor of T.
+ */
+template<typename T> inline void aligned_delete(T *ptr, size_t size)
+{
+ destruct_elements_of_array<T>(ptr, size);
+ aligned_free(ptr);
+}
+
+/** \internal Deletes objects constructed with conditional_aligned_new
+ * The \a size parameters tells on how many objects to call the destructor of T.
+ */
+template<typename T, bool Align> inline void conditional_aligned_delete(T *ptr, size_t size)
+{
+ destruct_elements_of_array<T>(ptr, size);
+ conditional_aligned_free<Align>(ptr);
+}
+
+template<typename T, bool Align> inline T* conditional_aligned_realloc_new(T* pts, size_t new_size, size_t old_size)
+{
+ check_size_for_overflow<T>(new_size);
+ check_size_for_overflow<T>(old_size);
+ if(new_size < old_size)
+ destruct_elements_of_array(pts+new_size, old_size-new_size);
+ T *result = reinterpret_cast<T*>(conditional_aligned_realloc<Align>(reinterpret_cast<void*>(pts), sizeof(T)*new_size, sizeof(T)*old_size));
+ if(new_size > old_size)
+ construct_elements_of_array(result+old_size, new_size-old_size);
+ return result;
+}
+
+
+template<typename T, bool Align> inline T* conditional_aligned_new_auto(size_t size)
+{
+ check_size_for_overflow<T>(size);
+ T *result = reinterpret_cast<T*>(conditional_aligned_malloc<Align>(sizeof(T)*size));
+ if(NumTraits<T>::RequireInitialization)
+ construct_elements_of_array(result, size);
+ return result;
+}
+
+template<typename T, bool Align> inline T* conditional_aligned_realloc_new_auto(T* pts, size_t new_size, size_t old_size)
+{
+ check_size_for_overflow<T>(new_size);
+ check_size_for_overflow<T>(old_size);
+ if(NumTraits<T>::RequireInitialization && (new_size < old_size))
+ destruct_elements_of_array(pts+new_size, old_size-new_size);
+ T *result = reinterpret_cast<T*>(conditional_aligned_realloc<Align>(reinterpret_cast<void*>(pts), sizeof(T)*new_size, sizeof(T)*old_size));
+ if(NumTraits<T>::RequireInitialization && (new_size > old_size))
+ construct_elements_of_array(result+old_size, new_size-old_size);
+ return result;
+}
+
+template<typename T, bool Align> inline void conditional_aligned_delete_auto(T *ptr, size_t size)
+{
+ if(NumTraits<T>::RequireInitialization)
+ destruct_elements_of_array<T>(ptr, size);
+ conditional_aligned_free<Align>(ptr);
+}
+
+/****************************************************************************/
+
+/** \internal Returns the index of the first element of the array that is well aligned for vectorization.
+ *
+ * \param array the address of the start of the array
+ * \param size the size of the array
+ *
+ * \note If no element of the array is well aligned, the size of the array is returned. Typically,
+ * for example with SSE, "well aligned" means 16-byte-aligned. If vectorization is disabled or if the
+ * packet size for the given scalar type is 1, then everything is considered well-aligned.
+ *
+ * \note If the scalar type is vectorizable, we rely on the following assumptions: sizeof(Scalar) is a
+ * power of 2, the packet size in bytes is also a power of 2, and is a multiple of sizeof(Scalar). On the
+ * other hand, we do not assume that the array address is a multiple of sizeof(Scalar), as that fails for
+ * example with Scalar=double on certain 32-bit platforms, see bug #79.
+ *
+ * There is also the variant first_aligned(const MatrixBase&) defined in DenseCoeffsBase.h.
+ */
+template<typename Scalar, typename Index>
+static inline Index first_aligned(const Scalar* array, Index size)
+{
+ typedef typename packet_traits<Scalar>::type Packet;
+ enum { PacketSize = packet_traits<Scalar>::size,
+ PacketAlignedMask = PacketSize-1
+ };
+
+ if(PacketSize==1)
+ {
+ // Either there is no vectorization, or a packet consists of exactly 1 scalar so that all elements
+ // of the array have the same alignment.
+ return 0;
+ }
+ else if(size_t(array) & (sizeof(Scalar)-1))
+ {
+ // There is vectorization for this scalar type, but the array is not aligned to the size of a single scalar.
+ // Consequently, no element of the array is well aligned.
+ return size;
+ }
+ else
+ {
+ return std::min<Index>( (PacketSize - (Index((size_t(array)/sizeof(Scalar))) & PacketAlignedMask))
+ & PacketAlignedMask, size);
+ }
+}
+
+
+// std::copy is much slower than memcpy, so let's introduce a smart_copy which
+// use memcpy on trivial types, i.e., on types that does not require an initialization ctor.
+template<typename T, bool UseMemcpy> struct smart_copy_helper;
+
+template<typename T> void smart_copy(const T* start, const T* end, T* target)
+{
+ smart_copy_helper<T,!NumTraits<T>::RequireInitialization>::run(start, end, target);
+}
+
+template<typename T> struct smart_copy_helper<T,true> {
+ static inline void run(const T* start, const T* end, T* target)
+ { memcpy(target, start, std::ptrdiff_t(end)-std::ptrdiff_t(start)); }
+};
+
+template<typename T> struct smart_copy_helper<T,false> {
+ static inline void run(const T* start, const T* end, T* target)
+ { std::copy(start, end, target); }
+};
+
+
+/*****************************************************************************
+*** Implementation of runtime stack allocation (falling back to malloc) ***
+*****************************************************************************/
+
+// you can overwrite Eigen's default behavior regarding alloca by defining EIGEN_ALLOCA
+// to the appropriate stack allocation function
+#ifndef EIGEN_ALLOCA
+ #if (defined __linux__)
+ #define EIGEN_ALLOCA alloca
+ #elif defined(_MSC_VER)
+ #define EIGEN_ALLOCA _alloca
+ #endif
+#endif
+
+// This helper class construct the allocated memory, and takes care of destructing and freeing the handled data
+// at destruction time. In practice this helper class is mainly useful to avoid memory leak in case of exceptions.
+template<typename T> class aligned_stack_memory_handler
+{
+ public:
+ /* Creates a stack_memory_handler responsible for the buffer \a ptr of size \a size.
+ * Note that \a ptr can be 0 regardless of the other parameters.
+ * This constructor takes care of constructing/initializing the elements of the buffer if required by the scalar type T (see NumTraits<T>::RequireInitialization).
+ * In this case, the buffer elements will also be destructed when this handler will be destructed.
+ * Finally, if \a dealloc is true, then the pointer \a ptr is freed.
+ **/
+ aligned_stack_memory_handler(T* ptr, size_t size, bool dealloc)
+ : m_ptr(ptr), m_size(size), m_deallocate(dealloc)
+ {
+ if(NumTraits<T>::RequireInitialization && m_ptr)
+ Eigen::internal::construct_elements_of_array(m_ptr, size);
+ }
+ ~aligned_stack_memory_handler()
+ {
+ if(NumTraits<T>::RequireInitialization && m_ptr)
+ Eigen::internal::destruct_elements_of_array<T>(m_ptr, m_size);
+ if(m_deallocate)
+ Eigen::internal::aligned_free(m_ptr);
+ }
+ protected:
+ T* m_ptr;
+ size_t m_size;
+ bool m_deallocate;
+};
+
+} // end namespace internal
+
+/** \internal
+ * Declares, allocates and construct an aligned buffer named NAME of SIZE elements of type TYPE on the stack
+ * if SIZE is smaller than EIGEN_STACK_ALLOCATION_LIMIT, and if stack allocation is supported by the platform
+ * (currently, this is Linux and Visual Studio only). Otherwise the memory is allocated on the heap.
+ * The allocated buffer is automatically deleted when exiting the scope of this declaration.
+ * If BUFFER is non null, then the declared variable is simply an alias for BUFFER, and no allocation/deletion occurs.
+ * Here is an example:
+ * \code
+ * {
+ * ei_declare_aligned_stack_constructed_variable(float,data,size,0);
+ * // use data[0] to data[size-1]
+ * }
+ * \endcode
+ * The underlying stack allocation function can controlled with the EIGEN_ALLOCA preprocessor token.
+ */
+#ifdef EIGEN_ALLOCA
+
+ #ifdef __arm__
+ #define EIGEN_ALIGNED_ALLOCA(SIZE) reinterpret_cast<void*>((reinterpret_cast<size_t>(EIGEN_ALLOCA(SIZE+16)) & ~(size_t(15))) + 16)
+ #else
+ #define EIGEN_ALIGNED_ALLOCA EIGEN_ALLOCA
+ #endif
+
+ #define ei_declare_aligned_stack_constructed_variable(TYPE,NAME,SIZE,BUFFER) \
+ Eigen::internal::check_size_for_overflow<TYPE>(SIZE); \
+ TYPE* NAME = (BUFFER)!=0 ? (BUFFER) \
+ : reinterpret_cast<TYPE*>( \
+ (sizeof(TYPE)*SIZE<=EIGEN_STACK_ALLOCATION_LIMIT) ? EIGEN_ALIGNED_ALLOCA(sizeof(TYPE)*SIZE) \
+ : Eigen::internal::aligned_malloc(sizeof(TYPE)*SIZE) ); \
+ Eigen::internal::aligned_stack_memory_handler<TYPE> EIGEN_CAT(NAME,_stack_memory_destructor)((BUFFER)==0 ? NAME : 0,SIZE,sizeof(TYPE)*SIZE>EIGEN_STACK_ALLOCATION_LIMIT)
+
+#else
+
+ #define ei_declare_aligned_stack_constructed_variable(TYPE,NAME,SIZE,BUFFER) \
+ Eigen::internal::check_size_for_overflow<TYPE>(SIZE); \
+ TYPE* NAME = (BUFFER)!=0 ? BUFFER : reinterpret_cast<TYPE*>(Eigen::internal::aligned_malloc(sizeof(TYPE)*SIZE)); \
+ Eigen::internal::aligned_stack_memory_handler<TYPE> EIGEN_CAT(NAME,_stack_memory_destructor)((BUFFER)==0 ? NAME : 0,SIZE,true)
+
+#endif
+
+
+/*****************************************************************************
+*** Implementation of EIGEN_MAKE_ALIGNED_OPERATOR_NEW [_IF] ***
+*****************************************************************************/
+
+#if EIGEN_ALIGN
+ #ifdef EIGEN_EXCEPTIONS
+ #define EIGEN_MAKE_ALIGNED_OPERATOR_NEW_NOTHROW(NeedsToAlign) \
+ void* operator new(size_t size, const std::nothrow_t&) throw() { \
+ try { return Eigen::internal::conditional_aligned_malloc<NeedsToAlign>(size); } \
+ catch (...) { return 0; } \
+ return 0; \
+ }
+ #else
+ #define EIGEN_MAKE_ALIGNED_OPERATOR_NEW_NOTHROW(NeedsToAlign) \
+ void* operator new(size_t size, const std::nothrow_t&) throw() { \
+ return Eigen::internal::conditional_aligned_malloc<NeedsToAlign>(size); \
+ }
+ #endif
+
+ #define EIGEN_MAKE_ALIGNED_OPERATOR_NEW_IF(NeedsToAlign) \
+ void *operator new(size_t size) { \
+ return Eigen::internal::conditional_aligned_malloc<NeedsToAlign>(size); \
+ } \
+ void *operator new[](size_t size) { \
+ return Eigen::internal::conditional_aligned_malloc<NeedsToAlign>(size); \
+ } \
+ void operator delete(void * ptr) throw() { Eigen::internal::conditional_aligned_free<NeedsToAlign>(ptr); } \
+ void operator delete[](void * ptr) throw() { Eigen::internal::conditional_aligned_free<NeedsToAlign>(ptr); } \
+ /* in-place new and delete. since (at least afaik) there is no actual */ \
+ /* memory allocated we can safely let the default implementation handle */ \
+ /* this particular case. */ \
+ static void *operator new(size_t size, void *ptr) { return ::operator new(size,ptr); } \
+ void operator delete(void * memory, void *ptr) throw() { return ::operator delete(memory,ptr); } \
+ /* nothrow-new (returns zero instead of std::bad_alloc) */ \
+ EIGEN_MAKE_ALIGNED_OPERATOR_NEW_NOTHROW(NeedsToAlign) \
+ void operator delete(void *ptr, const std::nothrow_t&) throw() { \
+ Eigen::internal::conditional_aligned_free<NeedsToAlign>(ptr); \
+ } \
+ typedef void eigen_aligned_operator_new_marker_type;
+#else
+ #define EIGEN_MAKE_ALIGNED_OPERATOR_NEW_IF(NeedsToAlign)
+#endif
+
+#define EIGEN_MAKE_ALIGNED_OPERATOR_NEW EIGEN_MAKE_ALIGNED_OPERATOR_NEW_IF(true)
+#define EIGEN_MAKE_ALIGNED_OPERATOR_NEW_IF_VECTORIZABLE_FIXED_SIZE(Scalar,Size) \
+ EIGEN_MAKE_ALIGNED_OPERATOR_NEW_IF(bool(((Size)!=Eigen::Dynamic) && ((sizeof(Scalar)*(Size))%16==0)))
+
+/****************************************************************************/
+
+/** \class aligned_allocator
+* \ingroup Core_Module
+*
+* \brief STL compatible allocator to use with with 16 byte aligned types
+*
+* Example:
+* \code
+* // Matrix4f requires 16 bytes alignment:
+* std::map< int, Matrix4f, std::less<int>,
+* aligned_allocator<std::pair<const int, Matrix4f> > > my_map_mat4;
+* // Vector3f does not require 16 bytes alignment, no need to use Eigen's allocator:
+* std::map< int, Vector3f > my_map_vec3;
+* \endcode
+*
+* \sa \ref TopicStlContainers.
+*/
+template<class T>
+class aligned_allocator
+{
+public:
+ typedef size_t size_type;
+ typedef std::ptrdiff_t difference_type;
+ typedef T* pointer;
+ typedef const T* const_pointer;
+ typedef T& reference;
+ typedef const T& const_reference;
+ typedef T value_type;
+
+ template<class U>
+ struct rebind
+ {
+ typedef aligned_allocator<U> other;
+ };
+
+ pointer address( reference value ) const
+ {
+ return &value;
+ }
+
+ const_pointer address( const_reference value ) const
+ {
+ return &value;
+ }
+
+ aligned_allocator()
+ {
+ }
+
+ aligned_allocator( const aligned_allocator& )
+ {
+ }
+
+ template<class U>
+ aligned_allocator( const aligned_allocator<U>& )
+ {
+ }
+
+ ~aligned_allocator()
+ {
+ }
+
+ size_type max_size() const
+ {
+ return (std::numeric_limits<size_type>::max)();
+ }
+
+ pointer allocate( size_type num, const void* hint = 0 )
+ {
+ EIGEN_UNUSED_VARIABLE(hint);
+ internal::check_size_for_overflow<T>(num);
+ return static_cast<pointer>( internal::aligned_malloc( num * sizeof(T) ) );
+ }
+
+ void construct( pointer p, const T& value )
+ {
+ ::new( p ) T( value );
+ }
+
+ // Support for c++11
+#if (__cplusplus >= 201103L)
+ template<typename... Args>
+ void construct(pointer p, Args&&... args)
+ {
+ ::new(p) T(std::forward<Args>(args)...);
+ }
+#endif
+
+ void destroy( pointer p )
+ {
+ p->~T();
+ }
+
+ void deallocate( pointer p, size_type /*num*/ )
+ {
+ internal::aligned_free( p );
+ }
+
+ bool operator!=(const aligned_allocator<T>& ) const
+ { return false; }
+
+ bool operator==(const aligned_allocator<T>& ) const
+ { return true; }
+};
+
+//---------- Cache sizes ----------
+
+#if !defined(EIGEN_NO_CPUID)
+# if defined(__GNUC__) && ( defined(__i386__) || defined(__x86_64__) )
+# if defined(__PIC__) && defined(__i386__)
+ // Case for x86 with PIC
+# define EIGEN_CPUID(abcd,func,id) \
+ __asm__ __volatile__ ("xchgl %%ebx, %%esi;cpuid; xchgl %%ebx,%%esi": "=a" (abcd[0]), "=S" (abcd[1]), "=c" (abcd[2]), "=d" (abcd[3]) : "a" (func), "c" (id));
+# else
+ // Case for x86_64 or x86 w/o PIC
+# define EIGEN_CPUID(abcd,func,id) \
+ __asm__ __volatile__ ("cpuid": "=a" (abcd[0]), "=b" (abcd[1]), "=c" (abcd[2]), "=d" (abcd[3]) : "a" (func), "c" (id) );
+# endif
+# elif defined(_MSC_VER)
+# if (_MSC_VER > 1500)
+# define EIGEN_CPUID(abcd,func,id) __cpuidex((int*)abcd,func,id)
+# endif
+# endif
+#endif
+
+namespace internal {
+
+#ifdef EIGEN_CPUID
+
+inline bool cpuid_is_vendor(int abcd[4], const char* vendor)
+{
+ return abcd[1]==(reinterpret_cast<const int*>(vendor))[0] && abcd[3]==(reinterpret_cast<const int*>(vendor))[1] && abcd[2]==(reinterpret_cast<const int*>(vendor))[2];
+}
+
+inline void queryCacheSizes_intel_direct(int& l1, int& l2, int& l3)
+{
+ int abcd[4];
+ l1 = l2 = l3 = 0;
+ int cache_id = 0;
+ int cache_type = 0;
+ do {
+ abcd[0] = abcd[1] = abcd[2] = abcd[3] = 0;
+ EIGEN_CPUID(abcd,0x4,cache_id);
+ cache_type = (abcd[0] & 0x0F) >> 0;
+ if(cache_type==1||cache_type==3) // data or unified cache
+ {
+ int cache_level = (abcd[0] & 0xE0) >> 5; // A[7:5]
+ int ways = (abcd[1] & 0xFFC00000) >> 22; // B[31:22]
+ int partitions = (abcd[1] & 0x003FF000) >> 12; // B[21:12]
+ int line_size = (abcd[1] & 0x00000FFF) >> 0; // B[11:0]
+ int sets = (abcd[2]); // C[31:0]
+
+ int cache_size = (ways+1) * (partitions+1) * (line_size+1) * (sets+1);
+
+ switch(cache_level)
+ {
+ case 1: l1 = cache_size; break;
+ case 2: l2 = cache_size; break;
+ case 3: l3 = cache_size; break;
+ default: break;
+ }
+ }
+ cache_id++;
+ } while(cache_type>0 && cache_id<16);
+}
+
+inline void queryCacheSizes_intel_codes(int& l1, int& l2, int& l3)
+{
+ int abcd[4];
+ abcd[0] = abcd[1] = abcd[2] = abcd[3] = 0;
+ l1 = l2 = l3 = 0;
+ EIGEN_CPUID(abcd,0x00000002,0);
+ unsigned char * bytes = reinterpret_cast<unsigned char *>(abcd)+2;
+ bool check_for_p2_core2 = false;
+ for(int i=0; i<14; ++i)
+ {
+ switch(bytes[i])
+ {
+ case 0x0A: l1 = 8; break; // 0Ah data L1 cache, 8 KB, 2 ways, 32 byte lines
+ case 0x0C: l1 = 16; break; // 0Ch data L1 cache, 16 KB, 4 ways, 32 byte lines
+ case 0x0E: l1 = 24; break; // 0Eh data L1 cache, 24 KB, 6 ways, 64 byte lines
+ case 0x10: l1 = 16; break; // 10h data L1 cache, 16 KB, 4 ways, 32 byte lines (IA-64)
+ case 0x15: l1 = 16; break; // 15h code L1 cache, 16 KB, 4 ways, 32 byte lines (IA-64)
+ case 0x2C: l1 = 32; break; // 2Ch data L1 cache, 32 KB, 8 ways, 64 byte lines
+ case 0x30: l1 = 32; break; // 30h code L1 cache, 32 KB, 8 ways, 64 byte lines
+ case 0x60: l1 = 16; break; // 60h data L1 cache, 16 KB, 8 ways, 64 byte lines, sectored
+ case 0x66: l1 = 8; break; // 66h data L1 cache, 8 KB, 4 ways, 64 byte lines, sectored
+ case 0x67: l1 = 16; break; // 67h data L1 cache, 16 KB, 4 ways, 64 byte lines, sectored
+ case 0x68: l1 = 32; break; // 68h data L1 cache, 32 KB, 4 ways, 64 byte lines, sectored
+ case 0x1A: l2 = 96; break; // code and data L2 cache, 96 KB, 6 ways, 64 byte lines (IA-64)
+ case 0x22: l3 = 512; break; // code and data L3 cache, 512 KB, 4 ways (!), 64 byte lines, dual-sectored
+ case 0x23: l3 = 1024; break; // code and data L3 cache, 1024 KB, 8 ways, 64 byte lines, dual-sectored
+ case 0x25: l3 = 2048; break; // code and data L3 cache, 2048 KB, 8 ways, 64 byte lines, dual-sectored
+ case 0x29: l3 = 4096; break; // code and data L3 cache, 4096 KB, 8 ways, 64 byte lines, dual-sectored
+ case 0x39: l2 = 128; break; // code and data L2 cache, 128 KB, 4 ways, 64 byte lines, sectored
+ case 0x3A: l2 = 192; break; // code and data L2 cache, 192 KB, 6 ways, 64 byte lines, sectored
+ case 0x3B: l2 = 128; break; // code and data L2 cache, 128 KB, 2 ways, 64 byte lines, sectored
+ case 0x3C: l2 = 256; break; // code and data L2 cache, 256 KB, 4 ways, 64 byte lines, sectored
+ case 0x3D: l2 = 384; break; // code and data L2 cache, 384 KB, 6 ways, 64 byte lines, sectored
+ case 0x3E: l2 = 512; break; // code and data L2 cache, 512 KB, 4 ways, 64 byte lines, sectored
+ case 0x40: l2 = 0; break; // no integrated L2 cache (P6 core) or L3 cache (P4 core)
+ case 0x41: l2 = 128; break; // code and data L2 cache, 128 KB, 4 ways, 32 byte lines
+ case 0x42: l2 = 256; break; // code and data L2 cache, 256 KB, 4 ways, 32 byte lines
+ case 0x43: l2 = 512; break; // code and data L2 cache, 512 KB, 4 ways, 32 byte lines
+ case 0x44: l2 = 1024; break; // code and data L2 cache, 1024 KB, 4 ways, 32 byte lines
+ case 0x45: l2 = 2048; break; // code and data L2 cache, 2048 KB, 4 ways, 32 byte lines
+ case 0x46: l3 = 4096; break; // code and data L3 cache, 4096 KB, 4 ways, 64 byte lines
+ case 0x47: l3 = 8192; break; // code and data L3 cache, 8192 KB, 8 ways, 64 byte lines
+ case 0x48: l2 = 3072; break; // code and data L2 cache, 3072 KB, 12 ways, 64 byte lines
+ case 0x49: if(l2!=0) l3 = 4096; else {check_for_p2_core2=true; l3 = l2 = 4096;} break;// code and data L3 cache, 4096 KB, 16 ways, 64 byte lines (P4) or L2 for core2
+ case 0x4A: l3 = 6144; break; // code and data L3 cache, 6144 KB, 12 ways, 64 byte lines
+ case 0x4B: l3 = 8192; break; // code and data L3 cache, 8192 KB, 16 ways, 64 byte lines
+ case 0x4C: l3 = 12288; break; // code and data L3 cache, 12288 KB, 12 ways, 64 byte lines
+ case 0x4D: l3 = 16384; break; // code and data L3 cache, 16384 KB, 16 ways, 64 byte lines
+ case 0x4E: l2 = 6144; break; // code and data L2 cache, 6144 KB, 24 ways, 64 byte lines
+ case 0x78: l2 = 1024; break; // code and data L2 cache, 1024 KB, 4 ways, 64 byte lines
+ case 0x79: l2 = 128; break; // code and data L2 cache, 128 KB, 8 ways, 64 byte lines, dual-sectored
+ case 0x7A: l2 = 256; break; // code and data L2 cache, 256 KB, 8 ways, 64 byte lines, dual-sectored
+ case 0x7B: l2 = 512; break; // code and data L2 cache, 512 KB, 8 ways, 64 byte lines, dual-sectored
+ case 0x7C: l2 = 1024; break; // code and data L2 cache, 1024 KB, 8 ways, 64 byte lines, dual-sectored
+ case 0x7D: l2 = 2048; break; // code and data L2 cache, 2048 KB, 8 ways, 64 byte lines
+ case 0x7E: l2 = 256; break; // code and data L2 cache, 256 KB, 8 ways, 128 byte lines, sect. (IA-64)
+ case 0x7F: l2 = 512; break; // code and data L2 cache, 512 KB, 2 ways, 64 byte lines
+ case 0x80: l2 = 512; break; // code and data L2 cache, 512 KB, 8 ways, 64 byte lines
+ case 0x81: l2 = 128; break; // code and data L2 cache, 128 KB, 8 ways, 32 byte lines
+ case 0x82: l2 = 256; break; // code and data L2 cache, 256 KB, 8 ways, 32 byte lines
+ case 0x83: l2 = 512; break; // code and data L2 cache, 512 KB, 8 ways, 32 byte lines
+ case 0x84: l2 = 1024; break; // code and data L2 cache, 1024 KB, 8 ways, 32 byte lines
+ case 0x85: l2 = 2048; break; // code and data L2 cache, 2048 KB, 8 ways, 32 byte lines
+ case 0x86: l2 = 512; break; // code and data L2 cache, 512 KB, 4 ways, 64 byte lines
+ case 0x87: l2 = 1024; break; // code and data L2 cache, 1024 KB, 8 ways, 64 byte lines
+ case 0x88: l3 = 2048; break; // code and data L3 cache, 2048 KB, 4 ways, 64 byte lines (IA-64)
+ case 0x89: l3 = 4096; break; // code and data L3 cache, 4096 KB, 4 ways, 64 byte lines (IA-64)
+ case 0x8A: l3 = 8192; break; // code and data L3 cache, 8192 KB, 4 ways, 64 byte lines (IA-64)
+ case 0x8D: l3 = 3072; break; // code and data L3 cache, 3072 KB, 12 ways, 128 byte lines (IA-64)
+
+ default: break;
+ }
+ }
+ if(check_for_p2_core2 && l2 == l3)
+ l3 = 0;
+ l1 *= 1024;
+ l2 *= 1024;
+ l3 *= 1024;
+}
+
+inline void queryCacheSizes_intel(int& l1, int& l2, int& l3, int max_std_funcs)
+{
+ if(max_std_funcs>=4)
+ queryCacheSizes_intel_direct(l1,l2,l3);
+ else
+ queryCacheSizes_intel_codes(l1,l2,l3);
+}
+
+inline void queryCacheSizes_amd(int& l1, int& l2, int& l3)
+{
+ int abcd[4];
+ abcd[0] = abcd[1] = abcd[2] = abcd[3] = 0;
+ EIGEN_CPUID(abcd,0x80000005,0);
+ l1 = (abcd[2] >> 24) * 1024; // C[31:24] = L1 size in KB
+ abcd[0] = abcd[1] = abcd[2] = abcd[3] = 0;
+ EIGEN_CPUID(abcd,0x80000006,0);
+ l2 = (abcd[2] >> 16) * 1024; // C[31;16] = l2 cache size in KB
+ l3 = ((abcd[3] & 0xFFFC000) >> 18) * 512 * 1024; // D[31;18] = l3 cache size in 512KB
+}
+#endif
+
+/** \internal
+ * Queries and returns the cache sizes in Bytes of the L1, L2, and L3 data caches respectively */
+inline void queryCacheSizes(int& l1, int& l2, int& l3)
+{
+ #ifdef EIGEN_CPUID
+ int abcd[4];
+
+ // identify the CPU vendor
+ EIGEN_CPUID(abcd,0x0,0);
+ int max_std_funcs = abcd[1];
+ if(cpuid_is_vendor(abcd,"GenuineIntel"))
+ queryCacheSizes_intel(l1,l2,l3,max_std_funcs);
+ else if(cpuid_is_vendor(abcd,"AuthenticAMD") || cpuid_is_vendor(abcd,"AMDisbetter!"))
+ queryCacheSizes_amd(l1,l2,l3);
+ else
+ // by default let's use Intel's API
+ queryCacheSizes_intel(l1,l2,l3,max_std_funcs);
+
+ // here is the list of other vendors:
+// ||cpuid_is_vendor(abcd,"VIA VIA VIA ")
+// ||cpuid_is_vendor(abcd,"CyrixInstead")
+// ||cpuid_is_vendor(abcd,"CentaurHauls")
+// ||cpuid_is_vendor(abcd,"GenuineTMx86")
+// ||cpuid_is_vendor(abcd,"TransmetaCPU")
+// ||cpuid_is_vendor(abcd,"RiseRiseRise")
+// ||cpuid_is_vendor(abcd,"Geode by NSC")
+// ||cpuid_is_vendor(abcd,"SiS SiS SiS ")
+// ||cpuid_is_vendor(abcd,"UMC UMC UMC ")
+// ||cpuid_is_vendor(abcd,"NexGenDriven")
+ #else
+ l1 = l2 = l3 = -1;
+ #endif
+}
+
+/** \internal
+ * \returns the size in Bytes of the L1 data cache */
+inline int queryL1CacheSize()
+{
+ int l1(-1), l2, l3;
+ queryCacheSizes(l1,l2,l3);
+ return l1;
+}
+
+/** \internal
+ * \returns the size in Bytes of the L2 or L3 cache if this later is present */
+inline int queryTopLevelCacheSize()
+{
+ int l1, l2(-1), l3(-1);
+ queryCacheSizes(l1,l2,l3);
+ return (std::max)(l2,l3);
+}
+
+} // end namespace internal
+
+} // end namespace Eigen
+
+#endif // EIGEN_MEMORY_H
diff --git a/Eigen/src/Core/util/Meta.h b/Eigen/src/Core/util/Meta.h
new file mode 100644
index 000000000..a5f31164d
--- /dev/null
+++ b/Eigen/src/Core/util/Meta.h
@@ -0,0 +1,231 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra.
+//
+// Copyright (C) 2008-2009 Gael Guennebaud <gael.guennebaud@inria.fr>
+// Copyright (C) 2006-2008 Benoit Jacob <jacob.benoit.1@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 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<bool Condition, typename Then, typename Else>
+struct conditional { typedef Then type; };
+
+template<typename Then, typename Else>
+struct conditional <false, Then, Else> { typedef Else type; };
+
+template<typename T, typename U> struct is_same { enum { value = 0 }; };
+template<typename T> struct is_same<T,T> { enum { value = 1 }; };
+
+template<typename T> struct remove_reference { typedef T type; };
+template<typename T> struct remove_reference<T&> { typedef T type; };
+
+template<typename T> struct remove_pointer { typedef T type; };
+template<typename T> struct remove_pointer<T*> { typedef T type; };
+template<typename T> struct remove_pointer<T*const> { typedef T type; };
+
+template <class T> struct remove_const { typedef T type; };
+template <class T> struct remove_const<const T> { typedef T type; };
+template <class T> struct remove_const<const T[]> { typedef T type[]; };
+template <class T, unsigned int Size> struct remove_const<const T[Size]> { typedef T type[Size]; };
+
+template<typename T> struct remove_all { typedef T type; };
+template<typename T> struct remove_all<const T> { typedef typename remove_all<T>::type type; };
+template<typename T> struct remove_all<T const&> { typedef typename remove_all<T>::type type; };
+template<typename T> struct remove_all<T&> { typedef typename remove_all<T>::type type; };
+template<typename T> struct remove_all<T const*> { typedef typename remove_all<T>::type type; };
+template<typename T> struct remove_all<T*> { typedef typename remove_all<T>::type type; };
+
+template<typename T> struct is_arithmetic { enum { value = false }; };
+template<> struct is_arithmetic<float> { enum { value = true }; };
+template<> struct is_arithmetic<double> { enum { value = true }; };
+template<> struct is_arithmetic<long double> { enum { value = true }; };
+template<> struct is_arithmetic<bool> { enum { value = true }; };
+template<> struct is_arithmetic<char> { enum { value = true }; };
+template<> struct is_arithmetic<signed char> { enum { value = true }; };
+template<> struct is_arithmetic<unsigned char> { enum { value = true }; };
+template<> struct is_arithmetic<signed short> { enum { value = true }; };
+template<> struct is_arithmetic<unsigned short>{ enum { value = true }; };
+template<> struct is_arithmetic<signed int> { enum { value = true }; };
+template<> struct is_arithmetic<unsigned int> { enum { value = true }; };
+template<> struct is_arithmetic<signed long> { enum { value = true }; };
+template<> struct is_arithmetic<unsigned long> { enum { value = true }; };
+
+template <typename T> struct add_const { typedef const T type; };
+template <typename T> struct add_const<T&> { typedef T& type; };
+
+template <typename T> struct is_const { enum { value = 0 }; };
+template <typename T> struct is_const<T const> { enum { value = 1 }; };
+
+template<typename T> struct add_const_on_value_type { typedef const T type; };
+template<typename T> struct add_const_on_value_type<T&> { typedef T const& type; };
+template<typename T> struct add_const_on_value_type<T*> { typedef T const* type; };
+template<typename T> struct add_const_on_value_type<T* const> { typedef T const* const type; };
+template<typename T> struct add_const_on_value_type<T const* const> { typedef T const* const type; };
+
+/** \internal Allows to enable/disable an overload
+ * according to a compile time condition.
+ */
+template<bool Condition, typename T> struct enable_if;
+
+template<typename T> struct enable_if<true,T>
+{ 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<typename T> 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<typename Func, typename ArgType, int SizeOf=sizeof(has_none)>
+struct unary_result_of_select {typedef ArgType type;};
+
+template<typename Func, typename ArgType>
+struct unary_result_of_select<Func, ArgType, sizeof(has_std_result_type)> {typedef typename Func::result_type type;};
+
+template<typename Func, typename ArgType>
+struct unary_result_of_select<Func, ArgType, sizeof(has_tr1_result)> {typedef typename Func::template result<Func(ArgType)>::type type;};
+
+template<typename Func, typename ArgType>
+struct result_of<Func(ArgType)> {
+ template<typename T>
+ static has_std_result_type testFunctor(T const *, typename T::result_type const * = 0);
+ template<typename T>
+ static has_tr1_result testFunctor(T const *, typename T::template result<T(ArgType)>::type const * = 0);
+ static has_none testFunctor(...);
+
+ // note that the following indirection is needed for gcc-3.3
+ enum {FunctorType = sizeof(testFunctor(static_cast<Func*>(0)))};
+ typedef typename unary_result_of_select<Func, ArgType, FunctorType>::type type;
+};
+
+template<typename Func, typename ArgType0, typename ArgType1, int SizeOf=sizeof(has_none)>
+struct binary_result_of_select {typedef ArgType0 type;};
+
+template<typename Func, typename ArgType0, typename ArgType1>
+struct binary_result_of_select<Func, ArgType0, ArgType1, sizeof(has_std_result_type)>
+{typedef typename Func::result_type type;};
+
+template<typename Func, typename ArgType0, typename ArgType1>
+struct binary_result_of_select<Func, ArgType0, ArgType1, sizeof(has_tr1_result)>
+{typedef typename Func::template result<Func(ArgType0,ArgType1)>::type type;};
+
+template<typename Func, typename ArgType0, typename ArgType1>
+struct result_of<Func(ArgType0,ArgType1)> {
+ template<typename T>
+ static has_std_result_type testFunctor(T const *, typename T::result_type const * = 0);
+ template<typename T>
+ static has_tr1_result testFunctor(T const *, typename T::template result<T(ArgType0,ArgType1)>::type const * = 0);
+ static has_none testFunctor(...);
+
+ // note that the following indirection is needed for gcc-3.3
+ enum {FunctorType = sizeof(testFunctor(static_cast<Func*>(0)))};
+ typedef typename binary_result_of_select<Func, ArgType0, ArgType1, FunctorType>::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<int Y,
+ int InfX = 0,
+ int SupX = ((Y==1) ? 1 : Y/2),
+ bool Done = ((SupX-InfX)<=1 ? true : ((SupX*SupX <= Y) && ((SupX+1)*(SupX+1) > 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<Y,NewInf,NewSup>::ret };
+};
+
+template<int Y, int InfX, int SupX>
+class meta_sqrt<Y, InfX, SupX, true> { 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<typename T, typename U> struct scalar_product_traits;
+
+template<typename T> struct scalar_product_traits<T,T>
+{
+ //enum { Cost = NumTraits<T>::MulCost };
+ typedef T ReturnType;
+};
+
+template<typename T> struct scalar_product_traits<T,std::complex<T> >
+{
+ //enum { Cost = 2*NumTraits<T>::MulCost };
+ typedef std::complex<T> ReturnType;
+};
+
+template<typename T> struct scalar_product_traits<std::complex<T>, T>
+{
+ //enum { Cost = 2*NumTraits<T>::MulCost };
+ typedef std::complex<T> ReturnType;
+};
+
+// FIXME quick workaround around current limitation of result_of
+// template<typename Scalar, typename ArgType0, typename ArgType1>
+// struct result_of<scalar_product_op<Scalar>(ArgType0,ArgType1)> {
+// typedef typename scalar_product_traits<typename remove_all<ArgType0>::type, typename remove_all<ArgType1>::type>::ReturnType type;
+// };
+
+template<typename T> struct is_diagonal
+{ enum { ret = false }; };
+
+template<typename T> struct is_diagonal<DiagonalBase<T> >
+{ enum { ret = true }; };
+
+template<typename T> struct is_diagonal<DiagonalWrapper<T> >
+{ enum { ret = true }; };
+
+template<typename T, int S> struct is_diagonal<DiagonalMatrix<T,S> >
+{ enum { ret = true }; };
+
+} // end namespace internal
+
+} // end namespace Eigen
+
+#endif // EIGEN_META_H
diff --git a/Eigen/src/Core/util/NonMPL2.h b/Eigen/src/Core/util/NonMPL2.h
new file mode 100644
index 000000000..629537a5e
--- /dev/null
+++ b/Eigen/src/Core/util/NonMPL2.h
@@ -0,0 +1,6 @@
+// Force error if including non MPL2 license code regardless
+// EIGEN_MPL2_ONLY flag.
+
+//#ifdef EIGEN_MPL2_ONLY
+#error Including non-MPL2 code in EIGEN_MPL2_ONLY mode
+//#endif
diff --git a/Eigen/src/Core/util/ReenableStupidWarnings.h b/Eigen/src/Core/util/ReenableStupidWarnings.h
new file mode 100644
index 000000000..5ddfbd4aa
--- /dev/null
+++ b/Eigen/src/Core/util/ReenableStupidWarnings.h
@@ -0,0 +1,14 @@
+#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/Eigen/src/Core/util/StaticAssert.h b/Eigen/src/Core/util/StaticAssert.h
new file mode 100644
index 000000000..b46a75b37
--- /dev/null
+++ b/Eigen/src/Core/util/StaticAssert.h
@@ -0,0 +1,205 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra.
+//
+// Copyright (C) 2008 Gael Guennebaud <gael.guennebaud@inria.fr>
+// Copyright (C) 2008 Benoit Jacob <jacob.benoit.1@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 EIGEN_STATIC_ASSERT_H
+#define EIGEN_STATIC_ASSERT_H
+
+/* Some notes on Eigen's static assertion mechanism:
+ *
+ * - in EIGEN_STATIC_ASSERT(CONDITION,MSG) the parameter CONDITION must be a compile time boolean
+ * expression, and MSG an enum listed in struct internal::static_assertion<true>
+ *
+ * - define EIGEN_NO_STATIC_ASSERT to disable them (and save compilation time)
+ * in that case, the static assertion is converted to the following runtime assert:
+ * eigen_assert(CONDITION && "MSG")
+ *
+ * - currently EIGEN_STATIC_ASSERT can only be used in function scope
+ *
+ */
+
+#ifndef EIGEN_NO_STATIC_ASSERT
+
+ #if defined(__GXX_EXPERIMENTAL_CXX0X__) || (defined(_MSC_VER) && (_MSC_VER >= 1600))
+
+ // if native static_assert is enabled, let's use it
+ #define EIGEN_STATIC_ASSERT(X,MSG) static_assert(X,#MSG);
+
+ #else // not CXX0X
+
+ namespace Eigen {
+
+ namespace internal {
+
+ template<bool condition>
+ struct static_assertion {};
+
+ template<>
+ struct static_assertion<true>
+ {
+ enum {
+ YOU_TRIED_CALLING_A_VECTOR_METHOD_ON_A_MATRIX,
+ YOU_MIXED_VECTORS_OF_DIFFERENT_SIZES,
+ YOU_MIXED_MATRICES_OF_DIFFERENT_SIZES,
+ THIS_METHOD_IS_ONLY_FOR_VECTORS_OF_A_SPECIFIC_SIZE,
+ THIS_METHOD_IS_ONLY_FOR_MATRICES_OF_A_SPECIFIC_SIZE,
+ THIS_METHOD_IS_ONLY_FOR_OBJECTS_OF_A_SPECIFIC_SIZE,
+ YOU_MADE_A_PROGRAMMING_MISTAKE,
+ EIGEN_INTERNAL_ERROR_PLEASE_FILE_A_BUG_REPORT,
+ EIGEN_INTERNAL_COMPILATION_ERROR_OR_YOU_MADE_A_PROGRAMMING_MISTAKE,
+ YOU_CALLED_A_FIXED_SIZE_METHOD_ON_A_DYNAMIC_SIZE_MATRIX_OR_VECTOR,
+ YOU_CALLED_A_DYNAMIC_SIZE_METHOD_ON_A_FIXED_SIZE_MATRIX_OR_VECTOR,
+ UNALIGNED_LOAD_AND_STORE_OPERATIONS_UNIMPLEMENTED_ON_ALTIVEC,
+ THIS_FUNCTION_IS_NOT_FOR_INTEGER_NUMERIC_TYPES,
+ FLOATING_POINT_ARGUMENT_PASSED__INTEGER_WAS_EXPECTED,
+ NUMERIC_TYPE_MUST_BE_REAL,
+ COEFFICIENT_WRITE_ACCESS_TO_SELFADJOINT_NOT_SUPPORTED,
+ WRITING_TO_TRIANGULAR_PART_WITH_UNIT_DIAGONAL_IS_NOT_SUPPORTED,
+ THIS_METHOD_IS_ONLY_FOR_FIXED_SIZE,
+ INVALID_MATRIX_PRODUCT,
+ INVALID_VECTOR_VECTOR_PRODUCT__IF_YOU_WANTED_A_DOT_OR_COEFF_WISE_PRODUCT_YOU_MUST_USE_THE_EXPLICIT_FUNCTIONS,
+ INVALID_MATRIX_PRODUCT__IF_YOU_WANTED_A_COEFF_WISE_PRODUCT_YOU_MUST_USE_THE_EXPLICIT_FUNCTION,
+ YOU_MIXED_DIFFERENT_NUMERIC_TYPES__YOU_NEED_TO_USE_THE_CAST_METHOD_OF_MATRIXBASE_TO_CAST_NUMERIC_TYPES_EXPLICITLY,
+ THIS_METHOD_IS_ONLY_FOR_COLUMN_MAJOR_MATRICES,
+ THIS_METHOD_IS_ONLY_FOR_ROW_MAJOR_MATRICES,
+ INVALID_MATRIX_TEMPLATE_PARAMETERS,
+ INVALID_MATRIXBASE_TEMPLATE_PARAMETERS,
+ BOTH_MATRICES_MUST_HAVE_THE_SAME_STORAGE_ORDER,
+ THIS_METHOD_IS_ONLY_FOR_DIAGONAL_MATRIX,
+ THE_MATRIX_OR_EXPRESSION_THAT_YOU_PASSED_DOES_NOT_HAVE_THE_EXPECTED_TYPE,
+ THIS_METHOD_IS_ONLY_FOR_EXPRESSIONS_WITH_DIRECT_MEMORY_ACCESS_SUCH_AS_MAP_OR_PLAIN_MATRICES,
+ YOU_ALREADY_SPECIFIED_THIS_STRIDE,
+ INVALID_STORAGE_ORDER_FOR_THIS_VECTOR_EXPRESSION,
+ THE_BRACKET_OPERATOR_IS_ONLY_FOR_VECTORS__USE_THE_PARENTHESIS_OPERATOR_INSTEAD,
+ PACKET_ACCESS_REQUIRES_TO_HAVE_INNER_STRIDE_FIXED_TO_1,
+ THIS_METHOD_IS_ONLY_FOR_SPECIFIC_TRANSFORMATIONS,
+ YOU_CANNOT_MIX_ARRAYS_AND_MATRICES,
+ YOU_PERFORMED_AN_INVALID_TRANSFORMATION_CONVERSION,
+ THIS_EXPRESSION_IS_NOT_A_LVALUE__IT_IS_READ_ONLY,
+ YOU_ARE_TRYING_TO_USE_AN_INDEX_BASED_ACCESSOR_ON_AN_EXPRESSION_THAT_DOES_NOT_SUPPORT_THAT,
+ THIS_METHOD_IS_ONLY_FOR_1x1_EXPRESSIONS,
+ THIS_METHOD_IS_ONLY_FOR_EXPRESSIONS_OF_BOOL,
+ THIS_METHOD_IS_ONLY_FOR_ARRAYS_NOT_MATRICES,
+ YOU_PASSED_A_ROW_VECTOR_BUT_A_COLUMN_VECTOR_WAS_EXPECTED,
+ YOU_PASSED_A_COLUMN_VECTOR_BUT_A_ROW_VECTOR_WAS_EXPECTED,
+ THE_INDEX_TYPE_MUST_BE_A_SIGNED_TYPE,
+ THE_STORAGE_ORDER_OF_BOTH_SIDES_MUST_MATCH
+ };
+ };
+
+ } // end namespace internal
+
+ } // end namespace Eigen
+
+ // Specialized implementation for MSVC to avoid "conditional
+ // expression is constant" warnings. This implementation doesn't
+ // appear to work under GCC, hence the multiple implementations.
+ #ifdef _MSC_VER
+
+ #define EIGEN_STATIC_ASSERT(CONDITION,MSG) \
+ {Eigen::internal::static_assertion<bool(CONDITION)>::MSG;}
+
+ #else
+
+ #define EIGEN_STATIC_ASSERT(CONDITION,MSG) \
+ if (Eigen::internal::static_assertion<bool(CONDITION)>::MSG) {}
+
+ #endif
+
+ #endif // not CXX0X
+
+#else // EIGEN_NO_STATIC_ASSERT
+
+ #define EIGEN_STATIC_ASSERT(CONDITION,MSG) eigen_assert((CONDITION) && #MSG);
+
+#endif // EIGEN_NO_STATIC_ASSERT
+
+
+// static assertion failing if the type \a TYPE is not a vector type
+#define EIGEN_STATIC_ASSERT_VECTOR_ONLY(TYPE) \
+ EIGEN_STATIC_ASSERT(TYPE::IsVectorAtCompileTime, \
+ YOU_TRIED_CALLING_A_VECTOR_METHOD_ON_A_MATRIX)
+
+// static assertion failing if the type \a TYPE is not fixed-size
+#define EIGEN_STATIC_ASSERT_FIXED_SIZE(TYPE) \
+ EIGEN_STATIC_ASSERT(TYPE::SizeAtCompileTime!=Eigen::Dynamic, \
+ YOU_CALLED_A_FIXED_SIZE_METHOD_ON_A_DYNAMIC_SIZE_MATRIX_OR_VECTOR)
+
+// static assertion failing if the type \a TYPE is not dynamic-size
+#define EIGEN_STATIC_ASSERT_DYNAMIC_SIZE(TYPE) \
+ EIGEN_STATIC_ASSERT(TYPE::SizeAtCompileTime==Eigen::Dynamic, \
+ YOU_CALLED_A_DYNAMIC_SIZE_METHOD_ON_A_FIXED_SIZE_MATRIX_OR_VECTOR)
+
+// static assertion failing if the type \a TYPE is not a vector type of the given size
+#define EIGEN_STATIC_ASSERT_VECTOR_SPECIFIC_SIZE(TYPE, SIZE) \
+ EIGEN_STATIC_ASSERT(TYPE::IsVectorAtCompileTime && TYPE::SizeAtCompileTime==SIZE, \
+ THIS_METHOD_IS_ONLY_FOR_VECTORS_OF_A_SPECIFIC_SIZE)
+
+// static assertion failing if the type \a TYPE is not a vector type of the given size
+#define EIGEN_STATIC_ASSERT_MATRIX_SPECIFIC_SIZE(TYPE, ROWS, COLS) \
+ EIGEN_STATIC_ASSERT(TYPE::RowsAtCompileTime==ROWS && TYPE::ColsAtCompileTime==COLS, \
+ THIS_METHOD_IS_ONLY_FOR_MATRICES_OF_A_SPECIFIC_SIZE)
+
+// static assertion failing if the two vector expression types are not compatible (same fixed-size or dynamic size)
+#define EIGEN_STATIC_ASSERT_SAME_VECTOR_SIZE(TYPE0,TYPE1) \
+ EIGEN_STATIC_ASSERT( \
+ (int(TYPE0::SizeAtCompileTime)==Eigen::Dynamic \
+ || int(TYPE1::SizeAtCompileTime)==Eigen::Dynamic \
+ || int(TYPE0::SizeAtCompileTime)==int(TYPE1::SizeAtCompileTime)),\
+ YOU_MIXED_VECTORS_OF_DIFFERENT_SIZES)
+
+#define EIGEN_PREDICATE_SAME_MATRIX_SIZE(TYPE0,TYPE1) \
+ ( \
+ (int(TYPE0::SizeAtCompileTime)==0 && int(TYPE1::SizeAtCompileTime)==0) \
+ || (\
+ (int(TYPE0::RowsAtCompileTime)==Eigen::Dynamic \
+ || int(TYPE1::RowsAtCompileTime)==Eigen::Dynamic \
+ || int(TYPE0::RowsAtCompileTime)==int(TYPE1::RowsAtCompileTime)) \
+ && (int(TYPE0::ColsAtCompileTime)==Eigen::Dynamic \
+ || int(TYPE1::ColsAtCompileTime)==Eigen::Dynamic \
+ || int(TYPE0::ColsAtCompileTime)==int(TYPE1::ColsAtCompileTime))\
+ ) \
+ )
+
+#ifdef EIGEN2_SUPPORT
+ #define EIGEN_STATIC_ASSERT_NON_INTEGER(TYPE) \
+ eigen_assert(!NumTraits<Scalar>::IsInteger);
+#else
+ #define EIGEN_STATIC_ASSERT_NON_INTEGER(TYPE) \
+ EIGEN_STATIC_ASSERT(!NumTraits<TYPE>::IsInteger, THIS_FUNCTION_IS_NOT_FOR_INTEGER_NUMERIC_TYPES)
+#endif
+
+
+// static assertion failing if it is guaranteed at compile-time that the two matrix expression types have different sizes
+#define EIGEN_STATIC_ASSERT_SAME_MATRIX_SIZE(TYPE0,TYPE1) \
+ EIGEN_STATIC_ASSERT( \
+ EIGEN_PREDICATE_SAME_MATRIX_SIZE(TYPE0,TYPE1),\
+ YOU_MIXED_MATRICES_OF_DIFFERENT_SIZES)
+
+#define EIGEN_STATIC_ASSERT_SIZE_1x1(TYPE) \
+ EIGEN_STATIC_ASSERT((TYPE::RowsAtCompileTime == 1 || TYPE::RowsAtCompileTime == Dynamic) && \
+ (TYPE::ColsAtCompileTime == 1 || TYPE::ColsAtCompileTime == Dynamic), \
+ THIS_METHOD_IS_ONLY_FOR_1x1_EXPRESSIONS)
+
+#define EIGEN_STATIC_ASSERT_LVALUE(Derived) \
+ EIGEN_STATIC_ASSERT(internal::is_lvalue<Derived>::value, \
+ THIS_EXPRESSION_IS_NOT_A_LVALUE__IT_IS_READ_ONLY)
+
+#define EIGEN_STATIC_ASSERT_ARRAYXPR(Derived) \
+ EIGEN_STATIC_ASSERT((internal::is_same<typename internal::traits<Derived>::XprKind, ArrayXpr>::value), \
+ THIS_METHOD_IS_ONLY_FOR_ARRAYS_NOT_MATRICES)
+
+#define EIGEN_STATIC_ASSERT_SAME_XPR_KIND(Derived1, Derived2) \
+ EIGEN_STATIC_ASSERT((internal::is_same<typename internal::traits<Derived1>::XprKind, \
+ typename internal::traits<Derived2>::XprKind \
+ >::value), \
+ YOU_CANNOT_MIX_ARRAYS_AND_MATRICES)
+
+
+#endif // EIGEN_STATIC_ASSERT_H
diff --git a/Eigen/src/Core/util/XprHelper.h b/Eigen/src/Core/util/XprHelper.h
new file mode 100644
index 000000000..2a65c7cbf
--- /dev/null
+++ b/Eigen/src/Core/util/XprHelper.h
@@ -0,0 +1,447 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra.
+//
+// Copyright (C) 2008 Gael Guennebaud <gael.guennebaud@inria.fr>
+// Copyright (C) 2006-2008 Benoit Jacob <jacob.benoit.1@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 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<typename I1, typename I2>
+struct promote_index_type
+{
+ typedef typename conditional<(sizeof(I1)<sizeof(I2)), I2, 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<typename T, int Value> 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<typename T> class variable_if_dynamic<T, 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; }
+};
+
+template<typename T> struct functor_traits
+{
+ enum
+ {
+ Cost = 10,
+ PacketAccess = false
+ };
+};
+
+template<typename T> struct packet_traits;
+
+template<typename T> struct unpacket_traits
+{
+ typedef T type;
+ enum {size=1};
+};
+
+template<typename _Scalar, int _Rows, int _Cols,
+ int _Options = AutoAlign |
+ ( (_Rows==1 && _Cols!=1) ? RowMajor
+ : (_Cols==1 && _Rows!=1) ? ColMajor
+ : EIGEN_DEFAULT_MATRIX_STORAGE_ORDER_OPTION ),
+ int _MaxRows = _Rows,
+ int _MaxCols = _Cols
+> 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<typename Scalar, int Rows, int Cols, int Options, int MaxRows, int MaxCols>
+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<Scalar>::Vectorizable && aligned_bit ? PacketAccessBit : 0
+ };
+
+ public:
+ enum { ret = LinearAccessBit | LvalueBit | DirectAccessBit | NestByRefBit | packet_access_bit | row_major_bit | aligned_bit };
+};
+
+template<int _Rows, int _Cols> 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<typename T, typename StorageKind = typename traits<T>::StorageKind> struct plain_matrix_type;
+template<typename T, typename BaseClassType> struct plain_matrix_type_dense;
+template<typename T> struct plain_matrix_type<T,Dense>
+{
+ typedef typename plain_matrix_type_dense<T,typename traits<T>::XprKind>::type type;
+};
+
+template<typename T> struct plain_matrix_type_dense<T,MatrixXpr>
+{
+ typedef Matrix<typename traits<T>::Scalar,
+ traits<T>::RowsAtCompileTime,
+ traits<T>::ColsAtCompileTime,
+ AutoAlign | (traits<T>::Flags&RowMajorBit ? RowMajor : ColMajor),
+ traits<T>::MaxRowsAtCompileTime,
+ traits<T>::MaxColsAtCompileTime
+ > type;
+};
+
+template<typename T> struct plain_matrix_type_dense<T,ArrayXpr>
+{
+ typedef Array<typename traits<T>::Scalar,
+ traits<T>::RowsAtCompileTime,
+ traits<T>::ColsAtCompileTime,
+ AutoAlign | (traits<T>::Flags&RowMajorBit ? RowMajor : ColMajor),
+ traits<T>::MaxRowsAtCompileTime,
+ traits<T>::MaxColsAtCompileTime
+ > type;
+};
+
+/* eval : the return type of eval(). For matrices, this is just a const reference
+ * in order to avoid a useless copy
+ */
+
+template<typename T, typename StorageKind = typename traits<T>::StorageKind> struct eval;
+
+template<typename T> struct eval<T,Dense>
+{
+ typedef typename plain_matrix_type<T>::type type;
+// typedef typename T::PlainObject type;
+// typedef T::Matrix<typename traits<T>::Scalar,
+// traits<T>::RowsAtCompileTime,
+// traits<T>::ColsAtCompileTime,
+// AutoAlign | (traits<T>::Flags&RowMajorBit ? RowMajor : ColMajor),
+// traits<T>::MaxRowsAtCompileTime,
+// traits<T>::MaxColsAtCompileTime
+// > type;
+};
+
+// for matrices, no need to evaluate, just use a const reference to avoid a useless copy
+template<typename _Scalar, int _Rows, int _Cols, int _Options, int _MaxRows, int _MaxCols>
+struct eval<Matrix<_Scalar, _Rows, _Cols, _Options, _MaxRows, _MaxCols>, Dense>
+{
+ typedef const Matrix<_Scalar, _Rows, _Cols, _Options, _MaxRows, _MaxCols>& type;
+};
+
+template<typename _Scalar, int _Rows, int _Cols, int _Options, int _MaxRows, int _MaxCols>
+struct eval<Array<_Scalar, _Rows, _Cols, _Options, _MaxRows, _MaxCols>, 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<typename T> struct plain_matrix_type_column_major
+{
+ enum { Rows = traits<T>::RowsAtCompileTime,
+ Cols = traits<T>::ColsAtCompileTime,
+ MaxRows = traits<T>::MaxRowsAtCompileTime,
+ MaxCols = traits<T>::MaxColsAtCompileTime
+ };
+ typedef Matrix<typename traits<T>::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<typename T> struct plain_matrix_type_row_major
+{
+ enum { Rows = traits<T>::RowsAtCompileTime,
+ Cols = traits<T>::ColsAtCompileTime,
+ MaxRows = traits<T>::MaxRowsAtCompileTime,
+ MaxCols = traits<T>::MaxColsAtCompileTime
+ };
+ typedef Matrix<typename traits<T>::Scalar,
+ Rows,
+ Cols,
+ (MaxCols==1&&MaxRows!=1) ? RowMajor : ColMajor,
+ MaxRows,
+ MaxCols
+ > type;
+};
+
+// we should be able to get rid of this one too
+template<typename T> 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 <typename T>
+struct ref_selector
+{
+ typedef typename conditional<
+ bool(traits<T>::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<typename T1, typename T2>
+struct transfer_constness
+{
+ typedef typename conditional<
+ bool(internal::is_const<T1>::value),
+ typename internal::add_const_on_value_type<T2>::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<S, 3>::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<Matrix3d, 3>::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<typename T, int n=1, typename PlainObject = typename eval<T>::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<typename traits<T>::Scalar>::ReadCost,
+ ScalarReadCostAsInteger = ScalarReadCost == Dynamic ? DynamicAsInteger : ScalarReadCost,
+ CoeffReadCost = traits<T>::CoeffReadCost,
+ CoeffReadCostAsInteger = CoeffReadCost == Dynamic ? DynamicAsInteger : CoeffReadCost,
+ NAsInteger = n == Dynamic ? int(DynamicAsInteger) : n,
+ CostEvalAsInteger = (NAsInteger+1) * ScalarReadCostAsInteger + CoeffReadCostAsInteger,
+ CostNoEvalAsInteger = NAsInteger * CoeffReadCostAsInteger
+ };
+
+ typedef typename conditional<
+ ( (int(traits<T>::Flags) & EvalBeforeNestingBit) ||
+ int(CostEvalAsInteger) < int(CostNoEvalAsInteger)
+ ),
+ PlainObject,
+ typename ref_selector<T>::type
+ >::type type;
+};
+
+template<typename T>
+T* const_cast_ptr(const T* ptr)
+{
+ return const_cast<T*>(ptr);
+}
+
+template<typename Derived, typename XprKind = typename traits<Derived>::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<typename Derived>
+struct dense_xpr_base<Derived, MatrixXpr>
+{
+ typedef MatrixBase<Derived> type;
+};
+
+template<typename Derived>
+struct dense_xpr_base<Derived, ArrayXpr>
+{
+ typedef ArrayBase<Derived> type;
+};
+
+/** \internal Helper base class to add a scalar multiple operator
+ * overloads for complex types */
+template<typename Derived,typename Scalar,typename OtherScalar,
+ bool EnableIt = !is_same<Scalar,OtherScalar>::value >
+struct special_scalar_op_base : public DenseCoeffsBase<Derived>
+{
+ // dummy operator* so that the
+ // "using special_scalar_op_base::operator*" compiles
+ void operator*() const;
+};
+
+template<typename Derived,typename Scalar,typename OtherScalar>
+struct special_scalar_op_base<Derived,Scalar,OtherScalar,true> : public DenseCoeffsBase<Derived>
+{
+ const CwiseUnaryOp<scalar_multiple2_op<Scalar,OtherScalar>, Derived>
+ operator*(const OtherScalar& scalar) const
+ {
+ return CwiseUnaryOp<scalar_multiple2_op<Scalar,OtherScalar>, Derived>
+ (*static_cast<const Derived*>(this), scalar_multiple2_op<Scalar,OtherScalar>(scalar));
+ }
+
+ inline friend const CwiseUnaryOp<scalar_multiple2_op<Scalar,OtherScalar>, Derived>
+ operator*(const OtherScalar& scalar, const Derived& matrix)
+ { return static_cast<const special_scalar_op_base&>(matrix).operator*(scalar); }
+};
+
+template<typename XprType, typename CastType> struct cast_return_type
+{
+ typedef typename XprType::Scalar CurrentScalarType;
+ typedef typename remove_all<CastType>::type _CastType;
+ typedef typename _CastType::Scalar NewScalarType;
+ typedef typename conditional<is_same<CurrentScalarType,NewScalarType>::value,
+ const XprType&,CastType>::type type;
+};
+
+template <typename A, typename B> struct promote_storage_type;
+
+template <typename A> struct promote_storage_type<A,A>
+{
+ 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<typename ExpressionType, typename Scalar = typename ExpressionType::Scalar>
+struct plain_row_type
+{
+ typedef Matrix<Scalar, 1, ExpressionType::ColsAtCompileTime,
+ ExpressionType::PlainObject::Options | RowMajor, 1, ExpressionType::MaxColsAtCompileTime> MatrixRowType;
+ typedef Array<Scalar, 1, ExpressionType::ColsAtCompileTime,
+ ExpressionType::PlainObject::Options | RowMajor, 1, ExpressionType::MaxColsAtCompileTime> ArrayRowType;
+
+ typedef typename conditional<
+ is_same< typename traits<ExpressionType>::XprKind, MatrixXpr >::value,
+ MatrixRowType,
+ ArrayRowType
+ >::type type;
+};
+
+template<typename ExpressionType, typename Scalar = typename ExpressionType::Scalar>
+struct plain_col_type
+{
+ typedef Matrix<Scalar, ExpressionType::RowsAtCompileTime, 1,
+ ExpressionType::PlainObject::Options & ~RowMajor, ExpressionType::MaxRowsAtCompileTime, 1> MatrixColType;
+ typedef Array<Scalar, ExpressionType::RowsAtCompileTime, 1,
+ ExpressionType::PlainObject::Options & ~RowMajor, ExpressionType::MaxRowsAtCompileTime, 1> ArrayColType;
+
+ typedef typename conditional<
+ is_same< typename traits<ExpressionType>::XprKind, MatrixXpr >::value,
+ MatrixColType,
+ ArrayColType
+ >::type type;
+};
+
+template<typename ExpressionType, typename Scalar = typename ExpressionType::Scalar>
+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<Scalar, diag_size, 1, ExpressionType::PlainObject::Options & ~RowMajor, max_diag_size, 1> MatrixDiagType;
+ typedef Array<Scalar, diag_size, 1, ExpressionType::PlainObject::Options & ~RowMajor, max_diag_size, 1> ArrayDiagType;
+
+ typedef typename conditional<
+ is_same< typename traits<ExpressionType>::XprKind, MatrixXpr >::value,
+ MatrixDiagType,
+ ArrayDiagType
+ >::type type;
+};
+
+template<typename ExpressionType>
+struct is_lvalue
+{
+ enum { value = !bool(is_const<ExpressionType>::value) &&
+ bool(traits<ExpressionType>::Flags & LvalueBit) };
+};
+
+} // end namespace internal
+
+} // end namespace Eigen
+
+#endif // EIGEN_XPRHELPER_H
diff --git a/Eigen/src/Eigen2Support/Block.h b/Eigen/src/Eigen2Support/Block.h
new file mode 100644
index 000000000..604456f40
--- /dev/null
+++ b/Eigen/src/Eigen2Support/Block.h
@@ -0,0 +1,126 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra.
+//
+// Copyright (C) 2008-2009 Gael Guennebaud <gael.guennebaud@inria.fr>
+// Copyright (C) 2006-2008 Benoit Jacob <jacob.benoit.1@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 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<typename Derived>
+inline Block<Derived> DenseBase<Derived>
+ ::corner(CornerType type, Index cRows, Index cCols)
+{
+ switch(type)
+ {
+ default:
+ eigen_assert(false && "Bad corner type.");
+ case TopLeft:
+ return Block<Derived>(derived(), 0, 0, cRows, cCols);
+ case TopRight:
+ return Block<Derived>(derived(), 0, cols() - cCols, cRows, cCols);
+ case BottomLeft:
+ return Block<Derived>(derived(), rows() - cRows, 0, cRows, cCols);
+ case BottomRight:
+ return Block<Derived>(derived(), rows() - cRows, cols() - cCols, cRows, cCols);
+ }
+}
+
+/** This is the const version of corner(CornerType, Index, Index).*/
+template<typename Derived>
+inline const Block<Derived>
+DenseBase<Derived>::corner(CornerType type, Index cRows, Index cCols) const
+{
+ switch(type)
+ {
+ default:
+ eigen_assert(false && "Bad corner type.");
+ case TopLeft:
+ return Block<Derived>(derived(), 0, 0, cRows, cCols);
+ case TopRight:
+ return Block<Derived>(derived(), 0, cols() - cCols, cRows, cCols);
+ case BottomLeft:
+ return Block<Derived>(derived(), rows() - cRows, 0, cRows, cCols);
+ case BottomRight:
+ return Block<Derived>(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<typename Derived>
+template<int CRows, int CCols>
+inline Block<Derived, CRows, CCols>
+DenseBase<Derived>::corner(CornerType type)
+{
+ switch(type)
+ {
+ default:
+ eigen_assert(false && "Bad corner type.");
+ case TopLeft:
+ return Block<Derived, CRows, CCols>(derived(), 0, 0);
+ case TopRight:
+ return Block<Derived, CRows, CCols>(derived(), 0, cols() - CCols);
+ case BottomLeft:
+ return Block<Derived, CRows, CCols>(derived(), rows() - CRows, 0);
+ case BottomRight:
+ return Block<Derived, CRows, CCols>(derived(), rows() - CRows, cols() - CCols);
+ }
+}
+
+/** This is the const version of corner<int, int>(CornerType).*/
+template<typename Derived>
+template<int CRows, int CCols>
+inline const Block<Derived, CRows, CCols>
+DenseBase<Derived>::corner(CornerType type) const
+{
+ switch(type)
+ {
+ default:
+ eigen_assert(false && "Bad corner type.");
+ case TopLeft:
+ return Block<Derived, CRows, CCols>(derived(), 0, 0);
+ case TopRight:
+ return Block<Derived, CRows, CCols>(derived(), 0, cols() - CCols);
+ case BottomLeft:
+ return Block<Derived, CRows, CCols>(derived(), rows() - CRows, 0);
+ case BottomRight:
+ return Block<Derived, CRows, CCols>(derived(), rows() - CRows, cols() - CCols);
+ }
+}
+
+} // end namespace Eigen
+
+#endif // EIGEN_BLOCK2_H
diff --git a/Eigen/src/Eigen2Support/CMakeLists.txt b/Eigen/src/Eigen2Support/CMakeLists.txt
new file mode 100644
index 000000000..7ae41b3cb
--- /dev/null
+++ b/Eigen/src/Eigen2Support/CMakeLists.txt
@@ -0,0 +1,8 @@
+FILE(GLOB Eigen_Eigen2Support_SRCS "*.h")
+
+INSTALL(FILES
+ ${Eigen_Eigen2Support_SRCS}
+ DESTINATION ${INCLUDE_INSTALL_DIR}/Eigen/src/Eigen2Support COMPONENT Devel
+ )
+
+ADD_SUBDIRECTORY(Geometry) \ No newline at end of file
diff --git a/Eigen/src/Eigen2Support/Cwise.h b/Eigen/src/Eigen2Support/Cwise.h
new file mode 100644
index 000000000..d95009b6e
--- /dev/null
+++ b/Eigen/src/Eigen2Support/Cwise.h
@@ -0,0 +1,192 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra.
+//
+// Copyright (C) 2008 Gael Guennebaud <gael.guennebaud@inria.fr>
+// Copyright (C) 2008 Benoit Jacob <jacob.benoit.1@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 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<OP<typename internal::traits<ExpressionType>::Scalar>, ExpressionType, OtherDerived>
+
+/** \internal
+ * convenient macro to defined the return type of a cwise unary operation */
+#define EIGEN_CWISE_UNOP_RETURN_TYPE(OP) \
+ CwiseUnaryOp<OP<typename internal::traits<ExpressionType>::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<OP<typename internal::traits<ExpressionType>::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<typename ExpressionType> class Cwise
+{
+ public:
+
+ typedef typename internal::traits<ExpressionType>::Scalar Scalar;
+ typedef typename internal::conditional<internal::must_nest_by_value<ExpressionType>::ret,
+ ExpressionType, const ExpressionType&>::type ExpressionTypeNested;
+ typedef CwiseUnaryOp<internal::scalar_add_op<Scalar>, ExpressionType> ScalarAddReturnType;
+
+ inline Cwise(const ExpressionType& matrix) : m_matrix(matrix) {}
+
+ /** \internal */
+ inline const ExpressionType& _expression() const { return m_matrix; }
+
+ template<typename OtherDerived>
+ const EIGEN_CWISE_PRODUCT_RETURN_TYPE(ExpressionType,OtherDerived)
+ operator*(const MatrixBase<OtherDerived> &other) const;
+
+ template<typename OtherDerived>
+ const EIGEN_CWISE_BINOP_RETURN_TYPE(internal::scalar_quotient_op)
+ operator/(const MatrixBase<OtherDerived> &other) const;
+
+ /** \deprecated ArrayBase::min() */
+ template<typename OtherDerived>
+ const EIGEN_CWISE_BINOP_RETURN_TYPE(internal::scalar_min_op)
+ (min)(const MatrixBase<OtherDerived> &other) const
+ { return EIGEN_CWISE_BINOP_RETURN_TYPE(internal::scalar_min_op)(_expression(), other.derived()); }
+
+ /** \deprecated ArrayBase::max() */
+ template<typename OtherDerived>
+ const EIGEN_CWISE_BINOP_RETURN_TYPE(internal::scalar_max_op)
+ (max)(const MatrixBase<OtherDerived> &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<typename OtherDerived>
+ inline ExpressionType& operator*=(const MatrixBase<OtherDerived> &other);
+
+ template<typename OtherDerived>
+ inline ExpressionType& operator/=(const MatrixBase<OtherDerived> &other);
+
+ template<typename OtherDerived> const EIGEN_CWISE_BINOP_RETURN_TYPE(std::less)
+ operator<(const MatrixBase<OtherDerived>& other) const;
+
+ template<typename OtherDerived> const EIGEN_CWISE_BINOP_RETURN_TYPE(std::less_equal)
+ operator<=(const MatrixBase<OtherDerived>& other) const;
+
+ template<typename OtherDerived> const EIGEN_CWISE_BINOP_RETURN_TYPE(std::greater)
+ operator>(const MatrixBase<OtherDerived>& other) const;
+
+ template<typename OtherDerived> const EIGEN_CWISE_BINOP_RETURN_TYPE(std::greater_equal)
+ operator>=(const MatrixBase<OtherDerived>& other) const;
+
+ template<typename OtherDerived> const EIGEN_CWISE_BINOP_RETURN_TYPE(std::equal_to)
+ operator==(const MatrixBase<OtherDerived>& other) const;
+
+ template<typename OtherDerived> const EIGEN_CWISE_BINOP_RETURN_TYPE(std::not_equal_to)
+ operator!=(const MatrixBase<OtherDerived>& 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<typename Derived>
+inline const Cwise<Derived> MatrixBase<Derived>::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<typename Derived>
+inline Cwise<Derived> MatrixBase<Derived>::cwise()
+{
+ return derived();
+}
+
+} // end namespace Eigen
+
+#endif // EIGEN_CWISE_H
diff --git a/Eigen/src/Eigen2Support/CwiseOperators.h b/Eigen/src/Eigen2Support/CwiseOperators.h
new file mode 100644
index 000000000..482f30648
--- /dev/null
+++ b/Eigen/src/Eigen2Support/CwiseOperators.h
@@ -0,0 +1,298 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra.
+//
+// Copyright (C) 2008 Gael Guennebaud <gael.guennebaud@inria.fr>
+//
+// This Source Code Form is subject to the terms of the Mozilla
+// Public License v. 2.0. If 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<typename ExpressionType>
+EIGEN_STRONG_INLINE const EIGEN_CWISE_UNOP_RETURN_TYPE(internal::scalar_abs_op)
+Cwise<ExpressionType>::abs() const
+{
+ return _expression();
+}
+
+/** \deprecated ArrayBase::abs2() */
+template<typename ExpressionType>
+EIGEN_STRONG_INLINE const EIGEN_CWISE_UNOP_RETURN_TYPE(internal::scalar_abs2_op)
+Cwise<ExpressionType>::abs2() const
+{
+ return _expression();
+}
+
+/** \deprecated ArrayBase::exp() */
+template<typename ExpressionType>
+inline const EIGEN_CWISE_UNOP_RETURN_TYPE(internal::scalar_exp_op)
+Cwise<ExpressionType>::exp() const
+{
+ return _expression();
+}
+
+/** \deprecated ArrayBase::log() */
+template<typename ExpressionType>
+inline const EIGEN_CWISE_UNOP_RETURN_TYPE(internal::scalar_log_op)
+Cwise<ExpressionType>::log() const
+{
+ return _expression();
+}
+
+/** \deprecated ArrayBase::operator*() */
+template<typename ExpressionType>
+template<typename OtherDerived>
+EIGEN_STRONG_INLINE const EIGEN_CWISE_PRODUCT_RETURN_TYPE(ExpressionType,OtherDerived)
+Cwise<ExpressionType>::operator*(const MatrixBase<OtherDerived> &other) const
+{
+ return EIGEN_CWISE_PRODUCT_RETURN_TYPE(ExpressionType,OtherDerived)(_expression(), other.derived());
+}
+
+/** \deprecated ArrayBase::operator/() */
+template<typename ExpressionType>
+template<typename OtherDerived>
+EIGEN_STRONG_INLINE const EIGEN_CWISE_BINOP_RETURN_TYPE(internal::scalar_quotient_op)
+Cwise<ExpressionType>::operator/(const MatrixBase<OtherDerived> &other) const
+{
+ return EIGEN_CWISE_BINOP_RETURN_TYPE(internal::scalar_quotient_op)(_expression(), other.derived());
+}
+
+/** \deprecated ArrayBase::operator*=() */
+template<typename ExpressionType>
+template<typename OtherDerived>
+inline ExpressionType& Cwise<ExpressionType>::operator*=(const MatrixBase<OtherDerived> &other)
+{
+ return m_matrix.const_cast_derived() = *this * other;
+}
+
+/** \deprecated ArrayBase::operator/=() */
+template<typename ExpressionType>
+template<typename OtherDerived>
+inline ExpressionType& Cwise<ExpressionType>::operator/=(const MatrixBase<OtherDerived> &other)
+{
+ return m_matrix.const_cast_derived() = *this / other;
+}
+
+/***************************************************************************
+* The following functions were defined in Array
+***************************************************************************/
+
+// -- unary operators --
+
+/** \deprecated ArrayBase::sqrt() */
+template<typename ExpressionType>
+inline const EIGEN_CWISE_UNOP_RETURN_TYPE(internal::scalar_sqrt_op)
+Cwise<ExpressionType>::sqrt() const
+{
+ return _expression();
+}
+
+/** \deprecated ArrayBase::cos() */
+template<typename ExpressionType>
+inline const EIGEN_CWISE_UNOP_RETURN_TYPE(internal::scalar_cos_op)
+Cwise<ExpressionType>::cos() const
+{
+ return _expression();
+}
+
+
+/** \deprecated ArrayBase::sin() */
+template<typename ExpressionType>
+inline const EIGEN_CWISE_UNOP_RETURN_TYPE(internal::scalar_sin_op)
+Cwise<ExpressionType>::sin() const
+{
+ return _expression();
+}
+
+
+/** \deprecated ArrayBase::log() */
+template<typename ExpressionType>
+inline const EIGEN_CWISE_UNOP_RETURN_TYPE(internal::scalar_pow_op)
+Cwise<ExpressionType>::pow(const Scalar& exponent) const
+{
+ return EIGEN_CWISE_UNOP_RETURN_TYPE(internal::scalar_pow_op)(_expression(), internal::scalar_pow_op<Scalar>(exponent));
+}
+
+
+/** \deprecated ArrayBase::inverse() */
+template<typename ExpressionType>
+inline const EIGEN_CWISE_UNOP_RETURN_TYPE(internal::scalar_inverse_op)
+Cwise<ExpressionType>::inverse() const
+{
+ return _expression();
+}
+
+/** \deprecated ArrayBase::square() */
+template<typename ExpressionType>
+inline const EIGEN_CWISE_UNOP_RETURN_TYPE(internal::scalar_square_op)
+Cwise<ExpressionType>::square() const
+{
+ return _expression();
+}
+
+/** \deprecated ArrayBase::cube() */
+template<typename ExpressionType>
+inline const EIGEN_CWISE_UNOP_RETURN_TYPE(internal::scalar_cube_op)
+Cwise<ExpressionType>::cube() const
+{
+ return _expression();
+}
+
+
+// -- binary operators --
+
+/** \deprecated ArrayBase::operator<() */
+template<typename ExpressionType>
+template<typename OtherDerived>
+inline const EIGEN_CWISE_BINOP_RETURN_TYPE(std::less)
+Cwise<ExpressionType>::operator<(const MatrixBase<OtherDerived> &other) const
+{
+ return EIGEN_CWISE_BINOP_RETURN_TYPE(std::less)(_expression(), other.derived());
+}
+
+/** \deprecated ArrayBase::<=() */
+template<typename ExpressionType>
+template<typename OtherDerived>
+inline const EIGEN_CWISE_BINOP_RETURN_TYPE(std::less_equal)
+Cwise<ExpressionType>::operator<=(const MatrixBase<OtherDerived> &other) const
+{
+ return EIGEN_CWISE_BINOP_RETURN_TYPE(std::less_equal)(_expression(), other.derived());
+}
+
+/** \deprecated ArrayBase::operator>() */
+template<typename ExpressionType>
+template<typename OtherDerived>
+inline const EIGEN_CWISE_BINOP_RETURN_TYPE(std::greater)
+Cwise<ExpressionType>::operator>(const MatrixBase<OtherDerived> &other) const
+{
+ return EIGEN_CWISE_BINOP_RETURN_TYPE(std::greater)(_expression(), other.derived());
+}
+
+/** \deprecated ArrayBase::operator>=() */
+template<typename ExpressionType>
+template<typename OtherDerived>
+inline const EIGEN_CWISE_BINOP_RETURN_TYPE(std::greater_equal)
+Cwise<ExpressionType>::operator>=(const MatrixBase<OtherDerived> &other) const
+{
+ return EIGEN_CWISE_BINOP_RETURN_TYPE(std::greater_equal)(_expression(), other.derived());
+}
+
+/** \deprecated ArrayBase::operator==() */
+template<typename ExpressionType>
+template<typename OtherDerived>
+inline const EIGEN_CWISE_BINOP_RETURN_TYPE(std::equal_to)
+Cwise<ExpressionType>::operator==(const MatrixBase<OtherDerived> &other) const
+{
+ return EIGEN_CWISE_BINOP_RETURN_TYPE(std::equal_to)(_expression(), other.derived());
+}
+
+/** \deprecated ArrayBase::operator!=() */
+template<typename ExpressionType>
+template<typename OtherDerived>
+inline const EIGEN_CWISE_BINOP_RETURN_TYPE(std::not_equal_to)
+Cwise<ExpressionType>::operator!=(const MatrixBase<OtherDerived> &other) const
+{
+ return EIGEN_CWISE_BINOP_RETURN_TYPE(std::not_equal_to)(_expression(), other.derived());
+}
+
+// comparisons to scalar value
+
+/** \deprecated ArrayBase::operator<(Scalar) */
+template<typename ExpressionType>
+inline const EIGEN_CWISE_COMP_TO_SCALAR_RETURN_TYPE(std::less)
+Cwise<ExpressionType>::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<typename ExpressionType>
+inline const EIGEN_CWISE_COMP_TO_SCALAR_RETURN_TYPE(std::less_equal)
+Cwise<ExpressionType>::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<typename ExpressionType>
+inline const EIGEN_CWISE_COMP_TO_SCALAR_RETURN_TYPE(std::greater)
+Cwise<ExpressionType>::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<typename ExpressionType>
+inline const EIGEN_CWISE_COMP_TO_SCALAR_RETURN_TYPE(std::greater_equal)
+Cwise<ExpressionType>::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<typename ExpressionType>
+inline const EIGEN_CWISE_COMP_TO_SCALAR_RETURN_TYPE(std::equal_to)
+Cwise<ExpressionType>::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<typename ExpressionType>
+inline const EIGEN_CWISE_COMP_TO_SCALAR_RETURN_TYPE(std::not_equal_to)
+Cwise<ExpressionType>::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<typename ExpressionType>
+inline const typename Cwise<ExpressionType>::ScalarAddReturnType
+Cwise<ExpressionType>::operator+(const Scalar& scalar) const
+{
+ return typename Cwise<ExpressionType>::ScalarAddReturnType(m_matrix, internal::scalar_add_op<Scalar>(scalar));
+}
+
+/** \deprecated ArrayBase::operator+=(Scalar) */
+template<typename ExpressionType>
+inline ExpressionType& Cwise<ExpressionType>::operator+=(const Scalar& scalar)
+{
+ return m_matrix.const_cast_derived() = *this + scalar;
+}
+
+/** \deprecated ArrayBase::operator-(Scalar) */
+template<typename ExpressionType>
+inline const typename Cwise<ExpressionType>::ScalarAddReturnType
+Cwise<ExpressionType>::operator-(const Scalar& scalar) const
+{
+ return *this + (-scalar);
+}
+
+/** \deprecated ArrayBase::operator-=(Scalar) */
+template<typename ExpressionType>
+inline ExpressionType& Cwise<ExpressionType>::operator-=(const Scalar& scalar)
+{
+ return m_matrix.const_cast_derived() = *this - scalar;
+}
+
+} // end namespace Eigen
+
+#endif // EIGEN_ARRAY_CWISE_OPERATORS_H
diff --git a/Eigen/src/Eigen2Support/Geometry/AlignedBox.h b/Eigen/src/Eigen2Support/Geometry/AlignedBox.h
new file mode 100644
index 000000000..5c928e8fc
--- /dev/null
+++ b/Eigen/src/Eigen2Support/Geometry/AlignedBox.h
@@ -0,0 +1,159 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra. Eigen itself is part of the KDE project.
+//
+// Copyright (C) 2008 Gael Guennebaud <g.gael@free.fr>
+//
+// This Source Code Form is subject to the terms of the Mozilla
+// Public License v. 2.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 <typename _Scalar, int _AmbientDim>
+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<Scalar>::Real RealScalar;
+ typedef Matrix<Scalar,AmbientDimAtCompileTime,1> VectorType;
+
+ /** Default constructor initializing a null box. */
+ inline explicit 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<Scalar>::max)());
+ m_max.setConstant(-(std::numeric_limits<Scalar>::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<typename NewScalarType>
+ inline typename internal::cast_return_type<AlignedBox,
+ AlignedBox<NewScalarType,AmbientDimAtCompileTime> >::type cast() const
+ {
+ return typename internal::cast_return_type<AlignedBox,
+ AlignedBox<NewScalarType,AmbientDimAtCompileTime> >::type(*this);
+ }
+
+ /** Copy constructor with scalar type conversion */
+ template<typename OtherScalarType>
+ inline explicit AlignedBox(const AlignedBox<OtherScalarType,AmbientDimAtCompileTime>& other)
+ {
+ m_min = (other.min)().template cast<Scalar>();
+ m_max = (other.max)().template cast<Scalar>();
+ }
+
+ /** \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<Scalar>::Real prec = precision<Scalar>()) const
+ { return m_min.isApprox(other.m_min, prec) && m_max.isApprox(other.m_max, prec); }
+
+protected:
+
+ VectorType m_min, m_max;
+};
+
+template<typename Scalar,int AmbiantDim>
+inline Scalar AlignedBox<Scalar,AmbiantDim>::squaredExteriorDistance(const VectorType& p) const
+{
+ Scalar dist2(0);
+ Scalar aux;
+ for (int k=0; k<dim(); ++k)
+ {
+ if ((aux = (p[k]-m_min[k]))<Scalar(0))
+ dist2 += aux*aux;
+ else if ( (aux = (m_max[k]-p[k]))<Scalar(0))
+ dist2 += aux*aux;
+ }
+ return dist2;
+}
+
+} // end namespace Eigen
diff --git a/Eigen/src/Eigen2Support/Geometry/All.h b/Eigen/src/Eigen2Support/Geometry/All.h
new file mode 100644
index 000000000..e0b00fccc
--- /dev/null
+++ b/Eigen/src/Eigen2Support/Geometry/All.h
@@ -0,0 +1,115 @@
+#ifndef EIGEN2_GEOMETRY_MODULE_H
+#define EIGEN2_GEOMETRY_MODULE_H
+
+#include <limits>
+
+#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/Eigen/src/Eigen2Support/Geometry/AngleAxis.h b/Eigen/src/Eigen2Support/Geometry/AngleAxis.h
new file mode 100644
index 000000000..20f1fceeb
--- /dev/null
+++ b/Eigen/src/Eigen2Support/Geometry/AngleAxis.h
@@ -0,0 +1,214 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra. Eigen itself is part of the KDE project.
+//
+// Copyright (C) 2008 Gael Guennebaud <g.gael@free.fr>
+//
+// This Source Code Form is subject to the terms of the Mozilla
+// Public License v. 2.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<typename _Scalar> struct ei_traits<AngleAxis<_Scalar> >
+{
+ typedef _Scalar Scalar;
+};
+
+template<typename _Scalar>
+class AngleAxis : public RotationBase<AngleAxis<_Scalar>,3>
+{
+ typedef RotationBase<AngleAxis<_Scalar>,3> Base;
+
+public:
+
+ using Base::operator*;
+
+ enum { Dim = 3 };
+ /** the scalar type of the coefficients */
+ typedef _Scalar Scalar;
+ typedef Matrix<Scalar,3,3> Matrix3;
+ typedef Matrix<Scalar,3,1> Vector3;
+ typedef Quaternion<Scalar> 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<typename Derived>
+ inline AngleAxis(Scalar angle, const MatrixBase<Derived>& 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<typename Derived>
+ inline explicit AngleAxis(const MatrixBase<Derived>& 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<typename Derived>
+ AngleAxis& operator=(const MatrixBase<Derived>& m);
+
+ template<typename Derived>
+ AngleAxis& fromRotationMatrix(const MatrixBase<Derived>& 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<typename NewScalarType>
+ inline typename internal::cast_return_type<AngleAxis,AngleAxis<NewScalarType> >::type cast() const
+ { return typename internal::cast_return_type<AngleAxis,AngleAxis<NewScalarType> >::type(*this); }
+
+ /** Copy constructor with scalar type conversion */
+ template<typename OtherScalarType>
+ inline explicit AngleAxis(const AngleAxis<OtherScalarType>& other)
+ {
+ m_axis = other.axis().template cast<Scalar>();
+ 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<Scalar>::Real prec = precision<Scalar>()) 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<float> AngleAxisf;
+/** \ingroup Geometry_Module
+ * double precision angle-axis type */
+typedef AngleAxis<double> AngleAxisd;
+
+/** Set \c *this from a quaternion.
+ * The axis is normalized.
+ */
+template<typename Scalar>
+AngleAxis<Scalar>& AngleAxis<Scalar>::operator=(const QuaternionType& q)
+{
+ Scalar n2 = q.vec().squaredNorm();
+ if (n2 < precision<Scalar>()*precision<Scalar>())
+ {
+ 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<typename Scalar>
+template<typename Derived>
+AngleAxis<Scalar>& AngleAxis<Scalar>::operator=(const MatrixBase<Derived>& 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 Scalar>
+typename AngleAxis<Scalar>::Matrix3
+AngleAxis<Scalar>::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/Eigen/src/Eigen2Support/Geometry/CMakeLists.txt b/Eigen/src/Eigen2Support/Geometry/CMakeLists.txt
new file mode 100644
index 000000000..c347a8f26
--- /dev/null
+++ b/Eigen/src/Eigen2Support/Geometry/CMakeLists.txt
@@ -0,0 +1,6 @@
+FILE(GLOB Eigen_Eigen2Support_Geometry_SRCS "*.h")
+
+INSTALL(FILES
+ ${Eigen_Eigen2Support_Geometry_SRCS}
+ DESTINATION ${INCLUDE_INSTALL_DIR}/Eigen/src/Eigen2Support/Geometry
+ )
diff --git a/Eigen/src/Eigen2Support/Geometry/Hyperplane.h b/Eigen/src/Eigen2Support/Geometry/Hyperplane.h
new file mode 100644
index 000000000..19cc1bfd8
--- /dev/null
+++ b/Eigen/src/Eigen2Support/Geometry/Hyperplane.h
@@ -0,0 +1,254 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra. Eigen itself is part of the KDE project.
+//
+// Copyright (C) 2008 Gael Guennebaud <g.gael@free.fr>
+// Copyright (C) 2008 Benoit Jacob <jacob.benoit.1@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/.
+
+// 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 <typename _Scalar, int _AmbientDim>
+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<Scalar>::Real RealScalar;
+ typedef Matrix<Scalar,AmbientDimAtCompileTime,1> VectorType;
+ typedef Matrix<Scalar,int(AmbientDimAtCompileTime)==Dynamic
+ ? Dynamic
+ : int(AmbientDimAtCompileTime)+1,1> Coefficients;
+ typedef Block<Coefficients,AmbientDimAtCompileTime,1> NormalReturnType;
+
+ /** Default constructor without initialization */
+ inline explicit 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<Scalar, AmbientDimAtCompileTime>& 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<Coefficients*>(&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<typename XprType>
+ inline Hyperplane& transform(const MatrixBase<XprType>& 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<Scalar,AmbientDimAtCompileTime>& 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<typename NewScalarType>
+ inline typename internal::cast_return_type<Hyperplane,
+ Hyperplane<NewScalarType,AmbientDimAtCompileTime> >::type cast() const
+ {
+ return typename internal::cast_return_type<Hyperplane,
+ Hyperplane<NewScalarType,AmbientDimAtCompileTime> >::type(*this);
+ }
+
+ /** Copy constructor with scalar type conversion */
+ template<typename OtherScalarType>
+ inline explicit Hyperplane(const Hyperplane<OtherScalarType,AmbientDimAtCompileTime>& other)
+ { m_coeffs = other.coeffs().template cast<Scalar>(); }
+
+ /** \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<Scalar>::Real prec = precision<Scalar>()) const
+ { return m_coeffs.isApprox(other.m_coeffs, prec); }
+
+protected:
+
+ Coefficients m_coeffs;
+};
+
+} // end namespace Eigen
diff --git a/Eigen/src/Eigen2Support/Geometry/ParametrizedLine.h b/Eigen/src/Eigen2Support/Geometry/ParametrizedLine.h
new file mode 100644
index 000000000..6e4a168a8
--- /dev/null
+++ b/Eigen/src/Eigen2Support/Geometry/ParametrizedLine.h
@@ -0,0 +1,141 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra. Eigen itself is part of the KDE project.
+//
+// Copyright (C) 2008 Gael Guennebaud <g.gael@free.fr>
+// Copyright (C) 2008 Benoit Jacob <jacob.benoit.1@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/.
+
+// 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 <typename _Scalar, int _AmbientDim>
+class ParametrizedLine
+{
+public:
+ EIGEN_MAKE_ALIGNED_OPERATOR_NEW_IF_VECTORIZABLE_FIXED_SIZE(_Scalar,_AmbientDim)
+ enum { AmbientDimAtCompileTime = _AmbientDim };
+ typedef _Scalar Scalar;
+ typedef typename NumTraits<Scalar>::Real RealScalar;
+ typedef Matrix<Scalar,AmbientDimAtCompileTime,1> VectorType;
+
+ /** Default constructor without initialization */
+ inline explicit 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<typename NewScalarType>
+ inline typename internal::cast_return_type<ParametrizedLine,
+ ParametrizedLine<NewScalarType,AmbientDimAtCompileTime> >::type cast() const
+ {
+ return typename internal::cast_return_type<ParametrizedLine,
+ ParametrizedLine<NewScalarType,AmbientDimAtCompileTime> >::type(*this);
+ }
+
+ /** Copy constructor with scalar type conversion */
+ template<typename OtherScalarType>
+ inline explicit ParametrizedLine(const ParametrizedLine<OtherScalarType,AmbientDimAtCompileTime>& other)
+ {
+ m_origin = other.origin().template cast<Scalar>();
+ m_direction = other.direction().template cast<Scalar>();
+ }
+
+ /** \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<Scalar>::Real prec = precision<Scalar>()) 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 <typename _Scalar, int _AmbientDim>
+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 <typename _Scalar, int _AmbientDim>
+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/Eigen/src/Eigen2Support/Geometry/Quaternion.h b/Eigen/src/Eigen2Support/Geometry/Quaternion.h
new file mode 100644
index 000000000..ec87da054
--- /dev/null
+++ b/Eigen/src/Eigen2Support/Geometry/Quaternion.h
@@ -0,0 +1,495 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra. Eigen itself is part of the KDE project.
+//
+// Copyright (C) 2008 Gael Guennebaud <g.gael@free.fr>
+//
+// This Source Code Form is subject to the terms of the Mozilla
+// Public License v. 2.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<typename Other,
+ int OtherRows=Other::RowsAtCompileTime,
+ int OtherCols=Other::ColsAtCompileTime>
+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<typename _Scalar> struct ei_traits<Quaternion<_Scalar> >
+{
+ typedef _Scalar Scalar;
+};
+
+template<typename _Scalar>
+class Quaternion : public RotationBase<Quaternion<_Scalar>,3>
+{
+ typedef RotationBase<Quaternion<_Scalar>,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<Scalar, 4, 1> Coefficients;
+ /** the type of a 3D vector */
+ typedef Matrix<Scalar,3,1> Vector3;
+ /** the equivalent rotation matrix type */
+ typedef Matrix<Scalar,3,3> Matrix3;
+ /** the equivalent angle-axis type */
+ typedef AngleAxis<Scalar> 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<const Coefficients,3,1> vec() const { return m_coeffs.template start<3>(); }
+
+ /** \returns a vector expression of the imaginary part (x,y,z) */
+ inline Block<Coefficients,3,1> 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<Derived>)
+ */
+ template<typename Derived>
+ explicit inline Quaternion(const MatrixBase<Derived>& other) { *this = other; }
+
+ Quaternion& operator=(const Quaternion& other);
+ Quaternion& operator=(const AngleAxisType& aa);
+ template<typename Derived>
+ Quaternion& operator=(const MatrixBase<Derived>& 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<typename Derived1, typename Derived2>
+ Quaternion& setFromTwoVectors(const MatrixBase<Derived1>& a, const MatrixBase<Derived2>& 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<typename Derived>
+ Vector3 operator* (const MatrixBase<Derived>& 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<typename NewScalarType>
+ inline typename internal::cast_return_type<Quaternion,Quaternion<NewScalarType> >::type cast() const
+ { return typename internal::cast_return_type<Quaternion,Quaternion<NewScalarType> >::type(*this); }
+
+ /** Copy constructor with scalar type conversion */
+ template<typename OtherScalarType>
+ inline explicit Quaternion(const Quaternion<OtherScalarType>& other)
+ { m_coeffs = other.coeffs().template cast<Scalar>(); }
+
+ /** \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<Scalar>::Real prec = precision<Scalar>()) const
+ { return m_coeffs.isApprox(other.m_coeffs, prec); }
+
+protected:
+ Coefficients m_coeffs;
+};
+
+/** \ingroup Geometry_Module
+ * single precision quaternion type */
+typedef Quaternion<float> Quaternionf;
+/** \ingroup Geometry_Module
+ * double precision quaternion type */
+typedef Quaternion<double> Quaterniond;
+
+// Generic Quaternion * Quaternion product
+template<typename Scalar> inline Quaternion<Scalar>
+ei_quaternion_product(const Quaternion<Scalar>& a, const Quaternion<Scalar>& b)
+{
+ return Quaternion<Scalar>
+ (
+ 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 <typename Scalar>
+inline Quaternion<Scalar> Quaternion<Scalar>::operator* (const Quaternion& other) const
+{
+ return ei_quaternion_product(*this,other);
+}
+
+/** \sa operator*(Quaternion) */
+template <typename Scalar>
+inline Quaternion<Scalar>& Quaternion<Scalar>::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 <typename Scalar>
+template<typename Derived>
+inline typename Quaternion<Scalar>::Vector3
+Quaternion<Scalar>::operator* (const MatrixBase<Derived>& 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<typename Scalar>
+inline Quaternion<Scalar>& Quaternion<Scalar>::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<typename Scalar>
+inline Quaternion<Scalar>& Quaternion<Scalar>::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<typename Scalar>
+template<typename Derived>
+inline Quaternion<Scalar>& Quaternion<Scalar>::operator=(const MatrixBase<Derived>& xpr)
+{
+ ei_quaternion_assign_impl<Derived>::run(*this, xpr.derived());
+ return *this;
+}
+
+/** Convert the quaternion to a 3x3 rotation matrix */
+template<typename Scalar>
+inline typename Quaternion<Scalar>::Matrix3
+Quaternion<Scalar>::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<typename Scalar>
+template<typename Derived1, typename Derived2>
+inline Quaternion<Scalar>& Quaternion<Scalar>::setFromTwoVectors(const MatrixBase<Derived1>& a, const MatrixBase<Derived2>& 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 <typename Scalar>
+inline Quaternion<Scalar> Quaternion<Scalar>::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 <typename Scalar>
+inline Quaternion<Scalar> Quaternion<Scalar>::conjugate() const
+{
+ return Quaternion(this->w(),-this->x(),-this->y(),-this->z());
+}
+
+/** \returns the angle (in radian) between two rotations
+ * \sa eigen2_dot()
+ */
+template <typename Scalar>
+inline Scalar Quaternion<Scalar>::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 <typename Scalar>
+Quaternion<Scalar> Quaternion<Scalar>::slerp(Scalar t, const Quaternion& other) const
+{
+ static const Scalar one = Scalar(1) - machine_epsilon<Scalar>();
+ 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<Scalar>(scale0 * coeffs() + scale1 * other.coeffs());
+}
+
+// set from a rotation matrix
+template<typename Other>
+struct ei_quaternion_assign_impl<Other,3,3>
+{
+ typedef typename Other::Scalar Scalar;
+ static inline void run(Quaternion<Scalar>& 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<typename Other>
+struct ei_quaternion_assign_impl<Other,4,1>
+{
+ typedef typename Other::Scalar Scalar;
+ static inline void run(Quaternion<Scalar>& q, const Other& vec)
+ {
+ q.coeffs() = vec;
+ }
+};
+
+} // end namespace Eigen
diff --git a/Eigen/src/Eigen2Support/Geometry/Rotation2D.h b/Eigen/src/Eigen2Support/Geometry/Rotation2D.h
new file mode 100644
index 000000000..3e02b7a4f
--- /dev/null
+++ b/Eigen/src/Eigen2Support/Geometry/Rotation2D.h
@@ -0,0 +1,145 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra. Eigen itself is part of the KDE project.
+//
+// Copyright (C) 2008 Gael Guennebaud <g.gael@free.fr>
+//
+// This Source Code Form is subject to the terms of the Mozilla
+// Public License v. 2.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<typename _Scalar> struct ei_traits<Rotation2D<_Scalar> >
+{
+ typedef _Scalar Scalar;
+};
+
+template<typename _Scalar>
+class Rotation2D : public RotationBase<Rotation2D<_Scalar>,2>
+{
+ typedef RotationBase<Rotation2D<_Scalar>,2> Base;
+
+public:
+
+ using Base::operator*;
+
+ enum { Dim = 2 };
+ /** the scalar type of the coefficients */
+ typedef _Scalar Scalar;
+ typedef Matrix<Scalar,2,1> Vector2;
+ typedef Matrix<Scalar,2,2> 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<typename Derived>
+ Rotation2D& fromRotationMatrix(const MatrixBase<Derived>& 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<typename NewScalarType>
+ inline typename internal::cast_return_type<Rotation2D,Rotation2D<NewScalarType> >::type cast() const
+ { return typename internal::cast_return_type<Rotation2D,Rotation2D<NewScalarType> >::type(*this); }
+
+ /** Copy constructor with scalar type conversion */
+ template<typename OtherScalarType>
+ inline explicit Rotation2D(const Rotation2D<OtherScalarType>& 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<Scalar>::Real prec = precision<Scalar>()) const
+ { return ei_isApprox(m_angle,other.m_angle, prec); }
+};
+
+/** \ingroup Geometry_Module
+ * single precision 2D rotation type */
+typedef Rotation2D<float> Rotation2Df;
+/** \ingroup Geometry_Module
+ * double precision 2D rotation type */
+typedef Rotation2D<double> 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<typename Scalar>
+template<typename Derived>
+Rotation2D<Scalar>& Rotation2D<Scalar>::fromRotationMatrix(const MatrixBase<Derived>& 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 Scalar>
+typename Rotation2D<Scalar>::Matrix2
+Rotation2D<Scalar>::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/Eigen/src/Eigen2Support/Geometry/RotationBase.h b/Eigen/src/Eigen2Support/Geometry/RotationBase.h
new file mode 100644
index 000000000..78ad73b60
--- /dev/null
+++ b/Eigen/src/Eigen2Support/Geometry/RotationBase.h
@@ -0,0 +1,123 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra. Eigen itself is part of the KDE project.
+//
+// Copyright (C) 2008 Gael Guennebaud <g.gael@free.fr>
+//
+// This Source Code Form is subject to the terms of the Mozilla
+// Public License v. 2.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<typename Derived, int _Dim>
+class RotationBase
+{
+ public:
+ enum { Dim = _Dim };
+ /** the scalar type of the coefficients */
+ typedef typename ei_traits<Derived>::Scalar Scalar;
+
+ /** corresponding linear transformation matrix type */
+ typedef Matrix<Scalar,Dim,Dim> RotationMatrixType;
+
+ inline const Derived& derived() const { return *static_cast<const Derived*>(this); }
+ inline Derived& derived() { return *static_cast<Derived*>(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<Scalar,Dim> operator*(const Translation<Scalar,Dim>& t) const
+ { return toRotationMatrix() * t; }
+
+ /** \returns the concatenation of the rotation \c *this with a scaling \a s */
+ inline RotationMatrixType operator*(const Scaling<Scalar,Dim>& s) const
+ { return toRotationMatrix() * s; }
+
+ /** \returns the concatenation of the rotation \c *this with an affine transformation \a t */
+ inline Transform<Scalar,Dim> operator*(const Transform<Scalar,Dim>& t) const
+ { return toRotationMatrix() * t; }
+};
+
+/** \geometry_module
+ *
+ * Constructs a Dim x Dim rotation matrix from the rotation \a r
+ */
+template<typename _Scalar, int _Rows, int _Cols, int _Storage, int _MaxRows, int _MaxCols>
+template<typename OtherDerived>
+Matrix<_Scalar, _Rows, _Cols, _Storage, _MaxRows, _MaxCols>
+::Matrix(const RotationBase<OtherDerived,ColsAtCompileTime>& 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<typename _Scalar, int _Rows, int _Cols, int _Storage, int _MaxRows, int _MaxCols>
+template<typename OtherDerived>
+Matrix<_Scalar, _Rows, _Cols, _Storage, _MaxRows, _MaxCols>&
+Matrix<_Scalar, _Rows, _Cols, _Storage, _MaxRows, _MaxCols>
+::operator=(const RotationBase<OtherDerived,ColsAtCompileTime>& 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<typename Scalar, int Dim>
+static inline Matrix<Scalar,2,2> ei_toRotationMatrix(const Scalar& s)
+{
+ EIGEN_STATIC_ASSERT(Dim==2,YOU_MADE_A_PROGRAMMING_MISTAKE)
+ return Rotation2D<Scalar>(s).toRotationMatrix();
+}
+
+template<typename Scalar, int Dim, typename OtherDerived>
+static inline Matrix<Scalar,Dim,Dim> ei_toRotationMatrix(const RotationBase<OtherDerived,Dim>& r)
+{
+ return r.toRotationMatrix();
+}
+
+template<typename Scalar, int Dim, typename OtherDerived>
+static inline const MatrixBase<OtherDerived>& ei_toRotationMatrix(const MatrixBase<OtherDerived>& mat)
+{
+ EIGEN_STATIC_ASSERT(OtherDerived::RowsAtCompileTime==Dim && OtherDerived::ColsAtCompileTime==Dim,
+ YOU_MADE_A_PROGRAMMING_MISTAKE)
+ return mat;
+}
+
+} // end namespace Eigen
diff --git a/Eigen/src/Eigen2Support/Geometry/Scaling.h b/Eigen/src/Eigen2Support/Geometry/Scaling.h
new file mode 100644
index 000000000..a07c1c7c7
--- /dev/null
+++ b/Eigen/src/Eigen2Support/Geometry/Scaling.h
@@ -0,0 +1,167 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra. Eigen itself is part of the KDE project.
+//
+// Copyright (C) 2008 Gael Guennebaud <g.gael@free.fr>
+//
+// This Source Code Form is subject to the terms of the Mozilla
+// Public License v. 2.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<typename _Scalar, int _Dim>
+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<Scalar,Dim,1> VectorType;
+ /** corresponding linear transformation matrix type */
+ typedef Matrix<Scalar,Dim,Dim> LinearMatrixType;
+ /** corresponding translation type */
+ typedef Translation<Scalar,Dim> TranslationType;
+ /** corresponding affine transformation type */
+ typedef Transform<Scalar,Dim> 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<typename Derived>
+ inline LinearMatrixType operator*(const RotationBase<Derived,Dim>& 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<typename NewScalarType>
+ inline typename internal::cast_return_type<Scaling,Scaling<NewScalarType,Dim> >::type cast() const
+ { return typename internal::cast_return_type<Scaling,Scaling<NewScalarType,Dim> >::type(*this); }
+
+ /** Copy constructor with scalar type conversion */
+ template<typename OtherScalarType>
+ inline explicit Scaling(const Scaling<OtherScalarType,Dim>& other)
+ { m_coeffs = other.coeffs().template cast<Scalar>(); }
+
+ /** \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<Scalar>::Real prec = precision<Scalar>()) const
+ { return m_coeffs.isApprox(other.m_coeffs, prec); }
+
+};
+
+/** \addtogroup Geometry_Module */
+//@{
+typedef Scaling<float, 2> Scaling2f;
+typedef Scaling<double,2> Scaling2d;
+typedef Scaling<float, 3> Scaling3f;
+typedef Scaling<double,3> Scaling3d;
+//@}
+
+template<typename Scalar, int Dim>
+inline typename Scaling<Scalar,Dim>::TransformType
+Scaling<Scalar,Dim>::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<typename Scalar, int Dim>
+inline typename Scaling<Scalar,Dim>::TransformType
+Scaling<Scalar,Dim>::operator* (const TransformType& t) const
+{
+ TransformType res = t;
+ res.prescale(m_coeffs);
+ return res;
+}
+
+} // end namespace Eigen
diff --git a/Eigen/src/Eigen2Support/Geometry/Transform.h b/Eigen/src/Eigen2Support/Geometry/Transform.h
new file mode 100644
index 000000000..dceb80203
--- /dev/null
+++ b/Eigen/src/Eigen2Support/Geometry/Transform.h
@@ -0,0 +1,786 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra. Eigen itself is part of the KDE project.
+//
+// Copyright (C) 2008 Gael Guennebaud <g.gael@free.fr>
+// Copyright (C) 2009 Benoit Jacob <jacob.benoit.1@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/.
+
+// 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<typename _Scalar, int _Dim>
+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<Scalar,HDim,HDim> MatrixType;
+ /** type of the matrix used to represent the linear part of the transformation */
+ typedef Matrix<Scalar,Dim,Dim> LinearMatrixType;
+ /** type of read/write reference to the linear part of the transformation */
+ typedef Block<MatrixType,Dim,Dim> LinearPart;
+ /** type of read/write reference to the linear part of the transformation */
+ typedef const Block<const MatrixType,Dim,Dim> ConstLinearPart;
+ /** type of a vector */
+ typedef Matrix<Scalar,Dim,1> VectorType;
+ /** type of a read/write reference to the translation part of the rotation */
+ typedef Block<MatrixType,Dim,1> TranslationPart;
+ /** type of a read/write reference to the translation part of the rotation */
+ typedef const Block<const MatrixType,Dim,1> ConstTranslationPart;
+ /** corresponding translation type */
+ typedef Translation<Scalar,Dim> TranslationType;
+ /** corresponding scaling transformation type */
+ typedef Scaling<Scalar,Dim> 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<typename Derived>
+ inline explicit Transform(const RotationBase<Derived, Dim>& r) { *this = r; }
+
+ inline Transform& operator=(const Transform& other)
+ { m_matrix = other.m_matrix; return *this; }
+
+ template<typename OtherDerived, bool BigMatrix> // MSVC 2005 will commit suicide if BigMatrix has a default value
+ struct construct_from_matrix
+ {
+ static inline void run(Transform *transform, const MatrixBase<OtherDerived>& other)
+ {
+ transform->matrix() = other;
+ }
+ };
+
+ template<typename OtherDerived> struct construct_from_matrix<OtherDerived, true>
+ {
+ static inline void run(Transform *transform, const MatrixBase<OtherDerived>& 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<typename OtherDerived>
+ inline explicit Transform(const MatrixBase<OtherDerived>& other)
+ {
+ construct_from_matrix<OtherDerived, int(OtherDerived::RowsAtCompileTime) == Dim>::run(this, other);
+ }
+
+ /** Set \c *this from a (Dim+1)^2 matrix. */
+ template<typename OtherDerived>
+ inline Transform& operator=(const MatrixBase<OtherDerived>& 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<Dim,Dim>(0,0); }
+ /** \returns a writable expression of the linear (linear) part of the transformation */
+ inline LinearPart linear() { return m_matrix.template block<Dim,Dim>(0,0); }
+
+ /** \returns a read-only expression of the translation vector of the transformation */
+ inline ConstTranslationPart translation() const { return m_matrix.template block<Dim,1>(0,Dim); }
+ /** \returns a writable expression of the translation vector of the transformation */
+ inline TranslationPart translation() { return m_matrix.template block<Dim,1>(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<typename OtherDerived>
+ inline const typename ei_transform_product_impl<OtherDerived,_Dim,_Dim+1>::ResultType
+ operator * (const MatrixBase<OtherDerived> &other) const
+ { return ei_transform_product_impl<OtherDerived,Dim,HDim>::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<typename OtherDerived>
+ friend inline const typename ProductReturnType<OtherDerived,MatrixType>::Type
+ operator * (const MatrixBase<OtherDerived> &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<typename OtherDerived>
+ inline Transform& scale(const MatrixBase<OtherDerived> &other);
+
+ template<typename OtherDerived>
+ inline Transform& prescale(const MatrixBase<OtherDerived> &other);
+
+ inline Transform& scale(Scalar s);
+ inline Transform& prescale(Scalar s);
+
+ template<typename OtherDerived>
+ inline Transform& translate(const MatrixBase<OtherDerived> &other);
+
+ template<typename OtherDerived>
+ inline Transform& pretranslate(const MatrixBase<OtherDerived> &other);
+
+ template<typename RotationType>
+ inline Transform& rotate(const RotationType& rotation);
+
+ template<typename RotationType>
+ 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<Dim,HDim>(0,0) = (mat * t.matrix().template block<Dim,HDim>(0,0)).lazy();
+ return res;
+ }
+
+ template<typename Derived>
+ inline Transform& operator=(const RotationBase<Derived,Dim>& r);
+ template<typename Derived>
+ inline Transform& operator*=(const RotationBase<Derived,Dim>& r) { return rotate(r.toRotationMatrix()); }
+ template<typename Derived>
+ inline Transform operator*(const RotationBase<Derived,Dim>& r) const;
+
+ LinearMatrixType rotation() const;
+ template<typename RotationMatrixType, typename ScalingMatrixType>
+ void computeRotationScaling(RotationMatrixType *rotation, ScalingMatrixType *scaling) const;
+ template<typename ScalingMatrixType, typename RotationMatrixType>
+ void computeScalingRotation(ScalingMatrixType *scaling, RotationMatrixType *rotation) const;
+
+ template<typename PositionDerived, typename OrientationType, typename ScaleDerived>
+ Transform& fromPositionOrientationScale(const MatrixBase<PositionDerived> &position,
+ const OrientationType& orientation, const MatrixBase<ScaleDerived> &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<typename NewScalarType>
+ inline typename internal::cast_return_type<Transform,Transform<NewScalarType,Dim> >::type cast() const
+ { return typename internal::cast_return_type<Transform,Transform<NewScalarType,Dim> >::type(*this); }
+
+ /** Copy constructor with scalar type conversion */
+ template<typename OtherScalarType>
+ inline explicit Transform(const Transform<OtherScalarType,Dim>& other)
+ { m_matrix = other.matrix().template cast<Scalar>(); }
+
+ /** \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<Scalar>::Real prec = precision<Scalar>()) const
+ { return m_matrix.isApprox(other.m_matrix, prec); }
+
+ #ifdef EIGEN_TRANSFORM_PLUGIN
+ #include EIGEN_TRANSFORM_PLUGIN
+ #endif
+
+protected:
+
+};
+
+/** \ingroup Geometry_Module */
+typedef Transform<float,2> Transform2f;
+/** \ingroup Geometry_Module */
+typedef Transform<float,3> Transform3f;
+/** \ingroup Geometry_Module */
+typedef Transform<double,2> Transform2d;
+/** \ingroup Geometry_Module */
+typedef Transform<double,3> 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<typename Scalar, int Dim>
+Transform<Scalar,Dim>::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<typename Scalar, int Dim>
+Transform<Scalar,Dim>& Transform<Scalar,Dim>::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<typename Scalar, int Dim>
+QMatrix Transform<Scalar,Dim>::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<typename Scalar, int Dim>
+Transform<Scalar,Dim>::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<typename Scalar, int Dim>
+Transform<Scalar,Dim>& Transform<Scalar,Dim>::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<typename Scalar, int Dim>
+QTransform Transform<Scalar,Dim>::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<typename Scalar, int Dim>
+template<typename OtherDerived>
+Transform<Scalar,Dim>&
+Transform<Scalar,Dim>::scale(const MatrixBase<OtherDerived> &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<typename Scalar, int Dim>
+inline Transform<Scalar,Dim>& Transform<Scalar,Dim>::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<typename Scalar, int Dim>
+template<typename OtherDerived>
+Transform<Scalar,Dim>&
+Transform<Scalar,Dim>::prescale(const MatrixBase<OtherDerived> &other)
+{
+ EIGEN_STATIC_ASSERT_VECTOR_SPECIFIC_SIZE(OtherDerived,int(Dim))
+ m_matrix.template block<Dim,HDim>(0,0) = (other.asDiagonal() * m_matrix.template block<Dim,HDim>(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<typename Scalar, int Dim>
+inline Transform<Scalar,Dim>& Transform<Scalar,Dim>::prescale(Scalar s)
+{
+ m_matrix.template corner<Dim,HDim>(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<typename Scalar, int Dim>
+template<typename OtherDerived>
+Transform<Scalar,Dim>&
+Transform<Scalar,Dim>::translate(const MatrixBase<OtherDerived> &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<typename Scalar, int Dim>
+template<typename OtherDerived>
+Transform<Scalar,Dim>&
+Transform<Scalar,Dim>::pretranslate(const MatrixBase<OtherDerived> &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<typename Scalar, int Dim>
+template<typename RotationType>
+Transform<Scalar,Dim>&
+Transform<Scalar,Dim>::rotate(const RotationType& rotation)
+{
+ linear() *= ei_toRotationMatrix<Scalar,Dim>(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<typename Scalar, int Dim>
+template<typename RotationType>
+Transform<Scalar,Dim>&
+Transform<Scalar,Dim>::prerotate(const RotationType& rotation)
+{
+ m_matrix.template block<Dim,HDim>(0,0) = ei_toRotationMatrix<Scalar,Dim>(rotation)
+ * m_matrix.template block<Dim,HDim>(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<typename Scalar, int Dim>
+Transform<Scalar,Dim>&
+Transform<Scalar,Dim>::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<typename Scalar, int Dim>
+Transform<Scalar,Dim>&
+Transform<Scalar,Dim>::preshear(Scalar sx, Scalar sy)
+{
+ EIGEN_STATIC_ASSERT(int(Dim)==2, YOU_MADE_A_PROGRAMMING_MISTAKE)
+ m_matrix.template block<Dim,HDim>(0,0) = LinearMatrixType(1, sx, sy, 1) * m_matrix.template block<Dim,HDim>(0,0);
+ return *this;
+}
+
+/******************************************************
+*** Scaling, Translation and Rotation compatibility ***
+******************************************************/
+
+template<typename Scalar, int Dim>
+inline Transform<Scalar,Dim>& Transform<Scalar,Dim>::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<typename Scalar, int Dim>
+inline Transform<Scalar,Dim> Transform<Scalar,Dim>::operator*(const TranslationType& t) const
+{
+ Transform res = *this;
+ res.translate(t.vector());
+ return res;
+}
+
+template<typename Scalar, int Dim>
+inline Transform<Scalar,Dim>& Transform<Scalar,Dim>::operator=(const ScalingType& s)
+{
+ m_matrix.setZero();
+ linear().diagonal() = s.coeffs();
+ m_matrix.coeffRef(Dim,Dim) = Scalar(1);
+ return *this;
+}
+
+template<typename Scalar, int Dim>
+inline Transform<Scalar,Dim> Transform<Scalar,Dim>::operator*(const ScalingType& s) const
+{
+ Transform res = *this;
+ res.scale(s.coeffs());
+ return res;
+}
+
+template<typename Scalar, int Dim>
+template<typename Derived>
+inline Transform<Scalar,Dim>& Transform<Scalar,Dim>::operator=(const RotationBase<Derived,Dim>& r)
+{
+ linear() = ei_toRotationMatrix<Scalar,Dim>(r);
+ translation().setZero();
+ m_matrix.template block<1,Dim>(Dim,0).setZero();
+ m_matrix.coeffRef(Dim,Dim) = Scalar(1);
+ return *this;
+}
+
+template<typename Scalar, int Dim>
+template<typename Derived>
+inline Transform<Scalar,Dim> Transform<Scalar,Dim>::operator*(const RotationBase<Derived,Dim>& 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 Scalar, int Dim>
+typename Transform<Scalar,Dim>::LinearMatrixType
+Transform<Scalar,Dim>::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<typename Scalar, int Dim>
+template<typename RotationMatrixType, typename ScalingMatrixType>
+void Transform<Scalar,Dim>::computeRotationScaling(RotationMatrixType *rotation, ScalingMatrixType *scaling) const
+{
+ JacobiSVD<LinearMatrixType> svd(linear(), ComputeFullU|ComputeFullV);
+ Scalar x = (svd.matrixU() * svd.matrixV().adjoint()).determinant(); // so x has absolute value 1
+ Matrix<Scalar, Dim, 1> 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<typename Scalar, int Dim>
+template<typename ScalingMatrixType, typename RotationMatrixType>
+void Transform<Scalar,Dim>::computeScalingRotation(ScalingMatrixType *scaling, RotationMatrixType *rotation) const
+{
+ JacobiSVD<LinearMatrixType> svd(linear(), ComputeFullU|ComputeFullV);
+ Scalar x = (svd.matrixU() * svd.matrixV().adjoint()).determinant(); // so x has absolute value 1
+ Matrix<Scalar, Dim, 1> 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<typename Scalar, int Dim>
+template<typename PositionDerived, typename OrientationType, typename ScaleDerived>
+Transform<Scalar,Dim>&
+Transform<Scalar,Dim>::fromPositionOrientationScale(const MatrixBase<PositionDerived> &position,
+ const OrientationType& orientation, const MatrixBase<ScaleDerived> &scale)
+{
+ linear() = ei_toRotationMatrix<Scalar,Dim>(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<typename Scalar, int Dim>
+inline const typename Transform<Scalar,Dim>::MatrixType
+Transform<Scalar,Dim>::inverse(TransformTraits traits) const
+{
+ if (traits == Projective)
+ {
+ return m_matrix.inverse();
+ }
+ else
+ {
+ MatrixType res;
+ if (traits == Affine)
+ {
+ res.template corner<Dim,Dim>(TopLeft) = linear().inverse();
+ }
+ else if (traits == Isometry)
+ {
+ res.template corner<Dim,Dim>(TopLeft) = linear().transpose();
+ }
+ else
+ {
+ ei_assert("invalid traits value in Transform::inverse()");
+ }
+ // translation and remaining parts
+ res.template corner<Dim,1>(TopRight) = - res.template corner<Dim,Dim>(TopLeft) * translation();
+ res.template corner<1,Dim>(BottomLeft).setZero();
+ res.coeffRef(Dim,Dim) = Scalar(1);
+ return res;
+ }
+}
+
+/*****************************************************
+*** Specializations of operator* with a MatrixBase ***
+*****************************************************/
+
+template<typename Other, int Dim, int HDim>
+struct ei_transform_product_impl<Other,Dim,HDim, HDim,HDim>
+{
+ typedef Transform<typename Other::Scalar,Dim> TransformType;
+ typedef typename TransformType::MatrixType MatrixType;
+ typedef typename ProductReturnType<MatrixType,Other>::Type ResultType;
+ static ResultType run(const TransformType& tr, const Other& other)
+ { return tr.matrix() * other; }
+};
+
+template<typename Other, int Dim, int HDim>
+struct ei_transform_product_impl<Other,Dim,HDim, Dim,Dim>
+{
+ typedef Transform<typename Other::Scalar,Dim> 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<typename Other, int Dim, int HDim>
+struct ei_transform_product_impl<Other,Dim,HDim, HDim,1>
+{
+ typedef Transform<typename Other::Scalar,Dim> TransformType;
+ typedef typename TransformType::MatrixType MatrixType;
+ typedef typename ProductReturnType<MatrixType,Other>::Type ResultType;
+ static ResultType run(const TransformType& tr, const Other& other)
+ { return tr.matrix() * other; }
+};
+
+template<typename Other, int Dim, int HDim>
+struct ei_transform_product_impl<Other,Dim,HDim, Dim,1>
+{
+ typedef typename Other::Scalar Scalar;
+ typedef Transform<Scalar,Dim> TransformType;
+ typedef Matrix<Scalar,Dim,1> 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/Eigen/src/Eigen2Support/Geometry/Translation.h b/Eigen/src/Eigen2Support/Geometry/Translation.h
new file mode 100644
index 000000000..0fb9a9f9a
--- /dev/null
+++ b/Eigen/src/Eigen2Support/Geometry/Translation.h
@@ -0,0 +1,184 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra. Eigen itself is part of the KDE project.
+//
+// Copyright (C) 2008 Gael Guennebaud <g.gael@free.fr>
+//
+// This Source Code Form is subject to the terms of the Mozilla
+// Public License v. 2.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<typename _Scalar, int _Dim>
+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<Scalar,Dim,1> VectorType;
+ /** corresponding linear transformation matrix type */
+ typedef Matrix<Scalar,Dim,Dim> LinearMatrixType;
+ /** corresponding scaling transformation type */
+ typedef Scaling<Scalar,Dim> ScalingType;
+ /** corresponding affine transformation type */
+ typedef Transform<Scalar,Dim> 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<typename Derived>
+ inline TransformType operator*(const RotationBase<Derived,Dim>& 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<typename NewScalarType>
+ inline typename internal::cast_return_type<Translation,Translation<NewScalarType,Dim> >::type cast() const
+ { return typename internal::cast_return_type<Translation,Translation<NewScalarType,Dim> >::type(*this); }
+
+ /** Copy constructor with scalar type conversion */
+ template<typename OtherScalarType>
+ inline explicit Translation(const Translation<OtherScalarType,Dim>& other)
+ { m_coeffs = other.vector().template cast<Scalar>(); }
+
+ /** \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<Scalar>::Real prec = precision<Scalar>()) const
+ { return m_coeffs.isApprox(other.m_coeffs, prec); }
+
+};
+
+/** \addtogroup Geometry_Module */
+//@{
+typedef Translation<float, 2> Translation2f;
+typedef Translation<double,2> Translation2d;
+typedef Translation<float, 3> Translation3f;
+typedef Translation<double,3> Translation3d;
+//@}
+
+
+template<typename Scalar, int Dim>
+inline typename Translation<Scalar,Dim>::TransformType
+Translation<Scalar,Dim>::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<typename Scalar, int Dim>
+inline typename Translation<Scalar,Dim>::TransformType
+Translation<Scalar,Dim>::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<typename Scalar, int Dim>
+inline typename Translation<Scalar,Dim>::TransformType
+Translation<Scalar,Dim>::operator* (const TransformType& t) const
+{
+ TransformType res = t;
+ res.pretranslate(m_coeffs);
+ return res;
+}
+
+} // end namespace Eigen
diff --git a/Eigen/src/Eigen2Support/LU.h b/Eigen/src/Eigen2Support/LU.h
new file mode 100644
index 000000000..49f19ad76
--- /dev/null
+++ b/Eigen/src/Eigen2Support/LU.h
@@ -0,0 +1,120 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra.
+//
+// Copyright (C) 2011 Benoit Jacob <jacob.benoit.1@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 EIGEN2_LU_H
+#define EIGEN2_LU_H
+
+namespace Eigen {
+
+template<typename MatrixType>
+class LU : public FullPivLU<MatrixType>
+{
+ public:
+
+ typedef typename MatrixType::Scalar Scalar;
+ typedef typename NumTraits<typename MatrixType::Scalar>::Real RealScalar;
+ typedef Matrix<int, 1, MatrixType::ColsAtCompileTime, MatrixType::Options, 1, MatrixType::MaxColsAtCompileTime> IntRowVectorType;
+ typedef Matrix<int, MatrixType::RowsAtCompileTime, 1, MatrixType::Options, MatrixType::MaxRowsAtCompileTime, 1> IntColVectorType;
+ typedef Matrix<Scalar, 1, MatrixType::ColsAtCompileTime, MatrixType::Options, 1, MatrixType::MaxColsAtCompileTime> RowVectorType;
+ typedef Matrix<Scalar, MatrixType::RowsAtCompileTime, 1, MatrixType::Options, MatrixType::MaxRowsAtCompileTime, 1> ColVectorType;
+
+ typedef Matrix<typename MatrixType::Scalar,
+ MatrixType::ColsAtCompileTime, // the number of rows in the "kernel matrix" is the number of cols of the original matrix
+ // so that the product "matrix * kernel = zero" makes sense
+ Dynamic, // we don't know at compile-time the dimension of the kernel
+ MatrixType::Options,
+ MatrixType::MaxColsAtCompileTime, // see explanation for 2nd template parameter
+ MatrixType::MaxColsAtCompileTime // the kernel is a subspace of the domain space, whose dimension is the number
+ // of columns of the original matrix
+ > KernelResultType;
+
+ typedef Matrix<typename MatrixType::Scalar,
+ MatrixType::RowsAtCompileTime, // the image is a subspace of the destination space, whose dimension is the number
+ // of rows of the original matrix
+ Dynamic, // we don't know at compile time the dimension of the image (the rank)
+ MatrixType::Options,
+ MatrixType::MaxRowsAtCompileTime, // the image matrix will consist of columns from the original matrix,
+ MatrixType::MaxColsAtCompileTime // so it has the same number of rows and at most as many columns.
+ > ImageResultType;
+
+ typedef FullPivLU<MatrixType> Base;
+
+ template<typename T>
+ explicit LU(const T& t) : Base(t), m_originalMatrix(t) {}
+
+ template<typename OtherDerived, typename ResultType>
+ bool solve(const MatrixBase<OtherDerived>& b, ResultType *result) const
+ {
+ *result = static_cast<const Base*>(this)->solve(b);
+ return true;
+ }
+
+ template<typename ResultType>
+ inline void computeInverse(ResultType *result) const
+ {
+ solve(MatrixType::Identity(this->rows(), this->cols()), result);
+ }
+
+ template<typename KernelMatrixType>
+ void computeKernel(KernelMatrixType *result) const
+ {
+ *result = static_cast<const Base*>(this)->kernel();
+ }
+
+ template<typename ImageMatrixType>
+ void computeImage(ImageMatrixType *result) const
+ {
+ *result = static_cast<const Base*>(this)->image(m_originalMatrix);
+ }
+
+ const ImageResultType image() const
+ {
+ return static_cast<const Base*>(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<typename Derived>
+inline const LU<typename MatrixBase<Derived>::PlainObject>
+MatrixBase<Derived>::lu() const
+{
+ return LU<PlainObject>(eval());
+}
+#endif
+
+#ifdef EIGEN2_SUPPORT
+/** \lu_module
+ *
+ * Synonym of partialPivLu().
+ *
+ * \return the partial-pivoting LU decomposition of \c *this.
+ *
+ * \sa class PartialPivLU
+ */
+template<typename Derived>
+inline const LU<typename MatrixBase<Derived>::PlainObject>
+MatrixBase<Derived>::eigen2_lu() const
+{
+ return LU<PlainObject>(eval());
+}
+#endif
+
+} // end namespace Eigen
+
+#endif // EIGEN2_LU_H
diff --git a/Eigen/src/Eigen2Support/Lazy.h b/Eigen/src/Eigen2Support/Lazy.h
new file mode 100644
index 000000000..593fc78e6
--- /dev/null
+++ b/Eigen/src/Eigen2Support/Lazy.h
@@ -0,0 +1,71 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra.
+//
+// Copyright (C) 2008 Benoit Jacob <jacob.benoit.1@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 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<typename Derived>
+template<unsigned int Added>
+inline const Flagged<Derived, Added, 0>
+MatrixBase<Derived>::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<typename Derived>
+inline const Flagged<Derived, 0, EvalBeforeAssigningBit>
+MatrixBase<Derived>::lazy() const
+{
+ return derived();
+}
+
+
+/** \internal
+ * Overloaded to perform an efficient C += (A*B).lazy() */
+template<typename Derived>
+template<typename ProductDerived, typename Lhs, typename Rhs>
+Derived& MatrixBase<Derived>::operator+=(const Flagged<ProductBase<ProductDerived, Lhs,Rhs>, 0,
+ EvalBeforeAssigningBit>& other)
+{
+ other._expression().derived().addTo(derived()); return derived();
+}
+
+/** \internal
+ * Overloaded to perform an efficient C -= (A*B).lazy() */
+template<typename Derived>
+template<typename ProductDerived, typename Lhs, typename Rhs>
+Derived& MatrixBase<Derived>::operator-=(const Flagged<ProductBase<ProductDerived, Lhs,Rhs>, 0,
+ EvalBeforeAssigningBit>& other)
+{
+ other._expression().derived().subTo(derived()); return derived();
+}
+
+} // end namespace Eigen
+
+#endif // EIGEN_LAZY_H
diff --git a/Eigen/src/Eigen2Support/LeastSquares.h b/Eigen/src/Eigen2Support/LeastSquares.h
new file mode 100644
index 000000000..7aff428dc
--- /dev/null
+++ b/Eigen/src/Eigen2Support/LeastSquares.h
@@ -0,0 +1,170 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra. Eigen itself is part of the KDE project.
+//
+// Copyright (C) 2006-2009 Benoit Jacob <jacob.benoit.1@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 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<typename VectorType>
+void linearRegression(int numPoints,
+ VectorType **points,
+ VectorType *result,
+ int funcOfOthers )
+{
+ typedef typename VectorType::Scalar Scalar;
+ typedef Hyperplane<Scalar, VectorType::SizeAtCompileTime> 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<typename VectorType, typename HyperplaneType>
+void fitHyperplane(int numPoints,
+ VectorType **points,
+ HyperplaneType *result,
+ typename NumTraits<typename VectorType::Scalar>::Real* soundness = 0)
+{
+ typedef typename VectorType::Scalar Scalar;
+ typedef Matrix<Scalar,VectorType::SizeAtCompileTime,VectorType::SizeAtCompileTime> 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);
+ VectorType remean = VectorType::Zero(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<CovMatrixType> 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/Eigen/src/Eigen2Support/Macros.h b/Eigen/src/Eigen2Support/Macros.h
new file mode 100644
index 000000000..351c32afb
--- /dev/null
+++ b/Eigen/src/Eigen2Support/Macros.h
@@ -0,0 +1,20 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra.
+//
+// Copyright (C) 2011 Benoit Jacob <jacob.benoit.1@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 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/Eigen/src/Eigen2Support/MathFunctions.h b/Eigen/src/Eigen2Support/MathFunctions.h
new file mode 100644
index 000000000..3a8a9ca81
--- /dev/null
+++ b/Eigen/src/Eigen2Support/MathFunctions.h
@@ -0,0 +1,57 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra.
+//
+// Copyright (C) 2010 Gael Guennebaud <gael.guennebaud@inria.fr>
+//
+// This Source Code Form is subject to the terms of the Mozilla
+// Public License v. 2.0. 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<typename T> inline typename NumTraits<T>::Real ei_real(const T& x) { return internal::real(x); }
+template<typename T> inline typename NumTraits<T>::Real ei_imag(const T& x) { return internal::imag(x); }
+template<typename T> inline T ei_conj(const T& x) { return internal::conj(x); }
+template<typename T> inline typename NumTraits<T>::Real ei_abs (const T& x) { return internal::abs(x); }
+template<typename T> inline typename NumTraits<T>::Real ei_abs2(const T& x) { return internal::abs2(x); }
+template<typename T> inline T ei_sqrt(const T& x) { return internal::sqrt(x); }
+template<typename T> inline T ei_exp (const T& x) { return internal::exp(x); }
+template<typename T> inline T ei_log (const T& x) { return internal::log(x); }
+template<typename T> inline T ei_sin (const T& x) { return internal::sin(x); }
+template<typename T> inline T ei_cos (const T& x) { return internal::cos(x); }
+template<typename T> inline T ei_atan2(const T& x,const T& y) { return internal::atan2(x,y); }
+template<typename T> inline T ei_pow (const T& x,const T& y) { return internal::pow(x,y); }
+template<typename T> inline T ei_random () { return internal::random<T>(); }
+template<typename T> inline T ei_random (const T& x, const T& y) { return internal::random(x, y); }
+
+template<typename T> inline T precision () { return NumTraits<T>::dummy_precision(); }
+template<typename T> inline T machine_epsilon () { return NumTraits<T>::epsilon(); }
+
+
+template<typename Scalar, typename OtherScalar>
+inline bool ei_isMuchSmallerThan(const Scalar& x, const OtherScalar& y,
+ typename NumTraits<Scalar>::Real precision = NumTraits<Scalar>::dummy_precision())
+{
+ return internal::isMuchSmallerThan(x, y, precision);
+}
+
+template<typename Scalar>
+inline bool ei_isApprox(const Scalar& x, const Scalar& y,
+ typename NumTraits<Scalar>::Real precision = NumTraits<Scalar>::dummy_precision())
+{
+ return internal::isApprox(x, y, precision);
+}
+
+template<typename Scalar>
+inline bool ei_isApproxOrLessThan(const Scalar& x, const Scalar& y,
+ typename NumTraits<Scalar>::Real precision = NumTraits<Scalar>::dummy_precision())
+{
+ return internal::isApproxOrLessThan(x, y, precision);
+}
+
+} // end namespace Eigen
+
+#endif // EIGEN2_MATH_FUNCTIONS_H
diff --git a/Eigen/src/Eigen2Support/Memory.h b/Eigen/src/Eigen2Support/Memory.h
new file mode 100644
index 000000000..f86372b6b
--- /dev/null
+++ b/Eigen/src/Eigen2Support/Memory.h
@@ -0,0 +1,45 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra.
+//
+// Copyright (C) 2011 Benoit Jacob <jacob.benoit.1@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 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<bool Align> inline void* ei_conditional_aligned_malloc(size_t size)
+{
+ return internal::conditional_aligned_malloc<Align>(size);
+}
+template<bool Align> inline void ei_conditional_aligned_free(void *ptr)
+{
+ internal::conditional_aligned_free<Align>(ptr);
+}
+template<bool Align> inline void* ei_conditional_aligned_realloc(void* ptr, size_t new_size, size_t old_size)
+{
+ return internal::conditional_aligned_realloc<Align>(ptr, new_size, old_size);
+}
+
+template<typename T> inline T* ei_aligned_new(size_t size)
+{
+ return internal::aligned_new<T>(size);
+}
+template<typename T> 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/Eigen/src/Eigen2Support/Meta.h b/Eigen/src/Eigen2Support/Meta.h
new file mode 100644
index 000000000..fa37cfc96
--- /dev/null
+++ b/Eigen/src/Eigen2Support/Meta.h
@@ -0,0 +1,75 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra.
+//
+// Copyright (C) 2011 Benoit Jacob <jacob.benoit.1@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 EIGEN2_META_H
+#define EIGEN2_META_H
+
+namespace Eigen {
+
+template<typename T>
+struct ei_traits : internal::traits<T>
+{};
+
+struct ei_meta_true { enum { ret = 1 }; };
+struct ei_meta_false { enum { ret = 0 }; };
+
+template<bool Condition, typename Then, typename Else>
+struct ei_meta_if { typedef Then ret; };
+
+template<typename Then, typename Else>
+struct ei_meta_if <false, Then, Else> { typedef Else ret; };
+
+template<typename T, typename U> struct ei_is_same_type { enum { ret = 0 }; };
+template<typename T> struct ei_is_same_type<T,T> { enum { ret = 1 }; };
+
+template<typename T> struct ei_unref { typedef T type; };
+template<typename T> struct ei_unref<T&> { typedef T type; };
+
+template<typename T> struct ei_unpointer { typedef T type; };
+template<typename T> struct ei_unpointer<T*> { typedef T type; };
+template<typename T> struct ei_unpointer<T*const> { typedef T type; };
+
+template<typename T> struct ei_unconst { typedef T type; };
+template<typename T> struct ei_unconst<const T> { typedef T type; };
+template<typename T> struct ei_unconst<T const &> { typedef T & type; };
+template<typename T> struct ei_unconst<T const *> { typedef T * type; };
+
+template<typename T> struct ei_cleantype { typedef T type; };
+template<typename T> struct ei_cleantype<const T> { typedef typename ei_cleantype<T>::type type; };
+template<typename T> struct ei_cleantype<const T&> { typedef typename ei_cleantype<T>::type type; };
+template<typename T> struct ei_cleantype<T&> { typedef typename ei_cleantype<T>::type type; };
+template<typename T> struct ei_cleantype<const T*> { typedef typename ei_cleantype<T>::type type; };
+template<typename T> struct ei_cleantype<T*> { typedef typename ei_cleantype<T>::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<int Y,
+ int InfX = 0,
+ int SupX = ((Y==1) ? 1 : Y/2),
+ bool Done = ((SupX-InfX)<=1 ? true : ((SupX*SupX <= Y) && ((SupX+1)*(SupX+1) > 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<Y,NewInf,NewSup>::ret };
+};
+
+template<int Y, int InfX, int SupX>
+class ei_meta_sqrt<Y, InfX, SupX, true> { public: enum { ret = (SupX*SupX <= Y) ? SupX : InfX }; };
+
+} // end namespace Eigen
+
+#endif // EIGEN2_META_H
diff --git a/Eigen/src/Eigen2Support/Minor.h b/Eigen/src/Eigen2Support/Minor.h
new file mode 100644
index 000000000..4cded5734
--- /dev/null
+++ b/Eigen/src/Eigen2Support/Minor.h
@@ -0,0 +1,117 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra.
+//
+// Copyright (C) 2006-2009 Benoit Jacob <jacob.benoit.1@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 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<typename MatrixType>
+struct traits<Minor<MatrixType> >
+ : traits<MatrixType>
+{
+ typedef typename nested<MatrixType>::type MatrixTypeNested;
+ typedef typename remove_reference<MatrixTypeNested>::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<typename MatrixType> class Minor
+ : public MatrixBase<Minor<MatrixType> >
+{
+ public:
+
+ typedef MatrixBase<Minor> 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<typename Derived>
+inline Minor<Derived>
+MatrixBase<Derived>::minor(Index row, Index col)
+{
+ return Minor<Derived>(derived(), row, col);
+}
+
+/**
+ * This is the const version of minor(). */
+template<typename Derived>
+inline const Minor<Derived>
+MatrixBase<Derived>::minor(Index row, Index col) const
+{
+ return Minor<Derived>(derived(), row, col);
+}
+
+} // end namespace Eigen
+
+#endif // EIGEN_MINOR_H
diff --git a/Eigen/src/Eigen2Support/QR.h b/Eigen/src/Eigen2Support/QR.h
new file mode 100644
index 000000000..2042c9851
--- /dev/null
+++ b/Eigen/src/Eigen2Support/QR.h
@@ -0,0 +1,67 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra.
+//
+// Copyright (C) 2008 Gael Guennebaud <g.gael@free.fr>
+// Copyright (C) 2011 Benoit Jacob <jacob.benoit.1@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 EIGEN2_QR_H
+#define EIGEN2_QR_H
+
+namespace Eigen {
+
+template<typename MatrixType>
+class QR : public HouseholderQR<MatrixType>
+{
+ public:
+
+ typedef HouseholderQR<MatrixType> Base;
+ typedef Block<const MatrixType, MatrixType::ColsAtCompileTime, MatrixType::ColsAtCompileTime> MatrixRBlockType;
+
+ QR() : Base() {}
+
+ template<typename T>
+ explicit QR(const T& t) : Base(t) {}
+
+ template<typename OtherDerived, typename ResultType>
+ bool solve(const MatrixBase<OtherDerived>& b, ResultType *result) const
+ {
+ *result = static_cast<const Base*>(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<MatrixRBlockType, UpperTriangular>
+ matrixR(void) const
+ {
+ int cols = this->cols();
+ return MatrixRBlockType(this->matrixQR(), 0, 0, cols, cols).template triangularView<UpperTriangular>();
+ }
+};
+
+/** \return the QR decomposition of \c *this.
+ *
+ * \sa class QR
+ */
+template<typename Derived>
+const QR<typename MatrixBase<Derived>::PlainObject>
+MatrixBase<Derived>::qr() const
+{
+ return QR<PlainObject>(eval());
+}
+
+} // end namespace Eigen
+
+#endif // EIGEN2_QR_H
diff --git a/Eigen/src/Eigen2Support/SVD.h b/Eigen/src/Eigen2Support/SVD.h
new file mode 100644
index 000000000..3d2eeb445
--- /dev/null
+++ b/Eigen/src/Eigen2Support/SVD.h
@@ -0,0 +1,638 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra. Eigen itself is part of the KDE project.
+//
+// Copyright (C) 2008 Gael Guennebaud <g.gael@free.fr>
+//
+// This Source Code Form is subject to the terms of the Mozilla
+// Public License v. 2.0. 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<typename MatrixType> class SVD
+{
+ private:
+ typedef typename MatrixType::Scalar Scalar;
+ typedef typename NumTraits<typename MatrixType::Scalar>::Real RealScalar;
+
+ enum {
+ PacketSize = internal::packet_traits<Scalar>::size,
+ AlignmentMask = int(PacketSize)-1,
+ MinSize = EIGEN_SIZE_MIN_PREFER_DYNAMIC(MatrixType::RowsAtCompileTime, MatrixType::ColsAtCompileTime)
+ };
+
+ typedef Matrix<Scalar, MatrixType::RowsAtCompileTime, 1> ColVector;
+ typedef Matrix<Scalar, MatrixType::ColsAtCompileTime, 1> RowVector;
+
+ typedef Matrix<Scalar, MatrixType::RowsAtCompileTime, MinSize> MatrixUType;
+ typedef Matrix<Scalar, MatrixType::ColsAtCompileTime, MatrixType::ColsAtCompileTime> MatrixVType;
+ typedef Matrix<Scalar, MinSize, 1> 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<typename OtherDerived, typename ResultType>
+ bool solve(const MatrixBase<OtherDerived> &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<typename UnitaryType, typename PositiveType>
+ void computeUnitaryPositive(UnitaryType *unitary, PositiveType *positive) const;
+ template<typename PositiveType, typename UnitaryType>
+ void computePositiveUnitary(PositiveType *positive, UnitaryType *unitary) const;
+ template<typename RotationType, typename ScalingType>
+ void computeRotationScaling(RotationType *unitary, ScalingType *positive) const;
+ template<typename ScalingType, typename RotationType>
+ 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<typename MatrixType>
+void SVD<MatrixType>::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<Scalar,float>::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<p
+ // kase = 2 if s(k) is negligible and k<p
+ // kase = 3 if e[k-1] is negligible, k<p, and
+ // s(k), ..., s(p) are not negligible (qr step).
+ // kase = 4 if e(p-1) is negligible (convergence).
+
+ for (k = p-2; 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(internal::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(internal::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 = internal::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 = internal::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<typename MatrixType>
+SVD<MatrixType>& SVD<MatrixType>::sort()
+{
+ int mu = m_matU.rows();
+ int mv = m_matV.rows();
+ int n = m_matU.cols();
+
+ for (int i=0; i<n; ++i)
+ {
+ int k = i;
+ Scalar p = m_sigma.coeff(i);
+
+ for (int j=i+1; j<n; ++j)
+ {
+ if (m_sigma.coeff(j) > 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<typename MatrixType>
+template<typename OtherDerived, typename ResultType>
+bool SVD<MatrixType>::solve(const MatrixBase<OtherDerived> &b, ResultType* result) const
+{
+ const int rows = m_matU.rows();
+ ei_assert(b.rows() == rows);
+
+ Scalar maxVal = m_sigma.cwise().abs().maxCoeff();
+ for (int j=0; j<b.cols(); ++j)
+ {
+ Matrix<Scalar,MatrixUType::RowsAtCompileTime,1> aux = m_matU.transpose() * b.col(j);
+
+ for (int i = 0; i <m_matU.cols(); ++i)
+ {
+ Scalar si = m_sigma.coeff(i);
+ if (ei_isMuchSmallerThan(ei_abs(si),maxVal))
+ aux.coeffRef(i) = 0;
+ else
+ aux.coeffRef(i) /= si;
+ }
+
+ result->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<typename MatrixType>
+template<typename UnitaryType, typename PositiveType>
+void SVD<MatrixType>::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<typename MatrixType>
+template<typename UnitaryType, typename PositiveType>
+void SVD<MatrixType>::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<typename MatrixType>
+template<typename RotationType, typename ScalingType>
+void SVD<MatrixType>::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<Scalar, MatrixType::RowsAtCompileTime, 1> 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<typename MatrixType>
+template<typename ScalingType, typename RotationType>
+void SVD<MatrixType>::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<Scalar, MatrixType::RowsAtCompileTime, 1> 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<typename Derived>
+inline SVD<typename MatrixBase<Derived>::PlainObject>
+MatrixBase<Derived>::svd() const
+{
+ return SVD<PlainObject>(derived());
+}
+
+} // end namespace Eigen
+
+#endif // EIGEN2_SVD_H
diff --git a/Eigen/src/Eigen2Support/TriangularSolver.h b/Eigen/src/Eigen2Support/TriangularSolver.h
new file mode 100644
index 000000000..ebbeb3b49
--- /dev/null
+++ b/Eigen/src/Eigen2Support/TriangularSolver.h
@@ -0,0 +1,42 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra.
+//
+// Copyright (C) 2010 Gael Guennebaud <gael.guennebaud@inria.fr>
+//
+// This Source Code Form is subject to the terms of the Mozilla
+// Public License v. 2.0. If 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<typename ExpressionType, unsigned int Added, unsigned int Removed>
+template<typename OtherDerived>
+typename ExpressionType::PlainObject
+Flagged<ExpressionType,Added,Removed>::solveTriangular(const MatrixBase<OtherDerived>& other) const
+{
+ return m_matrix.template triangularView<Added>().solve(other.derived());
+}
+
+template<typename ExpressionType, unsigned int Added, unsigned int Removed>
+template<typename OtherDerived>
+void Flagged<ExpressionType,Added,Removed>::solveTriangularInPlace(const MatrixBase<OtherDerived>& other) const
+{
+ m_matrix.template triangularView<Added>().solveInPlace(other.derived());
+}
+
+} // end namespace Eigen
+
+#endif // EIGEN_TRIANGULAR_SOLVER2_H
diff --git a/Eigen/src/Eigen2Support/VectorBlock.h b/Eigen/src/Eigen2Support/VectorBlock.h
new file mode 100644
index 000000000..71a8080a9
--- /dev/null
+++ b/Eigen/src/Eigen2Support/VectorBlock.h
@@ -0,0 +1,94 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra.
+//
+// Copyright (C) 2008-2009 Gael Guennebaud <gael.guennebaud@inria.fr>
+// Copyright (C) 2006-2008 Benoit Jacob <jacob.benoit.1@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 EIGEN2_VECTORBLOCK_H
+#define EIGEN2_VECTORBLOCK_H
+
+namespace Eigen {
+
+/** \deprecated use DenseMase::head(Index) */
+template<typename Derived>
+inline VectorBlock<Derived>
+MatrixBase<Derived>::start(Index size)
+{
+ EIGEN_STATIC_ASSERT_VECTOR_ONLY(Derived)
+ return VectorBlock<Derived>(derived(), 0, size);
+}
+
+/** \deprecated use DenseMase::head(Index) */
+template<typename Derived>
+inline const VectorBlock<const Derived>
+MatrixBase<Derived>::start(Index size) const
+{
+ EIGEN_STATIC_ASSERT_VECTOR_ONLY(Derived)
+ return VectorBlock<const Derived>(derived(), 0, size);
+}
+
+/** \deprecated use DenseMase::tail(Index) */
+template<typename Derived>
+inline VectorBlock<Derived>
+MatrixBase<Derived>::end(Index size)
+{
+ EIGEN_STATIC_ASSERT_VECTOR_ONLY(Derived)
+ return VectorBlock<Derived>(derived(), this->size() - size, size);
+}
+
+/** \deprecated use DenseMase::tail(Index) */
+template<typename Derived>
+inline const VectorBlock<const Derived>
+MatrixBase<Derived>::end(Index size) const
+{
+ EIGEN_STATIC_ASSERT_VECTOR_ONLY(Derived)
+ return VectorBlock<const Derived>(derived(), this->size() - size, size);
+}
+
+/** \deprecated use DenseMase::head() */
+template<typename Derived>
+template<int Size>
+inline VectorBlock<Derived,Size>
+MatrixBase<Derived>::start()
+{
+ EIGEN_STATIC_ASSERT_VECTOR_ONLY(Derived)
+ return VectorBlock<Derived,Size>(derived(), 0);
+}
+
+/** \deprecated use DenseMase::head() */
+template<typename Derived>
+template<int Size>
+inline const VectorBlock<const Derived,Size>
+MatrixBase<Derived>::start() const
+{
+ EIGEN_STATIC_ASSERT_VECTOR_ONLY(Derived)
+ return VectorBlock<const Derived,Size>(derived(), 0);
+}
+
+/** \deprecated use DenseMase::tail() */
+template<typename Derived>
+template<int Size>
+inline VectorBlock<Derived,Size>
+MatrixBase<Derived>::end()
+{
+ EIGEN_STATIC_ASSERT_VECTOR_ONLY(Derived)
+ return VectorBlock<Derived, Size>(derived(), size() - Size);
+}
+
+/** \deprecated use DenseMase::tail() */
+template<typename Derived>
+template<int Size>
+inline const VectorBlock<const Derived,Size>
+MatrixBase<Derived>::end() const
+{
+ EIGEN_STATIC_ASSERT_VECTOR_ONLY(Derived)
+ return VectorBlock<const Derived, Size>(derived(), size() - Size);
+}
+
+} // end namespace Eigen
+
+#endif // EIGEN2_VECTORBLOCK_H
diff --git a/Eigen/src/Eigenvalues/CMakeLists.txt b/Eigen/src/Eigenvalues/CMakeLists.txt
new file mode 100644
index 000000000..193e02685
--- /dev/null
+++ b/Eigen/src/Eigenvalues/CMakeLists.txt
@@ -0,0 +1,6 @@
+FILE(GLOB Eigen_EIGENVALUES_SRCS "*.h")
+
+INSTALL(FILES
+ ${Eigen_EIGENVALUES_SRCS}
+ DESTINATION ${INCLUDE_INSTALL_DIR}/Eigen/src/Eigenvalues COMPONENT Devel
+ )
diff --git a/Eigen/src/Eigenvalues/ComplexEigenSolver.h b/Eigen/src/Eigenvalues/ComplexEigenSolver.h
new file mode 100644
index 000000000..c4b8a308c
--- /dev/null
+++ b/Eigen/src/Eigenvalues/ComplexEigenSolver.h
@@ -0,0 +1,319 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra.
+//
+// Copyright (C) 2009 Claire Maurice
+// Copyright (C) 2009 Gael Guennebaud <gael.guennebaud@inria.fr>
+// Copyright (C) 2010 Jitse Niesen <jitse@maths.leeds.ac.uk>
+//
+// This Source Code Form is subject to the terms of the Mozilla
+// Public License v. 2.0. If a copy of the MPL was not distributed
+// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+#ifndef EIGEN_COMPLEX_EIGEN_SOLVER_H
+#define EIGEN_COMPLEX_EIGEN_SOLVER_H
+
+#include "./ComplexSchur.h"
+
+namespace Eigen {
+
+/** \eigenvalues_module \ingroup Eigenvalues_Module
+ *
+ *
+ * \class ComplexEigenSolver
+ *
+ * \brief Computes eigenvalues and eigenvectors of general complex matrices
+ *
+ * \tparam _MatrixType the type of the matrix of which we are
+ * computing the eigendecomposition; this is expected to be an
+ * instantiation of the Matrix class template.
+ *
+ * The eigenvalues and eigenvectors of a matrix \f$ A \f$ are scalars
+ * \f$ \lambda \f$ and vectors \f$ v \f$ such that \f$ Av = \lambda v
+ * \f$. If \f$ D \f$ is a diagonal matrix with the eigenvalues on
+ * the diagonal, and \f$ V \f$ is a matrix with the eigenvectors as
+ * its columns, then \f$ A V = V D \f$. The matrix \f$ V \f$ is
+ * almost always invertible, in which case we have \f$ A = V D V^{-1}
+ * \f$. This is called the eigendecomposition.
+ *
+ * The main function in this class is compute(), which computes the
+ * eigenvalues and eigenvectors of a given function. The
+ * documentation for that function contains an example showing the
+ * main features of the class.
+ *
+ * \sa class EigenSolver, class SelfAdjointEigenSolver
+ */
+template<typename _MatrixType> class ComplexEigenSolver
+{
+ public:
+
+ /** \brief Synonym for the template parameter \p _MatrixType. */
+ typedef _MatrixType MatrixType;
+
+ enum {
+ RowsAtCompileTime = MatrixType::RowsAtCompileTime,
+ ColsAtCompileTime = MatrixType::ColsAtCompileTime,
+ Options = MatrixType::Options,
+ MaxRowsAtCompileTime = MatrixType::MaxRowsAtCompileTime,
+ MaxColsAtCompileTime = MatrixType::MaxColsAtCompileTime
+ };
+
+ /** \brief Scalar type for matrices of type #MatrixType. */
+ typedef typename MatrixType::Scalar Scalar;
+ typedef typename NumTraits<Scalar>::Real RealScalar;
+ typedef typename MatrixType::Index Index;
+
+ /** \brief Complex scalar type for #MatrixType.
+ *
+ * This is \c std::complex<Scalar> if #Scalar is real (e.g.,
+ * \c float or \c double) and just \c Scalar if #Scalar is
+ * complex.
+ */
+ typedef std::complex<RealScalar> ComplexScalar;
+
+ /** \brief Type for vector of eigenvalues as returned by eigenvalues().
+ *
+ * This is a column vector with entries of type #ComplexScalar.
+ * The length of the vector is the size of #MatrixType.
+ */
+ typedef Matrix<ComplexScalar, ColsAtCompileTime, 1, Options&(~RowMajor), MaxColsAtCompileTime, 1> EigenvalueType;
+
+ /** \brief Type for matrix of eigenvectors as returned by eigenvectors().
+ *
+ * This is a square matrix with entries of type #ComplexScalar.
+ * The size is the same as the size of #MatrixType.
+ */
+ typedef Matrix<ComplexScalar, RowsAtCompileTime, ColsAtCompileTime, Options, MaxRowsAtCompileTime, MaxColsAtCompileTime> EigenvectorType;
+
+ /** \brief Default constructor.
+ *
+ * The default constructor is useful in cases in which the user intends to
+ * perform decompositions via compute().
+ */
+ ComplexEigenSolver()
+ : m_eivec(),
+ m_eivalues(),
+ m_schur(),
+ m_isInitialized(false),
+ m_eigenvectorsOk(false),
+ m_matX()
+ {}
+
+ /** \brief Default Constructor with memory preallocation
+ *
+ * Like the default constructor but with preallocation of the internal data
+ * according to the specified problem \a size.
+ * \sa ComplexEigenSolver()
+ */
+ ComplexEigenSolver(Index size)
+ : m_eivec(size, size),
+ m_eivalues(size),
+ m_schur(size),
+ m_isInitialized(false),
+ m_eigenvectorsOk(false),
+ m_matX(size, size)
+ {}
+
+ /** \brief Constructor; computes eigendecomposition of given matrix.
+ *
+ * \param[in] matrix Square matrix whose eigendecomposition is to be computed.
+ * \param[in] computeEigenvectors If true, both the eigenvectors and the
+ * eigenvalues are computed; if false, only the eigenvalues are
+ * computed.
+ *
+ * This constructor calls compute() to compute the eigendecomposition.
+ */
+ ComplexEigenSolver(const MatrixType& matrix, bool computeEigenvectors = true)
+ : m_eivec(matrix.rows(),matrix.cols()),
+ m_eivalues(matrix.cols()),
+ m_schur(matrix.rows()),
+ m_isInitialized(false),
+ m_eigenvectorsOk(false),
+ m_matX(matrix.rows(),matrix.cols())
+ {
+ compute(matrix, computeEigenvectors);
+ }
+
+ /** \brief Returns the eigenvectors of given matrix.
+ *
+ * \returns A const reference to the matrix whose columns are the eigenvectors.
+ *
+ * \pre Either the constructor
+ * ComplexEigenSolver(const MatrixType& matrix, bool) or the member
+ * function compute(const MatrixType& matrix, bool) has been called before
+ * to compute the eigendecomposition of a matrix, and
+ * \p computeEigenvectors was set to true (the default).
+ *
+ * This function returns a matrix whose columns are the eigenvectors. Column
+ * \f$ k \f$ is an eigenvector corresponding to eigenvalue number \f$ k
+ * \f$ as returned by eigenvalues(). The eigenvectors are normalized to
+ * have (Euclidean) norm equal to one. The matrix returned by this
+ * function is the matrix \f$ V \f$ in the eigendecomposition \f$ A = V D
+ * V^{-1} \f$, if it exists.
+ *
+ * Example: \include ComplexEigenSolver_eigenvectors.cpp
+ * Output: \verbinclude ComplexEigenSolver_eigenvectors.out
+ */
+ const EigenvectorType& eigenvectors() const
+ {
+ eigen_assert(m_isInitialized && "ComplexEigenSolver is not initialized.");
+ eigen_assert(m_eigenvectorsOk && "The eigenvectors have not been computed together with the eigenvalues.");
+ return m_eivec;
+ }
+
+ /** \brief Returns the eigenvalues of given matrix.
+ *
+ * \returns A const reference to the column vector containing the eigenvalues.
+ *
+ * \pre Either the constructor
+ * ComplexEigenSolver(const MatrixType& matrix, bool) or the member
+ * function compute(const MatrixType& matrix, bool) has been called before
+ * to compute the eigendecomposition of a matrix.
+ *
+ * This function returns a column vector containing the
+ * eigenvalues. Eigenvalues are repeated according to their
+ * algebraic multiplicity, so there are as many eigenvalues as
+ * rows in the matrix. The eigenvalues are not sorted in any particular
+ * order.
+ *
+ * Example: \include ComplexEigenSolver_eigenvalues.cpp
+ * Output: \verbinclude ComplexEigenSolver_eigenvalues.out
+ */
+ const EigenvalueType& eigenvalues() const
+ {
+ eigen_assert(m_isInitialized && "ComplexEigenSolver is not initialized.");
+ return m_eivalues;
+ }
+
+ /** \brief Computes eigendecomposition of given matrix.
+ *
+ * \param[in] matrix Square matrix whose eigendecomposition is to be computed.
+ * \param[in] computeEigenvectors If true, both the eigenvectors and the
+ * eigenvalues are computed; if false, only the eigenvalues are
+ * computed.
+ * \returns Reference to \c *this
+ *
+ * This function computes the eigenvalues of the complex matrix \p matrix.
+ * The eigenvalues() function can be used to retrieve them. If
+ * \p computeEigenvectors is true, then the eigenvectors are also computed
+ * and can be retrieved by calling eigenvectors().
+ *
+ * The matrix is first reduced to Schur form using the
+ * ComplexSchur class. The Schur decomposition is then used to
+ * compute the eigenvalues and eigenvectors.
+ *
+ * The cost of the computation is dominated by the cost of the
+ * Schur decomposition, which is \f$ O(n^3) \f$ where \f$ n \f$
+ * is the size of the matrix.
+ *
+ * Example: \include ComplexEigenSolver_compute.cpp
+ * Output: \verbinclude ComplexEigenSolver_compute.out
+ */
+ ComplexEigenSolver& compute(const MatrixType& matrix, bool computeEigenvectors = true);
+
+ /** \brief Reports whether previous computation was successful.
+ *
+ * \returns \c Success if computation was succesful, \c NoConvergence otherwise.
+ */
+ ComputationInfo info() const
+ {
+ eigen_assert(m_isInitialized && "ComplexEigenSolver is not initialized.");
+ return m_schur.info();
+ }
+
+ protected:
+ EigenvectorType m_eivec;
+ EigenvalueType m_eivalues;
+ ComplexSchur<MatrixType> m_schur;
+ bool m_isInitialized;
+ bool m_eigenvectorsOk;
+ EigenvectorType m_matX;
+
+ private:
+ void doComputeEigenvectors(RealScalar matrixnorm);
+ void sortEigenvalues(bool computeEigenvectors);
+};
+
+
+template<typename MatrixType>
+ComplexEigenSolver<MatrixType>& ComplexEigenSolver<MatrixType>::compute(const MatrixType& matrix, bool computeEigenvectors)
+{
+ // this code is inspired from Jampack
+ assert(matrix.cols() == matrix.rows());
+
+ // Do a complex Schur decomposition, A = U T U^*
+ // The eigenvalues are on the diagonal of T.
+ m_schur.compute(matrix, computeEigenvectors);
+
+ if(m_schur.info() == Success)
+ {
+ m_eivalues = m_schur.matrixT().diagonal();
+ if(computeEigenvectors)
+ doComputeEigenvectors(matrix.norm());
+ sortEigenvalues(computeEigenvectors);
+ }
+
+ m_isInitialized = true;
+ m_eigenvectorsOk = computeEigenvectors;
+ return *this;
+}
+
+
+template<typename MatrixType>
+void ComplexEigenSolver<MatrixType>::doComputeEigenvectors(RealScalar matrixnorm)
+{
+ const Index n = m_eivalues.size();
+
+ // Compute X such that T = X D X^(-1), where D is the diagonal of T.
+ // The matrix X is unit triangular.
+ m_matX = EigenvectorType::Zero(n, n);
+ for(Index k=n-1 ; k>=0 ; k--)
+ {
+ m_matX.coeffRef(k,k) = ComplexScalar(1.0,0.0);
+ // Compute X(i,k) using the (i,k) entry of the equation X T = D X
+ for(Index i=k-1 ; i>=0 ; i--)
+ {
+ m_matX.coeffRef(i,k) = -m_schur.matrixT().coeff(i,k);
+ if(k-i-1>0)
+ m_matX.coeffRef(i,k) -= (m_schur.matrixT().row(i).segment(i+1,k-i-1) * m_matX.col(k).segment(i+1,k-i-1)).value();
+ ComplexScalar z = m_schur.matrixT().coeff(i,i) - m_schur.matrixT().coeff(k,k);
+ if(z==ComplexScalar(0))
+ {
+ // If the i-th and k-th eigenvalue are equal, then z equals 0.
+ // Use a small value instead, to prevent division by zero.
+ internal::real_ref(z) = NumTraits<RealScalar>::epsilon() * matrixnorm;
+ }
+ m_matX.coeffRef(i,k) = m_matX.coeff(i,k) / z;
+ }
+ }
+
+ // Compute V as V = U X; now A = U T U^* = U X D X^(-1) U^* = V D V^(-1)
+ m_eivec.noalias() = m_schur.matrixU() * m_matX;
+ // .. and normalize the eigenvectors
+ for(Index k=0 ; k<n ; k++)
+ {
+ m_eivec.col(k).normalize();
+ }
+}
+
+
+template<typename MatrixType>
+void ComplexEigenSolver<MatrixType>::sortEigenvalues(bool computeEigenvectors)
+{
+ const Index n = m_eivalues.size();
+ for (Index i=0; i<n; i++)
+ {
+ Index k;
+ m_eivalues.cwiseAbs().tail(n-i).minCoeff(&k);
+ if (k != 0)
+ {
+ k += i;
+ std::swap(m_eivalues[k],m_eivalues[i]);
+ if(computeEigenvectors)
+ m_eivec.col(i).swap(m_eivec.col(k));
+ }
+ }
+}
+
+} // end namespace Eigen
+
+#endif // EIGEN_COMPLEX_EIGEN_SOLVER_H
diff --git a/Eigen/src/Eigenvalues/ComplexSchur.h b/Eigen/src/Eigenvalues/ComplexSchur.h
new file mode 100644
index 000000000..16a9a03d2
--- /dev/null
+++ b/Eigen/src/Eigenvalues/ComplexSchur.h
@@ -0,0 +1,396 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra.
+//
+// Copyright (C) 2009 Claire Maurice
+// Copyright (C) 2009 Gael Guennebaud <gael.guennebaud@inria.fr>
+// Copyright (C) 2010 Jitse Niesen <jitse@maths.leeds.ac.uk>
+//
+// This Source Code Form is subject to the terms of the Mozilla
+// Public License v. 2.0. If a copy of the MPL was not distributed
+// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+#ifndef EIGEN_COMPLEX_SCHUR_H
+#define EIGEN_COMPLEX_SCHUR_H
+
+#include "./HessenbergDecomposition.h"
+
+namespace Eigen {
+
+namespace internal {
+template<typename MatrixType, bool IsComplex> struct complex_schur_reduce_to_hessenberg;
+}
+
+/** \eigenvalues_module \ingroup Eigenvalues_Module
+ *
+ *
+ * \class ComplexSchur
+ *
+ * \brief Performs a complex Schur decomposition of a real or complex square matrix
+ *
+ * \tparam _MatrixType the type of the matrix of which we are
+ * computing the Schur decomposition; this is expected to be an
+ * instantiation of the Matrix class template.
+ *
+ * Given a real or complex square matrix A, this class computes the
+ * Schur decomposition: \f$ A = U T U^*\f$ where U is a unitary
+ * complex matrix, and T is a complex upper triangular matrix. The
+ * diagonal of the matrix T corresponds to the eigenvalues of the
+ * matrix A.
+ *
+ * Call the function compute() to compute the Schur decomposition of
+ * a given matrix. Alternatively, you can use the
+ * ComplexSchur(const MatrixType&, bool) constructor which computes
+ * the Schur decomposition at construction time. Once the
+ * decomposition is computed, you can use the matrixU() and matrixT()
+ * functions to retrieve the matrices U and V in the decomposition.
+ *
+ * \note This code is inspired from Jampack
+ *
+ * \sa class RealSchur, class EigenSolver, class ComplexEigenSolver
+ */
+template<typename _MatrixType> class ComplexSchur
+{
+ public:
+ typedef _MatrixType MatrixType;
+ enum {
+ RowsAtCompileTime = MatrixType::RowsAtCompileTime,
+ ColsAtCompileTime = MatrixType::ColsAtCompileTime,
+ Options = MatrixType::Options,
+ MaxRowsAtCompileTime = MatrixType::MaxRowsAtCompileTime,
+ MaxColsAtCompileTime = MatrixType::MaxColsAtCompileTime
+ };
+
+ /** \brief Scalar type for matrices of type \p _MatrixType. */
+ typedef typename MatrixType::Scalar Scalar;
+ typedef typename NumTraits<Scalar>::Real RealScalar;
+ typedef typename MatrixType::Index Index;
+
+ /** \brief Complex scalar type for \p _MatrixType.
+ *
+ * This is \c std::complex<Scalar> if #Scalar is real (e.g.,
+ * \c float or \c double) and just \c Scalar if #Scalar is
+ * complex.
+ */
+ typedef std::complex<RealScalar> ComplexScalar;
+
+ /** \brief Type for the matrices in the Schur decomposition.
+ *
+ * This is a square matrix with entries of type #ComplexScalar.
+ * The size is the same as the size of \p _MatrixType.
+ */
+ typedef Matrix<ComplexScalar, RowsAtCompileTime, ColsAtCompileTime, Options, MaxRowsAtCompileTime, MaxColsAtCompileTime> ComplexMatrixType;
+
+ /** \brief Default constructor.
+ *
+ * \param [in] size Positive integer, size of the matrix whose Schur decomposition will be computed.
+ *
+ * The default constructor is useful in cases in which the user
+ * intends to perform decompositions via compute(). The \p size
+ * parameter is only used as a hint. It is not an error to give a
+ * wrong \p size, but it may impair performance.
+ *
+ * \sa compute() for an example.
+ */
+ ComplexSchur(Index size = RowsAtCompileTime==Dynamic ? 1 : RowsAtCompileTime)
+ : m_matT(size,size),
+ m_matU(size,size),
+ m_hess(size),
+ m_isInitialized(false),
+ m_matUisUptodate(false)
+ {}
+
+ /** \brief Constructor; computes Schur decomposition of given matrix.
+ *
+ * \param[in] matrix Square matrix whose Schur decomposition is to be computed.
+ * \param[in] computeU If true, both T and U are computed; if false, only T is computed.
+ *
+ * This constructor calls compute() to compute the Schur decomposition.
+ *
+ * \sa matrixT() and matrixU() for examples.
+ */
+ ComplexSchur(const MatrixType& matrix, bool computeU = true)
+ : m_matT(matrix.rows(),matrix.cols()),
+ m_matU(matrix.rows(),matrix.cols()),
+ m_hess(matrix.rows()),
+ m_isInitialized(false),
+ m_matUisUptodate(false)
+ {
+ compute(matrix, computeU);
+ }
+
+ /** \brief Returns the unitary matrix in the Schur decomposition.
+ *
+ * \returns A const reference to the matrix U.
+ *
+ * It is assumed that either the constructor
+ * ComplexSchur(const MatrixType& matrix, bool computeU) or the
+ * member function compute(const MatrixType& matrix, bool computeU)
+ * has been called before to compute the Schur decomposition of a
+ * matrix, and that \p computeU was set to true (the default
+ * value).
+ *
+ * Example: \include ComplexSchur_matrixU.cpp
+ * Output: \verbinclude ComplexSchur_matrixU.out
+ */
+ const ComplexMatrixType& matrixU() const
+ {
+ eigen_assert(m_isInitialized && "ComplexSchur is not initialized.");
+ eigen_assert(m_matUisUptodate && "The matrix U has not been computed during the ComplexSchur decomposition.");
+ return m_matU;
+ }
+
+ /** \brief Returns the triangular matrix in the Schur decomposition.
+ *
+ * \returns A const reference to the matrix T.
+ *
+ * It is assumed that either the constructor
+ * ComplexSchur(const MatrixType& matrix, bool computeU) or the
+ * member function compute(const MatrixType& matrix, bool computeU)
+ * has been called before to compute the Schur decomposition of a
+ * matrix.
+ *
+ * Note that this function returns a plain square matrix. If you want to reference
+ * only the upper triangular part, use:
+ * \code schur.matrixT().triangularView<Upper>() \endcode
+ *
+ * Example: \include ComplexSchur_matrixT.cpp
+ * Output: \verbinclude ComplexSchur_matrixT.out
+ */
+ const ComplexMatrixType& matrixT() const
+ {
+ eigen_assert(m_isInitialized && "ComplexSchur is not initialized.");
+ return m_matT;
+ }
+
+ /** \brief Computes Schur decomposition of given matrix.
+ *
+ * \param[in] matrix Square matrix whose Schur decomposition is to be computed.
+ * \param[in] computeU If true, both T and U are computed; if false, only T is computed.
+ * \returns Reference to \c *this
+ *
+ * The Schur decomposition is computed by first reducing the
+ * matrix to Hessenberg form using the class
+ * HessenbergDecomposition. The Hessenberg matrix is then reduced
+ * to triangular form by performing QR iterations with a single
+ * shift. The cost of computing the Schur decomposition depends
+ * on the number of iterations; as a rough guide, it may be taken
+ * on the number of iterations; as a rough guide, it may be taken
+ * to be \f$25n^3\f$ complex flops, or \f$10n^3\f$ complex flops
+ * if \a computeU is false.
+ *
+ * Example: \include ComplexSchur_compute.cpp
+ * Output: \verbinclude ComplexSchur_compute.out
+ */
+ ComplexSchur& compute(const MatrixType& matrix, bool computeU = true);
+
+ /** \brief Reports whether previous computation was successful.
+ *
+ * \returns \c Success if computation was succesful, \c NoConvergence otherwise.
+ */
+ ComputationInfo info() const
+ {
+ eigen_assert(m_isInitialized && "RealSchur is not initialized.");
+ return m_info;
+ }
+
+ /** \brief Maximum number of iterations.
+ *
+ * Maximum number of iterations allowed for an eigenvalue to converge.
+ */
+ static const int m_maxIterations = 30;
+
+ protected:
+ ComplexMatrixType m_matT, m_matU;
+ HessenbergDecomposition<MatrixType> m_hess;
+ ComputationInfo m_info;
+ bool m_isInitialized;
+ bool m_matUisUptodate;
+
+ private:
+ bool subdiagonalEntryIsNeglegible(Index i);
+ ComplexScalar computeShift(Index iu, Index iter);
+ void reduceToTriangularForm(bool computeU);
+ friend struct internal::complex_schur_reduce_to_hessenberg<MatrixType, NumTraits<Scalar>::IsComplex>;
+};
+
+/** If m_matT(i+1,i) is neglegible in floating point arithmetic
+ * compared to m_matT(i,i) and m_matT(j,j), then set it to zero and
+ * return true, else return false. */
+template<typename MatrixType>
+inline bool ComplexSchur<MatrixType>::subdiagonalEntryIsNeglegible(Index i)
+{
+ RealScalar d = internal::norm1(m_matT.coeff(i,i)) + internal::norm1(m_matT.coeff(i+1,i+1));
+ RealScalar sd = internal::norm1(m_matT.coeff(i+1,i));
+ if (internal::isMuchSmallerThan(sd, d, NumTraits<RealScalar>::epsilon()))
+ {
+ m_matT.coeffRef(i+1,i) = ComplexScalar(0);
+ return true;
+ }
+ return false;
+}
+
+
+/** Compute the shift in the current QR iteration. */
+template<typename MatrixType>
+typename ComplexSchur<MatrixType>::ComplexScalar ComplexSchur<MatrixType>::computeShift(Index iu, Index iter)
+{
+ if (iter == 10 || iter == 20)
+ {
+ // exceptional shift, taken from http://www.netlib.org/eispack/comqr.f
+ return internal::abs(internal::real(m_matT.coeff(iu,iu-1))) + internal::abs(internal::real(m_matT.coeff(iu-1,iu-2)));
+ }
+
+ // compute the shift as one of the eigenvalues of t, the 2x2
+ // diagonal block on the bottom of the active submatrix
+ Matrix<ComplexScalar,2,2> t = m_matT.template block<2,2>(iu-1,iu-1);
+ RealScalar normt = t.cwiseAbs().sum();
+ t /= normt; // the normalization by sf is to avoid under/overflow
+
+ ComplexScalar b = t.coeff(0,1) * t.coeff(1,0);
+ ComplexScalar c = t.coeff(0,0) - t.coeff(1,1);
+ ComplexScalar disc = sqrt(c*c + RealScalar(4)*b);
+ ComplexScalar det = t.coeff(0,0) * t.coeff(1,1) - b;
+ ComplexScalar trace = t.coeff(0,0) + t.coeff(1,1);
+ ComplexScalar eival1 = (trace + disc) / RealScalar(2);
+ ComplexScalar eival2 = (trace - disc) / RealScalar(2);
+
+ if(internal::norm1(eival1) > internal::norm1(eival2))
+ eival2 = det / eival1;
+ else
+ eival1 = det / eival2;
+
+ // choose the eigenvalue closest to the bottom entry of the diagonal
+ if(internal::norm1(eival1-t.coeff(1,1)) < internal::norm1(eival2-t.coeff(1,1)))
+ return normt * eival1;
+ else
+ return normt * eival2;
+}
+
+
+template<typename MatrixType>
+ComplexSchur<MatrixType>& ComplexSchur<MatrixType>::compute(const MatrixType& matrix, bool computeU)
+{
+ m_matUisUptodate = false;
+ eigen_assert(matrix.cols() == matrix.rows());
+
+ if(matrix.cols() == 1)
+ {
+ m_matT = matrix.template cast<ComplexScalar>();
+ if(computeU) m_matU = ComplexMatrixType::Identity(1,1);
+ m_info = Success;
+ m_isInitialized = true;
+ m_matUisUptodate = computeU;
+ return *this;
+ }
+
+ internal::complex_schur_reduce_to_hessenberg<MatrixType, NumTraits<Scalar>::IsComplex>::run(*this, matrix, computeU);
+ reduceToTriangularForm(computeU);
+ return *this;
+}
+
+namespace internal {
+
+/* Reduce given matrix to Hessenberg form */
+template<typename MatrixType, bool IsComplex>
+struct complex_schur_reduce_to_hessenberg
+{
+ // this is the implementation for the case IsComplex = true
+ static void run(ComplexSchur<MatrixType>& _this, const MatrixType& matrix, bool computeU)
+ {
+ _this.m_hess.compute(matrix);
+ _this.m_matT = _this.m_hess.matrixH();
+ if(computeU) _this.m_matU = _this.m_hess.matrixQ();
+ }
+};
+
+template<typename MatrixType>
+struct complex_schur_reduce_to_hessenberg<MatrixType, false>
+{
+ static void run(ComplexSchur<MatrixType>& _this, const MatrixType& matrix, bool computeU)
+ {
+ typedef typename ComplexSchur<MatrixType>::ComplexScalar ComplexScalar;
+ typedef typename ComplexSchur<MatrixType>::ComplexMatrixType ComplexMatrixType;
+
+ // Note: m_hess is over RealScalar; m_matT and m_matU is over ComplexScalar
+ _this.m_hess.compute(matrix);
+ _this.m_matT = _this.m_hess.matrixH().template cast<ComplexScalar>();
+ if(computeU)
+ {
+ // This may cause an allocation which seems to be avoidable
+ MatrixType Q = _this.m_hess.matrixQ();
+ _this.m_matU = Q.template cast<ComplexScalar>();
+ }
+ }
+};
+
+} // end namespace internal
+
+// Reduce the Hessenberg matrix m_matT to triangular form by QR iteration.
+template<typename MatrixType>
+void ComplexSchur<MatrixType>::reduceToTriangularForm(bool computeU)
+{
+ // The matrix m_matT is divided in three parts.
+ // Rows 0,...,il-1 are decoupled from the rest because m_matT(il,il-1) is zero.
+ // Rows il,...,iu is the part we are working on (the active submatrix).
+ // Rows iu+1,...,end are already brought in triangular form.
+ Index iu = m_matT.cols() - 1;
+ Index il;
+ Index iter = 0; // number of iterations we are working on the (iu,iu) element
+
+ while(true)
+ {
+ // find iu, the bottom row of the active submatrix
+ while(iu > 0)
+ {
+ if(!subdiagonalEntryIsNeglegible(iu-1)) break;
+ iter = 0;
+ --iu;
+ }
+
+ // if iu is zero then we are done; the whole matrix is triangularized
+ if(iu==0) break;
+
+ // if we spent too many iterations on the current element, we give up
+ iter++;
+ if(iter > m_maxIterations * m_matT.cols()) break;
+
+ // find il, the top row of the active submatrix
+ il = iu-1;
+ while(il > 0 && !subdiagonalEntryIsNeglegible(il-1))
+ {
+ --il;
+ }
+
+ /* perform the QR step using Givens rotations. The first rotation
+ creates a bulge; the (il+2,il) element becomes nonzero. This
+ bulge is chased down to the bottom of the active submatrix. */
+
+ ComplexScalar shift = computeShift(iu, iter);
+ JacobiRotation<ComplexScalar> rot;
+ rot.makeGivens(m_matT.coeff(il,il) - shift, m_matT.coeff(il+1,il));
+ m_matT.rightCols(m_matT.cols()-il).applyOnTheLeft(il, il+1, rot.adjoint());
+ m_matT.topRows((std::min)(il+2,iu)+1).applyOnTheRight(il, il+1, rot);
+ if(computeU) m_matU.applyOnTheRight(il, il+1, rot);
+
+ for(Index i=il+1 ; i<iu ; i++)
+ {
+ rot.makeGivens(m_matT.coeffRef(i,i-1), m_matT.coeffRef(i+1,i-1), &m_matT.coeffRef(i,i-1));
+ m_matT.coeffRef(i+1,i-1) = ComplexScalar(0);
+ m_matT.rightCols(m_matT.cols()-i).applyOnTheLeft(i, i+1, rot.adjoint());
+ m_matT.topRows((std::min)(i+2,iu)+1).applyOnTheRight(i, i+1, rot);
+ if(computeU) m_matU.applyOnTheRight(i, i+1, rot);
+ }
+ }
+
+ if(iter <= m_maxIterations * m_matT.cols())
+ m_info = Success;
+ else
+ m_info = NoConvergence;
+
+ m_isInitialized = true;
+ m_matUisUptodate = computeU;
+}
+
+} // end namespace Eigen
+
+#endif // EIGEN_COMPLEX_SCHUR_H
diff --git a/Eigen/src/Eigenvalues/ComplexSchur_MKL.h b/Eigen/src/Eigenvalues/ComplexSchur_MKL.h
new file mode 100644
index 000000000..aa18e6963
--- /dev/null
+++ b/Eigen/src/Eigenvalues/ComplexSchur_MKL.h
@@ -0,0 +1,94 @@
+/*
+ Copyright (c) 2011, Intel Corporation. All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without modification,
+ are permitted provided that the following conditions are met:
+
+ * Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+ * Neither the name of Intel Corporation nor the names of its contributors may
+ be used to endorse or promote products derived from this software without
+ specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+ ********************************************************************************
+ * Content : Eigen bindings to Intel(R) MKL
+ * Complex Schur needed to complex unsymmetrical eigenvalues/eigenvectors.
+ ********************************************************************************
+*/
+
+#ifndef EIGEN_COMPLEX_SCHUR_MKL_H
+#define EIGEN_COMPLEX_SCHUR_MKL_H
+
+#include "Eigen/src/Core/util/MKL_support.h"
+
+namespace Eigen {
+
+/** \internal Specialization for the data types supported by MKL */
+
+#define EIGEN_MKL_SCHUR_COMPLEX(EIGTYPE, MKLTYPE, MKLPREFIX, MKLPREFIX_U, EIGCOLROW, MKLCOLROW) \
+template<> inline\
+ComplexSchur<Matrix<EIGTYPE, Dynamic, Dynamic, EIGCOLROW> >& \
+ComplexSchur<Matrix<EIGTYPE, Dynamic, Dynamic, EIGCOLROW> >::compute(const Matrix<EIGTYPE, Dynamic, Dynamic, EIGCOLROW>& matrix, bool computeU) \
+{ \
+ typedef Matrix<EIGTYPE, Dynamic, Dynamic, EIGCOLROW> MatrixType; \
+ typedef MatrixType::Scalar Scalar; \
+ typedef MatrixType::RealScalar RealScalar; \
+ typedef std::complex<RealScalar> ComplexScalar; \
+\
+ assert(matrix.cols() == matrix.rows()); \
+\
+ m_matUisUptodate = false; \
+ if(matrix.cols() == 1) \
+ { \
+ m_matT = matrix.cast<ComplexScalar>(); \
+ if(computeU) m_matU = ComplexMatrixType::Identity(1,1); \
+ m_info = Success; \
+ m_isInitialized = true; \
+ m_matUisUptodate = computeU; \
+ return *this; \
+ } \
+ lapack_int n = matrix.cols(), sdim, info; \
+ lapack_int lda = matrix.outerStride(); \
+ lapack_int matrix_order = MKLCOLROW; \
+ char jobvs, sort='N'; \
+ LAPACK_##MKLPREFIX_U##_SELECT1 select = 0; \
+ jobvs = (computeU) ? 'V' : 'N'; \
+ m_matU.resize(n, n); \
+ lapack_int ldvs = m_matU.outerStride(); \
+ m_matT = matrix; \
+ Matrix<EIGTYPE, Dynamic, Dynamic> w; \
+ w.resize(n, 1);\
+ info = LAPACKE_##MKLPREFIX##gees( matrix_order, jobvs, sort, select, n, (MKLTYPE*)m_matT.data(), lda, &sdim, (MKLTYPE*)w.data(), (MKLTYPE*)m_matU.data(), ldvs ); \
+ if(info == 0) \
+ m_info = Success; \
+ else \
+ m_info = NoConvergence; \
+\
+ m_isInitialized = true; \
+ m_matUisUptodate = computeU; \
+ return *this; \
+\
+}
+
+EIGEN_MKL_SCHUR_COMPLEX(dcomplex, MKL_Complex16, z, Z, ColMajor, LAPACK_COL_MAJOR)
+EIGEN_MKL_SCHUR_COMPLEX(scomplex, MKL_Complex8, c, C, ColMajor, LAPACK_COL_MAJOR)
+EIGEN_MKL_SCHUR_COMPLEX(dcomplex, MKL_Complex16, z, Z, RowMajor, LAPACK_ROW_MAJOR)
+EIGEN_MKL_SCHUR_COMPLEX(scomplex, MKL_Complex8, c, C, RowMajor, LAPACK_ROW_MAJOR)
+
+} // end namespace Eigen
+
+#endif // EIGEN_COMPLEX_SCHUR_MKL_H
diff --git a/Eigen/src/Eigenvalues/EigenSolver.h b/Eigen/src/Eigenvalues/EigenSolver.h
new file mode 100644
index 000000000..c16ff2b74
--- /dev/null
+++ b/Eigen/src/Eigenvalues/EigenSolver.h
@@ -0,0 +1,579 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra.
+//
+// Copyright (C) 2008 Gael Guennebaud <gael.guennebaud@inria.fr>
+// Copyright (C) 2010 Jitse Niesen <jitse@maths.leeds.ac.uk>
+//
+// This Source Code Form is subject to the terms of the Mozilla
+// Public License v. 2.0. If a copy of the MPL was not distributed
+// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+#ifndef EIGEN_EIGENSOLVER_H
+#define EIGEN_EIGENSOLVER_H
+
+#include "./RealSchur.h"
+
+namespace Eigen {
+
+/** \eigenvalues_module \ingroup Eigenvalues_Module
+ *
+ *
+ * \class EigenSolver
+ *
+ * \brief Computes eigenvalues and eigenvectors of general matrices
+ *
+ * \tparam _MatrixType the type of the matrix of which we are computing the
+ * eigendecomposition; this is expected to be an instantiation of the Matrix
+ * class template. Currently, only real matrices are supported.
+ *
+ * The eigenvalues and eigenvectors of a matrix \f$ A \f$ are scalars
+ * \f$ \lambda \f$ and vectors \f$ v \f$ such that \f$ Av = \lambda v \f$. If
+ * \f$ D \f$ is a diagonal matrix with the eigenvalues on the diagonal, and
+ * \f$ V \f$ is a matrix with the eigenvectors as its columns, then \f$ A V =
+ * V D \f$. The matrix \f$ V \f$ is almost always invertible, in which case we
+ * have \f$ A = V D V^{-1} \f$. This is called the eigendecomposition.
+ *
+ * The eigenvalues and eigenvectors of a matrix may be complex, even when the
+ * matrix is real. However, we can choose real matrices \f$ V \f$ and \f$ D
+ * \f$ satisfying \f$ A V = V D \f$, just like the eigendecomposition, if the
+ * matrix \f$ D \f$ is not required to be diagonal, but if it is allowed to
+ * have blocks of the form
+ * \f[ \begin{bmatrix} u & v \\ -v & u \end{bmatrix} \f]
+ * (where \f$ u \f$ and \f$ v \f$ are real numbers) on the diagonal. These
+ * blocks correspond to complex eigenvalue pairs \f$ u \pm iv \f$. We call
+ * this variant of the eigendecomposition the pseudo-eigendecomposition.
+ *
+ * Call the function compute() to compute the eigenvalues and eigenvectors of
+ * a given matrix. Alternatively, you can use the
+ * EigenSolver(const MatrixType&, bool) constructor which computes the
+ * eigenvalues and eigenvectors at construction time. Once the eigenvalue and
+ * eigenvectors are computed, they can be retrieved with the eigenvalues() and
+ * eigenvectors() functions. The pseudoEigenvalueMatrix() and
+ * pseudoEigenvectors() methods allow the construction of the
+ * pseudo-eigendecomposition.
+ *
+ * The documentation for EigenSolver(const MatrixType&, bool) contains an
+ * example of the typical use of this class.
+ *
+ * \note The implementation is adapted from
+ * <a href="http://math.nist.gov/javanumerics/jama/">JAMA</a> (public domain).
+ * Their code is based on EISPACK.
+ *
+ * \sa MatrixBase::eigenvalues(), class ComplexEigenSolver, class SelfAdjointEigenSolver
+ */
+template<typename _MatrixType> class EigenSolver
+{
+ public:
+
+ /** \brief Synonym for the template parameter \p _MatrixType. */
+ typedef _MatrixType MatrixType;
+
+ enum {
+ RowsAtCompileTime = MatrixType::RowsAtCompileTime,
+ ColsAtCompileTime = MatrixType::ColsAtCompileTime,
+ Options = MatrixType::Options,
+ MaxRowsAtCompileTime = MatrixType::MaxRowsAtCompileTime,
+ MaxColsAtCompileTime = MatrixType::MaxColsAtCompileTime
+ };
+
+ /** \brief Scalar type for matrices of type #MatrixType. */
+ typedef typename MatrixType::Scalar Scalar;
+ typedef typename NumTraits<Scalar>::Real RealScalar;
+ typedef typename MatrixType::Index Index;
+
+ /** \brief Complex scalar type for #MatrixType.
+ *
+ * This is \c std::complex<Scalar> if #Scalar is real (e.g.,
+ * \c float or \c double) and just \c Scalar if #Scalar is
+ * complex.
+ */
+ typedef std::complex<RealScalar> ComplexScalar;
+
+ /** \brief Type for vector of eigenvalues as returned by eigenvalues().
+ *
+ * This is a column vector with entries of type #ComplexScalar.
+ * The length of the vector is the size of #MatrixType.
+ */
+ typedef Matrix<ComplexScalar, ColsAtCompileTime, 1, Options & ~RowMajor, MaxColsAtCompileTime, 1> EigenvalueType;
+
+ /** \brief Type for matrix of eigenvectors as returned by eigenvectors().
+ *
+ * This is a square matrix with entries of type #ComplexScalar.
+ * The size is the same as the size of #MatrixType.
+ */
+ typedef Matrix<ComplexScalar, RowsAtCompileTime, ColsAtCompileTime, Options, MaxRowsAtCompileTime, MaxColsAtCompileTime> EigenvectorsType;
+
+ /** \brief Default constructor.
+ *
+ * The default constructor is useful in cases in which the user intends to
+ * perform decompositions via EigenSolver::compute(const MatrixType&, bool).
+ *
+ * \sa compute() for an example.
+ */
+ EigenSolver() : m_eivec(), m_eivalues(), m_isInitialized(false), m_realSchur(), m_matT(), m_tmp() {}
+
+ /** \brief Default constructor with memory preallocation
+ *
+ * Like the default constructor but with preallocation of the internal data
+ * according to the specified problem \a size.
+ * \sa EigenSolver()
+ */
+ EigenSolver(Index size)
+ : m_eivec(size, size),
+ m_eivalues(size),
+ m_isInitialized(false),
+ m_eigenvectorsOk(false),
+ m_realSchur(size),
+ m_matT(size, size),
+ m_tmp(size)
+ {}
+
+ /** \brief Constructor; computes eigendecomposition of given matrix.
+ *
+ * \param[in] matrix Square matrix whose eigendecomposition is to be computed.
+ * \param[in] computeEigenvectors If true, both the eigenvectors and the
+ * eigenvalues are computed; if false, only the eigenvalues are
+ * computed.
+ *
+ * This constructor calls compute() to compute the eigenvalues
+ * and eigenvectors.
+ *
+ * Example: \include EigenSolver_EigenSolver_MatrixType.cpp
+ * Output: \verbinclude EigenSolver_EigenSolver_MatrixType.out
+ *
+ * \sa compute()
+ */
+ EigenSolver(const MatrixType& matrix, bool computeEigenvectors = true)
+ : m_eivec(matrix.rows(), matrix.cols()),
+ m_eivalues(matrix.cols()),
+ m_isInitialized(false),
+ m_eigenvectorsOk(false),
+ m_realSchur(matrix.cols()),
+ m_matT(matrix.rows(), matrix.cols()),
+ m_tmp(matrix.cols())
+ {
+ compute(matrix, computeEigenvectors);
+ }
+
+ /** \brief Returns the eigenvectors of given matrix.
+ *
+ * \returns %Matrix whose columns are the (possibly complex) eigenvectors.
+ *
+ * \pre Either the constructor
+ * EigenSolver(const MatrixType&,bool) or the member function
+ * compute(const MatrixType&, bool) has been called before, and
+ * \p computeEigenvectors was set to true (the default).
+ *
+ * Column \f$ k \f$ of the returned matrix is an eigenvector corresponding
+ * to eigenvalue number \f$ k \f$ as returned by eigenvalues(). The
+ * eigenvectors are normalized to have (Euclidean) norm equal to one. The
+ * matrix returned by this function is the matrix \f$ V \f$ in the
+ * eigendecomposition \f$ A = V D V^{-1} \f$, if it exists.
+ *
+ * Example: \include EigenSolver_eigenvectors.cpp
+ * Output: \verbinclude EigenSolver_eigenvectors.out
+ *
+ * \sa eigenvalues(), pseudoEigenvectors()
+ */
+ EigenvectorsType eigenvectors() const;
+
+ /** \brief Returns the pseudo-eigenvectors of given matrix.
+ *
+ * \returns Const reference to matrix whose columns are the pseudo-eigenvectors.
+ *
+ * \pre Either the constructor
+ * EigenSolver(const MatrixType&,bool) or the member function
+ * compute(const MatrixType&, bool) has been called before, and
+ * \p computeEigenvectors was set to true (the default).
+ *
+ * The real matrix \f$ V \f$ returned by this function and the
+ * block-diagonal matrix \f$ D \f$ returned by pseudoEigenvalueMatrix()
+ * satisfy \f$ AV = VD \f$.
+ *
+ * Example: \include EigenSolver_pseudoEigenvectors.cpp
+ * Output: \verbinclude EigenSolver_pseudoEigenvectors.out
+ *
+ * \sa pseudoEigenvalueMatrix(), eigenvectors()
+ */
+ const MatrixType& pseudoEigenvectors() const
+ {
+ eigen_assert(m_isInitialized && "EigenSolver is not initialized.");
+ eigen_assert(m_eigenvectorsOk && "The eigenvectors have not been computed together with the eigenvalues.");
+ return m_eivec;
+ }
+
+ /** \brief Returns the block-diagonal matrix in the pseudo-eigendecomposition.
+ *
+ * \returns A block-diagonal matrix.
+ *
+ * \pre Either the constructor
+ * EigenSolver(const MatrixType&,bool) or the member function
+ * compute(const MatrixType&, bool) has been called before.
+ *
+ * The matrix \f$ D \f$ returned by this function is real and
+ * block-diagonal. The blocks on the diagonal are either 1-by-1 or 2-by-2
+ * blocks of the form
+ * \f$ \begin{bmatrix} u & v \\ -v & u \end{bmatrix} \f$.
+ * These blocks are not sorted in any particular order.
+ * The matrix \f$ D \f$ and the matrix \f$ V \f$ returned by
+ * pseudoEigenvectors() satisfy \f$ AV = VD \f$.
+ *
+ * \sa pseudoEigenvectors() for an example, eigenvalues()
+ */
+ MatrixType pseudoEigenvalueMatrix() const;
+
+ /** \brief Returns the eigenvalues of given matrix.
+ *
+ * \returns A const reference to the column vector containing the eigenvalues.
+ *
+ * \pre Either the constructor
+ * EigenSolver(const MatrixType&,bool) or the member function
+ * compute(const MatrixType&, bool) has been called before.
+ *
+ * The eigenvalues are repeated according to their algebraic multiplicity,
+ * so there are as many eigenvalues as rows in the matrix. The eigenvalues
+ * are not sorted in any particular order.
+ *
+ * Example: \include EigenSolver_eigenvalues.cpp
+ * Output: \verbinclude EigenSolver_eigenvalues.out
+ *
+ * \sa eigenvectors(), pseudoEigenvalueMatrix(),
+ * MatrixBase::eigenvalues()
+ */
+ const EigenvalueType& eigenvalues() const
+ {
+ eigen_assert(m_isInitialized && "EigenSolver is not initialized.");
+ return m_eivalues;
+ }
+
+ /** \brief Computes eigendecomposition of given matrix.
+ *
+ * \param[in] matrix Square matrix whose eigendecomposition is to be computed.
+ * \param[in] computeEigenvectors If true, both the eigenvectors and the
+ * eigenvalues are computed; if false, only the eigenvalues are
+ * computed.
+ * \returns Reference to \c *this
+ *
+ * This function computes the eigenvalues of the real matrix \p matrix.
+ * The eigenvalues() function can be used to retrieve them. If
+ * \p computeEigenvectors is true, then the eigenvectors are also computed
+ * and can be retrieved by calling eigenvectors().
+ *
+ * The matrix is first reduced to real Schur form using the RealSchur
+ * class. The Schur decomposition is then used to compute the eigenvalues
+ * and eigenvectors.
+ *
+ * The cost of the computation is dominated by the cost of the
+ * Schur decomposition, which is very approximately \f$ 25n^3 \f$
+ * (where \f$ n \f$ is the size of the matrix) if \p computeEigenvectors
+ * is true, and \f$ 10n^3 \f$ if \p computeEigenvectors is false.
+ *
+ * This method reuses of the allocated data in the EigenSolver object.
+ *
+ * Example: \include EigenSolver_compute.cpp
+ * Output: \verbinclude EigenSolver_compute.out
+ */
+ EigenSolver& compute(const MatrixType& matrix, bool computeEigenvectors = true);
+
+ ComputationInfo info() const
+ {
+ eigen_assert(m_isInitialized && "EigenSolver is not initialized.");
+ return m_realSchur.info();
+ }
+
+ private:
+ void doComputeEigenvectors();
+
+ protected:
+ MatrixType m_eivec;
+ EigenvalueType m_eivalues;
+ bool m_isInitialized;
+ bool m_eigenvectorsOk;
+ RealSchur<MatrixType> m_realSchur;
+ MatrixType m_matT;
+
+ typedef Matrix<Scalar, ColsAtCompileTime, 1, Options & ~RowMajor, MaxColsAtCompileTime, 1> ColumnVectorType;
+ ColumnVectorType m_tmp;
+};
+
+template<typename MatrixType>
+MatrixType EigenSolver<MatrixType>::pseudoEigenvalueMatrix() const
+{
+ eigen_assert(m_isInitialized && "EigenSolver is not initialized.");
+ Index n = m_eivalues.rows();
+ MatrixType matD = MatrixType::Zero(n,n);
+ for (Index i=0; i<n; ++i)
+ {
+ if (internal::isMuchSmallerThan(internal::imag(m_eivalues.coeff(i)), internal::real(m_eivalues.coeff(i))))
+ matD.coeffRef(i,i) = internal::real(m_eivalues.coeff(i));
+ else
+ {
+ matD.template block<2,2>(i,i) << internal::real(m_eivalues.coeff(i)), internal::imag(m_eivalues.coeff(i)),
+ -internal::imag(m_eivalues.coeff(i)), internal::real(m_eivalues.coeff(i));
+ ++i;
+ }
+ }
+ return matD;
+}
+
+template<typename MatrixType>
+typename EigenSolver<MatrixType>::EigenvectorsType EigenSolver<MatrixType>::eigenvectors() const
+{
+ eigen_assert(m_isInitialized && "EigenSolver is not initialized.");
+ eigen_assert(m_eigenvectorsOk && "The eigenvectors have not been computed together with the eigenvalues.");
+ Index n = m_eivec.cols();
+ EigenvectorsType matV(n,n);
+ for (Index j=0; j<n; ++j)
+ {
+ if (internal::isMuchSmallerThan(internal::imag(m_eivalues.coeff(j)), internal::real(m_eivalues.coeff(j))) || j+1==n)
+ {
+ // we have a real eigen value
+ matV.col(j) = m_eivec.col(j).template cast<ComplexScalar>();
+ matV.col(j).normalize();
+ }
+ else
+ {
+ // we have a pair of complex eigen values
+ for (Index i=0; i<n; ++i)
+ {
+ matV.coeffRef(i,j) = ComplexScalar(m_eivec.coeff(i,j), m_eivec.coeff(i,j+1));
+ matV.coeffRef(i,j+1) = ComplexScalar(m_eivec.coeff(i,j), -m_eivec.coeff(i,j+1));
+ }
+ matV.col(j).normalize();
+ matV.col(j+1).normalize();
+ ++j;
+ }
+ }
+ return matV;
+}
+
+template<typename MatrixType>
+EigenSolver<MatrixType>& EigenSolver<MatrixType>::compute(const MatrixType& matrix, bool computeEigenvectors)
+{
+ assert(matrix.cols() == matrix.rows());
+
+ // Reduce to real Schur form.
+ m_realSchur.compute(matrix, computeEigenvectors);
+ if (m_realSchur.info() == Success)
+ {
+ m_matT = m_realSchur.matrixT();
+ if (computeEigenvectors)
+ m_eivec = m_realSchur.matrixU();
+
+ // Compute eigenvalues from matT
+ m_eivalues.resize(matrix.cols());
+ Index i = 0;
+ while (i < matrix.cols())
+ {
+ if (i == matrix.cols() - 1 || m_matT.coeff(i+1, i) == Scalar(0))
+ {
+ m_eivalues.coeffRef(i) = m_matT.coeff(i, i);
+ ++i;
+ }
+ else
+ {
+ Scalar p = Scalar(0.5) * (m_matT.coeff(i, i) - m_matT.coeff(i+1, i+1));
+ Scalar z = internal::sqrt(internal::abs(p * p + m_matT.coeff(i+1, i) * m_matT.coeff(i, i+1)));
+ m_eivalues.coeffRef(i) = ComplexScalar(m_matT.coeff(i+1, i+1) + p, z);
+ m_eivalues.coeffRef(i+1) = ComplexScalar(m_matT.coeff(i+1, i+1) + p, -z);
+ i += 2;
+ }
+ }
+
+ // Compute eigenvectors.
+ if (computeEigenvectors)
+ doComputeEigenvectors();
+ }
+
+ m_isInitialized = true;
+ m_eigenvectorsOk = computeEigenvectors;
+
+ return *this;
+}
+
+// Complex scalar division.
+template<typename Scalar>
+std::complex<Scalar> cdiv(Scalar xr, Scalar xi, Scalar yr, Scalar yi)
+{
+ Scalar r,d;
+ if (internal::abs(yr) > internal::abs(yi))
+ {
+ r = yi/yr;
+ d = yr + r*yi;
+ return std::complex<Scalar>((xr + r*xi)/d, (xi - r*xr)/d);
+ }
+ else
+ {
+ r = yr/yi;
+ d = yi + r*yr;
+ return std::complex<Scalar>((r*xr + xi)/d, (r*xi - xr)/d);
+ }
+}
+
+
+template<typename MatrixType>
+void EigenSolver<MatrixType>::doComputeEigenvectors()
+{
+ const Index size = m_eivec.cols();
+ const Scalar eps = NumTraits<Scalar>::epsilon();
+
+ // inefficient! this is already computed in RealSchur
+ Scalar norm(0);
+ for (Index j = 0; j < size; ++j)
+ {
+ norm += m_matT.row(j).segment((std::max)(j-1,Index(0)), size-(std::max)(j-1,Index(0))).cwiseAbs().sum();
+ }
+
+ // Backsubstitute to find vectors of upper triangular form
+ if (norm == 0.0)
+ {
+ return;
+ }
+
+ for (Index n = size-1; n >= 0; n--)
+ {
+ Scalar p = m_eivalues.coeff(n).real();
+ Scalar q = m_eivalues.coeff(n).imag();
+
+ // Scalar vector
+ if (q == Scalar(0))
+ {
+ Scalar lastr(0), lastw(0);
+ Index l = n;
+
+ m_matT.coeffRef(n,n) = 1.0;
+ for (Index i = n-1; i >= 0; i--)
+ {
+ Scalar w = m_matT.coeff(i,i) - p;
+ Scalar r = m_matT.row(i).segment(l,n-l+1).dot(m_matT.col(n).segment(l, n-l+1));
+
+ if (m_eivalues.coeff(i).imag() < 0.0)
+ {
+ lastw = w;
+ lastr = r;
+ }
+ else
+ {
+ l = i;
+ if (m_eivalues.coeff(i).imag() == 0.0)
+ {
+ if (w != 0.0)
+ m_matT.coeffRef(i,n) = -r / w;
+ else
+ m_matT.coeffRef(i,n) = -r / (eps * norm);
+ }
+ else // Solve real equations
+ {
+ Scalar x = m_matT.coeff(i,i+1);
+ Scalar y = m_matT.coeff(i+1,i);
+ Scalar denom = (m_eivalues.coeff(i).real() - p) * (m_eivalues.coeff(i).real() - p) + m_eivalues.coeff(i).imag() * m_eivalues.coeff(i).imag();
+ Scalar t = (x * lastr - lastw * r) / denom;
+ m_matT.coeffRef(i,n) = t;
+ if (internal::abs(x) > internal::abs(lastw))
+ m_matT.coeffRef(i+1,n) = (-r - w * t) / x;
+ else
+ m_matT.coeffRef(i+1,n) = (-lastr - y * t) / lastw;
+ }
+
+ // Overflow control
+ Scalar t = internal::abs(m_matT.coeff(i,n));
+ if ((eps * t) * t > Scalar(1))
+ m_matT.col(n).tail(size-i) /= t;
+ }
+ }
+ }
+ else if (q < Scalar(0) && n > 0) // Complex vector
+ {
+ Scalar lastra(0), lastsa(0), lastw(0);
+ Index l = n-1;
+
+ // Last vector component imaginary so matrix is triangular
+ if (internal::abs(m_matT.coeff(n,n-1)) > internal::abs(m_matT.coeff(n-1,n)))
+ {
+ m_matT.coeffRef(n-1,n-1) = q / m_matT.coeff(n,n-1);
+ m_matT.coeffRef(n-1,n) = -(m_matT.coeff(n,n) - p) / m_matT.coeff(n,n-1);
+ }
+ else
+ {
+ std::complex<Scalar> cc = cdiv<Scalar>(0.0,-m_matT.coeff(n-1,n),m_matT.coeff(n-1,n-1)-p,q);
+ m_matT.coeffRef(n-1,n-1) = internal::real(cc);
+ m_matT.coeffRef(n-1,n) = internal::imag(cc);
+ }
+ m_matT.coeffRef(n,n-1) = 0.0;
+ m_matT.coeffRef(n,n) = 1.0;
+ for (Index i = n-2; i >= 0; i--)
+ {
+ Scalar ra = m_matT.row(i).segment(l, n-l+1).dot(m_matT.col(n-1).segment(l, n-l+1));
+ Scalar sa = m_matT.row(i).segment(l, n-l+1).dot(m_matT.col(n).segment(l, n-l+1));
+ Scalar w = m_matT.coeff(i,i) - p;
+
+ if (m_eivalues.coeff(i).imag() < 0.0)
+ {
+ lastw = w;
+ lastra = ra;
+ lastsa = sa;
+ }
+ else
+ {
+ l = i;
+ if (m_eivalues.coeff(i).imag() == RealScalar(0))
+ {
+ std::complex<Scalar> cc = cdiv(-ra,-sa,w,q);
+ m_matT.coeffRef(i,n-1) = internal::real(cc);
+ m_matT.coeffRef(i,n) = internal::imag(cc);
+ }
+ else
+ {
+ // Solve complex equations
+ Scalar x = m_matT.coeff(i,i+1);
+ Scalar y = m_matT.coeff(i+1,i);
+ Scalar vr = (m_eivalues.coeff(i).real() - p) * (m_eivalues.coeff(i).real() - p) + m_eivalues.coeff(i).imag() * m_eivalues.coeff(i).imag() - q * q;
+ Scalar vi = (m_eivalues.coeff(i).real() - p) * Scalar(2) * q;
+ if ((vr == 0.0) && (vi == 0.0))
+ vr = eps * norm * (internal::abs(w) + internal::abs(q) + internal::abs(x) + internal::abs(y) + internal::abs(lastw));
+
+ std::complex<Scalar> cc = cdiv(x*lastra-lastw*ra+q*sa,x*lastsa-lastw*sa-q*ra,vr,vi);
+ m_matT.coeffRef(i,n-1) = internal::real(cc);
+ m_matT.coeffRef(i,n) = internal::imag(cc);
+ if (internal::abs(x) > (internal::abs(lastw) + internal::abs(q)))
+ {
+ m_matT.coeffRef(i+1,n-1) = (-ra - w * m_matT.coeff(i,n-1) + q * m_matT.coeff(i,n)) / x;
+ m_matT.coeffRef(i+1,n) = (-sa - w * m_matT.coeff(i,n) - q * m_matT.coeff(i,n-1)) / x;
+ }
+ else
+ {
+ cc = cdiv(-lastra-y*m_matT.coeff(i,n-1),-lastsa-y*m_matT.coeff(i,n),lastw,q);
+ m_matT.coeffRef(i+1,n-1) = internal::real(cc);
+ m_matT.coeffRef(i+1,n) = internal::imag(cc);
+ }
+ }
+
+ // Overflow control
+ using std::max;
+ Scalar t = (max)(internal::abs(m_matT.coeff(i,n-1)),internal::abs(m_matT.coeff(i,n)));
+ if ((eps * t) * t > Scalar(1))
+ m_matT.block(i, n-1, size-i, 2) /= t;
+
+ }
+ }
+
+ // We handled a pair of complex conjugate eigenvalues, so need to skip them both
+ n--;
+ }
+ else
+ {
+ eigen_assert(0 && "Internal bug in EigenSolver"); // this should not happen
+ }
+ }
+
+ // Back transformation to get eigenvectors of original matrix
+ for (Index j = size-1; j >= 0; j--)
+ {
+ m_tmp.noalias() = m_eivec.leftCols(j+1) * m_matT.col(j).segment(0, j+1);
+ m_eivec.col(j) = m_tmp;
+ }
+}
+
+} // end namespace Eigen
+
+#endif // EIGEN_EIGENSOLVER_H
diff --git a/Eigen/src/Eigenvalues/GeneralizedSelfAdjointEigenSolver.h b/Eigen/src/Eigenvalues/GeneralizedSelfAdjointEigenSolver.h
new file mode 100644
index 000000000..07bf1ea09
--- /dev/null
+++ b/Eigen/src/Eigenvalues/GeneralizedSelfAdjointEigenSolver.h
@@ -0,0 +1,227 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra.
+//
+// Copyright (C) 2008-2010 Gael Guennebaud <gael.guennebaud@inria.fr>
+// Copyright (C) 2010 Jitse Niesen <jitse@maths.leeds.ac.uk>
+//
+// This Source Code Form is subject to the terms of the Mozilla
+// Public License v. 2.0. If a copy of the MPL was not distributed
+// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+#ifndef EIGEN_GENERALIZEDSELFADJOINTEIGENSOLVER_H
+#define EIGEN_GENERALIZEDSELFADJOINTEIGENSOLVER_H
+
+#include "./Tridiagonalization.h"
+
+namespace Eigen {
+
+/** \eigenvalues_module \ingroup Eigenvalues_Module
+ *
+ *
+ * \class GeneralizedSelfAdjointEigenSolver
+ *
+ * \brief Computes eigenvalues and eigenvectors of the generalized selfadjoint eigen problem
+ *
+ * \tparam _MatrixType the type of the matrix of which we are computing the
+ * eigendecomposition; this is expected to be an instantiation of the Matrix
+ * class template.
+ *
+ * This class solves the generalized eigenvalue problem
+ * \f$ Av = \lambda Bv \f$. In this case, the matrix \f$ A \f$ should be
+ * selfadjoint and the matrix \f$ B \f$ should be positive definite.
+ *
+ * Only the \b lower \b triangular \b part of the input matrix is referenced.
+ *
+ * Call the function compute() to compute the eigenvalues and eigenvectors of
+ * a given matrix. Alternatively, you can use the
+ * GeneralizedSelfAdjointEigenSolver(const MatrixType&, const MatrixType&, int)
+ * constructor which computes the eigenvalues and eigenvectors at construction time.
+ * Once the eigenvalue and eigenvectors are computed, they can be retrieved with the eigenvalues()
+ * and eigenvectors() functions.
+ *
+ * The documentation for GeneralizedSelfAdjointEigenSolver(const MatrixType&, const MatrixType&, int)
+ * contains an example of the typical use of this class.
+ *
+ * \sa class SelfAdjointEigenSolver, class EigenSolver, class ComplexEigenSolver
+ */
+template<typename _MatrixType>
+class GeneralizedSelfAdjointEigenSolver : public SelfAdjointEigenSolver<_MatrixType>
+{
+ typedef SelfAdjointEigenSolver<_MatrixType> Base;
+ public:
+
+ typedef typename Base::Index Index;
+ typedef _MatrixType MatrixType;
+
+ /** \brief Default constructor for fixed-size matrices.
+ *
+ * The default constructor is useful in cases in which the user intends to
+ * perform decompositions via compute(). This constructor
+ * can only be used if \p _MatrixType is a fixed-size matrix; use
+ * GeneralizedSelfAdjointEigenSolver(Index) for dynamic-size matrices.
+ */
+ GeneralizedSelfAdjointEigenSolver() : Base() {}
+
+ /** \brief Constructor, pre-allocates memory for dynamic-size matrices.
+ *
+ * \param [in] size Positive integer, size of the matrix whose
+ * eigenvalues and eigenvectors will be computed.
+ *
+ * This constructor is useful for dynamic-size matrices, when the user
+ * intends to perform decompositions via compute(). The \p size
+ * parameter is only used as a hint. It is not an error to give a wrong
+ * \p size, but it may impair performance.
+ *
+ * \sa compute() for an example
+ */
+ GeneralizedSelfAdjointEigenSolver(Index size)
+ : Base(size)
+ {}
+
+ /** \brief Constructor; computes generalized eigendecomposition of given matrix pencil.
+ *
+ * \param[in] matA Selfadjoint matrix in matrix pencil.
+ * Only the lower triangular part of the matrix is referenced.
+ * \param[in] matB Positive-definite matrix in matrix pencil.
+ * Only the lower triangular part of the matrix is referenced.
+ * \param[in] options A or-ed set of flags {#ComputeEigenvectors,#EigenvaluesOnly} | {#Ax_lBx,#ABx_lx,#BAx_lx}.
+ * Default is #ComputeEigenvectors|#Ax_lBx.
+ *
+ * This constructor calls compute(const MatrixType&, const MatrixType&, int)
+ * to compute the eigenvalues and (if requested) the eigenvectors of the
+ * generalized eigenproblem \f$ Ax = \lambda B x \f$ with \a matA the
+ * selfadjoint matrix \f$ A \f$ and \a matB the positive definite matrix
+ * \f$ B \f$. Each eigenvector \f$ x \f$ satisfies the property
+ * \f$ x^* B x = 1 \f$. The eigenvectors are computed if
+ * \a options contains ComputeEigenvectors.
+ *
+ * In addition, the two following variants can be solved via \p options:
+ * - \c ABx_lx: \f$ ABx = \lambda x \f$
+ * - \c BAx_lx: \f$ BAx = \lambda x \f$
+ *
+ * Example: \include SelfAdjointEigenSolver_SelfAdjointEigenSolver_MatrixType2.cpp
+ * Output: \verbinclude SelfAdjointEigenSolver_SelfAdjointEigenSolver_MatrixType2.out
+ *
+ * \sa compute(const MatrixType&, const MatrixType&, int)
+ */
+ GeneralizedSelfAdjointEigenSolver(const MatrixType& matA, const MatrixType& matB,
+ int options = ComputeEigenvectors|Ax_lBx)
+ : Base(matA.cols())
+ {
+ compute(matA, matB, options);
+ }
+
+ /** \brief Computes generalized eigendecomposition of given matrix pencil.
+ *
+ * \param[in] matA Selfadjoint matrix in matrix pencil.
+ * Only the lower triangular part of the matrix is referenced.
+ * \param[in] matB Positive-definite matrix in matrix pencil.
+ * Only the lower triangular part of the matrix is referenced.
+ * \param[in] options A or-ed set of flags {#ComputeEigenvectors,#EigenvaluesOnly} | {#Ax_lBx,#ABx_lx,#BAx_lx}.
+ * Default is #ComputeEigenvectors|#Ax_lBx.
+ *
+ * \returns Reference to \c *this
+ *
+ * Accoring to \p options, this function computes eigenvalues and (if requested)
+ * the eigenvectors of one of the following three generalized eigenproblems:
+ * - \c Ax_lBx: \f$ Ax = \lambda B x \f$
+ * - \c ABx_lx: \f$ ABx = \lambda x \f$
+ * - \c BAx_lx: \f$ BAx = \lambda x \f$
+ * with \a matA the selfadjoint matrix \f$ A \f$ and \a matB the positive definite
+ * matrix \f$ B \f$.
+ * In addition, each eigenvector \f$ x \f$ satisfies the property \f$ x^* B x = 1 \f$.
+ *
+ * The eigenvalues() function can be used to retrieve
+ * the eigenvalues. If \p options contains ComputeEigenvectors, then the
+ * eigenvectors are also computed and can be retrieved by calling
+ * eigenvectors().
+ *
+ * The implementation uses LLT to compute the Cholesky decomposition
+ * \f$ B = LL^* \f$ and computes the classical eigendecomposition
+ * of the selfadjoint matrix \f$ L^{-1} A (L^*)^{-1} \f$ if \p options contains Ax_lBx
+ * and of \f$ L^{*} A L \f$ otherwise. This solves the
+ * generalized eigenproblem, because any solution of the generalized
+ * eigenproblem \f$ Ax = \lambda B x \f$ corresponds to a solution
+ * \f$ L^{-1} A (L^*)^{-1} (L^* x) = \lambda (L^* x) \f$ of the
+ * eigenproblem for \f$ L^{-1} A (L^*)^{-1} \f$. Similar statements
+ * can be made for the two other variants.
+ *
+ * Example: \include SelfAdjointEigenSolver_compute_MatrixType2.cpp
+ * Output: \verbinclude SelfAdjointEigenSolver_compute_MatrixType2.out
+ *
+ * \sa GeneralizedSelfAdjointEigenSolver(const MatrixType&, const MatrixType&, int)
+ */
+ GeneralizedSelfAdjointEigenSolver& compute(const MatrixType& matA, const MatrixType& matB,
+ int options = ComputeEigenvectors|Ax_lBx);
+
+ protected:
+
+};
+
+
+template<typename MatrixType>
+GeneralizedSelfAdjointEigenSolver<MatrixType>& GeneralizedSelfAdjointEigenSolver<MatrixType>::
+compute(const MatrixType& matA, const MatrixType& matB, int options)
+{
+ eigen_assert(matA.cols()==matA.rows() && matB.rows()==matA.rows() && matB.cols()==matB.rows());
+ eigen_assert((options&~(EigVecMask|GenEigMask))==0
+ && (options&EigVecMask)!=EigVecMask
+ && ((options&GenEigMask)==0 || (options&GenEigMask)==Ax_lBx
+ || (options&GenEigMask)==ABx_lx || (options&GenEigMask)==BAx_lx)
+ && "invalid option parameter");
+
+ bool computeEigVecs = ((options&EigVecMask)==0) || ((options&EigVecMask)==ComputeEigenvectors);
+
+ // Compute the cholesky decomposition of matB = L L' = U'U
+ LLT<MatrixType> cholB(matB);
+
+ int type = (options&GenEigMask);
+ if(type==0)
+ type = Ax_lBx;
+
+ if(type==Ax_lBx)
+ {
+ // compute C = inv(L) A inv(L')
+ MatrixType matC = matA.template selfadjointView<Lower>();
+ cholB.matrixL().template solveInPlace<OnTheLeft>(matC);
+ cholB.matrixU().template solveInPlace<OnTheRight>(matC);
+
+ Base::compute(matC, computeEigVecs ? ComputeEigenvectors : EigenvaluesOnly );
+
+ // transform back the eigen vectors: evecs = inv(U) * evecs
+ if(computeEigVecs)
+ cholB.matrixU().solveInPlace(Base::m_eivec);
+ }
+ else if(type==ABx_lx)
+ {
+ // compute C = L' A L
+ MatrixType matC = matA.template selfadjointView<Lower>();
+ matC = matC * cholB.matrixL();
+ matC = cholB.matrixU() * matC;
+
+ Base::compute(matC, computeEigVecs ? ComputeEigenvectors : EigenvaluesOnly);
+
+ // transform back the eigen vectors: evecs = inv(U) * evecs
+ if(computeEigVecs)
+ cholB.matrixU().solveInPlace(Base::m_eivec);
+ }
+ else if(type==BAx_lx)
+ {
+ // compute C = L' A L
+ MatrixType matC = matA.template selfadjointView<Lower>();
+ matC = matC * cholB.matrixL();
+ matC = cholB.matrixU() * matC;
+
+ Base::compute(matC, computeEigVecs ? ComputeEigenvectors : EigenvaluesOnly);
+
+ // transform back the eigen vectors: evecs = L * evecs
+ if(computeEigVecs)
+ Base::m_eivec = cholB.matrixL() * Base::m_eivec;
+ }
+
+ return *this;
+}
+
+} // end namespace Eigen
+
+#endif // EIGEN_GENERALIZEDSELFADJOINTEIGENSOLVER_H
diff --git a/Eigen/src/Eigenvalues/HessenbergDecomposition.h b/Eigen/src/Eigenvalues/HessenbergDecomposition.h
new file mode 100644
index 000000000..b8378b08a
--- /dev/null
+++ b/Eigen/src/Eigenvalues/HessenbergDecomposition.h
@@ -0,0 +1,373 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra.
+//
+// Copyright (C) 2008-2009 Gael Guennebaud <gael.guennebaud@inria.fr>
+// Copyright (C) 2010 Jitse Niesen <jitse@maths.leeds.ac.uk>
+//
+// This Source Code Form is subject to the terms of the Mozilla
+// Public License v. 2.0. If a copy of the MPL was not distributed
+// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+#ifndef EIGEN_HESSENBERGDECOMPOSITION_H
+#define EIGEN_HESSENBERGDECOMPOSITION_H
+
+namespace Eigen {
+
+namespace internal {
+
+template<typename MatrixType> struct HessenbergDecompositionMatrixHReturnType;
+template<typename MatrixType>
+struct traits<HessenbergDecompositionMatrixHReturnType<MatrixType> >
+{
+ typedef MatrixType ReturnType;
+};
+
+}
+
+/** \eigenvalues_module \ingroup Eigenvalues_Module
+ *
+ *
+ * \class HessenbergDecomposition
+ *
+ * \brief Reduces a square matrix to Hessenberg form by an orthogonal similarity transformation
+ *
+ * \tparam _MatrixType the type of the matrix of which we are computing the Hessenberg decomposition
+ *
+ * This class performs an Hessenberg decomposition of a matrix \f$ A \f$. In
+ * the real case, the Hessenberg decomposition consists of an orthogonal
+ * matrix \f$ Q \f$ and a Hessenberg matrix \f$ H \f$ such that \f$ A = Q H
+ * Q^T \f$. An orthogonal matrix is a matrix whose inverse equals its
+ * transpose (\f$ Q^{-1} = Q^T \f$). A Hessenberg matrix has zeros below the
+ * subdiagonal, so it is almost upper triangular. The Hessenberg decomposition
+ * of a complex matrix is \f$ A = Q H Q^* \f$ with \f$ Q \f$ unitary (that is,
+ * \f$ Q^{-1} = Q^* \f$).
+ *
+ * Call the function compute() to compute the Hessenberg decomposition of a
+ * given matrix. Alternatively, you can use the
+ * HessenbergDecomposition(const MatrixType&) constructor which computes the
+ * Hessenberg decomposition at construction time. Once the decomposition is
+ * computed, you can use the matrixH() and matrixQ() functions to construct
+ * the matrices H and Q in the decomposition.
+ *
+ * The documentation for matrixH() contains an example of the typical use of
+ * this class.
+ *
+ * \sa class ComplexSchur, class Tridiagonalization, \ref QR_Module "QR Module"
+ */
+template<typename _MatrixType> class HessenbergDecomposition
+{
+ public:
+
+ /** \brief Synonym for the template parameter \p _MatrixType. */
+ typedef _MatrixType MatrixType;
+
+ enum {
+ Size = MatrixType::RowsAtCompileTime,
+ SizeMinusOne = Size == Dynamic ? Dynamic : Size - 1,
+ Options = MatrixType::Options,
+ MaxSize = MatrixType::MaxRowsAtCompileTime,
+ MaxSizeMinusOne = MaxSize == Dynamic ? Dynamic : MaxSize - 1
+ };
+
+ /** \brief Scalar type for matrices of type #MatrixType. */
+ typedef typename MatrixType::Scalar Scalar;
+ typedef typename MatrixType::Index Index;
+
+ /** \brief Type for vector of Householder coefficients.
+ *
+ * This is column vector with entries of type #Scalar. The length of the
+ * vector is one less than the size of #MatrixType, if it is a fixed-side
+ * type.
+ */
+ typedef Matrix<Scalar, SizeMinusOne, 1, Options & ~RowMajor, MaxSizeMinusOne, 1> CoeffVectorType;
+
+ /** \brief Return type of matrixQ() */
+ typedef typename HouseholderSequence<MatrixType,CoeffVectorType>::ConjugateReturnType HouseholderSequenceType;
+
+ typedef internal::HessenbergDecompositionMatrixHReturnType<MatrixType> MatrixHReturnType;
+
+ /** \brief Default constructor; the decomposition will be computed later.
+ *
+ * \param [in] size The size of the matrix whose Hessenberg decomposition will be computed.
+ *
+ * The default constructor is useful in cases in which the user intends to
+ * perform decompositions via compute(). The \p size parameter is only
+ * used as a hint. It is not an error to give a wrong \p size, but it may
+ * impair performance.
+ *
+ * \sa compute() for an example.
+ */
+ HessenbergDecomposition(Index size = Size==Dynamic ? 2 : Size)
+ : m_matrix(size,size),
+ m_temp(size),
+ m_isInitialized(false)
+ {
+ if(size>1)
+ m_hCoeffs.resize(size-1);
+ }
+
+ /** \brief Constructor; computes Hessenberg decomposition of given matrix.
+ *
+ * \param[in] matrix Square matrix whose Hessenberg decomposition is to be computed.
+ *
+ * This constructor calls compute() to compute the Hessenberg
+ * decomposition.
+ *
+ * \sa matrixH() for an example.
+ */
+ HessenbergDecomposition(const MatrixType& matrix)
+ : m_matrix(matrix),
+ m_temp(matrix.rows()),
+ m_isInitialized(false)
+ {
+ if(matrix.rows()<2)
+ {
+ m_isInitialized = true;
+ return;
+ }
+ m_hCoeffs.resize(matrix.rows()-1,1);
+ _compute(m_matrix, m_hCoeffs, m_temp);
+ m_isInitialized = true;
+ }
+
+ /** \brief Computes Hessenberg decomposition of given matrix.
+ *
+ * \param[in] matrix Square matrix whose Hessenberg decomposition is to be computed.
+ * \returns Reference to \c *this
+ *
+ * The Hessenberg decomposition is computed by bringing the columns of the
+ * matrix successively in the required form using Householder reflections
+ * (see, e.g., Algorithm 7.4.2 in Golub \& Van Loan, <i>%Matrix
+ * Computations</i>). The cost is \f$ 10n^3/3 \f$ flops, where \f$ n \f$
+ * denotes the size of the given matrix.
+ *
+ * This method reuses of the allocated data in the HessenbergDecomposition
+ * object.
+ *
+ * Example: \include HessenbergDecomposition_compute.cpp
+ * Output: \verbinclude HessenbergDecomposition_compute.out
+ */
+ HessenbergDecomposition& compute(const MatrixType& matrix)
+ {
+ m_matrix = matrix;
+ if(matrix.rows()<2)
+ {
+ m_isInitialized = true;
+ return *this;
+ }
+ m_hCoeffs.resize(matrix.rows()-1,1);
+ _compute(m_matrix, m_hCoeffs, m_temp);
+ m_isInitialized = true;
+ return *this;
+ }
+
+ /** \brief Returns the Householder coefficients.
+ *
+ * \returns a const reference to the vector of Householder coefficients
+ *
+ * \pre Either the constructor HessenbergDecomposition(const MatrixType&)
+ * or the member function compute(const MatrixType&) has been called
+ * before to compute the Hessenberg decomposition of a matrix.
+ *
+ * The Householder coefficients allow the reconstruction of the matrix
+ * \f$ Q \f$ in the Hessenberg decomposition from the packed data.
+ *
+ * \sa packedMatrix(), \ref Householder_Module "Householder module"
+ */
+ const CoeffVectorType& householderCoefficients() const
+ {
+ eigen_assert(m_isInitialized && "HessenbergDecomposition is not initialized.");
+ return m_hCoeffs;
+ }
+
+ /** \brief Returns the internal representation of the decomposition
+ *
+ * \returns a const reference to a matrix with the internal representation
+ * of the decomposition.
+ *
+ * \pre Either the constructor HessenbergDecomposition(const MatrixType&)
+ * or the member function compute(const MatrixType&) has been called
+ * before to compute the Hessenberg decomposition of a matrix.
+ *
+ * The returned matrix contains the following information:
+ * - the upper part and lower sub-diagonal represent the Hessenberg matrix H
+ * - the rest of the lower part contains the Householder vectors that, combined with
+ * Householder coefficients returned by householderCoefficients(),
+ * allows to reconstruct the matrix Q as
+ * \f$ Q = H_{N-1} \ldots H_1 H_0 \f$.
+ * Here, the matrices \f$ H_i \f$ are the Householder transformations
+ * \f$ H_i = (I - h_i v_i v_i^T) \f$
+ * where \f$ h_i \f$ is the \f$ i \f$th Householder coefficient and
+ * \f$ v_i \f$ is the Householder vector defined by
+ * \f$ v_i = [ 0, \ldots, 0, 1, M(i+2,i), \ldots, M(N-1,i) ]^T \f$
+ * with M the matrix returned by this function.
+ *
+ * See LAPACK for further details on this packed storage.
+ *
+ * Example: \include HessenbergDecomposition_packedMatrix.cpp
+ * Output: \verbinclude HessenbergDecomposition_packedMatrix.out
+ *
+ * \sa householderCoefficients()
+ */
+ const MatrixType& packedMatrix() const
+ {
+ eigen_assert(m_isInitialized && "HessenbergDecomposition is not initialized.");
+ return m_matrix;
+ }
+
+ /** \brief Reconstructs the orthogonal matrix Q in the decomposition
+ *
+ * \returns object representing the matrix Q
+ *
+ * \pre Either the constructor HessenbergDecomposition(const MatrixType&)
+ * or the member function compute(const MatrixType&) has been called
+ * before to compute the Hessenberg decomposition of a matrix.
+ *
+ * This function returns a light-weight object of template class
+ * HouseholderSequence. You can either apply it directly to a matrix or
+ * you can convert it to a matrix of type #MatrixType.
+ *
+ * \sa matrixH() for an example, class HouseholderSequence
+ */
+ HouseholderSequenceType matrixQ() const
+ {
+ eigen_assert(m_isInitialized && "HessenbergDecomposition is not initialized.");
+ return HouseholderSequenceType(m_matrix, m_hCoeffs.conjugate())
+ .setLength(m_matrix.rows() - 1)
+ .setShift(1);
+ }
+
+ /** \brief Constructs the Hessenberg matrix H in the decomposition
+ *
+ * \returns expression object representing the matrix H
+ *
+ * \pre Either the constructor HessenbergDecomposition(const MatrixType&)
+ * or the member function compute(const MatrixType&) has been called
+ * before to compute the Hessenberg decomposition of a matrix.
+ *
+ * The object returned by this function constructs the Hessenberg matrix H
+ * when it is assigned to a matrix or otherwise evaluated. The matrix H is
+ * constructed from the packed matrix as returned by packedMatrix(): The
+ * upper part (including the subdiagonal) of the packed matrix contains
+ * the matrix H. It may sometimes be better to directly use the packed
+ * matrix instead of constructing the matrix H.
+ *
+ * Example: \include HessenbergDecomposition_matrixH.cpp
+ * Output: \verbinclude HessenbergDecomposition_matrixH.out
+ *
+ * \sa matrixQ(), packedMatrix()
+ */
+ MatrixHReturnType matrixH() const
+ {
+ eigen_assert(m_isInitialized && "HessenbergDecomposition is not initialized.");
+ return MatrixHReturnType(*this);
+ }
+
+ private:
+
+ typedef Matrix<Scalar, 1, Size, Options | RowMajor, 1, MaxSize> VectorType;
+ typedef typename NumTraits<Scalar>::Real RealScalar;
+ static void _compute(MatrixType& matA, CoeffVectorType& hCoeffs, VectorType& temp);
+
+ protected:
+ MatrixType m_matrix;
+ CoeffVectorType m_hCoeffs;
+ VectorType m_temp;
+ bool m_isInitialized;
+};
+
+/** \internal
+ * Performs a tridiagonal decomposition of \a matA in place.
+ *
+ * \param matA the input selfadjoint matrix
+ * \param hCoeffs returned Householder coefficients
+ *
+ * The result is written in the lower triangular part of \a matA.
+ *
+ * Implemented from Golub's "%Matrix Computations", algorithm 8.3.1.
+ *
+ * \sa packedMatrix()
+ */
+template<typename MatrixType>
+void HessenbergDecomposition<MatrixType>::_compute(MatrixType& matA, CoeffVectorType& hCoeffs, VectorType& temp)
+{
+ assert(matA.rows()==matA.cols());
+ Index n = matA.rows();
+ temp.resize(n);
+ for (Index i = 0; i<n-1; ++i)
+ {
+ // let's consider the vector v = i-th column starting at position i+1
+ Index remainingSize = n-i-1;
+ RealScalar beta;
+ Scalar h;
+ matA.col(i).tail(remainingSize).makeHouseholderInPlace(h, beta);
+ matA.col(i).coeffRef(i+1) = beta;
+ hCoeffs.coeffRef(i) = h;
+
+ // Apply similarity transformation to remaining columns,
+ // i.e., compute A = H A H'
+
+ // A = H A
+ matA.bottomRightCorner(remainingSize, remainingSize)
+ .applyHouseholderOnTheLeft(matA.col(i).tail(remainingSize-1), h, &temp.coeffRef(0));
+
+ // A = A H'
+ matA.rightCols(remainingSize)
+ .applyHouseholderOnTheRight(matA.col(i).tail(remainingSize-1).conjugate(), internal::conj(h), &temp.coeffRef(0));
+ }
+}
+
+namespace internal {
+
+/** \eigenvalues_module \ingroup Eigenvalues_Module
+ *
+ *
+ * \brief Expression type for return value of HessenbergDecomposition::matrixH()
+ *
+ * \tparam MatrixType type of matrix in the Hessenberg decomposition
+ *
+ * Objects of this type represent the Hessenberg matrix in the Hessenberg
+ * decomposition of some matrix. The object holds a reference to the
+ * HessenbergDecomposition class until the it is assigned or evaluated for
+ * some other reason (the reference should remain valid during the life time
+ * of this object). This class is the return type of
+ * HessenbergDecomposition::matrixH(); there is probably no other use for this
+ * class.
+ */
+template<typename MatrixType> struct HessenbergDecompositionMatrixHReturnType
+: public ReturnByValue<HessenbergDecompositionMatrixHReturnType<MatrixType> >
+{
+ typedef typename MatrixType::Index Index;
+ public:
+ /** \brief Constructor.
+ *
+ * \param[in] hess Hessenberg decomposition
+ */
+ HessenbergDecompositionMatrixHReturnType(const HessenbergDecomposition<MatrixType>& hess) : m_hess(hess) { }
+
+ /** \brief Hessenberg matrix in decomposition.
+ *
+ * \param[out] result Hessenberg matrix in decomposition \p hess which
+ * was passed to the constructor
+ */
+ template <typename ResultType>
+ inline void evalTo(ResultType& result) const
+ {
+ result = m_hess.packedMatrix();
+ Index n = result.rows();
+ if (n>2)
+ result.bottomLeftCorner(n-2, n-2).template triangularView<Lower>().setZero();
+ }
+
+ Index rows() const { return m_hess.packedMatrix().rows(); }
+ Index cols() const { return m_hess.packedMatrix().cols(); }
+
+ protected:
+ const HessenbergDecomposition<MatrixType>& m_hess;
+};
+
+} // end namespace internal
+
+} // end namespace Eigen
+
+#endif // EIGEN_HESSENBERGDECOMPOSITION_H
diff --git a/Eigen/src/Eigenvalues/MatrixBaseEigenvalues.h b/Eigen/src/Eigenvalues/MatrixBaseEigenvalues.h
new file mode 100644
index 000000000..6af481c75
--- /dev/null
+++ b/Eigen/src/Eigenvalues/MatrixBaseEigenvalues.h
@@ -0,0 +1,159 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra.
+//
+// Copyright (C) 2008 Gael Guennebaud <gael.guennebaud@inria.fr>
+// Copyright (C) 2010 Jitse Niesen <jitse@maths.leeds.ac.uk>
+//
+// This Source Code Form is subject to the terms of the Mozilla
+// Public License v. 2.0. If a copy of the MPL was not distributed
+// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+#ifndef EIGEN_MATRIXBASEEIGENVALUES_H
+#define EIGEN_MATRIXBASEEIGENVALUES_H
+
+namespace Eigen {
+
+namespace internal {
+
+template<typename Derived, bool IsComplex>
+struct eigenvalues_selector
+{
+ // this is the implementation for the case IsComplex = true
+ static inline typename MatrixBase<Derived>::EigenvaluesReturnType const
+ run(const MatrixBase<Derived>& m)
+ {
+ typedef typename Derived::PlainObject PlainObject;
+ PlainObject m_eval(m);
+ return ComplexEigenSolver<PlainObject>(m_eval, false).eigenvalues();
+ }
+};
+
+template<typename Derived>
+struct eigenvalues_selector<Derived, false>
+{
+ static inline typename MatrixBase<Derived>::EigenvaluesReturnType const
+ run(const MatrixBase<Derived>& m)
+ {
+ typedef typename Derived::PlainObject PlainObject;
+ PlainObject m_eval(m);
+ return EigenSolver<PlainObject>(m_eval, false).eigenvalues();
+ }
+};
+
+} // end namespace internal
+
+/** \brief Computes the eigenvalues of a matrix
+ * \returns Column vector containing the eigenvalues.
+ *
+ * \eigenvalues_module
+ * This function computes the eigenvalues with the help of the EigenSolver
+ * class (for real matrices) or the ComplexEigenSolver class (for complex
+ * matrices).
+ *
+ * The eigenvalues are repeated according to their algebraic multiplicity,
+ * so there are as many eigenvalues as rows in the matrix.
+ *
+ * The SelfAdjointView class provides a better algorithm for selfadjoint
+ * matrices.
+ *
+ * Example: \include MatrixBase_eigenvalues.cpp
+ * Output: \verbinclude MatrixBase_eigenvalues.out
+ *
+ * \sa EigenSolver::eigenvalues(), ComplexEigenSolver::eigenvalues(),
+ * SelfAdjointView::eigenvalues()
+ */
+template<typename Derived>
+inline typename MatrixBase<Derived>::EigenvaluesReturnType
+MatrixBase<Derived>::eigenvalues() const
+{
+ typedef typename internal::traits<Derived>::Scalar Scalar;
+ return internal::eigenvalues_selector<Derived, NumTraits<Scalar>::IsComplex>::run(derived());
+}
+
+/** \brief Computes the eigenvalues of a matrix
+ * \returns Column vector containing the eigenvalues.
+ *
+ * \eigenvalues_module
+ * This function computes the eigenvalues with the help of the
+ * SelfAdjointEigenSolver class. The eigenvalues are repeated according to
+ * their algebraic multiplicity, so there are as many eigenvalues as rows in
+ * the matrix.
+ *
+ * Example: \include SelfAdjointView_eigenvalues.cpp
+ * Output: \verbinclude SelfAdjointView_eigenvalues.out
+ *
+ * \sa SelfAdjointEigenSolver::eigenvalues(), MatrixBase::eigenvalues()
+ */
+template<typename MatrixType, unsigned int UpLo>
+inline typename SelfAdjointView<MatrixType, UpLo>::EigenvaluesReturnType
+SelfAdjointView<MatrixType, UpLo>::eigenvalues() const
+{
+ typedef typename SelfAdjointView<MatrixType, UpLo>::PlainObject PlainObject;
+ PlainObject thisAsMatrix(*this);
+ return SelfAdjointEigenSolver<PlainObject>(thisAsMatrix, false).eigenvalues();
+}
+
+
+
+/** \brief Computes the L2 operator norm
+ * \returns Operator norm of the matrix.
+ *
+ * \eigenvalues_module
+ * This function computes the L2 operator norm of a matrix, which is also
+ * known as the spectral norm. The norm of a matrix \f$ A \f$ is defined to be
+ * \f[ \|A\|_2 = \max_x \frac{\|Ax\|_2}{\|x\|_2} \f]
+ * where the maximum is over all vectors and the norm on the right is the
+ * Euclidean vector norm. The norm equals the largest singular value, which is
+ * the square root of the largest eigenvalue of the positive semi-definite
+ * matrix \f$ A^*A \f$.
+ *
+ * The current implementation uses the eigenvalues of \f$ A^*A \f$, as computed
+ * by SelfAdjointView::eigenvalues(), to compute the operator norm of a
+ * matrix. The SelfAdjointView class provides a better algorithm for
+ * selfadjoint matrices.
+ *
+ * Example: \include MatrixBase_operatorNorm.cpp
+ * Output: \verbinclude MatrixBase_operatorNorm.out
+ *
+ * \sa SelfAdjointView::eigenvalues(), SelfAdjointView::operatorNorm()
+ */
+template<typename Derived>
+inline typename MatrixBase<Derived>::RealScalar
+MatrixBase<Derived>::operatorNorm() const
+{
+ typename Derived::PlainObject m_eval(derived());
+ // FIXME if it is really guaranteed that the eigenvalues are already sorted,
+ // then we don't need to compute a maxCoeff() here, comparing the 1st and last ones is enough.
+ return internal::sqrt((m_eval*m_eval.adjoint())
+ .eval()
+ .template selfadjointView<Lower>()
+ .eigenvalues()
+ .maxCoeff()
+ );
+}
+
+/** \brief Computes the L2 operator norm
+ * \returns Operator norm of the matrix.
+ *
+ * \eigenvalues_module
+ * This function computes the L2 operator norm of a self-adjoint matrix. For a
+ * self-adjoint matrix, the operator norm is the largest eigenvalue.
+ *
+ * The current implementation uses the eigenvalues of the matrix, as computed
+ * by eigenvalues(), to compute the operator norm of the matrix.
+ *
+ * Example: \include SelfAdjointView_operatorNorm.cpp
+ * Output: \verbinclude SelfAdjointView_operatorNorm.out
+ *
+ * \sa eigenvalues(), MatrixBase::operatorNorm()
+ */
+template<typename MatrixType, unsigned int UpLo>
+inline typename SelfAdjointView<MatrixType, UpLo>::RealScalar
+SelfAdjointView<MatrixType, UpLo>::operatorNorm() const
+{
+ return eigenvalues().cwiseAbs().maxCoeff();
+}
+
+} // end namespace Eigen
+
+#endif
diff --git a/Eigen/src/Eigenvalues/RealSchur.h b/Eigen/src/Eigenvalues/RealSchur.h
new file mode 100644
index 000000000..781692ecc
--- /dev/null
+++ b/Eigen/src/Eigenvalues/RealSchur.h
@@ -0,0 +1,464 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra.
+//
+// Copyright (C) 2008 Gael Guennebaud <gael.guennebaud@inria.fr>
+// Copyright (C) 2010 Jitse Niesen <jitse@maths.leeds.ac.uk>
+//
+// This Source Code Form is subject to the terms of the Mozilla
+// Public License v. 2.0. If a copy of the MPL was not distributed
+// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+#ifndef EIGEN_REAL_SCHUR_H
+#define EIGEN_REAL_SCHUR_H
+
+#include "./HessenbergDecomposition.h"
+
+namespace Eigen {
+
+/** \eigenvalues_module \ingroup Eigenvalues_Module
+ *
+ *
+ * \class RealSchur
+ *
+ * \brief Performs a real Schur decomposition of a square matrix
+ *
+ * \tparam _MatrixType the type of the matrix of which we are computing the
+ * real Schur decomposition; this is expected to be an instantiation of the
+ * Matrix class template.
+ *
+ * Given a real square matrix A, this class computes the real Schur
+ * decomposition: \f$ A = U T U^T \f$ where U is a real orthogonal matrix and
+ * T is a real quasi-triangular matrix. An orthogonal matrix is a matrix whose
+ * inverse is equal to its transpose, \f$ U^{-1} = U^T \f$. A quasi-triangular
+ * matrix is a block-triangular matrix whose diagonal consists of 1-by-1
+ * blocks and 2-by-2 blocks with complex eigenvalues. The eigenvalues of the
+ * blocks on the diagonal of T are the same as the eigenvalues of the matrix
+ * A, and thus the real Schur decomposition is used in EigenSolver to compute
+ * the eigendecomposition of a matrix.
+ *
+ * Call the function compute() to compute the real Schur decomposition of a
+ * given matrix. Alternatively, you can use the RealSchur(const MatrixType&, bool)
+ * constructor which computes the real Schur decomposition at construction
+ * time. Once the decomposition is computed, you can use the matrixU() and
+ * matrixT() functions to retrieve the matrices U and T in the decomposition.
+ *
+ * The documentation of RealSchur(const MatrixType&, bool) contains an example
+ * of the typical use of this class.
+ *
+ * \note The implementation is adapted from
+ * <a href="http://math.nist.gov/javanumerics/jama/">JAMA</a> (public domain).
+ * Their code is based on EISPACK.
+ *
+ * \sa class ComplexSchur, class EigenSolver, class ComplexEigenSolver
+ */
+template<typename _MatrixType> class RealSchur
+{
+ public:
+ typedef _MatrixType MatrixType;
+ enum {
+ RowsAtCompileTime = MatrixType::RowsAtCompileTime,
+ ColsAtCompileTime = MatrixType::ColsAtCompileTime,
+ Options = MatrixType::Options,
+ MaxRowsAtCompileTime = MatrixType::MaxRowsAtCompileTime,
+ MaxColsAtCompileTime = MatrixType::MaxColsAtCompileTime
+ };
+ typedef typename MatrixType::Scalar Scalar;
+ typedef std::complex<typename NumTraits<Scalar>::Real> ComplexScalar;
+ typedef typename MatrixType::Index Index;
+
+ typedef Matrix<ComplexScalar, ColsAtCompileTime, 1, Options & ~RowMajor, MaxColsAtCompileTime, 1> EigenvalueType;
+ typedef Matrix<Scalar, ColsAtCompileTime, 1, Options & ~RowMajor, MaxColsAtCompileTime, 1> ColumnVectorType;
+
+ /** \brief Default constructor.
+ *
+ * \param [in] size Positive integer, size of the matrix whose Schur decomposition will be computed.
+ *
+ * The default constructor is useful in cases in which the user intends to
+ * perform decompositions via compute(). The \p size parameter is only
+ * used as a hint. It is not an error to give a wrong \p size, but it may
+ * impair performance.
+ *
+ * \sa compute() for an example.
+ */
+ RealSchur(Index size = RowsAtCompileTime==Dynamic ? 1 : RowsAtCompileTime)
+ : m_matT(size, size),
+ m_matU(size, size),
+ m_workspaceVector(size),
+ m_hess(size),
+ m_isInitialized(false),
+ m_matUisUptodate(false)
+ { }
+
+ /** \brief Constructor; computes real Schur decomposition of given matrix.
+ *
+ * \param[in] matrix Square matrix whose Schur decomposition is to be computed.
+ * \param[in] computeU If true, both T and U are computed; if false, only T is computed.
+ *
+ * This constructor calls compute() to compute the Schur decomposition.
+ *
+ * Example: \include RealSchur_RealSchur_MatrixType.cpp
+ * Output: \verbinclude RealSchur_RealSchur_MatrixType.out
+ */
+ RealSchur(const MatrixType& matrix, bool computeU = true)
+ : m_matT(matrix.rows(),matrix.cols()),
+ m_matU(matrix.rows(),matrix.cols()),
+ m_workspaceVector(matrix.rows()),
+ m_hess(matrix.rows()),
+ m_isInitialized(false),
+ m_matUisUptodate(false)
+ {
+ compute(matrix, computeU);
+ }
+
+ /** \brief Returns the orthogonal matrix in the Schur decomposition.
+ *
+ * \returns A const reference to the matrix U.
+ *
+ * \pre Either the constructor RealSchur(const MatrixType&, bool) or the
+ * member function compute(const MatrixType&, bool) has been called before
+ * to compute the Schur decomposition of a matrix, and \p computeU was set
+ * to true (the default value).
+ *
+ * \sa RealSchur(const MatrixType&, bool) for an example
+ */
+ const MatrixType& matrixU() const
+ {
+ eigen_assert(m_isInitialized && "RealSchur is not initialized.");
+ eigen_assert(m_matUisUptodate && "The matrix U has not been computed during the RealSchur decomposition.");
+ return m_matU;
+ }
+
+ /** \brief Returns the quasi-triangular matrix in the Schur decomposition.
+ *
+ * \returns A const reference to the matrix T.
+ *
+ * \pre Either the constructor RealSchur(const MatrixType&, bool) or the
+ * member function compute(const MatrixType&, bool) has been called before
+ * to compute the Schur decomposition of a matrix.
+ *
+ * \sa RealSchur(const MatrixType&, bool) for an example
+ */
+ const MatrixType& matrixT() const
+ {
+ eigen_assert(m_isInitialized && "RealSchur is not initialized.");
+ return m_matT;
+ }
+
+ /** \brief Computes Schur decomposition of given matrix.
+ *
+ * \param[in] matrix Square matrix whose Schur decomposition is to be computed.
+ * \param[in] computeU If true, both T and U are computed; if false, only T is computed.
+ * \returns Reference to \c *this
+ *
+ * The Schur decomposition is computed by first reducing the matrix to
+ * Hessenberg form using the class HessenbergDecomposition. The Hessenberg
+ * matrix is then reduced to triangular form by performing Francis QR
+ * iterations with implicit double shift. The cost of computing the Schur
+ * decomposition depends on the number of iterations; as a rough guide, it
+ * may be taken to be \f$25n^3\f$ flops if \a computeU is true and
+ * \f$10n^3\f$ flops if \a computeU is false.
+ *
+ * Example: \include RealSchur_compute.cpp
+ * Output: \verbinclude RealSchur_compute.out
+ */
+ RealSchur& compute(const MatrixType& matrix, bool computeU = true);
+
+ /** \brief Reports whether previous computation was successful.
+ *
+ * \returns \c Success if computation was succesful, \c NoConvergence otherwise.
+ */
+ ComputationInfo info() const
+ {
+ eigen_assert(m_isInitialized && "RealSchur is not initialized.");
+ return m_info;
+ }
+
+ /** \brief Maximum number of iterations.
+ *
+ * Maximum number of iterations allowed for an eigenvalue to converge.
+ */
+ static const int m_maxIterations = 40;
+
+ private:
+
+ MatrixType m_matT;
+ MatrixType m_matU;
+ ColumnVectorType m_workspaceVector;
+ HessenbergDecomposition<MatrixType> m_hess;
+ ComputationInfo m_info;
+ bool m_isInitialized;
+ bool m_matUisUptodate;
+
+ typedef Matrix<Scalar,3,1> Vector3s;
+
+ Scalar computeNormOfT();
+ Index findSmallSubdiagEntry(Index iu, Scalar norm);
+ void splitOffTwoRows(Index iu, bool computeU, Scalar exshift);
+ void computeShift(Index iu, Index iter, Scalar& exshift, Vector3s& shiftInfo);
+ void initFrancisQRStep(Index il, Index iu, const Vector3s& shiftInfo, Index& im, Vector3s& firstHouseholderVector);
+ void performFrancisQRStep(Index il, Index im, Index iu, bool computeU, const Vector3s& firstHouseholderVector, Scalar* workspace);
+};
+
+
+template<typename MatrixType>
+RealSchur<MatrixType>& RealSchur<MatrixType>::compute(const MatrixType& matrix, bool computeU)
+{
+ assert(matrix.cols() == matrix.rows());
+
+ // Step 1. Reduce to Hessenberg form
+ m_hess.compute(matrix);
+ m_matT = m_hess.matrixH();
+ if (computeU)
+ m_matU = m_hess.matrixQ();
+
+ // Step 2. Reduce to real Schur form
+ m_workspaceVector.resize(m_matT.cols());
+ Scalar* workspace = &m_workspaceVector.coeffRef(0);
+
+ // The matrix m_matT is divided in three parts.
+ // Rows 0,...,il-1 are decoupled from the rest because m_matT(il,il-1) is zero.
+ // Rows il,...,iu is the part we are working on (the active window).
+ // Rows iu+1,...,end are already brought in triangular form.
+ Index iu = m_matT.cols() - 1;
+ Index iter = 0; // iteration count
+ Scalar exshift(0); // sum of exceptional shifts
+ Scalar norm = computeNormOfT();
+
+ if(norm!=0)
+ {
+ while (iu >= 0)
+ {
+ Index il = findSmallSubdiagEntry(iu, norm);
+
+ // Check for convergence
+ if (il == iu) // One root found
+ {
+ m_matT.coeffRef(iu,iu) = m_matT.coeff(iu,iu) + exshift;
+ if (iu > 0)
+ m_matT.coeffRef(iu, iu-1) = Scalar(0);
+ iu--;
+ iter = 0;
+ }
+ else if (il == iu-1) // Two roots found
+ {
+ splitOffTwoRows(iu, computeU, exshift);
+ iu -= 2;
+ iter = 0;
+ }
+ else // No convergence yet
+ {
+ // The firstHouseholderVector vector has to be initialized to something to get rid of a silly GCC warning (-O1 -Wall -DNDEBUG )
+ Vector3s firstHouseholderVector(0,0,0), shiftInfo;
+ computeShift(iu, iter, exshift, shiftInfo);
+ iter = iter + 1;
+ if (iter > m_maxIterations * m_matT.cols()) break;
+ Index im;
+ initFrancisQRStep(il, iu, shiftInfo, im, firstHouseholderVector);
+ performFrancisQRStep(il, im, iu, computeU, firstHouseholderVector, workspace);
+ }
+ }
+ }
+ if(iter <= m_maxIterations * m_matT.cols())
+ m_info = Success;
+ else
+ m_info = NoConvergence;
+
+ m_isInitialized = true;
+ m_matUisUptodate = computeU;
+ return *this;
+}
+
+/** \internal Computes and returns vector L1 norm of T */
+template<typename MatrixType>
+inline typename MatrixType::Scalar RealSchur<MatrixType>::computeNormOfT()
+{
+ const Index size = m_matT.cols();
+ // FIXME to be efficient the following would requires a triangular reduxion code
+ // Scalar norm = m_matT.upper().cwiseAbs().sum()
+ // + m_matT.bottomLeftCorner(size-1,size-1).diagonal().cwiseAbs().sum();
+ Scalar norm(0);
+ for (Index j = 0; j < size; ++j)
+ norm += m_matT.row(j).segment((std::max)(j-1,Index(0)), size-(std::max)(j-1,Index(0))).cwiseAbs().sum();
+ return norm;
+}
+
+/** \internal Look for single small sub-diagonal element and returns its index */
+template<typename MatrixType>
+inline typename MatrixType::Index RealSchur<MatrixType>::findSmallSubdiagEntry(Index iu, Scalar norm)
+{
+ Index res = iu;
+ while (res > 0)
+ {
+ Scalar s = internal::abs(m_matT.coeff(res-1,res-1)) + internal::abs(m_matT.coeff(res,res));
+ if (s == 0.0)
+ s = norm;
+ if (internal::abs(m_matT.coeff(res,res-1)) < NumTraits<Scalar>::epsilon() * s)
+ break;
+ res--;
+ }
+ return res;
+}
+
+/** \internal Update T given that rows iu-1 and iu decouple from the rest. */
+template<typename MatrixType>
+inline void RealSchur<MatrixType>::splitOffTwoRows(Index iu, bool computeU, Scalar exshift)
+{
+ const Index size = m_matT.cols();
+
+ // The eigenvalues of the 2x2 matrix [a b; c d] are
+ // trace +/- sqrt(discr/4) where discr = tr^2 - 4*det, tr = a + d, det = ad - bc
+ Scalar p = Scalar(0.5) * (m_matT.coeff(iu-1,iu-1) - m_matT.coeff(iu,iu));
+ Scalar q = p * p + m_matT.coeff(iu,iu-1) * m_matT.coeff(iu-1,iu); // q = tr^2 / 4 - det = discr/4
+ m_matT.coeffRef(iu,iu) += exshift;
+ m_matT.coeffRef(iu-1,iu-1) += exshift;
+
+ if (q >= Scalar(0)) // Two real eigenvalues
+ {
+ Scalar z = internal::sqrt(internal::abs(q));
+ JacobiRotation<Scalar> rot;
+ if (p >= Scalar(0))
+ rot.makeGivens(p + z, m_matT.coeff(iu, iu-1));
+ else
+ rot.makeGivens(p - z, m_matT.coeff(iu, iu-1));
+
+ m_matT.rightCols(size-iu+1).applyOnTheLeft(iu-1, iu, rot.adjoint());
+ m_matT.topRows(iu+1).applyOnTheRight(iu-1, iu, rot);
+ m_matT.coeffRef(iu, iu-1) = Scalar(0);
+ if (computeU)
+ m_matU.applyOnTheRight(iu-1, iu, rot);
+ }
+
+ if (iu > 1)
+ m_matT.coeffRef(iu-1, iu-2) = Scalar(0);
+}
+
+/** \internal Form shift in shiftInfo, and update exshift if an exceptional shift is performed. */
+template<typename MatrixType>
+inline void RealSchur<MatrixType>::computeShift(Index iu, Index iter, Scalar& exshift, Vector3s& shiftInfo)
+{
+ shiftInfo.coeffRef(0) = m_matT.coeff(iu,iu);
+ shiftInfo.coeffRef(1) = m_matT.coeff(iu-1,iu-1);
+ shiftInfo.coeffRef(2) = m_matT.coeff(iu,iu-1) * m_matT.coeff(iu-1,iu);
+
+ // Wilkinson's original ad hoc shift
+ if (iter == 10)
+ {
+ exshift += shiftInfo.coeff(0);
+ for (Index i = 0; i <= iu; ++i)
+ m_matT.coeffRef(i,i) -= shiftInfo.coeff(0);
+ Scalar s = internal::abs(m_matT.coeff(iu,iu-1)) + internal::abs(m_matT.coeff(iu-1,iu-2));
+ shiftInfo.coeffRef(0) = Scalar(0.75) * s;
+ shiftInfo.coeffRef(1) = Scalar(0.75) * s;
+ shiftInfo.coeffRef(2) = Scalar(-0.4375) * s * s;
+ }
+
+ // MATLAB's new ad hoc shift
+ if (iter == 30)
+ {
+ Scalar s = (shiftInfo.coeff(1) - shiftInfo.coeff(0)) / Scalar(2.0);
+ s = s * s + shiftInfo.coeff(2);
+ if (s > Scalar(0))
+ {
+ s = internal::sqrt(s);
+ if (shiftInfo.coeff(1) < shiftInfo.coeff(0))
+ s = -s;
+ s = s + (shiftInfo.coeff(1) - shiftInfo.coeff(0)) / Scalar(2.0);
+ s = shiftInfo.coeff(0) - shiftInfo.coeff(2) / s;
+ exshift += s;
+ for (Index i = 0; i <= iu; ++i)
+ m_matT.coeffRef(i,i) -= s;
+ shiftInfo.setConstant(Scalar(0.964));
+ }
+ }
+}
+
+/** \internal Compute index im at which Francis QR step starts and the first Householder vector. */
+template<typename MatrixType>
+inline void RealSchur<MatrixType>::initFrancisQRStep(Index il, Index iu, const Vector3s& shiftInfo, Index& im, Vector3s& firstHouseholderVector)
+{
+ Vector3s& v = firstHouseholderVector; // alias to save typing
+
+ for (im = iu-2; im >= il; --im)
+ {
+ const Scalar Tmm = m_matT.coeff(im,im);
+ const Scalar r = shiftInfo.coeff(0) - Tmm;
+ const Scalar s = shiftInfo.coeff(1) - Tmm;
+ v.coeffRef(0) = (r * s - shiftInfo.coeff(2)) / m_matT.coeff(im+1,im) + m_matT.coeff(im,im+1);
+ v.coeffRef(1) = m_matT.coeff(im+1,im+1) - Tmm - r - s;
+ v.coeffRef(2) = m_matT.coeff(im+2,im+1);
+ if (im == il) {
+ break;
+ }
+ const Scalar lhs = m_matT.coeff(im,im-1) * (internal::abs(v.coeff(1)) + internal::abs(v.coeff(2)));
+ const Scalar rhs = v.coeff(0) * (internal::abs(m_matT.coeff(im-1,im-1)) + internal::abs(Tmm) + internal::abs(m_matT.coeff(im+1,im+1)));
+ if (internal::abs(lhs) < NumTraits<Scalar>::epsilon() * rhs)
+ {
+ break;
+ }
+ }
+}
+
+/** \internal Perform a Francis QR step involving rows il:iu and columns im:iu. */
+template<typename MatrixType>
+inline void RealSchur<MatrixType>::performFrancisQRStep(Index il, Index im, Index iu, bool computeU, const Vector3s& firstHouseholderVector, Scalar* workspace)
+{
+ assert(im >= il);
+ assert(im <= iu-2);
+
+ const Index size = m_matT.cols();
+
+ for (Index k = im; k <= iu-2; ++k)
+ {
+ bool firstIteration = (k == im);
+
+ Vector3s v;
+ if (firstIteration)
+ v = firstHouseholderVector;
+ else
+ v = m_matT.template block<3,1>(k,k-1);
+
+ Scalar tau, beta;
+ Matrix<Scalar, 2, 1> ess;
+ v.makeHouseholder(ess, tau, beta);
+
+ if (beta != Scalar(0)) // if v is not zero
+ {
+ if (firstIteration && k > il)
+ m_matT.coeffRef(k,k-1) = -m_matT.coeff(k,k-1);
+ else if (!firstIteration)
+ m_matT.coeffRef(k,k-1) = beta;
+
+ // These Householder transformations form the O(n^3) part of the algorithm
+ m_matT.block(k, k, 3, size-k).applyHouseholderOnTheLeft(ess, tau, workspace);
+ m_matT.block(0, k, (std::min)(iu,k+3) + 1, 3).applyHouseholderOnTheRight(ess, tau, workspace);
+ if (computeU)
+ m_matU.block(0, k, size, 3).applyHouseholderOnTheRight(ess, tau, workspace);
+ }
+ }
+
+ Matrix<Scalar, 2, 1> v = m_matT.template block<2,1>(iu-1, iu-2);
+ Scalar tau, beta;
+ Matrix<Scalar, 1, 1> ess;
+ v.makeHouseholder(ess, tau, beta);
+
+ if (beta != Scalar(0)) // if v is not zero
+ {
+ m_matT.coeffRef(iu-1, iu-2) = beta;
+ m_matT.block(iu-1, iu-1, 2, size-iu+1).applyHouseholderOnTheLeft(ess, tau, workspace);
+ m_matT.block(0, iu-1, iu+1, 2).applyHouseholderOnTheRight(ess, tau, workspace);
+ if (computeU)
+ m_matU.block(0, iu-1, size, 2).applyHouseholderOnTheRight(ess, tau, workspace);
+ }
+
+ // clean up pollution due to round-off errors
+ for (Index i = im+2; i <= iu; ++i)
+ {
+ m_matT.coeffRef(i,i-2) = Scalar(0);
+ if (i > im+2)
+ m_matT.coeffRef(i,i-3) = Scalar(0);
+ }
+}
+
+} // end namespace Eigen
+
+#endif // EIGEN_REAL_SCHUR_H
diff --git a/Eigen/src/Eigenvalues/RealSchur_MKL.h b/Eigen/src/Eigenvalues/RealSchur_MKL.h
new file mode 100644
index 000000000..960ec3c76
--- /dev/null
+++ b/Eigen/src/Eigenvalues/RealSchur_MKL.h
@@ -0,0 +1,83 @@
+/*
+ Copyright (c) 2011, Intel Corporation. All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without modification,
+ are permitted provided that the following conditions are met:
+
+ * Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+ * Neither the name of Intel Corporation nor the names of its contributors may
+ be used to endorse or promote products derived from this software without
+ specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+ ********************************************************************************
+ * Content : Eigen bindings to Intel(R) MKL
+ * Real Schur needed to real unsymmetrical eigenvalues/eigenvectors.
+ ********************************************************************************
+*/
+
+#ifndef EIGEN_REAL_SCHUR_MKL_H
+#define EIGEN_REAL_SCHUR_MKL_H
+
+#include "Eigen/src/Core/util/MKL_support.h"
+
+namespace Eigen {
+
+/** \internal Specialization for the data types supported by MKL */
+
+#define EIGEN_MKL_SCHUR_REAL(EIGTYPE, MKLTYPE, MKLPREFIX, MKLPREFIX_U, EIGCOLROW, MKLCOLROW) \
+template<> inline \
+RealSchur<Matrix<EIGTYPE, Dynamic, Dynamic, EIGCOLROW> >& \
+RealSchur<Matrix<EIGTYPE, Dynamic, Dynamic, EIGCOLROW> >::compute(const Matrix<EIGTYPE, Dynamic, Dynamic, EIGCOLROW>& matrix, bool computeU) \
+{ \
+ typedef Matrix<EIGTYPE, Dynamic, Dynamic, EIGCOLROW> MatrixType; \
+ typedef MatrixType::Scalar Scalar; \
+ typedef MatrixType::RealScalar RealScalar; \
+\
+ assert(matrix.cols() == matrix.rows()); \
+\
+ lapack_int n = matrix.cols(), sdim, info; \
+ lapack_int lda = matrix.outerStride(); \
+ lapack_int matrix_order = MKLCOLROW; \
+ char jobvs, sort='N'; \
+ LAPACK_##MKLPREFIX_U##_SELECT2 select = 0; \
+ jobvs = (computeU) ? 'V' : 'N'; \
+ m_matU.resize(n, n); \
+ lapack_int ldvs = m_matU.outerStride(); \
+ m_matT = matrix; \
+ Matrix<EIGTYPE, Dynamic, Dynamic> wr, wi; \
+ wr.resize(n, 1); wi.resize(n, 1); \
+ info = LAPACKE_##MKLPREFIX##gees( matrix_order, jobvs, sort, select, n, (MKLTYPE*)m_matT.data(), lda, &sdim, (MKLTYPE*)wr.data(), (MKLTYPE*)wi.data(), (MKLTYPE*)m_matU.data(), ldvs ); \
+ if(info == 0) \
+ m_info = Success; \
+ else \
+ m_info = NoConvergence; \
+\
+ m_isInitialized = true; \
+ m_matUisUptodate = computeU; \
+ return *this; \
+\
+}
+
+EIGEN_MKL_SCHUR_REAL(double, double, d, D, ColMajor, LAPACK_COL_MAJOR)
+EIGEN_MKL_SCHUR_REAL(float, float, s, S, ColMajor, LAPACK_COL_MAJOR)
+EIGEN_MKL_SCHUR_REAL(double, double, d, D, RowMajor, LAPACK_ROW_MAJOR)
+EIGEN_MKL_SCHUR_REAL(float, float, s, S, RowMajor, LAPACK_ROW_MAJOR)
+
+} // end namespace Eigen
+
+#endif // EIGEN_REAL_SCHUR_MKL_H
diff --git a/Eigen/src/Eigenvalues/SelfAdjointEigenSolver.h b/Eigen/src/Eigenvalues/SelfAdjointEigenSolver.h
new file mode 100644
index 000000000..acc5576fe
--- /dev/null
+++ b/Eigen/src/Eigenvalues/SelfAdjointEigenSolver.h
@@ -0,0 +1,789 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra.
+//
+// Copyright (C) 2008-2010 Gael Guennebaud <gael.guennebaud@inria.fr>
+// Copyright (C) 2010 Jitse Niesen <jitse@maths.leeds.ac.uk>
+//
+// This Source Code Form is subject to the terms of the Mozilla
+// Public License v. 2.0. If a copy of the MPL was not distributed
+// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+#ifndef EIGEN_SELFADJOINTEIGENSOLVER_H
+#define EIGEN_SELFADJOINTEIGENSOLVER_H
+
+#include "./Tridiagonalization.h"
+
+namespace Eigen {
+
+template<typename _MatrixType>
+class GeneralizedSelfAdjointEigenSolver;
+
+namespace internal {
+template<typename SolverType,int Size,bool IsComplex> struct direct_selfadjoint_eigenvalues;
+}
+
+/** \eigenvalues_module \ingroup Eigenvalues_Module
+ *
+ *
+ * \class SelfAdjointEigenSolver
+ *
+ * \brief Computes eigenvalues and eigenvectors of selfadjoint matrices
+ *
+ * \tparam _MatrixType the type of the matrix of which we are computing the
+ * eigendecomposition; this is expected to be an instantiation of the Matrix
+ * class template.
+ *
+ * A matrix \f$ A \f$ is selfadjoint if it equals its adjoint. For real
+ * matrices, this means that the matrix is symmetric: it equals its
+ * transpose. This class computes the eigenvalues and eigenvectors of a
+ * selfadjoint matrix. These are the scalars \f$ \lambda \f$ and vectors
+ * \f$ v \f$ such that \f$ Av = \lambda v \f$. The eigenvalues of a
+ * selfadjoint matrix are always real. If \f$ D \f$ is a diagonal matrix with
+ * the eigenvalues on the diagonal, and \f$ V \f$ is a matrix with the
+ * eigenvectors as its columns, then \f$ A = V D V^{-1} \f$ (for selfadjoint
+ * matrices, the matrix \f$ V \f$ is always invertible). This is called the
+ * eigendecomposition.
+ *
+ * The algorithm exploits the fact that the matrix is selfadjoint, making it
+ * faster and more accurate than the general purpose eigenvalue algorithms
+ * implemented in EigenSolver and ComplexEigenSolver.
+ *
+ * Only the \b lower \b triangular \b part of the input matrix is referenced.
+ *
+ * Call the function compute() to compute the eigenvalues and eigenvectors of
+ * a given matrix. Alternatively, you can use the
+ * SelfAdjointEigenSolver(const MatrixType&, int) constructor which computes
+ * the eigenvalues and eigenvectors at construction time. Once the eigenvalue
+ * and eigenvectors are computed, they can be retrieved with the eigenvalues()
+ * and eigenvectors() functions.
+ *
+ * The documentation for SelfAdjointEigenSolver(const MatrixType&, int)
+ * contains an example of the typical use of this class.
+ *
+ * To solve the \em generalized eigenvalue problem \f$ Av = \lambda Bv \f$ and
+ * the likes, see the class GeneralizedSelfAdjointEigenSolver.
+ *
+ * \sa MatrixBase::eigenvalues(), class EigenSolver, class ComplexEigenSolver
+ */
+template<typename _MatrixType> class SelfAdjointEigenSolver
+{
+ public:
+
+ typedef _MatrixType MatrixType;
+ enum {
+ Size = MatrixType::RowsAtCompileTime,
+ ColsAtCompileTime = MatrixType::ColsAtCompileTime,
+ Options = MatrixType::Options,
+ MaxColsAtCompileTime = MatrixType::MaxColsAtCompileTime
+ };
+
+ /** \brief Scalar type for matrices of type \p _MatrixType. */
+ typedef typename MatrixType::Scalar Scalar;
+ typedef typename MatrixType::Index Index;
+
+ /** \brief Real scalar type for \p _MatrixType.
+ *
+ * This is just \c Scalar if #Scalar is real (e.g., \c float or
+ * \c double), and the type of the real part of \c Scalar if #Scalar is
+ * complex.
+ */
+ typedef typename NumTraits<Scalar>::Real RealScalar;
+
+ friend struct internal::direct_selfadjoint_eigenvalues<SelfAdjointEigenSolver,Size,NumTraits<Scalar>::IsComplex>;
+
+ /** \brief Type for vector of eigenvalues as returned by eigenvalues().
+ *
+ * This is a column vector with entries of type #RealScalar.
+ * The length of the vector is the size of \p _MatrixType.
+ */
+ typedef typename internal::plain_col_type<MatrixType, RealScalar>::type RealVectorType;
+ typedef Tridiagonalization<MatrixType> TridiagonalizationType;
+
+ /** \brief Default constructor for fixed-size matrices.
+ *
+ * The default constructor is useful in cases in which the user intends to
+ * perform decompositions via compute(). This constructor
+ * can only be used if \p _MatrixType is a fixed-size matrix; use
+ * SelfAdjointEigenSolver(Index) for dynamic-size matrices.
+ *
+ * Example: \include SelfAdjointEigenSolver_SelfAdjointEigenSolver.cpp
+ * Output: \verbinclude SelfAdjointEigenSolver_SelfAdjointEigenSolver.out
+ */
+ SelfAdjointEigenSolver()
+ : m_eivec(),
+ m_eivalues(),
+ m_subdiag(),
+ m_isInitialized(false)
+ { }
+
+ /** \brief Constructor, pre-allocates memory for dynamic-size matrices.
+ *
+ * \param [in] size Positive integer, size of the matrix whose
+ * eigenvalues and eigenvectors will be computed.
+ *
+ * This constructor is useful for dynamic-size matrices, when the user
+ * intends to perform decompositions via compute(). The \p size
+ * parameter is only used as a hint. It is not an error to give a wrong
+ * \p size, but it may impair performance.
+ *
+ * \sa compute() for an example
+ */
+ SelfAdjointEigenSolver(Index size)
+ : m_eivec(size, size),
+ m_eivalues(size),
+ m_subdiag(size > 1 ? size - 1 : 1),
+ m_isInitialized(false)
+ {}
+
+ /** \brief Constructor; computes eigendecomposition of given matrix.
+ *
+ * \param[in] matrix Selfadjoint matrix whose eigendecomposition is to
+ * be computed. Only the lower triangular part of the matrix is referenced.
+ * \param[in] options Can be #ComputeEigenvectors (default) or #EigenvaluesOnly.
+ *
+ * This constructor calls compute(const MatrixType&, int) to compute the
+ * eigenvalues of the matrix \p matrix. The eigenvectors are computed if
+ * \p options equals #ComputeEigenvectors.
+ *
+ * Example: \include SelfAdjointEigenSolver_SelfAdjointEigenSolver_MatrixType.cpp
+ * Output: \verbinclude SelfAdjointEigenSolver_SelfAdjointEigenSolver_MatrixType.out
+ *
+ * \sa compute(const MatrixType&, int)
+ */
+ SelfAdjointEigenSolver(const MatrixType& matrix, int options = ComputeEigenvectors)
+ : m_eivec(matrix.rows(), matrix.cols()),
+ m_eivalues(matrix.cols()),
+ m_subdiag(matrix.rows() > 1 ? matrix.rows() - 1 : 1),
+ m_isInitialized(false)
+ {
+ compute(matrix, options);
+ }
+
+ /** \brief Computes eigendecomposition of given matrix.
+ *
+ * \param[in] matrix Selfadjoint matrix whose eigendecomposition is to
+ * be computed. Only the lower triangular part of the matrix is referenced.
+ * \param[in] options Can be #ComputeEigenvectors (default) or #EigenvaluesOnly.
+ * \returns Reference to \c *this
+ *
+ * This function computes the eigenvalues of \p matrix. The eigenvalues()
+ * function can be used to retrieve them. If \p options equals #ComputeEigenvectors,
+ * then the eigenvectors are also computed and can be retrieved by
+ * calling eigenvectors().
+ *
+ * This implementation uses a symmetric QR algorithm. The matrix is first
+ * reduced to tridiagonal form using the Tridiagonalization class. The
+ * tridiagonal matrix is then brought to diagonal form with implicit
+ * symmetric QR steps with Wilkinson shift. Details can be found in
+ * Section 8.3 of Golub \& Van Loan, <i>%Matrix Computations</i>.
+ *
+ * The cost of the computation is about \f$ 9n^3 \f$ if the eigenvectors
+ * are required and \f$ 4n^3/3 \f$ if they are not required.
+ *
+ * This method reuses the memory in the SelfAdjointEigenSolver object that
+ * was allocated when the object was constructed, if the size of the
+ * matrix does not change.
+ *
+ * Example: \include SelfAdjointEigenSolver_compute_MatrixType.cpp
+ * Output: \verbinclude SelfAdjointEigenSolver_compute_MatrixType.out
+ *
+ * \sa SelfAdjointEigenSolver(const MatrixType&, int)
+ */
+ SelfAdjointEigenSolver& compute(const MatrixType& matrix, int options = ComputeEigenvectors);
+
+ /** \brief Computes eigendecomposition of given matrix using a direct algorithm
+ *
+ * This is a variant of compute(const MatrixType&, int options) which
+ * directly solves the underlying polynomial equation.
+ *
+ * Currently only 3x3 matrices for which the sizes are known at compile time are supported (e.g., Matrix3d).
+ *
+ * This method is usually significantly faster than the QR algorithm
+ * but it might also be less accurate. It is also worth noting that
+ * for 3x3 matrices it involves trigonometric operations which are
+ * not necessarily available for all scalar types.
+ *
+ * \sa compute(const MatrixType&, int options)
+ */
+ SelfAdjointEigenSolver& computeDirect(const MatrixType& matrix, int options = ComputeEigenvectors);
+
+ /** \brief Returns the eigenvectors of given matrix.
+ *
+ * \returns A const reference to the matrix whose columns are the eigenvectors.
+ *
+ * \pre The eigenvectors have been computed before.
+ *
+ * Column \f$ k \f$ of the returned matrix is an eigenvector corresponding
+ * to eigenvalue number \f$ k \f$ as returned by eigenvalues(). The
+ * eigenvectors are normalized to have (Euclidean) norm equal to one. If
+ * this object was used to solve the eigenproblem for the selfadjoint
+ * matrix \f$ A \f$, then the matrix returned by this function is the
+ * matrix \f$ V \f$ in the eigendecomposition \f$ A = V D V^{-1} \f$.
+ *
+ * Example: \include SelfAdjointEigenSolver_eigenvectors.cpp
+ * Output: \verbinclude SelfAdjointEigenSolver_eigenvectors.out
+ *
+ * \sa eigenvalues()
+ */
+ const MatrixType& eigenvectors() const
+ {
+ eigen_assert(m_isInitialized && "SelfAdjointEigenSolver is not initialized.");
+ eigen_assert(m_eigenvectorsOk && "The eigenvectors have not been computed together with the eigenvalues.");
+ return m_eivec;
+ }
+
+ /** \brief Returns the eigenvalues of given matrix.
+ *
+ * \returns A const reference to the column vector containing the eigenvalues.
+ *
+ * \pre The eigenvalues have been computed before.
+ *
+ * The eigenvalues are repeated according to their algebraic multiplicity,
+ * so there are as many eigenvalues as rows in the matrix. The eigenvalues
+ * are sorted in increasing order.
+ *
+ * Example: \include SelfAdjointEigenSolver_eigenvalues.cpp
+ * Output: \verbinclude SelfAdjointEigenSolver_eigenvalues.out
+ *
+ * \sa eigenvectors(), MatrixBase::eigenvalues()
+ */
+ const RealVectorType& eigenvalues() const
+ {
+ eigen_assert(m_isInitialized && "SelfAdjointEigenSolver is not initialized.");
+ return m_eivalues;
+ }
+
+ /** \brief Computes the positive-definite square root of the matrix.
+ *
+ * \returns the positive-definite square root of the matrix
+ *
+ * \pre The eigenvalues and eigenvectors of a positive-definite matrix
+ * have been computed before.
+ *
+ * The square root of a positive-definite matrix \f$ A \f$ is the
+ * positive-definite matrix whose square equals \f$ A \f$. This function
+ * uses the eigendecomposition \f$ A = V D V^{-1} \f$ to compute the
+ * square root as \f$ A^{1/2} = V D^{1/2} V^{-1} \f$.
+ *
+ * Example: \include SelfAdjointEigenSolver_operatorSqrt.cpp
+ * Output: \verbinclude SelfAdjointEigenSolver_operatorSqrt.out
+ *
+ * \sa operatorInverseSqrt(),
+ * \ref MatrixFunctions_Module "MatrixFunctions Module"
+ */
+ MatrixType operatorSqrt() const
+ {
+ eigen_assert(m_isInitialized && "SelfAdjointEigenSolver is not initialized.");
+ eigen_assert(m_eigenvectorsOk && "The eigenvectors have not been computed together with the eigenvalues.");
+ return m_eivec * m_eivalues.cwiseSqrt().asDiagonal() * m_eivec.adjoint();
+ }
+
+ /** \brief Computes the inverse square root of the matrix.
+ *
+ * \returns the inverse positive-definite square root of the matrix
+ *
+ * \pre The eigenvalues and eigenvectors of a positive-definite matrix
+ * have been computed before.
+ *
+ * This function uses the eigendecomposition \f$ A = V D V^{-1} \f$ to
+ * compute the inverse square root as \f$ V D^{-1/2} V^{-1} \f$. This is
+ * cheaper than first computing the square root with operatorSqrt() and
+ * then its inverse with MatrixBase::inverse().
+ *
+ * Example: \include SelfAdjointEigenSolver_operatorInverseSqrt.cpp
+ * Output: \verbinclude SelfAdjointEigenSolver_operatorInverseSqrt.out
+ *
+ * \sa operatorSqrt(), MatrixBase::inverse(),
+ * \ref MatrixFunctions_Module "MatrixFunctions Module"
+ */
+ MatrixType operatorInverseSqrt() const
+ {
+ eigen_assert(m_isInitialized && "SelfAdjointEigenSolver is not initialized.");
+ eigen_assert(m_eigenvectorsOk && "The eigenvectors have not been computed together with the eigenvalues.");
+ return m_eivec * m_eivalues.cwiseInverse().cwiseSqrt().asDiagonal() * m_eivec.adjoint();
+ }
+
+ /** \brief Reports whether previous computation was successful.
+ *
+ * \returns \c Success if computation was succesful, \c NoConvergence otherwise.
+ */
+ ComputationInfo info() const
+ {
+ eigen_assert(m_isInitialized && "SelfAdjointEigenSolver is not initialized.");
+ return m_info;
+ }
+
+ /** \brief Maximum number of iterations.
+ *
+ * The algorithm terminates if it does not converge within m_maxIterations * n iterations, where n
+ * denotes the size of the matrix. This value is currently set to 30 (copied from LAPACK).
+ */
+ static const int m_maxIterations = 30;
+
+ #ifdef EIGEN2_SUPPORT
+ SelfAdjointEigenSolver(const MatrixType& matrix, bool computeEigenvectors)
+ : m_eivec(matrix.rows(), matrix.cols()),
+ m_eivalues(matrix.cols()),
+ m_subdiag(matrix.rows() > 1 ? matrix.rows() - 1 : 1),
+ m_isInitialized(false)
+ {
+ compute(matrix, computeEigenvectors);
+ }
+
+ SelfAdjointEigenSolver(const MatrixType& matA, const MatrixType& matB, bool computeEigenvectors = true)
+ : m_eivec(matA.cols(), matA.cols()),
+ m_eivalues(matA.cols()),
+ m_subdiag(matA.cols() > 1 ? matA.cols() - 1 : 1),
+ m_isInitialized(false)
+ {
+ static_cast<GeneralizedSelfAdjointEigenSolver<MatrixType>*>(this)->compute(matA, matB, computeEigenvectors ? ComputeEigenvectors : EigenvaluesOnly);
+ }
+
+ void compute(const MatrixType& matrix, bool computeEigenvectors)
+ {
+ compute(matrix, computeEigenvectors ? ComputeEigenvectors : EigenvaluesOnly);
+ }
+
+ void compute(const MatrixType& matA, const MatrixType& matB, bool computeEigenvectors = true)
+ {
+ compute(matA, matB, computeEigenvectors ? ComputeEigenvectors : EigenvaluesOnly);
+ }
+ #endif // EIGEN2_SUPPORT
+
+ protected:
+ MatrixType m_eivec;
+ RealVectorType m_eivalues;
+ typename TridiagonalizationType::SubDiagonalType m_subdiag;
+ ComputationInfo m_info;
+ bool m_isInitialized;
+ bool m_eigenvectorsOk;
+};
+
+/** \internal
+ *
+ * \eigenvalues_module \ingroup Eigenvalues_Module
+ *
+ * Performs a QR step on a tridiagonal symmetric matrix represented as a
+ * pair of two vectors \a diag and \a subdiag.
+ *
+ * \param matA the input selfadjoint matrix
+ * \param hCoeffs returned Householder coefficients
+ *
+ * For compilation efficiency reasons, this procedure does not use eigen expression
+ * for its arguments.
+ *
+ * Implemented from Golub's "Matrix Computations", algorithm 8.3.2:
+ * "implicit symmetric QR step with Wilkinson shift"
+ */
+namespace internal {
+template<int StorageOrder,typename RealScalar, typename Scalar, typename Index>
+static void tridiagonal_qr_step(RealScalar* diag, RealScalar* subdiag, Index start, Index end, Scalar* matrixQ, Index n);
+}
+
+template<typename MatrixType>
+SelfAdjointEigenSolver<MatrixType>& SelfAdjointEigenSolver<MatrixType>
+::compute(const MatrixType& matrix, int options)
+{
+ eigen_assert(matrix.cols() == matrix.rows());
+ eigen_assert((options&~(EigVecMask|GenEigMask))==0
+ && (options&EigVecMask)!=EigVecMask
+ && "invalid option parameter");
+ bool computeEigenvectors = (options&ComputeEigenvectors)==ComputeEigenvectors;
+ Index n = matrix.cols();
+ m_eivalues.resize(n,1);
+
+ if(n==1)
+ {
+ m_eivalues.coeffRef(0,0) = internal::real(matrix.coeff(0,0));
+ if(computeEigenvectors)
+ m_eivec.setOnes(n,n);
+ m_info = Success;
+ m_isInitialized = true;
+ m_eigenvectorsOk = computeEigenvectors;
+ return *this;
+ }
+
+ // declare some aliases
+ RealVectorType& diag = m_eivalues;
+ MatrixType& mat = m_eivec;
+
+ // map the matrix coefficients to [-1:1] to avoid over- and underflow.
+ RealScalar scale = matrix.cwiseAbs().maxCoeff();
+ if(scale==RealScalar(0)) scale = RealScalar(1);
+ mat = matrix / scale;
+ m_subdiag.resize(n-1);
+ internal::tridiagonalization_inplace(mat, diag, m_subdiag, computeEigenvectors);
+
+ Index end = n-1;
+ Index start = 0;
+ Index iter = 0; // total number of iterations
+
+ while (end>0)
+ {
+ for (Index i = start; i<end; ++i)
+ if (internal::isMuchSmallerThan(internal::abs(m_subdiag[i]),(internal::abs(diag[i])+internal::abs(diag[i+1]))))
+ m_subdiag[i] = 0;
+
+ // find the largest unreduced block
+ while (end>0 && m_subdiag[end-1]==0)
+ {
+ end--;
+ }
+ if (end<=0)
+ break;
+
+ // if we spent too many iterations, we give up
+ iter++;
+ if(iter > m_maxIterations * n) break;
+
+ start = end - 1;
+ while (start>0 && m_subdiag[start-1]!=0)
+ start--;
+
+ internal::tridiagonal_qr_step<MatrixType::Flags&RowMajorBit ? RowMajor : ColMajor>(diag.data(), m_subdiag.data(), start, end, computeEigenvectors ? m_eivec.data() : (Scalar*)0, n);
+ }
+
+ if (iter <= m_maxIterations * n)
+ m_info = Success;
+ else
+ m_info = NoConvergence;
+
+ // Sort eigenvalues and corresponding vectors.
+ // TODO make the sort optional ?
+ // TODO use a better sort algorithm !!
+ if (m_info == Success)
+ {
+ for (Index i = 0; i < n-1; ++i)
+ {
+ Index k;
+ m_eivalues.segment(i,n-i).minCoeff(&k);
+ if (k > 0)
+ {
+ std::swap(m_eivalues[i], m_eivalues[k+i]);
+ if(computeEigenvectors)
+ m_eivec.col(i).swap(m_eivec.col(k+i));
+ }
+ }
+ }
+
+ // scale back the eigen values
+ m_eivalues *= scale;
+
+ m_isInitialized = true;
+ m_eigenvectorsOk = computeEigenvectors;
+ return *this;
+}
+
+
+namespace internal {
+
+template<typename SolverType,int Size,bool IsComplex> struct direct_selfadjoint_eigenvalues
+{
+ static inline void run(SolverType& eig, const typename SolverType::MatrixType& A, int options)
+ { eig.compute(A,options); }
+};
+
+template<typename SolverType> struct direct_selfadjoint_eigenvalues<SolverType,3,false>
+{
+ typedef typename SolverType::MatrixType MatrixType;
+ typedef typename SolverType::RealVectorType VectorType;
+ typedef typename SolverType::Scalar Scalar;
+
+ static inline void computeRoots(const MatrixType& m, VectorType& roots)
+ {
+ using std::sqrt;
+ using std::atan2;
+ using std::cos;
+ using std::sin;
+ const Scalar s_inv3 = Scalar(1.0)/Scalar(3.0);
+ const Scalar s_sqrt3 = sqrt(Scalar(3.0));
+
+ // The characteristic equation is x^3 - c2*x^2 + c1*x - c0 = 0. The
+ // eigenvalues are the roots to this equation, all guaranteed to be
+ // real-valued, because the matrix is symmetric.
+ Scalar c0 = m(0,0)*m(1,1)*m(2,2) + Scalar(2)*m(1,0)*m(2,0)*m(2,1) - m(0,0)*m(2,1)*m(2,1) - m(1,1)*m(2,0)*m(2,0) - m(2,2)*m(1,0)*m(1,0);
+ Scalar c1 = m(0,0)*m(1,1) - m(1,0)*m(1,0) + m(0,0)*m(2,2) - m(2,0)*m(2,0) + m(1,1)*m(2,2) - m(2,1)*m(2,1);
+ Scalar c2 = m(0,0) + m(1,1) + m(2,2);
+
+ // Construct the parameters used in classifying the roots of the equation
+ // and in solving the equation for the roots in closed form.
+ Scalar c2_over_3 = c2*s_inv3;
+ Scalar a_over_3 = (c1 - c2*c2_over_3)*s_inv3;
+ if (a_over_3 > Scalar(0))
+ a_over_3 = Scalar(0);
+
+ Scalar half_b = Scalar(0.5)*(c0 + c2_over_3*(Scalar(2)*c2_over_3*c2_over_3 - c1));
+
+ Scalar q = half_b*half_b + a_over_3*a_over_3*a_over_3;
+ if (q > Scalar(0))
+ q = Scalar(0);
+
+ // Compute the eigenvalues by solving for the roots of the polynomial.
+ Scalar rho = sqrt(-a_over_3);
+ Scalar theta = atan2(sqrt(-q),half_b)*s_inv3;
+ Scalar cos_theta = cos(theta);
+ Scalar sin_theta = sin(theta);
+ roots(0) = c2_over_3 + Scalar(2)*rho*cos_theta;
+ roots(1) = c2_over_3 - rho*(cos_theta + s_sqrt3*sin_theta);
+ roots(2) = c2_over_3 - rho*(cos_theta - s_sqrt3*sin_theta);
+
+ // Sort in increasing order.
+ if (roots(0) >= roots(1))
+ std::swap(roots(0),roots(1));
+ if (roots(1) >= roots(2))
+ {
+ std::swap(roots(1),roots(2));
+ if (roots(0) >= roots(1))
+ std::swap(roots(0),roots(1));
+ }
+ }
+
+ static inline void run(SolverType& solver, const MatrixType& mat, int options)
+ {
+ using std::sqrt;
+ eigen_assert(mat.cols() == 3 && mat.cols() == mat.rows());
+ eigen_assert((options&~(EigVecMask|GenEigMask))==0
+ && (options&EigVecMask)!=EigVecMask
+ && "invalid option parameter");
+ bool computeEigenvectors = (options&ComputeEigenvectors)==ComputeEigenvectors;
+
+ MatrixType& eivecs = solver.m_eivec;
+ VectorType& eivals = solver.m_eivalues;
+
+ // map the matrix coefficients to [-1:1] to avoid over- and underflow.
+ Scalar scale = mat.cwiseAbs().maxCoeff();
+ MatrixType scaledMat = mat / scale;
+
+ // compute the eigenvalues
+ computeRoots(scaledMat,eivals);
+
+ // compute the eigen vectors
+ if(computeEigenvectors)
+ {
+ Scalar safeNorm2 = Eigen::NumTraits<Scalar>::epsilon();
+ safeNorm2 *= safeNorm2;
+ if((eivals(2)-eivals(0))<=Eigen::NumTraits<Scalar>::epsilon())
+ {
+ eivecs.setIdentity();
+ }
+ else
+ {
+ scaledMat = scaledMat.template selfadjointView<Lower>();
+ MatrixType tmp;
+ tmp = scaledMat;
+
+ Scalar d0 = eivals(2) - eivals(1);
+ Scalar d1 = eivals(1) - eivals(0);
+ int k = d0 > d1 ? 2 : 0;
+ d0 = d0 > d1 ? d1 : d0;
+
+ tmp.diagonal().array () -= eivals(k);
+ VectorType cross;
+ Scalar n;
+ n = (cross = tmp.row(0).cross(tmp.row(1))).squaredNorm();
+
+ if(n>safeNorm2)
+ eivecs.col(k) = cross / sqrt(n);
+ else
+ {
+ n = (cross = tmp.row(0).cross(tmp.row(2))).squaredNorm();
+
+ if(n>safeNorm2)
+ eivecs.col(k) = cross / sqrt(n);
+ else
+ {
+ n = (cross = tmp.row(1).cross(tmp.row(2))).squaredNorm();
+
+ if(n>safeNorm2)
+ eivecs.col(k) = cross / sqrt(n);
+ else
+ {
+ // the input matrix and/or the eigenvaues probably contains some inf/NaN,
+ // => exit
+ // scale back to the original size.
+ eivals *= scale;
+
+ solver.m_info = NumericalIssue;
+ solver.m_isInitialized = true;
+ solver.m_eigenvectorsOk = computeEigenvectors;
+ return;
+ }
+ }
+ }
+
+ tmp = scaledMat;
+ tmp.diagonal().array() -= eivals(1);
+
+ if(d0<=Eigen::NumTraits<Scalar>::epsilon())
+ eivecs.col(1) = eivecs.col(k).unitOrthogonal();
+ else
+ {
+ n = (cross = eivecs.col(k).cross(tmp.row(0).normalized())).squaredNorm();
+ if(n>safeNorm2)
+ eivecs.col(1) = cross / sqrt(n);
+ else
+ {
+ n = (cross = eivecs.col(k).cross(tmp.row(1))).squaredNorm();
+ if(n>safeNorm2)
+ eivecs.col(1) = cross / sqrt(n);
+ else
+ {
+ n = (cross = eivecs.col(k).cross(tmp.row(2))).squaredNorm();
+ if(n>safeNorm2)
+ eivecs.col(1) = cross / sqrt(n);
+ else
+ {
+ // we should never reach this point,
+ // if so the last two eigenvalues are likely to ve very closed to each other
+ eivecs.col(1) = eivecs.col(k).unitOrthogonal();
+ }
+ }
+ }
+
+ // make sure that eivecs[1] is orthogonal to eivecs[2]
+ Scalar d = eivecs.col(1).dot(eivecs.col(k));
+ eivecs.col(1) = (eivecs.col(1) - d * eivecs.col(k)).normalized();
+ }
+
+ eivecs.col(k==2 ? 0 : 2) = eivecs.col(k).cross(eivecs.col(1)).normalized();
+ }
+ }
+ // Rescale back to the original size.
+ eivals *= scale;
+
+ solver.m_info = Success;
+ solver.m_isInitialized = true;
+ solver.m_eigenvectorsOk = computeEigenvectors;
+ }
+};
+
+// 2x2 direct eigenvalues decomposition, code from Hauke Heibel
+template<typename SolverType> struct direct_selfadjoint_eigenvalues<SolverType,2,false>
+{
+ typedef typename SolverType::MatrixType MatrixType;
+ typedef typename SolverType::RealVectorType VectorType;
+ typedef typename SolverType::Scalar Scalar;
+
+ static inline void computeRoots(const MatrixType& m, VectorType& roots)
+ {
+ using std::sqrt;
+ const Scalar t0 = Scalar(0.5) * sqrt( abs2(m(0,0)-m(1,1)) + Scalar(4)*m(1,0)*m(1,0));
+ const Scalar t1 = Scalar(0.5) * (m(0,0) + m(1,1));
+ roots(0) = t1 - t0;
+ roots(1) = t1 + t0;
+ }
+
+ static inline void run(SolverType& solver, const MatrixType& mat, int options)
+ {
+ eigen_assert(mat.cols() == 2 && mat.cols() == mat.rows());
+ eigen_assert((options&~(EigVecMask|GenEigMask))==0
+ && (options&EigVecMask)!=EigVecMask
+ && "invalid option parameter");
+ bool computeEigenvectors = (options&ComputeEigenvectors)==ComputeEigenvectors;
+
+ MatrixType& eivecs = solver.m_eivec;
+ VectorType& eivals = solver.m_eivalues;
+
+ // map the matrix coefficients to [-1:1] to avoid over- and underflow.
+ Scalar scale = mat.cwiseAbs().maxCoeff();
+ scale = (std::max)(scale,Scalar(1));
+ MatrixType scaledMat = mat / scale;
+
+ // Compute the eigenvalues
+ computeRoots(scaledMat,eivals);
+
+ // compute the eigen vectors
+ if(computeEigenvectors)
+ {
+ scaledMat.diagonal().array () -= eivals(1);
+ Scalar a2 = abs2(scaledMat(0,0));
+ Scalar c2 = abs2(scaledMat(1,1));
+ Scalar b2 = abs2(scaledMat(1,0));
+ if(a2>c2)
+ {
+ eivecs.col(1) << -scaledMat(1,0), scaledMat(0,0);
+ eivecs.col(1) /= sqrt(a2+b2);
+ }
+ else
+ {
+ eivecs.col(1) << -scaledMat(1,1), scaledMat(1,0);
+ eivecs.col(1) /= sqrt(c2+b2);
+ }
+
+ eivecs.col(0) << eivecs.col(1).unitOrthogonal();
+ }
+
+ // Rescale back to the original size.
+ eivals *= scale;
+
+ solver.m_info = Success;
+ solver.m_isInitialized = true;
+ solver.m_eigenvectorsOk = computeEigenvectors;
+ }
+};
+
+}
+
+template<typename MatrixType>
+SelfAdjointEigenSolver<MatrixType>& SelfAdjointEigenSolver<MatrixType>
+::computeDirect(const MatrixType& matrix, int options)
+{
+ internal::direct_selfadjoint_eigenvalues<SelfAdjointEigenSolver,Size,NumTraits<Scalar>::IsComplex>::run(*this,matrix,options);
+ return *this;
+}
+
+namespace internal {
+template<int StorageOrder,typename RealScalar, typename Scalar, typename Index>
+static void tridiagonal_qr_step(RealScalar* diag, RealScalar* subdiag, Index start, Index end, Scalar* matrixQ, Index n)
+{
+ RealScalar td = (diag[end-1] - diag[end])*RealScalar(0.5);
+ RealScalar e = subdiag[end-1];
+ // Note that thanks to scaling, e^2 or td^2 cannot overflow, however they can still
+ // underflow thus leading to inf/NaN values when using the following commented code:
+// RealScalar e2 = abs2(subdiag[end-1]);
+// RealScalar mu = diag[end] - e2 / (td + (td>0 ? 1 : -1) * sqrt(td*td + e2));
+ // This explain the following, somewhat more complicated, version:
+ RealScalar mu = diag[end] - (e / (td + (td>0 ? 1 : -1))) * (e / hypot(td,e));
+
+ RealScalar x = diag[start] - mu;
+ RealScalar z = subdiag[start];
+ for (Index k = start; k < end; ++k)
+ {
+ JacobiRotation<RealScalar> rot;
+ rot.makeGivens(x, z);
+
+ // do T = G' T G
+ RealScalar sdk = rot.s() * diag[k] + rot.c() * subdiag[k];
+ RealScalar dkp1 = rot.s() * subdiag[k] + rot.c() * diag[k+1];
+
+ diag[k] = rot.c() * (rot.c() * diag[k] - rot.s() * subdiag[k]) - rot.s() * (rot.c() * subdiag[k] - rot.s() * diag[k+1]);
+ diag[k+1] = rot.s() * sdk + rot.c() * dkp1;
+ subdiag[k] = rot.c() * sdk - rot.s() * dkp1;
+
+
+ if (k > start)
+ subdiag[k - 1] = rot.c() * subdiag[k-1] - rot.s() * z;
+
+ x = subdiag[k];
+
+ if (k < end - 1)
+ {
+ z = -rot.s() * subdiag[k+1];
+ subdiag[k + 1] = rot.c() * subdiag[k+1];
+ }
+
+ // apply the givens rotation to the unit matrix Q = Q * G
+ if (matrixQ)
+ {
+ // FIXME if StorageOrder == RowMajor this operation is not very efficient
+ Map<Matrix<Scalar,Dynamic,Dynamic,StorageOrder> > q(matrixQ,n,n);
+ q.applyOnTheRight(k,k+1,rot);
+ }
+ }
+}
+
+} // end namespace internal
+
+} // end namespace Eigen
+
+#endif // EIGEN_SELFADJOINTEIGENSOLVER_H
diff --git a/Eigen/src/Eigenvalues/SelfAdjointEigenSolver_MKL.h b/Eigen/src/Eigenvalues/SelfAdjointEigenSolver_MKL.h
new file mode 100644
index 000000000..9380956b5
--- /dev/null
+++ b/Eigen/src/Eigenvalues/SelfAdjointEigenSolver_MKL.h
@@ -0,0 +1,92 @@
+/*
+ Copyright (c) 2011, Intel Corporation. All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without modification,
+ are permitted provided that the following conditions are met:
+
+ * Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+ * Neither the name of Intel Corporation nor the names of its contributors may
+ be used to endorse or promote products derived from this software without
+ specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+ ********************************************************************************
+ * Content : Eigen bindings to Intel(R) MKL
+ * Self-adjoint eigenvalues/eigenvectors.
+ ********************************************************************************
+*/
+
+#ifndef EIGEN_SAEIGENSOLVER_MKL_H
+#define EIGEN_SAEIGENSOLVER_MKL_H
+
+#include "Eigen/src/Core/util/MKL_support.h"
+
+namespace Eigen {
+
+/** \internal Specialization for the data types supported by MKL */
+
+#define EIGEN_MKL_EIG_SELFADJ(EIGTYPE, MKLTYPE, MKLRTYPE, MKLNAME, EIGCOLROW, MKLCOLROW ) \
+template<> inline\
+SelfAdjointEigenSolver<Matrix<EIGTYPE, Dynamic, Dynamic, EIGCOLROW> >& \
+SelfAdjointEigenSolver<Matrix<EIGTYPE, Dynamic, Dynamic, EIGCOLROW> >::compute(const Matrix<EIGTYPE, Dynamic, Dynamic, EIGCOLROW>& matrix, int options) \
+{ \
+ eigen_assert(matrix.cols() == matrix.rows()); \
+ eigen_assert((options&~(EigVecMask|GenEigMask))==0 \
+ && (options&EigVecMask)!=EigVecMask \
+ && "invalid option parameter"); \
+ bool computeEigenvectors = (options&ComputeEigenvectors)==ComputeEigenvectors; \
+ lapack_int n = matrix.cols(), lda, matrix_order, info; \
+ m_eivalues.resize(n,1); \
+ m_subdiag.resize(n-1); \
+ m_eivec = matrix; \
+\
+ if(n==1) \
+ { \
+ m_eivalues.coeffRef(0,0) = internal::real(matrix.coeff(0,0)); \
+ if(computeEigenvectors) m_eivec.setOnes(n,n); \
+ m_info = Success; \
+ m_isInitialized = true; \
+ m_eigenvectorsOk = computeEigenvectors; \
+ return *this; \
+ } \
+\
+ lda = matrix.outerStride(); \
+ matrix_order=MKLCOLROW; \
+ char jobz, uplo='L'/*, range='A'*/; \
+ jobz = computeEigenvectors ? 'V' : 'N'; \
+\
+ info = LAPACKE_##MKLNAME( matrix_order, jobz, uplo, n, (MKLTYPE*)m_eivec.data(), lda, (MKLRTYPE*)m_eivalues.data() ); \
+ m_info = (info==0) ? Success : NoConvergence; \
+ m_isInitialized = true; \
+ m_eigenvectorsOk = computeEigenvectors; \
+ return *this; \
+}
+
+
+EIGEN_MKL_EIG_SELFADJ(double, double, double, dsyev, ColMajor, LAPACK_COL_MAJOR)
+EIGEN_MKL_EIG_SELFADJ(float, float, float, ssyev, ColMajor, LAPACK_COL_MAJOR)
+EIGEN_MKL_EIG_SELFADJ(dcomplex, MKL_Complex16, double, zheev, ColMajor, LAPACK_COL_MAJOR)
+EIGEN_MKL_EIG_SELFADJ(scomplex, MKL_Complex8, float, cheev, ColMajor, LAPACK_COL_MAJOR)
+
+EIGEN_MKL_EIG_SELFADJ(double, double, double, dsyev, RowMajor, LAPACK_ROW_MAJOR)
+EIGEN_MKL_EIG_SELFADJ(float, float, float, ssyev, RowMajor, LAPACK_ROW_MAJOR)
+EIGEN_MKL_EIG_SELFADJ(dcomplex, MKL_Complex16, double, zheev, RowMajor, LAPACK_ROW_MAJOR)
+EIGEN_MKL_EIG_SELFADJ(scomplex, MKL_Complex8, float, cheev, RowMajor, LAPACK_ROW_MAJOR)
+
+} // end namespace Eigen
+
+#endif // EIGEN_SAEIGENSOLVER_H
diff --git a/Eigen/src/Eigenvalues/Tridiagonalization.h b/Eigen/src/Eigenvalues/Tridiagonalization.h
new file mode 100644
index 000000000..c34b7b3b8
--- /dev/null
+++ b/Eigen/src/Eigenvalues/Tridiagonalization.h
@@ -0,0 +1,557 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra.
+//
+// Copyright (C) 2008 Gael Guennebaud <gael.guennebaud@inria.fr>
+// Copyright (C) 2010 Jitse Niesen <jitse@maths.leeds.ac.uk>
+//
+// This Source Code Form is subject to the terms of the Mozilla
+// Public License v. 2.0. If a copy of the MPL was not distributed
+// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+#ifndef EIGEN_TRIDIAGONALIZATION_H
+#define EIGEN_TRIDIAGONALIZATION_H
+
+namespace Eigen {
+
+namespace internal {
+
+template<typename MatrixType> struct TridiagonalizationMatrixTReturnType;
+template<typename MatrixType>
+struct traits<TridiagonalizationMatrixTReturnType<MatrixType> >
+{
+ typedef typename MatrixType::PlainObject ReturnType;
+};
+
+template<typename MatrixType, typename CoeffVectorType>
+void tridiagonalization_inplace(MatrixType& matA, CoeffVectorType& hCoeffs);
+}
+
+/** \eigenvalues_module \ingroup Eigenvalues_Module
+ *
+ *
+ * \class Tridiagonalization
+ *
+ * \brief Tridiagonal decomposition of a selfadjoint matrix
+ *
+ * \tparam _MatrixType the type of the matrix of which we are computing the
+ * tridiagonal decomposition; this is expected to be an instantiation of the
+ * Matrix class template.
+ *
+ * This class performs a tridiagonal decomposition of a selfadjoint matrix \f$ A \f$ such that:
+ * \f$ A = Q T Q^* \f$ where \f$ Q \f$ is unitary and \f$ T \f$ a real symmetric tridiagonal matrix.
+ *
+ * A tridiagonal matrix is a matrix which has nonzero elements only on the
+ * main diagonal and the first diagonal below and above it. The Hessenberg
+ * decomposition of a selfadjoint matrix is in fact a tridiagonal
+ * decomposition. This class is used in SelfAdjointEigenSolver to compute the
+ * eigenvalues and eigenvectors of a selfadjoint matrix.
+ *
+ * Call the function compute() to compute the tridiagonal decomposition of a
+ * given matrix. Alternatively, you can use the Tridiagonalization(const MatrixType&)
+ * constructor which computes the tridiagonal Schur decomposition at
+ * construction time. Once the decomposition is computed, you can use the
+ * matrixQ() and matrixT() functions to retrieve the matrices Q and T in the
+ * decomposition.
+ *
+ * The documentation of Tridiagonalization(const MatrixType&) contains an
+ * example of the typical use of this class.
+ *
+ * \sa class HessenbergDecomposition, class SelfAdjointEigenSolver
+ */
+template<typename _MatrixType> class Tridiagonalization
+{
+ public:
+
+ /** \brief Synonym for the template parameter \p _MatrixType. */
+ typedef _MatrixType MatrixType;
+
+ typedef typename MatrixType::Scalar Scalar;
+ typedef typename NumTraits<Scalar>::Real RealScalar;
+ typedef typename MatrixType::Index Index;
+
+ enum {
+ Size = MatrixType::RowsAtCompileTime,
+ SizeMinusOne = Size == Dynamic ? Dynamic : (Size > 1 ? Size - 1 : 1),
+ Options = MatrixType::Options,
+ MaxSize = MatrixType::MaxRowsAtCompileTime,
+ MaxSizeMinusOne = MaxSize == Dynamic ? Dynamic : (MaxSize > 1 ? MaxSize - 1 : 1)
+ };
+
+ typedef Matrix<Scalar, SizeMinusOne, 1, Options & ~RowMajor, MaxSizeMinusOne, 1> CoeffVectorType;
+ typedef typename internal::plain_col_type<MatrixType, RealScalar>::type DiagonalType;
+ typedef Matrix<RealScalar, SizeMinusOne, 1, Options & ~RowMajor, MaxSizeMinusOne, 1> SubDiagonalType;
+ typedef typename internal::remove_all<typename MatrixType::RealReturnType>::type MatrixTypeRealView;
+ typedef internal::TridiagonalizationMatrixTReturnType<MatrixTypeRealView> MatrixTReturnType;
+
+ typedef typename internal::conditional<NumTraits<Scalar>::IsComplex,
+ typename internal::add_const_on_value_type<typename Diagonal<const MatrixType>::RealReturnType>::type,
+ const Diagonal<const MatrixType>
+ >::type DiagonalReturnType;
+
+ typedef typename internal::conditional<NumTraits<Scalar>::IsComplex,
+ typename internal::add_const_on_value_type<typename Diagonal<
+ Block<const MatrixType,SizeMinusOne,SizeMinusOne> >::RealReturnType>::type,
+ const Diagonal<
+ Block<const MatrixType,SizeMinusOne,SizeMinusOne> >
+ >::type SubDiagonalReturnType;
+
+ /** \brief Return type of matrixQ() */
+ typedef typename HouseholderSequence<MatrixType,CoeffVectorType>::ConjugateReturnType HouseholderSequenceType;
+
+ /** \brief Default constructor.
+ *
+ * \param [in] size Positive integer, size of the matrix whose tridiagonal
+ * decomposition will be computed.
+ *
+ * The default constructor is useful in cases in which the user intends to
+ * perform decompositions via compute(). The \p size parameter is only
+ * used as a hint. It is not an error to give a wrong \p size, but it may
+ * impair performance.
+ *
+ * \sa compute() for an example.
+ */
+ Tridiagonalization(Index size = Size==Dynamic ? 2 : Size)
+ : m_matrix(size,size),
+ m_hCoeffs(size > 1 ? size-1 : 1),
+ m_isInitialized(false)
+ {}
+
+ /** \brief Constructor; computes tridiagonal decomposition of given matrix.
+ *
+ * \param[in] matrix Selfadjoint matrix whose tridiagonal decomposition
+ * is to be computed.
+ *
+ * This constructor calls compute() to compute the tridiagonal decomposition.
+ *
+ * Example: \include Tridiagonalization_Tridiagonalization_MatrixType.cpp
+ * Output: \verbinclude Tridiagonalization_Tridiagonalization_MatrixType.out
+ */
+ Tridiagonalization(const MatrixType& matrix)
+ : m_matrix(matrix),
+ m_hCoeffs(matrix.cols() > 1 ? matrix.cols()-1 : 1),
+ m_isInitialized(false)
+ {
+ internal::tridiagonalization_inplace(m_matrix, m_hCoeffs);
+ m_isInitialized = true;
+ }
+
+ /** \brief Computes tridiagonal decomposition of given matrix.
+ *
+ * \param[in] matrix Selfadjoint matrix whose tridiagonal decomposition
+ * is to be computed.
+ * \returns Reference to \c *this
+ *
+ * The tridiagonal decomposition is computed by bringing the columns of
+ * the matrix successively in the required form using Householder
+ * reflections. The cost is \f$ 4n^3/3 \f$ flops, where \f$ n \f$ denotes
+ * the size of the given matrix.
+ *
+ * This method reuses of the allocated data in the Tridiagonalization
+ * object, if the size of the matrix does not change.
+ *
+ * Example: \include Tridiagonalization_compute.cpp
+ * Output: \verbinclude Tridiagonalization_compute.out
+ */
+ Tridiagonalization& compute(const MatrixType& matrix)
+ {
+ m_matrix = matrix;
+ m_hCoeffs.resize(matrix.rows()-1, 1);
+ internal::tridiagonalization_inplace(m_matrix, m_hCoeffs);
+ m_isInitialized = true;
+ return *this;
+ }
+
+ /** \brief Returns the Householder coefficients.
+ *
+ * \returns a const reference to the vector of Householder coefficients
+ *
+ * \pre Either the constructor Tridiagonalization(const MatrixType&) or
+ * the member function compute(const MatrixType&) has been called before
+ * to compute the tridiagonal decomposition of a matrix.
+ *
+ * The Householder coefficients allow the reconstruction of the matrix
+ * \f$ Q \f$ in the tridiagonal decomposition from the packed data.
+ *
+ * Example: \include Tridiagonalization_householderCoefficients.cpp
+ * Output: \verbinclude Tridiagonalization_householderCoefficients.out
+ *
+ * \sa packedMatrix(), \ref Householder_Module "Householder module"
+ */
+ inline CoeffVectorType householderCoefficients() const
+ {
+ eigen_assert(m_isInitialized && "Tridiagonalization is not initialized.");
+ return m_hCoeffs;
+ }
+
+ /** \brief Returns the internal representation of the decomposition
+ *
+ * \returns a const reference to a matrix with the internal representation
+ * of the decomposition.
+ *
+ * \pre Either the constructor Tridiagonalization(const MatrixType&) or
+ * the member function compute(const MatrixType&) has been called before
+ * to compute the tridiagonal decomposition of a matrix.
+ *
+ * The returned matrix contains the following information:
+ * - the strict upper triangular part is equal to the input matrix A.
+ * - the diagonal and lower sub-diagonal represent the real tridiagonal
+ * symmetric matrix T.
+ * - the rest of the lower part contains the Householder vectors that,
+ * combined with Householder coefficients returned by
+ * householderCoefficients(), allows to reconstruct the matrix Q as
+ * \f$ Q = H_{N-1} \ldots H_1 H_0 \f$.
+ * Here, the matrices \f$ H_i \f$ are the Householder transformations
+ * \f$ H_i = (I - h_i v_i v_i^T) \f$
+ * where \f$ h_i \f$ is the \f$ i \f$th Householder coefficient and
+ * \f$ v_i \f$ is the Householder vector defined by
+ * \f$ v_i = [ 0, \ldots, 0, 1, M(i+2,i), \ldots, M(N-1,i) ]^T \f$
+ * with M the matrix returned by this function.
+ *
+ * See LAPACK for further details on this packed storage.
+ *
+ * Example: \include Tridiagonalization_packedMatrix.cpp
+ * Output: \verbinclude Tridiagonalization_packedMatrix.out
+ *
+ * \sa householderCoefficients()
+ */
+ inline const MatrixType& packedMatrix() const
+ {
+ eigen_assert(m_isInitialized && "Tridiagonalization is not initialized.");
+ return m_matrix;
+ }
+
+ /** \brief Returns the unitary matrix Q in the decomposition
+ *
+ * \returns object representing the matrix Q
+ *
+ * \pre Either the constructor Tridiagonalization(const MatrixType&) or
+ * the member function compute(const MatrixType&) has been called before
+ * to compute the tridiagonal decomposition of a matrix.
+ *
+ * This function returns a light-weight object of template class
+ * HouseholderSequence. You can either apply it directly to a matrix or
+ * you can convert it to a matrix of type #MatrixType.
+ *
+ * \sa Tridiagonalization(const MatrixType&) for an example,
+ * matrixT(), class HouseholderSequence
+ */
+ HouseholderSequenceType matrixQ() const
+ {
+ eigen_assert(m_isInitialized && "Tridiagonalization is not initialized.");
+ return HouseholderSequenceType(m_matrix, m_hCoeffs.conjugate())
+ .setLength(m_matrix.rows() - 1)
+ .setShift(1);
+ }
+
+ /** \brief Returns an expression of the tridiagonal matrix T in the decomposition
+ *
+ * \returns expression object representing the matrix T
+ *
+ * \pre Either the constructor Tridiagonalization(const MatrixType&) or
+ * the member function compute(const MatrixType&) has been called before
+ * to compute the tridiagonal decomposition of a matrix.
+ *
+ * Currently, this function can be used to extract the matrix T from internal
+ * data and copy it to a dense matrix object. In most cases, it may be
+ * sufficient to directly use the packed matrix or the vector expressions
+ * returned by diagonal() and subDiagonal() instead of creating a new
+ * dense copy matrix with this function.
+ *
+ * \sa Tridiagonalization(const MatrixType&) for an example,
+ * matrixQ(), packedMatrix(), diagonal(), subDiagonal()
+ */
+ MatrixTReturnType matrixT() const
+ {
+ eigen_assert(m_isInitialized && "Tridiagonalization is not initialized.");
+ return MatrixTReturnType(m_matrix.real());
+ }
+
+ /** \brief Returns the diagonal of the tridiagonal matrix T in the decomposition.
+ *
+ * \returns expression representing the diagonal of T
+ *
+ * \pre Either the constructor Tridiagonalization(const MatrixType&) or
+ * the member function compute(const MatrixType&) has been called before
+ * to compute the tridiagonal decomposition of a matrix.
+ *
+ * Example: \include Tridiagonalization_diagonal.cpp
+ * Output: \verbinclude Tridiagonalization_diagonal.out
+ *
+ * \sa matrixT(), subDiagonal()
+ */
+ DiagonalReturnType diagonal() const;
+
+ /** \brief Returns the subdiagonal of the tridiagonal matrix T in the decomposition.
+ *
+ * \returns expression representing the subdiagonal of T
+ *
+ * \pre Either the constructor Tridiagonalization(const MatrixType&) or
+ * the member function compute(const MatrixType&) has been called before
+ * to compute the tridiagonal decomposition of a matrix.
+ *
+ * \sa diagonal() for an example, matrixT()
+ */
+ SubDiagonalReturnType subDiagonal() const;
+
+ protected:
+
+ MatrixType m_matrix;
+ CoeffVectorType m_hCoeffs;
+ bool m_isInitialized;
+};
+
+template<typename MatrixType>
+typename Tridiagonalization<MatrixType>::DiagonalReturnType
+Tridiagonalization<MatrixType>::diagonal() const
+{
+ eigen_assert(m_isInitialized && "Tridiagonalization is not initialized.");
+ return m_matrix.diagonal();
+}
+
+template<typename MatrixType>
+typename Tridiagonalization<MatrixType>::SubDiagonalReturnType
+Tridiagonalization<MatrixType>::subDiagonal() const
+{
+ eigen_assert(m_isInitialized && "Tridiagonalization is not initialized.");
+ Index n = m_matrix.rows();
+ return Block<const MatrixType,SizeMinusOne,SizeMinusOne>(m_matrix, 1, 0, n-1,n-1).diagonal();
+}
+
+namespace internal {
+
+/** \internal
+ * Performs a tridiagonal decomposition of the selfadjoint matrix \a matA in-place.
+ *
+ * \param[in,out] matA On input the selfadjoint matrix. Only the \b lower triangular part is referenced.
+ * On output, the strict upper part is left unchanged, and the lower triangular part
+ * represents the T and Q matrices in packed format has detailed below.
+ * \param[out] hCoeffs returned Householder coefficients (see below)
+ *
+ * On output, the tridiagonal selfadjoint matrix T is stored in the diagonal
+ * and lower sub-diagonal of the matrix \a matA.
+ * The unitary matrix Q is represented in a compact way as a product of
+ * Householder reflectors \f$ H_i \f$ such that:
+ * \f$ Q = H_{N-1} \ldots H_1 H_0 \f$.
+ * The Householder reflectors are defined as
+ * \f$ H_i = (I - h_i v_i v_i^T) \f$
+ * where \f$ h_i = hCoeffs[i]\f$ is the \f$ i \f$th Householder coefficient and
+ * \f$ v_i \f$ is the Householder vector defined by
+ * \f$ v_i = [ 0, \ldots, 0, 1, matA(i+2,i), \ldots, matA(N-1,i) ]^T \f$.
+ *
+ * Implemented from Golub's "Matrix Computations", algorithm 8.3.1.
+ *
+ * \sa Tridiagonalization::packedMatrix()
+ */
+template<typename MatrixType, typename CoeffVectorType>
+void tridiagonalization_inplace(MatrixType& matA, CoeffVectorType& hCoeffs)
+{
+ typedef typename MatrixType::Index Index;
+ typedef typename MatrixType::Scalar Scalar;
+ typedef typename MatrixType::RealScalar RealScalar;
+ Index n = matA.rows();
+ eigen_assert(n==matA.cols());
+ eigen_assert(n==hCoeffs.size()+1 || n==1);
+
+ for (Index i = 0; i<n-1; ++i)
+ {
+ Index remainingSize = n-i-1;
+ RealScalar beta;
+ Scalar h;
+ matA.col(i).tail(remainingSize).makeHouseholderInPlace(h, beta);
+
+ // Apply similarity transformation to remaining columns,
+ // i.e., A = H A H' where H = I - h v v' and v = matA.col(i).tail(n-i-1)
+ matA.col(i).coeffRef(i+1) = 1;
+
+ hCoeffs.tail(n-i-1).noalias() = (matA.bottomRightCorner(remainingSize,remainingSize).template selfadjointView<Lower>()
+ * (conj(h) * matA.col(i).tail(remainingSize)));
+
+ hCoeffs.tail(n-i-1) += (conj(h)*Scalar(-0.5)*(hCoeffs.tail(remainingSize).dot(matA.col(i).tail(remainingSize)))) * matA.col(i).tail(n-i-1);
+
+ matA.bottomRightCorner(remainingSize, remainingSize).template selfadjointView<Lower>()
+ .rankUpdate(matA.col(i).tail(remainingSize), hCoeffs.tail(remainingSize), -1);
+
+ matA.col(i).coeffRef(i+1) = beta;
+ hCoeffs.coeffRef(i) = h;
+ }
+}
+
+// forward declaration, implementation at the end of this file
+template<typename MatrixType,
+ int Size=MatrixType::ColsAtCompileTime,
+ bool IsComplex=NumTraits<typename MatrixType::Scalar>::IsComplex>
+struct tridiagonalization_inplace_selector;
+
+/** \brief Performs a full tridiagonalization in place
+ *
+ * \param[in,out] mat On input, the selfadjoint matrix whose tridiagonal
+ * decomposition is to be computed. Only the lower triangular part referenced.
+ * The rest is left unchanged. On output, the orthogonal matrix Q
+ * in the decomposition if \p extractQ is true.
+ * \param[out] diag The diagonal of the tridiagonal matrix T in the
+ * decomposition.
+ * \param[out] subdiag The subdiagonal of the tridiagonal matrix T in
+ * the decomposition.
+ * \param[in] extractQ If true, the orthogonal matrix Q in the
+ * decomposition is computed and stored in \p mat.
+ *
+ * Computes the tridiagonal decomposition of the selfadjoint matrix \p mat in place
+ * such that \f$ mat = Q T Q^* \f$ where \f$ Q \f$ is unitary and \f$ T \f$ a real
+ * symmetric tridiagonal matrix.
+ *
+ * The tridiagonal matrix T is passed to the output parameters \p diag and \p subdiag. If
+ * \p extractQ is true, then the orthogonal matrix Q is passed to \p mat. Otherwise the lower
+ * part of the matrix \p mat is destroyed.
+ *
+ * The vectors \p diag and \p subdiag are not resized. The function
+ * assumes that they are already of the correct size. The length of the
+ * vector \p diag should equal the number of rows in \p mat, and the
+ * length of the vector \p subdiag should be one left.
+ *
+ * This implementation contains an optimized path for 3-by-3 matrices
+ * which is especially useful for plane fitting.
+ *
+ * \note Currently, it requires two temporary vectors to hold the intermediate
+ * Householder coefficients, and to reconstruct the matrix Q from the Householder
+ * reflectors.
+ *
+ * Example (this uses the same matrix as the example in
+ * Tridiagonalization::Tridiagonalization(const MatrixType&)):
+ * \include Tridiagonalization_decomposeInPlace.cpp
+ * Output: \verbinclude Tridiagonalization_decomposeInPlace.out
+ *
+ * \sa class Tridiagonalization
+ */
+template<typename MatrixType, typename DiagonalType, typename SubDiagonalType>
+void tridiagonalization_inplace(MatrixType& mat, DiagonalType& diag, SubDiagonalType& subdiag, bool extractQ)
+{
+ typedef typename MatrixType::Index Index;
+ //Index n = mat.rows();
+ eigen_assert(mat.cols()==mat.rows() && diag.size()==mat.rows() && subdiag.size()==mat.rows()-1);
+ tridiagonalization_inplace_selector<MatrixType>::run(mat, diag, subdiag, extractQ);
+}
+
+/** \internal
+ * General full tridiagonalization
+ */
+template<typename MatrixType, int Size, bool IsComplex>
+struct tridiagonalization_inplace_selector
+{
+ typedef typename Tridiagonalization<MatrixType>::CoeffVectorType CoeffVectorType;
+ typedef typename Tridiagonalization<MatrixType>::HouseholderSequenceType HouseholderSequenceType;
+ typedef typename MatrixType::Index Index;
+ template<typename DiagonalType, typename SubDiagonalType>
+ static void run(MatrixType& mat, DiagonalType& diag, SubDiagonalType& subdiag, bool extractQ)
+ {
+ CoeffVectorType hCoeffs(mat.cols()-1);
+ tridiagonalization_inplace(mat,hCoeffs);
+ diag = mat.diagonal().real();
+ subdiag = mat.template diagonal<-1>().real();
+ if(extractQ)
+ mat = HouseholderSequenceType(mat, hCoeffs.conjugate())
+ .setLength(mat.rows() - 1)
+ .setShift(1);
+ }
+};
+
+/** \internal
+ * Specialization for 3x3 real matrices.
+ * Especially useful for plane fitting.
+ */
+template<typename MatrixType>
+struct tridiagonalization_inplace_selector<MatrixType,3,false>
+{
+ typedef typename MatrixType::Scalar Scalar;
+ typedef typename MatrixType::RealScalar RealScalar;
+
+ template<typename DiagonalType, typename SubDiagonalType>
+ static void run(MatrixType& mat, DiagonalType& diag, SubDiagonalType& subdiag, bool extractQ)
+ {
+ diag[0] = mat(0,0);
+ RealScalar v1norm2 = abs2(mat(2,0));
+ if(v1norm2 == RealScalar(0))
+ {
+ diag[1] = mat(1,1);
+ diag[2] = mat(2,2);
+ subdiag[0] = mat(1,0);
+ subdiag[1] = mat(2,1);
+ if (extractQ)
+ mat.setIdentity();
+ }
+ else
+ {
+ RealScalar beta = sqrt(abs2(mat(1,0)) + v1norm2);
+ RealScalar invBeta = RealScalar(1)/beta;
+ Scalar m01 = mat(1,0) * invBeta;
+ Scalar m02 = mat(2,0) * invBeta;
+ Scalar q = RealScalar(2)*m01*mat(2,1) + m02*(mat(2,2) - mat(1,1));
+ diag[1] = mat(1,1) + m02*q;
+ diag[2] = mat(2,2) - m02*q;
+ subdiag[0] = beta;
+ subdiag[1] = mat(2,1) - m01 * q;
+ if (extractQ)
+ {
+ mat << 1, 0, 0,
+ 0, m01, m02,
+ 0, m02, -m01;
+ }
+ }
+ }
+};
+
+/** \internal
+ * Trivial specialization for 1x1 matrices
+ */
+template<typename MatrixType, bool IsComplex>
+struct tridiagonalization_inplace_selector<MatrixType,1,IsComplex>
+{
+ typedef typename MatrixType::Scalar Scalar;
+
+ template<typename DiagonalType, typename SubDiagonalType>
+ static void run(MatrixType& mat, DiagonalType& diag, SubDiagonalType&, bool extractQ)
+ {
+ diag(0,0) = real(mat(0,0));
+ if(extractQ)
+ mat(0,0) = Scalar(1);
+ }
+};
+
+/** \internal
+ * \eigenvalues_module \ingroup Eigenvalues_Module
+ *
+ * \brief Expression type for return value of Tridiagonalization::matrixT()
+ *
+ * \tparam MatrixType type of underlying dense matrix
+ */
+template<typename MatrixType> struct TridiagonalizationMatrixTReturnType
+: public ReturnByValue<TridiagonalizationMatrixTReturnType<MatrixType> >
+{
+ typedef typename MatrixType::Index Index;
+ public:
+ /** \brief Constructor.
+ *
+ * \param[in] mat The underlying dense matrix
+ */
+ TridiagonalizationMatrixTReturnType(const MatrixType& mat) : m_matrix(mat) { }
+
+ template <typename ResultType>
+ inline void evalTo(ResultType& result) const
+ {
+ result.setZero();
+ result.template diagonal<1>() = m_matrix.template diagonal<-1>().conjugate();
+ result.diagonal() = m_matrix.diagonal();
+ result.template diagonal<-1>() = m_matrix.template diagonal<-1>();
+ }
+
+ Index rows() const { return m_matrix.rows(); }
+ Index cols() const { return m_matrix.cols(); }
+
+ protected:
+ typename MatrixType::Nested m_matrix;
+};
+
+} // end namespace internal
+
+} // end namespace Eigen
+
+#endif // EIGEN_TRIDIAGONALIZATION_H
diff --git a/Eigen/src/Geometry/AlignedBox.h b/Eigen/src/Geometry/AlignedBox.h
new file mode 100644
index 000000000..5830fcd35
--- /dev/null
+++ b/Eigen/src/Geometry/AlignedBox.h
@@ -0,0 +1,375 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra.
+//
+// Copyright (C) 2008 Gael Guennebaud <gael.guennebaud@inria.fr>
+//
+// This Source Code Form is subject to the terms of the Mozilla
+// Public License v. 2.0. If a copy of the MPL was not distributed
+// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+#ifndef EIGEN_ALIGNEDBOX_H
+#define EIGEN_ALIGNEDBOX_H
+
+namespace Eigen {
+
+/** \geometry_module \ingroup Geometry_Module
+ *
+ *
+ * \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 <typename _Scalar, int _AmbientDim>
+class AlignedBox
+{
+public:
+EIGEN_MAKE_ALIGNED_OPERATOR_NEW_IF_VECTORIZABLE_FIXED_SIZE(_Scalar,_AmbientDim)
+ enum { AmbientDimAtCompileTime = _AmbientDim };
+ typedef _Scalar Scalar;
+ typedef NumTraits<Scalar> ScalarTraits;
+ typedef DenseIndex Index;
+ typedef typename ScalarTraits::Real RealScalar;
+ typedef typename ScalarTraits::NonInteger NonInteger;
+ typedef Matrix<Scalar,AmbientDimAtCompileTime,1> VectorType;
+
+ /** Define constants to name the corners of a 1D, 2D or 3D axis aligned bounding box */
+ enum CornerType
+ {
+ /** 1D names */
+ Min=0, Max=1,
+
+ /** Added names for 2D */
+ BottomLeft=0, BottomRight=1,
+ TopLeft=2, TopRight=3,
+
+ /** Added names for 3D */
+ BottomLeftFloor=0, BottomRightFloor=1,
+ TopLeftFloor=2, TopRightFloor=3,
+ BottomLeftCeil=4, BottomRightCeil=5,
+ TopLeftCeil=6, TopRightCeil=7
+ };
+
+
+ /** Default constructor initializing a null box. */
+ inline explicit AlignedBox()
+ { if (AmbientDimAtCompileTime!=Dynamic) setEmpty(); }
+
+ /** Constructs a null box with \a _dim the dimension of the ambient space. */
+ inline explicit AlignedBox(Index _dim) : m_min(_dim), m_max(_dim)
+ { setEmpty(); }
+
+ /** Constructs a box with extremities \a _min and \a _max. */
+ template<typename OtherVectorType1, typename OtherVectorType2>
+ inline AlignedBox(const OtherVectorType1& _min, const OtherVectorType2& _max) : m_min(_min), m_max(_max) {}
+
+ /** Constructs a box containing a single point \a p. */
+ template<typename Derived>
+ inline explicit AlignedBox(const MatrixBase<Derived>& a_p)
+ {
+ const typename internal::nested<Derived,2>::type p(a_p.derived());
+ m_min = p;
+ m_max = p;
+ }
+
+ ~AlignedBox() {}
+
+ /** \returns the dimension in which the box holds */
+ inline Index dim() const { return AmbientDimAtCompileTime==Dynamic ? m_min.size()-1 : Index(AmbientDimAtCompileTime); }
+
+ /** \deprecated use isEmpty */
+ inline bool isNull() const { return isEmpty(); }
+
+ /** \deprecated use setEmpty */
+ inline void setNull() { setEmpty(); }
+
+ /** \returns true if the box is empty. */
+ inline bool isEmpty() const { return (m_min.array() > m_max.array()).any(); }
+
+ /** Makes \c *this an empty box. */
+ inline void setEmpty()
+ {
+ m_min.setConstant( ScalarTraits::highest() );
+ m_max.setConstant( ScalarTraits::lowest() );
+ }
+
+ /** \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 the center of the box */
+ inline const CwiseUnaryOp<internal::scalar_quotient1_op<Scalar>,
+ const CwiseBinaryOp<internal::scalar_sum_op<Scalar>, const VectorType, const VectorType> >
+ center() const
+ { return (m_min+m_max)/2; }
+
+ /** \returns the lengths of the sides of the bounding box.
+ * Note that this function does not get the same
+ * result for integral or floating scalar types: see
+ */
+ inline const CwiseBinaryOp< internal::scalar_difference_op<Scalar>, const VectorType, const VectorType> sizes() const
+ { return m_max - m_min; }
+
+ /** \returns the volume of the bounding box */
+ inline Scalar volume() const
+ { return sizes().prod(); }
+
+ /** \returns an expression for the bounding box diagonal vector
+ * if the length of the diagonal is needed: diagonal().norm()
+ * will provide it.
+ */
+ inline CwiseBinaryOp< internal::scalar_difference_op<Scalar>, const VectorType, const VectorType> diagonal() const
+ { return sizes(); }
+
+ /** \returns the vertex of the bounding box at the corner defined by
+ * the corner-id corner. It works only for a 1D, 2D or 3D bounding box.
+ * For 1D bounding boxes corners are named by 2 enum constants:
+ * BottomLeft and BottomRight.
+ * For 2D bounding boxes, corners are named by 4 enum constants:
+ * BottomLeft, BottomRight, TopLeft, TopRight.
+ * For 3D bounding boxes, the following names are added:
+ * BottomLeftCeil, BottomRightCeil, TopLeftCeil, TopRightCeil.
+ */
+ inline VectorType corner(CornerType corner) const
+ {
+ EIGEN_STATIC_ASSERT(_AmbientDim <= 3, THIS_METHOD_IS_ONLY_FOR_VECTORS_OF_A_SPECIFIC_SIZE);
+
+ VectorType res;
+
+ Index mult = 1;
+ for(Index d=0; d<dim(); ++d)
+ {
+ if( mult & corner ) res[d] = m_max[d];
+ else res[d] = m_min[d];
+ mult *= 2;
+ }
+ return res;
+ }
+
+ /** \returns a random point inside the bounding box sampled with
+ * a uniform distribution */
+ inline VectorType sample() const
+ {
+ VectorType r;
+ for(Index d=0; d<dim(); ++d)
+ {
+ if(!ScalarTraits::IsInteger)
+ {
+ r[d] = m_min[d] + (m_max[d]-m_min[d])
+ * internal::random<Scalar>(Scalar(0), Scalar(1));
+ }
+ else
+ r[d] = internal::random(m_min[d], m_max[d]);
+ }
+ return r;
+ }
+
+ /** \returns true if the point \a p is inside the box \c *this. */
+ template<typename Derived>
+ inline bool contains(const MatrixBase<Derived>& a_p) const
+ {
+ typename internal::nested<Derived,2>::type p(a_p.derived());
+ return (m_min.array()<=p.array()).all() && (p.array()<=m_max.array()).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.array()<=(b.min)().array()).all() && ((b.max)().array()<=m_max.array()).all(); }
+
+ /** Extends \c *this such that it contains the point \a p and returns a reference to \c *this. */
+ template<typename Derived>
+ inline AlignedBox& extend(const MatrixBase<Derived>& a_p)
+ {
+ typename internal::nested<Derived,2>::type p(a_p.derived());
+ m_min = m_min.cwiseMin(p);
+ m_max = m_max.cwiseMax(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.cwiseMin(b.m_min);
+ m_max = m_max.cwiseMax(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.cwiseMax(b.m_min);
+ m_max = m_max.cwiseMin(b.m_max);
+ return *this;
+ }
+
+ /** Returns an AlignedBox that is the intersection of \a b and \c *this */
+ inline AlignedBox intersection(const AlignedBox& b) const
+ {return AlignedBox(m_min.cwiseMax(b.m_min), m_max.cwiseMin(b.m_max)); }
+
+ /** Returns an AlignedBox that is the union of \a b and \c *this */
+ inline AlignedBox merged(const AlignedBox& b) const
+ { return AlignedBox(m_min.cwiseMin(b.m_min), m_max.cwiseMax(b.m_max)); }
+
+ /** Translate \c *this by the vector \a t and returns a reference to \c *this. */
+ template<typename Derived>
+ inline AlignedBox& translate(const MatrixBase<Derived>& a_t)
+ {
+ const typename internal::nested<Derived,2>::type t(a_t.derived());
+ 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()
+ */
+ template<typename Derived>
+ inline Scalar squaredExteriorDistance(const MatrixBase<Derived>& a_p) const;
+
+ /** \returns the squared distance between the boxes \a b and \c *this,
+ * and zero if the boxes intersect.
+ * \sa exteriorDistance()
+ */
+ inline Scalar squaredExteriorDistance(const AlignedBox& b) 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()
+ */
+ template<typename Derived>
+ inline NonInteger exteriorDistance(const MatrixBase<Derived>& p) const
+ { return internal::sqrt(NonInteger(squaredExteriorDistance(p))); }
+
+ /** \returns the distance between the boxes \a b and \c *this,
+ * and zero if the boxes intersect.
+ * \sa squaredExteriorDistance()
+ */
+ inline NonInteger exteriorDistance(const AlignedBox& b) const
+ { return internal::sqrt(NonInteger(squaredExteriorDistance(b))); }
+
+ /** \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<typename NewScalarType>
+ inline typename internal::cast_return_type<AlignedBox,
+ AlignedBox<NewScalarType,AmbientDimAtCompileTime> >::type cast() const
+ {
+ return typename internal::cast_return_type<AlignedBox,
+ AlignedBox<NewScalarType,AmbientDimAtCompileTime> >::type(*this);
+ }
+
+ /** Copy constructor with scalar type conversion */
+ template<typename OtherScalarType>
+ inline explicit AlignedBox(const AlignedBox<OtherScalarType,AmbientDimAtCompileTime>& other)
+ {
+ m_min = (other.min)().template cast<Scalar>();
+ m_max = (other.max)().template cast<Scalar>();
+ }
+
+ /** \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, RealScalar prec = ScalarTraits::dummy_precision()) const
+ { return m_min.isApprox(other.m_min, prec) && m_max.isApprox(other.m_max, prec); }
+
+protected:
+
+ VectorType m_min, m_max;
+};
+
+
+
+template<typename Scalar,int AmbientDim>
+template<typename Derived>
+inline Scalar AlignedBox<Scalar,AmbientDim>::squaredExteriorDistance(const MatrixBase<Derived>& a_p) const
+{
+ const typename internal::nested<Derived,2*AmbientDim>::type p(a_p.derived());
+ Scalar dist2(0);
+ Scalar aux;
+ for (Index k=0; k<dim(); ++k)
+ {
+ if( m_min[k] > p[k] )
+ {
+ aux = m_min[k] - p[k];
+ dist2 += aux*aux;
+ }
+ else if( p[k] > m_max[k] )
+ {
+ aux = p[k] - m_max[k];
+ dist2 += aux*aux;
+ }
+ }
+ return dist2;
+}
+
+template<typename Scalar,int AmbientDim>
+inline Scalar AlignedBox<Scalar,AmbientDim>::squaredExteriorDistance(const AlignedBox& b) const
+{
+ Scalar dist2(0);
+ Scalar aux;
+ for (Index k=0; k<dim(); ++k)
+ {
+ if( m_min[k] > b.m_max[k] )
+ {
+ aux = m_min[k] - b.m_max[k];
+ dist2 += aux*aux;
+ }
+ else if( b.m_min[k] > m_max[k] )
+ {
+ aux = b.m_min[k] - m_max[k];
+ dist2 += aux*aux;
+ }
+ }
+ return dist2;
+}
+
+/** \defgroup alignedboxtypedefs Global aligned box typedefs
+ *
+ * \ingroup Geometry_Module
+ *
+ * Eigen defines several typedef shortcuts for most common aligned box types.
+ *
+ * The general patterns are the following:
+ *
+ * \c AlignedBoxSizeType where \c Size can be \c 1, \c 2,\c 3,\c 4 for fixed size boxes or \c X for dynamic size,
+ * and where \c Type can be \c i for integer, \c f for float, \c d for double.
+ *
+ * For example, \c AlignedBox3d is a fixed-size 3x3 aligned box type of doubles, and \c AlignedBoxXf is a dynamic-size aligned box of floats.
+ *
+ * \sa class AlignedBox
+ */
+
+#define EIGEN_MAKE_TYPEDEFS(Type, TypeSuffix, Size, SizeSuffix) \
+/** \ingroup alignedboxtypedefs */ \
+typedef AlignedBox<Type, Size> AlignedBox##SizeSuffix##TypeSuffix;
+
+#define EIGEN_MAKE_TYPEDEFS_ALL_SIZES(Type, TypeSuffix) \
+EIGEN_MAKE_TYPEDEFS(Type, TypeSuffix, 1, 1) \
+EIGEN_MAKE_TYPEDEFS(Type, TypeSuffix, 2, 2) \
+EIGEN_MAKE_TYPEDEFS(Type, TypeSuffix, 3, 3) \
+EIGEN_MAKE_TYPEDEFS(Type, TypeSuffix, 4, 4) \
+EIGEN_MAKE_TYPEDEFS(Type, TypeSuffix, Dynamic, X)
+
+EIGEN_MAKE_TYPEDEFS_ALL_SIZES(int, i)
+EIGEN_MAKE_TYPEDEFS_ALL_SIZES(float, f)
+EIGEN_MAKE_TYPEDEFS_ALL_SIZES(double, d)
+
+#undef EIGEN_MAKE_TYPEDEFS_ALL_SIZES
+#undef EIGEN_MAKE_TYPEDEFS
+
+} // end namespace Eigen
+
+#endif // EIGEN_ALIGNEDBOX_H
diff --git a/Eigen/src/Geometry/AngleAxis.h b/Eigen/src/Geometry/AngleAxis.h
new file mode 100644
index 000000000..67197ac78
--- /dev/null
+++ b/Eigen/src/Geometry/AngleAxis.h
@@ -0,0 +1,230 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra.
+//
+// Copyright (C) 2008 Gael Guennebaud <gael.guennebaud@inria.fr>
+//
+// This Source Code Form is subject to the terms of the Mozilla
+// Public License v. 2.0. If a copy of the MPL was not distributed
+// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+#ifndef EIGEN_ANGLEAXIS_H
+#define EIGEN_ANGLEAXIS_H
+
+namespace Eigen {
+
+/** \geometry_module \ingroup Geometry_Module
+ *
+ * \class AngleAxis
+ *
+ * \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.
+ *
+ * \warning When setting up an AngleAxis object, the axis vector \b must \b be \b normalized.
+ *
+ * The following two typedefs are provided for convenience:
+ * \li \c AngleAxisf for \c float
+ * \li \c AngleAxisd for \c double
+ *
+ * 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()
+ */
+
+namespace internal {
+template<typename _Scalar> struct traits<AngleAxis<_Scalar> >
+{
+ typedef _Scalar Scalar;
+};
+}
+
+template<typename _Scalar>
+class AngleAxis : public RotationBase<AngleAxis<_Scalar>,3>
+{
+ typedef RotationBase<AngleAxis<_Scalar>,3> Base;
+
+public:
+
+ using Base::operator*;
+
+ enum { Dim = 3 };
+ /** the scalar type of the coefficients */
+ typedef _Scalar Scalar;
+ typedef Matrix<Scalar,3,3> Matrix3;
+ typedef Matrix<Scalar,3,1> Vector3;
+ typedef Quaternion<Scalar> 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 \b must \b be \b normalized.
+ *
+ * \warning If the \a axis vector is not normalized, then the angle-axis object
+ * represents an invalid rotation. */
+ template<typename Derived>
+ inline AngleAxis(Scalar angle, const MatrixBase<Derived>& axis) : m_axis(axis), m_angle(angle) {}
+ /** Constructs and initialize the angle-axis rotation from a quaternion \a q. */
+ template<typename QuatDerived> inline explicit AngleAxis(const QuaternionBase<QuatDerived>& q) { *this = q; }
+ /** Constructs and initialize the angle-axis rotation from a 3x3 rotation matrix. */
+ template<typename Derived>
+ inline explicit AngleAxis(const MatrixBase<Derived>& 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); }
+
+ /** \returns the inverse rotation, i.e., an angle-axis with opposite rotation angle */
+ AngleAxis inverse() const
+ { return AngleAxis(-m_angle, m_axis); }
+
+ template<class QuatDerived>
+ AngleAxis& operator=(const QuaternionBase<QuatDerived>& q);
+ template<typename Derived>
+ AngleAxis& operator=(const MatrixBase<Derived>& m);
+
+ template<typename Derived>
+ AngleAxis& fromRotationMatrix(const MatrixBase<Derived>& 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<typename NewScalarType>
+ inline typename internal::cast_return_type<AngleAxis,AngleAxis<NewScalarType> >::type cast() const
+ { return typename internal::cast_return_type<AngleAxis,AngleAxis<NewScalarType> >::type(*this); }
+
+ /** Copy constructor with scalar type conversion */
+ template<typename OtherScalarType>
+ inline explicit AngleAxis(const AngleAxis<OtherScalarType>& other)
+ {
+ m_axis = other.axis().template cast<Scalar>();
+ m_angle = Scalar(other.angle());
+ }
+
+ static inline const AngleAxis Identity() { return AngleAxis(0, Vector3::UnitX()); }
+
+ /** \returns \c true if \c *this is approximately equal to \a other, within the precision
+ * determined by \a prec.
+ *
+ * \sa MatrixBase::isApprox() */
+ bool isApprox(const AngleAxis& other, typename NumTraits<Scalar>::Real prec = NumTraits<Scalar>::dummy_precision()) const
+ { return m_axis.isApprox(other.m_axis, prec) && internal::isApprox(m_angle,other.m_angle, prec); }
+};
+
+/** \ingroup Geometry_Module
+ * single precision angle-axis type */
+typedef AngleAxis<float> AngleAxisf;
+/** \ingroup Geometry_Module
+ * double precision angle-axis type */
+typedef AngleAxis<double> AngleAxisd;
+
+/** Set \c *this from a \b unit quaternion.
+ * The axis is normalized.
+ *
+ * \warning As any other method dealing with quaternion, if the input quaternion
+ * is not normalized then the result is undefined.
+ */
+template<typename Scalar>
+template<typename QuatDerived>
+AngleAxis<Scalar>& AngleAxis<Scalar>::operator=(const QuaternionBase<QuatDerived>& q)
+{
+ using std::acos;
+ using std::min;
+ using std::max;
+ Scalar n2 = q.vec().squaredNorm();
+ if (n2 < NumTraits<Scalar>::dummy_precision()*NumTraits<Scalar>::dummy_precision())
+ {
+ m_angle = 0;
+ m_axis << 1, 0, 0;
+ }
+ else
+ {
+ m_angle = Scalar(2)*acos((min)((max)(Scalar(-1),q.w()),Scalar(1)));
+ m_axis = q.vec() / internal::sqrt(n2);
+ }
+ return *this;
+}
+
+/** Set \c *this from a 3x3 rotation matrix \a mat.
+ */
+template<typename Scalar>
+template<typename Derived>
+AngleAxis<Scalar>& AngleAxis<Scalar>::operator=(const MatrixBase<Derived>& mat)
+{
+ // Since a direct conversion would not be really faster,
+ // let's use the robust Quaternion implementation:
+ return *this = QuaternionType(mat);
+}
+
+/**
+* \brief Sets \c *this from a 3x3 rotation matrix.
+**/
+template<typename Scalar>
+template<typename Derived>
+AngleAxis<Scalar>& AngleAxis<Scalar>::fromRotationMatrix(const MatrixBase<Derived>& mat)
+{
+ return *this = QuaternionType(mat);
+}
+
+/** Constructs and \returns an equivalent 3x3 rotation matrix.
+ */
+template<typename Scalar>
+typename AngleAxis<Scalar>::Matrix3
+AngleAxis<Scalar>::toRotationMatrix(void) const
+{
+ Matrix3 res;
+ Vector3 sin_axis = internal::sin(m_angle) * m_axis;
+ Scalar c = internal::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.cwiseProduct(m_axis)).array() + c;
+
+ return res;
+}
+
+} // end namespace Eigen
+
+#endif // EIGEN_ANGLEAXIS_H
diff --git a/Eigen/src/Geometry/CMakeLists.txt b/Eigen/src/Geometry/CMakeLists.txt
new file mode 100644
index 000000000..f8f728b84
--- /dev/null
+++ b/Eigen/src/Geometry/CMakeLists.txt
@@ -0,0 +1,8 @@
+FILE(GLOB Eigen_Geometry_SRCS "*.h")
+
+INSTALL(FILES
+ ${Eigen_Geometry_SRCS}
+ DESTINATION ${INCLUDE_INSTALL_DIR}/Eigen/src/Geometry COMPONENT Devel
+ )
+
+ADD_SUBDIRECTORY(arch)
diff --git a/Eigen/src/Geometry/EulerAngles.h b/Eigen/src/Geometry/EulerAngles.h
new file mode 100644
index 000000000..e424d2406
--- /dev/null
+++ b/Eigen/src/Geometry/EulerAngles.h
@@ -0,0 +1,84 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra.
+//
+// Copyright (C) 2008 Gael Guennebaud <gael.guennebaud@inria.fr>
+//
+// This Source Code Form is subject to the terms of the Mozilla
+// Public License v. 2.0. If a copy of the MPL was not distributed
+// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+#ifndef EIGEN_EULERANGLES_H
+#define EIGEN_EULERANGLES_H
+
+namespace Eigen {
+
+/** \geometry_module \ingroup Geometry_Module
+ *
+ *
+ * \returns the Euler-angles of the rotation matrix \c *this using the convention defined by the triplet (\a a0,\a a1,\a a2)
+ *
+ * Each of the three parameters \a a0,\a a1,\a a2 represents the respective rotation axis as an integer in {0,1,2}.
+ * For instance, in:
+ * \code Vector3f ea = mat.eulerAngles(2, 0, 2); \endcode
+ * "2" represents the z axis and "0" the x axis, etc. The returned angles are such that
+ * we have the following equality:
+ * \code
+ * mat == AngleAxisf(ea[0], Vector3f::UnitZ())
+ * * AngleAxisf(ea[1], Vector3f::UnitX())
+ * * AngleAxisf(ea[2], Vector3f::UnitZ()); \endcode
+ * This corresponds to the right-multiply conventions (with right hand side frames).
+ */
+template<typename Derived>
+inline Matrix<typename MatrixBase<Derived>::Scalar,3,1>
+MatrixBase<Derived>::eulerAngles(Index a0, Index a1, Index a2) const
+{
+ /* Implemented from Graphics Gems IV */
+ EIGEN_STATIC_ASSERT_MATRIX_SPECIFIC_SIZE(Derived,3,3)
+
+ Matrix<Scalar,3,1> res;
+ typedef Matrix<typename Derived::Scalar,2,1> Vector2;
+ const Scalar epsilon = NumTraits<Scalar>::dummy_precision();
+
+ const Index odd = ((a0+1)%3 == a1) ? 0 : 1;
+ const Index i = a0;
+ const Index j = (a0 + 1 + odd)%3;
+ const Index k = (a0 + 2 - odd)%3;
+
+ if (a0==a2)
+ {
+ Scalar s = Vector2(coeff(j,i) , coeff(k,i)).norm();
+ res[1] = internal::atan2(s, coeff(i,i));
+ if (s > epsilon)
+ {
+ res[0] = internal::atan2(coeff(j,i), coeff(k,i));
+ res[2] = internal::atan2(coeff(i,j),-coeff(i,k));
+ }
+ else
+ {
+ res[0] = Scalar(0);
+ res[2] = (coeff(i,i)>0?1:-1)*internal::atan2(-coeff(k,j), coeff(j,j));
+ }
+ }
+ else
+ {
+ Scalar c = Vector2(coeff(i,i) , coeff(i,j)).norm();
+ res[1] = internal::atan2(-coeff(i,k), c);
+ if (c > epsilon)
+ {
+ res[0] = internal::atan2(coeff(j,k), coeff(k,k));
+ res[2] = internal::atan2(coeff(i,j), coeff(i,i));
+ }
+ else
+ {
+ res[0] = Scalar(0);
+ res[2] = (coeff(i,k)>0?1:-1)*internal::atan2(-coeff(k,j), coeff(j,j));
+ }
+ }
+ if (!odd)
+ res = -res;
+ return res;
+}
+
+} // end namespace Eigen
+
+#endif // EIGEN_EULERANGLES_H
diff --git a/Eigen/src/Geometry/Homogeneous.h b/Eigen/src/Geometry/Homogeneous.h
new file mode 100644
index 000000000..df03feb55
--- /dev/null
+++ b/Eigen/src/Geometry/Homogeneous.h
@@ -0,0 +1,307 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra.
+//
+// Copyright (C) 2009-2010 Gael Guennebaud <gael.guennebaud@inria.fr>
+//
+// This Source Code Form is subject to the terms of the Mozilla
+// Public License v. 2.0. If 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<typename MatrixType,int Direction>
+struct traits<Homogeneous<MatrixType,Direction> >
+ : traits<MatrixType>
+{
+ typedef typename traits<MatrixType>::StorageKind StorageKind;
+ typedef typename nested<MatrixType>::type MatrixTypeNested;
+ typedef typename remove_reference<MatrixTypeNested>::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<typename MatrixType,typename Lhs> struct homogeneous_left_product_impl;
+template<typename MatrixType,typename Rhs> struct homogeneous_right_product_impl;
+
+} // end namespace internal
+
+template<typename MatrixType,int _Direction> class Homogeneous
+ : public MatrixBase<Homogeneous<MatrixType,_Direction> >
+{
+ public:
+
+ enum { Direction = _Direction };
+
+ typedef MatrixBase<Homogeneous> 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 1;
+ return m_matrix.coeff(row, col);
+ }
+
+ template<typename Rhs>
+ inline const internal::homogeneous_right_product_impl<Homogeneous,Rhs>
+ operator* (const MatrixBase<Rhs>& rhs) const
+ {
+ eigen_assert(int(Direction)==Horizontal);
+ return internal::homogeneous_right_product_impl<Homogeneous,Rhs>(m_matrix,rhs.derived());
+ }
+
+ template<typename Lhs> friend
+ inline const internal::homogeneous_left_product_impl<Homogeneous,Lhs>
+ operator* (const MatrixBase<Lhs>& lhs, const Homogeneous& rhs)
+ {
+ eigen_assert(int(Direction)==Vertical);
+ return internal::homogeneous_left_product_impl<Homogeneous,Lhs>(lhs.derived(),rhs.m_matrix);
+ }
+
+ template<typename Scalar, int Dim, int Mode, int Options> friend
+ inline const internal::homogeneous_left_product_impl<Homogeneous,Transform<Scalar,Dim,Mode,Options> >
+ operator* (const Transform<Scalar,Dim,Mode,Options>& lhs, const Homogeneous& rhs)
+ {
+ eigen_assert(int(Direction)==Vertical);
+ return internal::homogeneous_left_product_impl<Homogeneous,Transform<Scalar,Dim,Mode,Options> >(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<typename Derived>
+inline typename MatrixBase<Derived>::HomogeneousReturnType
+MatrixBase<Derived>::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<typename ExpressionType, int Direction>
+inline Homogeneous<ExpressionType,Direction>
+VectorwiseOp<ExpressionType,Direction>::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<typename Derived>
+inline const typename MatrixBase<Derived>::HNormalizedReturnType
+MatrixBase<Derived>::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<typename ExpressionType, int Direction>
+inline const typename VectorwiseOp<ExpressionType,Direction>::HNormalizedReturnType
+VectorwiseOp<ExpressionType,Direction>::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,
+ Direction==Vertical ? HNormalized_SizeMinusOne : 1,
+ Direction==Horizontal ? HNormalized_SizeMinusOne : 1>
+ (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<typename MatrixOrTransformType>
+struct take_matrix_for_product
+{
+ typedef MatrixOrTransformType type;
+ static const type& run(const type &x) { return x; }
+};
+
+template<typename Scalar, int Dim, int Mode,int Options>
+struct take_matrix_for_product<Transform<Scalar, Dim, Mode, Options> >
+{
+ typedef Transform<Scalar, Dim, Mode, Options> TransformType;
+ typedef typename internal::add_const<typename TransformType::ConstAffinePart>::type type;
+ static type run (const TransformType& x) { return x.affine(); }
+};
+
+template<typename Scalar, int Dim, int Options>
+struct take_matrix_for_product<Transform<Scalar, Dim, Projective, Options> >
+{
+ typedef Transform<Scalar, Dim, Projective, Options> TransformType;
+ typedef typename TransformType::MatrixType type;
+ static const type& run (const TransformType& x) { return x.matrix(); }
+};
+
+template<typename MatrixType,typename Lhs>
+struct traits<homogeneous_left_product_impl<Homogeneous<MatrixType,Vertical>,Lhs> >
+{
+ typedef typename take_matrix_for_product<Lhs>::type LhsMatrixType;
+ typedef typename remove_all<MatrixType>::type MatrixTypeCleaned;
+ typedef typename remove_all<LhsMatrixType>::type LhsMatrixTypeCleaned;
+ typedef typename make_proper_matrix_type<
+ typename traits<MatrixTypeCleaned>::Scalar,
+ LhsMatrixTypeCleaned::RowsAtCompileTime,
+ MatrixTypeCleaned::ColsAtCompileTime,
+ MatrixTypeCleaned::PlainObject::Options,
+ LhsMatrixTypeCleaned::MaxRowsAtCompileTime,
+ MatrixTypeCleaned::MaxColsAtCompileTime>::type ReturnType;
+};
+
+template<typename MatrixType,typename Lhs>
+struct homogeneous_left_product_impl<Homogeneous<MatrixType,Vertical>,Lhs>
+ : public ReturnByValue<homogeneous_left_product_impl<Homogeneous<MatrixType,Vertical>,Lhs> >
+{
+ typedef typename traits<homogeneous_left_product_impl>::LhsMatrixType LhsMatrixType;
+ typedef typename remove_all<LhsMatrixType>::type LhsMatrixTypeCleaned;
+ typedef typename remove_all<typename LhsMatrixTypeCleaned::Nested>::type LhsMatrixTypeNested;
+ typedef typename MatrixType::Index Index;
+ homogeneous_left_product_impl(const Lhs& lhs, const MatrixType& rhs)
+ : m_lhs(take_matrix_for_product<Lhs>::run(lhs)),
+ m_rhs(rhs)
+ {}
+
+ inline Index rows() const { return m_lhs.rows(); }
+ inline Index cols() const { return m_rhs.cols(); }
+
+ template<typename Dest> void evalTo(Dest& dst) const
+ {
+ // FIXME investigate how to allow lazy evaluation of this product when possible
+ dst = Block<const LhsMatrixTypeNested,
+ LhsMatrixTypeNested::RowsAtCompileTime,
+ LhsMatrixTypeNested::ColsAtCompileTime==Dynamic?Dynamic:LhsMatrixTypeNested::ColsAtCompileTime-1>
+ (m_lhs,0,0,m_lhs.rows(),m_lhs.cols()-1) * m_rhs;
+ dst += m_lhs.col(m_lhs.cols()-1).rowwise()
+ .template replicate<MatrixType::ColsAtCompileTime>(m_rhs.cols());
+ }
+
+ typename LhsMatrixTypeCleaned::Nested m_lhs;
+ typename MatrixType::Nested m_rhs;
+};
+
+template<typename MatrixType,typename Rhs>
+struct traits<homogeneous_right_product_impl<Homogeneous<MatrixType,Horizontal>,Rhs> >
+{
+ typedef typename make_proper_matrix_type<typename traits<MatrixType>::Scalar,
+ MatrixType::RowsAtCompileTime,
+ Rhs::ColsAtCompileTime,
+ MatrixType::PlainObject::Options,
+ MatrixType::MaxRowsAtCompileTime,
+ Rhs::MaxColsAtCompileTime>::type ReturnType;
+};
+
+template<typename MatrixType,typename Rhs>
+struct homogeneous_right_product_impl<Homogeneous<MatrixType,Horizontal>,Rhs>
+ : public ReturnByValue<homogeneous_right_product_impl<Homogeneous<MatrixType,Horizontal>,Rhs> >
+{
+ typedef typename remove_all<typename Rhs::Nested>::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<typename Dest> void evalTo(Dest& dst) const
+ {
+ // FIXME investigate how to allow lazy evaluation of this product when possible
+ dst = m_lhs * Block<const RhsNested,
+ RhsNested::RowsAtCompileTime==Dynamic?Dynamic:RhsNested::RowsAtCompileTime-1,
+ RhsNested::ColsAtCompileTime>
+ (m_rhs,0,0,m_rhs.rows()-1,m_rhs.cols());
+ dst += m_rhs.row(m_rhs.rows()-1).colwise()
+ .template replicate<MatrixType::RowsAtCompileTime>(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/Eigen/src/Geometry/Hyperplane.h b/Eigen/src/Geometry/Hyperplane.h
new file mode 100644
index 000000000..1b7c7c78c
--- /dev/null
+++ b/Eigen/src/Geometry/Hyperplane.h
@@ -0,0 +1,269 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra.
+//
+// Copyright (C) 2008 Gael Guennebaud <gael.guennebaud@inria.fr>
+// Copyright (C) 2008 Benoit Jacob <jacob.benoit.1@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 EIGEN_HYPERPLANE_H
+#define EIGEN_HYPERPLANE_H
+
+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 <typename _Scalar, int _AmbientDim, int _Options>
+class Hyperplane
+{
+public:
+ EIGEN_MAKE_ALIGNED_OPERATOR_NEW_IF_VECTORIZABLE_FIXED_SIZE(_Scalar,_AmbientDim==Dynamic ? Dynamic : _AmbientDim+1)
+ enum {
+ AmbientDimAtCompileTime = _AmbientDim,
+ Options = _Options
+ };
+ typedef _Scalar Scalar;
+ typedef typename NumTraits<Scalar>::Real RealScalar;
+ typedef DenseIndex Index;
+ typedef Matrix<Scalar,AmbientDimAtCompileTime,1> VectorType;
+ typedef Matrix<Scalar,Index(AmbientDimAtCompileTime)==Dynamic
+ ? Dynamic
+ : Index(AmbientDimAtCompileTime)+1,1,Options> Coefficients;
+ typedef Block<Coefficients,AmbientDimAtCompileTime,1> NormalReturnType;
+ typedef const Block<const Coefficients,AmbientDimAtCompileTime,1> ConstNormalReturnType;
+
+ /** Default constructor without initialization */
+ inline explicit Hyperplane() {}
+
+ template<int OtherOptions>
+ Hyperplane(const Hyperplane<Scalar,AmbientDimAtCompileTime,OtherOptions>& other)
+ : m_coeffs(other.coeffs())
+ {}
+
+ /** Constructs a dynamic-size hyperplane with \a _dim the dimension
+ * of the ambient space */
+ inline explicit Hyperplane(Index _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() = -n.dot(e);
+ }
+
+ /** 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() = -p0.dot(result.normal());
+ 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() = -p0.dot(result.normal());
+ 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<Scalar, AmbientDimAtCompileTime>& parametrized)
+ {
+ normal() = parametrized.direction().unitOrthogonal();
+ offset() = -parametrized.origin().dot(normal());
+ }
+
+ ~Hyperplane() {}
+
+ /** \returns the dimension in which the plane holds */
+ inline Index dim() const { return AmbientDimAtCompileTime==Dynamic ? m_coeffs.size()-1 : Index(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 normal().dot(p) + 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 internal::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 ConstNormalReturnType normal() const { return ConstNormalReturnType(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) const
+ {
+ 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(internal::isMuchSmallerThan(det, Scalar(1)))
+ { // special case where the two lines are approximately parallel. Pick any point on the first line.
+ if(internal::abs(coeffs().coeff(1))>internal::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<typename XprType>
+ inline Hyperplane& transform(const MatrixBase<XprType>& mat, TransformTraits traits = Affine)
+ {
+ if (traits==Affine)
+ normal() = mat.inverse().transpose() * normal();
+ else if (traits==Isometry)
+ normal() = mat * normal();
+ else
+ {
+ eigen_assert(0 && "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.
+ */
+ template<int TrOptions>
+ inline Hyperplane& transform(const Transform<Scalar,AmbientDimAtCompileTime,Affine,TrOptions>& t,
+ TransformTraits traits = Affine)
+ {
+ transform(t.linear(), traits);
+ offset() -= normal().dot(t.translation());
+ 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<typename NewScalarType>
+ inline typename internal::cast_return_type<Hyperplane,
+ Hyperplane<NewScalarType,AmbientDimAtCompileTime,Options> >::type cast() const
+ {
+ return typename internal::cast_return_type<Hyperplane,
+ Hyperplane<NewScalarType,AmbientDimAtCompileTime,Options> >::type(*this);
+ }
+
+ /** Copy constructor with scalar type conversion */
+ template<typename OtherScalarType,int OtherOptions>
+ inline explicit Hyperplane(const Hyperplane<OtherScalarType,AmbientDimAtCompileTime,OtherOptions>& other)
+ { m_coeffs = other.coeffs().template cast<Scalar>(); }
+
+ /** \returns \c true if \c *this is approximately equal to \a other, within the precision
+ * determined by \a prec.
+ *
+ * \sa MatrixBase::isApprox() */
+ template<int OtherOptions>
+ bool isApprox(const Hyperplane<Scalar,AmbientDimAtCompileTime,OtherOptions>& other, typename NumTraits<Scalar>::Real prec = NumTraits<Scalar>::dummy_precision()) const
+ { return m_coeffs.isApprox(other.m_coeffs, prec); }
+
+protected:
+
+ Coefficients m_coeffs;
+};
+
+} // end namespace Eigen
+
+#endif // EIGEN_HYPERPLANE_H
diff --git a/Eigen/src/Geometry/OrthoMethods.h b/Eigen/src/Geometry/OrthoMethods.h
new file mode 100644
index 000000000..11ad5829c
--- /dev/null
+++ b/Eigen/src/Geometry/OrthoMethods.h
@@ -0,0 +1,218 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra.
+//
+// Copyright (C) 2008-2009 Gael Guennebaud <gael.guennebaud@inria.fr>
+// Copyright (C) 2006-2008 Benoit Jacob <jacob.benoit.1@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 EIGEN_ORTHOMETHODS_H
+#define EIGEN_ORTHOMETHODS_H
+
+namespace Eigen {
+
+/** \geometry_module
+ *
+ * \returns the cross product of \c *this and \a other
+ *
+ * Here is a very good explanation of cross-product: http://xkcd.com/199/
+ * \sa MatrixBase::cross3()
+ */
+template<typename Derived>
+template<typename OtherDerived>
+inline typename MatrixBase<Derived>::template cross_product_return_type<OtherDerived>::type
+MatrixBase<Derived>::cross(const MatrixBase<OtherDerived>& other) const
+{
+ EIGEN_STATIC_ASSERT_VECTOR_SPECIFIC_SIZE(Derived,3)
+ EIGEN_STATIC_ASSERT_VECTOR_SPECIFIC_SIZE(OtherDerived,3)
+
+ // Note that there is no need for an expression here since the compiler
+ // optimize such a small temporary very well (even within a complex expression)
+ typename internal::nested<Derived,2>::type lhs(derived());
+ typename internal::nested<OtherDerived,2>::type rhs(other.derived());
+ return typename cross_product_return_type<OtherDerived>::type(
+ internal::conj(lhs.coeff(1) * rhs.coeff(2) - lhs.coeff(2) * rhs.coeff(1)),
+ internal::conj(lhs.coeff(2) * rhs.coeff(0) - lhs.coeff(0) * rhs.coeff(2)),
+ internal::conj(lhs.coeff(0) * rhs.coeff(1) - lhs.coeff(1) * rhs.coeff(0))
+ );
+}
+
+namespace internal {
+
+template< int Arch,typename VectorLhs,typename VectorRhs,
+ typename Scalar = typename VectorLhs::Scalar,
+ bool Vectorizable = bool((VectorLhs::Flags&VectorRhs::Flags)&PacketAccessBit)>
+struct cross3_impl {
+ static inline typename internal::plain_matrix_type<VectorLhs>::type
+ run(const VectorLhs& lhs, const VectorRhs& rhs)
+ {
+ return typename internal::plain_matrix_type<VectorLhs>::type(
+ internal::conj(lhs.coeff(1) * rhs.coeff(2) - lhs.coeff(2) * rhs.coeff(1)),
+ internal::conj(lhs.coeff(2) * rhs.coeff(0) - lhs.coeff(0) * rhs.coeff(2)),
+ internal::conj(lhs.coeff(0) * rhs.coeff(1) - lhs.coeff(1) * rhs.coeff(0)),
+ 0
+ );
+ }
+};
+
+}
+
+/** \geometry_module
+ *
+ * \returns the cross product of \c *this and \a other using only the x, y, and z coefficients
+ *
+ * The size of \c *this and \a other must be four. This function is especially useful
+ * when using 4D vectors instead of 3D ones to get advantage of SSE/AltiVec vectorization.
+ *
+ * \sa MatrixBase::cross()
+ */
+template<typename Derived>
+template<typename OtherDerived>
+inline typename MatrixBase<Derived>::PlainObject
+MatrixBase<Derived>::cross3(const MatrixBase<OtherDerived>& other) const
+{
+ EIGEN_STATIC_ASSERT_VECTOR_SPECIFIC_SIZE(Derived,4)
+ EIGEN_STATIC_ASSERT_VECTOR_SPECIFIC_SIZE(OtherDerived,4)
+
+ typedef typename internal::nested<Derived,2>::type DerivedNested;
+ typedef typename internal::nested<OtherDerived,2>::type OtherDerivedNested;
+ const DerivedNested lhs(derived());
+ const OtherDerivedNested rhs(other.derived());
+
+ return internal::cross3_impl<Architecture::Target,
+ typename internal::remove_all<DerivedNested>::type,
+ typename internal::remove_all<OtherDerivedNested>::type>::run(lhs,rhs);
+}
+
+/** \returns a matrix expression of the cross product of each column or row
+ * of the referenced expression with the \a other vector.
+ *
+ * The referenced matrix must have one dimension equal to 3.
+ * The result matrix has the same dimensions than the referenced one.
+ *
+ * \geometry_module
+ *
+ * \sa MatrixBase::cross() */
+template<typename ExpressionType, int Direction>
+template<typename OtherDerived>
+const typename VectorwiseOp<ExpressionType,Direction>::CrossReturnType
+VectorwiseOp<ExpressionType,Direction>::cross(const MatrixBase<OtherDerived>& other) const
+{
+ EIGEN_STATIC_ASSERT_VECTOR_SPECIFIC_SIZE(OtherDerived,3)
+ EIGEN_STATIC_ASSERT((internal::is_same<Scalar, typename OtherDerived::Scalar>::value),
+ YOU_MIXED_DIFFERENT_NUMERIC_TYPES__YOU_NEED_TO_USE_THE_CAST_METHOD_OF_MATRIXBASE_TO_CAST_NUMERIC_TYPES_EXPLICITLY)
+
+ CrossReturnType res(_expression().rows(),_expression().cols());
+ if(Direction==Vertical)
+ {
+ eigen_assert(CrossReturnType::RowsAtCompileTime==3 && "the matrix must have exactly 3 rows");
+ res.row(0) = (_expression().row(1) * other.coeff(2) - _expression().row(2) * other.coeff(1)).conjugate();
+ res.row(1) = (_expression().row(2) * other.coeff(0) - _expression().row(0) * other.coeff(2)).conjugate();
+ res.row(2) = (_expression().row(0) * other.coeff(1) - _expression().row(1) * other.coeff(0)).conjugate();
+ }
+ else
+ {
+ eigen_assert(CrossReturnType::ColsAtCompileTime==3 && "the matrix must have exactly 3 columns");
+ res.col(0) = (_expression().col(1) * other.coeff(2) - _expression().col(2) * other.coeff(1)).conjugate();
+ res.col(1) = (_expression().col(2) * other.coeff(0) - _expression().col(0) * other.coeff(2)).conjugate();
+ res.col(2) = (_expression().col(0) * other.coeff(1) - _expression().col(1) * other.coeff(0)).conjugate();
+ }
+ return res;
+}
+
+namespace internal {
+
+template<typename Derived, int Size = Derived::SizeAtCompileTime>
+struct unitOrthogonal_selector
+{
+ typedef typename plain_matrix_type<Derived>::type VectorType;
+ typedef typename traits<Derived>::Scalar Scalar;
+ typedef typename NumTraits<Scalar>::Real RealScalar;
+ typedef typename Derived::Index Index;
+ typedef Matrix<Scalar,2,1> Vector2;
+ static inline VectorType run(const Derived& src)
+ {
+ VectorType perp = VectorType::Zero(src.size());
+ Index maxi = 0;
+ Index sndi = 0;
+ src.cwiseAbs().maxCoeff(&maxi);
+ if (maxi==0)
+ sndi = 1;
+ RealScalar invnm = RealScalar(1)/(Vector2() << src.coeff(sndi),src.coeff(maxi)).finished().norm();
+ perp.coeffRef(maxi) = -conj(src.coeff(sndi)) * invnm;
+ perp.coeffRef(sndi) = conj(src.coeff(maxi)) * invnm;
+
+ return perp;
+ }
+};
+
+template<typename Derived>
+struct unitOrthogonal_selector<Derived,3>
+{
+ typedef typename plain_matrix_type<Derived>::type VectorType;
+ typedef typename traits<Derived>::Scalar Scalar;
+ typedef typename NumTraits<Scalar>::Real RealScalar;
+ static inline VectorType run(const Derived& src)
+ {
+ VectorType perp;
+ /* Let us compute the crossed product of *this with a vector
+ * that is not too close to being colinear to *this.
+ */
+
+ /* unless the x and y coords are both close to zero, we can
+ * simply take ( -y, x, 0 ) and normalize it.
+ */
+ if((!isMuchSmallerThan(src.x(), src.z()))
+ || (!isMuchSmallerThan(src.y(), src.z())))
+ {
+ RealScalar invnm = RealScalar(1)/src.template head<2>().norm();
+ perp.coeffRef(0) = -conj(src.y())*invnm;
+ perp.coeffRef(1) = conj(src.x())*invnm;
+ perp.coeffRef(2) = 0;
+ }
+ /* if both x and y are close to zero, then the vector is close
+ * to the z-axis, so it's far from colinear to the x-axis for instance.
+ * So we take the crossed product with (1,0,0) and normalize it.
+ */
+ else
+ {
+ RealScalar invnm = RealScalar(1)/src.template tail<2>().norm();
+ perp.coeffRef(0) = 0;
+ perp.coeffRef(1) = -conj(src.z())*invnm;
+ perp.coeffRef(2) = conj(src.y())*invnm;
+ }
+
+ return perp;
+ }
+};
+
+template<typename Derived>
+struct unitOrthogonal_selector<Derived,2>
+{
+ typedef typename plain_matrix_type<Derived>::type VectorType;
+ static inline VectorType run(const Derived& src)
+ { return VectorType(-conj(src.y()), conj(src.x())).normalized(); }
+};
+
+} // end namespace internal
+
+/** \returns a unit vector which is orthogonal to \c *this
+ *
+ * The size of \c *this must be at least 2. If the size is exactly 2,
+ * then the returned vector is a counter clock wise rotation of \c *this, i.e., (-y,x).normalized().
+ *
+ * \sa cross()
+ */
+template<typename Derived>
+typename MatrixBase<Derived>::PlainObject
+MatrixBase<Derived>::unitOrthogonal() const
+{
+ EIGEN_STATIC_ASSERT_VECTOR_ONLY(Derived)
+ return internal::unitOrthogonal_selector<Derived>::run(derived());
+}
+
+} // end namespace Eigen
+
+#endif // EIGEN_ORTHOMETHODS_H
diff --git a/Eigen/src/Geometry/ParametrizedLine.h b/Eigen/src/Geometry/ParametrizedLine.h
new file mode 100644
index 000000000..719a90441
--- /dev/null
+++ b/Eigen/src/Geometry/ParametrizedLine.h
@@ -0,0 +1,195 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra.
+//
+// Copyright (C) 2008 Gael Guennebaud <gael.guennebaud@inria.fr>
+// Copyright (C) 2008 Benoit Jacob <jacob.benoit.1@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 EIGEN_PARAMETRIZEDLINE_H
+#define EIGEN_PARAMETRIZEDLINE_H
+
+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$ t \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 <typename _Scalar, int _AmbientDim, int _Options>
+class ParametrizedLine
+{
+public:
+ EIGEN_MAKE_ALIGNED_OPERATOR_NEW_IF_VECTORIZABLE_FIXED_SIZE(_Scalar,_AmbientDim)
+ enum {
+ AmbientDimAtCompileTime = _AmbientDim,
+ Options = _Options
+ };
+ typedef _Scalar Scalar;
+ typedef typename NumTraits<Scalar>::Real RealScalar;
+ typedef DenseIndex Index;
+ typedef Matrix<Scalar,AmbientDimAtCompileTime,1,Options> VectorType;
+
+ /** Default constructor without initialization */
+ inline explicit ParametrizedLine() {}
+
+ template<int OtherOptions>
+ ParametrizedLine(const ParametrizedLine<Scalar,AmbientDimAtCompileTime,OtherOptions>& other)
+ : m_origin(other.origin()), m_direction(other.direction())
+ {}
+
+ /** Constructs a dynamic-size line with \a _dim the dimension
+ * of the ambient space */
+ inline explicit ParametrizedLine(Index _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) {}
+
+ template <int OtherOptions>
+ explicit ParametrizedLine(const Hyperplane<_Scalar, _AmbientDim, OtherOptions>& 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 Index 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 - direction().dot(diff) * 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 internal::sqrt(squaredDistance(p)); }
+
+ /** \returns the projection of a point \a p onto the line \c *this. */
+ VectorType projection(const VectorType& p) const
+ { return origin() + direction().dot(p-origin()) * direction(); }
+
+ VectorType pointAt( Scalar t ) const;
+
+ template <int OtherOptions>
+ Scalar intersectionParameter(const Hyperplane<_Scalar, _AmbientDim, OtherOptions>& hyperplane) const;
+
+ template <int OtherOptions>
+ Scalar intersection(const Hyperplane<_Scalar, _AmbientDim, OtherOptions>& hyperplane) const;
+
+ template <int OtherOptions>
+ VectorType intersectionPoint(const Hyperplane<_Scalar, _AmbientDim, OtherOptions>& hyperplane) 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<typename NewScalarType>
+ inline typename internal::cast_return_type<ParametrizedLine,
+ ParametrizedLine<NewScalarType,AmbientDimAtCompileTime,Options> >::type cast() const
+ {
+ return typename internal::cast_return_type<ParametrizedLine,
+ ParametrizedLine<NewScalarType,AmbientDimAtCompileTime,Options> >::type(*this);
+ }
+
+ /** Copy constructor with scalar type conversion */
+ template<typename OtherScalarType,int OtherOptions>
+ inline explicit ParametrizedLine(const ParametrizedLine<OtherScalarType,AmbientDimAtCompileTime,OtherOptions>& other)
+ {
+ m_origin = other.origin().template cast<Scalar>();
+ m_direction = other.direction().template cast<Scalar>();
+ }
+
+ /** \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<Scalar>::Real prec = NumTraits<Scalar>::dummy_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 <typename _Scalar, int _AmbientDim, int _Options>
+template <int OtherOptions>
+inline ParametrizedLine<_Scalar, _AmbientDim,_Options>::ParametrizedLine(const Hyperplane<_Scalar, _AmbientDim,OtherOptions>& hyperplane)
+{
+ EIGEN_STATIC_ASSERT_VECTOR_SPECIFIC_SIZE(VectorType, 2)
+ direction() = hyperplane.normal().unitOrthogonal();
+ origin() = -hyperplane.normal()*hyperplane.offset();
+}
+
+/** \returns the point at \a t along this line
+ */
+template <typename _Scalar, int _AmbientDim, int _Options>
+inline typename ParametrizedLine<_Scalar, _AmbientDim,_Options>::VectorType
+ParametrizedLine<_Scalar, _AmbientDim,_Options>::pointAt( _Scalar t ) const
+{
+ return origin() + (direction()*t);
+}
+
+/** \returns the parameter value of the intersection between \c *this and the given \a hyperplane
+ */
+template <typename _Scalar, int _AmbientDim, int _Options>
+template <int OtherOptions>
+inline _Scalar ParametrizedLine<_Scalar, _AmbientDim,_Options>::intersectionParameter(const Hyperplane<_Scalar, _AmbientDim, OtherOptions>& hyperplane) const
+{
+ return -(hyperplane.offset()+hyperplane.normal().dot(origin()))
+ / hyperplane.normal().dot(direction());
+}
+
+
+/** \deprecated use intersectionParameter()
+ * \returns the parameter value of the intersection between \c *this and the given \a hyperplane
+ */
+template <typename _Scalar, int _AmbientDim, int _Options>
+template <int OtherOptions>
+inline _Scalar ParametrizedLine<_Scalar, _AmbientDim,_Options>::intersection(const Hyperplane<_Scalar, _AmbientDim, OtherOptions>& hyperplane) const
+{
+ return intersectionParameter(hyperplane);
+}
+
+/** \returns the point of the intersection between \c *this and the given hyperplane
+ */
+template <typename _Scalar, int _AmbientDim, int _Options>
+template <int OtherOptions>
+inline typename ParametrizedLine<_Scalar, _AmbientDim,_Options>::VectorType
+ParametrizedLine<_Scalar, _AmbientDim,_Options>::intersectionPoint(const Hyperplane<_Scalar, _AmbientDim, OtherOptions>& hyperplane) const
+{
+ return pointAt(intersectionParameter(hyperplane));
+}
+
+} // end namespace Eigen
+
+#endif // EIGEN_PARAMETRIZEDLINE_H
diff --git a/Eigen/src/Geometry/Quaternion.h b/Eigen/src/Geometry/Quaternion.h
new file mode 100644
index 000000000..8792e2da2
--- /dev/null
+++ b/Eigen/src/Geometry/Quaternion.h
@@ -0,0 +1,778 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra.
+//
+// Copyright (C) 2008-2010 Gael Guennebaud <gael.guennebaud@inria.fr>
+// Copyright (C) 2009 Mathieu Gautier <mathieu.gautier@cea.fr>
+//
+// This Source Code Form is subject to the terms of the Mozilla
+// Public License v. 2.0. If a copy of the MPL was not distributed
+// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+#ifndef EIGEN_QUATERNION_H
+#define EIGEN_QUATERNION_H
+namespace Eigen {
+
+
+/***************************************************************************
+* Definition of QuaternionBase<Derived>
+* The implementation is at the end of the file
+***************************************************************************/
+
+namespace internal {
+template<typename Other,
+ int OtherRows=Other::RowsAtCompileTime,
+ int OtherCols=Other::ColsAtCompileTime>
+struct quaternionbase_assign_impl;
+}
+
+/** \geometry_module \ingroup Geometry_Module
+ * \class QuaternionBase
+ * \brief Base class for quaternion expressions
+ * \tparam Derived derived type (CRTP)
+ * \sa class Quaternion
+ */
+template<class Derived>
+class QuaternionBase : public RotationBase<Derived, 3>
+{
+ typedef RotationBase<Derived, 3> Base;
+public:
+ using Base::operator*;
+ using Base::derived;
+
+ typedef typename internal::traits<Derived>::Scalar Scalar;
+ typedef typename NumTraits<Scalar>::Real RealScalar;
+ typedef typename internal::traits<Derived>::Coefficients Coefficients;
+ enum {
+ Flags = Eigen::internal::traits<Derived>::Flags
+ };
+
+ // typedef typename Matrix<Scalar,4,1> Coefficients;
+ /** the type of a 3D vector */
+ typedef Matrix<Scalar,3,1> Vector3;
+ /** the equivalent rotation matrix type */
+ typedef Matrix<Scalar,3,3> Matrix3;
+ /** the equivalent angle-axis type */
+ typedef AngleAxis<Scalar> AngleAxisType;
+
+
+
+ /** \returns the \c x coefficient */
+ inline Scalar x() const { return this->derived().coeffs().coeff(0); }
+ /** \returns the \c y coefficient */
+ inline Scalar y() const { return this->derived().coeffs().coeff(1); }
+ /** \returns the \c z coefficient */
+ inline Scalar z() const { return this->derived().coeffs().coeff(2); }
+ /** \returns the \c w coefficient */
+ inline Scalar w() const { return this->derived().coeffs().coeff(3); }
+
+ /** \returns a reference to the \c x coefficient */
+ inline Scalar& x() { return this->derived().coeffs().coeffRef(0); }
+ /** \returns a reference to the \c y coefficient */
+ inline Scalar& y() { return this->derived().coeffs().coeffRef(1); }
+ /** \returns a reference to the \c z coefficient */
+ inline Scalar& z() { return this->derived().coeffs().coeffRef(2); }
+ /** \returns a reference to the \c w coefficient */
+ inline Scalar& w() { return this->derived().coeffs().coeffRef(3); }
+
+ /** \returns a read-only vector expression of the imaginary part (x,y,z) */
+ inline const VectorBlock<const Coefficients,3> vec() const { return coeffs().template head<3>(); }
+
+ /** \returns a vector expression of the imaginary part (x,y,z) */
+ inline VectorBlock<Coefficients,3> vec() { return coeffs().template head<3>(); }
+
+ /** \returns a read-only vector expression of the coefficients (x,y,z,w) */
+ inline const typename internal::traits<Derived>::Coefficients& coeffs() const { return derived().coeffs(); }
+
+ /** \returns a vector expression of the coefficients (x,y,z,w) */
+ inline typename internal::traits<Derived>::Coefficients& coeffs() { return derived().coeffs(); }
+
+ EIGEN_STRONG_INLINE QuaternionBase<Derived>& operator=(const QuaternionBase<Derived>& other);
+ template<class OtherDerived> EIGEN_STRONG_INLINE Derived& operator=(const QuaternionBase<OtherDerived>& other);
+
+// disabled this copy operator as it is giving very strange compilation errors when compiling
+// test_stdvector with GCC 4.4.2. This looks like a GCC bug though, so feel free to re-enable it if it's
+// useful; however notice that we already have the templated operator= above and e.g. in MatrixBase
+// we didn't have to add, in addition to templated operator=, such a non-templated copy operator.
+// Derived& operator=(const QuaternionBase& other)
+// { return operator=<Derived>(other); }
+
+ Derived& operator=(const AngleAxisType& aa);
+ template<class OtherDerived> Derived& operator=(const MatrixBase<OtherDerived>& m);
+
+ /** \returns a quaternion representing an identity rotation
+ * \sa MatrixBase::Identity()
+ */
+ static inline Quaternion<Scalar> Identity() { return Quaternion<Scalar>(1, 0, 0, 0); }
+
+ /** \sa QuaternionBase::Identity(), MatrixBase::setIdentity()
+ */
+ inline QuaternionBase& setIdentity() { coeffs() << 0, 0, 0, 1; return *this; }
+
+ /** \returns the squared norm of the quaternion's coefficients
+ * \sa QuaternionBase::norm(), MatrixBase::squaredNorm()
+ */
+ inline Scalar squaredNorm() const { return coeffs().squaredNorm(); }
+
+ /** \returns the norm of the quaternion's coefficients
+ * \sa QuaternionBase::squaredNorm(), MatrixBase::norm()
+ */
+ inline Scalar norm() const { return coeffs().norm(); }
+
+ /** Normalizes the quaternion \c *this
+ * \sa normalized(), MatrixBase::normalize() */
+ inline void normalize() { coeffs().normalize(); }
+ /** \returns a normalized copy of \c *this
+ * \sa normalize(), MatrixBase::normalized() */
+ inline Quaternion<Scalar> normalized() const { return Quaternion<Scalar>(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()
+ */
+ template<class OtherDerived> inline Scalar dot(const QuaternionBase<OtherDerived>& other) const { return coeffs().dot(other.coeffs()); }
+
+ template<class OtherDerived> Scalar angularDistance(const QuaternionBase<OtherDerived>& other) const;
+
+ /** \returns an equivalent 3x3 rotation matrix */
+ Matrix3 toRotationMatrix() const;
+
+ /** \returns the quaternion which transform \a a into \a b through a rotation */
+ template<typename Derived1, typename Derived2>
+ Derived& setFromTwoVectors(const MatrixBase<Derived1>& a, const MatrixBase<Derived2>& b);
+
+ template<class OtherDerived> EIGEN_STRONG_INLINE Quaternion<Scalar> operator* (const QuaternionBase<OtherDerived>& q) const;
+ template<class OtherDerived> EIGEN_STRONG_INLINE Derived& operator*= (const QuaternionBase<OtherDerived>& q);
+
+ /** \returns the quaternion describing the inverse rotation */
+ Quaternion<Scalar> inverse() const;
+
+ /** \returns the conjugated quaternion */
+ Quaternion<Scalar> conjugate() const;
+
+ /** \returns an interpolation for a constant motion between \a other and \c *this
+ * \a t in [0;1]
+ * see http://en.wikipedia.org/wiki/Slerp
+ */
+ template<class OtherDerived> Quaternion<Scalar> slerp(Scalar t, const QuaternionBase<OtherDerived>& other) const;
+
+ /** \returns \c true if \c *this is approximately equal to \a other, within the precision
+ * determined by \a prec.
+ *
+ * \sa MatrixBase::isApprox() */
+ template<class OtherDerived>
+ bool isApprox(const QuaternionBase<OtherDerived>& other, RealScalar prec = NumTraits<Scalar>::dummy_precision()) const
+ { return coeffs().isApprox(other.coeffs(), prec); }
+
+ /** return the result vector of \a v through the rotation*/
+ EIGEN_STRONG_INLINE Vector3 _transformVector(Vector3 v) 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<typename NewScalarType>
+ inline typename internal::cast_return_type<Derived,Quaternion<NewScalarType> >::type cast() const
+ {
+ return typename internal::cast_return_type<Derived,Quaternion<NewScalarType> >::type(derived());
+ }
+
+#ifdef EIGEN_QUATERNIONBASE_PLUGIN
+# include EIGEN_QUATERNIONBASE_PLUGIN
+#endif
+};
+
+/***************************************************************************
+* Definition/implementation of Quaternion<Scalar>
+***************************************************************************/
+
+/** \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
+ */
+
+namespace internal {
+template<typename _Scalar,int _Options>
+struct traits<Quaternion<_Scalar,_Options> >
+{
+ typedef Quaternion<_Scalar,_Options> PlainObject;
+ typedef _Scalar Scalar;
+ typedef Matrix<_Scalar,4,1,_Options> Coefficients;
+ enum{
+ IsAligned = internal::traits<Coefficients>::Flags & AlignedBit,
+ Flags = IsAligned ? (AlignedBit | LvalueBit) : LvalueBit
+ };
+};
+}
+
+template<typename _Scalar, int _Options>
+class Quaternion : public QuaternionBase<Quaternion<_Scalar,_Options> >
+{
+ typedef QuaternionBase<Quaternion<_Scalar,_Options> > Base;
+ enum { IsAligned = internal::traits<Quaternion>::IsAligned };
+
+public:
+ typedef _Scalar Scalar;
+
+ EIGEN_INHERIT_ASSIGNMENT_EQUAL_OPERATOR(Quaternion)
+ using Base::operator*=;
+
+ typedef typename internal::traits<Quaternion>::Coefficients Coefficients;
+ typedef typename Base::AngleAxisType AngleAxisType;
+
+ /** 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){}
+
+ /** Constructs and initialize a quaternion from the array data */
+ inline Quaternion(const Scalar* data) : m_coeffs(data) {}
+
+ /** Copy constructor */
+ template<class Derived> EIGEN_STRONG_INLINE Quaternion(const QuaternionBase<Derived>& other) { this->Base::operator=(other); }
+
+ /** 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.
+ */
+ template<typename Derived>
+ explicit inline Quaternion(const MatrixBase<Derived>& other) { *this = other; }
+
+ /** Explicit copy constructor with scalar conversion */
+ template<typename OtherScalar, int OtherOptions>
+ explicit inline Quaternion(const Quaternion<OtherScalar, OtherOptions>& other)
+ { m_coeffs = other.coeffs().template cast<Scalar>(); }
+
+ template<typename Derived1, typename Derived2>
+ static Quaternion FromTwoVectors(const MatrixBase<Derived1>& a, const MatrixBase<Derived2>& b);
+
+ inline Coefficients& coeffs() { return m_coeffs;}
+ inline const Coefficients& coeffs() const { return m_coeffs;}
+
+ EIGEN_MAKE_ALIGNED_OPERATOR_NEW_IF(IsAligned)
+
+protected:
+ Coefficients m_coeffs;
+
+#ifndef EIGEN_PARSED_BY_DOXYGEN
+ static EIGEN_STRONG_INLINE void _check_template_params()
+ {
+ EIGEN_STATIC_ASSERT( (_Options & DontAlign) == _Options,
+ INVALID_MATRIX_TEMPLATE_PARAMETERS)
+ }
+#endif
+};
+
+/** \ingroup Geometry_Module
+ * single precision quaternion type */
+typedef Quaternion<float> Quaternionf;
+/** \ingroup Geometry_Module
+ * double precision quaternion type */
+typedef Quaternion<double> Quaterniond;
+
+/***************************************************************************
+* Specialization of Map<Quaternion<Scalar>>
+***************************************************************************/
+
+namespace internal {
+ template<typename _Scalar, int _Options>
+ struct traits<Map<Quaternion<_Scalar>, _Options> >:
+ traits<Quaternion<_Scalar, _Options> >
+ {
+ typedef _Scalar Scalar;
+ typedef Map<Matrix<_Scalar,4,1>, _Options> Coefficients;
+
+ typedef traits<Quaternion<_Scalar, _Options> > TraitsBase;
+ enum {
+ IsAligned = TraitsBase::IsAligned,
+
+ Flags = TraitsBase::Flags
+ };
+ };
+}
+
+namespace internal {
+ template<typename _Scalar, int _Options>
+ struct traits<Map<const Quaternion<_Scalar>, _Options> >:
+ traits<Quaternion<_Scalar> >
+ {
+ typedef _Scalar Scalar;
+ typedef Map<const Matrix<_Scalar,4,1>, _Options> Coefficients;
+
+ typedef traits<Quaternion<_Scalar, _Options> > TraitsBase;
+ enum {
+ IsAligned = TraitsBase::IsAligned,
+ Flags = TraitsBase::Flags & ~LvalueBit
+ };
+ };
+}
+
+/** \brief Quaternion expression mapping a constant memory buffer
+ *
+ * \param _Scalar the type of the Quaternion coefficients
+ * \param _Options see class Map
+ *
+ * This is a specialization of class Map for Quaternion. This class allows to view
+ * a 4 scalar memory buffer as an Eigen's Quaternion object.
+ *
+ * \sa class Map, class Quaternion, class QuaternionBase
+ */
+template<typename _Scalar, int _Options>
+class Map<const Quaternion<_Scalar>, _Options >
+ : public QuaternionBase<Map<const Quaternion<_Scalar>, _Options> >
+{
+ typedef QuaternionBase<Map<const Quaternion<_Scalar>, _Options> > Base;
+
+ public:
+ typedef _Scalar Scalar;
+ typedef typename internal::traits<Map>::Coefficients Coefficients;
+ EIGEN_INHERIT_ASSIGNMENT_EQUAL_OPERATOR(Map)
+ using Base::operator*=;
+
+ /** Constructs a Mapped Quaternion object from the pointer \a coeffs
+ *
+ * The pointer \a coeffs must reference the four coeffecients of Quaternion in the following order:
+ * \code *coeffs == {x, y, z, w} \endcode
+ *
+ * If the template parameter _Options is set to #Aligned, then the pointer coeffs must be aligned. */
+ EIGEN_STRONG_INLINE Map(const Scalar* coeffs) : m_coeffs(coeffs) {}
+
+ inline const Coefficients& coeffs() const { return m_coeffs;}
+
+ protected:
+ const Coefficients m_coeffs;
+};
+
+/** \brief Expression of a quaternion from a memory buffer
+ *
+ * \param _Scalar the type of the Quaternion coefficients
+ * \param _Options see class Map
+ *
+ * This is a specialization of class Map for Quaternion. This class allows to view
+ * a 4 scalar memory buffer as an Eigen's Quaternion object.
+ *
+ * \sa class Map, class Quaternion, class QuaternionBase
+ */
+template<typename _Scalar, int _Options>
+class Map<Quaternion<_Scalar>, _Options >
+ : public QuaternionBase<Map<Quaternion<_Scalar>, _Options> >
+{
+ typedef QuaternionBase<Map<Quaternion<_Scalar>, _Options> > Base;
+
+ public:
+ typedef _Scalar Scalar;
+ typedef typename internal::traits<Map>::Coefficients Coefficients;
+ EIGEN_INHERIT_ASSIGNMENT_EQUAL_OPERATOR(Map)
+ using Base::operator*=;
+
+ /** Constructs a Mapped Quaternion object from the pointer \a coeffs
+ *
+ * The pointer \a coeffs must reference the four coeffecients of Quaternion in the following order:
+ * \code *coeffs == {x, y, z, w} \endcode
+ *
+ * If the template parameter _Options is set to #Aligned, then the pointer coeffs must be aligned. */
+ EIGEN_STRONG_INLINE Map(Scalar* coeffs) : m_coeffs(coeffs) {}
+
+ inline Coefficients& coeffs() { return m_coeffs; }
+ inline const Coefficients& coeffs() const { return m_coeffs; }
+
+ protected:
+ Coefficients m_coeffs;
+};
+
+/** \ingroup Geometry_Module
+ * Map an unaligned array of single precision scalar as a quaternion */
+typedef Map<Quaternion<float>, 0> QuaternionMapf;
+/** \ingroup Geometry_Module
+ * Map an unaligned array of double precision scalar as a quaternion */
+typedef Map<Quaternion<double>, 0> QuaternionMapd;
+/** \ingroup Geometry_Module
+ * Map a 16-bits aligned array of double precision scalars as a quaternion */
+typedef Map<Quaternion<float>, Aligned> QuaternionMapAlignedf;
+/** \ingroup Geometry_Module
+ * Map a 16-bits aligned array of double precision scalars as a quaternion */
+typedef Map<Quaternion<double>, Aligned> QuaternionMapAlignedd;
+
+/***************************************************************************
+* Implementation of QuaternionBase methods
+***************************************************************************/
+
+// Generic Quaternion * Quaternion product
+// This product can be specialized for a given architecture via the Arch template argument.
+namespace internal {
+template<int Arch, class Derived1, class Derived2, typename Scalar, int _Options> struct quat_product
+{
+ static EIGEN_STRONG_INLINE Quaternion<Scalar> run(const QuaternionBase<Derived1>& a, const QuaternionBase<Derived2>& b){
+ return Quaternion<Scalar>
+ (
+ 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 <class Derived>
+template <class OtherDerived>
+EIGEN_STRONG_INLINE Quaternion<typename internal::traits<Derived>::Scalar>
+QuaternionBase<Derived>::operator* (const QuaternionBase<OtherDerived>& other) const
+{
+ EIGEN_STATIC_ASSERT((internal::is_same<typename Derived::Scalar, typename OtherDerived::Scalar>::value),
+ YOU_MIXED_DIFFERENT_NUMERIC_TYPES__YOU_NEED_TO_USE_THE_CAST_METHOD_OF_MATRIXBASE_TO_CAST_NUMERIC_TYPES_EXPLICITLY)
+ return internal::quat_product<Architecture::Target, Derived, OtherDerived,
+ typename internal::traits<Derived>::Scalar,
+ internal::traits<Derived>::IsAligned && internal::traits<OtherDerived>::IsAligned>::run(*this, other);
+}
+
+/** \sa operator*(Quaternion) */
+template <class Derived>
+template <class OtherDerived>
+EIGEN_STRONG_INLINE Derived& QuaternionBase<Derived>::operator*= (const QuaternionBase<OtherDerived>& other)
+{
+ derived() = derived() * other.derived();
+ return derived();
+}
+
+/** 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:
+ * - Quaternion2: 30n
+ * - Via a Matrix3: 24 + 15n
+ */
+template <class Derived>
+EIGEN_STRONG_INLINE typename QuaternionBase<Derived>::Vector3
+QuaternionBase<Derived>::_transformVector(Vector3 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 = this->vec().cross(v);
+ uv += uv;
+ return v + this->w() * uv + this->vec().cross(uv);
+}
+
+template<class Derived>
+EIGEN_STRONG_INLINE QuaternionBase<Derived>& QuaternionBase<Derived>::operator=(const QuaternionBase<Derived>& other)
+{
+ coeffs() = other.coeffs();
+ return derived();
+}
+
+template<class Derived>
+template<class OtherDerived>
+EIGEN_STRONG_INLINE Derived& QuaternionBase<Derived>::operator=(const QuaternionBase<OtherDerived>& other)
+{
+ coeffs() = other.coeffs();
+ return derived();
+}
+
+/** Set \c *this from an angle-axis \a aa and returns a reference to \c *this
+ */
+template<class Derived>
+EIGEN_STRONG_INLINE Derived& QuaternionBase<Derived>::operator=(const AngleAxisType& aa)
+{
+ Scalar ha = Scalar(0.5)*aa.angle(); // Scalar(0.5) to suppress precision loss warnings
+ this->w() = internal::cos(ha);
+ this->vec() = internal::sin(ha) * aa.axis();
+ return derived();
+}
+
+/** 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<class Derived>
+template<class MatrixDerived>
+inline Derived& QuaternionBase<Derived>::operator=(const MatrixBase<MatrixDerived>& xpr)
+{
+ EIGEN_STATIC_ASSERT((internal::is_same<typename Derived::Scalar, typename MatrixDerived::Scalar>::value),
+ YOU_MIXED_DIFFERENT_NUMERIC_TYPES__YOU_NEED_TO_USE_THE_CAST_METHOD_OF_MATRIXBASE_TO_CAST_NUMERIC_TYPES_EXPLICITLY)
+ internal::quaternionbase_assign_impl<MatrixDerived>::run(*this, xpr.derived());
+ return derived();
+}
+
+/** Convert the quaternion to a 3x3 rotation matrix. The quaternion is required to
+ * be normalized, otherwise the result is undefined.
+ */
+template<class Derived>
+inline typename QuaternionBase<Derived>::Matrix3
+QuaternionBase<Derived>::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 \c *this to be a quaternion representing a rotation between
+ * the two arbitrary vectors \a a and \a b. In other words, the built
+ * rotation represent a rotation sending the line of direction \a a
+ * to the line of direction \a b, both lines passing through the origin.
+ *
+ * \returns a reference to \c *this.
+ *
+ * Note that the two input vectors do \b not have to be normalized, and
+ * do not need to have the same norm.
+ */
+template<class Derived>
+template<typename Derived1, typename Derived2>
+inline Derived& QuaternionBase<Derived>::setFromTwoVectors(const MatrixBase<Derived1>& a, const MatrixBase<Derived2>& b)
+{
+ using std::max;
+ Vector3 v0 = a.normalized();
+ Vector3 v1 = b.normalized();
+ Scalar c = v1.dot(v0);
+
+ // if dot == -1, vectors are nearly opposites
+ // => accuraletly compute the rotation axis by computing the
+ // intersection of the two planes. This is done by solving:
+ // x^T v0 = 0
+ // x^T v1 = 0
+ // under the constraint:
+ // ||x|| = 1
+ // which yields a singular value problem
+ if (c < Scalar(-1)+NumTraits<Scalar>::dummy_precision())
+ {
+ c = max<Scalar>(c,-1);
+ Matrix<Scalar,2,3> m; m << v0.transpose(), v1.transpose();
+ JacobiSVD<Matrix<Scalar,2,3> > svd(m, ComputeFullV);
+ Vector3 axis = svd.matrixV().col(2);
+
+ Scalar w2 = (Scalar(1)+c)*Scalar(0.5);
+ this->w() = internal::sqrt(w2);
+ this->vec() = axis * internal::sqrt(Scalar(1) - w2);
+ return derived();
+ }
+ Vector3 axis = v0.cross(v1);
+ Scalar s = internal::sqrt((Scalar(1)+c)*Scalar(2));
+ Scalar invs = Scalar(1)/s;
+ this->vec() = axis * invs;
+ this->w() = s * Scalar(0.5);
+
+ return derived();
+}
+
+
+/** Returns a quaternion representing a rotation between
+ * the two arbitrary vectors \a a and \a b. In other words, the built
+ * rotation represent a rotation sending the line of direction \a a
+ * to the line of direction \a b, both lines passing through the origin.
+ *
+ * \returns resulting quaternion
+ *
+ * Note that the two input vectors do \b not have to be normalized, and
+ * do not need to have the same norm.
+ */
+template<typename Scalar, int Options>
+template<typename Derived1, typename Derived2>
+Quaternion<Scalar,Options> Quaternion<Scalar,Options>::FromTwoVectors(const MatrixBase<Derived1>& a, const MatrixBase<Derived2>& b)
+{
+ Quaternion quat;
+ quat.setFromTwoVectors(a, b);
+ return quat;
+}
+
+
+/** \returns the multiplicative inverse of \c *this
+ * Note that in most cases, i.e., if you simply want the opposite rotation,
+ * and/or the quaternion is normalized, then it is enough to use the conjugate.
+ *
+ * \sa QuaternionBase::conjugate()
+ */
+template <class Derived>
+inline Quaternion<typename internal::traits<Derived>::Scalar> QuaternionBase<Derived>::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<Scalar>(conjugate().coeffs() / n2);
+ else
+ {
+ // return an invalid result to flag the error
+ return Quaternion<Scalar>(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 Quaternion2::inverse()
+ */
+template <class Derived>
+inline Quaternion<typename internal::traits<Derived>::Scalar>
+QuaternionBase<Derived>::conjugate() const
+{
+ return Quaternion<Scalar>(this->w(),-this->x(),-this->y(),-this->z());
+}
+
+/** \returns the angle (in radian) between two rotations
+ * \sa dot()
+ */
+template <class Derived>
+template <class OtherDerived>
+inline typename internal::traits<Derived>::Scalar
+QuaternionBase<Derived>::angularDistance(const QuaternionBase<OtherDerived>& other) const
+{
+ using std::acos;
+ double d = internal::abs(this->dot(other));
+ if (d>=1.0)
+ return Scalar(0);
+ return static_cast<Scalar>(2 * acos(d));
+}
+
+/** \returns the spherical linear interpolation between the two quaternions
+ * \c *this and \a other at the parameter \a t
+ */
+template <class Derived>
+template <class OtherDerived>
+Quaternion<typename internal::traits<Derived>::Scalar>
+QuaternionBase<Derived>::slerp(Scalar t, const QuaternionBase<OtherDerived>& other) const
+{
+ using std::acos;
+ static const Scalar one = Scalar(1) - NumTraits<Scalar>::epsilon();
+ Scalar d = this->dot(other);
+ Scalar absD = internal::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 = acos(absD);
+ Scalar sinTheta = internal::sin(theta);
+
+ scale0 = internal::sin( ( Scalar(1) - t ) * theta) / sinTheta;
+ scale1 = internal::sin( ( t * theta) ) / sinTheta;
+ }
+ if(d<0) scale1 = -scale1;
+
+ return Quaternion<Scalar>(scale0 * coeffs() + scale1 * other.coeffs());
+}
+
+namespace internal {
+
+// set from a rotation matrix
+template<typename Other>
+struct quaternionbase_assign_impl<Other,3,3>
+{
+ typedef typename Other::Scalar Scalar;
+ typedef DenseIndex Index;
+ template<class Derived> static inline void run(QuaternionBase<Derived>& 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 > Scalar(0))
+ {
+ t = 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
+ {
+ DenseIndex i = 0;
+ if (mat.coeff(1,1) > mat.coeff(0,0))
+ i = 1;
+ if (mat.coeff(2,2) > mat.coeff(i,i))
+ i = 2;
+ DenseIndex j = (i+1)%3;
+ DenseIndex k = (j+1)%3;
+
+ t = 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<typename Other>
+struct quaternionbase_assign_impl<Other,4,1>
+{
+ typedef typename Other::Scalar Scalar;
+ template<class Derived> static inline void run(QuaternionBase<Derived>& q, const Other& vec)
+ {
+ q.coeffs() = vec;
+ }
+};
+
+} // end namespace internal
+
+} // end namespace Eigen
+
+#endif // EIGEN_QUATERNION_H
diff --git a/Eigen/src/Geometry/Rotation2D.h b/Eigen/src/Geometry/Rotation2D.h
new file mode 100644
index 000000000..868e2ef31
--- /dev/null
+++ b/Eigen/src/Geometry/Rotation2D.h
@@ -0,0 +1,154 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra.
+//
+// Copyright (C) 2008 Gael Guennebaud <gael.guennebaud@inria.fr>
+//
+// This Source Code Form is subject to the terms of the Mozilla
+// Public License v. 2.0. If a copy of the MPL was not distributed
+// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+#ifndef EIGEN_ROTATION2D_H
+#define EIGEN_ROTATION2D_H
+
+namespace Eigen {
+
+/** \geometry_module \ingroup Geometry_Module
+ *
+ * \class Rotation2D
+ *
+ * \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
+ */
+
+namespace internal {
+
+template<typename _Scalar> struct traits<Rotation2D<_Scalar> >
+{
+ typedef _Scalar Scalar;
+};
+} // end namespace internal
+
+template<typename _Scalar>
+class Rotation2D : public RotationBase<Rotation2D<_Scalar>,2>
+{
+ typedef RotationBase<Rotation2D<_Scalar>,2> Base;
+
+public:
+
+ using Base::operator*;
+
+ enum { Dim = 2 };
+ /** the scalar type of the coefficients */
+ typedef _Scalar Scalar;
+ typedef Matrix<Scalar,2,1> Vector2;
+ typedef Matrix<Scalar,2,2> 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)
+ { m_angle += other.m_angle; return *this; }
+
+ /** Applies the rotation to a 2D vector */
+ Vector2 operator* (const Vector2& vec) const
+ { return toRotationMatrix() * vec; }
+
+ template<typename Derived>
+ Rotation2D& fromRotationMatrix(const MatrixBase<Derived>& 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<typename NewScalarType>
+ inline typename internal::cast_return_type<Rotation2D,Rotation2D<NewScalarType> >::type cast() const
+ { return typename internal::cast_return_type<Rotation2D,Rotation2D<NewScalarType> >::type(*this); }
+
+ /** Copy constructor with scalar type conversion */
+ template<typename OtherScalarType>
+ inline explicit Rotation2D(const Rotation2D<OtherScalarType>& other)
+ {
+ m_angle = Scalar(other.angle());
+ }
+
+ static inline Rotation2D Identity() { return Rotation2D(0); }
+
+ /** \returns \c true if \c *this is approximately equal to \a other, within the precision
+ * determined by \a prec.
+ *
+ * \sa MatrixBase::isApprox() */
+ bool isApprox(const Rotation2D& other, typename NumTraits<Scalar>::Real prec = NumTraits<Scalar>::dummy_precision()) const
+ { return internal::isApprox(m_angle,other.m_angle, prec); }
+};
+
+/** \ingroup Geometry_Module
+ * single precision 2D rotation type */
+typedef Rotation2D<float> Rotation2Df;
+/** \ingroup Geometry_Module
+ * double precision 2D rotation type */
+typedef Rotation2D<double> 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<typename Scalar>
+template<typename Derived>
+Rotation2D<Scalar>& Rotation2D<Scalar>::fromRotationMatrix(const MatrixBase<Derived>& mat)
+{
+ EIGEN_STATIC_ASSERT(Derived::RowsAtCompileTime==2 && Derived::ColsAtCompileTime==2,YOU_MADE_A_PROGRAMMING_MISTAKE)
+ m_angle = internal::atan2(mat.coeff(1,0), mat.coeff(0,0));
+ return *this;
+}
+
+/** Constructs and \returns an equivalent 2x2 rotation matrix.
+ */
+template<typename Scalar>
+typename Rotation2D<Scalar>::Matrix2
+Rotation2D<Scalar>::toRotationMatrix(void) const
+{
+ Scalar sinA = internal::sin(m_angle);
+ Scalar cosA = internal::cos(m_angle);
+ return (Matrix2() << cosA, -sinA, sinA, cosA).finished();
+}
+
+} // end namespace Eigen
+
+#endif // EIGEN_ROTATION2D_H
diff --git a/Eigen/src/Geometry/RotationBase.h b/Eigen/src/Geometry/RotationBase.h
new file mode 100644
index 000000000..b88661de6
--- /dev/null
+++ b/Eigen/src/Geometry/RotationBase.h
@@ -0,0 +1,206 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra.
+//
+// Copyright (C) 2008 Gael Guennebaud <gael.guennebaud@inria.fr>
+//
+// This Source Code Form is subject to the terms of the Mozilla
+// Public License v. 2.0. If a copy of the MPL was not distributed
+// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+#ifndef EIGEN_ROTATIONBASE_H
+#define EIGEN_ROTATIONBASE_H
+
+namespace Eigen {
+
+// forward declaration
+namespace internal {
+template<typename RotationDerived, typename MatrixType, bool IsVector=MatrixType::IsVectorAtCompileTime>
+struct rotation_base_generic_product_selector;
+}
+
+/** \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<typename Derived, int _Dim>
+class RotationBase
+{
+ public:
+ enum { Dim = _Dim };
+ /** the scalar type of the coefficients */
+ typedef typename internal::traits<Derived>::Scalar Scalar;
+
+ /** corresponding linear transformation matrix type */
+ typedef Matrix<Scalar,Dim,Dim> RotationMatrixType;
+ typedef Matrix<Scalar,Dim,1> VectorType;
+
+ public:
+ inline const Derived& derived() const { return *static_cast<const Derived*>(this); }
+ inline Derived& derived() { return *static_cast<Derived*>(this); }
+
+ /** \returns an equivalent rotation matrix */
+ inline RotationMatrixType toRotationMatrix() const { return derived().toRotationMatrix(); }
+
+ /** \returns an equivalent rotation matrix
+ * This function is added to be conform with the Transform class' naming scheme.
+ */
+ inline RotationMatrixType matrix() 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<Scalar,Dim,Isometry> operator*(const Translation<Scalar,Dim>& t) const
+ { return Transform<Scalar,Dim,Isometry>(*this) * t; }
+
+ /** \returns the concatenation of the rotation \c *this with a uniform scaling \a s */
+ inline RotationMatrixType operator*(const UniformScaling<Scalar>& s) const
+ { return toRotationMatrix() * s.factor(); }
+
+ /** \returns the concatenation of the rotation \c *this with a generic expression \a e
+ * \a e can be:
+ * - a DimxDim linear transformation matrix
+ * - a DimxDim diagonal matrix (axis aligned scaling)
+ * - a vector of size Dim
+ */
+ template<typename OtherDerived>
+ EIGEN_STRONG_INLINE typename internal::rotation_base_generic_product_selector<Derived,OtherDerived,OtherDerived::IsVectorAtCompileTime>::ReturnType
+ operator*(const EigenBase<OtherDerived>& e) const
+ { return internal::rotation_base_generic_product_selector<Derived,OtherDerived>::run(derived(), e.derived()); }
+
+ /** \returns the concatenation of a linear transformation \a l with the rotation \a r */
+ template<typename OtherDerived> friend
+ inline RotationMatrixType operator*(const EigenBase<OtherDerived>& l, const Derived& r)
+ { return l.derived() * r.toRotationMatrix(); }
+
+ /** \returns the concatenation of a scaling \a l with the rotation \a r */
+ friend inline Transform<Scalar,Dim,Affine> operator*(const DiagonalMatrix<Scalar,Dim>& l, const Derived& r)
+ {
+ Transform<Scalar,Dim,Affine> res(r);
+ res.linear().applyOnTheLeft(l);
+ return res;
+ }
+
+ /** \returns the concatenation of the rotation \c *this with a transformation \a t */
+ template<int Mode, int Options>
+ inline Transform<Scalar,Dim,Mode> operator*(const Transform<Scalar,Dim,Mode,Options>& t) const
+ { return toRotationMatrix() * t; }
+
+ template<typename OtherVectorType>
+ inline VectorType _transformVector(const OtherVectorType& v) const
+ { return toRotationMatrix() * v; }
+};
+
+namespace internal {
+
+// implementation of the generic product rotation * matrix
+template<typename RotationDerived, typename MatrixType>
+struct rotation_base_generic_product_selector<RotationDerived,MatrixType,false>
+{
+ enum { Dim = RotationDerived::Dim };
+ typedef Matrix<typename RotationDerived::Scalar,Dim,Dim> ReturnType;
+ static inline ReturnType run(const RotationDerived& r, const MatrixType& m)
+ { return r.toRotationMatrix() * m; }
+};
+
+template<typename RotationDerived, typename Scalar, int Dim, int MaxDim>
+struct rotation_base_generic_product_selector< RotationDerived, DiagonalMatrix<Scalar,Dim,MaxDim>, false >
+{
+ typedef Transform<Scalar,Dim,Affine> ReturnType;
+ static inline ReturnType run(const RotationDerived& r, const DiagonalMatrix<Scalar,Dim,MaxDim>& m)
+ {
+ ReturnType res(r);
+ res.linear() *= m;
+ return res;
+ }
+};
+
+template<typename RotationDerived,typename OtherVectorType>
+struct rotation_base_generic_product_selector<RotationDerived,OtherVectorType,true>
+{
+ enum { Dim = RotationDerived::Dim };
+ typedef Matrix<typename RotationDerived::Scalar,Dim,1> ReturnType;
+ static EIGEN_STRONG_INLINE ReturnType run(const RotationDerived& r, const OtherVectorType& v)
+ {
+ return r._transformVector(v);
+ }
+};
+
+} // end namespace internal
+
+/** \geometry_module
+ *
+ * \brief Constructs a Dim x Dim rotation matrix from the rotation \a r
+ */
+template<typename _Scalar, int _Rows, int _Cols, int _Storage, int _MaxRows, int _MaxCols>
+template<typename OtherDerived>
+Matrix<_Scalar, _Rows, _Cols, _Storage, _MaxRows, _MaxCols>
+::Matrix(const RotationBase<OtherDerived,ColsAtCompileTime>& r)
+{
+ EIGEN_STATIC_ASSERT_MATRIX_SPECIFIC_SIZE(Matrix,int(OtherDerived::Dim),int(OtherDerived::Dim))
+ *this = r.toRotationMatrix();
+}
+
+/** \geometry_module
+ *
+ * \brief Set a Dim x Dim rotation matrix from the rotation \a r
+ */
+template<typename _Scalar, int _Rows, int _Cols, int _Storage, int _MaxRows, int _MaxCols>
+template<typename OtherDerived>
+Matrix<_Scalar, _Rows, _Cols, _Storage, _MaxRows, _MaxCols>&
+Matrix<_Scalar, _Rows, _Cols, _Storage, _MaxRows, _MaxCols>
+::operator=(const RotationBase<OtherDerived,ColsAtCompileTime>& r)
+{
+ EIGEN_STATIC_ASSERT_MATRIX_SPECIFIC_SIZE(Matrix,int(OtherDerived::Dim),int(OtherDerived::Dim))
+ return *this = r.toRotationMatrix();
+}
+
+namespace internal {
+
+/** \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 toRotationMatrix is only used by Transform.
+ *
+ * \sa class Transform, class Rotation2D, class Quaternion, class AngleAxis
+ */
+template<typename Scalar, int Dim>
+static inline Matrix<Scalar,2,2> toRotationMatrix(const Scalar& s)
+{
+ EIGEN_STATIC_ASSERT(Dim==2,YOU_MADE_A_PROGRAMMING_MISTAKE)
+ return Rotation2D<Scalar>(s).toRotationMatrix();
+}
+
+template<typename Scalar, int Dim, typename OtherDerived>
+static inline Matrix<Scalar,Dim,Dim> toRotationMatrix(const RotationBase<OtherDerived,Dim>& r)
+{
+ return r.toRotationMatrix();
+}
+
+template<typename Scalar, int Dim, typename OtherDerived>
+static inline const MatrixBase<OtherDerived>& toRotationMatrix(const MatrixBase<OtherDerived>& mat)
+{
+ EIGEN_STATIC_ASSERT(OtherDerived::RowsAtCompileTime==Dim && OtherDerived::ColsAtCompileTime==Dim,
+ YOU_MADE_A_PROGRAMMING_MISTAKE)
+ return mat;
+}
+
+} // end namespace internal
+
+} // end namespace Eigen
+
+#endif // EIGEN_ROTATIONBASE_H
diff --git a/Eigen/src/Geometry/Scaling.h b/Eigen/src/Geometry/Scaling.h
new file mode 100644
index 000000000..8edcac31c
--- /dev/null
+++ b/Eigen/src/Geometry/Scaling.h
@@ -0,0 +1,166 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra.
+//
+// Copyright (C) 2008 Gael Guennebaud <gael.guennebaud@inria.fr>
+//
+// This Source Code Form is subject to the terms of the Mozilla
+// Public License v. 2.0. If a copy of the MPL was not distributed
+// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+#ifndef EIGEN_SCALING_H
+#define EIGEN_SCALING_H
+
+namespace Eigen {
+
+/** \geometry_module \ingroup Geometry_Module
+ *
+ * \class Scaling
+ *
+ * \brief Represents a generic uniform scaling transformation
+ *
+ * \param _Scalar the scalar type, i.e., the type of the coefficients.
+ *
+ * This class represent a uniform scaling transformation. It is the return
+ * type of Scaling(Scalar), and most of the time this is the only way it
+ * is used. In particular, 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.
+ *
+ * To represent an axis aligned scaling, use the DiagonalMatrix class.
+ *
+ * \sa Scaling(), class DiagonalMatrix, MatrixBase::asDiagonal(), class Translation, class Transform
+ */
+template<typename _Scalar>
+class UniformScaling
+{
+public:
+ /** the scalar type of the coefficients */
+ typedef _Scalar Scalar;
+
+protected:
+
+ Scalar m_factor;
+
+public:
+
+ /** Default constructor without initialization. */
+ UniformScaling() {}
+ /** Constructs and initialize a uniform scaling transformation */
+ explicit inline UniformScaling(const Scalar& s) : m_factor(s) {}
+
+ inline const Scalar& factor() const { return m_factor; }
+ inline Scalar& factor() { return m_factor; }
+
+ /** Concatenates two uniform scaling */
+ inline UniformScaling operator* (const UniformScaling& other) const
+ { return UniformScaling(m_factor * other.factor()); }
+
+ /** Concatenates a uniform scaling and a translation */
+ template<int Dim>
+ inline Transform<Scalar,Dim,Affine> operator* (const Translation<Scalar,Dim>& t) const;
+
+ /** Concatenates a uniform scaling and an affine transformation */
+ template<int Dim, int Mode, int Options>
+ inline Transform<Scalar,Dim,(int(Mode)==int(Isometry)?Affine:Mode)> operator* (const Transform<Scalar,Dim, Mode, Options>& t) const
+ {
+ Transform<Scalar,Dim,(int(Mode)==int(Isometry)?Affine:Mode)> res = t;
+ res.prescale(factor());
+ return res;
+}
+
+ /** Concatenates a uniform scaling and a linear transformation matrix */
+ // TODO returns an expression
+ template<typename Derived>
+ inline typename internal::plain_matrix_type<Derived>::type operator* (const MatrixBase<Derived>& other) const
+ { return other * m_factor; }
+
+ template<typename Derived,int Dim>
+ inline Matrix<Scalar,Dim,Dim> operator*(const RotationBase<Derived,Dim>& r) const
+ { return r.toRotationMatrix() * m_factor; }
+
+ /** \returns the inverse scaling */
+ inline UniformScaling inverse() const
+ { return UniformScaling(Scalar(1)/m_factor); }
+
+ /** \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<typename NewScalarType>
+ inline UniformScaling<NewScalarType> cast() const
+ { return UniformScaling<NewScalarType>(NewScalarType(m_factor)); }
+
+ /** Copy constructor with scalar type conversion */
+ template<typename OtherScalarType>
+ inline explicit UniformScaling(const UniformScaling<OtherScalarType>& other)
+ { m_factor = Scalar(other.factor()); }
+
+ /** \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 UniformScaling& other, typename NumTraits<Scalar>::Real prec = NumTraits<Scalar>::dummy_precision()) const
+ { return internal::isApprox(m_factor, other.factor(), prec); }
+
+};
+
+/** Concatenates a linear transformation matrix and a uniform scaling */
+// NOTE this operator is defiend in MatrixBase and not as a friend function
+// of UniformScaling to fix an internal crash of Intel's ICC
+template<typename Derived> typename MatrixBase<Derived>::ScalarMultipleReturnType
+MatrixBase<Derived>::operator*(const UniformScaling<Scalar>& s) const
+{ return derived() * s.factor(); }
+
+/** Constructs a uniform scaling from scale factor \a s */
+static inline UniformScaling<float> Scaling(float s) { return UniformScaling<float>(s); }
+/** Constructs a uniform scaling from scale factor \a s */
+static inline UniformScaling<double> Scaling(double s) { return UniformScaling<double>(s); }
+/** Constructs a uniform scaling from scale factor \a s */
+template<typename RealScalar>
+static inline UniformScaling<std::complex<RealScalar> > Scaling(const std::complex<RealScalar>& s)
+{ return UniformScaling<std::complex<RealScalar> >(s); }
+
+/** Constructs a 2D axis aligned scaling */
+template<typename Scalar>
+static inline DiagonalMatrix<Scalar,2> Scaling(Scalar sx, Scalar sy)
+{ return DiagonalMatrix<Scalar,2>(sx, sy); }
+/** Constructs a 3D axis aligned scaling */
+template<typename Scalar>
+static inline DiagonalMatrix<Scalar,3> Scaling(Scalar sx, Scalar sy, Scalar sz)
+{ return DiagonalMatrix<Scalar,3>(sx, sy, sz); }
+
+/** Constructs an axis aligned scaling expression from vector expression \a coeffs
+ * This is an alias for coeffs.asDiagonal()
+ */
+template<typename Derived>
+static inline const DiagonalWrapper<const Derived> Scaling(const MatrixBase<Derived>& coeffs)
+{ return coeffs.asDiagonal(); }
+
+/** \addtogroup Geometry_Module */
+//@{
+/** \deprecated */
+typedef DiagonalMatrix<float, 2> AlignedScaling2f;
+/** \deprecated */
+typedef DiagonalMatrix<double,2> AlignedScaling2d;
+/** \deprecated */
+typedef DiagonalMatrix<float, 3> AlignedScaling3f;
+/** \deprecated */
+typedef DiagonalMatrix<double,3> AlignedScaling3d;
+//@}
+
+template<typename Scalar>
+template<int Dim>
+inline Transform<Scalar,Dim,Affine>
+UniformScaling<Scalar>::operator* (const Translation<Scalar,Dim>& t) const
+{
+ Transform<Scalar,Dim,Affine> res;
+ res.matrix().setZero();
+ res.linear().diagonal().fill(factor());
+ res.translation() = factor() * t.vector();
+ res(Dim,Dim) = Scalar(1);
+ return res;
+}
+
+} // end namespace Eigen
+
+#endif // EIGEN_SCALING_H
diff --git a/Eigen/src/Geometry/Transform.h b/Eigen/src/Geometry/Transform.h
new file mode 100644
index 000000000..4c1ef8eaa
--- /dev/null
+++ b/Eigen/src/Geometry/Transform.h
@@ -0,0 +1,1440 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra.
+//
+// Copyright (C) 2008 Gael Guennebaud <gael.guennebaud@inria.fr>
+// Copyright (C) 2009 Benoit Jacob <jacob.benoit.1@gmail.com>
+// Copyright (C) 2010 Hauke Heibel <hauke.heibel@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 EIGEN_TRANSFORM_H
+#define EIGEN_TRANSFORM_H
+
+namespace Eigen {
+
+namespace internal {
+
+template<typename Transform>
+struct transform_traits
+{
+ enum
+ {
+ Dim = Transform::Dim,
+ HDim = Transform::HDim,
+ Mode = Transform::Mode,
+ IsProjective = (int(Mode)==int(Projective))
+ };
+};
+
+template< typename TransformType,
+ typename MatrixType,
+ int Case = transform_traits<TransformType>::IsProjective ? 0
+ : int(MatrixType::RowsAtCompileTime) == int(transform_traits<TransformType>::HDim) ? 1
+ : 2>
+struct transform_right_product_impl;
+
+template< typename Other,
+ int Mode,
+ int Options,
+ int Dim,
+ int HDim,
+ int OtherRows=Other::RowsAtCompileTime,
+ int OtherCols=Other::ColsAtCompileTime>
+struct transform_left_product_impl;
+
+template< typename Lhs,
+ typename Rhs,
+ bool AnyProjective =
+ transform_traits<Lhs>::IsProjective ||
+ transform_traits<Rhs>::IsProjective>
+struct transform_transform_product_impl;
+
+template< typename Other,
+ int Mode,
+ int Options,
+ int Dim,
+ int HDim,
+ int OtherRows=Other::RowsAtCompileTime,
+ int OtherCols=Other::ColsAtCompileTime>
+struct transform_construct_from_matrix;
+
+template<typename TransformType> struct transform_take_affine_part;
+
+} // end namespace internal
+
+/** \geometry_module \ingroup Geometry_Module
+ *
+ * \class Transform
+ *
+ * \brief Represents an homogeneous transformation in a N dimensional space
+ *
+ * \tparam _Scalar the scalar type, i.e., the type of the coefficients
+ * \tparam _Dim the dimension of the space
+ * \tparam _Mode the type of the transformation. Can be:
+ * - #Affine: the transformation is stored as a (Dim+1)^2 matrix,
+ * where the last row is assumed to be [0 ... 0 1].
+ * - #AffineCompact: the transformation is stored as a (Dim)x(Dim+1) matrix.
+ * - #Projective: the transformation is stored as a (Dim+1)^2 matrix
+ * without any assumption.
+ * \tparam _Options has the same meaning as in class Matrix. It allows to specify DontAlign and/or RowMajor.
+ * These Options are passed directly to the underlying matrix type.
+ *
+ * The homography is internally represented and stored by a matrix which
+ * is available through the matrix() method. To understand the behavior of
+ * this class you have to think a Transform object as its internal
+ * matrix representation. The chosen convention is right multiply:
+ *
+ * \code v' = T * v \endcode
+ *
+ * Therefore, an affine transformation matrix M is shaped like this:
+ *
+ * \f$ \left( \begin{array}{cc}
+ * linear & translation\\
+ * 0 ... 0 & 1
+ * \end{array} \right) \f$
+ *
+ * Note that for a projective transformation the last row can be anything,
+ * and then the interpretation of different parts might be sightly different.
+ *
+ * However, unlike a plain matrix, the Transform class provides many features
+ * simplifying both its assembly and usage. In particular, it can be composed
+ * with any other transformations (Transform,Translation,RotationBase,Matrix)
+ * and can be directly used to transform implicit homogeneous vectors. All these
+ * operations are handled via the operator*. For the composition of transformations,
+ * its principle consists to first convert the right/left hand sides of the product
+ * to a compatible (Dim+1)^2 matrix and then perform a pure matrix product.
+ * Of course, internally, operator* tries to perform the minimal number of operations
+ * according to the nature of each terms. Likewise, when applying the transform
+ * to non homogeneous vectors, the latters are automatically promoted to homogeneous
+ * one before doing the matrix product. The convertions to homogeneous representations
+ * are performed as follow:
+ *
+ * \b Translation t (Dim)x(1):
+ * \f$ \left( \begin{array}{cc}
+ * I & t \\
+ * 0\,...\,0 & 1
+ * \end{array} \right) \f$
+ *
+ * \b Rotation R (Dim)x(Dim):
+ * \f$ \left( \begin{array}{cc}
+ * R & 0\\
+ * 0\,...\,0 & 1
+ * \end{array} \right) \f$
+ *
+ * \b Linear \b Matrix L (Dim)x(Dim):
+ * \f$ \left( \begin{array}{cc}
+ * L & 0\\
+ * 0\,...\,0 & 1
+ * \end{array} \right) \f$
+ *
+ * \b Affine \b Matrix A (Dim)x(Dim+1):
+ * \f$ \left( \begin{array}{c}
+ * A\\
+ * 0\,...\,0\,1
+ * \end{array} \right) \f$
+ *
+ * \b Column \b vector v (Dim)x(1):
+ * \f$ \left( \begin{array}{c}
+ * v\\
+ * 1
+ * \end{array} \right) \f$
+ *
+ * \b Set \b of \b column \b vectors V1...Vn (Dim)x(n):
+ * \f$ \left( \begin{array}{ccc}
+ * v_1 & ... & v_n\\
+ * 1 & ... & 1
+ * \end{array} \right) \f$
+ *
+ * The concatenation of a Transform object with any kind of other transformation
+ * always returns a Transform object.
+ *
+ * A little exception to the "as pure matrix product" rule is the case of the
+ * transformation of non homogeneous vectors by an affine transformation. In
+ * that case the last matrix row can be ignored, and the product returns non
+ * homogeneous vectors.
+ *
+ * Since, for instance, a Dim x Dim matrix is interpreted as a linear transformation,
+ * it is not possible to directly transform Dim vectors stored in a Dim x Dim matrix.
+ * The solution is either to use a Dim x Dynamic matrix or explicitly request a
+ * vector transformation by making the vector homogeneous:
+ * \code
+ * m' = T * m.colwise().homogeneous();
+ * \endcode
+ * Note that there is zero overhead.
+ *
+ * Conversion methods from/to Qt's QMatrix and QTransform are available if the
+ * preprocessor token EIGEN_QT_SUPPORT is defined.
+ *
+ * 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_TRANSFORM_PLUGIN.
+ *
+ * \sa class Matrix, class Quaternion
+ */
+template<typename _Scalar, int _Dim, int _Mode, int _Options>
+class Transform
+{
+public:
+ EIGEN_MAKE_ALIGNED_OPERATOR_NEW_IF_VECTORIZABLE_FIXED_SIZE(_Scalar,_Dim==Dynamic ? Dynamic : (_Dim+1)*(_Dim+1))
+ enum {
+ Mode = _Mode,
+ Options = _Options,
+ Dim = _Dim, ///< space dimension in which the transformation holds
+ HDim = _Dim+1, ///< size of a respective homogeneous vector
+ Rows = int(Mode)==(AffineCompact) ? Dim : HDim
+ };
+ /** the scalar type of the coefficients */
+ typedef _Scalar Scalar;
+ typedef DenseIndex Index;
+ /** type of the matrix used to represent the transformation */
+ typedef typename internal::make_proper_matrix_type<Scalar,Rows,HDim,Options>::type MatrixType;
+ /** constified MatrixType */
+ typedef const MatrixType ConstMatrixType;
+ /** type of the matrix used to represent the linear part of the transformation */
+ typedef Matrix<Scalar,Dim,Dim,Options> LinearMatrixType;
+ /** type of read/write reference to the linear part of the transformation */
+ typedef Block<MatrixType,Dim,Dim,int(Mode)==(AffineCompact)> LinearPart;
+ /** type of read reference to the linear part of the transformation */
+ typedef const Block<ConstMatrixType,Dim,Dim,int(Mode)==(AffineCompact)> ConstLinearPart;
+ /** type of read/write reference to the affine part of the transformation */
+ typedef typename internal::conditional<int(Mode)==int(AffineCompact),
+ MatrixType&,
+ Block<MatrixType,Dim,HDim> >::type AffinePart;
+ /** type of read reference to the affine part of the transformation */
+ typedef typename internal::conditional<int(Mode)==int(AffineCompact),
+ const MatrixType&,
+ const Block<const MatrixType,Dim,HDim> >::type ConstAffinePart;
+ /** type of a vector */
+ typedef Matrix<Scalar,Dim,1> VectorType;
+ /** type of a read/write reference to the translation part of the rotation */
+ typedef Block<MatrixType,Dim,1,int(Mode)==(AffineCompact)> TranslationPart;
+ /** type of a read reference to the translation part of the rotation */
+ typedef const Block<ConstMatrixType,Dim,1,int(Mode)==(AffineCompact)> ConstTranslationPart;
+ /** corresponding translation type */
+ typedef Translation<Scalar,Dim> TranslationType;
+
+ // this intermediate enum is needed to avoid an ICE with gcc 3.4 and 4.0
+ enum { TransformTimeDiagonalMode = ((Mode==int(Isometry))?Affine:int(Mode)) };
+ /** The return type of the product between a diagonal matrix and a transform */
+ typedef Transform<Scalar,Dim,TransformTimeDiagonalMode> TransformTimeDiagonalReturnType;
+
+protected:
+
+ MatrixType m_matrix;
+
+public:
+
+ /** Default constructor without initialization of the meaningful coefficients.
+ * If Mode==Affine, then the last row is set to [0 ... 0 1] */
+ inline Transform()
+ {
+ check_template_params();
+ if (int(Mode)==Affine)
+ makeAffine();
+ }
+
+ inline Transform(const Transform& other)
+ {
+ check_template_params();
+ m_matrix = other.m_matrix;
+ }
+
+ inline explicit Transform(const TranslationType& t)
+ {
+ check_template_params();
+ *this = t;
+ }
+ inline explicit Transform(const UniformScaling<Scalar>& s)
+ {
+ check_template_params();
+ *this = s;
+ }
+ template<typename Derived>
+ inline explicit Transform(const RotationBase<Derived, Dim>& r)
+ {
+ check_template_params();
+ *this = r;
+ }
+
+ inline Transform& operator=(const Transform& other)
+ { m_matrix = other.m_matrix; return *this; }
+
+ typedef internal::transform_take_affine_part<Transform> take_affine_part;
+
+ /** Constructs and initializes a transformation from a Dim^2 or a (Dim+1)^2 matrix. */
+ template<typename OtherDerived>
+ inline explicit Transform(const EigenBase<OtherDerived>& other)
+ {
+ EIGEN_STATIC_ASSERT((internal::is_same<Scalar,typename OtherDerived::Scalar>::value),
+ YOU_MIXED_DIFFERENT_NUMERIC_TYPES__YOU_NEED_TO_USE_THE_CAST_METHOD_OF_MATRIXBASE_TO_CAST_NUMERIC_TYPES_EXPLICITLY);
+
+ check_template_params();
+ internal::transform_construct_from_matrix<OtherDerived,Mode,Options,Dim,HDim>::run(this, other.derived());
+ }
+
+ /** Set \c *this from a Dim^2 or (Dim+1)^2 matrix. */
+ template<typename OtherDerived>
+ inline Transform& operator=(const EigenBase<OtherDerived>& other)
+ {
+ EIGEN_STATIC_ASSERT((internal::is_same<Scalar,typename OtherDerived::Scalar>::value),
+ YOU_MIXED_DIFFERENT_NUMERIC_TYPES__YOU_NEED_TO_USE_THE_CAST_METHOD_OF_MATRIXBASE_TO_CAST_NUMERIC_TYPES_EXPLICITLY);
+
+ internal::transform_construct_from_matrix<OtherDerived,Mode,Options,Dim,HDim>::run(this, other.derived());
+ return *this;
+ }
+
+ template<int OtherOptions>
+ inline Transform(const Transform<Scalar,Dim,Mode,OtherOptions>& other)
+ {
+ check_template_params();
+ // only the options change, we can directly copy the matrices
+ m_matrix = other.matrix();
+ }
+
+ template<int OtherMode,int OtherOptions>
+ inline Transform(const Transform<Scalar,Dim,OtherMode,OtherOptions>& other)
+ {
+ check_template_params();
+ // prevent conversions as:
+ // Affine | AffineCompact | Isometry = Projective
+ EIGEN_STATIC_ASSERT(EIGEN_IMPLIES(OtherMode==int(Projective), Mode==int(Projective)),
+ YOU_PERFORMED_AN_INVALID_TRANSFORMATION_CONVERSION)
+
+ // prevent conversions as:
+ // Isometry = Affine | AffineCompact
+ EIGEN_STATIC_ASSERT(EIGEN_IMPLIES(OtherMode==int(Affine)||OtherMode==int(AffineCompact), Mode!=int(Isometry)),
+ YOU_PERFORMED_AN_INVALID_TRANSFORMATION_CONVERSION)
+
+ enum { ModeIsAffineCompact = Mode == int(AffineCompact),
+ OtherModeIsAffineCompact = OtherMode == int(AffineCompact)
+ };
+
+ if(ModeIsAffineCompact == OtherModeIsAffineCompact)
+ {
+ // We need the block expression because the code is compiled for all
+ // combinations of transformations and will trigger a compile time error
+ // if one tries to assign the matrices directly
+ m_matrix.template block<Dim,Dim+1>(0,0) = other.matrix().template block<Dim,Dim+1>(0,0);
+ makeAffine();
+ }
+ else if(OtherModeIsAffineCompact)
+ {
+ typedef typename Transform<Scalar,Dim,OtherMode,OtherOptions>::MatrixType OtherMatrixType;
+ internal::transform_construct_from_matrix<OtherMatrixType,Mode,Options,Dim,HDim>::run(this, other.matrix());
+ }
+ else
+ {
+ // here we know that Mode == AffineCompact and OtherMode != AffineCompact.
+ // if OtherMode were Projective, the static assert above would already have caught it.
+ // So the only possibility is that OtherMode == Affine
+ linear() = other.linear();
+ translation() = other.translation();
+ }
+ }
+
+ template<typename OtherDerived>
+ Transform(const ReturnByValue<OtherDerived>& other)
+ {
+ check_template_params();
+ other.evalTo(*this);
+ }
+
+ template<typename OtherDerived>
+ Transform& operator=(const ReturnByValue<OtherDerived>& other)
+ {
+ other.evalTo(*this);
+ 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::operator(Index,Index) const */
+ inline Scalar operator() (Index row, Index col) const { return m_matrix(row,col); }
+ /** shortcut for m_matrix(row,col);
+ * \sa MatrixBase::operator(Index,Index) */
+ inline Scalar& operator() (Index row, Index 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 part of the transformation */
+ inline ConstLinearPart linear() const { return ConstLinearPart(m_matrix,0,0); }
+ /** \returns a writable expression of the linear part of the transformation */
+ inline LinearPart linear() { return LinearPart(m_matrix,0,0); }
+
+ /** \returns a read-only expression of the Dim x HDim affine part of the transformation */
+ inline ConstAffinePart affine() const { return take_affine_part::run(m_matrix); }
+ /** \returns a writable expression of the Dim x HDim affine part of the transformation */
+ inline AffinePart affine() { return take_affine_part::run(m_matrix); }
+
+ /** \returns a read-only expression of the translation vector of the transformation */
+ inline ConstTranslationPart translation() const { return ConstTranslationPart(m_matrix,0,Dim); }
+ /** \returns a writable expression of the translation vector of the transformation */
+ inline TranslationPart translation() { return TranslationPart(m_matrix,0,Dim); }
+
+ /** \returns an expression of the product between the transform \c *this and a matrix expression \a other
+ *
+ * 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 set of vectors of size Dim x Dynamic,
+ * \li a set of homogeneous vectors of size Dim+1 x Dynamic,
+ * \li a linear transformation matrix of size Dim x Dim,
+ * \li an affine transformation matrix of size Dim x 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<typename OtherDerived>
+ EIGEN_STRONG_INLINE const typename internal::transform_right_product_impl<Transform, OtherDerived>::ResultType
+ operator * (const EigenBase<OtherDerived> &other) const
+ { return internal::transform_right_product_impl<Transform, OtherDerived>::run(*this,other.derived()); }
+
+ /** \returns the product expression of a transformation matrix \a a times a transform \a b
+ *
+ * The left hand side \a other might be either:
+ * \li a linear transformation matrix of size Dim x Dim,
+ * \li an affine transformation matrix of size Dim x Dim+1,
+ * \li a general transformation matrix of size Dim+1 x Dim+1.
+ */
+ template<typename OtherDerived> friend
+ inline const typename internal::transform_left_product_impl<OtherDerived,Mode,Options,_Dim,_Dim+1>::ResultType
+ operator * (const EigenBase<OtherDerived> &a, const Transform &b)
+ { return internal::transform_left_product_impl<OtherDerived,Mode,Options,Dim,HDim>::run(a.derived(),b); }
+
+ /** \returns The product expression of a transform \a a times a diagonal matrix \a b
+ *
+ * The rhs diagonal matrix is interpreted as an affine scaling transformation. The
+ * product results in a Transform of the same type (mode) as the lhs only if the lhs
+ * mode is no isometry. In that case, the returned transform is an affinity.
+ */
+ template<typename DiagonalDerived>
+ inline const TransformTimeDiagonalReturnType
+ operator * (const DiagonalBase<DiagonalDerived> &b) const
+ {
+ TransformTimeDiagonalReturnType res(*this);
+ res.linear() *= b;
+ return res;
+ }
+
+ /** \returns The product expression of a diagonal matrix \a a times a transform \a b
+ *
+ * The lhs diagonal matrix is interpreted as an affine scaling transformation. The
+ * product results in a Transform of the same type (mode) as the lhs only if the lhs
+ * mode is no isometry. In that case, the returned transform is an affinity.
+ */
+ template<typename DiagonalDerived>
+ friend inline TransformTimeDiagonalReturnType
+ operator * (const DiagonalBase<DiagonalDerived> &a, const Transform &b)
+ {
+ TransformTimeDiagonalReturnType res;
+ res.linear().noalias() = a*b.linear();
+ res.translation().noalias() = a*b.translation();
+ if (Mode!=int(AffineCompact))
+ res.matrix().row(Dim) = b.matrix().row(Dim);
+ return res;
+ }
+
+ template<typename OtherDerived>
+ inline Transform& operator*=(const EigenBase<OtherDerived>& other) { return *this = *this * other; }
+
+ /** Concatenates two transformations */
+ inline const Transform operator * (const Transform& other) const
+ {
+ return internal::transform_transform_product_impl<Transform,Transform>::run(*this,other);
+ }
+
+ #ifdef __INTEL_COMPILER
+private:
+ // this intermediate structure permits to workaround a bug in ICC 11:
+ // error: template instantiation resulted in unexpected function type of "Eigen::Transform<double, 3, 32, 0>
+ // (const Eigen::Transform<double, 3, 2, 0> &) const"
+ // (the meaning of a name may have changed since the template declaration -- the type of the template is:
+ // "Eigen::internal::transform_transform_product_impl<Eigen::Transform<double, 3, 32, 0>,
+ // Eigen::Transform<double, 3, Mode, Options>, <expression>>::ResultType (const Eigen::Transform<double, 3, Mode, Options> &) const")
+ //
+ template<int OtherMode,int OtherOptions> struct icc_11_workaround
+ {
+ typedef internal::transform_transform_product_impl<Transform,Transform<Scalar,Dim,OtherMode,OtherOptions> > ProductType;
+ typedef typename ProductType::ResultType ResultType;
+ };
+
+public:
+ /** Concatenates two different transformations */
+ template<int OtherMode,int OtherOptions>
+ inline typename icc_11_workaround<OtherMode,OtherOptions>::ResultType
+ operator * (const Transform<Scalar,Dim,OtherMode,OtherOptions>& other) const
+ {
+ typedef typename icc_11_workaround<OtherMode,OtherOptions>::ProductType ProductType;
+ return ProductType::run(*this,other);
+ }
+ #else
+ /** Concatenates two different transformations */
+ template<int OtherMode,int OtherOptions>
+ inline typename internal::transform_transform_product_impl<Transform,Transform<Scalar,Dim,OtherMode,OtherOptions> >::ResultType
+ operator * (const Transform<Scalar,Dim,OtherMode,OtherOptions>& other) const
+ {
+ return internal::transform_transform_product_impl<Transform,Transform<Scalar,Dim,OtherMode,OtherOptions> >::run(*this,other);
+ }
+ #endif
+
+ /** \sa MatrixBase::setIdentity() */
+ void setIdentity() { m_matrix.setIdentity(); }
+
+ /**
+ * \brief Returns an identity transformation.
+ * \todo In the future this function should be returning a Transform expression.
+ */
+ static const Transform Identity()
+ {
+ return Transform(MatrixType::Identity());
+ }
+
+ template<typename OtherDerived>
+ inline Transform& scale(const MatrixBase<OtherDerived> &other);
+
+ template<typename OtherDerived>
+ inline Transform& prescale(const MatrixBase<OtherDerived> &other);
+
+ inline Transform& scale(Scalar s);
+ inline Transform& prescale(Scalar s);
+
+ template<typename OtherDerived>
+ inline Transform& translate(const MatrixBase<OtherDerived> &other);
+
+ template<typename OtherDerived>
+ inline Transform& pretranslate(const MatrixBase<OtherDerived> &other);
+
+ template<typename RotationType>
+ inline Transform& rotate(const RotationType& rotation);
+
+ template<typename RotationType>
+ 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 UniformScaling<Scalar>& t);
+ inline Transform& operator*=(const UniformScaling<Scalar>& s) { return scale(s.factor()); }
+ inline Transform<Scalar,Dim,(int(Mode)==int(Isometry)?Affine:Isometry)> operator*(const UniformScaling<Scalar>& s) const
+ {
+ Transform<Scalar,Dim,(int(Mode)==int(Isometry)?Affine:Isometry),Options> res = *this;
+ res.scale(s.factor());
+ return res;
+ }
+
+ inline Transform& operator*=(const DiagonalMatrix<Scalar,Dim>& s) { linear() *= s; return *this; }
+
+ template<typename Derived>
+ inline Transform& operator=(const RotationBase<Derived,Dim>& r);
+ template<typename Derived>
+ inline Transform& operator*=(const RotationBase<Derived,Dim>& r) { return rotate(r.toRotationMatrix()); }
+ template<typename Derived>
+ inline Transform operator*(const RotationBase<Derived,Dim>& r) const;
+
+ const LinearMatrixType rotation() const;
+ template<typename RotationMatrixType, typename ScalingMatrixType>
+ void computeRotationScaling(RotationMatrixType *rotation, ScalingMatrixType *scaling) const;
+ template<typename ScalingMatrixType, typename RotationMatrixType>
+ void computeScalingRotation(ScalingMatrixType *scaling, RotationMatrixType *rotation) const;
+
+ template<typename PositionDerived, typename OrientationType, typename ScaleDerived>
+ Transform& fromPositionOrientationScale(const MatrixBase<PositionDerived> &position,
+ const OrientationType& orientation, const MatrixBase<ScaleDerived> &scale);
+
+ inline Transform inverse(TransformTraits traits = (TransformTraits)Mode) 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<typename NewScalarType>
+ inline typename internal::cast_return_type<Transform,Transform<NewScalarType,Dim,Mode,Options> >::type cast() const
+ { return typename internal::cast_return_type<Transform,Transform<NewScalarType,Dim,Mode,Options> >::type(*this); }
+
+ /** Copy constructor with scalar type conversion */
+ template<typename OtherScalarType>
+ inline explicit Transform(const Transform<OtherScalarType,Dim,Mode,Options>& other)
+ {
+ check_template_params();
+ m_matrix = other.matrix().template cast<Scalar>();
+ }
+
+ /** \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<Scalar>::Real prec = NumTraits<Scalar>::dummy_precision()) const
+ { return m_matrix.isApprox(other.m_matrix, prec); }
+
+ /** Sets the last row to [0 ... 0 1]
+ */
+ void makeAffine()
+ {
+ if(int(Mode)!=int(AffineCompact))
+ {
+ matrix().template block<1,Dim>(Dim,0).setZero();
+ matrix().coeffRef(Dim,Dim) = Scalar(1);
+ }
+ }
+
+ /** \internal
+ * \returns the Dim x Dim linear part if the transformation is affine,
+ * and the HDim x Dim part for projective transformations.
+ */
+ inline Block<MatrixType,int(Mode)==int(Projective)?HDim:Dim,Dim> linearExt()
+ { return m_matrix.template block<int(Mode)==int(Projective)?HDim:Dim,Dim>(0,0); }
+ /** \internal
+ * \returns the Dim x Dim linear part if the transformation is affine,
+ * and the HDim x Dim part for projective transformations.
+ */
+ inline const Block<MatrixType,int(Mode)==int(Projective)?HDim:Dim,Dim> linearExt() const
+ { return m_matrix.template block<int(Mode)==int(Projective)?HDim:Dim,Dim>(0,0); }
+
+ /** \internal
+ * \returns the translation part if the transformation is affine,
+ * and the last column for projective transformations.
+ */
+ inline Block<MatrixType,int(Mode)==int(Projective)?HDim:Dim,1> translationExt()
+ { return m_matrix.template block<int(Mode)==int(Projective)?HDim:Dim,1>(0,Dim); }
+ /** \internal
+ * \returns the translation part if the transformation is affine,
+ * and the last column for projective transformations.
+ */
+ inline const Block<MatrixType,int(Mode)==int(Projective)?HDim:Dim,1> translationExt() const
+ { return m_matrix.template block<int(Mode)==int(Projective)?HDim:Dim,1>(0,Dim); }
+
+
+ #ifdef EIGEN_TRANSFORM_PLUGIN
+ #include EIGEN_TRANSFORM_PLUGIN
+ #endif
+
+protected:
+ #ifndef EIGEN_PARSED_BY_DOXYGEN
+ static EIGEN_STRONG_INLINE void check_template_params()
+ {
+ EIGEN_STATIC_ASSERT((Options & (DontAlign|RowMajor)) == Options, INVALID_MATRIX_TEMPLATE_PARAMETERS)
+ }
+ #endif
+
+};
+
+/** \ingroup Geometry_Module */
+typedef Transform<float,2,Isometry> Isometry2f;
+/** \ingroup Geometry_Module */
+typedef Transform<float,3,Isometry> Isometry3f;
+/** \ingroup Geometry_Module */
+typedef Transform<double,2,Isometry> Isometry2d;
+/** \ingroup Geometry_Module */
+typedef Transform<double,3,Isometry> Isometry3d;
+
+/** \ingroup Geometry_Module */
+typedef Transform<float,2,Affine> Affine2f;
+/** \ingroup Geometry_Module */
+typedef Transform<float,3,Affine> Affine3f;
+/** \ingroup Geometry_Module */
+typedef Transform<double,2,Affine> Affine2d;
+/** \ingroup Geometry_Module */
+typedef Transform<double,3,Affine> Affine3d;
+
+/** \ingroup Geometry_Module */
+typedef Transform<float,2,AffineCompact> AffineCompact2f;
+/** \ingroup Geometry_Module */
+typedef Transform<float,3,AffineCompact> AffineCompact3f;
+/** \ingroup Geometry_Module */
+typedef Transform<double,2,AffineCompact> AffineCompact2d;
+/** \ingroup Geometry_Module */
+typedef Transform<double,3,AffineCompact> AffineCompact3d;
+
+/** \ingroup Geometry_Module */
+typedef Transform<float,2,Projective> Projective2f;
+/** \ingroup Geometry_Module */
+typedef Transform<float,3,Projective> Projective3f;
+/** \ingroup Geometry_Module */
+typedef Transform<double,2,Projective> Projective2d;
+/** \ingroup Geometry_Module */
+typedef Transform<double,3,Projective> Projective3d;
+
+/**************************
+*** Optional QT support ***
+**************************/
+
+#ifdef EIGEN_QT_SUPPORT
+/** Initializes \c *this from a QMatrix assuming the dimension is 2.
+ *
+ * This function is available only if the token EIGEN_QT_SUPPORT is defined.
+ */
+template<typename Scalar, int Dim, int Mode,int Options>
+Transform<Scalar,Dim,Mode,Options>::Transform(const QMatrix& other)
+{
+ check_template_params();
+ *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<typename Scalar, int Dim, int Mode,int Options>
+Transform<Scalar,Dim,Mode,Options>& Transform<Scalar,Dim,Mode,Options>::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 conversion might loss data if \c *this is not affine
+ *
+ * This function is available only if the token EIGEN_QT_SUPPORT is defined.
+ */
+template<typename Scalar, int Dim, int Mode, int Options>
+QMatrix Transform<Scalar,Dim,Mode,Options>::toQMatrix(void) const
+{
+ check_template_params();
+ 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));
+}
+
+/** Initializes \c *this from a QTransform assuming the dimension is 2.
+ *
+ * This function is available only if the token EIGEN_QT_SUPPORT is defined.
+ */
+template<typename Scalar, int Dim, int Mode,int Options>
+Transform<Scalar,Dim,Mode,Options>::Transform(const QTransform& other)
+{
+ check_template_params();
+ *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<typename Scalar, int Dim, int Mode, int Options>
+Transform<Scalar,Dim,Mode,Options>& Transform<Scalar,Dim,Mode,Options>::operator=(const QTransform& other)
+{
+ check_template_params();
+ EIGEN_STATIC_ASSERT(Dim==2, YOU_MADE_A_PROGRAMMING_MISTAKE)
+ if (Mode == int(AffineCompact))
+ m_matrix << other.m11(), other.m21(), other.dx(),
+ other.m12(), other.m22(), other.dy();
+ else
+ 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<typename Scalar, int Dim, int Mode, int Options>
+QTransform Transform<Scalar,Dim,Mode,Options>::toQTransform(void) const
+{
+ EIGEN_STATIC_ASSERT(Dim==2, YOU_MADE_A_PROGRAMMING_MISTAKE)
+ if (Mode == int(AffineCompact))
+ return QTransform(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));
+ else
+ 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<typename Scalar, int Dim, int Mode, int Options>
+template<typename OtherDerived>
+Transform<Scalar,Dim,Mode,Options>&
+Transform<Scalar,Dim,Mode,Options>::scale(const MatrixBase<OtherDerived> &other)
+{
+ EIGEN_STATIC_ASSERT_VECTOR_SPECIFIC_SIZE(OtherDerived,int(Dim))
+ EIGEN_STATIC_ASSERT(Mode!=int(Isometry), THIS_METHOD_IS_ONLY_FOR_SPECIFIC_TRANSFORMATIONS)
+ linearExt().noalias() = (linearExt() * other.asDiagonal());
+ 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<typename Scalar, int Dim, int Mode, int Options>
+inline Transform<Scalar,Dim,Mode,Options>& Transform<Scalar,Dim,Mode,Options>::scale(Scalar s)
+{
+ EIGEN_STATIC_ASSERT(Mode!=int(Isometry), THIS_METHOD_IS_ONLY_FOR_SPECIFIC_TRANSFORMATIONS)
+ linearExt() *= 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<typename Scalar, int Dim, int Mode, int Options>
+template<typename OtherDerived>
+Transform<Scalar,Dim,Mode,Options>&
+Transform<Scalar,Dim,Mode,Options>::prescale(const MatrixBase<OtherDerived> &other)
+{
+ EIGEN_STATIC_ASSERT_VECTOR_SPECIFIC_SIZE(OtherDerived,int(Dim))
+ EIGEN_STATIC_ASSERT(Mode!=int(Isometry), THIS_METHOD_IS_ONLY_FOR_SPECIFIC_TRANSFORMATIONS)
+ m_matrix.template block<Dim,HDim>(0,0).noalias() = (other.asDiagonal() * m_matrix.template block<Dim,HDim>(0,0));
+ 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<typename Scalar, int Dim, int Mode, int Options>
+inline Transform<Scalar,Dim,Mode,Options>& Transform<Scalar,Dim,Mode,Options>::prescale(Scalar s)
+{
+ EIGEN_STATIC_ASSERT(Mode!=int(Isometry), THIS_METHOD_IS_ONLY_FOR_SPECIFIC_TRANSFORMATIONS)
+ m_matrix.template topRows<Dim>() *= 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<typename Scalar, int Dim, int Mode, int Options>
+template<typename OtherDerived>
+Transform<Scalar,Dim,Mode,Options>&
+Transform<Scalar,Dim,Mode,Options>::translate(const MatrixBase<OtherDerived> &other)
+{
+ EIGEN_STATIC_ASSERT_VECTOR_SPECIFIC_SIZE(OtherDerived,int(Dim))
+ translationExt() += linearExt() * 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<typename Scalar, int Dim, int Mode, int Options>
+template<typename OtherDerived>
+Transform<Scalar,Dim,Mode,Options>&
+Transform<Scalar,Dim,Mode,Options>::pretranslate(const MatrixBase<OtherDerived> &other)
+{
+ EIGEN_STATIC_ASSERT_VECTOR_SPECIFIC_SIZE(OtherDerived,int(Dim))
+ if(int(Mode)==int(Projective))
+ affine() += other * m_matrix.row(Dim);
+ else
+ 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 internal::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<typename Scalar, int Dim, int Mode, int Options>
+template<typename RotationType>
+Transform<Scalar,Dim,Mode,Options>&
+Transform<Scalar,Dim,Mode,Options>::rotate(const RotationType& rotation)
+{
+ linearExt() *= internal::toRotationMatrix<Scalar,Dim>(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<typename Scalar, int Dim, int Mode, int Options>
+template<typename RotationType>
+Transform<Scalar,Dim,Mode,Options>&
+Transform<Scalar,Dim,Mode,Options>::prerotate(const RotationType& rotation)
+{
+ m_matrix.template block<Dim,HDim>(0,0) = internal::toRotationMatrix<Scalar,Dim>(rotation)
+ * m_matrix.template block<Dim,HDim>(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<typename Scalar, int Dim, int Mode, int Options>
+Transform<Scalar,Dim,Mode,Options>&
+Transform<Scalar,Dim,Mode,Options>::shear(Scalar sx, Scalar sy)
+{
+ EIGEN_STATIC_ASSERT(int(Dim)==2, YOU_MADE_A_PROGRAMMING_MISTAKE)
+ EIGEN_STATIC_ASSERT(Mode!=int(Isometry), THIS_METHOD_IS_ONLY_FOR_SPECIFIC_TRANSFORMATIONS)
+ 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<typename Scalar, int Dim, int Mode, int Options>
+Transform<Scalar,Dim,Mode,Options>&
+Transform<Scalar,Dim,Mode,Options>::preshear(Scalar sx, Scalar sy)
+{
+ EIGEN_STATIC_ASSERT(int(Dim)==2, YOU_MADE_A_PROGRAMMING_MISTAKE)
+ EIGEN_STATIC_ASSERT(Mode!=int(Isometry), THIS_METHOD_IS_ONLY_FOR_SPECIFIC_TRANSFORMATIONS)
+ m_matrix.template block<Dim,HDim>(0,0) = LinearMatrixType(1, sx, sy, 1) * m_matrix.template block<Dim,HDim>(0,0);
+ return *this;
+}
+
+/******************************************************
+*** Scaling, Translation and Rotation compatibility ***
+******************************************************/
+
+template<typename Scalar, int Dim, int Mode, int Options>
+inline Transform<Scalar,Dim,Mode,Options>& Transform<Scalar,Dim,Mode,Options>::operator=(const TranslationType& t)
+{
+ linear().setIdentity();
+ translation() = t.vector();
+ makeAffine();
+ return *this;
+}
+
+template<typename Scalar, int Dim, int Mode, int Options>
+inline Transform<Scalar,Dim,Mode,Options> Transform<Scalar,Dim,Mode,Options>::operator*(const TranslationType& t) const
+{
+ Transform res = *this;
+ res.translate(t.vector());
+ return res;
+}
+
+template<typename Scalar, int Dim, int Mode, int Options>
+inline Transform<Scalar,Dim,Mode,Options>& Transform<Scalar,Dim,Mode,Options>::operator=(const UniformScaling<Scalar>& s)
+{
+ m_matrix.setZero();
+ linear().diagonal().fill(s.factor());
+ makeAffine();
+ return *this;
+}
+
+template<typename Scalar, int Dim, int Mode, int Options>
+template<typename Derived>
+inline Transform<Scalar,Dim,Mode,Options>& Transform<Scalar,Dim,Mode,Options>::operator=(const RotationBase<Derived,Dim>& r)
+{
+ linear() = internal::toRotationMatrix<Scalar,Dim>(r);
+ translation().setZero();
+ makeAffine();
+ return *this;
+}
+
+template<typename Scalar, int Dim, int Mode, int Options>
+template<typename Derived>
+inline Transform<Scalar,Dim,Mode,Options> Transform<Scalar,Dim,Mode,Options>::operator*(const RotationBase<Derived,Dim>& r) const
+{
+ Transform res = *this;
+ res.rotate(r.derived());
+ return res;
+}
+
+/************************
+*** Special functions ***
+************************/
+
+/** \returns the rotation part of the transformation
+ *
+ *
+ * \svd_module
+ *
+ * \sa computeRotationScaling(), computeScalingRotation(), class SVD
+ */
+template<typename Scalar, int Dim, int Mode, int Options>
+const typename Transform<Scalar,Dim,Mode,Options>::LinearMatrixType
+Transform<Scalar,Dim,Mode,Options>::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.
+ *
+ *
+ *
+ * \svd_module
+ *
+ * \sa computeScalingRotation(), rotation(), class SVD
+ */
+template<typename Scalar, int Dim, int Mode, int Options>
+template<typename RotationMatrixType, typename ScalingMatrixType>
+void Transform<Scalar,Dim,Mode,Options>::computeRotationScaling(RotationMatrixType *rotation, ScalingMatrixType *scaling) const
+{
+ JacobiSVD<LinearMatrixType> svd(linear(), ComputeFullU | ComputeFullV);
+
+ Scalar x = (svd.matrixU() * svd.matrixV().adjoint()).determinant(); // so x has absolute value 1
+ VectorType sv(svd.singularValues());
+ sv.coeffRef(0) *= x;
+ if(scaling) scaling->lazyAssign(svd.matrixV() * sv.asDiagonal() * svd.matrixV().adjoint());
+ if(rotation)
+ {
+ LinearMatrixType m(svd.matrixU());
+ m.col(0) /= x;
+ rotation->lazyAssign(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.
+ *
+ *
+ *
+ * \svd_module
+ *
+ * \sa computeRotationScaling(), rotation(), class SVD
+ */
+template<typename Scalar, int Dim, int Mode, int Options>
+template<typename ScalingMatrixType, typename RotationMatrixType>
+void Transform<Scalar,Dim,Mode,Options>::computeScalingRotation(ScalingMatrixType *scaling, RotationMatrixType *rotation) const
+{
+ JacobiSVD<LinearMatrixType> svd(linear(), ComputeFullU | ComputeFullV);
+
+ Scalar x = (svd.matrixU() * svd.matrixV().adjoint()).determinant(); // so x has absolute value 1
+ VectorType sv(svd.singularValues());
+ sv.coeffRef(0) *= x;
+ if(scaling) scaling->lazyAssign(svd.matrixU() * sv.asDiagonal() * svd.matrixU().adjoint());
+ if(rotation)
+ {
+ LinearMatrixType m(svd.matrixU());
+ m.col(0) /= x;
+ rotation->lazyAssign(m * svd.matrixV().adjoint());
+ }
+}
+
+/** Convenient method to set \c *this from a position, orientation and scale
+ * of a 3D object.
+ */
+template<typename Scalar, int Dim, int Mode, int Options>
+template<typename PositionDerived, typename OrientationType, typename ScaleDerived>
+Transform<Scalar,Dim,Mode,Options>&
+Transform<Scalar,Dim,Mode,Options>::fromPositionOrientationScale(const MatrixBase<PositionDerived> &position,
+ const OrientationType& orientation, const MatrixBase<ScaleDerived> &scale)
+{
+ linear() = internal::toRotationMatrix<Scalar,Dim>(orientation);
+ linear() *= scale.asDiagonal();
+ translation() = position;
+ makeAffine();
+ return *this;
+}
+
+namespace internal {
+
+// selector needed to avoid taking the inverse of a 3x4 matrix
+template<typename TransformType, int Mode=TransformType::Mode>
+struct projective_transform_inverse
+{
+ static inline void run(const TransformType&, TransformType&)
+ {}
+};
+
+template<typename TransformType>
+struct projective_transform_inverse<TransformType, Projective>
+{
+ static inline void run(const TransformType& m, TransformType& res)
+ {
+ res.matrix() = m.matrix().inverse();
+ }
+};
+
+} // end namespace internal
+
+
+/**
+ *
+ * \returns the inverse transformation according to some given knowledge
+ * on \c *this.
+ *
+ * \param hint allows to optimize the inversion process when the transformation
+ * is known to be not a general transformation (optional). 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 if the last row can be assumed to be [0 ... 0 1]
+ * - #Isometry if the transformation is only a concatenations of translations
+ * and rotations.
+ * The default is the template class parameter \c Mode.
+ *
+ * \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<typename Scalar, int Dim, int Mode, int Options>
+Transform<Scalar,Dim,Mode,Options>
+Transform<Scalar,Dim,Mode,Options>::inverse(TransformTraits hint) const
+{
+ Transform res;
+ if (hint == Projective)
+ {
+ internal::projective_transform_inverse<Transform>::run(*this, res);
+ }
+ else
+ {
+ if (hint == Isometry)
+ {
+ res.matrix().template topLeftCorner<Dim,Dim>() = linear().transpose();
+ }
+ else if(hint&Affine)
+ {
+ res.matrix().template topLeftCorner<Dim,Dim>() = linear().inverse();
+ }
+ else
+ {
+ eigen_assert(false && "Invalid transform traits in Transform::Inverse");
+ }
+ // translation and remaining parts
+ res.matrix().template topRightCorner<Dim,1>()
+ = - res.matrix().template topLeftCorner<Dim,Dim>() * translation();
+ res.makeAffine(); // we do need this, because in the beginning res is uninitialized
+ }
+ return res;
+}
+
+namespace internal {
+
+/*****************************************************
+*** Specializations of take affine part ***
+*****************************************************/
+
+template<typename TransformType> struct transform_take_affine_part {
+ typedef typename TransformType::MatrixType MatrixType;
+ typedef typename TransformType::AffinePart AffinePart;
+ typedef typename TransformType::ConstAffinePart ConstAffinePart;
+ static inline AffinePart run(MatrixType& m)
+ { return m.template block<TransformType::Dim,TransformType::HDim>(0,0); }
+ static inline ConstAffinePart run(const MatrixType& m)
+ { return m.template block<TransformType::Dim,TransformType::HDim>(0,0); }
+};
+
+template<typename Scalar, int Dim, int Options>
+struct transform_take_affine_part<Transform<Scalar,Dim,AffineCompact, Options> > {
+ typedef typename Transform<Scalar,Dim,AffineCompact,Options>::MatrixType MatrixType;
+ static inline MatrixType& run(MatrixType& m) { return m; }
+ static inline const MatrixType& run(const MatrixType& m) { return m; }
+};
+
+/*****************************************************
+*** Specializations of construct from matrix ***
+*****************************************************/
+
+template<typename Other, int Mode, int Options, int Dim, int HDim>
+struct transform_construct_from_matrix<Other, Mode,Options,Dim,HDim, Dim,Dim>
+{
+ static inline void run(Transform<typename Other::Scalar,Dim,Mode,Options> *transform, const Other& other)
+ {
+ transform->linear() = other;
+ transform->translation().setZero();
+ transform->makeAffine();
+ }
+};
+
+template<typename Other, int Mode, int Options, int Dim, int HDim>
+struct transform_construct_from_matrix<Other, Mode,Options,Dim,HDim, Dim,HDim>
+{
+ static inline void run(Transform<typename Other::Scalar,Dim,Mode,Options> *transform, const Other& other)
+ {
+ transform->affine() = other;
+ transform->makeAffine();
+ }
+};
+
+template<typename Other, int Mode, int Options, int Dim, int HDim>
+struct transform_construct_from_matrix<Other, Mode,Options,Dim,HDim, HDim,HDim>
+{
+ static inline void run(Transform<typename Other::Scalar,Dim,Mode,Options> *transform, const Other& other)
+ { transform->matrix() = other; }
+};
+
+template<typename Other, int Options, int Dim, int HDim>
+struct transform_construct_from_matrix<Other, AffineCompact,Options,Dim,HDim, HDim,HDim>
+{
+ static inline void run(Transform<typename Other::Scalar,Dim,AffineCompact,Options> *transform, const Other& other)
+ { transform->matrix() = other.template block<Dim,HDim>(0,0); }
+};
+
+/**********************************************************
+*** Specializations of operator* with rhs EigenBase ***
+**********************************************************/
+
+template<int LhsMode,int RhsMode>
+struct transform_product_result
+{
+ enum
+ {
+ Mode =
+ (LhsMode == (int)Projective || RhsMode == (int)Projective ) ? Projective :
+ (LhsMode == (int)Affine || RhsMode == (int)Affine ) ? Affine :
+ (LhsMode == (int)AffineCompact || RhsMode == (int)AffineCompact ) ? AffineCompact :
+ (LhsMode == (int)Isometry || RhsMode == (int)Isometry ) ? Isometry : Projective
+ };
+};
+
+template< typename TransformType, typename MatrixType >
+struct transform_right_product_impl< TransformType, MatrixType, 0 >
+{
+ typedef typename MatrixType::PlainObject ResultType;
+
+ static EIGEN_STRONG_INLINE ResultType run(const TransformType& T, const MatrixType& other)
+ {
+ return T.matrix() * other;
+ }
+};
+
+template< typename TransformType, typename MatrixType >
+struct transform_right_product_impl< TransformType, MatrixType, 1 >
+{
+ enum {
+ Dim = TransformType::Dim,
+ HDim = TransformType::HDim,
+ OtherRows = MatrixType::RowsAtCompileTime,
+ OtherCols = MatrixType::ColsAtCompileTime
+ };
+
+ typedef typename MatrixType::PlainObject ResultType;
+
+ static EIGEN_STRONG_INLINE ResultType run(const TransformType& T, const MatrixType& other)
+ {
+ EIGEN_STATIC_ASSERT(OtherRows==HDim, YOU_MIXED_MATRICES_OF_DIFFERENT_SIZES);
+
+ typedef Block<ResultType, Dim, OtherCols, int(MatrixType::RowsAtCompileTime)==Dim> TopLeftLhs;
+
+ ResultType res(other.rows(),other.cols());
+ TopLeftLhs(res, 0, 0, Dim, other.cols()).noalias() = T.affine() * other;
+ res.row(OtherRows-1) = other.row(OtherRows-1);
+
+ return res;
+ }
+};
+
+template< typename TransformType, typename MatrixType >
+struct transform_right_product_impl< TransformType, MatrixType, 2 >
+{
+ enum {
+ Dim = TransformType::Dim,
+ HDim = TransformType::HDim,
+ OtherRows = MatrixType::RowsAtCompileTime,
+ OtherCols = MatrixType::ColsAtCompileTime
+ };
+
+ typedef typename MatrixType::PlainObject ResultType;
+
+ static EIGEN_STRONG_INLINE ResultType run(const TransformType& T, const MatrixType& other)
+ {
+ EIGEN_STATIC_ASSERT(OtherRows==Dim, YOU_MIXED_MATRICES_OF_DIFFERENT_SIZES);
+
+ typedef Block<ResultType, Dim, OtherCols, true> TopLeftLhs;
+ ResultType res(Replicate<typename TransformType::ConstTranslationPart, 1, OtherCols>(T.translation(),1,other.cols()));
+ TopLeftLhs(res, 0, 0, Dim, other.cols()).noalias() += T.linear() * other;
+
+ return res;
+ }
+};
+
+/**********************************************************
+*** Specializations of operator* with lhs EigenBase ***
+**********************************************************/
+
+// generic HDim x HDim matrix * T => Projective
+template<typename Other,int Mode, int Options, int Dim, int HDim>
+struct transform_left_product_impl<Other,Mode,Options,Dim,HDim, HDim,HDim>
+{
+ typedef Transform<typename Other::Scalar,Dim,Mode,Options> TransformType;
+ typedef typename TransformType::MatrixType MatrixType;
+ typedef Transform<typename Other::Scalar,Dim,Projective,Options> ResultType;
+ static ResultType run(const Other& other,const TransformType& tr)
+ { return ResultType(other * tr.matrix()); }
+};
+
+// generic HDim x HDim matrix * AffineCompact => Projective
+template<typename Other, int Options, int Dim, int HDim>
+struct transform_left_product_impl<Other,AffineCompact,Options,Dim,HDim, HDim,HDim>
+{
+ typedef Transform<typename Other::Scalar,Dim,AffineCompact,Options> TransformType;
+ typedef typename TransformType::MatrixType MatrixType;
+ typedef Transform<typename Other::Scalar,Dim,Projective,Options> ResultType;
+ static ResultType run(const Other& other,const TransformType& tr)
+ {
+ ResultType res;
+ res.matrix().noalias() = other.template block<HDim,Dim>(0,0) * tr.matrix();
+ res.matrix().col(Dim) += other.col(Dim);
+ return res;
+ }
+};
+
+// affine matrix * T
+template<typename Other,int Mode, int Options, int Dim, int HDim>
+struct transform_left_product_impl<Other,Mode,Options,Dim,HDim, Dim,HDim>
+{
+ typedef Transform<typename Other::Scalar,Dim,Mode,Options> TransformType;
+ typedef typename TransformType::MatrixType MatrixType;
+ typedef TransformType ResultType;
+ static ResultType run(const Other& other,const TransformType& tr)
+ {
+ ResultType res;
+ res.affine().noalias() = other * tr.matrix();
+ res.matrix().row(Dim) = tr.matrix().row(Dim);
+ return res;
+ }
+};
+
+// affine matrix * AffineCompact
+template<typename Other, int Options, int Dim, int HDim>
+struct transform_left_product_impl<Other,AffineCompact,Options,Dim,HDim, Dim,HDim>
+{
+ typedef Transform<typename Other::Scalar,Dim,AffineCompact,Options> TransformType;
+ typedef typename TransformType::MatrixType MatrixType;
+ typedef TransformType ResultType;
+ static ResultType run(const Other& other,const TransformType& tr)
+ {
+ ResultType res;
+ res.matrix().noalias() = other.template block<Dim,Dim>(0,0) * tr.matrix();
+ res.translation() += other.col(Dim);
+ return res;
+ }
+};
+
+// linear matrix * T
+template<typename Other,int Mode, int Options, int Dim, int HDim>
+struct transform_left_product_impl<Other,Mode,Options,Dim,HDim, Dim,Dim>
+{
+ typedef Transform<typename Other::Scalar,Dim,Mode,Options> TransformType;
+ typedef typename TransformType::MatrixType MatrixType;
+ typedef TransformType ResultType;
+ static ResultType run(const Other& other, const TransformType& tr)
+ {
+ TransformType res;
+ if(Mode!=int(AffineCompact))
+ res.matrix().row(Dim) = tr.matrix().row(Dim);
+ res.matrix().template topRows<Dim>().noalias()
+ = other * tr.matrix().template topRows<Dim>();
+ return res;
+ }
+};
+
+/**********************************************************
+*** Specializations of operator* with another Transform ***
+**********************************************************/
+
+template<typename Scalar, int Dim, int LhsMode, int LhsOptions, int RhsMode, int RhsOptions>
+struct transform_transform_product_impl<Transform<Scalar,Dim,LhsMode,LhsOptions>,Transform<Scalar,Dim,RhsMode,RhsOptions>,false >
+{
+ enum { ResultMode = transform_product_result<LhsMode,RhsMode>::Mode };
+ typedef Transform<Scalar,Dim,LhsMode,LhsOptions> Lhs;
+ typedef Transform<Scalar,Dim,RhsMode,RhsOptions> Rhs;
+ typedef Transform<Scalar,Dim,ResultMode,LhsOptions> ResultType;
+ static ResultType run(const Lhs& lhs, const Rhs& rhs)
+ {
+ ResultType res;
+ res.linear() = lhs.linear() * rhs.linear();
+ res.translation() = lhs.linear() * rhs.translation() + lhs.translation();
+ res.makeAffine();
+ return res;
+ }
+};
+
+template<typename Scalar, int Dim, int LhsMode, int LhsOptions, int RhsMode, int RhsOptions>
+struct transform_transform_product_impl<Transform<Scalar,Dim,LhsMode,LhsOptions>,Transform<Scalar,Dim,RhsMode,RhsOptions>,true >
+{
+ typedef Transform<Scalar,Dim,LhsMode,LhsOptions> Lhs;
+ typedef Transform<Scalar,Dim,RhsMode,RhsOptions> Rhs;
+ typedef Transform<Scalar,Dim,Projective> ResultType;
+ static ResultType run(const Lhs& lhs, const Rhs& rhs)
+ {
+ return ResultType( lhs.matrix() * rhs.matrix() );
+ }
+};
+
+template<typename Scalar, int Dim, int LhsOptions, int RhsOptions>
+struct transform_transform_product_impl<Transform<Scalar,Dim,AffineCompact,LhsOptions>,Transform<Scalar,Dim,Projective,RhsOptions>,true >
+{
+ typedef Transform<Scalar,Dim,AffineCompact,LhsOptions> Lhs;
+ typedef Transform<Scalar,Dim,Projective,RhsOptions> Rhs;
+ typedef Transform<Scalar,Dim,Projective> ResultType;
+ static ResultType run(const Lhs& lhs, const Rhs& rhs)
+ {
+ ResultType res;
+ res.matrix().template topRows<Dim>() = lhs.matrix() * rhs.matrix();
+ res.matrix().row(Dim) = rhs.matrix().row(Dim);
+ return res;
+ }
+};
+
+template<typename Scalar, int Dim, int LhsOptions, int RhsOptions>
+struct transform_transform_product_impl<Transform<Scalar,Dim,Projective,LhsOptions>,Transform<Scalar,Dim,AffineCompact,RhsOptions>,true >
+{
+ typedef Transform<Scalar,Dim,Projective,LhsOptions> Lhs;
+ typedef Transform<Scalar,Dim,AffineCompact,RhsOptions> Rhs;
+ typedef Transform<Scalar,Dim,Projective> ResultType;
+ static ResultType run(const Lhs& lhs, const Rhs& rhs)
+ {
+ ResultType res(lhs.matrix().template leftCols<Dim>() * rhs.matrix());
+ res.matrix().col(Dim) += lhs.matrix().col(Dim);
+ return res;
+ }
+};
+
+} // end namespace internal
+
+} // end namespace Eigen
+
+#endif // EIGEN_TRANSFORM_H
diff --git a/Eigen/src/Geometry/Translation.h b/Eigen/src/Geometry/Translation.h
new file mode 100644
index 000000000..7fda179cc
--- /dev/null
+++ b/Eigen/src/Geometry/Translation.h
@@ -0,0 +1,206 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra.
+//
+// Copyright (C) 2008 Gael Guennebaud <gael.guennebaud@inria.fr>
+//
+// This Source Code Form is subject to the terms of the Mozilla
+// Public License v. 2.0. If a copy of the MPL was not distributed
+// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+#ifndef EIGEN_TRANSLATION_H
+#define EIGEN_TRANSLATION_H
+
+namespace Eigen {
+
+/** \geometry_module \ingroup Geometry_Module
+ *
+ * \class Translation
+ *
+ * \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<typename _Scalar, int _Dim>
+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<Scalar,Dim,1> VectorType;
+ /** corresponding linear transformation matrix type */
+ typedef Matrix<Scalar,Dim,Dim> LinearMatrixType;
+ /** corresponding affine transformation type */
+ typedef Transform<Scalar,Dim,Affine> AffineTransformType;
+ /** corresponding isometric transformation type */
+ typedef Transform<Scalar,Dim,Isometry> IsometryTransformType;
+
+protected:
+
+ VectorType m_coeffs;
+
+public:
+
+ /** Default constructor without initialization. */
+ Translation() {}
+ /** */
+ inline Translation(const Scalar& sx, const Scalar& sy)
+ {
+ eigen_assert(Dim==2);
+ m_coeffs.x() = sx;
+ m_coeffs.y() = sy;
+ }
+ /** */
+ inline Translation(const Scalar& sx, const Scalar& sy, const Scalar& sz)
+ {
+ eigen_assert(Dim==3);
+ m_coeffs.x() = sx;
+ m_coeffs.y() = sy;
+ m_coeffs.z() = sz;
+ }
+ /** Constructs and initialize the translation transformation from a vector of translation coefficients */
+ explicit inline Translation(const VectorType& vector) : m_coeffs(vector) {}
+
+ /** \brief Retruns the x-translation by value. **/
+ inline Scalar x() const { return m_coeffs.x(); }
+ /** \brief Retruns the y-translation by value. **/
+ inline Scalar y() const { return m_coeffs.y(); }
+ /** \brief Retruns the z-translation by value. **/
+ inline Scalar z() const { return m_coeffs.z(); }
+
+ /** \brief Retruns the x-translation as a reference. **/
+ inline Scalar& x() { return m_coeffs.x(); }
+ /** \brief Retruns the y-translation as a reference. **/
+ inline Scalar& y() { return m_coeffs.y(); }
+ /** \brief Retruns the z-translation as a reference. **/
+ inline Scalar& z() { return m_coeffs.z(); }
+
+ const VectorType& vector() const { return m_coeffs; }
+ VectorType& vector() { return m_coeffs; }
+
+ const VectorType& translation() const { return m_coeffs; }
+ VectorType& translation() { 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 uniform scaling */
+ inline AffineTransformType operator* (const UniformScaling<Scalar>& other) const;
+
+ /** Concatenates a translation and a linear transformation */
+ template<typename OtherDerived>
+ inline AffineTransformType operator* (const EigenBase<OtherDerived>& linear) const;
+
+ /** Concatenates a translation and a rotation */
+ template<typename Derived>
+ inline IsometryTransformType operator*(const RotationBase<Derived,Dim>& r) const
+ { return *this * IsometryTransformType(r); }
+
+ /** \returns the concatenation of a linear transformation \a l with the translation \a t */
+ // its a nightmare to define a templated friend function outside its declaration
+ template<typename OtherDerived> friend
+ inline AffineTransformType operator*(const EigenBase<OtherDerived>& linear, const Translation& t)
+ {
+ AffineTransformType res;
+ res.matrix().setZero();
+ res.linear() = linear.derived();
+ res.translation() = linear.derived() * t.m_coeffs;
+ res.matrix().row(Dim).setZero();
+ res(Dim,Dim) = Scalar(1);
+ return res;
+ }
+
+ /** Concatenates a translation and a transformation */
+ template<int Mode, int Options>
+ inline Transform<Scalar,Dim,Mode> operator* (const Transform<Scalar,Dim,Mode,Options>& t) const
+ {
+ Transform<Scalar,Dim,Mode> res = t;
+ res.pretranslate(m_coeffs);
+ return res;
+ }
+
+ /** 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;
+ }
+
+ static const Translation Identity() { return Translation(VectorType::Zero()); }
+
+ /** \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<typename NewScalarType>
+ inline typename internal::cast_return_type<Translation,Translation<NewScalarType,Dim> >::type cast() const
+ { return typename internal::cast_return_type<Translation,Translation<NewScalarType,Dim> >::type(*this); }
+
+ /** Copy constructor with scalar type conversion */
+ template<typename OtherScalarType>
+ inline explicit Translation(const Translation<OtherScalarType,Dim>& other)
+ { m_coeffs = other.vector().template cast<Scalar>(); }
+
+ /** \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<Scalar>::Real prec = NumTraits<Scalar>::dummy_precision()) const
+ { return m_coeffs.isApprox(other.m_coeffs, prec); }
+
+};
+
+/** \addtogroup Geometry_Module */
+//@{
+typedef Translation<float, 2> Translation2f;
+typedef Translation<double,2> Translation2d;
+typedef Translation<float, 3> Translation3f;
+typedef Translation<double,3> Translation3d;
+//@}
+
+template<typename Scalar, int Dim>
+inline typename Translation<Scalar,Dim>::AffineTransformType
+Translation<Scalar,Dim>::operator* (const UniformScaling<Scalar>& other) const
+{
+ AffineTransformType res;
+ res.matrix().setZero();
+ res.linear().diagonal().fill(other.factor());
+ res.translation() = m_coeffs;
+ res(Dim,Dim) = Scalar(1);
+ return res;
+}
+
+template<typename Scalar, int Dim>
+template<typename OtherDerived>
+inline typename Translation<Scalar,Dim>::AffineTransformType
+Translation<Scalar,Dim>::operator* (const EigenBase<OtherDerived>& linear) const
+{
+ AffineTransformType res;
+ res.matrix().setZero();
+ res.linear() = linear.derived();
+ res.translation() = m_coeffs;
+ res.matrix().row(Dim).setZero();
+ res(Dim,Dim) = Scalar(1);
+ return res;
+}
+
+} // end namespace Eigen
+
+#endif // EIGEN_TRANSLATION_H
diff --git a/Eigen/src/Geometry/Umeyama.h b/Eigen/src/Geometry/Umeyama.h
new file mode 100644
index 000000000..ac0939cde
--- /dev/null
+++ b/Eigen/src/Geometry/Umeyama.h
@@ -0,0 +1,172 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra.
+//
+// Copyright (C) 2009 Hauke Heibel <hauke.heibel@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 EIGEN_UMEYAMA_H
+#define EIGEN_UMEYAMA_H
+
+// This file requires the user to include
+// * Eigen/Core
+// * Eigen/LU
+// * Eigen/SVD
+// * Eigen/Array
+
+namespace Eigen {
+
+#ifndef EIGEN_PARSED_BY_DOXYGEN
+
+// These helpers are required since it allows to use mixed types as parameters
+// for the Umeyama. The problem with mixed parameters is that the return type
+// cannot trivially be deduced when float and double types are mixed.
+namespace internal {
+
+// Compile time return type deduction for different MatrixBase types.
+// Different means here different alignment and parameters but the same underlying
+// real scalar type.
+template<typename MatrixType, typename OtherMatrixType>
+struct umeyama_transform_matrix_type
+{
+ enum {
+ MinRowsAtCompileTime = EIGEN_SIZE_MIN_PREFER_DYNAMIC(MatrixType::RowsAtCompileTime, OtherMatrixType::RowsAtCompileTime),
+
+ // When possible we want to choose some small fixed size value since the result
+ // is likely to fit on the stack. So here, EIGEN_SIZE_MIN_PREFER_DYNAMIC is not what we want.
+ HomogeneousDimension = int(MinRowsAtCompileTime) == Dynamic ? Dynamic : int(MinRowsAtCompileTime)+1
+ };
+
+ typedef Matrix<typename traits<MatrixType>::Scalar,
+ HomogeneousDimension,
+ HomogeneousDimension,
+ AutoAlign | (traits<MatrixType>::Flags & RowMajorBit ? RowMajor : ColMajor),
+ HomogeneousDimension,
+ HomogeneousDimension
+ > type;
+};
+
+}
+
+#endif
+
+/**
+* \geometry_module \ingroup Geometry_Module
+*
+* \brief Returns the transformation between two point sets.
+*
+* The algorithm is based on:
+* "Least-squares estimation of transformation parameters between two point patterns",
+* Shinji Umeyama, PAMI 1991, DOI: 10.1109/34.88573
+*
+* It estimates parameters \f$ c, \mathbf{R}, \f$ and \f$ \mathbf{t} \f$ such that
+* \f{align*}
+* \frac{1}{n} \sum_{i=1}^n \vert\vert y_i - (c\mathbf{R}x_i + \mathbf{t}) \vert\vert_2^2
+* \f}
+* is minimized.
+*
+* The algorithm is based on the analysis of the covariance matrix
+* \f$ \Sigma_{\mathbf{x}\mathbf{y}} \in \mathbb{R}^{d \times d} \f$
+* of the input point sets \f$ \mathbf{x} \f$ and \f$ \mathbf{y} \f$ where
+* \f$d\f$ is corresponding to the dimension (which is typically small).
+* The analysis is involving the SVD having a complexity of \f$O(d^3)\f$
+* though the actual computational effort lies in the covariance
+* matrix computation which has an asymptotic lower bound of \f$O(dm)\f$ when
+* the input point sets have dimension \f$d \times m\f$.
+*
+* Currently the method is working only for floating point matrices.
+*
+* \todo Should the return type of umeyama() become a Transform?
+*
+* \param src Source points \f$ \mathbf{x} = \left( x_1, \hdots, x_n \right) \f$.
+* \param dst Destination points \f$ \mathbf{y} = \left( y_1, \hdots, y_n \right) \f$.
+* \param with_scaling Sets \f$ c=1 \f$ when <code>false</code> is passed.
+* \return The homogeneous transformation
+* \f{align*}
+* T = \begin{bmatrix} c\mathbf{R} & \mathbf{t} \\ \mathbf{0} & 1 \end{bmatrix}
+* \f}
+* minimizing the resudiual above. This transformation is always returned as an
+* Eigen::Matrix.
+*/
+template <typename Derived, typename OtherDerived>
+typename internal::umeyama_transform_matrix_type<Derived, OtherDerived>::type
+umeyama(const MatrixBase<Derived>& src, const MatrixBase<OtherDerived>& dst, bool with_scaling = true)
+{
+ typedef typename internal::umeyama_transform_matrix_type<Derived, OtherDerived>::type TransformationMatrixType;
+ typedef typename internal::traits<TransformationMatrixType>::Scalar Scalar;
+ typedef typename NumTraits<Scalar>::Real RealScalar;
+ typedef typename Derived::Index Index;
+
+ EIGEN_STATIC_ASSERT(!NumTraits<Scalar>::IsComplex, NUMERIC_TYPE_MUST_BE_REAL)
+ EIGEN_STATIC_ASSERT((internal::is_same<Scalar, typename internal::traits<OtherDerived>::Scalar>::value),
+ YOU_MIXED_DIFFERENT_NUMERIC_TYPES__YOU_NEED_TO_USE_THE_CAST_METHOD_OF_MATRIXBASE_TO_CAST_NUMERIC_TYPES_EXPLICITLY)
+
+ enum { Dimension = EIGEN_SIZE_MIN_PREFER_DYNAMIC(Derived::RowsAtCompileTime, OtherDerived::RowsAtCompileTime) };
+
+ typedef Matrix<Scalar, Dimension, 1> VectorType;
+ typedef Matrix<Scalar, Dimension, Dimension> MatrixType;
+ typedef typename internal::plain_matrix_type_row_major<Derived>::type RowMajorMatrixType;
+
+ const Index m = src.rows(); // dimension
+ const Index n = src.cols(); // number of measurements
+
+ // required for demeaning ...
+ const RealScalar one_over_n = 1 / static_cast<RealScalar>(n);
+
+ // computation of mean
+ const VectorType src_mean = src.rowwise().sum() * one_over_n;
+ const VectorType dst_mean = dst.rowwise().sum() * one_over_n;
+
+ // demeaning of src and dst points
+ const RowMajorMatrixType src_demean = src.colwise() - src_mean;
+ const RowMajorMatrixType dst_demean = dst.colwise() - dst_mean;
+
+ // Eq. (36)-(37)
+ const Scalar src_var = src_demean.rowwise().squaredNorm().sum() * one_over_n;
+
+ // Eq. (38)
+ const MatrixType sigma = one_over_n * dst_demean * src_demean.transpose();
+
+ JacobiSVD<MatrixType> svd(sigma, ComputeFullU | ComputeFullV);
+
+ // Initialize the resulting transformation with an identity matrix...
+ TransformationMatrixType Rt = TransformationMatrixType::Identity(m+1,m+1);
+
+ // Eq. (39)
+ VectorType S = VectorType::Ones(m);
+ if (sigma.determinant()<0) S(m-1) = -1;
+
+ // Eq. (40) and (43)
+ const VectorType& d = svd.singularValues();
+ Index rank = 0; for (Index i=0; i<m; ++i) if (!internal::isMuchSmallerThan(d.coeff(i),d.coeff(0))) ++rank;
+ if (rank == m-1) {
+ if ( svd.matrixU().determinant() * svd.matrixV().determinant() > 0 ) {
+ Rt.block(0,0,m,m).noalias() = svd.matrixU()*svd.matrixV().transpose();
+ } else {
+ const Scalar s = S(m-1); S(m-1) = -1;
+ Rt.block(0,0,m,m).noalias() = svd.matrixU() * S.asDiagonal() * svd.matrixV().transpose();
+ S(m-1) = s;
+ }
+ } else {
+ Rt.block(0,0,m,m).noalias() = svd.matrixU() * S.asDiagonal() * svd.matrixV().transpose();
+ }
+
+ // Eq. (42)
+ const Scalar c = 1/src_var * svd.singularValues().dot(S);
+
+ // Eq. (41)
+ // Note that we first assign dst_mean to the destination so that there no need
+ // for a temporary.
+ Rt.col(m).head(m) = dst_mean;
+ Rt.col(m).head(m).noalias() -= c*Rt.topLeftCorner(m,m)*src_mean;
+
+ if (with_scaling) Rt.block(0,0,m,m) *= c;
+
+ return Rt;
+}
+
+} // end namespace Eigen
+
+#endif // EIGEN_UMEYAMA_H
diff --git a/Eigen/src/Geometry/arch/CMakeLists.txt b/Eigen/src/Geometry/arch/CMakeLists.txt
new file mode 100644
index 000000000..1267a79c7
--- /dev/null
+++ b/Eigen/src/Geometry/arch/CMakeLists.txt
@@ -0,0 +1,6 @@
+FILE(GLOB Eigen_Geometry_arch_SRCS "*.h")
+
+INSTALL(FILES
+ ${Eigen_Geometry_arch_SRCS}
+ DESTINATION ${INCLUDE_INSTALL_DIR}/Eigen/src/Geometry/arch COMPONENT Devel
+ )
diff --git a/Eigen/src/Geometry/arch/Geometry_SSE.h b/Eigen/src/Geometry/arch/Geometry_SSE.h
new file mode 100644
index 000000000..3d8284f2d
--- /dev/null
+++ b/Eigen/src/Geometry/arch/Geometry_SSE.h
@@ -0,0 +1,115 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra.
+//
+// Copyright (C) 2009 Rohit Garg <rpg.314@gmail.com>
+// Copyright (C) 2009-2010 Gael Guennebaud <gael.guennebaud@inria.fr>
+//
+// This Source Code Form is subject to the terms of the Mozilla
+// Public License v. 2.0. If a copy of the MPL was not distributed
+// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+#ifndef EIGEN_GEOMETRY_SSE_H
+#define EIGEN_GEOMETRY_SSE_H
+
+namespace Eigen {
+
+namespace internal {
+
+template<class Derived, class OtherDerived>
+struct quat_product<Architecture::SSE, Derived, OtherDerived, float, Aligned>
+{
+ static inline Quaternion<float> run(const QuaternionBase<Derived>& _a, const QuaternionBase<OtherDerived>& _b)
+ {
+ const __m128 mask = _mm_castsi128_ps(_mm_setr_epi32(0,0,0,0x80000000));
+ Quaternion<float> res;
+ __m128 a = _a.coeffs().template packet<Aligned>(0);
+ __m128 b = _b.coeffs().template packet<Aligned>(0);
+ __m128 flip1 = _mm_xor_ps(_mm_mul_ps(vec4f_swizzle1(a,1,2,0,2),
+ vec4f_swizzle1(b,2,0,1,2)),mask);
+ __m128 flip2 = _mm_xor_ps(_mm_mul_ps(vec4f_swizzle1(a,3,3,3,1),
+ vec4f_swizzle1(b,0,1,2,1)),mask);
+ pstore(&res.x(),
+ _mm_add_ps(_mm_sub_ps(_mm_mul_ps(a,vec4f_swizzle1(b,3,3,3,3)),
+ _mm_mul_ps(vec4f_swizzle1(a,2,0,1,0),
+ vec4f_swizzle1(b,1,2,0,0))),
+ _mm_add_ps(flip1,flip2)));
+ return res;
+ }
+};
+
+template<typename VectorLhs,typename VectorRhs>
+struct cross3_impl<Architecture::SSE,VectorLhs,VectorRhs,float,true>
+{
+ static inline typename plain_matrix_type<VectorLhs>::type
+ run(const VectorLhs& lhs, const VectorRhs& rhs)
+ {
+ __m128 a = lhs.template packet<VectorLhs::Flags&AlignedBit ? Aligned : Unaligned>(0);
+ __m128 b = rhs.template packet<VectorRhs::Flags&AlignedBit ? Aligned : Unaligned>(0);
+ __m128 mul1=_mm_mul_ps(vec4f_swizzle1(a,1,2,0,3),vec4f_swizzle1(b,2,0,1,3));
+ __m128 mul2=_mm_mul_ps(vec4f_swizzle1(a,2,0,1,3),vec4f_swizzle1(b,1,2,0,3));
+ typename plain_matrix_type<VectorLhs>::type res;
+ pstore(&res.x(),_mm_sub_ps(mul1,mul2));
+ return res;
+ }
+};
+
+
+
+
+template<class Derived, class OtherDerived>
+struct quat_product<Architecture::SSE, Derived, OtherDerived, double, Aligned>
+{
+ static inline Quaternion<double> run(const QuaternionBase<Derived>& _a, const QuaternionBase<OtherDerived>& _b)
+ {
+ const Packet2d mask = _mm_castsi128_pd(_mm_set_epi32(0x0,0x0,0x80000000,0x0));
+
+ Quaternion<double> res;
+
+ const double* a = _a.coeffs().data();
+ Packet2d b_xy = _b.coeffs().template packet<Aligned>(0);
+ Packet2d b_zw = _b.coeffs().template packet<Aligned>(2);
+ Packet2d a_xx = pset1<Packet2d>(a[0]);
+ Packet2d a_yy = pset1<Packet2d>(a[1]);
+ Packet2d a_zz = pset1<Packet2d>(a[2]);
+ Packet2d a_ww = pset1<Packet2d>(a[3]);
+
+ // two temporaries:
+ Packet2d t1, t2;
+
+ /*
+ * t1 = ww*xy + yy*zw
+ * t2 = zz*xy - xx*zw
+ * res.xy = t1 +/- swap(t2)
+ */
+ t1 = padd(pmul(a_ww, b_xy), pmul(a_yy, b_zw));
+ t2 = psub(pmul(a_zz, b_xy), pmul(a_xx, b_zw));
+#ifdef EIGEN_VECTORIZE_SSE3
+ EIGEN_UNUSED_VARIABLE(mask)
+ pstore(&res.x(), _mm_addsub_pd(t1, preverse(t2)));
+#else
+ pstore(&res.x(), padd(t1, pxor(mask,preverse(t2))));
+#endif
+
+ /*
+ * t1 = ww*zw - yy*xy
+ * t2 = zz*zw + xx*xy
+ * res.zw = t1 -/+ swap(t2) = swap( swap(t1) +/- t2)
+ */
+ t1 = psub(pmul(a_ww, b_zw), pmul(a_yy, b_xy));
+ t2 = padd(pmul(a_zz, b_zw), pmul(a_xx, b_xy));
+#ifdef EIGEN_VECTORIZE_SSE3
+ EIGEN_UNUSED_VARIABLE(mask)
+ pstore(&res.z(), preverse(_mm_addsub_pd(preverse(t1), t2)));
+#else
+ pstore(&res.z(), psub(t1, pxor(mask,preverse(t2))));
+#endif
+
+ return res;
+}
+};
+
+} // end namespace internal
+
+} // end namespace Eigen
+
+#endif // EIGEN_GEOMETRY_SSE_H
diff --git a/Eigen/src/Householder/BlockHouseholder.h b/Eigen/src/Householder/BlockHouseholder.h
new file mode 100644
index 000000000..1991c6527
--- /dev/null
+++ b/Eigen/src/Householder/BlockHouseholder.h
@@ -0,0 +1,68 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra.
+//
+// Copyright (C) 2010 Vincent Lejeune
+// Copyright (C) 2010 Gael Guennebaud <gael.guennebaud@inria.fr>
+//
+// This Source Code Form is subject to the terms of the Mozilla
+// Public License v. 2.0. If 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<typename TriangularFactorType,typename VectorsType,typename CoeffsType>
+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<Upper>()
+ * triFactor.col(i).head(i);
+ triFactor(i,i) = hCoeffs(i);
+ }
+}
+
+/** \internal */
+template<typename MatrixType,typename VectorsType,typename CoeffsType>
+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<typename MatrixType::Scalar, TFactorSize, TFactorSize> T(nbVecs,nbVecs);
+ make_block_householder_triangular_factor(T, vectors, hCoeffs);
+
+ const TriangularView<const VectorsType, UnitLower>& V(vectors);
+
+ // A -= V T V^* A
+ Matrix<typename MatrixType::Scalar,VectorsType::ColsAtCompileTime,MatrixType::ColsAtCompileTime,0,
+ VectorsType::MaxColsAtCompileTime,MatrixType::MaxColsAtCompileTime> tmp = V.adjoint() * mat;
+ // FIXME add .noalias() once the triangular product can work inplace
+ tmp = T.template triangularView<Upper>().adjoint() * tmp;
+ mat.noalias() -= V * tmp;
+}
+
+} // end namespace internal
+
+} // end namespace Eigen
+
+#endif // EIGEN_BLOCK_HOUSEHOLDER_H
diff --git a/Eigen/src/Householder/CMakeLists.txt b/Eigen/src/Householder/CMakeLists.txt
new file mode 100644
index 000000000..ce4937db0
--- /dev/null
+++ b/Eigen/src/Householder/CMakeLists.txt
@@ -0,0 +1,6 @@
+FILE(GLOB Eigen_Householder_SRCS "*.h")
+
+INSTALL(FILES
+ ${Eigen_Householder_SRCS}
+ DESTINATION ${INCLUDE_INSTALL_DIR}/Eigen/src/Householder COMPONENT Devel
+ )
diff --git a/Eigen/src/Householder/Householder.h b/Eigen/src/Householder/Householder.h
new file mode 100644
index 000000000..3f64b7dde
--- /dev/null
+++ b/Eigen/src/Householder/Householder.h
@@ -0,0 +1,168 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra.
+//
+// Copyright (C) 2010 Benoit Jacob <jacob.benoit.1@gmail.com>
+// Copyright (C) 2009 Gael Guennebaud <gael.guennebaud@inria.fr>
+//
+// This Source Code Form is subject to the terms of the Mozilla
+// Public License v. 2.0. If a copy of the MPL was not distributed
+// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+#ifndef EIGEN_HOUSEHOLDER_H
+#define EIGEN_HOUSEHOLDER_H
+
+namespace Eigen {
+
+namespace internal {
+template<int n> struct decrement_size
+{
+ enum {
+ ret = n==Dynamic ? n : n-1
+ };
+};
+}
+
+/** Computes the elementary reflector H such that:
+ * \f$ H *this = [ beta 0 ... 0]^T \f$
+ * where the transformation H is:
+ * \f$ H = I - tau v v^*\f$
+ * and the vector v is:
+ * \f$ v^T = [1 essential^T] \f$
+ *
+ * The essential part of the vector \c v is stored in *this.
+ *
+ * On output:
+ * \param tau the scaling factor of the Householder transformation
+ * \param beta the result of H * \c *this
+ *
+ * \sa MatrixBase::makeHouseholder(), MatrixBase::applyHouseholderOnTheLeft(),
+ * MatrixBase::applyHouseholderOnTheRight()
+ */
+template<typename Derived>
+void MatrixBase<Derived>::makeHouseholderInPlace(Scalar& tau, RealScalar& beta)
+{
+ VectorBlock<Derived, internal::decrement_size<Base::SizeAtCompileTime>::ret> essentialPart(derived(), 1, size()-1);
+ makeHouseholder(essentialPart, tau, beta);
+}
+
+/** Computes the elementary reflector H such that:
+ * \f$ H *this = [ beta 0 ... 0]^T \f$
+ * where the transformation H is:
+ * \f$ H = I - tau v v^*\f$
+ * and the vector v is:
+ * \f$ v^T = [1 essential^T] \f$
+ *
+ * On output:
+ * \param essential the essential part of the vector \c v
+ * \param tau the scaling factor of the Householder transformation
+ * \param beta the result of H * \c *this
+ *
+ * \sa MatrixBase::makeHouseholderInPlace(), MatrixBase::applyHouseholderOnTheLeft(),
+ * MatrixBase::applyHouseholderOnTheRight()
+ */
+template<typename Derived>
+template<typename EssentialPart>
+void MatrixBase<Derived>::makeHouseholder(
+ EssentialPart& essential,
+ Scalar& tau,
+ RealScalar& beta) const
+{
+ EIGEN_STATIC_ASSERT_VECTOR_ONLY(EssentialPart)
+ VectorBlock<const Derived, EssentialPart::SizeAtCompileTime> tail(derived(), 1, size()-1);
+
+ RealScalar tailSqNorm = size()==1 ? RealScalar(0) : tail.squaredNorm();
+ Scalar c0 = coeff(0);
+
+ if(tailSqNorm == RealScalar(0) && internal::imag(c0)==RealScalar(0))
+ {
+ tau = RealScalar(0);
+ beta = internal::real(c0);
+ essential.setZero();
+ }
+ else
+ {
+ beta = internal::sqrt(internal::abs2(c0) + tailSqNorm);
+ if (internal::real(c0)>=RealScalar(0))
+ beta = -beta;
+ essential = tail / (c0 - beta);
+ tau = internal::conj((beta - c0) / beta);
+ }
+}
+
+/** Apply the elementary reflector H given by
+ * \f$ H = I - tau v v^*\f$
+ * with
+ * \f$ v^T = [1 essential^T] \f$
+ * from the left to a vector or matrix.
+ *
+ * On input:
+ * \param essential the essential part of the vector \c v
+ * \param tau the scaling factor of the Householder transformation
+ * \param workspace a pointer to working space with at least
+ * this->cols() * essential.size() entries
+ *
+ * \sa MatrixBase::makeHouseholder(), MatrixBase::makeHouseholderInPlace(),
+ * MatrixBase::applyHouseholderOnTheRight()
+ */
+template<typename Derived>
+template<typename EssentialPart>
+void MatrixBase<Derived>::applyHouseholderOnTheLeft(
+ const EssentialPart& essential,
+ const Scalar& tau,
+ Scalar* workspace)
+{
+ if(rows() == 1)
+ {
+ *this *= Scalar(1)-tau;
+ }
+ else
+ {
+ Map<typename internal::plain_row_type<PlainObject>::type> tmp(workspace,cols());
+ Block<Derived, EssentialPart::SizeAtCompileTime, Derived::ColsAtCompileTime> bottom(derived(), 1, 0, rows()-1, cols());
+ tmp.noalias() = essential.adjoint() * bottom;
+ tmp += this->row(0);
+ this->row(0) -= tau * tmp;
+ bottom.noalias() -= tau * essential * tmp;
+ }
+}
+
+/** Apply the elementary reflector H given by
+ * \f$ H = I - tau v v^*\f$
+ * with
+ * \f$ v^T = [1 essential^T] \f$
+ * from the right to a vector or matrix.
+ *
+ * On input:
+ * \param essential the essential part of the vector \c v
+ * \param tau the scaling factor of the Householder transformation
+ * \param workspace a pointer to working space with at least
+ * this->cols() * essential.size() entries
+ *
+ * \sa MatrixBase::makeHouseholder(), MatrixBase::makeHouseholderInPlace(),
+ * MatrixBase::applyHouseholderOnTheLeft()
+ */
+template<typename Derived>
+template<typename EssentialPart>
+void MatrixBase<Derived>::applyHouseholderOnTheRight(
+ const EssentialPart& essential,
+ const Scalar& tau,
+ Scalar* workspace)
+{
+ if(cols() == 1)
+ {
+ *this *= Scalar(1)-tau;
+ }
+ else
+ {
+ Map<typename internal::plain_col_type<PlainObject>::type> tmp(workspace,rows());
+ Block<Derived, Derived::RowsAtCompileTime, EssentialPart::SizeAtCompileTime> right(derived(), 0, 1, rows(), cols()-1);
+ tmp.noalias() = right * essential.conjugate();
+ tmp += this->col(0);
+ this->col(0) -= tau * tmp;
+ right.noalias() -= tau * tmp * essential.transpose();
+ }
+}
+
+} // end namespace Eigen
+
+#endif // EIGEN_HOUSEHOLDER_H
diff --git a/Eigen/src/Householder/HouseholderSequence.h b/Eigen/src/Householder/HouseholderSequence.h
new file mode 100644
index 000000000..1e71e16a7
--- /dev/null
+++ b/Eigen/src/Householder/HouseholderSequence.h
@@ -0,0 +1,441 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra.
+//
+// Copyright (C) 2009 Gael Guennebaud <gael.guennebaud@inria.fr>
+// Copyright (C) 2010 Benoit Jacob <jacob.benoit.1@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 EIGEN_HOUSEHOLDER_SEQUENCE_H
+#define EIGEN_HOUSEHOLDER_SEQUENCE_H
+
+namespace Eigen {
+
+/** \ingroup Householder_Module
+ * \householder_module
+ * \class HouseholderSequence
+ * \brief Sequence of Householder reflections acting on subspaces with decreasing size
+ * \tparam VectorsType type of matrix containing the Householder vectors
+ * \tparam CoeffsType type of vector containing the Householder coefficients
+ * \tparam Side either OnTheLeft (the default) or OnTheRight
+ *
+ * This class represents a product sequence of Householder reflections where the first Householder reflection
+ * acts on the whole space, the second Householder reflection leaves the one-dimensional subspace spanned by
+ * the first unit vector invariant, the third Householder reflection leaves the two-dimensional subspace
+ * spanned by the first two unit vectors invariant, and so on up to the last reflection which leaves all but
+ * one dimensions invariant and acts only on the last dimension. Such sequences of Householder reflections
+ * are used in several algorithms to zero out certain parts of a matrix. Indeed, the methods
+ * HessenbergDecomposition::matrixQ(), Tridiagonalization::matrixQ(), HouseholderQR::householderQ(),
+ * and ColPivHouseholderQR::householderQ() all return a %HouseholderSequence.
+ *
+ * More precisely, the class %HouseholderSequence represents an \f$ n \times n \f$ matrix \f$ H \f$ of the
+ * form \f$ H = \prod_{i=0}^{n-1} H_i \f$ where the i-th Householder reflection is \f$ H_i = I - h_i v_i
+ * v_i^* \f$. The i-th Householder coefficient \f$ h_i \f$ is a scalar and the i-th Householder vector \f$
+ * v_i \f$ is a vector of the form
+ * \f[
+ * v_i = [\underbrace{0, \ldots, 0}_{i-1\mbox{ zeros}}, 1, \underbrace{*, \ldots,*}_{n-i\mbox{ arbitrary entries}} ].
+ * \f]
+ * The last \f$ n-i \f$ entries of \f$ v_i \f$ are called the essential part of the Householder vector.
+ *
+ * Typical usages are listed below, where H is a HouseholderSequence:
+ * \code
+ * A.applyOnTheRight(H); // A = A * H
+ * A.applyOnTheLeft(H); // A = H * A
+ * A.applyOnTheRight(H.adjoint()); // A = A * H^*
+ * A.applyOnTheLeft(H.adjoint()); // A = H^* * A
+ * MatrixXd Q = H; // conversion to a dense matrix
+ * \endcode
+ * In addition to the adjoint, you can also apply the inverse (=adjoint), the transpose, and the conjugate operators.
+ *
+ * See the documentation for HouseholderSequence(const VectorsType&, const CoeffsType&) for an example.
+ *
+ * \sa MatrixBase::applyOnTheLeft(), MatrixBase::applyOnTheRight()
+ */
+
+namespace internal {
+
+template<typename VectorsType, typename CoeffsType, int Side>
+struct traits<HouseholderSequence<VectorsType,CoeffsType,Side> >
+{
+ typedef typename VectorsType::Scalar Scalar;
+ typedef typename VectorsType::Index Index;
+ typedef typename VectorsType::StorageKind StorageKind;
+ enum {
+ RowsAtCompileTime = Side==OnTheLeft ? traits<VectorsType>::RowsAtCompileTime
+ : traits<VectorsType>::ColsAtCompileTime,
+ ColsAtCompileTime = RowsAtCompileTime,
+ MaxRowsAtCompileTime = Side==OnTheLeft ? traits<VectorsType>::MaxRowsAtCompileTime
+ : traits<VectorsType>::MaxColsAtCompileTime,
+ MaxColsAtCompileTime = MaxRowsAtCompileTime,
+ Flags = 0
+ };
+};
+
+template<typename VectorsType, typename CoeffsType, int Side>
+struct hseq_side_dependent_impl
+{
+ typedef Block<const VectorsType, Dynamic, 1> EssentialVectorType;
+ typedef HouseholderSequence<VectorsType, CoeffsType, OnTheLeft> HouseholderSequenceType;
+ typedef typename VectorsType::Index Index;
+ static inline const EssentialVectorType essentialVector(const HouseholderSequenceType& h, Index k)
+ {
+ Index start = k+1+h.m_shift;
+ return Block<const VectorsType,Dynamic,1>(h.m_vectors, start, k, h.rows()-start, 1);
+ }
+};
+
+template<typename VectorsType, typename CoeffsType>
+struct hseq_side_dependent_impl<VectorsType, CoeffsType, OnTheRight>
+{
+ typedef Transpose<Block<const VectorsType, 1, Dynamic> > EssentialVectorType;
+ typedef HouseholderSequence<VectorsType, CoeffsType, OnTheRight> HouseholderSequenceType;
+ typedef typename VectorsType::Index Index;
+ static inline const EssentialVectorType essentialVector(const HouseholderSequenceType& h, Index k)
+ {
+ Index start = k+1+h.m_shift;
+ return Block<const VectorsType,1,Dynamic>(h.m_vectors, k, start, 1, h.rows()-start).transpose();
+ }
+};
+
+template<typename OtherScalarType, typename MatrixType> struct matrix_type_times_scalar_type
+{
+ typedef typename scalar_product_traits<OtherScalarType, typename MatrixType::Scalar>::ReturnType
+ ResultScalar;
+ typedef Matrix<ResultScalar, MatrixType::RowsAtCompileTime, MatrixType::ColsAtCompileTime,
+ 0, MatrixType::MaxRowsAtCompileTime, MatrixType::MaxColsAtCompileTime> Type;
+};
+
+} // end namespace internal
+
+template<typename VectorsType, typename CoeffsType, int Side> class HouseholderSequence
+ : public EigenBase<HouseholderSequence<VectorsType,CoeffsType,Side> >
+{
+ enum {
+ RowsAtCompileTime = internal::traits<HouseholderSequence>::RowsAtCompileTime,
+ ColsAtCompileTime = internal::traits<HouseholderSequence>::ColsAtCompileTime,
+ MaxRowsAtCompileTime = internal::traits<HouseholderSequence>::MaxRowsAtCompileTime,
+ MaxColsAtCompileTime = internal::traits<HouseholderSequence>::MaxColsAtCompileTime
+ };
+ typedef typename internal::traits<HouseholderSequence>::Scalar Scalar;
+ typedef typename VectorsType::Index Index;
+
+ typedef typename internal::hseq_side_dependent_impl<VectorsType,CoeffsType,Side>::EssentialVectorType
+ EssentialVectorType;
+
+ public:
+
+ typedef HouseholderSequence<
+ VectorsType,
+ typename internal::conditional<NumTraits<Scalar>::IsComplex,
+ typename internal::remove_all<typename CoeffsType::ConjugateReturnType>::type,
+ CoeffsType>::type,
+ Side
+ > ConjugateReturnType;
+
+ /** \brief Constructor.
+ * \param[in] v %Matrix containing the essential parts of the Householder vectors
+ * \param[in] h Vector containing the Householder coefficients
+ *
+ * Constructs the Householder sequence with coefficients given by \p h and vectors given by \p v. The
+ * i-th Householder coefficient \f$ h_i \f$ is given by \p h(i) and the essential part of the i-th
+ * Householder vector \f$ v_i \f$ is given by \p v(k,i) with \p k > \p i (the subdiagonal part of the
+ * i-th column). If \p v has fewer columns than rows, then the Householder sequence contains as many
+ * Householder reflections as there are columns.
+ *
+ * \note The %HouseholderSequence object stores \p v and \p h by reference.
+ *
+ * Example: \include HouseholderSequence_HouseholderSequence.cpp
+ * Output: \verbinclude HouseholderSequence_HouseholderSequence.out
+ *
+ * \sa setLength(), setShift()
+ */
+ HouseholderSequence(const VectorsType& v, const CoeffsType& h)
+ : m_vectors(v), m_coeffs(h), m_trans(false), m_length(v.diagonalSize()),
+ m_shift(0)
+ {
+ }
+
+ /** \brief Copy constructor. */
+ HouseholderSequence(const HouseholderSequence& other)
+ : m_vectors(other.m_vectors),
+ m_coeffs(other.m_coeffs),
+ m_trans(other.m_trans),
+ m_length(other.m_length),
+ m_shift(other.m_shift)
+ {
+ }
+
+ /** \brief Number of rows of transformation viewed as a matrix.
+ * \returns Number of rows
+ * \details This equals the dimension of the space that the transformation acts on.
+ */
+ Index rows() const { return Side==OnTheLeft ? m_vectors.rows() : m_vectors.cols(); }
+
+ /** \brief Number of columns of transformation viewed as a matrix.
+ * \returns Number of columns
+ * \details This equals the dimension of the space that the transformation acts on.
+ */
+ Index cols() const { return rows(); }
+
+ /** \brief Essential part of a Householder vector.
+ * \param[in] k Index of Householder reflection
+ * \returns Vector containing non-trivial entries of k-th Householder vector
+ *
+ * This function returns the essential part of the Householder vector \f$ v_i \f$. This is a vector of
+ * length \f$ n-i \f$ containing the last \f$ n-i \f$ entries of the vector
+ * \f[
+ * v_i = [\underbrace{0, \ldots, 0}_{i-1\mbox{ zeros}}, 1, \underbrace{*, \ldots,*}_{n-i\mbox{ arbitrary entries}} ].
+ * \f]
+ * The index \f$ i \f$ equals \p k + shift(), corresponding to the k-th column of the matrix \p v
+ * passed to the constructor.
+ *
+ * \sa setShift(), shift()
+ */
+ const EssentialVectorType essentialVector(Index k) const
+ {
+ eigen_assert(k >= 0 && k < m_length);
+ return internal::hseq_side_dependent_impl<VectorsType,CoeffsType,Side>::essentialVector(*this, k);
+ }
+
+ /** \brief %Transpose of the Householder sequence. */
+ HouseholderSequence transpose() const
+ {
+ return HouseholderSequence(*this).setTrans(!m_trans);
+ }
+
+ /** \brief Complex conjugate of the Householder sequence. */
+ ConjugateReturnType conjugate() const
+ {
+ return ConjugateReturnType(m_vectors, m_coeffs.conjugate())
+ .setTrans(m_trans)
+ .setLength(m_length)
+ .setShift(m_shift);
+ }
+
+ /** \brief Adjoint (conjugate transpose) of the Householder sequence. */
+ ConjugateReturnType adjoint() const
+ {
+ return conjugate().setTrans(!m_trans);
+ }
+
+ /** \brief Inverse of the Householder sequence (equals the adjoint). */
+ ConjugateReturnType inverse() const { return adjoint(); }
+
+ /** \internal */
+ template<typename DestType> inline void evalTo(DestType& dst) const
+ {
+ Matrix<Scalar, DestType::RowsAtCompileTime, 1,
+ AutoAlign|ColMajor, DestType::MaxRowsAtCompileTime, 1> workspace(rows());
+ evalTo(dst, workspace);
+ }
+
+ /** \internal */
+ template<typename Dest, typename Workspace>
+ void evalTo(Dest& dst, Workspace& workspace) const
+ {
+ workspace.resize(rows());
+ Index vecs = m_length;
+ if( internal::is_same<typename internal::remove_all<VectorsType>::type,Dest>::value
+ && internal::extract_data(dst) == internal::extract_data(m_vectors))
+ {
+ // in-place
+ dst.diagonal().setOnes();
+ dst.template triangularView<StrictlyUpper>().setZero();
+ for(Index k = vecs-1; k >= 0; --k)
+ {
+ Index cornerSize = rows() - k - m_shift;
+ if(m_trans)
+ dst.bottomRightCorner(cornerSize, cornerSize)
+ .applyHouseholderOnTheRight(essentialVector(k), m_coeffs.coeff(k), workspace.data());
+ else
+ dst.bottomRightCorner(cornerSize, cornerSize)
+ .applyHouseholderOnTheLeft(essentialVector(k), m_coeffs.coeff(k), workspace.data());
+
+ // clear the off diagonal vector
+ dst.col(k).tail(rows()-k-1).setZero();
+ }
+ // clear the remaining columns if needed
+ for(Index k = 0; k<cols()-vecs ; ++k)
+ dst.col(k).tail(rows()-k-1).setZero();
+ }
+ else
+ {
+ dst.setIdentity(rows(), rows());
+ for(Index k = vecs-1; k >= 0; --k)
+ {
+ Index cornerSize = rows() - k - m_shift;
+ if(m_trans)
+ dst.bottomRightCorner(cornerSize, cornerSize)
+ .applyHouseholderOnTheRight(essentialVector(k), m_coeffs.coeff(k), &workspace.coeffRef(0));
+ else
+ dst.bottomRightCorner(cornerSize, cornerSize)
+ .applyHouseholderOnTheLeft(essentialVector(k), m_coeffs.coeff(k), &workspace.coeffRef(0));
+ }
+ }
+ }
+
+ /** \internal */
+ template<typename Dest> inline void applyThisOnTheRight(Dest& dst) const
+ {
+ Matrix<Scalar,1,Dest::RowsAtCompileTime,RowMajor,1,Dest::MaxRowsAtCompileTime> workspace(dst.rows());
+ applyThisOnTheRight(dst, workspace);
+ }
+
+ /** \internal */
+ template<typename Dest, typename Workspace>
+ inline void applyThisOnTheRight(Dest& dst, Workspace& workspace) const
+ {
+ workspace.resize(dst.rows());
+ for(Index k = 0; k < m_length; ++k)
+ {
+ Index actual_k = m_trans ? m_length-k-1 : k;
+ dst.rightCols(rows()-m_shift-actual_k)
+ .applyHouseholderOnTheRight(essentialVector(actual_k), m_coeffs.coeff(actual_k), workspace.data());
+ }
+ }
+
+ /** \internal */
+ template<typename Dest> inline void applyThisOnTheLeft(Dest& dst) const
+ {
+ Matrix<Scalar,1,Dest::ColsAtCompileTime,RowMajor,1,Dest::MaxColsAtCompileTime> workspace(dst.cols());
+ applyThisOnTheLeft(dst, workspace);
+ }
+
+ /** \internal */
+ template<typename Dest, typename Workspace>
+ inline void applyThisOnTheLeft(Dest& dst, Workspace& workspace) const
+ {
+ workspace.resize(dst.cols());
+ for(Index k = 0; k < m_length; ++k)
+ {
+ Index actual_k = m_trans ? k : m_length-k-1;
+ dst.bottomRows(rows()-m_shift-actual_k)
+ .applyHouseholderOnTheLeft(essentialVector(actual_k), m_coeffs.coeff(actual_k), workspace.data());
+ }
+ }
+
+ /** \brief Computes the product of a Householder sequence with a matrix.
+ * \param[in] other %Matrix being multiplied.
+ * \returns Expression object representing the product.
+ *
+ * This function computes \f$ HM \f$ where \f$ H \f$ is the Householder sequence represented by \p *this
+ * and \f$ M \f$ is the matrix \p other.
+ */
+ template<typename OtherDerived>
+ typename internal::matrix_type_times_scalar_type<Scalar, OtherDerived>::Type operator*(const MatrixBase<OtherDerived>& other) const
+ {
+ typename internal::matrix_type_times_scalar_type<Scalar, OtherDerived>::Type
+ res(other.template cast<typename internal::matrix_type_times_scalar_type<Scalar,OtherDerived>::ResultScalar>());
+ applyThisOnTheLeft(res);
+ return res;
+ }
+
+ template<typename _VectorsType, typename _CoeffsType, int _Side> friend struct internal::hseq_side_dependent_impl;
+
+ /** \brief Sets the length of the Householder sequence.
+ * \param [in] length New value for the length.
+ *
+ * By default, the length \f$ n \f$ of the Householder sequence \f$ H = H_0 H_1 \ldots H_{n-1} \f$ is set
+ * to the number of columns of the matrix \p v passed to the constructor, or the number of rows if that
+ * is smaller. After this function is called, the length equals \p length.
+ *
+ * \sa length()
+ */
+ HouseholderSequence& setLength(Index length)
+ {
+ m_length = length;
+ return *this;
+ }
+
+ /** \brief Sets the shift of the Householder sequence.
+ * \param [in] shift New value for the shift.
+ *
+ * By default, a %HouseholderSequence object represents \f$ H = H_0 H_1 \ldots H_{n-1} \f$ and the i-th
+ * column of the matrix \p v passed to the constructor corresponds to the i-th Householder
+ * reflection. After this function is called, the object represents \f$ H = H_{\mathrm{shift}}
+ * H_{\mathrm{shift}+1} \ldots H_{n-1} \f$ and the i-th column of \p v corresponds to the (shift+i)-th
+ * Householder reflection.
+ *
+ * \sa shift()
+ */
+ HouseholderSequence& setShift(Index shift)
+ {
+ m_shift = shift;
+ return *this;
+ }
+
+ Index length() const { return m_length; } /**< \brief Returns the length of the Householder sequence. */
+ Index shift() const { return m_shift; } /**< \brief Returns the shift of the Householder sequence. */
+
+ /* Necessary for .adjoint() and .conjugate() */
+ template <typename VectorsType2, typename CoeffsType2, int Side2> friend class HouseholderSequence;
+
+ protected:
+
+ /** \brief Sets the transpose flag.
+ * \param [in] trans New value of the transpose flag.
+ *
+ * By default, the transpose flag is not set. If the transpose flag is set, then this object represents
+ * \f$ H^T = H_{n-1}^T \ldots H_1^T H_0^T \f$ instead of \f$ H = H_0 H_1 \ldots H_{n-1} \f$.
+ *
+ * \sa trans()
+ */
+ HouseholderSequence& setTrans(bool trans)
+ {
+ m_trans = trans;
+ return *this;
+ }
+
+ bool trans() const { return m_trans; } /**< \brief Returns the transpose flag. */
+
+ typename VectorsType::Nested m_vectors;
+ typename CoeffsType::Nested m_coeffs;
+ bool m_trans;
+ Index m_length;
+ Index m_shift;
+};
+
+/** \brief Computes the product of a matrix with a Householder sequence.
+ * \param[in] other %Matrix being multiplied.
+ * \param[in] h %HouseholderSequence being multiplied.
+ * \returns Expression object representing the product.
+ *
+ * This function computes \f$ MH \f$ where \f$ M \f$ is the matrix \p other and \f$ H \f$ is the
+ * Householder sequence represented by \p h.
+ */
+template<typename OtherDerived, typename VectorsType, typename CoeffsType, int Side>
+typename internal::matrix_type_times_scalar_type<typename VectorsType::Scalar,OtherDerived>::Type operator*(const MatrixBase<OtherDerived>& other, const HouseholderSequence<VectorsType,CoeffsType,Side>& h)
+{
+ typename internal::matrix_type_times_scalar_type<typename VectorsType::Scalar,OtherDerived>::Type
+ res(other.template cast<typename internal::matrix_type_times_scalar_type<typename VectorsType::Scalar,OtherDerived>::ResultScalar>());
+ h.applyThisOnTheRight(res);
+ return res;
+}
+
+/** \ingroup Householder_Module \householder_module
+ * \brief Convenience function for constructing a Householder sequence.
+ * \returns A HouseholderSequence constructed from the specified arguments.
+ */
+template<typename VectorsType, typename CoeffsType>
+HouseholderSequence<VectorsType,CoeffsType> householderSequence(const VectorsType& v, const CoeffsType& h)
+{
+ return HouseholderSequence<VectorsType,CoeffsType,OnTheLeft>(v, h);
+}
+
+/** \ingroup Householder_Module \householder_module
+ * \brief Convenience function for constructing a Householder sequence.
+ * \returns A HouseholderSequence constructed from the specified arguments.
+ * \details This function differs from householderSequence() in that the template argument \p OnTheSide of
+ * the constructed HouseholderSequence is set to OnTheRight, instead of the default OnTheLeft.
+ */
+template<typename VectorsType, typename CoeffsType>
+HouseholderSequence<VectorsType,CoeffsType,OnTheRight> rightHouseholderSequence(const VectorsType& v, const CoeffsType& h)
+{
+ return HouseholderSequence<VectorsType,CoeffsType,OnTheRight>(v, h);
+}
+
+} // end namespace Eigen
+
+#endif // EIGEN_HOUSEHOLDER_SEQUENCE_H
diff --git a/Eigen/src/IterativeLinearSolvers/BasicPreconditioners.h b/Eigen/src/IterativeLinearSolvers/BasicPreconditioners.h
new file mode 100644
index 000000000..73ca9bfde
--- /dev/null
+++ b/Eigen/src/IterativeLinearSolvers/BasicPreconditioners.h
@@ -0,0 +1,149 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra.
+//
+// Copyright (C) 2011 Gael Guennebaud <gael.guennebaud@inria.fr>
+//
+// This Source Code Form is subject to the terms of the Mozilla
+// Public License v. 2.0. If a copy of the MPL was not distributed
+// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+#ifndef EIGEN_BASIC_PRECONDITIONERS_H
+#define EIGEN_BASIC_PRECONDITIONERS_H
+
+namespace Eigen {
+
+/** \ingroup IterativeLinearSolvers_Module
+ * \brief A preconditioner based on the digonal entries
+ *
+ * This class allows to approximately solve for A.x = b problems assuming A is a diagonal matrix.
+ * In other words, this preconditioner neglects all off diagonal entries and, in Eigen's language, solves for:
+ * \code
+ * A.diagonal().asDiagonal() . x = b
+ * \endcode
+ *
+ * \tparam _Scalar the type of the scalar.
+ *
+ * This preconditioner is suitable for both selfadjoint and general problems.
+ * The diagonal entries are pre-inverted and stored into a dense vector.
+ *
+ * \note A variant that has yet to be implemented would attempt to preserve the norm of each column.
+ *
+ */
+template <typename _Scalar>
+class DiagonalPreconditioner
+{
+ typedef _Scalar Scalar;
+ typedef Matrix<Scalar,Dynamic,1> Vector;
+ typedef typename Vector::Index Index;
+
+ public:
+ // this typedef is only to export the scalar type and compile-time dimensions to solve_retval
+ typedef Matrix<Scalar,Dynamic,Dynamic> MatrixType;
+
+ DiagonalPreconditioner() : m_isInitialized(false) {}
+
+ template<typename MatType>
+ DiagonalPreconditioner(const MatType& mat) : m_invdiag(mat.cols())
+ {
+ compute(mat);
+ }
+
+ Index rows() const { return m_invdiag.size(); }
+ Index cols() const { return m_invdiag.size(); }
+
+ template<typename MatType>
+ DiagonalPreconditioner& analyzePattern(const MatType& )
+ {
+ return *this;
+ }
+
+ template<typename MatType>
+ DiagonalPreconditioner& factorize(const MatType& mat)
+ {
+ m_invdiag.resize(mat.cols());
+ for(int j=0; j<mat.outerSize(); ++j)
+ {
+ typename MatType::InnerIterator it(mat,j);
+ while(it && it.index()!=j) ++it;
+ if(it && it.index()==j)
+ m_invdiag(j) = Scalar(1)/it.value();
+ else
+ m_invdiag(j) = 0;
+ }
+ m_isInitialized = true;
+ return *this;
+ }
+
+ template<typename MatType>
+ DiagonalPreconditioner& compute(const MatType& mat)
+ {
+ return factorize(mat);
+ }
+
+ template<typename Rhs, typename Dest>
+ void _solve(const Rhs& b, Dest& x) const
+ {
+ x = m_invdiag.array() * b.array() ;
+ }
+
+ template<typename Rhs> inline const internal::solve_retval<DiagonalPreconditioner, Rhs>
+ solve(const MatrixBase<Rhs>& b) const
+ {
+ eigen_assert(m_isInitialized && "DiagonalPreconditioner is not initialized.");
+ eigen_assert(m_invdiag.size()==b.rows()
+ && "DiagonalPreconditioner::solve(): invalid number of rows of the right hand side matrix b");
+ return internal::solve_retval<DiagonalPreconditioner, Rhs>(*this, b.derived());
+ }
+
+ protected:
+ Vector m_invdiag;
+ bool m_isInitialized;
+};
+
+namespace internal {
+
+template<typename _MatrixType, typename Rhs>
+struct solve_retval<DiagonalPreconditioner<_MatrixType>, Rhs>
+ : solve_retval_base<DiagonalPreconditioner<_MatrixType>, Rhs>
+{
+ typedef DiagonalPreconditioner<_MatrixType> Dec;
+ EIGEN_MAKE_SOLVE_HELPERS(Dec,Rhs)
+
+ template<typename Dest> void evalTo(Dest& dst) const
+ {
+ dec()._solve(rhs(),dst);
+ }
+};
+
+}
+
+/** \ingroup IterativeLinearSolvers_Module
+ * \brief A naive preconditioner which approximates any matrix as the identity matrix
+ *
+ * \sa class DiagonalPreconditioner
+ */
+class IdentityPreconditioner
+{
+ public:
+
+ IdentityPreconditioner() {}
+
+ template<typename MatrixType>
+ IdentityPreconditioner(const MatrixType& ) {}
+
+ template<typename MatrixType>
+ IdentityPreconditioner& analyzePattern(const MatrixType& ) { return *this; }
+
+ template<typename MatrixType>
+ IdentityPreconditioner& factorize(const MatrixType& ) { return *this; }
+
+ template<typename MatrixType>
+ IdentityPreconditioner& compute(const MatrixType& ) { return *this; }
+
+ template<typename Rhs>
+ inline const Rhs& solve(const Rhs& b) const { return b; }
+};
+
+} // end namespace Eigen
+
+#endif // EIGEN_BASIC_PRECONDITIONERS_H
diff --git a/Eigen/src/IterativeLinearSolvers/BiCGSTAB.h b/Eigen/src/IterativeLinearSolvers/BiCGSTAB.h
new file mode 100644
index 000000000..126341be8
--- /dev/null
+++ b/Eigen/src/IterativeLinearSolvers/BiCGSTAB.h
@@ -0,0 +1,254 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra.
+//
+// Copyright (C) 2011 Gael Guennebaud <gael.guennebaud@inria.fr>
+// Copyright (C) 2012 Désiré Nuentsa-Wakam <desire.nuentsa_wakam@inria.fr>
+//
+// This Source Code Form is subject to the terms of the Mozilla
+// Public License v. 2.0. If a copy of the MPL was not distributed
+// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+#ifndef EIGEN_BICGSTAB_H
+#define EIGEN_BICGSTAB_H
+
+namespace Eigen {
+
+namespace internal {
+
+/** \internal Low-level bi conjugate gradient stabilized algorithm
+ * \param mat The matrix A
+ * \param rhs The right hand side vector b
+ * \param x On input and initial solution, on output the computed solution.
+ * \param precond A preconditioner being able to efficiently solve for an
+ * approximation of Ax=b (regardless of b)
+ * \param iters On input the max number of iteration, on output the number of performed iterations.
+ * \param tol_error On input the tolerance error, on output an estimation of the relative error.
+ * \return false in the case of numerical issue, for example a break down of BiCGSTAB.
+ */
+template<typename MatrixType, typename Rhs, typename Dest, typename Preconditioner>
+bool bicgstab(const MatrixType& mat, const Rhs& rhs, Dest& x,
+ const Preconditioner& precond, int& iters,
+ typename Dest::RealScalar& tol_error)
+{
+ using std::sqrt;
+ using std::abs;
+ typedef typename Dest::RealScalar RealScalar;
+ typedef typename Dest::Scalar Scalar;
+ typedef Matrix<Scalar,Dynamic,1> VectorType;
+ RealScalar tol = tol_error;
+ int maxIters = iters;
+
+ int n = mat.cols();
+ VectorType r = rhs - mat * x;
+ VectorType r0 = r;
+
+ RealScalar r0_sqnorm = r0.squaredNorm();
+ Scalar rho = 1;
+ Scalar alpha = 1;
+ Scalar w = 1;
+
+ VectorType v = VectorType::Zero(n), p = VectorType::Zero(n);
+ VectorType y(n), z(n);
+ VectorType kt(n), ks(n);
+
+ VectorType s(n), t(n);
+
+ RealScalar tol2 = tol*tol;
+ int i = 0;
+
+ while ( r.squaredNorm()/r0_sqnorm > tol2 && i<maxIters )
+ {
+ Scalar rho_old = rho;
+
+ rho = r0.dot(r);
+ if (rho == Scalar(0)) return false; /* New search directions cannot be found */
+ Scalar beta = (rho/rho_old) * (alpha / w);
+ p = r + beta * (p - w * v);
+
+ y = precond.solve(p);
+
+ v.noalias() = mat * y;
+
+ alpha = rho / r0.dot(v);
+ s = r - alpha * v;
+
+ z = precond.solve(s);
+ t.noalias() = mat * z;
+
+ w = t.dot(s) / t.squaredNorm();
+ x += alpha * y + w * z;
+ r = s - w * t;
+ ++i;
+ }
+ tol_error = sqrt(r.squaredNorm()/r0_sqnorm);
+ iters = i;
+ return true;
+}
+
+}
+
+template< typename _MatrixType,
+ typename _Preconditioner = DiagonalPreconditioner<typename _MatrixType::Scalar> >
+class BiCGSTAB;
+
+namespace internal {
+
+template< typename _MatrixType, typename _Preconditioner>
+struct traits<BiCGSTAB<_MatrixType,_Preconditioner> >
+{
+ typedef _MatrixType MatrixType;
+ typedef _Preconditioner Preconditioner;
+};
+
+}
+
+/** \ingroup IterativeLinearSolvers_Module
+ * \brief A bi conjugate gradient stabilized solver for sparse square problems
+ *
+ * This class allows to solve for A.x = b sparse linear problems using a bi conjugate gradient
+ * stabilized algorithm. The vectors x and b can be either dense or sparse.
+ *
+ * \tparam _MatrixType the type of the sparse matrix A, can be a dense or a sparse matrix.
+ * \tparam _Preconditioner the type of the preconditioner. Default is DiagonalPreconditioner
+ *
+ * The maximal number of iterations and tolerance value can be controlled via the setMaxIterations()
+ * and setTolerance() methods. The defaults are the size of the problem for the maximal number of iterations
+ * and NumTraits<Scalar>::epsilon() for the tolerance.
+ *
+ * This class can be used as the direct solver classes. Here is a typical usage example:
+ * \code
+ * int n = 10000;
+ * VectorXd x(n), b(n);
+ * SparseMatrix<double> A(n,n);
+ * // fill A and b
+ * BiCGSTAB<SparseMatrix<double> > solver;
+ * solver(A);
+ * x = solver.solve(b);
+ * std::cout << "#iterations: " << solver.iterations() << std::endl;
+ * std::cout << "estimated error: " << solver.error() << std::endl;
+ * // update b, and solve again
+ * x = solver.solve(b);
+ * \endcode
+ *
+ * By default the iterations start with x=0 as an initial guess of the solution.
+ * One can control the start using the solveWithGuess() method. Here is a step by
+ * step execution example starting with a random guess and printing the evolution
+ * of the estimated error:
+ * * \code
+ * x = VectorXd::Random(n);
+ * solver.setMaxIterations(1);
+ * int i = 0;
+ * do {
+ * x = solver.solveWithGuess(b,x);
+ * std::cout << i << " : " << solver.error() << std::endl;
+ * ++i;
+ * } while (solver.info()!=Success && i<100);
+ * \endcode
+ * Note that such a step by step excution is slightly slower.
+ *
+ * \sa class SimplicialCholesky, DiagonalPreconditioner, IdentityPreconditioner
+ */
+template< typename _MatrixType, typename _Preconditioner>
+class BiCGSTAB : public IterativeSolverBase<BiCGSTAB<_MatrixType,_Preconditioner> >
+{
+ typedef IterativeSolverBase<BiCGSTAB> Base;
+ using Base::mp_matrix;
+ using Base::m_error;
+ using Base::m_iterations;
+ using Base::m_info;
+ using Base::m_isInitialized;
+public:
+ typedef _MatrixType MatrixType;
+ typedef typename MatrixType::Scalar Scalar;
+ typedef typename MatrixType::Index Index;
+ typedef typename MatrixType::RealScalar RealScalar;
+ typedef _Preconditioner Preconditioner;
+
+public:
+
+ /** Default constructor. */
+ BiCGSTAB() : Base() {}
+
+ /** Initialize the solver with matrix \a A for further \c Ax=b solving.
+ *
+ * This constructor is a shortcut for the default constructor followed
+ * by a call to compute().
+ *
+ * \warning this class stores a reference to the matrix A as well as some
+ * precomputed values that depend on it. Therefore, if \a A is changed
+ * this class becomes invalid. Call compute() to update it with the new
+ * matrix A, or modify a copy of A.
+ */
+ BiCGSTAB(const MatrixType& A) : Base(A) {}
+
+ ~BiCGSTAB() {}
+
+ /** \returns the solution x of \f$ A x = b \f$ using the current decomposition of A
+ * \a x0 as an initial solution.
+ *
+ * \sa compute()
+ */
+ template<typename Rhs,typename Guess>
+ inline const internal::solve_retval_with_guess<BiCGSTAB, Rhs, Guess>
+ solveWithGuess(const MatrixBase<Rhs>& b, const Guess& x0) const
+ {
+ eigen_assert(m_isInitialized && "BiCGSTAB is not initialized.");
+ eigen_assert(Base::rows()==b.rows()
+ && "BiCGSTAB::solve(): invalid number of rows of the right hand side matrix b");
+ return internal::solve_retval_with_guess
+ <BiCGSTAB, Rhs, Guess>(*this, b.derived(), x0);
+ }
+
+ /** \internal */
+ template<typename Rhs,typename Dest>
+ void _solveWithGuess(const Rhs& b, Dest& x) const
+ {
+ bool failed = false;
+ for(int j=0; j<b.cols(); ++j)
+ {
+ m_iterations = Base::maxIterations();
+ m_error = Base::m_tolerance;
+
+ typename Dest::ColXpr xj(x,j);
+ if(!internal::bicgstab(*mp_matrix, b.col(j), xj, Base::m_preconditioner, m_iterations, m_error))
+ failed = true;
+ }
+ m_info = failed ? NumericalIssue
+ : m_error <= Base::m_tolerance ? Success
+ : NoConvergence;
+ m_isInitialized = true;
+ }
+
+ /** \internal */
+ template<typename Rhs,typename Dest>
+ void _solve(const Rhs& b, Dest& x) const
+ {
+ x.setZero();
+ _solveWithGuess(b,x);
+ }
+
+protected:
+
+};
+
+
+namespace internal {
+
+ template<typename _MatrixType, typename _Preconditioner, typename Rhs>
+struct solve_retval<BiCGSTAB<_MatrixType, _Preconditioner>, Rhs>
+ : solve_retval_base<BiCGSTAB<_MatrixType, _Preconditioner>, Rhs>
+{
+ typedef BiCGSTAB<_MatrixType, _Preconditioner> Dec;
+ EIGEN_MAKE_SOLVE_HELPERS(Dec,Rhs)
+
+ template<typename Dest> void evalTo(Dest& dst) const
+ {
+ dec()._solve(rhs(),dst);
+ }
+};
+
+} // end namespace internal
+
+} // end namespace Eigen
+
+#endif // EIGEN_BICGSTAB_H
diff --git a/Eigen/src/IterativeLinearSolvers/CMakeLists.txt b/Eigen/src/IterativeLinearSolvers/CMakeLists.txt
new file mode 100644
index 000000000..59ccc0072
--- /dev/null
+++ b/Eigen/src/IterativeLinearSolvers/CMakeLists.txt
@@ -0,0 +1,6 @@
+FILE(GLOB Eigen_IterativeLinearSolvers_SRCS "*.h")
+
+INSTALL(FILES
+ ${Eigen_IterativeLinearSolvers_SRCS}
+ DESTINATION ${INCLUDE_INSTALL_DIR}/Eigen/src/IterativeLinearSolvers COMPONENT Devel
+ )
diff --git a/Eigen/src/IterativeLinearSolvers/ConjugateGradient.h b/Eigen/src/IterativeLinearSolvers/ConjugateGradient.h
new file mode 100644
index 000000000..f64f2534d
--- /dev/null
+++ b/Eigen/src/IterativeLinearSolvers/ConjugateGradient.h
@@ -0,0 +1,251 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra.
+//
+// Copyright (C) 2011 Gael Guennebaud <gael.guennebaud@inria.fr>
+//
+// This Source Code Form is subject to the terms of the Mozilla
+// Public License v. 2.0. If a copy of the MPL was not distributed
+// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+#ifndef EIGEN_CONJUGATE_GRADIENT_H
+#define EIGEN_CONJUGATE_GRADIENT_H
+
+namespace Eigen {
+
+namespace internal {
+
+/** \internal Low-level conjugate gradient algorithm
+ * \param mat The matrix A
+ * \param rhs The right hand side vector b
+ * \param x On input and initial solution, on output the computed solution.
+ * \param precond A preconditioner being able to efficiently solve for an
+ * approximation of Ax=b (regardless of b)
+ * \param iters On input the max number of iteration, on output the number of performed iterations.
+ * \param tol_error On input the tolerance error, on output an estimation of the relative error.
+ */
+template<typename MatrixType, typename Rhs, typename Dest, typename Preconditioner>
+EIGEN_DONT_INLINE
+void conjugate_gradient(const MatrixType& mat, const Rhs& rhs, Dest& x,
+ const Preconditioner& precond, int& iters,
+ typename Dest::RealScalar& tol_error)
+{
+ using std::sqrt;
+ using std::abs;
+ typedef typename Dest::RealScalar RealScalar;
+ typedef typename Dest::Scalar Scalar;
+ typedef Matrix<Scalar,Dynamic,1> VectorType;
+
+ RealScalar tol = tol_error;
+ int maxIters = iters;
+
+ int n = mat.cols();
+
+ VectorType residual = rhs - mat * x; //initial residual
+ VectorType p(n);
+
+ p = precond.solve(residual); //initial search direction
+
+ VectorType z(n), tmp(n);
+ RealScalar absNew = internal::real(residual.dot(p)); // the square of the absolute value of r scaled by invM
+ RealScalar rhsNorm2 = rhs.squaredNorm();
+ RealScalar residualNorm2 = 0;
+ RealScalar threshold = tol*tol*rhsNorm2;
+ int i = 0;
+ while(i < maxIters)
+ {
+ tmp.noalias() = mat * p; // the bottleneck of the algorithm
+
+ Scalar alpha = absNew / p.dot(tmp); // the amount we travel on dir
+ x += alpha * p; // update solution
+ residual -= alpha * tmp; // update residue
+
+ residualNorm2 = residual.squaredNorm();
+ if(residualNorm2 < threshold)
+ break;
+
+ z = precond.solve(residual); // approximately solve for "A z = residual"
+
+ RealScalar absOld = absNew;
+ absNew = internal::real(residual.dot(z)); // update the absolute value of r
+ RealScalar beta = absNew / absOld; // calculate the Gram-Schmidt value used to create the new search direction
+ p = z + beta * p; // update search direction
+ i++;
+ }
+ tol_error = sqrt(residualNorm2 / rhsNorm2);
+ iters = i;
+}
+
+}
+
+template< typename _MatrixType, int _UpLo=Lower,
+ typename _Preconditioner = DiagonalPreconditioner<typename _MatrixType::Scalar> >
+class ConjugateGradient;
+
+namespace internal {
+
+template< typename _MatrixType, int _UpLo, typename _Preconditioner>
+struct traits<ConjugateGradient<_MatrixType,_UpLo,_Preconditioner> >
+{
+ typedef _MatrixType MatrixType;
+ typedef _Preconditioner Preconditioner;
+};
+
+}
+
+/** \ingroup IterativeLinearSolvers_Module
+ * \brief A conjugate gradient solver for sparse self-adjoint problems
+ *
+ * This class allows to solve for A.x = b sparse linear problems using a conjugate gradient algorithm.
+ * The sparse matrix A must be selfadjoint. The vectors x and b can be either dense or sparse.
+ *
+ * \tparam _MatrixType the type of the sparse matrix A, can be a dense or a sparse matrix.
+ * \tparam _UpLo the triangular part that will be used for the computations. It can be Lower
+ * or Upper. Default is Lower.
+ * \tparam _Preconditioner the type of the preconditioner. Default is DiagonalPreconditioner
+ *
+ * The maximal number of iterations and tolerance value can be controlled via the setMaxIterations()
+ * and setTolerance() methods. The defaults are the size of the problem for the maximal number of iterations
+ * and NumTraits<Scalar>::epsilon() for the tolerance.
+ *
+ * This class can be used as the direct solver classes. Here is a typical usage example:
+ * \code
+ * int n = 10000;
+ * VectorXd x(n), b(n);
+ * SparseMatrix<double> A(n,n);
+ * // fill A and b
+ * ConjugateGradient<SparseMatrix<double> > cg;
+ * cg.compute(A);
+ * x = cg.solve(b);
+ * std::cout << "#iterations: " << cg.iterations() << std::endl;
+ * std::cout << "estimated error: " << cg.error() << std::endl;
+ * // update b, and solve again
+ * x = cg.solve(b);
+ * \endcode
+ *
+ * By default the iterations start with x=0 as an initial guess of the solution.
+ * One can control the start using the solveWithGuess() method. Here is a step by
+ * step execution example starting with a random guess and printing the evolution
+ * of the estimated error:
+ * * \code
+ * x = VectorXd::Random(n);
+ * cg.setMaxIterations(1);
+ * int i = 0;
+ * do {
+ * x = cg.solveWithGuess(b,x);
+ * std::cout << i << " : " << cg.error() << std::endl;
+ * ++i;
+ * } while (cg.info()!=Success && i<100);
+ * \endcode
+ * Note that such a step by step excution is slightly slower.
+ *
+ * \sa class SimplicialCholesky, DiagonalPreconditioner, IdentityPreconditioner
+ */
+template< typename _MatrixType, int _UpLo, typename _Preconditioner>
+class ConjugateGradient : public IterativeSolverBase<ConjugateGradient<_MatrixType,_UpLo,_Preconditioner> >
+{
+ typedef IterativeSolverBase<ConjugateGradient> Base;
+ using Base::mp_matrix;
+ using Base::m_error;
+ using Base::m_iterations;
+ using Base::m_info;
+ using Base::m_isInitialized;
+public:
+ typedef _MatrixType MatrixType;
+ typedef typename MatrixType::Scalar Scalar;
+ typedef typename MatrixType::Index Index;
+ typedef typename MatrixType::RealScalar RealScalar;
+ typedef _Preconditioner Preconditioner;
+
+ enum {
+ UpLo = _UpLo
+ };
+
+public:
+
+ /** Default constructor. */
+ ConjugateGradient() : Base() {}
+
+ /** Initialize the solver with matrix \a A for further \c Ax=b solving.
+ *
+ * This constructor is a shortcut for the default constructor followed
+ * by a call to compute().
+ *
+ * \warning this class stores a reference to the matrix A as well as some
+ * precomputed values that depend on it. Therefore, if \a A is changed
+ * this class becomes invalid. Call compute() to update it with the new
+ * matrix A, or modify a copy of A.
+ */
+ ConjugateGradient(const MatrixType& A) : Base(A) {}
+
+ ~ConjugateGradient() {}
+
+ /** \returns the solution x of \f$ A x = b \f$ using the current decomposition of A
+ * \a x0 as an initial solution.
+ *
+ * \sa compute()
+ */
+ template<typename Rhs,typename Guess>
+ inline const internal::solve_retval_with_guess<ConjugateGradient, Rhs, Guess>
+ solveWithGuess(const MatrixBase<Rhs>& b, const Guess& x0) const
+ {
+ eigen_assert(m_isInitialized && "ConjugateGradient is not initialized.");
+ eigen_assert(Base::rows()==b.rows()
+ && "ConjugateGradient::solve(): invalid number of rows of the right hand side matrix b");
+ return internal::solve_retval_with_guess
+ <ConjugateGradient, Rhs, Guess>(*this, b.derived(), x0);
+ }
+
+ /** \internal */
+ template<typename Rhs,typename Dest>
+ void _solveWithGuess(const Rhs& b, Dest& x) const
+ {
+ m_iterations = Base::maxIterations();
+ m_error = Base::m_tolerance;
+
+ for(int j=0; j<b.cols(); ++j)
+ {
+ m_iterations = Base::maxIterations();
+ m_error = Base::m_tolerance;
+
+ typename Dest::ColXpr xj(x,j);
+ internal::conjugate_gradient(mp_matrix->template selfadjointView<UpLo>(), b.col(j), xj,
+ Base::m_preconditioner, m_iterations, m_error);
+ }
+
+ m_isInitialized = true;
+ m_info = m_error <= Base::m_tolerance ? Success : NoConvergence;
+ }
+
+ /** \internal */
+ template<typename Rhs,typename Dest>
+ void _solve(const Rhs& b, Dest& x) const
+ {
+ x.setOnes();
+ _solveWithGuess(b,x);
+ }
+
+protected:
+
+};
+
+
+namespace internal {
+
+template<typename _MatrixType, int _UpLo, typename _Preconditioner, typename Rhs>
+struct solve_retval<ConjugateGradient<_MatrixType,_UpLo,_Preconditioner>, Rhs>
+ : solve_retval_base<ConjugateGradient<_MatrixType,_UpLo,_Preconditioner>, Rhs>
+{
+ typedef ConjugateGradient<_MatrixType,_UpLo,_Preconditioner> Dec;
+ EIGEN_MAKE_SOLVE_HELPERS(Dec,Rhs)
+
+ template<typename Dest> void evalTo(Dest& dst) const
+ {
+ dec()._solve(rhs(),dst);
+ }
+};
+
+} // end namespace internal
+
+} // end namespace Eigen
+
+#endif // EIGEN_CONJUGATE_GRADIENT_H
diff --git a/Eigen/src/IterativeLinearSolvers/IncompleteLUT.h b/Eigen/src/IterativeLinearSolvers/IncompleteLUT.h
new file mode 100644
index 000000000..224304f0e
--- /dev/null
+++ b/Eigen/src/IterativeLinearSolvers/IncompleteLUT.h
@@ -0,0 +1,466 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra.
+//
+// Copyright (C) 2012 Désiré Nuentsa-Wakam <desire.nuentsa_wakam@inria.fr>
+//
+// This Source Code Form is subject to the terms of the Mozilla
+// Public License v. 2.0. If a copy of the MPL was not distributed
+// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+#ifndef EIGEN_INCOMPLETE_LUT_H
+#define EIGEN_INCOMPLETE_LUT_H
+
+namespace Eigen {
+
+/**
+ * \brief Incomplete LU factorization with dual-threshold strategy
+ * During the numerical factorization, two dropping rules are used :
+ * 1) any element whose magnitude is less than some tolerance is dropped.
+ * This tolerance is obtained by multiplying the input tolerance @p droptol
+ * by the average magnitude of all the original elements in the current row.
+ * 2) After the elimination of the row, only the @p fill largest elements in
+ * the L part and the @p fill largest elements in the U part are kept
+ * (in addition to the diagonal element ). Note that @p fill is computed from
+ * the input parameter @p fillfactor which is used the ratio to control the fill_in
+ * relatively to the initial number of nonzero elements.
+ *
+ * The two extreme cases are when @p droptol=0 (to keep all the @p fill*2 largest elements)
+ * and when @p fill=n/2 with @p droptol being different to zero.
+ *
+ * References : Yousef Saad, ILUT: A dual threshold incomplete LU factorization,
+ * Numerical Linear Algebra with Applications, 1(4), pp 387-402, 1994.
+ *
+ * NOTE : The following implementation is derived from the ILUT implementation
+ * in the SPARSKIT package, Copyright (C) 2005, the Regents of the University of Minnesota
+ * released under the terms of the GNU LGPL:
+ * http://www-users.cs.umn.edu/~saad/software/SPARSKIT/README
+ * However, Yousef Saad gave us permission to relicense his ILUT code to MPL2.
+ * See the Eigen mailing list archive, thread: ILUT, date: July 8, 2012:
+ * http://listengine.tuxfamily.org/lists.tuxfamily.org/eigen/2012/07/msg00064.html
+ * alternatively, on GMANE:
+ * http://comments.gmane.org/gmane.comp.lib.eigen/3302
+ */
+template <typename _Scalar>
+class IncompleteLUT : internal::noncopyable
+{
+ typedef _Scalar Scalar;
+ typedef typename NumTraits<Scalar>::Real RealScalar;
+ typedef Matrix<Scalar,Dynamic,1> Vector;
+ typedef SparseMatrix<Scalar,RowMajor> FactorType;
+ typedef SparseMatrix<Scalar,ColMajor> PermutType;
+ typedef typename FactorType::Index Index;
+
+ public:
+ typedef Matrix<Scalar,Dynamic,Dynamic> MatrixType;
+
+ IncompleteLUT()
+ : m_droptol(NumTraits<Scalar>::dummy_precision()), m_fillfactor(10),
+ m_analysisIsOk(false), m_factorizationIsOk(false), m_isInitialized(false)
+ {}
+
+ template<typename MatrixType>
+ IncompleteLUT(const MatrixType& mat, RealScalar droptol=NumTraits<Scalar>::dummy_precision(), int fillfactor = 10)
+ : m_droptol(droptol),m_fillfactor(fillfactor),
+ m_analysisIsOk(false),m_factorizationIsOk(false),m_isInitialized(false)
+ {
+ eigen_assert(fillfactor != 0);
+ compute(mat);
+ }
+
+ Index rows() const { return m_lu.rows(); }
+
+ Index cols() const { return m_lu.cols(); }
+
+ /** \brief Reports whether previous computation was successful.
+ *
+ * \returns \c Success if computation was succesful,
+ * \c NumericalIssue if the matrix.appears to be negative.
+ */
+ ComputationInfo info() const
+ {
+ eigen_assert(m_isInitialized && "IncompleteLUT is not initialized.");
+ return m_info;
+ }
+
+ template<typename MatrixType>
+ void analyzePattern(const MatrixType& amat);
+
+ template<typename MatrixType>
+ void factorize(const MatrixType& amat);
+
+ /**
+ * Compute an incomplete LU factorization with dual threshold on the matrix mat
+ * No pivoting is done in this version
+ *
+ **/
+ template<typename MatrixType>
+ IncompleteLUT<Scalar>& compute(const MatrixType& amat)
+ {
+ analyzePattern(amat);
+ factorize(amat);
+ eigen_assert(m_factorizationIsOk == true);
+ m_isInitialized = true;
+ return *this;
+ }
+
+ void setDroptol(RealScalar droptol);
+ void setFillfactor(int fillfactor);
+
+ template<typename Rhs, typename Dest>
+ void _solve(const Rhs& b, Dest& x) const
+ {
+ x = m_Pinv * b;
+ x = m_lu.template triangularView<UnitLower>().solve(x);
+ x = m_lu.template triangularView<Upper>().solve(x);
+ x = m_P * x;
+ }
+
+ template<typename Rhs> inline const internal::solve_retval<IncompleteLUT, Rhs>
+ solve(const MatrixBase<Rhs>& b) const
+ {
+ eigen_assert(m_isInitialized && "IncompleteLUT is not initialized.");
+ eigen_assert(cols()==b.rows()
+ && "IncompleteLUT::solve(): invalid number of rows of the right hand side matrix b");
+ return internal::solve_retval<IncompleteLUT, Rhs>(*this, b.derived());
+ }
+
+protected:
+
+ template <typename VectorV, typename VectorI>
+ int QuickSplit(VectorV &row, VectorI &ind, int ncut);
+
+
+ /** keeps off-diagonal entries; drops diagonal entries */
+ struct keep_diag {
+ inline bool operator() (const Index& row, const Index& col, const Scalar&) const
+ {
+ return row!=col;
+ }
+ };
+
+protected:
+
+ FactorType m_lu;
+ RealScalar m_droptol;
+ int m_fillfactor;
+ bool m_analysisIsOk;
+ bool m_factorizationIsOk;
+ bool m_isInitialized;
+ ComputationInfo m_info;
+ PermutationMatrix<Dynamic,Dynamic,Index> m_P; // Fill-reducing permutation
+ PermutationMatrix<Dynamic,Dynamic,Index> m_Pinv; // Inverse permutation
+};
+
+/**
+ * Set control parameter droptol
+ * \param droptol Drop any element whose magnitude is less than this tolerance
+ **/
+template<typename Scalar>
+void IncompleteLUT<Scalar>::setDroptol(RealScalar droptol)
+{
+ this->m_droptol = droptol;
+}
+
+/**
+ * Set control parameter fillfactor
+ * \param fillfactor This is used to compute the number @p fill_in of largest elements to keep on each row.
+ **/
+template<typename Scalar>
+void IncompleteLUT<Scalar>::setFillfactor(int fillfactor)
+{
+ this->m_fillfactor = fillfactor;
+}
+
+
+/**
+ * Compute a quick-sort split of a vector
+ * On output, the vector row is permuted such that its elements satisfy
+ * abs(row(i)) >= abs(row(ncut)) if i<ncut
+ * abs(row(i)) <= abs(row(ncut)) if i>ncut
+ * \param row The vector of values
+ * \param ind The array of index for the elements in @p row
+ * \param ncut The number of largest elements to keep
+ **/
+template <typename Scalar>
+template <typename VectorV, typename VectorI>
+int IncompleteLUT<Scalar>::QuickSplit(VectorV &row, VectorI &ind, int ncut)
+{
+ using std::swap;
+ int mid;
+ int n = row.size(); /* length of the vector */
+ int first, last ;
+
+ ncut--; /* to fit the zero-based indices */
+ first = 0;
+ last = n-1;
+ if (ncut < first || ncut > last ) return 0;
+
+ do {
+ mid = first;
+ RealScalar abskey = std::abs(row(mid));
+ for (int j = first + 1; j <= last; j++) {
+ if ( std::abs(row(j)) > abskey) {
+ ++mid;
+ swap(row(mid), row(j));
+ swap(ind(mid), ind(j));
+ }
+ }
+ /* Interchange for the pivot element */
+ swap(row(mid), row(first));
+ swap(ind(mid), ind(first));
+
+ if (mid > ncut) last = mid - 1;
+ else if (mid < ncut ) first = mid + 1;
+ } while (mid != ncut );
+
+ return 0; /* mid is equal to ncut */
+}
+
+template <typename Scalar>
+template<typename _MatrixType>
+void IncompleteLUT<Scalar>::analyzePattern(const _MatrixType& amat)
+{
+ // Compute the Fill-reducing permutation
+ SparseMatrix<Scalar,ColMajor, Index> mat1 = amat;
+ SparseMatrix<Scalar,ColMajor, Index> mat2 = amat.transpose();
+ // Symmetrize the pattern
+ // FIXME for a matrix with nearly symmetric pattern, mat2+mat1 is the appropriate choice.
+ // on the other hand for a really non-symmetric pattern, mat2*mat1 should be prefered...
+ SparseMatrix<Scalar,ColMajor, Index> AtA = mat2 + mat1;
+ AtA.prune(keep_diag());
+ internal::minimum_degree_ordering<Scalar, Index>(AtA, m_P); // Then compute the AMD ordering...
+
+ m_Pinv = m_P.inverse(); // ... and the inverse permutation
+
+ m_analysisIsOk = true;
+}
+
+template <typename Scalar>
+template<typename _MatrixType>
+void IncompleteLUT<Scalar>::factorize(const _MatrixType& amat)
+{
+ using std::sqrt;
+ using std::swap;
+ using std::abs;
+
+ eigen_assert((amat.rows() == amat.cols()) && "The factorization should be done on a square matrix");
+ int n = amat.cols(); // Size of the matrix
+ m_lu.resize(n,n);
+ // Declare Working vectors and variables
+ Vector u(n) ; // real values of the row -- maximum size is n --
+ VectorXi ju(n); // column position of the values in u -- maximum size is n
+ VectorXi jr(n); // Indicate the position of the nonzero elements in the vector u -- A zero location is indicated by -1
+
+ // Apply the fill-reducing permutation
+ eigen_assert(m_analysisIsOk && "You must first call analyzePattern()");
+ SparseMatrix<Scalar,RowMajor, Index> mat;
+ mat = amat.twistedBy(m_Pinv);
+
+ // Initialization
+ jr.fill(-1);
+ ju.fill(0);
+ u.fill(0);
+
+ // number of largest elements to keep in each row:
+ int fill_in = static_cast<int> (amat.nonZeros()*m_fillfactor)/n+1;
+ if (fill_in > n) fill_in = n;
+
+ // number of largest nonzero elements to keep in the L and the U part of the current row:
+ int nnzL = fill_in/2;
+ int nnzU = nnzL;
+ m_lu.reserve(n * (nnzL + nnzU + 1));
+
+ // global loop over the rows of the sparse matrix
+ for (int ii = 0; ii < n; ii++)
+ {
+ // 1 - copy the lower and the upper part of the row i of mat in the working vector u
+
+ int sizeu = 1; // number of nonzero elements in the upper part of the current row
+ int sizel = 0; // number of nonzero elements in the lower part of the current row
+ ju(ii) = ii;
+ u(ii) = 0;
+ jr(ii) = ii;
+ RealScalar rownorm = 0;
+
+ typename FactorType::InnerIterator j_it(mat, ii); // Iterate through the current row ii
+ for (; j_it; ++j_it)
+ {
+ int k = j_it.index();
+ if (k < ii)
+ {
+ // copy the lower part
+ ju(sizel) = k;
+ u(sizel) = j_it.value();
+ jr(k) = sizel;
+ ++sizel;
+ }
+ else if (k == ii)
+ {
+ u(ii) = j_it.value();
+ }
+ else
+ {
+ // copy the upper part
+ int jpos = ii + sizeu;
+ ju(jpos) = k;
+ u(jpos) = j_it.value();
+ jr(k) = jpos;
+ ++sizeu;
+ }
+ rownorm += internal::abs2(j_it.value());
+ }
+
+ // 2 - detect possible zero row
+ if(rownorm==0)
+ {
+ m_info = NumericalIssue;
+ return;
+ }
+ // Take the 2-norm of the current row as a relative tolerance
+ rownorm = sqrt(rownorm);
+
+ // 3 - eliminate the previous nonzero rows
+ int jj = 0;
+ int len = 0;
+ while (jj < sizel)
+ {
+ // In order to eliminate in the correct order,
+ // we must select first the smallest column index among ju(jj:sizel)
+ int k;
+ int minrow = ju.segment(jj,sizel-jj).minCoeff(&k); // k is relative to the segment
+ k += jj;
+ if (minrow != ju(jj))
+ {
+ // swap the two locations
+ int j = ju(jj);
+ swap(ju(jj), ju(k));
+ jr(minrow) = jj; jr(j) = k;
+ swap(u(jj), u(k));
+ }
+ // Reset this location
+ jr(minrow) = -1;
+
+ // Start elimination
+ typename FactorType::InnerIterator ki_it(m_lu, minrow);
+ while (ki_it && ki_it.index() < minrow) ++ki_it;
+ eigen_internal_assert(ki_it && ki_it.col()==minrow);
+ Scalar fact = u(jj) / ki_it.value();
+
+ // drop too small elements
+ if(abs(fact) <= m_droptol)
+ {
+ jj++;
+ continue;
+ }
+
+ // linear combination of the current row ii and the row minrow
+ ++ki_it;
+ for (; ki_it; ++ki_it)
+ {
+ Scalar prod = fact * ki_it.value();
+ int j = ki_it.index();
+ int jpos = jr(j);
+ if (jpos == -1) // fill-in element
+ {
+ int newpos;
+ if (j >= ii) // dealing with the upper part
+ {
+ newpos = ii + sizeu;
+ sizeu++;
+ eigen_internal_assert(sizeu<=n);
+ }
+ else // dealing with the lower part
+ {
+ newpos = sizel;
+ sizel++;
+ eigen_internal_assert(sizel<=ii);
+ }
+ ju(newpos) = j;
+ u(newpos) = -prod;
+ jr(j) = newpos;
+ }
+ else
+ u(jpos) -= prod;
+ }
+ // store the pivot element
+ u(len) = fact;
+ ju(len) = minrow;
+ ++len;
+
+ jj++;
+ } // end of the elimination on the row ii
+
+ // reset the upper part of the pointer jr to zero
+ for(int k = 0; k <sizeu; k++) jr(ju(ii+k)) = -1;
+
+ // 4 - partially sort and insert the elements in the m_lu matrix
+
+ // sort the L-part of the row
+ sizel = len;
+ len = (std::min)(sizel, nnzL);
+ typename Vector::SegmentReturnType ul(u.segment(0, sizel));
+ typename VectorXi::SegmentReturnType jul(ju.segment(0, sizel));
+ QuickSplit(ul, jul, len);
+
+ // store the largest m_fill elements of the L part
+ m_lu.startVec(ii);
+ for(int k = 0; k < len; k++)
+ m_lu.insertBackByOuterInnerUnordered(ii,ju(k)) = u(k);
+
+ // store the diagonal element
+ // apply a shifting rule to avoid zero pivots (we are doing an incomplete factorization)
+ if (u(ii) == Scalar(0))
+ u(ii) = sqrt(m_droptol) * rownorm;
+ m_lu.insertBackByOuterInnerUnordered(ii, ii) = u(ii);
+
+ // sort the U-part of the row
+ // apply the dropping rule first
+ len = 0;
+ for(int k = 1; k < sizeu; k++)
+ {
+ if(abs(u(ii+k)) > m_droptol * rownorm )
+ {
+ ++len;
+ u(ii + len) = u(ii + k);
+ ju(ii + len) = ju(ii + k);
+ }
+ }
+ sizeu = len + 1; // +1 to take into account the diagonal element
+ len = (std::min)(sizeu, nnzU);
+ typename Vector::SegmentReturnType uu(u.segment(ii+1, sizeu-1));
+ typename VectorXi::SegmentReturnType juu(ju.segment(ii+1, sizeu-1));
+ QuickSplit(uu, juu, len);
+
+ // store the largest elements of the U part
+ for(int k = ii + 1; k < ii + len; k++)
+ m_lu.insertBackByOuterInnerUnordered(ii,ju(k)) = u(k);
+ }
+
+ m_lu.finalize();
+ m_lu.makeCompressed();
+
+ m_factorizationIsOk = true;
+ m_info = Success;
+}
+
+namespace internal {
+
+template<typename _MatrixType, typename Rhs>
+struct solve_retval<IncompleteLUT<_MatrixType>, Rhs>
+ : solve_retval_base<IncompleteLUT<_MatrixType>, Rhs>
+{
+ typedef IncompleteLUT<_MatrixType> Dec;
+ EIGEN_MAKE_SOLVE_HELPERS(Dec,Rhs)
+
+ template<typename Dest> void evalTo(Dest& dst) const
+ {
+ dec()._solve(rhs(),dst);
+ }
+};
+
+} // end namespace internal
+
+} // end namespace Eigen
+
+#endif // EIGEN_INCOMPLETE_LUT_H
+
diff --git a/Eigen/src/IterativeLinearSolvers/IterativeSolverBase.h b/Eigen/src/IterativeLinearSolvers/IterativeSolverBase.h
new file mode 100644
index 000000000..11706ceba
--- /dev/null
+++ b/Eigen/src/IterativeLinearSolvers/IterativeSolverBase.h
@@ -0,0 +1,254 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra.
+//
+// Copyright (C) 2011 Gael Guennebaud <gael.guennebaud@inria.fr>
+//
+// This Source Code Form is subject to the terms of the Mozilla
+// Public License v. 2.0. If 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<Derived>::MatrixType MatrixType;
+ typedef typename internal::traits<Derived>::Preconditioner Preconditioner;
+ typedef typename MatrixType::Scalar Scalar;
+ typedef typename MatrixType::Index Index;
+ typedef typename MatrixType::RealScalar RealScalar;
+
+public:
+
+ Derived& derived() { return *static_cast<Derived*>(this); }
+ const Derived& derived() const { return *static_cast<const Derived*>(this); }
+
+ /** Default constructor. */
+ IterativeSolverBase()
+ : mp_matrix(0)
+ {
+ init();
+ }
+
+ /** Initialize the solver with matrix \a A for further \c Ax=b solving.
+ *
+ * This constructor is a shortcut for the default constructor followed
+ * by a call to compute().
+ *
+ * \warning this class stores a reference to the matrix A as well as some
+ * precomputed values that depend on it. Therefore, if \a A is changed
+ * this class becomes invalid. Call compute() to update it with the new
+ * matrix A, or modify a copy of A.
+ */
+ IterativeSolverBase(const MatrixType& A)
+ {
+ init();
+ compute(A);
+ }
+
+ ~IterativeSolverBase() {}
+
+ /** Initializes the iterative solver for the sparcity pattern of the matrix \a A for further solving \c Ax=b problems.
+ *
+ * Currently, this function mostly call analyzePattern on the preconditioner. In the future
+ * we might, for instance, implement column reodering for faster matrix vector products.
+ */
+ Derived& analyzePattern(const MatrixType& A)
+ {
+ m_preconditioner.analyzePattern(A);
+ m_isInitialized = true;
+ m_analysisIsOk = true;
+ m_info = Success;
+ return derived();
+ }
+
+ /** Initializes the iterative solver with the numerical values of the matrix \a A for further solving \c Ax=b problems.
+ *
+ * Currently, this function mostly call factorize on the preconditioner.
+ *
+ * \warning this class stores a reference to the matrix A as well as some
+ * precomputed values that depend on it. Therefore, if \a A is changed
+ * this class becomes invalid. Call compute() to update it with the new
+ * matrix A, or modify a copy of A.
+ */
+ Derived& factorize(const MatrixType& A)
+ {
+ eigen_assert(m_analysisIsOk && "You must first call analyzePattern()");
+ mp_matrix = &A;
+ m_preconditioner.factorize(A);
+ m_factorizationIsOk = true;
+ m_info = Success;
+ return derived();
+ }
+
+ /** Initializes the iterative solver with the matrix \a A for further solving \c Ax=b problems.
+ *
+ * Currently, this function mostly initialized/compute the preconditioner. In the future
+ * we might, for instance, implement column reodering for faster matrix vector products.
+ *
+ * \warning this class stores a reference to the matrix A as well as some
+ * precomputed values that depend on it. Therefore, if \a A is changed
+ * this class becomes invalid. Call compute() to update it with the new
+ * matrix A, or modify a copy of A.
+ */
+ Derived& compute(const MatrixType& A)
+ {
+ mp_matrix = &A;
+ m_preconditioner.compute(A);
+ m_isInitialized = true;
+ m_analysisIsOk = true;
+ m_factorizationIsOk = true;
+ m_info = Success;
+ return derived();
+ }
+
+ /** \internal */
+ Index rows() const { return mp_matrix ? mp_matrix->rows() : 0; }
+ /** \internal */
+ Index cols() const { return mp_matrix ? mp_matrix->cols() : 0; }
+
+ /** \returns the tolerance threshold used by the stopping criteria */
+ RealScalar tolerance() const { return m_tolerance; }
+
+ /** Sets the tolerance threshold used by the stopping criteria */
+ Derived& setTolerance(RealScalar tolerance)
+ {
+ m_tolerance = tolerance;
+ return derived();
+ }
+
+ /** \returns a read-write reference to the preconditioner for custom configuration. */
+ Preconditioner& preconditioner() { return m_preconditioner; }
+
+ /** \returns a read-only reference to the preconditioner. */
+ const Preconditioner& preconditioner() const { return m_preconditioner; }
+
+ /** \returns the max number of iterations */
+ int maxIterations() const
+ {
+ return (mp_matrix && m_maxIterations<0) ? mp_matrix->cols() : m_maxIterations;
+ }
+
+ /** Sets the max number of iterations */
+ Derived& setMaxIterations(int maxIters)
+ {
+ m_maxIterations = maxIters;
+ return derived();
+ }
+
+ /** \returns the number of iterations performed during the last solve */
+ int iterations() const
+ {
+ eigen_assert(m_isInitialized && "ConjugateGradient is not initialized.");
+ return m_iterations;
+ }
+
+ /** \returns the tolerance error reached during the last solve */
+ RealScalar error() const
+ {
+ eigen_assert(m_isInitialized && "ConjugateGradient is not initialized.");
+ return m_error;
+ }
+
+ /** \returns the solution x of \f$ A x = b \f$ using the current decomposition of A.
+ *
+ * \sa compute()
+ */
+ template<typename Rhs> inline const internal::solve_retval<Derived, Rhs>
+ solve(const MatrixBase<Rhs>& 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, Rhs>(derived(), b.derived());
+ }
+
+ /** \returns the solution x of \f$ A x = b \f$ using the current decomposition of A.
+ *
+ * \sa compute()
+ */
+ template<typename Rhs>
+ inline const internal::sparse_solve_retval<IterativeSolverBase, Rhs>
+ solve(const SparseMatrixBase<Rhs>& 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<IterativeSolverBase, Rhs>(*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<typename Rhs, typename DestScalar, int DestOptions, typename DestIndex>
+ void _solve_sparse(const Rhs& b, SparseMatrix<DestScalar,DestOptions,DestIndex> &dest) const
+ {
+ eigen_assert(rows()==b.rows());
+
+ int rhsCols = b.cols();
+ int size = b.rows();
+ Eigen::Matrix<DestScalar,Dynamic,1> tb(size);
+ Eigen::Matrix<DestScalar,Dynamic,1> tx(size);
+ for(int k=0; k<rhsCols; ++k)
+ {
+ tb = b.col(k);
+ tx = derived().solve(tb);
+ dest.col(k) = tx.sparseView(0);
+ }
+ }
+
+protected:
+ void init()
+ {
+ m_isInitialized = false;
+ m_analysisIsOk = false;
+ m_factorizationIsOk = false;
+ m_maxIterations = -1;
+ m_tolerance = NumTraits<Scalar>::epsilon();
+ }
+ const MatrixType* mp_matrix;
+ Preconditioner m_preconditioner;
+
+ int m_maxIterations;
+ RealScalar m_tolerance;
+
+ mutable RealScalar m_error;
+ mutable int m_iterations;
+ mutable ComputationInfo m_info;
+ mutable bool m_isInitialized, m_analysisIsOk, m_factorizationIsOk;
+};
+
+namespace internal {
+
+template<typename Derived, typename Rhs>
+struct sparse_solve_retval<IterativeSolverBase<Derived>, Rhs>
+ : sparse_solve_retval_base<IterativeSolverBase<Derived>, Rhs>
+{
+ typedef IterativeSolverBase<Derived> Dec;
+ EIGEN_MAKE_SPARSE_SOLVE_HELPERS(Dec,Rhs)
+
+ template<typename Dest> 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/Eigen/src/Jacobi/CMakeLists.txt b/Eigen/src/Jacobi/CMakeLists.txt
new file mode 100644
index 000000000..490dac626
--- /dev/null
+++ b/Eigen/src/Jacobi/CMakeLists.txt
@@ -0,0 +1,6 @@
+FILE(GLOB Eigen_Jacobi_SRCS "*.h")
+
+INSTALL(FILES
+ ${Eigen_Jacobi_SRCS}
+ DESTINATION ${INCLUDE_INSTALL_DIR}/Eigen/src/Jacobi COMPONENT Devel
+ )
diff --git a/Eigen/src/Jacobi/Jacobi.h b/Eigen/src/Jacobi/Jacobi.h
new file mode 100644
index 000000000..a9c17dcdf
--- /dev/null
+++ b/Eigen/src/Jacobi/Jacobi.h
@@ -0,0 +1,420 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra.
+//
+// Copyright (C) 2009 Benoit Jacob <jacob.benoit.1@gmail.com>
+// Copyright (C) 2009 Gael Guennebaud <gael.guennebaud@inria.fr>
+//
+// This Source Code Form is subject to the terms of the Mozilla
+// Public License v. 2.0. If a copy of the MPL was not distributed
+// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+#ifndef EIGEN_JACOBI_H
+#define EIGEN_JACOBI_H
+
+namespace Eigen {
+
+/** \ingroup Jacobi_Module
+ * \jacobi_module
+ * \class JacobiRotation
+ * \brief Rotation given by a cosine-sine pair.
+ *
+ * This class represents a Jacobi or Givens rotation.
+ * This is a 2D rotation in the plane \c J of angle \f$ \theta \f$ defined by
+ * its cosine \c c and sine \c s as follow:
+ * \f$ J = \left ( \begin{array}{cc} c & \overline s \\ -s & \overline c \end{array} \right ) \f$
+ *
+ * You can apply the respective counter-clockwise rotation to a column vector \c v by
+ * applying its adjoint on the left: \f$ v = J^* v \f$ that translates to the following Eigen code:
+ * \code
+ * v.applyOnTheLeft(J.adjoint());
+ * \endcode
+ *
+ * \sa MatrixBase::applyOnTheLeft(), MatrixBase::applyOnTheRight()
+ */
+template<typename Scalar> class JacobiRotation
+{
+ public:
+ typedef typename NumTraits<Scalar>::Real RealScalar;
+
+ /** Default constructor without any initialization. */
+ JacobiRotation() {}
+
+ /** Construct a planar rotation from a cosine-sine pair (\a c, \c s). */
+ JacobiRotation(const Scalar& c, const Scalar& s) : m_c(c), m_s(s) {}
+
+ Scalar& c() { return m_c; }
+ Scalar c() const { return m_c; }
+ Scalar& s() { return m_s; }
+ Scalar s() const { return m_s; }
+
+ /** Concatenates two planar rotation */
+ JacobiRotation operator*(const JacobiRotation& other)
+ {
+ return JacobiRotation(m_c * other.m_c - internal::conj(m_s) * other.m_s,
+ internal::conj(m_c * internal::conj(other.m_s) + internal::conj(m_s) * internal::conj(other.m_c)));
+ }
+
+ /** Returns the transposed transformation */
+ JacobiRotation transpose() const { return JacobiRotation(m_c, -internal::conj(m_s)); }
+
+ /** Returns the adjoint transformation */
+ JacobiRotation adjoint() const { return JacobiRotation(internal::conj(m_c), -m_s); }
+
+ template<typename Derived>
+ bool makeJacobi(const MatrixBase<Derived>&, typename Derived::Index p, typename Derived::Index q);
+ bool makeJacobi(RealScalar x, Scalar y, RealScalar z);
+
+ void makeGivens(const Scalar& p, const Scalar& q, Scalar* z=0);
+
+ protected:
+ void makeGivens(const Scalar& p, const Scalar& q, Scalar* z, internal::true_type);
+ void makeGivens(const Scalar& p, const Scalar& q, Scalar* z, internal::false_type);
+
+ Scalar m_c, m_s;
+};
+
+/** Makes \c *this as a Jacobi rotation \a J such that applying \a J on both the right and left sides of the selfadjoint 2x2 matrix
+ * \f$ B = \left ( \begin{array}{cc} x & y \\ \overline y & z \end{array} \right )\f$ yields a diagonal matrix \f$ A = J^* B J \f$
+ *
+ * \sa MatrixBase::makeJacobi(const MatrixBase<Derived>&, Index, Index), MatrixBase::applyOnTheLeft(), MatrixBase::applyOnTheRight()
+ */
+template<typename Scalar>
+bool JacobiRotation<Scalar>::makeJacobi(RealScalar x, Scalar y, RealScalar z)
+{
+ typedef typename NumTraits<Scalar>::Real RealScalar;
+ if(y == Scalar(0))
+ {
+ m_c = Scalar(1);
+ m_s = Scalar(0);
+ return false;
+ }
+ else
+ {
+ RealScalar tau = (x-z)/(RealScalar(2)*internal::abs(y));
+ RealScalar w = internal::sqrt(internal::abs2(tau) + RealScalar(1));
+ RealScalar t;
+ if(tau>RealScalar(0))
+ {
+ t = RealScalar(1) / (tau + w);
+ }
+ else
+ {
+ t = RealScalar(1) / (tau - w);
+ }
+ RealScalar sign_t = t > RealScalar(0) ? RealScalar(1) : RealScalar(-1);
+ RealScalar n = RealScalar(1) / internal::sqrt(internal::abs2(t)+RealScalar(1));
+ m_s = - sign_t * (internal::conj(y) / internal::abs(y)) * internal::abs(t) * n;
+ m_c = n;
+ return true;
+ }
+}
+
+/** Makes \c *this as a Jacobi rotation \c J such that applying \a J on both the right and left sides of the 2x2 selfadjoint matrix
+ * \f$ B = \left ( \begin{array}{cc} \text{this}_{pp} & \text{this}_{pq} \\ (\text{this}_{pq})^* & \text{this}_{qq} \end{array} \right )\f$ yields
+ * a diagonal matrix \f$ A = J^* B J \f$
+ *
+ * Example: \include Jacobi_makeJacobi.cpp
+ * Output: \verbinclude Jacobi_makeJacobi.out
+ *
+ * \sa JacobiRotation::makeJacobi(RealScalar, Scalar, RealScalar), MatrixBase::applyOnTheLeft(), MatrixBase::applyOnTheRight()
+ */
+template<typename Scalar>
+template<typename Derived>
+inline bool JacobiRotation<Scalar>::makeJacobi(const MatrixBase<Derived>& m, typename Derived::Index p, typename Derived::Index q)
+{
+ return makeJacobi(internal::real(m.coeff(p,p)), m.coeff(p,q), internal::real(m.coeff(q,q)));
+}
+
+/** Makes \c *this as a Givens rotation \c G such that applying \f$ G^* \f$ to the left of the vector
+ * \f$ V = \left ( \begin{array}{c} p \\ q \end{array} \right )\f$ yields:
+ * \f$ G^* V = \left ( \begin{array}{c} r \\ 0 \end{array} \right )\f$.
+ *
+ * The value of \a z is returned if \a z is not null (the default is null).
+ * Also note that G is built such that the cosine is always real.
+ *
+ * Example: \include Jacobi_makeGivens.cpp
+ * Output: \verbinclude Jacobi_makeGivens.out
+ *
+ * This function implements the continuous Givens rotation generation algorithm
+ * found in Anderson (2000), Discontinuous Plane Rotations and the Symmetric Eigenvalue Problem.
+ * LAPACK Working Note 150, University of Tennessee, UT-CS-00-454, December 4, 2000.
+ *
+ * \sa MatrixBase::applyOnTheLeft(), MatrixBase::applyOnTheRight()
+ */
+template<typename Scalar>
+void JacobiRotation<Scalar>::makeGivens(const Scalar& p, const Scalar& q, Scalar* z)
+{
+ makeGivens(p, q, z, typename internal::conditional<NumTraits<Scalar>::IsComplex, internal::true_type, internal::false_type>::type());
+}
+
+
+// specialization for complexes
+template<typename Scalar>
+void JacobiRotation<Scalar>::makeGivens(const Scalar& p, const Scalar& q, Scalar* r, internal::true_type)
+{
+ if(q==Scalar(0))
+ {
+ m_c = internal::real(p)<0 ? Scalar(-1) : Scalar(1);
+ m_s = 0;
+ if(r) *r = m_c * p;
+ }
+ else if(p==Scalar(0))
+ {
+ m_c = 0;
+ m_s = -q/internal::abs(q);
+ if(r) *r = internal::abs(q);
+ }
+ else
+ {
+ RealScalar p1 = internal::norm1(p);
+ RealScalar q1 = internal::norm1(q);
+ if(p1>=q1)
+ {
+ Scalar ps = p / p1;
+ RealScalar p2 = internal::abs2(ps);
+ Scalar qs = q / p1;
+ RealScalar q2 = internal::abs2(qs);
+
+ RealScalar u = internal::sqrt(RealScalar(1) + q2/p2);
+ if(internal::real(p)<RealScalar(0))
+ u = -u;
+
+ m_c = Scalar(1)/u;
+ m_s = -qs*internal::conj(ps)*(m_c/p2);
+ if(r) *r = p * u;
+ }
+ else
+ {
+ Scalar ps = p / q1;
+ RealScalar p2 = internal::abs2(ps);
+ Scalar qs = q / q1;
+ RealScalar q2 = internal::abs2(qs);
+
+ RealScalar u = q1 * internal::sqrt(p2 + q2);
+ if(internal::real(p)<RealScalar(0))
+ u = -u;
+
+ p1 = internal::abs(p);
+ ps = p/p1;
+ m_c = p1/u;
+ m_s = -internal::conj(ps) * (q/u);
+ if(r) *r = ps * u;
+ }
+ }
+}
+
+// specialization for reals
+template<typename Scalar>
+void JacobiRotation<Scalar>::makeGivens(const Scalar& p, const Scalar& q, Scalar* r, internal::false_type)
+{
+
+ if(q==Scalar(0))
+ {
+ m_c = p<Scalar(0) ? Scalar(-1) : Scalar(1);
+ m_s = Scalar(0);
+ if(r) *r = internal::abs(p);
+ }
+ else if(p==Scalar(0))
+ {
+ m_c = Scalar(0);
+ m_s = q<Scalar(0) ? Scalar(1) : Scalar(-1);
+ if(r) *r = internal::abs(q);
+ }
+ else if(internal::abs(p) > internal::abs(q))
+ {
+ Scalar t = q/p;
+ Scalar u = internal::sqrt(Scalar(1) + internal::abs2(t));
+ if(p<Scalar(0))
+ u = -u;
+ m_c = Scalar(1)/u;
+ m_s = -t * m_c;
+ if(r) *r = p * u;
+ }
+ else
+ {
+ Scalar t = p/q;
+ Scalar u = internal::sqrt(Scalar(1) + internal::abs2(t));
+ if(q<Scalar(0))
+ u = -u;
+ m_s = -Scalar(1)/u;
+ m_c = -t * m_s;
+ if(r) *r = q * u;
+ }
+
+}
+
+/****************************************************************************************
+* Implementation of MatrixBase methods
+****************************************************************************************/
+
+/** \jacobi_module
+ * Applies the clock wise 2D rotation \a j to the set of 2D vectors of cordinates \a x and \a y:
+ * \f$ \left ( \begin{array}{cc} x \\ y \end{array} \right ) = J \left ( \begin{array}{cc} x \\ y \end{array} \right ) \f$
+ *
+ * \sa MatrixBase::applyOnTheLeft(), MatrixBase::applyOnTheRight()
+ */
+namespace internal {
+template<typename VectorX, typename VectorY, typename OtherScalar>
+void apply_rotation_in_the_plane(VectorX& _x, VectorY& _y, const JacobiRotation<OtherScalar>& j);
+}
+
+/** \jacobi_module
+ * Applies the rotation in the plane \a j to the rows \a p and \a q of \c *this, i.e., it computes B = J * B,
+ * with \f$ B = \left ( \begin{array}{cc} \text{*this.row}(p) \\ \text{*this.row}(q) \end{array} \right ) \f$.
+ *
+ * \sa class JacobiRotation, MatrixBase::applyOnTheRight(), internal::apply_rotation_in_the_plane()
+ */
+template<typename Derived>
+template<typename OtherScalar>
+inline void MatrixBase<Derived>::applyOnTheLeft(Index p, Index q, const JacobiRotation<OtherScalar>& j)
+{
+ RowXpr x(this->row(p));
+ RowXpr y(this->row(q));
+ internal::apply_rotation_in_the_plane(x, y, j);
+}
+
+/** \ingroup Jacobi_Module
+ * Applies the rotation in the plane \a j to the columns \a p and \a q of \c *this, i.e., it computes B = B * J
+ * with \f$ B = \left ( \begin{array}{cc} \text{*this.col}(p) & \text{*this.col}(q) \end{array} \right ) \f$.
+ *
+ * \sa class JacobiRotation, MatrixBase::applyOnTheLeft(), internal::apply_rotation_in_the_plane()
+ */
+template<typename Derived>
+template<typename OtherScalar>
+inline void MatrixBase<Derived>::applyOnTheRight(Index p, Index q, const JacobiRotation<OtherScalar>& j)
+{
+ ColXpr x(this->col(p));
+ ColXpr y(this->col(q));
+ internal::apply_rotation_in_the_plane(x, y, j.transpose());
+}
+
+namespace internal {
+template<typename VectorX, typename VectorY, typename OtherScalar>
+void /*EIGEN_DONT_INLINE*/ apply_rotation_in_the_plane(VectorX& _x, VectorY& _y, const JacobiRotation<OtherScalar>& j)
+{
+ typedef typename VectorX::Index Index;
+ typedef typename VectorX::Scalar Scalar;
+ enum { PacketSize = packet_traits<Scalar>::size };
+ typedef typename packet_traits<Scalar>::type Packet;
+ eigen_assert(_x.size() == _y.size());
+ Index size = _x.size();
+ Index incrx = _x.innerStride();
+ Index incry = _y.innerStride();
+
+ Scalar* EIGEN_RESTRICT x = &_x.coeffRef(0);
+ Scalar* EIGEN_RESTRICT y = &_y.coeffRef(0);
+
+ /*** dynamic-size vectorized paths ***/
+
+ if(VectorX::SizeAtCompileTime == Dynamic &&
+ (VectorX::Flags & VectorY::Flags & PacketAccessBit) &&
+ ((incrx==1 && incry==1) || PacketSize == 1))
+ {
+ // both vectors are sequentially stored in memory => vectorization
+ enum { Peeling = 2 };
+
+ Index alignedStart = internal::first_aligned(y, size);
+ Index alignedEnd = alignedStart + ((size-alignedStart)/PacketSize)*PacketSize;
+
+ const Packet pc = pset1<Packet>(j.c());
+ const Packet ps = pset1<Packet>(j.s());
+ conj_helper<Packet,Packet,NumTraits<Scalar>::IsComplex,false> pcj;
+
+ for(Index i=0; i<alignedStart; ++i)
+ {
+ Scalar xi = x[i];
+ Scalar yi = y[i];
+ x[i] = j.c() * xi + conj(j.s()) * yi;
+ y[i] = -j.s() * xi + conj(j.c()) * yi;
+ }
+
+ Scalar* EIGEN_RESTRICT px = x + alignedStart;
+ Scalar* EIGEN_RESTRICT py = y + alignedStart;
+
+ if(internal::first_aligned(x, size)==alignedStart)
+ {
+ for(Index i=alignedStart; i<alignedEnd; i+=PacketSize)
+ {
+ Packet xi = pload<Packet>(px);
+ Packet yi = pload<Packet>(py);
+ pstore(px, padd(pmul(pc,xi),pcj.pmul(ps,yi)));
+ pstore(py, psub(pcj.pmul(pc,yi),pmul(ps,xi)));
+ px += PacketSize;
+ py += PacketSize;
+ }
+ }
+ else
+ {
+ Index peelingEnd = alignedStart + ((size-alignedStart)/(Peeling*PacketSize))*(Peeling*PacketSize);
+ for(Index i=alignedStart; i<peelingEnd; i+=Peeling*PacketSize)
+ {
+ Packet xi = ploadu<Packet>(px);
+ Packet xi1 = ploadu<Packet>(px+PacketSize);
+ Packet yi = pload <Packet>(py);
+ Packet yi1 = pload <Packet>(py+PacketSize);
+ pstoreu(px, padd(pmul(pc,xi),pcj.pmul(ps,yi)));
+ pstoreu(px+PacketSize, padd(pmul(pc,xi1),pcj.pmul(ps,yi1)));
+ pstore (py, psub(pcj.pmul(pc,yi),pmul(ps,xi)));
+ pstore (py+PacketSize, psub(pcj.pmul(pc,yi1),pmul(ps,xi1)));
+ px += Peeling*PacketSize;
+ py += Peeling*PacketSize;
+ }
+ if(alignedEnd!=peelingEnd)
+ {
+ Packet xi = ploadu<Packet>(x+peelingEnd);
+ Packet yi = pload <Packet>(y+peelingEnd);
+ pstoreu(x+peelingEnd, padd(pmul(pc,xi),pcj.pmul(ps,yi)));
+ pstore (y+peelingEnd, psub(pcj.pmul(pc,yi),pmul(ps,xi)));
+ }
+ }
+
+ for(Index i=alignedEnd; i<size; ++i)
+ {
+ Scalar xi = x[i];
+ Scalar yi = y[i];
+ x[i] = j.c() * xi + conj(j.s()) * yi;
+ y[i] = -j.s() * xi + conj(j.c()) * yi;
+ }
+ }
+
+ /*** fixed-size vectorized path ***/
+ else if(VectorX::SizeAtCompileTime != Dynamic &&
+ (VectorX::Flags & VectorY::Flags & PacketAccessBit) &&
+ (VectorX::Flags & VectorY::Flags & AlignedBit))
+ {
+ const Packet pc = pset1<Packet>(j.c());
+ const Packet ps = pset1<Packet>(j.s());
+ conj_helper<Packet,Packet,NumTraits<Scalar>::IsComplex,false> pcj;
+ Scalar* EIGEN_RESTRICT px = x;
+ Scalar* EIGEN_RESTRICT py = y;
+ for(Index i=0; i<size; i+=PacketSize)
+ {
+ Packet xi = pload<Packet>(px);
+ Packet yi = pload<Packet>(py);
+ pstore(px, padd(pmul(pc,xi),pcj.pmul(ps,yi)));
+ pstore(py, psub(pcj.pmul(pc,yi),pmul(ps,xi)));
+ px += PacketSize;
+ py += PacketSize;
+ }
+ }
+
+ /*** non-vectorized path ***/
+ else
+ {
+ for(Index i=0; i<size; ++i)
+ {
+ Scalar xi = *x;
+ Scalar yi = *y;
+ *x = j.c() * xi + conj(j.s()) * yi;
+ *y = -j.s() * xi + conj(j.c()) * yi;
+ x += incrx;
+ y += incry;
+ }
+ }
+}
+
+} // end namespace internal
+
+} // end namespace Eigen
+
+#endif // EIGEN_JACOBI_H
diff --git a/Eigen/src/LU/CMakeLists.txt b/Eigen/src/LU/CMakeLists.txt
new file mode 100644
index 000000000..e0d8d78c1
--- /dev/null
+++ b/Eigen/src/LU/CMakeLists.txt
@@ -0,0 +1,8 @@
+FILE(GLOB Eigen_LU_SRCS "*.h")
+
+INSTALL(FILES
+ ${Eigen_LU_SRCS}
+ DESTINATION ${INCLUDE_INSTALL_DIR}/Eigen/src/LU COMPONENT Devel
+ )
+
+ADD_SUBDIRECTORY(arch)
diff --git a/Eigen/src/LU/Determinant.h b/Eigen/src/LU/Determinant.h
new file mode 100644
index 000000000..d862c5d77
--- /dev/null
+++ b/Eigen/src/LU/Determinant.h
@@ -0,0 +1,101 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra.
+//
+// Copyright (C) 2008 Benoit Jacob <jacob.benoit.1@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 EIGEN_DETERMINANT_H
+#define EIGEN_DETERMINANT_H
+
+namespace Eigen {
+
+namespace internal {
+
+template<typename Derived>
+inline const typename Derived::Scalar bruteforce_det3_helper
+(const MatrixBase<Derived>& matrix, int a, int b, int c)
+{
+ return matrix.coeff(0,a)
+ * (matrix.coeff(1,b) * matrix.coeff(2,c) - matrix.coeff(1,c) * matrix.coeff(2,b));
+}
+
+template<typename Derived>
+const typename Derived::Scalar bruteforce_det4_helper
+(const MatrixBase<Derived>& matrix, int j, int k, int m, int n)
+{
+ return (matrix.coeff(j,0) * matrix.coeff(k,1) - matrix.coeff(k,0) * matrix.coeff(j,1))
+ * (matrix.coeff(m,2) * matrix.coeff(n,3) - matrix.coeff(n,2) * matrix.coeff(m,3));
+}
+
+template<typename Derived,
+ int DeterminantType = Derived::RowsAtCompileTime
+> struct determinant_impl
+{
+ static inline typename traits<Derived>::Scalar run(const Derived& m)
+ {
+ if(Derived::ColsAtCompileTime==Dynamic && m.rows()==0)
+ return typename traits<Derived>::Scalar(1);
+ return m.partialPivLu().determinant();
+ }
+};
+
+template<typename Derived> struct determinant_impl<Derived, 1>
+{
+ static inline typename traits<Derived>::Scalar run(const Derived& m)
+ {
+ return m.coeff(0,0);
+ }
+};
+
+template<typename Derived> struct determinant_impl<Derived, 2>
+{
+ static inline typename traits<Derived>::Scalar run(const Derived& m)
+ {
+ return m.coeff(0,0) * m.coeff(1,1) - m.coeff(1,0) * m.coeff(0,1);
+ }
+};
+
+template<typename Derived> struct determinant_impl<Derived, 3>
+{
+ static inline typename traits<Derived>::Scalar run(const Derived& m)
+ {
+ return bruteforce_det3_helper(m,0,1,2)
+ - bruteforce_det3_helper(m,1,0,2)
+ + bruteforce_det3_helper(m,2,0,1);
+ }
+};
+
+template<typename Derived> struct determinant_impl<Derived, 4>
+{
+ static typename traits<Derived>::Scalar run(const Derived& m)
+ {
+ // trick by Martin Costabel to compute 4x4 det with only 30 muls
+ return bruteforce_det4_helper(m,0,1,2,3)
+ - bruteforce_det4_helper(m,0,2,1,3)
+ + bruteforce_det4_helper(m,0,3,1,2)
+ + bruteforce_det4_helper(m,1,2,0,3)
+ - bruteforce_det4_helper(m,1,3,0,2)
+ + bruteforce_det4_helper(m,2,3,0,1);
+ }
+};
+
+} // end namespace internal
+
+/** \lu_module
+ *
+ * \returns the determinant of this matrix
+ */
+template<typename Derived>
+inline typename internal::traits<Derived>::Scalar MatrixBase<Derived>::determinant() const
+{
+ assert(rows() == cols());
+ typedef typename internal::nested<Derived,Base::RowsAtCompileTime>::type Nested;
+ return internal::determinant_impl<typename internal::remove_all<Nested>::type>::run(derived());
+}
+
+} // end namespace Eigen
+
+#endif // EIGEN_DETERMINANT_H
diff --git a/Eigen/src/LU/FullPivLU.h b/Eigen/src/LU/FullPivLU.h
new file mode 100644
index 000000000..e23f96cdc
--- /dev/null
+++ b/Eigen/src/LU/FullPivLU.h
@@ -0,0 +1,736 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra.
+//
+// Copyright (C) 2006-2009 Benoit Jacob <jacob.benoit.1@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 EIGEN_LU_H
+#define EIGEN_LU_H
+
+namespace Eigen {
+
+/** \ingroup LU_Module
+ *
+ * \class FullPivLU
+ *
+ * \brief LU decomposition of a matrix with complete pivoting, and related features
+ *
+ * \param MatrixType the type of the matrix of which we are computing the LU decomposition
+ *
+ * This class represents a LU decomposition of any matrix, with complete pivoting: the matrix A
+ * is decomposed as A = PLUQ where L is unit-lower-triangular, U is upper-triangular, and P and Q
+ * are permutation matrices. This is a rank-revealing LU decomposition. The eigenvalues (diagonal
+ * coefficients) of U are sorted in such a way that any zeros are at the end.
+ *
+ * This decomposition provides the generic approach to solving systems of linear equations, computing
+ * the rank, invertibility, inverse, kernel, and determinant.
+ *
+ * This LU decomposition is very stable and well tested with large matrices. However there are use cases where the SVD
+ * decomposition is inherently more stable and/or flexible. For example, when computing the kernel of a matrix,
+ * working with the SVD allows to select the smallest singular values of the matrix, something that
+ * the LU decomposition doesn't see.
+ *
+ * The data of the LU decomposition can be directly accessed through the methods matrixLU(),
+ * permutationP(), permutationQ().
+ *
+ * As an exemple, here is how the original matrix can be retrieved:
+ * \include class_FullPivLU.cpp
+ * Output: \verbinclude class_FullPivLU.out
+ *
+ * \sa MatrixBase::fullPivLu(), MatrixBase::determinant(), MatrixBase::inverse()
+ */
+template<typename _MatrixType> class FullPivLU
+{
+ public:
+ typedef _MatrixType MatrixType;
+ enum {
+ RowsAtCompileTime = MatrixType::RowsAtCompileTime,
+ ColsAtCompileTime = MatrixType::ColsAtCompileTime,
+ Options = MatrixType::Options,
+ MaxRowsAtCompileTime = MatrixType::MaxRowsAtCompileTime,
+ MaxColsAtCompileTime = MatrixType::MaxColsAtCompileTime
+ };
+ typedef typename MatrixType::Scalar Scalar;
+ typedef typename NumTraits<typename MatrixType::Scalar>::Real RealScalar;
+ typedef typename internal::traits<MatrixType>::StorageKind StorageKind;
+ typedef typename MatrixType::Index Index;
+ typedef typename internal::plain_row_type<MatrixType, Index>::type IntRowVectorType;
+ typedef typename internal::plain_col_type<MatrixType, Index>::type IntColVectorType;
+ typedef PermutationMatrix<ColsAtCompileTime, MaxColsAtCompileTime> PermutationQType;
+ typedef PermutationMatrix<RowsAtCompileTime, MaxRowsAtCompileTime> PermutationPType;
+
+ /**
+ * \brief Default Constructor.
+ *
+ * The default constructor is useful in cases in which the user intends to
+ * perform decompositions via LU::compute(const MatrixType&).
+ */
+ FullPivLU();
+
+ /** \brief Default Constructor with memory preallocation
+ *
+ * Like the default constructor but with preallocation of the internal data
+ * according to the specified problem \a size.
+ * \sa FullPivLU()
+ */
+ FullPivLU(Index rows, Index cols);
+
+ /** Constructor.
+ *
+ * \param matrix the matrix of which to compute the LU decomposition.
+ * It is required to be nonzero.
+ */
+ FullPivLU(const MatrixType& matrix);
+
+ /** Computes the LU decomposition of the given matrix.
+ *
+ * \param matrix the matrix of which to compute the LU decomposition.
+ * It is required to be nonzero.
+ *
+ * \returns a reference to *this
+ */
+ FullPivLU& compute(const MatrixType& matrix);
+
+ /** \returns the LU decomposition matrix: the upper-triangular part is U, the
+ * unit-lower-triangular part is L (at least for square matrices; in the non-square
+ * case, special care is needed, see the documentation of class FullPivLU).
+ *
+ * \sa matrixL(), matrixU()
+ */
+ inline const MatrixType& matrixLU() const
+ {
+ eigen_assert(m_isInitialized && "LU is not initialized.");
+ return m_lu;
+ }
+
+ /** \returns the number of nonzero pivots in the LU decomposition.
+ * Here nonzero is meant in the exact sense, not in a fuzzy sense.
+ * So that notion isn't really intrinsically interesting, but it is
+ * still useful when implementing algorithms.
+ *
+ * \sa rank()
+ */
+ inline Index nonzeroPivots() const
+ {
+ eigen_assert(m_isInitialized && "LU is not initialized.");
+ return m_nonzero_pivots;
+ }
+
+ /** \returns the absolute value of the biggest pivot, i.e. the biggest
+ * diagonal coefficient of U.
+ */
+ RealScalar maxPivot() const { return m_maxpivot; }
+
+ /** \returns the permutation matrix P
+ *
+ * \sa permutationQ()
+ */
+ inline const PermutationPType& permutationP() const
+ {
+ eigen_assert(m_isInitialized && "LU is not initialized.");
+ return m_p;
+ }
+
+ /** \returns the permutation matrix Q
+ *
+ * \sa permutationP()
+ */
+ inline const PermutationQType& permutationQ() const
+ {
+ eigen_assert(m_isInitialized && "LU is not initialized.");
+ return m_q;
+ }
+
+ /** \returns the kernel of the matrix, also called its null-space. The columns of the returned matrix
+ * will form a basis of the kernel.
+ *
+ * \note If the kernel has dimension zero, then the returned matrix is a column-vector filled with zeros.
+ *
+ * \note This method has to determine which pivots should be considered nonzero.
+ * For that, it uses the threshold value that you can control by calling
+ * setThreshold(const RealScalar&).
+ *
+ * Example: \include FullPivLU_kernel.cpp
+ * Output: \verbinclude FullPivLU_kernel.out
+ *
+ * \sa image()
+ */
+ inline const internal::kernel_retval<FullPivLU> kernel() const
+ {
+ eigen_assert(m_isInitialized && "LU is not initialized.");
+ return internal::kernel_retval<FullPivLU>(*this);
+ }
+
+ /** \returns the image of the matrix, also called its column-space. The columns of the returned matrix
+ * will form a basis of the kernel.
+ *
+ * \param originalMatrix the original matrix, of which *this is the LU decomposition.
+ * The reason why it is needed to pass it here, is that this allows
+ * a large optimization, as otherwise this method would need to reconstruct it
+ * from the LU decomposition.
+ *
+ * \note If the image has dimension zero, then the returned matrix is a column-vector filled with zeros.
+ *
+ * \note This method has to determine which pivots should be considered nonzero.
+ * For that, it uses the threshold value that you can control by calling
+ * setThreshold(const RealScalar&).
+ *
+ * Example: \include FullPivLU_image.cpp
+ * Output: \verbinclude FullPivLU_image.out
+ *
+ * \sa kernel()
+ */
+ inline const internal::image_retval<FullPivLU>
+ image(const MatrixType& originalMatrix) const
+ {
+ eigen_assert(m_isInitialized && "LU is not initialized.");
+ return internal::image_retval<FullPivLU>(*this, originalMatrix);
+ }
+
+ /** \return a solution x to the equation Ax=b, where A is the matrix of which
+ * *this is the LU decomposition.
+ *
+ * \param b the right-hand-side of the equation to solve. Can be a vector or a matrix,
+ * the only requirement in order for the equation to make sense is that
+ * b.rows()==A.rows(), where A is the matrix of which *this is the LU decomposition.
+ *
+ * \returns a solution.
+ *
+ * \note_about_checking_solutions
+ *
+ * \note_about_arbitrary_choice_of_solution
+ * \note_about_using_kernel_to_study_multiple_solutions
+ *
+ * Example: \include FullPivLU_solve.cpp
+ * Output: \verbinclude FullPivLU_solve.out
+ *
+ * \sa TriangularView::solve(), kernel(), inverse()
+ */
+ template<typename Rhs>
+ inline const internal::solve_retval<FullPivLU, Rhs>
+ solve(const MatrixBase<Rhs>& b) const
+ {
+ eigen_assert(m_isInitialized && "LU is not initialized.");
+ return internal::solve_retval<FullPivLU, Rhs>(*this, b.derived());
+ }
+
+ /** \returns the determinant of the matrix of which
+ * *this is the LU decomposition. It has only linear complexity
+ * (that is, O(n) where n is the dimension of the square matrix)
+ * as the LU decomposition has already been computed.
+ *
+ * \note This is only for square matrices.
+ *
+ * \note For fixed-size matrices of size up to 4, MatrixBase::determinant() offers
+ * optimized paths.
+ *
+ * \warning a determinant can be very big or small, so for matrices
+ * of large enough dimension, there is a risk of overflow/underflow.
+ *
+ * \sa MatrixBase::determinant()
+ */
+ typename internal::traits<MatrixType>::Scalar determinant() const;
+
+ /** Allows to prescribe a threshold to be used by certain methods, such as rank(),
+ * who need to determine when pivots are to be considered nonzero. This is not used for the
+ * LU decomposition itself.
+ *
+ * When it needs to get the threshold value, Eigen calls threshold(). By default, this
+ * uses a formula to automatically determine a reasonable threshold.
+ * Once you have called the present method setThreshold(const RealScalar&),
+ * your value is used instead.
+ *
+ * \param threshold The new value to use as the threshold.
+ *
+ * A pivot will be considered nonzero if its absolute value is strictly greater than
+ * \f$ \vert pivot \vert \leqslant threshold \times \vert maxpivot \vert \f$
+ * where maxpivot is the biggest pivot.
+ *
+ * If you want to come back to the default behavior, call setThreshold(Default_t)
+ */
+ FullPivLU& 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 lu.setThreshold(Eigen::Default); \endcode
+ *
+ * See the documentation of setThreshold(const RealScalar&).
+ */
+ FullPivLU& 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
+ // this formula comes from experimenting (see "LU precision tuning" thread on the list)
+ // and turns out to be identical to Higham's formula used already in LDLt.
+ : NumTraits<Scalar>::epsilon() * m_lu.diagonalSize();
+ }
+
+ /** \returns the rank of the matrix of which *this is the LU decomposition.
+ *
+ * \note This method has to determine which pivots should be considered nonzero.
+ * For that, it uses the threshold value that you can control by calling
+ * setThreshold(const RealScalar&).
+ */
+ inline Index rank() const
+ {
+ eigen_assert(m_isInitialized && "LU is not initialized.");
+ RealScalar premultiplied_threshold = internal::abs(m_maxpivot) * threshold();
+ Index result = 0;
+ for(Index i = 0; i < m_nonzero_pivots; ++i)
+ result += (internal::abs(m_lu.coeff(i,i)) > premultiplied_threshold);
+ return result;
+ }
+
+ /** \returns the dimension of the kernel of the matrix of which *this is the LU decomposition.
+ *
+ * \note This method has to determine which pivots should be considered nonzero.
+ * For that, it uses the threshold value that you can control by calling
+ * setThreshold(const RealScalar&).
+ */
+ inline Index dimensionOfKernel() const
+ {
+ eigen_assert(m_isInitialized && "LU is not initialized.");
+ return cols() - rank();
+ }
+
+ /** \returns true if the matrix of which *this is the LU decomposition represents an injective
+ * linear map, i.e. has trivial kernel; false otherwise.
+ *
+ * \note This method has to determine which pivots should be considered nonzero.
+ * For that, it uses the threshold value that you can control by calling
+ * setThreshold(const RealScalar&).
+ */
+ inline bool isInjective() const
+ {
+ eigen_assert(m_isInitialized && "LU is not initialized.");
+ return rank() == cols();
+ }
+
+ /** \returns true if the matrix of which *this is the LU decomposition represents a surjective
+ * linear map; false otherwise.
+ *
+ * \note This method has to determine which pivots should be considered nonzero.
+ * For that, it uses the threshold value that you can control by calling
+ * setThreshold(const RealScalar&).
+ */
+ inline bool isSurjective() const
+ {
+ eigen_assert(m_isInitialized && "LU is not initialized.");
+ return rank() == rows();
+ }
+
+ /** \returns true if the matrix of which *this is the LU decomposition is invertible.
+ *
+ * \note This method has to determine which pivots should be considered nonzero.
+ * For that, it uses the threshold value that you can control by calling
+ * setThreshold(const RealScalar&).
+ */
+ inline bool isInvertible() const
+ {
+ eigen_assert(m_isInitialized && "LU is not initialized.");
+ return isInjective() && (m_lu.rows() == m_lu.cols());
+ }
+
+ /** \returns the inverse of the matrix of which *this is the LU decomposition.
+ *
+ * \note If this matrix is not invertible, the returned matrix has undefined coefficients.
+ * Use isInvertible() to first determine whether this matrix is invertible.
+ *
+ * \sa MatrixBase::inverse()
+ */
+ inline const internal::solve_retval<FullPivLU,typename MatrixType::IdentityReturnType> inverse() const
+ {
+ eigen_assert(m_isInitialized && "LU is not initialized.");
+ eigen_assert(m_lu.rows() == m_lu.cols() && "You can't take the inverse of a non-square matrix!");
+ return internal::solve_retval<FullPivLU,typename MatrixType::IdentityReturnType>
+ (*this, MatrixType::Identity(m_lu.rows(), m_lu.cols()));
+ }
+
+ MatrixType reconstructedMatrix() const;
+
+ inline Index rows() const { return m_lu.rows(); }
+ inline Index cols() const { return m_lu.cols(); }
+
+ protected:
+ MatrixType m_lu;
+ PermutationPType m_p;
+ PermutationQType m_q;
+ IntColVectorType m_rowsTranspositions;
+ IntRowVectorType m_colsTranspositions;
+ Index m_det_pq, m_nonzero_pivots;
+ RealScalar m_maxpivot, m_prescribedThreshold;
+ bool m_isInitialized, m_usePrescribedThreshold;
+};
+
+template<typename MatrixType>
+FullPivLU<MatrixType>::FullPivLU()
+ : m_isInitialized(false), m_usePrescribedThreshold(false)
+{
+}
+
+template<typename MatrixType>
+FullPivLU<MatrixType>::FullPivLU(Index rows, Index cols)
+ : m_lu(rows, cols),
+ m_p(rows),
+ m_q(cols),
+ m_rowsTranspositions(rows),
+ m_colsTranspositions(cols),
+ m_isInitialized(false),
+ m_usePrescribedThreshold(false)
+{
+}
+
+template<typename MatrixType>
+FullPivLU<MatrixType>::FullPivLU(const MatrixType& matrix)
+ : m_lu(matrix.rows(), matrix.cols()),
+ m_p(matrix.rows()),
+ m_q(matrix.cols()),
+ m_rowsTranspositions(matrix.rows()),
+ m_colsTranspositions(matrix.cols()),
+ m_isInitialized(false),
+ m_usePrescribedThreshold(false)
+{
+ compute(matrix);
+}
+
+template<typename MatrixType>
+FullPivLU<MatrixType>& FullPivLU<MatrixType>::compute(const MatrixType& matrix)
+{
+ m_isInitialized = true;
+ m_lu = matrix;
+
+ const Index size = matrix.diagonalSize();
+ const Index rows = matrix.rows();
+ const Index cols = matrix.cols();
+
+ // will store the transpositions, before we accumulate them at the end.
+ // can't accumulate on-the-fly because that will be done in reverse order for the rows.
+ m_rowsTranspositions.resize(matrix.rows());
+ m_colsTranspositions.resize(matrix.cols());
+ Index number_of_transpositions = 0; // number of NONTRIVIAL transpositions, i.e. m_rowsTranspositions[i]!=i
+
+ m_nonzero_pivots = size; // the generic case is that in which all pivots are nonzero (invertible case)
+ m_maxpivot = RealScalar(0);
+
+ for(Index k = 0; k < size; ++k)
+ {
+ // First, we need to find the pivot.
+
+ // biggest coefficient in the remaining bottom-right corner (starting at row k, col k)
+ Index row_of_biggest_in_corner, col_of_biggest_in_corner;
+ RealScalar biggest_in_corner;
+ biggest_in_corner = m_lu.bottomRightCorner(rows-k, cols-k)
+ .cwiseAbs()
+ .maxCoeff(&row_of_biggest_in_corner, &col_of_biggest_in_corner);
+ row_of_biggest_in_corner += k; // correct the values! since they were computed in the corner,
+ col_of_biggest_in_corner += k; // need to add k to them.
+
+ if(biggest_in_corner==RealScalar(0))
+ {
+ // before exiting, make sure to initialize the still uninitialized transpositions
+ // in a sane state without destroying what we already have.
+ m_nonzero_pivots = k;
+ for(Index i = k; i < size; ++i)
+ {
+ m_rowsTranspositions.coeffRef(i) = i;
+ m_colsTranspositions.coeffRef(i) = i;
+ }
+ break;
+ }
+
+ if(biggest_in_corner > m_maxpivot) m_maxpivot = biggest_in_corner;
+
+ // Now that we've found the pivot, we need to apply the row/col swaps to
+ // bring it to the location (k,k).
+
+ m_rowsTranspositions.coeffRef(k) = row_of_biggest_in_corner;
+ m_colsTranspositions.coeffRef(k) = col_of_biggest_in_corner;
+ if(k != row_of_biggest_in_corner) {
+ m_lu.row(k).swap(m_lu.row(row_of_biggest_in_corner));
+ ++number_of_transpositions;
+ }
+ if(k != col_of_biggest_in_corner) {
+ m_lu.col(k).swap(m_lu.col(col_of_biggest_in_corner));
+ ++number_of_transpositions;
+ }
+
+ // Now that the pivot is at the right location, we update the remaining
+ // bottom-right corner by Gaussian elimination.
+
+ if(k<rows-1)
+ m_lu.col(k).tail(rows-k-1) /= m_lu.coeff(k,k);
+ if(k<size-1)
+ m_lu.block(k+1,k+1,rows-k-1,cols-k-1).noalias() -= m_lu.col(k).tail(rows-k-1) * m_lu.row(k).tail(cols-k-1);
+ }
+
+ // the main loop is over, we still have to accumulate the transpositions to find the
+ // permutations P and Q
+
+ m_p.setIdentity(rows);
+ for(Index k = size-1; k >= 0; --k)
+ m_p.applyTranspositionOnTheRight(k, m_rowsTranspositions.coeff(k));
+
+ m_q.setIdentity(cols);
+ for(Index k = 0; k < size; ++k)
+ m_q.applyTranspositionOnTheRight(k, m_colsTranspositions.coeff(k));
+
+ m_det_pq = (number_of_transpositions%2) ? -1 : 1;
+ return *this;
+}
+
+template<typename MatrixType>
+typename internal::traits<MatrixType>::Scalar FullPivLU<MatrixType>::determinant() const
+{
+ eigen_assert(m_isInitialized && "LU is not initialized.");
+ eigen_assert(m_lu.rows() == m_lu.cols() && "You can't take the determinant of a non-square matrix!");
+ return Scalar(m_det_pq) * Scalar(m_lu.diagonal().prod());
+}
+
+/** \returns the matrix represented by the decomposition,
+ * i.e., it returns the product: P^{-1} L U Q^{-1}.
+ * This function is provided for debug purpose. */
+template<typename MatrixType>
+MatrixType FullPivLU<MatrixType>::reconstructedMatrix() const
+{
+ eigen_assert(m_isInitialized && "LU is not initialized.");
+ const Index smalldim = (std::min)(m_lu.rows(), m_lu.cols());
+ // LU
+ MatrixType res(m_lu.rows(),m_lu.cols());
+ // FIXME the .toDenseMatrix() should not be needed...
+ res = m_lu.leftCols(smalldim)
+ .template triangularView<UnitLower>().toDenseMatrix()
+ * m_lu.topRows(smalldim)
+ .template triangularView<Upper>().toDenseMatrix();
+
+ // P^{-1}(LU)
+ res = m_p.inverse() * res;
+
+ // (P^{-1}LU)Q^{-1}
+ res = res * m_q.inverse();
+
+ return res;
+}
+
+/********* Implementation of kernel() **************************************************/
+
+namespace internal {
+template<typename _MatrixType>
+struct kernel_retval<FullPivLU<_MatrixType> >
+ : kernel_retval_base<FullPivLU<_MatrixType> >
+{
+ EIGEN_MAKE_KERNEL_HELPERS(FullPivLU<_MatrixType>)
+
+ enum { MaxSmallDimAtCompileTime = EIGEN_SIZE_MIN_PREFER_FIXED(
+ MatrixType::MaxColsAtCompileTime,
+ MatrixType::MaxRowsAtCompileTime)
+ };
+
+ template<typename Dest> void evalTo(Dest& dst) const
+ {
+ const Index cols = dec().matrixLU().cols(), dimker = cols - rank();
+ if(dimker == 0)
+ {
+ // The Kernel is just {0}, so it doesn't have a basis properly speaking, but let's
+ // avoid crashing/asserting as that depends on floating point calculations. Let's
+ // just return a single column vector filled with zeros.
+ dst.setZero();
+ return;
+ }
+
+ /* Let us use the following lemma:
+ *
+ * Lemma: If the matrix A has the LU decomposition PAQ = LU,
+ * then Ker A = Q(Ker U).
+ *
+ * Proof: trivial: just keep in mind that P, Q, L are invertible.
+ */
+
+ /* Thus, all we need to do is to compute Ker U, and then apply Q.
+ *
+ * U is upper triangular, with eigenvalues sorted so that any zeros appear at the end.
+ * Thus, the diagonal of U ends with exactly
+ * dimKer zero's. Let us use that to construct dimKer linearly
+ * independent vectors in Ker U.
+ */
+
+ Matrix<Index, Dynamic, 1, 0, MaxSmallDimAtCompileTime, 1> pivots(rank());
+ RealScalar premultiplied_threshold = dec().maxPivot() * dec().threshold();
+ Index p = 0;
+ for(Index i = 0; i < dec().nonzeroPivots(); ++i)
+ if(abs(dec().matrixLU().coeff(i,i)) > premultiplied_threshold)
+ pivots.coeffRef(p++) = i;
+ eigen_internal_assert(p == rank());
+
+ // we construct a temporaty trapezoid matrix m, by taking the U matrix and
+ // permuting the rows and cols to bring the nonnegligible pivots to the top of
+ // the main diagonal. We need that to be able to apply our triangular solvers.
+ // FIXME when we get triangularView-for-rectangular-matrices, this can be simplified
+ Matrix<typename MatrixType::Scalar, Dynamic, Dynamic, MatrixType::Options,
+ MaxSmallDimAtCompileTime, MatrixType::MaxColsAtCompileTime>
+ m(dec().matrixLU().block(0, 0, rank(), cols));
+ for(Index i = 0; i < rank(); ++i)
+ {
+ if(i) m.row(i).head(i).setZero();
+ m.row(i).tail(cols-i) = dec().matrixLU().row(pivots.coeff(i)).tail(cols-i);
+ }
+ m.block(0, 0, rank(), rank());
+ m.block(0, 0, rank(), rank()).template triangularView<StrictlyLower>().setZero();
+ for(Index i = 0; i < rank(); ++i)
+ m.col(i).swap(m.col(pivots.coeff(i)));
+
+ // ok, we have our trapezoid matrix, we can apply the triangular solver.
+ // notice that the math behind this suggests that we should apply this to the
+ // negative of the RHS, but for performance we just put the negative sign elsewhere, see below.
+ m.topLeftCorner(rank(), rank())
+ .template triangularView<Upper>().solveInPlace(
+ m.topRightCorner(rank(), dimker)
+ );
+
+ // now we must undo the column permutation that we had applied!
+ for(Index i = rank()-1; i >= 0; --i)
+ m.col(i).swap(m.col(pivots.coeff(i)));
+
+ // see the negative sign in the next line, that's what we were talking about above.
+ for(Index i = 0; i < rank(); ++i) dst.row(dec().permutationQ().indices().coeff(i)) = -m.row(i).tail(dimker);
+ for(Index i = rank(); i < cols; ++i) dst.row(dec().permutationQ().indices().coeff(i)).setZero();
+ for(Index k = 0; k < dimker; ++k) dst.coeffRef(dec().permutationQ().indices().coeff(rank()+k), k) = Scalar(1);
+ }
+};
+
+/***** Implementation of image() *****************************************************/
+
+template<typename _MatrixType>
+struct image_retval<FullPivLU<_MatrixType> >
+ : image_retval_base<FullPivLU<_MatrixType> >
+{
+ EIGEN_MAKE_IMAGE_HELPERS(FullPivLU<_MatrixType>)
+
+ enum { MaxSmallDimAtCompileTime = EIGEN_SIZE_MIN_PREFER_FIXED(
+ MatrixType::MaxColsAtCompileTime,
+ MatrixType::MaxRowsAtCompileTime)
+ };
+
+ template<typename Dest> void evalTo(Dest& dst) const
+ {
+ if(rank() == 0)
+ {
+ // The Image is just {0}, so it doesn't have a basis properly speaking, but let's
+ // avoid crashing/asserting as that depends on floating point calculations. Let's
+ // just return a single column vector filled with zeros.
+ dst.setZero();
+ return;
+ }
+
+ Matrix<Index, Dynamic, 1, 0, MaxSmallDimAtCompileTime, 1> pivots(rank());
+ RealScalar premultiplied_threshold = dec().maxPivot() * dec().threshold();
+ Index p = 0;
+ for(Index i = 0; i < dec().nonzeroPivots(); ++i)
+ if(abs(dec().matrixLU().coeff(i,i)) > premultiplied_threshold)
+ pivots.coeffRef(p++) = i;
+ eigen_internal_assert(p == rank());
+
+ for(Index i = 0; i < rank(); ++i)
+ dst.col(i) = originalMatrix().col(dec().permutationQ().indices().coeff(pivots.coeff(i)));
+ }
+};
+
+/***** Implementation of solve() *****************************************************/
+
+template<typename _MatrixType, typename Rhs>
+struct solve_retval<FullPivLU<_MatrixType>, Rhs>
+ : solve_retval_base<FullPivLU<_MatrixType>, Rhs>
+{
+ EIGEN_MAKE_SOLVE_HELPERS(FullPivLU<_MatrixType>,Rhs)
+
+ template<typename Dest> void evalTo(Dest& dst) const
+ {
+ /* The decomposition PAQ = LU can be rewritten as A = P^{-1} L U Q^{-1}.
+ * So we proceed as follows:
+ * Step 1: compute c = P * rhs.
+ * Step 2: replace c by the solution x to Lx = c. Exists because L is invertible.
+ * Step 3: replace c by the solution x to Ux = c. May or may not exist.
+ * Step 4: result = Q * c;
+ */
+
+ const Index rows = dec().rows(), cols = dec().cols(),
+ nonzero_pivots = dec().nonzeroPivots();
+ eigen_assert(rhs().rows() == rows);
+ const Index smalldim = (std::min)(rows, cols);
+
+ if(nonzero_pivots == 0)
+ {
+ dst.setZero();
+ return;
+ }
+
+ typename Rhs::PlainObject c(rhs().rows(), rhs().cols());
+
+ // Step 1
+ c = dec().permutationP() * rhs();
+
+ // Step 2
+ dec().matrixLU()
+ .topLeftCorner(smalldim,smalldim)
+ .template triangularView<UnitLower>()
+ .solveInPlace(c.topRows(smalldim));
+ if(rows>cols)
+ {
+ c.bottomRows(rows-cols)
+ -= dec().matrixLU().bottomRows(rows-cols)
+ * c.topRows(cols);
+ }
+
+ // Step 3
+ dec().matrixLU()
+ .topLeftCorner(nonzero_pivots, nonzero_pivots)
+ .template triangularView<Upper>()
+ .solveInPlace(c.topRows(nonzero_pivots));
+
+ // Step 4
+ for(Index i = 0; i < nonzero_pivots; ++i)
+ dst.row(dec().permutationQ().indices().coeff(i)) = c.row(i);
+ for(Index i = nonzero_pivots; i < dec().matrixLU().cols(); ++i)
+ dst.row(dec().permutationQ().indices().coeff(i)).setZero();
+ }
+};
+
+} // end namespace internal
+
+/******* MatrixBase methods *****************************************************************/
+
+/** \lu_module
+ *
+ * \return the full-pivoting LU decomposition of \c *this.
+ *
+ * \sa class FullPivLU
+ */
+template<typename Derived>
+inline const FullPivLU<typename MatrixBase<Derived>::PlainObject>
+MatrixBase<Derived>::fullPivLu() const
+{
+ return FullPivLU<PlainObject>(eval());
+}
+
+} // end namespace Eigen
+
+#endif // EIGEN_LU_H
diff --git a/Eigen/src/LU/Inverse.h b/Eigen/src/LU/Inverse.h
new file mode 100644
index 000000000..39b8cdbc8
--- /dev/null
+++ b/Eigen/src/LU/Inverse.h
@@ -0,0 +1,396 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra.
+//
+// Copyright (C) 2008-2010 Benoit Jacob <jacob.benoit.1@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 EIGEN_INVERSE_H
+#define EIGEN_INVERSE_H
+
+namespace Eigen {
+
+namespace internal {
+
+/**********************************
+*** General case implementation ***
+**********************************/
+
+template<typename MatrixType, typename ResultType, int Size = MatrixType::RowsAtCompileTime>
+struct compute_inverse
+{
+ static inline void run(const MatrixType& matrix, ResultType& result)
+ {
+ result = matrix.partialPivLu().inverse();
+ }
+};
+
+template<typename MatrixType, typename ResultType, int Size = MatrixType::RowsAtCompileTime>
+struct compute_inverse_and_det_with_check { /* nothing! general case not supported. */ };
+
+/****************************
+*** Size 1 implementation ***
+****************************/
+
+template<typename MatrixType, typename ResultType>
+struct compute_inverse<MatrixType, ResultType, 1>
+{
+ static inline void run(const MatrixType& matrix, ResultType& result)
+ {
+ typedef typename MatrixType::Scalar Scalar;
+ result.coeffRef(0,0) = Scalar(1) / matrix.coeff(0,0);
+ }
+};
+
+template<typename MatrixType, typename ResultType>
+struct compute_inverse_and_det_with_check<MatrixType, ResultType, 1>
+{
+ static inline void run(
+ const MatrixType& matrix,
+ const typename MatrixType::RealScalar& absDeterminantThreshold,
+ ResultType& result,
+ typename ResultType::Scalar& determinant,
+ bool& invertible
+ )
+ {
+ determinant = matrix.coeff(0,0);
+ invertible = abs(determinant) > absDeterminantThreshold;
+ if(invertible) result.coeffRef(0,0) = typename ResultType::Scalar(1) / determinant;
+ }
+};
+
+/****************************
+*** Size 2 implementation ***
+****************************/
+
+template<typename MatrixType, typename ResultType>
+inline void compute_inverse_size2_helper(
+ const MatrixType& matrix, const typename ResultType::Scalar& invdet,
+ ResultType& result)
+{
+ result.coeffRef(0,0) = matrix.coeff(1,1) * invdet;
+ result.coeffRef(1,0) = -matrix.coeff(1,0) * invdet;
+ result.coeffRef(0,1) = -matrix.coeff(0,1) * invdet;
+ result.coeffRef(1,1) = matrix.coeff(0,0) * invdet;
+}
+
+template<typename MatrixType, typename ResultType>
+struct compute_inverse<MatrixType, ResultType, 2>
+{
+ static inline void run(const MatrixType& matrix, ResultType& result)
+ {
+ typedef typename ResultType::Scalar Scalar;
+ const Scalar invdet = typename MatrixType::Scalar(1) / matrix.determinant();
+ compute_inverse_size2_helper(matrix, invdet, result);
+ }
+};
+
+template<typename MatrixType, typename ResultType>
+struct compute_inverse_and_det_with_check<MatrixType, ResultType, 2>
+{
+ static inline void run(
+ const MatrixType& matrix,
+ const typename MatrixType::RealScalar& absDeterminantThreshold,
+ ResultType& inverse,
+ typename ResultType::Scalar& determinant,
+ bool& invertible
+ )
+ {
+ typedef typename ResultType::Scalar Scalar;
+ determinant = matrix.determinant();
+ invertible = abs(determinant) > absDeterminantThreshold;
+ if(!invertible) return;
+ const Scalar invdet = Scalar(1) / determinant;
+ compute_inverse_size2_helper(matrix, invdet, inverse);
+ }
+};
+
+/****************************
+*** Size 3 implementation ***
+****************************/
+
+template<typename MatrixType, int i, int j>
+inline typename MatrixType::Scalar cofactor_3x3(const MatrixType& m)
+{
+ enum {
+ i1 = (i+1) % 3,
+ i2 = (i+2) % 3,
+ j1 = (j+1) % 3,
+ j2 = (j+2) % 3
+ };
+ return m.coeff(i1, j1) * m.coeff(i2, j2)
+ - m.coeff(i1, j2) * m.coeff(i2, j1);
+}
+
+template<typename MatrixType, typename ResultType>
+inline void compute_inverse_size3_helper(
+ const MatrixType& matrix,
+ const typename ResultType::Scalar& invdet,
+ const Matrix<typename ResultType::Scalar,3,1>& cofactors_col0,
+ ResultType& result)
+{
+ result.row(0) = cofactors_col0 * invdet;
+ result.coeffRef(1,0) = cofactor_3x3<MatrixType,0,1>(matrix) * invdet;
+ result.coeffRef(1,1) = cofactor_3x3<MatrixType,1,1>(matrix) * invdet;
+ result.coeffRef(1,2) = cofactor_3x3<MatrixType,2,1>(matrix) * invdet;
+ result.coeffRef(2,0) = cofactor_3x3<MatrixType,0,2>(matrix) * invdet;
+ result.coeffRef(2,1) = cofactor_3x3<MatrixType,1,2>(matrix) * invdet;
+ result.coeffRef(2,2) = cofactor_3x3<MatrixType,2,2>(matrix) * invdet;
+}
+
+template<typename MatrixType, typename ResultType>
+struct compute_inverse<MatrixType, ResultType, 3>
+{
+ static inline void run(const MatrixType& matrix, ResultType& result)
+ {
+ typedef typename ResultType::Scalar Scalar;
+ Matrix<typename MatrixType::Scalar,3,1> cofactors_col0;
+ cofactors_col0.coeffRef(0) = cofactor_3x3<MatrixType,0,0>(matrix);
+ cofactors_col0.coeffRef(1) = cofactor_3x3<MatrixType,1,0>(matrix);
+ cofactors_col0.coeffRef(2) = cofactor_3x3<MatrixType,2,0>(matrix);
+ const Scalar det = (cofactors_col0.cwiseProduct(matrix.col(0))).sum();
+ const Scalar invdet = Scalar(1) / det;
+ compute_inverse_size3_helper(matrix, invdet, cofactors_col0, result);
+ }
+};
+
+template<typename MatrixType, typename ResultType>
+struct compute_inverse_and_det_with_check<MatrixType, ResultType, 3>
+{
+ static inline void run(
+ const MatrixType& matrix,
+ const typename MatrixType::RealScalar& absDeterminantThreshold,
+ ResultType& inverse,
+ typename ResultType::Scalar& determinant,
+ bool& invertible
+ )
+ {
+ typedef typename ResultType::Scalar Scalar;
+ Matrix<Scalar,3,1> cofactors_col0;
+ cofactors_col0.coeffRef(0) = cofactor_3x3<MatrixType,0,0>(matrix);
+ cofactors_col0.coeffRef(1) = cofactor_3x3<MatrixType,1,0>(matrix);
+ cofactors_col0.coeffRef(2) = cofactor_3x3<MatrixType,2,0>(matrix);
+ determinant = (cofactors_col0.cwiseProduct(matrix.col(0))).sum();
+ invertible = abs(determinant) > absDeterminantThreshold;
+ if(!invertible) return;
+ const Scalar invdet = Scalar(1) / determinant;
+ compute_inverse_size3_helper(matrix, invdet, cofactors_col0, inverse);
+ }
+};
+
+/****************************
+*** Size 4 implementation ***
+****************************/
+
+template<typename Derived>
+inline const typename Derived::Scalar general_det3_helper
+(const MatrixBase<Derived>& matrix, int i1, int i2, int i3, int j1, int j2, int j3)
+{
+ return matrix.coeff(i1,j1)
+ * (matrix.coeff(i2,j2) * matrix.coeff(i3,j3) - matrix.coeff(i2,j3) * matrix.coeff(i3,j2));
+}
+
+template<typename MatrixType, int i, int j>
+inline typename MatrixType::Scalar cofactor_4x4(const MatrixType& matrix)
+{
+ enum {
+ i1 = (i+1) % 4,
+ i2 = (i+2) % 4,
+ i3 = (i+3) % 4,
+ j1 = (j+1) % 4,
+ j2 = (j+2) % 4,
+ j3 = (j+3) % 4
+ };
+ return general_det3_helper(matrix, i1, i2, i3, j1, j2, j3)
+ + general_det3_helper(matrix, i2, i3, i1, j1, j2, j3)
+ + general_det3_helper(matrix, i3, i1, i2, j1, j2, j3);
+}
+
+template<int Arch, typename Scalar, typename MatrixType, typename ResultType>
+struct compute_inverse_size4
+{
+ static void run(const MatrixType& matrix, ResultType& result)
+ {
+ result.coeffRef(0,0) = cofactor_4x4<MatrixType,0,0>(matrix);
+ result.coeffRef(1,0) = -cofactor_4x4<MatrixType,0,1>(matrix);
+ result.coeffRef(2,0) = cofactor_4x4<MatrixType,0,2>(matrix);
+ result.coeffRef(3,0) = -cofactor_4x4<MatrixType,0,3>(matrix);
+ result.coeffRef(0,2) = cofactor_4x4<MatrixType,2,0>(matrix);
+ result.coeffRef(1,2) = -cofactor_4x4<MatrixType,2,1>(matrix);
+ result.coeffRef(2,2) = cofactor_4x4<MatrixType,2,2>(matrix);
+ result.coeffRef(3,2) = -cofactor_4x4<MatrixType,2,3>(matrix);
+ result.coeffRef(0,1) = -cofactor_4x4<MatrixType,1,0>(matrix);
+ result.coeffRef(1,1) = cofactor_4x4<MatrixType,1,1>(matrix);
+ result.coeffRef(2,1) = -cofactor_4x4<MatrixType,1,2>(matrix);
+ result.coeffRef(3,1) = cofactor_4x4<MatrixType,1,3>(matrix);
+ result.coeffRef(0,3) = -cofactor_4x4<MatrixType,3,0>(matrix);
+ result.coeffRef(1,3) = cofactor_4x4<MatrixType,3,1>(matrix);
+ result.coeffRef(2,3) = -cofactor_4x4<MatrixType,3,2>(matrix);
+ result.coeffRef(3,3) = cofactor_4x4<MatrixType,3,3>(matrix);
+ result /= (matrix.col(0).cwiseProduct(result.row(0).transpose())).sum();
+ }
+};
+
+template<typename MatrixType, typename ResultType>
+struct compute_inverse<MatrixType, ResultType, 4>
+ : compute_inverse_size4<Architecture::Target, typename MatrixType::Scalar,
+ MatrixType, ResultType>
+{
+};
+
+template<typename MatrixType, typename ResultType>
+struct compute_inverse_and_det_with_check<MatrixType, ResultType, 4>
+{
+ static inline void run(
+ const MatrixType& matrix,
+ const typename MatrixType::RealScalar& absDeterminantThreshold,
+ ResultType& inverse,
+ typename ResultType::Scalar& determinant,
+ bool& invertible
+ )
+ {
+ determinant = matrix.determinant();
+ invertible = abs(determinant) > absDeterminantThreshold;
+ if(invertible) compute_inverse<MatrixType, ResultType>::run(matrix, inverse);
+ }
+};
+
+/*************************
+*** MatrixBase methods ***
+*************************/
+
+template<typename MatrixType>
+struct traits<inverse_impl<MatrixType> >
+{
+ typedef typename MatrixType::PlainObject ReturnType;
+};
+
+template<typename MatrixType>
+struct inverse_impl : public ReturnByValue<inverse_impl<MatrixType> >
+{
+ typedef typename MatrixType::Index Index;
+ typedef typename internal::eval<MatrixType>::type MatrixTypeNested;
+ typedef typename remove_all<MatrixTypeNested>::type MatrixTypeNestedCleaned;
+ MatrixTypeNested m_matrix;
+
+ inverse_impl(const MatrixType& matrix)
+ : m_matrix(matrix)
+ {}
+
+ inline Index rows() const { return m_matrix.rows(); }
+ inline Index cols() const { return m_matrix.cols(); }
+
+ template<typename Dest> inline void evalTo(Dest& dst) const
+ {
+ const int Size = EIGEN_PLAIN_ENUM_MIN(MatrixType::ColsAtCompileTime,Dest::ColsAtCompileTime);
+ EIGEN_ONLY_USED_FOR_DEBUG(Size);
+ eigen_assert(( (Size<=1) || (Size>4) || (extract_data(m_matrix)!=extract_data(dst)))
+ && "Aliasing problem detected in inverse(), you need to do inverse().eval() here.");
+
+ compute_inverse<MatrixTypeNestedCleaned, Dest>::run(m_matrix, dst);
+ }
+};
+
+} // end namespace internal
+
+/** \lu_module
+ *
+ * \returns the matrix inverse of this matrix.
+ *
+ * For small fixed sizes up to 4x4, this method uses cofactors.
+ * In the general case, this method uses class PartialPivLU.
+ *
+ * \note This matrix must be invertible, otherwise the result is undefined. If you need an
+ * invertibility check, do the following:
+ * \li for fixed sizes up to 4x4, use computeInverseAndDetWithCheck().
+ * \li for the general case, use class FullPivLU.
+ *
+ * Example: \include MatrixBase_inverse.cpp
+ * Output: \verbinclude MatrixBase_inverse.out
+ *
+ * \sa computeInverseAndDetWithCheck()
+ */
+template<typename Derived>
+inline const internal::inverse_impl<Derived> MatrixBase<Derived>::inverse() const
+{
+ EIGEN_STATIC_ASSERT(!NumTraits<Scalar>::IsInteger,THIS_FUNCTION_IS_NOT_FOR_INTEGER_NUMERIC_TYPES)
+ eigen_assert(rows() == cols());
+ return internal::inverse_impl<Derived>(derived());
+}
+
+/** \lu_module
+ *
+ * Computation of matrix inverse and determinant, with invertibility check.
+ *
+ * This is only for fixed-size square matrices of size up to 4x4.
+ *
+ * \param inverse Reference to the matrix in which to store the inverse.
+ * \param determinant Reference to the variable in which to store the inverse.
+ * \param invertible Reference to the bool variable in which to store whether the matrix is invertible.
+ * \param absDeterminantThreshold Optional parameter controlling the invertibility check.
+ * The matrix will be declared invertible if the absolute value of its
+ * determinant is greater than this threshold.
+ *
+ * Example: \include MatrixBase_computeInverseAndDetWithCheck.cpp
+ * Output: \verbinclude MatrixBase_computeInverseAndDetWithCheck.out
+ *
+ * \sa inverse(), computeInverseWithCheck()
+ */
+template<typename Derived>
+template<typename ResultType>
+inline void MatrixBase<Derived>::computeInverseAndDetWithCheck(
+ ResultType& inverse,
+ typename ResultType::Scalar& determinant,
+ bool& invertible,
+ const RealScalar& absDeterminantThreshold
+ ) const
+{
+ // i'd love to put some static assertions there, but SFINAE means that they have no effect...
+ eigen_assert(rows() == cols());
+ // for 2x2, it's worth giving a chance to avoid evaluating.
+ // for larger sizes, evaluating has negligible cost and limits code size.
+ typedef typename internal::conditional<
+ RowsAtCompileTime == 2,
+ typename internal::remove_all<typename internal::nested<Derived, 2>::type>::type,
+ PlainObject
+ >::type MatrixType;
+ internal::compute_inverse_and_det_with_check<MatrixType, ResultType>::run
+ (derived(), absDeterminantThreshold, inverse, determinant, invertible);
+}
+
+/** \lu_module
+ *
+ * Computation of matrix inverse, with invertibility check.
+ *
+ * This is only for fixed-size square matrices of size up to 4x4.
+ *
+ * \param inverse Reference to the matrix in which to store the inverse.
+ * \param invertible Reference to the bool variable in which to store whether the matrix is invertible.
+ * \param absDeterminantThreshold Optional parameter controlling the invertibility check.
+ * The matrix will be declared invertible if the absolute value of its
+ * determinant is greater than this threshold.
+ *
+ * Example: \include MatrixBase_computeInverseWithCheck.cpp
+ * Output: \verbinclude MatrixBase_computeInverseWithCheck.out
+ *
+ * \sa inverse(), computeInverseAndDetWithCheck()
+ */
+template<typename Derived>
+template<typename ResultType>
+inline void MatrixBase<Derived>::computeInverseWithCheck(
+ ResultType& inverse,
+ bool& invertible,
+ const RealScalar& absDeterminantThreshold
+ ) const
+{
+ RealScalar determinant;
+ // i'd love to put some static assertions there, but SFINAE means that they have no effect...
+ eigen_assert(rows() == cols());
+ computeInverseAndDetWithCheck(inverse,determinant,invertible,absDeterminantThreshold);
+}
+
+} // end namespace Eigen
+
+#endif // EIGEN_INVERSE_H
diff --git a/Eigen/src/LU/PartialPivLU.h b/Eigen/src/LU/PartialPivLU.h
new file mode 100644
index 000000000..c9ff9dd5a
--- /dev/null
+++ b/Eigen/src/LU/PartialPivLU.h
@@ -0,0 +1,498 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra.
+//
+// Copyright (C) 2006-2009 Benoit Jacob <jacob.benoit.1@gmail.com>
+// Copyright (C) 2009 Gael Guennebaud <gael.guennebaud@inria.fr>
+//
+// This Source Code Form is subject to the terms of the Mozilla
+// Public License v. 2.0. If a copy of the MPL was not distributed
+// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+#ifndef EIGEN_PARTIALLU_H
+#define EIGEN_PARTIALLU_H
+
+namespace Eigen {
+
+/** \ingroup LU_Module
+ *
+ * \class PartialPivLU
+ *
+ * \brief LU decomposition of a matrix with partial pivoting, and related features
+ *
+ * \param MatrixType the type of the matrix of which we are computing the LU decomposition
+ *
+ * This class represents a LU decomposition of a \b square \b invertible matrix, with partial pivoting: the matrix A
+ * is decomposed as A = PLU where L is unit-lower-triangular, U is upper-triangular, and P
+ * is a permutation matrix.
+ *
+ * Typically, partial pivoting LU decomposition is only considered numerically stable for square invertible
+ * matrices. Thus LAPACK's dgesv and dgesvx require the matrix to be square and invertible. The present class
+ * does the same. It will assert that the matrix is square, but it won't (actually it can't) check that the
+ * matrix is invertible: it is your task to check that you only use this decomposition on invertible matrices.
+ *
+ * The guaranteed safe alternative, working for all matrices, is the full pivoting LU decomposition, provided
+ * by class FullPivLU.
+ *
+ * This is \b not a rank-revealing LU decomposition. Many features are intentionally absent from this class,
+ * such as rank computation. If you need these features, use class FullPivLU.
+ *
+ * This LU decomposition is suitable to invert invertible matrices. It is what MatrixBase::inverse() uses
+ * in the general case.
+ * On the other hand, it is \b not suitable to determine whether a given matrix is invertible.
+ *
+ * The data of the LU decomposition can be directly accessed through the methods matrixLU(), permutationP().
+ *
+ * \sa MatrixBase::partialPivLu(), MatrixBase::determinant(), MatrixBase::inverse(), MatrixBase::computeInverse(), class FullPivLU
+ */
+template<typename _MatrixType> class PartialPivLU
+{
+ public:
+
+ typedef _MatrixType MatrixType;
+ enum {
+ RowsAtCompileTime = MatrixType::RowsAtCompileTime,
+ ColsAtCompileTime = MatrixType::ColsAtCompileTime,
+ Options = MatrixType::Options,
+ MaxRowsAtCompileTime = MatrixType::MaxRowsAtCompileTime,
+ MaxColsAtCompileTime = MatrixType::MaxColsAtCompileTime
+ };
+ typedef typename MatrixType::Scalar Scalar;
+ typedef typename NumTraits<typename MatrixType::Scalar>::Real RealScalar;
+ typedef typename internal::traits<MatrixType>::StorageKind StorageKind;
+ typedef typename MatrixType::Index Index;
+ typedef PermutationMatrix<RowsAtCompileTime, MaxRowsAtCompileTime> PermutationType;
+ typedef Transpositions<RowsAtCompileTime, MaxRowsAtCompileTime> TranspositionType;
+
+
+ /**
+ * \brief Default Constructor.
+ *
+ * The default constructor is useful in cases in which the user intends to
+ * perform decompositions via PartialPivLU::compute(const MatrixType&).
+ */
+ PartialPivLU();
+
+ /** \brief Default Constructor with memory preallocation
+ *
+ * Like the default constructor but with preallocation of the internal data
+ * according to the specified problem \a size.
+ * \sa PartialPivLU()
+ */
+ PartialPivLU(Index size);
+
+ /** Constructor.
+ *
+ * \param matrix the matrix of which to compute the LU decomposition.
+ *
+ * \warning The matrix should have full rank (e.g. if it's square, it should be invertible).
+ * If you need to deal with non-full rank, use class FullPivLU instead.
+ */
+ PartialPivLU(const MatrixType& matrix);
+
+ PartialPivLU& compute(const MatrixType& matrix);
+
+ /** \returns the LU decomposition matrix: the upper-triangular part is U, the
+ * unit-lower-triangular part is L (at least for square matrices; in the non-square
+ * case, special care is needed, see the documentation of class FullPivLU).
+ *
+ * \sa matrixL(), matrixU()
+ */
+ inline const MatrixType& matrixLU() const
+ {
+ eigen_assert(m_isInitialized && "PartialPivLU is not initialized.");
+ return m_lu;
+ }
+
+ /** \returns the permutation matrix P.
+ */
+ inline const PermutationType& permutationP() const
+ {
+ eigen_assert(m_isInitialized && "PartialPivLU is not initialized.");
+ return m_p;
+ }
+
+ /** This method returns the solution x to the equation Ax=b, where A is the matrix of which
+ * *this is the LU decomposition.
+ *
+ * \param b the right-hand-side of the equation to solve. Can be a vector or a matrix,
+ * the only requirement in order for the equation to make sense is that
+ * b.rows()==A.rows(), where A is the matrix of which *this is the LU decomposition.
+ *
+ * \returns the solution.
+ *
+ * Example: \include PartialPivLU_solve.cpp
+ * Output: \verbinclude PartialPivLU_solve.out
+ *
+ * Since this PartialPivLU class assumes anyway that the matrix A is invertible, the solution
+ * theoretically exists and is unique regardless of b.
+ *
+ * \sa TriangularView::solve(), inverse(), computeInverse()
+ */
+ template<typename Rhs>
+ inline const internal::solve_retval<PartialPivLU, Rhs>
+ solve(const MatrixBase<Rhs>& b) const
+ {
+ eigen_assert(m_isInitialized && "PartialPivLU is not initialized.");
+ return internal::solve_retval<PartialPivLU, Rhs>(*this, b.derived());
+ }
+
+ /** \returns the inverse of the matrix of which *this is the LU decomposition.
+ *
+ * \warning The matrix being decomposed here is assumed to be invertible. If you need to check for
+ * invertibility, use class FullPivLU instead.
+ *
+ * \sa MatrixBase::inverse(), LU::inverse()
+ */
+ inline const internal::solve_retval<PartialPivLU,typename MatrixType::IdentityReturnType> inverse() const
+ {
+ eigen_assert(m_isInitialized && "PartialPivLU is not initialized.");
+ return internal::solve_retval<PartialPivLU,typename MatrixType::IdentityReturnType>
+ (*this, MatrixType::Identity(m_lu.rows(), m_lu.cols()));
+ }
+
+ /** \returns the determinant of the matrix of which
+ * *this is the LU decomposition. It has only linear complexity
+ * (that is, O(n) where n is the dimension of the square matrix)
+ * as the LU decomposition has already been computed.
+ *
+ * \note For fixed-size matrices of size up to 4, MatrixBase::determinant() offers
+ * optimized paths.
+ *
+ * \warning a determinant can be very big or small, so for matrices
+ * of large enough dimension, there is a risk of overflow/underflow.
+ *
+ * \sa MatrixBase::determinant()
+ */
+ typename internal::traits<MatrixType>::Scalar determinant() const;
+
+ MatrixType reconstructedMatrix() const;
+
+ inline Index rows() const { return m_lu.rows(); }
+ inline Index cols() const { return m_lu.cols(); }
+
+ protected:
+ MatrixType m_lu;
+ PermutationType m_p;
+ TranspositionType m_rowsTranspositions;
+ Index m_det_p;
+ bool m_isInitialized;
+};
+
+template<typename MatrixType>
+PartialPivLU<MatrixType>::PartialPivLU()
+ : m_lu(),
+ m_p(),
+ m_rowsTranspositions(),
+ m_det_p(0),
+ m_isInitialized(false)
+{
+}
+
+template<typename MatrixType>
+PartialPivLU<MatrixType>::PartialPivLU(Index size)
+ : m_lu(size, size),
+ m_p(size),
+ m_rowsTranspositions(size),
+ m_det_p(0),
+ m_isInitialized(false)
+{
+}
+
+template<typename MatrixType>
+PartialPivLU<MatrixType>::PartialPivLU(const MatrixType& matrix)
+ : m_lu(matrix.rows(), matrix.rows()),
+ m_p(matrix.rows()),
+ m_rowsTranspositions(matrix.rows()),
+ m_det_p(0),
+ m_isInitialized(false)
+{
+ compute(matrix);
+}
+
+namespace internal {
+
+/** \internal This is the blocked version of fullpivlu_unblocked() */
+template<typename Scalar, int StorageOrder, typename PivIndex>
+struct partial_lu_impl
+{
+ // FIXME add a stride to Map, so that the following mapping becomes easier,
+ // another option would be to create an expression being able to automatically
+ // warp any Map, Matrix, and Block expressions as a unique type, but since that's exactly
+ // a Map + stride, why not adding a stride to Map, and convenient ctors from a Matrix,
+ // and Block.
+ typedef Map<Matrix<Scalar, Dynamic, Dynamic, StorageOrder> > MapLU;
+ typedef Block<MapLU, Dynamic, Dynamic> MatrixType;
+ typedef Block<MatrixType,Dynamic,Dynamic> BlockType;
+ typedef typename MatrixType::RealScalar RealScalar;
+ typedef typename MatrixType::Index Index;
+
+ /** \internal performs the LU decomposition in-place of the matrix \a lu
+ * using an unblocked algorithm.
+ *
+ * In addition, this function returns the row transpositions in the
+ * vector \a row_transpositions which must have a size equal to the number
+ * of columns of the matrix \a lu, and an integer \a nb_transpositions
+ * which returns the actual number of transpositions.
+ *
+ * \returns The index of the first pivot which is exactly zero if any, or a negative number otherwise.
+ */
+ static Index unblocked_lu(MatrixType& lu, PivIndex* row_transpositions, PivIndex& nb_transpositions)
+ {
+ const Index rows = lu.rows();
+ const Index cols = lu.cols();
+ const Index size = (std::min)(rows,cols);
+ nb_transpositions = 0;
+ int first_zero_pivot = -1;
+ for(Index k = 0; k < size; ++k)
+ {
+ Index rrows = rows-k-1;
+ Index rcols = cols-k-1;
+
+ Index row_of_biggest_in_col;
+ RealScalar biggest_in_corner
+ = lu.col(k).tail(rows-k).cwiseAbs().maxCoeff(&row_of_biggest_in_col);
+ row_of_biggest_in_col += k;
+
+ row_transpositions[k] = row_of_biggest_in_col;
+
+ if(biggest_in_corner != RealScalar(0))
+ {
+ if(k != row_of_biggest_in_col)
+ {
+ lu.row(k).swap(lu.row(row_of_biggest_in_col));
+ ++nb_transpositions;
+ }
+
+ // FIXME shall we introduce a safe quotient expression in cas 1/lu.coeff(k,k)
+ // overflow but not the actual quotient?
+ lu.col(k).tail(rrows) /= lu.coeff(k,k);
+ }
+ else if(first_zero_pivot==-1)
+ {
+ // the pivot is exactly zero, we record the index of the first pivot which is exactly 0,
+ // and continue the factorization such we still have A = PLU
+ first_zero_pivot = k;
+ }
+
+ if(k<rows-1)
+ lu.bottomRightCorner(rrows,rcols).noalias() -= lu.col(k).tail(rrows) * lu.row(k).tail(rcols);
+ }
+ return first_zero_pivot;
+ }
+
+ /** \internal performs the LU decomposition in-place of the matrix represented
+ * by the variables \a rows, \a cols, \a lu_data, and \a lu_stride using a
+ * recursive, blocked algorithm.
+ *
+ * In addition, this function returns the row transpositions in the
+ * vector \a row_transpositions which must have a size equal to the number
+ * of columns of the matrix \a lu, and an integer \a nb_transpositions
+ * which returns the actual number of transpositions.
+ *
+ * \returns The index of the first pivot which is exactly zero if any, or a negative number otherwise.
+ *
+ * \note This very low level interface using pointers, etc. is to:
+ * 1 - reduce the number of instanciations to the strict minimum
+ * 2 - avoid infinite recursion of the instanciations with Block<Block<Block<...> > >
+ */
+ static Index blocked_lu(Index rows, Index cols, Scalar* lu_data, Index luStride, PivIndex* row_transpositions, PivIndex& nb_transpositions, Index maxBlockSize=256)
+ {
+ MapLU lu1(lu_data,StorageOrder==RowMajor?rows:luStride,StorageOrder==RowMajor?luStride:cols);
+ MatrixType lu(lu1,0,0,rows,cols);
+
+ const Index size = (std::min)(rows,cols);
+
+ // if the matrix is too small, no blocking:
+ if(size<=16)
+ {
+ return unblocked_lu(lu, row_transpositions, nb_transpositions);
+ }
+
+ // automatically adjust the number of subdivisions to the size
+ // of the matrix so that there is enough sub blocks:
+ Index blockSize;
+ {
+ blockSize = size/8;
+ blockSize = (blockSize/16)*16;
+ blockSize = (std::min)((std::max)(blockSize,Index(8)), maxBlockSize);
+ }
+
+ nb_transpositions = 0;
+ int first_zero_pivot = -1;
+ for(Index k = 0; k < size; k+=blockSize)
+ {
+ Index bs = (std::min)(size-k,blockSize); // actual size of the block
+ Index trows = rows - k - bs; // trailing rows
+ Index tsize = size - k - bs; // trailing size
+
+ // partition the matrix:
+ // A00 | A01 | A02
+ // lu = A_0 | A_1 | A_2 = A10 | A11 | A12
+ // A20 | A21 | A22
+ BlockType A_0(lu,0,0,rows,k);
+ BlockType A_2(lu,0,k+bs,rows,tsize);
+ BlockType A11(lu,k,k,bs,bs);
+ BlockType A12(lu,k,k+bs,bs,tsize);
+ BlockType A21(lu,k+bs,k,trows,bs);
+ BlockType A22(lu,k+bs,k+bs,trows,tsize);
+
+ PivIndex nb_transpositions_in_panel;
+ // recursively call the blocked LU algorithm on [A11^T A21^T]^T
+ // with a very small blocking size:
+ Index ret = blocked_lu(trows+bs, bs, &lu.coeffRef(k,k), luStride,
+ row_transpositions+k, nb_transpositions_in_panel, 16);
+ if(ret>=0 && first_zero_pivot==-1)
+ first_zero_pivot = k+ret;
+
+ nb_transpositions += nb_transpositions_in_panel;
+ // update permutations and apply them to A_0
+ for(Index i=k; i<k+bs; ++i)
+ {
+ Index piv = (row_transpositions[i] += k);
+ A_0.row(i).swap(A_0.row(piv));
+ }
+
+ if(trows)
+ {
+ // apply permutations to A_2
+ for(Index i=k;i<k+bs; ++i)
+ A_2.row(i).swap(A_2.row(row_transpositions[i]));
+
+ // A12 = A11^-1 A12
+ A11.template triangularView<UnitLower>().solveInPlace(A12);
+
+ A22.noalias() -= A21 * A12;
+ }
+ }
+ return first_zero_pivot;
+ }
+};
+
+/** \internal performs the LU decomposition with partial pivoting in-place.
+ */
+template<typename MatrixType, typename TranspositionType>
+void partial_lu_inplace(MatrixType& lu, TranspositionType& row_transpositions, typename TranspositionType::Index& nb_transpositions)
+{
+ eigen_assert(lu.cols() == row_transpositions.size());
+ eigen_assert((&row_transpositions.coeffRef(1)-&row_transpositions.coeffRef(0)) == 1);
+
+ partial_lu_impl
+ <typename MatrixType::Scalar, MatrixType::Flags&RowMajorBit?RowMajor:ColMajor, typename TranspositionType::Index>
+ ::blocked_lu(lu.rows(), lu.cols(), &lu.coeffRef(0,0), lu.outerStride(), &row_transpositions.coeffRef(0), nb_transpositions);
+}
+
+} // end namespace internal
+
+template<typename MatrixType>
+PartialPivLU<MatrixType>& PartialPivLU<MatrixType>::compute(const MatrixType& matrix)
+{
+ m_lu = matrix;
+
+ eigen_assert(matrix.rows() == matrix.cols() && "PartialPivLU is only for square (and moreover invertible) matrices");
+ const Index size = matrix.rows();
+
+ m_rowsTranspositions.resize(size);
+
+ typename TranspositionType::Index nb_transpositions;
+ internal::partial_lu_inplace(m_lu, m_rowsTranspositions, nb_transpositions);
+ m_det_p = (nb_transpositions%2) ? -1 : 1;
+
+ m_p = m_rowsTranspositions;
+
+ m_isInitialized = true;
+ return *this;
+}
+
+template<typename MatrixType>
+typename internal::traits<MatrixType>::Scalar PartialPivLU<MatrixType>::determinant() const
+{
+ eigen_assert(m_isInitialized && "PartialPivLU is not initialized.");
+ return Scalar(m_det_p) * m_lu.diagonal().prod();
+}
+
+/** \returns the matrix represented by the decomposition,
+ * i.e., it returns the product: P^{-1} L U.
+ * This function is provided for debug purpose. */
+template<typename MatrixType>
+MatrixType PartialPivLU<MatrixType>::reconstructedMatrix() const
+{
+ eigen_assert(m_isInitialized && "LU is not initialized.");
+ // LU
+ MatrixType res = m_lu.template triangularView<UnitLower>().toDenseMatrix()
+ * m_lu.template triangularView<Upper>();
+
+ // P^{-1}(LU)
+ res = m_p.inverse() * res;
+
+ return res;
+}
+
+/***** Implementation of solve() *****************************************************/
+
+namespace internal {
+
+template<typename _MatrixType, typename Rhs>
+struct solve_retval<PartialPivLU<_MatrixType>, Rhs>
+ : solve_retval_base<PartialPivLU<_MatrixType>, Rhs>
+{
+ EIGEN_MAKE_SOLVE_HELPERS(PartialPivLU<_MatrixType>,Rhs)
+
+ template<typename Dest> void evalTo(Dest& dst) const
+ {
+ /* The decomposition PA = LU can be rewritten as A = P^{-1} L U.
+ * So we proceed as follows:
+ * Step 1: compute c = Pb.
+ * Step 2: replace c by the solution x to Lx = c.
+ * Step 3: replace c by the solution x to Ux = c.
+ */
+
+ eigen_assert(rhs().rows() == dec().matrixLU().rows());
+
+ // Step 1
+ dst = dec().permutationP() * rhs();
+
+ // Step 2
+ dec().matrixLU().template triangularView<UnitLower>().solveInPlace(dst);
+
+ // Step 3
+ dec().matrixLU().template triangularView<Upper>().solveInPlace(dst);
+ }
+};
+
+} // end namespace internal
+
+/******** MatrixBase methods *******/
+
+/** \lu_module
+ *
+ * \return the partial-pivoting LU decomposition of \c *this.
+ *
+ * \sa class PartialPivLU
+ */
+template<typename Derived>
+inline const PartialPivLU<typename MatrixBase<Derived>::PlainObject>
+MatrixBase<Derived>::partialPivLu() const
+{
+ return PartialPivLU<PlainObject>(eval());
+}
+
+#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<typename Derived>
+inline const PartialPivLU<typename MatrixBase<Derived>::PlainObject>
+MatrixBase<Derived>::lu() const
+{
+ return PartialPivLU<PlainObject>(eval());
+}
+#endif
+
+} // end namespace Eigen
+
+#endif // EIGEN_PARTIALLU_H
diff --git a/Eigen/src/LU/PartialPivLU_MKL.h b/Eigen/src/LU/PartialPivLU_MKL.h
new file mode 100644
index 000000000..9035953c8
--- /dev/null
+++ b/Eigen/src/LU/PartialPivLU_MKL.h
@@ -0,0 +1,85 @@
+/*
+ Copyright (c) 2011, Intel Corporation. All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without modification,
+ are permitted provided that the following conditions are met:
+
+ * Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+ * Neither the name of Intel Corporation nor the names of its contributors may
+ be used to endorse or promote products derived from this software without
+ specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+ ********************************************************************************
+ * Content : Eigen bindings to Intel(R) MKL
+ * LU decomposition with partial pivoting based on LAPACKE_?getrf function.
+ ********************************************************************************
+*/
+
+#ifndef EIGEN_PARTIALLU_LAPACK_H
+#define EIGEN_PARTIALLU_LAPACK_H
+
+#include "Eigen/src/Core/util/MKL_support.h"
+
+namespace Eigen {
+
+namespace internal {
+
+/** \internal Specialization for the data types supported by MKL */
+
+#define EIGEN_MKL_LU_PARTPIV(EIGTYPE, MKLTYPE, MKLPREFIX) \
+template<int StorageOrder> \
+struct partial_lu_impl<EIGTYPE, StorageOrder, lapack_int> \
+{ \
+ /* \internal performs the LU decomposition in-place of the matrix represented */ \
+ static lapack_int blocked_lu(lapack_int rows, lapack_int cols, EIGTYPE* lu_data, lapack_int luStride, lapack_int* row_transpositions, lapack_int& nb_transpositions, lapack_int maxBlockSize=256) \
+ { \
+ EIGEN_UNUSED_VARIABLE(maxBlockSize);\
+ lapack_int matrix_order, first_zero_pivot; \
+ lapack_int m, n, lda, *ipiv, info; \
+ EIGTYPE* a; \
+/* Set up parameters for ?getrf */ \
+ matrix_order = StorageOrder==RowMajor ? LAPACK_ROW_MAJOR : LAPACK_COL_MAJOR; \
+ lda = luStride; \
+ a = lu_data; \
+ ipiv = row_transpositions; \
+ m = rows; \
+ n = cols; \
+ nb_transpositions = 0; \
+\
+ info = LAPACKE_##MKLPREFIX##getrf( matrix_order, m, n, (MKLTYPE*)a, lda, ipiv ); \
+\
+ for(int i=0;i<m;i++) { ipiv[i]--; if (ipiv[i]!=i) nb_transpositions++; } \
+\
+ eigen_assert(info >= 0); \
+/* something should be done with nb_transpositions */ \
+\
+ first_zero_pivot = info; \
+ return first_zero_pivot; \
+ } \
+};
+
+EIGEN_MKL_LU_PARTPIV(double, double, d)
+EIGEN_MKL_LU_PARTPIV(float, float, s)
+EIGEN_MKL_LU_PARTPIV(dcomplex, MKL_Complex16, z)
+EIGEN_MKL_LU_PARTPIV(scomplex, MKL_Complex8, c)
+
+} // end namespace internal
+
+} // end namespace Eigen
+
+#endif // EIGEN_PARTIALLU_LAPACK_H
diff --git a/Eigen/src/LU/arch/CMakeLists.txt b/Eigen/src/LU/arch/CMakeLists.txt
new file mode 100644
index 000000000..f6b7ed9ec
--- /dev/null
+++ b/Eigen/src/LU/arch/CMakeLists.txt
@@ -0,0 +1,6 @@
+FILE(GLOB Eigen_LU_arch_SRCS "*.h")
+
+INSTALL(FILES
+ ${Eigen_LU_arch_SRCS}
+ DESTINATION ${INCLUDE_INSTALL_DIR}/Eigen/src/LU/arch COMPONENT Devel
+ )
diff --git a/Eigen/src/LU/arch/Inverse_SSE.h b/Eigen/src/LU/arch/Inverse_SSE.h
new file mode 100644
index 000000000..60b7a2376
--- /dev/null
+++ b/Eigen/src/LU/arch/Inverse_SSE.h
@@ -0,0 +1,329 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra.
+//
+// Copyright (C) 2001 Intel Corporation
+// Copyright (C) 2010 Gael Guennebaud <gael.guennebaud@inria.fr>
+// Copyright (C) 2009 Benoit Jacob <jacob.benoit.1@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/.
+
+// The SSE code for the 4x4 float and double matrix inverse in this file
+// comes from the following Intel's library:
+// http://software.intel.com/en-us/articles/optimized-matrix-library-for-use-with-the-intel-pentiumr-4-processors-sse2-instructions/
+//
+// Here is the respective copyright and license statement:
+//
+// Copyright (c) 2001 Intel Corporation.
+//
+// Permition is granted to use, copy, distribute and prepare derivative works
+// of this library for any purpose and without fee, provided, that the above
+// copyright notice and this statement appear in all copies.
+// Intel makes no representations about the suitability of this software for
+// any purpose, and specifically disclaims all warranties.
+// See LEGAL.TXT for all the legal information.
+
+#ifndef EIGEN_INVERSE_SSE_H
+#define EIGEN_INVERSE_SSE_H
+
+namespace Eigen {
+
+namespace internal {
+
+template<typename MatrixType, typename ResultType>
+struct compute_inverse_size4<Architecture::SSE, float, MatrixType, ResultType>
+{
+ enum {
+ MatrixAlignment = bool(MatrixType::Flags&AlignedBit),
+ ResultAlignment = bool(ResultType::Flags&AlignedBit),
+ StorageOrdersMatch = (MatrixType::Flags&RowMajorBit) == (ResultType::Flags&RowMajorBit)
+ };
+
+ static void run(const MatrixType& matrix, ResultType& result)
+ {
+ EIGEN_ALIGN16 const unsigned int _Sign_PNNP[4] = { 0x00000000, 0x80000000, 0x80000000, 0x00000000 };
+
+ // Load the full matrix into registers
+ __m128 _L1 = matrix.template packet<MatrixAlignment>( 0);
+ __m128 _L2 = matrix.template packet<MatrixAlignment>( 4);
+ __m128 _L3 = matrix.template packet<MatrixAlignment>( 8);
+ __m128 _L4 = matrix.template packet<MatrixAlignment>(12);
+
+ // The inverse is calculated using "Divide and Conquer" technique. The
+ // original matrix is divide into four 2x2 sub-matrices. Since each
+ // register holds four matrix element, the smaller matrices are
+ // represented as a registers. Hence we get a better locality of the
+ // calculations.
+
+ __m128 A, B, C, D; // the four sub-matrices
+ if(!StorageOrdersMatch)
+ {
+ A = _mm_unpacklo_ps(_L1, _L2);
+ B = _mm_unpacklo_ps(_L3, _L4);
+ C = _mm_unpackhi_ps(_L1, _L2);
+ D = _mm_unpackhi_ps(_L3, _L4);
+ }
+ else
+ {
+ A = _mm_movelh_ps(_L1, _L2);
+ B = _mm_movehl_ps(_L2, _L1);
+ C = _mm_movelh_ps(_L3, _L4);
+ D = _mm_movehl_ps(_L4, _L3);
+ }
+
+ __m128 iA, iB, iC, iD, // partial inverse of the sub-matrices
+ DC, AB;
+ __m128 dA, dB, dC, dD; // determinant of the sub-matrices
+ __m128 det, d, d1, d2;
+ __m128 rd; // reciprocal of the determinant
+
+ // AB = A# * B
+ AB = _mm_mul_ps(_mm_shuffle_ps(A,A,0x0F), B);
+ AB = _mm_sub_ps(AB,_mm_mul_ps(_mm_shuffle_ps(A,A,0xA5), _mm_shuffle_ps(B,B,0x4E)));
+ // DC = D# * C
+ DC = _mm_mul_ps(_mm_shuffle_ps(D,D,0x0F), C);
+ DC = _mm_sub_ps(DC,_mm_mul_ps(_mm_shuffle_ps(D,D,0xA5), _mm_shuffle_ps(C,C,0x4E)));
+
+ // dA = |A|
+ dA = _mm_mul_ps(_mm_shuffle_ps(A, A, 0x5F),A);
+ dA = _mm_sub_ss(dA, _mm_movehl_ps(dA,dA));
+ // dB = |B|
+ dB = _mm_mul_ps(_mm_shuffle_ps(B, B, 0x5F),B);
+ dB = _mm_sub_ss(dB, _mm_movehl_ps(dB,dB));
+
+ // dC = |C|
+ dC = _mm_mul_ps(_mm_shuffle_ps(C, C, 0x5F),C);
+ dC = _mm_sub_ss(dC, _mm_movehl_ps(dC,dC));
+ // dD = |D|
+ dD = _mm_mul_ps(_mm_shuffle_ps(D, D, 0x5F),D);
+ dD = _mm_sub_ss(dD, _mm_movehl_ps(dD,dD));
+
+ // d = trace(AB*DC) = trace(A#*B*D#*C)
+ d = _mm_mul_ps(_mm_shuffle_ps(DC,DC,0xD8),AB);
+
+ // iD = C*A#*B
+ iD = _mm_mul_ps(_mm_shuffle_ps(C,C,0xA0), _mm_movelh_ps(AB,AB));
+ iD = _mm_add_ps(iD,_mm_mul_ps(_mm_shuffle_ps(C,C,0xF5), _mm_movehl_ps(AB,AB)));
+ // iA = B*D#*C
+ iA = _mm_mul_ps(_mm_shuffle_ps(B,B,0xA0), _mm_movelh_ps(DC,DC));
+ iA = _mm_add_ps(iA,_mm_mul_ps(_mm_shuffle_ps(B,B,0xF5), _mm_movehl_ps(DC,DC)));
+
+ // d = trace(AB*DC) = trace(A#*B*D#*C) [continue]
+ d = _mm_add_ps(d, _mm_movehl_ps(d, d));
+ d = _mm_add_ss(d, _mm_shuffle_ps(d, d, 1));
+ d1 = _mm_mul_ss(dA,dD);
+ d2 = _mm_mul_ss(dB,dC);
+
+ // iD = D*|A| - C*A#*B
+ iD = _mm_sub_ps(_mm_mul_ps(D,_mm_shuffle_ps(dA,dA,0)), iD);
+
+ // iA = A*|D| - B*D#*C;
+ iA = _mm_sub_ps(_mm_mul_ps(A,_mm_shuffle_ps(dD,dD,0)), iA);
+
+ // det = |A|*|D| + |B|*|C| - trace(A#*B*D#*C)
+ det = _mm_sub_ss(_mm_add_ss(d1,d2),d);
+ rd = _mm_div_ss(_mm_set_ss(1.0f), det);
+
+// #ifdef ZERO_SINGULAR
+// rd = _mm_and_ps(_mm_cmpneq_ss(det,_mm_setzero_ps()), rd);
+// #endif
+
+ // iB = D * (A#B)# = D*B#*A
+ iB = _mm_mul_ps(D, _mm_shuffle_ps(AB,AB,0x33));
+ iB = _mm_sub_ps(iB, _mm_mul_ps(_mm_shuffle_ps(D,D,0xB1), _mm_shuffle_ps(AB,AB,0x66)));
+ // iC = A * (D#C)# = A*C#*D
+ iC = _mm_mul_ps(A, _mm_shuffle_ps(DC,DC,0x33));
+ iC = _mm_sub_ps(iC, _mm_mul_ps(_mm_shuffle_ps(A,A,0xB1), _mm_shuffle_ps(DC,DC,0x66)));
+
+ rd = _mm_shuffle_ps(rd,rd,0);
+ rd = _mm_xor_ps(rd, _mm_load_ps((float*)_Sign_PNNP));
+
+ // iB = C*|B| - D*B#*A
+ iB = _mm_sub_ps(_mm_mul_ps(C,_mm_shuffle_ps(dB,dB,0)), iB);
+
+ // iC = B*|C| - A*C#*D;
+ iC = _mm_sub_ps(_mm_mul_ps(B,_mm_shuffle_ps(dC,dC,0)), iC);
+
+ // iX = iX / det
+ iA = _mm_mul_ps(rd,iA);
+ iB = _mm_mul_ps(rd,iB);
+ iC = _mm_mul_ps(rd,iC);
+ iD = _mm_mul_ps(rd,iD);
+
+ result.template writePacket<ResultAlignment>( 0, _mm_shuffle_ps(iA,iB,0x77));
+ result.template writePacket<ResultAlignment>( 4, _mm_shuffle_ps(iA,iB,0x22));
+ result.template writePacket<ResultAlignment>( 8, _mm_shuffle_ps(iC,iD,0x77));
+ result.template writePacket<ResultAlignment>(12, _mm_shuffle_ps(iC,iD,0x22));
+ }
+
+};
+
+template<typename MatrixType, typename ResultType>
+struct compute_inverse_size4<Architecture::SSE, double, MatrixType, ResultType>
+{
+ enum {
+ MatrixAlignment = bool(MatrixType::Flags&AlignedBit),
+ ResultAlignment = bool(ResultType::Flags&AlignedBit),
+ StorageOrdersMatch = (MatrixType::Flags&RowMajorBit) == (ResultType::Flags&RowMajorBit)
+ };
+ static void run(const MatrixType& matrix, ResultType& result)
+ {
+ const __m128d _Sign_NP = _mm_castsi128_pd(_mm_set_epi32(0x0,0x0,0x80000000,0x0));
+ const __m128d _Sign_PN = _mm_castsi128_pd(_mm_set_epi32(0x80000000,0x0,0x0,0x0));
+
+ // The inverse is calculated using "Divide and Conquer" technique. The
+ // original matrix is divide into four 2x2 sub-matrices. Since each
+ // register of the matrix holds two element, the smaller matrices are
+ // consisted of two registers. Hence we get a better locality of the
+ // calculations.
+
+ // the four sub-matrices
+ __m128d A1, A2, B1, B2, C1, C2, D1, D2;
+
+ if(StorageOrdersMatch)
+ {
+ A1 = matrix.template packet<MatrixAlignment>( 0); B1 = matrix.template packet<MatrixAlignment>( 2);
+ A2 = matrix.template packet<MatrixAlignment>( 4); B2 = matrix.template packet<MatrixAlignment>( 6);
+ C1 = matrix.template packet<MatrixAlignment>( 8); D1 = matrix.template packet<MatrixAlignment>(10);
+ C2 = matrix.template packet<MatrixAlignment>(12); D2 = matrix.template packet<MatrixAlignment>(14);
+ }
+ else
+ {
+ __m128d tmp;
+ A1 = matrix.template packet<MatrixAlignment>( 0); C1 = matrix.template packet<MatrixAlignment>( 2);
+ A2 = matrix.template packet<MatrixAlignment>( 4); C2 = matrix.template packet<MatrixAlignment>( 6);
+ tmp = A1;
+ A1 = _mm_unpacklo_pd(A1,A2);
+ A2 = _mm_unpackhi_pd(tmp,A2);
+ tmp = C1;
+ C1 = _mm_unpacklo_pd(C1,C2);
+ C2 = _mm_unpackhi_pd(tmp,C2);
+
+ B1 = matrix.template packet<MatrixAlignment>( 8); D1 = matrix.template packet<MatrixAlignment>(10);
+ B2 = matrix.template packet<MatrixAlignment>(12); D2 = matrix.template packet<MatrixAlignment>(14);
+ tmp = B1;
+ B1 = _mm_unpacklo_pd(B1,B2);
+ B2 = _mm_unpackhi_pd(tmp,B2);
+ tmp = D1;
+ D1 = _mm_unpacklo_pd(D1,D2);
+ D2 = _mm_unpackhi_pd(tmp,D2);
+ }
+
+ __m128d iA1, iA2, iB1, iB2, iC1, iC2, iD1, iD2, // partial invese of the sub-matrices
+ DC1, DC2, AB1, AB2;
+ __m128d dA, dB, dC, dD; // determinant of the sub-matrices
+ __m128d det, d1, d2, rd;
+
+ // dA = |A|
+ dA = _mm_shuffle_pd(A2, A2, 1);
+ dA = _mm_mul_pd(A1, dA);
+ dA = _mm_sub_sd(dA, _mm_shuffle_pd(dA,dA,3));
+ // dB = |B|
+ dB = _mm_shuffle_pd(B2, B2, 1);
+ dB = _mm_mul_pd(B1, dB);
+ dB = _mm_sub_sd(dB, _mm_shuffle_pd(dB,dB,3));
+
+ // AB = A# * B
+ AB1 = _mm_mul_pd(B1, _mm_shuffle_pd(A2,A2,3));
+ AB2 = _mm_mul_pd(B2, _mm_shuffle_pd(A1,A1,0));
+ AB1 = _mm_sub_pd(AB1, _mm_mul_pd(B2, _mm_shuffle_pd(A1,A1,3)));
+ AB2 = _mm_sub_pd(AB2, _mm_mul_pd(B1, _mm_shuffle_pd(A2,A2,0)));
+
+ // dC = |C|
+ dC = _mm_shuffle_pd(C2, C2, 1);
+ dC = _mm_mul_pd(C1, dC);
+ dC = _mm_sub_sd(dC, _mm_shuffle_pd(dC,dC,3));
+ // dD = |D|
+ dD = _mm_shuffle_pd(D2, D2, 1);
+ dD = _mm_mul_pd(D1, dD);
+ dD = _mm_sub_sd(dD, _mm_shuffle_pd(dD,dD,3));
+
+ // DC = D# * C
+ DC1 = _mm_mul_pd(C1, _mm_shuffle_pd(D2,D2,3));
+ DC2 = _mm_mul_pd(C2, _mm_shuffle_pd(D1,D1,0));
+ DC1 = _mm_sub_pd(DC1, _mm_mul_pd(C2, _mm_shuffle_pd(D1,D1,3)));
+ DC2 = _mm_sub_pd(DC2, _mm_mul_pd(C1, _mm_shuffle_pd(D2,D2,0)));
+
+ // rd = trace(AB*DC) = trace(A#*B*D#*C)
+ d1 = _mm_mul_pd(AB1, _mm_shuffle_pd(DC1, DC2, 0));
+ d2 = _mm_mul_pd(AB2, _mm_shuffle_pd(DC1, DC2, 3));
+ rd = _mm_add_pd(d1, d2);
+ rd = _mm_add_sd(rd, _mm_shuffle_pd(rd, rd,3));
+
+ // iD = C*A#*B
+ iD1 = _mm_mul_pd(AB1, _mm_shuffle_pd(C1,C1,0));
+ iD2 = _mm_mul_pd(AB1, _mm_shuffle_pd(C2,C2,0));
+ iD1 = _mm_add_pd(iD1, _mm_mul_pd(AB2, _mm_shuffle_pd(C1,C1,3)));
+ iD2 = _mm_add_pd(iD2, _mm_mul_pd(AB2, _mm_shuffle_pd(C2,C2,3)));
+
+ // iA = B*D#*C
+ iA1 = _mm_mul_pd(DC1, _mm_shuffle_pd(B1,B1,0));
+ iA2 = _mm_mul_pd(DC1, _mm_shuffle_pd(B2,B2,0));
+ iA1 = _mm_add_pd(iA1, _mm_mul_pd(DC2, _mm_shuffle_pd(B1,B1,3)));
+ iA2 = _mm_add_pd(iA2, _mm_mul_pd(DC2, _mm_shuffle_pd(B2,B2,3)));
+
+ // iD = D*|A| - C*A#*B
+ dA = _mm_shuffle_pd(dA,dA,0);
+ iD1 = _mm_sub_pd(_mm_mul_pd(D1, dA), iD1);
+ iD2 = _mm_sub_pd(_mm_mul_pd(D2, dA), iD2);
+
+ // iA = A*|D| - B*D#*C;
+ dD = _mm_shuffle_pd(dD,dD,0);
+ iA1 = _mm_sub_pd(_mm_mul_pd(A1, dD), iA1);
+ iA2 = _mm_sub_pd(_mm_mul_pd(A2, dD), iA2);
+
+ d1 = _mm_mul_sd(dA, dD);
+ d2 = _mm_mul_sd(dB, dC);
+
+ // iB = D * (A#B)# = D*B#*A
+ iB1 = _mm_mul_pd(D1, _mm_shuffle_pd(AB2,AB1,1));
+ iB2 = _mm_mul_pd(D2, _mm_shuffle_pd(AB2,AB1,1));
+ iB1 = _mm_sub_pd(iB1, _mm_mul_pd(_mm_shuffle_pd(D1,D1,1), _mm_shuffle_pd(AB2,AB1,2)));
+ iB2 = _mm_sub_pd(iB2, _mm_mul_pd(_mm_shuffle_pd(D2,D2,1), _mm_shuffle_pd(AB2,AB1,2)));
+
+ // det = |A|*|D| + |B|*|C| - trace(A#*B*D#*C)
+ det = _mm_add_sd(d1, d2);
+ det = _mm_sub_sd(det, rd);
+
+ // iC = A * (D#C)# = A*C#*D
+ iC1 = _mm_mul_pd(A1, _mm_shuffle_pd(DC2,DC1,1));
+ iC2 = _mm_mul_pd(A2, _mm_shuffle_pd(DC2,DC1,1));
+ iC1 = _mm_sub_pd(iC1, _mm_mul_pd(_mm_shuffle_pd(A1,A1,1), _mm_shuffle_pd(DC2,DC1,2)));
+ iC2 = _mm_sub_pd(iC2, _mm_mul_pd(_mm_shuffle_pd(A2,A2,1), _mm_shuffle_pd(DC2,DC1,2)));
+
+ rd = _mm_div_sd(_mm_set_sd(1.0), det);
+// #ifdef ZERO_SINGULAR
+// rd = _mm_and_pd(_mm_cmpneq_sd(det,_mm_setzero_pd()), rd);
+// #endif
+ rd = _mm_shuffle_pd(rd,rd,0);
+
+ // iB = C*|B| - D*B#*A
+ dB = _mm_shuffle_pd(dB,dB,0);
+ iB1 = _mm_sub_pd(_mm_mul_pd(C1, dB), iB1);
+ iB2 = _mm_sub_pd(_mm_mul_pd(C2, dB), iB2);
+
+ d1 = _mm_xor_pd(rd, _Sign_PN);
+ d2 = _mm_xor_pd(rd, _Sign_NP);
+
+ // iC = B*|C| - A*C#*D;
+ dC = _mm_shuffle_pd(dC,dC,0);
+ iC1 = _mm_sub_pd(_mm_mul_pd(B1, dC), iC1);
+ iC2 = _mm_sub_pd(_mm_mul_pd(B2, dC), iC2);
+
+ result.template writePacket<ResultAlignment>( 0, _mm_mul_pd(_mm_shuffle_pd(iA2, iA1, 3), d1)); // iA# / det
+ result.template writePacket<ResultAlignment>( 4, _mm_mul_pd(_mm_shuffle_pd(iA2, iA1, 0), d2));
+ result.template writePacket<ResultAlignment>( 2, _mm_mul_pd(_mm_shuffle_pd(iB2, iB1, 3), d1)); // iB# / det
+ result.template writePacket<ResultAlignment>( 6, _mm_mul_pd(_mm_shuffle_pd(iB2, iB1, 0), d2));
+ result.template writePacket<ResultAlignment>( 8, _mm_mul_pd(_mm_shuffle_pd(iC2, iC1, 3), d1)); // iC# / det
+ result.template writePacket<ResultAlignment>(12, _mm_mul_pd(_mm_shuffle_pd(iC2, iC1, 0), d2));
+ result.template writePacket<ResultAlignment>(10, _mm_mul_pd(_mm_shuffle_pd(iD2, iD1, 3), d1)); // iD# / det
+ result.template writePacket<ResultAlignment>(14, _mm_mul_pd(_mm_shuffle_pd(iD2, iD1, 0), d2));
+ }
+};
+
+} // end namespace internal
+
+} // end namespace Eigen
+
+#endif // EIGEN_INVERSE_SSE_H
diff --git a/Eigen/src/OrderingMethods/Amd.h b/Eigen/src/OrderingMethods/Amd.h
new file mode 100644
index 000000000..ce04852b8
--- /dev/null
+++ b/Eigen/src/OrderingMethods/Amd.h
@@ -0,0 +1,439 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra.
+//
+// Copyright (C) 2010 Gael Guennebaud <gael.guennebaud@inria.fr>
+//
+// This Source Code Form is subject to the terms of the Mozilla
+// Public License v. 2.0. If a copy of the MPL was not distributed
+// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+/*
+
+NOTE: this routine has been adapted from the CSparse library:
+
+Copyright (c) 2006, Timothy A. Davis.
+http://www.cise.ufl.edu/research/sparse/CSparse
+
+CSparse is free software; you can redistribute it and/or
+modify it under the terms of the GNU Lesser General Public
+License as published by the Free Software Foundation; either
+version 2.1 of the License, or (at your option) any later version.
+
+CSparse is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+Lesser General Public License for more details.
+
+You should have received a copy of the GNU Lesser General Public
+License along with this Module; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+
+*/
+
+#include "../Core/util/NonMPL2.h"
+
+#ifndef EIGEN_SPARSE_AMD_H
+#define EIGEN_SPARSE_AMD_H
+
+namespace Eigen {
+
+namespace internal {
+
+template<typename T> inline T amd_flip(const T& i) { return -i-2; }
+template<typename T> inline T amd_unflip(const T& i) { return i<0 ? amd_flip(i) : i; }
+template<typename T0, typename T1> inline bool amd_marked(const T0* w, const T1& j) { return w[j]<0; }
+template<typename T0, typename T1> inline void amd_mark(const T0* w, const T1& j) { return w[j] = amd_flip(w[j]); }
+
+/* clear w */
+template<typename Index>
+static int cs_wclear (Index mark, Index lemax, Index *w, Index n)
+{
+ Index k;
+ if(mark < 2 || (mark + lemax < 0))
+ {
+ for(k = 0; k < n; k++)
+ if(w[k] != 0)
+ w[k] = 1;
+ mark = 2;
+ }
+ return (mark); /* at this point, w[0..n-1] < mark holds */
+}
+
+/* depth-first search and postorder of a tree rooted at node j */
+template<typename Index>
+Index cs_tdfs(Index j, Index k, Index *head, const Index *next, Index *post, Index *stack)
+{
+ int i, p, top = 0;
+ if(!head || !next || !post || !stack) return (-1); /* check inputs */
+ stack[0] = j; /* place j on the stack */
+ while (top >= 0) /* while (stack is not empty) */
+ {
+ p = stack[top]; /* p = top of stack */
+ i = head[p]; /* i = youngest child of p */
+ if(i == -1)
+ {
+ top--; /* p has no unordered children left */
+ post[k++] = p; /* node p is the kth postordered node */
+ }
+ else
+ {
+ head[p] = next[i]; /* remove i from children of p */
+ stack[++top] = i; /* start dfs on child node i */
+ }
+ }
+ return k;
+}
+
+
+/** \internal
+ * Approximate minimum degree ordering algorithm.
+ * \returns the permutation P reducing the fill-in of the input matrix \a C
+ * The input matrix \a C must be a selfadjoint compressed column major SparseMatrix object. Both the upper and lower parts have to be stored, but the diagonal entries are optional.
+ * On exit the values of C are destroyed */
+template<typename Scalar, typename Index>
+void minimum_degree_ordering(SparseMatrix<Scalar,ColMajor,Index>& C, PermutationMatrix<Dynamic,Dynamic,Index>& perm)
+{
+ using std::sqrt;
+ typedef SparseMatrix<Scalar,ColMajor,Index> CCS;
+
+ int d, dk, dext, lemax = 0, e, elenk, eln, i, j, k, k1,
+ k2, k3, jlast, ln, dense, nzmax, mindeg = 0, nvi, nvj, nvk, mark, wnvi,
+ ok, nel = 0, p, p1, p2, p3, p4, pj, pk, pk1, pk2, pn, q, t;
+ unsigned int h;
+
+ Index n = C.cols();
+ dense = std::max<Index> (16, Index(10 * sqrt(double(n)))); /* find dense threshold */
+ dense = std::min<Index> (n-2, dense);
+
+ Index cnz = C.nonZeros();
+ perm.resize(n+1);
+ t = cnz + cnz/5 + 2*n; /* add elbow room to C */
+ C.resizeNonZeros(t);
+
+ Index* W = new Index[8*(n+1)]; /* get workspace */
+ Index* len = W;
+ Index* nv = W + (n+1);
+ Index* next = W + 2*(n+1);
+ Index* head = W + 3*(n+1);
+ Index* elen = W + 4*(n+1);
+ Index* degree = W + 5*(n+1);
+ Index* w = W + 6*(n+1);
+ Index* hhead = W + 7*(n+1);
+ Index* last = perm.indices().data(); /* use P as workspace for last */
+
+ /* --- Initialize quotient graph ---------------------------------------- */
+ Index* Cp = C.outerIndexPtr();
+ Index* Ci = C.innerIndexPtr();
+ for(k = 0; k < n; k++)
+ len[k] = Cp[k+1] - Cp[k];
+ len[n] = 0;
+ nzmax = t;
+
+ for(i = 0; i <= n; i++)
+ {
+ head[i] = -1; // degree list i is empty
+ last[i] = -1;
+ next[i] = -1;
+ hhead[i] = -1; // hash list i is empty
+ nv[i] = 1; // node i is just one node
+ w[i] = 1; // node i is alive
+ elen[i] = 0; // Ek of node i is empty
+ degree[i] = len[i]; // degree of node i
+ }
+ mark = internal::cs_wclear<Index>(0, 0, w, n); /* clear w */
+ elen[n] = -2; /* n is a dead element */
+ Cp[n] = -1; /* n is a root of assembly tree */
+ w[n] = 0; /* n is a dead element */
+
+ /* --- Initialize degree lists ------------------------------------------ */
+ for(i = 0; i < n; i++)
+ {
+ d = degree[i];
+ if(d == 0) /* node i is empty */
+ {
+ elen[i] = -2; /* element i is dead */
+ nel++;
+ Cp[i] = -1; /* i is a root of assembly tree */
+ w[i] = 0;
+ }
+ else if(d > dense) /* node i is dense */
+ {
+ nv[i] = 0; /* absorb i into element n */
+ elen[i] = -1; /* node i is dead */
+ nel++;
+ Cp[i] = amd_flip (n);
+ nv[n]++;
+ }
+ else
+ {
+ if(head[d] != -1) last[head[d]] = i;
+ next[i] = head[d]; /* put node i in degree list d */
+ head[d] = i;
+ }
+ }
+
+ while (nel < n) /* while (selecting pivots) do */
+ {
+ /* --- Select node of minimum approximate degree -------------------- */
+ for(k = -1; mindeg < n && (k = head[mindeg]) == -1; mindeg++) {}
+ if(next[k] != -1) last[next[k]] = -1;
+ head[mindeg] = next[k]; /* remove k from degree list */
+ elenk = elen[k]; /* elenk = |Ek| */
+ nvk = nv[k]; /* # of nodes k represents */
+ nel += nvk; /* nv[k] nodes of A eliminated */
+
+ /* --- Garbage collection ------------------------------------------- */
+ if(elenk > 0 && cnz + mindeg >= nzmax)
+ {
+ for(j = 0; j < n; j++)
+ {
+ if((p = Cp[j]) >= 0) /* j is a live node or element */
+ {
+ Cp[j] = Ci[p]; /* save first entry of object */
+ Ci[p] = amd_flip (j); /* first entry is now amd_flip(j) */
+ }
+ }
+ for(q = 0, p = 0; p < cnz; ) /* scan all of memory */
+ {
+ if((j = amd_flip (Ci[p++])) >= 0) /* found object j */
+ {
+ Ci[q] = Cp[j]; /* restore first entry of object */
+ Cp[j] = q++; /* new pointer to object j */
+ for(k3 = 0; k3 < len[j]-1; k3++) Ci[q++] = Ci[p++];
+ }
+ }
+ cnz = q; /* Ci[cnz...nzmax-1] now free */
+ }
+
+ /* --- Construct new element ---------------------------------------- */
+ dk = 0;
+ nv[k] = -nvk; /* flag k as in Lk */
+ p = Cp[k];
+ pk1 = (elenk == 0) ? p : cnz; /* do in place if elen[k] == 0 */
+ pk2 = pk1;
+ for(k1 = 1; k1 <= elenk + 1; k1++)
+ {
+ if(k1 > elenk)
+ {
+ e = k; /* search the nodes in k */
+ pj = p; /* list of nodes starts at Ci[pj]*/
+ ln = len[k] - elenk; /* length of list of nodes in k */
+ }
+ else
+ {
+ e = Ci[p++]; /* search the nodes in e */
+ pj = Cp[e];
+ ln = len[e]; /* length of list of nodes in e */
+ }
+ for(k2 = 1; k2 <= ln; k2++)
+ {
+ i = Ci[pj++];
+ if((nvi = nv[i]) <= 0) continue; /* node i dead, or seen */
+ dk += nvi; /* degree[Lk] += size of node i */
+ nv[i] = -nvi; /* negate nv[i] to denote i in Lk*/
+ Ci[pk2++] = i; /* place i in Lk */
+ if(next[i] != -1) last[next[i]] = last[i];
+ if(last[i] != -1) /* remove i from degree list */
+ {
+ next[last[i]] = next[i];
+ }
+ else
+ {
+ head[degree[i]] = next[i];
+ }
+ }
+ if(e != k)
+ {
+ Cp[e] = amd_flip (k); /* absorb e into k */
+ w[e] = 0; /* e is now a dead element */
+ }
+ }
+ if(elenk != 0) cnz = pk2; /* Ci[cnz...nzmax] is free */
+ degree[k] = dk; /* external degree of k - |Lk\i| */
+ Cp[k] = pk1; /* element k is in Ci[pk1..pk2-1] */
+ len[k] = pk2 - pk1;
+ elen[k] = -2; /* k is now an element */
+
+ /* --- Find set differences ----------------------------------------- */
+ mark = internal::cs_wclear<Index>(mark, lemax, w, n); /* clear w if necessary */
+ for(pk = pk1; pk < pk2; pk++) /* scan 1: find |Le\Lk| */
+ {
+ i = Ci[pk];
+ if((eln = elen[i]) <= 0) continue;/* skip if elen[i] empty */
+ nvi = -nv[i]; /* nv[i] was negated */
+ wnvi = mark - nvi;
+ for(p = Cp[i]; p <= Cp[i] + eln - 1; p++) /* scan Ei */
+ {
+ e = Ci[p];
+ if(w[e] >= mark)
+ {
+ w[e] -= nvi; /* decrement |Le\Lk| */
+ }
+ else if(w[e] != 0) /* ensure e is a live element */
+ {
+ w[e] = degree[e] + wnvi; /* 1st time e seen in scan 1 */
+ }
+ }
+ }
+
+ /* --- Degree update ------------------------------------------------ */
+ for(pk = pk1; pk < pk2; pk++) /* scan2: degree update */
+ {
+ i = Ci[pk]; /* consider node i in Lk */
+ p1 = Cp[i];
+ p2 = p1 + elen[i] - 1;
+ pn = p1;
+ for(h = 0, d = 0, p = p1; p <= p2; p++) /* scan Ei */
+ {
+ e = Ci[p];
+ if(w[e] != 0) /* e is an unabsorbed element */
+ {
+ dext = w[e] - mark; /* dext = |Le\Lk| */
+ if(dext > 0)
+ {
+ d += dext; /* sum up the set differences */
+ Ci[pn++] = e; /* keep e in Ei */
+ h += e; /* compute the hash of node i */
+ }
+ else
+ {
+ Cp[e] = amd_flip (k); /* aggressive absorb. e->k */
+ w[e] = 0; /* e is a dead element */
+ }
+ }
+ }
+ elen[i] = pn - p1 + 1; /* elen[i] = |Ei| */
+ p3 = pn;
+ p4 = p1 + len[i];
+ for(p = p2 + 1; p < p4; p++) /* prune edges in Ai */
+ {
+ j = Ci[p];
+ if((nvj = nv[j]) <= 0) continue; /* node j dead or in Lk */
+ d += nvj; /* degree(i) += |j| */
+ Ci[pn++] = j; /* place j in node list of i */
+ h += j; /* compute hash for node i */
+ }
+ if(d == 0) /* check for mass elimination */
+ {
+ Cp[i] = amd_flip (k); /* absorb i into k */
+ nvi = -nv[i];
+ dk -= nvi; /* |Lk| -= |i| */
+ nvk += nvi; /* |k| += nv[i] */
+ nel += nvi;
+ nv[i] = 0;
+ elen[i] = -1; /* node i is dead */
+ }
+ else
+ {
+ degree[i] = std::min<Index> (degree[i], d); /* update degree(i) */
+ Ci[pn] = Ci[p3]; /* move first node to end */
+ Ci[p3] = Ci[p1]; /* move 1st el. to end of Ei */
+ Ci[p1] = k; /* add k as 1st element in of Ei */
+ len[i] = pn - p1 + 1; /* new len of adj. list of node i */
+ h %= n; /* finalize hash of i */
+ next[i] = hhead[h]; /* place i in hash bucket */
+ hhead[h] = i;
+ last[i] = h; /* save hash of i in last[i] */
+ }
+ } /* scan2 is done */
+ degree[k] = dk; /* finalize |Lk| */
+ lemax = std::max<Index>(lemax, dk);
+ mark = internal::cs_wclear<Index>(mark+lemax, lemax, w, n); /* clear w */
+
+ /* --- Supernode detection ------------------------------------------ */
+ for(pk = pk1; pk < pk2; pk++)
+ {
+ i = Ci[pk];
+ if(nv[i] >= 0) continue; /* skip if i is dead */
+ h = last[i]; /* scan hash bucket of node i */
+ i = hhead[h];
+ hhead[h] = -1; /* hash bucket will be empty */
+ for(; i != -1 && next[i] != -1; i = next[i], mark++)
+ {
+ ln = len[i];
+ eln = elen[i];
+ for(p = Cp[i]+1; p <= Cp[i] + ln-1; p++) w[Ci[p]] = mark;
+ jlast = i;
+ for(j = next[i]; j != -1; ) /* compare i with all j */
+ {
+ ok = (len[j] == ln) && (elen[j] == eln);
+ for(p = Cp[j] + 1; ok && p <= Cp[j] + ln - 1; p++)
+ {
+ if(w[Ci[p]] != mark) ok = 0; /* compare i and j*/
+ }
+ if(ok) /* i and j are identical */
+ {
+ Cp[j] = amd_flip (i); /* absorb j into i */
+ nv[i] += nv[j];
+ nv[j] = 0;
+ elen[j] = -1; /* node j is dead */
+ j = next[j]; /* delete j from hash bucket */
+ next[jlast] = j;
+ }
+ else
+ {
+ jlast = j; /* j and i are different */
+ j = next[j];
+ }
+ }
+ }
+ }
+
+ /* --- Finalize new element------------------------------------------ */
+ for(p = pk1, pk = pk1; pk < pk2; pk++) /* finalize Lk */
+ {
+ i = Ci[pk];
+ if((nvi = -nv[i]) <= 0) continue;/* skip if i is dead */
+ nv[i] = nvi; /* restore nv[i] */
+ d = degree[i] + dk - nvi; /* compute external degree(i) */
+ d = std::min<Index> (d, n - nel - nvi);
+ if(head[d] != -1) last[head[d]] = i;
+ next[i] = head[d]; /* put i back in degree list */
+ last[i] = -1;
+ head[d] = i;
+ mindeg = std::min<Index> (mindeg, d); /* find new minimum degree */
+ degree[i] = d;
+ Ci[p++] = i; /* place i in Lk */
+ }
+ nv[k] = nvk; /* # nodes absorbed into k */
+ if((len[k] = p-pk1) == 0) /* length of adj list of element k*/
+ {
+ Cp[k] = -1; /* k is a root of the tree */
+ w[k] = 0; /* k is now a dead element */
+ }
+ if(elenk != 0) cnz = p; /* free unused space in Lk */
+ }
+
+ /* --- Postordering ----------------------------------------------------- */
+ for(i = 0; i < n; i++) Cp[i] = amd_flip (Cp[i]);/* fix assembly tree */
+ for(j = 0; j <= n; j++) head[j] = -1;
+ for(j = n; j >= 0; j--) /* place unordered nodes in lists */
+ {
+ if(nv[j] > 0) continue; /* skip if j is an element */
+ next[j] = head[Cp[j]]; /* place j in list of its parent */
+ head[Cp[j]] = j;
+ }
+ for(e = n; e >= 0; e--) /* place elements in lists */
+ {
+ if(nv[e] <= 0) continue; /* skip unless e is an element */
+ if(Cp[e] != -1)
+ {
+ next[e] = head[Cp[e]]; /* place e in list of its parent */
+ head[Cp[e]] = e;
+ }
+ }
+ for(k = 0, i = 0; i <= n; i++) /* postorder the assembly tree */
+ {
+ if(Cp[i] == -1) k = internal::cs_tdfs<Index>(i, k, head, next, perm.indices().data(), w);
+ }
+
+ perm.indices().conservativeResize(n);
+
+ delete[] W;
+}
+
+} // namespace internal
+
+} // end namespace Eigen
+
+#endif // EIGEN_SPARSE_AMD_H
diff --git a/Eigen/src/OrderingMethods/CMakeLists.txt b/Eigen/src/OrderingMethods/CMakeLists.txt
new file mode 100644
index 000000000..9f4bb2758
--- /dev/null
+++ b/Eigen/src/OrderingMethods/CMakeLists.txt
@@ -0,0 +1,6 @@
+FILE(GLOB Eigen_OrderingMethods_SRCS "*.h")
+
+INSTALL(FILES
+ ${Eigen_OrderingMethods_SRCS}
+ DESTINATION ${INCLUDE_INSTALL_DIR}/Eigen/src/OrderingMethods COMPONENT Devel
+ )
diff --git a/Eigen/src/PaStiXSupport/CMakeLists.txt b/Eigen/src/PaStiXSupport/CMakeLists.txt
new file mode 100644
index 000000000..28c657e9b
--- /dev/null
+++ b/Eigen/src/PaStiXSupport/CMakeLists.txt
@@ -0,0 +1,6 @@
+FILE(GLOB Eigen_PastixSupport_SRCS "*.h")
+
+INSTALL(FILES
+ ${Eigen_PastixSupport_SRCS}
+ DESTINATION ${INCLUDE_INSTALL_DIR}/Eigen/src/PaStiXSupport COMPONENT Devel
+ )
diff --git a/Eigen/src/PaStiXSupport/PaStiXSupport.h b/Eigen/src/PaStiXSupport/PaStiXSupport.h
new file mode 100644
index 000000000..82e137c64
--- /dev/null
+++ b/Eigen/src/PaStiXSupport/PaStiXSupport.h
@@ -0,0 +1,742 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra.
+//
+// Copyright (C) 2012 Désiré Nuentsa-Wakam <desire.nuentsa_wakam@inria.fr>
+//
+// This Source Code Form is subject to the terms of the Mozilla
+// Public License v. 2.0. If a copy of the MPL was not distributed
+// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+#ifndef EIGEN_PASTIXSUPPORT_H
+#define EIGEN_PASTIXSUPPORT_H
+
+namespace Eigen {
+
+/** \ingroup PaStiXSupport_Module
+ * \brief Interface to the PaStix solver
+ *
+ * This class is used to solve the linear systems A.X = B via the PaStix library.
+ * The matrix can be either real or complex, symmetric or not.
+ *
+ * \sa TutorialSparseDirectSolvers
+ */
+template<typename _MatrixType, bool IsStrSym = false> class PastixLU;
+template<typename _MatrixType, int Options> class PastixLLT;
+template<typename _MatrixType, int Options> class PastixLDLT;
+
+namespace internal
+{
+
+ template<class Pastix> struct pastix_traits;
+
+ template<typename _MatrixType>
+ struct pastix_traits< PastixLU<_MatrixType> >
+ {
+ typedef _MatrixType MatrixType;
+ typedef typename _MatrixType::Scalar Scalar;
+ typedef typename _MatrixType::RealScalar RealScalar;
+ typedef typename _MatrixType::Index Index;
+ };
+
+ template<typename _MatrixType, int Options>
+ struct pastix_traits< PastixLLT<_MatrixType,Options> >
+ {
+ typedef _MatrixType MatrixType;
+ typedef typename _MatrixType::Scalar Scalar;
+ typedef typename _MatrixType::RealScalar RealScalar;
+ typedef typename _MatrixType::Index Index;
+ };
+
+ template<typename _MatrixType, int Options>
+ struct pastix_traits< PastixLDLT<_MatrixType,Options> >
+ {
+ typedef _MatrixType MatrixType;
+ typedef typename _MatrixType::Scalar Scalar;
+ typedef typename _MatrixType::RealScalar RealScalar;
+ typedef typename _MatrixType::Index Index;
+ };
+
+ void eigen_pastix(pastix_data_t **pastix_data, int pastix_comm, int n, int *ptr, int *idx, float *vals, int *perm, int * invp, float *x, int nbrhs, int *iparm, double *dparm)
+ {
+ if (n == 0) { ptr = NULL; idx = NULL; vals = NULL; }
+ if (nbrhs == 0) {x = NULL; nbrhs=1;}
+ s_pastix(pastix_data, pastix_comm, n, ptr, idx, vals, perm, invp, x, nbrhs, iparm, dparm);
+ }
+
+ void eigen_pastix(pastix_data_t **pastix_data, int pastix_comm, int n, int *ptr, int *idx, double *vals, int *perm, int * invp, double *x, int nbrhs, int *iparm, double *dparm)
+ {
+ if (n == 0) { ptr = NULL; idx = NULL; vals = NULL; }
+ if (nbrhs == 0) {x = NULL; nbrhs=1;}
+ d_pastix(pastix_data, pastix_comm, n, ptr, idx, vals, perm, invp, x, nbrhs, iparm, dparm);
+ }
+
+ void eigen_pastix(pastix_data_t **pastix_data, int pastix_comm, int n, int *ptr, int *idx, std::complex<float> *vals, int *perm, int * invp, std::complex<float> *x, int nbrhs, int *iparm, double *dparm)
+ {
+ if (n == 0) { ptr = NULL; idx = NULL; vals = NULL; }
+ if (nbrhs == 0) {x = NULL; nbrhs=1;}
+ c_pastix(pastix_data, pastix_comm, n, ptr, idx, reinterpret_cast<COMPLEX*>(vals), perm, invp, reinterpret_cast<COMPLEX*>(x), nbrhs, iparm, dparm);
+ }
+
+ void eigen_pastix(pastix_data_t **pastix_data, int pastix_comm, int n, int *ptr, int *idx, std::complex<double> *vals, int *perm, int * invp, std::complex<double> *x, int nbrhs, int *iparm, double *dparm)
+ {
+ if (n == 0) { ptr = NULL; idx = NULL; vals = NULL; }
+ if (nbrhs == 0) {x = NULL; nbrhs=1;}
+ z_pastix(pastix_data, pastix_comm, n, ptr, idx, reinterpret_cast<DCOMPLEX*>(vals), perm, invp, reinterpret_cast<DCOMPLEX*>(x), nbrhs, iparm, dparm);
+ }
+
+ // Convert the matrix to Fortran-style Numbering
+ template <typename MatrixType>
+ void c_to_fortran_numbering (MatrixType& mat)
+ {
+ if ( !(mat.outerIndexPtr()[0]) )
+ {
+ int i;
+ for(i = 0; i <= mat.rows(); ++i)
+ ++mat.outerIndexPtr()[i];
+ for(i = 0; i < mat.nonZeros(); ++i)
+ ++mat.innerIndexPtr()[i];
+ }
+ }
+
+ // Convert to C-style Numbering
+ template <typename MatrixType>
+ void fortran_to_c_numbering (MatrixType& mat)
+ {
+ // Check the Numbering
+ if ( mat.outerIndexPtr()[0] == 1 )
+ { // Convert to C-style numbering
+ int i;
+ for(i = 0; i <= mat.rows(); ++i)
+ --mat.outerIndexPtr()[i];
+ for(i = 0; i < mat.nonZeros(); ++i)
+ --mat.innerIndexPtr()[i];
+ }
+ }
+}
+
+// This is the base class to interface with PaStiX functions.
+// Users should not used this class directly.
+template <class Derived>
+class PastixBase : internal::noncopyable
+{
+ public:
+ typedef typename internal::pastix_traits<Derived>::MatrixType _MatrixType;
+ typedef _MatrixType MatrixType;
+ typedef typename MatrixType::Scalar Scalar;
+ typedef typename MatrixType::RealScalar RealScalar;
+ typedef typename MatrixType::Index Index;
+ typedef Matrix<Scalar,Dynamic,1> Vector;
+ typedef SparseMatrix<Scalar, ColMajor> ColSpMatrix;
+
+ public:
+
+ PastixBase() : m_initisOk(false), m_analysisIsOk(false), m_factorizationIsOk(false), m_isInitialized(false), m_pastixdata(0), m_size(0)
+ {
+ init();
+ }
+
+ ~PastixBase()
+ {
+ clean();
+ }
+
+ /** \returns the solution x of \f$ A x = b \f$ using the current decomposition of A.
+ *
+ * \sa compute()
+ */
+ template<typename Rhs>
+ inline const internal::solve_retval<PastixBase, Rhs>
+ solve(const MatrixBase<Rhs>& b) const
+ {
+ eigen_assert(m_isInitialized && "Pastix solver is not initialized.");
+ eigen_assert(rows()==b.rows()
+ && "PastixBase::solve(): invalid number of rows of the right hand side matrix b");
+ return internal::solve_retval<PastixBase, Rhs>(*this, b.derived());
+ }
+
+ template<typename Rhs,typename Dest>
+ bool _solve (const MatrixBase<Rhs> &b, MatrixBase<Dest> &x) const;
+
+ /** \internal */
+ template<typename Rhs, typename DestScalar, int DestOptions, typename DestIndex>
+ void _solve_sparse(const Rhs& b, SparseMatrix<DestScalar,DestOptions,DestIndex> &dest) const
+ {
+ eigen_assert(m_factorizationIsOk && "The decomposition is not in a valid state for solving, you must first call either compute() or symbolic()/numeric()");
+ eigen_assert(rows()==b.rows());
+
+ // we process the sparse rhs per block of NbColsAtOnce columns temporarily stored into a dense matrix.
+ static const int NbColsAtOnce = 1;
+ int rhsCols = b.cols();
+ int size = b.rows();
+ Eigen::Matrix<DestScalar,Dynamic,Dynamic> tmp(size,rhsCols);
+ for(int k=0; k<rhsCols; k+=NbColsAtOnce)
+ {
+ int actualCols = std::min<int>(rhsCols-k, NbColsAtOnce);
+ tmp.leftCols(actualCols) = b.middleCols(k,actualCols);
+ tmp.leftCols(actualCols) = derived().solve(tmp.leftCols(actualCols));
+ dest.middleCols(k,actualCols) = tmp.leftCols(actualCols).sparseView();
+ }
+ }
+
+ Derived& derived()
+ {
+ return *static_cast<Derived*>(this);
+ }
+ const Derived& derived() const
+ {
+ return *static_cast<const Derived*>(this);
+ }
+
+ /** Returns a reference to the integer vector IPARM of PaStiX parameters
+ * to modify the default parameters.
+ * The statistics related to the different phases of factorization and solve are saved here as well
+ * \sa analyzePattern() factorize()
+ */
+ Array<Index,IPARM_SIZE,1>& iparm()
+ {
+ return m_iparm;
+ }
+
+ /** Return a reference to a particular index parameter of the IPARM vector
+ * \sa iparm()
+ */
+
+ int& iparm(int idxparam)
+ {
+ return m_iparm(idxparam);
+ }
+
+ /** Returns a reference to the double vector DPARM of PaStiX parameters
+ * The statistics related to the different phases of factorization and solve are saved here as well
+ * \sa analyzePattern() factorize()
+ */
+ Array<RealScalar,IPARM_SIZE,1>& dparm()
+ {
+ return m_dparm;
+ }
+
+
+ /** Return a reference to a particular index parameter of the DPARM vector
+ * \sa dparm()
+ */
+ double& dparm(int idxparam)
+ {
+ return m_dparm(idxparam);
+ }
+
+ inline Index cols() const { return m_size; }
+ inline Index rows() const { return m_size; }
+
+ /** \brief Reports whether previous computation was successful.
+ *
+ * \returns \c Success if computation was succesful,
+ * \c NumericalIssue if the PaStiX reports a problem
+ * \c InvalidInput if the input matrix is invalid
+ *
+ * \sa iparm()
+ */
+ ComputationInfo info() const
+ {
+ eigen_assert(m_isInitialized && "Decomposition is not initialized.");
+ return m_info;
+ }
+
+ /** \returns the solution x of \f$ A x = b \f$ using the current decomposition of A.
+ *
+ * \sa compute()
+ */
+ template<typename Rhs>
+ inline const internal::sparse_solve_retval<PastixBase, Rhs>
+ solve(const SparseMatrixBase<Rhs>& b) const
+ {
+ eigen_assert(m_isInitialized && "Pastix LU, LLT or LDLT is not initialized.");
+ eigen_assert(rows()==b.rows()
+ && "PastixBase::solve(): invalid number of rows of the right hand side matrix b");
+ return internal::sparse_solve_retval<PastixBase, Rhs>(*this, b.derived());
+ }
+
+ protected:
+
+ // Initialize the Pastix data structure, check the matrix
+ void init();
+
+ // Compute the ordering and the symbolic factorization
+ void analyzePattern(ColSpMatrix& mat);
+
+ // Compute the numerical factorization
+ void factorize(ColSpMatrix& mat);
+
+ // Free all the data allocated by Pastix
+ void clean()
+ {
+ eigen_assert(m_initisOk && "The Pastix structure should be allocated first");
+ m_iparm(IPARM_START_TASK) = API_TASK_CLEAN;
+ m_iparm(IPARM_END_TASK) = API_TASK_CLEAN;
+ internal::eigen_pastix(&m_pastixdata, MPI_COMM_WORLD, 0, 0, 0, (Scalar*)0,
+ m_perm.data(), m_invp.data(), 0, 0, m_iparm.data(), m_dparm.data());
+ }
+
+ void compute(ColSpMatrix& mat);
+
+ int m_initisOk;
+ int m_analysisIsOk;
+ int m_factorizationIsOk;
+ bool m_isInitialized;
+ mutable ComputationInfo m_info;
+ mutable pastix_data_t *m_pastixdata; // Data structure for pastix
+ mutable int m_comm; // The MPI communicator identifier
+ mutable Matrix<int,IPARM_SIZE,1> m_iparm; // integer vector for the input parameters
+ mutable Matrix<double,DPARM_SIZE,1> m_dparm; // Scalar vector for the input parameters
+ mutable Matrix<Index,Dynamic,1> m_perm; // Permutation vector
+ mutable Matrix<Index,Dynamic,1> m_invp; // Inverse permutation vector
+ mutable int m_size; // Size of the matrix
+};
+
+ /** Initialize the PaStiX data structure.
+ *A first call to this function fills iparm and dparm with the default PaStiX parameters
+ * \sa iparm() dparm()
+ */
+template <class Derived>
+void PastixBase<Derived>::init()
+{
+ m_size = 0;
+ m_iparm.setZero(IPARM_SIZE);
+ m_dparm.setZero(DPARM_SIZE);
+
+ m_iparm(IPARM_MODIFY_PARAMETER) = API_NO;
+ pastix(&m_pastixdata, MPI_COMM_WORLD,
+ 0, 0, 0, 0,
+ 0, 0, 0, 1, m_iparm.data(), m_dparm.data());
+
+ m_iparm[IPARM_MATRIX_VERIFICATION] = API_NO;
+ m_iparm[IPARM_VERBOSE] = 2;
+ m_iparm[IPARM_ORDERING] = API_ORDER_SCOTCH;
+ m_iparm[IPARM_INCOMPLETE] = API_NO;
+ m_iparm[IPARM_OOC_LIMIT] = 2000;
+ m_iparm[IPARM_RHS_MAKING] = API_RHS_B;
+ m_iparm(IPARM_MATRIX_VERIFICATION) = API_NO;
+
+ m_iparm(IPARM_START_TASK) = API_TASK_INIT;
+ m_iparm(IPARM_END_TASK) = API_TASK_INIT;
+ internal::eigen_pastix(&m_pastixdata, MPI_COMM_WORLD, 0, 0, 0, (Scalar*)0,
+ 0, 0, 0, 0, m_iparm.data(), m_dparm.data());
+
+ // Check the returned error
+ if(m_iparm(IPARM_ERROR_NUMBER)) {
+ m_info = InvalidInput;
+ m_initisOk = false;
+ }
+ else {
+ m_info = Success;
+ m_initisOk = true;
+ }
+}
+
+template <class Derived>
+void PastixBase<Derived>::compute(ColSpMatrix& mat)
+{
+ eigen_assert(mat.rows() == mat.cols() && "The input matrix should be squared");
+
+ analyzePattern(mat);
+ factorize(mat);
+
+ m_iparm(IPARM_MATRIX_VERIFICATION) = API_NO;
+ m_isInitialized = m_factorizationIsOk;
+}
+
+
+template <class Derived>
+void PastixBase<Derived>::analyzePattern(ColSpMatrix& mat)
+{
+ eigen_assert(m_initisOk && "The initialization of PaSTiX failed");
+
+ // clean previous calls
+ if(m_size>0)
+ clean();
+
+ m_size = mat.rows();
+ m_perm.resize(m_size);
+ m_invp.resize(m_size);
+
+ m_iparm(IPARM_START_TASK) = API_TASK_ORDERING;
+ m_iparm(IPARM_END_TASK) = API_TASK_ANALYSE;
+ internal::eigen_pastix(&m_pastixdata, MPI_COMM_WORLD, m_size, mat.outerIndexPtr(), mat.innerIndexPtr(),
+ mat.valuePtr(), m_perm.data(), m_invp.data(), 0, 0, m_iparm.data(), m_dparm.data());
+
+ // Check the returned error
+ if(m_iparm(IPARM_ERROR_NUMBER))
+ {
+ m_info = NumericalIssue;
+ m_analysisIsOk = false;
+ }
+ else
+ {
+ m_info = Success;
+ m_analysisIsOk = true;
+ }
+}
+
+template <class Derived>
+void PastixBase<Derived>::factorize(ColSpMatrix& mat)
+{
+// if(&m_cpyMat != &mat) m_cpyMat = mat;
+ eigen_assert(m_analysisIsOk && "The analysis phase should be called before the factorization phase");
+ m_iparm(IPARM_START_TASK) = API_TASK_NUMFACT;
+ m_iparm(IPARM_END_TASK) = API_TASK_NUMFACT;
+ m_size = mat.rows();
+
+ internal::eigen_pastix(&m_pastixdata, MPI_COMM_WORLD, m_size, mat.outerIndexPtr(), mat.innerIndexPtr(),
+ mat.valuePtr(), m_perm.data(), m_invp.data(), 0, 0, m_iparm.data(), m_dparm.data());
+
+ // Check the returned error
+ if(m_iparm(IPARM_ERROR_NUMBER))
+ {
+ m_info = NumericalIssue;
+ m_factorizationIsOk = false;
+ m_isInitialized = false;
+ }
+ else
+ {
+ m_info = Success;
+ m_factorizationIsOk = true;
+ m_isInitialized = true;
+ }
+}
+
+/* Solve the system */
+template<typename Base>
+template<typename Rhs,typename Dest>
+bool PastixBase<Base>::_solve (const MatrixBase<Rhs> &b, MatrixBase<Dest> &x) const
+{
+ eigen_assert(m_isInitialized && "The matrix should be factorized first");
+ EIGEN_STATIC_ASSERT((Dest::Flags&RowMajorBit)==0,
+ THIS_METHOD_IS_ONLY_FOR_COLUMN_MAJOR_MATRICES);
+ int rhs = 1;
+
+ x = b; /* on return, x is overwritten by the computed solution */
+
+ for (int i = 0; i < b.cols(); i++){
+ m_iparm[IPARM_START_TASK] = API_TASK_SOLVE;
+ m_iparm[IPARM_END_TASK] = API_TASK_REFINE;
+
+ internal::eigen_pastix(&m_pastixdata, MPI_COMM_WORLD, x.rows(), 0, 0, 0,
+ m_perm.data(), m_invp.data(), &x(0, i), rhs, m_iparm.data(), m_dparm.data());
+ }
+
+ // Check the returned error
+ m_info = m_iparm(IPARM_ERROR_NUMBER)==0 ? Success : NumericalIssue;
+
+ return m_iparm(IPARM_ERROR_NUMBER)==0;
+}
+
+/** \ingroup PaStiXSupport_Module
+ * \class PastixLU
+ * \brief Sparse direct LU solver based on PaStiX library
+ *
+ * This class is used to solve the linear systems A.X = B with a supernodal LU
+ * factorization in the PaStiX library. The matrix A should be squared and nonsingular
+ * PaStiX requires that the matrix A has a symmetric structural pattern.
+ * This interface can symmetrize the input matrix otherwise.
+ * The vectors or matrices X and B can be either dense or sparse.
+ *
+ * \tparam _MatrixType the type of the sparse matrix A, it must be a SparseMatrix<>
+ * \tparam IsStrSym Indicates if the input matrix has a symmetric pattern, default is false
+ * NOTE : Note that if the analysis and factorization phase are called separately,
+ * the input matrix will be symmetrized at each call, hence it is advised to
+ * symmetrize the matrix in a end-user program and set \p IsStrSym to true
+ *
+ * \sa \ref TutorialSparseDirectSolvers
+ *
+ */
+template<typename _MatrixType, bool IsStrSym>
+class PastixLU : public PastixBase< PastixLU<_MatrixType> >
+{
+ public:
+ typedef _MatrixType MatrixType;
+ typedef PastixBase<PastixLU<MatrixType> > Base;
+ typedef typename Base::ColSpMatrix ColSpMatrix;
+ typedef typename MatrixType::Index Index;
+
+ public:
+ PastixLU() : Base()
+ {
+ init();
+ }
+
+ PastixLU(const MatrixType& matrix):Base()
+ {
+ init();
+ compute(matrix);
+ }
+ /** Compute the LU supernodal factorization of \p matrix.
+ * iparm and dparm can be used to tune the PaStiX parameters.
+ * see the PaStiX user's manual
+ * \sa analyzePattern() factorize()
+ */
+ void compute (const MatrixType& matrix)
+ {
+ m_structureIsUptodate = false;
+ ColSpMatrix temp;
+ grabMatrix(matrix, temp);
+ Base::compute(temp);
+ }
+ /** Compute the LU symbolic factorization of \p matrix using its sparsity pattern.
+ * Several ordering methods can be used at this step. See the PaStiX user's manual.
+ * The result of this operation can be used with successive matrices having the same pattern as \p matrix
+ * \sa factorize()
+ */
+ void analyzePattern(const MatrixType& matrix)
+ {
+ m_structureIsUptodate = false;
+ ColSpMatrix temp;
+ grabMatrix(matrix, temp);
+ Base::analyzePattern(temp);
+ }
+
+ /** Compute the LU supernodal factorization of \p matrix
+ * WARNING The matrix \p matrix should have the same structural pattern
+ * as the same used in the analysis phase.
+ * \sa analyzePattern()
+ */
+ void factorize(const MatrixType& matrix)
+ {
+ ColSpMatrix temp;
+ grabMatrix(matrix, temp);
+ Base::factorize(temp);
+ }
+ protected:
+
+ void init()
+ {
+ m_structureIsUptodate = false;
+ m_iparm(IPARM_SYM) = API_SYM_NO;
+ m_iparm(IPARM_FACTORIZATION) = API_FACT_LU;
+ }
+
+ void grabMatrix(const MatrixType& matrix, ColSpMatrix& out)
+ {
+ if(IsStrSym)
+ out = matrix;
+ else
+ {
+ if(!m_structureIsUptodate)
+ {
+ // update the transposed structure
+ m_transposedStructure = matrix.transpose();
+
+ // Set the elements of the matrix to zero
+ for (Index j=0; j<m_transposedStructure.outerSize(); ++j)
+ for(typename ColSpMatrix::InnerIterator it(m_transposedStructure, j); it; ++it)
+ it.valueRef() = 0.0;
+
+ m_structureIsUptodate = true;
+ }
+
+ out = m_transposedStructure + matrix;
+ }
+ internal::c_to_fortran_numbering(out);
+ }
+
+ using Base::m_iparm;
+ using Base::m_dparm;
+
+ ColSpMatrix m_transposedStructure;
+ bool m_structureIsUptodate;
+};
+
+/** \ingroup PaStiXSupport_Module
+ * \class PastixLLT
+ * \brief A sparse direct supernodal Cholesky (LLT) factorization and solver based on the PaStiX library
+ *
+ * This class is used to solve the linear systems A.X = B via a LL^T supernodal Cholesky factorization
+ * available in the PaStiX library. The matrix A should be symmetric and positive definite
+ * WARNING Selfadjoint complex matrices are not supported in the current version of PaStiX
+ * The vectors or matrices X and B can be either dense or sparse
+ *
+ * \tparam MatrixType the type of the sparse matrix A, it must be a SparseMatrix<>
+ * \tparam UpLo The part of the matrix to use : Lower or Upper. The default is Lower as required by PaStiX
+ *
+ * \sa \ref TutorialSparseDirectSolvers
+ */
+template<typename _MatrixType, int _UpLo>
+class PastixLLT : public PastixBase< PastixLLT<_MatrixType, _UpLo> >
+{
+ public:
+ typedef _MatrixType MatrixType;
+ typedef PastixBase<PastixLLT<MatrixType, _UpLo> > Base;
+ typedef typename Base::ColSpMatrix ColSpMatrix;
+
+ public:
+ enum { UpLo = _UpLo };
+ PastixLLT() : Base()
+ {
+ init();
+ }
+
+ PastixLLT(const MatrixType& matrix):Base()
+ {
+ init();
+ compute(matrix);
+ }
+
+ /** Compute the L factor of the LL^T supernodal factorization of \p matrix
+ * \sa analyzePattern() factorize()
+ */
+ void compute (const MatrixType& matrix)
+ {
+ ColSpMatrix temp;
+ grabMatrix(matrix, temp);
+ Base::compute(temp);
+ }
+
+ /** Compute the LL^T symbolic factorization of \p matrix using its sparsity pattern
+ * The result of this operation can be used with successive matrices having the same pattern as \p matrix
+ * \sa factorize()
+ */
+ void analyzePattern(const MatrixType& matrix)
+ {
+ ColSpMatrix temp;
+ grabMatrix(matrix, temp);
+ Base::analyzePattern(temp);
+ }
+ /** Compute the LL^T supernodal numerical factorization of \p matrix
+ * \sa analyzePattern()
+ */
+ void factorize(const MatrixType& matrix)
+ {
+ ColSpMatrix temp;
+ grabMatrix(matrix, temp);
+ Base::factorize(temp);
+ }
+ protected:
+ using Base::m_iparm;
+
+ void init()
+ {
+ m_iparm(IPARM_SYM) = API_SYM_YES;
+ m_iparm(IPARM_FACTORIZATION) = API_FACT_LLT;
+ }
+
+ void grabMatrix(const MatrixType& matrix, ColSpMatrix& out)
+ {
+ // Pastix supports only lower, column-major matrices
+ out.template selfadjointView<Lower>() = matrix.template selfadjointView<UpLo>();
+ internal::c_to_fortran_numbering(out);
+ }
+};
+
+/** \ingroup PaStiXSupport_Module
+ * \class PastixLDLT
+ * \brief A sparse direct supernodal Cholesky (LLT) factorization and solver based on the PaStiX library
+ *
+ * This class is used to solve the linear systems A.X = B via a LDL^T supernodal Cholesky factorization
+ * available in the PaStiX library. The matrix A should be symmetric and positive definite
+ * WARNING Selfadjoint complex matrices are not supported in the current version of PaStiX
+ * The vectors or matrices X and B can be either dense or sparse
+ *
+ * \tparam MatrixType the type of the sparse matrix A, it must be a SparseMatrix<>
+ * \tparam UpLo The part of the matrix to use : Lower or Upper. The default is Lower as required by PaStiX
+ *
+ * \sa \ref TutorialSparseDirectSolvers
+ */
+template<typename _MatrixType, int _UpLo>
+class PastixLDLT : public PastixBase< PastixLDLT<_MatrixType, _UpLo> >
+{
+ public:
+ typedef _MatrixType MatrixType;
+ typedef PastixBase<PastixLDLT<MatrixType, _UpLo> > Base;
+ typedef typename Base::ColSpMatrix ColSpMatrix;
+
+ public:
+ enum { UpLo = _UpLo };
+ PastixLDLT():Base()
+ {
+ init();
+ }
+
+ PastixLDLT(const MatrixType& matrix):Base()
+ {
+ init();
+ compute(matrix);
+ }
+
+ /** Compute the L and D factors of the LDL^T factorization of \p matrix
+ * \sa analyzePattern() factorize()
+ */
+ void compute (const MatrixType& matrix)
+ {
+ ColSpMatrix temp;
+ grabMatrix(matrix, temp);
+ Base::compute(temp);
+ }
+
+ /** Compute the LDL^T symbolic factorization of \p matrix using its sparsity pattern
+ * The result of this operation can be used with successive matrices having the same pattern as \p matrix
+ * \sa factorize()
+ */
+ void analyzePattern(const MatrixType& matrix)
+ {
+ ColSpMatrix temp;
+ grabMatrix(matrix, temp);
+ Base::analyzePattern(temp);
+ }
+ /** Compute the LDL^T supernodal numerical factorization of \p matrix
+ *
+ */
+ void factorize(const MatrixType& matrix)
+ {
+ ColSpMatrix temp;
+ grabMatrix(matrix, temp);
+ Base::factorize(temp);
+ }
+
+ protected:
+ using Base::m_iparm;
+
+ void init()
+ {
+ m_iparm(IPARM_SYM) = API_SYM_YES;
+ m_iparm(IPARM_FACTORIZATION) = API_FACT_LDLT;
+ }
+
+ void grabMatrix(const MatrixType& matrix, ColSpMatrix& out)
+ {
+ // Pastix supports only lower, column-major matrices
+ out.template selfadjointView<Lower>() = matrix.template selfadjointView<UpLo>();
+ internal::c_to_fortran_numbering(out);
+ }
+};
+
+namespace internal {
+
+template<typename _MatrixType, typename Rhs>
+struct solve_retval<PastixBase<_MatrixType>, Rhs>
+ : solve_retval_base<PastixBase<_MatrixType>, Rhs>
+{
+ typedef PastixBase<_MatrixType> Dec;
+ EIGEN_MAKE_SOLVE_HELPERS(Dec,Rhs)
+
+ template<typename Dest> void evalTo(Dest& dst) const
+ {
+ dec()._solve(rhs(),dst);
+ }
+};
+
+template<typename _MatrixType, typename Rhs>
+struct sparse_solve_retval<PastixBase<_MatrixType>, Rhs>
+ : sparse_solve_retval_base<PastixBase<_MatrixType>, Rhs>
+{
+ typedef PastixBase<_MatrixType> Dec;
+ EIGEN_MAKE_SPARSE_SOLVE_HELPERS(Dec,Rhs)
+
+ template<typename Dest> void evalTo(Dest& dst) const
+ {
+ dec()._solve_sparse(rhs(),dst);
+ }
+};
+
+} // end namespace internal
+
+} // end namespace Eigen
+
+#endif
diff --git a/Eigen/src/PardisoSupport/CMakeLists.txt b/Eigen/src/PardisoSupport/CMakeLists.txt
new file mode 100644
index 000000000..a097ab401
--- /dev/null
+++ b/Eigen/src/PardisoSupport/CMakeLists.txt
@@ -0,0 +1,6 @@
+FILE(GLOB Eigen_PardisoSupport_SRCS "*.h")
+
+INSTALL(FILES
+ ${Eigen_PardisoSupport_SRCS}
+ DESTINATION ${INCLUDE_INSTALL_DIR}/Eigen/src/PardisoSupport COMPONENT Devel
+ )
diff --git a/Eigen/src/PardisoSupport/PardisoSupport.h b/Eigen/src/PardisoSupport/PardisoSupport.h
new file mode 100644
index 000000000..e6defc8c3
--- /dev/null
+++ b/Eigen/src/PardisoSupport/PardisoSupport.h
@@ -0,0 +1,614 @@
+/*
+ Copyright (c) 2011, Intel Corporation. All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without modification,
+ are permitted provided that the following conditions are met:
+
+ * Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+ * Neither the name of Intel Corporation nor the names of its contributors may
+ be used to endorse or promote products derived from this software without
+ specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+ ********************************************************************************
+ * Content : Eigen bindings to Intel(R) MKL PARDISO
+ ********************************************************************************
+*/
+
+#ifndef EIGEN_PARDISOSUPPORT_H
+#define EIGEN_PARDISOSUPPORT_H
+
+namespace Eigen {
+
+template<typename _MatrixType> class PardisoLU;
+template<typename _MatrixType, int Options=Upper> class PardisoLLT;
+template<typename _MatrixType, int Options=Upper> class PardisoLDLT;
+
+namespace internal
+{
+ template<typename Index>
+ struct pardiso_run_selector
+ {
+ static Index run( _MKL_DSS_HANDLE_t pt, Index maxfct, Index mnum, Index type, Index phase, Index n, void *a,
+ Index *ia, Index *ja, Index *perm, Index nrhs, Index *iparm, Index msglvl, void *b, void *x)
+ {
+ Index error = 0;
+ ::pardiso(pt, &maxfct, &mnum, &type, &phase, &n, a, ia, ja, perm, &nrhs, iparm, &msglvl, b, x, &error);
+ return error;
+ }
+ };
+ template<>
+ struct pardiso_run_selector<long long int>
+ {
+ typedef long long int Index;
+ static Index run( _MKL_DSS_HANDLE_t pt, Index maxfct, Index mnum, Index type, Index phase, Index n, void *a,
+ Index *ia, Index *ja, Index *perm, Index nrhs, Index *iparm, Index msglvl, void *b, void *x)
+ {
+ Index error = 0;
+ ::pardiso_64(pt, &maxfct, &mnum, &type, &phase, &n, a, ia, ja, perm, &nrhs, iparm, &msglvl, b, x, &error);
+ return error;
+ }
+ };
+
+ template<class Pardiso> struct pardiso_traits;
+
+ template<typename _MatrixType>
+ struct pardiso_traits< PardisoLU<_MatrixType> >
+ {
+ typedef _MatrixType MatrixType;
+ typedef typename _MatrixType::Scalar Scalar;
+ typedef typename _MatrixType::RealScalar RealScalar;
+ typedef typename _MatrixType::Index Index;
+ };
+
+ template<typename _MatrixType, int Options>
+ struct pardiso_traits< PardisoLLT<_MatrixType, Options> >
+ {
+ typedef _MatrixType MatrixType;
+ typedef typename _MatrixType::Scalar Scalar;
+ typedef typename _MatrixType::RealScalar RealScalar;
+ typedef typename _MatrixType::Index Index;
+ };
+
+ template<typename _MatrixType, int Options>
+ struct pardiso_traits< PardisoLDLT<_MatrixType, Options> >
+ {
+ typedef _MatrixType MatrixType;
+ typedef typename _MatrixType::Scalar Scalar;
+ typedef typename _MatrixType::RealScalar RealScalar;
+ typedef typename _MatrixType::Index Index;
+ };
+
+}
+
+template<class Derived>
+class PardisoImpl
+{
+ typedef internal::pardiso_traits<Derived> Traits;
+ public:
+ typedef typename Traits::MatrixType MatrixType;
+ typedef typename Traits::Scalar Scalar;
+ typedef typename Traits::RealScalar RealScalar;
+ typedef typename Traits::Index Index;
+ typedef SparseMatrix<Scalar,RowMajor,Index> SparseMatrixType;
+ typedef Matrix<Scalar,Dynamic,1> VectorType;
+ typedef Matrix<Index, 1, MatrixType::ColsAtCompileTime> IntRowVectorType;
+ typedef Matrix<Index, MatrixType::RowsAtCompileTime, 1> IntColVectorType;
+ enum {
+ ScalarIsComplex = NumTraits<Scalar>::IsComplex
+ };
+
+ PardisoImpl()
+ {
+ eigen_assert((sizeof(Index) >= sizeof(_INTEGER_t) && sizeof(Index) <= 8) && "Non-supported index type");
+ m_iparm.setZero();
+ m_msglvl = 0; // No output
+ m_initialized = false;
+ }
+
+ ~PardisoImpl()
+ {
+ pardisoRelease();
+ }
+
+ inline Index cols() const { return m_size; }
+ inline Index rows() const { return m_size; }
+
+ /** \brief Reports whether previous computation was successful.
+ *
+ * \returns \c Success if computation was succesful,
+ * \c NumericalIssue if the matrix appears to be negative.
+ */
+ ComputationInfo info() const
+ {
+ eigen_assert(m_initialized && "Decomposition is not initialized.");
+ return m_info;
+ }
+
+ /** \warning for advanced usage only.
+ * \returns a reference to the parameter array controlling PARDISO.
+ * See the PARDISO manual to know how to use it. */
+ Array<Index,64,1>& pardisoParameterArray()
+ {
+ return m_iparm;
+ }
+
+ /** Performs a symbolic decomposition on the sparcity of \a matrix.
+ *
+ * This function is particularly useful when solving for several problems having the same structure.
+ *
+ * \sa factorize()
+ */
+ Derived& analyzePattern(const MatrixType& matrix);
+
+ /** Performs a numeric decomposition of \a matrix
+ *
+ * The given matrix must has the same sparcity than the matrix on which the symbolic decomposition has been performed.
+ *
+ * \sa analyzePattern()
+ */
+ Derived& factorize(const MatrixType& matrix);
+
+ Derived& compute(const MatrixType& matrix);
+
+ /** \returns the solution x of \f$ A x = b \f$ using the current decomposition of A.
+ *
+ * \sa compute()
+ */
+ template<typename Rhs>
+ inline const internal::solve_retval<PardisoImpl, Rhs>
+ solve(const MatrixBase<Rhs>& b) const
+ {
+ eigen_assert(m_initialized && "Pardiso solver is not initialized.");
+ eigen_assert(rows()==b.rows()
+ && "PardisoImpl::solve(): invalid number of rows of the right hand side matrix b");
+ return internal::solve_retval<PardisoImpl, Rhs>(*this, b.derived());
+ }
+
+ /** \returns the solution x of \f$ A x = b \f$ using the current decomposition of A.
+ *
+ * \sa compute()
+ */
+ template<typename Rhs>
+ inline const internal::sparse_solve_retval<PardisoImpl, Rhs>
+ solve(const SparseMatrixBase<Rhs>& b) const
+ {
+ eigen_assert(m_initialized && "Pardiso solver is not initialized.");
+ eigen_assert(rows()==b.rows()
+ && "PardisoImpl::solve(): invalid number of rows of the right hand side matrix b");
+ return internal::sparse_solve_retval<PardisoImpl, Rhs>(*this, b.derived());
+ }
+
+ Derived& derived()
+ {
+ return *static_cast<Derived*>(this);
+ }
+ const Derived& derived() const
+ {
+ return *static_cast<const Derived*>(this);
+ }
+
+ template<typename BDerived, typename XDerived>
+ bool _solve(const MatrixBase<BDerived> &b, MatrixBase<XDerived>& x) const;
+
+ /** \internal */
+ template<typename Rhs, typename DestScalar, int DestOptions, typename DestIndex>
+ void _solve_sparse(const Rhs& b, SparseMatrix<DestScalar,DestOptions,DestIndex> &dest) const
+ {
+ eigen_assert(m_size==b.rows());
+
+ // we process the sparse rhs per block of NbColsAtOnce columns temporarily stored into a dense matrix.
+ static const int NbColsAtOnce = 4;
+ int rhsCols = b.cols();
+ int size = b.rows();
+ // Pardiso cannot solve in-place,
+ // so we need two temporaries
+ Eigen::Matrix<DestScalar,Dynamic,Dynamic,ColMajor> tmp_rhs(size,rhsCols);
+ Eigen::Matrix<DestScalar,Dynamic,Dynamic,ColMajor> tmp_res(size,rhsCols);
+ for(int k=0; k<rhsCols; k+=NbColsAtOnce)
+ {
+ int actualCols = std::min<int>(rhsCols-k, NbColsAtOnce);
+ tmp_rhs.leftCols(actualCols) = b.middleCols(k,actualCols);
+ tmp_res.leftCols(actualCols) = derived().solve(tmp_rhs.leftCols(actualCols));
+ dest.middleCols(k,actualCols) = tmp_res.leftCols(actualCols).sparseView();
+ }
+ }
+
+ protected:
+ void pardisoRelease()
+ {
+ if(m_initialized) // Factorization ran at least once
+ {
+ internal::pardiso_run_selector<Index>::run(m_pt, 1, 1, m_type, -1, m_size, 0, 0, 0, m_perm.data(), 0,
+ m_iparm.data(), m_msglvl, 0, 0);
+ }
+ }
+
+ void pardisoInit(int type)
+ {
+ m_type = type;
+ bool symmetric = abs(m_type) < 10;
+ m_iparm[0] = 1; // No solver default
+ m_iparm[1] = 3; // use Metis for the ordering
+ m_iparm[2] = 1; // Numbers of processors, value of OMP_NUM_THREADS
+ m_iparm[3] = 0; // No iterative-direct algorithm
+ m_iparm[4] = 0; // No user fill-in reducing permutation
+ m_iparm[5] = 0; // Write solution into x
+ m_iparm[6] = 0; // Not in use
+ m_iparm[7] = 2; // Max numbers of iterative refinement steps
+ m_iparm[8] = 0; // Not in use
+ m_iparm[9] = 13; // Perturb the pivot elements with 1E-13
+ m_iparm[10] = symmetric ? 0 : 1; // Use nonsymmetric permutation and scaling MPS
+ m_iparm[11] = 0; // Not in use
+ m_iparm[12] = symmetric ? 0 : 1; // Maximum weighted matching algorithm is switched-off (default for symmetric).
+ // Try m_iparm[12] = 1 in case of inappropriate accuracy
+ m_iparm[13] = 0; // Output: Number of perturbed pivots
+ m_iparm[14] = 0; // Not in use
+ m_iparm[15] = 0; // Not in use
+ m_iparm[16] = 0; // Not in use
+ m_iparm[17] = -1; // Output: Number of nonzeros in the factor LU
+ m_iparm[18] = -1; // Output: Mflops for LU factorization
+ m_iparm[19] = 0; // Output: Numbers of CG Iterations
+
+ m_iparm[20] = 0; // 1x1 pivoting
+ m_iparm[26] = 0; // No matrix checker
+ m_iparm[27] = (sizeof(RealScalar) == 4) ? 1 : 0;
+ m_iparm[34] = 1; // C indexing
+ m_iparm[59] = 1; // Automatic switch between In-Core and Out-of-Core modes
+ }
+
+ protected:
+ // cached data to reduce reallocation, etc.
+
+ void manageErrorCode(Index error)
+ {
+ switch(error)
+ {
+ case 0:
+ m_info = Success;
+ break;
+ case -4:
+ case -7:
+ m_info = NumericalIssue;
+ break;
+ default:
+ m_info = InvalidInput;
+ }
+ }
+
+ mutable SparseMatrixType m_matrix;
+ ComputationInfo m_info;
+ bool m_initialized, m_analysisIsOk, m_factorizationIsOk;
+ Index m_type, m_msglvl;
+ mutable void *m_pt[64];
+ mutable Array<Index,64,1> m_iparm;
+ mutable IntColVectorType m_perm;
+ Index m_size;
+
+ private:
+ PardisoImpl(PardisoImpl &) {}
+};
+
+template<class Derived>
+Derived& PardisoImpl<Derived>::compute(const MatrixType& a)
+{
+ m_size = a.rows();
+ eigen_assert(a.rows() == a.cols());
+
+ pardisoRelease();
+ memset(m_pt, 0, sizeof(m_pt));
+ m_perm.setZero(m_size);
+ derived().getMatrix(a);
+
+ Index error;
+ error = internal::pardiso_run_selector<Index>::run(m_pt, 1, 1, m_type, 12, m_size,
+ m_matrix.valuePtr(), m_matrix.outerIndexPtr(), m_matrix.innerIndexPtr(),
+ m_perm.data(), 0, m_iparm.data(), m_msglvl, NULL, NULL);
+
+ manageErrorCode(error);
+ m_analysisIsOk = true;
+ m_factorizationIsOk = true;
+ m_initialized = true;
+ return derived();
+}
+
+template<class Derived>
+Derived& PardisoImpl<Derived>::analyzePattern(const MatrixType& a)
+{
+ m_size = a.rows();
+ eigen_assert(m_size == a.cols());
+
+ pardisoRelease();
+ memset(m_pt, 0, sizeof(m_pt));
+ m_perm.setZero(m_size);
+ derived().getMatrix(a);
+
+ Index error;
+ error = internal::pardiso_run_selector<Index>::run(m_pt, 1, 1, m_type, 11, m_size,
+ m_matrix.valuePtr(), m_matrix.outerIndexPtr(), m_matrix.innerIndexPtr(),
+ m_perm.data(), 0, m_iparm.data(), m_msglvl, NULL, NULL);
+
+ manageErrorCode(error);
+ m_analysisIsOk = true;
+ m_factorizationIsOk = false;
+ m_initialized = true;
+ return derived();
+}
+
+template<class Derived>
+Derived& PardisoImpl<Derived>::factorize(const MatrixType& a)
+{
+ eigen_assert(m_analysisIsOk && "You must first call analyzePattern()");
+ eigen_assert(m_size == a.rows() && m_size == a.cols());
+
+ derived().getMatrix(a);
+
+ Index error;
+ error = internal::pardiso_run_selector<Index>::run(m_pt, 1, 1, m_type, 22, m_size,
+ m_matrix.valuePtr(), m_matrix.outerIndexPtr(), m_matrix.innerIndexPtr(),
+ m_perm.data(), 0, m_iparm.data(), m_msglvl, NULL, NULL);
+
+ manageErrorCode(error);
+ m_factorizationIsOk = true;
+ return derived();
+}
+
+template<class Base>
+template<typename BDerived,typename XDerived>
+bool PardisoImpl<Base>::_solve(const MatrixBase<BDerived> &b, MatrixBase<XDerived>& x) const
+{
+ if(m_iparm[0] == 0) // Factorization was not computed
+ return false;
+
+ //Index n = m_matrix.rows();
+ Index nrhs = Index(b.cols());
+ eigen_assert(m_size==b.rows());
+ eigen_assert(((MatrixBase<BDerived>::Flags & RowMajorBit) == 0 || nrhs == 1) && "Row-major right hand sides are not supported");
+ eigen_assert(((MatrixBase<XDerived>::Flags & RowMajorBit) == 0 || nrhs == 1) && "Row-major matrices of unknowns are not supported");
+ eigen_assert(((nrhs == 1) || b.outerStride() == b.rows()));
+
+
+// switch (transposed) {
+// case SvNoTrans : m_iparm[11] = 0 ; break;
+// case SvTranspose : m_iparm[11] = 2 ; break;
+// case SvAdjoint : m_iparm[11] = 1 ; break;
+// default:
+// //std::cerr << "Eigen: transposition option \"" << transposed << "\" not supported by the PARDISO backend\n";
+// m_iparm[11] = 0;
+// }
+
+ Scalar* rhs_ptr = const_cast<Scalar*>(b.derived().data());
+ Matrix<Scalar,Dynamic,Dynamic,ColMajor> tmp;
+
+ // Pardiso cannot solve in-place
+ if(rhs_ptr == x.derived().data())
+ {
+ tmp = b;
+ rhs_ptr = tmp.data();
+ }
+
+ Index error;
+ error = internal::pardiso_run_selector<Index>::run(m_pt, 1, 1, m_type, 33, m_size,
+ m_matrix.valuePtr(), m_matrix.outerIndexPtr(), m_matrix.innerIndexPtr(),
+ m_perm.data(), nrhs, m_iparm.data(), m_msglvl,
+ rhs_ptr, x.derived().data());
+
+ return error==0;
+}
+
+
+/** \ingroup PardisoSupport_Module
+ * \class PardisoLU
+ * \brief A sparse direct LU factorization and solver based on the PARDISO library
+ *
+ * This class allows to solve for A.X = B sparse linear problems via a direct LU factorization
+ * using the Intel MKL PARDISO library. The sparse matrix A must be squared and invertible.
+ * The vectors or matrices X and B can be either dense or sparse.
+ *
+ * \tparam _MatrixType the type of the sparse matrix A, it must be a SparseMatrix<>
+ *
+ * \sa \ref TutorialSparseDirectSolvers
+ */
+template<typename MatrixType>
+class PardisoLU : public PardisoImpl< PardisoLU<MatrixType> >
+{
+ protected:
+ typedef PardisoImpl< PardisoLU<MatrixType> > Base;
+ typedef typename Base::Scalar Scalar;
+ typedef typename Base::RealScalar RealScalar;
+ using Base::pardisoInit;
+ using Base::m_matrix;
+ friend class PardisoImpl< PardisoLU<MatrixType> >;
+
+ public:
+
+ using Base::compute;
+ using Base::solve;
+
+ PardisoLU()
+ : Base()
+ {
+ pardisoInit(Base::ScalarIsComplex ? 13 : 11);
+ }
+
+ PardisoLU(const MatrixType& matrix)
+ : Base()
+ {
+ pardisoInit(Base::ScalarIsComplex ? 13 : 11);
+ compute(matrix);
+ }
+ protected:
+ void getMatrix(const MatrixType& matrix)
+ {
+ m_matrix = matrix;
+ }
+
+ private:
+ PardisoLU(PardisoLU& ) {}
+};
+
+/** \ingroup PardisoSupport_Module
+ * \class PardisoLLT
+ * \brief A sparse direct Cholesky (LLT) factorization and solver based on the PARDISO library
+ *
+ * This class allows to solve for A.X = B sparse linear problems via a LL^T Cholesky factorization
+ * using the Intel MKL PARDISO library. The sparse matrix A must be selfajoint and positive definite.
+ * The vectors or matrices X and B can be either dense or sparse.
+ *
+ * \tparam MatrixType the type of the sparse matrix A, it must be a SparseMatrix<>
+ * \tparam UpLo can be any bitwise combination of Upper, Lower. The default is Upper, meaning only the upper triangular part has to be used.
+ * Upper|Lower can be used to tell both triangular parts can be used as input.
+ *
+ * \sa \ref TutorialSparseDirectSolvers
+ */
+template<typename MatrixType, int _UpLo>
+class PardisoLLT : public PardisoImpl< PardisoLLT<MatrixType,_UpLo> >
+{
+ protected:
+ typedef PardisoImpl< PardisoLLT<MatrixType,_UpLo> > Base;
+ typedef typename Base::Scalar Scalar;
+ typedef typename Base::Index Index;
+ typedef typename Base::RealScalar RealScalar;
+ using Base::pardisoInit;
+ using Base::m_matrix;
+ friend class PardisoImpl< PardisoLLT<MatrixType,_UpLo> >;
+
+ public:
+
+ enum { UpLo = _UpLo };
+ using Base::compute;
+ using Base::solve;
+
+ PardisoLLT()
+ : Base()
+ {
+ pardisoInit(Base::ScalarIsComplex ? 4 : 2);
+ }
+
+ PardisoLLT(const MatrixType& matrix)
+ : Base()
+ {
+ pardisoInit(Base::ScalarIsComplex ? 4 : 2);
+ compute(matrix);
+ }
+
+ protected:
+
+ void getMatrix(const MatrixType& matrix)
+ {
+ // PARDISO supports only upper, row-major matrices
+ PermutationMatrix<Dynamic,Dynamic,Index> p_null;
+ m_matrix.resize(matrix.rows(), matrix.cols());
+ m_matrix.template selfadjointView<Upper>() = matrix.template selfadjointView<UpLo>().twistedBy(p_null);
+ }
+
+ private:
+ PardisoLLT(PardisoLLT& ) {}
+};
+
+/** \ingroup PardisoSupport_Module
+ * \class PardisoLDLT
+ * \brief A sparse direct Cholesky (LDLT) factorization and solver based on the PARDISO library
+ *
+ * This class allows to solve for A.X = B sparse linear problems via a LDL^T Cholesky factorization
+ * using the Intel MKL PARDISO library. The sparse matrix A is assumed to be selfajoint and positive definite.
+ * For complex matrices, A can also be symmetric only, see the \a Options template parameter.
+ * The vectors or matrices X and B can be either dense or sparse.
+ *
+ * \tparam MatrixType the type of the sparse matrix A, it must be a SparseMatrix<>
+ * \tparam Options can be any bitwise combination of Upper, Lower, and Symmetric. The default is Upper, meaning only the upper triangular part has to be used.
+ * Symmetric can be used for symmetric, non-selfadjoint complex matrices, the default being to assume a selfadjoint matrix.
+ * Upper|Lower can be used to tell both triangular parts can be used as input.
+ *
+ * \sa \ref TutorialSparseDirectSolvers
+ */
+template<typename MatrixType, int Options>
+class PardisoLDLT : public PardisoImpl< PardisoLDLT<MatrixType,Options> >
+{
+ protected:
+ typedef PardisoImpl< PardisoLDLT<MatrixType,Options> > Base;
+ typedef typename Base::Scalar Scalar;
+ typedef typename Base::Index Index;
+ typedef typename Base::RealScalar RealScalar;
+ using Base::pardisoInit;
+ using Base::m_matrix;
+ friend class PardisoImpl< PardisoLDLT<MatrixType,Options> >;
+
+ public:
+
+ using Base::compute;
+ using Base::solve;
+ enum { UpLo = Options&(Upper|Lower) };
+
+ PardisoLDLT()
+ : Base()
+ {
+ pardisoInit(Base::ScalarIsComplex ? ( bool(Options&Symmetric) ? 6 : -4 ) : -2);
+ }
+
+ PardisoLDLT(const MatrixType& matrix)
+ : Base()
+ {
+ pardisoInit(Base::ScalarIsComplex ? ( bool(Options&Symmetric) ? 6 : -4 ) : -2);
+ compute(matrix);
+ }
+
+ void getMatrix(const MatrixType& matrix)
+ {
+ // PARDISO supports only upper, row-major matrices
+ PermutationMatrix<Dynamic,Dynamic,Index> p_null;
+ m_matrix.resize(matrix.rows(), matrix.cols());
+ m_matrix.template selfadjointView<Upper>() = matrix.template selfadjointView<UpLo>().twistedBy(p_null);
+ }
+
+ private:
+ PardisoLDLT(PardisoLDLT& ) {}
+};
+
+namespace internal {
+
+template<typename _Derived, typename Rhs>
+struct solve_retval<PardisoImpl<_Derived>, Rhs>
+ : solve_retval_base<PardisoImpl<_Derived>, Rhs>
+{
+ typedef PardisoImpl<_Derived> Dec;
+ EIGEN_MAKE_SOLVE_HELPERS(Dec,Rhs)
+
+ template<typename Dest> void evalTo(Dest& dst) const
+ {
+ dec()._solve(rhs(),dst);
+ }
+};
+
+template<typename Derived, typename Rhs>
+struct sparse_solve_retval<PardisoImpl<Derived>, Rhs>
+ : sparse_solve_retval_base<PardisoImpl<Derived>, Rhs>
+{
+ typedef PardisoImpl<Derived> Dec;
+ EIGEN_MAKE_SPARSE_SOLVE_HELPERS(Dec,Rhs)
+
+ template<typename Dest> void evalTo(Dest& dst) const
+ {
+ dec().derived()._solve_sparse(rhs(),dst);
+ }
+};
+
+} // end namespace internal
+
+} // end namespace Eigen
+
+#endif // EIGEN_PARDISOSUPPORT_H
diff --git a/Eigen/src/QR/CMakeLists.txt b/Eigen/src/QR/CMakeLists.txt
new file mode 100644
index 000000000..96f43d7f5
--- /dev/null
+++ b/Eigen/src/QR/CMakeLists.txt
@@ -0,0 +1,6 @@
+FILE(GLOB Eigen_QR_SRCS "*.h")
+
+INSTALL(FILES
+ ${Eigen_QR_SRCS}
+ DESTINATION ${INCLUDE_INSTALL_DIR}/Eigen/src/QR COMPONENT Devel
+ )
diff --git a/Eigen/src/QR/ColPivHouseholderQR.h b/Eigen/src/QR/ColPivHouseholderQR.h
new file mode 100644
index 000000000..2daa23cc3
--- /dev/null
+++ b/Eigen/src/QR/ColPivHouseholderQR.h
@@ -0,0 +1,520 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra.
+//
+// Copyright (C) 2008-2009 Gael Guennebaud <gael.guennebaud@inria.fr>
+// Copyright (C) 2009 Benoit Jacob <jacob.benoit.1@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 EIGEN_COLPIVOTINGHOUSEHOLDERQR_H
+#define EIGEN_COLPIVOTINGHOUSEHOLDERQR_H
+
+namespace Eigen {
+
+/** \ingroup QR_Module
+ *
+ * \class ColPivHouseholderQR
+ *
+ * \brief Householder rank-revealing QR decomposition of a matrix with column-pivoting
+ *
+ * \param MatrixType the type of the matrix of which we are computing the QR decomposition
+ *
+ * This class performs a rank-revealing QR decomposition of a matrix \b A into matrices \b P, \b Q and \b R
+ * such that
+ * \f[
+ * \mathbf{A} \, \mathbf{P} = \mathbf{Q} \, \mathbf{R}
+ * \f]
+ * by using Householder transformations. Here, \b P is a permutation matrix, \b Q a unitary matrix and \b R an
+ * upper triangular matrix.
+ *
+ * This decomposition performs column pivoting in order to be rank-revealing and improve
+ * numerical stability. It is slower than HouseholderQR, and faster than FullPivHouseholderQR.
+ *
+ * \sa MatrixBase::colPivHouseholderQr()
+ */
+template<typename _MatrixType> class ColPivHouseholderQR
+{
+ public:
+
+ typedef _MatrixType MatrixType;
+ enum {
+ RowsAtCompileTime = MatrixType::RowsAtCompileTime,
+ ColsAtCompileTime = MatrixType::ColsAtCompileTime,
+ Options = MatrixType::Options,
+ MaxRowsAtCompileTime = MatrixType::MaxRowsAtCompileTime,
+ MaxColsAtCompileTime = MatrixType::MaxColsAtCompileTime
+ };
+ typedef typename MatrixType::Scalar Scalar;
+ typedef typename MatrixType::RealScalar RealScalar;
+ typedef typename MatrixType::Index Index;
+ typedef Matrix<Scalar, RowsAtCompileTime, RowsAtCompileTime, Options, MaxRowsAtCompileTime, MaxRowsAtCompileTime> MatrixQType;
+ typedef typename internal::plain_diag_type<MatrixType>::type HCoeffsType;
+ typedef PermutationMatrix<ColsAtCompileTime, MaxColsAtCompileTime> PermutationType;
+ typedef typename internal::plain_row_type<MatrixType, Index>::type IntRowVectorType;
+ typedef typename internal::plain_row_type<MatrixType>::type RowVectorType;
+ typedef typename internal::plain_row_type<MatrixType, RealScalar>::type RealRowVectorType;
+ typedef typename HouseholderSequence<MatrixType,HCoeffsType>::ConjugateReturnType HouseholderSequenceType;
+
+ /**
+ * \brief Default Constructor.
+ *
+ * The default constructor is useful in cases in which the user intends to
+ * perform decompositions via ColPivHouseholderQR::compute(const MatrixType&).
+ */
+ ColPivHouseholderQR()
+ : m_qr(),
+ m_hCoeffs(),
+ m_colsPermutation(),
+ m_colsTranspositions(),
+ m_temp(),
+ m_colSqNorms(),
+ m_isInitialized(false) {}
+
+ /** \brief Default Constructor with memory preallocation
+ *
+ * Like the default constructor but with preallocation of the internal data
+ * according to the specified problem \a size.
+ * \sa ColPivHouseholderQR()
+ */
+ ColPivHouseholderQR(Index rows, Index cols)
+ : m_qr(rows, cols),
+ m_hCoeffs((std::min)(rows,cols)),
+ m_colsPermutation(cols),
+ m_colsTranspositions(cols),
+ m_temp(cols),
+ m_colSqNorms(cols),
+ m_isInitialized(false),
+ m_usePrescribedThreshold(false) {}
+
+ ColPivHouseholderQR(const MatrixType& matrix)
+ : m_qr(matrix.rows(), matrix.cols()),
+ m_hCoeffs((std::min)(matrix.rows(),matrix.cols())),
+ m_colsPermutation(matrix.cols()),
+ m_colsTranspositions(matrix.cols()),
+ m_temp(matrix.cols()),
+ m_colSqNorms(matrix.cols()),
+ m_isInitialized(false),
+ m_usePrescribedThreshold(false)
+ {
+ compute(matrix);
+ }
+
+ /** This method finds a solution x to the equation Ax=b, where A is the matrix of which
+ * *this is the QR decomposition, if any exists.
+ *
+ * \param b the right-hand-side of the equation to solve.
+ *
+ * \returns a solution.
+ *
+ * \note The case where b is a matrix is not yet implemented. Also, this
+ * code is space inefficient.
+ *
+ * \note_about_checking_solutions
+ *
+ * \note_about_arbitrary_choice_of_solution
+ *
+ * Example: \include ColPivHouseholderQR_solve.cpp
+ * Output: \verbinclude ColPivHouseholderQR_solve.out
+ */
+ template<typename Rhs>
+ inline const internal::solve_retval<ColPivHouseholderQR, Rhs>
+ solve(const MatrixBase<Rhs>& b) const
+ {
+ eigen_assert(m_isInitialized && "ColPivHouseholderQR is not initialized.");
+ return internal::solve_retval<ColPivHouseholderQR, Rhs>(*this, b.derived());
+ }
+
+ HouseholderSequenceType householderQ(void) const;
+
+ /** \returns a reference to the matrix where the Householder QR decomposition is stored
+ */
+ const MatrixType& matrixQR() const
+ {
+ eigen_assert(m_isInitialized && "ColPivHouseholderQR is not initialized.");
+ return m_qr;
+ }
+
+ ColPivHouseholderQR& compute(const MatrixType& matrix);
+
+ const PermutationType& colsPermutation() const
+ {
+ eigen_assert(m_isInitialized && "ColPivHouseholderQR is not initialized.");
+ return m_colsPermutation;
+ }
+
+ /** \returns the absolute value of the determinant of the matrix of which
+ * *this is the QR decomposition. It has only linear complexity
+ * (that is, O(n) where n is the dimension of the square matrix)
+ * as the QR decomposition has already been computed.
+ *
+ * \note This is only for square matrices.
+ *
+ * \warning a determinant can be very big or small, so for matrices
+ * of large enough dimension, there is a risk of overflow/underflow.
+ * One way to work around that is to use logAbsDeterminant() instead.
+ *
+ * \sa logAbsDeterminant(), MatrixBase::determinant()
+ */
+ typename MatrixType::RealScalar absDeterminant() const;
+
+ /** \returns the natural log of the absolute value of the determinant of the matrix of which
+ * *this is the QR decomposition. It has only linear complexity
+ * (that is, O(n) where n is the dimension of the square matrix)
+ * as the QR decomposition has already been computed.
+ *
+ * \note This is only for square matrices.
+ *
+ * \note This method is useful to work around the risk of overflow/underflow that's inherent
+ * to determinant computation.
+ *
+ * \sa absDeterminant(), MatrixBase::determinant()
+ */
+ typename MatrixType::RealScalar logAbsDeterminant() const;
+
+ /** \returns the rank of the matrix of which *this is the QR decomposition.
+ *
+ * \note This method has to determine which pivots should be considered nonzero.
+ * For that, it uses the threshold value that you can control by calling
+ * setThreshold(const RealScalar&).
+ */
+ inline Index rank() const
+ {
+ eigen_assert(m_isInitialized && "ColPivHouseholderQR is not initialized.");
+ RealScalar premultiplied_threshold = internal::abs(m_maxpivot) * threshold();
+ Index result = 0;
+ for(Index i = 0; i < m_nonzero_pivots; ++i)
+ result += (internal::abs(m_qr.coeff(i,i)) > premultiplied_threshold);
+ return result;
+ }
+
+ /** \returns the dimension of the kernel of the matrix of which *this is the QR decomposition.
+ *
+ * \note This method has to determine which pivots should be considered nonzero.
+ * For that, it uses the threshold value that you can control by calling
+ * setThreshold(const RealScalar&).
+ */
+ inline Index dimensionOfKernel() const
+ {
+ eigen_assert(m_isInitialized && "ColPivHouseholderQR is not initialized.");
+ return cols() - rank();
+ }
+
+ /** \returns true if the matrix of which *this is the QR decomposition represents an injective
+ * linear map, i.e. has trivial kernel; false otherwise.
+ *
+ * \note This method has to determine which pivots should be considered nonzero.
+ * For that, it uses the threshold value that you can control by calling
+ * setThreshold(const RealScalar&).
+ */
+ inline bool isInjective() const
+ {
+ eigen_assert(m_isInitialized && "ColPivHouseholderQR is not initialized.");
+ return rank() == cols();
+ }
+
+ /** \returns true if the matrix of which *this is the QR decomposition represents a surjective
+ * linear map; false otherwise.
+ *
+ * \note This method has to determine which pivots should be considered nonzero.
+ * For that, it uses the threshold value that you can control by calling
+ * setThreshold(const RealScalar&).
+ */
+ inline bool isSurjective() const
+ {
+ eigen_assert(m_isInitialized && "ColPivHouseholderQR is not initialized.");
+ return rank() == rows();
+ }
+
+ /** \returns true if the matrix of which *this is the QR decomposition is invertible.
+ *
+ * \note This method has to determine which pivots should be considered nonzero.
+ * For that, it uses the threshold value that you can control by calling
+ * setThreshold(const RealScalar&).
+ */
+ inline bool isInvertible() const
+ {
+ eigen_assert(m_isInitialized && "ColPivHouseholderQR is not initialized.");
+ return isInjective() && isSurjective();
+ }
+
+ /** \returns the inverse of the matrix of which *this is the QR decomposition.
+ *
+ * \note If this matrix is not invertible, the returned matrix has undefined coefficients.
+ * Use isInvertible() to first determine whether this matrix is invertible.
+ */
+ inline const
+ internal::solve_retval<ColPivHouseholderQR, typename MatrixType::IdentityReturnType>
+ inverse() const
+ {
+ eigen_assert(m_isInitialized && "ColPivHouseholderQR is not initialized.");
+ return internal::solve_retval<ColPivHouseholderQR,typename MatrixType::IdentityReturnType>
+ (*this, MatrixType::Identity(m_qr.rows(), m_qr.cols()));
+ }
+
+ inline Index rows() const { return m_qr.rows(); }
+ inline Index cols() const { return m_qr.cols(); }
+ const HCoeffsType& hCoeffs() const { return m_hCoeffs; }
+
+ /** Allows to prescribe a threshold to be used by certain methods, such as rank(),
+ * who need to determine when pivots are to be considered nonzero. This is not used for the
+ * QR decomposition itself.
+ *
+ * When it needs to get the threshold value, Eigen calls threshold(). By default, this
+ * uses a formula to automatically determine a reasonable threshold.
+ * Once you have called the present method setThreshold(const RealScalar&),
+ * your value is used instead.
+ *
+ * \param threshold The new value to use as the threshold.
+ *
+ * A pivot will be considered nonzero if its absolute value is strictly greater than
+ * \f$ \vert pivot \vert \leqslant threshold \times \vert maxpivot \vert \f$
+ * where maxpivot is the biggest pivot.
+ *
+ * If you want to come back to the default behavior, call setThreshold(Default_t)
+ */
+ ColPivHouseholderQR& 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 qr.setThreshold(Eigen::Default); \endcode
+ *
+ * See the documentation of setThreshold(const RealScalar&).
+ */
+ ColPivHouseholderQR& 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
+ // this formula comes from experimenting (see "LU precision tuning" thread on the list)
+ // and turns out to be identical to Higham's formula used already in LDLt.
+ : NumTraits<Scalar>::epsilon() * m_qr.diagonalSize();
+ }
+
+ /** \returns the number of nonzero pivots in the QR decomposition.
+ * Here nonzero is meant in the exact sense, not in a fuzzy sense.
+ * So that notion isn't really intrinsically interesting, but it is
+ * still useful when implementing algorithms.
+ *
+ * \sa rank()
+ */
+ inline Index nonzeroPivots() const
+ {
+ eigen_assert(m_isInitialized && "ColPivHouseholderQR is not initialized.");
+ return m_nonzero_pivots;
+ }
+
+ /** \returns the absolute value of the biggest pivot, i.e. the biggest
+ * diagonal coefficient of R.
+ */
+ RealScalar maxPivot() const { return m_maxpivot; }
+
+ protected:
+ MatrixType m_qr;
+ HCoeffsType m_hCoeffs;
+ PermutationType m_colsPermutation;
+ IntRowVectorType m_colsTranspositions;
+ RowVectorType m_temp;
+ RealRowVectorType m_colSqNorms;
+ bool m_isInitialized, m_usePrescribedThreshold;
+ RealScalar m_prescribedThreshold, m_maxpivot;
+ Index m_nonzero_pivots;
+ Index m_det_pq;
+};
+
+template<typename MatrixType>
+typename MatrixType::RealScalar ColPivHouseholderQR<MatrixType>::absDeterminant() const
+{
+ eigen_assert(m_isInitialized && "ColPivHouseholderQR is not initialized.");
+ eigen_assert(m_qr.rows() == m_qr.cols() && "You can't take the determinant of a non-square matrix!");
+ return internal::abs(m_qr.diagonal().prod());
+}
+
+template<typename MatrixType>
+typename MatrixType::RealScalar ColPivHouseholderQR<MatrixType>::logAbsDeterminant() const
+{
+ eigen_assert(m_isInitialized && "ColPivHouseholderQR is not initialized.");
+ eigen_assert(m_qr.rows() == m_qr.cols() && "You can't take the determinant of a non-square matrix!");
+ return m_qr.diagonal().cwiseAbs().array().log().sum();
+}
+
+template<typename MatrixType>
+ColPivHouseholderQR<MatrixType>& ColPivHouseholderQR<MatrixType>::compute(const MatrixType& matrix)
+{
+ Index rows = matrix.rows();
+ Index cols = matrix.cols();
+ Index size = matrix.diagonalSize();
+
+ m_qr = matrix;
+ m_hCoeffs.resize(size);
+
+ m_temp.resize(cols);
+
+ m_colsTranspositions.resize(matrix.cols());
+ Index number_of_transpositions = 0;
+
+ m_colSqNorms.resize(cols);
+ for(Index k = 0; k < cols; ++k)
+ m_colSqNorms.coeffRef(k) = m_qr.col(k).squaredNorm();
+
+ RealScalar threshold_helper = m_colSqNorms.maxCoeff() * internal::abs2(NumTraits<Scalar>::epsilon()) / RealScalar(rows);
+
+ m_nonzero_pivots = size; // the generic case is that in which all pivots are nonzero (invertible case)
+ m_maxpivot = RealScalar(0);
+
+ for(Index k = 0; k < size; ++k)
+ {
+ // first, we look up in our table m_colSqNorms which column has the biggest squared norm
+ Index biggest_col_index;
+ RealScalar biggest_col_sq_norm = m_colSqNorms.tail(cols-k).maxCoeff(&biggest_col_index);
+ biggest_col_index += k;
+
+ // since our table m_colSqNorms accumulates imprecision at every step, we must now recompute
+ // the actual squared norm of the selected column.
+ // Note that not doing so does result in solve() sometimes returning inf/nan values
+ // when running the unit test with 1000 repetitions.
+ biggest_col_sq_norm = m_qr.col(biggest_col_index).tail(rows-k).squaredNorm();
+
+ // we store that back into our table: it can't hurt to correct our table.
+ m_colSqNorms.coeffRef(biggest_col_index) = biggest_col_sq_norm;
+
+ // if the current biggest column is smaller than epsilon times the initial biggest column,
+ // terminate to avoid generating nan/inf values.
+ // Note that here, if we test instead for "biggest == 0", we get a failure every 1000 (or so)
+ // repetitions of the unit test, with the result of solve() filled with large values of the order
+ // of 1/(size*epsilon).
+ if(biggest_col_sq_norm < threshold_helper * RealScalar(rows-k))
+ {
+ m_nonzero_pivots = k;
+ m_hCoeffs.tail(size-k).setZero();
+ m_qr.bottomRightCorner(rows-k,cols-k)
+ .template triangularView<StrictlyLower>()
+ .setZero();
+ break;
+ }
+
+ // apply the transposition to the columns
+ m_colsTranspositions.coeffRef(k) = biggest_col_index;
+ if(k != biggest_col_index) {
+ m_qr.col(k).swap(m_qr.col(biggest_col_index));
+ std::swap(m_colSqNorms.coeffRef(k), m_colSqNorms.coeffRef(biggest_col_index));
+ ++number_of_transpositions;
+ }
+
+ // generate the householder vector, store it below the diagonal
+ RealScalar beta;
+ m_qr.col(k).tail(rows-k).makeHouseholderInPlace(m_hCoeffs.coeffRef(k), beta);
+
+ // apply the householder transformation to the diagonal coefficient
+ m_qr.coeffRef(k,k) = beta;
+
+ // remember the maximum absolute value of diagonal coefficients
+ if(internal::abs(beta) > m_maxpivot) m_maxpivot = internal::abs(beta);
+
+ // apply the householder transformation
+ m_qr.bottomRightCorner(rows-k, cols-k-1)
+ .applyHouseholderOnTheLeft(m_qr.col(k).tail(rows-k-1), m_hCoeffs.coeffRef(k), &m_temp.coeffRef(k+1));
+
+ // update our table of squared norms of the columns
+ m_colSqNorms.tail(cols-k-1) -= m_qr.row(k).tail(cols-k-1).cwiseAbs2();
+ }
+
+ m_colsPermutation.setIdentity(cols);
+ for(Index k = 0; k < m_nonzero_pivots; ++k)
+ m_colsPermutation.applyTranspositionOnTheRight(k, m_colsTranspositions.coeff(k));
+
+ m_det_pq = (number_of_transpositions%2) ? -1 : 1;
+ m_isInitialized = true;
+
+ return *this;
+}
+
+namespace internal {
+
+template<typename _MatrixType, typename Rhs>
+struct solve_retval<ColPivHouseholderQR<_MatrixType>, Rhs>
+ : solve_retval_base<ColPivHouseholderQR<_MatrixType>, Rhs>
+{
+ EIGEN_MAKE_SOLVE_HELPERS(ColPivHouseholderQR<_MatrixType>,Rhs)
+
+ template<typename Dest> void evalTo(Dest& dst) const
+ {
+ eigen_assert(rhs().rows() == dec().rows());
+
+ const int cols = dec().cols(),
+ nonzero_pivots = dec().nonzeroPivots();
+
+ if(nonzero_pivots == 0)
+ {
+ dst.setZero();
+ return;
+ }
+
+ typename Rhs::PlainObject c(rhs());
+
+ // Note that the matrix Q = H_0^* H_1^*... so its inverse is Q^* = (H_0 H_1 ...)^T
+ c.applyOnTheLeft(householderSequence(dec().matrixQR(), dec().hCoeffs())
+ .setLength(dec().nonzeroPivots())
+ .transpose()
+ );
+
+ dec().matrixQR()
+ .topLeftCorner(nonzero_pivots, nonzero_pivots)
+ .template triangularView<Upper>()
+ .solveInPlace(c.topRows(nonzero_pivots));
+
+
+ typename Rhs::PlainObject d(c);
+ d.topRows(nonzero_pivots)
+ = dec().matrixQR()
+ .topLeftCorner(nonzero_pivots, nonzero_pivots)
+ .template triangularView<Upper>()
+ * c.topRows(nonzero_pivots);
+
+ for(Index i = 0; i < nonzero_pivots; ++i) dst.row(dec().colsPermutation().indices().coeff(i)) = c.row(i);
+ for(Index i = nonzero_pivots; i < cols; ++i) dst.row(dec().colsPermutation().indices().coeff(i)).setZero();
+ }
+};
+
+} // end namespace internal
+
+/** \returns the matrix Q as a sequence of householder transformations */
+template<typename MatrixType>
+typename ColPivHouseholderQR<MatrixType>::HouseholderSequenceType ColPivHouseholderQR<MatrixType>
+ ::householderQ() const
+{
+ eigen_assert(m_isInitialized && "ColPivHouseholderQR is not initialized.");
+ return HouseholderSequenceType(m_qr, m_hCoeffs.conjugate()).setLength(m_nonzero_pivots);
+}
+
+/** \return the column-pivoting Householder QR decomposition of \c *this.
+ *
+ * \sa class ColPivHouseholderQR
+ */
+template<typename Derived>
+const ColPivHouseholderQR<typename MatrixBase<Derived>::PlainObject>
+MatrixBase<Derived>::colPivHouseholderQr() const
+{
+ return ColPivHouseholderQR<PlainObject>(eval());
+}
+
+} // end namespace Eigen
+
+#endif // EIGEN_COLPIVOTINGHOUSEHOLDERQR_H
diff --git a/Eigen/src/QR/ColPivHouseholderQR_MKL.h b/Eigen/src/QR/ColPivHouseholderQR_MKL.h
new file mode 100644
index 000000000..745ecf8be
--- /dev/null
+++ b/Eigen/src/QR/ColPivHouseholderQR_MKL.h
@@ -0,0 +1,98 @@
+/*
+ Copyright (c) 2011, Intel Corporation. All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without modification,
+ are permitted provided that the following conditions are met:
+
+ * Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+ * Neither the name of Intel Corporation nor the names of its contributors may
+ be used to endorse or promote products derived from this software without
+ specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+ ********************************************************************************
+ * Content : Eigen bindings to Intel(R) MKL
+ * Householder QR decomposition of a matrix with column pivoting based on
+ * LAPACKE_?geqp3 function.
+ ********************************************************************************
+*/
+
+#ifndef EIGEN_COLPIVOTINGHOUSEHOLDERQR_MKL_H
+#define EIGEN_COLPIVOTINGHOUSEHOLDERQR_MKL_H
+
+#include "Eigen/src/Core/util/MKL_support.h"
+
+namespace Eigen {
+
+/** \internal Specialization for the data types supported by MKL */
+
+#define EIGEN_MKL_QR_COLPIV(EIGTYPE, MKLTYPE, MKLPREFIX, EIGCOLROW, MKLCOLROW) \
+template<> inline\
+ColPivHouseholderQR<Matrix<EIGTYPE, Dynamic, Dynamic, EIGCOLROW, Dynamic, Dynamic> >& \
+ColPivHouseholderQR<Matrix<EIGTYPE, Dynamic, Dynamic, EIGCOLROW, Dynamic, Dynamic> >::compute( \
+ const Matrix<EIGTYPE, Dynamic, Dynamic, EIGCOLROW, Dynamic, Dynamic>& matrix) \
+\
+{ \
+ typedef Matrix<EIGTYPE, Dynamic, Dynamic, EIGCOLROW, Dynamic, Dynamic> MatrixType; \
+ typedef MatrixType::Scalar Scalar; \
+ typedef MatrixType::RealScalar RealScalar; \
+ Index rows = matrix.rows();\
+ Index cols = matrix.cols();\
+ Index size = matrix.diagonalSize();\
+\
+ m_qr = matrix;\
+ m_hCoeffs.resize(size);\
+\
+ m_colsTranspositions.resize(cols);\
+ /*Index number_of_transpositions = 0;*/ \
+\
+ m_nonzero_pivots = 0; \
+ m_maxpivot = RealScalar(0);\
+ m_colsPermutation.resize(cols); \
+ m_colsPermutation.indices().setZero(); \
+\
+ lapack_int lda = m_qr.outerStride(), i; \
+ lapack_int matrix_order = MKLCOLROW; \
+ LAPACKE_##MKLPREFIX##geqp3( matrix_order, rows, cols, (MKLTYPE*)m_qr.data(), lda, (lapack_int*)m_colsPermutation.indices().data(), (MKLTYPE*)m_hCoeffs.data()); \
+ m_isInitialized = true; \
+ m_maxpivot=m_qr.diagonal().cwiseAbs().maxCoeff(); \
+ m_hCoeffs.adjointInPlace(); \
+ RealScalar premultiplied_threshold = internal::abs(m_maxpivot) * threshold(); \
+ lapack_int *perm = m_colsPermutation.indices().data(); \
+ for(i=0;i<size;i++) { \
+ m_nonzero_pivots += (internal::abs(m_qr.coeff(i,i)) > premultiplied_threshold);\
+ } \
+ for(i=0;i<cols;i++) perm[i]--;\
+\
+ /*m_det_pq = (number_of_transpositions%2) ? -1 : 1; // TODO: It's not needed now; fix upon availability in Eigen */ \
+\
+ return *this; \
+}
+
+EIGEN_MKL_QR_COLPIV(double, double, d, ColMajor, LAPACK_COL_MAJOR)
+EIGEN_MKL_QR_COLPIV(float, float, s, ColMajor, LAPACK_COL_MAJOR)
+EIGEN_MKL_QR_COLPIV(dcomplex, MKL_Complex16, z, ColMajor, LAPACK_COL_MAJOR)
+EIGEN_MKL_QR_COLPIV(scomplex, MKL_Complex8, c, ColMajor, LAPACK_COL_MAJOR)
+
+EIGEN_MKL_QR_COLPIV(double, double, d, RowMajor, LAPACK_ROW_MAJOR)
+EIGEN_MKL_QR_COLPIV(float, float, s, RowMajor, LAPACK_ROW_MAJOR)
+EIGEN_MKL_QR_COLPIV(dcomplex, MKL_Complex16, z, RowMajor, LAPACK_ROW_MAJOR)
+EIGEN_MKL_QR_COLPIV(scomplex, MKL_Complex8, c, RowMajor, LAPACK_ROW_MAJOR)
+
+} // end namespace Eigen
+
+#endif // EIGEN_COLPIVOTINGHOUSEHOLDERQR_MKL_H
diff --git a/Eigen/src/QR/FullPivHouseholderQR.h b/Eigen/src/QR/FullPivHouseholderQR.h
new file mode 100644
index 000000000..37898e77c
--- /dev/null
+++ b/Eigen/src/QR/FullPivHouseholderQR.h
@@ -0,0 +1,594 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra.
+//
+// Copyright (C) 2008-2009 Gael Guennebaud <gael.guennebaud@inria.fr>
+// Copyright (C) 2009 Benoit Jacob <jacob.benoit.1@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 EIGEN_FULLPIVOTINGHOUSEHOLDERQR_H
+#define EIGEN_FULLPIVOTINGHOUSEHOLDERQR_H
+
+namespace Eigen {
+
+namespace internal {
+
+template<typename MatrixType> struct FullPivHouseholderQRMatrixQReturnType;
+
+template<typename MatrixType>
+struct traits<FullPivHouseholderQRMatrixQReturnType<MatrixType> >
+{
+ typedef typename MatrixType::PlainObject ReturnType;
+};
+
+}
+
+/** \ingroup QR_Module
+ *
+ * \class FullPivHouseholderQR
+ *
+ * \brief Householder rank-revealing QR decomposition of a matrix with full pivoting
+ *
+ * \param MatrixType the type of the matrix of which we are computing the QR decomposition
+ *
+ * This class performs a rank-revealing QR decomposition of a matrix \b A into matrices \b P, \b Q and \b R
+ * such that
+ * \f[
+ * \mathbf{A} \, \mathbf{P} = \mathbf{Q} \, \mathbf{R}
+ * \f]
+ * by using Householder transformations. Here, \b P is a permutation matrix, \b Q a unitary matrix and \b R an
+ * upper triangular matrix.
+ *
+ * This decomposition performs a very prudent full pivoting in order to be rank-revealing and achieve optimal
+ * numerical stability. The trade-off is that it is slower than HouseholderQR and ColPivHouseholderQR.
+ *
+ * \sa MatrixBase::fullPivHouseholderQr()
+ */
+template<typename _MatrixType> class FullPivHouseholderQR
+{
+ public:
+
+ typedef _MatrixType MatrixType;
+ enum {
+ RowsAtCompileTime = MatrixType::RowsAtCompileTime,
+ ColsAtCompileTime = MatrixType::ColsAtCompileTime,
+ Options = MatrixType::Options,
+ MaxRowsAtCompileTime = MatrixType::MaxRowsAtCompileTime,
+ MaxColsAtCompileTime = MatrixType::MaxColsAtCompileTime
+ };
+ typedef typename MatrixType::Scalar Scalar;
+ typedef typename MatrixType::RealScalar RealScalar;
+ typedef typename MatrixType::Index Index;
+ typedef internal::FullPivHouseholderQRMatrixQReturnType<MatrixType> MatrixQReturnType;
+ typedef typename internal::plain_diag_type<MatrixType>::type HCoeffsType;
+ typedef Matrix<Index, 1, ColsAtCompileTime, RowMajor, 1, MaxColsAtCompileTime> IntRowVectorType;
+ typedef PermutationMatrix<ColsAtCompileTime, MaxColsAtCompileTime> PermutationType;
+ typedef typename internal::plain_col_type<MatrixType, Index>::type IntColVectorType;
+ typedef typename internal::plain_row_type<MatrixType>::type RowVectorType;
+ typedef typename internal::plain_col_type<MatrixType>::type ColVectorType;
+
+ /** \brief Default Constructor.
+ *
+ * The default constructor is useful in cases in which the user intends to
+ * perform decompositions via FullPivHouseholderQR::compute(const MatrixType&).
+ */
+ FullPivHouseholderQR()
+ : m_qr(),
+ m_hCoeffs(),
+ m_rows_transpositions(),
+ m_cols_transpositions(),
+ m_cols_permutation(),
+ m_temp(),
+ m_isInitialized(false),
+ m_usePrescribedThreshold(false) {}
+
+ /** \brief Default Constructor with memory preallocation
+ *
+ * Like the default constructor but with preallocation of the internal data
+ * according to the specified problem \a size.
+ * \sa FullPivHouseholderQR()
+ */
+ FullPivHouseholderQR(Index rows, Index cols)
+ : m_qr(rows, cols),
+ m_hCoeffs((std::min)(rows,cols)),
+ m_rows_transpositions(rows),
+ m_cols_transpositions(cols),
+ m_cols_permutation(cols),
+ m_temp((std::min)(rows,cols)),
+ m_isInitialized(false),
+ m_usePrescribedThreshold(false) {}
+
+ FullPivHouseholderQR(const MatrixType& matrix)
+ : m_qr(matrix.rows(), matrix.cols()),
+ m_hCoeffs((std::min)(matrix.rows(), matrix.cols())),
+ m_rows_transpositions(matrix.rows()),
+ m_cols_transpositions(matrix.cols()),
+ m_cols_permutation(matrix.cols()),
+ m_temp((std::min)(matrix.rows(), matrix.cols())),
+ m_isInitialized(false),
+ m_usePrescribedThreshold(false)
+ {
+ compute(matrix);
+ }
+
+ /** This method finds a solution x to the equation Ax=b, where A is the matrix of which
+ * *this is the QR decomposition, if any exists.
+ *
+ * \param b the right-hand-side of the equation to solve.
+ *
+ * \returns a solution.
+ *
+ * \note The case where b is a matrix is not yet implemented. Also, this
+ * code is space inefficient.
+ *
+ * \note_about_checking_solutions
+ *
+ * \note_about_arbitrary_choice_of_solution
+ *
+ * Example: \include FullPivHouseholderQR_solve.cpp
+ * Output: \verbinclude FullPivHouseholderQR_solve.out
+ */
+ template<typename Rhs>
+ inline const internal::solve_retval<FullPivHouseholderQR, Rhs>
+ solve(const MatrixBase<Rhs>& b) const
+ {
+ eigen_assert(m_isInitialized && "FullPivHouseholderQR is not initialized.");
+ return internal::solve_retval<FullPivHouseholderQR, Rhs>(*this, b.derived());
+ }
+
+ /** \returns Expression object representing the matrix Q
+ */
+ MatrixQReturnType matrixQ(void) const;
+
+ /** \returns a reference to the matrix where the Householder QR decomposition is stored
+ */
+ const MatrixType& matrixQR() const
+ {
+ eigen_assert(m_isInitialized && "FullPivHouseholderQR is not initialized.");
+ return m_qr;
+ }
+
+ FullPivHouseholderQR& compute(const MatrixType& matrix);
+
+ const PermutationType& colsPermutation() const
+ {
+ eigen_assert(m_isInitialized && "FullPivHouseholderQR is not initialized.");
+ return m_cols_permutation;
+ }
+
+ const IntColVectorType& rowsTranspositions() const
+ {
+ eigen_assert(m_isInitialized && "FullPivHouseholderQR is not initialized.");
+ return m_rows_transpositions;
+ }
+
+ /** \returns the absolute value of the determinant of the matrix of which
+ * *this is the QR decomposition. It has only linear complexity
+ * (that is, O(n) where n is the dimension of the square matrix)
+ * as the QR decomposition has already been computed.
+ *
+ * \note This is only for square matrices.
+ *
+ * \warning a determinant can be very big or small, so for matrices
+ * of large enough dimension, there is a risk of overflow/underflow.
+ * One way to work around that is to use logAbsDeterminant() instead.
+ *
+ * \sa logAbsDeterminant(), MatrixBase::determinant()
+ */
+ typename MatrixType::RealScalar absDeterminant() const;
+
+ /** \returns the natural log of the absolute value of the determinant of the matrix of which
+ * *this is the QR decomposition. It has only linear complexity
+ * (that is, O(n) where n is the dimension of the square matrix)
+ * as the QR decomposition has already been computed.
+ *
+ * \note This is only for square matrices.
+ *
+ * \note This method is useful to work around the risk of overflow/underflow that's inherent
+ * to determinant computation.
+ *
+ * \sa absDeterminant(), MatrixBase::determinant()
+ */
+ typename MatrixType::RealScalar logAbsDeterminant() const;
+
+ /** \returns the rank of the matrix of which *this is the QR decomposition.
+ *
+ * \note This method has to determine which pivots should be considered nonzero.
+ * For that, it uses the threshold value that you can control by calling
+ * setThreshold(const RealScalar&).
+ */
+ inline Index rank() const
+ {
+ eigen_assert(m_isInitialized && "FullPivHouseholderQR is not initialized.");
+ RealScalar premultiplied_threshold = internal::abs(m_maxpivot) * threshold();
+ Index result = 0;
+ for(Index i = 0; i < m_nonzero_pivots; ++i)
+ result += (internal::abs(m_qr.coeff(i,i)) > premultiplied_threshold);
+ return result;
+ }
+
+ /** \returns the dimension of the kernel of the matrix of which *this is the QR decomposition.
+ *
+ * \note This method has to determine which pivots should be considered nonzero.
+ * For that, it uses the threshold value that you can control by calling
+ * setThreshold(const RealScalar&).
+ */
+ inline Index dimensionOfKernel() const
+ {
+ eigen_assert(m_isInitialized && "FullPivHouseholderQR is not initialized.");
+ return cols() - rank();
+ }
+
+ /** \returns true if the matrix of which *this is the QR decomposition represents an injective
+ * linear map, i.e. has trivial kernel; false otherwise.
+ *
+ * \note This method has to determine which pivots should be considered nonzero.
+ * For that, it uses the threshold value that you can control by calling
+ * setThreshold(const RealScalar&).
+ */
+ inline bool isInjective() const
+ {
+ eigen_assert(m_isInitialized && "FullPivHouseholderQR is not initialized.");
+ return rank() == cols();
+ }
+
+ /** \returns true if the matrix of which *this is the QR decomposition represents a surjective
+ * linear map; false otherwise.
+ *
+ * \note This method has to determine which pivots should be considered nonzero.
+ * For that, it uses the threshold value that you can control by calling
+ * setThreshold(const RealScalar&).
+ */
+ inline bool isSurjective() const
+ {
+ eigen_assert(m_isInitialized && "FullPivHouseholderQR is not initialized.");
+ return rank() == rows();
+ }
+
+ /** \returns true if the matrix of which *this is the QR decomposition is invertible.
+ *
+ * \note This method has to determine which pivots should be considered nonzero.
+ * For that, it uses the threshold value that you can control by calling
+ * setThreshold(const RealScalar&).
+ */
+ inline bool isInvertible() const
+ {
+ eigen_assert(m_isInitialized && "FullPivHouseholderQR is not initialized.");
+ return isInjective() && isSurjective();
+ }
+
+ /** \returns the inverse of the matrix of which *this is the QR decomposition.
+ *
+ * \note If this matrix is not invertible, the returned matrix has undefined coefficients.
+ * Use isInvertible() to first determine whether this matrix is invertible.
+ */ inline const
+ internal::solve_retval<FullPivHouseholderQR, typename MatrixType::IdentityReturnType>
+ inverse() const
+ {
+ eigen_assert(m_isInitialized && "FullPivHouseholderQR is not initialized.");
+ return internal::solve_retval<FullPivHouseholderQR,typename MatrixType::IdentityReturnType>
+ (*this, MatrixType::Identity(m_qr.rows(), m_qr.cols()));
+ }
+
+ inline Index rows() const { return m_qr.rows(); }
+ inline Index cols() const { return m_qr.cols(); }
+ const HCoeffsType& hCoeffs() const { return m_hCoeffs; }
+
+ /** Allows to prescribe a threshold to be used by certain methods, such as rank(),
+ * who need to determine when pivots are to be considered nonzero. This is not used for the
+ * QR decomposition itself.
+ *
+ * When it needs to get the threshold value, Eigen calls threshold(). By default, this
+ * uses a formula to automatically determine a reasonable threshold.
+ * Once you have called the present method setThreshold(const RealScalar&),
+ * your value is used instead.
+ *
+ * \param threshold The new value to use as the threshold.
+ *
+ * A pivot will be considered nonzero if its absolute value is strictly greater than
+ * \f$ \vert pivot \vert \leqslant threshold \times \vert maxpivot \vert \f$
+ * where maxpivot is the biggest pivot.
+ *
+ * If you want to come back to the default behavior, call setThreshold(Default_t)
+ */
+ FullPivHouseholderQR& 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 qr.setThreshold(Eigen::Default); \endcode
+ *
+ * See the documentation of setThreshold(const RealScalar&).
+ */
+ FullPivHouseholderQR& 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
+ // this formula comes from experimenting (see "LU precision tuning" thread on the list)
+ // and turns out to be identical to Higham's formula used already in LDLt.
+ : NumTraits<Scalar>::epsilon() * m_qr.diagonalSize();
+ }
+
+ /** \returns the number of nonzero pivots in the QR decomposition.
+ * Here nonzero is meant in the exact sense, not in a fuzzy sense.
+ * So that notion isn't really intrinsically interesting, but it is
+ * still useful when implementing algorithms.
+ *
+ * \sa rank()
+ */
+ inline Index nonzeroPivots() const
+ {
+ eigen_assert(m_isInitialized && "LU is not initialized.");
+ return m_nonzero_pivots;
+ }
+
+ /** \returns the absolute value of the biggest pivot, i.e. the biggest
+ * diagonal coefficient of U.
+ */
+ RealScalar maxPivot() const { return m_maxpivot; }
+
+ protected:
+ MatrixType m_qr;
+ HCoeffsType m_hCoeffs;
+ IntColVectorType m_rows_transpositions;
+ IntRowVectorType m_cols_transpositions;
+ PermutationType m_cols_permutation;
+ RowVectorType m_temp;
+ bool m_isInitialized, m_usePrescribedThreshold;
+ RealScalar m_prescribedThreshold, m_maxpivot;
+ Index m_nonzero_pivots;
+ RealScalar m_precision;
+ Index m_det_pq;
+};
+
+template<typename MatrixType>
+typename MatrixType::RealScalar FullPivHouseholderQR<MatrixType>::absDeterminant() const
+{
+ eigen_assert(m_isInitialized && "FullPivHouseholderQR is not initialized.");
+ eigen_assert(m_qr.rows() == m_qr.cols() && "You can't take the determinant of a non-square matrix!");
+ return internal::abs(m_qr.diagonal().prod());
+}
+
+template<typename MatrixType>
+typename MatrixType::RealScalar FullPivHouseholderQR<MatrixType>::logAbsDeterminant() const
+{
+ eigen_assert(m_isInitialized && "FullPivHouseholderQR is not initialized.");
+ eigen_assert(m_qr.rows() == m_qr.cols() && "You can't take the determinant of a non-square matrix!");
+ return m_qr.diagonal().cwiseAbs().array().log().sum();
+}
+
+template<typename MatrixType>
+FullPivHouseholderQR<MatrixType>& FullPivHouseholderQR<MatrixType>::compute(const MatrixType& matrix)
+{
+ Index rows = matrix.rows();
+ Index cols = matrix.cols();
+ Index size = (std::min)(rows,cols);
+
+ m_qr = matrix;
+ m_hCoeffs.resize(size);
+
+ m_temp.resize(cols);
+
+ m_precision = NumTraits<Scalar>::epsilon() * size;
+
+ m_rows_transpositions.resize(matrix.rows());
+ m_cols_transpositions.resize(matrix.cols());
+ Index number_of_transpositions = 0;
+
+ RealScalar biggest(0);
+
+ m_nonzero_pivots = size; // the generic case is that in which all pivots are nonzero (invertible case)
+ m_maxpivot = RealScalar(0);
+
+ for (Index k = 0; k < size; ++k)
+ {
+ Index row_of_biggest_in_corner, col_of_biggest_in_corner;
+ RealScalar biggest_in_corner;
+
+ biggest_in_corner = m_qr.bottomRightCorner(rows-k, cols-k)
+ .cwiseAbs()
+ .maxCoeff(&row_of_biggest_in_corner, &col_of_biggest_in_corner);
+ row_of_biggest_in_corner += k;
+ col_of_biggest_in_corner += k;
+ if(k==0) biggest = biggest_in_corner;
+
+ // if the corner is negligible, then we have less than full rank, and we can finish early
+ if(internal::isMuchSmallerThan(biggest_in_corner, biggest, m_precision))
+ {
+ m_nonzero_pivots = k;
+ for(Index i = k; i < size; i++)
+ {
+ m_rows_transpositions.coeffRef(i) = i;
+ m_cols_transpositions.coeffRef(i) = i;
+ m_hCoeffs.coeffRef(i) = Scalar(0);
+ }
+ break;
+ }
+
+ m_rows_transpositions.coeffRef(k) = row_of_biggest_in_corner;
+ m_cols_transpositions.coeffRef(k) = col_of_biggest_in_corner;
+ if(k != row_of_biggest_in_corner) {
+ m_qr.row(k).tail(cols-k).swap(m_qr.row(row_of_biggest_in_corner).tail(cols-k));
+ ++number_of_transpositions;
+ }
+ if(k != col_of_biggest_in_corner) {
+ m_qr.col(k).swap(m_qr.col(col_of_biggest_in_corner));
+ ++number_of_transpositions;
+ }
+
+ RealScalar beta;
+ m_qr.col(k).tail(rows-k).makeHouseholderInPlace(m_hCoeffs.coeffRef(k), beta);
+ m_qr.coeffRef(k,k) = beta;
+
+ // remember the maximum absolute value of diagonal coefficients
+ if(internal::abs(beta) > m_maxpivot) m_maxpivot = internal::abs(beta);
+
+ m_qr.bottomRightCorner(rows-k, cols-k-1)
+ .applyHouseholderOnTheLeft(m_qr.col(k).tail(rows-k-1), m_hCoeffs.coeffRef(k), &m_temp.coeffRef(k+1));
+ }
+
+ m_cols_permutation.setIdentity(cols);
+ for(Index k = 0; k < size; ++k)
+ m_cols_permutation.applyTranspositionOnTheRight(k, m_cols_transpositions.coeff(k));
+
+ m_det_pq = (number_of_transpositions%2) ? -1 : 1;
+ m_isInitialized = true;
+
+ return *this;
+}
+
+namespace internal {
+
+template<typename _MatrixType, typename Rhs>
+struct solve_retval<FullPivHouseholderQR<_MatrixType>, Rhs>
+ : solve_retval_base<FullPivHouseholderQR<_MatrixType>, Rhs>
+{
+ EIGEN_MAKE_SOLVE_HELPERS(FullPivHouseholderQR<_MatrixType>,Rhs)
+
+ template<typename Dest> void evalTo(Dest& dst) const
+ {
+ const Index rows = dec().rows(), cols = dec().cols();
+ eigen_assert(rhs().rows() == rows);
+
+ // FIXME introduce nonzeroPivots() and use it here. and more generally,
+ // make the same improvements in this dec as in FullPivLU.
+ if(dec().rank()==0)
+ {
+ dst.setZero();
+ return;
+ }
+
+ typename Rhs::PlainObject c(rhs());
+
+ Matrix<Scalar,1,Rhs::ColsAtCompileTime> temp(rhs().cols());
+ for (Index k = 0; k < dec().rank(); ++k)
+ {
+ Index remainingSize = rows-k;
+ c.row(k).swap(c.row(dec().rowsTranspositions().coeff(k)));
+ c.bottomRightCorner(remainingSize, rhs().cols())
+ .applyHouseholderOnTheLeft(dec().matrixQR().col(k).tail(remainingSize-1),
+ dec().hCoeffs().coeff(k), &temp.coeffRef(0));
+ }
+
+ if(!dec().isSurjective())
+ {
+ // is c is in the image of R ?
+ RealScalar biggest_in_upper_part_of_c = c.topRows( dec().rank() ).cwiseAbs().maxCoeff();
+ RealScalar biggest_in_lower_part_of_c = c.bottomRows(rows-dec().rank()).cwiseAbs().maxCoeff();
+ // FIXME brain dead
+ const RealScalar m_precision = NumTraits<Scalar>::epsilon() * (std::min)(rows,cols);
+ // this internal:: prefix is needed by at least gcc 3.4 and ICC
+ if(!internal::isMuchSmallerThan(biggest_in_lower_part_of_c, biggest_in_upper_part_of_c, m_precision))
+ return;
+ }
+ dec().matrixQR()
+ .topLeftCorner(dec().rank(), dec().rank())
+ .template triangularView<Upper>()
+ .solveInPlace(c.topRows(dec().rank()));
+
+ for(Index i = 0; i < dec().rank(); ++i) dst.row(dec().colsPermutation().indices().coeff(i)) = c.row(i);
+ for(Index i = dec().rank(); i < cols; ++i) dst.row(dec().colsPermutation().indices().coeff(i)).setZero();
+ }
+};
+
+/** \ingroup QR_Module
+ *
+ * \brief Expression type for return value of FullPivHouseholderQR::matrixQ()
+ *
+ * \tparam MatrixType type of underlying dense matrix
+ */
+template<typename MatrixType> struct FullPivHouseholderQRMatrixQReturnType
+ : public ReturnByValue<FullPivHouseholderQRMatrixQReturnType<MatrixType> >
+{
+public:
+ typedef typename MatrixType::Index Index;
+ typedef typename internal::plain_col_type<MatrixType, Index>::type IntColVectorType;
+ typedef typename internal::plain_diag_type<MatrixType>::type HCoeffsType;
+ typedef Matrix<typename MatrixType::Scalar, 1, MatrixType::RowsAtCompileTime, RowMajor, 1,
+ MatrixType::MaxRowsAtCompileTime> WorkVectorType;
+
+ FullPivHouseholderQRMatrixQReturnType(const MatrixType& qr,
+ const HCoeffsType& hCoeffs,
+ const IntColVectorType& rowsTranspositions)
+ : m_qr(qr),
+ m_hCoeffs(hCoeffs),
+ m_rowsTranspositions(rowsTranspositions)
+ {}
+
+ template <typename ResultType>
+ void evalTo(ResultType& result) const
+ {
+ const Index rows = m_qr.rows();
+ WorkVectorType workspace(rows);
+ evalTo(result, workspace);
+ }
+
+ template <typename ResultType>
+ void evalTo(ResultType& result, WorkVectorType& workspace) const
+ {
+ // compute the product H'_0 H'_1 ... H'_n-1,
+ // where H_k is the k-th Householder transformation I - h_k v_k v_k'
+ // and v_k is the k-th Householder vector [1,m_qr(k+1,k), m_qr(k+2,k), ...]
+ const Index rows = m_qr.rows();
+ const Index cols = m_qr.cols();
+ const Index size = (std::min)(rows, cols);
+ workspace.resize(rows);
+ result.setIdentity(rows, rows);
+ for (Index k = size-1; k >= 0; k--)
+ {
+ result.block(k, k, rows-k, rows-k)
+ .applyHouseholderOnTheLeft(m_qr.col(k).tail(rows-k-1), internal::conj(m_hCoeffs.coeff(k)), &workspace.coeffRef(k));
+ result.row(k).swap(result.row(m_rowsTranspositions.coeff(k)));
+ }
+ }
+
+ Index rows() const { return m_qr.rows(); }
+ Index cols() const { return m_qr.rows(); }
+
+protected:
+ typename MatrixType::Nested m_qr;
+ typename HCoeffsType::Nested m_hCoeffs;
+ typename IntColVectorType::Nested m_rowsTranspositions;
+};
+
+} // end namespace internal
+
+template<typename MatrixType>
+inline typename FullPivHouseholderQR<MatrixType>::MatrixQReturnType FullPivHouseholderQR<MatrixType>::matrixQ() const
+{
+ eigen_assert(m_isInitialized && "FullPivHouseholderQR is not initialized.");
+ return MatrixQReturnType(m_qr, m_hCoeffs, m_rows_transpositions);
+}
+
+/** \return the full-pivoting Householder QR decomposition of \c *this.
+ *
+ * \sa class FullPivHouseholderQR
+ */
+template<typename Derived>
+const FullPivHouseholderQR<typename MatrixBase<Derived>::PlainObject>
+MatrixBase<Derived>::fullPivHouseholderQr() const
+{
+ return FullPivHouseholderQR<PlainObject>(eval());
+}
+
+} // end namespace Eigen
+
+#endif // EIGEN_FULLPIVOTINGHOUSEHOLDERQR_H
diff --git a/Eigen/src/QR/HouseholderQR.h b/Eigen/src/QR/HouseholderQR.h
new file mode 100644
index 000000000..5bcb32c1e
--- /dev/null
+++ b/Eigen/src/QR/HouseholderQR.h
@@ -0,0 +1,343 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra.
+//
+// Copyright (C) 2008-2010 Gael Guennebaud <gael.guennebaud@inria.fr>
+// Copyright (C) 2009 Benoit Jacob <jacob.benoit.1@gmail.com>
+// Copyright (C) 2010 Vincent Lejeune
+//
+// This Source Code Form is subject to the terms of the Mozilla
+// Public License v. 2.0. If a copy of the MPL was not distributed
+// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+#ifndef EIGEN_QR_H
+#define EIGEN_QR_H
+
+namespace Eigen {
+
+/** \ingroup QR_Module
+ *
+ *
+ * \class HouseholderQR
+ *
+ * \brief Householder QR decomposition of a matrix
+ *
+ * \param MatrixType the type of the matrix of which we are computing the QR decomposition
+ *
+ * This class performs a QR decomposition of a matrix \b A into matrices \b Q and \b R
+ * such that
+ * \f[
+ * \mathbf{A} = \mathbf{Q} \, \mathbf{R}
+ * \f]
+ * by using Householder transformations. Here, \b Q a unitary matrix and \b R an upper triangular matrix.
+ * The result is stored in a compact way compatible with LAPACK.
+ *
+ * Note that no pivoting is performed. This is \b not a rank-revealing decomposition.
+ * If you want that feature, use FullPivHouseholderQR or ColPivHouseholderQR instead.
+ *
+ * This Householder QR decomposition is faster, but less numerically stable and less feature-full than
+ * FullPivHouseholderQR or ColPivHouseholderQR.
+ *
+ * \sa MatrixBase::householderQr()
+ */
+template<typename _MatrixType> class HouseholderQR
+{
+ public:
+
+ typedef _MatrixType MatrixType;
+ enum {
+ RowsAtCompileTime = MatrixType::RowsAtCompileTime,
+ ColsAtCompileTime = MatrixType::ColsAtCompileTime,
+ Options = MatrixType::Options,
+ MaxRowsAtCompileTime = MatrixType::MaxRowsAtCompileTime,
+ MaxColsAtCompileTime = MatrixType::MaxColsAtCompileTime
+ };
+ typedef typename MatrixType::Scalar Scalar;
+ typedef typename MatrixType::RealScalar RealScalar;
+ typedef typename MatrixType::Index Index;
+ typedef Matrix<Scalar, RowsAtCompileTime, RowsAtCompileTime, (MatrixType::Flags&RowMajorBit) ? RowMajor : ColMajor, MaxRowsAtCompileTime, MaxRowsAtCompileTime> MatrixQType;
+ typedef typename internal::plain_diag_type<MatrixType>::type HCoeffsType;
+ typedef typename internal::plain_row_type<MatrixType>::type RowVectorType;
+ typedef typename HouseholderSequence<MatrixType,HCoeffsType>::ConjugateReturnType HouseholderSequenceType;
+
+ /**
+ * \brief Default Constructor.
+ *
+ * The default constructor is useful in cases in which the user intends to
+ * perform decompositions via HouseholderQR::compute(const MatrixType&).
+ */
+ HouseholderQR() : m_qr(), m_hCoeffs(), m_temp(), m_isInitialized(false) {}
+
+ /** \brief Default Constructor with memory preallocation
+ *
+ * Like the default constructor but with preallocation of the internal data
+ * according to the specified problem \a size.
+ * \sa HouseholderQR()
+ */
+ HouseholderQR(Index rows, Index cols)
+ : m_qr(rows, cols),
+ m_hCoeffs((std::min)(rows,cols)),
+ m_temp(cols),
+ m_isInitialized(false) {}
+
+ HouseholderQR(const MatrixType& matrix)
+ : m_qr(matrix.rows(), matrix.cols()),
+ m_hCoeffs((std::min)(matrix.rows(),matrix.cols())),
+ m_temp(matrix.cols()),
+ m_isInitialized(false)
+ {
+ compute(matrix);
+ }
+
+ /** This method finds a solution x to the equation Ax=b, where A is the matrix of which
+ * *this is the QR decomposition, if any exists.
+ *
+ * \param b the right-hand-side of the equation to solve.
+ *
+ * \returns a solution.
+ *
+ * \note The case where b is a matrix is not yet implemented. Also, this
+ * code is space inefficient.
+ *
+ * \note_about_checking_solutions
+ *
+ * \note_about_arbitrary_choice_of_solution
+ *
+ * Example: \include HouseholderQR_solve.cpp
+ * Output: \verbinclude HouseholderQR_solve.out
+ */
+ template<typename Rhs>
+ inline const internal::solve_retval<HouseholderQR, Rhs>
+ solve(const MatrixBase<Rhs>& b) const
+ {
+ eigen_assert(m_isInitialized && "HouseholderQR is not initialized.");
+ return internal::solve_retval<HouseholderQR, Rhs>(*this, b.derived());
+ }
+
+ HouseholderSequenceType householderQ() const
+ {
+ eigen_assert(m_isInitialized && "HouseholderQR is not initialized.");
+ return HouseholderSequenceType(m_qr, m_hCoeffs.conjugate());
+ }
+
+ /** \returns a reference to the matrix where the Householder QR decomposition is stored
+ * in a LAPACK-compatible way.
+ */
+ const MatrixType& matrixQR() const
+ {
+ eigen_assert(m_isInitialized && "HouseholderQR is not initialized.");
+ return m_qr;
+ }
+
+ HouseholderQR& compute(const MatrixType& matrix);
+
+ /** \returns the absolute value of the determinant of the matrix of which
+ * *this is the QR decomposition. It has only linear complexity
+ * (that is, O(n) where n is the dimension of the square matrix)
+ * as the QR decomposition has already been computed.
+ *
+ * \note This is only for square matrices.
+ *
+ * \warning a determinant can be very big or small, so for matrices
+ * of large enough dimension, there is a risk of overflow/underflow.
+ * One way to work around that is to use logAbsDeterminant() instead.
+ *
+ * \sa logAbsDeterminant(), MatrixBase::determinant()
+ */
+ typename MatrixType::RealScalar absDeterminant() const;
+
+ /** \returns the natural log of the absolute value of the determinant of the matrix of which
+ * *this is the QR decomposition. It has only linear complexity
+ * (that is, O(n) where n is the dimension of the square matrix)
+ * as the QR decomposition has already been computed.
+ *
+ * \note This is only for square matrices.
+ *
+ * \note This method is useful to work around the risk of overflow/underflow that's inherent
+ * to determinant computation.
+ *
+ * \sa absDeterminant(), MatrixBase::determinant()
+ */
+ typename MatrixType::RealScalar logAbsDeterminant() const;
+
+ inline Index rows() const { return m_qr.rows(); }
+ inline Index cols() const { return m_qr.cols(); }
+ const HCoeffsType& hCoeffs() const { return m_hCoeffs; }
+
+ protected:
+ MatrixType m_qr;
+ HCoeffsType m_hCoeffs;
+ RowVectorType m_temp;
+ bool m_isInitialized;
+};
+
+template<typename MatrixType>
+typename MatrixType::RealScalar HouseholderQR<MatrixType>::absDeterminant() const
+{
+ eigen_assert(m_isInitialized && "HouseholderQR is not initialized.");
+ eigen_assert(m_qr.rows() == m_qr.cols() && "You can't take the determinant of a non-square matrix!");
+ return internal::abs(m_qr.diagonal().prod());
+}
+
+template<typename MatrixType>
+typename MatrixType::RealScalar HouseholderQR<MatrixType>::logAbsDeterminant() const
+{
+ eigen_assert(m_isInitialized && "HouseholderQR is not initialized.");
+ eigen_assert(m_qr.rows() == m_qr.cols() && "You can't take the determinant of a non-square matrix!");
+ return m_qr.diagonal().cwiseAbs().array().log().sum();
+}
+
+namespace internal {
+
+/** \internal */
+template<typename MatrixQR, typename HCoeffs>
+void householder_qr_inplace_unblocked(MatrixQR& mat, HCoeffs& hCoeffs, typename MatrixQR::Scalar* tempData = 0)
+{
+ typedef typename MatrixQR::Index Index;
+ typedef typename MatrixQR::Scalar Scalar;
+ typedef typename MatrixQR::RealScalar RealScalar;
+ Index rows = mat.rows();
+ Index cols = mat.cols();
+ Index size = (std::min)(rows,cols);
+
+ eigen_assert(hCoeffs.size() == size);
+
+ typedef Matrix<Scalar,MatrixQR::ColsAtCompileTime,1> TempType;
+ TempType tempVector;
+ if(tempData==0)
+ {
+ tempVector.resize(cols);
+ tempData = tempVector.data();
+ }
+
+ for(Index k = 0; k < size; ++k)
+ {
+ Index remainingRows = rows - k;
+ Index remainingCols = cols - k - 1;
+
+ RealScalar beta;
+ mat.col(k).tail(remainingRows).makeHouseholderInPlace(hCoeffs.coeffRef(k), beta);
+ mat.coeffRef(k,k) = beta;
+
+ // apply H to remaining part of m_qr from the left
+ mat.bottomRightCorner(remainingRows, remainingCols)
+ .applyHouseholderOnTheLeft(mat.col(k).tail(remainingRows-1), hCoeffs.coeffRef(k), tempData+k+1);
+ }
+}
+
+/** \internal */
+template<typename MatrixQR, typename HCoeffs>
+void householder_qr_inplace_blocked(MatrixQR& mat, HCoeffs& hCoeffs,
+ typename MatrixQR::Index maxBlockSize=32,
+ typename MatrixQR::Scalar* tempData = 0)
+{
+ typedef typename MatrixQR::Index Index;
+ typedef typename MatrixQR::Scalar Scalar;
+ typedef typename MatrixQR::RealScalar RealScalar;
+ typedef Block<MatrixQR,Dynamic,Dynamic> BlockType;
+
+ Index rows = mat.rows();
+ Index cols = mat.cols();
+ Index size = (std::min)(rows, cols);
+
+ typedef Matrix<Scalar,Dynamic,1,ColMajor,MatrixQR::MaxColsAtCompileTime,1> TempType;
+ TempType tempVector;
+ if(tempData==0)
+ {
+ tempVector.resize(cols);
+ tempData = tempVector.data();
+ }
+
+ Index blockSize = (std::min)(maxBlockSize,size);
+
+ Index k = 0;
+ for (k = 0; k < size; k += blockSize)
+ {
+ Index bs = (std::min)(size-k,blockSize); // actual size of the block
+ Index tcols = cols - k - bs; // trailing columns
+ Index brows = rows-k; // rows of the block
+
+ // partition the matrix:
+ // A00 | A01 | A02
+ // mat = A10 | A11 | A12
+ // A20 | A21 | A22
+ // and performs the qr dec of [A11^T A12^T]^T
+ // and update [A21^T A22^T]^T using level 3 operations.
+ // Finally, the algorithm continue on A22
+
+ BlockType A11_21 = mat.block(k,k,brows,bs);
+ Block<HCoeffs,Dynamic,1> hCoeffsSegment = hCoeffs.segment(k,bs);
+
+ householder_qr_inplace_unblocked(A11_21, hCoeffsSegment, tempData);
+
+ if(tcols)
+ {
+ BlockType A21_22 = mat.block(k,k+bs,brows,tcols);
+ apply_block_householder_on_the_left(A21_22,A11_21,hCoeffsSegment.adjoint());
+ }
+ }
+}
+
+template<typename _MatrixType, typename Rhs>
+struct solve_retval<HouseholderQR<_MatrixType>, Rhs>
+ : solve_retval_base<HouseholderQR<_MatrixType>, Rhs>
+{
+ EIGEN_MAKE_SOLVE_HELPERS(HouseholderQR<_MatrixType>,Rhs)
+
+ template<typename Dest> void evalTo(Dest& dst) const
+ {
+ const Index rows = dec().rows(), cols = dec().cols();
+ const Index rank = (std::min)(rows, cols);
+ eigen_assert(rhs().rows() == rows);
+
+ typename Rhs::PlainObject c(rhs());
+
+ // Note that the matrix Q = H_0^* H_1^*... so its inverse is Q^* = (H_0 H_1 ...)^T
+ c.applyOnTheLeft(householderSequence(
+ dec().matrixQR().leftCols(rank),
+ dec().hCoeffs().head(rank)).transpose()
+ );
+
+ dec().matrixQR()
+ .topLeftCorner(rank, rank)
+ .template triangularView<Upper>()
+ .solveInPlace(c.topRows(rank));
+
+ dst.topRows(rank) = c.topRows(rank);
+ dst.bottomRows(cols-rank).setZero();
+ }
+};
+
+} // end namespace internal
+
+template<typename MatrixType>
+HouseholderQR<MatrixType>& HouseholderQR<MatrixType>::compute(const MatrixType& matrix)
+{
+ Index rows = matrix.rows();
+ Index cols = matrix.cols();
+ Index size = (std::min)(rows,cols);
+
+ m_qr = matrix;
+ m_hCoeffs.resize(size);
+
+ m_temp.resize(cols);
+
+ internal::householder_qr_inplace_blocked(m_qr, m_hCoeffs, 48, m_temp.data());
+
+ m_isInitialized = true;
+ return *this;
+}
+
+/** \return the Householder QR decomposition of \c *this.
+ *
+ * \sa class HouseholderQR
+ */
+template<typename Derived>
+const HouseholderQR<typename MatrixBase<Derived>::PlainObject>
+MatrixBase<Derived>::householderQr() const
+{
+ return HouseholderQR<PlainObject>(eval());
+}
+
+} // end namespace Eigen
+
+#endif // EIGEN_QR_H
diff --git a/Eigen/src/QR/HouseholderQR_MKL.h b/Eigen/src/QR/HouseholderQR_MKL.h
new file mode 100644
index 000000000..5313de604
--- /dev/null
+++ b/Eigen/src/QR/HouseholderQR_MKL.h
@@ -0,0 +1,69 @@
+/*
+ Copyright (c) 2011, Intel Corporation. All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without modification,
+ are permitted provided that the following conditions are met:
+
+ * Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+ * Neither the name of Intel Corporation nor the names of its contributors may
+ be used to endorse or promote products derived from this software without
+ specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+ ********************************************************************************
+ * Content : Eigen bindings to Intel(R) MKL
+ * Householder QR decomposition of a matrix w/o pivoting based on
+ * LAPACKE_?geqrf function.
+ ********************************************************************************
+*/
+
+#ifndef EIGEN_QR_MKL_H
+#define EIGEN_QR_MKL_H
+
+#include "Eigen/src/Core/util/MKL_support.h"
+
+namespace Eigen {
+
+namespace internal {
+
+/** \internal Specialization for the data types supported by MKL */
+
+#define EIGEN_MKL_QR_NOPIV(EIGTYPE, MKLTYPE, MKLPREFIX) \
+template<typename MatrixQR, typename HCoeffs> \
+void householder_qr_inplace_blocked(MatrixQR& mat, HCoeffs& hCoeffs, \
+ typename MatrixQR::Index maxBlockSize=32, \
+ EIGTYPE* tempData = 0) \
+{ \
+ lapack_int m = mat.rows(); \
+ lapack_int n = mat.cols(); \
+ lapack_int lda = mat.outerStride(); \
+ lapack_int matrix_order = (MatrixQR::IsRowMajor) ? LAPACK_ROW_MAJOR : LAPACK_COL_MAJOR; \
+ LAPACKE_##MKLPREFIX##geqrf( matrix_order, m, n, (MKLTYPE*)mat.data(), lda, (MKLTYPE*)hCoeffs.data()); \
+ hCoeffs.adjointInPlace(); \
+\
+}
+
+EIGEN_MKL_QR_NOPIV(double, double, d)
+EIGEN_MKL_QR_NOPIV(float, float, s)
+EIGEN_MKL_QR_NOPIV(dcomplex, MKL_Complex16, z)
+EIGEN_MKL_QR_NOPIV(scomplex, MKL_Complex8, c)
+
+} // end namespace internal
+
+} // end namespace Eigen
+
+#endif // EIGEN_QR_MKL_H
diff --git a/Eigen/src/SVD/CMakeLists.txt b/Eigen/src/SVD/CMakeLists.txt
new file mode 100644
index 000000000..55efc44b1
--- /dev/null
+++ b/Eigen/src/SVD/CMakeLists.txt
@@ -0,0 +1,6 @@
+FILE(GLOB Eigen_SVD_SRCS "*.h")
+
+INSTALL(FILES
+ ${Eigen_SVD_SRCS}
+ DESTINATION ${INCLUDE_INSTALL_DIR}/Eigen/src/SVD COMPONENT Devel
+ )
diff --git a/Eigen/src/SVD/JacobiSVD.h b/Eigen/src/SVD/JacobiSVD.h
new file mode 100644
index 000000000..a7dbf0737
--- /dev/null
+++ b/Eigen/src/SVD/JacobiSVD.h
@@ -0,0 +1,867 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra.
+//
+// Copyright (C) 2009-2010 Benoit Jacob <jacob.benoit.1@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 EIGEN_JACOBISVD_H
+#define EIGEN_JACOBISVD_H
+
+namespace Eigen {
+
+namespace internal {
+// forward declaration (needed by ICC)
+// the empty body is required by MSVC
+template<typename MatrixType, int QRPreconditioner,
+ bool IsComplex = NumTraits<typename MatrixType::Scalar>::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<typename MatrixType, int QRPreconditioner, int Case>
+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<typename MatrixType, int QRPreconditioner, int Case,
+ bool DoAnything = qr_preconditioner_should_do_anything<MatrixType, QRPreconditioner, Case>::ret
+> struct qr_preconditioner_impl {};
+
+template<typename MatrixType, int QRPreconditioner, int Case>
+class qr_preconditioner_impl<MatrixType, QRPreconditioner, Case, false>
+{
+public:
+ typedef typename MatrixType::Index Index;
+ void allocate(const JacobiSVD<MatrixType, QRPreconditioner>&) {}
+ bool run(JacobiSVD<MatrixType, QRPreconditioner>&, const MatrixType&)
+ {
+ return false;
+ }
+};
+
+/*** preconditioner using FullPivHouseholderQR ***/
+
+template<typename MatrixType>
+class qr_preconditioner_impl<MatrixType, FullPivHouseholderQRPreconditioner, PreconditionIfMoreRowsThanCols, true>
+{
+public:
+ typedef typename MatrixType::Index Index;
+ typedef typename MatrixType::Scalar Scalar;
+ enum
+ {
+ RowsAtCompileTime = MatrixType::RowsAtCompileTime,
+ MaxRowsAtCompileTime = MatrixType::MaxRowsAtCompileTime
+ };
+ typedef Matrix<Scalar, 1, RowsAtCompileTime, RowMajor, 1, MaxRowsAtCompileTime> WorkspaceType;
+
+ void allocate(const JacobiSVD<MatrixType, FullPivHouseholderQRPreconditioner>& svd)
+ {
+ if (svd.rows() != m_qr.rows() || svd.cols() != m_qr.cols())
+ {
+ m_qr = FullPivHouseholderQR<MatrixType>(svd.rows(), svd.cols());
+ }
+ if (svd.m_computeFullU) m_workspace.resize(svd.rows());
+ }
+
+ bool run(JacobiSVD<MatrixType, FullPivHouseholderQRPreconditioner>& 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<Upper>();
+ if(svd.m_computeFullU) m_qr.matrixQ().evalTo(svd.m_matrixU, m_workspace);
+ if(svd.computeV()) svd.m_matrixV = m_qr.colsPermutation();
+ return true;
+ }
+ return false;
+ }
+private:
+ FullPivHouseholderQR<MatrixType> m_qr;
+ WorkspaceType m_workspace;
+};
+
+template<typename MatrixType>
+class qr_preconditioner_impl<MatrixType, FullPivHouseholderQRPreconditioner, PreconditionIfMoreColsThanRows, true>
+{
+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<Scalar, ColsAtCompileTime, RowsAtCompileTime, Options, MaxColsAtCompileTime, MaxRowsAtCompileTime>
+ TransposeTypeWithSameStorageOrder;
+
+ void allocate(const JacobiSVD<MatrixType, FullPivHouseholderQRPreconditioner>& svd)
+ {
+ if (svd.cols() != m_qr.rows() || svd.rows() != m_qr.cols())
+ {
+ m_qr = FullPivHouseholderQR<TransposeTypeWithSameStorageOrder>(svd.cols(), svd.rows());
+ }
+ m_adjoint.resize(svd.cols(), svd.rows());
+ if (svd.m_computeFullV) m_workspace.resize(svd.cols());
+ }
+
+ bool run(JacobiSVD<MatrixType, FullPivHouseholderQRPreconditioner>& 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<Upper>().adjoint();
+ if(svd.m_computeFullV) m_qr.matrixQ().evalTo(svd.m_matrixV, m_workspace);
+ if(svd.computeU()) svd.m_matrixU = m_qr.colsPermutation();
+ return true;
+ }
+ else return false;
+ }
+private:
+ FullPivHouseholderQR<TransposeTypeWithSameStorageOrder> m_qr;
+ TransposeTypeWithSameStorageOrder m_adjoint;
+ typename internal::plain_row_type<MatrixType>::type m_workspace;
+};
+
+/*** preconditioner using ColPivHouseholderQR ***/
+
+template<typename MatrixType>
+class qr_preconditioner_impl<MatrixType, ColPivHouseholderQRPreconditioner, PreconditionIfMoreRowsThanCols, true>
+{
+public:
+ typedef typename MatrixType::Index Index;
+
+ void allocate(const JacobiSVD<MatrixType, ColPivHouseholderQRPreconditioner>& svd)
+ {
+ if (svd.rows() != m_qr.rows() || svd.cols() != m_qr.cols())
+ {
+ m_qr = ColPivHouseholderQR<MatrixType>(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<MatrixType, ColPivHouseholderQRPreconditioner>& 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<Upper>();
+ 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:
+ ColPivHouseholderQR<MatrixType> m_qr;
+ typename internal::plain_col_type<MatrixType>::type m_workspace;
+};
+
+template<typename MatrixType>
+class qr_preconditioner_impl<MatrixType, ColPivHouseholderQRPreconditioner, PreconditionIfMoreColsThanRows, true>
+{
+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<Scalar, ColsAtCompileTime, RowsAtCompileTime, Options, MaxColsAtCompileTime, MaxRowsAtCompileTime>
+ TransposeTypeWithSameStorageOrder;
+
+ void allocate(const JacobiSVD<MatrixType, ColPivHouseholderQRPreconditioner>& svd)
+ {
+ if (svd.cols() != m_qr.rows() || svd.rows() != m_qr.cols())
+ {
+ m_qr = ColPivHouseholderQR<TransposeTypeWithSameStorageOrder>(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<MatrixType, ColPivHouseholderQRPreconditioner>& 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<Upper>().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:
+ ColPivHouseholderQR<TransposeTypeWithSameStorageOrder> m_qr;
+ TransposeTypeWithSameStorageOrder m_adjoint;
+ typename internal::plain_row_type<MatrixType>::type m_workspace;
+};
+
+/*** preconditioner using HouseholderQR ***/
+
+template<typename MatrixType>
+class qr_preconditioner_impl<MatrixType, HouseholderQRPreconditioner, PreconditionIfMoreRowsThanCols, true>
+{
+public:
+ typedef typename MatrixType::Index Index;
+
+ void allocate(const JacobiSVD<MatrixType, HouseholderQRPreconditioner>& svd)
+ {
+ if (svd.rows() != m_qr.rows() || svd.cols() != m_qr.cols())
+ {
+ m_qr = HouseholderQR<MatrixType>(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<MatrixType, HouseholderQRPreconditioner>& 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<Upper>();
+ 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:
+ HouseholderQR<MatrixType> m_qr;
+ typename internal::plain_col_type<MatrixType>::type m_workspace;
+};
+
+template<typename MatrixType>
+class qr_preconditioner_impl<MatrixType, HouseholderQRPreconditioner, PreconditionIfMoreColsThanRows, true>
+{
+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<Scalar, ColsAtCompileTime, RowsAtCompileTime, Options, MaxColsAtCompileTime, MaxRowsAtCompileTime>
+ TransposeTypeWithSameStorageOrder;
+
+ void allocate(const JacobiSVD<MatrixType, HouseholderQRPreconditioner>& svd)
+ {
+ if (svd.cols() != m_qr.rows() || svd.rows() != m_qr.cols())
+ {
+ m_qr = HouseholderQR<TransposeTypeWithSameStorageOrder>(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<MatrixType, HouseholderQRPreconditioner>& 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<Upper>().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:
+ HouseholderQR<TransposeTypeWithSameStorageOrder> m_qr;
+ TransposeTypeWithSameStorageOrder m_adjoint;
+ typename internal::plain_row_type<MatrixType>::type m_workspace;
+};
+
+/*** 2x2 SVD implementation
+ ***
+ *** JacobiSVD consists in performing a series of 2x2 SVD subproblems
+ ***/
+
+template<typename MatrixType, int QRPreconditioner>
+struct svd_precondition_2x2_block_to_be_real<MatrixType, QRPreconditioner, false>
+{
+ typedef JacobiSVD<MatrixType, QRPreconditioner> SVD;
+ typedef typename SVD::Index Index;
+ static void run(typename SVD::WorkMatrixType&, SVD&, Index, Index) {}
+};
+
+template<typename MatrixType, int QRPreconditioner>
+struct svd_precondition_2x2_block_to_be_real<MatrixType, QRPreconditioner, true>
+{
+ typedef JacobiSVD<MatrixType, QRPreconditioner> 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)
+ {
+ Scalar z;
+ JacobiRotation<Scalar> rot;
+ RealScalar n = sqrt(abs2(work_matrix.coeff(p,p)) + 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);
+ 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);
+ }
+ 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<typename MatrixType, typename RealScalar, typename Index>
+void real_2x2_jacobi_svd(const MatrixType& matrix, Index p, Index q,
+ JacobiRotation<RealScalar> *j_left,
+ JacobiRotation<RealScalar> *j_right)
+{
+ Matrix<RealScalar,2,2> m;
+ m << real(matrix.coeff(p,p)), real(matrix.coeff(p,q)),
+ real(matrix.coeff(q,p)), real(matrix.coeff(q,q));
+ JacobiRotation<RealScalar> 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 u = d / t;
+ rot1.c() = RealScalar(1) / sqrt(RealScalar(1) + abs2(u));
+ rot1.s() = rot1.c() * u;
+ }
+ m.applyOnTheLeft(0,1,rot1);
+ j_right->makeJacobi(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<typename _MatrixType, int QRPreconditioner> class JacobiSVD
+{
+ public:
+
+ typedef _MatrixType MatrixType;
+ typedef typename MatrixType::Scalar Scalar;
+ typedef typename NumTraits<typename MatrixType::Scalar>::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<Scalar, RowsAtCompileTime, RowsAtCompileTime,
+ MatrixOptions, MaxRowsAtCompileTime, MaxRowsAtCompileTime>
+ MatrixUType;
+ typedef Matrix<Scalar, ColsAtCompileTime, ColsAtCompileTime,
+ MatrixOptions, MaxColsAtCompileTime, MaxColsAtCompileTime>
+ MatrixVType;
+ typedef typename internal::plain_diag_type<MatrixType, RealScalar>::type SingularValuesType;
+ typedef typename internal::plain_row_type<MatrixType>::type RowType;
+ typedef typename internal::plain_col_type<MatrixType>::type ColType;
+ typedef Matrix<Scalar, DiagSizeAtCompileTime, DiagSizeAtCompileTime,
+ MatrixOptions, MaxDiagSizeAtCompileTime, MaxDiagSizeAtCompileTime>
+ 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_computationOptions(0),
+ m_rows(-1), m_cols(-1)
+ {}
+
+
+ /** \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_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_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<typename Rhs>
+ inline const internal::solve_retval<JacobiSVD, Rhs>
+ solve(const MatrixBase<Rhs>& 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<JacobiSVD, Rhs>(*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;
+ }
+
+ inline Index rows() const { return m_rows; }
+ inline Index cols() const { return m_cols; }
+
+ private:
+ void allocate(Index rows, Index cols, unsigned int computationOptions);
+
+ protected:
+ MatrixUType m_matrixU;
+ MatrixVType m_matrixV;
+ SingularValuesType m_singularValues;
+ WorkMatrixType m_workMatrix;
+ bool m_isInitialized, m_isAllocated;
+ bool m_computeFullU, m_computeThinU;
+ bool m_computeFullV, m_computeThinV;
+ unsigned int m_computationOptions;
+ Index m_nonzeroSingularValues, m_rows, m_cols, m_diagSize;
+
+ template<typename __MatrixType, int _QRPreconditioner, bool _IsComplex>
+ friend struct internal::svd_precondition_2x2_block_to_be_real;
+ template<typename __MatrixType, int _QRPreconditioner, int _Case, bool _DoAnything>
+ friend struct internal::qr_preconditioner_impl;
+
+ internal::qr_preconditioner_impl<MatrixType, QRPreconditioner, internal::PreconditionIfMoreColsThanRows> m_qr_precond_morecols;
+ internal::qr_preconditioner_impl<MatrixType, QRPreconditioner, internal::PreconditionIfMoreRowsThanCols> m_qr_precond_morerows;
+};
+
+template<typename MatrixType, int QRPreconditioner>
+void JacobiSVD<MatrixType, QRPreconditioner>::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);
+ m_matrixU.resize(m_rows, m_computeFullU ? m_rows
+ : m_computeThinU ? m_diagSize
+ : 0);
+ 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);
+}
+
+template<typename MatrixType, int QRPreconditioner>
+JacobiSVD<MatrixType, QRPreconditioner>&
+JacobiSVD<MatrixType, QRPreconditioner>::compute(const MatrixType& matrix, unsigned int computationOptions)
+{
+ 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<Scalar>::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<RealScalar>::denorm_min();
+
+ /*** step 1. The R-SVD step: we use a QR decomposition to reduce to the case of a square matrix */
+
+ if(!m_qr_precond_morecols.run(*this, matrix) && !m_qr_precond_morerows.run(*this, matrix))
+ {
+ m_workMatrix = matrix.block(0,0,m_diagSize,m_diagSize);
+ if(m_computeFullU) m_matrixU.setIdentity(m_rows,m_rows);
+ 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)(internal::abs(m_workMatrix.coeff(p,p)),
+ internal::abs(m_workMatrix.coeff(q,q))));
+ if((max)(internal::abs(m_workMatrix.coeff(p,q)),internal::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<MatrixType, QRPreconditioner>::run(m_workMatrix, *this, p, q);
+ JacobiRotation<RealScalar> 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 = internal::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_isInitialized = true;
+ return *this;
+}
+
+namespace internal {
+template<typename _MatrixType, int QRPreconditioner, typename Rhs>
+struct solve_retval<JacobiSVD<_MatrixType, QRPreconditioner>, Rhs>
+ : solve_retval_base<JacobiSVD<_MatrixType, QRPreconditioner>, Rhs>
+{
+ typedef JacobiSVD<_MatrixType, QRPreconditioner> JacobiSVDType;
+ EIGEN_MAKE_SOLVE_HELPERS(JacobiSVDType,Rhs)
+
+ template<typename Dest> void evalTo(Dest& dst) const
+ {
+ eigen_assert(rhs().rows() == dec().rows());
+
+ // A = U S V^*
+ // So A^{-1} = V S^{-1} U^*
+
+ Index diagSize = (std::min)(dec().rows(), dec().cols());
+ typename JacobiSVDType::SingularValuesType invertedSingVals(diagSize);
+
+ Index nonzeroSingVals = dec().nonzeroSingularValues();
+ invertedSingVals.head(nonzeroSingVals) = dec().singularValues().head(nonzeroSingVals).array().inverse();
+ invertedSingVals.tail(diagSize - nonzeroSingVals).setZero();
+
+ dst = dec().matrixV().leftCols(diagSize)
+ * invertedSingVals.asDiagonal()
+ * dec().matrixU().leftCols(diagSize).adjoint()
+ * rhs();
+ }
+};
+} // end namespace internal
+
+/** \svd_module
+ *
+ * \return the singular value decomposition of \c *this computed by two-sided
+ * Jacobi transformations.
+ *
+ * \sa class JacobiSVD
+ */
+template<typename Derived>
+JacobiSVD<typename MatrixBase<Derived>::PlainObject>
+MatrixBase<Derived>::jacobiSvd(unsigned int computationOptions) const
+{
+ return JacobiSVD<PlainObject>(*this, computationOptions);
+}
+
+} // end namespace Eigen
+
+#endif // EIGEN_JACOBISVD_H
diff --git a/Eigen/src/SVD/JacobiSVD_MKL.h b/Eigen/src/SVD/JacobiSVD_MKL.h
new file mode 100644
index 000000000..4d479f6b2
--- /dev/null
+++ b/Eigen/src/SVD/JacobiSVD_MKL.h
@@ -0,0 +1,92 @@
+/*
+ Copyright (c) 2011, Intel Corporation. All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without modification,
+ are permitted provided that the following conditions are met:
+
+ * Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+ * Neither the name of Intel Corporation nor the names of its contributors may
+ be used to endorse or promote products derived from this software without
+ specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+ ********************************************************************************
+ * Content : Eigen bindings to Intel(R) MKL
+ * Singular Value Decomposition - SVD.
+ ********************************************************************************
+*/
+
+#ifndef EIGEN_JACOBISVD_MKL_H
+#define EIGEN_JACOBISVD_MKL_H
+
+#include "Eigen/src/Core/util/MKL_support.h"
+
+namespace Eigen {
+
+/** \internal Specialization for the data types supported by MKL */
+
+#define EIGEN_MKL_SVD(EIGTYPE, MKLTYPE, MKLRTYPE, MKLPREFIX, EIGCOLROW, MKLCOLROW) \
+template<> inline\
+JacobiSVD<Matrix<EIGTYPE, Dynamic, Dynamic, EIGCOLROW, Dynamic, Dynamic>, ColPivHouseholderQRPreconditioner>& \
+JacobiSVD<Matrix<EIGTYPE, Dynamic, Dynamic, EIGCOLROW, Dynamic, Dynamic>, ColPivHouseholderQRPreconditioner>::compute(const Matrix<EIGTYPE, Dynamic, Dynamic, EIGCOLROW, Dynamic, Dynamic>& matrix, unsigned int computationOptions) \
+{ \
+ typedef Matrix<EIGTYPE, Dynamic, Dynamic, EIGCOLROW, Dynamic, Dynamic> MatrixType; \
+ typedef MatrixType::Scalar Scalar; \
+ typedef MatrixType::RealScalar RealScalar; \
+ allocate(matrix.rows(), matrix.cols(), computationOptions); \
+\
+ /*const RealScalar precision = RealScalar(2) * NumTraits<Scalar>::epsilon();*/ \
+ m_nonzeroSingularValues = m_diagSize; \
+\
+ lapack_int lda = matrix.outerStride(), ldu, ldvt; \
+ lapack_int matrix_order = MKLCOLROW; \
+ char jobu, jobvt; \
+ MKLTYPE *u, *vt, dummy; \
+ jobu = (m_computeFullU) ? 'A' : (m_computeThinU) ? 'S' : 'N'; \
+ jobvt = (m_computeFullV) ? 'A' : (m_computeThinV) ? 'S' : 'N'; \
+ if (computeU()) { \
+ ldu = m_matrixU.outerStride(); \
+ u = (MKLTYPE*)m_matrixU.data(); \
+ } else { ldu=1; u=&dummy; }\
+ MatrixType localV; \
+ ldvt = (m_computeFullV) ? m_cols : (m_computeThinV) ? m_diagSize : 1; \
+ if (computeV()) { \
+ localV.resize(ldvt, m_cols); \
+ vt = (MKLTYPE*)localV.data(); \
+ } else { ldvt=1; vt=&dummy; }\
+ Matrix<MKLRTYPE, Dynamic, Dynamic> superb; superb.resize(m_diagSize, 1); \
+ MatrixType m_temp; m_temp = matrix; \
+ LAPACKE_##MKLPREFIX##gesvd( matrix_order, jobu, jobvt, m_rows, m_cols, (MKLTYPE*)m_temp.data(), lda, (MKLRTYPE*)m_singularValues.data(), u, ldu, vt, ldvt, superb.data()); \
+ if (computeV()) m_matrixV = localV.adjoint(); \
+ /* for(int i=0;i<m_diagSize;i++) if (m_singularValues.coeffRef(i) < precision) { m_nonzeroSingularValues--; m_singularValues.coeffRef(i)=RealScalar(0);}*/ \
+ m_isInitialized = true; \
+ return *this; \
+}
+
+EIGEN_MKL_SVD(double, double, double, d, ColMajor, LAPACK_COL_MAJOR)
+EIGEN_MKL_SVD(float, float, float , s, ColMajor, LAPACK_COL_MAJOR)
+EIGEN_MKL_SVD(dcomplex, MKL_Complex16, double, z, ColMajor, LAPACK_COL_MAJOR)
+EIGEN_MKL_SVD(scomplex, MKL_Complex8, float , c, ColMajor, LAPACK_COL_MAJOR)
+
+EIGEN_MKL_SVD(double, double, double, d, RowMajor, LAPACK_ROW_MAJOR)
+EIGEN_MKL_SVD(float, float, float , s, RowMajor, LAPACK_ROW_MAJOR)
+EIGEN_MKL_SVD(dcomplex, MKL_Complex16, double, z, RowMajor, LAPACK_ROW_MAJOR)
+EIGEN_MKL_SVD(scomplex, MKL_Complex8, float , c, RowMajor, LAPACK_ROW_MAJOR)
+
+} // end namespace Eigen
+
+#endif // EIGEN_JACOBISVD_MKL_H
diff --git a/Eigen/src/SVD/UpperBidiagonalization.h b/Eigen/src/SVD/UpperBidiagonalization.h
new file mode 100644
index 000000000..213b3100d
--- /dev/null
+++ b/Eigen/src/SVD/UpperBidiagonalization.h
@@ -0,0 +1,148 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra.
+//
+// Copyright (C) 2010 Benoit Jacob <jacob.benoit.1@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 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<typename _MatrixType> class UpperBidiagonalization
+{
+ public:
+
+ typedef _MatrixType MatrixType;
+ enum {
+ RowsAtCompileTime = MatrixType::RowsAtCompileTime,
+ ColsAtCompileTime = MatrixType::ColsAtCompileTime,
+ ColsAtCompileTimeMinusOne = internal::decrement_size<ColsAtCompileTime>::ret
+ };
+ typedef typename MatrixType::Scalar Scalar;
+ typedef typename MatrixType::RealScalar RealScalar;
+ typedef typename MatrixType::Index Index;
+ typedef Matrix<Scalar, 1, ColsAtCompileTime> RowVectorType;
+ typedef Matrix<Scalar, RowsAtCompileTime, 1> ColVectorType;
+ typedef BandMatrix<RealScalar, ColsAtCompileTime, ColsAtCompileTime, 1, 0> BidiagonalType;
+ typedef Matrix<Scalar, ColsAtCompileTime, 1> DiagVectorType;
+ typedef Matrix<Scalar, ColsAtCompileTimeMinusOne, 1> SuperDiagVectorType;
+ typedef HouseholderSequence<
+ const MatrixType,
+ CwiseUnaryOp<internal::scalar_conjugate_op<Scalar>, const Diagonal<const MatrixType,0> >
+ > HouseholderUSequenceType;
+ typedef HouseholderSequence<
+ const MatrixType,
+ Diagonal<const MatrixType,1>,
+ 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, 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<typename _MatrixType>
+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<typename Derived>
+const UpperBidiagonalization<typename MatrixBase<Derived>::PlainObject>
+MatrixBase<Derived>::bidiagonalization() const
+{
+ return UpperBidiagonalization<PlainObject>(eval());
+}
+#endif
+
+} // end namespace internal
+
+} // end namespace Eigen
+
+#endif // EIGEN_BIDIAGONALIZATION_H
diff --git a/Eigen/src/SparseCholesky/CMakeLists.txt b/Eigen/src/SparseCholesky/CMakeLists.txt
new file mode 100644
index 000000000..375a59d7a
--- /dev/null
+++ b/Eigen/src/SparseCholesky/CMakeLists.txt
@@ -0,0 +1,6 @@
+FILE(GLOB Eigen_SparseCholesky_SRCS "*.h")
+
+INSTALL(FILES
+ ${Eigen_SparseCholesky_SRCS}
+ DESTINATION ${INCLUDE_INSTALL_DIR}/Eigen/src/SparseCholesky COMPONENT Devel
+ )
diff --git a/Eigen/src/SparseCholesky/SimplicialCholesky.h b/Eigen/src/SparseCholesky/SimplicialCholesky.h
new file mode 100644
index 000000000..9bf38ab2d
--- /dev/null
+++ b/Eigen/src/SparseCholesky/SimplicialCholesky.h
@@ -0,0 +1,873 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra.
+//
+// Copyright (C) 2008-2010 Gael Guennebaud <gael.guennebaud@inria.fr>
+//
+// This Source Code Form is subject to the terms of the Mozilla
+// Public License v. 2.0. If a copy of the MPL was not distributed
+// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+/*
+
+NOTE: the _symbolic, and _numeric functions has been adapted from
+ the LDL library:
+
+LDL Copyright (c) 2005 by Timothy A. Davis. All Rights Reserved.
+
+LDL License:
+
+ Your use or distribution of LDL or any modified version of
+ LDL implies that you agree to this License.
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+ USA
+
+ Permission is hereby granted to use or copy this program under the
+ terms of the GNU LGPL, provided that the Copyright, this License,
+ and the Availability of the original version is retained on all copies.
+ User documentation of any code that uses this code or any modified
+ version of this code must cite the Copyright, this License, the
+ Availability note, and "Used by permission." Permission to modify
+ the code and to distribute modified code is granted, provided the
+ Copyright, this License, and the Availability note are retained,
+ and a notice that the code was modified is included.
+ */
+
+#include "../Core/util/NonMPL2.h"
+
+#ifndef EIGEN_SIMPLICIAL_CHOLESKY_H
+#define EIGEN_SIMPLICIAL_CHOLESKY_H
+
+namespace Eigen {
+
+enum SimplicialCholeskyMode {
+ SimplicialCholeskyLLT,
+ SimplicialCholeskyLDLT
+};
+
+/** \ingroup SparseCholesky_Module
+ * \brief A direct sparse Cholesky factorizations
+ *
+ * These classes provide LL^T and LDL^T Cholesky factorizations of sparse matrices that are
+ * selfadjoint and positive definite. The factorization allows for solving A.X = B where
+ * X and B can be either dense or sparse.
+ *
+ * In order to reduce the fill-in, a symmetric permutation P is applied prior to the factorization
+ * such that the factorized matrix is P A P^-1.
+ *
+ * \tparam _MatrixType the type of the sparse matrix A, it must be a SparseMatrix<>
+ * \tparam _UpLo the triangular part that will be used for the computations. It can be Lower
+ * or Upper. Default is Lower.
+ *
+ */
+template<typename Derived>
+class SimplicialCholeskyBase : internal::noncopyable
+{
+ public:
+ typedef typename internal::traits<Derived>::MatrixType MatrixType;
+ enum { UpLo = internal::traits<Derived>::UpLo };
+ typedef typename MatrixType::Scalar Scalar;
+ typedef typename MatrixType::RealScalar RealScalar;
+ typedef typename MatrixType::Index Index;
+ typedef SparseMatrix<Scalar,ColMajor,Index> CholMatrixType;
+ typedef Matrix<Scalar,Dynamic,1> VectorType;
+
+ public:
+
+ /** Default constructor */
+ SimplicialCholeskyBase()
+ : m_info(Success), m_isInitialized(false), m_shiftOffset(0), m_shiftScale(1)
+ {}
+
+ SimplicialCholeskyBase(const MatrixType& matrix)
+ : m_info(Success), m_isInitialized(false), m_shiftOffset(0), m_shiftScale(1)
+ {
+ derived().compute(matrix);
+ }
+
+ ~SimplicialCholeskyBase()
+ {
+ }
+
+ Derived& derived() { return *static_cast<Derived*>(this); }
+ const Derived& derived() const { return *static_cast<const Derived*>(this); }
+
+ inline Index cols() const { return m_matrix.cols(); }
+ inline Index rows() const { return m_matrix.rows(); }
+
+ /** \brief Reports whether previous computation was successful.
+ *
+ * \returns \c Success if computation was succesful,
+ * \c NumericalIssue if the matrix.appears to be negative.
+ */
+ ComputationInfo info() const
+ {
+ eigen_assert(m_isInitialized && "Decomposition is not initialized.");
+ return m_info;
+ }
+
+ /** \returns the solution x of \f$ A x = b \f$ using the current decomposition of A.
+ *
+ * \sa compute()
+ */
+ template<typename Rhs>
+ inline const internal::solve_retval<SimplicialCholeskyBase, Rhs>
+ solve(const MatrixBase<Rhs>& b) const
+ {
+ eigen_assert(m_isInitialized && "Simplicial LLT or LDLT is not initialized.");
+ eigen_assert(rows()==b.rows()
+ && "SimplicialCholeskyBase::solve(): invalid number of rows of the right hand side matrix b");
+ return internal::solve_retval<SimplicialCholeskyBase, Rhs>(*this, b.derived());
+ }
+
+ /** \returns the solution x of \f$ A x = b \f$ using the current decomposition of A.
+ *
+ * \sa compute()
+ */
+ template<typename Rhs>
+ inline const internal::sparse_solve_retval<SimplicialCholeskyBase, Rhs>
+ solve(const SparseMatrixBase<Rhs>& b) const
+ {
+ eigen_assert(m_isInitialized && "Simplicial LLT or LDLT is not initialized.");
+ eigen_assert(rows()==b.rows()
+ && "SimplicialCholesky::solve(): invalid number of rows of the right hand side matrix b");
+ return internal::sparse_solve_retval<SimplicialCholeskyBase, Rhs>(*this, b.derived());
+ }
+
+ /** \returns the permutation P
+ * \sa permutationPinv() */
+ const PermutationMatrix<Dynamic,Dynamic,Index>& permutationP() const
+ { return m_P; }
+
+ /** \returns the inverse P^-1 of the permutation P
+ * \sa permutationP() */
+ const PermutationMatrix<Dynamic,Dynamic,Index>& permutationPinv() const
+ { return m_Pinv; }
+
+ /** Sets the shift parameters that will be used to adjust the diagonal coefficients during the numerical factorization.
+ *
+ * During the numerical factorization, the diagonal coefficients are transformed by the following linear model:\n
+ * \c d_ii = \a offset + \a scale * \c d_ii
+ *
+ * The default is the identity transformation with \a offset=0, and \a scale=1.
+ *
+ * \returns a reference to \c *this.
+ */
+ Derived& setShift(const RealScalar& offset, const RealScalar& scale = 1)
+ {
+ m_shiftOffset = offset;
+ m_shiftScale = scale;
+ return derived();
+ }
+
+#ifndef EIGEN_PARSED_BY_DOXYGEN
+ /** \internal */
+ template<typename Stream>
+ void dumpMemory(Stream& s)
+ {
+ int total = 0;
+ s << " L: " << ((total+=(m_matrix.cols()+1) * sizeof(int) + m_matrix.nonZeros()*(sizeof(int)+sizeof(Scalar))) >> 20) << "Mb" << "\n";
+ s << " diag: " << ((total+=m_diag.size() * sizeof(Scalar)) >> 20) << "Mb" << "\n";
+ s << " tree: " << ((total+=m_parent.size() * sizeof(int)) >> 20) << "Mb" << "\n";
+ s << " nonzeros: " << ((total+=m_nonZerosPerCol.size() * sizeof(int)) >> 20) << "Mb" << "\n";
+ s << " perm: " << ((total+=m_P.size() * sizeof(int)) >> 20) << "Mb" << "\n";
+ s << " perm^-1: " << ((total+=m_Pinv.size() * sizeof(int)) >> 20) << "Mb" << "\n";
+ s << " TOTAL: " << (total>> 20) << "Mb" << "\n";
+ }
+
+ /** \internal */
+ template<typename Rhs,typename Dest>
+ void _solve(const MatrixBase<Rhs> &b, MatrixBase<Dest> &dest) const
+ {
+ eigen_assert(m_factorizationIsOk && "The decomposition is not in a valid state for solving, you must first call either compute() or symbolic()/numeric()");
+ eigen_assert(m_matrix.rows()==b.rows());
+
+ if(m_info!=Success)
+ return;
+
+ if(m_P.size()>0)
+ dest = m_P * b;
+ else
+ dest = b;
+
+ if(m_matrix.nonZeros()>0) // otherwise L==I
+ derived().matrixL().solveInPlace(dest);
+
+ if(m_diag.size()>0)
+ dest = m_diag.asDiagonal().inverse() * dest;
+
+ if (m_matrix.nonZeros()>0) // otherwise U==I
+ derived().matrixU().solveInPlace(dest);
+
+ if(m_P.size()>0)
+ dest = m_Pinv * dest;
+ }
+
+ /** \internal */
+ template<typename Rhs, typename DestScalar, int DestOptions, typename DestIndex>
+ void _solve_sparse(const Rhs& b, SparseMatrix<DestScalar,DestOptions,DestIndex> &dest) const
+ {
+ eigen_assert(m_factorizationIsOk && "The decomposition is not in a valid state for solving, you must first call either compute() or symbolic()/numeric()");
+ eigen_assert(m_matrix.rows()==b.rows());
+
+ // we process the sparse rhs per block of NbColsAtOnce columns temporarily stored into a dense matrix.
+ static const int NbColsAtOnce = 4;
+ int rhsCols = b.cols();
+ int size = b.rows();
+ Eigen::Matrix<DestScalar,Dynamic,Dynamic> tmp(size,rhsCols);
+ for(int k=0; k<rhsCols; k+=NbColsAtOnce)
+ {
+ int actualCols = std::min<int>(rhsCols-k, NbColsAtOnce);
+ tmp.leftCols(actualCols) = b.middleCols(k,actualCols);
+ tmp.leftCols(actualCols) = derived().solve(tmp.leftCols(actualCols));
+ dest.middleCols(k,actualCols) = tmp.leftCols(actualCols).sparseView();
+ }
+ }
+
+#endif // EIGEN_PARSED_BY_DOXYGEN
+
+ protected:
+
+ /** Computes the sparse Cholesky decomposition of \a matrix */
+ template<bool DoLDLT>
+ void compute(const MatrixType& matrix)
+ {
+ eigen_assert(matrix.rows()==matrix.cols());
+ Index size = matrix.cols();
+ CholMatrixType ap(size,size);
+ ordering(matrix, ap);
+ analyzePattern_preordered(ap, DoLDLT);
+ factorize_preordered<DoLDLT>(ap);
+ }
+
+ template<bool DoLDLT>
+ void factorize(const MatrixType& a)
+ {
+ eigen_assert(a.rows()==a.cols());
+ int size = a.cols();
+ CholMatrixType ap(size,size);
+ ap.template selfadjointView<Upper>() = a.template selfadjointView<UpLo>().twistedBy(m_P);
+ factorize_preordered<DoLDLT>(ap);
+ }
+
+ template<bool DoLDLT>
+ void factorize_preordered(const CholMatrixType& a);
+
+ void analyzePattern(const MatrixType& a, bool doLDLT)
+ {
+ eigen_assert(a.rows()==a.cols());
+ int size = a.cols();
+ CholMatrixType ap(size,size);
+ ordering(a, ap);
+ analyzePattern_preordered(ap,doLDLT);
+ }
+ void analyzePattern_preordered(const CholMatrixType& a, bool doLDLT);
+
+ void ordering(const MatrixType& a, CholMatrixType& ap);
+
+ /** keeps off-diagonal entries; drops diagonal entries */
+ struct keep_diag {
+ inline bool operator() (const Index& row, const Index& col, const Scalar&) const
+ {
+ return row!=col;
+ }
+ };
+
+ mutable ComputationInfo m_info;
+ bool m_isInitialized;
+ bool m_factorizationIsOk;
+ bool m_analysisIsOk;
+
+ CholMatrixType m_matrix;
+ VectorType m_diag; // the diagonal coefficients (LDLT mode)
+ VectorXi m_parent; // elimination tree
+ VectorXi m_nonZerosPerCol;
+ PermutationMatrix<Dynamic,Dynamic,Index> m_P; // the permutation
+ PermutationMatrix<Dynamic,Dynamic,Index> m_Pinv; // the inverse permutation
+
+ RealScalar m_shiftOffset;
+ RealScalar m_shiftScale;
+};
+
+template<typename _MatrixType, int _UpLo = Lower> class SimplicialLLT;
+template<typename _MatrixType, int _UpLo = Lower> class SimplicialLDLT;
+template<typename _MatrixType, int _UpLo = Lower> class SimplicialCholesky;
+
+namespace internal {
+
+template<typename _MatrixType, int _UpLo> struct traits<SimplicialLLT<_MatrixType,_UpLo> >
+{
+ typedef _MatrixType MatrixType;
+ enum { UpLo = _UpLo };
+ typedef typename MatrixType::Scalar Scalar;
+ typedef typename MatrixType::Index Index;
+ typedef SparseMatrix<Scalar, ColMajor, Index> CholMatrixType;
+ typedef SparseTriangularView<CholMatrixType, Eigen::Lower> MatrixL;
+ typedef SparseTriangularView<typename CholMatrixType::AdjointReturnType, Eigen::Upper> MatrixU;
+ static inline MatrixL getL(const MatrixType& m) { return m; }
+ static inline MatrixU getU(const MatrixType& m) { return m.adjoint(); }
+};
+
+template<typename _MatrixType,int _UpLo> struct traits<SimplicialLDLT<_MatrixType,_UpLo> >
+{
+ typedef _MatrixType MatrixType;
+ enum { UpLo = _UpLo };
+ typedef typename MatrixType::Scalar Scalar;
+ typedef typename MatrixType::Index Index;
+ typedef SparseMatrix<Scalar, ColMajor, Index> CholMatrixType;
+ typedef SparseTriangularView<CholMatrixType, Eigen::UnitLower> MatrixL;
+ typedef SparseTriangularView<typename CholMatrixType::AdjointReturnType, Eigen::UnitUpper> MatrixU;
+ static inline MatrixL getL(const MatrixType& m) { return m; }
+ static inline MatrixU getU(const MatrixType& m) { return m.adjoint(); }
+};
+
+template<typename _MatrixType, int _UpLo> struct traits<SimplicialCholesky<_MatrixType,_UpLo> >
+{
+ typedef _MatrixType MatrixType;
+ enum { UpLo = _UpLo };
+};
+
+}
+
+/** \ingroup SparseCholesky_Module
+ * \class SimplicialLLT
+ * \brief A direct sparse LLT Cholesky factorizations
+ *
+ * This class provides a LL^T Cholesky factorizations of sparse matrices that are
+ * selfadjoint and positive definite. The factorization allows for solving A.X = B where
+ * X and B can be either dense or sparse.
+ *
+ * In order to reduce the fill-in, a symmetric permutation P is applied prior to the factorization
+ * such that the factorized matrix is P A P^-1.
+ *
+ * \tparam _MatrixType the type of the sparse matrix A, it must be a SparseMatrix<>
+ * \tparam _UpLo the triangular part that will be used for the computations. It can be Lower
+ * or Upper. Default is Lower.
+ *
+ * \sa class SimplicialLDLT
+ */
+template<typename _MatrixType, int _UpLo>
+ class SimplicialLLT : public SimplicialCholeskyBase<SimplicialLLT<_MatrixType,_UpLo> >
+{
+public:
+ typedef _MatrixType MatrixType;
+ enum { UpLo = _UpLo };
+ typedef SimplicialCholeskyBase<SimplicialLLT> Base;
+ typedef typename MatrixType::Scalar Scalar;
+ typedef typename MatrixType::RealScalar RealScalar;
+ typedef typename MatrixType::Index Index;
+ typedef SparseMatrix<Scalar,ColMajor,Index> CholMatrixType;
+ typedef Matrix<Scalar,Dynamic,1> VectorType;
+ typedef internal::traits<SimplicialLLT> Traits;
+ typedef typename Traits::MatrixL MatrixL;
+ typedef typename Traits::MatrixU MatrixU;
+public:
+ /** Default constructor */
+ SimplicialLLT() : Base() {}
+ /** Constructs and performs the LLT factorization of \a matrix */
+ SimplicialLLT(const MatrixType& matrix)
+ : Base(matrix) {}
+
+ /** \returns an expression of the factor L */
+ inline const MatrixL matrixL() const {
+ eigen_assert(Base::m_factorizationIsOk && "Simplicial LLT not factorized");
+ return Traits::getL(Base::m_matrix);
+ }
+
+ /** \returns an expression of the factor U (= L^*) */
+ inline const MatrixU matrixU() const {
+ eigen_assert(Base::m_factorizationIsOk && "Simplicial LLT not factorized");
+ return Traits::getU(Base::m_matrix);
+ }
+
+ /** Computes the sparse Cholesky decomposition of \a matrix */
+ SimplicialLLT& compute(const MatrixType& matrix)
+ {
+ Base::template compute<false>(matrix);
+ return *this;
+ }
+
+ /** Performs a symbolic decomposition on the sparcity of \a matrix.
+ *
+ * This function is particularly useful when solving for several problems having the same structure.
+ *
+ * \sa factorize()
+ */
+ void analyzePattern(const MatrixType& a)
+ {
+ Base::analyzePattern(a, false);
+ }
+
+ /** Performs a numeric decomposition of \a matrix
+ *
+ * The given matrix must has the same sparcity than the matrix on which the symbolic decomposition has been performed.
+ *
+ * \sa analyzePattern()
+ */
+ void factorize(const MatrixType& a)
+ {
+ Base::template factorize<false>(a);
+ }
+
+ /** \returns the determinant of the underlying matrix from the current factorization */
+ Scalar determinant() const
+ {
+ Scalar detL = Base::m_matrix.diagonal().prod();
+ return internal::abs2(detL);
+ }
+};
+
+/** \ingroup SparseCholesky_Module
+ * \class SimplicialLDLT
+ * \brief A direct sparse LDLT Cholesky factorizations without square root.
+ *
+ * This class provides a LDL^T Cholesky factorizations without square root of sparse matrices that are
+ * selfadjoint and positive definite. The factorization allows for solving A.X = B where
+ * X and B can be either dense or sparse.
+ *
+ * In order to reduce the fill-in, a symmetric permutation P is applied prior to the factorization
+ * such that the factorized matrix is P A P^-1.
+ *
+ * \tparam _MatrixType the type of the sparse matrix A, it must be a SparseMatrix<>
+ * \tparam _UpLo the triangular part that will be used for the computations. It can be Lower
+ * or Upper. Default is Lower.
+ *
+ * \sa class SimplicialLLT
+ */
+template<typename _MatrixType, int _UpLo>
+ class SimplicialLDLT : public SimplicialCholeskyBase<SimplicialLDLT<_MatrixType,_UpLo> >
+{
+public:
+ typedef _MatrixType MatrixType;
+ enum { UpLo = _UpLo };
+ typedef SimplicialCholeskyBase<SimplicialLDLT> Base;
+ typedef typename MatrixType::Scalar Scalar;
+ typedef typename MatrixType::RealScalar RealScalar;
+ typedef typename MatrixType::Index Index;
+ typedef SparseMatrix<Scalar,ColMajor,Index> CholMatrixType;
+ typedef Matrix<Scalar,Dynamic,1> VectorType;
+ typedef internal::traits<SimplicialLDLT> Traits;
+ typedef typename Traits::MatrixL MatrixL;
+ typedef typename Traits::MatrixU MatrixU;
+public:
+ /** Default constructor */
+ SimplicialLDLT() : Base() {}
+
+ /** Constructs and performs the LLT factorization of \a matrix */
+ SimplicialLDLT(const MatrixType& matrix)
+ : Base(matrix) {}
+
+ /** \returns a vector expression of the diagonal D */
+ inline const VectorType vectorD() const {
+ eigen_assert(Base::m_factorizationIsOk && "Simplicial LDLT not factorized");
+ return Base::m_diag;
+ }
+ /** \returns an expression of the factor L */
+ inline const MatrixL matrixL() const {
+ eigen_assert(Base::m_factorizationIsOk && "Simplicial LDLT not factorized");
+ return Traits::getL(Base::m_matrix);
+ }
+
+ /** \returns an expression of the factor U (= L^*) */
+ inline const MatrixU matrixU() const {
+ eigen_assert(Base::m_factorizationIsOk && "Simplicial LDLT not factorized");
+ return Traits::getU(Base::m_matrix);
+ }
+
+ /** Computes the sparse Cholesky decomposition of \a matrix */
+ SimplicialLDLT& compute(const MatrixType& matrix)
+ {
+ Base::template compute<true>(matrix);
+ return *this;
+ }
+
+ /** Performs a symbolic decomposition on the sparcity of \a matrix.
+ *
+ * This function is particularly useful when solving for several problems having the same structure.
+ *
+ * \sa factorize()
+ */
+ void analyzePattern(const MatrixType& a)
+ {
+ Base::analyzePattern(a, true);
+ }
+
+ /** Performs a numeric decomposition of \a matrix
+ *
+ * The given matrix must has the same sparcity than the matrix on which the symbolic decomposition has been performed.
+ *
+ * \sa analyzePattern()
+ */
+ void factorize(const MatrixType& a)
+ {
+ Base::template factorize<true>(a);
+ }
+
+ /** \returns the determinant of the underlying matrix from the current factorization */
+ Scalar determinant() const
+ {
+ return Base::m_diag.prod();
+ }
+};
+
+/** \deprecated use SimplicialLDLT or class SimplicialLLT
+ * \ingroup SparseCholesky_Module
+ * \class SimplicialCholesky
+ *
+ * \sa class SimplicialLDLT, class SimplicialLLT
+ */
+template<typename _MatrixType, int _UpLo>
+ class SimplicialCholesky : public SimplicialCholeskyBase<SimplicialCholesky<_MatrixType,_UpLo> >
+{
+public:
+ typedef _MatrixType MatrixType;
+ enum { UpLo = _UpLo };
+ typedef SimplicialCholeskyBase<SimplicialCholesky> Base;
+ typedef typename MatrixType::Scalar Scalar;
+ typedef typename MatrixType::RealScalar RealScalar;
+ typedef typename MatrixType::Index Index;
+ typedef SparseMatrix<Scalar,ColMajor,Index> CholMatrixType;
+ typedef Matrix<Scalar,Dynamic,1> VectorType;
+ typedef internal::traits<SimplicialCholesky> Traits;
+ typedef internal::traits<SimplicialLDLT<MatrixType,UpLo> > LDLTTraits;
+ typedef internal::traits<SimplicialLLT<MatrixType,UpLo> > LLTTraits;
+ public:
+ SimplicialCholesky() : Base(), m_LDLT(true) {}
+
+ SimplicialCholesky(const MatrixType& matrix)
+ : Base(), m_LDLT(true)
+ {
+ compute(matrix);
+ }
+
+ SimplicialCholesky& setMode(SimplicialCholeskyMode mode)
+ {
+ switch(mode)
+ {
+ case SimplicialCholeskyLLT:
+ m_LDLT = false;
+ break;
+ case SimplicialCholeskyLDLT:
+ m_LDLT = true;
+ break;
+ default:
+ break;
+ }
+
+ return *this;
+ }
+
+ inline const VectorType vectorD() const {
+ eigen_assert(Base::m_factorizationIsOk && "Simplicial Cholesky not factorized");
+ return Base::m_diag;
+ }
+ inline const CholMatrixType rawMatrix() const {
+ eigen_assert(Base::m_factorizationIsOk && "Simplicial Cholesky not factorized");
+ return Base::m_matrix;
+ }
+
+ /** Computes the sparse Cholesky decomposition of \a matrix */
+ SimplicialCholesky& compute(const MatrixType& matrix)
+ {
+ if(m_LDLT)
+ Base::template compute<true>(matrix);
+ else
+ Base::template compute<false>(matrix);
+ return *this;
+ }
+
+ /** Performs a symbolic decomposition on the sparcity of \a matrix.
+ *
+ * This function is particularly useful when solving for several problems having the same structure.
+ *
+ * \sa factorize()
+ */
+ void analyzePattern(const MatrixType& a)
+ {
+ Base::analyzePattern(a, m_LDLT);
+ }
+
+ /** Performs a numeric decomposition of \a matrix
+ *
+ * The given matrix must has the same sparcity than the matrix on which the symbolic decomposition has been performed.
+ *
+ * \sa analyzePattern()
+ */
+ void factorize(const MatrixType& a)
+ {
+ if(m_LDLT)
+ Base::template factorize<true>(a);
+ else
+ Base::template factorize<false>(a);
+ }
+
+ /** \internal */
+ template<typename Rhs,typename Dest>
+ void _solve(const MatrixBase<Rhs> &b, MatrixBase<Dest> &dest) const
+ {
+ eigen_assert(Base::m_factorizationIsOk && "The decomposition is not in a valid state for solving, you must first call either compute() or symbolic()/numeric()");
+ eigen_assert(Base::m_matrix.rows()==b.rows());
+
+ if(Base::m_info!=Success)
+ return;
+
+ if(Base::m_P.size()>0)
+ dest = Base::m_P * b;
+ else
+ dest = b;
+
+ if(Base::m_matrix.nonZeros()>0) // otherwise L==I
+ {
+ if(m_LDLT)
+ LDLTTraits::getL(Base::m_matrix).solveInPlace(dest);
+ else
+ LLTTraits::getL(Base::m_matrix).solveInPlace(dest);
+ }
+
+ if(Base::m_diag.size()>0)
+ dest = Base::m_diag.asDiagonal().inverse() * dest;
+
+ if (Base::m_matrix.nonZeros()>0) // otherwise I==I
+ {
+ if(m_LDLT)
+ LDLTTraits::getU(Base::m_matrix).solveInPlace(dest);
+ else
+ LLTTraits::getU(Base::m_matrix).solveInPlace(dest);
+ }
+
+ if(Base::m_P.size()>0)
+ dest = Base::m_Pinv * dest;
+ }
+
+ Scalar determinant() const
+ {
+ if(m_LDLT)
+ {
+ return Base::m_diag.prod();
+ }
+ else
+ {
+ Scalar detL = Diagonal<const CholMatrixType>(Base::m_matrix).prod();
+ return internal::abs2(detL);
+ }
+ }
+
+ protected:
+ bool m_LDLT;
+};
+
+template<typename Derived>
+void SimplicialCholeskyBase<Derived>::ordering(const MatrixType& a, CholMatrixType& ap)
+{
+ eigen_assert(a.rows()==a.cols());
+ const Index size = a.rows();
+ // TODO allows to configure the permutation
+ // Note that amd compute the inverse permutation
+ {
+ CholMatrixType C;
+ C = a.template selfadjointView<UpLo>();
+ // remove diagonal entries:
+ // seems not to be needed
+ // C.prune(keep_diag());
+ internal::minimum_degree_ordering(C, m_Pinv);
+ }
+
+ if(m_Pinv.size()>0)
+ m_P = m_Pinv.inverse();
+ else
+ m_P.resize(0);
+
+ ap.resize(size,size);
+ ap.template selfadjointView<Upper>() = a.template selfadjointView<UpLo>().twistedBy(m_P);
+}
+
+template<typename Derived>
+void SimplicialCholeskyBase<Derived>::analyzePattern_preordered(const CholMatrixType& ap, bool doLDLT)
+{
+ const Index size = ap.rows();
+ m_matrix.resize(size, size);
+ m_parent.resize(size);
+ m_nonZerosPerCol.resize(size);
+
+ ei_declare_aligned_stack_constructed_variable(Index, tags, size, 0);
+
+ for(Index k = 0; k < size; ++k)
+ {
+ /* L(k,:) pattern: all nodes reachable in etree from nz in A(0:k-1,k) */
+ m_parent[k] = -1; /* parent of k is not yet known */
+ tags[k] = k; /* mark node k as visited */
+ m_nonZerosPerCol[k] = 0; /* count of nonzeros in column k of L */
+ for(typename CholMatrixType::InnerIterator it(ap,k); it; ++it)
+ {
+ Index i = it.index();
+ if(i < k)
+ {
+ /* follow path from i to root of etree, stop at flagged node */
+ for(; tags[i] != k; i = m_parent[i])
+ {
+ /* find parent of i if not yet determined */
+ if (m_parent[i] == -1)
+ m_parent[i] = k;
+ m_nonZerosPerCol[i]++; /* L (k,i) is nonzero */
+ tags[i] = k; /* mark i as visited */
+ }
+ }
+ }
+ }
+
+ /* construct Lp index array from m_nonZerosPerCol column counts */
+ Index* Lp = m_matrix.outerIndexPtr();
+ Lp[0] = 0;
+ for(Index k = 0; k < size; ++k)
+ Lp[k+1] = Lp[k] + m_nonZerosPerCol[k] + (doLDLT ? 0 : 1);
+
+ m_matrix.resizeNonZeros(Lp[size]);
+
+ m_isInitialized = true;
+ m_info = Success;
+ m_analysisIsOk = true;
+ m_factorizationIsOk = false;
+}
+
+
+template<typename Derived>
+template<bool DoLDLT>
+void SimplicialCholeskyBase<Derived>::factorize_preordered(const CholMatrixType& ap)
+{
+ eigen_assert(m_analysisIsOk && "You must first call analyzePattern()");
+ eigen_assert(ap.rows()==ap.cols());
+ const Index size = ap.rows();
+ eigen_assert(m_parent.size()==size);
+ eigen_assert(m_nonZerosPerCol.size()==size);
+
+ const Index* Lp = m_matrix.outerIndexPtr();
+ Index* Li = m_matrix.innerIndexPtr();
+ Scalar* Lx = m_matrix.valuePtr();
+
+ ei_declare_aligned_stack_constructed_variable(Scalar, y, size, 0);
+ ei_declare_aligned_stack_constructed_variable(Index, pattern, size, 0);
+ ei_declare_aligned_stack_constructed_variable(Index, tags, size, 0);
+
+ bool ok = true;
+ m_diag.resize(DoLDLT ? size : 0);
+
+ for(Index k = 0; k < size; ++k)
+ {
+ // compute nonzero pattern of kth row of L, in topological order
+ y[k] = 0.0; // Y(0:k) is now all zero
+ Index top = size; // stack for pattern is empty
+ tags[k] = k; // mark node k as visited
+ m_nonZerosPerCol[k] = 0; // count of nonzeros in column k of L
+ for(typename MatrixType::InnerIterator it(ap,k); it; ++it)
+ {
+ Index i = it.index();
+ if(i <= k)
+ {
+ y[i] += internal::conj(it.value()); /* scatter A(i,k) into Y (sum duplicates) */
+ Index len;
+ for(len = 0; tags[i] != k; i = m_parent[i])
+ {
+ pattern[len++] = i; /* L(k,i) is nonzero */
+ tags[i] = k; /* mark i as visited */
+ }
+ while(len > 0)
+ pattern[--top] = pattern[--len];
+ }
+ }
+
+ /* compute numerical values kth row of L (a sparse triangular solve) */
+
+ RealScalar d = internal::real(y[k]) * m_shiftScale + m_shiftOffset; // get D(k,k), apply the shift function, and clear Y(k)
+ y[k] = 0.0;
+ for(; top < size; ++top)
+ {
+ Index i = pattern[top]; /* pattern[top:n-1] is pattern of L(:,k) */
+ Scalar yi = y[i]; /* get and clear Y(i) */
+ y[i] = 0.0;
+
+ /* the nonzero entry L(k,i) */
+ Scalar l_ki;
+ if(DoLDLT)
+ l_ki = yi / m_diag[i];
+ else
+ yi = l_ki = yi / Lx[Lp[i]];
+
+ Index p2 = Lp[i] + m_nonZerosPerCol[i];
+ Index p;
+ for(p = Lp[i] + (DoLDLT ? 0 : 1); p < p2; ++p)
+ y[Li[p]] -= internal::conj(Lx[p]) * yi;
+ d -= internal::real(l_ki * internal::conj(yi));
+ Li[p] = k; /* store L(k,i) in column form of L */
+ Lx[p] = l_ki;
+ ++m_nonZerosPerCol[i]; /* increment count of nonzeros in col i */
+ }
+ if(DoLDLT)
+ {
+ m_diag[k] = d;
+ if(d == RealScalar(0))
+ {
+ ok = false; /* failure, D(k,k) is zero */
+ break;
+ }
+ }
+ else
+ {
+ Index p = Lp[k] + m_nonZerosPerCol[k]++;
+ Li[p] = k ; /* store L(k,k) = sqrt (d) in column k */
+ if(d <= RealScalar(0)) {
+ ok = false; /* failure, matrix is not positive definite */
+ break;
+ }
+ Lx[p] = internal::sqrt(d) ;
+ }
+ }
+
+ m_info = ok ? Success : NumericalIssue;
+ m_factorizationIsOk = true;
+}
+
+namespace internal {
+
+template<typename Derived, typename Rhs>
+struct solve_retval<SimplicialCholeskyBase<Derived>, Rhs>
+ : solve_retval_base<SimplicialCholeskyBase<Derived>, Rhs>
+{
+ typedef SimplicialCholeskyBase<Derived> Dec;
+ EIGEN_MAKE_SOLVE_HELPERS(Dec,Rhs)
+
+ template<typename Dest> void evalTo(Dest& dst) const
+ {
+ dec().derived()._solve(rhs(),dst);
+ }
+};
+
+template<typename Derived, typename Rhs>
+struct sparse_solve_retval<SimplicialCholeskyBase<Derived>, Rhs>
+ : sparse_solve_retval_base<SimplicialCholeskyBase<Derived>, Rhs>
+{
+ typedef SimplicialCholeskyBase<Derived> Dec;
+ EIGEN_MAKE_SPARSE_SOLVE_HELPERS(Dec,Rhs)
+
+ template<typename Dest> void evalTo(Dest& dst) const
+ {
+ dec().derived()._solve_sparse(rhs(),dst);
+ }
+};
+
+} // end namespace internal
+
+} // end namespace Eigen
+
+#endif // EIGEN_SIMPLICIAL_CHOLESKY_H
diff --git a/Eigen/src/SparseCore/AmbiVector.h b/Eigen/src/SparseCore/AmbiVector.h
new file mode 100644
index 000000000..6cfaadbaa
--- /dev/null
+++ b/Eigen/src/SparseCore/AmbiVector.h
@@ -0,0 +1,371 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra.
+//
+// Copyright (C) 2008 Gael Guennebaud <gael.guennebaud@inria.fr>
+//
+// This Source Code Form is subject to the terms of the Mozilla
+// Public License v. 2.0. If a copy of the MPL was not distributed
+// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+#ifndef EIGEN_AMBIVECTOR_H
+#define EIGEN_AMBIVECTOR_H
+
+namespace Eigen {
+
+namespace internal {
+
+/** \internal
+ * Hybrid sparse/dense vector class designed for intensive read-write operations.
+ *
+ * See BasicSparseLLT and SparseProduct for usage examples.
+ */
+template<typename _Scalar, typename _Index>
+class AmbiVector
+{
+ public:
+ typedef _Scalar Scalar;
+ typedef _Index Index;
+ typedef typename NumTraits<Scalar>::Real RealScalar;
+
+ AmbiVector(Index size)
+ : m_buffer(0), m_zero(0), m_size(0), m_allocatedSize(0), m_allocatedElements(0), m_mode(-1)
+ {
+ resize(size);
+ }
+
+ void init(double estimatedDensity);
+ void init(int mode);
+
+ Index nonZeros() const;
+
+ /** Specifies a sub-vector to work on */
+ void setBounds(Index start, Index end) { m_start = start; m_end = end; }
+
+ void setZero();
+
+ void restart();
+ Scalar& coeffRef(Index i);
+ Scalar& coeff(Index i);
+
+ class Iterator;
+
+ ~AmbiVector() { delete[] m_buffer; }
+
+ void resize(Index size)
+ {
+ if (m_allocatedSize < size)
+ reallocate(size);
+ m_size = size;
+ }
+
+ Index size() const { return m_size; }
+
+ protected:
+
+ void reallocate(Index size)
+ {
+ // if the size of the matrix is not too large, let's allocate a bit more than needed such
+ // that we can handle dense vector even in sparse mode.
+ delete[] m_buffer;
+ if (size<1000)
+ {
+ Index allocSize = (size * sizeof(ListEl))/sizeof(Scalar);
+ m_allocatedElements = (allocSize*sizeof(Scalar))/sizeof(ListEl);
+ m_buffer = new Scalar[allocSize];
+ }
+ else
+ {
+ m_allocatedElements = (size*sizeof(Scalar))/sizeof(ListEl);
+ m_buffer = new Scalar[size];
+ }
+ m_size = size;
+ m_start = 0;
+ m_end = m_size;
+ }
+
+ void reallocateSparse()
+ {
+ Index copyElements = m_allocatedElements;
+ m_allocatedElements = (std::min)(Index(m_allocatedElements*1.5),m_size);
+ Index allocSize = m_allocatedElements * sizeof(ListEl);
+ allocSize = allocSize/sizeof(Scalar) + (allocSize%sizeof(Scalar)>0?1:0);
+ Scalar* newBuffer = new Scalar[allocSize];
+ memcpy(newBuffer, m_buffer, copyElements * sizeof(ListEl));
+ delete[] m_buffer;
+ m_buffer = newBuffer;
+ }
+
+ protected:
+ // element type of the linked list
+ struct ListEl
+ {
+ Index next;
+ Index index;
+ Scalar value;
+ };
+
+ // used to store data in both mode
+ Scalar* m_buffer;
+ Scalar m_zero;
+ Index m_size;
+ Index m_start;
+ Index m_end;
+ Index m_allocatedSize;
+ Index m_allocatedElements;
+ Index m_mode;
+
+ // linked list mode
+ Index m_llStart;
+ Index m_llCurrent;
+ Index m_llSize;
+};
+
+/** \returns the number of non zeros in the current sub vector */
+template<typename _Scalar,typename _Index>
+_Index AmbiVector<_Scalar,_Index>::nonZeros() const
+{
+ if (m_mode==IsSparse)
+ return m_llSize;
+ else
+ return m_end - m_start;
+}
+
+template<typename _Scalar,typename _Index>
+void AmbiVector<_Scalar,_Index>::init(double estimatedDensity)
+{
+ if (estimatedDensity>0.1)
+ init(IsDense);
+ else
+ init(IsSparse);
+}
+
+template<typename _Scalar,typename _Index>
+void AmbiVector<_Scalar,_Index>::init(int mode)
+{
+ m_mode = mode;
+ if (m_mode==IsSparse)
+ {
+ m_llSize = 0;
+ m_llStart = -1;
+ }
+}
+
+/** Must be called whenever we might perform a write access
+ * with an index smaller than the previous one.
+ *
+ * Don't worry, this function is extremely cheap.
+ */
+template<typename _Scalar,typename _Index>
+void AmbiVector<_Scalar,_Index>::restart()
+{
+ m_llCurrent = m_llStart;
+}
+
+/** Set all coefficients of current subvector to zero */
+template<typename _Scalar,typename _Index>
+void AmbiVector<_Scalar,_Index>::setZero()
+{
+ if (m_mode==IsDense)
+ {
+ for (Index i=m_start; i<m_end; ++i)
+ m_buffer[i] = Scalar(0);
+ }
+ else
+ {
+ eigen_assert(m_mode==IsSparse);
+ m_llSize = 0;
+ m_llStart = -1;
+ }
+}
+
+template<typename _Scalar,typename _Index>
+_Scalar& AmbiVector<_Scalar,_Index>::coeffRef(_Index i)
+{
+ if (m_mode==IsDense)
+ return m_buffer[i];
+ else
+ {
+ ListEl* EIGEN_RESTRICT llElements = reinterpret_cast<ListEl*>(m_buffer);
+ // TODO factorize the following code to reduce code generation
+ eigen_assert(m_mode==IsSparse);
+ if (m_llSize==0)
+ {
+ // this is the first element
+ m_llStart = 0;
+ m_llCurrent = 0;
+ ++m_llSize;
+ llElements[0].value = Scalar(0);
+ llElements[0].index = i;
+ llElements[0].next = -1;
+ return llElements[0].value;
+ }
+ else if (i<llElements[m_llStart].index)
+ {
+ // this is going to be the new first element of the list
+ ListEl& el = llElements[m_llSize];
+ el.value = Scalar(0);
+ el.index = i;
+ el.next = m_llStart;
+ m_llStart = m_llSize;
+ ++m_llSize;
+ m_llCurrent = m_llStart;
+ return el.value;
+ }
+ else
+ {
+ Index nextel = llElements[m_llCurrent].next;
+ eigen_assert(i>=llElements[m_llCurrent].index && "you must call restart() before inserting an element with lower or equal index");
+ while (nextel >= 0 && llElements[nextel].index<=i)
+ {
+ m_llCurrent = nextel;
+ nextel = llElements[nextel].next;
+ }
+
+ if (llElements[m_llCurrent].index==i)
+ {
+ // the coefficient already exists and we found it !
+ return llElements[m_llCurrent].value;
+ }
+ else
+ {
+ if (m_llSize>=m_allocatedElements)
+ {
+ reallocateSparse();
+ llElements = reinterpret_cast<ListEl*>(m_buffer);
+ }
+ eigen_internal_assert(m_llSize<m_allocatedElements && "internal error: overflow in sparse mode");
+ // let's insert a new coefficient
+ ListEl& el = llElements[m_llSize];
+ el.value = Scalar(0);
+ el.index = i;
+ el.next = llElements[m_llCurrent].next;
+ llElements[m_llCurrent].next = m_llSize;
+ ++m_llSize;
+ return el.value;
+ }
+ }
+ }
+}
+
+template<typename _Scalar,typename _Index>
+_Scalar& AmbiVector<_Scalar,_Index>::coeff(_Index i)
+{
+ if (m_mode==IsDense)
+ return m_buffer[i];
+ else
+ {
+ ListEl* EIGEN_RESTRICT llElements = reinterpret_cast<ListEl*>(m_buffer);
+ eigen_assert(m_mode==IsSparse);
+ if ((m_llSize==0) || (i<llElements[m_llStart].index))
+ {
+ return m_zero;
+ }
+ else
+ {
+ Index elid = m_llStart;
+ while (elid >= 0 && llElements[elid].index<i)
+ elid = llElements[elid].next;
+
+ if (llElements[elid].index==i)
+ return llElements[m_llCurrent].value;
+ else
+ return m_zero;
+ }
+ }
+}
+
+/** Iterator over the nonzero coefficients */
+template<typename _Scalar,typename _Index>
+class AmbiVector<_Scalar,_Index>::Iterator
+{
+ public:
+ typedef _Scalar Scalar;
+ typedef typename NumTraits<Scalar>::Real RealScalar;
+
+ /** Default constructor
+ * \param vec the vector on which we iterate
+ * \param epsilon the minimal value used to prune zero coefficients.
+ * In practice, all coefficients having a magnitude smaller than \a epsilon
+ * are skipped.
+ */
+ Iterator(const AmbiVector& vec, RealScalar epsilon = 0)
+ : m_vector(vec)
+ {
+ m_epsilon = epsilon;
+ m_isDense = m_vector.m_mode==IsDense;
+ if (m_isDense)
+ {
+ m_currentEl = 0; // this is to avoid a compilation warning
+ m_cachedValue = 0; // this is to avoid a compilation warning
+ m_cachedIndex = m_vector.m_start-1;
+ ++(*this);
+ }
+ else
+ {
+ ListEl* EIGEN_RESTRICT llElements = reinterpret_cast<ListEl*>(m_vector.m_buffer);
+ m_currentEl = m_vector.m_llStart;
+ while (m_currentEl>=0 && internal::abs(llElements[m_currentEl].value)<=m_epsilon)
+ m_currentEl = llElements[m_currentEl].next;
+ if (m_currentEl<0)
+ {
+ m_cachedValue = 0; // this is to avoid a compilation warning
+ m_cachedIndex = -1;
+ }
+ else
+ {
+ m_cachedIndex = llElements[m_currentEl].index;
+ m_cachedValue = llElements[m_currentEl].value;
+ }
+ }
+ }
+
+ Index index() const { return m_cachedIndex; }
+ Scalar value() const { return m_cachedValue; }
+
+ operator bool() const { return m_cachedIndex>=0; }
+
+ Iterator& operator++()
+ {
+ if (m_isDense)
+ {
+ do {
+ ++m_cachedIndex;
+ } while (m_cachedIndex<m_vector.m_end && internal::abs(m_vector.m_buffer[m_cachedIndex])<m_epsilon);
+ if (m_cachedIndex<m_vector.m_end)
+ m_cachedValue = m_vector.m_buffer[m_cachedIndex];
+ else
+ m_cachedIndex=-1;
+ }
+ else
+ {
+ ListEl* EIGEN_RESTRICT llElements = reinterpret_cast<ListEl*>(m_vector.m_buffer);
+ do {
+ m_currentEl = llElements[m_currentEl].next;
+ } while (m_currentEl>=0 && internal::abs(llElements[m_currentEl].value)<m_epsilon);
+ if (m_currentEl<0)
+ {
+ m_cachedIndex = -1;
+ }
+ else
+ {
+ m_cachedIndex = llElements[m_currentEl].index;
+ m_cachedValue = llElements[m_currentEl].value;
+ }
+ }
+ return *this;
+ }
+
+ protected:
+ const AmbiVector& m_vector; // the target vector
+ Index m_currentEl; // the current element in sparse/linked-list mode
+ RealScalar m_epsilon; // epsilon used to prune zero coefficients
+ Index m_cachedIndex; // current coordinate
+ Scalar m_cachedValue; // current value
+ bool m_isDense; // mode of the vector
+};
+
+} // end namespace internal
+
+} // end namespace Eigen
+
+#endif // EIGEN_AMBIVECTOR_H
diff --git a/Eigen/src/SparseCore/CMakeLists.txt b/Eigen/src/SparseCore/CMakeLists.txt
new file mode 100644
index 000000000..d860452a6
--- /dev/null
+++ b/Eigen/src/SparseCore/CMakeLists.txt
@@ -0,0 +1,6 @@
+FILE(GLOB Eigen_SparseCore_SRCS "*.h")
+
+INSTALL(FILES
+ ${Eigen_SparseCore_SRCS}
+ DESTINATION ${INCLUDE_INSTALL_DIR}/Eigen/src/SparseCore COMPONENT Devel
+ )
diff --git a/Eigen/src/SparseCore/CompressedStorage.h b/Eigen/src/SparseCore/CompressedStorage.h
new file mode 100644
index 000000000..85a998aff
--- /dev/null
+++ b/Eigen/src/SparseCore/CompressedStorage.h
@@ -0,0 +1,233 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra.
+//
+// Copyright (C) 2008 Gael Guennebaud <gael.guennebaud@inria.fr>
+//
+// This Source Code Form is subject to the terms of the Mozilla
+// Public License v. 2.0. If a copy of the MPL was not distributed
+// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+#ifndef EIGEN_COMPRESSED_STORAGE_H
+#define EIGEN_COMPRESSED_STORAGE_H
+
+namespace Eigen {
+
+namespace internal {
+
+/** \internal
+ * Stores a sparse set of values as a list of values and a list of indices.
+ *
+ */
+template<typename _Scalar,typename _Index>
+class CompressedStorage
+{
+ public:
+
+ typedef _Scalar Scalar;
+ typedef _Index Index;
+
+ protected:
+
+ typedef typename NumTraits<Scalar>::Real RealScalar;
+
+ public:
+
+ CompressedStorage()
+ : m_values(0), m_indices(0), m_size(0), m_allocatedSize(0)
+ {}
+
+ CompressedStorage(size_t size)
+ : m_values(0), m_indices(0), m_size(0), m_allocatedSize(0)
+ {
+ resize(size);
+ }
+
+ CompressedStorage(const CompressedStorage& other)
+ : m_values(0), m_indices(0), m_size(0), m_allocatedSize(0)
+ {
+ *this = other;
+ }
+
+ CompressedStorage& operator=(const CompressedStorage& other)
+ {
+ resize(other.size());
+ memcpy(m_values, other.m_values, m_size * sizeof(Scalar));
+ memcpy(m_indices, other.m_indices, m_size * sizeof(Index));
+ return *this;
+ }
+
+ void swap(CompressedStorage& other)
+ {
+ std::swap(m_values, other.m_values);
+ std::swap(m_indices, other.m_indices);
+ std::swap(m_size, other.m_size);
+ std::swap(m_allocatedSize, other.m_allocatedSize);
+ }
+
+ ~CompressedStorage()
+ {
+ delete[] m_values;
+ delete[] m_indices;
+ }
+
+ void reserve(size_t size)
+ {
+ size_t newAllocatedSize = m_size + size;
+ if (newAllocatedSize > m_allocatedSize)
+ reallocate(newAllocatedSize);
+ }
+
+ void squeeze()
+ {
+ if (m_allocatedSize>m_size)
+ reallocate(m_size);
+ }
+
+ void resize(size_t size, float reserveSizeFactor = 0)
+ {
+ if (m_allocatedSize<size)
+ reallocate(size + size_t(reserveSizeFactor*size));
+ m_size = size;
+ }
+
+ void append(const Scalar& v, Index i)
+ {
+ Index id = static_cast<Index>(m_size);
+ resize(m_size+1, 1);
+ m_values[id] = v;
+ m_indices[id] = i;
+ }
+
+ inline size_t size() const { return m_size; }
+ inline size_t allocatedSize() const { return m_allocatedSize; }
+ inline void clear() { m_size = 0; }
+
+ inline Scalar& value(size_t i) { return m_values[i]; }
+ inline const Scalar& value(size_t i) const { return m_values[i]; }
+
+ inline Index& index(size_t i) { return m_indices[i]; }
+ inline const Index& index(size_t i) const { return m_indices[i]; }
+
+ static CompressedStorage Map(Index* indices, Scalar* values, size_t size)
+ {
+ CompressedStorage res;
+ res.m_indices = indices;
+ res.m_values = values;
+ res.m_allocatedSize = res.m_size = size;
+ return res;
+ }
+
+ /** \returns the largest \c k such that for all \c j in [0,k) index[\c j]\<\a key */
+ inline Index searchLowerIndex(Index key) const
+ {
+ return searchLowerIndex(0, m_size, key);
+ }
+
+ /** \returns the largest \c k in [start,end) such that for all \c j in [start,k) index[\c j]\<\a key */
+ inline Index searchLowerIndex(size_t start, size_t end, Index key) const
+ {
+ while(end>start)
+ {
+ size_t mid = (end+start)>>1;
+ if (m_indices[mid]<key)
+ start = mid+1;
+ else
+ end = mid;
+ }
+ return static_cast<Index>(start);
+ }
+
+ /** \returns the stored value at index \a key
+ * If the value does not exist, then the value \a defaultValue is returned without any insertion. */
+ inline Scalar at(Index key, Scalar defaultValue = Scalar(0)) const
+ {
+ if (m_size==0)
+ return defaultValue;
+ else if (key==m_indices[m_size-1])
+ return m_values[m_size-1];
+ // ^^ optimization: let's first check if it is the last coefficient
+ // (very common in high level algorithms)
+ const size_t id = searchLowerIndex(0,m_size-1,key);
+ return ((id<m_size) && (m_indices[id]==key)) ? m_values[id] : defaultValue;
+ }
+
+ /** Like at(), but the search is performed in the range [start,end) */
+ inline Scalar atInRange(size_t start, size_t end, Index key, Scalar defaultValue = Scalar(0)) const
+ {
+ if (start>=end)
+ return Scalar(0);
+ else if (end>start && key==m_indices[end-1])
+ return m_values[end-1];
+ // ^^ optimization: let's first check if it is the last coefficient
+ // (very common in high level algorithms)
+ const size_t id = searchLowerIndex(start,end-1,key);
+ return ((id<end) && (m_indices[id]==key)) ? m_values[id] : defaultValue;
+ }
+
+ /** \returns a reference to the value at index \a key
+ * If the value does not exist, then the value \a defaultValue is inserted
+ * such that the keys are sorted. */
+ inline Scalar& atWithInsertion(Index key, Scalar defaultValue = Scalar(0))
+ {
+ size_t id = searchLowerIndex(0,m_size,key);
+ if (id>=m_size || m_indices[id]!=key)
+ {
+ resize(m_size+1,1);
+ for (size_t j=m_size-1; j>id; --j)
+ {
+ m_indices[j] = m_indices[j-1];
+ m_values[j] = m_values[j-1];
+ }
+ m_indices[id] = key;
+ m_values[id] = defaultValue;
+ }
+ return m_values[id];
+ }
+
+ void prune(Scalar reference, RealScalar epsilon = NumTraits<RealScalar>::dummy_precision())
+ {
+ size_t k = 0;
+ size_t n = size();
+ for (size_t i=0; i<n; ++i)
+ {
+ if (!internal::isMuchSmallerThan(value(i), reference, epsilon))
+ {
+ value(k) = value(i);
+ index(k) = index(i);
+ ++k;
+ }
+ }
+ resize(k,0);
+ }
+
+ protected:
+
+ inline void reallocate(size_t size)
+ {
+ Scalar* newValues = new Scalar[size];
+ Index* newIndices = new Index[size];
+ size_t copySize = (std::min)(size, m_size);
+ // copy
+ internal::smart_copy(m_values, m_values+copySize, newValues);
+ internal::smart_copy(m_indices, m_indices+copySize, newIndices);
+ // delete old stuff
+ delete[] m_values;
+ delete[] m_indices;
+ m_values = newValues;
+ m_indices = newIndices;
+ m_allocatedSize = size;
+ }
+
+ protected:
+ Scalar* m_values;
+ Index* m_indices;
+ size_t m_size;
+ size_t m_allocatedSize;
+
+};
+
+} // end namespace internal
+
+} // end namespace Eigen
+
+#endif // EIGEN_COMPRESSED_STORAGE_H
diff --git a/Eigen/src/SparseCore/ConservativeSparseSparseProduct.h b/Eigen/src/SparseCore/ConservativeSparseSparseProduct.h
new file mode 100644
index 000000000..16b5e1dba
--- /dev/null
+++ b/Eigen/src/SparseCore/ConservativeSparseSparseProduct.h
@@ -0,0 +1,245 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra.
+//
+// Copyright (C) 2008-2011 Gael Guennebaud <gael.guennebaud@inria.fr>
+//
+// This Source Code Form is subject to the terms of the Mozilla
+// Public License v. 2.0. If 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<typename Lhs, typename Rhs, typename ResultType>
+static void conservative_sparse_sparse_product_impl(const Lhs& lhs, const Rhs& rhs, ResultType& res)
+{
+ typedef typename remove_all<Lhs>::type::Scalar Scalar;
+ typedef typename remove_all<Lhs>::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<bool> mask(rows,false);
+ Matrix<Scalar,Dynamic,1> values(rows);
+ Matrix<Index,Dynamic,1> 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<cols; ++j)
+ {
+
+ res.startVec(j);
+ Index nnz = 0;
+ for (typename Rhs::InnerIterator rhsIt(rhs, j); rhsIt; ++rhsIt)
+ {
+ Scalar y = rhsIt.value();
+ Index k = rhsIt.index();
+ for (typename Lhs::InnerIterator lhsIt(lhs, k); lhsIt; ++lhsIt)
+ {
+ Index i = lhsIt.index();
+ Scalar x = lhsIt.value();
+ if(!mask[i])
+ {
+ mask[i] = true;
+ values[i] = x * y;
+ indices[nnz] = i;
+ ++nnz;
+ }
+ else
+ values[i] += x * y;
+ }
+ }
+
+ // unordered insertion
+ for(int k=0; k<nnz; ++k)
+ {
+ int i = indices[k];
+ res.insertBackByOuterInnerUnordered(j,i) = values[i];
+ mask[i] = false;
+ }
+
+#if 0
+ // alternative ordered insertion code:
+
+ int t200 = rows/(log2(200)*1.39);
+ int t = (rows*100)/139;
+
+ // FIXME reserve nnz non zeros
+ // FIXME implement fast sort algorithms for very small nnz
+ // if the result is sparse enough => 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 && nnz<t200) || nnz * log2(nnz) < t)
+ //res.startVec(j);
+ if(true)
+ {
+ if(nnz>1) std::sort(indices.data(),indices.data()+nnz);
+ for(int k=0; k<nnz; ++k)
+ {
+ int i = indices[k];
+ res.insertBackByOuterInner(j,i) = values[i];
+ mask[i] = false;
+ }
+ }
+ else
+ {
+ // dense path
+ for(int i=0; i<rows; ++i)
+ {
+ if(mask[i])
+ {
+ mask[i] = false;
+ res.insertBackByOuterInner(j,i) = values[i];
+ }
+ }
+ }
+#endif
+
+ }
+ res.finalize();
+}
+
+
+} // end namespace internal
+
+namespace internal {
+
+template<typename Lhs, typename Rhs, typename ResultType,
+ int LhsStorageOrder = traits<Lhs>::Flags&RowMajorBit,
+ int RhsStorageOrder = traits<Rhs>::Flags&RowMajorBit,
+ int ResStorageOrder = traits<ResultType>::Flags&RowMajorBit>
+struct conservative_sparse_sparse_product_selector;
+
+template<typename Lhs, typename Rhs, typename ResultType>
+struct conservative_sparse_sparse_product_selector<Lhs,Rhs,ResultType,ColMajor,ColMajor,ColMajor>
+{
+ typedef typename remove_all<Lhs>::type LhsCleaned;
+ typedef typename LhsCleaned::Scalar Scalar;
+
+ static void run(const Lhs& lhs, const Rhs& rhs, ResultType& res)
+ {
+ typedef SparseMatrix<typename ResultType::Scalar,RowMajor> RowMajorMatrix;
+ typedef SparseMatrix<typename ResultType::Scalar,ColMajor> ColMajorMatrix;
+ ColMajorMatrix resCol(lhs.rows(),rhs.cols());
+ internal::conservative_sparse_sparse_product_impl<Lhs,Rhs,ColMajorMatrix>(lhs, rhs, resCol);
+ // sort the non zeros:
+ RowMajorMatrix resRow(resCol);
+ res = resRow;
+ }
+};
+
+template<typename Lhs, typename Rhs, typename ResultType>
+struct conservative_sparse_sparse_product_selector<Lhs,Rhs,ResultType,RowMajor,ColMajor,ColMajor>
+{
+ static void run(const Lhs& lhs, const Rhs& rhs, ResultType& res)
+ {
+ typedef SparseMatrix<typename ResultType::Scalar,RowMajor> RowMajorMatrix;
+ RowMajorMatrix rhsRow = rhs;
+ RowMajorMatrix resRow(lhs.rows(), rhs.cols());
+ internal::conservative_sparse_sparse_product_impl<RowMajorMatrix,Lhs,RowMajorMatrix>(rhsRow, lhs, resRow);
+ res = resRow;
+ }
+};
+
+template<typename Lhs, typename Rhs, typename ResultType>
+struct conservative_sparse_sparse_product_selector<Lhs,Rhs,ResultType,ColMajor,RowMajor,ColMajor>
+{
+ static void run(const Lhs& lhs, const Rhs& rhs, ResultType& res)
+ {
+ typedef SparseMatrix<typename ResultType::Scalar,RowMajor> RowMajorMatrix;
+ RowMajorMatrix lhsRow = lhs;
+ RowMajorMatrix resRow(lhs.rows(), rhs.cols());
+ internal::conservative_sparse_sparse_product_impl<Rhs,RowMajorMatrix,RowMajorMatrix>(rhs, lhsRow, resRow);
+ res = resRow;
+ }
+};
+
+template<typename Lhs, typename Rhs, typename ResultType>
+struct conservative_sparse_sparse_product_selector<Lhs,Rhs,ResultType,RowMajor,RowMajor,ColMajor>
+{
+ static void run(const Lhs& lhs, const Rhs& rhs, ResultType& res)
+ {
+ typedef SparseMatrix<typename ResultType::Scalar,RowMajor> RowMajorMatrix;
+ RowMajorMatrix resRow(lhs.rows(), rhs.cols());
+ internal::conservative_sparse_sparse_product_impl<Rhs,Lhs,RowMajorMatrix>(rhs, lhs, resRow);
+ res = resRow;
+ }
+};
+
+
+template<typename Lhs, typename Rhs, typename ResultType>
+struct conservative_sparse_sparse_product_selector<Lhs,Rhs,ResultType,ColMajor,ColMajor,RowMajor>
+{
+ typedef typename traits<typename remove_all<Lhs>::type>::Scalar Scalar;
+
+ static void run(const Lhs& lhs, const Rhs& rhs, ResultType& res)
+ {
+ typedef SparseMatrix<typename ResultType::Scalar,ColMajor> ColMajorMatrix;
+ ColMajorMatrix resCol(lhs.rows(), rhs.cols());
+ internal::conservative_sparse_sparse_product_impl<Lhs,Rhs,ColMajorMatrix>(lhs, rhs, resCol);
+ res = resCol;
+ }
+};
+
+template<typename Lhs, typename Rhs, typename ResultType>
+struct conservative_sparse_sparse_product_selector<Lhs,Rhs,ResultType,RowMajor,ColMajor,RowMajor>
+{
+ static void run(const Lhs& lhs, const Rhs& rhs, ResultType& res)
+ {
+ typedef SparseMatrix<typename ResultType::Scalar,ColMajor> ColMajorMatrix;
+ ColMajorMatrix lhsCol = lhs;
+ ColMajorMatrix resCol(lhs.rows(), rhs.cols());
+ internal::conservative_sparse_sparse_product_impl<ColMajorMatrix,Rhs,ColMajorMatrix>(lhsCol, rhs, resCol);
+ res = resCol;
+ }
+};
+
+template<typename Lhs, typename Rhs, typename ResultType>
+struct conservative_sparse_sparse_product_selector<Lhs,Rhs,ResultType,ColMajor,RowMajor,RowMajor>
+{
+ static void run(const Lhs& lhs, const Rhs& rhs, ResultType& res)
+ {
+ typedef SparseMatrix<typename ResultType::Scalar,ColMajor> ColMajorMatrix;
+ ColMajorMatrix rhsCol = rhs;
+ ColMajorMatrix resCol(lhs.rows(), rhs.cols());
+ internal::conservative_sparse_sparse_product_impl<Lhs,ColMajorMatrix,ColMajorMatrix>(lhs, rhsCol, resCol);
+ res = resCol;
+ }
+};
+
+template<typename Lhs, typename Rhs, typename ResultType>
+struct conservative_sparse_sparse_product_selector<Lhs,Rhs,ResultType,RowMajor,RowMajor,RowMajor>
+{
+ static void run(const Lhs& lhs, const Rhs& rhs, ResultType& res)
+ {
+ typedef SparseMatrix<typename ResultType::Scalar,RowMajor> RowMajorMatrix;
+ typedef SparseMatrix<typename ResultType::Scalar,ColMajor> ColMajorMatrix;
+ RowMajorMatrix resRow(lhs.rows(),rhs.cols());
+ internal::conservative_sparse_sparse_product_impl<Rhs,Lhs,RowMajorMatrix>(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/Eigen/src/SparseCore/CoreIterators.h b/Eigen/src/SparseCore/CoreIterators.h
new file mode 100644
index 000000000..6da4683d2
--- /dev/null
+++ b/Eigen/src/SparseCore/CoreIterators.h
@@ -0,0 +1,61 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra.
+//
+// Copyright (C) 2008-2010 Gael Guennebaud <gael.guennebaud@inria.fr>
+//
+// This Source Code Form is subject to the terms of the Mozilla
+// Public License v. 2.0. If 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<typename Derived> class DenseBase<Derived>::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/Eigen/src/SparseCore/MappedSparseMatrix.h b/Eigen/src/SparseCore/MappedSparseMatrix.h
new file mode 100644
index 000000000..93cd4832d
--- /dev/null
+++ b/Eigen/src/SparseCore/MappedSparseMatrix.h
@@ -0,0 +1,179 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra.
+//
+// Copyright (C) 2008 Gael Guennebaud <gael.guennebaud@inria.fr>
+//
+// This Source Code Form is subject to the terms of the Mozilla
+// Public License v. 2.0. If 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<typename _Scalar, int _Flags, typename _Index>
+struct traits<MappedSparseMatrix<_Scalar, _Flags, _Index> > : traits<SparseMatrix<_Scalar, _Flags, _Index> >
+{};
+}
+
+template<typename _Scalar, int _Flags, typename _Index>
+class MappedSparseMatrix
+ : public SparseMatrixBase<MappedSparseMatrix<_Scalar, _Flags, _Index> >
+{
+ public:
+ EIGEN_SPARSE_PUBLIC_INTERFACE(MappedSparseMatrix)
+ enum { IsRowMajor = Base::IsRowMajor };
+
+ protected:
+
+ Index m_outerSize;
+ Index m_innerSize;
+ Index m_nnz;
+ Index* m_outerIndex;
+ Index* m_innerIndices;
+ Scalar* m_values;
+
+ public:
+
+ inline Index rows() const { return IsRowMajor ? m_outerSize : m_innerSize; }
+ inline Index cols() const { return IsRowMajor ? m_innerSize : m_outerSize; }
+ inline Index innerSize() const { return m_innerSize; }
+ inline Index outerSize() const { return m_outerSize; }
+
+ //----------------------------------------
+ // direct access interface
+ inline const Scalar* valuePtr() const { return m_values; }
+ inline Scalar* valuePtr() { return m_values; }
+
+ inline const Index* innerIndexPtr() const { return m_innerIndices; }
+ inline Index* innerIndexPtr() { return m_innerIndices; }
+
+ inline const Index* outerIndexPtr() const { return m_outerIndex; }
+ inline Index* outerIndexPtr() { return m_outerIndex; }
+ //----------------------------------------
+
+ inline Scalar coeff(Index row, Index col) const
+ {
+ const Index outer = IsRowMajor ? row : col;
+ const Index inner = IsRowMajor ? col : row;
+
+ Index start = m_outerIndex[outer];
+ Index end = m_outerIndex[outer+1];
+ if (start==end)
+ return Scalar(0);
+ else if (end>0 && inner==m_innerIndices[end-1])
+ return m_values[end-1];
+ // ^^ optimization: let's first check if it is the last coefficient
+ // (very common in high level algorithms)
+
+ const Index* r = std::lower_bound(&m_innerIndices[start],&m_innerIndices[end-1],inner);
+ const Index id = r-&m_innerIndices[0];
+ return ((*r==inner) && (id<end)) ? m_values[id] : Scalar(0);
+ }
+
+ inline Scalar& coeffRef(Index row, Index col)
+ {
+ const Index outer = IsRowMajor ? row : col;
+ const Index inner = IsRowMajor ? col : row;
+
+ Index start = m_outerIndex[outer];
+ Index end = m_outerIndex[outer+1];
+ eigen_assert(end>=start && "you probably called coeffRef on a non finalized matrix");
+ eigen_assert(end>start && "coeffRef cannot be called on a zero coefficient");
+ Index* r = std::lower_bound(&m_innerIndices[start],&m_innerIndices[end],inner);
+ const Index id = r-&m_innerIndices[0];
+ eigen_assert((*r==inner) && (id<end) && "coeffRef cannot be called on a zero coefficient");
+ return m_values[id];
+ }
+
+ class InnerIterator;
+ class ReverseInnerIterator;
+
+ /** \returns the number of non zero coefficients */
+ inline Index nonZeros() const { return m_nnz; }
+
+ inline MappedSparseMatrix(Index rows, Index cols, Index nnz, Index* outerIndexPtr, Index* innerIndexPtr, Scalar* valuePtr)
+ : m_outerSize(IsRowMajor?rows:cols), m_innerSize(IsRowMajor?cols:rows), m_nnz(nnz), m_outerIndex(outerIndexPtr),
+ m_innerIndices(innerIndexPtr), m_values(valuePtr)
+ {}
+
+ /** Empty destructor */
+ inline ~MappedSparseMatrix() {}
+};
+
+template<typename Scalar, int _Flags, typename _Index>
+class MappedSparseMatrix<Scalar,_Flags,_Index>::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<Scalar&>(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<typename Scalar, int _Flags, typename _Index>
+class MappedSparseMatrix<Scalar,_Flags,_Index>::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<Scalar&>(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/Eigen/src/SparseCore/SparseAssign.h b/Eigen/src/SparseCore/SparseAssign.h
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/Eigen/src/SparseCore/SparseAssign.h
diff --git a/Eigen/src/SparseCore/SparseBlock.h b/Eigen/src/SparseCore/SparseBlock.h
new file mode 100644
index 000000000..eefd80702
--- /dev/null
+++ b/Eigen/src/SparseCore/SparseBlock.h
@@ -0,0 +1,387 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra.
+//
+// Copyright (C) 2008-2009 Gael Guennebaud <gael.guennebaud@inria.fr>
+//
+// This Source Code Form is subject to the terms of the Mozilla
+// Public License v. 2.0. If a copy of the MPL was not distributed
+// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+#ifndef EIGEN_SPARSE_BLOCK_H
+#define EIGEN_SPARSE_BLOCK_H
+
+namespace Eigen {
+
+namespace internal {
+template<typename MatrixType, int Size>
+struct traits<SparseInnerVectorSet<MatrixType, Size> >
+{
+ typedef typename traits<MatrixType>::Scalar Scalar;
+ typedef typename traits<MatrixType>::Index Index;
+ typedef typename traits<MatrixType>::StorageKind StorageKind;
+ typedef MatrixXpr XprKind;
+ enum {
+ IsRowMajor = (int(MatrixType::Flags)&RowMajorBit)==RowMajorBit,
+ Flags = MatrixType::Flags,
+ RowsAtCompileTime = IsRowMajor ? Size : MatrixType::RowsAtCompileTime,
+ ColsAtCompileTime = IsRowMajor ? MatrixType::ColsAtCompileTime : Size,
+ MaxRowsAtCompileTime = RowsAtCompileTime,
+ MaxColsAtCompileTime = ColsAtCompileTime,
+ CoeffReadCost = MatrixType::CoeffReadCost
+ };
+};
+} // end namespace internal
+
+template<typename MatrixType, int Size>
+class SparseInnerVectorSet : internal::no_assignment_operator,
+ public SparseMatrixBase<SparseInnerVectorSet<MatrixType, Size> >
+{
+ public:
+
+ enum { IsRowMajor = internal::traits<SparseInnerVectorSet>::IsRowMajor };
+
+ EIGEN_SPARSE_PUBLIC_INTERFACE(SparseInnerVectorSet)
+ class InnerIterator: public MatrixType::InnerIterator
+ {
+ public:
+ inline InnerIterator(const SparseInnerVectorSet& xpr, Index outer)
+ : MatrixType::InnerIterator(xpr.m_matrix, xpr.m_outerStart + outer), m_outer(outer)
+ {}
+ inline Index row() const { return IsRowMajor ? m_outer : this->index(); }
+ inline Index col() const { return IsRowMajor ? this->index() : m_outer; }
+ protected:
+ Index m_outer;
+ };
+ class ReverseInnerIterator: public MatrixType::ReverseInnerIterator
+ {
+ public:
+ inline ReverseInnerIterator(const SparseInnerVectorSet& xpr, Index outer)
+ : MatrixType::ReverseInnerIterator(xpr.m_matrix, xpr.m_outerStart + outer), m_outer(outer)
+ {}
+ inline Index row() const { return IsRowMajor ? m_outer : this->index(); }
+ inline Index col() const { return IsRowMajor ? this->index() : m_outer; }
+ protected:
+ Index m_outer;
+ };
+
+ inline SparseInnerVectorSet(const MatrixType& matrix, Index outerStart, Index outerSize)
+ : m_matrix(matrix), m_outerStart(outerStart), m_outerSize(outerSize)
+ {
+ eigen_assert( (outerStart>=0) && ((outerStart+outerSize)<=matrix.outerSize()) );
+ }
+
+ inline SparseInnerVectorSet(const MatrixType& matrix, Index outer)
+ : m_matrix(matrix), m_outerStart(outer), m_outerSize(Size)
+ {
+ eigen_assert(Size!=Dynamic);
+ eigen_assert( (outer>=0) && (outer<matrix.outerSize()) );
+ }
+
+// template<typename OtherDerived>
+// inline SparseInnerVectorSet& operator=(const SparseMatrixBase<OtherDerived>& other)
+// {
+// return *this;
+// }
+
+// template<typename Sparse>
+// inline SparseInnerVectorSet& operator=(const SparseMatrixBase<OtherDerived>& other)
+// {
+// return *this;
+// }
+
+ EIGEN_STRONG_INLINE Index rows() const { return IsRowMajor ? m_outerSize.value() : m_matrix.rows(); }
+ EIGEN_STRONG_INLINE Index cols() const { return IsRowMajor ? m_matrix.cols() : m_outerSize.value(); }
+
+ protected:
+
+ const typename MatrixType::Nested m_matrix;
+ Index m_outerStart;
+ const internal::variable_if_dynamic<Index, Size> m_outerSize;
+};
+
+
+/***************************************************************************
+* specialisation for SparseMatrix
+***************************************************************************/
+
+template<typename _Scalar, int _Options, typename _Index, int Size>
+class SparseInnerVectorSet<SparseMatrix<_Scalar, _Options, _Index>, Size>
+ : public SparseMatrixBase<SparseInnerVectorSet<SparseMatrix<_Scalar, _Options, _Index>, Size> >
+{
+ typedef SparseMatrix<_Scalar, _Options, _Index> MatrixType;
+ public:
+
+ enum { IsRowMajor = internal::traits<SparseInnerVectorSet>::IsRowMajor };
+
+ EIGEN_SPARSE_PUBLIC_INTERFACE(SparseInnerVectorSet)
+ class InnerIterator: public MatrixType::InnerIterator
+ {
+ public:
+ inline InnerIterator(const SparseInnerVectorSet& xpr, Index outer)
+ : MatrixType::InnerIterator(xpr.m_matrix, xpr.m_outerStart + outer), m_outer(outer)
+ {}
+ inline Index row() const { return IsRowMajor ? m_outer : this->index(); }
+ inline Index col() const { return IsRowMajor ? this->index() : m_outer; }
+ protected:
+ Index m_outer;
+ };
+ class ReverseInnerIterator: public MatrixType::ReverseInnerIterator
+ {
+ public:
+ inline ReverseInnerIterator(const SparseInnerVectorSet& xpr, Index outer)
+ : MatrixType::ReverseInnerIterator(xpr.m_matrix, xpr.m_outerStart + outer), m_outer(outer)
+ {}
+ inline Index row() const { return IsRowMajor ? m_outer : this->index(); }
+ inline Index col() const { return IsRowMajor ? this->index() : m_outer; }
+ protected:
+ Index m_outer;
+ };
+
+ inline SparseInnerVectorSet(const MatrixType& matrix, Index outerStart, Index outerSize)
+ : m_matrix(matrix), m_outerStart(outerStart), m_outerSize(outerSize)
+ {
+ eigen_assert( (outerStart>=0) && ((outerStart+outerSize)<=matrix.outerSize()) );
+ }
+
+ inline SparseInnerVectorSet(const MatrixType& matrix, Index outer)
+ : m_matrix(matrix), m_outerStart(outer), m_outerSize(Size)
+ {
+ eigen_assert(Size==1);
+ eigen_assert( (outer>=0) && (outer<matrix.outerSize()) );
+ }
+
+ template<typename OtherDerived>
+ inline SparseInnerVectorSet& operator=(const SparseMatrixBase<OtherDerived>& other)
+ {
+ typedef typename internal::remove_all<typename MatrixType::Nested>::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<Scalar, IsRowMajor ? RowMajor : ColMajor, Index> tmp(other);
+
+ // 2 - let's check whether there is enough allocated memory
+ Index nnz = tmp.nonZeros();
+ Index nnz_previous = nonZeros();
+ Index free_size = Index(matrix.data().allocatedSize()) + nnz_previous;
+ Index nnz_head = m_outerStart==0 ? 0 : matrix.outerIndexPtr()[m_outerStart];
+ Index tail = m_matrix.outerIndexPtr()[m_outerStart+m_outerSize.value()];
+ Index nnz_tail = matrix.nonZeros() - tail;
+
+ if(nnz>free_size)
+ {
+ // realloc manually to reduce copies
+ typename MatrixType::Storage newdata(m_matrix.nonZeros() - nnz_previous + nnz);
+
+ std::memcpy(&newdata.value(0), &m_matrix.data().value(0), nnz_head*sizeof(Scalar));
+ std::memcpy(&newdata.index(0), &m_matrix.data().index(0), nnz_head*sizeof(Index));
+
+ std::memcpy(&newdata.value(nnz_head), &tmp.data().value(0), nnz*sizeof(Scalar));
+ std::memcpy(&newdata.index(nnz_head), &tmp.data().index(0), nnz*sizeof(Index));
+
+ std::memcpy(&newdata.value(nnz_head+nnz), &matrix.data().value(tail), nnz_tail*sizeof(Scalar));
+ std::memcpy(&newdata.index(nnz_head+nnz), &matrix.data().index(tail), nnz_tail*sizeof(Index));
+
+ matrix.data().swap(newdata);
+ }
+ else
+ {
+ // no need to realloc, simply copy the tail at its respective position and insert tmp
+ matrix.data().resize(nnz_head + nnz + nnz_tail);
+
+ if(nnz<nnz_previous)
+ {
+ std::memcpy(&matrix.data().value(nnz_head+nnz), &matrix.data().value(tail), nnz_tail*sizeof(Scalar));
+ std::memcpy(&matrix.data().index(nnz_head+nnz), &matrix.data().index(tail), nnz_tail*sizeof(Index));
+ }
+ else
+ {
+ for(Index i=nnz_tail-1; i>=0; --i)
+ {
+ matrix.data().value(nnz_head+nnz+i) = matrix.data().value(tail+i);
+ matrix.data().index(nnz_head+nnz+i) = matrix.data().index(tail+i);
+ }
+ }
+
+ std::memcpy(&matrix.data().value(nnz_head), &tmp.data().value(0), nnz*sizeof(Scalar));
+ std::memcpy(&matrix.data().index(nnz_head), &tmp.data().index(0), nnz*sizeof(Index));
+ }
+
+ // update outer index pointers
+ Index p = nnz_head;
+ for(Index k=0; k<m_outerSize.value(); ++k)
+ {
+ matrix.outerIndexPtr()[m_outerStart+k] = p;
+ p += tmp.innerVector(k).nonZeros();
+ }
+ std::ptrdiff_t offset = nnz - nnz_previous;
+ for(Index k = m_outerStart + m_outerSize.value(); k<=matrix.outerSize(); ++k)
+ {
+ matrix.outerIndexPtr()[k] += offset;
+ }
+
+ return *this;
+ }
+
+ inline SparseInnerVectorSet& operator=(const SparseInnerVectorSet& other)
+ {
+ return operator=<SparseInnerVectorSet>(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<const Matrix<Index,Size,1> >(m_matrix.innerNonZeroPtr()+m_outerStart, m_outerSize.value()).sum();
+ }
+
+ const Scalar& lastCoeff() const
+ {
+ EIGEN_STATIC_ASSERT_VECTOR_ONLY(SparseInnerVectorSet);
+ eigen_assert(nonZeros()>0);
+ if(m_matrix.isCompressed())
+ return m_matrix.valuePtr()[m_matrix.outerIndexPtr()[m_outerStart+1]-1];
+ else
+ return m_matrix.valuePtr()[m_matrix.outerIndexPtr()[m_outerStart]+m_matrix.innerNonZeroPtr()[m_outerStart]-1];
+ }
+
+// template<typename Sparse>
+// inline SparseInnerVectorSet& operator=(const SparseMatrixBase<OtherDerived>& other)
+// {
+// return *this;
+// }
+
+ EIGEN_STRONG_INLINE Index rows() const { return IsRowMajor ? m_outerSize.value() : m_matrix.rows(); }
+ EIGEN_STRONG_INLINE Index cols() const { return IsRowMajor ? m_matrix.cols() : m_outerSize.value(); }
+
+ protected:
+
+ typename MatrixType::Nested m_matrix;
+ Index m_outerStart;
+ const internal::variable_if_dynamic<Index, Size> m_outerSize;
+
+};
+
+//----------
+
+/** \returns the i-th row of the matrix \c *this. For row-major matrix only. */
+template<typename Derived>
+SparseInnerVectorSet<Derived,1> SparseMatrixBase<Derived>::row(Index i)
+{
+ EIGEN_STATIC_ASSERT(IsRowMajor,THIS_METHOD_IS_ONLY_FOR_ROW_MAJOR_MATRICES);
+ return innerVector(i);
+}
+
+/** \returns the i-th row of the matrix \c *this. For row-major matrix only.
+ * (read-only version) */
+template<typename Derived>
+const SparseInnerVectorSet<Derived,1> SparseMatrixBase<Derived>::row(Index i) const
+{
+ EIGEN_STATIC_ASSERT(IsRowMajor,THIS_METHOD_IS_ONLY_FOR_ROW_MAJOR_MATRICES);
+ return innerVector(i);
+}
+
+/** \returns the i-th column of the matrix \c *this. For column-major matrix only. */
+template<typename Derived>
+SparseInnerVectorSet<Derived,1> SparseMatrixBase<Derived>::col(Index i)
+{
+ EIGEN_STATIC_ASSERT(!IsRowMajor,THIS_METHOD_IS_ONLY_FOR_COLUMN_MAJOR_MATRICES);
+ return innerVector(i);
+}
+
+/** \returns the i-th column of the matrix \c *this. For column-major matrix only.
+ * (read-only version) */
+template<typename Derived>
+const SparseInnerVectorSet<Derived,1> SparseMatrixBase<Derived>::col(Index i) const
+{
+ EIGEN_STATIC_ASSERT(!IsRowMajor,THIS_METHOD_IS_ONLY_FOR_COLUMN_MAJOR_MATRICES);
+ return innerVector(i);
+}
+
+/** \returns the \a outer -th column (resp. row) of the matrix \c *this if \c *this
+ * is col-major (resp. row-major).
+ */
+template<typename Derived>
+SparseInnerVectorSet<Derived,1> SparseMatrixBase<Derived>::innerVector(Index outer)
+{ return SparseInnerVectorSet<Derived,1>(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<typename Derived>
+const SparseInnerVectorSet<Derived,1> SparseMatrixBase<Derived>::innerVector(Index outer) const
+{ return SparseInnerVectorSet<Derived,1>(derived(), outer); }
+
+/** \returns the i-th row of the matrix \c *this. For row-major matrix only. */
+template<typename Derived>
+SparseInnerVectorSet<Derived,Dynamic> SparseMatrixBase<Derived>::middleRows(Index start, Index size)
+{
+ EIGEN_STATIC_ASSERT(IsRowMajor,THIS_METHOD_IS_ONLY_FOR_ROW_MAJOR_MATRICES);
+ return innerVectors(start, size);
+}
+
+/** \returns the i-th row of the matrix \c *this. For row-major matrix only.
+ * (read-only version) */
+template<typename Derived>
+const SparseInnerVectorSet<Derived,Dynamic> SparseMatrixBase<Derived>::middleRows(Index start, Index size) const
+{
+ EIGEN_STATIC_ASSERT(IsRowMajor,THIS_METHOD_IS_ONLY_FOR_ROW_MAJOR_MATRICES);
+ return innerVectors(start, size);
+}
+
+/** \returns the i-th column of the matrix \c *this. For column-major matrix only. */
+template<typename Derived>
+SparseInnerVectorSet<Derived,Dynamic> SparseMatrixBase<Derived>::middleCols(Index start, Index size)
+{
+ EIGEN_STATIC_ASSERT(!IsRowMajor,THIS_METHOD_IS_ONLY_FOR_COLUMN_MAJOR_MATRICES);
+ return innerVectors(start, size);
+}
+
+/** \returns the i-th column of the matrix \c *this. For column-major matrix only.
+ * (read-only version) */
+template<typename Derived>
+const SparseInnerVectorSet<Derived,Dynamic> SparseMatrixBase<Derived>::middleCols(Index start, Index size) const
+{
+ EIGEN_STATIC_ASSERT(!IsRowMajor,THIS_METHOD_IS_ONLY_FOR_COLUMN_MAJOR_MATRICES);
+ return innerVectors(start, size);
+}
+
+
+
+/** \returns the \a outer -th column (resp. row) of the matrix \c *this if \c *this
+ * is col-major (resp. row-major).
+ */
+template<typename Derived>
+SparseInnerVectorSet<Derived,Dynamic> SparseMatrixBase<Derived>::innerVectors(Index outerStart, Index outerSize)
+{ return SparseInnerVectorSet<Derived,Dynamic>(derived(), outerStart, outerSize); }
+
+/** \returns the \a outer -th column (resp. row) of the matrix \c *this if \c *this
+ * is col-major (resp. row-major). Read-only.
+ */
+template<typename Derived>
+const SparseInnerVectorSet<Derived,Dynamic> SparseMatrixBase<Derived>::innerVectors(Index outerStart, Index outerSize) const
+{ return SparseInnerVectorSet<Derived,Dynamic>(derived(), outerStart, outerSize); }
+
+} // end namespace Eigen
+
+#endif // EIGEN_SPARSE_BLOCK_H
diff --git a/Eigen/src/SparseCore/SparseCwiseBinaryOp.h b/Eigen/src/SparseCore/SparseCwiseBinaryOp.h
new file mode 100644
index 000000000..d5f97f78f
--- /dev/null
+++ b/Eigen/src/SparseCore/SparseCwiseBinaryOp.h
@@ -0,0 +1,324 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra.
+//
+// Copyright (C) 2008 Gael Guennebaud <gael.guennebaud@inria.fr>
+//
+// This Source Code Form is subject to the terms of the Mozilla
+// Public License v. 2.0. If 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<Dense,Sparse>
+{ typedef Sparse ret; };
+
+template<> struct promote_storage_type<Sparse,Dense>
+{ typedef Sparse ret; };
+
+template<typename BinaryOp, typename Lhs, typename Rhs, typename Derived,
+ typename _LhsStorageMode = typename traits<Lhs>::StorageKind,
+ typename _RhsStorageMode = typename traits<Rhs>::StorageKind>
+class sparse_cwise_binary_op_inner_iterator_selector;
+
+} // end namespace internal
+
+template<typename BinaryOp, typename Lhs, typename Rhs>
+class CwiseBinaryOpImpl<BinaryOp, Lhs, Rhs, Sparse>
+ : public SparseMatrixBase<CwiseBinaryOp<BinaryOp, Lhs, Rhs> >
+{
+ public:
+ class InnerIterator;
+ class ReverseInnerIterator;
+ typedef CwiseBinaryOp<BinaryOp, Lhs, Rhs> Derived;
+ EIGEN_SPARSE_PUBLIC_INTERFACE(Derived)
+ CwiseBinaryOpImpl()
+ {
+ typedef typename internal::traits<Lhs>::StorageKind LhsStorageKind;
+ typedef typename internal::traits<Rhs>::StorageKind RhsStorageKind;
+ EIGEN_STATIC_ASSERT((
+ (!internal::is_same<LhsStorageKind,RhsStorageKind>::value)
+ || ((Lhs::Flags&RowMajorBit) == (Rhs::Flags&RowMajorBit))),
+ THE_STORAGE_ORDER_OF_BOTH_SIDES_MUST_MATCH);
+ }
+};
+
+template<typename BinaryOp, typename Lhs, typename Rhs>
+class CwiseBinaryOpImpl<BinaryOp,Lhs,Rhs,Sparse>::InnerIterator
+ : public internal::sparse_cwise_binary_op_inner_iterator_selector<BinaryOp,Lhs,Rhs,typename CwiseBinaryOpImpl<BinaryOp,Lhs,Rhs,Sparse>::InnerIterator>
+{
+ public:
+ typedef typename Lhs::Index Index;
+ typedef internal::sparse_cwise_binary_op_inner_iterator_selector<
+ BinaryOp,Lhs,Rhs, InnerIterator> Base;
+
+ EIGEN_STRONG_INLINE InnerIterator(const CwiseBinaryOpImpl& binOp, typename CwiseBinaryOpImpl::Index outer)
+ : Base(binOp.derived(),outer)
+ {}
+};
+
+/***************************************************************************
+* Implementation of inner-iterators
+***************************************************************************/
+
+// template<typename T> struct internal::func_is_conjunction { enum { ret = false }; };
+// template<typename T> struct internal::func_is_conjunction<internal::scalar_product_op<T> > { enum { ret = true }; };
+
+// TODO generalize the internal::scalar_product_op specialization to all conjunctions if any !
+
+namespace internal {
+
+// sparse - sparse (generic)
+template<typename BinaryOp, typename Lhs, typename Rhs, typename Derived>
+class sparse_cwise_binary_op_inner_iterator_selector<BinaryOp, Lhs, Rhs, Derived, Sparse, Sparse>
+{
+ typedef CwiseBinaryOp<BinaryOp, Lhs, Rhs> CwiseBinaryXpr;
+ typedef typename traits<CwiseBinaryXpr>::Scalar Scalar;
+ typedef typename traits<CwiseBinaryXpr>::_LhsNested _LhsNested;
+ typedef typename traits<CwiseBinaryXpr>::_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<Derived*>(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<typename T, typename Lhs, typename Rhs, typename Derived>
+class sparse_cwise_binary_op_inner_iterator_selector<scalar_product_op<T>, Lhs, Rhs, Derived, Sparse, Sparse>
+{
+ typedef scalar_product_op<T> BinaryFunc;
+ typedef CwiseBinaryOp<BinaryFunc, Lhs, Rhs> CwiseBinaryXpr;
+ typedef typename CwiseBinaryXpr::Scalar Scalar;
+ typedef typename traits<CwiseBinaryXpr>::_LhsNested _LhsNested;
+ typedef typename _LhsNested::InnerIterator LhsIterator;
+ typedef typename traits<CwiseBinaryXpr>::_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<Derived*>(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<typename T, typename Lhs, typename Rhs, typename Derived>
+class sparse_cwise_binary_op_inner_iterator_selector<scalar_product_op<T>, Lhs, Rhs, Derived, Sparse, Dense>
+{
+ typedef scalar_product_op<T> BinaryFunc;
+ typedef CwiseBinaryOp<BinaryFunc, Lhs, Rhs> CwiseBinaryXpr;
+ typedef typename CwiseBinaryXpr::Scalar Scalar;
+ typedef typename traits<CwiseBinaryXpr>::_LhsNested _LhsNested;
+ typedef typename traits<CwiseBinaryXpr>::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<Derived*>(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<typename T, typename Lhs, typename Rhs, typename Derived>
+class sparse_cwise_binary_op_inner_iterator_selector<scalar_product_op<T>, Lhs, Rhs, Derived, Dense, Sparse>
+{
+ typedef scalar_product_op<T> BinaryFunc;
+ typedef CwiseBinaryOp<BinaryFunc, Lhs, Rhs> CwiseBinaryXpr;
+ typedef typename CwiseBinaryXpr::Scalar Scalar;
+ typedef typename traits<CwiseBinaryXpr>::_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<Derived*>(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<typename Derived>
+template<typename OtherDerived>
+EIGEN_STRONG_INLINE Derived &
+SparseMatrixBase<Derived>::operator-=(const SparseMatrixBase<OtherDerived> &other)
+{
+ return *this = derived() - other.derived();
+}
+
+template<typename Derived>
+template<typename OtherDerived>
+EIGEN_STRONG_INLINE Derived &
+SparseMatrixBase<Derived>::operator+=(const SparseMatrixBase<OtherDerived>& other)
+{
+ return *this = derived() + other.derived();
+}
+
+template<typename Derived>
+template<typename OtherDerived>
+EIGEN_STRONG_INLINE const EIGEN_SPARSE_CWISE_PRODUCT_RETURN_TYPE
+SparseMatrixBase<Derived>::cwiseProduct(const MatrixBase<OtherDerived> &other) const
+{
+ return EIGEN_SPARSE_CWISE_PRODUCT_RETURN_TYPE(derived(), other.derived());
+}
+
+} // end namespace Eigen
+
+#endif // EIGEN_SPARSE_CWISE_BINARY_OP_H
diff --git a/Eigen/src/SparseCore/SparseCwiseUnaryOp.h b/Eigen/src/SparseCore/SparseCwiseUnaryOp.h
new file mode 100644
index 000000000..5a50c7803
--- /dev/null
+++ b/Eigen/src/SparseCore/SparseCwiseUnaryOp.h
@@ -0,0 +1,163 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra.
+//
+// Copyright (C) 2008-2010 Gael Guennebaud <gael.guennebaud@inria.fr>
+//
+// This Source Code Form is subject to the terms of the Mozilla
+// Public License v. 2.0. If 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<typename UnaryOp, typename MatrixType>
+class CwiseUnaryOpImpl<UnaryOp,MatrixType,Sparse>
+ : public SparseMatrixBase<CwiseUnaryOp<UnaryOp, MatrixType> >
+{
+ public:
+
+ class InnerIterator;
+ class ReverseInnerIterator;
+
+ typedef CwiseUnaryOp<UnaryOp, MatrixType> Derived;
+ EIGEN_SPARSE_PUBLIC_INTERFACE(Derived)
+
+ protected:
+ typedef typename internal::traits<Derived>::_XprTypeNested _MatrixTypeNested;
+ typedef typename _MatrixTypeNested::InnerIterator MatrixTypeIterator;
+ typedef typename _MatrixTypeNested::ReverseInnerIterator MatrixTypeReverseIterator;
+};
+
+template<typename UnaryOp, typename MatrixType>
+class CwiseUnaryOpImpl<UnaryOp,MatrixType,Sparse>::InnerIterator
+ : public CwiseUnaryOpImpl<UnaryOp,MatrixType,Sparse>::MatrixTypeIterator
+{
+ typedef typename CwiseUnaryOpImpl::Scalar Scalar;
+ typedef typename CwiseUnaryOpImpl<UnaryOp,MatrixType,Sparse>::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<typename UnaryOp, typename MatrixType>
+class CwiseUnaryOpImpl<UnaryOp,MatrixType,Sparse>::ReverseInnerIterator
+ : public CwiseUnaryOpImpl<UnaryOp,MatrixType,Sparse>::MatrixTypeReverseIterator
+{
+ typedef typename CwiseUnaryOpImpl::Scalar Scalar;
+ typedef typename CwiseUnaryOpImpl<UnaryOp,MatrixType,Sparse>::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<typename ViewOp, typename MatrixType>
+class CwiseUnaryViewImpl<ViewOp,MatrixType,Sparse>
+ : public SparseMatrixBase<CwiseUnaryView<ViewOp, MatrixType> >
+{
+ public:
+
+ class InnerIterator;
+ class ReverseInnerIterator;
+
+ typedef CwiseUnaryView<ViewOp, MatrixType> Derived;
+ EIGEN_SPARSE_PUBLIC_INTERFACE(Derived)
+
+ protected:
+ typedef typename internal::traits<Derived>::_MatrixTypeNested _MatrixTypeNested;
+ typedef typename _MatrixTypeNested::InnerIterator MatrixTypeIterator;
+ typedef typename _MatrixTypeNested::ReverseInnerIterator MatrixTypeReverseIterator;
+};
+
+template<typename ViewOp, typename MatrixType>
+class CwiseUnaryViewImpl<ViewOp,MatrixType,Sparse>::InnerIterator
+ : public CwiseUnaryViewImpl<ViewOp,MatrixType,Sparse>::MatrixTypeIterator
+{
+ typedef typename CwiseUnaryViewImpl::Scalar Scalar;
+ typedef typename CwiseUnaryViewImpl<ViewOp,MatrixType,Sparse>::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<typename ViewOp, typename MatrixType>
+class CwiseUnaryViewImpl<ViewOp,MatrixType,Sparse>::ReverseInnerIterator
+ : public CwiseUnaryViewImpl<ViewOp,MatrixType,Sparse>::MatrixTypeReverseIterator
+{
+ typedef typename CwiseUnaryViewImpl::Scalar Scalar;
+ typedef typename CwiseUnaryViewImpl<ViewOp,MatrixType,Sparse>::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<typename Derived>
+EIGEN_STRONG_INLINE Derived&
+SparseMatrixBase<Derived>::operator*=(const Scalar& other)
+{
+ for (Index j=0; j<outerSize(); ++j)
+ for (typename Derived::InnerIterator i(derived(),j); i; ++i)
+ i.valueRef() *= other;
+ return derived();
+}
+
+template<typename Derived>
+EIGEN_STRONG_INLINE Derived&
+SparseMatrixBase<Derived>::operator/=(const Scalar& other)
+{
+ for (Index j=0; j<outerSize(); ++j)
+ for (typename Derived::InnerIterator i(derived(),j); i; ++i)
+ i.valueRef() /= other;
+ return derived();
+}
+
+} // end namespace Eigen
+
+#endif // EIGEN_SPARSE_CWISE_UNARY_OP_H
diff --git a/Eigen/src/SparseCore/SparseDenseProduct.h b/Eigen/src/SparseCore/SparseDenseProduct.h
new file mode 100644
index 000000000..6f32940d6
--- /dev/null
+++ b/Eigen/src/SparseCore/SparseDenseProduct.h
@@ -0,0 +1,300 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra.
+//
+// Copyright (C) 2008-2010 Gael Guennebaud <gael.guennebaud@inria.fr>
+//
+// This Source Code Form is subject to the terms of the Mozilla
+// Public License v. 2.0. If 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<typename Lhs, typename Rhs, int InnerSize> struct SparseDenseProductReturnType
+{
+ typedef SparseTimeDenseProduct<Lhs,Rhs> Type;
+};
+
+template<typename Lhs, typename Rhs> struct SparseDenseProductReturnType<Lhs,Rhs,1>
+{
+ typedef SparseDenseOuterProduct<Lhs,Rhs,false> Type;
+};
+
+template<typename Lhs, typename Rhs, int InnerSize> struct DenseSparseProductReturnType
+{
+ typedef DenseTimeSparseProduct<Lhs,Rhs> Type;
+};
+
+template<typename Lhs, typename Rhs> struct DenseSparseProductReturnType<Lhs,Rhs,1>
+{
+ typedef SparseDenseOuterProduct<Rhs,Lhs,true> Type;
+};
+
+namespace internal {
+
+template<typename Lhs, typename Rhs, bool Tr>
+struct traits<SparseDenseOuterProduct<Lhs,Rhs,Tr> >
+{
+ typedef Sparse StorageKind;
+ typedef typename scalar_product_traits<typename traits<Lhs>::Scalar,
+ typename traits<Rhs>::Scalar>::ReturnType Scalar;
+ typedef typename Lhs::Index Index;
+ typedef typename Lhs::Nested LhsNested;
+ typedef typename Rhs::Nested RhsNested;
+ typedef typename remove_all<LhsNested>::type _LhsNested;
+ typedef typename remove_all<RhsNested>::type _RhsNested;
+
+ enum {
+ LhsCoeffReadCost = traits<_LhsNested>::CoeffReadCost,
+ RhsCoeffReadCost = traits<_RhsNested>::CoeffReadCost,
+
+ RowsAtCompileTime = Tr ? int(traits<Rhs>::RowsAtCompileTime) : int(traits<Lhs>::RowsAtCompileTime),
+ ColsAtCompileTime = Tr ? int(traits<Lhs>::ColsAtCompileTime) : int(traits<Rhs>::ColsAtCompileTime),
+ MaxRowsAtCompileTime = Tr ? int(traits<Rhs>::MaxRowsAtCompileTime) : int(traits<Lhs>::MaxRowsAtCompileTime),
+ MaxColsAtCompileTime = Tr ? int(traits<Lhs>::MaxColsAtCompileTime) : int(traits<Rhs>::MaxColsAtCompileTime),
+
+ Flags = Tr ? RowMajorBit : 0,
+
+ CoeffReadCost = LhsCoeffReadCost + RhsCoeffReadCost + NumTraits<Scalar>::MulCost
+ };
+};
+
+} // end namespace internal
+
+template<typename Lhs, typename Rhs, bool Tr>
+class SparseDenseOuterProduct
+ : public SparseMatrixBase<SparseDenseOuterProduct<Lhs,Rhs,Tr> >
+{
+ public:
+
+ typedef SparseMatrixBase<SparseDenseOuterProduct> Base;
+ EIGEN_DENSE_PUBLIC_INTERFACE(SparseDenseOuterProduct)
+ typedef internal::traits<SparseDenseOuterProduct> 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<typename Lhs, typename Rhs, bool Transpose>
+class SparseDenseOuterProduct<Lhs,Rhs,Transpose>::InnerIterator : public _LhsNested::InnerIterator
+{
+ typedef typename _LhsNested::InnerIterator Base;
+ public:
+ EIGEN_STRONG_INLINE InnerIterator(const SparseDenseOuterProduct& prod, Index outer)
+ : Base(prod.lhs(), 0), m_outer(outer), m_factor(prod.rhs().coeff(outer))
+ {
+ }
+
+ inline Index outer() const { return m_outer; }
+ inline Index row() const { return Transpose ? Base::row() : m_outer; }
+ inline Index col() const { return Transpose ? m_outer : Base::row(); }
+
+ inline Scalar value() const { return Base::value() * m_factor; }
+
+ protected:
+ int m_outer;
+ Scalar m_factor;
+};
+
+namespace internal {
+template<typename Lhs, typename Rhs>
+struct traits<SparseTimeDenseProduct<Lhs,Rhs> >
+ : traits<ProductBase<SparseTimeDenseProduct<Lhs,Rhs>, Lhs, Rhs> >
+{
+ typedef Dense StorageKind;
+ typedef MatrixXpr XprKind;
+};
+
+template<typename SparseLhsType, typename DenseRhsType, typename DenseResType,
+ int LhsStorageOrder = ((SparseLhsType::Flags&RowMajorBit)==RowMajorBit) ? RowMajor : ColMajor,
+ bool ColPerCol = ((DenseRhsType::Flags&RowMajorBit)==0) || DenseRhsType::ColsAtCompileTime==1>
+struct sparse_time_dense_product_impl;
+
+template<typename SparseLhsType, typename DenseRhsType, typename DenseResType>
+struct sparse_time_dense_product_impl<SparseLhsType,DenseRhsType,DenseResType, RowMajor, true>
+{
+ typedef typename internal::remove_all<SparseLhsType>::type Lhs;
+ typedef typename internal::remove_all<DenseRhsType>::type Rhs;
+ typedef typename internal::remove_all<DenseResType>::type Res;
+ typedef typename Lhs::Index Index;
+ typedef typename Lhs::InnerIterator LhsInnerIterator;
+ static void run(const SparseLhsType& lhs, const DenseRhsType& rhs, DenseResType& res, typename Res::Scalar alpha)
+ {
+ for(Index c=0; c<rhs.cols(); ++c)
+ {
+ int n = lhs.outerSize();
+ for(Index j=0; j<n; ++j)
+ {
+ typename Res::Scalar tmp(0);
+ for(LhsInnerIterator it(lhs,j); it ;++it)
+ tmp += it.value() * rhs.coeff(it.index(),c);
+ res.coeffRef(j,c) = alpha * tmp;
+ }
+ }
+ }
+};
+
+template<typename SparseLhsType, typename DenseRhsType, typename DenseResType>
+struct sparse_time_dense_product_impl<SparseLhsType,DenseRhsType,DenseResType, ColMajor, true>
+{
+ typedef typename internal::remove_all<SparseLhsType>::type Lhs;
+ typedef typename internal::remove_all<DenseRhsType>::type Rhs;
+ typedef typename internal::remove_all<DenseResType>::type Res;
+ typedef typename Lhs::InnerIterator LhsInnerIterator;
+ typedef typename Lhs::Index Index;
+ static void run(const SparseLhsType& lhs, const DenseRhsType& rhs, DenseResType& res, typename Res::Scalar alpha)
+ {
+ for(Index c=0; c<rhs.cols(); ++c)
+ {
+ for(Index j=0; j<lhs.outerSize(); ++j)
+ {
+ typename Res::Scalar rhs_j = alpha * rhs.coeff(j,c);
+ for(LhsInnerIterator it(lhs,j); it ;++it)
+ res.coeffRef(it.index(),c) += it.value() * rhs_j;
+ }
+ }
+ }
+};
+
+template<typename SparseLhsType, typename DenseRhsType, typename DenseResType>
+struct sparse_time_dense_product_impl<SparseLhsType,DenseRhsType,DenseResType, RowMajor, false>
+{
+ typedef typename internal::remove_all<SparseLhsType>::type Lhs;
+ typedef typename internal::remove_all<DenseRhsType>::type Rhs;
+ typedef typename internal::remove_all<DenseResType>::type Res;
+ typedef typename Lhs::InnerIterator LhsInnerIterator;
+ typedef typename Lhs::Index Index;
+ static void run(const SparseLhsType& lhs, const DenseRhsType& rhs, DenseResType& res, typename Res::Scalar alpha)
+ {
+ for(Index j=0; j<lhs.outerSize(); ++j)
+ {
+ typename Res::RowXpr res_j(res.row(j));
+ for(LhsInnerIterator it(lhs,j); it ;++it)
+ res_j += (alpha*it.value()) * rhs.row(it.index());
+ }
+ }
+};
+
+template<typename SparseLhsType, typename DenseRhsType, typename DenseResType>
+struct sparse_time_dense_product_impl<SparseLhsType,DenseRhsType,DenseResType, ColMajor, false>
+{
+ typedef typename internal::remove_all<SparseLhsType>::type Lhs;
+ typedef typename internal::remove_all<DenseRhsType>::type Rhs;
+ typedef typename internal::remove_all<DenseResType>::type Res;
+ typedef typename Lhs::InnerIterator LhsInnerIterator;
+ typedef typename Lhs::Index Index;
+ static void run(const SparseLhsType& lhs, const DenseRhsType& rhs, DenseResType& res, typename Res::Scalar alpha)
+ {
+ for(Index j=0; j<lhs.outerSize(); ++j)
+ {
+ typename Rhs::ConstRowXpr rhs_j(rhs.row(j));
+ for(LhsInnerIterator it(lhs,j); it ;++it)
+ res.row(it.index()) += (alpha*it.value()) * rhs_j;
+ }
+ }
+};
+
+template<typename SparseLhsType, typename DenseRhsType, typename DenseResType,typename AlphaType>
+inline void sparse_time_dense_product(const SparseLhsType& lhs, const DenseRhsType& rhs, DenseResType& res, const AlphaType& alpha)
+{
+ sparse_time_dense_product_impl<SparseLhsType,DenseRhsType,DenseResType>::run(lhs, rhs, res, alpha);
+}
+
+} // end namespace internal
+
+template<typename Lhs, typename Rhs>
+class SparseTimeDenseProduct
+ : public ProductBase<SparseTimeDenseProduct<Lhs,Rhs>, Lhs, Rhs>
+{
+ public:
+ EIGEN_PRODUCT_PUBLIC_INTERFACE(SparseTimeDenseProduct)
+
+ SparseTimeDenseProduct(const Lhs& lhs, const Rhs& rhs) : Base(lhs,rhs)
+ {}
+
+ template<typename Dest> void scaleAndAddTo(Dest& dest, Scalar alpha) const
+ {
+ internal::sparse_time_dense_product(m_lhs, m_rhs, dest, alpha);
+ }
+
+ private:
+ SparseTimeDenseProduct& operator=(const SparseTimeDenseProduct&);
+};
+
+
+// dense = dense * sparse
+namespace internal {
+template<typename Lhs, typename Rhs>
+struct traits<DenseTimeSparseProduct<Lhs,Rhs> >
+ : traits<ProductBase<DenseTimeSparseProduct<Lhs,Rhs>, Lhs, Rhs> >
+{
+ typedef Dense StorageKind;
+};
+} // end namespace internal
+
+template<typename Lhs, typename Rhs>
+class DenseTimeSparseProduct
+ : public ProductBase<DenseTimeSparseProduct<Lhs,Rhs>, Lhs, Rhs>
+{
+ public:
+ EIGEN_PRODUCT_PUBLIC_INTERFACE(DenseTimeSparseProduct)
+
+ DenseTimeSparseProduct(const Lhs& lhs, const Rhs& rhs) : Base(lhs,rhs)
+ {}
+
+ template<typename Dest> void scaleAndAddTo(Dest& dest, Scalar alpha) const
+ {
+ Transpose<const _LhsNested> lhs_t(m_lhs);
+ Transpose<const _RhsNested> rhs_t(m_rhs);
+ Transpose<Dest> dest_t(dest);
+ internal::sparse_time_dense_product(rhs_t, lhs_t, dest_t, alpha);
+ }
+
+ private:
+ DenseTimeSparseProduct& operator=(const DenseTimeSparseProduct&);
+};
+
+// sparse * dense
+template<typename Derived>
+template<typename OtherDerived>
+inline const typename SparseDenseProductReturnType<Derived,OtherDerived>::Type
+SparseMatrixBase<Derived>::operator*(const MatrixBase<OtherDerived> &other) const
+{
+ return typename SparseDenseProductReturnType<Derived,OtherDerived>::Type(derived(), other.derived());
+}
+
+} // end namespace Eigen
+
+#endif // EIGEN_SPARSEDENSEPRODUCT_H
diff --git a/Eigen/src/SparseCore/SparseDiagonalProduct.h b/Eigen/src/SparseCore/SparseDiagonalProduct.h
new file mode 100644
index 000000000..095bf6863
--- /dev/null
+++ b/Eigen/src/SparseCore/SparseDiagonalProduct.h
@@ -0,0 +1,184 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra.
+//
+// Copyright (C) 2009 Gael Guennebaud <gael.guennebaud@inria.fr>
+//
+// This Source Code Form is subject to the terms of the Mozilla
+// Public License v. 2.0. If 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<typename Lhs, typename Rhs>
+struct traits<SparseDiagonalProduct<Lhs, Rhs> >
+{
+ typedef typename remove_all<Lhs>::type _Lhs;
+ typedef typename remove_all<Rhs>::type _Rhs;
+ typedef typename _Lhs::Scalar Scalar;
+ typedef typename promote_index_type<typename traits<Lhs>::Index,
+ typename traits<Rhs>::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<typename Lhs, typename Rhs, typename SparseDiagonalProductType, int RhsMode, int LhsMode>
+class sparse_diagonal_product_inner_iterator_selector;
+
+} // end namespace internal
+
+template<typename Lhs, typename Rhs>
+class SparseDiagonalProduct
+ : public SparseMatrixBase<SparseDiagonalProduct<Lhs,Rhs> >,
+ internal::no_assignment_operator
+{
+ typedef typename Lhs::Nested LhsNested;
+ typedef typename Rhs::Nested RhsNested;
+
+ typedef typename internal::remove_all<LhsNested>::type _LhsNested;
+ typedef typename internal::remove_all<RhsNested>::type _RhsNested;
+
+ enum {
+ LhsMode = internal::is_diagonal<_LhsNested>::ret ? internal::SDP_IsDiagonal
+ : (_LhsNested::Flags&RowMajorBit) ? internal::SDP_IsSparseRowMajor : internal::SDP_IsSparseColMajor,
+ RhsMode = internal::is_diagonal<_RhsNested>::ret ? internal::SDP_IsDiagonal
+ : (_RhsNested::Flags&RowMajorBit) ? internal::SDP_IsSparseRowMajor : internal::SDP_IsSparseColMajor
+ };
+
+ public:
+
+ EIGEN_SPARSE_PUBLIC_INTERFACE(SparseDiagonalProduct)
+
+ typedef internal::sparse_diagonal_product_inner_iterator_selector
+ <_LhsNested,_RhsNested,SparseDiagonalProduct,LhsMode,RhsMode> InnerIterator;
+
+ EIGEN_STRONG_INLINE SparseDiagonalProduct(const Lhs& lhs, const Rhs& rhs)
+ : m_lhs(lhs), m_rhs(rhs)
+ {
+ eigen_assert(lhs.cols() == rhs.rows() && "invalid sparse matrix * diagonal matrix product");
+ }
+
+ EIGEN_STRONG_INLINE Index rows() const { return m_lhs.rows(); }
+ EIGEN_STRONG_INLINE Index cols() const { return m_rhs.cols(); }
+
+ EIGEN_STRONG_INLINE const _LhsNested& lhs() const { return m_lhs; }
+ EIGEN_STRONG_INLINE const _RhsNested& rhs() const { return m_rhs; }
+
+ protected:
+ LhsNested m_lhs;
+ RhsNested m_rhs;
+};
+
+namespace internal {
+
+template<typename Lhs, typename Rhs, typename SparseDiagonalProductType>
+class sparse_diagonal_product_inner_iterator_selector
+<Lhs,Rhs,SparseDiagonalProductType,SDP_IsDiagonal,SDP_IsSparseRowMajor>
+ : public CwiseUnaryOp<scalar_multiple_op<typename Lhs::Scalar>,const Rhs>::InnerIterator
+{
+ typedef typename CwiseUnaryOp<scalar_multiple_op<typename Lhs::Scalar>,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<typename Lhs, typename Rhs, typename SparseDiagonalProductType>
+class sparse_diagonal_product_inner_iterator_selector
+<Lhs,Rhs,SparseDiagonalProductType,SDP_IsDiagonal,SDP_IsSparseColMajor>
+ : public CwiseBinaryOp<
+ scalar_product_op<typename Lhs::Scalar>,
+ SparseInnerVectorSet<Rhs,1>,
+ typename Lhs::DiagonalVectorType>::InnerIterator
+{
+ typedef typename CwiseBinaryOp<
+ scalar_product_op<typename Lhs::Scalar>,
+ SparseInnerVectorSet<Rhs,1>,
+ typename Lhs::DiagonalVectorType>::InnerIterator Base;
+ typedef typename Lhs::Index Index;
+ public:
+ inline sparse_diagonal_product_inner_iterator_selector(
+ const SparseDiagonalProductType& expr, Index outer)
+ : Base(expr.rhs().innerVector(outer) .cwiseProduct(expr.lhs().diagonal()), 0)
+ {}
+};
+
+template<typename Lhs, typename Rhs, typename SparseDiagonalProductType>
+class sparse_diagonal_product_inner_iterator_selector
+<Lhs,Rhs,SparseDiagonalProductType,SDP_IsSparseColMajor,SDP_IsDiagonal>
+ : public CwiseUnaryOp<scalar_multiple_op<typename Rhs::Scalar>,const Lhs>::InnerIterator
+{
+ typedef typename CwiseUnaryOp<scalar_multiple_op<typename Rhs::Scalar>,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<typename Lhs, typename Rhs, typename SparseDiagonalProductType>
+class sparse_diagonal_product_inner_iterator_selector
+<Lhs,Rhs,SparseDiagonalProductType,SDP_IsSparseRowMajor,SDP_IsDiagonal>
+ : public CwiseBinaryOp<
+ scalar_product_op<typename Rhs::Scalar>,
+ SparseInnerVectorSet<Lhs,1>,
+ Transpose<const typename Rhs::DiagonalVectorType> >::InnerIterator
+{
+ typedef typename CwiseBinaryOp<
+ scalar_product_op<typename Rhs::Scalar>,
+ SparseInnerVectorSet<Lhs,1>,
+ Transpose<const typename Rhs::DiagonalVectorType> >::InnerIterator Base;
+ typedef typename Lhs::Index Index;
+ public:
+ inline sparse_diagonal_product_inner_iterator_selector(
+ const SparseDiagonalProductType& expr, Index outer)
+ : Base(expr.lhs().innerVector(outer) .cwiseProduct(expr.rhs().diagonal().transpose()), 0)
+ {}
+};
+
+} // end namespace internal
+
+// SparseMatrixBase functions
+
+template<typename Derived>
+template<typename OtherDerived>
+const SparseDiagonalProduct<Derived,OtherDerived>
+SparseMatrixBase<Derived>::operator*(const DiagonalBase<OtherDerived> &other) const
+{
+ return SparseDiagonalProduct<Derived,OtherDerived>(this->derived(), other.derived());
+}
+
+} // end namespace Eigen
+
+#endif // EIGEN_SPARSE_DIAGONAL_PRODUCT_H
diff --git a/Eigen/src/SparseCore/SparseDot.h b/Eigen/src/SparseCore/SparseDot.h
new file mode 100644
index 000000000..5c4a593dc
--- /dev/null
+++ b/Eigen/src/SparseCore/SparseDot.h
@@ -0,0 +1,94 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra.
+//
+// Copyright (C) 2008 Gael Guennebaud <gael.guennebaud@inria.fr>
+//
+// This Source Code Form is subject to the terms of the Mozilla
+// Public License v. 2.0. If a copy of the MPL was not distributed
+// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+#ifndef EIGEN_SPARSE_DOT_H
+#define EIGEN_SPARSE_DOT_H
+
+namespace Eigen {
+
+template<typename Derived>
+template<typename OtherDerived>
+typename internal::traits<Derived>::Scalar
+SparseMatrixBase<Derived>::dot(const MatrixBase<OtherDerived>& 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<Scalar, typename OtherDerived::Scalar>::value),
+ YOU_MIXED_DIFFERENT_NUMERIC_TYPES__YOU_NEED_TO_USE_THE_CAST_METHOD_OF_MATRIXBASE_TO_CAST_NUMERIC_TYPES_EXPLICITLY)
+
+ eigen_assert(size() == other.size());
+ eigen_assert(other.size()>0 && "you are using a non initialized vector");
+
+ typename Derived::InnerIterator i(derived(),0);
+ Scalar res(0);
+ while (i)
+ {
+ res += internal::conj(i.value()) * other.coeff(i.index());
+ ++i;
+ }
+ return res;
+}
+
+template<typename Derived>
+template<typename OtherDerived>
+typename internal::traits<Derived>::Scalar
+SparseMatrixBase<Derived>::dot(const SparseMatrixBase<OtherDerived>& 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<Scalar, typename OtherDerived::Scalar>::value),
+ YOU_MIXED_DIFFERENT_NUMERIC_TYPES__YOU_NEED_TO_USE_THE_CAST_METHOD_OF_MATRIXBASE_TO_CAST_NUMERIC_TYPES_EXPLICITLY)
+
+ eigen_assert(size() == other.size());
+
+ typedef typename Derived::Nested Nested;
+ typedef typename OtherDerived::Nested OtherNested;
+ typedef typename internal::remove_all<Nested>::type NestedCleaned;
+ typedef typename internal::remove_all<OtherNested>::type OtherNestedCleaned;
+
+ const Nested nthis(derived());
+ const OtherNested nother(other.derived());
+
+ typename NestedCleaned::InnerIterator i(nthis,0);
+ typename OtherNestedCleaned::InnerIterator j(nother,0);
+ Scalar res(0);
+ while (i && j)
+ {
+ if (i.index()==j.index())
+ {
+ res += internal::conj(i.value()) * j.value();
+ ++i; ++j;
+ }
+ else if (i.index()<j.index())
+ ++i;
+ else
+ ++j;
+ }
+ return res;
+}
+
+template<typename Derived>
+inline typename NumTraits<typename internal::traits<Derived>::Scalar>::Real
+SparseMatrixBase<Derived>::squaredNorm() const
+{
+ return internal::real((*this).cwiseAbs2().sum());
+}
+
+template<typename Derived>
+inline typename NumTraits<typename internal::traits<Derived>::Scalar>::Real
+SparseMatrixBase<Derived>::norm() const
+{
+ return internal::sqrt(squaredNorm());
+}
+
+} // end namespace Eigen
+
+#endif // EIGEN_SPARSE_DOT_H
diff --git a/Eigen/src/SparseCore/SparseFuzzy.h b/Eigen/src/SparseCore/SparseFuzzy.h
new file mode 100644
index 000000000..45f36e9eb
--- /dev/null
+++ b/Eigen/src/SparseCore/SparseFuzzy.h
@@ -0,0 +1,26 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra.
+//
+// Copyright (C) 2008 Gael Guennebaud <gael.guennebaud@inria.fr>
+//
+// This Source Code Form is subject to the terms of the Mozilla
+// Public License v. 2.0. If 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<typename Derived>
+// template<typename OtherDerived>
+// bool SparseMatrixBase<Derived>::isApprox(
+// const OtherDerived& other,
+// typename NumTraits<Scalar>::Real prec
+// ) const
+// {
+// const typename internal::nested<Derived,2>::type nested(derived());
+// const typename internal::nested<OtherDerived,2>::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/Eigen/src/SparseCore/SparseMatrix.h b/Eigen/src/SparseCore/SparseMatrix.h
new file mode 100644
index 000000000..efb774f03
--- /dev/null
+++ b/Eigen/src/SparseCore/SparseMatrix.h
@@ -0,0 +1,1116 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra.
+//
+// Copyright (C) 2008-2010 Gael Guennebaud <gael.guennebaud@inria.fr>
+//
+// This Source Code Form is subject to the terms of the Mozilla
+// Public License v. 2.0. If a copy of the MPL was not distributed
+// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+#ifndef EIGEN_SPARSEMATRIX_H
+#define EIGEN_SPARSEMATRIX_H
+
+namespace Eigen {
+
+/** \ingroup SparseCore_Module
+ *
+ * \class SparseMatrix
+ *
+ * \brief A versatible sparse matrix representation
+ *
+ * This class implements a more versatile variants of the common \em compressed row/column storage format.
+ * Each colmun's (resp. row) non zeros are stored as a pair of value with associated row (resp. colmiun) index.
+ * All the non zeros are stored in a single large buffer. Unlike the \em compressed format, there might be extra
+ * space inbetween the nonzeros of two successive colmuns (resp. rows) such that insertion of new non-zero
+ * can be done with limited memory reallocation and copies.
+ *
+ * A call to the function makeCompressed() turns the matrix into the standard \em compressed format
+ * compatible with many library.
+ *
+ * More details on this storage sceheme are given in the \ref TutorialSparse "manual pages".
+ *
+ * \tparam _Scalar the scalar type, i.e. the type of the coefficients
+ * \tparam _Options Union of bit flags controlling the storage scheme. Currently the only possibility
+ * is RowMajor. The default is 0 which means column-major.
+ * \tparam _Index the type of the indices. It has to be a \b signed type (e.g., short, int, std::ptrdiff_t). Default is \c int.
+ *
+ * This class can be extended with the help of the plugin mechanism described on the page
+ * \ref TopicCustomizingEigen by defining the preprocessor symbol \c EIGEN_SPARSEMATRIX_PLUGIN.
+ */
+
+namespace internal {
+template<typename _Scalar, int _Options, typename _Index>
+struct traits<SparseMatrix<_Scalar, _Options, _Index> >
+{
+ typedef _Scalar Scalar;
+ typedef _Index Index;
+ typedef Sparse StorageKind;
+ typedef MatrixXpr XprKind;
+ enum {
+ RowsAtCompileTime = Dynamic,
+ ColsAtCompileTime = Dynamic,
+ MaxRowsAtCompileTime = Dynamic,
+ MaxColsAtCompileTime = Dynamic,
+ Flags = _Options | NestByRefBit | LvalueBit,
+ CoeffReadCost = NumTraits<Scalar>::ReadCost,
+ SupportedAccessPatterns = InnerRandomAccessPattern
+ };
+};
+
+template<typename _Scalar, int _Options, typename _Index, int DiagIndex>
+struct traits<Diagonal<const SparseMatrix<_Scalar, _Options, _Index>, DiagIndex> >
+{
+ typedef SparseMatrix<_Scalar, _Options, _Index> MatrixType;
+ typedef typename nested<MatrixType>::type MatrixTypeNested;
+ typedef typename remove_reference<MatrixTypeNested>::type _MatrixTypeNested;
+
+ typedef _Scalar Scalar;
+ typedef Dense StorageKind;
+ typedef _Index Index;
+ typedef MatrixXpr XprKind;
+
+ enum {
+ RowsAtCompileTime = Dynamic,
+ ColsAtCompileTime = 1,
+ MaxRowsAtCompileTime = Dynamic,
+ MaxColsAtCompileTime = 1,
+ Flags = 0,
+ CoeffReadCost = _MatrixTypeNested::CoeffReadCost*10
+ };
+};
+
+} // end namespace internal
+
+template<typename _Scalar, int _Options, typename _Index>
+class SparseMatrix
+ : public SparseMatrixBase<SparseMatrix<_Scalar, _Options, _Index> >
+{
+ public:
+ EIGEN_SPARSE_PUBLIC_INTERFACE(SparseMatrix)
+ EIGEN_SPARSE_INHERIT_ASSIGNMENT_OPERATOR(SparseMatrix, +=)
+ EIGEN_SPARSE_INHERIT_ASSIGNMENT_OPERATOR(SparseMatrix, -=)
+
+ typedef MappedSparseMatrix<Scalar,Flags> Map;
+ using Base::IsRowMajor;
+ typedef internal::CompressedStorage<Scalar,Index> Storage;
+ enum {
+ Options = _Options
+ };
+
+ protected:
+
+ typedef SparseMatrix<Scalar,(Flags&~RowMajorBit)|(IsRowMajor?RowMajorBit:0)> TransposedSparseMatrix;
+
+ Index m_outerSize;
+ Index m_innerSize;
+ Index* m_outerIndex;
+ Index* m_innerNonZeros; // optional, if null then the data is compressed
+ Storage m_data;
+
+ Eigen::Map<Matrix<Index,Dynamic,1> > innerNonZeros() { return Eigen::Map<Matrix<Index,Dynamic,1> >(m_innerNonZeros, m_innerNonZeros?m_outerSize:0); }
+ const Eigen::Map<const Matrix<Index,Dynamic,1> > innerNonZeros() const { return Eigen::Map<const Matrix<Index,Dynamic,1> >(m_innerNonZeros, m_innerNonZeros?m_outerSize:0); }
+
+ public:
+
+ /** \returns whether \c *this is in compressed form. */
+ inline bool isCompressed() const { return m_innerNonZeros==0; }
+
+ /** \returns the number of rows of the matrix */
+ inline Index rows() const { return IsRowMajor ? m_outerSize : m_innerSize; }
+ /** \returns the number of columns of the matrix */
+ inline Index cols() const { return IsRowMajor ? m_innerSize : m_outerSize; }
+
+ /** \returns the number of rows (resp. columns) of the matrix if the storage order column major (resp. row major) */
+ inline Index innerSize() const { return m_innerSize; }
+ /** \returns the number of columns (resp. rows) of the matrix if the storage order column major (resp. row major) */
+ inline Index outerSize() const { return m_outerSize; }
+
+ /** \returns a const pointer to the array of values.
+ * This function is aimed at interoperability with other libraries.
+ * \sa innerIndexPtr(), outerIndexPtr() */
+ inline const Scalar* valuePtr() const { return &m_data.value(0); }
+ /** \returns a non-const pointer to the array of values.
+ * This function is aimed at interoperability with other libraries.
+ * \sa innerIndexPtr(), outerIndexPtr() */
+ inline Scalar* valuePtr() { return &m_data.value(0); }
+
+ /** \returns a const pointer to the array of inner indices.
+ * This function is aimed at interoperability with other libraries.
+ * \sa valuePtr(), outerIndexPtr() */
+ inline const Index* innerIndexPtr() const { return &m_data.index(0); }
+ /** \returns a non-const pointer to the array of inner indices.
+ * This function is aimed at interoperability with other libraries.
+ * \sa valuePtr(), outerIndexPtr() */
+ inline Index* innerIndexPtr() { return &m_data.index(0); }
+
+ /** \returns a const pointer to the array of the starting positions of the inner vectors.
+ * This function is aimed at interoperability with other libraries.
+ * \sa valuePtr(), innerIndexPtr() */
+ inline const Index* outerIndexPtr() const { return m_outerIndex; }
+ /** \returns a non-const pointer to the array of the starting positions of the inner vectors.
+ * This function is aimed at interoperability with other libraries.
+ * \sa valuePtr(), innerIndexPtr() */
+ inline Index* outerIndexPtr() { return m_outerIndex; }
+
+ /** \returns a const pointer to the array of the number of non zeros of the inner vectors.
+ * This function is aimed at interoperability with other libraries.
+ * \warning it returns the null pointer 0 in compressed mode */
+ inline const Index* innerNonZeroPtr() const { return m_innerNonZeros; }
+ /** \returns a non-const pointer to the array of the number of non zeros of the inner vectors.
+ * This function is aimed at interoperability with other libraries.
+ * \warning it returns the null pointer 0 in compressed mode */
+ inline Index* innerNonZeroPtr() { return m_innerNonZeros; }
+
+ /** \internal */
+ inline Storage& data() { return m_data; }
+ /** \internal */
+ inline const Storage& data() const { return m_data; }
+
+ /** \returns the value of the matrix at position \a i, \a j
+ * This function returns Scalar(0) if the element is an explicit \em zero */
+ inline Scalar coeff(Index row, Index col) const
+ {
+ const Index outer = IsRowMajor ? row : col;
+ const Index inner = IsRowMajor ? col : row;
+ Index end = m_innerNonZeros ? m_outerIndex[outer] + m_innerNonZeros[outer] : m_outerIndex[outer+1];
+ return m_data.atInRange(m_outerIndex[outer], end, inner);
+ }
+
+ /** \returns a non-const reference to the value of the matrix at position \a i, \a j
+ *
+ * If the element does not exist then it is inserted via the insert(Index,Index) function
+ * which itself turns the matrix into a non compressed form if that was not the case.
+ *
+ * This is a O(log(nnz_j)) operation (binary search) plus the cost of insert(Index,Index)
+ * function if the element does not already exist.
+ */
+ inline Scalar& coeffRef(Index row, Index col)
+ {
+ const Index outer = IsRowMajor ? row : col;
+ const Index inner = IsRowMajor ? col : row;
+
+ Index start = m_outerIndex[outer];
+ Index end = m_innerNonZeros ? m_outerIndex[outer] + m_innerNonZeros[outer] : m_outerIndex[outer+1];
+ eigen_assert(end>=start && "you probably called coeffRef on a non finalized matrix");
+ if(end<=start)
+ return insert(row,col);
+ const Index p = m_data.searchLowerIndex(start,end-1,inner);
+ if((p<end) && (m_data.index(p)==inner))
+ return m_data.value(p);
+ else
+ return insert(row,col);
+ }
+
+ /** \returns a reference to a novel non zero coefficient with coordinates \a row x \a col.
+ * The non zero coefficient must \b not already exist.
+ *
+ * If the matrix \c *this is in compressed mode, then \c *this is turned into uncompressed
+ * mode while reserving room for 2 non zeros per inner vector. It is strongly recommended to first
+ * call reserve(const SizesType &) to reserve a more appropriate number of elements per
+ * inner vector that better match your scenario.
+ *
+ * This function performs a sorted insertion in O(1) if the elements of each inner vector are
+ * inserted in increasing inner index order, and in O(nnz_j) for a random insertion.
+ *
+ */
+ EIGEN_DONT_INLINE Scalar& insert(Index row, Index col)
+ {
+ if(isCompressed())
+ {
+ reserve(VectorXi::Constant(outerSize(), 2));
+ }
+ return insertUncompressed(row,col);
+ }
+
+ public:
+
+ class InnerIterator;
+ class ReverseInnerIterator;
+
+ /** Removes all non zeros but keep allocated memory */
+ inline void setZero()
+ {
+ m_data.clear();
+ memset(m_outerIndex, 0, (m_outerSize+1)*sizeof(Index));
+ if(m_innerNonZeros)
+ memset(m_innerNonZeros, 0, (m_outerSize)*sizeof(Index));
+ }
+
+ /** \returns the number of non zero coefficients */
+ inline Index nonZeros() const
+ {
+ if(m_innerNonZeros)
+ return innerNonZeros().sum();
+ return static_cast<Index>(m_data.size());
+ }
+
+ /** Preallocates \a reserveSize non zeros.
+ *
+ * Precondition: the matrix must be in compressed mode. */
+ inline void reserve(Index reserveSize)
+ {
+ eigen_assert(isCompressed() && "This function does not make sense in non compressed mode.");
+ m_data.reserve(reserveSize);
+ }
+
+ #ifdef EIGEN_PARSED_BY_DOXYGEN
+ /** Preallocates \a reserveSize[\c j] non zeros for each column (resp. row) \c j.
+ *
+ * This function turns the matrix in non-compressed mode */
+ template<class SizesType>
+ inline void reserve(const SizesType& reserveSizes);
+ #else
+ template<class SizesType>
+ inline void reserve(const SizesType& reserveSizes, const typename SizesType::value_type& enableif = typename SizesType::value_type())
+ {
+ EIGEN_UNUSED_VARIABLE(enableif);
+ reserveInnerVectors(reserveSizes);
+ }
+ template<class SizesType>
+ inline void reserve(const SizesType& reserveSizes, const typename SizesType::Scalar& enableif =
+ #if (!defined(_MSC_VER)) || (_MSC_VER>=1500) // MSVC 2005 fails to compile with this typename
+ typename
+ #endif
+ SizesType::Scalar())
+ {
+ EIGEN_UNUSED_VARIABLE(enableif);
+ reserveInnerVectors(reserveSizes);
+ }
+ #endif // EIGEN_PARSED_BY_DOXYGEN
+ protected:
+ template<class SizesType>
+ inline void reserveInnerVectors(const SizesType& reserveSizes)
+ {
+
+ if(isCompressed())
+ {
+ std::size_t totalReserveSize = 0;
+ // turn the matrix into non-compressed mode
+ m_innerNonZeros = new Index[m_outerSize];
+
+ // temporarily use m_innerSizes to hold the new starting points.
+ Index* newOuterIndex = m_innerNonZeros;
+
+ Index count = 0;
+ for(Index j=0; j<m_outerSize; ++j)
+ {
+ newOuterIndex[j] = count;
+ count += reserveSizes[j] + (m_outerIndex[j+1]-m_outerIndex[j]);
+ totalReserveSize += reserveSizes[j];
+ }
+ m_data.reserve(totalReserveSize);
+ std::ptrdiff_t previousOuterIndex = m_outerIndex[m_outerSize];
+ for(std::ptrdiff_t j=m_outerSize-1; j>=0; --j)
+ {
+ ptrdiff_t innerNNZ = previousOuterIndex - m_outerIndex[j];
+ for(std::ptrdiff_t i=innerNNZ-1; i>=0; --i)
+ {
+ m_data.index(newOuterIndex[j]+i) = m_data.index(m_outerIndex[j]+i);
+ m_data.value(newOuterIndex[j]+i) = m_data.value(m_outerIndex[j]+i);
+ }
+ previousOuterIndex = m_outerIndex[j];
+ m_outerIndex[j] = newOuterIndex[j];
+ m_innerNonZeros[j] = innerNNZ;
+ }
+ m_outerIndex[m_outerSize] = m_outerIndex[m_outerSize-1] + m_innerNonZeros[m_outerSize-1] + reserveSizes[m_outerSize-1];
+
+ m_data.resize(m_outerIndex[m_outerSize]);
+ }
+ else
+ {
+ Index* newOuterIndex = new Index[m_outerSize+1];
+ Index count = 0;
+ for(Index j=0; j<m_outerSize; ++j)
+ {
+ newOuterIndex[j] = count;
+ Index alreadyReserved = (m_outerIndex[j+1]-m_outerIndex[j]) - m_innerNonZeros[j];
+ Index toReserve = std::max<std::ptrdiff_t>(reserveSizes[j], alreadyReserved);
+ count += toReserve + m_innerNonZeros[j];
+ }
+ newOuterIndex[m_outerSize] = count;
+
+ m_data.resize(count);
+ for(ptrdiff_t j=m_outerSize-1; j>=0; --j)
+ {
+ std::ptrdiff_t offset = newOuterIndex[j] - m_outerIndex[j];
+ if(offset>0)
+ {
+ std::ptrdiff_t innerNNZ = m_innerNonZeros[j];
+ for(std::ptrdiff_t i=innerNNZ-1; i>=0; --i)
+ {
+ m_data.index(newOuterIndex[j]+i) = m_data.index(m_outerIndex[j]+i);
+ m_data.value(newOuterIndex[j]+i) = m_data.value(m_outerIndex[j]+i);
+ }
+ }
+ }
+
+ std::swap(m_outerIndex, newOuterIndex);
+ delete[] newOuterIndex;
+ }
+
+ }
+ public:
+
+ //--- low level purely coherent filling ---
+
+ /** \internal
+ * \returns a reference to the non zero coefficient at position \a row, \a col assuming that:
+ * - the nonzero does not already exist
+ * - the new coefficient is the last one according to the storage order
+ *
+ * Before filling a given inner vector you must call the statVec(Index) function.
+ *
+ * After an insertion session, you should call the finalize() function.
+ *
+ * \sa insert, insertBackByOuterInner, startVec */
+ inline Scalar& insertBack(Index row, Index col)
+ {
+ return insertBackByOuterInner(IsRowMajor?row:col, IsRowMajor?col:row);
+ }
+
+ /** \internal
+ * \sa insertBack, startVec */
+ inline Scalar& insertBackByOuterInner(Index outer, Index inner)
+ {
+ eigen_assert(size_t(m_outerIndex[outer+1]) == m_data.size() && "Invalid ordered insertion (invalid outer index)");
+ eigen_assert( (m_outerIndex[outer+1]-m_outerIndex[outer]==0 || m_data.index(m_data.size()-1)<inner) && "Invalid ordered insertion (invalid inner index)");
+ Index p = m_outerIndex[outer+1];
+ ++m_outerIndex[outer+1];
+ m_data.append(0, inner);
+ return m_data.value(p);
+ }
+
+ /** \internal
+ * \warning use it only if you know what you are doing */
+ inline Scalar& insertBackByOuterInnerUnordered(Index outer, Index inner)
+ {
+ Index p = m_outerIndex[outer+1];
+ ++m_outerIndex[outer+1];
+ m_data.append(0, inner);
+ return m_data.value(p);
+ }
+
+ /** \internal
+ * \sa insertBack, insertBackByOuterInner */
+ inline void startVec(Index outer)
+ {
+ eigen_assert(m_outerIndex[outer]==int(m_data.size()) && "You must call startVec for each inner vector sequentially");
+ eigen_assert(m_outerIndex[outer+1]==0 && "You must call startVec for each inner vector sequentially");
+ m_outerIndex[outer+1] = m_outerIndex[outer];
+ }
+
+ /** \internal
+ * Must be called after inserting a set of non zero entries using the low level compressed API.
+ */
+ inline void finalize()
+ {
+ if(isCompressed())
+ {
+ Index size = static_cast<Index>(m_data.size());
+ Index i = m_outerSize;
+ // find the last filled column
+ while (i>=0 && m_outerIndex[i]==0)
+ --i;
+ ++i;
+ while (i<=m_outerSize)
+ {
+ m_outerIndex[i] = size;
+ ++i;
+ }
+ }
+ }
+
+ //---
+
+ template<typename InputIterators>
+ void setFromTriplets(const InputIterators& begin, const InputIterators& end);
+
+ void sumupDuplicates();
+
+ //---
+
+ /** \internal
+ * same as insert(Index,Index) except that the indices are given relative to the storage order */
+ EIGEN_DONT_INLINE Scalar& insertByOuterInner(Index j, Index i)
+ {
+ return insert(IsRowMajor ? j : i, IsRowMajor ? i : j);
+ }
+
+ /** Turns the matrix into the \em compressed format.
+ */
+ void makeCompressed()
+ {
+ if(isCompressed())
+ return;
+
+ Index oldStart = m_outerIndex[1];
+ m_outerIndex[1] = m_innerNonZeros[0];
+ for(Index j=1; j<m_outerSize; ++j)
+ {
+ Index nextOldStart = m_outerIndex[j+1];
+ std::ptrdiff_t offset = oldStart - m_outerIndex[j];
+ if(offset>0)
+ {
+ for(Index k=0; k<m_innerNonZeros[j]; ++k)
+ {
+ m_data.index(m_outerIndex[j]+k) = m_data.index(oldStart+k);
+ m_data.value(m_outerIndex[j]+k) = m_data.value(oldStart+k);
+ }
+ }
+ m_outerIndex[j+1] = m_outerIndex[j] + m_innerNonZeros[j];
+ oldStart = nextOldStart;
+ }
+ delete[] m_innerNonZeros;
+ m_innerNonZeros = 0;
+ m_data.resize(m_outerIndex[m_outerSize]);
+ m_data.squeeze();
+ }
+
+ /** Suppresses all nonzeros which are \b much \b smaller \b than \a reference under the tolerence \a epsilon */
+ void prune(Scalar reference, RealScalar epsilon = NumTraits<RealScalar>::dummy_precision())
+ {
+ prune(default_prunning_func(reference,epsilon));
+ }
+
+ /** Turns the matrix into compressed format, and suppresses all nonzeros which do not satisfy the predicate \a keep.
+ * The functor type \a KeepFunc must implement the following function:
+ * \code
+ * bool operator() (const Index& row, const Index& col, const Scalar& value) const;
+ * \endcode
+ * \sa prune(Scalar,RealScalar)
+ */
+ template<typename KeepFunc>
+ void prune(const KeepFunc& keep = KeepFunc())
+ {
+ // TODO optimize the uncompressed mode to avoid moving and allocating the data twice
+ // TODO also implement a unit test
+ makeCompressed();
+
+ Index k = 0;
+ for(Index j=0; j<m_outerSize; ++j)
+ {
+ Index previousStart = m_outerIndex[j];
+ m_outerIndex[j] = k;
+ Index end = m_outerIndex[j+1];
+ for(Index i=previousStart; i<end; ++i)
+ {
+ if(keep(IsRowMajor?j:m_data.index(i), IsRowMajor?m_data.index(i):j, m_data.value(i)))
+ {
+ m_data.value(k) = m_data.value(i);
+ m_data.index(k) = m_data.index(i);
+ ++k;
+ }
+ }
+ }
+ m_outerIndex[m_outerSize] = k;
+ m_data.resize(k,0);
+ }
+
+ /** Resizes the matrix to a \a rows x \a cols matrix and initializes it to zero.
+ * \sa resizeNonZeros(Index), reserve(), setZero()
+ */
+ void resize(Index rows, Index cols)
+ {
+ const Index outerSize = IsRowMajor ? rows : cols;
+ m_innerSize = IsRowMajor ? cols : rows;
+ m_data.clear();
+ if (m_outerSize != outerSize || m_outerSize==0)
+ {
+ delete[] m_outerIndex;
+ m_outerIndex = new Index [outerSize+1];
+ m_outerSize = outerSize;
+ }
+ if(m_innerNonZeros)
+ {
+ delete[] m_innerNonZeros;
+ m_innerNonZeros = 0;
+ }
+ memset(m_outerIndex, 0, (m_outerSize+1)*sizeof(Index));
+ }
+
+ /** \internal
+ * Resize the nonzero vector to \a size */
+ void resizeNonZeros(Index size)
+ {
+ // TODO remove this function
+ m_data.resize(size);
+ }
+
+ /** \returns a const expression of the diagonal coefficients */
+ const Diagonal<const SparseMatrix> diagonal() const { return *this; }
+
+ /** Default constructor yielding an empty \c 0 \c x \c 0 matrix */
+ inline SparseMatrix()
+ : m_outerSize(-1), m_innerSize(0), m_outerIndex(0), m_innerNonZeros(0)
+ {
+ check_template_parameters();
+ resize(0, 0);
+ }
+
+ /** Constructs a \a rows \c x \a cols empty matrix */
+ inline SparseMatrix(Index rows, Index cols)
+ : m_outerSize(0), m_innerSize(0), m_outerIndex(0), m_innerNonZeros(0)
+ {
+ check_template_parameters();
+ resize(rows, cols);
+ }
+
+ /** Constructs a sparse matrix from the sparse expression \a other */
+ template<typename OtherDerived>
+ inline SparseMatrix(const SparseMatrixBase<OtherDerived>& other)
+ : m_outerSize(0), m_innerSize(0), m_outerIndex(0), m_innerNonZeros(0)
+ {
+ check_template_parameters();
+ *this = other.derived();
+ }
+
+ /** Copy constructor (it performs a deep copy) */
+ inline SparseMatrix(const SparseMatrix& other)
+ : Base(), m_outerSize(0), m_innerSize(0), m_outerIndex(0), m_innerNonZeros(0)
+ {
+ check_template_parameters();
+ *this = other.derived();
+ }
+
+ /** Swaps the content of two sparse matrices of the same type.
+ * This is a fast operation that simply swaps the underlying pointers and parameters. */
+ inline void swap(SparseMatrix& other)
+ {
+ //EIGEN_DBG_SPARSE(std::cout << "SparseMatrix:: swap\n");
+ std::swap(m_outerIndex, other.m_outerIndex);
+ std::swap(m_innerSize, other.m_innerSize);
+ std::swap(m_outerSize, other.m_outerSize);
+ std::swap(m_innerNonZeros, other.m_innerNonZeros);
+ m_data.swap(other.m_data);
+ }
+
+ inline SparseMatrix& operator=(const SparseMatrix& other)
+ {
+ if (other.isRValue())
+ {
+ swap(other.const_cast_derived());
+ }
+ else
+ {
+ initAssignment(other);
+ if(other.isCompressed())
+ {
+ memcpy(m_outerIndex, other.m_outerIndex, (m_outerSize+1)*sizeof(Index));
+ m_data = other.m_data;
+ }
+ else
+ {
+ Base::operator=(other);
+ }
+ }
+ return *this;
+ }
+
+ #ifndef EIGEN_PARSED_BY_DOXYGEN
+ template<typename Lhs, typename Rhs>
+ inline SparseMatrix& operator=(const SparseSparseProduct<Lhs,Rhs>& product)
+ { return Base::operator=(product); }
+
+ template<typename OtherDerived>
+ inline SparseMatrix& operator=(const ReturnByValue<OtherDerived>& other)
+ { return Base::operator=(other.derived()); }
+
+ template<typename OtherDerived>
+ inline SparseMatrix& operator=(const EigenBase<OtherDerived>& other)
+ { return Base::operator=(other.derived()); }
+ #endif
+
+ template<typename OtherDerived>
+ EIGEN_DONT_INLINE SparseMatrix& operator=(const SparseMatrixBase<OtherDerived>& other)
+ {
+ initAssignment(other.derived());
+ const bool needToTranspose = (Flags & RowMajorBit) != (OtherDerived::Flags & RowMajorBit);
+ if (needToTranspose)
+ {
+ // two passes algorithm:
+ // 1 - compute the number of coeffs per dest inner vector
+ // 2 - do the actual copy/eval
+ // Since each coeff of the rhs has to be evaluated twice, let's evaluate it if needed
+ typedef typename internal::nested<OtherDerived,2>::type OtherCopy;
+ typedef typename internal::remove_all<OtherCopy>::type _OtherCopy;
+ OtherCopy otherCopy(other.derived());
+
+ Eigen::Map<Matrix<Index, Dynamic, 1> > (m_outerIndex,outerSize()).setZero();
+ // pass 1
+ // FIXME the above copy could be merged with that pass
+ for (Index j=0; j<otherCopy.outerSize(); ++j)
+ for (typename _OtherCopy::InnerIterator it(otherCopy, j); it; ++it)
+ ++m_outerIndex[it.index()];
+
+ // prefix sum
+ Index count = 0;
+ VectorXi positions(outerSize());
+ for (Index j=0; j<outerSize(); ++j)
+ {
+ Index tmp = m_outerIndex[j];
+ m_outerIndex[j] = count;
+ positions[j] = count;
+ count += tmp;
+ }
+ m_outerIndex[outerSize()] = count;
+ // alloc
+ m_data.resize(count);
+ // pass 2
+ for (Index j=0; j<otherCopy.outerSize(); ++j)
+ {
+ for (typename _OtherCopy::InnerIterator it(otherCopy, j); it; ++it)
+ {
+ Index pos = positions[it.index()]++;
+ m_data.index(pos) = j;
+ m_data.value(pos) = it.value();
+ }
+ }
+ return *this;
+ }
+ else
+ {
+ // there is no special optimization
+ return Base::operator=(other.derived());
+ }
+ }
+
+ friend std::ostream & operator << (std::ostream & s, const SparseMatrix& m)
+ {
+ EIGEN_DBG_SPARSE(
+ s << "Nonzero entries:\n";
+ if(m.isCompressed())
+ for (Index i=0; i<m.nonZeros(); ++i)
+ s << "(" << m.m_data.value(i) << "," << m.m_data.index(i) << ") ";
+ else
+ for (Index i=0; i<m.outerSize(); ++i)
+ {
+ int p = m.m_outerIndex[i];
+ int pe = m.m_outerIndex[i]+m.m_innerNonZeros[i];
+ Index k=p;
+ for (; k<pe; ++k)
+ s << "(" << m.m_data.value(k) << "," << m.m_data.index(k) << ") ";
+ for (; k<m.m_outerIndex[i+1]; ++k)
+ s << "(_,_) ";
+ }
+ s << std::endl;
+ s << std::endl;
+ s << "Outer pointers:\n";
+ for (Index i=0; i<m.outerSize(); ++i)
+ s << m.m_outerIndex[i] << " ";
+ s << " $" << std::endl;
+ if(!m.isCompressed())
+ {
+ s << "Inner non zeros:\n";
+ for (Index i=0; i<m.outerSize(); ++i)
+ s << m.m_innerNonZeros[i] << " ";
+ s << " $" << std::endl;
+ }
+ s << std::endl;
+ );
+ s << static_cast<const SparseMatrixBase<SparseMatrix>&>(m);
+ return s;
+ }
+
+ /** Destructor */
+ inline ~SparseMatrix()
+ {
+ delete[] m_outerIndex;
+ delete[] m_innerNonZeros;
+ }
+
+#ifndef EIGEN_PARSED_BY_DOXYGEN
+ /** Overloaded for performance */
+ Scalar sum() const;
+#endif
+
+# ifdef EIGEN_SPARSEMATRIX_PLUGIN
+# include EIGEN_SPARSEMATRIX_PLUGIN
+# endif
+
+protected:
+
+ template<typename Other>
+ void initAssignment(const Other& other)
+ {
+ resize(other.rows(), other.cols());
+ if(m_innerNonZeros)
+ {
+ delete[] m_innerNonZeros;
+ m_innerNonZeros = 0;
+ }
+ }
+
+ /** \internal
+ * \sa insert(Index,Index) */
+ EIGEN_DONT_INLINE Scalar& insertCompressed(Index row, Index col)
+ {
+ eigen_assert(isCompressed());
+
+ const Index outer = IsRowMajor ? row : col;
+ const Index inner = IsRowMajor ? col : row;
+
+ Index previousOuter = outer;
+ if (m_outerIndex[outer+1]==0)
+ {
+ // we start a new inner vector
+ while (previousOuter>=0 && m_outerIndex[previousOuter]==0)
+ {
+ m_outerIndex[previousOuter] = static_cast<Index>(m_data.size());
+ --previousOuter;
+ }
+ m_outerIndex[outer+1] = m_outerIndex[outer];
+ }
+
+ // here we have to handle the tricky case where the outerIndex array
+ // starts with: [ 0 0 0 0 0 1 ...] and we are inserted in, e.g.,
+ // the 2nd inner vector...
+ bool isLastVec = (!(previousOuter==-1 && m_data.size()!=0))
+ && (size_t(m_outerIndex[outer+1]) == m_data.size());
+
+ size_t startId = m_outerIndex[outer];
+ // FIXME let's make sure sizeof(long int) == sizeof(size_t)
+ size_t p = m_outerIndex[outer+1];
+ ++m_outerIndex[outer+1];
+
+ float reallocRatio = 1;
+ if (m_data.allocatedSize()<=m_data.size())
+ {
+ // if there is no preallocated memory, let's reserve a minimum of 32 elements
+ if (m_data.size()==0)
+ {
+ m_data.reserve(32);
+ }
+ else
+ {
+ // we need to reallocate the data, to reduce multiple reallocations
+ // we use a smart resize algorithm based on the current filling ratio
+ // in addition, we use float to avoid integers overflows
+ float nnzEstimate = float(m_outerIndex[outer])*float(m_outerSize)/float(outer+1);
+ reallocRatio = (nnzEstimate-float(m_data.size()))/float(m_data.size());
+ // furthermore we bound the realloc ratio to:
+ // 1) reduce multiple minor realloc when the matrix is almost filled
+ // 2) avoid to allocate too much memory when the matrix is almost empty
+ reallocRatio = (std::min)((std::max)(reallocRatio,1.5f),8.f);
+ }
+ }
+ m_data.resize(m_data.size()+1,reallocRatio);
+
+ if (!isLastVec)
+ {
+ if (previousOuter==-1)
+ {
+ // oops wrong guess.
+ // let's correct the outer offsets
+ for (Index k=0; k<=(outer+1); ++k)
+ m_outerIndex[k] = 0;
+ Index k=outer+1;
+ while(m_outerIndex[k]==0)
+ m_outerIndex[k++] = 1;
+ while (k<=m_outerSize && m_outerIndex[k]!=0)
+ m_outerIndex[k++]++;
+ p = 0;
+ --k;
+ k = m_outerIndex[k]-1;
+ while (k>0)
+ {
+ m_data.index(k) = m_data.index(k-1);
+ m_data.value(k) = m_data.value(k-1);
+ k--;
+ }
+ }
+ else
+ {
+ // we are not inserting into the last inner vec
+ // update outer indices:
+ Index j = outer+2;
+ while (j<=m_outerSize && m_outerIndex[j]!=0)
+ m_outerIndex[j++]++;
+ --j;
+ // shift data of last vecs:
+ Index k = m_outerIndex[j]-1;
+ while (k>=Index(p))
+ {
+ m_data.index(k) = m_data.index(k-1);
+ m_data.value(k) = m_data.value(k-1);
+ k--;
+ }
+ }
+ }
+
+ while ( (p > startId) && (m_data.index(p-1) > inner) )
+ {
+ m_data.index(p) = m_data.index(p-1);
+ m_data.value(p) = m_data.value(p-1);
+ --p;
+ }
+
+ m_data.index(p) = inner;
+ return (m_data.value(p) = 0);
+ }
+
+ /** \internal
+ * A vector object that is equal to 0 everywhere but v at the position i */
+ class SingletonVector
+ {
+ Index m_index;
+ Index m_value;
+ public:
+ typedef Index value_type;
+ SingletonVector(Index i, Index v)
+ : m_index(i), m_value(v)
+ {}
+
+ Index operator[](Index i) const { return i==m_index ? m_value : 0; }
+ };
+
+ /** \internal
+ * \sa insert(Index,Index) */
+ EIGEN_DONT_INLINE Scalar& insertUncompressed(Index row, Index col)
+ {
+ eigen_assert(!isCompressed());
+
+ const Index outer = IsRowMajor ? row : col;
+ const Index inner = IsRowMajor ? col : row;
+
+ std::ptrdiff_t room = m_outerIndex[outer+1] - m_outerIndex[outer];
+ std::ptrdiff_t innerNNZ = m_innerNonZeros[outer];
+ if(innerNNZ>=room)
+ {
+ // this inner vector is full, we need to reallocate the whole buffer :(
+ reserve(SingletonVector(outer,std::max<std::ptrdiff_t>(2,innerNNZ)));
+ }
+
+ Index startId = m_outerIndex[outer];
+ Index p = startId + m_innerNonZeros[outer];
+ while ( (p > startId) && (m_data.index(p-1) > inner) )
+ {
+ m_data.index(p) = m_data.index(p-1);
+ m_data.value(p) = m_data.value(p-1);
+ --p;
+ }
+
+ m_innerNonZeros[outer]++;
+
+ m_data.index(p) = inner;
+ return (m_data.value(p) = 0);
+ }
+
+public:
+ /** \internal
+ * \sa insert(Index,Index) */
+ inline Scalar& insertBackUncompressed(Index row, Index col)
+ {
+ const Index outer = IsRowMajor ? row : col;
+ const Index inner = IsRowMajor ? col : row;
+
+ eigen_assert(!isCompressed());
+ eigen_assert(m_innerNonZeros[outer]<=(m_outerIndex[outer+1] - m_outerIndex[outer]));
+
+ Index p = m_outerIndex[outer] + m_innerNonZeros[outer];
+ m_innerNonZeros[outer]++;
+ m_data.index(p) = inner;
+ return (m_data.value(p) = 0);
+ }
+
+private:
+ static void check_template_parameters()
+ {
+ EIGEN_STATIC_ASSERT(NumTraits<Index>::IsSigned,THE_INDEX_TYPE_MUST_BE_A_SIGNED_TYPE);
+ }
+
+ struct default_prunning_func {
+ default_prunning_func(Scalar ref, RealScalar eps) : reference(ref), epsilon(eps) {}
+ inline bool operator() (const Index&, const Index&, const Scalar& value) const
+ {
+ return !internal::isMuchSmallerThan(value, reference, epsilon);
+ }
+ Scalar reference;
+ RealScalar epsilon;
+ };
+};
+
+template<typename Scalar, int _Options, typename _Index>
+class SparseMatrix<Scalar,_Options,_Index>::InnerIterator
+{
+ public:
+ InnerIterator(const SparseMatrix& mat, Index outer)
+ : m_values(mat.valuePtr()), m_indices(mat.innerIndexPtr()), m_outer(outer), m_id(mat.m_outerIndex[outer])
+ {
+ if(mat.isCompressed())
+ m_end = mat.m_outerIndex[outer+1];
+ else
+ m_end = m_id + mat.m_innerNonZeros[outer];
+ }
+
+ inline InnerIterator& operator++() { m_id++; return *this; }
+
+ inline const Scalar& value() const { return m_values[m_id]; }
+ inline Scalar& valueRef() { return const_cast<Scalar&>(m_values[m_id]); }
+
+ inline Index index() const { return m_indices[m_id]; }
+ inline Index outer() const { return m_outer; }
+ inline Index row() const { return IsRowMajor ? m_outer : index(); }
+ inline Index col() const { return IsRowMajor ? index() : m_outer; }
+
+ inline operator bool() const { return (m_id < m_end); }
+
+ protected:
+ const Scalar* m_values;
+ const Index* m_indices;
+ const Index m_outer;
+ Index m_id;
+ Index m_end;
+};
+
+template<typename Scalar, int _Options, typename _Index>
+class SparseMatrix<Scalar,_Options,_Index>::ReverseInnerIterator
+{
+ public:
+ ReverseInnerIterator(const SparseMatrix& mat, Index outer)
+ : m_values(mat.valuePtr()), m_indices(mat.innerIndexPtr()), m_outer(outer), m_start(mat.m_outerIndex[outer])
+ {
+ if(mat.isCompressed())
+ m_id = mat.m_outerIndex[outer+1];
+ else
+ m_id = m_start + mat.m_innerNonZeros[outer];
+ }
+
+ inline ReverseInnerIterator& operator--() { --m_id; return *this; }
+
+ inline const Scalar& value() const { return m_values[m_id-1]; }
+ inline Scalar& valueRef() { return const_cast<Scalar&>(m_values[m_id-1]); }
+
+ inline Index index() const { return m_indices[m_id-1]; }
+ inline Index outer() const { return m_outer; }
+ inline Index row() const { return IsRowMajor ? m_outer : index(); }
+ inline Index col() const { return IsRowMajor ? index() : m_outer; }
+
+ inline operator bool() const { return (m_id > m_start); }
+
+ protected:
+ const Scalar* m_values;
+ const Index* m_indices;
+ const Index m_outer;
+ Index m_id;
+ const Index m_start;
+};
+
+namespace internal {
+
+template<typename InputIterator, typename SparseMatrixType>
+void set_from_triplets(const InputIterator& begin, const InputIterator& end, SparseMatrixType& mat, int Options = 0)
+{
+ EIGEN_UNUSED_VARIABLE(Options);
+ enum { IsRowMajor = SparseMatrixType::IsRowMajor };
+ typedef typename SparseMatrixType::Scalar Scalar;
+ typedef typename SparseMatrixType::Index Index;
+ SparseMatrix<Scalar,IsRowMajor?ColMajor:RowMajor> trMat(mat.rows(),mat.cols());
+
+ // pass 1: count the nnz per inner-vector
+ VectorXi wi(trMat.outerSize());
+ wi.setZero();
+ for(InputIterator it(begin); it!=end; ++it)
+ wi(IsRowMajor ? it->col() : it->row())++;
+
+ // pass 2: insert all the elements into trMat
+ trMat.reserve(wi);
+ for(InputIterator it(begin); it!=end; ++it)
+ trMat.insertBackUncompressed(it->row(),it->col()) = it->value();
+
+ // pass 3:
+ trMat.sumupDuplicates();
+
+ // pass 4: transposed copy -> implicit sorting
+ mat = trMat;
+}
+
+}
+
+
+/** Fill the matrix \c *this with the list of \em triplets defined by the iterator range \a begin - \b.
+ *
+ * A \em triplet is a tuple (i,j,value) defining a non-zero element.
+ * The input list of triplets does not have to be sorted, and can contains duplicated elements.
+ * In any case, the result is a \b sorted and \b compressed sparse matrix where the duplicates have been summed up.
+ * This is a \em O(n) operation, with \em n the number of triplet elements.
+ * The initial contents of \c *this is destroyed.
+ * The matrix \c *this must be properly resized beforehand using the SparseMatrix(Index,Index) constructor,
+ * or the resize(Index,Index) method. The sizes are not extracted from the triplet list.
+ *
+ * The \a InputIterators value_type must provide the following interface:
+ * \code
+ * Scalar value() const; // the value
+ * Scalar row() const; // the row index i
+ * Scalar col() const; // the column index j
+ * \endcode
+ * See for instance the Eigen::Triplet template class.
+ *
+ * Here is a typical usage example:
+ * \code
+ typedef Triplet<double> T;
+ std::vector<T> tripletList;
+ triplets.reserve(estimation_of_entries);
+ for(...)
+ {
+ // ...
+ tripletList.push_back(T(i,j,v_ij));
+ }
+ SparseMatrixType m(rows,cols);
+ m.setFromTriplets(tripletList.begin(), tripletList.end());
+ // m is ready to go!
+ * \endcode
+ *
+ * \warning The list of triplets is read multiple times (at least twice). Therefore, it is not recommended to define
+ * an abstract iterator over a complex data-structure that would be expensive to evaluate. The triplets should rather
+ * be explicitely stored into a std::vector for instance.
+ */
+template<typename Scalar, int _Options, typename _Index>
+template<typename InputIterators>
+void SparseMatrix<Scalar,_Options,_Index>::setFromTriplets(const InputIterators& begin, const InputIterators& end)
+{
+ internal::set_from_triplets(begin, end, *this);
+}
+
+/** \internal */
+template<typename Scalar, int _Options, typename _Index>
+void SparseMatrix<Scalar,_Options,_Index>::sumupDuplicates()
+{
+ eigen_assert(!isCompressed());
+ // TODO, in practice we should be able to use m_innerNonZeros for that task
+ VectorXi wi(innerSize());
+ wi.fill(-1);
+ Index count = 0;
+ // for each inner-vector, wi[inner_index] will hold the position of first element into the index/value buffers
+ for(int j=0; j<outerSize(); ++j)
+ {
+ Index start = count;
+ Index oldEnd = m_outerIndex[j]+m_innerNonZeros[j];
+ for(Index k=m_outerIndex[j]; k<oldEnd; ++k)
+ {
+ Index i = m_data.index(k);
+ if(wi(i)>=start)
+ {
+ // we already meet this entry => accumulate it
+ m_data.value(wi(i)) += m_data.value(k);
+ }
+ else
+ {
+ m_data.value(count) = m_data.value(k);
+ m_data.index(count) = m_data.index(k);
+ wi(i) = count;
+ ++count;
+ }
+ }
+ m_outerIndex[j] = start;
+ }
+ m_outerIndex[m_outerSize] = count;
+
+ // turn the matrix into compressed form
+ delete[] m_innerNonZeros;
+ m_innerNonZeros = 0;
+ m_data.resize(m_outerIndex[m_outerSize]);
+}
+
+} // end namespace Eigen
+
+#endif // EIGEN_SPARSEMATRIX_H
diff --git a/Eigen/src/SparseCore/SparseMatrixBase.h b/Eigen/src/SparseCore/SparseMatrixBase.h
new file mode 100644
index 000000000..9a1258097
--- /dev/null
+++ b/Eigen/src/SparseCore/SparseMatrixBase.h
@@ -0,0 +1,458 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra.
+//
+// Copyright (C) 2008-2011 Gael Guennebaud <gael.guennebaud@inria.fr>
+//
+// This Source Code Form is subject to the terms of the Mozilla
+// Public License v. 2.0. If a copy of the MPL was not distributed
+// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+#ifndef EIGEN_SPARSEMATRIXBASE_H
+#define EIGEN_SPARSEMATRIXBASE_H
+
+namespace Eigen {
+
+/** \ingroup SparseCore_Module
+ *
+ * \class SparseMatrixBase
+ *
+ * \brief Base class of any sparse matrices or sparse expressions
+ *
+ * \tparam Derived
+ *
+ * This class can be extended with the help of the plugin mechanism described on the page
+ * \ref TopicCustomizingEigen by defining the preprocessor symbol \c EIGEN_SPARSEMATRIXBASE_PLUGIN.
+ */
+template<typename Derived> class SparseMatrixBase : public EigenBase<Derived>
+{
+ public:
+
+ typedef typename internal::traits<Derived>::Scalar Scalar;
+ typedef typename internal::packet_traits<Scalar>::type PacketScalar;
+ typedef typename internal::traits<Derived>::StorageKind StorageKind;
+ typedef typename internal::traits<Derived>::Index Index;
+ typedef typename internal::add_const_on_value_type_if_arithmetic<
+ typename internal::packet_traits<Scalar>::type
+ >::type PacketReturnType;
+
+ typedef SparseMatrixBase StorageBaseType;
+ typedef EigenBase<Derived> Base;
+
+ template<typename OtherDerived>
+ Derived& operator=(const EigenBase<OtherDerived> &other)
+ {
+ other.derived().evalTo(derived());
+ return derived();
+ }
+
+ enum {
+
+ RowsAtCompileTime = internal::traits<Derived>::RowsAtCompileTime,
+ /**< The number of rows at compile-time. This is just a copy of the value provided
+ * by the \a Derived type. If a value is not known at compile-time,
+ * it is set to the \a Dynamic constant.
+ * \sa MatrixBase::rows(), MatrixBase::cols(), ColsAtCompileTime, SizeAtCompileTime */
+
+ ColsAtCompileTime = internal::traits<Derived>::ColsAtCompileTime,
+ /**< The number of columns at compile-time. This is just a copy of the value provided
+ * by the \a Derived type. If a value is not known at compile-time,
+ * it is set to the \a Dynamic constant.
+ * \sa MatrixBase::rows(), MatrixBase::cols(), RowsAtCompileTime, SizeAtCompileTime */
+
+
+ SizeAtCompileTime = (internal::size_at_compile_time<internal::traits<Derived>::RowsAtCompileTime,
+ internal::traits<Derived>::ColsAtCompileTime>::ret),
+ /**< This is equal to the number of coefficients, i.e. the number of
+ * rows times the number of columns, or to \a Dynamic if this is not
+ * known at compile-time. \sa RowsAtCompileTime, ColsAtCompileTime */
+
+ MaxRowsAtCompileTime = RowsAtCompileTime,
+ MaxColsAtCompileTime = ColsAtCompileTime,
+
+ MaxSizeAtCompileTime = (internal::size_at_compile_time<MaxRowsAtCompileTime,
+ MaxColsAtCompileTime>::ret),
+
+ IsVectorAtCompileTime = RowsAtCompileTime == 1 || ColsAtCompileTime == 1,
+ /**< This is set to true if either the number of rows or the number of
+ * columns is known at compile-time to be equal to 1. Indeed, in that case,
+ * we are dealing with a column-vector (if there is only one column) or with
+ * a row-vector (if there is only one row). */
+
+ Flags = internal::traits<Derived>::Flags,
+ /**< This stores expression \ref flags flags which may or may not be inherited by new expressions
+ * constructed from this one. See the \ref flags "list of flags".
+ */
+
+ CoeffReadCost = internal::traits<Derived>::CoeffReadCost,
+ /**< This is a rough measure of how expensive it is to read one coefficient from
+ * this expression.
+ */
+
+ IsRowMajor = Flags&RowMajorBit ? 1 : 0,
+
+ #ifndef EIGEN_PARSED_BY_DOXYGEN
+ _HasDirectAccess = (int(Flags)&DirectAccessBit) ? 1 : 0 // workaround sunCC
+ #endif
+ };
+
+ /** \internal the return type of MatrixBase::adjoint() */
+ typedef typename internal::conditional<NumTraits<Scalar>::IsComplex,
+ CwiseUnaryOp<internal::scalar_conjugate_op<Scalar>, Eigen::Transpose<const Derived> >,
+ Transpose<const Derived>
+ >::type AdjointReturnType;
+
+
+ typedef SparseMatrix<Scalar, Flags&RowMajorBit ? RowMajor : ColMajor> PlainObject;
+
+
+#ifndef EIGEN_PARSED_BY_DOXYGEN
+ /** This is the "real scalar" type; if the \a Scalar type is already real numbers
+ * (e.g. int, float or double) then \a RealScalar is just the same as \a Scalar. If
+ * \a Scalar is \a std::complex<T> then RealScalar is \a T.
+ *
+ * \sa class NumTraits
+ */
+ typedef typename NumTraits<Scalar>::Real RealScalar;
+
+ /** \internal the return type of coeff()
+ */
+ typedef typename internal::conditional<_HasDirectAccess, const Scalar&, Scalar>::type CoeffReturnType;
+
+ /** \internal Represents a matrix with all coefficients equal to one another*/
+ typedef CwiseNullaryOp<internal::scalar_constant_op<Scalar>,Matrix<Scalar,Dynamic,Dynamic> > ConstantReturnType;
+
+ /** type of the equivalent square matrix */
+ typedef Matrix<Scalar,EIGEN_SIZE_MAX(RowsAtCompileTime,ColsAtCompileTime),
+ EIGEN_SIZE_MAX(RowsAtCompileTime,ColsAtCompileTime)> SquareMatrixType;
+
+ inline const Derived& derived() const { return *static_cast<const Derived*>(this); }
+ inline Derived& derived() { return *static_cast<Derived*>(this); }
+ inline Derived& const_cast_derived() const
+ { return *static_cast<Derived*>(const_cast<SparseMatrixBase*>(this)); }
+#endif // not EIGEN_PARSED_BY_DOXYGEN
+
+#define EIGEN_CURRENT_STORAGE_BASE_CLASS Eigen::SparseMatrixBase
+# include "../plugins/CommonCwiseUnaryOps.h"
+# include "../plugins/CommonCwiseBinaryOps.h"
+# include "../plugins/MatrixCwiseUnaryOps.h"
+# include "../plugins/MatrixCwiseBinaryOps.h"
+# ifdef EIGEN_SPARSEMATRIXBASE_PLUGIN
+# include EIGEN_SPARSEMATRIXBASE_PLUGIN
+# endif
+# undef EIGEN_CURRENT_STORAGE_BASE_CLASS
+#undef EIGEN_CURRENT_STORAGE_BASE_CLASS
+
+
+ /** \returns the number of rows. \sa cols() */
+ inline Index rows() const { return derived().rows(); }
+ /** \returns the number of columns. \sa rows() */
+ inline Index cols() const { return derived().cols(); }
+ /** \returns the number of coefficients, which is \a rows()*cols().
+ * \sa rows(), cols(). */
+ inline Index size() const { return rows() * cols(); }
+ /** \returns the number of nonzero coefficients which is in practice the number
+ * of stored coefficients. */
+ inline Index nonZeros() const { return derived().nonZeros(); }
+ /** \returns true if either the number of rows or the number of columns is equal to 1.
+ * In other words, this function returns
+ * \code rows()==1 || cols()==1 \endcode
+ * \sa rows(), cols(), IsVectorAtCompileTime. */
+ inline bool isVector() const { return rows()==1 || cols()==1; }
+ /** \returns the size of the storage major dimension,
+ * i.e., the number of columns for a columns major matrix, and the number of rows otherwise */
+ Index outerSize() const { return (int(Flags)&RowMajorBit) ? this->rows() : this->cols(); }
+ /** \returns the size of the inner dimension according to the storage order,
+ * i.e., the number of rows for a columns major matrix, and the number of cols otherwise */
+ Index innerSize() const { return (int(Flags)&RowMajorBit) ? this->cols() : this->rows(); }
+
+ bool isRValue() const { return m_isRValue; }
+ Derived& markAsRValue() { m_isRValue = true; return derived(); }
+
+ SparseMatrixBase() : m_isRValue(false) { /* TODO check flags */ }
+
+
+ template<typename OtherDerived>
+ Derived& operator=(const ReturnByValue<OtherDerived>& other)
+ {
+ other.evalTo(derived());
+ return derived();
+ }
+
+
+ template<typename OtherDerived>
+ inline Derived& operator=(const SparseMatrixBase<OtherDerived>& other)
+ {
+ return assign(other.derived());
+ }
+
+ inline Derived& operator=(const Derived& other)
+ {
+// if (other.isRValue())
+// derived().swap(other.const_cast_derived());
+// else
+ return assign(other.derived());
+ }
+
+ protected:
+
+ template<typename OtherDerived>
+ inline Derived& assign(const OtherDerived& other)
+ {
+ const bool transpose = (Flags & RowMajorBit) != (OtherDerived::Flags & RowMajorBit);
+ const Index outerSize = (int(OtherDerived::Flags) & RowMajorBit) ? other.rows() : other.cols();
+ if ((!transpose) && other.isRValue())
+ {
+ // eval without temporary
+ derived().resize(other.rows(), other.cols());
+ derived().setZero();
+ derived().reserve((std::max)(this->rows(),this->cols())*2);
+ for (Index j=0; j<outerSize; ++j)
+ {
+ derived().startVec(j);
+ for (typename OtherDerived::InnerIterator it(other, j); it; ++it)
+ {
+ Scalar v = it.value();
+ derived().insertBackByOuterInner(j,it.index()) = v;
+ }
+ }
+ derived().finalize();
+ }
+ else
+ {
+ assignGeneric(other);
+ }
+ return derived();
+ }
+
+ template<typename OtherDerived>
+ inline void assignGeneric(const OtherDerived& other)
+ {
+ //const bool transpose = (Flags & RowMajorBit) != (OtherDerived::Flags & RowMajorBit);
+ eigen_assert(( ((internal::traits<Derived>::SupportedAccessPatterns&OuterRandomAccessPattern)==OuterRandomAccessPattern) ||
+ (!((Flags & RowMajorBit) != (OtherDerived::Flags & RowMajorBit)))) &&
+ "the transpose operation is supposed to be handled in SparseMatrix::operator=");
+
+ enum { Flip = (Flags & RowMajorBit) != (OtherDerived::Flags & RowMajorBit) };
+
+ const Index outerSize = other.outerSize();
+ //typedef typename internal::conditional<transpose, LinkedVectorMatrix<Scalar,Flags&RowMajorBit>, Derived>::type TempType;
+ // thanks to shallow copies, we always eval to a tempary
+ Derived temp(other.rows(), other.cols());
+
+ temp.reserve((std::max)(this->rows(),this->cols())*2);
+ for (Index j=0; j<outerSize; ++j)
+ {
+ temp.startVec(j);
+ for (typename OtherDerived::InnerIterator it(other.derived(), j); it; ++it)
+ {
+ Scalar v = it.value();
+ temp.insertBackByOuterInner(Flip?it.index():j,Flip?j:it.index()) = v;
+ }
+ }
+ temp.finalize();
+
+ derived() = temp.markAsRValue();
+ }
+
+ public:
+
+ template<typename Lhs, typename Rhs>
+ inline Derived& operator=(const SparseSparseProduct<Lhs,Rhs>& product);
+
+ friend std::ostream & operator << (std::ostream & s, const SparseMatrixBase& m)
+ {
+ typedef typename Derived::Nested Nested;
+ typedef typename internal::remove_all<Nested>::type NestedCleaned;
+
+ if (Flags&RowMajorBit)
+ {
+ const Nested nm(m.derived());
+ for (Index row=0; row<nm.outerSize(); ++row)
+ {
+ Index col = 0;
+ for (typename NestedCleaned::InnerIterator it(nm.derived(), row); it; ++it)
+ {
+ for ( ; col<it.index(); ++col)
+ s << "0 ";
+ s << it.value() << " ";
+ ++col;
+ }
+ for ( ; col<m.cols(); ++col)
+ s << "0 ";
+ s << std::endl;
+ }
+ }
+ else
+ {
+ const Nested nm(m.derived());
+ if (m.cols() == 1) {
+ Index row = 0;
+ for (typename NestedCleaned::InnerIterator it(nm.derived(), 0); it; ++it)
+ {
+ for ( ; row<it.index(); ++row)
+ s << "0" << std::endl;
+ s << it.value() << std::endl;
+ ++row;
+ }
+ for ( ; row<m.rows(); ++row)
+ s << "0" << std::endl;
+ }
+ else
+ {
+ SparseMatrix<Scalar, RowMajorBit> trans = m;
+ s << static_cast<const SparseMatrixBase<SparseMatrix<Scalar, RowMajorBit> >&>(trans);
+ }
+ }
+ return s;
+ }
+
+ template<typename OtherDerived>
+ Derived& operator+=(const SparseMatrixBase<OtherDerived>& other);
+ template<typename OtherDerived>
+ Derived& operator-=(const SparseMatrixBase<OtherDerived>& other);
+
+ Derived& operator*=(const Scalar& other);
+ Derived& operator/=(const Scalar& other);
+
+ #define EIGEN_SPARSE_CWISE_PRODUCT_RETURN_TYPE \
+ CwiseBinaryOp< \
+ internal::scalar_product_op< \
+ typename internal::scalar_product_traits< \
+ typename internal::traits<Derived>::Scalar, \
+ typename internal::traits<OtherDerived>::Scalar \
+ >::ReturnType \
+ >, \
+ Derived, \
+ OtherDerived \
+ >
+
+ template<typename OtherDerived>
+ EIGEN_STRONG_INLINE const EIGEN_SPARSE_CWISE_PRODUCT_RETURN_TYPE
+ cwiseProduct(const MatrixBase<OtherDerived> &other) const;
+
+ // sparse * sparse
+ template<typename OtherDerived>
+ const typename SparseSparseProductReturnType<Derived,OtherDerived>::Type
+ operator*(const SparseMatrixBase<OtherDerived> &other) const;
+
+ // sparse * diagonal
+ template<typename OtherDerived>
+ const SparseDiagonalProduct<Derived,OtherDerived>
+ operator*(const DiagonalBase<OtherDerived> &other) const;
+
+ // diagonal * sparse
+ template<typename OtherDerived> friend
+ const SparseDiagonalProduct<OtherDerived,Derived>
+ operator*(const DiagonalBase<OtherDerived> &lhs, const SparseMatrixBase& rhs)
+ { return SparseDiagonalProduct<OtherDerived,Derived>(lhs.derived(), rhs.derived()); }
+
+ /** dense * sparse (return a dense object unless it is an outer product) */
+ template<typename OtherDerived> friend
+ const typename DenseSparseProductReturnType<OtherDerived,Derived>::Type
+ operator*(const MatrixBase<OtherDerived>& lhs, const Derived& rhs)
+ { return typename DenseSparseProductReturnType<OtherDerived,Derived>::Type(lhs.derived(),rhs); }
+
+ /** sparse * dense (returns a dense object unless it is an outer product) */
+ template<typename OtherDerived>
+ const typename SparseDenseProductReturnType<Derived,OtherDerived>::Type
+ operator*(const MatrixBase<OtherDerived> &other) const;
+
+ /** \returns an expression of P H P^-1 where H is the matrix represented by \c *this */
+ SparseSymmetricPermutationProduct<Derived,Upper|Lower> twistedBy(const PermutationMatrix<Dynamic,Dynamic,Index>& perm) const
+ {
+ return SparseSymmetricPermutationProduct<Derived,Upper|Lower>(derived(), perm);
+ }
+
+ template<typename OtherDerived>
+ Derived& operator*=(const SparseMatrixBase<OtherDerived>& other);
+
+ #ifdef EIGEN2_SUPPORT
+ // deprecated
+ template<typename OtherDerived>
+ typename internal::plain_matrix_type_column_major<OtherDerived>::type
+ solveTriangular(const MatrixBase<OtherDerived>& other) const;
+
+ // deprecated
+ template<typename OtherDerived>
+ void solveTriangularInPlace(MatrixBase<OtherDerived>& other) const;
+ #endif // EIGEN2_SUPPORT
+
+ template<int Mode>
+ inline const SparseTriangularView<Derived, Mode> triangularView() const;
+
+ template<unsigned int UpLo> inline const SparseSelfAdjointView<Derived, UpLo> selfadjointView() const;
+ template<unsigned int UpLo> inline SparseSelfAdjointView<Derived, UpLo> selfadjointView();
+
+ template<typename OtherDerived> Scalar dot(const MatrixBase<OtherDerived>& other) const;
+ template<typename OtherDerived> Scalar dot(const SparseMatrixBase<OtherDerived>& other) const;
+ RealScalar squaredNorm() const;
+ RealScalar norm() const;
+
+ Transpose<Derived> transpose() { return derived(); }
+ const Transpose<const Derived> transpose() const { return derived(); }
+ const AdjointReturnType adjoint() const { return transpose(); }
+
+ // sub-vector
+ SparseInnerVectorSet<Derived,1> row(Index i);
+ const SparseInnerVectorSet<Derived,1> row(Index i) const;
+ SparseInnerVectorSet<Derived,1> col(Index j);
+ const SparseInnerVectorSet<Derived,1> col(Index j) const;
+ SparseInnerVectorSet<Derived,1> innerVector(Index outer);
+ const SparseInnerVectorSet<Derived,1> innerVector(Index outer) const;
+
+ // set of sub-vectors
+ SparseInnerVectorSet<Derived,Dynamic> subrows(Index start, Index size);
+ const SparseInnerVectorSet<Derived,Dynamic> subrows(Index start, Index size) const;
+ SparseInnerVectorSet<Derived,Dynamic> subcols(Index start, Index size);
+ const SparseInnerVectorSet<Derived,Dynamic> subcols(Index start, Index size) const;
+
+ SparseInnerVectorSet<Derived,Dynamic> middleRows(Index start, Index size);
+ const SparseInnerVectorSet<Derived,Dynamic> middleRows(Index start, Index size) const;
+ SparseInnerVectorSet<Derived,Dynamic> middleCols(Index start, Index size);
+ const SparseInnerVectorSet<Derived,Dynamic> middleCols(Index start, Index size) const;
+ SparseInnerVectorSet<Derived,Dynamic> innerVectors(Index outerStart, Index outerSize);
+ const SparseInnerVectorSet<Derived,Dynamic> innerVectors(Index outerStart, Index outerSize) const;
+
+ /** \internal use operator= */
+ template<typename DenseDerived>
+ void evalTo(MatrixBase<DenseDerived>& dst) const
+ {
+ dst.setZero();
+ for (Index j=0; j<outerSize(); ++j)
+ for (typename Derived::InnerIterator i(derived(),j); i; ++i)
+ dst.coeffRef(i.row(),i.col()) = i.value();
+ }
+
+ Matrix<Scalar,RowsAtCompileTime,ColsAtCompileTime> toDense() const
+ {
+ return derived();
+ }
+
+ template<typename OtherDerived>
+ bool isApprox(const SparseMatrixBase<OtherDerived>& other,
+ RealScalar prec = NumTraits<Scalar>::dummy_precision()) const
+ { return toDense().isApprox(other.toDense(),prec); }
+
+ template<typename OtherDerived>
+ bool isApprox(const MatrixBase<OtherDerived>& other,
+ RealScalar prec = NumTraits<Scalar>::dummy_precision()) const
+ { return toDense().isApprox(other,prec); }
+
+ /** \returns the matrix or vector obtained by evaluating this expression.
+ *
+ * Notice that in the case of a plain matrix or vector (not an expression) this function just returns
+ * a const reference, in order to avoid a useless copy.
+ */
+ inline const typename internal::eval<Derived>::type eval() const
+ { return typename internal::eval<Derived>::type(derived()); }
+
+ Scalar sum() const;
+
+ protected:
+
+ bool m_isRValue;
+};
+
+} // end namespace Eigen
+
+#endif // EIGEN_SPARSEMATRIXBASE_H
diff --git a/Eigen/src/SparseCore/SparsePermutation.h b/Eigen/src/SparseCore/SparsePermutation.h
new file mode 100644
index 000000000..b897b7595
--- /dev/null
+++ b/Eigen/src/SparseCore/SparsePermutation.h
@@ -0,0 +1,148 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra.
+//
+// Copyright (C) 2012 Gael Guennebaud <gael.guennebaud@inria.fr>
+//
+// This Source Code Form is subject to the terms of the Mozilla
+// Public License v. 2.0. If 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<typename PermutationType, typename MatrixType, int Side, bool Transposed>
+struct traits<permut_sparsematrix_product_retval<PermutationType, MatrixType, Side, Transposed> >
+{
+ typedef typename remove_all<typename MatrixType::Nested>::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<MoveOuter,
+ SparseMatrix<Scalar,SrcStorageOrder,Index>,
+ SparseMatrix<Scalar,int(SrcStorageOrder)==RowMajor?ColMajor:RowMajor,Index> >::type ReturnType;
+};
+
+template<typename PermutationType, typename MatrixType, int Side, bool Transposed>
+struct permut_sparsematrix_product_retval
+ : public ReturnByValue<permut_sparsematrix_product_retval<PermutationType, MatrixType, Side, Transposed> >
+{
+ typedef typename remove_all<typename MatrixType::Nested>::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<typename Dest> inline void evalTo(Dest& dst) const
+ {
+ if(MoveOuter)
+ {
+ SparseMatrix<Scalar,SrcStorageOrder,Index> tmp(m_matrix.rows(), m_matrix.cols());
+ VectorXi sizes(m_matrix.outerSize());
+ for(Index j=0; j<m_matrix.outerSize(); ++j)
+ {
+ Index jp = m_permutation.indices().coeff(j);
+ sizes[((Side==OnTheLeft) ^ Transposed) ? jp : j] = m_matrix.innerVector(((Side==OnTheRight) ^ Transposed) ? jp : j).size();
+ }
+ tmp.reserve(sizes);
+ for(Index j=0; j<m_matrix.outerSize(); ++j)
+ {
+ Index jp = m_permutation.indices().coeff(j);
+ Index jsrc = ((Side==OnTheRight) ^ Transposed) ? jp : j;
+ Index jdst = ((Side==OnTheLeft) ^ Transposed) ? jp : j;
+ for(typename MatrixTypeNestedCleaned::InnerIterator it(m_matrix,jsrc); it; ++it)
+ tmp.insertByOuterInner(jdst,it.index()) = it.value();
+ }
+ dst = tmp;
+ }
+ else
+ {
+ SparseMatrix<Scalar,int(SrcStorageOrder)==RowMajor?ColMajor:RowMajor,Index> tmp(m_matrix.rows(), m_matrix.cols());
+ VectorXi sizes(tmp.outerSize());
+ sizes.setZero();
+ PermutationMatrix<Dynamic,Dynamic,Index> perm;
+ if((Side==OnTheLeft) ^ Transposed)
+ perm = m_permutation;
+ else
+ perm = m_permutation.transpose();
+
+ for(Index j=0; j<m_matrix.outerSize(); ++j)
+ for(typename MatrixTypeNestedCleaned::InnerIterator it(m_matrix,j); it; ++it)
+ sizes[perm.indices().coeff(it.index())]++;
+ tmp.reserve(sizes);
+ for(Index j=0; j<m_matrix.outerSize(); ++j)
+ for(typename MatrixTypeNestedCleaned::InnerIterator it(m_matrix,j); it; ++it)
+ tmp.insertByOuterInner(perm.indices().coeff(it.index()),j) = it.value();
+ dst = tmp;
+ }
+ }
+
+ protected:
+ const PermutationType& m_permutation;
+ typename MatrixType::Nested m_matrix;
+};
+
+}
+
+
+
+/** \returns the matrix with the permutation applied to the columns
+ */
+template<typename SparseDerived, typename PermDerived>
+inline const internal::permut_sparsematrix_product_retval<PermutationBase<PermDerived>, SparseDerived, OnTheRight, false>
+operator*(const SparseMatrixBase<SparseDerived>& matrix, const PermutationBase<PermDerived>& perm)
+{
+ return internal::permut_sparsematrix_product_retval<PermutationBase<PermDerived>, SparseDerived, OnTheRight, false>(perm, matrix.derived());
+}
+
+/** \returns the matrix with the permutation applied to the rows
+ */
+template<typename SparseDerived, typename PermDerived>
+inline const internal::permut_sparsematrix_product_retval<PermutationBase<PermDerived>, SparseDerived, OnTheLeft, false>
+operator*( const PermutationBase<PermDerived>& perm, const SparseMatrixBase<SparseDerived>& matrix)
+{
+ return internal::permut_sparsematrix_product_retval<PermutationBase<PermDerived>, SparseDerived, OnTheLeft, false>(perm, matrix.derived());
+}
+
+
+
+/** \returns the matrix with the inverse permutation applied to the columns.
+ */
+template<typename SparseDerived, typename PermDerived>
+inline const internal::permut_sparsematrix_product_retval<PermutationBase<PermDerived>, SparseDerived, OnTheRight, true>
+operator*(const SparseMatrixBase<SparseDerived>& matrix, const Transpose<PermutationBase<PermDerived> >& tperm)
+{
+ return internal::permut_sparsematrix_product_retval<PermutationBase<PermDerived>, SparseDerived, OnTheRight, true>(tperm.nestedPermutation(), matrix.derived());
+}
+
+/** \returns the matrix with the inverse permutation applied to the rows.
+ */
+template<typename SparseDerived, typename PermDerived>
+inline const internal::permut_sparsematrix_product_retval<PermutationBase<PermDerived>, SparseDerived, OnTheLeft, true>
+operator*(const Transpose<PermutationBase<PermDerived> >& tperm, const SparseMatrixBase<SparseDerived>& matrix)
+{
+ return internal::permut_sparsematrix_product_retval<PermutationBase<PermDerived>, SparseDerived, OnTheLeft, true>(tperm.nestedPermutation(), matrix.derived());
+}
+
+} // end namespace Eigen
+
+#endif // EIGEN_SPARSE_SELFADJOINTVIEW_H
diff --git a/Eigen/src/SparseCore/SparseProduct.h b/Eigen/src/SparseCore/SparseProduct.h
new file mode 100644
index 000000000..6a555b834
--- /dev/null
+++ b/Eigen/src/SparseCore/SparseProduct.h
@@ -0,0 +1,186 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra.
+//
+// Copyright (C) 2008-2010 Gael Guennebaud <gael.guennebaud@inria.fr>
+//
+// This Source Code Form is subject to the terms of the Mozilla
+// Public License v. 2.0. If 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<typename Lhs, typename Rhs>
+struct SparseSparseProductReturnType
+{
+ typedef typename internal::traits<Lhs>::Scalar Scalar;
+ enum {
+ LhsRowMajor = internal::traits<Lhs>::Flags & RowMajorBit,
+ RhsRowMajor = internal::traits<Rhs>::Flags & RowMajorBit,
+ TransposeRhs = (!LhsRowMajor) && RhsRowMajor,
+ TransposeLhs = LhsRowMajor && (!RhsRowMajor)
+ };
+
+ typedef typename internal::conditional<TransposeLhs,
+ SparseMatrix<Scalar,0>,
+ typename internal::nested<Lhs,Rhs::RowsAtCompileTime>::type>::type LhsNested;
+
+ typedef typename internal::conditional<TransposeRhs,
+ SparseMatrix<Scalar,0>,
+ typename internal::nested<Rhs,Lhs::RowsAtCompileTime>::type>::type RhsNested;
+
+ typedef SparseSparseProduct<LhsNested, RhsNested> Type;
+};
+
+namespace internal {
+template<typename LhsNested, typename RhsNested>
+struct traits<SparseSparseProduct<LhsNested, RhsNested> >
+{
+ typedef MatrixXpr XprKind;
+ // clean the nested types:
+ typedef typename remove_all<LhsNested>::type _LhsNested;
+ typedef typename remove_all<RhsNested>::type _RhsNested;
+ typedef typename _LhsNested::Scalar Scalar;
+ typedef typename promote_index_type<typename traits<_LhsNested>::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<typename LhsNested, typename RhsNested>
+class SparseSparseProduct : internal::no_assignment_operator,
+ public SparseMatrixBase<SparseSparseProduct<LhsNested, RhsNested> >
+{
+ public:
+
+ typedef SparseMatrixBase<SparseSparseProduct> Base;
+ EIGEN_DENSE_PUBLIC_INTERFACE(SparseSparseProduct)
+
+ private:
+
+ typedef typename internal::traits<SparseSparseProduct>::_LhsNested _LhsNested;
+ typedef typename internal::traits<SparseSparseProduct>::_RhsNested _RhsNested;
+
+ public:
+
+ template<typename Lhs, typename Rhs>
+ EIGEN_STRONG_INLINE SparseSparseProduct(const Lhs& lhs, const Rhs& rhs)
+ : m_lhs(lhs), m_rhs(rhs), m_tolerance(0), m_conservative(true)
+ {
+ init();
+ }
+
+ template<typename Lhs, typename Rhs>
+ EIGEN_STRONG_INLINE SparseSparseProduct(const Lhs& lhs, const Rhs& rhs, RealScalar tolerance)
+ : m_lhs(lhs), m_rhs(rhs), m_tolerance(tolerance), m_conservative(false)
+ {
+ init();
+ }
+
+ SparseSparseProduct pruned(Scalar reference = 0, RealScalar epsilon = NumTraits<RealScalar>::dummy_precision()) const
+ {
+ return SparseSparseProduct(m_lhs,m_rhs,internal::abs(reference)*epsilon);
+ }
+
+ template<typename Dest>
+ 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<typename Derived>
+template<typename Lhs, typename Rhs>
+inline Derived& SparseMatrixBase<Derived>::operator=(const SparseSparseProduct<Lhs,Rhs>& 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<typename Derived>
+template<typename OtherDerived>
+inline const typename SparseSparseProductReturnType<Derived,OtherDerived>::Type
+SparseMatrixBase<Derived>::operator*(const SparseMatrixBase<OtherDerived> &other) const
+{
+ return typename SparseSparseProductReturnType<Derived,OtherDerived>::Type(derived(), other.derived());
+}
+
+} // end namespace Eigen
+
+#endif // EIGEN_SPARSEPRODUCT_H
diff --git a/Eigen/src/SparseCore/SparseRedux.h b/Eigen/src/SparseCore/SparseRedux.h
new file mode 100644
index 000000000..f3da93a71
--- /dev/null
+++ b/Eigen/src/SparseCore/SparseRedux.h
@@ -0,0 +1,45 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra.
+//
+// Copyright (C) 2008 Gael Guennebaud <gael.guennebaud@inria.fr>
+//
+// This Source Code Form is subject to the terms of the Mozilla
+// Public License v. 2.0. If a copy of the MPL was not distributed
+// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+#ifndef EIGEN_SPARSEREDUX_H
+#define EIGEN_SPARSEREDUX_H
+
+namespace Eigen {
+
+template<typename Derived>
+typename internal::traits<Derived>::Scalar
+SparseMatrixBase<Derived>::sum() const
+{
+ eigen_assert(rows()>0 && cols()>0 && "you are using a non initialized matrix");
+ Scalar res(0);
+ for (Index j=0; j<outerSize(); ++j)
+ for (typename Derived::InnerIterator iter(derived(),j); iter; ++iter)
+ res += iter.value();
+ return res;
+}
+
+template<typename _Scalar, int _Options, typename _Index>
+typename internal::traits<SparseMatrix<_Scalar,_Options,_Index> >::Scalar
+SparseMatrix<_Scalar,_Options,_Index>::sum() const
+{
+ eigen_assert(rows()>0 && cols()>0 && "you are using a non initialized matrix");
+ return Matrix<Scalar,1,Dynamic>::Map(&m_data.value(0), m_data.size()).sum();
+}
+
+template<typename _Scalar, int _Options, typename _Index>
+typename internal::traits<SparseVector<_Scalar,_Options, _Index> >::Scalar
+SparseVector<_Scalar,_Options,_Index>::sum() const
+{
+ eigen_assert(rows()>0 && cols()>0 && "you are using a non initialized matrix");
+ return Matrix<Scalar,1,Dynamic>::Map(&m_data.value(0), m_data.size()).sum();
+}
+
+} // end namespace Eigen
+
+#endif // EIGEN_SPARSEREDUX_H
diff --git a/Eigen/src/SparseCore/SparseSelfAdjointView.h b/Eigen/src/SparseCore/SparseSelfAdjointView.h
new file mode 100644
index 000000000..86ec0a6c5
--- /dev/null
+++ b/Eigen/src/SparseCore/SparseSelfAdjointView.h
@@ -0,0 +1,480 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra.
+//
+// Copyright (C) 2009 Gael Guennebaud <gael.guennebaud@inria.fr>
+//
+// This Source Code Form is subject to the terms of the Mozilla
+// Public License v. 2.0. If 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<typename Lhs, typename Rhs, int UpLo>
+class SparseSelfAdjointTimeDenseProduct;
+
+template<typename Lhs, typename Rhs, int UpLo>
+class DenseTimeSparseSelfAdjointProduct;
+
+namespace internal {
+
+template<typename MatrixType, unsigned int UpLo>
+struct traits<SparseSelfAdjointView<MatrixType,UpLo> > : traits<MatrixType> {
+};
+
+template<int SrcUpLo,int DstUpLo,typename MatrixType,int DestOrder>
+void permute_symm_to_symm(const MatrixType& mat, SparseMatrix<typename MatrixType::Scalar,DestOrder,typename MatrixType::Index>& _dest, const typename MatrixType::Index* perm = 0);
+
+template<int UpLo,typename MatrixType,int DestOrder>
+void permute_symm_to_fullsymm(const MatrixType& mat, SparseMatrix<typename MatrixType::Scalar,DestOrder,typename MatrixType::Index>& _dest, const typename MatrixType::Index* perm = 0);
+
+}
+
+template<typename MatrixType, unsigned int UpLo> class SparseSelfAdjointView
+ : public EigenBase<SparseSelfAdjointView<MatrixType,UpLo> >
+{
+ public:
+
+ typedef typename MatrixType::Scalar Scalar;
+ typedef typename MatrixType::Index Index;
+ typedef Matrix<Index,Dynamic,1> VectorI;
+ typedef typename MatrixType::Nested MatrixTypeNested;
+ typedef typename internal::remove_all<MatrixTypeNested>::type _MatrixTypeNested;
+
+ inline SparseSelfAdjointView(const MatrixType& matrix) : m_matrix(matrix)
+ {
+ eigen_assert(rows()==cols() && "SelfAdjointView is only for squared matrices");
+ }
+
+ inline Index rows() const { return m_matrix.rows(); }
+ inline Index cols() const { return m_matrix.cols(); }
+
+ /** \internal \returns a reference to the nested matrix */
+ const _MatrixTypeNested& matrix() const { return m_matrix; }
+ _MatrixTypeNested& matrix() { return m_matrix.const_cast_derived(); }
+
+ /** Efficient sparse self-adjoint matrix times dense vector/matrix product */
+ template<typename OtherDerived>
+ SparseSelfAdjointTimeDenseProduct<MatrixType,OtherDerived,UpLo>
+ operator*(const MatrixBase<OtherDerived>& rhs) const
+ {
+ return SparseSelfAdjointTimeDenseProduct<MatrixType,OtherDerived,UpLo>(m_matrix, rhs.derived());
+ }
+
+ /** Efficient dense vector/matrix times sparse self-adjoint matrix product */
+ template<typename OtherDerived> friend
+ DenseTimeSparseSelfAdjointProduct<OtherDerived,MatrixType,UpLo>
+ operator*(const MatrixBase<OtherDerived>& lhs, const SparseSelfAdjointView& rhs)
+ {
+ return DenseTimeSparseSelfAdjointProduct<OtherDerived,_MatrixTypeNested,UpLo>(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<typename DerivedU>
+ SparseSelfAdjointView& rankUpdate(const SparseMatrixBase<DerivedU>& u, Scalar alpha = Scalar(1));
+
+ /** \internal triggered by sparse_matrix = SparseSelfadjointView; */
+ template<typename DestScalar,int StorageOrder> void evalTo(SparseMatrix<DestScalar,StorageOrder,Index>& _dest) const
+ {
+ internal::permute_symm_to_fullsymm<UpLo>(m_matrix, _dest);
+ }
+
+ template<typename DestScalar> void evalTo(DynamicSparseMatrix<DestScalar,ColMajor,Index>& _dest) const
+ {
+ // TODO directly evaluate into _dest;
+ SparseMatrix<DestScalar,ColMajor,Index> tmp(_dest.rows(),_dest.cols());
+ internal::permute_symm_to_fullsymm<UpLo>(m_matrix, tmp);
+ _dest = tmp;
+ }
+
+ /** \returns an expression of P H P^-1 */
+ SparseSymmetricPermutationProduct<_MatrixTypeNested,UpLo> twistedBy(const PermutationMatrix<Dynamic,Dynamic,Index>& perm) const
+ {
+ return SparseSymmetricPermutationProduct<_MatrixTypeNested,UpLo>(m_matrix, perm);
+ }
+
+ template<typename SrcMatrixType,int SrcUpLo>
+ SparseSelfAdjointView& operator=(const SparseSymmetricPermutationProduct<SrcMatrixType,SrcUpLo>& permutedMatrix)
+ {
+ permutedMatrix.evalTo(*this);
+ return *this;
+ }
+
+
+ SparseSelfAdjointView& operator=(const SparseSelfAdjointView& src)
+ {
+ PermutationMatrix<Dynamic> pnull;
+ return *this = src.twistedBy(pnull);
+ }
+
+ template<typename SrcMatrixType,unsigned int SrcUpLo>
+ SparseSelfAdjointView& operator=(const SparseSelfAdjointView<SrcMatrixType,SrcUpLo>& src)
+ {
+ PermutationMatrix<Dynamic> pnull;
+ return *this = src.twistedBy(pnull);
+ }
+
+
+ // const SparseLLT<PlainObject, UpLo> llt() const;
+ // const SparseLDLT<PlainObject, UpLo> ldlt() const;
+
+ protected:
+
+ typename MatrixType::Nested m_matrix;
+ mutable VectorI m_countPerRow;
+ mutable VectorI m_countPerCol;
+};
+
+/***************************************************************************
+* Implementation of SparseMatrixBase methods
+***************************************************************************/
+
+template<typename Derived>
+template<unsigned int UpLo>
+const SparseSelfAdjointView<Derived, UpLo> SparseMatrixBase<Derived>::selfadjointView() const
+{
+ return derived();
+}
+
+template<typename Derived>
+template<unsigned int UpLo>
+SparseSelfAdjointView<Derived, UpLo> SparseMatrixBase<Derived>::selfadjointView()
+{
+ return derived();
+}
+
+/***************************************************************************
+* Implementation of SparseSelfAdjointView methods
+***************************************************************************/
+
+template<typename MatrixType, unsigned int UpLo>
+template<typename DerivedU>
+SparseSelfAdjointView<MatrixType,UpLo>&
+SparseSelfAdjointView<MatrixType,UpLo>::rankUpdate(const SparseMatrixBase<DerivedU>& u, Scalar alpha)
+{
+ SparseMatrix<Scalar,MatrixType::Flags&RowMajorBit?RowMajor:ColMajor> tmp = u * u.adjoint();
+ if(alpha==Scalar(0))
+ m_matrix.const_cast_derived() = tmp.template triangularView<UpLo>();
+ else
+ m_matrix.const_cast_derived() += alpha * tmp.template triangularView<UpLo>();
+
+ return *this;
+}
+
+/***************************************************************************
+* Implementation of sparse self-adjoint time dense matrix
+***************************************************************************/
+
+namespace internal {
+template<typename Lhs, typename Rhs, int UpLo>
+struct traits<SparseSelfAdjointTimeDenseProduct<Lhs,Rhs,UpLo> >
+ : traits<ProductBase<SparseSelfAdjointTimeDenseProduct<Lhs,Rhs,UpLo>, Lhs, Rhs> >
+{
+ typedef Dense StorageKind;
+};
+}
+
+template<typename Lhs, typename Rhs, int UpLo>
+class SparseSelfAdjointTimeDenseProduct
+ : public ProductBase<SparseSelfAdjointTimeDenseProduct<Lhs,Rhs,UpLo>, Lhs, Rhs>
+{
+ public:
+ EIGEN_PRODUCT_PUBLIC_INTERFACE(SparseSelfAdjointTimeDenseProduct)
+
+ SparseSelfAdjointTimeDenseProduct(const Lhs& lhs, const Rhs& rhs) : Base(lhs,rhs)
+ {}
+
+ template<typename Dest> void scaleAndAddTo(Dest& dest, Scalar alpha) const
+ {
+ // TODO use alpha
+ eigen_assert(alpha==Scalar(1) && "alpha != 1 is not implemented yet, sorry");
+ typedef typename internal::remove_all<Lhs>::type _Lhs;
+ typedef typename internal::remove_all<Rhs>::type _Rhs;
+ typedef typename _Lhs::InnerIterator LhsInnerIterator;
+ enum {
+ LhsIsRowMajor = (_Lhs::Flags&RowMajorBit)==RowMajorBit,
+ ProcessFirstHalf =
+ ((UpLo&(Upper|Lower))==(Upper|Lower))
+ || ( (UpLo&Upper) && !LhsIsRowMajor)
+ || ( (UpLo&Lower) && LhsIsRowMajor),
+ ProcessSecondHalf = !ProcessFirstHalf
+ };
+ for (Index j=0; j<m_lhs.outerSize(); ++j)
+ {
+ LhsInnerIterator i(m_lhs,j);
+ if (ProcessSecondHalf)
+ {
+ while (i && i.index()<j) ++i;
+ if(i && i.index()==j)
+ {
+ dest.row(j) += i.value() * m_rhs.row(j);
+ ++i;
+ }
+ }
+ for(; (ProcessFirstHalf ? i && i.index() < j : i) ; ++i)
+ {
+ Index a = LhsIsRowMajor ? j : i.index();
+ Index b = LhsIsRowMajor ? i.index() : j;
+ typename Lhs::Scalar v = i.value();
+ dest.row(a) += (v) * m_rhs.row(b);
+ dest.row(b) += internal::conj(v) * m_rhs.row(a);
+ }
+ if (ProcessFirstHalf && i && (i.index()==j))
+ dest.row(j) += i.value() * m_rhs.row(j);
+ }
+ }
+
+ private:
+ SparseSelfAdjointTimeDenseProduct& operator=(const SparseSelfAdjointTimeDenseProduct&);
+};
+
+namespace internal {
+template<typename Lhs, typename Rhs, int UpLo>
+struct traits<DenseTimeSparseSelfAdjointProduct<Lhs,Rhs,UpLo> >
+ : traits<ProductBase<DenseTimeSparseSelfAdjointProduct<Lhs,Rhs,UpLo>, Lhs, Rhs> >
+{};
+}
+
+template<typename Lhs, typename Rhs, int UpLo>
+class DenseTimeSparseSelfAdjointProduct
+ : public ProductBase<DenseTimeSparseSelfAdjointProduct<Lhs,Rhs,UpLo>, Lhs, Rhs>
+{
+ public:
+ EIGEN_PRODUCT_PUBLIC_INTERFACE(DenseTimeSparseSelfAdjointProduct)
+
+ DenseTimeSparseSelfAdjointProduct(const Lhs& lhs, const Rhs& rhs) : Base(lhs,rhs)
+ {}
+
+ template<typename Dest> void scaleAndAddTo(Dest& /*dest*/, Scalar /*alpha*/) const
+ {
+ // TODO
+ }
+
+ private:
+ DenseTimeSparseSelfAdjointProduct& operator=(const DenseTimeSparseSelfAdjointProduct&);
+};
+
+/***************************************************************************
+* Implementation of symmetric copies and permutations
+***************************************************************************/
+namespace internal {
+
+template<typename MatrixType, int UpLo>
+struct traits<SparseSymmetricPermutationProduct<MatrixType,UpLo> > : traits<MatrixType> {
+};
+
+template<int UpLo,typename MatrixType,int DestOrder>
+void permute_symm_to_fullsymm(const MatrixType& mat, SparseMatrix<typename MatrixType::Scalar,DestOrder,typename MatrixType::Index>& _dest, const typename MatrixType::Index* perm)
+{
+ typedef typename MatrixType::Index Index;
+ typedef typename MatrixType::Scalar Scalar;
+ typedef SparseMatrix<Scalar,DestOrder,Index> Dest;
+ typedef Matrix<Index,Dynamic,1> 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; j<size; ++j)
+ {
+ Index jp = perm ? perm[j] : j;
+ for(typename MatrixType::InnerIterator it(mat,j); it; ++it)
+ {
+ Index i = it.index();
+ Index r = it.row();
+ Index c = it.col();
+ Index ip = perm ? perm[i] : i;
+ if(UpLo==(Upper|Lower))
+ count[StorageOrderMatch ? jp : ip]++;
+ else if(r==c)
+ count[ip]++;
+ else if(( UpLo==Lower && r>c) || ( UpLo==Upper && r<c))
+ {
+ count[ip]++;
+ count[jp]++;
+ }
+ }
+ }
+ Index nnz = count.sum();
+
+ // reserve space
+ dest.resizeNonZeros(nnz);
+ dest.outerIndexPtr()[0] = 0;
+ for(Index j=0; j<size; ++j)
+ dest.outerIndexPtr()[j+1] = dest.outerIndexPtr()[j] + count[j];
+ for(Index j=0; j<size; ++j)
+ count[j] = dest.outerIndexPtr()[j];
+
+ // copy data
+ for(Index j = 0; j<size; ++j)
+ {
+ for(typename MatrixType::InnerIterator it(mat,j); it; ++it)
+ {
+ Index i = it.index();
+ Index r = it.row();
+ Index c = it.col();
+
+ Index jp = perm ? perm[j] : j;
+ Index ip = perm ? perm[i] : i;
+
+ if(UpLo==(Upper|Lower))
+ {
+ Index k = count[StorageOrderMatch ? jp : ip]++;
+ dest.innerIndexPtr()[k] = StorageOrderMatch ? ip : jp;
+ dest.valuePtr()[k] = it.value();
+ }
+ else if(r==c)
+ {
+ Index k = count[ip]++;
+ dest.innerIndexPtr()[k] = ip;
+ dest.valuePtr()[k] = it.value();
+ }
+ else if(( (UpLo&Lower)==Lower && r>c) || ( (UpLo&Upper)==Upper && r<c))
+ {
+ if(!StorageOrderMatch)
+ std::swap(ip,jp);
+ Index k = count[jp]++;
+ dest.innerIndexPtr()[k] = ip;
+ dest.valuePtr()[k] = it.value();
+ k = count[ip]++;
+ dest.innerIndexPtr()[k] = jp;
+ dest.valuePtr()[k] = internal::conj(it.value());
+ }
+ }
+ }
+}
+
+template<int _SrcUpLo,int _DstUpLo,typename MatrixType,int DstOrder>
+void permute_symm_to_symm(const MatrixType& mat, SparseMatrix<typename MatrixType::Scalar,DstOrder,typename MatrixType::Index>& _dest, const typename MatrixType::Index* perm)
+{
+ typedef typename MatrixType::Index Index;
+ typedef typename MatrixType::Scalar Scalar;
+ SparseMatrix<Scalar,DstOrder,Index>& dest(_dest.derived());
+ typedef Matrix<Index,Dynamic,1> 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; j<size; ++j)
+ {
+ Index jp = perm ? perm[j] : j;
+ for(typename MatrixType::InnerIterator it(mat,j); it; ++it)
+ {
+ Index i = it.index();
+ if((int(SrcUpLo)==int(Lower) && i<j) || (int(SrcUpLo)==int(Upper) && i>j))
+ 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; j<size; ++j)
+ dest.outerIndexPtr()[j+1] = dest.outerIndexPtr()[j] + count[j];
+ dest.resizeNonZeros(dest.outerIndexPtr()[size]);
+ for(Index j=0; j<size; ++j)
+ count[j] = dest.outerIndexPtr()[j];
+
+ for(Index j = 0; j<size; ++j)
+ {
+
+ for(typename MatrixType::InnerIterator it(mat,j); it; ++it)
+ {
+ Index i = it.index();
+ if((int(SrcUpLo)==int(Lower) && i<j) || (int(SrcUpLo)==int(Upper) && i>j))
+ 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) && ip<jp) || (int(DstUpLo)==int(Upper) && ip>jp)))
+ dest.valuePtr()[k] = conj(it.value());
+ else
+ dest.valuePtr()[k] = it.value();
+ }
+ }
+}
+
+}
+
+template<typename MatrixType,int UpLo>
+class SparseSymmetricPermutationProduct
+ : public EigenBase<SparseSymmetricPermutationProduct<MatrixType,UpLo> >
+{
+ public:
+ typedef typename MatrixType::Scalar Scalar;
+ typedef typename MatrixType::Index Index;
+ protected:
+ typedef PermutationMatrix<Dynamic,Dynamic,Index> Perm;
+ public:
+ typedef Matrix<Index,Dynamic,1> VectorI;
+ typedef typename MatrixType::Nested MatrixTypeNested;
+ typedef typename internal::remove_all<MatrixTypeNested>::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<typename DestScalar, int Options, typename DstIndex>
+ void evalTo(SparseMatrix<DestScalar,Options,DstIndex>& _dest) const
+ {
+ internal::permute_symm_to_fullsymm<UpLo>(m_matrix,_dest,m_perm.indices().data());
+ }
+
+ template<typename DestType,unsigned int DestUpLo> void evalTo(SparseSelfAdjointView<DestType,DestUpLo>& dest) const
+ {
+ internal::permute_symm_to_symm<UpLo,DestUpLo>(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/Eigen/src/SparseCore/SparseSparseProductWithPruning.h b/Eigen/src/SparseCore/SparseSparseProductWithPruning.h
new file mode 100644
index 000000000..2438ac573
--- /dev/null
+++ b/Eigen/src/SparseCore/SparseSparseProductWithPruning.h
@@ -0,0 +1,149 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra.
+//
+// Copyright (C) 2008-2011 Gael Guennebaud <gael.guennebaud@inria.fr>
+//
+// This Source Code Form is subject to the terms of the Mozilla
+// Public License v. 2.0. If a copy of the MPL was not distributed
+// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+#ifndef EIGEN_SPARSESPARSEPRODUCTWITHPRUNING_H
+#define EIGEN_SPARSESPARSEPRODUCTWITHPRUNING_H
+
+namespace Eigen {
+
+namespace internal {
+
+
+// perform a pseudo in-place sparse * sparse product assuming all matrices are col major
+template<typename Lhs, typename Rhs, typename ResultType>
+static void sparse_sparse_product_with_pruning_impl(const Lhs& lhs, const Rhs& rhs, ResultType& res, typename ResultType::RealScalar tolerance)
+{
+ // return sparse_sparse_product_with_pruning_impl2(lhs,rhs,res);
+
+ typedef typename remove_all<Lhs>::type::Scalar Scalar;
+ typedef typename remove_all<Lhs>::type::Index Index;
+
+ // make sure to call innerSize/outerSize since we fake the storage order.
+ Index rows = lhs.innerSize();
+ Index cols = rhs.outerSize();
+ //int size = lhs.outerSize();
+ eigen_assert(lhs.outerSize() == rhs.innerSize());
+
+ // allocate a temporary buffer
+ AmbiVector<Scalar,Index> tempVector(rows);
+
+ // estimate the number of non zero entries
+ // given a rhs column containing Y non zeros, we assume that the respective Y columns
+ // of the lhs differs in average of one non zeros, thus the number of non zeros for
+ // the product of a rhs column with the lhs is X+Y where X is the average number of non zero
+ // per column of the lhs.
+ // Therefore, we have nnz(lhs*rhs) = nnz(lhs) + nnz(rhs)
+ Index estimated_nnz_prod = lhs.nonZeros() + rhs.nonZeros();
+
+ // mimics a resizeByInnerOuter:
+ if(ResultType::IsRowMajor)
+ res.resize(cols, rows);
+ else
+ res.resize(rows, cols);
+
+ res.reserve(estimated_nnz_prod);
+ double ratioColRes = double(estimated_nnz_prod)/double(lhs.rows()*rhs.cols());
+ for (Index j=0; j<cols; ++j)
+ {
+ // FIXME:
+ //double ratioColRes = (double(rhs.innerVector(j).nonZeros()) + double(lhs.nonZeros())/double(lhs.cols()))/double(lhs.rows());
+ // let's do a more accurate determination of the nnz ratio for the current column j of res
+ tempVector.init(ratioColRes);
+ tempVector.setZero();
+ for (typename Rhs::InnerIterator rhsIt(rhs, j); rhsIt; ++rhsIt)
+ {
+ // FIXME should be written like this: tmp += rhsIt.value() * lhs.col(rhsIt.index())
+ tempVector.restart();
+ Scalar x = rhsIt.value();
+ for (typename Lhs::InnerIterator lhsIt(lhs, rhsIt.index()); lhsIt; ++lhsIt)
+ {
+ tempVector.coeffRef(lhsIt.index()) += lhsIt.value() * x;
+ }
+ }
+ res.startVec(j);
+ for (typename AmbiVector<Scalar,Index>::Iterator it(tempVector,tolerance); it; ++it)
+ res.insertBackByOuterInner(j,it.index()) = it.value();
+ }
+ res.finalize();
+}
+
+template<typename Lhs, typename Rhs, typename ResultType,
+ int LhsStorageOrder = traits<Lhs>::Flags&RowMajorBit,
+ int RhsStorageOrder = traits<Rhs>::Flags&RowMajorBit,
+ int ResStorageOrder = traits<ResultType>::Flags&RowMajorBit>
+struct sparse_sparse_product_with_pruning_selector;
+
+template<typename Lhs, typename Rhs, typename ResultType>
+struct sparse_sparse_product_with_pruning_selector<Lhs,Rhs,ResultType,ColMajor,ColMajor,ColMajor>
+{
+ typedef typename traits<typename remove_all<Lhs>::type>::Scalar Scalar;
+ typedef typename ResultType::RealScalar RealScalar;
+
+ static void run(const Lhs& lhs, const Rhs& rhs, ResultType& res, RealScalar tolerance)
+ {
+ typename remove_all<ResultType>::type _res(res.rows(), res.cols());
+ internal::sparse_sparse_product_with_pruning_impl<Lhs,Rhs,ResultType>(lhs, rhs, _res, tolerance);
+ res.swap(_res);
+ }
+};
+
+template<typename Lhs, typename Rhs, typename ResultType>
+struct sparse_sparse_product_with_pruning_selector<Lhs,Rhs,ResultType,ColMajor,ColMajor,RowMajor>
+{
+ typedef typename ResultType::RealScalar RealScalar;
+ static void run(const Lhs& lhs, const Rhs& rhs, ResultType& res, RealScalar tolerance)
+ {
+ // we need a col-major matrix to hold the result
+ typedef SparseMatrix<typename ResultType::Scalar> SparseTemporaryType;
+ SparseTemporaryType _res(res.rows(), res.cols());
+ internal::sparse_sparse_product_with_pruning_impl<Lhs,Rhs,SparseTemporaryType>(lhs, rhs, _res, tolerance);
+ res = _res;
+ }
+};
+
+template<typename Lhs, typename Rhs, typename ResultType>
+struct sparse_sparse_product_with_pruning_selector<Lhs,Rhs,ResultType,RowMajor,RowMajor,RowMajor>
+{
+ typedef typename ResultType::RealScalar RealScalar;
+ static void run(const Lhs& lhs, const Rhs& rhs, ResultType& res, RealScalar tolerance)
+ {
+ // let's transpose the product to get a column x column product
+ typename remove_all<ResultType>::type _res(res.rows(), res.cols());
+ internal::sparse_sparse_product_with_pruning_impl<Rhs,Lhs,ResultType>(rhs, lhs, _res, tolerance);
+ res.swap(_res);
+ }
+};
+
+template<typename Lhs, typename Rhs, typename ResultType>
+struct sparse_sparse_product_with_pruning_selector<Lhs,Rhs,ResultType,RowMajor,RowMajor,ColMajor>
+{
+ typedef typename ResultType::RealScalar RealScalar;
+ static void run(const Lhs& lhs, const Rhs& rhs, ResultType& res, RealScalar tolerance)
+ {
+ typedef SparseMatrix<typename ResultType::Scalar,ColMajor> ColMajorMatrix;
+ ColMajorMatrix colLhs(lhs);
+ ColMajorMatrix colRhs(rhs);
+ internal::sparse_sparse_product_with_pruning_impl<ColMajorMatrix,ColMajorMatrix,ResultType>(colLhs, colRhs, res, tolerance);
+
+ // let's transpose the product to get a column x column product
+// typedef SparseMatrix<typename ResultType::Scalar> SparseTemporaryType;
+// SparseTemporaryType _res(res.cols(), res.rows());
+// sparse_sparse_product_with_pruning_impl<Rhs,Lhs,SparseTemporaryType>(rhs, lhs, _res);
+// res = _res.transpose();
+ }
+};
+
+// NOTE the 2 others cases (col row *) must never occur since they are caught
+// by ProductReturnType which transforms it to (col col *) by evaluating rhs.
+
+} // end namespace internal
+
+} // end namespace Eigen
+
+#endif // EIGEN_SPARSESPARSEPRODUCTWITHPRUNING_H
diff --git a/Eigen/src/SparseCore/SparseTranspose.h b/Eigen/src/SparseCore/SparseTranspose.h
new file mode 100644
index 000000000..273f9de68
--- /dev/null
+++ b/Eigen/src/SparseCore/SparseTranspose.h
@@ -0,0 +1,61 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra.
+//
+// Copyright (C) 2008-2009 Gael Guennebaud <gael.guennebaud@inria.fr>
+//
+// This Source Code Form is subject to the terms of the Mozilla
+// Public License v. 2.0. If 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<typename MatrixType> class TransposeImpl<MatrixType,Sparse>
+ : public SparseMatrixBase<Transpose<MatrixType> >
+{
+ typedef typename internal::remove_all<typename MatrixType::Nested>::type _MatrixTypeNested;
+ public:
+
+ EIGEN_SPARSE_PUBLIC_INTERFACE(Transpose<MatrixType>)
+
+ class InnerIterator;
+ class ReverseInnerIterator;
+
+ inline Index nonZeros() const { return derived().nestedExpression().nonZeros(); }
+};
+
+// NOTE: VC10 trigger an ICE if don't put typename TransposeImpl<MatrixType,Sparse>:: in front of Index,
+// a typedef typename TransposeImpl<MatrixType,Sparse>::Index Index;
+// does not fix the issue.
+// An alternative is to define the nested class in the parent class itself.
+template<typename MatrixType> class TransposeImpl<MatrixType,Sparse>::InnerIterator
+ : public _MatrixTypeNested::InnerIterator
+{
+ typedef typename _MatrixTypeNested::InnerIterator Base;
+ public:
+
+ EIGEN_STRONG_INLINE InnerIterator(const TransposeImpl& trans, typename TransposeImpl<MatrixType,Sparse>::Index outer)
+ : Base(trans.derived().nestedExpression(), outer)
+ {}
+ inline typename TransposeImpl<MatrixType,Sparse>::Index row() const { return Base::col(); }
+ inline typename TransposeImpl<MatrixType,Sparse>::Index col() const { return Base::row(); }
+};
+
+template<typename MatrixType> class TransposeImpl<MatrixType,Sparse>::ReverseInnerIterator
+ : public _MatrixTypeNested::ReverseInnerIterator
+{
+ typedef typename _MatrixTypeNested::ReverseInnerIterator Base;
+ public:
+
+ EIGEN_STRONG_INLINE ReverseInnerIterator(const TransposeImpl& xpr, typename TransposeImpl<MatrixType,Sparse>::Index outer)
+ : Base(xpr.derived().nestedExpression(), outer)
+ {}
+ inline typename TransposeImpl<MatrixType,Sparse>::Index row() const { return Base::col(); }
+ inline typename TransposeImpl<MatrixType,Sparse>::Index col() const { return Base::row(); }
+};
+
+} // end namespace Eigen
+
+#endif // EIGEN_SPARSETRANSPOSE_H
diff --git a/Eigen/src/SparseCore/SparseTriangularView.h b/Eigen/src/SparseCore/SparseTriangularView.h
new file mode 100644
index 000000000..477e4bd94
--- /dev/null
+++ b/Eigen/src/SparseCore/SparseTriangularView.h
@@ -0,0 +1,164 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra.
+//
+// Copyright (C) 2009 Gael Guennebaud <gael.guennebaud@inria.fr>
+//
+// This Source Code Form is subject to the terms of the Mozilla
+// Public License v. 2.0. If 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<typename MatrixType, int Mode>
+struct traits<SparseTriangularView<MatrixType,Mode> >
+: public traits<MatrixType>
+{};
+
+} // namespace internal
+
+template<typename MatrixType, int Mode> class SparseTriangularView
+ : public SparseMatrixBase<SparseTriangularView<MatrixType,Mode> >
+{
+ enum { SkipFirst = ((Mode&Lower) && !(MatrixType::Flags&RowMajorBit))
+ || ((Mode&Upper) && (MatrixType::Flags&RowMajorBit)),
+ SkipLast = !SkipFirst,
+ HasUnitDiag = (Mode&UnitDiag) ? 1 : 0
+ };
+
+ public:
+
+ EIGEN_SPARSE_PUBLIC_INTERFACE(SparseTriangularView)
+
+ class InnerIterator;
+ class ReverseInnerIterator;
+
+ inline Index rows() const { return m_matrix.rows(); }
+ inline Index cols() const { return m_matrix.cols(); }
+
+ typedef typename MatrixType::Nested MatrixTypeNested;
+ typedef typename internal::remove_reference<MatrixTypeNested>::type MatrixTypeNestedNonRef;
+ typedef typename internal::remove_all<MatrixTypeNested>::type MatrixTypeNestedCleaned;
+
+ inline SparseTriangularView(const MatrixType& matrix) : m_matrix(matrix) {}
+
+ /** \internal */
+ inline const MatrixTypeNestedCleaned& nestedExpression() const { return m_matrix; }
+
+ template<typename OtherDerived>
+ typename internal::plain_matrix_type_column_major<OtherDerived>::type
+ solve(const MatrixBase<OtherDerived>& other) const;
+
+ template<typename OtherDerived> void solveInPlace(MatrixBase<OtherDerived>& other) const;
+ template<typename OtherDerived> void solveInPlace(SparseMatrixBase<OtherDerived>& other) const;
+
+ protected:
+ MatrixTypeNested m_matrix;
+};
+
+template<typename MatrixType, int Mode>
+class SparseTriangularView<MatrixType,Mode>::InnerIterator : public MatrixTypeNestedCleaned::InnerIterator
+{
+ typedef typename MatrixTypeNestedCleaned::InnerIterator Base;
+ public:
+
+ EIGEN_STRONG_INLINE InnerIterator(const SparseTriangularView& view, Index outer)
+ : Base(view.nestedExpression(), outer), m_returnOne(false)
+ {
+ if(SkipFirst)
+ {
+ while((*this) && (HasUnitDiag ? this->index()<=outer : this->index()<outer))
+ Base::operator++();
+ if(HasUnitDiag)
+ m_returnOne = true;
+ }
+ else if(HasUnitDiag && ((!Base::operator bool()) || Base::index()>=Base::outer()))
+ {
+ if((!SkipFirst) && Base::operator bool())
+ Base::operator++();
+ m_returnOne = true;
+ }
+ }
+
+ EIGEN_STRONG_INLINE InnerIterator& operator++()
+ {
+ if(HasUnitDiag && m_returnOne)
+ m_returnOne = false;
+ else
+ {
+ Base::operator++();
+ if(HasUnitDiag && (!SkipFirst) && ((!Base::operator bool()) || Base::index()>=Base::outer()))
+ {
+ if((!SkipFirst) && Base::operator bool())
+ Base::operator++();
+ m_returnOne = true;
+ }
+ }
+ return *this;
+ }
+
+ inline Index row() const { return Base::row(); }
+ inline Index col() const { return Base::col(); }
+ inline Index index() const
+ {
+ if(HasUnitDiag && m_returnOne) return Base::outer();
+ else return Base::index();
+ }
+ inline Scalar value() const
+ {
+ if(HasUnitDiag && m_returnOne) return Scalar(1);
+ else return Base::value();
+ }
+
+ EIGEN_STRONG_INLINE operator bool() const
+ {
+ if(HasUnitDiag && m_returnOne)
+ return true;
+ return (SkipFirst ? Base::operator bool() : (Base::operator bool() && this->index() <= this->outer()));
+ }
+ protected:
+ bool m_returnOne;
+};
+
+template<typename MatrixType, int Mode>
+class SparseTriangularView<MatrixType,Mode>::ReverseInnerIterator : public MatrixTypeNestedCleaned::ReverseInnerIterator
+{
+ typedef typename MatrixTypeNestedCleaned::ReverseInnerIterator Base;
+ public:
+
+ EIGEN_STRONG_INLINE ReverseInnerIterator(const SparseTriangularView& view, Index outer)
+ : Base(view.nestedExpression(), outer)
+ {
+ eigen_assert((!HasUnitDiag) && "ReverseInnerIterator does not support yet triangular views with a unit diagonal");
+ if(SkipLast)
+ while((*this) && this->index()>outer)
+ --(*this);
+ }
+
+ EIGEN_STRONG_INLINE InnerIterator& operator--()
+ { Base::operator--(); return *this; }
+
+ inline Index row() const { return Base::row(); }
+ inline Index col() const { return Base::col(); }
+
+ EIGEN_STRONG_INLINE operator bool() const
+ {
+ return SkipLast ? Base::operator bool() : (Base::operator bool() && this->index() >= this->outer());
+ }
+};
+
+template<typename Derived>
+template<int Mode>
+inline const SparseTriangularView<Derived, Mode>
+SparseMatrixBase<Derived>::triangularView() const
+{
+ return derived();
+}
+
+} // end namespace Eigen
+
+#endif // EIGEN_SPARSE_TRIANGULARVIEW_H
diff --git a/Eigen/src/SparseCore/SparseUtil.h b/Eigen/src/SparseCore/SparseUtil.h
new file mode 100644
index 000000000..6062a086f
--- /dev/null
+++ b/Eigen/src/SparseCore/SparseUtil.h
@@ -0,0 +1,173 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra.
+//
+// Copyright (C) 2008 Gael Guennebaud <gael.guennebaud@inria.fr>
+//
+// This Source Code Form is subject to the terms of the Mozilla
+// Public License v. 2.0. If a copy of the MPL was not distributed
+// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+#ifndef EIGEN_SPARSEUTIL_H
+#define EIGEN_SPARSEUTIL_H
+
+namespace Eigen {
+
+#ifdef NDEBUG
+#define EIGEN_DBG_SPARSE(X)
+#else
+#define EIGEN_DBG_SPARSE(X) X
+#endif
+
+#define EIGEN_SPARSE_INHERIT_ASSIGNMENT_OPERATOR(Derived, Op) \
+template<typename OtherDerived> \
+EIGEN_STRONG_INLINE Derived& operator Op(const Eigen::SparseMatrixBase<OtherDerived>& other) \
+{ \
+ return Base::operator Op(other.derived()); \
+} \
+EIGEN_STRONG_INLINE Derived& operator Op(const Derived& other) \
+{ \
+ return Base::operator Op(other); \
+}
+
+#define EIGEN_SPARSE_INHERIT_SCALAR_ASSIGNMENT_OPERATOR(Derived, Op) \
+template<typename Other> \
+EIGEN_STRONG_INLINE Derived& operator Op(const Other& scalar) \
+{ \
+ return Base::operator Op(scalar); \
+}
+
+#define EIGEN_SPARSE_INHERIT_ASSIGNMENT_OPERATORS(Derived) \
+EIGEN_SPARSE_INHERIT_ASSIGNMENT_OPERATOR(Derived, =) \
+EIGEN_SPARSE_INHERIT_ASSIGNMENT_OPERATOR(Derived, +=) \
+EIGEN_SPARSE_INHERIT_ASSIGNMENT_OPERATOR(Derived, -=) \
+EIGEN_SPARSE_INHERIT_SCALAR_ASSIGNMENT_OPERATOR(Derived, *=) \
+EIGEN_SPARSE_INHERIT_SCALAR_ASSIGNMENT_OPERATOR(Derived, /=)
+
+#define _EIGEN_SPARSE_PUBLIC_INTERFACE(Derived, BaseClass) \
+ typedef BaseClass Base; \
+ typedef typename Eigen::internal::traits<Derived >::Scalar Scalar; \
+ typedef typename Eigen::NumTraits<Scalar>::Real RealScalar; \
+ typedef typename Eigen::internal::nested<Derived >::type Nested; \
+ typedef typename Eigen::internal::traits<Derived >::StorageKind StorageKind; \
+ typedef typename Eigen::internal::traits<Derived >::Index Index; \
+ enum { RowsAtCompileTime = Eigen::internal::traits<Derived >::RowsAtCompileTime, \
+ ColsAtCompileTime = Eigen::internal::traits<Derived >::ColsAtCompileTime, \
+ Flags = Eigen::internal::traits<Derived >::Flags, \
+ CoeffReadCost = Eigen::internal::traits<Derived >::CoeffReadCost, \
+ SizeAtCompileTime = Base::SizeAtCompileTime, \
+ IsVectorAtCompileTime = Base::IsVectorAtCompileTime }; \
+ using Base::derived; \
+ using Base::const_cast_derived;
+
+#define EIGEN_SPARSE_PUBLIC_INTERFACE(Derived) \
+ _EIGEN_SPARSE_PUBLIC_INTERFACE(Derived, Eigen::SparseMatrixBase<Derived >)
+
+const int CoherentAccessPattern = 0x1;
+const int InnerRandomAccessPattern = 0x2 | CoherentAccessPattern;
+const int OuterRandomAccessPattern = 0x4 | CoherentAccessPattern;
+const int RandomAccessPattern = 0x8 | OuterRandomAccessPattern | InnerRandomAccessPattern;
+
+template<typename Derived> class SparseMatrixBase;
+template<typename _Scalar, int _Flags = 0, typename _Index = int> class SparseMatrix;
+template<typename _Scalar, int _Flags = 0, typename _Index = int> class DynamicSparseMatrix;
+template<typename _Scalar, int _Flags = 0, typename _Index = int> class SparseVector;
+template<typename _Scalar, int _Flags = 0, typename _Index = int> class MappedSparseMatrix;
+
+template<typename MatrixType, int Size> class SparseInnerVectorSet;
+template<typename MatrixType, int Mode> class SparseTriangularView;
+template<typename MatrixType, unsigned int UpLo> class SparseSelfAdjointView;
+template<typename Lhs, typename Rhs> class SparseDiagonalProduct;
+template<typename MatrixType> class SparseView;
+
+template<typename Lhs, typename Rhs> class SparseSparseProduct;
+template<typename Lhs, typename Rhs> class SparseTimeDenseProduct;
+template<typename Lhs, typename Rhs> class DenseTimeSparseProduct;
+template<typename Lhs, typename Rhs, bool Transpose> class SparseDenseOuterProduct;
+
+template<typename Lhs, typename Rhs> struct SparseSparseProductReturnType;
+template<typename Lhs, typename Rhs, int InnerSize = internal::traits<Lhs>::ColsAtCompileTime> struct DenseSparseProductReturnType;
+template<typename Lhs, typename Rhs, int InnerSize = internal::traits<Lhs>::ColsAtCompileTime> struct SparseDenseProductReturnType;
+template<typename MatrixType,int UpLo> class SparseSymmetricPermutationProduct;
+
+namespace internal {
+
+template<typename T,int Rows,int Cols> struct sparse_eval;
+
+template<typename T> struct eval<T,Sparse>
+ : public sparse_eval<T, traits<T>::RowsAtCompileTime,traits<T>::ColsAtCompileTime>
+{};
+
+template<typename T,int Cols> struct sparse_eval<T,1,Cols> {
+ typedef typename traits<T>::Scalar _Scalar;
+ enum { _Flags = traits<T>::Flags| RowMajorBit };
+ public:
+ typedef SparseVector<_Scalar, _Flags> type;
+};
+
+template<typename T,int Rows> struct sparse_eval<T,Rows,1> {
+ typedef typename traits<T>::Scalar _Scalar;
+ enum { _Flags = traits<T>::Flags & (~RowMajorBit) };
+ public:
+ typedef SparseVector<_Scalar, _Flags> type;
+};
+
+template<typename T,int Rows,int Cols> struct sparse_eval {
+ typedef typename traits<T>::Scalar _Scalar;
+ enum { _Flags = traits<T>::Flags };
+ public:
+ typedef SparseMatrix<_Scalar, _Flags> type;
+};
+
+template<typename T> struct sparse_eval<T,1,1> {
+ typedef typename traits<T>::Scalar _Scalar;
+ public:
+ typedef Matrix<_Scalar, 1, 1> type;
+};
+
+template<typename T> struct plain_matrix_type<T,Sparse>
+{
+ typedef typename traits<T>::Scalar _Scalar;
+ enum {
+ _Flags = traits<T>::Flags
+ };
+
+ public:
+ typedef SparseMatrix<_Scalar, _Flags> type;
+};
+
+} // end namespace internal
+
+/** \ingroup SparseCore_Module
+ *
+ * \class Triplet
+ *
+ * \brief A small structure to hold a non zero as a triplet (i,j,value).
+ *
+ * \sa SparseMatrix::setFromTriplets()
+ */
+template<typename Scalar, typename Index=unsigned int>
+class Triplet
+{
+public:
+ Triplet() : m_row(0), m_col(0), m_value(0) {}
+
+ Triplet(const Index& i, const Index& j, const Scalar& v = Scalar(0))
+ : m_row(i), m_col(j), m_value(v)
+ {}
+
+ /** \returns the row index of the element */
+ const Index& row() const { return m_row; }
+
+ /** \returns the column index of the element */
+ const Index& col() const { return m_col; }
+
+ /** \returns the value of the element */
+ const Scalar& value() const { return m_value; }
+protected:
+ Index m_row, m_col;
+ Scalar m_value;
+};
+
+} // end namespace Eigen
+
+#endif // EIGEN_SPARSEUTIL_H
diff --git a/Eigen/src/SparseCore/SparseVector.h b/Eigen/src/SparseCore/SparseVector.h
new file mode 100644
index 000000000..c952f6540
--- /dev/null
+++ b/Eigen/src/SparseCore/SparseVector.h
@@ -0,0 +1,398 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra.
+//
+// Copyright (C) 2008-2009 Gael Guennebaud <gael.guennebaud@inria.fr>
+//
+// This Source Code Form is subject to the terms of the Mozilla
+// Public License v. 2.0. If a copy of the MPL was not distributed
+// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+#ifndef EIGEN_SPARSEVECTOR_H
+#define EIGEN_SPARSEVECTOR_H
+
+namespace Eigen {
+
+/** \ingroup SparseCore_Module
+ * \class SparseVector
+ *
+ * \brief a sparse vector class
+ *
+ * \tparam _Scalar the scalar type, i.e. the type of the coefficients
+ *
+ * See http://www.netlib.org/linalg/html_templates/node91.html for details on the storage scheme.
+ *
+ * This class can be extended with the help of the plugin mechanism described on the page
+ * \ref TopicCustomizingEigen by defining the preprocessor symbol \c EIGEN_SPARSEVECTOR_PLUGIN.
+ */
+
+namespace internal {
+template<typename _Scalar, int _Options, typename _Index>
+struct traits<SparseVector<_Scalar, _Options, _Index> >
+{
+ typedef _Scalar Scalar;
+ typedef _Index Index;
+ typedef Sparse StorageKind;
+ typedef MatrixXpr XprKind;
+ enum {
+ IsColVector = (_Options & RowMajorBit) ? 0 : 1,
+
+ RowsAtCompileTime = IsColVector ? Dynamic : 1,
+ ColsAtCompileTime = IsColVector ? 1 : Dynamic,
+ MaxRowsAtCompileTime = RowsAtCompileTime,
+ MaxColsAtCompileTime = ColsAtCompileTime,
+ Flags = _Options | NestByRefBit | LvalueBit | (IsColVector ? 0 : RowMajorBit),
+ CoeffReadCost = NumTraits<Scalar>::ReadCost,
+ SupportedAccessPatterns = InnerRandomAccessPattern
+ };
+};
+}
+
+template<typename _Scalar, int _Options, typename _Index>
+class SparseVector
+ : public SparseMatrixBase<SparseVector<_Scalar, _Options, _Index> >
+{
+ public:
+ EIGEN_SPARSE_PUBLIC_INTERFACE(SparseVector)
+ EIGEN_SPARSE_INHERIT_ASSIGNMENT_OPERATOR(SparseVector, +=)
+ EIGEN_SPARSE_INHERIT_ASSIGNMENT_OPERATOR(SparseVector, -=)
+
+ protected:
+ public:
+
+ typedef SparseMatrixBase<SparseVector> SparseBase;
+ enum { IsColVector = internal::traits<SparseVector>::IsColVector };
+
+ enum {
+ Options = _Options
+ };
+
+ internal::CompressedStorage<Scalar,Index> m_data;
+ Index m_size;
+
+ internal::CompressedStorage<Scalar,Index>& _data() { return m_data; }
+ internal::CompressedStorage<Scalar,Index>& _data() const { return m_data; }
+
+ public:
+
+ EIGEN_STRONG_INLINE Index rows() const { return IsColVector ? m_size : 1; }
+ EIGEN_STRONG_INLINE Index cols() const { return IsColVector ? 1 : m_size; }
+ EIGEN_STRONG_INLINE Index innerSize() const { return m_size; }
+ EIGEN_STRONG_INLINE Index outerSize() const { return 1; }
+
+ EIGEN_STRONG_INLINE const Scalar* valuePtr() const { return &m_data.value(0); }
+ EIGEN_STRONG_INLINE Scalar* valuePtr() { return &m_data.value(0); }
+
+ EIGEN_STRONG_INLINE const Index* innerIndexPtr() const { return &m_data.index(0); }
+ EIGEN_STRONG_INLINE Index* innerIndexPtr() { return &m_data.index(0); }
+
+ inline Scalar coeff(Index row, Index col) const
+ {
+ eigen_assert((IsColVector ? col : row)==0);
+ return coeff(IsColVector ? row : col);
+ }
+ inline Scalar coeff(Index i) const { return m_data.at(i); }
+
+ inline Scalar& coeffRef(Index row, Index col)
+ {
+ eigen_assert((IsColVector ? col : row)==0);
+ return coeff(IsColVector ? row : col);
+ }
+
+ /** \returns a reference to the coefficient value at given index \a i
+ * This operation involes a log(rho*size) binary search. If the coefficient does not
+ * exist yet, then a sorted insertion into a sequential buffer is performed.
+ *
+ * This insertion might be very costly if the number of nonzeros above \a i is large.
+ */
+ inline Scalar& coeffRef(Index i)
+ {
+ return m_data.atWithInsertion(i);
+ }
+
+ public:
+
+ class InnerIterator;
+ class ReverseInnerIterator;
+
+ inline void setZero() { m_data.clear(); }
+
+ /** \returns the number of non zero coefficients */
+ inline Index nonZeros() const { return static_cast<Index>(m_data.size()); }
+
+ inline void startVec(Index outer)
+ {
+ EIGEN_UNUSED_VARIABLE(outer);
+ eigen_assert(outer==0);
+ }
+
+ inline Scalar& insertBackByOuterInner(Index outer, Index inner)
+ {
+ EIGEN_UNUSED_VARIABLE(outer);
+ eigen_assert(outer==0);
+ return insertBack(inner);
+ }
+ inline Scalar& insertBack(Index i)
+ {
+ m_data.append(0, i);
+ return m_data.value(m_data.size()-1);
+ }
+
+ inline Scalar& insert(Index row, Index col)
+ {
+ Index inner = IsColVector ? row : col;
+ Index outer = IsColVector ? col : row;
+ eigen_assert(outer==0);
+ return insert(inner);
+ }
+ Scalar& insert(Index i)
+ {
+ Index startId = 0;
+ Index p = Index(m_data.size()) - 1;
+ // TODO smart realloc
+ m_data.resize(p+2,1);
+
+ while ( (p >= startId) && (m_data.index(p) > i) )
+ {
+ m_data.index(p+1) = m_data.index(p);
+ m_data.value(p+1) = m_data.value(p);
+ --p;
+ }
+ m_data.index(p+1) = i;
+ m_data.value(p+1) = 0;
+ return m_data.value(p+1);
+ }
+
+ /**
+ */
+ inline void reserve(Index reserveSize) { m_data.reserve(reserveSize); }
+
+
+ inline void finalize() {}
+
+ void prune(Scalar reference, RealScalar epsilon = NumTraits<RealScalar>::dummy_precision())
+ {
+ m_data.prune(reference,epsilon);
+ }
+
+ void resize(Index rows, Index cols)
+ {
+ eigen_assert(rows==1 || cols==1);
+ resize(IsColVector ? rows : cols);
+ }
+
+ void resize(Index newSize)
+ {
+ m_size = newSize;
+ m_data.clear();
+ }
+
+ void resizeNonZeros(Index size) { m_data.resize(size); }
+
+ inline SparseVector() : m_size(0) { resize(0); }
+
+ inline SparseVector(Index size) : m_size(0) { resize(size); }
+
+ inline SparseVector(Index rows, Index cols) : m_size(0) { resize(rows,cols); }
+
+ template<typename OtherDerived>
+ inline SparseVector(const SparseMatrixBase<OtherDerived>& other)
+ : m_size(0)
+ {
+ *this = other.derived();
+ }
+
+ inline SparseVector(const SparseVector& other)
+ : m_size(0)
+ {
+ *this = other.derived();
+ }
+
+ inline void swap(SparseVector& other)
+ {
+ std::swap(m_size, other.m_size);
+ m_data.swap(other.m_data);
+ }
+
+ inline SparseVector& operator=(const SparseVector& other)
+ {
+ if (other.isRValue())
+ {
+ swap(other.const_cast_derived());
+ }
+ else
+ {
+ resize(other.size());
+ m_data = other.m_data;
+ }
+ return *this;
+ }
+
+ template<typename OtherDerived>
+ inline SparseVector& operator=(const SparseMatrixBase<OtherDerived>& other)
+ {
+ if (int(RowsAtCompileTime)!=int(OtherDerived::RowsAtCompileTime))
+ return assign(other.transpose());
+ else
+ return assign(other);
+ }
+
+ #ifndef EIGEN_PARSED_BY_DOXYGEN
+ template<typename Lhs, typename Rhs>
+ inline SparseVector& operator=(const SparseSparseProduct<Lhs,Rhs>& product)
+ {
+ return Base::operator=(product);
+ }
+ #endif
+
+ friend std::ostream & operator << (std::ostream & s, const SparseVector& m)
+ {
+ for (Index i=0; i<m.nonZeros(); ++i)
+ s << "(" << m.m_data.value(i) << "," << m.m_data.index(i) << ") ";
+ s << std::endl;
+ return s;
+ }
+
+ /** Destructor */
+ inline ~SparseVector() {}
+
+ /** Overloaded for performance */
+ Scalar sum() const;
+
+ public:
+
+ /** \deprecated use setZero() and reserve() */
+ EIGEN_DEPRECATED void startFill(Index reserve)
+ {
+ setZero();
+ m_data.reserve(reserve);
+ }
+
+ /** \deprecated use insertBack(Index,Index) */
+ EIGEN_DEPRECATED Scalar& fill(Index r, Index c)
+ {
+ eigen_assert(r==0 || c==0);
+ return fill(IsColVector ? r : c);
+ }
+
+ /** \deprecated use insertBack(Index) */
+ EIGEN_DEPRECATED Scalar& fill(Index i)
+ {
+ m_data.append(0, i);
+ return m_data.value(m_data.size()-1);
+ }
+
+ /** \deprecated use insert(Index,Index) */
+ EIGEN_DEPRECATED Scalar& fillrand(Index r, Index c)
+ {
+ eigen_assert(r==0 || c==0);
+ return fillrand(IsColVector ? r : c);
+ }
+
+ /** \deprecated use insert(Index) */
+ EIGEN_DEPRECATED Scalar& fillrand(Index i)
+ {
+ return insert(i);
+ }
+
+ /** \deprecated use finalize() */
+ EIGEN_DEPRECATED void endFill() {}
+
+# ifdef EIGEN_SPARSEVECTOR_PLUGIN
+# include EIGEN_SPARSEVECTOR_PLUGIN
+# endif
+
+protected:
+ template<typename OtherDerived>
+ EIGEN_DONT_INLINE SparseVector& assign(const SparseMatrixBase<OtherDerived>& _other)
+ {
+ const OtherDerived& other(_other.derived());
+ const bool needToTranspose = (Flags & RowMajorBit) != (OtherDerived::Flags & RowMajorBit);
+ if(needToTranspose)
+ {
+ Index size = other.size();
+ Index nnz = other.nonZeros();
+ resize(size);
+ reserve(nnz);
+ for(Index i=0; i<size; ++i)
+ {
+ typename OtherDerived::InnerIterator it(other, i);
+ if(it)
+ insert(i) = it.value();
+ }
+ return *this;
+ }
+ else
+ {
+ // there is no special optimization
+ return Base::operator=(other);
+ }
+ }
+};
+
+template<typename Scalar, int _Options, typename _Index>
+class SparseVector<Scalar,_Options,_Index>::InnerIterator
+{
+ public:
+ InnerIterator(const SparseVector& vec, Index outer=0)
+ : m_data(vec.m_data), m_id(0), m_end(static_cast<Index>(m_data.size()))
+ {
+ EIGEN_UNUSED_VARIABLE(outer);
+ eigen_assert(outer==0);
+ }
+
+ InnerIterator(const internal::CompressedStorage<Scalar,Index>& data)
+ : m_data(data), m_id(0), m_end(static_cast<Index>(m_data.size()))
+ {}
+
+ inline InnerIterator& operator++() { m_id++; return *this; }
+
+ inline Scalar value() const { return m_data.value(m_id); }
+ inline Scalar& valueRef() { return const_cast<Scalar&>(m_data.value(m_id)); }
+
+ inline Index index() const { return m_data.index(m_id); }
+ inline Index row() const { return IsColVector ? index() : 0; }
+ inline Index col() const { return IsColVector ? 0 : index(); }
+
+ inline operator bool() const { return (m_id < m_end); }
+
+ protected:
+ const internal::CompressedStorage<Scalar,Index>& m_data;
+ Index m_id;
+ const Index m_end;
+};
+
+template<typename Scalar, int _Options, typename _Index>
+class SparseVector<Scalar,_Options,_Index>::ReverseInnerIterator
+{
+ public:
+ ReverseInnerIterator(const SparseVector& vec, Index outer=0)
+ : m_data(vec.m_data), m_id(static_cast<Index>(m_data.size())), m_start(0)
+ {
+ EIGEN_UNUSED_VARIABLE(outer);
+ eigen_assert(outer==0);
+ }
+
+ ReverseInnerIterator(const internal::CompressedStorage<Scalar,Index>& data)
+ : m_data(data), m_id(static_cast<Index>(m_data.size())), m_start(0)
+ {}
+
+ inline ReverseInnerIterator& operator--() { m_id--; return *this; }
+
+ inline Scalar value() const { return m_data.value(m_id-1); }
+ inline Scalar& valueRef() { return const_cast<Scalar&>(m_data.value(m_id-1)); }
+
+ inline Index index() const { return m_data.index(m_id-1); }
+ inline Index row() const { return IsColVector ? index() : 0; }
+ inline Index col() const { return IsColVector ? 0 : index(); }
+
+ inline operator bool() const { return (m_id > m_start); }
+
+ protected:
+ const internal::CompressedStorage<Scalar,Index>& m_data;
+ Index m_id;
+ const Index m_start;
+};
+
+} // end namespace Eigen
+
+#endif // EIGEN_SPARSEVECTOR_H
diff --git a/Eigen/src/SparseCore/SparseView.h b/Eigen/src/SparseCore/SparseView.h
new file mode 100644
index 000000000..8b0b9ea03
--- /dev/null
+++ b/Eigen/src/SparseCore/SparseView.h
@@ -0,0 +1,98 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra.
+//
+// Copyright (C) 2011 Gael Guennebaud <gael.guennebaud@inria.fr>
+// Copyright (C) 2010 Daniel Lowengrub <lowdanie@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 EIGEN_SPARSEVIEW_H
+#define EIGEN_SPARSEVIEW_H
+
+namespace Eigen {
+
+namespace internal {
+
+template<typename MatrixType>
+struct traits<SparseView<MatrixType> > : traits<MatrixType>
+{
+ typedef int Index;
+ typedef Sparse StorageKind;
+ enum {
+ Flags = int(traits<MatrixType>::Flags) & (RowMajorBit)
+ };
+};
+
+} // end namespace internal
+
+template<typename MatrixType>
+class SparseView : public SparseMatrixBase<SparseView<MatrixType> >
+{
+ typedef typename MatrixType::Nested MatrixTypeNested;
+ typedef typename internal::remove_all<MatrixTypeNested>::type _MatrixTypeNested;
+public:
+ EIGEN_SPARSE_PUBLIC_INTERFACE(SparseView)
+
+ SparseView(const MatrixType& mat, const Scalar& m_reference = Scalar(0),
+ typename NumTraits<Scalar>::Real m_epsilon = NumTraits<Scalar>::dummy_precision()) :
+ m_matrix(mat), m_reference(m_reference), m_epsilon(m_epsilon) {}
+
+ class InnerIterator;
+
+ inline Index rows() const { return m_matrix.rows(); }
+ inline Index cols() const { return m_matrix.cols(); }
+
+ inline Index innerSize() const { return m_matrix.innerSize(); }
+ inline Index outerSize() const { return m_matrix.outerSize(); }
+
+protected:
+ MatrixTypeNested m_matrix;
+ Scalar m_reference;
+ typename NumTraits<Scalar>::Real m_epsilon;
+};
+
+template<typename MatrixType>
+class SparseView<MatrixType>::InnerIterator : public _MatrixTypeNested::InnerIterator
+{
+public:
+ typedef typename _MatrixTypeNested::InnerIterator IterBase;
+ InnerIterator(const SparseView& view, Index outer) :
+ IterBase(view.m_matrix, outer), m_view(view)
+ {
+ incrementToNonZero();
+ }
+
+ EIGEN_STRONG_INLINE InnerIterator& operator++()
+ {
+ IterBase::operator++();
+ incrementToNonZero();
+ return *this;
+ }
+
+ using IterBase::value;
+
+protected:
+ const SparseView& m_view;
+
+private:
+ void incrementToNonZero()
+ {
+ while((bool(*this)) && internal::isMuchSmallerThan(value(), m_view.m_reference, m_view.m_epsilon))
+ {
+ IterBase::operator++();
+ }
+ }
+};
+
+template<typename Derived>
+const SparseView<Derived> MatrixBase<Derived>::sparseView(const Scalar& m_reference,
+ typename NumTraits<Scalar>::Real m_epsilon) const
+{
+ return SparseView<Derived>(derived(), m_reference, m_epsilon);
+}
+
+} // end namespace Eigen
+
+#endif
diff --git a/Eigen/src/SparseCore/TriangularSolver.h b/Eigen/src/SparseCore/TriangularSolver.h
new file mode 100644
index 000000000..cb8ad82b4
--- /dev/null
+++ b/Eigen/src/SparseCore/TriangularSolver.h
@@ -0,0 +1,334 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra.
+//
+// Copyright (C) 2008 Gael Guennebaud <gael.guennebaud@inria.fr>
+//
+// This Source Code Form is subject to the terms of the Mozilla
+// Public License v. 2.0. If a copy of the MPL was not distributed
+// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+#ifndef EIGEN_SPARSETRIANGULARSOLVER_H
+#define EIGEN_SPARSETRIANGULARSOLVER_H
+
+namespace Eigen {
+
+namespace internal {
+
+template<typename Lhs, typename Rhs, int Mode,
+ int UpLo = (Mode & Lower)
+ ? Lower
+ : (Mode & Upper)
+ ? Upper
+ : -1,
+ int StorageOrder = int(traits<Lhs>::Flags) & RowMajorBit>
+struct sparse_solve_triangular_selector;
+
+// forward substitution, row-major
+template<typename Lhs, typename Rhs, int Mode>
+struct sparse_solve_triangular_selector<Lhs,Rhs,Mode,Lower,RowMajor>
+{
+ typedef typename Rhs::Scalar Scalar;
+ static void run(const Lhs& lhs, Rhs& other)
+ {
+ for(int col=0 ; col<other.cols() ; ++col)
+ {
+ for(int i=0; i<lhs.rows(); ++i)
+ {
+ Scalar tmp = other.coeff(i,col);
+ Scalar lastVal(0);
+ int lastIndex = 0;
+ for(typename Lhs::InnerIterator it(lhs, i); it; ++it)
+ {
+ lastVal = it.value();
+ lastIndex = it.index();
+ if(lastIndex==i)
+ break;
+ tmp -= lastVal * other.coeff(lastIndex,col);
+ }
+ if (Mode & UnitDiag)
+ other.coeffRef(i,col) = tmp;
+ else
+ {
+ eigen_assert(lastIndex==i);
+ other.coeffRef(i,col) = tmp/lastVal;
+ }
+ }
+ }
+ }
+};
+
+// backward substitution, row-major
+template<typename Lhs, typename Rhs, int Mode>
+struct sparse_solve_triangular_selector<Lhs,Rhs,Mode,Upper,RowMajor>
+{
+ typedef typename Rhs::Scalar Scalar;
+ static void run(const Lhs& lhs, Rhs& other)
+ {
+ for(int col=0 ; col<other.cols() ; ++col)
+ {
+ for(int i=lhs.rows()-1 ; i>=0 ; --i)
+ {
+ Scalar tmp = other.coeff(i,col);
+ Scalar l_ii = 0;
+ typename Lhs::InnerIterator it(lhs, i);
+ while(it && it.index()<i)
+ ++it;
+ if(!(Mode & UnitDiag))
+ {
+ eigen_assert(it && it.index()==i);
+ l_ii = it.value();
+ ++it;
+ }
+ else if (it && it.index() == i)
+ ++it;
+ for(; it; ++it)
+ {
+ tmp -= it.value() * other.coeff(it.index(),col);
+ }
+
+ if (Mode & UnitDiag)
+ other.coeffRef(i,col) = tmp;
+ else
+ other.coeffRef(i,col) = tmp/l_ii;
+ }
+ }
+ }
+};
+
+// forward substitution, col-major
+template<typename Lhs, typename Rhs, int Mode>
+struct sparse_solve_triangular_selector<Lhs,Rhs,Mode,Lower,ColMajor>
+{
+ typedef typename Rhs::Scalar Scalar;
+ static void run(const Lhs& lhs, Rhs& other)
+ {
+ for(int col=0 ; col<other.cols() ; ++col)
+ {
+ for(int i=0; i<lhs.cols(); ++i)
+ {
+ Scalar& tmp = other.coeffRef(i,col);
+ if (tmp!=Scalar(0)) // optimization when other is actually sparse
+ {
+ typename Lhs::InnerIterator it(lhs, i);
+ while(it && it.index()<i)
+ ++it;
+ if(!(Mode & UnitDiag))
+ {
+ eigen_assert(it && it.index()==i);
+ tmp /= it.value();
+ }
+ if (it && it.index()==i)
+ ++it;
+ for(; it; ++it)
+ other.coeffRef(it.index(), col) -= tmp * it.value();
+ }
+ }
+ }
+ }
+};
+
+// backward substitution, col-major
+template<typename Lhs, typename Rhs, int Mode>
+struct sparse_solve_triangular_selector<Lhs,Rhs,Mode,Upper,ColMajor>
+{
+ typedef typename Rhs::Scalar Scalar;
+ static void run(const Lhs& lhs, Rhs& other)
+ {
+ for(int col=0 ; col<other.cols() ; ++col)
+ {
+ for(int i=lhs.cols()-1; i>=0; --i)
+ {
+ Scalar& tmp = other.coeffRef(i,col);
+ if (tmp!=Scalar(0)) // optimization when other is actually sparse
+ {
+ if(!(Mode & UnitDiag))
+ {
+ // TODO replace this by a binary search. make sure the binary search is safe for partially sorted elements
+ typename Lhs::ReverseInnerIterator it(lhs, i);
+ while(it && it.index()!=i)
+ --it;
+ eigen_assert(it && it.index()==i);
+ other.coeffRef(i,col) /= it.value();
+ }
+ typename Lhs::InnerIterator it(lhs, i);
+ for(; it && it.index()<i; ++it)
+ other.coeffRef(it.index(), col) -= tmp * it.value();
+ }
+ }
+ }
+ }
+};
+
+} // end namespace internal
+
+template<typename ExpressionType,int Mode>
+template<typename OtherDerived>
+void SparseTriangularView<ExpressionType,Mode>::solveInPlace(MatrixBase<OtherDerived>& other) const
+{
+ eigen_assert(m_matrix.cols() == m_matrix.rows() && m_matrix.cols() == other.rows());
+ eigen_assert((!(Mode & ZeroDiag)) && bool(Mode & (Upper|Lower)));
+
+ enum { copy = internal::traits<OtherDerived>::Flags & RowMajorBit };
+
+ typedef typename internal::conditional<copy,
+ typename internal::plain_matrix_type_column_major<OtherDerived>::type, OtherDerived&>::type OtherCopy;
+ OtherCopy otherCopy(other.derived());
+
+ internal::sparse_solve_triangular_selector<ExpressionType, typename internal::remove_reference<OtherCopy>::type, Mode>::run(m_matrix, otherCopy);
+
+ if (copy)
+ other = otherCopy;
+}
+
+template<typename ExpressionType,int Mode>
+template<typename OtherDerived>
+typename internal::plain_matrix_type_column_major<OtherDerived>::type
+SparseTriangularView<ExpressionType,Mode>::solve(const MatrixBase<OtherDerived>& other) const
+{
+ typename internal::plain_matrix_type_column_major<OtherDerived>::type res(other);
+ solveInPlace(res);
+ return res;
+}
+
+// pure sparse path
+
+namespace internal {
+
+template<typename Lhs, typename Rhs, int Mode,
+ int UpLo = (Mode & Lower)
+ ? Lower
+ : (Mode & Upper)
+ ? Upper
+ : -1,
+ int StorageOrder = int(Lhs::Flags) & (RowMajorBit)>
+struct sparse_solve_triangular_sparse_selector;
+
+// forward substitution, col-major
+template<typename Lhs, typename Rhs, int Mode, int UpLo>
+struct sparse_solve_triangular_sparse_selector<Lhs,Rhs,Mode,UpLo,ColMajor>
+{
+ typedef typename Rhs::Scalar Scalar;
+ typedef typename promote_index_type<typename traits<Lhs>::Index,
+ typename traits<Rhs>::Index>::type Index;
+ static void run(const Lhs& lhs, Rhs& other)
+ {
+ const bool IsLower = (UpLo==Lower);
+ AmbiVector<Scalar,Index> tempVector(other.rows()*2);
+ tempVector.setBounds(0,other.rows());
+
+ Rhs res(other.rows(), other.cols());
+ res.reserve(other.nonZeros());
+
+ for(int col=0 ; col<other.cols() ; ++col)
+ {
+ // FIXME estimate number of non zeros
+ tempVector.init(.99/*float(other.col(col).nonZeros())/float(other.rows())*/);
+ tempVector.setZero();
+ tempVector.restart();
+ for (typename Rhs::InnerIterator rhsIt(other, col); rhsIt; ++rhsIt)
+ {
+ tempVector.coeffRef(rhsIt.index()) = rhsIt.value();
+ }
+
+ for(int i=IsLower?0:lhs.cols()-1;
+ IsLower?i<lhs.cols():i>=0;
+ i+=IsLower?1:-1)
+ {
+ tempVector.restart();
+ Scalar& ci = tempVector.coeffRef(i);
+ if (ci!=Scalar(0))
+ {
+ // find
+ typename Lhs::InnerIterator it(lhs, i);
+ if(!(Mode & UnitDiag))
+ {
+ if (IsLower)
+ {
+ eigen_assert(it.index()==i);
+ ci /= it.value();
+ }
+ else
+ ci /= lhs.coeff(i,i);
+ }
+ tempVector.restart();
+ if (IsLower)
+ {
+ if (it.index()==i)
+ ++it;
+ for(; it; ++it)
+ tempVector.coeffRef(it.index()) -= ci * it.value();
+ }
+ else
+ {
+ for(; it && it.index()<i; ++it)
+ tempVector.coeffRef(it.index()) -= ci * it.value();
+ }
+ }
+ }
+
+
+ int count = 0;
+ // FIXME compute a reference value to filter zeros
+ for (typename AmbiVector<Scalar,Index>::Iterator it(tempVector/*,1e-12*/); it; ++it)
+ {
+ ++ count;
+// std::cerr << "fill " << it.index() << ", " << col << "\n";
+// std::cout << it.value() << " ";
+ // FIXME use insertBack
+ res.insert(it.index(), col) = it.value();
+ }
+// std::cout << "tempVector.nonZeros() == " << int(count) << " / " << (other.rows()) << "\n";
+ }
+ res.finalize();
+ other = res.markAsRValue();
+ }
+};
+
+} // end namespace internal
+
+template<typename ExpressionType,int Mode>
+template<typename OtherDerived>
+void SparseTriangularView<ExpressionType,Mode>::solveInPlace(SparseMatrixBase<OtherDerived>& other) const
+{
+ eigen_assert(m_matrix.cols() == m_matrix.rows() && m_matrix.cols() == other.rows());
+ eigen_assert( (!(Mode & ZeroDiag)) && bool(Mode & (Upper|Lower)));
+
+// enum { copy = internal::traits<OtherDerived>::Flags & RowMajorBit };
+
+// typedef typename internal::conditional<copy,
+// typename internal::plain_matrix_type_column_major<OtherDerived>::type, OtherDerived&>::type OtherCopy;
+// OtherCopy otherCopy(other.derived());
+
+ internal::sparse_solve_triangular_sparse_selector<ExpressionType, OtherDerived, Mode>::run(m_matrix, other.derived());
+
+// if (copy)
+// other = otherCopy;
+}
+
+#ifdef EIGEN2_SUPPORT
+
+// deprecated stuff:
+
+/** \deprecated */
+template<typename Derived>
+template<typename OtherDerived>
+void SparseMatrixBase<Derived>::solveTriangularInPlace(MatrixBase<OtherDerived>& other) const
+{
+ this->template triangular<Flags&(Upper|Lower)>().solveInPlace(other);
+}
+
+/** \deprecated */
+template<typename Derived>
+template<typename OtherDerived>
+typename internal::plain_matrix_type_column_major<OtherDerived>::type
+SparseMatrixBase<Derived>::solveTriangular(const MatrixBase<OtherDerived>& other) const
+{
+ typename internal::plain_matrix_type_column_major<OtherDerived>::type res(other);
+ derived().solveTriangularInPlace(res);
+ return res;
+}
+#endif // EIGEN2_SUPPORT
+
+} // end namespace Eigen
+
+#endif // EIGEN_SPARSETRIANGULARSOLVER_H
diff --git a/Eigen/src/StlSupport/CMakeLists.txt b/Eigen/src/StlSupport/CMakeLists.txt
new file mode 100644
index 000000000..0f094f637
--- /dev/null
+++ b/Eigen/src/StlSupport/CMakeLists.txt
@@ -0,0 +1,6 @@
+FILE(GLOB Eigen_StlSupport_SRCS "*.h")
+
+INSTALL(FILES
+ ${Eigen_StlSupport_SRCS}
+ DESTINATION ${INCLUDE_INSTALL_DIR}/Eigen/src/StlSupport COMPONENT Devel
+ )
diff --git a/Eigen/src/StlSupport/StdDeque.h b/Eigen/src/StlSupport/StdDeque.h
new file mode 100644
index 000000000..4ee8e5c10
--- /dev/null
+++ b/Eigen/src/StlSupport/StdDeque.h
@@ -0,0 +1,134 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra.
+//
+// Copyright (C) 2009 Gael Guennebaud <gael.guennebaud@inria.fr>
+// Copyright (C) 2009 Hauke Heibel <hauke.heibel@googlemail.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_STDDEQUE_H
+#define EIGEN_STDDEQUE_H
+
+#include "Eigen/src/StlSupport/details.h"
+
+// Define the explicit instantiation (e.g. necessary for the Intel compiler)
+#if defined(__INTEL_COMPILER) || defined(__GNUC__)
+ #define EIGEN_EXPLICIT_STL_DEQUE_INSTANTIATION(...) template class std::deque<__VA_ARGS__, EIGEN_ALIGNED_ALLOCATOR<__VA_ARGS__> >;
+#else
+ #define EIGEN_EXPLICIT_STL_DEQUE_INSTANTIATION(...)
+#endif
+
+/**
+ * This section contains a convenience MACRO which allows an easy specialization of
+ * std::deque such that for data types with alignment issues the correct allocator
+ * is used automatically.
+ */
+#define EIGEN_DEFINE_STL_DEQUE_SPECIALIZATION(...) \
+EIGEN_EXPLICIT_STL_DEQUE_INSTANTIATION(__VA_ARGS__) \
+namespace std \
+{ \
+ template<typename _Ay> \
+ class deque<__VA_ARGS__, _Ay> \
+ : public deque<__VA_ARGS__, EIGEN_ALIGNED_ALLOCATOR<__VA_ARGS__> > \
+ { \
+ typedef deque<__VA_ARGS__, EIGEN_ALIGNED_ALLOCATOR<__VA_ARGS__> > deque_base; \
+ public: \
+ typedef __VA_ARGS__ value_type; \
+ typedef typename deque_base::allocator_type allocator_type; \
+ typedef typename deque_base::size_type size_type; \
+ typedef typename deque_base::iterator iterator; \
+ explicit deque(const allocator_type& a = allocator_type()) : deque_base(a) {} \
+ template<typename InputIterator> \
+ deque(InputIterator first, InputIterator last, const allocator_type& a = allocator_type()) : deque_base(first, last, a) {} \
+ deque(const deque& c) : deque_base(c) {} \
+ explicit deque(size_type num, const value_type& val = value_type()) : deque_base(num, val) {} \
+ deque(iterator start, iterator end) : deque_base(start, end) {} \
+ deque& operator=(const deque& x) { \
+ deque_base::operator=(x); \
+ return *this; \
+ } \
+ }; \
+}
+
+// check whether we really need the std::deque specialization
+#if !(defined(_GLIBCXX_DEQUE) && (!EIGEN_GNUC_AT_LEAST(4,1))) /* Note that before gcc-4.1 we already have: std::deque::resize(size_type,const T&). */
+
+namespace std {
+
+#define EIGEN_STD_DEQUE_SPECIALIZATION_BODY \
+ public: \
+ typedef T value_type; \
+ typedef typename deque_base::allocator_type allocator_type; \
+ typedef typename deque_base::size_type size_type; \
+ typedef typename deque_base::iterator iterator; \
+ typedef typename deque_base::const_iterator const_iterator; \
+ explicit deque(const allocator_type& a = allocator_type()) : deque_base(a) {} \
+ template<typename InputIterator> \
+ deque(InputIterator first, InputIterator last, const allocator_type& a = allocator_type()) \
+ : deque_base(first, last, a) {} \
+ deque(const deque& c) : deque_base(c) {} \
+ explicit deque(size_type num, const value_type& val = value_type()) : deque_base(num, val) {} \
+ deque(iterator start, iterator end) : deque_base(start, end) {} \
+ deque& operator=(const deque& x) { \
+ deque_base::operator=(x); \
+ return *this; \
+ }
+
+ template<typename T>
+ class deque<T,EIGEN_ALIGNED_ALLOCATOR<T> >
+ : public deque<EIGEN_WORKAROUND_MSVC_STL_SUPPORT(T),
+ Eigen::aligned_allocator_indirection<EIGEN_WORKAROUND_MSVC_STL_SUPPORT(T)> >
+{
+ typedef deque<EIGEN_WORKAROUND_MSVC_STL_SUPPORT(T),
+ Eigen::aligned_allocator_indirection<EIGEN_WORKAROUND_MSVC_STL_SUPPORT(T)> > deque_base;
+ EIGEN_STD_DEQUE_SPECIALIZATION_BODY
+
+ void resize(size_type new_size)
+ { resize(new_size, T()); }
+
+#if defined(_DEQUE_)
+ // workaround MSVC std::deque implementation
+ void resize(size_type new_size, const value_type& x)
+ {
+ if (deque_base::size() < new_size)
+ deque_base::_Insert_n(deque_base::end(), new_size - deque_base::size(), x);
+ else if (new_size < deque_base::size())
+ deque_base::erase(deque_base::begin() + new_size, deque_base::end());
+ }
+ void push_back(const value_type& x)
+ { deque_base::push_back(x); }
+ void push_front(const value_type& x)
+ { deque_base::push_front(x); }
+ using deque_base::insert;
+ iterator insert(const_iterator position, const value_type& x)
+ { return deque_base::insert(position,x); }
+ void insert(const_iterator position, size_type new_size, const value_type& x)
+ { deque_base::insert(position, new_size, x); }
+#elif defined(_GLIBCXX_DEQUE) && EIGEN_GNUC_AT_LEAST(4,2)
+ // workaround GCC std::deque implementation
+ void resize(size_type new_size, const value_type& x)
+ {
+ if (new_size < deque_base::size())
+ deque_base::_M_erase_at_end(this->_M_impl._M_start + new_size);
+ else
+ deque_base::insert(deque_base::end(), new_size - deque_base::size(), x);
+ }
+#else
+ // either GCC 4.1 or non-GCC
+ // default implementation which should always work.
+ void resize(size_type new_size, const value_type& x)
+ {
+ if (new_size < deque_base::size())
+ deque_base::erase(deque_base::begin() + new_size, deque_base::end());
+ else if (new_size > deque_base::size())
+ deque_base::insert(deque_base::end(), new_size - deque_base::size(), x);
+ }
+#endif
+ };
+}
+
+#endif // check whether specialization is actually required
+
+#endif // EIGEN_STDDEQUE_H
diff --git a/Eigen/src/StlSupport/StdList.h b/Eigen/src/StlSupport/StdList.h
new file mode 100644
index 000000000..627381ece
--- /dev/null
+++ b/Eigen/src/StlSupport/StdList.h
@@ -0,0 +1,114 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra.
+//
+// Copyright (C) 2009 Hauke Heibel <hauke.heibel@googlemail.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_STDLIST_H
+#define EIGEN_STDLIST_H
+
+#include "Eigen/src/StlSupport/details.h"
+
+// Define the explicit instantiation (e.g. necessary for the Intel compiler)
+#if defined(__INTEL_COMPILER) || defined(__GNUC__)
+ #define EIGEN_EXPLICIT_STL_LIST_INSTANTIATION(...) template class std::list<__VA_ARGS__, EIGEN_ALIGNED_ALLOCATOR<__VA_ARGS__> >;
+#else
+ #define EIGEN_EXPLICIT_STL_LIST_INSTANTIATION(...)
+#endif
+
+/**
+ * This section contains a convenience MACRO which allows an easy specialization of
+ * std::list such that for data types with alignment issues the correct allocator
+ * is used automatically.
+ */
+#define EIGEN_DEFINE_STL_LIST_SPECIALIZATION(...) \
+EIGEN_EXPLICIT_STL_LIST_INSTANTIATION(__VA_ARGS__) \
+namespace std \
+{ \
+ template<typename _Ay> \
+ class list<__VA_ARGS__, _Ay> \
+ : public list<__VA_ARGS__, EIGEN_ALIGNED_ALLOCATOR<__VA_ARGS__> > \
+ { \
+ typedef list<__VA_ARGS__, EIGEN_ALIGNED_ALLOCATOR<__VA_ARGS__> > list_base; \
+ public: \
+ typedef __VA_ARGS__ value_type; \
+ typedef typename list_base::allocator_type allocator_type; \
+ typedef typename list_base::size_type size_type; \
+ typedef typename list_base::iterator iterator; \
+ explicit list(const allocator_type& a = allocator_type()) : list_base(a) {} \
+ template<typename InputIterator> \
+ list(InputIterator first, InputIterator last, const allocator_type& a = allocator_type()) : list_base(first, last, a) {} \
+ list(const list& c) : list_base(c) {} \
+ explicit list(size_type num, const value_type& val = value_type()) : list_base(num, val) {} \
+ list(iterator start, iterator end) : list_base(start, end) {} \
+ list& operator=(const list& x) { \
+ list_base::operator=(x); \
+ return *this; \
+ } \
+ }; \
+}
+
+// check whether we really need the std::vector specialization
+#if !(defined(_GLIBCXX_VECTOR) && (!EIGEN_GNUC_AT_LEAST(4,1))) /* Note that before gcc-4.1 we already have: std::list::resize(size_type,const T&). */
+
+namespace std
+{
+
+#define EIGEN_STD_LIST_SPECIALIZATION_BODY \
+ public: \
+ typedef T value_type; \
+ typedef typename list_base::allocator_type allocator_type; \
+ typedef typename list_base::size_type size_type; \
+ typedef typename list_base::iterator iterator; \
+ typedef typename list_base::const_iterator const_iterator; \
+ explicit list(const allocator_type& a = allocator_type()) : list_base(a) {} \
+ template<typename InputIterator> \
+ list(InputIterator first, InputIterator last, const allocator_type& a = allocator_type()) \
+ : list_base(first, last, a) {} \
+ list(const list& c) : list_base(c) {} \
+ explicit list(size_type num, const value_type& val = value_type()) : list_base(num, val) {} \
+ list(iterator start, iterator end) : list_base(start, end) {} \
+ list& operator=(const list& x) { \
+ list_base::operator=(x); \
+ return *this; \
+ }
+
+ template<typename T>
+ class list<T,EIGEN_ALIGNED_ALLOCATOR<T> >
+ : public list<EIGEN_WORKAROUND_MSVC_STL_SUPPORT(T),
+ Eigen::aligned_allocator_indirection<EIGEN_WORKAROUND_MSVC_STL_SUPPORT(T)> >
+ {
+ typedef list<EIGEN_WORKAROUND_MSVC_STL_SUPPORT(T),
+ Eigen::aligned_allocator_indirection<EIGEN_WORKAROUND_MSVC_STL_SUPPORT(T)> > list_base;
+ EIGEN_STD_LIST_SPECIALIZATION_BODY
+
+ void resize(size_type new_size)
+ { resize(new_size, T()); }
+
+ void resize(size_type new_size, const value_type& x)
+ {
+ if (list_base::size() < new_size)
+ list_base::insert(list_base::end(), new_size - list_base::size(), x);
+ else
+ while (new_size < list_base::size()) list_base::pop_back();
+ }
+
+#if defined(_LIST_)
+ // workaround MSVC std::list implementation
+ void push_back(const value_type& x)
+ { list_base::push_back(x); }
+ using list_base::insert;
+ iterator insert(const_iterator position, const value_type& x)
+ { return list_base::insert(position,x); }
+ void insert(const_iterator position, size_type new_size, const value_type& x)
+ { list_base::insert(position, new_size, x); }
+#endif
+ };
+}
+
+#endif // check whether specialization is actually required
+
+#endif // EIGEN_STDLIST_H
diff --git a/Eigen/src/StlSupport/StdVector.h b/Eigen/src/StlSupport/StdVector.h
new file mode 100644
index 000000000..40a9abefa
--- /dev/null
+++ b/Eigen/src/StlSupport/StdVector.h
@@ -0,0 +1,126 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra.
+//
+// Copyright (C) 2009 Gael Guennebaud <gael.guennebaud@inria.fr>
+// Copyright (C) 2009 Hauke Heibel <hauke.heibel@googlemail.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_STDVECTOR_H
+#define EIGEN_STDVECTOR_H
+
+#include "Eigen/src/StlSupport/details.h"
+
+/**
+ * This section contains a convenience MACRO which allows an easy specialization of
+ * std::vector such that for data types with alignment issues the correct allocator
+ * is used automatically.
+ */
+#define EIGEN_DEFINE_STL_VECTOR_SPECIALIZATION(...) \
+namespace std \
+{ \
+ template<> \
+ class vector<__VA_ARGS__, std::allocator<__VA_ARGS__> > \
+ : public vector<__VA_ARGS__, EIGEN_ALIGNED_ALLOCATOR<__VA_ARGS__> > \
+ { \
+ typedef vector<__VA_ARGS__, EIGEN_ALIGNED_ALLOCATOR<__VA_ARGS__> > vector_base; \
+ public: \
+ typedef __VA_ARGS__ value_type; \
+ typedef vector_base::allocator_type allocator_type; \
+ typedef vector_base::size_type size_type; \
+ typedef vector_base::iterator iterator; \
+ explicit vector(const allocator_type& a = allocator_type()) : vector_base(a) {} \
+ template<typename InputIterator> \
+ vector(InputIterator first, InputIterator last, const allocator_type& a = allocator_type()) : vector_base(first, last, a) {} \
+ vector(const vector& c) : vector_base(c) {} \
+ explicit vector(size_type num, const value_type& val = value_type()) : vector_base(num, val) {} \
+ vector(iterator start, iterator end) : vector_base(start, end) {} \
+ vector& operator=(const vector& x) { \
+ vector_base::operator=(x); \
+ return *this; \
+ } \
+ }; \
+}
+
+namespace std {
+
+#define EIGEN_STD_VECTOR_SPECIALIZATION_BODY \
+ public: \
+ typedef T value_type; \
+ typedef typename vector_base::allocator_type allocator_type; \
+ typedef typename vector_base::size_type size_type; \
+ typedef typename vector_base::iterator iterator; \
+ typedef typename vector_base::const_iterator const_iterator; \
+ explicit vector(const allocator_type& a = allocator_type()) : vector_base(a) {} \
+ template<typename InputIterator> \
+ vector(InputIterator first, InputIterator last, const allocator_type& a = allocator_type()) \
+ : vector_base(first, last, a) {} \
+ vector(const vector& c) : vector_base(c) {} \
+ explicit vector(size_type num, const value_type& val = value_type()) : vector_base(num, val) {} \
+ vector(iterator start, iterator end) : vector_base(start, end) {} \
+ vector& operator=(const vector& x) { \
+ vector_base::operator=(x); \
+ return *this; \
+ }
+
+ template<typename T>
+ class vector<T,EIGEN_ALIGNED_ALLOCATOR<T> >
+ : public vector<EIGEN_WORKAROUND_MSVC_STL_SUPPORT(T),
+ Eigen::aligned_allocator_indirection<EIGEN_WORKAROUND_MSVC_STL_SUPPORT(T)> >
+{
+ typedef vector<EIGEN_WORKAROUND_MSVC_STL_SUPPORT(T),
+ Eigen::aligned_allocator_indirection<EIGEN_WORKAROUND_MSVC_STL_SUPPORT(T)> > vector_base;
+ EIGEN_STD_VECTOR_SPECIALIZATION_BODY
+
+ void resize(size_type new_size)
+ { resize(new_size, T()); }
+
+#if defined(_VECTOR_)
+ // workaround MSVC std::vector implementation
+ void resize(size_type new_size, const value_type& x)
+ {
+ if (vector_base::size() < new_size)
+ vector_base::_Insert_n(vector_base::end(), new_size - vector_base::size(), x);
+ else if (new_size < vector_base::size())
+ vector_base::erase(vector_base::begin() + new_size, vector_base::end());
+ }
+ void push_back(const value_type& x)
+ { vector_base::push_back(x); }
+ using vector_base::insert;
+ iterator insert(const_iterator position, const value_type& x)
+ { return vector_base::insert(position,x); }
+ void insert(const_iterator position, size_type new_size, const value_type& x)
+ { vector_base::insert(position, new_size, x); }
+#elif defined(_GLIBCXX_VECTOR) && (!(EIGEN_GNUC_AT_LEAST(4,1)))
+ /* Note that before gcc-4.1 we already have: std::vector::resize(size_type,const T&).
+ * However, this specialization is still needed to make the above EIGEN_DEFINE_STL_VECTOR_SPECIALIZATION trick to work. */
+ void resize(size_type new_size, const value_type& x)
+ {
+ vector_base::resize(new_size,x);
+ }
+#elif defined(_GLIBCXX_VECTOR) && EIGEN_GNUC_AT_LEAST(4,2)
+ // workaround GCC std::vector implementation
+ void resize(size_type new_size, const value_type& x)
+ {
+ if (new_size < vector_base::size())
+ vector_base::_M_erase_at_end(this->_M_impl._M_start + new_size);
+ else
+ vector_base::insert(vector_base::end(), new_size - vector_base::size(), x);
+ }
+#else
+ // either GCC 4.1 or non-GCC
+ // default implementation which should always work.
+ void resize(size_type new_size, const value_type& x)
+ {
+ if (new_size < vector_base::size())
+ vector_base::erase(vector_base::begin() + new_size, vector_base::end());
+ else if (new_size > vector_base::size())
+ vector_base::insert(vector_base::end(), new_size - vector_base::size(), x);
+ }
+#endif
+ };
+}
+
+#endif // EIGEN_STDVECTOR_H
diff --git a/Eigen/src/StlSupport/details.h b/Eigen/src/StlSupport/details.h
new file mode 100644
index 000000000..d8debc7c4
--- /dev/null
+++ b/Eigen/src/StlSupport/details.h
@@ -0,0 +1,84 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra.
+//
+// Copyright (C) 2009 Gael Guennebaud <gael.guennebaud@inria.fr>
+// Copyright (C) 2009 Hauke Heibel <hauke.heibel@googlemail.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_STL_DETAILS_H
+#define EIGEN_STL_DETAILS_H
+
+#ifndef EIGEN_ALIGNED_ALLOCATOR
+ #define EIGEN_ALIGNED_ALLOCATOR Eigen::aligned_allocator
+#endif
+
+namespace Eigen {
+
+ // This one is needed to prevent reimplementing the whole std::vector.
+ template <class T>
+ class aligned_allocator_indirection : public EIGEN_ALIGNED_ALLOCATOR<T>
+ {
+ public:
+ typedef size_t size_type;
+ typedef ptrdiff_t difference_type;
+ typedef T* pointer;
+ typedef const T* const_pointer;
+ typedef T& reference;
+ typedef const T& const_reference;
+ typedef T value_type;
+
+ template<class U>
+ struct rebind
+ {
+ typedef aligned_allocator_indirection<U> other;
+ };
+
+ aligned_allocator_indirection() {}
+ aligned_allocator_indirection(const aligned_allocator_indirection& ) : EIGEN_ALIGNED_ALLOCATOR<T>() {}
+ aligned_allocator_indirection(const EIGEN_ALIGNED_ALLOCATOR<T>& ) {}
+ template<class U>
+ aligned_allocator_indirection(const aligned_allocator_indirection<U>& ) {}
+ template<class U>
+ aligned_allocator_indirection(const EIGEN_ALIGNED_ALLOCATOR<U>& ) {}
+ ~aligned_allocator_indirection() {}
+ };
+
+#ifdef _MSC_VER
+
+ // sometimes, MSVC detects, at compile time, that the argument x
+ // in std::vector::resize(size_t s,T x) won't be aligned and generate an error
+ // even if this function is never called. Whence this little wrapper.
+#define EIGEN_WORKAROUND_MSVC_STL_SUPPORT(T) \
+ typename Eigen::internal::conditional< \
+ Eigen::internal::is_arithmetic<T>::value, \
+ T, \
+ Eigen::internal::workaround_msvc_stl_support<T> \
+ >::type
+
+ namespace internal {
+ template<typename T> struct workaround_msvc_stl_support : public T
+ {
+ inline workaround_msvc_stl_support() : T() {}
+ inline workaround_msvc_stl_support(const T& other) : T(other) {}
+ inline operator T& () { return *static_cast<T*>(this); }
+ inline operator const T& () const { return *static_cast<const T*>(this); }
+ template<typename OtherT>
+ inline T& operator=(const OtherT& other)
+ { T::operator=(other); return *this; }
+ inline workaround_msvc_stl_support& operator=(const workaround_msvc_stl_support& other)
+ { T::operator=(other); return *this; }
+ };
+ }
+
+#else
+
+#define EIGEN_WORKAROUND_MSVC_STL_SUPPORT(T) T
+
+#endif
+
+}
+
+#endif // EIGEN_STL_DETAILS_H
diff --git a/Eigen/src/SuperLUSupport/CMakeLists.txt b/Eigen/src/SuperLUSupport/CMakeLists.txt
new file mode 100644
index 000000000..b28ebe583
--- /dev/null
+++ b/Eigen/src/SuperLUSupport/CMakeLists.txt
@@ -0,0 +1,6 @@
+FILE(GLOB Eigen_SuperLUSupport_SRCS "*.h")
+
+INSTALL(FILES
+ ${Eigen_SuperLUSupport_SRCS}
+ DESTINATION ${INCLUDE_INSTALL_DIR}/Eigen/src/SuperLUSupport COMPONENT Devel
+ )
diff --git a/Eigen/src/SuperLUSupport/SuperLUSupport.h b/Eigen/src/SuperLUSupport/SuperLUSupport.h
new file mode 100644
index 000000000..11fb014dd
--- /dev/null
+++ b/Eigen/src/SuperLUSupport/SuperLUSupport.h
@@ -0,0 +1,1025 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra.
+//
+// Copyright (C) 2008-2011 Gael Guennebaud <gael.guennebaud@inria.fr>
+//
+// This Source Code Form is subject to the terms of the Mozilla
+// Public License v. 2.0. If a copy of the MPL was not distributed
+// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+#ifndef EIGEN_SUPERLUSUPPORT_H
+#define EIGEN_SUPERLUSUPPORT_H
+
+namespace Eigen {
+
+#define DECL_GSSVX(PREFIX,FLOATTYPE,KEYTYPE) \
+ extern "C" { \
+ typedef struct { FLOATTYPE for_lu; FLOATTYPE total_needed; int expansions; } PREFIX##mem_usage_t; \
+ extern void PREFIX##gssvx(superlu_options_t *, SuperMatrix *, int *, int *, int *, \
+ char *, FLOATTYPE *, FLOATTYPE *, SuperMatrix *, SuperMatrix *, \
+ void *, int, SuperMatrix *, SuperMatrix *, \
+ FLOATTYPE *, FLOATTYPE *, FLOATTYPE *, FLOATTYPE *, \
+ PREFIX##mem_usage_t *, SuperLUStat_t *, int *); \
+ } \
+ inline float SuperLU_gssvx(superlu_options_t *options, SuperMatrix *A, \
+ int *perm_c, int *perm_r, int *etree, char *equed, \
+ FLOATTYPE *R, FLOATTYPE *C, SuperMatrix *L, \
+ SuperMatrix *U, void *work, int lwork, \
+ SuperMatrix *B, SuperMatrix *X, \
+ FLOATTYPE *recip_pivot_growth, \
+ FLOATTYPE *rcond, FLOATTYPE *ferr, FLOATTYPE *berr, \
+ SuperLUStat_t *stats, int *info, KEYTYPE) { \
+ PREFIX##mem_usage_t mem_usage; \
+ PREFIX##gssvx(options, A, perm_c, perm_r, etree, equed, R, C, L, \
+ U, work, lwork, B, X, recip_pivot_growth, rcond, \
+ ferr, berr, &mem_usage, stats, info); \
+ return mem_usage.for_lu; /* bytes used by the factor storage */ \
+ }
+
+DECL_GSSVX(s,float,float)
+DECL_GSSVX(c,float,std::complex<float>)
+DECL_GSSVX(d,double,double)
+DECL_GSSVX(z,double,std::complex<double>)
+
+#ifdef MILU_ALPHA
+#define EIGEN_SUPERLU_HAS_ILU
+#endif
+
+#ifdef EIGEN_SUPERLU_HAS_ILU
+
+// similarly for the incomplete factorization using gsisx
+#define DECL_GSISX(PREFIX,FLOATTYPE,KEYTYPE) \
+ extern "C" { \
+ extern void PREFIX##gsisx(superlu_options_t *, SuperMatrix *, int *, int *, int *, \
+ char *, FLOATTYPE *, FLOATTYPE *, SuperMatrix *, SuperMatrix *, \
+ void *, int, SuperMatrix *, SuperMatrix *, FLOATTYPE *, FLOATTYPE *, \
+ PREFIX##mem_usage_t *, SuperLUStat_t *, int *); \
+ } \
+ inline float SuperLU_gsisx(superlu_options_t *options, SuperMatrix *A, \
+ int *perm_c, int *perm_r, int *etree, char *equed, \
+ FLOATTYPE *R, FLOATTYPE *C, SuperMatrix *L, \
+ SuperMatrix *U, void *work, int lwork, \
+ SuperMatrix *B, SuperMatrix *X, \
+ FLOATTYPE *recip_pivot_growth, \
+ FLOATTYPE *rcond, \
+ SuperLUStat_t *stats, int *info, KEYTYPE) { \
+ PREFIX##mem_usage_t mem_usage; \
+ PREFIX##gsisx(options, A, perm_c, perm_r, etree, equed, R, C, L, \
+ U, work, lwork, B, X, recip_pivot_growth, rcond, \
+ &mem_usage, stats, info); \
+ return mem_usage.for_lu; /* bytes used by the factor storage */ \
+ }
+
+DECL_GSISX(s,float,float)
+DECL_GSISX(c,float,std::complex<float>)
+DECL_GSISX(d,double,double)
+DECL_GSISX(z,double,std::complex<double>)
+
+#endif
+
+template<typename MatrixType>
+struct SluMatrixMapHelper;
+
+/** \internal
+ *
+ * A wrapper class for SuperLU matrices. It supports only compressed sparse matrices
+ * and dense matrices. Supernodal and other fancy format are not supported by this wrapper.
+ *
+ * This wrapper class mainly aims to avoids the need of dynamic allocation of the storage structure.
+ */
+struct SluMatrix : SuperMatrix
+{
+ SluMatrix()
+ {
+ Store = &storage;
+ }
+
+ SluMatrix(const SluMatrix& other)
+ : SuperMatrix(other)
+ {
+ Store = &storage;
+ storage = other.storage;
+ }
+
+ SluMatrix& operator=(const SluMatrix& other)
+ {
+ SuperMatrix::operator=(static_cast<const SuperMatrix&>(other));
+ Store = &storage;
+ storage = other.storage;
+ return *this;
+ }
+
+ struct
+ {
+ union {int nnz;int lda;};
+ void *values;
+ int *innerInd;
+ int *outerInd;
+ } storage;
+
+ void setStorageType(Stype_t t)
+ {
+ Stype = t;
+ if (t==SLU_NC || t==SLU_NR || t==SLU_DN)
+ Store = &storage;
+ else
+ {
+ eigen_assert(false && "storage type not supported");
+ Store = 0;
+ }
+ }
+
+ template<typename Scalar>
+ void setScalarType()
+ {
+ if (internal::is_same<Scalar,float>::value)
+ Dtype = SLU_S;
+ else if (internal::is_same<Scalar,double>::value)
+ Dtype = SLU_D;
+ else if (internal::is_same<Scalar,std::complex<float> >::value)
+ Dtype = SLU_C;
+ else if (internal::is_same<Scalar,std::complex<double> >::value)
+ Dtype = SLU_Z;
+ else
+ {
+ eigen_assert(false && "Scalar type not supported by SuperLU");
+ }
+ }
+
+ template<typename MatrixType>
+ static SluMatrix Map(MatrixBase<MatrixType>& _mat)
+ {
+ MatrixType& mat(_mat.derived());
+ eigen_assert( ((MatrixType::Flags&RowMajorBit)!=RowMajorBit) && "row-major dense matrices are not supported by SuperLU");
+ SluMatrix res;
+ res.setStorageType(SLU_DN);
+ res.setScalarType<typename MatrixType::Scalar>();
+ res.Mtype = SLU_GE;
+
+ res.nrow = mat.rows();
+ res.ncol = mat.cols();
+
+ res.storage.lda = MatrixType::IsVectorAtCompileTime ? mat.size() : mat.outerStride();
+ res.storage.values = mat.data();
+ return res;
+ }
+
+ template<typename MatrixType>
+ static SluMatrix Map(SparseMatrixBase<MatrixType>& mat)
+ {
+ SluMatrix res;
+ if ((MatrixType::Flags&RowMajorBit)==RowMajorBit)
+ {
+ res.setStorageType(SLU_NR);
+ res.nrow = mat.cols();
+ res.ncol = mat.rows();
+ }
+ else
+ {
+ res.setStorageType(SLU_NC);
+ res.nrow = mat.rows();
+ res.ncol = mat.cols();
+ }
+
+ res.Mtype = SLU_GE;
+
+ res.storage.nnz = mat.nonZeros();
+ res.storage.values = mat.derived().valuePtr();
+ res.storage.innerInd = mat.derived().innerIndexPtr();
+ res.storage.outerInd = mat.derived().outerIndexPtr();
+
+ res.setScalarType<typename MatrixType::Scalar>();
+
+ // FIXME the following is not very accurate
+ if (MatrixType::Flags & Upper)
+ res.Mtype = SLU_TRU;
+ if (MatrixType::Flags & Lower)
+ res.Mtype = SLU_TRL;
+
+ eigen_assert(((MatrixType::Flags & SelfAdjoint)==0) && "SelfAdjoint matrix shape not supported by SuperLU");
+
+ return res;
+ }
+};
+
+template<typename Scalar, int Rows, int Cols, int Options, int MRows, int MCols>
+struct SluMatrixMapHelper<Matrix<Scalar,Rows,Cols,Options,MRows,MCols> >
+{
+ typedef Matrix<Scalar,Rows,Cols,Options,MRows,MCols> MatrixType;
+ static void run(MatrixType& mat, SluMatrix& res)
+ {
+ eigen_assert( ((Options&RowMajor)!=RowMajor) && "row-major dense matrices is not supported by SuperLU");
+ res.setStorageType(SLU_DN);
+ res.setScalarType<Scalar>();
+ res.Mtype = SLU_GE;
+
+ res.nrow = mat.rows();
+ res.ncol = mat.cols();
+
+ res.storage.lda = mat.outerStride();
+ res.storage.values = mat.data();
+ }
+};
+
+template<typename Derived>
+struct SluMatrixMapHelper<SparseMatrixBase<Derived> >
+{
+ typedef Derived MatrixType;
+ static void run(MatrixType& mat, SluMatrix& res)
+ {
+ if ((MatrixType::Flags&RowMajorBit)==RowMajorBit)
+ {
+ res.setStorageType(SLU_NR);
+ res.nrow = mat.cols();
+ res.ncol = mat.rows();
+ }
+ else
+ {
+ res.setStorageType(SLU_NC);
+ res.nrow = mat.rows();
+ res.ncol = mat.cols();
+ }
+
+ res.Mtype = SLU_GE;
+
+ res.storage.nnz = mat.nonZeros();
+ res.storage.values = mat.valuePtr();
+ res.storage.innerInd = mat.innerIndexPtr();
+ res.storage.outerInd = mat.outerIndexPtr();
+
+ res.setScalarType<typename MatrixType::Scalar>();
+
+ // FIXME the following is not very accurate
+ if (MatrixType::Flags & Upper)
+ res.Mtype = SLU_TRU;
+ if (MatrixType::Flags & Lower)
+ res.Mtype = SLU_TRL;
+
+ eigen_assert(((MatrixType::Flags & SelfAdjoint)==0) && "SelfAdjoint matrix shape not supported by SuperLU");
+ }
+};
+
+namespace internal {
+
+template<typename MatrixType>
+SluMatrix asSluMatrix(MatrixType& mat)
+{
+ return SluMatrix::Map(mat);
+}
+
+/** View a Super LU matrix as an Eigen expression */
+template<typename Scalar, int Flags, typename Index>
+MappedSparseMatrix<Scalar,Flags,Index> map_superlu(SluMatrix& sluMat)
+{
+ eigen_assert((Flags&RowMajor)==RowMajor && sluMat.Stype == SLU_NR
+ || (Flags&ColMajor)==ColMajor && sluMat.Stype == SLU_NC);
+
+ Index outerSize = (Flags&RowMajor)==RowMajor ? sluMat.ncol : sluMat.nrow;
+
+ return MappedSparseMatrix<Scalar,Flags,Index>(
+ sluMat.nrow, sluMat.ncol, sluMat.storage.outerInd[outerSize],
+ sluMat.storage.outerInd, sluMat.storage.innerInd, reinterpret_cast<Scalar*>(sluMat.storage.values) );
+}
+
+} // end namespace internal
+
+/** \ingroup SuperLUSupport_Module
+ * \class SuperLUBase
+ * \brief The base class for the direct and incomplete LU factorization of SuperLU
+ */
+template<typename _MatrixType, typename Derived>
+class SuperLUBase : internal::noncopyable
+{
+ public:
+ typedef _MatrixType MatrixType;
+ typedef typename MatrixType::Scalar Scalar;
+ typedef typename MatrixType::RealScalar RealScalar;
+ typedef typename MatrixType::Index Index;
+ typedef Matrix<Scalar,Dynamic,1> Vector;
+ typedef Matrix<int, 1, MatrixType::ColsAtCompileTime> IntRowVectorType;
+ typedef Matrix<int, MatrixType::RowsAtCompileTime, 1> IntColVectorType;
+ typedef SparseMatrix<Scalar> LUMatrixType;
+
+ public:
+
+ SuperLUBase() {}
+
+ ~SuperLUBase()
+ {
+ clearFactors();
+ }
+
+ Derived& derived() { return *static_cast<Derived*>(this); }
+ const Derived& derived() const { return *static_cast<const Derived*>(this); }
+
+ inline Index rows() const { return m_matrix.rows(); }
+ inline Index cols() const { return m_matrix.cols(); }
+
+ /** \returns a reference to the Super LU option object to configure the Super LU algorithms. */
+ inline superlu_options_t& options() { return m_sluOptions; }
+
+ /** \brief Reports whether previous computation was successful.
+ *
+ * \returns \c Success if computation was succesful,
+ * \c NumericalIssue if the matrix.appears to be negative.
+ */
+ ComputationInfo info() const
+ {
+ eigen_assert(m_isInitialized && "Decomposition is not initialized.");
+ return m_info;
+ }
+
+ /** Computes the sparse Cholesky decomposition of \a matrix */
+ void compute(const MatrixType& matrix)
+ {
+ derived().analyzePattern(matrix);
+ derived().factorize(matrix);
+ }
+
+ /** \returns the solution x of \f$ A x = b \f$ using the current decomposition of A.
+ *
+ * \sa compute()
+ */
+ template<typename Rhs>
+ inline const internal::solve_retval<SuperLUBase, Rhs> solve(const MatrixBase<Rhs>& b) const
+ {
+ eigen_assert(m_isInitialized && "SuperLU is not initialized.");
+ eigen_assert(rows()==b.rows()
+ && "SuperLU::solve(): invalid number of rows of the right hand side matrix b");
+ return internal::solve_retval<SuperLUBase, Rhs>(*this, b.derived());
+ }
+
+ /** \returns the solution x of \f$ A x = b \f$ using the current decomposition of A.
+ *
+ * \sa compute()
+ */
+// template<typename Rhs>
+// inline const internal::sparse_solve_retval<SuperLU, Rhs> solve(const SparseMatrixBase<Rhs>& b) const
+// {
+// eigen_assert(m_isInitialized && "SuperLU is not initialized.");
+// eigen_assert(rows()==b.rows()
+// && "SuperLU::solve(): invalid number of rows of the right hand side matrix b");
+// return internal::sparse_solve_retval<SuperLU, Rhs>(*this, b.derived());
+// }
+
+ /** Performs a symbolic decomposition on the sparcity of \a matrix.
+ *
+ * This function is particularly useful when solving for several problems having the same structure.
+ *
+ * \sa factorize()
+ */
+ void analyzePattern(const MatrixType& /*matrix*/)
+ {
+ m_isInitialized = true;
+ m_info = Success;
+ m_analysisIsOk = true;
+ m_factorizationIsOk = false;
+ }
+
+ template<typename Stream>
+ void dumpMemory(Stream& s)
+ {}
+
+ protected:
+
+ void initFactorization(const MatrixType& a)
+ {
+ set_default_options(&this->m_sluOptions);
+
+ const int size = a.rows();
+ m_matrix = a;
+
+ m_sluA = internal::asSluMatrix(m_matrix);
+ clearFactors();
+
+ m_p.resize(size);
+ m_q.resize(size);
+ m_sluRscale.resize(size);
+ m_sluCscale.resize(size);
+ m_sluEtree.resize(size);
+
+ // set empty B and X
+ m_sluB.setStorageType(SLU_DN);
+ m_sluB.setScalarType<Scalar>();
+ m_sluB.Mtype = SLU_GE;
+ m_sluB.storage.values = 0;
+ m_sluB.nrow = 0;
+ m_sluB.ncol = 0;
+ m_sluB.storage.lda = size;
+ m_sluX = m_sluB;
+
+ m_extractedDataAreDirty = true;
+ }
+
+ void init()
+ {
+ m_info = InvalidInput;
+ m_isInitialized = false;
+ m_sluL.Store = 0;
+ m_sluU.Store = 0;
+ }
+
+ void extractData() const;
+
+ void clearFactors()
+ {
+ if(m_sluL.Store)
+ Destroy_SuperNode_Matrix(&m_sluL);
+ if(m_sluU.Store)
+ Destroy_CompCol_Matrix(&m_sluU);
+
+ m_sluL.Store = 0;
+ m_sluU.Store = 0;
+
+ memset(&m_sluL,0,sizeof m_sluL);
+ memset(&m_sluU,0,sizeof m_sluU);
+ }
+
+ // cached data to reduce reallocation, etc.
+ mutable LUMatrixType m_l;
+ mutable LUMatrixType m_u;
+ mutable IntColVectorType m_p;
+ mutable IntRowVectorType m_q;
+
+ mutable LUMatrixType m_matrix; // copy of the factorized matrix
+ mutable SluMatrix m_sluA;
+ mutable SuperMatrix m_sluL, m_sluU;
+ mutable SluMatrix m_sluB, m_sluX;
+ mutable SuperLUStat_t m_sluStat;
+ mutable superlu_options_t m_sluOptions;
+ mutable std::vector<int> m_sluEtree;
+ mutable Matrix<RealScalar,Dynamic,1> m_sluRscale, m_sluCscale;
+ mutable Matrix<RealScalar,Dynamic,1> m_sluFerr, m_sluBerr;
+ mutable char m_sluEqued;
+
+ mutable ComputationInfo m_info;
+ bool m_isInitialized;
+ int m_factorizationIsOk;
+ int m_analysisIsOk;
+ mutable bool m_extractedDataAreDirty;
+
+ private:
+ SuperLUBase(SuperLUBase& ) { }
+};
+
+
+/** \ingroup SuperLUSupport_Module
+ * \class SuperLU
+ * \brief A sparse direct LU factorization and solver based on the SuperLU library
+ *
+ * This class allows to solve for A.X = B sparse linear problems via a direct LU factorization
+ * using the SuperLU library. The sparse matrix A must be squared and invertible. The vectors or matrices
+ * X and B can be either dense or sparse.
+ *
+ * \tparam _MatrixType the type of the sparse matrix A, it must be a SparseMatrix<>
+ *
+ * \sa \ref TutorialSparseDirectSolvers
+ */
+template<typename _MatrixType>
+class SuperLU : public SuperLUBase<_MatrixType,SuperLU<_MatrixType> >
+{
+ public:
+ typedef SuperLUBase<_MatrixType,SuperLU> Base;
+ typedef _MatrixType MatrixType;
+ typedef typename Base::Scalar Scalar;
+ typedef typename Base::RealScalar RealScalar;
+ typedef typename Base::Index Index;
+ typedef typename Base::IntRowVectorType IntRowVectorType;
+ typedef typename Base::IntColVectorType IntColVectorType;
+ typedef typename Base::LUMatrixType LUMatrixType;
+ typedef TriangularView<LUMatrixType, Lower|UnitDiag> LMatrixType;
+ typedef TriangularView<LUMatrixType, Upper> UMatrixType;
+
+ public:
+
+ SuperLU() : Base() { init(); }
+
+ SuperLU(const MatrixType& matrix) : Base()
+ {
+ Base::init();
+ compute(matrix);
+ }
+
+ ~SuperLU()
+ {
+ }
+
+ /** Performs a symbolic decomposition on the sparcity of \a matrix.
+ *
+ * This function is particularly useful when solving for several problems having the same structure.
+ *
+ * \sa factorize()
+ */
+ void analyzePattern(const MatrixType& matrix)
+ {
+ m_info = InvalidInput;
+ m_isInitialized = false;
+ Base::analyzePattern(matrix);
+ }
+
+ /** Performs a numeric decomposition of \a matrix
+ *
+ * The given matrix must has the same sparcity than the matrix on which the symbolic decomposition has been performed.
+ *
+ * \sa analyzePattern()
+ */
+ void factorize(const MatrixType& matrix);
+
+ #ifndef EIGEN_PARSED_BY_DOXYGEN
+ /** \internal */
+ template<typename Rhs,typename Dest>
+ void _solve(const MatrixBase<Rhs> &b, MatrixBase<Dest> &dest) const;
+ #endif // EIGEN_PARSED_BY_DOXYGEN
+
+ inline const LMatrixType& matrixL() const
+ {
+ if (m_extractedDataAreDirty) this->extractData();
+ return m_l;
+ }
+
+ inline const UMatrixType& matrixU() const
+ {
+ if (m_extractedDataAreDirty) this->extractData();
+ return m_u;
+ }
+
+ inline const IntColVectorType& permutationP() const
+ {
+ if (m_extractedDataAreDirty) this->extractData();
+ return m_p;
+ }
+
+ inline const IntRowVectorType& permutationQ() const
+ {
+ if (m_extractedDataAreDirty) this->extractData();
+ return m_q;
+ }
+
+ Scalar determinant() const;
+
+ protected:
+
+ using Base::m_matrix;
+ using Base::m_sluOptions;
+ using Base::m_sluA;
+ using Base::m_sluB;
+ using Base::m_sluX;
+ using Base::m_p;
+ using Base::m_q;
+ using Base::m_sluEtree;
+ using Base::m_sluEqued;
+ using Base::m_sluRscale;
+ using Base::m_sluCscale;
+ using Base::m_sluL;
+ using Base::m_sluU;
+ using Base::m_sluStat;
+ using Base::m_sluFerr;
+ using Base::m_sluBerr;
+ using Base::m_l;
+ using Base::m_u;
+
+ using Base::m_analysisIsOk;
+ using Base::m_factorizationIsOk;
+ using Base::m_extractedDataAreDirty;
+ using Base::m_isInitialized;
+ using Base::m_info;
+
+ void init()
+ {
+ Base::init();
+
+ set_default_options(&this->m_sluOptions);
+ m_sluOptions.PrintStat = NO;
+ m_sluOptions.ConditionNumber = NO;
+ m_sluOptions.Trans = NOTRANS;
+ m_sluOptions.ColPerm = COLAMD;
+ }
+
+
+ private:
+ SuperLU(SuperLU& ) { }
+};
+
+template<typename MatrixType>
+void SuperLU<MatrixType>::factorize(const MatrixType& a)
+{
+ eigen_assert(m_analysisIsOk && "You must first call analyzePattern()");
+ if(!m_analysisIsOk)
+ {
+ m_info = InvalidInput;
+ return;
+ }
+
+ this->initFactorization(a);
+
+ int info = 0;
+ RealScalar recip_pivot_growth, rcond;
+ RealScalar ferr, berr;
+
+ StatInit(&m_sluStat);
+ SuperLU_gssvx(&m_sluOptions, &m_sluA, m_q.data(), m_p.data(), &m_sluEtree[0],
+ &m_sluEqued, &m_sluRscale[0], &m_sluCscale[0],
+ &m_sluL, &m_sluU,
+ NULL, 0,
+ &m_sluB, &m_sluX,
+ &recip_pivot_growth, &rcond,
+ &ferr, &berr,
+ &m_sluStat, &info, Scalar());
+ StatFree(&m_sluStat);
+
+ m_extractedDataAreDirty = true;
+
+ // FIXME how to better check for errors ???
+ m_info = info == 0 ? Success : NumericalIssue;
+ m_factorizationIsOk = true;
+}
+
+template<typename MatrixType>
+template<typename Rhs,typename Dest>
+void SuperLU<MatrixType>::_solve(const MatrixBase<Rhs> &b, MatrixBase<Dest>& x) const
+{
+ eigen_assert(m_factorizationIsOk && "The decomposition is not in a valid state for solving, you must first call either compute() or analyzePattern()/factorize()");
+
+ const int size = m_matrix.rows();
+ const int rhsCols = b.cols();
+ eigen_assert(size==b.rows());
+
+ m_sluOptions.Trans = NOTRANS;
+ m_sluOptions.Fact = FACTORED;
+ m_sluOptions.IterRefine = NOREFINE;
+
+
+ m_sluFerr.resize(rhsCols);
+ m_sluBerr.resize(rhsCols);
+ m_sluB = SluMatrix::Map(b.const_cast_derived());
+ m_sluX = SluMatrix::Map(x.derived());
+
+ typename Rhs::PlainObject b_cpy;
+ if(m_sluEqued!='N')
+ {
+ b_cpy = b;
+ m_sluB = SluMatrix::Map(b_cpy.const_cast_derived());
+ }
+
+ StatInit(&m_sluStat);
+ int info = 0;
+ RealScalar recip_pivot_growth, rcond;
+ SuperLU_gssvx(&m_sluOptions, &m_sluA,
+ m_q.data(), m_p.data(),
+ &m_sluEtree[0], &m_sluEqued,
+ &m_sluRscale[0], &m_sluCscale[0],
+ &m_sluL, &m_sluU,
+ NULL, 0,
+ &m_sluB, &m_sluX,
+ &recip_pivot_growth, &rcond,
+ &m_sluFerr[0], &m_sluBerr[0],
+ &m_sluStat, &info, Scalar());
+ StatFree(&m_sluStat);
+ m_info = info==0 ? Success : NumericalIssue;
+}
+
+// the code of this extractData() function has been adapted from the SuperLU's Matlab support code,
+//
+// Copyright (c) 1994 by Xerox Corporation. All rights reserved.
+//
+// THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY
+// EXPRESSED OR IMPLIED. ANY USE IS AT YOUR OWN RISK.
+//
+template<typename MatrixType, typename Derived>
+void SuperLUBase<MatrixType,Derived>::extractData() const
+{
+ eigen_assert(m_factorizationIsOk && "The decomposition is not in a valid state for extracting factors, you must first call either compute() or analyzePattern()/factorize()");
+ if (m_extractedDataAreDirty)
+ {
+ int upper;
+ int fsupc, istart, nsupr;
+ int lastl = 0, lastu = 0;
+ SCformat *Lstore = static_cast<SCformat*>(m_sluL.Store);
+ NCformat *Ustore = static_cast<NCformat*>(m_sluU.Store);
+ Scalar *SNptr;
+
+ const int size = m_matrix.rows();
+ m_l.resize(size,size);
+ m_l.resizeNonZeros(Lstore->nnz);
+ m_u.resize(size,size);
+ m_u.resizeNonZeros(Ustore->nnz);
+
+ int* Lcol = m_l.outerIndexPtr();
+ int* Lrow = m_l.innerIndexPtr();
+ Scalar* Lval = m_l.valuePtr();
+
+ int* Ucol = m_u.outerIndexPtr();
+ int* Urow = m_u.innerIndexPtr();
+ Scalar* Uval = m_u.valuePtr();
+
+ Ucol[0] = 0;
+ Ucol[0] = 0;
+
+ /* for each supernode */
+ for (int k = 0; k <= Lstore->nsuper; ++k)
+ {
+ fsupc = L_FST_SUPC(k);
+ istart = L_SUB_START(fsupc);
+ nsupr = L_SUB_START(fsupc+1) - istart;
+ upper = 1;
+
+ /* for each column in the supernode */
+ for (int j = fsupc; j < L_FST_SUPC(k+1); ++j)
+ {
+ SNptr = &((Scalar*)Lstore->nzval)[L_NZ_START(j)];
+
+ /* Extract U */
+ for (int i = U_NZ_START(j); i < U_NZ_START(j+1); ++i)
+ {
+ Uval[lastu] = ((Scalar*)Ustore->nzval)[i];
+ /* Matlab doesn't like explicit zero. */
+ if (Uval[lastu] != 0.0)
+ Urow[lastu++] = U_SUB(i);
+ }
+ for (int i = 0; i < upper; ++i)
+ {
+ /* upper triangle in the supernode */
+ Uval[lastu] = SNptr[i];
+ /* Matlab doesn't like explicit zero. */
+ if (Uval[lastu] != 0.0)
+ Urow[lastu++] = L_SUB(istart+i);
+ }
+ Ucol[j+1] = lastu;
+
+ /* Extract L */
+ Lval[lastl] = 1.0; /* unit diagonal */
+ Lrow[lastl++] = L_SUB(istart + upper - 1);
+ for (int i = upper; i < nsupr; ++i)
+ {
+ Lval[lastl] = SNptr[i];
+ /* Matlab doesn't like explicit zero. */
+ if (Lval[lastl] != 0.0)
+ Lrow[lastl++] = L_SUB(istart+i);
+ }
+ Lcol[j+1] = lastl;
+
+ ++upper;
+ } /* for j ... */
+
+ } /* for k ... */
+
+ // squeeze the matrices :
+ m_l.resizeNonZeros(lastl);
+ m_u.resizeNonZeros(lastu);
+
+ m_extractedDataAreDirty = false;
+ }
+}
+
+template<typename MatrixType>
+typename SuperLU<MatrixType>::Scalar SuperLU<MatrixType>::determinant() const
+{
+ eigen_assert(m_factorizationIsOk && "The decomposition is not in a valid state for computing the determinant, you must first call either compute() or analyzePattern()/factorize()");
+
+ if (m_extractedDataAreDirty)
+ this->extractData();
+
+ Scalar det = Scalar(1);
+ for (int j=0; j<m_u.cols(); ++j)
+ {
+ if (m_u.outerIndexPtr()[j+1]-m_u.outerIndexPtr()[j] > 0)
+ {
+ int lastId = m_u.outerIndexPtr()[j+1]-1;
+ eigen_assert(m_u.innerIndexPtr()[lastId]<=j);
+ if (m_u.innerIndexPtr()[lastId]==j)
+ det *= m_u.valuePtr()[lastId];
+ }
+ }
+ if(m_sluEqued!='N')
+ return det/m_sluRscale.prod()/m_sluCscale.prod();
+ else
+ return det;
+}
+
+#ifdef EIGEN_PARSED_BY_DOXYGEN
+#define EIGEN_SUPERLU_HAS_ILU
+#endif
+
+#ifdef EIGEN_SUPERLU_HAS_ILU
+
+/** \ingroup SuperLUSupport_Module
+ * \class SuperILU
+ * \brief A sparse direct \b incomplete LU factorization and solver based on the SuperLU library
+ *
+ * This class allows to solve for an approximate solution of A.X = B sparse linear problems via an incomplete LU factorization
+ * using the SuperLU library. This class is aimed to be used as a preconditioner of the iterative linear solvers.
+ *
+ * \warning This class requires SuperLU 4 or later.
+ *
+ * \tparam _MatrixType the type of the sparse matrix A, it must be a SparseMatrix<>
+ *
+ * \sa \ref TutorialSparseDirectSolvers, class ConjugateGradient, class BiCGSTAB
+ */
+
+template<typename _MatrixType>
+class SuperILU : public SuperLUBase<_MatrixType,SuperILU<_MatrixType> >
+{
+ public:
+ typedef SuperLUBase<_MatrixType,SuperILU> Base;
+ typedef _MatrixType MatrixType;
+ typedef typename Base::Scalar Scalar;
+ typedef typename Base::RealScalar RealScalar;
+ typedef typename Base::Index Index;
+
+ public:
+
+ SuperILU() : Base() { init(); }
+
+ SuperILU(const MatrixType& matrix) : Base()
+ {
+ init();
+ compute(matrix);
+ }
+
+ ~SuperILU()
+ {
+ }
+
+ /** Performs a symbolic decomposition on the sparcity of \a matrix.
+ *
+ * This function is particularly useful when solving for several problems having the same structure.
+ *
+ * \sa factorize()
+ */
+ void analyzePattern(const MatrixType& matrix)
+ {
+ Base::analyzePattern(matrix);
+ }
+
+ /** Performs a numeric decomposition of \a matrix
+ *
+ * The given matrix must has the same sparcity than the matrix on which the symbolic decomposition has been performed.
+ *
+ * \sa analyzePattern()
+ */
+ void factorize(const MatrixType& matrix);
+
+ #ifndef EIGEN_PARSED_BY_DOXYGEN
+ /** \internal */
+ template<typename Rhs,typename Dest>
+ void _solve(const MatrixBase<Rhs> &b, MatrixBase<Dest> &dest) const;
+ #endif // EIGEN_PARSED_BY_DOXYGEN
+
+ protected:
+
+ using Base::m_matrix;
+ using Base::m_sluOptions;
+ using Base::m_sluA;
+ using Base::m_sluB;
+ using Base::m_sluX;
+ using Base::m_p;
+ using Base::m_q;
+ using Base::m_sluEtree;
+ using Base::m_sluEqued;
+ using Base::m_sluRscale;
+ using Base::m_sluCscale;
+ using Base::m_sluL;
+ using Base::m_sluU;
+ using Base::m_sluStat;
+ using Base::m_sluFerr;
+ using Base::m_sluBerr;
+ using Base::m_l;
+ using Base::m_u;
+
+ using Base::m_analysisIsOk;
+ using Base::m_factorizationIsOk;
+ using Base::m_extractedDataAreDirty;
+ using Base::m_isInitialized;
+ using Base::m_info;
+
+ void init()
+ {
+ Base::init();
+
+ ilu_set_default_options(&m_sluOptions);
+ m_sluOptions.PrintStat = NO;
+ m_sluOptions.ConditionNumber = NO;
+ m_sluOptions.Trans = NOTRANS;
+ m_sluOptions.ColPerm = MMD_AT_PLUS_A;
+
+ // no attempt to preserve column sum
+ m_sluOptions.ILU_MILU = SILU;
+ // only basic ILU(k) support -- no direct control over memory consumption
+ // better to use ILU_DropRule = DROP_BASIC | DROP_AREA
+ // and set ILU_FillFactor to max memory growth
+ m_sluOptions.ILU_DropRule = DROP_BASIC;
+ m_sluOptions.ILU_DropTol = NumTraits<Scalar>::dummy_precision()*10;
+ }
+
+ private:
+ SuperILU(SuperILU& ) { }
+};
+
+template<typename MatrixType>
+void SuperILU<MatrixType>::factorize(const MatrixType& a)
+{
+ eigen_assert(m_analysisIsOk && "You must first call analyzePattern()");
+ if(!m_analysisIsOk)
+ {
+ m_info = InvalidInput;
+ return;
+ }
+
+ this->initFactorization(a);
+
+ int info = 0;
+ RealScalar recip_pivot_growth, rcond;
+
+ StatInit(&m_sluStat);
+ SuperLU_gsisx(&m_sluOptions, &m_sluA, m_q.data(), m_p.data(), &m_sluEtree[0],
+ &m_sluEqued, &m_sluRscale[0], &m_sluCscale[0],
+ &m_sluL, &m_sluU,
+ NULL, 0,
+ &m_sluB, &m_sluX,
+ &recip_pivot_growth, &rcond,
+ &m_sluStat, &info, Scalar());
+ StatFree(&m_sluStat);
+
+ // FIXME how to better check for errors ???
+ m_info = info == 0 ? Success : NumericalIssue;
+ m_factorizationIsOk = true;
+}
+
+template<typename MatrixType>
+template<typename Rhs,typename Dest>
+void SuperILU<MatrixType>::_solve(const MatrixBase<Rhs> &b, MatrixBase<Dest>& x) const
+{
+ eigen_assert(m_factorizationIsOk && "The decomposition is not in a valid state for solving, you must first call either compute() or analyzePattern()/factorize()");
+
+ const int size = m_matrix.rows();
+ const int rhsCols = b.cols();
+ eigen_assert(size==b.rows());
+
+ m_sluOptions.Trans = NOTRANS;
+ m_sluOptions.Fact = FACTORED;
+ m_sluOptions.IterRefine = NOREFINE;
+
+ m_sluFerr.resize(rhsCols);
+ m_sluBerr.resize(rhsCols);
+ m_sluB = SluMatrix::Map(b.const_cast_derived());
+ m_sluX = SluMatrix::Map(x.derived());
+
+ typename Rhs::PlainObject b_cpy;
+ if(m_sluEqued!='N')
+ {
+ b_cpy = b;
+ m_sluB = SluMatrix::Map(b_cpy.const_cast_derived());
+ }
+
+ int info = 0;
+ RealScalar recip_pivot_growth, rcond;
+
+ StatInit(&m_sluStat);
+ SuperLU_gsisx(&m_sluOptions, &m_sluA,
+ m_q.data(), m_p.data(),
+ &m_sluEtree[0], &m_sluEqued,
+ &m_sluRscale[0], &m_sluCscale[0],
+ &m_sluL, &m_sluU,
+ NULL, 0,
+ &m_sluB, &m_sluX,
+ &recip_pivot_growth, &rcond,
+ &m_sluStat, &info, Scalar());
+ StatFree(&m_sluStat);
+
+ m_info = info==0 ? Success : NumericalIssue;
+}
+#endif
+
+namespace internal {
+
+template<typename _MatrixType, typename Derived, typename Rhs>
+struct solve_retval<SuperLUBase<_MatrixType,Derived>, Rhs>
+ : solve_retval_base<SuperLUBase<_MatrixType,Derived>, Rhs>
+{
+ typedef SuperLUBase<_MatrixType,Derived> Dec;
+ EIGEN_MAKE_SOLVE_HELPERS(Dec,Rhs)
+
+ template<typename Dest> void evalTo(Dest& dst) const
+ {
+ dec().derived()._solve(rhs(),dst);
+ }
+};
+
+template<typename _MatrixType, typename Derived, typename Rhs>
+struct sparse_solve_retval<SuperLUBase<_MatrixType,Derived>, Rhs>
+ : sparse_solve_retval_base<SuperLUBase<_MatrixType,Derived>, Rhs>
+{
+ typedef SuperLUBase<_MatrixType,Derived> Dec;
+ EIGEN_MAKE_SPARSE_SOLVE_HELPERS(Dec,Rhs)
+
+ template<typename Dest> void evalTo(Dest& dst) const
+ {
+ dec().derived()._solve(rhs(),dst);
+ }
+};
+
+} // end namespace internal
+
+} // end namespace Eigen
+
+#endif // EIGEN_SUPERLUSUPPORT_H
diff --git a/Eigen/src/UmfPackSupport/CMakeLists.txt b/Eigen/src/UmfPackSupport/CMakeLists.txt
new file mode 100644
index 000000000..a57de0020
--- /dev/null
+++ b/Eigen/src/UmfPackSupport/CMakeLists.txt
@@ -0,0 +1,6 @@
+FILE(GLOB Eigen_UmfPackSupport_SRCS "*.h")
+
+INSTALL(FILES
+ ${Eigen_UmfPackSupport_SRCS}
+ DESTINATION ${INCLUDE_INSTALL_DIR}/Eigen/src/UmfPackSupport COMPONENT Devel
+ )
diff --git a/Eigen/src/UmfPackSupport/UmfPackSupport.h b/Eigen/src/UmfPackSupport/UmfPackSupport.h
new file mode 100644
index 000000000..f01720362
--- /dev/null
+++ b/Eigen/src/UmfPackSupport/UmfPackSupport.h
@@ -0,0 +1,431 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra.
+//
+// Copyright (C) 2008-2011 Gael Guennebaud <gael.guennebaud@inria.fr>
+//
+// This Source Code Form is subject to the terms of the Mozilla
+// Public License v. 2.0. If a copy of the MPL was not distributed
+// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+#ifndef EIGEN_UMFPACKSUPPORT_H
+#define EIGEN_UMFPACKSUPPORT_H
+
+namespace Eigen {
+
+/* TODO extract L, extract U, compute det, etc... */
+
+// generic double/complex<double> wrapper functions:
+
+inline void umfpack_free_numeric(void **Numeric, double)
+{ umfpack_di_free_numeric(Numeric); *Numeric = 0; }
+
+inline void umfpack_free_numeric(void **Numeric, std::complex<double>)
+{ umfpack_zi_free_numeric(Numeric); *Numeric = 0; }
+
+inline void umfpack_free_symbolic(void **Symbolic, double)
+{ umfpack_di_free_symbolic(Symbolic); *Symbolic = 0; }
+
+inline void umfpack_free_symbolic(void **Symbolic, std::complex<double>)
+{ umfpack_zi_free_symbolic(Symbolic); *Symbolic = 0; }
+
+inline int umfpack_symbolic(int n_row,int n_col,
+ const int Ap[], const int Ai[], const double Ax[], void **Symbolic,
+ const double Control [UMFPACK_CONTROL], double Info [UMFPACK_INFO])
+{
+ return umfpack_di_symbolic(n_row,n_col,Ap,Ai,Ax,Symbolic,Control,Info);
+}
+
+inline int umfpack_symbolic(int n_row,int n_col,
+ const int Ap[], const int Ai[], const std::complex<double> Ax[], void **Symbolic,
+ const double Control [UMFPACK_CONTROL], double Info [UMFPACK_INFO])
+{
+ return umfpack_zi_symbolic(n_row,n_col,Ap,Ai,&internal::real_ref(Ax[0]),0,Symbolic,Control,Info);
+}
+
+inline int umfpack_numeric( const int Ap[], const int Ai[], const double Ax[],
+ void *Symbolic, void **Numeric,
+ const double Control[UMFPACK_CONTROL],double Info [UMFPACK_INFO])
+{
+ return umfpack_di_numeric(Ap,Ai,Ax,Symbolic,Numeric,Control,Info);
+}
+
+inline int umfpack_numeric( const int Ap[], const int Ai[], const std::complex<double> Ax[],
+ void *Symbolic, void **Numeric,
+ const double Control[UMFPACK_CONTROL],double Info [UMFPACK_INFO])
+{
+ return umfpack_zi_numeric(Ap,Ai,&internal::real_ref(Ax[0]),0,Symbolic,Numeric,Control,Info);
+}
+
+inline int umfpack_solve( int sys, const int Ap[], const int Ai[], const double Ax[],
+ double X[], const double B[], void *Numeric,
+ const double Control[UMFPACK_CONTROL], double Info[UMFPACK_INFO])
+{
+ return umfpack_di_solve(sys,Ap,Ai,Ax,X,B,Numeric,Control,Info);
+}
+
+inline int umfpack_solve( int sys, const int Ap[], const int Ai[], const std::complex<double> Ax[],
+ std::complex<double> X[], const std::complex<double> B[], void *Numeric,
+ const double Control[UMFPACK_CONTROL], double Info[UMFPACK_INFO])
+{
+ return umfpack_zi_solve(sys,Ap,Ai,&internal::real_ref(Ax[0]),0,&internal::real_ref(X[0]),0,&internal::real_ref(B[0]),0,Numeric,Control,Info);
+}
+
+inline int umfpack_get_lunz(int *lnz, int *unz, int *n_row, int *n_col, int *nz_udiag, void *Numeric, double)
+{
+ return umfpack_di_get_lunz(lnz,unz,n_row,n_col,nz_udiag,Numeric);
+}
+
+inline int umfpack_get_lunz(int *lnz, int *unz, int *n_row, int *n_col, int *nz_udiag, void *Numeric, std::complex<double>)
+{
+ return umfpack_zi_get_lunz(lnz,unz,n_row,n_col,nz_udiag,Numeric);
+}
+
+inline int umfpack_get_numeric(int Lp[], int Lj[], double Lx[], int Up[], int Ui[], double Ux[],
+ int P[], int Q[], double Dx[], int *do_recip, double Rs[], void *Numeric)
+{
+ return umfpack_di_get_numeric(Lp,Lj,Lx,Up,Ui,Ux,P,Q,Dx,do_recip,Rs,Numeric);
+}
+
+inline int umfpack_get_numeric(int Lp[], int Lj[], std::complex<double> Lx[], int Up[], int Ui[], std::complex<double> Ux[],
+ int P[], int Q[], std::complex<double> Dx[], int *do_recip, double Rs[], void *Numeric)
+{
+ double& lx0_real = internal::real_ref(Lx[0]);
+ double& ux0_real = internal::real_ref(Ux[0]);
+ double& dx0_real = internal::real_ref(Dx[0]);
+ return umfpack_zi_get_numeric(Lp,Lj,Lx?&lx0_real:0,0,Up,Ui,Ux?&ux0_real:0,0,P,Q,
+ Dx?&dx0_real:0,0,do_recip,Rs,Numeric);
+}
+
+inline int umfpack_get_determinant(double *Mx, double *Ex, void *NumericHandle, double User_Info [UMFPACK_INFO])
+{
+ return umfpack_di_get_determinant(Mx,Ex,NumericHandle,User_Info);
+}
+
+inline int umfpack_get_determinant(std::complex<double> *Mx, double *Ex, void *NumericHandle, double User_Info [UMFPACK_INFO])
+{
+ double& mx_real = internal::real_ref(*Mx);
+ return umfpack_zi_get_determinant(&mx_real,0,Ex,NumericHandle,User_Info);
+}
+
+/** \ingroup UmfPackSupport_Module
+ * \brief A sparse LU factorization and solver based on UmfPack
+ *
+ * This class allows to solve for A.X = B sparse linear problems via a LU factorization
+ * using the UmfPack library. The sparse matrix A must be squared and full rank.
+ * The vectors or matrices X and B can be either dense or sparse.
+ *
+ * \WARNING The input matrix A should be in a \b compressed and \b column-major form.
+ * Otherwise an expensive copy will be made. You can call the inexpensive makeCompressed() to get a compressed matrix.
+ * \tparam _MatrixType the type of the sparse matrix A, it must be a SparseMatrix<>
+ *
+ * \sa \ref TutorialSparseDirectSolvers
+ */
+template<typename _MatrixType>
+class UmfPackLU : internal::noncopyable
+{
+ public:
+ typedef _MatrixType MatrixType;
+ typedef typename MatrixType::Scalar Scalar;
+ typedef typename MatrixType::RealScalar RealScalar;
+ typedef typename MatrixType::Index Index;
+ typedef Matrix<Scalar,Dynamic,1> Vector;
+ typedef Matrix<int, 1, MatrixType::ColsAtCompileTime> IntRowVectorType;
+ typedef Matrix<int, MatrixType::RowsAtCompileTime, 1> IntColVectorType;
+ typedef SparseMatrix<Scalar> LUMatrixType;
+ typedef SparseMatrix<Scalar,ColMajor,int> UmfpackMatrixType;
+
+ public:
+
+ UmfPackLU() { init(); }
+
+ UmfPackLU(const MatrixType& matrix)
+ {
+ init();
+ compute(matrix);
+ }
+
+ ~UmfPackLU()
+ {
+ if(m_symbolic) umfpack_free_symbolic(&m_symbolic,Scalar());
+ if(m_numeric) umfpack_free_numeric(&m_numeric,Scalar());
+ }
+
+ inline Index rows() const { return m_copyMatrix.rows(); }
+ inline Index cols() const { return m_copyMatrix.cols(); }
+
+ /** \brief Reports whether previous computation was successful.
+ *
+ * \returns \c Success if computation was succesful,
+ * \c NumericalIssue if the matrix.appears to be negative.
+ */
+ ComputationInfo info() const
+ {
+ eigen_assert(m_isInitialized && "Decomposition is not initialized.");
+ return m_info;
+ }
+
+ inline const LUMatrixType& matrixL() const
+ {
+ if (m_extractedDataAreDirty) extractData();
+ return m_l;
+ }
+
+ inline const LUMatrixType& matrixU() const
+ {
+ if (m_extractedDataAreDirty) extractData();
+ return m_u;
+ }
+
+ inline const IntColVectorType& permutationP() const
+ {
+ if (m_extractedDataAreDirty) extractData();
+ return m_p;
+ }
+
+ inline const IntRowVectorType& permutationQ() const
+ {
+ if (m_extractedDataAreDirty) extractData();
+ return m_q;
+ }
+
+ /** Computes the sparse Cholesky decomposition of \a matrix
+ * Note that the matrix should be column-major, and in compressed format for best performance.
+ * \sa SparseMatrix::makeCompressed().
+ */
+ void compute(const MatrixType& matrix)
+ {
+ analyzePattern(matrix);
+ factorize(matrix);
+ }
+
+ /** \returns the solution x of \f$ A x = b \f$ using the current decomposition of A.
+ *
+ * \sa compute()
+ */
+ template<typename Rhs>
+ inline const internal::solve_retval<UmfPackLU, Rhs> solve(const MatrixBase<Rhs>& b) const
+ {
+ eigen_assert(m_isInitialized && "UmfPackLU is not initialized.");
+ eigen_assert(rows()==b.rows()
+ && "UmfPackLU::solve(): invalid number of rows of the right hand side matrix b");
+ return internal::solve_retval<UmfPackLU, Rhs>(*this, b.derived());
+ }
+
+ /** \returns the solution x of \f$ A x = b \f$ using the current decomposition of A.
+ *
+ * \sa compute()
+ */
+// template<typename Rhs>
+// inline const internal::sparse_solve_retval<UmfPAckLU, Rhs> solve(const SparseMatrixBase<Rhs>& b) const
+// {
+// eigen_assert(m_isInitialized && "UmfPAckLU is not initialized.");
+// eigen_assert(rows()==b.rows()
+// && "UmfPAckLU::solve(): invalid number of rows of the right hand side matrix b");
+// return internal::sparse_solve_retval<UmfPAckLU, Rhs>(*this, b.derived());
+// }
+
+ /** Performs a symbolic decomposition on the sparcity of \a matrix.
+ *
+ * This function is particularly useful when solving for several problems having the same structure.
+ *
+ * \sa factorize(), compute()
+ */
+ void analyzePattern(const MatrixType& matrix)
+ {
+ if(m_symbolic)
+ umfpack_free_symbolic(&m_symbolic,Scalar());
+ if(m_numeric)
+ umfpack_free_numeric(&m_numeric,Scalar());
+
+ grapInput(matrix);
+
+ int errorCode = 0;
+ errorCode = umfpack_symbolic(matrix.rows(), matrix.cols(), m_outerIndexPtr, m_innerIndexPtr, m_valuePtr,
+ &m_symbolic, 0, 0);
+
+ m_isInitialized = true;
+ m_info = errorCode ? InvalidInput : Success;
+ m_analysisIsOk = true;
+ m_factorizationIsOk = false;
+ }
+
+ /** Performs a numeric decomposition of \a matrix
+ *
+ * The given matrix must has the same sparcity than the matrix on which the pattern anylysis has been performed.
+ *
+ * \sa analyzePattern(), compute()
+ */
+ void factorize(const MatrixType& matrix)
+ {
+ eigen_assert(m_analysisIsOk && "UmfPackLU: you must first call analyzePattern()");
+ if(m_numeric)
+ umfpack_free_numeric(&m_numeric,Scalar());
+
+ grapInput(matrix);
+
+ int errorCode;
+ errorCode = umfpack_numeric(m_outerIndexPtr, m_innerIndexPtr, m_valuePtr,
+ m_symbolic, &m_numeric, 0, 0);
+
+ m_info = errorCode ? NumericalIssue : Success;
+ m_factorizationIsOk = true;
+ }
+
+ #ifndef EIGEN_PARSED_BY_DOXYGEN
+ /** \internal */
+ template<typename BDerived,typename XDerived>
+ bool _solve(const MatrixBase<BDerived> &b, MatrixBase<XDerived> &x) const;
+ #endif
+
+ Scalar determinant() const;
+
+ void extractData() const;
+
+ protected:
+
+
+ void init()
+ {
+ m_info = InvalidInput;
+ m_isInitialized = false;
+ m_numeric = 0;
+ m_symbolic = 0;
+ m_outerIndexPtr = 0;
+ m_innerIndexPtr = 0;
+ m_valuePtr = 0;
+ }
+
+ void grapInput(const MatrixType& mat)
+ {
+ m_copyMatrix.resize(mat.rows(), mat.cols());
+ if( ((MatrixType::Flags&RowMajorBit)==RowMajorBit) || sizeof(typename MatrixType::Index)!=sizeof(int) || !mat.isCompressed() )
+ {
+ // non supported input -> copy
+ m_copyMatrix = mat;
+ m_outerIndexPtr = m_copyMatrix.outerIndexPtr();
+ m_innerIndexPtr = m_copyMatrix.innerIndexPtr();
+ m_valuePtr = m_copyMatrix.valuePtr();
+ }
+ else
+ {
+ m_outerIndexPtr = mat.outerIndexPtr();
+ m_innerIndexPtr = mat.innerIndexPtr();
+ m_valuePtr = mat.valuePtr();
+ }
+ }
+
+ // cached data to reduce reallocation, etc.
+ mutable LUMatrixType m_l;
+ mutable LUMatrixType m_u;
+ mutable IntColVectorType m_p;
+ mutable IntRowVectorType m_q;
+
+ UmfpackMatrixType m_copyMatrix;
+ const Scalar* m_valuePtr;
+ const int* m_outerIndexPtr;
+ const int* m_innerIndexPtr;
+ void* m_numeric;
+ void* m_symbolic;
+
+ mutable ComputationInfo m_info;
+ bool m_isInitialized;
+ int m_factorizationIsOk;
+ int m_analysisIsOk;
+ mutable bool m_extractedDataAreDirty;
+
+ private:
+ UmfPackLU(UmfPackLU& ) { }
+};
+
+
+template<typename MatrixType>
+void UmfPackLU<MatrixType>::extractData() const
+{
+ if (m_extractedDataAreDirty)
+ {
+ // get size of the data
+ int lnz, unz, rows, cols, nz_udiag;
+ umfpack_get_lunz(&lnz, &unz, &rows, &cols, &nz_udiag, m_numeric, Scalar());
+
+ // allocate data
+ m_l.resize(rows,(std::min)(rows,cols));
+ m_l.resizeNonZeros(lnz);
+
+ m_u.resize((std::min)(rows,cols),cols);
+ m_u.resizeNonZeros(unz);
+
+ m_p.resize(rows);
+ m_q.resize(cols);
+
+ // extract
+ umfpack_get_numeric(m_l.outerIndexPtr(), m_l.innerIndexPtr(), m_l.valuePtr(),
+ m_u.outerIndexPtr(), m_u.innerIndexPtr(), m_u.valuePtr(),
+ m_p.data(), m_q.data(), 0, 0, 0, m_numeric);
+
+ m_extractedDataAreDirty = false;
+ }
+}
+
+template<typename MatrixType>
+typename UmfPackLU<MatrixType>::Scalar UmfPackLU<MatrixType>::determinant() const
+{
+ Scalar det;
+ umfpack_get_determinant(&det, 0, m_numeric, 0);
+ return det;
+}
+
+template<typename MatrixType>
+template<typename BDerived,typename XDerived>
+bool UmfPackLU<MatrixType>::_solve(const MatrixBase<BDerived> &b, MatrixBase<XDerived> &x) const
+{
+ const int rhsCols = b.cols();
+ eigen_assert((BDerived::Flags&RowMajorBit)==0 && "UmfPackLU backend does not support non col-major rhs yet");
+ eigen_assert((XDerived::Flags&RowMajorBit)==0 && "UmfPackLU backend does not support non col-major result yet");
+
+ int errorCode;
+ for (int j=0; j<rhsCols; ++j)
+ {
+ errorCode = umfpack_solve(UMFPACK_A,
+ m_outerIndexPtr, m_innerIndexPtr, m_valuePtr,
+ &x.col(j).coeffRef(0), &b.const_cast_derived().col(j).coeffRef(0), m_numeric, 0, 0);
+ if (errorCode!=0)
+ return false;
+ }
+
+ return true;
+}
+
+
+namespace internal {
+
+template<typename _MatrixType, typename Rhs>
+struct solve_retval<UmfPackLU<_MatrixType>, Rhs>
+ : solve_retval_base<UmfPackLU<_MatrixType>, Rhs>
+{
+ typedef UmfPackLU<_MatrixType> Dec;
+ EIGEN_MAKE_SOLVE_HELPERS(Dec,Rhs)
+
+ template<typename Dest> void evalTo(Dest& dst) const
+ {
+ dec()._solve(rhs(),dst);
+ }
+};
+
+template<typename _MatrixType, typename Rhs>
+struct sparse_solve_retval<UmfPackLU<_MatrixType>, Rhs>
+ : sparse_solve_retval_base<UmfPackLU<_MatrixType>, Rhs>
+{
+ typedef UmfPackLU<_MatrixType> Dec;
+ EIGEN_MAKE_SPARSE_SOLVE_HELPERS(Dec,Rhs)
+
+ template<typename Dest> void evalTo(Dest& dst) const
+ {
+ dec()._solve(rhs(),dst);
+ }
+};
+
+} // end namespace internal
+
+} // end namespace Eigen
+
+#endif // EIGEN_UMFPACKSUPPORT_H
diff --git a/Eigen/src/misc/CMakeLists.txt b/Eigen/src/misc/CMakeLists.txt
new file mode 100644
index 000000000..a58ffb745
--- /dev/null
+++ b/Eigen/src/misc/CMakeLists.txt
@@ -0,0 +1,6 @@
+FILE(GLOB Eigen_misc_SRCS "*.h")
+
+INSTALL(FILES
+ ${Eigen_misc_SRCS}
+ DESTINATION ${INCLUDE_INSTALL_DIR}/Eigen/src/misc COMPONENT Devel
+ )
diff --git a/Eigen/src/misc/Image.h b/Eigen/src/misc/Image.h
new file mode 100644
index 000000000..75c5f433a
--- /dev/null
+++ b/Eigen/src/misc/Image.h
@@ -0,0 +1,84 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra.
+//
+// Copyright (C) 2009 Benoit Jacob <jacob.benoit.1@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 EIGEN_MISC_IMAGE_H
+#define EIGEN_MISC_IMAGE_H
+
+namespace Eigen {
+
+namespace internal {
+
+/** \class image_retval_base
+ *
+ */
+template<typename DecompositionType>
+struct traits<image_retval_base<DecompositionType> >
+{
+ typedef typename DecompositionType::MatrixType MatrixType;
+ typedef Matrix<
+ typename MatrixType::Scalar,
+ MatrixType::RowsAtCompileTime, // the image is a subspace of the destination space, whose
+ // dimension is the number of rows of the original matrix
+ Dynamic, // we don't know at compile time the dimension of the image (the rank)
+ MatrixType::Options,
+ MatrixType::MaxRowsAtCompileTime, // the image matrix will consist of columns from the original matrix,
+ MatrixType::MaxColsAtCompileTime // so it has the same number of rows and at most as many columns.
+ > ReturnType;
+};
+
+template<typename _DecompositionType> struct image_retval_base
+ : public ReturnByValue<image_retval_base<_DecompositionType> >
+{
+ typedef _DecompositionType DecompositionType;
+ typedef typename DecompositionType::MatrixType MatrixType;
+ typedef ReturnByValue<image_retval_base> Base;
+ typedef typename Base::Index Index;
+
+ image_retval_base(const DecompositionType& dec, const MatrixType& originalMatrix)
+ : m_dec(dec), m_rank(dec.rank()),
+ m_cols(m_rank == 0 ? 1 : m_rank),
+ m_originalMatrix(originalMatrix)
+ {}
+
+ inline Index rows() const { return m_dec.rows(); }
+ inline Index cols() const { return m_cols; }
+ inline Index rank() const { return m_rank; }
+ inline const DecompositionType& dec() const { return m_dec; }
+ inline const MatrixType& originalMatrix() const { return m_originalMatrix; }
+
+ template<typename Dest> inline void evalTo(Dest& dst) const
+ {
+ static_cast<const image_retval<DecompositionType>*>(this)->evalTo(dst);
+ }
+
+ protected:
+ const DecompositionType& m_dec;
+ Index m_rank, m_cols;
+ const MatrixType& m_originalMatrix;
+};
+
+} // end namespace internal
+
+#define EIGEN_MAKE_IMAGE_HELPERS(DecompositionType) \
+ typedef typename DecompositionType::MatrixType MatrixType; \
+ typedef typename MatrixType::Scalar Scalar; \
+ typedef typename MatrixType::RealScalar RealScalar; \
+ typedef typename MatrixType::Index Index; \
+ typedef Eigen::internal::image_retval_base<DecompositionType> Base; \
+ using Base::dec; \
+ using Base::originalMatrix; \
+ using Base::rank; \
+ using Base::rows; \
+ using Base::cols; \
+ image_retval(const DecompositionType& dec, const MatrixType& originalMatrix) \
+ : Base(dec, originalMatrix) {}
+
+} // end namespace Eigen
+
+#endif // EIGEN_MISC_IMAGE_H
diff --git a/Eigen/src/misc/Kernel.h b/Eigen/src/misc/Kernel.h
new file mode 100644
index 000000000..b9e1518fd
--- /dev/null
+++ b/Eigen/src/misc/Kernel.h
@@ -0,0 +1,81 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra.
+//
+// Copyright (C) 2009 Benoit Jacob <jacob.benoit.1@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 EIGEN_MISC_KERNEL_H
+#define EIGEN_MISC_KERNEL_H
+
+namespace Eigen {
+
+namespace internal {
+
+/** \class kernel_retval_base
+ *
+ */
+template<typename DecompositionType>
+struct traits<kernel_retval_base<DecompositionType> >
+{
+ typedef typename DecompositionType::MatrixType MatrixType;
+ typedef Matrix<
+ typename MatrixType::Scalar,
+ MatrixType::ColsAtCompileTime, // the number of rows in the "kernel matrix"
+ // is the number of cols of the original matrix
+ // so that the product "matrix * kernel = zero" makes sense
+ Dynamic, // we don't know at compile-time the dimension of the kernel
+ MatrixType::Options,
+ MatrixType::MaxColsAtCompileTime, // see explanation for 2nd template parameter
+ MatrixType::MaxColsAtCompileTime // the kernel is a subspace of the domain space,
+ // whose dimension is the number of columns of the original matrix
+ > ReturnType;
+};
+
+template<typename _DecompositionType> struct kernel_retval_base
+ : public ReturnByValue<kernel_retval_base<_DecompositionType> >
+{
+ typedef _DecompositionType DecompositionType;
+ typedef ReturnByValue<kernel_retval_base> Base;
+ typedef typename Base::Index Index;
+
+ kernel_retval_base(const DecompositionType& dec)
+ : m_dec(dec),
+ m_rank(dec.rank()),
+ m_cols(m_rank==dec.cols() ? 1 : dec.cols() - m_rank)
+ {}
+
+ inline Index rows() const { return m_dec.cols(); }
+ inline Index cols() const { return m_cols; }
+ inline Index rank() const { return m_rank; }
+ inline const DecompositionType& dec() const { return m_dec; }
+
+ template<typename Dest> inline void evalTo(Dest& dst) const
+ {
+ static_cast<const kernel_retval<DecompositionType>*>(this)->evalTo(dst);
+ }
+
+ protected:
+ const DecompositionType& m_dec;
+ Index m_rank, m_cols;
+};
+
+} // end namespace internal
+
+#define EIGEN_MAKE_KERNEL_HELPERS(DecompositionType) \
+ typedef typename DecompositionType::MatrixType MatrixType; \
+ typedef typename MatrixType::Scalar Scalar; \
+ typedef typename MatrixType::RealScalar RealScalar; \
+ typedef typename MatrixType::Index Index; \
+ typedef Eigen::internal::kernel_retval_base<DecompositionType> Base; \
+ using Base::dec; \
+ using Base::rank; \
+ using Base::rows; \
+ using Base::cols; \
+ kernel_retval(const DecompositionType& dec) : Base(dec) {}
+
+} // end namespace Eigen
+
+#endif // EIGEN_MISC_KERNEL_H
diff --git a/Eigen/src/misc/Solve.h b/Eigen/src/misc/Solve.h
new file mode 100644
index 000000000..7f70d60af
--- /dev/null
+++ b/Eigen/src/misc/Solve.h
@@ -0,0 +1,76 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra.
+//
+// Copyright (C) 2009 Benoit Jacob <jacob.benoit.1@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 EIGEN_MISC_SOLVE_H
+#define EIGEN_MISC_SOLVE_H
+
+namespace Eigen {
+
+namespace internal {
+
+/** \class solve_retval_base
+ *
+ */
+template<typename DecompositionType, typename Rhs>
+struct traits<solve_retval_base<DecompositionType, Rhs> >
+{
+ typedef typename DecompositionType::MatrixType MatrixType;
+ typedef Matrix<typename Rhs::Scalar,
+ MatrixType::ColsAtCompileTime,
+ Rhs::ColsAtCompileTime,
+ Rhs::PlainObject::Options,
+ MatrixType::MaxColsAtCompileTime,
+ Rhs::MaxColsAtCompileTime> ReturnType;
+};
+
+template<typename _DecompositionType, typename Rhs> struct solve_retval_base
+ : public ReturnByValue<solve_retval_base<_DecompositionType, Rhs> >
+{
+ typedef typename remove_all<typename Rhs::Nested>::type RhsNestedCleaned;
+ typedef _DecompositionType DecompositionType;
+ typedef ReturnByValue<solve_retval_base> 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<typename Dest> inline void evalTo(Dest& dst) const
+ {
+ static_cast<const solve_retval<DecompositionType,Rhs>*>(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<DecompositionType,Rhs> 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/Eigen/src/misc/SparseSolve.h b/Eigen/src/misc/SparseSolve.h
new file mode 100644
index 000000000..272c4a479
--- /dev/null
+++ b/Eigen/src/misc/SparseSolve.h
@@ -0,0 +1,111 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra.
+//
+// Copyright (C) 2010 Gael Guennebaud <gael.guennebaud@inria.fr>
+//
+// This Source Code Form is subject to the terms of the Mozilla
+// Public License v. 2.0. If 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<typename _DecompositionType, typename Rhs> struct sparse_solve_retval_base;
+template<typename _DecompositionType, typename Rhs> struct sparse_solve_retval;
+
+template<typename DecompositionType, typename Rhs>
+struct traits<sparse_solve_retval_base<DecompositionType, Rhs> >
+{
+ typedef typename DecompositionType::MatrixType MatrixType;
+ typedef SparseMatrix<typename Rhs::Scalar, Rhs::Options, typename Rhs::Index> ReturnType;
+};
+
+template<typename _DecompositionType, typename Rhs> struct sparse_solve_retval_base
+ : public ReturnByValue<sparse_solve_retval_base<_DecompositionType, Rhs> >
+{
+ typedef typename remove_all<typename Rhs::Nested>::type RhsNestedCleaned;
+ typedef _DecompositionType DecompositionType;
+ typedef ReturnByValue<sparse_solve_retval_base> 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<typename Dest> inline void evalTo(Dest& dst) const
+ {
+ static_cast<const sparse_solve_retval<DecompositionType,Rhs>*>(this)->evalTo(dst);
+ }
+
+ protected:
+ const DecompositionType& m_dec;
+ typename Rhs::Nested m_rhs;
+};
+
+#define EIGEN_MAKE_SPARSE_SOLVE_HELPERS(DecompositionType,Rhs) \
+ typedef typename DecompositionType::MatrixType MatrixType; \
+ typedef typename MatrixType::Scalar Scalar; \
+ typedef typename MatrixType::RealScalar RealScalar; \
+ typedef typename MatrixType::Index Index; \
+ typedef Eigen::internal::sparse_solve_retval_base<DecompositionType,Rhs> 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<typename DecompositionType, typename Rhs, typename Guess> struct solve_retval_with_guess;
+
+template<typename DecompositionType, typename Rhs, typename Guess>
+struct traits<solve_retval_with_guess<DecompositionType, Rhs, Guess> >
+{
+ typedef typename DecompositionType::MatrixType MatrixType;
+ typedef Matrix<typename Rhs::Scalar,
+ MatrixType::ColsAtCompileTime,
+ Rhs::ColsAtCompileTime,
+ Rhs::PlainObject::Options,
+ MatrixType::MaxColsAtCompileTime,
+ Rhs::MaxColsAtCompileTime> ReturnType;
+};
+
+template<typename DecompositionType, typename Rhs, typename Guess> struct solve_retval_with_guess
+ : public ReturnByValue<solve_retval_with_guess<DecompositionType, Rhs, Guess> >
+{
+ 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<typename Dest> 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/Eigen/src/misc/blas.h b/Eigen/src/misc/blas.h
new file mode 100644
index 000000000..6fce99ed5
--- /dev/null
+++ b/Eigen/src/misc/blas.h
@@ -0,0 +1,658 @@
+#ifndef BLAS_H
+#define BLAS_H
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+#define BLASFUNC(FUNC) FUNC##_
+
+#ifdef __WIN64__
+typedef long long BLASLONG;
+typedef unsigned long long BLASULONG;
+#else
+typedef long BLASLONG;
+typedef unsigned long BLASULONG;
+#endif
+
+int BLASFUNC(xerbla)(const char *, int *info, int);
+
+float BLASFUNC(sdot) (int *, float *, int *, float *, int *);
+float BLASFUNC(sdsdot)(int *, float *, float *, int *, float *, int *);
+
+double BLASFUNC(dsdot) (int *, float *, int *, float *, int *);
+double BLASFUNC(ddot) (int *, double *, int *, double *, int *);
+double BLASFUNC(qdot) (int *, double *, int *, double *, int *);
+
+int BLASFUNC(cdotuw) (int *, float *, int *, float *, int *, float*);
+int BLASFUNC(cdotcw) (int *, float *, int *, float *, int *, float*);
+int BLASFUNC(zdotuw) (int *, double *, int *, double *, int *, double*);
+int BLASFUNC(zdotcw) (int *, double *, int *, double *, int *, double*);
+
+int BLASFUNC(saxpy) (int *, float *, float *, int *, float *, int *);
+int BLASFUNC(daxpy) (int *, double *, double *, int *, double *, int *);
+int BLASFUNC(qaxpy) (int *, double *, double *, int *, double *, int *);
+int BLASFUNC(caxpy) (int *, float *, float *, int *, float *, int *);
+int BLASFUNC(zaxpy) (int *, double *, double *, int *, double *, int *);
+int BLASFUNC(xaxpy) (int *, double *, double *, int *, double *, int *);
+int BLASFUNC(caxpyc)(int *, float *, float *, int *, float *, int *);
+int BLASFUNC(zaxpyc)(int *, double *, double *, int *, double *, int *);
+int BLASFUNC(xaxpyc)(int *, double *, double *, int *, double *, int *);
+
+int BLASFUNC(scopy) (int *, float *, int *, float *, int *);
+int BLASFUNC(dcopy) (int *, double *, int *, double *, int *);
+int BLASFUNC(qcopy) (int *, double *, int *, double *, int *);
+int BLASFUNC(ccopy) (int *, float *, int *, float *, int *);
+int BLASFUNC(zcopy) (int *, double *, int *, double *, int *);
+int BLASFUNC(xcopy) (int *, double *, int *, double *, int *);
+
+int BLASFUNC(sswap) (int *, float *, int *, float *, int *);
+int BLASFUNC(dswap) (int *, double *, int *, double *, int *);
+int BLASFUNC(qswap) (int *, double *, int *, double *, int *);
+int BLASFUNC(cswap) (int *, float *, int *, float *, int *);
+int BLASFUNC(zswap) (int *, double *, int *, double *, int *);
+int BLASFUNC(xswap) (int *, double *, int *, double *, int *);
+
+float BLASFUNC(sasum) (int *, float *, int *);
+float BLASFUNC(scasum)(int *, float *, int *);
+double BLASFUNC(dasum) (int *, double *, int *);
+double BLASFUNC(qasum) (int *, double *, int *);
+double BLASFUNC(dzasum)(int *, double *, int *);
+double BLASFUNC(qxasum)(int *, double *, int *);
+
+int BLASFUNC(isamax)(int *, float *, int *);
+int BLASFUNC(idamax)(int *, double *, int *);
+int BLASFUNC(iqamax)(int *, double *, int *);
+int BLASFUNC(icamax)(int *, float *, int *);
+int BLASFUNC(izamax)(int *, double *, int *);
+int BLASFUNC(ixamax)(int *, double *, int *);
+
+int BLASFUNC(ismax) (int *, float *, int *);
+int BLASFUNC(idmax) (int *, double *, int *);
+int BLASFUNC(iqmax) (int *, double *, int *);
+int BLASFUNC(icmax) (int *, float *, int *);
+int BLASFUNC(izmax) (int *, double *, int *);
+int BLASFUNC(ixmax) (int *, double *, int *);
+
+int BLASFUNC(isamin)(int *, float *, int *);
+int BLASFUNC(idamin)(int *, double *, int *);
+int BLASFUNC(iqamin)(int *, double *, int *);
+int BLASFUNC(icamin)(int *, float *, int *);
+int BLASFUNC(izamin)(int *, double *, int *);
+int BLASFUNC(ixamin)(int *, double *, int *);
+
+int BLASFUNC(ismin)(int *, float *, int *);
+int BLASFUNC(idmin)(int *, double *, int *);
+int BLASFUNC(iqmin)(int *, double *, int *);
+int BLASFUNC(icmin)(int *, float *, int *);
+int BLASFUNC(izmin)(int *, double *, int *);
+int BLASFUNC(ixmin)(int *, double *, int *);
+
+float BLASFUNC(samax) (int *, float *, int *);
+double BLASFUNC(damax) (int *, double *, int *);
+double BLASFUNC(qamax) (int *, double *, int *);
+float BLASFUNC(scamax)(int *, float *, int *);
+double BLASFUNC(dzamax)(int *, double *, int *);
+double BLASFUNC(qxamax)(int *, double *, int *);
+
+float BLASFUNC(samin) (int *, float *, int *);
+double BLASFUNC(damin) (int *, double *, int *);
+double BLASFUNC(qamin) (int *, double *, int *);
+float BLASFUNC(scamin)(int *, float *, int *);
+double BLASFUNC(dzamin)(int *, double *, int *);
+double BLASFUNC(qxamin)(int *, double *, int *);
+
+float BLASFUNC(smax) (int *, float *, int *);
+double BLASFUNC(dmax) (int *, double *, int *);
+double BLASFUNC(qmax) (int *, double *, int *);
+float BLASFUNC(scmax) (int *, float *, int *);
+double BLASFUNC(dzmax) (int *, double *, int *);
+double BLASFUNC(qxmax) (int *, double *, int *);
+
+float BLASFUNC(smin) (int *, float *, int *);
+double BLASFUNC(dmin) (int *, double *, int *);
+double BLASFUNC(qmin) (int *, double *, int *);
+float BLASFUNC(scmin) (int *, float *, int *);
+double BLASFUNC(dzmin) (int *, double *, int *);
+double BLASFUNC(qxmin) (int *, double *, int *);
+
+int BLASFUNC(sscal) (int *, float *, float *, int *);
+int BLASFUNC(dscal) (int *, double *, double *, int *);
+int BLASFUNC(qscal) (int *, double *, double *, int *);
+int BLASFUNC(cscal) (int *, float *, float *, int *);
+int BLASFUNC(zscal) (int *, double *, double *, int *);
+int BLASFUNC(xscal) (int *, double *, double *, int *);
+int BLASFUNC(csscal)(int *, float *, float *, int *);
+int BLASFUNC(zdscal)(int *, double *, double *, int *);
+int BLASFUNC(xqscal)(int *, double *, double *, int *);
+
+float BLASFUNC(snrm2) (int *, float *, int *);
+float BLASFUNC(scnrm2)(int *, float *, int *);
+
+double BLASFUNC(dnrm2) (int *, double *, int *);
+double BLASFUNC(qnrm2) (int *, double *, int *);
+double BLASFUNC(dznrm2)(int *, double *, int *);
+double BLASFUNC(qxnrm2)(int *, double *, int *);
+
+int BLASFUNC(srot) (int *, float *, int *, float *, int *, float *, float *);
+int BLASFUNC(drot) (int *, double *, int *, double *, int *, double *, double *);
+int BLASFUNC(qrot) (int *, double *, int *, double *, int *, double *, double *);
+int BLASFUNC(csrot) (int *, float *, int *, float *, int *, float *, float *);
+int BLASFUNC(zdrot) (int *, double *, int *, double *, int *, double *, double *);
+int BLASFUNC(xqrot) (int *, double *, int *, double *, int *, double *, double *);
+
+int BLASFUNC(srotg) (float *, float *, float *, float *);
+int BLASFUNC(drotg) (double *, double *, double *, double *);
+int BLASFUNC(qrotg) (double *, double *, double *, double *);
+int BLASFUNC(crotg) (float *, float *, float *, float *);
+int BLASFUNC(zrotg) (double *, double *, double *, double *);
+int BLASFUNC(xrotg) (double *, double *, double *, double *);
+
+int BLASFUNC(srotmg)(float *, float *, float *, float *, float *);
+int BLASFUNC(drotmg)(double *, double *, double *, double *, double *);
+
+int BLASFUNC(srotm) (int *, float *, int *, float *, int *, float *);
+int BLASFUNC(drotm) (int *, double *, int *, double *, int *, double *);
+int BLASFUNC(qrotm) (int *, double *, int *, double *, int *, double *);
+
+/* Level 2 routines */
+
+int BLASFUNC(sger)(int *, int *, float *, float *, int *,
+ float *, int *, float *, int *);
+int BLASFUNC(dger)(int *, int *, double *, double *, int *,
+ double *, int *, double *, int *);
+int BLASFUNC(qger)(int *, int *, double *, double *, int *,
+ double *, int *, double *, int *);
+int BLASFUNC(cgeru)(int *, int *, float *, float *, int *,
+ float *, int *, float *, int *);
+int BLASFUNC(cgerc)(int *, int *, float *, float *, int *,
+ float *, int *, float *, int *);
+int BLASFUNC(zgeru)(int *, int *, double *, double *, int *,
+ double *, int *, double *, int *);
+int BLASFUNC(zgerc)(int *, int *, double *, double *, int *,
+ double *, int *, double *, int *);
+int BLASFUNC(xgeru)(int *, int *, double *, double *, int *,
+ double *, int *, double *, int *);
+int BLASFUNC(xgerc)(int *, int *, double *, double *, int *,
+ double *, int *, double *, int *);
+
+int BLASFUNC(sgemv)(char *, int *, int *, float *, float *, int *,
+ float *, int *, float *, float *, int *);
+int BLASFUNC(dgemv)(char *, int *, int *, double *, double *, int *,
+ double *, int *, double *, double *, int *);
+int BLASFUNC(qgemv)(char *, int *, int *, double *, double *, int *,
+ double *, int *, double *, double *, int *);
+int BLASFUNC(cgemv)(char *, int *, int *, float *, float *, int *,
+ float *, int *, float *, float *, int *);
+int BLASFUNC(zgemv)(char *, int *, int *, double *, double *, int *,
+ double *, int *, double *, double *, int *);
+int BLASFUNC(xgemv)(char *, int *, int *, double *, double *, int *,
+ double *, int *, double *, double *, int *);
+
+int BLASFUNC(strsv) (char *, char *, char *, int *, float *, int *,
+ float *, int *);
+int BLASFUNC(dtrsv) (char *, char *, char *, int *, double *, int *,
+ double *, int *);
+int BLASFUNC(qtrsv) (char *, char *, char *, int *, double *, int *,
+ double *, int *);
+int BLASFUNC(ctrsv) (char *, char *, char *, int *, float *, int *,
+ float *, int *);
+int BLASFUNC(ztrsv) (char *, char *, char *, int *, double *, int *,
+ double *, int *);
+int BLASFUNC(xtrsv) (char *, char *, char *, int *, double *, int *,
+ double *, int *);
+
+int BLASFUNC(stpsv) (char *, char *, char *, int *, float *, float *, int *);
+int BLASFUNC(dtpsv) (char *, char *, char *, int *, double *, double *, int *);
+int BLASFUNC(qtpsv) (char *, char *, char *, int *, double *, double *, int *);
+int BLASFUNC(ctpsv) (char *, char *, char *, int *, float *, float *, int *);
+int BLASFUNC(ztpsv) (char *, char *, char *, int *, double *, double *, int *);
+int BLASFUNC(xtpsv) (char *, char *, char *, int *, double *, double *, int *);
+
+int BLASFUNC(strmv) (char *, char *, char *, int *, float *, int *,
+ float *, int *);
+int BLASFUNC(dtrmv) (char *, char *, char *, int *, double *, int *,
+ double *, int *);
+int BLASFUNC(qtrmv) (char *, char *, char *, int *, double *, int *,
+ double *, int *);
+int BLASFUNC(ctrmv) (char *, char *, char *, int *, float *, int *,
+ float *, int *);
+int BLASFUNC(ztrmv) (char *, char *, char *, int *, double *, int *,
+ double *, int *);
+int BLASFUNC(xtrmv) (char *, char *, char *, int *, double *, int *,
+ double *, int *);
+
+int BLASFUNC(stpmv) (char *, char *, char *, int *, float *, float *, int *);
+int BLASFUNC(dtpmv) (char *, char *, char *, int *, double *, double *, int *);
+int BLASFUNC(qtpmv) (char *, char *, char *, int *, double *, double *, int *);
+int BLASFUNC(ctpmv) (char *, char *, char *, int *, float *, float *, int *);
+int BLASFUNC(ztpmv) (char *, char *, char *, int *, double *, double *, int *);
+int BLASFUNC(xtpmv) (char *, char *, char *, int *, double *, double *, int *);
+
+int BLASFUNC(stbmv) (char *, char *, char *, int *, int *, float *, int *, float *, int *);
+int BLASFUNC(dtbmv) (char *, char *, char *, int *, int *, double *, int *, double *, int *);
+int BLASFUNC(qtbmv) (char *, char *, char *, int *, int *, double *, int *, double *, int *);
+int BLASFUNC(ctbmv) (char *, char *, char *, int *, int *, float *, int *, float *, int *);
+int BLASFUNC(ztbmv) (char *, char *, char *, int *, int *, double *, int *, double *, int *);
+int BLASFUNC(xtbmv) (char *, char *, char *, int *, int *, double *, int *, double *, int *);
+
+int BLASFUNC(stbsv) (char *, char *, char *, int *, int *, float *, int *, float *, int *);
+int BLASFUNC(dtbsv) (char *, char *, char *, int *, int *, double *, int *, double *, int *);
+int BLASFUNC(qtbsv) (char *, char *, char *, int *, int *, double *, int *, double *, int *);
+int BLASFUNC(ctbsv) (char *, char *, char *, int *, int *, float *, int *, float *, int *);
+int BLASFUNC(ztbsv) (char *, char *, char *, int *, int *, double *, int *, double *, int *);
+int BLASFUNC(xtbsv) (char *, char *, char *, int *, int *, double *, int *, double *, int *);
+
+int BLASFUNC(ssymv) (char *, int *, float *, float *, int *,
+ float *, int *, float *, float *, int *);
+int BLASFUNC(dsymv) (char *, int *, double *, double *, int *,
+ double *, int *, double *, double *, int *);
+int BLASFUNC(qsymv) (char *, int *, double *, double *, int *,
+ double *, int *, double *, double *, int *);
+int BLASFUNC(csymv) (char *, int *, float *, float *, int *,
+ float *, int *, float *, float *, int *);
+int BLASFUNC(zsymv) (char *, int *, double *, double *, int *,
+ double *, int *, double *, double *, int *);
+int BLASFUNC(xsymv) (char *, int *, double *, double *, int *,
+ double *, int *, double *, double *, int *);
+
+int BLASFUNC(sspmv) (char *, int *, float *, float *,
+ float *, int *, float *, float *, int *);
+int BLASFUNC(dspmv) (char *, int *, double *, double *,
+ double *, int *, double *, double *, int *);
+int BLASFUNC(qspmv) (char *, int *, double *, double *,
+ double *, int *, double *, double *, int *);
+int BLASFUNC(cspmv) (char *, int *, float *, float *,
+ float *, int *, float *, float *, int *);
+int BLASFUNC(zspmv) (char *, int *, double *, double *,
+ double *, int *, double *, double *, int *);
+int BLASFUNC(xspmv) (char *, int *, double *, double *,
+ double *, int *, double *, double *, int *);
+
+int BLASFUNC(ssyr) (char *, int *, float *, float *, int *,
+ float *, int *);
+int BLASFUNC(dsyr) (char *, int *, double *, double *, int *,
+ double *, int *);
+int BLASFUNC(qsyr) (char *, int *, double *, double *, int *,
+ double *, int *);
+int BLASFUNC(csyr) (char *, int *, float *, float *, int *,
+ float *, int *);
+int BLASFUNC(zsyr) (char *, int *, double *, double *, int *,
+ double *, int *);
+int BLASFUNC(xsyr) (char *, int *, double *, double *, int *,
+ double *, int *);
+
+int BLASFUNC(ssyr2) (char *, int *, float *,
+ float *, int *, float *, int *, float *, int *);
+int BLASFUNC(dsyr2) (char *, int *, double *,
+ double *, int *, double *, int *, double *, int *);
+int BLASFUNC(qsyr2) (char *, int *, double *,
+ double *, int *, double *, int *, double *, int *);
+int BLASFUNC(csyr2) (char *, int *, float *,
+ float *, int *, float *, int *, float *, int *);
+int BLASFUNC(zsyr2) (char *, int *, double *,
+ double *, int *, double *, int *, double *, int *);
+int BLASFUNC(xsyr2) (char *, int *, double *,
+ double *, int *, double *, int *, double *, int *);
+
+int BLASFUNC(sspr) (char *, int *, float *, float *, int *,
+ float *);
+int BLASFUNC(dspr) (char *, int *, double *, double *, int *,
+ double *);
+int BLASFUNC(qspr) (char *, int *, double *, double *, int *,
+ double *);
+int BLASFUNC(cspr) (char *, int *, float *, float *, int *,
+ float *);
+int BLASFUNC(zspr) (char *, int *, double *, double *, int *,
+ double *);
+int BLASFUNC(xspr) (char *, int *, double *, double *, int *,
+ double *);
+
+int BLASFUNC(sspr2) (char *, int *, float *,
+ float *, int *, float *, int *, float *);
+int BLASFUNC(dspr2) (char *, int *, double *,
+ double *, int *, double *, int *, double *);
+int BLASFUNC(qspr2) (char *, int *, double *,
+ double *, int *, double *, int *, double *);
+int BLASFUNC(cspr2) (char *, int *, float *,
+ float *, int *, float *, int *, float *);
+int BLASFUNC(zspr2) (char *, int *, double *,
+ double *, int *, double *, int *, double *);
+int BLASFUNC(xspr2) (char *, int *, double *,
+ double *, int *, double *, int *, double *);
+
+int BLASFUNC(cher) (char *, int *, float *, float *, int *,
+ float *, int *);
+int BLASFUNC(zher) (char *, int *, double *, double *, int *,
+ double *, int *);
+int BLASFUNC(xher) (char *, int *, double *, double *, int *,
+ double *, int *);
+
+int BLASFUNC(chpr) (char *, int *, float *, float *, int *, float *);
+int BLASFUNC(zhpr) (char *, int *, double *, double *, int *, double *);
+int BLASFUNC(xhpr) (char *, int *, double *, double *, int *, double *);
+
+int BLASFUNC(cher2) (char *, int *, float *,
+ float *, int *, float *, int *, float *, int *);
+int BLASFUNC(zher2) (char *, int *, double *,
+ double *, int *, double *, int *, double *, int *);
+int BLASFUNC(xher2) (char *, int *, double *,
+ double *, int *, double *, int *, double *, int *);
+
+int BLASFUNC(chpr2) (char *, int *, float *,
+ float *, int *, float *, int *, float *);
+int BLASFUNC(zhpr2) (char *, int *, double *,
+ double *, int *, double *, int *, double *);
+int BLASFUNC(xhpr2) (char *, int *, double *,
+ double *, int *, double *, int *, double *);
+
+int BLASFUNC(chemv) (char *, int *, float *, float *, int *,
+ float *, int *, float *, float *, int *);
+int BLASFUNC(zhemv) (char *, int *, double *, double *, int *,
+ double *, int *, double *, double *, int *);
+int BLASFUNC(xhemv) (char *, int *, double *, double *, int *,
+ double *, int *, double *, double *, int *);
+
+int BLASFUNC(chpmv) (char *, int *, float *, float *,
+ float *, int *, float *, float *, int *);
+int BLASFUNC(zhpmv) (char *, int *, double *, double *,
+ double *, int *, double *, double *, int *);
+int BLASFUNC(xhpmv) (char *, int *, double *, double *,
+ double *, int *, double *, double *, int *);
+
+int BLASFUNC(snorm)(char *, int *, int *, float *, int *);
+int BLASFUNC(dnorm)(char *, int *, int *, double *, int *);
+int BLASFUNC(cnorm)(char *, int *, int *, float *, int *);
+int BLASFUNC(znorm)(char *, int *, int *, double *, int *);
+
+int BLASFUNC(sgbmv)(char *, int *, int *, int *, int *, float *, float *, int *,
+ float *, int *, float *, float *, int *);
+int BLASFUNC(dgbmv)(char *, int *, int *, int *, int *, double *, double *, int *,
+ double *, int *, double *, double *, int *);
+int BLASFUNC(qgbmv)(char *, int *, int *, int *, int *, double *, double *, int *,
+ double *, int *, double *, double *, int *);
+int BLASFUNC(cgbmv)(char *, int *, int *, int *, int *, float *, float *, int *,
+ float *, int *, float *, float *, int *);
+int BLASFUNC(zgbmv)(char *, int *, int *, int *, int *, double *, double *, int *,
+ double *, int *, double *, double *, int *);
+int BLASFUNC(xgbmv)(char *, int *, int *, int *, int *, double *, double *, int *,
+ double *, int *, double *, double *, int *);
+
+int BLASFUNC(ssbmv)(char *, int *, int *, float *, float *, int *,
+ float *, int *, float *, float *, int *);
+int BLASFUNC(dsbmv)(char *, int *, int *, double *, double *, int *,
+ double *, int *, double *, double *, int *);
+int BLASFUNC(qsbmv)(char *, int *, int *, double *, double *, int *,
+ double *, int *, double *, double *, int *);
+int BLASFUNC(csbmv)(char *, int *, int *, float *, float *, int *,
+ float *, int *, float *, float *, int *);
+int BLASFUNC(zsbmv)(char *, int *, int *, double *, double *, int *,
+ double *, int *, double *, double *, int *);
+int BLASFUNC(xsbmv)(char *, int *, int *, double *, double *, int *,
+ double *, int *, double *, double *, int *);
+
+int BLASFUNC(chbmv)(char *, int *, int *, float *, float *, int *,
+ float *, int *, float *, float *, int *);
+int BLASFUNC(zhbmv)(char *, int *, int *, double *, double *, int *,
+ double *, int *, double *, double *, int *);
+int BLASFUNC(xhbmv)(char *, int *, int *, double *, double *, int *,
+ double *, int *, double *, double *, int *);
+
+/* Level 3 routines */
+
+int BLASFUNC(sgemm)(char *, char *, int *, int *, int *, float *,
+ float *, int *, float *, int *, float *, float *, int *);
+int BLASFUNC(dgemm)(char *, char *, int *, int *, int *, double *,
+ double *, int *, double *, int *, double *, double *, int *);
+int BLASFUNC(qgemm)(char *, char *, int *, int *, int *, double *,
+ double *, int *, double *, int *, double *, double *, int *);
+int BLASFUNC(cgemm)(char *, char *, int *, int *, int *, float *,
+ float *, int *, float *, int *, float *, float *, int *);
+int BLASFUNC(zgemm)(char *, char *, int *, int *, int *, double *,
+ double *, int *, double *, int *, double *, double *, int *);
+int BLASFUNC(xgemm)(char *, char *, int *, int *, int *, double *,
+ double *, int *, double *, int *, double *, double *, int *);
+
+int BLASFUNC(cgemm3m)(char *, char *, int *, int *, int *, float *,
+ float *, int *, float *, int *, float *, float *, int *);
+int BLASFUNC(zgemm3m)(char *, char *, int *, int *, int *, double *,
+ double *, int *, double *, int *, double *, double *, int *);
+int BLASFUNC(xgemm3m)(char *, char *, int *, int *, int *, double *,
+ double *, int *, double *, int *, double *, double *, int *);
+
+int BLASFUNC(sge2mm)(char *, char *, char *, int *, int *,
+ float *, float *, int *, float *, int *,
+ float *, float *, int *);
+int BLASFUNC(dge2mm)(char *, char *, char *, int *, int *,
+ double *, double *, int *, double *, int *,
+ double *, double *, int *);
+int BLASFUNC(cge2mm)(char *, char *, char *, int *, int *,
+ float *, float *, int *, float *, int *,
+ float *, float *, int *);
+int BLASFUNC(zge2mm)(char *, char *, char *, int *, int *,
+ double *, double *, int *, double *, int *,
+ double *, double *, int *);
+
+int BLASFUNC(strsm)(char *, char *, char *, char *, int *, int *,
+ float *, float *, int *, float *, int *);
+int BLASFUNC(dtrsm)(char *, char *, char *, char *, int *, int *,
+ double *, double *, int *, double *, int *);
+int BLASFUNC(qtrsm)(char *, char *, char *, char *, int *, int *,
+ double *, double *, int *, double *, int *);
+int BLASFUNC(ctrsm)(char *, char *, char *, char *, int *, int *,
+ float *, float *, int *, float *, int *);
+int BLASFUNC(ztrsm)(char *, char *, char *, char *, int *, int *,
+ double *, double *, int *, double *, int *);
+int BLASFUNC(xtrsm)(char *, char *, char *, char *, int *, int *,
+ double *, double *, int *, double *, int *);
+
+int BLASFUNC(strmm)(char *, char *, char *, char *, int *, int *,
+ float *, float *, int *, float *, int *);
+int BLASFUNC(dtrmm)(char *, char *, char *, char *, int *, int *,
+ double *, double *, int *, double *, int *);
+int BLASFUNC(qtrmm)(char *, char *, char *, char *, int *, int *,
+ double *, double *, int *, double *, int *);
+int BLASFUNC(ctrmm)(char *, char *, char *, char *, int *, int *,
+ float *, float *, int *, float *, int *);
+int BLASFUNC(ztrmm)(char *, char *, char *, char *, int *, int *,
+ double *, double *, int *, double *, int *);
+int BLASFUNC(xtrmm)(char *, char *, char *, char *, int *, int *,
+ double *, double *, int *, double *, int *);
+
+int BLASFUNC(ssymm)(char *, char *, int *, int *, float *, float *, int *,
+ float *, int *, float *, float *, int *);
+int BLASFUNC(dsymm)(char *, char *, int *, int *, double *, double *, int *,
+ double *, int *, double *, double *, int *);
+int BLASFUNC(qsymm)(char *, char *, int *, int *, double *, double *, int *,
+ double *, int *, double *, double *, int *);
+int BLASFUNC(csymm)(char *, char *, int *, int *, float *, float *, int *,
+ float *, int *, float *, float *, int *);
+int BLASFUNC(zsymm)(char *, char *, int *, int *, double *, double *, int *,
+ double *, int *, double *, double *, int *);
+int BLASFUNC(xsymm)(char *, char *, int *, int *, double *, double *, int *,
+ double *, int *, double *, double *, int *);
+
+int BLASFUNC(csymm3m)(char *, char *, int *, int *, float *, float *, int *,
+ float *, int *, float *, float *, int *);
+int BLASFUNC(zsymm3m)(char *, char *, int *, int *, double *, double *, int *,
+ double *, int *, double *, double *, int *);
+int BLASFUNC(xsymm3m)(char *, char *, int *, int *, double *, double *, int *,
+ double *, int *, double *, double *, int *);
+
+int BLASFUNC(ssyrk)(char *, char *, int *, int *, float *, float *, int *,
+ float *, float *, int *);
+int BLASFUNC(dsyrk)(char *, char *, int *, int *, double *, double *, int *,
+ double *, double *, int *);
+int BLASFUNC(qsyrk)(char *, char *, int *, int *, double *, double *, int *,
+ double *, double *, int *);
+int BLASFUNC(csyrk)(char *, char *, int *, int *, float *, float *, int *,
+ float *, float *, int *);
+int BLASFUNC(zsyrk)(char *, char *, int *, int *, double *, double *, int *,
+ double *, double *, int *);
+int BLASFUNC(xsyrk)(char *, char *, int *, int *, double *, double *, int *,
+ double *, double *, int *);
+
+int BLASFUNC(ssyr2k)(char *, char *, int *, int *, float *, float *, int *,
+ float *, int *, float *, float *, int *);
+int BLASFUNC(dsyr2k)(char *, char *, int *, int *, double *, double *, int *,
+ double*, int *, double *, double *, int *);
+int BLASFUNC(qsyr2k)(char *, char *, int *, int *, double *, double *, int *,
+ double*, int *, double *, double *, int *);
+int BLASFUNC(csyr2k)(char *, char *, int *, int *, float *, float *, int *,
+ float *, int *, float *, float *, int *);
+int BLASFUNC(zsyr2k)(char *, char *, int *, int *, double *, double *, int *,
+ double*, int *, double *, double *, int *);
+int BLASFUNC(xsyr2k)(char *, char *, int *, int *, double *, double *, int *,
+ double*, int *, double *, double *, int *);
+
+int BLASFUNC(chemm)(char *, char *, int *, int *, float *, float *, int *,
+ float *, int *, float *, float *, int *);
+int BLASFUNC(zhemm)(char *, char *, int *, int *, double *, double *, int *,
+ double *, int *, double *, double *, int *);
+int BLASFUNC(xhemm)(char *, char *, int *, int *, double *, double *, int *,
+ double *, int *, double *, double *, int *);
+
+int BLASFUNC(chemm3m)(char *, char *, int *, int *, float *, float *, int *,
+ float *, int *, float *, float *, int *);
+int BLASFUNC(zhemm3m)(char *, char *, int *, int *, double *, double *, int *,
+ double *, int *, double *, double *, int *);
+int BLASFUNC(xhemm3m)(char *, char *, int *, int *, double *, double *, int *,
+ double *, int *, double *, double *, int *);
+
+int BLASFUNC(cherk)(char *, char *, int *, int *, float *, float *, int *,
+ float *, float *, int *);
+int BLASFUNC(zherk)(char *, char *, int *, int *, double *, double *, int *,
+ double *, double *, int *);
+int BLASFUNC(xherk)(char *, char *, int *, int *, double *, double *, int *,
+ double *, double *, int *);
+
+int BLASFUNC(cher2k)(char *, char *, int *, int *, float *, float *, int *,
+ float *, int *, float *, float *, int *);
+int BLASFUNC(zher2k)(char *, char *, int *, int *, double *, double *, int *,
+ double*, int *, double *, double *, int *);
+int BLASFUNC(xher2k)(char *, char *, int *, int *, double *, double *, int *,
+ double*, int *, double *, double *, int *);
+int BLASFUNC(cher2m)(char *, char *, char *, int *, int *, float *, float *, int *,
+ float *, int *, float *, float *, int *);
+int BLASFUNC(zher2m)(char *, char *, char *, int *, int *, double *, double *, int *,
+ double*, int *, double *, double *, int *);
+int BLASFUNC(xher2m)(char *, char *, char *, int *, int *, double *, double *, int *,
+ double*, int *, double *, double *, int *);
+
+int BLASFUNC(sgemt)(char *, int *, int *, float *, float *, int *,
+ float *, int *);
+int BLASFUNC(dgemt)(char *, int *, int *, double *, double *, int *,
+ double *, int *);
+int BLASFUNC(cgemt)(char *, int *, int *, float *, float *, int *,
+ float *, int *);
+int BLASFUNC(zgemt)(char *, int *, int *, double *, double *, int *,
+ double *, int *);
+
+int BLASFUNC(sgema)(char *, char *, int *, int *, float *,
+ float *, int *, float *, float *, int *, float *, int *);
+int BLASFUNC(dgema)(char *, char *, int *, int *, double *,
+ double *, int *, double*, double *, int *, double*, int *);
+int BLASFUNC(cgema)(char *, char *, int *, int *, float *,
+ float *, int *, float *, float *, int *, float *, int *);
+int BLASFUNC(zgema)(char *, char *, int *, int *, double *,
+ double *, int *, double*, double *, int *, double*, int *);
+
+int BLASFUNC(sgems)(char *, char *, int *, int *, float *,
+ float *, int *, float *, float *, int *, float *, int *);
+int BLASFUNC(dgems)(char *, char *, int *, int *, double *,
+ double *, int *, double*, double *, int *, double*, int *);
+int BLASFUNC(cgems)(char *, char *, int *, int *, float *,
+ float *, int *, float *, float *, int *, float *, int *);
+int BLASFUNC(zgems)(char *, char *, int *, int *, double *,
+ double *, int *, double*, double *, int *, double*, int *);
+
+int BLASFUNC(sgetf2)(int *, int *, float *, int *, int *, int *);
+int BLASFUNC(dgetf2)(int *, int *, double *, int *, int *, int *);
+int BLASFUNC(qgetf2)(int *, int *, double *, int *, int *, int *);
+int BLASFUNC(cgetf2)(int *, int *, float *, int *, int *, int *);
+int BLASFUNC(zgetf2)(int *, int *, double *, int *, int *, int *);
+int BLASFUNC(xgetf2)(int *, int *, double *, int *, int *, int *);
+
+int BLASFUNC(sgetrf)(int *, int *, float *, int *, int *, int *);
+int BLASFUNC(dgetrf)(int *, int *, double *, int *, int *, int *);
+int BLASFUNC(qgetrf)(int *, int *, double *, int *, int *, int *);
+int BLASFUNC(cgetrf)(int *, int *, float *, int *, int *, int *);
+int BLASFUNC(zgetrf)(int *, int *, double *, int *, int *, int *);
+int BLASFUNC(xgetrf)(int *, int *, double *, int *, int *, int *);
+
+int BLASFUNC(slaswp)(int *, float *, int *, int *, int *, int *, int *);
+int BLASFUNC(dlaswp)(int *, double *, int *, int *, int *, int *, int *);
+int BLASFUNC(qlaswp)(int *, double *, int *, int *, int *, int *, int *);
+int BLASFUNC(claswp)(int *, float *, int *, int *, int *, int *, int *);
+int BLASFUNC(zlaswp)(int *, double *, int *, int *, int *, int *, int *);
+int BLASFUNC(xlaswp)(int *, double *, int *, int *, int *, int *, int *);
+
+int BLASFUNC(sgetrs)(char *, int *, int *, float *, int *, int *, float *, int *, int *);
+int BLASFUNC(dgetrs)(char *, int *, int *, double *, int *, int *, double *, int *, int *);
+int BLASFUNC(qgetrs)(char *, int *, int *, double *, int *, int *, double *, int *, int *);
+int BLASFUNC(cgetrs)(char *, int *, int *, float *, int *, int *, float *, int *, int *);
+int BLASFUNC(zgetrs)(char *, int *, int *, double *, int *, int *, double *, int *, int *);
+int BLASFUNC(xgetrs)(char *, int *, int *, double *, int *, int *, double *, int *, int *);
+
+int BLASFUNC(sgesv)(int *, int *, float *, int *, int *, float *, int *, int *);
+int BLASFUNC(dgesv)(int *, int *, double *, int *, int *, double*, int *, int *);
+int BLASFUNC(qgesv)(int *, int *, double *, int *, int *, double*, int *, int *);
+int BLASFUNC(cgesv)(int *, int *, float *, int *, int *, float *, int *, int *);
+int BLASFUNC(zgesv)(int *, int *, double *, int *, int *, double*, int *, int *);
+int BLASFUNC(xgesv)(int *, int *, double *, int *, int *, double*, int *, int *);
+
+int BLASFUNC(spotf2)(char *, int *, float *, int *, int *);
+int BLASFUNC(dpotf2)(char *, int *, double *, int *, int *);
+int BLASFUNC(qpotf2)(char *, int *, double *, int *, int *);
+int BLASFUNC(cpotf2)(char *, int *, float *, int *, int *);
+int BLASFUNC(zpotf2)(char *, int *, double *, int *, int *);
+int BLASFUNC(xpotf2)(char *, int *, double *, int *, int *);
+
+int BLASFUNC(spotrf)(char *, int *, float *, int *, int *);
+int BLASFUNC(dpotrf)(char *, int *, double *, int *, int *);
+int BLASFUNC(qpotrf)(char *, int *, double *, int *, int *);
+int BLASFUNC(cpotrf)(char *, int *, float *, int *, int *);
+int BLASFUNC(zpotrf)(char *, int *, double *, int *, int *);
+int BLASFUNC(xpotrf)(char *, int *, double *, int *, int *);
+
+int BLASFUNC(slauu2)(char *, int *, float *, int *, int *);
+int BLASFUNC(dlauu2)(char *, int *, double *, int *, int *);
+int BLASFUNC(qlauu2)(char *, int *, double *, int *, int *);
+int BLASFUNC(clauu2)(char *, int *, float *, int *, int *);
+int BLASFUNC(zlauu2)(char *, int *, double *, int *, int *);
+int BLASFUNC(xlauu2)(char *, int *, double *, int *, int *);
+
+int BLASFUNC(slauum)(char *, int *, float *, int *, int *);
+int BLASFUNC(dlauum)(char *, int *, double *, int *, int *);
+int BLASFUNC(qlauum)(char *, int *, double *, int *, int *);
+int BLASFUNC(clauum)(char *, int *, float *, int *, int *);
+int BLASFUNC(zlauum)(char *, int *, double *, int *, int *);
+int BLASFUNC(xlauum)(char *, int *, double *, int *, int *);
+
+int BLASFUNC(strti2)(char *, char *, int *, float *, int *, int *);
+int BLASFUNC(dtrti2)(char *, char *, int *, double *, int *, int *);
+int BLASFUNC(qtrti2)(char *, char *, int *, double *, int *, int *);
+int BLASFUNC(ctrti2)(char *, char *, int *, float *, int *, int *);
+int BLASFUNC(ztrti2)(char *, char *, int *, double *, int *, int *);
+int BLASFUNC(xtrti2)(char *, char *, int *, double *, int *, int *);
+
+int BLASFUNC(strtri)(char *, char *, int *, float *, int *, int *);
+int BLASFUNC(dtrtri)(char *, char *, int *, double *, int *, int *);
+int BLASFUNC(qtrtri)(char *, char *, int *, double *, int *, int *);
+int BLASFUNC(ctrtri)(char *, char *, int *, float *, int *, int *);
+int BLASFUNC(ztrtri)(char *, char *, int *, double *, int *, int *);
+int BLASFUNC(xtrtri)(char *, char *, int *, double *, int *, int *);
+
+int BLASFUNC(spotri)(char *, int *, float *, int *, int *);
+int BLASFUNC(dpotri)(char *, int *, double *, int *, int *);
+int BLASFUNC(qpotri)(char *, int *, double *, int *, int *);
+int BLASFUNC(cpotri)(char *, int *, float *, int *, int *);
+int BLASFUNC(zpotri)(char *, int *, double *, int *, int *);
+int BLASFUNC(xpotri)(char *, int *, double *, int *, int *);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/Eigen/src/plugins/ArrayCwiseBinaryOps.h b/Eigen/src/plugins/ArrayCwiseBinaryOps.h
new file mode 100644
index 000000000..5b979ebf8
--- /dev/null
+++ b/Eigen/src/plugins/ArrayCwiseBinaryOps.h
@@ -0,0 +1,199 @@
+/** \returns an expression of the coefficient wise product of \c *this and \a other
+ *
+ * \sa MatrixBase::cwiseProduct
+ */
+template<typename OtherDerived>
+EIGEN_STRONG_INLINE const EIGEN_CWISE_PRODUCT_RETURN_TYPE(Derived,OtherDerived)
+operator*(const EIGEN_CURRENT_STORAGE_BASE_CLASS<OtherDerived> &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<typename OtherDerived>
+EIGEN_STRONG_INLINE const CwiseBinaryOp<internal::scalar_quotient_op<Scalar>, const Derived, const OtherDerived>
+operator/(const EIGEN_CURRENT_STORAGE_BASE_CLASS<OtherDerived> &other) const
+{
+ return CwiseBinaryOp<internal::scalar_quotient_op<Scalar>, 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<internal::scalar_min_op<Scalar>, const Derived, const ConstantReturnType>
+(min)(const Scalar &other) const
+{
+ return (min)(Derived::PlainObject::Constant(rows(), cols(), other));
+}
+
+/** \returns an expression of the coefficient-wise max of \c *this and \a other
+ *
+ * Example: \include Cwise_max.cpp
+ * 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<internal::scalar_max_op<Scalar>, const Derived, const ConstantReturnType>
+(max)(const Scalar &other) const
+{
+ return (max)(Derived::PlainObject::Constant(rows(), cols(), other));
+}
+
+/** \returns an expression of the coefficient-wise \< operator of *this and \a other
+ *
+ * Example: \include Cwise_less.cpp
+ * Output: \verbinclude Cwise_less.out
+ *
+ * \sa all(), any(), operator>(), operator<=()
+ */
+EIGEN_MAKE_CWISE_BINARY_OP(operator<,std::less)
+
+/** \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_BINARY_OP(operator<=,std::less_equal)
+
+/** \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_BINARY_OP(operator>,std::greater)
+
+/** \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_BINARY_OP(operator>=,std::greater_equal)
+
+/** \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_BINARY_OP(operator==,std::equal_to)
+
+/** \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_BINARY_OP(operator!=,std::not_equal_to)
+
+// 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<internal::scalar_add_op<Scalar>, const Derived>
+operator+(const Scalar& scalar) const
+{
+ return CwiseUnaryOp<internal::scalar_add_op<Scalar>, const Derived>(derived(), internal::scalar_add_op<Scalar>(scalar));
+}
+
+friend inline const CwiseUnaryOp<internal::scalar_add_op<Scalar>, const Derived>
+operator+(const Scalar& scalar,const EIGEN_CURRENT_STORAGE_BASE_CLASS<Derived>& 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<internal::scalar_add_op<Scalar>, const Derived>
+operator-(const Scalar& scalar) const
+{
+ return *this + (-scalar);
+}
+
+friend inline const CwiseUnaryOp<internal::scalar_add_op<Scalar>, const CwiseUnaryOp<internal::scalar_opposite_op<Scalar>, const Derived> >
+operator-(const Scalar& scalar,const EIGEN_CURRENT_STORAGE_BASE_CLASS<Derived>& 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<typename OtherDerived>
+inline const CwiseBinaryOp<internal::scalar_boolean_and_op, const Derived, const OtherDerived>
+operator&&(const EIGEN_CURRENT_STORAGE_BASE_CLASS<OtherDerived> &other) const
+{
+ EIGEN_STATIC_ASSERT((internal::is_same<bool,Scalar>::value && internal::is_same<bool,typename OtherDerived::Scalar>::value),
+ THIS_METHOD_IS_ONLY_FOR_EXPRESSIONS_OF_BOOL);
+ return CwiseBinaryOp<internal::scalar_boolean_and_op, const Derived, const OtherDerived>(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<typename OtherDerived>
+inline const CwiseBinaryOp<internal::scalar_boolean_or_op, const Derived, const OtherDerived>
+operator||(const EIGEN_CURRENT_STORAGE_BASE_CLASS<OtherDerived> &other) const
+{
+ EIGEN_STATIC_ASSERT((internal::is_same<bool,Scalar>::value && internal::is_same<bool,typename OtherDerived::Scalar>::value),
+ THIS_METHOD_IS_ONLY_FOR_EXPRESSIONS_OF_BOOL);
+ return CwiseBinaryOp<internal::scalar_boolean_or_op, const Derived, const OtherDerived>(derived(),other.derived());
+}
diff --git a/Eigen/src/plugins/ArrayCwiseUnaryOps.h b/Eigen/src/plugins/ArrayCwiseUnaryOps.h
new file mode 100644
index 000000000..0dffaf413
--- /dev/null
+++ b/Eigen/src/plugins/ArrayCwiseUnaryOps.h
@@ -0,0 +1,202 @@
+
+
+/** \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<internal::scalar_abs_op<Scalar>, 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<internal::scalar_abs2_op<Scalar>, 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<internal::scalar_exp_op<Scalar>, 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<internal::scalar_log_op<Scalar>, 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<internal::scalar_sqrt_op<Scalar>, 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<internal::scalar_cos_op<Scalar>, 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<internal::scalar_sin_op<Scalar>, 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<internal::scalar_acos_op<Scalar>, 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<internal::scalar_asin_op<Scalar>, 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<internal::scalar_tan_op<Scalar>, 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<internal::scalar_pow_op<Scalar>, const Derived>
+pow(const Scalar& exponent) const
+{
+ return CwiseUnaryOp<internal::scalar_pow_op<Scalar>, const Derived>
+ (derived(), internal::scalar_pow_op<Scalar>(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<internal::scalar_inverse_op<Scalar>, 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<internal::scalar_square_op<Scalar>, 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<internal::scalar_cube_op<Scalar>, const Derived>
+cube() const
+{
+ return derived();
+}
+
+#define EIGEN_MAKE_SCALAR_CWISE_UNARY_OP(METHOD_NAME,FUNCTOR) \
+ inline const CwiseUnaryOp<std::binder2nd<FUNCTOR<Scalar> >, const Derived> \
+ METHOD_NAME(const Scalar& s) const { \
+ return CwiseUnaryOp<std::binder2nd<FUNCTOR<Scalar> >, const Derived> \
+ (derived(), std::bind2nd(FUNCTOR<Scalar>(), s)); \
+ }
+
+EIGEN_MAKE_SCALAR_CWISE_UNARY_OP(operator==, std::equal_to)
+EIGEN_MAKE_SCALAR_CWISE_UNARY_OP(operator!=, std::not_equal_to)
+EIGEN_MAKE_SCALAR_CWISE_UNARY_OP(operator<, std::less)
+EIGEN_MAKE_SCALAR_CWISE_UNARY_OP(operator<=, std::less_equal)
+EIGEN_MAKE_SCALAR_CWISE_UNARY_OP(operator>, std::greater)
+EIGEN_MAKE_SCALAR_CWISE_UNARY_OP(operator>=, std::greater_equal)
+
diff --git a/Eigen/src/plugins/BlockMethods.h b/Eigen/src/plugins/BlockMethods.h
new file mode 100644
index 000000000..ef224001a
--- /dev/null
+++ b/Eigen/src/plugins/BlockMethods.h
@@ -0,0 +1,580 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra.
+//
+// Copyright (C) 2008-2010 Gael Guennebaud <gael.guennebaud@inria.fr>
+// Copyright (C) 2006-2010 Benoit Jacob <jacob.benoit.1@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 EIGEN_BLOCKMETHODS_H
+#define EIGEN_BLOCKMETHODS_H
+
+#ifndef EIGEN_PARSED_BY_DOXYGEN
+
+/** \internal expression type of a column */
+typedef Block<Derived, internal::traits<Derived>::RowsAtCompileTime, 1, !IsRowMajor> ColXpr;
+typedef const Block<const Derived, internal::traits<Derived>::RowsAtCompileTime, 1, !IsRowMajor> ConstColXpr;
+/** \internal expression type of a row */
+typedef Block<Derived, 1, internal::traits<Derived>::ColsAtCompileTime, IsRowMajor> RowXpr;
+typedef const Block<const Derived, 1, internal::traits<Derived>::ColsAtCompileTime, IsRowMajor> ConstRowXpr;
+/** \internal expression type of a block of whole columns */
+typedef Block<Derived, internal::traits<Derived>::RowsAtCompileTime, Dynamic, !IsRowMajor> ColsBlockXpr;
+typedef const Block<const Derived, internal::traits<Derived>::RowsAtCompileTime, Dynamic, !IsRowMajor> ConstColsBlockXpr;
+/** \internal expression type of a block of whole rows */
+typedef Block<Derived, Dynamic, internal::traits<Derived>::ColsAtCompileTime, IsRowMajor> RowsBlockXpr;
+typedef const Block<const Derived, Dynamic, internal::traits<Derived>::ColsAtCompileTime, IsRowMajor> ConstRowsBlockXpr;
+/** \internal expression type of a block of whole columns */
+template<int N> struct NColsBlockXpr { typedef Block<Derived, internal::traits<Derived>::RowsAtCompileTime, N, !IsRowMajor> Type; };
+template<int N> struct ConstNColsBlockXpr { typedef const Block<const Derived, internal::traits<Derived>::RowsAtCompileTime, N, !IsRowMajor> Type; };
+/** \internal expression type of a block of whole rows */
+template<int N> struct NRowsBlockXpr { typedef Block<Derived, N, internal::traits<Derived>::ColsAtCompileTime, IsRowMajor> Type; };
+template<int N> struct ConstNRowsBlockXpr { typedef const Block<const Derived, N, internal::traits<Derived>::ColsAtCompileTime, IsRowMajor> 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<Derived> block(Index startRow, Index startCol, Index blockRows, Index blockCols)
+{
+ return Block<Derived>(derived(), startRow, startCol, blockRows, blockCols);
+}
+
+/** This is the const version of block(Index,Index,Index,Index). */
+inline const Block<const Derived> block(Index startRow, Index startCol, Index blockRows, Index blockCols) const
+{
+ return Block<const Derived>(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<Derived> topRightCorner(Index cRows, Index cCols)
+{
+ return Block<Derived>(derived(), 0, cols() - cCols, cRows, cCols);
+}
+
+/** This is the const version of topRightCorner(Index, Index).*/
+inline const Block<const Derived> topRightCorner(Index cRows, Index cCols) const
+{
+ return Block<const Derived>(derived(), 0, cols() - cCols, cRows, cCols);
+}
+
+/** \returns an expression of a fixed-size top-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_topRightCorner.cpp
+ * Output: \verbinclude MatrixBase_template_int_int_topRightCorner.out
+ *
+ * \sa class Block, block(Index,Index,Index,Index)
+ */
+template<int CRows, int CCols>
+inline Block<Derived, CRows, CCols> topRightCorner()
+{
+ return Block<Derived, CRows, CCols>(derived(), 0, cols() - CCols);
+}
+
+/** This is the const version of topRightCorner<int, int>().*/
+template<int CRows, int CCols>
+inline const Block<const Derived, CRows, CCols> topRightCorner() const
+{
+ return Block<const Derived, CRows, CCols>(derived(), 0, cols() - 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<Derived> topLeftCorner(Index cRows, Index cCols)
+{
+ return Block<Derived>(derived(), 0, 0, cRows, cCols);
+}
+
+/** This is the const version of topLeftCorner(Index, Index).*/
+inline const Block<const Derived> topLeftCorner(Index cRows, Index cCols) const
+{
+ return Block<const Derived>(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<int CRows, int CCols>
+inline Block<Derived, CRows, CCols> topLeftCorner()
+{
+ return Block<Derived, CRows, CCols>(derived(), 0, 0);
+}
+
+/** This is the const version of topLeftCorner<int, int>().*/
+template<int CRows, int CCols>
+inline const Block<const Derived, CRows, CCols> topLeftCorner() const
+{
+ return Block<const Derived, CRows, CCols>(derived(), 0, 0);
+}
+
+
+
+/** \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<Derived> bottomRightCorner(Index cRows, Index cCols)
+{
+ return Block<Derived>(derived(), rows() - cRows, cols() - cCols, cRows, cCols);
+}
+
+/** This is the const version of bottomRightCorner(Index, Index).*/
+inline const Block<const Derived> bottomRightCorner(Index cRows, Index cCols) const
+{
+ return Block<const Derived>(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<int CRows, int CCols>
+inline Block<Derived, CRows, CCols> bottomRightCorner()
+{
+ return Block<Derived, CRows, CCols>(derived(), rows() - CRows, cols() - CCols);
+}
+
+/** This is the const version of bottomRightCorner<int, int>().*/
+template<int CRows, int CCols>
+inline const Block<const Derived, CRows, CCols> bottomRightCorner() const
+{
+ return Block<const Derived, CRows, CCols>(derived(), rows() - CRows, cols() - 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<Derived> bottomLeftCorner(Index cRows, Index cCols)
+{
+ return Block<Derived>(derived(), rows() - cRows, 0, cRows, cCols);
+}
+
+/** This is the const version of bottomLeftCorner(Index, Index).*/
+inline const Block<const Derived> bottomLeftCorner(Index cRows, Index cCols) const
+{
+ return Block<const Derived>(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<int CRows, int CCols>
+inline Block<Derived, CRows, CCols> bottomLeftCorner()
+{
+ return Block<Derived, CRows, CCols>(derived(), rows() - CRows, 0);
+}
+
+/** This is the const version of bottomLeftCorner<int, int>().*/
+template<int CRows, int CCols>
+inline const Block<const Derived, CRows, CCols> bottomLeftCorner() const
+{
+ return Block<const Derived, CRows, CCols>(derived(), rows() - CRows, 0);
+}
+
+
+
+/** \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
+ *
+ * Example: \include MatrixBase_template_int_topRows.cpp
+ * Output: \verbinclude MatrixBase_template_int_topRows.out
+ *
+ * \sa class Block, block(Index,Index,Index,Index)
+ */
+template<int N>
+inline typename NRowsBlockXpr<N>::Type topRows()
+{
+ return typename NRowsBlockXpr<N>::Type(derived(), 0, 0, N, cols());
+}
+
+/** This is the const version of topRows<int>().*/
+template<int N>
+inline typename ConstNRowsBlockXpr<N>::Type topRows() const
+{
+ return typename ConstNRowsBlockXpr<N>::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
+ *
+ * Example: \include MatrixBase_template_int_bottomRows.cpp
+ * Output: \verbinclude MatrixBase_template_int_bottomRows.out
+ *
+ * \sa class Block, block(Index,Index,Index,Index)
+ */
+template<int N>
+inline typename NRowsBlockXpr<N>::Type bottomRows()
+{
+ return typename NRowsBlockXpr<N>::Type(derived(), rows() - N, 0, N, cols());
+}
+
+/** This is the const version of bottomRows<int>().*/
+template<int N>
+inline typename ConstNRowsBlockXpr<N>::Type bottomRows() const
+{
+ return typename ConstNRowsBlockXpr<N>::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 numRows 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 numRows)
+{
+ return RowsBlockXpr(derived(), startRow, 0, numRows, cols());
+}
+
+/** This is the const version of middleRows(Index,Index).*/
+inline ConstRowsBlockXpr middleRows(Index startRow, Index numRows) const
+{
+ return ConstRowsBlockXpr(derived(), startRow, 0, numRows, cols());
+}
+
+/** \returns a block consisting of a range of rows of *this.
+ *
+ * \tparam N the number of rows in the block
+ * \param startRow the index of the first row in the block
+ *
+ * Example: \include DenseBase_template_int_middleRows.cpp
+ * Output: \verbinclude DenseBase_template_int_middleRows.out
+ *
+ * \sa class Block, block(Index,Index,Index,Index)
+ */
+template<int N>
+inline typename NRowsBlockXpr<N>::Type middleRows(Index startRow)
+{
+ return typename NRowsBlockXpr<N>::Type(derived(), startRow, 0, N, cols());
+}
+
+/** This is the const version of middleRows<int>().*/
+template<int N>
+inline typename ConstNRowsBlockXpr<N>::Type middleRows(Index startRow) const
+{
+ return typename ConstNRowsBlockXpr<N>::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
+ *
+ * Example: \include MatrixBase_template_int_leftCols.cpp
+ * Output: \verbinclude MatrixBase_template_int_leftCols.out
+ *
+ * \sa class Block, block(Index,Index,Index,Index)
+ */
+template<int N>
+inline typename NColsBlockXpr<N>::Type leftCols()
+{
+ return typename NColsBlockXpr<N>::Type(derived(), 0, 0, rows(), N);
+}
+
+/** This is the const version of leftCols<int>().*/
+template<int N>
+inline typename ConstNColsBlockXpr<N>::Type leftCols() const
+{
+ return typename ConstNColsBlockXpr<N>::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
+ *
+ * Example: \include MatrixBase_template_int_rightCols.cpp
+ * Output: \verbinclude MatrixBase_template_int_rightCols.out
+ *
+ * \sa class Block, block(Index,Index,Index,Index)
+ */
+template<int N>
+inline typename NColsBlockXpr<N>::Type rightCols()
+{
+ return typename NColsBlockXpr<N>::Type(derived(), 0, cols() - N, rows(), N);
+}
+
+/** This is the const version of rightCols<int>().*/
+template<int N>
+inline typename ConstNColsBlockXpr<N>::Type rightCols() const
+{
+ return typename ConstNColsBlockXpr<N>::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
+ * \param startCol the index of the first column in the block
+ *
+ * Example: \include DenseBase_template_int_middleCols.cpp
+ * Output: \verbinclude DenseBase_template_int_middleCols.out
+ *
+ * \sa class Block, block(Index,Index,Index,Index)
+ */
+template<int N>
+inline typename NColsBlockXpr<N>::Type middleCols(Index startCol)
+{
+ return typename NColsBlockXpr<N>::Type(derived(), 0, startCol, rows(), N);
+}
+
+/** This is the const version of middleCols<int>().*/
+template<int N>
+inline typename ConstNColsBlockXpr<N>::Type middleCols(Index startCol) const
+{
+ return typename ConstNColsBlockXpr<N>::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<int BlockRows, int BlockCols>
+inline Block<Derived, BlockRows, BlockCols> block(Index startRow, Index startCol)
+{
+ return Block<Derived, BlockRows, BlockCols>(derived(), startRow, startCol);
+}
+
+/** This is the const version of block<>(Index, Index). */
+template<int BlockRows, int BlockCols>
+inline const Block<const Derived, BlockRows, BlockCols> block(Index startRow, Index startCol) const
+{
+ return Block<const Derived, BlockRows, BlockCols>(derived(), startRow, startCol);
+}
+
+/** \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);
+}
+
+#endif // EIGEN_BLOCKMETHODS_H
diff --git a/Eigen/src/plugins/CMakeLists.txt b/Eigen/src/plugins/CMakeLists.txt
new file mode 100644
index 000000000..1a1d3ffbd
--- /dev/null
+++ b/Eigen/src/plugins/CMakeLists.txt
@@ -0,0 +1,6 @@
+FILE(GLOB Eigen_plugins_SRCS "*.h")
+
+INSTALL(FILES
+ ${Eigen_plugins_SRCS}
+ DESTINATION ${INCLUDE_INSTALL_DIR}/Eigen/src/plugins COMPONENT Devel
+ )
diff --git a/Eigen/src/plugins/CommonCwiseBinaryOps.h b/Eigen/src/plugins/CommonCwiseBinaryOps.h
new file mode 100644
index 000000000..688d22440
--- /dev/null
+++ b/Eigen/src/plugins/CommonCwiseBinaryOps.h
@@ -0,0 +1,46 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra.
+//
+// Copyright (C) 2008-2009 Gael Guennebaud <gael.guennebaud@inria.fr>
+// Copyright (C) 2006-2008 Benoit Jacob <jacob.benoit.1@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/.
+
+// 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<typename CustomBinaryOp, typename OtherDerived>
+EIGEN_STRONG_INLINE const CwiseBinaryOp<CustomBinaryOp, const Derived, const OtherDerived>
+binaryExpr(const EIGEN_CURRENT_STORAGE_BASE_CLASS<OtherDerived> &other, const CustomBinaryOp& func = CustomBinaryOp()) const
+{
+ return CwiseBinaryOp<CustomBinaryOp, const Derived, const OtherDerived>(derived(), other.derived(), func);
+}
+
diff --git a/Eigen/src/plugins/CommonCwiseUnaryOps.h b/Eigen/src/plugins/CommonCwiseUnaryOps.h
new file mode 100644
index 000000000..08e931aad
--- /dev/null
+++ b/Eigen/src/plugins/CommonCwiseUnaryOps.h
@@ -0,0 +1,172 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra.
+//
+// Copyright (C) 2008-2009 Gael Guennebaud <gael.guennebaud@inria.fr>
+// Copyright (C) 2006-2008 Benoit Jacob <jacob.benoit.1@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/.
+
+// 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<internal::scalar_multiple_op<Scalar>, const Derived> ScalarMultipleReturnType;
+/** \internal Represents a quotient of an expression by a scalar*/
+typedef CwiseUnaryOp<internal::scalar_quotient1_op<Scalar>, const Derived> ScalarQuotient1ReturnType;
+/** \internal the return type of conjugate() */
+typedef typename internal::conditional<NumTraits<Scalar>::IsComplex,
+ const CwiseUnaryOp<internal::scalar_conjugate_op<Scalar>, const Derived>,
+ const Derived&
+ >::type ConjugateReturnType;
+/** \internal the return type of real() const */
+typedef typename internal::conditional<NumTraits<Scalar>::IsComplex,
+ const CwiseUnaryOp<internal::scalar_real_op<Scalar>, const Derived>,
+ const Derived&
+ >::type RealReturnType;
+/** \internal the return type of real() */
+typedef typename internal::conditional<NumTraits<Scalar>::IsComplex,
+ CwiseUnaryView<internal::scalar_real_ref_op<Scalar>, Derived>,
+ Derived&
+ >::type NonConstRealReturnType;
+/** \internal the return type of imag() const */
+typedef CwiseUnaryOp<internal::scalar_imag_op<Scalar>, const Derived> ImagReturnType;
+/** \internal the return type of imag() */
+typedef CwiseUnaryView<internal::scalar_imag_ref_op<Scalar>, Derived> NonConstImagReturnType;
+
+#endif // not EIGEN_PARSED_BY_DOXYGEN
+
+/** \returns an expression of the opposite of \c *this
+ */
+inline const CwiseUnaryOp<internal::scalar_opposite_op<typename internal::traits<Derived>::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<internal::scalar_multiple_op<Scalar>, const Derived>
+ (derived(), internal::scalar_multiple_op<Scalar>(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<internal::scalar_quotient1_op<typename internal::traits<Derived>::Scalar>, const Derived>
+operator/(const Scalar& scalar) const
+{
+ return CwiseUnaryOp<internal::scalar_quotient1_op<Scalar>, const Derived>
+ (derived(), internal::scalar_quotient1_op<Scalar>(scalar));
+}
+
+/** Overloaded for efficient real matrix times complex scalar value */
+inline const CwiseUnaryOp<internal::scalar_multiple2_op<Scalar,std::complex<Scalar> >, const Derived>
+operator*(const std::complex<Scalar>& scalar) const
+{
+ return CwiseUnaryOp<internal::scalar_multiple2_op<Scalar,std::complex<Scalar> >, const Derived>
+ (*static_cast<const Derived*>(this), internal::scalar_multiple2_op<Scalar,std::complex<Scalar> >(scalar));
+}
+
+inline friend const ScalarMultipleReturnType
+operator*(const Scalar& scalar, const StorageBaseType& matrix)
+{ return matrix*scalar; }
+
+inline friend const CwiseUnaryOp<internal::scalar_multiple2_op<Scalar,std::complex<Scalar> >, const Derived>
+operator*(const std::complex<Scalar>& 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 NewType>
+typename internal::cast_return_type<Derived,const CwiseUnaryOp<internal::scalar_cast_op<typename internal::traits<Derived>::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<typename CustomUnaryOp>
+inline const CwiseUnaryOp<CustomUnaryOp, const Derived>
+unaryExpr(const CustomUnaryOp& func = CustomUnaryOp()) const
+{
+ return CwiseUnaryOp<CustomUnaryOp, const Derived>(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<typename CustomViewOp>
+inline const CwiseUnaryView<CustomViewOp, const Derived>
+unaryViewExpr(const CustomViewOp& func = CustomViewOp()) const
+{
+ return CwiseUnaryView<CustomViewOp, const Derived>(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/Eigen/src/plugins/MatrixCwiseBinaryOps.h b/Eigen/src/plugins/MatrixCwiseBinaryOps.h
new file mode 100644
index 000000000..3a737df7b
--- /dev/null
+++ b/Eigen/src/plugins/MatrixCwiseBinaryOps.h
@@ -0,0 +1,126 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra.
+//
+// Copyright (C) 2008-2009 Gael Guennebaud <gael.guennebaud@inria.fr>
+// Copyright (C) 2006-2008 Benoit Jacob <jacob.benoit.1@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/.
+
+// This file is a base class plugin containing matrix specifics coefficient wise functions.
+
+/** \returns an expression of the Schur product (coefficient wise product) of *this and \a other
+ *
+ * Example: \include MatrixBase_cwiseProduct.cpp
+ * Output: \verbinclude MatrixBase_cwiseProduct.out
+ *
+ * \sa class CwiseBinaryOp, cwiseAbs2
+ */
+template<typename OtherDerived>
+EIGEN_STRONG_INLINE const EIGEN_CWISE_PRODUCT_RETURN_TYPE(Derived,OtherDerived)
+cwiseProduct(const EIGEN_CURRENT_STORAGE_BASE_CLASS<OtherDerived> &other) const
+{
+ return EIGEN_CWISE_PRODUCT_RETURN_TYPE(Derived,OtherDerived)(derived(), other.derived());
+}
+
+/** \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 MatrixBase_cwiseEqual.cpp
+ * Output: \verbinclude MatrixBase_cwiseEqual.out
+ *
+ * \sa cwiseNotEqual(), isApprox(), isMuchSmallerThan()
+ */
+template<typename OtherDerived>
+inline const CwiseBinaryOp<std::equal_to<Scalar>, const Derived, const OtherDerived>
+cwiseEqual(const EIGEN_CURRENT_STORAGE_BASE_CLASS<OtherDerived> &other) const
+{
+ return CwiseBinaryOp<std::equal_to<Scalar>, const Derived, const OtherDerived>(derived(), other.derived());
+}
+
+/** \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 MatrixBase_cwiseNotEqual.cpp
+ * Output: \verbinclude MatrixBase_cwiseNotEqual.out
+ *
+ * \sa cwiseEqual(), isApprox(), isMuchSmallerThan()
+ */
+template<typename OtherDerived>
+inline const CwiseBinaryOp<std::not_equal_to<Scalar>, const Derived, const OtherDerived>
+cwiseNotEqual(const EIGEN_CURRENT_STORAGE_BASE_CLASS<OtherDerived> &other) const
+{
+ return CwiseBinaryOp<std::not_equal_to<Scalar>, const Derived, const OtherDerived>(derived(), other.derived());
+}
+
+/** \returns an expression of the coefficient-wise min of *this and \a other
+ *
+ * Example: \include MatrixBase_cwiseMin.cpp
+ * Output: \verbinclude MatrixBase_cwiseMin.out
+ *
+ * \sa class CwiseBinaryOp, max()
+ */
+template<typename OtherDerived>
+EIGEN_STRONG_INLINE const CwiseBinaryOp<internal::scalar_min_op<Scalar>, const Derived, const OtherDerived>
+cwiseMin(const EIGEN_CURRENT_STORAGE_BASE_CLASS<OtherDerived> &other) const
+{
+ return CwiseBinaryOp<internal::scalar_min_op<Scalar>, const Derived, const OtherDerived>(derived(), other.derived());
+}
+
+/** \returns an expression of the coefficient-wise min of *this and scalar \a other
+ *
+ * \sa class CwiseBinaryOp, min()
+ */
+EIGEN_STRONG_INLINE const CwiseBinaryOp<internal::scalar_min_op<Scalar>, const Derived, const ConstantReturnType>
+cwiseMin(const Scalar &other) const
+{
+ return cwiseMin(Derived::PlainObject::Constant(rows(), cols(), other));
+}
+
+/** \returns an expression of the coefficient-wise max of *this and \a other
+ *
+ * Example: \include MatrixBase_cwiseMax.cpp
+ * Output: \verbinclude MatrixBase_cwiseMax.out
+ *
+ * \sa class CwiseBinaryOp, min()
+ */
+template<typename OtherDerived>
+EIGEN_STRONG_INLINE const CwiseBinaryOp<internal::scalar_max_op<Scalar>, const Derived, const OtherDerived>
+cwiseMax(const EIGEN_CURRENT_STORAGE_BASE_CLASS<OtherDerived> &other) const
+{
+ return CwiseBinaryOp<internal::scalar_max_op<Scalar>, const Derived, const OtherDerived>(derived(), other.derived());
+}
+
+/** \returns an expression of the coefficient-wise max of *this and scalar \a other
+ *
+ * \sa class CwiseBinaryOp, min()
+ */
+EIGEN_STRONG_INLINE const CwiseBinaryOp<internal::scalar_max_op<Scalar>, const Derived, const ConstantReturnType>
+cwiseMax(const Scalar &other) const
+{
+ return cwiseMax(Derived::PlainObject::Constant(rows(), cols(), other));
+}
+
+
+/** \returns an expression of the coefficient-wise quotient of *this and \a other
+ *
+ * Example: \include MatrixBase_cwiseQuotient.cpp
+ * Output: \verbinclude MatrixBase_cwiseQuotient.out
+ *
+ * \sa class CwiseBinaryOp, cwiseProduct(), cwiseInverse()
+ */
+template<typename OtherDerived>
+EIGEN_STRONG_INLINE const CwiseBinaryOp<internal::scalar_quotient_op<Scalar>, const Derived, const OtherDerived>
+cwiseQuotient(const EIGEN_CURRENT_STORAGE_BASE_CLASS<OtherDerived> &other) const
+{
+ return CwiseBinaryOp<internal::scalar_quotient_op<Scalar>, const Derived, const OtherDerived>(derived(), other.derived());
+}
diff --git a/Eigen/src/plugins/MatrixCwiseUnaryOps.h b/Eigen/src/plugins/MatrixCwiseUnaryOps.h
new file mode 100644
index 000000000..0cf0640ba
--- /dev/null
+++ b/Eigen/src/plugins/MatrixCwiseUnaryOps.h
@@ -0,0 +1,67 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra.
+//
+// Copyright (C) 2008-2009 Gael Guennebaud <gael.guennebaud@inria.fr>
+// Copyright (C) 2006-2008 Benoit Jacob <jacob.benoit.1@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/.
+
+// 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<internal::scalar_abs_op<Scalar>, 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<internal::scalar_abs2_op<Scalar>, 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<internal::scalar_sqrt_op<Scalar>, 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<internal::scalar_inverse_op<Scalar>, const Derived>
+cwiseInverse() const { return derived(); }
+
+/** \returns an expression of the coefficient-wise == operator of \c *this and a scalar \a s
+ *
+ * \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().
+ *
+ * \sa cwiseEqual(const MatrixBase<OtherDerived> &) const
+ */
+inline const CwiseUnaryOp<std::binder1st<std::equal_to<Scalar> >, const Derived>
+cwiseEqual(const Scalar& s) const
+{
+ return CwiseUnaryOp<std::binder1st<std::equal_to<Scalar> >,const Derived>
+ (derived(), std::bind1st(std::equal_to<Scalar>(), s));
+}
diff --git a/INSTALL b/INSTALL
new file mode 100644
index 000000000..4f717e9c2
--- /dev/null
+++ b/INSTALL
@@ -0,0 +1,35 @@
+Installation instructions for Eigen
+***********************************
+
+Explanation before starting
+***************************
+
+Eigen consists only of header files, hence there is nothing to compile
+before you can use it. Moreover, these header files do not depend on your
+platform, they are the same for everybody.
+
+Method 1. Installing without using CMake
+****************************************
+
+You can use right away the headers in the Eigen/ subdirectory. In order
+to install, just copy this Eigen/ subdirectory to your favorite location.
+If you also want the unsupported features, copy the unsupported/
+subdirectory too.
+
+Method 2. Installing using CMake
+********************************
+
+Let's call this directory 'source_dir' (where this INSTALL file is).
+Before starting, create another directory which we will call 'build_dir'.
+
+Do:
+
+ cd build_dir
+ cmake source_dir
+ make install
+
+The "make install" step may require administrator privileges.
+
+You can adjust the installation destination (the "prefix")
+by passing the -DCMAKE_INSTALL_PREFIX=myprefix option to cmake, as is
+explained in the message that cmake prints at the end.
diff --git a/MODULE_LICENSE_MPL2 b/MODULE_LICENSE_MPL2
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/MODULE_LICENSE_MPL2
diff --git a/README.android b/README.android
new file mode 100644
index 000000000..6610a1a6e
--- /dev/null
+++ b/README.android
@@ -0,0 +1,13 @@
+Eigen 3.1.1
+-----------
+
+Eigen is a C++ template library for linear algebra: matrices, vectors,
+numerical solvers, and related algorithms.
+
+Website: http://eigen.tuxfamily.org/
+
+v3.1.1. Released on July 22, 2012. This is a copy of the source
+distribution from http://bitbucket.org/eigen/eigen/get/3.1.1.tar.gz.
+
+Non MPL2 license code is disabled. Trying to include such files will
+lead to an error. See ./Eigen/src/Core/util/NonMPL2.h for details.
diff --git a/bench/BenchSparseUtil.h b/bench/BenchSparseUtil.h
new file mode 100644
index 000000000..13981f6b7
--- /dev/null
+++ b/bench/BenchSparseUtil.h
@@ -0,0 +1,149 @@
+
+#include <Eigen/Sparse>
+#include <bench/BenchTimer.h>
+#include <set>
+
+using namespace std;
+using namespace Eigen;
+using namespace Eigen;
+
+#ifndef SIZE
+#define SIZE 1024
+#endif
+
+#ifndef DENSITY
+#define DENSITY 0.01
+#endif
+
+#ifndef SCALAR
+#define SCALAR double
+#endif
+
+typedef SCALAR Scalar;
+typedef Matrix<Scalar,Dynamic,Dynamic> DenseMatrix;
+typedef Matrix<Scalar,Dynamic,1> DenseVector;
+typedef SparseMatrix<Scalar> EigenSparseMatrix;
+
+void fillMatrix(float density, int rows, int cols, EigenSparseMatrix& dst)
+{
+ dst.reserve(double(rows)*cols*density);
+ for(int j = 0; j < cols; j++)
+ {
+ for(int i = 0; i < rows; i++)
+ {
+ Scalar v = (internal::random<float>(0,1) < density) ? internal::random<Scalar>() : 0;
+ if (v!=0)
+ dst.insert(i,j) = v;
+ }
+ }
+ dst.finalize();
+}
+
+void fillMatrix2(int nnzPerCol, int rows, int cols, EigenSparseMatrix& dst)
+{
+// std::cout << "alloc " << nnzPerCol*cols << "\n";
+ dst.reserve(nnzPerCol*cols);
+ for(int j = 0; j < cols; j++)
+ {
+ std::set<int> aux;
+ for(int i = 0; i < nnzPerCol; i++)
+ {
+ int k = internal::random<int>(0,rows-1);
+ while (aux.find(k)!=aux.end())
+ k = internal::random<int>(0,rows-1);
+ aux.insert(k);
+
+ dst.insert(k,j) = internal::random<Scalar>();
+ }
+ }
+ dst.finalize();
+}
+
+void eiToDense(const EigenSparseMatrix& src, DenseMatrix& dst)
+{
+ dst.setZero();
+ for (int j=0; j<src.cols(); ++j)
+ for (EigenSparseMatrix::InnerIterator it(src.derived(), j); it; ++it)
+ dst(it.index(),j) = it.value();
+}
+
+#ifndef NOGMM
+#include "gmm/gmm.h"
+typedef gmm::csc_matrix<Scalar> GmmSparse;
+typedef gmm::col_matrix< gmm::wsvector<Scalar> > GmmDynSparse;
+void eiToGmm(const EigenSparseMatrix& src, GmmSparse& dst)
+{
+ GmmDynSparse tmp(src.rows(), src.cols());
+ for (int j=0; j<src.cols(); ++j)
+ for (EigenSparseMatrix::InnerIterator it(src.derived(), j); it; ++it)
+ tmp(it.index(),j) = it.value();
+ gmm::copy(tmp, dst);
+}
+#endif
+
+#ifndef NOMTL
+#include <boost/numeric/mtl/mtl.hpp>
+typedef mtl::compressed2D<Scalar, mtl::matrix::parameters<mtl::tag::col_major> > MtlSparse;
+typedef mtl::compressed2D<Scalar, mtl::matrix::parameters<mtl::tag::row_major> > MtlSparseRowMajor;
+void eiToMtl(const EigenSparseMatrix& src, MtlSparse& dst)
+{
+ mtl::matrix::inserter<MtlSparse> ins(dst);
+ for (int j=0; j<src.cols(); ++j)
+ for (EigenSparseMatrix::InnerIterator it(src.derived(), j); it; ++it)
+ ins[it.index()][j] = it.value();
+}
+#endif
+
+#ifdef CSPARSE
+extern "C" {
+#include "cs.h"
+}
+void eiToCSparse(const EigenSparseMatrix& src, cs* &dst)
+{
+ cs* aux = cs_spalloc (0, 0, 1, 1, 1);
+ for (int j=0; j<src.cols(); ++j)
+ for (EigenSparseMatrix::InnerIterator it(src.derived(), j); it; ++it)
+ if (!cs_entry(aux, it.index(), j, it.value()))
+ {
+ std::cout << "cs_entry error\n";
+ exit(2);
+ }
+ dst = cs_compress(aux);
+// cs_spfree(aux);
+}
+#endif // CSPARSE
+
+#ifndef NOUBLAS
+#include <boost/numeric/ublas/vector.hpp>
+#include <boost/numeric/ublas/matrix.hpp>
+#include <boost/numeric/ublas/io.hpp>
+#include <boost/numeric/ublas/triangular.hpp>
+#include <boost/numeric/ublas/vector_sparse.hpp>
+#include <boost/numeric/ublas/matrix_sparse.hpp>
+#include <boost/numeric/ublas/vector_of_vector.hpp>
+#include <boost/numeric/ublas/operation.hpp>
+
+typedef boost::numeric::ublas::compressed_matrix<Scalar,boost::numeric::ublas::column_major> UBlasSparse;
+
+void eiToUblas(const EigenSparseMatrix& src, UBlasSparse& dst)
+{
+ dst.resize(src.rows(), src.cols(), false);
+ for (int j=0; j<src.cols(); ++j)
+ for (EigenSparseMatrix::InnerIterator it(src.derived(), j); it; ++it)
+ dst(it.index(),j) = it.value();
+}
+
+template <typename EigenType, typename UblasType>
+void eiToUblasVec(const EigenType& src, UblasType& dst)
+{
+ dst.resize(src.size());
+ for (int j=0; j<src.size(); ++j)
+ dst[j] = src.coeff(j);
+}
+#endif
+
+#ifdef OSKI
+extern "C" {
+#include <oski/oski.h>
+}
+#endif
diff --git a/bench/BenchTimer.h b/bench/BenchTimer.h
new file mode 100644
index 000000000..28e2bcaea
--- /dev/null
+++ b/bench/BenchTimer.h
@@ -0,0 +1,187 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra.
+//
+// Copyright (C) 2008-2010 Gael Guennebaud <gael.guennebaud@inria.fr>
+// Copyright (C) 2009 Benoit Jacob <jacob.benoit.1@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 EIGEN_BENCH_TIMERR_H
+#define EIGEN_BENCH_TIMERR_H
+
+#if defined(_WIN32) || defined(__CYGWIN__)
+# ifndef NOMINMAX
+# define NOMINMAX
+# define EIGEN_BT_UNDEF_NOMINMAX
+# endif
+# ifndef WIN32_LEAN_AND_MEAN
+# define WIN32_LEAN_AND_MEAN
+# define EIGEN_BT_UNDEF_WIN32_LEAN_AND_MEAN
+# endif
+# include <windows.h>
+#elif defined(__APPLE__)
+#include <CoreServices/CoreServices.h>
+#include <mach/mach_time.h>
+#else
+# include <unistd.h>
+#endif
+
+#include <Eigen/Core>
+
+namespace Eigen
+{
+
+enum {
+ CPU_TIMER = 0,
+ REAL_TIMER = 1
+};
+
+/** Elapsed time timer keeping the best try.
+ *
+ * On POSIX platforms we use clock_gettime with CLOCK_PROCESS_CPUTIME_ID.
+ * On Windows we use QueryPerformanceCounter
+ *
+ * Important: on linux, you must link with -lrt
+ */
+class BenchTimer
+{
+public:
+
+ BenchTimer()
+ {
+#if defined(_WIN32) || defined(__CYGWIN__)
+ LARGE_INTEGER freq;
+ QueryPerformanceFrequency(&freq);
+ m_frequency = (double)freq.QuadPart;
+#endif
+ reset();
+ }
+
+ ~BenchTimer() {}
+
+ inline void reset()
+ {
+ m_bests.fill(1e9);
+ m_worsts.fill(0);
+ m_totals.setZero();
+ }
+ inline void start()
+ {
+ m_starts[CPU_TIMER] = getCpuTime();
+ m_starts[REAL_TIMER] = getRealTime();
+ }
+ inline void stop()
+ {
+ m_times[CPU_TIMER] = getCpuTime() - m_starts[CPU_TIMER];
+ m_times[REAL_TIMER] = getRealTime() - m_starts[REAL_TIMER];
+ #if EIGEN_VERSION_AT_LEAST(2,90,0)
+ m_bests = m_bests.cwiseMin(m_times);
+ m_worsts = m_worsts.cwiseMax(m_times);
+ #else
+ m_bests(0) = std::min(m_bests(0),m_times(0));
+ m_bests(1) = std::min(m_bests(1),m_times(1));
+ m_worsts(0) = std::max(m_worsts(0),m_times(0));
+ m_worsts(1) = std::max(m_worsts(1),m_times(1));
+ #endif
+ m_totals += m_times;
+ }
+
+ /** Return the elapsed time in seconds between the last start/stop pair
+ */
+ inline double value(int TIMER = CPU_TIMER) const
+ {
+ return m_times[TIMER];
+ }
+
+ /** Return the best elapsed time in seconds
+ */
+ inline double best(int TIMER = CPU_TIMER) const
+ {
+ return m_bests[TIMER];
+ }
+
+ /** Return the worst elapsed time in seconds
+ */
+ inline double worst(int TIMER = CPU_TIMER) const
+ {
+ return m_worsts[TIMER];
+ }
+
+ /** Return the total elapsed time in seconds.
+ */
+ inline double total(int TIMER = CPU_TIMER) const
+ {
+ return m_totals[TIMER];
+ }
+
+ inline double getCpuTime() const
+ {
+#ifdef _WIN32
+ LARGE_INTEGER query_ticks;
+ QueryPerformanceCounter(&query_ticks);
+ return query_ticks.QuadPart/m_frequency;
+#elif __APPLE__
+ return double(mach_absolute_time())*1e-9;
+#else
+ timespec ts;
+ clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &ts);
+ return double(ts.tv_sec) + 1e-9 * double(ts.tv_nsec);
+#endif
+ }
+
+ inline double getRealTime() const
+ {
+#ifdef _WIN32
+ SYSTEMTIME st;
+ GetSystemTime(&st);
+ return (double)st.wSecond + 1.e-3 * (double)st.wMilliseconds;
+#elif __APPLE__
+ return double(mach_absolute_time())*1e-9;
+#else
+ timespec ts;
+ clock_gettime(CLOCK_REALTIME, &ts);
+ return double(ts.tv_sec) + 1e-9 * double(ts.tv_nsec);
+#endif
+ }
+
+protected:
+#if defined(_WIN32) || defined(__CYGWIN__)
+ double m_frequency;
+#endif
+ Vector2d m_starts;
+ Vector2d m_times;
+ Vector2d m_bests;
+ Vector2d m_worsts;
+ Vector2d m_totals;
+
+public:
+ EIGEN_MAKE_ALIGNED_OPERATOR_NEW
+};
+
+#define BENCH(TIMER,TRIES,REP,CODE) { \
+ TIMER.reset(); \
+ for(int uglyvarname1=0; uglyvarname1<TRIES; ++uglyvarname1){ \
+ TIMER.start(); \
+ for(int uglyvarname2=0; uglyvarname2<REP; ++uglyvarname2){ \
+ CODE; \
+ } \
+ TIMER.stop(); \
+ } \
+ }
+
+}
+
+// clean #defined tokens
+#ifdef EIGEN_BT_UNDEF_NOMINMAX
+# undef EIGEN_BT_UNDEF_NOMINMAX
+# undef NOMINMAX
+#endif
+
+#ifdef EIGEN_BT_UNDEF_WIN32_LEAN_AND_MEAN
+# undef EIGEN_BT_UNDEF_WIN32_LEAN_AND_MEAN
+# undef WIN32_LEAN_AND_MEAN
+#endif
+
+#endif // EIGEN_BENCH_TIMERR_H
diff --git a/bench/BenchUtil.h b/bench/BenchUtil.h
new file mode 100644
index 000000000..8883a1380
--- /dev/null
+++ b/bench/BenchUtil.h
@@ -0,0 +1,92 @@
+
+#ifndef EIGEN_BENCH_UTIL_H
+#define EIGEN_BENCH_UTIL_H
+
+#include <Eigen/Core>
+#include "BenchTimer.h"
+
+using namespace std;
+using namespace Eigen;
+
+#include <boost/preprocessor/repetition/enum_params.hpp>
+#include <boost/preprocessor/repetition.hpp>
+#include <boost/preprocessor/seq.hpp>
+#include <boost/preprocessor/array.hpp>
+#include <boost/preprocessor/arithmetic.hpp>
+#include <boost/preprocessor/comparison.hpp>
+#include <boost/preprocessor/punctuation.hpp>
+#include <boost/preprocessor/punctuation/comma.hpp>
+#include <boost/preprocessor/stringize.hpp>
+
+template<typename MatrixType> void initMatrix_random(MatrixType& mat) __attribute__((noinline));
+template<typename MatrixType> void initMatrix_random(MatrixType& mat)
+{
+ mat.setRandom();// = MatrixType::random(mat.rows(), mat.cols());
+}
+
+template<typename MatrixType> void initMatrix_identity(MatrixType& mat) __attribute__((noinline));
+template<typename MatrixType> void initMatrix_identity(MatrixType& mat)
+{
+ mat.setIdentity();
+}
+
+#ifndef __INTEL_COMPILER
+#define DISABLE_SSE_EXCEPTIONS() { \
+ int aux; \
+ asm( \
+ "stmxcsr %[aux] \n\t" \
+ "orl $32832, %[aux] \n\t" \
+ "ldmxcsr %[aux] \n\t" \
+ : : [aux] "m" (aux)); \
+}
+#else
+#define DISABLE_SSE_EXCEPTIONS()
+#endif
+
+#ifdef BENCH_GMM
+#include <gmm/gmm.h>
+template <typename EigenMatrixType, typename GmmMatrixType>
+void eiToGmm(const EigenMatrixType& src, GmmMatrixType& dst)
+{
+ dst.resize(src.rows(),src.cols());
+ for (int j=0; j<src.cols(); ++j)
+ for (int i=0; i<src.rows(); ++i)
+ dst(i,j) = src.coeff(i,j);
+}
+#endif
+
+
+#ifdef BENCH_GSL
+#include <gsl/gsl_matrix.h>
+#include <gsl/gsl_linalg.h>
+#include <gsl/gsl_eigen.h>
+template <typename EigenMatrixType>
+void eiToGsl(const EigenMatrixType& src, gsl_matrix** dst)
+{
+ for (int j=0; j<src.cols(); ++j)
+ for (int i=0; i<src.rows(); ++i)
+ gsl_matrix_set(*dst, i, j, src.coeff(i,j));
+}
+#endif
+
+#ifdef BENCH_UBLAS
+#include <boost/numeric/ublas/matrix.hpp>
+#include <boost/numeric/ublas/vector.hpp>
+template <typename EigenMatrixType, typename UblasMatrixType>
+void eiToUblas(const EigenMatrixType& src, UblasMatrixType& dst)
+{
+ dst.resize(src.rows(),src.cols());
+ for (int j=0; j<src.cols(); ++j)
+ for (int i=0; i<src.rows(); ++i)
+ dst(i,j) = src.coeff(i,j);
+}
+template <typename EigenType, typename UblasType>
+void eiToUblasVec(const EigenType& src, UblasType& dst)
+{
+ dst.resize(src.size());
+ for (int j=0; j<src.size(); ++j)
+ dst[j] = src.coeff(j);
+}
+#endif
+
+#endif // EIGEN_BENCH_UTIL_H
diff --git a/bench/README.txt b/bench/README.txt
new file mode 100644
index 000000000..39831ae8a
--- /dev/null
+++ b/bench/README.txt
@@ -0,0 +1,55 @@
+
+This folder contains a couple of benchmark utities and Eigen benchmarks.
+
+****************************
+* bench_multi_compilers.sh *
+****************************
+
+This script allows to run a benchmark on a set of different compilers/compiler options.
+It takes two arguments:
+ - a file defining the list of the compilers with their options
+ - the .cpp file of the benchmark
+
+Examples:
+
+$ ./bench_multi_compilers.sh basicbench.cxxlist basicbenchmark.cpp
+
+ g++-4.1 -O3 -DNDEBUG -finline-limit=10000
+ 3d-3x3 / 4d-4x4 / Xd-4x4 / Xd-20x20 /
+ 0.271102 0.131416 0.422322 0.198633
+ 0.201658 0.102436 0.397566 0.207282
+
+ g++-4.2 -O3 -DNDEBUG -finline-limit=10000
+ 3d-3x3 / 4d-4x4 / Xd-4x4 / Xd-20x20 /
+ 0.107805 0.0890579 0.30265 0.161843
+ 0.127157 0.0712581 0.278341 0.191029
+
+ g++-4.3 -O3 -DNDEBUG -finline-limit=10000
+ 3d-3x3 / 4d-4x4 / Xd-4x4 / Xd-20x20 /
+ 0.134318 0.105291 0.3704 0.180966
+ 0.137703 0.0732472 0.31225 0.202204
+
+ icpc -fast -DNDEBUG -fno-exceptions -no-inline-max-size
+ 3d-3x3 / 4d-4x4 / Xd-4x4 / Xd-20x20 /
+ 0.226145 0.0941319 0.371873 0.159433
+ 0.109302 0.0837538 0.328102 0.173891
+
+
+$ ./bench_multi_compilers.sh ompbench.cxxlist ompbenchmark.cpp
+
+ g++-4.2 -O3 -DNDEBUG -finline-limit=10000 -fopenmp
+ double, fixed-size 4x4: 0.00165105s 0.0778739s
+ double, 32x32: 0.0654769s 0.075289s => x0.869674 (2)
+ double, 128x128: 0.054148s 0.0419669s => x1.29025 (2)
+ double, 512x512: 0.913799s 0.428533s => x2.13239 (2)
+ double, 1024x1024: 14.5972s 9.3542s => x1.5605 (2)
+
+ icpc -fast -DNDEBUG -fno-exceptions -no-inline-max-size -openmp
+ double, fixed-size 4x4: 0.000589848s 0.019949s
+ double, 32x32: 0.0682781s 0.0449722s => x1.51823 (2)
+ double, 128x128: 0.0547509s 0.0435519s => x1.25714 (2)
+ double, 512x512: 0.829436s 0.424438s => x1.9542 (2)
+ double, 1024x1024: 14.5243s 10.7735s => x1.34815 (2)
+
+
+
diff --git a/bench/basicbench.cxxlist b/bench/basicbench.cxxlist
new file mode 100644
index 000000000..a8ab34e0d
--- /dev/null
+++ b/bench/basicbench.cxxlist
@@ -0,0 +1,28 @@
+#!/bin/bash
+
+# CLIST[((g++))]="g++-3.4 -O3 -DNDEBUG"
+# CLIST[((g++))]="g++-3.4 -O3 -DNDEBUG -finline-limit=20000"
+
+# CLIST[((g++))]="g++-4.1 -O3 -DNDEBUG"
+#CLIST[((g++))]="g++-4.1 -O3 -DNDEBUG -finline-limit=20000"
+
+# CLIST[((g++))]="g++-4.2 -O3 -DNDEBUG"
+#CLIST[((g++))]="g++-4.2 -O3 -DNDEBUG -finline-limit=20000"
+# CLIST[((g++))]="g++-4.2 -O3 -DNDEBUG -finline-limit=20000 -fprofile-generate"
+# CLIST[((g++))]="g++-4.2 -O3 -DNDEBUG -finline-limit=20000 -fprofile-use"
+
+# CLIST[((g++))]="g++-4.3 -O3 -DNDEBUG"
+#CLIST[((g++))]="g++-4.3 -O3 -DNDEBUG -finline-limit=20000"
+# CLIST[((g++))]="g++-4.3 -O3 -DNDEBUG -finline-limit=20000 -fprofile-generate"
+# CLIST[((g++))]="g++-4.3 -O3 -DNDEBUG -finline-limit=20000 -fprofile-use"
+
+# CLIST[((g++))]="icpc -fast -DNDEBUG -fno-exceptions -no-inline-max-size -prof-genx"
+# CLIST[((g++))]="icpc -fast -DNDEBUG -fno-exceptions -no-inline-max-size -prof-use"
+
+#CLIST[((g++))]="/opt/intel/Compiler/11.1/072/bin/intel64/icpc -fast -DNDEBUG -fno-exceptions -no-inline-max-size -lrt"
+CLIST[((g++))]="/home/orzel/svn/llvm/Release/bin/clang++ -O3 -DNDEBUG -DEIGEN_DONT_VECTORIZE -lrt"
+CLIST[((g++))]="/home/orzel/svn/llvm/Release/bin/clang++ -O3 -DNDEBUG -lrt"
+CLIST[((g++))]="g++-4.4.4 -O3 -DNDEBUG -DEIGEN_DONT_VECTORIZE -lrt"
+CLIST[((g++))]="g++-4.4.4 -O3 -DNDEBUG -lrt"
+CLIST[((g++))]="g++-4.5.0 -O3 -DNDEBUG -DEIGEN_DONT_VECTORIZE -lrt"
+CLIST[((g++))]="g++-4.5.0 -O3 -DNDEBUG -lrt"
diff --git a/bench/basicbenchmark.cpp b/bench/basicbenchmark.cpp
new file mode 100644
index 000000000..a26ea853f
--- /dev/null
+++ b/bench/basicbenchmark.cpp
@@ -0,0 +1,35 @@
+
+#include <iostream>
+#include "BenchUtil.h"
+#include "basicbenchmark.h"
+
+int main(int argc, char *argv[])
+{
+ DISABLE_SSE_EXCEPTIONS();
+
+ // this is the list of matrix type and size we want to bench:
+ // ((suffix) (matrix size) (number of iterations))
+ #define MODES ((3d)(3)(4000000)) ((4d)(4)(1000000)) ((Xd)(4)(1000000)) ((Xd)(20)(10000))
+// #define MODES ((Xd)(20)(10000))
+
+ #define _GENERATE_HEADER(R,ARG,EL) << BOOST_PP_STRINGIZE(BOOST_PP_SEQ_HEAD(EL)) << "-" \
+ << BOOST_PP_STRINGIZE(BOOST_PP_SEQ_ELEM(1,EL)) << "x" \
+ << BOOST_PP_STRINGIZE(BOOST_PP_SEQ_ELEM(1,EL)) << " / "
+
+ std::cout BOOST_PP_SEQ_FOR_EACH(_GENERATE_HEADER, ~, MODES ) << endl;
+
+ const int tries = 10;
+
+ #define _RUN_BENCH(R,ARG,EL) \
+ std::cout << ARG( \
+ BOOST_PP_CAT(Matrix, BOOST_PP_SEQ_HEAD(EL)) (\
+ BOOST_PP_SEQ_ELEM(1,EL),BOOST_PP_SEQ_ELEM(1,EL)), BOOST_PP_SEQ_ELEM(2,EL), tries) \
+ << " ";
+
+ BOOST_PP_SEQ_FOR_EACH(_RUN_BENCH, benchBasic<LazyEval>, MODES );
+ std::cout << endl;
+ BOOST_PP_SEQ_FOR_EACH(_RUN_BENCH, benchBasic<EarlyEval>, MODES );
+ std::cout << endl;
+
+ return 0;
+}
diff --git a/bench/basicbenchmark.h b/bench/basicbenchmark.h
new file mode 100644
index 000000000..3fdc35732
--- /dev/null
+++ b/bench/basicbenchmark.h
@@ -0,0 +1,63 @@
+
+#ifndef EIGEN_BENCH_BASICBENCH_H
+#define EIGEN_BENCH_BASICBENCH_H
+
+enum {LazyEval, EarlyEval, OmpEval};
+
+template<int Mode, typename MatrixType>
+void benchBasic_loop(const MatrixType& I, MatrixType& m, int iterations) __attribute__((noinline));
+
+template<int Mode, typename MatrixType>
+void benchBasic_loop(const MatrixType& I, MatrixType& m, int iterations)
+{
+ for(int a = 0; a < iterations; a++)
+ {
+ if (Mode==LazyEval)
+ {
+ asm("#begin_bench_loop LazyEval");
+ if (MatrixType::SizeAtCompileTime!=Eigen::Dynamic) asm("#fixedsize");
+ m = (I + 0.00005 * (m + m.lazy() * m)).eval();
+ }
+ else if (Mode==OmpEval)
+ {
+ asm("#begin_bench_loop OmpEval");
+ if (MatrixType::SizeAtCompileTime!=Eigen::Dynamic) asm("#fixedsize");
+ m = (I + 0.00005 * (m + m.lazy() * m)).evalOMP();
+ }
+ else
+ {
+ asm("#begin_bench_loop EarlyEval");
+ if (MatrixType::SizeAtCompileTime!=Eigen::Dynamic) asm("#fixedsize");
+ m = I + 0.00005 * (m + m * m);
+ }
+ asm("#end_bench_loop");
+ }
+}
+
+template<int Mode, typename MatrixType>
+double benchBasic(const MatrixType& mat, int size, int tries) __attribute__((noinline));
+
+template<int Mode, typename MatrixType>
+double benchBasic(const MatrixType& mat, int iterations, int tries)
+{
+ const int rows = mat.rows();
+ const int cols = mat.cols();
+
+ MatrixType I(rows,cols);
+ MatrixType m(rows,cols);
+
+ initMatrix_identity(I);
+
+ Eigen::BenchTimer timer;
+ for(uint t=0; t<tries; ++t)
+ {
+ initMatrix_random(m);
+ timer.start();
+ benchBasic_loop<Mode>(I, m, iterations);
+ timer.stop();
+ cerr << m;
+ }
+ return timer.value();
+};
+
+#endif // EIGEN_BENCH_BASICBENCH_H
diff --git a/bench/benchBlasGemm.cpp b/bench/benchBlasGemm.cpp
new file mode 100644
index 000000000..cb086a555
--- /dev/null
+++ b/bench/benchBlasGemm.cpp
@@ -0,0 +1,219 @@
+// g++ -O3 -DNDEBUG -I.. -L /usr/lib64/atlas/ benchBlasGemm.cpp -o benchBlasGemm -lrt -lcblas
+// possible options:
+// -DEIGEN_DONT_VECTORIZE
+// -msse2
+
+// #define EIGEN_DEFAULT_TO_ROW_MAJOR
+#define _FLOAT
+
+#include <iostream>
+
+#include <Eigen/Core>
+#include "BenchTimer.h"
+
+// include the BLAS headers
+extern "C" {
+#include <cblas.h>
+}
+#include <string>
+
+#ifdef _FLOAT
+typedef float Scalar;
+#define CBLAS_GEMM cblas_sgemm
+#else
+typedef double Scalar;
+#define CBLAS_GEMM cblas_dgemm
+#endif
+
+
+typedef Eigen::Matrix<Scalar,Eigen::Dynamic,Eigen::Dynamic> MyMatrix;
+void bench_eigengemm(MyMatrix& mc, const MyMatrix& ma, const MyMatrix& mb, int nbloops);
+void check_product(int M, int N, int K);
+void check_product(void);
+
+int main(int argc, char *argv[])
+{
+ // disable SSE exceptions
+ #ifdef __GNUC__
+ {
+ int aux;
+ asm(
+ "stmxcsr %[aux] \n\t"
+ "orl $32832, %[aux] \n\t"
+ "ldmxcsr %[aux] \n\t"
+ : : [aux] "m" (aux));
+ }
+ #endif
+
+ int nbtries=1, nbloops=1, M, N, K;
+
+ if (argc==2)
+ {
+ if (std::string(argv[1])=="check")
+ check_product();
+ else
+ M = N = K = atoi(argv[1]);
+ }
+ else if ((argc==3) && (std::string(argv[1])=="auto"))
+ {
+ M = N = K = atoi(argv[2]);
+ nbloops = 1000000000/(M*M*M);
+ if (nbloops<1)
+ nbloops = 1;
+ nbtries = 6;
+ }
+ else if (argc==4)
+ {
+ M = N = K = atoi(argv[1]);
+ nbloops = atoi(argv[2]);
+ nbtries = atoi(argv[3]);
+ }
+ else if (argc==6)
+ {
+ M = atoi(argv[1]);
+ N = atoi(argv[2]);
+ K = atoi(argv[3]);
+ nbloops = atoi(argv[4]);
+ nbtries = atoi(argv[5]);
+ }
+ else
+ {
+ std::cout << "Usage: " << argv[0] << " size \n";
+ std::cout << "Usage: " << argv[0] << " auto size\n";
+ std::cout << "Usage: " << argv[0] << " size nbloops nbtries\n";
+ std::cout << "Usage: " << argv[0] << " M N K nbloops nbtries\n";
+ std::cout << "Usage: " << argv[0] << " check\n";
+ std::cout << "Options:\n";
+ std::cout << " size unique size of the 2 matrices (integer)\n";
+ std::cout << " auto automatically set the number of repetitions and tries\n";
+ std::cout << " nbloops number of times the GEMM routines is executed\n";
+ std::cout << " nbtries number of times the loop is benched (return the best try)\n";
+ std::cout << " M N K sizes of the matrices: MxN = MxK * KxN (integers)\n";
+ std::cout << " check check eigen product using cblas as a reference\n";
+ exit(1);
+ }
+
+ double nbmad = double(M) * double(N) * double(K) * double(nbloops);
+
+ if (!(std::string(argv[1])=="auto"))
+ std::cout << M << " x " << N << " x " << K << "\n";
+
+ Scalar alpha, beta;
+ MyMatrix ma(M,K), mb(K,N), mc(M,N);
+ ma = MyMatrix::Random(M,K);
+ mb = MyMatrix::Random(K,N);
+ mc = MyMatrix::Random(M,N);
+
+ Eigen::BenchTimer timer;
+
+ // we simply compute c += a*b, so:
+ alpha = 1;
+ beta = 1;
+
+ // bench cblas
+ // ROWS_A, COLS_B, COLS_A, 1.0, A, COLS_A, B, COLS_B, 0.0, C, COLS_B);
+ if (!(std::string(argv[1])=="auto"))
+ {
+ timer.reset();
+ for (uint k=0 ; k<nbtries ; ++k)
+ {
+ timer.start();
+ for (uint j=0 ; j<nbloops ; ++j)
+ #ifdef EIGEN_DEFAULT_TO_ROW_MAJOR
+ CBLAS_GEMM(CblasRowMajor, CblasNoTrans, CblasNoTrans, M, N, K, alpha, ma.data(), K, mb.data(), N, beta, mc.data(), N);
+ #else
+ CBLAS_GEMM(CblasColMajor, CblasNoTrans, CblasNoTrans, M, N, K, alpha, ma.data(), M, mb.data(), K, beta, mc.data(), M);
+ #endif
+ timer.stop();
+ }
+ if (!(std::string(argv[1])=="auto"))
+ std::cout << "cblas: " << timer.value() << " (" << 1e-3*floor(1e-6*nbmad/timer.value()) << " GFlops/s)\n";
+ else
+ std::cout << M << " : " << timer.value() << " ; " << 1e-3*floor(1e-6*nbmad/timer.value()) << "\n";
+ }
+
+ // clear
+ ma = MyMatrix::Random(M,K);
+ mb = MyMatrix::Random(K,N);
+ mc = MyMatrix::Random(M,N);
+
+ // eigen
+// if (!(std::string(argv[1])=="auto"))
+ {
+ timer.reset();
+ for (uint k=0 ; k<nbtries ; ++k)
+ {
+ timer.start();
+ bench_eigengemm(mc, ma, mb, nbloops);
+ timer.stop();
+ }
+ if (!(std::string(argv[1])=="auto"))
+ std::cout << "eigen : " << timer.value() << " (" << 1e-3*floor(1e-6*nbmad/timer.value()) << " GFlops/s)\n";
+ else
+ std::cout << M << " : " << timer.value() << " ; " << 1e-3*floor(1e-6*nbmad/timer.value()) << "\n";
+ }
+
+ std::cout << "l1: " << Eigen::l1CacheSize() << std::endl;
+ std::cout << "l2: " << Eigen::l2CacheSize() << std::endl;
+
+
+ return 0;
+}
+
+using namespace Eigen;
+
+void bench_eigengemm(MyMatrix& mc, const MyMatrix& ma, const MyMatrix& mb, int nbloops)
+{
+ for (uint j=0 ; j<nbloops ; ++j)
+ mc.noalias() += ma * mb;
+}
+
+#define MYVERIFY(A,M) if (!(A)) { \
+ std::cout << "FAIL: " << M << "\n"; \
+ }
+void check_product(int M, int N, int K)
+{
+ MyMatrix ma(M,K), mb(K,N), mc(M,N), maT(K,M), mbT(N,K), meigen(M,N), mref(M,N);
+ ma = MyMatrix::Random(M,K);
+ mb = MyMatrix::Random(K,N);
+ maT = ma.transpose();
+ mbT = mb.transpose();
+ mc = MyMatrix::Random(M,N);
+
+ MyMatrix::Scalar eps = 1e-4;
+
+ meigen = mref = mc;
+ CBLAS_GEMM(CblasColMajor, CblasNoTrans, CblasNoTrans, M, N, K, 1, ma.data(), M, mb.data(), K, 1, mref.data(), M);
+ meigen += ma * mb;
+ MYVERIFY(meigen.isApprox(mref, eps),". * .");
+
+ meigen = mref = mc;
+ CBLAS_GEMM(CblasColMajor, CblasTrans, CblasNoTrans, M, N, K, 1, maT.data(), K, mb.data(), K, 1, mref.data(), M);
+ meigen += maT.transpose() * mb;
+ MYVERIFY(meigen.isApprox(mref, eps),"T * .");
+
+ meigen = mref = mc;
+ CBLAS_GEMM(CblasColMajor, CblasTrans, CblasTrans, M, N, K, 1, maT.data(), K, mbT.data(), N, 1, mref.data(), M);
+ meigen += (maT.transpose()) * (mbT.transpose());
+ MYVERIFY(meigen.isApprox(mref, eps),"T * T");
+
+ meigen = mref = mc;
+ CBLAS_GEMM(CblasColMajor, CblasNoTrans, CblasTrans, M, N, K, 1, ma.data(), M, mbT.data(), N, 1, mref.data(), M);
+ meigen += ma * mbT.transpose();
+ MYVERIFY(meigen.isApprox(mref, eps),". * T");
+}
+
+void check_product(void)
+{
+ int M, N, K;
+ for (uint i=0; i<1000; ++i)
+ {
+ M = internal::random<int>(1,64);
+ N = internal::random<int>(1,768);
+ K = internal::random<int>(1,768);
+ M = (0 + M) * 1;
+ std::cout << M << " x " << N << " x " << K << "\n";
+ check_product(M, N, K);
+ }
+}
+
diff --git a/bench/benchCholesky.cpp b/bench/benchCholesky.cpp
new file mode 100644
index 000000000..42b3e1285
--- /dev/null
+++ b/bench/benchCholesky.cpp
@@ -0,0 +1,142 @@
+
+// g++ -DNDEBUG -O3 -I.. benchLLT.cpp -o benchLLT && ./benchLLT
+// options:
+// -DBENCH_GSL -lgsl /usr/lib/libcblas.so.3
+// -DEIGEN_DONT_VECTORIZE
+// -msse2
+// -DREPEAT=100
+// -DTRIES=10
+// -DSCALAR=double
+
+#include <iostream>
+
+#include <Eigen/Core>
+#include <Eigen/Cholesky>
+#include <bench/BenchUtil.h>
+using namespace Eigen;
+
+#ifndef REPEAT
+#define REPEAT 10000
+#endif
+
+#ifndef TRIES
+#define TRIES 10
+#endif
+
+typedef float Scalar;
+
+template <typename MatrixType>
+__attribute__ ((noinline)) void benchLLT(const MatrixType& m)
+{
+ int rows = m.rows();
+ int cols = m.cols();
+
+ int cost = 0;
+ for (int j=0; j<rows; ++j)
+ {
+ int r = std::max(rows - j -1,0);
+ cost += 2*(r*j+r+j);
+ }
+
+ int repeats = (REPEAT*1000)/(rows*rows);
+
+ typedef typename MatrixType::Scalar Scalar;
+ typedef Matrix<Scalar, MatrixType::RowsAtCompileTime, MatrixType::RowsAtCompileTime> SquareMatrixType;
+
+ MatrixType a = MatrixType::Random(rows,cols);
+ SquareMatrixType covMat = a * a.adjoint();
+
+ BenchTimer timerNoSqrt, timerSqrt;
+
+ Scalar acc = 0;
+ int r = internal::random<int>(0,covMat.rows()-1);
+ int c = internal::random<int>(0,covMat.cols()-1);
+ for (int t=0; t<TRIES; ++t)
+ {
+ timerNoSqrt.start();
+ for (int k=0; k<repeats; ++k)
+ {
+ LDLT<SquareMatrixType> cholnosqrt(covMat);
+ acc += cholnosqrt.matrixL().coeff(r,c);
+ }
+ timerNoSqrt.stop();
+ }
+
+ for (int t=0; t<TRIES; ++t)
+ {
+ timerSqrt.start();
+ for (int k=0; k<repeats; ++k)
+ {
+ LLT<SquareMatrixType> chol(covMat);
+ acc += chol.matrixL().coeff(r,c);
+ }
+ timerSqrt.stop();
+ }
+
+ if (MatrixType::RowsAtCompileTime==Dynamic)
+ std::cout << "dyn ";
+ else
+ std::cout << "fixed ";
+ std::cout << covMat.rows() << " \t"
+ << (timerNoSqrt.value() * REPEAT) / repeats << "s "
+ << "(" << 1e-6 * cost*repeats/timerNoSqrt.value() << " MFLOPS)\t"
+ << (timerSqrt.value() * REPEAT) / repeats << "s "
+ << "(" << 1e-6 * cost*repeats/timerSqrt.value() << " MFLOPS)\n";
+
+
+ #ifdef BENCH_GSL
+ if (MatrixType::RowsAtCompileTime==Dynamic)
+ {
+ timerSqrt.reset();
+
+ gsl_matrix* gslCovMat = gsl_matrix_alloc(covMat.rows(),covMat.cols());
+ gsl_matrix* gslCopy = gsl_matrix_alloc(covMat.rows(),covMat.cols());
+
+ eiToGsl(covMat, &gslCovMat);
+ for (int t=0; t<TRIES; ++t)
+ {
+ timerSqrt.start();
+ for (int k=0; k<repeats; ++k)
+ {
+ gsl_matrix_memcpy(gslCopy,gslCovMat);
+ gsl_linalg_cholesky_decomp(gslCopy);
+ acc += gsl_matrix_get(gslCopy,r,c);
+ }
+ timerSqrt.stop();
+ }
+
+ std::cout << " | \t"
+ << timerSqrt.value() * REPEAT / repeats << "s";
+
+ gsl_matrix_free(gslCovMat);
+ }
+ #endif
+ std::cout << "\n";
+ // make sure the compiler does not optimize too much
+ if (acc==123)
+ std::cout << acc;
+}
+
+int main(int argc, char* argv[])
+{
+ const int dynsizes[] = {4,6,8,16,24,32,49,64,128,256,512,900,0};
+ std::cout << "size no sqrt standard";
+// #ifdef BENCH_GSL
+// std::cout << " GSL (standard + double + ATLAS) ";
+// #endif
+ std::cout << "\n";
+ for (uint i=0; dynsizes[i]>0; ++i)
+ benchLLT(Matrix<Scalar,Dynamic,Dynamic>(dynsizes[i],dynsizes[i]));
+
+ benchLLT(Matrix<Scalar,2,2>());
+ benchLLT(Matrix<Scalar,3,3>());
+ benchLLT(Matrix<Scalar,4,4>());
+ benchLLT(Matrix<Scalar,5,5>());
+ benchLLT(Matrix<Scalar,6,6>());
+ benchLLT(Matrix<Scalar,7,7>());
+ benchLLT(Matrix<Scalar,8,8>());
+ benchLLT(Matrix<Scalar,12,12>());
+ benchLLT(Matrix<Scalar,16,16>());
+ return 0;
+}
+
diff --git a/bench/benchEigenSolver.cpp b/bench/benchEigenSolver.cpp
new file mode 100644
index 000000000..dd78c7e01
--- /dev/null
+++ b/bench/benchEigenSolver.cpp
@@ -0,0 +1,212 @@
+
+// g++ -DNDEBUG -O3 -I.. benchEigenSolver.cpp -o benchEigenSolver && ./benchEigenSolver
+// options:
+// -DBENCH_GMM
+// -DBENCH_GSL -lgsl /usr/lib/libcblas.so.3
+// -DEIGEN_DONT_VECTORIZE
+// -msse2
+// -DREPEAT=100
+// -DTRIES=10
+// -DSCALAR=double
+
+#include <iostream>
+
+#include <Eigen/Core>
+#include <Eigen/QR>
+#include <bench/BenchUtil.h>
+using namespace Eigen;
+
+#ifndef REPEAT
+#define REPEAT 1000
+#endif
+
+#ifndef TRIES
+#define TRIES 4
+#endif
+
+#ifndef SCALAR
+#define SCALAR float
+#endif
+
+typedef SCALAR Scalar;
+
+template <typename MatrixType>
+__attribute__ ((noinline)) void benchEigenSolver(const MatrixType& m)
+{
+ int rows = m.rows();
+ int cols = m.cols();
+
+ int stdRepeats = std::max(1,int((REPEAT*1000)/(rows*rows*sqrt(rows))));
+ int saRepeats = stdRepeats * 4;
+
+ typedef typename MatrixType::Scalar Scalar;
+ typedef Matrix<Scalar, MatrixType::RowsAtCompileTime, MatrixType::RowsAtCompileTime> SquareMatrixType;
+
+ MatrixType a = MatrixType::Random(rows,cols);
+ SquareMatrixType covMat = a * a.adjoint();
+
+ BenchTimer timerSa, timerStd;
+
+ Scalar acc = 0;
+ int r = internal::random<int>(0,covMat.rows()-1);
+ int c = internal::random<int>(0,covMat.cols()-1);
+ {
+ SelfAdjointEigenSolver<SquareMatrixType> ei(covMat);
+ for (int t=0; t<TRIES; ++t)
+ {
+ timerSa.start();
+ for (int k=0; k<saRepeats; ++k)
+ {
+ ei.compute(covMat);
+ acc += ei.eigenvectors().coeff(r,c);
+ }
+ timerSa.stop();
+ }
+ }
+
+ {
+ EigenSolver<SquareMatrixType> ei(covMat);
+ for (int t=0; t<TRIES; ++t)
+ {
+ timerStd.start();
+ for (int k=0; k<stdRepeats; ++k)
+ {
+ ei.compute(covMat);
+ acc += ei.eigenvectors().coeff(r,c);
+ }
+ timerStd.stop();
+ }
+ }
+
+ if (MatrixType::RowsAtCompileTime==Dynamic)
+ std::cout << "dyn ";
+ else
+ std::cout << "fixed ";
+ std::cout << covMat.rows() << " \t"
+ << timerSa.value() * REPEAT / saRepeats << "s \t"
+ << timerStd.value() * REPEAT / stdRepeats << "s";
+
+ #ifdef BENCH_GMM
+ if (MatrixType::RowsAtCompileTime==Dynamic)
+ {
+ timerSa.reset();
+ timerStd.reset();
+
+ gmm::dense_matrix<Scalar> gmmCovMat(covMat.rows(),covMat.cols());
+ gmm::dense_matrix<Scalar> eigvect(covMat.rows(),covMat.cols());
+ std::vector<Scalar> eigval(covMat.rows());
+ eiToGmm(covMat, gmmCovMat);
+ for (int t=0; t<TRIES; ++t)
+ {
+ timerSa.start();
+ for (int k=0; k<saRepeats; ++k)
+ {
+ gmm::symmetric_qr_algorithm(gmmCovMat, eigval, eigvect);
+ acc += eigvect(r,c);
+ }
+ timerSa.stop();
+ }
+ // the non-selfadjoint solver does not compute the eigen vectors
+// for (int t=0; t<TRIES; ++t)
+// {
+// timerStd.start();
+// for (int k=0; k<stdRepeats; ++k)
+// {
+// gmm::implicit_qr_algorithm(gmmCovMat, eigval, eigvect);
+// acc += eigvect(r,c);
+// }
+// timerStd.stop();
+// }
+
+ std::cout << " | \t"
+ << timerSa.value() * REPEAT / saRepeats << "s"
+ << /*timerStd.value() * REPEAT / stdRepeats << "s"*/ " na ";
+ }
+ #endif
+
+ #ifdef BENCH_GSL
+ if (MatrixType::RowsAtCompileTime==Dynamic)
+ {
+ timerSa.reset();
+ timerStd.reset();
+
+ gsl_matrix* gslCovMat = gsl_matrix_alloc(covMat.rows(),covMat.cols());
+ gsl_matrix* gslCopy = gsl_matrix_alloc(covMat.rows(),covMat.cols());
+ gsl_matrix* eigvect = gsl_matrix_alloc(covMat.rows(),covMat.cols());
+ gsl_vector* eigval = gsl_vector_alloc(covMat.rows());
+ gsl_eigen_symmv_workspace* eisymm = gsl_eigen_symmv_alloc(covMat.rows());
+
+ gsl_matrix_complex* eigvectz = gsl_matrix_complex_alloc(covMat.rows(),covMat.cols());
+ gsl_vector_complex* eigvalz = gsl_vector_complex_alloc(covMat.rows());
+ gsl_eigen_nonsymmv_workspace* einonsymm = gsl_eigen_nonsymmv_alloc(covMat.rows());
+
+ eiToGsl(covMat, &gslCovMat);
+ for (int t=0; t<TRIES; ++t)
+ {
+ timerSa.start();
+ for (int k=0; k<saRepeats; ++k)
+ {
+ gsl_matrix_memcpy(gslCopy,gslCovMat);
+ gsl_eigen_symmv(gslCopy, eigval, eigvect, eisymm);
+ acc += gsl_matrix_get(eigvect,r,c);
+ }
+ timerSa.stop();
+ }
+ for (int t=0; t<TRIES; ++t)
+ {
+ timerStd.start();
+ for (int k=0; k<stdRepeats; ++k)
+ {
+ gsl_matrix_memcpy(gslCopy,gslCovMat);
+ gsl_eigen_nonsymmv(gslCopy, eigvalz, eigvectz, einonsymm);
+ acc += GSL_REAL(gsl_matrix_complex_get(eigvectz,r,c));
+ }
+ timerStd.stop();
+ }
+
+ std::cout << " | \t"
+ << timerSa.value() * REPEAT / saRepeats << "s \t"
+ << timerStd.value() * REPEAT / stdRepeats << "s";
+
+ gsl_matrix_free(gslCovMat);
+ gsl_vector_free(gslCopy);
+ gsl_matrix_free(eigvect);
+ gsl_vector_free(eigval);
+ gsl_matrix_complex_free(eigvectz);
+ gsl_vector_complex_free(eigvalz);
+ gsl_eigen_symmv_free(eisymm);
+ gsl_eigen_nonsymmv_free(einonsymm);
+ }
+ #endif
+
+ std::cout << "\n";
+
+ // make sure the compiler does not optimize too much
+ if (acc==123)
+ std::cout << acc;
+}
+
+int main(int argc, char* argv[])
+{
+ const int dynsizes[] = {4,6,8,12,16,24,32,64,128,256,512,0};
+ std::cout << "size selfadjoint generic";
+ #ifdef BENCH_GMM
+ std::cout << " GMM++ ";
+ #endif
+ #ifdef BENCH_GSL
+ std::cout << " GSL (double + ATLAS) ";
+ #endif
+ std::cout << "\n";
+ for (uint i=0; dynsizes[i]>0; ++i)
+ benchEigenSolver(Matrix<Scalar,Dynamic,Dynamic>(dynsizes[i],dynsizes[i]));
+
+ benchEigenSolver(Matrix<Scalar,2,2>());
+ benchEigenSolver(Matrix<Scalar,3,3>());
+ benchEigenSolver(Matrix<Scalar,4,4>());
+ benchEigenSolver(Matrix<Scalar,6,6>());
+ benchEigenSolver(Matrix<Scalar,8,8>());
+ benchEigenSolver(Matrix<Scalar,12,12>());
+ benchEigenSolver(Matrix<Scalar,16,16>());
+ return 0;
+}
+
diff --git a/bench/benchFFT.cpp b/bench/benchFFT.cpp
new file mode 100644
index 000000000..3eb1a1ac0
--- /dev/null
+++ b/bench/benchFFT.cpp
@@ -0,0 +1,115 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra.
+//
+// Copyright (C) 2009 Mark Borgerding mark a borgerding net
+//
+// This Source Code Form is subject to the terms of the Mozilla
+// Public License v. 2.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 <iostream>
+
+#include <bench/BenchUtil.h>
+#include <complex>
+#include <vector>
+#include <Eigen/Core>
+
+#include <unsupported/Eigen/FFT>
+
+using namespace Eigen;
+using namespace std;
+
+
+template <typename T>
+string nameof();
+
+template <> string nameof<float>() {return "float";}
+template <> string nameof<double>() {return "double";}
+template <> string nameof<long double>() {return "long double";}
+
+#ifndef TYPE
+#define TYPE float
+#endif
+
+#ifndef NFFT
+#define NFFT 1024
+#endif
+#ifndef NDATA
+#define NDATA 1000000
+#endif
+
+using namespace Eigen;
+
+template <typename T>
+void bench(int nfft,bool fwd,bool unscaled=false, bool halfspec=false)
+{
+ typedef typename NumTraits<T>::Real Scalar;
+ typedef typename std::complex<Scalar> Complex;
+ int nits = NDATA/nfft;
+ vector<T> inbuf(nfft);
+ vector<Complex > outbuf(nfft);
+ FFT< Scalar > fft;
+
+ if (unscaled) {
+ fft.SetFlag(fft.Unscaled);
+ cout << "unscaled ";
+ }
+ if (halfspec) {
+ fft.SetFlag(fft.HalfSpectrum);
+ cout << "halfspec ";
+ }
+
+
+ std::fill(inbuf.begin(),inbuf.end(),0);
+ fft.fwd( outbuf , inbuf);
+
+ BenchTimer timer;
+ timer.reset();
+ for (int k=0;k<8;++k) {
+ timer.start();
+ if (fwd)
+ for(int i = 0; i < nits; i++)
+ fft.fwd( outbuf , inbuf);
+ else
+ for(int i = 0; i < nits; i++)
+ fft.inv(inbuf,outbuf);
+ timer.stop();
+ }
+
+ cout << nameof<Scalar>() << " ";
+ double mflops = 5.*nfft*log2((double)nfft) / (1e6 * timer.value() / (double)nits );
+ if ( NumTraits<T>::IsComplex ) {
+ cout << "complex";
+ }else{
+ cout << "real ";
+ mflops /= 2;
+ }
+
+
+ if (fwd)
+ cout << " fwd";
+ else
+ cout << " inv";
+
+ cout << " NFFT=" << nfft << " " << (double(1e-6*nfft*nits)/timer.value()) << " MS/s " << mflops << "MFLOPS\n";
+}
+
+int main(int argc,char ** argv)
+{
+ bench<complex<float> >(NFFT,true);
+ bench<complex<float> >(NFFT,false);
+ bench<float>(NFFT,true);
+ bench<float>(NFFT,false);
+ bench<float>(NFFT,false,true);
+ bench<float>(NFFT,false,true,true);
+
+ bench<complex<double> >(NFFT,true);
+ bench<complex<double> >(NFFT,false);
+ bench<double>(NFFT,true);
+ bench<double>(NFFT,false);
+ bench<complex<long double> >(NFFT,true);
+ bench<complex<long double> >(NFFT,false);
+ bench<long double>(NFFT,true);
+ bench<long double>(NFFT,false);
+ return 0;
+}
diff --git a/bench/benchVecAdd.cpp b/bench/benchVecAdd.cpp
new file mode 100644
index 000000000..ce8e1e911
--- /dev/null
+++ b/bench/benchVecAdd.cpp
@@ -0,0 +1,135 @@
+
+#include <iostream>
+#include <Eigen/Core>
+#include <bench/BenchTimer.h>
+using namespace Eigen;
+
+#ifndef SIZE
+#define SIZE 50
+#endif
+
+#ifndef REPEAT
+#define REPEAT 10000
+#endif
+
+typedef float Scalar;
+
+__attribute__ ((noinline)) void benchVec(Scalar* a, Scalar* b, Scalar* c, int size);
+__attribute__ ((noinline)) void benchVec(MatrixXf& a, MatrixXf& b, MatrixXf& c);
+__attribute__ ((noinline)) void benchVec(VectorXf& a, VectorXf& b, VectorXf& c);
+
+int main(int argc, char* argv[])
+{
+ int size = SIZE * 8;
+ int size2 = size * size;
+ Scalar* a = internal::aligned_new<Scalar>(size2);
+ Scalar* b = internal::aligned_new<Scalar>(size2+4)+1;
+ Scalar* c = internal::aligned_new<Scalar>(size2);
+
+ for (int i=0; i<size; ++i)
+ {
+ a[i] = b[i] = c[i] = 0;
+ }
+
+ BenchTimer timer;
+
+ timer.reset();
+ for (int k=0; k<10; ++k)
+ {
+ timer.start();
+ benchVec(a, b, c, size2);
+ timer.stop();
+ }
+ std::cout << timer.value() << "s " << (double(size2*REPEAT)/timer.value())/(1024.*1024.*1024.) << " GFlops\n";
+ return 0;
+ for (int innersize = size; innersize>2 ; --innersize)
+ {
+ if (size2%innersize==0)
+ {
+ int outersize = size2/innersize;
+ MatrixXf ma = Map<MatrixXf>(a, innersize, outersize );
+ MatrixXf mb = Map<MatrixXf>(b, innersize, outersize );
+ MatrixXf mc = Map<MatrixXf>(c, innersize, outersize );
+ timer.reset();
+ for (int k=0; k<3; ++k)
+ {
+ timer.start();
+ benchVec(ma, mb, mc);
+ timer.stop();
+ }
+ std::cout << innersize << " x " << outersize << " " << timer.value() << "s " << (double(size2*REPEAT)/timer.value())/(1024.*1024.*1024.) << " GFlops\n";
+ }
+ }
+
+ VectorXf va = Map<VectorXf>(a, size2);
+ VectorXf vb = Map<VectorXf>(b, size2);
+ VectorXf vc = Map<VectorXf>(c, size2);
+ timer.reset();
+ for (int k=0; k<3; ++k)
+ {
+ timer.start();
+ benchVec(va, vb, vc);
+ timer.stop();
+ }
+ std::cout << timer.value() << "s " << (double(size2*REPEAT)/timer.value())/(1024.*1024.*1024.) << " GFlops\n";
+
+ return 0;
+}
+
+void benchVec(MatrixXf& a, MatrixXf& b, MatrixXf& c)
+{
+ for (int k=0; k<REPEAT; ++k)
+ a = a + b;
+}
+
+void benchVec(VectorXf& a, VectorXf& b, VectorXf& c)
+{
+ for (int k=0; k<REPEAT; ++k)
+ a = a + b;
+}
+
+void benchVec(Scalar* a, Scalar* b, Scalar* c, int size)
+{
+ typedef internal::packet_traits<Scalar>::type PacketScalar;
+ const int PacketSize = internal::packet_traits<Scalar>::size;
+ PacketScalar a0, a1, a2, a3, b0, b1, b2, b3;
+ for (int k=0; k<REPEAT; ++k)
+ for (int i=0; i<size; i+=PacketSize*8)
+ {
+// a0 = internal::pload(&a[i]);
+// b0 = internal::pload(&b[i]);
+// a1 = internal::pload(&a[i+1*PacketSize]);
+// b1 = internal::pload(&b[i+1*PacketSize]);
+// a2 = internal::pload(&a[i+2*PacketSize]);
+// b2 = internal::pload(&b[i+2*PacketSize]);
+// a3 = internal::pload(&a[i+3*PacketSize]);
+// b3 = internal::pload(&b[i+3*PacketSize]);
+// internal::pstore(&a[i], internal::padd(a0, b0));
+// a0 = internal::pload(&a[i+4*PacketSize]);
+// b0 = internal::pload(&b[i+4*PacketSize]);
+//
+// internal::pstore(&a[i+1*PacketSize], internal::padd(a1, b1));
+// a1 = internal::pload(&a[i+5*PacketSize]);
+// b1 = internal::pload(&b[i+5*PacketSize]);
+//
+// internal::pstore(&a[i+2*PacketSize], internal::padd(a2, b2));
+// a2 = internal::pload(&a[i+6*PacketSize]);
+// b2 = internal::pload(&b[i+6*PacketSize]);
+//
+// internal::pstore(&a[i+3*PacketSize], internal::padd(a3, b3));
+// a3 = internal::pload(&a[i+7*PacketSize]);
+// b3 = internal::pload(&b[i+7*PacketSize]);
+//
+// internal::pstore(&a[i+4*PacketSize], internal::padd(a0, b0));
+// internal::pstore(&a[i+5*PacketSize], internal::padd(a1, b1));
+// internal::pstore(&a[i+6*PacketSize], internal::padd(a2, b2));
+// internal::pstore(&a[i+7*PacketSize], internal::padd(a3, b3));
+
+ internal::pstore(&a[i+2*PacketSize], internal::padd(internal::ploadu(&a[i+2*PacketSize]), internal::ploadu(&b[i+2*PacketSize])));
+ internal::pstore(&a[i+3*PacketSize], internal::padd(internal::ploadu(&a[i+3*PacketSize]), internal::ploadu(&b[i+3*PacketSize])));
+ internal::pstore(&a[i+4*PacketSize], internal::padd(internal::ploadu(&a[i+4*PacketSize]), internal::ploadu(&b[i+4*PacketSize])));
+ internal::pstore(&a[i+5*PacketSize], internal::padd(internal::ploadu(&a[i+5*PacketSize]), internal::ploadu(&b[i+5*PacketSize])));
+ internal::pstore(&a[i+6*PacketSize], internal::padd(internal::ploadu(&a[i+6*PacketSize]), internal::ploadu(&b[i+6*PacketSize])));
+ internal::pstore(&a[i+7*PacketSize], internal::padd(internal::ploadu(&a[i+7*PacketSize]), internal::ploadu(&b[i+7*PacketSize])));
+ }
+}
diff --git a/bench/bench_gemm.cpp b/bench/bench_gemm.cpp
new file mode 100644
index 000000000..98ac34e20
--- /dev/null
+++ b/bench/bench_gemm.cpp
@@ -0,0 +1,271 @@
+
+// g++-4.4 bench_gemm.cpp -I .. -O2 -DNDEBUG -lrt -fopenmp && OMP_NUM_THREADS=2 ./a.out
+// icpc bench_gemm.cpp -I .. -O3 -DNDEBUG -lrt -openmp && OMP_NUM_THREADS=2 ./a.out
+
+#include <iostream>
+#include <Eigen/Core>
+#include <bench/BenchTimer.h>
+
+using namespace std;
+using namespace Eigen;
+
+#ifndef SCALAR
+// #define SCALAR std::complex<float>
+#define SCALAR float
+#endif
+
+typedef SCALAR Scalar;
+typedef NumTraits<Scalar>::Real RealScalar;
+typedef Matrix<RealScalar,Dynamic,Dynamic> A;
+typedef Matrix</*Real*/Scalar,Dynamic,Dynamic> B;
+typedef Matrix<Scalar,Dynamic,Dynamic> C;
+typedef Matrix<RealScalar,Dynamic,Dynamic> M;
+
+#ifdef HAVE_BLAS
+
+extern "C" {
+ #include <bench/btl/libs/C_BLAS/blas.h>
+}
+
+static float fone = 1;
+static float fzero = 0;
+static double done = 1;
+static double szero = 0;
+static std::complex<float> cfone = 1;
+static std::complex<float> cfzero = 0;
+static std::complex<double> cdone = 1;
+static std::complex<double> cdzero = 0;
+static char notrans = 'N';
+static char trans = 'T';
+static char nonunit = 'N';
+static char lower = 'L';
+static char right = 'R';
+static int intone = 1;
+
+void blas_gemm(const MatrixXf& a, const MatrixXf& b, MatrixXf& c)
+{
+ int M = c.rows(); int N = c.cols(); int K = a.cols();
+ int lda = a.rows(); int ldb = b.rows(); int ldc = c.rows();
+
+ sgemm_(&notrans,&notrans,&M,&N,&K,&fone,
+ const_cast<float*>(a.data()),&lda,
+ const_cast<float*>(b.data()),&ldb,&fone,
+ c.data(),&ldc);
+}
+
+EIGEN_DONT_INLINE void blas_gemm(const MatrixXd& a, const MatrixXd& b, MatrixXd& c)
+{
+ int M = c.rows(); int N = c.cols(); int K = a.cols();
+ int lda = a.rows(); int ldb = b.rows(); int ldc = c.rows();
+
+ dgemm_(&notrans,&notrans,&M,&N,&K,&done,
+ const_cast<double*>(a.data()),&lda,
+ const_cast<double*>(b.data()),&ldb,&done,
+ c.data(),&ldc);
+}
+
+void blas_gemm(const MatrixXcf& a, const MatrixXcf& b, MatrixXcf& c)
+{
+ int M = c.rows(); int N = c.cols(); int K = a.cols();
+ int lda = a.rows(); int ldb = b.rows(); int ldc = c.rows();
+
+ cgemm_(&notrans,&notrans,&M,&N,&K,(float*)&cfone,
+ const_cast<float*>((const float*)a.data()),&lda,
+ const_cast<float*>((const float*)b.data()),&ldb,(float*)&cfone,
+ (float*)c.data(),&ldc);
+}
+
+void blas_gemm(const MatrixXcd& a, const MatrixXcd& b, MatrixXcd& c)
+{
+ int M = c.rows(); int N = c.cols(); int K = a.cols();
+ int lda = a.rows(); int ldb = b.rows(); int ldc = c.rows();
+
+ zgemm_(&notrans,&notrans,&M,&N,&K,(double*)&cdone,
+ const_cast<double*>((const double*)a.data()),&lda,
+ const_cast<double*>((const double*)b.data()),&ldb,(double*)&cdone,
+ (double*)c.data(),&ldc);
+}
+
+
+
+#endif
+
+void matlab_cplx_cplx(const M& ar, const M& ai, const M& br, const M& bi, M& cr, M& ci)
+{
+ cr.noalias() += ar * br;
+ cr.noalias() -= ai * bi;
+ ci.noalias() += ar * bi;
+ ci.noalias() += ai * br;
+}
+
+void matlab_real_cplx(const M& a, const M& br, const M& bi, M& cr, M& ci)
+{
+ cr.noalias() += a * br;
+ ci.noalias() += a * bi;
+}
+
+void matlab_cplx_real(const M& ar, const M& ai, const M& b, M& cr, M& ci)
+{
+ cr.noalias() += ar * b;
+ ci.noalias() += ai * b;
+}
+
+template<typename A, typename B, typename C>
+EIGEN_DONT_INLINE void gemm(const A& a, const B& b, C& c)
+{
+ c.noalias() += a * b;
+}
+
+int main(int argc, char ** argv)
+{
+ std::ptrdiff_t l1 = internal::queryL1CacheSize();
+ std::ptrdiff_t l2 = internal::queryTopLevelCacheSize();
+ std::cout << "L1 cache size = " << (l1>0 ? l1/1024 : -1) << " KB\n";
+ std::cout << "L2/L3 cache size = " << (l2>0 ? l2/1024 : -1) << " KB\n";
+ typedef internal::gebp_traits<Scalar,Scalar> Traits;
+ std::cout << "Register blocking = " << Traits::mr << " x " << Traits::nr << "\n";
+
+ int rep = 1; // number of repetitions per try
+ int tries = 2; // number of tries, we keep the best
+
+ int s = 2048;
+ int cache_size = -1;
+
+ bool need_help = false;
+ for (int i=1; i<argc; ++i)
+ {
+ if(argv[i][0]=='s')
+ s = atoi(argv[i]+1);
+ else if(argv[i][0]=='c')
+ cache_size = atoi(argv[i]+1);
+ else if(argv[i][0]=='t')
+ tries = atoi(argv[i]+1);
+ else if(argv[i][0]=='p')
+ rep = atoi(argv[i]+1);
+ else
+ need_help = true;
+ }
+
+ if(need_help)
+ {
+ std::cout << argv[0] << " s<matrix size> c<cache size> t<nb tries> p<nb repeats>\n";
+ return 1;
+ }
+
+ if(cache_size>0)
+ setCpuCacheSizes(cache_size,96*cache_size);
+
+ int m = s;
+ int n = s;
+ int p = s;
+ A a(m,p); a.setRandom();
+ B b(p,n); b.setRandom();
+ C c(m,n); c.setOnes();
+ C rc = c;
+
+ std::cout << "Matrix sizes = " << m << "x" << p << " * " << p << "x" << n << "\n";
+ std::ptrdiff_t mc(m), nc(n), kc(p);
+ internal::computeProductBlockingSizes<Scalar,Scalar>(kc, mc, nc);
+ std::cout << "blocking size (mc x kc) = " << mc << " x " << kc << "\n";
+
+ C r = c;
+
+ // check the parallel product is correct
+ #if defined EIGEN_HAS_OPENMP
+ int procs = omp_get_max_threads();
+ if(procs>1)
+ {
+ #ifdef HAVE_BLAS
+ blas_gemm(a,b,r);
+ #else
+ omp_set_num_threads(1);
+ r.noalias() += a * b;
+ omp_set_num_threads(procs);
+ #endif
+ c.noalias() += a * b;
+ if(!r.isApprox(c)) std::cerr << "Warning, your parallel product is crap!\n\n";
+ }
+ #elif defined HAVE_BLAS
+ blas_gemm(a,b,r);
+ c.noalias() += a * b;
+ if(!r.isApprox(c)) std::cerr << "Warning, your product is crap!\n\n";
+ #else
+ gemm(a,b,c);
+ r.noalias() += a.cast<Scalar>() * b.cast<Scalar>();
+ if(!r.isApprox(c)) std::cerr << "Warning, your product is crap!\n\n";
+ #endif
+
+ #ifdef HAVE_BLAS
+ BenchTimer tblas;
+ c = rc;
+ BENCH(tblas, tries, rep, blas_gemm(a,b,c));
+ std::cout << "blas cpu " << tblas.best(CPU_TIMER)/rep << "s \t" << (double(m)*n*p*rep*2/tblas.best(CPU_TIMER))*1e-9 << " GFLOPS \t(" << tblas.total(CPU_TIMER) << "s)\n";
+ std::cout << "blas real " << tblas.best(REAL_TIMER)/rep << "s \t" << (double(m)*n*p*rep*2/tblas.best(REAL_TIMER))*1e-9 << " GFLOPS \t(" << tblas.total(REAL_TIMER) << "s)\n";
+ #endif
+
+ BenchTimer tmt;
+ c = rc;
+ BENCH(tmt, tries, rep, gemm(a,b,c));
+ std::cout << "eigen cpu " << tmt.best(CPU_TIMER)/rep << "s \t" << (double(m)*n*p*rep*2/tmt.best(CPU_TIMER))*1e-9 << " GFLOPS \t(" << tmt.total(CPU_TIMER) << "s)\n";
+ std::cout << "eigen real " << tmt.best(REAL_TIMER)/rep << "s \t" << (double(m)*n*p*rep*2/tmt.best(REAL_TIMER))*1e-9 << " GFLOPS \t(" << tmt.total(REAL_TIMER) << "s)\n";
+
+ #ifdef EIGEN_HAS_OPENMP
+ if(procs>1)
+ {
+ BenchTimer tmono;
+ omp_set_num_threads(1);
+ Eigen::internal::setNbThreads(1);
+ c = rc;
+ BENCH(tmono, tries, rep, gemm(a,b,c));
+ std::cout << "eigen mono cpu " << tmono.best(CPU_TIMER)/rep << "s \t" << (double(m)*n*p*rep*2/tmono.best(CPU_TIMER))*1e-9 << " GFLOPS \t(" << tmono.total(CPU_TIMER) << "s)\n";
+ std::cout << "eigen mono real " << tmono.best(REAL_TIMER)/rep << "s \t" << (double(m)*n*p*rep*2/tmono.best(REAL_TIMER))*1e-9 << " GFLOPS \t(" << tmono.total(REAL_TIMER) << "s)\n";
+ std::cout << "mt speed up x" << tmono.best(CPU_TIMER) / tmt.best(REAL_TIMER) << " => " << (100.0*tmono.best(CPU_TIMER) / tmt.best(REAL_TIMER))/procs << "%\n";
+ }
+ #endif
+
+ #ifdef DECOUPLED
+ if((NumTraits<A::Scalar>::IsComplex) && (NumTraits<B::Scalar>::IsComplex))
+ {
+ M ar(m,p); ar.setRandom();
+ M ai(m,p); ai.setRandom();
+ M br(p,n); br.setRandom();
+ M bi(p,n); bi.setRandom();
+ M cr(m,n); cr.setRandom();
+ M ci(m,n); ci.setRandom();
+
+ BenchTimer t;
+ BENCH(t, tries, rep, matlab_cplx_cplx(ar,ai,br,bi,cr,ci));
+ std::cout << "\"matlab\" cpu " << t.best(CPU_TIMER)/rep << "s \t" << (double(m)*n*p*rep*2/t.best(CPU_TIMER))*1e-9 << " GFLOPS \t(" << t.total(CPU_TIMER) << "s)\n";
+ std::cout << "\"matlab\" real " << t.best(REAL_TIMER)/rep << "s \t" << (double(m)*n*p*rep*2/t.best(REAL_TIMER))*1e-9 << " GFLOPS \t(" << t.total(REAL_TIMER) << "s)\n";
+ }
+ if((!NumTraits<A::Scalar>::IsComplex) && (NumTraits<B::Scalar>::IsComplex))
+ {
+ M a(m,p); a.setRandom();
+ M br(p,n); br.setRandom();
+ M bi(p,n); bi.setRandom();
+ M cr(m,n); cr.setRandom();
+ M ci(m,n); ci.setRandom();
+
+ BenchTimer t;
+ BENCH(t, tries, rep, matlab_real_cplx(a,br,bi,cr,ci));
+ std::cout << "\"matlab\" cpu " << t.best(CPU_TIMER)/rep << "s \t" << (double(m)*n*p*rep*2/t.best(CPU_TIMER))*1e-9 << " GFLOPS \t(" << t.total(CPU_TIMER) << "s)\n";
+ std::cout << "\"matlab\" real " << t.best(REAL_TIMER)/rep << "s \t" << (double(m)*n*p*rep*2/t.best(REAL_TIMER))*1e-9 << " GFLOPS \t(" << t.total(REAL_TIMER) << "s)\n";
+ }
+ if((NumTraits<A::Scalar>::IsComplex) && (!NumTraits<B::Scalar>::IsComplex))
+ {
+ M ar(m,p); ar.setRandom();
+ M ai(m,p); ai.setRandom();
+ M b(p,n); b.setRandom();
+ M cr(m,n); cr.setRandom();
+ M ci(m,n); ci.setRandom();
+
+ BenchTimer t;
+ BENCH(t, tries, rep, matlab_cplx_real(ar,ai,b,cr,ci));
+ std::cout << "\"matlab\" cpu " << t.best(CPU_TIMER)/rep << "s \t" << (double(m)*n*p*rep*2/t.best(CPU_TIMER))*1e-9 << " GFLOPS \t(" << t.total(CPU_TIMER) << "s)\n";
+ std::cout << "\"matlab\" real " << t.best(REAL_TIMER)/rep << "s \t" << (double(m)*n*p*rep*2/t.best(REAL_TIMER))*1e-9 << " GFLOPS \t(" << t.total(REAL_TIMER) << "s)\n";
+ }
+ #endif
+
+ return 0;
+}
+
diff --git a/bench/bench_multi_compilers.sh b/bench/bench_multi_compilers.sh
new file mode 100755
index 000000000..27e91f1d5
--- /dev/null
+++ b/bench/bench_multi_compilers.sh
@@ -0,0 +1,28 @@
+#!/bin/bash
+
+if (($# < 2)); then
+ echo "Usage: $0 compilerlist.txt benchfile.cpp"
+else
+
+compilerlist=$1
+benchfile=$2
+
+g=0
+source $compilerlist
+
+# for each compiler, compile benchfile and run the benchmark
+for (( i=0 ; i<g ; ++i )) ; do
+ # check the compiler exists
+ compiler=`echo ${CLIST[$i]} | cut -d " " -f 1`
+ if [ -e `which $compiler` ]; then
+ echo "${CLIST[$i]}"
+# echo "${CLIST[$i]} $benchfile -I.. -o bench~"
+# if [ -e ./.bench ] ; then rm .bench; fi
+ ${CLIST[$i]} $benchfile -I.. -o .bench && ./.bench 2> /dev/null
+ echo ""
+ else
+ echo "compiler not found: $compiler"
+ fi
+done
+
+fi
diff --git a/bench/bench_norm.cpp b/bench/bench_norm.cpp
new file mode 100644
index 000000000..806db292c
--- /dev/null
+++ b/bench/bench_norm.cpp
@@ -0,0 +1,345 @@
+#include <typeinfo>
+#include <iostream>
+#include <Eigen/Core>
+#include "BenchTimer.h"
+using namespace Eigen;
+using namespace std;
+
+template<typename T>
+EIGEN_DONT_INLINE typename T::Scalar sqsumNorm(const T& v)
+{
+ return v.norm();
+}
+
+template<typename T>
+EIGEN_DONT_INLINE typename T::Scalar hypotNorm(const T& v)
+{
+ return v.hypotNorm();
+}
+
+template<typename T>
+EIGEN_DONT_INLINE typename T::Scalar blueNorm(const T& v)
+{
+ return v.blueNorm();
+}
+
+template<typename T>
+EIGEN_DONT_INLINE typename T::Scalar lapackNorm(T& v)
+{
+ typedef typename T::Scalar Scalar;
+ int n = v.size();
+ Scalar scale = 0;
+ Scalar ssq = 1;
+ for (int i=0;i<n;++i)
+ {
+ Scalar ax = internal::abs(v.coeff(i));
+ if (scale >= ax)
+ {
+ ssq += internal::abs2(ax/scale);
+ }
+ else
+ {
+ ssq = Scalar(1) + ssq * internal::abs2(scale/ax);
+ scale = ax;
+ }
+ }
+ return scale * internal::sqrt(ssq);
+}
+
+template<typename T>
+EIGEN_DONT_INLINE typename T::Scalar twopassNorm(T& v)
+{
+ typedef typename T::Scalar Scalar;
+ Scalar s = v.cwise().abs().maxCoeff();
+ return s*(v/s).norm();
+}
+
+template<typename T>
+EIGEN_DONT_INLINE typename T::Scalar bl2passNorm(T& v)
+{
+ return v.stableNorm();
+}
+
+template<typename T>
+EIGEN_DONT_INLINE typename T::Scalar divacNorm(T& v)
+{
+ int n =v.size() / 2;
+ for (int i=0;i<n;++i)
+ v(i) = v(2*i)*v(2*i) + v(2*i+1)*v(2*i+1);
+ n = n/2;
+ while (n>0)
+ {
+ for (int i=0;i<n;++i)
+ v(i) = v(2*i) + v(2*i+1);
+ n = n/2;
+ }
+ return internal::sqrt(v(0));
+}
+
+#ifdef EIGEN_VECTORIZE
+Packet4f internal::plt(const Packet4f& a, Packet4f& b) { return _mm_cmplt_ps(a,b); }
+Packet2d internal::plt(const Packet2d& a, Packet2d& b) { return _mm_cmplt_pd(a,b); }
+
+Packet4f internal::pandnot(const Packet4f& a, Packet4f& b) { return _mm_andnot_ps(a,b); }
+Packet2d internal::pandnot(const Packet2d& a, Packet2d& b) { return _mm_andnot_pd(a,b); }
+#endif
+
+template<typename T>
+EIGEN_DONT_INLINE typename T::Scalar pblueNorm(const T& v)
+{
+ #ifndef EIGEN_VECTORIZE
+ return v.blueNorm();
+ #else
+ typedef typename T::Scalar Scalar;
+
+ static int nmax = 0;
+ static Scalar b1, b2, s1m, s2m, overfl, rbig, relerr;
+ int n;
+
+ if(nmax <= 0)
+ {
+ int nbig, ibeta, it, iemin, iemax, iexp;
+ Scalar abig, eps;
+
+ nbig = std::numeric_limits<int>::max(); // largest integer
+ ibeta = std::numeric_limits<Scalar>::radix; //NumTraits<Scalar>::Base; // base for floating-point numbers
+ it = std::numeric_limits<Scalar>::digits; //NumTraits<Scalar>::Mantissa; // number of base-beta digits in mantissa
+ iemin = std::numeric_limits<Scalar>::min_exponent; // minimum exponent
+ iemax = std::numeric_limits<Scalar>::max_exponent; // maximum exponent
+ rbig = std::numeric_limits<Scalar>::max(); // largest floating-point number
+
+ // Check the basic machine-dependent constants.
+ if(iemin > 1 - 2*it || 1+it>iemax || (it==2 && ibeta<5)
+ || (it<=4 && ibeta <= 3 ) || it<2)
+ {
+ eigen_assert(false && "the algorithm cannot be guaranteed on this computer");
+ }
+ iexp = -((1-iemin)/2);
+ b1 = std::pow(ibeta, iexp); // lower boundary of midrange
+ iexp = (iemax + 1 - it)/2;
+ b2 = std::pow(ibeta,iexp); // upper boundary of midrange
+
+ iexp = (2-iemin)/2;
+ s1m = std::pow(ibeta,iexp); // scaling factor for lower range
+ iexp = - ((iemax+it)/2);
+ s2m = std::pow(ibeta,iexp); // scaling factor for upper range
+
+ overfl = rbig*s2m; // overfow boundary for abig
+ eps = std::pow(ibeta, 1-it);
+ relerr = internal::sqrt(eps); // tolerance for neglecting asml
+ abig = 1.0/eps - 1.0;
+ if (Scalar(nbig)>abig) nmax = abig; // largest safe n
+ else nmax = nbig;
+ }
+
+ typedef typename internal::packet_traits<Scalar>::type Packet;
+ const int ps = internal::packet_traits<Scalar>::size;
+ Packet pasml = internal::pset1(Scalar(0));
+ Packet pamed = internal::pset1(Scalar(0));
+ Packet pabig = internal::pset1(Scalar(0));
+ Packet ps2m = internal::pset1(s2m);
+ Packet ps1m = internal::pset1(s1m);
+ Packet pb2 = internal::pset1(b2);
+ Packet pb1 = internal::pset1(b1);
+ for(int j=0; j<v.size(); j+=ps)
+ {
+ Packet ax = internal::pabs(v.template packet<Aligned>(j));
+ Packet ax_s2m = internal::pmul(ax,ps2m);
+ Packet ax_s1m = internal::pmul(ax,ps1m);
+ Packet maskBig = internal::plt(pb2,ax);
+ Packet maskSml = internal::plt(ax,pb1);
+
+// Packet maskMed = internal::pand(maskSml,maskBig);
+// Packet scale = internal::pset1(Scalar(0));
+// scale = internal::por(scale, internal::pand(maskBig,ps2m));
+// scale = internal::por(scale, internal::pand(maskSml,ps1m));
+// scale = internal::por(scale, internal::pandnot(internal::pset1(Scalar(1)),maskMed));
+// ax = internal::pmul(ax,scale);
+// ax = internal::pmul(ax,ax);
+// pabig = internal::padd(pabig, internal::pand(maskBig, ax));
+// pasml = internal::padd(pasml, internal::pand(maskSml, ax));
+// pamed = internal::padd(pamed, internal::pandnot(ax,maskMed));
+
+
+ pabig = internal::padd(pabig, internal::pand(maskBig, internal::pmul(ax_s2m,ax_s2m)));
+ pasml = internal::padd(pasml, internal::pand(maskSml, internal::pmul(ax_s1m,ax_s1m)));
+ pamed = internal::padd(pamed, internal::pandnot(internal::pmul(ax,ax),internal::pand(maskSml,maskBig)));
+ }
+ Scalar abig = internal::predux(pabig);
+ Scalar asml = internal::predux(pasml);
+ Scalar amed = internal::predux(pamed);
+ if(abig > Scalar(0))
+ {
+ abig = internal::sqrt(abig);
+ if(abig > overfl)
+ {
+ eigen_assert(false && "overflow");
+ return rbig;
+ }
+ if(amed > Scalar(0))
+ {
+ abig = abig/s2m;
+ amed = internal::sqrt(amed);
+ }
+ else
+ {
+ return abig/s2m;
+ }
+
+ }
+ else if(asml > Scalar(0))
+ {
+ if (amed > Scalar(0))
+ {
+ abig = internal::sqrt(amed);
+ amed = internal::sqrt(asml) / s1m;
+ }
+ else
+ {
+ return internal::sqrt(asml)/s1m;
+ }
+ }
+ else
+ {
+ return internal::sqrt(amed);
+ }
+ asml = std::min(abig, amed);
+ abig = std::max(abig, amed);
+ if(asml <= abig*relerr)
+ return abig;
+ else
+ return abig * internal::sqrt(Scalar(1) + internal::abs2(asml/abig));
+ #endif
+}
+
+#define BENCH_PERF(NRM) { \
+ Eigen::BenchTimer tf, td, tcf; tf.reset(); td.reset(); tcf.reset();\
+ for (int k=0; k<tries; ++k) { \
+ tf.start(); \
+ for (int i=0; i<iters; ++i) NRM(vf); \
+ tf.stop(); \
+ } \
+ for (int k=0; k<tries; ++k) { \
+ td.start(); \
+ for (int i=0; i<iters; ++i) NRM(vd); \
+ td.stop(); \
+ } \
+ for (int k=0; k<std::max(1,tries/3); ++k) { \
+ tcf.start(); \
+ for (int i=0; i<iters; ++i) NRM(vcf); \
+ tcf.stop(); \
+ } \
+ std::cout << #NRM << "\t" << tf.value() << " " << td.value() << " " << tcf.value() << "\n"; \
+}
+
+void check_accuracy(double basef, double based, int s)
+{
+ double yf = basef * internal::abs(internal::random<double>());
+ double yd = based * internal::abs(internal::random<double>());
+ VectorXf vf = VectorXf::Ones(s) * yf;
+ VectorXd vd = VectorXd::Ones(s) * yd;
+
+ std::cout << "reference\t" << internal::sqrt(double(s))*yf << "\t" << internal::sqrt(double(s))*yd << "\n";
+ std::cout << "sqsumNorm\t" << sqsumNorm(vf) << "\t" << sqsumNorm(vd) << "\n";
+ std::cout << "hypotNorm\t" << hypotNorm(vf) << "\t" << hypotNorm(vd) << "\n";
+ std::cout << "blueNorm\t" << blueNorm(vf) << "\t" << blueNorm(vd) << "\n";
+ std::cout << "pblueNorm\t" << pblueNorm(vf) << "\t" << pblueNorm(vd) << "\n";
+ std::cout << "lapackNorm\t" << lapackNorm(vf) << "\t" << lapackNorm(vd) << "\n";
+ std::cout << "twopassNorm\t" << twopassNorm(vf) << "\t" << twopassNorm(vd) << "\n";
+ std::cout << "bl2passNorm\t" << bl2passNorm(vf) << "\t" << bl2passNorm(vd) << "\n";
+}
+
+void check_accuracy_var(int ef0, int ef1, int ed0, int ed1, int s)
+{
+ VectorXf vf(s);
+ VectorXd vd(s);
+ for (int i=0; i<s; ++i)
+ {
+ vf[i] = internal::abs(internal::random<double>()) * std::pow(double(10), internal::random<int>(ef0,ef1));
+ vd[i] = internal::abs(internal::random<double>()) * std::pow(double(10), internal::random<int>(ed0,ed1));
+ }
+
+ //std::cout << "reference\t" << internal::sqrt(double(s))*yf << "\t" << internal::sqrt(double(s))*yd << "\n";
+ std::cout << "sqsumNorm\t" << sqsumNorm(vf) << "\t" << sqsumNorm(vd) << "\t" << sqsumNorm(vf.cast<long double>()) << "\t" << sqsumNorm(vd.cast<long double>()) << "\n";
+ std::cout << "hypotNorm\t" << hypotNorm(vf) << "\t" << hypotNorm(vd) << "\t" << hypotNorm(vf.cast<long double>()) << "\t" << hypotNorm(vd.cast<long double>()) << "\n";
+ std::cout << "blueNorm\t" << blueNorm(vf) << "\t" << blueNorm(vd) << "\t" << blueNorm(vf.cast<long double>()) << "\t" << blueNorm(vd.cast<long double>()) << "\n";
+ std::cout << "pblueNorm\t" << pblueNorm(vf) << "\t" << pblueNorm(vd) << "\t" << blueNorm(vf.cast<long double>()) << "\t" << blueNorm(vd.cast<long double>()) << "\n";
+ std::cout << "lapackNorm\t" << lapackNorm(vf) << "\t" << lapackNorm(vd) << "\t" << lapackNorm(vf.cast<long double>()) << "\t" << lapackNorm(vd.cast<long double>()) << "\n";
+ std::cout << "twopassNorm\t" << twopassNorm(vf) << "\t" << twopassNorm(vd) << "\t" << twopassNorm(vf.cast<long double>()) << "\t" << twopassNorm(vd.cast<long double>()) << "\n";
+// std::cout << "bl2passNorm\t" << bl2passNorm(vf) << "\t" << bl2passNorm(vd) << "\t" << bl2passNorm(vf.cast<long double>()) << "\t" << bl2passNorm(vd.cast<long double>()) << "\n";
+}
+
+int main(int argc, char** argv)
+{
+ int tries = 10;
+ int iters = 100000;
+ double y = 1.1345743233455785456788e12 * internal::random<double>();
+ VectorXf v = VectorXf::Ones(1024) * y;
+
+// return 0;
+ int s = 10000;
+ double basef_ok = 1.1345743233455785456788e15;
+ double based_ok = 1.1345743233455785456788e95;
+
+ double basef_under = 1.1345743233455785456788e-27;
+ double based_under = 1.1345743233455785456788e-303;
+
+ double basef_over = 1.1345743233455785456788e+27;
+ double based_over = 1.1345743233455785456788e+302;
+
+ std::cout.precision(20);
+
+ std::cerr << "\nNo under/overflow:\n";
+ check_accuracy(basef_ok, based_ok, s);
+
+ std::cerr << "\nUnderflow:\n";
+ check_accuracy(basef_under, based_under, s);
+
+ std::cerr << "\nOverflow:\n";
+ check_accuracy(basef_over, based_over, s);
+
+ std::cerr << "\nVarying (over):\n";
+ for (int k=0; k<1; ++k)
+ {
+ check_accuracy_var(20,27,190,302,s);
+ std::cout << "\n";
+ }
+
+ std::cerr << "\nVarying (under):\n";
+ for (int k=0; k<1; ++k)
+ {
+ check_accuracy_var(-27,20,-302,-190,s);
+ std::cout << "\n";
+ }
+
+ std::cout.precision(4);
+ std::cerr << "Performance (out of cache):\n";
+ {
+ int iters = 1;
+ VectorXf vf = VectorXf::Random(1024*1024*32) * y;
+ VectorXd vd = VectorXd::Random(1024*1024*32) * y;
+ VectorXcf vcf = VectorXcf::Random(1024*1024*32) * y;
+ BENCH_PERF(sqsumNorm);
+ BENCH_PERF(blueNorm);
+// BENCH_PERF(pblueNorm);
+// BENCH_PERF(lapackNorm);
+// BENCH_PERF(hypotNorm);
+// BENCH_PERF(twopassNorm);
+ BENCH_PERF(bl2passNorm);
+ }
+
+ std::cerr << "\nPerformance (in cache):\n";
+ {
+ int iters = 100000;
+ VectorXf vf = VectorXf::Random(512) * y;
+ VectorXd vd = VectorXd::Random(512) * y;
+ VectorXcf vcf = VectorXcf::Random(512) * y;
+ BENCH_PERF(sqsumNorm);
+ BENCH_PERF(blueNorm);
+// BENCH_PERF(pblueNorm);
+// BENCH_PERF(lapackNorm);
+// BENCH_PERF(hypotNorm);
+// BENCH_PERF(twopassNorm);
+ BENCH_PERF(bl2passNorm);
+ }
+}
diff --git a/bench/bench_reverse.cpp b/bench/bench_reverse.cpp
new file mode 100644
index 000000000..1e69ca1b2
--- /dev/null
+++ b/bench/bench_reverse.cpp
@@ -0,0 +1,84 @@
+
+#include <iostream>
+#include <Eigen/Core>
+#include <bench/BenchUtil.h>
+using namespace Eigen;
+
+#ifndef REPEAT
+#define REPEAT 100000
+#endif
+
+#ifndef TRIES
+#define TRIES 20
+#endif
+
+typedef double Scalar;
+
+template <typename MatrixType>
+__attribute__ ((noinline)) void bench_reverse(const MatrixType& m)
+{
+ int rows = m.rows();
+ int cols = m.cols();
+ int size = m.size();
+
+ int repeats = (REPEAT*1000)/size;
+ MatrixType a = MatrixType::Random(rows,cols);
+ MatrixType b = MatrixType::Random(rows,cols);
+
+ BenchTimer timerB, timerH, timerV;
+
+ Scalar acc = 0;
+ int r = internal::random<int>(0,rows-1);
+ int c = internal::random<int>(0,cols-1);
+ for (int t=0; t<TRIES; ++t)
+ {
+ timerB.start();
+ for (int k=0; k<repeats; ++k)
+ {
+ asm("#begin foo");
+ b = a.reverse();
+ asm("#end foo");
+ acc += b.coeff(r,c);
+ }
+ timerB.stop();
+ }
+
+ if (MatrixType::RowsAtCompileTime==Dynamic)
+ std::cout << "dyn ";
+ else
+ std::cout << "fixed ";
+ std::cout << rows << " x " << cols << " \t"
+ << (timerB.value() * REPEAT) / repeats << "s "
+ << "(" << 1e-6 * size*repeats/timerB.value() << " MFLOPS)\t";
+
+ std::cout << "\n";
+ // make sure the compiler does not optimize too much
+ if (acc==123)
+ std::cout << acc;
+}
+
+int main(int argc, char* argv[])
+{
+ const int dynsizes[] = {4,6,8,16,24,32,49,64,128,256,512,900,0};
+ std::cout << "size no sqrt standard";
+// #ifdef BENCH_GSL
+// std::cout << " GSL (standard + double + ATLAS) ";
+// #endif
+ std::cout << "\n";
+ for (uint i=0; dynsizes[i]>0; ++i)
+ {
+ bench_reverse(Matrix<Scalar,Dynamic,Dynamic>(dynsizes[i],dynsizes[i]));
+ bench_reverse(Matrix<Scalar,Dynamic,1>(dynsizes[i]*dynsizes[i]));
+ }
+// bench_reverse(Matrix<Scalar,2,2>());
+// bench_reverse(Matrix<Scalar,3,3>());
+// bench_reverse(Matrix<Scalar,4,4>());
+// bench_reverse(Matrix<Scalar,5,5>());
+// bench_reverse(Matrix<Scalar,6,6>());
+// bench_reverse(Matrix<Scalar,7,7>());
+// bench_reverse(Matrix<Scalar,8,8>());
+// bench_reverse(Matrix<Scalar,12,12>());
+// bench_reverse(Matrix<Scalar,16,16>());
+ return 0;
+}
+
diff --git a/bench/bench_sum.cpp b/bench/bench_sum.cpp
new file mode 100644
index 000000000..a3d925e4f
--- /dev/null
+++ b/bench/bench_sum.cpp
@@ -0,0 +1,18 @@
+#include <iostream>
+#include <Eigen/Core>
+using namespace Eigen;
+using namespace std;
+
+int main()
+{
+ typedef Matrix<SCALAR,Eigen::Dynamic,1> Vec;
+ Vec v(SIZE);
+ v.setZero();
+ v[0] = 1;
+ v[1] = 2;
+ for(int i = 0; i < 1000000; i++)
+ {
+ v.coeffRef(0) += v.sum() * SCALAR(1e-20);
+ }
+ cout << v.sum() << endl;
+}
diff --git a/bench/bench_unrolling b/bench/bench_unrolling
new file mode 100755
index 000000000..826443845
--- /dev/null
+++ b/bench/bench_unrolling
@@ -0,0 +1,12 @@
+#!/bin/bash
+
+# gcc : CXX="g++ -finline-limit=10000 -ftemplate-depth-2000 --param max-inline-recursive-depth=2000"
+# icc : CXX="icpc -fast -no-inline-max-size -fno-exceptions"
+CXX=${CXX-g++ -finline-limit=10000 -ftemplate-depth-2000 --param max-inline-recursive-depth=2000} # default value
+
+for ((i=1; i<16; ++i)); do
+ echo "Matrix size: $i x $i :"
+ $CXX -O3 -I.. -DNDEBUG benchmark.cpp -DMATSIZE=$i -DEIGEN_UNROLLING_LIMIT=400 -o benchmark && time ./benchmark >/dev/null
+ $CXX -O3 -I.. -DNDEBUG -finline-limit=10000 benchmark.cpp -DMATSIZE=$i -DEIGEN_DONT_USE_UNROLLED_LOOPS=1 -o benchmark && time ./benchmark >/dev/null
+ echo " "
+done
diff --git a/bench/benchmark.cpp b/bench/benchmark.cpp
new file mode 100644
index 000000000..c721b9081
--- /dev/null
+++ b/bench/benchmark.cpp
@@ -0,0 +1,39 @@
+// g++ -O3 -DNDEBUG -DMATSIZE=<x> benchmark.cpp -o benchmark && time ./benchmark
+
+#include <iostream>
+
+#include <Eigen/Core>
+
+#ifndef MATSIZE
+#define MATSIZE 3
+#endif
+
+using namespace std;
+using namespace Eigen;
+
+#ifndef REPEAT
+#define REPEAT 40000000
+#endif
+
+#ifndef SCALAR
+#define SCALAR double
+#endif
+
+int main(int argc, char *argv[])
+{
+ Matrix<SCALAR,MATSIZE,MATSIZE> I = Matrix<SCALAR,MATSIZE,MATSIZE>::Ones();
+ Matrix<SCALAR,MATSIZE,MATSIZE> m;
+ for(int i = 0; i < MATSIZE; i++)
+ for(int j = 0; j < MATSIZE; j++)
+ {
+ m(i,j) = (i+MATSIZE*j);
+ }
+ asm("#begin");
+ for(int a = 0; a < REPEAT; a++)
+ {
+ m = Matrix<SCALAR,MATSIZE,MATSIZE>::Ones() + 0.00005 * (m + (m*m));
+ }
+ asm("#end");
+ cout << m << endl;
+ return 0;
+}
diff --git a/bench/benchmarkSlice.cpp b/bench/benchmarkSlice.cpp
new file mode 100644
index 000000000..c5b89c545
--- /dev/null
+++ b/bench/benchmarkSlice.cpp
@@ -0,0 +1,38 @@
+// g++ -O3 -DNDEBUG benchmarkX.cpp -o benchmarkX && time ./benchmarkX
+
+#include <iostream>
+
+#include <Eigen/Core>
+
+using namespace std;
+using namespace Eigen;
+
+#ifndef REPEAT
+#define REPEAT 10000
+#endif
+
+#ifndef SCALAR
+#define SCALAR float
+#endif
+
+int main(int argc, char *argv[])
+{
+ typedef Matrix<SCALAR, Eigen::Dynamic, Eigen::Dynamic> Mat;
+ Mat m(100, 100);
+ m.setRandom();
+
+ for(int a = 0; a < REPEAT; a++)
+ {
+ int r, c, nr, nc;
+ r = Eigen::internal::random<int>(0,10);
+ c = Eigen::internal::random<int>(0,10);
+ nr = Eigen::internal::random<int>(50,80);
+ nc = Eigen::internal::random<int>(50,80);
+ m.block(r,c,nr,nc) += Mat::Ones(nr,nc);
+ m.block(r,c,nr,nc) *= SCALAR(10);
+ m.block(r,c,nr,nc) -= Mat::constant(nr,nc,10);
+ m.block(r,c,nr,nc) /= SCALAR(10);
+ }
+ cout << m[0] << endl;
+ return 0;
+}
diff --git a/bench/benchmarkX.cpp b/bench/benchmarkX.cpp
new file mode 100644
index 000000000..8e4b60c2b
--- /dev/null
+++ b/bench/benchmarkX.cpp
@@ -0,0 +1,36 @@
+// g++ -fopenmp -I .. -O3 -DNDEBUG -finline-limit=1000 benchmarkX.cpp -o b && time ./b
+
+#include <iostream>
+
+#include <Eigen/Core>
+
+using namespace std;
+using namespace Eigen;
+
+#ifndef MATTYPE
+#define MATTYPE MatrixXLd
+#endif
+
+#ifndef MATSIZE
+#define MATSIZE 400
+#endif
+
+#ifndef REPEAT
+#define REPEAT 100
+#endif
+
+int main(int argc, char *argv[])
+{
+ MATTYPE I = MATTYPE::Ones(MATSIZE,MATSIZE);
+ MATTYPE m(MATSIZE,MATSIZE);
+ for(int i = 0; i < MATSIZE; i++) for(int j = 0; j < MATSIZE; j++)
+ {
+ m(i,j) = (i+j+1)/(MATSIZE*MATSIZE);
+ }
+ for(int a = 0; a < REPEAT; a++)
+ {
+ m = I + 0.0001 * (m + m*m);
+ }
+ cout << m(0,0) << endl;
+ return 0;
+}
diff --git a/bench/benchmarkXcwise.cpp b/bench/benchmarkXcwise.cpp
new file mode 100644
index 000000000..62437435e
--- /dev/null
+++ b/bench/benchmarkXcwise.cpp
@@ -0,0 +1,35 @@
+// g++ -O3 -DNDEBUG benchmarkX.cpp -o benchmarkX && time ./benchmarkX
+
+#include <iostream>
+#include <Eigen/Core>
+
+using namespace std;
+using namespace Eigen;
+
+#ifndef VECTYPE
+#define VECTYPE VectorXLd
+#endif
+
+#ifndef VECSIZE
+#define VECSIZE 1000000
+#endif
+
+#ifndef REPEAT
+#define REPEAT 1000
+#endif
+
+int main(int argc, char *argv[])
+{
+ VECTYPE I = VECTYPE::Ones(VECSIZE);
+ VECTYPE m(VECSIZE,1);
+ for(int i = 0; i < VECSIZE; i++)
+ {
+ m[i] = 0.1 * i/VECSIZE;
+ }
+ for(int a = 0; a < REPEAT; a++)
+ {
+ m = VECTYPE::Ones(VECSIZE) + 0.00005 * (m.cwise().square() + m/4);
+ }
+ cout << m[0] << endl;
+ return 0;
+}
diff --git a/bench/benchmark_suite b/bench/benchmark_suite
new file mode 100755
index 000000000..3f21d3661
--- /dev/null
+++ b/bench/benchmark_suite
@@ -0,0 +1,18 @@
+#!/bin/bash
+CXX=${CXX-g++} # default value unless caller has defined CXX
+echo "Fixed size 3x3, column-major, -DNDEBUG"
+$CXX -O3 -I .. -DNDEBUG benchmark.cpp -o benchmark && time ./benchmark >/dev/null
+echo "Fixed size 3x3, column-major, with asserts"
+$CXX -O3 -I .. benchmark.cpp -o benchmark && time ./benchmark >/dev/null
+echo "Fixed size 3x3, row-major, -DNDEBUG"
+$CXX -O3 -I .. -DEIGEN_DEFAULT_TO_ROW_MAJOR -DNDEBUG benchmark.cpp -o benchmark && time ./benchmark >/dev/null
+echo "Fixed size 3x3, row-major, with asserts"
+$CXX -O3 -I .. -DEIGEN_DEFAULT_TO_ROW_MAJOR benchmark.cpp -o benchmark && time ./benchmark >/dev/null
+echo "Dynamic size 20x20, column-major, -DNDEBUG"
+$CXX -O3 -I .. -DNDEBUG benchmarkX.cpp -o benchmarkX && time ./benchmarkX >/dev/null
+echo "Dynamic size 20x20, column-major, with asserts"
+$CXX -O3 -I .. benchmarkX.cpp -o benchmarkX && time ./benchmarkX >/dev/null
+echo "Dynamic size 20x20, row-major, -DNDEBUG"
+$CXX -O3 -I .. -DEIGEN_DEFAULT_TO_ROW_MAJOR -DNDEBUG benchmarkX.cpp -o benchmarkX && time ./benchmarkX >/dev/null
+echo "Dynamic size 20x20, row-major, with asserts"
+$CXX -O3 -I .. -DEIGEN_DEFAULT_TO_ROW_MAJOR benchmarkX.cpp -o benchmarkX && time ./benchmarkX >/dev/null
diff --git a/bench/btl/CMakeLists.txt b/bench/btl/CMakeLists.txt
new file mode 100644
index 000000000..119b470d9
--- /dev/null
+++ b/bench/btl/CMakeLists.txt
@@ -0,0 +1,104 @@
+PROJECT(BTL)
+
+CMAKE_MINIMUM_REQUIRED(VERSION 2.6.2)
+
+set(CMAKE_MODULE_PATH ${PROJECT_SOURCE_DIR}/cmake ${Eigen_SOURCE_DIR}/cmake)
+include(MacroOptionalAddSubdirectory)
+
+OPTION(BTL_NOVEC "Disable SSE/Altivec optimizations when possible" OFF)
+
+SET(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+string(REGEX MATCH icpc IS_ICPC ${CMAKE_CXX_COMPILER})
+IF(CMAKE_COMPILER_IS_GNUCXX OR IS_ICPC)
+ SET(CMAKE_CXX_FLAGS "-g0 -O3 -DNDEBUG")
+ SET(CMAKE_Fortran_FLAGS "-g0 -O3 -DNDEBUG")
+ IF(NOT BTL_NOVEC)
+ SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -msse2")
+ SET(CMAKE_Fortran_FLAGS "${CMAKE_Fortran_FLAGS} -msse2")
+ ELSE(NOT BTL_NOVEC)
+ SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DEIGEN_DONT_VECTORIZE")
+ ENDIF(NOT BTL_NOVEC)
+ENDIF(CMAKE_COMPILER_IS_GNUCXX OR IS_ICPC)
+
+IF(MSVC)
+ SET(CMAKE_CXX_FLAGS " /O2 /Ot /GL /fp:fast -DNDEBUG")
+# SET(CMAKE_Fortran_FLAGS "-g0 -O3 -DNDEBUG")
+ IF(NOT BTL_NOVEC)
+ SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /arch:SSE2")
+ ELSE(NOT BTL_NOVEC)
+ SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DEIGEN_DONT_VECTORIZE")
+ ENDIF(NOT BTL_NOVEC)
+ENDIF(MSVC)
+
+if(IS_ICPC)
+ set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fast")
+ set(CMAKE_Fortran_FLAGS "${CMAKE_Fortran_FLAGS} -fast")
+endif(IS_ICPC)
+
+include_directories(
+ ${PROJECT_SOURCE_DIR}/actions
+ ${PROJECT_SOURCE_DIR}/generic_bench
+ ${PROJECT_SOURCE_DIR}/generic_bench/utils
+ ${PROJECT_SOURCE_DIR}/libs/STL)
+
+# find_package(MKL)
+# if (MKL_FOUND)
+# add_definitions(-DHAVE_MKL)
+# set(DEFAULT_LIBRARIES ${MKL_LIBRARIES})
+# endif (MKL_FOUND)
+
+MACRO(BTL_ADD_BENCH targetname)
+
+ foreach(_current_var ${ARGN})
+ set(_last_var ${_current_var})
+ endforeach(_current_var)
+
+ set(_sources ${ARGN})
+ list(LENGTH _sources _argn_length)
+
+ list(REMOVE_ITEM _sources ON OFF TRUE FALSE)
+
+ list(LENGTH _sources _src_length)
+
+ if (${_argn_length} EQUAL ${_src_length})
+ set(_last_var ON)
+ endif (${_argn_length} EQUAL ${_src_length})
+
+ OPTION(BUILD_${targetname} "Build benchmark ${targetname}" ${_last_var})
+
+ IF(BUILD_${targetname})
+ ADD_EXECUTABLE(${targetname} ${_sources})
+ ADD_TEST(${targetname} "${targetname}")
+ target_link_libraries(${targetname} ${DEFAULT_LIBRARIES} rt)
+ ENDIF(BUILD_${targetname})
+
+ENDMACRO(BTL_ADD_BENCH)
+
+macro(btl_add_target_property target prop value)
+
+ if(BUILD_${target})
+ get_target_property(previous ${target} ${prop})
+ if(NOT previous)
+ set(previous "")
+ endif()
+ set_target_properties(${target} PROPERTIES ${prop} "${previous} ${value}")
+ endif()
+
+endmacro(btl_add_target_property)
+
+ENABLE_TESTING()
+
+add_subdirectory(libs/eigen3)
+add_subdirectory(libs/eigen2)
+add_subdirectory(libs/BLAS)
+add_subdirectory(libs/ublas)
+add_subdirectory(libs/gmm)
+add_subdirectory(libs/mtl4)
+add_subdirectory(libs/blitz)
+add_subdirectory(libs/tvmet)
+add_subdirectory(libs/STL)
+
+add_subdirectory(data)
+
+
diff --git a/bench/btl/COPYING b/bench/btl/COPYING
new file mode 100644
index 000000000..486449cc3
--- /dev/null
+++ b/bench/btl/COPYING
@@ -0,0 +1,340 @@
+ GNU GENERAL PUBLIC LICENSE
+ Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.
+ 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+ Preamble
+
+ The licenses for most software are designed to take away your
+freedom to share and change it. By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users. This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it. (Some other Free Software Foundation software is covered by
+the GNU Library General Public License instead.) You can apply it to
+your programs, too.
+
+ When we speak of free software, we are referring to freedom, not
+price. Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+ To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+ For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have. You must make sure that they, too, receive or can get the
+source code. And you must show them these terms so they know their
+rights.
+
+ We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+ Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software. If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+ Finally, any free program is threatened constantly by software
+patents. We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary. To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+ The precise terms and conditions for copying, distribution and
+modification follow.
+
+ GNU GENERAL PUBLIC LICENSE
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+ 0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License. The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language. (Hereinafter, translation is included without limitation in
+the term "modification".) Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope. The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+ 1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+ 2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+ a) You must cause the modified files to carry prominent notices
+ stating that you changed the files and the date of any change.
+
+ b) You must cause any work that you distribute or publish, that in
+ whole or in part contains or is derived from the Program or any
+ part thereof, to be licensed as a whole at no charge to all third
+ parties under the terms of this License.
+
+ c) If the modified program normally reads commands interactively
+ when run, you must cause it, when started running for such
+ interactive use in the most ordinary way, to print or display an
+ announcement including an appropriate copyright notice and a
+ notice that there is no warranty (or else, saying that you provide
+ a warranty) and that users may redistribute the program under
+ these conditions, and telling the user how to view a copy of this
+ License. (Exception: if the Program itself is interactive but
+ does not normally print such an announcement, your work based on
+ the Program is not required to print an announcement.)
+
+These requirements apply to the modified work as a whole. If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works. But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+ 3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+ a) Accompany it with the complete corresponding machine-readable
+ source code, which must be distributed under the terms of Sections
+ 1 and 2 above on a medium customarily used for software interchange; or,
+
+ b) Accompany it with a written offer, valid for at least three
+ years, to give any third party, for a charge no more than your
+ cost of physically performing source distribution, a complete
+ machine-readable copy of the corresponding source code, to be
+ distributed under the terms of Sections 1 and 2 above on a medium
+ customarily used for software interchange; or,
+
+ c) Accompany it with the information you received as to the offer
+ to distribute corresponding source code. (This alternative is
+ allowed only for noncommercial distribution and only if you
+ received the program in object code or executable form with such
+ an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it. For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable. However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+ 4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License. Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+ 5. You are not required to accept this License, since you have not
+signed it. However, nothing else grants you permission to modify or
+distribute the Program or its derivative works. These actions are
+prohibited by law if you do not accept this License. Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+ 6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions. You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+ 7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all. For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices. Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+ 8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded. In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+ 9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time. Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number. If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation. If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+ 10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission. For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this. Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+ NO WARRANTY
+
+ 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+ 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+ END OF TERMS AND CONDITIONS
+
+ How to Apply These Terms to Your New Programs
+
+ If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+ To do so, attach the following notices to the program. It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+ <one line to give the program's name and a brief idea of what it does.>
+ Copyright (C) <year> <name of author>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+ Gnomovision version 69, Copyright (C) year name of author
+ Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+ This is free software, and you are welcome to redistribute it
+ under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License. Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary. Here is a sample; alter the names:
+
+ Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+ `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+ <signature of Ty Coon>, 1 April 1989
+ Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs. If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library. If this is what you want to do, use the GNU Library General
+Public License instead of this License.
diff --git a/bench/btl/README b/bench/btl/README
new file mode 100644
index 000000000..f3f5fb36f
--- /dev/null
+++ b/bench/btl/README
@@ -0,0 +1,154 @@
+Bench Template Library
+
+****************************************
+Introduction :
+
+The aim of this project is to compare the performance
+of available numerical libraries. The code is designed
+as generic and modular as possible. Thus, adding new
+numerical libraries or new numerical tests should
+require minimal effort.
+
+
+*****************************************
+
+Installation :
+
+BTL uses cmake / ctest:
+
+1 - create a build directory:
+
+ $ mkdir build
+ $ cd build
+
+2 - configure:
+
+ $ ccmake ..
+
+3 - run the bench using ctest:
+
+ $ ctest -V
+
+You can run the benchmarks only on libraries matching a given regular expression:
+ ctest -V -R <regexp>
+For instance:
+ ctest -V -R eigen2
+
+You can also select a given set of actions defining the environment variable BTL_CONFIG this way:
+ BTL_CONFIG="-a action1{:action2}*" ctest -V
+An exemple:
+ BTL_CONFIG="-a axpy:vector_matrix:trisolve:ata" ctest -V -R eigen2
+
+Finally, if bench results already exist (the bench*.dat files) then they merges by keeping the best for each matrix size. If you want to overwrite the previous ones you can simply add the "--overwrite" option:
+ BTL_CONFIG="-a axpy:vector_matrix:trisolve:ata --overwrite" ctest -V -R eigen2
+
+4 : Analyze the result. different data files (.dat) are produced in each libs directories.
+ If gnuplot is available, choose a directory name in the data directory to store the results and type:
+ $ cd data
+ $ mkdir my_directory
+ $ cp ../libs/*/*.dat my_directory
+ Build the data utilities in this (data) directory
+ make
+ Then you can look the raw data,
+ go_mean my_directory
+ or smooth the data first :
+ smooth_all.sh my_directory
+ go_mean my_directory_smooth
+
+
+*************************************************
+
+Files and directories :
+
+ generic_bench : all the bench sources common to all libraries
+
+ actions : sources for different action wrappers (axpy, matrix-matrix product) to be tested.
+
+ libs/* : bench sources specific to each tested libraries.
+
+ machine_dep : directory used to store machine specific Makefile.in
+
+ data : directory used to store gnuplot scripts and data analysis utilities
+
+**************************************************
+
+Principles : the code modularity is achieved by defining two concepts :
+
+ ****** Action concept : This is a class defining which kind
+ of test must be performed (e.g. a matrix_vector_product).
+ An Action should define the following methods :
+
+ *** Ctor using the size of the problem (matrix or vector size) as an argument
+ Action action(size);
+ *** initialize : this method initialize the calculation (e.g. initialize the matrices and vectors arguments)
+ action.initialize();
+ *** calculate : this method actually launch the calculation to be benchmarked
+ action.calculate;
+ *** nb_op_base() : this method returns the complexity of the calculate method (allowing the mflops evaluation)
+ *** name() : this method returns the name of the action (std::string)
+
+ ****** Interface concept : This is a class or namespace defining how to use a given library and
+ its specific containers (matrix and vector). Up to now an interface should following types
+
+ *** real_type : kind of float to be used (float or double)
+ *** stl_vector : must correspond to std::vector<real_type>
+ *** stl_matrix : must correspond to std::vector<stl_vector>
+ *** gene_vector : the vector type for this interface --> e.g. (real_type *) for the C_interface
+ *** gene_matrix : the matrix type for this interface --> e.g. (gene_vector *) for the C_interface
+
+ + the following common methods
+
+ *** free_matrix(gene_matrix & A, int N) dealocation of a N sized gene_matrix A
+ *** free_vector(gene_vector & B) dealocation of a N sized gene_vector B
+ *** matrix_from_stl(gene_matrix & A, stl_matrix & A_stl) copy the content of an stl_matrix A_stl into a gene_matrix A.
+ The allocation of A is done in this function.
+ *** vector_to_stl(gene_vector & B, stl_vector & B_stl) copy the content of an stl_vector B_stl into a gene_vector B.
+ The allocation of B is done in this function.
+ *** matrix_to_stl(gene_matrix & A, stl_matrix & A_stl) copy the content of an gene_matrix A into an stl_matrix A_stl.
+ The size of A_STL must corresponds to the size of A.
+ *** vector_to_stl(gene_vector & A, stl_vector & A_stl) copy the content of an gene_vector A into an stl_vector A_stl.
+ The size of B_STL must corresponds to the size of B.
+ *** copy_matrix(gene_matrix & source, gene_matrix & cible, int N) : copy the content of source in cible. Both source
+ and cible must be sized NxN.
+ *** copy_vector(gene_vector & source, gene_vector & cible, int N) : copy the content of source in cible. Both source
+ and cible must be sized N.
+
+ and the following method corresponding to the action one wants to be benchmarked :
+
+ *** matrix_vector_product(const gene_matrix & A, const gene_vector & B, gene_vector & X, int N)
+ *** matrix_matrix_product(const gene_matrix & A, const gene_matrix & B, gene_matrix & X, int N)
+ *** ata_product(const gene_matrix & A, gene_matrix & X, int N)
+ *** aat_product(const gene_matrix & A, gene_matrix & X, int N)
+ *** axpy(real coef, const gene_vector & X, gene_vector & Y, int N)
+
+ The bench algorithm (generic_bench/bench.hh) is templated with an action itself templated with
+ an interface. A typical main.cpp source stored in a given library directory libs/A_LIB
+ looks like :
+
+ bench< AN_ACTION < AN_INTERFACE > >( 10 , 1000 , 50 ) ;
+
+ this function will produce XY data file containing measured mflops as a function of the size for 50
+ sizes between 10 and 10000.
+
+ This algorithm can be adapted by providing a given Perf_Analyzer object which determines how the time
+ measurements must be done. For example, the X86_Perf_Analyzer use the asm rdtsc function and provides
+ a very fast and accurate (but less portable) timing method. The default is the Portable_Perf_Analyzer
+ so
+
+ bench< AN_ACTION < AN_INTERFACE > >( 10 , 1000 , 50 ) ;
+
+ is equivalent to
+
+ bench< Portable_Perf_Analyzer,AN_ACTION < AN_INTERFACE > >( 10 , 1000 , 50 ) ;
+
+ If your system supports it we suggest to use a mixed implementation (X86_perf_Analyzer+Portable_Perf_Analyzer).
+ replace
+ bench<Portable_Perf_Analyzer,Action>(size_min,size_max,nb_point);
+ with
+ bench<Mixed_Perf_Analyzer,Action>(size_min,size_max,nb_point);
+ in generic/bench.hh
+
+.
+
+
+
diff --git a/bench/btl/actions/action_aat_product.hh b/bench/btl/actions/action_aat_product.hh
new file mode 100644
index 000000000..aa5b35c94
--- /dev/null
+++ b/bench/btl/actions/action_aat_product.hh
@@ -0,0 +1,145 @@
+//=====================================================
+// File : action_aat_product.hh
+// Author : L. Plagne <laurent.plagne@edf.fr)>
+// Copyright (C) EDF R&D, lun sep 30 14:23:19 CEST 2002
+//=====================================================
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+//
+#ifndef ACTION_AAT_PRODUCT
+#define ACTION_AAT_PRODUCT
+#include "utilities.h"
+#include "STL_interface.hh"
+#include <string>
+#include "init/init_function.hh"
+#include "init/init_vector.hh"
+#include "init/init_matrix.hh"
+
+using namespace std;
+
+template<class Interface>
+class Action_aat_product {
+
+public :
+
+ // Ctor
+
+ Action_aat_product( int size ):_size(size)
+ {
+ MESSAGE("Action_aat_product Ctor");
+
+ // STL matrix and vector initialization
+
+ init_matrix<pseudo_random>(A_stl,_size);
+ init_matrix<null_function>(X_stl,_size);
+ init_matrix<null_function>(resu_stl,_size);
+
+ // generic matrix and vector initialization
+
+ Interface::matrix_from_stl(A_ref,A_stl);
+ Interface::matrix_from_stl(X_ref,X_stl);
+
+ Interface::matrix_from_stl(A,A_stl);
+ Interface::matrix_from_stl(X,X_stl);
+
+ }
+
+ // invalidate copy ctor
+
+ Action_aat_product( const Action_aat_product & )
+ {
+ INFOS("illegal call to Action_aat_product Copy Ctor");
+ exit(0);
+ }
+
+ // Dtor
+
+ ~Action_aat_product( void ){
+
+ MESSAGE("Action_aat_product Dtor");
+
+ // deallocation
+
+ Interface::free_matrix(A,_size);
+ Interface::free_matrix(X,_size);
+
+ Interface::free_matrix(A_ref,_size);
+ Interface::free_matrix(X_ref,_size);
+
+ }
+
+ // action name
+
+ static inline std::string name( void )
+ {
+ return "aat_"+Interface::name();
+ }
+
+ double nb_op_base( void ){
+ return double(_size)*double(_size)*double(_size);
+ }
+
+ inline void initialize( void ){
+
+ Interface::copy_matrix(A_ref,A,_size);
+ Interface::copy_matrix(X_ref,X,_size);
+
+ }
+
+ inline void calculate( void ) {
+
+ Interface::aat_product(A,X,_size);
+
+ }
+
+ void check_result( void ){
+ if (_size>128) return;
+ // calculation check
+
+ Interface::matrix_to_stl(X,resu_stl);
+
+ STL_interface<typename Interface::real_type>::aat_product(A_stl,X_stl,_size);
+
+ typename Interface::real_type error=
+ STL_interface<typename Interface::real_type>::norm_diff(X_stl,resu_stl);
+
+ if (error>1.e-6){
+ INFOS("WRONG CALCULATION...residual=" << error);
+ exit(1);
+ }
+
+ }
+
+private :
+
+ typename Interface::stl_matrix A_stl;
+ typename Interface::stl_matrix X_stl;
+ typename Interface::stl_matrix resu_stl;
+
+ typename Interface::gene_matrix A_ref;
+ typename Interface::gene_matrix X_ref;
+
+ typename Interface::gene_matrix A;
+ typename Interface::gene_matrix X;
+
+
+ int _size;
+
+};
+
+
+#endif
+
+
+
diff --git a/bench/btl/actions/action_ata_product.hh b/bench/btl/actions/action_ata_product.hh
new file mode 100644
index 000000000..04364fe67
--- /dev/null
+++ b/bench/btl/actions/action_ata_product.hh
@@ -0,0 +1,145 @@
+//=====================================================
+// File : action_ata_product.hh
+// Author : L. Plagne <laurent.plagne@edf.fr)>
+// Copyright (C) EDF R&D, lun sep 30 14:23:19 CEST 2002
+//=====================================================
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+//
+#ifndef ACTION_ATA_PRODUCT
+#define ACTION_ATA_PRODUCT
+#include "utilities.h"
+#include "STL_interface.hh"
+#include <string>
+#include "init/init_function.hh"
+#include "init/init_vector.hh"
+#include "init/init_matrix.hh"
+
+using namespace std;
+
+template<class Interface>
+class Action_ata_product {
+
+public :
+
+ // Ctor
+
+ Action_ata_product( int size ):_size(size)
+ {
+ MESSAGE("Action_ata_product Ctor");
+
+ // STL matrix and vector initialization
+
+ init_matrix<pseudo_random>(A_stl,_size);
+ init_matrix<null_function>(X_stl,_size);
+ init_matrix<null_function>(resu_stl,_size);
+
+ // generic matrix and vector initialization
+
+ Interface::matrix_from_stl(A_ref,A_stl);
+ Interface::matrix_from_stl(X_ref,X_stl);
+
+ Interface::matrix_from_stl(A,A_stl);
+ Interface::matrix_from_stl(X,X_stl);
+
+ }
+
+ // invalidate copy ctor
+
+ Action_ata_product( const Action_ata_product & )
+ {
+ INFOS("illegal call to Action_ata_product Copy Ctor");
+ exit(0);
+ }
+
+ // Dtor
+
+ ~Action_ata_product( void ){
+
+ MESSAGE("Action_ata_product Dtor");
+
+ // deallocation
+
+ Interface::free_matrix(A,_size);
+ Interface::free_matrix(X,_size);
+
+ Interface::free_matrix(A_ref,_size);
+ Interface::free_matrix(X_ref,_size);
+
+ }
+
+ // action name
+
+ static inline std::string name( void )
+ {
+ return "ata_"+Interface::name();
+ }
+
+ double nb_op_base( void ){
+ return 2.0*_size*_size*_size;
+ }
+
+ inline void initialize( void ){
+
+ Interface::copy_matrix(A_ref,A,_size);
+ Interface::copy_matrix(X_ref,X,_size);
+
+ }
+
+ inline void calculate( void ) {
+
+ Interface::ata_product(A,X,_size);
+
+ }
+
+ void check_result( void ){
+ if (_size>128) return;
+ // calculation check
+
+ Interface::matrix_to_stl(X,resu_stl);
+
+ STL_interface<typename Interface::real_type>::ata_product(A_stl,X_stl,_size);
+
+ typename Interface::real_type error=
+ STL_interface<typename Interface::real_type>::norm_diff(X_stl,resu_stl);
+
+ if (error>1.e-6){
+ INFOS("WRONG CALCULATION...residual=" << error);
+ exit(1);
+ }
+
+ }
+
+private :
+
+ typename Interface::stl_matrix A_stl;
+ typename Interface::stl_matrix X_stl;
+ typename Interface::stl_matrix resu_stl;
+
+ typename Interface::gene_matrix A_ref;
+ typename Interface::gene_matrix X_ref;
+
+ typename Interface::gene_matrix A;
+ typename Interface::gene_matrix X;
+
+
+ int _size;
+
+};
+
+
+#endif
+
+
+
diff --git a/bench/btl/actions/action_atv_product.hh b/bench/btl/actions/action_atv_product.hh
new file mode 100644
index 000000000..a8234514b
--- /dev/null
+++ b/bench/btl/actions/action_atv_product.hh
@@ -0,0 +1,134 @@
+//=====================================================
+// File : action_atv_product.hh
+// Author : L. Plagne <laurent.plagne@edf.fr)>
+// Copyright (C) EDF R&D, lun sep 30 14:23:19 CEST 2002
+//=====================================================
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+//
+#ifndef ACTION_ATV_PRODUCT
+#define ACTION_ATV_PRODUCT
+#include "utilities.h"
+#include "STL_interface.hh"
+#include <string>
+#include "init/init_function.hh"
+#include "init/init_vector.hh"
+#include "init/init_matrix.hh"
+
+using namespace std;
+
+template<class Interface>
+class Action_atv_product {
+
+public :
+
+ Action_atv_product( int size ) : _size(size)
+ {
+ MESSAGE("Action_atv_product Ctor");
+
+ // STL matrix and vector initialization
+
+ init_matrix<pseudo_random>(A_stl,_size);
+ init_vector<pseudo_random>(B_stl,_size);
+ init_vector<null_function>(X_stl,_size);
+ init_vector<null_function>(resu_stl,_size);
+
+ // generic matrix and vector initialization
+
+ Interface::matrix_from_stl(A_ref,A_stl);
+ Interface::vector_from_stl(B_ref,B_stl);
+ Interface::vector_from_stl(X_ref,X_stl);
+
+ Interface::matrix_from_stl(A,A_stl);
+ Interface::vector_from_stl(B,B_stl);
+ Interface::vector_from_stl(X,X_stl);
+ }
+
+ // invalidate copy ctor
+ Action_atv_product( const Action_atv_product & )
+ {
+ INFOS("illegal call to Action_atv_product Copy Ctor");
+ exit(1);
+ }
+
+ ~Action_atv_product( void )
+ {
+ MESSAGE("Action_atv_product Dtor");
+
+ Interface::free_matrix(A,_size);
+ Interface::free_vector(B);
+ Interface::free_vector(X);
+
+ Interface::free_matrix(A_ref,_size);
+ Interface::free_vector(B_ref);
+ Interface::free_vector(X_ref);
+ }
+
+ static inline std::string name() { return "atv_" + Interface::name(); }
+
+ double nb_op_base( void ) { return 2.0*_size*_size; }
+
+ inline void initialize( void ){
+ Interface::copy_matrix(A_ref,A,_size);
+ Interface::copy_vector(B_ref,B,_size);
+ Interface::copy_vector(X_ref,X,_size);
+ }
+
+ BTL_DONT_INLINE void calculate( void ) {
+ BTL_ASM_COMMENT("begin atv");
+ Interface::atv_product(A,B,X,_size);
+ BTL_ASM_COMMENT("end atv");
+ }
+
+ void check_result( void )
+ {
+ if (_size>128) return;
+ Interface::vector_to_stl(X,resu_stl);
+
+ STL_interface<typename Interface::real_type>::atv_product(A_stl,B_stl,X_stl,_size);
+
+ typename Interface::real_type error=
+ STL_interface<typename Interface::real_type>::norm_diff(X_stl,resu_stl);
+
+ if (error>1.e-6){
+ INFOS("WRONG CALCULATION...residual=" << error);
+ exit(1);
+ }
+ }
+
+private :
+
+ typename Interface::stl_matrix A_stl;
+ typename Interface::stl_vector B_stl;
+ typename Interface::stl_vector X_stl;
+ typename Interface::stl_vector resu_stl;
+
+ typename Interface::gene_matrix A_ref;
+ typename Interface::gene_vector B_ref;
+ typename Interface::gene_vector X_ref;
+
+ typename Interface::gene_matrix A;
+ typename Interface::gene_vector B;
+ typename Interface::gene_vector X;
+
+
+ int _size;
+
+};
+
+
+#endif
+
+
+
diff --git a/bench/btl/actions/action_axpby.hh b/bench/btl/actions/action_axpby.hh
new file mode 100644
index 000000000..98511ab6a
--- /dev/null
+++ b/bench/btl/actions/action_axpby.hh
@@ -0,0 +1,127 @@
+//=====================================================
+// File : action_axpby.hh
+// Copyright (C) 2008 Gael Guennebaud <gael.guennebaud@inria.fr>
+//=====================================================
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+//
+#ifndef ACTION_AXPBY
+#define ACTION_AXPBY
+#include "utilities.h"
+#include "STL_interface.hh"
+#include <string>
+#include "init/init_function.hh"
+#include "init/init_vector.hh"
+#include "init/init_matrix.hh"
+
+using namespace std;
+
+template<class Interface>
+class Action_axpby {
+
+public :
+
+ // Ctor
+ Action_axpby( int size ):_size(size),_alpha(0.5),_beta(0.95)
+ {
+ MESSAGE("Action_axpby Ctor");
+
+ // STL vector initialization
+ init_vector<pseudo_random>(X_stl,_size);
+ init_vector<pseudo_random>(Y_stl,_size);
+ init_vector<null_function>(resu_stl,_size);
+
+ // generic matrix and vector initialization
+ Interface::vector_from_stl(X_ref,X_stl);
+ Interface::vector_from_stl(Y_ref,Y_stl);
+
+ Interface::vector_from_stl(X,X_stl);
+ Interface::vector_from_stl(Y,Y_stl);
+ }
+
+ // invalidate copy ctor
+ Action_axpby( const Action_axpby & )
+ {
+ INFOS("illegal call to Action_axpby Copy Ctor");
+ exit(1);
+ }
+
+ // Dtor
+ ~Action_axpby( void ){
+ MESSAGE("Action_axpby Dtor");
+
+ // deallocation
+ Interface::free_vector(X_ref);
+ Interface::free_vector(Y_ref);
+
+ Interface::free_vector(X);
+ Interface::free_vector(Y);
+ }
+
+ // action name
+ static inline std::string name( void )
+ {
+ return "axpby_"+Interface::name();
+ }
+
+ double nb_op_base( void ){
+ return 3.0*_size;
+ }
+
+ inline void initialize( void ){
+ Interface::copy_vector(X_ref,X,_size);
+ Interface::copy_vector(Y_ref,Y,_size);
+ }
+
+ inline void calculate( void ) {
+ BTL_ASM_COMMENT("mybegin axpby");
+ Interface::axpby(_alpha,X,_beta,Y,_size);
+ BTL_ASM_COMMENT("myend axpby");
+ }
+
+ void check_result( void ){
+ if (_size>128) return;
+ // calculation check
+ Interface::vector_to_stl(Y,resu_stl);
+
+ STL_interface<typename Interface::real_type>::axpby(_alpha,X_stl,_beta,Y_stl,_size);
+
+ typename Interface::real_type error=
+ STL_interface<typename Interface::real_type>::norm_diff(Y_stl,resu_stl);
+
+ if (error>1.e-6){
+ INFOS("WRONG CALCULATION...residual=" << error);
+ exit(2);
+ }
+ }
+
+private :
+
+ typename Interface::stl_vector X_stl;
+ typename Interface::stl_vector Y_stl;
+ typename Interface::stl_vector resu_stl;
+
+ typename Interface::gene_vector X_ref;
+ typename Interface::gene_vector Y_ref;
+
+ typename Interface::gene_vector X;
+ typename Interface::gene_vector Y;
+
+ typename Interface::real_type _alpha;
+ typename Interface::real_type _beta;
+
+ int _size;
+};
+
+#endif
diff --git a/bench/btl/actions/action_axpy.hh b/bench/btl/actions/action_axpy.hh
new file mode 100644
index 000000000..e4cb3a5bd
--- /dev/null
+++ b/bench/btl/actions/action_axpy.hh
@@ -0,0 +1,139 @@
+//=====================================================
+// File : action_axpy.hh
+// Author : L. Plagne <laurent.plagne@edf.fr)>
+// Copyright (C) EDF R&D, lun sep 30 14:23:19 CEST 2002
+//=====================================================
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+//
+#ifndef ACTION_AXPY
+#define ACTION_AXPY
+#include "utilities.h"
+#include "STL_interface.hh"
+#include <string>
+#include "init/init_function.hh"
+#include "init/init_vector.hh"
+#include "init/init_matrix.hh"
+
+using namespace std;
+
+template<class Interface>
+class Action_axpy {
+
+public :
+
+ // Ctor
+
+ Action_axpy( int size ):_size(size),_coef(1.0)
+ {
+ MESSAGE("Action_axpy Ctor");
+
+ // STL vector initialization
+
+ init_vector<pseudo_random>(X_stl,_size);
+ init_vector<pseudo_random>(Y_stl,_size);
+ init_vector<null_function>(resu_stl,_size);
+
+ // generic matrix and vector initialization
+
+ Interface::vector_from_stl(X_ref,X_stl);
+ Interface::vector_from_stl(Y_ref,Y_stl);
+
+ Interface::vector_from_stl(X,X_stl);
+ Interface::vector_from_stl(Y,Y_stl);
+
+
+ }
+
+ // invalidate copy ctor
+
+ Action_axpy( const Action_axpy & )
+ {
+ INFOS("illegal call to Action_axpy Copy Ctor");
+ exit(1);
+ }
+
+ // Dtor
+
+ ~Action_axpy( void ){
+
+ MESSAGE("Action_axpy Dtor");
+
+ // deallocation
+
+ Interface::free_vector(X_ref);
+ Interface::free_vector(Y_ref);
+
+ Interface::free_vector(X);
+ Interface::free_vector(Y);
+ }
+
+ // action name
+
+ static inline std::string name( void )
+ {
+ return "axpy_"+Interface::name();
+ }
+
+ double nb_op_base( void ){
+ return 2.0*_size;
+ }
+
+ inline void initialize( void ){
+ Interface::copy_vector(X_ref,X,_size);
+ Interface::copy_vector(Y_ref,Y,_size);
+ }
+
+ inline void calculate( void ) {
+ BTL_ASM_COMMENT("mybegin axpy");
+ Interface::axpy(_coef,X,Y,_size);
+ BTL_ASM_COMMENT("myend axpy");
+ }
+
+ void check_result( void ){
+ if (_size>128) return;
+ // calculation check
+
+ Interface::vector_to_stl(Y,resu_stl);
+
+ STL_interface<typename Interface::real_type>::axpy(_coef,X_stl,Y_stl,_size);
+
+ typename Interface::real_type error=
+ STL_interface<typename Interface::real_type>::norm_diff(Y_stl,resu_stl);
+
+ if (error>1.e-6){
+ INFOS("WRONG CALCULATION...residual=" << error);
+ exit(0);
+ }
+
+ }
+
+private :
+
+ typename Interface::stl_vector X_stl;
+ typename Interface::stl_vector Y_stl;
+ typename Interface::stl_vector resu_stl;
+
+ typename Interface::gene_vector X_ref;
+ typename Interface::gene_vector Y_ref;
+
+ typename Interface::gene_vector X;
+ typename Interface::gene_vector Y;
+
+ typename Interface::real_type _coef;
+
+ int _size;
+};
+
+#endif
diff --git a/bench/btl/actions/action_cholesky.hh b/bench/btl/actions/action_cholesky.hh
new file mode 100644
index 000000000..5f66d113a
--- /dev/null
+++ b/bench/btl/actions/action_cholesky.hh
@@ -0,0 +1,128 @@
+//=====================================================
+// File : action_cholesky.hh
+// Copyright (C) 2008 Gael Guennebaud <gael.guennebaud@inria.fr>
+//=====================================================
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+//
+#ifndef ACTION_CHOLESKY
+#define ACTION_CHOLESKY
+#include "utilities.h"
+#include "STL_interface.hh"
+#include <string>
+#include "init/init_function.hh"
+#include "init/init_vector.hh"
+#include "init/init_matrix.hh"
+
+using namespace std;
+
+template<class Interface>
+class Action_cholesky {
+
+public :
+
+ // Ctor
+
+ Action_cholesky( int size ):_size(size)
+ {
+ MESSAGE("Action_cholesky Ctor");
+
+ // STL mat/vec initialization
+ init_matrix_symm<pseudo_random>(X_stl,_size);
+ init_matrix<null_function>(C_stl,_size);
+
+ // make sure X is invertible
+ for (int i=0; i<_size; ++i)
+ X_stl[i][i] = std::abs(X_stl[i][i]) * 1e2 + 100;
+
+ // generic matrix and vector initialization
+ Interface::matrix_from_stl(X_ref,X_stl);
+ Interface::matrix_from_stl(X,X_stl);
+ Interface::matrix_from_stl(C,C_stl);
+
+ _cost = 0;
+ for (int j=0; j<_size; ++j)
+ {
+ double r = std::max(_size - j -1,0);
+ _cost += 2*(r*j+r+j);
+ }
+ }
+
+ // invalidate copy ctor
+
+ Action_cholesky( const Action_cholesky & )
+ {
+ INFOS("illegal call to Action_cholesky Copy Ctor");
+ exit(1);
+ }
+
+ // Dtor
+
+ ~Action_cholesky( void ){
+
+ MESSAGE("Action_cholesky Dtor");
+
+ // deallocation
+ Interface::free_matrix(X_ref,_size);
+ Interface::free_matrix(X,_size);
+ Interface::free_matrix(C,_size);
+ }
+
+ // action name
+
+ static inline std::string name( void )
+ {
+ return "cholesky_"+Interface::name();
+ }
+
+ double nb_op_base( void ){
+ return _cost;
+ }
+
+ inline void initialize( void ){
+ Interface::copy_matrix(X_ref,X,_size);
+ }
+
+ inline void calculate( void ) {
+ Interface::cholesky(X,C,_size);
+ }
+
+ void check_result( void ){
+ // calculation check
+// STL_interface<typename Interface::real_type>::cholesky(X_stl,C_stl,_size);
+//
+// typename Interface::real_type error=
+// STL_interface<typename Interface::real_type>::norm_diff(C_stl,resu_stl);
+//
+// if (error>1.e-6){
+// INFOS("WRONG CALCULATION...residual=" << error);
+// exit(0);
+// }
+
+ }
+
+private :
+
+ typename Interface::stl_matrix X_stl;
+ typename Interface::stl_matrix C_stl;
+
+ typename Interface::gene_matrix X_ref;
+ typename Interface::gene_matrix X;
+ typename Interface::gene_matrix C;
+
+ int _size;
+ double _cost;
+};
+
+#endif
diff --git a/bench/btl/actions/action_ger.hh b/bench/btl/actions/action_ger.hh
new file mode 100644
index 000000000..dc766efc5
--- /dev/null
+++ b/bench/btl/actions/action_ger.hh
@@ -0,0 +1,128 @@
+
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+//
+#ifndef ACTION_GER
+#define ACTION_GER
+#include "utilities.h"
+#include "STL_interface.hh"
+#include <string>
+#include "init/init_function.hh"
+#include "init/init_vector.hh"
+#include "init/init_matrix.hh"
+
+using namespace std;
+
+template<class Interface>
+class Action_ger {
+
+public :
+
+ // Ctor
+ BTL_DONT_INLINE Action_ger( int size ):_size(size)
+ {
+ MESSAGE("Action_ger Ctor");
+
+ // STL matrix and vector initialization
+ typename Interface::stl_matrix tmp;
+ init_matrix<pseudo_random>(A_stl,_size);
+ init_vector<pseudo_random>(B_stl,_size);
+ init_vector<pseudo_random>(X_stl,_size);
+ init_vector<null_function>(resu_stl,_size);
+
+ // generic matrix and vector initialization
+ Interface::matrix_from_stl(A_ref,A_stl);
+ Interface::matrix_from_stl(A,A_stl);
+ Interface::vector_from_stl(B_ref,B_stl);
+ Interface::vector_from_stl(B,B_stl);
+ Interface::vector_from_stl(X_ref,X_stl);
+ Interface::vector_from_stl(X,X_stl);
+ }
+
+ // invalidate copy ctor
+ Action_ger( const Action_ger & )
+ {
+ INFOS("illegal call to Action_ger Copy Ctor");
+ exit(1);
+ }
+
+ // Dtor
+ BTL_DONT_INLINE ~Action_ger( void ){
+ MESSAGE("Action_ger Dtor");
+ Interface::free_matrix(A,_size);
+ Interface::free_vector(B);
+ Interface::free_vector(X);
+ Interface::free_matrix(A_ref,_size);
+ Interface::free_vector(B_ref);
+ Interface::free_vector(X_ref);
+
+ }
+
+ // action name
+ static inline std::string name( void )
+ {
+ return "ger_" + Interface::name();
+ }
+
+ double nb_op_base( void ){
+ return 2.0*_size*_size;
+ }
+
+ BTL_DONT_INLINE void initialize( void ){
+ Interface::copy_matrix(A_ref,A,_size);
+ Interface::copy_vector(B_ref,B,_size);
+ Interface::copy_vector(X_ref,X,_size);
+ }
+
+ BTL_DONT_INLINE void calculate( void ) {
+ BTL_ASM_COMMENT("#begin ger");
+ Interface::ger(A,B,X,_size);
+ BTL_ASM_COMMENT("end ger");
+ }
+
+ BTL_DONT_INLINE void check_result( void ){
+ // calculation check
+ Interface::vector_to_stl(X,resu_stl);
+
+ STL_interface<typename Interface::real_type>::ger(A_stl,B_stl,X_stl,_size);
+
+ typename Interface::real_type error=
+ STL_interface<typename Interface::real_type>::norm_diff(X_stl,resu_stl);
+
+ if (error>1.e-3){
+ INFOS("WRONG CALCULATION...residual=" << error);
+// exit(0);
+ }
+
+ }
+
+private :
+
+ typename Interface::stl_matrix A_stl;
+ typename Interface::stl_vector B_stl;
+ typename Interface::stl_vector X_stl;
+ typename Interface::stl_vector resu_stl;
+
+ typename Interface::gene_matrix A_ref;
+ typename Interface::gene_vector B_ref;
+ typename Interface::gene_vector X_ref;
+
+ typename Interface::gene_matrix A;
+ typename Interface::gene_vector B;
+ typename Interface::gene_vector X;
+
+ int _size;
+};
+
+
+#endif
diff --git a/bench/btl/actions/action_hessenberg.hh b/bench/btl/actions/action_hessenberg.hh
new file mode 100644
index 000000000..2100ebd89
--- /dev/null
+++ b/bench/btl/actions/action_hessenberg.hh
@@ -0,0 +1,233 @@
+//=====================================================
+// File : action_hessenberg.hh
+// Copyright (C) 2008 Gael Guennebaud <gael.guennebaud@inria.fr>
+//=====================================================
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+//
+#ifndef ACTION_HESSENBERG
+#define ACTION_HESSENBERG
+#include "utilities.h"
+#include "STL_interface.hh"
+#include <string>
+#include "init/init_function.hh"
+#include "init/init_vector.hh"
+#include "init/init_matrix.hh"
+
+using namespace std;
+
+template<class Interface>
+class Action_hessenberg {
+
+public :
+
+ // Ctor
+
+ Action_hessenberg( int size ):_size(size)
+ {
+ MESSAGE("Action_hessenberg Ctor");
+
+ // STL vector initialization
+ init_matrix<pseudo_random>(X_stl,_size);
+
+ init_matrix<null_function>(C_stl,_size);
+ init_matrix<null_function>(resu_stl,_size);
+
+ // generic matrix and vector initialization
+ Interface::matrix_from_stl(X_ref,X_stl);
+ Interface::matrix_from_stl(X,X_stl);
+ Interface::matrix_from_stl(C,C_stl);
+
+ _cost = 0;
+ for (int j=0; j<_size-2; ++j)
+ {
+ double r = std::max(0,_size-j-1);
+ double b = std::max(0,_size-j-2);
+ _cost += 6 + 3*b + r*r*4 + r*_size*4;
+ }
+ }
+
+ // invalidate copy ctor
+
+ Action_hessenberg( const Action_hessenberg & )
+ {
+ INFOS("illegal call to Action_hessenberg Copy Ctor");
+ exit(1);
+ }
+
+ // Dtor
+
+ ~Action_hessenberg( void ){
+
+ MESSAGE("Action_hessenberg Dtor");
+
+ // deallocation
+ Interface::free_matrix(X_ref,_size);
+ Interface::free_matrix(X,_size);
+ Interface::free_matrix(C,_size);
+ }
+
+ // action name
+
+ static inline std::string name( void )
+ {
+ return "hessenberg_"+Interface::name();
+ }
+
+ double nb_op_base( void ){
+ return _cost;
+ }
+
+ inline void initialize( void ){
+ Interface::copy_matrix(X_ref,X,_size);
+ }
+
+ inline void calculate( void ) {
+ Interface::hessenberg(X,C,_size);
+ }
+
+ void check_result( void ){
+ // calculation check
+ Interface::matrix_to_stl(C,resu_stl);
+
+// STL_interface<typename Interface::real_type>::hessenberg(X_stl,C_stl,_size);
+//
+// typename Interface::real_type error=
+// STL_interface<typename Interface::real_type>::norm_diff(C_stl,resu_stl);
+//
+// if (error>1.e-6){
+// INFOS("WRONG CALCULATION...residual=" << error);
+// exit(0);
+// }
+
+ }
+
+private :
+
+ typename Interface::stl_matrix X_stl;
+ typename Interface::stl_matrix C_stl;
+ typename Interface::stl_matrix resu_stl;
+
+ typename Interface::gene_matrix X_ref;
+ typename Interface::gene_matrix X;
+ typename Interface::gene_matrix C;
+
+ int _size;
+ double _cost;
+};
+
+template<class Interface>
+class Action_tridiagonalization {
+
+public :
+
+ // Ctor
+
+ Action_tridiagonalization( int size ):_size(size)
+ {
+ MESSAGE("Action_tridiagonalization Ctor");
+
+ // STL vector initialization
+ init_matrix<pseudo_random>(X_stl,_size);
+
+ for(int i=0; i<_size; ++i)
+ {
+ for(int j=0; j<i; ++j)
+ X_stl[i][j] = X_stl[j][i];
+ }
+
+ init_matrix<null_function>(C_stl,_size);
+ init_matrix<null_function>(resu_stl,_size);
+
+ // generic matrix and vector initialization
+ Interface::matrix_from_stl(X_ref,X_stl);
+ Interface::matrix_from_stl(X,X_stl);
+ Interface::matrix_from_stl(C,C_stl);
+
+ _cost = 0;
+ for (int j=0; j<_size-2; ++j)
+ {
+ double r = std::max(0,_size-j-1);
+ double b = std::max(0,_size-j-2);
+ _cost += 6. + 3.*b + r*r*8.;
+ }
+ }
+
+ // invalidate copy ctor
+
+ Action_tridiagonalization( const Action_tridiagonalization & )
+ {
+ INFOS("illegal call to Action_tridiagonalization Copy Ctor");
+ exit(1);
+ }
+
+ // Dtor
+
+ ~Action_tridiagonalization( void ){
+
+ MESSAGE("Action_tridiagonalization Dtor");
+
+ // deallocation
+ Interface::free_matrix(X_ref,_size);
+ Interface::free_matrix(X,_size);
+ Interface::free_matrix(C,_size);
+ }
+
+ // action name
+
+ static inline std::string name( void ) { return "tridiagonalization_"+Interface::name(); }
+
+ double nb_op_base( void ){
+ return _cost;
+ }
+
+ inline void initialize( void ){
+ Interface::copy_matrix(X_ref,X,_size);
+ }
+
+ inline void calculate( void ) {
+ Interface::tridiagonalization(X,C,_size);
+ }
+
+ void check_result( void ){
+ // calculation check
+ Interface::matrix_to_stl(C,resu_stl);
+
+// STL_interface<typename Interface::real_type>::tridiagonalization(X_stl,C_stl,_size);
+//
+// typename Interface::real_type error=
+// STL_interface<typename Interface::real_type>::norm_diff(C_stl,resu_stl);
+//
+// if (error>1.e-6){
+// INFOS("WRONG CALCULATION...residual=" << error);
+// exit(0);
+// }
+
+ }
+
+private :
+
+ typename Interface::stl_matrix X_stl;
+ typename Interface::stl_matrix C_stl;
+ typename Interface::stl_matrix resu_stl;
+
+ typename Interface::gene_matrix X_ref;
+ typename Interface::gene_matrix X;
+ typename Interface::gene_matrix C;
+
+ int _size;
+ double _cost;
+};
+
+#endif
diff --git a/bench/btl/actions/action_lu_decomp.hh b/bench/btl/actions/action_lu_decomp.hh
new file mode 100644
index 000000000..2448e82c4
--- /dev/null
+++ b/bench/btl/actions/action_lu_decomp.hh
@@ -0,0 +1,124 @@
+//=====================================================
+// File : action_lu_decomp.hh
+// Copyright (C) 2008 Gael Guennebaud <gael.guennebaud@inria.fr>
+//=====================================================
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+//
+#ifndef ACTION_LU_DECOMP
+#define ACTION_LU_DECOMP
+#include "utilities.h"
+#include "STL_interface.hh"
+#include <string>
+#include "init/init_function.hh"
+#include "init/init_vector.hh"
+#include "init/init_matrix.hh"
+
+using namespace std;
+
+template<class Interface>
+class Action_lu_decomp {
+
+public :
+
+ // Ctor
+
+ Action_lu_decomp( int size ):_size(size)
+ {
+ MESSAGE("Action_lu_decomp Ctor");
+
+ // STL vector initialization
+ init_matrix<pseudo_random>(X_stl,_size);
+
+ init_matrix<null_function>(C_stl,_size);
+ init_matrix<null_function>(resu_stl,_size);
+
+ // generic matrix and vector initialization
+ Interface::matrix_from_stl(X_ref,X_stl);
+ Interface::matrix_from_stl(X,X_stl);
+ Interface::matrix_from_stl(C,C_stl);
+
+ _cost = 2.0*size*size*size/3.0 + size*size;
+ }
+
+ // invalidate copy ctor
+
+ Action_lu_decomp( const Action_lu_decomp & )
+ {
+ INFOS("illegal call to Action_lu_decomp Copy Ctor");
+ exit(1);
+ }
+
+ // Dtor
+
+ ~Action_lu_decomp( void ){
+
+ MESSAGE("Action_lu_decomp Dtor");
+
+ // deallocation
+ Interface::free_matrix(X_ref,_size);
+ Interface::free_matrix(X,_size);
+ Interface::free_matrix(C,_size);
+ }
+
+ // action name
+
+ static inline std::string name( void )
+ {
+ return "complete_lu_decomp_"+Interface::name();
+ }
+
+ double nb_op_base( void ){
+ return _cost;
+ }
+
+ inline void initialize( void ){
+ Interface::copy_matrix(X_ref,X,_size);
+ }
+
+ inline void calculate( void ) {
+ Interface::lu_decomp(X,C,_size);
+ }
+
+ void check_result( void ){
+ // calculation check
+ Interface::matrix_to_stl(C,resu_stl);
+
+// STL_interface<typename Interface::real_type>::lu_decomp(X_stl,C_stl,_size);
+//
+// typename Interface::real_type error=
+// STL_interface<typename Interface::real_type>::norm_diff(C_stl,resu_stl);
+//
+// if (error>1.e-6){
+// INFOS("WRONG CALCULATION...residual=" << error);
+// exit(0);
+// }
+
+ }
+
+private :
+
+ typename Interface::stl_matrix X_stl;
+ typename Interface::stl_matrix C_stl;
+ typename Interface::stl_matrix resu_stl;
+
+ typename Interface::gene_matrix X_ref;
+ typename Interface::gene_matrix X;
+ typename Interface::gene_matrix C;
+
+ int _size;
+ double _cost;
+};
+
+#endif
diff --git a/bench/btl/actions/action_lu_solve.hh b/bench/btl/actions/action_lu_solve.hh
new file mode 100644
index 000000000..5a81e6341
--- /dev/null
+++ b/bench/btl/actions/action_lu_solve.hh
@@ -0,0 +1,136 @@
+//=====================================================
+// File : action_lu_solve.hh
+// Author : L. Plagne <laurent.plagne@edf.fr)>
+// Copyright (C) EDF R&D, lun sep 30 14:23:19 CEST 2002
+//=====================================================
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+//
+#ifndef ACTION_LU_SOLVE
+#define ACTION_LU_SOLVE
+#include "utilities.h"
+#include "STL_interface.hh"
+#include <string>
+#include "init/init_function.hh"
+#include "init/init_vector.hh"
+#include "init/init_matrix.hh"
+
+using namespace std;
+
+template<class Interface>
+class Action_lu_solve
+{
+
+public :
+
+ static inline std::string name( void )
+ {
+ return "lu_solve_"+Interface::name();
+ }
+
+ static double nb_op_base(int size){
+ return 2.0*size*size*size/3.0; // questionable but not really important
+ }
+
+
+ static double calculate( int nb_calc, int size ) {
+
+ // STL matrix and vector initialization
+
+ typename Interface::stl_matrix A_stl;
+ typename Interface::stl_vector B_stl;
+ typename Interface::stl_vector X_stl;
+
+ init_matrix<pseudo_random>(A_stl,size);
+ init_vector<pseudo_random>(B_stl,size);
+ init_vector<null_function>(X_stl,size);
+
+ // generic matrix and vector initialization
+
+ typename Interface::gene_matrix A;
+ typename Interface::gene_vector B;
+ typename Interface::gene_vector X;
+
+ typename Interface::gene_matrix LU;
+
+ Interface::matrix_from_stl(A,A_stl);
+ Interface::vector_from_stl(B,B_stl);
+ Interface::vector_from_stl(X,X_stl);
+ Interface::matrix_from_stl(LU,A_stl);
+
+ // local variable :
+
+ typename Interface::Pivot_Vector pivot; // pivot vector
+ Interface::new_Pivot_Vector(pivot,size);
+
+ // timer utilities
+
+ Portable_Timer chronos;
+
+ // time measurement
+
+ chronos.start();
+
+ for (int ii=0;ii<nb_calc;ii++){
+
+ // LU factorization
+ Interface::copy_matrix(A,LU,size);
+ Interface::LU_factor(LU,pivot,size);
+
+ // LU solve
+
+ Interface::LU_solve(LU,pivot,B,X,size);
+
+ }
+
+ // Time stop
+
+ chronos.stop();
+
+ double time=chronos.user_time();
+
+ // check result :
+
+ typename Interface::stl_vector B_new_stl(size);
+ Interface::vector_to_stl(X,X_stl);
+
+ STL_interface<typename Interface::real_type>::matrix_vector_product(A_stl,X_stl,B_new_stl,size);
+
+ typename Interface::real_type error=
+ STL_interface<typename Interface::real_type>::norm_diff(B_stl,B_new_stl);
+
+ if (error>1.e-5){
+ INFOS("WRONG CALCULATION...residual=" << error);
+ STL_interface<typename Interface::real_type>::display_vector(B_stl);
+ STL_interface<typename Interface::real_type>::display_vector(B_new_stl);
+ exit(0);
+ }
+
+ // deallocation and return time
+
+ Interface::free_matrix(A,size);
+ Interface::free_vector(B);
+ Interface::free_vector(X);
+ Interface::free_Pivot_Vector(pivot);
+
+ return time;
+ }
+
+};
+
+
+#endif
+
+
+
diff --git a/bench/btl/actions/action_matrix_matrix_product.hh b/bench/btl/actions/action_matrix_matrix_product.hh
new file mode 100644
index 000000000..f65ee0529
--- /dev/null
+++ b/bench/btl/actions/action_matrix_matrix_product.hh
@@ -0,0 +1,150 @@
+//=====================================================
+// File : action_matrix_matrix_product.hh
+// Author : L. Plagne <laurent.plagne@edf.fr)>
+// Copyright (C) EDF R&D, lun sep 30 14:23:19 CEST 2002
+//=====================================================
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+//
+#ifndef ACTION_MATRIX_MATRIX_PRODUCT
+#define ACTION_MATRIX_MATRIX_PRODUCT
+#include "utilities.h"
+#include "STL_interface.hh"
+#include <string>
+#include "init/init_function.hh"
+#include "init/init_vector.hh"
+#include "init/init_matrix.hh"
+
+using namespace std;
+
+template<class Interface>
+class Action_matrix_matrix_product {
+
+public :
+
+ // Ctor
+
+ Action_matrix_matrix_product( int size ):_size(size)
+ {
+ MESSAGE("Action_matrix_matrix_product Ctor");
+
+ // STL matrix and vector initialization
+
+ init_matrix<pseudo_random>(A_stl,_size);
+ init_matrix<pseudo_random>(B_stl,_size);
+ init_matrix<null_function>(X_stl,_size);
+ init_matrix<null_function>(resu_stl,_size);
+
+ // generic matrix and vector initialization
+
+ Interface::matrix_from_stl(A_ref,A_stl);
+ Interface::matrix_from_stl(B_ref,B_stl);
+ Interface::matrix_from_stl(X_ref,X_stl);
+
+ Interface::matrix_from_stl(A,A_stl);
+ Interface::matrix_from_stl(B,B_stl);
+ Interface::matrix_from_stl(X,X_stl);
+
+ }
+
+ // invalidate copy ctor
+
+ Action_matrix_matrix_product( const Action_matrix_matrix_product & )
+ {
+ INFOS("illegal call to Action_matrix_matrix_product Copy Ctor");
+ exit(0);
+ }
+
+ // Dtor
+
+ ~Action_matrix_matrix_product( void ){
+
+ MESSAGE("Action_matrix_matrix_product Dtor");
+
+ // deallocation
+
+ Interface::free_matrix(A,_size);
+ Interface::free_matrix(B,_size);
+ Interface::free_matrix(X,_size);
+
+ Interface::free_matrix(A_ref,_size);
+ Interface::free_matrix(B_ref,_size);
+ Interface::free_matrix(X_ref,_size);
+
+ }
+
+ // action name
+
+ static inline std::string name( void )
+ {
+ return "matrix_matrix_"+Interface::name();
+ }
+
+ double nb_op_base( void ){
+ return 2.0*_size*_size*_size;
+ }
+
+ inline void initialize( void ){
+
+ Interface::copy_matrix(A_ref,A,_size);
+ Interface::copy_matrix(B_ref,B,_size);
+ Interface::copy_matrix(X_ref,X,_size);
+
+ }
+
+ inline void calculate( void ) {
+ Interface::matrix_matrix_product(A,B,X,_size);
+ }
+
+ void check_result( void ){
+
+ // calculation check
+ if (_size<200)
+ {
+ Interface::matrix_to_stl(X,resu_stl);
+ STL_interface<typename Interface::real_type>::matrix_matrix_product(A_stl,B_stl,X_stl,_size);
+ typename Interface::real_type error=
+ STL_interface<typename Interface::real_type>::norm_diff(X_stl,resu_stl);
+ if (error>1.e-6){
+ INFOS("WRONG CALCULATION...residual=" << error);
+ exit(1);
+ }
+ }
+ }
+
+private :
+
+ typename Interface::stl_matrix A_stl;
+ typename Interface::stl_matrix B_stl;
+ typename Interface::stl_matrix X_stl;
+ typename Interface::stl_matrix resu_stl;
+
+ typename Interface::gene_matrix A_ref;
+ typename Interface::gene_matrix B_ref;
+ typename Interface::gene_matrix X_ref;
+
+ typename Interface::gene_matrix A;
+ typename Interface::gene_matrix B;
+ typename Interface::gene_matrix X;
+
+
+ int _size;
+
+};
+
+
+#endif
+
+
+
diff --git a/bench/btl/actions/action_matrix_matrix_product_bis.hh b/bench/btl/actions/action_matrix_matrix_product_bis.hh
new file mode 100644
index 000000000..29c10a6e2
--- /dev/null
+++ b/bench/btl/actions/action_matrix_matrix_product_bis.hh
@@ -0,0 +1,152 @@
+//=====================================================
+// File : action_matrix_matrix_product_bis.hh
+// Author : L. Plagne <laurent.plagne@edf.fr)>
+// Copyright (C) EDF R&D, lun sep 30 14:23:19 CEST 2002
+//=====================================================
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+//
+#ifndef ACTION_MATRIX_MATRIX_PRODUCT_BIS
+#define ACTION_MATRIX_MATRIX_PRODUCT_BIS
+#include "utilities.h"
+#include "STL_interface.hh"
+#include "STL_timer.hh"
+#include <string>
+#include "init_function.hh"
+#include "init_vector.hh"
+#include "init_matrix.hh"
+
+using namespace std;
+
+template<class Interface>
+class Action_matrix_matrix_product_bis {
+
+public :
+
+ static inline std::string name( void )
+ {
+ return "matrix_matrix_"+Interface::name();
+ }
+
+ static double nb_op_base(int size){
+ return 2.0*size*size*size;
+ }
+
+ static double calculate( int nb_calc, int size ) {
+
+ // STL matrix and vector initialization
+
+ typename Interface::stl_matrix A_stl;
+ typename Interface::stl_matrix B_stl;
+ typename Interface::stl_matrix X_stl;
+
+ init_matrix<pseudo_random>(A_stl,size);
+ init_matrix<pseudo_random>(B_stl,size);
+ init_matrix<null_function>(X_stl,size);
+
+ // generic matrix and vector initialization
+
+ typename Interface::gene_matrix A_ref;
+ typename Interface::gene_matrix B_ref;
+ typename Interface::gene_matrix X_ref;
+
+ typename Interface::gene_matrix A;
+ typename Interface::gene_matrix B;
+ typename Interface::gene_matrix X;
+
+
+ Interface::matrix_from_stl(A_ref,A_stl);
+ Interface::matrix_from_stl(B_ref,B_stl);
+ Interface::matrix_from_stl(X_ref,X_stl);
+
+ Interface::matrix_from_stl(A,A_stl);
+ Interface::matrix_from_stl(B,B_stl);
+ Interface::matrix_from_stl(X,X_stl);
+
+
+ // STL_timer utilities
+
+ STL_timer chronos;
+
+ // Baseline evaluation
+
+ chronos.start_baseline(nb_calc);
+
+ do {
+
+ Interface::copy_matrix(A_ref,A,size);
+ Interface::copy_matrix(B_ref,B,size);
+ Interface::copy_matrix(X_ref,X,size);
+
+
+ // Interface::matrix_matrix_product(A,B,X,size); This line must be commented !!!!
+ }
+ while(chronos.check());
+
+ chronos.report(true);
+
+ // Time measurement
+
+ chronos.start(nb_calc);
+
+ do {
+
+ Interface::copy_matrix(A_ref,A,size);
+ Interface::copy_matrix(B_ref,B,size);
+ Interface::copy_matrix(X_ref,X,size);
+
+ Interface::matrix_matrix_product(A,B,X,size); // here it is not commented !!!!
+ }
+ while(chronos.check());
+
+ chronos.report(true);
+
+ double time=chronos.calculated_time/2000.0;
+
+ // calculation check
+
+ typename Interface::stl_matrix resu_stl(size);
+
+ Interface::matrix_to_stl(X,resu_stl);
+
+ STL_interface<typename Interface::real_type>::matrix_matrix_product(A_stl,B_stl,X_stl,size);
+
+ typename Interface::real_type error=
+ STL_interface<typename Interface::real_type>::norm_diff(X_stl,resu_stl);
+
+ if (error>1.e-6){
+ INFOS("WRONG CALCULATION...residual=" << error);
+ exit(1);
+ }
+
+ // deallocation and return time
+
+ Interface::free_matrix(A,size);
+ Interface::free_matrix(B,size);
+ Interface::free_matrix(X,size);
+
+ Interface::free_matrix(A_ref,size);
+ Interface::free_matrix(B_ref,size);
+ Interface::free_matrix(X_ref,size);
+
+ return time;
+ }
+
+};
+
+
+#endif
+
+
+
diff --git a/bench/btl/actions/action_matrix_vector_product.hh b/bench/btl/actions/action_matrix_vector_product.hh
new file mode 100644
index 000000000..8bab79d18
--- /dev/null
+++ b/bench/btl/actions/action_matrix_vector_product.hh
@@ -0,0 +1,153 @@
+//=====================================================
+// File : action_matrix_vector_product.hh
+// Author : L. Plagne <laurent.plagne@edf.fr)>
+// Copyright (C) EDF R&D, lun sep 30 14:23:19 CEST 2002
+//=====================================================
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+//
+#ifndef ACTION_MATRIX_VECTOR_PRODUCT
+#define ACTION_MATRIX_VECTOR_PRODUCT
+#include "utilities.h"
+#include "STL_interface.hh"
+#include <string>
+#include "init/init_function.hh"
+#include "init/init_vector.hh"
+#include "init/init_matrix.hh"
+
+using namespace std;
+
+template<class Interface>
+class Action_matrix_vector_product {
+
+public :
+
+ // Ctor
+
+ BTL_DONT_INLINE Action_matrix_vector_product( int size ):_size(size)
+ {
+ MESSAGE("Action_matrix_vector_product Ctor");
+
+ // STL matrix and vector initialization
+
+ init_matrix<pseudo_random>(A_stl,_size);
+ init_vector<pseudo_random>(B_stl,_size);
+ init_vector<null_function>(X_stl,_size);
+ init_vector<null_function>(resu_stl,_size);
+
+ // generic matrix and vector initialization
+
+ Interface::matrix_from_stl(A_ref,A_stl);
+ Interface::matrix_from_stl(A,A_stl);
+ Interface::vector_from_stl(B_ref,B_stl);
+ Interface::vector_from_stl(B,B_stl);
+ Interface::vector_from_stl(X_ref,X_stl);
+ Interface::vector_from_stl(X,X_stl);
+
+ }
+
+ // invalidate copy ctor
+
+ Action_matrix_vector_product( const Action_matrix_vector_product & )
+ {
+ INFOS("illegal call to Action_matrix_vector_product Copy Ctor");
+ exit(1);
+ }
+
+ // Dtor
+
+ BTL_DONT_INLINE ~Action_matrix_vector_product( void ){
+
+ MESSAGE("Action_matrix_vector_product Dtor");
+
+ // deallocation
+
+ Interface::free_matrix(A,_size);
+ Interface::free_vector(B);
+ Interface::free_vector(X);
+
+ Interface::free_matrix(A_ref,_size);
+ Interface::free_vector(B_ref);
+ Interface::free_vector(X_ref);
+
+ }
+
+ // action name
+
+ static inline std::string name( void )
+ {
+ return "matrix_vector_" + Interface::name();
+ }
+
+ double nb_op_base( void ){
+ return 2.0*_size*_size;
+ }
+
+ BTL_DONT_INLINE void initialize( void ){
+
+ Interface::copy_matrix(A_ref,A,_size);
+ Interface::copy_vector(B_ref,B,_size);
+ Interface::copy_vector(X_ref,X,_size);
+
+ }
+
+ BTL_DONT_INLINE void calculate( void ) {
+ BTL_ASM_COMMENT("#begin matrix_vector_product");
+ Interface::matrix_vector_product(A,B,X,_size);
+ BTL_ASM_COMMENT("end matrix_vector_product");
+ }
+
+ BTL_DONT_INLINE void check_result( void ){
+
+ // calculation check
+
+ Interface::vector_to_stl(X,resu_stl);
+
+ STL_interface<typename Interface::real_type>::matrix_vector_product(A_stl,B_stl,X_stl,_size);
+
+ typename Interface::real_type error=
+ STL_interface<typename Interface::real_type>::norm_diff(X_stl,resu_stl);
+
+ if (error>1.e-5){
+ INFOS("WRONG CALCULATION...residual=" << error);
+ exit(0);
+ }
+
+ }
+
+private :
+
+ typename Interface::stl_matrix A_stl;
+ typename Interface::stl_vector B_stl;
+ typename Interface::stl_vector X_stl;
+ typename Interface::stl_vector resu_stl;
+
+ typename Interface::gene_matrix A_ref;
+ typename Interface::gene_vector B_ref;
+ typename Interface::gene_vector X_ref;
+
+ typename Interface::gene_matrix A;
+ typename Interface::gene_vector B;
+ typename Interface::gene_vector X;
+
+
+ int _size;
+
+};
+
+
+#endif
+
+
+
diff --git a/bench/btl/actions/action_partial_lu.hh b/bench/btl/actions/action_partial_lu.hh
new file mode 100644
index 000000000..770ea1d1e
--- /dev/null
+++ b/bench/btl/actions/action_partial_lu.hh
@@ -0,0 +1,125 @@
+//=====================================================
+// File : action_lu_decomp.hh
+// Copyright (C) 2008 Gael Guennebaud <gael.guennebaud@inria.fr>
+//=====================================================
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+//
+#ifndef ACTION_PARTIAL_LU
+#define ACTION_PARTIAL_LU
+#include "utilities.h"
+#include "STL_interface.hh"
+#include <string>
+#include "init/init_function.hh"
+#include "init/init_vector.hh"
+#include "init/init_matrix.hh"
+
+using namespace std;
+
+template<class Interface>
+class Action_partial_lu {
+
+public :
+
+ // Ctor
+
+ Action_partial_lu( int size ):_size(size)
+ {
+ MESSAGE("Action_partial_lu Ctor");
+
+ // STL vector initialization
+ init_matrix<pseudo_random>(X_stl,_size);
+ init_matrix<null_function>(C_stl,_size);
+
+ // make sure X is invertible
+ for (int i=0; i<_size; ++i)
+ X_stl[i][i] = X_stl[i][i] * 1e2 + 1;
+
+ // generic matrix and vector initialization
+ Interface::matrix_from_stl(X_ref,X_stl);
+ Interface::matrix_from_stl(X,X_stl);
+ Interface::matrix_from_stl(C,C_stl);
+
+ _cost = 2.0*size*size*size/3.0 + size*size;
+ }
+
+ // invalidate copy ctor
+
+ Action_partial_lu( const Action_partial_lu & )
+ {
+ INFOS("illegal call to Action_partial_lu Copy Ctor");
+ exit(1);
+ }
+
+ // Dtor
+
+ ~Action_partial_lu( void ){
+
+ MESSAGE("Action_partial_lu Dtor");
+
+ // deallocation
+ Interface::free_matrix(X_ref,_size);
+ Interface::free_matrix(X,_size);
+ Interface::free_matrix(C,_size);
+ }
+
+ // action name
+
+ static inline std::string name( void )
+ {
+ return "partial_lu_decomp_"+Interface::name();
+ }
+
+ double nb_op_base( void ){
+ return _cost;
+ }
+
+ inline void initialize( void ){
+ Interface::copy_matrix(X_ref,X,_size);
+ }
+
+ inline void calculate( void ) {
+ Interface::partial_lu_decomp(X,C,_size);
+ }
+
+ void check_result( void ){
+ // calculation check
+// Interface::matrix_to_stl(C,resu_stl);
+
+// STL_interface<typename Interface::real_type>::lu_decomp(X_stl,C_stl,_size);
+//
+// typename Interface::real_type error=
+// STL_interface<typename Interface::real_type>::norm_diff(C_stl,resu_stl);
+//
+// if (error>1.e-6){
+// INFOS("WRONG CALCULATION...residual=" << error);
+// exit(0);
+// }
+
+ }
+
+private :
+
+ typename Interface::stl_matrix X_stl;
+ typename Interface::stl_matrix C_stl;
+
+ typename Interface::gene_matrix X_ref;
+ typename Interface::gene_matrix X;
+ typename Interface::gene_matrix C;
+
+ int _size;
+ double _cost;
+};
+
+#endif
diff --git a/bench/btl/actions/action_rot.hh b/bench/btl/actions/action_rot.hh
new file mode 100644
index 000000000..df822a6d6
--- /dev/null
+++ b/bench/btl/actions/action_rot.hh
@@ -0,0 +1,116 @@
+
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+//
+#ifndef ACTION_ROT
+#define ACTION_ROT
+#include "utilities.h"
+#include "STL_interface.hh"
+#include <string>
+#include "init/init_function.hh"
+#include "init/init_vector.hh"
+#include "init/init_matrix.hh"
+
+using namespace std;
+
+template<class Interface>
+class Action_rot {
+
+public :
+
+ // Ctor
+ BTL_DONT_INLINE Action_rot( int size ):_size(size)
+ {
+ MESSAGE("Action_rot Ctor");
+
+ // STL matrix and vector initialization
+ typename Interface::stl_matrix tmp;
+ init_vector<pseudo_random>(A_stl,_size);
+ init_vector<pseudo_random>(B_stl,_size);
+
+ // generic matrix and vector initialization
+ Interface::vector_from_stl(A_ref,A_stl);
+ Interface::vector_from_stl(A,A_stl);
+ Interface::vector_from_stl(B_ref,B_stl);
+ Interface::vector_from_stl(B,B_stl);
+ }
+
+ // invalidate copy ctor
+ Action_rot( const Action_rot & )
+ {
+ INFOS("illegal call to Action_rot Copy Ctor");
+ exit(1);
+ }
+
+ // Dtor
+ BTL_DONT_INLINE ~Action_rot( void ){
+ MESSAGE("Action_rot Dtor");
+ Interface::free_vector(A);
+ Interface::free_vector(B);
+ Interface::free_vector(A_ref);
+ Interface::free_vector(B_ref);
+ }
+
+ // action name
+ static inline std::string name( void )
+ {
+ return "rot_" + Interface::name();
+ }
+
+ double nb_op_base( void ){
+ return 6.0*_size;
+ }
+
+ BTL_DONT_INLINE void initialize( void ){
+ Interface::copy_vector(A_ref,A,_size);
+ Interface::copy_vector(B_ref,B,_size);
+ }
+
+ BTL_DONT_INLINE void calculate( void ) {
+ BTL_ASM_COMMENT("#begin rot");
+ Interface::rot(A,B,0.5,0.6,_size);
+ BTL_ASM_COMMENT("end rot");
+ }
+
+ BTL_DONT_INLINE void check_result( void ){
+ // calculation check
+// Interface::vector_to_stl(X,resu_stl);
+
+// STL_interface<typename Interface::real_type>::rot(A_stl,B_stl,X_stl,_size);
+
+// typename Interface::real_type error=
+// STL_interface<typename Interface::real_type>::norm_diff(X_stl,resu_stl);
+
+// if (error>1.e-3){
+// INFOS("WRONG CALCULATION...residual=" << error);
+// exit(0);
+// }
+
+ }
+
+private :
+
+ typename Interface::stl_vector A_stl;
+ typename Interface::stl_vector B_stl;
+
+ typename Interface::gene_vector A_ref;
+ typename Interface::gene_vector B_ref;
+
+ typename Interface::gene_vector A;
+ typename Interface::gene_vector B;
+
+ int _size;
+};
+
+
+#endif
diff --git a/bench/btl/actions/action_symv.hh b/bench/btl/actions/action_symv.hh
new file mode 100644
index 000000000..a32b9dfa0
--- /dev/null
+++ b/bench/btl/actions/action_symv.hh
@@ -0,0 +1,139 @@
+//=====================================================
+// File : action_symv.hh
+// Author : L. Plagne <laurent.plagne@edf.fr)>
+// Copyright (C) EDF R&D, lun sep 30 14:23:19 CEST 2002
+//=====================================================
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+//
+#ifndef ACTION_SYMV
+#define ACTION_SYMV
+#include "utilities.h"
+#include "STL_interface.hh"
+#include <string>
+#include "init/init_function.hh"
+#include "init/init_vector.hh"
+#include "init/init_matrix.hh"
+
+using namespace std;
+
+template<class Interface>
+class Action_symv {
+
+public :
+
+ // Ctor
+
+ BTL_DONT_INLINE Action_symv( int size ):_size(size)
+ {
+ MESSAGE("Action_symv Ctor");
+
+ // STL matrix and vector initialization
+ init_matrix_symm<pseudo_random>(A_stl,_size);
+ init_vector<pseudo_random>(B_stl,_size);
+ init_vector<null_function>(X_stl,_size);
+ init_vector<null_function>(resu_stl,_size);
+
+ // generic matrix and vector initialization
+ Interface::matrix_from_stl(A_ref,A_stl);
+ Interface::matrix_from_stl(A,A_stl);
+ Interface::vector_from_stl(B_ref,B_stl);
+ Interface::vector_from_stl(B,B_stl);
+ Interface::vector_from_stl(X_ref,X_stl);
+ Interface::vector_from_stl(X,X_stl);
+
+ }
+
+ // invalidate copy ctor
+
+ Action_symv( const Action_symv & )
+ {
+ INFOS("illegal call to Action_symv Copy Ctor");
+ exit(1);
+ }
+
+ // Dtor
+ BTL_DONT_INLINE ~Action_symv( void ){
+ Interface::free_matrix(A,_size);
+ Interface::free_vector(B);
+ Interface::free_vector(X);
+ Interface::free_matrix(A_ref,_size);
+ Interface::free_vector(B_ref);
+ Interface::free_vector(X_ref);
+ }
+
+ // action name
+
+ static inline std::string name( void )
+ {
+ return "symv_" + Interface::name();
+ }
+
+ double nb_op_base( void ){
+ return 2.0*_size*_size;
+ }
+
+ BTL_DONT_INLINE void initialize( void ){
+
+ Interface::copy_matrix(A_ref,A,_size);
+ Interface::copy_vector(B_ref,B,_size);
+ Interface::copy_vector(X_ref,X,_size);
+
+ }
+
+ BTL_DONT_INLINE void calculate( void ) {
+ BTL_ASM_COMMENT("#begin symv");
+ Interface::symv(A,B,X,_size);
+ BTL_ASM_COMMENT("end symv");
+ }
+
+ BTL_DONT_INLINE void check_result( void ){
+ if (_size>128) return;
+ // calculation check
+ Interface::vector_to_stl(X,resu_stl);
+
+ STL_interface<typename Interface::real_type>::symv(A_stl,B_stl,X_stl,_size);
+
+ typename Interface::real_type error=
+ STL_interface<typename Interface::real_type>::norm_diff(X_stl,resu_stl);
+
+ if (error>1.e-5){
+ INFOS("WRONG CALCULATION...residual=" << error);
+ exit(0);
+ }
+
+ }
+
+private :
+
+ typename Interface::stl_matrix A_stl;
+ typename Interface::stl_vector B_stl;
+ typename Interface::stl_vector X_stl;
+ typename Interface::stl_vector resu_stl;
+
+ typename Interface::gene_matrix A_ref;
+ typename Interface::gene_vector B_ref;
+ typename Interface::gene_vector X_ref;
+
+ typename Interface::gene_matrix A;
+ typename Interface::gene_vector B;
+ typename Interface::gene_vector X;
+
+
+ int _size;
+
+};
+
+
+#endif
diff --git a/bench/btl/actions/action_syr2.hh b/bench/btl/actions/action_syr2.hh
new file mode 100644
index 000000000..7c6712b13
--- /dev/null
+++ b/bench/btl/actions/action_syr2.hh
@@ -0,0 +1,133 @@
+//=====================================================
+// File : action_syr2.hh
+// Author : L. Plagne <laurent.plagne@edf.fr)>
+// Copyright (C) EDF R&D, lun sep 30 14:23:19 CEST 2002
+//=====================================================
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+//
+#ifndef ACTION_SYR2
+#define ACTION_SYR2
+#include "utilities.h"
+#include "STL_interface.hh"
+#include <string>
+#include "init/init_function.hh"
+#include "init/init_vector.hh"
+#include "init/init_matrix.hh"
+
+using namespace std;
+
+template<class Interface>
+class Action_syr2 {
+
+public :
+
+ // Ctor
+
+ BTL_DONT_INLINE Action_syr2( int size ):_size(size)
+ {
+ // STL matrix and vector initialization
+ typename Interface::stl_matrix tmp;
+ init_matrix<pseudo_random>(A_stl,_size);
+ init_vector<pseudo_random>(B_stl,_size);
+ init_vector<pseudo_random>(X_stl,_size);
+ init_vector<null_function>(resu_stl,_size);
+
+ // generic matrix and vector initialization
+ Interface::matrix_from_stl(A_ref,A_stl);
+ Interface::matrix_from_stl(A,A_stl);
+ Interface::vector_from_stl(B_ref,B_stl);
+ Interface::vector_from_stl(B,B_stl);
+ Interface::vector_from_stl(X_ref,X_stl);
+ Interface::vector_from_stl(X,X_stl);
+ }
+
+ // invalidate copy ctor
+ Action_syr2( const Action_syr2 & )
+ {
+ INFOS("illegal call to Action_syr2 Copy Ctor");
+ exit(1);
+ }
+
+ // Dtor
+ BTL_DONT_INLINE ~Action_syr2( void ){
+ Interface::free_matrix(A,_size);
+ Interface::free_vector(B);
+ Interface::free_vector(X);
+ Interface::free_matrix(A_ref,_size);
+ Interface::free_vector(B_ref);
+ Interface::free_vector(X_ref);
+ }
+
+ // action name
+
+ static inline std::string name( void )
+ {
+ return "syr2_" + Interface::name();
+ }
+
+ double nb_op_base( void ){
+ return 2.0*_size*_size;
+ }
+
+ BTL_DONT_INLINE void initialize( void ){
+ Interface::copy_matrix(A_ref,A,_size);
+ Interface::copy_vector(B_ref,B,_size);
+ Interface::copy_vector(X_ref,X,_size);
+ }
+
+ BTL_DONT_INLINE void calculate( void ) {
+ BTL_ASM_COMMENT("#begin syr2");
+ Interface::syr2(A,B,X,_size);
+ BTL_ASM_COMMENT("end syr2");
+ }
+
+ BTL_DONT_INLINE void check_result( void ){
+ // calculation check
+ Interface::vector_to_stl(X,resu_stl);
+
+ STL_interface<typename Interface::real_type>::syr2(A_stl,B_stl,X_stl,_size);
+
+ typename Interface::real_type error=
+ STL_interface<typename Interface::real_type>::norm_diff(X_stl,resu_stl);
+
+ if (error>1.e-3){
+ INFOS("WRONG CALCULATION...residual=" << error);
+// exit(0);
+ }
+
+ }
+
+private :
+
+ typename Interface::stl_matrix A_stl;
+ typename Interface::stl_vector B_stl;
+ typename Interface::stl_vector X_stl;
+ typename Interface::stl_vector resu_stl;
+
+ typename Interface::gene_matrix A_ref;
+ typename Interface::gene_vector B_ref;
+ typename Interface::gene_vector X_ref;
+
+ typename Interface::gene_matrix A;
+ typename Interface::gene_vector B;
+ typename Interface::gene_vector X;
+
+
+ int _size;
+
+};
+
+
+#endif
diff --git a/bench/btl/actions/action_trisolve.hh b/bench/btl/actions/action_trisolve.hh
new file mode 100644
index 000000000..d6f0b477e
--- /dev/null
+++ b/bench/btl/actions/action_trisolve.hh
@@ -0,0 +1,137 @@
+//=====================================================
+// File : action_trisolve.hh
+// Copyright (C) 2008 Gael Guennebaud <gael.guennebaud@inria.fr>
+//=====================================================
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+//
+#ifndef ACTION_TRISOLVE
+#define ACTION_TRISOLVE
+#include "utilities.h"
+#include "STL_interface.hh"
+#include <string>
+#include "init/init_function.hh"
+#include "init/init_vector.hh"
+#include "init/init_matrix.hh"
+
+using namespace std;
+
+template<class Interface>
+class Action_trisolve {
+
+public :
+
+ // Ctor
+
+ Action_trisolve( int size ):_size(size)
+ {
+ MESSAGE("Action_trisolve Ctor");
+
+ // STL vector initialization
+ init_matrix<pseudo_random>(L_stl,_size);
+ init_vector<pseudo_random>(B_stl,_size);
+ init_vector<null_function>(X_stl,_size);
+ for (int j=0; j<_size; ++j)
+ {
+ for (int i=0; i<j; ++i)
+ L_stl[j][i] = 0;
+ L_stl[j][j] += 3;
+ }
+
+ init_vector<null_function>(resu_stl,_size);
+
+ // generic matrix and vector initialization
+ Interface::matrix_from_stl(L,L_stl);
+ Interface::vector_from_stl(X,X_stl);
+ Interface::vector_from_stl(B,B_stl);
+
+ _cost = 0;
+ for (int j=0; j<_size; ++j)
+ {
+ _cost += 2*j + 1;
+ }
+ }
+
+ // invalidate copy ctor
+
+ Action_trisolve( const Action_trisolve & )
+ {
+ INFOS("illegal call to Action_trisolve Copy Ctor");
+ exit(1);
+ }
+
+ // Dtor
+
+ ~Action_trisolve( void ){
+
+ MESSAGE("Action_trisolve Dtor");
+
+ // deallocation
+ Interface::free_matrix(L,_size);
+ Interface::free_vector(B);
+ Interface::free_vector(X);
+ }
+
+ // action name
+
+ static inline std::string name( void )
+ {
+ return "trisolve_vector_"+Interface::name();
+ }
+
+ double nb_op_base( void ){
+ return _cost;
+ }
+
+ inline void initialize( void ){
+ //Interface::copy_vector(X_ref,X,_size);
+ }
+
+ inline void calculate( void ) {
+ Interface::trisolve_lower(L,B,X,_size);
+ }
+
+ void check_result(){
+ if (_size>128) return;
+ // calculation check
+ Interface::vector_to_stl(X,resu_stl);
+
+ STL_interface<typename Interface::real_type>::trisolve_lower(L_stl,B_stl,X_stl,_size);
+
+ typename Interface::real_type error=
+ STL_interface<typename Interface::real_type>::norm_diff(X_stl,resu_stl);
+
+ if (error>1.e-4){
+ INFOS("WRONG CALCULATION...residual=" << error);
+ exit(2);
+ } //else INFOS("CALCULATION OK...residual=" << error);
+
+ }
+
+private :
+
+ typename Interface::stl_matrix L_stl;
+ typename Interface::stl_vector X_stl;
+ typename Interface::stl_vector B_stl;
+ typename Interface::stl_vector resu_stl;
+
+ typename Interface::gene_matrix L;
+ typename Interface::gene_vector X;
+ typename Interface::gene_vector B;
+
+ int _size;
+ double _cost;
+};
+
+#endif
diff --git a/bench/btl/actions/action_trisolve_matrix.hh b/bench/btl/actions/action_trisolve_matrix.hh
new file mode 100644
index 000000000..0fc2bb9ef
--- /dev/null
+++ b/bench/btl/actions/action_trisolve_matrix.hh
@@ -0,0 +1,165 @@
+//=====================================================
+// File : action_matrix_matrix_product.hh
+// Author : L. Plagne <laurent.plagne@edf.fr)>
+// Copyright (C) EDF R&D, lun sep 30 14:23:19 CEST 2002
+//=====================================================
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+//
+#ifndef ACTION_TRISOLVE_MATRIX_PRODUCT
+#define ACTION_TRISOLVE_MATRIX_PRODUCT
+#include "utilities.h"
+#include "STL_interface.hh"
+#include <string>
+#include "init/init_function.hh"
+#include "init/init_vector.hh"
+#include "init/init_matrix.hh"
+
+using namespace std;
+
+template<class Interface>
+class Action_trisolve_matrix {
+
+public :
+
+ // Ctor
+
+ Action_trisolve_matrix( int size ):_size(size)
+ {
+ MESSAGE("Action_trisolve_matrix Ctor");
+
+ // STL matrix and vector initialization
+
+ init_matrix<pseudo_random>(A_stl,_size);
+ init_matrix<pseudo_random>(B_stl,_size);
+ init_matrix<null_function>(X_stl,_size);
+ init_matrix<null_function>(resu_stl,_size);
+
+ for (int j=0; j<_size; ++j)
+ {
+ for (int i=0; i<j; ++i)
+ A_stl[j][i] = 0;
+ A_stl[j][j] += 3;
+ }
+
+ // generic matrix and vector initialization
+
+ Interface::matrix_from_stl(A_ref,A_stl);
+ Interface::matrix_from_stl(B_ref,B_stl);
+ Interface::matrix_from_stl(X_ref,X_stl);
+
+ Interface::matrix_from_stl(A,A_stl);
+ Interface::matrix_from_stl(B,B_stl);
+ Interface::matrix_from_stl(X,X_stl);
+
+ _cost = 0;
+ for (int j=0; j<_size; ++j)
+ {
+ _cost += 2*j + 1;
+ }
+ _cost *= _size;
+ }
+
+ // invalidate copy ctor
+
+ Action_trisolve_matrix( const Action_trisolve_matrix & )
+ {
+ INFOS("illegal call to Action_trisolve_matrix Copy Ctor");
+ exit(0);
+ }
+
+ // Dtor
+
+ ~Action_trisolve_matrix( void ){
+
+ MESSAGE("Action_trisolve_matrix Dtor");
+
+ // deallocation
+
+ Interface::free_matrix(A,_size);
+ Interface::free_matrix(B,_size);
+ Interface::free_matrix(X,_size);
+
+ Interface::free_matrix(A_ref,_size);
+ Interface::free_matrix(B_ref,_size);
+ Interface::free_matrix(X_ref,_size);
+
+ }
+
+ // action name
+
+ static inline std::string name( void )
+ {
+ return "trisolve_matrix_"+Interface::name();
+ }
+
+ double nb_op_base( void ){
+ return _cost;
+ }
+
+ inline void initialize( void ){
+
+ Interface::copy_matrix(A_ref,A,_size);
+ Interface::copy_matrix(B_ref,B,_size);
+ Interface::copy_matrix(X_ref,X,_size);
+
+ }
+
+ inline void calculate( void ) {
+ Interface::trisolve_lower_matrix(A,B,X,_size);
+ }
+
+ void check_result( void ){
+
+ // calculation check
+
+// Interface::matrix_to_stl(X,resu_stl);
+//
+// STL_interface<typename Interface::real_type>::matrix_matrix_product(A_stl,B_stl,X_stl,_size);
+//
+// typename Interface::real_type error=
+// STL_interface<typename Interface::real_type>::norm_diff(X_stl,resu_stl);
+//
+// if (error>1.e-6){
+// INFOS("WRONG CALCULATION...residual=" << error);
+// // exit(1);
+// }
+
+ }
+
+private :
+
+ typename Interface::stl_matrix A_stl;
+ typename Interface::stl_matrix B_stl;
+ typename Interface::stl_matrix X_stl;
+ typename Interface::stl_matrix resu_stl;
+
+ typename Interface::gene_matrix A_ref;
+ typename Interface::gene_matrix B_ref;
+ typename Interface::gene_matrix X_ref;
+
+ typename Interface::gene_matrix A;
+ typename Interface::gene_matrix B;
+ typename Interface::gene_matrix X;
+
+ int _size;
+ double _cost;
+
+};
+
+
+#endif
+
+
+
diff --git a/bench/btl/actions/action_trmm.hh b/bench/btl/actions/action_trmm.hh
new file mode 100644
index 000000000..8f7813818
--- /dev/null
+++ b/bench/btl/actions/action_trmm.hh
@@ -0,0 +1,165 @@
+//=====================================================
+// File : action_matrix_matrix_product.hh
+// Author : L. Plagne <laurent.plagne@edf.fr)>
+// Copyright (C) EDF R&D, lun sep 30 14:23:19 CEST 2002
+//=====================================================
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+//
+#ifndef ACTION_TRMM
+#define ACTION_TRMM
+#include "utilities.h"
+#include "STL_interface.hh"
+#include <string>
+#include "init/init_function.hh"
+#include "init/init_vector.hh"
+#include "init/init_matrix.hh"
+
+using namespace std;
+
+template<class Interface>
+class Action_trmm {
+
+public :
+
+ // Ctor
+
+ Action_trmm( int size ):_size(size)
+ {
+ MESSAGE("Action_trmm Ctor");
+
+ // STL matrix and vector initialization
+
+ init_matrix<pseudo_random>(A_stl,_size);
+ init_matrix<pseudo_random>(B_stl,_size);
+ init_matrix<null_function>(X_stl,_size);
+ init_matrix<null_function>(resu_stl,_size);
+
+ for (int j=0; j<_size; ++j)
+ {
+ for (int i=0; i<j; ++i)
+ A_stl[j][i] = 0;
+ A_stl[j][j] += 3;
+ }
+
+ // generic matrix and vector initialization
+
+ Interface::matrix_from_stl(A_ref,A_stl);
+ Interface::matrix_from_stl(B_ref,B_stl);
+ Interface::matrix_from_stl(X_ref,X_stl);
+
+ Interface::matrix_from_stl(A,A_stl);
+ Interface::matrix_from_stl(B,B_stl);
+ Interface::matrix_from_stl(X,X_stl);
+
+ _cost = 0;
+ for (int j=0; j<_size; ++j)
+ {
+ _cost += 2*j + 1;
+ }
+ _cost *= _size;
+ }
+
+ // invalidate copy ctor
+
+ Action_trmm( const Action_trmm & )
+ {
+ INFOS("illegal call to Action_trmm Copy Ctor");
+ exit(0);
+ }
+
+ // Dtor
+
+ ~Action_trmm( void ){
+
+ MESSAGE("Action_trmm Dtor");
+
+ // deallocation
+
+ Interface::free_matrix(A,_size);
+ Interface::free_matrix(B,_size);
+ Interface::free_matrix(X,_size);
+
+ Interface::free_matrix(A_ref,_size);
+ Interface::free_matrix(B_ref,_size);
+ Interface::free_matrix(X_ref,_size);
+
+ }
+
+ // action name
+
+ static inline std::string name( void )
+ {
+ return "trmm_"+Interface::name();
+ }
+
+ double nb_op_base( void ){
+ return _cost;
+ }
+
+ inline void initialize( void ){
+
+ Interface::copy_matrix(A_ref,A,_size);
+ Interface::copy_matrix(B_ref,B,_size);
+ Interface::copy_matrix(X_ref,X,_size);
+
+ }
+
+ inline void calculate( void ) {
+ Interface::trmm(A,B,X,_size);
+ }
+
+ void check_result( void ){
+
+ // calculation check
+
+// Interface::matrix_to_stl(X,resu_stl);
+//
+// STL_interface<typename Interface::real_type>::matrix_matrix_product(A_stl,B_stl,X_stl,_size);
+//
+// typename Interface::real_type error=
+// STL_interface<typename Interface::real_type>::norm_diff(X_stl,resu_stl);
+//
+// if (error>1.e-6){
+// INFOS("WRONG CALCULATION...residual=" << error);
+// // exit(1);
+// }
+
+ }
+
+private :
+
+ typename Interface::stl_matrix A_stl;
+ typename Interface::stl_matrix B_stl;
+ typename Interface::stl_matrix X_stl;
+ typename Interface::stl_matrix resu_stl;
+
+ typename Interface::gene_matrix A_ref;
+ typename Interface::gene_matrix B_ref;
+ typename Interface::gene_matrix X_ref;
+
+ typename Interface::gene_matrix A;
+ typename Interface::gene_matrix B;
+ typename Interface::gene_matrix X;
+
+ int _size;
+ double _cost;
+
+};
+
+
+#endif
+
+
+
diff --git a/bench/btl/actions/basic_actions.hh b/bench/btl/actions/basic_actions.hh
new file mode 100644
index 000000000..a3333ea26
--- /dev/null
+++ b/bench/btl/actions/basic_actions.hh
@@ -0,0 +1,21 @@
+
+#include "action_axpy.hh"
+#include "action_axpby.hh"
+
+#include "action_matrix_vector_product.hh"
+#include "action_atv_product.hh"
+
+#include "action_matrix_matrix_product.hh"
+// #include "action_ata_product.hh"
+#include "action_aat_product.hh"
+
+#include "action_trisolve.hh"
+#include "action_trmm.hh"
+#include "action_symv.hh"
+// #include "action_symm.hh"
+#include "action_syr2.hh"
+#include "action_ger.hh"
+#include "action_rot.hh"
+
+// #include "action_lu_solve.hh"
+
diff --git a/bench/btl/cmake/FindACML.cmake b/bench/btl/cmake/FindACML.cmake
new file mode 100644
index 000000000..f45ae1b0d
--- /dev/null
+++ b/bench/btl/cmake/FindACML.cmake
@@ -0,0 +1,49 @@
+
+if (ACML_LIBRARIES)
+ set(ACML_FIND_QUIETLY TRUE)
+endif (ACML_LIBRARIES)
+
+find_library(ACML_LIBRARIES
+ NAMES
+ acml_mp acml_mv
+ PATHS
+ $ENV{ACMLDIR}/lib
+ $ENV{ACML_DIR}/lib
+ ${LIB_INSTALL_DIR}
+)
+
+find_file(ACML_LIBRARIES
+ NAMES
+ libacml_mp.so
+ PATHS
+ /usr/lib
+ $ENV{ACMLDIR}/lib
+ ${LIB_INSTALL_DIR}
+)
+
+if(NOT ACML_LIBRARIES)
+ message(STATUS "Multi-threaded library not found, looking for single-threaded")
+ find_library(ACML_LIBRARIES
+ NAMES
+ acml acml_mv
+ PATHS
+ $ENV{ACMLDIR}/lib
+ $ENV{ACML_DIR}/lib
+ ${LIB_INSTALL_DIR}
+ )
+ find_file(ACML_LIBRARIES
+ libacml.so libacml_mv.so
+ PATHS
+ /usr/lib
+ $ENV{ACMLDIR}/lib
+ ${LIB_INSTALL_DIR}
+ )
+endif()
+
+
+
+
+include(FindPackageHandleStandardArgs)
+find_package_handle_standard_args(ACML DEFAULT_MSG ACML_LIBRARIES)
+
+mark_as_advanced(ACML_LIBRARIES)
diff --git a/bench/btl/cmake/FindATLAS.cmake b/bench/btl/cmake/FindATLAS.cmake
new file mode 100644
index 000000000..6b9065206
--- /dev/null
+++ b/bench/btl/cmake/FindATLAS.cmake
@@ -0,0 +1,39 @@
+
+if (ATLAS_LIBRARIES)
+ set(ATLAS_FIND_QUIETLY TRUE)
+endif (ATLAS_LIBRARIES)
+
+find_file(ATLAS_LIB libatlas.so.3 PATHS /usr/lib $ENV{ATLASDIR} ${LIB_INSTALL_DIR})
+find_library(ATLAS_LIB atlas PATHS $ENV{ATLASDIR} ${LIB_INSTALL_DIR})
+
+find_file(ATLAS_CBLAS libcblas.so.3 PATHS /usr/lib $ENV{ATLASDIR} ${LIB_INSTALL_DIR})
+find_library(ATLAS_CBLAS cblas PATHS $ENV{ATLASDIR} ${LIB_INSTALL_DIR})
+
+find_file(ATLAS_LAPACK liblapack_atlas.so.3 PATHS /usr/lib $ENV{ATLASDIR} ${LIB_INSTALL_DIR})
+find_library(ATLAS_LAPACK lapack_atlas PATHS $ENV{ATLASDIR} ${LIB_INSTALL_DIR})
+
+if(NOT ATLAS_LAPACK)
+ find_file(ATLAS_LAPACK liblapack.so.3 PATHS /usr/lib/atlas $ENV{ATLASDIR} ${LIB_INSTALL_DIR})
+ find_library(ATLAS_LAPACK lapack PATHS $ENV{ATLASDIR} ${LIB_INSTALL_DIR})
+endif(NOT ATLAS_LAPACK)
+
+find_file(ATLAS_F77BLAS libf77blas.so.3 PATHS /usr/lib $ENV{ATLASDIR} ${LIB_INSTALL_DIR})
+find_library(ATLAS_F77BLAS f77blas PATHS $ENV{ATLASDIR} ${LIB_INSTALL_DIR})
+
+if(ATLAS_LIB AND ATLAS_CBLAS AND ATLAS_LAPACK AND ATLAS_F77BLAS)
+
+ set(ATLAS_LIBRARIES ${ATLAS_LAPACK} ${ATLAS_CBLAS} ${ATLAS_F77BLAS} ${ATLAS_LIB})
+
+ # search the default lapack lib link to it
+ find_file(ATLAS_REFERENCE_LAPACK liblapack.so.3 PATHS /usr/lib /usr/lib64)
+ find_library(ATLAS_REFERENCE_LAPACK NAMES lapack)
+ if(ATLAS_REFERENCE_LAPACK)
+ set(ATLAS_LIBRARIES ${ATLAS_LIBRARIES} ${ATLAS_REFERENCE_LAPACK})
+ endif()
+
+endif(ATLAS_LIB AND ATLAS_CBLAS AND ATLAS_LAPACK AND ATLAS_F77BLAS)
+
+include(FindPackageHandleStandardArgs)
+find_package_handle_standard_args(ATLAS DEFAULT_MSG ATLAS_LIBRARIES)
+
+mark_as_advanced(ATLAS_LIBRARIES)
diff --git a/bench/btl/cmake/FindBlitz.cmake b/bench/btl/cmake/FindBlitz.cmake
new file mode 100644
index 000000000..92880bbed
--- /dev/null
+++ b/bench/btl/cmake/FindBlitz.cmake
@@ -0,0 +1,40 @@
+# - Try to find blitz lib
+# Once done this will define
+#
+# BLITZ_FOUND - system has blitz lib
+# BLITZ_INCLUDES - the blitz include directory
+# BLITZ_LIBRARIES - The libraries needed to use blitz
+
+# Copyright (c) 2006, Montel Laurent, <montel@kde.org>
+# Copyright (c) 2007, Allen Winter, <winter@kde.org>
+# Copyright (C) 2008 Gael Guennebaud <gael.guennebaud@inria.fr>
+# Redistribution and use is allowed according to the terms of the BSD license.
+# For details see the accompanying COPYING-CMAKE-SCRIPTS file.
+
+# include(FindLibraryWithDebug)
+
+if (BLITZ_INCLUDES AND BLITZ_LIBRARIES)
+ set(Blitz_FIND_QUIETLY TRUE)
+endif (BLITZ_INCLUDES AND BLITZ_LIBRARIES)
+
+find_path(BLITZ_INCLUDES
+ NAMES
+ blitz/array.h
+ PATH_SUFFIXES blitz*
+ PATHS
+ $ENV{BLITZDIR}/include
+ ${INCLUDE_INSTALL_DIR}
+)
+
+find_library(BLITZ_LIBRARIES
+ blitz
+ PATHS
+ $ENV{BLITZDIR}/lib
+ ${LIB_INSTALL_DIR}
+)
+
+include(FindPackageHandleStandardArgs)
+find_package_handle_standard_args(Blitz DEFAULT_MSG
+ BLITZ_INCLUDES BLITZ_LIBRARIES)
+
+mark_as_advanced(BLITZ_INCLUDES BLITZ_LIBRARIES)
diff --git a/bench/btl/cmake/FindCBLAS.cmake b/bench/btl/cmake/FindCBLAS.cmake
new file mode 100644
index 000000000..554f0291b
--- /dev/null
+++ b/bench/btl/cmake/FindCBLAS.cmake
@@ -0,0 +1,34 @@
+# include(FindLibraryWithDebug)
+
+if (CBLAS_INCLUDES AND CBLAS_LIBRARIES)
+ set(CBLAS_FIND_QUIETLY TRUE)
+endif (CBLAS_INCLUDES AND CBLAS_LIBRARIES)
+
+find_path(CBLAS_INCLUDES
+ NAMES
+ cblas.h
+ PATHS
+ $ENV{CBLASDIR}/include
+ ${INCLUDE_INSTALL_DIR}
+)
+
+find_library(CBLAS_LIBRARIES
+ cblas
+ PATHS
+ $ENV{CBLASDIR}/lib
+ ${LIB_INSTALL_DIR}
+)
+
+find_file(CBLAS_LIBRARIES
+ libcblas.so.3
+ PATHS
+ /usr/lib
+ $ENV{CBLASDIR}/lib
+ ${LIB_INSTALL_DIR}
+)
+
+include(FindPackageHandleStandardArgs)
+find_package_handle_standard_args(CBLAS DEFAULT_MSG
+ CBLAS_INCLUDES CBLAS_LIBRARIES)
+
+mark_as_advanced(CBLAS_INCLUDES CBLAS_LIBRARIES)
diff --git a/bench/btl/cmake/FindGMM.cmake b/bench/btl/cmake/FindGMM.cmake
new file mode 100644
index 000000000..5049c64ed
--- /dev/null
+++ b/bench/btl/cmake/FindGMM.cmake
@@ -0,0 +1,17 @@
+if (GMM_INCLUDE_DIR)
+ # in cache already
+ set(GMM_FOUND TRUE)
+else (GMM_INCLUDE_DIR)
+
+find_path(GMM_INCLUDE_DIR NAMES gmm/gmm.h
+ PATHS
+ ${INCLUDE_INSTALL_DIR}
+ ${GMM_INCLUDE_PATH}
+ )
+
+include(FindPackageHandleStandardArgs)
+FIND_PACKAGE_HANDLE_STANDARD_ARGS(GMM DEFAULT_MSG GMM_INCLUDE_DIR )
+
+mark_as_advanced(GMM_INCLUDE_DIR)
+
+endif(GMM_INCLUDE_DIR)
diff --git a/bench/btl/cmake/FindGOTO.cmake b/bench/btl/cmake/FindGOTO.cmake
new file mode 100644
index 000000000..67ea0934a
--- /dev/null
+++ b/bench/btl/cmake/FindGOTO.cmake
@@ -0,0 +1,15 @@
+
+if (GOTO_LIBRARIES)
+ set(GOTO_FIND_QUIETLY TRUE)
+endif (GOTO_LIBRARIES)
+
+find_library(GOTO_LIBRARIES goto PATHS $ENV{GOTODIR} ${LIB_INSTALL_DIR})
+
+if(GOTO_LIBRARIES AND CMAKE_COMPILER_IS_GNUCXX)
+ set(GOTO_LIBRARIES ${GOTO_LIBRARIES} "-lpthread -lgfortran")
+endif()
+
+include(FindPackageHandleStandardArgs)
+find_package_handle_standard_args(GOTO DEFAULT_MSG GOTO_LIBRARIES)
+
+mark_as_advanced(GOTO_LIBRARIES)
diff --git a/bench/btl/cmake/FindGOTO2.cmake b/bench/btl/cmake/FindGOTO2.cmake
new file mode 100644
index 000000000..baa68d213
--- /dev/null
+++ b/bench/btl/cmake/FindGOTO2.cmake
@@ -0,0 +1,25 @@
+
+if (GOTO2_LIBRARIES)
+ set(GOTO2_FIND_QUIETLY TRUE)
+endif (GOTO2_LIBRARIES)
+#
+# find_path(GOTO_INCLUDES
+# NAMES
+# cblas.h
+# PATHS
+# $ENV{GOTODIR}/include
+# ${INCLUDE_INSTALL_DIR}
+# )
+
+find_file(GOTO2_LIBRARIES libgoto2.so PATHS /usr/lib $ENV{GOTO2DIR} ${LIB_INSTALL_DIR})
+find_library(GOTO2_LIBRARIES goto2 PATHS $ENV{GOTO2DIR} ${LIB_INSTALL_DIR})
+
+if(GOTO2_LIBRARIES AND CMAKE_COMPILER_IS_GNUCXX)
+ set(GOTO2_LIBRARIES ${GOTO2_LIBRARIES} "-lpthread -lgfortran")
+endif()
+
+include(FindPackageHandleStandardArgs)
+find_package_handle_standard_args(GOTO2 DEFAULT_MSG
+ GOTO2_LIBRARIES)
+
+mark_as_advanced(GOTO2_LIBRARIES)
diff --git a/bench/btl/cmake/FindMKL.cmake b/bench/btl/cmake/FindMKL.cmake
new file mode 100644
index 000000000..f4d7c6ebe
--- /dev/null
+++ b/bench/btl/cmake/FindMKL.cmake
@@ -0,0 +1,65 @@
+
+if (MKL_LIBRARIES)
+ set(MKL_FIND_QUIETLY TRUE)
+endif (MKL_LIBRARIES)
+
+if(CMAKE_MINOR_VERSION GREATER 4)
+
+if(${CMAKE_HOST_SYSTEM_PROCESSOR} STREQUAL "x86_64")
+
+find_library(MKL_LIBRARIES
+ mkl_core
+ PATHS
+ $ENV{MKLLIB}
+ /opt/intel/mkl/*/lib/em64t
+ /opt/intel/Compiler/*/*/mkl/lib/em64t
+ ${LIB_INSTALL_DIR}
+)
+
+find_library(MKL_GUIDE
+ guide
+ PATHS
+ $ENV{MKLLIB}
+ /opt/intel/mkl/*/lib/em64t
+ /opt/intel/Compiler/*/*/mkl/lib/em64t
+ /opt/intel/Compiler/*/*/lib/intel64
+ ${LIB_INSTALL_DIR}
+)
+
+if(MKL_LIBRARIES AND MKL_GUIDE)
+ set(MKL_LIBRARIES ${MKL_LIBRARIES} mkl_intel_lp64 mkl_sequential ${MKL_GUIDE} pthread)
+endif()
+
+else(${CMAKE_HOST_SYSTEM_PROCESSOR} STREQUAL "x86_64")
+
+find_library(MKL_LIBRARIES
+ mkl_core
+ PATHS
+ $ENV{MKLLIB}
+ /opt/intel/mkl/*/lib/32
+ /opt/intel/Compiler/*/*/mkl/lib/32
+ ${LIB_INSTALL_DIR}
+)
+
+find_library(MKL_GUIDE
+ guide
+ PATHS
+ $ENV{MKLLIB}
+ /opt/intel/mkl/*/lib/32
+ /opt/intel/Compiler/*/*/mkl/lib/32
+ /opt/intel/Compiler/*/*/lib/intel32
+ ${LIB_INSTALL_DIR}
+)
+
+if(MKL_LIBRARIES AND MKL_GUIDE)
+ set(MKL_LIBRARIES ${MKL_LIBRARIES} mkl_intel mkl_sequential ${MKL_GUIDE} pthread)
+endif()
+
+endif(${CMAKE_HOST_SYSTEM_PROCESSOR} STREQUAL "x86_64")
+
+endif(CMAKE_MINOR_VERSION GREATER 4)
+
+include(FindPackageHandleStandardArgs)
+find_package_handle_standard_args(MKL DEFAULT_MSG MKL_LIBRARIES)
+
+mark_as_advanced(MKL_LIBRARIES)
diff --git a/bench/btl/cmake/FindMTL4.cmake b/bench/btl/cmake/FindMTL4.cmake
new file mode 100644
index 000000000..3de490980
--- /dev/null
+++ b/bench/btl/cmake/FindMTL4.cmake
@@ -0,0 +1,31 @@
+# - Try to find eigen2 headers
+# Once done this will define
+#
+# MTL4_FOUND - system has eigen2 lib
+# MTL4_INCLUDE_DIR - the eigen2 include directory
+#
+# Copyright (C) 2008 Gael Guennebaud <gael.guennebaud@inria.fr>
+# Adapted from FindEigen.cmake:
+# Copyright (c) 2006, 2007 Montel Laurent, <montel@kde.org>
+# Redistribution and use is allowed according to the terms of the BSD license.
+# For details see the accompanying COPYING-CMAKE-SCRIPTS file.
+
+if (MTL4_INCLUDE_DIR)
+
+ # in cache already
+ set(MTL4_FOUND TRUE)
+
+else (MTL4_INCLUDE_DIR)
+
+find_path(MTL4_INCLUDE_DIR NAMES boost/numeric/mtl/mtl.hpp
+ PATHS
+ ${INCLUDE_INSTALL_DIR}
+ )
+
+include(FindPackageHandleStandardArgs)
+find_package_handle_standard_args(MTL4 DEFAULT_MSG MTL4_INCLUDE_DIR)
+
+mark_as_advanced(MTL4_INCLUDE_DIR)
+
+endif(MTL4_INCLUDE_DIR)
+
diff --git a/bench/btl/cmake/FindPackageHandleStandardArgs.cmake b/bench/btl/cmake/FindPackageHandleStandardArgs.cmake
new file mode 100644
index 000000000..7f122edcd
--- /dev/null
+++ b/bench/btl/cmake/FindPackageHandleStandardArgs.cmake
@@ -0,0 +1,60 @@
+# FIND_PACKAGE_HANDLE_STANDARD_ARGS(NAME (DEFAULT_MSG|"Custom failure message") VAR1 ... )
+#
+# This macro is intended to be used in FindXXX.cmake modules files.
+# It handles the REQUIRED and QUIET argument to FIND_PACKAGE() and
+# it also sets the <UPPERCASED_NAME>_FOUND variable.
+# The package is found if all variables listed are TRUE.
+# Example:
+#
+# FIND_PACKAGE_HANDLE_STANDARD_ARGS(LibXml2 DEFAULT_MSG LIBXML2_LIBRARIES LIBXML2_INCLUDE_DIR)
+#
+# LibXml2 is considered to be found, if both LIBXML2_LIBRARIES and
+# LIBXML2_INCLUDE_DIR are valid. Then also LIBXML2_FOUND is set to TRUE.
+# If it is not found and REQUIRED was used, it fails with FATAL_ERROR,
+# independent whether QUIET was used or not.
+#
+# If it is found, the location is reported using the VAR1 argument, so
+# here a message "Found LibXml2: /usr/lib/libxml2.so" will be printed out.
+# If the second argument is DEFAULT_MSG, the message in the failure case will
+# be "Could NOT find LibXml2", if you don't like this message you can specify
+# your own custom failure message there.
+
+MACRO(FIND_PACKAGE_HANDLE_STANDARD_ARGS _NAME _FAIL_MSG _VAR1 )
+
+ IF("${_FAIL_MSG}" STREQUAL "DEFAULT_MSG")
+ IF (${_NAME}_FIND_REQUIRED)
+ SET(_FAIL_MESSAGE "Could not find REQUIRED package ${_NAME}")
+ ELSE (${_NAME}_FIND_REQUIRED)
+ SET(_FAIL_MESSAGE "Could not find OPTIONAL package ${_NAME}")
+ ENDIF (${_NAME}_FIND_REQUIRED)
+ ELSE("${_FAIL_MSG}" STREQUAL "DEFAULT_MSG")
+ SET(_FAIL_MESSAGE "${_FAIL_MSG}")
+ ENDIF("${_FAIL_MSG}" STREQUAL "DEFAULT_MSG")
+
+ STRING(TOUPPER ${_NAME} _NAME_UPPER)
+
+ SET(${_NAME_UPPER}_FOUND TRUE)
+ IF(NOT ${_VAR1})
+ SET(${_NAME_UPPER}_FOUND FALSE)
+ ENDIF(NOT ${_VAR1})
+
+ FOREACH(_CURRENT_VAR ${ARGN})
+ IF(NOT ${_CURRENT_VAR})
+ SET(${_NAME_UPPER}_FOUND FALSE)
+ ENDIF(NOT ${_CURRENT_VAR})
+ ENDFOREACH(_CURRENT_VAR)
+
+ IF (${_NAME_UPPER}_FOUND)
+ IF (NOT ${_NAME}_FIND_QUIETLY)
+ MESSAGE(STATUS "Found ${_NAME}: ${${_VAR1}}")
+ ENDIF (NOT ${_NAME}_FIND_QUIETLY)
+ ELSE (${_NAME_UPPER}_FOUND)
+ IF (${_NAME}_FIND_REQUIRED)
+ MESSAGE(FATAL_ERROR "${_FAIL_MESSAGE}")
+ ELSE (${_NAME}_FIND_REQUIRED)
+ IF (NOT ${_NAME}_FIND_QUIETLY)
+ MESSAGE(STATUS "${_FAIL_MESSAGE}")
+ ENDIF (NOT ${_NAME}_FIND_QUIETLY)
+ ENDIF (${_NAME}_FIND_REQUIRED)
+ ENDIF (${_NAME_UPPER}_FOUND)
+ENDMACRO(FIND_PACKAGE_HANDLE_STANDARD_ARGS)
diff --git a/bench/btl/cmake/FindTvmet.cmake b/bench/btl/cmake/FindTvmet.cmake
new file mode 100644
index 000000000..26a29d965
--- /dev/null
+++ b/bench/btl/cmake/FindTvmet.cmake
@@ -0,0 +1,32 @@
+# - Try to find tvmet headers
+# Once done this will define
+#
+# TVMET_FOUND - system has tvmet lib
+# TVMET_INCLUDE_DIR - the tvmet include directory
+#
+# Copyright (C) 2008 Gael Guennebaud <gael.guennebaud@inria.fr>
+# Adapted from FindEigen.cmake:
+# Copyright (c) 2006, 2007 Montel Laurent, <montel@kde.org>
+# Redistribution and use is allowed according to the terms of the BSD license.
+# For details see the accompanying COPYING-CMAKE-SCRIPTS file.
+
+if (TVMET_INCLUDE_DIR)
+
+ # in cache already
+ set(TVMET_FOUND TRUE)
+
+else (TVMET_INCLUDE_DIR)
+
+find_path(TVMET_INCLUDE_DIR NAMES tvmet/tvmet.h
+ PATHS
+ ${TVMETDIR}/
+ ${INCLUDE_INSTALL_DIR}
+ )
+
+include(FindPackageHandleStandardArgs)
+find_package_handle_standard_args(Tvmet DEFAULT_MSG TVMET_INCLUDE_DIR)
+
+mark_as_advanced(TVMET_INCLUDE_DIR)
+
+endif(TVMET_INCLUDE_DIR)
+
diff --git a/bench/btl/cmake/MacroOptionalAddSubdirectory.cmake b/bench/btl/cmake/MacroOptionalAddSubdirectory.cmake
new file mode 100644
index 000000000..545048b68
--- /dev/null
+++ b/bench/btl/cmake/MacroOptionalAddSubdirectory.cmake
@@ -0,0 +1,31 @@
+# - MACRO_OPTIONAL_ADD_SUBDIRECTORY() combines ADD_SUBDIRECTORY() with an OPTION()
+# MACRO_OPTIONAL_ADD_SUBDIRECTORY( <dir> )
+# If you use MACRO_OPTIONAL_ADD_SUBDIRECTORY() instead of ADD_SUBDIRECTORY(),
+# this will have two effects
+# 1 - CMake will not complain if the directory doesn't exist
+# This makes sense if you want to distribute just one of the subdirs
+# in a source package, e.g. just one of the subdirs in kdeextragear.
+# 2 - If the directory exists, it will offer an option to skip the
+# subdirectory.
+# This is useful if you want to compile only a subset of all
+# directories.
+
+# Copyright (c) 2007, Alexander Neundorf, <neundorf@kde.org>
+#
+# Redistribution and use is allowed according to the terms of the BSD license.
+# For details see the accompanying COPYING-CMAKE-SCRIPTS file.
+
+
+MACRO (MACRO_OPTIONAL_ADD_SUBDIRECTORY _dir )
+ GET_FILENAME_COMPONENT(_fullPath ${_dir} ABSOLUTE)
+ IF(EXISTS ${_fullPath})
+ IF(${ARGC} EQUAL 2)
+ OPTION(BUILD_${_dir} "Build directory ${_dir}" ${ARGV1})
+ ELSE(${ARGC} EQUAL 2)
+ OPTION(BUILD_${_dir} "Build directory ${_dir}" TRUE)
+ ENDIF(${ARGC} EQUAL 2)
+ IF(BUILD_${_dir})
+ ADD_SUBDIRECTORY(${_dir})
+ ENDIF(BUILD_${_dir})
+ ENDIF(EXISTS ${_fullPath})
+ENDMACRO (MACRO_OPTIONAL_ADD_SUBDIRECTORY)
diff --git a/bench/btl/data/CMakeLists.txt b/bench/btl/data/CMakeLists.txt
new file mode 100644
index 000000000..6af2a366f
--- /dev/null
+++ b/bench/btl/data/CMakeLists.txt
@@ -0,0 +1,32 @@
+
+ADD_CUSTOM_TARGET(copy_scripts)
+
+SET(script_files go_mean mk_mean_script.sh mk_new_gnuplot.sh
+ perlib_plot_settings.txt action_settings.txt gnuplot_common_settings.hh )
+
+FOREACH(script_file ${script_files})
+ADD_CUSTOM_COMMAND(
+ TARGET copy_scripts
+ POST_BUILD
+ COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_CURRENT_SOURCE_DIR}/${script_file} ${CMAKE_CURRENT_BINARY_DIR}/
+ ARGS
+)
+ENDFOREACH(script_file)
+
+ADD_CUSTOM_COMMAND(
+ TARGET copy_scripts
+ POST_BUILD
+ COMMAND ${CMAKE_CXX_COMPILER} --version | head -n 1 > ${CMAKE_CURRENT_BINARY_DIR}/compiler_version.txt
+ ARGS
+)
+ADD_CUSTOM_COMMAND(
+ TARGET copy_scripts
+ POST_BUILD
+ COMMAND echo "${Eigen_SOURCE_DIR}" > ${CMAKE_CURRENT_BINARY_DIR}/eigen_root_dir.txt
+ ARGS
+)
+
+add_executable(smooth smooth.cxx)
+add_executable(regularize regularize.cxx)
+add_executable(main mean.cxx)
+add_dependencies(main copy_scripts)
diff --git a/bench/btl/data/action_settings.txt b/bench/btl/data/action_settings.txt
new file mode 100644
index 000000000..e32213e22
--- /dev/null
+++ b/bench/btl/data/action_settings.txt
@@ -0,0 +1,19 @@
+aat ; "{/*1.5 A x A^T}" ; "matrix size" ; 4:3000
+ata ; "{/*1.5 A^T x A}" ; "matrix size" ; 4:3000
+atv ; "{/*1.5 matrix^T x vector}" ; "matrix size" ; 4:3000
+axpby ; "{/*1.5 Y = alpha X + beta Y}" ; "vector size" ; 5:1000000
+axpy ; "{/*1.5 Y += alpha X}" ; "vector size" ; 5:1000000
+matrix_matrix ; "{/*1.5 matrix matrix product}" ; "matrix size" ; 4:3000
+matrix_vector ; "{/*1.5 matrix vector product}" ; "matrix size" ; 4:3000
+trmm ; "{/*1.5 triangular matrix matrix product}" ; "matrix size" ; 4:3000
+trisolve_vector ; "{/*1.5 triangular solver - vector (X = inv(L) X)}" ; "size" ; 4:3000
+trisolve_matrix ; "{/*1.5 triangular solver - matrix (M = inv(L) M)}" ; "size" ; 4:3000
+cholesky ; "{/*1.5 Cholesky decomposition}" ; "matrix size" ; 4:3000
+complete_lu_decomp ; "{/*1.5 Complete LU decomposition}" ; "matrix size" ; 4:3000
+partial_lu_decomp ; "{/*1.5 Partial LU decomposition}" ; "matrix size" ; 4:3000
+tridiagonalization ; "{/*1.5 Tridiagonalization}" ; "matrix size" ; 4:3000
+hessenberg ; "{/*1.5 Hessenberg decomposition}" ; "matrix size" ; 4:3000
+symv ; "{/*1.5 symmetric matrix vector product}" ; "matrix size" ; 4:3000
+syr2 ; "{/*1.5 symmretric rank-2 update (A += u^T v + u v^T)}" ; "matrix size" ; 4:3000
+ger ; "{/*1.5 general rank-1 update (A += u v^T)}" ; "matrix size" ; 4:3000
+rot ; "{/*1.5 apply rotation in the plane}" ; "vector size" ; 4:1000000 \ No newline at end of file
diff --git a/bench/btl/data/gnuplot_common_settings.hh b/bench/btl/data/gnuplot_common_settings.hh
new file mode 100644
index 000000000..6f677df60
--- /dev/null
+++ b/bench/btl/data/gnuplot_common_settings.hh
@@ -0,0 +1,87 @@
+set noclip points
+set clip one
+set noclip two
+set bar 1.000000
+set border 31 lt -1 lw 1.000
+set xdata
+set ydata
+set zdata
+set x2data
+set y2data
+set boxwidth
+set dummy x,y
+set format x "%g"
+set format y "%g"
+set format x2 "%g"
+set format y2 "%g"
+set format z "%g"
+set angles radians
+set nogrid
+set key title ""
+set key left top Right noreverse box linetype -2 linewidth 1.000 samplen 4 spacing 1 width 0
+set nolabel
+set noarrow
+# set nolinestyle # deprecated
+set nologscale
+set logscale x 10
+set offsets 0, 0, 0, 0
+set pointsize 1
+set encoding default
+set nopolar
+set noparametric
+set view 60, 30, 1, 1
+set samples 100, 100
+set isosamples 10, 10
+set surface
+set nocontour
+set clabel '%8.3g'
+set mapping cartesian
+set nohidden3d
+set cntrparam order 4
+set cntrparam linear
+set cntrparam levels auto 5
+set cntrparam points 5
+set size ratio 0 1,1
+set origin 0,0
+# set data style lines
+# set function style lines
+set xzeroaxis lt -2 lw 1.000
+set x2zeroaxis lt -2 lw 1.000
+set yzeroaxis lt -2 lw 1.000
+set y2zeroaxis lt -2 lw 1.000
+set tics in
+set ticslevel 0.5
+set tics scale 1, 0.5
+set mxtics default
+set mytics default
+set mx2tics default
+set my2tics default
+set xtics border mirror norotate autofreq
+set ytics border mirror norotate autofreq
+set ztics border nomirror norotate autofreq
+set nox2tics
+set noy2tics
+set timestamp "" bottom norotate offset 0,0
+set rrange [ * : * ] noreverse nowriteback # (currently [-0:10] )
+set trange [ * : * ] noreverse nowriteback # (currently [-5:5] )
+set urange [ * : * ] noreverse nowriteback # (currently [-5:5] )
+set vrange [ * : * ] noreverse nowriteback # (currently [-5:5] )
+set xlabel "matrix size" offset 0,0
+set x2label "" offset 0,0
+set timefmt "%d/%m/%y\n%H:%M"
+set xrange [ 10 : 1000 ] noreverse nowriteback
+set x2range [ * : * ] noreverse nowriteback # (currently [-10:10] )
+set ylabel "MFLOPS" offset 0,0
+set y2label "" offset 0,0
+set yrange [ * : * ] noreverse nowriteback # (currently [-10:10] )
+set y2range [ * : * ] noreverse nowriteback # (currently [-10:10] )
+set zlabel "" offset 0,0
+set zrange [ * : * ] noreverse nowriteback # (currently [-10:10] )
+set zero 1e-08
+set lmargin -1
+set bmargin -1
+set rmargin -1
+set tmargin -1
+set locale "C"
+set xrange [4:1024]
+
diff --git a/bench/btl/data/go_mean b/bench/btl/data/go_mean
new file mode 100755
index 000000000..42338ca27
--- /dev/null
+++ b/bench/btl/data/go_mean
@@ -0,0 +1,58 @@
+#!/bin/bash
+
+if [ $# < 1 ]; then
+ echo "Usage: $0 working_directory [tiny|large [prefix]]"
+else
+
+mkdir -p $1
+##cp ../libs/*/*.dat $1
+
+mode=large
+if [ $# > 2 ]; then
+ mode=$2
+fi
+if [ $# > 3 ]; then
+ prefix=$3
+fi
+
+EIGENDIR=`cat eigen_root_dir.txt`
+
+webpagefilename=$1/index.html
+meanstatsfilename=$1/mean.html
+
+echo '' > $meanstatsfilename
+echo '' > $webpagefilename
+echo '<p><strong>Configuration</strong>' >> $webpagefilename
+echo '<ul>'\
+ '<li>' `cat /proc/cpuinfo | grep "model name" | head -n 1`\
+ ' (' `uname -m` ')</li>'\
+ '<li> compiler: ' `cat compiler_version.txt` '</li>'\
+ '<li> eigen3: ' `hg identify -i $EIGENDIR` '</li>'\
+ '</ul>' \
+ '</p>' >> $webpagefilename
+
+source mk_mean_script.sh axpy $1 11 2500 100000 250000 $mode $prefix
+source mk_mean_script.sh axpby $1 11 2500 100000 250000 $mode $prefix
+source mk_mean_script.sh matrix_vector $1 11 50 300 1000 $mode $prefix
+source mk_mean_script.sh atv $1 11 50 300 1000 $mode $prefix
+source mk_mean_script.sh matrix_matrix $1 11 100 300 1000 $mode $prefix
+source mk_mean_script.sh aat $1 11 100 300 1000 $mode $prefix
+# source mk_mean_script.sh ata $1 11 100 300 1000 $mode $prefix
+source mk_mean_script.sh trmm $1 11 100 300 1000 $mode $prefix
+source mk_mean_script.sh trisolve_vector $1 11 100 300 1000 $mode $prefix
+source mk_mean_script.sh trisolve_matrix $1 11 100 300 1000 $mode $prefix
+source mk_mean_script.sh cholesky $1 11 100 300 1000 $mode $prefix
+source mk_mean_script.sh partial_lu_decomp $1 11 100 300 1000 $mode $prefix
+source mk_mean_script.sh tridiagonalization $1 11 100 300 1000 $mode $prefix
+source mk_mean_script.sh hessenberg $1 11 100 300 1000 $mode $prefix
+source mk_mean_script.sh symv $1 11 50 300 1000 $mode $prefix
+source mk_mean_script.sh syr2 $1 11 50 300 1000 $mode $prefix
+source mk_mean_script.sh ger $1 11 50 300 1000 $mode $prefix
+source mk_mean_script.sh rot $1 11 2500 100000 250000 $mode $prefix
+source mk_mean_script.sh complete_lu_decomp $1 11 100 300 1000 $mode $prefix
+
+fi
+
+## compile the web page ##
+
+#echo `cat footer.html` >> $webpagefilename \ No newline at end of file
diff --git a/bench/btl/data/mean.cxx b/bench/btl/data/mean.cxx
new file mode 100644
index 000000000..c567ef33e
--- /dev/null
+++ b/bench/btl/data/mean.cxx
@@ -0,0 +1,182 @@
+//=====================================================
+// File : mean.cxx
+// Author : L. Plagne <laurent.plagne@edf.fr)>
+// Copyright (C) EDF R&D, lun sep 30 14:23:15 CEST 2002
+//=====================================================
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+//
+#include "utilities.h"
+#include <vector>
+#include <string>
+#include <iostream>
+#include <fstream>
+#include "bench_parameter.hh"
+#include "utils/xy_file.hh"
+#include <set>
+
+using namespace std;
+
+double mean_calc(const vector<int> & tab_sizes, const vector<double> & tab_mflops, const int size_min, const int size_max);
+
+class Lib_Mean{
+
+public:
+ Lib_Mean( void ):_lib_name(),_mean_in_cache(),_mean_out_of_cache(){
+ MESSAGE("Lib_mean Default Ctor");
+ MESSAGE("!!! should not be used");
+ exit(0);
+ }
+ Lib_Mean(const string & name, const double & mic, const double & moc):_lib_name(name),_mean_in_cache(mic),_mean_out_of_cache(moc){
+ MESSAGE("Lib_mean Ctor");
+ }
+ Lib_Mean(const Lib_Mean & lm):_lib_name(lm._lib_name),_mean_in_cache(lm._mean_in_cache),_mean_out_of_cache(lm._mean_out_of_cache){
+ MESSAGE("Lib_mean Copy Ctor");
+ }
+ ~Lib_Mean( void ){
+ MESSAGE("Lib_mean Dtor");
+ }
+
+ double _mean_in_cache;
+ double _mean_out_of_cache;
+ string _lib_name;
+
+ bool operator < ( const Lib_Mean &right) const
+ {
+ //return ( this->_mean_out_of_cache > right._mean_out_of_cache) ;
+ return ( this->_mean_in_cache > right._mean_in_cache) ;
+ }
+
+};
+
+
+int main( int argc , char *argv[] )
+{
+
+ if (argc<6){
+ INFOS("!!! Error ... usage : main what mic Mic moc Moc filename1 finename2...");
+ exit(0);
+ }
+ INFOS(argc);
+
+ int min_in_cache=atoi(argv[2]);
+ int max_in_cache=atoi(argv[3]);
+ int min_out_of_cache=atoi(argv[4]);
+ int max_out_of_cache=atoi(argv[5]);
+
+
+ multiset<Lib_Mean> s_lib_mean ;
+
+ for (int i=6;i<argc;i++){
+
+ string filename=argv[i];
+
+ INFOS(filename);
+
+ double mic=0;
+ double moc=0;
+
+ {
+
+ vector<int> tab_sizes;
+ vector<double> tab_mflops;
+
+ read_xy_file(filename,tab_sizes,tab_mflops);
+
+ mic=mean_calc(tab_sizes,tab_mflops,min_in_cache,max_in_cache);
+ moc=mean_calc(tab_sizes,tab_mflops,min_out_of_cache,max_out_of_cache);
+
+ Lib_Mean cur_lib_mean(filename,mic,moc);
+
+ s_lib_mean.insert(cur_lib_mean);
+
+ }
+
+ }
+
+
+ cout << "<TABLE BORDER CELLPADDING=2>" << endl ;
+ cout << " <TR>" << endl ;
+ cout << " <TH ALIGN=CENTER> " << argv[1] << " </TH>" << endl ;
+ cout << " <TH ALIGN=CENTER> <a href=""#mean_marker""> in cache <BR> mean perf <BR> Mflops </a></TH>" << endl ;
+ cout << " <TH ALIGN=CENTER> in cache <BR> % best </TH>" << endl ;
+ cout << " <TH ALIGN=CENTER> <a href=""#mean_marker""> out of cache <BR> mean perf <BR> Mflops </a></TH>" << endl ;
+ cout << " <TH ALIGN=CENTER> out of cache <BR> % best </TH>" << endl ;
+ cout << " <TH ALIGN=CENTER> details </TH>" << endl ;
+ cout << " <TH ALIGN=CENTER> comments </TH>" << endl ;
+ cout << " </TR>" << endl ;
+
+ multiset<Lib_Mean>::iterator is = s_lib_mean.begin();
+ Lib_Mean best(*is);
+
+
+ for (is=s_lib_mean.begin(); is!=s_lib_mean.end() ; is++){
+
+ cout << " <TR>" << endl ;
+ cout << " <TD> " << is->_lib_name << " </TD>" << endl ;
+ cout << " <TD> " << is->_mean_in_cache << " </TD>" << endl ;
+ cout << " <TD> " << 100*(is->_mean_in_cache/best._mean_in_cache) << " </TD>" << endl ;
+ cout << " <TD> " << is->_mean_out_of_cache << " </TD>" << endl ;
+ cout << " <TD> " << 100*(is->_mean_out_of_cache/best._mean_out_of_cache) << " </TD>" << endl ;
+ cout << " <TD> " <<
+ "<a href=\"#"<<is->_lib_name<<"_"<<argv[1]<<"\">snippet</a>/"
+ "<a href=\"#"<<is->_lib_name<<"_flags\">flags</a> </TD>" << endl ;
+ cout << " <TD> " <<
+ "<a href=\"#"<<is->_lib_name<<"_comments\">click here</a> </TD>" << endl ;
+ cout << " </TR>" << endl ;
+
+ }
+
+ cout << "</TABLE>" << endl ;
+
+ ofstream output_file ("../order_lib",ios::out) ;
+
+ for (is=s_lib_mean.begin(); is!=s_lib_mean.end() ; is++){
+ output_file << is->_lib_name << endl ;
+ }
+
+ output_file.close();
+
+}
+
+double mean_calc(const vector<int> & tab_sizes, const vector<double> & tab_mflops, const int size_min, const int size_max){
+
+ int size=tab_sizes.size();
+ int nb_sample=0;
+ double mean=0.0;
+
+ for (int i=0;i<size;i++){
+
+
+ if ((tab_sizes[i]>=size_min)&&(tab_sizes[i]<=size_max)){
+
+ nb_sample++;
+ mean+=tab_mflops[i];
+
+ }
+
+
+ }
+
+ if (nb_sample==0){
+ INFOS("no data for mean calculation");
+ return 0.0;
+ }
+
+ return mean/nb_sample;
+}
+
+
+
+
diff --git a/bench/btl/data/mk_gnuplot_script.sh b/bench/btl/data/mk_gnuplot_script.sh
new file mode 100644
index 000000000..2ca7b5cb5
--- /dev/null
+++ b/bench/btl/data/mk_gnuplot_script.sh
@@ -0,0 +1,68 @@
+#! /bin/bash
+WHAT=$1
+DIR=$2
+echo $WHAT script generation
+cat $WHAT.hh > $WHAT.gnuplot
+
+DATA_FILE=`find $DIR -name "*.dat" | grep $WHAT`
+
+echo plot \\ >> $WHAT.gnuplot
+
+for FILE in $DATA_FILE
+do
+ LAST=$FILE
+done
+
+echo LAST=$LAST
+
+for FILE in $DATA_FILE
+do
+ if [ $FILE != $LAST ]
+ then
+ BASE=${FILE##*/} ; BASE=${FILE##*/} ; AVANT=bench_${WHAT}_ ; REDUC=${BASE##*$AVANT} ; TITLE=${REDUC%.dat}
+ echo "'"$FILE"'" title "'"$TITLE"'" ",\\" >> $WHAT.gnuplot
+ fi
+done
+BASE=${LAST##*/} ; BASE=${FILE##*/} ; AVANT=bench_${WHAT}_ ; REDUC=${BASE##*$AVANT} ; TITLE=${REDUC%.dat}
+echo "'"$LAST"'" title "'"$TITLE"'" >> $WHAT.gnuplot
+
+#echo set term postscript color >> $WHAT.gnuplot
+#echo set output "'"$WHAT.ps"'" >> $WHAT.gnuplot
+echo set term pbm small color >> $WHAT.gnuplot
+echo set output "'"$WHAT.ppm"'" >> $WHAT.gnuplot
+echo plot \\ >> $WHAT.gnuplot
+
+for FILE in $DATA_FILE
+do
+ if [ $FILE != $LAST ]
+ then
+ BASE=${FILE##*/} ; BASE=${FILE##*/} ; AVANT=bench_${WHAT}_ ; REDUC=${BASE##*$AVANT} ; TITLE=${REDUC%.dat}
+ echo "'"$FILE"'" title "'"$TITLE"'" ",\\" >> $WHAT.gnuplot
+ fi
+done
+BASE=${LAST##*/} ; BASE=${FILE##*/} ; AVANT=bench_${WHAT}_ ; REDUC=${BASE##*$AVANT} ; TITLE=${REDUC%.dat}
+echo "'"$LAST"'" title "'"$TITLE"'" >> $WHAT.gnuplot
+
+echo set term jpeg large >> $WHAT.gnuplot
+echo set output "'"$WHAT.jpg"'" >> $WHAT.gnuplot
+echo plot \\ >> $WHAT.gnuplot
+
+for FILE in $DATA_FILE
+do
+ if [ $FILE != $LAST ]
+ then
+ BASE=${FILE##*/} ; BASE=${FILE##*/} ; AVANT=bench_${WHAT}_ ; REDUC=${BASE##*$AVANT} ; TITLE=${REDUC%.dat}
+ echo "'"$FILE"'" title "'"$TITLE"'" ",\\" >> $WHAT.gnuplot
+ fi
+done
+BASE=${LAST##*/} ; BASE=${FILE##*/} ; AVANT=bench_${WHAT}_ ; REDUC=${BASE##*$AVANT} ; TITLE=${REDUC%.dat}
+echo "'"$LAST"'" title "'"$TITLE"'" >> $WHAT.gnuplot
+
+
+gnuplot -persist < $WHAT.gnuplot
+
+rm $WHAT.gnuplot
+
+
+
+
diff --git a/bench/btl/data/mk_mean_script.sh b/bench/btl/data/mk_mean_script.sh
new file mode 100644
index 000000000..b10df0240
--- /dev/null
+++ b/bench/btl/data/mk_mean_script.sh
@@ -0,0 +1,52 @@
+#! /bin/bash
+WHAT=$1
+DIR=$2
+MINIC=$3
+MAXIC=$4
+MINOC=$5
+MAXOC=$6
+prefix=$8
+
+meanstatsfilename=$2/mean.html
+
+WORK_DIR=tmp
+mkdir $WORK_DIR
+
+DATA_FILE=`find $DIR -name "*.dat" | grep _${WHAT}`
+
+if [ -n "$DATA_FILE" ]; then
+
+ echo ""
+ echo "$1..."
+ for FILE in $DATA_FILE
+ do
+ ##echo hello world
+ ##echo "mk_mean_script1" ${FILE}
+ BASE=${FILE##*/} ; BASE=${FILE##*/} ; AVANT=bench_${WHAT}_ ; REDUC=${BASE##*$AVANT} ; TITLE=${REDUC%.dat}
+
+ ##echo "mk_mean_script1" ${TITLE}
+ cp $FILE ${WORK_DIR}/${TITLE}
+
+ done
+
+ cd $WORK_DIR
+ ../main $1 $3 $4 $5 $6 * >> ../$meanstatsfilename
+ ../mk_new_gnuplot.sh $1 $2 $7
+ rm -f *.gnuplot
+ cd ..
+
+ echo '<br/>' >> $meanstatsfilename
+
+ webpagefilename=$2/index.html
+ # echo '<h3>'${WHAT}'</h3>' >> $webpagefilename
+ echo '<hr/><a href="'$prefix$1'.pdf"><img src="'$prefix$1'.png" alt="'${WHAT}'" /></a><br/>' >> $webpagefilename
+
+fi
+
+rm -R $WORK_DIR
+
+
+
+
+
+
diff --git a/bench/btl/data/mk_new_gnuplot.sh b/bench/btl/data/mk_new_gnuplot.sh
new file mode 100755
index 000000000..fad3b23a4
--- /dev/null
+++ b/bench/btl/data/mk_new_gnuplot.sh
@@ -0,0 +1,54 @@
+#!/bin/bash
+WHAT=$1
+DIR=$2
+
+cat ../gnuplot_common_settings.hh > ${WHAT}.gnuplot
+
+echo "set title " `grep ${WHAT} ../action_settings.txt | head -n 1 | cut -d ";" -f 2` >> $WHAT.gnuplot
+echo "set xlabel " `grep ${WHAT} ../action_settings.txt | head -n 1 | cut -d ";" -f 3` " offset 0,0" >> $WHAT.gnuplot
+echo "set xrange [" `grep ${WHAT} ../action_settings.txt | head -n 1 | cut -d ";" -f 4` "]" >> $WHAT.gnuplot
+
+if [ $# > 3 ]; then
+ if [ "$3" == "tiny" ]; then
+ echo "set xrange [2:16]" >> $WHAT.gnuplot
+ echo "set nologscale" >> $WHAT.gnuplot
+ fi
+fi
+
+
+
+DATA_FILE=`cat ../order_lib`
+echo set term postscript color rounded enhanced >> $WHAT.gnuplot
+echo set output "'"../${DIR}/$WHAT.ps"'" >> $WHAT.gnuplot
+
+# echo set term svg color rounded enhanced >> $WHAT.gnuplot
+# echo "set terminal svg enhanced size 1000 1000 fname \"Times\" fsize 36" >> $WHAT.gnuplot
+# echo set output "'"../${DIR}/$WHAT.svg"'" >> $WHAT.gnuplot
+
+echo plot \\ >> $WHAT.gnuplot
+
+for FILE in $DATA_FILE
+do
+ LAST=$FILE
+done
+
+for FILE in $DATA_FILE
+do
+ BASE=${FILE##*/} ; BASE=${FILE##*/} ; AVANT=bench_${WHAT}_ ; REDUC=${BASE##*$AVANT} ; TITLE=${REDUC%.dat}
+
+ echo "'"$FILE"'" `grep $TITLE ../perlib_plot_settings.txt | head -n 1 | cut -d ";" -f 2` "\\" >> $WHAT.gnuplot
+ if [ $FILE != $LAST ]
+ then
+ echo ", \\" >> $WHAT.gnuplot
+ fi
+done
+echo " " >> $WHAT.gnuplot
+
+gnuplot -persist < $WHAT.gnuplot
+
+rm $WHAT.gnuplot
+
+ps2pdf ../${DIR}/$WHAT.ps ../${DIR}/$WHAT.pdf
+convert -background white -density 120 -rotate 90 -resize 800 +dither -colors 256 -quality 0 ../${DIR}/$WHAT.ps -background white -flatten ../${DIR}/$WHAT.png
+
+# pstoedit -rotate -90 -xscale 0.8 -yscale 0.8 -centered -yshift -50 -xshift -100 -f plot-svg aat.ps aat2.svg
diff --git a/bench/btl/data/perlib_plot_settings.txt b/bench/btl/data/perlib_plot_settings.txt
new file mode 100644
index 000000000..6844bab28
--- /dev/null
+++ b/bench/btl/data/perlib_plot_settings.txt
@@ -0,0 +1,16 @@
+eigen3 ; with lines lw 4 lt 1 lc rgbcolor "black"
+eigen2 ; with lines lw 3 lt 1 lc rgbcolor "#999999"
+EigenBLAS ; with lines lw 3 lt 3 lc rgbcolor "#999999"
+eigen3_novec ; with lines lw 2 lt 1 lc rgbcolor "#999999"
+eigen3_nogccvec ; with lines lw 2 lt 2 lc rgbcolor "#991010"
+INTEL_MKL ; with lines lw 3 lt 1 lc rgbcolor "#ff0000"
+ATLAS ; with lines lw 3 lt 1 lc rgbcolor "#008000"
+gmm ; with lines lw 3 lt 1 lc rgbcolor "#0000ff"
+ublas ; with lines lw 3 lt 1 lc rgbcolor "#00b7ff"
+mtl4 ; with lines lw 3 lt 1 lc rgbcolor "#d18847"
+blitz ; with lines lw 3 lt 1 lc rgbcolor "#ff00ff"
+F77 ; with lines lw 3 lt 3 lc rgbcolor "#e6e64c"
+GOTO ; with lines lw 3 lt 3 lc rgbcolor "#C05600"
+GOTO2 ; with lines lw 3 lt 1 lc rgbcolor "#C05600"
+C ; with lines lw 3 lt 3 lc rgbcolor "#e6bd96"
+ACML ; with lines lw 2 lt 3 lc rgbcolor "#e6e64c"
diff --git a/bench/btl/data/regularize.cxx b/bench/btl/data/regularize.cxx
new file mode 100644
index 000000000..eea2b8b85
--- /dev/null
+++ b/bench/btl/data/regularize.cxx
@@ -0,0 +1,131 @@
+//=====================================================
+// File : regularize.cxx
+// Author : L. Plagne <laurent.plagne@edf.fr)>
+// Copyright (C) EDF R&D, lun sep 30 14:23:15 CEST 2002
+//=====================================================
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+//
+#include "utilities.h"
+#include <vector>
+#include <string>
+#include <iostream>
+#include <fstream>
+#include "bench_parameter.hh"
+#include <set>
+
+using namespace std;
+
+void read_xy_file(const string & filename, vector<int> & tab_sizes, vector<double> & tab_mflops);
+void regularize_curve(const string & filename,
+ const vector<double> & tab_mflops,
+ const vector<int> & tab_sizes,
+ int start_cut_size, int stop_cut_size);
+/////////////////////////////////////////////////////////////////////////////////////////////////
+
+int main( int argc , char *argv[] )
+{
+
+ // input data
+
+ if (argc<4){
+ INFOS("!!! Error ... usage : main filename start_cut_size stop_cut_size regularize_filename");
+ exit(0);
+ }
+ INFOS(argc);
+
+ int start_cut_size=atoi(argv[2]);
+ int stop_cut_size=atoi(argv[3]);
+
+ string filename=argv[1];
+ string regularize_filename=argv[4];
+
+ INFOS(filename);
+ INFOS("start_cut_size="<<start_cut_size);
+
+ vector<int> tab_sizes;
+ vector<double> tab_mflops;
+
+ read_xy_file(filename,tab_sizes,tab_mflops);
+
+ // regularizeing
+
+ regularize_curve(regularize_filename,tab_mflops,tab_sizes,start_cut_size,stop_cut_size);
+
+
+}
+
+//////////////////////////////////////////////////////////////////////////////////////
+
+void regularize_curve(const string & filename,
+ const vector<double> & tab_mflops,
+ const vector<int> & tab_sizes,
+ int start_cut_size, int stop_cut_size)
+{
+ int size=tab_mflops.size();
+ ofstream output_file (filename.c_str(),ios::out) ;
+
+ int i=0;
+
+ while(tab_sizes[i]<start_cut_size){
+
+ output_file << tab_sizes[i] << " " << tab_mflops[i] << endl ;
+ i++;
+
+ }
+
+ output_file << endl ;
+
+ while(tab_sizes[i]<stop_cut_size){
+
+ i++;
+
+ }
+
+ while(i<size){
+
+ output_file << tab_sizes[i] << " " << tab_mflops[i] << endl ;
+ i++;
+
+ }
+
+ output_file.close();
+
+}
+
+///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+void read_xy_file(const string & filename, vector<int> & tab_sizes, vector<double> & tab_mflops){
+
+ ifstream input_file (filename.c_str(),ios::in) ;
+
+ if (!input_file){
+ INFOS("!!! Error opening "<<filename);
+ exit(0);
+ }
+
+ int nb_point=0;
+ int size=0;
+ double mflops=0;
+
+ while (input_file >> size >> mflops ){
+ nb_point++;
+ tab_sizes.push_back(size);
+ tab_mflops.push_back(mflops);
+ }
+ SCRUTE(nb_point);
+
+ input_file.close();
+}
+
diff --git a/bench/btl/data/smooth.cxx b/bench/btl/data/smooth.cxx
new file mode 100644
index 000000000..e5270cc32
--- /dev/null
+++ b/bench/btl/data/smooth.cxx
@@ -0,0 +1,198 @@
+//=====================================================
+// File : smooth.cxx
+// Author : L. Plagne <laurent.plagne@edf.fr)>
+// Copyright (C) EDF R&D, lun sep 30 14:23:15 CEST 2002
+//=====================================================
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+//
+#include "utilities.h"
+#include <vector>
+#include <deque>
+#include <string>
+#include <iostream>
+#include <fstream>
+#include "bench_parameter.hh"
+#include <set>
+
+using namespace std;
+
+void read_xy_file(const string & filename, vector<int> & tab_sizes, vector<double> & tab_mflops);
+void write_xy_file(const string & filename, vector<int> & tab_sizes, vector<double> & tab_mflops);
+void smooth_curve(const vector<double> & tab_mflops, vector<double> & smooth_tab_mflops,int window_half_width);
+void centered_smooth_curve(const vector<double> & tab_mflops, vector<double> & smooth_tab_mflops,int window_half_width);
+
+/////////////////////////////////////////////////////////////////////////////////////////////////
+
+int main( int argc , char *argv[] )
+{
+
+ // input data
+
+ if (argc<3){
+ INFOS("!!! Error ... usage : main filename window_half_width smooth_filename");
+ exit(0);
+ }
+ INFOS(argc);
+
+ int window_half_width=atoi(argv[2]);
+
+ string filename=argv[1];
+ string smooth_filename=argv[3];
+
+ INFOS(filename);
+ INFOS("window_half_width="<<window_half_width);
+
+ vector<int> tab_sizes;
+ vector<double> tab_mflops;
+
+ read_xy_file(filename,tab_sizes,tab_mflops);
+
+ // smoothing
+
+ vector<double> smooth_tab_mflops;
+
+ //smooth_curve(tab_mflops,smooth_tab_mflops,window_half_width);
+ centered_smooth_curve(tab_mflops,smooth_tab_mflops,window_half_width);
+
+ // output result
+
+ write_xy_file(smooth_filename,tab_sizes,smooth_tab_mflops);
+
+
+}
+
+///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+template<class VECTOR>
+double weighted_mean(const VECTOR & data)
+{
+
+ double mean=0.0;
+
+ for (int i=0 ; i<data.size() ; i++){
+
+ mean+=data[i];
+
+ }
+
+ return mean/double(data.size()) ;
+
+}
+
+
+
+
+///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+
+void smooth_curve(const vector<double> & tab_mflops, vector<double> & smooth_tab_mflops,int window_half_width){
+
+ int window_width=2*window_half_width+1;
+
+ int size=tab_mflops.size();
+
+ vector<double> sample(window_width);
+
+ for (int i=0 ; i < size ; i++){
+
+ for ( int j=0 ; j < window_width ; j++ ){
+
+ int shifted_index=i+j-window_half_width;
+ if (shifted_index<0) shifted_index=0;
+ if (shifted_index>size-1) shifted_index=size-1;
+ sample[j]=tab_mflops[shifted_index];
+
+ }
+
+ smooth_tab_mflops.push_back(weighted_mean(sample));
+
+ }
+
+}
+
+void centered_smooth_curve(const vector<double> & tab_mflops, vector<double> & smooth_tab_mflops,int window_half_width){
+
+ int max_window_width=2*window_half_width+1;
+
+ int size=tab_mflops.size();
+
+
+ for (int i=0 ; i < size ; i++){
+
+ deque<double> sample;
+
+
+ sample.push_back(tab_mflops[i]);
+
+ for ( int j=1 ; j <= window_half_width ; j++ ){
+
+ int before=i-j;
+ int after=i+j;
+
+ if ((before>=0)&&(after<size)) // inside of the vector
+ {
+ sample.push_front(tab_mflops[before]);
+ sample.push_back(tab_mflops[after]);
+ }
+ }
+
+ smooth_tab_mflops.push_back(weighted_mean(sample));
+
+ }
+
+}
+
+
+///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+void write_xy_file(const string & filename, vector<int> & tab_sizes, vector<double> & tab_mflops){
+
+ ofstream output_file (filename.c_str(),ios::out) ;
+
+ for (int i=0 ; i < tab_sizes.size() ; i++)
+ {
+ output_file << tab_sizes[i] << " " << tab_mflops[i] << endl ;
+ }
+
+ output_file.close();
+
+}
+
+
+///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+void read_xy_file(const string & filename, vector<int> & tab_sizes, vector<double> & tab_mflops){
+
+ ifstream input_file (filename.c_str(),ios::in) ;
+
+ if (!input_file){
+ INFOS("!!! Error opening "<<filename);
+ exit(0);
+ }
+
+ int nb_point=0;
+ int size=0;
+ double mflops=0;
+
+ while (input_file >> size >> mflops ){
+ nb_point++;
+ tab_sizes.push_back(size);
+ tab_mflops.push_back(mflops);
+ }
+ SCRUTE(nb_point);
+
+ input_file.close();
+}
+
diff --git a/bench/btl/data/smooth_all.sh b/bench/btl/data/smooth_all.sh
new file mode 100755
index 000000000..3e5bfdf47
--- /dev/null
+++ b/bench/btl/data/smooth_all.sh
@@ -0,0 +1,68 @@
+#! /bin/bash
+ORIG_DIR=$1
+SMOOTH_DIR=${ORIG_DIR}_smooth
+mkdir ${SMOOTH_DIR}
+
+AXPY_FILE=`find ${ORIG_DIR} -name "*.dat" | grep axpy`
+for FILE in ${AXPY_FILE}
+do
+ echo $FILE
+ BASE=${FILE##*/}
+ ./smooth ${ORIG_DIR}/${BASE} 4 ${SMOOTH_DIR}/${BASE}_tmp
+ ./regularize ${SMOOTH_DIR}/${BASE}_tmp 2500 15000 ${SMOOTH_DIR}/${BASE}
+ rm -f ${SMOOTH_DIR}/${BASE}_tmp
+done
+
+
+MATRIX_VECTOR_FILE=`find ${ORIG_DIR} -name "*.dat" | grep matrix_vector`
+for FILE in ${MATRIX_VECTOR_FILE}
+do
+ echo $FILE
+ BASE=${FILE##*/}
+ ./smooth ${ORIG_DIR}/${BASE} 4 ${SMOOTH_DIR}/${BASE}_tmp
+ ./regularize ${SMOOTH_DIR}/${BASE}_tmp 50 180 ${SMOOTH_DIR}/${BASE}
+ rm -f ${SMOOTH_DIR}/${BASE}_tmp
+done
+
+MATRIX_MATRIX_FILE=`find ${ORIG_DIR} -name "*.dat" | grep matrix_matrix`
+for FILE in ${MATRIX_MATRIX_FILE}
+do
+ echo $FILE
+ BASE=${FILE##*/}
+ ./smooth ${ORIG_DIR}/${BASE} 4 ${SMOOTH_DIR}/${BASE}
+done
+
+AAT_FILE=`find ${ORIG_DIR} -name "*.dat" | grep _aat`
+for FILE in ${AAT_FILE}
+do
+ echo $FILE
+ BASE=${FILE##*/}
+ ./smooth ${ORIG_DIR}/${BASE} 4 ${SMOOTH_DIR}/${BASE}
+done
+
+
+ATA_FILE=`find ${ORIG_DIR} -name "*.dat" | grep _ata`
+for FILE in ${ATA_FILE}
+do
+ echo $FILE
+ BASE=${FILE##*/}
+ ./smooth ${ORIG_DIR}/${BASE} 4 ${SMOOTH_DIR}/${BASE}
+done
+
+### no smoothing for tinyvector and matrices libs
+
+TINY_BLITZ_FILE=`find ${ORIG_DIR} -name "*.dat" | grep tiny_blitz`
+for FILE in ${TINY_BLITZ_FILE}
+do
+ echo $FILE
+ BASE=${FILE##*/}
+ cp ${ORIG_DIR}/${BASE} ${SMOOTH_DIR}/${BASE}
+done
+
+TVMET_FILE=`find ${ORIG_DIR} -name "*.dat" | grep tvmet`
+for FILE in ${TVMET_FILE}
+do
+ echo $FILE
+ BASE=${FILE##*/}
+ cp ${ORIG_DIR}/${BASE} ${SMOOTH_DIR}/${BASE}
+done
diff --git a/bench/btl/generic_bench/bench.hh b/bench/btl/generic_bench/bench.hh
new file mode 100644
index 000000000..005c36395
--- /dev/null
+++ b/bench/btl/generic_bench/bench.hh
@@ -0,0 +1,168 @@
+//=====================================================
+// File : bench.hh
+// Author : L. Plagne <laurent.plagne@edf.fr)>
+// Copyright (C) EDF R&D, lun sep 30 14:23:16 CEST 2002
+//=====================================================
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+//
+#ifndef BENCH_HH
+#define BENCH_HH
+
+#include "btl.hh"
+#include "bench_parameter.hh"
+#include <iostream>
+#include "utilities.h"
+#include "size_lin_log.hh"
+#include "xy_file.hh"
+#include <vector>
+#include <string>
+#include "timers/portable_perf_analyzer.hh"
+// #include "timers/mixed_perf_analyzer.hh"
+// #include "timers/x86_perf_analyzer.hh"
+// #include "timers/STL_perf_analyzer.hh"
+#ifdef HAVE_MKL
+extern "C" void cblas_saxpy(const int, const float, const float*, const int, float *, const int);
+#endif
+using namespace std;
+
+template <template<class> class Perf_Analyzer, class Action>
+BTL_DONT_INLINE void bench( int size_min, int size_max, int nb_point )
+{
+ if (BtlConfig::skipAction(Action::name()))
+ return;
+
+ string filename="bench_"+Action::name()+".dat";
+
+ INFOS("starting " <<filename);
+
+ // utilities
+
+ std::vector<double> tab_mflops(nb_point);
+ std::vector<int> tab_sizes(nb_point);
+
+ // matrices and vector size calculations
+ size_lin_log(nb_point,size_min,size_max,tab_sizes);
+
+ std::vector<int> oldSizes;
+ std::vector<double> oldFlops;
+ bool hasOldResults = read_xy_file(filename, oldSizes, oldFlops, true);
+ int oldi = oldSizes.size() - 1;
+
+ // loop on matrix size
+ Perf_Analyzer<Action> perf_action;
+ for (int i=nb_point-1;i>=0;i--)
+ {
+ //INFOS("size=" <<tab_sizes[i]<<" ("<<nb_point-i<<"/"<<nb_point<<")");
+ std::cout << " " << "size = " << tab_sizes[i] << " " << std::flush;
+
+ BTL_DISABLE_SSE_EXCEPTIONS();
+ #ifdef HAVE_MKL
+ {
+ float dummy;
+ cblas_saxpy(1,0,&dummy,1,&dummy,1);
+ }
+ #endif
+
+ tab_mflops[i] = perf_action.eval_mflops(tab_sizes[i]);
+ std::cout << tab_mflops[i];
+
+ if (hasOldResults)
+ {
+ while (oldi>=0 && oldSizes[oldi]>tab_sizes[i])
+ --oldi;
+ if (oldi>=0 && oldSizes[oldi]==tab_sizes[i])
+ {
+ if (oldFlops[oldi]<tab_mflops[i])
+ std::cout << "\t > ";
+ else
+ std::cout << "\t < ";
+ std::cout << oldFlops[oldi];
+ }
+ --oldi;
+ }
+ std::cout << " MFlops (" << nb_point-i << "/" << nb_point << ")" << std::endl;
+ }
+
+ if (!BtlConfig::Instance.overwriteResults)
+ {
+ if (hasOldResults)
+ {
+ // merge the two data
+ std::vector<int> newSizes;
+ std::vector<double> newFlops;
+ int i=0;
+ int j=0;
+ while (i<tab_sizes.size() && j<oldSizes.size())
+ {
+ if (tab_sizes[i] == oldSizes[j])
+ {
+ newSizes.push_back(tab_sizes[i]);
+ newFlops.push_back(std::max(tab_mflops[i], oldFlops[j]));
+ ++i;
+ ++j;
+ }
+ else if (tab_sizes[i] < oldSizes[j])
+ {
+ newSizes.push_back(tab_sizes[i]);
+ newFlops.push_back(tab_mflops[i]);
+ ++i;
+ }
+ else
+ {
+ newSizes.push_back(oldSizes[j]);
+ newFlops.push_back(oldFlops[j]);
+ ++j;
+ }
+ }
+ while (i<tab_sizes.size())
+ {
+ newSizes.push_back(tab_sizes[i]);
+ newFlops.push_back(tab_mflops[i]);
+ ++i;
+ }
+ while (j<oldSizes.size())
+ {
+ newSizes.push_back(oldSizes[j]);
+ newFlops.push_back(oldFlops[j]);
+ ++j;
+ }
+ tab_mflops = newFlops;
+ tab_sizes = newSizes;
+ }
+ }
+
+ // dump the result in a file :
+ dump_xy_file(tab_sizes,tab_mflops,filename);
+
+}
+
+// default Perf Analyzer
+
+template <class Action>
+BTL_DONT_INLINE void bench( int size_min, int size_max, int nb_point ){
+
+ // if the rdtsc is not available :
+ bench<Portable_Perf_Analyzer,Action>(size_min,size_max,nb_point);
+ // if the rdtsc is available :
+// bench<Mixed_Perf_Analyzer,Action>(size_min,size_max,nb_point);
+
+
+ // Only for small problem size. Otherwize it will be too long
+// bench<X86_Perf_Analyzer,Action>(size_min,size_max,nb_point);
+// bench<STL_Perf_Analyzer,Action>(size_min,size_max,nb_point);
+
+}
+
+#endif
diff --git a/bench/btl/generic_bench/bench_parameter.hh b/bench/btl/generic_bench/bench_parameter.hh
new file mode 100644
index 000000000..4c355cd6e
--- /dev/null
+++ b/bench/btl/generic_bench/bench_parameter.hh
@@ -0,0 +1,53 @@
+//=====================================================
+// File : bench_parameter.hh
+// Author : L. Plagne <laurent.plagne@edf.fr)>
+// Copyright (C) EDF R&D, lun sep 30 14:23:16 CEST 2002
+//=====================================================
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+//
+#ifndef BENCH_PARAMETER_HH
+#define BENCH_PARAMETER_HH
+
+// minimal time for each measurement
+#define REAL_TYPE float
+// minimal time for each measurement
+#define MIN_TIME 0.2
+// nb of point on bench curves
+#define NB_POINT 100
+// min vector size for axpy bench
+#define MIN_AXPY 5
+// max vector size for axpy bench
+#define MAX_AXPY 1000000
+// min matrix size for matrix vector product bench
+#define MIN_MV 5
+// max matrix size for matrix vector product bench
+#define MAX_MV 3000
+// min matrix size for matrix matrix product bench
+#define MIN_MM 5
+// max matrix size for matrix matrix product bench
+#define MAX_MM MAX_MV
+// min matrix size for LU bench
+#define MIN_LU 5
+// max matrix size for LU bench
+#define MAX_LU 3000
+// max size for tiny vector and matrix
+#define TINY_MV_MAX_SIZE 16
+// default nb_sample for x86 timer
+#define DEFAULT_NB_SAMPLE 1000
+
+// how many times we run a single bench (keep the best perf)
+#define DEFAULT_NB_TRIES 3
+
+#endif
diff --git a/bench/btl/generic_bench/btl.hh b/bench/btl/generic_bench/btl.hh
new file mode 100644
index 000000000..f1a88ff74
--- /dev/null
+++ b/bench/btl/generic_bench/btl.hh
@@ -0,0 +1,247 @@
+//=====================================================
+// File : btl.hh
+// Copyright (C) 2008 Gael Guennebaud <gael.guennebaud@inria.fr>
+//=====================================================
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+//
+#ifndef BTL_HH
+#define BTL_HH
+
+#include "bench_parameter.hh"
+#include <iostream>
+#include <algorithm>
+#include <vector>
+#include <string>
+#include "utilities.h"
+
+#if (defined __GNUC__)
+#define BTL_ALWAYS_INLINE __attribute__((always_inline)) inline
+#else
+#define BTL_ALWAYS_INLINE inline
+#endif
+
+#if (defined __GNUC__)
+#define BTL_DONT_INLINE __attribute__((noinline))
+#else
+#define BTL_DONT_INLINE
+#endif
+
+#if (defined __GNUC__)
+#define BTL_ASM_COMMENT(X) asm("#" X)
+#else
+#define BTL_ASM_COMMENT(X)
+#endif
+
+#if (defined __GNUC__) && (!defined __INTEL_COMPILER) && !defined(__arm__) && !defined(__powerpc__)
+#define BTL_DISABLE_SSE_EXCEPTIONS() { \
+ int aux; \
+ asm( \
+ "stmxcsr %[aux] \n\t" \
+ "orl $32832, %[aux] \n\t" \
+ "ldmxcsr %[aux] \n\t" \
+ : : [aux] "m" (aux)); \
+}
+#else
+#define BTL_DISABLE_SSE_EXCEPTIONS()
+#endif
+
+/** Enhanced std::string
+*/
+class BtlString : public std::string
+{
+public:
+ BtlString() : std::string() {}
+ BtlString(const BtlString& str) : std::string(static_cast<const std::string&>(str)) {}
+ BtlString(const std::string& str) : std::string(str) {}
+ BtlString(const char* str) : std::string(str) {}
+
+ operator const char* () const { return c_str(); }
+
+ void trim( bool left = true, bool right = true )
+ {
+ int lspaces, rspaces, len = length(), i;
+ lspaces = rspaces = 0;
+
+ if ( left )
+ for (i=0; i<len && (at(i)==' '||at(i)=='\t'||at(i)=='\r'||at(i)=='\n'); ++lspaces,++i);
+
+ if ( right && lspaces < len )
+ for(i=len-1; i>=0 && (at(i)==' '||at(i)=='\t'||at(i)=='\r'||at(i)=='\n'); rspaces++,i--);
+
+ *this = substr(lspaces, len-lspaces-rspaces);
+ }
+
+ std::vector<BtlString> split( const BtlString& delims = "\t\n ") const
+ {
+ std::vector<BtlString> ret;
+ unsigned int numSplits = 0;
+ size_t start, pos;
+ start = 0;
+ do
+ {
+ pos = find_first_of(delims, start);
+ if (pos == start)
+ {
+ ret.push_back("");
+ start = pos + 1;
+ }
+ else if (pos == npos)
+ ret.push_back( substr(start) );
+ else
+ {
+ ret.push_back( substr(start, pos - start) );
+ start = pos + 1;
+ }
+ //start = find_first_not_of(delims, start);
+ ++numSplits;
+ } while (pos != npos);
+ return ret;
+ }
+
+ bool endsWith(const BtlString& str) const
+ {
+ if(str.size()>this->size())
+ return false;
+ return this->substr(this->size()-str.size(),str.size()) == str;
+ }
+ bool contains(const BtlString& str) const
+ {
+ return this->find(str)<this->size();
+ }
+ bool beginsWith(const BtlString& str) const
+ {
+ if(str.size()>this->size())
+ return false;
+ return this->substr(0,str.size()) == str;
+ }
+
+ BtlString toLowerCase( void )
+ {
+ std::transform(begin(), end(), begin(), static_cast<int(*)(int)>(::tolower) );
+ return *this;
+ }
+ BtlString toUpperCase( void )
+ {
+ std::transform(begin(), end(), begin(), static_cast<int(*)(int)>(::toupper) );
+ return *this;
+ }
+
+ /** Case insensitive comparison.
+ */
+ bool isEquiv(const BtlString& str) const
+ {
+ BtlString str0 = *this;
+ str0.toLowerCase();
+ BtlString str1 = str;
+ str1.toLowerCase();
+ return str0 == str1;
+ }
+
+ /** Decompose the current string as a path and a file.
+ For instance: "dir1/dir2/file.ext" leads to path="dir1/dir2/" and filename="file.ext"
+ */
+ void decomposePathAndFile(BtlString& path, BtlString& filename) const
+ {
+ std::vector<BtlString> elements = this->split("/\\");
+ path = "";
+ filename = elements.back();
+ elements.pop_back();
+ if (this->at(0)=='/')
+ path = "/";
+ for (unsigned int i=0 ; i<elements.size() ; ++i)
+ path += elements[i] + "/";
+ }
+};
+
+class BtlConfig
+{
+public:
+ BtlConfig()
+ : overwriteResults(false), checkResults(true), realclock(false), tries(DEFAULT_NB_TRIES)
+ {
+ char * _config;
+ _config = getenv ("BTL_CONFIG");
+ if (_config!=NULL)
+ {
+ std::vector<BtlString> config = BtlString(_config).split(" \t\n");
+ for (int i = 0; i<config.size(); i++)
+ {
+ if (config[i].beginsWith("-a"))
+ {
+ if (i+1==config.size())
+ {
+ std::cerr << "error processing option: " << config[i] << "\n";
+ exit(2);
+ }
+ Instance.m_selectedActionNames = config[i+1].split(":");
+
+ i += 1;
+ }
+ else if (config[i].beginsWith("-t"))
+ {
+ if (i+1==config.size())
+ {
+ std::cerr << "error processing option: " << config[i] << "\n";
+ exit(2);
+ }
+ Instance.tries = atoi(config[i+1].c_str());
+
+ i += 1;
+ }
+ else if (config[i].beginsWith("--overwrite"))
+ {
+ Instance.overwriteResults = true;
+ }
+ else if (config[i].beginsWith("--nocheck"))
+ {
+ Instance.checkResults = false;
+ }
+ else if (config[i].beginsWith("--real"))
+ {
+ Instance.realclock = true;
+ }
+ }
+ }
+
+ BTL_DISABLE_SSE_EXCEPTIONS();
+ }
+
+ BTL_DONT_INLINE static bool skipAction(const std::string& _name)
+ {
+ if (Instance.m_selectedActionNames.empty())
+ return false;
+
+ BtlString name(_name);
+ for (int i=0; i<Instance.m_selectedActionNames.size(); ++i)
+ if (name.contains(Instance.m_selectedActionNames[i]))
+ return false;
+
+ return true;
+ }
+
+ static BtlConfig Instance;
+ bool overwriteResults;
+ bool checkResults;
+ bool realclock;
+ int tries;
+
+protected:
+ std::vector<BtlString> m_selectedActionNames;
+};
+
+#define BTL_MAIN \
+ BtlConfig BtlConfig::Instance
+
+#endif // BTL_HH
diff --git a/bench/btl/generic_bench/init/init_function.hh b/bench/btl/generic_bench/init/init_function.hh
new file mode 100644
index 000000000..7b3bdbafc
--- /dev/null
+++ b/bench/btl/generic_bench/init/init_function.hh
@@ -0,0 +1,54 @@
+//=====================================================
+// File : init_function.hh
+// Author : L. Plagne <laurent.plagne@edf.fr)>
+// Copyright (C) EDF R&D, lun sep 30 14:23:18 CEST 2002
+//=====================================================
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+//
+#ifndef INIT_FUNCTION_HH
+#define INIT_FUNCTION_HH
+
+double simple_function(int index)
+{
+ return index;
+}
+
+double simple_function(int index_i, int index_j)
+{
+ return index_i+index_j;
+}
+
+double pseudo_random(int index)
+{
+ return std::rand()/double(RAND_MAX);
+}
+
+double pseudo_random(int index_i, int index_j)
+{
+ return std::rand()/double(RAND_MAX);
+}
+
+
+double null_function(int index)
+{
+ return 0.0;
+}
+
+double null_function(int index_i, int index_j)
+{
+ return 0.0;
+}
+
+#endif
diff --git a/bench/btl/generic_bench/init/init_matrix.hh b/bench/btl/generic_bench/init/init_matrix.hh
new file mode 100644
index 000000000..67cbd2073
--- /dev/null
+++ b/bench/btl/generic_bench/init/init_matrix.hh
@@ -0,0 +1,64 @@
+//=====================================================
+// File : init_matrix.hh
+// Author : L. Plagne <laurent.plagne@edf.fr)>
+// Copyright (C) EDF R&D, lun sep 30 14:23:19 CEST 2002
+//=====================================================
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+//
+#ifndef INIT_MATRIX_HH
+#define INIT_MATRIX_HH
+
+// The Vector class must satisfy the following part of STL vector concept :
+// resize() method
+// [] operator for setting element
+// value_type defined
+template<double init_function(int,int), class Vector>
+BTL_DONT_INLINE void init_row(Vector & X, int size, int row){
+
+ X.resize(size);
+
+ for (int j=0;j<X.size();j++){
+ X[j]=typename Vector::value_type(init_function(row,j));
+ }
+}
+
+
+// Matrix is a Vector of Vector
+// The Matrix class must satisfy the following part of STL vector concept :
+// resize() method
+// [] operator for setting rows
+template<double init_function(int,int),class Vector>
+BTL_DONT_INLINE void init_matrix(Vector & A, int size){
+ A.resize(size);
+ for (int row=0; row<A.size() ; row++){
+ init_row<init_function>(A[row],size,row);
+ }
+}
+
+template<double init_function(int,int),class Matrix>
+BTL_DONT_INLINE void init_matrix_symm(Matrix& A, int size){
+ A.resize(size);
+ for (int row=0; row<A.size() ; row++)
+ A[row].resize(size);
+ for (int row=0; row<A.size() ; row++){
+ A[row][row] = init_function(row,row);
+ for (int col=0; col<row ; col++){
+ double x = init_function(row,col);
+ A[row][col] = A[col][row] = x;
+ }
+ }
+}
+
+#endif
diff --git a/bench/btl/generic_bench/init/init_vector.hh b/bench/btl/generic_bench/init/init_vector.hh
new file mode 100644
index 000000000..efaf0c92e
--- /dev/null
+++ b/bench/btl/generic_bench/init/init_vector.hh
@@ -0,0 +1,37 @@
+//=====================================================
+// File : init_vector.hh
+// Author : L. Plagne <laurent.plagne@edf.fr)>
+// Copyright (C) EDF R&D, lun sep 30 14:23:18 CEST 2002
+//=====================================================
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+//
+#ifndef INIT_VECTOR_HH
+#define INIT_VECTOR_HH
+
+// The Vector class must satisfy the following part of STL vector concept :
+// resize() method
+// [] operator for setting element
+// value_type defined
+template<double init_function(int), class Vector>
+void init_vector(Vector & X, int size){
+
+ X.resize(size);
+
+ for (int i=0;i<X.size();i++){
+ X[i]=typename Vector::value_type(init_function(i));
+ }
+}
+
+#endif
diff --git a/bench/btl/generic_bench/static/bench_static.hh b/bench/btl/generic_bench/static/bench_static.hh
new file mode 100644
index 000000000..23b55ecff
--- /dev/null
+++ b/bench/btl/generic_bench/static/bench_static.hh
@@ -0,0 +1,80 @@
+//=====================================================
+// File : bench_static.hh
+// Author : L. Plagne <laurent.plagne@edf.fr)>
+// Copyright (C) EDF R&D, lun sep 30 14:23:16 CEST 2002
+//=====================================================
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+//
+#ifndef BENCH_STATIC_HH
+#define BENCH_STATIC_HH
+
+#include "btl.hh"
+#include "bench_parameter.hh"
+#include <iostream>
+#include "utilities.h"
+#include "xy_file.hh"
+#include "static/static_size_generator.hh"
+#include "timers/portable_perf_analyzer.hh"
+// #include "timers/mixed_perf_analyzer.hh"
+// #include "timers/x86_perf_analyzer.hh"
+
+using namespace std;
+
+
+template <template<class> class Perf_Analyzer, template<class> class Action, template<class,int> class Interface>
+BTL_DONT_INLINE void bench_static(void)
+{
+ if (BtlConfig::skipAction(Action<Interface<REAL_TYPE,10> >::name()))
+ return;
+
+ string filename = "bench_" + Action<Interface<REAL_TYPE,10> >::name() + ".dat";
+
+ INFOS("starting " << filename);
+
+ const int max_size = TINY_MV_MAX_SIZE;
+
+ std::vector<double> tab_mflops;
+ std::vector<double> tab_sizes;
+
+ static_size_generator<max_size,Perf_Analyzer,Action,Interface>::go(tab_sizes,tab_mflops);
+
+ dump_xy_file(tab_sizes,tab_mflops,filename);
+}
+
+// default Perf Analyzer
+template <template<class> class Action, template<class,int> class Interface>
+BTL_DONT_INLINE void bench_static(void)
+{
+ bench_static<Portable_Perf_Analyzer,Action,Interface>();
+ //bench_static<Mixed_Perf_Analyzer,Action,Interface>();
+ //bench_static<X86_Perf_Analyzer,Action,Interface>();
+}
+
+#endif
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/bench/btl/generic_bench/static/intel_bench_fixed_size.hh b/bench/btl/generic_bench/static/intel_bench_fixed_size.hh
new file mode 100644
index 000000000..b4edcbc46
--- /dev/null
+++ b/bench/btl/generic_bench/static/intel_bench_fixed_size.hh
@@ -0,0 +1,66 @@
+//=====================================================
+// File : intel_bench_fixed_size.hh
+// Author : L. Plagne <laurent.plagne@edf.fr)>
+// Copyright (C) EDF R&D, mar déc 3 18:59:37 CET 2002
+//=====================================================
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+//
+#ifndef _BENCH_FIXED_SIZE_HH_
+#define _BENCH_FIXED_SIZE_HH_
+
+#include "utilities.h"
+#include "function_time.hh"
+
+template <class Action>
+double bench_fixed_size(int size, unsigned long long & nb_calc,unsigned long long & nb_init)
+{
+
+ Action action(size);
+
+ double time_baseline=time_init(nb_init,action);
+
+ while (time_baseline < MIN_TIME) {
+
+ //INFOS("nb_init="<<nb_init);
+ //INFOS("time_baseline="<<time_baseline);
+ nb_init*=2;
+ time_baseline=time_init(nb_init,action);
+ }
+
+ time_baseline=time_baseline/(double(nb_init));
+
+ double time_action=time_calculate(nb_calc,action);
+
+ while (time_action < MIN_TIME) {
+
+ nb_calc*=2;
+ time_action=time_calculate(nb_calc,action);
+ }
+
+ INFOS("nb_init="<<nb_init);
+ INFOS("nb_calc="<<nb_calc);
+
+
+ time_action=time_action/(double(nb_calc));
+
+ action.check_result();
+
+ time_action=time_action-time_baseline;
+
+ return action.nb_op_base()/(time_action*1000000.0);
+
+}
+
+#endif
diff --git a/bench/btl/generic_bench/static/static_size_generator.hh b/bench/btl/generic_bench/static/static_size_generator.hh
new file mode 100644
index 000000000..dd02df3f1
--- /dev/null
+++ b/bench/btl/generic_bench/static/static_size_generator.hh
@@ -0,0 +1,57 @@
+//=====================================================
+// File : static_size_generator.hh
+// Author : L. Plagne <laurent.plagne@edf.fr)>
+// Copyright (C) EDF R&D, mar déc 3 18:59:36 CET 2002
+//=====================================================
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+//
+#ifndef _STATIC_SIZE_GENERATOR_HH
+#define _STATIC_SIZE_GENERATOR_HH
+#include <vector>
+
+using namespace std;
+
+//recursive generation of statically defined matrix and vector sizes
+
+template <int SIZE,template<class> class Perf_Analyzer, template<class> class Action, template<class,int> class Interface>
+struct static_size_generator{
+ static void go(vector<double> & tab_sizes, vector<double> & tab_mflops)
+ {
+ tab_sizes.push_back(SIZE);
+ std::cout << tab_sizes.back() << " \t" << std::flush;
+ Perf_Analyzer<Action<Interface<REAL_TYPE,SIZE> > > perf_action;
+ tab_mflops.push_back(perf_action.eval_mflops(SIZE));
+ std::cout << tab_mflops.back() << " MFlops" << std::endl;
+ static_size_generator<SIZE-1,Perf_Analyzer,Action,Interface>::go(tab_sizes,tab_mflops);
+ };
+};
+
+//recursion end
+
+template <template<class> class Perf_Analyzer, template<class> class Action, template<class,int> class Interface>
+struct static_size_generator<1,Perf_Analyzer,Action,Interface>{
+ static void go(vector<double> & tab_sizes, vector<double> & tab_mflops)
+ {
+ tab_sizes.push_back(1);
+ Perf_Analyzer<Action<Interface<REAL_TYPE,1> > > perf_action;
+ tab_mflops.push_back(perf_action.eval_mflops(1));
+ };
+};
+
+#endif
+
+
+
+
diff --git a/bench/btl/generic_bench/timers/STL_perf_analyzer.hh b/bench/btl/generic_bench/timers/STL_perf_analyzer.hh
new file mode 100644
index 000000000..c9f894b1f
--- /dev/null
+++ b/bench/btl/generic_bench/timers/STL_perf_analyzer.hh
@@ -0,0 +1,82 @@
+//=====================================================
+// File : STL_perf_analyzer.hh
+// Author : L. Plagne <laurent.plagne@edf.fr)>
+// Copyright (C) EDF R&D, mar déc 3 18:59:35 CET 2002
+//=====================================================
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+//
+#ifndef _STL_PERF_ANALYSER_HH
+#define _STL_PERF_ANALYSER_HH
+
+#include "STL_timer.hh"
+#include "bench_parameter.hh"
+
+template<class ACTION>
+class STL_Perf_Analyzer{
+public:
+ STL_Perf_Analyzer(unsigned long long nb_sample=DEFAULT_NB_SAMPLE):_nb_sample(nb_sample),_chronos()
+ {
+ MESSAGE("STL_Perf_Analyzer Ctor");
+ };
+ STL_Perf_Analyzer( const STL_Perf_Analyzer & ){
+ INFOS("Copy Ctor not implemented");
+ exit(0);
+ };
+ ~STL_Perf_Analyzer( void ){
+ MESSAGE("STL_Perf_Analyzer Dtor");
+ };
+
+
+ inline double eval_mflops(int size)
+ {
+
+ ACTION action(size);
+
+ _chronos.start_baseline(_nb_sample);
+
+ do {
+
+ action.initialize();
+ } while (_chronos.check());
+
+ double baseline_time=_chronos.get_time();
+
+ _chronos.start(_nb_sample);
+ do {
+ action.initialize();
+ action.calculate();
+ } while (_chronos.check());
+
+ double calculate_time=_chronos.get_time();
+
+ double corrected_time=calculate_time-baseline_time;
+
+ // cout << size <<" "<<baseline_time<<" "<<calculate_time<<" "<<corrected_time<<" "<<action.nb_op_base() << endl;
+
+ return action.nb_op_base()/(corrected_time*1000000.0);
+ //return action.nb_op_base()/(calculate_time*1000000.0);
+
+ }
+private:
+
+ STL_Timer _chronos;
+ unsigned long long _nb_sample;
+
+
+};
+
+
+
+#endif
diff --git a/bench/btl/generic_bench/timers/STL_timer.hh b/bench/btl/generic_bench/timers/STL_timer.hh
new file mode 100644
index 000000000..19c54e9c1
--- /dev/null
+++ b/bench/btl/generic_bench/timers/STL_timer.hh
@@ -0,0 +1,78 @@
+//=====================================================
+// File : STL_Timer.hh
+// Author : L. Plagne <laurent.plagne@edf.fr)>
+// Copyright (C) EDF R&D, mar déc 3 18:59:35 CET 2002
+//=====================================================
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+//
+// STL Timer Class. Adapted (L.P.) from the timer class by Musser et Al
+// described int the Book : STL Tutorial and reference guide.
+// Define a timer class for analyzing algorithm performance.
+#include <iostream>
+#include <iomanip>
+#include <vector>
+#include <map>
+#include <algorithm>
+using namespace std;
+
+class STL_Timer {
+public:
+ STL_Timer(){ baseline = false; }; // Default constructor
+ // Start a series of r trials:
+ void start(unsigned int r){
+ reps = r;
+ count = 0;
+ iterations.clear();
+ iterations.reserve(reps);
+ initial = time(0);
+ };
+ // Start a series of r trials to determine baseline time:
+ void start_baseline(unsigned int r)
+ {
+ baseline = true;
+ start(r);
+ }
+ // Returns true if the trials have been completed, else false
+ bool check()
+ {
+ ++count;
+ final = time(0);
+ if (initial < final) {
+ iterations.push_back(count);
+ initial = final;
+ count = 0;
+ }
+ return (iterations.size() < reps);
+ };
+ // Returns the results for external use
+ double get_time( void )
+ {
+ sort(iterations.begin(), iterations.end());
+ return 1.0/iterations[reps/2];
+ };
+private:
+ unsigned int reps; // Number of trials
+ // For storing loop iterations of a trial
+ vector<long> iterations;
+ // For saving initial and final times of a trial
+ time_t initial, final;
+ // For counting loop iterations of a trial
+ unsigned long count;
+ // true if this is a baseline computation, false otherwise
+ bool baseline;
+ // For recording the baseline time
+ double baseline_time;
+};
+
diff --git a/bench/btl/generic_bench/timers/mixed_perf_analyzer.hh b/bench/btl/generic_bench/timers/mixed_perf_analyzer.hh
new file mode 100644
index 000000000..e190236e0
--- /dev/null
+++ b/bench/btl/generic_bench/timers/mixed_perf_analyzer.hh
@@ -0,0 +1,73 @@
+//=====================================================
+// File : mixed_perf_analyzer.hh
+// Author : L. Plagne <laurent.plagne@edf.fr)>
+// Copyright (C) EDF R&D, mar déc 3 18:59:36 CET 2002
+//=====================================================
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+//
+#ifndef _MIXED_PERF_ANALYSER_HH
+#define _MIXED_PERF_ANALYSER_HH
+
+#include "x86_perf_analyzer.hh"
+#include "portable_perf_analyzer.hh"
+
+// choose portable perf analyzer for long calculations and x86 analyser for short ones
+
+
+template<class Action>
+class Mixed_Perf_Analyzer{
+
+public:
+ Mixed_Perf_Analyzer( void ):_x86pa(),_ppa(),_use_ppa(true)
+ {
+ MESSAGE("Mixed_Perf_Analyzer Ctor");
+ };
+ Mixed_Perf_Analyzer( const Mixed_Perf_Analyzer & ){
+ INFOS("Copy Ctor not implemented");
+ exit(0);
+ };
+ ~Mixed_Perf_Analyzer( void ){
+ MESSAGE("Mixed_Perf_Analyzer Dtor");
+ };
+
+
+ inline double eval_mflops(int size)
+ {
+
+ double result=0.0;
+ if (_use_ppa){
+ result=_ppa.eval_mflops(size);
+ if (_ppa.get_nb_calc()>DEFAULT_NB_SAMPLE){_use_ppa=false;}
+ }
+ else{
+ result=_x86pa.eval_mflops(size);
+ }
+
+ return result;
+ }
+
+private:
+
+ Portable_Perf_Analyzer<Action> _ppa;
+ X86_Perf_Analyzer<Action> _x86pa;
+ bool _use_ppa;
+
+};
+
+#endif
+
+
+
+
diff --git a/bench/btl/generic_bench/timers/portable_perf_analyzer.hh b/bench/btl/generic_bench/timers/portable_perf_analyzer.hh
new file mode 100644
index 000000000..fc0f3168d
--- /dev/null
+++ b/bench/btl/generic_bench/timers/portable_perf_analyzer.hh
@@ -0,0 +1,103 @@
+//=====================================================
+// File : portable_perf_analyzer.hh
+// Author : L. Plagne <laurent.plagne@edf.fr)>
+// Copyright (C) EDF R&D, mar d�c 3 18:59:35 CET 2002
+// Copyright (C) 2008 Gael Guennebaud <gael.guennebaud@inria.fr>
+//=====================================================
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+//
+#ifndef _PORTABLE_PERF_ANALYZER_HH
+#define _PORTABLE_PERF_ANALYZER_HH
+
+#include "utilities.h"
+#include "timers/portable_timer.hh"
+
+template <class Action>
+class Portable_Perf_Analyzer{
+public:
+ Portable_Perf_Analyzer( ):_nb_calc(0), m_time_action(0), _chronos(){
+ MESSAGE("Portable_Perf_Analyzer Ctor");
+ };
+ Portable_Perf_Analyzer( const Portable_Perf_Analyzer & ){
+ INFOS("Copy Ctor not implemented");
+ exit(0);
+ };
+ ~Portable_Perf_Analyzer(){
+ MESSAGE("Portable_Perf_Analyzer Dtor");
+ };
+
+ BTL_DONT_INLINE double eval_mflops(int size)
+ {
+ Action action(size);
+
+// action.initialize();
+// time_action = time_calculate(action);
+ while (m_time_action < MIN_TIME)
+ {
+ if(_nb_calc==0) _nb_calc = 1;
+ else _nb_calc *= 2;
+ action.initialize();
+ m_time_action = time_calculate(action);
+ }
+
+ // optimize
+ for (int i=1; i<BtlConfig::Instance.tries; ++i)
+ {
+ Action _action(size);
+ std::cout << " " << _action.nb_op_base()*_nb_calc/(m_time_action*1e6) << " ";
+ _action.initialize();
+ m_time_action = std::min(m_time_action, time_calculate(_action));
+ }
+
+ double time_action = m_time_action / (double(_nb_calc));
+
+ // check
+ if (BtlConfig::Instance.checkResults && size<128)
+ {
+ action.initialize();
+ action.calculate();
+ action.check_result();
+ }
+ return action.nb_op_base()/(time_action*1e6);
+ }
+
+ BTL_DONT_INLINE double time_calculate(Action & action)
+ {
+ // time measurement
+ action.calculate();
+ _chronos.start();
+ for (int ii=0;ii<_nb_calc;ii++)
+ {
+ action.calculate();
+ }
+ _chronos.stop();
+ return _chronos.user_time();
+ }
+
+ unsigned long long get_nb_calc()
+ {
+ return _nb_calc;
+ }
+
+
+private:
+ unsigned long long _nb_calc;
+ double m_time_action;
+ Portable_Timer _chronos;
+
+};
+
+#endif //_PORTABLE_PERF_ANALYZER_HH
+
diff --git a/bench/btl/generic_bench/timers/portable_perf_analyzer_old.hh b/bench/btl/generic_bench/timers/portable_perf_analyzer_old.hh
new file mode 100644
index 000000000..fce378168
--- /dev/null
+++ b/bench/btl/generic_bench/timers/portable_perf_analyzer_old.hh
@@ -0,0 +1,134 @@
+//=====================================================
+// File : portable_perf_analyzer.hh
+// Author : L. Plagne <laurent.plagne@edf.fr)>
+// Copyright (C) EDF R&D, mar d�c 3 18:59:35 CET 2002
+//=====================================================
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+//
+#ifndef _PORTABLE_PERF_ANALYZER_HH
+#define _PORTABLE_PERF_ANALYZER_HH
+
+#include "utilities.h"
+#include "timers/portable_timer.hh"
+
+template <class Action>
+class Portable_Perf_Analyzer{
+public:
+ Portable_Perf_Analyzer( void ):_nb_calc(1),_nb_init(1),_chronos(){
+ MESSAGE("Portable_Perf_Analyzer Ctor");
+ };
+ Portable_Perf_Analyzer( const Portable_Perf_Analyzer & ){
+ INFOS("Copy Ctor not implemented");
+ exit(0);
+ };
+ ~Portable_Perf_Analyzer( void ){
+ MESSAGE("Portable_Perf_Analyzer Dtor");
+ };
+
+
+
+ inline double eval_mflops(int size)
+ {
+
+ Action action(size);
+
+// double time_baseline = time_init(action);
+// while (time_baseline < MIN_TIME_INIT)
+// {
+// _nb_init *= 2;
+// time_baseline = time_init(action);
+// }
+//
+// // optimize
+// for (int i=1; i<NB_TRIES; ++i)
+// time_baseline = std::min(time_baseline, time_init(action));
+//
+// time_baseline = time_baseline/(double(_nb_init));
+
+ double time_action = time_calculate(action);
+ while (time_action < MIN_TIME)
+ {
+ _nb_calc *= 2;
+ time_action = time_calculate(action);
+ }
+
+ // optimize
+ for (int i=1; i<NB_TRIES; ++i)
+ time_action = std::min(time_action, time_calculate(action));
+
+// INFOS("size="<<size);
+// INFOS("_nb_init="<<_nb_init);
+// INFOS("_nb_calc="<<_nb_calc);
+
+ time_action = time_action / (double(_nb_calc));
+
+ action.check_result();
+
+
+ double time_baseline = time_init(action);
+ for (int i=1; i<NB_TRIES; ++i)
+ time_baseline = std::min(time_baseline, time_init(action));
+ time_baseline = time_baseline/(double(_nb_init));
+
+
+
+// INFOS("time_baseline="<<time_baseline);
+// INFOS("time_action="<<time_action);
+
+ time_action = time_action - time_baseline;
+
+// INFOS("time_corrected="<<time_action);
+
+ return action.nb_op_base()/(time_action*1000000.0);
+ }
+
+ inline double time_init(Action & action)
+ {
+ // time measurement
+ _chronos.start();
+ for (int ii=0; ii<_nb_init; ii++)
+ action.initialize();
+ _chronos.stop();
+ return _chronos.user_time();
+ }
+
+
+ inline double time_calculate(Action & action)
+ {
+ // time measurement
+ _chronos.start();
+ for (int ii=0;ii<_nb_calc;ii++)
+ {
+ action.initialize();
+ action.calculate();
+ }
+ _chronos.stop();
+ return _chronos.user_time();
+ }
+
+ unsigned long long get_nb_calc( void )
+ {
+ return _nb_calc;
+ }
+
+
+private:
+ unsigned long long _nb_calc;
+ unsigned long long _nb_init;
+ Portable_Timer _chronos;
+
+};
+
+#endif //_PORTABLE_PERF_ANALYZER_HH
diff --git a/bench/btl/generic_bench/timers/portable_timer.hh b/bench/btl/generic_bench/timers/portable_timer.hh
new file mode 100755
index 000000000..e6ad309fe
--- /dev/null
+++ b/bench/btl/generic_bench/timers/portable_timer.hh
@@ -0,0 +1,145 @@
+//=====================================================
+// File : portable_timer.hh
+// Author : L. Plagne <laurent.plagne@edf.fr)> from boost lib
+// Copyright (C) EDF R&D, lun sep 30 14:23:17 CEST 2002
+//=====================================================
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+//
+// simple_time extracted from the boost library
+//
+#ifndef _PORTABLE_TIMER_HH
+#define _PORTABLE_TIMER_HH
+
+#include <ctime>
+#include <cstdlib>
+
+#include <time.h>
+
+
+#define USEC_IN_SEC 1000000
+
+
+// timer -------------------------------------------------------------------//
+
+// A timer object measures CPU time.
+#ifdef _MSC_VER
+
+#define NOMINMAX
+#include <windows.h>
+
+/*#ifndef hr_timer
+#include "hr_time.h"
+#define hr_timer
+#endif*/
+
+ class Portable_Timer
+ {
+ public:
+
+ typedef struct {
+ LARGE_INTEGER start;
+ LARGE_INTEGER stop;
+ } stopWatch;
+
+
+ Portable_Timer()
+ {
+ startVal.QuadPart = 0;
+ stopVal.QuadPart = 0;
+ QueryPerformanceFrequency(&frequency);
+ }
+
+ void start() { QueryPerformanceCounter(&startVal); }
+
+ void stop() { QueryPerformanceCounter(&stopVal); }
+
+ double elapsed() {
+ LARGE_INTEGER time;
+ time.QuadPart = stopVal.QuadPart - startVal.QuadPart;
+ return LIToSecs(time);
+ }
+
+ double user_time() { return elapsed(); }
+
+
+ private:
+
+ double LIToSecs(LARGE_INTEGER& L) {
+ return ((double)L.QuadPart /(double)frequency.QuadPart) ;
+ }
+
+ LARGE_INTEGER startVal;
+ LARGE_INTEGER stopVal;
+ LARGE_INTEGER frequency;
+
+
+ }; // Portable_Timer
+
+#else
+
+#include <sys/time.h>
+#include <sys/resource.h>
+#include <unistd.h>
+#include <sys/times.h>
+
+class Portable_Timer
+{
+ public:
+
+ Portable_Timer()
+ {
+ m_clkid = BtlConfig::Instance.realclock ? CLOCK_REALTIME : CLOCK_PROCESS_CPUTIME_ID;
+ }
+
+ Portable_Timer(int clkid) : m_clkid(clkid)
+ {}
+
+ void start()
+ {
+ timespec ts;
+ clock_gettime(m_clkid, &ts);
+ m_start_time = double(ts.tv_sec) + 1e-9 * double(ts.tv_nsec);
+
+ }
+
+ void stop()
+ {
+ timespec ts;
+ clock_gettime(m_clkid, &ts);
+ m_stop_time = double(ts.tv_sec) + 1e-9 * double(ts.tv_nsec);
+
+ }
+
+ double elapsed()
+ {
+ return user_time();
+ }
+
+ double user_time()
+ {
+ return m_stop_time - m_start_time;
+ }
+
+
+private:
+
+ int m_clkid;
+ double m_stop_time, m_start_time;
+
+}; // Portable_Timer
+
+#endif
+
+#endif // PORTABLE_TIMER_HPP
diff --git a/bench/btl/generic_bench/timers/x86_perf_analyzer.hh b/bench/btl/generic_bench/timers/x86_perf_analyzer.hh
new file mode 100644
index 000000000..37ea21dcc
--- /dev/null
+++ b/bench/btl/generic_bench/timers/x86_perf_analyzer.hh
@@ -0,0 +1,108 @@
+//=====================================================
+// File : x86_perf_analyzer.hh
+// Author : L. Plagne <laurent.plagne@edf.fr)>
+// Copyright (C) EDF R&D, mar d�c 3 18:59:35 CET 2002
+//=====================================================
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+//
+#ifndef _X86_PERF_ANALYSER_HH
+#define _X86_PERF_ANALYSER_HH
+
+#include "x86_timer.hh"
+#include "bench_parameter.hh"
+
+template<class ACTION>
+class X86_Perf_Analyzer{
+public:
+ X86_Perf_Analyzer( unsigned long long nb_sample=DEFAULT_NB_SAMPLE):_nb_sample(nb_sample),_chronos()
+ {
+ MESSAGE("X86_Perf_Analyzer Ctor");
+ _chronos.find_frequency();
+ };
+ X86_Perf_Analyzer( const X86_Perf_Analyzer & ){
+ INFOS("Copy Ctor not implemented");
+ exit(0);
+ };
+ ~X86_Perf_Analyzer( void ){
+ MESSAGE("X86_Perf_Analyzer Dtor");
+ };
+
+
+ inline double eval_mflops(int size)
+ {
+
+ ACTION action(size);
+
+ int nb_loop=5;
+ double calculate_time=0.0;
+ double baseline_time=0.0;
+
+ for (int j=0 ; j < nb_loop ; j++){
+
+ _chronos.clear();
+
+ for(int i=0 ; i < _nb_sample ; i++)
+ {
+ _chronos.start();
+ action.initialize();
+ action.calculate();
+ _chronos.stop();
+ _chronos.add_get_click();
+ }
+
+ calculate_time += double(_chronos.get_shortest_clicks())/_chronos.frequency();
+
+ if (j==0) action.check_result();
+
+ _chronos.clear();
+
+ for(int i=0 ; i < _nb_sample ; i++)
+ {
+ _chronos.start();
+ action.initialize();
+ _chronos.stop();
+ _chronos.add_get_click();
+
+ }
+
+ baseline_time+=double(_chronos.get_shortest_clicks())/_chronos.frequency();
+
+ }
+
+ double corrected_time = (calculate_time-baseline_time)/double(nb_loop);
+
+
+// INFOS("_nb_sample="<<_nb_sample);
+// INFOS("baseline_time="<<baseline_time);
+// INFOS("calculate_time="<<calculate_time);
+// INFOS("corrected_time="<<corrected_time);
+
+// cout << size <<" "<<baseline_time<<" "<<calculate_time<<" "<<corrected_time<<" "<<action.nb_op_base() << endl;
+
+ return action.nb_op_base()/(corrected_time*1000000.0);
+ //return action.nb_op_base()/(calculate_time*1000000.0);
+ }
+
+private:
+
+ X86_Timer _chronos;
+ unsigned long long _nb_sample;
+
+
+};
+
+
+
+#endif
diff --git a/bench/btl/generic_bench/timers/x86_timer.hh b/bench/btl/generic_bench/timers/x86_timer.hh
new file mode 100644
index 000000000..cfb5ee833
--- /dev/null
+++ b/bench/btl/generic_bench/timers/x86_timer.hh
@@ -0,0 +1,246 @@
+//=====================================================
+// File : x86_timer.hh
+// Author : L. Plagne <laurent.plagne@edf.fr)>
+// Copyright (C) EDF R&D, mar d�c 3 18:59:35 CET 2002
+//=====================================================
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+//
+#ifndef _X86_TIMER_HH
+#define _X86_TIMER_HH
+
+#include <sys/time.h>
+#include <sys/resource.h>
+#include <unistd.h>
+#include <sys/times.h>
+//#include "system_time.h"
+#define u32 unsigned int
+#include <asm/msr.h>
+#include "utilities.h"
+#include <map>
+#include <fstream>
+#include <string>
+#include <iostream>
+
+// frequence de la becanne en Hz
+//#define FREQUENCY 648000000
+//#define FREQUENCY 1400000000
+#define FREQUENCY 1695000000
+
+using namespace std;
+
+
+class X86_Timer {
+
+public :
+
+ X86_Timer( void ):_frequency(FREQUENCY),_nb_sample(0)
+ {
+ MESSAGE("X86_Timer Default Ctor");
+ }
+
+ inline void start( void ){
+
+ rdtsc(_click_start.n32[0],_click_start.n32[1]);
+
+ }
+
+
+ inline void stop( void ){
+
+ rdtsc(_click_stop.n32[0],_click_stop.n32[1]);
+
+ }
+
+
+ inline double frequency( void ){
+ return _frequency;
+ }
+
+ double get_elapsed_time_in_second( void ){
+
+ return (_click_stop.n64-_click_start.n64)/double(FREQUENCY);
+
+
+ }
+
+ unsigned long long get_click( void ){
+
+ return (_click_stop.n64-_click_start.n64);
+
+ }
+
+ inline void find_frequency( void ){
+
+ time_t initial, final;
+ int dummy=2;
+
+ initial = time(0);
+ start();
+ do {
+ dummy+=2;
+ }
+ while(time(0)==initial);
+ // On est au debut d'un cycle d'une seconde !!!
+ initial = time(0);
+ start();
+ do {
+ dummy+=2;
+ }
+ while(time(0)==initial);
+ final=time(0);
+ stop();
+ // INFOS("fine grained time : "<< get_elapsed_time_in_second());
+ // INFOS("coarse grained time : "<< final-initial);
+ _frequency=_frequency*get_elapsed_time_in_second()/double(final-initial);
+ /// INFOS("CPU frequency : "<< _frequency);
+
+ }
+
+ void add_get_click( void ){
+
+ _nb_sample++;
+ _counted_clicks[get_click()]++;
+ fill_history_clicks();
+
+ }
+
+ void dump_statistics(string filemane){
+
+ ofstream outfile (filemane.c_str(),ios::out) ;
+
+ std::map<unsigned long long , unsigned long long>::iterator itr;
+ for(itr=_counted_clicks.begin() ; itr!=_counted_clicks.end() ; itr++)
+ {
+ outfile << (*itr).first << " " << (*itr).second << endl ;
+ }
+
+ outfile.close();
+
+ }
+
+ void dump_history(string filemane){
+
+ ofstream outfile (filemane.c_str(),ios::out) ;
+
+
+
+ for(int i=0 ; i<_history_mean_clicks.size() ; i++)
+ {
+ outfile << i << " "
+ << _history_mean_clicks[i] << " "
+ << _history_shortest_clicks[i] << " "
+ << _history_most_occured_clicks[i] << endl ;
+ }
+
+ outfile.close();
+
+ }
+
+
+
+ double get_mean_clicks( void ){
+
+ std::map<unsigned long long,unsigned long long>::iterator itr;
+
+ unsigned long long mean_clicks=0;
+
+ for(itr=_counted_clicks.begin() ; itr!=_counted_clicks.end() ; itr++)
+ {
+
+ mean_clicks+=(*itr).second*(*itr).first;
+ }
+
+ return mean_clicks/double(_nb_sample);
+
+ }
+
+ double get_shortest_clicks( void ){
+
+ return double((*_counted_clicks.begin()).first);
+
+ }
+
+ void fill_history_clicks( void ){
+
+ _history_mean_clicks.push_back(get_mean_clicks());
+ _history_shortest_clicks.push_back(get_shortest_clicks());
+ _history_most_occured_clicks.push_back(get_most_occured_clicks());
+
+ }
+
+
+ double get_most_occured_clicks( void ){
+
+ unsigned long long moc=0;
+ unsigned long long max_occurence=0;
+
+ std::map<unsigned long long,unsigned long long>::iterator itr;
+
+ for(itr=_counted_clicks.begin() ; itr!=_counted_clicks.end() ; itr++)
+ {
+
+ if (max_occurence<=(*itr).second){
+ max_occurence=(*itr).second;
+ moc=(*itr).first;
+ }
+ }
+
+ return double(moc);
+
+ }
+
+ void clear( void )
+ {
+ _counted_clicks.clear();
+
+ _history_mean_clicks.clear();
+ _history_shortest_clicks.clear();
+ _history_most_occured_clicks.clear();
+
+ _nb_sample=0;
+ }
+
+
+
+private :
+
+ union
+ {
+ unsigned long int n32[2] ;
+ unsigned long long n64 ;
+ } _click_start;
+
+ union
+ {
+ unsigned long int n32[2] ;
+ unsigned long long n64 ;
+ } _click_stop;
+
+ double _frequency ;
+
+ map<unsigned long long,unsigned long long> _counted_clicks;
+
+ vector<double> _history_mean_clicks;
+ vector<double> _history_shortest_clicks;
+ vector<double> _history_most_occured_clicks;
+
+ unsigned long long _nb_sample;
+
+
+
+};
+
+
+#endif
diff --git a/bench/btl/generic_bench/utils/size_lin_log.hh b/bench/btl/generic_bench/utils/size_lin_log.hh
new file mode 100644
index 000000000..bca3932ae
--- /dev/null
+++ b/bench/btl/generic_bench/utils/size_lin_log.hh
@@ -0,0 +1,70 @@
+//=====================================================
+// File : size_lin_log.hh
+// Author : L. Plagne <laurent.plagne@edf.fr)>
+// Copyright (C) EDF R&D, mar déc 3 18:59:37 CET 2002
+//=====================================================
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+//
+#ifndef SIZE_LIN_LOG
+#define SIZE_LIN_LOG
+
+#include "size_log.hh"
+
+template<class Vector>
+void size_lin_log(const int nb_point, const int size_min, const int size_max, Vector & X)
+{
+ int ten=10;
+ int nine=9;
+
+ X.resize(nb_point);
+
+ if (nb_point>ten){
+
+ for (int i=0;i<nine;i++){
+
+ X[i]=i+1;
+
+ }
+
+ Vector log_size;
+ size_log(nb_point-nine,ten,size_max,log_size);
+
+ for (int i=0;i<nb_point-nine;i++){
+
+ X[i+nine]=log_size[i];
+
+ }
+ }
+ else{
+
+ for (int i=0;i<nb_point;i++){
+
+ X[i]=i+1;
+
+ }
+ }
+
+ // for (int i=0;i<nb_point;i++){
+
+// INFOS("computed sizes : X["<<i<<"]="<<X[i]);
+
+// }
+
+}
+
+#endif
+
+
+
diff --git a/bench/btl/generic_bench/utils/size_log.hh b/bench/btl/generic_bench/utils/size_log.hh
new file mode 100644
index 000000000..13a3da7a8
--- /dev/null
+++ b/bench/btl/generic_bench/utils/size_log.hh
@@ -0,0 +1,54 @@
+//=====================================================
+// File : size_log.hh
+// Author : L. Plagne <laurent.plagne@edf.fr)>
+// Copyright (C) EDF R&D, lun sep 30 14:23:17 CEST 2002
+//=====================================================
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+//
+#ifndef SIZE_LOG
+#define SIZE_LOG
+
+#include "math.h"
+// The Vector class must satisfy the following part of STL vector concept :
+// resize() method
+// [] operator for seting element
+// the vector element are int compatible.
+template<class Vector>
+void size_log(const int nb_point, const int size_min, const int size_max, Vector & X)
+{
+ X.resize(nb_point);
+
+ float ls_min=log(float(size_min));
+ float ls_max=log(float(size_max));
+
+ float ls=0.0;
+
+ float delta_ls=(ls_max-ls_min)/(float(nb_point-1));
+
+ int size=0;
+
+ for (int i=0;i<nb_point;i++){
+
+ ls = ls_min + float(i)*delta_ls ;
+
+ size=int(exp(ls));
+
+ X[i]=size;
+ }
+
+}
+
+
+#endif
diff --git a/bench/btl/generic_bench/utils/utilities.h b/bench/btl/generic_bench/utils/utilities.h
new file mode 100644
index 000000000..d2330d06b
--- /dev/null
+++ b/bench/btl/generic_bench/utils/utilities.h
@@ -0,0 +1,90 @@
+//=============================================================================
+// File : utilities.h
+// Created : mar jun 19 13:18:14 CEST 2001
+// Author : Antoine YESSAYAN, Paul RASCLE, EDF
+// Project : SALOME
+// Copyright : EDF 2001
+// $Header$
+//=============================================================================
+
+/* --- Definition macros file to print information if _DEBUG_ is defined --- */
+
+# ifndef UTILITIES_H
+# define UTILITIES_H
+
+# include <stdlib.h>
+//# include <iostream> ok for gcc3.01
+# include <iostream>
+
+/* --- INFOS is always defined (without _DEBUG_): to be used for warnings, with release version --- */
+
+# define HEREWEARE cout<<flush ; cerr << __FILE__ << " [" << __LINE__ << "] : " << flush ;
+# define INFOS(chain) {HEREWEARE ; cerr << chain << endl ;}
+# define PYSCRIPT(chain) {cout<<flush ; cerr << "---PYSCRIPT--- " << chain << endl ;}
+
+/* --- To print date and time of compilation of current source on stdout --- */
+
+# if defined ( __GNUC__ )
+# define COMPILER "g++" ;
+# elif defined ( __sun )
+# define COMPILER "CC" ;
+# elif defined ( __KCC )
+# define COMPILER "KCC" ;
+# elif defined ( __PGI )
+# define COMPILER "pgCC" ;
+# else
+# define COMPILER "undefined" ;
+# endif
+
+# ifdef INFOS_COMPILATION
+# error INFOS_COMPILATION already defined
+# endif
+# define INFOS_COMPILATION {\
+ cerr << flush;\
+ cout << __FILE__ ;\
+ cout << " [" << __LINE__ << "] : " ;\
+ cout << "COMPILED with " << COMPILER ;\
+ cout << ", " << __DATE__ ; \
+ cout << " at " << __TIME__ << endl ;\
+ cout << "\n\n" ;\
+ cout << flush ;\
+ }
+
+# ifdef _DEBUG_
+
+/* --- the following MACROS are useful at debug time --- */
+
+# define HERE cout<<flush ; cerr << "- Trace " << __FILE__ << " [" << __LINE__ << "] : " << flush ;
+# define SCRUTE(var) HERE ; cerr << #var << "=" << var << endl ;
+# define MESSAGE(chain) {HERE ; cerr << chain << endl ;}
+# define INTERRUPTION(code) HERE ; cerr << "INTERRUPTION return code= " << code << endl ; exit(code) ;
+
+# ifndef ASSERT
+# define ASSERT(condition) if (!(condition)){ HERE ; cerr << "CONDITION " << #condition << " NOT VERIFIED"<< endl ; INTERRUPTION(1) ;}
+# endif /* ASSERT */
+
+#define REPERE cout<<flush ; cerr << " --------------" << endl << flush ;
+#define BEGIN_OF(chain) {REPERE ; HERE ; cerr << "Begin of: " << chain << endl ; REPERE ; }
+#define END_OF(chain) {REPERE ; HERE ; cerr << "Normal end of: " << chain << endl ; REPERE ; }
+
+
+
+# else /* ifdef _DEBUG_*/
+
+# define HERE
+# define SCRUTE(var)
+# define MESSAGE(chain)
+# define INTERRUPTION(code)
+
+# ifndef ASSERT
+# define ASSERT(condition)
+# endif /* ASSERT */
+
+#define REPERE
+#define BEGIN_OF(chain)
+#define END_OF(chain)
+
+
+# endif /* ifdef _DEBUG_*/
+
+# endif /* ifndef UTILITIES_H */
diff --git a/bench/btl/generic_bench/utils/xy_file.hh b/bench/btl/generic_bench/utils/xy_file.hh
new file mode 100644
index 000000000..4571bed8f
--- /dev/null
+++ b/bench/btl/generic_bench/utils/xy_file.hh
@@ -0,0 +1,75 @@
+//=====================================================
+// File : dump_file_x_y.hh
+// Author : L. Plagne <laurent.plagne@edf.fr)>
+// Copyright (C) EDF R&D, lun sep 30 14:23:20 CEST 2002
+//=====================================================
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+//
+#ifndef XY_FILE_HH
+#define XY_FILE_HH
+#include <fstream>
+#include <iostream>
+#include <string>
+#include <vector>
+using namespace std;
+
+bool read_xy_file(const std::string & filename, std::vector<int> & tab_sizes,
+ std::vector<double> & tab_mflops, bool quiet = false)
+{
+
+ std::ifstream input_file (filename.c_str(),std::ios::in);
+
+ if (!input_file){
+ if (!quiet) {
+ INFOS("!!! Error opening "<<filename);
+ }
+ return false;
+ }
+
+ int nb_point=0;
+ int size=0;
+ double mflops=0;
+
+ while (input_file >> size >> mflops ){
+ nb_point++;
+ tab_sizes.push_back(size);
+ tab_mflops.push_back(mflops);
+ }
+ SCRUTE(nb_point);
+
+ input_file.close();
+ return true;
+}
+
+// The Vector class must satisfy the following part of STL vector concept :
+// resize() method
+// [] operator for seting element
+// the vector element must have the << operator define
+
+using namespace std;
+
+template<class Vector_A, class Vector_B>
+void dump_xy_file(const Vector_A & X, const Vector_B & Y, const std::string & filename){
+
+ ofstream outfile (filename.c_str(),ios::out) ;
+ int size=X.size();
+
+ for (int i=0;i<size;i++)
+ outfile << X[i] << " " << Y[i] << endl;
+
+ outfile.close();
+}
+
+#endif
diff --git a/bench/btl/libs/BLAS/CMakeLists.txt b/bench/btl/libs/BLAS/CMakeLists.txt
new file mode 100644
index 000000000..de42fe047
--- /dev/null
+++ b/bench/btl/libs/BLAS/CMakeLists.txt
@@ -0,0 +1,60 @@
+
+find_package(ATLAS)
+if (ATLAS_FOUND)
+ btl_add_bench(btl_atlas main.cpp)
+ if(BUILD_btl_atlas)
+ target_link_libraries(btl_atlas ${ATLAS_LIBRARIES})
+ set_target_properties(btl_atlas PROPERTIES COMPILE_FLAGS "-DCBLASNAME=ATLAS -DHAS_LAPACK=1")
+ endif(BUILD_btl_atlas)
+endif (ATLAS_FOUND)
+
+find_package(MKL)
+if (MKL_FOUND)
+ btl_add_bench(btl_mkl main.cpp)
+ if(BUILD_btl_mkl)
+ target_link_libraries(btl_mkl ${MKL_LIBRARIES})
+ set_target_properties(btl_mkl PROPERTIES COMPILE_FLAGS "-DCBLASNAME=INTEL_MKL -DHAS_LAPACK=1")
+ endif(BUILD_btl_mkl)
+endif (MKL_FOUND)
+
+
+find_package(GOTO2)
+if (GOTO2_FOUND)
+ btl_add_bench(btl_goto2 main.cpp)
+ if(BUILD_btl_goto2)
+ target_link_libraries(btl_goto2 ${GOTO_LIBRARIES} )
+ set_target_properties(btl_goto2 PROPERTIES COMPILE_FLAGS "-DCBLASNAME=GOTO2")
+ endif(BUILD_btl_goto2)
+endif (GOTO2_FOUND)
+
+find_package(GOTO)
+if (GOTO_FOUND)
+ if(GOTO2_FOUND)
+ btl_add_bench(btl_goto main.cpp OFF)
+ else()
+ btl_add_bench(btl_goto main.cpp)
+ endif()
+ if(BUILD_btl_goto)
+ target_link_libraries(btl_goto ${GOTO_LIBRARIES} )
+ set_target_properties(btl_goto PROPERTIES COMPILE_FLAGS "-DCBLASNAME=GOTO")
+ endif(BUILD_btl_goto)
+endif (GOTO_FOUND)
+
+find_package(ACML)
+if (ACML_FOUND)
+ btl_add_bench(btl_acml main.cpp)
+ if(BUILD_btl_acml)
+ target_link_libraries(btl_acml ${ACML_LIBRARIES} )
+ set_target_properties(btl_acml PROPERTIES COMPILE_FLAGS "-DCBLASNAME=ACML -DHAS_LAPACK=1")
+ endif(BUILD_btl_acml)
+endif (ACML_FOUND)
+
+if(Eigen_SOURCE_DIR AND CMAKE_Fortran_COMPILER_WORKS)
+ # we are inside Eigen and blas/lapack interface is compilable
+ include_directories(${Eigen_SOURCE_DIR})
+ btl_add_bench(btl_eigenblas main.cpp)
+ if(BUILD_btl_eigenblas)
+ target_link_libraries(btl_eigenblas eigen_blas eigen_lapack )
+ set_target_properties(btl_eigenblas PROPERTIES COMPILE_FLAGS "-DCBLASNAME=EigenBLAS")
+ endif()
+endif()
diff --git a/bench/btl/libs/BLAS/blas.h b/bench/btl/libs/BLAS/blas.h
new file mode 100644
index 000000000..28f3a4e57
--- /dev/null
+++ b/bench/btl/libs/BLAS/blas.h
@@ -0,0 +1,675 @@
+#ifndef BLAS_H
+#define BLAS_H
+
+#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 *);
+
+#if defined(F_INTERFACE_GFORT) && !defined(__64BIT__)
+int BLASFUNC(cdotu) (int *, float * , int *, float *, int *);
+int BLASFUNC(cdotc) (int *, float *, int *, float *, int *);
+void BLASFUNC(zdotu) (double *, int *, double *, int *, double *, int *);
+void BLASFUNC(zdotc) (double *, int *, double *, int *, double *, int *);
+void BLASFUNC(xdotu) (double *, int *, double *, int *, double *, int *);
+void BLASFUNC(xdotc) (double *, int *, double *, int *, double *, int *);
+#elif defined(F_INTERFACE_F2C) || \
+ defined(F_INTERFACE_PGI) || \
+ defined(F_INTERFACE_GFORT) || \
+ (defined(F_INTERFACE_PATHSCALE) && defined(__64BIT__))
+void BLASFUNC(cdotu) (float *, int *, float * , int *, float *, int *);
+void BLASFUNC(cdotc) (float *, int *, float *, int *, float *, int *);
+void BLASFUNC(zdotu) (double *, int *, double *, int *, double *, int *);
+void BLASFUNC(zdotc) (double *, int *, double *, int *, double *, int *);
+void BLASFUNC(xdotu) (double *, int *, double *, int *, double *, int *);
+void BLASFUNC(xdotc) (double *, int *, double *, int *, double *, int *);
+#else
+std::complex<float> BLASFUNC(cdotu) (int *, float *, int *, float *, int *);
+std::complex<float> BLASFUNC(cdotc) (int *, float *, int *, float *, int *);
+std::complex<double> BLASFUNC(zdotu) (int *, double *, int *, double *, int *);
+std::complex<double> BLASFUNC(zdotc) (int *, double *, int *, double *, int *);
+double BLASFUNC(xdotu) (int *, double *, int *, double *, int *);
+double BLASFUNC(xdotc) (int *, double *, int *, double *, int *);
+#endif
+
+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 *);
+
+#endif
diff --git a/bench/btl/libs/BLAS/blas_interface.hh b/bench/btl/libs/BLAS/blas_interface.hh
new file mode 100644
index 000000000..651054632
--- /dev/null
+++ b/bench/btl/libs/BLAS/blas_interface.hh
@@ -0,0 +1,83 @@
+//=====================================================
+// File : blas_interface.hh
+// Author : L. Plagne <laurent.plagne@edf.fr)>
+// Copyright (C) EDF R&D, lun sep 30 14:23:28 CEST 2002
+//=====================================================
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+//
+#ifndef blas_PRODUIT_MATRICE_VECTEUR_HH
+#define blas_PRODUIT_MATRICE_VECTEUR_HH
+
+#include <c_interface_base.h>
+#include <complex>
+extern "C"
+{
+#include "blas.h"
+
+ // Cholesky Factorization
+// void spotrf_(const char* uplo, const int* n, float *a, const int* ld, int* info);
+// void dpotrf_(const char* uplo, const int* n, double *a, const int* ld, int* info);
+ void ssytrd_(char *uplo, const int *n, float *a, const int *lda, float *d, float *e, float *tau, float *work, int *lwork, int *info );
+ void dsytrd_(char *uplo, const int *n, double *a, const int *lda, double *d, double *e, double *tau, double *work, int *lwork, int *info );
+ void sgehrd_( const int *n, int *ilo, int *ihi, float *a, const int *lda, float *tau, float *work, int *lwork, int *info );
+ void dgehrd_( const int *n, int *ilo, int *ihi, double *a, const int *lda, double *tau, double *work, int *lwork, int *info );
+
+ // LU row pivoting
+// void dgetrf_( int *m, int *n, double *a, int *lda, int *ipiv, int *info );
+// void sgetrf_(const int* m, const int* n, float *a, const int* ld, int* ipivot, int* info);
+ // LU full pivoting
+ void sgetc2_(const int* n, float *a, const int *lda, int *ipiv, int *jpiv, int*info );
+ void dgetc2_(const int* n, double *a, const int *lda, int *ipiv, int *jpiv, int*info );
+#ifdef HAS_LAPACK
+#endif
+}
+
+#define MAKE_STRING2(S) #S
+#define MAKE_STRING(S) MAKE_STRING2(S)
+
+#define CAT2(A,B) A##B
+#define CAT(A,B) CAT2(A,B)
+
+
+template<class real> class blas_interface;
+
+
+static char notrans = 'N';
+static char trans = 'T';
+static char nonunit = 'N';
+static char lower = 'L';
+static char right = 'R';
+static char left = 'L';
+static int intone = 1;
+
+
+
+#define SCALAR float
+#define SCALAR_PREFIX s
+#include "blas_interface_impl.hh"
+#undef SCALAR
+#undef SCALAR_PREFIX
+
+
+#define SCALAR double
+#define SCALAR_PREFIX d
+#include "blas_interface_impl.hh"
+#undef SCALAR
+#undef SCALAR_PREFIX
+
+#endif
+
+
+
diff --git a/bench/btl/libs/BLAS/blas_interface_impl.hh b/bench/btl/libs/BLAS/blas_interface_impl.hh
new file mode 100644
index 000000000..0e84df038
--- /dev/null
+++ b/bench/btl/libs/BLAS/blas_interface_impl.hh
@@ -0,0 +1,151 @@
+
+#define BLAS_FUNC(NAME) CAT(CAT(SCALAR_PREFIX,NAME),_)
+
+template<> class blas_interface<SCALAR> : public c_interface_base<SCALAR>
+{
+
+public :
+
+ static SCALAR fone;
+ static SCALAR fzero;
+
+ static inline std::string name()
+ {
+ return MAKE_STRING(CBLASNAME);
+ }
+
+ static inline void matrix_vector_product(gene_matrix & A, gene_vector & B, gene_vector & X, int N){
+ BLAS_FUNC(gemv)(&notrans,&N,&N,&fone,A,&N,B,&intone,&fzero,X,&intone);
+ }
+
+ static inline void symv(gene_matrix & A, gene_vector & B, gene_vector & X, int N){
+ BLAS_FUNC(symv)(&lower, &N,&fone,A,&N,B,&intone,&fzero,X,&intone);
+ }
+
+ static inline void syr2(gene_matrix & A, gene_vector & B, gene_vector & X, int N){
+ BLAS_FUNC(syr2)(&lower,&N,&fone,B,&intone,X,&intone,A,&N);
+ }
+
+ static inline void ger(gene_matrix & A, gene_vector & X, gene_vector & Y, int N){
+ BLAS_FUNC(ger)(&N,&N,&fone,X,&intone,Y,&intone,A,&N);
+ }
+
+ static inline void rot(gene_vector & A, gene_vector & B, SCALAR c, SCALAR s, int N){
+ BLAS_FUNC(rot)(&N,A,&intone,B,&intone,&c,&s);
+ }
+
+ static inline void atv_product(gene_matrix & A, gene_vector & B, gene_vector & X, int N){
+ BLAS_FUNC(gemv)(&trans,&N,&N,&fone,A,&N,B,&intone,&fzero,X,&intone);
+ }
+
+ static inline void matrix_matrix_product(gene_matrix & A, gene_matrix & B, gene_matrix & X, int N){
+ BLAS_FUNC(gemm)(&notrans,&notrans,&N,&N,&N,&fone,A,&N,B,&N,&fzero,X,&N);
+ }
+
+ static inline void transposed_matrix_matrix_product(gene_matrix & A, gene_matrix & B, gene_matrix & X, int N){
+ BLAS_FUNC(gemm)(&notrans,&notrans,&N,&N,&N,&fone,A,&N,B,&N,&fzero,X,&N);
+ }
+
+// static inline void ata_product(gene_matrix & A, gene_matrix & X, int N){
+// ssyrk_(&lower,&trans,&N,&N,&fone,A,&N,&fzero,X,&N);
+// }
+
+ static inline void aat_product(gene_matrix & A, gene_matrix & X, int N){
+ BLAS_FUNC(syrk)(&lower,&notrans,&N,&N,&fone,A,&N,&fzero,X,&N);
+ }
+
+ static inline void axpy(SCALAR coef, const gene_vector & X, gene_vector & Y, int N){
+ BLAS_FUNC(axpy)(&N,&coef,X,&intone,Y,&intone);
+ }
+
+ static inline void axpby(SCALAR a, const gene_vector & X, SCALAR b, gene_vector & Y, int N){
+ BLAS_FUNC(scal)(&N,&b,Y,&intone);
+ BLAS_FUNC(axpy)(&N,&a,X,&intone,Y,&intone);
+ }
+
+ static inline void cholesky(const gene_matrix & X, gene_matrix & C, int N){
+ int N2 = N*N;
+ BLAS_FUNC(copy)(&N2, X, &intone, C, &intone);
+ char uplo = 'L';
+ int info = 0;
+ BLAS_FUNC(potrf)(&uplo, &N, C, &N, &info);
+ if(info!=0) std::cerr << "potrf_ error " << info << "\n";
+ }
+
+ static inline void partial_lu_decomp(const gene_matrix & X, gene_matrix & C, int N){
+ int N2 = N*N;
+ BLAS_FUNC(copy)(&N2, X, &intone, C, &intone);
+ char uplo = 'L';
+ int info = 0;
+ int * ipiv = (int*)alloca(sizeof(int)*N);
+ BLAS_FUNC(getrf)(&N, &N, C, &N, ipiv, &info);
+ if(info!=0) std::cerr << "getrf_ error " << info << "\n";
+ }
+
+ static inline void trisolve_lower(const gene_matrix & L, const gene_vector& B, gene_vector & X, int N){
+ BLAS_FUNC(copy)(&N, B, &intone, X, &intone);
+ BLAS_FUNC(trsv)(&lower, &notrans, &nonunit, &N, L, &N, X, &intone);
+ }
+
+ static inline void trisolve_lower_matrix(const gene_matrix & L, const gene_matrix& B, gene_matrix & X, int N){
+ BLAS_FUNC(copy)(&N, B, &intone, X, &intone);
+ BLAS_FUNC(trsm)(&right, &lower, &notrans, &nonunit, &N, &N, &fone, L, &N, X, &N);
+ }
+
+ static inline void trmm(gene_matrix & A, gene_matrix & B, gene_matrix & X, int N){
+ BLAS_FUNC(trmm)(&left, &lower, &notrans,&nonunit, &N,&N,&fone,A,&N,B,&N);
+ }
+
+ #ifdef HAS_LAPACK
+
+ static inline void lu_decomp(const gene_matrix & X, gene_matrix & C, int N){
+ int N2 = N*N;
+ BLAS_FUNC(copy)(&N2, X, &intone, C, &intone);
+ char uplo = 'L';
+ int info = 0;
+ int * ipiv = (int*)alloca(sizeof(int)*N);
+ int * jpiv = (int*)alloca(sizeof(int)*N);
+ BLAS_FUNC(getc2)(&N, C, &N, ipiv, jpiv, &info);
+ }
+
+
+
+ static inline void hessenberg(const gene_matrix & X, gene_matrix & C, int N){
+ {
+ int N2 = N*N;
+ int inc = 1;
+ BLAS_FUNC(copy)(&N2, X, &inc, C, &inc);
+ }
+ int info = 0;
+ int ilo = 1;
+ int ihi = N;
+ int bsize = 64;
+ int worksize = N*bsize;
+ SCALAR* d = new SCALAR[N+worksize];
+ BLAS_FUNC(gehrd)(&N, &ilo, &ihi, C, &N, d, d+N, &worksize, &info);
+ delete[] d;
+ }
+
+ static inline void tridiagonalization(const gene_matrix & X, gene_matrix & C, int N){
+ {
+ int N2 = N*N;
+ int inc = 1;
+ BLAS_FUNC(copy)(&N2, X, &inc, C, &inc);
+ }
+ char uplo = 'U';
+ int info = 0;
+ int ilo = 1;
+ int ihi = N;
+ int bsize = 64;
+ int worksize = N*bsize;
+ SCALAR* d = new SCALAR[3*N+worksize];
+ BLAS_FUNC(sytrd)(&uplo, &N, C, &N, d, d+N, d+2*N, d+3*N, &worksize, &info);
+ delete[] d;
+ }
+
+ #endif // HAS_LAPACK
+
+};
+
+SCALAR blas_interface<SCALAR>::fone = SCALAR(1);
+SCALAR blas_interface<SCALAR>::fzero = SCALAR(0);
diff --git a/bench/btl/libs/BLAS/c_interface_base.h b/bench/btl/libs/BLAS/c_interface_base.h
new file mode 100644
index 000000000..515d8dcfc
--- /dev/null
+++ b/bench/btl/libs/BLAS/c_interface_base.h
@@ -0,0 +1,73 @@
+
+#ifndef BTL_C_INTERFACE_BASE_H
+#define BTL_C_INTERFACE_BASE_H
+
+#include "utilities.h"
+#include <vector>
+
+template<class real> class c_interface_base
+{
+
+public:
+
+ typedef real real_type;
+ typedef std::vector<real> stl_vector;
+ typedef std::vector<stl_vector > stl_matrix;
+
+ typedef real* gene_matrix;
+ typedef real* gene_vector;
+
+ static void free_matrix(gene_matrix & A, int N){
+ delete A;
+ }
+
+ static void free_vector(gene_vector & B){
+ delete B;
+ }
+
+ static inline void matrix_from_stl(gene_matrix & A, stl_matrix & A_stl){
+ int N = A_stl.size();
+ A = new real[N*N];
+ for (int j=0;j<N;j++)
+ for (int i=0;i<N;i++)
+ A[i+N*j] = A_stl[j][i];
+ }
+
+ static inline void vector_from_stl(gene_vector & B, stl_vector & B_stl){
+ int N = B_stl.size();
+ B = new real[N];
+ for (int i=0;i<N;i++)
+ B[i] = B_stl[i];
+ }
+
+ static inline void vector_to_stl(gene_vector & B, stl_vector & B_stl){
+ int N = B_stl.size();
+ for (int i=0;i<N;i++)
+ B_stl[i] = B[i];
+ }
+
+ static inline void matrix_to_stl(gene_matrix & A, stl_matrix & A_stl){
+ int N = A_stl.size();
+ for (int j=0;j<N;j++){
+ A_stl[j].resize(N);
+ for (int i=0;i<N;i++)
+ A_stl[j][i] = A[i+N*j];
+ }
+ }
+
+ static inline void copy_vector(const gene_vector & source, gene_vector & cible, int N){
+ for (int i=0;i<N;i++)
+ cible[i]=source[i];
+ }
+
+ static inline void copy_matrix(const gene_matrix & source, gene_matrix & cible, int N){
+ for (int j=0;j<N;j++){
+ for (int i=0;i<N;i++){
+ cible[i+N*j] = source[i+N*j];
+ }
+ }
+ }
+
+};
+
+#endif
diff --git a/bench/btl/libs/BLAS/main.cpp b/bench/btl/libs/BLAS/main.cpp
new file mode 100644
index 000000000..8347c9f0b
--- /dev/null
+++ b/bench/btl/libs/BLAS/main.cpp
@@ -0,0 +1,73 @@
+//=====================================================
+// File : main.cpp
+// Author : L. Plagne <laurent.plagne@edf.fr)>
+// Copyright (C) EDF R&D, lun sep 30 14:23:28 CEST 2002
+//=====================================================
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+//
+#include "utilities.h"
+#include "blas_interface.hh"
+#include "bench.hh"
+#include "basic_actions.hh"
+
+#include "action_cholesky.hh"
+#include "action_lu_decomp.hh"
+#include "action_partial_lu.hh"
+#include "action_trisolve_matrix.hh"
+
+#ifdef HAS_LAPACK
+#include "action_hessenberg.hh"
+#endif
+
+BTL_MAIN;
+
+int main()
+{
+
+ bench<Action_axpy<blas_interface<REAL_TYPE> > >(MIN_AXPY,MAX_AXPY,NB_POINT);
+ bench<Action_axpby<blas_interface<REAL_TYPE> > >(MIN_AXPY,MAX_AXPY,NB_POINT);
+
+ bench<Action_matrix_vector_product<blas_interface<REAL_TYPE> > >(MIN_MV,MAX_MV,NB_POINT);
+ bench<Action_atv_product<blas_interface<REAL_TYPE> > >(MIN_MV,MAX_MV,NB_POINT);
+ bench<Action_symv<blas_interface<REAL_TYPE> > >(MIN_MV,MAX_MV,NB_POINT);
+ bench<Action_syr2<blas_interface<REAL_TYPE> > >(MIN_MV,MAX_MV,NB_POINT);
+
+ bench<Action_ger<blas_interface<REAL_TYPE> > >(MIN_MV,MAX_MV,NB_POINT);
+ bench<Action_rot<blas_interface<REAL_TYPE> > >(MIN_AXPY,MAX_AXPY,NB_POINT);
+
+ bench<Action_matrix_matrix_product<blas_interface<REAL_TYPE> > >(MIN_MM,MAX_MM,NB_POINT);
+// bench<Action_ata_product<blas_interface<REAL_TYPE> > >(MIN_MM,MAX_MM,NB_POINT);
+ bench<Action_aat_product<blas_interface<REAL_TYPE> > >(MIN_MM,MAX_MM,NB_POINT);
+
+ bench<Action_trisolve<blas_interface<REAL_TYPE> > >(MIN_MM,MAX_MM,NB_POINT);
+ bench<Action_trisolve_matrix<blas_interface<REAL_TYPE> > >(MIN_MM,MAX_MM,NB_POINT);
+
+ bench<Action_trmm<blas_interface<REAL_TYPE> > >(MIN_MM,MAX_MM,NB_POINT);
+
+ bench<Action_cholesky<blas_interface<REAL_TYPE> > >(MIN_MM,MAX_MM,NB_POINT);
+ bench<Action_partial_lu<blas_interface<REAL_TYPE> > >(MIN_MM,MAX_MM,NB_POINT);
+
+ #ifdef HAS_LAPACK
+ bench<Action_lu_decomp<blas_interface<REAL_TYPE> > >(MIN_MM,MAX_MM,NB_POINT);
+ bench<Action_hessenberg<blas_interface<REAL_TYPE> > >(MIN_MM,MAX_MM,NB_POINT);
+ bench<Action_tridiagonalization<blas_interface<REAL_TYPE> > >(MIN_MM,MAX_MM,NB_POINT);
+ #endif
+
+ //bench<Action_lu_solve<blas_LU_solve_interface<REAL_TYPE> > >(MIN_LU,MAX_LU,NB_POINT);
+
+ return 0;
+}
+
+
diff --git a/bench/btl/libs/STL/CMakeLists.txt b/bench/btl/libs/STL/CMakeLists.txt
new file mode 100644
index 000000000..4cfc2dcf2
--- /dev/null
+++ b/bench/btl/libs/STL/CMakeLists.txt
@@ -0,0 +1,2 @@
+
+btl_add_bench(btl_STL main.cpp OFF)
diff --git a/bench/btl/libs/STL/STL_interface.hh b/bench/btl/libs/STL/STL_interface.hh
new file mode 100644
index 000000000..93e76bd55
--- /dev/null
+++ b/bench/btl/libs/STL/STL_interface.hh
@@ -0,0 +1,244 @@
+//=====================================================
+// File : STL_interface.hh
+// Author : L. Plagne <laurent.plagne@edf.fr)>
+// Copyright (C) EDF R&D, lun sep 30 14:23:24 CEST 2002
+//=====================================================
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+//
+#ifndef STL_INTERFACE_HH
+#define STL_INTERFACE_HH
+#include <string>
+#include <vector>
+#include "utilities.h"
+
+using namespace std;
+
+template<class real>
+class STL_interface{
+
+public :
+
+ typedef real real_type ;
+
+ typedef std::vector<real> stl_vector;
+ typedef std::vector<stl_vector > stl_matrix;
+
+ typedef stl_matrix gene_matrix;
+
+ typedef stl_vector gene_vector;
+
+ static inline std::string name( void )
+ {
+ return "STL";
+ }
+
+ static void free_matrix(gene_matrix & A, int N){}
+
+ static void free_vector(gene_vector & B){}
+
+ static inline void matrix_from_stl(gene_matrix & A, stl_matrix & A_stl){
+ A = A_stl;
+ }
+
+ static inline void vector_from_stl(gene_vector & B, stl_vector & B_stl){
+ B = B_stl;
+ }
+
+ static inline void vector_to_stl(gene_vector & B, stl_vector & B_stl){
+ B_stl = B ;
+ }
+
+
+ static inline void matrix_to_stl(gene_matrix & A, stl_matrix & A_stl){
+ A_stl = A ;
+ }
+
+ static inline void copy_vector(const gene_vector & source, gene_vector & cible, int N){
+ for (int i=0;i<N;i++){
+ cible[i]=source[i];
+ }
+ }
+
+
+ static inline void copy_matrix(const gene_matrix & source, gene_matrix & cible, int N){
+ for (int i=0;i<N;i++)
+ for (int j=0;j<N;j++)
+ cible[i][j]=source[i][j];
+ }
+
+// static inline void ata_product(const gene_matrix & A, gene_matrix & X, int N)
+// {
+// real somme;
+// for (int j=0;j<N;j++){
+// for (int i=0;i<N;i++){
+// somme=0.0;
+// for (int k=0;k<N;k++)
+// somme += A[i][k]*A[j][k];
+// X[j][i]=somme;
+// }
+// }
+// }
+
+ static inline void aat_product(const gene_matrix & A, gene_matrix & X, int N)
+ {
+ real somme;
+ for (int j=0;j<N;j++){
+ for (int i=0;i<N;i++){
+ somme=0.0;
+ if(i>=j)
+ {
+ for (int k=0;k<N;k++){
+ somme+=A[k][i]*A[k][j];
+ }
+ X[j][i]=somme;
+ }
+ }
+ }
+ }
+
+
+ static inline void matrix_matrix_product(const gene_matrix & A, const gene_matrix & B, gene_matrix & X, int N)
+ {
+ real somme;
+ for (int j=0;j<N;j++){
+ for (int i=0;i<N;i++){
+ somme=0.0;
+ for (int k=0;k<N;k++)
+ somme+=A[k][i]*B[j][k];
+ X[j][i]=somme;
+ }
+ }
+ }
+
+ static inline void matrix_vector_product(gene_matrix & A, gene_vector & B, gene_vector & X, int N)
+ {
+ real somme;
+ for (int i=0;i<N;i++){
+ somme=0.0;
+ for (int j=0;j<N;j++)
+ somme+=A[j][i]*B[j];
+ X[i]=somme;
+ }
+ }
+
+ static inline void symv(gene_matrix & A, gene_vector & B, gene_vector & X, int N)
+ {
+ for (int j=0; j<N; ++j)
+ X[j] = 0;
+ for (int j=0; j<N; ++j)
+ {
+ real t1 = B[j];
+ real t2 = 0;
+ X[j] += t1 * A[j][j];
+ for (int i=j+1; i<N; ++i) {
+ X[i] += t1 * A[j][i];
+ t2 += A[j][i] * B[i];
+ }
+ X[j] += t2;
+ }
+ }
+
+ static inline void syr2(gene_matrix & A, gene_vector & B, gene_vector & X, int N)
+ {
+ for (int j=0; j<N; ++j)
+ {
+ for (int i=j; i<N; ++i)
+ A[j][i] += B[i]*X[j] + B[j]*X[i];
+ }
+ }
+
+ static inline void ger(gene_matrix & A, gene_vector & X, gene_vector & Y, int N)
+ {
+ for (int j=0; j<N; ++j)
+ {
+ for (int i=j; i<N; ++i)
+ A[j][i] += X[i]*Y[j];
+ }
+ }
+
+ static inline void atv_product(gene_matrix & A, gene_vector & B, gene_vector & X, int N)
+ {
+ real somme;
+ for (int i=0;i<N;i++){
+ somme = 0.0;
+ for (int j=0;j<N;j++)
+ somme += A[i][j]*B[j];
+ X[i] = somme;
+ }
+ }
+
+ static inline void axpy(real coef, const gene_vector & X, gene_vector & Y, int N){
+ for (int i=0;i<N;i++)
+ Y[i]+=coef*X[i];
+ }
+
+ static inline void axpby(real a, const gene_vector & X, real b, gene_vector & Y, int N){
+ for (int i=0;i<N;i++)
+ Y[i] = a*X[i] + b*Y[i];
+ }
+
+ static inline void trisolve_lower(const gene_matrix & L, const gene_vector & B, gene_vector & X, int N){
+ copy_vector(B,X,N);
+ for(int i=0; i<N; ++i)
+ {
+ X[i] /= L[i][i];
+ real tmp = X[i];
+ for (int j=i+1; j<N; ++j)
+ X[j] -= tmp * L[i][j];
+ }
+ }
+
+ static inline real norm_diff(const stl_vector & A, const stl_vector & B)
+ {
+ int N=A.size();
+ real somme=0.0;
+ real somme2=0.0;
+
+ for (int i=0;i<N;i++){
+ real diff=A[i]-B[i];
+ somme+=diff*diff;
+ somme2+=A[i]*A[i];
+ }
+ return somme/somme2;
+ }
+
+ static inline real norm_diff(const stl_matrix & A, const stl_matrix & B)
+ {
+ int N=A[0].size();
+ real somme=0.0;
+ real somme2=0.0;
+
+ for (int i=0;i<N;i++){
+ for (int j=0;j<N;j++){
+ real diff=A[i][j] - B[i][j];
+ somme += diff*diff;
+ somme2 += A[i][j]*A[i][j];
+ }
+ }
+
+ return somme/somme2;
+ }
+
+ static inline void display_vector(const stl_vector & A)
+ {
+ int N=A.size();
+ for (int i=0;i<N;i++){
+ INFOS("A["<<i<<"]="<<A[i]<<endl);
+ }
+ }
+
+};
+
+#endif
diff --git a/bench/btl/libs/STL/main.cpp b/bench/btl/libs/STL/main.cpp
new file mode 100644
index 000000000..4e73328ef
--- /dev/null
+++ b/bench/btl/libs/STL/main.cpp
@@ -0,0 +1,42 @@
+//=====================================================
+// File : main.cpp
+// Author : L. Plagne <laurent.plagne@edf.fr)>
+// Copyright (C) EDF R&D, lun sep 30 14:23:23 CEST 2002
+//=====================================================
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+//
+#include "utilities.h"
+#include "STL_interface.hh"
+#include "bench.hh"
+#include "basic_actions.hh"
+
+BTL_MAIN;
+
+int main()
+{
+ bench<Action_axpy<STL_interface<REAL_TYPE> > >(MIN_AXPY,MAX_AXPY,NB_POINT);
+ bench<Action_axpby<STL_interface<REAL_TYPE> > >(MIN_AXPY,MAX_AXPY,NB_POINT);
+ bench<Action_matrix_vector_product<STL_interface<REAL_TYPE> > >(MIN_MV,MAX_MV,NB_POINT);
+ bench<Action_atv_product<STL_interface<REAL_TYPE> > >(MIN_MV,MAX_MV,NB_POINT);
+ bench<Action_symv<STL_interface<REAL_TYPE> > >(MIN_MV,MAX_MV,NB_POINT);
+ bench<Action_syr2<STL_interface<REAL_TYPE> > >(MIN_MV,MAX_MV,NB_POINT);
+ bench<Action_matrix_matrix_product<STL_interface<REAL_TYPE> > >(MIN_MM,MAX_MM,NB_POINT);
+ bench<Action_ata_product<STL_interface<REAL_TYPE> > >(MIN_MM,MAX_MM,NB_POINT);
+ bench<Action_aat_product<STL_interface<REAL_TYPE> > >(MIN_MM,MAX_MM,NB_POINT);
+
+ return 0;
+}
+
+
diff --git a/bench/btl/libs/blitz/CMakeLists.txt b/bench/btl/libs/blitz/CMakeLists.txt
new file mode 100644
index 000000000..880ab7338
--- /dev/null
+++ b/bench/btl/libs/blitz/CMakeLists.txt
@@ -0,0 +1,17 @@
+
+find_package(Blitz)
+
+if (BLITZ_FOUND)
+ include_directories(${BLITZ_INCLUDES})
+
+ btl_add_bench(btl_blitz btl_blitz.cpp)
+ if (BUILD_btl_blitz)
+ target_link_libraries(btl_blitz ${BLITZ_LIBRARIES})
+ endif (BUILD_btl_blitz)
+
+ btl_add_bench(btl_tiny_blitz btl_tiny_blitz.cpp OFF)
+ if (BUILD_btl_tiny_blitz)
+ target_link_libraries(btl_tiny_blitz ${BLITZ_LIBRARIES})
+ endif (BUILD_btl_tiny_blitz)
+
+endif (BLITZ_FOUND)
diff --git a/bench/btl/libs/blitz/blitz_LU_solve_interface.hh b/bench/btl/libs/blitz/blitz_LU_solve_interface.hh
new file mode 100644
index 000000000..dcb9f567f
--- /dev/null
+++ b/bench/btl/libs/blitz/blitz_LU_solve_interface.hh
@@ -0,0 +1,192 @@
+//=====================================================
+// File : blitz_LU_solve_interface.hh
+// Author : L. Plagne <laurent.plagne@edf.fr)>
+// Copyright (C) EDF R&D, lun sep 30 14:23:31 CEST 2002
+//=====================================================
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+//
+#ifndef BLITZ_LU_SOLVE_INTERFACE_HH
+#define BLITZ_LU_SOLVE_INTERFACE_HH
+
+#include "blitz/array.h"
+#include <vector>
+
+BZ_USING_NAMESPACE(blitz)
+
+template<class real>
+class blitz_LU_solve_interface : public blitz_interface<real>
+{
+
+public :
+
+ typedef typename blitz_interface<real>::gene_matrix gene_matrix;
+ typedef typename blitz_interface<real>::gene_vector gene_vector;
+
+ typedef blitz::Array<int,1> Pivot_Vector;
+
+ inline static void new_Pivot_Vector(Pivot_Vector & pivot,int N)
+ {
+
+ pivot.resize(N);
+
+ }
+
+ inline static void free_Pivot_Vector(Pivot_Vector & pivot)
+ {
+
+ return;
+
+ }
+
+
+ static inline real matrix_vector_product_sliced(const gene_matrix & A, gene_vector B, int row, int col_start, int col_end)
+ {
+
+ real somme=0.;
+
+ for (int j=col_start ; j<col_end+1 ; j++){
+
+ somme+=A(row,j)*B(j);
+
+ }
+
+ return somme;
+
+ }
+
+
+
+
+ static inline real matrix_matrix_product_sliced(gene_matrix & A, int row, int col_start, int col_end, gene_matrix & B, int row_shift, int col )
+ {
+
+ real somme=0.;
+
+ for (int j=col_start ; j<col_end+1 ; j++){
+
+ somme+=A(row,j)*B(j+row_shift,col);
+
+ }
+
+ return somme;
+
+ }
+
+ inline static void LU_factor(gene_matrix & LU, Pivot_Vector & pivot, int N)
+ {
+
+ ASSERT( LU.rows()==LU.cols() ) ;
+ int index_max = 0 ;
+ real big = 0. ;
+ real theSum = 0. ;
+ real dum = 0. ;
+ // Get the implicit scaling information :
+ gene_vector ImplicitScaling( N ) ;
+ for( int i=0; i<N; i++ ) {
+ big = 0. ;
+ for( int j=0; j<N; j++ ) {
+ if( abs( LU( i, j ) )>=big ) big = abs( LU( i, j ) ) ;
+ }
+ if( big==0. ) {
+ INFOS( "blitz_LU_factor::Singular matrix" ) ;
+ exit( 0 ) ;
+ }
+ ImplicitScaling( i ) = 1./big ;
+ }
+ // Loop over columns of Crout's method :
+ for( int j=0; j<N; j++ ) {
+ for( int i=0; i<j; i++ ) {
+ theSum = LU( i, j ) ;
+ theSum -= matrix_matrix_product_sliced(LU, i, 0, i-1, LU, 0, j) ;
+ // theSum -= sum( LU( i, Range( fromStart, i-1 ) )*LU( Range( fromStart, i-1 ), j ) ) ;
+ LU( i, j ) = theSum ;
+ }
+
+ // Search for the largest pivot element :
+ big = 0. ;
+ for( int i=j; i<N; i++ ) {
+ theSum = LU( i, j ) ;
+ theSum -= matrix_matrix_product_sliced(LU, i, 0, j-1, LU, 0, j) ;
+ // theSum -= sum( LU( i, Range( fromStart, j-1 ) )*LU( Range( fromStart, j-1 ), j ) ) ;
+ LU( i, j ) = theSum ;
+ if( (ImplicitScaling( i )*abs( theSum ))>=big ) {
+ dum = ImplicitScaling( i )*abs( theSum ) ;
+ big = dum ;
+ index_max = i ;
+ }
+ }
+ // Interchanging rows and the scale factor :
+ if( j!=index_max ) {
+ for( int k=0; k<N; k++ ) {
+ dum = LU( index_max, k ) ;
+ LU( index_max, k ) = LU( j, k ) ;
+ LU( j, k ) = dum ;
+ }
+ ImplicitScaling( index_max ) = ImplicitScaling( j ) ;
+ }
+ pivot( j ) = index_max ;
+ if ( LU( j, j )==0. ) LU( j, j ) = 1.e-20 ;
+ // Divide by the pivot element :
+ if( j<N ) {
+ dum = 1./LU( j, j ) ;
+ for( int i=j+1; i<N; i++ ) LU( i, j ) *= dum ;
+ }
+ }
+
+ }
+
+ inline static void LU_solve(const gene_matrix & LU, const Pivot_Vector pivot, gene_vector &B, gene_vector X, int N)
+ {
+
+ // Pour conserver le meme header, on travaille sur X, copie du second-membre B
+ X = B.copy() ;
+ ASSERT( LU.rows()==LU.cols() ) ;
+ firstIndex indI ;
+ // Forward substitution :
+ int ii = 0 ;
+ real theSum = 0. ;
+ for( int i=0; i<N; i++ ) {
+ int ip = pivot( i ) ;
+ theSum = X( ip ) ;
+ // theSum = B( ip ) ;
+ X( ip ) = X( i ) ;
+ // B( ip ) = B( i ) ;
+ if( ii ) {
+ theSum -= matrix_vector_product_sliced(LU, X, i, ii-1, i-1) ;
+ // theSum -= sum( LU( i, Range( ii-1, i-1 ) )*X( Range( ii-1, i-1 ) ) ) ;
+ // theSum -= sum( LU( i, Range( ii-1, i-1 ) )*B( Range( ii-1, i-1 ) ) ) ;
+ } else if( theSum ) {
+ ii = i+1 ;
+ }
+ X( i ) = theSum ;
+ // B( i ) = theSum ;
+ }
+ // Backsubstitution :
+ for( int i=N-1; i>=0; i-- ) {
+ theSum = X( i ) ;
+ // theSum = B( i ) ;
+ theSum -= matrix_vector_product_sliced(LU, X, i, i+1, N) ;
+ // theSum -= sum( LU( i, Range( i+1, toEnd ) )*X( Range( i+1, toEnd ) ) ) ;
+ // theSum -= sum( LU( i, Range( i+1, toEnd ) )*B( Range( i+1, toEnd ) ) ) ;
+ // Store a component of the solution vector :
+ X( i ) = theSum/LU( i, i ) ;
+ // B( i ) = theSum/LU( i, i ) ;
+ }
+
+ }
+
+};
+
+#endif
diff --git a/bench/btl/libs/blitz/blitz_interface.hh b/bench/btl/libs/blitz/blitz_interface.hh
new file mode 100644
index 000000000..a67c47c75
--- /dev/null
+++ b/bench/btl/libs/blitz/blitz_interface.hh
@@ -0,0 +1,147 @@
+//=====================================================
+// File : blitz_interface.hh
+// Author : L. Plagne <laurent.plagne@edf.fr)>
+// Copyright (C) EDF R&D, lun sep 30 14:23:30 CEST 2002
+// Copyright (C) 2008 Gael Guennebaud <gael.guennebaud@inria.fr>
+//=====================================================
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+//
+#ifndef BLITZ_INTERFACE_HH
+#define BLITZ_INTERFACE_HH
+
+#include <blitz/blitz.h>
+#include <blitz/array.h>
+#include <blitz/vector-et.h>
+#include <blitz/vecwhere.h>
+#include <blitz/matrix.h>
+#include <vector>
+
+BZ_USING_NAMESPACE(blitz)
+
+template<class real>
+class blitz_interface{
+
+public :
+
+ typedef real real_type ;
+
+ typedef std::vector<real> stl_vector;
+ typedef std::vector<stl_vector > stl_matrix;
+
+ typedef blitz::Array<real, 2> gene_matrix;
+ typedef blitz::Array<real, 1> gene_vector;
+// typedef blitz::Matrix<real, blitz::ColumnMajor> gene_matrix;
+// typedef blitz::Vector<real> gene_vector;
+
+ static inline std::string name() { return "blitz"; }
+
+ static void free_matrix(gene_matrix & A, int N){}
+
+ static void free_vector(gene_vector & B){}
+
+ static inline void matrix_from_stl(gene_matrix & A, stl_matrix & A_stl){
+ A.resize(A_stl[0].size(),A_stl.size());
+ for (int j=0; j<A_stl.size() ; j++){
+ for (int i=0; i<A_stl[j].size() ; i++){
+ A(i,j)=A_stl[j][i];
+ }
+ }
+ }
+
+ static inline void vector_from_stl(gene_vector & B, stl_vector & B_stl){
+ B.resize(B_stl.size());
+ for (int i=0; i<B_stl.size() ; i++){
+ B(i)=B_stl[i];
+ }
+ }
+
+ static inline void vector_to_stl(gene_vector & B, stl_vector & B_stl){
+ for (int i=0; i<B_stl.size() ; i++){
+ B_stl[i]=B(i);
+ }
+ }
+
+ static inline void matrix_to_stl(gene_matrix & A, stl_matrix & A_stl){
+ int N=A_stl.size();
+ for (int j=0;j<N;j++){
+ A_stl[j].resize(N);
+ for (int i=0;i<N;i++)
+ A_stl[j][i] = A(i,j);
+ }
+ }
+
+ static inline void matrix_matrix_product(const gene_matrix & A, const gene_matrix & B, gene_matrix & X, int N)
+ {
+ firstIndex i;
+ secondIndex j;
+ thirdIndex k;
+ X = sum(A(i,k) * B(k,j), k);
+ }
+
+ static inline void ata_product(const gene_matrix & A, gene_matrix & X, int N)
+ {
+ firstIndex i;
+ secondIndex j;
+ thirdIndex k;
+ X = sum(A(k,i) * A(k,j), k);
+ }
+
+ static inline void aat_product(const gene_matrix & A, gene_matrix & X, int N)
+ {
+ firstIndex i;
+ secondIndex j;
+ thirdIndex k;
+ X = sum(A(i,k) * A(j,k), k);
+ }
+
+ static inline void matrix_vector_product(gene_matrix & A, gene_vector & B, gene_vector & X, int N)
+ {
+ firstIndex i;
+ secondIndex j;
+ X = sum(A(i,j)*B(j),j);
+ }
+
+ static inline void atv_product(gene_matrix & A, gene_vector & B, gene_vector & X, int N)
+ {
+ firstIndex i;
+ secondIndex j;
+ X = sum(A(j,i) * B(j),j);
+ }
+
+ static inline void axpy(const real coef, const gene_vector & X, gene_vector & Y, int N)
+ {
+ firstIndex i;
+ Y = Y(i) + coef * X(i);
+ //Y += coef * X;
+ }
+
+ static inline void copy_matrix(const gene_matrix & source, gene_matrix & cible, int N){
+ cible = source;
+ //cible.template operator=<gene_matrix>(source);
+// for (int i=0;i<N;i++){
+// for (int j=0;j<N;j++){
+// cible(i,j)=source(i,j);
+// }
+// }
+ }
+
+ static inline void copy_vector(const gene_vector & source, gene_vector & cible, int N){
+ //cible.template operator=<gene_vector>(source);
+ cible = source;
+ }
+
+};
+
+#endif
diff --git a/bench/btl/libs/blitz/btl_blitz.cpp b/bench/btl/libs/blitz/btl_blitz.cpp
new file mode 100644
index 000000000..16d2b5951
--- /dev/null
+++ b/bench/btl/libs/blitz/btl_blitz.cpp
@@ -0,0 +1,51 @@
+//=====================================================
+// File : main.cpp
+// Author : L. Plagne <laurent.plagne@edf.fr)>
+// Copyright (C) EDF R&D, lun sep 30 14:23:30 CEST 2002
+//=====================================================
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+//
+#include "utilities.h"
+#include "blitz_interface.hh"
+#include "blitz_LU_solve_interface.hh"
+#include "bench.hh"
+#include "action_matrix_vector_product.hh"
+#include "action_matrix_matrix_product.hh"
+#include "action_axpy.hh"
+#include "action_lu_solve.hh"
+#include "action_ata_product.hh"
+#include "action_aat_product.hh"
+#include "action_atv_product.hh"
+
+BTL_MAIN;
+
+int main()
+{
+
+ bench<Action_matrix_vector_product<blitz_interface<REAL_TYPE> > >(MIN_MV,MAX_MV,NB_POINT);
+ bench<Action_atv_product<blitz_interface<REAL_TYPE> > >(MIN_MV,MAX_MV,NB_POINT);
+
+ bench<Action_matrix_matrix_product<blitz_interface<REAL_TYPE> > >(MIN_MM,MAX_MM,NB_POINT);
+ bench<Action_ata_product<blitz_interface<REAL_TYPE> > >(MIN_MM,MAX_MM,NB_POINT);
+ bench<Action_aat_product<blitz_interface<REAL_TYPE> > >(MIN_MM,MAX_MM,NB_POINT);
+
+ bench<Action_axpy<blitz_interface<REAL_TYPE> > >(MIN_AXPY,MAX_AXPY,NB_POINT);
+
+ //bench<Action_lu_solve<blitz_LU_solve_interface<REAL_TYPE> > >(MIN_LU,MAX_LU,NB_POINT);
+
+ return 0;
+}
+
+
diff --git a/bench/btl/libs/blitz/btl_tiny_blitz.cpp b/bench/btl/libs/blitz/btl_tiny_blitz.cpp
new file mode 100644
index 000000000..9fddde752
--- /dev/null
+++ b/bench/btl/libs/blitz/btl_tiny_blitz.cpp
@@ -0,0 +1,38 @@
+//=====================================================
+// File : main.cpp
+// Author : L. Plagne <laurent.plagne@edf.fr)>
+// Copyright (C) EDF R&D, lun sep 30 14:23:30 CEST 2002
+//=====================================================
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+//
+#include "utilities.h"
+#include "tiny_blitz_interface.hh"
+#include "static/bench_static.hh"
+#include "action_matrix_vector_product.hh"
+#include "action_matrix_matrix_product.hh"
+#include "action_axpy.hh"
+
+BTL_MAIN;
+
+int main()
+{
+ bench_static<Action_axpy,tiny_blitz_interface>();
+ bench_static<Action_matrix_matrix_product,tiny_blitz_interface>();
+ bench_static<Action_matrix_vector_product,tiny_blitz_interface>();
+
+ return 0;
+}
+
+
diff --git a/bench/btl/libs/blitz/tiny_blitz_interface.hh b/bench/btl/libs/blitz/tiny_blitz_interface.hh
new file mode 100644
index 000000000..6b26db72d
--- /dev/null
+++ b/bench/btl/libs/blitz/tiny_blitz_interface.hh
@@ -0,0 +1,106 @@
+//=====================================================
+// File : tiny_blitz_interface.hh
+// Author : L. Plagne <laurent.plagne@edf.fr)>
+// Copyright (C) EDF R&D, lun sep 30 14:23:30 CEST 2002
+//=====================================================
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+//
+#ifndef TINY_BLITZ_INTERFACE_HH
+#define TINY_BLITZ_INTERFACE_HH
+
+#include "blitz/array.h"
+#include "blitz/tiny.h"
+#include "blitz/tinymat.h"
+#include "blitz/tinyvec.h"
+#include <blitz/tinyvec-et.h>
+
+#include <vector>
+
+BZ_USING_NAMESPACE(blitz)
+
+template<class real, int SIZE>
+class tiny_blitz_interface
+{
+
+public :
+
+ typedef real real_type ;
+
+ typedef std::vector<real> stl_vector;
+ typedef std::vector<stl_vector > stl_matrix;
+
+ typedef TinyVector<real,SIZE> gene_vector;
+ typedef TinyMatrix<real,SIZE,SIZE> gene_matrix;
+
+ static inline std::string name() { return "tiny_blitz"; }
+
+ static void free_matrix(gene_matrix & A, int N){}
+
+ static void free_vector(gene_vector & B){}
+
+ static inline void matrix_from_stl(gene_matrix & A, stl_matrix & A_stl){
+ for (int j=0; j<A_stl.size() ; j++)
+ for (int i=0; i<A_stl[j].size() ; i++)
+ A(i,j)=A_stl[j][i];
+ }
+
+ static inline void vector_from_stl(gene_vector & B, stl_vector & B_stl){
+ for (int i=0; i<B_stl.size() ; i++)
+ B(i) = B_stl[i];
+ }
+
+ static inline void vector_to_stl(gene_vector & B, stl_vector & B_stl){
+ for (int i=0; i<B_stl.size() ; i++)
+ B_stl[i] = B(i);
+ }
+
+ static inline void matrix_to_stl(gene_matrix & A, stl_matrix & A_stl){
+ int N = A_stl.size();
+ for (int j=0;j<N;j++)
+ {
+ A_stl[j].resize(N);
+ for (int i=0;i<N;i++)
+ A_stl[j][i] = A(i,j);
+ }
+ }
+
+ static inline void copy_matrix(const gene_matrix & source, gene_matrix & cible, int N){
+ for (int j=0;j<N;j++)
+ for (int i=0;i<N;i++)
+ cible(i,j) = source(i,j);
+ }
+
+ static inline void copy_vector(const gene_vector & source, gene_vector & cible, int N){
+ for (int i=0;i<N;i++){
+ cible(i) = source(i);
+ }
+ }
+
+ static inline void matrix_matrix_product(const gene_matrix & A, const gene_matrix & B, gene_matrix & X, int N){
+ X = product(A,B);
+ }
+
+ static inline void matrix_vector_product(gene_matrix & A, gene_vector & B, gene_vector & X, int N){
+ X = product(A,B);
+ }
+
+ static inline void axpy(const real coef, const gene_vector & X, gene_vector & Y, int N){
+ Y += coef * X;
+ }
+
+};
+
+
+#endif
diff --git a/bench/btl/libs/eigen2/CMakeLists.txt b/bench/btl/libs/eigen2/CMakeLists.txt
new file mode 100644
index 000000000..a2e8fc6da
--- /dev/null
+++ b/bench/btl/libs/eigen2/CMakeLists.txt
@@ -0,0 +1,19 @@
+
+find_package(Eigen2)
+
+if(EIGEN2_FOUND)
+
+ include_directories(BEFORE ${EIGEN2_INCLUDE_DIR})
+ btl_add_bench(btl_eigen2_linear main_linear.cpp)
+ btl_add_bench(btl_eigen2_vecmat main_vecmat.cpp)
+ btl_add_bench(btl_eigen2_matmat main_matmat.cpp)
+ btl_add_bench(btl_eigen2_adv main_adv.cpp )
+
+ btl_add_target_property(btl_eigen2_linear COMPILE_FLAGS "-fno-exceptions -DBTL_PREFIX=eigen2")
+ btl_add_target_property(btl_eigen2_vecmat COMPILE_FLAGS "-fno-exceptions -DBTL_PREFIX=eigen2")
+ btl_add_target_property(btl_eigen2_matmat COMPILE_FLAGS "-fno-exceptions -DBTL_PREFIX=eigen2")
+ btl_add_target_property(btl_eigen2_adv COMPILE_FLAGS "-fno-exceptions -DBTL_PREFIX=eigen2")
+
+ btl_add_bench(btl_tiny_eigen2 btl_tiny_eigen2.cpp OFF)
+
+endif() # EIGEN2_FOUND
diff --git a/bench/btl/libs/eigen2/btl_tiny_eigen2.cpp b/bench/btl/libs/eigen2/btl_tiny_eigen2.cpp
new file mode 100644
index 000000000..d1515be84
--- /dev/null
+++ b/bench/btl/libs/eigen2/btl_tiny_eigen2.cpp
@@ -0,0 +1,46 @@
+//=====================================================
+// Copyright (C) 2008 Gael Guennebaud <gael.guennebaud@inria.fr>
+//=====================================================
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+//
+#include "utilities.h"
+#include "eigen3_interface.hh"
+#include "static/bench_static.hh"
+#include "action_matrix_vector_product.hh"
+#include "action_matrix_matrix_product.hh"
+#include "action_axpy.hh"
+#include "action_lu_solve.hh"
+#include "action_ata_product.hh"
+#include "action_aat_product.hh"
+#include "action_atv_product.hh"
+#include "action_cholesky.hh"
+#include "action_trisolve.hh"
+
+BTL_MAIN;
+
+int main()
+{
+
+ bench_static<Action_axpy,eigen2_interface>();
+ bench_static<Action_matrix_matrix_product,eigen2_interface>();
+ bench_static<Action_matrix_vector_product,eigen2_interface>();
+ bench_static<Action_atv_product,eigen2_interface>();
+ bench_static<Action_cholesky,eigen2_interface>();
+ bench_static<Action_trisolve,eigen2_interface>();
+
+ return 0;
+}
+
+
diff --git a/bench/btl/libs/eigen2/eigen2_interface.hh b/bench/btl/libs/eigen2/eigen2_interface.hh
new file mode 100644
index 000000000..47fe58135
--- /dev/null
+++ b/bench/btl/libs/eigen2/eigen2_interface.hh
@@ -0,0 +1,168 @@
+//=====================================================
+// Copyright (C) 2008 Gael Guennebaud <g.gael@free.fr>
+//=====================================================
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+//
+#ifndef EIGEN2_INTERFACE_HH
+#define EIGEN2_INTERFACE_HH
+// #include <cblas.h>
+#include <Eigen/Core>
+#include <Eigen/Cholesky>
+#include <Eigen/LU>
+#include <Eigen/QR>
+#include <vector>
+#include "btl.hh"
+
+using namespace Eigen;
+
+template<class real, int SIZE=Dynamic>
+class eigen2_interface
+{
+
+public :
+
+ enum {IsFixedSize = (SIZE!=Dynamic)};
+
+ typedef real real_type;
+
+ typedef std::vector<real> stl_vector;
+ typedef std::vector<stl_vector> stl_matrix;
+
+ typedef Eigen::Matrix<real,SIZE,SIZE> gene_matrix;
+ typedef Eigen::Matrix<real,SIZE,1> gene_vector;
+
+ static inline std::string name( void )
+ {
+ #if defined(EIGEN_VECTORIZE_SSE)
+ if (SIZE==Dynamic) return "eigen2"; else return "tiny_eigen2";
+ #elif defined(EIGEN_VECTORIZE_ALTIVEC)
+ if (SIZE==Dynamic) return "eigen2"; else return "tiny_eigen2";
+ #else
+ if (SIZE==Dynamic) return "eigen2_novec"; else return "tiny_eigen2_novec";
+ #endif
+ }
+
+ static void free_matrix(gene_matrix & A, int N) {}
+
+ static void free_vector(gene_vector & B) {}
+
+ static BTL_DONT_INLINE void matrix_from_stl(gene_matrix & A, stl_matrix & A_stl){
+ A.resize(A_stl[0].size(), A_stl.size());
+
+ for (int j=0; j<A_stl.size() ; j++){
+ for (int i=0; i<A_stl[j].size() ; i++){
+ A.coeffRef(i,j) = A_stl[j][i];
+ }
+ }
+ }
+
+ static BTL_DONT_INLINE void vector_from_stl(gene_vector & B, stl_vector & B_stl){
+ B.resize(B_stl.size(),1);
+
+ for (int i=0; i<B_stl.size() ; i++){
+ B.coeffRef(i) = B_stl[i];
+ }
+ }
+
+ static BTL_DONT_INLINE void vector_to_stl(gene_vector & B, stl_vector & B_stl){
+ for (int i=0; i<B_stl.size() ; i++){
+ B_stl[i] = B.coeff(i);
+ }
+ }
+
+ static BTL_DONT_INLINE void matrix_to_stl(gene_matrix & A, stl_matrix & A_stl){
+ int N=A_stl.size();
+
+ for (int j=0;j<N;j++){
+ A_stl[j].resize(N);
+ for (int i=0;i<N;i++){
+ A_stl[j][i] = A.coeff(i,j);
+ }
+ }
+ }
+
+ static inline void matrix_matrix_product(const gene_matrix & A, const gene_matrix & B, gene_matrix & X, int N){
+ X = (A*B).lazy();
+ }
+
+ static inline void transposed_matrix_matrix_product(const gene_matrix & A, const gene_matrix & B, gene_matrix & X, int N){
+ X = (A.transpose()*B.transpose()).lazy();
+ }
+
+ static inline void ata_product(const gene_matrix & A, gene_matrix & X, int N){
+ X = (A.transpose()*A).lazy();
+ }
+
+ static inline void aat_product(const gene_matrix & A, gene_matrix & X, int N){
+ X = (A*A.transpose()).lazy();
+ }
+
+ static inline void matrix_vector_product(const gene_matrix & A, const gene_vector & B, gene_vector & X, int N){
+ X = (A*B)/*.lazy()*/;
+ }
+
+ static inline void atv_product(gene_matrix & A, gene_vector & B, gene_vector & X, int N){
+ X = (A.transpose()*B)/*.lazy()*/;
+ }
+
+ static inline void axpy(real coef, const gene_vector & X, gene_vector & Y, int N){
+ Y += coef * X;
+ }
+
+ static inline void axpby(real a, const gene_vector & X, real b, gene_vector & Y, int N){
+ Y = a*X + b*Y;
+ }
+
+ static inline void copy_matrix(const gene_matrix & source, gene_matrix & cible, int N){
+ cible = source;
+ }
+
+ static inline void copy_vector(const gene_vector & source, gene_vector & cible, int N){
+ cible = source;
+ }
+
+ static inline void trisolve_lower(const gene_matrix & L, const gene_vector& B, gene_vector& X, int N){
+ X = L.template marked<LowerTriangular>().solveTriangular(B);
+ }
+
+ static inline void trisolve_lower_matrix(const gene_matrix & L, const gene_matrix& B, gene_matrix& X, int N){
+ X = L.template marked<LowerTriangular>().solveTriangular(B);
+ }
+
+ static inline void cholesky(const gene_matrix & X, gene_matrix & C, int N){
+ C = X.llt().matrixL();
+// C = X;
+// Cholesky<gene_matrix>::computeInPlace(C);
+// Cholesky<gene_matrix>::computeInPlaceBlock(C);
+ }
+
+ static inline void lu_decomp(const gene_matrix & X, gene_matrix & C, int N){
+ C = X.lu().matrixLU();
+// C = X.inverse();
+ }
+
+ static inline void tridiagonalization(const gene_matrix & X, gene_matrix & C, int N){
+ C = Tridiagonalization<gene_matrix>(X).packedMatrix();
+ }
+
+ static inline void hessenberg(const gene_matrix & X, gene_matrix & C, int N){
+ C = HessenbergDecomposition<gene_matrix>(X).packedMatrix();
+ }
+
+
+
+};
+
+#endif
diff --git a/bench/btl/libs/eigen2/main_adv.cpp b/bench/btl/libs/eigen2/main_adv.cpp
new file mode 100644
index 000000000..fe3368925
--- /dev/null
+++ b/bench/btl/libs/eigen2/main_adv.cpp
@@ -0,0 +1,44 @@
+//=====================================================
+// Copyright (C) 2008 Gael Guennebaud <gael.guennebaud@inria.fr>
+//=====================================================
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+//
+#include "utilities.h"
+#include "eigen2_interface.hh"
+#include "bench.hh"
+#include "action_trisolve.hh"
+#include "action_trisolve_matrix.hh"
+#include "action_cholesky.hh"
+#include "action_hessenberg.hh"
+#include "action_lu_decomp.hh"
+// #include "action_partial_lu.hh"
+
+BTL_MAIN;
+
+int main()
+{
+ bench<Action_trisolve<eigen2_interface<REAL_TYPE> > >(MIN_MM,MAX_MM,NB_POINT);
+ bench<Action_trisolve_matrix<eigen2_interface<REAL_TYPE> > >(MIN_MM,MAX_MM,NB_POINT);
+ bench<Action_cholesky<eigen2_interface<REAL_TYPE> > >(MIN_MM,MAX_MM,NB_POINT);
+ bench<Action_lu_decomp<eigen2_interface<REAL_TYPE> > >(MIN_MM,MAX_MM,NB_POINT);
+// bench<Action_partial_lu<eigen2_interface<REAL_TYPE> > >(MIN_MM,MAX_MM,NB_POINT);
+
+ bench<Action_hessenberg<eigen2_interface<REAL_TYPE> > >(MIN_MM,MAX_MM,NB_POINT);
+ bench<Action_tridiagonalization<eigen2_interface<REAL_TYPE> > >(MIN_MM,MAX_MM,NB_POINT);
+
+ return 0;
+}
+
+
diff --git a/bench/btl/libs/eigen2/main_linear.cpp b/bench/btl/libs/eigen2/main_linear.cpp
new file mode 100644
index 000000000..c17d16c08
--- /dev/null
+++ b/bench/btl/libs/eigen2/main_linear.cpp
@@ -0,0 +1,34 @@
+//=====================================================
+// Copyright (C) 2008 Gael Guennebaud <gael.guennebaud@inria.fr>
+//=====================================================
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+//
+#include "utilities.h"
+#include "eigen2_interface.hh"
+#include "bench.hh"
+#include "basic_actions.hh"
+
+BTL_MAIN;
+
+int main()
+{
+
+ bench<Action_axpy<eigen2_interface<REAL_TYPE> > >(MIN_AXPY,MAX_AXPY,NB_POINT);
+ bench<Action_axpby<eigen2_interface<REAL_TYPE> > >(MIN_AXPY,MAX_AXPY,NB_POINT);
+
+ return 0;
+}
+
+
diff --git a/bench/btl/libs/eigen2/main_matmat.cpp b/bench/btl/libs/eigen2/main_matmat.cpp
new file mode 100644
index 000000000..cd9dc9cb0
--- /dev/null
+++ b/bench/btl/libs/eigen2/main_matmat.cpp
@@ -0,0 +1,35 @@
+//=====================================================
+// Copyright (C) 2008 Gael Guennebaud <gael.guennebaud@inria.fr>
+//=====================================================
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+//
+#include "utilities.h"
+#include "eigen2_interface.hh"
+#include "bench.hh"
+#include "basic_actions.hh"
+
+BTL_MAIN;
+
+int main()
+{
+ bench<Action_matrix_matrix_product<eigen2_interface<REAL_TYPE> > >(MIN_MM,MAX_MM,NB_POINT);
+// bench<Action_ata_product<eigen2_interface<REAL_TYPE> > >(MIN_MM,MAX_MM,NB_POINT);
+ bench<Action_aat_product<eigen2_interface<REAL_TYPE> > >(MIN_MM,MAX_MM,NB_POINT);
+// bench<Action_trmm<eigen2_interface<REAL_TYPE> > >(MIN_MM,MAX_MM,NB_POINT);
+
+ return 0;
+}
+
+
diff --git a/bench/btl/libs/eigen2/main_vecmat.cpp b/bench/btl/libs/eigen2/main_vecmat.cpp
new file mode 100644
index 000000000..8b66cd2d9
--- /dev/null
+++ b/bench/btl/libs/eigen2/main_vecmat.cpp
@@ -0,0 +1,36 @@
+//=====================================================
+// Copyright (C) 2008 Gael Guennebaud <gael.guennebaud@inria.fr>
+//=====================================================
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+//
+#include "utilities.h"
+#include "eigen2_interface.hh"
+#include "bench.hh"
+#include "basic_actions.hh"
+
+BTL_MAIN;
+
+int main()
+{
+ bench<Action_matrix_vector_product<eigen2_interface<REAL_TYPE> > >(MIN_MV,MAX_MV,NB_POINT);
+ bench<Action_atv_product<eigen2_interface<REAL_TYPE> > >(MIN_MV,MAX_MV,NB_POINT);
+// bench<Action_symv<eigen2_interface<REAL_TYPE> > >(MIN_MV,MAX_MV,NB_POINT);
+// bench<Action_syr2<eigen2_interface<REAL_TYPE> > >(MIN_MV,MAX_MV,NB_POINT);
+// bench<Action_ger<eigen2_interface<REAL_TYPE> > >(MIN_MV,MAX_MV,NB_POINT);
+
+ return 0;
+}
+
+
diff --git a/bench/btl/libs/eigen3/CMakeLists.txt b/bench/btl/libs/eigen3/CMakeLists.txt
new file mode 100644
index 000000000..00cae23d3
--- /dev/null
+++ b/bench/btl/libs/eigen3/CMakeLists.txt
@@ -0,0 +1,65 @@
+
+
+if((NOT EIGEN3_INCLUDE_DIR) AND Eigen_SOURCE_DIR)
+ # unless EIGEN3_INCLUDE_DIR is defined, let's use current Eigen version
+ set(EIGEN3_INCLUDE_DIR ${Eigen_SOURCE_DIR})
+ set(EIGEN3_FOUND TRUE)
+else()
+ find_package(Eigen3)
+endif()
+
+if (EIGEN3_FOUND)
+
+ include_directories(${EIGEN3_INCLUDE_DIR})
+ btl_add_bench(btl_eigen3_linear main_linear.cpp)
+ btl_add_bench(btl_eigen3_vecmat main_vecmat.cpp)
+ btl_add_bench(btl_eigen3_matmat main_matmat.cpp)
+ btl_add_bench(btl_eigen3_adv main_adv.cpp )
+
+ btl_add_target_property(btl_eigen3_linear COMPILE_FLAGS "-fno-exceptions -DBTL_PREFIX=eigen3")
+ btl_add_target_property(btl_eigen3_vecmat COMPILE_FLAGS "-fno-exceptions -DBTL_PREFIX=eigen3")
+ btl_add_target_property(btl_eigen3_matmat COMPILE_FLAGS "-fno-exceptions -DBTL_PREFIX=eigen3")
+ btl_add_target_property(btl_eigen3_adv COMPILE_FLAGS "-fno-exceptions -DBTL_PREFIX=eigen3")
+
+ option(BTL_BENCH_NOGCCVEC "also bench Eigen explicit vec without GCC's auto vec" OFF)
+ if(CMAKE_COMPILER_IS_GNUCXX AND BTL_BENCH_NOGCCVEC)
+ btl_add_bench(btl_eigen3_nogccvec_linear main_linear.cpp)
+ btl_add_bench(btl_eigen3_nogccvec_vecmat main_vecmat.cpp)
+ btl_add_bench(btl_eigen3_nogccvec_matmat main_matmat.cpp)
+ btl_add_bench(btl_eigen3_nogccvec_adv main_adv.cpp )
+
+ btl_add_target_property(btl_eigen3_nogccvec_linear COMPILE_FLAGS "-fno-exceptions -fno-tree-vectorize -DBTL_PREFIX=eigen3_nogccvec")
+ btl_add_target_property(btl_eigen3_nogccvec_vecmat COMPILE_FLAGS "-fno-exceptions -fno-tree-vectorize -DBTL_PREFIX=eigen3_nogccvec")
+ btl_add_target_property(btl_eigen3_nogccvec_matmat COMPILE_FLAGS "-fno-exceptions -fno-tree-vectorize -DBTL_PREFIX=eigen3_nogccvec")
+ btl_add_target_property(btl_eigen3_nogccvec_adv COMPILE_FLAGS "-fno-exceptions -fno-tree-vectorize -DBTL_PREFIX=eigen3_nogccvec")
+ endif()
+
+
+ if(NOT BTL_NOVEC)
+ btl_add_bench(btl_eigen3_novec_linear main_linear.cpp OFF)
+ btl_add_bench(btl_eigen3_novec_vecmat main_vecmat.cpp OFF)
+ btl_add_bench(btl_eigen3_novec_matmat main_matmat.cpp OFF)
+ btl_add_bench(btl_eigen3_novec_adv main_adv.cpp OFF)
+ btl_add_target_property(btl_eigen3_novec_linear COMPILE_FLAGS "-fno-exceptions -DEIGEN_DONT_VECTORIZE -DBTL_PREFIX=eigen3_novec")
+ btl_add_target_property(btl_eigen3_novec_vecmat COMPILE_FLAGS "-fno-exceptions -DEIGEN_DONT_VECTORIZE -DBTL_PREFIX=eigen3_novec")
+ btl_add_target_property(btl_eigen3_novec_matmat COMPILE_FLAGS "-fno-exceptions -DEIGEN_DONT_VECTORIZE -DBTL_PREFIX=eigen3_novec")
+ btl_add_target_property(btl_eigen3_novec_adv COMPILE_FLAGS "-fno-exceptions -DEIGEN_DONT_VECTORIZE -DBTL_PREFIX=eigen3_novec")
+
+# if(BUILD_btl_eigen3_adv)
+# target_link_libraries(btl_eigen3_adv ${MKL_LIBRARIES})
+# endif(BUILD_btl_eigen3_adv)
+
+ endif(NOT BTL_NOVEC)
+
+ btl_add_bench(btl_tiny_eigen3 btl_tiny_eigen3.cpp OFF)
+
+ if(NOT BTL_NOVEC)
+ btl_add_bench(btl_tiny_eigen3_novec btl_tiny_eigen3.cpp OFF)
+ btl_add_target_property(btl_tiny_eigen3_novec COMPILE_FLAGS "-DBTL_PREFIX=eigen3_tiny")
+
+ if(BUILD_btl_tiny_eigen3_novec)
+ btl_add_target_property(btl_tiny_eigen3_novec COMPILE_FLAGS "-DEIGEN_DONT_VECTORIZE -DBTL_PREFIX=eigen3_tiny_novec")
+ endif(BUILD_btl_tiny_eigen3_novec)
+ endif(NOT BTL_NOVEC)
+
+endif (EIGEN3_FOUND)
diff --git a/bench/btl/libs/eigen3/btl_tiny_eigen3.cpp b/bench/btl/libs/eigen3/btl_tiny_eigen3.cpp
new file mode 100644
index 000000000..d1515be84
--- /dev/null
+++ b/bench/btl/libs/eigen3/btl_tiny_eigen3.cpp
@@ -0,0 +1,46 @@
+//=====================================================
+// Copyright (C) 2008 Gael Guennebaud <gael.guennebaud@inria.fr>
+//=====================================================
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+//
+#include "utilities.h"
+#include "eigen3_interface.hh"
+#include "static/bench_static.hh"
+#include "action_matrix_vector_product.hh"
+#include "action_matrix_matrix_product.hh"
+#include "action_axpy.hh"
+#include "action_lu_solve.hh"
+#include "action_ata_product.hh"
+#include "action_aat_product.hh"
+#include "action_atv_product.hh"
+#include "action_cholesky.hh"
+#include "action_trisolve.hh"
+
+BTL_MAIN;
+
+int main()
+{
+
+ bench_static<Action_axpy,eigen2_interface>();
+ bench_static<Action_matrix_matrix_product,eigen2_interface>();
+ bench_static<Action_matrix_vector_product,eigen2_interface>();
+ bench_static<Action_atv_product,eigen2_interface>();
+ bench_static<Action_cholesky,eigen2_interface>();
+ bench_static<Action_trisolve,eigen2_interface>();
+
+ return 0;
+}
+
+
diff --git a/bench/btl/libs/eigen3/eigen3_interface.hh b/bench/btl/libs/eigen3/eigen3_interface.hh
new file mode 100644
index 000000000..31bcc1f93
--- /dev/null
+++ b/bench/btl/libs/eigen3/eigen3_interface.hh
@@ -0,0 +1,240 @@
+//=====================================================
+// Copyright (C) 2008 Gael Guennebaud <gael.guennebaud@inria.fr>
+//=====================================================
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+//
+#ifndef EIGEN3_INTERFACE_HH
+#define EIGEN3_INTERFACE_HH
+
+#include <Eigen/Eigen>
+#include <vector>
+#include "btl.hh"
+
+using namespace Eigen;
+
+template<class real, int SIZE=Dynamic>
+class eigen3_interface
+{
+
+public :
+
+ enum {IsFixedSize = (SIZE!=Dynamic)};
+
+ typedef real real_type;
+
+ typedef std::vector<real> stl_vector;
+ typedef std::vector<stl_vector> stl_matrix;
+
+ typedef Eigen::Matrix<real,SIZE,SIZE> gene_matrix;
+ typedef Eigen::Matrix<real,SIZE,1> gene_vector;
+
+ static inline std::string name( void )
+ {
+ return EIGEN_MAKESTRING(BTL_PREFIX);
+ }
+
+ static void free_matrix(gene_matrix & A, int N) {}
+
+ static void free_vector(gene_vector & B) {}
+
+ static BTL_DONT_INLINE void matrix_from_stl(gene_matrix & A, stl_matrix & A_stl){
+ A.resize(A_stl[0].size(), A_stl.size());
+
+ for (int j=0; j<A_stl.size() ; j++){
+ for (int i=0; i<A_stl[j].size() ; i++){
+ A.coeffRef(i,j) = A_stl[j][i];
+ }
+ }
+ }
+
+ static BTL_DONT_INLINE void vector_from_stl(gene_vector & B, stl_vector & B_stl){
+ B.resize(B_stl.size(),1);
+
+ for (int i=0; i<B_stl.size() ; i++){
+ B.coeffRef(i) = B_stl[i];
+ }
+ }
+
+ static BTL_DONT_INLINE void vector_to_stl(gene_vector & B, stl_vector & B_stl){
+ for (int i=0; i<B_stl.size() ; i++){
+ B_stl[i] = B.coeff(i);
+ }
+ }
+
+ static BTL_DONT_INLINE void matrix_to_stl(gene_matrix & A, stl_matrix & A_stl){
+ int N=A_stl.size();
+
+ for (int j=0;j<N;j++){
+ A_stl[j].resize(N);
+ for (int i=0;i<N;i++){
+ A_stl[j][i] = A.coeff(i,j);
+ }
+ }
+ }
+
+ static inline void matrix_matrix_product(const gene_matrix & A, const gene_matrix & B, gene_matrix & X, int N){
+ X.noalias() = A*B;
+ }
+
+ static inline void transposed_matrix_matrix_product(const gene_matrix & A, const gene_matrix & B, gene_matrix & X, int N){
+ X.noalias() = A.transpose()*B.transpose();
+ }
+
+// static inline void ata_product(const gene_matrix & A, gene_matrix & X, int N){
+// X.noalias() = A.transpose()*A;
+// }
+
+ static inline void aat_product(const gene_matrix & A, gene_matrix & X, int N){
+ X.template triangularView<Lower>().setZero();
+ X.template selfadjointView<Lower>().rankUpdate(A);
+ }
+
+ static inline void matrix_vector_product(const gene_matrix & A, const gene_vector & B, gene_vector & X, int N){
+ X.noalias() = A*B;
+ }
+
+ static inline void symv(const gene_matrix & A, const gene_vector & B, gene_vector & X, int N){
+ X.noalias() = (A.template selfadjointView<Lower>() * B);
+// internal::product_selfadjoint_vector<real,0,LowerTriangularBit,false,false>(N,A.data(),N, B.data(), 1, X.data(), 1);
+ }
+
+ template<typename Dest, typename Src> static void triassign(Dest& dst, const Src& src)
+ {
+ typedef typename Dest::Scalar Scalar;
+ typedef typename internal::packet_traits<Scalar>::type Packet;
+ const int PacketSize = sizeof(Packet)/sizeof(Scalar);
+ int size = dst.cols();
+ for(int j=0; j<size; j+=1)
+ {
+// const int alignedEnd = alignedStart + ((innerSize-alignedStart) & ~packetAlignedMask);
+ Scalar* A0 = dst.data() + j*dst.stride();
+ int starti = j;
+ int alignedEnd = starti;
+ int alignedStart = (starti) + internal::first_aligned(&A0[starti], size-starti);
+ alignedEnd = alignedStart + ((size-alignedStart)/(2*PacketSize))*(PacketSize*2);
+
+ // do the non-vectorizable part of the assignment
+ for (int index = starti; index<alignedStart ; ++index)
+ {
+ if(Dest::Flags&RowMajorBit)
+ dst.copyCoeff(j, index, src);
+ else
+ dst.copyCoeff(index, j, src);
+ }
+
+ // do the vectorizable part of the assignment
+ for (int index = alignedStart; index<alignedEnd; index+=PacketSize)
+ {
+ if(Dest::Flags&RowMajorBit)
+ dst.template copyPacket<Src, Aligned, Unaligned>(j, index, src);
+ else
+ dst.template copyPacket<Src, Aligned, Unaligned>(index, j, src);
+ }
+
+ // do the non-vectorizable part of the assignment
+ for (int index = alignedEnd; index<size; ++index)
+ {
+ if(Dest::Flags&RowMajorBit)
+ dst.copyCoeff(j, index, src);
+ else
+ dst.copyCoeff(index, j, src);
+ }
+ //dst.col(j).tail(N-j) = src.col(j).tail(N-j);
+ }
+ }
+
+ static EIGEN_DONT_INLINE void syr2(gene_matrix & A, gene_vector & X, gene_vector & Y, int N){
+ // internal::product_selfadjoint_rank2_update<real,0,LowerTriangularBit>(N,A.data(),N, X.data(), 1, Y.data(), 1, -1);
+ for(int j=0; j<N; ++j)
+ A.col(j).tail(N-j) += X[j] * Y.tail(N-j) + Y[j] * X.tail(N-j);
+ }
+
+ static EIGEN_DONT_INLINE void ger(gene_matrix & A, gene_vector & X, gene_vector & Y, int N){
+ for(int j=0; j<N; ++j)
+ A.col(j) += X * Y[j];
+ }
+
+ static EIGEN_DONT_INLINE void rot(gene_vector & A, gene_vector & B, real c, real s, int N){
+ internal::apply_rotation_in_the_plane(A, B, JacobiRotation<real>(c,s));
+ }
+
+ static inline void atv_product(gene_matrix & A, gene_vector & B, gene_vector & X, int N){
+ X.noalias() = (A.transpose()*B);
+ }
+
+ static inline void axpy(real coef, const gene_vector & X, gene_vector & Y, int N){
+ Y += coef * X;
+ }
+
+ static inline void axpby(real a, const gene_vector & X, real b, gene_vector & Y, int N){
+ Y = a*X + b*Y;
+ }
+
+ static EIGEN_DONT_INLINE void copy_matrix(const gene_matrix & source, gene_matrix & cible, int N){
+ cible = source;
+ }
+
+ static EIGEN_DONT_INLINE void copy_vector(const gene_vector & source, gene_vector & cible, int N){
+ cible = source;
+ }
+
+ static inline void trisolve_lower(const gene_matrix & L, const gene_vector& B, gene_vector& X, int N){
+ X = L.template triangularView<Lower>().solve(B);
+ }
+
+ static inline void trisolve_lower_matrix(const gene_matrix & L, const gene_matrix& B, gene_matrix& X, int N){
+ X = L.template triangularView<Upper>().solve(B);
+ }
+
+ static inline void trmm(const gene_matrix & L, const gene_matrix& B, gene_matrix& X, int N){
+ X.noalias() = L.template triangularView<Lower>() * B;
+ }
+
+ static inline void cholesky(const gene_matrix & X, gene_matrix & C, int N){
+ C = X;
+ internal::llt_inplace<real,Lower>::blocked(C);
+ //C = X.llt().matrixL();
+// C = X;
+// Cholesky<gene_matrix>::computeInPlace(C);
+// Cholesky<gene_matrix>::computeInPlaceBlock(C);
+ }
+
+ static inline void lu_decomp(const gene_matrix & X, gene_matrix & C, int N){
+ C = X.fullPivLu().matrixLU();
+ }
+
+ static inline void partial_lu_decomp(const gene_matrix & X, gene_matrix & C, int N){
+ Matrix<DenseIndex,1,Dynamic> piv(N);
+ DenseIndex nb;
+ C = X;
+ internal::partial_lu_inplace(C,piv,nb);
+// C = X.partialPivLu().matrixLU();
+ }
+
+ static inline void tridiagonalization(const gene_matrix & X, gene_matrix & C, int N){
+ typename Tridiagonalization<gene_matrix>::CoeffVectorType aux(N-1);
+ C = X;
+ internal::tridiagonalization_inplace(C, aux);
+ }
+
+ static inline void hessenberg(const gene_matrix & X, gene_matrix & C, int N){
+ C = HessenbergDecomposition<gene_matrix>(X).packedMatrix();
+ }
+
+
+
+};
+
+#endif
diff --git a/bench/btl/libs/eigen3/main_adv.cpp b/bench/btl/libs/eigen3/main_adv.cpp
new file mode 100644
index 000000000..efe5857e4
--- /dev/null
+++ b/bench/btl/libs/eigen3/main_adv.cpp
@@ -0,0 +1,44 @@
+//=====================================================
+// Copyright (C) 2008 Gael Guennebaud <gael.guennebaud@inria.fr>
+//=====================================================
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+//
+#include "utilities.h"
+#include "eigen3_interface.hh"
+#include "bench.hh"
+#include "action_trisolve.hh"
+#include "action_trisolve_matrix.hh"
+#include "action_cholesky.hh"
+#include "action_hessenberg.hh"
+#include "action_lu_decomp.hh"
+#include "action_partial_lu.hh"
+
+BTL_MAIN;
+
+int main()
+{
+ bench<Action_trisolve<eigen3_interface<REAL_TYPE> > >(MIN_MM,MAX_MM,NB_POINT);
+ bench<Action_trisolve_matrix<eigen3_interface<REAL_TYPE> > >(MIN_MM,MAX_MM,NB_POINT);
+ bench<Action_cholesky<eigen3_interface<REAL_TYPE> > >(MIN_MM,MAX_MM,NB_POINT);
+ bench<Action_lu_decomp<eigen3_interface<REAL_TYPE> > >(MIN_MM,MAX_MM,NB_POINT);
+ bench<Action_partial_lu<eigen3_interface<REAL_TYPE> > >(MIN_MM,MAX_MM,NB_POINT);
+
+ bench<Action_hessenberg<eigen3_interface<REAL_TYPE> > >(MIN_MM,MAX_MM,NB_POINT);
+ bench<Action_tridiagonalization<eigen3_interface<REAL_TYPE> > >(MIN_MM,MAX_MM,NB_POINT);
+
+ return 0;
+}
+
+
diff --git a/bench/btl/libs/eigen3/main_linear.cpp b/bench/btl/libs/eigen3/main_linear.cpp
new file mode 100644
index 000000000..e8538b7d0
--- /dev/null
+++ b/bench/btl/libs/eigen3/main_linear.cpp
@@ -0,0 +1,35 @@
+//=====================================================
+// Copyright (C) 2008 Gael Guennebaud <gael.guennebaud@inria.fr>
+//=====================================================
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+//
+#include "utilities.h"
+#include "eigen3_interface.hh"
+#include "bench.hh"
+#include "basic_actions.hh"
+
+BTL_MAIN;
+
+int main()
+{
+
+ bench<Action_axpy<eigen3_interface<REAL_TYPE> > >(MIN_AXPY,MAX_AXPY,NB_POINT);
+ bench<Action_axpby<eigen3_interface<REAL_TYPE> > >(MIN_AXPY,MAX_AXPY,NB_POINT);
+ bench<Action_rot<eigen3_interface<REAL_TYPE> > >(MIN_AXPY,MAX_AXPY,NB_POINT);
+
+ return 0;
+}
+
+
diff --git a/bench/btl/libs/eigen3/main_matmat.cpp b/bench/btl/libs/eigen3/main_matmat.cpp
new file mode 100644
index 000000000..926fa2b01
--- /dev/null
+++ b/bench/btl/libs/eigen3/main_matmat.cpp
@@ -0,0 +1,35 @@
+//=====================================================
+// Copyright (C) 2008 Gael Guennebaud <gael.guennebaud@inria.fr>
+//=====================================================
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+//
+#include "utilities.h"
+#include "eigen3_interface.hh"
+#include "bench.hh"
+#include "basic_actions.hh"
+
+BTL_MAIN;
+
+int main()
+{
+ bench<Action_matrix_matrix_product<eigen3_interface<REAL_TYPE> > >(MIN_MM,MAX_MM,NB_POINT);
+// bench<Action_ata_product<eigen3_interface<REAL_TYPE> > >(MIN_MM,MAX_MM,NB_POINT);
+ bench<Action_aat_product<eigen3_interface<REAL_TYPE> > >(MIN_MM,MAX_MM,NB_POINT);
+ bench<Action_trmm<eigen3_interface<REAL_TYPE> > >(MIN_MM,MAX_MM,NB_POINT);
+
+ return 0;
+}
+
+
diff --git a/bench/btl/libs/eigen3/main_vecmat.cpp b/bench/btl/libs/eigen3/main_vecmat.cpp
new file mode 100644
index 000000000..0dda444cf
--- /dev/null
+++ b/bench/btl/libs/eigen3/main_vecmat.cpp
@@ -0,0 +1,36 @@
+//=====================================================
+// Copyright (C) 2008 Gael Guennebaud <gael.guennebaud@inria.fr>
+//=====================================================
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+//
+#include "utilities.h"
+#include "eigen3_interface.hh"
+#include "bench.hh"
+#include "basic_actions.hh"
+
+BTL_MAIN;
+
+int main()
+{
+ bench<Action_matrix_vector_product<eigen3_interface<REAL_TYPE> > >(MIN_MV,MAX_MV,NB_POINT);
+ bench<Action_atv_product<eigen3_interface<REAL_TYPE> > >(MIN_MV,MAX_MV,NB_POINT);
+ bench<Action_symv<eigen3_interface<REAL_TYPE> > >(MIN_MV,MAX_MV,NB_POINT);
+ bench<Action_syr2<eigen3_interface<REAL_TYPE> > >(MIN_MV,MAX_MV,NB_POINT);
+ bench<Action_ger<eigen3_interface<REAL_TYPE> > >(MIN_MV,MAX_MV,NB_POINT);
+
+ return 0;
+}
+
+
diff --git a/bench/btl/libs/gmm/CMakeLists.txt b/bench/btl/libs/gmm/CMakeLists.txt
new file mode 100644
index 000000000..bc2586243
--- /dev/null
+++ b/bench/btl/libs/gmm/CMakeLists.txt
@@ -0,0 +1,6 @@
+
+find_package(GMM)
+if (GMM_FOUND)
+ include_directories(${GMM_INCLUDES})
+ btl_add_bench(btl_gmm main.cpp)
+endif (GMM_FOUND)
diff --git a/bench/btl/libs/gmm/gmm_LU_solve_interface.hh b/bench/btl/libs/gmm/gmm_LU_solve_interface.hh
new file mode 100644
index 000000000..dcb9f567f
--- /dev/null
+++ b/bench/btl/libs/gmm/gmm_LU_solve_interface.hh
@@ -0,0 +1,192 @@
+//=====================================================
+// File : blitz_LU_solve_interface.hh
+// Author : L. Plagne <laurent.plagne@edf.fr)>
+// Copyright (C) EDF R&D, lun sep 30 14:23:31 CEST 2002
+//=====================================================
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+//
+#ifndef BLITZ_LU_SOLVE_INTERFACE_HH
+#define BLITZ_LU_SOLVE_INTERFACE_HH
+
+#include "blitz/array.h"
+#include <vector>
+
+BZ_USING_NAMESPACE(blitz)
+
+template<class real>
+class blitz_LU_solve_interface : public blitz_interface<real>
+{
+
+public :
+
+ typedef typename blitz_interface<real>::gene_matrix gene_matrix;
+ typedef typename blitz_interface<real>::gene_vector gene_vector;
+
+ typedef blitz::Array<int,1> Pivot_Vector;
+
+ inline static void new_Pivot_Vector(Pivot_Vector & pivot,int N)
+ {
+
+ pivot.resize(N);
+
+ }
+
+ inline static void free_Pivot_Vector(Pivot_Vector & pivot)
+ {
+
+ return;
+
+ }
+
+
+ static inline real matrix_vector_product_sliced(const gene_matrix & A, gene_vector B, int row, int col_start, int col_end)
+ {
+
+ real somme=0.;
+
+ for (int j=col_start ; j<col_end+1 ; j++){
+
+ somme+=A(row,j)*B(j);
+
+ }
+
+ return somme;
+
+ }
+
+
+
+
+ static inline real matrix_matrix_product_sliced(gene_matrix & A, int row, int col_start, int col_end, gene_matrix & B, int row_shift, int col )
+ {
+
+ real somme=0.;
+
+ for (int j=col_start ; j<col_end+1 ; j++){
+
+ somme+=A(row,j)*B(j+row_shift,col);
+
+ }
+
+ return somme;
+
+ }
+
+ inline static void LU_factor(gene_matrix & LU, Pivot_Vector & pivot, int N)
+ {
+
+ ASSERT( LU.rows()==LU.cols() ) ;
+ int index_max = 0 ;
+ real big = 0. ;
+ real theSum = 0. ;
+ real dum = 0. ;
+ // Get the implicit scaling information :
+ gene_vector ImplicitScaling( N ) ;
+ for( int i=0; i<N; i++ ) {
+ big = 0. ;
+ for( int j=0; j<N; j++ ) {
+ if( abs( LU( i, j ) )>=big ) big = abs( LU( i, j ) ) ;
+ }
+ if( big==0. ) {
+ INFOS( "blitz_LU_factor::Singular matrix" ) ;
+ exit( 0 ) ;
+ }
+ ImplicitScaling( i ) = 1./big ;
+ }
+ // Loop over columns of Crout's method :
+ for( int j=0; j<N; j++ ) {
+ for( int i=0; i<j; i++ ) {
+ theSum = LU( i, j ) ;
+ theSum -= matrix_matrix_product_sliced(LU, i, 0, i-1, LU, 0, j) ;
+ // theSum -= sum( LU( i, Range( fromStart, i-1 ) )*LU( Range( fromStart, i-1 ), j ) ) ;
+ LU( i, j ) = theSum ;
+ }
+
+ // Search for the largest pivot element :
+ big = 0. ;
+ for( int i=j; i<N; i++ ) {
+ theSum = LU( i, j ) ;
+ theSum -= matrix_matrix_product_sliced(LU, i, 0, j-1, LU, 0, j) ;
+ // theSum -= sum( LU( i, Range( fromStart, j-1 ) )*LU( Range( fromStart, j-1 ), j ) ) ;
+ LU( i, j ) = theSum ;
+ if( (ImplicitScaling( i )*abs( theSum ))>=big ) {
+ dum = ImplicitScaling( i )*abs( theSum ) ;
+ big = dum ;
+ index_max = i ;
+ }
+ }
+ // Interchanging rows and the scale factor :
+ if( j!=index_max ) {
+ for( int k=0; k<N; k++ ) {
+ dum = LU( index_max, k ) ;
+ LU( index_max, k ) = LU( j, k ) ;
+ LU( j, k ) = dum ;
+ }
+ ImplicitScaling( index_max ) = ImplicitScaling( j ) ;
+ }
+ pivot( j ) = index_max ;
+ if ( LU( j, j )==0. ) LU( j, j ) = 1.e-20 ;
+ // Divide by the pivot element :
+ if( j<N ) {
+ dum = 1./LU( j, j ) ;
+ for( int i=j+1; i<N; i++ ) LU( i, j ) *= dum ;
+ }
+ }
+
+ }
+
+ inline static void LU_solve(const gene_matrix & LU, const Pivot_Vector pivot, gene_vector &B, gene_vector X, int N)
+ {
+
+ // Pour conserver le meme header, on travaille sur X, copie du second-membre B
+ X = B.copy() ;
+ ASSERT( LU.rows()==LU.cols() ) ;
+ firstIndex indI ;
+ // Forward substitution :
+ int ii = 0 ;
+ real theSum = 0. ;
+ for( int i=0; i<N; i++ ) {
+ int ip = pivot( i ) ;
+ theSum = X( ip ) ;
+ // theSum = B( ip ) ;
+ X( ip ) = X( i ) ;
+ // B( ip ) = B( i ) ;
+ if( ii ) {
+ theSum -= matrix_vector_product_sliced(LU, X, i, ii-1, i-1) ;
+ // theSum -= sum( LU( i, Range( ii-1, i-1 ) )*X( Range( ii-1, i-1 ) ) ) ;
+ // theSum -= sum( LU( i, Range( ii-1, i-1 ) )*B( Range( ii-1, i-1 ) ) ) ;
+ } else if( theSum ) {
+ ii = i+1 ;
+ }
+ X( i ) = theSum ;
+ // B( i ) = theSum ;
+ }
+ // Backsubstitution :
+ for( int i=N-1; i>=0; i-- ) {
+ theSum = X( i ) ;
+ // theSum = B( i ) ;
+ theSum -= matrix_vector_product_sliced(LU, X, i, i+1, N) ;
+ // theSum -= sum( LU( i, Range( i+1, toEnd ) )*X( Range( i+1, toEnd ) ) ) ;
+ // theSum -= sum( LU( i, Range( i+1, toEnd ) )*B( Range( i+1, toEnd ) ) ) ;
+ // Store a component of the solution vector :
+ X( i ) = theSum/LU( i, i ) ;
+ // B( i ) = theSum/LU( i, i ) ;
+ }
+
+ }
+
+};
+
+#endif
diff --git a/bench/btl/libs/gmm/gmm_interface.hh b/bench/btl/libs/gmm/gmm_interface.hh
new file mode 100644
index 000000000..3ea303c1b
--- /dev/null
+++ b/bench/btl/libs/gmm/gmm_interface.hh
@@ -0,0 +1,144 @@
+//=====================================================
+// Copyright (C) 2008 Gael Guennebaud <gael.guennebaud@inria.fr>
+//=====================================================
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+//
+#ifndef GMM_INTERFACE_HH
+#define GMM_INTERFACE_HH
+
+#include <gmm/gmm.h>
+#include <vector>
+
+using namespace gmm;
+
+template<class real>
+class gmm_interface {
+
+public :
+
+ typedef real real_type ;
+
+ typedef std::vector<real> stl_vector;
+ typedef std::vector<stl_vector > stl_matrix;
+
+ typedef gmm::dense_matrix<real> gene_matrix;
+ typedef stl_vector gene_vector;
+
+ static inline std::string name( void )
+ {
+ return "gmm";
+ }
+
+ static void free_matrix(gene_matrix & A, int N){
+ return ;
+ }
+
+ static void free_vector(gene_vector & B){
+ return ;
+ }
+
+ static inline void matrix_from_stl(gene_matrix & A, stl_matrix & A_stl){
+ A.resize(A_stl[0].size(),A_stl.size());
+
+ for (int j=0; j<A_stl.size() ; j++){
+ for (int i=0; i<A_stl[j].size() ; i++){
+ A(i,j) = A_stl[j][i];
+ }
+ }
+ }
+
+ static inline void vector_from_stl(gene_vector & B, stl_vector & B_stl){
+ B = B_stl;
+ }
+
+ static inline void vector_to_stl(gene_vector & B, stl_vector & B_stl){
+ B_stl = B;
+ }
+
+ static inline void matrix_to_stl(gene_matrix & A, stl_matrix & A_stl){
+ int N=A_stl.size();
+
+ for (int j=0;j<N;j++){
+ A_stl[j].resize(N);
+ for (int i=0;i<N;i++){
+ A_stl[j][i] = A(i,j);
+ }
+ }
+ }
+
+ static inline void matrix_matrix_product(const gene_matrix & A, const gene_matrix & B, gene_matrix & X, int N){
+ gmm::mult(A,B, X);
+ }
+
+ static inline void transposed_matrix_matrix_product(const gene_matrix & A, const gene_matrix & B, gene_matrix & X, int N){
+ gmm::mult(gmm::transposed(A),gmm::transposed(B), X);
+ }
+
+ static inline void ata_product(const gene_matrix & A, gene_matrix & X, int N){
+ gmm::mult(gmm::transposed(A),A, X);
+ }
+
+ static inline void aat_product(const gene_matrix & A, gene_matrix & X, int N){
+ gmm::mult(A,gmm::transposed(A), X);
+ }
+
+ static inline void matrix_vector_product(gene_matrix & A, gene_vector & B, gene_vector & X, int N){
+ gmm::mult(A,B,X);
+ }
+
+ static inline void atv_product(gene_matrix & A, gene_vector & B, gene_vector & X, int N){
+ gmm::mult(gmm::transposed(A),B,X);
+ }
+
+ static inline void axpy(const real coef, const gene_vector & X, gene_vector & Y, int N){
+ gmm::add(gmm::scaled(X,coef), Y);
+ }
+
+ static inline void axpby(real a, const gene_vector & X, real b, gene_vector & Y, int N){
+ gmm::add(gmm::scaled(X,a), gmm::scaled(Y,b), Y);
+ }
+
+ static inline void copy_matrix(const gene_matrix & source, gene_matrix & cible, int N){
+ gmm::copy(source,cible);
+ }
+
+ static inline void copy_vector(const gene_vector & source, gene_vector & cible, int N){
+ gmm::copy(source,cible);
+ }
+
+ static inline void trisolve_lower(const gene_matrix & L, const gene_vector& B, gene_vector & X, int N){
+ gmm::copy(B,X);
+ gmm::lower_tri_solve(L, X, false);
+ }
+
+ static inline void partial_lu_decomp(const gene_matrix & X, gene_matrix & R, int N){
+ gmm::copy(X,R);
+ std::vector<int> ipvt(N);
+ gmm::lu_factor(R, ipvt);
+ }
+
+ static inline void hessenberg(const gene_matrix & X, gene_matrix & R, int N){
+ gmm::copy(X,R);
+ gmm::Hessenberg_reduction(R,X,false);
+ }
+
+ static inline void tridiagonalization(const gene_matrix & X, gene_matrix & R, int N){
+ gmm::copy(X,R);
+ gmm::Householder_tridiagonalization(R,X,false);
+ }
+
+};
+
+#endif
diff --git a/bench/btl/libs/gmm/main.cpp b/bench/btl/libs/gmm/main.cpp
new file mode 100644
index 000000000..1f0c051eb
--- /dev/null
+++ b/bench/btl/libs/gmm/main.cpp
@@ -0,0 +1,51 @@
+//=====================================================
+// Copyright (C) 2008 Gael Guennebaud <gael.guennebaud@inria.fr>
+//=====================================================
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+//
+#include "utilities.h"
+#include "gmm_interface.hh"
+#include "bench.hh"
+#include "basic_actions.hh"
+#include "action_hessenberg.hh"
+#include "action_partial_lu.hh"
+
+BTL_MAIN;
+
+int main()
+{
+
+ bench<Action_axpy<gmm_interface<REAL_TYPE> > >(MIN_AXPY,MAX_AXPY,NB_POINT);
+ bench<Action_axpby<gmm_interface<REAL_TYPE> > >(MIN_AXPY,MAX_AXPY,NB_POINT);
+
+ bench<Action_matrix_vector_product<gmm_interface<REAL_TYPE> > >(MIN_MV,MAX_MV,NB_POINT);
+ bench<Action_atv_product<gmm_interface<REAL_TYPE> > >(MIN_MV,MAX_MV,NB_POINT);
+
+ bench<Action_matrix_matrix_product<gmm_interface<REAL_TYPE> > >(MIN_MM,MAX_MM,NB_POINT);
+// bench<Action_ata_product<gmm_interface<REAL_TYPE> > >(MIN_MM,MAX_MM,NB_POINT);
+// bench<Action_aat_product<gmm_interface<REAL_TYPE> > >(MIN_MM,MAX_MM,NB_POINT);
+
+ bench<Action_trisolve<gmm_interface<REAL_TYPE> > >(MIN_MM,MAX_MM,NB_POINT);
+ //bench<Action_lu_solve<blitz_LU_solve_interface<REAL_TYPE> > >(MIN_LU,MAX_LU,NB_POINT);
+
+ bench<Action_partial_lu<gmm_interface<REAL_TYPE> > >(MIN_MM,MAX_MM,NB_POINT);
+
+ bench<Action_hessenberg<gmm_interface<REAL_TYPE> > >(MIN_MM,MAX_MM,NB_POINT);
+ bench<Action_tridiagonalization<gmm_interface<REAL_TYPE> > >(MIN_MM,MAX_MM,NB_POINT);
+
+ return 0;
+}
+
+
diff --git a/bench/btl/libs/mtl4/.kdbgrc.main b/bench/btl/libs/mtl4/.kdbgrc.main
new file mode 100644
index 000000000..fed082f7f
--- /dev/null
+++ b/bench/btl/libs/mtl4/.kdbgrc.main
@@ -0,0 +1,12 @@
+[General]
+DebuggerCmdStr=
+DriverName=GDB
+FileVersion=1
+OptionsSelected=
+ProgramArgs=
+TTYLevel=7
+WorkingDirectory=
+
+[Memory]
+ColumnWidths=80,0
+NumExprs=0
diff --git a/bench/btl/libs/mtl4/CMakeLists.txt b/bench/btl/libs/mtl4/CMakeLists.txt
new file mode 100644
index 000000000..14b47a808
--- /dev/null
+++ b/bench/btl/libs/mtl4/CMakeLists.txt
@@ -0,0 +1,6 @@
+
+find_package(MTL4)
+if (MTL4_FOUND)
+ include_directories(${MTL4_INCLUDE_DIR})
+ btl_add_bench(btl_mtl4 main.cpp)
+endif (MTL4_FOUND)
diff --git a/bench/btl/libs/mtl4/main.cpp b/bench/btl/libs/mtl4/main.cpp
new file mode 100644
index 000000000..96fcfb9c9
--- /dev/null
+++ b/bench/btl/libs/mtl4/main.cpp
@@ -0,0 +1,46 @@
+//=====================================================
+// Copyright (C) 2008 Gael Guennebaud <gael.guennebaud@inria.fr>
+//=====================================================
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+//
+#include "utilities.h"
+#include "mtl4_interface.hh"
+#include "bench.hh"
+#include "basic_actions.hh"
+#include "action_cholesky.hh"
+// #include "action_lu_decomp.hh"
+
+BTL_MAIN;
+
+int main()
+{
+
+ bench<Action_axpy<mtl4_interface<REAL_TYPE> > >(MIN_AXPY,MAX_AXPY,NB_POINT);
+ bench<Action_axpby<mtl4_interface<REAL_TYPE> > >(MIN_AXPY,MAX_AXPY,NB_POINT);
+
+ bench<Action_matrix_vector_product<mtl4_interface<REAL_TYPE> > >(MIN_MV,MAX_MV,NB_POINT);
+ bench<Action_atv_product<mtl4_interface<REAL_TYPE> > >(MIN_MV,MAX_MV,NB_POINT);
+ bench<Action_matrix_matrix_product<mtl4_interface<REAL_TYPE> > >(MIN_MM,MAX_MM,NB_POINT);
+// bench<Action_ata_product<mtl4_interface<REAL_TYPE> > >(MIN_MM,MAX_MM,NB_POINT);
+// bench<Action_aat_product<mtl4_interface<REAL_TYPE> > >(MIN_MM,MAX_MM,NB_POINT);
+
+ bench<Action_trisolve<mtl4_interface<REAL_TYPE> > >(MIN_MM,MAX_MM,NB_POINT);
+// bench<Action_cholesky<mtl4_interface<REAL_TYPE> > >(MIN_MM,MAX_MM,NB_POINT);
+// bench<Action_lu_decomp<mtl4_interface<REAL_TYPE> > >(MIN_MM,MAX_MM,NB_POINT);
+
+ return 0;
+}
+
+
diff --git a/bench/btl/libs/mtl4/mtl4_LU_solve_interface.hh b/bench/btl/libs/mtl4/mtl4_LU_solve_interface.hh
new file mode 100644
index 000000000..dcb9f567f
--- /dev/null
+++ b/bench/btl/libs/mtl4/mtl4_LU_solve_interface.hh
@@ -0,0 +1,192 @@
+//=====================================================
+// File : blitz_LU_solve_interface.hh
+// Author : L. Plagne <laurent.plagne@edf.fr)>
+// Copyright (C) EDF R&D, lun sep 30 14:23:31 CEST 2002
+//=====================================================
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+//
+#ifndef BLITZ_LU_SOLVE_INTERFACE_HH
+#define BLITZ_LU_SOLVE_INTERFACE_HH
+
+#include "blitz/array.h"
+#include <vector>
+
+BZ_USING_NAMESPACE(blitz)
+
+template<class real>
+class blitz_LU_solve_interface : public blitz_interface<real>
+{
+
+public :
+
+ typedef typename blitz_interface<real>::gene_matrix gene_matrix;
+ typedef typename blitz_interface<real>::gene_vector gene_vector;
+
+ typedef blitz::Array<int,1> Pivot_Vector;
+
+ inline static void new_Pivot_Vector(Pivot_Vector & pivot,int N)
+ {
+
+ pivot.resize(N);
+
+ }
+
+ inline static void free_Pivot_Vector(Pivot_Vector & pivot)
+ {
+
+ return;
+
+ }
+
+
+ static inline real matrix_vector_product_sliced(const gene_matrix & A, gene_vector B, int row, int col_start, int col_end)
+ {
+
+ real somme=0.;
+
+ for (int j=col_start ; j<col_end+1 ; j++){
+
+ somme+=A(row,j)*B(j);
+
+ }
+
+ return somme;
+
+ }
+
+
+
+
+ static inline real matrix_matrix_product_sliced(gene_matrix & A, int row, int col_start, int col_end, gene_matrix & B, int row_shift, int col )
+ {
+
+ real somme=0.;
+
+ for (int j=col_start ; j<col_end+1 ; j++){
+
+ somme+=A(row,j)*B(j+row_shift,col);
+
+ }
+
+ return somme;
+
+ }
+
+ inline static void LU_factor(gene_matrix & LU, Pivot_Vector & pivot, int N)
+ {
+
+ ASSERT( LU.rows()==LU.cols() ) ;
+ int index_max = 0 ;
+ real big = 0. ;
+ real theSum = 0. ;
+ real dum = 0. ;
+ // Get the implicit scaling information :
+ gene_vector ImplicitScaling( N ) ;
+ for( int i=0; i<N; i++ ) {
+ big = 0. ;
+ for( int j=0; j<N; j++ ) {
+ if( abs( LU( i, j ) )>=big ) big = abs( LU( i, j ) ) ;
+ }
+ if( big==0. ) {
+ INFOS( "blitz_LU_factor::Singular matrix" ) ;
+ exit( 0 ) ;
+ }
+ ImplicitScaling( i ) = 1./big ;
+ }
+ // Loop over columns of Crout's method :
+ for( int j=0; j<N; j++ ) {
+ for( int i=0; i<j; i++ ) {
+ theSum = LU( i, j ) ;
+ theSum -= matrix_matrix_product_sliced(LU, i, 0, i-1, LU, 0, j) ;
+ // theSum -= sum( LU( i, Range( fromStart, i-1 ) )*LU( Range( fromStart, i-1 ), j ) ) ;
+ LU( i, j ) = theSum ;
+ }
+
+ // Search for the largest pivot element :
+ big = 0. ;
+ for( int i=j; i<N; i++ ) {
+ theSum = LU( i, j ) ;
+ theSum -= matrix_matrix_product_sliced(LU, i, 0, j-1, LU, 0, j) ;
+ // theSum -= sum( LU( i, Range( fromStart, j-1 ) )*LU( Range( fromStart, j-1 ), j ) ) ;
+ LU( i, j ) = theSum ;
+ if( (ImplicitScaling( i )*abs( theSum ))>=big ) {
+ dum = ImplicitScaling( i )*abs( theSum ) ;
+ big = dum ;
+ index_max = i ;
+ }
+ }
+ // Interchanging rows and the scale factor :
+ if( j!=index_max ) {
+ for( int k=0; k<N; k++ ) {
+ dum = LU( index_max, k ) ;
+ LU( index_max, k ) = LU( j, k ) ;
+ LU( j, k ) = dum ;
+ }
+ ImplicitScaling( index_max ) = ImplicitScaling( j ) ;
+ }
+ pivot( j ) = index_max ;
+ if ( LU( j, j )==0. ) LU( j, j ) = 1.e-20 ;
+ // Divide by the pivot element :
+ if( j<N ) {
+ dum = 1./LU( j, j ) ;
+ for( int i=j+1; i<N; i++ ) LU( i, j ) *= dum ;
+ }
+ }
+
+ }
+
+ inline static void LU_solve(const gene_matrix & LU, const Pivot_Vector pivot, gene_vector &B, gene_vector X, int N)
+ {
+
+ // Pour conserver le meme header, on travaille sur X, copie du second-membre B
+ X = B.copy() ;
+ ASSERT( LU.rows()==LU.cols() ) ;
+ firstIndex indI ;
+ // Forward substitution :
+ int ii = 0 ;
+ real theSum = 0. ;
+ for( int i=0; i<N; i++ ) {
+ int ip = pivot( i ) ;
+ theSum = X( ip ) ;
+ // theSum = B( ip ) ;
+ X( ip ) = X( i ) ;
+ // B( ip ) = B( i ) ;
+ if( ii ) {
+ theSum -= matrix_vector_product_sliced(LU, X, i, ii-1, i-1) ;
+ // theSum -= sum( LU( i, Range( ii-1, i-1 ) )*X( Range( ii-1, i-1 ) ) ) ;
+ // theSum -= sum( LU( i, Range( ii-1, i-1 ) )*B( Range( ii-1, i-1 ) ) ) ;
+ } else if( theSum ) {
+ ii = i+1 ;
+ }
+ X( i ) = theSum ;
+ // B( i ) = theSum ;
+ }
+ // Backsubstitution :
+ for( int i=N-1; i>=0; i-- ) {
+ theSum = X( i ) ;
+ // theSum = B( i ) ;
+ theSum -= matrix_vector_product_sliced(LU, X, i, i+1, N) ;
+ // theSum -= sum( LU( i, Range( i+1, toEnd ) )*X( Range( i+1, toEnd ) ) ) ;
+ // theSum -= sum( LU( i, Range( i+1, toEnd ) )*B( Range( i+1, toEnd ) ) ) ;
+ // Store a component of the solution vector :
+ X( i ) = theSum/LU( i, i ) ;
+ // B( i ) = theSum/LU( i, i ) ;
+ }
+
+ }
+
+};
+
+#endif
diff --git a/bench/btl/libs/mtl4/mtl4_interface.hh b/bench/btl/libs/mtl4/mtl4_interface.hh
new file mode 100644
index 000000000..3795ac61e
--- /dev/null
+++ b/bench/btl/libs/mtl4/mtl4_interface.hh
@@ -0,0 +1,144 @@
+//=====================================================
+// Copyright (C) 2008 Gael Guennebaud <gael.guennebaud@inria.fr>
+//=====================================================
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+//
+#ifndef MTL4_INTERFACE_HH
+#define MTL4_INTERFACE_HH
+
+#include <boost/numeric/mtl/mtl.hpp>
+#include <boost/numeric/mtl/utility/range_generator.hpp>
+// #include <boost/numeric/mtl/operation/cholesky.hpp>
+#include <vector>
+
+using namespace mtl;
+
+template<class real>
+class mtl4_interface {
+
+public :
+
+ typedef real real_type ;
+
+ typedef std::vector<real> stl_vector;
+ typedef std::vector<stl_vector > stl_matrix;
+
+ typedef mtl::dense2D<real, mtl::matrix::parameters<mtl::tag::col_major> > gene_matrix;
+ typedef mtl::dense_vector<real> gene_vector;
+
+ static inline std::string name() { return "mtl4"; }
+
+ static void free_matrix(gene_matrix & A, int N){
+ return ;
+ }
+
+ static void free_vector(gene_vector & B){
+ return ;
+ }
+
+ static inline void matrix_from_stl(gene_matrix & A, stl_matrix & A_stl){
+ A.change_dim(A_stl[0].size(), A_stl.size());
+
+ for (int j=0; j<A_stl.size() ; j++){
+ for (int i=0; i<A_stl[j].size() ; i++){
+ A(i,j) = A_stl[j][i];
+ }
+ }
+ }
+
+ static inline void vector_from_stl(gene_vector & B, stl_vector & B_stl){
+ B.change_dim(B_stl.size());
+ for (int i=0; i<B_stl.size() ; i++){
+ B[i] = B_stl[i];
+ }
+ }
+
+ static inline void vector_to_stl(gene_vector & B, stl_vector & B_stl){
+ for (int i=0; i<B_stl.size() ; i++){
+ B_stl[i] = B[i];
+ }
+ }
+
+ static inline void matrix_to_stl(gene_matrix & A, stl_matrix & A_stl){
+ int N=A_stl.size();
+ for (int j=0;j<N;j++){
+ A_stl[j].resize(N);
+ for (int i=0;i<N;i++){
+ A_stl[j][i] = A(i,j);
+ }
+ }
+ }
+
+ static inline void matrix_matrix_product(const gene_matrix & A, const gene_matrix & B, gene_matrix & X, int N){
+ X = (A*B);
+// morton_dense<double, doppled_64_row_mask> C(N,N);
+// C = B;
+// X = (A*C);
+ }
+
+ static inline void transposed_matrix_matrix_product(const gene_matrix & A, const gene_matrix & B, gene_matrix & X, int N){
+ X = (trans(A)*trans(B));
+ }
+
+// static inline void ata_product(const gene_matrix & A, gene_matrix & X, int N){
+// X = (trans(A)*A);
+// }
+
+ static inline void aat_product(const gene_matrix & A, gene_matrix & X, int N){
+ X = (A*trans(A));
+ }
+
+ static inline void matrix_vector_product(gene_matrix & A, gene_vector & B, gene_vector & X, int N){
+ X = (A*B);
+ }
+
+ static inline void atv_product(gene_matrix & A, gene_vector & B, gene_vector & X, int N){
+ X = (trans(A)*B);
+ }
+
+ static inline void axpy(const real coef, const gene_vector & X, gene_vector & Y, int N){
+ Y += coef * X;
+ }
+
+ static inline void axpby(real a, const gene_vector & X, real b, gene_vector & Y, int N){
+ Y = a*X + b*Y;
+ }
+
+// static inline void cholesky(const gene_matrix & X, gene_matrix & C, int N){
+// C = X;
+// recursive_cholesky(C);
+// }
+
+// static inline void lu_decomp(const gene_matrix & X, gene_matrix & R, int N){
+// R = X;
+// std::vector<int> ipvt(N);
+// lu_factor(R, ipvt);
+// }
+
+ static inline void trisolve_lower(const gene_matrix & L, const gene_vector& B, gene_vector & X, int N){
+ X = lower_trisolve(L, B);
+ }
+
+ static inline void copy_matrix(const gene_matrix & source, gene_matrix & cible, int N){
+ cible = source;
+ }
+
+ static inline void copy_vector(const gene_vector & source, gene_vector & cible, int N){
+ cible = source;
+ }
+
+};
+
+#endif
diff --git a/bench/btl/libs/tvmet/CMakeLists.txt b/bench/btl/libs/tvmet/CMakeLists.txt
new file mode 100644
index 000000000..25b565b97
--- /dev/null
+++ b/bench/btl/libs/tvmet/CMakeLists.txt
@@ -0,0 +1,6 @@
+
+find_package(Tvmet)
+if (TVMET_FOUND)
+ include_directories(${TVMET_INCLUDE_DIR})
+ btl_add_bench(btl_tvmet main.cpp OFF)
+endif (TVMET_FOUND)
diff --git a/bench/btl/libs/tvmet/main.cpp b/bench/btl/libs/tvmet/main.cpp
new file mode 100644
index 000000000..633215c43
--- /dev/null
+++ b/bench/btl/libs/tvmet/main.cpp
@@ -0,0 +1,40 @@
+//=====================================================
+// File : main.cpp
+// Author : L. Plagne <laurent.plagne@edf.fr)>
+// Copyright (C) EDF R&D, lun sep 30 14:23:30 CEST 2002
+//=====================================================
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+//
+#include "utilities.h"
+#include "tvmet_interface.hh"
+#include "static/bench_static.hh"
+#include "action_matrix_vector_product.hh"
+#include "action_matrix_matrix_product.hh"
+#include "action_atv_product.hh"
+#include "action_axpy.hh"
+
+BTL_MAIN;
+
+int main()
+{
+ bench_static<Action_axpy,tvmet_interface>();
+ bench_static<Action_matrix_matrix_product,tvmet_interface>();
+ bench_static<Action_matrix_vector_product,tvmet_interface>();
+ bench_static<Action_atv_product,tvmet_interface>();
+
+ return 0;
+}
+
+
diff --git a/bench/btl/libs/tvmet/tvmet_interface.hh b/bench/btl/libs/tvmet/tvmet_interface.hh
new file mode 100644
index 000000000..b441ada21
--- /dev/null
+++ b/bench/btl/libs/tvmet/tvmet_interface.hh
@@ -0,0 +1,104 @@
+//=====================================================
+// File : tvmet_interface.hh
+// Author : L. Plagne <laurent.plagne@edf.fr)>
+// Copyright (C) EDF R&D, lun sep 30 14:23:30 CEST 2002
+//=====================================================
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+//
+#ifndef TVMET_INTERFACE_HH
+#define TVMET_INTERFACE_HH
+
+#include <tvmet/tvmet.h>
+#include <tvmet/Vector.h>
+#include <tvmet/Matrix.h>
+
+#include <vector>
+
+using namespace tvmet;
+
+template<class real, int SIZE>
+class tvmet_interface{
+
+public :
+
+ typedef real real_type ;
+
+ typedef std::vector<real> stl_vector;
+ typedef std::vector<stl_vector > stl_matrix;
+
+ typedef Vector<real,SIZE> gene_vector;
+ typedef Matrix<real,SIZE,SIZE> gene_matrix;
+
+ static inline std::string name() { return "tiny_tvmet"; }
+
+ static void free_matrix(gene_matrix & A, int N){}
+
+ static void free_vector(gene_vector & B){}
+
+ static inline void matrix_from_stl(gene_matrix & A, stl_matrix & A_stl){
+ for (int j=0; j<A_stl.size() ; j++)
+ for (int i=0; i<A_stl[j].size() ; i++)
+ A(i,j) = A_stl[j][i];
+ }
+
+ static inline void vector_from_stl(gene_vector & B, stl_vector & B_stl){
+ for (int i=0; i<B_stl.size() ; i++)
+ B[i]=B_stl[i];
+ }
+
+ static inline void vector_to_stl(gene_vector & B, stl_vector & B_stl){
+ for (int i=0; i<B_stl.size() ; i++){
+ B_stl[i]=B[i];
+ }
+ }
+
+ static inline void matrix_to_stl(gene_matrix & A, stl_matrix & A_stl){
+ int N = A_stl.size();
+ for (int j=0;j<N;j++){
+ A_stl[j].resize(N);
+ for (int i=0;i<N;i++)
+ A_stl[j][i] = A(i,j);
+ }
+ }
+
+
+ static inline void copy_matrix(const gene_matrix & source, gene_matrix & cible, int N){
+ cible = source;
+ }
+
+ static inline void copy_vector(const gene_vector & source, gene_vector & cible, int N){
+ cible = source;
+ }
+
+ static inline void matrix_matrix_product(const gene_matrix & A, const gene_matrix & B, gene_matrix & X, int N){
+ X = prod(A,B);
+ }
+
+ static inline void matrix_vector_product(gene_matrix & A, gene_vector & B, gene_vector & X, int N){
+ X = prod(A,B);
+ }
+
+ static inline void atv_product(gene_matrix & A, gene_vector & B, gene_vector & X, int N){
+ X = prod(trans(A),B);
+ }
+
+ static inline void axpy(const real coef, const gene_vector & X, gene_vector & Y, int N){
+ Y+=coef*X;
+ }
+
+};
+
+
+#endif
diff --git a/bench/btl/libs/ublas/CMakeLists.txt b/bench/btl/libs/ublas/CMakeLists.txt
new file mode 100644
index 000000000..bdb58bea1
--- /dev/null
+++ b/bench/btl/libs/ublas/CMakeLists.txt
@@ -0,0 +1,7 @@
+
+find_package(Boost)
+if (Boost_FOUND)
+ include_directories(${Boost_INCLUDE_DIRS})
+ include_directories(${Boost_INCLUDES})
+ btl_add_bench(btl_ublas main.cpp)
+endif (Boost_FOUND)
diff --git a/bench/btl/libs/ublas/main.cpp b/bench/btl/libs/ublas/main.cpp
new file mode 100644
index 000000000..e2e77ee1f
--- /dev/null
+++ b/bench/btl/libs/ublas/main.cpp
@@ -0,0 +1,44 @@
+//=====================================================
+// File : main.cpp
+// Author : L. Plagne <laurent.plagne@edf.fr)>
+// Copyright (C) EDF R&D, lun sep 30 14:23:27 CEST 2002
+//=====================================================
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+//
+#include "utilities.h"
+#include "ublas_interface.hh"
+#include "bench.hh"
+#include "basic_actions.hh"
+
+BTL_MAIN;
+
+int main()
+{
+ bench<Action_axpy<ublas_interface<REAL_TYPE> > >(MIN_AXPY,MAX_AXPY,NB_POINT);
+ bench<Action_axpby<ublas_interface<REAL_TYPE> > >(MIN_AXPY,MAX_AXPY,NB_POINT);
+
+ bench<Action_matrix_vector_product<ublas_interface<REAL_TYPE> > >(MIN_MV,MAX_MV,NB_POINT);
+ bench<Action_atv_product<ublas_interface<REAL_TYPE> > >(MIN_MV,MAX_MV,NB_POINT);
+
+ bench<Action_matrix_matrix_product<ublas_interface<REAL_TYPE> > >(MIN_MM,MAX_MM,NB_POINT);
+// bench<Action_ata_product<ublas_interface<REAL_TYPE> > >(MIN_MM,MAX_MM,NB_POINT);
+// bench<Action_aat_product<ublas_interface<REAL_TYPE> > >(MIN_MM,MAX_MM,NB_POINT);
+
+ bench<Action_trisolve<ublas_interface<REAL_TYPE> > >(MIN_MM,MAX_MM,NB_POINT);
+
+ return 0;
+}
+
+
diff --git a/bench/btl/libs/ublas/ublas_interface.hh b/bench/btl/libs/ublas/ublas_interface.hh
new file mode 100644
index 000000000..95cad5195
--- /dev/null
+++ b/bench/btl/libs/ublas/ublas_interface.hh
@@ -0,0 +1,141 @@
+//=====================================================
+// File : ublas_interface.hh
+// Author : L. Plagne <laurent.plagne@edf.fr)>
+// Copyright (C) EDF R&D, lun sep 30 14:23:27 CEST 2002
+//=====================================================
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+//
+#ifndef UBLAS_INTERFACE_HH
+#define UBLAS_INTERFACE_HH
+
+#include <boost/numeric/ublas/vector.hpp>
+#include <boost/numeric/ublas/matrix.hpp>
+#include <boost/numeric/ublas/io.hpp>
+#include <boost/numeric/ublas/triangular.hpp>
+
+using namespace boost::numeric;
+
+template <class real>
+class ublas_interface{
+
+public :
+
+ typedef real real_type ;
+
+ typedef std::vector<real> stl_vector;
+ typedef std::vector<stl_vector> stl_matrix;
+
+ typedef typename boost::numeric::ublas::matrix<real,boost::numeric::ublas::column_major> gene_matrix;
+ typedef typename boost::numeric::ublas::vector<real> gene_vector;
+
+ static inline std::string name( void ) { return "ublas"; }
+
+ static void free_matrix(gene_matrix & A, int N) {}
+
+ static void free_vector(gene_vector & B) {}
+
+ static inline void matrix_from_stl(gene_matrix & A, stl_matrix & A_stl){
+ A.resize(A_stl.size(),A_stl[0].size());
+ for (int j=0; j<A_stl.size() ; j++)
+ for (int i=0; i<A_stl[j].size() ; i++)
+ A(i,j)=A_stl[j][i];
+ }
+
+ static inline void vector_from_stl(gene_vector & B, stl_vector & B_stl){
+ B.resize(B_stl.size());
+ for (int i=0; i<B_stl.size() ; i++)
+ B(i)=B_stl[i];
+ }
+
+ static inline void vector_to_stl(gene_vector & B, stl_vector & B_stl){
+ for (int i=0; i<B_stl.size() ; i++)
+ B_stl[i]=B(i);
+ }
+
+ static inline void matrix_to_stl(gene_matrix & A, stl_matrix & A_stl){
+ int N=A_stl.size();
+ for (int j=0;j<N;j++)
+ {
+ A_stl[j].resize(N);
+ for (int i=0;i<N;i++)
+ A_stl[j][i]=A(i,j);
+ }
+ }
+
+ static inline void copy_vector(const gene_vector & source, gene_vector & cible, int N){
+ for (int i=0;i<N;i++){
+ cible(i) = source(i);
+ }
+ }
+
+ static inline void copy_matrix(const gene_matrix & source, gene_matrix & cible, int N){
+ for (int i=0;i<N;i++){
+ for (int j=0;j<N;j++){
+ cible(i,j) = source(i,j);
+ }
+ }
+ }
+
+ static inline void matrix_vector_product_slow(gene_matrix & A, gene_vector & B, gene_vector & X, int N){
+ X = prod(A,B);
+ }
+
+ static inline void matrix_matrix_product_slow(gene_matrix & A, gene_matrix & B, gene_matrix & X, int N){
+ X = prod(A,B);
+ }
+
+ static inline void axpy_slow(const real coef, const gene_vector & X, gene_vector & Y, int N){
+ Y+=coef*X;
+ }
+
+ // alias free assignements
+
+ static inline void matrix_vector_product(gene_matrix & A, gene_vector & B, gene_vector & X, int N){
+ X.assign(prod(A,B));
+ }
+
+ static inline void atv_product(gene_matrix & A, gene_vector & B, gene_vector & X, int N){
+ X.assign(prod(trans(A),B));
+ }
+
+ static inline void matrix_matrix_product(gene_matrix & A, gene_matrix & B, gene_matrix & X, int N){
+ X.assign(prod(A,B));
+ }
+
+ static inline void axpy(const real coef, const gene_vector & X, gene_vector & Y, int N){
+ Y.plus_assign(coef*X);
+ }
+
+ static inline void axpby(real a, const gene_vector & X, real b, gene_vector & Y, int N){
+ Y = a*X + b*Y;
+ }
+
+ static inline void ata_product(gene_matrix & A, gene_matrix & X, int N){
+ // X = prod(trans(A),A);
+ X.assign(prod(trans(A),A));
+ }
+
+ static inline void aat_product(gene_matrix & A, gene_matrix & X, int N){
+ // X = prod(A,trans(A));
+ X.assign(prod(A,trans(A)));
+ }
+
+ static inline void trisolve_lower(const gene_matrix & L, const gene_vector& B, gene_vector & X, int N){
+ X = solve(L, B, ublas::lower_tag ());
+ }
+
+};
+
+#endif
diff --git a/bench/check_cache_queries.cpp b/bench/check_cache_queries.cpp
new file mode 100644
index 000000000..029d44cf6
--- /dev/null
+++ b/bench/check_cache_queries.cpp
@@ -0,0 +1,101 @@
+
+#define EIGEN_INTERNAL_DEBUG_CACHE_QUERY
+#include <iostream>
+#include "../Eigen/Core"
+
+using namespace Eigen;
+using namespace std;
+
+#define DUMP_CPUID(CODE) {\
+ int abcd[4]; \
+ abcd[0] = abcd[1] = abcd[2] = abcd[3] = 0;\
+ EIGEN_CPUID(abcd, CODE, 0); \
+ std::cout << "The code " << CODE << " gives " \
+ << (int*)(abcd[0]) << " " << (int*)(abcd[1]) << " " \
+ << (int*)(abcd[2]) << " " << (int*)(abcd[3]) << " " << std::endl; \
+ }
+
+int main()
+{
+ cout << "Eigen's L1 = " << internal::queryL1CacheSize() << endl;
+ cout << "Eigen's L2/L3 = " << internal::queryTopLevelCacheSize() << endl;
+ int l1, l2, l3;
+ internal::queryCacheSizes(l1, l2, l3);
+ cout << "Eigen's L1, L2, L3 = " << l1 << " " << l2 << " " << l3 << endl;
+
+ #ifdef EIGEN_CPUID
+
+ int abcd[4];
+ int string[8];
+ char* string_char = (char*)(string);
+
+ // vendor ID
+ EIGEN_CPUID(abcd,0x0,0);
+ string[0] = abcd[1];
+ string[1] = abcd[3];
+ string[2] = abcd[2];
+ string[3] = 0;
+ cout << endl;
+ cout << "vendor id = " << string_char << endl;
+ cout << endl;
+ int max_funcs = abcd[0];
+
+ internal::queryCacheSizes_intel_codes(l1, l2, l3);
+ cout << "Eigen's intel codes L1, L2, L3 = " << l1 << " " << l2 << " " << l3 << endl;
+ if(max_funcs>=4)
+ {
+ internal::queryCacheSizes_intel_direct(l1, l2, l3);
+ cout << "Eigen's intel direct L1, L2, L3 = " << l1 << " " << l2 << " " << l3 << endl;
+ }
+ internal::queryCacheSizes_amd(l1, l2, l3);
+ cout << "Eigen's amd L1, L2, L3 = " << l1 << " " << l2 << " " << l3 << endl;
+ cout << endl;
+
+ // dump Intel direct method
+ if(max_funcs>=4)
+ {
+ l1 = l2 = l3 = 0;
+ int cache_id = 0;
+ int cache_type = 0;
+ do {
+ abcd[0] = abcd[1] = abcd[2] = abcd[3] = 0;
+ EIGEN_CPUID(abcd,0x4,cache_id);
+ cache_type = (abcd[0] & 0x0F) >> 0;
+ int cache_level = (abcd[0] & 0xE0) >> 5; // A[7:5]
+ int ways = (abcd[1] & 0xFFC00000) >> 22; // B[31:22]
+ int partitions = (abcd[1] & 0x003FF000) >> 12; // B[21:12]
+ int line_size = (abcd[1] & 0x00000FFF) >> 0; // B[11:0]
+ int sets = (abcd[2]); // C[31:0]
+ int cache_size = (ways+1) * (partitions+1) * (line_size+1) * (sets+1);
+
+ cout << "cache[" << cache_id << "].type = " << cache_type << "\n";
+ cout << "cache[" << cache_id << "].level = " << cache_level << "\n";
+ cout << "cache[" << cache_id << "].ways = " << ways << "\n";
+ cout << "cache[" << cache_id << "].partitions = " << partitions << "\n";
+ cout << "cache[" << cache_id << "].line_size = " << line_size << "\n";
+ cout << "cache[" << cache_id << "].sets = " << sets << "\n";
+ cout << "cache[" << cache_id << "].size = " << cache_size << "\n";
+
+ cache_id++;
+ } while(cache_type>0 && cache_id<16);
+ }
+
+ // dump everything
+ std::cout << endl <<"Raw dump:" << endl;
+ for(int i=0; i<max_funcs; ++i)
+ DUMP_CPUID(i);
+
+ DUMP_CPUID(0x80000000);
+ DUMP_CPUID(0x80000001);
+ DUMP_CPUID(0x80000002);
+ DUMP_CPUID(0x80000003);
+ DUMP_CPUID(0x80000004);
+ DUMP_CPUID(0x80000005);
+ DUMP_CPUID(0x80000006);
+ DUMP_CPUID(0x80000007);
+ DUMP_CPUID(0x80000008);
+ #else
+ cout << "EIGEN_CPUID is not defined" << endl;
+ #endif
+ return 0;
+}
diff --git a/bench/eig33.cpp b/bench/eig33.cpp
new file mode 100644
index 000000000..1608b999d
--- /dev/null
+++ b/bench/eig33.cpp
@@ -0,0 +1,196 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra.
+//
+// Copyright (C) 2010 Gael Guennebaud <gael.guennebaud@inria.fr>
+//
+// This Source Code Form is subject to the terms of the Mozilla
+// Public License v. 2.0. If a copy of the MPL was not distributed
+// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+// The computeRoots function included in this is based on materials
+// covered by the following copyright and license:
+//
+// Geometric Tools, LLC
+// Copyright (c) 1998-2010
+// Distributed under the Boost Software License, Version 1.0.
+//
+// Permission is hereby granted, free of charge, to any person or organization
+// obtaining a copy of the software and accompanying documentation covered by
+// this license (the "Software") to use, reproduce, display, distribute,
+// execute, and transmit the Software, and to prepare derivative works of the
+// Software, and to permit third-parties to whom the Software is furnished to
+// do so, all subject to the following:
+//
+// The copyright notices in the Software and this entire statement, including
+// the above license grant, this restriction and the following disclaimer,
+// must be included in all copies of the Software, in whole or in part, and
+// all derivative works of the Software, unless such copies or derivative
+// works are solely in the form of machine-executable object code generated by
+// a source language processor.
+//
+// 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, TITLE AND NON-INFRINGEMENT. IN NO EVENT
+// SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
+// FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
+// ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+// DEALINGS IN THE SOFTWARE.
+
+#include <iostream>
+#include <Eigen/Core>
+#include <Eigen/Eigenvalues>
+#include <Eigen/Geometry>
+#include <bench/BenchTimer.h>
+
+using namespace Eigen;
+using namespace std;
+
+template<typename Matrix, typename Roots>
+inline void computeRoots(const Matrix& m, Roots& roots)
+{
+ typedef typename Matrix::Scalar Scalar;
+ const Scalar s_inv3 = 1.0/3.0;
+ const Scalar s_sqrt3 = internal::sqrt(Scalar(3.0));
+
+ // The characteristic equation is x^3 - c2*x^2 + c1*x - c0 = 0. The
+ // eigenvalues are the roots to this equation, all guaranteed to be
+ // real-valued, because the matrix is symmetric.
+ Scalar c0 = m(0,0)*m(1,1)*m(2,2) + Scalar(2)*m(0,1)*m(0,2)*m(1,2) - m(0,0)*m(1,2)*m(1,2) - m(1,1)*m(0,2)*m(0,2) - m(2,2)*m(0,1)*m(0,1);
+ Scalar c1 = m(0,0)*m(1,1) - m(0,1)*m(0,1) + m(0,0)*m(2,2) - m(0,2)*m(0,2) + m(1,1)*m(2,2) - m(1,2)*m(1,2);
+ Scalar c2 = m(0,0) + m(1,1) + m(2,2);
+
+ // Construct the parameters used in classifying the roots of the equation
+ // and in solving the equation for the roots in closed form.
+ Scalar c2_over_3 = c2*s_inv3;
+ Scalar a_over_3 = (c1 - c2*c2_over_3)*s_inv3;
+ if (a_over_3 > Scalar(0))
+ a_over_3 = Scalar(0);
+
+ Scalar half_b = Scalar(0.5)*(c0 + c2_over_3*(Scalar(2)*c2_over_3*c2_over_3 - c1));
+
+ Scalar q = half_b*half_b + a_over_3*a_over_3*a_over_3;
+ if (q > Scalar(0))
+ q = Scalar(0);
+
+ // Compute the eigenvalues by solving for the roots of the polynomial.
+ Scalar rho = internal::sqrt(-a_over_3);
+ Scalar theta = std::atan2(internal::sqrt(-q),half_b)*s_inv3;
+ Scalar cos_theta = internal::cos(theta);
+ Scalar sin_theta = internal::sin(theta);
+ roots(0) = c2_over_3 + Scalar(2)*rho*cos_theta;
+ roots(1) = c2_over_3 - rho*(cos_theta + s_sqrt3*sin_theta);
+ roots(2) = c2_over_3 - rho*(cos_theta - s_sqrt3*sin_theta);
+
+ // Sort in increasing order.
+ if (roots(0) >= roots(1))
+ std::swap(roots(0),roots(1));
+ if (roots(1) >= roots(2))
+ {
+ std::swap(roots(1),roots(2));
+ if (roots(0) >= roots(1))
+ std::swap(roots(0),roots(1));
+ }
+}
+
+template<typename Matrix, typename Vector>
+void eigen33(const Matrix& mat, Matrix& evecs, Vector& evals)
+{
+ typedef typename Matrix::Scalar Scalar;
+ // Scale the matrix so its entries are in [-1,1]. The scaling is applied
+ // only when at least one matrix entry has magnitude larger than 1.
+
+ Scalar scale = mat.cwiseAbs()/*.template triangularView<Lower>()*/.maxCoeff();
+ scale = std::max(scale,Scalar(1));
+ Matrix scaledMat = mat / scale;
+
+ // Compute the eigenvalues
+// scaledMat.setZero();
+ computeRoots(scaledMat,evals);
+
+ // compute the eigen vectors
+ // **here we assume 3 differents eigenvalues**
+
+ // "optimized version" which appears to be slower with gcc!
+// Vector base;
+// Scalar alpha, beta;
+// base << scaledMat(1,0) * scaledMat(2,1),
+// scaledMat(1,0) * scaledMat(2,0),
+// -scaledMat(1,0) * scaledMat(1,0);
+// for(int k=0; k<2; ++k)
+// {
+// alpha = scaledMat(0,0) - evals(k);
+// beta = scaledMat(1,1) - evals(k);
+// evecs.col(k) = (base + Vector(-beta*scaledMat(2,0), -alpha*scaledMat(2,1), alpha*beta)).normalized();
+// }
+// evecs.col(2) = evecs.col(0).cross(evecs.col(1)).normalized();
+
+// // naive version
+// Matrix tmp;
+// tmp = scaledMat;
+// tmp.diagonal().array() -= evals(0);
+// evecs.col(0) = tmp.row(0).cross(tmp.row(1)).normalized();
+//
+// tmp = scaledMat;
+// tmp.diagonal().array() -= evals(1);
+// evecs.col(1) = tmp.row(0).cross(tmp.row(1)).normalized();
+//
+// tmp = scaledMat;
+// tmp.diagonal().array() -= evals(2);
+// evecs.col(2) = tmp.row(0).cross(tmp.row(1)).normalized();
+
+ // a more stable version:
+ if((evals(2)-evals(0))<=Eigen::NumTraits<Scalar>::epsilon())
+ {
+ evecs.setIdentity();
+ }
+ else
+ {
+ Matrix tmp;
+ tmp = scaledMat;
+ tmp.diagonal ().array () -= evals (2);
+ evecs.col (2) = tmp.row (0).cross (tmp.row (1)).normalized ();
+
+ tmp = scaledMat;
+ tmp.diagonal ().array () -= evals (1);
+ evecs.col(1) = tmp.row (0).cross(tmp.row (1));
+ Scalar n1 = evecs.col(1).norm();
+ if(n1<=Eigen::NumTraits<Scalar>::epsilon())
+ evecs.col(1) = evecs.col(2).unitOrthogonal();
+ else
+ evecs.col(1) /= n1;
+
+ // make sure that evecs[1] is orthogonal to evecs[2]
+ evecs.col(1) = evecs.col(2).cross(evecs.col(1).cross(evecs.col(2))).normalized();
+ evecs.col(0) = evecs.col(2).cross(evecs.col(1));
+ }
+
+ // Rescale back to the original size.
+ evals *= scale;
+}
+
+int main()
+{
+ BenchTimer t;
+ int tries = 10;
+ int rep = 400000;
+ typedef Matrix3f Mat;
+ typedef Vector3f Vec;
+ Mat A = Mat::Random(3,3);
+ A = A.adjoint() * A;
+
+ SelfAdjointEigenSolver<Mat> eig(A);
+ BENCH(t, tries, rep, eig.compute(A));
+ std::cout << "Eigen: " << t.best() << "s\n";
+
+ Mat evecs;
+ Vec evals;
+ BENCH(t, tries, rep, eigen33(A,evecs,evals));
+ std::cout << "Direct: " << t.best() << "s\n\n";
+
+ std::cerr << "Eigenvalue/eigenvector diffs:\n";
+ std::cerr << (evals - eig.eigenvalues()).transpose() << "\n";
+ for(int k=0;k<3;++k)
+ if(evecs.col(k).dot(eig.eigenvectors().col(k))<0)
+ evecs.col(k) = -evecs.col(k);
+ std::cerr << evecs - eig.eigenvectors() << "\n\n";
+}
diff --git a/bench/geometry.cpp b/bench/geometry.cpp
new file mode 100644
index 000000000..b187a515f
--- /dev/null
+++ b/bench/geometry.cpp
@@ -0,0 +1,126 @@
+
+#include <iostream>
+#include <Eigen/Geometry>
+#include <bench/BenchTimer.h>
+
+using namespace std;
+using namespace Eigen;
+
+#ifndef SCALAR
+#define SCALAR float
+#endif
+
+#ifndef SIZE
+#define SIZE 8
+#endif
+
+typedef SCALAR Scalar;
+typedef NumTraits<Scalar>::Real RealScalar;
+typedef Matrix<RealScalar,Dynamic,Dynamic> A;
+typedef Matrix</*Real*/Scalar,Dynamic,Dynamic> B;
+typedef Matrix<Scalar,Dynamic,Dynamic> C;
+typedef Matrix<RealScalar,Dynamic,Dynamic> M;
+
+template<typename Transformation, typename Data>
+EIGEN_DONT_INLINE void transform(const Transformation& t, Data& data)
+{
+ EIGEN_ASM_COMMENT("begin");
+ data = t * data;
+ EIGEN_ASM_COMMENT("end");
+}
+
+template<typename Scalar, typename Data>
+EIGEN_DONT_INLINE void transform(const Quaternion<Scalar>& t, Data& data)
+{
+ EIGEN_ASM_COMMENT("begin quat");
+ for(int i=0;i<data.cols();++i)
+ data.col(i) = t * data.col(i);
+ EIGEN_ASM_COMMENT("end quat");
+}
+
+template<typename T> struct ToRotationMatrixWrapper
+{
+ enum {Dim = T::Dim};
+ typedef typename T::Scalar Scalar;
+ ToRotationMatrixWrapper(const T& o) : object(o) {}
+ T object;
+};
+
+template<typename QType, typename Data>
+EIGEN_DONT_INLINE void transform(const ToRotationMatrixWrapper<QType>& t, Data& data)
+{
+ EIGEN_ASM_COMMENT("begin quat via mat");
+ data = t.object.toRotationMatrix() * data;
+ EIGEN_ASM_COMMENT("end quat via mat");
+}
+
+template<typename Scalar, int Dim, typename Data>
+EIGEN_DONT_INLINE void transform(const Transform<Scalar,Dim,Projective>& t, Data& data)
+{
+ data = (t * data.colwise().homogeneous()).template block<Dim,Data::ColsAtCompileTime>(0,0);
+}
+
+template<typename T> struct get_dim { enum { Dim = T::Dim }; };
+template<typename S, int R, int C, int O, int MR, int MC>
+struct get_dim<Matrix<S,R,C,O,MR,MC> > { enum { Dim = R }; };
+
+template<typename Transformation, int N>
+struct bench_impl
+{
+ static EIGEN_DONT_INLINE void run(const Transformation& t)
+ {
+ Matrix<typename Transformation::Scalar,get_dim<Transformation>::Dim,N> data;
+ data.setRandom();
+ bench_impl<Transformation,N-1>::run(t);
+ BenchTimer timer;
+ BENCH(timer,10,100000,transform(t,data));
+ cout.width(9);
+ cout << timer.best() << " ";
+ }
+};
+
+
+template<typename Transformation>
+struct bench_impl<Transformation,0>
+{
+ static EIGEN_DONT_INLINE void run(const Transformation&) {}
+};
+
+template<typename Transformation>
+EIGEN_DONT_INLINE void bench(const std::string& msg, const Transformation& t)
+{
+ cout << msg << " ";
+ bench_impl<Transformation,SIZE>::run(t);
+ std::cout << "\n";
+}
+
+int main(int argc, char ** argv)
+{
+ Matrix<Scalar,3,4> mat34; mat34.setRandom();
+ Transform<Scalar,3,Isometry> iso3(mat34);
+ Transform<Scalar,3,Affine> aff3(mat34);
+ Transform<Scalar,3,AffineCompact> caff3(mat34);
+ Transform<Scalar,3,Projective> proj3(mat34);
+ Quaternion<Scalar> quat;quat.setIdentity();
+ ToRotationMatrixWrapper<Quaternion<Scalar> > quatmat(quat);
+ Matrix<Scalar,3,3> mat33; mat33.setRandom();
+
+ cout.precision(4);
+ std::cout
+ << "N ";
+ for(int i=0;i<SIZE;++i)
+ {
+ cout.width(9);
+ cout << i+1 << " ";
+ }
+ cout << "\n";
+
+ bench("matrix 3x3", mat33);
+ bench("quaternion", quat);
+ bench("quat-mat ", quatmat);
+ bench("isometry3 ", iso3);
+ bench("affine3 ", aff3);
+ bench("c affine3 ", caff3);
+ bench("proj3 ", proj3);
+}
+
diff --git a/bench/product_threshold.cpp b/bench/product_threshold.cpp
new file mode 100644
index 000000000..dd6d15a07
--- /dev/null
+++ b/bench/product_threshold.cpp
@@ -0,0 +1,143 @@
+
+#include <iostream>
+#include <Eigen/Core>
+#include <bench/BenchTimer.h>
+
+using namespace Eigen;
+using namespace std;
+
+#define END 9
+
+template<int S> struct map_size { enum { ret = S }; };
+template<> struct map_size<10> { enum { ret = 20 }; };
+template<> struct map_size<11> { enum { ret = 50 }; };
+template<> struct map_size<12> { enum { ret = 100 }; };
+template<> struct map_size<13> { enum { ret = 300 }; };
+
+template<int M, int N,int K> struct alt_prod
+{
+ enum {
+ ret = M==1 && N==1 ? InnerProduct
+ : K==1 ? OuterProduct
+ : M==1 ? GemvProduct
+ : N==1 ? GemvProduct
+ : GemmProduct
+ };
+};
+
+void print_mode(int mode)
+{
+ if(mode==InnerProduct) std::cout << "i";
+ if(mode==OuterProduct) std::cout << "o";
+ if(mode==CoeffBasedProductMode) std::cout << "c";
+ if(mode==LazyCoeffBasedProductMode) std::cout << "l";
+ if(mode==GemvProduct) std::cout << "v";
+ if(mode==GemmProduct) std::cout << "m";
+}
+
+template<int Mode, typename Lhs, typename Rhs, typename Res>
+EIGEN_DONT_INLINE void prod(const Lhs& a, const Rhs& b, Res& c)
+{
+ c.noalias() += typename ProductReturnType<Lhs,Rhs,Mode>::Type(a,b);
+}
+
+template<int M, int N, int K, typename Scalar, int Mode>
+EIGEN_DONT_INLINE void bench_prod()
+{
+ typedef Matrix<Scalar,M,K> Lhs; Lhs a; a.setRandom();
+ typedef Matrix<Scalar,K,N> Rhs; Rhs b; b.setRandom();
+ typedef Matrix<Scalar,M,N> Res; Res c; c.setRandom();
+
+ BenchTimer t;
+ double n = 2.*double(M)*double(N)*double(K);
+ int rep = 100000./n;
+ rep /= 2;
+ if(rep<1) rep = 1;
+ do {
+ rep *= 2;
+ t.reset();
+ BENCH(t,1,rep,prod<CoeffBasedProductMode>(a,b,c));
+ } while(t.best()<0.1);
+
+ t.reset();
+ BENCH(t,5,rep,prod<Mode>(a,b,c));
+
+ print_mode(Mode);
+ std::cout << int(1e-6*n*rep/t.best()) << "\t";
+}
+
+template<int N> struct print_n;
+template<int M, int N, int K> struct loop_on_m;
+template<int M, int N, int K, typename Scalar, int Mode> struct loop_on_n;
+
+template<int M, int N, int K>
+struct loop_on_k
+{
+ static void run()
+ {
+ std::cout << "K=" << K << "\t";
+ print_n<N>::run();
+ std::cout << "\n";
+
+ loop_on_m<M,N,K>::run();
+ std::cout << "\n\n";
+
+ loop_on_k<M,N,K+1>::run();
+ }
+};
+
+template<int M, int N>
+struct loop_on_k<M,N,END> { static void run(){} };
+
+
+template<int M, int N, int K>
+struct loop_on_m
+{
+ static void run()
+ {
+ std::cout << M << "f\t";
+ loop_on_n<M,N,K,float,CoeffBasedProductMode>::run();
+ std::cout << "\n";
+
+ std::cout << M << "f\t";
+ loop_on_n<M,N,K,float,-1>::run();
+ std::cout << "\n";
+
+ loop_on_m<M+1,N,K>::run();
+ }
+};
+
+template<int N, int K>
+struct loop_on_m<END,N,K> { static void run(){} };
+
+template<int M, int N, int K, typename Scalar, int Mode>
+struct loop_on_n
+{
+ static void run()
+ {
+ bench_prod<M,N,K,Scalar,Mode==-1? alt_prod<M,N,K>::ret : Mode>();
+
+ loop_on_n<M,N+1,K,Scalar,Mode>::run();
+ }
+};
+
+template<int M, int K, typename Scalar, int Mode>
+struct loop_on_n<M,END,K,Scalar,Mode> { static void run(){} };
+
+template<int N> struct print_n
+{
+ static void run()
+ {
+ std::cout << map_size<N>::ret << "\t";
+ print_n<N+1>::run();
+ }
+};
+
+template<> struct print_n<END> { static void run(){} };
+
+int main()
+{
+ loop_on_k<1,1,1>::run();
+
+ return 0;
+}
diff --git a/bench/quat_slerp.cpp b/bench/quat_slerp.cpp
new file mode 100644
index 000000000..bffb3bf11
--- /dev/null
+++ b/bench/quat_slerp.cpp
@@ -0,0 +1,247 @@
+
+#include <iostream>
+#include <Eigen/Geometry>
+#include <bench/BenchTimer.h>
+using namespace Eigen;
+using namespace std;
+
+
+
+template<typename Q>
+EIGEN_DONT_INLINE Q nlerp(const Q& a, const Q& b, typename Q::Scalar t)
+{
+ return Q((a.coeffs() * (1.0-t) + b.coeffs() * t).normalized());
+}
+
+template<typename Q>
+EIGEN_DONT_INLINE Q slerp_eigen(const Q& a, const Q& b, typename Q::Scalar t)
+{
+ return a.slerp(t,b);
+}
+
+template<typename Q>
+EIGEN_DONT_INLINE Q slerp_legacy(const Q& a, const Q& b, typename Q::Scalar t)
+{
+ typedef typename Q::Scalar Scalar;
+ static const Scalar one = Scalar(1) - dummy_precision<Scalar>();
+ Scalar d = a.dot(b);
+ Scalar absD = internal::abs(d);
+ if (absD>=one)
+ return a;
+
+ // theta is the angle between the 2 quaternions
+ Scalar theta = std::acos(absD);
+ Scalar sinTheta = internal::sin(theta);
+
+ Scalar scale0 = internal::sin( ( Scalar(1) - t ) * theta) / sinTheta;
+ Scalar scale1 = internal::sin( ( t * theta) ) / sinTheta;
+ if (d<0)
+ scale1 = -scale1;
+
+ return Q(scale0 * a.coeffs() + scale1 * b.coeffs());
+}
+
+template<typename Q>
+EIGEN_DONT_INLINE Q slerp_legacy_nlerp(const Q& a, const Q& b, typename Q::Scalar t)
+{
+ typedef typename Q::Scalar Scalar;
+ static const Scalar one = Scalar(1) - epsilon<Scalar>();
+ Scalar d = a.dot(b);
+ Scalar absD = internal::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 = internal::sin(theta);
+
+ scale0 = internal::sin( ( Scalar(1) - t ) * theta) / sinTheta;
+ scale1 = internal::sin( ( t * theta) ) / sinTheta;
+ if (d<0)
+ scale1 = -scale1;
+ }
+
+ return Q(scale0 * a.coeffs() + scale1 * b.coeffs());
+}
+
+template<typename T>
+inline T sin_over_x(T x)
+{
+ if (T(1) + x*x == T(1))
+ return T(1);
+ else
+ return std::sin(x)/x;
+}
+
+template<typename Q>
+EIGEN_DONT_INLINE Q slerp_rw(const Q& a, const Q& b, typename Q::Scalar t)
+{
+ typedef typename Q::Scalar Scalar;
+
+ Scalar d = a.dot(b);
+ Scalar theta;
+ if (d<0.0)
+ theta = /*M_PI -*/ Scalar(2)*std::asin( (a.coeffs()+b.coeffs()).norm()/2 );
+ else
+ theta = Scalar(2)*std::asin( (a.coeffs()-b.coeffs()).norm()/2 );
+
+ // theta is the angle between the 2 quaternions
+// Scalar theta = std::acos(absD);
+ Scalar sinOverTheta = sin_over_x(theta);
+
+ Scalar scale0 = (Scalar(1)-t)*sin_over_x( ( Scalar(1) - t ) * theta) / sinOverTheta;
+ Scalar scale1 = t * sin_over_x( ( t * theta) ) / sinOverTheta;
+ if (d<0)
+ scale1 = -scale1;
+
+ return Quaternion<Scalar>(scale0 * a.coeffs() + scale1 * b.coeffs());
+}
+
+template<typename Q>
+EIGEN_DONT_INLINE Q slerp_gael(const Q& a, const Q& b, typename Q::Scalar t)
+{
+ typedef typename Q::Scalar Scalar;
+
+ Scalar d = a.dot(b);
+ Scalar theta;
+// theta = Scalar(2) * atan2((a.coeffs()-b.coeffs()).norm(),(a.coeffs()+b.coeffs()).norm());
+// if (d<0.0)
+// theta = M_PI-theta;
+
+ if (d<0.0)
+ theta = /*M_PI -*/ Scalar(2)*std::asin( (-a.coeffs()-b.coeffs()).norm()/2 );
+ else
+ theta = Scalar(2)*std::asin( (a.coeffs()-b.coeffs()).norm()/2 );
+
+
+ Scalar scale0;
+ Scalar scale1;
+ if(theta*theta-Scalar(6)==-Scalar(6))
+ {
+ scale0 = Scalar(1) - t;
+ scale1 = t;
+ }
+ else
+ {
+ Scalar sinTheta = std::sin(theta);
+ scale0 = internal::sin( ( Scalar(1) - t ) * theta) / sinTheta;
+ scale1 = internal::sin( ( t * theta) ) / sinTheta;
+ if (d<0)
+ scale1 = -scale1;
+ }
+
+ return Quaternion<Scalar>(scale0 * a.coeffs() + scale1 * b.coeffs());
+}
+
+int main()
+{
+ typedef double RefScalar;
+ typedef float TestScalar;
+
+ typedef Quaternion<RefScalar> Qd;
+ typedef Quaternion<TestScalar> Qf;
+
+ unsigned int g_seed = (unsigned int) time(NULL);
+ std::cout << g_seed << "\n";
+// g_seed = 1259932496;
+ srand(g_seed);
+
+ Matrix<RefScalar,Dynamic,1> maxerr(7);
+ maxerr.setZero();
+
+ Matrix<RefScalar,Dynamic,1> avgerr(7);
+ avgerr.setZero();
+
+ cout << "double=>float=>double nlerp eigen legacy(snap) legacy(nlerp) rightway gael's criteria\n";
+
+ int rep = 100;
+ int iters = 40;
+ for (int w=0; w<rep; ++w)
+ {
+ Qf a, b;
+ a.coeffs().setRandom();
+ a.normalize();
+ b.coeffs().setRandom();
+ b.normalize();
+
+ Qf c[6];
+
+ Qd ar(a.cast<RefScalar>());
+ Qd br(b.cast<RefScalar>());
+ Qd cr;
+
+
+
+ cout.precision(8);
+ cout << std::scientific;
+ for (int i=0; i<iters; ++i)
+ {
+ RefScalar t = 0.65;
+ cr = slerp_rw(ar,br,t);
+
+ Qf refc = cr.cast<TestScalar>();
+ c[0] = nlerp(a,b,t);
+ c[1] = slerp_eigen(a,b,t);
+ c[2] = slerp_legacy(a,b,t);
+ c[3] = slerp_legacy_nlerp(a,b,t);
+ c[4] = slerp_rw(a,b,t);
+ c[5] = slerp_gael(a,b,t);
+
+ VectorXd err(7);
+ err[0] = (cr.coeffs()-refc.cast<RefScalar>().coeffs()).norm();
+// std::cout << err[0] << " ";
+ for (int k=0; k<6; ++k)
+ {
+ err[k+1] = (c[k].coeffs()-refc.coeffs()).norm();
+// std::cout << err[k+1] << " ";
+ }
+ maxerr = maxerr.cwise().max(err);
+ avgerr += err;
+// std::cout << "\n";
+ b = cr.cast<TestScalar>();
+ br = cr;
+ }
+// std::cout << "\n";
+ }
+ avgerr /= RefScalar(rep*iters);
+ cout << "\n\nAccuracy:\n"
+ << " max: " << maxerr.transpose() << "\n";
+ cout << " avg: " << avgerr.transpose() << "\n";
+
+ // perf bench
+ Quaternionf a,b;
+ a.coeffs().setRandom();
+ a.normalize();
+ b.coeffs().setRandom();
+ b.normalize();
+ //b = a;
+ float s = 0.65;
+
+ #define BENCH(FUNC) {\
+ BenchTimer t; \
+ for(int k=0; k<2; ++k) {\
+ t.start(); \
+ for(int i=0; i<1000000; ++i) \
+ FUNC(a,b,s); \
+ t.stop(); \
+ } \
+ cout << " " << #FUNC << " => \t " << t.value() << "s\n"; \
+ }
+
+ cout << "\nSpeed:\n" << std::fixed;
+ BENCH(nlerp);
+ BENCH(slerp_eigen);
+ BENCH(slerp_legacy);
+ BENCH(slerp_legacy_nlerp);
+ BENCH(slerp_rw);
+ BENCH(slerp_gael);
+}
+
diff --git a/bench/quatmul.cpp b/bench/quatmul.cpp
new file mode 100644
index 000000000..8d9d7922c
--- /dev/null
+++ b/bench/quatmul.cpp
@@ -0,0 +1,47 @@
+#include <iostream>
+#include <Eigen/Core>
+#include <Eigen/Geometry>
+#include <bench/BenchTimer.h>
+
+using namespace Eigen;
+
+template<typename Quat>
+EIGEN_DONT_INLINE void quatmul_default(const Quat& a, const Quat& b, Quat& c)
+{
+ c = a * b;
+}
+
+template<typename Quat>
+EIGEN_DONT_INLINE void quatmul_novec(const Quat& a, const Quat& b, Quat& c)
+{
+ c = internal::quat_product<0, Quat, Quat, typename Quat::Scalar, Aligned>::run(a,b);
+}
+
+template<typename Quat> void bench(const std::string& label)
+{
+ int tries = 10;
+ int rep = 1000000;
+ BenchTimer t;
+
+ Quat a(4, 1, 2, 3);
+ Quat b(2, 3, 4, 5);
+ Quat c;
+
+ std::cout.precision(3);
+
+ BENCH(t, tries, rep, quatmul_default(a,b,c));
+ std::cout << label << " default " << 1e3*t.best(CPU_TIMER) << "ms \t" << 1e-6*double(rep)/(t.best(CPU_TIMER)) << " M mul/s\n";
+
+ BENCH(t, tries, rep, quatmul_novec(a,b,c));
+ std::cout << label << " novec " << 1e3*t.best(CPU_TIMER) << "ms \t" << 1e-6*double(rep)/(t.best(CPU_TIMER)) << " M mul/s\n";
+}
+
+int main()
+{
+ bench<Quaternionf>("float ");
+ bench<Quaterniond>("double");
+
+ return 0;
+
+}
+
diff --git a/bench/sparse_cholesky.cpp b/bench/sparse_cholesky.cpp
new file mode 100644
index 000000000..ecb226786
--- /dev/null
+++ b/bench/sparse_cholesky.cpp
@@ -0,0 +1,216 @@
+// #define EIGEN_TAUCS_SUPPORT
+// #define EIGEN_CHOLMOD_SUPPORT
+#include <iostream>
+#include <Eigen/Sparse>
+
+// g++ -DSIZE=10000 -DDENSITY=0.001 sparse_cholesky.cpp -I.. -DDENSEMATRI -O3 -g0 -DNDEBUG -DNBTRIES=1 -I /home/gael/Coding/LinearAlgebra/taucs_full/src/ -I/home/gael/Coding/LinearAlgebra/taucs_full/build/linux/ -L/home/gael/Coding/LinearAlgebra/taucs_full/lib/linux/ -ltaucs /home/gael/Coding/LinearAlgebra/GotoBLAS/libgoto.a -lpthread -I /home/gael/Coding/LinearAlgebra/SuiteSparse/CHOLMOD/Include/ $CHOLLIB -I /home/gael/Coding/LinearAlgebra/SuiteSparse/UFconfig/ /home/gael/Coding/LinearAlgebra/SuiteSparse/CCOLAMD/Lib/libccolamd.a /home/gael/Coding/LinearAlgebra/SuiteSparse/CHOLMOD/Lib/libcholmod.a -lmetis /home/gael/Coding/LinearAlgebra/SuiteSparse/AMD/Lib/libamd.a /home/gael/Coding/LinearAlgebra/SuiteSparse/CAMD/Lib/libcamd.a /home/gael/Coding/LinearAlgebra/SuiteSparse/CCOLAMD/Lib/libccolamd.a /home/gael/Coding/LinearAlgebra/SuiteSparse/COLAMD/Lib/libcolamd.a -llapack && ./a.out
+
+#define NOGMM
+#define NOMTL
+
+#ifndef SIZE
+#define SIZE 10
+#endif
+
+#ifndef DENSITY
+#define DENSITY 0.01
+#endif
+
+#ifndef REPEAT
+#define REPEAT 1
+#endif
+
+#include "BenchSparseUtil.h"
+
+#ifndef MINDENSITY
+#define MINDENSITY 0.0004
+#endif
+
+#ifndef NBTRIES
+#define NBTRIES 10
+#endif
+
+#define BENCH(X) \
+ timer.reset(); \
+ for (int _j=0; _j<NBTRIES; ++_j) { \
+ timer.start(); \
+ for (int _k=0; _k<REPEAT; ++_k) { \
+ X \
+ } timer.stop(); }
+
+// typedef SparseMatrix<Scalar,UpperTriangular> EigenSparseTriMatrix;
+typedef SparseMatrix<Scalar,SelfAdjoint|LowerTriangular> EigenSparseSelfAdjointMatrix;
+
+void fillSpdMatrix(float density, int rows, int cols, EigenSparseSelfAdjointMatrix& dst)
+{
+ dst.startFill(rows*cols*density);
+ for(int j = 0; j < cols; j++)
+ {
+ dst.fill(j,j) = internal::random<Scalar>(10,20);
+ for(int i = j+1; i < rows; i++)
+ {
+ Scalar v = (internal::random<float>(0,1) < density) ? internal::random<Scalar>() : 0;
+ if (v!=0)
+ dst.fill(i,j) = v;
+ }
+
+ }
+ dst.endFill();
+}
+
+#include <Eigen/Cholesky>
+
+template<int Backend>
+void doEigen(const char* name, const EigenSparseSelfAdjointMatrix& sm1, int flags = 0)
+{
+ std::cout << name << "..." << std::flush;
+ BenchTimer timer;
+ timer.start();
+ SparseLLT<EigenSparseSelfAdjointMatrix,Backend> chol(sm1, flags);
+ timer.stop();
+ std::cout << ":\t" << timer.value() << endl;
+
+ std::cout << " nnz: " << sm1.nonZeros() << " => " << chol.matrixL().nonZeros() << "\n";
+// std::cout << "sparse\n" << chol.matrixL() << "%\n";
+}
+
+int main(int argc, char *argv[])
+{
+ int rows = SIZE;
+ int cols = SIZE;
+ float density = DENSITY;
+ BenchTimer timer;
+
+ VectorXf b = VectorXf::Random(cols);
+ VectorXf x = VectorXf::Random(cols);
+
+ bool densedone = false;
+
+ //for (float density = DENSITY; density>=MINDENSITY; density*=0.5)
+// float density = 0.5;
+ {
+ EigenSparseSelfAdjointMatrix sm1(rows, cols);
+ std::cout << "Generate sparse matrix (might take a while)...\n";
+ fillSpdMatrix(density, rows, cols, sm1);
+ std::cout << "DONE\n\n";
+
+ // dense matrices
+ #ifdef DENSEMATRIX
+ if (!densedone)
+ {
+ densedone = true;
+ std::cout << "Eigen Dense\t" << density*100 << "%\n";
+ DenseMatrix m1(rows,cols);
+ eiToDense(sm1, m1);
+ m1 = (m1 + m1.transpose()).eval();
+ m1.diagonal() *= 0.5;
+
+// BENCH(LLT<DenseMatrix> chol(m1);)
+// std::cout << "dense:\t" << timer.value() << endl;
+
+ BenchTimer timer;
+ timer.start();
+ LLT<DenseMatrix> chol(m1);
+ timer.stop();
+ std::cout << "dense:\t" << timer.value() << endl;
+ int count = 0;
+ for (int j=0; j<cols; ++j)
+ for (int i=j; i<rows; ++i)
+ if (!internal::isMuchSmallerThan(internal::abs(chol.matrixL()(i,j)), 0.1))
+ count++;
+ std::cout << "dense: " << "nnz = " << count << "\n";
+// std::cout << "dense:\n" << m1 << "\n\n" << chol.matrixL() << endl;
+ }
+ #endif
+
+ // eigen sparse matrices
+ doEigen<Eigen::DefaultBackend>("Eigen/Sparse", sm1, Eigen::IncompleteFactorization);
+
+ #ifdef EIGEN_CHOLMOD_SUPPORT
+ doEigen<Eigen::Cholmod>("Eigen/Cholmod", sm1, Eigen::IncompleteFactorization);
+ #endif
+
+ #ifdef EIGEN_TAUCS_SUPPORT
+ doEigen<Eigen::Taucs>("Eigen/Taucs", sm1, Eigen::IncompleteFactorization);
+ #endif
+
+ #if 0
+ // TAUCS
+ {
+ taucs_ccs_matrix A = sm1.asTaucsMatrix();
+
+ //BENCH(taucs_ccs_matrix* chol = taucs_ccs_factor_llt(&A, 0, 0);)
+// BENCH(taucs_supernodal_factor_to_ccs(taucs_ccs_factor_llt_ll(&A));)
+// std::cout << "taucs:\t" << timer.value() << endl;
+
+ taucs_ccs_matrix* chol = taucs_ccs_factor_llt(&A, 0, 0);
+
+ for (int j=0; j<cols; ++j)
+ {
+ for (int i=chol->colptr[j]; i<chol->colptr[j+1]; ++i)
+ std::cout << chol->values.d[i] << " ";
+ }
+ }
+
+ // CHOLMOD
+ #ifdef EIGEN_CHOLMOD_SUPPORT
+ {
+ cholmod_common c;
+ cholmod_start (&c);
+ cholmod_sparse A;
+ cholmod_factor *L;
+
+ A = sm1.asCholmodMatrix();
+ BenchTimer timer;
+// timer.reset();
+ timer.start();
+ std::vector<int> perm(cols);
+// std::vector<int> set(ncols);
+ for (int i=0; i<cols; ++i)
+ perm[i] = i;
+// c.nmethods = 1;
+// c.method[0] = 1;
+
+ c.nmethods = 1;
+ c.method [0].ordering = CHOLMOD_NATURAL;
+ c.postorder = 0;
+ c.final_ll = 1;
+
+ L = cholmod_analyze_p(&A, &perm[0], &perm[0], cols, &c);
+ timer.stop();
+ std::cout << "cholmod/analyze:\t" << timer.value() << endl;
+ timer.reset();
+ timer.start();
+ cholmod_factorize(&A, L, &c);
+ timer.stop();
+ std::cout << "cholmod/factorize:\t" << timer.value() << endl;
+
+ cholmod_sparse* cholmat = cholmod_factor_to_sparse(L, &c);
+
+ cholmod_print_factor(L, "Factors", &c);
+
+ cholmod_print_sparse(cholmat, "Chol", &c);
+ cholmod_write_sparse(stdout, cholmat, 0, 0, &c);
+//
+// cholmod_print_sparse(&A, "A", &c);
+// cholmod_write_sparse(stdout, &A, 0, 0, &c);
+
+
+// for (int j=0; j<cols; ++j)
+// {
+// for (int i=chol->colptr[j]; i<chol->colptr[j+1]; ++i)
+// std::cout << chol->values.s[i] << " ";
+// }
+ }
+ #endif
+
+ #endif
+
+
+
+ }
+
+
+ return 0;
+}
+
diff --git a/bench/sparse_dense_product.cpp b/bench/sparse_dense_product.cpp
new file mode 100644
index 000000000..f3f519406
--- /dev/null
+++ b/bench/sparse_dense_product.cpp
@@ -0,0 +1,187 @@
+
+//g++ -O3 -g0 -DNDEBUG sparse_product.cpp -I.. -I/home/gael/Coding/LinearAlgebra/mtl4/ -DDENSITY=0.005 -DSIZE=10000 && ./a.out
+//g++ -O3 -g0 -DNDEBUG sparse_product.cpp -I.. -I/home/gael/Coding/LinearAlgebra/mtl4/ -DDENSITY=0.05 -DSIZE=2000 && ./a.out
+// -DNOGMM -DNOMTL -DCSPARSE
+// -I /home/gael/Coding/LinearAlgebra/CSparse/Include/ /home/gael/Coding/LinearAlgebra/CSparse/Lib/libcsparse.a
+#ifndef SIZE
+#define SIZE 650000
+#endif
+
+#ifndef DENSITY
+#define DENSITY 0.01
+#endif
+
+#ifndef REPEAT
+#define REPEAT 1
+#endif
+
+#include "BenchSparseUtil.h"
+
+#ifndef MINDENSITY
+#define MINDENSITY 0.0004
+#endif
+
+#ifndef NBTRIES
+#define NBTRIES 10
+#endif
+
+#define BENCH(X) \
+ timer.reset(); \
+ for (int _j=0; _j<NBTRIES; ++_j) { \
+ timer.start(); \
+ for (int _k=0; _k<REPEAT; ++_k) { \
+ X \
+ } timer.stop(); }
+
+
+#ifdef CSPARSE
+cs* cs_sorted_multiply(const cs* a, const cs* b)
+{
+ cs* A = cs_transpose (a, 1) ;
+ cs* B = cs_transpose (b, 1) ;
+ cs* D = cs_multiply (B,A) ; /* D = B'*A' */
+ cs_spfree (A) ;
+ cs_spfree (B) ;
+ cs_dropzeros (D) ; /* drop zeros from D */
+ cs* C = cs_transpose (D, 1) ; /* C = D', so that C is sorted */
+ cs_spfree (D) ;
+ return C;
+}
+#endif
+
+int main(int argc, char *argv[])
+{
+ int rows = SIZE;
+ int cols = SIZE;
+ float density = DENSITY;
+
+ EigenSparseMatrix sm1(rows,cols);
+ DenseVector v1(cols), v2(cols);
+ v1.setRandom();
+
+ BenchTimer timer;
+ for (float density = DENSITY; density>=MINDENSITY; density*=0.5)
+ {
+ //fillMatrix(density, rows, cols, sm1);
+ fillMatrix2(7, rows, cols, sm1);
+
+ // dense matrices
+ #ifdef DENSEMATRIX
+ {
+ std::cout << "Eigen Dense\t" << density*100 << "%\n";
+ DenseMatrix m1(rows,cols);
+ eiToDense(sm1, m1);
+
+ timer.reset();
+ timer.start();
+ for (int k=0; k<REPEAT; ++k)
+ v2 = m1 * v1;
+ timer.stop();
+ std::cout << " a * v:\t" << timer.best() << " " << double(REPEAT)/timer.best() << " * / sec " << endl;
+
+ timer.reset();
+ timer.start();
+ for (int k=0; k<REPEAT; ++k)
+ v2 = m1.transpose() * v1;
+ timer.stop();
+ std::cout << " a' * v:\t" << timer.best() << endl;
+ }
+ #endif
+
+ // eigen sparse matrices
+ {
+ std::cout << "Eigen sparse\t" << sm1.nonZeros()/float(sm1.rows()*sm1.cols())*100 << "%\n";
+
+ BENCH(asm("#myc"); v2 = sm1 * v1; asm("#myd");)
+ std::cout << " a * v:\t" << timer.best()/REPEAT << " " << double(REPEAT)/timer.best(REAL_TIMER) << " * / sec " << endl;
+
+
+ BENCH( { asm("#mya"); v2 = sm1.transpose() * v1; asm("#myb"); })
+
+ std::cout << " a' * v:\t" << timer.best()/REPEAT << endl;
+ }
+
+// {
+// DynamicSparseMatrix<Scalar> m1(sm1);
+// std::cout << "Eigen dyn-sparse\t" << m1.nonZeros()/float(m1.rows()*m1.cols())*100 << "%\n";
+//
+// BENCH(for (int k=0; k<REPEAT; ++k) v2 = m1 * v1;)
+// std::cout << " a * v:\t" << timer.value() << endl;
+//
+// BENCH(for (int k=0; k<REPEAT; ++k) v2 = m1.transpose() * v1;)
+// std::cout << " a' * v:\t" << timer.value() << endl;
+// }
+
+ // GMM++
+ #ifndef NOGMM
+ {
+ std::cout << "GMM++ sparse\t" << density*100 << "%\n";
+ //GmmDynSparse gmmT3(rows,cols);
+ GmmSparse m1(rows,cols);
+ eiToGmm(sm1, m1);
+
+ std::vector<Scalar> gmmV1(cols), gmmV2(cols);
+ Map<Matrix<Scalar,Dynamic,1> >(&gmmV1[0], cols) = v1;
+ Map<Matrix<Scalar,Dynamic,1> >(&gmmV2[0], cols) = v2;
+
+ BENCH( asm("#myx"); gmm::mult(m1, gmmV1, gmmV2); asm("#myy"); )
+ std::cout << " a * v:\t" << timer.value() << endl;
+
+ BENCH( gmm::mult(gmm::transposed(m1), gmmV1, gmmV2); )
+ std::cout << " a' * v:\t" << timer.value() << endl;
+ }
+ #endif
+
+ #ifndef NOUBLAS
+ {
+ std::cout << "ublas sparse\t" << density*100 << "%\n";
+ UBlasSparse m1(rows,cols);
+ eiToUblas(sm1, m1);
+
+ boost::numeric::ublas::vector<Scalar> uv1, uv2;
+ eiToUblasVec(v1,uv1);
+ eiToUblasVec(v2,uv2);
+
+// std::vector<Scalar> gmmV1(cols), gmmV2(cols);
+// Map<Matrix<Scalar,Dynamic,1> >(&gmmV1[0], cols) = v1;
+// Map<Matrix<Scalar,Dynamic,1> >(&gmmV2[0], cols) = v2;
+
+ BENCH( uv2 = boost::numeric::ublas::prod(m1, uv1); )
+ std::cout << " a * v:\t" << timer.value() << endl;
+
+// BENCH( boost::ublas::prod(gmm::transposed(m1), gmmV1, gmmV2); )
+// std::cout << " a' * v:\t" << timer.value() << endl;
+ }
+ #endif
+
+ // MTL4
+ #ifndef NOMTL
+ {
+ std::cout << "MTL4\t" << density*100 << "%\n";
+ MtlSparse m1(rows,cols);
+ eiToMtl(sm1, m1);
+ mtl::dense_vector<Scalar> mtlV1(cols, 1.0);
+ mtl::dense_vector<Scalar> mtlV2(cols, 1.0);
+
+ timer.reset();
+ timer.start();
+ for (int k=0; k<REPEAT; ++k)
+ mtlV2 = m1 * mtlV1;
+ timer.stop();
+ std::cout << " a * v:\t" << timer.value() << endl;
+
+ timer.reset();
+ timer.start();
+ for (int k=0; k<REPEAT; ++k)
+ mtlV2 = trans(m1) * mtlV1;
+ timer.stop();
+ std::cout << " a' * v:\t" << timer.value() << endl;
+ }
+ #endif
+
+ std::cout << "\n\n";
+ }
+
+ return 0;
+}
+
diff --git a/bench/sparse_lu.cpp b/bench/sparse_lu.cpp
new file mode 100644
index 000000000..5c7500182
--- /dev/null
+++ b/bench/sparse_lu.cpp
@@ -0,0 +1,132 @@
+
+// g++ -I.. sparse_lu.cpp -O3 -g0 -I /usr/include/superlu/ -lsuperlu -lgfortran -DSIZE=1000 -DDENSITY=.05 && ./a.out
+
+#define EIGEN_SUPERLU_SUPPORT
+#define EIGEN_UMFPACK_SUPPORT
+#include <Eigen/Sparse>
+
+#define NOGMM
+#define NOMTL
+
+#ifndef SIZE
+#define SIZE 10
+#endif
+
+#ifndef DENSITY
+#define DENSITY 0.01
+#endif
+
+#ifndef REPEAT
+#define REPEAT 1
+#endif
+
+#include "BenchSparseUtil.h"
+
+#ifndef MINDENSITY
+#define MINDENSITY 0.0004
+#endif
+
+#ifndef NBTRIES
+#define NBTRIES 10
+#endif
+
+#define BENCH(X) \
+ timer.reset(); \
+ for (int _j=0; _j<NBTRIES; ++_j) { \
+ timer.start(); \
+ for (int _k=0; _k<REPEAT; ++_k) { \
+ X \
+ } timer.stop(); }
+
+typedef Matrix<Scalar,Dynamic,1> VectorX;
+
+#include <Eigen/LU>
+
+template<int Backend>
+void doEigen(const char* name, const EigenSparseMatrix& sm1, const VectorX& b, VectorX& x, int flags = 0)
+{
+ std::cout << name << "..." << std::flush;
+ BenchTimer timer; timer.start();
+ SparseLU<EigenSparseMatrix,Backend> lu(sm1, flags);
+ timer.stop();
+ if (lu.succeeded())
+ std::cout << ":\t" << timer.value() << endl;
+ else
+ {
+ std::cout << ":\t FAILED" << endl;
+ return;
+ }
+
+ bool ok;
+ timer.reset(); timer.start();
+ ok = lu.solve(b,&x);
+ timer.stop();
+ if (ok)
+ std::cout << " solve:\t" << timer.value() << endl;
+ else
+ std::cout << " solve:\t" << " FAILED" << endl;
+
+ //std::cout << x.transpose() << "\n";
+}
+
+int main(int argc, char *argv[])
+{
+ int rows = SIZE;
+ int cols = SIZE;
+ float density = DENSITY;
+ BenchTimer timer;
+
+ VectorX b = VectorX::Random(cols);
+ VectorX x = VectorX::Random(cols);
+
+ bool densedone = false;
+
+ //for (float density = DENSITY; density>=MINDENSITY; density*=0.5)
+// float density = 0.5;
+ {
+ EigenSparseMatrix sm1(rows, cols);
+ fillMatrix(density, rows, cols, sm1);
+
+ // dense matrices
+ #ifdef DENSEMATRIX
+ if (!densedone)
+ {
+ densedone = true;
+ std::cout << "Eigen Dense\t" << density*100 << "%\n";
+ DenseMatrix m1(rows,cols);
+ eiToDense(sm1, m1);
+
+ BenchTimer timer;
+ timer.start();
+ FullPivLU<DenseMatrix> lu(m1);
+ timer.stop();
+ std::cout << "Eigen/dense:\t" << timer.value() << endl;
+
+ timer.reset();
+ timer.start();
+ lu.solve(b,&x);
+ timer.stop();
+ std::cout << " solve:\t" << timer.value() << endl;
+// std::cout << b.transpose() << "\n";
+// std::cout << x.transpose() << "\n";
+ }
+ #endif
+
+ #ifdef EIGEN_UMFPACK_SUPPORT
+ x.setZero();
+ doEigen<Eigen::UmfPack>("Eigen/UmfPack (auto)", sm1, b, x, 0);
+ #endif
+
+ #ifdef EIGEN_SUPERLU_SUPPORT
+ x.setZero();
+ doEigen<Eigen::SuperLU>("Eigen/SuperLU (nat)", sm1, b, x, Eigen::NaturalOrdering);
+// doEigen<Eigen::SuperLU>("Eigen/SuperLU (MD AT+A)", sm1, b, x, Eigen::MinimumDegree_AT_PLUS_A);
+// doEigen<Eigen::SuperLU>("Eigen/SuperLU (MD ATA)", sm1, b, x, Eigen::MinimumDegree_ATA);
+ doEigen<Eigen::SuperLU>("Eigen/SuperLU (COLAMD)", sm1, b, x, Eigen::ColApproxMinimumDegree);
+ #endif
+
+ }
+
+ return 0;
+}
+
diff --git a/bench/sparse_product.cpp b/bench/sparse_product.cpp
new file mode 100644
index 000000000..d2fc44f0d
--- /dev/null
+++ b/bench/sparse_product.cpp
@@ -0,0 +1,323 @@
+
+//g++ -O3 -g0 -DNDEBUG sparse_product.cpp -I.. -I/home/gael/Coding/LinearAlgebra/mtl4/ -DDENSITY=0.005 -DSIZE=10000 && ./a.out
+//g++ -O3 -g0 -DNDEBUG sparse_product.cpp -I.. -I/home/gael/Coding/LinearAlgebra/mtl4/ -DDENSITY=0.05 -DSIZE=2000 && ./a.out
+// -DNOGMM -DNOMTL -DCSPARSE
+// -I /home/gael/Coding/LinearAlgebra/CSparse/Include/ /home/gael/Coding/LinearAlgebra/CSparse/Lib/libcsparse.a
+
+#include <typeinfo>
+
+#ifndef SIZE
+#define SIZE 1000000
+#endif
+
+#ifndef NNZPERCOL
+#define NNZPERCOL 6
+#endif
+
+#ifndef REPEAT
+#define REPEAT 1
+#endif
+
+#include <algorithm>
+#include "BenchTimer.h"
+#include "BenchUtil.h"
+#include "BenchSparseUtil.h"
+
+#ifndef NBTRIES
+#define NBTRIES 1
+#endif
+
+#define BENCH(X) \
+ timer.reset(); \
+ for (int _j=0; _j<NBTRIES; ++_j) { \
+ timer.start(); \
+ for (int _k=0; _k<REPEAT; ++_k) { \
+ X \
+ } timer.stop(); }
+
+// #ifdef MKL
+//
+// #include "mkl_types.h"
+// #include "mkl_spblas.h"
+//
+// template<typename Lhs,typename Rhs,typename Res>
+// void mkl_multiply(const Lhs& lhs, const Rhs& rhs, Res& res)
+// {
+// char n = 'N';
+// float alpha = 1;
+// char matdescra[6];
+// matdescra[0] = 'G';
+// matdescra[1] = 0;
+// matdescra[2] = 0;
+// matdescra[3] = 'C';
+// mkl_scscmm(&n, lhs.rows(), rhs.cols(), lhs.cols(), &alpha, matdescra,
+// lhs._valuePtr(), lhs._innerIndexPtr(), lhs.outerIndexPtr(),
+// pntre, b, &ldb, &beta, c, &ldc);
+// // mkl_somatcopy('C', 'T', lhs.rows(), lhs.cols(), 1,
+// // lhs._valuePtr(), lhs.rows(), DST, dst_stride);
+// }
+//
+// #endif
+
+
+#ifdef CSPARSE
+cs* cs_sorted_multiply(const cs* a, const cs* b)
+{
+// return cs_multiply(a,b);
+
+ cs* A = cs_transpose(a, 1);
+ cs* B = cs_transpose(b, 1);
+ cs* D = cs_multiply(B,A); /* D = B'*A' */
+ cs_spfree (A) ;
+ cs_spfree (B) ;
+ cs_dropzeros (D) ; /* drop zeros from D */
+ cs* C = cs_transpose (D, 1) ; /* C = D', so that C is sorted */
+ cs_spfree (D) ;
+ return C;
+
+// cs* A = cs_transpose(a, 1);
+// cs* C = cs_transpose(A, 1);
+// return C;
+}
+
+cs* cs_sorted_multiply2(const cs* a, const cs* b)
+{
+ cs* D = cs_multiply(a,b);
+ cs* E = cs_transpose(D,1);
+ cs_spfree(D);
+ cs* C = cs_transpose(E,1);
+ cs_spfree(E);
+ return C;
+}
+#endif
+
+void bench_sort();
+
+int main(int argc, char *argv[])
+{
+// bench_sort();
+
+ int rows = SIZE;
+ int cols = SIZE;
+ float density = DENSITY;
+
+ EigenSparseMatrix sm1(rows,cols), sm2(rows,cols), sm3(rows,cols), sm4(rows,cols);
+
+ BenchTimer timer;
+ for (int nnzPerCol = NNZPERCOL; nnzPerCol>1; nnzPerCol/=1.1)
+ {
+ sm1.setZero();
+ sm2.setZero();
+ fillMatrix2(nnzPerCol, rows, cols, sm1);
+ fillMatrix2(nnzPerCol, rows, cols, sm2);
+// std::cerr << "filling OK\n";
+
+ // dense matrices
+ #ifdef DENSEMATRIX
+ {
+ std::cout << "Eigen Dense\t" << nnzPerCol << "%\n";
+ DenseMatrix m1(rows,cols), m2(rows,cols), m3(rows,cols);
+ eiToDense(sm1, m1);
+ eiToDense(sm2, m2);
+
+ timer.reset();
+ timer.start();
+ for (int k=0; k<REPEAT; ++k)
+ m3 = m1 * m2;
+ timer.stop();
+ std::cout << " a * b:\t" << timer.value() << endl;
+
+ timer.reset();
+ timer.start();
+ for (int k=0; k<REPEAT; ++k)
+ m3 = m1.transpose() * m2;
+ timer.stop();
+ std::cout << " a' * b:\t" << timer.value() << endl;
+
+ timer.reset();
+ timer.start();
+ for (int k=0; k<REPEAT; ++k)
+ m3 = m1.transpose() * m2.transpose();
+ timer.stop();
+ std::cout << " a' * b':\t" << timer.value() << endl;
+
+ timer.reset();
+ timer.start();
+ for (int k=0; k<REPEAT; ++k)
+ m3 = m1 * m2.transpose();
+ timer.stop();
+ std::cout << " a * b':\t" << timer.value() << endl;
+ }
+ #endif
+
+ // eigen sparse matrices
+ {
+ std::cout << "Eigen sparse\t" << sm1.nonZeros()/(float(sm1.rows())*float(sm1.cols()))*100 << "% * "
+ << sm2.nonZeros()/(float(sm2.rows())*float(sm2.cols()))*100 << "%\n";
+
+ BENCH(sm3 = sm1 * sm2; )
+ std::cout << " a * b:\t" << timer.value() << endl;
+
+// BENCH(sm3 = sm1.transpose() * sm2; )
+// std::cout << " a' * b:\t" << timer.value() << endl;
+// //
+// BENCH(sm3 = sm1.transpose() * sm2.transpose(); )
+// std::cout << " a' * b':\t" << timer.value() << endl;
+// //
+// BENCH(sm3 = sm1 * sm2.transpose(); )
+// std::cout << " a * b' :\t" << timer.value() << endl;
+
+
+// std::cout << "\n";
+//
+// BENCH( sm3._experimentalNewProduct(sm1, sm2); )
+// std::cout << " a * b:\t" << timer.value() << endl;
+//
+// BENCH(sm3._experimentalNewProduct(sm1.transpose(),sm2); )
+// std::cout << " a' * b:\t" << timer.value() << endl;
+// //
+// BENCH(sm3._experimentalNewProduct(sm1.transpose(),sm2.transpose()); )
+// std::cout << " a' * b':\t" << timer.value() << endl;
+// //
+// BENCH(sm3._experimentalNewProduct(sm1, sm2.transpose());)
+// std::cout << " a * b' :\t" << timer.value() << endl;
+ }
+
+ // eigen dyn-sparse matrices
+ /*{
+ DynamicSparseMatrix<Scalar> m1(sm1), m2(sm2), m3(sm3);
+ std::cout << "Eigen dyn-sparse\t" << m1.nonZeros()/(float(m1.rows())*float(m1.cols()))*100 << "% * "
+ << m2.nonZeros()/(float(m2.rows())*float(m2.cols()))*100 << "%\n";
+
+// timer.reset();
+// timer.start();
+ BENCH(for (int k=0; k<REPEAT; ++k) m3 = m1 * m2;)
+// timer.stop();
+ std::cout << " a * b:\t" << timer.value() << endl;
+// std::cout << sm3 << "\n";
+
+ timer.reset();
+ timer.start();
+// std::cerr << "transpose...\n";
+// EigenSparseMatrix sm4 = sm1.transpose();
+// std::cout << sm4.nonZeros() << " == " << sm1.nonZeros() << "\n";
+// exit(1);
+// std::cerr << "transpose OK\n";
+// std::cout << sm1 << "\n\n" << sm1.transpose() << "\n\n" << sm4.transpose() << "\n\n";
+ BENCH(for (int k=0; k<REPEAT; ++k) m3 = m1.transpose() * m2;)
+// timer.stop();
+ std::cout << " a' * b:\t" << timer.value() << endl;
+
+// timer.reset();
+// timer.start();
+ BENCH( for (int k=0; k<REPEAT; ++k) m3 = m1.transpose() * m2.transpose(); )
+// timer.stop();
+ std::cout << " a' * b':\t" << timer.value() << endl;
+
+// timer.reset();
+// timer.start();
+ BENCH( for (int k=0; k<REPEAT; ++k) m3 = m1 * m2.transpose(); )
+// timer.stop();
+ std::cout << " a * b' :\t" << timer.value() << endl;
+ }*/
+
+ // CSparse
+ #ifdef CSPARSE
+ {
+ std::cout << "CSparse \t" << nnzPerCol << "%\n";
+ cs *m1, *m2, *m3;
+ eiToCSparse(sm1, m1);
+ eiToCSparse(sm2, m2);
+
+ BENCH(
+ {
+ m3 = cs_sorted_multiply(m1, m2);
+ if (!m3)
+ {
+ std::cerr << "cs_multiply failed\n";
+ }
+// cs_print(m3, 0);
+ cs_spfree(m3);
+ }
+ );
+// timer.stop();
+ std::cout << " a * b:\t" << timer.value() << endl;
+
+// BENCH( { m3 = cs_sorted_multiply2(m1, m2); cs_spfree(m3); } );
+// std::cout << " a * b:\t" << timer.value() << endl;
+ }
+ #endif
+
+ #ifndef NOUBLAS
+ {
+ std::cout << "ublas\t" << nnzPerCol << "%\n";
+ UBlasSparse m1(rows,cols), m2(rows,cols), m3(rows,cols);
+ eiToUblas(sm1, m1);
+ eiToUblas(sm2, m2);
+
+ BENCH(boost::numeric::ublas::prod(m1, m2, m3););
+ std::cout << " a * b:\t" << timer.value() << endl;
+ }
+ #endif
+
+ // GMM++
+ #ifndef NOGMM
+ {
+ std::cout << "GMM++ sparse\t" << nnzPerCol << "%\n";
+ GmmDynSparse gmmT3(rows,cols);
+ GmmSparse m1(rows,cols), m2(rows,cols), m3(rows,cols);
+ eiToGmm(sm1, m1);
+ eiToGmm(sm2, m2);
+
+ BENCH(gmm::mult(m1, m2, gmmT3););
+ std::cout << " a * b:\t" << timer.value() << endl;
+
+// BENCH(gmm::mult(gmm::transposed(m1), m2, gmmT3););
+// std::cout << " a' * b:\t" << timer.value() << endl;
+//
+// if (rows<500)
+// {
+// BENCH(gmm::mult(gmm::transposed(m1), gmm::transposed(m2), gmmT3););
+// std::cout << " a' * b':\t" << timer.value() << endl;
+//
+// BENCH(gmm::mult(m1, gmm::transposed(m2), gmmT3););
+// std::cout << " a * b':\t" << timer.value() << endl;
+// }
+// else
+// {
+// std::cout << " a' * b':\t" << "forever" << endl;
+// std::cout << " a * b':\t" << "forever" << endl;
+// }
+ }
+ #endif
+
+ // MTL4
+ #ifndef NOMTL
+ {
+ std::cout << "MTL4\t" << nnzPerCol << "%\n";
+ MtlSparse m1(rows,cols), m2(rows,cols), m3(rows,cols);
+ eiToMtl(sm1, m1);
+ eiToMtl(sm2, m2);
+
+ BENCH(m3 = m1 * m2;);
+ std::cout << " a * b:\t" << timer.value() << endl;
+
+// BENCH(m3 = trans(m1) * m2;);
+// std::cout << " a' * b:\t" << timer.value() << endl;
+//
+// BENCH(m3 = trans(m1) * trans(m2););
+// std::cout << " a' * b':\t" << timer.value() << endl;
+//
+// BENCH(m3 = m1 * trans(m2););
+// std::cout << " a * b' :\t" << timer.value() << endl;
+ }
+ #endif
+
+ std::cout << "\n\n";
+ }
+
+ return 0;
+}
+
+
+
diff --git a/bench/sparse_randomsetter.cpp b/bench/sparse_randomsetter.cpp
new file mode 100644
index 000000000..19a76e38d
--- /dev/null
+++ b/bench/sparse_randomsetter.cpp
@@ -0,0 +1,125 @@
+
+#define NOGMM
+#define NOMTL
+
+#include <map>
+#include <ext/hash_map>
+#include <google/dense_hash_map>
+#include <google/sparse_hash_map>
+
+#ifndef SIZE
+#define SIZE 10000
+#endif
+
+#ifndef DENSITY
+#define DENSITY 0.01
+#endif
+
+#ifndef REPEAT
+#define REPEAT 1
+#endif
+
+#include "BenchSparseUtil.h"
+
+#ifndef MINDENSITY
+#define MINDENSITY 0.0004
+#endif
+
+#ifndef NBTRIES
+#define NBTRIES 10
+#endif
+
+#define BENCH(X) \
+ timer.reset(); \
+ for (int _j=0; _j<NBTRIES; ++_j) { \
+ timer.start(); \
+ for (int _k=0; _k<REPEAT; ++_k) { \
+ X \
+ } timer.stop(); }
+
+
+static double rtime;
+static double nentries;
+
+template<typename SetterType>
+void dostuff(const char* name, EigenSparseMatrix& sm1)
+{
+ int rows = sm1.rows();
+ int cols = sm1.cols();
+ sm1.setZero();
+ BenchTimer t;
+ SetterType* set1 = new SetterType(sm1);
+ t.reset(); t.start();
+ for (int k=0; k<nentries; ++k)
+ (*set1)(internal::random<int>(0,rows-1),internal::random<int>(0,cols-1)) += 1;
+ t.stop();
+ std::cout << "std::map => \t" << t.value()-rtime
+ << " nnz=" << set1->nonZeros() << std::flush;
+
+ // getchar();
+
+ t.reset(); t.start(); delete set1; t.stop();
+ std::cout << " back: \t" << t.value() << "\n";
+}
+
+int main(int argc, char *argv[])
+{
+ int rows = SIZE;
+ int cols = SIZE;
+ float density = DENSITY;
+
+ EigenSparseMatrix sm1(rows,cols), sm2(rows,cols);
+
+
+ nentries = rows*cols*density;
+ std::cout << "n = " << nentries << "\n";
+ int dummy;
+ BenchTimer t;
+
+ t.reset(); t.start();
+ for (int k=0; k<nentries; ++k)
+ dummy = internal::random<int>(0,rows-1) + internal::random<int>(0,cols-1);
+ t.stop();
+ rtime = t.value();
+ std::cout << "rtime = " << rtime << " (" << dummy << ")\n\n";
+ const int Bits = 6;
+ for (;;)
+ {
+ dostuff<RandomSetter<EigenSparseMatrix,StdMapTraits,Bits> >("std::map ", sm1);
+ dostuff<RandomSetter<EigenSparseMatrix,GnuHashMapTraits,Bits> >("gnu::hash_map", sm1);
+ dostuff<RandomSetter<EigenSparseMatrix,GoogleDenseHashMapTraits,Bits> >("google::dense", sm1);
+ dostuff<RandomSetter<EigenSparseMatrix,GoogleSparseHashMapTraits,Bits> >("google::sparse", sm1);
+
+// {
+// RandomSetter<EigenSparseMatrix,GnuHashMapTraits,Bits> set1(sm1);
+// t.reset(); t.start();
+// for (int k=0; k<n; ++k)
+// set1(internal::random<int>(0,rows-1),internal::random<int>(0,cols-1)) += 1;
+// t.stop();
+// std::cout << "gnu::hash_map => \t" << t.value()-rtime
+// << " nnz=" << set1.nonZeros() << "\n";getchar();
+// }
+// {
+// RandomSetter<EigenSparseMatrix,GoogleDenseHashMapTraits,Bits> set1(sm1);
+// t.reset(); t.start();
+// for (int k=0; k<n; ++k)
+// set1(internal::random<int>(0,rows-1),internal::random<int>(0,cols-1)) += 1;
+// t.stop();
+// std::cout << "google::dense => \t" << t.value()-rtime
+// << " nnz=" << set1.nonZeros() << "\n";getchar();
+// }
+// {
+// RandomSetter<EigenSparseMatrix,GoogleSparseHashMapTraits,Bits> set1(sm1);
+// t.reset(); t.start();
+// for (int k=0; k<n; ++k)
+// set1(internal::random<int>(0,rows-1),internal::random<int>(0,cols-1)) += 1;
+// t.stop();
+// std::cout << "google::sparse => \t" << t.value()-rtime
+// << " nnz=" << set1.nonZeros() << "\n";getchar();
+// }
+ std::cout << "\n\n";
+ }
+
+ return 0;
+}
+
diff --git a/bench/sparse_setter.cpp b/bench/sparse_setter.cpp
new file mode 100644
index 000000000..a9f0b11cc
--- /dev/null
+++ b/bench/sparse_setter.cpp
@@ -0,0 +1,485 @@
+
+//g++ -O3 -g0 -DNDEBUG sparse_product.cpp -I.. -I/home/gael/Coding/LinearAlgebra/mtl4/ -DDENSITY=0.005 -DSIZE=10000 && ./a.out
+//g++ -O3 -g0 -DNDEBUG sparse_product.cpp -I.. -I/home/gael/Coding/LinearAlgebra/mtl4/ -DDENSITY=0.05 -DSIZE=2000 && ./a.out
+// -DNOGMM -DNOMTL -DCSPARSE
+// -I /home/gael/Coding/LinearAlgebra/CSparse/Include/ /home/gael/Coding/LinearAlgebra/CSparse/Lib/libcsparse.a
+#ifndef SIZE
+#define SIZE 100000
+#endif
+
+#ifndef NBPERROW
+#define NBPERROW 24
+#endif
+
+#ifndef REPEAT
+#define REPEAT 2
+#endif
+
+#ifndef NBTRIES
+#define NBTRIES 2
+#endif
+
+#ifndef KK
+#define KK 10
+#endif
+
+#ifndef NOGOOGLE
+#define EIGEN_GOOGLEHASH_SUPPORT
+#include <google/sparse_hash_map>
+#endif
+
+#include "BenchSparseUtil.h"
+
+#define CHECK_MEM
+// #define CHECK_MEM std/**/::cout << "check mem\n"; getchar();
+
+#define BENCH(X) \
+ timer.reset(); \
+ for (int _j=0; _j<NBTRIES; ++_j) { \
+ timer.start(); \
+ for (int _k=0; _k<REPEAT; ++_k) { \
+ X \
+ } timer.stop(); }
+
+typedef std::vector<Vector2i> Coordinates;
+typedef std::vector<float> Values;
+
+EIGEN_DONT_INLINE Scalar* setinnerrand_eigen(const Coordinates& coords, const Values& vals);
+EIGEN_DONT_INLINE Scalar* setrand_eigen_dynamic(const Coordinates& coords, const Values& vals);
+EIGEN_DONT_INLINE Scalar* setrand_eigen_compact(const Coordinates& coords, const Values& vals);
+EIGEN_DONT_INLINE Scalar* setrand_eigen_sumeq(const Coordinates& coords, const Values& vals);
+EIGEN_DONT_INLINE Scalar* setrand_eigen_gnu_hash(const Coordinates& coords, const Values& vals);
+EIGEN_DONT_INLINE Scalar* setrand_eigen_google_dense(const Coordinates& coords, const Values& vals);
+EIGEN_DONT_INLINE Scalar* setrand_eigen_google_sparse(const Coordinates& coords, const Values& vals);
+EIGEN_DONT_INLINE Scalar* setrand_scipy(const Coordinates& coords, const Values& vals);
+EIGEN_DONT_INLINE Scalar* setrand_ublas_mapped(const Coordinates& coords, const Values& vals);
+EIGEN_DONT_INLINE Scalar* setrand_ublas_coord(const Coordinates& coords, const Values& vals);
+EIGEN_DONT_INLINE Scalar* setrand_ublas_compressed(const Coordinates& coords, const Values& vals);
+EIGEN_DONT_INLINE Scalar* setrand_ublas_genvec(const Coordinates& coords, const Values& vals);
+EIGEN_DONT_INLINE Scalar* setrand_mtl(const Coordinates& coords, const Values& vals);
+
+int main(int argc, char *argv[])
+{
+ int rows = SIZE;
+ int cols = SIZE;
+ bool fullyrand = true;
+
+ BenchTimer timer;
+ Coordinates coords;
+ Values values;
+ if(fullyrand)
+ {
+ Coordinates pool;
+ pool.reserve(cols*NBPERROW);
+ std::cerr << "fill pool" << "\n";
+ for (int i=0; i<cols*NBPERROW; )
+ {
+// DynamicSparseMatrix<int> stencil(SIZE,SIZE);
+ Vector2i ij(internal::random<int>(0,rows-1),internal::random<int>(0,cols-1));
+// if(stencil.coeffRef(ij.x(), ij.y())==0)
+ {
+// stencil.coeffRef(ij.x(), ij.y()) = 1;
+ pool.push_back(ij);
+
+ }
+ ++i;
+ }
+ std::cerr << "pool ok" << "\n";
+ int n = cols*NBPERROW*KK;
+ coords.reserve(n);
+ values.reserve(n);
+ for (int i=0; i<n; ++i)
+ {
+ int i = internal::random<int>(0,pool.size());
+ coords.push_back(pool[i]);
+ values.push_back(internal::random<Scalar>());
+ }
+ }
+ else
+ {
+ for (int j=0; j<cols; ++j)
+ for (int i=0; i<NBPERROW; ++i)
+ {
+ coords.push_back(Vector2i(internal::random<int>(0,rows-1),j));
+ values.push_back(internal::random<Scalar>());
+ }
+ }
+ std::cout << "nnz = " << coords.size() << "\n";
+ CHECK_MEM
+
+ // dense matrices
+ #ifdef DENSEMATRIX
+ {
+ BENCH(setrand_eigen_dense(coords,values);)
+ std::cout << "Eigen Dense\t" << timer.value() << "\n";
+ }
+ #endif
+
+ // eigen sparse matrices
+// if (!fullyrand)
+// {
+// BENCH(setinnerrand_eigen(coords,values);)
+// std::cout << "Eigen fillrand\t" << timer.value() << "\n";
+// }
+ {
+ BENCH(setrand_eigen_dynamic(coords,values);)
+ std::cout << "Eigen dynamic\t" << timer.value() << "\n";
+ }
+// {
+// BENCH(setrand_eigen_compact(coords,values);)
+// std::cout << "Eigen compact\t" << timer.value() << "\n";
+// }
+ {
+ BENCH(setrand_eigen_sumeq(coords,values);)
+ std::cout << "Eigen sumeq\t" << timer.value() << "\n";
+ }
+ {
+// BENCH(setrand_eigen_gnu_hash(coords,values);)
+// std::cout << "Eigen std::map\t" << timer.value() << "\n";
+ }
+ {
+ BENCH(setrand_scipy(coords,values);)
+ std::cout << "scipy\t" << timer.value() << "\n";
+ }
+ #ifndef NOGOOGLE
+ {
+ BENCH(setrand_eigen_google_dense(coords,values);)
+ std::cout << "Eigen google dense\t" << timer.value() << "\n";
+ }
+ {
+ BENCH(setrand_eigen_google_sparse(coords,values);)
+ std::cout << "Eigen google sparse\t" << timer.value() << "\n";
+ }
+ #endif
+
+ #ifndef NOUBLAS
+ {
+// BENCH(setrand_ublas_mapped(coords,values);)
+// std::cout << "ublas mapped\t" << timer.value() << "\n";
+ }
+ {
+ BENCH(setrand_ublas_genvec(coords,values);)
+ std::cout << "ublas vecofvec\t" << timer.value() << "\n";
+ }
+ /*{
+ timer.reset();
+ timer.start();
+ for (int k=0; k<REPEAT; ++k)
+ setrand_ublas_compressed(coords,values);
+ timer.stop();
+ std::cout << "ublas comp\t" << timer.value() << "\n";
+ }
+ {
+ timer.reset();
+ timer.start();
+ for (int k=0; k<REPEAT; ++k)
+ setrand_ublas_coord(coords,values);
+ timer.stop();
+ std::cout << "ublas coord\t" << timer.value() << "\n";
+ }*/
+ #endif
+
+
+ // MTL4
+ #ifndef NOMTL
+ {
+ BENCH(setrand_mtl(coords,values));
+ std::cout << "MTL\t" << timer.value() << "\n";
+ }
+ #endif
+
+ return 0;
+}
+
+EIGEN_DONT_INLINE Scalar* setinnerrand_eigen(const Coordinates& coords, const Values& vals)
+{
+ using namespace Eigen;
+ SparseMatrix<Scalar> mat(SIZE,SIZE);
+ //mat.startFill(2000000/*coords.size()*/);
+ for (int i=0; i<coords.size(); ++i)
+ {
+ mat.insert(coords[i].x(), coords[i].y()) = vals[i];
+ }
+ mat.finalize();
+ CHECK_MEM;
+ return 0;
+}
+
+EIGEN_DONT_INLINE Scalar* setrand_eigen_dynamic(const Coordinates& coords, const Values& vals)
+{
+ using namespace Eigen;
+ DynamicSparseMatrix<Scalar> mat(SIZE,SIZE);
+ mat.reserve(coords.size()/10);
+ for (int i=0; i<coords.size(); ++i)
+ {
+ mat.coeffRef(coords[i].x(), coords[i].y()) += vals[i];
+ }
+ mat.finalize();
+ CHECK_MEM;
+ return &mat.coeffRef(coords[0].x(), coords[0].y());
+}
+
+EIGEN_DONT_INLINE Scalar* setrand_eigen_sumeq(const Coordinates& coords, const Values& vals)
+{
+ using namespace Eigen;
+ int n = coords.size()/KK;
+ DynamicSparseMatrix<Scalar> mat(SIZE,SIZE);
+ for (int j=0; j<KK; ++j)
+ {
+ DynamicSparseMatrix<Scalar> aux(SIZE,SIZE);
+ mat.reserve(n);
+ for (int i=j*n; i<(j+1)*n; ++i)
+ {
+ aux.insert(coords[i].x(), coords[i].y()) += vals[i];
+ }
+ aux.finalize();
+ mat += aux;
+ }
+ return &mat.coeffRef(coords[0].x(), coords[0].y());
+}
+
+EIGEN_DONT_INLINE Scalar* setrand_eigen_compact(const Coordinates& coords, const Values& vals)
+{
+ using namespace Eigen;
+ DynamicSparseMatrix<Scalar> setter(SIZE,SIZE);
+ setter.reserve(coords.size()/10);
+ for (int i=0; i<coords.size(); ++i)
+ {
+ setter.coeffRef(coords[i].x(), coords[i].y()) += vals[i];
+ }
+ SparseMatrix<Scalar> mat = setter;
+ CHECK_MEM;
+ return &mat.coeffRef(coords[0].x(), coords[0].y());
+}
+
+EIGEN_DONT_INLINE Scalar* setrand_eigen_gnu_hash(const Coordinates& coords, const Values& vals)
+{
+ using namespace Eigen;
+ SparseMatrix<Scalar> mat(SIZE,SIZE);
+ {
+ RandomSetter<SparseMatrix<Scalar>, StdMapTraits > setter(mat);
+ for (int i=0; i<coords.size(); ++i)
+ {
+ setter(coords[i].x(), coords[i].y()) += vals[i];
+ }
+ CHECK_MEM;
+ }
+ return &mat.coeffRef(coords[0].x(), coords[0].y());
+}
+
+#ifndef NOGOOGLE
+EIGEN_DONT_INLINE Scalar* setrand_eigen_google_dense(const Coordinates& coords, const Values& vals)
+{
+ using namespace Eigen;
+ SparseMatrix<Scalar> mat(SIZE,SIZE);
+ {
+ RandomSetter<SparseMatrix<Scalar>, GoogleDenseHashMapTraits> setter(mat);
+ for (int i=0; i<coords.size(); ++i)
+ setter(coords[i].x(), coords[i].y()) += vals[i];
+ CHECK_MEM;
+ }
+ return &mat.coeffRef(coords[0].x(), coords[0].y());
+}
+
+EIGEN_DONT_INLINE Scalar* setrand_eigen_google_sparse(const Coordinates& coords, const Values& vals)
+{
+ using namespace Eigen;
+ SparseMatrix<Scalar> mat(SIZE,SIZE);
+ {
+ RandomSetter<SparseMatrix<Scalar>, GoogleSparseHashMapTraits> setter(mat);
+ for (int i=0; i<coords.size(); ++i)
+ setter(coords[i].x(), coords[i].y()) += vals[i];
+ CHECK_MEM;
+ }
+ return &mat.coeffRef(coords[0].x(), coords[0].y());
+}
+#endif
+
+
+template <class T>
+void coo_tocsr(const int n_row,
+ const int n_col,
+ const int nnz,
+ const Coordinates Aij,
+ const Values Ax,
+ int Bp[],
+ int Bj[],
+ T Bx[])
+{
+ //compute number of non-zero entries per row of A coo_tocsr
+ std::fill(Bp, Bp + n_row, 0);
+
+ for (int n = 0; n < nnz; n++){
+ Bp[Aij[n].x()]++;
+ }
+
+ //cumsum the nnz per row to get Bp[]
+ for(int i = 0, cumsum = 0; i < n_row; i++){
+ int temp = Bp[i];
+ Bp[i] = cumsum;
+ cumsum += temp;
+ }
+ Bp[n_row] = nnz;
+
+ //write Aj,Ax into Bj,Bx
+ for(int n = 0; n < nnz; n++){
+ int row = Aij[n].x();
+ int dest = Bp[row];
+
+ Bj[dest] = Aij[n].y();
+ Bx[dest] = Ax[n];
+
+ Bp[row]++;
+ }
+
+ for(int i = 0, last = 0; i <= n_row; i++){
+ int temp = Bp[i];
+ Bp[i] = last;
+ last = temp;
+ }
+
+ //now Bp,Bj,Bx form a CSR representation (with possible duplicates)
+}
+
+template< class T1, class T2 >
+bool kv_pair_less(const std::pair<T1,T2>& x, const std::pair<T1,T2>& y){
+ return x.first < y.first;
+}
+
+
+template<class I, class T>
+void csr_sort_indices(const I n_row,
+ const I Ap[],
+ I Aj[],
+ T Ax[])
+{
+ std::vector< std::pair<I,T> > temp;
+
+ for(I i = 0; i < n_row; i++){
+ I row_start = Ap[i];
+ I row_end = Ap[i+1];
+
+ temp.clear();
+
+ for(I jj = row_start; jj < row_end; jj++){
+ temp.push_back(std::make_pair(Aj[jj],Ax[jj]));
+ }
+
+ std::sort(temp.begin(),temp.end(),kv_pair_less<I,T>);
+
+ for(I jj = row_start, n = 0; jj < row_end; jj++, n++){
+ Aj[jj] = temp[n].first;
+ Ax[jj] = temp[n].second;
+ }
+ }
+}
+
+template <class I, class T>
+void csr_sum_duplicates(const I n_row,
+ const I n_col,
+ I Ap[],
+ I Aj[],
+ T Ax[])
+{
+ I nnz = 0;
+ I row_end = 0;
+ for(I i = 0; i < n_row; i++){
+ I jj = row_end;
+ row_end = Ap[i+1];
+ while( jj < row_end ){
+ I j = Aj[jj];
+ T x = Ax[jj];
+ jj++;
+ while( jj < row_end && Aj[jj] == j ){
+ x += Ax[jj];
+ jj++;
+ }
+ Aj[nnz] = j;
+ Ax[nnz] = x;
+ nnz++;
+ }
+ Ap[i+1] = nnz;
+ }
+}
+
+EIGEN_DONT_INLINE Scalar* setrand_scipy(const Coordinates& coords, const Values& vals)
+{
+ using namespace Eigen;
+ SparseMatrix<Scalar> mat(SIZE,SIZE);
+ mat.resizeNonZeros(coords.size());
+// std::cerr << "setrand_scipy...\n";
+ coo_tocsr<Scalar>(SIZE,SIZE, coords.size(), coords, vals, mat._outerIndexPtr(), mat._innerIndexPtr(), mat._valuePtr());
+// std::cerr << "coo_tocsr ok\n";
+
+ csr_sort_indices(SIZE, mat._outerIndexPtr(), mat._innerIndexPtr(), mat._valuePtr());
+
+ csr_sum_duplicates(SIZE, SIZE, mat._outerIndexPtr(), mat._innerIndexPtr(), mat._valuePtr());
+
+ mat.resizeNonZeros(mat._outerIndexPtr()[SIZE]);
+
+ return &mat.coeffRef(coords[0].x(), coords[0].y());
+}
+
+
+#ifndef NOUBLAS
+EIGEN_DONT_INLINE Scalar* setrand_ublas_mapped(const Coordinates& coords, const Values& vals)
+{
+ using namespace boost;
+ using namespace boost::numeric;
+ using namespace boost::numeric::ublas;
+ mapped_matrix<Scalar> aux(SIZE,SIZE);
+ for (int i=0; i<coords.size(); ++i)
+ {
+ aux(coords[i].x(), coords[i].y()) += vals[i];
+ }
+ CHECK_MEM;
+ compressed_matrix<Scalar> mat(aux);
+ return 0;// &mat(coords[0].x(), coords[0].y());
+}
+/*EIGEN_DONT_INLINE Scalar* setrand_ublas_coord(const Coordinates& coords, const Values& vals)
+{
+ using namespace boost;
+ using namespace boost::numeric;
+ using namespace boost::numeric::ublas;
+ coordinate_matrix<Scalar> aux(SIZE,SIZE);
+ for (int i=0; i<coords.size(); ++i)
+ {
+ aux(coords[i].x(), coords[i].y()) = vals[i];
+ }
+ compressed_matrix<Scalar> mat(aux);
+ return 0;//&mat(coords[0].x(), coords[0].y());
+}
+EIGEN_DONT_INLINE Scalar* setrand_ublas_compressed(const Coordinates& coords, const Values& vals)
+{
+ using namespace boost;
+ using namespace boost::numeric;
+ using namespace boost::numeric::ublas;
+ compressed_matrix<Scalar> mat(SIZE,SIZE);
+ for (int i=0; i<coords.size(); ++i)
+ {
+ mat(coords[i].x(), coords[i].y()) = vals[i];
+ }
+ return 0;//&mat(coords[0].x(), coords[0].y());
+}*/
+EIGEN_DONT_INLINE Scalar* setrand_ublas_genvec(const Coordinates& coords, const Values& vals)
+{
+ using namespace boost;
+ using namespace boost::numeric;
+ using namespace boost::numeric::ublas;
+
+// ublas::vector<coordinate_vector<Scalar> > foo;
+ generalized_vector_of_vector<Scalar, row_major, ublas::vector<coordinate_vector<Scalar> > > aux(SIZE,SIZE);
+ for (int i=0; i<coords.size(); ++i)
+ {
+ aux(coords[i].x(), coords[i].y()) += vals[i];
+ }
+ CHECK_MEM;
+ compressed_matrix<Scalar,row_major> mat(aux);
+ return 0;//&mat(coords[0].x(), coords[0].y());
+}
+#endif
+
+#ifndef NOMTL
+EIGEN_DONT_INLINE void setrand_mtl(const Coordinates& coords, const Values& vals);
+#endif
+
diff --git a/bench/sparse_transpose.cpp b/bench/sparse_transpose.cpp
new file mode 100644
index 000000000..c9aacf5f1
--- /dev/null
+++ b/bench/sparse_transpose.cpp
@@ -0,0 +1,104 @@
+
+//g++ -O3 -g0 -DNDEBUG sparse_transpose.cpp -I.. -I/home/gael/Coding/LinearAlgebra/mtl4/ -DDENSITY=0.005 -DSIZE=10000 && ./a.out
+// -DNOGMM -DNOMTL
+// -DCSPARSE -I /home/gael/Coding/LinearAlgebra/CSparse/Include/ /home/gael/Coding/LinearAlgebra/CSparse/Lib/libcsparse.a
+
+#ifndef SIZE
+#define SIZE 10000
+#endif
+
+#ifndef DENSITY
+#define DENSITY 0.01
+#endif
+
+#ifndef REPEAT
+#define REPEAT 1
+#endif
+
+#include "BenchSparseUtil.h"
+
+#ifndef MINDENSITY
+#define MINDENSITY 0.0004
+#endif
+
+#ifndef NBTRIES
+#define NBTRIES 10
+#endif
+
+#define BENCH(X) \
+ timer.reset(); \
+ for (int _j=0; _j<NBTRIES; ++_j) { \
+ timer.start(); \
+ for (int _k=0; _k<REPEAT; ++_k) { \
+ X \
+ } timer.stop(); }
+
+int main(int argc, char *argv[])
+{
+ int rows = SIZE;
+ int cols = SIZE;
+ float density = DENSITY;
+
+ EigenSparseMatrix sm1(rows,cols), sm3(rows,cols);
+
+ BenchTimer timer;
+ for (float density = DENSITY; density>=MINDENSITY; density*=0.5)
+ {
+ fillMatrix(density, rows, cols, sm1);
+
+ // dense matrices
+ #ifdef DENSEMATRIX
+ {
+ DenseMatrix m1(rows,cols), m3(rows,cols);
+ eiToDense(sm1, m1);
+ BENCH(for (int k=0; k<REPEAT; ++k) m3 = m1.transpose();)
+ std::cout << " Eigen dense:\t" << timer.value() << endl;
+ }
+ #endif
+
+ std::cout << "Non zeros: " << sm1.nonZeros()/float(sm1.rows()*sm1.cols())*100 << "%\n";
+
+ // eigen sparse matrices
+ {
+ BENCH(for (int k=0; k<REPEAT; ++k) sm3 = sm1.transpose();)
+ std::cout << " Eigen:\t" << timer.value() << endl;
+ }
+
+ // CSparse
+ #ifdef CSPARSE
+ {
+ cs *m1, *m3;
+ eiToCSparse(sm1, m1);
+
+ BENCH(for (int k=0; k<REPEAT; ++k) { m3 = cs_transpose(m1,1); cs_spfree(m3);})
+ std::cout << " CSparse:\t" << timer.value() << endl;
+ }
+ #endif
+
+ // GMM++
+ #ifndef NOGMM
+ {
+ GmmDynSparse gmmT3(rows,cols);
+ GmmSparse m1(rows,cols), m3(rows,cols);
+ eiToGmm(sm1, m1);
+ BENCH(for (int k=0; k<REPEAT; ++k) gmm::copy(gmm::transposed(m1),m3);)
+ std::cout << " GMM:\t\t" << timer.value() << endl;
+ }
+ #endif
+
+ // MTL4
+ #ifndef NOMTL
+ {
+ MtlSparse m1(rows,cols), m3(rows,cols);
+ eiToMtl(sm1, m1);
+ BENCH(for (int k=0; k<REPEAT; ++k) m3 = trans(m1);)
+ std::cout << " MTL4:\t\t" << timer.value() << endl;
+ }
+ #endif
+
+ std::cout << "\n\n";
+ }
+
+ return 0;
+}
+
diff --git a/bench/sparse_trisolver.cpp b/bench/sparse_trisolver.cpp
new file mode 100644
index 000000000..13f4f0a24
--- /dev/null
+++ b/bench/sparse_trisolver.cpp
@@ -0,0 +1,220 @@
+
+//g++ -O3 -g0 -DNDEBUG sparse_product.cpp -I.. -I/home/gael/Coding/LinearAlgebra/mtl4/ -DDENSITY=0.005 -DSIZE=10000 && ./a.out
+//g++ -O3 -g0 -DNDEBUG sparse_product.cpp -I.. -I/home/gael/Coding/LinearAlgebra/mtl4/ -DDENSITY=0.05 -DSIZE=2000 && ./a.out
+// -DNOGMM -DNOMTL
+// -I /home/gael/Coding/LinearAlgebra/CSparse/Include/ /home/gael/Coding/LinearAlgebra/CSparse/Lib/libcsparse.a
+
+#ifndef SIZE
+#define SIZE 10000
+#endif
+
+#ifndef DENSITY
+#define DENSITY 0.01
+#endif
+
+#ifndef REPEAT
+#define REPEAT 1
+#endif
+
+#include "BenchSparseUtil.h"
+
+#ifndef MINDENSITY
+#define MINDENSITY 0.0004
+#endif
+
+#ifndef NBTRIES
+#define NBTRIES 10
+#endif
+
+#define BENCH(X) \
+ timer.reset(); \
+ for (int _j=0; _j<NBTRIES; ++_j) { \
+ timer.start(); \
+ for (int _k=0; _k<REPEAT; ++_k) { \
+ X \
+ } timer.stop(); }
+
+typedef SparseMatrix<Scalar,UpperTriangular> EigenSparseTriMatrix;
+typedef SparseMatrix<Scalar,RowMajorBit|UpperTriangular> EigenSparseTriMatrixRow;
+
+void fillMatrix(float density, int rows, int cols, EigenSparseTriMatrix& dst)
+{
+ dst.startFill(rows*cols*density);
+ for(int j = 0; j < cols; j++)
+ {
+ for(int i = 0; i < j; i++)
+ {
+ Scalar v = (internal::random<float>(0,1) < density) ? internal::random<Scalar>() : 0;
+ if (v!=0)
+ dst.fill(i,j) = v;
+ }
+ dst.fill(j,j) = internal::random<Scalar>();
+ }
+ dst.endFill();
+}
+
+int main(int argc, char *argv[])
+{
+ int rows = SIZE;
+ int cols = SIZE;
+ float density = DENSITY;
+ BenchTimer timer;
+ #if 1
+ EigenSparseTriMatrix sm1(rows,cols);
+ typedef Matrix<Scalar,Dynamic,1> DenseVector;
+ DenseVector b = DenseVector::Random(cols);
+ DenseVector x = DenseVector::Random(cols);
+
+ bool densedone = false;
+
+ for (float density = DENSITY; density>=MINDENSITY; density*=0.5)
+ {
+ EigenSparseTriMatrix sm1(rows, cols);
+ fillMatrix(density, rows, cols, sm1);
+
+ // dense matrices
+ #ifdef DENSEMATRIX
+ if (!densedone)
+ {
+ densedone = true;
+ std::cout << "Eigen Dense\t" << density*100 << "%\n";
+ DenseMatrix m1(rows,cols);
+ Matrix<Scalar,Dynamic,Dynamic,Dynamic,Dynamic,RowMajorBit> m2(rows,cols);
+ eiToDense(sm1, m1);
+ m2 = m1;
+
+ BENCH(x = m1.marked<UpperTriangular>().solveTriangular(b);)
+ std::cout << " colmajor^-1 * b:\t" << timer.value() << endl;
+// std::cerr << x.transpose() << "\n";
+
+ BENCH(x = m2.marked<UpperTriangular>().solveTriangular(b);)
+ std::cout << " rowmajor^-1 * b:\t" << timer.value() << endl;
+// std::cerr << x.transpose() << "\n";
+ }
+ #endif
+
+ // eigen sparse matrices
+ {
+ std::cout << "Eigen sparse\t" << density*100 << "%\n";
+ EigenSparseTriMatrixRow sm2 = sm1;
+
+ BENCH(x = sm1.solveTriangular(b);)
+ std::cout << " colmajor^-1 * b:\t" << timer.value() << endl;
+// std::cerr << x.transpose() << "\n";
+
+ BENCH(x = sm2.solveTriangular(b);)
+ std::cout << " rowmajor^-1 * b:\t" << timer.value() << endl;
+// std::cerr << x.transpose() << "\n";
+
+// x = b;
+// BENCH(sm1.inverseProductInPlace(x);)
+// std::cout << " colmajor^-1 * b:\t" << timer.value() << " (inplace)" << endl;
+// std::cerr << x.transpose() << "\n";
+//
+// x = b;
+// BENCH(sm2.inverseProductInPlace(x);)
+// std::cout << " rowmajor^-1 * b:\t" << timer.value() << " (inplace)" << endl;
+// std::cerr << x.transpose() << "\n";
+ }
+
+
+
+ // CSparse
+ #ifdef CSPARSE
+ {
+ std::cout << "CSparse \t" << density*100 << "%\n";
+ cs *m1;
+ eiToCSparse(sm1, m1);
+
+ BENCH(x = b; if (!cs_lsolve (m1, x.data())){std::cerr << "cs_lsolve failed\n"; break;}; )
+ std::cout << " colmajor^-1 * b:\t" << timer.value() << endl;
+ }
+ #endif
+
+ // GMM++
+ #ifndef NOGMM
+ {
+ std::cout << "GMM++ sparse\t" << density*100 << "%\n";
+ GmmSparse m1(rows,cols);
+ gmm::csr_matrix<Scalar> m2;
+ eiToGmm(sm1, m1);
+ gmm::copy(m1,m2);
+ std::vector<Scalar> gmmX(cols), gmmB(cols);
+ Map<Matrix<Scalar,Dynamic,1> >(&gmmX[0], cols) = x;
+ Map<Matrix<Scalar,Dynamic,1> >(&gmmB[0], cols) = b;
+
+ gmmX = gmmB;
+ BENCH(gmm::upper_tri_solve(m1, gmmX, false);)
+ std::cout << " colmajor^-1 * b:\t" << timer.value() << endl;
+// std::cerr << Map<Matrix<Scalar,Dynamic,1> >(&gmmX[0], cols).transpose() << "\n";
+
+ gmmX = gmmB;
+ BENCH(gmm::upper_tri_solve(m2, gmmX, false);)
+ timer.stop();
+ std::cout << " rowmajor^-1 * b:\t" << timer.value() << endl;
+// std::cerr << Map<Matrix<Scalar,Dynamic,1> >(&gmmX[0], cols).transpose() << "\n";
+ }
+ #endif
+
+ // MTL4
+ #ifndef NOMTL
+ {
+ std::cout << "MTL4\t" << density*100 << "%\n";
+ MtlSparse m1(rows,cols);
+ MtlSparseRowMajor m2(rows,cols);
+ eiToMtl(sm1, m1);
+ m2 = m1;
+ mtl::dense_vector<Scalar> x(rows, 1.0);
+ mtl::dense_vector<Scalar> b(rows, 1.0);
+
+ BENCH(x = mtl::upper_trisolve(m1,b);)
+ std::cout << " colmajor^-1 * b:\t" << timer.value() << endl;
+// std::cerr << x << "\n";
+
+ BENCH(x = mtl::upper_trisolve(m2,b);)
+ std::cout << " rowmajor^-1 * b:\t" << timer.value() << endl;
+// std::cerr << x << "\n";
+ }
+ #endif
+
+
+ std::cout << "\n\n";
+ }
+ #endif
+
+ #if 0
+ // bench small matrices (in-place versus return bye value)
+ {
+ timer.reset();
+ for (int _j=0; _j<10; ++_j) {
+ Matrix4f m = Matrix4f::Random();
+ Vector4f b = Vector4f::Random();
+ Vector4f x = Vector4f::Random();
+ timer.start();
+ for (int _k=0; _k<1000000; ++_k) {
+ b = m.inverseProduct(b);
+ }
+ timer.stop();
+ }
+ std::cout << "4x4 :\t" << timer.value() << endl;
+ }
+
+ {
+ timer.reset();
+ for (int _j=0; _j<10; ++_j) {
+ Matrix4f m = Matrix4f::Random();
+ Vector4f b = Vector4f::Random();
+ Vector4f x = Vector4f::Random();
+ timer.start();
+ for (int _k=0; _k<1000000; ++_k) {
+ m.inverseProductInPlace(x);
+ }
+ timer.stop();
+ }
+ std::cout << "4x4 IP :\t" << timer.value() << endl;
+ }
+ #endif
+
+ return 0;
+}
+
diff --git a/bench/spbench/CMakeLists.txt b/bench/spbench/CMakeLists.txt
new file mode 100644
index 000000000..079912266
--- /dev/null
+++ b/bench/spbench/CMakeLists.txt
@@ -0,0 +1,65 @@
+
+
+set(BLAS_FOUND TRUE)
+set(LAPACK_FOUND TRUE)
+set(BLAS_LIBRARIES eigen_blas_static)
+set(LAPACK_LIBRARIES eigen_lapack_static)
+
+set(SPARSE_LIBS "")
+
+# find_library(PARDISO_LIBRARIES pardiso412-GNU450-X86-64)
+# if(PARDISO_LIBRARIES)
+# add_definitions("-DEIGEN_PARDISO_SUPPORT")
+# set(SPARSE_LIBS ${SPARSE_LIBS} ${PARDISO_LIBRARIES})
+# endif(PARDISO_LIBRARIES)
+
+find_package(Cholmod)
+if(CHOLMOD_FOUND AND BLAS_FOUND AND LAPACK_FOUND)
+ add_definitions("-DEIGEN_CHOLMOD_SUPPORT")
+ include_directories(${CHOLMOD_INCLUDES})
+ set(SPARSE_LIBS ${SPARSE_LIBS} ${CHOLMOD_LIBRARIES} ${BLAS_LIBRARIES} ${LAPACK_LIBRARIES})
+ set(CHOLMOD_ALL_LIBS ${CHOLMOD_LIBRARIES} ${BLAS_LIBRARIES} ${LAPACK_LIBRARIES})
+endif()
+
+find_package(Umfpack)
+if(UMFPACK_FOUND AND BLAS_FOUND)
+ add_definitions("-DEIGEN_UMFPACK_SUPPORT")
+ include_directories(${UMFPACK_INCLUDES})
+ set(SPARSE_LIBS ${SPARSE_LIBS} ${UMFPACK_LIBRARIES} ${BLAS_LIBRARIES})
+ set(UMFPACK_ALL_LIBS ${UMFPACK_LIBRARIES} ${BLAS_LIBRARIES})
+endif()
+
+find_package(SuperLU)
+if(SUPERLU_FOUND AND BLAS_FOUND)
+ add_definitions("-DEIGEN_SUPERLU_SUPPORT")
+ include_directories(${SUPERLU_INCLUDES})
+ set(SPARSE_LIBS ${SPARSE_LIBS} ${SUPERLU_LIBRARIES} ${BLAS_LIBRARIES})
+ set(SUPERLU_ALL_LIBS ${SUPERLU_LIBRARIES} ${BLAS_LIBRARIES})
+endif()
+
+
+find_package(Pastix)
+find_package(Scotch)
+find_package(Metis)
+if(PASTIX_FOUND AND BLAS_FOUND)
+ add_definitions("-DEIGEN_PASTIX_SUPPORT")
+ include_directories(${PASTIX_INCLUDES})
+ if(SCOTCH_FOUND)
+ include_directories(${SCOTCH_INCLUDES})
+ set(PASTIX_LIBRARIES ${PASTIX_LIBRARIES} ${SCOTCH_LIBRARIES})
+ elseif(METIS_FOUND)
+ include_directories(${METIS_INCLUDES})
+ set(PASTIX_LIBRARIES ${PASTIX_LIBRARIES} ${METIS_LIBRARIES})
+ endif(SCOTCH_FOUND)
+ set(SPARSE_LIBS ${SPARSE_LIBS} ${PASTIX_LIBRARIES} ${ORDERING_LIBRARIES} ${BLAS_LIBRARIES})
+ set(PASTIX_ALL_LIBS ${PASTIX_LIBRARIES} ${BLAS_LIBRARIES})
+endif(PASTIX_FOUND AND BLAS_FOUND)
+
+find_library(RT_LIBRARY rt)
+if(RT_LIBRARY)
+ set(SPARSE_LIBS ${SPARSE_LIBS} ${RT_LIBRARY})
+endif(RT_LIBRARY)
+
+add_executable(spbenchsolver spbenchsolver.cpp)
+target_link_libraries (spbenchsolver ${SPARSE_LIBS})
+
diff --git a/bench/spbench/spbenchsolver.cpp b/bench/spbench/spbenchsolver.cpp
new file mode 100644
index 000000000..830542ff1
--- /dev/null
+++ b/bench/spbench/spbenchsolver.cpp
@@ -0,0 +1,90 @@
+#include <bench/spbench/spbenchsolver.h>
+
+void bench_printhelp()
+{
+ cout<< " \nbenchsolver : performs a benchmark of all the solvers available in Eigen \n\n";
+ cout<< " MATRIX FOLDER : \n";
+ cout<< " The matrices for the benchmark should be collected in a folder specified with an environment variable EIGEN_MATRIXDIR \n";
+ cout<< " This folder should contain the subfolders real/ and complex/ : \n";
+ cout<< " The matrices are stored using the matrix market coordinate format \n";
+ cout<< " The matrix and associated right-hand side (rhs) files are named respectively \n";
+ cout<< " as MatrixName.mtx and MatrixName_b.mtx. If the rhs does not exist, a random one is generated. \n";
+ cout<< " If a matrix is SPD, the matrix should be named as MatrixName_SPD.mtx \n";
+ cout<< " If a true solution exists, it should be named as MatrixName_x.mtx; \n" ;
+ cout<< " it will be used to compute the norm of the error relative to the computed solutions\n\n";
+ cout<< " OPTIONS : \n";
+ cout<< " -h or --help \n print this help and return\n\n";
+ cout<< " -d matrixdir \n Use matrixdir as the matrix folder instead of the one specified in the environment variable EIGEN_MATRIXDIR\n\n";
+ cout<< " -o outputfile.html \n Output the statistics to a html file \n\n";
+ cout<< " --eps <RelErr> Sets the relative tolerance for iterative solvers (default 1e-08) \n\n";
+ cout<< " --maxits <MaxIts> Sets the maximum number of iterations (default 1000) \n\n";
+
+}
+int main(int argc, char ** args)
+{
+
+ bool help = ( get_options(argc, args, "-h") || get_options(argc, args, "--help") );
+ if(help) {
+ bench_printhelp();
+ return 0;
+ }
+
+ // Get the location of the test matrices
+ string matrix_dir;
+ if (!get_options(argc, args, "-d", &matrix_dir))
+ {
+ if(getenv("EIGEN_MATRIXDIR") == NULL){
+ std::cerr << "Please, specify the location of the matrices with -d mat_folder or the environment variable EIGEN_MATRIXDIR \n";
+ std::cerr << " Run with --help to see the list of all the available options \n";
+ return -1;
+ }
+ matrix_dir = getenv("EIGEN_MATRIXDIR");
+ }
+
+ std::ofstream statbuf;
+ string statFile ;
+
+ // Get the file to write the statistics
+ bool statFileExists = get_options(argc, args, "-o", &statFile);
+ if(statFileExists)
+ {
+ statbuf.open(statFile.c_str(), std::ios::out);
+ if(statbuf.good()){
+ statFileExists = true;
+ printStatheader(statbuf);
+ statbuf.close();
+ }
+ else
+ std::cerr << "Unable to open the provided file for writting... \n";
+ }
+
+ // Get the maximum number of iterations and the tolerance
+ int maxiters = 1000;
+ double tol = 1e-08;
+ string inval;
+ if (get_options(argc, args, "--eps", &inval))
+ tol = atof(inval.c_str());
+ if(get_options(argc, args, "--maxits", &inval))
+ maxiters = atoi(inval.c_str());
+
+ string current_dir;
+ // Test the matrices in %EIGEN_MATRIXDIR/real
+ current_dir = matrix_dir + "/real";
+ Browse_Matrices<double>(current_dir, statFileExists, statFile,maxiters, tol);
+
+ // Test the matrices in %EIGEN_MATRIXDIR/complex
+ current_dir = matrix_dir + "/complex";
+ Browse_Matrices<std::complex<double> >(current_dir, statFileExists, statFile, maxiters, tol);
+
+ if(statFileExists)
+ {
+ statbuf.open(statFile.c_str(), std::ios::app);
+ statbuf << "</TABLE> \n";
+ cout << "\n Output written in " << statFile << " ...\n";
+ statbuf.close();
+ }
+
+ return 0;
+}
+
+
diff --git a/bench/spbench/spbenchsolver.h b/bench/spbench/spbenchsolver.h
new file mode 100644
index 000000000..609c7c39d
--- /dev/null
+++ b/bench/spbench/spbenchsolver.h
@@ -0,0 +1,533 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra.
+//
+// Copyright (C) 2012 Désiré Nuentsa-Wakam <desire.nuentsa_wakam@inria.fr>
+//
+// This Source Code Form is subject to the terms of the Mozilla
+// Public License v. 2.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 <iostream>
+#include <fstream>
+#include "Eigen/SparseCore"
+#include <bench/BenchTimer.h>
+#include <cstdlib>
+#include <string>
+#include <Eigen/Cholesky>
+#include <Eigen/Jacobi>
+#include <Eigen/Householder>
+#include <Eigen/IterativeLinearSolvers>
+#include <unsupported/Eigen/IterativeSolvers>
+#include <Eigen/LU>
+#include <unsupported/Eigen/SparseExtra>
+
+#ifdef EIGEN_CHOLMOD_SUPPORT
+#include <Eigen/CholmodSupport>
+#endif
+
+#ifdef EIGEN_UMFPACK_SUPPORT
+#include <Eigen/UmfPackSupport>
+#endif
+
+#ifdef EIGEN_PARDISO_SUPPORT
+#include <Eigen/PardisoSupport>
+#endif
+
+#ifdef EIGEN_SUPERLU_SUPPORT
+#include <Eigen/SuperLUSupport>
+#endif
+
+#ifdef EIGEN_PASTIX_SUPPORT
+#include <Eigen/PaStiXSupport>
+#endif
+
+// CONSTANTS
+#define EIGEN_UMFPACK 0
+#define EIGEN_SUPERLU 1
+#define EIGEN_PASTIX 2
+#define EIGEN_PARDISO 3
+#define EIGEN_BICGSTAB 4
+#define EIGEN_BICGSTAB_ILUT 5
+#define EIGEN_GMRES 6
+#define EIGEN_GMRES_ILUT 7
+#define EIGEN_SIMPLICIAL_LDLT 8
+#define EIGEN_CHOLMOD_LDLT 9
+#define EIGEN_PASTIX_LDLT 10
+#define EIGEN_PARDISO_LDLT 11
+#define EIGEN_SIMPLICIAL_LLT 12
+#define EIGEN_CHOLMOD_SUPERNODAL_LLT 13
+#define EIGEN_CHOLMOD_SIMPLICIAL_LLT 14
+#define EIGEN_PASTIX_LLT 15
+#define EIGEN_PARDISO_LLT 16
+#define EIGEN_CG 17
+#define EIGEN_CG_PRECOND 18
+#define EIGEN_ALL_SOLVERS 19
+
+using namespace Eigen;
+using namespace std;
+
+struct Stats{
+ ComputationInfo info;
+ double total_time;
+ double compute_time;
+ double solve_time;
+ double rel_error;
+ int memory_used;
+ int iterations;
+ int isavail;
+ int isIterative;
+};
+
+// Global variables for input parameters
+int MaximumIters; // Maximum number of iterations
+double RelErr; // Relative error of the computed solution
+
+template<typename T> inline typename NumTraits<T>::Real test_precision() { return NumTraits<T>::dummy_precision(); }
+template<> inline float test_precision<float>() { return 1e-3f; }
+template<> inline double test_precision<double>() { return 1e-6; }
+template<> inline float test_precision<std::complex<float> >() { return test_precision<float>(); }
+template<> inline double test_precision<std::complex<double> >() { return test_precision<double>(); }
+
+void printStatheader(std::ofstream& out)
+{
+ int LUcnt = 0;
+ string LUlist =" ", LLTlist = "<TH > LLT", LDLTlist = "<TH > LDLT ";
+
+#ifdef EIGEN_UMFPACK_SUPPORT
+ LUlist += "<TH > UMFPACK "; LUcnt++;
+#endif
+#ifdef EIGEN_SUPERLU_SUPPORT
+ LUlist += "<TH > SUPERLU "; LUcnt++;
+#endif
+#ifdef EIGEN_CHOLMOD_SUPPORT
+ LLTlist += "<TH > CHOLMOD SP LLT<TH > CHOLMOD LLT";
+ LDLTlist += "<TH>CHOLMOD LDLT";
+#endif
+#ifdef EIGEN_PARDISO_SUPPORT
+ LUlist += "<TH > PARDISO LU"; LUcnt++;
+ LLTlist += "<TH > PARDISO LLT";
+ LDLTlist += "<TH > PARDISO LDLT";
+#endif
+#ifdef EIGEN_PASTIX_SUPPORT
+ LUlist += "<TH > PASTIX LU"; LUcnt++;
+ LLTlist += "<TH > PASTIX LLT";
+ LDLTlist += "<TH > PASTIX LDLT";
+#endif
+
+ out << "<TABLE border=\"1\" >\n ";
+ out << "<TR><TH>Matrix <TH> N <TH> NNZ <TH> ";
+ if (LUcnt) out << LUlist;
+ out << " <TH >BiCGSTAB <TH >BiCGSTAB+ILUT"<< "<TH >GMRES+ILUT" <<LDLTlist << LLTlist << "<TH> CG "<< std::endl;
+}
+
+
+template<typename Solver, typename Scalar>
+Stats call_solver(Solver &solver, const typename Solver::MatrixType& A, const Matrix<Scalar, Dynamic, 1>& b, const Matrix<Scalar, Dynamic, 1>& refX)
+{
+ Stats stat;
+ Matrix<Scalar, Dynamic, 1> x;
+ BenchTimer timer;
+ timer.reset();
+ timer.start();
+ solver.compute(A);
+ if (solver.info() != Success)
+ {
+ stat.info = NumericalIssue;
+ std::cerr << "Solver failed ... \n";
+ return stat;
+ }
+ timer.stop();
+ stat.compute_time = timer.value();
+
+ timer.reset();
+ timer.start();
+ x = solver.solve(b);
+ if (solver.info() == NumericalIssue)
+ {
+ stat.info = NumericalIssue;
+ std::cerr << "Solver failed ... \n";
+ return stat;
+ }
+
+ timer.stop();
+ stat.solve_time = timer.value();
+ stat.total_time = stat.solve_time + stat.compute_time;
+ stat.memory_used = 0;
+ // Verify the relative error
+ if(refX.size() != 0)
+ stat.rel_error = (refX - x).norm()/refX.norm();
+ else
+ {
+ // Compute the relative residual norm
+ Matrix<Scalar, Dynamic, 1> temp;
+ temp = A * x;
+ stat.rel_error = (b-temp).norm()/b.norm();
+ }
+ if ( stat.rel_error > RelErr )
+ {
+ stat.info = NoConvergence;
+ return stat;
+ }
+ else
+ {
+ stat.info = Success;
+ return stat;
+ }
+}
+
+template<typename Solver, typename Scalar>
+Stats call_directsolver(Solver& solver, const typename Solver::MatrixType& A, const Matrix<Scalar, Dynamic, 1>& b, const Matrix<Scalar, Dynamic, 1>& refX)
+{
+ Stats stat;
+ stat = call_solver(solver, A, b, refX);
+ return stat;
+}
+
+template<typename Solver, typename Scalar>
+Stats call_itersolver(Solver &solver, const typename Solver::MatrixType& A, const Matrix<Scalar, Dynamic, 1>& b, const Matrix<Scalar, Dynamic, 1>& refX)
+{
+ Stats stat;
+ solver.setTolerance(RelErr);
+ solver.setMaxIterations(MaximumIters);
+
+ stat = call_solver(solver, A, b, refX);
+ stat.iterations = solver.iterations();
+ return stat;
+}
+
+inline void printStatItem(Stats *stat, int solver_id, int& best_time_id, double& best_time_val)
+{
+ stat[solver_id].isavail = 1;
+
+ if (stat[solver_id].info == NumericalIssue)
+ {
+ cout << " SOLVER FAILED ... Probably a numerical issue \n";
+ return;
+ }
+ if (stat[solver_id].info == NoConvergence){
+ cout << "REL. ERROR " << stat[solver_id].rel_error;
+ if(stat[solver_id].isIterative == 1)
+ cout << " (" << stat[solver_id].iterations << ") \n";
+ return;
+ }
+
+ // Record the best CPU time
+ if (!best_time_val)
+ {
+ best_time_val = stat[solver_id].total_time;
+ best_time_id = solver_id;
+ }
+ else if (stat[solver_id].total_time < best_time_val)
+ {
+ best_time_val = stat[solver_id].total_time;
+ best_time_id = solver_id;
+ }
+ // Print statistics to standard output
+ if (stat[solver_id].info == Success){
+ cout<< "COMPUTE TIME : " << stat[solver_id].compute_time<< " \n";
+ cout<< "SOLVE TIME : " << stat[solver_id].solve_time<< " \n";
+ cout<< "TOTAL TIME : " << stat[solver_id].total_time<< " \n";
+ cout << "REL. ERROR : " << stat[solver_id].rel_error ;
+ if(stat[solver_id].isIterative == 1) {
+ cout << " (" << stat[solver_id].iterations << ") ";
+ }
+ cout << std::endl;
+ }
+
+}
+
+
+/* Print the results from all solvers corresponding to a particular matrix
+ * The best CPU time is printed in bold
+ */
+inline void printHtmlStatLine(Stats *stat, int best_time_id, string& statline)
+{
+
+ string markup;
+ ostringstream compute,solve,total,error;
+ for (int i = 0; i < EIGEN_ALL_SOLVERS; i++)
+ {
+ if (stat[i].isavail == 0) continue;
+ if(i == best_time_id)
+ markup = "<TD style=\"background-color:red\">";
+ else
+ markup = "<TD>";
+
+ if (stat[i].info == Success){
+ compute << markup << stat[i].compute_time;
+ solve << markup << stat[i].solve_time;
+ total << markup << stat[i].total_time;
+ error << " <TD> " << stat[i].rel_error;
+ if(stat[i].isIterative == 1) {
+ error << " (" << stat[i].iterations << ") ";
+ }
+ }
+ else {
+ compute << " <TD> -" ;
+ solve << " <TD> -" ;
+ total << " <TD> -" ;
+ if(stat[i].info == NoConvergence){
+ error << " <TD> "<< stat[i].rel_error ;
+ if(stat[i].isIterative == 1)
+ error << " (" << stat[i].iterations << ") ";
+ }
+ else error << " <TD> - ";
+ }
+ }
+
+ statline = "<TH>Compute Time " + compute.str() + "\n"
+ + "<TR><TH>Solve Time " + solve.str() + "\n"
+ + "<TR><TH>Total Time " + total.str() + "\n"
+ +"<TR><TH>Error(Iter)" + error.str() + "\n";
+
+}
+
+template <typename Scalar>
+int SelectSolvers(const SparseMatrix<Scalar>&A, unsigned int sym, Matrix<Scalar, Dynamic, 1>& b, const Matrix<Scalar, Dynamic, 1>& refX, Stats *stat)
+{
+ typedef SparseMatrix<Scalar, ColMajor> SpMat;
+ // First, deal with Nonsymmetric and symmetric matrices
+ int best_time_id = 0;
+ double best_time_val = 0.0;
+ //UMFPACK
+ #ifdef EIGEN_UMFPACK_SUPPORT
+ {
+ cout << "Solving with UMFPACK LU ... \n";
+ UmfPackLU<SpMat> solver;
+ stat[EIGEN_UMFPACK] = call_directsolver(solver, A, b, refX);
+ printStatItem(stat, EIGEN_UMFPACK, best_time_id, best_time_val);
+ }
+ #endif
+ //SuperLU
+ #ifdef EIGEN_SUPERLU_SUPPORT
+ {
+ cout << "\nSolving with SUPERLU ... \n";
+ SuperLU<SpMat> solver;
+ stat[EIGEN_SUPERLU] = call_directsolver(solver, A, b, refX);
+ printStatItem(stat, EIGEN_SUPERLU, best_time_id, best_time_val);
+ }
+ #endif
+
+ // PaStix LU
+ #ifdef EIGEN_PASTIX_SUPPORT
+ {
+ cout << "\nSolving with PASTIX LU ... \n";
+ PastixLU<SpMat> solver;
+ stat[EIGEN_PASTIX] = call_directsolver(solver, A, b, refX) ;
+ printStatItem(stat, EIGEN_PASTIX, best_time_id, best_time_val);
+ }
+ #endif
+
+ //PARDISO LU
+ #ifdef EIGEN_PARDISO_SUPPORT
+ {
+ cout << "\nSolving with PARDISO LU ... \n";
+ PardisoLU<SpMat> solver;
+ stat[EIGEN_PARDISO] = call_directsolver(solver, A, b, refX);
+ printStatItem(stat, EIGEN_PARDISO, best_time_id, best_time_val);
+ }
+ #endif
+
+
+
+ //BiCGSTAB
+ {
+ cout << "\nSolving with BiCGSTAB ... \n";
+ BiCGSTAB<SpMat> solver;
+ stat[EIGEN_BICGSTAB] = call_itersolver(solver, A, b, refX);
+ stat[EIGEN_BICGSTAB].isIterative = 1;
+ printStatItem(stat, EIGEN_BICGSTAB, best_time_id, best_time_val);
+ }
+ //BiCGSTAB+ILUT
+ {
+ cout << "\nSolving with BiCGSTAB and ILUT ... \n";
+ BiCGSTAB<SpMat, IncompleteLUT<Scalar> > solver;
+ stat[EIGEN_BICGSTAB_ILUT] = call_itersolver(solver, A, b, refX);
+ stat[EIGEN_BICGSTAB_ILUT].isIterative = 1;
+ printStatItem(stat, EIGEN_BICGSTAB_ILUT, best_time_id, best_time_val);
+ }
+
+
+ //GMRES
+// {
+// cout << "\nSolving with GMRES ... \n";
+// GMRES<SpMat> solver;
+// stat[EIGEN_GMRES] = call_itersolver(solver, A, b, refX);
+// stat[EIGEN_GMRES].isIterative = 1;
+// printStatItem(stat, EIGEN_GMRES, best_time_id, best_time_val);
+// }
+ //GMRES+ILUT
+ {
+ cout << "\nSolving with GMRES and ILUT ... \n";
+ GMRES<SpMat, IncompleteLUT<Scalar> > solver;
+ stat[EIGEN_GMRES_ILUT] = call_itersolver(solver, A, b, refX);
+ stat[EIGEN_GMRES_ILUT].isIterative = 1;
+ printStatItem(stat, EIGEN_GMRES_ILUT, best_time_id, best_time_val);
+ }
+
+ // Hermitian and not necessarily positive-definites
+ if (sym != NonSymmetric)
+ {
+ // Internal Cholesky
+ {
+ cout << "\nSolving with Simplicial LDLT ... \n";
+ SimplicialLDLT<SpMat, Lower> solver;
+ stat[EIGEN_SIMPLICIAL_LDLT] = call_directsolver(solver, A, b, refX);
+ printStatItem(stat, EIGEN_SIMPLICIAL_LDLT, best_time_id, best_time_val);
+ }
+
+ // CHOLMOD
+ #ifdef EIGEN_CHOLMOD_SUPPORT
+ {
+ cout << "\nSolving with CHOLMOD LDLT ... \n";
+ CholmodDecomposition<SpMat, Lower> solver;
+ solver.setMode(CholmodLDLt);
+ stat[EIGEN_CHOLMOD_LDLT] = call_directsolver(solver, A, b, refX);
+ printStatItem(stat,EIGEN_CHOLMOD_LDLT, best_time_id, best_time_val);
+ }
+ #endif
+
+ //PASTIX LLT
+ #ifdef EIGEN_PASTIX_SUPPORT
+ {
+ cout << "\nSolving with PASTIX LDLT ... \n";
+ PastixLDLT<SpMat, Lower> solver;
+ stat[EIGEN_PASTIX_LDLT] = call_directsolver(solver, A, b, refX);
+ printStatItem(stat,EIGEN_PASTIX_LDLT, best_time_id, best_time_val);
+ }
+ #endif
+
+ //PARDISO LLT
+ #ifdef EIGEN_PARDISO_SUPPORT
+ {
+ cout << "\nSolving with PARDISO LDLT ... \n";
+ PardisoLDLT<SpMat, Lower> solver;
+ stat[EIGEN_PARDISO_LDLT] = call_directsolver(solver, A, b, refX);
+ printStatItem(stat,EIGEN_PARDISO_LDLT, best_time_id, best_time_val);
+ }
+ #endif
+ }
+
+ // Now, symmetric POSITIVE DEFINITE matrices
+ if (sym == SPD)
+ {
+
+ //Internal Sparse Cholesky
+ {
+ cout << "\nSolving with SIMPLICIAL LLT ... \n";
+ SimplicialLLT<SpMat, Lower> solver;
+ stat[EIGEN_SIMPLICIAL_LLT] = call_directsolver(solver, A, b, refX);
+ printStatItem(stat,EIGEN_SIMPLICIAL_LLT, best_time_id, best_time_val);
+ }
+
+ // CHOLMOD
+ #ifdef EIGEN_CHOLMOD_SUPPORT
+ {
+ // CholMOD SuperNodal LLT
+ cout << "\nSolving with CHOLMOD LLT (Supernodal)... \n";
+ CholmodDecomposition<SpMat, Lower> solver;
+ solver.setMode(CholmodSupernodalLLt);
+ stat[EIGEN_CHOLMOD_SUPERNODAL_LLT] = call_directsolver(solver, A, b, refX);
+ printStatItem(stat,EIGEN_CHOLMOD_SUPERNODAL_LLT, best_time_id, best_time_val);
+ // CholMod Simplicial LLT
+ cout << "\nSolving with CHOLMOD LLT (Simplicial) ... \n";
+ solver.setMode(CholmodSimplicialLLt);
+ stat[EIGEN_CHOLMOD_SIMPLICIAL_LLT] = call_directsolver(solver, A, b, refX);
+ printStatItem(stat,EIGEN_CHOLMOD_SIMPLICIAL_LLT, best_time_id, best_time_val);
+ }
+ #endif
+
+ //PASTIX LLT
+ #ifdef EIGEN_PASTIX_SUPPORT
+ {
+ cout << "\nSolving with PASTIX LLT ... \n";
+ PastixLLT<SpMat, Lower> solver;
+ stat[EIGEN_PASTIX_LLT] = call_directsolver(solver, A, b, refX);
+ printStatItem(stat,EIGEN_PASTIX_LLT, best_time_id, best_time_val);
+ }
+ #endif
+
+ //PARDISO LLT
+ #ifdef EIGEN_PARDISO_SUPPORT
+ {
+ cout << "\nSolving with PARDISO LLT ... \n";
+ PardisoLLT<SpMat, Lower> solver;
+ stat[EIGEN_PARDISO_LLT] = call_directsolver(solver, A, b, refX);
+ printStatItem(stat,EIGEN_PARDISO_LLT, best_time_id, best_time_val);
+ }
+ #endif
+
+ // Internal CG
+ {
+ cout << "\nSolving with CG ... \n";
+ ConjugateGradient<SpMat, Lower> solver;
+ stat[EIGEN_CG] = call_itersolver(solver, A, b, refX);
+ stat[EIGEN_CG].isIterative = 1;
+ printStatItem(stat,EIGEN_CG, best_time_id, best_time_val);
+ }
+ //CG+IdentityPreconditioner
+// {
+// cout << "\nSolving with CG and IdentityPreconditioner ... \n";
+// ConjugateGradient<SpMat, Lower, IdentityPreconditioner> solver;
+// stat[EIGEN_CG_PRECOND] = call_itersolver(solver, A, b, refX);
+// stat[EIGEN_CG_PRECOND].isIterative = 1;
+// printStatItem(stat,EIGEN_CG_PRECOND, best_time_id, best_time_val);
+// }
+ } // End SPD matrices
+
+ return best_time_id;
+}
+
+/* Browse all the matrices available in the specified folder
+ * and solve the associated linear system.
+ * The results of each solve are printed in the standard output
+ * and optionally in the provided html file
+ */
+template <typename Scalar>
+void Browse_Matrices(const string folder, bool statFileExists, std::string& statFile, int maxiters, double tol)
+{
+ MaximumIters = maxiters; // Maximum number of iterations, global variable
+ RelErr = tol; //Relative residual error as stopping criterion for iterative solvers
+ MatrixMarketIterator<Scalar> it(folder);
+ Stats stat[EIGEN_ALL_SOLVERS];
+ for ( ; it; ++it)
+ {
+ for (int i = 0; i < EIGEN_ALL_SOLVERS; i++)
+ {
+ stat[i].isavail = 0;
+ stat[i].isIterative = 0;
+ }
+
+ int best_time_id;
+ cout<< "\n\n===================================================== \n";
+ cout<< " ====== SOLVING WITH MATRIX " << it.matname() << " ====\n";
+ cout<< " =================================================== \n\n";
+ Matrix<Scalar, Dynamic, 1> refX;
+ if(it.hasrefX()) refX = it.refX();
+ best_time_id = SelectSolvers<Scalar>(it.matrix(), it.sym(), it.rhs(), refX, &stat[0]);
+
+ if(statFileExists)
+ {
+ string statline;
+ printHtmlStatLine(&stat[0], best_time_id, statline);
+ std::ofstream statbuf(statFile.c_str(), std::ios::app);
+ statbuf << "<TR><TH rowspan=\"4\">" << it.matname() << " <TD rowspan=\"4\"> "
+ << it.matrix().rows() << " <TD rowspan=\"4\"> " << it.matrix().nonZeros()<< " "<< statline ;
+ statbuf.close();
+ }
+ }
+}
+
+bool get_options(int argc, char **args, string option, string* value=0)
+{
+ int idx = 1, found=false;
+ while (idx<argc && !found){
+ if (option.compare(args[idx]) == 0){
+ found = true;
+ if(value) *value = args[idx+1];
+ }
+ idx+=2;
+ }
+ return found;
+}
diff --git a/bench/spmv.cpp b/bench/spmv.cpp
new file mode 100644
index 000000000..f6326dbb1
--- /dev/null
+++ b/bench/spmv.cpp
@@ -0,0 +1,233 @@
+
+//g++-4.4 -DNOMTL -Wl,-rpath /usr/local/lib/oski -L /usr/local/lib/oski/ -l oski -l oski_util -l oski_util_Tid -DOSKI -I ~/Coding/LinearAlgebra/mtl4/ spmv.cpp -I .. -O2 -DNDEBUG -lrt -lm -l oski_mat_CSC_Tid -loskilt && ./a.out r200000 c200000 n100 t1 p1
+
+#define SCALAR double
+
+#include <iostream>
+#include <algorithm>
+#include "BenchTimer.h"
+#include "BenchSparseUtil.h"
+
+#define SPMV_BENCH(CODE) BENCH(t,tries,repeats,CODE);
+
+// #ifdef MKL
+//
+// #include "mkl_types.h"
+// #include "mkl_spblas.h"
+//
+// template<typename Lhs,typename Rhs,typename Res>
+// void mkl_multiply(const Lhs& lhs, const Rhs& rhs, Res& res)
+// {
+// char n = 'N';
+// float alpha = 1;
+// char matdescra[6];
+// matdescra[0] = 'G';
+// matdescra[1] = 0;
+// matdescra[2] = 0;
+// matdescra[3] = 'C';
+// mkl_scscmm(&n, lhs.rows(), rhs.cols(), lhs.cols(), &alpha, matdescra,
+// lhs._valuePtr(), lhs._innerIndexPtr(), lhs.outerIndexPtr(),
+// pntre, b, &ldb, &beta, c, &ldc);
+// // mkl_somatcopy('C', 'T', lhs.rows(), lhs.cols(), 1,
+// // lhs._valuePtr(), lhs.rows(), DST, dst_stride);
+// }
+//
+// #endif
+
+int main(int argc, char *argv[])
+{
+ int size = 10000;
+ int rows = size;
+ int cols = size;
+ int nnzPerCol = 40;
+ int tries = 2;
+ int repeats = 2;
+
+ bool need_help = false;
+ for(int i = 1; i < argc; i++)
+ {
+ if(argv[i][0] == 'r')
+ {
+ rows = atoi(argv[i]+1);
+ }
+ else if(argv[i][0] == 'c')
+ {
+ cols = atoi(argv[i]+1);
+ }
+ else if(argv[i][0] == 'n')
+ {
+ nnzPerCol = atoi(argv[i]+1);
+ }
+ else if(argv[i][0] == 't')
+ {
+ tries = atoi(argv[i]+1);
+ }
+ else if(argv[i][0] == 'p')
+ {
+ repeats = atoi(argv[i]+1);
+ }
+ else
+ {
+ need_help = true;
+ }
+ }
+ if(need_help)
+ {
+ std::cout << argv[0] << " r<nb rows> c<nb columns> n<non zeros per column> t<nb tries> p<nb repeats>\n";
+ return 1;
+ }
+
+ std::cout << "SpMV " << rows << " x " << cols << " with " << nnzPerCol << " non zeros per column. (" << repeats << " repeats, and " << tries << " tries)\n\n";
+
+ EigenSparseMatrix sm(rows,cols);
+ DenseVector dv(cols), res(rows);
+ dv.setRandom();
+
+ BenchTimer t;
+ while (nnzPerCol>=4)
+ {
+ std::cout << "nnz: " << nnzPerCol << "\n";
+ sm.setZero();
+ fillMatrix2(nnzPerCol, rows, cols, sm);
+
+ // dense matrices
+ #ifdef DENSEMATRIX
+ {
+ DenseMatrix dm(rows,cols), (rows,cols);
+ eiToDense(sm, dm);
+
+ SPMV_BENCH(res = dm * sm);
+ std::cout << "Dense " << t.value()/repeats << "\t";
+
+ SPMV_BENCHres = dm.transpose() * sm);
+ std::cout << t.value()/repeats << endl;
+ }
+ #endif
+
+ // eigen sparse matrices
+ {
+ SPMV_BENCH(res.noalias() += sm * dv; )
+ std::cout << "Eigen " << t.value()/repeats << "\t";
+
+ SPMV_BENCH(res.noalias() += sm.transpose() * dv; )
+ std::cout << t.value()/repeats << endl;
+ }
+
+ // CSparse
+ #ifdef CSPARSE
+ {
+ std::cout << "CSparse \n";
+ cs *csm;
+ eiToCSparse(sm, csm);
+
+// BENCH();
+// timer.stop();
+// std::cout << " a * b:\t" << timer.value() << endl;
+
+// BENCH( { m3 = cs_sorted_multiply2(m1, m2); cs_spfree(m3); } );
+// std::cout << " a * b:\t" << timer.value() << endl;
+ }
+ #endif
+
+ #ifdef OSKI
+ {
+ oski_matrix_t om;
+ oski_vecview_t ov, ores;
+ oski_Init();
+ om = oski_CreateMatCSC(sm._outerIndexPtr(), sm._innerIndexPtr(), sm._valuePtr(), rows, cols,
+ SHARE_INPUTMAT, 1, INDEX_ZERO_BASED);
+ ov = oski_CreateVecView(dv.data(), cols, STRIDE_UNIT);
+ ores = oski_CreateVecView(res.data(), rows, STRIDE_UNIT);
+
+ SPMV_BENCH( oski_MatMult(om, OP_NORMAL, 1, ov, 0, ores) );
+ std::cout << "OSKI " << t.value()/repeats << "\t";
+
+ SPMV_BENCH( oski_MatMult(om, OP_TRANS, 1, ov, 0, ores) );
+ std::cout << t.value()/repeats << "\n";
+
+ // tune
+ t.reset();
+ t.start();
+ oski_SetHintMatMult(om, OP_NORMAL, 1.0, SYMBOLIC_VEC, 0.0, SYMBOLIC_VEC, ALWAYS_TUNE_AGGRESSIVELY);
+ oski_TuneMat(om);
+ t.stop();
+ double tuning = t.value();
+
+ SPMV_BENCH( oski_MatMult(om, OP_NORMAL, 1, ov, 0, ores) );
+ std::cout << "OSKI tuned " << t.value()/repeats << "\t";
+
+ SPMV_BENCH( oski_MatMult(om, OP_TRANS, 1, ov, 0, ores) );
+ std::cout << t.value()/repeats << "\t(" << tuning << ")\n";
+
+
+ oski_DestroyMat(om);
+ oski_DestroyVecView(ov);
+ oski_DestroyVecView(ores);
+ oski_Close();
+ }
+ #endif
+
+ #ifndef NOUBLAS
+ {
+ using namespace boost::numeric;
+ UblasMatrix um(rows,cols);
+ eiToUblas(sm, um);
+
+ boost::numeric::ublas::vector<Scalar> uv(cols), ures(rows);
+ Map<Matrix<Scalar,Dynamic,1> >(&uv[0], cols) = dv;
+ Map<Matrix<Scalar,Dynamic,1> >(&ures[0], rows) = res;
+
+ SPMV_BENCH(ublas::axpy_prod(um, uv, ures, true));
+ std::cout << "ublas " << t.value()/repeats << "\t";
+
+ SPMV_BENCH(ublas::axpy_prod(boost::numeric::ublas::trans(um), uv, ures, true));
+ std::cout << t.value()/repeats << endl;
+ }
+ #endif
+
+ // GMM++
+ #ifndef NOGMM
+ {
+ GmmSparse gm(rows,cols);
+ eiToGmm(sm, gm);
+
+ std::vector<Scalar> gv(cols), gres(rows);
+ Map<Matrix<Scalar,Dynamic,1> >(&gv[0], cols) = dv;
+ Map<Matrix<Scalar,Dynamic,1> >(&gres[0], rows) = res;
+
+ SPMV_BENCH(gmm::mult(gm, gv, gres));
+ std::cout << "GMM++ " << t.value()/repeats << "\t";
+
+ SPMV_BENCH(gmm::mult(gmm::transposed(gm), gv, gres));
+ std::cout << t.value()/repeats << endl;
+ }
+ #endif
+
+ // MTL4
+ #ifndef NOMTL
+ {
+ MtlSparse mm(rows,cols);
+ eiToMtl(sm, mm);
+ mtl::dense_vector<Scalar> mv(cols, 1.0);
+ mtl::dense_vector<Scalar> mres(rows, 1.0);
+
+ SPMV_BENCH(mres = mm * mv);
+ std::cout << "MTL4 " << t.value()/repeats << "\t";
+
+ SPMV_BENCH(mres = trans(mm) * mv);
+ std::cout << t.value()/repeats << endl;
+ }
+ #endif
+
+ std::cout << "\n";
+
+ if(nnzPerCol==1)
+ break;
+ nnzPerCol -= nnzPerCol/2;
+ }
+
+ return 0;
+}
+
+
+
diff --git a/bench/vdw_new.cpp b/bench/vdw_new.cpp
new file mode 100644
index 000000000..d2604049f
--- /dev/null
+++ b/bench/vdw_new.cpp
@@ -0,0 +1,56 @@
+#include <iostream>
+#include <Eigen/Core>
+
+using namespace Eigen;
+
+#ifndef SCALAR
+#define SCALAR float
+#endif
+
+#ifndef SIZE
+#define SIZE 10000
+#endif
+
+#ifndef REPEAT
+#define REPEAT 10000
+#endif
+
+typedef Matrix<SCALAR, Eigen::Dynamic, 1> Vec;
+
+using namespace std;
+
+SCALAR E_VDW(const Vec &interactions1, const Vec &interactions2)
+{
+ return (interactions2.cwise()/interactions1)
+ .cwise().cube()
+ .cwise().square()
+ .cwise().square()
+ .sum();
+}
+
+int main()
+{
+ //
+ // 1 2 3 4 ... (interactions)
+ // ka . . . . ...
+ // rab . . . . ...
+ // energy . . . . ...
+ // ... ... ... ... ... ...
+ // (variables
+ // for
+ // interaction)
+ //
+ Vec interactions1(SIZE), interactions2(SIZE); // SIZE is the number of vdw interactions in our system
+ // SetupCalculations()
+ SCALAR rab = 1.0;
+ interactions1.setConstant(2.4);
+ interactions2.setConstant(rab);
+
+ // Energy()
+ SCALAR energy = 0.0;
+ for (unsigned int i = 0; i<REPEAT; ++i) {
+ energy += E_VDW(interactions1, interactions2);
+ energy *= 1 + 1e-20 * i; // prevent compiler from optimizing the loop
+ }
+ cout << "energy = " << energy << endl;
+}
diff --git a/blas/BandTriangularSolver.h b/blas/BandTriangularSolver.h
new file mode 100644
index 000000000..ce2d74daa
--- /dev/null
+++ b/blas/BandTriangularSolver.h
@@ -0,0 +1,97 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra.
+//
+// Copyright (C) 2011 Gael Guennebaud <gael.guennebaud@inria.fr>
+//
+// This Source Code Form is subject to the terms of the Mozilla
+// Public License v. 2.0. If a copy of the MPL was not distributed
+// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+#ifndef EIGEN_BAND_TRIANGULARSOLVER_H
+#define EIGEN_BAND_TRIANGULARSOLVER_H
+
+namespace internal {
+
+ /* \internal
+ * Solve Ax=b with A a band triangular matrix
+ * TODO: extend it to matrices for x abd b */
+template<typename Index, int Mode, typename LhsScalar, bool ConjLhs, typename RhsScalar, int StorageOrder>
+struct band_solve_triangular_selector;
+
+
+template<typename Index, int Mode, typename LhsScalar, bool ConjLhs, typename RhsScalar>
+struct band_solve_triangular_selector<Index,Mode,LhsScalar,ConjLhs,RhsScalar,RowMajor>
+{
+ typedef Map<const Matrix<LhsScalar,Dynamic,Dynamic,RowMajor>, 0, OuterStride<> > LhsMap;
+ typedef Map<Matrix<RhsScalar,Dynamic,1> > RhsMap;
+ enum { IsLower = (Mode&Lower) ? 1 : 0 };
+ static void run(Index size, Index k, const LhsScalar* _lhs, Index lhsStride, RhsScalar* _other)
+ {
+ const LhsMap lhs(_lhs,size,k+1,OuterStride<>(lhsStride));
+ RhsMap other(_other,size,1);
+ typename internal::conditional<
+ ConjLhs,
+ const CwiseUnaryOp<typename internal::scalar_conjugate_op<LhsScalar>,LhsMap>,
+ const LhsMap&>
+ ::type cjLhs(lhs);
+
+ for(int col=0 ; col<other.cols() ; ++col)
+ {
+ for(int ii=0; ii<size; ++ii)
+ {
+ int i = IsLower ? ii : size-ii-1;
+ int actual_k = (std::min)(k,ii);
+ int actual_start = IsLower ? k-actual_k : 1;
+
+ if(actual_k>0)
+ other.coeffRef(i,col) -= cjLhs.row(i).segment(actual_start,actual_k).transpose()
+ .cwiseProduct(other.col(col).segment(IsLower ? i-actual_k : i+1,actual_k)).sum();
+
+ if((Mode&UnitDiag)==0)
+ other.coeffRef(i,col) /= cjLhs(i,IsLower ? k : 0);
+ }
+ }
+ }
+
+};
+
+template<typename Index, int Mode, typename LhsScalar, bool ConjLhs, typename RhsScalar>
+struct band_solve_triangular_selector<Index,Mode,LhsScalar,ConjLhs,RhsScalar,ColMajor>
+{
+ typedef Map<const Matrix<LhsScalar,Dynamic,Dynamic,ColMajor>, 0, OuterStride<> > LhsMap;
+ typedef Map<Matrix<RhsScalar,Dynamic,1> > RhsMap;
+ enum { IsLower = (Mode&Lower) ? 1 : 0 };
+ static void run(Index size, Index k, const LhsScalar* _lhs, Index lhsStride, RhsScalar* _other)
+ {
+ const LhsMap lhs(_lhs,k+1,size,OuterStride<>(lhsStride));
+ RhsMap other(_other,size,1);
+ typename internal::conditional<
+ ConjLhs,
+ const CwiseUnaryOp<typename internal::scalar_conjugate_op<LhsScalar>,LhsMap>,
+ const LhsMap&>
+ ::type cjLhs(lhs);
+
+ for(int col=0 ; col<other.cols() ; ++col)
+ {
+ for(int ii=0; ii<size; ++ii)
+ {
+ int i = IsLower ? ii : size-ii-1;
+ int actual_k = (std::min)(k,size-ii-1);
+ int actual_start = IsLower ? 1 : k-actual_k;
+
+ if((Mode&UnitDiag)==0)
+ other.coeffRef(i,col) /= cjLhs(IsLower ? 0 : k, i);
+
+ if(actual_k>0)
+ other.col(col).segment(IsLower ? i+1 : i-actual_k, actual_k)
+ -= other.coeff(i,col) * cjLhs.col(i).segment(actual_start,actual_k);
+
+ }
+ }
+ }
+};
+
+
+} // end namespace internal
+
+#endif // EIGEN_BAND_TRIANGULARSOLVER_H
diff --git a/blas/CMakeLists.txt b/blas/CMakeLists.txt
new file mode 100644
index 000000000..453d5874c
--- /dev/null
+++ b/blas/CMakeLists.txt
@@ -0,0 +1,57 @@
+
+project(EigenBlas CXX)
+
+include("../cmake/language_support.cmake")
+
+workaround_9220(Fortran EIGEN_Fortran_COMPILER_WORKS)
+
+if(EIGEN_Fortran_COMPILER_WORKS)
+ enable_language(Fortran OPTIONAL)
+endif()
+
+add_custom_target(blas)
+
+set(EigenBlas_SRCS single.cpp double.cpp complex_single.cpp complex_double.cpp xerbla.cpp)
+
+if(EIGEN_Fortran_COMPILER_WORKS)
+
+set(EigenBlas_SRCS ${EigenBlas_SRCS}
+ complexdots.f
+ srotm.f srotmg.f drotm.f drotmg.f
+ lsame.f chpr2.f dspmv.f dtpsv.f ssbmv.f sspr.f stpmv.f
+ zhpr2.f chbmv.f chpr.f ctpmv.f dspr2.f sspmv.f stpsv.f
+ zhbmv.f zhpr.f ztpmv.f chpmv.f ctpsv.f dsbmv.f dspr.f dtpmv.f sspr2.f
+ zhpmv.f ztpsv.f
+ dtbmv.f stbmv.f ctbmv.f ztbmv.f
+)
+else()
+
+message(WARNING " No fortran compiler has been detected, the blas build will be incomplete.")
+
+endif()
+
+add_library(eigen_blas_static ${EigenBlas_SRCS})
+add_library(eigen_blas SHARED ${EigenBlas_SRCS})
+
+if(EIGEN_STANDARD_LIBRARIES_TO_LINK_TO)
+ target_link_libraries(eigen_blas_static ${EIGEN_STANDARD_LIBRARIES_TO_LINK_TO})
+ target_link_libraries(eigen_blas ${EIGEN_STANDARD_LIBRARIES_TO_LINK_TO})
+endif()
+
+add_dependencies(blas eigen_blas eigen_blas_static)
+
+install(TARGETS eigen_blas eigen_blas_static
+ RUNTIME DESTINATION bin
+ LIBRARY DESTINATION lib
+ ARCHIVE DESTINATION lib)
+
+if(EIGEN_Fortran_COMPILER_WORKS)
+
+if(EIGEN_LEAVE_TEST_IN_ALL_TARGET)
+ add_subdirectory(testing) # can't do EXCLUDE_FROM_ALL here, breaks CTest
+else()
+ add_subdirectory(testing EXCLUDE_FROM_ALL)
+endif()
+
+endif()
+
diff --git a/blas/README.txt b/blas/README.txt
new file mode 100644
index 000000000..07a8bd92a
--- /dev/null
+++ b/blas/README.txt
@@ -0,0 +1,9 @@
+
+This directory contains a BLAS library built on top of Eigen.
+
+This is currently a work in progress which is far to be ready for use,
+but feel free to contribute to it if you wish.
+
+This module is not built by default. In order to compile it, you need to
+type 'make blas' from within your build dir.
+
diff --git a/blas/chbmv.f b/blas/chbmv.f
new file mode 100644
index 000000000..1b1c330ea
--- /dev/null
+++ b/blas/chbmv.f
@@ -0,0 +1,310 @@
+ SUBROUTINE CHBMV(UPLO,N,K,ALPHA,A,LDA,X,INCX,BETA,Y,INCY)
+* .. Scalar Arguments ..
+ COMPLEX ALPHA,BETA
+ INTEGER INCX,INCY,K,LDA,N
+ CHARACTER UPLO
+* ..
+* .. Array Arguments ..
+ COMPLEX A(LDA,*),X(*),Y(*)
+* ..
+*
+* Purpose
+* =======
+*
+* CHBMV performs the matrix-vector operation
+*
+* y := alpha*A*x + beta*y,
+*
+* where alpha and beta are scalars, x and y are n element vectors and
+* A is an n by n hermitian band matrix, with k super-diagonals.
+*
+* Arguments
+* ==========
+*
+* UPLO - CHARACTER*1.
+* On entry, UPLO specifies whether the upper or lower
+* triangular part of the band matrix A is being supplied as
+* follows:
+*
+* UPLO = 'U' or 'u' The upper triangular part of A is
+* being supplied.
+*
+* UPLO = 'L' or 'l' The lower triangular part of A is
+* being supplied.
+*
+* Unchanged on exit.
+*
+* N - INTEGER.
+* On entry, N specifies the order of the matrix A.
+* N must be at least zero.
+* Unchanged on exit.
+*
+* K - INTEGER.
+* On entry, K specifies the number of super-diagonals of the
+* matrix A. K must satisfy 0 .le. K.
+* Unchanged on exit.
+*
+* ALPHA - COMPLEX .
+* On entry, ALPHA specifies the scalar alpha.
+* Unchanged on exit.
+*
+* A - COMPLEX array of DIMENSION ( LDA, n ).
+* Before entry with UPLO = 'U' or 'u', the leading ( k + 1 )
+* by n part of the array A must contain the upper triangular
+* band part of the hermitian matrix, supplied column by
+* column, with the leading diagonal of the matrix in row
+* ( k + 1 ) of the array, the first super-diagonal starting at
+* position 2 in row k, and so on. The top left k by k triangle
+* of the array A is not referenced.
+* The following program segment will transfer the upper
+* triangular part of a hermitian band matrix from conventional
+* full matrix storage to band storage:
+*
+* DO 20, J = 1, N
+* M = K + 1 - J
+* DO 10, I = MAX( 1, J - K ), J
+* A( M + I, J ) = matrix( I, J )
+* 10 CONTINUE
+* 20 CONTINUE
+*
+* Before entry with UPLO = 'L' or 'l', the leading ( k + 1 )
+* by n part of the array A must contain the lower triangular
+* band part of the hermitian matrix, supplied column by
+* column, with the leading diagonal of the matrix in row 1 of
+* the array, the first sub-diagonal starting at position 1 in
+* row 2, and so on. The bottom right k by k triangle of the
+* array A is not referenced.
+* The following program segment will transfer the lower
+* triangular part of a hermitian band matrix from conventional
+* full matrix storage to band storage:
+*
+* DO 20, J = 1, N
+* M = 1 - J
+* DO 10, I = J, MIN( N, J + K )
+* A( M + I, J ) = matrix( I, J )
+* 10 CONTINUE
+* 20 CONTINUE
+*
+* Note that the imaginary parts of the diagonal elements need
+* not be set and are assumed to be zero.
+* Unchanged on exit.
+*
+* LDA - INTEGER.
+* On entry, LDA specifies the first dimension of A as declared
+* in the calling (sub) program. LDA must be at least
+* ( k + 1 ).
+* Unchanged on exit.
+*
+* X - COMPLEX array of DIMENSION at least
+* ( 1 + ( n - 1 )*abs( INCX ) ).
+* Before entry, the incremented array X must contain the
+* vector x.
+* Unchanged on exit.
+*
+* INCX - INTEGER.
+* On entry, INCX specifies the increment for the elements of
+* X. INCX must not be zero.
+* Unchanged on exit.
+*
+* BETA - COMPLEX .
+* On entry, BETA specifies the scalar beta.
+* Unchanged on exit.
+*
+* Y - COMPLEX array of DIMENSION at least
+* ( 1 + ( n - 1 )*abs( INCY ) ).
+* Before entry, the incremented array Y must contain the
+* vector y. On exit, Y is overwritten by the updated vector y.
+*
+* INCY - INTEGER.
+* On entry, INCY specifies the increment for the elements of
+* Y. INCY must not be zero.
+* Unchanged on exit.
+*
+* Further Details
+* ===============
+*
+* Level 2 Blas routine.
+*
+* -- Written on 22-October-1986.
+* Jack Dongarra, Argonne National Lab.
+* Jeremy Du Croz, Nag Central Office.
+* Sven Hammarling, Nag Central Office.
+* Richard Hanson, Sandia National Labs.
+*
+* =====================================================================
+*
+* .. Parameters ..
+ COMPLEX ONE
+ PARAMETER (ONE= (1.0E+0,0.0E+0))
+ COMPLEX ZERO
+ PARAMETER (ZERO= (0.0E+0,0.0E+0))
+* ..
+* .. Local Scalars ..
+ COMPLEX TEMP1,TEMP2
+ INTEGER I,INFO,IX,IY,J,JX,JY,KPLUS1,KX,KY,L
+* ..
+* .. External Functions ..
+ LOGICAL LSAME
+ EXTERNAL LSAME
+* ..
+* .. External Subroutines ..
+ EXTERNAL XERBLA
+* ..
+* .. Intrinsic Functions ..
+ INTRINSIC CONJG,MAX,MIN,REAL
+* ..
+*
+* Test the input parameters.
+*
+ INFO = 0
+ IF (.NOT.LSAME(UPLO,'U') .AND. .NOT.LSAME(UPLO,'L')) THEN
+ INFO = 1
+ ELSE IF (N.LT.0) THEN
+ INFO = 2
+ ELSE IF (K.LT.0) THEN
+ INFO = 3
+ ELSE IF (LDA.LT. (K+1)) THEN
+ INFO = 6
+ ELSE IF (INCX.EQ.0) THEN
+ INFO = 8
+ ELSE IF (INCY.EQ.0) THEN
+ INFO = 11
+ END IF
+ IF (INFO.NE.0) THEN
+ CALL XERBLA('CHBMV ',INFO)
+ RETURN
+ END IF
+*
+* Quick return if possible.
+*
+ IF ((N.EQ.0) .OR. ((ALPHA.EQ.ZERO).AND. (BETA.EQ.ONE))) RETURN
+*
+* Set up the start points in X and Y.
+*
+ IF (INCX.GT.0) THEN
+ KX = 1
+ ELSE
+ KX = 1 - (N-1)*INCX
+ END IF
+ IF (INCY.GT.0) THEN
+ KY = 1
+ ELSE
+ KY = 1 - (N-1)*INCY
+ END IF
+*
+* Start the operations. In this version the elements of the array A
+* are accessed sequentially with one pass through A.
+*
+* First form y := beta*y.
+*
+ IF (BETA.NE.ONE) THEN
+ IF (INCY.EQ.1) THEN
+ IF (BETA.EQ.ZERO) THEN
+ DO 10 I = 1,N
+ Y(I) = ZERO
+ 10 CONTINUE
+ ELSE
+ DO 20 I = 1,N
+ Y(I) = BETA*Y(I)
+ 20 CONTINUE
+ END IF
+ ELSE
+ IY = KY
+ IF (BETA.EQ.ZERO) THEN
+ DO 30 I = 1,N
+ Y(IY) = ZERO
+ IY = IY + INCY
+ 30 CONTINUE
+ ELSE
+ DO 40 I = 1,N
+ Y(IY) = BETA*Y(IY)
+ IY = IY + INCY
+ 40 CONTINUE
+ END IF
+ END IF
+ END IF
+ IF (ALPHA.EQ.ZERO) RETURN
+ IF (LSAME(UPLO,'U')) THEN
+*
+* Form y when upper triangle of A is stored.
+*
+ KPLUS1 = K + 1
+ IF ((INCX.EQ.1) .AND. (INCY.EQ.1)) THEN
+ DO 60 J = 1,N
+ TEMP1 = ALPHA*X(J)
+ TEMP2 = ZERO
+ L = KPLUS1 - J
+ DO 50 I = MAX(1,J-K),J - 1
+ Y(I) = Y(I) + TEMP1*A(L+I,J)
+ TEMP2 = TEMP2 + CONJG(A(L+I,J))*X(I)
+ 50 CONTINUE
+ Y(J) = Y(J) + TEMP1*REAL(A(KPLUS1,J)) + ALPHA*TEMP2
+ 60 CONTINUE
+ ELSE
+ JX = KX
+ JY = KY
+ DO 80 J = 1,N
+ TEMP1 = ALPHA*X(JX)
+ TEMP2 = ZERO
+ IX = KX
+ IY = KY
+ L = KPLUS1 - J
+ DO 70 I = MAX(1,J-K),J - 1
+ Y(IY) = Y(IY) + TEMP1*A(L+I,J)
+ TEMP2 = TEMP2 + CONJG(A(L+I,J))*X(IX)
+ IX = IX + INCX
+ IY = IY + INCY
+ 70 CONTINUE
+ Y(JY) = Y(JY) + TEMP1*REAL(A(KPLUS1,J)) + ALPHA*TEMP2
+ JX = JX + INCX
+ JY = JY + INCY
+ IF (J.GT.K) THEN
+ KX = KX + INCX
+ KY = KY + INCY
+ END IF
+ 80 CONTINUE
+ END IF
+ ELSE
+*
+* Form y when lower triangle of A is stored.
+*
+ IF ((INCX.EQ.1) .AND. (INCY.EQ.1)) THEN
+ DO 100 J = 1,N
+ TEMP1 = ALPHA*X(J)
+ TEMP2 = ZERO
+ Y(J) = Y(J) + TEMP1*REAL(A(1,J))
+ L = 1 - J
+ DO 90 I = J + 1,MIN(N,J+K)
+ Y(I) = Y(I) + TEMP1*A(L+I,J)
+ TEMP2 = TEMP2 + CONJG(A(L+I,J))*X(I)
+ 90 CONTINUE
+ Y(J) = Y(J) + ALPHA*TEMP2
+ 100 CONTINUE
+ ELSE
+ JX = KX
+ JY = KY
+ DO 120 J = 1,N
+ TEMP1 = ALPHA*X(JX)
+ TEMP2 = ZERO
+ Y(JY) = Y(JY) + TEMP1*REAL(A(1,J))
+ L = 1 - J
+ IX = JX
+ IY = JY
+ DO 110 I = J + 1,MIN(N,J+K)
+ IX = IX + INCX
+ IY = IY + INCY
+ Y(IY) = Y(IY) + TEMP1*A(L+I,J)
+ TEMP2 = TEMP2 + CONJG(A(L+I,J))*X(IX)
+ 110 CONTINUE
+ Y(JY) = Y(JY) + ALPHA*TEMP2
+ JX = JX + INCX
+ JY = JY + INCY
+ 120 CONTINUE
+ END IF
+ END IF
+*
+ RETURN
+*
+* End of CHBMV .
+*
+ END
diff --git a/blas/chpmv.f b/blas/chpmv.f
new file mode 100644
index 000000000..158be5a7b
--- /dev/null
+++ b/blas/chpmv.f
@@ -0,0 +1,272 @@
+ SUBROUTINE CHPMV(UPLO,N,ALPHA,AP,X,INCX,BETA,Y,INCY)
+* .. Scalar Arguments ..
+ COMPLEX ALPHA,BETA
+ INTEGER INCX,INCY,N
+ CHARACTER UPLO
+* ..
+* .. Array Arguments ..
+ COMPLEX AP(*),X(*),Y(*)
+* ..
+*
+* Purpose
+* =======
+*
+* CHPMV performs the matrix-vector operation
+*
+* y := alpha*A*x + beta*y,
+*
+* where alpha and beta are scalars, x and y are n element vectors and
+* A is an n by n hermitian matrix, supplied in packed form.
+*
+* Arguments
+* ==========
+*
+* UPLO - CHARACTER*1.
+* On entry, UPLO specifies whether the upper or lower
+* triangular part of the matrix A is supplied in the packed
+* array AP as follows:
+*
+* UPLO = 'U' or 'u' The upper triangular part of A is
+* supplied in AP.
+*
+* UPLO = 'L' or 'l' The lower triangular part of A is
+* supplied in AP.
+*
+* Unchanged on exit.
+*
+* N - INTEGER.
+* On entry, N specifies the order of the matrix A.
+* N must be at least zero.
+* Unchanged on exit.
+*
+* ALPHA - COMPLEX .
+* On entry, ALPHA specifies the scalar alpha.
+* Unchanged on exit.
+*
+* AP - COMPLEX array of DIMENSION at least
+* ( ( n*( n + 1 ) )/2 ).
+* Before entry with UPLO = 'U' or 'u', the array AP must
+* contain the upper triangular part of the hermitian matrix
+* packed sequentially, column by column, so that AP( 1 )
+* contains a( 1, 1 ), AP( 2 ) and AP( 3 ) contain a( 1, 2 )
+* and a( 2, 2 ) respectively, and so on.
+* Before entry with UPLO = 'L' or 'l', the array AP must
+* contain the lower triangular part of the hermitian matrix
+* packed sequentially, column by column, so that AP( 1 )
+* contains a( 1, 1 ), AP( 2 ) and AP( 3 ) contain a( 2, 1 )
+* and a( 3, 1 ) respectively, and so on.
+* Note that the imaginary parts of the diagonal elements need
+* not be set and are assumed to be zero.
+* Unchanged on exit.
+*
+* X - COMPLEX array of dimension at least
+* ( 1 + ( n - 1 )*abs( INCX ) ).
+* Before entry, the incremented array X must contain the n
+* element vector x.
+* Unchanged on exit.
+*
+* INCX - INTEGER.
+* On entry, INCX specifies the increment for the elements of
+* X. INCX must not be zero.
+* Unchanged on exit.
+*
+* BETA - COMPLEX .
+* On entry, BETA specifies the scalar beta. When BETA is
+* supplied as zero then Y need not be set on input.
+* Unchanged on exit.
+*
+* Y - COMPLEX array of dimension at least
+* ( 1 + ( n - 1 )*abs( INCY ) ).
+* Before entry, the incremented array Y must contain the n
+* element vector y. On exit, Y is overwritten by the updated
+* vector y.
+*
+* INCY - INTEGER.
+* On entry, INCY specifies the increment for the elements of
+* Y. INCY must not be zero.
+* Unchanged on exit.
+*
+* Further Details
+* ===============
+*
+* Level 2 Blas routine.
+*
+* -- Written on 22-October-1986.
+* Jack Dongarra, Argonne National Lab.
+* Jeremy Du Croz, Nag Central Office.
+* Sven Hammarling, Nag Central Office.
+* Richard Hanson, Sandia National Labs.
+*
+* =====================================================================
+*
+* .. Parameters ..
+ COMPLEX ONE
+ PARAMETER (ONE= (1.0E+0,0.0E+0))
+ COMPLEX ZERO
+ PARAMETER (ZERO= (0.0E+0,0.0E+0))
+* ..
+* .. Local Scalars ..
+ COMPLEX TEMP1,TEMP2
+ INTEGER I,INFO,IX,IY,J,JX,JY,K,KK,KX,KY
+* ..
+* .. External Functions ..
+ LOGICAL LSAME
+ EXTERNAL LSAME
+* ..
+* .. External Subroutines ..
+ EXTERNAL XERBLA
+* ..
+* .. Intrinsic Functions ..
+ INTRINSIC CONJG,REAL
+* ..
+*
+* Test the input parameters.
+*
+ INFO = 0
+ IF (.NOT.LSAME(UPLO,'U') .AND. .NOT.LSAME(UPLO,'L')) THEN
+ INFO = 1
+ ELSE IF (N.LT.0) THEN
+ INFO = 2
+ ELSE IF (INCX.EQ.0) THEN
+ INFO = 6
+ ELSE IF (INCY.EQ.0) THEN
+ INFO = 9
+ END IF
+ IF (INFO.NE.0) THEN
+ CALL XERBLA('CHPMV ',INFO)
+ RETURN
+ END IF
+*
+* Quick return if possible.
+*
+ IF ((N.EQ.0) .OR. ((ALPHA.EQ.ZERO).AND. (BETA.EQ.ONE))) RETURN
+*
+* Set up the start points in X and Y.
+*
+ IF (INCX.GT.0) THEN
+ KX = 1
+ ELSE
+ KX = 1 - (N-1)*INCX
+ END IF
+ IF (INCY.GT.0) THEN
+ KY = 1
+ ELSE
+ KY = 1 - (N-1)*INCY
+ END IF
+*
+* Start the operations. In this version the elements of the array AP
+* are accessed sequentially with one pass through AP.
+*
+* First form y := beta*y.
+*
+ IF (BETA.NE.ONE) THEN
+ IF (INCY.EQ.1) THEN
+ IF (BETA.EQ.ZERO) THEN
+ DO 10 I = 1,N
+ Y(I) = ZERO
+ 10 CONTINUE
+ ELSE
+ DO 20 I = 1,N
+ Y(I) = BETA*Y(I)
+ 20 CONTINUE
+ END IF
+ ELSE
+ IY = KY
+ IF (BETA.EQ.ZERO) THEN
+ DO 30 I = 1,N
+ Y(IY) = ZERO
+ IY = IY + INCY
+ 30 CONTINUE
+ ELSE
+ DO 40 I = 1,N
+ Y(IY) = BETA*Y(IY)
+ IY = IY + INCY
+ 40 CONTINUE
+ END IF
+ END IF
+ END IF
+ IF (ALPHA.EQ.ZERO) RETURN
+ KK = 1
+ IF (LSAME(UPLO,'U')) THEN
+*
+* Form y when AP contains the upper triangle.
+*
+ IF ((INCX.EQ.1) .AND. (INCY.EQ.1)) THEN
+ DO 60 J = 1,N
+ TEMP1 = ALPHA*X(J)
+ TEMP2 = ZERO
+ K = KK
+ DO 50 I = 1,J - 1
+ Y(I) = Y(I) + TEMP1*AP(K)
+ TEMP2 = TEMP2 + CONJG(AP(K))*X(I)
+ K = K + 1
+ 50 CONTINUE
+ Y(J) = Y(J) + TEMP1*REAL(AP(KK+J-1)) + ALPHA*TEMP2
+ KK = KK + J
+ 60 CONTINUE
+ ELSE
+ JX = KX
+ JY = KY
+ DO 80 J = 1,N
+ TEMP1 = ALPHA*X(JX)
+ TEMP2 = ZERO
+ IX = KX
+ IY = KY
+ DO 70 K = KK,KK + J - 2
+ Y(IY) = Y(IY) + TEMP1*AP(K)
+ TEMP2 = TEMP2 + CONJG(AP(K))*X(IX)
+ IX = IX + INCX
+ IY = IY + INCY
+ 70 CONTINUE
+ Y(JY) = Y(JY) + TEMP1*REAL(AP(KK+J-1)) + ALPHA*TEMP2
+ JX = JX + INCX
+ JY = JY + INCY
+ KK = KK + J
+ 80 CONTINUE
+ END IF
+ ELSE
+*
+* Form y when AP contains the lower triangle.
+*
+ IF ((INCX.EQ.1) .AND. (INCY.EQ.1)) THEN
+ DO 100 J = 1,N
+ TEMP1 = ALPHA*X(J)
+ TEMP2 = ZERO
+ Y(J) = Y(J) + TEMP1*REAL(AP(KK))
+ K = KK + 1
+ DO 90 I = J + 1,N
+ Y(I) = Y(I) + TEMP1*AP(K)
+ TEMP2 = TEMP2 + CONJG(AP(K))*X(I)
+ K = K + 1
+ 90 CONTINUE
+ Y(J) = Y(J) + ALPHA*TEMP2
+ KK = KK + (N-J+1)
+ 100 CONTINUE
+ ELSE
+ JX = KX
+ JY = KY
+ DO 120 J = 1,N
+ TEMP1 = ALPHA*X(JX)
+ TEMP2 = ZERO
+ Y(JY) = Y(JY) + TEMP1*REAL(AP(KK))
+ IX = JX
+ IY = JY
+ DO 110 K = KK + 1,KK + N - J
+ IX = IX + INCX
+ IY = IY + INCY
+ Y(IY) = Y(IY) + TEMP1*AP(K)
+ TEMP2 = TEMP2 + CONJG(AP(K))*X(IX)
+ 110 CONTINUE
+ Y(JY) = Y(JY) + ALPHA*TEMP2
+ JX = JX + INCX
+ JY = JY + INCY
+ KK = KK + (N-J+1)
+ 120 CONTINUE
+ END IF
+ END IF
+*
+ RETURN
+*
+* End of CHPMV .
+*
+ END
diff --git a/blas/chpr.f b/blas/chpr.f
new file mode 100644
index 000000000..11bd5c6ee
--- /dev/null
+++ b/blas/chpr.f
@@ -0,0 +1,220 @@
+ SUBROUTINE CHPR(UPLO,N,ALPHA,X,INCX,AP)
+* .. Scalar Arguments ..
+ REAL ALPHA
+ INTEGER INCX,N
+ CHARACTER UPLO
+* ..
+* .. Array Arguments ..
+ COMPLEX AP(*),X(*)
+* ..
+*
+* Purpose
+* =======
+*
+* CHPR performs the hermitian rank 1 operation
+*
+* A := alpha*x*conjg( x' ) + A,
+*
+* where alpha is a real scalar, x is an n element vector and A is an
+* n by n hermitian matrix, supplied in packed form.
+*
+* Arguments
+* ==========
+*
+* UPLO - CHARACTER*1.
+* On entry, UPLO specifies whether the upper or lower
+* triangular part of the matrix A is supplied in the packed
+* array AP as follows:
+*
+* UPLO = 'U' or 'u' The upper triangular part of A is
+* supplied in AP.
+*
+* UPLO = 'L' or 'l' The lower triangular part of A is
+* supplied in AP.
+*
+* Unchanged on exit.
+*
+* N - INTEGER.
+* On entry, N specifies the order of the matrix A.
+* N must be at least zero.
+* Unchanged on exit.
+*
+* ALPHA - REAL .
+* On entry, ALPHA specifies the scalar alpha.
+* Unchanged on exit.
+*
+* X - COMPLEX array of dimension at least
+* ( 1 + ( n - 1 )*abs( INCX ) ).
+* Before entry, the incremented array X must contain the n
+* element vector x.
+* Unchanged on exit.
+*
+* INCX - INTEGER.
+* On entry, INCX specifies the increment for the elements of
+* X. INCX must not be zero.
+* Unchanged on exit.
+*
+* AP - COMPLEX array of DIMENSION at least
+* ( ( n*( n + 1 ) )/2 ).
+* Before entry with UPLO = 'U' or 'u', the array AP must
+* contain the upper triangular part of the hermitian matrix
+* packed sequentially, column by column, so that AP( 1 )
+* contains a( 1, 1 ), AP( 2 ) and AP( 3 ) contain a( 1, 2 )
+* and a( 2, 2 ) respectively, and so on. On exit, the array
+* AP is overwritten by the upper triangular part of the
+* updated matrix.
+* Before entry with UPLO = 'L' or 'l', the array AP must
+* contain the lower triangular part of the hermitian matrix
+* packed sequentially, column by column, so that AP( 1 )
+* contains a( 1, 1 ), AP( 2 ) and AP( 3 ) contain a( 2, 1 )
+* and a( 3, 1 ) respectively, and so on. On exit, the array
+* AP is overwritten by the lower triangular part of the
+* updated matrix.
+* Note that the imaginary parts of the diagonal elements need
+* not be set, they are assumed to be zero, and on exit they
+* are set to zero.
+*
+* Further Details
+* ===============
+*
+* Level 2 Blas routine.
+*
+* -- Written on 22-October-1986.
+* Jack Dongarra, Argonne National Lab.
+* Jeremy Du Croz, Nag Central Office.
+* Sven Hammarling, Nag Central Office.
+* Richard Hanson, Sandia National Labs.
+*
+* =====================================================================
+*
+* .. Parameters ..
+ COMPLEX ZERO
+ PARAMETER (ZERO= (0.0E+0,0.0E+0))
+* ..
+* .. Local Scalars ..
+ COMPLEX TEMP
+ INTEGER I,INFO,IX,J,JX,K,KK,KX
+* ..
+* .. External Functions ..
+ LOGICAL LSAME
+ EXTERNAL LSAME
+* ..
+* .. External Subroutines ..
+ EXTERNAL XERBLA
+* ..
+* .. Intrinsic Functions ..
+ INTRINSIC CONJG,REAL
+* ..
+*
+* Test the input parameters.
+*
+ INFO = 0
+ IF (.NOT.LSAME(UPLO,'U') .AND. .NOT.LSAME(UPLO,'L')) THEN
+ INFO = 1
+ ELSE IF (N.LT.0) THEN
+ INFO = 2
+ ELSE IF (INCX.EQ.0) THEN
+ INFO = 5
+ END IF
+ IF (INFO.NE.0) THEN
+ CALL XERBLA('CHPR ',INFO)
+ RETURN
+ END IF
+*
+* Quick return if possible.
+*
+ IF ((N.EQ.0) .OR. (ALPHA.EQ.REAL(ZERO))) RETURN
+*
+* Set the start point in X if the increment is not unity.
+*
+ IF (INCX.LE.0) THEN
+ KX = 1 - (N-1)*INCX
+ ELSE IF (INCX.NE.1) THEN
+ KX = 1
+ END IF
+*
+* Start the operations. In this version the elements of the array AP
+* are accessed sequentially with one pass through AP.
+*
+ KK = 1
+ IF (LSAME(UPLO,'U')) THEN
+*
+* Form A when upper triangle is stored in AP.
+*
+ IF (INCX.EQ.1) THEN
+ DO 20 J = 1,N
+ IF (X(J).NE.ZERO) THEN
+ TEMP = ALPHA*CONJG(X(J))
+ K = KK
+ DO 10 I = 1,J - 1
+ AP(K) = AP(K) + X(I)*TEMP
+ K = K + 1
+ 10 CONTINUE
+ AP(KK+J-1) = REAL(AP(KK+J-1)) + REAL(X(J)*TEMP)
+ ELSE
+ AP(KK+J-1) = REAL(AP(KK+J-1))
+ END IF
+ KK = KK + J
+ 20 CONTINUE
+ ELSE
+ JX = KX
+ DO 40 J = 1,N
+ IF (X(JX).NE.ZERO) THEN
+ TEMP = ALPHA*CONJG(X(JX))
+ IX = KX
+ DO 30 K = KK,KK + J - 2
+ AP(K) = AP(K) + X(IX)*TEMP
+ IX = IX + INCX
+ 30 CONTINUE
+ AP(KK+J-1) = REAL(AP(KK+J-1)) + REAL(X(JX)*TEMP)
+ ELSE
+ AP(KK+J-1) = REAL(AP(KK+J-1))
+ END IF
+ JX = JX + INCX
+ KK = KK + J
+ 40 CONTINUE
+ END IF
+ ELSE
+*
+* Form A when lower triangle is stored in AP.
+*
+ IF (INCX.EQ.1) THEN
+ DO 60 J = 1,N
+ IF (X(J).NE.ZERO) THEN
+ TEMP = ALPHA*CONJG(X(J))
+ AP(KK) = REAL(AP(KK)) + REAL(TEMP*X(J))
+ K = KK + 1
+ DO 50 I = J + 1,N
+ AP(K) = AP(K) + X(I)*TEMP
+ K = K + 1
+ 50 CONTINUE
+ ELSE
+ AP(KK) = REAL(AP(KK))
+ END IF
+ KK = KK + N - J + 1
+ 60 CONTINUE
+ ELSE
+ JX = KX
+ DO 80 J = 1,N
+ IF (X(JX).NE.ZERO) THEN
+ TEMP = ALPHA*CONJG(X(JX))
+ AP(KK) = REAL(AP(KK)) + REAL(TEMP*X(JX))
+ IX = JX
+ DO 70 K = KK + 1,KK + N - J
+ IX = IX + INCX
+ AP(K) = AP(K) + X(IX)*TEMP
+ 70 CONTINUE
+ ELSE
+ AP(KK) = REAL(AP(KK))
+ END IF
+ JX = JX + INCX
+ KK = KK + N - J + 1
+ 80 CONTINUE
+ END IF
+ END IF
+*
+ RETURN
+*
+* End of CHPR .
+*
+ END
diff --git a/blas/chpr2.f b/blas/chpr2.f
new file mode 100644
index 000000000..a0020ef3e
--- /dev/null
+++ b/blas/chpr2.f
@@ -0,0 +1,255 @@
+ SUBROUTINE CHPR2(UPLO,N,ALPHA,X,INCX,Y,INCY,AP)
+* .. Scalar Arguments ..
+ COMPLEX ALPHA
+ INTEGER INCX,INCY,N
+ CHARACTER UPLO
+* ..
+* .. Array Arguments ..
+ COMPLEX AP(*),X(*),Y(*)
+* ..
+*
+* Purpose
+* =======
+*
+* CHPR2 performs the hermitian rank 2 operation
+*
+* A := alpha*x*conjg( y' ) + conjg( alpha )*y*conjg( x' ) + A,
+*
+* where alpha is a scalar, x and y are n element vectors and A is an
+* n by n hermitian matrix, supplied in packed form.
+*
+* Arguments
+* ==========
+*
+* UPLO - CHARACTER*1.
+* On entry, UPLO specifies whether the upper or lower
+* triangular part of the matrix A is supplied in the packed
+* array AP as follows:
+*
+* UPLO = 'U' or 'u' The upper triangular part of A is
+* supplied in AP.
+*
+* UPLO = 'L' or 'l' The lower triangular part of A is
+* supplied in AP.
+*
+* Unchanged on exit.
+*
+* N - INTEGER.
+* On entry, N specifies the order of the matrix A.
+* N must be at least zero.
+* Unchanged on exit.
+*
+* ALPHA - COMPLEX .
+* On entry, ALPHA specifies the scalar alpha.
+* Unchanged on exit.
+*
+* X - COMPLEX array of dimension at least
+* ( 1 + ( n - 1 )*abs( INCX ) ).
+* Before entry, the incremented array X must contain the n
+* element vector x.
+* Unchanged on exit.
+*
+* INCX - INTEGER.
+* On entry, INCX specifies the increment for the elements of
+* X. INCX must not be zero.
+* Unchanged on exit.
+*
+* Y - COMPLEX array of dimension at least
+* ( 1 + ( n - 1 )*abs( INCY ) ).
+* Before entry, the incremented array Y must contain the n
+* element vector y.
+* Unchanged on exit.
+*
+* INCY - INTEGER.
+* On entry, INCY specifies the increment for the elements of
+* Y. INCY must not be zero.
+* Unchanged on exit.
+*
+* AP - COMPLEX array of DIMENSION at least
+* ( ( n*( n + 1 ) )/2 ).
+* Before entry with UPLO = 'U' or 'u', the array AP must
+* contain the upper triangular part of the hermitian matrix
+* packed sequentially, column by column, so that AP( 1 )
+* contains a( 1, 1 ), AP( 2 ) and AP( 3 ) contain a( 1, 2 )
+* and a( 2, 2 ) respectively, and so on. On exit, the array
+* AP is overwritten by the upper triangular part of the
+* updated matrix.
+* Before entry with UPLO = 'L' or 'l', the array AP must
+* contain the lower triangular part of the hermitian matrix
+* packed sequentially, column by column, so that AP( 1 )
+* contains a( 1, 1 ), AP( 2 ) and AP( 3 ) contain a( 2, 1 )
+* and a( 3, 1 ) respectively, and so on. On exit, the array
+* AP is overwritten by the lower triangular part of the
+* updated matrix.
+* Note that the imaginary parts of the diagonal elements need
+* not be set, they are assumed to be zero, and on exit they
+* are set to zero.
+*
+* Further Details
+* ===============
+*
+* Level 2 Blas routine.
+*
+* -- Written on 22-October-1986.
+* Jack Dongarra, Argonne National Lab.
+* Jeremy Du Croz, Nag Central Office.
+* Sven Hammarling, Nag Central Office.
+* Richard Hanson, Sandia National Labs.
+*
+* =====================================================================
+*
+* .. Parameters ..
+ COMPLEX ZERO
+ PARAMETER (ZERO= (0.0E+0,0.0E+0))
+* ..
+* .. Local Scalars ..
+ COMPLEX TEMP1,TEMP2
+ INTEGER I,INFO,IX,IY,J,JX,JY,K,KK,KX,KY
+* ..
+* .. External Functions ..
+ LOGICAL LSAME
+ EXTERNAL LSAME
+* ..
+* .. External Subroutines ..
+ EXTERNAL XERBLA
+* ..
+* .. Intrinsic Functions ..
+ INTRINSIC CONJG,REAL
+* ..
+*
+* Test the input parameters.
+*
+ INFO = 0
+ IF (.NOT.LSAME(UPLO,'U') .AND. .NOT.LSAME(UPLO,'L')) THEN
+ INFO = 1
+ ELSE IF (N.LT.0) THEN
+ INFO = 2
+ ELSE IF (INCX.EQ.0) THEN
+ INFO = 5
+ ELSE IF (INCY.EQ.0) THEN
+ INFO = 7
+ END IF
+ IF (INFO.NE.0) THEN
+ CALL XERBLA('CHPR2 ',INFO)
+ RETURN
+ END IF
+*
+* Quick return if possible.
+*
+ IF ((N.EQ.0) .OR. (ALPHA.EQ.ZERO)) RETURN
+*
+* Set up the start points in X and Y if the increments are not both
+* unity.
+*
+ IF ((INCX.NE.1) .OR. (INCY.NE.1)) THEN
+ IF (INCX.GT.0) THEN
+ KX = 1
+ ELSE
+ KX = 1 - (N-1)*INCX
+ END IF
+ IF (INCY.GT.0) THEN
+ KY = 1
+ ELSE
+ KY = 1 - (N-1)*INCY
+ END IF
+ JX = KX
+ JY = KY
+ END IF
+*
+* Start the operations. In this version the elements of the array AP
+* are accessed sequentially with one pass through AP.
+*
+ KK = 1
+ IF (LSAME(UPLO,'U')) THEN
+*
+* Form A when upper triangle is stored in AP.
+*
+ IF ((INCX.EQ.1) .AND. (INCY.EQ.1)) THEN
+ DO 20 J = 1,N
+ IF ((X(J).NE.ZERO) .OR. (Y(J).NE.ZERO)) THEN
+ TEMP1 = ALPHA*CONJG(Y(J))
+ TEMP2 = CONJG(ALPHA*X(J))
+ K = KK
+ DO 10 I = 1,J - 1
+ AP(K) = AP(K) + X(I)*TEMP1 + Y(I)*TEMP2
+ K = K + 1
+ 10 CONTINUE
+ AP(KK+J-1) = REAL(AP(KK+J-1)) +
+ + REAL(X(J)*TEMP1+Y(J)*TEMP2)
+ ELSE
+ AP(KK+J-1) = REAL(AP(KK+J-1))
+ END IF
+ KK = KK + J
+ 20 CONTINUE
+ ELSE
+ DO 40 J = 1,N
+ IF ((X(JX).NE.ZERO) .OR. (Y(JY).NE.ZERO)) THEN
+ TEMP1 = ALPHA*CONJG(Y(JY))
+ TEMP2 = CONJG(ALPHA*X(JX))
+ IX = KX
+ IY = KY
+ DO 30 K = KK,KK + J - 2
+ AP(K) = AP(K) + X(IX)*TEMP1 + Y(IY)*TEMP2
+ IX = IX + INCX
+ IY = IY + INCY
+ 30 CONTINUE
+ AP(KK+J-1) = REAL(AP(KK+J-1)) +
+ + REAL(X(JX)*TEMP1+Y(JY)*TEMP2)
+ ELSE
+ AP(KK+J-1) = REAL(AP(KK+J-1))
+ END IF
+ JX = JX + INCX
+ JY = JY + INCY
+ KK = KK + J
+ 40 CONTINUE
+ END IF
+ ELSE
+*
+* Form A when lower triangle is stored in AP.
+*
+ IF ((INCX.EQ.1) .AND. (INCY.EQ.1)) THEN
+ DO 60 J = 1,N
+ IF ((X(J).NE.ZERO) .OR. (Y(J).NE.ZERO)) THEN
+ TEMP1 = ALPHA*CONJG(Y(J))
+ TEMP2 = CONJG(ALPHA*X(J))
+ AP(KK) = REAL(AP(KK)) +
+ + REAL(X(J)*TEMP1+Y(J)*TEMP2)
+ K = KK + 1
+ DO 50 I = J + 1,N
+ AP(K) = AP(K) + X(I)*TEMP1 + Y(I)*TEMP2
+ K = K + 1
+ 50 CONTINUE
+ ELSE
+ AP(KK) = REAL(AP(KK))
+ END IF
+ KK = KK + N - J + 1
+ 60 CONTINUE
+ ELSE
+ DO 80 J = 1,N
+ IF ((X(JX).NE.ZERO) .OR. (Y(JY).NE.ZERO)) THEN
+ TEMP1 = ALPHA*CONJG(Y(JY))
+ TEMP2 = CONJG(ALPHA*X(JX))
+ AP(KK) = REAL(AP(KK)) +
+ + REAL(X(JX)*TEMP1+Y(JY)*TEMP2)
+ IX = JX
+ IY = JY
+ DO 70 K = KK + 1,KK + N - J
+ IX = IX + INCX
+ IY = IY + INCY
+ AP(K) = AP(K) + X(IX)*TEMP1 + Y(IY)*TEMP2
+ 70 CONTINUE
+ ELSE
+ AP(KK) = REAL(AP(KK))
+ END IF
+ JX = JX + INCX
+ JY = JY + INCY
+ KK = KK + N - J + 1
+ 80 CONTINUE
+ END IF
+ END IF
+*
+ RETURN
+*
+* End of CHPR2 .
+*
+ END
diff --git a/blas/common.h b/blas/common.h
new file mode 100644
index 000000000..b598c4e45
--- /dev/null
+++ b/blas/common.h
@@ -0,0 +1,140 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra.
+//
+// Copyright (C) 2009-2010 Gael Guennebaud <gael.guennebaud@inria.fr>
+//
+// This Source Code Form is subject to the terms of the Mozilla
+// Public License v. 2.0. If a copy of the MPL was not distributed
+// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+#ifndef EIGEN_BLAS_COMMON_H
+#define EIGEN_BLAS_COMMON_H
+
+#include <iostream>
+#include <complex>
+
+#ifndef SCALAR
+#error the token SCALAR must be defined to compile this file
+#endif
+
+#include <Eigen/src/misc/blas.h>
+
+
+#define NOTR 0
+#define TR 1
+#define ADJ 2
+
+#define LEFT 0
+#define RIGHT 1
+
+#define UP 0
+#define LO 1
+
+#define NUNIT 0
+#define UNIT 1
+
+#define INVALID 0xff
+
+#define OP(X) ( ((X)=='N' || (X)=='n') ? NOTR \
+ : ((X)=='T' || (X)=='t') ? TR \
+ : ((X)=='C' || (X)=='c') ? ADJ \
+ : INVALID)
+
+#define SIDE(X) ( ((X)=='L' || (X)=='l') ? LEFT \
+ : ((X)=='R' || (X)=='r') ? RIGHT \
+ : INVALID)
+
+#define UPLO(X) ( ((X)=='U' || (X)=='u') ? UP \
+ : ((X)=='L' || (X)=='l') ? LO \
+ : INVALID)
+
+#define DIAG(X) ( ((X)=='N' || (X)=='N') ? NUNIT \
+ : ((X)=='U' || (X)=='u') ? UNIT \
+ : INVALID)
+
+
+inline bool check_op(const char* op)
+{
+ return OP(*op)!=0xff;
+}
+
+inline bool check_side(const char* side)
+{
+ return SIDE(*side)!=0xff;
+}
+
+inline bool check_uplo(const char* uplo)
+{
+ return UPLO(*uplo)!=0xff;
+}
+
+#include <Eigen/Core>
+#include <Eigen/Jacobi>
+
+
+namespace Eigen {
+#include "BandTriangularSolver.h"
+}
+
+using namespace Eigen;
+
+typedef SCALAR Scalar;
+typedef NumTraits<Scalar>::Real RealScalar;
+typedef std::complex<RealScalar> Complex;
+
+enum
+{
+ IsComplex = Eigen::NumTraits<SCALAR>::IsComplex,
+ Conj = IsComplex
+};
+
+typedef Matrix<Scalar,Dynamic,Dynamic,ColMajor> PlainMatrixType;
+typedef Map<Matrix<Scalar,Dynamic,Dynamic,ColMajor>, 0, OuterStride<> > MatrixType;
+typedef Map<Matrix<Scalar,Dynamic,1>, 0, InnerStride<Dynamic> > StridedVectorType;
+typedef Map<Matrix<Scalar,Dynamic,1> > CompactVectorType;
+
+template<typename T>
+Map<Matrix<T,Dynamic,Dynamic,ColMajor>, 0, OuterStride<> >
+matrix(T* data, int rows, int cols, int stride)
+{
+ return Map<Matrix<T,Dynamic,Dynamic,ColMajor>, 0, OuterStride<> >(data, rows, cols, OuterStride<>(stride));
+}
+
+template<typename T>
+Map<Matrix<T,Dynamic,1>, 0, InnerStride<Dynamic> > vector(T* data, int size, int incr)
+{
+ return Map<Matrix<T,Dynamic,1>, 0, InnerStride<Dynamic> >(data, size, InnerStride<Dynamic>(incr));
+}
+
+template<typename T>
+Map<Matrix<T,Dynamic,1> > vector(T* data, int size)
+{
+ return Map<Matrix<T,Dynamic,1> >(data, size);
+}
+
+template<typename T>
+T* get_compact_vector(T* x, int n, int incx)
+{
+ if(incx==1)
+ return x;
+
+ T* ret = new Scalar[n];
+ if(incx<0) vector(ret,n) = vector(x,n,-incx).reverse();
+ else vector(ret,n) = vector(x,n, incx);
+ return ret;
+}
+
+template<typename T>
+T* copy_back(T* x_cpy, T* x, int n, int incx)
+{
+ if(x_cpy==x)
+ return 0;
+
+ if(incx<0) vector(x,n,-incx).reverse() = vector(x_cpy,n);
+ else vector(x,n, incx) = vector(x_cpy,n);
+ return x_cpy;
+}
+
+#define EIGEN_BLAS_FUNC(X) EIGEN_CAT(SCALAR_SUFFIX,X##_)
+
+#endif // EIGEN_BLAS_COMMON_H
diff --git a/blas/complex_double.cpp b/blas/complex_double.cpp
new file mode 100644
index 000000000..648c6d4c6
--- /dev/null
+++ b/blas/complex_double.cpp
@@ -0,0 +1,20 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra.
+//
+// Copyright (C) 2009 Gael Guennebaud <gael.guennebaud@inria.fr>
+//
+// This Source Code Form is subject to the terms of the Mozilla
+// Public License v. 2.0. If a copy of the MPL was not distributed
+// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+#define SCALAR std::complex<double>
+#define SCALAR_SUFFIX z
+#define SCALAR_SUFFIX_UP "Z"
+#define REAL_SCALAR_SUFFIX d
+#define ISCOMPLEX 1
+
+#include "level1_impl.h"
+#include "level1_cplx_impl.h"
+#include "level2_impl.h"
+#include "level2_cplx_impl.h"
+#include "level3_impl.h"
diff --git a/blas/complex_single.cpp b/blas/complex_single.cpp
new file mode 100644
index 000000000..778651943
--- /dev/null
+++ b/blas/complex_single.cpp
@@ -0,0 +1,20 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra.
+//
+// Copyright (C) 2009 Gael Guennebaud <gael.guennebaud@inria.fr>
+//
+// This Source Code Form is subject to the terms of the Mozilla
+// Public License v. 2.0. If a copy of the MPL was not distributed
+// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+#define SCALAR std::complex<float>
+#define SCALAR_SUFFIX c
+#define SCALAR_SUFFIX_UP "C"
+#define REAL_SCALAR_SUFFIX s
+#define ISCOMPLEX 1
+
+#include "level1_impl.h"
+#include "level1_cplx_impl.h"
+#include "level2_impl.h"
+#include "level2_cplx_impl.h"
+#include "level3_impl.h"
diff --git a/blas/complexdots.f b/blas/complexdots.f
new file mode 100644
index 000000000..a7da51d16
--- /dev/null
+++ b/blas/complexdots.f
@@ -0,0 +1,43 @@
+ COMPLEX FUNCTION CDOTC(N,CX,INCX,CY,INCY)
+ INTEGER INCX,INCY,N
+ COMPLEX CX(*),CY(*)
+ COMPLEX RES
+ EXTERNAL CDOTCW
+
+ CALL CDOTCW(N,CX,INCX,CY,INCY,RES)
+ CDOTC = RES
+ RETURN
+ END
+
+ COMPLEX FUNCTION CDOTU(N,CX,INCX,CY,INCY)
+ INTEGER INCX,INCY,N
+ COMPLEX CX(*),CY(*)
+ COMPLEX RES
+ EXTERNAL CDOTUW
+
+ CALL CDOTUW(N,CX,INCX,CY,INCY,RES)
+ CDOTU = RES
+ RETURN
+ END
+
+ DOUBLE COMPLEX FUNCTION ZDOTC(N,CX,INCX,CY,INCY)
+ INTEGER INCX,INCY,N
+ DOUBLE COMPLEX CX(*),CY(*)
+ DOUBLE COMPLEX RES
+ EXTERNAL ZDOTCW
+
+ CALL ZDOTCW(N,CX,INCX,CY,INCY,RES)
+ ZDOTC = RES
+ RETURN
+ END
+
+ DOUBLE COMPLEX FUNCTION ZDOTU(N,CX,INCX,CY,INCY)
+ INTEGER INCX,INCY,N
+ DOUBLE COMPLEX CX(*),CY(*)
+ DOUBLE COMPLEX RES
+ EXTERNAL ZDOTUW
+
+ CALL ZDOTUW(N,CX,INCX,CY,INCY,RES)
+ ZDOTU = RES
+ RETURN
+ END
diff --git a/blas/ctbmv.f b/blas/ctbmv.f
new file mode 100644
index 000000000..5a879fa01
--- /dev/null
+++ b/blas/ctbmv.f
@@ -0,0 +1,366 @@
+ SUBROUTINE CTBMV(UPLO,TRANS,DIAG,N,K,A,LDA,X,INCX)
+* .. Scalar Arguments ..
+ INTEGER INCX,K,LDA,N
+ CHARACTER DIAG,TRANS,UPLO
+* ..
+* .. Array Arguments ..
+ COMPLEX A(LDA,*),X(*)
+* ..
+*
+* Purpose
+* =======
+*
+* CTBMV performs one of the matrix-vector operations
+*
+* x := A*x, or x := A'*x, or x := conjg( A' )*x,
+*
+* where x is an n element vector and A is an n by n unit, or non-unit,
+* upper or lower triangular band matrix, with ( k + 1 ) diagonals.
+*
+* Arguments
+* ==========
+*
+* UPLO - CHARACTER*1.
+* On entry, UPLO specifies whether the matrix is an upper or
+* lower triangular matrix as follows:
+*
+* UPLO = 'U' or 'u' A is an upper triangular matrix.
+*
+* UPLO = 'L' or 'l' A is a lower triangular matrix.
+*
+* Unchanged on exit.
+*
+* TRANS - CHARACTER*1.
+* On entry, TRANS specifies the operation to be performed as
+* follows:
+*
+* TRANS = 'N' or 'n' x := A*x.
+*
+* TRANS = 'T' or 't' x := A'*x.
+*
+* TRANS = 'C' or 'c' x := conjg( A' )*x.
+*
+* Unchanged on exit.
+*
+* DIAG - CHARACTER*1.
+* On entry, DIAG specifies whether or not A is unit
+* triangular as follows:
+*
+* DIAG = 'U' or 'u' A is assumed to be unit triangular.
+*
+* DIAG = 'N' or 'n' A is not assumed to be unit
+* triangular.
+*
+* Unchanged on exit.
+*
+* N - INTEGER.
+* On entry, N specifies the order of the matrix A.
+* N must be at least zero.
+* Unchanged on exit.
+*
+* K - INTEGER.
+* On entry with UPLO = 'U' or 'u', K specifies the number of
+* super-diagonals of the matrix A.
+* On entry with UPLO = 'L' or 'l', K specifies the number of
+* sub-diagonals of the matrix A.
+* K must satisfy 0 .le. K.
+* Unchanged on exit.
+*
+* A - COMPLEX array of DIMENSION ( LDA, n ).
+* Before entry with UPLO = 'U' or 'u', the leading ( k + 1 )
+* by n part of the array A must contain the upper triangular
+* band part of the matrix of coefficients, supplied column by
+* column, with the leading diagonal of the matrix in row
+* ( k + 1 ) of the array, the first super-diagonal starting at
+* position 2 in row k, and so on. The top left k by k triangle
+* of the array A is not referenced.
+* The following program segment will transfer an upper
+* triangular band matrix from conventional full matrix storage
+* to band storage:
+*
+* DO 20, J = 1, N
+* M = K + 1 - J
+* DO 10, I = MAX( 1, J - K ), J
+* A( M + I, J ) = matrix( I, J )
+* 10 CONTINUE
+* 20 CONTINUE
+*
+* Before entry with UPLO = 'L' or 'l', the leading ( k + 1 )
+* by n part of the array A must contain the lower triangular
+* band part of the matrix of coefficients, supplied column by
+* column, with the leading diagonal of the matrix in row 1 of
+* the array, the first sub-diagonal starting at position 1 in
+* row 2, and so on. The bottom right k by k triangle of the
+* array A is not referenced.
+* The following program segment will transfer a lower
+* triangular band matrix from conventional full matrix storage
+* to band storage:
+*
+* DO 20, J = 1, N
+* M = 1 - J
+* DO 10, I = J, MIN( N, J + K )
+* A( M + I, J ) = matrix( I, J )
+* 10 CONTINUE
+* 20 CONTINUE
+*
+* Note that when DIAG = 'U' or 'u' the elements of the array A
+* corresponding to the diagonal elements of the matrix are not
+* referenced, but are assumed to be unity.
+* Unchanged on exit.
+*
+* LDA - INTEGER.
+* On entry, LDA specifies the first dimension of A as declared
+* in the calling (sub) program. LDA must be at least
+* ( k + 1 ).
+* Unchanged on exit.
+*
+* X - COMPLEX array of dimension at least
+* ( 1 + ( n - 1 )*abs( INCX ) ).
+* Before entry, the incremented array X must contain the n
+* element vector x. On exit, X is overwritten with the
+* tranformed vector x.
+*
+* INCX - INTEGER.
+* On entry, INCX specifies the increment for the elements of
+* X. INCX must not be zero.
+* Unchanged on exit.
+*
+* Further Details
+* ===============
+*
+* Level 2 Blas routine.
+*
+* -- Written on 22-October-1986.
+* Jack Dongarra, Argonne National Lab.
+* Jeremy Du Croz, Nag Central Office.
+* Sven Hammarling, Nag Central Office.
+* Richard Hanson, Sandia National Labs.
+*
+* =====================================================================
+*
+* .. Parameters ..
+ COMPLEX ZERO
+ PARAMETER (ZERO= (0.0E+0,0.0E+0))
+* ..
+* .. Local Scalars ..
+ COMPLEX TEMP
+ INTEGER I,INFO,IX,J,JX,KPLUS1,KX,L
+ LOGICAL NOCONJ,NOUNIT
+* ..
+* .. External Functions ..
+ LOGICAL LSAME
+ EXTERNAL LSAME
+* ..
+* .. External Subroutines ..
+ EXTERNAL XERBLA
+* ..
+* .. Intrinsic Functions ..
+ INTRINSIC CONJG,MAX,MIN
+* ..
+*
+* Test the input parameters.
+*
+ INFO = 0
+ IF (.NOT.LSAME(UPLO,'U') .AND. .NOT.LSAME(UPLO,'L')) THEN
+ INFO = 1
+ ELSE IF (.NOT.LSAME(TRANS,'N') .AND. .NOT.LSAME(TRANS,'T') .AND.
+ + .NOT.LSAME(TRANS,'C')) THEN
+ INFO = 2
+ ELSE IF (.NOT.LSAME(DIAG,'U') .AND. .NOT.LSAME(DIAG,'N')) THEN
+ INFO = 3
+ ELSE IF (N.LT.0) THEN
+ INFO = 4
+ ELSE IF (K.LT.0) THEN
+ INFO = 5
+ ELSE IF (LDA.LT. (K+1)) THEN
+ INFO = 7
+ ELSE IF (INCX.EQ.0) THEN
+ INFO = 9
+ END IF
+ IF (INFO.NE.0) THEN
+ CALL XERBLA('CTBMV ',INFO)
+ RETURN
+ END IF
+*
+* Quick return if possible.
+*
+ IF (N.EQ.0) RETURN
+*
+ NOCONJ = LSAME(TRANS,'T')
+ NOUNIT = LSAME(DIAG,'N')
+*
+* Set up the start point in X if the increment is not unity. This
+* will be ( N - 1 )*INCX too small for descending loops.
+*
+ IF (INCX.LE.0) THEN
+ KX = 1 - (N-1)*INCX
+ ELSE IF (INCX.NE.1) THEN
+ KX = 1
+ END IF
+*
+* Start the operations. In this version the elements of A are
+* accessed sequentially with one pass through A.
+*
+ IF (LSAME(TRANS,'N')) THEN
+*
+* Form x := A*x.
+*
+ IF (LSAME(UPLO,'U')) THEN
+ KPLUS1 = K + 1
+ IF (INCX.EQ.1) THEN
+ DO 20 J = 1,N
+ IF (X(J).NE.ZERO) THEN
+ TEMP = X(J)
+ L = KPLUS1 - J
+ DO 10 I = MAX(1,J-K),J - 1
+ X(I) = X(I) + TEMP*A(L+I,J)
+ 10 CONTINUE
+ IF (NOUNIT) X(J) = X(J)*A(KPLUS1,J)
+ END IF
+ 20 CONTINUE
+ ELSE
+ JX = KX
+ DO 40 J = 1,N
+ IF (X(JX).NE.ZERO) THEN
+ TEMP = X(JX)
+ IX = KX
+ L = KPLUS1 - J
+ DO 30 I = MAX(1,J-K),J - 1
+ X(IX) = X(IX) + TEMP*A(L+I,J)
+ IX = IX + INCX
+ 30 CONTINUE
+ IF (NOUNIT) X(JX) = X(JX)*A(KPLUS1,J)
+ END IF
+ JX = JX + INCX
+ IF (J.GT.K) KX = KX + INCX
+ 40 CONTINUE
+ END IF
+ ELSE
+ IF (INCX.EQ.1) THEN
+ DO 60 J = N,1,-1
+ IF (X(J).NE.ZERO) THEN
+ TEMP = X(J)
+ L = 1 - J
+ DO 50 I = MIN(N,J+K),J + 1,-1
+ X(I) = X(I) + TEMP*A(L+I,J)
+ 50 CONTINUE
+ IF (NOUNIT) X(J) = X(J)*A(1,J)
+ END IF
+ 60 CONTINUE
+ ELSE
+ KX = KX + (N-1)*INCX
+ JX = KX
+ DO 80 J = N,1,-1
+ IF (X(JX).NE.ZERO) THEN
+ TEMP = X(JX)
+ IX = KX
+ L = 1 - J
+ DO 70 I = MIN(N,J+K),J + 1,-1
+ X(IX) = X(IX) + TEMP*A(L+I,J)
+ IX = IX - INCX
+ 70 CONTINUE
+ IF (NOUNIT) X(JX) = X(JX)*A(1,J)
+ END IF
+ JX = JX - INCX
+ IF ((N-J).GE.K) KX = KX - INCX
+ 80 CONTINUE
+ END IF
+ END IF
+ ELSE
+*
+* Form x := A'*x or x := conjg( A' )*x.
+*
+ IF (LSAME(UPLO,'U')) THEN
+ KPLUS1 = K + 1
+ IF (INCX.EQ.1) THEN
+ DO 110 J = N,1,-1
+ TEMP = X(J)
+ L = KPLUS1 - J
+ IF (NOCONJ) THEN
+ IF (NOUNIT) TEMP = TEMP*A(KPLUS1,J)
+ DO 90 I = J - 1,MAX(1,J-K),-1
+ TEMP = TEMP + A(L+I,J)*X(I)
+ 90 CONTINUE
+ ELSE
+ IF (NOUNIT) TEMP = TEMP*CONJG(A(KPLUS1,J))
+ DO 100 I = J - 1,MAX(1,J-K),-1
+ TEMP = TEMP + CONJG(A(L+I,J))*X(I)
+ 100 CONTINUE
+ END IF
+ X(J) = TEMP
+ 110 CONTINUE
+ ELSE
+ KX = KX + (N-1)*INCX
+ JX = KX
+ DO 140 J = N,1,-1
+ TEMP = X(JX)
+ KX = KX - INCX
+ IX = KX
+ L = KPLUS1 - J
+ IF (NOCONJ) THEN
+ IF (NOUNIT) TEMP = TEMP*A(KPLUS1,J)
+ DO 120 I = J - 1,MAX(1,J-K),-1
+ TEMP = TEMP + A(L+I,J)*X(IX)
+ IX = IX - INCX
+ 120 CONTINUE
+ ELSE
+ IF (NOUNIT) TEMP = TEMP*CONJG(A(KPLUS1,J))
+ DO 130 I = J - 1,MAX(1,J-K),-1
+ TEMP = TEMP + CONJG(A(L+I,J))*X(IX)
+ IX = IX - INCX
+ 130 CONTINUE
+ END IF
+ X(JX) = TEMP
+ JX = JX - INCX
+ 140 CONTINUE
+ END IF
+ ELSE
+ IF (INCX.EQ.1) THEN
+ DO 170 J = 1,N
+ TEMP = X(J)
+ L = 1 - J
+ IF (NOCONJ) THEN
+ IF (NOUNIT) TEMP = TEMP*A(1,J)
+ DO 150 I = J + 1,MIN(N,J+K)
+ TEMP = TEMP + A(L+I,J)*X(I)
+ 150 CONTINUE
+ ELSE
+ IF (NOUNIT) TEMP = TEMP*CONJG(A(1,J))
+ DO 160 I = J + 1,MIN(N,J+K)
+ TEMP = TEMP + CONJG(A(L+I,J))*X(I)
+ 160 CONTINUE
+ END IF
+ X(J) = TEMP
+ 170 CONTINUE
+ ELSE
+ JX = KX
+ DO 200 J = 1,N
+ TEMP = X(JX)
+ KX = KX + INCX
+ IX = KX
+ L = 1 - J
+ IF (NOCONJ) THEN
+ IF (NOUNIT) TEMP = TEMP*A(1,J)
+ DO 180 I = J + 1,MIN(N,J+K)
+ TEMP = TEMP + A(L+I,J)*X(IX)
+ IX = IX + INCX
+ 180 CONTINUE
+ ELSE
+ IF (NOUNIT) TEMP = TEMP*CONJG(A(1,J))
+ DO 190 I = J + 1,MIN(N,J+K)
+ TEMP = TEMP + CONJG(A(L+I,J))*X(IX)
+ IX = IX + INCX
+ 190 CONTINUE
+ END IF
+ X(JX) = TEMP
+ JX = JX + INCX
+ 200 CONTINUE
+ END IF
+ END IF
+ END IF
+*
+ RETURN
+*
+* End of CTBMV .
+*
+ END
diff --git a/blas/ctpmv.f b/blas/ctpmv.f
new file mode 100644
index 000000000..b63742ccb
--- /dev/null
+++ b/blas/ctpmv.f
@@ -0,0 +1,329 @@
+ SUBROUTINE CTPMV(UPLO,TRANS,DIAG,N,AP,X,INCX)
+* .. Scalar Arguments ..
+ INTEGER INCX,N
+ CHARACTER DIAG,TRANS,UPLO
+* ..
+* .. Array Arguments ..
+ COMPLEX AP(*),X(*)
+* ..
+*
+* Purpose
+* =======
+*
+* CTPMV performs one of the matrix-vector operations
+*
+* x := A*x, or x := A'*x, or x := conjg( A' )*x,
+*
+* where x is an n element vector and A is an n by n unit, or non-unit,
+* upper or lower triangular matrix, supplied in packed form.
+*
+* Arguments
+* ==========
+*
+* UPLO - CHARACTER*1.
+* On entry, UPLO specifies whether the matrix is an upper or
+* lower triangular matrix as follows:
+*
+* UPLO = 'U' or 'u' A is an upper triangular matrix.
+*
+* UPLO = 'L' or 'l' A is a lower triangular matrix.
+*
+* Unchanged on exit.
+*
+* TRANS - CHARACTER*1.
+* On entry, TRANS specifies the operation to be performed as
+* follows:
+*
+* TRANS = 'N' or 'n' x := A*x.
+*
+* TRANS = 'T' or 't' x := A'*x.
+*
+* TRANS = 'C' or 'c' x := conjg( A' )*x.
+*
+* Unchanged on exit.
+*
+* DIAG - CHARACTER*1.
+* On entry, DIAG specifies whether or not A is unit
+* triangular as follows:
+*
+* DIAG = 'U' or 'u' A is assumed to be unit triangular.
+*
+* DIAG = 'N' or 'n' A is not assumed to be unit
+* triangular.
+*
+* Unchanged on exit.
+*
+* N - INTEGER.
+* On entry, N specifies the order of the matrix A.
+* N must be at least zero.
+* Unchanged on exit.
+*
+* AP - COMPLEX array of DIMENSION at least
+* ( ( n*( n + 1 ) )/2 ).
+* Before entry with UPLO = 'U' or 'u', the array AP must
+* contain the upper triangular matrix packed sequentially,
+* column by column, so that AP( 1 ) contains a( 1, 1 ),
+* AP( 2 ) and AP( 3 ) contain a( 1, 2 ) and a( 2, 2 )
+* respectively, and so on.
+* Before entry with UPLO = 'L' or 'l', the array AP must
+* contain the lower triangular matrix packed sequentially,
+* column by column, so that AP( 1 ) contains a( 1, 1 ),
+* AP( 2 ) and AP( 3 ) contain a( 2, 1 ) and a( 3, 1 )
+* respectively, and so on.
+* Note that when DIAG = 'U' or 'u', the diagonal elements of
+* A are not referenced, but are assumed to be unity.
+* Unchanged on exit.
+*
+* X - COMPLEX array of dimension at least
+* ( 1 + ( n - 1 )*abs( INCX ) ).
+* Before entry, the incremented array X must contain the n
+* element vector x. On exit, X is overwritten with the
+* tranformed vector x.
+*
+* INCX - INTEGER.
+* On entry, INCX specifies the increment for the elements of
+* X. INCX must not be zero.
+* Unchanged on exit.
+*
+* Further Details
+* ===============
+*
+* Level 2 Blas routine.
+*
+* -- Written on 22-October-1986.
+* Jack Dongarra, Argonne National Lab.
+* Jeremy Du Croz, Nag Central Office.
+* Sven Hammarling, Nag Central Office.
+* Richard Hanson, Sandia National Labs.
+*
+* =====================================================================
+*
+* .. Parameters ..
+ COMPLEX ZERO
+ PARAMETER (ZERO= (0.0E+0,0.0E+0))
+* ..
+* .. Local Scalars ..
+ COMPLEX TEMP
+ INTEGER I,INFO,IX,J,JX,K,KK,KX
+ LOGICAL NOCONJ,NOUNIT
+* ..
+* .. External Functions ..
+ LOGICAL LSAME
+ EXTERNAL LSAME
+* ..
+* .. External Subroutines ..
+ EXTERNAL XERBLA
+* ..
+* .. Intrinsic Functions ..
+ INTRINSIC CONJG
+* ..
+*
+* Test the input parameters.
+*
+ INFO = 0
+ IF (.NOT.LSAME(UPLO,'U') .AND. .NOT.LSAME(UPLO,'L')) THEN
+ INFO = 1
+ ELSE IF (.NOT.LSAME(TRANS,'N') .AND. .NOT.LSAME(TRANS,'T') .AND.
+ + .NOT.LSAME(TRANS,'C')) THEN
+ INFO = 2
+ ELSE IF (.NOT.LSAME(DIAG,'U') .AND. .NOT.LSAME(DIAG,'N')) THEN
+ INFO = 3
+ ELSE IF (N.LT.0) THEN
+ INFO = 4
+ ELSE IF (INCX.EQ.0) THEN
+ INFO = 7
+ END IF
+ IF (INFO.NE.0) THEN
+ CALL XERBLA('CTPMV ',INFO)
+ RETURN
+ END IF
+*
+* Quick return if possible.
+*
+ IF (N.EQ.0) RETURN
+*
+ NOCONJ = LSAME(TRANS,'T')
+ NOUNIT = LSAME(DIAG,'N')
+*
+* Set up the start point in X if the increment is not unity. This
+* will be ( N - 1 )*INCX too small for descending loops.
+*
+ IF (INCX.LE.0) THEN
+ KX = 1 - (N-1)*INCX
+ ELSE IF (INCX.NE.1) THEN
+ KX = 1
+ END IF
+*
+* Start the operations. In this version the elements of AP are
+* accessed sequentially with one pass through AP.
+*
+ IF (LSAME(TRANS,'N')) THEN
+*
+* Form x:= A*x.
+*
+ IF (LSAME(UPLO,'U')) THEN
+ KK = 1
+ IF (INCX.EQ.1) THEN
+ DO 20 J = 1,N
+ IF (X(J).NE.ZERO) THEN
+ TEMP = X(J)
+ K = KK
+ DO 10 I = 1,J - 1
+ X(I) = X(I) + TEMP*AP(K)
+ K = K + 1
+ 10 CONTINUE
+ IF (NOUNIT) X(J) = X(J)*AP(KK+J-1)
+ END IF
+ KK = KK + J
+ 20 CONTINUE
+ ELSE
+ JX = KX
+ DO 40 J = 1,N
+ IF (X(JX).NE.ZERO) THEN
+ TEMP = X(JX)
+ IX = KX
+ DO 30 K = KK,KK + J - 2
+ X(IX) = X(IX) + TEMP*AP(K)
+ IX = IX + INCX
+ 30 CONTINUE
+ IF (NOUNIT) X(JX) = X(JX)*AP(KK+J-1)
+ END IF
+ JX = JX + INCX
+ KK = KK + J
+ 40 CONTINUE
+ END IF
+ ELSE
+ KK = (N* (N+1))/2
+ IF (INCX.EQ.1) THEN
+ DO 60 J = N,1,-1
+ IF (X(J).NE.ZERO) THEN
+ TEMP = X(J)
+ K = KK
+ DO 50 I = N,J + 1,-1
+ X(I) = X(I) + TEMP*AP(K)
+ K = K - 1
+ 50 CONTINUE
+ IF (NOUNIT) X(J) = X(J)*AP(KK-N+J)
+ END IF
+ KK = KK - (N-J+1)
+ 60 CONTINUE
+ ELSE
+ KX = KX + (N-1)*INCX
+ JX = KX
+ DO 80 J = N,1,-1
+ IF (X(JX).NE.ZERO) THEN
+ TEMP = X(JX)
+ IX = KX
+ DO 70 K = KK,KK - (N- (J+1)),-1
+ X(IX) = X(IX) + TEMP*AP(K)
+ IX = IX - INCX
+ 70 CONTINUE
+ IF (NOUNIT) X(JX) = X(JX)*AP(KK-N+J)
+ END IF
+ JX = JX - INCX
+ KK = KK - (N-J+1)
+ 80 CONTINUE
+ END IF
+ END IF
+ ELSE
+*
+* Form x := A'*x or x := conjg( A' )*x.
+*
+ IF (LSAME(UPLO,'U')) THEN
+ KK = (N* (N+1))/2
+ IF (INCX.EQ.1) THEN
+ DO 110 J = N,1,-1
+ TEMP = X(J)
+ K = KK - 1
+ IF (NOCONJ) THEN
+ IF (NOUNIT) TEMP = TEMP*AP(KK)
+ DO 90 I = J - 1,1,-1
+ TEMP = TEMP + AP(K)*X(I)
+ K = K - 1
+ 90 CONTINUE
+ ELSE
+ IF (NOUNIT) TEMP = TEMP*CONJG(AP(KK))
+ DO 100 I = J - 1,1,-1
+ TEMP = TEMP + CONJG(AP(K))*X(I)
+ K = K - 1
+ 100 CONTINUE
+ END IF
+ X(J) = TEMP
+ KK = KK - J
+ 110 CONTINUE
+ ELSE
+ JX = KX + (N-1)*INCX
+ DO 140 J = N,1,-1
+ TEMP = X(JX)
+ IX = JX
+ IF (NOCONJ) THEN
+ IF (NOUNIT) TEMP = TEMP*AP(KK)
+ DO 120 K = KK - 1,KK - J + 1,-1
+ IX = IX - INCX
+ TEMP = TEMP + AP(K)*X(IX)
+ 120 CONTINUE
+ ELSE
+ IF (NOUNIT) TEMP = TEMP*CONJG(AP(KK))
+ DO 130 K = KK - 1,KK - J + 1,-1
+ IX = IX - INCX
+ TEMP = TEMP + CONJG(AP(K))*X(IX)
+ 130 CONTINUE
+ END IF
+ X(JX) = TEMP
+ JX = JX - INCX
+ KK = KK - J
+ 140 CONTINUE
+ END IF
+ ELSE
+ KK = 1
+ IF (INCX.EQ.1) THEN
+ DO 170 J = 1,N
+ TEMP = X(J)
+ K = KK + 1
+ IF (NOCONJ) THEN
+ IF (NOUNIT) TEMP = TEMP*AP(KK)
+ DO 150 I = J + 1,N
+ TEMP = TEMP + AP(K)*X(I)
+ K = K + 1
+ 150 CONTINUE
+ ELSE
+ IF (NOUNIT) TEMP = TEMP*CONJG(AP(KK))
+ DO 160 I = J + 1,N
+ TEMP = TEMP + CONJG(AP(K))*X(I)
+ K = K + 1
+ 160 CONTINUE
+ END IF
+ X(J) = TEMP
+ KK = KK + (N-J+1)
+ 170 CONTINUE
+ ELSE
+ JX = KX
+ DO 200 J = 1,N
+ TEMP = X(JX)
+ IX = JX
+ IF (NOCONJ) THEN
+ IF (NOUNIT) TEMP = TEMP*AP(KK)
+ DO 180 K = KK + 1,KK + N - J
+ IX = IX + INCX
+ TEMP = TEMP + AP(K)*X(IX)
+ 180 CONTINUE
+ ELSE
+ IF (NOUNIT) TEMP = TEMP*CONJG(AP(KK))
+ DO 190 K = KK + 1,KK + N - J
+ IX = IX + INCX
+ TEMP = TEMP + CONJG(AP(K))*X(IX)
+ 190 CONTINUE
+ END IF
+ X(JX) = TEMP
+ JX = JX + INCX
+ KK = KK + (N-J+1)
+ 200 CONTINUE
+ END IF
+ END IF
+ END IF
+*
+ RETURN
+*
+* End of CTPMV .
+*
+ END
diff --git a/blas/ctpsv.f b/blas/ctpsv.f
new file mode 100644
index 000000000..1804797ea
--- /dev/null
+++ b/blas/ctpsv.f
@@ -0,0 +1,332 @@
+ SUBROUTINE CTPSV(UPLO,TRANS,DIAG,N,AP,X,INCX)
+* .. Scalar Arguments ..
+ INTEGER INCX,N
+ CHARACTER DIAG,TRANS,UPLO
+* ..
+* .. Array Arguments ..
+ COMPLEX AP(*),X(*)
+* ..
+*
+* Purpose
+* =======
+*
+* CTPSV solves one of the systems of equations
+*
+* A*x = b, or A'*x = b, or conjg( A' )*x = b,
+*
+* where b and x are n element vectors and A is an n by n unit, or
+* non-unit, upper or lower triangular matrix, supplied in packed form.
+*
+* No test for singularity or near-singularity is included in this
+* routine. Such tests must be performed before calling this routine.
+*
+* Arguments
+* ==========
+*
+* UPLO - CHARACTER*1.
+* On entry, UPLO specifies whether the matrix is an upper or
+* lower triangular matrix as follows:
+*
+* UPLO = 'U' or 'u' A is an upper triangular matrix.
+*
+* UPLO = 'L' or 'l' A is a lower triangular matrix.
+*
+* Unchanged on exit.
+*
+* TRANS - CHARACTER*1.
+* On entry, TRANS specifies the equations to be solved as
+* follows:
+*
+* TRANS = 'N' or 'n' A*x = b.
+*
+* TRANS = 'T' or 't' A'*x = b.
+*
+* TRANS = 'C' or 'c' conjg( A' )*x = b.
+*
+* Unchanged on exit.
+*
+* DIAG - CHARACTER*1.
+* On entry, DIAG specifies whether or not A is unit
+* triangular as follows:
+*
+* DIAG = 'U' or 'u' A is assumed to be unit triangular.
+*
+* DIAG = 'N' or 'n' A is not assumed to be unit
+* triangular.
+*
+* Unchanged on exit.
+*
+* N - INTEGER.
+* On entry, N specifies the order of the matrix A.
+* N must be at least zero.
+* Unchanged on exit.
+*
+* AP - COMPLEX array of DIMENSION at least
+* ( ( n*( n + 1 ) )/2 ).
+* Before entry with UPLO = 'U' or 'u', the array AP must
+* contain the upper triangular matrix packed sequentially,
+* column by column, so that AP( 1 ) contains a( 1, 1 ),
+* AP( 2 ) and AP( 3 ) contain a( 1, 2 ) and a( 2, 2 )
+* respectively, and so on.
+* Before entry with UPLO = 'L' or 'l', the array AP must
+* contain the lower triangular matrix packed sequentially,
+* column by column, so that AP( 1 ) contains a( 1, 1 ),
+* AP( 2 ) and AP( 3 ) contain a( 2, 1 ) and a( 3, 1 )
+* respectively, and so on.
+* Note that when DIAG = 'U' or 'u', the diagonal elements of
+* A are not referenced, but are assumed to be unity.
+* Unchanged on exit.
+*
+* X - COMPLEX array of dimension at least
+* ( 1 + ( n - 1 )*abs( INCX ) ).
+* Before entry, the incremented array X must contain the n
+* element right-hand side vector b. On exit, X is overwritten
+* with the solution vector x.
+*
+* INCX - INTEGER.
+* On entry, INCX specifies the increment for the elements of
+* X. INCX must not be zero.
+* Unchanged on exit.
+*
+* Further Details
+* ===============
+*
+* Level 2 Blas routine.
+*
+* -- Written on 22-October-1986.
+* Jack Dongarra, Argonne National Lab.
+* Jeremy Du Croz, Nag Central Office.
+* Sven Hammarling, Nag Central Office.
+* Richard Hanson, Sandia National Labs.
+*
+* =====================================================================
+*
+* .. Parameters ..
+ COMPLEX ZERO
+ PARAMETER (ZERO= (0.0E+0,0.0E+0))
+* ..
+* .. Local Scalars ..
+ COMPLEX TEMP
+ INTEGER I,INFO,IX,J,JX,K,KK,KX
+ LOGICAL NOCONJ,NOUNIT
+* ..
+* .. External Functions ..
+ LOGICAL LSAME
+ EXTERNAL LSAME
+* ..
+* .. External Subroutines ..
+ EXTERNAL XERBLA
+* ..
+* .. Intrinsic Functions ..
+ INTRINSIC CONJG
+* ..
+*
+* Test the input parameters.
+*
+ INFO = 0
+ IF (.NOT.LSAME(UPLO,'U') .AND. .NOT.LSAME(UPLO,'L')) THEN
+ INFO = 1
+ ELSE IF (.NOT.LSAME(TRANS,'N') .AND. .NOT.LSAME(TRANS,'T') .AND.
+ + .NOT.LSAME(TRANS,'C')) THEN
+ INFO = 2
+ ELSE IF (.NOT.LSAME(DIAG,'U') .AND. .NOT.LSAME(DIAG,'N')) THEN
+ INFO = 3
+ ELSE IF (N.LT.0) THEN
+ INFO = 4
+ ELSE IF (INCX.EQ.0) THEN
+ INFO = 7
+ END IF
+ IF (INFO.NE.0) THEN
+ CALL XERBLA('CTPSV ',INFO)
+ RETURN
+ END IF
+*
+* Quick return if possible.
+*
+ IF (N.EQ.0) RETURN
+*
+ NOCONJ = LSAME(TRANS,'T')
+ NOUNIT = LSAME(DIAG,'N')
+*
+* Set up the start point in X if the increment is not unity. This
+* will be ( N - 1 )*INCX too small for descending loops.
+*
+ IF (INCX.LE.0) THEN
+ KX = 1 - (N-1)*INCX
+ ELSE IF (INCX.NE.1) THEN
+ KX = 1
+ END IF
+*
+* Start the operations. In this version the elements of AP are
+* accessed sequentially with one pass through AP.
+*
+ IF (LSAME(TRANS,'N')) THEN
+*
+* Form x := inv( A )*x.
+*
+ IF (LSAME(UPLO,'U')) THEN
+ KK = (N* (N+1))/2
+ IF (INCX.EQ.1) THEN
+ DO 20 J = N,1,-1
+ IF (X(J).NE.ZERO) THEN
+ IF (NOUNIT) X(J) = X(J)/AP(KK)
+ TEMP = X(J)
+ K = KK - 1
+ DO 10 I = J - 1,1,-1
+ X(I) = X(I) - TEMP*AP(K)
+ K = K - 1
+ 10 CONTINUE
+ END IF
+ KK = KK - J
+ 20 CONTINUE
+ ELSE
+ JX = KX + (N-1)*INCX
+ DO 40 J = N,1,-1
+ IF (X(JX).NE.ZERO) THEN
+ IF (NOUNIT) X(JX) = X(JX)/AP(KK)
+ TEMP = X(JX)
+ IX = JX
+ DO 30 K = KK - 1,KK - J + 1,-1
+ IX = IX - INCX
+ X(IX) = X(IX) - TEMP*AP(K)
+ 30 CONTINUE
+ END IF
+ JX = JX - INCX
+ KK = KK - J
+ 40 CONTINUE
+ END IF
+ ELSE
+ KK = 1
+ IF (INCX.EQ.1) THEN
+ DO 60 J = 1,N
+ IF (X(J).NE.ZERO) THEN
+ IF (NOUNIT) X(J) = X(J)/AP(KK)
+ TEMP = X(J)
+ K = KK + 1
+ DO 50 I = J + 1,N
+ X(I) = X(I) - TEMP*AP(K)
+ K = K + 1
+ 50 CONTINUE
+ END IF
+ KK = KK + (N-J+1)
+ 60 CONTINUE
+ ELSE
+ JX = KX
+ DO 80 J = 1,N
+ IF (X(JX).NE.ZERO) THEN
+ IF (NOUNIT) X(JX) = X(JX)/AP(KK)
+ TEMP = X(JX)
+ IX = JX
+ DO 70 K = KK + 1,KK + N - J
+ IX = IX + INCX
+ X(IX) = X(IX) - TEMP*AP(K)
+ 70 CONTINUE
+ END IF
+ JX = JX + INCX
+ KK = KK + (N-J+1)
+ 80 CONTINUE
+ END IF
+ END IF
+ ELSE
+*
+* Form x := inv( A' )*x or x := inv( conjg( A' ) )*x.
+*
+ IF (LSAME(UPLO,'U')) THEN
+ KK = 1
+ IF (INCX.EQ.1) THEN
+ DO 110 J = 1,N
+ TEMP = X(J)
+ K = KK
+ IF (NOCONJ) THEN
+ DO 90 I = 1,J - 1
+ TEMP = TEMP - AP(K)*X(I)
+ K = K + 1
+ 90 CONTINUE
+ IF (NOUNIT) TEMP = TEMP/AP(KK+J-1)
+ ELSE
+ DO 100 I = 1,J - 1
+ TEMP = TEMP - CONJG(AP(K))*X(I)
+ K = K + 1
+ 100 CONTINUE
+ IF (NOUNIT) TEMP = TEMP/CONJG(AP(KK+J-1))
+ END IF
+ X(J) = TEMP
+ KK = KK + J
+ 110 CONTINUE
+ ELSE
+ JX = KX
+ DO 140 J = 1,N
+ TEMP = X(JX)
+ IX = KX
+ IF (NOCONJ) THEN
+ DO 120 K = KK,KK + J - 2
+ TEMP = TEMP - AP(K)*X(IX)
+ IX = IX + INCX
+ 120 CONTINUE
+ IF (NOUNIT) TEMP = TEMP/AP(KK+J-1)
+ ELSE
+ DO 130 K = KK,KK + J - 2
+ TEMP = TEMP - CONJG(AP(K))*X(IX)
+ IX = IX + INCX
+ 130 CONTINUE
+ IF (NOUNIT) TEMP = TEMP/CONJG(AP(KK+J-1))
+ END IF
+ X(JX) = TEMP
+ JX = JX + INCX
+ KK = KK + J
+ 140 CONTINUE
+ END IF
+ ELSE
+ KK = (N* (N+1))/2
+ IF (INCX.EQ.1) THEN
+ DO 170 J = N,1,-1
+ TEMP = X(J)
+ K = KK
+ IF (NOCONJ) THEN
+ DO 150 I = N,J + 1,-1
+ TEMP = TEMP - AP(K)*X(I)
+ K = K - 1
+ 150 CONTINUE
+ IF (NOUNIT) TEMP = TEMP/AP(KK-N+J)
+ ELSE
+ DO 160 I = N,J + 1,-1
+ TEMP = TEMP - CONJG(AP(K))*X(I)
+ K = K - 1
+ 160 CONTINUE
+ IF (NOUNIT) TEMP = TEMP/CONJG(AP(KK-N+J))
+ END IF
+ X(J) = TEMP
+ KK = KK - (N-J+1)
+ 170 CONTINUE
+ ELSE
+ KX = KX + (N-1)*INCX
+ JX = KX
+ DO 200 J = N,1,-1
+ TEMP = X(JX)
+ IX = KX
+ IF (NOCONJ) THEN
+ DO 180 K = KK,KK - (N- (J+1)),-1
+ TEMP = TEMP - AP(K)*X(IX)
+ IX = IX - INCX
+ 180 CONTINUE
+ IF (NOUNIT) TEMP = TEMP/AP(KK-N+J)
+ ELSE
+ DO 190 K = KK,KK - (N- (J+1)),-1
+ TEMP = TEMP - CONJG(AP(K))*X(IX)
+ IX = IX - INCX
+ 190 CONTINUE
+ IF (NOUNIT) TEMP = TEMP/CONJG(AP(KK-N+J))
+ END IF
+ X(JX) = TEMP
+ JX = JX - INCX
+ KK = KK - (N-J+1)
+ 200 CONTINUE
+ END IF
+ END IF
+ END IF
+*
+ RETURN
+*
+* End of CTPSV .
+*
+ END
diff --git a/blas/double.cpp b/blas/double.cpp
new file mode 100644
index 000000000..cad2f63ec
--- /dev/null
+++ b/blas/double.cpp
@@ -0,0 +1,19 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra.
+//
+// Copyright (C) 2009 Gael Guennebaud <gael.guennebaud@inria.fr>
+//
+// This Source Code Form is subject to the terms of the Mozilla
+// Public License v. 2.0. If a copy of the MPL was not distributed
+// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+#define SCALAR double
+#define SCALAR_SUFFIX d
+#define SCALAR_SUFFIX_UP "D"
+#define ISCOMPLEX 0
+
+#include "level1_impl.h"
+#include "level1_real_impl.h"
+#include "level2_impl.h"
+#include "level2_real_impl.h"
+#include "level3_impl.h"
diff --git a/blas/drotm.f b/blas/drotm.f
new file mode 100644
index 000000000..63a3b1134
--- /dev/null
+++ b/blas/drotm.f
@@ -0,0 +1,147 @@
+ SUBROUTINE DROTM(N,DX,INCX,DY,INCY,DPARAM)
+* .. Scalar Arguments ..
+ INTEGER INCX,INCY,N
+* ..
+* .. Array Arguments ..
+ DOUBLE PRECISION DPARAM(5),DX(*),DY(*)
+* ..
+*
+* Purpose
+* =======
+*
+* APPLY THE MODIFIED GIVENS TRANSFORMATION, H, TO THE 2 BY N MATRIX
+*
+* (DX**T) , WHERE **T INDICATES TRANSPOSE. THE ELEMENTS OF DX ARE IN
+* (DY**T)
+*
+* DX(LX+I*INCX), I = 0 TO N-1, WHERE LX = 1 IF INCX .GE. 0, ELSE
+* LX = (-INCX)*N, AND SIMILARLY FOR SY USING LY AND INCY.
+* WITH DPARAM(1)=DFLAG, H HAS ONE OF THE FOLLOWING FORMS..
+*
+* DFLAG=-1.D0 DFLAG=0.D0 DFLAG=1.D0 DFLAG=-2.D0
+*
+* (DH11 DH12) (1.D0 DH12) (DH11 1.D0) (1.D0 0.D0)
+* H=( ) ( ) ( ) ( )
+* (DH21 DH22), (DH21 1.D0), (-1.D0 DH22), (0.D0 1.D0).
+* SEE DROTMG FOR A DESCRIPTION OF DATA STORAGE IN DPARAM.
+*
+* Arguments
+* =========
+*
+* N (input) INTEGER
+* number of elements in input vector(s)
+*
+* DX (input/output) DOUBLE PRECISION array, dimension N
+* double precision vector with N elements
+*
+* INCX (input) INTEGER
+* storage spacing between elements of DX
+*
+* DY (input/output) DOUBLE PRECISION array, dimension N
+* double precision vector with N elements
+*
+* INCY (input) INTEGER
+* storage spacing between elements of DY
+*
+* DPARAM (input/output) DOUBLE PRECISION array, dimension 5
+* DPARAM(1)=DFLAG
+* DPARAM(2)=DH11
+* DPARAM(3)=DH21
+* DPARAM(4)=DH12
+* DPARAM(5)=DH22
+*
+* =====================================================================
+*
+* .. Local Scalars ..
+ DOUBLE PRECISION DFLAG,DH11,DH12,DH21,DH22,TWO,W,Z,ZERO
+ INTEGER I,KX,KY,NSTEPS
+* ..
+* .. Data statements ..
+ DATA ZERO,TWO/0.D0,2.D0/
+* ..
+*
+ DFLAG = DPARAM(1)
+ IF (N.LE.0 .OR. (DFLAG+TWO.EQ.ZERO)) GO TO 140
+ IF (.NOT. (INCX.EQ.INCY.AND.INCX.GT.0)) GO TO 70
+*
+ NSTEPS = N*INCX
+ IF (DFLAG) 50,10,30
+ 10 CONTINUE
+ DH12 = DPARAM(4)
+ DH21 = DPARAM(3)
+ DO 20 I = 1,NSTEPS,INCX
+ W = DX(I)
+ Z = DY(I)
+ DX(I) = W + Z*DH12
+ DY(I) = W*DH21 + Z
+ 20 CONTINUE
+ GO TO 140
+ 30 CONTINUE
+ DH11 = DPARAM(2)
+ DH22 = DPARAM(5)
+ DO 40 I = 1,NSTEPS,INCX
+ W = DX(I)
+ Z = DY(I)
+ DX(I) = W*DH11 + Z
+ DY(I) = -W + DH22*Z
+ 40 CONTINUE
+ GO TO 140
+ 50 CONTINUE
+ DH11 = DPARAM(2)
+ DH12 = DPARAM(4)
+ DH21 = DPARAM(3)
+ DH22 = DPARAM(5)
+ DO 60 I = 1,NSTEPS,INCX
+ W = DX(I)
+ Z = DY(I)
+ DX(I) = W*DH11 + Z*DH12
+ DY(I) = W*DH21 + Z*DH22
+ 60 CONTINUE
+ GO TO 140
+ 70 CONTINUE
+ KX = 1
+ KY = 1
+ IF (INCX.LT.0) KX = 1 + (1-N)*INCX
+ IF (INCY.LT.0) KY = 1 + (1-N)*INCY
+*
+ IF (DFLAG) 120,80,100
+ 80 CONTINUE
+ DH12 = DPARAM(4)
+ DH21 = DPARAM(3)
+ DO 90 I = 1,N
+ W = DX(KX)
+ Z = DY(KY)
+ DX(KX) = W + Z*DH12
+ DY(KY) = W*DH21 + Z
+ KX = KX + INCX
+ KY = KY + INCY
+ 90 CONTINUE
+ GO TO 140
+ 100 CONTINUE
+ DH11 = DPARAM(2)
+ DH22 = DPARAM(5)
+ DO 110 I = 1,N
+ W = DX(KX)
+ Z = DY(KY)
+ DX(KX) = W*DH11 + Z
+ DY(KY) = -W + DH22*Z
+ KX = KX + INCX
+ KY = KY + INCY
+ 110 CONTINUE
+ GO TO 140
+ 120 CONTINUE
+ DH11 = DPARAM(2)
+ DH12 = DPARAM(4)
+ DH21 = DPARAM(3)
+ DH22 = DPARAM(5)
+ DO 130 I = 1,N
+ W = DX(KX)
+ Z = DY(KY)
+ DX(KX) = W*DH11 + Z*DH12
+ DY(KY) = W*DH21 + Z*DH22
+ KX = KX + INCX
+ KY = KY + INCY
+ 130 CONTINUE
+ 140 CONTINUE
+ RETURN
+ END
diff --git a/blas/drotmg.f b/blas/drotmg.f
new file mode 100644
index 000000000..3ae647b08
--- /dev/null
+++ b/blas/drotmg.f
@@ -0,0 +1,206 @@
+ SUBROUTINE DROTMG(DD1,DD2,DX1,DY1,DPARAM)
+* .. Scalar Arguments ..
+ DOUBLE PRECISION DD1,DD2,DX1,DY1
+* ..
+* .. Array Arguments ..
+ DOUBLE PRECISION DPARAM(5)
+* ..
+*
+* Purpose
+* =======
+*
+* CONSTRUCT THE MODIFIED GIVENS TRANSFORMATION MATRIX H WHICH ZEROS
+* THE SECOND COMPONENT OF THE 2-VECTOR (DSQRT(DD1)*DX1,DSQRT(DD2)*
+* DY2)**T.
+* WITH DPARAM(1)=DFLAG, H HAS ONE OF THE FOLLOWING FORMS..
+*
+* DFLAG=-1.D0 DFLAG=0.D0 DFLAG=1.D0 DFLAG=-2.D0
+*
+* (DH11 DH12) (1.D0 DH12) (DH11 1.D0) (1.D0 0.D0)
+* H=( ) ( ) ( ) ( )
+* (DH21 DH22), (DH21 1.D0), (-1.D0 DH22), (0.D0 1.D0).
+* LOCATIONS 2-4 OF DPARAM CONTAIN DH11, DH21, DH12, AND DH22
+* RESPECTIVELY. (VALUES OF 1.D0, -1.D0, OR 0.D0 IMPLIED BY THE
+* VALUE OF DPARAM(1) ARE NOT STORED IN DPARAM.)
+*
+* THE VALUES OF GAMSQ AND RGAMSQ SET IN THE DATA STATEMENT MAY BE
+* INEXACT. THIS IS OK AS THEY ARE ONLY USED FOR TESTING THE SIZE
+* OF DD1 AND DD2. ALL ACTUAL SCALING OF DATA IS DONE USING GAM.
+*
+*
+* Arguments
+* =========
+*
+* DD1 (input/output) DOUBLE PRECISION
+*
+* DD2 (input/output) DOUBLE PRECISION
+*
+* DX1 (input/output) DOUBLE PRECISION
+*
+* DY1 (input) DOUBLE PRECISION
+*
+* DPARAM (input/output) DOUBLE PRECISION array, dimension 5
+* DPARAM(1)=DFLAG
+* DPARAM(2)=DH11
+* DPARAM(3)=DH21
+* DPARAM(4)=DH12
+* DPARAM(5)=DH22
+*
+* =====================================================================
+*
+* .. Local Scalars ..
+ DOUBLE PRECISION DFLAG,DH11,DH12,DH21,DH22,DP1,DP2,DQ1,DQ2,DTEMP,
+ + DU,GAM,GAMSQ,ONE,RGAMSQ,TWO,ZERO
+ INTEGER IGO
+* ..
+* .. Intrinsic Functions ..
+ INTRINSIC DABS
+* ..
+* .. Data statements ..
+*
+ DATA ZERO,ONE,TWO/0.D0,1.D0,2.D0/
+ DATA GAM,GAMSQ,RGAMSQ/4096.D0,16777216.D0,5.9604645D-8/
+* ..
+
+ IF (.NOT.DD1.LT.ZERO) GO TO 10
+* GO ZERO-H-D-AND-DX1..
+ GO TO 60
+ 10 CONTINUE
+* CASE-DD1-NONNEGATIVE
+ DP2 = DD2*DY1
+ IF (.NOT.DP2.EQ.ZERO) GO TO 20
+ DFLAG = -TWO
+ GO TO 260
+* REGULAR-CASE..
+ 20 CONTINUE
+ DP1 = DD1*DX1
+ DQ2 = DP2*DY1
+ DQ1 = DP1*DX1
+*
+ IF (.NOT.DABS(DQ1).GT.DABS(DQ2)) GO TO 40
+ DH21 = -DY1/DX1
+ DH12 = DP2/DP1
+*
+ DU = ONE - DH12*DH21
+*
+ IF (.NOT.DU.LE.ZERO) GO TO 30
+* GO ZERO-H-D-AND-DX1..
+ GO TO 60
+ 30 CONTINUE
+ DFLAG = ZERO
+ DD1 = DD1/DU
+ DD2 = DD2/DU
+ DX1 = DX1*DU
+* GO SCALE-CHECK..
+ GO TO 100
+ 40 CONTINUE
+ IF (.NOT.DQ2.LT.ZERO) GO TO 50
+* GO ZERO-H-D-AND-DX1..
+ GO TO 60
+ 50 CONTINUE
+ DFLAG = ONE
+ DH11 = DP1/DP2
+ DH22 = DX1/DY1
+ DU = ONE + DH11*DH22
+ DTEMP = DD2/DU
+ DD2 = DD1/DU
+ DD1 = DTEMP
+ DX1 = DY1*DU
+* GO SCALE-CHECK
+ GO TO 100
+* PROCEDURE..ZERO-H-D-AND-DX1..
+ 60 CONTINUE
+ DFLAG = -ONE
+ DH11 = ZERO
+ DH12 = ZERO
+ DH21 = ZERO
+ DH22 = ZERO
+*
+ DD1 = ZERO
+ DD2 = ZERO
+ DX1 = ZERO
+* RETURN..
+ GO TO 220
+* PROCEDURE..FIX-H..
+ 70 CONTINUE
+ IF (.NOT.DFLAG.GE.ZERO) GO TO 90
+*
+ IF (.NOT.DFLAG.EQ.ZERO) GO TO 80
+ DH11 = ONE
+ DH22 = ONE
+ DFLAG = -ONE
+ GO TO 90
+ 80 CONTINUE
+ DH21 = -ONE
+ DH12 = ONE
+ DFLAG = -ONE
+ 90 CONTINUE
+ GO TO IGO(120,150,180,210)
+* PROCEDURE..SCALE-CHECK
+ 100 CONTINUE
+ 110 CONTINUE
+ IF (.NOT.DD1.LE.RGAMSQ) GO TO 130
+ IF (DD1.EQ.ZERO) GO TO 160
+ ASSIGN 120 TO IGO
+* FIX-H..
+ GO TO 70
+ 120 CONTINUE
+ DD1 = DD1*GAM**2
+ DX1 = DX1/GAM
+ DH11 = DH11/GAM
+ DH12 = DH12/GAM
+ GO TO 110
+ 130 CONTINUE
+ 140 CONTINUE
+ IF (.NOT.DD1.GE.GAMSQ) GO TO 160
+ ASSIGN 150 TO IGO
+* FIX-H..
+ GO TO 70
+ 150 CONTINUE
+ DD1 = DD1/GAM**2
+ DX1 = DX1*GAM
+ DH11 = DH11*GAM
+ DH12 = DH12*GAM
+ GO TO 140
+ 160 CONTINUE
+ 170 CONTINUE
+ IF (.NOT.DABS(DD2).LE.RGAMSQ) GO TO 190
+ IF (DD2.EQ.ZERO) GO TO 220
+ ASSIGN 180 TO IGO
+* FIX-H..
+ GO TO 70
+ 180 CONTINUE
+ DD2 = DD2*GAM**2
+ DH21 = DH21/GAM
+ DH22 = DH22/GAM
+ GO TO 170
+ 190 CONTINUE
+ 200 CONTINUE
+ IF (.NOT.DABS(DD2).GE.GAMSQ) GO TO 220
+ ASSIGN 210 TO IGO
+* FIX-H..
+ GO TO 70
+ 210 CONTINUE
+ DD2 = DD2/GAM**2
+ DH21 = DH21*GAM
+ DH22 = DH22*GAM
+ GO TO 200
+ 220 CONTINUE
+ IF (DFLAG) 250,230,240
+ 230 CONTINUE
+ DPARAM(3) = DH21
+ DPARAM(4) = DH12
+ GO TO 260
+ 240 CONTINUE
+ DPARAM(2) = DH11
+ DPARAM(5) = DH22
+ GO TO 260
+ 250 CONTINUE
+ DPARAM(2) = DH11
+ DPARAM(3) = DH21
+ DPARAM(4) = DH12
+ DPARAM(5) = DH22
+ 260 CONTINUE
+ DPARAM(1) = DFLAG
+ RETURN
+ END
diff --git a/blas/dsbmv.f b/blas/dsbmv.f
new file mode 100644
index 000000000..8c82d1fa1
--- /dev/null
+++ b/blas/dsbmv.f
@@ -0,0 +1,304 @@
+ SUBROUTINE DSBMV(UPLO,N,K,ALPHA,A,LDA,X,INCX,BETA,Y,INCY)
+* .. Scalar Arguments ..
+ DOUBLE PRECISION ALPHA,BETA
+ INTEGER INCX,INCY,K,LDA,N
+ CHARACTER UPLO
+* ..
+* .. Array Arguments ..
+ DOUBLE PRECISION A(LDA,*),X(*),Y(*)
+* ..
+*
+* Purpose
+* =======
+*
+* DSBMV performs the matrix-vector operation
+*
+* y := alpha*A*x + beta*y,
+*
+* where alpha and beta are scalars, x and y are n element vectors and
+* A is an n by n symmetric band matrix, with k super-diagonals.
+*
+* Arguments
+* ==========
+*
+* UPLO - CHARACTER*1.
+* On entry, UPLO specifies whether the upper or lower
+* triangular part of the band matrix A is being supplied as
+* follows:
+*
+* UPLO = 'U' or 'u' The upper triangular part of A is
+* being supplied.
+*
+* UPLO = 'L' or 'l' The lower triangular part of A is
+* being supplied.
+*
+* Unchanged on exit.
+*
+* N - INTEGER.
+* On entry, N specifies the order of the matrix A.
+* N must be at least zero.
+* Unchanged on exit.
+*
+* K - INTEGER.
+* On entry, K specifies the number of super-diagonals of the
+* matrix A. K must satisfy 0 .le. K.
+* Unchanged on exit.
+*
+* ALPHA - DOUBLE PRECISION.
+* On entry, ALPHA specifies the scalar alpha.
+* Unchanged on exit.
+*
+* A - DOUBLE PRECISION array of DIMENSION ( LDA, n ).
+* Before entry with UPLO = 'U' or 'u', the leading ( k + 1 )
+* by n part of the array A must contain the upper triangular
+* band part of the symmetric matrix, supplied column by
+* column, with the leading diagonal of the matrix in row
+* ( k + 1 ) of the array, the first super-diagonal starting at
+* position 2 in row k, and so on. The top left k by k triangle
+* of the array A is not referenced.
+* The following program segment will transfer the upper
+* triangular part of a symmetric band matrix from conventional
+* full matrix storage to band storage:
+*
+* DO 20, J = 1, N
+* M = K + 1 - J
+* DO 10, I = MAX( 1, J - K ), J
+* A( M + I, J ) = matrix( I, J )
+* 10 CONTINUE
+* 20 CONTINUE
+*
+* Before entry with UPLO = 'L' or 'l', the leading ( k + 1 )
+* by n part of the array A must contain the lower triangular
+* band part of the symmetric matrix, supplied column by
+* column, with the leading diagonal of the matrix in row 1 of
+* the array, the first sub-diagonal starting at position 1 in
+* row 2, and so on. The bottom right k by k triangle of the
+* array A is not referenced.
+* The following program segment will transfer the lower
+* triangular part of a symmetric band matrix from conventional
+* full matrix storage to band storage:
+*
+* DO 20, J = 1, N
+* M = 1 - J
+* DO 10, I = J, MIN( N, J + K )
+* A( M + I, J ) = matrix( I, J )
+* 10 CONTINUE
+* 20 CONTINUE
+*
+* Unchanged on exit.
+*
+* LDA - INTEGER.
+* On entry, LDA specifies the first dimension of A as declared
+* in the calling (sub) program. LDA must be at least
+* ( k + 1 ).
+* Unchanged on exit.
+*
+* X - DOUBLE PRECISION array of DIMENSION at least
+* ( 1 + ( n - 1 )*abs( INCX ) ).
+* Before entry, the incremented array X must contain the
+* vector x.
+* Unchanged on exit.
+*
+* INCX - INTEGER.
+* On entry, INCX specifies the increment for the elements of
+* X. INCX must not be zero.
+* Unchanged on exit.
+*
+* BETA - DOUBLE PRECISION.
+* On entry, BETA specifies the scalar beta.
+* Unchanged on exit.
+*
+* Y - DOUBLE PRECISION array of DIMENSION at least
+* ( 1 + ( n - 1 )*abs( INCY ) ).
+* Before entry, the incremented array Y must contain the
+* vector y. On exit, Y is overwritten by the updated vector y.
+*
+* INCY - INTEGER.
+* On entry, INCY specifies the increment for the elements of
+* Y. INCY must not be zero.
+* Unchanged on exit.
+*
+*
+* Level 2 Blas routine.
+*
+* -- Written on 22-October-1986.
+* Jack Dongarra, Argonne National Lab.
+* Jeremy Du Croz, Nag Central Office.
+* Sven Hammarling, Nag Central Office.
+* Richard Hanson, Sandia National Labs.
+*
+* =====================================================================
+*
+* .. Parameters ..
+ DOUBLE PRECISION ONE,ZERO
+ PARAMETER (ONE=1.0D+0,ZERO=0.0D+0)
+* ..
+* .. Local Scalars ..
+ DOUBLE PRECISION TEMP1,TEMP2
+ INTEGER I,INFO,IX,IY,J,JX,JY,KPLUS1,KX,KY,L
+* ..
+* .. External Functions ..
+ LOGICAL LSAME
+ EXTERNAL LSAME
+* ..
+* .. External Subroutines ..
+ EXTERNAL XERBLA
+* ..
+* .. Intrinsic Functions ..
+ INTRINSIC MAX,MIN
+* ..
+*
+* Test the input parameters.
+*
+ INFO = 0
+ IF (.NOT.LSAME(UPLO,'U') .AND. .NOT.LSAME(UPLO,'L')) THEN
+ INFO = 1
+ ELSE IF (N.LT.0) THEN
+ INFO = 2
+ ELSE IF (K.LT.0) THEN
+ INFO = 3
+ ELSE IF (LDA.LT. (K+1)) THEN
+ INFO = 6
+ ELSE IF (INCX.EQ.0) THEN
+ INFO = 8
+ ELSE IF (INCY.EQ.0) THEN
+ INFO = 11
+ END IF
+ IF (INFO.NE.0) THEN
+ CALL XERBLA('DSBMV ',INFO)
+ RETURN
+ END IF
+*
+* Quick return if possible.
+*
+ IF ((N.EQ.0) .OR. ((ALPHA.EQ.ZERO).AND. (BETA.EQ.ONE))) RETURN
+*
+* Set up the start points in X and Y.
+*
+ IF (INCX.GT.0) THEN
+ KX = 1
+ ELSE
+ KX = 1 - (N-1)*INCX
+ END IF
+ IF (INCY.GT.0) THEN
+ KY = 1
+ ELSE
+ KY = 1 - (N-1)*INCY
+ END IF
+*
+* Start the operations. In this version the elements of the array A
+* are accessed sequentially with one pass through A.
+*
+* First form y := beta*y.
+*
+ IF (BETA.NE.ONE) THEN
+ IF (INCY.EQ.1) THEN
+ IF (BETA.EQ.ZERO) THEN
+ DO 10 I = 1,N
+ Y(I) = ZERO
+ 10 CONTINUE
+ ELSE
+ DO 20 I = 1,N
+ Y(I) = BETA*Y(I)
+ 20 CONTINUE
+ END IF
+ ELSE
+ IY = KY
+ IF (BETA.EQ.ZERO) THEN
+ DO 30 I = 1,N
+ Y(IY) = ZERO
+ IY = IY + INCY
+ 30 CONTINUE
+ ELSE
+ DO 40 I = 1,N
+ Y(IY) = BETA*Y(IY)
+ IY = IY + INCY
+ 40 CONTINUE
+ END IF
+ END IF
+ END IF
+ IF (ALPHA.EQ.ZERO) RETURN
+ IF (LSAME(UPLO,'U')) THEN
+*
+* Form y when upper triangle of A is stored.
+*
+ KPLUS1 = K + 1
+ IF ((INCX.EQ.1) .AND. (INCY.EQ.1)) THEN
+ DO 60 J = 1,N
+ TEMP1 = ALPHA*X(J)
+ TEMP2 = ZERO
+ L = KPLUS1 - J
+ DO 50 I = MAX(1,J-K),J - 1
+ Y(I) = Y(I) + TEMP1*A(L+I,J)
+ TEMP2 = TEMP2 + A(L+I,J)*X(I)
+ 50 CONTINUE
+ Y(J) = Y(J) + TEMP1*A(KPLUS1,J) + ALPHA*TEMP2
+ 60 CONTINUE
+ ELSE
+ JX = KX
+ JY = KY
+ DO 80 J = 1,N
+ TEMP1 = ALPHA*X(JX)
+ TEMP2 = ZERO
+ IX = KX
+ IY = KY
+ L = KPLUS1 - J
+ DO 70 I = MAX(1,J-K),J - 1
+ Y(IY) = Y(IY) + TEMP1*A(L+I,J)
+ TEMP2 = TEMP2 + A(L+I,J)*X(IX)
+ IX = IX + INCX
+ IY = IY + INCY
+ 70 CONTINUE
+ Y(JY) = Y(JY) + TEMP1*A(KPLUS1,J) + ALPHA*TEMP2
+ JX = JX + INCX
+ JY = JY + INCY
+ IF (J.GT.K) THEN
+ KX = KX + INCX
+ KY = KY + INCY
+ END IF
+ 80 CONTINUE
+ END IF
+ ELSE
+*
+* Form y when lower triangle of A is stored.
+*
+ IF ((INCX.EQ.1) .AND. (INCY.EQ.1)) THEN
+ DO 100 J = 1,N
+ TEMP1 = ALPHA*X(J)
+ TEMP2 = ZERO
+ Y(J) = Y(J) + TEMP1*A(1,J)
+ L = 1 - J
+ DO 90 I = J + 1,MIN(N,J+K)
+ Y(I) = Y(I) + TEMP1*A(L+I,J)
+ TEMP2 = TEMP2 + A(L+I,J)*X(I)
+ 90 CONTINUE
+ Y(J) = Y(J) + ALPHA*TEMP2
+ 100 CONTINUE
+ ELSE
+ JX = KX
+ JY = KY
+ DO 120 J = 1,N
+ TEMP1 = ALPHA*X(JX)
+ TEMP2 = ZERO
+ Y(JY) = Y(JY) + TEMP1*A(1,J)
+ L = 1 - J
+ IX = JX
+ IY = JY
+ DO 110 I = J + 1,MIN(N,J+K)
+ IX = IX + INCX
+ IY = IY + INCY
+ Y(IY) = Y(IY) + TEMP1*A(L+I,J)
+ TEMP2 = TEMP2 + A(L+I,J)*X(IX)
+ 110 CONTINUE
+ Y(JY) = Y(JY) + ALPHA*TEMP2
+ JX = JX + INCX
+ JY = JY + INCY
+ 120 CONTINUE
+ END IF
+ END IF
+*
+ RETURN
+*
+* End of DSBMV .
+*
+ END
diff --git a/blas/dspmv.f b/blas/dspmv.f
new file mode 100644
index 000000000..f6e121e76
--- /dev/null
+++ b/blas/dspmv.f
@@ -0,0 +1,265 @@
+ SUBROUTINE DSPMV(UPLO,N,ALPHA,AP,X,INCX,BETA,Y,INCY)
+* .. Scalar Arguments ..
+ DOUBLE PRECISION ALPHA,BETA
+ INTEGER INCX,INCY,N
+ CHARACTER UPLO
+* ..
+* .. Array Arguments ..
+ DOUBLE PRECISION AP(*),X(*),Y(*)
+* ..
+*
+* Purpose
+* =======
+*
+* DSPMV performs the matrix-vector operation
+*
+* y := alpha*A*x + beta*y,
+*
+* where alpha and beta are scalars, x and y are n element vectors and
+* A is an n by n symmetric matrix, supplied in packed form.
+*
+* Arguments
+* ==========
+*
+* UPLO - CHARACTER*1.
+* On entry, UPLO specifies whether the upper or lower
+* triangular part of the matrix A is supplied in the packed
+* array AP as follows:
+*
+* UPLO = 'U' or 'u' The upper triangular part of A is
+* supplied in AP.
+*
+* UPLO = 'L' or 'l' The lower triangular part of A is
+* supplied in AP.
+*
+* Unchanged on exit.
+*
+* N - INTEGER.
+* On entry, N specifies the order of the matrix A.
+* N must be at least zero.
+* Unchanged on exit.
+*
+* ALPHA - DOUBLE PRECISION.
+* On entry, ALPHA specifies the scalar alpha.
+* Unchanged on exit.
+*
+* AP - DOUBLE PRECISION array of DIMENSION at least
+* ( ( n*( n + 1 ) )/2 ).
+* Before entry with UPLO = 'U' or 'u', the array AP must
+* contain the upper triangular part of the symmetric matrix
+* packed sequentially, column by column, so that AP( 1 )
+* contains a( 1, 1 ), AP( 2 ) and AP( 3 ) contain a( 1, 2 )
+* and a( 2, 2 ) respectively, and so on.
+* Before entry with UPLO = 'L' or 'l', the array AP must
+* contain the lower triangular part of the symmetric matrix
+* packed sequentially, column by column, so that AP( 1 )
+* contains a( 1, 1 ), AP( 2 ) and AP( 3 ) contain a( 2, 1 )
+* and a( 3, 1 ) respectively, and so on.
+* Unchanged on exit.
+*
+* X - DOUBLE PRECISION array of dimension at least
+* ( 1 + ( n - 1 )*abs( INCX ) ).
+* Before entry, the incremented array X must contain the n
+* element vector x.
+* Unchanged on exit.
+*
+* INCX - INTEGER.
+* On entry, INCX specifies the increment for the elements of
+* X. INCX must not be zero.
+* Unchanged on exit.
+*
+* BETA - DOUBLE PRECISION.
+* On entry, BETA specifies the scalar beta. When BETA is
+* supplied as zero then Y need not be set on input.
+* Unchanged on exit.
+*
+* Y - DOUBLE PRECISION array of dimension at least
+* ( 1 + ( n - 1 )*abs( INCY ) ).
+* Before entry, the incremented array Y must contain the n
+* element vector y. On exit, Y is overwritten by the updated
+* vector y.
+*
+* INCY - INTEGER.
+* On entry, INCY specifies the increment for the elements of
+* Y. INCY must not be zero.
+* Unchanged on exit.
+*
+* Further Details
+* ===============
+*
+* Level 2 Blas routine.
+*
+* -- Written on 22-October-1986.
+* Jack Dongarra, Argonne National Lab.
+* Jeremy Du Croz, Nag Central Office.
+* Sven Hammarling, Nag Central Office.
+* Richard Hanson, Sandia National Labs.
+*
+* =====================================================================
+*
+* .. Parameters ..
+ DOUBLE PRECISION ONE,ZERO
+ PARAMETER (ONE=1.0D+0,ZERO=0.0D+0)
+* ..
+* .. Local Scalars ..
+ DOUBLE PRECISION TEMP1,TEMP2
+ INTEGER I,INFO,IX,IY,J,JX,JY,K,KK,KX,KY
+* ..
+* .. External Functions ..
+ LOGICAL LSAME
+ EXTERNAL LSAME
+* ..
+* .. External Subroutines ..
+ EXTERNAL XERBLA
+* ..
+*
+* Test the input parameters.
+*
+ INFO = 0
+ IF (.NOT.LSAME(UPLO,'U') .AND. .NOT.LSAME(UPLO,'L')) THEN
+ INFO = 1
+ ELSE IF (N.LT.0) THEN
+ INFO = 2
+ ELSE IF (INCX.EQ.0) THEN
+ INFO = 6
+ ELSE IF (INCY.EQ.0) THEN
+ INFO = 9
+ END IF
+ IF (INFO.NE.0) THEN
+ CALL XERBLA('DSPMV ',INFO)
+ RETURN
+ END IF
+*
+* Quick return if possible.
+*
+ IF ((N.EQ.0) .OR. ((ALPHA.EQ.ZERO).AND. (BETA.EQ.ONE))) RETURN
+*
+* Set up the start points in X and Y.
+*
+ IF (INCX.GT.0) THEN
+ KX = 1
+ ELSE
+ KX = 1 - (N-1)*INCX
+ END IF
+ IF (INCY.GT.0) THEN
+ KY = 1
+ ELSE
+ KY = 1 - (N-1)*INCY
+ END IF
+*
+* Start the operations. In this version the elements of the array AP
+* are accessed sequentially with one pass through AP.
+*
+* First form y := beta*y.
+*
+ IF (BETA.NE.ONE) THEN
+ IF (INCY.EQ.1) THEN
+ IF (BETA.EQ.ZERO) THEN
+ DO 10 I = 1,N
+ Y(I) = ZERO
+ 10 CONTINUE
+ ELSE
+ DO 20 I = 1,N
+ Y(I) = BETA*Y(I)
+ 20 CONTINUE
+ END IF
+ ELSE
+ IY = KY
+ IF (BETA.EQ.ZERO) THEN
+ DO 30 I = 1,N
+ Y(IY) = ZERO
+ IY = IY + INCY
+ 30 CONTINUE
+ ELSE
+ DO 40 I = 1,N
+ Y(IY) = BETA*Y(IY)
+ IY = IY + INCY
+ 40 CONTINUE
+ END IF
+ END IF
+ END IF
+ IF (ALPHA.EQ.ZERO) RETURN
+ KK = 1
+ IF (LSAME(UPLO,'U')) THEN
+*
+* Form y when AP contains the upper triangle.
+*
+ IF ((INCX.EQ.1) .AND. (INCY.EQ.1)) THEN
+ DO 60 J = 1,N
+ TEMP1 = ALPHA*X(J)
+ TEMP2 = ZERO
+ K = KK
+ DO 50 I = 1,J - 1
+ Y(I) = Y(I) + TEMP1*AP(K)
+ TEMP2 = TEMP2 + AP(K)*X(I)
+ K = K + 1
+ 50 CONTINUE
+ Y(J) = Y(J) + TEMP1*AP(KK+J-1) + ALPHA*TEMP2
+ KK = KK + J
+ 60 CONTINUE
+ ELSE
+ JX = KX
+ JY = KY
+ DO 80 J = 1,N
+ TEMP1 = ALPHA*X(JX)
+ TEMP2 = ZERO
+ IX = KX
+ IY = KY
+ DO 70 K = KK,KK + J - 2
+ Y(IY) = Y(IY) + TEMP1*AP(K)
+ TEMP2 = TEMP2 + AP(K)*X(IX)
+ IX = IX + INCX
+ IY = IY + INCY
+ 70 CONTINUE
+ Y(JY) = Y(JY) + TEMP1*AP(KK+J-1) + ALPHA*TEMP2
+ JX = JX + INCX
+ JY = JY + INCY
+ KK = KK + J
+ 80 CONTINUE
+ END IF
+ ELSE
+*
+* Form y when AP contains the lower triangle.
+*
+ IF ((INCX.EQ.1) .AND. (INCY.EQ.1)) THEN
+ DO 100 J = 1,N
+ TEMP1 = ALPHA*X(J)
+ TEMP2 = ZERO
+ Y(J) = Y(J) + TEMP1*AP(KK)
+ K = KK + 1
+ DO 90 I = J + 1,N
+ Y(I) = Y(I) + TEMP1*AP(K)
+ TEMP2 = TEMP2 + AP(K)*X(I)
+ K = K + 1
+ 90 CONTINUE
+ Y(J) = Y(J) + ALPHA*TEMP2
+ KK = KK + (N-J+1)
+ 100 CONTINUE
+ ELSE
+ JX = KX
+ JY = KY
+ DO 120 J = 1,N
+ TEMP1 = ALPHA*X(JX)
+ TEMP2 = ZERO
+ Y(JY) = Y(JY) + TEMP1*AP(KK)
+ IX = JX
+ IY = JY
+ DO 110 K = KK + 1,KK + N - J
+ IX = IX + INCX
+ IY = IY + INCY
+ Y(IY) = Y(IY) + TEMP1*AP(K)
+ TEMP2 = TEMP2 + AP(K)*X(IX)
+ 110 CONTINUE
+ Y(JY) = Y(JY) + ALPHA*TEMP2
+ JX = JX + INCX
+ JY = JY + INCY
+ KK = KK + (N-J+1)
+ 120 CONTINUE
+ END IF
+ END IF
+*
+ RETURN
+*
+* End of DSPMV .
+*
+ END
diff --git a/blas/dspr.f b/blas/dspr.f
new file mode 100644
index 000000000..538e4f76b
--- /dev/null
+++ b/blas/dspr.f
@@ -0,0 +1,202 @@
+ SUBROUTINE DSPR(UPLO,N,ALPHA,X,INCX,AP)
+* .. Scalar Arguments ..
+ DOUBLE PRECISION ALPHA
+ INTEGER INCX,N
+ CHARACTER UPLO
+* ..
+* .. Array Arguments ..
+ DOUBLE PRECISION AP(*),X(*)
+* ..
+*
+* Purpose
+* =======
+*
+* DSPR performs the symmetric rank 1 operation
+*
+* A := alpha*x*x' + A,
+*
+* where alpha is a real scalar, x is an n element vector and A is an
+* n by n symmetric matrix, supplied in packed form.
+*
+* Arguments
+* ==========
+*
+* UPLO - CHARACTER*1.
+* On entry, UPLO specifies whether the upper or lower
+* triangular part of the matrix A is supplied in the packed
+* array AP as follows:
+*
+* UPLO = 'U' or 'u' The upper triangular part of A is
+* supplied in AP.
+*
+* UPLO = 'L' or 'l' The lower triangular part of A is
+* supplied in AP.
+*
+* Unchanged on exit.
+*
+* N - INTEGER.
+* On entry, N specifies the order of the matrix A.
+* N must be at least zero.
+* Unchanged on exit.
+*
+* ALPHA - DOUBLE PRECISION.
+* On entry, ALPHA specifies the scalar alpha.
+* Unchanged on exit.
+*
+* X - DOUBLE PRECISION array of dimension at least
+* ( 1 + ( n - 1 )*abs( INCX ) ).
+* Before entry, the incremented array X must contain the n
+* element vector x.
+* Unchanged on exit.
+*
+* INCX - INTEGER.
+* On entry, INCX specifies the increment for the elements of
+* X. INCX must not be zero.
+* Unchanged on exit.
+*
+* AP - DOUBLE PRECISION array of DIMENSION at least
+* ( ( n*( n + 1 ) )/2 ).
+* Before entry with UPLO = 'U' or 'u', the array AP must
+* contain the upper triangular part of the symmetric matrix
+* packed sequentially, column by column, so that AP( 1 )
+* contains a( 1, 1 ), AP( 2 ) and AP( 3 ) contain a( 1, 2 )
+* and a( 2, 2 ) respectively, and so on. On exit, the array
+* AP is overwritten by the upper triangular part of the
+* updated matrix.
+* Before entry with UPLO = 'L' or 'l', the array AP must
+* contain the lower triangular part of the symmetric matrix
+* packed sequentially, column by column, so that AP( 1 )
+* contains a( 1, 1 ), AP( 2 ) and AP( 3 ) contain a( 2, 1 )
+* and a( 3, 1 ) respectively, and so on. On exit, the array
+* AP is overwritten by the lower triangular part of the
+* updated matrix.
+*
+* Further Details
+* ===============
+*
+* Level 2 Blas routine.
+*
+* -- Written on 22-October-1986.
+* Jack Dongarra, Argonne National Lab.
+* Jeremy Du Croz, Nag Central Office.
+* Sven Hammarling, Nag Central Office.
+* Richard Hanson, Sandia National Labs.
+*
+* =====================================================================
+*
+* .. Parameters ..
+ DOUBLE PRECISION ZERO
+ PARAMETER (ZERO=0.0D+0)
+* ..
+* .. Local Scalars ..
+ DOUBLE PRECISION TEMP
+ INTEGER I,INFO,IX,J,JX,K,KK,KX
+* ..
+* .. External Functions ..
+ LOGICAL LSAME
+ EXTERNAL LSAME
+* ..
+* .. External Subroutines ..
+ EXTERNAL XERBLA
+* ..
+*
+* Test the input parameters.
+*
+ INFO = 0
+ IF (.NOT.LSAME(UPLO,'U') .AND. .NOT.LSAME(UPLO,'L')) THEN
+ INFO = 1
+ ELSE IF (N.LT.0) THEN
+ INFO = 2
+ ELSE IF (INCX.EQ.0) THEN
+ INFO = 5
+ END IF
+ IF (INFO.NE.0) THEN
+ CALL XERBLA('DSPR ',INFO)
+ RETURN
+ END IF
+*
+* Quick return if possible.
+*
+ IF ((N.EQ.0) .OR. (ALPHA.EQ.ZERO)) RETURN
+*
+* Set the start point in X if the increment is not unity.
+*
+ IF (INCX.LE.0) THEN
+ KX = 1 - (N-1)*INCX
+ ELSE IF (INCX.NE.1) THEN
+ KX = 1
+ END IF
+*
+* Start the operations. In this version the elements of the array AP
+* are accessed sequentially with one pass through AP.
+*
+ KK = 1
+ IF (LSAME(UPLO,'U')) THEN
+*
+* Form A when upper triangle is stored in AP.
+*
+ IF (INCX.EQ.1) THEN
+ DO 20 J = 1,N
+ IF (X(J).NE.ZERO) THEN
+ TEMP = ALPHA*X(J)
+ K = KK
+ DO 10 I = 1,J
+ AP(K) = AP(K) + X(I)*TEMP
+ K = K + 1
+ 10 CONTINUE
+ END IF
+ KK = KK + J
+ 20 CONTINUE
+ ELSE
+ JX = KX
+ DO 40 J = 1,N
+ IF (X(JX).NE.ZERO) THEN
+ TEMP = ALPHA*X(JX)
+ IX = KX
+ DO 30 K = KK,KK + J - 1
+ AP(K) = AP(K) + X(IX)*TEMP
+ IX = IX + INCX
+ 30 CONTINUE
+ END IF
+ JX = JX + INCX
+ KK = KK + J
+ 40 CONTINUE
+ END IF
+ ELSE
+*
+* Form A when lower triangle is stored in AP.
+*
+ IF (INCX.EQ.1) THEN
+ DO 60 J = 1,N
+ IF (X(J).NE.ZERO) THEN
+ TEMP = ALPHA*X(J)
+ K = KK
+ DO 50 I = J,N
+ AP(K) = AP(K) + X(I)*TEMP
+ K = K + 1
+ 50 CONTINUE
+ END IF
+ KK = KK + N - J + 1
+ 60 CONTINUE
+ ELSE
+ JX = KX
+ DO 80 J = 1,N
+ IF (X(JX).NE.ZERO) THEN
+ TEMP = ALPHA*X(JX)
+ IX = JX
+ DO 70 K = KK,KK + N - J
+ AP(K) = AP(K) + X(IX)*TEMP
+ IX = IX + INCX
+ 70 CONTINUE
+ END IF
+ JX = JX + INCX
+ KK = KK + N - J + 1
+ 80 CONTINUE
+ END IF
+ END IF
+*
+ RETURN
+*
+* End of DSPR .
+*
+ END
diff --git a/blas/dspr2.f b/blas/dspr2.f
new file mode 100644
index 000000000..6f6b54a8c
--- /dev/null
+++ b/blas/dspr2.f
@@ -0,0 +1,233 @@
+ SUBROUTINE DSPR2(UPLO,N,ALPHA,X,INCX,Y,INCY,AP)
+* .. Scalar Arguments ..
+ DOUBLE PRECISION ALPHA
+ INTEGER INCX,INCY,N
+ CHARACTER UPLO
+* ..
+* .. Array Arguments ..
+ DOUBLE PRECISION AP(*),X(*),Y(*)
+* ..
+*
+* Purpose
+* =======
+*
+* DSPR2 performs the symmetric rank 2 operation
+*
+* A := alpha*x*y' + alpha*y*x' + A,
+*
+* where alpha is a scalar, x and y are n element vectors and A is an
+* n by n symmetric matrix, supplied in packed form.
+*
+* Arguments
+* ==========
+*
+* UPLO - CHARACTER*1.
+* On entry, UPLO specifies whether the upper or lower
+* triangular part of the matrix A is supplied in the packed
+* array AP as follows:
+*
+* UPLO = 'U' or 'u' The upper triangular part of A is
+* supplied in AP.
+*
+* UPLO = 'L' or 'l' The lower triangular part of A is
+* supplied in AP.
+*
+* Unchanged on exit.
+*
+* N - INTEGER.
+* On entry, N specifies the order of the matrix A.
+* N must be at least zero.
+* Unchanged on exit.
+*
+* ALPHA - DOUBLE PRECISION.
+* On entry, ALPHA specifies the scalar alpha.
+* Unchanged on exit.
+*
+* X - DOUBLE PRECISION array of dimension at least
+* ( 1 + ( n - 1 )*abs( INCX ) ).
+* Before entry, the incremented array X must contain the n
+* element vector x.
+* Unchanged on exit.
+*
+* INCX - INTEGER.
+* On entry, INCX specifies the increment for the elements of
+* X. INCX must not be zero.
+* Unchanged on exit.
+*
+* Y - DOUBLE PRECISION array of dimension at least
+* ( 1 + ( n - 1 )*abs( INCY ) ).
+* Before entry, the incremented array Y must contain the n
+* element vector y.
+* Unchanged on exit.
+*
+* INCY - INTEGER.
+* On entry, INCY specifies the increment for the elements of
+* Y. INCY must not be zero.
+* Unchanged on exit.
+*
+* AP - DOUBLE PRECISION array of DIMENSION at least
+* ( ( n*( n + 1 ) )/2 ).
+* Before entry with UPLO = 'U' or 'u', the array AP must
+* contain the upper triangular part of the symmetric matrix
+* packed sequentially, column by column, so that AP( 1 )
+* contains a( 1, 1 ), AP( 2 ) and AP( 3 ) contain a( 1, 2 )
+* and a( 2, 2 ) respectively, and so on. On exit, the array
+* AP is overwritten by the upper triangular part of the
+* updated matrix.
+* Before entry with UPLO = 'L' or 'l', the array AP must
+* contain the lower triangular part of the symmetric matrix
+* packed sequentially, column by column, so that AP( 1 )
+* contains a( 1, 1 ), AP( 2 ) and AP( 3 ) contain a( 2, 1 )
+* and a( 3, 1 ) respectively, and so on. On exit, the array
+* AP is overwritten by the lower triangular part of the
+* updated matrix.
+*
+* Further Details
+* ===============
+*
+* Level 2 Blas routine.
+*
+* -- Written on 22-October-1986.
+* Jack Dongarra, Argonne National Lab.
+* Jeremy Du Croz, Nag Central Office.
+* Sven Hammarling, Nag Central Office.
+* Richard Hanson, Sandia National Labs.
+*
+* =====================================================================
+*
+* .. Parameters ..
+ DOUBLE PRECISION ZERO
+ PARAMETER (ZERO=0.0D+0)
+* ..
+* .. Local Scalars ..
+ DOUBLE PRECISION TEMP1,TEMP2
+ INTEGER I,INFO,IX,IY,J,JX,JY,K,KK,KX,KY
+* ..
+* .. External Functions ..
+ LOGICAL LSAME
+ EXTERNAL LSAME
+* ..
+* .. External Subroutines ..
+ EXTERNAL XERBLA
+* ..
+*
+* Test the input parameters.
+*
+ INFO = 0
+ IF (.NOT.LSAME(UPLO,'U') .AND. .NOT.LSAME(UPLO,'L')) THEN
+ INFO = 1
+ ELSE IF (N.LT.0) THEN
+ INFO = 2
+ ELSE IF (INCX.EQ.0) THEN
+ INFO = 5
+ ELSE IF (INCY.EQ.0) THEN
+ INFO = 7
+ END IF
+ IF (INFO.NE.0) THEN
+ CALL XERBLA('DSPR2 ',INFO)
+ RETURN
+ END IF
+*
+* Quick return if possible.
+*
+ IF ((N.EQ.0) .OR. (ALPHA.EQ.ZERO)) RETURN
+*
+* Set up the start points in X and Y if the increments are not both
+* unity.
+*
+ IF ((INCX.NE.1) .OR. (INCY.NE.1)) THEN
+ IF (INCX.GT.0) THEN
+ KX = 1
+ ELSE
+ KX = 1 - (N-1)*INCX
+ END IF
+ IF (INCY.GT.0) THEN
+ KY = 1
+ ELSE
+ KY = 1 - (N-1)*INCY
+ END IF
+ JX = KX
+ JY = KY
+ END IF
+*
+* Start the operations. In this version the elements of the array AP
+* are accessed sequentially with one pass through AP.
+*
+ KK = 1
+ IF (LSAME(UPLO,'U')) THEN
+*
+* Form A when upper triangle is stored in AP.
+*
+ IF ((INCX.EQ.1) .AND. (INCY.EQ.1)) THEN
+ DO 20 J = 1,N
+ IF ((X(J).NE.ZERO) .OR. (Y(J).NE.ZERO)) THEN
+ TEMP1 = ALPHA*Y(J)
+ TEMP2 = ALPHA*X(J)
+ K = KK
+ DO 10 I = 1,J
+ AP(K) = AP(K) + X(I)*TEMP1 + Y(I)*TEMP2
+ K = K + 1
+ 10 CONTINUE
+ END IF
+ KK = KK + J
+ 20 CONTINUE
+ ELSE
+ DO 40 J = 1,N
+ IF ((X(JX).NE.ZERO) .OR. (Y(JY).NE.ZERO)) THEN
+ TEMP1 = ALPHA*Y(JY)
+ TEMP2 = ALPHA*X(JX)
+ IX = KX
+ IY = KY
+ DO 30 K = KK,KK + J - 1
+ AP(K) = AP(K) + X(IX)*TEMP1 + Y(IY)*TEMP2
+ IX = IX + INCX
+ IY = IY + INCY
+ 30 CONTINUE
+ END IF
+ JX = JX + INCX
+ JY = JY + INCY
+ KK = KK + J
+ 40 CONTINUE
+ END IF
+ ELSE
+*
+* Form A when lower triangle is stored in AP.
+*
+ IF ((INCX.EQ.1) .AND. (INCY.EQ.1)) THEN
+ DO 60 J = 1,N
+ IF ((X(J).NE.ZERO) .OR. (Y(J).NE.ZERO)) THEN
+ TEMP1 = ALPHA*Y(J)
+ TEMP2 = ALPHA*X(J)
+ K = KK
+ DO 50 I = J,N
+ AP(K) = AP(K) + X(I)*TEMP1 + Y(I)*TEMP2
+ K = K + 1
+ 50 CONTINUE
+ END IF
+ KK = KK + N - J + 1
+ 60 CONTINUE
+ ELSE
+ DO 80 J = 1,N
+ IF ((X(JX).NE.ZERO) .OR. (Y(JY).NE.ZERO)) THEN
+ TEMP1 = ALPHA*Y(JY)
+ TEMP2 = ALPHA*X(JX)
+ IX = JX
+ IY = JY
+ DO 70 K = KK,KK + N - J
+ AP(K) = AP(K) + X(IX)*TEMP1 + Y(IY)*TEMP2
+ IX = IX + INCX
+ IY = IY + INCY
+ 70 CONTINUE
+ END IF
+ JX = JX + INCX
+ JY = JY + INCY
+ KK = KK + N - J + 1
+ 80 CONTINUE
+ END IF
+ END IF
+*
+ RETURN
+*
+* End of DSPR2 .
+*
+ END
diff --git a/blas/dtbmv.f b/blas/dtbmv.f
new file mode 100644
index 000000000..a87ffdeae
--- /dev/null
+++ b/blas/dtbmv.f
@@ -0,0 +1,335 @@
+ SUBROUTINE DTBMV(UPLO,TRANS,DIAG,N,K,A,LDA,X,INCX)
+* .. Scalar Arguments ..
+ INTEGER INCX,K,LDA,N
+ CHARACTER DIAG,TRANS,UPLO
+* ..
+* .. Array Arguments ..
+ DOUBLE PRECISION A(LDA,*),X(*)
+* ..
+*
+* Purpose
+* =======
+*
+* DTBMV performs one of the matrix-vector operations
+*
+* x := A*x, or x := A'*x,
+*
+* where x is an n element vector and A is an n by n unit, or non-unit,
+* upper or lower triangular band matrix, with ( k + 1 ) diagonals.
+*
+* Arguments
+* ==========
+*
+* UPLO - CHARACTER*1.
+* On entry, UPLO specifies whether the matrix is an upper or
+* lower triangular matrix as follows:
+*
+* UPLO = 'U' or 'u' A is an upper triangular matrix.
+*
+* UPLO = 'L' or 'l' A is a lower triangular matrix.
+*
+* Unchanged on exit.
+*
+* TRANS - CHARACTER*1.
+* On entry, TRANS specifies the operation to be performed as
+* follows:
+*
+* TRANS = 'N' or 'n' x := A*x.
+*
+* TRANS = 'T' or 't' x := A'*x.
+*
+* TRANS = 'C' or 'c' x := A'*x.
+*
+* Unchanged on exit.
+*
+* DIAG - CHARACTER*1.
+* On entry, DIAG specifies whether or not A is unit
+* triangular as follows:
+*
+* DIAG = 'U' or 'u' A is assumed to be unit triangular.
+*
+* DIAG = 'N' or 'n' A is not assumed to be unit
+* triangular.
+*
+* Unchanged on exit.
+*
+* N - INTEGER.
+* On entry, N specifies the order of the matrix A.
+* N must be at least zero.
+* Unchanged on exit.
+*
+* K - INTEGER.
+* On entry with UPLO = 'U' or 'u', K specifies the number of
+* super-diagonals of the matrix A.
+* On entry with UPLO = 'L' or 'l', K specifies the number of
+* sub-diagonals of the matrix A.
+* K must satisfy 0 .le. K.
+* Unchanged on exit.
+*
+* A - DOUBLE PRECISION array of DIMENSION ( LDA, n ).
+* Before entry with UPLO = 'U' or 'u', the leading ( k + 1 )
+* by n part of the array A must contain the upper triangular
+* band part of the matrix of coefficients, supplied column by
+* column, with the leading diagonal of the matrix in row
+* ( k + 1 ) of the array, the first super-diagonal starting at
+* position 2 in row k, and so on. The top left k by k triangle
+* of the array A is not referenced.
+* The following program segment will transfer an upper
+* triangular band matrix from conventional full matrix storage
+* to band storage:
+*
+* DO 20, J = 1, N
+* M = K + 1 - J
+* DO 10, I = MAX( 1, J - K ), J
+* A( M + I, J ) = matrix( I, J )
+* 10 CONTINUE
+* 20 CONTINUE
+*
+* Before entry with UPLO = 'L' or 'l', the leading ( k + 1 )
+* by n part of the array A must contain the lower triangular
+* band part of the matrix of coefficients, supplied column by
+* column, with the leading diagonal of the matrix in row 1 of
+* the array, the first sub-diagonal starting at position 1 in
+* row 2, and so on. The bottom right k by k triangle of the
+* array A is not referenced.
+* The following program segment will transfer a lower
+* triangular band matrix from conventional full matrix storage
+* to band storage:
+*
+* DO 20, J = 1, N
+* M = 1 - J
+* DO 10, I = J, MIN( N, J + K )
+* A( M + I, J ) = matrix( I, J )
+* 10 CONTINUE
+* 20 CONTINUE
+*
+* Note that when DIAG = 'U' or 'u' the elements of the array A
+* corresponding to the diagonal elements of the matrix are not
+* referenced, but are assumed to be unity.
+* Unchanged on exit.
+*
+* LDA - INTEGER.
+* On entry, LDA specifies the first dimension of A as declared
+* in the calling (sub) program. LDA must be at least
+* ( k + 1 ).
+* Unchanged on exit.
+*
+* X - DOUBLE PRECISION array of dimension at least
+* ( 1 + ( n - 1 )*abs( INCX ) ).
+* Before entry, the incremented array X must contain the n
+* element vector x. On exit, X is overwritten with the
+* tranformed vector x.
+*
+* INCX - INTEGER.
+* On entry, INCX specifies the increment for the elements of
+* X. INCX must not be zero.
+* Unchanged on exit.
+*
+* Further Details
+* ===============
+*
+* Level 2 Blas routine.
+*
+* -- Written on 22-October-1986.
+* Jack Dongarra, Argonne National Lab.
+* Jeremy Du Croz, Nag Central Office.
+* Sven Hammarling, Nag Central Office.
+* Richard Hanson, Sandia National Labs.
+*
+* =====================================================================
+*
+* .. Parameters ..
+ DOUBLE PRECISION ZERO
+ PARAMETER (ZERO=0.0D+0)
+* ..
+* .. Local Scalars ..
+ DOUBLE PRECISION TEMP
+ INTEGER I,INFO,IX,J,JX,KPLUS1,KX,L
+ LOGICAL NOUNIT
+* ..
+* .. External Functions ..
+ LOGICAL LSAME
+ EXTERNAL LSAME
+* ..
+* .. External Subroutines ..
+ EXTERNAL XERBLA
+* ..
+* .. Intrinsic Functions ..
+ INTRINSIC MAX,MIN
+* ..
+*
+* Test the input parameters.
+*
+ INFO = 0
+ IF (.NOT.LSAME(UPLO,'U') .AND. .NOT.LSAME(UPLO,'L')) THEN
+ INFO = 1
+ ELSE IF (.NOT.LSAME(TRANS,'N') .AND. .NOT.LSAME(TRANS,'T') .AND.
+ + .NOT.LSAME(TRANS,'C')) THEN
+ INFO = 2
+ ELSE IF (.NOT.LSAME(DIAG,'U') .AND. .NOT.LSAME(DIAG,'N')) THEN
+ INFO = 3
+ ELSE IF (N.LT.0) THEN
+ INFO = 4
+ ELSE IF (K.LT.0) THEN
+ INFO = 5
+ ELSE IF (LDA.LT. (K+1)) THEN
+ INFO = 7
+ ELSE IF (INCX.EQ.0) THEN
+ INFO = 9
+ END IF
+ IF (INFO.NE.0) THEN
+ CALL XERBLA('DTBMV ',INFO)
+ RETURN
+ END IF
+*
+* Quick return if possible.
+*
+ IF (N.EQ.0) RETURN
+*
+ NOUNIT = LSAME(DIAG,'N')
+*
+* Set up the start point in X if the increment is not unity. This
+* will be ( N - 1 )*INCX too small for descending loops.
+*
+ IF (INCX.LE.0) THEN
+ KX = 1 - (N-1)*INCX
+ ELSE IF (INCX.NE.1) THEN
+ KX = 1
+ END IF
+*
+* Start the operations. In this version the elements of A are
+* accessed sequentially with one pass through A.
+*
+ IF (LSAME(TRANS,'N')) THEN
+*
+* Form x := A*x.
+*
+ IF (LSAME(UPLO,'U')) THEN
+ KPLUS1 = K + 1
+ IF (INCX.EQ.1) THEN
+ DO 20 J = 1,N
+ IF (X(J).NE.ZERO) THEN
+ TEMP = X(J)
+ L = KPLUS1 - J
+ DO 10 I = MAX(1,J-K),J - 1
+ X(I) = X(I) + TEMP*A(L+I,J)
+ 10 CONTINUE
+ IF (NOUNIT) X(J) = X(J)*A(KPLUS1,J)
+ END IF
+ 20 CONTINUE
+ ELSE
+ JX = KX
+ DO 40 J = 1,N
+ IF (X(JX).NE.ZERO) THEN
+ TEMP = X(JX)
+ IX = KX
+ L = KPLUS1 - J
+ DO 30 I = MAX(1,J-K),J - 1
+ X(IX) = X(IX) + TEMP*A(L+I,J)
+ IX = IX + INCX
+ 30 CONTINUE
+ IF (NOUNIT) X(JX) = X(JX)*A(KPLUS1,J)
+ END IF
+ JX = JX + INCX
+ IF (J.GT.K) KX = KX + INCX
+ 40 CONTINUE
+ END IF
+ ELSE
+ IF (INCX.EQ.1) THEN
+ DO 60 J = N,1,-1
+ IF (X(J).NE.ZERO) THEN
+ TEMP = X(J)
+ L = 1 - J
+ DO 50 I = MIN(N,J+K),J + 1,-1
+ X(I) = X(I) + TEMP*A(L+I,J)
+ 50 CONTINUE
+ IF (NOUNIT) X(J) = X(J)*A(1,J)
+ END IF
+ 60 CONTINUE
+ ELSE
+ KX = KX + (N-1)*INCX
+ JX = KX
+ DO 80 J = N,1,-1
+ IF (X(JX).NE.ZERO) THEN
+ TEMP = X(JX)
+ IX = KX
+ L = 1 - J
+ DO 70 I = MIN(N,J+K),J + 1,-1
+ X(IX) = X(IX) + TEMP*A(L+I,J)
+ IX = IX - INCX
+ 70 CONTINUE
+ IF (NOUNIT) X(JX) = X(JX)*A(1,J)
+ END IF
+ JX = JX - INCX
+ IF ((N-J).GE.K) KX = KX - INCX
+ 80 CONTINUE
+ END IF
+ END IF
+ ELSE
+*
+* Form x := A'*x.
+*
+ IF (LSAME(UPLO,'U')) THEN
+ KPLUS1 = K + 1
+ IF (INCX.EQ.1) THEN
+ DO 100 J = N,1,-1
+ TEMP = X(J)
+ L = KPLUS1 - J
+ IF (NOUNIT) TEMP = TEMP*A(KPLUS1,J)
+ DO 90 I = J - 1,MAX(1,J-K),-1
+ TEMP = TEMP + A(L+I,J)*X(I)
+ 90 CONTINUE
+ X(J) = TEMP
+ 100 CONTINUE
+ ELSE
+ KX = KX + (N-1)*INCX
+ JX = KX
+ DO 120 J = N,1,-1
+ TEMP = X(JX)
+ KX = KX - INCX
+ IX = KX
+ L = KPLUS1 - J
+ IF (NOUNIT) TEMP = TEMP*A(KPLUS1,J)
+ DO 110 I = J - 1,MAX(1,J-K),-1
+ TEMP = TEMP + A(L+I,J)*X(IX)
+ IX = IX - INCX
+ 110 CONTINUE
+ X(JX) = TEMP
+ JX = JX - INCX
+ 120 CONTINUE
+ END IF
+ ELSE
+ IF (INCX.EQ.1) THEN
+ DO 140 J = 1,N
+ TEMP = X(J)
+ L = 1 - J
+ IF (NOUNIT) TEMP = TEMP*A(1,J)
+ DO 130 I = J + 1,MIN(N,J+K)
+ TEMP = TEMP + A(L+I,J)*X(I)
+ 130 CONTINUE
+ X(J) = TEMP
+ 140 CONTINUE
+ ELSE
+ JX = KX
+ DO 160 J = 1,N
+ TEMP = X(JX)
+ KX = KX + INCX
+ IX = KX
+ L = 1 - J
+ IF (NOUNIT) TEMP = TEMP*A(1,J)
+ DO 150 I = J + 1,MIN(N,J+K)
+ TEMP = TEMP + A(L+I,J)*X(IX)
+ IX = IX + INCX
+ 150 CONTINUE
+ X(JX) = TEMP
+ JX = JX + INCX
+ 160 CONTINUE
+ END IF
+ END IF
+ END IF
+*
+ RETURN
+*
+* End of DTBMV .
+*
+ END
diff --git a/blas/dtpmv.f b/blas/dtpmv.f
new file mode 100644
index 000000000..c5bc112dc
--- /dev/null
+++ b/blas/dtpmv.f
@@ -0,0 +1,293 @@
+ SUBROUTINE DTPMV(UPLO,TRANS,DIAG,N,AP,X,INCX)
+* .. Scalar Arguments ..
+ INTEGER INCX,N
+ CHARACTER DIAG,TRANS,UPLO
+* ..
+* .. Array Arguments ..
+ DOUBLE PRECISION AP(*),X(*)
+* ..
+*
+* Purpose
+* =======
+*
+* DTPMV performs one of the matrix-vector operations
+*
+* x := A*x, or x := A'*x,
+*
+* where x is an n element vector and A is an n by n unit, or non-unit,
+* upper or lower triangular matrix, supplied in packed form.
+*
+* Arguments
+* ==========
+*
+* UPLO - CHARACTER*1.
+* On entry, UPLO specifies whether the matrix is an upper or
+* lower triangular matrix as follows:
+*
+* UPLO = 'U' or 'u' A is an upper triangular matrix.
+*
+* UPLO = 'L' or 'l' A is a lower triangular matrix.
+*
+* Unchanged on exit.
+*
+* TRANS - CHARACTER*1.
+* On entry, TRANS specifies the operation to be performed as
+* follows:
+*
+* TRANS = 'N' or 'n' x := A*x.
+*
+* TRANS = 'T' or 't' x := A'*x.
+*
+* TRANS = 'C' or 'c' x := A'*x.
+*
+* Unchanged on exit.
+*
+* DIAG - CHARACTER*1.
+* On entry, DIAG specifies whether or not A is unit
+* triangular as follows:
+*
+* DIAG = 'U' or 'u' A is assumed to be unit triangular.
+*
+* DIAG = 'N' or 'n' A is not assumed to be unit
+* triangular.
+*
+* Unchanged on exit.
+*
+* N - INTEGER.
+* On entry, N specifies the order of the matrix A.
+* N must be at least zero.
+* Unchanged on exit.
+*
+* AP - DOUBLE PRECISION array of DIMENSION at least
+* ( ( n*( n + 1 ) )/2 ).
+* Before entry with UPLO = 'U' or 'u', the array AP must
+* contain the upper triangular matrix packed sequentially,
+* column by column, so that AP( 1 ) contains a( 1, 1 ),
+* AP( 2 ) and AP( 3 ) contain a( 1, 2 ) and a( 2, 2 )
+* respectively, and so on.
+* Before entry with UPLO = 'L' or 'l', the array AP must
+* contain the lower triangular matrix packed sequentially,
+* column by column, so that AP( 1 ) contains a( 1, 1 ),
+* AP( 2 ) and AP( 3 ) contain a( 2, 1 ) and a( 3, 1 )
+* respectively, and so on.
+* Note that when DIAG = 'U' or 'u', the diagonal elements of
+* A are not referenced, but are assumed to be unity.
+* Unchanged on exit.
+*
+* X - DOUBLE PRECISION array of dimension at least
+* ( 1 + ( n - 1 )*abs( INCX ) ).
+* Before entry, the incremented array X must contain the n
+* element vector x. On exit, X is overwritten with the
+* tranformed vector x.
+*
+* INCX - INTEGER.
+* On entry, INCX specifies the increment for the elements of
+* X. INCX must not be zero.
+* Unchanged on exit.
+*
+* Further Details
+* ===============
+*
+* Level 2 Blas routine.
+*
+* -- Written on 22-October-1986.
+* Jack Dongarra, Argonne National Lab.
+* Jeremy Du Croz, Nag Central Office.
+* Sven Hammarling, Nag Central Office.
+* Richard Hanson, Sandia National Labs.
+*
+* =====================================================================
+*
+* .. Parameters ..
+ DOUBLE PRECISION ZERO
+ PARAMETER (ZERO=0.0D+0)
+* ..
+* .. Local Scalars ..
+ DOUBLE PRECISION TEMP
+ INTEGER I,INFO,IX,J,JX,K,KK,KX
+ LOGICAL NOUNIT
+* ..
+* .. External Functions ..
+ LOGICAL LSAME
+ EXTERNAL LSAME
+* ..
+* .. External Subroutines ..
+ EXTERNAL XERBLA
+* ..
+*
+* Test the input parameters.
+*
+ INFO = 0
+ IF (.NOT.LSAME(UPLO,'U') .AND. .NOT.LSAME(UPLO,'L')) THEN
+ INFO = 1
+ ELSE IF (.NOT.LSAME(TRANS,'N') .AND. .NOT.LSAME(TRANS,'T') .AND.
+ + .NOT.LSAME(TRANS,'C')) THEN
+ INFO = 2
+ ELSE IF (.NOT.LSAME(DIAG,'U') .AND. .NOT.LSAME(DIAG,'N')) THEN
+ INFO = 3
+ ELSE IF (N.LT.0) THEN
+ INFO = 4
+ ELSE IF (INCX.EQ.0) THEN
+ INFO = 7
+ END IF
+ IF (INFO.NE.0) THEN
+ CALL XERBLA('DTPMV ',INFO)
+ RETURN
+ END IF
+*
+* Quick return if possible.
+*
+ IF (N.EQ.0) RETURN
+*
+ NOUNIT = LSAME(DIAG,'N')
+*
+* Set up the start point in X if the increment is not unity. This
+* will be ( N - 1 )*INCX too small for descending loops.
+*
+ IF (INCX.LE.0) THEN
+ KX = 1 - (N-1)*INCX
+ ELSE IF (INCX.NE.1) THEN
+ KX = 1
+ END IF
+*
+* Start the operations. In this version the elements of AP are
+* accessed sequentially with one pass through AP.
+*
+ IF (LSAME(TRANS,'N')) THEN
+*
+* Form x:= A*x.
+*
+ IF (LSAME(UPLO,'U')) THEN
+ KK = 1
+ IF (INCX.EQ.1) THEN
+ DO 20 J = 1,N
+ IF (X(J).NE.ZERO) THEN
+ TEMP = X(J)
+ K = KK
+ DO 10 I = 1,J - 1
+ X(I) = X(I) + TEMP*AP(K)
+ K = K + 1
+ 10 CONTINUE
+ IF (NOUNIT) X(J) = X(J)*AP(KK+J-1)
+ END IF
+ KK = KK + J
+ 20 CONTINUE
+ ELSE
+ JX = KX
+ DO 40 J = 1,N
+ IF (X(JX).NE.ZERO) THEN
+ TEMP = X(JX)
+ IX = KX
+ DO 30 K = KK,KK + J - 2
+ X(IX) = X(IX) + TEMP*AP(K)
+ IX = IX + INCX
+ 30 CONTINUE
+ IF (NOUNIT) X(JX) = X(JX)*AP(KK+J-1)
+ END IF
+ JX = JX + INCX
+ KK = KK + J
+ 40 CONTINUE
+ END IF
+ ELSE
+ KK = (N* (N+1))/2
+ IF (INCX.EQ.1) THEN
+ DO 60 J = N,1,-1
+ IF (X(J).NE.ZERO) THEN
+ TEMP = X(J)
+ K = KK
+ DO 50 I = N,J + 1,-1
+ X(I) = X(I) + TEMP*AP(K)
+ K = K - 1
+ 50 CONTINUE
+ IF (NOUNIT) X(J) = X(J)*AP(KK-N+J)
+ END IF
+ KK = KK - (N-J+1)
+ 60 CONTINUE
+ ELSE
+ KX = KX + (N-1)*INCX
+ JX = KX
+ DO 80 J = N,1,-1
+ IF (X(JX).NE.ZERO) THEN
+ TEMP = X(JX)
+ IX = KX
+ DO 70 K = KK,KK - (N- (J+1)),-1
+ X(IX) = X(IX) + TEMP*AP(K)
+ IX = IX - INCX
+ 70 CONTINUE
+ IF (NOUNIT) X(JX) = X(JX)*AP(KK-N+J)
+ END IF
+ JX = JX - INCX
+ KK = KK - (N-J+1)
+ 80 CONTINUE
+ END IF
+ END IF
+ ELSE
+*
+* Form x := A'*x.
+*
+ IF (LSAME(UPLO,'U')) THEN
+ KK = (N* (N+1))/2
+ IF (INCX.EQ.1) THEN
+ DO 100 J = N,1,-1
+ TEMP = X(J)
+ IF (NOUNIT) TEMP = TEMP*AP(KK)
+ K = KK - 1
+ DO 90 I = J - 1,1,-1
+ TEMP = TEMP + AP(K)*X(I)
+ K = K - 1
+ 90 CONTINUE
+ X(J) = TEMP
+ KK = KK - J
+ 100 CONTINUE
+ ELSE
+ JX = KX + (N-1)*INCX
+ DO 120 J = N,1,-1
+ TEMP = X(JX)
+ IX = JX
+ IF (NOUNIT) TEMP = TEMP*AP(KK)
+ DO 110 K = KK - 1,KK - J + 1,-1
+ IX = IX - INCX
+ TEMP = TEMP + AP(K)*X(IX)
+ 110 CONTINUE
+ X(JX) = TEMP
+ JX = JX - INCX
+ KK = KK - J
+ 120 CONTINUE
+ END IF
+ ELSE
+ KK = 1
+ IF (INCX.EQ.1) THEN
+ DO 140 J = 1,N
+ TEMP = X(J)
+ IF (NOUNIT) TEMP = TEMP*AP(KK)
+ K = KK + 1
+ DO 130 I = J + 1,N
+ TEMP = TEMP + AP(K)*X(I)
+ K = K + 1
+ 130 CONTINUE
+ X(J) = TEMP
+ KK = KK + (N-J+1)
+ 140 CONTINUE
+ ELSE
+ JX = KX
+ DO 160 J = 1,N
+ TEMP = X(JX)
+ IX = JX
+ IF (NOUNIT) TEMP = TEMP*AP(KK)
+ DO 150 K = KK + 1,KK + N - J
+ IX = IX + INCX
+ TEMP = TEMP + AP(K)*X(IX)
+ 150 CONTINUE
+ X(JX) = TEMP
+ JX = JX + INCX
+ KK = KK + (N-J+1)
+ 160 CONTINUE
+ END IF
+ END IF
+ END IF
+*
+ RETURN
+*
+* End of DTPMV .
+*
+ END
diff --git a/blas/dtpsv.f b/blas/dtpsv.f
new file mode 100644
index 000000000..c7e58d32f
--- /dev/null
+++ b/blas/dtpsv.f
@@ -0,0 +1,296 @@
+ SUBROUTINE DTPSV(UPLO,TRANS,DIAG,N,AP,X,INCX)
+* .. Scalar Arguments ..
+ INTEGER INCX,N
+ CHARACTER DIAG,TRANS,UPLO
+* ..
+* .. Array Arguments ..
+ DOUBLE PRECISION AP(*),X(*)
+* ..
+*
+* Purpose
+* =======
+*
+* DTPSV solves one of the systems of equations
+*
+* A*x = b, or A'*x = b,
+*
+* where b and x are n element vectors and A is an n by n unit, or
+* non-unit, upper or lower triangular matrix, supplied in packed form.
+*
+* No test for singularity or near-singularity is included in this
+* routine. Such tests must be performed before calling this routine.
+*
+* Arguments
+* ==========
+*
+* UPLO - CHARACTER*1.
+* On entry, UPLO specifies whether the matrix is an upper or
+* lower triangular matrix as follows:
+*
+* UPLO = 'U' or 'u' A is an upper triangular matrix.
+*
+* UPLO = 'L' or 'l' A is a lower triangular matrix.
+*
+* Unchanged on exit.
+*
+* TRANS - CHARACTER*1.
+* On entry, TRANS specifies the equations to be solved as
+* follows:
+*
+* TRANS = 'N' or 'n' A*x = b.
+*
+* TRANS = 'T' or 't' A'*x = b.
+*
+* TRANS = 'C' or 'c' A'*x = b.
+*
+* Unchanged on exit.
+*
+* DIAG - CHARACTER*1.
+* On entry, DIAG specifies whether or not A is unit
+* triangular as follows:
+*
+* DIAG = 'U' or 'u' A is assumed to be unit triangular.
+*
+* DIAG = 'N' or 'n' A is not assumed to be unit
+* triangular.
+*
+* Unchanged on exit.
+*
+* N - INTEGER.
+* On entry, N specifies the order of the matrix A.
+* N must be at least zero.
+* Unchanged on exit.
+*
+* AP - DOUBLE PRECISION array of DIMENSION at least
+* ( ( n*( n + 1 ) )/2 ).
+* Before entry with UPLO = 'U' or 'u', the array AP must
+* contain the upper triangular matrix packed sequentially,
+* column by column, so that AP( 1 ) contains a( 1, 1 ),
+* AP( 2 ) and AP( 3 ) contain a( 1, 2 ) and a( 2, 2 )
+* respectively, and so on.
+* Before entry with UPLO = 'L' or 'l', the array AP must
+* contain the lower triangular matrix packed sequentially,
+* column by column, so that AP( 1 ) contains a( 1, 1 ),
+* AP( 2 ) and AP( 3 ) contain a( 2, 1 ) and a( 3, 1 )
+* respectively, and so on.
+* Note that when DIAG = 'U' or 'u', the diagonal elements of
+* A are not referenced, but are assumed to be unity.
+* Unchanged on exit.
+*
+* X - DOUBLE PRECISION array of dimension at least
+* ( 1 + ( n - 1 )*abs( INCX ) ).
+* Before entry, the incremented array X must contain the n
+* element right-hand side vector b. On exit, X is overwritten
+* with the solution vector x.
+*
+* INCX - INTEGER.
+* On entry, INCX specifies the increment for the elements of
+* X. INCX must not be zero.
+* Unchanged on exit.
+*
+* Further Details
+* ===============
+*
+* Level 2 Blas routine.
+*
+* -- Written on 22-October-1986.
+* Jack Dongarra, Argonne National Lab.
+* Jeremy Du Croz, Nag Central Office.
+* Sven Hammarling, Nag Central Office.
+* Richard Hanson, Sandia National Labs.
+*
+* =====================================================================
+*
+* .. Parameters ..
+ DOUBLE PRECISION ZERO
+ PARAMETER (ZERO=0.0D+0)
+* ..
+* .. Local Scalars ..
+ DOUBLE PRECISION TEMP
+ INTEGER I,INFO,IX,J,JX,K,KK,KX
+ LOGICAL NOUNIT
+* ..
+* .. External Functions ..
+ LOGICAL LSAME
+ EXTERNAL LSAME
+* ..
+* .. External Subroutines ..
+ EXTERNAL XERBLA
+* ..
+*
+* Test the input parameters.
+*
+ INFO = 0
+ IF (.NOT.LSAME(UPLO,'U') .AND. .NOT.LSAME(UPLO,'L')) THEN
+ INFO = 1
+ ELSE IF (.NOT.LSAME(TRANS,'N') .AND. .NOT.LSAME(TRANS,'T') .AND.
+ + .NOT.LSAME(TRANS,'C')) THEN
+ INFO = 2
+ ELSE IF (.NOT.LSAME(DIAG,'U') .AND. .NOT.LSAME(DIAG,'N')) THEN
+ INFO = 3
+ ELSE IF (N.LT.0) THEN
+ INFO = 4
+ ELSE IF (INCX.EQ.0) THEN
+ INFO = 7
+ END IF
+ IF (INFO.NE.0) THEN
+ CALL XERBLA('DTPSV ',INFO)
+ RETURN
+ END IF
+*
+* Quick return if possible.
+*
+ IF (N.EQ.0) RETURN
+*
+ NOUNIT = LSAME(DIAG,'N')
+*
+* Set up the start point in X if the increment is not unity. This
+* will be ( N - 1 )*INCX too small for descending loops.
+*
+ IF (INCX.LE.0) THEN
+ KX = 1 - (N-1)*INCX
+ ELSE IF (INCX.NE.1) THEN
+ KX = 1
+ END IF
+*
+* Start the operations. In this version the elements of AP are
+* accessed sequentially with one pass through AP.
+*
+ IF (LSAME(TRANS,'N')) THEN
+*
+* Form x := inv( A )*x.
+*
+ IF (LSAME(UPLO,'U')) THEN
+ KK = (N* (N+1))/2
+ IF (INCX.EQ.1) THEN
+ DO 20 J = N,1,-1
+ IF (X(J).NE.ZERO) THEN
+ IF (NOUNIT) X(J) = X(J)/AP(KK)
+ TEMP = X(J)
+ K = KK - 1
+ DO 10 I = J - 1,1,-1
+ X(I) = X(I) - TEMP*AP(K)
+ K = K - 1
+ 10 CONTINUE
+ END IF
+ KK = KK - J
+ 20 CONTINUE
+ ELSE
+ JX = KX + (N-1)*INCX
+ DO 40 J = N,1,-1
+ IF (X(JX).NE.ZERO) THEN
+ IF (NOUNIT) X(JX) = X(JX)/AP(KK)
+ TEMP = X(JX)
+ IX = JX
+ DO 30 K = KK - 1,KK - J + 1,-1
+ IX = IX - INCX
+ X(IX) = X(IX) - TEMP*AP(K)
+ 30 CONTINUE
+ END IF
+ JX = JX - INCX
+ KK = KK - J
+ 40 CONTINUE
+ END IF
+ ELSE
+ KK = 1
+ IF (INCX.EQ.1) THEN
+ DO 60 J = 1,N
+ IF (X(J).NE.ZERO) THEN
+ IF (NOUNIT) X(J) = X(J)/AP(KK)
+ TEMP = X(J)
+ K = KK + 1
+ DO 50 I = J + 1,N
+ X(I) = X(I) - TEMP*AP(K)
+ K = K + 1
+ 50 CONTINUE
+ END IF
+ KK = KK + (N-J+1)
+ 60 CONTINUE
+ ELSE
+ JX = KX
+ DO 80 J = 1,N
+ IF (X(JX).NE.ZERO) THEN
+ IF (NOUNIT) X(JX) = X(JX)/AP(KK)
+ TEMP = X(JX)
+ IX = JX
+ DO 70 K = KK + 1,KK + N - J
+ IX = IX + INCX
+ X(IX) = X(IX) - TEMP*AP(K)
+ 70 CONTINUE
+ END IF
+ JX = JX + INCX
+ KK = KK + (N-J+1)
+ 80 CONTINUE
+ END IF
+ END IF
+ ELSE
+*
+* Form x := inv( A' )*x.
+*
+ IF (LSAME(UPLO,'U')) THEN
+ KK = 1
+ IF (INCX.EQ.1) THEN
+ DO 100 J = 1,N
+ TEMP = X(J)
+ K = KK
+ DO 90 I = 1,J - 1
+ TEMP = TEMP - AP(K)*X(I)
+ K = K + 1
+ 90 CONTINUE
+ IF (NOUNIT) TEMP = TEMP/AP(KK+J-1)
+ X(J) = TEMP
+ KK = KK + J
+ 100 CONTINUE
+ ELSE
+ JX = KX
+ DO 120 J = 1,N
+ TEMP = X(JX)
+ IX = KX
+ DO 110 K = KK,KK + J - 2
+ TEMP = TEMP - AP(K)*X(IX)
+ IX = IX + INCX
+ 110 CONTINUE
+ IF (NOUNIT) TEMP = TEMP/AP(KK+J-1)
+ X(JX) = TEMP
+ JX = JX + INCX
+ KK = KK + J
+ 120 CONTINUE
+ END IF
+ ELSE
+ KK = (N* (N+1))/2
+ IF (INCX.EQ.1) THEN
+ DO 140 J = N,1,-1
+ TEMP = X(J)
+ K = KK
+ DO 130 I = N,J + 1,-1
+ TEMP = TEMP - AP(K)*X(I)
+ K = K - 1
+ 130 CONTINUE
+ IF (NOUNIT) TEMP = TEMP/AP(KK-N+J)
+ X(J) = TEMP
+ KK = KK - (N-J+1)
+ 140 CONTINUE
+ ELSE
+ KX = KX + (N-1)*INCX
+ JX = KX
+ DO 160 J = N,1,-1
+ TEMP = X(JX)
+ IX = KX
+ DO 150 K = KK,KK - (N- (J+1)),-1
+ TEMP = TEMP - AP(K)*X(IX)
+ IX = IX - INCX
+ 150 CONTINUE
+ IF (NOUNIT) TEMP = TEMP/AP(KK-N+J)
+ X(JX) = TEMP
+ JX = JX - INCX
+ KK = KK - (N-J+1)
+ 160 CONTINUE
+ END IF
+ END IF
+ END IF
+*
+ RETURN
+*
+* End of DTPSV .
+*
+ END
diff --git a/blas/level1_cplx_impl.h b/blas/level1_cplx_impl.h
new file mode 100644
index 000000000..8d6b92829
--- /dev/null
+++ b/blas/level1_cplx_impl.h
@@ -0,0 +1,127 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra.
+//
+// Copyright (C) 2009-2010 Gael Guennebaud <gael.guennebaud@inria.fr>
+//
+// This Source Code Form is subject to the terms of the Mozilla
+// Public License v. 2.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 "common.h"
+
+struct scalar_norm1_op {
+ typedef RealScalar result_type;
+ EIGEN_EMPTY_STRUCT_CTOR(scalar_norm1_op)
+ inline RealScalar operator() (const Scalar& a) const { return internal::norm1(a); }
+};
+namespace Eigen {
+ namespace internal {
+ template<> struct functor_traits<scalar_norm1_op >
+ {
+ enum { Cost = 3 * NumTraits<Scalar>::AddCost, PacketAccess = 0 };
+ };
+ }
+}
+
+// computes the sum of magnitudes of all vector elements or, for a complex vector x, the sum
+// res = |Rex1| + |Imx1| + |Rex2| + |Imx2| + ... + |Rexn| + |Imxn|, where x is a vector of order n
+RealScalar EIGEN_CAT(EIGEN_CAT(REAL_SCALAR_SUFFIX,SCALAR_SUFFIX),asum_)(int *n, RealScalar *px, int *incx)
+{
+// std::cerr << "__asum " << *n << " " << *incx << "\n";
+ Complex* x = reinterpret_cast<Complex*>(px);
+
+ if(*n<=0) return 0;
+
+ if(*incx==1) return vector(x,*n).unaryExpr<scalar_norm1_op>().sum();
+ else return vector(x,*n,std::abs(*incx)).unaryExpr<scalar_norm1_op>().sum();
+}
+
+// computes a dot product of a conjugated vector with another vector.
+int EIGEN_BLAS_FUNC(dotcw)(int *n, RealScalar *px, int *incx, RealScalar *py, int *incy, RealScalar* pres)
+{
+// std::cerr << "_dotc " << *n << " " << *incx << " " << *incy << "\n";
+
+ if(*n<=0) return 0;
+
+ Scalar* x = reinterpret_cast<Scalar*>(px);
+ Scalar* y = reinterpret_cast<Scalar*>(py);
+ Scalar* res = reinterpret_cast<Scalar*>(pres);
+
+ if(*incx==1 && *incy==1) *res = (vector(x,*n).dot(vector(y,*n)));
+ else if(*incx>0 && *incy>0) *res = (vector(x,*n,*incx).dot(vector(y,*n,*incy)));
+ else if(*incx<0 && *incy>0) *res = (vector(x,*n,-*incx).reverse().dot(vector(y,*n,*incy)));
+ else if(*incx>0 && *incy<0) *res = (vector(x,*n,*incx).dot(vector(y,*n,-*incy).reverse()));
+ else if(*incx<0 && *incy<0) *res = (vector(x,*n,-*incx).reverse().dot(vector(y,*n,-*incy).reverse()));
+ return 0;
+}
+
+// computes a vector-vector dot product without complex conjugation.
+int EIGEN_BLAS_FUNC(dotuw)(int *n, RealScalar *px, int *incx, RealScalar *py, int *incy, RealScalar* pres)
+{
+// std::cerr << "_dotu " << *n << " " << *incx << " " << *incy << "\n";
+
+ if(*n<=0) return 0;
+
+ Scalar* x = reinterpret_cast<Scalar*>(px);
+ Scalar* y = reinterpret_cast<Scalar*>(py);
+ Scalar* res = reinterpret_cast<Scalar*>(pres);
+
+ if(*incx==1 && *incy==1) *res = (vector(x,*n).cwiseProduct(vector(y,*n))).sum();
+ else if(*incx>0 && *incy>0) *res = (vector(x,*n,*incx).cwiseProduct(vector(y,*n,*incy))).sum();
+ else if(*incx<0 && *incy>0) *res = (vector(x,*n,-*incx).reverse().cwiseProduct(vector(y,*n,*incy))).sum();
+ else if(*incx>0 && *incy<0) *res = (vector(x,*n,*incx).cwiseProduct(vector(y,*n,-*incy).reverse())).sum();
+ else if(*incx<0 && *incy<0) *res = (vector(x,*n,-*incx).reverse().cwiseProduct(vector(y,*n,-*incy).reverse())).sum();
+ return 0;
+}
+
+RealScalar EIGEN_CAT(EIGEN_CAT(REAL_SCALAR_SUFFIX,SCALAR_SUFFIX),nrm2_)(int *n, RealScalar *px, int *incx)
+{
+// std::cerr << "__nrm2 " << *n << " " << *incx << "\n";
+ if(*n<=0) return 0;
+
+ Scalar* x = reinterpret_cast<Scalar*>(px);
+
+ if(*incx==1)
+ return vector(x,*n).stableNorm();
+
+ return vector(x,*n,*incx).stableNorm();
+}
+
+int EIGEN_CAT(EIGEN_CAT(SCALAR_SUFFIX,REAL_SCALAR_SUFFIX),rot_)(int *n, RealScalar *px, int *incx, RealScalar *py, int *incy, RealScalar *pc, RealScalar *ps)
+{
+ if(*n<=0) return 0;
+
+ Scalar* x = reinterpret_cast<Scalar*>(px);
+ Scalar* y = reinterpret_cast<Scalar*>(py);
+ RealScalar c = *pc;
+ RealScalar s = *ps;
+
+ StridedVectorType vx(vector(x,*n,std::abs(*incx)));
+ StridedVectorType vy(vector(y,*n,std::abs(*incy)));
+
+ Reverse<StridedVectorType> rvx(vx);
+ Reverse<StridedVectorType> rvy(vy);
+
+ // TODO implement mixed real-scalar rotations
+ if(*incx<0 && *incy>0) internal::apply_rotation_in_the_plane(rvx, vy, JacobiRotation<Scalar>(c,s));
+ else if(*incx>0 && *incy<0) internal::apply_rotation_in_the_plane(vx, rvy, JacobiRotation<Scalar>(c,s));
+ else internal::apply_rotation_in_the_plane(vx, vy, JacobiRotation<Scalar>(c,s));
+
+ return 0;
+}
+
+int EIGEN_CAT(EIGEN_CAT(SCALAR_SUFFIX,REAL_SCALAR_SUFFIX),scal_)(int *n, RealScalar *palpha, RealScalar *px, int *incx)
+{
+ if(*n<=0) return 0;
+
+ Scalar* x = reinterpret_cast<Scalar*>(px);
+ RealScalar alpha = *palpha;
+
+// std::cerr << "__scal " << *n << " " << alpha << " " << *incx << "\n";
+
+ if(*incx==1) vector(x,*n) *= alpha;
+ else vector(x,*n,std::abs(*incx)) *= alpha;
+
+ return 0;
+}
+
diff --git a/blas/level1_impl.h b/blas/level1_impl.h
new file mode 100644
index 000000000..95ea220af
--- /dev/null
+++ b/blas/level1_impl.h
@@ -0,0 +1,164 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra.
+//
+// Copyright (C) 2009-2010 Gael Guennebaud <gael.guennebaud@inria.fr>
+//
+// This Source Code Form is subject to the terms of the Mozilla
+// Public License v. 2.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 "common.h"
+
+int EIGEN_BLAS_FUNC(axpy)(int *n, RealScalar *palpha, RealScalar *px, int *incx, RealScalar *py, int *incy)
+{
+ Scalar* x = reinterpret_cast<Scalar*>(px);
+ Scalar* y = reinterpret_cast<Scalar*>(py);
+ Scalar alpha = *reinterpret_cast<Scalar*>(palpha);
+
+ if(*n<=0) return 0;
+
+ if(*incx==1 && *incy==1) vector(y,*n) += alpha * vector(x,*n);
+ else if(*incx>0 && *incy>0) vector(y,*n,*incy) += alpha * vector(x,*n,*incx);
+ else if(*incx>0 && *incy<0) vector(y,*n,-*incy).reverse() += alpha * vector(x,*n,*incx);
+ else if(*incx<0 && *incy>0) vector(y,*n,*incy) += alpha * vector(x,*n,-*incx).reverse();
+ else if(*incx<0 && *incy<0) vector(y,*n,-*incy).reverse() += alpha * vector(x,*n,-*incx).reverse();
+
+ return 0;
+}
+
+int EIGEN_BLAS_FUNC(copy)(int *n, RealScalar *px, int *incx, RealScalar *py, int *incy)
+{
+ if(*n<=0) return 0;
+
+ Scalar* x = reinterpret_cast<Scalar*>(px);
+ Scalar* y = reinterpret_cast<Scalar*>(py);
+
+ // be carefull, *incx==0 is allowed !!
+ if(*incx==1 && *incy==1)
+ vector(y,*n) = vector(x,*n);
+ else
+ {
+ if(*incx<0) x = x - (*n-1)*(*incx);
+ if(*incy<0) y = y - (*n-1)*(*incy);
+ for(int i=0;i<*n;++i)
+ {
+ *y = *x;
+ x += *incx;
+ y += *incy;
+ }
+ }
+
+ return 0;
+}
+
+int EIGEN_CAT(EIGEN_CAT(i,SCALAR_SUFFIX),amax_)(int *n, RealScalar *px, int *incx)
+{
+ if(*n<=0) return 0;
+ Scalar* x = reinterpret_cast<Scalar*>(px);
+
+ DenseIndex ret;
+ if(*incx==1) vector(x,*n).cwiseAbs().maxCoeff(&ret);
+ else vector(x,*n,std::abs(*incx)).cwiseAbs().maxCoeff(&ret);
+ return ret+1;
+}
+
+int EIGEN_CAT(EIGEN_CAT(i,SCALAR_SUFFIX),amin_)(int *n, RealScalar *px, int *incx)
+{
+ if(*n<=0) return 0;
+ Scalar* x = reinterpret_cast<Scalar*>(px);
+
+ DenseIndex ret;
+ if(*incx==1) vector(x,*n).cwiseAbs().minCoeff(&ret);
+ else vector(x,*n,std::abs(*incx)).cwiseAbs().minCoeff(&ret);
+ return ret+1;
+}
+
+int EIGEN_BLAS_FUNC(rotg)(RealScalar *pa, RealScalar *pb, RealScalar *pc, RealScalar *ps)
+{
+ Scalar& a = *reinterpret_cast<Scalar*>(pa);
+ Scalar& b = *reinterpret_cast<Scalar*>(pb);
+ RealScalar* c = pc;
+ Scalar* s = reinterpret_cast<Scalar*>(ps);
+
+ #if !ISCOMPLEX
+ Scalar r,z;
+ Scalar aa = internal::abs(a);
+ Scalar ab = internal::abs(b);
+ if((aa+ab)==Scalar(0))
+ {
+ *c = 1;
+ *s = 0;
+ r = 0;
+ z = 0;
+ }
+ else
+ {
+ r = internal::sqrt(a*a + b*b);
+ Scalar amax = aa>ab ? a : b;
+ r = amax>0 ? r : -r;
+ *c = a/r;
+ *s = b/r;
+ z = 1;
+ if (aa > ab) z = *s;
+ if (ab > aa && *c!=RealScalar(0))
+ z = Scalar(1)/ *c;
+ }
+ *pa = r;
+ *pb = z;
+ #else
+ Scalar alpha;
+ RealScalar norm,scale;
+ if(internal::abs(a)==RealScalar(0))
+ {
+ *c = RealScalar(0);
+ *s = Scalar(1);
+ a = b;
+ }
+ else
+ {
+ scale = internal::abs(a) + internal::abs(b);
+ norm = scale*internal::sqrt((internal::abs2(a/scale))+ (internal::abs2(b/scale)));
+ alpha = a/internal::abs(a);
+ *c = internal::abs(a)/norm;
+ *s = alpha*internal::conj(b)/norm;
+ a = alpha*norm;
+ }
+ #endif
+
+// JacobiRotation<Scalar> r;
+// r.makeGivens(a,b);
+// *c = r.c();
+// *s = r.s();
+
+ return 0;
+}
+
+int EIGEN_BLAS_FUNC(scal)(int *n, RealScalar *palpha, RealScalar *px, int *incx)
+{
+ if(*n<=0) return 0;
+
+ Scalar* x = reinterpret_cast<Scalar*>(px);
+ Scalar alpha = *reinterpret_cast<Scalar*>(palpha);
+
+ if(*incx==1) vector(x,*n) *= alpha;
+ else vector(x,*n,std::abs(*incx)) *= alpha;
+
+ return 0;
+}
+
+int EIGEN_BLAS_FUNC(swap)(int *n, RealScalar *px, int *incx, RealScalar *py, int *incy)
+{
+ if(*n<=0) return 0;
+
+ Scalar* x = reinterpret_cast<Scalar*>(px);
+ Scalar* y = reinterpret_cast<Scalar*>(py);
+
+ if(*incx==1 && *incy==1) vector(y,*n).swap(vector(x,*n));
+ else if(*incx>0 && *incy>0) vector(y,*n,*incy).swap(vector(x,*n,*incx));
+ else if(*incx>0 && *incy<0) vector(y,*n,-*incy).reverse().swap(vector(x,*n,*incx));
+ else if(*incx<0 && *incy>0) vector(y,*n,*incy).swap(vector(x,*n,-*incx).reverse());
+ else if(*incx<0 && *incy<0) vector(y,*n,-*incy).reverse().swap(vector(x,*n,-*incx).reverse());
+
+ return 1;
+}
+
diff --git a/blas/level1_real_impl.h b/blas/level1_real_impl.h
new file mode 100644
index 000000000..8acecdfc6
--- /dev/null
+++ b/blas/level1_real_impl.h
@@ -0,0 +1,100 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra.
+//
+// Copyright (C) 2009-2010 Gael Guennebaud <gael.guennebaud@inria.fr>
+//
+// This Source Code Form is subject to the terms of the Mozilla
+// Public License v. 2.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 "common.h"
+
+// computes the sum of magnitudes of all vector elements or, for a complex vector x, the sum
+// res = |Rex1| + |Imx1| + |Rex2| + |Imx2| + ... + |Rexn| + |Imxn|, where x is a vector of order n
+RealScalar EIGEN_BLAS_FUNC(asum)(int *n, RealScalar *px, int *incx)
+{
+// std::cerr << "_asum " << *n << " " << *incx << "\n";
+
+ Scalar* x = reinterpret_cast<Scalar*>(px);
+
+ if(*n<=0) return 0;
+
+ if(*incx==1) return vector(x,*n).cwiseAbs().sum();
+ else return vector(x,*n,std::abs(*incx)).cwiseAbs().sum();
+}
+
+// computes a vector-vector dot product.
+Scalar EIGEN_BLAS_FUNC(dot)(int *n, RealScalar *px, int *incx, RealScalar *py, int *incy)
+{
+// std::cerr << "_dot " << *n << " " << *incx << " " << *incy << "\n";
+
+ if(*n<=0) return 0;
+
+ Scalar* x = reinterpret_cast<Scalar*>(px);
+ Scalar* y = reinterpret_cast<Scalar*>(py);
+
+ if(*incx==1 && *incy==1) return (vector(x,*n).cwiseProduct(vector(y,*n))).sum();
+ else if(*incx>0 && *incy>0) return (vector(x,*n,*incx).cwiseProduct(vector(y,*n,*incy))).sum();
+ else if(*incx<0 && *incy>0) return (vector(x,*n,-*incx).reverse().cwiseProduct(vector(y,*n,*incy))).sum();
+ else if(*incx>0 && *incy<0) return (vector(x,*n,*incx).cwiseProduct(vector(y,*n,-*incy).reverse())).sum();
+ else if(*incx<0 && *incy<0) return (vector(x,*n,-*incx).reverse().cwiseProduct(vector(y,*n,-*incy).reverse())).sum();
+ else return 0;
+}
+
+// computes the Euclidean norm of a vector.
+// FIXME
+Scalar EIGEN_BLAS_FUNC(nrm2)(int *n, RealScalar *px, int *incx)
+{
+// std::cerr << "_nrm2 " << *n << " " << *incx << "\n";
+ if(*n<=0) return 0;
+
+ Scalar* x = reinterpret_cast<Scalar*>(px);
+
+ if(*incx==1) return vector(x,*n).stableNorm();
+ else return vector(x,*n,std::abs(*incx)).stableNorm();
+}
+
+int EIGEN_BLAS_FUNC(rot)(int *n, RealScalar *px, int *incx, RealScalar *py, int *incy, RealScalar *pc, RealScalar *ps)
+{
+// std::cerr << "_rot " << *n << " " << *incx << " " << *incy << "\n";
+ if(*n<=0) return 0;
+
+ Scalar* x = reinterpret_cast<Scalar*>(px);
+ Scalar* y = reinterpret_cast<Scalar*>(py);
+ Scalar c = *reinterpret_cast<Scalar*>(pc);
+ Scalar s = *reinterpret_cast<Scalar*>(ps);
+
+ StridedVectorType vx(vector(x,*n,std::abs(*incx)));
+ StridedVectorType vy(vector(y,*n,std::abs(*incy)));
+
+ Reverse<StridedVectorType> rvx(vx);
+ Reverse<StridedVectorType> rvy(vy);
+
+ if(*incx<0 && *incy>0) internal::apply_rotation_in_the_plane(rvx, vy, JacobiRotation<Scalar>(c,s));
+ else if(*incx>0 && *incy<0) internal::apply_rotation_in_the_plane(vx, rvy, JacobiRotation<Scalar>(c,s));
+ else internal::apply_rotation_in_the_plane(vx, vy, JacobiRotation<Scalar>(c,s));
+
+
+ return 0;
+}
+
+/*
+// performs rotation of points in the modified plane.
+int EIGEN_BLAS_FUNC(rotm)(int *n, RealScalar *px, int *incx, RealScalar *py, int *incy, RealScalar *param)
+{
+ Scalar* x = reinterpret_cast<Scalar*>(px);
+ Scalar* y = reinterpret_cast<Scalar*>(py);
+
+ // TODO
+
+ return 0;
+}
+
+// computes the modified parameters for a Givens rotation.
+int EIGEN_BLAS_FUNC(rotmg)(RealScalar *d1, RealScalar *d2, RealScalar *x1, RealScalar *x2, RealScalar *param)
+{
+ // TODO
+
+ return 0;
+}
+*/
diff --git a/blas/level2_cplx_impl.h b/blas/level2_cplx_impl.h
new file mode 100644
index 000000000..7878f2a16
--- /dev/null
+++ b/blas/level2_cplx_impl.h
@@ -0,0 +1,270 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra.
+//
+// Copyright (C) 2009-2010 Gael Guennebaud <gael.guennebaud@inria.fr>
+//
+// This Source Code Form is subject to the terms of the Mozilla
+// Public License v. 2.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 "common.h"
+
+/** ZHEMV performs the matrix-vector operation
+ *
+ * y := alpha*A*x + beta*y,
+ *
+ * where alpha and beta are scalars, x and y are n element vectors and
+ * A is an n by n hermitian matrix.
+ */
+int EIGEN_BLAS_FUNC(hemv)(char *uplo, int *n, RealScalar *palpha, RealScalar *pa, int *lda, RealScalar *px, int *incx, RealScalar *pbeta, RealScalar *py, int *incy)
+{
+ Scalar* a = reinterpret_cast<Scalar*>(pa);
+ Scalar* x = reinterpret_cast<Scalar*>(px);
+ Scalar* y = reinterpret_cast<Scalar*>(py);
+ Scalar alpha = *reinterpret_cast<Scalar*>(palpha);
+ Scalar beta = *reinterpret_cast<Scalar*>(pbeta);
+
+ // check arguments
+ int info = 0;
+ if(UPLO(*uplo)==INVALID) info = 1;
+ else if(*n<0) info = 2;
+ else if(*lda<std::max(1,*n)) info = 5;
+ else if(*incx==0) info = 7;
+ else if(*incy==0) info = 10;
+ if(info)
+ return xerbla_(SCALAR_SUFFIX_UP"HEMV ",&info,6);
+
+ if(*n==0)
+ return 1;
+
+ Scalar* actual_x = get_compact_vector(x,*n,*incx);
+ Scalar* actual_y = get_compact_vector(y,*n,*incy);
+
+ if(beta!=Scalar(1))
+ {
+ if(beta==Scalar(0)) vector(actual_y, *n).setZero();
+ else vector(actual_y, *n) *= beta;
+ }
+
+ if(alpha!=Scalar(0))
+ {
+ // TODO performs a direct call to the underlying implementation function
+ if(UPLO(*uplo)==UP) vector(actual_y,*n).noalias() += matrix(a,*n,*n,*lda).selfadjointView<Upper>() * (alpha * vector(actual_x,*n));
+ else if(UPLO(*uplo)==LO) vector(actual_y,*n).noalias() += matrix(a,*n,*n,*lda).selfadjointView<Lower>() * (alpha * vector(actual_x,*n));
+ }
+
+ if(actual_x!=x) delete[] actual_x;
+ if(actual_y!=y) delete[] copy_back(actual_y,y,*n,*incy);
+
+ return 1;
+}
+
+/** ZHBMV performs the matrix-vector operation
+ *
+ * y := alpha*A*x + beta*y,
+ *
+ * where alpha and beta are scalars, x and y are n element vectors and
+ * A is an n by n hermitian band matrix, with k super-diagonals.
+ */
+// int EIGEN_BLAS_FUNC(hbmv)(char *uplo, int *n, int *k, RealScalar *alpha, RealScalar *a, int *lda,
+// RealScalar *x, int *incx, RealScalar *beta, RealScalar *y, int *incy)
+// {
+// return 1;
+// }
+
+/** ZHPMV performs the matrix-vector operation
+ *
+ * y := alpha*A*x + beta*y,
+ *
+ * where alpha and beta are scalars, x and y are n element vectors and
+ * A is an n by n hermitian matrix, supplied in packed form.
+ */
+// int EIGEN_BLAS_FUNC(hpmv)(char *uplo, int *n, RealScalar *alpha, RealScalar *ap, RealScalar *x, int *incx, RealScalar *beta, RealScalar *y, int *incy)
+// {
+// return 1;
+// }
+
+/** ZHPR performs the hermitian rank 1 operation
+ *
+ * A := alpha*x*conjg( x' ) + A,
+ *
+ * where alpha is a real scalar, x is an n element vector and A is an
+ * n by n hermitian matrix, supplied in packed form.
+ */
+// int EIGEN_BLAS_FUNC(hpr)(char *uplo, int *n, RealScalar *alpha, RealScalar *x, int *incx, RealScalar *ap)
+// {
+// return 1;
+// }
+
+/** ZHPR2 performs the hermitian rank 2 operation
+ *
+ * A := alpha*x*conjg( y' ) + conjg( alpha )*y*conjg( x' ) + A,
+ *
+ * where alpha is a scalar, x and y are n element vectors and A is an
+ * n by n hermitian matrix, supplied in packed form.
+ */
+// int EIGEN_BLAS_FUNC(hpr2)(char *uplo, int *n, RealScalar *palpha, RealScalar *x, int *incx, RealScalar *y, int *incy, RealScalar *ap)
+// {
+// return 1;
+// }
+
+/** ZHER performs the hermitian rank 1 operation
+ *
+ * A := alpha*x*conjg( x' ) + A,
+ *
+ * where alpha is a real scalar, x is an n element vector and A is an
+ * n by n hermitian matrix.
+ */
+int EIGEN_BLAS_FUNC(her)(char *uplo, int *n, RealScalar *palpha, RealScalar *px, int *incx, RealScalar *pa, int *lda)
+{
+ Scalar* x = reinterpret_cast<Scalar*>(px);
+ Scalar* a = reinterpret_cast<Scalar*>(pa);
+ RealScalar alpha = *reinterpret_cast<RealScalar*>(palpha);
+
+ int info = 0;
+ if(UPLO(*uplo)==INVALID) info = 1;
+ else if(*n<0) info = 2;
+ else if(*incx==0) info = 5;
+ else if(*lda<std::max(1,*n)) info = 7;
+ if(info)
+ return xerbla_(SCALAR_SUFFIX_UP"HER ",&info,6);
+
+ if(alpha==RealScalar(0))
+ return 1;
+
+ Scalar* x_cpy = get_compact_vector(x, *n, *incx);
+
+ // TODO perform direct calls to underlying implementation
+// if(UPLO(*uplo)==LO) matrix(a,*n,*n,*lda).selfadjointView<Lower>().rankUpdate(vector(x_cpy,*n), alpha);
+// else if(UPLO(*uplo)==UP) matrix(a,*n,*n,*lda).selfadjointView<Upper>().rankUpdate(vector(x_cpy,*n), alpha);
+
+ if(UPLO(*uplo)==LO)
+ for(int j=0;j<*n;++j)
+ matrix(a,*n,*n,*lda).col(j).tail(*n-j) += alpha * internal::conj(x_cpy[j]) * vector(x_cpy+j,*n-j);
+ else
+ for(int j=0;j<*n;++j)
+ matrix(a,*n,*n,*lda).col(j).head(j+1) += alpha * internal::conj(x_cpy[j]) * vector(x_cpy,j+1);
+
+ matrix(a,*n,*n,*lda).diagonal().imag().setZero();
+
+ if(x_cpy!=x) delete[] x_cpy;
+
+ return 1;
+}
+
+/** ZHER2 performs the hermitian rank 2 operation
+ *
+ * A := alpha*x*conjg( y' ) + conjg( alpha )*y*conjg( x' ) + A,
+ *
+ * where alpha is a scalar, x and y are n element vectors and A is an n
+ * by n hermitian matrix.
+ */
+int EIGEN_BLAS_FUNC(her2)(char *uplo, int *n, RealScalar *palpha, RealScalar *px, int *incx, RealScalar *py, int *incy, RealScalar *pa, int *lda)
+{
+ Scalar* x = reinterpret_cast<Scalar*>(px);
+ Scalar* y = reinterpret_cast<Scalar*>(py);
+ Scalar* a = reinterpret_cast<Scalar*>(pa);
+ Scalar alpha = *reinterpret_cast<Scalar*>(palpha);
+
+ int info = 0;
+ if(UPLO(*uplo)==INVALID) info = 1;
+ else if(*n<0) info = 2;
+ else if(*incx==0) info = 5;
+ else if(*incy==0) info = 7;
+ else if(*lda<std::max(1,*n)) info = 9;
+ if(info)
+ return xerbla_(SCALAR_SUFFIX_UP"HER2 ",&info,6);
+
+ if(alpha==Scalar(0))
+ return 1;
+
+ Scalar* x_cpy = get_compact_vector(x, *n, *incx);
+ Scalar* y_cpy = get_compact_vector(y, *n, *incy);
+
+ // TODO perform direct calls to underlying implementation
+ if(UPLO(*uplo)==LO) matrix(a,*n,*n,*lda).selfadjointView<Lower>().rankUpdate(vector(x_cpy,*n),vector(y_cpy,*n),alpha);
+ else if(UPLO(*uplo)==UP) matrix(a,*n,*n,*lda).selfadjointView<Upper>().rankUpdate(vector(x_cpy,*n),vector(y_cpy,*n),alpha);
+
+ matrix(a,*n,*n,*lda).diagonal().imag().setZero();
+
+ if(x_cpy!=x) delete[] x_cpy;
+ if(y_cpy!=y) delete[] y_cpy;
+
+ return 1;
+}
+
+/** ZGERU performs the rank 1 operation
+ *
+ * A := alpha*x*y' + A,
+ *
+ * where alpha is a scalar, x is an m element vector, y is an n element
+ * vector and A is an m by n matrix.
+ */
+int EIGEN_BLAS_FUNC(geru)(int *m, int *n, RealScalar *palpha, RealScalar *px, int *incx, RealScalar *py, int *incy, RealScalar *pa, int *lda)
+{
+ Scalar* x = reinterpret_cast<Scalar*>(px);
+ Scalar* y = reinterpret_cast<Scalar*>(py);
+ Scalar* a = reinterpret_cast<Scalar*>(pa);
+ Scalar alpha = *reinterpret_cast<Scalar*>(palpha);
+
+ int info = 0;
+ if(*m<0) info = 1;
+ else if(*n<0) info = 2;
+ else if(*incx==0) info = 5;
+ else if(*incy==0) info = 7;
+ else if(*lda<std::max(1,*m)) info = 9;
+ if(info)
+ return xerbla_(SCALAR_SUFFIX_UP"GERU ",&info,6);
+
+ if(alpha==Scalar(0))
+ return 1;
+
+ Scalar* x_cpy = get_compact_vector(x,*m,*incx);
+ Scalar* y_cpy = get_compact_vector(y,*n,*incy);
+
+ // TODO perform direct calls to underlying implementation
+ matrix(a,*m,*n,*lda) += alpha * vector(x_cpy,*m) * vector(y_cpy,*n).transpose();
+
+ if(x_cpy!=x) delete[] x_cpy;
+ if(y_cpy!=y) delete[] y_cpy;
+
+ return 1;
+}
+
+/** ZGERC performs the rank 1 operation
+ *
+ * A := alpha*x*conjg( y' ) + A,
+ *
+ * where alpha is a scalar, x is an m element vector, y is an n element
+ * vector and A is an m by n matrix.
+ */
+int EIGEN_BLAS_FUNC(gerc)(int *m, int *n, RealScalar *palpha, RealScalar *px, int *incx, RealScalar *py, int *incy, RealScalar *pa, int *lda)
+{
+ Scalar* x = reinterpret_cast<Scalar*>(px);
+ Scalar* y = reinterpret_cast<Scalar*>(py);
+ Scalar* a = reinterpret_cast<Scalar*>(pa);
+ Scalar alpha = *reinterpret_cast<Scalar*>(palpha);
+
+ int info = 0;
+ if(*m<0) info = 1;
+ else if(*n<0) info = 2;
+ else if(*incx==0) info = 5;
+ else if(*incy==0) info = 7;
+ else if(*lda<std::max(1,*m)) info = 9;
+ if(info)
+ return xerbla_(SCALAR_SUFFIX_UP"GERC ",&info,6);
+
+ if(alpha==Scalar(0))
+ return 1;
+
+ Scalar* x_cpy = get_compact_vector(x,*m,*incx);
+ Scalar* y_cpy = get_compact_vector(y,*n,*incy);
+
+ // TODO perform direct calls to underlying implementation
+ matrix(a,*m,*n,*lda) += alpha * vector(x_cpy,*m) * vector(y_cpy,*n).adjoint();
+
+ if(x_cpy!=x) delete[] x_cpy;
+ if(y_cpy!=y) delete[] y_cpy;
+
+ return 1;
+}
diff --git a/blas/level2_impl.h b/blas/level2_impl.h
new file mode 100644
index 000000000..7099cf96d
--- /dev/null
+++ b/blas/level2_impl.h
@@ -0,0 +1,457 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra.
+//
+// Copyright (C) 2009-2010 Gael Guennebaud <gael.guennebaud@inria.fr>
+//
+// This Source Code Form is subject to the terms of the Mozilla
+// Public License v. 2.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 "common.h"
+
+int EIGEN_BLAS_FUNC(gemv)(char *opa, int *m, int *n, RealScalar *palpha, RealScalar *pa, int *lda, RealScalar *pb, int *incb, RealScalar *pbeta, RealScalar *pc, int *incc)
+{
+ typedef void (*functype)(int, int, const Scalar *, int, const Scalar *, int , Scalar *, int, Scalar);
+ static functype func[4];
+
+ static bool init = false;
+ if(!init)
+ {
+ for(int k=0; k<4; ++k)
+ func[k] = 0;
+
+ func[NOTR] = (internal::general_matrix_vector_product<int,Scalar,ColMajor,false,Scalar,false>::run);
+ func[TR ] = (internal::general_matrix_vector_product<int,Scalar,RowMajor,false,Scalar,false>::run);
+ func[ADJ ] = (internal::general_matrix_vector_product<int,Scalar,RowMajor,Conj, Scalar,false>::run);
+
+ init = true;
+ }
+
+ Scalar* a = reinterpret_cast<Scalar*>(pa);
+ Scalar* b = reinterpret_cast<Scalar*>(pb);
+ Scalar* c = reinterpret_cast<Scalar*>(pc);
+ Scalar alpha = *reinterpret_cast<Scalar*>(palpha);
+ Scalar beta = *reinterpret_cast<Scalar*>(pbeta);
+
+ // check arguments
+ int info = 0;
+ if(OP(*opa)==INVALID) info = 1;
+ else if(*m<0) info = 2;
+ else if(*n<0) info = 3;
+ else if(*lda<std::max(1,*m)) info = 6;
+ else if(*incb==0) info = 8;
+ else if(*incc==0) info = 11;
+ if(info)
+ return xerbla_(SCALAR_SUFFIX_UP"GEMV ",&info,6);
+
+ if(*m==0 || *n==0 || (alpha==Scalar(0) && beta==Scalar(1)))
+ return 0;
+
+ int actual_m = *m;
+ int actual_n = *n;
+ if(OP(*opa)!=NOTR)
+ std::swap(actual_m,actual_n);
+
+ Scalar* actual_b = get_compact_vector(b,actual_n,*incb);
+ Scalar* actual_c = get_compact_vector(c,actual_m,*incc);
+
+ if(beta!=Scalar(1))
+ {
+ if(beta==Scalar(0)) vector(actual_c, actual_m).setZero();
+ else vector(actual_c, actual_m) *= beta;
+ }
+
+ int code = OP(*opa);
+ func[code](actual_m, actual_n, a, *lda, actual_b, 1, actual_c, 1, alpha);
+
+ if(actual_b!=b) delete[] actual_b;
+ if(actual_c!=c) delete[] copy_back(actual_c,c,actual_m,*incc);
+
+ return 1;
+}
+
+int EIGEN_BLAS_FUNC(trsv)(char *uplo, char *opa, char *diag, int *n, RealScalar *pa, int *lda, RealScalar *pb, int *incb)
+{
+ typedef void (*functype)(int, const Scalar *, int, Scalar *);
+ static functype func[16];
+
+ static bool init = false;
+ if(!init)
+ {
+ for(int k=0; k<16; ++k)
+ func[k] = 0;
+
+ func[NOTR | (UP << 2) | (NUNIT << 3)] = (internal::triangular_solve_vector<Scalar,Scalar,int,OnTheLeft, Upper|0, false,ColMajor>::run);
+ func[TR | (UP << 2) | (NUNIT << 3)] = (internal::triangular_solve_vector<Scalar,Scalar,int,OnTheLeft, Lower|0, false,RowMajor>::run);
+ func[ADJ | (UP << 2) | (NUNIT << 3)] = (internal::triangular_solve_vector<Scalar,Scalar,int,OnTheLeft, Lower|0, Conj, RowMajor>::run);
+
+ func[NOTR | (LO << 2) | (NUNIT << 3)] = (internal::triangular_solve_vector<Scalar,Scalar,int,OnTheLeft, Lower|0, false,ColMajor>::run);
+ func[TR | (LO << 2) | (NUNIT << 3)] = (internal::triangular_solve_vector<Scalar,Scalar,int,OnTheLeft, Upper|0, false,RowMajor>::run);
+ func[ADJ | (LO << 2) | (NUNIT << 3)] = (internal::triangular_solve_vector<Scalar,Scalar,int,OnTheLeft, Upper|0, Conj, RowMajor>::run);
+
+ func[NOTR | (UP << 2) | (UNIT << 3)] = (internal::triangular_solve_vector<Scalar,Scalar,int,OnTheLeft, Upper|UnitDiag,false,ColMajor>::run);
+ func[TR | (UP << 2) | (UNIT << 3)] = (internal::triangular_solve_vector<Scalar,Scalar,int,OnTheLeft, Lower|UnitDiag,false,RowMajor>::run);
+ func[ADJ | (UP << 2) | (UNIT << 3)] = (internal::triangular_solve_vector<Scalar,Scalar,int,OnTheLeft, Lower|UnitDiag,Conj, RowMajor>::run);
+
+ func[NOTR | (LO << 2) | (UNIT << 3)] = (internal::triangular_solve_vector<Scalar,Scalar,int,OnTheLeft, Lower|UnitDiag,false,ColMajor>::run);
+ func[TR | (LO << 2) | (UNIT << 3)] = (internal::triangular_solve_vector<Scalar,Scalar,int,OnTheLeft, Upper|UnitDiag,false,RowMajor>::run);
+ func[ADJ | (LO << 2) | (UNIT << 3)] = (internal::triangular_solve_vector<Scalar,Scalar,int,OnTheLeft, Upper|UnitDiag,Conj, RowMajor>::run);
+
+ init = true;
+ }
+
+ Scalar* a = reinterpret_cast<Scalar*>(pa);
+ Scalar* b = reinterpret_cast<Scalar*>(pb);
+
+ int info = 0;
+ if(UPLO(*uplo)==INVALID) info = 1;
+ else if(OP(*opa)==INVALID) info = 2;
+ else if(DIAG(*diag)==INVALID) info = 3;
+ else if(*n<0) info = 4;
+ else if(*lda<std::max(1,*n)) info = 6;
+ else if(*incb==0) info = 8;
+ if(info)
+ return xerbla_(SCALAR_SUFFIX_UP"TRSV ",&info,6);
+
+ Scalar* actual_b = get_compact_vector(b,*n,*incb);
+
+ int code = OP(*opa) | (UPLO(*uplo) << 2) | (DIAG(*diag) << 3);
+ func[code](*n, a, *lda, actual_b);
+
+ if(actual_b!=b) delete[] copy_back(actual_b,b,*n,*incb);
+
+ return 0;
+}
+
+
+
+int EIGEN_BLAS_FUNC(trmv)(char *uplo, char *opa, char *diag, int *n, RealScalar *pa, int *lda, RealScalar *pb, int *incb)
+{
+ typedef void (*functype)(int, int, const Scalar *, int, const Scalar *, int, Scalar *, int, Scalar);
+ static functype func[16];
+
+ static bool init = false;
+ if(!init)
+ {
+ for(int k=0; k<16; ++k)
+ func[k] = 0;
+
+ func[NOTR | (UP << 2) | (NUNIT << 3)] = (internal::triangular_matrix_vector_product<int,Upper|0, Scalar,false,Scalar,false,ColMajor>::run);
+ func[TR | (UP << 2) | (NUNIT << 3)] = (internal::triangular_matrix_vector_product<int,Lower|0, Scalar,false,Scalar,false,RowMajor>::run);
+ func[ADJ | (UP << 2) | (NUNIT << 3)] = (internal::triangular_matrix_vector_product<int,Lower|0, Scalar,Conj, Scalar,false,RowMajor>::run);
+
+ func[NOTR | (LO << 2) | (NUNIT << 3)] = (internal::triangular_matrix_vector_product<int,Lower|0, Scalar,false,Scalar,false,ColMajor>::run);
+ func[TR | (LO << 2) | (NUNIT << 3)] = (internal::triangular_matrix_vector_product<int,Upper|0, Scalar,false,Scalar,false,RowMajor>::run);
+ func[ADJ | (LO << 2) | (NUNIT << 3)] = (internal::triangular_matrix_vector_product<int,Upper|0, Scalar,Conj, Scalar,false,RowMajor>::run);
+
+ func[NOTR | (UP << 2) | (UNIT << 3)] = (internal::triangular_matrix_vector_product<int,Upper|UnitDiag,Scalar,false,Scalar,false,ColMajor>::run);
+ func[TR | (UP << 2) | (UNIT << 3)] = (internal::triangular_matrix_vector_product<int,Lower|UnitDiag,Scalar,false,Scalar,false,RowMajor>::run);
+ func[ADJ | (UP << 2) | (UNIT << 3)] = (internal::triangular_matrix_vector_product<int,Lower|UnitDiag,Scalar,Conj, Scalar,false,RowMajor>::run);
+
+ func[NOTR | (LO << 2) | (UNIT << 3)] = (internal::triangular_matrix_vector_product<int,Lower|UnitDiag,Scalar,false,Scalar,false,ColMajor>::run);
+ func[TR | (LO << 2) | (UNIT << 3)] = (internal::triangular_matrix_vector_product<int,Upper|UnitDiag,Scalar,false,Scalar,false,RowMajor>::run);
+ func[ADJ | (LO << 2) | (UNIT << 3)] = (internal::triangular_matrix_vector_product<int,Upper|UnitDiag,Scalar,Conj, Scalar,false,RowMajor>::run);
+
+ init = true;
+ }
+
+ Scalar* a = reinterpret_cast<Scalar*>(pa);
+ Scalar* b = reinterpret_cast<Scalar*>(pb);
+
+ int info = 0;
+ if(UPLO(*uplo)==INVALID) info = 1;
+ else if(OP(*opa)==INVALID) info = 2;
+ else if(DIAG(*diag)==INVALID) info = 3;
+ else if(*n<0) info = 4;
+ else if(*lda<std::max(1,*n)) info = 6;
+ else if(*incb==0) info = 8;
+ if(info)
+ return xerbla_(SCALAR_SUFFIX_UP"TRMV ",&info,6);
+
+ if(*n==0)
+ return 1;
+
+ Scalar* actual_b = get_compact_vector(b,*n,*incb);
+ Matrix<Scalar,Dynamic,1> res(*n);
+ res.setZero();
+
+ int code = OP(*opa) | (UPLO(*uplo) << 2) | (DIAG(*diag) << 3);
+ if(code>=16 || func[code]==0)
+ return 0;
+
+ func[code](*n, *n, a, *lda, actual_b, 1, res.data(), 1, Scalar(1));
+
+ copy_back(res.data(),b,*n,*incb);
+ if(actual_b!=b) delete[] actual_b;
+
+ return 0;
+}
+
+/** GBMV performs one of the matrix-vector operations
+ *
+ * y := alpha*A*x + beta*y, or y := alpha*A'*x + beta*y,
+ *
+ * where alpha and beta are scalars, x and y are vectors and A is an
+ * m by n band matrix, with kl sub-diagonals and ku super-diagonals.
+ */
+int EIGEN_BLAS_FUNC(gbmv)(char *trans, int *m, int *n, int *kl, int *ku, RealScalar *palpha, RealScalar *pa, int *lda,
+ RealScalar *px, int *incx, RealScalar *pbeta, RealScalar *py, int *incy)
+{
+ Scalar* a = reinterpret_cast<Scalar*>(pa);
+ Scalar* x = reinterpret_cast<Scalar*>(px);
+ Scalar* y = reinterpret_cast<Scalar*>(py);
+ Scalar alpha = *reinterpret_cast<Scalar*>(palpha);
+ Scalar beta = *reinterpret_cast<Scalar*>(pbeta);
+ int coeff_rows = *kl+*ku+1;
+
+ int info = 0;
+ if(OP(*trans)==INVALID) info = 1;
+ else if(*m<0) info = 2;
+ else if(*n<0) info = 3;
+ else if(*kl<0) info = 4;
+ else if(*ku<0) info = 5;
+ else if(*lda<coeff_rows) info = 8;
+ else if(*incx==0) info = 10;
+ else if(*incy==0) info = 13;
+ if(info)
+ return xerbla_(SCALAR_SUFFIX_UP"GBMV ",&info,6);
+
+ if(*m==0 || *n==0 || (alpha==Scalar(0) && beta==Scalar(1)))
+ return 0;
+
+ int actual_m = *m;
+ int actual_n = *n;
+ if(OP(*trans)!=NOTR)
+ std::swap(actual_m,actual_n);
+
+ Scalar* actual_x = get_compact_vector(x,actual_n,*incx);
+ Scalar* actual_y = get_compact_vector(y,actual_m,*incy);
+
+ if(beta!=Scalar(1))
+ {
+ if(beta==Scalar(0)) vector(actual_y, actual_m).setZero();
+ else vector(actual_y, actual_m) *= beta;
+ }
+
+ MatrixType mat_coeffs(a,coeff_rows,*n,*lda);
+
+ int nb = std::min(*n,(*m)+(*ku));
+ for(int j=0; j<nb; ++j)
+ {
+ int start = std::max(0,j - *ku);
+ int end = std::min((*m)-1,j + *kl);
+ int len = end - start + 1;
+ int offset = (*ku) - j + start;
+ if(OP(*trans)==NOTR)
+ vector(actual_y+start,len) += (alpha*actual_x[j]) * mat_coeffs.col(j).segment(offset,len);
+ else if(OP(*trans)==TR)
+ actual_y[j] += alpha * ( mat_coeffs.col(j).segment(offset,len).transpose() * vector(actual_x+start,len) ).value();
+ else
+ actual_y[j] += alpha * ( mat_coeffs.col(j).segment(offset,len).adjoint() * vector(actual_x+start,len) ).value();
+ }
+
+ if(actual_x!=x) delete[] actual_x;
+ if(actual_y!=y) delete[] copy_back(actual_y,y,actual_m,*incy);
+
+ return 0;
+}
+
+#if 0
+/** TBMV performs one of the matrix-vector operations
+ *
+ * x := A*x, or x := A'*x,
+ *
+ * where x is an n element vector and A is an n by n unit, or non-unit,
+ * upper or lower triangular band matrix, with ( k + 1 ) diagonals.
+ */
+int EIGEN_BLAS_FUNC(tbmv)(char *uplo, char *opa, char *diag, int *n, int *k, RealScalar *pa, int *lda, RealScalar *px, int *incx)
+{
+ Scalar* a = reinterpret_cast<Scalar*>(pa);
+ Scalar* x = reinterpret_cast<Scalar*>(px);
+ int coeff_rows = *k + 1;
+
+ int info = 0;
+ if(UPLO(*uplo)==INVALID) info = 1;
+ else if(OP(*opa)==INVALID) info = 2;
+ else if(DIAG(*diag)==INVALID) info = 3;
+ else if(*n<0) info = 4;
+ else if(*k<0) info = 5;
+ else if(*lda<coeff_rows) info = 7;
+ else if(*incx==0) info = 9;
+ if(info)
+ return xerbla_(SCALAR_SUFFIX_UP"TBMV ",&info,6);
+
+ if(*n==0)
+ return 0;
+
+ int actual_n = *n;
+
+ Scalar* actual_x = get_compact_vector(x,actual_n,*incx);
+
+ MatrixType mat_coeffs(a,coeff_rows,*n,*lda);
+
+ int ku = UPLO(*uplo)==UPPER ? *k : 0;
+ int kl = UPLO(*uplo)==LOWER ? *k : 0;
+
+ for(int j=0; j<*n; ++j)
+ {
+ int start = std::max(0,j - ku);
+ int end = std::min((*m)-1,j + kl);
+ int len = end - start + 1;
+ int offset = (ku) - j + start;
+
+ if(OP(*trans)==NOTR)
+ vector(actual_y+start,len) += (alpha*actual_x[j]) * mat_coeffs.col(j).segment(offset,len);
+ else if(OP(*trans)==TR)
+ actual_y[j] += alpha * ( mat_coeffs.col(j).segment(offset,len).transpose() * vector(actual_x+start,len) ).value();
+ else
+ actual_y[j] += alpha * ( mat_coeffs.col(j).segment(offset,len).adjoint() * vector(actual_x+start,len) ).value();
+ }
+
+ if(actual_x!=x) delete[] actual_x;
+ if(actual_y!=y) delete[] copy_back(actual_y,y,actual_m,*incy);
+
+ return 0;
+}
+#endif
+
+/** DTBSV solves one of the systems of equations
+ *
+ * A*x = b, or A'*x = b,
+ *
+ * where b and x are n element vectors and A is an n by n unit, or
+ * non-unit, upper or lower triangular band matrix, with ( k + 1 )
+ * diagonals.
+ *
+ * No test for singularity or near-singularity is included in this
+ * routine. Such tests must be performed before calling this routine.
+ */
+int EIGEN_BLAS_FUNC(tbsv)(char *uplo, char *op, char *diag, int *n, int *k, RealScalar *pa, int *lda, RealScalar *px, int *incx)
+{
+ typedef void (*functype)(int, int, const Scalar *, int, Scalar *);
+ static functype func[16];
+
+ static bool init = false;
+ if(!init)
+ {
+ for(int k=0; k<16; ++k)
+ func[k] = 0;
+
+ func[NOTR | (UP << 2) | (NUNIT << 3)] = (internal::band_solve_triangular_selector<int,Upper|0, Scalar,false,Scalar,ColMajor>::run);
+ func[TR | (UP << 2) | (NUNIT << 3)] = (internal::band_solve_triangular_selector<int,Lower|0, Scalar,false,Scalar,RowMajor>::run);
+ func[ADJ | (UP << 2) | (NUNIT << 3)] = (internal::band_solve_triangular_selector<int,Lower|0, Scalar,Conj, Scalar,RowMajor>::run);
+
+ func[NOTR | (LO << 2) | (NUNIT << 3)] = (internal::band_solve_triangular_selector<int,Lower|0, Scalar,false,Scalar,ColMajor>::run);
+ func[TR | (LO << 2) | (NUNIT << 3)] = (internal::band_solve_triangular_selector<int,Upper|0, Scalar,false,Scalar,RowMajor>::run);
+ func[ADJ | (LO << 2) | (NUNIT << 3)] = (internal::band_solve_triangular_selector<int,Upper|0, Scalar,Conj, Scalar,RowMajor>::run);
+
+ func[NOTR | (UP << 2) | (UNIT << 3)] = (internal::band_solve_triangular_selector<int,Upper|UnitDiag,Scalar,false,Scalar,ColMajor>::run);
+ func[TR | (UP << 2) | (UNIT << 3)] = (internal::band_solve_triangular_selector<int,Lower|UnitDiag,Scalar,false,Scalar,RowMajor>::run);
+ func[ADJ | (UP << 2) | (UNIT << 3)] = (internal::band_solve_triangular_selector<int,Lower|UnitDiag,Scalar,Conj, Scalar,RowMajor>::run);
+
+ func[NOTR | (LO << 2) | (UNIT << 3)] = (internal::band_solve_triangular_selector<int,Lower|UnitDiag,Scalar,false,Scalar,ColMajor>::run);
+ func[TR | (LO << 2) | (UNIT << 3)] = (internal::band_solve_triangular_selector<int,Upper|UnitDiag,Scalar,false,Scalar,RowMajor>::run);
+ func[ADJ | (LO << 2) | (UNIT << 3)] = (internal::band_solve_triangular_selector<int,Upper|UnitDiag,Scalar,Conj, Scalar,RowMajor>::run);
+
+ init = true;
+ }
+
+ Scalar* a = reinterpret_cast<Scalar*>(pa);
+ Scalar* x = reinterpret_cast<Scalar*>(px);
+ int coeff_rows = *k+1;
+
+ int info = 0;
+ if(UPLO(*uplo)==INVALID) info = 1;
+ else if(OP(*op)==INVALID) info = 2;
+ else if(DIAG(*diag)==INVALID) info = 3;
+ else if(*n<0) info = 4;
+ else if(*k<0) info = 5;
+ else if(*lda<coeff_rows) info = 7;
+ else if(*incx==0) info = 9;
+ if(info)
+ return xerbla_(SCALAR_SUFFIX_UP"TBSV ",&info,6);
+
+ if(*n==0 || (*k==0 && DIAG(*diag)==UNIT))
+ return 0;
+
+ int actual_n = *n;
+
+ Scalar* actual_x = get_compact_vector(x,actual_n,*incx);
+
+ int code = OP(*op) | (UPLO(*uplo) << 2) | (DIAG(*diag) << 3);
+ if(code>=16 || func[code]==0)
+ return 0;
+
+ func[code](*n, *k, a, *lda, actual_x);
+
+ if(actual_x!=x) delete[] copy_back(actual_x,x,actual_n,*incx);
+
+ return 0;
+}
+
+/** DTPMV performs one of the matrix-vector operations
+ *
+ * x := A*x, or x := A'*x,
+ *
+ * where x is an n element vector and A is an n by n unit, or non-unit,
+ * upper or lower triangular matrix, supplied in packed form.
+ */
+// int EIGEN_BLAS_FUNC(tpmv)(char *uplo, char *trans, char *diag, int *n, RealScalar *ap, RealScalar *x, int *incx)
+// {
+// return 1;
+// }
+
+/** DTPSV solves one of the systems of equations
+ *
+ * A*x = b, or A'*x = b,
+ *
+ * where b and x are n element vectors and A is an n by n unit, or
+ * non-unit, upper or lower triangular matrix, supplied in packed form.
+ *
+ * No test for singularity or near-singularity is included in this
+ * routine. Such tests must be performed before calling this routine.
+ */
+// int EIGEN_BLAS_FUNC(tpsv)(char *uplo, char *trans, char *diag, int *n, RealScalar *ap, RealScalar *x, int *incx)
+// {
+// return 1;
+// }
+
+/** DGER performs the rank 1 operation
+ *
+ * A := alpha*x*y' + A,
+ *
+ * where alpha is a scalar, x is an m element vector, y is an n element
+ * vector and A is an m by n matrix.
+ */
+int EIGEN_BLAS_FUNC(ger)(int *m, int *n, Scalar *palpha, Scalar *px, int *incx, Scalar *py, int *incy, Scalar *pa, int *lda)
+{
+ Scalar* x = reinterpret_cast<Scalar*>(px);
+ Scalar* y = reinterpret_cast<Scalar*>(py);
+ Scalar* a = reinterpret_cast<Scalar*>(pa);
+ Scalar alpha = *reinterpret_cast<Scalar*>(palpha);
+
+ int info = 0;
+ if(*m<0) info = 1;
+ else if(*n<0) info = 2;
+ else if(*incx==0) info = 5;
+ else if(*incy==0) info = 7;
+ else if(*lda<std::max(1,*m)) info = 9;
+ if(info)
+ return xerbla_(SCALAR_SUFFIX_UP"GER ",&info,6);
+
+ if(alpha==Scalar(0))
+ return 1;
+
+ Scalar* x_cpy = get_compact_vector(x,*m,*incx);
+ Scalar* y_cpy = get_compact_vector(y,*n,*incy);
+
+ // TODO perform direct calls to underlying implementation
+ matrix(a,*m,*n,*lda) += alpha * vector(x_cpy,*m) * vector(y_cpy,*n).adjoint();
+
+ if(x_cpy!=x) delete[] x_cpy;
+ if(y_cpy!=y) delete[] y_cpy;
+
+ return 1;
+}
+
+
diff --git a/blas/level2_real_impl.h b/blas/level2_real_impl.h
new file mode 100644
index 000000000..cd8332973
--- /dev/null
+++ b/blas/level2_real_impl.h
@@ -0,0 +1,210 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra.
+//
+// Copyright (C) 2009-2010 Gael Guennebaud <gael.guennebaud@inria.fr>
+//
+// This Source Code Form is subject to the terms of the Mozilla
+// Public License v. 2.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 "common.h"
+
+// y = alpha*A*x + beta*y
+int EIGEN_BLAS_FUNC(symv) (char *uplo, int *n, RealScalar *palpha, RealScalar *pa, int *lda, RealScalar *px, int *incx, RealScalar *pbeta, RealScalar *py, int *incy)
+{
+ Scalar* a = reinterpret_cast<Scalar*>(pa);
+ Scalar* x = reinterpret_cast<Scalar*>(px);
+ Scalar* y = reinterpret_cast<Scalar*>(py);
+ Scalar alpha = *reinterpret_cast<Scalar*>(palpha);
+ Scalar beta = *reinterpret_cast<Scalar*>(pbeta);
+
+ // check arguments
+ int info = 0;
+ if(UPLO(*uplo)==INVALID) info = 1;
+ else if(*n<0) info = 2;
+ else if(*lda<std::max(1,*n)) info = 5;
+ else if(*incx==0) info = 7;
+ else if(*incy==0) info = 10;
+ if(info)
+ return xerbla_(SCALAR_SUFFIX_UP"SYMV ",&info,6);
+
+ if(*n==0)
+ return 0;
+
+ Scalar* actual_x = get_compact_vector(x,*n,*incx);
+ Scalar* actual_y = get_compact_vector(y,*n,*incy);
+
+ if(beta!=Scalar(1))
+ {
+ if(beta==Scalar(0)) vector(actual_y, *n).setZero();
+ else vector(actual_y, *n) *= beta;
+ }
+
+ // TODO performs a direct call to the underlying implementation function
+ if(UPLO(*uplo)==UP) vector(actual_y,*n).noalias() += matrix(a,*n,*n,*lda).selfadjointView<Upper>() * (alpha * vector(actual_x,*n));
+ else if(UPLO(*uplo)==LO) vector(actual_y,*n).noalias() += matrix(a,*n,*n,*lda).selfadjointView<Lower>() * (alpha * vector(actual_x,*n));
+
+ if(actual_x!=x) delete[] actual_x;
+ if(actual_y!=y) delete[] copy_back(actual_y,y,*n,*incy);
+
+ return 1;
+}
+
+// C := alpha*x*x' + C
+int EIGEN_BLAS_FUNC(syr)(char *uplo, int *n, RealScalar *palpha, RealScalar *px, int *incx, RealScalar *pc, int *ldc)
+{
+
+// typedef void (*functype)(int, const Scalar *, int, Scalar *, int, Scalar);
+// static functype func[2];
+
+// static bool init = false;
+// if(!init)
+// {
+// for(int k=0; k<2; ++k)
+// func[k] = 0;
+//
+// func[UP] = (internal::selfadjoint_product<Scalar,ColMajor,ColMajor,false,UpperTriangular>::run);
+// func[LO] = (internal::selfadjoint_product<Scalar,ColMajor,ColMajor,false,LowerTriangular>::run);
+
+// init = true;
+// }
+
+ Scalar* x = reinterpret_cast<Scalar*>(px);
+ Scalar* c = reinterpret_cast<Scalar*>(pc);
+ Scalar alpha = *reinterpret_cast<Scalar*>(palpha);
+
+ int info = 0;
+ if(UPLO(*uplo)==INVALID) info = 1;
+ else if(*n<0) info = 2;
+ else if(*incx==0) info = 5;
+ else if(*ldc<std::max(1,*n)) info = 7;
+ if(info)
+ return xerbla_(SCALAR_SUFFIX_UP"SYR ",&info,6);
+
+ if(*n==0 || alpha==Scalar(0)) return 1;
+
+ // if the increment is not 1, let's copy it to a temporary vector to enable vectorization
+ Scalar* x_cpy = get_compact_vector(x,*n,*incx);
+
+ Matrix<Scalar,Dynamic,Dynamic> m2(matrix(c,*n,*n,*ldc));
+
+ // TODO check why this is not accurate enough for lapack tests
+// if(UPLO(*uplo)==LO) matrix(c,*n,*n,*ldc).selfadjointView<Lower>().rankUpdate(vector(x_cpy,*n), alpha);
+// else if(UPLO(*uplo)==UP) matrix(c,*n,*n,*ldc).selfadjointView<Upper>().rankUpdate(vector(x_cpy,*n), alpha);
+
+ if(UPLO(*uplo)==LO)
+ for(int j=0;j<*n;++j)
+ matrix(c,*n,*n,*ldc).col(j).tail(*n-j) += alpha * x_cpy[j] * vector(x_cpy+j,*n-j);
+ else
+ for(int j=0;j<*n;++j)
+ matrix(c,*n,*n,*ldc).col(j).head(j+1) += alpha * x_cpy[j] * vector(x_cpy,j+1);
+
+ if(x_cpy!=x) delete[] x_cpy;
+
+ return 1;
+}
+
+// C := alpha*x*y' + alpha*y*x' + C
+int EIGEN_BLAS_FUNC(syr2)(char *uplo, int *n, RealScalar *palpha, RealScalar *px, int *incx, RealScalar *py, int *incy, RealScalar *pc, int *ldc)
+{
+// typedef void (*functype)(int, const Scalar *, int, const Scalar *, int, Scalar *, int, Scalar);
+// static functype func[2];
+//
+// static bool init = false;
+// if(!init)
+// {
+// for(int k=0; k<2; ++k)
+// func[k] = 0;
+//
+// func[UP] = (internal::selfadjoint_product<Scalar,ColMajor,ColMajor,false,UpperTriangular>::run);
+// func[LO] = (internal::selfadjoint_product<Scalar,ColMajor,ColMajor,false,LowerTriangular>::run);
+//
+// init = true;
+// }
+
+ Scalar* x = reinterpret_cast<Scalar*>(px);
+ Scalar* y = reinterpret_cast<Scalar*>(py);
+ Scalar* c = reinterpret_cast<Scalar*>(pc);
+ Scalar alpha = *reinterpret_cast<Scalar*>(palpha);
+
+ int info = 0;
+ if(UPLO(*uplo)==INVALID) info = 1;
+ else if(*n<0) info = 2;
+ else if(*incx==0) info = 5;
+ else if(*incy==0) info = 7;
+ else if(*ldc<std::max(1,*n)) info = 9;
+ if(info)
+ return xerbla_(SCALAR_SUFFIX_UP"SYR2 ",&info,6);
+
+ if(alpha==Scalar(0))
+ return 1;
+
+ Scalar* x_cpy = get_compact_vector(x,*n,*incx);
+ Scalar* y_cpy = get_compact_vector(y,*n,*incy);
+
+ // TODO perform direct calls to underlying implementation
+ if(UPLO(*uplo)==LO) matrix(c,*n,*n,*ldc).selfadjointView<Lower>().rankUpdate(vector(x_cpy,*n), vector(y_cpy,*n), alpha);
+ else if(UPLO(*uplo)==UP) matrix(c,*n,*n,*ldc).selfadjointView<Upper>().rankUpdate(vector(x_cpy,*n), vector(y_cpy,*n), alpha);
+
+ if(x_cpy!=x) delete[] x_cpy;
+ if(y_cpy!=y) delete[] y_cpy;
+
+// int code = UPLO(*uplo);
+// if(code>=2 || func[code]==0)
+// return 0;
+
+// func[code](*n, a, *inca, b, *incb, c, *ldc, alpha);
+ return 1;
+}
+
+/** DSBMV performs the matrix-vector operation
+ *
+ * y := alpha*A*x + beta*y,
+ *
+ * where alpha and beta are scalars, x and y are n element vectors and
+ * A is an n by n symmetric band matrix, with k super-diagonals.
+ */
+// int EIGEN_BLAS_FUNC(sbmv)( char *uplo, int *n, int *k, RealScalar *alpha, RealScalar *a, int *lda,
+// RealScalar *x, int *incx, RealScalar *beta, RealScalar *y, int *incy)
+// {
+// return 1;
+// }
+
+
+/** DSPMV performs the matrix-vector operation
+ *
+ * y := alpha*A*x + beta*y,
+ *
+ * where alpha and beta are scalars, x and y are n element vectors and
+ * A is an n by n symmetric matrix, supplied in packed form.
+ *
+ */
+// int EIGEN_BLAS_FUNC(spmv)(char *uplo, int *n, RealScalar *alpha, RealScalar *ap, RealScalar *x, int *incx, RealScalar *beta, RealScalar *y, int *incy)
+// {
+// return 1;
+// }
+
+/** DSPR performs the symmetric rank 1 operation
+ *
+ * A := alpha*x*x' + A,
+ *
+ * where alpha is a real scalar, x is an n element vector and A is an
+ * n by n symmetric matrix, supplied in packed form.
+ */
+// int EIGEN_BLAS_FUNC(spr)(char *uplo, int *n, Scalar *alpha, Scalar *x, int *incx, Scalar *ap)
+// {
+// return 1;
+// }
+
+/** DSPR2 performs the symmetric rank 2 operation
+ *
+ * A := alpha*x*y' + alpha*y*x' + A,
+ *
+ * where alpha is a scalar, x and y are n element vectors and A is an
+ * n by n symmetric matrix, supplied in packed form.
+ */
+// int EIGEN_BLAS_FUNC(spr2)(char *uplo, int *n, RealScalar *alpha, RealScalar *x, int *incx, RealScalar *y, int *incy, RealScalar *ap)
+// {
+// return 1;
+// }
+
diff --git a/blas/level3_impl.h b/blas/level3_impl.h
new file mode 100644
index 000000000..2371f25c3
--- /dev/null
+++ b/blas/level3_impl.h
@@ -0,0 +1,632 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra.
+//
+// Copyright (C) 2009-2010 Gael Guennebaud <gael.guennebaud@inria.fr>
+//
+// This Source Code Form is subject to the terms of the Mozilla
+// Public License v. 2.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 "common.h"
+
+int EIGEN_BLAS_FUNC(gemm)(char *opa, char *opb, int *m, int *n, int *k, RealScalar *palpha, RealScalar *pa, int *lda, RealScalar *pb, int *ldb, RealScalar *pbeta, RealScalar *pc, int *ldc)
+{
+// std::cerr << "in gemm " << *opa << " " << *opb << " " << *m << " " << *n << " " << *k << " " << *lda << " " << *ldb << " " << *ldc << " " << *palpha << " " << *pbeta << "\n";
+ typedef void (*functype)(DenseIndex, DenseIndex, DenseIndex, const Scalar *, DenseIndex, const Scalar *, DenseIndex, Scalar *, DenseIndex, Scalar, internal::level3_blocking<Scalar,Scalar>&, Eigen::internal::GemmParallelInfo<DenseIndex>*);
+ static functype func[12];
+
+ static bool init = false;
+ if(!init)
+ {
+ for(int k=0; k<12; ++k)
+ func[k] = 0;
+ func[NOTR | (NOTR << 2)] = (internal::general_matrix_matrix_product<DenseIndex,Scalar,ColMajor,false,Scalar,ColMajor,false,ColMajor>::run);
+ func[TR | (NOTR << 2)] = (internal::general_matrix_matrix_product<DenseIndex,Scalar,RowMajor,false,Scalar,ColMajor,false,ColMajor>::run);
+ func[ADJ | (NOTR << 2)] = (internal::general_matrix_matrix_product<DenseIndex,Scalar,RowMajor,Conj, Scalar,ColMajor,false,ColMajor>::run);
+ func[NOTR | (TR << 2)] = (internal::general_matrix_matrix_product<DenseIndex,Scalar,ColMajor,false,Scalar,RowMajor,false,ColMajor>::run);
+ func[TR | (TR << 2)] = (internal::general_matrix_matrix_product<DenseIndex,Scalar,RowMajor,false,Scalar,RowMajor,false,ColMajor>::run);
+ func[ADJ | (TR << 2)] = (internal::general_matrix_matrix_product<DenseIndex,Scalar,RowMajor,Conj, Scalar,RowMajor,false,ColMajor>::run);
+ func[NOTR | (ADJ << 2)] = (internal::general_matrix_matrix_product<DenseIndex,Scalar,ColMajor,false,Scalar,RowMajor,Conj, ColMajor>::run);
+ func[TR | (ADJ << 2)] = (internal::general_matrix_matrix_product<DenseIndex,Scalar,RowMajor,false,Scalar,RowMajor,Conj, ColMajor>::run);
+ func[ADJ | (ADJ << 2)] = (internal::general_matrix_matrix_product<DenseIndex,Scalar,RowMajor,Conj, Scalar,RowMajor,Conj, ColMajor>::run);
+ init = true;
+ }
+
+ Scalar* a = reinterpret_cast<Scalar*>(pa);
+ Scalar* b = reinterpret_cast<Scalar*>(pb);
+ Scalar* c = reinterpret_cast<Scalar*>(pc);
+ Scalar alpha = *reinterpret_cast<Scalar*>(palpha);
+ Scalar beta = *reinterpret_cast<Scalar*>(pbeta);
+
+ int info = 0;
+ if(OP(*opa)==INVALID) info = 1;
+ else if(OP(*opb)==INVALID) info = 2;
+ else if(*m<0) info = 3;
+ else if(*n<0) info = 4;
+ else if(*k<0) info = 5;
+ else if(*lda<std::max(1,(OP(*opa)==NOTR)?*m:*k)) info = 8;
+ else if(*ldb<std::max(1,(OP(*opb)==NOTR)?*k:*n)) info = 10;
+ else if(*ldc<std::max(1,*m)) info = 13;
+ if(info)
+ return xerbla_(SCALAR_SUFFIX_UP"GEMM ",&info,6);
+
+ if(beta!=Scalar(1))
+ {
+ if(beta==Scalar(0)) matrix(c, *m, *n, *ldc).setZero();
+ else matrix(c, *m, *n, *ldc) *= beta;
+ }
+
+ internal::gemm_blocking_space<ColMajor,Scalar,Scalar,Dynamic,Dynamic,Dynamic> blocking(*m,*n,*k);
+
+ int code = OP(*opa) | (OP(*opb) << 2);
+ func[code](*m, *n, *k, a, *lda, b, *ldb, c, *ldc, alpha, blocking, 0);
+ return 0;
+}
+
+int EIGEN_BLAS_FUNC(trsm)(char *side, char *uplo, char *opa, char *diag, int *m, int *n, RealScalar *palpha, RealScalar *pa, int *lda, RealScalar *pb, int *ldb)
+{
+// std::cerr << "in trsm " << *side << " " << *uplo << " " << *opa << " " << *diag << " " << *m << "," << *n << " " << *palpha << " " << *lda << " " << *ldb<< "\n";
+ typedef void (*functype)(DenseIndex, DenseIndex, const Scalar *, DenseIndex, Scalar *, DenseIndex, internal::level3_blocking<Scalar,Scalar>&);
+ static functype func[32];
+
+ static bool init = false;
+ if(!init)
+ {
+ for(int k=0; k<32; ++k)
+ func[k] = 0;
+
+ func[NOTR | (LEFT << 2) | (UP << 3) | (NUNIT << 4)] = (internal::triangular_solve_matrix<Scalar,DenseIndex,OnTheLeft, Upper|0, false,ColMajor,ColMajor>::run);
+ func[TR | (LEFT << 2) | (UP << 3) | (NUNIT << 4)] = (internal::triangular_solve_matrix<Scalar,DenseIndex,OnTheLeft, Lower|0, false,RowMajor,ColMajor>::run);
+ func[ADJ | (LEFT << 2) | (UP << 3) | (NUNIT << 4)] = (internal::triangular_solve_matrix<Scalar,DenseIndex,OnTheLeft, Lower|0, Conj, RowMajor,ColMajor>::run);
+
+ func[NOTR | (RIGHT << 2) | (UP << 3) | (NUNIT << 4)] = (internal::triangular_solve_matrix<Scalar,DenseIndex,OnTheRight,Upper|0, false,ColMajor,ColMajor>::run);
+ func[TR | (RIGHT << 2) | (UP << 3) | (NUNIT << 4)] = (internal::triangular_solve_matrix<Scalar,DenseIndex,OnTheRight,Lower|0, false,RowMajor,ColMajor>::run);
+ func[ADJ | (RIGHT << 2) | (UP << 3) | (NUNIT << 4)] = (internal::triangular_solve_matrix<Scalar,DenseIndex,OnTheRight,Lower|0, Conj, RowMajor,ColMajor>::run);
+
+ func[NOTR | (LEFT << 2) | (LO << 3) | (NUNIT << 4)] = (internal::triangular_solve_matrix<Scalar,DenseIndex,OnTheLeft, Lower|0, false,ColMajor,ColMajor>::run);
+ func[TR | (LEFT << 2) | (LO << 3) | (NUNIT << 4)] = (internal::triangular_solve_matrix<Scalar,DenseIndex,OnTheLeft, Upper|0, false,RowMajor,ColMajor>::run);
+ func[ADJ | (LEFT << 2) | (LO << 3) | (NUNIT << 4)] = (internal::triangular_solve_matrix<Scalar,DenseIndex,OnTheLeft, Upper|0, Conj, RowMajor,ColMajor>::run);
+
+ func[NOTR | (RIGHT << 2) | (LO << 3) | (NUNIT << 4)] = (internal::triangular_solve_matrix<Scalar,DenseIndex,OnTheRight,Lower|0, false,ColMajor,ColMajor>::run);
+ func[TR | (RIGHT << 2) | (LO << 3) | (NUNIT << 4)] = (internal::triangular_solve_matrix<Scalar,DenseIndex,OnTheRight,Upper|0, false,RowMajor,ColMajor>::run);
+ func[ADJ | (RIGHT << 2) | (LO << 3) | (NUNIT << 4)] = (internal::triangular_solve_matrix<Scalar,DenseIndex,OnTheRight,Upper|0, Conj, RowMajor,ColMajor>::run);
+
+
+ func[NOTR | (LEFT << 2) | (UP << 3) | (UNIT << 4)] = (internal::triangular_solve_matrix<Scalar,DenseIndex,OnTheLeft, Upper|UnitDiag,false,ColMajor,ColMajor>::run);
+ func[TR | (LEFT << 2) | (UP << 3) | (UNIT << 4)] = (internal::triangular_solve_matrix<Scalar,DenseIndex,OnTheLeft, Lower|UnitDiag,false,RowMajor,ColMajor>::run);
+ func[ADJ | (LEFT << 2) | (UP << 3) | (UNIT << 4)] = (internal::triangular_solve_matrix<Scalar,DenseIndex,OnTheLeft, Lower|UnitDiag,Conj, RowMajor,ColMajor>::run);
+
+ func[NOTR | (RIGHT << 2) | (UP << 3) | (UNIT << 4)] = (internal::triangular_solve_matrix<Scalar,DenseIndex,OnTheRight,Upper|UnitDiag,false,ColMajor,ColMajor>::run);
+ func[TR | (RIGHT << 2) | (UP << 3) | (UNIT << 4)] = (internal::triangular_solve_matrix<Scalar,DenseIndex,OnTheRight,Lower|UnitDiag,false,RowMajor,ColMajor>::run);
+ func[ADJ | (RIGHT << 2) | (UP << 3) | (UNIT << 4)] = (internal::triangular_solve_matrix<Scalar,DenseIndex,OnTheRight,Lower|UnitDiag,Conj, RowMajor,ColMajor>::run);
+
+ func[NOTR | (LEFT << 2) | (LO << 3) | (UNIT << 4)] = (internal::triangular_solve_matrix<Scalar,DenseIndex,OnTheLeft, Lower|UnitDiag,false,ColMajor,ColMajor>::run);
+ func[TR | (LEFT << 2) | (LO << 3) | (UNIT << 4)] = (internal::triangular_solve_matrix<Scalar,DenseIndex,OnTheLeft, Upper|UnitDiag,false,RowMajor,ColMajor>::run);
+ func[ADJ | (LEFT << 2) | (LO << 3) | (UNIT << 4)] = (internal::triangular_solve_matrix<Scalar,DenseIndex,OnTheLeft, Upper|UnitDiag,Conj, RowMajor,ColMajor>::run);
+
+ func[NOTR | (RIGHT << 2) | (LO << 3) | (UNIT << 4)] = (internal::triangular_solve_matrix<Scalar,DenseIndex,OnTheRight,Lower|UnitDiag,false,ColMajor,ColMajor>::run);
+ func[TR | (RIGHT << 2) | (LO << 3) | (UNIT << 4)] = (internal::triangular_solve_matrix<Scalar,DenseIndex,OnTheRight,Upper|UnitDiag,false,RowMajor,ColMajor>::run);
+ func[ADJ | (RIGHT << 2) | (LO << 3) | (UNIT << 4)] = (internal::triangular_solve_matrix<Scalar,DenseIndex,OnTheRight,Upper|UnitDiag,Conj, RowMajor,ColMajor>::run);
+
+ init = true;
+ }
+
+ Scalar* a = reinterpret_cast<Scalar*>(pa);
+ Scalar* b = reinterpret_cast<Scalar*>(pb);
+ Scalar alpha = *reinterpret_cast<Scalar*>(palpha);
+
+ int info = 0;
+ if(SIDE(*side)==INVALID) info = 1;
+ else if(UPLO(*uplo)==INVALID) info = 2;
+ else if(OP(*opa)==INVALID) info = 3;
+ else if(DIAG(*diag)==INVALID) info = 4;
+ else if(*m<0) info = 5;
+ else if(*n<0) info = 6;
+ else if(*lda<std::max(1,(SIDE(*side)==LEFT)?*m:*n)) info = 9;
+ else if(*ldb<std::max(1,*m)) info = 11;
+ if(info)
+ return xerbla_(SCALAR_SUFFIX_UP"TRSM ",&info,6);
+
+ int code = OP(*opa) | (SIDE(*side) << 2) | (UPLO(*uplo) << 3) | (DIAG(*diag) << 4);
+
+ if(SIDE(*side)==LEFT)
+ {
+ internal::gemm_blocking_space<ColMajor,Scalar,Scalar,Dynamic,Dynamic,Dynamic,4> blocking(*m,*n,*m);
+ func[code](*m, *n, a, *lda, b, *ldb, blocking);
+ }
+ else
+ {
+ internal::gemm_blocking_space<ColMajor,Scalar,Scalar,Dynamic,Dynamic,Dynamic,4> blocking(*m,*n,*n);
+ func[code](*n, *m, a, *lda, b, *ldb, blocking);
+ }
+
+ if(alpha!=Scalar(1))
+ matrix(b,*m,*n,*ldb) *= alpha;
+
+ return 0;
+}
+
+
+// b = alpha*op(a)*b for side = 'L'or'l'
+// b = alpha*b*op(a) for side = 'R'or'r'
+int EIGEN_BLAS_FUNC(trmm)(char *side, char *uplo, char *opa, char *diag, int *m, int *n, RealScalar *palpha, RealScalar *pa, int *lda, RealScalar *pb, int *ldb)
+{
+// std::cerr << "in trmm " << *side << " " << *uplo << " " << *opa << " " << *diag << " " << *m << " " << *n << " " << *lda << " " << *ldb << " " << *palpha << "\n";
+ typedef void (*functype)(DenseIndex, DenseIndex, DenseIndex, const Scalar *, DenseIndex, const Scalar *, DenseIndex, Scalar *, DenseIndex, Scalar, internal::level3_blocking<Scalar,Scalar>&);
+ static functype func[32];
+ static bool init = false;
+ if(!init)
+ {
+ for(int k=0; k<32; ++k)
+ func[k] = 0;
+
+ func[NOTR | (LEFT << 2) | (UP << 3) | (NUNIT << 4)] = (internal::product_triangular_matrix_matrix<Scalar,DenseIndex,Upper|0, true, ColMajor,false,ColMajor,false,ColMajor>::run);
+ func[TR | (LEFT << 2) | (UP << 3) | (NUNIT << 4)] = (internal::product_triangular_matrix_matrix<Scalar,DenseIndex,Lower|0, true, RowMajor,false,ColMajor,false,ColMajor>::run);
+ func[ADJ | (LEFT << 2) | (UP << 3) | (NUNIT << 4)] = (internal::product_triangular_matrix_matrix<Scalar,DenseIndex,Lower|0, true, RowMajor,Conj, ColMajor,false,ColMajor>::run);
+
+ func[NOTR | (RIGHT << 2) | (UP << 3) | (NUNIT << 4)] = (internal::product_triangular_matrix_matrix<Scalar,DenseIndex,Upper|0, false,ColMajor,false,ColMajor,false,ColMajor>::run);
+ func[TR | (RIGHT << 2) | (UP << 3) | (NUNIT << 4)] = (internal::product_triangular_matrix_matrix<Scalar,DenseIndex,Lower|0, false,ColMajor,false,RowMajor,false,ColMajor>::run);
+ func[ADJ | (RIGHT << 2) | (UP << 3) | (NUNIT << 4)] = (internal::product_triangular_matrix_matrix<Scalar,DenseIndex,Lower|0, false,ColMajor,false,RowMajor,Conj, ColMajor>::run);
+
+ func[NOTR | (LEFT << 2) | (LO << 3) | (NUNIT << 4)] = (internal::product_triangular_matrix_matrix<Scalar,DenseIndex,Lower|0, true, ColMajor,false,ColMajor,false,ColMajor>::run);
+ func[TR | (LEFT << 2) | (LO << 3) | (NUNIT << 4)] = (internal::product_triangular_matrix_matrix<Scalar,DenseIndex,Upper|0, true, RowMajor,false,ColMajor,false,ColMajor>::run);
+ func[ADJ | (LEFT << 2) | (LO << 3) | (NUNIT << 4)] = (internal::product_triangular_matrix_matrix<Scalar,DenseIndex,Upper|0, true, RowMajor,Conj, ColMajor,false,ColMajor>::run);
+
+ func[NOTR | (RIGHT << 2) | (LO << 3) | (NUNIT << 4)] = (internal::product_triangular_matrix_matrix<Scalar,DenseIndex,Lower|0, false,ColMajor,false,ColMajor,false,ColMajor>::run);
+ func[TR | (RIGHT << 2) | (LO << 3) | (NUNIT << 4)] = (internal::product_triangular_matrix_matrix<Scalar,DenseIndex,Upper|0, false,ColMajor,false,RowMajor,false,ColMajor>::run);
+ func[ADJ | (RIGHT << 2) | (LO << 3) | (NUNIT << 4)] = (internal::product_triangular_matrix_matrix<Scalar,DenseIndex,Upper|0, false,ColMajor,false,RowMajor,Conj, ColMajor>::run);
+
+ func[NOTR | (LEFT << 2) | (UP << 3) | (UNIT << 4)] = (internal::product_triangular_matrix_matrix<Scalar,DenseIndex,Upper|UnitDiag,true, ColMajor,false,ColMajor,false,ColMajor>::run);
+ func[TR | (LEFT << 2) | (UP << 3) | (UNIT << 4)] = (internal::product_triangular_matrix_matrix<Scalar,DenseIndex,Lower|UnitDiag,true, RowMajor,false,ColMajor,false,ColMajor>::run);
+ func[ADJ | (LEFT << 2) | (UP << 3) | (UNIT << 4)] = (internal::product_triangular_matrix_matrix<Scalar,DenseIndex,Lower|UnitDiag,true, RowMajor,Conj, ColMajor,false,ColMajor>::run);
+
+ func[NOTR | (RIGHT << 2) | (UP << 3) | (UNIT << 4)] = (internal::product_triangular_matrix_matrix<Scalar,DenseIndex,Upper|UnitDiag,false,ColMajor,false,ColMajor,false,ColMajor>::run);
+ func[TR | (RIGHT << 2) | (UP << 3) | (UNIT << 4)] = (internal::product_triangular_matrix_matrix<Scalar,DenseIndex,Lower|UnitDiag,false,ColMajor,false,RowMajor,false,ColMajor>::run);
+ func[ADJ | (RIGHT << 2) | (UP << 3) | (UNIT << 4)] = (internal::product_triangular_matrix_matrix<Scalar,DenseIndex,Lower|UnitDiag,false,ColMajor,false,RowMajor,Conj, ColMajor>::run);
+
+ func[NOTR | (LEFT << 2) | (LO << 3) | (UNIT << 4)] = (internal::product_triangular_matrix_matrix<Scalar,DenseIndex,Lower|UnitDiag,true, ColMajor,false,ColMajor,false,ColMajor>::run);
+ func[TR | (LEFT << 2) | (LO << 3) | (UNIT << 4)] = (internal::product_triangular_matrix_matrix<Scalar,DenseIndex,Upper|UnitDiag,true, RowMajor,false,ColMajor,false,ColMajor>::run);
+ func[ADJ | (LEFT << 2) | (LO << 3) | (UNIT << 4)] = (internal::product_triangular_matrix_matrix<Scalar,DenseIndex,Upper|UnitDiag,true, RowMajor,Conj, ColMajor,false,ColMajor>::run);
+
+ func[NOTR | (RIGHT << 2) | (LO << 3) | (UNIT << 4)] = (internal::product_triangular_matrix_matrix<Scalar,DenseIndex,Lower|UnitDiag,false,ColMajor,false,ColMajor,false,ColMajor>::run);
+ func[TR | (RIGHT << 2) | (LO << 3) | (UNIT << 4)] = (internal::product_triangular_matrix_matrix<Scalar,DenseIndex,Upper|UnitDiag,false,ColMajor,false,RowMajor,false,ColMajor>::run);
+ func[ADJ | (RIGHT << 2) | (LO << 3) | (UNIT << 4)] = (internal::product_triangular_matrix_matrix<Scalar,DenseIndex,Upper|UnitDiag,false,ColMajor,false,RowMajor,Conj, ColMajor>::run);
+
+ init = true;
+ }
+
+ Scalar* a = reinterpret_cast<Scalar*>(pa);
+ Scalar* b = reinterpret_cast<Scalar*>(pb);
+ Scalar alpha = *reinterpret_cast<Scalar*>(palpha);
+
+ int info = 0;
+ if(SIDE(*side)==INVALID) info = 1;
+ else if(UPLO(*uplo)==INVALID) info = 2;
+ else if(OP(*opa)==INVALID) info = 3;
+ else if(DIAG(*diag)==INVALID) info = 4;
+ else if(*m<0) info = 5;
+ else if(*n<0) info = 6;
+ else if(*lda<std::max(1,(SIDE(*side)==LEFT)?*m:*n)) info = 9;
+ else if(*ldb<std::max(1,*m)) info = 11;
+ if(info)
+ return xerbla_(SCALAR_SUFFIX_UP"TRMM ",&info,6);
+
+ int code = OP(*opa) | (SIDE(*side) << 2) | (UPLO(*uplo) << 3) | (DIAG(*diag) << 4);
+
+ if(*m==0 || *n==0)
+ return 1;
+
+ // FIXME find a way to avoid this copy
+ Matrix<Scalar,Dynamic,Dynamic,ColMajor> tmp = matrix(b,*m,*n,*ldb);
+ matrix(b,*m,*n,*ldb).setZero();
+
+ if(SIDE(*side)==LEFT)
+ {
+ internal::gemm_blocking_space<ColMajor,Scalar,Scalar,Dynamic,Dynamic,Dynamic,4> blocking(*m,*n,*m);
+ func[code](*m, *n, *m, a, *lda, tmp.data(), tmp.outerStride(), b, *ldb, alpha, blocking);
+ }
+ else
+ {
+ internal::gemm_blocking_space<ColMajor,Scalar,Scalar,Dynamic,Dynamic,Dynamic,4> blocking(*m,*n,*n);
+ func[code](*m, *n, *n, tmp.data(), tmp.outerStride(), a, *lda, b, *ldb, alpha, blocking);
+ }
+ return 1;
+}
+
+// c = alpha*a*b + beta*c for side = 'L'or'l'
+// c = alpha*b*a + beta*c for side = 'R'or'r
+int EIGEN_BLAS_FUNC(symm)(char *side, char *uplo, int *m, int *n, RealScalar *palpha, RealScalar *pa, int *lda, RealScalar *pb, int *ldb, RealScalar *pbeta, RealScalar *pc, int *ldc)
+{
+// std::cerr << "in symm " << *side << " " << *uplo << " " << *m << "x" << *n << " lda:" << *lda << " ldb:" << *ldb << " ldc:" << *ldc << " alpha:" << *palpha << " beta:" << *pbeta << "\n";
+ Scalar* a = reinterpret_cast<Scalar*>(pa);
+ Scalar* b = reinterpret_cast<Scalar*>(pb);
+ Scalar* c = reinterpret_cast<Scalar*>(pc);
+ Scalar alpha = *reinterpret_cast<Scalar*>(palpha);
+ Scalar beta = *reinterpret_cast<Scalar*>(pbeta);
+
+ int info = 0;
+ if(SIDE(*side)==INVALID) info = 1;
+ else if(UPLO(*uplo)==INVALID) info = 2;
+ else if(*m<0) info = 3;
+ else if(*n<0) info = 4;
+ else if(*lda<std::max(1,(SIDE(*side)==LEFT)?*m:*n)) info = 7;
+ else if(*ldb<std::max(1,*m)) info = 9;
+ else if(*ldc<std::max(1,*m)) info = 12;
+ if(info)
+ return xerbla_(SCALAR_SUFFIX_UP"SYMM ",&info,6);
+
+ if(beta!=Scalar(1))
+ {
+ if(beta==Scalar(0)) matrix(c, *m, *n, *ldc).setZero();
+ else matrix(c, *m, *n, *ldc) *= beta;
+ }
+
+ if(*m==0 || *n==0)
+ {
+ return 1;
+ }
+
+ #if ISCOMPLEX
+ // FIXME add support for symmetric complex matrix
+ int size = (SIDE(*side)==LEFT) ? (*m) : (*n);
+ Matrix<Scalar,Dynamic,Dynamic,ColMajor> matA(size,size);
+ if(UPLO(*uplo)==UP)
+ {
+ matA.triangularView<Upper>() = matrix(a,size,size,*lda);
+ matA.triangularView<Lower>() = matrix(a,size,size,*lda).transpose();
+ }
+ else if(UPLO(*uplo)==LO)
+ {
+ matA.triangularView<Lower>() = matrix(a,size,size,*lda);
+ matA.triangularView<Upper>() = matrix(a,size,size,*lda).transpose();
+ }
+ if(SIDE(*side)==LEFT)
+ matrix(c, *m, *n, *ldc) += alpha * matA * matrix(b, *m, *n, *ldb);
+ else if(SIDE(*side)==RIGHT)
+ matrix(c, *m, *n, *ldc) += alpha * matrix(b, *m, *n, *ldb) * matA;
+ #else
+ if(SIDE(*side)==LEFT)
+ if(UPLO(*uplo)==UP) internal::product_selfadjoint_matrix<Scalar, DenseIndex, RowMajor,true,false, ColMajor,false,false, ColMajor>::run(*m, *n, a, *lda, b, *ldb, c, *ldc, alpha);
+ else if(UPLO(*uplo)==LO) internal::product_selfadjoint_matrix<Scalar, DenseIndex, ColMajor,true,false, ColMajor,false,false, ColMajor>::run(*m, *n, a, *lda, b, *ldb, c, *ldc, alpha);
+ else return 0;
+ else if(SIDE(*side)==RIGHT)
+ if(UPLO(*uplo)==UP) internal::product_selfadjoint_matrix<Scalar, DenseIndex, ColMajor,false,false, RowMajor,true,false, ColMajor>::run(*m, *n, b, *ldb, a, *lda, c, *ldc, alpha);
+ else if(UPLO(*uplo)==LO) internal::product_selfadjoint_matrix<Scalar, DenseIndex, ColMajor,false,false, ColMajor,true,false, ColMajor>::run(*m, *n, b, *ldb, a, *lda, c, *ldc, alpha);
+ else return 0;
+ else
+ return 0;
+ #endif
+
+ return 0;
+}
+
+// c = alpha*a*a' + beta*c for op = 'N'or'n'
+// c = alpha*a'*a + beta*c for op = 'T'or't','C'or'c'
+int EIGEN_BLAS_FUNC(syrk)(char *uplo, char *op, int *n, int *k, RealScalar *palpha, RealScalar *pa, int *lda, RealScalar *pbeta, RealScalar *pc, int *ldc)
+{
+// std::cerr << "in syrk " << *uplo << " " << *op << " " << *n << " " << *k << " " << *palpha << " " << *lda << " " << *pbeta << " " << *ldc << "\n";
+ typedef void (*functype)(DenseIndex, DenseIndex, const Scalar *, DenseIndex, const Scalar *, DenseIndex, Scalar *, DenseIndex, Scalar);
+ static functype func[8];
+
+ static bool init = false;
+ if(!init)
+ {
+ for(int k=0; k<8; ++k)
+ func[k] = 0;
+
+ func[NOTR | (UP << 2)] = (internal::general_matrix_matrix_triangular_product<DenseIndex,Scalar,ColMajor,false,Scalar,RowMajor,ColMajor,Conj, Upper>::run);
+ func[TR | (UP << 2)] = (internal::general_matrix_matrix_triangular_product<DenseIndex,Scalar,RowMajor,false,Scalar,ColMajor,ColMajor,Conj, Upper>::run);
+ func[ADJ | (UP << 2)] = (internal::general_matrix_matrix_triangular_product<DenseIndex,Scalar,RowMajor,Conj, Scalar,ColMajor,ColMajor,false,Upper>::run);
+
+ func[NOTR | (LO << 2)] = (internal::general_matrix_matrix_triangular_product<DenseIndex,Scalar,ColMajor,false,Scalar,RowMajor,ColMajor,Conj, Lower>::run);
+ func[TR | (LO << 2)] = (internal::general_matrix_matrix_triangular_product<DenseIndex,Scalar,RowMajor,false,Scalar,ColMajor,ColMajor,Conj, Lower>::run);
+ func[ADJ | (LO << 2)] = (internal::general_matrix_matrix_triangular_product<DenseIndex,Scalar,RowMajor,Conj, Scalar,ColMajor,ColMajor,false,Lower>::run);
+
+ init = true;
+ }
+
+ Scalar* a = reinterpret_cast<Scalar*>(pa);
+ Scalar* c = reinterpret_cast<Scalar*>(pc);
+ Scalar alpha = *reinterpret_cast<Scalar*>(palpha);
+ Scalar beta = *reinterpret_cast<Scalar*>(pbeta);
+
+ int info = 0;
+ if(UPLO(*uplo)==INVALID) info = 1;
+ else if(OP(*op)==INVALID) info = 2;
+ else if(*n<0) info = 3;
+ else if(*k<0) info = 4;
+ else if(*lda<std::max(1,(OP(*op)==NOTR)?*n:*k)) info = 7;
+ else if(*ldc<std::max(1,*n)) info = 10;
+ if(info)
+ return xerbla_(SCALAR_SUFFIX_UP"SYRK ",&info,6);
+
+ if(beta!=Scalar(1))
+ {
+ if(UPLO(*uplo)==UP)
+ if(beta==Scalar(0)) matrix(c, *n, *n, *ldc).triangularView<Upper>().setZero();
+ else matrix(c, *n, *n, *ldc).triangularView<Upper>() *= beta;
+ else
+ if(beta==Scalar(0)) matrix(c, *n, *n, *ldc).triangularView<Lower>().setZero();
+ else matrix(c, *n, *n, *ldc).triangularView<Lower>() *= beta;
+ }
+
+ #if ISCOMPLEX
+ // FIXME add support for symmetric complex matrix
+ if(UPLO(*uplo)==UP)
+ {
+ if(OP(*op)==NOTR)
+ matrix(c, *n, *n, *ldc).triangularView<Upper>() += alpha * matrix(a,*n,*k,*lda) * matrix(a,*n,*k,*lda).transpose();
+ else
+ matrix(c, *n, *n, *ldc).triangularView<Upper>() += alpha * matrix(a,*k,*n,*lda).transpose() * matrix(a,*k,*n,*lda);
+ }
+ else
+ {
+ if(OP(*op)==NOTR)
+ matrix(c, *n, *n, *ldc).triangularView<Lower>() += alpha * matrix(a,*n,*k,*lda) * matrix(a,*n,*k,*lda).transpose();
+ else
+ matrix(c, *n, *n, *ldc).triangularView<Lower>() += alpha * matrix(a,*k,*n,*lda).transpose() * matrix(a,*k,*n,*lda);
+ }
+ #else
+ int code = OP(*op) | (UPLO(*uplo) << 2);
+ func[code](*n, *k, a, *lda, a, *lda, c, *ldc, alpha);
+ #endif
+
+ return 0;
+}
+
+// c = alpha*a*b' + alpha*b*a' + beta*c for op = 'N'or'n'
+// c = alpha*a'*b + alpha*b'*a + beta*c for op = 'T'or't'
+int EIGEN_BLAS_FUNC(syr2k)(char *uplo, char *op, int *n, int *k, RealScalar *palpha, RealScalar *pa, int *lda, RealScalar *pb, int *ldb, RealScalar *pbeta, RealScalar *pc, int *ldc)
+{
+ Scalar* a = reinterpret_cast<Scalar*>(pa);
+ Scalar* b = reinterpret_cast<Scalar*>(pb);
+ Scalar* c = reinterpret_cast<Scalar*>(pc);
+ Scalar alpha = *reinterpret_cast<Scalar*>(palpha);
+ Scalar beta = *reinterpret_cast<Scalar*>(pbeta);
+
+ int info = 0;
+ if(UPLO(*uplo)==INVALID) info = 1;
+ else if(OP(*op)==INVALID) info = 2;
+ else if(*n<0) info = 3;
+ else if(*k<0) info = 4;
+ else if(*lda<std::max(1,(OP(*op)==NOTR)?*n:*k)) info = 7;
+ else if(*ldb<std::max(1,(OP(*op)==NOTR)?*n:*k)) info = 9;
+ else if(*ldc<std::max(1,*n)) info = 12;
+ if(info)
+ return xerbla_(SCALAR_SUFFIX_UP"SYR2K",&info,6);
+
+ if(beta!=Scalar(1))
+ {
+ if(UPLO(*uplo)==UP)
+ if(beta==Scalar(0)) matrix(c, *n, *n, *ldc).triangularView<Upper>().setZero();
+ else matrix(c, *n, *n, *ldc).triangularView<Upper>() *= beta;
+ else
+ if(beta==Scalar(0)) matrix(c, *n, *n, *ldc).triangularView<Lower>().setZero();
+ else matrix(c, *n, *n, *ldc).triangularView<Lower>() *= beta;
+ }
+
+ if(*k==0)
+ return 1;
+
+ if(OP(*op)==NOTR)
+ {
+ if(UPLO(*uplo)==UP)
+ {
+ matrix(c, *n, *n, *ldc).triangularView<Upper>()
+ += alpha *matrix(a, *n, *k, *lda)*matrix(b, *n, *k, *ldb).transpose()
+ + alpha*matrix(b, *n, *k, *ldb)*matrix(a, *n, *k, *lda).transpose();
+ }
+ else if(UPLO(*uplo)==LO)
+ matrix(c, *n, *n, *ldc).triangularView<Lower>()
+ += alpha*matrix(a, *n, *k, *lda)*matrix(b, *n, *k, *ldb).transpose()
+ + alpha*matrix(b, *n, *k, *ldb)*matrix(a, *n, *k, *lda).transpose();
+ }
+ else if(OP(*op)==TR || OP(*op)==ADJ)
+ {
+ if(UPLO(*uplo)==UP)
+ matrix(c, *n, *n, *ldc).triangularView<Upper>()
+ += alpha*matrix(a, *k, *n, *lda).transpose()*matrix(b, *k, *n, *ldb)
+ + alpha*matrix(b, *k, *n, *ldb).transpose()*matrix(a, *k, *n, *lda);
+ else if(UPLO(*uplo)==LO)
+ matrix(c, *n, *n, *ldc).triangularView<Lower>()
+ += alpha*matrix(a, *k, *n, *lda).transpose()*matrix(b, *k, *n, *ldb)
+ + alpha*matrix(b, *k, *n, *ldb).transpose()*matrix(a, *k, *n, *lda);
+ }
+
+ return 0;
+}
+
+
+#if ISCOMPLEX
+
+// c = alpha*a*b + beta*c for side = 'L'or'l'
+// c = alpha*b*a + beta*c for side = 'R'or'r
+int EIGEN_BLAS_FUNC(hemm)(char *side, char *uplo, int *m, int *n, RealScalar *palpha, RealScalar *pa, int *lda, RealScalar *pb, int *ldb, RealScalar *pbeta, RealScalar *pc, int *ldc)
+{
+ Scalar* a = reinterpret_cast<Scalar*>(pa);
+ Scalar* b = reinterpret_cast<Scalar*>(pb);
+ Scalar* c = reinterpret_cast<Scalar*>(pc);
+ Scalar alpha = *reinterpret_cast<Scalar*>(palpha);
+ Scalar beta = *reinterpret_cast<Scalar*>(pbeta);
+
+// std::cerr << "in hemm " << *side << " " << *uplo << " " << *m << " " << *n << " " << alpha << " " << *lda << " " << beta << " " << *ldc << "\n";
+
+ int info = 0;
+ if(SIDE(*side)==INVALID) info = 1;
+ else if(UPLO(*uplo)==INVALID) info = 2;
+ else if(*m<0) info = 3;
+ else if(*n<0) info = 4;
+ else if(*lda<std::max(1,(SIDE(*side)==LEFT)?*m:*n)) info = 7;
+ else if(*ldb<std::max(1,*m)) info = 9;
+ else if(*ldc<std::max(1,*m)) info = 12;
+ if(info)
+ return xerbla_(SCALAR_SUFFIX_UP"HEMM ",&info,6);
+
+ if(beta==Scalar(0)) matrix(c, *m, *n, *ldc).setZero();
+ else if(beta!=Scalar(1)) matrix(c, *m, *n, *ldc) *= beta;
+
+ if(*m==0 || *n==0)
+ {
+ return 1;
+ }
+
+ if(SIDE(*side)==LEFT)
+ {
+ if(UPLO(*uplo)==UP) internal::product_selfadjoint_matrix<Scalar,DenseIndex,RowMajor,true,Conj, ColMajor,false,false, ColMajor>
+ ::run(*m, *n, a, *lda, b, *ldb, c, *ldc, alpha);
+ else if(UPLO(*uplo)==LO) internal::product_selfadjoint_matrix<Scalar,DenseIndex,ColMajor,true,false, ColMajor,false,false, ColMajor>
+ ::run(*m, *n, a, *lda, b, *ldb, c, *ldc, alpha);
+ else return 0;
+ }
+ else if(SIDE(*side)==RIGHT)
+ {
+ if(UPLO(*uplo)==UP) matrix(c,*m,*n,*ldc) += alpha * matrix(b,*m,*n,*ldb) * matrix(a,*n,*n,*lda).selfadjointView<Upper>();/*internal::product_selfadjoint_matrix<Scalar,DenseIndex,ColMajor,false,false, RowMajor,true,Conj, ColMajor>
+ ::run(*m, *n, b, *ldb, a, *lda, c, *ldc, alpha);*/
+ else if(UPLO(*uplo)==LO) internal::product_selfadjoint_matrix<Scalar,DenseIndex,ColMajor,false,false, ColMajor,true,false, ColMajor>
+ ::run(*m, *n, b, *ldb, a, *lda, c, *ldc, alpha);
+ else return 0;
+ }
+ else
+ {
+ return 0;
+ }
+
+ return 0;
+}
+
+// c = alpha*a*conj(a') + beta*c for op = 'N'or'n'
+// c = alpha*conj(a')*a + beta*c for op = 'C'or'c'
+int EIGEN_BLAS_FUNC(herk)(char *uplo, char *op, int *n, int *k, RealScalar *palpha, RealScalar *pa, int *lda, RealScalar *pbeta, RealScalar *pc, int *ldc)
+{
+ typedef void (*functype)(DenseIndex, DenseIndex, const Scalar *, DenseIndex, const Scalar *, DenseIndex, Scalar *, DenseIndex, Scalar);
+ static functype func[8];
+
+ static bool init = false;
+ if(!init)
+ {
+ for(int k=0; k<8; ++k)
+ func[k] = 0;
+
+ func[NOTR | (UP << 2)] = (internal::general_matrix_matrix_triangular_product<DenseIndex,Scalar,ColMajor,false,Scalar,RowMajor,Conj, ColMajor,Upper>::run);
+ func[ADJ | (UP << 2)] = (internal::general_matrix_matrix_triangular_product<DenseIndex,Scalar,RowMajor,Conj, Scalar,ColMajor,false,ColMajor,Upper>::run);
+
+ func[NOTR | (LO << 2)] = (internal::general_matrix_matrix_triangular_product<DenseIndex,Scalar,ColMajor,false,Scalar,RowMajor,Conj, ColMajor,Lower>::run);
+ func[ADJ | (LO << 2)] = (internal::general_matrix_matrix_triangular_product<DenseIndex,Scalar,RowMajor,Conj, Scalar,ColMajor,false,ColMajor,Lower>::run);
+
+ init = true;
+ }
+
+ Scalar* a = reinterpret_cast<Scalar*>(pa);
+ Scalar* c = reinterpret_cast<Scalar*>(pc);
+ RealScalar alpha = *palpha;
+ RealScalar beta = *pbeta;
+
+// std::cerr << "in herk " << *uplo << " " << *op << " " << *n << " " << *k << " " << alpha << " " << *lda << " " << beta << " " << *ldc << "\n";
+
+ int info = 0;
+ if(UPLO(*uplo)==INVALID) info = 1;
+ else if((OP(*op)==INVALID) || (OP(*op)==TR)) info = 2;
+ else if(*n<0) info = 3;
+ else if(*k<0) info = 4;
+ else if(*lda<std::max(1,(OP(*op)==NOTR)?*n:*k)) info = 7;
+ else if(*ldc<std::max(1,*n)) info = 10;
+ if(info)
+ return xerbla_(SCALAR_SUFFIX_UP"HERK ",&info,6);
+
+ int code = OP(*op) | (UPLO(*uplo) << 2);
+
+ if(beta!=RealScalar(1))
+ {
+ if(UPLO(*uplo)==UP)
+ if(beta==Scalar(0)) matrix(c, *n, *n, *ldc).triangularView<Upper>().setZero();
+ else matrix(c, *n, *n, *ldc).triangularView<StrictlyUpper>() *= beta;
+ else
+ if(beta==Scalar(0)) matrix(c, *n, *n, *ldc).triangularView<Lower>().setZero();
+ else matrix(c, *n, *n, *ldc).triangularView<StrictlyLower>() *= beta;
+
+ if(beta!=Scalar(0))
+ {
+ matrix(c, *n, *n, *ldc).diagonal().real() *= beta;
+ matrix(c, *n, *n, *ldc).diagonal().imag().setZero();
+ }
+ }
+
+ if(*k>0 && alpha!=RealScalar(0))
+ {
+ func[code](*n, *k, a, *lda, a, *lda, c, *ldc, alpha);
+ matrix(c, *n, *n, *ldc).diagonal().imag().setZero();
+ }
+ return 0;
+}
+
+// c = alpha*a*conj(b') + conj(alpha)*b*conj(a') + beta*c, for op = 'N'or'n'
+// c = alpha*conj(a')*b + conj(alpha)*conj(b')*a + beta*c, for op = 'C'or'c'
+int EIGEN_BLAS_FUNC(her2k)(char *uplo, char *op, int *n, int *k, RealScalar *palpha, RealScalar *pa, int *lda, RealScalar *pb, int *ldb, RealScalar *pbeta, RealScalar *pc, int *ldc)
+{
+ Scalar* a = reinterpret_cast<Scalar*>(pa);
+ Scalar* b = reinterpret_cast<Scalar*>(pb);
+ Scalar* c = reinterpret_cast<Scalar*>(pc);
+ Scalar alpha = *reinterpret_cast<Scalar*>(palpha);
+ RealScalar beta = *pbeta;
+
+ int info = 0;
+ if(UPLO(*uplo)==INVALID) info = 1;
+ else if((OP(*op)==INVALID) || (OP(*op)==TR)) info = 2;
+ else if(*n<0) info = 3;
+ else if(*k<0) info = 4;
+ else if(*lda<std::max(1,(OP(*op)==NOTR)?*n:*k)) info = 7;
+ else if(*lda<std::max(1,(OP(*op)==NOTR)?*n:*k)) info = 9;
+ else if(*ldc<std::max(1,*n)) info = 12;
+ if(info)
+ return xerbla_(SCALAR_SUFFIX_UP"HER2K",&info,6);
+
+ if(beta!=RealScalar(1))
+ {
+ if(UPLO(*uplo)==UP)
+ if(beta==Scalar(0)) matrix(c, *n, *n, *ldc).triangularView<Upper>().setZero();
+ else matrix(c, *n, *n, *ldc).triangularView<StrictlyUpper>() *= beta;
+ else
+ if(beta==Scalar(0)) matrix(c, *n, *n, *ldc).triangularView<Lower>().setZero();
+ else matrix(c, *n, *n, *ldc).triangularView<StrictlyLower>() *= beta;
+
+ if(beta!=Scalar(0))
+ {
+ matrix(c, *n, *n, *ldc).diagonal().real() *= beta;
+ matrix(c, *n, *n, *ldc).diagonal().imag().setZero();
+ }
+ }
+ else if(*k>0 && alpha!=Scalar(0))
+ matrix(c, *n, *n, *ldc).diagonal().imag().setZero();
+
+ if(*k==0)
+ return 1;
+
+ if(OP(*op)==NOTR)
+ {
+ if(UPLO(*uplo)==UP)
+ {
+ matrix(c, *n, *n, *ldc).triangularView<Upper>()
+ += alpha *matrix(a, *n, *k, *lda)*matrix(b, *n, *k, *ldb).adjoint()
+ + internal::conj(alpha)*matrix(b, *n, *k, *ldb)*matrix(a, *n, *k, *lda).adjoint();
+ }
+ else if(UPLO(*uplo)==LO)
+ matrix(c, *n, *n, *ldc).triangularView<Lower>()
+ += alpha*matrix(a, *n, *k, *lda)*matrix(b, *n, *k, *ldb).adjoint()
+ + internal::conj(alpha)*matrix(b, *n, *k, *ldb)*matrix(a, *n, *k, *lda).adjoint();
+ }
+ else if(OP(*op)==ADJ)
+ {
+ if(UPLO(*uplo)==UP)
+ matrix(c, *n, *n, *ldc).triangularView<Upper>()
+ += alpha*matrix(a, *k, *n, *lda).adjoint()*matrix(b, *k, *n, *ldb)
+ + internal::conj(alpha)*matrix(b, *k, *n, *ldb).adjoint()*matrix(a, *k, *n, *lda);
+ else if(UPLO(*uplo)==LO)
+ matrix(c, *n, *n, *ldc).triangularView<Lower>()
+ += alpha*matrix(a, *k, *n, *lda).adjoint()*matrix(b, *k, *n, *ldb)
+ + internal::conj(alpha)*matrix(b, *k, *n, *ldb).adjoint()*matrix(a, *k, *n, *lda);
+ }
+
+ return 1;
+}
+
+#endif // ISCOMPLEX
diff --git a/blas/lsame.f b/blas/lsame.f
new file mode 100644
index 000000000..f53690268
--- /dev/null
+++ b/blas/lsame.f
@@ -0,0 +1,85 @@
+ LOGICAL FUNCTION LSAME(CA,CB)
+*
+* -- LAPACK auxiliary routine (version 3.1) --
+* Univ. of Tennessee, Univ. of California Berkeley and NAG Ltd..
+* November 2006
+*
+* .. Scalar Arguments ..
+ CHARACTER CA,CB
+* ..
+*
+* Purpose
+* =======
+*
+* LSAME returns .TRUE. if CA is the same letter as CB regardless of
+* case.
+*
+* Arguments
+* =========
+*
+* CA (input) CHARACTER*1
+*
+* CB (input) CHARACTER*1
+* CA and CB specify the single characters to be compared.
+*
+* =====================================================================
+*
+* .. Intrinsic Functions ..
+ INTRINSIC ICHAR
+* ..
+* .. Local Scalars ..
+ INTEGER INTA,INTB,ZCODE
+* ..
+*
+* Test if the characters are equal
+*
+ LSAME = CA .EQ. CB
+ IF (LSAME) RETURN
+*
+* Now test for equivalence if both characters are alphabetic.
+*
+ ZCODE = ICHAR('Z')
+*
+* Use 'Z' rather than 'A' so that ASCII can be detected on Prime
+* machines, on which ICHAR returns a value with bit 8 set.
+* ICHAR('A') on Prime machines returns 193 which is the same as
+* ICHAR('A') on an EBCDIC machine.
+*
+ INTA = ICHAR(CA)
+ INTB = ICHAR(CB)
+*
+ IF (ZCODE.EQ.90 .OR. ZCODE.EQ.122) THEN
+*
+* ASCII is assumed - ZCODE is the ASCII code of either lower or
+* upper case 'Z'.
+*
+ IF (INTA.GE.97 .AND. INTA.LE.122) INTA = INTA - 32
+ IF (INTB.GE.97 .AND. INTB.LE.122) INTB = INTB - 32
+*
+ ELSE IF (ZCODE.EQ.233 .OR. ZCODE.EQ.169) THEN
+*
+* EBCDIC is assumed - ZCODE is the EBCDIC code of either lower or
+* upper case 'Z'.
+*
+ IF (INTA.GE.129 .AND. INTA.LE.137 .OR.
+ + INTA.GE.145 .AND. INTA.LE.153 .OR.
+ + INTA.GE.162 .AND. INTA.LE.169) INTA = INTA + 64
+ IF (INTB.GE.129 .AND. INTB.LE.137 .OR.
+ + INTB.GE.145 .AND. INTB.LE.153 .OR.
+ + INTB.GE.162 .AND. INTB.LE.169) INTB = INTB + 64
+*
+ ELSE IF (ZCODE.EQ.218 .OR. ZCODE.EQ.250) THEN
+*
+* ASCII is assumed, on Prime machines - ZCODE is the ASCII code
+* plus 128 of either lower or upper case 'Z'.
+*
+ IF (INTA.GE.225 .AND. INTA.LE.250) INTA = INTA - 32
+ IF (INTB.GE.225 .AND. INTB.LE.250) INTB = INTB - 32
+ END IF
+ LSAME = INTA .EQ. INTB
+*
+* RETURN
+*
+* End of LSAME
+*
+ END
diff --git a/blas/single.cpp b/blas/single.cpp
new file mode 100644
index 000000000..1b7775aed
--- /dev/null
+++ b/blas/single.cpp
@@ -0,0 +1,19 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra.
+//
+// Copyright (C) 2009 Gael Guennebaud <gael.guennebaud@inria.fr>
+//
+// This Source Code Form is subject to the terms of the Mozilla
+// Public License v. 2.0. If a copy of the MPL was not distributed
+// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+#define SCALAR float
+#define SCALAR_SUFFIX s
+#define SCALAR_SUFFIX_UP "S"
+#define ISCOMPLEX 0
+
+#include "level1_impl.h"
+#include "level1_real_impl.h"
+#include "level2_impl.h"
+#include "level2_real_impl.h"
+#include "level3_impl.h"
diff --git a/blas/srotm.f b/blas/srotm.f
new file mode 100644
index 000000000..fc5a59333
--- /dev/null
+++ b/blas/srotm.f
@@ -0,0 +1,148 @@
+ SUBROUTINE SROTM(N,SX,INCX,SY,INCY,SPARAM)
+* .. Scalar Arguments ..
+ INTEGER INCX,INCY,N
+* ..
+* .. Array Arguments ..
+ REAL SPARAM(5),SX(*),SY(*)
+* ..
+*
+* Purpose
+* =======
+*
+* APPLY THE MODIFIED GIVENS TRANSFORMATION, H, TO THE 2 BY N MATRIX
+*
+* (SX**T) , WHERE **T INDICATES TRANSPOSE. THE ELEMENTS OF SX ARE IN
+* (DX**T)
+*
+* SX(LX+I*INCX), I = 0 TO N-1, WHERE LX = 1 IF INCX .GE. 0, ELSE
+* LX = (-INCX)*N, AND SIMILARLY FOR SY USING USING LY AND INCY.
+* WITH SPARAM(1)=SFLAG, H HAS ONE OF THE FOLLOWING FORMS..
+*
+* SFLAG=-1.E0 SFLAG=0.E0 SFLAG=1.E0 SFLAG=-2.E0
+*
+* (SH11 SH12) (1.E0 SH12) (SH11 1.E0) (1.E0 0.E0)
+* H=( ) ( ) ( ) ( )
+* (SH21 SH22), (SH21 1.E0), (-1.E0 SH22), (0.E0 1.E0).
+* SEE SROTMG FOR A DESCRIPTION OF DATA STORAGE IN SPARAM.
+*
+*
+* Arguments
+* =========
+*
+* N (input) INTEGER
+* number of elements in input vector(s)
+*
+* SX (input/output) REAL array, dimension N
+* double precision vector with N elements
+*
+* INCX (input) INTEGER
+* storage spacing between elements of SX
+*
+* SY (input/output) REAL array, dimension N
+* double precision vector with N elements
+*
+* INCY (input) INTEGER
+* storage spacing between elements of SY
+*
+* SPARAM (input/output) REAL array, dimension 5
+* SPARAM(1)=SFLAG
+* SPARAM(2)=SH11
+* SPARAM(3)=SH21
+* SPARAM(4)=SH12
+* SPARAM(5)=SH22
+*
+* =====================================================================
+*
+* .. Local Scalars ..
+ REAL SFLAG,SH11,SH12,SH21,SH22,TWO,W,Z,ZERO
+ INTEGER I,KX,KY,NSTEPS
+* ..
+* .. Data statements ..
+ DATA ZERO,TWO/0.E0,2.E0/
+* ..
+*
+ SFLAG = SPARAM(1)
+ IF (N.LE.0 .OR. (SFLAG+TWO.EQ.ZERO)) GO TO 140
+ IF (.NOT. (INCX.EQ.INCY.AND.INCX.GT.0)) GO TO 70
+*
+ NSTEPS = N*INCX
+ IF (SFLAG) 50,10,30
+ 10 CONTINUE
+ SH12 = SPARAM(4)
+ SH21 = SPARAM(3)
+ DO 20 I = 1,NSTEPS,INCX
+ W = SX(I)
+ Z = SY(I)
+ SX(I) = W + Z*SH12
+ SY(I) = W*SH21 + Z
+ 20 CONTINUE
+ GO TO 140
+ 30 CONTINUE
+ SH11 = SPARAM(2)
+ SH22 = SPARAM(5)
+ DO 40 I = 1,NSTEPS,INCX
+ W = SX(I)
+ Z = SY(I)
+ SX(I) = W*SH11 + Z
+ SY(I) = -W + SH22*Z
+ 40 CONTINUE
+ GO TO 140
+ 50 CONTINUE
+ SH11 = SPARAM(2)
+ SH12 = SPARAM(4)
+ SH21 = SPARAM(3)
+ SH22 = SPARAM(5)
+ DO 60 I = 1,NSTEPS,INCX
+ W = SX(I)
+ Z = SY(I)
+ SX(I) = W*SH11 + Z*SH12
+ SY(I) = W*SH21 + Z*SH22
+ 60 CONTINUE
+ GO TO 140
+ 70 CONTINUE
+ KX = 1
+ KY = 1
+ IF (INCX.LT.0) KX = 1 + (1-N)*INCX
+ IF (INCY.LT.0) KY = 1 + (1-N)*INCY
+*
+ IF (SFLAG) 120,80,100
+ 80 CONTINUE
+ SH12 = SPARAM(4)
+ SH21 = SPARAM(3)
+ DO 90 I = 1,N
+ W = SX(KX)
+ Z = SY(KY)
+ SX(KX) = W + Z*SH12
+ SY(KY) = W*SH21 + Z
+ KX = KX + INCX
+ KY = KY + INCY
+ 90 CONTINUE
+ GO TO 140
+ 100 CONTINUE
+ SH11 = SPARAM(2)
+ SH22 = SPARAM(5)
+ DO 110 I = 1,N
+ W = SX(KX)
+ Z = SY(KY)
+ SX(KX) = W*SH11 + Z
+ SY(KY) = -W + SH22*Z
+ KX = KX + INCX
+ KY = KY + INCY
+ 110 CONTINUE
+ GO TO 140
+ 120 CONTINUE
+ SH11 = SPARAM(2)
+ SH12 = SPARAM(4)
+ SH21 = SPARAM(3)
+ SH22 = SPARAM(5)
+ DO 130 I = 1,N
+ W = SX(KX)
+ Z = SY(KY)
+ SX(KX) = W*SH11 + Z*SH12
+ SY(KY) = W*SH21 + Z*SH22
+ KX = KX + INCX
+ KY = KY + INCY
+ 130 CONTINUE
+ 140 CONTINUE
+ RETURN
+ END
diff --git a/blas/srotmg.f b/blas/srotmg.f
new file mode 100644
index 000000000..7b3bd4272
--- /dev/null
+++ b/blas/srotmg.f
@@ -0,0 +1,208 @@
+ SUBROUTINE SROTMG(SD1,SD2,SX1,SY1,SPARAM)
+* .. Scalar Arguments ..
+ REAL SD1,SD2,SX1,SY1
+* ..
+* .. Array Arguments ..
+ REAL SPARAM(5)
+* ..
+*
+* Purpose
+* =======
+*
+* CONSTRUCT THE MODIFIED GIVENS TRANSFORMATION MATRIX H WHICH ZEROS
+* THE SECOND COMPONENT OF THE 2-VECTOR (SQRT(SD1)*SX1,SQRT(SD2)*
+* SY2)**T.
+* WITH SPARAM(1)=SFLAG, H HAS ONE OF THE FOLLOWING FORMS..
+*
+* SFLAG=-1.E0 SFLAG=0.E0 SFLAG=1.E0 SFLAG=-2.E0
+*
+* (SH11 SH12) (1.E0 SH12) (SH11 1.E0) (1.E0 0.E0)
+* H=( ) ( ) ( ) ( )
+* (SH21 SH22), (SH21 1.E0), (-1.E0 SH22), (0.E0 1.E0).
+* LOCATIONS 2-4 OF SPARAM CONTAIN SH11,SH21,SH12, AND SH22
+* RESPECTIVELY. (VALUES OF 1.E0, -1.E0, OR 0.E0 IMPLIED BY THE
+* VALUE OF SPARAM(1) ARE NOT STORED IN SPARAM.)
+*
+* THE VALUES OF GAMSQ AND RGAMSQ SET IN THE DATA STATEMENT MAY BE
+* INEXACT. THIS IS OK AS THEY ARE ONLY USED FOR TESTING THE SIZE
+* OF SD1 AND SD2. ALL ACTUAL SCALING OF DATA IS DONE USING GAM.
+*
+*
+* Arguments
+* =========
+*
+*
+* SD1 (input/output) REAL
+*
+* SD2 (input/output) REAL
+*
+* SX1 (input/output) REAL
+*
+* SY1 (input) REAL
+*
+*
+* SPARAM (input/output) REAL array, dimension 5
+* SPARAM(1)=SFLAG
+* SPARAM(2)=SH11
+* SPARAM(3)=SH21
+* SPARAM(4)=SH12
+* SPARAM(5)=SH22
+*
+* =====================================================================
+*
+* .. Local Scalars ..
+ REAL GAM,GAMSQ,ONE,RGAMSQ,SFLAG,SH11,SH12,SH21,SH22,SP1,SP2,SQ1,
+ + SQ2,STEMP,SU,TWO,ZERO
+ INTEGER IGO
+* ..
+* .. Intrinsic Functions ..
+ INTRINSIC ABS
+* ..
+* .. Data statements ..
+*
+ DATA ZERO,ONE,TWO/0.E0,1.E0,2.E0/
+ DATA GAM,GAMSQ,RGAMSQ/4096.E0,1.67772E7,5.96046E-8/
+* ..
+
+ IF (.NOT.SD1.LT.ZERO) GO TO 10
+* GO ZERO-H-D-AND-SX1..
+ GO TO 60
+ 10 CONTINUE
+* CASE-SD1-NONNEGATIVE
+ SP2 = SD2*SY1
+ IF (.NOT.SP2.EQ.ZERO) GO TO 20
+ SFLAG = -TWO
+ GO TO 260
+* REGULAR-CASE..
+ 20 CONTINUE
+ SP1 = SD1*SX1
+ SQ2 = SP2*SY1
+ SQ1 = SP1*SX1
+*
+ IF (.NOT.ABS(SQ1).GT.ABS(SQ2)) GO TO 40
+ SH21 = -SY1/SX1
+ SH12 = SP2/SP1
+*
+ SU = ONE - SH12*SH21
+*
+ IF (.NOT.SU.LE.ZERO) GO TO 30
+* GO ZERO-H-D-AND-SX1..
+ GO TO 60
+ 30 CONTINUE
+ SFLAG = ZERO
+ SD1 = SD1/SU
+ SD2 = SD2/SU
+ SX1 = SX1*SU
+* GO SCALE-CHECK..
+ GO TO 100
+ 40 CONTINUE
+ IF (.NOT.SQ2.LT.ZERO) GO TO 50
+* GO ZERO-H-D-AND-SX1..
+ GO TO 60
+ 50 CONTINUE
+ SFLAG = ONE
+ SH11 = SP1/SP2
+ SH22 = SX1/SY1
+ SU = ONE + SH11*SH22
+ STEMP = SD2/SU
+ SD2 = SD1/SU
+ SD1 = STEMP
+ SX1 = SY1*SU
+* GO SCALE-CHECK
+ GO TO 100
+* PROCEDURE..ZERO-H-D-AND-SX1..
+ 60 CONTINUE
+ SFLAG = -ONE
+ SH11 = ZERO
+ SH12 = ZERO
+ SH21 = ZERO
+ SH22 = ZERO
+*
+ SD1 = ZERO
+ SD2 = ZERO
+ SX1 = ZERO
+* RETURN..
+ GO TO 220
+* PROCEDURE..FIX-H..
+ 70 CONTINUE
+ IF (.NOT.SFLAG.GE.ZERO) GO TO 90
+*
+ IF (.NOT.SFLAG.EQ.ZERO) GO TO 80
+ SH11 = ONE
+ SH22 = ONE
+ SFLAG = -ONE
+ GO TO 90
+ 80 CONTINUE
+ SH21 = -ONE
+ SH12 = ONE
+ SFLAG = -ONE
+ 90 CONTINUE
+ GO TO IGO(120,150,180,210)
+* PROCEDURE..SCALE-CHECK
+ 100 CONTINUE
+ 110 CONTINUE
+ IF (.NOT.SD1.LE.RGAMSQ) GO TO 130
+ IF (SD1.EQ.ZERO) GO TO 160
+ ASSIGN 120 TO IGO
+* FIX-H..
+ GO TO 70
+ 120 CONTINUE
+ SD1 = SD1*GAM**2
+ SX1 = SX1/GAM
+ SH11 = SH11/GAM
+ SH12 = SH12/GAM
+ GO TO 110
+ 130 CONTINUE
+ 140 CONTINUE
+ IF (.NOT.SD1.GE.GAMSQ) GO TO 160
+ ASSIGN 150 TO IGO
+* FIX-H..
+ GO TO 70
+ 150 CONTINUE
+ SD1 = SD1/GAM**2
+ SX1 = SX1*GAM
+ SH11 = SH11*GAM
+ SH12 = SH12*GAM
+ GO TO 140
+ 160 CONTINUE
+ 170 CONTINUE
+ IF (.NOT.ABS(SD2).LE.RGAMSQ) GO TO 190
+ IF (SD2.EQ.ZERO) GO TO 220
+ ASSIGN 180 TO IGO
+* FIX-H..
+ GO TO 70
+ 180 CONTINUE
+ SD2 = SD2*GAM**2
+ SH21 = SH21/GAM
+ SH22 = SH22/GAM
+ GO TO 170
+ 190 CONTINUE
+ 200 CONTINUE
+ IF (.NOT.ABS(SD2).GE.GAMSQ) GO TO 220
+ ASSIGN 210 TO IGO
+* FIX-H..
+ GO TO 70
+ 210 CONTINUE
+ SD2 = SD2/GAM**2
+ SH21 = SH21*GAM
+ SH22 = SH22*GAM
+ GO TO 200
+ 220 CONTINUE
+ IF (SFLAG) 250,230,240
+ 230 CONTINUE
+ SPARAM(3) = SH21
+ SPARAM(4) = SH12
+ GO TO 260
+ 240 CONTINUE
+ SPARAM(2) = SH11
+ SPARAM(5) = SH22
+ GO TO 260
+ 250 CONTINUE
+ SPARAM(2) = SH11
+ SPARAM(3) = SH21
+ SPARAM(4) = SH12
+ SPARAM(5) = SH22
+ 260 CONTINUE
+ SPARAM(1) = SFLAG
+ RETURN
+ END
diff --git a/blas/ssbmv.f b/blas/ssbmv.f
new file mode 100644
index 000000000..16893a295
--- /dev/null
+++ b/blas/ssbmv.f
@@ -0,0 +1,306 @@
+ SUBROUTINE SSBMV(UPLO,N,K,ALPHA,A,LDA,X,INCX,BETA,Y,INCY)
+* .. Scalar Arguments ..
+ REAL ALPHA,BETA
+ INTEGER INCX,INCY,K,LDA,N
+ CHARACTER UPLO
+* ..
+* .. Array Arguments ..
+ REAL A(LDA,*),X(*),Y(*)
+* ..
+*
+* Purpose
+* =======
+*
+* SSBMV performs the matrix-vector operation
+*
+* y := alpha*A*x + beta*y,
+*
+* where alpha and beta are scalars, x and y are n element vectors and
+* A is an n by n symmetric band matrix, with k super-diagonals.
+*
+* Arguments
+* ==========
+*
+* UPLO - CHARACTER*1.
+* On entry, UPLO specifies whether the upper or lower
+* triangular part of the band matrix A is being supplied as
+* follows:
+*
+* UPLO = 'U' or 'u' The upper triangular part of A is
+* being supplied.
+*
+* UPLO = 'L' or 'l' The lower triangular part of A is
+* being supplied.
+*
+* Unchanged on exit.
+*
+* N - INTEGER.
+* On entry, N specifies the order of the matrix A.
+* N must be at least zero.
+* Unchanged on exit.
+*
+* K - INTEGER.
+* On entry, K specifies the number of super-diagonals of the
+* matrix A. K must satisfy 0 .le. K.
+* Unchanged on exit.
+*
+* ALPHA - REAL .
+* On entry, ALPHA specifies the scalar alpha.
+* Unchanged on exit.
+*
+* A - REAL array of DIMENSION ( LDA, n ).
+* Before entry with UPLO = 'U' or 'u', the leading ( k + 1 )
+* by n part of the array A must contain the upper triangular
+* band part of the symmetric matrix, supplied column by
+* column, with the leading diagonal of the matrix in row
+* ( k + 1 ) of the array, the first super-diagonal starting at
+* position 2 in row k, and so on. The top left k by k triangle
+* of the array A is not referenced.
+* The following program segment will transfer the upper
+* triangular part of a symmetric band matrix from conventional
+* full matrix storage to band storage:
+*
+* DO 20, J = 1, N
+* M = K + 1 - J
+* DO 10, I = MAX( 1, J - K ), J
+* A( M + I, J ) = matrix( I, J )
+* 10 CONTINUE
+* 20 CONTINUE
+*
+* Before entry with UPLO = 'L' or 'l', the leading ( k + 1 )
+* by n part of the array A must contain the lower triangular
+* band part of the symmetric matrix, supplied column by
+* column, with the leading diagonal of the matrix in row 1 of
+* the array, the first sub-diagonal starting at position 1 in
+* row 2, and so on. The bottom right k by k triangle of the
+* array A is not referenced.
+* The following program segment will transfer the lower
+* triangular part of a symmetric band matrix from conventional
+* full matrix storage to band storage:
+*
+* DO 20, J = 1, N
+* M = 1 - J
+* DO 10, I = J, MIN( N, J + K )
+* A( M + I, J ) = matrix( I, J )
+* 10 CONTINUE
+* 20 CONTINUE
+*
+* Unchanged on exit.
+*
+* LDA - INTEGER.
+* On entry, LDA specifies the first dimension of A as declared
+* in the calling (sub) program. LDA must be at least
+* ( k + 1 ).
+* Unchanged on exit.
+*
+* X - REAL array of DIMENSION at least
+* ( 1 + ( n - 1 )*abs( INCX ) ).
+* Before entry, the incremented array X must contain the
+* vector x.
+* Unchanged on exit.
+*
+* INCX - INTEGER.
+* On entry, INCX specifies the increment for the elements of
+* X. INCX must not be zero.
+* Unchanged on exit.
+*
+* BETA - REAL .
+* On entry, BETA specifies the scalar beta.
+* Unchanged on exit.
+*
+* Y - REAL array of DIMENSION at least
+* ( 1 + ( n - 1 )*abs( INCY ) ).
+* Before entry, the incremented array Y must contain the
+* vector y. On exit, Y is overwritten by the updated vector y.
+*
+* INCY - INTEGER.
+* On entry, INCY specifies the increment for the elements of
+* Y. INCY must not be zero.
+* Unchanged on exit.
+*
+* Further Details
+* ===============
+*
+* Level 2 Blas routine.
+*
+* -- Written on 22-October-1986.
+* Jack Dongarra, Argonne National Lab.
+* Jeremy Du Croz, Nag Central Office.
+* Sven Hammarling, Nag Central Office.
+* Richard Hanson, Sandia National Labs.
+*
+* =====================================================================
+*
+* .. Parameters ..
+ REAL ONE,ZERO
+ PARAMETER (ONE=1.0E+0,ZERO=0.0E+0)
+* ..
+* .. Local Scalars ..
+ REAL TEMP1,TEMP2
+ INTEGER I,INFO,IX,IY,J,JX,JY,KPLUS1,KX,KY,L
+* ..
+* .. External Functions ..
+ LOGICAL LSAME
+ EXTERNAL LSAME
+* ..
+* .. External Subroutines ..
+ EXTERNAL XERBLA
+* ..
+* .. Intrinsic Functions ..
+ INTRINSIC MAX,MIN
+* ..
+*
+* Test the input parameters.
+*
+ INFO = 0
+ IF (.NOT.LSAME(UPLO,'U') .AND. .NOT.LSAME(UPLO,'L')) THEN
+ INFO = 1
+ ELSE IF (N.LT.0) THEN
+ INFO = 2
+ ELSE IF (K.LT.0) THEN
+ INFO = 3
+ ELSE IF (LDA.LT. (K+1)) THEN
+ INFO = 6
+ ELSE IF (INCX.EQ.0) THEN
+ INFO = 8
+ ELSE IF (INCY.EQ.0) THEN
+ INFO = 11
+ END IF
+ IF (INFO.NE.0) THEN
+ CALL XERBLA('SSBMV ',INFO)
+ RETURN
+ END IF
+*
+* Quick return if possible.
+*
+ IF ((N.EQ.0) .OR. ((ALPHA.EQ.ZERO).AND. (BETA.EQ.ONE))) RETURN
+*
+* Set up the start points in X and Y.
+*
+ IF (INCX.GT.0) THEN
+ KX = 1
+ ELSE
+ KX = 1 - (N-1)*INCX
+ END IF
+ IF (INCY.GT.0) THEN
+ KY = 1
+ ELSE
+ KY = 1 - (N-1)*INCY
+ END IF
+*
+* Start the operations. In this version the elements of the array A
+* are accessed sequentially with one pass through A.
+*
+* First form y := beta*y.
+*
+ IF (BETA.NE.ONE) THEN
+ IF (INCY.EQ.1) THEN
+ IF (BETA.EQ.ZERO) THEN
+ DO 10 I = 1,N
+ Y(I) = ZERO
+ 10 CONTINUE
+ ELSE
+ DO 20 I = 1,N
+ Y(I) = BETA*Y(I)
+ 20 CONTINUE
+ END IF
+ ELSE
+ IY = KY
+ IF (BETA.EQ.ZERO) THEN
+ DO 30 I = 1,N
+ Y(IY) = ZERO
+ IY = IY + INCY
+ 30 CONTINUE
+ ELSE
+ DO 40 I = 1,N
+ Y(IY) = BETA*Y(IY)
+ IY = IY + INCY
+ 40 CONTINUE
+ END IF
+ END IF
+ END IF
+ IF (ALPHA.EQ.ZERO) RETURN
+ IF (LSAME(UPLO,'U')) THEN
+*
+* Form y when upper triangle of A is stored.
+*
+ KPLUS1 = K + 1
+ IF ((INCX.EQ.1) .AND. (INCY.EQ.1)) THEN
+ DO 60 J = 1,N
+ TEMP1 = ALPHA*X(J)
+ TEMP2 = ZERO
+ L = KPLUS1 - J
+ DO 50 I = MAX(1,J-K),J - 1
+ Y(I) = Y(I) + TEMP1*A(L+I,J)
+ TEMP2 = TEMP2 + A(L+I,J)*X(I)
+ 50 CONTINUE
+ Y(J) = Y(J) + TEMP1*A(KPLUS1,J) + ALPHA*TEMP2
+ 60 CONTINUE
+ ELSE
+ JX = KX
+ JY = KY
+ DO 80 J = 1,N
+ TEMP1 = ALPHA*X(JX)
+ TEMP2 = ZERO
+ IX = KX
+ IY = KY
+ L = KPLUS1 - J
+ DO 70 I = MAX(1,J-K),J - 1
+ Y(IY) = Y(IY) + TEMP1*A(L+I,J)
+ TEMP2 = TEMP2 + A(L+I,J)*X(IX)
+ IX = IX + INCX
+ IY = IY + INCY
+ 70 CONTINUE
+ Y(JY) = Y(JY) + TEMP1*A(KPLUS1,J) + ALPHA*TEMP2
+ JX = JX + INCX
+ JY = JY + INCY
+ IF (J.GT.K) THEN
+ KX = KX + INCX
+ KY = KY + INCY
+ END IF
+ 80 CONTINUE
+ END IF
+ ELSE
+*
+* Form y when lower triangle of A is stored.
+*
+ IF ((INCX.EQ.1) .AND. (INCY.EQ.1)) THEN
+ DO 100 J = 1,N
+ TEMP1 = ALPHA*X(J)
+ TEMP2 = ZERO
+ Y(J) = Y(J) + TEMP1*A(1,J)
+ L = 1 - J
+ DO 90 I = J + 1,MIN(N,J+K)
+ Y(I) = Y(I) + TEMP1*A(L+I,J)
+ TEMP2 = TEMP2 + A(L+I,J)*X(I)
+ 90 CONTINUE
+ Y(J) = Y(J) + ALPHA*TEMP2
+ 100 CONTINUE
+ ELSE
+ JX = KX
+ JY = KY
+ DO 120 J = 1,N
+ TEMP1 = ALPHA*X(JX)
+ TEMP2 = ZERO
+ Y(JY) = Y(JY) + TEMP1*A(1,J)
+ L = 1 - J
+ IX = JX
+ IY = JY
+ DO 110 I = J + 1,MIN(N,J+K)
+ IX = IX + INCX
+ IY = IY + INCY
+ Y(IY) = Y(IY) + TEMP1*A(L+I,J)
+ TEMP2 = TEMP2 + A(L+I,J)*X(IX)
+ 110 CONTINUE
+ Y(JY) = Y(JY) + ALPHA*TEMP2
+ JX = JX + INCX
+ JY = JY + INCY
+ 120 CONTINUE
+ END IF
+ END IF
+*
+ RETURN
+*
+* End of SSBMV .
+*
+ END
diff --git a/blas/sspmv.f b/blas/sspmv.f
new file mode 100644
index 000000000..0b8449824
--- /dev/null
+++ b/blas/sspmv.f
@@ -0,0 +1,265 @@
+ SUBROUTINE SSPMV(UPLO,N,ALPHA,AP,X,INCX,BETA,Y,INCY)
+* .. Scalar Arguments ..
+ REAL ALPHA,BETA
+ INTEGER INCX,INCY,N
+ CHARACTER UPLO
+* ..
+* .. Array Arguments ..
+ REAL AP(*),X(*),Y(*)
+* ..
+*
+* Purpose
+* =======
+*
+* SSPMV performs the matrix-vector operation
+*
+* y := alpha*A*x + beta*y,
+*
+* where alpha and beta are scalars, x and y are n element vectors and
+* A is an n by n symmetric matrix, supplied in packed form.
+*
+* Arguments
+* ==========
+*
+* UPLO - CHARACTER*1.
+* On entry, UPLO specifies whether the upper or lower
+* triangular part of the matrix A is supplied in the packed
+* array AP as follows:
+*
+* UPLO = 'U' or 'u' The upper triangular part of A is
+* supplied in AP.
+*
+* UPLO = 'L' or 'l' The lower triangular part of A is
+* supplied in AP.
+*
+* Unchanged on exit.
+*
+* N - INTEGER.
+* On entry, N specifies the order of the matrix A.
+* N must be at least zero.
+* Unchanged on exit.
+*
+* ALPHA - REAL .
+* On entry, ALPHA specifies the scalar alpha.
+* Unchanged on exit.
+*
+* AP - REAL array of DIMENSION at least
+* ( ( n*( n + 1 ) )/2 ).
+* Before entry with UPLO = 'U' or 'u', the array AP must
+* contain the upper triangular part of the symmetric matrix
+* packed sequentially, column by column, so that AP( 1 )
+* contains a( 1, 1 ), AP( 2 ) and AP( 3 ) contain a( 1, 2 )
+* and a( 2, 2 ) respectively, and so on.
+* Before entry with UPLO = 'L' or 'l', the array AP must
+* contain the lower triangular part of the symmetric matrix
+* packed sequentially, column by column, so that AP( 1 )
+* contains a( 1, 1 ), AP( 2 ) and AP( 3 ) contain a( 2, 1 )
+* and a( 3, 1 ) respectively, and so on.
+* Unchanged on exit.
+*
+* X - REAL array of dimension at least
+* ( 1 + ( n - 1 )*abs( INCX ) ).
+* Before entry, the incremented array X must contain the n
+* element vector x.
+* Unchanged on exit.
+*
+* INCX - INTEGER.
+* On entry, INCX specifies the increment for the elements of
+* X. INCX must not be zero.
+* Unchanged on exit.
+*
+* BETA - REAL .
+* On entry, BETA specifies the scalar beta. When BETA is
+* supplied as zero then Y need not be set on input.
+* Unchanged on exit.
+*
+* Y - REAL array of dimension at least
+* ( 1 + ( n - 1 )*abs( INCY ) ).
+* Before entry, the incremented array Y must contain the n
+* element vector y. On exit, Y is overwritten by the updated
+* vector y.
+*
+* INCY - INTEGER.
+* On entry, INCY specifies the increment for the elements of
+* Y. INCY must not be zero.
+* Unchanged on exit.
+*
+* Further Details
+* ===============
+*
+* Level 2 Blas routine.
+*
+* -- Written on 22-October-1986.
+* Jack Dongarra, Argonne National Lab.
+* Jeremy Du Croz, Nag Central Office.
+* Sven Hammarling, Nag Central Office.
+* Richard Hanson, Sandia National Labs.
+*
+* =====================================================================
+*
+* .. Parameters ..
+ REAL ONE,ZERO
+ PARAMETER (ONE=1.0E+0,ZERO=0.0E+0)
+* ..
+* .. Local Scalars ..
+ REAL TEMP1,TEMP2
+ INTEGER I,INFO,IX,IY,J,JX,JY,K,KK,KX,KY
+* ..
+* .. External Functions ..
+ LOGICAL LSAME
+ EXTERNAL LSAME
+* ..
+* .. External Subroutines ..
+ EXTERNAL XERBLA
+* ..
+*
+* Test the input parameters.
+*
+ INFO = 0
+ IF (.NOT.LSAME(UPLO,'U') .AND. .NOT.LSAME(UPLO,'L')) THEN
+ INFO = 1
+ ELSE IF (N.LT.0) THEN
+ INFO = 2
+ ELSE IF (INCX.EQ.0) THEN
+ INFO = 6
+ ELSE IF (INCY.EQ.0) THEN
+ INFO = 9
+ END IF
+ IF (INFO.NE.0) THEN
+ CALL XERBLA('SSPMV ',INFO)
+ RETURN
+ END IF
+*
+* Quick return if possible.
+*
+ IF ((N.EQ.0) .OR. ((ALPHA.EQ.ZERO).AND. (BETA.EQ.ONE))) RETURN
+*
+* Set up the start points in X and Y.
+*
+ IF (INCX.GT.0) THEN
+ KX = 1
+ ELSE
+ KX = 1 - (N-1)*INCX
+ END IF
+ IF (INCY.GT.0) THEN
+ KY = 1
+ ELSE
+ KY = 1 - (N-1)*INCY
+ END IF
+*
+* Start the operations. In this version the elements of the array AP
+* are accessed sequentially with one pass through AP.
+*
+* First form y := beta*y.
+*
+ IF (BETA.NE.ONE) THEN
+ IF (INCY.EQ.1) THEN
+ IF (BETA.EQ.ZERO) THEN
+ DO 10 I = 1,N
+ Y(I) = ZERO
+ 10 CONTINUE
+ ELSE
+ DO 20 I = 1,N
+ Y(I) = BETA*Y(I)
+ 20 CONTINUE
+ END IF
+ ELSE
+ IY = KY
+ IF (BETA.EQ.ZERO) THEN
+ DO 30 I = 1,N
+ Y(IY) = ZERO
+ IY = IY + INCY
+ 30 CONTINUE
+ ELSE
+ DO 40 I = 1,N
+ Y(IY) = BETA*Y(IY)
+ IY = IY + INCY
+ 40 CONTINUE
+ END IF
+ END IF
+ END IF
+ IF (ALPHA.EQ.ZERO) RETURN
+ KK = 1
+ IF (LSAME(UPLO,'U')) THEN
+*
+* Form y when AP contains the upper triangle.
+*
+ IF ((INCX.EQ.1) .AND. (INCY.EQ.1)) THEN
+ DO 60 J = 1,N
+ TEMP1 = ALPHA*X(J)
+ TEMP2 = ZERO
+ K = KK
+ DO 50 I = 1,J - 1
+ Y(I) = Y(I) + TEMP1*AP(K)
+ TEMP2 = TEMP2 + AP(K)*X(I)
+ K = K + 1
+ 50 CONTINUE
+ Y(J) = Y(J) + TEMP1*AP(KK+J-1) + ALPHA*TEMP2
+ KK = KK + J
+ 60 CONTINUE
+ ELSE
+ JX = KX
+ JY = KY
+ DO 80 J = 1,N
+ TEMP1 = ALPHA*X(JX)
+ TEMP2 = ZERO
+ IX = KX
+ IY = KY
+ DO 70 K = KK,KK + J - 2
+ Y(IY) = Y(IY) + TEMP1*AP(K)
+ TEMP2 = TEMP2 + AP(K)*X(IX)
+ IX = IX + INCX
+ IY = IY + INCY
+ 70 CONTINUE
+ Y(JY) = Y(JY) + TEMP1*AP(KK+J-1) + ALPHA*TEMP2
+ JX = JX + INCX
+ JY = JY + INCY
+ KK = KK + J
+ 80 CONTINUE
+ END IF
+ ELSE
+*
+* Form y when AP contains the lower triangle.
+*
+ IF ((INCX.EQ.1) .AND. (INCY.EQ.1)) THEN
+ DO 100 J = 1,N
+ TEMP1 = ALPHA*X(J)
+ TEMP2 = ZERO
+ Y(J) = Y(J) + TEMP1*AP(KK)
+ K = KK + 1
+ DO 90 I = J + 1,N
+ Y(I) = Y(I) + TEMP1*AP(K)
+ TEMP2 = TEMP2 + AP(K)*X(I)
+ K = K + 1
+ 90 CONTINUE
+ Y(J) = Y(J) + ALPHA*TEMP2
+ KK = KK + (N-J+1)
+ 100 CONTINUE
+ ELSE
+ JX = KX
+ JY = KY
+ DO 120 J = 1,N
+ TEMP1 = ALPHA*X(JX)
+ TEMP2 = ZERO
+ Y(JY) = Y(JY) + TEMP1*AP(KK)
+ IX = JX
+ IY = JY
+ DO 110 K = KK + 1,KK + N - J
+ IX = IX + INCX
+ IY = IY + INCY
+ Y(IY) = Y(IY) + TEMP1*AP(K)
+ TEMP2 = TEMP2 + AP(K)*X(IX)
+ 110 CONTINUE
+ Y(JY) = Y(JY) + ALPHA*TEMP2
+ JX = JX + INCX
+ JY = JY + INCY
+ KK = KK + (N-J+1)
+ 120 CONTINUE
+ END IF
+ END IF
+*
+ RETURN
+*
+* End of SSPMV .
+*
+ END
diff --git a/blas/sspr.f b/blas/sspr.f
new file mode 100644
index 000000000..bae92612e
--- /dev/null
+++ b/blas/sspr.f
@@ -0,0 +1,202 @@
+ SUBROUTINE SSPR(UPLO,N,ALPHA,X,INCX,AP)
+* .. Scalar Arguments ..
+ REAL ALPHA
+ INTEGER INCX,N
+ CHARACTER UPLO
+* ..
+* .. Array Arguments ..
+ REAL AP(*),X(*)
+* ..
+*
+* Purpose
+* =======
+*
+* SSPR performs the symmetric rank 1 operation
+*
+* A := alpha*x*x' + A,
+*
+* where alpha is a real scalar, x is an n element vector and A is an
+* n by n symmetric matrix, supplied in packed form.
+*
+* Arguments
+* ==========
+*
+* UPLO - CHARACTER*1.
+* On entry, UPLO specifies whether the upper or lower
+* triangular part of the matrix A is supplied in the packed
+* array AP as follows:
+*
+* UPLO = 'U' or 'u' The upper triangular part of A is
+* supplied in AP.
+*
+* UPLO = 'L' or 'l' The lower triangular part of A is
+* supplied in AP.
+*
+* Unchanged on exit.
+*
+* N - INTEGER.
+* On entry, N specifies the order of the matrix A.
+* N must be at least zero.
+* Unchanged on exit.
+*
+* ALPHA - REAL .
+* On entry, ALPHA specifies the scalar alpha.
+* Unchanged on exit.
+*
+* X - REAL array of dimension at least
+* ( 1 + ( n - 1 )*abs( INCX ) ).
+* Before entry, the incremented array X must contain the n
+* element vector x.
+* Unchanged on exit.
+*
+* INCX - INTEGER.
+* On entry, INCX specifies the increment for the elements of
+* X. INCX must not be zero.
+* Unchanged on exit.
+*
+* AP - REAL array of DIMENSION at least
+* ( ( n*( n + 1 ) )/2 ).
+* Before entry with UPLO = 'U' or 'u', the array AP must
+* contain the upper triangular part of the symmetric matrix
+* packed sequentially, column by column, so that AP( 1 )
+* contains a( 1, 1 ), AP( 2 ) and AP( 3 ) contain a( 1, 2 )
+* and a( 2, 2 ) respectively, and so on. On exit, the array
+* AP is overwritten by the upper triangular part of the
+* updated matrix.
+* Before entry with UPLO = 'L' or 'l', the array AP must
+* contain the lower triangular part of the symmetric matrix
+* packed sequentially, column by column, so that AP( 1 )
+* contains a( 1, 1 ), AP( 2 ) and AP( 3 ) contain a( 2, 1 )
+* and a( 3, 1 ) respectively, and so on. On exit, the array
+* AP is overwritten by the lower triangular part of the
+* updated matrix.
+*
+* Further Details
+* ===============
+*
+* Level 2 Blas routine.
+*
+* -- Written on 22-October-1986.
+* Jack Dongarra, Argonne National Lab.
+* Jeremy Du Croz, Nag Central Office.
+* Sven Hammarling, Nag Central Office.
+* Richard Hanson, Sandia National Labs.
+*
+* =====================================================================
+*
+* .. Parameters ..
+ REAL ZERO
+ PARAMETER (ZERO=0.0E+0)
+* ..
+* .. Local Scalars ..
+ REAL TEMP
+ INTEGER I,INFO,IX,J,JX,K,KK,KX
+* ..
+* .. External Functions ..
+ LOGICAL LSAME
+ EXTERNAL LSAME
+* ..
+* .. External Subroutines ..
+ EXTERNAL XERBLA
+* ..
+*
+* Test the input parameters.
+*
+ INFO = 0
+ IF (.NOT.LSAME(UPLO,'U') .AND. .NOT.LSAME(UPLO,'L')) THEN
+ INFO = 1
+ ELSE IF (N.LT.0) THEN
+ INFO = 2
+ ELSE IF (INCX.EQ.0) THEN
+ INFO = 5
+ END IF
+ IF (INFO.NE.0) THEN
+ CALL XERBLA('SSPR ',INFO)
+ RETURN
+ END IF
+*
+* Quick return if possible.
+*
+ IF ((N.EQ.0) .OR. (ALPHA.EQ.ZERO)) RETURN
+*
+* Set the start point in X if the increment is not unity.
+*
+ IF (INCX.LE.0) THEN
+ KX = 1 - (N-1)*INCX
+ ELSE IF (INCX.NE.1) THEN
+ KX = 1
+ END IF
+*
+* Start the operations. In this version the elements of the array AP
+* are accessed sequentially with one pass through AP.
+*
+ KK = 1
+ IF (LSAME(UPLO,'U')) THEN
+*
+* Form A when upper triangle is stored in AP.
+*
+ IF (INCX.EQ.1) THEN
+ DO 20 J = 1,N
+ IF (X(J).NE.ZERO) THEN
+ TEMP = ALPHA*X(J)
+ K = KK
+ DO 10 I = 1,J
+ AP(K) = AP(K) + X(I)*TEMP
+ K = K + 1
+ 10 CONTINUE
+ END IF
+ KK = KK + J
+ 20 CONTINUE
+ ELSE
+ JX = KX
+ DO 40 J = 1,N
+ IF (X(JX).NE.ZERO) THEN
+ TEMP = ALPHA*X(JX)
+ IX = KX
+ DO 30 K = KK,KK + J - 1
+ AP(K) = AP(K) + X(IX)*TEMP
+ IX = IX + INCX
+ 30 CONTINUE
+ END IF
+ JX = JX + INCX
+ KK = KK + J
+ 40 CONTINUE
+ END IF
+ ELSE
+*
+* Form A when lower triangle is stored in AP.
+*
+ IF (INCX.EQ.1) THEN
+ DO 60 J = 1,N
+ IF (X(J).NE.ZERO) THEN
+ TEMP = ALPHA*X(J)
+ K = KK
+ DO 50 I = J,N
+ AP(K) = AP(K) + X(I)*TEMP
+ K = K + 1
+ 50 CONTINUE
+ END IF
+ KK = KK + N - J + 1
+ 60 CONTINUE
+ ELSE
+ JX = KX
+ DO 80 J = 1,N
+ IF (X(JX).NE.ZERO) THEN
+ TEMP = ALPHA*X(JX)
+ IX = JX
+ DO 70 K = KK,KK + N - J
+ AP(K) = AP(K) + X(IX)*TEMP
+ IX = IX + INCX
+ 70 CONTINUE
+ END IF
+ JX = JX + INCX
+ KK = KK + N - J + 1
+ 80 CONTINUE
+ END IF
+ END IF
+*
+ RETURN
+*
+* End of SSPR .
+*
+ END
diff --git a/blas/sspr2.f b/blas/sspr2.f
new file mode 100644
index 000000000..cd27c734b
--- /dev/null
+++ b/blas/sspr2.f
@@ -0,0 +1,233 @@
+ SUBROUTINE SSPR2(UPLO,N,ALPHA,X,INCX,Y,INCY,AP)
+* .. Scalar Arguments ..
+ REAL ALPHA
+ INTEGER INCX,INCY,N
+ CHARACTER UPLO
+* ..
+* .. Array Arguments ..
+ REAL AP(*),X(*),Y(*)
+* ..
+*
+* Purpose
+* =======
+*
+* SSPR2 performs the symmetric rank 2 operation
+*
+* A := alpha*x*y' + alpha*y*x' + A,
+*
+* where alpha is a scalar, x and y are n element vectors and A is an
+* n by n symmetric matrix, supplied in packed form.
+*
+* Arguments
+* ==========
+*
+* UPLO - CHARACTER*1.
+* On entry, UPLO specifies whether the upper or lower
+* triangular part of the matrix A is supplied in the packed
+* array AP as follows:
+*
+* UPLO = 'U' or 'u' The upper triangular part of A is
+* supplied in AP.
+*
+* UPLO = 'L' or 'l' The lower triangular part of A is
+* supplied in AP.
+*
+* Unchanged on exit.
+*
+* N - INTEGER.
+* On entry, N specifies the order of the matrix A.
+* N must be at least zero.
+* Unchanged on exit.
+*
+* ALPHA - REAL .
+* On entry, ALPHA specifies the scalar alpha.
+* Unchanged on exit.
+*
+* X - REAL array of dimension at least
+* ( 1 + ( n - 1 )*abs( INCX ) ).
+* Before entry, the incremented array X must contain the n
+* element vector x.
+* Unchanged on exit.
+*
+* INCX - INTEGER.
+* On entry, INCX specifies the increment for the elements of
+* X. INCX must not be zero.
+* Unchanged on exit.
+*
+* Y - REAL array of dimension at least
+* ( 1 + ( n - 1 )*abs( INCY ) ).
+* Before entry, the incremented array Y must contain the n
+* element vector y.
+* Unchanged on exit.
+*
+* INCY - INTEGER.
+* On entry, INCY specifies the increment for the elements of
+* Y. INCY must not be zero.
+* Unchanged on exit.
+*
+* AP - REAL array of DIMENSION at least
+* ( ( n*( n + 1 ) )/2 ).
+* Before entry with UPLO = 'U' or 'u', the array AP must
+* contain the upper triangular part of the symmetric matrix
+* packed sequentially, column by column, so that AP( 1 )
+* contains a( 1, 1 ), AP( 2 ) and AP( 3 ) contain a( 1, 2 )
+* and a( 2, 2 ) respectively, and so on. On exit, the array
+* AP is overwritten by the upper triangular part of the
+* updated matrix.
+* Before entry with UPLO = 'L' or 'l', the array AP must
+* contain the lower triangular part of the symmetric matrix
+* packed sequentially, column by column, so that AP( 1 )
+* contains a( 1, 1 ), AP( 2 ) and AP( 3 ) contain a( 2, 1 )
+* and a( 3, 1 ) respectively, and so on. On exit, the array
+* AP is overwritten by the lower triangular part of the
+* updated matrix.
+*
+* Further Details
+* ===============
+*
+* Level 2 Blas routine.
+*
+* -- Written on 22-October-1986.
+* Jack Dongarra, Argonne National Lab.
+* Jeremy Du Croz, Nag Central Office.
+* Sven Hammarling, Nag Central Office.
+* Richard Hanson, Sandia National Labs.
+*
+* =====================================================================
+*
+* .. Parameters ..
+ REAL ZERO
+ PARAMETER (ZERO=0.0E+0)
+* ..
+* .. Local Scalars ..
+ REAL TEMP1,TEMP2
+ INTEGER I,INFO,IX,IY,J,JX,JY,K,KK,KX,KY
+* ..
+* .. External Functions ..
+ LOGICAL LSAME
+ EXTERNAL LSAME
+* ..
+* .. External Subroutines ..
+ EXTERNAL XERBLA
+* ..
+*
+* Test the input parameters.
+*
+ INFO = 0
+ IF (.NOT.LSAME(UPLO,'U') .AND. .NOT.LSAME(UPLO,'L')) THEN
+ INFO = 1
+ ELSE IF (N.LT.0) THEN
+ INFO = 2
+ ELSE IF (INCX.EQ.0) THEN
+ INFO = 5
+ ELSE IF (INCY.EQ.0) THEN
+ INFO = 7
+ END IF
+ IF (INFO.NE.0) THEN
+ CALL XERBLA('SSPR2 ',INFO)
+ RETURN
+ END IF
+*
+* Quick return if possible.
+*
+ IF ((N.EQ.0) .OR. (ALPHA.EQ.ZERO)) RETURN
+*
+* Set up the start points in X and Y if the increments are not both
+* unity.
+*
+ IF ((INCX.NE.1) .OR. (INCY.NE.1)) THEN
+ IF (INCX.GT.0) THEN
+ KX = 1
+ ELSE
+ KX = 1 - (N-1)*INCX
+ END IF
+ IF (INCY.GT.0) THEN
+ KY = 1
+ ELSE
+ KY = 1 - (N-1)*INCY
+ END IF
+ JX = KX
+ JY = KY
+ END IF
+*
+* Start the operations. In this version the elements of the array AP
+* are accessed sequentially with one pass through AP.
+*
+ KK = 1
+ IF (LSAME(UPLO,'U')) THEN
+*
+* Form A when upper triangle is stored in AP.
+*
+ IF ((INCX.EQ.1) .AND. (INCY.EQ.1)) THEN
+ DO 20 J = 1,N
+ IF ((X(J).NE.ZERO) .OR. (Y(J).NE.ZERO)) THEN
+ TEMP1 = ALPHA*Y(J)
+ TEMP2 = ALPHA*X(J)
+ K = KK
+ DO 10 I = 1,J
+ AP(K) = AP(K) + X(I)*TEMP1 + Y(I)*TEMP2
+ K = K + 1
+ 10 CONTINUE
+ END IF
+ KK = KK + J
+ 20 CONTINUE
+ ELSE
+ DO 40 J = 1,N
+ IF ((X(JX).NE.ZERO) .OR. (Y(JY).NE.ZERO)) THEN
+ TEMP1 = ALPHA*Y(JY)
+ TEMP2 = ALPHA*X(JX)
+ IX = KX
+ IY = KY
+ DO 30 K = KK,KK + J - 1
+ AP(K) = AP(K) + X(IX)*TEMP1 + Y(IY)*TEMP2
+ IX = IX + INCX
+ IY = IY + INCY
+ 30 CONTINUE
+ END IF
+ JX = JX + INCX
+ JY = JY + INCY
+ KK = KK + J
+ 40 CONTINUE
+ END IF
+ ELSE
+*
+* Form A when lower triangle is stored in AP.
+*
+ IF ((INCX.EQ.1) .AND. (INCY.EQ.1)) THEN
+ DO 60 J = 1,N
+ IF ((X(J).NE.ZERO) .OR. (Y(J).NE.ZERO)) THEN
+ TEMP1 = ALPHA*Y(J)
+ TEMP2 = ALPHA*X(J)
+ K = KK
+ DO 50 I = J,N
+ AP(K) = AP(K) + X(I)*TEMP1 + Y(I)*TEMP2
+ K = K + 1
+ 50 CONTINUE
+ END IF
+ KK = KK + N - J + 1
+ 60 CONTINUE
+ ELSE
+ DO 80 J = 1,N
+ IF ((X(JX).NE.ZERO) .OR. (Y(JY).NE.ZERO)) THEN
+ TEMP1 = ALPHA*Y(JY)
+ TEMP2 = ALPHA*X(JX)
+ IX = JX
+ IY = JY
+ DO 70 K = KK,KK + N - J
+ AP(K) = AP(K) + X(IX)*TEMP1 + Y(IY)*TEMP2
+ IX = IX + INCX
+ IY = IY + INCY
+ 70 CONTINUE
+ END IF
+ JX = JX + INCX
+ JY = JY + INCY
+ KK = KK + N - J + 1
+ 80 CONTINUE
+ END IF
+ END IF
+*
+ RETURN
+*
+* End of SSPR2 .
+*
+ END
diff --git a/blas/stbmv.f b/blas/stbmv.f
new file mode 100644
index 000000000..c0b8f1136
--- /dev/null
+++ b/blas/stbmv.f
@@ -0,0 +1,335 @@
+ SUBROUTINE STBMV(UPLO,TRANS,DIAG,N,K,A,LDA,X,INCX)
+* .. Scalar Arguments ..
+ INTEGER INCX,K,LDA,N
+ CHARACTER DIAG,TRANS,UPLO
+* ..
+* .. Array Arguments ..
+ REAL A(LDA,*),X(*)
+* ..
+*
+* Purpose
+* =======
+*
+* STBMV performs one of the matrix-vector operations
+*
+* x := A*x, or x := A'*x,
+*
+* where x is an n element vector and A is an n by n unit, or non-unit,
+* upper or lower triangular band matrix, with ( k + 1 ) diagonals.
+*
+* Arguments
+* ==========
+*
+* UPLO - CHARACTER*1.
+* On entry, UPLO specifies whether the matrix is an upper or
+* lower triangular matrix as follows:
+*
+* UPLO = 'U' or 'u' A is an upper triangular matrix.
+*
+* UPLO = 'L' or 'l' A is a lower triangular matrix.
+*
+* Unchanged on exit.
+*
+* TRANS - CHARACTER*1.
+* On entry, TRANS specifies the operation to be performed as
+* follows:
+*
+* TRANS = 'N' or 'n' x := A*x.
+*
+* TRANS = 'T' or 't' x := A'*x.
+*
+* TRANS = 'C' or 'c' x := A'*x.
+*
+* Unchanged on exit.
+*
+* DIAG - CHARACTER*1.
+* On entry, DIAG specifies whether or not A is unit
+* triangular as follows:
+*
+* DIAG = 'U' or 'u' A is assumed to be unit triangular.
+*
+* DIAG = 'N' or 'n' A is not assumed to be unit
+* triangular.
+*
+* Unchanged on exit.
+*
+* N - INTEGER.
+* On entry, N specifies the order of the matrix A.
+* N must be at least zero.
+* Unchanged on exit.
+*
+* K - INTEGER.
+* On entry with UPLO = 'U' or 'u', K specifies the number of
+* super-diagonals of the matrix A.
+* On entry with UPLO = 'L' or 'l', K specifies the number of
+* sub-diagonals of the matrix A.
+* K must satisfy 0 .le. K.
+* Unchanged on exit.
+*
+* A - REAL array of DIMENSION ( LDA, n ).
+* Before entry with UPLO = 'U' or 'u', the leading ( k + 1 )
+* by n part of the array A must contain the upper triangular
+* band part of the matrix of coefficients, supplied column by
+* column, with the leading diagonal of the matrix in row
+* ( k + 1 ) of the array, the first super-diagonal starting at
+* position 2 in row k, and so on. The top left k by k triangle
+* of the array A is not referenced.
+* The following program segment will transfer an upper
+* triangular band matrix from conventional full matrix storage
+* to band storage:
+*
+* DO 20, J = 1, N
+* M = K + 1 - J
+* DO 10, I = MAX( 1, J - K ), J
+* A( M + I, J ) = matrix( I, J )
+* 10 CONTINUE
+* 20 CONTINUE
+*
+* Before entry with UPLO = 'L' or 'l', the leading ( k + 1 )
+* by n part of the array A must contain the lower triangular
+* band part of the matrix of coefficients, supplied column by
+* column, with the leading diagonal of the matrix in row 1 of
+* the array, the first sub-diagonal starting at position 1 in
+* row 2, and so on. The bottom right k by k triangle of the
+* array A is not referenced.
+* The following program segment will transfer a lower
+* triangular band matrix from conventional full matrix storage
+* to band storage:
+*
+* DO 20, J = 1, N
+* M = 1 - J
+* DO 10, I = J, MIN( N, J + K )
+* A( M + I, J ) = matrix( I, J )
+* 10 CONTINUE
+* 20 CONTINUE
+*
+* Note that when DIAG = 'U' or 'u' the elements of the array A
+* corresponding to the diagonal elements of the matrix are not
+* referenced, but are assumed to be unity.
+* Unchanged on exit.
+*
+* LDA - INTEGER.
+* On entry, LDA specifies the first dimension of A as declared
+* in the calling (sub) program. LDA must be at least
+* ( k + 1 ).
+* Unchanged on exit.
+*
+* X - REAL array of dimension at least
+* ( 1 + ( n - 1 )*abs( INCX ) ).
+* Before entry, the incremented array X must contain the n
+* element vector x. On exit, X is overwritten with the
+* tranformed vector x.
+*
+* INCX - INTEGER.
+* On entry, INCX specifies the increment for the elements of
+* X. INCX must not be zero.
+* Unchanged on exit.
+*
+* Further Details
+* ===============
+*
+* Level 2 Blas routine.
+*
+* -- Written on 22-October-1986.
+* Jack Dongarra, Argonne National Lab.
+* Jeremy Du Croz, Nag Central Office.
+* Sven Hammarling, Nag Central Office.
+* Richard Hanson, Sandia National Labs.
+*
+* =====================================================================
+*
+* .. Parameters ..
+ REAL ZERO
+ PARAMETER (ZERO=0.0E+0)
+* ..
+* .. Local Scalars ..
+ REAL TEMP
+ INTEGER I,INFO,IX,J,JX,KPLUS1,KX,L
+ LOGICAL NOUNIT
+* ..
+* .. External Functions ..
+ LOGICAL LSAME
+ EXTERNAL LSAME
+* ..
+* .. External Subroutines ..
+ EXTERNAL XERBLA
+* ..
+* .. Intrinsic Functions ..
+ INTRINSIC MAX,MIN
+* ..
+*
+* Test the input parameters.
+*
+ INFO = 0
+ IF (.NOT.LSAME(UPLO,'U') .AND. .NOT.LSAME(UPLO,'L')) THEN
+ INFO = 1
+ ELSE IF (.NOT.LSAME(TRANS,'N') .AND. .NOT.LSAME(TRANS,'T') .AND.
+ + .NOT.LSAME(TRANS,'C')) THEN
+ INFO = 2
+ ELSE IF (.NOT.LSAME(DIAG,'U') .AND. .NOT.LSAME(DIAG,'N')) THEN
+ INFO = 3
+ ELSE IF (N.LT.0) THEN
+ INFO = 4
+ ELSE IF (K.LT.0) THEN
+ INFO = 5
+ ELSE IF (LDA.LT. (K+1)) THEN
+ INFO = 7
+ ELSE IF (INCX.EQ.0) THEN
+ INFO = 9
+ END IF
+ IF (INFO.NE.0) THEN
+ CALL XERBLA('STBMV ',INFO)
+ RETURN
+ END IF
+*
+* Quick return if possible.
+*
+ IF (N.EQ.0) RETURN
+*
+ NOUNIT = LSAME(DIAG,'N')
+*
+* Set up the start point in X if the increment is not unity. This
+* will be ( N - 1 )*INCX too small for descending loops.
+*
+ IF (INCX.LE.0) THEN
+ KX = 1 - (N-1)*INCX
+ ELSE IF (INCX.NE.1) THEN
+ KX = 1
+ END IF
+*
+* Start the operations. In this version the elements of A are
+* accessed sequentially with one pass through A.
+*
+ IF (LSAME(TRANS,'N')) THEN
+*
+* Form x := A*x.
+*
+ IF (LSAME(UPLO,'U')) THEN
+ KPLUS1 = K + 1
+ IF (INCX.EQ.1) THEN
+ DO 20 J = 1,N
+ IF (X(J).NE.ZERO) THEN
+ TEMP = X(J)
+ L = KPLUS1 - J
+ DO 10 I = MAX(1,J-K),J - 1
+ X(I) = X(I) + TEMP*A(L+I,J)
+ 10 CONTINUE
+ IF (NOUNIT) X(J) = X(J)*A(KPLUS1,J)
+ END IF
+ 20 CONTINUE
+ ELSE
+ JX = KX
+ DO 40 J = 1,N
+ IF (X(JX).NE.ZERO) THEN
+ TEMP = X(JX)
+ IX = KX
+ L = KPLUS1 - J
+ DO 30 I = MAX(1,J-K),J - 1
+ X(IX) = X(IX) + TEMP*A(L+I,J)
+ IX = IX + INCX
+ 30 CONTINUE
+ IF (NOUNIT) X(JX) = X(JX)*A(KPLUS1,J)
+ END IF
+ JX = JX + INCX
+ IF (J.GT.K) KX = KX + INCX
+ 40 CONTINUE
+ END IF
+ ELSE
+ IF (INCX.EQ.1) THEN
+ DO 60 J = N,1,-1
+ IF (X(J).NE.ZERO) THEN
+ TEMP = X(J)
+ L = 1 - J
+ DO 50 I = MIN(N,J+K),J + 1,-1
+ X(I) = X(I) + TEMP*A(L+I,J)
+ 50 CONTINUE
+ IF (NOUNIT) X(J) = X(J)*A(1,J)
+ END IF
+ 60 CONTINUE
+ ELSE
+ KX = KX + (N-1)*INCX
+ JX = KX
+ DO 80 J = N,1,-1
+ IF (X(JX).NE.ZERO) THEN
+ TEMP = X(JX)
+ IX = KX
+ L = 1 - J
+ DO 70 I = MIN(N,J+K),J + 1,-1
+ X(IX) = X(IX) + TEMP*A(L+I,J)
+ IX = IX - INCX
+ 70 CONTINUE
+ IF (NOUNIT) X(JX) = X(JX)*A(1,J)
+ END IF
+ JX = JX - INCX
+ IF ((N-J).GE.K) KX = KX - INCX
+ 80 CONTINUE
+ END IF
+ END IF
+ ELSE
+*
+* Form x := A'*x.
+*
+ IF (LSAME(UPLO,'U')) THEN
+ KPLUS1 = K + 1
+ IF (INCX.EQ.1) THEN
+ DO 100 J = N,1,-1
+ TEMP = X(J)
+ L = KPLUS1 - J
+ IF (NOUNIT) TEMP = TEMP*A(KPLUS1,J)
+ DO 90 I = J - 1,MAX(1,J-K),-1
+ TEMP = TEMP + A(L+I,J)*X(I)
+ 90 CONTINUE
+ X(J) = TEMP
+ 100 CONTINUE
+ ELSE
+ KX = KX + (N-1)*INCX
+ JX = KX
+ DO 120 J = N,1,-1
+ TEMP = X(JX)
+ KX = KX - INCX
+ IX = KX
+ L = KPLUS1 - J
+ IF (NOUNIT) TEMP = TEMP*A(KPLUS1,J)
+ DO 110 I = J - 1,MAX(1,J-K),-1
+ TEMP = TEMP + A(L+I,J)*X(IX)
+ IX = IX - INCX
+ 110 CONTINUE
+ X(JX) = TEMP
+ JX = JX - INCX
+ 120 CONTINUE
+ END IF
+ ELSE
+ IF (INCX.EQ.1) THEN
+ DO 140 J = 1,N
+ TEMP = X(J)
+ L = 1 - J
+ IF (NOUNIT) TEMP = TEMP*A(1,J)
+ DO 130 I = J + 1,MIN(N,J+K)
+ TEMP = TEMP + A(L+I,J)*X(I)
+ 130 CONTINUE
+ X(J) = TEMP
+ 140 CONTINUE
+ ELSE
+ JX = KX
+ DO 160 J = 1,N
+ TEMP = X(JX)
+ KX = KX + INCX
+ IX = KX
+ L = 1 - J
+ IF (NOUNIT) TEMP = TEMP*A(1,J)
+ DO 150 I = J + 1,MIN(N,J+K)
+ TEMP = TEMP + A(L+I,J)*X(IX)
+ IX = IX + INCX
+ 150 CONTINUE
+ X(JX) = TEMP
+ JX = JX + INCX
+ 160 CONTINUE
+ END IF
+ END IF
+ END IF
+*
+ RETURN
+*
+* End of STBMV .
+*
+ END
diff --git a/blas/stpmv.f b/blas/stpmv.f
new file mode 100644
index 000000000..71ea49a36
--- /dev/null
+++ b/blas/stpmv.f
@@ -0,0 +1,293 @@
+ SUBROUTINE STPMV(UPLO,TRANS,DIAG,N,AP,X,INCX)
+* .. Scalar Arguments ..
+ INTEGER INCX,N
+ CHARACTER DIAG,TRANS,UPLO
+* ..
+* .. Array Arguments ..
+ REAL AP(*),X(*)
+* ..
+*
+* Purpose
+* =======
+*
+* STPMV performs one of the matrix-vector operations
+*
+* x := A*x, or x := A'*x,
+*
+* where x is an n element vector and A is an n by n unit, or non-unit,
+* upper or lower triangular matrix, supplied in packed form.
+*
+* Arguments
+* ==========
+*
+* UPLO - CHARACTER*1.
+* On entry, UPLO specifies whether the matrix is an upper or
+* lower triangular matrix as follows:
+*
+* UPLO = 'U' or 'u' A is an upper triangular matrix.
+*
+* UPLO = 'L' or 'l' A is a lower triangular matrix.
+*
+* Unchanged on exit.
+*
+* TRANS - CHARACTER*1.
+* On entry, TRANS specifies the operation to be performed as
+* follows:
+*
+* TRANS = 'N' or 'n' x := A*x.
+*
+* TRANS = 'T' or 't' x := A'*x.
+*
+* TRANS = 'C' or 'c' x := A'*x.
+*
+* Unchanged on exit.
+*
+* DIAG - CHARACTER*1.
+* On entry, DIAG specifies whether or not A is unit
+* triangular as follows:
+*
+* DIAG = 'U' or 'u' A is assumed to be unit triangular.
+*
+* DIAG = 'N' or 'n' A is not assumed to be unit
+* triangular.
+*
+* Unchanged on exit.
+*
+* N - INTEGER.
+* On entry, N specifies the order of the matrix A.
+* N must be at least zero.
+* Unchanged on exit.
+*
+* AP - REAL array of DIMENSION at least
+* ( ( n*( n + 1 ) )/2 ).
+* Before entry with UPLO = 'U' or 'u', the array AP must
+* contain the upper triangular matrix packed sequentially,
+* column by column, so that AP( 1 ) contains a( 1, 1 ),
+* AP( 2 ) and AP( 3 ) contain a( 1, 2 ) and a( 2, 2 )
+* respectively, and so on.
+* Before entry with UPLO = 'L' or 'l', the array AP must
+* contain the lower triangular matrix packed sequentially,
+* column by column, so that AP( 1 ) contains a( 1, 1 ),
+* AP( 2 ) and AP( 3 ) contain a( 2, 1 ) and a( 3, 1 )
+* respectively, and so on.
+* Note that when DIAG = 'U' or 'u', the diagonal elements of
+* A are not referenced, but are assumed to be unity.
+* Unchanged on exit.
+*
+* X - REAL array of dimension at least
+* ( 1 + ( n - 1 )*abs( INCX ) ).
+* Before entry, the incremented array X must contain the n
+* element vector x. On exit, X is overwritten with the
+* tranformed vector x.
+*
+* INCX - INTEGER.
+* On entry, INCX specifies the increment for the elements of
+* X. INCX must not be zero.
+* Unchanged on exit.
+*
+* Further Details
+* ===============
+*
+* Level 2 Blas routine.
+*
+* -- Written on 22-October-1986.
+* Jack Dongarra, Argonne National Lab.
+* Jeremy Du Croz, Nag Central Office.
+* Sven Hammarling, Nag Central Office.
+* Richard Hanson, Sandia National Labs.
+*
+* =====================================================================
+*
+* .. Parameters ..
+ REAL ZERO
+ PARAMETER (ZERO=0.0E+0)
+* ..
+* .. Local Scalars ..
+ REAL TEMP
+ INTEGER I,INFO,IX,J,JX,K,KK,KX
+ LOGICAL NOUNIT
+* ..
+* .. External Functions ..
+ LOGICAL LSAME
+ EXTERNAL LSAME
+* ..
+* .. External Subroutines ..
+ EXTERNAL XERBLA
+* ..
+*
+* Test the input parameters.
+*
+ INFO = 0
+ IF (.NOT.LSAME(UPLO,'U') .AND. .NOT.LSAME(UPLO,'L')) THEN
+ INFO = 1
+ ELSE IF (.NOT.LSAME(TRANS,'N') .AND. .NOT.LSAME(TRANS,'T') .AND.
+ + .NOT.LSAME(TRANS,'C')) THEN
+ INFO = 2
+ ELSE IF (.NOT.LSAME(DIAG,'U') .AND. .NOT.LSAME(DIAG,'N')) THEN
+ INFO = 3
+ ELSE IF (N.LT.0) THEN
+ INFO = 4
+ ELSE IF (INCX.EQ.0) THEN
+ INFO = 7
+ END IF
+ IF (INFO.NE.0) THEN
+ CALL XERBLA('STPMV ',INFO)
+ RETURN
+ END IF
+*
+* Quick return if possible.
+*
+ IF (N.EQ.0) RETURN
+*
+ NOUNIT = LSAME(DIAG,'N')
+*
+* Set up the start point in X if the increment is not unity. This
+* will be ( N - 1 )*INCX too small for descending loops.
+*
+ IF (INCX.LE.0) THEN
+ KX = 1 - (N-1)*INCX
+ ELSE IF (INCX.NE.1) THEN
+ KX = 1
+ END IF
+*
+* Start the operations. In this version the elements of AP are
+* accessed sequentially with one pass through AP.
+*
+ IF (LSAME(TRANS,'N')) THEN
+*
+* Form x:= A*x.
+*
+ IF (LSAME(UPLO,'U')) THEN
+ KK = 1
+ IF (INCX.EQ.1) THEN
+ DO 20 J = 1,N
+ IF (X(J).NE.ZERO) THEN
+ TEMP = X(J)
+ K = KK
+ DO 10 I = 1,J - 1
+ X(I) = X(I) + TEMP*AP(K)
+ K = K + 1
+ 10 CONTINUE
+ IF (NOUNIT) X(J) = X(J)*AP(KK+J-1)
+ END IF
+ KK = KK + J
+ 20 CONTINUE
+ ELSE
+ JX = KX
+ DO 40 J = 1,N
+ IF (X(JX).NE.ZERO) THEN
+ TEMP = X(JX)
+ IX = KX
+ DO 30 K = KK,KK + J - 2
+ X(IX) = X(IX) + TEMP*AP(K)
+ IX = IX + INCX
+ 30 CONTINUE
+ IF (NOUNIT) X(JX) = X(JX)*AP(KK+J-1)
+ END IF
+ JX = JX + INCX
+ KK = KK + J
+ 40 CONTINUE
+ END IF
+ ELSE
+ KK = (N* (N+1))/2
+ IF (INCX.EQ.1) THEN
+ DO 60 J = N,1,-1
+ IF (X(J).NE.ZERO) THEN
+ TEMP = X(J)
+ K = KK
+ DO 50 I = N,J + 1,-1
+ X(I) = X(I) + TEMP*AP(K)
+ K = K - 1
+ 50 CONTINUE
+ IF (NOUNIT) X(J) = X(J)*AP(KK-N+J)
+ END IF
+ KK = KK - (N-J+1)
+ 60 CONTINUE
+ ELSE
+ KX = KX + (N-1)*INCX
+ JX = KX
+ DO 80 J = N,1,-1
+ IF (X(JX).NE.ZERO) THEN
+ TEMP = X(JX)
+ IX = KX
+ DO 70 K = KK,KK - (N- (J+1)),-1
+ X(IX) = X(IX) + TEMP*AP(K)
+ IX = IX - INCX
+ 70 CONTINUE
+ IF (NOUNIT) X(JX) = X(JX)*AP(KK-N+J)
+ END IF
+ JX = JX - INCX
+ KK = KK - (N-J+1)
+ 80 CONTINUE
+ END IF
+ END IF
+ ELSE
+*
+* Form x := A'*x.
+*
+ IF (LSAME(UPLO,'U')) THEN
+ KK = (N* (N+1))/2
+ IF (INCX.EQ.1) THEN
+ DO 100 J = N,1,-1
+ TEMP = X(J)
+ IF (NOUNIT) TEMP = TEMP*AP(KK)
+ K = KK - 1
+ DO 90 I = J - 1,1,-1
+ TEMP = TEMP + AP(K)*X(I)
+ K = K - 1
+ 90 CONTINUE
+ X(J) = TEMP
+ KK = KK - J
+ 100 CONTINUE
+ ELSE
+ JX = KX + (N-1)*INCX
+ DO 120 J = N,1,-1
+ TEMP = X(JX)
+ IX = JX
+ IF (NOUNIT) TEMP = TEMP*AP(KK)
+ DO 110 K = KK - 1,KK - J + 1,-1
+ IX = IX - INCX
+ TEMP = TEMP + AP(K)*X(IX)
+ 110 CONTINUE
+ X(JX) = TEMP
+ JX = JX - INCX
+ KK = KK - J
+ 120 CONTINUE
+ END IF
+ ELSE
+ KK = 1
+ IF (INCX.EQ.1) THEN
+ DO 140 J = 1,N
+ TEMP = X(J)
+ IF (NOUNIT) TEMP = TEMP*AP(KK)
+ K = KK + 1
+ DO 130 I = J + 1,N
+ TEMP = TEMP + AP(K)*X(I)
+ K = K + 1
+ 130 CONTINUE
+ X(J) = TEMP
+ KK = KK + (N-J+1)
+ 140 CONTINUE
+ ELSE
+ JX = KX
+ DO 160 J = 1,N
+ TEMP = X(JX)
+ IX = JX
+ IF (NOUNIT) TEMP = TEMP*AP(KK)
+ DO 150 K = KK + 1,KK + N - J
+ IX = IX + INCX
+ TEMP = TEMP + AP(K)*X(IX)
+ 150 CONTINUE
+ X(JX) = TEMP
+ JX = JX + INCX
+ KK = KK + (N-J+1)
+ 160 CONTINUE
+ END IF
+ END IF
+ END IF
+*
+ RETURN
+*
+* End of STPMV .
+*
+ END
diff --git a/blas/stpsv.f b/blas/stpsv.f
new file mode 100644
index 000000000..7d95efbde
--- /dev/null
+++ b/blas/stpsv.f
@@ -0,0 +1,296 @@
+ SUBROUTINE STPSV(UPLO,TRANS,DIAG,N,AP,X,INCX)
+* .. Scalar Arguments ..
+ INTEGER INCX,N
+ CHARACTER DIAG,TRANS,UPLO
+* ..
+* .. Array Arguments ..
+ REAL AP(*),X(*)
+* ..
+*
+* Purpose
+* =======
+*
+* STPSV solves one of the systems of equations
+*
+* A*x = b, or A'*x = b,
+*
+* where b and x are n element vectors and A is an n by n unit, or
+* non-unit, upper or lower triangular matrix, supplied in packed form.
+*
+* No test for singularity or near-singularity is included in this
+* routine. Such tests must be performed before calling this routine.
+*
+* Arguments
+* ==========
+*
+* UPLO - CHARACTER*1.
+* On entry, UPLO specifies whether the matrix is an upper or
+* lower triangular matrix as follows:
+*
+* UPLO = 'U' or 'u' A is an upper triangular matrix.
+*
+* UPLO = 'L' or 'l' A is a lower triangular matrix.
+*
+* Unchanged on exit.
+*
+* TRANS - CHARACTER*1.
+* On entry, TRANS specifies the equations to be solved as
+* follows:
+*
+* TRANS = 'N' or 'n' A*x = b.
+*
+* TRANS = 'T' or 't' A'*x = b.
+*
+* TRANS = 'C' or 'c' A'*x = b.
+*
+* Unchanged on exit.
+*
+* DIAG - CHARACTER*1.
+* On entry, DIAG specifies whether or not A is unit
+* triangular as follows:
+*
+* DIAG = 'U' or 'u' A is assumed to be unit triangular.
+*
+* DIAG = 'N' or 'n' A is not assumed to be unit
+* triangular.
+*
+* Unchanged on exit.
+*
+* N - INTEGER.
+* On entry, N specifies the order of the matrix A.
+* N must be at least zero.
+* Unchanged on exit.
+*
+* AP - REAL array of DIMENSION at least
+* ( ( n*( n + 1 ) )/2 ).
+* Before entry with UPLO = 'U' or 'u', the array AP must
+* contain the upper triangular matrix packed sequentially,
+* column by column, so that AP( 1 ) contains a( 1, 1 ),
+* AP( 2 ) and AP( 3 ) contain a( 1, 2 ) and a( 2, 2 )
+* respectively, and so on.
+* Before entry with UPLO = 'L' or 'l', the array AP must
+* contain the lower triangular matrix packed sequentially,
+* column by column, so that AP( 1 ) contains a( 1, 1 ),
+* AP( 2 ) and AP( 3 ) contain a( 2, 1 ) and a( 3, 1 )
+* respectively, and so on.
+* Note that when DIAG = 'U' or 'u', the diagonal elements of
+* A are not referenced, but are assumed to be unity.
+* Unchanged on exit.
+*
+* X - REAL array of dimension at least
+* ( 1 + ( n - 1 )*abs( INCX ) ).
+* Before entry, the incremented array X must contain the n
+* element right-hand side vector b. On exit, X is overwritten
+* with the solution vector x.
+*
+* INCX - INTEGER.
+* On entry, INCX specifies the increment for the elements of
+* X. INCX must not be zero.
+* Unchanged on exit.
+*
+* Further Details
+* ===============
+*
+* Level 2 Blas routine.
+*
+* -- Written on 22-October-1986.
+* Jack Dongarra, Argonne National Lab.
+* Jeremy Du Croz, Nag Central Office.
+* Sven Hammarling, Nag Central Office.
+* Richard Hanson, Sandia National Labs.
+*
+* =====================================================================
+*
+* .. Parameters ..
+ REAL ZERO
+ PARAMETER (ZERO=0.0E+0)
+* ..
+* .. Local Scalars ..
+ REAL TEMP
+ INTEGER I,INFO,IX,J,JX,K,KK,KX
+ LOGICAL NOUNIT
+* ..
+* .. External Functions ..
+ LOGICAL LSAME
+ EXTERNAL LSAME
+* ..
+* .. External Subroutines ..
+ EXTERNAL XERBLA
+* ..
+*
+* Test the input parameters.
+*
+ INFO = 0
+ IF (.NOT.LSAME(UPLO,'U') .AND. .NOT.LSAME(UPLO,'L')) THEN
+ INFO = 1
+ ELSE IF (.NOT.LSAME(TRANS,'N') .AND. .NOT.LSAME(TRANS,'T') .AND.
+ + .NOT.LSAME(TRANS,'C')) THEN
+ INFO = 2
+ ELSE IF (.NOT.LSAME(DIAG,'U') .AND. .NOT.LSAME(DIAG,'N')) THEN
+ INFO = 3
+ ELSE IF (N.LT.0) THEN
+ INFO = 4
+ ELSE IF (INCX.EQ.0) THEN
+ INFO = 7
+ END IF
+ IF (INFO.NE.0) THEN
+ CALL XERBLA('STPSV ',INFO)
+ RETURN
+ END IF
+*
+* Quick return if possible.
+*
+ IF (N.EQ.0) RETURN
+*
+ NOUNIT = LSAME(DIAG,'N')
+*
+* Set up the start point in X if the increment is not unity. This
+* will be ( N - 1 )*INCX too small for descending loops.
+*
+ IF (INCX.LE.0) THEN
+ KX = 1 - (N-1)*INCX
+ ELSE IF (INCX.NE.1) THEN
+ KX = 1
+ END IF
+*
+* Start the operations. In this version the elements of AP are
+* accessed sequentially with one pass through AP.
+*
+ IF (LSAME(TRANS,'N')) THEN
+*
+* Form x := inv( A )*x.
+*
+ IF (LSAME(UPLO,'U')) THEN
+ KK = (N* (N+1))/2
+ IF (INCX.EQ.1) THEN
+ DO 20 J = N,1,-1
+ IF (X(J).NE.ZERO) THEN
+ IF (NOUNIT) X(J) = X(J)/AP(KK)
+ TEMP = X(J)
+ K = KK - 1
+ DO 10 I = J - 1,1,-1
+ X(I) = X(I) - TEMP*AP(K)
+ K = K - 1
+ 10 CONTINUE
+ END IF
+ KK = KK - J
+ 20 CONTINUE
+ ELSE
+ JX = KX + (N-1)*INCX
+ DO 40 J = N,1,-1
+ IF (X(JX).NE.ZERO) THEN
+ IF (NOUNIT) X(JX) = X(JX)/AP(KK)
+ TEMP = X(JX)
+ IX = JX
+ DO 30 K = KK - 1,KK - J + 1,-1
+ IX = IX - INCX
+ X(IX) = X(IX) - TEMP*AP(K)
+ 30 CONTINUE
+ END IF
+ JX = JX - INCX
+ KK = KK - J
+ 40 CONTINUE
+ END IF
+ ELSE
+ KK = 1
+ IF (INCX.EQ.1) THEN
+ DO 60 J = 1,N
+ IF (X(J).NE.ZERO) THEN
+ IF (NOUNIT) X(J) = X(J)/AP(KK)
+ TEMP = X(J)
+ K = KK + 1
+ DO 50 I = J + 1,N
+ X(I) = X(I) - TEMP*AP(K)
+ K = K + 1
+ 50 CONTINUE
+ END IF
+ KK = KK + (N-J+1)
+ 60 CONTINUE
+ ELSE
+ JX = KX
+ DO 80 J = 1,N
+ IF (X(JX).NE.ZERO) THEN
+ IF (NOUNIT) X(JX) = X(JX)/AP(KK)
+ TEMP = X(JX)
+ IX = JX
+ DO 70 K = KK + 1,KK + N - J
+ IX = IX + INCX
+ X(IX) = X(IX) - TEMP*AP(K)
+ 70 CONTINUE
+ END IF
+ JX = JX + INCX
+ KK = KK + (N-J+1)
+ 80 CONTINUE
+ END IF
+ END IF
+ ELSE
+*
+* Form x := inv( A' )*x.
+*
+ IF (LSAME(UPLO,'U')) THEN
+ KK = 1
+ IF (INCX.EQ.1) THEN
+ DO 100 J = 1,N
+ TEMP = X(J)
+ K = KK
+ DO 90 I = 1,J - 1
+ TEMP = TEMP - AP(K)*X(I)
+ K = K + 1
+ 90 CONTINUE
+ IF (NOUNIT) TEMP = TEMP/AP(KK+J-1)
+ X(J) = TEMP
+ KK = KK + J
+ 100 CONTINUE
+ ELSE
+ JX = KX
+ DO 120 J = 1,N
+ TEMP = X(JX)
+ IX = KX
+ DO 110 K = KK,KK + J - 2
+ TEMP = TEMP - AP(K)*X(IX)
+ IX = IX + INCX
+ 110 CONTINUE
+ IF (NOUNIT) TEMP = TEMP/AP(KK+J-1)
+ X(JX) = TEMP
+ JX = JX + INCX
+ KK = KK + J
+ 120 CONTINUE
+ END IF
+ ELSE
+ KK = (N* (N+1))/2
+ IF (INCX.EQ.1) THEN
+ DO 140 J = N,1,-1
+ TEMP = X(J)
+ K = KK
+ DO 130 I = N,J + 1,-1
+ TEMP = TEMP - AP(K)*X(I)
+ K = K - 1
+ 130 CONTINUE
+ IF (NOUNIT) TEMP = TEMP/AP(KK-N+J)
+ X(J) = TEMP
+ KK = KK - (N-J+1)
+ 140 CONTINUE
+ ELSE
+ KX = KX + (N-1)*INCX
+ JX = KX
+ DO 160 J = N,1,-1
+ TEMP = X(JX)
+ IX = KX
+ DO 150 K = KK,KK - (N- (J+1)),-1
+ TEMP = TEMP - AP(K)*X(IX)
+ IX = IX - INCX
+ 150 CONTINUE
+ IF (NOUNIT) TEMP = TEMP/AP(KK-N+J)
+ X(JX) = TEMP
+ JX = JX - INCX
+ KK = KK - (N-J+1)
+ 160 CONTINUE
+ END IF
+ END IF
+ END IF
+*
+ RETURN
+*
+* End of STPSV .
+*
+ END
diff --git a/blas/testing/CMakeLists.txt b/blas/testing/CMakeLists.txt
new file mode 100644
index 000000000..3ab8026ea
--- /dev/null
+++ b/blas/testing/CMakeLists.txt
@@ -0,0 +1,40 @@
+
+macro(ei_add_blas_test testname)
+
+ set(targetname ${testname})
+
+ set(filename ${testname}.f)
+ add_executable(${targetname} ${filename})
+
+ target_link_libraries(${targetname} eigen_blas)
+
+ if(EIGEN_STANDARD_LIBRARIES_TO_LINK_TO)
+ target_link_libraries(${targetname} ${EIGEN_STANDARD_LIBRARIES_TO_LINK_TO})
+ endif()
+
+ target_link_libraries(${targetname} ${EXTERNAL_LIBS})
+
+ add_test(${testname} "${Eigen_SOURCE_DIR}/blas/testing/runblastest.sh" "${testname}" "${Eigen_SOURCE_DIR}/blas/testing/${testname}.dat")
+ add_dependencies(buildtests ${targetname})
+
+endmacro(ei_add_blas_test)
+
+ei_add_blas_test(sblat1)
+ei_add_blas_test(sblat2)
+ei_add_blas_test(sblat3)
+
+ei_add_blas_test(dblat1)
+ei_add_blas_test(dblat2)
+ei_add_blas_test(dblat3)
+
+ei_add_blas_test(cblat1)
+ei_add_blas_test(cblat2)
+ei_add_blas_test(cblat3)
+
+ei_add_blas_test(zblat1)
+ei_add_blas_test(zblat2)
+ei_add_blas_test(zblat3)
+
+# add_custom_target(level1)
+# add_dependencies(level1 sblat1)
+
diff --git a/blas/testing/cblat1.f b/blas/testing/cblat1.f
new file mode 100644
index 000000000..a4c996fda
--- /dev/null
+++ b/blas/testing/cblat1.f
@@ -0,0 +1,681 @@
+ PROGRAM CBLAT1
+* Test program for the COMPLEX Level 1 BLAS.
+* Based upon the original BLAS test routine together with:
+* F06GAF Example Program Text
+* .. Parameters ..
+ INTEGER NOUT
+ PARAMETER (NOUT=6)
+* .. Scalars in Common ..
+ INTEGER ICASE, INCX, INCY, MODE, N
+ LOGICAL PASS
+* .. Local Scalars ..
+ REAL SFAC
+ INTEGER IC
+* .. External Subroutines ..
+ EXTERNAL CHECK1, CHECK2, HEADER
+* .. Common blocks ..
+ COMMON /COMBLA/ICASE, N, INCX, INCY, MODE, PASS
+* .. Data statements ..
+ DATA SFAC/9.765625E-4/
+* .. Executable Statements ..
+ WRITE (NOUT,99999)
+ DO 20 IC = 1, 10
+ ICASE = IC
+ CALL HEADER
+*
+* Initialize PASS, INCX, INCY, and MODE for a new case.
+* The value 9999 for INCX, INCY or MODE will appear in the
+* detailed output, if any, for cases that do not involve
+* these parameters.
+*
+ PASS = .TRUE.
+ INCX = 9999
+ INCY = 9999
+ MODE = 9999
+ IF (ICASE.LE.5) THEN
+ CALL CHECK2(SFAC)
+ ELSE IF (ICASE.GE.6) THEN
+ CALL CHECK1(SFAC)
+ END IF
+* -- Print
+ IF (PASS) WRITE (NOUT,99998)
+ 20 CONTINUE
+ STOP
+*
+99999 FORMAT (' Complex BLAS Test Program Results',/1X)
+99998 FORMAT (' ----- PASS -----')
+ END
+ SUBROUTINE HEADER
+* .. Parameters ..
+ INTEGER NOUT
+ PARAMETER (NOUT=6)
+* .. Scalars in Common ..
+ INTEGER ICASE, INCX, INCY, MODE, N
+ LOGICAL PASS
+* .. Local Arrays ..
+ CHARACTER*6 L(10)
+* .. Common blocks ..
+ COMMON /COMBLA/ICASE, N, INCX, INCY, MODE, PASS
+* .. Data statements ..
+ DATA L(1)/'CDOTC '/
+ DATA L(2)/'CDOTU '/
+ DATA L(3)/'CAXPY '/
+ DATA L(4)/'CCOPY '/
+ DATA L(5)/'CSWAP '/
+ DATA L(6)/'SCNRM2'/
+ DATA L(7)/'SCASUM'/
+ DATA L(8)/'CSCAL '/
+ DATA L(9)/'CSSCAL'/
+ DATA L(10)/'ICAMAX'/
+* .. Executable Statements ..
+ WRITE (NOUT,99999) ICASE, L(ICASE)
+ RETURN
+*
+99999 FORMAT (/' Test of subprogram number',I3,12X,A6)
+ END
+ SUBROUTINE CHECK1(SFAC)
+* .. Parameters ..
+ INTEGER NOUT
+ PARAMETER (NOUT=6)
+* .. Scalar Arguments ..
+ REAL SFAC
+* .. Scalars in Common ..
+ INTEGER ICASE, INCX, INCY, MODE, N
+ LOGICAL PASS
+* .. Local Scalars ..
+ COMPLEX CA
+ REAL SA
+ INTEGER I, J, LEN, NP1
+* .. Local Arrays ..
+ COMPLEX CTRUE5(8,5,2), CTRUE6(8,5,2), CV(8,5,2), CX(8),
+ + MWPCS(5), MWPCT(5)
+ REAL STRUE2(5), STRUE4(5)
+ INTEGER ITRUE3(5)
+* .. External Functions ..
+ REAL SCASUM, SCNRM2
+ INTEGER ICAMAX
+ EXTERNAL SCASUM, SCNRM2, ICAMAX
+* .. External Subroutines ..
+ EXTERNAL CSCAL, CSSCAL, CTEST, ITEST1, STEST1
+* .. Intrinsic Functions ..
+ INTRINSIC MAX
+* .. Common blocks ..
+ COMMON /COMBLA/ICASE, N, INCX, INCY, MODE, PASS
+* .. Data statements ..
+ DATA SA, CA/0.3E0, (0.4E0,-0.7E0)/
+ DATA ((CV(I,J,1),I=1,8),J=1,5)/(0.1E0,0.1E0),
+ + (1.0E0,2.0E0), (1.0E0,2.0E0), (1.0E0,2.0E0),
+ + (1.0E0,2.0E0), (1.0E0,2.0E0), (1.0E0,2.0E0),
+ + (1.0E0,2.0E0), (0.3E0,-0.4E0), (3.0E0,4.0E0),
+ + (3.0E0,4.0E0), (3.0E0,4.0E0), (3.0E0,4.0E0),
+ + (3.0E0,4.0E0), (3.0E0,4.0E0), (3.0E0,4.0E0),
+ + (0.1E0,-0.3E0), (0.5E0,-0.1E0), (5.0E0,6.0E0),
+ + (5.0E0,6.0E0), (5.0E0,6.0E0), (5.0E0,6.0E0),
+ + (5.0E0,6.0E0), (5.0E0,6.0E0), (0.1E0,0.1E0),
+ + (-0.6E0,0.1E0), (0.1E0,-0.3E0), (7.0E0,8.0E0),
+ + (7.0E0,8.0E0), (7.0E0,8.0E0), (7.0E0,8.0E0),
+ + (7.0E0,8.0E0), (0.3E0,0.1E0), (0.1E0,0.4E0),
+ + (0.4E0,0.1E0), (0.1E0,0.2E0), (2.0E0,3.0E0),
+ + (2.0E0,3.0E0), (2.0E0,3.0E0), (2.0E0,3.0E0)/
+ DATA ((CV(I,J,2),I=1,8),J=1,5)/(0.1E0,0.1E0),
+ + (4.0E0,5.0E0), (4.0E0,5.0E0), (4.0E0,5.0E0),
+ + (4.0E0,5.0E0), (4.0E0,5.0E0), (4.0E0,5.0E0),
+ + (4.0E0,5.0E0), (0.3E0,-0.4E0), (6.0E0,7.0E0),
+ + (6.0E0,7.0E0), (6.0E0,7.0E0), (6.0E0,7.0E0),
+ + (6.0E0,7.0E0), (6.0E0,7.0E0), (6.0E0,7.0E0),
+ + (0.1E0,-0.3E0), (8.0E0,9.0E0), (0.5E0,-0.1E0),
+ + (2.0E0,5.0E0), (2.0E0,5.0E0), (2.0E0,5.0E0),
+ + (2.0E0,5.0E0), (2.0E0,5.0E0), (0.1E0,0.1E0),
+ + (3.0E0,6.0E0), (-0.6E0,0.1E0), (4.0E0,7.0E0),
+ + (0.1E0,-0.3E0), (7.0E0,2.0E0), (7.0E0,2.0E0),
+ + (7.0E0,2.0E0), (0.3E0,0.1E0), (5.0E0,8.0E0),
+ + (0.1E0,0.4E0), (6.0E0,9.0E0), (0.4E0,0.1E0),
+ + (8.0E0,3.0E0), (0.1E0,0.2E0), (9.0E0,4.0E0)/
+ DATA STRUE2/0.0E0, 0.5E0, 0.6E0, 0.7E0, 0.7E0/
+ DATA STRUE4/0.0E0, 0.7E0, 1.0E0, 1.3E0, 1.7E0/
+ DATA ((CTRUE5(I,J,1),I=1,8),J=1,5)/(0.1E0,0.1E0),
+ + (1.0E0,2.0E0), (1.0E0,2.0E0), (1.0E0,2.0E0),
+ + (1.0E0,2.0E0), (1.0E0,2.0E0), (1.0E0,2.0E0),
+ + (1.0E0,2.0E0), (-0.16E0,-0.37E0), (3.0E0,4.0E0),
+ + (3.0E0,4.0E0), (3.0E0,4.0E0), (3.0E0,4.0E0),
+ + (3.0E0,4.0E0), (3.0E0,4.0E0), (3.0E0,4.0E0),
+ + (-0.17E0,-0.19E0), (0.13E0,-0.39E0),
+ + (5.0E0,6.0E0), (5.0E0,6.0E0), (5.0E0,6.0E0),
+ + (5.0E0,6.0E0), (5.0E0,6.0E0), (5.0E0,6.0E0),
+ + (0.11E0,-0.03E0), (-0.17E0,0.46E0),
+ + (-0.17E0,-0.19E0), (7.0E0,8.0E0), (7.0E0,8.0E0),
+ + (7.0E0,8.0E0), (7.0E0,8.0E0), (7.0E0,8.0E0),
+ + (0.19E0,-0.17E0), (0.32E0,0.09E0),
+ + (0.23E0,-0.24E0), (0.18E0,0.01E0),
+ + (2.0E0,3.0E0), (2.0E0,3.0E0), (2.0E0,3.0E0),
+ + (2.0E0,3.0E0)/
+ DATA ((CTRUE5(I,J,2),I=1,8),J=1,5)/(0.1E0,0.1E0),
+ + (4.0E0,5.0E0), (4.0E0,5.0E0), (4.0E0,5.0E0),
+ + (4.0E0,5.0E0), (4.0E0,5.0E0), (4.0E0,5.0E0),
+ + (4.0E0,5.0E0), (-0.16E0,-0.37E0), (6.0E0,7.0E0),
+ + (6.0E0,7.0E0), (6.0E0,7.0E0), (6.0E0,7.0E0),
+ + (6.0E0,7.0E0), (6.0E0,7.0E0), (6.0E0,7.0E0),
+ + (-0.17E0,-0.19E0), (8.0E0,9.0E0),
+ + (0.13E0,-0.39E0), (2.0E0,5.0E0), (2.0E0,5.0E0),
+ + (2.0E0,5.0E0), (2.0E0,5.0E0), (2.0E0,5.0E0),
+ + (0.11E0,-0.03E0), (3.0E0,6.0E0),
+ + (-0.17E0,0.46E0), (4.0E0,7.0E0),
+ + (-0.17E0,-0.19E0), (7.0E0,2.0E0), (7.0E0,2.0E0),
+ + (7.0E0,2.0E0), (0.19E0,-0.17E0), (5.0E0,8.0E0),
+ + (0.32E0,0.09E0), (6.0E0,9.0E0),
+ + (0.23E0,-0.24E0), (8.0E0,3.0E0),
+ + (0.18E0,0.01E0), (9.0E0,4.0E0)/
+ DATA ((CTRUE6(I,J,1),I=1,8),J=1,5)/(0.1E0,0.1E0),
+ + (1.0E0,2.0E0), (1.0E0,2.0E0), (1.0E0,2.0E0),
+ + (1.0E0,2.0E0), (1.0E0,2.0E0), (1.0E0,2.0E0),
+ + (1.0E0,2.0E0), (0.09E0,-0.12E0), (3.0E0,4.0E0),
+ + (3.0E0,4.0E0), (3.0E0,4.0E0), (3.0E0,4.0E0),
+ + (3.0E0,4.0E0), (3.0E0,4.0E0), (3.0E0,4.0E0),
+ + (0.03E0,-0.09E0), (0.15E0,-0.03E0),
+ + (5.0E0,6.0E0), (5.0E0,6.0E0), (5.0E0,6.0E0),
+ + (5.0E0,6.0E0), (5.0E0,6.0E0), (5.0E0,6.0E0),
+ + (0.03E0,0.03E0), (-0.18E0,0.03E0),
+ + (0.03E0,-0.09E0), (7.0E0,8.0E0), (7.0E0,8.0E0),
+ + (7.0E0,8.0E0), (7.0E0,8.0E0), (7.0E0,8.0E0),
+ + (0.09E0,0.03E0), (0.03E0,0.12E0),
+ + (0.12E0,0.03E0), (0.03E0,0.06E0), (2.0E0,3.0E0),
+ + (2.0E0,3.0E0), (2.0E0,3.0E0), (2.0E0,3.0E0)/
+ DATA ((CTRUE6(I,J,2),I=1,8),J=1,5)/(0.1E0,0.1E0),
+ + (4.0E0,5.0E0), (4.0E0,5.0E0), (4.0E0,5.0E0),
+ + (4.0E0,5.0E0), (4.0E0,5.0E0), (4.0E0,5.0E0),
+ + (4.0E0,5.0E0), (0.09E0,-0.12E0), (6.0E0,7.0E0),
+ + (6.0E0,7.0E0), (6.0E0,7.0E0), (6.0E0,7.0E0),
+ + (6.0E0,7.0E0), (6.0E0,7.0E0), (6.0E0,7.0E0),
+ + (0.03E0,-0.09E0), (8.0E0,9.0E0),
+ + (0.15E0,-0.03E0), (2.0E0,5.0E0), (2.0E0,5.0E0),
+ + (2.0E0,5.0E0), (2.0E0,5.0E0), (2.0E0,5.0E0),
+ + (0.03E0,0.03E0), (3.0E0,6.0E0),
+ + (-0.18E0,0.03E0), (4.0E0,7.0E0),
+ + (0.03E0,-0.09E0), (7.0E0,2.0E0), (7.0E0,2.0E0),
+ + (7.0E0,2.0E0), (0.09E0,0.03E0), (5.0E0,8.0E0),
+ + (0.03E0,0.12E0), (6.0E0,9.0E0), (0.12E0,0.03E0),
+ + (8.0E0,3.0E0), (0.03E0,0.06E0), (9.0E0,4.0E0)/
+ DATA ITRUE3/0, 1, 2, 2, 2/
+* .. Executable Statements ..
+ DO 60 INCX = 1, 2
+ DO 40 NP1 = 1, 5
+ N = NP1 - 1
+ LEN = 2*MAX(N,1)
+* .. Set vector arguments ..
+ DO 20 I = 1, LEN
+ CX(I) = CV(I,NP1,INCX)
+ 20 CONTINUE
+ IF (ICASE.EQ.6) THEN
+* .. SCNRM2 ..
+ CALL STEST1(SCNRM2(N,CX,INCX),STRUE2(NP1),STRUE2(NP1),
+ + SFAC)
+ ELSE IF (ICASE.EQ.7) THEN
+* .. SCASUM ..
+ CALL STEST1(SCASUM(N,CX,INCX),STRUE4(NP1),STRUE4(NP1),
+ + SFAC)
+ ELSE IF (ICASE.EQ.8) THEN
+* .. CSCAL ..
+ CALL CSCAL(N,CA,CX,INCX)
+ CALL CTEST(LEN,CX,CTRUE5(1,NP1,INCX),CTRUE5(1,NP1,INCX),
+ + SFAC)
+ ELSE IF (ICASE.EQ.9) THEN
+* .. CSSCAL ..
+ CALL CSSCAL(N,SA,CX,INCX)
+ CALL CTEST(LEN,CX,CTRUE6(1,NP1,INCX),CTRUE6(1,NP1,INCX),
+ + SFAC)
+ ELSE IF (ICASE.EQ.10) THEN
+* .. ICAMAX ..
+ CALL ITEST1(ICAMAX(N,CX,INCX),ITRUE3(NP1))
+ ELSE
+ WRITE (NOUT,*) ' Shouldn''t be here in CHECK1'
+ STOP
+ END IF
+*
+ 40 CONTINUE
+ 60 CONTINUE
+*
+ INCX = 1
+ IF (ICASE.EQ.8) THEN
+* CSCAL
+* Add a test for alpha equal to zero.
+ CA = (0.0E0,0.0E0)
+ DO 80 I = 1, 5
+ MWPCT(I) = (0.0E0,0.0E0)
+ MWPCS(I) = (1.0E0,1.0E0)
+ 80 CONTINUE
+ CALL CSCAL(5,CA,CX,INCX)
+ CALL CTEST(5,CX,MWPCT,MWPCS,SFAC)
+ ELSE IF (ICASE.EQ.9) THEN
+* CSSCAL
+* Add a test for alpha equal to zero.
+ SA = 0.0E0
+ DO 100 I = 1, 5
+ MWPCT(I) = (0.0E0,0.0E0)
+ MWPCS(I) = (1.0E0,1.0E0)
+ 100 CONTINUE
+ CALL CSSCAL(5,SA,CX,INCX)
+ CALL CTEST(5,CX,MWPCT,MWPCS,SFAC)
+* Add a test for alpha equal to one.
+ SA = 1.0E0
+ DO 120 I = 1, 5
+ MWPCT(I) = CX(I)
+ MWPCS(I) = CX(I)
+ 120 CONTINUE
+ CALL CSSCAL(5,SA,CX,INCX)
+ CALL CTEST(5,CX,MWPCT,MWPCS,SFAC)
+* Add a test for alpha equal to minus one.
+ SA = -1.0E0
+ DO 140 I = 1, 5
+ MWPCT(I) = -CX(I)
+ MWPCS(I) = -CX(I)
+ 140 CONTINUE
+ CALL CSSCAL(5,SA,CX,INCX)
+ CALL CTEST(5,CX,MWPCT,MWPCS,SFAC)
+ END IF
+ RETURN
+ END
+ SUBROUTINE CHECK2(SFAC)
+* .. Parameters ..
+ INTEGER NOUT
+ PARAMETER (NOUT=6)
+* .. Scalar Arguments ..
+ REAL SFAC
+* .. Scalars in Common ..
+ INTEGER ICASE, INCX, INCY, MODE, N
+ LOGICAL PASS
+* .. Local Scalars ..
+ COMPLEX CA
+ INTEGER I, J, KI, KN, KSIZE, LENX, LENY, MX, MY
+* .. Local Arrays ..
+ COMPLEX CDOT(1), CSIZE1(4), CSIZE2(7,2), CSIZE3(14),
+ + CT10X(7,4,4), CT10Y(7,4,4), CT6(4,4), CT7(4,4),
+ + CT8(7,4,4), CX(7), CX1(7), CY(7), CY1(7)
+ INTEGER INCXS(4), INCYS(4), LENS(4,2), NS(4)
+* .. External Functions ..
+ COMPLEX CDOTC, CDOTU
+ EXTERNAL CDOTC, CDOTU
+* .. External Subroutines ..
+ EXTERNAL CAXPY, CCOPY, CSWAP, CTEST
+* .. Intrinsic Functions ..
+ INTRINSIC ABS, MIN
+* .. Common blocks ..
+ COMMON /COMBLA/ICASE, N, INCX, INCY, MODE, PASS
+* .. Data statements ..
+ DATA CA/(0.4E0,-0.7E0)/
+ DATA INCXS/1, 2, -2, -1/
+ DATA INCYS/1, -2, 1, -2/
+ DATA LENS/1, 1, 2, 4, 1, 1, 3, 7/
+ DATA NS/0, 1, 2, 4/
+ DATA CX1/(0.7E0,-0.8E0), (-0.4E0,-0.7E0),
+ + (-0.1E0,-0.9E0), (0.2E0,-0.8E0),
+ + (-0.9E0,-0.4E0), (0.1E0,0.4E0), (-0.6E0,0.6E0)/
+ DATA CY1/(0.6E0,-0.6E0), (-0.9E0,0.5E0),
+ + (0.7E0,-0.6E0), (0.1E0,-0.5E0), (-0.1E0,-0.2E0),
+ + (-0.5E0,-0.3E0), (0.8E0,-0.7E0)/
+ DATA ((CT8(I,J,1),I=1,7),J=1,4)/(0.6E0,-0.6E0),
+ + (0.0E0,0.0E0), (0.0E0,0.0E0), (0.0E0,0.0E0),
+ + (0.0E0,0.0E0), (0.0E0,0.0E0), (0.0E0,0.0E0),
+ + (0.32E0,-1.41E0), (0.0E0,0.0E0), (0.0E0,0.0E0),
+ + (0.0E0,0.0E0), (0.0E0,0.0E0), (0.0E0,0.0E0),
+ + (0.0E0,0.0E0), (0.32E0,-1.41E0),
+ + (-1.55E0,0.5E0), (0.0E0,0.0E0), (0.0E0,0.0E0),
+ + (0.0E0,0.0E0), (0.0E0,0.0E0), (0.0E0,0.0E0),
+ + (0.32E0,-1.41E0), (-1.55E0,0.5E0),
+ + (0.03E0,-0.89E0), (-0.38E0,-0.96E0),
+ + (0.0E0,0.0E0), (0.0E0,0.0E0), (0.0E0,0.0E0)/
+ DATA ((CT8(I,J,2),I=1,7),J=1,4)/(0.6E0,-0.6E0),
+ + (0.0E0,0.0E0), (0.0E0,0.0E0), (0.0E0,0.0E0),
+ + (0.0E0,0.0E0), (0.0E0,0.0E0), (0.0E0,0.0E0),
+ + (0.32E0,-1.41E0), (0.0E0,0.0E0), (0.0E0,0.0E0),
+ + (0.0E0,0.0E0), (0.0E0,0.0E0), (0.0E0,0.0E0),
+ + (0.0E0,0.0E0), (-0.07E0,-0.89E0),
+ + (-0.9E0,0.5E0), (0.42E0,-1.41E0), (0.0E0,0.0E0),
+ + (0.0E0,0.0E0), (0.0E0,0.0E0), (0.0E0,0.0E0),
+ + (0.78E0,0.06E0), (-0.9E0,0.5E0),
+ + (0.06E0,-0.13E0), (0.1E0,-0.5E0),
+ + (-0.77E0,-0.49E0), (-0.5E0,-0.3E0),
+ + (0.52E0,-1.51E0)/
+ DATA ((CT8(I,J,3),I=1,7),J=1,4)/(0.6E0,-0.6E0),
+ + (0.0E0,0.0E0), (0.0E0,0.0E0), (0.0E0,0.0E0),
+ + (0.0E0,0.0E0), (0.0E0,0.0E0), (0.0E0,0.0E0),
+ + (0.32E0,-1.41E0), (0.0E0,0.0E0), (0.0E0,0.0E0),
+ + (0.0E0,0.0E0), (0.0E0,0.0E0), (0.0E0,0.0E0),
+ + (0.0E0,0.0E0), (-0.07E0,-0.89E0),
+ + (-1.18E0,-0.31E0), (0.0E0,0.0E0), (0.0E0,0.0E0),
+ + (0.0E0,0.0E0), (0.0E0,0.0E0), (0.0E0,0.0E0),
+ + (0.78E0,0.06E0), (-1.54E0,0.97E0),
+ + (0.03E0,-0.89E0), (-0.18E0,-1.31E0),
+ + (0.0E0,0.0E0), (0.0E0,0.0E0), (0.0E0,0.0E0)/
+ DATA ((CT8(I,J,4),I=1,7),J=1,4)/(0.6E0,-0.6E0),
+ + (0.0E0,0.0E0), (0.0E0,0.0E0), (0.0E0,0.0E0),
+ + (0.0E0,0.0E0), (0.0E0,0.0E0), (0.0E0,0.0E0),
+ + (0.32E0,-1.41E0), (0.0E0,0.0E0), (0.0E0,0.0E0),
+ + (0.0E0,0.0E0), (0.0E0,0.0E0), (0.0E0,0.0E0),
+ + (0.0E0,0.0E0), (0.32E0,-1.41E0), (-0.9E0,0.5E0),
+ + (0.05E0,-0.6E0), (0.0E0,0.0E0), (0.0E0,0.0E0),
+ + (0.0E0,0.0E0), (0.0E0,0.0E0), (0.32E0,-1.41E0),
+ + (-0.9E0,0.5E0), (0.05E0,-0.6E0), (0.1E0,-0.5E0),
+ + (-0.77E0,-0.49E0), (-0.5E0,-0.3E0),
+ + (0.32E0,-1.16E0)/
+ DATA CT7/(0.0E0,0.0E0), (-0.06E0,-0.90E0),
+ + (0.65E0,-0.47E0), (-0.34E0,-1.22E0),
+ + (0.0E0,0.0E0), (-0.06E0,-0.90E0),
+ + (-0.59E0,-1.46E0), (-1.04E0,-0.04E0),
+ + (0.0E0,0.0E0), (-0.06E0,-0.90E0),
+ + (-0.83E0,0.59E0), (0.07E0,-0.37E0),
+ + (0.0E0,0.0E0), (-0.06E0,-0.90E0),
+ + (-0.76E0,-1.15E0), (-1.33E0,-1.82E0)/
+ DATA CT6/(0.0E0,0.0E0), (0.90E0,0.06E0),
+ + (0.91E0,-0.77E0), (1.80E0,-0.10E0),
+ + (0.0E0,0.0E0), (0.90E0,0.06E0), (1.45E0,0.74E0),
+ + (0.20E0,0.90E0), (0.0E0,0.0E0), (0.90E0,0.06E0),
+ + (-0.55E0,0.23E0), (0.83E0,-0.39E0),
+ + (0.0E0,0.0E0), (0.90E0,0.06E0), (1.04E0,0.79E0),
+ + (1.95E0,1.22E0)/
+ DATA ((CT10X(I,J,1),I=1,7),J=1,4)/(0.7E0,-0.8E0),
+ + (0.0E0,0.0E0), (0.0E0,0.0E0), (0.0E0,0.0E0),
+ + (0.0E0,0.0E0), (0.0E0,0.0E0), (0.0E0,0.0E0),
+ + (0.6E0,-0.6E0), (0.0E0,0.0E0), (0.0E0,0.0E0),
+ + (0.0E0,0.0E0), (0.0E0,0.0E0), (0.0E0,0.0E0),
+ + (0.0E0,0.0E0), (0.6E0,-0.6E0), (-0.9E0,0.5E0),
+ + (0.0E0,0.0E0), (0.0E0,0.0E0), (0.0E0,0.0E0),
+ + (0.0E0,0.0E0), (0.0E0,0.0E0), (0.6E0,-0.6E0),
+ + (-0.9E0,0.5E0), (0.7E0,-0.6E0), (0.1E0,-0.5E0),
+ + (0.0E0,0.0E0), (0.0E0,0.0E0), (0.0E0,0.0E0)/
+ DATA ((CT10X(I,J,2),I=1,7),J=1,4)/(0.7E0,-0.8E0),
+ + (0.0E0,0.0E0), (0.0E0,0.0E0), (0.0E0,0.0E0),
+ + (0.0E0,0.0E0), (0.0E0,0.0E0), (0.0E0,0.0E0),
+ + (0.6E0,-0.6E0), (0.0E0,0.0E0), (0.0E0,0.0E0),
+ + (0.0E0,0.0E0), (0.0E0,0.0E0), (0.0E0,0.0E0),
+ + (0.0E0,0.0E0), (0.7E0,-0.6E0), (-0.4E0,-0.7E0),
+ + (0.6E0,-0.6E0), (0.0E0,0.0E0), (0.0E0,0.0E0),
+ + (0.0E0,0.0E0), (0.0E0,0.0E0), (0.8E0,-0.7E0),
+ + (-0.4E0,-0.7E0), (-0.1E0,-0.2E0),
+ + (0.2E0,-0.8E0), (0.7E0,-0.6E0), (0.1E0,0.4E0),
+ + (0.6E0,-0.6E0)/
+ DATA ((CT10X(I,J,3),I=1,7),J=1,4)/(0.7E0,-0.8E0),
+ + (0.0E0,0.0E0), (0.0E0,0.0E0), (0.0E0,0.0E0),
+ + (0.0E0,0.0E0), (0.0E0,0.0E0), (0.0E0,0.0E0),
+ + (0.6E0,-0.6E0), (0.0E0,0.0E0), (0.0E0,0.0E0),
+ + (0.0E0,0.0E0), (0.0E0,0.0E0), (0.0E0,0.0E0),
+ + (0.0E0,0.0E0), (-0.9E0,0.5E0), (-0.4E0,-0.7E0),
+ + (0.6E0,-0.6E0), (0.0E0,0.0E0), (0.0E0,0.0E0),
+ + (0.0E0,0.0E0), (0.0E0,0.0E0), (0.1E0,-0.5E0),
+ + (-0.4E0,-0.7E0), (0.7E0,-0.6E0), (0.2E0,-0.8E0),
+ + (-0.9E0,0.5E0), (0.1E0,0.4E0), (0.6E0,-0.6E0)/
+ DATA ((CT10X(I,J,4),I=1,7),J=1,4)/(0.7E0,-0.8E0),
+ + (0.0E0,0.0E0), (0.0E0,0.0E0), (0.0E0,0.0E0),
+ + (0.0E0,0.0E0), (0.0E0,0.0E0), (0.0E0,0.0E0),
+ + (0.6E0,-0.6E0), (0.0E0,0.0E0), (0.0E0,0.0E0),
+ + (0.0E0,0.0E0), (0.0E0,0.0E0), (0.0E0,0.0E0),
+ + (0.0E0,0.0E0), (0.6E0,-0.6E0), (0.7E0,-0.6E0),
+ + (0.0E0,0.0E0), (0.0E0,0.0E0), (0.0E0,0.0E0),
+ + (0.0E0,0.0E0), (0.0E0,0.0E0), (0.6E0,-0.6E0),
+ + (0.7E0,-0.6E0), (-0.1E0,-0.2E0), (0.8E0,-0.7E0),
+ + (0.0E0,0.0E0), (0.0E0,0.0E0), (0.0E0,0.0E0)/
+ DATA ((CT10Y(I,J,1),I=1,7),J=1,4)/(0.6E0,-0.6E0),
+ + (0.0E0,0.0E0), (0.0E0,0.0E0), (0.0E0,0.0E0),
+ + (0.0E0,0.0E0), (0.0E0,0.0E0), (0.0E0,0.0E0),
+ + (0.7E0,-0.8E0), (0.0E0,0.0E0), (0.0E0,0.0E0),
+ + (0.0E0,0.0E0), (0.0E0,0.0E0), (0.0E0,0.0E0),
+ + (0.0E0,0.0E0), (0.7E0,-0.8E0), (-0.4E0,-0.7E0),
+ + (0.0E0,0.0E0), (0.0E0,0.0E0), (0.0E0,0.0E0),
+ + (0.0E0,0.0E0), (0.0E0,0.0E0), (0.7E0,-0.8E0),
+ + (-0.4E0,-0.7E0), (-0.1E0,-0.9E0),
+ + (0.2E0,-0.8E0), (0.0E0,0.0E0), (0.0E0,0.0E0),
+ + (0.0E0,0.0E0)/
+ DATA ((CT10Y(I,J,2),I=1,7),J=1,4)/(0.6E0,-0.6E0),
+ + (0.0E0,0.0E0), (0.0E0,0.0E0), (0.0E0,0.0E0),
+ + (0.0E0,0.0E0), (0.0E0,0.0E0), (0.0E0,0.0E0),
+ + (0.7E0,-0.8E0), (0.0E0,0.0E0), (0.0E0,0.0E0),
+ + (0.0E0,0.0E0), (0.0E0,0.0E0), (0.0E0,0.0E0),
+ + (0.0E0,0.0E0), (-0.1E0,-0.9E0), (-0.9E0,0.5E0),
+ + (0.7E0,-0.8E0), (0.0E0,0.0E0), (0.0E0,0.0E0),
+ + (0.0E0,0.0E0), (0.0E0,0.0E0), (-0.6E0,0.6E0),
+ + (-0.9E0,0.5E0), (-0.9E0,-0.4E0), (0.1E0,-0.5E0),
+ + (-0.1E0,-0.9E0), (-0.5E0,-0.3E0),
+ + (0.7E0,-0.8E0)/
+ DATA ((CT10Y(I,J,3),I=1,7),J=1,4)/(0.6E0,-0.6E0),
+ + (0.0E0,0.0E0), (0.0E0,0.0E0), (0.0E0,0.0E0),
+ + (0.0E0,0.0E0), (0.0E0,0.0E0), (0.0E0,0.0E0),
+ + (0.7E0,-0.8E0), (0.0E0,0.0E0), (0.0E0,0.0E0),
+ + (0.0E0,0.0E0), (0.0E0,0.0E0), (0.0E0,0.0E0),
+ + (0.0E0,0.0E0), (-0.1E0,-0.9E0), (0.7E0,-0.8E0),
+ + (0.0E0,0.0E0), (0.0E0,0.0E0), (0.0E0,0.0E0),
+ + (0.0E0,0.0E0), (0.0E0,0.0E0), (-0.6E0,0.6E0),
+ + (-0.9E0,-0.4E0), (-0.1E0,-0.9E0),
+ + (0.7E0,-0.8E0), (0.0E0,0.0E0), (0.0E0,0.0E0),
+ + (0.0E0,0.0E0)/
+ DATA ((CT10Y(I,J,4),I=1,7),J=1,4)/(0.6E0,-0.6E0),
+ + (0.0E0,0.0E0), (0.0E0,0.0E0), (0.0E0,0.0E0),
+ + (0.0E0,0.0E0), (0.0E0,0.0E0), (0.0E0,0.0E0),
+ + (0.7E0,-0.8E0), (0.0E0,0.0E0), (0.0E0,0.0E0),
+ + (0.0E0,0.0E0), (0.0E0,0.0E0), (0.0E0,0.0E0),
+ + (0.0E0,0.0E0), (0.7E0,-0.8E0), (-0.9E0,0.5E0),
+ + (-0.4E0,-0.7E0), (0.0E0,0.0E0), (0.0E0,0.0E0),
+ + (0.0E0,0.0E0), (0.0E0,0.0E0), (0.7E0,-0.8E0),
+ + (-0.9E0,0.5E0), (-0.4E0,-0.7E0), (0.1E0,-0.5E0),
+ + (-0.1E0,-0.9E0), (-0.5E0,-0.3E0),
+ + (0.2E0,-0.8E0)/
+ DATA CSIZE1/(0.0E0,0.0E0), (0.9E0,0.9E0),
+ + (1.63E0,1.73E0), (2.90E0,2.78E0)/
+ DATA CSIZE3/(0.0E0,0.0E0), (0.0E0,0.0E0),
+ + (0.0E0,0.0E0), (0.0E0,0.0E0), (0.0E0,0.0E0),
+ + (0.0E0,0.0E0), (0.0E0,0.0E0), (1.17E0,1.17E0),
+ + (1.17E0,1.17E0), (1.17E0,1.17E0),
+ + (1.17E0,1.17E0), (1.17E0,1.17E0),
+ + (1.17E0,1.17E0), (1.17E0,1.17E0)/
+ DATA CSIZE2/(0.0E0,0.0E0), (0.0E0,0.0E0),
+ + (0.0E0,0.0E0), (0.0E0,0.0E0), (0.0E0,0.0E0),
+ + (0.0E0,0.0E0), (0.0E0,0.0E0), (1.54E0,1.54E0),
+ + (1.54E0,1.54E0), (1.54E0,1.54E0),
+ + (1.54E0,1.54E0), (1.54E0,1.54E0),
+ + (1.54E0,1.54E0), (1.54E0,1.54E0)/
+* .. Executable Statements ..
+ DO 60 KI = 1, 4
+ INCX = INCXS(KI)
+ INCY = INCYS(KI)
+ MX = ABS(INCX)
+ MY = ABS(INCY)
+*
+ DO 40 KN = 1, 4
+ N = NS(KN)
+ KSIZE = MIN(2,KN)
+ LENX = LENS(KN,MX)
+ LENY = LENS(KN,MY)
+* .. initialize all argument arrays ..
+ DO 20 I = 1, 7
+ CX(I) = CX1(I)
+ CY(I) = CY1(I)
+ 20 CONTINUE
+ IF (ICASE.EQ.1) THEN
+* .. CDOTC ..
+ CDOT(1) = CDOTC(N,CX,INCX,CY,INCY)
+ CALL CTEST(1,CDOT,CT6(KN,KI),CSIZE1(KN),SFAC)
+ ELSE IF (ICASE.EQ.2) THEN
+* .. CDOTU ..
+ CDOT(1) = CDOTU(N,CX,INCX,CY,INCY)
+ CALL CTEST(1,CDOT,CT7(KN,KI),CSIZE1(KN),SFAC)
+ ELSE IF (ICASE.EQ.3) THEN
+* .. CAXPY ..
+ CALL CAXPY(N,CA,CX,INCX,CY,INCY)
+ CALL CTEST(LENY,CY,CT8(1,KN,KI),CSIZE2(1,KSIZE),SFAC)
+ ELSE IF (ICASE.EQ.4) THEN
+* .. CCOPY ..
+ CALL CCOPY(N,CX,INCX,CY,INCY)
+ CALL CTEST(LENY,CY,CT10Y(1,KN,KI),CSIZE3,1.0E0)
+ ELSE IF (ICASE.EQ.5) THEN
+* .. CSWAP ..
+ CALL CSWAP(N,CX,INCX,CY,INCY)
+ CALL CTEST(LENX,CX,CT10X(1,KN,KI),CSIZE3,1.0E0)
+ CALL CTEST(LENY,CY,CT10Y(1,KN,KI),CSIZE3,1.0E0)
+ ELSE
+ WRITE (NOUT,*) ' Shouldn''t be here in CHECK2'
+ STOP
+ END IF
+*
+ 40 CONTINUE
+ 60 CONTINUE
+ RETURN
+ END
+ SUBROUTINE STEST(LEN,SCOMP,STRUE,SSIZE,SFAC)
+* ********************************* STEST **************************
+*
+* THIS SUBR COMPARES ARRAYS SCOMP() AND STRUE() OF LENGTH LEN TO
+* SEE IF THE TERM BY TERM DIFFERENCES, MULTIPLIED BY SFAC, ARE
+* NEGLIGIBLE.
+*
+* C. L. LAWSON, JPL, 1974 DEC 10
+*
+* .. Parameters ..
+ INTEGER NOUT
+ PARAMETER (NOUT=6)
+* .. Scalar Arguments ..
+ REAL SFAC
+ INTEGER LEN
+* .. Array Arguments ..
+ REAL SCOMP(LEN), SSIZE(LEN), STRUE(LEN)
+* .. Scalars in Common ..
+ INTEGER ICASE, INCX, INCY, MODE, N
+ LOGICAL PASS
+* .. Local Scalars ..
+ REAL SD
+ INTEGER I
+* .. External Functions ..
+ REAL SDIFF
+ EXTERNAL SDIFF
+* .. Intrinsic Functions ..
+ INTRINSIC ABS
+* .. Common blocks ..
+ COMMON /COMBLA/ICASE, N, INCX, INCY, MODE, PASS
+* .. Executable Statements ..
+*
+ DO 40 I = 1, LEN
+ SD = SCOMP(I) - STRUE(I)
+ IF (SDIFF(ABS(SSIZE(I))+ABS(SFAC*SD),ABS(SSIZE(I))).EQ.0.0E0)
+ + GO TO 40
+*
+* HERE SCOMP(I) IS NOT CLOSE TO STRUE(I).
+*
+ IF ( .NOT. PASS) GO TO 20
+* PRINT FAIL MESSAGE AND HEADER.
+ PASS = .FALSE.
+ WRITE (NOUT,99999)
+ WRITE (NOUT,99998)
+ 20 WRITE (NOUT,99997) ICASE, N, INCX, INCY, MODE, I, SCOMP(I),
+ + STRUE(I), SD, SSIZE(I)
+ 40 CONTINUE
+ RETURN
+*
+99999 FORMAT (' FAIL')
+99998 FORMAT (/' CASE N INCX INCY MODE I ',
+ + ' COMP(I) TRUE(I) DIFFERENCE',
+ + ' SIZE(I)',/1X)
+99997 FORMAT (1X,I4,I3,3I5,I3,2E36.8,2E12.4)
+ END
+ SUBROUTINE STEST1(SCOMP1,STRUE1,SSIZE,SFAC)
+* ************************* STEST1 *****************************
+*
+* THIS IS AN INTERFACE SUBROUTINE TO ACCOMODATE THE FORTRAN
+* REQUIREMENT THAT WHEN A DUMMY ARGUMENT IS AN ARRAY, THE
+* ACTUAL ARGUMENT MUST ALSO BE AN ARRAY OR AN ARRAY ELEMENT.
+*
+* C.L. LAWSON, JPL, 1978 DEC 6
+*
+* .. Scalar Arguments ..
+ REAL SCOMP1, SFAC, STRUE1
+* .. Array Arguments ..
+ REAL SSIZE(*)
+* .. Local Arrays ..
+ REAL SCOMP(1), STRUE(1)
+* .. External Subroutines ..
+ EXTERNAL STEST
+* .. Executable Statements ..
+*
+ SCOMP(1) = SCOMP1
+ STRUE(1) = STRUE1
+ CALL STEST(1,SCOMP,STRUE,SSIZE,SFAC)
+*
+ RETURN
+ END
+ REAL FUNCTION SDIFF(SA,SB)
+* ********************************* SDIFF **************************
+* COMPUTES DIFFERENCE OF TWO NUMBERS. C. L. LAWSON, JPL 1974 FEB 15
+*
+* .. Scalar Arguments ..
+ REAL SA, SB
+* .. Executable Statements ..
+ SDIFF = SA - SB
+ RETURN
+ END
+ SUBROUTINE CTEST(LEN,CCOMP,CTRUE,CSIZE,SFAC)
+* **************************** CTEST *****************************
+*
+* C.L. LAWSON, JPL, 1978 DEC 6
+*
+* .. Scalar Arguments ..
+ REAL SFAC
+ INTEGER LEN
+* .. Array Arguments ..
+ COMPLEX CCOMP(LEN), CSIZE(LEN), CTRUE(LEN)
+* .. Local Scalars ..
+ INTEGER I
+* .. Local Arrays ..
+ REAL SCOMP(20), SSIZE(20), STRUE(20)
+* .. External Subroutines ..
+ EXTERNAL STEST
+* .. Intrinsic Functions ..
+ INTRINSIC AIMAG, REAL
+* .. Executable Statements ..
+ DO 20 I = 1, LEN
+ SCOMP(2*I-1) = REAL(CCOMP(I))
+ SCOMP(2*I) = AIMAG(CCOMP(I))
+ STRUE(2*I-1) = REAL(CTRUE(I))
+ STRUE(2*I) = AIMAG(CTRUE(I))
+ SSIZE(2*I-1) = REAL(CSIZE(I))
+ SSIZE(2*I) = AIMAG(CSIZE(I))
+ 20 CONTINUE
+*
+ CALL STEST(2*LEN,SCOMP,STRUE,SSIZE,SFAC)
+ RETURN
+ END
+ SUBROUTINE ITEST1(ICOMP,ITRUE)
+* ********************************* ITEST1 *************************
+*
+* THIS SUBROUTINE COMPARES THE VARIABLES ICOMP AND ITRUE FOR
+* EQUALITY.
+* C. L. LAWSON, JPL, 1974 DEC 10
+*
+* .. Parameters ..
+ INTEGER NOUT
+ PARAMETER (NOUT=6)
+* .. Scalar Arguments ..
+ INTEGER ICOMP, ITRUE
+* .. Scalars in Common ..
+ INTEGER ICASE, INCX, INCY, MODE, N
+ LOGICAL PASS
+* .. Local Scalars ..
+ INTEGER ID
+* .. Common blocks ..
+ COMMON /COMBLA/ICASE, N, INCX, INCY, MODE, PASS
+* .. Executable Statements ..
+ IF (ICOMP.EQ.ITRUE) GO TO 40
+*
+* HERE ICOMP IS NOT EQUAL TO ITRUE.
+*
+ IF ( .NOT. PASS) GO TO 20
+* PRINT FAIL MESSAGE AND HEADER.
+ PASS = .FALSE.
+ WRITE (NOUT,99999)
+ WRITE (NOUT,99998)
+ 20 ID = ICOMP - ITRUE
+ WRITE (NOUT,99997) ICASE, N, INCX, INCY, MODE, ICOMP, ITRUE, ID
+ 40 CONTINUE
+ RETURN
+*
+99999 FORMAT (' FAIL')
+99998 FORMAT (/' CASE N INCX INCY MODE ',
+ + ' COMP TRUE DIFFERENCE',
+ + /1X)
+99997 FORMAT (1X,I4,I3,3I5,2I36,I12)
+ END
diff --git a/blas/testing/cblat2.dat b/blas/testing/cblat2.dat
new file mode 100644
index 000000000..ae98730b7
--- /dev/null
+++ b/blas/testing/cblat2.dat
@@ -0,0 +1,35 @@
+'cblat2.summ' NAME OF SUMMARY OUTPUT FILE
+6 UNIT NUMBER OF SUMMARY FILE
+'cblat2.snap' NAME OF SNAPSHOT OUTPUT FILE
+-1 UNIT NUMBER OF SNAPSHOT FILE (NOT USED IF .LT. 0)
+F LOGICAL FLAG, T TO REWIND SNAPSHOT FILE AFTER EACH RECORD.
+F LOGICAL FLAG, T TO STOP ON FAILURES.
+T LOGICAL FLAG, T TO TEST ERROR EXITS.
+16.0 THRESHOLD VALUE OF TEST RATIO
+6 NUMBER OF VALUES OF N
+0 1 2 3 5 9 VALUES OF N
+4 NUMBER OF VALUES OF K
+0 1 2 4 VALUES OF K
+4 NUMBER OF VALUES OF INCX AND INCY
+1 2 -1 -2 VALUES OF INCX AND INCY
+3 NUMBER OF VALUES OF ALPHA
+(0.0,0.0) (1.0,0.0) (0.7,-0.9) VALUES OF ALPHA
+3 NUMBER OF VALUES OF BETA
+(0.0,0.0) (1.0,0.0) (1.3,-1.1) VALUES OF BETA
+CGEMV T PUT F FOR NO TEST. SAME COLUMNS.
+CGBMV T PUT F FOR NO TEST. SAME COLUMNS.
+CHEMV T PUT F FOR NO TEST. SAME COLUMNS.
+CHBMV T PUT F FOR NO TEST. SAME COLUMNS.
+CHPMV T PUT F FOR NO TEST. SAME COLUMNS.
+CTRMV T PUT F FOR NO TEST. SAME COLUMNS.
+CTBMV T PUT F FOR NO TEST. SAME COLUMNS.
+CTPMV T PUT F FOR NO TEST. SAME COLUMNS.
+CTRSV T PUT F FOR NO TEST. SAME COLUMNS.
+CTBSV T PUT F FOR NO TEST. SAME COLUMNS.
+CTPSV T PUT F FOR NO TEST. SAME COLUMNS.
+CGERC T PUT F FOR NO TEST. SAME COLUMNS.
+CGERU T PUT F FOR NO TEST. SAME COLUMNS.
+CHER T PUT F FOR NO TEST. SAME COLUMNS.
+CHPR T PUT F FOR NO TEST. SAME COLUMNS.
+CHER2 T PUT F FOR NO TEST. SAME COLUMNS.
+CHPR2 T PUT F FOR NO TEST. SAME COLUMNS.
diff --git a/blas/testing/cblat2.f b/blas/testing/cblat2.f
new file mode 100644
index 000000000..20f188100
--- /dev/null
+++ b/blas/testing/cblat2.f
@@ -0,0 +1,3241 @@
+ PROGRAM CBLAT2
+*
+* Test program for the COMPLEX Level 2 Blas.
+*
+* The program must be driven by a short data file. The first 18 records
+* of the file are read using list-directed input, the last 17 records
+* are read using the format ( A6, L2 ). An annotated example of a data
+* file can be obtained by deleting the first 3 characters from the
+* following 35 lines:
+* 'CBLAT2.SUMM' NAME OF SUMMARY OUTPUT FILE
+* 6 UNIT NUMBER OF SUMMARY FILE
+* 'CBLA2T.SNAP' NAME OF SNAPSHOT OUTPUT FILE
+* -1 UNIT NUMBER OF SNAPSHOT FILE (NOT USED IF .LT. 0)
+* F LOGICAL FLAG, T TO REWIND SNAPSHOT FILE AFTER EACH RECORD.
+* F LOGICAL FLAG, T TO STOP ON FAILURES.
+* T LOGICAL FLAG, T TO TEST ERROR EXITS.
+* 16.0 THRESHOLD VALUE OF TEST RATIO
+* 6 NUMBER OF VALUES OF N
+* 0 1 2 3 5 9 VALUES OF N
+* 4 NUMBER OF VALUES OF K
+* 0 1 2 4 VALUES OF K
+* 4 NUMBER OF VALUES OF INCX AND INCY
+* 1 2 -1 -2 VALUES OF INCX AND INCY
+* 3 NUMBER OF VALUES OF ALPHA
+* (0.0,0.0) (1.0,0.0) (0.7,-0.9) VALUES OF ALPHA
+* 3 NUMBER OF VALUES OF BETA
+* (0.0,0.0) (1.0,0.0) (1.3,-1.1) VALUES OF BETA
+* CGEMV T PUT F FOR NO TEST. SAME COLUMNS.
+* CGBMV T PUT F FOR NO TEST. SAME COLUMNS.
+* CHEMV T PUT F FOR NO TEST. SAME COLUMNS.
+* CHBMV T PUT F FOR NO TEST. SAME COLUMNS.
+* CHPMV T PUT F FOR NO TEST. SAME COLUMNS.
+* CTRMV T PUT F FOR NO TEST. SAME COLUMNS.
+* CTBMV T PUT F FOR NO TEST. SAME COLUMNS.
+* CTPMV T PUT F FOR NO TEST. SAME COLUMNS.
+* CTRSV T PUT F FOR NO TEST. SAME COLUMNS.
+* CTBSV T PUT F FOR NO TEST. SAME COLUMNS.
+* CTPSV T PUT F FOR NO TEST. SAME COLUMNS.
+* CGERC T PUT F FOR NO TEST. SAME COLUMNS.
+* CGERU T PUT F FOR NO TEST. SAME COLUMNS.
+* CHER T PUT F FOR NO TEST. SAME COLUMNS.
+* CHPR T PUT F FOR NO TEST. SAME COLUMNS.
+* CHER2 T PUT F FOR NO TEST. SAME COLUMNS.
+* CHPR2 T PUT F FOR NO TEST. SAME COLUMNS.
+*
+* See:
+*
+* Dongarra J. J., Du Croz J. J., Hammarling S. and Hanson R. J..
+* An extended set of Fortran Basic Linear Algebra Subprograms.
+*
+* Technical Memoranda Nos. 41 (revision 3) and 81, Mathematics
+* and Computer Science Division, Argonne National Laboratory,
+* 9700 South Cass Avenue, Argonne, Illinois 60439, US.
+*
+* Or
+*
+* NAG Technical Reports TR3/87 and TR4/87, Numerical Algorithms
+* Group Ltd., NAG Central Office, 256 Banbury Road, Oxford
+* OX2 7DE, UK, and Numerical Algorithms Group Inc., 1101 31st
+* Street, Suite 100, Downers Grove, Illinois 60515-1263, USA.
+*
+*
+* -- Written on 10-August-1987.
+* Richard Hanson, Sandia National Labs.
+* Jeremy Du Croz, NAG Central Office.
+*
+* .. Parameters ..
+ INTEGER NIN
+ PARAMETER ( NIN = 5 )
+ INTEGER NSUBS
+ PARAMETER ( NSUBS = 17 )
+ COMPLEX ZERO, ONE
+ PARAMETER ( ZERO = ( 0.0, 0.0 ), ONE = ( 1.0, 0.0 ) )
+ REAL RZERO, RHALF, RONE
+ PARAMETER ( RZERO = 0.0, RHALF = 0.5, RONE = 1.0 )
+ INTEGER NMAX, INCMAX
+ PARAMETER ( NMAX = 65, INCMAX = 2 )
+ INTEGER NINMAX, NIDMAX, NKBMAX, NALMAX, NBEMAX
+ PARAMETER ( NINMAX = 7, NIDMAX = 9, NKBMAX = 7,
+ $ NALMAX = 7, NBEMAX = 7 )
+* .. Local Scalars ..
+ REAL EPS, ERR, THRESH
+ INTEGER I, ISNUM, J, N, NALF, NBET, NIDIM, NINC, NKB,
+ $ NOUT, NTRA
+ LOGICAL FATAL, LTESTT, REWI, SAME, SFATAL, TRACE,
+ $ TSTERR
+ CHARACTER*1 TRANS
+ CHARACTER*6 SNAMET
+ CHARACTER*32 SNAPS, SUMMRY
+* .. Local Arrays ..
+ COMPLEX A( NMAX, NMAX ), AA( NMAX*NMAX ),
+ $ ALF( NALMAX ), AS( NMAX*NMAX ), BET( NBEMAX ),
+ $ X( NMAX ), XS( NMAX*INCMAX ),
+ $ XX( NMAX*INCMAX ), Y( NMAX ),
+ $ YS( NMAX*INCMAX ), YT( NMAX ),
+ $ YY( NMAX*INCMAX ), Z( 2*NMAX )
+ REAL G( NMAX )
+ INTEGER IDIM( NIDMAX ), INC( NINMAX ), KB( NKBMAX )
+ LOGICAL LTEST( NSUBS )
+ CHARACTER*6 SNAMES( NSUBS )
+* .. External Functions ..
+ REAL SDIFF
+ LOGICAL LCE
+ EXTERNAL SDIFF, LCE
+* .. External Subroutines ..
+ EXTERNAL CCHK1, CCHK2, CCHK3, CCHK4, CCHK5, CCHK6,
+ $ CCHKE, CMVCH
+* .. Intrinsic Functions ..
+ INTRINSIC ABS, MAX, MIN
+* .. Scalars in Common ..
+ INTEGER INFOT, NOUTC
+ LOGICAL LERR, OK
+ CHARACTER*6 SRNAMT
+* .. Common blocks ..
+ COMMON /INFOC/INFOT, NOUTC, OK, LERR
+ COMMON /SRNAMC/SRNAMT
+* .. Data statements ..
+ DATA SNAMES/'CGEMV ', 'CGBMV ', 'CHEMV ', 'CHBMV ',
+ $ 'CHPMV ', 'CTRMV ', 'CTBMV ', 'CTPMV ',
+ $ 'CTRSV ', 'CTBSV ', 'CTPSV ', 'CGERC ',
+ $ 'CGERU ', 'CHER ', 'CHPR ', 'CHER2 ',
+ $ 'CHPR2 '/
+* .. Executable Statements ..
+*
+* Read name and unit number for summary output file and open file.
+*
+ READ( NIN, FMT = * )SUMMRY
+ READ( NIN, FMT = * )NOUT
+ OPEN( NOUT, FILE = SUMMRY, STATUS = 'NEW' )
+ NOUTC = NOUT
+*
+* Read name and unit number for snapshot output file and open file.
+*
+ READ( NIN, FMT = * )SNAPS
+ READ( NIN, FMT = * )NTRA
+ TRACE = NTRA.GE.0
+ IF( TRACE )THEN
+ OPEN( NTRA, FILE = SNAPS, STATUS = 'NEW' )
+ END IF
+* Read the flag that directs rewinding of the snapshot file.
+ READ( NIN, FMT = * )REWI
+ REWI = REWI.AND.TRACE
+* Read the flag that directs stopping on any failure.
+ READ( NIN, FMT = * )SFATAL
+* Read the flag that indicates whether error exits are to be tested.
+ READ( NIN, FMT = * )TSTERR
+* Read the threshold value of the test ratio
+ READ( NIN, FMT = * )THRESH
+*
+* Read and check the parameter values for the tests.
+*
+* Values of N
+ READ( NIN, FMT = * )NIDIM
+ IF( NIDIM.LT.1.OR.NIDIM.GT.NIDMAX )THEN
+ WRITE( NOUT, FMT = 9997 )'N', NIDMAX
+ GO TO 230
+ END IF
+ READ( NIN, FMT = * )( IDIM( I ), I = 1, NIDIM )
+ DO 10 I = 1, NIDIM
+ IF( IDIM( I ).LT.0.OR.IDIM( I ).GT.NMAX )THEN
+ WRITE( NOUT, FMT = 9996 )NMAX
+ GO TO 230
+ END IF
+ 10 CONTINUE
+* Values of K
+ READ( NIN, FMT = * )NKB
+ IF( NKB.LT.1.OR.NKB.GT.NKBMAX )THEN
+ WRITE( NOUT, FMT = 9997 )'K', NKBMAX
+ GO TO 230
+ END IF
+ READ( NIN, FMT = * )( KB( I ), I = 1, NKB )
+ DO 20 I = 1, NKB
+ IF( KB( I ).LT.0 )THEN
+ WRITE( NOUT, FMT = 9995 )
+ GO TO 230
+ END IF
+ 20 CONTINUE
+* Values of INCX and INCY
+ READ( NIN, FMT = * )NINC
+ IF( NINC.LT.1.OR.NINC.GT.NINMAX )THEN
+ WRITE( NOUT, FMT = 9997 )'INCX AND INCY', NINMAX
+ GO TO 230
+ END IF
+ READ( NIN, FMT = * )( INC( I ), I = 1, NINC )
+ DO 30 I = 1, NINC
+ IF( INC( I ).EQ.0.OR.ABS( INC( I ) ).GT.INCMAX )THEN
+ WRITE( NOUT, FMT = 9994 )INCMAX
+ GO TO 230
+ END IF
+ 30 CONTINUE
+* Values of ALPHA
+ READ( NIN, FMT = * )NALF
+ IF( NALF.LT.1.OR.NALF.GT.NALMAX )THEN
+ WRITE( NOUT, FMT = 9997 )'ALPHA', NALMAX
+ GO TO 230
+ END IF
+ READ( NIN, FMT = * )( ALF( I ), I = 1, NALF )
+* Values of BETA
+ READ( NIN, FMT = * )NBET
+ IF( NBET.LT.1.OR.NBET.GT.NBEMAX )THEN
+ WRITE( NOUT, FMT = 9997 )'BETA', NBEMAX
+ GO TO 230
+ END IF
+ READ( NIN, FMT = * )( BET( I ), I = 1, NBET )
+*
+* Report values of parameters.
+*
+ WRITE( NOUT, FMT = 9993 )
+ WRITE( NOUT, FMT = 9992 )( IDIM( I ), I = 1, NIDIM )
+ WRITE( NOUT, FMT = 9991 )( KB( I ), I = 1, NKB )
+ WRITE( NOUT, FMT = 9990 )( INC( I ), I = 1, NINC )
+ WRITE( NOUT, FMT = 9989 )( ALF( I ), I = 1, NALF )
+ WRITE( NOUT, FMT = 9988 )( BET( I ), I = 1, NBET )
+ IF( .NOT.TSTERR )THEN
+ WRITE( NOUT, FMT = * )
+ WRITE( NOUT, FMT = 9980 )
+ END IF
+ WRITE( NOUT, FMT = * )
+ WRITE( NOUT, FMT = 9999 )THRESH
+ WRITE( NOUT, FMT = * )
+*
+* Read names of subroutines and flags which indicate
+* whether they are to be tested.
+*
+ DO 40 I = 1, NSUBS
+ LTEST( I ) = .FALSE.
+ 40 CONTINUE
+ 50 READ( NIN, FMT = 9984, END = 80 )SNAMET, LTESTT
+ DO 60 I = 1, NSUBS
+ IF( SNAMET.EQ.SNAMES( I ) )
+ $ GO TO 70
+ 60 CONTINUE
+ WRITE( NOUT, FMT = 9986 )SNAMET
+ STOP
+ 70 LTEST( I ) = LTESTT
+ GO TO 50
+*
+ 80 CONTINUE
+ CLOSE ( NIN )
+*
+* Compute EPS (the machine precision).
+*
+ EPS = RONE
+ 90 CONTINUE
+ IF( SDIFF( RONE + EPS, RONE ).EQ.RZERO )
+ $ GO TO 100
+ EPS = RHALF*EPS
+ GO TO 90
+ 100 CONTINUE
+ EPS = EPS + EPS
+ WRITE( NOUT, FMT = 9998 )EPS
+*
+* Check the reliability of CMVCH using exact data.
+*
+ N = MIN( 32, NMAX )
+ DO 120 J = 1, N
+ DO 110 I = 1, N
+ A( I, J ) = MAX( I - J + 1, 0 )
+ 110 CONTINUE
+ X( J ) = J
+ Y( J ) = ZERO
+ 120 CONTINUE
+ DO 130 J = 1, N
+ YY( J ) = J*( ( J + 1 )*J )/2 - ( ( J + 1 )*J*( J - 1 ) )/3
+ 130 CONTINUE
+* YY holds the exact result. On exit from CMVCH YT holds
+* the result computed by CMVCH.
+ TRANS = 'N'
+ CALL CMVCH( TRANS, N, N, ONE, A, NMAX, X, 1, ZERO, Y, 1, YT, G,
+ $ YY, EPS, ERR, FATAL, NOUT, .TRUE. )
+ SAME = LCE( YY, YT, N )
+ IF( .NOT.SAME.OR.ERR.NE.RZERO )THEN
+ WRITE( NOUT, FMT = 9985 )TRANS, SAME, ERR
+ STOP
+ END IF
+ TRANS = 'T'
+ CALL CMVCH( TRANS, N, N, ONE, A, NMAX, X, -1, ZERO, Y, -1, YT, G,
+ $ YY, EPS, ERR, FATAL, NOUT, .TRUE. )
+ SAME = LCE( YY, YT, N )
+ IF( .NOT.SAME.OR.ERR.NE.RZERO )THEN
+ WRITE( NOUT, FMT = 9985 )TRANS, SAME, ERR
+ STOP
+ END IF
+*
+* Test each subroutine in turn.
+*
+ DO 210 ISNUM = 1, NSUBS
+ WRITE( NOUT, FMT = * )
+ IF( .NOT.LTEST( ISNUM ) )THEN
+* Subprogram is not to be tested.
+ WRITE( NOUT, FMT = 9983 )SNAMES( ISNUM )
+ ELSE
+ SRNAMT = SNAMES( ISNUM )
+* Test error exits.
+ IF( TSTERR )THEN
+ CALL CCHKE( ISNUM, SNAMES( ISNUM ), NOUT )
+ WRITE( NOUT, FMT = * )
+ END IF
+* Test computations.
+ INFOT = 0
+ OK = .TRUE.
+ FATAL = .FALSE.
+ GO TO ( 140, 140, 150, 150, 150, 160, 160,
+ $ 160, 160, 160, 160, 170, 170, 180,
+ $ 180, 190, 190 )ISNUM
+* Test CGEMV, 01, and CGBMV, 02.
+ 140 CALL CCHK1( SNAMES( ISNUM ), EPS, THRESH, NOUT, NTRA, TRACE,
+ $ REWI, FATAL, NIDIM, IDIM, NKB, KB, NALF, ALF,
+ $ NBET, BET, NINC, INC, NMAX, INCMAX, A, AA, AS,
+ $ X, XX, XS, Y, YY, YS, YT, G )
+ GO TO 200
+* Test CHEMV, 03, CHBMV, 04, and CHPMV, 05.
+ 150 CALL CCHK2( SNAMES( ISNUM ), EPS, THRESH, NOUT, NTRA, TRACE,
+ $ REWI, FATAL, NIDIM, IDIM, NKB, KB, NALF, ALF,
+ $ NBET, BET, NINC, INC, NMAX, INCMAX, A, AA, AS,
+ $ X, XX, XS, Y, YY, YS, YT, G )
+ GO TO 200
+* Test CTRMV, 06, CTBMV, 07, CTPMV, 08,
+* CTRSV, 09, CTBSV, 10, and CTPSV, 11.
+ 160 CALL CCHK3( SNAMES( ISNUM ), EPS, THRESH, NOUT, NTRA, TRACE,
+ $ REWI, FATAL, NIDIM, IDIM, NKB, KB, NINC, INC,
+ $ NMAX, INCMAX, A, AA, AS, Y, YY, YS, YT, G, Z )
+ GO TO 200
+* Test CGERC, 12, CGERU, 13.
+ 170 CALL CCHK4( SNAMES( ISNUM ), EPS, THRESH, NOUT, NTRA, TRACE,
+ $ REWI, FATAL, NIDIM, IDIM, NALF, ALF, NINC, INC,
+ $ NMAX, INCMAX, A, AA, AS, X, XX, XS, Y, YY, YS,
+ $ YT, G, Z )
+ GO TO 200
+* Test CHER, 14, and CHPR, 15.
+ 180 CALL CCHK5( SNAMES( ISNUM ), EPS, THRESH, NOUT, NTRA, TRACE,
+ $ REWI, FATAL, NIDIM, IDIM, NALF, ALF, NINC, INC,
+ $ NMAX, INCMAX, A, AA, AS, X, XX, XS, Y, YY, YS,
+ $ YT, G, Z )
+ GO TO 200
+* Test CHER2, 16, and CHPR2, 17.
+ 190 CALL CCHK6( SNAMES( ISNUM ), EPS, THRESH, NOUT, NTRA, TRACE,
+ $ REWI, FATAL, NIDIM, IDIM, NALF, ALF, NINC, INC,
+ $ NMAX, INCMAX, A, AA, AS, X, XX, XS, Y, YY, YS,
+ $ YT, G, Z )
+*
+ 200 IF( FATAL.AND.SFATAL )
+ $ GO TO 220
+ END IF
+ 210 CONTINUE
+ WRITE( NOUT, FMT = 9982 )
+ GO TO 240
+*
+ 220 CONTINUE
+ WRITE( NOUT, FMT = 9981 )
+ GO TO 240
+*
+ 230 CONTINUE
+ WRITE( NOUT, FMT = 9987 )
+*
+ 240 CONTINUE
+ IF( TRACE )
+ $ CLOSE ( NTRA )
+ CLOSE ( NOUT )
+ STOP
+*
+ 9999 FORMAT( ' ROUTINES PASS COMPUTATIONAL TESTS IF TEST RATIO IS LES',
+ $ 'S THAN', F8.2 )
+ 9998 FORMAT( ' RELATIVE MACHINE PRECISION IS TAKEN TO BE', 1P, E9.1 )
+ 9997 FORMAT( ' NUMBER OF VALUES OF ', A, ' IS LESS THAN 1 OR GREATER ',
+ $ 'THAN ', I2 )
+ 9996 FORMAT( ' VALUE OF N IS LESS THAN 0 OR GREATER THAN ', I2 )
+ 9995 FORMAT( ' VALUE OF K IS LESS THAN 0' )
+ 9994 FORMAT( ' ABSOLUTE VALUE OF INCX OR INCY IS 0 OR GREATER THAN ',
+ $ I2 )
+ 9993 FORMAT( ' TESTS OF THE COMPLEX LEVEL 2 BLAS', //' THE F',
+ $ 'OLLOWING PARAMETER VALUES WILL BE USED:' )
+ 9992 FORMAT( ' FOR N ', 9I6 )
+ 9991 FORMAT( ' FOR K ', 7I6 )
+ 9990 FORMAT( ' FOR INCX AND INCY ', 7I6 )
+ 9989 FORMAT( ' FOR ALPHA ',
+ $ 7( '(', F4.1, ',', F4.1, ') ', : ) )
+ 9988 FORMAT( ' FOR BETA ',
+ $ 7( '(', F4.1, ',', F4.1, ') ', : ) )
+ 9987 FORMAT( ' AMEND DATA FILE OR INCREASE ARRAY SIZES IN PROGRAM',
+ $ /' ******* TESTS ABANDONED *******' )
+ 9986 FORMAT( ' SUBPROGRAM NAME ', A6, ' NOT RECOGNIZED', /' ******* T',
+ $ 'ESTS ABANDONED *******' )
+ 9985 FORMAT( ' ERROR IN CMVCH - IN-LINE DOT PRODUCTS ARE BEING EVALU',
+ $ 'ATED WRONGLY.', /' CMVCH WAS CALLED WITH TRANS = ', A1,
+ $ ' AND RETURNED SAME = ', L1, ' AND ERR = ', F12.3, '.', /
+ $ ' THIS MAY BE DUE TO FAULTS IN THE ARITHMETIC OR THE COMPILER.'
+ $ , /' ******* TESTS ABANDONED *******' )
+ 9984 FORMAT( A6, L2 )
+ 9983 FORMAT( 1X, A6, ' WAS NOT TESTED' )
+ 9982 FORMAT( /' END OF TESTS' )
+ 9981 FORMAT( /' ******* FATAL ERROR - TESTS ABANDONED *******' )
+ 9980 FORMAT( ' ERROR-EXITS WILL NOT BE TESTED' )
+*
+* End of CBLAT2.
+*
+ END
+ SUBROUTINE CCHK1( SNAME, EPS, THRESH, NOUT, NTRA, TRACE, REWI,
+ $ FATAL, NIDIM, IDIM, NKB, KB, NALF, ALF, NBET,
+ $ BET, NINC, INC, NMAX, INCMAX, A, AA, AS, X, XX,
+ $ XS, Y, YY, YS, YT, G )
+*
+* Tests CGEMV and CGBMV.
+*
+* Auxiliary routine for test program for Level 2 Blas.
+*
+* -- Written on 10-August-1987.
+* Richard Hanson, Sandia National Labs.
+* Jeremy Du Croz, NAG Central Office.
+*
+* .. Parameters ..
+ COMPLEX ZERO, HALF
+ PARAMETER ( ZERO = ( 0.0, 0.0 ), HALF = ( 0.5, 0.0 ) )
+ REAL RZERO
+ PARAMETER ( RZERO = 0.0 )
+* .. Scalar Arguments ..
+ REAL EPS, THRESH
+ INTEGER INCMAX, NALF, NBET, NIDIM, NINC, NKB, NMAX,
+ $ NOUT, NTRA
+ LOGICAL FATAL, REWI, TRACE
+ CHARACTER*6 SNAME
+* .. Array Arguments ..
+ COMPLEX A( NMAX, NMAX ), AA( NMAX*NMAX ), ALF( NALF ),
+ $ AS( NMAX*NMAX ), BET( NBET ), X( NMAX ),
+ $ XS( NMAX*INCMAX ), XX( NMAX*INCMAX ),
+ $ Y( NMAX ), YS( NMAX*INCMAX ), YT( NMAX ),
+ $ YY( NMAX*INCMAX )
+ REAL G( NMAX )
+ INTEGER IDIM( NIDIM ), INC( NINC ), KB( NKB )
+* .. Local Scalars ..
+ COMPLEX ALPHA, ALS, BETA, BLS, TRANSL
+ REAL ERR, ERRMAX
+ INTEGER I, IA, IB, IC, IKU, IM, IN, INCX, INCXS, INCY,
+ $ INCYS, IX, IY, KL, KLS, KU, KUS, LAA, LDA,
+ $ LDAS, LX, LY, M, ML, MS, N, NARGS, NC, ND, NK,
+ $ NL, NS
+ LOGICAL BANDED, FULL, NULL, RESET, SAME, TRAN
+ CHARACTER*1 TRANS, TRANSS
+ CHARACTER*3 ICH
+* .. Local Arrays ..
+ LOGICAL ISAME( 13 )
+* .. External Functions ..
+ LOGICAL LCE, LCERES
+ EXTERNAL LCE, LCERES
+* .. External Subroutines ..
+ EXTERNAL CGBMV, CGEMV, CMAKE, CMVCH
+* .. Intrinsic Functions ..
+ INTRINSIC ABS, MAX, MIN
+* .. Scalars in Common ..
+ INTEGER INFOT, NOUTC
+ LOGICAL LERR, OK
+* .. Common blocks ..
+ COMMON /INFOC/INFOT, NOUTC, OK, LERR
+* .. Data statements ..
+ DATA ICH/'NTC'/
+* .. Executable Statements ..
+ FULL = SNAME( 3: 3 ).EQ.'E'
+ BANDED = SNAME( 3: 3 ).EQ.'B'
+* Define the number of arguments.
+ IF( FULL )THEN
+ NARGS = 11
+ ELSE IF( BANDED )THEN
+ NARGS = 13
+ END IF
+*
+ NC = 0
+ RESET = .TRUE.
+ ERRMAX = RZERO
+*
+ DO 120 IN = 1, NIDIM
+ N = IDIM( IN )
+ ND = N/2 + 1
+*
+ DO 110 IM = 1, 2
+ IF( IM.EQ.1 )
+ $ M = MAX( N - ND, 0 )
+ IF( IM.EQ.2 )
+ $ M = MIN( N + ND, NMAX )
+*
+ IF( BANDED )THEN
+ NK = NKB
+ ELSE
+ NK = 1
+ END IF
+ DO 100 IKU = 1, NK
+ IF( BANDED )THEN
+ KU = KB( IKU )
+ KL = MAX( KU - 1, 0 )
+ ELSE
+ KU = N - 1
+ KL = M - 1
+ END IF
+* Set LDA to 1 more than minimum value if room.
+ IF( BANDED )THEN
+ LDA = KL + KU + 1
+ ELSE
+ LDA = M
+ END IF
+ IF( LDA.LT.NMAX )
+ $ LDA = LDA + 1
+* Skip tests if not enough room.
+ IF( LDA.GT.NMAX )
+ $ GO TO 100
+ LAA = LDA*N
+ NULL = N.LE.0.OR.M.LE.0
+*
+* Generate the matrix A.
+*
+ TRANSL = ZERO
+ CALL CMAKE( SNAME( 2: 3 ), ' ', ' ', M, N, A, NMAX, AA,
+ $ LDA, KL, KU, RESET, TRANSL )
+*
+ DO 90 IC = 1, 3
+ TRANS = ICH( IC: IC )
+ TRAN = TRANS.EQ.'T'.OR.TRANS.EQ.'C'
+*
+ IF( TRAN )THEN
+ ML = N
+ NL = M
+ ELSE
+ ML = M
+ NL = N
+ END IF
+*
+ DO 80 IX = 1, NINC
+ INCX = INC( IX )
+ LX = ABS( INCX )*NL
+*
+* Generate the vector X.
+*
+ TRANSL = HALF
+ CALL CMAKE( 'GE', ' ', ' ', 1, NL, X, 1, XX,
+ $ ABS( INCX ), 0, NL - 1, RESET, TRANSL )
+ IF( NL.GT.1 )THEN
+ X( NL/2 ) = ZERO
+ XX( 1 + ABS( INCX )*( NL/2 - 1 ) ) = ZERO
+ END IF
+*
+ DO 70 IY = 1, NINC
+ INCY = INC( IY )
+ LY = ABS( INCY )*ML
+*
+ DO 60 IA = 1, NALF
+ ALPHA = ALF( IA )
+*
+ DO 50 IB = 1, NBET
+ BETA = BET( IB )
+*
+* Generate the vector Y.
+*
+ TRANSL = ZERO
+ CALL CMAKE( 'GE', ' ', ' ', 1, ML, Y, 1,
+ $ YY, ABS( INCY ), 0, ML - 1,
+ $ RESET, TRANSL )
+*
+ NC = NC + 1
+*
+* Save every datum before calling the
+* subroutine.
+*
+ TRANSS = TRANS
+ MS = M
+ NS = N
+ KLS = KL
+ KUS = KU
+ ALS = ALPHA
+ DO 10 I = 1, LAA
+ AS( I ) = AA( I )
+ 10 CONTINUE
+ LDAS = LDA
+ DO 20 I = 1, LX
+ XS( I ) = XX( I )
+ 20 CONTINUE
+ INCXS = INCX
+ BLS = BETA
+ DO 30 I = 1, LY
+ YS( I ) = YY( I )
+ 30 CONTINUE
+ INCYS = INCY
+*
+* Call the subroutine.
+*
+ IF( FULL )THEN
+ IF( TRACE )
+ $ WRITE( NTRA, FMT = 9994 )NC, SNAME,
+ $ TRANS, M, N, ALPHA, LDA, INCX, BETA,
+ $ INCY
+ IF( REWI )
+ $ REWIND NTRA
+ CALL CGEMV( TRANS, M, N, ALPHA, AA,
+ $ LDA, XX, INCX, BETA, YY,
+ $ INCY )
+ ELSE IF( BANDED )THEN
+ IF( TRACE )
+ $ WRITE( NTRA, FMT = 9995 )NC, SNAME,
+ $ TRANS, M, N, KL, KU, ALPHA, LDA,
+ $ INCX, BETA, INCY
+ IF( REWI )
+ $ REWIND NTRA
+ CALL CGBMV( TRANS, M, N, KL, KU, ALPHA,
+ $ AA, LDA, XX, INCX, BETA,
+ $ YY, INCY )
+ END IF
+*
+* Check if error-exit was taken incorrectly.
+*
+ IF( .NOT.OK )THEN
+ WRITE( NOUT, FMT = 9993 )
+ FATAL = .TRUE.
+ GO TO 130
+ END IF
+*
+* See what data changed inside subroutines.
+*
+ ISAME( 1 ) = TRANS.EQ.TRANSS
+ ISAME( 2 ) = MS.EQ.M
+ ISAME( 3 ) = NS.EQ.N
+ IF( FULL )THEN
+ ISAME( 4 ) = ALS.EQ.ALPHA
+ ISAME( 5 ) = LCE( AS, AA, LAA )
+ ISAME( 6 ) = LDAS.EQ.LDA
+ ISAME( 7 ) = LCE( XS, XX, LX )
+ ISAME( 8 ) = INCXS.EQ.INCX
+ ISAME( 9 ) = BLS.EQ.BETA
+ IF( NULL )THEN
+ ISAME( 10 ) = LCE( YS, YY, LY )
+ ELSE
+ ISAME( 10 ) = LCERES( 'GE', ' ', 1,
+ $ ML, YS, YY,
+ $ ABS( INCY ) )
+ END IF
+ ISAME( 11 ) = INCYS.EQ.INCY
+ ELSE IF( BANDED )THEN
+ ISAME( 4 ) = KLS.EQ.KL
+ ISAME( 5 ) = KUS.EQ.KU
+ ISAME( 6 ) = ALS.EQ.ALPHA
+ ISAME( 7 ) = LCE( AS, AA, LAA )
+ ISAME( 8 ) = LDAS.EQ.LDA
+ ISAME( 9 ) = LCE( XS, XX, LX )
+ ISAME( 10 ) = INCXS.EQ.INCX
+ ISAME( 11 ) = BLS.EQ.BETA
+ IF( NULL )THEN
+ ISAME( 12 ) = LCE( YS, YY, LY )
+ ELSE
+ ISAME( 12 ) = LCERES( 'GE', ' ', 1,
+ $ ML, YS, YY,
+ $ ABS( INCY ) )
+ END IF
+ ISAME( 13 ) = INCYS.EQ.INCY
+ END IF
+*
+* If data was incorrectly changed, report
+* and return.
+*
+ SAME = .TRUE.
+ DO 40 I = 1, NARGS
+ SAME = SAME.AND.ISAME( I )
+ IF( .NOT.ISAME( I ) )
+ $ WRITE( NOUT, FMT = 9998 )I
+ 40 CONTINUE
+ IF( .NOT.SAME )THEN
+ FATAL = .TRUE.
+ GO TO 130
+ END IF
+*
+ IF( .NOT.NULL )THEN
+*
+* Check the result.
+*
+ CALL CMVCH( TRANS, M, N, ALPHA, A,
+ $ NMAX, X, INCX, BETA, Y,
+ $ INCY, YT, G, YY, EPS, ERR,
+ $ FATAL, NOUT, .TRUE. )
+ ERRMAX = MAX( ERRMAX, ERR )
+* If got really bad answer, report and
+* return.
+ IF( FATAL )
+ $ GO TO 130
+ ELSE
+* Avoid repeating tests with M.le.0 or
+* N.le.0.
+ GO TO 110
+ END IF
+*
+ 50 CONTINUE
+*
+ 60 CONTINUE
+*
+ 70 CONTINUE
+*
+ 80 CONTINUE
+*
+ 90 CONTINUE
+*
+ 100 CONTINUE
+*
+ 110 CONTINUE
+*
+ 120 CONTINUE
+*
+* Report result.
+*
+ IF( ERRMAX.LT.THRESH )THEN
+ WRITE( NOUT, FMT = 9999 )SNAME, NC
+ ELSE
+ WRITE( NOUT, FMT = 9997 )SNAME, NC, ERRMAX
+ END IF
+ GO TO 140
+*
+ 130 CONTINUE
+ WRITE( NOUT, FMT = 9996 )SNAME
+ IF( FULL )THEN
+ WRITE( NOUT, FMT = 9994 )NC, SNAME, TRANS, M, N, ALPHA, LDA,
+ $ INCX, BETA, INCY
+ ELSE IF( BANDED )THEN
+ WRITE( NOUT, FMT = 9995 )NC, SNAME, TRANS, M, N, KL, KU,
+ $ ALPHA, LDA, INCX, BETA, INCY
+ END IF
+*
+ 140 CONTINUE
+ RETURN
+*
+ 9999 FORMAT( ' ', A6, ' PASSED THE COMPUTATIONAL TESTS (', I6, ' CALL',
+ $ 'S)' )
+ 9998 FORMAT( ' ******* FATAL ERROR - PARAMETER NUMBER ', I2, ' WAS CH',
+ $ 'ANGED INCORRECTLY *******' )
+ 9997 FORMAT( ' ', A6, ' COMPLETED THE COMPUTATIONAL TESTS (', I6, ' C',
+ $ 'ALLS)', /' ******* BUT WITH MAXIMUM TEST RATIO', F8.2,
+ $ ' - SUSPECT *******' )
+ 9996 FORMAT( ' ******* ', A6, ' FAILED ON CALL NUMBER:' )
+ 9995 FORMAT( 1X, I6, ': ', A6, '(''', A1, ''',', 4( I3, ',' ), '(',
+ $ F4.1, ',', F4.1, '), A,', I3, ', X,', I2, ',(', F4.1, ',',
+ $ F4.1, '), Y,', I2, ') .' )
+ 9994 FORMAT( 1X, I6, ': ', A6, '(''', A1, ''',', 2( I3, ',' ), '(',
+ $ F4.1, ',', F4.1, '), A,', I3, ', X,', I2, ',(', F4.1, ',',
+ $ F4.1, '), Y,', I2, ') .' )
+ 9993 FORMAT( ' ******* FATAL ERROR - ERROR-EXIT TAKEN ON VALID CALL *',
+ $ '******' )
+*
+* End of CCHK1.
+*
+ END
+ SUBROUTINE CCHK2( SNAME, EPS, THRESH, NOUT, NTRA, TRACE, REWI,
+ $ FATAL, NIDIM, IDIM, NKB, KB, NALF, ALF, NBET,
+ $ BET, NINC, INC, NMAX, INCMAX, A, AA, AS, X, XX,
+ $ XS, Y, YY, YS, YT, G )
+*
+* Tests CHEMV, CHBMV and CHPMV.
+*
+* Auxiliary routine for test program for Level 2 Blas.
+*
+* -- Written on 10-August-1987.
+* Richard Hanson, Sandia National Labs.
+* Jeremy Du Croz, NAG Central Office.
+*
+* .. Parameters ..
+ COMPLEX ZERO, HALF
+ PARAMETER ( ZERO = ( 0.0, 0.0 ), HALF = ( 0.5, 0.0 ) )
+ REAL RZERO
+ PARAMETER ( RZERO = 0.0 )
+* .. Scalar Arguments ..
+ REAL EPS, THRESH
+ INTEGER INCMAX, NALF, NBET, NIDIM, NINC, NKB, NMAX,
+ $ NOUT, NTRA
+ LOGICAL FATAL, REWI, TRACE
+ CHARACTER*6 SNAME
+* .. Array Arguments ..
+ COMPLEX A( NMAX, NMAX ), AA( NMAX*NMAX ), ALF( NALF ),
+ $ AS( NMAX*NMAX ), BET( NBET ), X( NMAX ),
+ $ XS( NMAX*INCMAX ), XX( NMAX*INCMAX ),
+ $ Y( NMAX ), YS( NMAX*INCMAX ), YT( NMAX ),
+ $ YY( NMAX*INCMAX )
+ REAL G( NMAX )
+ INTEGER IDIM( NIDIM ), INC( NINC ), KB( NKB )
+* .. Local Scalars ..
+ COMPLEX ALPHA, ALS, BETA, BLS, TRANSL
+ REAL ERR, ERRMAX
+ INTEGER I, IA, IB, IC, IK, IN, INCX, INCXS, INCY,
+ $ INCYS, IX, IY, K, KS, LAA, LDA, LDAS, LX, LY,
+ $ N, NARGS, NC, NK, NS
+ LOGICAL BANDED, FULL, NULL, PACKED, RESET, SAME
+ CHARACTER*1 UPLO, UPLOS
+ CHARACTER*2 ICH
+* .. Local Arrays ..
+ LOGICAL ISAME( 13 )
+* .. External Functions ..
+ LOGICAL LCE, LCERES
+ EXTERNAL LCE, LCERES
+* .. External Subroutines ..
+ EXTERNAL CHBMV, CHEMV, CHPMV, CMAKE, CMVCH
+* .. Intrinsic Functions ..
+ INTRINSIC ABS, MAX
+* .. Scalars in Common ..
+ INTEGER INFOT, NOUTC
+ LOGICAL LERR, OK
+* .. Common blocks ..
+ COMMON /INFOC/INFOT, NOUTC, OK, LERR
+* .. Data statements ..
+ DATA ICH/'UL'/
+* .. Executable Statements ..
+ FULL = SNAME( 3: 3 ).EQ.'E'
+ BANDED = SNAME( 3: 3 ).EQ.'B'
+ PACKED = SNAME( 3: 3 ).EQ.'P'
+* Define the number of arguments.
+ IF( FULL )THEN
+ NARGS = 10
+ ELSE IF( BANDED )THEN
+ NARGS = 11
+ ELSE IF( PACKED )THEN
+ NARGS = 9
+ END IF
+*
+ NC = 0
+ RESET = .TRUE.
+ ERRMAX = RZERO
+*
+ DO 110 IN = 1, NIDIM
+ N = IDIM( IN )
+*
+ IF( BANDED )THEN
+ NK = NKB
+ ELSE
+ NK = 1
+ END IF
+ DO 100 IK = 1, NK
+ IF( BANDED )THEN
+ K = KB( IK )
+ ELSE
+ K = N - 1
+ END IF
+* Set LDA to 1 more than minimum value if room.
+ IF( BANDED )THEN
+ LDA = K + 1
+ ELSE
+ LDA = N
+ END IF
+ IF( LDA.LT.NMAX )
+ $ LDA = LDA + 1
+* Skip tests if not enough room.
+ IF( LDA.GT.NMAX )
+ $ GO TO 100
+ IF( PACKED )THEN
+ LAA = ( N*( N + 1 ) )/2
+ ELSE
+ LAA = LDA*N
+ END IF
+ NULL = N.LE.0
+*
+ DO 90 IC = 1, 2
+ UPLO = ICH( IC: IC )
+*
+* Generate the matrix A.
+*
+ TRANSL = ZERO
+ CALL CMAKE( SNAME( 2: 3 ), UPLO, ' ', N, N, A, NMAX, AA,
+ $ LDA, K, K, RESET, TRANSL )
+*
+ DO 80 IX = 1, NINC
+ INCX = INC( IX )
+ LX = ABS( INCX )*N
+*
+* Generate the vector X.
+*
+ TRANSL = HALF
+ CALL CMAKE( 'GE', ' ', ' ', 1, N, X, 1, XX,
+ $ ABS( INCX ), 0, N - 1, RESET, TRANSL )
+ IF( N.GT.1 )THEN
+ X( N/2 ) = ZERO
+ XX( 1 + ABS( INCX )*( N/2 - 1 ) ) = ZERO
+ END IF
+*
+ DO 70 IY = 1, NINC
+ INCY = INC( IY )
+ LY = ABS( INCY )*N
+*
+ DO 60 IA = 1, NALF
+ ALPHA = ALF( IA )
+*
+ DO 50 IB = 1, NBET
+ BETA = BET( IB )
+*
+* Generate the vector Y.
+*
+ TRANSL = ZERO
+ CALL CMAKE( 'GE', ' ', ' ', 1, N, Y, 1, YY,
+ $ ABS( INCY ), 0, N - 1, RESET,
+ $ TRANSL )
+*
+ NC = NC + 1
+*
+* Save every datum before calling the
+* subroutine.
+*
+ UPLOS = UPLO
+ NS = N
+ KS = K
+ ALS = ALPHA
+ DO 10 I = 1, LAA
+ AS( I ) = AA( I )
+ 10 CONTINUE
+ LDAS = LDA
+ DO 20 I = 1, LX
+ XS( I ) = XX( I )
+ 20 CONTINUE
+ INCXS = INCX
+ BLS = BETA
+ DO 30 I = 1, LY
+ YS( I ) = YY( I )
+ 30 CONTINUE
+ INCYS = INCY
+*
+* Call the subroutine.
+*
+ IF( FULL )THEN
+ IF( TRACE )
+ $ WRITE( NTRA, FMT = 9993 )NC, SNAME,
+ $ UPLO, N, ALPHA, LDA, INCX, BETA, INCY
+ IF( REWI )
+ $ REWIND NTRA
+ CALL CHEMV( UPLO, N, ALPHA, AA, LDA, XX,
+ $ INCX, BETA, YY, INCY )
+ ELSE IF( BANDED )THEN
+ IF( TRACE )
+ $ WRITE( NTRA, FMT = 9994 )NC, SNAME,
+ $ UPLO, N, K, ALPHA, LDA, INCX, BETA,
+ $ INCY
+ IF( REWI )
+ $ REWIND NTRA
+ CALL CHBMV( UPLO, N, K, ALPHA, AA, LDA,
+ $ XX, INCX, BETA, YY, INCY )
+ ELSE IF( PACKED )THEN
+ IF( TRACE )
+ $ WRITE( NTRA, FMT = 9995 )NC, SNAME,
+ $ UPLO, N, ALPHA, INCX, BETA, INCY
+ IF( REWI )
+ $ REWIND NTRA
+ CALL CHPMV( UPLO, N, ALPHA, AA, XX, INCX,
+ $ BETA, YY, INCY )
+ END IF
+*
+* Check if error-exit was taken incorrectly.
+*
+ IF( .NOT.OK )THEN
+ WRITE( NOUT, FMT = 9992 )
+ FATAL = .TRUE.
+ GO TO 120
+ END IF
+*
+* See what data changed inside subroutines.
+*
+ ISAME( 1 ) = UPLO.EQ.UPLOS
+ ISAME( 2 ) = NS.EQ.N
+ IF( FULL )THEN
+ ISAME( 3 ) = ALS.EQ.ALPHA
+ ISAME( 4 ) = LCE( AS, AA, LAA )
+ ISAME( 5 ) = LDAS.EQ.LDA
+ ISAME( 6 ) = LCE( XS, XX, LX )
+ ISAME( 7 ) = INCXS.EQ.INCX
+ ISAME( 8 ) = BLS.EQ.BETA
+ IF( NULL )THEN
+ ISAME( 9 ) = LCE( YS, YY, LY )
+ ELSE
+ ISAME( 9 ) = LCERES( 'GE', ' ', 1, N,
+ $ YS, YY, ABS( INCY ) )
+ END IF
+ ISAME( 10 ) = INCYS.EQ.INCY
+ ELSE IF( BANDED )THEN
+ ISAME( 3 ) = KS.EQ.K
+ ISAME( 4 ) = ALS.EQ.ALPHA
+ ISAME( 5 ) = LCE( AS, AA, LAA )
+ ISAME( 6 ) = LDAS.EQ.LDA
+ ISAME( 7 ) = LCE( XS, XX, LX )
+ ISAME( 8 ) = INCXS.EQ.INCX
+ ISAME( 9 ) = BLS.EQ.BETA
+ IF( NULL )THEN
+ ISAME( 10 ) = LCE( YS, YY, LY )
+ ELSE
+ ISAME( 10 ) = LCERES( 'GE', ' ', 1, N,
+ $ YS, YY, ABS( INCY ) )
+ END IF
+ ISAME( 11 ) = INCYS.EQ.INCY
+ ELSE IF( PACKED )THEN
+ ISAME( 3 ) = ALS.EQ.ALPHA
+ ISAME( 4 ) = LCE( AS, AA, LAA )
+ ISAME( 5 ) = LCE( XS, XX, LX )
+ ISAME( 6 ) = INCXS.EQ.INCX
+ ISAME( 7 ) = BLS.EQ.BETA
+ IF( NULL )THEN
+ ISAME( 8 ) = LCE( YS, YY, LY )
+ ELSE
+ ISAME( 8 ) = LCERES( 'GE', ' ', 1, N,
+ $ YS, YY, ABS( INCY ) )
+ END IF
+ ISAME( 9 ) = INCYS.EQ.INCY
+ END IF
+*
+* If data was incorrectly changed, report and
+* return.
+*
+ SAME = .TRUE.
+ DO 40 I = 1, NARGS
+ SAME = SAME.AND.ISAME( I )
+ IF( .NOT.ISAME( I ) )
+ $ WRITE( NOUT, FMT = 9998 )I
+ 40 CONTINUE
+ IF( .NOT.SAME )THEN
+ FATAL = .TRUE.
+ GO TO 120
+ END IF
+*
+ IF( .NOT.NULL )THEN
+*
+* Check the result.
+*
+ CALL CMVCH( 'N', N, N, ALPHA, A, NMAX, X,
+ $ INCX, BETA, Y, INCY, YT, G,
+ $ YY, EPS, ERR, FATAL, NOUT,
+ $ .TRUE. )
+ ERRMAX = MAX( ERRMAX, ERR )
+* If got really bad answer, report and
+* return.
+ IF( FATAL )
+ $ GO TO 120
+ ELSE
+* Avoid repeating tests with N.le.0
+ GO TO 110
+ END IF
+*
+ 50 CONTINUE
+*
+ 60 CONTINUE
+*
+ 70 CONTINUE
+*
+ 80 CONTINUE
+*
+ 90 CONTINUE
+*
+ 100 CONTINUE
+*
+ 110 CONTINUE
+*
+* Report result.
+*
+ IF( ERRMAX.LT.THRESH )THEN
+ WRITE( NOUT, FMT = 9999 )SNAME, NC
+ ELSE
+ WRITE( NOUT, FMT = 9997 )SNAME, NC, ERRMAX
+ END IF
+ GO TO 130
+*
+ 120 CONTINUE
+ WRITE( NOUT, FMT = 9996 )SNAME
+ IF( FULL )THEN
+ WRITE( NOUT, FMT = 9993 )NC, SNAME, UPLO, N, ALPHA, LDA, INCX,
+ $ BETA, INCY
+ ELSE IF( BANDED )THEN
+ WRITE( NOUT, FMT = 9994 )NC, SNAME, UPLO, N, K, ALPHA, LDA,
+ $ INCX, BETA, INCY
+ ELSE IF( PACKED )THEN
+ WRITE( NOUT, FMT = 9995 )NC, SNAME, UPLO, N, ALPHA, INCX,
+ $ BETA, INCY
+ END IF
+*
+ 130 CONTINUE
+ RETURN
+*
+ 9999 FORMAT( ' ', A6, ' PASSED THE COMPUTATIONAL TESTS (', I6, ' CALL',
+ $ 'S)' )
+ 9998 FORMAT( ' ******* FATAL ERROR - PARAMETER NUMBER ', I2, ' WAS CH',
+ $ 'ANGED INCORRECTLY *******' )
+ 9997 FORMAT( ' ', A6, ' COMPLETED THE COMPUTATIONAL TESTS (', I6, ' C',
+ $ 'ALLS)', /' ******* BUT WITH MAXIMUM TEST RATIO', F8.2,
+ $ ' - SUSPECT *******' )
+ 9996 FORMAT( ' ******* ', A6, ' FAILED ON CALL NUMBER:' )
+ 9995 FORMAT( 1X, I6, ': ', A6, '(''', A1, ''',', I3, ',(', F4.1, ',',
+ $ F4.1, '), AP, X,', I2, ',(', F4.1, ',', F4.1, '), Y,', I2,
+ $ ') .' )
+ 9994 FORMAT( 1X, I6, ': ', A6, '(''', A1, ''',', 2( I3, ',' ), '(',
+ $ F4.1, ',', F4.1, '), A,', I3, ', X,', I2, ',(', F4.1, ',',
+ $ F4.1, '), Y,', I2, ') .' )
+ 9993 FORMAT( 1X, I6, ': ', A6, '(''', A1, ''',', I3, ',(', F4.1, ',',
+ $ F4.1, '), A,', I3, ', X,', I2, ',(', F4.1, ',', F4.1, '), ',
+ $ 'Y,', I2, ') .' )
+ 9992 FORMAT( ' ******* FATAL ERROR - ERROR-EXIT TAKEN ON VALID CALL *',
+ $ '******' )
+*
+* End of CCHK2.
+*
+ END
+ SUBROUTINE CCHK3( SNAME, EPS, THRESH, NOUT, NTRA, TRACE, REWI,
+ $ FATAL, NIDIM, IDIM, NKB, KB, NINC, INC, NMAX,
+ $ INCMAX, A, AA, AS, X, XX, XS, XT, G, Z )
+*
+* Tests CTRMV, CTBMV, CTPMV, CTRSV, CTBSV and CTPSV.
+*
+* Auxiliary routine for test program for Level 2 Blas.
+*
+* -- Written on 10-August-1987.
+* Richard Hanson, Sandia National Labs.
+* Jeremy Du Croz, NAG Central Office.
+*
+* .. Parameters ..
+ COMPLEX ZERO, HALF, ONE
+ PARAMETER ( ZERO = ( 0.0, 0.0 ), HALF = ( 0.5, 0.0 ),
+ $ ONE = ( 1.0, 0.0 ) )
+ REAL RZERO
+ PARAMETER ( RZERO = 0.0 )
+* .. Scalar Arguments ..
+ REAL EPS, THRESH
+ INTEGER INCMAX, NIDIM, NINC, NKB, NMAX, NOUT, NTRA
+ LOGICAL FATAL, REWI, TRACE
+ CHARACTER*6 SNAME
+* .. Array Arguments ..
+ COMPLEX A( NMAX, NMAX ), AA( NMAX*NMAX ),
+ $ AS( NMAX*NMAX ), X( NMAX ), XS( NMAX*INCMAX ),
+ $ XT( NMAX ), XX( NMAX*INCMAX ), Z( NMAX )
+ REAL G( NMAX )
+ INTEGER IDIM( NIDIM ), INC( NINC ), KB( NKB )
+* .. Local Scalars ..
+ COMPLEX TRANSL
+ REAL ERR, ERRMAX
+ INTEGER I, ICD, ICT, ICU, IK, IN, INCX, INCXS, IX, K,
+ $ KS, LAA, LDA, LDAS, LX, N, NARGS, NC, NK, NS
+ LOGICAL BANDED, FULL, NULL, PACKED, RESET, SAME
+ CHARACTER*1 DIAG, DIAGS, TRANS, TRANSS, UPLO, UPLOS
+ CHARACTER*2 ICHD, ICHU
+ CHARACTER*3 ICHT
+* .. Local Arrays ..
+ LOGICAL ISAME( 13 )
+* .. External Functions ..
+ LOGICAL LCE, LCERES
+ EXTERNAL LCE, LCERES
+* .. External Subroutines ..
+ EXTERNAL CMAKE, CMVCH, CTBMV, CTBSV, CTPMV, CTPSV,
+ $ CTRMV, CTRSV
+* .. Intrinsic Functions ..
+ INTRINSIC ABS, MAX
+* .. Scalars in Common ..
+ INTEGER INFOT, NOUTC
+ LOGICAL LERR, OK
+* .. Common blocks ..
+ COMMON /INFOC/INFOT, NOUTC, OK, LERR
+* .. Data statements ..
+ DATA ICHU/'UL'/, ICHT/'NTC'/, ICHD/'UN'/
+* .. Executable Statements ..
+ FULL = SNAME( 3: 3 ).EQ.'R'
+ BANDED = SNAME( 3: 3 ).EQ.'B'
+ PACKED = SNAME( 3: 3 ).EQ.'P'
+* Define the number of arguments.
+ IF( FULL )THEN
+ NARGS = 8
+ ELSE IF( BANDED )THEN
+ NARGS = 9
+ ELSE IF( PACKED )THEN
+ NARGS = 7
+ END IF
+*
+ NC = 0
+ RESET = .TRUE.
+ ERRMAX = RZERO
+* Set up zero vector for CMVCH.
+ DO 10 I = 1, NMAX
+ Z( I ) = ZERO
+ 10 CONTINUE
+*
+ DO 110 IN = 1, NIDIM
+ N = IDIM( IN )
+*
+ IF( BANDED )THEN
+ NK = NKB
+ ELSE
+ NK = 1
+ END IF
+ DO 100 IK = 1, NK
+ IF( BANDED )THEN
+ K = KB( IK )
+ ELSE
+ K = N - 1
+ END IF
+* Set LDA to 1 more than minimum value if room.
+ IF( BANDED )THEN
+ LDA = K + 1
+ ELSE
+ LDA = N
+ END IF
+ IF( LDA.LT.NMAX )
+ $ LDA = LDA + 1
+* Skip tests if not enough room.
+ IF( LDA.GT.NMAX )
+ $ GO TO 100
+ IF( PACKED )THEN
+ LAA = ( N*( N + 1 ) )/2
+ ELSE
+ LAA = LDA*N
+ END IF
+ NULL = N.LE.0
+*
+ DO 90 ICU = 1, 2
+ UPLO = ICHU( ICU: ICU )
+*
+ DO 80 ICT = 1, 3
+ TRANS = ICHT( ICT: ICT )
+*
+ DO 70 ICD = 1, 2
+ DIAG = ICHD( ICD: ICD )
+*
+* Generate the matrix A.
+*
+ TRANSL = ZERO
+ CALL CMAKE( SNAME( 2: 3 ), UPLO, DIAG, N, N, A,
+ $ NMAX, AA, LDA, K, K, RESET, TRANSL )
+*
+ DO 60 IX = 1, NINC
+ INCX = INC( IX )
+ LX = ABS( INCX )*N
+*
+* Generate the vector X.
+*
+ TRANSL = HALF
+ CALL CMAKE( 'GE', ' ', ' ', 1, N, X, 1, XX,
+ $ ABS( INCX ), 0, N - 1, RESET,
+ $ TRANSL )
+ IF( N.GT.1 )THEN
+ X( N/2 ) = ZERO
+ XX( 1 + ABS( INCX )*( N/2 - 1 ) ) = ZERO
+ END IF
+*
+ NC = NC + 1
+*
+* Save every datum before calling the subroutine.
+*
+ UPLOS = UPLO
+ TRANSS = TRANS
+ DIAGS = DIAG
+ NS = N
+ KS = K
+ DO 20 I = 1, LAA
+ AS( I ) = AA( I )
+ 20 CONTINUE
+ LDAS = LDA
+ DO 30 I = 1, LX
+ XS( I ) = XX( I )
+ 30 CONTINUE
+ INCXS = INCX
+*
+* Call the subroutine.
+*
+ IF( SNAME( 4: 5 ).EQ.'MV' )THEN
+ IF( FULL )THEN
+ IF( TRACE )
+ $ WRITE( NTRA, FMT = 9993 )NC, SNAME,
+ $ UPLO, TRANS, DIAG, N, LDA, INCX
+ IF( REWI )
+ $ REWIND NTRA
+ CALL CTRMV( UPLO, TRANS, DIAG, N, AA, LDA,
+ $ XX, INCX )
+ ELSE IF( BANDED )THEN
+ IF( TRACE )
+ $ WRITE( NTRA, FMT = 9994 )NC, SNAME,
+ $ UPLO, TRANS, DIAG, N, K, LDA, INCX
+ IF( REWI )
+ $ REWIND NTRA
+ CALL CTBMV( UPLO, TRANS, DIAG, N, K, AA,
+ $ LDA, XX, INCX )
+ ELSE IF( PACKED )THEN
+ IF( TRACE )
+ $ WRITE( NTRA, FMT = 9995 )NC, SNAME,
+ $ UPLO, TRANS, DIAG, N, INCX
+ IF( REWI )
+ $ REWIND NTRA
+ CALL CTPMV( UPLO, TRANS, DIAG, N, AA, XX,
+ $ INCX )
+ END IF
+ ELSE IF( SNAME( 4: 5 ).EQ.'SV' )THEN
+ IF( FULL )THEN
+ IF( TRACE )
+ $ WRITE( NTRA, FMT = 9993 )NC, SNAME,
+ $ UPLO, TRANS, DIAG, N, LDA, INCX
+ IF( REWI )
+ $ REWIND NTRA
+ CALL CTRSV( UPLO, TRANS, DIAG, N, AA, LDA,
+ $ XX, INCX )
+ ELSE IF( BANDED )THEN
+ IF( TRACE )
+ $ WRITE( NTRA, FMT = 9994 )NC, SNAME,
+ $ UPLO, TRANS, DIAG, N, K, LDA, INCX
+ IF( REWI )
+ $ REWIND NTRA
+ CALL CTBSV( UPLO, TRANS, DIAG, N, K, AA,
+ $ LDA, XX, INCX )
+ ELSE IF( PACKED )THEN
+ IF( TRACE )
+ $ WRITE( NTRA, FMT = 9995 )NC, SNAME,
+ $ UPLO, TRANS, DIAG, N, INCX
+ IF( REWI )
+ $ REWIND NTRA
+ CALL CTPSV( UPLO, TRANS, DIAG, N, AA, XX,
+ $ INCX )
+ END IF
+ END IF
+*
+* Check if error-exit was taken incorrectly.
+*
+ IF( .NOT.OK )THEN
+ WRITE( NOUT, FMT = 9992 )
+ FATAL = .TRUE.
+ GO TO 120
+ END IF
+*
+* See what data changed inside subroutines.
+*
+ ISAME( 1 ) = UPLO.EQ.UPLOS
+ ISAME( 2 ) = TRANS.EQ.TRANSS
+ ISAME( 3 ) = DIAG.EQ.DIAGS
+ ISAME( 4 ) = NS.EQ.N
+ IF( FULL )THEN
+ ISAME( 5 ) = LCE( AS, AA, LAA )
+ ISAME( 6 ) = LDAS.EQ.LDA
+ IF( NULL )THEN
+ ISAME( 7 ) = LCE( XS, XX, LX )
+ ELSE
+ ISAME( 7 ) = LCERES( 'GE', ' ', 1, N, XS,
+ $ XX, ABS( INCX ) )
+ END IF
+ ISAME( 8 ) = INCXS.EQ.INCX
+ ELSE IF( BANDED )THEN
+ ISAME( 5 ) = KS.EQ.K
+ ISAME( 6 ) = LCE( AS, AA, LAA )
+ ISAME( 7 ) = LDAS.EQ.LDA
+ IF( NULL )THEN
+ ISAME( 8 ) = LCE( XS, XX, LX )
+ ELSE
+ ISAME( 8 ) = LCERES( 'GE', ' ', 1, N, XS,
+ $ XX, ABS( INCX ) )
+ END IF
+ ISAME( 9 ) = INCXS.EQ.INCX
+ ELSE IF( PACKED )THEN
+ ISAME( 5 ) = LCE( AS, AA, LAA )
+ IF( NULL )THEN
+ ISAME( 6 ) = LCE( XS, XX, LX )
+ ELSE
+ ISAME( 6 ) = LCERES( 'GE', ' ', 1, N, XS,
+ $ XX, ABS( INCX ) )
+ END IF
+ ISAME( 7 ) = INCXS.EQ.INCX
+ END IF
+*
+* If data was incorrectly changed, report and
+* return.
+*
+ SAME = .TRUE.
+ DO 40 I = 1, NARGS
+ SAME = SAME.AND.ISAME( I )
+ IF( .NOT.ISAME( I ) )
+ $ WRITE( NOUT, FMT = 9998 )I
+ 40 CONTINUE
+ IF( .NOT.SAME )THEN
+ FATAL = .TRUE.
+ GO TO 120
+ END IF
+*
+ IF( .NOT.NULL )THEN
+ IF( SNAME( 4: 5 ).EQ.'MV' )THEN
+*
+* Check the result.
+*
+ CALL CMVCH( TRANS, N, N, ONE, A, NMAX, X,
+ $ INCX, ZERO, Z, INCX, XT, G,
+ $ XX, EPS, ERR, FATAL, NOUT,
+ $ .TRUE. )
+ ELSE IF( SNAME( 4: 5 ).EQ.'SV' )THEN
+*
+* Compute approximation to original vector.
+*
+ DO 50 I = 1, N
+ Z( I ) = XX( 1 + ( I - 1 )*
+ $ ABS( INCX ) )
+ XX( 1 + ( I - 1 )*ABS( INCX ) )
+ $ = X( I )
+ 50 CONTINUE
+ CALL CMVCH( TRANS, N, N, ONE, A, NMAX, Z,
+ $ INCX, ZERO, X, INCX, XT, G,
+ $ XX, EPS, ERR, FATAL, NOUT,
+ $ .FALSE. )
+ END IF
+ ERRMAX = MAX( ERRMAX, ERR )
+* If got really bad answer, report and return.
+ IF( FATAL )
+ $ GO TO 120
+ ELSE
+* Avoid repeating tests with N.le.0.
+ GO TO 110
+ END IF
+*
+ 60 CONTINUE
+*
+ 70 CONTINUE
+*
+ 80 CONTINUE
+*
+ 90 CONTINUE
+*
+ 100 CONTINUE
+*
+ 110 CONTINUE
+*
+* Report result.
+*
+ IF( ERRMAX.LT.THRESH )THEN
+ WRITE( NOUT, FMT = 9999 )SNAME, NC
+ ELSE
+ WRITE( NOUT, FMT = 9997 )SNAME, NC, ERRMAX
+ END IF
+ GO TO 130
+*
+ 120 CONTINUE
+ WRITE( NOUT, FMT = 9996 )SNAME
+ IF( FULL )THEN
+ WRITE( NOUT, FMT = 9993 )NC, SNAME, UPLO, TRANS, DIAG, N, LDA,
+ $ INCX
+ ELSE IF( BANDED )THEN
+ WRITE( NOUT, FMT = 9994 )NC, SNAME, UPLO, TRANS, DIAG, N, K,
+ $ LDA, INCX
+ ELSE IF( PACKED )THEN
+ WRITE( NOUT, FMT = 9995 )NC, SNAME, UPLO, TRANS, DIAG, N, INCX
+ END IF
+*
+ 130 CONTINUE
+ RETURN
+*
+ 9999 FORMAT( ' ', A6, ' PASSED THE COMPUTATIONAL TESTS (', I6, ' CALL',
+ $ 'S)' )
+ 9998 FORMAT( ' ******* FATAL ERROR - PARAMETER NUMBER ', I2, ' WAS CH',
+ $ 'ANGED INCORRECTLY *******' )
+ 9997 FORMAT( ' ', A6, ' COMPLETED THE COMPUTATIONAL TESTS (', I6, ' C',
+ $ 'ALLS)', /' ******* BUT WITH MAXIMUM TEST RATIO', F8.2,
+ $ ' - SUSPECT *******' )
+ 9996 FORMAT( ' ******* ', A6, ' FAILED ON CALL NUMBER:' )
+ 9995 FORMAT( 1X, I6, ': ', A6, '(', 3( '''', A1, ''',' ), I3, ', AP, ',
+ $ 'X,', I2, ') .' )
+ 9994 FORMAT( 1X, I6, ': ', A6, '(', 3( '''', A1, ''',' ), 2( I3, ',' ),
+ $ ' A,', I3, ', X,', I2, ') .' )
+ 9993 FORMAT( 1X, I6, ': ', A6, '(', 3( '''', A1, ''',' ), I3, ', A,',
+ $ I3, ', X,', I2, ') .' )
+ 9992 FORMAT( ' ******* FATAL ERROR - ERROR-EXIT TAKEN ON VALID CALL *',
+ $ '******' )
+*
+* End of CCHK3.
+*
+ END
+ SUBROUTINE CCHK4( SNAME, EPS, THRESH, NOUT, NTRA, TRACE, REWI,
+ $ FATAL, NIDIM, IDIM, NALF, ALF, NINC, INC, NMAX,
+ $ INCMAX, A, AA, AS, X, XX, XS, Y, YY, YS, YT, G,
+ $ Z )
+*
+* Tests CGERC and CGERU.
+*
+* Auxiliary routine for test program for Level 2 Blas.
+*
+* -- Written on 10-August-1987.
+* Richard Hanson, Sandia National Labs.
+* Jeremy Du Croz, NAG Central Office.
+*
+* .. Parameters ..
+ COMPLEX ZERO, HALF, ONE
+ PARAMETER ( ZERO = ( 0.0, 0.0 ), HALF = ( 0.5, 0.0 ),
+ $ ONE = ( 1.0, 0.0 ) )
+ REAL RZERO
+ PARAMETER ( RZERO = 0.0 )
+* .. Scalar Arguments ..
+ REAL EPS, THRESH
+ INTEGER INCMAX, NALF, NIDIM, NINC, NMAX, NOUT, NTRA
+ LOGICAL FATAL, REWI, TRACE
+ CHARACTER*6 SNAME
+* .. Array Arguments ..
+ COMPLEX A( NMAX, NMAX ), AA( NMAX*NMAX ), ALF( NALF ),
+ $ AS( NMAX*NMAX ), X( NMAX ), XS( NMAX*INCMAX ),
+ $ XX( NMAX*INCMAX ), Y( NMAX ),
+ $ YS( NMAX*INCMAX ), YT( NMAX ),
+ $ YY( NMAX*INCMAX ), Z( NMAX )
+ REAL G( NMAX )
+ INTEGER IDIM( NIDIM ), INC( NINC )
+* .. Local Scalars ..
+ COMPLEX ALPHA, ALS, TRANSL
+ REAL ERR, ERRMAX
+ INTEGER I, IA, IM, IN, INCX, INCXS, INCY, INCYS, IX,
+ $ IY, J, LAA, LDA, LDAS, LX, LY, M, MS, N, NARGS,
+ $ NC, ND, NS
+ LOGICAL CONJ, NULL, RESET, SAME
+* .. Local Arrays ..
+ COMPLEX W( 1 )
+ LOGICAL ISAME( 13 )
+* .. External Functions ..
+ LOGICAL LCE, LCERES
+ EXTERNAL LCE, LCERES
+* .. External Subroutines ..
+ EXTERNAL CGERC, CGERU, CMAKE, CMVCH
+* .. Intrinsic Functions ..
+ INTRINSIC ABS, CONJG, MAX, MIN
+* .. Scalars in Common ..
+ INTEGER INFOT, NOUTC
+ LOGICAL LERR, OK
+* .. Common blocks ..
+ COMMON /INFOC/INFOT, NOUTC, OK, LERR
+* .. Executable Statements ..
+ CONJ = SNAME( 5: 5 ).EQ.'C'
+* Define the number of arguments.
+ NARGS = 9
+*
+ NC = 0
+ RESET = .TRUE.
+ ERRMAX = RZERO
+*
+ DO 120 IN = 1, NIDIM
+ N = IDIM( IN )
+ ND = N/2 + 1
+*
+ DO 110 IM = 1, 2
+ IF( IM.EQ.1 )
+ $ M = MAX( N - ND, 0 )
+ IF( IM.EQ.2 )
+ $ M = MIN( N + ND, NMAX )
+*
+* Set LDA to 1 more than minimum value if room.
+ LDA = M
+ IF( LDA.LT.NMAX )
+ $ LDA = LDA + 1
+* Skip tests if not enough room.
+ IF( LDA.GT.NMAX )
+ $ GO TO 110
+ LAA = LDA*N
+ NULL = N.LE.0.OR.M.LE.0
+*
+ DO 100 IX = 1, NINC
+ INCX = INC( IX )
+ LX = ABS( INCX )*M
+*
+* Generate the vector X.
+*
+ TRANSL = HALF
+ CALL CMAKE( 'GE', ' ', ' ', 1, M, X, 1, XX, ABS( INCX ),
+ $ 0, M - 1, RESET, TRANSL )
+ IF( M.GT.1 )THEN
+ X( M/2 ) = ZERO
+ XX( 1 + ABS( INCX )*( M/2 - 1 ) ) = ZERO
+ END IF
+*
+ DO 90 IY = 1, NINC
+ INCY = INC( IY )
+ LY = ABS( INCY )*N
+*
+* Generate the vector Y.
+*
+ TRANSL = ZERO
+ CALL CMAKE( 'GE', ' ', ' ', 1, N, Y, 1, YY,
+ $ ABS( INCY ), 0, N - 1, RESET, TRANSL )
+ IF( N.GT.1 )THEN
+ Y( N/2 ) = ZERO
+ YY( 1 + ABS( INCY )*( N/2 - 1 ) ) = ZERO
+ END IF
+*
+ DO 80 IA = 1, NALF
+ ALPHA = ALF( IA )
+*
+* Generate the matrix A.
+*
+ TRANSL = ZERO
+ CALL CMAKE( SNAME( 2: 3 ), ' ', ' ', M, N, A, NMAX,
+ $ AA, LDA, M - 1, N - 1, RESET, TRANSL )
+*
+ NC = NC + 1
+*
+* Save every datum before calling the subroutine.
+*
+ MS = M
+ NS = N
+ ALS = ALPHA
+ DO 10 I = 1, LAA
+ AS( I ) = AA( I )
+ 10 CONTINUE
+ LDAS = LDA
+ DO 20 I = 1, LX
+ XS( I ) = XX( I )
+ 20 CONTINUE
+ INCXS = INCX
+ DO 30 I = 1, LY
+ YS( I ) = YY( I )
+ 30 CONTINUE
+ INCYS = INCY
+*
+* Call the subroutine.
+*
+ IF( TRACE )
+ $ WRITE( NTRA, FMT = 9994 )NC, SNAME, M, N,
+ $ ALPHA, INCX, INCY, LDA
+ IF( CONJ )THEN
+ IF( REWI )
+ $ REWIND NTRA
+ CALL CGERC( M, N, ALPHA, XX, INCX, YY, INCY, AA,
+ $ LDA )
+ ELSE
+ IF( REWI )
+ $ REWIND NTRA
+ CALL CGERU( M, N, ALPHA, XX, INCX, YY, INCY, AA,
+ $ LDA )
+ END IF
+*
+* Check if error-exit was taken incorrectly.
+*
+ IF( .NOT.OK )THEN
+ WRITE( NOUT, FMT = 9993 )
+ FATAL = .TRUE.
+ GO TO 140
+ END IF
+*
+* See what data changed inside subroutine.
+*
+ ISAME( 1 ) = MS.EQ.M
+ ISAME( 2 ) = NS.EQ.N
+ ISAME( 3 ) = ALS.EQ.ALPHA
+ ISAME( 4 ) = LCE( XS, XX, LX )
+ ISAME( 5 ) = INCXS.EQ.INCX
+ ISAME( 6 ) = LCE( YS, YY, LY )
+ ISAME( 7 ) = INCYS.EQ.INCY
+ IF( NULL )THEN
+ ISAME( 8 ) = LCE( AS, AA, LAA )
+ ELSE
+ ISAME( 8 ) = LCERES( 'GE', ' ', M, N, AS, AA,
+ $ LDA )
+ END IF
+ ISAME( 9 ) = LDAS.EQ.LDA
+*
+* If data was incorrectly changed, report and return.
+*
+ SAME = .TRUE.
+ DO 40 I = 1, NARGS
+ SAME = SAME.AND.ISAME( I )
+ IF( .NOT.ISAME( I ) )
+ $ WRITE( NOUT, FMT = 9998 )I
+ 40 CONTINUE
+ IF( .NOT.SAME )THEN
+ FATAL = .TRUE.
+ GO TO 140
+ END IF
+*
+ IF( .NOT.NULL )THEN
+*
+* Check the result column by column.
+*
+ IF( INCX.GT.0 )THEN
+ DO 50 I = 1, M
+ Z( I ) = X( I )
+ 50 CONTINUE
+ ELSE
+ DO 60 I = 1, M
+ Z( I ) = X( M - I + 1 )
+ 60 CONTINUE
+ END IF
+ DO 70 J = 1, N
+ IF( INCY.GT.0 )THEN
+ W( 1 ) = Y( J )
+ ELSE
+ W( 1 ) = Y( N - J + 1 )
+ END IF
+ IF( CONJ )
+ $ W( 1 ) = CONJG( W( 1 ) )
+ CALL CMVCH( 'N', M, 1, ALPHA, Z, NMAX, W, 1,
+ $ ONE, A( 1, J ), 1, YT, G,
+ $ AA( 1 + ( J - 1 )*LDA ), EPS,
+ $ ERR, FATAL, NOUT, .TRUE. )
+ ERRMAX = MAX( ERRMAX, ERR )
+* If got really bad answer, report and return.
+ IF( FATAL )
+ $ GO TO 130
+ 70 CONTINUE
+ ELSE
+* Avoid repeating tests with M.le.0 or N.le.0.
+ GO TO 110
+ END IF
+*
+ 80 CONTINUE
+*
+ 90 CONTINUE
+*
+ 100 CONTINUE
+*
+ 110 CONTINUE
+*
+ 120 CONTINUE
+*
+* Report result.
+*
+ IF( ERRMAX.LT.THRESH )THEN
+ WRITE( NOUT, FMT = 9999 )SNAME, NC
+ ELSE
+ WRITE( NOUT, FMT = 9997 )SNAME, NC, ERRMAX
+ END IF
+ GO TO 150
+*
+ 130 CONTINUE
+ WRITE( NOUT, FMT = 9995 )J
+*
+ 140 CONTINUE
+ WRITE( NOUT, FMT = 9996 )SNAME
+ WRITE( NOUT, FMT = 9994 )NC, SNAME, M, N, ALPHA, INCX, INCY, LDA
+*
+ 150 CONTINUE
+ RETURN
+*
+ 9999 FORMAT( ' ', A6, ' PASSED THE COMPUTATIONAL TESTS (', I6, ' CALL',
+ $ 'S)' )
+ 9998 FORMAT( ' ******* FATAL ERROR - PARAMETER NUMBER ', I2, ' WAS CH',
+ $ 'ANGED INCORRECTLY *******' )
+ 9997 FORMAT( ' ', A6, ' COMPLETED THE COMPUTATIONAL TESTS (', I6, ' C',
+ $ 'ALLS)', /' ******* BUT WITH MAXIMUM TEST RATIO', F8.2,
+ $ ' - SUSPECT *******' )
+ 9996 FORMAT( ' ******* ', A6, ' FAILED ON CALL NUMBER:' )
+ 9995 FORMAT( ' THESE ARE THE RESULTS FOR COLUMN ', I3 )
+ 9994 FORMAT( 1X, I6, ': ', A6, '(', 2( I3, ',' ), '(', F4.1, ',', F4.1,
+ $ '), X,', I2, ', Y,', I2, ', A,', I3, ') ',
+ $ ' .' )
+ 9993 FORMAT( ' ******* FATAL ERROR - ERROR-EXIT TAKEN ON VALID CALL *',
+ $ '******' )
+*
+* End of CCHK4.
+*
+ END
+ SUBROUTINE CCHK5( SNAME, EPS, THRESH, NOUT, NTRA, TRACE, REWI,
+ $ FATAL, NIDIM, IDIM, NALF, ALF, NINC, INC, NMAX,
+ $ INCMAX, A, AA, AS, X, XX, XS, Y, YY, YS, YT, G,
+ $ Z )
+*
+* Tests CHER and CHPR.
+*
+* Auxiliary routine for test program for Level 2 Blas.
+*
+* -- Written on 10-August-1987.
+* Richard Hanson, Sandia National Labs.
+* Jeremy Du Croz, NAG Central Office.
+*
+* .. Parameters ..
+ COMPLEX ZERO, HALF, ONE
+ PARAMETER ( ZERO = ( 0.0, 0.0 ), HALF = ( 0.5, 0.0 ),
+ $ ONE = ( 1.0, 0.0 ) )
+ REAL RZERO
+ PARAMETER ( RZERO = 0.0 )
+* .. Scalar Arguments ..
+ REAL EPS, THRESH
+ INTEGER INCMAX, NALF, NIDIM, NINC, NMAX, NOUT, NTRA
+ LOGICAL FATAL, REWI, TRACE
+ CHARACTER*6 SNAME
+* .. Array Arguments ..
+ COMPLEX A( NMAX, NMAX ), AA( NMAX*NMAX ), ALF( NALF ),
+ $ AS( NMAX*NMAX ), X( NMAX ), XS( NMAX*INCMAX ),
+ $ XX( NMAX*INCMAX ), Y( NMAX ),
+ $ YS( NMAX*INCMAX ), YT( NMAX ),
+ $ YY( NMAX*INCMAX ), Z( NMAX )
+ REAL G( NMAX )
+ INTEGER IDIM( NIDIM ), INC( NINC )
+* .. Local Scalars ..
+ COMPLEX ALPHA, TRANSL
+ REAL ERR, ERRMAX, RALPHA, RALS
+ INTEGER I, IA, IC, IN, INCX, INCXS, IX, J, JA, JJ, LAA,
+ $ LDA, LDAS, LJ, LX, N, NARGS, NC, NS
+ LOGICAL FULL, NULL, PACKED, RESET, SAME, UPPER
+ CHARACTER*1 UPLO, UPLOS
+ CHARACTER*2 ICH
+* .. Local Arrays ..
+ COMPLEX W( 1 )
+ LOGICAL ISAME( 13 )
+* .. External Functions ..
+ LOGICAL LCE, LCERES
+ EXTERNAL LCE, LCERES
+* .. External Subroutines ..
+ EXTERNAL CHER, CHPR, CMAKE, CMVCH
+* .. Intrinsic Functions ..
+ INTRINSIC ABS, CMPLX, CONJG, MAX, REAL
+* .. Scalars in Common ..
+ INTEGER INFOT, NOUTC
+ LOGICAL LERR, OK
+* .. Common blocks ..
+ COMMON /INFOC/INFOT, NOUTC, OK, LERR
+* .. Data statements ..
+ DATA ICH/'UL'/
+* .. Executable Statements ..
+ FULL = SNAME( 3: 3 ).EQ.'E'
+ PACKED = SNAME( 3: 3 ).EQ.'P'
+* Define the number of arguments.
+ IF( FULL )THEN
+ NARGS = 7
+ ELSE IF( PACKED )THEN
+ NARGS = 6
+ END IF
+*
+ NC = 0
+ RESET = .TRUE.
+ ERRMAX = RZERO
+*
+ DO 100 IN = 1, NIDIM
+ N = IDIM( IN )
+* Set LDA to 1 more than minimum value if room.
+ LDA = N
+ IF( LDA.LT.NMAX )
+ $ LDA = LDA + 1
+* Skip tests if not enough room.
+ IF( LDA.GT.NMAX )
+ $ GO TO 100
+ IF( PACKED )THEN
+ LAA = ( N*( N + 1 ) )/2
+ ELSE
+ LAA = LDA*N
+ END IF
+*
+ DO 90 IC = 1, 2
+ UPLO = ICH( IC: IC )
+ UPPER = UPLO.EQ.'U'
+*
+ DO 80 IX = 1, NINC
+ INCX = INC( IX )
+ LX = ABS( INCX )*N
+*
+* Generate the vector X.
+*
+ TRANSL = HALF
+ CALL CMAKE( 'GE', ' ', ' ', 1, N, X, 1, XX, ABS( INCX ),
+ $ 0, N - 1, RESET, TRANSL )
+ IF( N.GT.1 )THEN
+ X( N/2 ) = ZERO
+ XX( 1 + ABS( INCX )*( N/2 - 1 ) ) = ZERO
+ END IF
+*
+ DO 70 IA = 1, NALF
+ RALPHA = REAL( ALF( IA ) )
+ ALPHA = CMPLX( RALPHA, RZERO )
+ NULL = N.LE.0.OR.RALPHA.EQ.RZERO
+*
+* Generate the matrix A.
+*
+ TRANSL = ZERO
+ CALL CMAKE( SNAME( 2: 3 ), UPLO, ' ', N, N, A, NMAX,
+ $ AA, LDA, N - 1, N - 1, RESET, TRANSL )
+*
+ NC = NC + 1
+*
+* Save every datum before calling the subroutine.
+*
+ UPLOS = UPLO
+ NS = N
+ RALS = RALPHA
+ DO 10 I = 1, LAA
+ AS( I ) = AA( I )
+ 10 CONTINUE
+ LDAS = LDA
+ DO 20 I = 1, LX
+ XS( I ) = XX( I )
+ 20 CONTINUE
+ INCXS = INCX
+*
+* Call the subroutine.
+*
+ IF( FULL )THEN
+ IF( TRACE )
+ $ WRITE( NTRA, FMT = 9993 )NC, SNAME, UPLO, N,
+ $ RALPHA, INCX, LDA
+ IF( REWI )
+ $ REWIND NTRA
+ CALL CHER( UPLO, N, RALPHA, XX, INCX, AA, LDA )
+ ELSE IF( PACKED )THEN
+ IF( TRACE )
+ $ WRITE( NTRA, FMT = 9994 )NC, SNAME, UPLO, N,
+ $ RALPHA, INCX
+ IF( REWI )
+ $ REWIND NTRA
+ CALL CHPR( UPLO, N, RALPHA, XX, INCX, AA )
+ END IF
+*
+* Check if error-exit was taken incorrectly.
+*
+ IF( .NOT.OK )THEN
+ WRITE( NOUT, FMT = 9992 )
+ FATAL = .TRUE.
+ GO TO 120
+ END IF
+*
+* See what data changed inside subroutines.
+*
+ ISAME( 1 ) = UPLO.EQ.UPLOS
+ ISAME( 2 ) = NS.EQ.N
+ ISAME( 3 ) = RALS.EQ.RALPHA
+ ISAME( 4 ) = LCE( XS, XX, LX )
+ ISAME( 5 ) = INCXS.EQ.INCX
+ IF( NULL )THEN
+ ISAME( 6 ) = LCE( AS, AA, LAA )
+ ELSE
+ ISAME( 6 ) = LCERES( SNAME( 2: 3 ), UPLO, N, N, AS,
+ $ AA, LDA )
+ END IF
+ IF( .NOT.PACKED )THEN
+ ISAME( 7 ) = LDAS.EQ.LDA
+ END IF
+*
+* If data was incorrectly changed, report and return.
+*
+ SAME = .TRUE.
+ DO 30 I = 1, NARGS
+ SAME = SAME.AND.ISAME( I )
+ IF( .NOT.ISAME( I ) )
+ $ WRITE( NOUT, FMT = 9998 )I
+ 30 CONTINUE
+ IF( .NOT.SAME )THEN
+ FATAL = .TRUE.
+ GO TO 120
+ END IF
+*
+ IF( .NOT.NULL )THEN
+*
+* Check the result column by column.
+*
+ IF( INCX.GT.0 )THEN
+ DO 40 I = 1, N
+ Z( I ) = X( I )
+ 40 CONTINUE
+ ELSE
+ DO 50 I = 1, N
+ Z( I ) = X( N - I + 1 )
+ 50 CONTINUE
+ END IF
+ JA = 1
+ DO 60 J = 1, N
+ W( 1 ) = CONJG( Z( J ) )
+ IF( UPPER )THEN
+ JJ = 1
+ LJ = J
+ ELSE
+ JJ = J
+ LJ = N - J + 1
+ END IF
+ CALL CMVCH( 'N', LJ, 1, ALPHA, Z( JJ ), LJ, W,
+ $ 1, ONE, A( JJ, J ), 1, YT, G,
+ $ AA( JA ), EPS, ERR, FATAL, NOUT,
+ $ .TRUE. )
+ IF( FULL )THEN
+ IF( UPPER )THEN
+ JA = JA + LDA
+ ELSE
+ JA = JA + LDA + 1
+ END IF
+ ELSE
+ JA = JA + LJ
+ END IF
+ ERRMAX = MAX( ERRMAX, ERR )
+* If got really bad answer, report and return.
+ IF( FATAL )
+ $ GO TO 110
+ 60 CONTINUE
+ ELSE
+* Avoid repeating tests if N.le.0.
+ IF( N.LE.0 )
+ $ GO TO 100
+ END IF
+*
+ 70 CONTINUE
+*
+ 80 CONTINUE
+*
+ 90 CONTINUE
+*
+ 100 CONTINUE
+*
+* Report result.
+*
+ IF( ERRMAX.LT.THRESH )THEN
+ WRITE( NOUT, FMT = 9999 )SNAME, NC
+ ELSE
+ WRITE( NOUT, FMT = 9997 )SNAME, NC, ERRMAX
+ END IF
+ GO TO 130
+*
+ 110 CONTINUE
+ WRITE( NOUT, FMT = 9995 )J
+*
+ 120 CONTINUE
+ WRITE( NOUT, FMT = 9996 )SNAME
+ IF( FULL )THEN
+ WRITE( NOUT, FMT = 9993 )NC, SNAME, UPLO, N, RALPHA, INCX, LDA
+ ELSE IF( PACKED )THEN
+ WRITE( NOUT, FMT = 9994 )NC, SNAME, UPLO, N, RALPHA, INCX
+ END IF
+*
+ 130 CONTINUE
+ RETURN
+*
+ 9999 FORMAT( ' ', A6, ' PASSED THE COMPUTATIONAL TESTS (', I6, ' CALL',
+ $ 'S)' )
+ 9998 FORMAT( ' ******* FATAL ERROR - PARAMETER NUMBER ', I2, ' WAS CH',
+ $ 'ANGED INCORRECTLY *******' )
+ 9997 FORMAT( ' ', A6, ' COMPLETED THE COMPUTATIONAL TESTS (', I6, ' C',
+ $ 'ALLS)', /' ******* BUT WITH MAXIMUM TEST RATIO', F8.2,
+ $ ' - SUSPECT *******' )
+ 9996 FORMAT( ' ******* ', A6, ' FAILED ON CALL NUMBER:' )
+ 9995 FORMAT( ' THESE ARE THE RESULTS FOR COLUMN ', I3 )
+ 9994 FORMAT( 1X, I6, ': ', A6, '(''', A1, ''',', I3, ',', F4.1, ', X,',
+ $ I2, ', AP) .' )
+ 9993 FORMAT( 1X, I6, ': ', A6, '(''', A1, ''',', I3, ',', F4.1, ', X,',
+ $ I2, ', A,', I3, ') .' )
+ 9992 FORMAT( ' ******* FATAL ERROR - ERROR-EXIT TAKEN ON VALID CALL *',
+ $ '******' )
+*
+* End of CCHK5.
+*
+ END
+ SUBROUTINE CCHK6( SNAME, EPS, THRESH, NOUT, NTRA, TRACE, REWI,
+ $ FATAL, NIDIM, IDIM, NALF, ALF, NINC, INC, NMAX,
+ $ INCMAX, A, AA, AS, X, XX, XS, Y, YY, YS, YT, G,
+ $ Z )
+*
+* Tests CHER2 and CHPR2.
+*
+* Auxiliary routine for test program for Level 2 Blas.
+*
+* -- Written on 10-August-1987.
+* Richard Hanson, Sandia National Labs.
+* Jeremy Du Croz, NAG Central Office.
+*
+* .. Parameters ..
+ COMPLEX ZERO, HALF, ONE
+ PARAMETER ( ZERO = ( 0.0, 0.0 ), HALF = ( 0.5, 0.0 ),
+ $ ONE = ( 1.0, 0.0 ) )
+ REAL RZERO
+ PARAMETER ( RZERO = 0.0 )
+* .. Scalar Arguments ..
+ REAL EPS, THRESH
+ INTEGER INCMAX, NALF, NIDIM, NINC, NMAX, NOUT, NTRA
+ LOGICAL FATAL, REWI, TRACE
+ CHARACTER*6 SNAME
+* .. Array Arguments ..
+ COMPLEX A( NMAX, NMAX ), AA( NMAX*NMAX ), ALF( NALF ),
+ $ AS( NMAX*NMAX ), X( NMAX ), XS( NMAX*INCMAX ),
+ $ XX( NMAX*INCMAX ), Y( NMAX ),
+ $ YS( NMAX*INCMAX ), YT( NMAX ),
+ $ YY( NMAX*INCMAX ), Z( NMAX, 2 )
+ REAL G( NMAX )
+ INTEGER IDIM( NIDIM ), INC( NINC )
+* .. Local Scalars ..
+ COMPLEX ALPHA, ALS, TRANSL
+ REAL ERR, ERRMAX
+ INTEGER I, IA, IC, IN, INCX, INCXS, INCY, INCYS, IX,
+ $ IY, J, JA, JJ, LAA, LDA, LDAS, LJ, LX, LY, N,
+ $ NARGS, NC, NS
+ LOGICAL FULL, NULL, PACKED, RESET, SAME, UPPER
+ CHARACTER*1 UPLO, UPLOS
+ CHARACTER*2 ICH
+* .. Local Arrays ..
+ COMPLEX W( 2 )
+ LOGICAL ISAME( 13 )
+* .. External Functions ..
+ LOGICAL LCE, LCERES
+ EXTERNAL LCE, LCERES
+* .. External Subroutines ..
+ EXTERNAL CHER2, CHPR2, CMAKE, CMVCH
+* .. Intrinsic Functions ..
+ INTRINSIC ABS, CONJG, MAX
+* .. Scalars in Common ..
+ INTEGER INFOT, NOUTC
+ LOGICAL LERR, OK
+* .. Common blocks ..
+ COMMON /INFOC/INFOT, NOUTC, OK, LERR
+* .. Data statements ..
+ DATA ICH/'UL'/
+* .. Executable Statements ..
+ FULL = SNAME( 3: 3 ).EQ.'E'
+ PACKED = SNAME( 3: 3 ).EQ.'P'
+* Define the number of arguments.
+ IF( FULL )THEN
+ NARGS = 9
+ ELSE IF( PACKED )THEN
+ NARGS = 8
+ END IF
+*
+ NC = 0
+ RESET = .TRUE.
+ ERRMAX = RZERO
+*
+ DO 140 IN = 1, NIDIM
+ N = IDIM( IN )
+* Set LDA to 1 more than minimum value if room.
+ LDA = N
+ IF( LDA.LT.NMAX )
+ $ LDA = LDA + 1
+* Skip tests if not enough room.
+ IF( LDA.GT.NMAX )
+ $ GO TO 140
+ IF( PACKED )THEN
+ LAA = ( N*( N + 1 ) )/2
+ ELSE
+ LAA = LDA*N
+ END IF
+*
+ DO 130 IC = 1, 2
+ UPLO = ICH( IC: IC )
+ UPPER = UPLO.EQ.'U'
+*
+ DO 120 IX = 1, NINC
+ INCX = INC( IX )
+ LX = ABS( INCX )*N
+*
+* Generate the vector X.
+*
+ TRANSL = HALF
+ CALL CMAKE( 'GE', ' ', ' ', 1, N, X, 1, XX, ABS( INCX ),
+ $ 0, N - 1, RESET, TRANSL )
+ IF( N.GT.1 )THEN
+ X( N/2 ) = ZERO
+ XX( 1 + ABS( INCX )*( N/2 - 1 ) ) = ZERO
+ END IF
+*
+ DO 110 IY = 1, NINC
+ INCY = INC( IY )
+ LY = ABS( INCY )*N
+*
+* Generate the vector Y.
+*
+ TRANSL = ZERO
+ CALL CMAKE( 'GE', ' ', ' ', 1, N, Y, 1, YY,
+ $ ABS( INCY ), 0, N - 1, RESET, TRANSL )
+ IF( N.GT.1 )THEN
+ Y( N/2 ) = ZERO
+ YY( 1 + ABS( INCY )*( N/2 - 1 ) ) = ZERO
+ END IF
+*
+ DO 100 IA = 1, NALF
+ ALPHA = ALF( IA )
+ NULL = N.LE.0.OR.ALPHA.EQ.ZERO
+*
+* Generate the matrix A.
+*
+ TRANSL = ZERO
+ CALL CMAKE( SNAME( 2: 3 ), UPLO, ' ', N, N, A,
+ $ NMAX, AA, LDA, N - 1, N - 1, RESET,
+ $ TRANSL )
+*
+ NC = NC + 1
+*
+* Save every datum before calling the subroutine.
+*
+ UPLOS = UPLO
+ NS = N
+ ALS = ALPHA
+ DO 10 I = 1, LAA
+ AS( I ) = AA( I )
+ 10 CONTINUE
+ LDAS = LDA
+ DO 20 I = 1, LX
+ XS( I ) = XX( I )
+ 20 CONTINUE
+ INCXS = INCX
+ DO 30 I = 1, LY
+ YS( I ) = YY( I )
+ 30 CONTINUE
+ INCYS = INCY
+*
+* Call the subroutine.
+*
+ IF( FULL )THEN
+ IF( TRACE )
+ $ WRITE( NTRA, FMT = 9993 )NC, SNAME, UPLO, N,
+ $ ALPHA, INCX, INCY, LDA
+ IF( REWI )
+ $ REWIND NTRA
+ CALL CHER2( UPLO, N, ALPHA, XX, INCX, YY, INCY,
+ $ AA, LDA )
+ ELSE IF( PACKED )THEN
+ IF( TRACE )
+ $ WRITE( NTRA, FMT = 9994 )NC, SNAME, UPLO, N,
+ $ ALPHA, INCX, INCY
+ IF( REWI )
+ $ REWIND NTRA
+ CALL CHPR2( UPLO, N, ALPHA, XX, INCX, YY, INCY,
+ $ AA )
+ END IF
+*
+* Check if error-exit was taken incorrectly.
+*
+ IF( .NOT.OK )THEN
+ WRITE( NOUT, FMT = 9992 )
+ FATAL = .TRUE.
+ GO TO 160
+ END IF
+*
+* See what data changed inside subroutines.
+*
+ ISAME( 1 ) = UPLO.EQ.UPLOS
+ ISAME( 2 ) = NS.EQ.N
+ ISAME( 3 ) = ALS.EQ.ALPHA
+ ISAME( 4 ) = LCE( XS, XX, LX )
+ ISAME( 5 ) = INCXS.EQ.INCX
+ ISAME( 6 ) = LCE( YS, YY, LY )
+ ISAME( 7 ) = INCYS.EQ.INCY
+ IF( NULL )THEN
+ ISAME( 8 ) = LCE( AS, AA, LAA )
+ ELSE
+ ISAME( 8 ) = LCERES( SNAME( 2: 3 ), UPLO, N, N,
+ $ AS, AA, LDA )
+ END IF
+ IF( .NOT.PACKED )THEN
+ ISAME( 9 ) = LDAS.EQ.LDA
+ END IF
+*
+* If data was incorrectly changed, report and return.
+*
+ SAME = .TRUE.
+ DO 40 I = 1, NARGS
+ SAME = SAME.AND.ISAME( I )
+ IF( .NOT.ISAME( I ) )
+ $ WRITE( NOUT, FMT = 9998 )I
+ 40 CONTINUE
+ IF( .NOT.SAME )THEN
+ FATAL = .TRUE.
+ GO TO 160
+ END IF
+*
+ IF( .NOT.NULL )THEN
+*
+* Check the result column by column.
+*
+ IF( INCX.GT.0 )THEN
+ DO 50 I = 1, N
+ Z( I, 1 ) = X( I )
+ 50 CONTINUE
+ ELSE
+ DO 60 I = 1, N
+ Z( I, 1 ) = X( N - I + 1 )
+ 60 CONTINUE
+ END IF
+ IF( INCY.GT.0 )THEN
+ DO 70 I = 1, N
+ Z( I, 2 ) = Y( I )
+ 70 CONTINUE
+ ELSE
+ DO 80 I = 1, N
+ Z( I, 2 ) = Y( N - I + 1 )
+ 80 CONTINUE
+ END IF
+ JA = 1
+ DO 90 J = 1, N
+ W( 1 ) = ALPHA*CONJG( Z( J, 2 ) )
+ W( 2 ) = CONJG( ALPHA )*CONJG( Z( J, 1 ) )
+ IF( UPPER )THEN
+ JJ = 1
+ LJ = J
+ ELSE
+ JJ = J
+ LJ = N - J + 1
+ END IF
+ CALL CMVCH( 'N', LJ, 2, ONE, Z( JJ, 1 ),
+ $ NMAX, W, 1, ONE, A( JJ, J ), 1,
+ $ YT, G, AA( JA ), EPS, ERR, FATAL,
+ $ NOUT, .TRUE. )
+ IF( FULL )THEN
+ IF( UPPER )THEN
+ JA = JA + LDA
+ ELSE
+ JA = JA + LDA + 1
+ END IF
+ ELSE
+ JA = JA + LJ
+ END IF
+ ERRMAX = MAX( ERRMAX, ERR )
+* If got really bad answer, report and return.
+ IF( FATAL )
+ $ GO TO 150
+ 90 CONTINUE
+ ELSE
+* Avoid repeating tests with N.le.0.
+ IF( N.LE.0 )
+ $ GO TO 140
+ END IF
+*
+ 100 CONTINUE
+*
+ 110 CONTINUE
+*
+ 120 CONTINUE
+*
+ 130 CONTINUE
+*
+ 140 CONTINUE
+*
+* Report result.
+*
+ IF( ERRMAX.LT.THRESH )THEN
+ WRITE( NOUT, FMT = 9999 )SNAME, NC
+ ELSE
+ WRITE( NOUT, FMT = 9997 )SNAME, NC, ERRMAX
+ END IF
+ GO TO 170
+*
+ 150 CONTINUE
+ WRITE( NOUT, FMT = 9995 )J
+*
+ 160 CONTINUE
+ WRITE( NOUT, FMT = 9996 )SNAME
+ IF( FULL )THEN
+ WRITE( NOUT, FMT = 9993 )NC, SNAME, UPLO, N, ALPHA, INCX,
+ $ INCY, LDA
+ ELSE IF( PACKED )THEN
+ WRITE( NOUT, FMT = 9994 )NC, SNAME, UPLO, N, ALPHA, INCX, INCY
+ END IF
+*
+ 170 CONTINUE
+ RETURN
+*
+ 9999 FORMAT( ' ', A6, ' PASSED THE COMPUTATIONAL TESTS (', I6, ' CALL',
+ $ 'S)' )
+ 9998 FORMAT( ' ******* FATAL ERROR - PARAMETER NUMBER ', I2, ' WAS CH',
+ $ 'ANGED INCORRECTLY *******' )
+ 9997 FORMAT( ' ', A6, ' COMPLETED THE COMPUTATIONAL TESTS (', I6, ' C',
+ $ 'ALLS)', /' ******* BUT WITH MAXIMUM TEST RATIO', F8.2,
+ $ ' - SUSPECT *******' )
+ 9996 FORMAT( ' ******* ', A6, ' FAILED ON CALL NUMBER:' )
+ 9995 FORMAT( ' THESE ARE THE RESULTS FOR COLUMN ', I3 )
+ 9994 FORMAT( 1X, I6, ': ', A6, '(''', A1, ''',', I3, ',(', F4.1, ',',
+ $ F4.1, '), X,', I2, ', Y,', I2, ', AP) ',
+ $ ' .' )
+ 9993 FORMAT( 1X, I6, ': ', A6, '(''', A1, ''',', I3, ',(', F4.1, ',',
+ $ F4.1, '), X,', I2, ', Y,', I2, ', A,', I3, ') ',
+ $ ' .' )
+ 9992 FORMAT( ' ******* FATAL ERROR - ERROR-EXIT TAKEN ON VALID CALL *',
+ $ '******' )
+*
+* End of CCHK6.
+*
+ END
+ SUBROUTINE CCHKE( ISNUM, SRNAMT, NOUT )
+*
+* Tests the error exits from the Level 2 Blas.
+* Requires a special version of the error-handling routine XERBLA.
+* ALPHA, RALPHA, BETA, A, X and Y should not need to be defined.
+*
+* Auxiliary routine for test program for Level 2 Blas.
+*
+* -- Written on 10-August-1987.
+* Richard Hanson, Sandia National Labs.
+* Jeremy Du Croz, NAG Central Office.
+*
+* .. Scalar Arguments ..
+ INTEGER ISNUM, NOUT
+ CHARACTER*6 SRNAMT
+* .. Scalars in Common ..
+ INTEGER INFOT, NOUTC
+ LOGICAL LERR, OK
+* .. Local Scalars ..
+ COMPLEX ALPHA, BETA
+ REAL RALPHA
+* .. Local Arrays ..
+ COMPLEX A( 1, 1 ), X( 1 ), Y( 1 )
+* .. External Subroutines ..
+ EXTERNAL CGBMV, CGEMV, CGERC, CGERU, CHBMV, CHEMV, CHER,
+ $ CHER2, CHKXER, CHPMV, CHPR, CHPR2, CTBMV,
+ $ CTBSV, CTPMV, CTPSV, CTRMV, CTRSV
+* .. Common blocks ..
+ COMMON /INFOC/INFOT, NOUTC, OK, LERR
+* .. Executable Statements ..
+* OK is set to .FALSE. by the special version of XERBLA or by CHKXER
+* if anything is wrong.
+ OK = .TRUE.
+* LERR is set to .TRUE. by the special version of XERBLA each time
+* it is called, and is then tested and re-set by CHKXER.
+ LERR = .FALSE.
+ GO TO ( 10, 20, 30, 40, 50, 60, 70, 80,
+ $ 90, 100, 110, 120, 130, 140, 150, 160,
+ $ 170 )ISNUM
+ 10 INFOT = 1
+ CALL CGEMV( '/', 0, 0, ALPHA, A, 1, X, 1, BETA, Y, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 2
+ CALL CGEMV( 'N', -1, 0, ALPHA, A, 1, X, 1, BETA, Y, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 3
+ CALL CGEMV( 'N', 0, -1, ALPHA, A, 1, X, 1, BETA, Y, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 6
+ CALL CGEMV( 'N', 2, 0, ALPHA, A, 1, X, 1, BETA, Y, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 8
+ CALL CGEMV( 'N', 0, 0, ALPHA, A, 1, X, 0, BETA, Y, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 11
+ CALL CGEMV( 'N', 0, 0, ALPHA, A, 1, X, 1, BETA, Y, 0 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ GO TO 180
+ 20 INFOT = 1
+ CALL CGBMV( '/', 0, 0, 0, 0, ALPHA, A, 1, X, 1, BETA, Y, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 2
+ CALL CGBMV( 'N', -1, 0, 0, 0, ALPHA, A, 1, X, 1, BETA, Y, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 3
+ CALL CGBMV( 'N', 0, -1, 0, 0, ALPHA, A, 1, X, 1, BETA, Y, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 4
+ CALL CGBMV( 'N', 0, 0, -1, 0, ALPHA, A, 1, X, 1, BETA, Y, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 5
+ CALL CGBMV( 'N', 2, 0, 0, -1, ALPHA, A, 1, X, 1, BETA, Y, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 8
+ CALL CGBMV( 'N', 0, 0, 1, 0, ALPHA, A, 1, X, 1, BETA, Y, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 10
+ CALL CGBMV( 'N', 0, 0, 0, 0, ALPHA, A, 1, X, 0, BETA, Y, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 13
+ CALL CGBMV( 'N', 0, 0, 0, 0, ALPHA, A, 1, X, 1, BETA, Y, 0 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ GO TO 180
+ 30 INFOT = 1
+ CALL CHEMV( '/', 0, ALPHA, A, 1, X, 1, BETA, Y, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 2
+ CALL CHEMV( 'U', -1, ALPHA, A, 1, X, 1, BETA, Y, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 5
+ CALL CHEMV( 'U', 2, ALPHA, A, 1, X, 1, BETA, Y, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 7
+ CALL CHEMV( 'U', 0, ALPHA, A, 1, X, 0, BETA, Y, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 10
+ CALL CHEMV( 'U', 0, ALPHA, A, 1, X, 1, BETA, Y, 0 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ GO TO 180
+ 40 INFOT = 1
+ CALL CHBMV( '/', 0, 0, ALPHA, A, 1, X, 1, BETA, Y, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 2
+ CALL CHBMV( 'U', -1, 0, ALPHA, A, 1, X, 1, BETA, Y, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 3
+ CALL CHBMV( 'U', 0, -1, ALPHA, A, 1, X, 1, BETA, Y, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 6
+ CALL CHBMV( 'U', 0, 1, ALPHA, A, 1, X, 1, BETA, Y, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 8
+ CALL CHBMV( 'U', 0, 0, ALPHA, A, 1, X, 0, BETA, Y, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 11
+ CALL CHBMV( 'U', 0, 0, ALPHA, A, 1, X, 1, BETA, Y, 0 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ GO TO 180
+ 50 INFOT = 1
+ CALL CHPMV( '/', 0, ALPHA, A, X, 1, BETA, Y, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 2
+ CALL CHPMV( 'U', -1, ALPHA, A, X, 1, BETA, Y, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 6
+ CALL CHPMV( 'U', 0, ALPHA, A, X, 0, BETA, Y, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 9
+ CALL CHPMV( 'U', 0, ALPHA, A, X, 1, BETA, Y, 0 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ GO TO 180
+ 60 INFOT = 1
+ CALL CTRMV( '/', 'N', 'N', 0, A, 1, X, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 2
+ CALL CTRMV( 'U', '/', 'N', 0, A, 1, X, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 3
+ CALL CTRMV( 'U', 'N', '/', 0, A, 1, X, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 4
+ CALL CTRMV( 'U', 'N', 'N', -1, A, 1, X, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 6
+ CALL CTRMV( 'U', 'N', 'N', 2, A, 1, X, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 8
+ CALL CTRMV( 'U', 'N', 'N', 0, A, 1, X, 0 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ GO TO 180
+ 70 INFOT = 1
+ CALL CTBMV( '/', 'N', 'N', 0, 0, A, 1, X, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 2
+ CALL CTBMV( 'U', '/', 'N', 0, 0, A, 1, X, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 3
+ CALL CTBMV( 'U', 'N', '/', 0, 0, A, 1, X, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 4
+ CALL CTBMV( 'U', 'N', 'N', -1, 0, A, 1, X, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 5
+ CALL CTBMV( 'U', 'N', 'N', 0, -1, A, 1, X, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 7
+ CALL CTBMV( 'U', 'N', 'N', 0, 1, A, 1, X, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 9
+ CALL CTBMV( 'U', 'N', 'N', 0, 0, A, 1, X, 0 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ GO TO 180
+ 80 INFOT = 1
+ CALL CTPMV( '/', 'N', 'N', 0, A, X, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 2
+ CALL CTPMV( 'U', '/', 'N', 0, A, X, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 3
+ CALL CTPMV( 'U', 'N', '/', 0, A, X, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 4
+ CALL CTPMV( 'U', 'N', 'N', -1, A, X, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 7
+ CALL CTPMV( 'U', 'N', 'N', 0, A, X, 0 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ GO TO 180
+ 90 INFOT = 1
+ CALL CTRSV( '/', 'N', 'N', 0, A, 1, X, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 2
+ CALL CTRSV( 'U', '/', 'N', 0, A, 1, X, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 3
+ CALL CTRSV( 'U', 'N', '/', 0, A, 1, X, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 4
+ CALL CTRSV( 'U', 'N', 'N', -1, A, 1, X, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 6
+ CALL CTRSV( 'U', 'N', 'N', 2, A, 1, X, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 8
+ CALL CTRSV( 'U', 'N', 'N', 0, A, 1, X, 0 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ GO TO 180
+ 100 INFOT = 1
+ CALL CTBSV( '/', 'N', 'N', 0, 0, A, 1, X, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 2
+ CALL CTBSV( 'U', '/', 'N', 0, 0, A, 1, X, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 3
+ CALL CTBSV( 'U', 'N', '/', 0, 0, A, 1, X, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 4
+ CALL CTBSV( 'U', 'N', 'N', -1, 0, A, 1, X, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 5
+ CALL CTBSV( 'U', 'N', 'N', 0, -1, A, 1, X, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 7
+ CALL CTBSV( 'U', 'N', 'N', 0, 1, A, 1, X, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 9
+ CALL CTBSV( 'U', 'N', 'N', 0, 0, A, 1, X, 0 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ GO TO 180
+ 110 INFOT = 1
+ CALL CTPSV( '/', 'N', 'N', 0, A, X, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 2
+ CALL CTPSV( 'U', '/', 'N', 0, A, X, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 3
+ CALL CTPSV( 'U', 'N', '/', 0, A, X, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 4
+ CALL CTPSV( 'U', 'N', 'N', -1, A, X, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 7
+ CALL CTPSV( 'U', 'N', 'N', 0, A, X, 0 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ GO TO 180
+ 120 INFOT = 1
+ CALL CGERC( -1, 0, ALPHA, X, 1, Y, 1, A, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 2
+ CALL CGERC( 0, -1, ALPHA, X, 1, Y, 1, A, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 5
+ CALL CGERC( 0, 0, ALPHA, X, 0, Y, 1, A, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 7
+ CALL CGERC( 0, 0, ALPHA, X, 1, Y, 0, A, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 9
+ CALL CGERC( 2, 0, ALPHA, X, 1, Y, 1, A, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ GO TO 180
+ 130 INFOT = 1
+ CALL CGERU( -1, 0, ALPHA, X, 1, Y, 1, A, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 2
+ CALL CGERU( 0, -1, ALPHA, X, 1, Y, 1, A, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 5
+ CALL CGERU( 0, 0, ALPHA, X, 0, Y, 1, A, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 7
+ CALL CGERU( 0, 0, ALPHA, X, 1, Y, 0, A, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 9
+ CALL CGERU( 2, 0, ALPHA, X, 1, Y, 1, A, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ GO TO 180
+ 140 INFOT = 1
+ CALL CHER( '/', 0, RALPHA, X, 1, A, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 2
+ CALL CHER( 'U', -1, RALPHA, X, 1, A, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 5
+ CALL CHER( 'U', 0, RALPHA, X, 0, A, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 7
+ CALL CHER( 'U', 2, RALPHA, X, 1, A, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ GO TO 180
+ 150 INFOT = 1
+ CALL CHPR( '/', 0, RALPHA, X, 1, A )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 2
+ CALL CHPR( 'U', -1, RALPHA, X, 1, A )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 5
+ CALL CHPR( 'U', 0, RALPHA, X, 0, A )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ GO TO 180
+ 160 INFOT = 1
+ CALL CHER2( '/', 0, ALPHA, X, 1, Y, 1, A, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 2
+ CALL CHER2( 'U', -1, ALPHA, X, 1, Y, 1, A, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 5
+ CALL CHER2( 'U', 0, ALPHA, X, 0, Y, 1, A, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 7
+ CALL CHER2( 'U', 0, ALPHA, X, 1, Y, 0, A, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 9
+ CALL CHER2( 'U', 2, ALPHA, X, 1, Y, 1, A, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ GO TO 180
+ 170 INFOT = 1
+ CALL CHPR2( '/', 0, ALPHA, X, 1, Y, 1, A )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 2
+ CALL CHPR2( 'U', -1, ALPHA, X, 1, Y, 1, A )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 5
+ CALL CHPR2( 'U', 0, ALPHA, X, 0, Y, 1, A )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 7
+ CALL CHPR2( 'U', 0, ALPHA, X, 1, Y, 0, A )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+*
+ 180 IF( OK )THEN
+ WRITE( NOUT, FMT = 9999 )SRNAMT
+ ELSE
+ WRITE( NOUT, FMT = 9998 )SRNAMT
+ END IF
+ RETURN
+*
+ 9999 FORMAT( ' ', A6, ' PASSED THE TESTS OF ERROR-EXITS' )
+ 9998 FORMAT( ' ******* ', A6, ' FAILED THE TESTS OF ERROR-EXITS *****',
+ $ '**' )
+*
+* End of CCHKE.
+*
+ END
+ SUBROUTINE CMAKE( TYPE, UPLO, DIAG, M, N, A, NMAX, AA, LDA, KL,
+ $ KU, RESET, TRANSL )
+*
+* Generates values for an M by N matrix A within the bandwidth
+* defined by KL and KU.
+* Stores the values in the array AA in the data structure required
+* by the routine, with unwanted elements set to rogue value.
+*
+* TYPE is 'GE', 'GB', 'HE', 'HB', 'HP', 'TR', 'TB' OR 'TP'.
+*
+* Auxiliary routine for test program for Level 2 Blas.
+*
+* -- Written on 10-August-1987.
+* Richard Hanson, Sandia National Labs.
+* Jeremy Du Croz, NAG Central Office.
+*
+* .. Parameters ..
+ COMPLEX ZERO, ONE
+ PARAMETER ( ZERO = ( 0.0, 0.0 ), ONE = ( 1.0, 0.0 ) )
+ COMPLEX ROGUE
+ PARAMETER ( ROGUE = ( -1.0E10, 1.0E10 ) )
+ REAL RZERO
+ PARAMETER ( RZERO = 0.0 )
+ REAL RROGUE
+ PARAMETER ( RROGUE = -1.0E10 )
+* .. Scalar Arguments ..
+ COMPLEX TRANSL
+ INTEGER KL, KU, LDA, M, N, NMAX
+ LOGICAL RESET
+ CHARACTER*1 DIAG, UPLO
+ CHARACTER*2 TYPE
+* .. Array Arguments ..
+ COMPLEX A( NMAX, * ), AA( * )
+* .. Local Scalars ..
+ INTEGER I, I1, I2, I3, IBEG, IEND, IOFF, J, JJ, KK
+ LOGICAL GEN, LOWER, SYM, TRI, UNIT, UPPER
+* .. External Functions ..
+ COMPLEX CBEG
+ EXTERNAL CBEG
+* .. Intrinsic Functions ..
+ INTRINSIC CMPLX, CONJG, MAX, MIN, REAL
+* .. Executable Statements ..
+ GEN = TYPE( 1: 1 ).EQ.'G'
+ SYM = TYPE( 1: 1 ).EQ.'H'
+ TRI = TYPE( 1: 1 ).EQ.'T'
+ UPPER = ( SYM.OR.TRI ).AND.UPLO.EQ.'U'
+ LOWER = ( SYM.OR.TRI ).AND.UPLO.EQ.'L'
+ UNIT = TRI.AND.DIAG.EQ.'U'
+*
+* Generate data in array A.
+*
+ DO 20 J = 1, N
+ DO 10 I = 1, M
+ IF( GEN.OR.( UPPER.AND.I.LE.J ).OR.( LOWER.AND.I.GE.J ) )
+ $ THEN
+ IF( ( I.LE.J.AND.J - I.LE.KU ).OR.
+ $ ( I.GE.J.AND.I - J.LE.KL ) )THEN
+ A( I, J ) = CBEG( RESET ) + TRANSL
+ ELSE
+ A( I, J ) = ZERO
+ END IF
+ IF( I.NE.J )THEN
+ IF( SYM )THEN
+ A( J, I ) = CONJG( A( I, J ) )
+ ELSE IF( TRI )THEN
+ A( J, I ) = ZERO
+ END IF
+ END IF
+ END IF
+ 10 CONTINUE
+ IF( SYM )
+ $ A( J, J ) = CMPLX( REAL( A( J, J ) ), RZERO )
+ IF( TRI )
+ $ A( J, J ) = A( J, J ) + ONE
+ IF( UNIT )
+ $ A( J, J ) = ONE
+ 20 CONTINUE
+*
+* Store elements in array AS in data structure required by routine.
+*
+ IF( TYPE.EQ.'GE' )THEN
+ DO 50 J = 1, N
+ DO 30 I = 1, M
+ AA( I + ( J - 1 )*LDA ) = A( I, J )
+ 30 CONTINUE
+ DO 40 I = M + 1, LDA
+ AA( I + ( J - 1 )*LDA ) = ROGUE
+ 40 CONTINUE
+ 50 CONTINUE
+ ELSE IF( TYPE.EQ.'GB' )THEN
+ DO 90 J = 1, N
+ DO 60 I1 = 1, KU + 1 - J
+ AA( I1 + ( J - 1 )*LDA ) = ROGUE
+ 60 CONTINUE
+ DO 70 I2 = I1, MIN( KL + KU + 1, KU + 1 + M - J )
+ AA( I2 + ( J - 1 )*LDA ) = A( I2 + J - KU - 1, J )
+ 70 CONTINUE
+ DO 80 I3 = I2, LDA
+ AA( I3 + ( J - 1 )*LDA ) = ROGUE
+ 80 CONTINUE
+ 90 CONTINUE
+ ELSE IF( TYPE.EQ.'HE'.OR.TYPE.EQ.'TR' )THEN
+ DO 130 J = 1, N
+ IF( UPPER )THEN
+ IBEG = 1
+ IF( UNIT )THEN
+ IEND = J - 1
+ ELSE
+ IEND = J
+ END IF
+ ELSE
+ IF( UNIT )THEN
+ IBEG = J + 1
+ ELSE
+ IBEG = J
+ END IF
+ IEND = N
+ END IF
+ DO 100 I = 1, IBEG - 1
+ AA( I + ( J - 1 )*LDA ) = ROGUE
+ 100 CONTINUE
+ DO 110 I = IBEG, IEND
+ AA( I + ( J - 1 )*LDA ) = A( I, J )
+ 110 CONTINUE
+ DO 120 I = IEND + 1, LDA
+ AA( I + ( J - 1 )*LDA ) = ROGUE
+ 120 CONTINUE
+ IF( SYM )THEN
+ JJ = J + ( J - 1 )*LDA
+ AA( JJ ) = CMPLX( REAL( AA( JJ ) ), RROGUE )
+ END IF
+ 130 CONTINUE
+ ELSE IF( TYPE.EQ.'HB'.OR.TYPE.EQ.'TB' )THEN
+ DO 170 J = 1, N
+ IF( UPPER )THEN
+ KK = KL + 1
+ IBEG = MAX( 1, KL + 2 - J )
+ IF( UNIT )THEN
+ IEND = KL
+ ELSE
+ IEND = KL + 1
+ END IF
+ ELSE
+ KK = 1
+ IF( UNIT )THEN
+ IBEG = 2
+ ELSE
+ IBEG = 1
+ END IF
+ IEND = MIN( KL + 1, 1 + M - J )
+ END IF
+ DO 140 I = 1, IBEG - 1
+ AA( I + ( J - 1 )*LDA ) = ROGUE
+ 140 CONTINUE
+ DO 150 I = IBEG, IEND
+ AA( I + ( J - 1 )*LDA ) = A( I + J - KK, J )
+ 150 CONTINUE
+ DO 160 I = IEND + 1, LDA
+ AA( I + ( J - 1 )*LDA ) = ROGUE
+ 160 CONTINUE
+ IF( SYM )THEN
+ JJ = KK + ( J - 1 )*LDA
+ AA( JJ ) = CMPLX( REAL( AA( JJ ) ), RROGUE )
+ END IF
+ 170 CONTINUE
+ ELSE IF( TYPE.EQ.'HP'.OR.TYPE.EQ.'TP' )THEN
+ IOFF = 0
+ DO 190 J = 1, N
+ IF( UPPER )THEN
+ IBEG = 1
+ IEND = J
+ ELSE
+ IBEG = J
+ IEND = N
+ END IF
+ DO 180 I = IBEG, IEND
+ IOFF = IOFF + 1
+ AA( IOFF ) = A( I, J )
+ IF( I.EQ.J )THEN
+ IF( UNIT )
+ $ AA( IOFF ) = ROGUE
+ IF( SYM )
+ $ AA( IOFF ) = CMPLX( REAL( AA( IOFF ) ), RROGUE )
+ END IF
+ 180 CONTINUE
+ 190 CONTINUE
+ END IF
+ RETURN
+*
+* End of CMAKE.
+*
+ END
+ SUBROUTINE CMVCH( TRANS, M, N, ALPHA, A, NMAX, X, INCX, BETA, Y,
+ $ INCY, YT, G, YY, EPS, ERR, FATAL, NOUT, MV )
+*
+* Checks the results of the computational tests.
+*
+* Auxiliary routine for test program for Level 2 Blas.
+*
+* -- Written on 10-August-1987.
+* Richard Hanson, Sandia National Labs.
+* Jeremy Du Croz, NAG Central Office.
+*
+* .. Parameters ..
+ COMPLEX ZERO
+ PARAMETER ( ZERO = ( 0.0, 0.0 ) )
+ REAL RZERO, RONE
+ PARAMETER ( RZERO = 0.0, RONE = 1.0 )
+* .. Scalar Arguments ..
+ COMPLEX ALPHA, BETA
+ REAL EPS, ERR
+ INTEGER INCX, INCY, M, N, NMAX, NOUT
+ LOGICAL FATAL, MV
+ CHARACTER*1 TRANS
+* .. Array Arguments ..
+ COMPLEX A( NMAX, * ), X( * ), Y( * ), YT( * ), YY( * )
+ REAL G( * )
+* .. Local Scalars ..
+ COMPLEX C
+ REAL ERRI
+ INTEGER I, INCXL, INCYL, IY, J, JX, KX, KY, ML, NL
+ LOGICAL CTRAN, TRAN
+* .. Intrinsic Functions ..
+ INTRINSIC ABS, AIMAG, CONJG, MAX, REAL, SQRT
+* .. Statement Functions ..
+ REAL ABS1
+* .. Statement Function definitions ..
+ ABS1( C ) = ABS( REAL( C ) ) + ABS( AIMAG( C ) )
+* .. Executable Statements ..
+ TRAN = TRANS.EQ.'T'
+ CTRAN = TRANS.EQ.'C'
+ IF( TRAN.OR.CTRAN )THEN
+ ML = N
+ NL = M
+ ELSE
+ ML = M
+ NL = N
+ END IF
+ IF( INCX.LT.0 )THEN
+ KX = NL
+ INCXL = -1
+ ELSE
+ KX = 1
+ INCXL = 1
+ END IF
+ IF( INCY.LT.0 )THEN
+ KY = ML
+ INCYL = -1
+ ELSE
+ KY = 1
+ INCYL = 1
+ END IF
+*
+* Compute expected result in YT using data in A, X and Y.
+* Compute gauges in G.
+*
+ IY = KY
+ DO 40 I = 1, ML
+ YT( IY ) = ZERO
+ G( IY ) = RZERO
+ JX = KX
+ IF( TRAN )THEN
+ DO 10 J = 1, NL
+ YT( IY ) = YT( IY ) + A( J, I )*X( JX )
+ G( IY ) = G( IY ) + ABS1( A( J, I ) )*ABS1( X( JX ) )
+ JX = JX + INCXL
+ 10 CONTINUE
+ ELSE IF( CTRAN )THEN
+ DO 20 J = 1, NL
+ YT( IY ) = YT( IY ) + CONJG( A( J, I ) )*X( JX )
+ G( IY ) = G( IY ) + ABS1( A( J, I ) )*ABS1( X( JX ) )
+ JX = JX + INCXL
+ 20 CONTINUE
+ ELSE
+ DO 30 J = 1, NL
+ YT( IY ) = YT( IY ) + A( I, J )*X( JX )
+ G( IY ) = G( IY ) + ABS1( A( I, J ) )*ABS1( X( JX ) )
+ JX = JX + INCXL
+ 30 CONTINUE
+ END IF
+ YT( IY ) = ALPHA*YT( IY ) + BETA*Y( IY )
+ G( IY ) = ABS1( ALPHA )*G( IY ) + ABS1( BETA )*ABS1( Y( IY ) )
+ IY = IY + INCYL
+ 40 CONTINUE
+*
+* Compute the error ratio for this result.
+*
+ ERR = ZERO
+ DO 50 I = 1, ML
+ ERRI = ABS( YT( I ) - YY( 1 + ( I - 1 )*ABS( INCY ) ) )/EPS
+ IF( G( I ).NE.RZERO )
+ $ ERRI = ERRI/G( I )
+ ERR = MAX( ERR, ERRI )
+ IF( ERR*SQRT( EPS ).GE.RONE )
+ $ GO TO 60
+ 50 CONTINUE
+* If the loop completes, all results are at least half accurate.
+ GO TO 80
+*
+* Report fatal error.
+*
+ 60 FATAL = .TRUE.
+ WRITE( NOUT, FMT = 9999 )
+ DO 70 I = 1, ML
+ IF( MV )THEN
+ WRITE( NOUT, FMT = 9998 )I, YT( I ),
+ $ YY( 1 + ( I - 1 )*ABS( INCY ) )
+ ELSE
+ WRITE( NOUT, FMT = 9998 )I,
+ $ YY( 1 + ( I - 1 )*ABS( INCY ) ), YT( I )
+ END IF
+ 70 CONTINUE
+*
+ 80 CONTINUE
+ RETURN
+*
+ 9999 FORMAT( ' ******* FATAL ERROR - COMPUTED RESULT IS LESS THAN HAL',
+ $ 'F ACCURATE *******', /' EXPECTED RE',
+ $ 'SULT COMPUTED RESULT' )
+ 9998 FORMAT( 1X, I7, 2( ' (', G15.6, ',', G15.6, ')' ) )
+*
+* End of CMVCH.
+*
+ END
+ LOGICAL FUNCTION LCE( RI, RJ, LR )
+*
+* Tests if two arrays are identical.
+*
+* Auxiliary routine for test program for Level 2 Blas.
+*
+* -- Written on 10-August-1987.
+* Richard Hanson, Sandia National Labs.
+* Jeremy Du Croz, NAG Central Office.
+*
+* .. Scalar Arguments ..
+ INTEGER LR
+* .. Array Arguments ..
+ COMPLEX RI( * ), RJ( * )
+* .. Local Scalars ..
+ INTEGER I
+* .. Executable Statements ..
+ DO 10 I = 1, LR
+ IF( RI( I ).NE.RJ( I ) )
+ $ GO TO 20
+ 10 CONTINUE
+ LCE = .TRUE.
+ GO TO 30
+ 20 CONTINUE
+ LCE = .FALSE.
+ 30 RETURN
+*
+* End of LCE.
+*
+ END
+ LOGICAL FUNCTION LCERES( TYPE, UPLO, M, N, AA, AS, LDA )
+*
+* Tests if selected elements in two arrays are equal.
+*
+* TYPE is 'GE', 'HE' or 'HP'.
+*
+* Auxiliary routine for test program for Level 2 Blas.
+*
+* -- Written on 10-August-1987.
+* Richard Hanson, Sandia National Labs.
+* Jeremy Du Croz, NAG Central Office.
+*
+* .. Scalar Arguments ..
+ INTEGER LDA, M, N
+ CHARACTER*1 UPLO
+ CHARACTER*2 TYPE
+* .. Array Arguments ..
+ COMPLEX AA( LDA, * ), AS( LDA, * )
+* .. Local Scalars ..
+ INTEGER I, IBEG, IEND, J
+ LOGICAL UPPER
+* .. Executable Statements ..
+ UPPER = UPLO.EQ.'U'
+ IF( TYPE.EQ.'GE' )THEN
+ DO 20 J = 1, N
+ DO 10 I = M + 1, LDA
+ IF( AA( I, J ).NE.AS( I, J ) )
+ $ GO TO 70
+ 10 CONTINUE
+ 20 CONTINUE
+ ELSE IF( TYPE.EQ.'HE' )THEN
+ DO 50 J = 1, N
+ IF( UPPER )THEN
+ IBEG = 1
+ IEND = J
+ ELSE
+ IBEG = J
+ IEND = N
+ END IF
+ DO 30 I = 1, IBEG - 1
+ IF( AA( I, J ).NE.AS( I, J ) )
+ $ GO TO 70
+ 30 CONTINUE
+ DO 40 I = IEND + 1, LDA
+ IF( AA( I, J ).NE.AS( I, J ) )
+ $ GO TO 70
+ 40 CONTINUE
+ 50 CONTINUE
+ END IF
+*
+ 60 CONTINUE
+ LCERES = .TRUE.
+ GO TO 80
+ 70 CONTINUE
+ LCERES = .FALSE.
+ 80 RETURN
+*
+* End of LCERES.
+*
+ END
+ COMPLEX FUNCTION CBEG( RESET )
+*
+* Generates complex numbers as pairs of random numbers uniformly
+* distributed between -0.5 and 0.5.
+*
+* Auxiliary routine for test program for Level 2 Blas.
+*
+* -- Written on 10-August-1987.
+* Richard Hanson, Sandia National Labs.
+* Jeremy Du Croz, NAG Central Office.
+*
+* .. Scalar Arguments ..
+ LOGICAL RESET
+* .. Local Scalars ..
+ INTEGER I, IC, J, MI, MJ
+* .. Save statement ..
+ SAVE I, IC, J, MI, MJ
+* .. Intrinsic Functions ..
+ INTRINSIC CMPLX
+* .. Executable Statements ..
+ IF( RESET )THEN
+* Initialize local variables.
+ MI = 891
+ MJ = 457
+ I = 7
+ J = 7
+ IC = 0
+ RESET = .FALSE.
+ END IF
+*
+* The sequence of values of I or J is bounded between 1 and 999.
+* If initial I or J = 1,2,3,6,7 or 9, the period will be 50.
+* If initial I or J = 4 or 8, the period will be 25.
+* If initial I or J = 5, the period will be 10.
+* IC is used to break up the period by skipping 1 value of I or J
+* in 6.
+*
+ IC = IC + 1
+ 10 I = I*MI
+ J = J*MJ
+ I = I - 1000*( I/1000 )
+ J = J - 1000*( J/1000 )
+ IF( IC.GE.5 )THEN
+ IC = 0
+ GO TO 10
+ END IF
+ CBEG = CMPLX( ( I - 500 )/1001.0, ( J - 500 )/1001.0 )
+ RETURN
+*
+* End of CBEG.
+*
+ END
+ REAL FUNCTION SDIFF( X, Y )
+*
+* Auxiliary routine for test program for Level 2 Blas.
+*
+* -- Written on 10-August-1987.
+* Richard Hanson, Sandia National Labs.
+*
+* .. Scalar Arguments ..
+ REAL X, Y
+* .. Executable Statements ..
+ SDIFF = X - Y
+ RETURN
+*
+* End of SDIFF.
+*
+ END
+ SUBROUTINE CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+*
+* Tests whether XERBLA has detected an error when it should.
+*
+* Auxiliary routine for test program for Level 2 Blas.
+*
+* -- Written on 10-August-1987.
+* Richard Hanson, Sandia National Labs.
+* Jeremy Du Croz, NAG Central Office.
+*
+* .. Scalar Arguments ..
+ INTEGER INFOT, NOUT
+ LOGICAL LERR, OK
+ CHARACTER*6 SRNAMT
+* .. Executable Statements ..
+ IF( .NOT.LERR )THEN
+ WRITE( NOUT, FMT = 9999 )INFOT, SRNAMT
+ OK = .FALSE.
+ END IF
+ LERR = .FALSE.
+ RETURN
+*
+ 9999 FORMAT( ' ***** ILLEGAL VALUE OF PARAMETER NUMBER ', I2, ' NOT D',
+ $ 'ETECTED BY ', A6, ' *****' )
+*
+* End of CHKXER.
+*
+ END
+ SUBROUTINE XERBLA( SRNAME, INFO )
+*
+* This is a special version of XERBLA to be used only as part of
+* the test program for testing error exits from the Level 2 BLAS
+* routines.
+*
+* XERBLA is an error handler for the Level 2 BLAS routines.
+*
+* It is called by the Level 2 BLAS routines if an input parameter is
+* invalid.
+*
+* Auxiliary routine for test program for Level 2 Blas.
+*
+* -- Written on 10-August-1987.
+* Richard Hanson, Sandia National Labs.
+* Jeremy Du Croz, NAG Central Office.
+*
+* .. Scalar Arguments ..
+ INTEGER INFO
+ CHARACTER*6 SRNAME
+* .. Scalars in Common ..
+ INTEGER INFOT, NOUT
+ LOGICAL LERR, OK
+ CHARACTER*6 SRNAMT
+* .. Common blocks ..
+ COMMON /INFOC/INFOT, NOUT, OK, LERR
+ COMMON /SRNAMC/SRNAMT
+* .. Executable Statements ..
+ LERR = .TRUE.
+ IF( INFO.NE.INFOT )THEN
+ IF( INFOT.NE.0 )THEN
+ WRITE( NOUT, FMT = 9999 )INFO, INFOT
+ ELSE
+ WRITE( NOUT, FMT = 9997 )INFO
+ END IF
+ OK = .FALSE.
+ END IF
+ IF( SRNAME.NE.SRNAMT )THEN
+ WRITE( NOUT, FMT = 9998 )SRNAME, SRNAMT
+ OK = .FALSE.
+ END IF
+ RETURN
+*
+ 9999 FORMAT( ' ******* XERBLA WAS CALLED WITH INFO = ', I6, ' INSTEAD',
+ $ ' OF ', I2, ' *******' )
+ 9998 FORMAT( ' ******* XERBLA WAS CALLED WITH SRNAME = ', A6, ' INSTE',
+ $ 'AD OF ', A6, ' *******' )
+ 9997 FORMAT( ' ******* XERBLA WAS CALLED WITH INFO = ', I6,
+ $ ' *******' )
+*
+* End of XERBLA
+*
+ END
+
diff --git a/blas/testing/cblat3.dat b/blas/testing/cblat3.dat
new file mode 100644
index 000000000..59881eac3
--- /dev/null
+++ b/blas/testing/cblat3.dat
@@ -0,0 +1,23 @@
+'cblat3.summ' NAME OF SUMMARY OUTPUT FILE
+6 UNIT NUMBER OF SUMMARY FILE
+'cblat3.snap' NAME OF SNAPSHOT OUTPUT FILE
+-1 UNIT NUMBER OF SNAPSHOT FILE (NOT USED IF .LT. 0)
+F LOGICAL FLAG, T TO REWIND SNAPSHOT FILE AFTER EACH RECORD.
+F LOGICAL FLAG, T TO STOP ON FAILURES.
+F LOGICAL FLAG, T TO TEST ERROR EXITS.
+16.0 THRESHOLD VALUE OF TEST RATIO
+6 NUMBER OF VALUES OF N
+0 1 2 3 5 9 VALUES OF N
+3 NUMBER OF VALUES OF ALPHA
+(0.0,0.0) (1.0,0.0) (0.7,-0.9) VALUES OF ALPHA
+3 NUMBER OF VALUES OF BETA
+(0.0,0.0) (1.0,0.0) (1.3,-1.1) VALUES OF BETA
+CGEMM T PUT F FOR NO TEST. SAME COLUMNS.
+CHEMM T PUT F FOR NO TEST. SAME COLUMNS.
+CSYMM T PUT F FOR NO TEST. SAME COLUMNS.
+CTRMM T PUT F FOR NO TEST. SAME COLUMNS.
+CTRSM T PUT F FOR NO TEST. SAME COLUMNS.
+CHERK T PUT F FOR NO TEST. SAME COLUMNS.
+CSYRK T PUT F FOR NO TEST. SAME COLUMNS.
+CHER2K T PUT F FOR NO TEST. SAME COLUMNS.
+CSYR2K T PUT F FOR NO TEST. SAME COLUMNS.
diff --git a/blas/testing/cblat3.f b/blas/testing/cblat3.f
new file mode 100644
index 000000000..b26be91e6
--- /dev/null
+++ b/blas/testing/cblat3.f
@@ -0,0 +1,3439 @@
+ PROGRAM CBLAT3
+*
+* Test program for the COMPLEX Level 3 Blas.
+*
+* The program must be driven by a short data file. The first 14 records
+* of the file are read using list-directed input, the last 9 records
+* are read using the format ( A6, L2 ). An annotated example of a data
+* file can be obtained by deleting the first 3 characters from the
+* following 23 lines:
+* 'CBLAT3.SUMM' NAME OF SUMMARY OUTPUT FILE
+* 6 UNIT NUMBER OF SUMMARY FILE
+* 'CBLAT3.SNAP' NAME OF SNAPSHOT OUTPUT FILE
+* -1 UNIT NUMBER OF SNAPSHOT FILE (NOT USED IF .LT. 0)
+* F LOGICAL FLAG, T TO REWIND SNAPSHOT FILE AFTER EACH RECORD.
+* F LOGICAL FLAG, T TO STOP ON FAILURES.
+* T LOGICAL FLAG, T TO TEST ERROR EXITS.
+* 16.0 THRESHOLD VALUE OF TEST RATIO
+* 6 NUMBER OF VALUES OF N
+* 0 1 2 3 5 9 VALUES OF N
+* 3 NUMBER OF VALUES OF ALPHA
+* (0.0,0.0) (1.0,0.0) (0.7,-0.9) VALUES OF ALPHA
+* 3 NUMBER OF VALUES OF BETA
+* (0.0,0.0) (1.0,0.0) (1.3,-1.1) VALUES OF BETA
+* CGEMM T PUT F FOR NO TEST. SAME COLUMNS.
+* CHEMM T PUT F FOR NO TEST. SAME COLUMNS.
+* CSYMM T PUT F FOR NO TEST. SAME COLUMNS.
+* CTRMM T PUT F FOR NO TEST. SAME COLUMNS.
+* CTRSM T PUT F FOR NO TEST. SAME COLUMNS.
+* CHERK T PUT F FOR NO TEST. SAME COLUMNS.
+* CSYRK T PUT F FOR NO TEST. SAME COLUMNS.
+* CHER2K T PUT F FOR NO TEST. SAME COLUMNS.
+* CSYR2K T PUT F FOR NO TEST. SAME COLUMNS.
+*
+* See:
+*
+* Dongarra J. J., Du Croz J. J., Duff I. S. and Hammarling S.
+* A Set of Level 3 Basic Linear Algebra Subprograms.
+*
+* Technical Memorandum No.88 (Revision 1), Mathematics and
+* Computer Science Division, Argonne National Laboratory, 9700
+* South Cass Avenue, Argonne, Illinois 60439, US.
+*
+* -- Written on 8-February-1989.
+* Jack Dongarra, Argonne National Laboratory.
+* Iain Duff, AERE Harwell.
+* Jeremy Du Croz, Numerical Algorithms Group Ltd.
+* Sven Hammarling, Numerical Algorithms Group Ltd.
+*
+* .. Parameters ..
+ INTEGER NIN
+ PARAMETER ( NIN = 5 )
+ INTEGER NSUBS
+ PARAMETER ( NSUBS = 9 )
+ COMPLEX ZERO, ONE
+ PARAMETER ( ZERO = ( 0.0, 0.0 ), ONE = ( 1.0, 0.0 ) )
+ REAL RZERO, RHALF, RONE
+ PARAMETER ( RZERO = 0.0, RHALF = 0.5, RONE = 1.0 )
+ INTEGER NMAX
+ PARAMETER ( NMAX = 65 )
+ INTEGER NIDMAX, NALMAX, NBEMAX
+ PARAMETER ( NIDMAX = 9, NALMAX = 7, NBEMAX = 7 )
+* .. Local Scalars ..
+ REAL EPS, ERR, THRESH
+ INTEGER I, ISNUM, J, N, NALF, NBET, NIDIM, NOUT, NTRA
+ LOGICAL FATAL, LTESTT, REWI, SAME, SFATAL, TRACE,
+ $ TSTERR
+ CHARACTER*1 TRANSA, TRANSB
+ CHARACTER*6 SNAMET
+ CHARACTER*32 SNAPS, SUMMRY
+* .. Local Arrays ..
+ COMPLEX AA( NMAX*NMAX ), AB( NMAX, 2*NMAX ),
+ $ ALF( NALMAX ), AS( NMAX*NMAX ),
+ $ BB( NMAX*NMAX ), BET( NBEMAX ),
+ $ BS( NMAX*NMAX ), C( NMAX, NMAX ),
+ $ CC( NMAX*NMAX ), CS( NMAX*NMAX ), CT( NMAX ),
+ $ W( 2*NMAX )
+ REAL G( NMAX )
+ INTEGER IDIM( NIDMAX )
+ LOGICAL LTEST( NSUBS )
+ CHARACTER*6 SNAMES( NSUBS )
+* .. External Functions ..
+ REAL SDIFF
+ LOGICAL LCE
+ EXTERNAL SDIFF, LCE
+* .. External Subroutines ..
+ EXTERNAL CCHK1, CCHK2, CCHK3, CCHK4, CCHK5, CCHKE, CMMCH
+* .. Intrinsic Functions ..
+ INTRINSIC MAX, MIN
+* .. Scalars in Common ..
+ INTEGER INFOT, NOUTC
+ LOGICAL LERR, OK
+ CHARACTER*6 SRNAMT
+* .. Common blocks ..
+ COMMON /INFOC/INFOT, NOUTC, OK, LERR
+ COMMON /SRNAMC/SRNAMT
+* .. Data statements ..
+ DATA SNAMES/'CGEMM ', 'CHEMM ', 'CSYMM ', 'CTRMM ',
+ $ 'CTRSM ', 'CHERK ', 'CSYRK ', 'CHER2K',
+ $ 'CSYR2K'/
+* .. Executable Statements ..
+*
+* Read name and unit number for summary output file and open file.
+*
+ READ( NIN, FMT = * )SUMMRY
+ READ( NIN, FMT = * )NOUT
+ OPEN( NOUT, FILE = SUMMRY, STATUS = 'NEW' )
+ NOUTC = NOUT
+*
+* Read name and unit number for snapshot output file and open file.
+*
+ READ( NIN, FMT = * )SNAPS
+ READ( NIN, FMT = * )NTRA
+ TRACE = NTRA.GE.0
+ IF( TRACE )THEN
+ OPEN( NTRA, FILE = SNAPS, STATUS = 'NEW' )
+ END IF
+* Read the flag that directs rewinding of the snapshot file.
+ READ( NIN, FMT = * )REWI
+ REWI = REWI.AND.TRACE
+* Read the flag that directs stopping on any failure.
+ READ( NIN, FMT = * )SFATAL
+* Read the flag that indicates whether error exits are to be tested.
+ READ( NIN, FMT = * )TSTERR
+* Read the threshold value of the test ratio
+ READ( NIN, FMT = * )THRESH
+*
+* Read and check the parameter values for the tests.
+*
+* Values of N
+ READ( NIN, FMT = * )NIDIM
+ IF( NIDIM.LT.1.OR.NIDIM.GT.NIDMAX )THEN
+ WRITE( NOUT, FMT = 9997 )'N', NIDMAX
+ GO TO 220
+ END IF
+ READ( NIN, FMT = * )( IDIM( I ), I = 1, NIDIM )
+ DO 10 I = 1, NIDIM
+ IF( IDIM( I ).LT.0.OR.IDIM( I ).GT.NMAX )THEN
+ WRITE( NOUT, FMT = 9996 )NMAX
+ GO TO 220
+ END IF
+ 10 CONTINUE
+* Values of ALPHA
+ READ( NIN, FMT = * )NALF
+ IF( NALF.LT.1.OR.NALF.GT.NALMAX )THEN
+ WRITE( NOUT, FMT = 9997 )'ALPHA', NALMAX
+ GO TO 220
+ END IF
+ READ( NIN, FMT = * )( ALF( I ), I = 1, NALF )
+* Values of BETA
+ READ( NIN, FMT = * )NBET
+ IF( NBET.LT.1.OR.NBET.GT.NBEMAX )THEN
+ WRITE( NOUT, FMT = 9997 )'BETA', NBEMAX
+ GO TO 220
+ END IF
+ READ( NIN, FMT = * )( BET( I ), I = 1, NBET )
+*
+* Report values of parameters.
+*
+ WRITE( NOUT, FMT = 9995 )
+ WRITE( NOUT, FMT = 9994 )( IDIM( I ), I = 1, NIDIM )
+ WRITE( NOUT, FMT = 9993 )( ALF( I ), I = 1, NALF )
+ WRITE( NOUT, FMT = 9992 )( BET( I ), I = 1, NBET )
+ IF( .NOT.TSTERR )THEN
+ WRITE( NOUT, FMT = * )
+ WRITE( NOUT, FMT = 9984 )
+ END IF
+ WRITE( NOUT, FMT = * )
+ WRITE( NOUT, FMT = 9999 )THRESH
+ WRITE( NOUT, FMT = * )
+*
+* Read names of subroutines and flags which indicate
+* whether they are to be tested.
+*
+ DO 20 I = 1, NSUBS
+ LTEST( I ) = .FALSE.
+ 20 CONTINUE
+ 30 READ( NIN, FMT = 9988, END = 60 )SNAMET, LTESTT
+ DO 40 I = 1, NSUBS
+ IF( SNAMET.EQ.SNAMES( I ) )
+ $ GO TO 50
+ 40 CONTINUE
+ WRITE( NOUT, FMT = 9990 )SNAMET
+ STOP
+ 50 LTEST( I ) = LTESTT
+ GO TO 30
+*
+ 60 CONTINUE
+ CLOSE ( NIN )
+*
+* Compute EPS (the machine precision).
+*
+ EPS = RONE
+ 70 CONTINUE
+ IF( SDIFF( RONE + EPS, RONE ).EQ.RZERO )
+ $ GO TO 80
+ EPS = RHALF*EPS
+ GO TO 70
+ 80 CONTINUE
+ EPS = EPS + EPS
+ WRITE( NOUT, FMT = 9998 )EPS
+*
+* Check the reliability of CMMCH using exact data.
+*
+ N = MIN( 32, NMAX )
+ DO 100 J = 1, N
+ DO 90 I = 1, N
+ AB( I, J ) = MAX( I - J + 1, 0 )
+ 90 CONTINUE
+ AB( J, NMAX + 1 ) = J
+ AB( 1, NMAX + J ) = J
+ C( J, 1 ) = ZERO
+ 100 CONTINUE
+ DO 110 J = 1, N
+ CC( J ) = J*( ( J + 1 )*J )/2 - ( ( J + 1 )*J*( J - 1 ) )/3
+ 110 CONTINUE
+* CC holds the exact result. On exit from CMMCH CT holds
+* the result computed by CMMCH.
+ TRANSA = 'N'
+ TRANSB = 'N'
+ CALL CMMCH( TRANSA, TRANSB, N, 1, N, ONE, AB, NMAX,
+ $ AB( 1, NMAX + 1 ), NMAX, ZERO, C, NMAX, CT, G, CC,
+ $ NMAX, EPS, ERR, FATAL, NOUT, .TRUE. )
+ SAME = LCE( CC, CT, N )
+ IF( .NOT.SAME.OR.ERR.NE.RZERO )THEN
+ WRITE( NOUT, FMT = 9989 )TRANSA, TRANSB, SAME, ERR
+ STOP
+ END IF
+ TRANSB = 'C'
+ CALL CMMCH( TRANSA, TRANSB, N, 1, N, ONE, AB, NMAX,
+ $ AB( 1, NMAX + 1 ), NMAX, ZERO, C, NMAX, CT, G, CC,
+ $ NMAX, EPS, ERR, FATAL, NOUT, .TRUE. )
+ SAME = LCE( CC, CT, N )
+ IF( .NOT.SAME.OR.ERR.NE.RZERO )THEN
+ WRITE( NOUT, FMT = 9989 )TRANSA, TRANSB, SAME, ERR
+ STOP
+ END IF
+ DO 120 J = 1, N
+ AB( J, NMAX + 1 ) = N - J + 1
+ AB( 1, NMAX + J ) = N - J + 1
+ 120 CONTINUE
+ DO 130 J = 1, N
+ CC( N - J + 1 ) = J*( ( J + 1 )*J )/2 -
+ $ ( ( J + 1 )*J*( J - 1 ) )/3
+ 130 CONTINUE
+ TRANSA = 'C'
+ TRANSB = 'N'
+ CALL CMMCH( TRANSA, TRANSB, N, 1, N, ONE, AB, NMAX,
+ $ AB( 1, NMAX + 1 ), NMAX, ZERO, C, NMAX, CT, G, CC,
+ $ NMAX, EPS, ERR, FATAL, NOUT, .TRUE. )
+ SAME = LCE( CC, CT, N )
+ IF( .NOT.SAME.OR.ERR.NE.RZERO )THEN
+ WRITE( NOUT, FMT = 9989 )TRANSA, TRANSB, SAME, ERR
+ STOP
+ END IF
+ TRANSB = 'C'
+ CALL CMMCH( TRANSA, TRANSB, N, 1, N, ONE, AB, NMAX,
+ $ AB( 1, NMAX + 1 ), NMAX, ZERO, C, NMAX, CT, G, CC,
+ $ NMAX, EPS, ERR, FATAL, NOUT, .TRUE. )
+ SAME = LCE( CC, CT, N )
+ IF( .NOT.SAME.OR.ERR.NE.RZERO )THEN
+ WRITE( NOUT, FMT = 9989 )TRANSA, TRANSB, SAME, ERR
+ STOP
+ END IF
+*
+* Test each subroutine in turn.
+*
+ DO 200 ISNUM = 1, NSUBS
+ WRITE( NOUT, FMT = * )
+ IF( .NOT.LTEST( ISNUM ) )THEN
+* Subprogram is not to be tested.
+ WRITE( NOUT, FMT = 9987 )SNAMES( ISNUM )
+ ELSE
+ SRNAMT = SNAMES( ISNUM )
+* Test error exits.
+ IF( TSTERR )THEN
+ CALL CCHKE( ISNUM, SNAMES( ISNUM ), NOUT )
+ WRITE( NOUT, FMT = * )
+ END IF
+* Test computations.
+ INFOT = 0
+ OK = .TRUE.
+ FATAL = .FALSE.
+ GO TO ( 140, 150, 150, 160, 160, 170, 170,
+ $ 180, 180 )ISNUM
+* Test CGEMM, 01.
+ 140 CALL CCHK1( SNAMES( ISNUM ), EPS, THRESH, NOUT, NTRA, TRACE,
+ $ REWI, FATAL, NIDIM, IDIM, NALF, ALF, NBET, BET,
+ $ NMAX, AB, AA, AS, AB( 1, NMAX + 1 ), BB, BS, C,
+ $ CC, CS, CT, G )
+ GO TO 190
+* Test CHEMM, 02, CSYMM, 03.
+ 150 CALL CCHK2( SNAMES( ISNUM ), EPS, THRESH, NOUT, NTRA, TRACE,
+ $ REWI, FATAL, NIDIM, IDIM, NALF, ALF, NBET, BET,
+ $ NMAX, AB, AA, AS, AB( 1, NMAX + 1 ), BB, BS, C,
+ $ CC, CS, CT, G )
+ GO TO 190
+* Test CTRMM, 04, CTRSM, 05.
+ 160 CALL CCHK3( SNAMES( ISNUM ), EPS, THRESH, NOUT, NTRA, TRACE,
+ $ REWI, FATAL, NIDIM, IDIM, NALF, ALF, NMAX, AB,
+ $ AA, AS, AB( 1, NMAX + 1 ), BB, BS, CT, G, C )
+ GO TO 190
+* Test CHERK, 06, CSYRK, 07.
+ 170 CALL CCHK4( SNAMES( ISNUM ), EPS, THRESH, NOUT, NTRA, TRACE,
+ $ REWI, FATAL, NIDIM, IDIM, NALF, ALF, NBET, BET,
+ $ NMAX, AB, AA, AS, AB( 1, NMAX + 1 ), BB, BS, C,
+ $ CC, CS, CT, G )
+ GO TO 190
+* Test CHER2K, 08, CSYR2K, 09.
+ 180 CALL CCHK5( SNAMES( ISNUM ), EPS, THRESH, NOUT, NTRA, TRACE,
+ $ REWI, FATAL, NIDIM, IDIM, NALF, ALF, NBET, BET,
+ $ NMAX, AB, AA, AS, BB, BS, C, CC, CS, CT, G, W )
+ GO TO 190
+*
+ 190 IF( FATAL.AND.SFATAL )
+ $ GO TO 210
+ END IF
+ 200 CONTINUE
+ WRITE( NOUT, FMT = 9986 )
+ GO TO 230
+*
+ 210 CONTINUE
+ WRITE( NOUT, FMT = 9985 )
+ GO TO 230
+*
+ 220 CONTINUE
+ WRITE( NOUT, FMT = 9991 )
+*
+ 230 CONTINUE
+ IF( TRACE )
+ $ CLOSE ( NTRA )
+ CLOSE ( NOUT )
+ STOP
+*
+ 9999 FORMAT( ' ROUTINES PASS COMPUTATIONAL TESTS IF TEST RATIO IS LES',
+ $ 'S THAN', F8.2 )
+ 9998 FORMAT( ' RELATIVE MACHINE PRECISION IS TAKEN TO BE', 1P, E9.1 )
+ 9997 FORMAT( ' NUMBER OF VALUES OF ', A, ' IS LESS THAN 1 OR GREATER ',
+ $ 'THAN ', I2 )
+ 9996 FORMAT( ' VALUE OF N IS LESS THAN 0 OR GREATER THAN ', I2 )
+ 9995 FORMAT( ' TESTS OF THE COMPLEX LEVEL 3 BLAS', //' THE F',
+ $ 'OLLOWING PARAMETER VALUES WILL BE USED:' )
+ 9994 FORMAT( ' FOR N ', 9I6 )
+ 9993 FORMAT( ' FOR ALPHA ',
+ $ 7( '(', F4.1, ',', F4.1, ') ', : ) )
+ 9992 FORMAT( ' FOR BETA ',
+ $ 7( '(', F4.1, ',', F4.1, ') ', : ) )
+ 9991 FORMAT( ' AMEND DATA FILE OR INCREASE ARRAY SIZES IN PROGRAM',
+ $ /' ******* TESTS ABANDONED *******' )
+ 9990 FORMAT( ' SUBPROGRAM NAME ', A6, ' NOT RECOGNIZED', /' ******* T',
+ $ 'ESTS ABANDONED *******' )
+ 9989 FORMAT( ' ERROR IN CMMCH - IN-LINE DOT PRODUCTS ARE BEING EVALU',
+ $ 'ATED WRONGLY.', /' CMMCH WAS CALLED WITH TRANSA = ', A1,
+ $ ' AND TRANSB = ', A1, /' AND RETURNED SAME = ', L1, ' AND ',
+ $ 'ERR = ', F12.3, '.', /' THIS MAY BE DUE TO FAULTS IN THE ',
+ $ 'ARITHMETIC OR THE COMPILER.', /' ******* TESTS ABANDONED ',
+ $ '*******' )
+ 9988 FORMAT( A6, L2 )
+ 9987 FORMAT( 1X, A6, ' WAS NOT TESTED' )
+ 9986 FORMAT( /' END OF TESTS' )
+ 9985 FORMAT( /' ******* FATAL ERROR - TESTS ABANDONED *******' )
+ 9984 FORMAT( ' ERROR-EXITS WILL NOT BE TESTED' )
+*
+* End of CBLAT3.
+*
+ END
+ SUBROUTINE CCHK1( SNAME, EPS, THRESH, NOUT, NTRA, TRACE, REWI,
+ $ FATAL, NIDIM, IDIM, NALF, ALF, NBET, BET, NMAX,
+ $ A, AA, AS, B, BB, BS, C, CC, CS, CT, G )
+*
+* Tests CGEMM.
+*
+* Auxiliary routine for test program for Level 3 Blas.
+*
+* -- Written on 8-February-1989.
+* Jack Dongarra, Argonne National Laboratory.
+* Iain Duff, AERE Harwell.
+* Jeremy Du Croz, Numerical Algorithms Group Ltd.
+* Sven Hammarling, Numerical Algorithms Group Ltd.
+*
+* .. Parameters ..
+ COMPLEX ZERO
+ PARAMETER ( ZERO = ( 0.0, 0.0 ) )
+ REAL RZERO
+ PARAMETER ( RZERO = 0.0 )
+* .. Scalar Arguments ..
+ REAL EPS, THRESH
+ INTEGER NALF, NBET, NIDIM, NMAX, NOUT, NTRA
+ LOGICAL FATAL, REWI, TRACE
+ CHARACTER*6 SNAME
+* .. Array Arguments ..
+ COMPLEX A( NMAX, NMAX ), AA( NMAX*NMAX ), ALF( NALF ),
+ $ AS( NMAX*NMAX ), B( NMAX, NMAX ),
+ $ BB( NMAX*NMAX ), BET( NBET ), BS( NMAX*NMAX ),
+ $ C( NMAX, NMAX ), CC( NMAX*NMAX ),
+ $ CS( NMAX*NMAX ), CT( NMAX )
+ REAL G( NMAX )
+ INTEGER IDIM( NIDIM )
+* .. Local Scalars ..
+ COMPLEX ALPHA, ALS, BETA, BLS
+ REAL ERR, ERRMAX
+ INTEGER I, IA, IB, ICA, ICB, IK, IM, IN, K, KS, LAA,
+ $ LBB, LCC, LDA, LDAS, LDB, LDBS, LDC, LDCS, M,
+ $ MA, MB, MS, N, NA, NARGS, NB, NC, NS
+ LOGICAL NULL, RESET, SAME, TRANA, TRANB
+ CHARACTER*1 TRANAS, TRANBS, TRANSA, TRANSB
+ CHARACTER*3 ICH
+* .. Local Arrays ..
+ LOGICAL ISAME( 13 )
+* .. External Functions ..
+ LOGICAL LCE, LCERES
+ EXTERNAL LCE, LCERES
+* .. External Subroutines ..
+ EXTERNAL CGEMM, CMAKE, CMMCH
+* .. Intrinsic Functions ..
+ INTRINSIC MAX
+* .. Scalars in Common ..
+ INTEGER INFOT, NOUTC
+ LOGICAL LERR, OK
+* .. Common blocks ..
+ COMMON /INFOC/INFOT, NOUTC, OK, LERR
+* .. Data statements ..
+ DATA ICH/'NTC'/
+* .. Executable Statements ..
+*
+ NARGS = 13
+ NC = 0
+ RESET = .TRUE.
+ ERRMAX = RZERO
+*
+ DO 110 IM = 1, NIDIM
+ M = IDIM( IM )
+*
+ DO 100 IN = 1, NIDIM
+ N = IDIM( IN )
+* Set LDC to 1 more than minimum value if room.
+ LDC = M
+ IF( LDC.LT.NMAX )
+ $ LDC = LDC + 1
+* Skip tests if not enough room.
+ IF( LDC.GT.NMAX )
+ $ GO TO 100
+ LCC = LDC*N
+ NULL = N.LE.0.OR.M.LE.0
+*
+ DO 90 IK = 1, NIDIM
+ K = IDIM( IK )
+*
+ DO 80 ICA = 1, 3
+ TRANSA = ICH( ICA: ICA )
+ TRANA = TRANSA.EQ.'T'.OR.TRANSA.EQ.'C'
+*
+ IF( TRANA )THEN
+ MA = K
+ NA = M
+ ELSE
+ MA = M
+ NA = K
+ END IF
+* Set LDA to 1 more than minimum value if room.
+ LDA = MA
+ IF( LDA.LT.NMAX )
+ $ LDA = LDA + 1
+* Skip tests if not enough room.
+ IF( LDA.GT.NMAX )
+ $ GO TO 80
+ LAA = LDA*NA
+*
+* Generate the matrix A.
+*
+ CALL CMAKE( 'GE', ' ', ' ', MA, NA, A, NMAX, AA, LDA,
+ $ RESET, ZERO )
+*
+ DO 70 ICB = 1, 3
+ TRANSB = ICH( ICB: ICB )
+ TRANB = TRANSB.EQ.'T'.OR.TRANSB.EQ.'C'
+*
+ IF( TRANB )THEN
+ MB = N
+ NB = K
+ ELSE
+ MB = K
+ NB = N
+ END IF
+* Set LDB to 1 more than minimum value if room.
+ LDB = MB
+ IF( LDB.LT.NMAX )
+ $ LDB = LDB + 1
+* Skip tests if not enough room.
+ IF( LDB.GT.NMAX )
+ $ GO TO 70
+ LBB = LDB*NB
+*
+* Generate the matrix B.
+*
+ CALL CMAKE( 'GE', ' ', ' ', MB, NB, B, NMAX, BB,
+ $ LDB, RESET, ZERO )
+*
+ DO 60 IA = 1, NALF
+ ALPHA = ALF( IA )
+*
+ DO 50 IB = 1, NBET
+ BETA = BET( IB )
+*
+* Generate the matrix C.
+*
+ CALL CMAKE( 'GE', ' ', ' ', M, N, C, NMAX,
+ $ CC, LDC, RESET, ZERO )
+*
+ NC = NC + 1
+*
+* Save every datum before calling the
+* subroutine.
+*
+ TRANAS = TRANSA
+ TRANBS = TRANSB
+ MS = M
+ NS = N
+ KS = K
+ ALS = ALPHA
+ DO 10 I = 1, LAA
+ AS( I ) = AA( I )
+ 10 CONTINUE
+ LDAS = LDA
+ DO 20 I = 1, LBB
+ BS( I ) = BB( I )
+ 20 CONTINUE
+ LDBS = LDB
+ BLS = BETA
+ DO 30 I = 1, LCC
+ CS( I ) = CC( I )
+ 30 CONTINUE
+ LDCS = LDC
+*
+* Call the subroutine.
+*
+ IF( TRACE )
+ $ WRITE( NTRA, FMT = 9995 )NC, SNAME,
+ $ TRANSA, TRANSB, M, N, K, ALPHA, LDA, LDB,
+ $ BETA, LDC
+ IF( REWI )
+ $ REWIND NTRA
+ CALL CGEMM( TRANSA, TRANSB, M, N, K, ALPHA,
+ $ AA, LDA, BB, LDB, BETA, CC, LDC )
+*
+* Check if error-exit was taken incorrectly.
+*
+ IF( .NOT.OK )THEN
+ WRITE( NOUT, FMT = 9994 )
+ FATAL = .TRUE.
+ GO TO 120
+ END IF
+*
+* See what data changed inside subroutines.
+*
+ ISAME( 1 ) = TRANSA.EQ.TRANAS
+ ISAME( 2 ) = TRANSB.EQ.TRANBS
+ ISAME( 3 ) = MS.EQ.M
+ ISAME( 4 ) = NS.EQ.N
+ ISAME( 5 ) = KS.EQ.K
+ ISAME( 6 ) = ALS.EQ.ALPHA
+ ISAME( 7 ) = LCE( AS, AA, LAA )
+ ISAME( 8 ) = LDAS.EQ.LDA
+ ISAME( 9 ) = LCE( BS, BB, LBB )
+ ISAME( 10 ) = LDBS.EQ.LDB
+ ISAME( 11 ) = BLS.EQ.BETA
+ IF( NULL )THEN
+ ISAME( 12 ) = LCE( CS, CC, LCC )
+ ELSE
+ ISAME( 12 ) = LCERES( 'GE', ' ', M, N, CS,
+ $ CC, LDC )
+ END IF
+ ISAME( 13 ) = LDCS.EQ.LDC
+*
+* If data was incorrectly changed, report
+* and return.
+*
+ SAME = .TRUE.
+ DO 40 I = 1, NARGS
+ SAME = SAME.AND.ISAME( I )
+ IF( .NOT.ISAME( I ) )
+ $ WRITE( NOUT, FMT = 9998 )I
+ 40 CONTINUE
+ IF( .NOT.SAME )THEN
+ FATAL = .TRUE.
+ GO TO 120
+ END IF
+*
+ IF( .NOT.NULL )THEN
+*
+* Check the result.
+*
+ CALL CMMCH( TRANSA, TRANSB, M, N, K,
+ $ ALPHA, A, NMAX, B, NMAX, BETA,
+ $ C, NMAX, CT, G, CC, LDC, EPS,
+ $ ERR, FATAL, NOUT, .TRUE. )
+ ERRMAX = MAX( ERRMAX, ERR )
+* If got really bad answer, report and
+* return.
+ IF( FATAL )
+ $ GO TO 120
+ END IF
+*
+ 50 CONTINUE
+*
+ 60 CONTINUE
+*
+ 70 CONTINUE
+*
+ 80 CONTINUE
+*
+ 90 CONTINUE
+*
+ 100 CONTINUE
+*
+ 110 CONTINUE
+*
+* Report result.
+*
+ IF( ERRMAX.LT.THRESH )THEN
+ WRITE( NOUT, FMT = 9999 )SNAME, NC
+ ELSE
+ WRITE( NOUT, FMT = 9997 )SNAME, NC, ERRMAX
+ END IF
+ GO TO 130
+*
+ 120 CONTINUE
+ WRITE( NOUT, FMT = 9996 )SNAME
+ WRITE( NOUT, FMT = 9995 )NC, SNAME, TRANSA, TRANSB, M, N, K,
+ $ ALPHA, LDA, LDB, BETA, LDC
+*
+ 130 CONTINUE
+ RETURN
+*
+ 9999 FORMAT( ' ', A6, ' PASSED THE COMPUTATIONAL TESTS (', I6, ' CALL',
+ $ 'S)' )
+ 9998 FORMAT( ' ******* FATAL ERROR - PARAMETER NUMBER ', I2, ' WAS CH',
+ $ 'ANGED INCORRECTLY *******' )
+ 9997 FORMAT( ' ', A6, ' COMPLETED THE COMPUTATIONAL TESTS (', I6, ' C',
+ $ 'ALLS)', /' ******* BUT WITH MAXIMUM TEST RATIO', F8.2,
+ $ ' - SUSPECT *******' )
+ 9996 FORMAT( ' ******* ', A6, ' FAILED ON CALL NUMBER:' )
+ 9995 FORMAT( 1X, I6, ': ', A6, '(''', A1, ''',''', A1, ''',',
+ $ 3( I3, ',' ), '(', F4.1, ',', F4.1, '), A,', I3, ', B,', I3,
+ $ ',(', F4.1, ',', F4.1, '), C,', I3, ').' )
+ 9994 FORMAT( ' ******* FATAL ERROR - ERROR-EXIT TAKEN ON VALID CALL *',
+ $ '******' )
+*
+* End of CCHK1.
+*
+ END
+ SUBROUTINE CCHK2( SNAME, EPS, THRESH, NOUT, NTRA, TRACE, REWI,
+ $ FATAL, NIDIM, IDIM, NALF, ALF, NBET, BET, NMAX,
+ $ A, AA, AS, B, BB, BS, C, CC, CS, CT, G )
+*
+* Tests CHEMM and CSYMM.
+*
+* Auxiliary routine for test program for Level 3 Blas.
+*
+* -- Written on 8-February-1989.
+* Jack Dongarra, Argonne National Laboratory.
+* Iain Duff, AERE Harwell.
+* Jeremy Du Croz, Numerical Algorithms Group Ltd.
+* Sven Hammarling, Numerical Algorithms Group Ltd.
+*
+* .. Parameters ..
+ COMPLEX ZERO
+ PARAMETER ( ZERO = ( 0.0, 0.0 ) )
+ REAL RZERO
+ PARAMETER ( RZERO = 0.0 )
+* .. Scalar Arguments ..
+ REAL EPS, THRESH
+ INTEGER NALF, NBET, NIDIM, NMAX, NOUT, NTRA
+ LOGICAL FATAL, REWI, TRACE
+ CHARACTER*6 SNAME
+* .. Array Arguments ..
+ COMPLEX A( NMAX, NMAX ), AA( NMAX*NMAX ), ALF( NALF ),
+ $ AS( NMAX*NMAX ), B( NMAX, NMAX ),
+ $ BB( NMAX*NMAX ), BET( NBET ), BS( NMAX*NMAX ),
+ $ C( NMAX, NMAX ), CC( NMAX*NMAX ),
+ $ CS( NMAX*NMAX ), CT( NMAX )
+ REAL G( NMAX )
+ INTEGER IDIM( NIDIM )
+* .. Local Scalars ..
+ COMPLEX ALPHA, ALS, BETA, BLS
+ REAL ERR, ERRMAX
+ INTEGER I, IA, IB, ICS, ICU, IM, IN, LAA, LBB, LCC,
+ $ LDA, LDAS, LDB, LDBS, LDC, LDCS, M, MS, N, NA,
+ $ NARGS, NC, NS
+ LOGICAL CONJ, LEFT, NULL, RESET, SAME
+ CHARACTER*1 SIDE, SIDES, UPLO, UPLOS
+ CHARACTER*2 ICHS, ICHU
+* .. Local Arrays ..
+ LOGICAL ISAME( 13 )
+* .. External Functions ..
+ LOGICAL LCE, LCERES
+ EXTERNAL LCE, LCERES
+* .. External Subroutines ..
+ EXTERNAL CHEMM, CMAKE, CMMCH, CSYMM
+* .. Intrinsic Functions ..
+ INTRINSIC MAX
+* .. Scalars in Common ..
+ INTEGER INFOT, NOUTC
+ LOGICAL LERR, OK
+* .. Common blocks ..
+ COMMON /INFOC/INFOT, NOUTC, OK, LERR
+* .. Data statements ..
+ DATA ICHS/'LR'/, ICHU/'UL'/
+* .. Executable Statements ..
+ CONJ = SNAME( 2: 3 ).EQ.'HE'
+*
+ NARGS = 12
+ NC = 0
+ RESET = .TRUE.
+ ERRMAX = RZERO
+*
+ DO 100 IM = 1, NIDIM
+ M = IDIM( IM )
+*
+ DO 90 IN = 1, NIDIM
+ N = IDIM( IN )
+* Set LDC to 1 more than minimum value if room.
+ LDC = M
+ IF( LDC.LT.NMAX )
+ $ LDC = LDC + 1
+* Skip tests if not enough room.
+ IF( LDC.GT.NMAX )
+ $ GO TO 90
+ LCC = LDC*N
+ NULL = N.LE.0.OR.M.LE.0
+* Set LDB to 1 more than minimum value if room.
+ LDB = M
+ IF( LDB.LT.NMAX )
+ $ LDB = LDB + 1
+* Skip tests if not enough room.
+ IF( LDB.GT.NMAX )
+ $ GO TO 90
+ LBB = LDB*N
+*
+* Generate the matrix B.
+*
+ CALL CMAKE( 'GE', ' ', ' ', M, N, B, NMAX, BB, LDB, RESET,
+ $ ZERO )
+*
+ DO 80 ICS = 1, 2
+ SIDE = ICHS( ICS: ICS )
+ LEFT = SIDE.EQ.'L'
+*
+ IF( LEFT )THEN
+ NA = M
+ ELSE
+ NA = N
+ END IF
+* Set LDA to 1 more than minimum value if room.
+ LDA = NA
+ IF( LDA.LT.NMAX )
+ $ LDA = LDA + 1
+* Skip tests if not enough room.
+ IF( LDA.GT.NMAX )
+ $ GO TO 80
+ LAA = LDA*NA
+*
+ DO 70 ICU = 1, 2
+ UPLO = ICHU( ICU: ICU )
+*
+* Generate the hermitian or symmetric matrix A.
+*
+ CALL CMAKE( SNAME( 2: 3 ), UPLO, ' ', NA, NA, A, NMAX,
+ $ AA, LDA, RESET, ZERO )
+*
+ DO 60 IA = 1, NALF
+ ALPHA = ALF( IA )
+*
+ DO 50 IB = 1, NBET
+ BETA = BET( IB )
+*
+* Generate the matrix C.
+*
+ CALL CMAKE( 'GE', ' ', ' ', M, N, C, NMAX, CC,
+ $ LDC, RESET, ZERO )
+*
+ NC = NC + 1
+*
+* Save every datum before calling the
+* subroutine.
+*
+ SIDES = SIDE
+ UPLOS = UPLO
+ MS = M
+ NS = N
+ ALS = ALPHA
+ DO 10 I = 1, LAA
+ AS( I ) = AA( I )
+ 10 CONTINUE
+ LDAS = LDA
+ DO 20 I = 1, LBB
+ BS( I ) = BB( I )
+ 20 CONTINUE
+ LDBS = LDB
+ BLS = BETA
+ DO 30 I = 1, LCC
+ CS( I ) = CC( I )
+ 30 CONTINUE
+ LDCS = LDC
+*
+* Call the subroutine.
+*
+ IF( TRACE )
+ $ WRITE( NTRA, FMT = 9995 )NC, SNAME, SIDE,
+ $ UPLO, M, N, ALPHA, LDA, LDB, BETA, LDC
+ IF( REWI )
+ $ REWIND NTRA
+ IF( CONJ )THEN
+ CALL CHEMM( SIDE, UPLO, M, N, ALPHA, AA, LDA,
+ $ BB, LDB, BETA, CC, LDC )
+ ELSE
+ CALL CSYMM( SIDE, UPLO, M, N, ALPHA, AA, LDA,
+ $ BB, LDB, BETA, CC, LDC )
+ END IF
+*
+* Check if error-exit was taken incorrectly.
+*
+ IF( .NOT.OK )THEN
+ WRITE( NOUT, FMT = 9994 )
+ FATAL = .TRUE.
+ GO TO 110
+ END IF
+*
+* See what data changed inside subroutines.
+*
+ ISAME( 1 ) = SIDES.EQ.SIDE
+ ISAME( 2 ) = UPLOS.EQ.UPLO
+ ISAME( 3 ) = MS.EQ.M
+ ISAME( 4 ) = NS.EQ.N
+ ISAME( 5 ) = ALS.EQ.ALPHA
+ ISAME( 6 ) = LCE( AS, AA, LAA )
+ ISAME( 7 ) = LDAS.EQ.LDA
+ ISAME( 8 ) = LCE( BS, BB, LBB )
+ ISAME( 9 ) = LDBS.EQ.LDB
+ ISAME( 10 ) = BLS.EQ.BETA
+ IF( NULL )THEN
+ ISAME( 11 ) = LCE( CS, CC, LCC )
+ ELSE
+ ISAME( 11 ) = LCERES( 'GE', ' ', M, N, CS,
+ $ CC, LDC )
+ END IF
+ ISAME( 12 ) = LDCS.EQ.LDC
+*
+* If data was incorrectly changed, report and
+* return.
+*
+ SAME = .TRUE.
+ DO 40 I = 1, NARGS
+ SAME = SAME.AND.ISAME( I )
+ IF( .NOT.ISAME( I ) )
+ $ WRITE( NOUT, FMT = 9998 )I
+ 40 CONTINUE
+ IF( .NOT.SAME )THEN
+ FATAL = .TRUE.
+ GO TO 110
+ END IF
+*
+ IF( .NOT.NULL )THEN
+*
+* Check the result.
+*
+ IF( LEFT )THEN
+ CALL CMMCH( 'N', 'N', M, N, M, ALPHA, A,
+ $ NMAX, B, NMAX, BETA, C, NMAX,
+ $ CT, G, CC, LDC, EPS, ERR,
+ $ FATAL, NOUT, .TRUE. )
+ ELSE
+ CALL CMMCH( 'N', 'N', M, N, N, ALPHA, B,
+ $ NMAX, A, NMAX, BETA, C, NMAX,
+ $ CT, G, CC, LDC, EPS, ERR,
+ $ FATAL, NOUT, .TRUE. )
+ END IF
+ ERRMAX = MAX( ERRMAX, ERR )
+* If got really bad answer, report and
+* return.
+ IF( FATAL )
+ $ GO TO 110
+ END IF
+*
+ 50 CONTINUE
+*
+ 60 CONTINUE
+*
+ 70 CONTINUE
+*
+ 80 CONTINUE
+*
+ 90 CONTINUE
+*
+ 100 CONTINUE
+*
+* Report result.
+*
+ IF( ERRMAX.LT.THRESH )THEN
+ WRITE( NOUT, FMT = 9999 )SNAME, NC
+ ELSE
+ WRITE( NOUT, FMT = 9997 )SNAME, NC, ERRMAX
+ END IF
+ GO TO 120
+*
+ 110 CONTINUE
+ WRITE( NOUT, FMT = 9996 )SNAME
+ WRITE( NOUT, FMT = 9995 )NC, SNAME, SIDE, UPLO, M, N, ALPHA, LDA,
+ $ LDB, BETA, LDC
+*
+ 120 CONTINUE
+ RETURN
+*
+ 9999 FORMAT( ' ', A6, ' PASSED THE COMPUTATIONAL TESTS (', I6, ' CALL',
+ $ 'S)' )
+ 9998 FORMAT( ' ******* FATAL ERROR - PARAMETER NUMBER ', I2, ' WAS CH',
+ $ 'ANGED INCORRECTLY *******' )
+ 9997 FORMAT( ' ', A6, ' COMPLETED THE COMPUTATIONAL TESTS (', I6, ' C',
+ $ 'ALLS)', /' ******* BUT WITH MAXIMUM TEST RATIO', F8.2,
+ $ ' - SUSPECT *******' )
+ 9996 FORMAT( ' ******* ', A6, ' FAILED ON CALL NUMBER:' )
+ 9995 FORMAT( 1X, I6, ': ', A6, '(', 2( '''', A1, ''',' ), 2( I3, ',' ),
+ $ '(', F4.1, ',', F4.1, '), A,', I3, ', B,', I3, ',(', F4.1,
+ $ ',', F4.1, '), C,', I3, ') .' )
+ 9994 FORMAT( ' ******* FATAL ERROR - ERROR-EXIT TAKEN ON VALID CALL *',
+ $ '******' )
+*
+* End of CCHK2.
+*
+ END
+ SUBROUTINE CCHK3( SNAME, EPS, THRESH, NOUT, NTRA, TRACE, REWI,
+ $ FATAL, NIDIM, IDIM, NALF, ALF, NMAX, A, AA, AS,
+ $ B, BB, BS, CT, G, C )
+*
+* Tests CTRMM and CTRSM.
+*
+* Auxiliary routine for test program for Level 3 Blas.
+*
+* -- Written on 8-February-1989.
+* Jack Dongarra, Argonne National Laboratory.
+* Iain Duff, AERE Harwell.
+* Jeremy Du Croz, Numerical Algorithms Group Ltd.
+* Sven Hammarling, Numerical Algorithms Group Ltd.
+*
+* .. Parameters ..
+ COMPLEX ZERO, ONE
+ PARAMETER ( ZERO = ( 0.0, 0.0 ), ONE = ( 1.0, 0.0 ) )
+ REAL RZERO
+ PARAMETER ( RZERO = 0.0 )
+* .. Scalar Arguments ..
+ REAL EPS, THRESH
+ INTEGER NALF, NIDIM, NMAX, NOUT, NTRA
+ LOGICAL FATAL, REWI, TRACE
+ CHARACTER*6 SNAME
+* .. Array Arguments ..
+ COMPLEX A( NMAX, NMAX ), AA( NMAX*NMAX ), ALF( NALF ),
+ $ AS( NMAX*NMAX ), B( NMAX, NMAX ),
+ $ BB( NMAX*NMAX ), BS( NMAX*NMAX ),
+ $ C( NMAX, NMAX ), CT( NMAX )
+ REAL G( NMAX )
+ INTEGER IDIM( NIDIM )
+* .. Local Scalars ..
+ COMPLEX ALPHA, ALS
+ REAL ERR, ERRMAX
+ INTEGER I, IA, ICD, ICS, ICT, ICU, IM, IN, J, LAA, LBB,
+ $ LDA, LDAS, LDB, LDBS, M, MS, N, NA, NARGS, NC,
+ $ NS
+ LOGICAL LEFT, NULL, RESET, SAME
+ CHARACTER*1 DIAG, DIAGS, SIDE, SIDES, TRANAS, TRANSA, UPLO,
+ $ UPLOS
+ CHARACTER*2 ICHD, ICHS, ICHU
+ CHARACTER*3 ICHT
+* .. Local Arrays ..
+ LOGICAL ISAME( 13 )
+* .. External Functions ..
+ LOGICAL LCE, LCERES
+ EXTERNAL LCE, LCERES
+* .. External Subroutines ..
+ EXTERNAL CMAKE, CMMCH, CTRMM, CTRSM
+* .. Intrinsic Functions ..
+ INTRINSIC MAX
+* .. Scalars in Common ..
+ INTEGER INFOT, NOUTC
+ LOGICAL LERR, OK
+* .. Common blocks ..
+ COMMON /INFOC/INFOT, NOUTC, OK, LERR
+* .. Data statements ..
+ DATA ICHU/'UL'/, ICHT/'NTC'/, ICHD/'UN'/, ICHS/'LR'/
+* .. Executable Statements ..
+*
+ NARGS = 11
+ NC = 0
+ RESET = .TRUE.
+ ERRMAX = RZERO
+* Set up zero matrix for CMMCH.
+ DO 20 J = 1, NMAX
+ DO 10 I = 1, NMAX
+ C( I, J ) = ZERO
+ 10 CONTINUE
+ 20 CONTINUE
+*
+ DO 140 IM = 1, NIDIM
+ M = IDIM( IM )
+*
+ DO 130 IN = 1, NIDIM
+ N = IDIM( IN )
+* Set LDB to 1 more than minimum value if room.
+ LDB = M
+ IF( LDB.LT.NMAX )
+ $ LDB = LDB + 1
+* Skip tests if not enough room.
+ IF( LDB.GT.NMAX )
+ $ GO TO 130
+ LBB = LDB*N
+ NULL = M.LE.0.OR.N.LE.0
+*
+ DO 120 ICS = 1, 2
+ SIDE = ICHS( ICS: ICS )
+ LEFT = SIDE.EQ.'L'
+ IF( LEFT )THEN
+ NA = M
+ ELSE
+ NA = N
+ END IF
+* Set LDA to 1 more than minimum value if room.
+ LDA = NA
+ IF( LDA.LT.NMAX )
+ $ LDA = LDA + 1
+* Skip tests if not enough room.
+ IF( LDA.GT.NMAX )
+ $ GO TO 130
+ LAA = LDA*NA
+*
+ DO 110 ICU = 1, 2
+ UPLO = ICHU( ICU: ICU )
+*
+ DO 100 ICT = 1, 3
+ TRANSA = ICHT( ICT: ICT )
+*
+ DO 90 ICD = 1, 2
+ DIAG = ICHD( ICD: ICD )
+*
+ DO 80 IA = 1, NALF
+ ALPHA = ALF( IA )
+*
+* Generate the matrix A.
+*
+ CALL CMAKE( 'TR', UPLO, DIAG, NA, NA, A,
+ $ NMAX, AA, LDA, RESET, ZERO )
+*
+* Generate the matrix B.
+*
+ CALL CMAKE( 'GE', ' ', ' ', M, N, B, NMAX,
+ $ BB, LDB, RESET, ZERO )
+*
+ NC = NC + 1
+*
+* Save every datum before calling the
+* subroutine.
+*
+ SIDES = SIDE
+ UPLOS = UPLO
+ TRANAS = TRANSA
+ DIAGS = DIAG
+ MS = M
+ NS = N
+ ALS = ALPHA
+ DO 30 I = 1, LAA
+ AS( I ) = AA( I )
+ 30 CONTINUE
+ LDAS = LDA
+ DO 40 I = 1, LBB
+ BS( I ) = BB( I )
+ 40 CONTINUE
+ LDBS = LDB
+*
+* Call the subroutine.
+*
+ IF( SNAME( 4: 5 ).EQ.'MM' )THEN
+ IF( TRACE )
+ $ WRITE( NTRA, FMT = 9995 )NC, SNAME,
+ $ SIDE, UPLO, TRANSA, DIAG, M, N, ALPHA,
+ $ LDA, LDB
+ IF( REWI )
+ $ REWIND NTRA
+ CALL CTRMM( SIDE, UPLO, TRANSA, DIAG, M,
+ $ N, ALPHA, AA, LDA, BB, LDB )
+ ELSE IF( SNAME( 4: 5 ).EQ.'SM' )THEN
+ IF( TRACE )
+ $ WRITE( NTRA, FMT = 9995 )NC, SNAME,
+ $ SIDE, UPLO, TRANSA, DIAG, M, N, ALPHA,
+ $ LDA, LDB
+ IF( REWI )
+ $ REWIND NTRA
+ CALL CTRSM( SIDE, UPLO, TRANSA, DIAG, M,
+ $ N, ALPHA, AA, LDA, BB, LDB )
+ END IF
+*
+* Check if error-exit was taken incorrectly.
+*
+ IF( .NOT.OK )THEN
+ WRITE( NOUT, FMT = 9994 )
+ FATAL = .TRUE.
+ GO TO 150
+ END IF
+*
+* See what data changed inside subroutines.
+*
+ ISAME( 1 ) = SIDES.EQ.SIDE
+ ISAME( 2 ) = UPLOS.EQ.UPLO
+ ISAME( 3 ) = TRANAS.EQ.TRANSA
+ ISAME( 4 ) = DIAGS.EQ.DIAG
+ ISAME( 5 ) = MS.EQ.M
+ ISAME( 6 ) = NS.EQ.N
+ ISAME( 7 ) = ALS.EQ.ALPHA
+ ISAME( 8 ) = LCE( AS, AA, LAA )
+ ISAME( 9 ) = LDAS.EQ.LDA
+ IF( NULL )THEN
+ ISAME( 10 ) = LCE( BS, BB, LBB )
+ ELSE
+ ISAME( 10 ) = LCERES( 'GE', ' ', M, N, BS,
+ $ BB, LDB )
+ END IF
+ ISAME( 11 ) = LDBS.EQ.LDB
+*
+* If data was incorrectly changed, report and
+* return.
+*
+ SAME = .TRUE.
+ DO 50 I = 1, NARGS
+ SAME = SAME.AND.ISAME( I )
+ IF( .NOT.ISAME( I ) )
+ $ WRITE( NOUT, FMT = 9998 )I
+ 50 CONTINUE
+ IF( .NOT.SAME )THEN
+ FATAL = .TRUE.
+ GO TO 150
+ END IF
+*
+ IF( .NOT.NULL )THEN
+ IF( SNAME( 4: 5 ).EQ.'MM' )THEN
+*
+* Check the result.
+*
+ IF( LEFT )THEN
+ CALL CMMCH( TRANSA, 'N', M, N, M,
+ $ ALPHA, A, NMAX, B, NMAX,
+ $ ZERO, C, NMAX, CT, G,
+ $ BB, LDB, EPS, ERR,
+ $ FATAL, NOUT, .TRUE. )
+ ELSE
+ CALL CMMCH( 'N', TRANSA, M, N, N,
+ $ ALPHA, B, NMAX, A, NMAX,
+ $ ZERO, C, NMAX, CT, G,
+ $ BB, LDB, EPS, ERR,
+ $ FATAL, NOUT, .TRUE. )
+ END IF
+ ELSE IF( SNAME( 4: 5 ).EQ.'SM' )THEN
+*
+* Compute approximation to original
+* matrix.
+*
+ DO 70 J = 1, N
+ DO 60 I = 1, M
+ C( I, J ) = BB( I + ( J - 1 )*
+ $ LDB )
+ BB( I + ( J - 1 )*LDB ) = ALPHA*
+ $ B( I, J )
+ 60 CONTINUE
+ 70 CONTINUE
+*
+ IF( LEFT )THEN
+ CALL CMMCH( TRANSA, 'N', M, N, M,
+ $ ONE, A, NMAX, C, NMAX,
+ $ ZERO, B, NMAX, CT, G,
+ $ BB, LDB, EPS, ERR,
+ $ FATAL, NOUT, .FALSE. )
+ ELSE
+ CALL CMMCH( 'N', TRANSA, M, N, N,
+ $ ONE, C, NMAX, A, NMAX,
+ $ ZERO, B, NMAX, CT, G,
+ $ BB, LDB, EPS, ERR,
+ $ FATAL, NOUT, .FALSE. )
+ END IF
+ END IF
+ ERRMAX = MAX( ERRMAX, ERR )
+* If got really bad answer, report and
+* return.
+ IF( FATAL )
+ $ GO TO 150
+ END IF
+*
+ 80 CONTINUE
+*
+ 90 CONTINUE
+*
+ 100 CONTINUE
+*
+ 110 CONTINUE
+*
+ 120 CONTINUE
+*
+ 130 CONTINUE
+*
+ 140 CONTINUE
+*
+* Report result.
+*
+ IF( ERRMAX.LT.THRESH )THEN
+ WRITE( NOUT, FMT = 9999 )SNAME, NC
+ ELSE
+ WRITE( NOUT, FMT = 9997 )SNAME, NC, ERRMAX
+ END IF
+ GO TO 160
+*
+ 150 CONTINUE
+ WRITE( NOUT, FMT = 9996 )SNAME
+ WRITE( NOUT, FMT = 9995 )NC, SNAME, SIDE, UPLO, TRANSA, DIAG, M,
+ $ N, ALPHA, LDA, LDB
+*
+ 160 CONTINUE
+ RETURN
+*
+ 9999 FORMAT( ' ', A6, ' PASSED THE COMPUTATIONAL TESTS (', I6, ' CALL',
+ $ 'S)' )
+ 9998 FORMAT( ' ******* FATAL ERROR - PARAMETER NUMBER ', I2, ' WAS CH',
+ $ 'ANGED INCORRECTLY *******' )
+ 9997 FORMAT( ' ', A6, ' COMPLETED THE COMPUTATIONAL TESTS (', I6, ' C',
+ $ 'ALLS)', /' ******* BUT WITH MAXIMUM TEST RATIO', F8.2,
+ $ ' - SUSPECT *******' )
+ 9996 FORMAT( ' ******* ', A6, ' FAILED ON CALL NUMBER:' )
+ 9995 FORMAT( 1X, I6, ': ', A6, '(', 4( '''', A1, ''',' ), 2( I3, ',' ),
+ $ '(', F4.1, ',', F4.1, '), A,', I3, ', B,', I3, ') ',
+ $ ' .' )
+ 9994 FORMAT( ' ******* FATAL ERROR - ERROR-EXIT TAKEN ON VALID CALL *',
+ $ '******' )
+*
+* End of CCHK3.
+*
+ END
+ SUBROUTINE CCHK4( SNAME, EPS, THRESH, NOUT, NTRA, TRACE, REWI,
+ $ FATAL, NIDIM, IDIM, NALF, ALF, NBET, BET, NMAX,
+ $ A, AA, AS, B, BB, BS, C, CC, CS, CT, G )
+*
+* Tests CHERK and CSYRK.
+*
+* Auxiliary routine for test program for Level 3 Blas.
+*
+* -- Written on 8-February-1989.
+* Jack Dongarra, Argonne National Laboratory.
+* Iain Duff, AERE Harwell.
+* Jeremy Du Croz, Numerical Algorithms Group Ltd.
+* Sven Hammarling, Numerical Algorithms Group Ltd.
+*
+* .. Parameters ..
+ COMPLEX ZERO
+ PARAMETER ( ZERO = ( 0.0, 0.0 ) )
+ REAL RONE, RZERO
+ PARAMETER ( RONE = 1.0, RZERO = 0.0 )
+* .. Scalar Arguments ..
+ REAL EPS, THRESH
+ INTEGER NALF, NBET, NIDIM, NMAX, NOUT, NTRA
+ LOGICAL FATAL, REWI, TRACE
+ CHARACTER*6 SNAME
+* .. Array Arguments ..
+ COMPLEX A( NMAX, NMAX ), AA( NMAX*NMAX ), ALF( NALF ),
+ $ AS( NMAX*NMAX ), B( NMAX, NMAX ),
+ $ BB( NMAX*NMAX ), BET( NBET ), BS( NMAX*NMAX ),
+ $ C( NMAX, NMAX ), CC( NMAX*NMAX ),
+ $ CS( NMAX*NMAX ), CT( NMAX )
+ REAL G( NMAX )
+ INTEGER IDIM( NIDIM )
+* .. Local Scalars ..
+ COMPLEX ALPHA, ALS, BETA, BETS
+ REAL ERR, ERRMAX, RALPHA, RALS, RBETA, RBETS
+ INTEGER I, IA, IB, ICT, ICU, IK, IN, J, JC, JJ, K, KS,
+ $ LAA, LCC, LDA, LDAS, LDC, LDCS, LJ, MA, N, NA,
+ $ NARGS, NC, NS
+ LOGICAL CONJ, NULL, RESET, SAME, TRAN, UPPER
+ CHARACTER*1 TRANS, TRANSS, TRANST, UPLO, UPLOS
+ CHARACTER*2 ICHT, ICHU
+* .. Local Arrays ..
+ LOGICAL ISAME( 13 )
+* .. External Functions ..
+ LOGICAL LCE, LCERES
+ EXTERNAL LCE, LCERES
+* .. External Subroutines ..
+ EXTERNAL CHERK, CMAKE, CMMCH, CSYRK
+* .. Intrinsic Functions ..
+ INTRINSIC CMPLX, MAX, REAL
+* .. Scalars in Common ..
+ INTEGER INFOT, NOUTC
+ LOGICAL LERR, OK
+* .. Common blocks ..
+ COMMON /INFOC/INFOT, NOUTC, OK, LERR
+* .. Data statements ..
+ DATA ICHT/'NC'/, ICHU/'UL'/
+* .. Executable Statements ..
+ CONJ = SNAME( 2: 3 ).EQ.'HE'
+*
+ NARGS = 10
+ NC = 0
+ RESET = .TRUE.
+ ERRMAX = RZERO
+*
+ DO 100 IN = 1, NIDIM
+ N = IDIM( IN )
+* Set LDC to 1 more than minimum value if room.
+ LDC = N
+ IF( LDC.LT.NMAX )
+ $ LDC = LDC + 1
+* Skip tests if not enough room.
+ IF( LDC.GT.NMAX )
+ $ GO TO 100
+ LCC = LDC*N
+*
+ DO 90 IK = 1, NIDIM
+ K = IDIM( IK )
+*
+ DO 80 ICT = 1, 2
+ TRANS = ICHT( ICT: ICT )
+ TRAN = TRANS.EQ.'C'
+ IF( TRAN.AND..NOT.CONJ )
+ $ TRANS = 'T'
+ IF( TRAN )THEN
+ MA = K
+ NA = N
+ ELSE
+ MA = N
+ NA = K
+ END IF
+* Set LDA to 1 more than minimum value if room.
+ LDA = MA
+ IF( LDA.LT.NMAX )
+ $ LDA = LDA + 1
+* Skip tests if not enough room.
+ IF( LDA.GT.NMAX )
+ $ GO TO 80
+ LAA = LDA*NA
+*
+* Generate the matrix A.
+*
+ CALL CMAKE( 'GE', ' ', ' ', MA, NA, A, NMAX, AA, LDA,
+ $ RESET, ZERO )
+*
+ DO 70 ICU = 1, 2
+ UPLO = ICHU( ICU: ICU )
+ UPPER = UPLO.EQ.'U'
+*
+ DO 60 IA = 1, NALF
+ ALPHA = ALF( IA )
+ IF( CONJ )THEN
+ RALPHA = REAL( ALPHA )
+ ALPHA = CMPLX( RALPHA, RZERO )
+ END IF
+*
+ DO 50 IB = 1, NBET
+ BETA = BET( IB )
+ IF( CONJ )THEN
+ RBETA = REAL( BETA )
+ BETA = CMPLX( RBETA, RZERO )
+ END IF
+ NULL = N.LE.0
+ IF( CONJ )
+ $ NULL = NULL.OR.( ( K.LE.0.OR.RALPHA.EQ.
+ $ RZERO ).AND.RBETA.EQ.RONE )
+*
+* Generate the matrix C.
+*
+ CALL CMAKE( SNAME( 2: 3 ), UPLO, ' ', N, N, C,
+ $ NMAX, CC, LDC, RESET, ZERO )
+*
+ NC = NC + 1
+*
+* Save every datum before calling the subroutine.
+*
+ UPLOS = UPLO
+ TRANSS = TRANS
+ NS = N
+ KS = K
+ IF( CONJ )THEN
+ RALS = RALPHA
+ ELSE
+ ALS = ALPHA
+ END IF
+ DO 10 I = 1, LAA
+ AS( I ) = AA( I )
+ 10 CONTINUE
+ LDAS = LDA
+ IF( CONJ )THEN
+ RBETS = RBETA
+ ELSE
+ BETS = BETA
+ END IF
+ DO 20 I = 1, LCC
+ CS( I ) = CC( I )
+ 20 CONTINUE
+ LDCS = LDC
+*
+* Call the subroutine.
+*
+ IF( CONJ )THEN
+ IF( TRACE )
+ $ WRITE( NTRA, FMT = 9994 )NC, SNAME, UPLO,
+ $ TRANS, N, K, RALPHA, LDA, RBETA, LDC
+ IF( REWI )
+ $ REWIND NTRA
+ CALL CHERK( UPLO, TRANS, N, K, RALPHA, AA,
+ $ LDA, RBETA, CC, LDC )
+ ELSE
+ IF( TRACE )
+ $ WRITE( NTRA, FMT = 9993 )NC, SNAME, UPLO,
+ $ TRANS, N, K, ALPHA, LDA, BETA, LDC
+ IF( REWI )
+ $ REWIND NTRA
+ CALL CSYRK( UPLO, TRANS, N, K, ALPHA, AA,
+ $ LDA, BETA, CC, LDC )
+ END IF
+*
+* Check if error-exit was taken incorrectly.
+*
+ IF( .NOT.OK )THEN
+ WRITE( NOUT, FMT = 9992 )
+ FATAL = .TRUE.
+ GO TO 120
+ END IF
+*
+* See what data changed inside subroutines.
+*
+ ISAME( 1 ) = UPLOS.EQ.UPLO
+ ISAME( 2 ) = TRANSS.EQ.TRANS
+ ISAME( 3 ) = NS.EQ.N
+ ISAME( 4 ) = KS.EQ.K
+ IF( CONJ )THEN
+ ISAME( 5 ) = RALS.EQ.RALPHA
+ ELSE
+ ISAME( 5 ) = ALS.EQ.ALPHA
+ END IF
+ ISAME( 6 ) = LCE( AS, AA, LAA )
+ ISAME( 7 ) = LDAS.EQ.LDA
+ IF( CONJ )THEN
+ ISAME( 8 ) = RBETS.EQ.RBETA
+ ELSE
+ ISAME( 8 ) = BETS.EQ.BETA
+ END IF
+ IF( NULL )THEN
+ ISAME( 9 ) = LCE( CS, CC, LCC )
+ ELSE
+ ISAME( 9 ) = LCERES( SNAME( 2: 3 ), UPLO, N,
+ $ N, CS, CC, LDC )
+ END IF
+ ISAME( 10 ) = LDCS.EQ.LDC
+*
+* If data was incorrectly changed, report and
+* return.
+*
+ SAME = .TRUE.
+ DO 30 I = 1, NARGS
+ SAME = SAME.AND.ISAME( I )
+ IF( .NOT.ISAME( I ) )
+ $ WRITE( NOUT, FMT = 9998 )I
+ 30 CONTINUE
+ IF( .NOT.SAME )THEN
+ FATAL = .TRUE.
+ GO TO 120
+ END IF
+*
+ IF( .NOT.NULL )THEN
+*
+* Check the result column by column.
+*
+ IF( CONJ )THEN
+ TRANST = 'C'
+ ELSE
+ TRANST = 'T'
+ END IF
+ JC = 1
+ DO 40 J = 1, N
+ IF( UPPER )THEN
+ JJ = 1
+ LJ = J
+ ELSE
+ JJ = J
+ LJ = N - J + 1
+ END IF
+ IF( TRAN )THEN
+ CALL CMMCH( TRANST, 'N', LJ, 1, K,
+ $ ALPHA, A( 1, JJ ), NMAX,
+ $ A( 1, J ), NMAX, BETA,
+ $ C( JJ, J ), NMAX, CT, G,
+ $ CC( JC ), LDC, EPS, ERR,
+ $ FATAL, NOUT, .TRUE. )
+ ELSE
+ CALL CMMCH( 'N', TRANST, LJ, 1, K,
+ $ ALPHA, A( JJ, 1 ), NMAX,
+ $ A( J, 1 ), NMAX, BETA,
+ $ C( JJ, J ), NMAX, CT, G,
+ $ CC( JC ), LDC, EPS, ERR,
+ $ FATAL, NOUT, .TRUE. )
+ END IF
+ IF( UPPER )THEN
+ JC = JC + LDC
+ ELSE
+ JC = JC + LDC + 1
+ END IF
+ ERRMAX = MAX( ERRMAX, ERR )
+* If got really bad answer, report and
+* return.
+ IF( FATAL )
+ $ GO TO 110
+ 40 CONTINUE
+ END IF
+*
+ 50 CONTINUE
+*
+ 60 CONTINUE
+*
+ 70 CONTINUE
+*
+ 80 CONTINUE
+*
+ 90 CONTINUE
+*
+ 100 CONTINUE
+*
+* Report result.
+*
+ IF( ERRMAX.LT.THRESH )THEN
+ WRITE( NOUT, FMT = 9999 )SNAME, NC
+ ELSE
+ WRITE( NOUT, FMT = 9997 )SNAME, NC, ERRMAX
+ END IF
+ GO TO 130
+*
+ 110 CONTINUE
+ IF( N.GT.1 )
+ $ WRITE( NOUT, FMT = 9995 )J
+*
+ 120 CONTINUE
+ WRITE( NOUT, FMT = 9996 )SNAME
+ IF( CONJ )THEN
+ WRITE( NOUT, FMT = 9994 )NC, SNAME, UPLO, TRANS, N, K, RALPHA,
+ $ LDA, RBETA, LDC
+ ELSE
+ WRITE( NOUT, FMT = 9993 )NC, SNAME, UPLO, TRANS, N, K, ALPHA,
+ $ LDA, BETA, LDC
+ END IF
+*
+ 130 CONTINUE
+ RETURN
+*
+ 9999 FORMAT( ' ', A6, ' PASSED THE COMPUTATIONAL TESTS (', I6, ' CALL',
+ $ 'S)' )
+ 9998 FORMAT( ' ******* FATAL ERROR - PARAMETER NUMBER ', I2, ' WAS CH',
+ $ 'ANGED INCORRECTLY *******' )
+ 9997 FORMAT( ' ', A6, ' COMPLETED THE COMPUTATIONAL TESTS (', I6, ' C',
+ $ 'ALLS)', /' ******* BUT WITH MAXIMUM TEST RATIO', F8.2,
+ $ ' - SUSPECT *******' )
+ 9996 FORMAT( ' ******* ', A6, ' FAILED ON CALL NUMBER:' )
+ 9995 FORMAT( ' THESE ARE THE RESULTS FOR COLUMN ', I3 )
+ 9994 FORMAT( 1X, I6, ': ', A6, '(', 2( '''', A1, ''',' ), 2( I3, ',' ),
+ $ F4.1, ', A,', I3, ',', F4.1, ', C,', I3, ') ',
+ $ ' .' )
+ 9993 FORMAT( 1X, I6, ': ', A6, '(', 2( '''', A1, ''',' ), 2( I3, ',' ),
+ $ '(', F4.1, ',', F4.1, ') , A,', I3, ',(', F4.1, ',', F4.1,
+ $ '), C,', I3, ') .' )
+ 9992 FORMAT( ' ******* FATAL ERROR - ERROR-EXIT TAKEN ON VALID CALL *',
+ $ '******' )
+*
+* End of CCHK4.
+*
+ END
+ SUBROUTINE CCHK5( SNAME, EPS, THRESH, NOUT, NTRA, TRACE, REWI,
+ $ FATAL, NIDIM, IDIM, NALF, ALF, NBET, BET, NMAX,
+ $ AB, AA, AS, BB, BS, C, CC, CS, CT, G, W )
+*
+* Tests CHER2K and CSYR2K.
+*
+* Auxiliary routine for test program for Level 3 Blas.
+*
+* -- Written on 8-February-1989.
+* Jack Dongarra, Argonne National Laboratory.
+* Iain Duff, AERE Harwell.
+* Jeremy Du Croz, Numerical Algorithms Group Ltd.
+* Sven Hammarling, Numerical Algorithms Group Ltd.
+*
+* .. Parameters ..
+ COMPLEX ZERO, ONE
+ PARAMETER ( ZERO = ( 0.0, 0.0 ), ONE = ( 1.0, 0.0 ) )
+ REAL RONE, RZERO
+ PARAMETER ( RONE = 1.0, RZERO = 0.0 )
+* .. Scalar Arguments ..
+ REAL EPS, THRESH
+ INTEGER NALF, NBET, NIDIM, NMAX, NOUT, NTRA
+ LOGICAL FATAL, REWI, TRACE
+ CHARACTER*6 SNAME
+* .. Array Arguments ..
+ COMPLEX AA( NMAX*NMAX ), AB( 2*NMAX*NMAX ),
+ $ ALF( NALF ), AS( NMAX*NMAX ), BB( NMAX*NMAX ),
+ $ BET( NBET ), BS( NMAX*NMAX ), C( NMAX, NMAX ),
+ $ CC( NMAX*NMAX ), CS( NMAX*NMAX ), CT( NMAX ),
+ $ W( 2*NMAX )
+ REAL G( NMAX )
+ INTEGER IDIM( NIDIM )
+* .. Local Scalars ..
+ COMPLEX ALPHA, ALS, BETA, BETS
+ REAL ERR, ERRMAX, RBETA, RBETS
+ INTEGER I, IA, IB, ICT, ICU, IK, IN, J, JC, JJ, JJAB,
+ $ K, KS, LAA, LBB, LCC, LDA, LDAS, LDB, LDBS,
+ $ LDC, LDCS, LJ, MA, N, NA, NARGS, NC, NS
+ LOGICAL CONJ, NULL, RESET, SAME, TRAN, UPPER
+ CHARACTER*1 TRANS, TRANSS, TRANST, UPLO, UPLOS
+ CHARACTER*2 ICHT, ICHU
+* .. Local Arrays ..
+ LOGICAL ISAME( 13 )
+* .. External Functions ..
+ LOGICAL LCE, LCERES
+ EXTERNAL LCE, LCERES
+* .. External Subroutines ..
+ EXTERNAL CHER2K, CMAKE, CMMCH, CSYR2K
+* .. Intrinsic Functions ..
+ INTRINSIC CMPLX, CONJG, MAX, REAL
+* .. Scalars in Common ..
+ INTEGER INFOT, NOUTC
+ LOGICAL LERR, OK
+* .. Common blocks ..
+ COMMON /INFOC/INFOT, NOUTC, OK, LERR
+* .. Data statements ..
+ DATA ICHT/'NC'/, ICHU/'UL'/
+* .. Executable Statements ..
+ CONJ = SNAME( 2: 3 ).EQ.'HE'
+*
+ NARGS = 12
+ NC = 0
+ RESET = .TRUE.
+ ERRMAX = RZERO
+*
+ DO 130 IN = 1, NIDIM
+ N = IDIM( IN )
+* Set LDC to 1 more than minimum value if room.
+ LDC = N
+ IF( LDC.LT.NMAX )
+ $ LDC = LDC + 1
+* Skip tests if not enough room.
+ IF( LDC.GT.NMAX )
+ $ GO TO 130
+ LCC = LDC*N
+*
+ DO 120 IK = 1, NIDIM
+ K = IDIM( IK )
+*
+ DO 110 ICT = 1, 2
+ TRANS = ICHT( ICT: ICT )
+ TRAN = TRANS.EQ.'C'
+ IF( TRAN.AND..NOT.CONJ )
+ $ TRANS = 'T'
+ IF( TRAN )THEN
+ MA = K
+ NA = N
+ ELSE
+ MA = N
+ NA = K
+ END IF
+* Set LDA to 1 more than minimum value if room.
+ LDA = MA
+ IF( LDA.LT.NMAX )
+ $ LDA = LDA + 1
+* Skip tests if not enough room.
+ IF( LDA.GT.NMAX )
+ $ GO TO 110
+ LAA = LDA*NA
+*
+* Generate the matrix A.
+*
+ IF( TRAN )THEN
+ CALL CMAKE( 'GE', ' ', ' ', MA, NA, AB, 2*NMAX, AA,
+ $ LDA, RESET, ZERO )
+ ELSE
+ CALL CMAKE( 'GE', ' ', ' ', MA, NA, AB, NMAX, AA, LDA,
+ $ RESET, ZERO )
+ END IF
+*
+* Generate the matrix B.
+*
+ LDB = LDA
+ LBB = LAA
+ IF( TRAN )THEN
+ CALL CMAKE( 'GE', ' ', ' ', MA, NA, AB( K + 1 ),
+ $ 2*NMAX, BB, LDB, RESET, ZERO )
+ ELSE
+ CALL CMAKE( 'GE', ' ', ' ', MA, NA, AB( K*NMAX + 1 ),
+ $ NMAX, BB, LDB, RESET, ZERO )
+ END IF
+*
+ DO 100 ICU = 1, 2
+ UPLO = ICHU( ICU: ICU )
+ UPPER = UPLO.EQ.'U'
+*
+ DO 90 IA = 1, NALF
+ ALPHA = ALF( IA )
+*
+ DO 80 IB = 1, NBET
+ BETA = BET( IB )
+ IF( CONJ )THEN
+ RBETA = REAL( BETA )
+ BETA = CMPLX( RBETA, RZERO )
+ END IF
+ NULL = N.LE.0
+ IF( CONJ )
+ $ NULL = NULL.OR.( ( K.LE.0.OR.ALPHA.EQ.
+ $ ZERO ).AND.RBETA.EQ.RONE )
+*
+* Generate the matrix C.
+*
+ CALL CMAKE( SNAME( 2: 3 ), UPLO, ' ', N, N, C,
+ $ NMAX, CC, LDC, RESET, ZERO )
+*
+ NC = NC + 1
+*
+* Save every datum before calling the subroutine.
+*
+ UPLOS = UPLO
+ TRANSS = TRANS
+ NS = N
+ KS = K
+ ALS = ALPHA
+ DO 10 I = 1, LAA
+ AS( I ) = AA( I )
+ 10 CONTINUE
+ LDAS = LDA
+ DO 20 I = 1, LBB
+ BS( I ) = BB( I )
+ 20 CONTINUE
+ LDBS = LDB
+ IF( CONJ )THEN
+ RBETS = RBETA
+ ELSE
+ BETS = BETA
+ END IF
+ DO 30 I = 1, LCC
+ CS( I ) = CC( I )
+ 30 CONTINUE
+ LDCS = LDC
+*
+* Call the subroutine.
+*
+ IF( CONJ )THEN
+ IF( TRACE )
+ $ WRITE( NTRA, FMT = 9994 )NC, SNAME, UPLO,
+ $ TRANS, N, K, ALPHA, LDA, LDB, RBETA, LDC
+ IF( REWI )
+ $ REWIND NTRA
+ CALL CHER2K( UPLO, TRANS, N, K, ALPHA, AA,
+ $ LDA, BB, LDB, RBETA, CC, LDC )
+ ELSE
+ IF( TRACE )
+ $ WRITE( NTRA, FMT = 9993 )NC, SNAME, UPLO,
+ $ TRANS, N, K, ALPHA, LDA, LDB, BETA, LDC
+ IF( REWI )
+ $ REWIND NTRA
+ CALL CSYR2K( UPLO, TRANS, N, K, ALPHA, AA,
+ $ LDA, BB, LDB, BETA, CC, LDC )
+ END IF
+*
+* Check if error-exit was taken incorrectly.
+*
+ IF( .NOT.OK )THEN
+ WRITE( NOUT, FMT = 9992 )
+ FATAL = .TRUE.
+ GO TO 150
+ END IF
+*
+* See what data changed inside subroutines.
+*
+ ISAME( 1 ) = UPLOS.EQ.UPLO
+ ISAME( 2 ) = TRANSS.EQ.TRANS
+ ISAME( 3 ) = NS.EQ.N
+ ISAME( 4 ) = KS.EQ.K
+ ISAME( 5 ) = ALS.EQ.ALPHA
+ ISAME( 6 ) = LCE( AS, AA, LAA )
+ ISAME( 7 ) = LDAS.EQ.LDA
+ ISAME( 8 ) = LCE( BS, BB, LBB )
+ ISAME( 9 ) = LDBS.EQ.LDB
+ IF( CONJ )THEN
+ ISAME( 10 ) = RBETS.EQ.RBETA
+ ELSE
+ ISAME( 10 ) = BETS.EQ.BETA
+ END IF
+ IF( NULL )THEN
+ ISAME( 11 ) = LCE( CS, CC, LCC )
+ ELSE
+ ISAME( 11 ) = LCERES( 'HE', UPLO, N, N, CS,
+ $ CC, LDC )
+ END IF
+ ISAME( 12 ) = LDCS.EQ.LDC
+*
+* If data was incorrectly changed, report and
+* return.
+*
+ SAME = .TRUE.
+ DO 40 I = 1, NARGS
+ SAME = SAME.AND.ISAME( I )
+ IF( .NOT.ISAME( I ) )
+ $ WRITE( NOUT, FMT = 9998 )I
+ 40 CONTINUE
+ IF( .NOT.SAME )THEN
+ FATAL = .TRUE.
+ GO TO 150
+ END IF
+*
+ IF( .NOT.NULL )THEN
+*
+* Check the result column by column.
+*
+ IF( CONJ )THEN
+ TRANST = 'C'
+ ELSE
+ TRANST = 'T'
+ END IF
+ JJAB = 1
+ JC = 1
+ DO 70 J = 1, N
+ IF( UPPER )THEN
+ JJ = 1
+ LJ = J
+ ELSE
+ JJ = J
+ LJ = N - J + 1
+ END IF
+ IF( TRAN )THEN
+ DO 50 I = 1, K
+ W( I ) = ALPHA*AB( ( J - 1 )*2*
+ $ NMAX + K + I )
+ IF( CONJ )THEN
+ W( K + I ) = CONJG( ALPHA )*
+ $ AB( ( J - 1 )*2*
+ $ NMAX + I )
+ ELSE
+ W( K + I ) = ALPHA*
+ $ AB( ( J - 1 )*2*
+ $ NMAX + I )
+ END IF
+ 50 CONTINUE
+ CALL CMMCH( TRANST, 'N', LJ, 1, 2*K,
+ $ ONE, AB( JJAB ), 2*NMAX, W,
+ $ 2*NMAX, BETA, C( JJ, J ),
+ $ NMAX, CT, G, CC( JC ), LDC,
+ $ EPS, ERR, FATAL, NOUT,
+ $ .TRUE. )
+ ELSE
+ DO 60 I = 1, K
+ IF( CONJ )THEN
+ W( I ) = ALPHA*CONJG( AB( ( K +
+ $ I - 1 )*NMAX + J ) )
+ W( K + I ) = CONJG( ALPHA*
+ $ AB( ( I - 1 )*NMAX +
+ $ J ) )
+ ELSE
+ W( I ) = ALPHA*AB( ( K + I - 1 )*
+ $ NMAX + J )
+ W( K + I ) = ALPHA*
+ $ AB( ( I - 1 )*NMAX +
+ $ J )
+ END IF
+ 60 CONTINUE
+ CALL CMMCH( 'N', 'N', LJ, 1, 2*K, ONE,
+ $ AB( JJ ), NMAX, W, 2*NMAX,
+ $ BETA, C( JJ, J ), NMAX, CT,
+ $ G, CC( JC ), LDC, EPS, ERR,
+ $ FATAL, NOUT, .TRUE. )
+ END IF
+ IF( UPPER )THEN
+ JC = JC + LDC
+ ELSE
+ JC = JC + LDC + 1
+ IF( TRAN )
+ $ JJAB = JJAB + 2*NMAX
+ END IF
+ ERRMAX = MAX( ERRMAX, ERR )
+* If got really bad answer, report and
+* return.
+ IF( FATAL )
+ $ GO TO 140
+ 70 CONTINUE
+ END IF
+*
+ 80 CONTINUE
+*
+ 90 CONTINUE
+*
+ 100 CONTINUE
+*
+ 110 CONTINUE
+*
+ 120 CONTINUE
+*
+ 130 CONTINUE
+*
+* Report result.
+*
+ IF( ERRMAX.LT.THRESH )THEN
+ WRITE( NOUT, FMT = 9999 )SNAME, NC
+ ELSE
+ WRITE( NOUT, FMT = 9997 )SNAME, NC, ERRMAX
+ END IF
+ GO TO 160
+*
+ 140 CONTINUE
+ IF( N.GT.1 )
+ $ WRITE( NOUT, FMT = 9995 )J
+*
+ 150 CONTINUE
+ WRITE( NOUT, FMT = 9996 )SNAME
+ IF( CONJ )THEN
+ WRITE( NOUT, FMT = 9994 )NC, SNAME, UPLO, TRANS, N, K, ALPHA,
+ $ LDA, LDB, RBETA, LDC
+ ELSE
+ WRITE( NOUT, FMT = 9993 )NC, SNAME, UPLO, TRANS, N, K, ALPHA,
+ $ LDA, LDB, BETA, LDC
+ END IF
+*
+ 160 CONTINUE
+ RETURN
+*
+ 9999 FORMAT( ' ', A6, ' PASSED THE COMPUTATIONAL TESTS (', I6, ' CALL',
+ $ 'S)' )
+ 9998 FORMAT( ' ******* FATAL ERROR - PARAMETER NUMBER ', I2, ' WAS CH',
+ $ 'ANGED INCORRECTLY *******' )
+ 9997 FORMAT( ' ', A6, ' COMPLETED THE COMPUTATIONAL TESTS (', I6, ' C',
+ $ 'ALLS)', /' ******* BUT WITH MAXIMUM TEST RATIO', F8.2,
+ $ ' - SUSPECT *******' )
+ 9996 FORMAT( ' ******* ', A6, ' FAILED ON CALL NUMBER:' )
+ 9995 FORMAT( ' THESE ARE THE RESULTS FOR COLUMN ', I3 )
+ 9994 FORMAT( 1X, I6, ': ', A6, '(', 2( '''', A1, ''',' ), 2( I3, ',' ),
+ $ '(', F4.1, ',', F4.1, '), A,', I3, ', B,', I3, ',', F4.1,
+ $ ', C,', I3, ') .' )
+ 9993 FORMAT( 1X, I6, ': ', A6, '(', 2( '''', A1, ''',' ), 2( I3, ',' ),
+ $ '(', F4.1, ',', F4.1, '), A,', I3, ', B,', I3, ',(', F4.1,
+ $ ',', F4.1, '), C,', I3, ') .' )
+ 9992 FORMAT( ' ******* FATAL ERROR - ERROR-EXIT TAKEN ON VALID CALL *',
+ $ '******' )
+*
+* End of CCHK5.
+*
+ END
+ SUBROUTINE CCHKE( ISNUM, SRNAMT, NOUT )
+*
+* Tests the error exits from the Level 3 Blas.
+* Requires a special version of the error-handling routine XERBLA.
+* ALPHA, RALPHA, BETA, RBETA, A, B and C should not need to be defined.
+*
+* Auxiliary routine for test program for Level 3 Blas.
+*
+* -- Written on 8-February-1989.
+* Jack Dongarra, Argonne National Laboratory.
+* Iain Duff, AERE Harwell.
+* Jeremy Du Croz, Numerical Algorithms Group Ltd.
+* Sven Hammarling, Numerical Algorithms Group Ltd.
+*
+* .. Scalar Arguments ..
+ INTEGER ISNUM, NOUT
+ CHARACTER*6 SRNAMT
+* .. Scalars in Common ..
+ INTEGER INFOT, NOUTC
+ LOGICAL LERR, OK
+* .. Local Scalars ..
+ COMPLEX ALPHA, BETA
+ REAL RALPHA, RBETA
+* .. Local Arrays ..
+ COMPLEX A( 2, 1 ), B( 2, 1 ), C( 2, 1 )
+* .. External Subroutines ..
+ EXTERNAL CGEMM, CHEMM, CHER2K, CHERK, CHKXER, CSYMM,
+ $ CSYR2K, CSYRK, CTRMM, CTRSM
+* .. Common blocks ..
+ COMMON /INFOC/INFOT, NOUTC, OK, LERR
+* .. Executable Statements ..
+* OK is set to .FALSE. by the special version of XERBLA or by CHKXER
+* if anything is wrong.
+ OK = .TRUE.
+* LERR is set to .TRUE. by the special version of XERBLA each time
+* it is called, and is then tested and re-set by CHKXER.
+ LERR = .FALSE.
+ GO TO ( 10, 20, 30, 40, 50, 60, 70, 80,
+ $ 90 )ISNUM
+ 10 INFOT = 1
+ CALL CGEMM( '/', 'N', 0, 0, 0, ALPHA, A, 1, B, 1, BETA, C, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 1
+ CALL CGEMM( '/', 'C', 0, 0, 0, ALPHA, A, 1, B, 1, BETA, C, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 1
+ CALL CGEMM( '/', 'T', 0, 0, 0, ALPHA, A, 1, B, 1, BETA, C, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 2
+ CALL CGEMM( 'N', '/', 0, 0, 0, ALPHA, A, 1, B, 1, BETA, C, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 2
+ CALL CGEMM( 'C', '/', 0, 0, 0, ALPHA, A, 1, B, 1, BETA, C, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 2
+ CALL CGEMM( 'T', '/', 0, 0, 0, ALPHA, A, 1, B, 1, BETA, C, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 3
+ CALL CGEMM( 'N', 'N', -1, 0, 0, ALPHA, A, 1, B, 1, BETA, C, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 3
+ CALL CGEMM( 'N', 'C', -1, 0, 0, ALPHA, A, 1, B, 1, BETA, C, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 3
+ CALL CGEMM( 'N', 'T', -1, 0, 0, ALPHA, A, 1, B, 1, BETA, C, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 3
+ CALL CGEMM( 'C', 'N', -1, 0, 0, ALPHA, A, 1, B, 1, BETA, C, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 3
+ CALL CGEMM( 'C', 'C', -1, 0, 0, ALPHA, A, 1, B, 1, BETA, C, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 3
+ CALL CGEMM( 'C', 'T', -1, 0, 0, ALPHA, A, 1, B, 1, BETA, C, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 3
+ CALL CGEMM( 'T', 'N', -1, 0, 0, ALPHA, A, 1, B, 1, BETA, C, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 3
+ CALL CGEMM( 'T', 'C', -1, 0, 0, ALPHA, A, 1, B, 1, BETA, C, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 3
+ CALL CGEMM( 'T', 'T', -1, 0, 0, ALPHA, A, 1, B, 1, BETA, C, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 4
+ CALL CGEMM( 'N', 'N', 0, -1, 0, ALPHA, A, 1, B, 1, BETA, C, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 4
+ CALL CGEMM( 'N', 'C', 0, -1, 0, ALPHA, A, 1, B, 1, BETA, C, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 4
+ CALL CGEMM( 'N', 'T', 0, -1, 0, ALPHA, A, 1, B, 1, BETA, C, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 4
+ CALL CGEMM( 'C', 'N', 0, -1, 0, ALPHA, A, 1, B, 1, BETA, C, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 4
+ CALL CGEMM( 'C', 'C', 0, -1, 0, ALPHA, A, 1, B, 1, BETA, C, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 4
+ CALL CGEMM( 'C', 'T', 0, -1, 0, ALPHA, A, 1, B, 1, BETA, C, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 4
+ CALL CGEMM( 'T', 'N', 0, -1, 0, ALPHA, A, 1, B, 1, BETA, C, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 4
+ CALL CGEMM( 'T', 'C', 0, -1, 0, ALPHA, A, 1, B, 1, BETA, C, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 4
+ CALL CGEMM( 'T', 'T', 0, -1, 0, ALPHA, A, 1, B, 1, BETA, C, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 5
+ CALL CGEMM( 'N', 'N', 0, 0, -1, ALPHA, A, 1, B, 1, BETA, C, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 5
+ CALL CGEMM( 'N', 'C', 0, 0, -1, ALPHA, A, 1, B, 1, BETA, C, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 5
+ CALL CGEMM( 'N', 'T', 0, 0, -1, ALPHA, A, 1, B, 1, BETA, C, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 5
+ CALL CGEMM( 'C', 'N', 0, 0, -1, ALPHA, A, 1, B, 1, BETA, C, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 5
+ CALL CGEMM( 'C', 'C', 0, 0, -1, ALPHA, A, 1, B, 1, BETA, C, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 5
+ CALL CGEMM( 'C', 'T', 0, 0, -1, ALPHA, A, 1, B, 1, BETA, C, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 5
+ CALL CGEMM( 'T', 'N', 0, 0, -1, ALPHA, A, 1, B, 1, BETA, C, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 5
+ CALL CGEMM( 'T', 'C', 0, 0, -1, ALPHA, A, 1, B, 1, BETA, C, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 5
+ CALL CGEMM( 'T', 'T', 0, 0, -1, ALPHA, A, 1, B, 1, BETA, C, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 8
+ CALL CGEMM( 'N', 'N', 2, 0, 0, ALPHA, A, 1, B, 1, BETA, C, 2 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 8
+ CALL CGEMM( 'N', 'C', 2, 0, 0, ALPHA, A, 1, B, 1, BETA, C, 2 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 8
+ CALL CGEMM( 'N', 'T', 2, 0, 0, ALPHA, A, 1, B, 1, BETA, C, 2 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 8
+ CALL CGEMM( 'C', 'N', 0, 0, 2, ALPHA, A, 1, B, 2, BETA, C, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 8
+ CALL CGEMM( 'C', 'C', 0, 0, 2, ALPHA, A, 1, B, 1, BETA, C, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 8
+ CALL CGEMM( 'C', 'T', 0, 0, 2, ALPHA, A, 1, B, 1, BETA, C, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 8
+ CALL CGEMM( 'T', 'N', 0, 0, 2, ALPHA, A, 1, B, 2, BETA, C, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 8
+ CALL CGEMM( 'T', 'C', 0, 0, 2, ALPHA, A, 1, B, 1, BETA, C, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 8
+ CALL CGEMM( 'T', 'T', 0, 0, 2, ALPHA, A, 1, B, 1, BETA, C, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 10
+ CALL CGEMM( 'N', 'N', 0, 0, 2, ALPHA, A, 1, B, 1, BETA, C, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 10
+ CALL CGEMM( 'C', 'N', 0, 0, 2, ALPHA, A, 2, B, 1, BETA, C, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 10
+ CALL CGEMM( 'T', 'N', 0, 0, 2, ALPHA, A, 2, B, 1, BETA, C, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 10
+ CALL CGEMM( 'N', 'C', 0, 2, 0, ALPHA, A, 1, B, 1, BETA, C, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 10
+ CALL CGEMM( 'C', 'C', 0, 2, 0, ALPHA, A, 1, B, 1, BETA, C, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 10
+ CALL CGEMM( 'T', 'C', 0, 2, 0, ALPHA, A, 1, B, 1, BETA, C, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 10
+ CALL CGEMM( 'N', 'T', 0, 2, 0, ALPHA, A, 1, B, 1, BETA, C, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 10
+ CALL CGEMM( 'C', 'T', 0, 2, 0, ALPHA, A, 1, B, 1, BETA, C, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 10
+ CALL CGEMM( 'T', 'T', 0, 2, 0, ALPHA, A, 1, B, 1, BETA, C, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 13
+ CALL CGEMM( 'N', 'N', 2, 0, 0, ALPHA, A, 2, B, 1, BETA, C, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 13
+ CALL CGEMM( 'N', 'C', 2, 0, 0, ALPHA, A, 2, B, 1, BETA, C, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 13
+ CALL CGEMM( 'N', 'T', 2, 0, 0, ALPHA, A, 2, B, 1, BETA, C, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 13
+ CALL CGEMM( 'C', 'N', 2, 0, 0, ALPHA, A, 1, B, 1, BETA, C, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 13
+ CALL CGEMM( 'C', 'C', 2, 0, 0, ALPHA, A, 1, B, 1, BETA, C, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 13
+ CALL CGEMM( 'C', 'T', 2, 0, 0, ALPHA, A, 1, B, 1, BETA, C, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 13
+ CALL CGEMM( 'T', 'N', 2, 0, 0, ALPHA, A, 1, B, 1, BETA, C, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 13
+ CALL CGEMM( 'T', 'C', 2, 0, 0, ALPHA, A, 1, B, 1, BETA, C, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 13
+ CALL CGEMM( 'T', 'T', 2, 0, 0, ALPHA, A, 1, B, 1, BETA, C, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ GO TO 100
+ 20 INFOT = 1
+ CALL CHEMM( '/', 'U', 0, 0, ALPHA, A, 1, B, 1, BETA, C, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 2
+ CALL CHEMM( 'L', '/', 0, 0, ALPHA, A, 1, B, 1, BETA, C, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 3
+ CALL CHEMM( 'L', 'U', -1, 0, ALPHA, A, 1, B, 1, BETA, C, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 3
+ CALL CHEMM( 'R', 'U', -1, 0, ALPHA, A, 1, B, 1, BETA, C, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 3
+ CALL CHEMM( 'L', 'L', -1, 0, ALPHA, A, 1, B, 1, BETA, C, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 3
+ CALL CHEMM( 'R', 'L', -1, 0, ALPHA, A, 1, B, 1, BETA, C, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 4
+ CALL CHEMM( 'L', 'U', 0, -1, ALPHA, A, 1, B, 1, BETA, C, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 4
+ CALL CHEMM( 'R', 'U', 0, -1, ALPHA, A, 1, B, 1, BETA, C, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 4
+ CALL CHEMM( 'L', 'L', 0, -1, ALPHA, A, 1, B, 1, BETA, C, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 4
+ CALL CHEMM( 'R', 'L', 0, -1, ALPHA, A, 1, B, 1, BETA, C, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 7
+ CALL CHEMM( 'L', 'U', 2, 0, ALPHA, A, 1, B, 2, BETA, C, 2 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 7
+ CALL CHEMM( 'R', 'U', 0, 2, ALPHA, A, 1, B, 1, BETA, C, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 7
+ CALL CHEMM( 'L', 'L', 2, 0, ALPHA, A, 1, B, 2, BETA, C, 2 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 7
+ CALL CHEMM( 'R', 'L', 0, 2, ALPHA, A, 1, B, 1, BETA, C, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 9
+ CALL CHEMM( 'L', 'U', 2, 0, ALPHA, A, 2, B, 1, BETA, C, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 9
+ CALL CHEMM( 'R', 'U', 2, 0, ALPHA, A, 1, B, 1, BETA, C, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 9
+ CALL CHEMM( 'L', 'L', 2, 0, ALPHA, A, 2, B, 1, BETA, C, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 9
+ CALL CHEMM( 'R', 'L', 2, 0, ALPHA, A, 1, B, 1, BETA, C, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 12
+ CALL CHEMM( 'L', 'U', 2, 0, ALPHA, A, 2, B, 2, BETA, C, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 12
+ CALL CHEMM( 'R', 'U', 2, 0, ALPHA, A, 1, B, 2, BETA, C, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 12
+ CALL CHEMM( 'L', 'L', 2, 0, ALPHA, A, 2, B, 2, BETA, C, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 12
+ CALL CHEMM( 'R', 'L', 2, 0, ALPHA, A, 1, B, 2, BETA, C, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ GO TO 100
+ 30 INFOT = 1
+ CALL CSYMM( '/', 'U', 0, 0, ALPHA, A, 1, B, 1, BETA, C, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 2
+ CALL CSYMM( 'L', '/', 0, 0, ALPHA, A, 1, B, 1, BETA, C, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 3
+ CALL CSYMM( 'L', 'U', -1, 0, ALPHA, A, 1, B, 1, BETA, C, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 3
+ CALL CSYMM( 'R', 'U', -1, 0, ALPHA, A, 1, B, 1, BETA, C, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 3
+ CALL CSYMM( 'L', 'L', -1, 0, ALPHA, A, 1, B, 1, BETA, C, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 3
+ CALL CSYMM( 'R', 'L', -1, 0, ALPHA, A, 1, B, 1, BETA, C, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 4
+ CALL CSYMM( 'L', 'U', 0, -1, ALPHA, A, 1, B, 1, BETA, C, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 4
+ CALL CSYMM( 'R', 'U', 0, -1, ALPHA, A, 1, B, 1, BETA, C, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 4
+ CALL CSYMM( 'L', 'L', 0, -1, ALPHA, A, 1, B, 1, BETA, C, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 4
+ CALL CSYMM( 'R', 'L', 0, -1, ALPHA, A, 1, B, 1, BETA, C, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 7
+ CALL CSYMM( 'L', 'U', 2, 0, ALPHA, A, 1, B, 2, BETA, C, 2 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 7
+ CALL CSYMM( 'R', 'U', 0, 2, ALPHA, A, 1, B, 1, BETA, C, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 7
+ CALL CSYMM( 'L', 'L', 2, 0, ALPHA, A, 1, B, 2, BETA, C, 2 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 7
+ CALL CSYMM( 'R', 'L', 0, 2, ALPHA, A, 1, B, 1, BETA, C, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 9
+ CALL CSYMM( 'L', 'U', 2, 0, ALPHA, A, 2, B, 1, BETA, C, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 9
+ CALL CSYMM( 'R', 'U', 2, 0, ALPHA, A, 1, B, 1, BETA, C, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 9
+ CALL CSYMM( 'L', 'L', 2, 0, ALPHA, A, 2, B, 1, BETA, C, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 9
+ CALL CSYMM( 'R', 'L', 2, 0, ALPHA, A, 1, B, 1, BETA, C, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 12
+ CALL CSYMM( 'L', 'U', 2, 0, ALPHA, A, 2, B, 2, BETA, C, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 12
+ CALL CSYMM( 'R', 'U', 2, 0, ALPHA, A, 1, B, 2, BETA, C, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 12
+ CALL CSYMM( 'L', 'L', 2, 0, ALPHA, A, 2, B, 2, BETA, C, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 12
+ CALL CSYMM( 'R', 'L', 2, 0, ALPHA, A, 1, B, 2, BETA, C, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ GO TO 100
+ 40 INFOT = 1
+ CALL CTRMM( '/', 'U', 'N', 'N', 0, 0, ALPHA, A, 1, B, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 2
+ CALL CTRMM( 'L', '/', 'N', 'N', 0, 0, ALPHA, A, 1, B, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 3
+ CALL CTRMM( 'L', 'U', '/', 'N', 0, 0, ALPHA, A, 1, B, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 4
+ CALL CTRMM( 'L', 'U', 'N', '/', 0, 0, ALPHA, A, 1, B, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 5
+ CALL CTRMM( 'L', 'U', 'N', 'N', -1, 0, ALPHA, A, 1, B, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 5
+ CALL CTRMM( 'L', 'U', 'C', 'N', -1, 0, ALPHA, A, 1, B, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 5
+ CALL CTRMM( 'L', 'U', 'T', 'N', -1, 0, ALPHA, A, 1, B, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 5
+ CALL CTRMM( 'R', 'U', 'N', 'N', -1, 0, ALPHA, A, 1, B, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 5
+ CALL CTRMM( 'R', 'U', 'C', 'N', -1, 0, ALPHA, A, 1, B, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 5
+ CALL CTRMM( 'R', 'U', 'T', 'N', -1, 0, ALPHA, A, 1, B, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 5
+ CALL CTRMM( 'L', 'L', 'N', 'N', -1, 0, ALPHA, A, 1, B, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 5
+ CALL CTRMM( 'L', 'L', 'C', 'N', -1, 0, ALPHA, A, 1, B, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 5
+ CALL CTRMM( 'L', 'L', 'T', 'N', -1, 0, ALPHA, A, 1, B, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 5
+ CALL CTRMM( 'R', 'L', 'N', 'N', -1, 0, ALPHA, A, 1, B, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 5
+ CALL CTRMM( 'R', 'L', 'C', 'N', -1, 0, ALPHA, A, 1, B, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 5
+ CALL CTRMM( 'R', 'L', 'T', 'N', -1, 0, ALPHA, A, 1, B, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 6
+ CALL CTRMM( 'L', 'U', 'N', 'N', 0, -1, ALPHA, A, 1, B, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 6
+ CALL CTRMM( 'L', 'U', 'C', 'N', 0, -1, ALPHA, A, 1, B, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 6
+ CALL CTRMM( 'L', 'U', 'T', 'N', 0, -1, ALPHA, A, 1, B, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 6
+ CALL CTRMM( 'R', 'U', 'N', 'N', 0, -1, ALPHA, A, 1, B, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 6
+ CALL CTRMM( 'R', 'U', 'C', 'N', 0, -1, ALPHA, A, 1, B, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 6
+ CALL CTRMM( 'R', 'U', 'T', 'N', 0, -1, ALPHA, A, 1, B, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 6
+ CALL CTRMM( 'L', 'L', 'N', 'N', 0, -1, ALPHA, A, 1, B, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 6
+ CALL CTRMM( 'L', 'L', 'C', 'N', 0, -1, ALPHA, A, 1, B, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 6
+ CALL CTRMM( 'L', 'L', 'T', 'N', 0, -1, ALPHA, A, 1, B, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 6
+ CALL CTRMM( 'R', 'L', 'N', 'N', 0, -1, ALPHA, A, 1, B, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 6
+ CALL CTRMM( 'R', 'L', 'C', 'N', 0, -1, ALPHA, A, 1, B, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 6
+ CALL CTRMM( 'R', 'L', 'T', 'N', 0, -1, ALPHA, A, 1, B, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 9
+ CALL CTRMM( 'L', 'U', 'N', 'N', 2, 0, ALPHA, A, 1, B, 2 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 9
+ CALL CTRMM( 'L', 'U', 'C', 'N', 2, 0, ALPHA, A, 1, B, 2 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 9
+ CALL CTRMM( 'L', 'U', 'T', 'N', 2, 0, ALPHA, A, 1, B, 2 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 9
+ CALL CTRMM( 'R', 'U', 'N', 'N', 0, 2, ALPHA, A, 1, B, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 9
+ CALL CTRMM( 'R', 'U', 'C', 'N', 0, 2, ALPHA, A, 1, B, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 9
+ CALL CTRMM( 'R', 'U', 'T', 'N', 0, 2, ALPHA, A, 1, B, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 9
+ CALL CTRMM( 'L', 'L', 'N', 'N', 2, 0, ALPHA, A, 1, B, 2 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 9
+ CALL CTRMM( 'L', 'L', 'C', 'N', 2, 0, ALPHA, A, 1, B, 2 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 9
+ CALL CTRMM( 'L', 'L', 'T', 'N', 2, 0, ALPHA, A, 1, B, 2 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 9
+ CALL CTRMM( 'R', 'L', 'N', 'N', 0, 2, ALPHA, A, 1, B, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 9
+ CALL CTRMM( 'R', 'L', 'C', 'N', 0, 2, ALPHA, A, 1, B, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 9
+ CALL CTRMM( 'R', 'L', 'T', 'N', 0, 2, ALPHA, A, 1, B, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 11
+ CALL CTRMM( 'L', 'U', 'N', 'N', 2, 0, ALPHA, A, 2, B, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 11
+ CALL CTRMM( 'L', 'U', 'C', 'N', 2, 0, ALPHA, A, 2, B, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 11
+ CALL CTRMM( 'L', 'U', 'T', 'N', 2, 0, ALPHA, A, 2, B, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 11
+ CALL CTRMM( 'R', 'U', 'N', 'N', 2, 0, ALPHA, A, 1, B, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 11
+ CALL CTRMM( 'R', 'U', 'C', 'N', 2, 0, ALPHA, A, 1, B, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 11
+ CALL CTRMM( 'R', 'U', 'T', 'N', 2, 0, ALPHA, A, 1, B, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 11
+ CALL CTRMM( 'L', 'L', 'N', 'N', 2, 0, ALPHA, A, 2, B, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 11
+ CALL CTRMM( 'L', 'L', 'C', 'N', 2, 0, ALPHA, A, 2, B, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 11
+ CALL CTRMM( 'L', 'L', 'T', 'N', 2, 0, ALPHA, A, 2, B, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 11
+ CALL CTRMM( 'R', 'L', 'N', 'N', 2, 0, ALPHA, A, 1, B, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 11
+ CALL CTRMM( 'R', 'L', 'C', 'N', 2, 0, ALPHA, A, 1, B, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 11
+ CALL CTRMM( 'R', 'L', 'T', 'N', 2, 0, ALPHA, A, 1, B, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ GO TO 100
+ 50 INFOT = 1
+ CALL CTRSM( '/', 'U', 'N', 'N', 0, 0, ALPHA, A, 1, B, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 2
+ CALL CTRSM( 'L', '/', 'N', 'N', 0, 0, ALPHA, A, 1, B, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 3
+ CALL CTRSM( 'L', 'U', '/', 'N', 0, 0, ALPHA, A, 1, B, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 4
+ CALL CTRSM( 'L', 'U', 'N', '/', 0, 0, ALPHA, A, 1, B, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 5
+ CALL CTRSM( 'L', 'U', 'N', 'N', -1, 0, ALPHA, A, 1, B, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 5
+ CALL CTRSM( 'L', 'U', 'C', 'N', -1, 0, ALPHA, A, 1, B, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 5
+ CALL CTRSM( 'L', 'U', 'T', 'N', -1, 0, ALPHA, A, 1, B, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 5
+ CALL CTRSM( 'R', 'U', 'N', 'N', -1, 0, ALPHA, A, 1, B, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 5
+ CALL CTRSM( 'R', 'U', 'C', 'N', -1, 0, ALPHA, A, 1, B, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 5
+ CALL CTRSM( 'R', 'U', 'T', 'N', -1, 0, ALPHA, A, 1, B, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 5
+ CALL CTRSM( 'L', 'L', 'N', 'N', -1, 0, ALPHA, A, 1, B, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 5
+ CALL CTRSM( 'L', 'L', 'C', 'N', -1, 0, ALPHA, A, 1, B, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 5
+ CALL CTRSM( 'L', 'L', 'T', 'N', -1, 0, ALPHA, A, 1, B, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 5
+ CALL CTRSM( 'R', 'L', 'N', 'N', -1, 0, ALPHA, A, 1, B, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 5
+ CALL CTRSM( 'R', 'L', 'C', 'N', -1, 0, ALPHA, A, 1, B, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 5
+ CALL CTRSM( 'R', 'L', 'T', 'N', -1, 0, ALPHA, A, 1, B, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 6
+ CALL CTRSM( 'L', 'U', 'N', 'N', 0, -1, ALPHA, A, 1, B, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 6
+ CALL CTRSM( 'L', 'U', 'C', 'N', 0, -1, ALPHA, A, 1, B, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 6
+ CALL CTRSM( 'L', 'U', 'T', 'N', 0, -1, ALPHA, A, 1, B, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 6
+ CALL CTRSM( 'R', 'U', 'N', 'N', 0, -1, ALPHA, A, 1, B, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 6
+ CALL CTRSM( 'R', 'U', 'C', 'N', 0, -1, ALPHA, A, 1, B, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 6
+ CALL CTRSM( 'R', 'U', 'T', 'N', 0, -1, ALPHA, A, 1, B, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 6
+ CALL CTRSM( 'L', 'L', 'N', 'N', 0, -1, ALPHA, A, 1, B, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 6
+ CALL CTRSM( 'L', 'L', 'C', 'N', 0, -1, ALPHA, A, 1, B, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 6
+ CALL CTRSM( 'L', 'L', 'T', 'N', 0, -1, ALPHA, A, 1, B, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 6
+ CALL CTRSM( 'R', 'L', 'N', 'N', 0, -1, ALPHA, A, 1, B, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 6
+ CALL CTRSM( 'R', 'L', 'C', 'N', 0, -1, ALPHA, A, 1, B, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 6
+ CALL CTRSM( 'R', 'L', 'T', 'N', 0, -1, ALPHA, A, 1, B, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 9
+ CALL CTRSM( 'L', 'U', 'N', 'N', 2, 0, ALPHA, A, 1, B, 2 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 9
+ CALL CTRSM( 'L', 'U', 'C', 'N', 2, 0, ALPHA, A, 1, B, 2 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 9
+ CALL CTRSM( 'L', 'U', 'T', 'N', 2, 0, ALPHA, A, 1, B, 2 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 9
+ CALL CTRSM( 'R', 'U', 'N', 'N', 0, 2, ALPHA, A, 1, B, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 9
+ CALL CTRSM( 'R', 'U', 'C', 'N', 0, 2, ALPHA, A, 1, B, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 9
+ CALL CTRSM( 'R', 'U', 'T', 'N', 0, 2, ALPHA, A, 1, B, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 9
+ CALL CTRSM( 'L', 'L', 'N', 'N', 2, 0, ALPHA, A, 1, B, 2 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 9
+ CALL CTRSM( 'L', 'L', 'C', 'N', 2, 0, ALPHA, A, 1, B, 2 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 9
+ CALL CTRSM( 'L', 'L', 'T', 'N', 2, 0, ALPHA, A, 1, B, 2 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 9
+ CALL CTRSM( 'R', 'L', 'N', 'N', 0, 2, ALPHA, A, 1, B, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 9
+ CALL CTRSM( 'R', 'L', 'C', 'N', 0, 2, ALPHA, A, 1, B, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 9
+ CALL CTRSM( 'R', 'L', 'T', 'N', 0, 2, ALPHA, A, 1, B, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 11
+ CALL CTRSM( 'L', 'U', 'N', 'N', 2, 0, ALPHA, A, 2, B, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 11
+ CALL CTRSM( 'L', 'U', 'C', 'N', 2, 0, ALPHA, A, 2, B, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 11
+ CALL CTRSM( 'L', 'U', 'T', 'N', 2, 0, ALPHA, A, 2, B, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 11
+ CALL CTRSM( 'R', 'U', 'N', 'N', 2, 0, ALPHA, A, 1, B, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 11
+ CALL CTRSM( 'R', 'U', 'C', 'N', 2, 0, ALPHA, A, 1, B, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 11
+ CALL CTRSM( 'R', 'U', 'T', 'N', 2, 0, ALPHA, A, 1, B, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 11
+ CALL CTRSM( 'L', 'L', 'N', 'N', 2, 0, ALPHA, A, 2, B, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 11
+ CALL CTRSM( 'L', 'L', 'C', 'N', 2, 0, ALPHA, A, 2, B, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 11
+ CALL CTRSM( 'L', 'L', 'T', 'N', 2, 0, ALPHA, A, 2, B, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 11
+ CALL CTRSM( 'R', 'L', 'N', 'N', 2, 0, ALPHA, A, 1, B, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 11
+ CALL CTRSM( 'R', 'L', 'C', 'N', 2, 0, ALPHA, A, 1, B, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 11
+ CALL CTRSM( 'R', 'L', 'T', 'N', 2, 0, ALPHA, A, 1, B, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ GO TO 100
+ 60 INFOT = 1
+ CALL CHERK( '/', 'N', 0, 0, RALPHA, A, 1, RBETA, C, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 2
+ CALL CHERK( 'U', 'T', 0, 0, RALPHA, A, 1, RBETA, C, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 3
+ CALL CHERK( 'U', 'N', -1, 0, RALPHA, A, 1, RBETA, C, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 3
+ CALL CHERK( 'U', 'C', -1, 0, RALPHA, A, 1, RBETA, C, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 3
+ CALL CHERK( 'L', 'N', -1, 0, RALPHA, A, 1, RBETA, C, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 3
+ CALL CHERK( 'L', 'C', -1, 0, RALPHA, A, 1, RBETA, C, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 4
+ CALL CHERK( 'U', 'N', 0, -1, RALPHA, A, 1, RBETA, C, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 4
+ CALL CHERK( 'U', 'C', 0, -1, RALPHA, A, 1, RBETA, C, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 4
+ CALL CHERK( 'L', 'N', 0, -1, RALPHA, A, 1, RBETA, C, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 4
+ CALL CHERK( 'L', 'C', 0, -1, RALPHA, A, 1, RBETA, C, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 7
+ CALL CHERK( 'U', 'N', 2, 0, RALPHA, A, 1, RBETA, C, 2 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 7
+ CALL CHERK( 'U', 'C', 0, 2, RALPHA, A, 1, RBETA, C, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 7
+ CALL CHERK( 'L', 'N', 2, 0, RALPHA, A, 1, RBETA, C, 2 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 7
+ CALL CHERK( 'L', 'C', 0, 2, RALPHA, A, 1, RBETA, C, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 10
+ CALL CHERK( 'U', 'N', 2, 0, RALPHA, A, 2, RBETA, C, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 10
+ CALL CHERK( 'U', 'C', 2, 0, RALPHA, A, 1, RBETA, C, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 10
+ CALL CHERK( 'L', 'N', 2, 0, RALPHA, A, 2, RBETA, C, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 10
+ CALL CHERK( 'L', 'C', 2, 0, RALPHA, A, 1, RBETA, C, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ GO TO 100
+ 70 INFOT = 1
+ CALL CSYRK( '/', 'N', 0, 0, ALPHA, A, 1, BETA, C, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 2
+ CALL CSYRK( 'U', 'C', 0, 0, ALPHA, A, 1, BETA, C, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 3
+ CALL CSYRK( 'U', 'N', -1, 0, ALPHA, A, 1, BETA, C, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 3
+ CALL CSYRK( 'U', 'T', -1, 0, ALPHA, A, 1, BETA, C, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 3
+ CALL CSYRK( 'L', 'N', -1, 0, ALPHA, A, 1, BETA, C, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 3
+ CALL CSYRK( 'L', 'T', -1, 0, ALPHA, A, 1, BETA, C, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 4
+ CALL CSYRK( 'U', 'N', 0, -1, ALPHA, A, 1, BETA, C, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 4
+ CALL CSYRK( 'U', 'T', 0, -1, ALPHA, A, 1, BETA, C, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 4
+ CALL CSYRK( 'L', 'N', 0, -1, ALPHA, A, 1, BETA, C, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 4
+ CALL CSYRK( 'L', 'T', 0, -1, ALPHA, A, 1, BETA, C, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 7
+ CALL CSYRK( 'U', 'N', 2, 0, ALPHA, A, 1, BETA, C, 2 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 7
+ CALL CSYRK( 'U', 'T', 0, 2, ALPHA, A, 1, BETA, C, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 7
+ CALL CSYRK( 'L', 'N', 2, 0, ALPHA, A, 1, BETA, C, 2 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 7
+ CALL CSYRK( 'L', 'T', 0, 2, ALPHA, A, 1, BETA, C, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 10
+ CALL CSYRK( 'U', 'N', 2, 0, ALPHA, A, 2, BETA, C, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 10
+ CALL CSYRK( 'U', 'T', 2, 0, ALPHA, A, 1, BETA, C, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 10
+ CALL CSYRK( 'L', 'N', 2, 0, ALPHA, A, 2, BETA, C, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 10
+ CALL CSYRK( 'L', 'T', 2, 0, ALPHA, A, 1, BETA, C, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ GO TO 100
+ 80 INFOT = 1
+ CALL CHER2K( '/', 'N', 0, 0, ALPHA, A, 1, B, 1, RBETA, C, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 2
+ CALL CHER2K( 'U', 'T', 0, 0, ALPHA, A, 1, B, 1, RBETA, C, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 3
+ CALL CHER2K( 'U', 'N', -1, 0, ALPHA, A, 1, B, 1, RBETA, C, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 3
+ CALL CHER2K( 'U', 'C', -1, 0, ALPHA, A, 1, B, 1, RBETA, C, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 3
+ CALL CHER2K( 'L', 'N', -1, 0, ALPHA, A, 1, B, 1, RBETA, C, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 3
+ CALL CHER2K( 'L', 'C', -1, 0, ALPHA, A, 1, B, 1, RBETA, C, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 4
+ CALL CHER2K( 'U', 'N', 0, -1, ALPHA, A, 1, B, 1, RBETA, C, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 4
+ CALL CHER2K( 'U', 'C', 0, -1, ALPHA, A, 1, B, 1, RBETA, C, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 4
+ CALL CHER2K( 'L', 'N', 0, -1, ALPHA, A, 1, B, 1, RBETA, C, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 4
+ CALL CHER2K( 'L', 'C', 0, -1, ALPHA, A, 1, B, 1, RBETA, C, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 7
+ CALL CHER2K( 'U', 'N', 2, 0, ALPHA, A, 1, B, 1, RBETA, C, 2 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 7
+ CALL CHER2K( 'U', 'C', 0, 2, ALPHA, A, 1, B, 1, RBETA, C, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 7
+ CALL CHER2K( 'L', 'N', 2, 0, ALPHA, A, 1, B, 1, RBETA, C, 2 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 7
+ CALL CHER2K( 'L', 'C', 0, 2, ALPHA, A, 1, B, 1, RBETA, C, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 9
+ CALL CHER2K( 'U', 'N', 2, 0, ALPHA, A, 2, B, 1, RBETA, C, 2 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 9
+ CALL CHER2K( 'U', 'C', 0, 2, ALPHA, A, 2, B, 1, RBETA, C, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 9
+ CALL CHER2K( 'L', 'N', 2, 0, ALPHA, A, 2, B, 1, RBETA, C, 2 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 9
+ CALL CHER2K( 'L', 'C', 0, 2, ALPHA, A, 2, B, 1, RBETA, C, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 12
+ CALL CHER2K( 'U', 'N', 2, 0, ALPHA, A, 2, B, 2, RBETA, C, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 12
+ CALL CHER2K( 'U', 'C', 2, 0, ALPHA, A, 1, B, 1, RBETA, C, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 12
+ CALL CHER2K( 'L', 'N', 2, 0, ALPHA, A, 2, B, 2, RBETA, C, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 12
+ CALL CHER2K( 'L', 'C', 2, 0, ALPHA, A, 1, B, 1, RBETA, C, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ GO TO 100
+ 90 INFOT = 1
+ CALL CSYR2K( '/', 'N', 0, 0, ALPHA, A, 1, B, 1, BETA, C, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 2
+ CALL CSYR2K( 'U', 'C', 0, 0, ALPHA, A, 1, B, 1, BETA, C, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 3
+ CALL CSYR2K( 'U', 'N', -1, 0, ALPHA, A, 1, B, 1, BETA, C, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 3
+ CALL CSYR2K( 'U', 'T', -1, 0, ALPHA, A, 1, B, 1, BETA, C, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 3
+ CALL CSYR2K( 'L', 'N', -1, 0, ALPHA, A, 1, B, 1, BETA, C, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 3
+ CALL CSYR2K( 'L', 'T', -1, 0, ALPHA, A, 1, B, 1, BETA, C, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 4
+ CALL CSYR2K( 'U', 'N', 0, -1, ALPHA, A, 1, B, 1, BETA, C, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 4
+ CALL CSYR2K( 'U', 'T', 0, -1, ALPHA, A, 1, B, 1, BETA, C, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 4
+ CALL CSYR2K( 'L', 'N', 0, -1, ALPHA, A, 1, B, 1, BETA, C, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 4
+ CALL CSYR2K( 'L', 'T', 0, -1, ALPHA, A, 1, B, 1, BETA, C, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 7
+ CALL CSYR2K( 'U', 'N', 2, 0, ALPHA, A, 1, B, 1, BETA, C, 2 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 7
+ CALL CSYR2K( 'U', 'T', 0, 2, ALPHA, A, 1, B, 1, BETA, C, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 7
+ CALL CSYR2K( 'L', 'N', 2, 0, ALPHA, A, 1, B, 1, BETA, C, 2 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 7
+ CALL CSYR2K( 'L', 'T', 0, 2, ALPHA, A, 1, B, 1, BETA, C, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 9
+ CALL CSYR2K( 'U', 'N', 2, 0, ALPHA, A, 2, B, 1, BETA, C, 2 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 9
+ CALL CSYR2K( 'U', 'T', 0, 2, ALPHA, A, 2, B, 1, BETA, C, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 9
+ CALL CSYR2K( 'L', 'N', 2, 0, ALPHA, A, 2, B, 1, BETA, C, 2 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 9
+ CALL CSYR2K( 'L', 'T', 0, 2, ALPHA, A, 2, B, 1, BETA, C, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 12
+ CALL CSYR2K( 'U', 'N', 2, 0, ALPHA, A, 2, B, 2, BETA, C, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 12
+ CALL CSYR2K( 'U', 'T', 2, 0, ALPHA, A, 1, B, 1, BETA, C, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 12
+ CALL CSYR2K( 'L', 'N', 2, 0, ALPHA, A, 2, B, 2, BETA, C, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 12
+ CALL CSYR2K( 'L', 'T', 2, 0, ALPHA, A, 1, B, 1, BETA, C, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+*
+ 100 IF( OK )THEN
+ WRITE( NOUT, FMT = 9999 )SRNAMT
+ ELSE
+ WRITE( NOUT, FMT = 9998 )SRNAMT
+ END IF
+ RETURN
+*
+ 9999 FORMAT( ' ', A6, ' PASSED THE TESTS OF ERROR-EXITS' )
+ 9998 FORMAT( ' ******* ', A6, ' FAILED THE TESTS OF ERROR-EXITS *****',
+ $ '**' )
+*
+* End of CCHKE.
+*
+ END
+ SUBROUTINE CMAKE( TYPE, UPLO, DIAG, M, N, A, NMAX, AA, LDA, RESET,
+ $ TRANSL )
+*
+* Generates values for an M by N matrix A.
+* Stores the values in the array AA in the data structure required
+* by the routine, with unwanted elements set to rogue value.
+*
+* TYPE is 'GE', 'HE', 'SY' or 'TR'.
+*
+* Auxiliary routine for test program for Level 3 Blas.
+*
+* -- Written on 8-February-1989.
+* Jack Dongarra, Argonne National Laboratory.
+* Iain Duff, AERE Harwell.
+* Jeremy Du Croz, Numerical Algorithms Group Ltd.
+* Sven Hammarling, Numerical Algorithms Group Ltd.
+*
+* .. Parameters ..
+ COMPLEX ZERO, ONE
+ PARAMETER ( ZERO = ( 0.0, 0.0 ), ONE = ( 1.0, 0.0 ) )
+ COMPLEX ROGUE
+ PARAMETER ( ROGUE = ( -1.0E10, 1.0E10 ) )
+ REAL RZERO
+ PARAMETER ( RZERO = 0.0 )
+ REAL RROGUE
+ PARAMETER ( RROGUE = -1.0E10 )
+* .. Scalar Arguments ..
+ COMPLEX TRANSL
+ INTEGER LDA, M, N, NMAX
+ LOGICAL RESET
+ CHARACTER*1 DIAG, UPLO
+ CHARACTER*2 TYPE
+* .. Array Arguments ..
+ COMPLEX A( NMAX, * ), AA( * )
+* .. Local Scalars ..
+ INTEGER I, IBEG, IEND, J, JJ
+ LOGICAL GEN, HER, LOWER, SYM, TRI, UNIT, UPPER
+* .. External Functions ..
+ COMPLEX CBEG
+ EXTERNAL CBEG
+* .. Intrinsic Functions ..
+ INTRINSIC CMPLX, CONJG, REAL
+* .. Executable Statements ..
+ GEN = TYPE.EQ.'GE'
+ HER = TYPE.EQ.'HE'
+ SYM = TYPE.EQ.'SY'
+ TRI = TYPE.EQ.'TR'
+ UPPER = ( HER.OR.SYM.OR.TRI ).AND.UPLO.EQ.'U'
+ LOWER = ( HER.OR.SYM.OR.TRI ).AND.UPLO.EQ.'L'
+ UNIT = TRI.AND.DIAG.EQ.'U'
+*
+* Generate data in array A.
+*
+ DO 20 J = 1, N
+ DO 10 I = 1, M
+ IF( GEN.OR.( UPPER.AND.I.LE.J ).OR.( LOWER.AND.I.GE.J ) )
+ $ THEN
+ A( I, J ) = CBEG( RESET ) + TRANSL
+ IF( I.NE.J )THEN
+* Set some elements to zero
+ IF( N.GT.3.AND.J.EQ.N/2 )
+ $ A( I, J ) = ZERO
+ IF( HER )THEN
+ A( J, I ) = CONJG( A( I, J ) )
+ ELSE IF( SYM )THEN
+ A( J, I ) = A( I, J )
+ ELSE IF( TRI )THEN
+ A( J, I ) = ZERO
+ END IF
+ END IF
+ END IF
+ 10 CONTINUE
+ IF( HER )
+ $ A( J, J ) = CMPLX( REAL( A( J, J ) ), RZERO )
+ IF( TRI )
+ $ A( J, J ) = A( J, J ) + ONE
+ IF( UNIT )
+ $ A( J, J ) = ONE
+ 20 CONTINUE
+*
+* Store elements in array AS in data structure required by routine.
+*
+ IF( TYPE.EQ.'GE' )THEN
+ DO 50 J = 1, N
+ DO 30 I = 1, M
+ AA( I + ( J - 1 )*LDA ) = A( I, J )
+ 30 CONTINUE
+ DO 40 I = M + 1, LDA
+ AA( I + ( J - 1 )*LDA ) = ROGUE
+ 40 CONTINUE
+ 50 CONTINUE
+ ELSE IF( TYPE.EQ.'HE'.OR.TYPE.EQ.'SY'.OR.TYPE.EQ.'TR' )THEN
+ DO 90 J = 1, N
+ IF( UPPER )THEN
+ IBEG = 1
+ IF( UNIT )THEN
+ IEND = J - 1
+ ELSE
+ IEND = J
+ END IF
+ ELSE
+ IF( UNIT )THEN
+ IBEG = J + 1
+ ELSE
+ IBEG = J
+ END IF
+ IEND = N
+ END IF
+ DO 60 I = 1, IBEG - 1
+ AA( I + ( J - 1 )*LDA ) = ROGUE
+ 60 CONTINUE
+ DO 70 I = IBEG, IEND
+ AA( I + ( J - 1 )*LDA ) = A( I, J )
+ 70 CONTINUE
+ DO 80 I = IEND + 1, LDA
+ AA( I + ( J - 1 )*LDA ) = ROGUE
+ 80 CONTINUE
+ IF( HER )THEN
+ JJ = J + ( J - 1 )*LDA
+ AA( JJ ) = CMPLX( REAL( AA( JJ ) ), RROGUE )
+ END IF
+ 90 CONTINUE
+ END IF
+ RETURN
+*
+* End of CMAKE.
+*
+ END
+ SUBROUTINE CMMCH( TRANSA, TRANSB, M, N, KK, ALPHA, A, LDA, B, LDB,
+ $ BETA, C, LDC, CT, G, CC, LDCC, EPS, ERR, FATAL,
+ $ NOUT, MV )
+*
+* Checks the results of the computational tests.
+*
+* Auxiliary routine for test program for Level 3 Blas.
+*
+* -- Written on 8-February-1989.
+* Jack Dongarra, Argonne National Laboratory.
+* Iain Duff, AERE Harwell.
+* Jeremy Du Croz, Numerical Algorithms Group Ltd.
+* Sven Hammarling, Numerical Algorithms Group Ltd.
+*
+* .. Parameters ..
+ COMPLEX ZERO
+ PARAMETER ( ZERO = ( 0.0, 0.0 ) )
+ REAL RZERO, RONE
+ PARAMETER ( RZERO = 0.0, RONE = 1.0 )
+* .. Scalar Arguments ..
+ COMPLEX ALPHA, BETA
+ REAL EPS, ERR
+ INTEGER KK, LDA, LDB, LDC, LDCC, M, N, NOUT
+ LOGICAL FATAL, MV
+ CHARACTER*1 TRANSA, TRANSB
+* .. Array Arguments ..
+ COMPLEX A( LDA, * ), B( LDB, * ), C( LDC, * ),
+ $ CC( LDCC, * ), CT( * )
+ REAL G( * )
+* .. Local Scalars ..
+ COMPLEX CL
+ REAL ERRI
+ INTEGER I, J, K
+ LOGICAL CTRANA, CTRANB, TRANA, TRANB
+* .. Intrinsic Functions ..
+ INTRINSIC ABS, AIMAG, CONJG, MAX, REAL, SQRT
+* .. Statement Functions ..
+ REAL ABS1
+* .. Statement Function definitions ..
+ ABS1( CL ) = ABS( REAL( CL ) ) + ABS( AIMAG( CL ) )
+* .. Executable Statements ..
+ TRANA = TRANSA.EQ.'T'.OR.TRANSA.EQ.'C'
+ TRANB = TRANSB.EQ.'T'.OR.TRANSB.EQ.'C'
+ CTRANA = TRANSA.EQ.'C'
+ CTRANB = TRANSB.EQ.'C'
+*
+* Compute expected result, one column at a time, in CT using data
+* in A, B and C.
+* Compute gauges in G.
+*
+ DO 220 J = 1, N
+*
+ DO 10 I = 1, M
+ CT( I ) = ZERO
+ G( I ) = RZERO
+ 10 CONTINUE
+ IF( .NOT.TRANA.AND..NOT.TRANB )THEN
+ DO 30 K = 1, KK
+ DO 20 I = 1, M
+ CT( I ) = CT( I ) + A( I, K )*B( K, J )
+ G( I ) = G( I ) + ABS1( A( I, K ) )*ABS1( B( K, J ) )
+ 20 CONTINUE
+ 30 CONTINUE
+ ELSE IF( TRANA.AND..NOT.TRANB )THEN
+ IF( CTRANA )THEN
+ DO 50 K = 1, KK
+ DO 40 I = 1, M
+ CT( I ) = CT( I ) + CONJG( A( K, I ) )*B( K, J )
+ G( I ) = G( I ) + ABS1( A( K, I ) )*
+ $ ABS1( B( K, J ) )
+ 40 CONTINUE
+ 50 CONTINUE
+ ELSE
+ DO 70 K = 1, KK
+ DO 60 I = 1, M
+ CT( I ) = CT( I ) + A( K, I )*B( K, J )
+ G( I ) = G( I ) + ABS1( A( K, I ) )*
+ $ ABS1( B( K, J ) )
+ 60 CONTINUE
+ 70 CONTINUE
+ END IF
+ ELSE IF( .NOT.TRANA.AND.TRANB )THEN
+ IF( CTRANB )THEN
+ DO 90 K = 1, KK
+ DO 80 I = 1, M
+ CT( I ) = CT( I ) + A( I, K )*CONJG( B( J, K ) )
+ G( I ) = G( I ) + ABS1( A( I, K ) )*
+ $ ABS1( B( J, K ) )
+ 80 CONTINUE
+ 90 CONTINUE
+ ELSE
+ DO 110 K = 1, KK
+ DO 100 I = 1, M
+ CT( I ) = CT( I ) + A( I, K )*B( J, K )
+ G( I ) = G( I ) + ABS1( A( I, K ) )*
+ $ ABS1( B( J, K ) )
+ 100 CONTINUE
+ 110 CONTINUE
+ END IF
+ ELSE IF( TRANA.AND.TRANB )THEN
+ IF( CTRANA )THEN
+ IF( CTRANB )THEN
+ DO 130 K = 1, KK
+ DO 120 I = 1, M
+ CT( I ) = CT( I ) + CONJG( A( K, I ) )*
+ $ CONJG( B( J, K ) )
+ G( I ) = G( I ) + ABS1( A( K, I ) )*
+ $ ABS1( B( J, K ) )
+ 120 CONTINUE
+ 130 CONTINUE
+ ELSE
+ DO 150 K = 1, KK
+ DO 140 I = 1, M
+ CT( I ) = CT( I ) + CONJG( A( K, I ) )*B( J, K )
+ G( I ) = G( I ) + ABS1( A( K, I ) )*
+ $ ABS1( B( J, K ) )
+ 140 CONTINUE
+ 150 CONTINUE
+ END IF
+ ELSE
+ IF( CTRANB )THEN
+ DO 170 K = 1, KK
+ DO 160 I = 1, M
+ CT( I ) = CT( I ) + A( K, I )*CONJG( B( J, K ) )
+ G( I ) = G( I ) + ABS1( A( K, I ) )*
+ $ ABS1( B( J, K ) )
+ 160 CONTINUE
+ 170 CONTINUE
+ ELSE
+ DO 190 K = 1, KK
+ DO 180 I = 1, M
+ CT( I ) = CT( I ) + A( K, I )*B( J, K )
+ G( I ) = G( I ) + ABS1( A( K, I ) )*
+ $ ABS1( B( J, K ) )
+ 180 CONTINUE
+ 190 CONTINUE
+ END IF
+ END IF
+ END IF
+ DO 200 I = 1, M
+ CT( I ) = ALPHA*CT( I ) + BETA*C( I, J )
+ G( I ) = ABS1( ALPHA )*G( I ) +
+ $ ABS1( BETA )*ABS1( C( I, J ) )
+ 200 CONTINUE
+*
+* Compute the error ratio for this result.
+*
+ ERR = ZERO
+ DO 210 I = 1, M
+ ERRI = ABS1( CT( I ) - CC( I, J ) )/EPS
+ IF( G( I ).NE.RZERO )
+ $ ERRI = ERRI/G( I )
+ ERR = MAX( ERR, ERRI )
+ IF( ERR*SQRT( EPS ).GE.RONE )
+ $ GO TO 230
+ 210 CONTINUE
+*
+ 220 CONTINUE
+*
+* If the loop completes, all results are at least half accurate.
+ GO TO 250
+*
+* Report fatal error.
+*
+ 230 FATAL = .TRUE.
+ WRITE( NOUT, FMT = 9999 )
+ DO 240 I = 1, M
+ IF( MV )THEN
+ WRITE( NOUT, FMT = 9998 )I, CT( I ), CC( I, J )
+ ELSE
+ WRITE( NOUT, FMT = 9998 )I, CC( I, J ), CT( I )
+ END IF
+ 240 CONTINUE
+ IF( N.GT.1 )
+ $ WRITE( NOUT, FMT = 9997 )J
+*
+ 250 CONTINUE
+ RETURN
+*
+ 9999 FORMAT( ' ******* FATAL ERROR - COMPUTED RESULT IS LESS THAN HAL',
+ $ 'F ACCURATE *******', /' EXPECTED RE',
+ $ 'SULT COMPUTED RESULT' )
+ 9998 FORMAT( 1X, I7, 2( ' (', G15.6, ',', G15.6, ')' ) )
+ 9997 FORMAT( ' THESE ARE THE RESULTS FOR COLUMN ', I3 )
+*
+* End of CMMCH.
+*
+ END
+ LOGICAL FUNCTION LCE( RI, RJ, LR )
+*
+* Tests if two arrays are identical.
+*
+* Auxiliary routine for test program for Level 3 Blas.
+*
+* -- Written on 8-February-1989.
+* Jack Dongarra, Argonne National Laboratory.
+* Iain Duff, AERE Harwell.
+* Jeremy Du Croz, Numerical Algorithms Group Ltd.
+* Sven Hammarling, Numerical Algorithms Group Ltd.
+*
+* .. Scalar Arguments ..
+ INTEGER LR
+* .. Array Arguments ..
+ COMPLEX RI( * ), RJ( * )
+* .. Local Scalars ..
+ INTEGER I
+* .. Executable Statements ..
+ DO 10 I = 1, LR
+ IF( RI( I ).NE.RJ( I ) )
+ $ GO TO 20
+ 10 CONTINUE
+ LCE = .TRUE.
+ GO TO 30
+ 20 CONTINUE
+ LCE = .FALSE.
+ 30 RETURN
+*
+* End of LCE.
+*
+ END
+ LOGICAL FUNCTION LCERES( TYPE, UPLO, M, N, AA, AS, LDA )
+*
+* Tests if selected elements in two arrays are equal.
+*
+* TYPE is 'GE' or 'HE' or 'SY'.
+*
+* Auxiliary routine for test program for Level 3 Blas.
+*
+* -- Written on 8-February-1989.
+* Jack Dongarra, Argonne National Laboratory.
+* Iain Duff, AERE Harwell.
+* Jeremy Du Croz, Numerical Algorithms Group Ltd.
+* Sven Hammarling, Numerical Algorithms Group Ltd.
+*
+* .. Scalar Arguments ..
+ INTEGER LDA, M, N
+ CHARACTER*1 UPLO
+ CHARACTER*2 TYPE
+* .. Array Arguments ..
+ COMPLEX AA( LDA, * ), AS( LDA, * )
+* .. Local Scalars ..
+ INTEGER I, IBEG, IEND, J
+ LOGICAL UPPER
+* .. Executable Statements ..
+ UPPER = UPLO.EQ.'U'
+ IF( TYPE.EQ.'GE' )THEN
+ DO 20 J = 1, N
+ DO 10 I = M + 1, LDA
+ IF( AA( I, J ).NE.AS( I, J ) )
+ $ GO TO 70
+ 10 CONTINUE
+ 20 CONTINUE
+ ELSE IF( TYPE.EQ.'HE'.OR.TYPE.EQ.'SY' )THEN
+ DO 50 J = 1, N
+ IF( UPPER )THEN
+ IBEG = 1
+ IEND = J
+ ELSE
+ IBEG = J
+ IEND = N
+ END IF
+ DO 30 I = 1, IBEG - 1
+ IF( AA( I, J ).NE.AS( I, J ) )
+ $ GO TO 70
+ 30 CONTINUE
+ DO 40 I = IEND + 1, LDA
+ IF( AA( I, J ).NE.AS( I, J ) )
+ $ GO TO 70
+ 40 CONTINUE
+ 50 CONTINUE
+ END IF
+*
+ 60 CONTINUE
+ LCERES = .TRUE.
+ GO TO 80
+ 70 CONTINUE
+ LCERES = .FALSE.
+ 80 RETURN
+*
+* End of LCERES.
+*
+ END
+ COMPLEX FUNCTION CBEG( RESET )
+*
+* Generates complex numbers as pairs of random numbers uniformly
+* distributed between -0.5 and 0.5.
+*
+* Auxiliary routine for test program for Level 3 Blas.
+*
+* -- Written on 8-February-1989.
+* Jack Dongarra, Argonne National Laboratory.
+* Iain Duff, AERE Harwell.
+* Jeremy Du Croz, Numerical Algorithms Group Ltd.
+* Sven Hammarling, Numerical Algorithms Group Ltd.
+*
+* .. Scalar Arguments ..
+ LOGICAL RESET
+* .. Local Scalars ..
+ INTEGER I, IC, J, MI, MJ
+* .. Save statement ..
+ SAVE I, IC, J, MI, MJ
+* .. Intrinsic Functions ..
+ INTRINSIC CMPLX
+* .. Executable Statements ..
+ IF( RESET )THEN
+* Initialize local variables.
+ MI = 891
+ MJ = 457
+ I = 7
+ J = 7
+ IC = 0
+ RESET = .FALSE.
+ END IF
+*
+* The sequence of values of I or J is bounded between 1 and 999.
+* If initial I or J = 1,2,3,6,7 or 9, the period will be 50.
+* If initial I or J = 4 or 8, the period will be 25.
+* If initial I or J = 5, the period will be 10.
+* IC is used to break up the period by skipping 1 value of I or J
+* in 6.
+*
+ IC = IC + 1
+ 10 I = I*MI
+ J = J*MJ
+ I = I - 1000*( I/1000 )
+ J = J - 1000*( J/1000 )
+ IF( IC.GE.5 )THEN
+ IC = 0
+ GO TO 10
+ END IF
+ CBEG = CMPLX( ( I - 500 )/1001.0, ( J - 500 )/1001.0 )
+ RETURN
+*
+* End of CBEG.
+*
+ END
+ REAL FUNCTION SDIFF( X, Y )
+*
+* Auxiliary routine for test program for Level 3 Blas.
+*
+* -- Written on 8-February-1989.
+* Jack Dongarra, Argonne National Laboratory.
+* Iain Duff, AERE Harwell.
+* Jeremy Du Croz, Numerical Algorithms Group Ltd.
+* Sven Hammarling, Numerical Algorithms Group Ltd.
+*
+* .. Scalar Arguments ..
+ REAL X, Y
+* .. Executable Statements ..
+ SDIFF = X - Y
+ RETURN
+*
+* End of SDIFF.
+*
+ END
+ SUBROUTINE CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+*
+* Tests whether XERBLA has detected an error when it should.
+*
+* Auxiliary routine for test program for Level 3 Blas.
+*
+* -- Written on 8-February-1989.
+* Jack Dongarra, Argonne National Laboratory.
+* Iain Duff, AERE Harwell.
+* Jeremy Du Croz, Numerical Algorithms Group Ltd.
+* Sven Hammarling, Numerical Algorithms Group Ltd.
+*
+* .. Scalar Arguments ..
+ INTEGER INFOT, NOUT
+ LOGICAL LERR, OK
+ CHARACTER*6 SRNAMT
+* .. Executable Statements ..
+ IF( .NOT.LERR )THEN
+ WRITE( NOUT, FMT = 9999 )INFOT, SRNAMT
+ OK = .FALSE.
+ END IF
+ LERR = .FALSE.
+ RETURN
+*
+ 9999 FORMAT( ' ***** ILLEGAL VALUE OF PARAMETER NUMBER ', I2, ' NOT D',
+ $ 'ETECTED BY ', A6, ' *****' )
+*
+* End of CHKXER.
+*
+ END
+ SUBROUTINE XERBLA( SRNAME, INFO )
+*
+* This is a special version of XERBLA to be used only as part of
+* the test program for testing error exits from the Level 3 BLAS
+* routines.
+*
+* XERBLA is an error handler for the Level 3 BLAS routines.
+*
+* It is called by the Level 3 BLAS routines if an input parameter is
+* invalid.
+*
+* Auxiliary routine for test program for Level 3 Blas.
+*
+* -- Written on 8-February-1989.
+* Jack Dongarra, Argonne National Laboratory.
+* Iain Duff, AERE Harwell.
+* Jeremy Du Croz, Numerical Algorithms Group Ltd.
+* Sven Hammarling, Numerical Algorithms Group Ltd.
+*
+* .. Scalar Arguments ..
+ INTEGER INFO
+ CHARACTER*6 SRNAME
+* .. Scalars in Common ..
+ INTEGER INFOT, NOUT
+ LOGICAL LERR, OK
+ CHARACTER*6 SRNAMT
+* .. Common blocks ..
+ COMMON /INFOC/INFOT, NOUT, OK, LERR
+ COMMON /SRNAMC/SRNAMT
+* .. Executable Statements ..
+ LERR = .TRUE.
+ IF( INFO.NE.INFOT )THEN
+ IF( INFOT.NE.0 )THEN
+ WRITE( NOUT, FMT = 9999 )INFO, INFOT
+ ELSE
+ WRITE( NOUT, FMT = 9997 )INFO
+ END IF
+ OK = .FALSE.
+ END IF
+ IF( SRNAME.NE.SRNAMT )THEN
+ WRITE( NOUT, FMT = 9998 )SRNAME, SRNAMT
+ OK = .FALSE.
+ END IF
+ RETURN
+*
+ 9999 FORMAT( ' ******* XERBLA WAS CALLED WITH INFO = ', I6, ' INSTEAD',
+ $ ' OF ', I2, ' *******' )
+ 9998 FORMAT( ' ******* XERBLA WAS CALLED WITH SRNAME = ', A6, ' INSTE',
+ $ 'AD OF ', A6, ' *******' )
+ 9997 FORMAT( ' ******* XERBLA WAS CALLED WITH INFO = ', I6,
+ $ ' *******' )
+*
+* End of XERBLA
+*
+ END
+
diff --git a/blas/testing/dblat1.f b/blas/testing/dblat1.f
new file mode 100644
index 000000000..5a45d69f4
--- /dev/null
+++ b/blas/testing/dblat1.f
@@ -0,0 +1,769 @@
+ PROGRAM DBLAT1
+* Test program for the DOUBLE PRECISION Level 1 BLAS.
+* Based upon the original BLAS test routine together with:
+* F06EAF Example Program Text
+* .. Parameters ..
+ INTEGER NOUT
+ PARAMETER (NOUT=6)
+* .. Scalars in Common ..
+ INTEGER ICASE, INCX, INCY, MODE, N
+ LOGICAL PASS
+* .. Local Scalars ..
+ DOUBLE PRECISION SFAC
+ INTEGER IC
+* .. External Subroutines ..
+ EXTERNAL CHECK0, CHECK1, CHECK2, CHECK3, HEADER
+* .. Common blocks ..
+ COMMON /COMBLA/ICASE, N, INCX, INCY, MODE, PASS
+* .. Data statements ..
+ DATA SFAC/9.765625D-4/
+* .. Executable Statements ..
+ WRITE (NOUT,99999)
+ DO 20 IC = 1, 10
+ ICASE = IC
+ CALL HEADER
+*
+* .. Initialize PASS, INCX, INCY, and MODE for a new case. ..
+* .. the value 9999 for INCX, INCY or MODE will appear in the ..
+* .. detailed output, if any, for cases that do not involve ..
+* .. these parameters ..
+*
+ PASS = .TRUE.
+ INCX = 9999
+ INCY = 9999
+ MODE = 9999
+ IF (ICASE.EQ.3) THEN
+ CALL CHECK0(SFAC)
+ ELSE IF (ICASE.EQ.7 .OR. ICASE.EQ.8 .OR. ICASE.EQ.9 .OR.
+ + ICASE.EQ.10) THEN
+ CALL CHECK1(SFAC)
+ ELSE IF (ICASE.EQ.1 .OR. ICASE.EQ.2 .OR. ICASE.EQ.5 .OR.
+ + ICASE.EQ.6) THEN
+ CALL CHECK2(SFAC)
+ ELSE IF (ICASE.EQ.4) THEN
+ CALL CHECK3(SFAC)
+ END IF
+* -- Print
+ IF (PASS) WRITE (NOUT,99998)
+ 20 CONTINUE
+ STOP
+*
+99999 FORMAT (' Real BLAS Test Program Results',/1X)
+99998 FORMAT (' ----- PASS -----')
+ END
+ SUBROUTINE HEADER
+* .. Parameters ..
+ INTEGER NOUT
+ PARAMETER (NOUT=6)
+* .. Scalars in Common ..
+ INTEGER ICASE, INCX, INCY, MODE, N
+ LOGICAL PASS
+* .. Local Arrays ..
+ CHARACTER*6 L(10)
+* .. Common blocks ..
+ COMMON /COMBLA/ICASE, N, INCX, INCY, MODE, PASS
+* .. Data statements ..
+ DATA L(1)/' DDOT '/
+ DATA L(2)/'DAXPY '/
+ DATA L(3)/'DROTG '/
+ DATA L(4)/' DROT '/
+ DATA L(5)/'DCOPY '/
+ DATA L(6)/'DSWAP '/
+ DATA L(7)/'DNRM2 '/
+ DATA L(8)/'DASUM '/
+ DATA L(9)/'DSCAL '/
+ DATA L(10)/'IDAMAX'/
+* .. Executable Statements ..
+ WRITE (NOUT,99999) ICASE, L(ICASE)
+ RETURN
+*
+99999 FORMAT (/' Test of subprogram number',I3,12X,A6)
+ END
+ SUBROUTINE CHECK0(SFAC)
+* .. Parameters ..
+ INTEGER NOUT
+ PARAMETER (NOUT=6)
+* .. Scalar Arguments ..
+ DOUBLE PRECISION SFAC
+* .. Scalars in Common ..
+ INTEGER ICASE, INCX, INCY, MODE, N
+ LOGICAL PASS
+* .. Local Scalars ..
+ DOUBLE PRECISION D12, SA, SB, SC, SS
+ INTEGER K
+* .. Local Arrays ..
+ DOUBLE PRECISION DA1(8), DATRUE(8), DB1(8), DBTRUE(8), DC1(8),
+ + DS1(8)
+* .. External Subroutines ..
+ EXTERNAL DROTG, STEST1
+* .. Common blocks ..
+ COMMON /COMBLA/ICASE, N, INCX, INCY, MODE, PASS
+* .. Data statements ..
+ DATA DA1/0.3D0, 0.4D0, -0.3D0, -0.4D0, -0.3D0, 0.0D0,
+ + 0.0D0, 1.0D0/
+ DATA DB1/0.4D0, 0.3D0, 0.4D0, 0.3D0, -0.4D0, 0.0D0,
+ + 1.0D0, 0.0D0/
+ DATA DC1/0.6D0, 0.8D0, -0.6D0, 0.8D0, 0.6D0, 1.0D0,
+ + 0.0D0, 1.0D0/
+ DATA DS1/0.8D0, 0.6D0, 0.8D0, -0.6D0, 0.8D0, 0.0D0,
+ + 1.0D0, 0.0D0/
+ DATA DATRUE/0.5D0, 0.5D0, 0.5D0, -0.5D0, -0.5D0,
+ + 0.0D0, 1.0D0, 1.0D0/
+ DATA DBTRUE/0.0D0, 0.6D0, 0.0D0, -0.6D0, 0.0D0,
+ + 0.0D0, 1.0D0, 0.0D0/
+ DATA D12/4096.0D0/
+* .. Executable Statements ..
+*
+* Compute true values which cannot be prestored
+* in decimal notation
+*
+ DBTRUE(1) = 1.0D0/0.6D0
+ DBTRUE(3) = -1.0D0/0.6D0
+ DBTRUE(5) = 1.0D0/0.6D0
+*
+ DO 20 K = 1, 8
+* .. Set N=K for identification in output if any ..
+ N = K
+ IF (ICASE.EQ.3) THEN
+* .. DROTG ..
+ IF (K.GT.8) GO TO 40
+ SA = DA1(K)
+ SB = DB1(K)
+ CALL DROTG(SA,SB,SC,SS)
+ CALL STEST1(SA,DATRUE(K),DATRUE(K),SFAC)
+ CALL STEST1(SB,DBTRUE(K),DBTRUE(K),SFAC)
+ CALL STEST1(SC,DC1(K),DC1(K),SFAC)
+ CALL STEST1(SS,DS1(K),DS1(K),SFAC)
+ ELSE
+ WRITE (NOUT,*) ' Shouldn''t be here in CHECK0'
+ STOP
+ END IF
+ 20 CONTINUE
+ 40 RETURN
+ END
+ SUBROUTINE CHECK1(SFAC)
+* .. Parameters ..
+ INTEGER NOUT
+ PARAMETER (NOUT=6)
+* .. Scalar Arguments ..
+ DOUBLE PRECISION SFAC
+* .. Scalars in Common ..
+ INTEGER ICASE, INCX, INCY, MODE, N
+ LOGICAL PASS
+* .. Local Scalars ..
+ INTEGER I, LEN, NP1
+* .. Local Arrays ..
+ DOUBLE PRECISION DTRUE1(5), DTRUE3(5), DTRUE5(8,5,2), DV(8,5,2),
+ + SA(10), STEMP(1), STRUE(8), SX(8)
+ INTEGER ITRUE2(5)
+* .. External Functions ..
+ DOUBLE PRECISION DASUM, DNRM2
+ INTEGER IDAMAX
+ EXTERNAL DASUM, DNRM2, IDAMAX
+* .. External Subroutines ..
+ EXTERNAL ITEST1, DSCAL, STEST, STEST1
+* .. Intrinsic Functions ..
+ INTRINSIC MAX
+* .. Common blocks ..
+ COMMON /COMBLA/ICASE, N, INCX, INCY, MODE, PASS
+* .. Data statements ..
+ DATA SA/0.3D0, -1.0D0, 0.0D0, 1.0D0, 0.3D0, 0.3D0,
+ + 0.3D0, 0.3D0, 0.3D0, 0.3D0/
+ DATA DV/0.1D0, 2.0D0, 2.0D0, 2.0D0, 2.0D0, 2.0D0,
+ + 2.0D0, 2.0D0, 0.3D0, 3.0D0, 3.0D0, 3.0D0, 3.0D0,
+ + 3.0D0, 3.0D0, 3.0D0, 0.3D0, -0.4D0, 4.0D0,
+ + 4.0D0, 4.0D0, 4.0D0, 4.0D0, 4.0D0, 0.2D0,
+ + -0.6D0, 0.3D0, 5.0D0, 5.0D0, 5.0D0, 5.0D0,
+ + 5.0D0, 0.1D0, -0.3D0, 0.5D0, -0.1D0, 6.0D0,
+ + 6.0D0, 6.0D0, 6.0D0, 0.1D0, 8.0D0, 8.0D0, 8.0D0,
+ + 8.0D0, 8.0D0, 8.0D0, 8.0D0, 0.3D0, 9.0D0, 9.0D0,
+ + 9.0D0, 9.0D0, 9.0D0, 9.0D0, 9.0D0, 0.3D0, 2.0D0,
+ + -0.4D0, 2.0D0, 2.0D0, 2.0D0, 2.0D0, 2.0D0,
+ + 0.2D0, 3.0D0, -0.6D0, 5.0D0, 0.3D0, 2.0D0,
+ + 2.0D0, 2.0D0, 0.1D0, 4.0D0, -0.3D0, 6.0D0,
+ + -0.5D0, 7.0D0, -0.1D0, 3.0D0/
+ DATA DTRUE1/0.0D0, 0.3D0, 0.5D0, 0.7D0, 0.6D0/
+ DATA DTRUE3/0.0D0, 0.3D0, 0.7D0, 1.1D0, 1.0D0/
+ DATA DTRUE5/0.10D0, 2.0D0, 2.0D0, 2.0D0, 2.0D0,
+ + 2.0D0, 2.0D0, 2.0D0, -0.3D0, 3.0D0, 3.0D0,
+ + 3.0D0, 3.0D0, 3.0D0, 3.0D0, 3.0D0, 0.0D0, 0.0D0,
+ + 4.0D0, 4.0D0, 4.0D0, 4.0D0, 4.0D0, 4.0D0,
+ + 0.20D0, -0.60D0, 0.30D0, 5.0D0, 5.0D0, 5.0D0,
+ + 5.0D0, 5.0D0, 0.03D0, -0.09D0, 0.15D0, -0.03D0,
+ + 6.0D0, 6.0D0, 6.0D0, 6.0D0, 0.10D0, 8.0D0,
+ + 8.0D0, 8.0D0, 8.0D0, 8.0D0, 8.0D0, 8.0D0,
+ + 0.09D0, 9.0D0, 9.0D0, 9.0D0, 9.0D0, 9.0D0,
+ + 9.0D0, 9.0D0, 0.09D0, 2.0D0, -0.12D0, 2.0D0,
+ + 2.0D0, 2.0D0, 2.0D0, 2.0D0, 0.06D0, 3.0D0,
+ + -0.18D0, 5.0D0, 0.09D0, 2.0D0, 2.0D0, 2.0D0,
+ + 0.03D0, 4.0D0, -0.09D0, 6.0D0, -0.15D0, 7.0D0,
+ + -0.03D0, 3.0D0/
+ DATA ITRUE2/0, 1, 2, 2, 3/
+* .. Executable Statements ..
+ DO 80 INCX = 1, 2
+ DO 60 NP1 = 1, 5
+ N = NP1 - 1
+ LEN = 2*MAX(N,1)
+* .. Set vector arguments ..
+ DO 20 I = 1, LEN
+ SX(I) = DV(I,NP1,INCX)
+ 20 CONTINUE
+*
+ IF (ICASE.EQ.7) THEN
+* .. DNRM2 ..
+ STEMP(1) = DTRUE1(NP1)
+ CALL STEST1(DNRM2(N,SX,INCX),STEMP,STEMP,SFAC)
+ ELSE IF (ICASE.EQ.8) THEN
+* .. DASUM ..
+ STEMP(1) = DTRUE3(NP1)
+ CALL STEST1(DASUM(N,SX,INCX),STEMP,STEMP,SFAC)
+ ELSE IF (ICASE.EQ.9) THEN
+* .. DSCAL ..
+ CALL DSCAL(N,SA((INCX-1)*5+NP1),SX,INCX)
+ DO 40 I = 1, LEN
+ STRUE(I) = DTRUE5(I,NP1,INCX)
+ 40 CONTINUE
+ CALL STEST(LEN,SX,STRUE,STRUE,SFAC)
+ ELSE IF (ICASE.EQ.10) THEN
+* .. IDAMAX ..
+ CALL ITEST1(IDAMAX(N,SX,INCX),ITRUE2(NP1))
+ ELSE
+ WRITE (NOUT,*) ' Shouldn''t be here in CHECK1'
+ STOP
+ END IF
+ 60 CONTINUE
+ 80 CONTINUE
+ RETURN
+ END
+ SUBROUTINE CHECK2(SFAC)
+* .. Parameters ..
+ INTEGER NOUT
+ PARAMETER (NOUT=6)
+* .. Scalar Arguments ..
+ DOUBLE PRECISION SFAC
+* .. Scalars in Common ..
+ INTEGER ICASE, INCX, INCY, MODE, N
+ LOGICAL PASS
+* .. Local Scalars ..
+ DOUBLE PRECISION SA, SC, SS
+ INTEGER I, J, KI, KN, KSIZE, LENX, LENY, MX, MY
+* .. Local Arrays ..
+ DOUBLE PRECISION DT10X(7,4,4), DT10Y(7,4,4), DT7(4,4),
+ + DT8(7,4,4), DT9X(7,4,4), DT9Y(7,4,4), DX1(7),
+ + DY1(7), SSIZE1(4), SSIZE2(14,2), STX(7), STY(7),
+ + SX(7), SY(7)
+ INTEGER INCXS(4), INCYS(4), LENS(4,2), NS(4)
+* .. External Functions ..
+ DOUBLE PRECISION DDOT
+ EXTERNAL DDOT
+* .. External Subroutines ..
+ EXTERNAL DAXPY, DCOPY, DSWAP, STEST, STEST1
+* .. Intrinsic Functions ..
+ INTRINSIC ABS, MIN
+* .. Common blocks ..
+ COMMON /COMBLA/ICASE, N, INCX, INCY, MODE, PASS
+* .. Data statements ..
+ DATA SA/0.3D0/
+ DATA INCXS/1, 2, -2, -1/
+ DATA INCYS/1, -2, 1, -2/
+ DATA LENS/1, 1, 2, 4, 1, 1, 3, 7/
+ DATA NS/0, 1, 2, 4/
+ DATA DX1/0.6D0, 0.1D0, -0.5D0, 0.8D0, 0.9D0, -0.3D0,
+ + -0.4D0/
+ DATA DY1/0.5D0, -0.9D0, 0.3D0, 0.7D0, -0.6D0, 0.2D0,
+ + 0.8D0/
+ DATA SC, SS/0.8D0, 0.6D0/
+ DATA DT7/0.0D0, 0.30D0, 0.21D0, 0.62D0, 0.0D0,
+ + 0.30D0, -0.07D0, 0.85D0, 0.0D0, 0.30D0, -0.79D0,
+ + -0.74D0, 0.0D0, 0.30D0, 0.33D0, 1.27D0/
+ DATA DT8/0.5D0, 0.0D0, 0.0D0, 0.0D0, 0.0D0, 0.0D0,
+ + 0.0D0, 0.68D0, 0.0D0, 0.0D0, 0.0D0, 0.0D0,
+ + 0.0D0, 0.0D0, 0.68D0, -0.87D0, 0.0D0, 0.0D0,
+ + 0.0D0, 0.0D0, 0.0D0, 0.68D0, -0.87D0, 0.15D0,
+ + 0.94D0, 0.0D0, 0.0D0, 0.0D0, 0.5D0, 0.0D0,
+ + 0.0D0, 0.0D0, 0.0D0, 0.0D0, 0.0D0, 0.68D0,
+ + 0.0D0, 0.0D0, 0.0D0, 0.0D0, 0.0D0, 0.0D0,
+ + 0.35D0, -0.9D0, 0.48D0, 0.0D0, 0.0D0, 0.0D0,
+ + 0.0D0, 0.38D0, -0.9D0, 0.57D0, 0.7D0, -0.75D0,
+ + 0.2D0, 0.98D0, 0.5D0, 0.0D0, 0.0D0, 0.0D0,
+ + 0.0D0, 0.0D0, 0.0D0, 0.68D0, 0.0D0, 0.0D0,
+ + 0.0D0, 0.0D0, 0.0D0, 0.0D0, 0.35D0, -0.72D0,
+ + 0.0D0, 0.0D0, 0.0D0, 0.0D0, 0.0D0, 0.38D0,
+ + -0.63D0, 0.15D0, 0.88D0, 0.0D0, 0.0D0, 0.0D0,
+ + 0.5D0, 0.0D0, 0.0D0, 0.0D0, 0.0D0, 0.0D0, 0.0D0,
+ + 0.68D0, 0.0D0, 0.0D0, 0.0D0, 0.0D0, 0.0D0,
+ + 0.0D0, 0.68D0, -0.9D0, 0.33D0, 0.0D0, 0.0D0,
+ + 0.0D0, 0.0D0, 0.68D0, -0.9D0, 0.33D0, 0.7D0,
+ + -0.75D0, 0.2D0, 1.04D0/
+ DATA DT9X/0.6D0, 0.0D0, 0.0D0, 0.0D0, 0.0D0, 0.0D0,
+ + 0.0D0, 0.78D0, 0.0D0, 0.0D0, 0.0D0, 0.0D0,
+ + 0.0D0, 0.0D0, 0.78D0, -0.46D0, 0.0D0, 0.0D0,
+ + 0.0D0, 0.0D0, 0.0D0, 0.78D0, -0.46D0, -0.22D0,
+ + 1.06D0, 0.0D0, 0.0D0, 0.0D0, 0.6D0, 0.0D0,
+ + 0.0D0, 0.0D0, 0.0D0, 0.0D0, 0.0D0, 0.78D0,
+ + 0.0D0, 0.0D0, 0.0D0, 0.0D0, 0.0D0, 0.0D0,
+ + 0.66D0, 0.1D0, -0.1D0, 0.0D0, 0.0D0, 0.0D0,
+ + 0.0D0, 0.96D0, 0.1D0, -0.76D0, 0.8D0, 0.90D0,
+ + -0.3D0, -0.02D0, 0.6D0, 0.0D0, 0.0D0, 0.0D0,
+ + 0.0D0, 0.0D0, 0.0D0, 0.78D0, 0.0D0, 0.0D0,
+ + 0.0D0, 0.0D0, 0.0D0, 0.0D0, -0.06D0, 0.1D0,
+ + -0.1D0, 0.0D0, 0.0D0, 0.0D0, 0.0D0, 0.90D0,
+ + 0.1D0, -0.22D0, 0.8D0, 0.18D0, -0.3D0, -0.02D0,
+ + 0.6D0, 0.0D0, 0.0D0, 0.0D0, 0.0D0, 0.0D0, 0.0D0,
+ + 0.78D0, 0.0D0, 0.0D0, 0.0D0, 0.0D0, 0.0D0,
+ + 0.0D0, 0.78D0, 0.26D0, 0.0D0, 0.0D0, 0.0D0,
+ + 0.0D0, 0.0D0, 0.78D0, 0.26D0, -0.76D0, 1.12D0,
+ + 0.0D0, 0.0D0, 0.0D0/
+ DATA DT9Y/0.5D0, 0.0D0, 0.0D0, 0.0D0, 0.0D0, 0.0D0,
+ + 0.0D0, 0.04D0, 0.0D0, 0.0D0, 0.0D0, 0.0D0,
+ + 0.0D0, 0.0D0, 0.04D0, -0.78D0, 0.0D0, 0.0D0,
+ + 0.0D0, 0.0D0, 0.0D0, 0.04D0, -0.78D0, 0.54D0,
+ + 0.08D0, 0.0D0, 0.0D0, 0.0D0, 0.5D0, 0.0D0,
+ + 0.0D0, 0.0D0, 0.0D0, 0.0D0, 0.0D0, 0.04D0,
+ + 0.0D0, 0.0D0, 0.0D0, 0.0D0, 0.0D0, 0.0D0, 0.7D0,
+ + -0.9D0, -0.12D0, 0.0D0, 0.0D0, 0.0D0, 0.0D0,
+ + 0.64D0, -0.9D0, -0.30D0, 0.7D0, -0.18D0, 0.2D0,
+ + 0.28D0, 0.5D0, 0.0D0, 0.0D0, 0.0D0, 0.0D0,
+ + 0.0D0, 0.0D0, 0.04D0, 0.0D0, 0.0D0, 0.0D0,
+ + 0.0D0, 0.0D0, 0.0D0, 0.7D0, -1.08D0, 0.0D0,
+ + 0.0D0, 0.0D0, 0.0D0, 0.0D0, 0.64D0, -1.26D0,
+ + 0.54D0, 0.20D0, 0.0D0, 0.0D0, 0.0D0, 0.5D0,
+ + 0.0D0, 0.0D0, 0.0D0, 0.0D0, 0.0D0, 0.0D0,
+ + 0.04D0, 0.0D0, 0.0D0, 0.0D0, 0.0D0, 0.0D0,
+ + 0.0D0, 0.04D0, -0.9D0, 0.18D0, 0.0D0, 0.0D0,
+ + 0.0D0, 0.0D0, 0.04D0, -0.9D0, 0.18D0, 0.7D0,
+ + -0.18D0, 0.2D0, 0.16D0/
+ DATA DT10X/0.6D0, 0.0D0, 0.0D0, 0.0D0, 0.0D0, 0.0D0,
+ + 0.0D0, 0.5D0, 0.0D0, 0.0D0, 0.0D0, 0.0D0, 0.0D0,
+ + 0.0D0, 0.5D0, -0.9D0, 0.0D0, 0.0D0, 0.0D0,
+ + 0.0D0, 0.0D0, 0.5D0, -0.9D0, 0.3D0, 0.7D0,
+ + 0.0D0, 0.0D0, 0.0D0, 0.6D0, 0.0D0, 0.0D0, 0.0D0,
+ + 0.0D0, 0.0D0, 0.0D0, 0.5D0, 0.0D0, 0.0D0, 0.0D0,
+ + 0.0D0, 0.0D0, 0.0D0, 0.3D0, 0.1D0, 0.5D0, 0.0D0,
+ + 0.0D0, 0.0D0, 0.0D0, 0.8D0, 0.1D0, -0.6D0,
+ + 0.8D0, 0.3D0, -0.3D0, 0.5D0, 0.6D0, 0.0D0,
+ + 0.0D0, 0.0D0, 0.0D0, 0.0D0, 0.0D0, 0.5D0, 0.0D0,
+ + 0.0D0, 0.0D0, 0.0D0, 0.0D0, 0.0D0, -0.9D0,
+ + 0.1D0, 0.5D0, 0.0D0, 0.0D0, 0.0D0, 0.0D0, 0.7D0,
+ + 0.1D0, 0.3D0, 0.8D0, -0.9D0, -0.3D0, 0.5D0,
+ + 0.6D0, 0.0D0, 0.0D0, 0.0D0, 0.0D0, 0.0D0, 0.0D0,
+ + 0.5D0, 0.0D0, 0.0D0, 0.0D0, 0.0D0, 0.0D0, 0.0D0,
+ + 0.5D0, 0.3D0, 0.0D0, 0.0D0, 0.0D0, 0.0D0, 0.0D0,
+ + 0.5D0, 0.3D0, -0.6D0, 0.8D0, 0.0D0, 0.0D0,
+ + 0.0D0/
+ DATA DT10Y/0.5D0, 0.0D0, 0.0D0, 0.0D0, 0.0D0, 0.0D0,
+ + 0.0D0, 0.6D0, 0.0D0, 0.0D0, 0.0D0, 0.0D0, 0.0D0,
+ + 0.0D0, 0.6D0, 0.1D0, 0.0D0, 0.0D0, 0.0D0, 0.0D0,
+ + 0.0D0, 0.6D0, 0.1D0, -0.5D0, 0.8D0, 0.0D0,
+ + 0.0D0, 0.0D0, 0.5D0, 0.0D0, 0.0D0, 0.0D0, 0.0D0,
+ + 0.0D0, 0.0D0, 0.6D0, 0.0D0, 0.0D0, 0.0D0, 0.0D0,
+ + 0.0D0, 0.0D0, -0.5D0, -0.9D0, 0.6D0, 0.0D0,
+ + 0.0D0, 0.0D0, 0.0D0, -0.4D0, -0.9D0, 0.9D0,
+ + 0.7D0, -0.5D0, 0.2D0, 0.6D0, 0.5D0, 0.0D0,
+ + 0.0D0, 0.0D0, 0.0D0, 0.0D0, 0.0D0, 0.6D0, 0.0D0,
+ + 0.0D0, 0.0D0, 0.0D0, 0.0D0, 0.0D0, -0.5D0,
+ + 0.6D0, 0.0D0, 0.0D0, 0.0D0, 0.0D0, 0.0D0,
+ + -0.4D0, 0.9D0, -0.5D0, 0.6D0, 0.0D0, 0.0D0,
+ + 0.0D0, 0.5D0, 0.0D0, 0.0D0, 0.0D0, 0.0D0, 0.0D0,
+ + 0.0D0, 0.6D0, 0.0D0, 0.0D0, 0.0D0, 0.0D0, 0.0D0,
+ + 0.0D0, 0.6D0, -0.9D0, 0.1D0, 0.0D0, 0.0D0,
+ + 0.0D0, 0.0D0, 0.6D0, -0.9D0, 0.1D0, 0.7D0,
+ + -0.5D0, 0.2D0, 0.8D0/
+ DATA SSIZE1/0.0D0, 0.3D0, 1.6D0, 3.2D0/
+ DATA SSIZE2/0.0D0, 0.0D0, 0.0D0, 0.0D0, 0.0D0, 0.0D0,
+ + 0.0D0, 0.0D0, 0.0D0, 0.0D0, 0.0D0, 0.0D0, 0.0D0,
+ + 0.0D0, 1.17D0, 1.17D0, 1.17D0, 1.17D0, 1.17D0,
+ + 1.17D0, 1.17D0, 1.17D0, 1.17D0, 1.17D0, 1.17D0,
+ + 1.17D0, 1.17D0, 1.17D0/
+* .. Executable Statements ..
+*
+ DO 120 KI = 1, 4
+ INCX = INCXS(KI)
+ INCY = INCYS(KI)
+ MX = ABS(INCX)
+ MY = ABS(INCY)
+*
+ DO 100 KN = 1, 4
+ N = NS(KN)
+ KSIZE = MIN(2,KN)
+ LENX = LENS(KN,MX)
+ LENY = LENS(KN,MY)
+* .. Initialize all argument arrays ..
+ DO 20 I = 1, 7
+ SX(I) = DX1(I)
+ SY(I) = DY1(I)
+ 20 CONTINUE
+*
+ IF (ICASE.EQ.1) THEN
+* .. DDOT ..
+ CALL STEST1(DDOT(N,SX,INCX,SY,INCY),DT7(KN,KI),SSIZE1(KN)
+ + ,SFAC)
+ ELSE IF (ICASE.EQ.2) THEN
+* .. DAXPY ..
+ CALL DAXPY(N,SA,SX,INCX,SY,INCY)
+ DO 40 J = 1, LENY
+ STY(J) = DT8(J,KN,KI)
+ 40 CONTINUE
+ CALL STEST(LENY,SY,STY,SSIZE2(1,KSIZE),SFAC)
+ ELSE IF (ICASE.EQ.5) THEN
+* .. DCOPY ..
+ DO 60 I = 1, 7
+ STY(I) = DT10Y(I,KN,KI)
+ 60 CONTINUE
+ CALL DCOPY(N,SX,INCX,SY,INCY)
+ CALL STEST(LENY,SY,STY,SSIZE2(1,1),1.0D0)
+ ELSE IF (ICASE.EQ.6) THEN
+* .. DSWAP ..
+ CALL DSWAP(N,SX,INCX,SY,INCY)
+ DO 80 I = 1, 7
+ STX(I) = DT10X(I,KN,KI)
+ STY(I) = DT10Y(I,KN,KI)
+ 80 CONTINUE
+ CALL STEST(LENX,SX,STX,SSIZE2(1,1),1.0D0)
+ CALL STEST(LENY,SY,STY,SSIZE2(1,1),1.0D0)
+ ELSE
+ WRITE (NOUT,*) ' Shouldn''t be here in CHECK2'
+ STOP
+ END IF
+ 100 CONTINUE
+ 120 CONTINUE
+ RETURN
+ END
+ SUBROUTINE CHECK3(SFAC)
+* .. Parameters ..
+ INTEGER NOUT
+ PARAMETER (NOUT=6)
+* .. Scalar Arguments ..
+ DOUBLE PRECISION SFAC
+* .. Scalars in Common ..
+ INTEGER ICASE, INCX, INCY, MODE, N
+ LOGICAL PASS
+* .. Local Scalars ..
+ DOUBLE PRECISION SA, SC, SS
+ INTEGER I, K, KI, KN, KSIZE, LENX, LENY, MX, MY
+* .. Local Arrays ..
+ DOUBLE PRECISION COPYX(5), COPYY(5), DT9X(7,4,4), DT9Y(7,4,4),
+ + DX1(7), DY1(7), MWPC(11), MWPS(11), MWPSTX(5),
+ + MWPSTY(5), MWPTX(11,5), MWPTY(11,5), MWPX(5),
+ + MWPY(5), SSIZE2(14,2), STX(7), STY(7), SX(7),
+ + SY(7)
+ INTEGER INCXS(4), INCYS(4), LENS(4,2), MWPINX(11),
+ + MWPINY(11), MWPN(11), NS(4)
+* .. External Subroutines ..
+ EXTERNAL DROT, STEST
+* .. Intrinsic Functions ..
+ INTRINSIC ABS, MIN
+* .. Common blocks ..
+ COMMON /COMBLA/ICASE, N, INCX, INCY, MODE, PASS
+* .. Data statements ..
+ DATA SA/0.3D0/
+ DATA INCXS/1, 2, -2, -1/
+ DATA INCYS/1, -2, 1, -2/
+ DATA LENS/1, 1, 2, 4, 1, 1, 3, 7/
+ DATA NS/0, 1, 2, 4/
+ DATA DX1/0.6D0, 0.1D0, -0.5D0, 0.8D0, 0.9D0, -0.3D0,
+ + -0.4D0/
+ DATA DY1/0.5D0, -0.9D0, 0.3D0, 0.7D0, -0.6D0, 0.2D0,
+ + 0.8D0/
+ DATA SC, SS/0.8D0, 0.6D0/
+ DATA DT9X/0.6D0, 0.0D0, 0.0D0, 0.0D0, 0.0D0, 0.0D0,
+ + 0.0D0, 0.78D0, 0.0D0, 0.0D0, 0.0D0, 0.0D0,
+ + 0.0D0, 0.0D0, 0.78D0, -0.46D0, 0.0D0, 0.0D0,
+ + 0.0D0, 0.0D0, 0.0D0, 0.78D0, -0.46D0, -0.22D0,
+ + 1.06D0, 0.0D0, 0.0D0, 0.0D0, 0.6D0, 0.0D0,
+ + 0.0D0, 0.0D0, 0.0D0, 0.0D0, 0.0D0, 0.78D0,
+ + 0.0D0, 0.0D0, 0.0D0, 0.0D0, 0.0D0, 0.0D0,
+ + 0.66D0, 0.1D0, -0.1D0, 0.0D0, 0.0D0, 0.0D0,
+ + 0.0D0, 0.96D0, 0.1D0, -0.76D0, 0.8D0, 0.90D0,
+ + -0.3D0, -0.02D0, 0.6D0, 0.0D0, 0.0D0, 0.0D0,
+ + 0.0D0, 0.0D0, 0.0D0, 0.78D0, 0.0D0, 0.0D0,
+ + 0.0D0, 0.0D0, 0.0D0, 0.0D0, -0.06D0, 0.1D0,
+ + -0.1D0, 0.0D0, 0.0D0, 0.0D0, 0.0D0, 0.90D0,
+ + 0.1D0, -0.22D0, 0.8D0, 0.18D0, -0.3D0, -0.02D0,
+ + 0.6D0, 0.0D0, 0.0D0, 0.0D0, 0.0D0, 0.0D0, 0.0D0,
+ + 0.78D0, 0.0D0, 0.0D0, 0.0D0, 0.0D0, 0.0D0,
+ + 0.0D0, 0.78D0, 0.26D0, 0.0D0, 0.0D0, 0.0D0,
+ + 0.0D0, 0.0D0, 0.78D0, 0.26D0, -0.76D0, 1.12D0,
+ + 0.0D0, 0.0D0, 0.0D0/
+ DATA DT9Y/0.5D0, 0.0D0, 0.0D0, 0.0D0, 0.0D0, 0.0D0,
+ + 0.0D0, 0.04D0, 0.0D0, 0.0D0, 0.0D0, 0.0D0,
+ + 0.0D0, 0.0D0, 0.04D0, -0.78D0, 0.0D0, 0.0D0,
+ + 0.0D0, 0.0D0, 0.0D0, 0.04D0, -0.78D0, 0.54D0,
+ + 0.08D0, 0.0D0, 0.0D0, 0.0D0, 0.5D0, 0.0D0,
+ + 0.0D0, 0.0D0, 0.0D0, 0.0D0, 0.0D0, 0.04D0,
+ + 0.0D0, 0.0D0, 0.0D0, 0.0D0, 0.0D0, 0.0D0, 0.7D0,
+ + -0.9D0, -0.12D0, 0.0D0, 0.0D0, 0.0D0, 0.0D0,
+ + 0.64D0, -0.9D0, -0.30D0, 0.7D0, -0.18D0, 0.2D0,
+ + 0.28D0, 0.5D0, 0.0D0, 0.0D0, 0.0D0, 0.0D0,
+ + 0.0D0, 0.0D0, 0.04D0, 0.0D0, 0.0D0, 0.0D0,
+ + 0.0D0, 0.0D0, 0.0D0, 0.7D0, -1.08D0, 0.0D0,
+ + 0.0D0, 0.0D0, 0.0D0, 0.0D0, 0.64D0, -1.26D0,
+ + 0.54D0, 0.20D0, 0.0D0, 0.0D0, 0.0D0, 0.5D0,
+ + 0.0D0, 0.0D0, 0.0D0, 0.0D0, 0.0D0, 0.0D0,
+ + 0.04D0, 0.0D0, 0.0D0, 0.0D0, 0.0D0, 0.0D0,
+ + 0.0D0, 0.04D0, -0.9D0, 0.18D0, 0.0D0, 0.0D0,
+ + 0.0D0, 0.0D0, 0.04D0, -0.9D0, 0.18D0, 0.7D0,
+ + -0.18D0, 0.2D0, 0.16D0/
+ DATA SSIZE2/0.0D0, 0.0D0, 0.0D0, 0.0D0, 0.0D0, 0.0D0,
+ + 0.0D0, 0.0D0, 0.0D0, 0.0D0, 0.0D0, 0.0D0, 0.0D0,
+ + 0.0D0, 1.17D0, 1.17D0, 1.17D0, 1.17D0, 1.17D0,
+ + 1.17D0, 1.17D0, 1.17D0, 1.17D0, 1.17D0, 1.17D0,
+ + 1.17D0, 1.17D0, 1.17D0/
+* .. Executable Statements ..
+*
+ DO 60 KI = 1, 4
+ INCX = INCXS(KI)
+ INCY = INCYS(KI)
+ MX = ABS(INCX)
+ MY = ABS(INCY)
+*
+ DO 40 KN = 1, 4
+ N = NS(KN)
+ KSIZE = MIN(2,KN)
+ LENX = LENS(KN,MX)
+ LENY = LENS(KN,MY)
+*
+ IF (ICASE.EQ.4) THEN
+* .. DROT ..
+ DO 20 I = 1, 7
+ SX(I) = DX1(I)
+ SY(I) = DY1(I)
+ STX(I) = DT9X(I,KN,KI)
+ STY(I) = DT9Y(I,KN,KI)
+ 20 CONTINUE
+ CALL DROT(N,SX,INCX,SY,INCY,SC,SS)
+ CALL STEST(LENX,SX,STX,SSIZE2(1,KSIZE),SFAC)
+ CALL STEST(LENY,SY,STY,SSIZE2(1,KSIZE),SFAC)
+ ELSE
+ WRITE (NOUT,*) ' Shouldn''t be here in CHECK3'
+ STOP
+ END IF
+ 40 CONTINUE
+ 60 CONTINUE
+*
+ MWPC(1) = 1
+ DO 80 I = 2, 11
+ MWPC(I) = 0
+ 80 CONTINUE
+ MWPS(1) = 0
+ DO 100 I = 2, 6
+ MWPS(I) = 1
+ 100 CONTINUE
+ DO 120 I = 7, 11
+ MWPS(I) = -1
+ 120 CONTINUE
+ MWPINX(1) = 1
+ MWPINX(2) = 1
+ MWPINX(3) = 1
+ MWPINX(4) = -1
+ MWPINX(5) = 1
+ MWPINX(6) = -1
+ MWPINX(7) = 1
+ MWPINX(8) = 1
+ MWPINX(9) = -1
+ MWPINX(10) = 1
+ MWPINX(11) = -1
+ MWPINY(1) = 1
+ MWPINY(2) = 1
+ MWPINY(3) = -1
+ MWPINY(4) = -1
+ MWPINY(5) = 2
+ MWPINY(6) = 1
+ MWPINY(7) = 1
+ MWPINY(8) = -1
+ MWPINY(9) = -1
+ MWPINY(10) = 2
+ MWPINY(11) = 1
+ DO 140 I = 1, 11
+ MWPN(I) = 5
+ 140 CONTINUE
+ MWPN(5) = 3
+ MWPN(10) = 3
+ DO 160 I = 1, 5
+ MWPX(I) = I
+ MWPY(I) = I
+ MWPTX(1,I) = I
+ MWPTY(1,I) = I
+ MWPTX(2,I) = I
+ MWPTY(2,I) = -I
+ MWPTX(3,I) = 6 - I
+ MWPTY(3,I) = I - 6
+ MWPTX(4,I) = I
+ MWPTY(4,I) = -I
+ MWPTX(6,I) = 6 - I
+ MWPTY(6,I) = I - 6
+ MWPTX(7,I) = -I
+ MWPTY(7,I) = I
+ MWPTX(8,I) = I - 6
+ MWPTY(8,I) = 6 - I
+ MWPTX(9,I) = -I
+ MWPTY(9,I) = I
+ MWPTX(11,I) = I - 6
+ MWPTY(11,I) = 6 - I
+ 160 CONTINUE
+ MWPTX(5,1) = 1
+ MWPTX(5,2) = 3
+ MWPTX(5,3) = 5
+ MWPTX(5,4) = 4
+ MWPTX(5,5) = 5
+ MWPTY(5,1) = -1
+ MWPTY(5,2) = 2
+ MWPTY(5,3) = -2
+ MWPTY(5,4) = 4
+ MWPTY(5,5) = -3
+ MWPTX(10,1) = -1
+ MWPTX(10,2) = -3
+ MWPTX(10,3) = -5
+ MWPTX(10,4) = 4
+ MWPTX(10,5) = 5
+ MWPTY(10,1) = 1
+ MWPTY(10,2) = 2
+ MWPTY(10,3) = 2
+ MWPTY(10,4) = 4
+ MWPTY(10,5) = 3
+ DO 200 I = 1, 11
+ INCX = MWPINX(I)
+ INCY = MWPINY(I)
+ DO 180 K = 1, 5
+ COPYX(K) = MWPX(K)
+ COPYY(K) = MWPY(K)
+ MWPSTX(K) = MWPTX(I,K)
+ MWPSTY(K) = MWPTY(I,K)
+ 180 CONTINUE
+ CALL DROT(MWPN(I),COPYX,INCX,COPYY,INCY,MWPC(I),MWPS(I))
+ CALL STEST(5,COPYX,MWPSTX,MWPSTX,SFAC)
+ CALL STEST(5,COPYY,MWPSTY,MWPSTY,SFAC)
+ 200 CONTINUE
+ RETURN
+ END
+ SUBROUTINE STEST(LEN,SCOMP,STRUE,SSIZE,SFAC)
+* ********************************* STEST **************************
+*
+* THIS SUBR COMPARES ARRAYS SCOMP() AND STRUE() OF LENGTH LEN TO
+* SEE IF THE TERM BY TERM DIFFERENCES, MULTIPLIED BY SFAC, ARE
+* NEGLIGIBLE.
+*
+* C. L. LAWSON, JPL, 1974 DEC 10
+*
+* .. Parameters ..
+ INTEGER NOUT
+ PARAMETER (NOUT=6)
+* .. Scalar Arguments ..
+ DOUBLE PRECISION SFAC
+ INTEGER LEN
+* .. Array Arguments ..
+ DOUBLE PRECISION SCOMP(LEN), SSIZE(LEN), STRUE(LEN)
+* .. Scalars in Common ..
+ INTEGER ICASE, INCX, INCY, MODE, N
+ LOGICAL PASS
+* .. Local Scalars ..
+ DOUBLE PRECISION SD
+ INTEGER I
+* .. External Functions ..
+ DOUBLE PRECISION SDIFF
+ EXTERNAL SDIFF
+* .. Intrinsic Functions ..
+ INTRINSIC ABS
+* .. Common blocks ..
+ COMMON /COMBLA/ICASE, N, INCX, INCY, MODE, PASS
+* .. Executable Statements ..
+*
+ DO 40 I = 1, LEN
+ SD = SCOMP(I) - STRUE(I)
+ IF (SDIFF(ABS(SSIZE(I))+ABS(SFAC*SD),ABS(SSIZE(I))).EQ.0.0D0)
+ + GO TO 40
+*
+* HERE SCOMP(I) IS NOT CLOSE TO STRUE(I).
+*
+ IF ( .NOT. PASS) GO TO 20
+* PRINT FAIL MESSAGE AND HEADER.
+ PASS = .FALSE.
+ WRITE (NOUT,99999)
+ WRITE (NOUT,99998)
+ 20 WRITE (NOUT,99997) ICASE, N, INCX, INCY, MODE, I, SCOMP(I),
+ + STRUE(I), SD, SSIZE(I)
+ 40 CONTINUE
+ RETURN
+*
+99999 FORMAT (' FAIL')
+99998 FORMAT (/' CASE N INCX INCY MODE I ',
+ + ' COMP(I) TRUE(I) DIFFERENCE',
+ + ' SIZE(I)',/1X)
+99997 FORMAT (1X,I4,I3,3I5,I3,2D36.8,2D12.4)
+ END
+ SUBROUTINE STEST1(SCOMP1,STRUE1,SSIZE,SFAC)
+* ************************* STEST1 *****************************
+*
+* THIS IS AN INTERFACE SUBROUTINE TO ACCOMODATE THE FORTRAN
+* REQUIREMENT THAT WHEN A DUMMY ARGUMENT IS AN ARRAY, THE
+* ACTUAL ARGUMENT MUST ALSO BE AN ARRAY OR AN ARRAY ELEMENT.
+*
+* C.L. LAWSON, JPL, 1978 DEC 6
+*
+* .. Scalar Arguments ..
+ DOUBLE PRECISION SCOMP1, SFAC, STRUE1
+* .. Array Arguments ..
+ DOUBLE PRECISION SSIZE(*)
+* .. Local Arrays ..
+ DOUBLE PRECISION SCOMP(1), STRUE(1)
+* .. External Subroutines ..
+ EXTERNAL STEST
+* .. Executable Statements ..
+*
+ SCOMP(1) = SCOMP1
+ STRUE(1) = STRUE1
+ CALL STEST(1,SCOMP,STRUE,SSIZE,SFAC)
+*
+ RETURN
+ END
+ DOUBLE PRECISION FUNCTION SDIFF(SA,SB)
+* ********************************* SDIFF **************************
+* COMPUTES DIFFERENCE OF TWO NUMBERS. C. L. LAWSON, JPL 1974 FEB 15
+*
+* .. Scalar Arguments ..
+ DOUBLE PRECISION SA, SB
+* .. Executable Statements ..
+ SDIFF = SA - SB
+ RETURN
+ END
+ SUBROUTINE ITEST1(ICOMP,ITRUE)
+* ********************************* ITEST1 *************************
+*
+* THIS SUBROUTINE COMPARES THE VARIABLES ICOMP AND ITRUE FOR
+* EQUALITY.
+* C. L. LAWSON, JPL, 1974 DEC 10
+*
+* .. Parameters ..
+ INTEGER NOUT
+ PARAMETER (NOUT=6)
+* .. Scalar Arguments ..
+ INTEGER ICOMP, ITRUE
+* .. Scalars in Common ..
+ INTEGER ICASE, INCX, INCY, MODE, N
+ LOGICAL PASS
+* .. Local Scalars ..
+ INTEGER ID
+* .. Common blocks ..
+ COMMON /COMBLA/ICASE, N, INCX, INCY, MODE, PASS
+* .. Executable Statements ..
+*
+ IF (ICOMP.EQ.ITRUE) GO TO 40
+*
+* HERE ICOMP IS NOT EQUAL TO ITRUE.
+*
+ IF ( .NOT. PASS) GO TO 20
+* PRINT FAIL MESSAGE AND HEADER.
+ PASS = .FALSE.
+ WRITE (NOUT,99999)
+ WRITE (NOUT,99998)
+ 20 ID = ICOMP - ITRUE
+ WRITE (NOUT,99997) ICASE, N, INCX, INCY, MODE, ICOMP, ITRUE, ID
+ 40 CONTINUE
+ RETURN
+*
+99999 FORMAT (' FAIL')
+99998 FORMAT (/' CASE N INCX INCY MODE ',
+ + ' COMP TRUE DIFFERENCE',
+ + /1X)
+99997 FORMAT (1X,I4,I3,3I5,2I36,I12)
+ END
diff --git a/blas/testing/dblat2.dat b/blas/testing/dblat2.dat
new file mode 100644
index 000000000..3755b83b8
--- /dev/null
+++ b/blas/testing/dblat2.dat
@@ -0,0 +1,34 @@
+'dblat2.summ' NAME OF SUMMARY OUTPUT FILE
+6 UNIT NUMBER OF SUMMARY FILE
+'dblat2.snap' NAME OF SNAPSHOT OUTPUT FILE
+-1 UNIT NUMBER OF SNAPSHOT FILE (NOT USED IF .LT. 0)
+F LOGICAL FLAG, T TO REWIND SNAPSHOT FILE AFTER EACH RECORD.
+F LOGICAL FLAG, T TO STOP ON FAILURES.
+T LOGICAL FLAG, T TO TEST ERROR EXITS.
+16.0 THRESHOLD VALUE OF TEST RATIO
+6 NUMBER OF VALUES OF N
+0 1 2 3 5 9 VALUES OF N
+4 NUMBER OF VALUES OF K
+0 1 2 4 VALUES OF K
+4 NUMBER OF VALUES OF INCX AND INCY
+1 2 -1 -2 VALUES OF INCX AND INCY
+3 NUMBER OF VALUES OF ALPHA
+0.0 1.0 0.7 VALUES OF ALPHA
+3 NUMBER OF VALUES OF BETA
+0.0 1.0 0.9 VALUES OF BETA
+DGEMV T PUT F FOR NO TEST. SAME COLUMNS.
+DGBMV T PUT F FOR NO TEST. SAME COLUMNS.
+DSYMV T PUT F FOR NO TEST. SAME COLUMNS.
+DSBMV T PUT F FOR NO TEST. SAME COLUMNS.
+DSPMV T PUT F FOR NO TEST. SAME COLUMNS.
+DTRMV T PUT F FOR NO TEST. SAME COLUMNS.
+DTBMV T PUT F FOR NO TEST. SAME COLUMNS.
+DTPMV T PUT F FOR NO TEST. SAME COLUMNS.
+DTRSV T PUT F FOR NO TEST. SAME COLUMNS.
+DTBSV T PUT F FOR NO TEST. SAME COLUMNS.
+DTPSV T PUT F FOR NO TEST. SAME COLUMNS.
+DGER T PUT F FOR NO TEST. SAME COLUMNS.
+DSYR T PUT F FOR NO TEST. SAME COLUMNS.
+DSPR T PUT F FOR NO TEST. SAME COLUMNS.
+DSYR2 T PUT F FOR NO TEST. SAME COLUMNS.
+DSPR2 T PUT F FOR NO TEST. SAME COLUMNS.
diff --git a/blas/testing/dblat2.f b/blas/testing/dblat2.f
new file mode 100644
index 000000000..4002d4368
--- /dev/null
+++ b/blas/testing/dblat2.f
@@ -0,0 +1,3138 @@
+ PROGRAM DBLAT2
+*
+* Test program for the DOUBLE PRECISION Level 2 Blas.
+*
+* The program must be driven by a short data file. The first 18 records
+* of the file are read using list-directed input, the last 16 records
+* are read using the format ( A6, L2 ). An annotated example of a data
+* file can be obtained by deleting the first 3 characters from the
+* following 34 lines:
+* 'DBLAT2.SUMM' NAME OF SUMMARY OUTPUT FILE
+* 6 UNIT NUMBER OF SUMMARY FILE
+* 'DBLAT2.SNAP' NAME OF SNAPSHOT OUTPUT FILE
+* -1 UNIT NUMBER OF SNAPSHOT FILE (NOT USED IF .LT. 0)
+* F LOGICAL FLAG, T TO REWIND SNAPSHOT FILE AFTER EACH RECORD.
+* F LOGICAL FLAG, T TO STOP ON FAILURES.
+* T LOGICAL FLAG, T TO TEST ERROR EXITS.
+* 16.0 THRESHOLD VALUE OF TEST RATIO
+* 6 NUMBER OF VALUES OF N
+* 0 1 2 3 5 9 VALUES OF N
+* 4 NUMBER OF VALUES OF K
+* 0 1 2 4 VALUES OF K
+* 4 NUMBER OF VALUES OF INCX AND INCY
+* 1 2 -1 -2 VALUES OF INCX AND INCY
+* 3 NUMBER OF VALUES OF ALPHA
+* 0.0 1.0 0.7 VALUES OF ALPHA
+* 3 NUMBER OF VALUES OF BETA
+* 0.0 1.0 0.9 VALUES OF BETA
+* DGEMV T PUT F FOR NO TEST. SAME COLUMNS.
+* DGBMV T PUT F FOR NO TEST. SAME COLUMNS.
+* DSYMV T PUT F FOR NO TEST. SAME COLUMNS.
+* DSBMV T PUT F FOR NO TEST. SAME COLUMNS.
+* DSPMV T PUT F FOR NO TEST. SAME COLUMNS.
+* DTRMV T PUT F FOR NO TEST. SAME COLUMNS.
+* DTBMV T PUT F FOR NO TEST. SAME COLUMNS.
+* DTPMV T PUT F FOR NO TEST. SAME COLUMNS.
+* DTRSV T PUT F FOR NO TEST. SAME COLUMNS.
+* DTBSV T PUT F FOR NO TEST. SAME COLUMNS.
+* DTPSV T PUT F FOR NO TEST. SAME COLUMNS.
+* DGER T PUT F FOR NO TEST. SAME COLUMNS.
+* DSYR T PUT F FOR NO TEST. SAME COLUMNS.
+* DSPR T PUT F FOR NO TEST. SAME COLUMNS.
+* DSYR2 T PUT F FOR NO TEST. SAME COLUMNS.
+* DSPR2 T PUT F FOR NO TEST. SAME COLUMNS.
+*
+* See:
+*
+* Dongarra J. J., Du Croz J. J., Hammarling S. and Hanson R. J..
+* An extended set of Fortran Basic Linear Algebra Subprograms.
+*
+* Technical Memoranda Nos. 41 (revision 3) and 81, Mathematics
+* and Computer Science Division, Argonne National Laboratory,
+* 9700 South Cass Avenue, Argonne, Illinois 60439, US.
+*
+* Or
+*
+* NAG Technical Reports TR3/87 and TR4/87, Numerical Algorithms
+* Group Ltd., NAG Central Office, 256 Banbury Road, Oxford
+* OX2 7DE, UK, and Numerical Algorithms Group Inc., 1101 31st
+* Street, Suite 100, Downers Grove, Illinois 60515-1263, USA.
+*
+*
+* -- Written on 10-August-1987.
+* Richard Hanson, Sandia National Labs.
+* Jeremy Du Croz, NAG Central Office.
+*
+* .. Parameters ..
+ INTEGER NIN
+ PARAMETER ( NIN = 5 )
+ INTEGER NSUBS
+ PARAMETER ( NSUBS = 16 )
+ DOUBLE PRECISION ZERO, HALF, ONE
+ PARAMETER ( ZERO = 0.0D0, HALF = 0.5D0, ONE = 1.0D0 )
+ INTEGER NMAX, INCMAX
+ PARAMETER ( NMAX = 65, INCMAX = 2 )
+ INTEGER NINMAX, NIDMAX, NKBMAX, NALMAX, NBEMAX
+ PARAMETER ( NINMAX = 7, NIDMAX = 9, NKBMAX = 7,
+ $ NALMAX = 7, NBEMAX = 7 )
+* .. Local Scalars ..
+ DOUBLE PRECISION EPS, ERR, THRESH
+ INTEGER I, ISNUM, J, N, NALF, NBET, NIDIM, NINC, NKB,
+ $ NOUT, NTRA
+ LOGICAL FATAL, LTESTT, REWI, SAME, SFATAL, TRACE,
+ $ TSTERR
+ CHARACTER*1 TRANS
+ CHARACTER*6 SNAMET
+ CHARACTER*32 SNAPS, SUMMRY
+* .. Local Arrays ..
+ DOUBLE PRECISION A( NMAX, NMAX ), AA( NMAX*NMAX ),
+ $ ALF( NALMAX ), AS( NMAX*NMAX ), BET( NBEMAX ),
+ $ G( NMAX ), X( NMAX ), XS( NMAX*INCMAX ),
+ $ XX( NMAX*INCMAX ), Y( NMAX ),
+ $ YS( NMAX*INCMAX ), YT( NMAX ),
+ $ YY( NMAX*INCMAX ), Z( 2*NMAX )
+ INTEGER IDIM( NIDMAX ), INC( NINMAX ), KB( NKBMAX )
+ LOGICAL LTEST( NSUBS )
+ CHARACTER*6 SNAMES( NSUBS )
+* .. External Functions ..
+ DOUBLE PRECISION DDIFF
+ LOGICAL LDE
+ EXTERNAL DDIFF, LDE
+* .. External Subroutines ..
+ EXTERNAL DCHK1, DCHK2, DCHK3, DCHK4, DCHK5, DCHK6,
+ $ DCHKE, DMVCH
+* .. Intrinsic Functions ..
+ INTRINSIC ABS, MAX, MIN
+* .. Scalars in Common ..
+ INTEGER INFOT, NOUTC
+ LOGICAL LERR, OK
+ CHARACTER*6 SRNAMT
+* .. Common blocks ..
+ COMMON /INFOC/INFOT, NOUTC, OK, LERR
+ COMMON /SRNAMC/SRNAMT
+* .. Data statements ..
+ DATA SNAMES/'DGEMV ', 'DGBMV ', 'DSYMV ', 'DSBMV ',
+ $ 'DSPMV ', 'DTRMV ', 'DTBMV ', 'DTPMV ',
+ $ 'DTRSV ', 'DTBSV ', 'DTPSV ', 'DGER ',
+ $ 'DSYR ', 'DSPR ', 'DSYR2 ', 'DSPR2 '/
+* .. Executable Statements ..
+*
+* Read name and unit number for summary output file and open file.
+*
+ READ( NIN, FMT = * )SUMMRY
+ READ( NIN, FMT = * )NOUT
+ OPEN( NOUT, FILE = SUMMRY, STATUS = 'NEW' )
+ NOUTC = NOUT
+*
+* Read name and unit number for snapshot output file and open file.
+*
+ READ( NIN, FMT = * )SNAPS
+ READ( NIN, FMT = * )NTRA
+ TRACE = NTRA.GE.0
+ IF( TRACE )THEN
+ OPEN( NTRA, FILE = SNAPS, STATUS = 'NEW' )
+ END IF
+* Read the flag that directs rewinding of the snapshot file.
+ READ( NIN, FMT = * )REWI
+ REWI = REWI.AND.TRACE
+* Read the flag that directs stopping on any failure.
+ READ( NIN, FMT = * )SFATAL
+* Read the flag that indicates whether error exits are to be tested.
+ READ( NIN, FMT = * )TSTERR
+* Read the threshold value of the test ratio
+ READ( NIN, FMT = * )THRESH
+*
+* Read and check the parameter values for the tests.
+*
+* Values of N
+ READ( NIN, FMT = * )NIDIM
+ IF( NIDIM.LT.1.OR.NIDIM.GT.NIDMAX )THEN
+ WRITE( NOUT, FMT = 9997 )'N', NIDMAX
+ GO TO 230
+ END IF
+ READ( NIN, FMT = * )( IDIM( I ), I = 1, NIDIM )
+ DO 10 I = 1, NIDIM
+ IF( IDIM( I ).LT.0.OR.IDIM( I ).GT.NMAX )THEN
+ WRITE( NOUT, FMT = 9996 )NMAX
+ GO TO 230
+ END IF
+ 10 CONTINUE
+* Values of K
+ READ( NIN, FMT = * )NKB
+ IF( NKB.LT.1.OR.NKB.GT.NKBMAX )THEN
+ WRITE( NOUT, FMT = 9997 )'K', NKBMAX
+ GO TO 230
+ END IF
+ READ( NIN, FMT = * )( KB( I ), I = 1, NKB )
+ DO 20 I = 1, NKB
+ IF( KB( I ).LT.0 )THEN
+ WRITE( NOUT, FMT = 9995 )
+ GO TO 230
+ END IF
+ 20 CONTINUE
+* Values of INCX and INCY
+ READ( NIN, FMT = * )NINC
+ IF( NINC.LT.1.OR.NINC.GT.NINMAX )THEN
+ WRITE( NOUT, FMT = 9997 )'INCX AND INCY', NINMAX
+ GO TO 230
+ END IF
+ READ( NIN, FMT = * )( INC( I ), I = 1, NINC )
+ DO 30 I = 1, NINC
+ IF( INC( I ).EQ.0.OR.ABS( INC( I ) ).GT.INCMAX )THEN
+ WRITE( NOUT, FMT = 9994 )INCMAX
+ GO TO 230
+ END IF
+ 30 CONTINUE
+* Values of ALPHA
+ READ( NIN, FMT = * )NALF
+ IF( NALF.LT.1.OR.NALF.GT.NALMAX )THEN
+ WRITE( NOUT, FMT = 9997 )'ALPHA', NALMAX
+ GO TO 230
+ END IF
+ READ( NIN, FMT = * )( ALF( I ), I = 1, NALF )
+* Values of BETA
+ READ( NIN, FMT = * )NBET
+ IF( NBET.LT.1.OR.NBET.GT.NBEMAX )THEN
+ WRITE( NOUT, FMT = 9997 )'BETA', NBEMAX
+ GO TO 230
+ END IF
+ READ( NIN, FMT = * )( BET( I ), I = 1, NBET )
+*
+* Report values of parameters.
+*
+ WRITE( NOUT, FMT = 9993 )
+ WRITE( NOUT, FMT = 9992 )( IDIM( I ), I = 1, NIDIM )
+ WRITE( NOUT, FMT = 9991 )( KB( I ), I = 1, NKB )
+ WRITE( NOUT, FMT = 9990 )( INC( I ), I = 1, NINC )
+ WRITE( NOUT, FMT = 9989 )( ALF( I ), I = 1, NALF )
+ WRITE( NOUT, FMT = 9988 )( BET( I ), I = 1, NBET )
+ IF( .NOT.TSTERR )THEN
+ WRITE( NOUT, FMT = * )
+ WRITE( NOUT, FMT = 9980 )
+ END IF
+ WRITE( NOUT, FMT = * )
+ WRITE( NOUT, FMT = 9999 )THRESH
+ WRITE( NOUT, FMT = * )
+*
+* Read names of subroutines and flags which indicate
+* whether they are to be tested.
+*
+ DO 40 I = 1, NSUBS
+ LTEST( I ) = .FALSE.
+ 40 CONTINUE
+ 50 READ( NIN, FMT = 9984, END = 80 )SNAMET, LTESTT
+ DO 60 I = 1, NSUBS
+ IF( SNAMET.EQ.SNAMES( I ) )
+ $ GO TO 70
+ 60 CONTINUE
+ WRITE( NOUT, FMT = 9986 )SNAMET
+ STOP
+ 70 LTEST( I ) = LTESTT
+ GO TO 50
+*
+ 80 CONTINUE
+ CLOSE ( NIN )
+*
+* Compute EPS (the machine precision).
+*
+ EPS = ONE
+ 90 CONTINUE
+ IF( DDIFF( ONE + EPS, ONE ).EQ.ZERO )
+ $ GO TO 100
+ EPS = HALF*EPS
+ GO TO 90
+ 100 CONTINUE
+ EPS = EPS + EPS
+ WRITE( NOUT, FMT = 9998 )EPS
+*
+* Check the reliability of DMVCH using exact data.
+*
+ N = MIN( 32, NMAX )
+ DO 120 J = 1, N
+ DO 110 I = 1, N
+ A( I, J ) = MAX( I - J + 1, 0 )
+ 110 CONTINUE
+ X( J ) = J
+ Y( J ) = ZERO
+ 120 CONTINUE
+ DO 130 J = 1, N
+ YY( J ) = J*( ( J + 1 )*J )/2 - ( ( J + 1 )*J*( J - 1 ) )/3
+ 130 CONTINUE
+* YY holds the exact result. On exit from DMVCH YT holds
+* the result computed by DMVCH.
+ TRANS = 'N'
+ CALL DMVCH( TRANS, N, N, ONE, A, NMAX, X, 1, ZERO, Y, 1, YT, G,
+ $ YY, EPS, ERR, FATAL, NOUT, .TRUE. )
+ SAME = LDE( YY, YT, N )
+ IF( .NOT.SAME.OR.ERR.NE.ZERO )THEN
+ WRITE( NOUT, FMT = 9985 )TRANS, SAME, ERR
+ STOP
+ END IF
+ TRANS = 'T'
+ CALL DMVCH( TRANS, N, N, ONE, A, NMAX, X, -1, ZERO, Y, -1, YT, G,
+ $ YY, EPS, ERR, FATAL, NOUT, .TRUE. )
+ SAME = LDE( YY, YT, N )
+ IF( .NOT.SAME.OR.ERR.NE.ZERO )THEN
+ WRITE( NOUT, FMT = 9985 )TRANS, SAME, ERR
+ STOP
+ END IF
+*
+* Test each subroutine in turn.
+*
+ DO 210 ISNUM = 1, NSUBS
+ WRITE( NOUT, FMT = * )
+ IF( .NOT.LTEST( ISNUM ) )THEN
+* Subprogram is not to be tested.
+ WRITE( NOUT, FMT = 9983 )SNAMES( ISNUM )
+ ELSE
+ SRNAMT = SNAMES( ISNUM )
+* Test error exits.
+ IF( TSTERR )THEN
+ CALL DCHKE( ISNUM, SNAMES( ISNUM ), NOUT )
+ WRITE( NOUT, FMT = * )
+ END IF
+* Test computations.
+ INFOT = 0
+ OK = .TRUE.
+ FATAL = .FALSE.
+ GO TO ( 140, 140, 150, 150, 150, 160, 160,
+ $ 160, 160, 160, 160, 170, 180, 180,
+ $ 190, 190 )ISNUM
+* Test DGEMV, 01, and DGBMV, 02.
+ 140 CALL DCHK1( SNAMES( ISNUM ), EPS, THRESH, NOUT, NTRA, TRACE,
+ $ REWI, FATAL, NIDIM, IDIM, NKB, KB, NALF, ALF,
+ $ NBET, BET, NINC, INC, NMAX, INCMAX, A, AA, AS,
+ $ X, XX, XS, Y, YY, YS, YT, G )
+ GO TO 200
+* Test DSYMV, 03, DSBMV, 04, and DSPMV, 05.
+ 150 CALL DCHK2( SNAMES( ISNUM ), EPS, THRESH, NOUT, NTRA, TRACE,
+ $ REWI, FATAL, NIDIM, IDIM, NKB, KB, NALF, ALF,
+ $ NBET, BET, NINC, INC, NMAX, INCMAX, A, AA, AS,
+ $ X, XX, XS, Y, YY, YS, YT, G )
+ GO TO 200
+* Test DTRMV, 06, DTBMV, 07, DTPMV, 08,
+* DTRSV, 09, DTBSV, 10, and DTPSV, 11.
+ 160 CALL DCHK3( SNAMES( ISNUM ), EPS, THRESH, NOUT, NTRA, TRACE,
+ $ REWI, FATAL, NIDIM, IDIM, NKB, KB, NINC, INC,
+ $ NMAX, INCMAX, A, AA, AS, Y, YY, YS, YT, G, Z )
+ GO TO 200
+* Test DGER, 12.
+ 170 CALL DCHK4( SNAMES( ISNUM ), EPS, THRESH, NOUT, NTRA, TRACE,
+ $ REWI, FATAL, NIDIM, IDIM, NALF, ALF, NINC, INC,
+ $ NMAX, INCMAX, A, AA, AS, X, XX, XS, Y, YY, YS,
+ $ YT, G, Z )
+ GO TO 200
+* Test DSYR, 13, and DSPR, 14.
+ 180 CALL DCHK5( SNAMES( ISNUM ), EPS, THRESH, NOUT, NTRA, TRACE,
+ $ REWI, FATAL, NIDIM, IDIM, NALF, ALF, NINC, INC,
+ $ NMAX, INCMAX, A, AA, AS, X, XX, XS, Y, YY, YS,
+ $ YT, G, Z )
+ GO TO 200
+* Test DSYR2, 15, and DSPR2, 16.
+ 190 CALL DCHK6( SNAMES( ISNUM ), EPS, THRESH, NOUT, NTRA, TRACE,
+ $ REWI, FATAL, NIDIM, IDIM, NALF, ALF, NINC, INC,
+ $ NMAX, INCMAX, A, AA, AS, X, XX, XS, Y, YY, YS,
+ $ YT, G, Z )
+*
+ 200 IF( FATAL.AND.SFATAL )
+ $ GO TO 220
+ END IF
+ 210 CONTINUE
+ WRITE( NOUT, FMT = 9982 )
+ GO TO 240
+*
+ 220 CONTINUE
+ WRITE( NOUT, FMT = 9981 )
+ GO TO 240
+*
+ 230 CONTINUE
+ WRITE( NOUT, FMT = 9987 )
+*
+ 240 CONTINUE
+ IF( TRACE )
+ $ CLOSE ( NTRA )
+ CLOSE ( NOUT )
+ STOP
+*
+ 9999 FORMAT( ' ROUTINES PASS COMPUTATIONAL TESTS IF TEST RATIO IS LES',
+ $ 'S THAN', F8.2 )
+ 9998 FORMAT( ' RELATIVE MACHINE PRECISION IS TAKEN TO BE', 1P, D9.1 )
+ 9997 FORMAT( ' NUMBER OF VALUES OF ', A, ' IS LESS THAN 1 OR GREATER ',
+ $ 'THAN ', I2 )
+ 9996 FORMAT( ' VALUE OF N IS LESS THAN 0 OR GREATER THAN ', I2 )
+ 9995 FORMAT( ' VALUE OF K IS LESS THAN 0' )
+ 9994 FORMAT( ' ABSOLUTE VALUE OF INCX OR INCY IS 0 OR GREATER THAN ',
+ $ I2 )
+ 9993 FORMAT( ' TESTS OF THE DOUBLE PRECISION LEVEL 2 BLAS', //' THE F',
+ $ 'OLLOWING PARAMETER VALUES WILL BE USED:' )
+ 9992 FORMAT( ' FOR N ', 9I6 )
+ 9991 FORMAT( ' FOR K ', 7I6 )
+ 9990 FORMAT( ' FOR INCX AND INCY ', 7I6 )
+ 9989 FORMAT( ' FOR ALPHA ', 7F6.1 )
+ 9988 FORMAT( ' FOR BETA ', 7F6.1 )
+ 9987 FORMAT( ' AMEND DATA FILE OR INCREASE ARRAY SIZES IN PROGRAM',
+ $ /' ******* TESTS ABANDONED *******' )
+ 9986 FORMAT( ' SUBPROGRAM NAME ', A6, ' NOT RECOGNIZED', /' ******* T',
+ $ 'ESTS ABANDONED *******' )
+ 9985 FORMAT( ' ERROR IN DMVCH - IN-LINE DOT PRODUCTS ARE BEING EVALU',
+ $ 'ATED WRONGLY.', /' DMVCH WAS CALLED WITH TRANS = ', A1,
+ $ ' AND RETURNED SAME = ', L1, ' AND ERR = ', F12.3, '.', /
+ $ ' THIS MAY BE DUE TO FAULTS IN THE ARITHMETIC OR THE COMPILER.'
+ $ , /' ******* TESTS ABANDONED *******' )
+ 9984 FORMAT( A6, L2 )
+ 9983 FORMAT( 1X, A6, ' WAS NOT TESTED' )
+ 9982 FORMAT( /' END OF TESTS' )
+ 9981 FORMAT( /' ******* FATAL ERROR - TESTS ABANDONED *******' )
+ 9980 FORMAT( ' ERROR-EXITS WILL NOT BE TESTED' )
+*
+* End of DBLAT2.
+*
+ END
+ SUBROUTINE DCHK1( SNAME, EPS, THRESH, NOUT, NTRA, TRACE, REWI,
+ $ FATAL, NIDIM, IDIM, NKB, KB, NALF, ALF, NBET,
+ $ BET, NINC, INC, NMAX, INCMAX, A, AA, AS, X, XX,
+ $ XS, Y, YY, YS, YT, G )
+*
+* Tests DGEMV and DGBMV.
+*
+* Auxiliary routine for test program for Level 2 Blas.
+*
+* -- Written on 10-August-1987.
+* Richard Hanson, Sandia National Labs.
+* Jeremy Du Croz, NAG Central Office.
+*
+* .. Parameters ..
+ DOUBLE PRECISION ZERO, HALF
+ PARAMETER ( ZERO = 0.0D0, HALF = 0.5D0 )
+* .. Scalar Arguments ..
+ DOUBLE PRECISION EPS, THRESH
+ INTEGER INCMAX, NALF, NBET, NIDIM, NINC, NKB, NMAX,
+ $ NOUT, NTRA
+ LOGICAL FATAL, REWI, TRACE
+ CHARACTER*6 SNAME
+* .. Array Arguments ..
+ DOUBLE PRECISION A( NMAX, NMAX ), AA( NMAX*NMAX ), ALF( NALF ),
+ $ AS( NMAX*NMAX ), BET( NBET ), G( NMAX ),
+ $ X( NMAX ), XS( NMAX*INCMAX ),
+ $ XX( NMAX*INCMAX ), Y( NMAX ),
+ $ YS( NMAX*INCMAX ), YT( NMAX ),
+ $ YY( NMAX*INCMAX )
+ INTEGER IDIM( NIDIM ), INC( NINC ), KB( NKB )
+* .. Local Scalars ..
+ DOUBLE PRECISION ALPHA, ALS, BETA, BLS, ERR, ERRMAX, TRANSL
+ INTEGER I, IA, IB, IC, IKU, IM, IN, INCX, INCXS, INCY,
+ $ INCYS, IX, IY, KL, KLS, KU, KUS, LAA, LDA,
+ $ LDAS, LX, LY, M, ML, MS, N, NARGS, NC, ND, NK,
+ $ NL, NS
+ LOGICAL BANDED, FULL, NULL, RESET, SAME, TRAN
+ CHARACTER*1 TRANS, TRANSS
+ CHARACTER*3 ICH
+* .. Local Arrays ..
+ LOGICAL ISAME( 13 )
+* .. External Functions ..
+ LOGICAL LDE, LDERES
+ EXTERNAL LDE, LDERES
+* .. External Subroutines ..
+ EXTERNAL DGBMV, DGEMV, DMAKE, DMVCH
+* .. Intrinsic Functions ..
+ INTRINSIC ABS, MAX, MIN
+* .. Scalars in Common ..
+ INTEGER INFOT, NOUTC
+ LOGICAL LERR, OK
+* .. Common blocks ..
+ COMMON /INFOC/INFOT, NOUTC, OK, LERR
+* .. Data statements ..
+ DATA ICH/'NTC'/
+* .. Executable Statements ..
+ FULL = SNAME( 3: 3 ).EQ.'E'
+ BANDED = SNAME( 3: 3 ).EQ.'B'
+* Define the number of arguments.
+ IF( FULL )THEN
+ NARGS = 11
+ ELSE IF( BANDED )THEN
+ NARGS = 13
+ END IF
+*
+ NC = 0
+ RESET = .TRUE.
+ ERRMAX = ZERO
+*
+ DO 120 IN = 1, NIDIM
+ N = IDIM( IN )
+ ND = N/2 + 1
+*
+ DO 110 IM = 1, 2
+ IF( IM.EQ.1 )
+ $ M = MAX( N - ND, 0 )
+ IF( IM.EQ.2 )
+ $ M = MIN( N + ND, NMAX )
+*
+ IF( BANDED )THEN
+ NK = NKB
+ ELSE
+ NK = 1
+ END IF
+ DO 100 IKU = 1, NK
+ IF( BANDED )THEN
+ KU = KB( IKU )
+ KL = MAX( KU - 1, 0 )
+ ELSE
+ KU = N - 1
+ KL = M - 1
+ END IF
+* Set LDA to 1 more than minimum value if room.
+ IF( BANDED )THEN
+ LDA = KL + KU + 1
+ ELSE
+ LDA = M
+ END IF
+ IF( LDA.LT.NMAX )
+ $ LDA = LDA + 1
+* Skip tests if not enough room.
+ IF( LDA.GT.NMAX )
+ $ GO TO 100
+ LAA = LDA*N
+ NULL = N.LE.0.OR.M.LE.0
+*
+* Generate the matrix A.
+*
+ TRANSL = ZERO
+ CALL DMAKE( SNAME( 2: 3 ), ' ', ' ', M, N, A, NMAX, AA,
+ $ LDA, KL, KU, RESET, TRANSL )
+*
+ DO 90 IC = 1, 3
+ TRANS = ICH( IC: IC )
+ TRAN = TRANS.EQ.'T'.OR.TRANS.EQ.'C'
+*
+ IF( TRAN )THEN
+ ML = N
+ NL = M
+ ELSE
+ ML = M
+ NL = N
+ END IF
+*
+ DO 80 IX = 1, NINC
+ INCX = INC( IX )
+ LX = ABS( INCX )*NL
+*
+* Generate the vector X.
+*
+ TRANSL = HALF
+ CALL DMAKE( 'GE', ' ', ' ', 1, NL, X, 1, XX,
+ $ ABS( INCX ), 0, NL - 1, RESET, TRANSL )
+ IF( NL.GT.1 )THEN
+ X( NL/2 ) = ZERO
+ XX( 1 + ABS( INCX )*( NL/2 - 1 ) ) = ZERO
+ END IF
+*
+ DO 70 IY = 1, NINC
+ INCY = INC( IY )
+ LY = ABS( INCY )*ML
+*
+ DO 60 IA = 1, NALF
+ ALPHA = ALF( IA )
+*
+ DO 50 IB = 1, NBET
+ BETA = BET( IB )
+*
+* Generate the vector Y.
+*
+ TRANSL = ZERO
+ CALL DMAKE( 'GE', ' ', ' ', 1, ML, Y, 1,
+ $ YY, ABS( INCY ), 0, ML - 1,
+ $ RESET, TRANSL )
+*
+ NC = NC + 1
+*
+* Save every datum before calling the
+* subroutine.
+*
+ TRANSS = TRANS
+ MS = M
+ NS = N
+ KLS = KL
+ KUS = KU
+ ALS = ALPHA
+ DO 10 I = 1, LAA
+ AS( I ) = AA( I )
+ 10 CONTINUE
+ LDAS = LDA
+ DO 20 I = 1, LX
+ XS( I ) = XX( I )
+ 20 CONTINUE
+ INCXS = INCX
+ BLS = BETA
+ DO 30 I = 1, LY
+ YS( I ) = YY( I )
+ 30 CONTINUE
+ INCYS = INCY
+*
+* Call the subroutine.
+*
+ IF( FULL )THEN
+ IF( TRACE )
+ $ WRITE( NTRA, FMT = 9994 )NC, SNAME,
+ $ TRANS, M, N, ALPHA, LDA, INCX, BETA,
+ $ INCY
+ IF( REWI )
+ $ REWIND NTRA
+ CALL DGEMV( TRANS, M, N, ALPHA, AA,
+ $ LDA, XX, INCX, BETA, YY,
+ $ INCY )
+ ELSE IF( BANDED )THEN
+ IF( TRACE )
+ $ WRITE( NTRA, FMT = 9995 )NC, SNAME,
+ $ TRANS, M, N, KL, KU, ALPHA, LDA,
+ $ INCX, BETA, INCY
+ IF( REWI )
+ $ REWIND NTRA
+ CALL DGBMV( TRANS, M, N, KL, KU, ALPHA,
+ $ AA, LDA, XX, INCX, BETA,
+ $ YY, INCY )
+ END IF
+*
+* Check if error-exit was taken incorrectly.
+*
+ IF( .NOT.OK )THEN
+ WRITE( NOUT, FMT = 9993 )
+ FATAL = .TRUE.
+ GO TO 130
+ END IF
+*
+* See what data changed inside subroutines.
+*
+ ISAME( 1 ) = TRANS.EQ.TRANSS
+ ISAME( 2 ) = MS.EQ.M
+ ISAME( 3 ) = NS.EQ.N
+ IF( FULL )THEN
+ ISAME( 4 ) = ALS.EQ.ALPHA
+ ISAME( 5 ) = LDE( AS, AA, LAA )
+ ISAME( 6 ) = LDAS.EQ.LDA
+ ISAME( 7 ) = LDE( XS, XX, LX )
+ ISAME( 8 ) = INCXS.EQ.INCX
+ ISAME( 9 ) = BLS.EQ.BETA
+ IF( NULL )THEN
+ ISAME( 10 ) = LDE( YS, YY, LY )
+ ELSE
+ ISAME( 10 ) = LDERES( 'GE', ' ', 1,
+ $ ML, YS, YY,
+ $ ABS( INCY ) )
+ END IF
+ ISAME( 11 ) = INCYS.EQ.INCY
+ ELSE IF( BANDED )THEN
+ ISAME( 4 ) = KLS.EQ.KL
+ ISAME( 5 ) = KUS.EQ.KU
+ ISAME( 6 ) = ALS.EQ.ALPHA
+ ISAME( 7 ) = LDE( AS, AA, LAA )
+ ISAME( 8 ) = LDAS.EQ.LDA
+ ISAME( 9 ) = LDE( XS, XX, LX )
+ ISAME( 10 ) = INCXS.EQ.INCX
+ ISAME( 11 ) = BLS.EQ.BETA
+ IF( NULL )THEN
+ ISAME( 12 ) = LDE( YS, YY, LY )
+ ELSE
+ ISAME( 12 ) = LDERES( 'GE', ' ', 1,
+ $ ML, YS, YY,
+ $ ABS( INCY ) )
+ END IF
+ ISAME( 13 ) = INCYS.EQ.INCY
+ END IF
+*
+* If data was incorrectly changed, report
+* and return.
+*
+ SAME = .TRUE.
+ DO 40 I = 1, NARGS
+ SAME = SAME.AND.ISAME( I )
+ IF( .NOT.ISAME( I ) )
+ $ WRITE( NOUT, FMT = 9998 )I
+ 40 CONTINUE
+ IF( .NOT.SAME )THEN
+ FATAL = .TRUE.
+ GO TO 130
+ END IF
+*
+ IF( .NOT.NULL )THEN
+*
+* Check the result.
+*
+ CALL DMVCH( TRANS, M, N, ALPHA, A,
+ $ NMAX, X, INCX, BETA, Y,
+ $ INCY, YT, G, YY, EPS, ERR,
+ $ FATAL, NOUT, .TRUE. )
+ ERRMAX = MAX( ERRMAX, ERR )
+* If got really bad answer, report and
+* return.
+ IF( FATAL )
+ $ GO TO 130
+ ELSE
+* Avoid repeating tests with M.le.0 or
+* N.le.0.
+ GO TO 110
+ END IF
+*
+ 50 CONTINUE
+*
+ 60 CONTINUE
+*
+ 70 CONTINUE
+*
+ 80 CONTINUE
+*
+ 90 CONTINUE
+*
+ 100 CONTINUE
+*
+ 110 CONTINUE
+*
+ 120 CONTINUE
+*
+* Report result.
+*
+ IF( ERRMAX.LT.THRESH )THEN
+ WRITE( NOUT, FMT = 9999 )SNAME, NC
+ ELSE
+ WRITE( NOUT, FMT = 9997 )SNAME, NC, ERRMAX
+ END IF
+ GO TO 140
+*
+ 130 CONTINUE
+ WRITE( NOUT, FMT = 9996 )SNAME
+ IF( FULL )THEN
+ WRITE( NOUT, FMT = 9994 )NC, SNAME, TRANS, M, N, ALPHA, LDA,
+ $ INCX, BETA, INCY
+ ELSE IF( BANDED )THEN
+ WRITE( NOUT, FMT = 9995 )NC, SNAME, TRANS, M, N, KL, KU,
+ $ ALPHA, LDA, INCX, BETA, INCY
+ END IF
+*
+ 140 CONTINUE
+ RETURN
+*
+ 9999 FORMAT( ' ', A6, ' PASSED THE COMPUTATIONAL TESTS (', I6, ' CALL',
+ $ 'S)' )
+ 9998 FORMAT( ' ******* FATAL ERROR - PARAMETER NUMBER ', I2, ' WAS CH',
+ $ 'ANGED INCORRECTLY *******' )
+ 9997 FORMAT( ' ', A6, ' COMPLETED THE COMPUTATIONAL TESTS (', I6, ' C',
+ $ 'ALLS)', /' ******* BUT WITH MAXIMUM TEST RATIO', F8.2,
+ $ ' - SUSPECT *******' )
+ 9996 FORMAT( ' ******* ', A6, ' FAILED ON CALL NUMBER:' )
+ 9995 FORMAT( 1X, I6, ': ', A6, '(''', A1, ''',', 4( I3, ',' ), F4.1,
+ $ ', A,', I3, ', X,', I2, ',', F4.1, ', Y,', I2, ') .' )
+ 9994 FORMAT( 1X, I6, ': ', A6, '(''', A1, ''',', 2( I3, ',' ), F4.1,
+ $ ', A,', I3, ', X,', I2, ',', F4.1, ', Y,', I2,
+ $ ') .' )
+ 9993 FORMAT( ' ******* FATAL ERROR - ERROR-EXIT TAKEN ON VALID CALL *',
+ $ '******' )
+*
+* End of DCHK1.
+*
+ END
+ SUBROUTINE DCHK2( SNAME, EPS, THRESH, NOUT, NTRA, TRACE, REWI,
+ $ FATAL, NIDIM, IDIM, NKB, KB, NALF, ALF, NBET,
+ $ BET, NINC, INC, NMAX, INCMAX, A, AA, AS, X, XX,
+ $ XS, Y, YY, YS, YT, G )
+*
+* Tests DSYMV, DSBMV and DSPMV.
+*
+* Auxiliary routine for test program for Level 2 Blas.
+*
+* -- Written on 10-August-1987.
+* Richard Hanson, Sandia National Labs.
+* Jeremy Du Croz, NAG Central Office.
+*
+* .. Parameters ..
+ DOUBLE PRECISION ZERO, HALF
+ PARAMETER ( ZERO = 0.0D0, HALF = 0.5D0 )
+* .. Scalar Arguments ..
+ DOUBLE PRECISION EPS, THRESH
+ INTEGER INCMAX, NALF, NBET, NIDIM, NINC, NKB, NMAX,
+ $ NOUT, NTRA
+ LOGICAL FATAL, REWI, TRACE
+ CHARACTER*6 SNAME
+* .. Array Arguments ..
+ DOUBLE PRECISION A( NMAX, NMAX ), AA( NMAX*NMAX ), ALF( NALF ),
+ $ AS( NMAX*NMAX ), BET( NBET ), G( NMAX ),
+ $ X( NMAX ), XS( NMAX*INCMAX ),
+ $ XX( NMAX*INCMAX ), Y( NMAX ),
+ $ YS( NMAX*INCMAX ), YT( NMAX ),
+ $ YY( NMAX*INCMAX )
+ INTEGER IDIM( NIDIM ), INC( NINC ), KB( NKB )
+* .. Local Scalars ..
+ DOUBLE PRECISION ALPHA, ALS, BETA, BLS, ERR, ERRMAX, TRANSL
+ INTEGER I, IA, IB, IC, IK, IN, INCX, INCXS, INCY,
+ $ INCYS, IX, IY, K, KS, LAA, LDA, LDAS, LX, LY,
+ $ N, NARGS, NC, NK, NS
+ LOGICAL BANDED, FULL, NULL, PACKED, RESET, SAME
+ CHARACTER*1 UPLO, UPLOS
+ CHARACTER*2 ICH
+* .. Local Arrays ..
+ LOGICAL ISAME( 13 )
+* .. External Functions ..
+ LOGICAL LDE, LDERES
+ EXTERNAL LDE, LDERES
+* .. External Subroutines ..
+ EXTERNAL DMAKE, DMVCH, DSBMV, DSPMV, DSYMV
+* .. Intrinsic Functions ..
+ INTRINSIC ABS, MAX
+* .. Scalars in Common ..
+ INTEGER INFOT, NOUTC
+ LOGICAL LERR, OK
+* .. Common blocks ..
+ COMMON /INFOC/INFOT, NOUTC, OK, LERR
+* .. Data statements ..
+ DATA ICH/'UL'/
+* .. Executable Statements ..
+ FULL = SNAME( 3: 3 ).EQ.'Y'
+ BANDED = SNAME( 3: 3 ).EQ.'B'
+ PACKED = SNAME( 3: 3 ).EQ.'P'
+* Define the number of arguments.
+ IF( FULL )THEN
+ NARGS = 10
+ ELSE IF( BANDED )THEN
+ NARGS = 11
+ ELSE IF( PACKED )THEN
+ NARGS = 9
+ END IF
+*
+ NC = 0
+ RESET = .TRUE.
+ ERRMAX = ZERO
+*
+ DO 110 IN = 1, NIDIM
+ N = IDIM( IN )
+*
+ IF( BANDED )THEN
+ NK = NKB
+ ELSE
+ NK = 1
+ END IF
+ DO 100 IK = 1, NK
+ IF( BANDED )THEN
+ K = KB( IK )
+ ELSE
+ K = N - 1
+ END IF
+* Set LDA to 1 more than minimum value if room.
+ IF( BANDED )THEN
+ LDA = K + 1
+ ELSE
+ LDA = N
+ END IF
+ IF( LDA.LT.NMAX )
+ $ LDA = LDA + 1
+* Skip tests if not enough room.
+ IF( LDA.GT.NMAX )
+ $ GO TO 100
+ IF( PACKED )THEN
+ LAA = ( N*( N + 1 ) )/2
+ ELSE
+ LAA = LDA*N
+ END IF
+ NULL = N.LE.0
+*
+ DO 90 IC = 1, 2
+ UPLO = ICH( IC: IC )
+*
+* Generate the matrix A.
+*
+ TRANSL = ZERO
+ CALL DMAKE( SNAME( 2: 3 ), UPLO, ' ', N, N, A, NMAX, AA,
+ $ LDA, K, K, RESET, TRANSL )
+*
+ DO 80 IX = 1, NINC
+ INCX = INC( IX )
+ LX = ABS( INCX )*N
+*
+* Generate the vector X.
+*
+ TRANSL = HALF
+ CALL DMAKE( 'GE', ' ', ' ', 1, N, X, 1, XX,
+ $ ABS( INCX ), 0, N - 1, RESET, TRANSL )
+ IF( N.GT.1 )THEN
+ X( N/2 ) = ZERO
+ XX( 1 + ABS( INCX )*( N/2 - 1 ) ) = ZERO
+ END IF
+*
+ DO 70 IY = 1, NINC
+ INCY = INC( IY )
+ LY = ABS( INCY )*N
+*
+ DO 60 IA = 1, NALF
+ ALPHA = ALF( IA )
+*
+ DO 50 IB = 1, NBET
+ BETA = BET( IB )
+*
+* Generate the vector Y.
+*
+ TRANSL = ZERO
+ CALL DMAKE( 'GE', ' ', ' ', 1, N, Y, 1, YY,
+ $ ABS( INCY ), 0, N - 1, RESET,
+ $ TRANSL )
+*
+ NC = NC + 1
+*
+* Save every datum before calling the
+* subroutine.
+*
+ UPLOS = UPLO
+ NS = N
+ KS = K
+ ALS = ALPHA
+ DO 10 I = 1, LAA
+ AS( I ) = AA( I )
+ 10 CONTINUE
+ LDAS = LDA
+ DO 20 I = 1, LX
+ XS( I ) = XX( I )
+ 20 CONTINUE
+ INCXS = INCX
+ BLS = BETA
+ DO 30 I = 1, LY
+ YS( I ) = YY( I )
+ 30 CONTINUE
+ INCYS = INCY
+*
+* Call the subroutine.
+*
+ IF( FULL )THEN
+ IF( TRACE )
+ $ WRITE( NTRA, FMT = 9993 )NC, SNAME,
+ $ UPLO, N, ALPHA, LDA, INCX, BETA, INCY
+ IF( REWI )
+ $ REWIND NTRA
+ CALL DSYMV( UPLO, N, ALPHA, AA, LDA, XX,
+ $ INCX, BETA, YY, INCY )
+ ELSE IF( BANDED )THEN
+ IF( TRACE )
+ $ WRITE( NTRA, FMT = 9994 )NC, SNAME,
+ $ UPLO, N, K, ALPHA, LDA, INCX, BETA,
+ $ INCY
+ IF( REWI )
+ $ REWIND NTRA
+ CALL DSBMV( UPLO, N, K, ALPHA, AA, LDA,
+ $ XX, INCX, BETA, YY, INCY )
+ ELSE IF( PACKED )THEN
+ IF( TRACE )
+ $ WRITE( NTRA, FMT = 9995 )NC, SNAME,
+ $ UPLO, N, ALPHA, INCX, BETA, INCY
+ IF( REWI )
+ $ REWIND NTRA
+ CALL DSPMV( UPLO, N, ALPHA, AA, XX, INCX,
+ $ BETA, YY, INCY )
+ END IF
+*
+* Check if error-exit was taken incorrectly.
+*
+ IF( .NOT.OK )THEN
+ WRITE( NOUT, FMT = 9992 )
+ FATAL = .TRUE.
+ GO TO 120
+ END IF
+*
+* See what data changed inside subroutines.
+*
+ ISAME( 1 ) = UPLO.EQ.UPLOS
+ ISAME( 2 ) = NS.EQ.N
+ IF( FULL )THEN
+ ISAME( 3 ) = ALS.EQ.ALPHA
+ ISAME( 4 ) = LDE( AS, AA, LAA )
+ ISAME( 5 ) = LDAS.EQ.LDA
+ ISAME( 6 ) = LDE( XS, XX, LX )
+ ISAME( 7 ) = INCXS.EQ.INCX
+ ISAME( 8 ) = BLS.EQ.BETA
+ IF( NULL )THEN
+ ISAME( 9 ) = LDE( YS, YY, LY )
+ ELSE
+ ISAME( 9 ) = LDERES( 'GE', ' ', 1, N,
+ $ YS, YY, ABS( INCY ) )
+ END IF
+ ISAME( 10 ) = INCYS.EQ.INCY
+ ELSE IF( BANDED )THEN
+ ISAME( 3 ) = KS.EQ.K
+ ISAME( 4 ) = ALS.EQ.ALPHA
+ ISAME( 5 ) = LDE( AS, AA, LAA )
+ ISAME( 6 ) = LDAS.EQ.LDA
+ ISAME( 7 ) = LDE( XS, XX, LX )
+ ISAME( 8 ) = INCXS.EQ.INCX
+ ISAME( 9 ) = BLS.EQ.BETA
+ IF( NULL )THEN
+ ISAME( 10 ) = LDE( YS, YY, LY )
+ ELSE
+ ISAME( 10 ) = LDERES( 'GE', ' ', 1, N,
+ $ YS, YY, ABS( INCY ) )
+ END IF
+ ISAME( 11 ) = INCYS.EQ.INCY
+ ELSE IF( PACKED )THEN
+ ISAME( 3 ) = ALS.EQ.ALPHA
+ ISAME( 4 ) = LDE( AS, AA, LAA )
+ ISAME( 5 ) = LDE( XS, XX, LX )
+ ISAME( 6 ) = INCXS.EQ.INCX
+ ISAME( 7 ) = BLS.EQ.BETA
+ IF( NULL )THEN
+ ISAME( 8 ) = LDE( YS, YY, LY )
+ ELSE
+ ISAME( 8 ) = LDERES( 'GE', ' ', 1, N,
+ $ YS, YY, ABS( INCY ) )
+ END IF
+ ISAME( 9 ) = INCYS.EQ.INCY
+ END IF
+*
+* If data was incorrectly changed, report and
+* return.
+*
+ SAME = .TRUE.
+ DO 40 I = 1, NARGS
+ SAME = SAME.AND.ISAME( I )
+ IF( .NOT.ISAME( I ) )
+ $ WRITE( NOUT, FMT = 9998 )I
+ 40 CONTINUE
+ IF( .NOT.SAME )THEN
+ FATAL = .TRUE.
+ GO TO 120
+ END IF
+*
+ IF( .NOT.NULL )THEN
+*
+* Check the result.
+*
+ CALL DMVCH( 'N', N, N, ALPHA, A, NMAX, X,
+ $ INCX, BETA, Y, INCY, YT, G,
+ $ YY, EPS, ERR, FATAL, NOUT,
+ $ .TRUE. )
+ ERRMAX = MAX( ERRMAX, ERR )
+* If got really bad answer, report and
+* return.
+ IF( FATAL )
+ $ GO TO 120
+ ELSE
+* Avoid repeating tests with N.le.0
+ GO TO 110
+ END IF
+*
+ 50 CONTINUE
+*
+ 60 CONTINUE
+*
+ 70 CONTINUE
+*
+ 80 CONTINUE
+*
+ 90 CONTINUE
+*
+ 100 CONTINUE
+*
+ 110 CONTINUE
+*
+* Report result.
+*
+ IF( ERRMAX.LT.THRESH )THEN
+ WRITE( NOUT, FMT = 9999 )SNAME, NC
+ ELSE
+ WRITE( NOUT, FMT = 9997 )SNAME, NC, ERRMAX
+ END IF
+ GO TO 130
+*
+ 120 CONTINUE
+ WRITE( NOUT, FMT = 9996 )SNAME
+ IF( FULL )THEN
+ WRITE( NOUT, FMT = 9993 )NC, SNAME, UPLO, N, ALPHA, LDA, INCX,
+ $ BETA, INCY
+ ELSE IF( BANDED )THEN
+ WRITE( NOUT, FMT = 9994 )NC, SNAME, UPLO, N, K, ALPHA, LDA,
+ $ INCX, BETA, INCY
+ ELSE IF( PACKED )THEN
+ WRITE( NOUT, FMT = 9995 )NC, SNAME, UPLO, N, ALPHA, INCX,
+ $ BETA, INCY
+ END IF
+*
+ 130 CONTINUE
+ RETURN
+*
+ 9999 FORMAT( ' ', A6, ' PASSED THE COMPUTATIONAL TESTS (', I6, ' CALL',
+ $ 'S)' )
+ 9998 FORMAT( ' ******* FATAL ERROR - PARAMETER NUMBER ', I2, ' WAS CH',
+ $ 'ANGED INCORRECTLY *******' )
+ 9997 FORMAT( ' ', A6, ' COMPLETED THE COMPUTATIONAL TESTS (', I6, ' C',
+ $ 'ALLS)', /' ******* BUT WITH MAXIMUM TEST RATIO', F8.2,
+ $ ' - SUSPECT *******' )
+ 9996 FORMAT( ' ******* ', A6, ' FAILED ON CALL NUMBER:' )
+ 9995 FORMAT( 1X, I6, ': ', A6, '(''', A1, ''',', I3, ',', F4.1, ', AP',
+ $ ', X,', I2, ',', F4.1, ', Y,', I2, ') .' )
+ 9994 FORMAT( 1X, I6, ': ', A6, '(''', A1, ''',', 2( I3, ',' ), F4.1,
+ $ ', A,', I3, ', X,', I2, ',', F4.1, ', Y,', I2,
+ $ ') .' )
+ 9993 FORMAT( 1X, I6, ': ', A6, '(''', A1, ''',', I3, ',', F4.1, ', A,',
+ $ I3, ', X,', I2, ',', F4.1, ', Y,', I2, ') .' )
+ 9992 FORMAT( ' ******* FATAL ERROR - ERROR-EXIT TAKEN ON VALID CALL *',
+ $ '******' )
+*
+* End of DCHK2.
+*
+ END
+ SUBROUTINE DCHK3( SNAME, EPS, THRESH, NOUT, NTRA, TRACE, REWI,
+ $ FATAL, NIDIM, IDIM, NKB, KB, NINC, INC, NMAX,
+ $ INCMAX, A, AA, AS, X, XX, XS, XT, G, Z )
+*
+* Tests DTRMV, DTBMV, DTPMV, DTRSV, DTBSV and DTPSV.
+*
+* Auxiliary routine for test program for Level 2 Blas.
+*
+* -- Written on 10-August-1987.
+* Richard Hanson, Sandia National Labs.
+* Jeremy Du Croz, NAG Central Office.
+*
+* .. Parameters ..
+ DOUBLE PRECISION ZERO, HALF, ONE
+ PARAMETER ( ZERO = 0.0D0, HALF = 0.5D0, ONE = 1.0D0 )
+* .. Scalar Arguments ..
+ DOUBLE PRECISION EPS, THRESH
+ INTEGER INCMAX, NIDIM, NINC, NKB, NMAX, NOUT, NTRA
+ LOGICAL FATAL, REWI, TRACE
+ CHARACTER*6 SNAME
+* .. Array Arguments ..
+ DOUBLE PRECISION A( NMAX, NMAX ), AA( NMAX*NMAX ),
+ $ AS( NMAX*NMAX ), G( NMAX ), X( NMAX ),
+ $ XS( NMAX*INCMAX ), XT( NMAX ),
+ $ XX( NMAX*INCMAX ), Z( NMAX )
+ INTEGER IDIM( NIDIM ), INC( NINC ), KB( NKB )
+* .. Local Scalars ..
+ DOUBLE PRECISION ERR, ERRMAX, TRANSL
+ INTEGER I, ICD, ICT, ICU, IK, IN, INCX, INCXS, IX, K,
+ $ KS, LAA, LDA, LDAS, LX, N, NARGS, NC, NK, NS
+ LOGICAL BANDED, FULL, NULL, PACKED, RESET, SAME
+ CHARACTER*1 DIAG, DIAGS, TRANS, TRANSS, UPLO, UPLOS
+ CHARACTER*2 ICHD, ICHU
+ CHARACTER*3 ICHT
+* .. Local Arrays ..
+ LOGICAL ISAME( 13 )
+* .. External Functions ..
+ LOGICAL LDE, LDERES
+ EXTERNAL LDE, LDERES
+* .. External Subroutines ..
+ EXTERNAL DMAKE, DMVCH, DTBMV, DTBSV, DTPMV, DTPSV,
+ $ DTRMV, DTRSV
+* .. Intrinsic Functions ..
+ INTRINSIC ABS, MAX
+* .. Scalars in Common ..
+ INTEGER INFOT, NOUTC
+ LOGICAL LERR, OK
+* .. Common blocks ..
+ COMMON /INFOC/INFOT, NOUTC, OK, LERR
+* .. Data statements ..
+ DATA ICHU/'UL'/, ICHT/'NTC'/, ICHD/'UN'/
+* .. Executable Statements ..
+ FULL = SNAME( 3: 3 ).EQ.'R'
+ BANDED = SNAME( 3: 3 ).EQ.'B'
+ PACKED = SNAME( 3: 3 ).EQ.'P'
+* Define the number of arguments.
+ IF( FULL )THEN
+ NARGS = 8
+ ELSE IF( BANDED )THEN
+ NARGS = 9
+ ELSE IF( PACKED )THEN
+ NARGS = 7
+ END IF
+*
+ NC = 0
+ RESET = .TRUE.
+ ERRMAX = ZERO
+* Set up zero vector for DMVCH.
+ DO 10 I = 1, NMAX
+ Z( I ) = ZERO
+ 10 CONTINUE
+*
+ DO 110 IN = 1, NIDIM
+ N = IDIM( IN )
+*
+ IF( BANDED )THEN
+ NK = NKB
+ ELSE
+ NK = 1
+ END IF
+ DO 100 IK = 1, NK
+ IF( BANDED )THEN
+ K = KB( IK )
+ ELSE
+ K = N - 1
+ END IF
+* Set LDA to 1 more than minimum value if room.
+ IF( BANDED )THEN
+ LDA = K + 1
+ ELSE
+ LDA = N
+ END IF
+ IF( LDA.LT.NMAX )
+ $ LDA = LDA + 1
+* Skip tests if not enough room.
+ IF( LDA.GT.NMAX )
+ $ GO TO 100
+ IF( PACKED )THEN
+ LAA = ( N*( N + 1 ) )/2
+ ELSE
+ LAA = LDA*N
+ END IF
+ NULL = N.LE.0
+*
+ DO 90 ICU = 1, 2
+ UPLO = ICHU( ICU: ICU )
+*
+ DO 80 ICT = 1, 3
+ TRANS = ICHT( ICT: ICT )
+*
+ DO 70 ICD = 1, 2
+ DIAG = ICHD( ICD: ICD )
+*
+* Generate the matrix A.
+*
+ TRANSL = ZERO
+ CALL DMAKE( SNAME( 2: 3 ), UPLO, DIAG, N, N, A,
+ $ NMAX, AA, LDA, K, K, RESET, TRANSL )
+*
+ DO 60 IX = 1, NINC
+ INCX = INC( IX )
+ LX = ABS( INCX )*N
+*
+* Generate the vector X.
+*
+ TRANSL = HALF
+ CALL DMAKE( 'GE', ' ', ' ', 1, N, X, 1, XX,
+ $ ABS( INCX ), 0, N - 1, RESET,
+ $ TRANSL )
+ IF( N.GT.1 )THEN
+ X( N/2 ) = ZERO
+ XX( 1 + ABS( INCX )*( N/2 - 1 ) ) = ZERO
+ END IF
+*
+ NC = NC + 1
+*
+* Save every datum before calling the subroutine.
+*
+ UPLOS = UPLO
+ TRANSS = TRANS
+ DIAGS = DIAG
+ NS = N
+ KS = K
+ DO 20 I = 1, LAA
+ AS( I ) = AA( I )
+ 20 CONTINUE
+ LDAS = LDA
+ DO 30 I = 1, LX
+ XS( I ) = XX( I )
+ 30 CONTINUE
+ INCXS = INCX
+*
+* Call the subroutine.
+*
+ IF( SNAME( 4: 5 ).EQ.'MV' )THEN
+ IF( FULL )THEN
+ IF( TRACE )
+ $ WRITE( NTRA, FMT = 9993 )NC, SNAME,
+ $ UPLO, TRANS, DIAG, N, LDA, INCX
+ IF( REWI )
+ $ REWIND NTRA
+ CALL DTRMV( UPLO, TRANS, DIAG, N, AA, LDA,
+ $ XX, INCX )
+ ELSE IF( BANDED )THEN
+ IF( TRACE )
+ $ WRITE( NTRA, FMT = 9994 )NC, SNAME,
+ $ UPLO, TRANS, DIAG, N, K, LDA, INCX
+ IF( REWI )
+ $ REWIND NTRA
+ CALL DTBMV( UPLO, TRANS, DIAG, N, K, AA,
+ $ LDA, XX, INCX )
+ ELSE IF( PACKED )THEN
+ IF( TRACE )
+ $ WRITE( NTRA, FMT = 9995 )NC, SNAME,
+ $ UPLO, TRANS, DIAG, N, INCX
+ IF( REWI )
+ $ REWIND NTRA
+ CALL DTPMV( UPLO, TRANS, DIAG, N, AA, XX,
+ $ INCX )
+ END IF
+ ELSE IF( SNAME( 4: 5 ).EQ.'SV' )THEN
+ IF( FULL )THEN
+ IF( TRACE )
+ $ WRITE( NTRA, FMT = 9993 )NC, SNAME,
+ $ UPLO, TRANS, DIAG, N, LDA, INCX
+ IF( REWI )
+ $ REWIND NTRA
+ CALL DTRSV( UPLO, TRANS, DIAG, N, AA, LDA,
+ $ XX, INCX )
+ ELSE IF( BANDED )THEN
+ IF( TRACE )
+ $ WRITE( NTRA, FMT = 9994 )NC, SNAME,
+ $ UPLO, TRANS, DIAG, N, K, LDA, INCX
+ IF( REWI )
+ $ REWIND NTRA
+ CALL DTBSV( UPLO, TRANS, DIAG, N, K, AA,
+ $ LDA, XX, INCX )
+ ELSE IF( PACKED )THEN
+ IF( TRACE )
+ $ WRITE( NTRA, FMT = 9995 )NC, SNAME,
+ $ UPLO, TRANS, DIAG, N, INCX
+ IF( REWI )
+ $ REWIND NTRA
+ CALL DTPSV( UPLO, TRANS, DIAG, N, AA, XX,
+ $ INCX )
+ END IF
+ END IF
+*
+* Check if error-exit was taken incorrectly.
+*
+ IF( .NOT.OK )THEN
+ WRITE( NOUT, FMT = 9992 )
+ FATAL = .TRUE.
+ GO TO 120
+ END IF
+*
+* See what data changed inside subroutines.
+*
+ ISAME( 1 ) = UPLO.EQ.UPLOS
+ ISAME( 2 ) = TRANS.EQ.TRANSS
+ ISAME( 3 ) = DIAG.EQ.DIAGS
+ ISAME( 4 ) = NS.EQ.N
+ IF( FULL )THEN
+ ISAME( 5 ) = LDE( AS, AA, LAA )
+ ISAME( 6 ) = LDAS.EQ.LDA
+ IF( NULL )THEN
+ ISAME( 7 ) = LDE( XS, XX, LX )
+ ELSE
+ ISAME( 7 ) = LDERES( 'GE', ' ', 1, N, XS,
+ $ XX, ABS( INCX ) )
+ END IF
+ ISAME( 8 ) = INCXS.EQ.INCX
+ ELSE IF( BANDED )THEN
+ ISAME( 5 ) = KS.EQ.K
+ ISAME( 6 ) = LDE( AS, AA, LAA )
+ ISAME( 7 ) = LDAS.EQ.LDA
+ IF( NULL )THEN
+ ISAME( 8 ) = LDE( XS, XX, LX )
+ ELSE
+ ISAME( 8 ) = LDERES( 'GE', ' ', 1, N, XS,
+ $ XX, ABS( INCX ) )
+ END IF
+ ISAME( 9 ) = INCXS.EQ.INCX
+ ELSE IF( PACKED )THEN
+ ISAME( 5 ) = LDE( AS, AA, LAA )
+ IF( NULL )THEN
+ ISAME( 6 ) = LDE( XS, XX, LX )
+ ELSE
+ ISAME( 6 ) = LDERES( 'GE', ' ', 1, N, XS,
+ $ XX, ABS( INCX ) )
+ END IF
+ ISAME( 7 ) = INCXS.EQ.INCX
+ END IF
+*
+* If data was incorrectly changed, report and
+* return.
+*
+ SAME = .TRUE.
+ DO 40 I = 1, NARGS
+ SAME = SAME.AND.ISAME( I )
+ IF( .NOT.ISAME( I ) )
+ $ WRITE( NOUT, FMT = 9998 )I
+ 40 CONTINUE
+ IF( .NOT.SAME )THEN
+ FATAL = .TRUE.
+ GO TO 120
+ END IF
+*
+ IF( .NOT.NULL )THEN
+ IF( SNAME( 4: 5 ).EQ.'MV' )THEN
+*
+* Check the result.
+*
+ CALL DMVCH( TRANS, N, N, ONE, A, NMAX, X,
+ $ INCX, ZERO, Z, INCX, XT, G,
+ $ XX, EPS, ERR, FATAL, NOUT,
+ $ .TRUE. )
+ ELSE IF( SNAME( 4: 5 ).EQ.'SV' )THEN
+*
+* Compute approximation to original vector.
+*
+ DO 50 I = 1, N
+ Z( I ) = XX( 1 + ( I - 1 )*
+ $ ABS( INCX ) )
+ XX( 1 + ( I - 1 )*ABS( INCX ) )
+ $ = X( I )
+ 50 CONTINUE
+ CALL DMVCH( TRANS, N, N, ONE, A, NMAX, Z,
+ $ INCX, ZERO, X, INCX, XT, G,
+ $ XX, EPS, ERR, FATAL, NOUT,
+ $ .FALSE. )
+ END IF
+ ERRMAX = MAX( ERRMAX, ERR )
+* If got really bad answer, report and return.
+ IF( FATAL )
+ $ GO TO 120
+ ELSE
+* Avoid repeating tests with N.le.0.
+ GO TO 110
+ END IF
+*
+ 60 CONTINUE
+*
+ 70 CONTINUE
+*
+ 80 CONTINUE
+*
+ 90 CONTINUE
+*
+ 100 CONTINUE
+*
+ 110 CONTINUE
+*
+* Report result.
+*
+ IF( ERRMAX.LT.THRESH )THEN
+ WRITE( NOUT, FMT = 9999 )SNAME, NC
+ ELSE
+ WRITE( NOUT, FMT = 9997 )SNAME, NC, ERRMAX
+ END IF
+ GO TO 130
+*
+ 120 CONTINUE
+ WRITE( NOUT, FMT = 9996 )SNAME
+ IF( FULL )THEN
+ WRITE( NOUT, FMT = 9993 )NC, SNAME, UPLO, TRANS, DIAG, N, LDA,
+ $ INCX
+ ELSE IF( BANDED )THEN
+ WRITE( NOUT, FMT = 9994 )NC, SNAME, UPLO, TRANS, DIAG, N, K,
+ $ LDA, INCX
+ ELSE IF( PACKED )THEN
+ WRITE( NOUT, FMT = 9995 )NC, SNAME, UPLO, TRANS, DIAG, N, INCX
+ END IF
+*
+ 130 CONTINUE
+ RETURN
+*
+ 9999 FORMAT( ' ', A6, ' PASSED THE COMPUTATIONAL TESTS (', I6, ' CALL',
+ $ 'S)' )
+ 9998 FORMAT( ' ******* FATAL ERROR - PARAMETER NUMBER ', I2, ' WAS CH',
+ $ 'ANGED INCORRECTLY *******' )
+ 9997 FORMAT( ' ', A6, ' COMPLETED THE COMPUTATIONAL TESTS (', I6, ' C',
+ $ 'ALLS)', /' ******* BUT WITH MAXIMUM TEST RATIO', F8.2,
+ $ ' - SUSPECT *******' )
+ 9996 FORMAT( ' ******* ', A6, ' FAILED ON CALL NUMBER:' )
+ 9995 FORMAT( 1X, I6, ': ', A6, '(', 3( '''', A1, ''',' ), I3, ', AP, ',
+ $ 'X,', I2, ') .' )
+ 9994 FORMAT( 1X, I6, ': ', A6, '(', 3( '''', A1, ''',' ), 2( I3, ',' ),
+ $ ' A,', I3, ', X,', I2, ') .' )
+ 9993 FORMAT( 1X, I6, ': ', A6, '(', 3( '''', A1, ''',' ), I3, ', A,',
+ $ I3, ', X,', I2, ') .' )
+ 9992 FORMAT( ' ******* FATAL ERROR - ERROR-EXIT TAKEN ON VALID CALL *',
+ $ '******' )
+*
+* End of DCHK3.
+*
+ END
+ SUBROUTINE DCHK4( SNAME, EPS, THRESH, NOUT, NTRA, TRACE, REWI,
+ $ FATAL, NIDIM, IDIM, NALF, ALF, NINC, INC, NMAX,
+ $ INCMAX, A, AA, AS, X, XX, XS, Y, YY, YS, YT, G,
+ $ Z )
+*
+* Tests DGER.
+*
+* Auxiliary routine for test program for Level 2 Blas.
+*
+* -- Written on 10-August-1987.
+* Richard Hanson, Sandia National Labs.
+* Jeremy Du Croz, NAG Central Office.
+*
+* .. Parameters ..
+ DOUBLE PRECISION ZERO, HALF, ONE
+ PARAMETER ( ZERO = 0.0D0, HALF = 0.5D0, ONE = 1.0D0 )
+* .. Scalar Arguments ..
+ DOUBLE PRECISION EPS, THRESH
+ INTEGER INCMAX, NALF, NIDIM, NINC, NMAX, NOUT, NTRA
+ LOGICAL FATAL, REWI, TRACE
+ CHARACTER*6 SNAME
+* .. Array Arguments ..
+ DOUBLE PRECISION A( NMAX, NMAX ), AA( NMAX*NMAX ), ALF( NALF ),
+ $ AS( NMAX*NMAX ), G( NMAX ), X( NMAX ),
+ $ XS( NMAX*INCMAX ), XX( NMAX*INCMAX ),
+ $ Y( NMAX ), YS( NMAX*INCMAX ), YT( NMAX ),
+ $ YY( NMAX*INCMAX ), Z( NMAX )
+ INTEGER IDIM( NIDIM ), INC( NINC )
+* .. Local Scalars ..
+ DOUBLE PRECISION ALPHA, ALS, ERR, ERRMAX, TRANSL
+ INTEGER I, IA, IM, IN, INCX, INCXS, INCY, INCYS, IX,
+ $ IY, J, LAA, LDA, LDAS, LX, LY, M, MS, N, NARGS,
+ $ NC, ND, NS
+ LOGICAL NULL, RESET, SAME
+* .. Local Arrays ..
+ DOUBLE PRECISION W( 1 )
+ LOGICAL ISAME( 13 )
+* .. External Functions ..
+ LOGICAL LDE, LDERES
+ EXTERNAL LDE, LDERES
+* .. External Subroutines ..
+ EXTERNAL DGER, DMAKE, DMVCH
+* .. Intrinsic Functions ..
+ INTRINSIC ABS, MAX, MIN
+* .. Scalars in Common ..
+ INTEGER INFOT, NOUTC
+ LOGICAL LERR, OK
+* .. Common blocks ..
+ COMMON /INFOC/INFOT, NOUTC, OK, LERR
+* .. Executable Statements ..
+* Define the number of arguments.
+ NARGS = 9
+*
+ NC = 0
+ RESET = .TRUE.
+ ERRMAX = ZERO
+*
+ DO 120 IN = 1, NIDIM
+ N = IDIM( IN )
+ ND = N/2 + 1
+*
+ DO 110 IM = 1, 2
+ IF( IM.EQ.1 )
+ $ M = MAX( N - ND, 0 )
+ IF( IM.EQ.2 )
+ $ M = MIN( N + ND, NMAX )
+*
+* Set LDA to 1 more than minimum value if room.
+ LDA = M
+ IF( LDA.LT.NMAX )
+ $ LDA = LDA + 1
+* Skip tests if not enough room.
+ IF( LDA.GT.NMAX )
+ $ GO TO 110
+ LAA = LDA*N
+ NULL = N.LE.0.OR.M.LE.0
+*
+ DO 100 IX = 1, NINC
+ INCX = INC( IX )
+ LX = ABS( INCX )*M
+*
+* Generate the vector X.
+*
+ TRANSL = HALF
+ CALL DMAKE( 'GE', ' ', ' ', 1, M, X, 1, XX, ABS( INCX ),
+ $ 0, M - 1, RESET, TRANSL )
+ IF( M.GT.1 )THEN
+ X( M/2 ) = ZERO
+ XX( 1 + ABS( INCX )*( M/2 - 1 ) ) = ZERO
+ END IF
+*
+ DO 90 IY = 1, NINC
+ INCY = INC( IY )
+ LY = ABS( INCY )*N
+*
+* Generate the vector Y.
+*
+ TRANSL = ZERO
+ CALL DMAKE( 'GE', ' ', ' ', 1, N, Y, 1, YY,
+ $ ABS( INCY ), 0, N - 1, RESET, TRANSL )
+ IF( N.GT.1 )THEN
+ Y( N/2 ) = ZERO
+ YY( 1 + ABS( INCY )*( N/2 - 1 ) ) = ZERO
+ END IF
+*
+ DO 80 IA = 1, NALF
+ ALPHA = ALF( IA )
+*
+* Generate the matrix A.
+*
+ TRANSL = ZERO
+ CALL DMAKE( SNAME( 2: 3 ), ' ', ' ', M, N, A, NMAX,
+ $ AA, LDA, M - 1, N - 1, RESET, TRANSL )
+*
+ NC = NC + 1
+*
+* Save every datum before calling the subroutine.
+*
+ MS = M
+ NS = N
+ ALS = ALPHA
+ DO 10 I = 1, LAA
+ AS( I ) = AA( I )
+ 10 CONTINUE
+ LDAS = LDA
+ DO 20 I = 1, LX
+ XS( I ) = XX( I )
+ 20 CONTINUE
+ INCXS = INCX
+ DO 30 I = 1, LY
+ YS( I ) = YY( I )
+ 30 CONTINUE
+ INCYS = INCY
+*
+* Call the subroutine.
+*
+ IF( TRACE )
+ $ WRITE( NTRA, FMT = 9994 )NC, SNAME, M, N,
+ $ ALPHA, INCX, INCY, LDA
+ IF( REWI )
+ $ REWIND NTRA
+ CALL DGER( M, N, ALPHA, XX, INCX, YY, INCY, AA,
+ $ LDA )
+*
+* Check if error-exit was taken incorrectly.
+*
+ IF( .NOT.OK )THEN
+ WRITE( NOUT, FMT = 9993 )
+ FATAL = .TRUE.
+ GO TO 140
+ END IF
+*
+* See what data changed inside subroutine.
+*
+ ISAME( 1 ) = MS.EQ.M
+ ISAME( 2 ) = NS.EQ.N
+ ISAME( 3 ) = ALS.EQ.ALPHA
+ ISAME( 4 ) = LDE( XS, XX, LX )
+ ISAME( 5 ) = INCXS.EQ.INCX
+ ISAME( 6 ) = LDE( YS, YY, LY )
+ ISAME( 7 ) = INCYS.EQ.INCY
+ IF( NULL )THEN
+ ISAME( 8 ) = LDE( AS, AA, LAA )
+ ELSE
+ ISAME( 8 ) = LDERES( 'GE', ' ', M, N, AS, AA,
+ $ LDA )
+ END IF
+ ISAME( 9 ) = LDAS.EQ.LDA
+*
+* If data was incorrectly changed, report and return.
+*
+ SAME = .TRUE.
+ DO 40 I = 1, NARGS
+ SAME = SAME.AND.ISAME( I )
+ IF( .NOT.ISAME( I ) )
+ $ WRITE( NOUT, FMT = 9998 )I
+ 40 CONTINUE
+ IF( .NOT.SAME )THEN
+ FATAL = .TRUE.
+ GO TO 140
+ END IF
+*
+ IF( .NOT.NULL )THEN
+*
+* Check the result column by column.
+*
+ IF( INCX.GT.0 )THEN
+ DO 50 I = 1, M
+ Z( I ) = X( I )
+ 50 CONTINUE
+ ELSE
+ DO 60 I = 1, M
+ Z( I ) = X( M - I + 1 )
+ 60 CONTINUE
+ END IF
+ DO 70 J = 1, N
+ IF( INCY.GT.0 )THEN
+ W( 1 ) = Y( J )
+ ELSE
+ W( 1 ) = Y( N - J + 1 )
+ END IF
+ CALL DMVCH( 'N', M, 1, ALPHA, Z, NMAX, W, 1,
+ $ ONE, A( 1, J ), 1, YT, G,
+ $ AA( 1 + ( J - 1 )*LDA ), EPS,
+ $ ERR, FATAL, NOUT, .TRUE. )
+ ERRMAX = MAX( ERRMAX, ERR )
+* If got really bad answer, report and return.
+ IF( FATAL )
+ $ GO TO 130
+ 70 CONTINUE
+ ELSE
+* Avoid repeating tests with M.le.0 or N.le.0.
+ GO TO 110
+ END IF
+*
+ 80 CONTINUE
+*
+ 90 CONTINUE
+*
+ 100 CONTINUE
+*
+ 110 CONTINUE
+*
+ 120 CONTINUE
+*
+* Report result.
+*
+ IF( ERRMAX.LT.THRESH )THEN
+ WRITE( NOUT, FMT = 9999 )SNAME, NC
+ ELSE
+ WRITE( NOUT, FMT = 9997 )SNAME, NC, ERRMAX
+ END IF
+ GO TO 150
+*
+ 130 CONTINUE
+ WRITE( NOUT, FMT = 9995 )J
+*
+ 140 CONTINUE
+ WRITE( NOUT, FMT = 9996 )SNAME
+ WRITE( NOUT, FMT = 9994 )NC, SNAME, M, N, ALPHA, INCX, INCY, LDA
+*
+ 150 CONTINUE
+ RETURN
+*
+ 9999 FORMAT( ' ', A6, ' PASSED THE COMPUTATIONAL TESTS (', I6, ' CALL',
+ $ 'S)' )
+ 9998 FORMAT( ' ******* FATAL ERROR - PARAMETER NUMBER ', I2, ' WAS CH',
+ $ 'ANGED INCORRECTLY *******' )
+ 9997 FORMAT( ' ', A6, ' COMPLETED THE COMPUTATIONAL TESTS (', I6, ' C',
+ $ 'ALLS)', /' ******* BUT WITH MAXIMUM TEST RATIO', F8.2,
+ $ ' - SUSPECT *******' )
+ 9996 FORMAT( ' ******* ', A6, ' FAILED ON CALL NUMBER:' )
+ 9995 FORMAT( ' THESE ARE THE RESULTS FOR COLUMN ', I3 )
+ 9994 FORMAT( 1X, I6, ': ', A6, '(', 2( I3, ',' ), F4.1, ', X,', I2,
+ $ ', Y,', I2, ', A,', I3, ') .' )
+ 9993 FORMAT( ' ******* FATAL ERROR - ERROR-EXIT TAKEN ON VALID CALL *',
+ $ '******' )
+*
+* End of DCHK4.
+*
+ END
+ SUBROUTINE DCHK5( SNAME, EPS, THRESH, NOUT, NTRA, TRACE, REWI,
+ $ FATAL, NIDIM, IDIM, NALF, ALF, NINC, INC, NMAX,
+ $ INCMAX, A, AA, AS, X, XX, XS, Y, YY, YS, YT, G,
+ $ Z )
+*
+* Tests DSYR and DSPR.
+*
+* Auxiliary routine for test program for Level 2 Blas.
+*
+* -- Written on 10-August-1987.
+* Richard Hanson, Sandia National Labs.
+* Jeremy Du Croz, NAG Central Office.
+*
+* .. Parameters ..
+ DOUBLE PRECISION ZERO, HALF, ONE
+ PARAMETER ( ZERO = 0.0D0, HALF = 0.5D0, ONE = 1.0D0 )
+* .. Scalar Arguments ..
+ DOUBLE PRECISION EPS, THRESH
+ INTEGER INCMAX, NALF, NIDIM, NINC, NMAX, NOUT, NTRA
+ LOGICAL FATAL, REWI, TRACE
+ CHARACTER*6 SNAME
+* .. Array Arguments ..
+ DOUBLE PRECISION A( NMAX, NMAX ), AA( NMAX*NMAX ), ALF( NALF ),
+ $ AS( NMAX*NMAX ), G( NMAX ), X( NMAX ),
+ $ XS( NMAX*INCMAX ), XX( NMAX*INCMAX ),
+ $ Y( NMAX ), YS( NMAX*INCMAX ), YT( NMAX ),
+ $ YY( NMAX*INCMAX ), Z( NMAX )
+ INTEGER IDIM( NIDIM ), INC( NINC )
+* .. Local Scalars ..
+ DOUBLE PRECISION ALPHA, ALS, ERR, ERRMAX, TRANSL
+ INTEGER I, IA, IC, IN, INCX, INCXS, IX, J, JA, JJ, LAA,
+ $ LDA, LDAS, LJ, LX, N, NARGS, NC, NS
+ LOGICAL FULL, NULL, PACKED, RESET, SAME, UPPER
+ CHARACTER*1 UPLO, UPLOS
+ CHARACTER*2 ICH
+* .. Local Arrays ..
+ DOUBLE PRECISION W( 1 )
+ LOGICAL ISAME( 13 )
+* .. External Functions ..
+ LOGICAL LDE, LDERES
+ EXTERNAL LDE, LDERES
+* .. External Subroutines ..
+ EXTERNAL DMAKE, DMVCH, DSPR, DSYR
+* .. Intrinsic Functions ..
+ INTRINSIC ABS, MAX
+* .. Scalars in Common ..
+ INTEGER INFOT, NOUTC
+ LOGICAL LERR, OK
+* .. Common blocks ..
+ COMMON /INFOC/INFOT, NOUTC, OK, LERR
+* .. Data statements ..
+ DATA ICH/'UL'/
+* .. Executable Statements ..
+ FULL = SNAME( 3: 3 ).EQ.'Y'
+ PACKED = SNAME( 3: 3 ).EQ.'P'
+* Define the number of arguments.
+ IF( FULL )THEN
+ NARGS = 7
+ ELSE IF( PACKED )THEN
+ NARGS = 6
+ END IF
+*
+ NC = 0
+ RESET = .TRUE.
+ ERRMAX = ZERO
+*
+ DO 100 IN = 1, NIDIM
+ N = IDIM( IN )
+* Set LDA to 1 more than minimum value if room.
+ LDA = N
+ IF( LDA.LT.NMAX )
+ $ LDA = LDA + 1
+* Skip tests if not enough room.
+ IF( LDA.GT.NMAX )
+ $ GO TO 100
+ IF( PACKED )THEN
+ LAA = ( N*( N + 1 ) )/2
+ ELSE
+ LAA = LDA*N
+ END IF
+*
+ DO 90 IC = 1, 2
+ UPLO = ICH( IC: IC )
+ UPPER = UPLO.EQ.'U'
+*
+ DO 80 IX = 1, NINC
+ INCX = INC( IX )
+ LX = ABS( INCX )*N
+*
+* Generate the vector X.
+*
+ TRANSL = HALF
+ CALL DMAKE( 'GE', ' ', ' ', 1, N, X, 1, XX, ABS( INCX ),
+ $ 0, N - 1, RESET, TRANSL )
+ IF( N.GT.1 )THEN
+ X( N/2 ) = ZERO
+ XX( 1 + ABS( INCX )*( N/2 - 1 ) ) = ZERO
+ END IF
+*
+ DO 70 IA = 1, NALF
+ ALPHA = ALF( IA )
+ NULL = N.LE.0.OR.ALPHA.EQ.ZERO
+*
+* Generate the matrix A.
+*
+ TRANSL = ZERO
+ CALL DMAKE( SNAME( 2: 3 ), UPLO, ' ', N, N, A, NMAX,
+ $ AA, LDA, N - 1, N - 1, RESET, TRANSL )
+*
+ NC = NC + 1
+*
+* Save every datum before calling the subroutine.
+*
+ UPLOS = UPLO
+ NS = N
+ ALS = ALPHA
+ DO 10 I = 1, LAA
+ AS( I ) = AA( I )
+ 10 CONTINUE
+ LDAS = LDA
+ DO 20 I = 1, LX
+ XS( I ) = XX( I )
+ 20 CONTINUE
+ INCXS = INCX
+*
+* Call the subroutine.
+*
+ IF( FULL )THEN
+ IF( TRACE )
+ $ WRITE( NTRA, FMT = 9993 )NC, SNAME, UPLO, N,
+ $ ALPHA, INCX, LDA
+ IF( REWI )
+ $ REWIND NTRA
+ CALL DSYR( UPLO, N, ALPHA, XX, INCX, AA, LDA )
+ ELSE IF( PACKED )THEN
+ IF( TRACE )
+ $ WRITE( NTRA, FMT = 9994 )NC, SNAME, UPLO, N,
+ $ ALPHA, INCX
+ IF( REWI )
+ $ REWIND NTRA
+ CALL DSPR( UPLO, N, ALPHA, XX, INCX, AA )
+ END IF
+*
+* Check if error-exit was taken incorrectly.
+*
+ IF( .NOT.OK )THEN
+ WRITE( NOUT, FMT = 9992 )
+ FATAL = .TRUE.
+ GO TO 120
+ END IF
+*
+* See what data changed inside subroutines.
+*
+ ISAME( 1 ) = UPLO.EQ.UPLOS
+ ISAME( 2 ) = NS.EQ.N
+ ISAME( 3 ) = ALS.EQ.ALPHA
+ ISAME( 4 ) = LDE( XS, XX, LX )
+ ISAME( 5 ) = INCXS.EQ.INCX
+ IF( NULL )THEN
+ ISAME( 6 ) = LDE( AS, AA, LAA )
+ ELSE
+ ISAME( 6 ) = LDERES( SNAME( 2: 3 ), UPLO, N, N, AS,
+ $ AA, LDA )
+ END IF
+ IF( .NOT.PACKED )THEN
+ ISAME( 7 ) = LDAS.EQ.LDA
+ END IF
+*
+* If data was incorrectly changed, report and return.
+*
+ SAME = .TRUE.
+ DO 30 I = 1, NARGS
+ SAME = SAME.AND.ISAME( I )
+ IF( .NOT.ISAME( I ) )
+ $ WRITE( NOUT, FMT = 9998 )I
+ 30 CONTINUE
+ IF( .NOT.SAME )THEN
+ FATAL = .TRUE.
+ GO TO 120
+ END IF
+*
+ IF( .NOT.NULL )THEN
+*
+* Check the result column by column.
+*
+ IF( INCX.GT.0 )THEN
+ DO 40 I = 1, N
+ Z( I ) = X( I )
+ 40 CONTINUE
+ ELSE
+ DO 50 I = 1, N
+ Z( I ) = X( N - I + 1 )
+ 50 CONTINUE
+ END IF
+ JA = 1
+ DO 60 J = 1, N
+ W( 1 ) = Z( J )
+ IF( UPPER )THEN
+ JJ = 1
+ LJ = J
+ ELSE
+ JJ = J
+ LJ = N - J + 1
+ END IF
+ CALL DMVCH( 'N', LJ, 1, ALPHA, Z( JJ ), LJ, W,
+ $ 1, ONE, A( JJ, J ), 1, YT, G,
+ $ AA( JA ), EPS, ERR, FATAL, NOUT,
+ $ .TRUE. )
+ IF( FULL )THEN
+ IF( UPPER )THEN
+ JA = JA + LDA
+ ELSE
+ JA = JA + LDA + 1
+ END IF
+ ELSE
+ JA = JA + LJ
+ END IF
+ ERRMAX = MAX( ERRMAX, ERR )
+* If got really bad answer, report and return.
+ IF( FATAL )
+ $ GO TO 110
+ 60 CONTINUE
+ ELSE
+* Avoid repeating tests if N.le.0.
+ IF( N.LE.0 )
+ $ GO TO 100
+ END IF
+*
+ 70 CONTINUE
+*
+ 80 CONTINUE
+*
+ 90 CONTINUE
+*
+ 100 CONTINUE
+*
+* Report result.
+*
+ IF( ERRMAX.LT.THRESH )THEN
+ WRITE( NOUT, FMT = 9999 )SNAME, NC
+ ELSE
+ WRITE( NOUT, FMT = 9997 )SNAME, NC, ERRMAX
+ END IF
+ GO TO 130
+*
+ 110 CONTINUE
+ WRITE( NOUT, FMT = 9995 )J
+*
+ 120 CONTINUE
+ WRITE( NOUT, FMT = 9996 )SNAME
+ IF( FULL )THEN
+ WRITE( NOUT, FMT = 9993 )NC, SNAME, UPLO, N, ALPHA, INCX, LDA
+ ELSE IF( PACKED )THEN
+ WRITE( NOUT, FMT = 9994 )NC, SNAME, UPLO, N, ALPHA, INCX
+ END IF
+*
+ 130 CONTINUE
+ RETURN
+*
+ 9999 FORMAT( ' ', A6, ' PASSED THE COMPUTATIONAL TESTS (', I6, ' CALL',
+ $ 'S)' )
+ 9998 FORMAT( ' ******* FATAL ERROR - PARAMETER NUMBER ', I2, ' WAS CH',
+ $ 'ANGED INCORRECTLY *******' )
+ 9997 FORMAT( ' ', A6, ' COMPLETED THE COMPUTATIONAL TESTS (', I6, ' C',
+ $ 'ALLS)', /' ******* BUT WITH MAXIMUM TEST RATIO', F8.2,
+ $ ' - SUSPECT *******' )
+ 9996 FORMAT( ' ******* ', A6, ' FAILED ON CALL NUMBER:' )
+ 9995 FORMAT( ' THESE ARE THE RESULTS FOR COLUMN ', I3 )
+ 9994 FORMAT( 1X, I6, ': ', A6, '(''', A1, ''',', I3, ',', F4.1, ', X,',
+ $ I2, ', AP) .' )
+ 9993 FORMAT( 1X, I6, ': ', A6, '(''', A1, ''',', I3, ',', F4.1, ', X,',
+ $ I2, ', A,', I3, ') .' )
+ 9992 FORMAT( ' ******* FATAL ERROR - ERROR-EXIT TAKEN ON VALID CALL *',
+ $ '******' )
+*
+* End of DCHK5.
+*
+ END
+ SUBROUTINE DCHK6( SNAME, EPS, THRESH, NOUT, NTRA, TRACE, REWI,
+ $ FATAL, NIDIM, IDIM, NALF, ALF, NINC, INC, NMAX,
+ $ INCMAX, A, AA, AS, X, XX, XS, Y, YY, YS, YT, G,
+ $ Z )
+*
+* Tests DSYR2 and DSPR2.
+*
+* Auxiliary routine for test program for Level 2 Blas.
+*
+* -- Written on 10-August-1987.
+* Richard Hanson, Sandia National Labs.
+* Jeremy Du Croz, NAG Central Office.
+*
+* .. Parameters ..
+ DOUBLE PRECISION ZERO, HALF, ONE
+ PARAMETER ( ZERO = 0.0D0, HALF = 0.5D0, ONE = 1.0D0 )
+* .. Scalar Arguments ..
+ DOUBLE PRECISION EPS, THRESH
+ INTEGER INCMAX, NALF, NIDIM, NINC, NMAX, NOUT, NTRA
+ LOGICAL FATAL, REWI, TRACE
+ CHARACTER*6 SNAME
+* .. Array Arguments ..
+ DOUBLE PRECISION A( NMAX, NMAX ), AA( NMAX*NMAX ), ALF( NALF ),
+ $ AS( NMAX*NMAX ), G( NMAX ), X( NMAX ),
+ $ XS( NMAX*INCMAX ), XX( NMAX*INCMAX ),
+ $ Y( NMAX ), YS( NMAX*INCMAX ), YT( NMAX ),
+ $ YY( NMAX*INCMAX ), Z( NMAX, 2 )
+ INTEGER IDIM( NIDIM ), INC( NINC )
+* .. Local Scalars ..
+ DOUBLE PRECISION ALPHA, ALS, ERR, ERRMAX, TRANSL
+ INTEGER I, IA, IC, IN, INCX, INCXS, INCY, INCYS, IX,
+ $ IY, J, JA, JJ, LAA, LDA, LDAS, LJ, LX, LY, N,
+ $ NARGS, NC, NS
+ LOGICAL FULL, NULL, PACKED, RESET, SAME, UPPER
+ CHARACTER*1 UPLO, UPLOS
+ CHARACTER*2 ICH
+* .. Local Arrays ..
+ DOUBLE PRECISION W( 2 )
+ LOGICAL ISAME( 13 )
+* .. External Functions ..
+ LOGICAL LDE, LDERES
+ EXTERNAL LDE, LDERES
+* .. External Subroutines ..
+ EXTERNAL DMAKE, DMVCH, DSPR2, DSYR2
+* .. Intrinsic Functions ..
+ INTRINSIC ABS, MAX
+* .. Scalars in Common ..
+ INTEGER INFOT, NOUTC
+ LOGICAL LERR, OK
+* .. Common blocks ..
+ COMMON /INFOC/INFOT, NOUTC, OK, LERR
+* .. Data statements ..
+ DATA ICH/'UL'/
+* .. Executable Statements ..
+ FULL = SNAME( 3: 3 ).EQ.'Y'
+ PACKED = SNAME( 3: 3 ).EQ.'P'
+* Define the number of arguments.
+ IF( FULL )THEN
+ NARGS = 9
+ ELSE IF( PACKED )THEN
+ NARGS = 8
+ END IF
+*
+ NC = 0
+ RESET = .TRUE.
+ ERRMAX = ZERO
+*
+ DO 140 IN = 1, NIDIM
+ N = IDIM( IN )
+* Set LDA to 1 more than minimum value if room.
+ LDA = N
+ IF( LDA.LT.NMAX )
+ $ LDA = LDA + 1
+* Skip tests if not enough room.
+ IF( LDA.GT.NMAX )
+ $ GO TO 140
+ IF( PACKED )THEN
+ LAA = ( N*( N + 1 ) )/2
+ ELSE
+ LAA = LDA*N
+ END IF
+*
+ DO 130 IC = 1, 2
+ UPLO = ICH( IC: IC )
+ UPPER = UPLO.EQ.'U'
+*
+ DO 120 IX = 1, NINC
+ INCX = INC( IX )
+ LX = ABS( INCX )*N
+*
+* Generate the vector X.
+*
+ TRANSL = HALF
+ CALL DMAKE( 'GE', ' ', ' ', 1, N, X, 1, XX, ABS( INCX ),
+ $ 0, N - 1, RESET, TRANSL )
+ IF( N.GT.1 )THEN
+ X( N/2 ) = ZERO
+ XX( 1 + ABS( INCX )*( N/2 - 1 ) ) = ZERO
+ END IF
+*
+ DO 110 IY = 1, NINC
+ INCY = INC( IY )
+ LY = ABS( INCY )*N
+*
+* Generate the vector Y.
+*
+ TRANSL = ZERO
+ CALL DMAKE( 'GE', ' ', ' ', 1, N, Y, 1, YY,
+ $ ABS( INCY ), 0, N - 1, RESET, TRANSL )
+ IF( N.GT.1 )THEN
+ Y( N/2 ) = ZERO
+ YY( 1 + ABS( INCY )*( N/2 - 1 ) ) = ZERO
+ END IF
+*
+ DO 100 IA = 1, NALF
+ ALPHA = ALF( IA )
+ NULL = N.LE.0.OR.ALPHA.EQ.ZERO
+*
+* Generate the matrix A.
+*
+ TRANSL = ZERO
+ CALL DMAKE( SNAME( 2: 3 ), UPLO, ' ', N, N, A,
+ $ NMAX, AA, LDA, N - 1, N - 1, RESET,
+ $ TRANSL )
+*
+ NC = NC + 1
+*
+* Save every datum before calling the subroutine.
+*
+ UPLOS = UPLO
+ NS = N
+ ALS = ALPHA
+ DO 10 I = 1, LAA
+ AS( I ) = AA( I )
+ 10 CONTINUE
+ LDAS = LDA
+ DO 20 I = 1, LX
+ XS( I ) = XX( I )
+ 20 CONTINUE
+ INCXS = INCX
+ DO 30 I = 1, LY
+ YS( I ) = YY( I )
+ 30 CONTINUE
+ INCYS = INCY
+*
+* Call the subroutine.
+*
+ IF( FULL )THEN
+ IF( TRACE )
+ $ WRITE( NTRA, FMT = 9993 )NC, SNAME, UPLO, N,
+ $ ALPHA, INCX, INCY, LDA
+ IF( REWI )
+ $ REWIND NTRA
+ CALL DSYR2( UPLO, N, ALPHA, XX, INCX, YY, INCY,
+ $ AA, LDA )
+ ELSE IF( PACKED )THEN
+ IF( TRACE )
+ $ WRITE( NTRA, FMT = 9994 )NC, SNAME, UPLO, N,
+ $ ALPHA, INCX, INCY
+ IF( REWI )
+ $ REWIND NTRA
+ CALL DSPR2( UPLO, N, ALPHA, XX, INCX, YY, INCY,
+ $ AA )
+ END IF
+*
+* Check if error-exit was taken incorrectly.
+*
+ IF( .NOT.OK )THEN
+ WRITE( NOUT, FMT = 9992 )
+ FATAL = .TRUE.
+ GO TO 160
+ END IF
+*
+* See what data changed inside subroutines.
+*
+ ISAME( 1 ) = UPLO.EQ.UPLOS
+ ISAME( 2 ) = NS.EQ.N
+ ISAME( 3 ) = ALS.EQ.ALPHA
+ ISAME( 4 ) = LDE( XS, XX, LX )
+ ISAME( 5 ) = INCXS.EQ.INCX
+ ISAME( 6 ) = LDE( YS, YY, LY )
+ ISAME( 7 ) = INCYS.EQ.INCY
+ IF( NULL )THEN
+ ISAME( 8 ) = LDE( AS, AA, LAA )
+ ELSE
+ ISAME( 8 ) = LDERES( SNAME( 2: 3 ), UPLO, N, N,
+ $ AS, AA, LDA )
+ END IF
+ IF( .NOT.PACKED )THEN
+ ISAME( 9 ) = LDAS.EQ.LDA
+ END IF
+*
+* If data was incorrectly changed, report and return.
+*
+ SAME = .TRUE.
+ DO 40 I = 1, NARGS
+ SAME = SAME.AND.ISAME( I )
+ IF( .NOT.ISAME( I ) )
+ $ WRITE( NOUT, FMT = 9998 )I
+ 40 CONTINUE
+ IF( .NOT.SAME )THEN
+ FATAL = .TRUE.
+ GO TO 160
+ END IF
+*
+ IF( .NOT.NULL )THEN
+*
+* Check the result column by column.
+*
+ IF( INCX.GT.0 )THEN
+ DO 50 I = 1, N
+ Z( I, 1 ) = X( I )
+ 50 CONTINUE
+ ELSE
+ DO 60 I = 1, N
+ Z( I, 1 ) = X( N - I + 1 )
+ 60 CONTINUE
+ END IF
+ IF( INCY.GT.0 )THEN
+ DO 70 I = 1, N
+ Z( I, 2 ) = Y( I )
+ 70 CONTINUE
+ ELSE
+ DO 80 I = 1, N
+ Z( I, 2 ) = Y( N - I + 1 )
+ 80 CONTINUE
+ END IF
+ JA = 1
+ DO 90 J = 1, N
+ W( 1 ) = Z( J, 2 )
+ W( 2 ) = Z( J, 1 )
+ IF( UPPER )THEN
+ JJ = 1
+ LJ = J
+ ELSE
+ JJ = J
+ LJ = N - J + 1
+ END IF
+ CALL DMVCH( 'N', LJ, 2, ALPHA, Z( JJ, 1 ),
+ $ NMAX, W, 1, ONE, A( JJ, J ), 1,
+ $ YT, G, AA( JA ), EPS, ERR, FATAL,
+ $ NOUT, .TRUE. )
+ IF( FULL )THEN
+ IF( UPPER )THEN
+ JA = JA + LDA
+ ELSE
+ JA = JA + LDA + 1
+ END IF
+ ELSE
+ JA = JA + LJ
+ END IF
+ ERRMAX = MAX( ERRMAX, ERR )
+* If got really bad answer, report and return.
+ IF( FATAL )
+ $ GO TO 150
+ 90 CONTINUE
+ ELSE
+* Avoid repeating tests with N.le.0.
+ IF( N.LE.0 )
+ $ GO TO 140
+ END IF
+*
+ 100 CONTINUE
+*
+ 110 CONTINUE
+*
+ 120 CONTINUE
+*
+ 130 CONTINUE
+*
+ 140 CONTINUE
+*
+* Report result.
+*
+ IF( ERRMAX.LT.THRESH )THEN
+ WRITE( NOUT, FMT = 9999 )SNAME, NC
+ ELSE
+ WRITE( NOUT, FMT = 9997 )SNAME, NC, ERRMAX
+ END IF
+ GO TO 170
+*
+ 150 CONTINUE
+ WRITE( NOUT, FMT = 9995 )J
+*
+ 160 CONTINUE
+ WRITE( NOUT, FMT = 9996 )SNAME
+ IF( FULL )THEN
+ WRITE( NOUT, FMT = 9993 )NC, SNAME, UPLO, N, ALPHA, INCX,
+ $ INCY, LDA
+ ELSE IF( PACKED )THEN
+ WRITE( NOUT, FMT = 9994 )NC, SNAME, UPLO, N, ALPHA, INCX, INCY
+ END IF
+*
+ 170 CONTINUE
+ RETURN
+*
+ 9999 FORMAT( ' ', A6, ' PASSED THE COMPUTATIONAL TESTS (', I6, ' CALL',
+ $ 'S)' )
+ 9998 FORMAT( ' ******* FATAL ERROR - PARAMETER NUMBER ', I2, ' WAS CH',
+ $ 'ANGED INCORRECTLY *******' )
+ 9997 FORMAT( ' ', A6, ' COMPLETED THE COMPUTATIONAL TESTS (', I6, ' C',
+ $ 'ALLS)', /' ******* BUT WITH MAXIMUM TEST RATIO', F8.2,
+ $ ' - SUSPECT *******' )
+ 9996 FORMAT( ' ******* ', A6, ' FAILED ON CALL NUMBER:' )
+ 9995 FORMAT( ' THESE ARE THE RESULTS FOR COLUMN ', I3 )
+ 9994 FORMAT( 1X, I6, ': ', A6, '(''', A1, ''',', I3, ',', F4.1, ', X,',
+ $ I2, ', Y,', I2, ', AP) .' )
+ 9993 FORMAT( 1X, I6, ': ', A6, '(''', A1, ''',', I3, ',', F4.1, ', X,',
+ $ I2, ', Y,', I2, ', A,', I3, ') .' )
+ 9992 FORMAT( ' ******* FATAL ERROR - ERROR-EXIT TAKEN ON VALID CALL *',
+ $ '******' )
+*
+* End of DCHK6.
+*
+ END
+ SUBROUTINE DCHKE( ISNUM, SRNAMT, NOUT )
+*
+* Tests the error exits from the Level 2 Blas.
+* Requires a special version of the error-handling routine XERBLA.
+* ALPHA, BETA, A, X and Y should not need to be defined.
+*
+* Auxiliary routine for test program for Level 2 Blas.
+*
+* -- Written on 10-August-1987.
+* Richard Hanson, Sandia National Labs.
+* Jeremy Du Croz, NAG Central Office.
+*
+* .. Scalar Arguments ..
+ INTEGER ISNUM, NOUT
+ CHARACTER*6 SRNAMT
+* .. Scalars in Common ..
+ INTEGER INFOT, NOUTC
+ LOGICAL LERR, OK
+* .. Local Scalars ..
+ DOUBLE PRECISION ALPHA, BETA
+* .. Local Arrays ..
+ DOUBLE PRECISION A( 1, 1 ), X( 1 ), Y( 1 )
+* .. External Subroutines ..
+ EXTERNAL CHKXER, DGBMV, DGEMV, DGER, DSBMV, DSPMV, DSPR,
+ $ DSPR2, DSYMV, DSYR, DSYR2, DTBMV, DTBSV, DTPMV,
+ $ DTPSV, DTRMV, DTRSV
+* .. Common blocks ..
+ COMMON /INFOC/INFOT, NOUTC, OK, LERR
+* .. Executable Statements ..
+* OK is set to .FALSE. by the special version of XERBLA or by CHKXER
+* if anything is wrong.
+ OK = .TRUE.
+* LERR is set to .TRUE. by the special version of XERBLA each time
+* it is called, and is then tested and re-set by CHKXER.
+ LERR = .FALSE.
+ GO TO ( 10, 20, 30, 40, 50, 60, 70, 80,
+ $ 90, 100, 110, 120, 130, 140, 150,
+ $ 160 )ISNUM
+ 10 INFOT = 1
+ CALL DGEMV( '/', 0, 0, ALPHA, A, 1, X, 1, BETA, Y, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 2
+ CALL DGEMV( 'N', -1, 0, ALPHA, A, 1, X, 1, BETA, Y, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 3
+ CALL DGEMV( 'N', 0, -1, ALPHA, A, 1, X, 1, BETA, Y, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 6
+ CALL DGEMV( 'N', 2, 0, ALPHA, A, 1, X, 1, BETA, Y, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 8
+ CALL DGEMV( 'N', 0, 0, ALPHA, A, 1, X, 0, BETA, Y, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 11
+ CALL DGEMV( 'N', 0, 0, ALPHA, A, 1, X, 1, BETA, Y, 0 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ GO TO 170
+ 20 INFOT = 1
+ CALL DGBMV( '/', 0, 0, 0, 0, ALPHA, A, 1, X, 1, BETA, Y, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 2
+ CALL DGBMV( 'N', -1, 0, 0, 0, ALPHA, A, 1, X, 1, BETA, Y, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 3
+ CALL DGBMV( 'N', 0, -1, 0, 0, ALPHA, A, 1, X, 1, BETA, Y, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 4
+ CALL DGBMV( 'N', 0, 0, -1, 0, ALPHA, A, 1, X, 1, BETA, Y, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 5
+ CALL DGBMV( 'N', 2, 0, 0, -1, ALPHA, A, 1, X, 1, BETA, Y, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 8
+ CALL DGBMV( 'N', 0, 0, 1, 0, ALPHA, A, 1, X, 1, BETA, Y, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 10
+ CALL DGBMV( 'N', 0, 0, 0, 0, ALPHA, A, 1, X, 0, BETA, Y, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 13
+ CALL DGBMV( 'N', 0, 0, 0, 0, ALPHA, A, 1, X, 1, BETA, Y, 0 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ GO TO 170
+ 30 INFOT = 1
+ CALL DSYMV( '/', 0, ALPHA, A, 1, X, 1, BETA, Y, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 2
+ CALL DSYMV( 'U', -1, ALPHA, A, 1, X, 1, BETA, Y, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 5
+ CALL DSYMV( 'U', 2, ALPHA, A, 1, X, 1, BETA, Y, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 7
+ CALL DSYMV( 'U', 0, ALPHA, A, 1, X, 0, BETA, Y, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 10
+ CALL DSYMV( 'U', 0, ALPHA, A, 1, X, 1, BETA, Y, 0 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ GO TO 170
+ 40 INFOT = 1
+ CALL DSBMV( '/', 0, 0, ALPHA, A, 1, X, 1, BETA, Y, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 2
+ CALL DSBMV( 'U', -1, 0, ALPHA, A, 1, X, 1, BETA, Y, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 3
+ CALL DSBMV( 'U', 0, -1, ALPHA, A, 1, X, 1, BETA, Y, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 6
+ CALL DSBMV( 'U', 0, 1, ALPHA, A, 1, X, 1, BETA, Y, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 8
+ CALL DSBMV( 'U', 0, 0, ALPHA, A, 1, X, 0, BETA, Y, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 11
+ CALL DSBMV( 'U', 0, 0, ALPHA, A, 1, X, 1, BETA, Y, 0 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ GO TO 170
+ 50 INFOT = 1
+ CALL DSPMV( '/', 0, ALPHA, A, X, 1, BETA, Y, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 2
+ CALL DSPMV( 'U', -1, ALPHA, A, X, 1, BETA, Y, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 6
+ CALL DSPMV( 'U', 0, ALPHA, A, X, 0, BETA, Y, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 9
+ CALL DSPMV( 'U', 0, ALPHA, A, X, 1, BETA, Y, 0 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ GO TO 170
+ 60 INFOT = 1
+ CALL DTRMV( '/', 'N', 'N', 0, A, 1, X, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 2
+ CALL DTRMV( 'U', '/', 'N', 0, A, 1, X, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 3
+ CALL DTRMV( 'U', 'N', '/', 0, A, 1, X, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 4
+ CALL DTRMV( 'U', 'N', 'N', -1, A, 1, X, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 6
+ CALL DTRMV( 'U', 'N', 'N', 2, A, 1, X, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 8
+ CALL DTRMV( 'U', 'N', 'N', 0, A, 1, X, 0 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ GO TO 170
+ 70 INFOT = 1
+ CALL DTBMV( '/', 'N', 'N', 0, 0, A, 1, X, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 2
+ CALL DTBMV( 'U', '/', 'N', 0, 0, A, 1, X, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 3
+ CALL DTBMV( 'U', 'N', '/', 0, 0, A, 1, X, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 4
+ CALL DTBMV( 'U', 'N', 'N', -1, 0, A, 1, X, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 5
+ CALL DTBMV( 'U', 'N', 'N', 0, -1, A, 1, X, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 7
+ CALL DTBMV( 'U', 'N', 'N', 0, 1, A, 1, X, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 9
+ CALL DTBMV( 'U', 'N', 'N', 0, 0, A, 1, X, 0 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ GO TO 170
+ 80 INFOT = 1
+ CALL DTPMV( '/', 'N', 'N', 0, A, X, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 2
+ CALL DTPMV( 'U', '/', 'N', 0, A, X, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 3
+ CALL DTPMV( 'U', 'N', '/', 0, A, X, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 4
+ CALL DTPMV( 'U', 'N', 'N', -1, A, X, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 7
+ CALL DTPMV( 'U', 'N', 'N', 0, A, X, 0 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ GO TO 170
+ 90 INFOT = 1
+ CALL DTRSV( '/', 'N', 'N', 0, A, 1, X, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 2
+ CALL DTRSV( 'U', '/', 'N', 0, A, 1, X, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 3
+ CALL DTRSV( 'U', 'N', '/', 0, A, 1, X, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 4
+ CALL DTRSV( 'U', 'N', 'N', -1, A, 1, X, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 6
+ CALL DTRSV( 'U', 'N', 'N', 2, A, 1, X, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 8
+ CALL DTRSV( 'U', 'N', 'N', 0, A, 1, X, 0 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ GO TO 170
+ 100 INFOT = 1
+ CALL DTBSV( '/', 'N', 'N', 0, 0, A, 1, X, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 2
+ CALL DTBSV( 'U', '/', 'N', 0, 0, A, 1, X, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 3
+ CALL DTBSV( 'U', 'N', '/', 0, 0, A, 1, X, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 4
+ CALL DTBSV( 'U', 'N', 'N', -1, 0, A, 1, X, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 5
+ CALL DTBSV( 'U', 'N', 'N', 0, -1, A, 1, X, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 7
+ CALL DTBSV( 'U', 'N', 'N', 0, 1, A, 1, X, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 9
+ CALL DTBSV( 'U', 'N', 'N', 0, 0, A, 1, X, 0 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ GO TO 170
+ 110 INFOT = 1
+ CALL DTPSV( '/', 'N', 'N', 0, A, X, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 2
+ CALL DTPSV( 'U', '/', 'N', 0, A, X, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 3
+ CALL DTPSV( 'U', 'N', '/', 0, A, X, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 4
+ CALL DTPSV( 'U', 'N', 'N', -1, A, X, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 7
+ CALL DTPSV( 'U', 'N', 'N', 0, A, X, 0 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ GO TO 170
+ 120 INFOT = 1
+ CALL DGER( -1, 0, ALPHA, X, 1, Y, 1, A, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 2
+ CALL DGER( 0, -1, ALPHA, X, 1, Y, 1, A, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 5
+ CALL DGER( 0, 0, ALPHA, X, 0, Y, 1, A, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 7
+ CALL DGER( 0, 0, ALPHA, X, 1, Y, 0, A, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 9
+ CALL DGER( 2, 0, ALPHA, X, 1, Y, 1, A, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ GO TO 170
+ 130 INFOT = 1
+ CALL DSYR( '/', 0, ALPHA, X, 1, A, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 2
+ CALL DSYR( 'U', -1, ALPHA, X, 1, A, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 5
+ CALL DSYR( 'U', 0, ALPHA, X, 0, A, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 7
+ CALL DSYR( 'U', 2, ALPHA, X, 1, A, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ GO TO 170
+ 140 INFOT = 1
+ CALL DSPR( '/', 0, ALPHA, X, 1, A )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 2
+ CALL DSPR( 'U', -1, ALPHA, X, 1, A )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 5
+ CALL DSPR( 'U', 0, ALPHA, X, 0, A )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ GO TO 170
+ 150 INFOT = 1
+ CALL DSYR2( '/', 0, ALPHA, X, 1, Y, 1, A, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 2
+ CALL DSYR2( 'U', -1, ALPHA, X, 1, Y, 1, A, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 5
+ CALL DSYR2( 'U', 0, ALPHA, X, 0, Y, 1, A, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 7
+ CALL DSYR2( 'U', 0, ALPHA, X, 1, Y, 0, A, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 9
+ CALL DSYR2( 'U', 2, ALPHA, X, 1, Y, 1, A, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ GO TO 170
+ 160 INFOT = 1
+ CALL DSPR2( '/', 0, ALPHA, X, 1, Y, 1, A )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 2
+ CALL DSPR2( 'U', -1, ALPHA, X, 1, Y, 1, A )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 5
+ CALL DSPR2( 'U', 0, ALPHA, X, 0, Y, 1, A )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 7
+ CALL DSPR2( 'U', 0, ALPHA, X, 1, Y, 0, A )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+*
+ 170 IF( OK )THEN
+ WRITE( NOUT, FMT = 9999 )SRNAMT
+ ELSE
+ WRITE( NOUT, FMT = 9998 )SRNAMT
+ END IF
+ RETURN
+*
+ 9999 FORMAT( ' ', A6, ' PASSED THE TESTS OF ERROR-EXITS' )
+ 9998 FORMAT( ' ******* ', A6, ' FAILED THE TESTS OF ERROR-EXITS *****',
+ $ '**' )
+*
+* End of DCHKE.
+*
+ END
+ SUBROUTINE DMAKE( TYPE, UPLO, DIAG, M, N, A, NMAX, AA, LDA, KL,
+ $ KU, RESET, TRANSL )
+*
+* Generates values for an M by N matrix A within the bandwidth
+* defined by KL and KU.
+* Stores the values in the array AA in the data structure required
+* by the routine, with unwanted elements set to rogue value.
+*
+* TYPE is 'GE', 'GB', 'SY', 'SB', 'SP', 'TR', 'TB' OR 'TP'.
+*
+* Auxiliary routine for test program for Level 2 Blas.
+*
+* -- Written on 10-August-1987.
+* Richard Hanson, Sandia National Labs.
+* Jeremy Du Croz, NAG Central Office.
+*
+* .. Parameters ..
+ DOUBLE PRECISION ZERO, ONE
+ PARAMETER ( ZERO = 0.0D0, ONE = 1.0D0 )
+ DOUBLE PRECISION ROGUE
+ PARAMETER ( ROGUE = -1.0D10 )
+* .. Scalar Arguments ..
+ DOUBLE PRECISION TRANSL
+ INTEGER KL, KU, LDA, M, N, NMAX
+ LOGICAL RESET
+ CHARACTER*1 DIAG, UPLO
+ CHARACTER*2 TYPE
+* .. Array Arguments ..
+ DOUBLE PRECISION A( NMAX, * ), AA( * )
+* .. Local Scalars ..
+ INTEGER I, I1, I2, I3, IBEG, IEND, IOFF, J, KK
+ LOGICAL GEN, LOWER, SYM, TRI, UNIT, UPPER
+* .. External Functions ..
+ DOUBLE PRECISION DBEG
+ EXTERNAL DBEG
+* .. Intrinsic Functions ..
+ INTRINSIC MAX, MIN
+* .. Executable Statements ..
+ GEN = TYPE( 1: 1 ).EQ.'G'
+ SYM = TYPE( 1: 1 ).EQ.'S'
+ TRI = TYPE( 1: 1 ).EQ.'T'
+ UPPER = ( SYM.OR.TRI ).AND.UPLO.EQ.'U'
+ LOWER = ( SYM.OR.TRI ).AND.UPLO.EQ.'L'
+ UNIT = TRI.AND.DIAG.EQ.'U'
+*
+* Generate data in array A.
+*
+ DO 20 J = 1, N
+ DO 10 I = 1, M
+ IF( GEN.OR.( UPPER.AND.I.LE.J ).OR.( LOWER.AND.I.GE.J ) )
+ $ THEN
+ IF( ( I.LE.J.AND.J - I.LE.KU ).OR.
+ $ ( I.GE.J.AND.I - J.LE.KL ) )THEN
+ A( I, J ) = DBEG( RESET ) + TRANSL
+ ELSE
+ A( I, J ) = ZERO
+ END IF
+ IF( I.NE.J )THEN
+ IF( SYM )THEN
+ A( J, I ) = A( I, J )
+ ELSE IF( TRI )THEN
+ A( J, I ) = ZERO
+ END IF
+ END IF
+ END IF
+ 10 CONTINUE
+ IF( TRI )
+ $ A( J, J ) = A( J, J ) + ONE
+ IF( UNIT )
+ $ A( J, J ) = ONE
+ 20 CONTINUE
+*
+* Store elements in array AS in data structure required by routine.
+*
+ IF( TYPE.EQ.'GE' )THEN
+ DO 50 J = 1, N
+ DO 30 I = 1, M
+ AA( I + ( J - 1 )*LDA ) = A( I, J )
+ 30 CONTINUE
+ DO 40 I = M + 1, LDA
+ AA( I + ( J - 1 )*LDA ) = ROGUE
+ 40 CONTINUE
+ 50 CONTINUE
+ ELSE IF( TYPE.EQ.'GB' )THEN
+ DO 90 J = 1, N
+ DO 60 I1 = 1, KU + 1 - J
+ AA( I1 + ( J - 1 )*LDA ) = ROGUE
+ 60 CONTINUE
+ DO 70 I2 = I1, MIN( KL + KU + 1, KU + 1 + M - J )
+ AA( I2 + ( J - 1 )*LDA ) = A( I2 + J - KU - 1, J )
+ 70 CONTINUE
+ DO 80 I3 = I2, LDA
+ AA( I3 + ( J - 1 )*LDA ) = ROGUE
+ 80 CONTINUE
+ 90 CONTINUE
+ ELSE IF( TYPE.EQ.'SY'.OR.TYPE.EQ.'TR' )THEN
+ DO 130 J = 1, N
+ IF( UPPER )THEN
+ IBEG = 1
+ IF( UNIT )THEN
+ IEND = J - 1
+ ELSE
+ IEND = J
+ END IF
+ ELSE
+ IF( UNIT )THEN
+ IBEG = J + 1
+ ELSE
+ IBEG = J
+ END IF
+ IEND = N
+ END IF
+ DO 100 I = 1, IBEG - 1
+ AA( I + ( J - 1 )*LDA ) = ROGUE
+ 100 CONTINUE
+ DO 110 I = IBEG, IEND
+ AA( I + ( J - 1 )*LDA ) = A( I, J )
+ 110 CONTINUE
+ DO 120 I = IEND + 1, LDA
+ AA( I + ( J - 1 )*LDA ) = ROGUE
+ 120 CONTINUE
+ 130 CONTINUE
+ ELSE IF( TYPE.EQ.'SB'.OR.TYPE.EQ.'TB' )THEN
+ DO 170 J = 1, N
+ IF( UPPER )THEN
+ KK = KL + 1
+ IBEG = MAX( 1, KL + 2 - J )
+ IF( UNIT )THEN
+ IEND = KL
+ ELSE
+ IEND = KL + 1
+ END IF
+ ELSE
+ KK = 1
+ IF( UNIT )THEN
+ IBEG = 2
+ ELSE
+ IBEG = 1
+ END IF
+ IEND = MIN( KL + 1, 1 + M - J )
+ END IF
+ DO 140 I = 1, IBEG - 1
+ AA( I + ( J - 1 )*LDA ) = ROGUE
+ 140 CONTINUE
+ DO 150 I = IBEG, IEND
+ AA( I + ( J - 1 )*LDA ) = A( I + J - KK, J )
+ 150 CONTINUE
+ DO 160 I = IEND + 1, LDA
+ AA( I + ( J - 1 )*LDA ) = ROGUE
+ 160 CONTINUE
+ 170 CONTINUE
+ ELSE IF( TYPE.EQ.'SP'.OR.TYPE.EQ.'TP' )THEN
+ IOFF = 0
+ DO 190 J = 1, N
+ IF( UPPER )THEN
+ IBEG = 1
+ IEND = J
+ ELSE
+ IBEG = J
+ IEND = N
+ END IF
+ DO 180 I = IBEG, IEND
+ IOFF = IOFF + 1
+ AA( IOFF ) = A( I, J )
+ IF( I.EQ.J )THEN
+ IF( UNIT )
+ $ AA( IOFF ) = ROGUE
+ END IF
+ 180 CONTINUE
+ 190 CONTINUE
+ END IF
+ RETURN
+*
+* End of DMAKE.
+*
+ END
+ SUBROUTINE DMVCH( TRANS, M, N, ALPHA, A, NMAX, X, INCX, BETA, Y,
+ $ INCY, YT, G, YY, EPS, ERR, FATAL, NOUT, MV )
+*
+* Checks the results of the computational tests.
+*
+* Auxiliary routine for test program for Level 2 Blas.
+*
+* -- Written on 10-August-1987.
+* Richard Hanson, Sandia National Labs.
+* Jeremy Du Croz, NAG Central Office.
+*
+* .. Parameters ..
+ DOUBLE PRECISION ZERO, ONE
+ PARAMETER ( ZERO = 0.0D0, ONE = 1.0D0 )
+* .. Scalar Arguments ..
+ DOUBLE PRECISION ALPHA, BETA, EPS, ERR
+ INTEGER INCX, INCY, M, N, NMAX, NOUT
+ LOGICAL FATAL, MV
+ CHARACTER*1 TRANS
+* .. Array Arguments ..
+ DOUBLE PRECISION A( NMAX, * ), G( * ), X( * ), Y( * ), YT( * ),
+ $ YY( * )
+* .. Local Scalars ..
+ DOUBLE PRECISION ERRI
+ INTEGER I, INCXL, INCYL, IY, J, JX, KX, KY, ML, NL
+ LOGICAL TRAN
+* .. Intrinsic Functions ..
+ INTRINSIC ABS, MAX, SQRT
+* .. Executable Statements ..
+ TRAN = TRANS.EQ.'T'.OR.TRANS.EQ.'C'
+ IF( TRAN )THEN
+ ML = N
+ NL = M
+ ELSE
+ ML = M
+ NL = N
+ END IF
+ IF( INCX.LT.0 )THEN
+ KX = NL
+ INCXL = -1
+ ELSE
+ KX = 1
+ INCXL = 1
+ END IF
+ IF( INCY.LT.0 )THEN
+ KY = ML
+ INCYL = -1
+ ELSE
+ KY = 1
+ INCYL = 1
+ END IF
+*
+* Compute expected result in YT using data in A, X and Y.
+* Compute gauges in G.
+*
+ IY = KY
+ DO 30 I = 1, ML
+ YT( IY ) = ZERO
+ G( IY ) = ZERO
+ JX = KX
+ IF( TRAN )THEN
+ DO 10 J = 1, NL
+ YT( IY ) = YT( IY ) + A( J, I )*X( JX )
+ G( IY ) = G( IY ) + ABS( A( J, I )*X( JX ) )
+ JX = JX + INCXL
+ 10 CONTINUE
+ ELSE
+ DO 20 J = 1, NL
+ YT( IY ) = YT( IY ) + A( I, J )*X( JX )
+ G( IY ) = G( IY ) + ABS( A( I, J )*X( JX ) )
+ JX = JX + INCXL
+ 20 CONTINUE
+ END IF
+ YT( IY ) = ALPHA*YT( IY ) + BETA*Y( IY )
+ G( IY ) = ABS( ALPHA )*G( IY ) + ABS( BETA*Y( IY ) )
+ IY = IY + INCYL
+ 30 CONTINUE
+*
+* Compute the error ratio for this result.
+*
+ ERR = ZERO
+ DO 40 I = 1, ML
+ ERRI = ABS( YT( I ) - YY( 1 + ( I - 1 )*ABS( INCY ) ) )/EPS
+ IF( G( I ).NE.ZERO )
+ $ ERRI = ERRI/G( I )
+ ERR = MAX( ERR, ERRI )
+ IF( ERR*SQRT( EPS ).GE.ONE )
+ $ GO TO 50
+ 40 CONTINUE
+* If the loop completes, all results are at least half accurate.
+ GO TO 70
+*
+* Report fatal error.
+*
+ 50 FATAL = .TRUE.
+ WRITE( NOUT, FMT = 9999 )
+ DO 60 I = 1, ML
+ IF( MV )THEN
+ WRITE( NOUT, FMT = 9998 )I, YT( I ),
+ $ YY( 1 + ( I - 1 )*ABS( INCY ) )
+ ELSE
+ WRITE( NOUT, FMT = 9998 )I,
+ $ YY( 1 + ( I - 1 )*ABS( INCY ) ), YT( I )
+ END IF
+ 60 CONTINUE
+*
+ 70 CONTINUE
+ RETURN
+*
+ 9999 FORMAT( ' ******* FATAL ERROR - COMPUTED RESULT IS LESS THAN HAL',
+ $ 'F ACCURATE *******', /' EXPECTED RESULT COMPU',
+ $ 'TED RESULT' )
+ 9998 FORMAT( 1X, I7, 2G18.6 )
+*
+* End of DMVCH.
+*
+ END
+ LOGICAL FUNCTION LDE( RI, RJ, LR )
+*
+* Tests if two arrays are identical.
+*
+* Auxiliary routine for test program for Level 2 Blas.
+*
+* -- Written on 10-August-1987.
+* Richard Hanson, Sandia National Labs.
+* Jeremy Du Croz, NAG Central Office.
+*
+* .. Scalar Arguments ..
+ INTEGER LR
+* .. Array Arguments ..
+ DOUBLE PRECISION RI( * ), RJ( * )
+* .. Local Scalars ..
+ INTEGER I
+* .. Executable Statements ..
+ DO 10 I = 1, LR
+ IF( RI( I ).NE.RJ( I ) )
+ $ GO TO 20
+ 10 CONTINUE
+ LDE = .TRUE.
+ GO TO 30
+ 20 CONTINUE
+ LDE = .FALSE.
+ 30 RETURN
+*
+* End of LDE.
+*
+ END
+ LOGICAL FUNCTION LDERES( TYPE, UPLO, M, N, AA, AS, LDA )
+*
+* Tests if selected elements in two arrays are equal.
+*
+* TYPE is 'GE', 'SY' or 'SP'.
+*
+* Auxiliary routine for test program for Level 2 Blas.
+*
+* -- Written on 10-August-1987.
+* Richard Hanson, Sandia National Labs.
+* Jeremy Du Croz, NAG Central Office.
+*
+* .. Scalar Arguments ..
+ INTEGER LDA, M, N
+ CHARACTER*1 UPLO
+ CHARACTER*2 TYPE
+* .. Array Arguments ..
+ DOUBLE PRECISION AA( LDA, * ), AS( LDA, * )
+* .. Local Scalars ..
+ INTEGER I, IBEG, IEND, J
+ LOGICAL UPPER
+* .. Executable Statements ..
+ UPPER = UPLO.EQ.'U'
+ IF( TYPE.EQ.'GE' )THEN
+ DO 20 J = 1, N
+ DO 10 I = M + 1, LDA
+ IF( AA( I, J ).NE.AS( I, J ) )
+ $ GO TO 70
+ 10 CONTINUE
+ 20 CONTINUE
+ ELSE IF( TYPE.EQ.'SY' )THEN
+ DO 50 J = 1, N
+ IF( UPPER )THEN
+ IBEG = 1
+ IEND = J
+ ELSE
+ IBEG = J
+ IEND = N
+ END IF
+ DO 30 I = 1, IBEG - 1
+ IF( AA( I, J ).NE.AS( I, J ) )
+ $ GO TO 70
+ 30 CONTINUE
+ DO 40 I = IEND + 1, LDA
+ IF( AA( I, J ).NE.AS( I, J ) )
+ $ GO TO 70
+ 40 CONTINUE
+ 50 CONTINUE
+ END IF
+*
+ 60 CONTINUE
+ LDERES = .TRUE.
+ GO TO 80
+ 70 CONTINUE
+ LDERES = .FALSE.
+ 80 RETURN
+*
+* End of LDERES.
+*
+ END
+ DOUBLE PRECISION FUNCTION DBEG( RESET )
+*
+* Generates random numbers uniformly distributed between -0.5 and 0.5.
+*
+* Auxiliary routine for test program for Level 2 Blas.
+*
+* -- Written on 10-August-1987.
+* Richard Hanson, Sandia National Labs.
+* Jeremy Du Croz, NAG Central Office.
+*
+* .. Scalar Arguments ..
+ LOGICAL RESET
+* .. Local Scalars ..
+ INTEGER I, IC, MI
+* .. Save statement ..
+ SAVE I, IC, MI
+* .. Intrinsic Functions ..
+ INTRINSIC DBLE
+* .. Executable Statements ..
+ IF( RESET )THEN
+* Initialize local variables.
+ MI = 891
+ I = 7
+ IC = 0
+ RESET = .FALSE.
+ END IF
+*
+* The sequence of values of I is bounded between 1 and 999.
+* If initial I = 1,2,3,6,7 or 9, the period will be 50.
+* If initial I = 4 or 8, the period will be 25.
+* If initial I = 5, the period will be 10.
+* IC is used to break up the period by skipping 1 value of I in 6.
+*
+ IC = IC + 1
+ 10 I = I*MI
+ I = I - 1000*( I/1000 )
+ IF( IC.GE.5 )THEN
+ IC = 0
+ GO TO 10
+ END IF
+ DBEG = DBLE( I - 500 )/1001.0D0
+ RETURN
+*
+* End of DBEG.
+*
+ END
+ DOUBLE PRECISION FUNCTION DDIFF( X, Y )
+*
+* Auxiliary routine for test program for Level 2 Blas.
+*
+* -- Written on 10-August-1987.
+* Richard Hanson, Sandia National Labs.
+*
+* .. Scalar Arguments ..
+ DOUBLE PRECISION X, Y
+* .. Executable Statements ..
+ DDIFF = X - Y
+ RETURN
+*
+* End of DDIFF.
+*
+ END
+ SUBROUTINE CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+*
+* Tests whether XERBLA has detected an error when it should.
+*
+* Auxiliary routine for test program for Level 2 Blas.
+*
+* -- Written on 10-August-1987.
+* Richard Hanson, Sandia National Labs.
+* Jeremy Du Croz, NAG Central Office.
+*
+* .. Scalar Arguments ..
+ INTEGER INFOT, NOUT
+ LOGICAL LERR, OK
+ CHARACTER*6 SRNAMT
+* .. Executable Statements ..
+ IF( .NOT.LERR )THEN
+ WRITE( NOUT, FMT = 9999 )INFOT, SRNAMT
+ OK = .FALSE.
+ END IF
+ LERR = .FALSE.
+ RETURN
+*
+ 9999 FORMAT( ' ***** ILLEGAL VALUE OF PARAMETER NUMBER ', I2, ' NOT D',
+ $ 'ETECTED BY ', A6, ' *****' )
+*
+* End of CHKXER.
+*
+ END
+ SUBROUTINE XERBLA( SRNAME, INFO )
+*
+* This is a special version of XERBLA to be used only as part of
+* the test program for testing error exits from the Level 2 BLAS
+* routines.
+*
+* XERBLA is an error handler for the Level 2 BLAS routines.
+*
+* It is called by the Level 2 BLAS routines if an input parameter is
+* invalid.
+*
+* Auxiliary routine for test program for Level 2 Blas.
+*
+* -- Written on 10-August-1987.
+* Richard Hanson, Sandia National Labs.
+* Jeremy Du Croz, NAG Central Office.
+*
+* .. Scalar Arguments ..
+ INTEGER INFO
+ CHARACTER*6 SRNAME
+* .. Scalars in Common ..
+ INTEGER INFOT, NOUT
+ LOGICAL LERR, OK
+ CHARACTER*6 SRNAMT
+* .. Common blocks ..
+ COMMON /INFOC/INFOT, NOUT, OK, LERR
+ COMMON /SRNAMC/SRNAMT
+* .. Executable Statements ..
+ LERR = .TRUE.
+ IF( INFO.NE.INFOT )THEN
+ IF( INFOT.NE.0 )THEN
+ WRITE( NOUT, FMT = 9999 )INFO, INFOT
+ ELSE
+ WRITE( NOUT, FMT = 9997 )INFO
+ END IF
+ OK = .FALSE.
+ END IF
+ IF( SRNAME.NE.SRNAMT )THEN
+ WRITE( NOUT, FMT = 9998 )SRNAME, SRNAMT
+ OK = .FALSE.
+ END IF
+ RETURN
+*
+ 9999 FORMAT( ' ******* XERBLA WAS CALLED WITH INFO = ', I6, ' INSTEAD',
+ $ ' OF ', I2, ' *******' )
+ 9998 FORMAT( ' ******* XERBLA WAS CALLED WITH SRNAME = ', A6, ' INSTE',
+ $ 'AD OF ', A6, ' *******' )
+ 9997 FORMAT( ' ******* XERBLA WAS CALLED WITH INFO = ', I6,
+ $ ' *******' )
+*
+* End of XERBLA
+*
+ END
+
diff --git a/blas/testing/dblat3.dat b/blas/testing/dblat3.dat
new file mode 100644
index 000000000..5cbc2e6b6
--- /dev/null
+++ b/blas/testing/dblat3.dat
@@ -0,0 +1,20 @@
+'dblat3.summ' NAME OF SUMMARY OUTPUT FILE
+6 UNIT NUMBER OF SUMMARY FILE
+'dblat3.snap' NAME OF SNAPSHOT OUTPUT FILE
+-1 UNIT NUMBER OF SNAPSHOT FILE (NOT USED IF .LT. 0)
+F LOGICAL FLAG, T TO REWIND SNAPSHOT FILE AFTER EACH RECORD.
+F LOGICAL FLAG, T TO STOP ON FAILURES.
+T LOGICAL FLAG, T TO TEST ERROR EXITS.
+16.0 THRESHOLD VALUE OF TEST RATIO
+6 NUMBER OF VALUES OF N
+0 1 2 3 5 9 VALUES OF N
+3 NUMBER OF VALUES OF ALPHA
+0.0 1.0 0.7 VALUES OF ALPHA
+3 NUMBER OF VALUES OF BETA
+0.0 1.0 1.3 VALUES OF BETA
+DGEMM T PUT F FOR NO TEST. SAME COLUMNS.
+DSYMM T PUT F FOR NO TEST. SAME COLUMNS.
+DTRMM T PUT F FOR NO TEST. SAME COLUMNS.
+DTRSM T PUT F FOR NO TEST. SAME COLUMNS.
+DSYRK T PUT F FOR NO TEST. SAME COLUMNS.
+DSYR2K T PUT F FOR NO TEST. SAME COLUMNS.
diff --git a/blas/testing/dblat3.f b/blas/testing/dblat3.f
new file mode 100644
index 000000000..082e03e5e
--- /dev/null
+++ b/blas/testing/dblat3.f
@@ -0,0 +1,2823 @@
+ PROGRAM DBLAT3
+*
+* Test program for the DOUBLE PRECISION Level 3 Blas.
+*
+* The program must be driven by a short data file. The first 14 records
+* of the file are read using list-directed input, the last 6 records
+* are read using the format ( A6, L2 ). An annotated example of a data
+* file can be obtained by deleting the first 3 characters from the
+* following 20 lines:
+* 'DBLAT3.SUMM' NAME OF SUMMARY OUTPUT FILE
+* 6 UNIT NUMBER OF SUMMARY FILE
+* 'DBLAT3.SNAP' NAME OF SNAPSHOT OUTPUT FILE
+* -1 UNIT NUMBER OF SNAPSHOT FILE (NOT USED IF .LT. 0)
+* F LOGICAL FLAG, T TO REWIND SNAPSHOT FILE AFTER EACH RECORD.
+* F LOGICAL FLAG, T TO STOP ON FAILURES.
+* T LOGICAL FLAG, T TO TEST ERROR EXITS.
+* 16.0 THRESHOLD VALUE OF TEST RATIO
+* 6 NUMBER OF VALUES OF N
+* 0 1 2 3 5 9 VALUES OF N
+* 3 NUMBER OF VALUES OF ALPHA
+* 0.0 1.0 0.7 VALUES OF ALPHA
+* 3 NUMBER OF VALUES OF BETA
+* 0.0 1.0 1.3 VALUES OF BETA
+* DGEMM T PUT F FOR NO TEST. SAME COLUMNS.
+* DSYMM T PUT F FOR NO TEST. SAME COLUMNS.
+* DTRMM T PUT F FOR NO TEST. SAME COLUMNS.
+* DTRSM T PUT F FOR NO TEST. SAME COLUMNS.
+* DSYRK T PUT F FOR NO TEST. SAME COLUMNS.
+* DSYR2K T PUT F FOR NO TEST. SAME COLUMNS.
+*
+* See:
+*
+* Dongarra J. J., Du Croz J. J., Duff I. S. and Hammarling S.
+* A Set of Level 3 Basic Linear Algebra Subprograms.
+*
+* Technical Memorandum No.88 (Revision 1), Mathematics and
+* Computer Science Division, Argonne National Laboratory, 9700
+* South Cass Avenue, Argonne, Illinois 60439, US.
+*
+* -- Written on 8-February-1989.
+* Jack Dongarra, Argonne National Laboratory.
+* Iain Duff, AERE Harwell.
+* Jeremy Du Croz, Numerical Algorithms Group Ltd.
+* Sven Hammarling, Numerical Algorithms Group Ltd.
+*
+* .. Parameters ..
+ INTEGER NIN
+ PARAMETER ( NIN = 5 )
+ INTEGER NSUBS
+ PARAMETER ( NSUBS = 6 )
+ DOUBLE PRECISION ZERO, HALF, ONE
+ PARAMETER ( ZERO = 0.0D0, HALF = 0.5D0, ONE = 1.0D0 )
+ INTEGER NMAX
+ PARAMETER ( NMAX = 65 )
+ INTEGER NIDMAX, NALMAX, NBEMAX
+ PARAMETER ( NIDMAX = 9, NALMAX = 7, NBEMAX = 7 )
+* .. Local Scalars ..
+ DOUBLE PRECISION EPS, ERR, THRESH
+ INTEGER I, ISNUM, J, N, NALF, NBET, NIDIM, NOUT, NTRA
+ LOGICAL FATAL, LTESTT, REWI, SAME, SFATAL, TRACE,
+ $ TSTERR
+ CHARACTER*1 TRANSA, TRANSB
+ CHARACTER*6 SNAMET
+ CHARACTER*32 SNAPS, SUMMRY
+* .. Local Arrays ..
+ DOUBLE PRECISION AA( NMAX*NMAX ), AB( NMAX, 2*NMAX ),
+ $ ALF( NALMAX ), AS( NMAX*NMAX ),
+ $ BB( NMAX*NMAX ), BET( NBEMAX ),
+ $ BS( NMAX*NMAX ), C( NMAX, NMAX ),
+ $ CC( NMAX*NMAX ), CS( NMAX*NMAX ), CT( NMAX ),
+ $ G( NMAX ), W( 2*NMAX )
+ INTEGER IDIM( NIDMAX )
+ LOGICAL LTEST( NSUBS )
+ CHARACTER*6 SNAMES( NSUBS )
+* .. External Functions ..
+ DOUBLE PRECISION DDIFF
+ LOGICAL LDE
+ EXTERNAL DDIFF, LDE
+* .. External Subroutines ..
+ EXTERNAL DCHK1, DCHK2, DCHK3, DCHK4, DCHK5, DCHKE, DMMCH
+* .. Intrinsic Functions ..
+ INTRINSIC MAX, MIN
+* .. Scalars in Common ..
+ INTEGER INFOT, NOUTC
+ LOGICAL LERR, OK
+ CHARACTER*6 SRNAMT
+* .. Common blocks ..
+ COMMON /INFOC/INFOT, NOUTC, OK, LERR
+ COMMON /SRNAMC/SRNAMT
+* .. Data statements ..
+ DATA SNAMES/'DGEMM ', 'DSYMM ', 'DTRMM ', 'DTRSM ',
+ $ 'DSYRK ', 'DSYR2K'/
+* .. Executable Statements ..
+*
+* Read name and unit number for summary output file and open file.
+*
+ READ( NIN, FMT = * )SUMMRY
+ READ( NIN, FMT = * )NOUT
+ OPEN( NOUT, FILE = SUMMRY, STATUS = 'NEW' )
+ NOUTC = NOUT
+*
+* Read name and unit number for snapshot output file and open file.
+*
+ READ( NIN, FMT = * )SNAPS
+ READ( NIN, FMT = * )NTRA
+ TRACE = NTRA.GE.0
+ IF( TRACE )THEN
+ OPEN( NTRA, FILE = SNAPS, STATUS = 'NEW' )
+ END IF
+* Read the flag that directs rewinding of the snapshot file.
+ READ( NIN, FMT = * )REWI
+ REWI = REWI.AND.TRACE
+* Read the flag that directs stopping on any failure.
+ READ( NIN, FMT = * )SFATAL
+* Read the flag that indicates whether error exits are to be tested.
+ READ( NIN, FMT = * )TSTERR
+* Read the threshold value of the test ratio
+ READ( NIN, FMT = * )THRESH
+*
+* Read and check the parameter values for the tests.
+*
+* Values of N
+ READ( NIN, FMT = * )NIDIM
+ IF( NIDIM.LT.1.OR.NIDIM.GT.NIDMAX )THEN
+ WRITE( NOUT, FMT = 9997 )'N', NIDMAX
+ GO TO 220
+ END IF
+ READ( NIN, FMT = * )( IDIM( I ), I = 1, NIDIM )
+ DO 10 I = 1, NIDIM
+ IF( IDIM( I ).LT.0.OR.IDIM( I ).GT.NMAX )THEN
+ WRITE( NOUT, FMT = 9996 )NMAX
+ GO TO 220
+ END IF
+ 10 CONTINUE
+* Values of ALPHA
+ READ( NIN, FMT = * )NALF
+ IF( NALF.LT.1.OR.NALF.GT.NALMAX )THEN
+ WRITE( NOUT, FMT = 9997 )'ALPHA', NALMAX
+ GO TO 220
+ END IF
+ READ( NIN, FMT = * )( ALF( I ), I = 1, NALF )
+* Values of BETA
+ READ( NIN, FMT = * )NBET
+ IF( NBET.LT.1.OR.NBET.GT.NBEMAX )THEN
+ WRITE( NOUT, FMT = 9997 )'BETA', NBEMAX
+ GO TO 220
+ END IF
+ READ( NIN, FMT = * )( BET( I ), I = 1, NBET )
+*
+* Report values of parameters.
+*
+ WRITE( NOUT, FMT = 9995 )
+ WRITE( NOUT, FMT = 9994 )( IDIM( I ), I = 1, NIDIM )
+ WRITE( NOUT, FMT = 9993 )( ALF( I ), I = 1, NALF )
+ WRITE( NOUT, FMT = 9992 )( BET( I ), I = 1, NBET )
+ IF( .NOT.TSTERR )THEN
+ WRITE( NOUT, FMT = * )
+ WRITE( NOUT, FMT = 9984 )
+ END IF
+ WRITE( NOUT, FMT = * )
+ WRITE( NOUT, FMT = 9999 )THRESH
+ WRITE( NOUT, FMT = * )
+*
+* Read names of subroutines and flags which indicate
+* whether they are to be tested.
+*
+ DO 20 I = 1, NSUBS
+ LTEST( I ) = .FALSE.
+ 20 CONTINUE
+ 30 READ( NIN, FMT = 9988, END = 60 )SNAMET, LTESTT
+ DO 40 I = 1, NSUBS
+ IF( SNAMET.EQ.SNAMES( I ) )
+ $ GO TO 50
+ 40 CONTINUE
+ WRITE( NOUT, FMT = 9990 )SNAMET
+ STOP
+ 50 LTEST( I ) = LTESTT
+ GO TO 30
+*
+ 60 CONTINUE
+ CLOSE ( NIN )
+*
+* Compute EPS (the machine precision).
+*
+ EPS = ONE
+ 70 CONTINUE
+ IF( DDIFF( ONE + EPS, ONE ).EQ.ZERO )
+ $ GO TO 80
+ EPS = HALF*EPS
+ GO TO 70
+ 80 CONTINUE
+ EPS = EPS + EPS
+ WRITE( NOUT, FMT = 9998 )EPS
+*
+* Check the reliability of DMMCH using exact data.
+*
+ N = MIN( 32, NMAX )
+ DO 100 J = 1, N
+ DO 90 I = 1, N
+ AB( I, J ) = MAX( I - J + 1, 0 )
+ 90 CONTINUE
+ AB( J, NMAX + 1 ) = J
+ AB( 1, NMAX + J ) = J
+ C( J, 1 ) = ZERO
+ 100 CONTINUE
+ DO 110 J = 1, N
+ CC( J ) = J*( ( J + 1 )*J )/2 - ( ( J + 1 )*J*( J - 1 ) )/3
+ 110 CONTINUE
+* CC holds the exact result. On exit from DMMCH CT holds
+* the result computed by DMMCH.
+ TRANSA = 'N'
+ TRANSB = 'N'
+ CALL DMMCH( TRANSA, TRANSB, N, 1, N, ONE, AB, NMAX,
+ $ AB( 1, NMAX + 1 ), NMAX, ZERO, C, NMAX, CT, G, CC,
+ $ NMAX, EPS, ERR, FATAL, NOUT, .TRUE. )
+ SAME = LDE( CC, CT, N )
+ IF( .NOT.SAME.OR.ERR.NE.ZERO )THEN
+ WRITE( NOUT, FMT = 9989 )TRANSA, TRANSB, SAME, ERR
+ STOP
+ END IF
+ TRANSB = 'T'
+ CALL DMMCH( TRANSA, TRANSB, N, 1, N, ONE, AB, NMAX,
+ $ AB( 1, NMAX + 1 ), NMAX, ZERO, C, NMAX, CT, G, CC,
+ $ NMAX, EPS, ERR, FATAL, NOUT, .TRUE. )
+ SAME = LDE( CC, CT, N )
+ IF( .NOT.SAME.OR.ERR.NE.ZERO )THEN
+ WRITE( NOUT, FMT = 9989 )TRANSA, TRANSB, SAME, ERR
+ STOP
+ END IF
+ DO 120 J = 1, N
+ AB( J, NMAX + 1 ) = N - J + 1
+ AB( 1, NMAX + J ) = N - J + 1
+ 120 CONTINUE
+ DO 130 J = 1, N
+ CC( N - J + 1 ) = J*( ( J + 1 )*J )/2 -
+ $ ( ( J + 1 )*J*( J - 1 ) )/3
+ 130 CONTINUE
+ TRANSA = 'T'
+ TRANSB = 'N'
+ CALL DMMCH( TRANSA, TRANSB, N, 1, N, ONE, AB, NMAX,
+ $ AB( 1, NMAX + 1 ), NMAX, ZERO, C, NMAX, CT, G, CC,
+ $ NMAX, EPS, ERR, FATAL, NOUT, .TRUE. )
+ SAME = LDE( CC, CT, N )
+ IF( .NOT.SAME.OR.ERR.NE.ZERO )THEN
+ WRITE( NOUT, FMT = 9989 )TRANSA, TRANSB, SAME, ERR
+ STOP
+ END IF
+ TRANSB = 'T'
+ CALL DMMCH( TRANSA, TRANSB, N, 1, N, ONE, AB, NMAX,
+ $ AB( 1, NMAX + 1 ), NMAX, ZERO, C, NMAX, CT, G, CC,
+ $ NMAX, EPS, ERR, FATAL, NOUT, .TRUE. )
+ SAME = LDE( CC, CT, N )
+ IF( .NOT.SAME.OR.ERR.NE.ZERO )THEN
+ WRITE( NOUT, FMT = 9989 )TRANSA, TRANSB, SAME, ERR
+ STOP
+ END IF
+*
+* Test each subroutine in turn.
+*
+ DO 200 ISNUM = 1, NSUBS
+ WRITE( NOUT, FMT = * )
+ IF( .NOT.LTEST( ISNUM ) )THEN
+* Subprogram is not to be tested.
+ WRITE( NOUT, FMT = 9987 )SNAMES( ISNUM )
+ ELSE
+ SRNAMT = SNAMES( ISNUM )
+* Test error exits.
+ IF( TSTERR )THEN
+ CALL DCHKE( ISNUM, SNAMES( ISNUM ), NOUT )
+ WRITE( NOUT, FMT = * )
+ END IF
+* Test computations.
+ INFOT = 0
+ OK = .TRUE.
+ FATAL = .FALSE.
+ GO TO ( 140, 150, 160, 160, 170, 180 )ISNUM
+* Test DGEMM, 01.
+ 140 CALL DCHK1( SNAMES( ISNUM ), EPS, THRESH, NOUT, NTRA, TRACE,
+ $ REWI, FATAL, NIDIM, IDIM, NALF, ALF, NBET, BET,
+ $ NMAX, AB, AA, AS, AB( 1, NMAX + 1 ), BB, BS, C,
+ $ CC, CS, CT, G )
+ GO TO 190
+* Test DSYMM, 02.
+ 150 CALL DCHK2( SNAMES( ISNUM ), EPS, THRESH, NOUT, NTRA, TRACE,
+ $ REWI, FATAL, NIDIM, IDIM, NALF, ALF, NBET, BET,
+ $ NMAX, AB, AA, AS, AB( 1, NMAX + 1 ), BB, BS, C,
+ $ CC, CS, CT, G )
+ GO TO 190
+* Test DTRMM, 03, DTRSM, 04.
+ 160 CALL DCHK3( SNAMES( ISNUM ), EPS, THRESH, NOUT, NTRA, TRACE,
+ $ REWI, FATAL, NIDIM, IDIM, NALF, ALF, NMAX, AB,
+ $ AA, AS, AB( 1, NMAX + 1 ), BB, BS, CT, G, C )
+ GO TO 190
+* Test DSYRK, 05.
+ 170 CALL DCHK4( SNAMES( ISNUM ), EPS, THRESH, NOUT, NTRA, TRACE,
+ $ REWI, FATAL, NIDIM, IDIM, NALF, ALF, NBET, BET,
+ $ NMAX, AB, AA, AS, AB( 1, NMAX + 1 ), BB, BS, C,
+ $ CC, CS, CT, G )
+ GO TO 190
+* Test DSYR2K, 06.
+ 180 CALL DCHK5( SNAMES( ISNUM ), EPS, THRESH, NOUT, NTRA, TRACE,
+ $ REWI, FATAL, NIDIM, IDIM, NALF, ALF, NBET, BET,
+ $ NMAX, AB, AA, AS, BB, BS, C, CC, CS, CT, G, W )
+ GO TO 190
+*
+ 190 IF( FATAL.AND.SFATAL )
+ $ GO TO 210
+ END IF
+ 200 CONTINUE
+ WRITE( NOUT, FMT = 9986 )
+ GO TO 230
+*
+ 210 CONTINUE
+ WRITE( NOUT, FMT = 9985 )
+ GO TO 230
+*
+ 220 CONTINUE
+ WRITE( NOUT, FMT = 9991 )
+*
+ 230 CONTINUE
+ IF( TRACE )
+ $ CLOSE ( NTRA )
+ CLOSE ( NOUT )
+ STOP
+*
+ 9999 FORMAT( ' ROUTINES PASS COMPUTATIONAL TESTS IF TEST RATIO IS LES',
+ $ 'S THAN', F8.2 )
+ 9998 FORMAT( ' RELATIVE MACHINE PRECISION IS TAKEN TO BE', 1P, D9.1 )
+ 9997 FORMAT( ' NUMBER OF VALUES OF ', A, ' IS LESS THAN 1 OR GREATER ',
+ $ 'THAN ', I2 )
+ 9996 FORMAT( ' VALUE OF N IS LESS THAN 0 OR GREATER THAN ', I2 )
+ 9995 FORMAT( ' TESTS OF THE DOUBLE PRECISION LEVEL 3 BLAS', //' THE F',
+ $ 'OLLOWING PARAMETER VALUES WILL BE USED:' )
+ 9994 FORMAT( ' FOR N ', 9I6 )
+ 9993 FORMAT( ' FOR ALPHA ', 7F6.1 )
+ 9992 FORMAT( ' FOR BETA ', 7F6.1 )
+ 9991 FORMAT( ' AMEND DATA FILE OR INCREASE ARRAY SIZES IN PROGRAM',
+ $ /' ******* TESTS ABANDONED *******' )
+ 9990 FORMAT( ' SUBPROGRAM NAME ', A6, ' NOT RECOGNIZED', /' ******* T',
+ $ 'ESTS ABANDONED *******' )
+ 9989 FORMAT( ' ERROR IN DMMCH - IN-LINE DOT PRODUCTS ARE BEING EVALU',
+ $ 'ATED WRONGLY.', /' DMMCH WAS CALLED WITH TRANSA = ', A1,
+ $ ' AND TRANSB = ', A1, /' AND RETURNED SAME = ', L1, ' AND ',
+ $ 'ERR = ', F12.3, '.', /' THIS MAY BE DUE TO FAULTS IN THE ',
+ $ 'ARITHMETIC OR THE COMPILER.', /' ******* TESTS ABANDONED ',
+ $ '*******' )
+ 9988 FORMAT( A6, L2 )
+ 9987 FORMAT( 1X, A6, ' WAS NOT TESTED' )
+ 9986 FORMAT( /' END OF TESTS' )
+ 9985 FORMAT( /' ******* FATAL ERROR - TESTS ABANDONED *******' )
+ 9984 FORMAT( ' ERROR-EXITS WILL NOT BE TESTED' )
+*
+* End of DBLAT3.
+*
+ END
+ SUBROUTINE DCHK1( SNAME, EPS, THRESH, NOUT, NTRA, TRACE, REWI,
+ $ FATAL, NIDIM, IDIM, NALF, ALF, NBET, BET, NMAX,
+ $ A, AA, AS, B, BB, BS, C, CC, CS, CT, G )
+*
+* Tests DGEMM.
+*
+* Auxiliary routine for test program for Level 3 Blas.
+*
+* -- Written on 8-February-1989.
+* Jack Dongarra, Argonne National Laboratory.
+* Iain Duff, AERE Harwell.
+* Jeremy Du Croz, Numerical Algorithms Group Ltd.
+* Sven Hammarling, Numerical Algorithms Group Ltd.
+*
+* .. Parameters ..
+ DOUBLE PRECISION ZERO
+ PARAMETER ( ZERO = 0.0D0 )
+* .. Scalar Arguments ..
+ DOUBLE PRECISION EPS, THRESH
+ INTEGER NALF, NBET, NIDIM, NMAX, NOUT, NTRA
+ LOGICAL FATAL, REWI, TRACE
+ CHARACTER*6 SNAME
+* .. Array Arguments ..
+ DOUBLE PRECISION A( NMAX, NMAX ), AA( NMAX*NMAX ), ALF( NALF ),
+ $ AS( NMAX*NMAX ), B( NMAX, NMAX ),
+ $ BB( NMAX*NMAX ), BET( NBET ), BS( NMAX*NMAX ),
+ $ C( NMAX, NMAX ), CC( NMAX*NMAX ),
+ $ CS( NMAX*NMAX ), CT( NMAX ), G( NMAX )
+ INTEGER IDIM( NIDIM )
+* .. Local Scalars ..
+ DOUBLE PRECISION ALPHA, ALS, BETA, BLS, ERR, ERRMAX
+ INTEGER I, IA, IB, ICA, ICB, IK, IM, IN, K, KS, LAA,
+ $ LBB, LCC, LDA, LDAS, LDB, LDBS, LDC, LDCS, M,
+ $ MA, MB, MS, N, NA, NARGS, NB, NC, NS
+ LOGICAL NULL, RESET, SAME, TRANA, TRANB
+ CHARACTER*1 TRANAS, TRANBS, TRANSA, TRANSB
+ CHARACTER*3 ICH
+* .. Local Arrays ..
+ LOGICAL ISAME( 13 )
+* .. External Functions ..
+ LOGICAL LDE, LDERES
+ EXTERNAL LDE, LDERES
+* .. External Subroutines ..
+ EXTERNAL DGEMM, DMAKE, DMMCH
+* .. Intrinsic Functions ..
+ INTRINSIC MAX
+* .. Scalars in Common ..
+ INTEGER INFOT, NOUTC
+ LOGICAL LERR, OK
+* .. Common blocks ..
+ COMMON /INFOC/INFOT, NOUTC, OK, LERR
+* .. Data statements ..
+ DATA ICH/'NTC'/
+* .. Executable Statements ..
+*
+ NARGS = 13
+ NC = 0
+ RESET = .TRUE.
+ ERRMAX = ZERO
+*
+ DO 110 IM = 1, NIDIM
+ M = IDIM( IM )
+*
+ DO 100 IN = 1, NIDIM
+ N = IDIM( IN )
+* Set LDC to 1 more than minimum value if room.
+ LDC = M
+ IF( LDC.LT.NMAX )
+ $ LDC = LDC + 1
+* Skip tests if not enough room.
+ IF( LDC.GT.NMAX )
+ $ GO TO 100
+ LCC = LDC*N
+ NULL = N.LE.0.OR.M.LE.0
+*
+ DO 90 IK = 1, NIDIM
+ K = IDIM( IK )
+*
+ DO 80 ICA = 1, 3
+ TRANSA = ICH( ICA: ICA )
+ TRANA = TRANSA.EQ.'T'.OR.TRANSA.EQ.'C'
+*
+ IF( TRANA )THEN
+ MA = K
+ NA = M
+ ELSE
+ MA = M
+ NA = K
+ END IF
+* Set LDA to 1 more than minimum value if room.
+ LDA = MA
+ IF( LDA.LT.NMAX )
+ $ LDA = LDA + 1
+* Skip tests if not enough room.
+ IF( LDA.GT.NMAX )
+ $ GO TO 80
+ LAA = LDA*NA
+*
+* Generate the matrix A.
+*
+ CALL DMAKE( 'GE', ' ', ' ', MA, NA, A, NMAX, AA, LDA,
+ $ RESET, ZERO )
+*
+ DO 70 ICB = 1, 3
+ TRANSB = ICH( ICB: ICB )
+ TRANB = TRANSB.EQ.'T'.OR.TRANSB.EQ.'C'
+*
+ IF( TRANB )THEN
+ MB = N
+ NB = K
+ ELSE
+ MB = K
+ NB = N
+ END IF
+* Set LDB to 1 more than minimum value if room.
+ LDB = MB
+ IF( LDB.LT.NMAX )
+ $ LDB = LDB + 1
+* Skip tests if not enough room.
+ IF( LDB.GT.NMAX )
+ $ GO TO 70
+ LBB = LDB*NB
+*
+* Generate the matrix B.
+*
+ CALL DMAKE( 'GE', ' ', ' ', MB, NB, B, NMAX, BB,
+ $ LDB, RESET, ZERO )
+*
+ DO 60 IA = 1, NALF
+ ALPHA = ALF( IA )
+*
+ DO 50 IB = 1, NBET
+ BETA = BET( IB )
+*
+* Generate the matrix C.
+*
+ CALL DMAKE( 'GE', ' ', ' ', M, N, C, NMAX,
+ $ CC, LDC, RESET, ZERO )
+*
+ NC = NC + 1
+*
+* Save every datum before calling the
+* subroutine.
+*
+ TRANAS = TRANSA
+ TRANBS = TRANSB
+ MS = M
+ NS = N
+ KS = K
+ ALS = ALPHA
+ DO 10 I = 1, LAA
+ AS( I ) = AA( I )
+ 10 CONTINUE
+ LDAS = LDA
+ DO 20 I = 1, LBB
+ BS( I ) = BB( I )
+ 20 CONTINUE
+ LDBS = LDB
+ BLS = BETA
+ DO 30 I = 1, LCC
+ CS( I ) = CC( I )
+ 30 CONTINUE
+ LDCS = LDC
+*
+* Call the subroutine.
+*
+ IF( TRACE )
+ $ WRITE( NTRA, FMT = 9995 )NC, SNAME,
+ $ TRANSA, TRANSB, M, N, K, ALPHA, LDA, LDB,
+ $ BETA, LDC
+ IF( REWI )
+ $ REWIND NTRA
+ CALL DGEMM( TRANSA, TRANSB, M, N, K, ALPHA,
+ $ AA, LDA, BB, LDB, BETA, CC, LDC )
+*
+* Check if error-exit was taken incorrectly.
+*
+ IF( .NOT.OK )THEN
+ WRITE( NOUT, FMT = 9994 )
+ FATAL = .TRUE.
+ GO TO 120
+ END IF
+*
+* See what data changed inside subroutines.
+*
+ ISAME( 1 ) = TRANSA.EQ.TRANAS
+ ISAME( 2 ) = TRANSB.EQ.TRANBS
+ ISAME( 3 ) = MS.EQ.M
+ ISAME( 4 ) = NS.EQ.N
+ ISAME( 5 ) = KS.EQ.K
+ ISAME( 6 ) = ALS.EQ.ALPHA
+ ISAME( 7 ) = LDE( AS, AA, LAA )
+ ISAME( 8 ) = LDAS.EQ.LDA
+ ISAME( 9 ) = LDE( BS, BB, LBB )
+ ISAME( 10 ) = LDBS.EQ.LDB
+ ISAME( 11 ) = BLS.EQ.BETA
+ IF( NULL )THEN
+ ISAME( 12 ) = LDE( CS, CC, LCC )
+ ELSE
+ ISAME( 12 ) = LDERES( 'GE', ' ', M, N, CS,
+ $ CC, LDC )
+ END IF
+ ISAME( 13 ) = LDCS.EQ.LDC
+*
+* If data was incorrectly changed, report
+* and return.
+*
+ SAME = .TRUE.
+ DO 40 I = 1, NARGS
+ SAME = SAME.AND.ISAME( I )
+ IF( .NOT.ISAME( I ) )
+ $ WRITE( NOUT, FMT = 9998 )I
+ 40 CONTINUE
+ IF( .NOT.SAME )THEN
+ FATAL = .TRUE.
+ GO TO 120
+ END IF
+*
+ IF( .NOT.NULL )THEN
+*
+* Check the result.
+*
+ CALL DMMCH( TRANSA, TRANSB, M, N, K,
+ $ ALPHA, A, NMAX, B, NMAX, BETA,
+ $ C, NMAX, CT, G, CC, LDC, EPS,
+ $ ERR, FATAL, NOUT, .TRUE. )
+ ERRMAX = MAX( ERRMAX, ERR )
+* If got really bad answer, report and
+* return.
+ IF( FATAL )
+ $ GO TO 120
+ END IF
+*
+ 50 CONTINUE
+*
+ 60 CONTINUE
+*
+ 70 CONTINUE
+*
+ 80 CONTINUE
+*
+ 90 CONTINUE
+*
+ 100 CONTINUE
+*
+ 110 CONTINUE
+*
+* Report result.
+*
+ IF( ERRMAX.LT.THRESH )THEN
+ WRITE( NOUT, FMT = 9999 )SNAME, NC
+ ELSE
+ WRITE( NOUT, FMT = 9997 )SNAME, NC, ERRMAX
+ END IF
+ GO TO 130
+*
+ 120 CONTINUE
+ WRITE( NOUT, FMT = 9996 )SNAME
+ WRITE( NOUT, FMT = 9995 )NC, SNAME, TRANSA, TRANSB, M, N, K,
+ $ ALPHA, LDA, LDB, BETA, LDC
+*
+ 130 CONTINUE
+ RETURN
+*
+ 9999 FORMAT( ' ', A6, ' PASSED THE COMPUTATIONAL TESTS (', I6, ' CALL',
+ $ 'S)' )
+ 9998 FORMAT( ' ******* FATAL ERROR - PARAMETER NUMBER ', I2, ' WAS CH',
+ $ 'ANGED INCORRECTLY *******' )
+ 9997 FORMAT( ' ', A6, ' COMPLETED THE COMPUTATIONAL TESTS (', I6, ' C',
+ $ 'ALLS)', /' ******* BUT WITH MAXIMUM TEST RATIO', F8.2,
+ $ ' - SUSPECT *******' )
+ 9996 FORMAT( ' ******* ', A6, ' FAILED ON CALL NUMBER:' )
+ 9995 FORMAT( 1X, I6, ': ', A6, '(''', A1, ''',''', A1, ''',',
+ $ 3( I3, ',' ), F4.1, ', A,', I3, ', B,', I3, ',', F4.1, ', ',
+ $ 'C,', I3, ').' )
+ 9994 FORMAT( ' ******* FATAL ERROR - ERROR-EXIT TAKEN ON VALID CALL *',
+ $ '******' )
+*
+* End of DCHK1.
+*
+ END
+ SUBROUTINE DCHK2( SNAME, EPS, THRESH, NOUT, NTRA, TRACE, REWI,
+ $ FATAL, NIDIM, IDIM, NALF, ALF, NBET, BET, NMAX,
+ $ A, AA, AS, B, BB, BS, C, CC, CS, CT, G )
+*
+* Tests DSYMM.
+*
+* Auxiliary routine for test program for Level 3 Blas.
+*
+* -- Written on 8-February-1989.
+* Jack Dongarra, Argonne National Laboratory.
+* Iain Duff, AERE Harwell.
+* Jeremy Du Croz, Numerical Algorithms Group Ltd.
+* Sven Hammarling, Numerical Algorithms Group Ltd.
+*
+* .. Parameters ..
+ DOUBLE PRECISION ZERO
+ PARAMETER ( ZERO = 0.0D0 )
+* .. Scalar Arguments ..
+ DOUBLE PRECISION EPS, THRESH
+ INTEGER NALF, NBET, NIDIM, NMAX, NOUT, NTRA
+ LOGICAL FATAL, REWI, TRACE
+ CHARACTER*6 SNAME
+* .. Array Arguments ..
+ DOUBLE PRECISION A( NMAX, NMAX ), AA( NMAX*NMAX ), ALF( NALF ),
+ $ AS( NMAX*NMAX ), B( NMAX, NMAX ),
+ $ BB( NMAX*NMAX ), BET( NBET ), BS( NMAX*NMAX ),
+ $ C( NMAX, NMAX ), CC( NMAX*NMAX ),
+ $ CS( NMAX*NMAX ), CT( NMAX ), G( NMAX )
+ INTEGER IDIM( NIDIM )
+* .. Local Scalars ..
+ DOUBLE PRECISION ALPHA, ALS, BETA, BLS, ERR, ERRMAX
+ INTEGER I, IA, IB, ICS, ICU, IM, IN, LAA, LBB, LCC,
+ $ LDA, LDAS, LDB, LDBS, LDC, LDCS, M, MS, N, NA,
+ $ NARGS, NC, NS
+ LOGICAL LEFT, NULL, RESET, SAME
+ CHARACTER*1 SIDE, SIDES, UPLO, UPLOS
+ CHARACTER*2 ICHS, ICHU
+* .. Local Arrays ..
+ LOGICAL ISAME( 13 )
+* .. External Functions ..
+ LOGICAL LDE, LDERES
+ EXTERNAL LDE, LDERES
+* .. External Subroutines ..
+ EXTERNAL DMAKE, DMMCH, DSYMM
+* .. Intrinsic Functions ..
+ INTRINSIC MAX
+* .. Scalars in Common ..
+ INTEGER INFOT, NOUTC
+ LOGICAL LERR, OK
+* .. Common blocks ..
+ COMMON /INFOC/INFOT, NOUTC, OK, LERR
+* .. Data statements ..
+ DATA ICHS/'LR'/, ICHU/'UL'/
+* .. Executable Statements ..
+*
+ NARGS = 12
+ NC = 0
+ RESET = .TRUE.
+ ERRMAX = ZERO
+*
+ DO 100 IM = 1, NIDIM
+ M = IDIM( IM )
+*
+ DO 90 IN = 1, NIDIM
+ N = IDIM( IN )
+* Set LDC to 1 more than minimum value if room.
+ LDC = M
+ IF( LDC.LT.NMAX )
+ $ LDC = LDC + 1
+* Skip tests if not enough room.
+ IF( LDC.GT.NMAX )
+ $ GO TO 90
+ LCC = LDC*N
+ NULL = N.LE.0.OR.M.LE.0
+*
+* Set LDB to 1 more than minimum value if room.
+ LDB = M
+ IF( LDB.LT.NMAX )
+ $ LDB = LDB + 1
+* Skip tests if not enough room.
+ IF( LDB.GT.NMAX )
+ $ GO TO 90
+ LBB = LDB*N
+*
+* Generate the matrix B.
+*
+ CALL DMAKE( 'GE', ' ', ' ', M, N, B, NMAX, BB, LDB, RESET,
+ $ ZERO )
+*
+ DO 80 ICS = 1, 2
+ SIDE = ICHS( ICS: ICS )
+ LEFT = SIDE.EQ.'L'
+*
+ IF( LEFT )THEN
+ NA = M
+ ELSE
+ NA = N
+ END IF
+* Set LDA to 1 more than minimum value if room.
+ LDA = NA
+ IF( LDA.LT.NMAX )
+ $ LDA = LDA + 1
+* Skip tests if not enough room.
+ IF( LDA.GT.NMAX )
+ $ GO TO 80
+ LAA = LDA*NA
+*
+ DO 70 ICU = 1, 2
+ UPLO = ICHU( ICU: ICU )
+*
+* Generate the symmetric matrix A.
+*
+ CALL DMAKE( 'SY', UPLO, ' ', NA, NA, A, NMAX, AA, LDA,
+ $ RESET, ZERO )
+*
+ DO 60 IA = 1, NALF
+ ALPHA = ALF( IA )
+*
+ DO 50 IB = 1, NBET
+ BETA = BET( IB )
+*
+* Generate the matrix C.
+*
+ CALL DMAKE( 'GE', ' ', ' ', M, N, C, NMAX, CC,
+ $ LDC, RESET, ZERO )
+*
+ NC = NC + 1
+*
+* Save every datum before calling the
+* subroutine.
+*
+ SIDES = SIDE
+ UPLOS = UPLO
+ MS = M
+ NS = N
+ ALS = ALPHA
+ DO 10 I = 1, LAA
+ AS( I ) = AA( I )
+ 10 CONTINUE
+ LDAS = LDA
+ DO 20 I = 1, LBB
+ BS( I ) = BB( I )
+ 20 CONTINUE
+ LDBS = LDB
+ BLS = BETA
+ DO 30 I = 1, LCC
+ CS( I ) = CC( I )
+ 30 CONTINUE
+ LDCS = LDC
+*
+* Call the subroutine.
+*
+ IF( TRACE )
+ $ WRITE( NTRA, FMT = 9995 )NC, SNAME, SIDE,
+ $ UPLO, M, N, ALPHA, LDA, LDB, BETA, LDC
+ IF( REWI )
+ $ REWIND NTRA
+ CALL DSYMM( SIDE, UPLO, M, N, ALPHA, AA, LDA,
+ $ BB, LDB, BETA, CC, LDC )
+*
+* Check if error-exit was taken incorrectly.
+*
+ IF( .NOT.OK )THEN
+ WRITE( NOUT, FMT = 9994 )
+ FATAL = .TRUE.
+ GO TO 110
+ END IF
+*
+* See what data changed inside subroutines.
+*
+ ISAME( 1 ) = SIDES.EQ.SIDE
+ ISAME( 2 ) = UPLOS.EQ.UPLO
+ ISAME( 3 ) = MS.EQ.M
+ ISAME( 4 ) = NS.EQ.N
+ ISAME( 5 ) = ALS.EQ.ALPHA
+ ISAME( 6 ) = LDE( AS, AA, LAA )
+ ISAME( 7 ) = LDAS.EQ.LDA
+ ISAME( 8 ) = LDE( BS, BB, LBB )
+ ISAME( 9 ) = LDBS.EQ.LDB
+ ISAME( 10 ) = BLS.EQ.BETA
+ IF( NULL )THEN
+ ISAME( 11 ) = LDE( CS, CC, LCC )
+ ELSE
+ ISAME( 11 ) = LDERES( 'GE', ' ', M, N, CS,
+ $ CC, LDC )
+ END IF
+ ISAME( 12 ) = LDCS.EQ.LDC
+*
+* If data was incorrectly changed, report and
+* return.
+*
+ SAME = .TRUE.
+ DO 40 I = 1, NARGS
+ SAME = SAME.AND.ISAME( I )
+ IF( .NOT.ISAME( I ) )
+ $ WRITE( NOUT, FMT = 9998 )I
+ 40 CONTINUE
+ IF( .NOT.SAME )THEN
+ FATAL = .TRUE.
+ GO TO 110
+ END IF
+*
+ IF( .NOT.NULL )THEN
+*
+* Check the result.
+*
+ IF( LEFT )THEN
+ CALL DMMCH( 'N', 'N', M, N, M, ALPHA, A,
+ $ NMAX, B, NMAX, BETA, C, NMAX,
+ $ CT, G, CC, LDC, EPS, ERR,
+ $ FATAL, NOUT, .TRUE. )
+ ELSE
+ CALL DMMCH( 'N', 'N', M, N, N, ALPHA, B,
+ $ NMAX, A, NMAX, BETA, C, NMAX,
+ $ CT, G, CC, LDC, EPS, ERR,
+ $ FATAL, NOUT, .TRUE. )
+ END IF
+ ERRMAX = MAX( ERRMAX, ERR )
+* If got really bad answer, report and
+* return.
+ IF( FATAL )
+ $ GO TO 110
+ END IF
+*
+ 50 CONTINUE
+*
+ 60 CONTINUE
+*
+ 70 CONTINUE
+*
+ 80 CONTINUE
+*
+ 90 CONTINUE
+*
+ 100 CONTINUE
+*
+* Report result.
+*
+ IF( ERRMAX.LT.THRESH )THEN
+ WRITE( NOUT, FMT = 9999 )SNAME, NC
+ ELSE
+ WRITE( NOUT, FMT = 9997 )SNAME, NC, ERRMAX
+ END IF
+ GO TO 120
+*
+ 110 CONTINUE
+ WRITE( NOUT, FMT = 9996 )SNAME
+ WRITE( NOUT, FMT = 9995 )NC, SNAME, SIDE, UPLO, M, N, ALPHA, LDA,
+ $ LDB, BETA, LDC
+*
+ 120 CONTINUE
+ RETURN
+*
+ 9999 FORMAT( ' ', A6, ' PASSED THE COMPUTATIONAL TESTS (', I6, ' CALL',
+ $ 'S)' )
+ 9998 FORMAT( ' ******* FATAL ERROR - PARAMETER NUMBER ', I2, ' WAS CH',
+ $ 'ANGED INCORRECTLY *******' )
+ 9997 FORMAT( ' ', A6, ' COMPLETED THE COMPUTATIONAL TESTS (', I6, ' C',
+ $ 'ALLS)', /' ******* BUT WITH MAXIMUM TEST RATIO', F8.2,
+ $ ' - SUSPECT *******' )
+ 9996 FORMAT( ' ******* ', A6, ' FAILED ON CALL NUMBER:' )
+ 9995 FORMAT( 1X, I6, ': ', A6, '(', 2( '''', A1, ''',' ), 2( I3, ',' ),
+ $ F4.1, ', A,', I3, ', B,', I3, ',', F4.1, ', C,', I3, ') ',
+ $ ' .' )
+ 9994 FORMAT( ' ******* FATAL ERROR - ERROR-EXIT TAKEN ON VALID CALL *',
+ $ '******' )
+*
+* End of DCHK2.
+*
+ END
+ SUBROUTINE DCHK3( SNAME, EPS, THRESH, NOUT, NTRA, TRACE, REWI,
+ $ FATAL, NIDIM, IDIM, NALF, ALF, NMAX, A, AA, AS,
+ $ B, BB, BS, CT, G, C )
+*
+* Tests DTRMM and DTRSM.
+*
+* Auxiliary routine for test program for Level 3 Blas.
+*
+* -- Written on 8-February-1989.
+* Jack Dongarra, Argonne National Laboratory.
+* Iain Duff, AERE Harwell.
+* Jeremy Du Croz, Numerical Algorithms Group Ltd.
+* Sven Hammarling, Numerical Algorithms Group Ltd.
+*
+* .. Parameters ..
+ DOUBLE PRECISION ZERO, ONE
+ PARAMETER ( ZERO = 0.0D0, ONE = 1.0D0 )
+* .. Scalar Arguments ..
+ DOUBLE PRECISION EPS, THRESH
+ INTEGER NALF, NIDIM, NMAX, NOUT, NTRA
+ LOGICAL FATAL, REWI, TRACE
+ CHARACTER*6 SNAME
+* .. Array Arguments ..
+ DOUBLE PRECISION A( NMAX, NMAX ), AA( NMAX*NMAX ), ALF( NALF ),
+ $ AS( NMAX*NMAX ), B( NMAX, NMAX ),
+ $ BB( NMAX*NMAX ), BS( NMAX*NMAX ),
+ $ C( NMAX, NMAX ), CT( NMAX ), G( NMAX )
+ INTEGER IDIM( NIDIM )
+* .. Local Scalars ..
+ DOUBLE PRECISION ALPHA, ALS, ERR, ERRMAX
+ INTEGER I, IA, ICD, ICS, ICT, ICU, IM, IN, J, LAA, LBB,
+ $ LDA, LDAS, LDB, LDBS, M, MS, N, NA, NARGS, NC,
+ $ NS
+ LOGICAL LEFT, NULL, RESET, SAME
+ CHARACTER*1 DIAG, DIAGS, SIDE, SIDES, TRANAS, TRANSA, UPLO,
+ $ UPLOS
+ CHARACTER*2 ICHD, ICHS, ICHU
+ CHARACTER*3 ICHT
+* .. Local Arrays ..
+ LOGICAL ISAME( 13 )
+* .. External Functions ..
+ LOGICAL LDE, LDERES
+ EXTERNAL LDE, LDERES
+* .. External Subroutines ..
+ EXTERNAL DMAKE, DMMCH, DTRMM, DTRSM
+* .. Intrinsic Functions ..
+ INTRINSIC MAX
+* .. Scalars in Common ..
+ INTEGER INFOT, NOUTC
+ LOGICAL LERR, OK
+* .. Common blocks ..
+ COMMON /INFOC/INFOT, NOUTC, OK, LERR
+* .. Data statements ..
+ DATA ICHU/'UL'/, ICHT/'NTC'/, ICHD/'UN'/, ICHS/'LR'/
+* .. Executable Statements ..
+*
+ NARGS = 11
+ NC = 0
+ RESET = .TRUE.
+ ERRMAX = ZERO
+* Set up zero matrix for DMMCH.
+ DO 20 J = 1, NMAX
+ DO 10 I = 1, NMAX
+ C( I, J ) = ZERO
+ 10 CONTINUE
+ 20 CONTINUE
+*
+ DO 140 IM = 1, NIDIM
+ M = IDIM( IM )
+*
+ DO 130 IN = 1, NIDIM
+ N = IDIM( IN )
+* Set LDB to 1 more than minimum value if room.
+ LDB = M
+ IF( LDB.LT.NMAX )
+ $ LDB = LDB + 1
+* Skip tests if not enough room.
+ IF( LDB.GT.NMAX )
+ $ GO TO 130
+ LBB = LDB*N
+ NULL = M.LE.0.OR.N.LE.0
+*
+ DO 120 ICS = 1, 2
+ SIDE = ICHS( ICS: ICS )
+ LEFT = SIDE.EQ.'L'
+ IF( LEFT )THEN
+ NA = M
+ ELSE
+ NA = N
+ END IF
+* Set LDA to 1 more than minimum value if room.
+ LDA = NA
+ IF( LDA.LT.NMAX )
+ $ LDA = LDA + 1
+* Skip tests if not enough room.
+ IF( LDA.GT.NMAX )
+ $ GO TO 130
+ LAA = LDA*NA
+*
+ DO 110 ICU = 1, 2
+ UPLO = ICHU( ICU: ICU )
+*
+ DO 100 ICT = 1, 3
+ TRANSA = ICHT( ICT: ICT )
+*
+ DO 90 ICD = 1, 2
+ DIAG = ICHD( ICD: ICD )
+*
+ DO 80 IA = 1, NALF
+ ALPHA = ALF( IA )
+*
+* Generate the matrix A.
+*
+ CALL DMAKE( 'TR', UPLO, DIAG, NA, NA, A,
+ $ NMAX, AA, LDA, RESET, ZERO )
+*
+* Generate the matrix B.
+*
+ CALL DMAKE( 'GE', ' ', ' ', M, N, B, NMAX,
+ $ BB, LDB, RESET, ZERO )
+*
+ NC = NC + 1
+*
+* Save every datum before calling the
+* subroutine.
+*
+ SIDES = SIDE
+ UPLOS = UPLO
+ TRANAS = TRANSA
+ DIAGS = DIAG
+ MS = M
+ NS = N
+ ALS = ALPHA
+ DO 30 I = 1, LAA
+ AS( I ) = AA( I )
+ 30 CONTINUE
+ LDAS = LDA
+ DO 40 I = 1, LBB
+ BS( I ) = BB( I )
+ 40 CONTINUE
+ LDBS = LDB
+*
+* Call the subroutine.
+*
+ IF( SNAME( 4: 5 ).EQ.'MM' )THEN
+ IF( TRACE )
+ $ WRITE( NTRA, FMT = 9995 )NC, SNAME,
+ $ SIDE, UPLO, TRANSA, DIAG, M, N, ALPHA,
+ $ LDA, LDB
+ IF( REWI )
+ $ REWIND NTRA
+ CALL DTRMM( SIDE, UPLO, TRANSA, DIAG, M,
+ $ N, ALPHA, AA, LDA, BB, LDB )
+ ELSE IF( SNAME( 4: 5 ).EQ.'SM' )THEN
+ IF( TRACE )
+ $ WRITE( NTRA, FMT = 9995 )NC, SNAME,
+ $ SIDE, UPLO, TRANSA, DIAG, M, N, ALPHA,
+ $ LDA, LDB
+ IF( REWI )
+ $ REWIND NTRA
+ CALL DTRSM( SIDE, UPLO, TRANSA, DIAG, M,
+ $ N, ALPHA, AA, LDA, BB, LDB )
+ END IF
+*
+* Check if error-exit was taken incorrectly.
+*
+ IF( .NOT.OK )THEN
+ WRITE( NOUT, FMT = 9994 )
+ FATAL = .TRUE.
+ GO TO 150
+ END IF
+*
+* See what data changed inside subroutines.
+*
+ ISAME( 1 ) = SIDES.EQ.SIDE
+ ISAME( 2 ) = UPLOS.EQ.UPLO
+ ISAME( 3 ) = TRANAS.EQ.TRANSA
+ ISAME( 4 ) = DIAGS.EQ.DIAG
+ ISAME( 5 ) = MS.EQ.M
+ ISAME( 6 ) = NS.EQ.N
+ ISAME( 7 ) = ALS.EQ.ALPHA
+ ISAME( 8 ) = LDE( AS, AA, LAA )
+ ISAME( 9 ) = LDAS.EQ.LDA
+ IF( NULL )THEN
+ ISAME( 10 ) = LDE( BS, BB, LBB )
+ ELSE
+ ISAME( 10 ) = LDERES( 'GE', ' ', M, N, BS,
+ $ BB, LDB )
+ END IF
+ ISAME( 11 ) = LDBS.EQ.LDB
+*
+* If data was incorrectly changed, report and
+* return.
+*
+ SAME = .TRUE.
+ DO 50 I = 1, NARGS
+ SAME = SAME.AND.ISAME( I )
+ IF( .NOT.ISAME( I ) )
+ $ WRITE( NOUT, FMT = 9998 )I
+ 50 CONTINUE
+ IF( .NOT.SAME )THEN
+ FATAL = .TRUE.
+ GO TO 150
+ END IF
+*
+ IF( .NOT.NULL )THEN
+ IF( SNAME( 4: 5 ).EQ.'MM' )THEN
+*
+* Check the result.
+*
+ IF( LEFT )THEN
+ CALL DMMCH( TRANSA, 'N', M, N, M,
+ $ ALPHA, A, NMAX, B, NMAX,
+ $ ZERO, C, NMAX, CT, G,
+ $ BB, LDB, EPS, ERR,
+ $ FATAL, NOUT, .TRUE. )
+ ELSE
+ CALL DMMCH( 'N', TRANSA, M, N, N,
+ $ ALPHA, B, NMAX, A, NMAX,
+ $ ZERO, C, NMAX, CT, G,
+ $ BB, LDB, EPS, ERR,
+ $ FATAL, NOUT, .TRUE. )
+ END IF
+ ELSE IF( SNAME( 4: 5 ).EQ.'SM' )THEN
+*
+* Compute approximation to original
+* matrix.
+*
+ DO 70 J = 1, N
+ DO 60 I = 1, M
+ C( I, J ) = BB( I + ( J - 1 )*
+ $ LDB )
+ BB( I + ( J - 1 )*LDB ) = ALPHA*
+ $ B( I, J )
+ 60 CONTINUE
+ 70 CONTINUE
+*
+ IF( LEFT )THEN
+ CALL DMMCH( TRANSA, 'N', M, N, M,
+ $ ONE, A, NMAX, C, NMAX,
+ $ ZERO, B, NMAX, CT, G,
+ $ BB, LDB, EPS, ERR,
+ $ FATAL, NOUT, .FALSE. )
+ ELSE
+ CALL DMMCH( 'N', TRANSA, M, N, N,
+ $ ONE, C, NMAX, A, NMAX,
+ $ ZERO, B, NMAX, CT, G,
+ $ BB, LDB, EPS, ERR,
+ $ FATAL, NOUT, .FALSE. )
+ END IF
+ END IF
+ ERRMAX = MAX( ERRMAX, ERR )
+* If got really bad answer, report and
+* return.
+ IF( FATAL )
+ $ GO TO 150
+ END IF
+*
+ 80 CONTINUE
+*
+ 90 CONTINUE
+*
+ 100 CONTINUE
+*
+ 110 CONTINUE
+*
+ 120 CONTINUE
+*
+ 130 CONTINUE
+*
+ 140 CONTINUE
+*
+* Report result.
+*
+ IF( ERRMAX.LT.THRESH )THEN
+ WRITE( NOUT, FMT = 9999 )SNAME, NC
+ ELSE
+ WRITE( NOUT, FMT = 9997 )SNAME, NC, ERRMAX
+ END IF
+ GO TO 160
+*
+ 150 CONTINUE
+ WRITE( NOUT, FMT = 9996 )SNAME
+ WRITE( NOUT, FMT = 9995 )NC, SNAME, SIDE, UPLO, TRANSA, DIAG, M,
+ $ N, ALPHA, LDA, LDB
+*
+ 160 CONTINUE
+ RETURN
+*
+ 9999 FORMAT( ' ', A6, ' PASSED THE COMPUTATIONAL TESTS (', I6, ' CALL',
+ $ 'S)' )
+ 9998 FORMAT( ' ******* FATAL ERROR - PARAMETER NUMBER ', I2, ' WAS CH',
+ $ 'ANGED INCORRECTLY *******' )
+ 9997 FORMAT( ' ', A6, ' COMPLETED THE COMPUTATIONAL TESTS (', I6, ' C',
+ $ 'ALLS)', /' ******* BUT WITH MAXIMUM TEST RATIO', F8.2,
+ $ ' - SUSPECT *******' )
+ 9996 FORMAT( ' ******* ', A6, ' FAILED ON CALL NUMBER:' )
+ 9995 FORMAT( 1X, I6, ': ', A6, '(', 4( '''', A1, ''',' ), 2( I3, ',' ),
+ $ F4.1, ', A,', I3, ', B,', I3, ') .' )
+ 9994 FORMAT( ' ******* FATAL ERROR - ERROR-EXIT TAKEN ON VALID CALL *',
+ $ '******' )
+*
+* End of DCHK3.
+*
+ END
+ SUBROUTINE DCHK4( SNAME, EPS, THRESH, NOUT, NTRA, TRACE, REWI,
+ $ FATAL, NIDIM, IDIM, NALF, ALF, NBET, BET, NMAX,
+ $ A, AA, AS, B, BB, BS, C, CC, CS, CT, G )
+*
+* Tests DSYRK.
+*
+* Auxiliary routine for test program for Level 3 Blas.
+*
+* -- Written on 8-February-1989.
+* Jack Dongarra, Argonne National Laboratory.
+* Iain Duff, AERE Harwell.
+* Jeremy Du Croz, Numerical Algorithms Group Ltd.
+* Sven Hammarling, Numerical Algorithms Group Ltd.
+*
+* .. Parameters ..
+ DOUBLE PRECISION ZERO
+ PARAMETER ( ZERO = 0.0D0 )
+* .. Scalar Arguments ..
+ DOUBLE PRECISION EPS, THRESH
+ INTEGER NALF, NBET, NIDIM, NMAX, NOUT, NTRA
+ LOGICAL FATAL, REWI, TRACE
+ CHARACTER*6 SNAME
+* .. Array Arguments ..
+ DOUBLE PRECISION A( NMAX, NMAX ), AA( NMAX*NMAX ), ALF( NALF ),
+ $ AS( NMAX*NMAX ), B( NMAX, NMAX ),
+ $ BB( NMAX*NMAX ), BET( NBET ), BS( NMAX*NMAX ),
+ $ C( NMAX, NMAX ), CC( NMAX*NMAX ),
+ $ CS( NMAX*NMAX ), CT( NMAX ), G( NMAX )
+ INTEGER IDIM( NIDIM )
+* .. Local Scalars ..
+ DOUBLE PRECISION ALPHA, ALS, BETA, BETS, ERR, ERRMAX
+ INTEGER I, IA, IB, ICT, ICU, IK, IN, J, JC, JJ, K, KS,
+ $ LAA, LCC, LDA, LDAS, LDC, LDCS, LJ, MA, N, NA,
+ $ NARGS, NC, NS
+ LOGICAL NULL, RESET, SAME, TRAN, UPPER
+ CHARACTER*1 TRANS, TRANSS, UPLO, UPLOS
+ CHARACTER*2 ICHU
+ CHARACTER*3 ICHT
+* .. Local Arrays ..
+ LOGICAL ISAME( 13 )
+* .. External Functions ..
+ LOGICAL LDE, LDERES
+ EXTERNAL LDE, LDERES
+* .. External Subroutines ..
+ EXTERNAL DMAKE, DMMCH, DSYRK
+* .. Intrinsic Functions ..
+ INTRINSIC MAX
+* .. Scalars in Common ..
+ INTEGER INFOT, NOUTC
+ LOGICAL LERR, OK
+* .. Common blocks ..
+ COMMON /INFOC/INFOT, NOUTC, OK, LERR
+* .. Data statements ..
+ DATA ICHT/'NTC'/, ICHU/'UL'/
+* .. Executable Statements ..
+*
+ NARGS = 10
+ NC = 0
+ RESET = .TRUE.
+ ERRMAX = ZERO
+*
+ DO 100 IN = 1, NIDIM
+ N = IDIM( IN )
+* Set LDC to 1 more than minimum value if room.
+ LDC = N
+ IF( LDC.LT.NMAX )
+ $ LDC = LDC + 1
+* Skip tests if not enough room.
+ IF( LDC.GT.NMAX )
+ $ GO TO 100
+ LCC = LDC*N
+ NULL = N.LE.0
+*
+ DO 90 IK = 1, NIDIM
+ K = IDIM( IK )
+*
+ DO 80 ICT = 1, 3
+ TRANS = ICHT( ICT: ICT )
+ TRAN = TRANS.EQ.'T'.OR.TRANS.EQ.'C'
+ IF( TRAN )THEN
+ MA = K
+ NA = N
+ ELSE
+ MA = N
+ NA = K
+ END IF
+* Set LDA to 1 more than minimum value if room.
+ LDA = MA
+ IF( LDA.LT.NMAX )
+ $ LDA = LDA + 1
+* Skip tests if not enough room.
+ IF( LDA.GT.NMAX )
+ $ GO TO 80
+ LAA = LDA*NA
+*
+* Generate the matrix A.
+*
+ CALL DMAKE( 'GE', ' ', ' ', MA, NA, A, NMAX, AA, LDA,
+ $ RESET, ZERO )
+*
+ DO 70 ICU = 1, 2
+ UPLO = ICHU( ICU: ICU )
+ UPPER = UPLO.EQ.'U'
+*
+ DO 60 IA = 1, NALF
+ ALPHA = ALF( IA )
+*
+ DO 50 IB = 1, NBET
+ BETA = BET( IB )
+*
+* Generate the matrix C.
+*
+ CALL DMAKE( 'SY', UPLO, ' ', N, N, C, NMAX, CC,
+ $ LDC, RESET, ZERO )
+*
+ NC = NC + 1
+*
+* Save every datum before calling the subroutine.
+*
+ UPLOS = UPLO
+ TRANSS = TRANS
+ NS = N
+ KS = K
+ ALS = ALPHA
+ DO 10 I = 1, LAA
+ AS( I ) = AA( I )
+ 10 CONTINUE
+ LDAS = LDA
+ BETS = BETA
+ DO 20 I = 1, LCC
+ CS( I ) = CC( I )
+ 20 CONTINUE
+ LDCS = LDC
+*
+* Call the subroutine.
+*
+ IF( TRACE )
+ $ WRITE( NTRA, FMT = 9994 )NC, SNAME, UPLO,
+ $ TRANS, N, K, ALPHA, LDA, BETA, LDC
+ IF( REWI )
+ $ REWIND NTRA
+ CALL DSYRK( UPLO, TRANS, N, K, ALPHA, AA, LDA,
+ $ BETA, CC, LDC )
+*
+* Check if error-exit was taken incorrectly.
+*
+ IF( .NOT.OK )THEN
+ WRITE( NOUT, FMT = 9993 )
+ FATAL = .TRUE.
+ GO TO 120
+ END IF
+*
+* See what data changed inside subroutines.
+*
+ ISAME( 1 ) = UPLOS.EQ.UPLO
+ ISAME( 2 ) = TRANSS.EQ.TRANS
+ ISAME( 3 ) = NS.EQ.N
+ ISAME( 4 ) = KS.EQ.K
+ ISAME( 5 ) = ALS.EQ.ALPHA
+ ISAME( 6 ) = LDE( AS, AA, LAA )
+ ISAME( 7 ) = LDAS.EQ.LDA
+ ISAME( 8 ) = BETS.EQ.BETA
+ IF( NULL )THEN
+ ISAME( 9 ) = LDE( CS, CC, LCC )
+ ELSE
+ ISAME( 9 ) = LDERES( 'SY', UPLO, N, N, CS,
+ $ CC, LDC )
+ END IF
+ ISAME( 10 ) = LDCS.EQ.LDC
+*
+* If data was incorrectly changed, report and
+* return.
+*
+ SAME = .TRUE.
+ DO 30 I = 1, NARGS
+ SAME = SAME.AND.ISAME( I )
+ IF( .NOT.ISAME( I ) )
+ $ WRITE( NOUT, FMT = 9998 )I
+ 30 CONTINUE
+ IF( .NOT.SAME )THEN
+ FATAL = .TRUE.
+ GO TO 120
+ END IF
+*
+ IF( .NOT.NULL )THEN
+*
+* Check the result column by column.
+*
+ JC = 1
+ DO 40 J = 1, N
+ IF( UPPER )THEN
+ JJ = 1
+ LJ = J
+ ELSE
+ JJ = J
+ LJ = N - J + 1
+ END IF
+ IF( TRAN )THEN
+ CALL DMMCH( 'T', 'N', LJ, 1, K, ALPHA,
+ $ A( 1, JJ ), NMAX,
+ $ A( 1, J ), NMAX, BETA,
+ $ C( JJ, J ), NMAX, CT, G,
+ $ CC( JC ), LDC, EPS, ERR,
+ $ FATAL, NOUT, .TRUE. )
+ ELSE
+ CALL DMMCH( 'N', 'T', LJ, 1, K, ALPHA,
+ $ A( JJ, 1 ), NMAX,
+ $ A( J, 1 ), NMAX, BETA,
+ $ C( JJ, J ), NMAX, CT, G,
+ $ CC( JC ), LDC, EPS, ERR,
+ $ FATAL, NOUT, .TRUE. )
+ END IF
+ IF( UPPER )THEN
+ JC = JC + LDC
+ ELSE
+ JC = JC + LDC + 1
+ END IF
+ ERRMAX = MAX( ERRMAX, ERR )
+* If got really bad answer, report and
+* return.
+ IF( FATAL )
+ $ GO TO 110
+ 40 CONTINUE
+ END IF
+*
+ 50 CONTINUE
+*
+ 60 CONTINUE
+*
+ 70 CONTINUE
+*
+ 80 CONTINUE
+*
+ 90 CONTINUE
+*
+ 100 CONTINUE
+*
+* Report result.
+*
+ IF( ERRMAX.LT.THRESH )THEN
+ WRITE( NOUT, FMT = 9999 )SNAME, NC
+ ELSE
+ WRITE( NOUT, FMT = 9997 )SNAME, NC, ERRMAX
+ END IF
+ GO TO 130
+*
+ 110 CONTINUE
+ IF( N.GT.1 )
+ $ WRITE( NOUT, FMT = 9995 )J
+*
+ 120 CONTINUE
+ WRITE( NOUT, FMT = 9996 )SNAME
+ WRITE( NOUT, FMT = 9994 )NC, SNAME, UPLO, TRANS, N, K, ALPHA,
+ $ LDA, BETA, LDC
+*
+ 130 CONTINUE
+ RETURN
+*
+ 9999 FORMAT( ' ', A6, ' PASSED THE COMPUTATIONAL TESTS (', I6, ' CALL',
+ $ 'S)' )
+ 9998 FORMAT( ' ******* FATAL ERROR - PARAMETER NUMBER ', I2, ' WAS CH',
+ $ 'ANGED INCORRECTLY *******' )
+ 9997 FORMAT( ' ', A6, ' COMPLETED THE COMPUTATIONAL TESTS (', I6, ' C',
+ $ 'ALLS)', /' ******* BUT WITH MAXIMUM TEST RATIO', F8.2,
+ $ ' - SUSPECT *******' )
+ 9996 FORMAT( ' ******* ', A6, ' FAILED ON CALL NUMBER:' )
+ 9995 FORMAT( ' THESE ARE THE RESULTS FOR COLUMN ', I3 )
+ 9994 FORMAT( 1X, I6, ': ', A6, '(', 2( '''', A1, ''',' ), 2( I3, ',' ),
+ $ F4.1, ', A,', I3, ',', F4.1, ', C,', I3, ') .' )
+ 9993 FORMAT( ' ******* FATAL ERROR - ERROR-EXIT TAKEN ON VALID CALL *',
+ $ '******' )
+*
+* End of DCHK4.
+*
+ END
+ SUBROUTINE DCHK5( SNAME, EPS, THRESH, NOUT, NTRA, TRACE, REWI,
+ $ FATAL, NIDIM, IDIM, NALF, ALF, NBET, BET, NMAX,
+ $ AB, AA, AS, BB, BS, C, CC, CS, CT, G, W )
+*
+* Tests DSYR2K.
+*
+* Auxiliary routine for test program for Level 3 Blas.
+*
+* -- Written on 8-February-1989.
+* Jack Dongarra, Argonne National Laboratory.
+* Iain Duff, AERE Harwell.
+* Jeremy Du Croz, Numerical Algorithms Group Ltd.
+* Sven Hammarling, Numerical Algorithms Group Ltd.
+*
+* .. Parameters ..
+ DOUBLE PRECISION ZERO
+ PARAMETER ( ZERO = 0.0D0 )
+* .. Scalar Arguments ..
+ DOUBLE PRECISION EPS, THRESH
+ INTEGER NALF, NBET, NIDIM, NMAX, NOUT, NTRA
+ LOGICAL FATAL, REWI, TRACE
+ CHARACTER*6 SNAME
+* .. Array Arguments ..
+ DOUBLE PRECISION AA( NMAX*NMAX ), AB( 2*NMAX*NMAX ),
+ $ ALF( NALF ), AS( NMAX*NMAX ), BB( NMAX*NMAX ),
+ $ BET( NBET ), BS( NMAX*NMAX ), C( NMAX, NMAX ),
+ $ CC( NMAX*NMAX ), CS( NMAX*NMAX ), CT( NMAX ),
+ $ G( NMAX ), W( 2*NMAX )
+ INTEGER IDIM( NIDIM )
+* .. Local Scalars ..
+ DOUBLE PRECISION ALPHA, ALS, BETA, BETS, ERR, ERRMAX
+ INTEGER I, IA, IB, ICT, ICU, IK, IN, J, JC, JJ, JJAB,
+ $ K, KS, LAA, LBB, LCC, LDA, LDAS, LDB, LDBS,
+ $ LDC, LDCS, LJ, MA, N, NA, NARGS, NC, NS
+ LOGICAL NULL, RESET, SAME, TRAN, UPPER
+ CHARACTER*1 TRANS, TRANSS, UPLO, UPLOS
+ CHARACTER*2 ICHU
+ CHARACTER*3 ICHT
+* .. Local Arrays ..
+ LOGICAL ISAME( 13 )
+* .. External Functions ..
+ LOGICAL LDE, LDERES
+ EXTERNAL LDE, LDERES
+* .. External Subroutines ..
+ EXTERNAL DMAKE, DMMCH, DSYR2K
+* .. Intrinsic Functions ..
+ INTRINSIC MAX
+* .. Scalars in Common ..
+ INTEGER INFOT, NOUTC
+ LOGICAL LERR, OK
+* .. Common blocks ..
+ COMMON /INFOC/INFOT, NOUTC, OK, LERR
+* .. Data statements ..
+ DATA ICHT/'NTC'/, ICHU/'UL'/
+* .. Executable Statements ..
+*
+ NARGS = 12
+ NC = 0
+ RESET = .TRUE.
+ ERRMAX = ZERO
+*
+ DO 130 IN = 1, NIDIM
+ N = IDIM( IN )
+* Set LDC to 1 more than minimum value if room.
+ LDC = N
+ IF( LDC.LT.NMAX )
+ $ LDC = LDC + 1
+* Skip tests if not enough room.
+ IF( LDC.GT.NMAX )
+ $ GO TO 130
+ LCC = LDC*N
+ NULL = N.LE.0
+*
+ DO 120 IK = 1, NIDIM
+ K = IDIM( IK )
+*
+ DO 110 ICT = 1, 3
+ TRANS = ICHT( ICT: ICT )
+ TRAN = TRANS.EQ.'T'.OR.TRANS.EQ.'C'
+ IF( TRAN )THEN
+ MA = K
+ NA = N
+ ELSE
+ MA = N
+ NA = K
+ END IF
+* Set LDA to 1 more than minimum value if room.
+ LDA = MA
+ IF( LDA.LT.NMAX )
+ $ LDA = LDA + 1
+* Skip tests if not enough room.
+ IF( LDA.GT.NMAX )
+ $ GO TO 110
+ LAA = LDA*NA
+*
+* Generate the matrix A.
+*
+ IF( TRAN )THEN
+ CALL DMAKE( 'GE', ' ', ' ', MA, NA, AB, 2*NMAX, AA,
+ $ LDA, RESET, ZERO )
+ ELSE
+ CALL DMAKE( 'GE', ' ', ' ', MA, NA, AB, NMAX, AA, LDA,
+ $ RESET, ZERO )
+ END IF
+*
+* Generate the matrix B.
+*
+ LDB = LDA
+ LBB = LAA
+ IF( TRAN )THEN
+ CALL DMAKE( 'GE', ' ', ' ', MA, NA, AB( K + 1 ),
+ $ 2*NMAX, BB, LDB, RESET, ZERO )
+ ELSE
+ CALL DMAKE( 'GE', ' ', ' ', MA, NA, AB( K*NMAX + 1 ),
+ $ NMAX, BB, LDB, RESET, ZERO )
+ END IF
+*
+ DO 100 ICU = 1, 2
+ UPLO = ICHU( ICU: ICU )
+ UPPER = UPLO.EQ.'U'
+*
+ DO 90 IA = 1, NALF
+ ALPHA = ALF( IA )
+*
+ DO 80 IB = 1, NBET
+ BETA = BET( IB )
+*
+* Generate the matrix C.
+*
+ CALL DMAKE( 'SY', UPLO, ' ', N, N, C, NMAX, CC,
+ $ LDC, RESET, ZERO )
+*
+ NC = NC + 1
+*
+* Save every datum before calling the subroutine.
+*
+ UPLOS = UPLO
+ TRANSS = TRANS
+ NS = N
+ KS = K
+ ALS = ALPHA
+ DO 10 I = 1, LAA
+ AS( I ) = AA( I )
+ 10 CONTINUE
+ LDAS = LDA
+ DO 20 I = 1, LBB
+ BS( I ) = BB( I )
+ 20 CONTINUE
+ LDBS = LDB
+ BETS = BETA
+ DO 30 I = 1, LCC
+ CS( I ) = CC( I )
+ 30 CONTINUE
+ LDCS = LDC
+*
+* Call the subroutine.
+*
+ IF( TRACE )
+ $ WRITE( NTRA, FMT = 9994 )NC, SNAME, UPLO,
+ $ TRANS, N, K, ALPHA, LDA, LDB, BETA, LDC
+ IF( REWI )
+ $ REWIND NTRA
+ CALL DSYR2K( UPLO, TRANS, N, K, ALPHA, AA, LDA,
+ $ BB, LDB, BETA, CC, LDC )
+*
+* Check if error-exit was taken incorrectly.
+*
+ IF( .NOT.OK )THEN
+ WRITE( NOUT, FMT = 9993 )
+ FATAL = .TRUE.
+ GO TO 150
+ END IF
+*
+* See what data changed inside subroutines.
+*
+ ISAME( 1 ) = UPLOS.EQ.UPLO
+ ISAME( 2 ) = TRANSS.EQ.TRANS
+ ISAME( 3 ) = NS.EQ.N
+ ISAME( 4 ) = KS.EQ.K
+ ISAME( 5 ) = ALS.EQ.ALPHA
+ ISAME( 6 ) = LDE( AS, AA, LAA )
+ ISAME( 7 ) = LDAS.EQ.LDA
+ ISAME( 8 ) = LDE( BS, BB, LBB )
+ ISAME( 9 ) = LDBS.EQ.LDB
+ ISAME( 10 ) = BETS.EQ.BETA
+ IF( NULL )THEN
+ ISAME( 11 ) = LDE( CS, CC, LCC )
+ ELSE
+ ISAME( 11 ) = LDERES( 'SY', UPLO, N, N, CS,
+ $ CC, LDC )
+ END IF
+ ISAME( 12 ) = LDCS.EQ.LDC
+*
+* If data was incorrectly changed, report and
+* return.
+*
+ SAME = .TRUE.
+ DO 40 I = 1, NARGS
+ SAME = SAME.AND.ISAME( I )
+ IF( .NOT.ISAME( I ) )
+ $ WRITE( NOUT, FMT = 9998 )I
+ 40 CONTINUE
+ IF( .NOT.SAME )THEN
+ FATAL = .TRUE.
+ GO TO 150
+ END IF
+*
+ IF( .NOT.NULL )THEN
+*
+* Check the result column by column.
+*
+ JJAB = 1
+ JC = 1
+ DO 70 J = 1, N
+ IF( UPPER )THEN
+ JJ = 1
+ LJ = J
+ ELSE
+ JJ = J
+ LJ = N - J + 1
+ END IF
+ IF( TRAN )THEN
+ DO 50 I = 1, K
+ W( I ) = AB( ( J - 1 )*2*NMAX + K +
+ $ I )
+ W( K + I ) = AB( ( J - 1 )*2*NMAX +
+ $ I )
+ 50 CONTINUE
+ CALL DMMCH( 'T', 'N', LJ, 1, 2*K,
+ $ ALPHA, AB( JJAB ), 2*NMAX,
+ $ W, 2*NMAX, BETA,
+ $ C( JJ, J ), NMAX, CT, G,
+ $ CC( JC ), LDC, EPS, ERR,
+ $ FATAL, NOUT, .TRUE. )
+ ELSE
+ DO 60 I = 1, K
+ W( I ) = AB( ( K + I - 1 )*NMAX +
+ $ J )
+ W( K + I ) = AB( ( I - 1 )*NMAX +
+ $ J )
+ 60 CONTINUE
+ CALL DMMCH( 'N', 'N', LJ, 1, 2*K,
+ $ ALPHA, AB( JJ ), NMAX, W,
+ $ 2*NMAX, BETA, C( JJ, J ),
+ $ NMAX, CT, G, CC( JC ), LDC,
+ $ EPS, ERR, FATAL, NOUT,
+ $ .TRUE. )
+ END IF
+ IF( UPPER )THEN
+ JC = JC + LDC
+ ELSE
+ JC = JC + LDC + 1
+ IF( TRAN )
+ $ JJAB = JJAB + 2*NMAX
+ END IF
+ ERRMAX = MAX( ERRMAX, ERR )
+* If got really bad answer, report and
+* return.
+ IF( FATAL )
+ $ GO TO 140
+ 70 CONTINUE
+ END IF
+*
+ 80 CONTINUE
+*
+ 90 CONTINUE
+*
+ 100 CONTINUE
+*
+ 110 CONTINUE
+*
+ 120 CONTINUE
+*
+ 130 CONTINUE
+*
+* Report result.
+*
+ IF( ERRMAX.LT.THRESH )THEN
+ WRITE( NOUT, FMT = 9999 )SNAME, NC
+ ELSE
+ WRITE( NOUT, FMT = 9997 )SNAME, NC, ERRMAX
+ END IF
+ GO TO 160
+*
+ 140 CONTINUE
+ IF( N.GT.1 )
+ $ WRITE( NOUT, FMT = 9995 )J
+*
+ 150 CONTINUE
+ WRITE( NOUT, FMT = 9996 )SNAME
+ WRITE( NOUT, FMT = 9994 )NC, SNAME, UPLO, TRANS, N, K, ALPHA,
+ $ LDA, LDB, BETA, LDC
+*
+ 160 CONTINUE
+ RETURN
+*
+ 9999 FORMAT( ' ', A6, ' PASSED THE COMPUTATIONAL TESTS (', I6, ' CALL',
+ $ 'S)' )
+ 9998 FORMAT( ' ******* FATAL ERROR - PARAMETER NUMBER ', I2, ' WAS CH',
+ $ 'ANGED INCORRECTLY *******' )
+ 9997 FORMAT( ' ', A6, ' COMPLETED THE COMPUTATIONAL TESTS (', I6, ' C',
+ $ 'ALLS)', /' ******* BUT WITH MAXIMUM TEST RATIO', F8.2,
+ $ ' - SUSPECT *******' )
+ 9996 FORMAT( ' ******* ', A6, ' FAILED ON CALL NUMBER:' )
+ 9995 FORMAT( ' THESE ARE THE RESULTS FOR COLUMN ', I3 )
+ 9994 FORMAT( 1X, I6, ': ', A6, '(', 2( '''', A1, ''',' ), 2( I3, ',' ),
+ $ F4.1, ', A,', I3, ', B,', I3, ',', F4.1, ', C,', I3, ') ',
+ $ ' .' )
+ 9993 FORMAT( ' ******* FATAL ERROR - ERROR-EXIT TAKEN ON VALID CALL *',
+ $ '******' )
+*
+* End of DCHK5.
+*
+ END
+ SUBROUTINE DCHKE( ISNUM, SRNAMT, NOUT )
+*
+* Tests the error exits from the Level 3 Blas.
+* Requires a special version of the error-handling routine XERBLA.
+* ALPHA, BETA, A, B and C should not need to be defined.
+*
+* Auxiliary routine for test program for Level 3 Blas.
+*
+* -- Written on 8-February-1989.
+* Jack Dongarra, Argonne National Laboratory.
+* Iain Duff, AERE Harwell.
+* Jeremy Du Croz, Numerical Algorithms Group Ltd.
+* Sven Hammarling, Numerical Algorithms Group Ltd.
+*
+* .. Scalar Arguments ..
+ INTEGER ISNUM, NOUT
+ CHARACTER*6 SRNAMT
+* .. Scalars in Common ..
+ INTEGER INFOT, NOUTC
+ LOGICAL LERR, OK
+* .. Local Scalars ..
+ DOUBLE PRECISION ALPHA, BETA
+* .. Local Arrays ..
+ DOUBLE PRECISION A( 2, 1 ), B( 2, 1 ), C( 2, 1 )
+* .. External Subroutines ..
+ EXTERNAL CHKXER, DGEMM, DSYMM, DSYR2K, DSYRK, DTRMM,
+ $ DTRSM
+* .. Common blocks ..
+ COMMON /INFOC/INFOT, NOUTC, OK, LERR
+* .. Executable Statements ..
+* OK is set to .FALSE. by the special version of XERBLA or by CHKXER
+* if anything is wrong.
+ OK = .TRUE.
+* LERR is set to .TRUE. by the special version of XERBLA each time
+* it is called, and is then tested and re-set by CHKXER.
+ LERR = .FALSE.
+ GO TO ( 10, 20, 30, 40, 50, 60 )ISNUM
+ 10 INFOT = 1
+ CALL DGEMM( '/', 'N', 0, 0, 0, ALPHA, A, 1, B, 1, BETA, C, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 1
+ CALL DGEMM( '/', 'T', 0, 0, 0, ALPHA, A, 1, B, 1, BETA, C, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 2
+ CALL DGEMM( 'N', '/', 0, 0, 0, ALPHA, A, 1, B, 1, BETA, C, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 2
+ CALL DGEMM( 'T', '/', 0, 0, 0, ALPHA, A, 1, B, 1, BETA, C, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 3
+ CALL DGEMM( 'N', 'N', -1, 0, 0, ALPHA, A, 1, B, 1, BETA, C, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 3
+ CALL DGEMM( 'N', 'T', -1, 0, 0, ALPHA, A, 1, B, 1, BETA, C, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 3
+ CALL DGEMM( 'T', 'N', -1, 0, 0, ALPHA, A, 1, B, 1, BETA, C, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 3
+ CALL DGEMM( 'T', 'T', -1, 0, 0, ALPHA, A, 1, B, 1, BETA, C, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 4
+ CALL DGEMM( 'N', 'N', 0, -1, 0, ALPHA, A, 1, B, 1, BETA, C, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 4
+ CALL DGEMM( 'N', 'T', 0, -1, 0, ALPHA, A, 1, B, 1, BETA, C, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 4
+ CALL DGEMM( 'T', 'N', 0, -1, 0, ALPHA, A, 1, B, 1, BETA, C, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 4
+ CALL DGEMM( 'T', 'T', 0, -1, 0, ALPHA, A, 1, B, 1, BETA, C, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 5
+ CALL DGEMM( 'N', 'N', 0, 0, -1, ALPHA, A, 1, B, 1, BETA, C, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 5
+ CALL DGEMM( 'N', 'T', 0, 0, -1, ALPHA, A, 1, B, 1, BETA, C, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 5
+ CALL DGEMM( 'T', 'N', 0, 0, -1, ALPHA, A, 1, B, 1, BETA, C, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 5
+ CALL DGEMM( 'T', 'T', 0, 0, -1, ALPHA, A, 1, B, 1, BETA, C, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 8
+ CALL DGEMM( 'N', 'N', 2, 0, 0, ALPHA, A, 1, B, 1, BETA, C, 2 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 8
+ CALL DGEMM( 'N', 'T', 2, 0, 0, ALPHA, A, 1, B, 1, BETA, C, 2 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 8
+ CALL DGEMM( 'T', 'N', 0, 0, 2, ALPHA, A, 1, B, 2, BETA, C, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 8
+ CALL DGEMM( 'T', 'T', 0, 0, 2, ALPHA, A, 1, B, 1, BETA, C, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 10
+ CALL DGEMM( 'N', 'N', 0, 0, 2, ALPHA, A, 1, B, 1, BETA, C, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 10
+ CALL DGEMM( 'T', 'N', 0, 0, 2, ALPHA, A, 2, B, 1, BETA, C, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 10
+ CALL DGEMM( 'N', 'T', 0, 2, 0, ALPHA, A, 1, B, 1, BETA, C, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 10
+ CALL DGEMM( 'T', 'T', 0, 2, 0, ALPHA, A, 1, B, 1, BETA, C, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 13
+ CALL DGEMM( 'N', 'N', 2, 0, 0, ALPHA, A, 2, B, 1, BETA, C, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 13
+ CALL DGEMM( 'N', 'T', 2, 0, 0, ALPHA, A, 2, B, 1, BETA, C, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 13
+ CALL DGEMM( 'T', 'N', 2, 0, 0, ALPHA, A, 1, B, 1, BETA, C, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 13
+ CALL DGEMM( 'T', 'T', 2, 0, 0, ALPHA, A, 1, B, 1, BETA, C, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ GO TO 70
+ 20 INFOT = 1
+ CALL DSYMM( '/', 'U', 0, 0, ALPHA, A, 1, B, 1, BETA, C, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 2
+ CALL DSYMM( 'L', '/', 0, 0, ALPHA, A, 1, B, 1, BETA, C, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 3
+ CALL DSYMM( 'L', 'U', -1, 0, ALPHA, A, 1, B, 1, BETA, C, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 3
+ CALL DSYMM( 'R', 'U', -1, 0, ALPHA, A, 1, B, 1, BETA, C, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 3
+ CALL DSYMM( 'L', 'L', -1, 0, ALPHA, A, 1, B, 1, BETA, C, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 3
+ CALL DSYMM( 'R', 'L', -1, 0, ALPHA, A, 1, B, 1, BETA, C, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 4
+ CALL DSYMM( 'L', 'U', 0, -1, ALPHA, A, 1, B, 1, BETA, C, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 4
+ CALL DSYMM( 'R', 'U', 0, -1, ALPHA, A, 1, B, 1, BETA, C, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 4
+ CALL DSYMM( 'L', 'L', 0, -1, ALPHA, A, 1, B, 1, BETA, C, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 4
+ CALL DSYMM( 'R', 'L', 0, -1, ALPHA, A, 1, B, 1, BETA, C, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 7
+ CALL DSYMM( 'L', 'U', 2, 0, ALPHA, A, 1, B, 2, BETA, C, 2 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 7
+ CALL DSYMM( 'R', 'U', 0, 2, ALPHA, A, 1, B, 1, BETA, C, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 7
+ CALL DSYMM( 'L', 'L', 2, 0, ALPHA, A, 1, B, 2, BETA, C, 2 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 7
+ CALL DSYMM( 'R', 'L', 0, 2, ALPHA, A, 1, B, 1, BETA, C, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 9
+ CALL DSYMM( 'L', 'U', 2, 0, ALPHA, A, 2, B, 1, BETA, C, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 9
+ CALL DSYMM( 'R', 'U', 2, 0, ALPHA, A, 1, B, 1, BETA, C, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 9
+ CALL DSYMM( 'L', 'L', 2, 0, ALPHA, A, 2, B, 1, BETA, C, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 9
+ CALL DSYMM( 'R', 'L', 2, 0, ALPHA, A, 1, B, 1, BETA, C, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 12
+ CALL DSYMM( 'L', 'U', 2, 0, ALPHA, A, 2, B, 2, BETA, C, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 12
+ CALL DSYMM( 'R', 'U', 2, 0, ALPHA, A, 1, B, 2, BETA, C, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 12
+ CALL DSYMM( 'L', 'L', 2, 0, ALPHA, A, 2, B, 2, BETA, C, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 12
+ CALL DSYMM( 'R', 'L', 2, 0, ALPHA, A, 1, B, 2, BETA, C, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ GO TO 70
+ 30 INFOT = 1
+ CALL DTRMM( '/', 'U', 'N', 'N', 0, 0, ALPHA, A, 1, B, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 2
+ CALL DTRMM( 'L', '/', 'N', 'N', 0, 0, ALPHA, A, 1, B, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 3
+ CALL DTRMM( 'L', 'U', '/', 'N', 0, 0, ALPHA, A, 1, B, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 4
+ CALL DTRMM( 'L', 'U', 'N', '/', 0, 0, ALPHA, A, 1, B, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 5
+ CALL DTRMM( 'L', 'U', 'N', 'N', -1, 0, ALPHA, A, 1, B, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 5
+ CALL DTRMM( 'L', 'U', 'T', 'N', -1, 0, ALPHA, A, 1, B, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 5
+ CALL DTRMM( 'R', 'U', 'N', 'N', -1, 0, ALPHA, A, 1, B, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 5
+ CALL DTRMM( 'R', 'U', 'T', 'N', -1, 0, ALPHA, A, 1, B, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 5
+ CALL DTRMM( 'L', 'L', 'N', 'N', -1, 0, ALPHA, A, 1, B, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 5
+ CALL DTRMM( 'L', 'L', 'T', 'N', -1, 0, ALPHA, A, 1, B, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 5
+ CALL DTRMM( 'R', 'L', 'N', 'N', -1, 0, ALPHA, A, 1, B, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 5
+ CALL DTRMM( 'R', 'L', 'T', 'N', -1, 0, ALPHA, A, 1, B, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 6
+ CALL DTRMM( 'L', 'U', 'N', 'N', 0, -1, ALPHA, A, 1, B, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 6
+ CALL DTRMM( 'L', 'U', 'T', 'N', 0, -1, ALPHA, A, 1, B, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 6
+ CALL DTRMM( 'R', 'U', 'N', 'N', 0, -1, ALPHA, A, 1, B, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 6
+ CALL DTRMM( 'R', 'U', 'T', 'N', 0, -1, ALPHA, A, 1, B, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 6
+ CALL DTRMM( 'L', 'L', 'N', 'N', 0, -1, ALPHA, A, 1, B, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 6
+ CALL DTRMM( 'L', 'L', 'T', 'N', 0, -1, ALPHA, A, 1, B, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 6
+ CALL DTRMM( 'R', 'L', 'N', 'N', 0, -1, ALPHA, A, 1, B, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 6
+ CALL DTRMM( 'R', 'L', 'T', 'N', 0, -1, ALPHA, A, 1, B, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 9
+ CALL DTRMM( 'L', 'U', 'N', 'N', 2, 0, ALPHA, A, 1, B, 2 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 9
+ CALL DTRMM( 'L', 'U', 'T', 'N', 2, 0, ALPHA, A, 1, B, 2 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 9
+ CALL DTRMM( 'R', 'U', 'N', 'N', 0, 2, ALPHA, A, 1, B, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 9
+ CALL DTRMM( 'R', 'U', 'T', 'N', 0, 2, ALPHA, A, 1, B, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 9
+ CALL DTRMM( 'L', 'L', 'N', 'N', 2, 0, ALPHA, A, 1, B, 2 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 9
+ CALL DTRMM( 'L', 'L', 'T', 'N', 2, 0, ALPHA, A, 1, B, 2 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 9
+ CALL DTRMM( 'R', 'L', 'N', 'N', 0, 2, ALPHA, A, 1, B, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 9
+ CALL DTRMM( 'R', 'L', 'T', 'N', 0, 2, ALPHA, A, 1, B, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 11
+ CALL DTRMM( 'L', 'U', 'N', 'N', 2, 0, ALPHA, A, 2, B, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 11
+ CALL DTRMM( 'L', 'U', 'T', 'N', 2, 0, ALPHA, A, 2, B, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 11
+ CALL DTRMM( 'R', 'U', 'N', 'N', 2, 0, ALPHA, A, 1, B, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 11
+ CALL DTRMM( 'R', 'U', 'T', 'N', 2, 0, ALPHA, A, 1, B, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 11
+ CALL DTRMM( 'L', 'L', 'N', 'N', 2, 0, ALPHA, A, 2, B, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 11
+ CALL DTRMM( 'L', 'L', 'T', 'N', 2, 0, ALPHA, A, 2, B, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 11
+ CALL DTRMM( 'R', 'L', 'N', 'N', 2, 0, ALPHA, A, 1, B, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 11
+ CALL DTRMM( 'R', 'L', 'T', 'N', 2, 0, ALPHA, A, 1, B, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ GO TO 70
+ 40 INFOT = 1
+ CALL DTRSM( '/', 'U', 'N', 'N', 0, 0, ALPHA, A, 1, B, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 2
+ CALL DTRSM( 'L', '/', 'N', 'N', 0, 0, ALPHA, A, 1, B, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 3
+ CALL DTRSM( 'L', 'U', '/', 'N', 0, 0, ALPHA, A, 1, B, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 4
+ CALL DTRSM( 'L', 'U', 'N', '/', 0, 0, ALPHA, A, 1, B, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 5
+ CALL DTRSM( 'L', 'U', 'N', 'N', -1, 0, ALPHA, A, 1, B, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 5
+ CALL DTRSM( 'L', 'U', 'T', 'N', -1, 0, ALPHA, A, 1, B, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 5
+ CALL DTRSM( 'R', 'U', 'N', 'N', -1, 0, ALPHA, A, 1, B, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 5
+ CALL DTRSM( 'R', 'U', 'T', 'N', -1, 0, ALPHA, A, 1, B, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 5
+ CALL DTRSM( 'L', 'L', 'N', 'N', -1, 0, ALPHA, A, 1, B, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 5
+ CALL DTRSM( 'L', 'L', 'T', 'N', -1, 0, ALPHA, A, 1, B, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 5
+ CALL DTRSM( 'R', 'L', 'N', 'N', -1, 0, ALPHA, A, 1, B, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 5
+ CALL DTRSM( 'R', 'L', 'T', 'N', -1, 0, ALPHA, A, 1, B, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 6
+ CALL DTRSM( 'L', 'U', 'N', 'N', 0, -1, ALPHA, A, 1, B, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 6
+ CALL DTRSM( 'L', 'U', 'T', 'N', 0, -1, ALPHA, A, 1, B, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 6
+ CALL DTRSM( 'R', 'U', 'N', 'N', 0, -1, ALPHA, A, 1, B, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 6
+ CALL DTRSM( 'R', 'U', 'T', 'N', 0, -1, ALPHA, A, 1, B, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 6
+ CALL DTRSM( 'L', 'L', 'N', 'N', 0, -1, ALPHA, A, 1, B, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 6
+ CALL DTRSM( 'L', 'L', 'T', 'N', 0, -1, ALPHA, A, 1, B, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 6
+ CALL DTRSM( 'R', 'L', 'N', 'N', 0, -1, ALPHA, A, 1, B, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 6
+ CALL DTRSM( 'R', 'L', 'T', 'N', 0, -1, ALPHA, A, 1, B, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 9
+ CALL DTRSM( 'L', 'U', 'N', 'N', 2, 0, ALPHA, A, 1, B, 2 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 9
+ CALL DTRSM( 'L', 'U', 'T', 'N', 2, 0, ALPHA, A, 1, B, 2 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 9
+ CALL DTRSM( 'R', 'U', 'N', 'N', 0, 2, ALPHA, A, 1, B, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 9
+ CALL DTRSM( 'R', 'U', 'T', 'N', 0, 2, ALPHA, A, 1, B, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 9
+ CALL DTRSM( 'L', 'L', 'N', 'N', 2, 0, ALPHA, A, 1, B, 2 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 9
+ CALL DTRSM( 'L', 'L', 'T', 'N', 2, 0, ALPHA, A, 1, B, 2 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 9
+ CALL DTRSM( 'R', 'L', 'N', 'N', 0, 2, ALPHA, A, 1, B, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 9
+ CALL DTRSM( 'R', 'L', 'T', 'N', 0, 2, ALPHA, A, 1, B, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 11
+ CALL DTRSM( 'L', 'U', 'N', 'N', 2, 0, ALPHA, A, 2, B, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 11
+ CALL DTRSM( 'L', 'U', 'T', 'N', 2, 0, ALPHA, A, 2, B, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 11
+ CALL DTRSM( 'R', 'U', 'N', 'N', 2, 0, ALPHA, A, 1, B, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 11
+ CALL DTRSM( 'R', 'U', 'T', 'N', 2, 0, ALPHA, A, 1, B, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 11
+ CALL DTRSM( 'L', 'L', 'N', 'N', 2, 0, ALPHA, A, 2, B, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 11
+ CALL DTRSM( 'L', 'L', 'T', 'N', 2, 0, ALPHA, A, 2, B, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 11
+ CALL DTRSM( 'R', 'L', 'N', 'N', 2, 0, ALPHA, A, 1, B, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 11
+ CALL DTRSM( 'R', 'L', 'T', 'N', 2, 0, ALPHA, A, 1, B, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ GO TO 70
+ 50 INFOT = 1
+ CALL DSYRK( '/', 'N', 0, 0, ALPHA, A, 1, BETA, C, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 2
+ CALL DSYRK( 'U', '/', 0, 0, ALPHA, A, 1, BETA, C, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 3
+ CALL DSYRK( 'U', 'N', -1, 0, ALPHA, A, 1, BETA, C, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 3
+ CALL DSYRK( 'U', 'T', -1, 0, ALPHA, A, 1, BETA, C, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 3
+ CALL DSYRK( 'L', 'N', -1, 0, ALPHA, A, 1, BETA, C, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 3
+ CALL DSYRK( 'L', 'T', -1, 0, ALPHA, A, 1, BETA, C, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 4
+ CALL DSYRK( 'U', 'N', 0, -1, ALPHA, A, 1, BETA, C, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 4
+ CALL DSYRK( 'U', 'T', 0, -1, ALPHA, A, 1, BETA, C, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 4
+ CALL DSYRK( 'L', 'N', 0, -1, ALPHA, A, 1, BETA, C, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 4
+ CALL DSYRK( 'L', 'T', 0, -1, ALPHA, A, 1, BETA, C, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 7
+ CALL DSYRK( 'U', 'N', 2, 0, ALPHA, A, 1, BETA, C, 2 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 7
+ CALL DSYRK( 'U', 'T', 0, 2, ALPHA, A, 1, BETA, C, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 7
+ CALL DSYRK( 'L', 'N', 2, 0, ALPHA, A, 1, BETA, C, 2 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 7
+ CALL DSYRK( 'L', 'T', 0, 2, ALPHA, A, 1, BETA, C, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 10
+ CALL DSYRK( 'U', 'N', 2, 0, ALPHA, A, 2, BETA, C, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 10
+ CALL DSYRK( 'U', 'T', 2, 0, ALPHA, A, 1, BETA, C, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 10
+ CALL DSYRK( 'L', 'N', 2, 0, ALPHA, A, 2, BETA, C, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 10
+ CALL DSYRK( 'L', 'T', 2, 0, ALPHA, A, 1, BETA, C, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ GO TO 70
+ 60 INFOT = 1
+ CALL DSYR2K( '/', 'N', 0, 0, ALPHA, A, 1, B, 1, BETA, C, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 2
+ CALL DSYR2K( 'U', '/', 0, 0, ALPHA, A, 1, B, 1, BETA, C, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 3
+ CALL DSYR2K( 'U', 'N', -1, 0, ALPHA, A, 1, B, 1, BETA, C, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 3
+ CALL DSYR2K( 'U', 'T', -1, 0, ALPHA, A, 1, B, 1, BETA, C, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 3
+ CALL DSYR2K( 'L', 'N', -1, 0, ALPHA, A, 1, B, 1, BETA, C, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 3
+ CALL DSYR2K( 'L', 'T', -1, 0, ALPHA, A, 1, B, 1, BETA, C, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 4
+ CALL DSYR2K( 'U', 'N', 0, -1, ALPHA, A, 1, B, 1, BETA, C, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 4
+ CALL DSYR2K( 'U', 'T', 0, -1, ALPHA, A, 1, B, 1, BETA, C, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 4
+ CALL DSYR2K( 'L', 'N', 0, -1, ALPHA, A, 1, B, 1, BETA, C, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 4
+ CALL DSYR2K( 'L', 'T', 0, -1, ALPHA, A, 1, B, 1, BETA, C, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 7
+ CALL DSYR2K( 'U', 'N', 2, 0, ALPHA, A, 1, B, 1, BETA, C, 2 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 7
+ CALL DSYR2K( 'U', 'T', 0, 2, ALPHA, A, 1, B, 1, BETA, C, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 7
+ CALL DSYR2K( 'L', 'N', 2, 0, ALPHA, A, 1, B, 1, BETA, C, 2 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 7
+ CALL DSYR2K( 'L', 'T', 0, 2, ALPHA, A, 1, B, 1, BETA, C, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 9
+ CALL DSYR2K( 'U', 'N', 2, 0, ALPHA, A, 2, B, 1, BETA, C, 2 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 9
+ CALL DSYR2K( 'U', 'T', 0, 2, ALPHA, A, 2, B, 1, BETA, C, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 9
+ CALL DSYR2K( 'L', 'N', 2, 0, ALPHA, A, 2, B, 1, BETA, C, 2 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 9
+ CALL DSYR2K( 'L', 'T', 0, 2, ALPHA, A, 2, B, 1, BETA, C, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 12
+ CALL DSYR2K( 'U', 'N', 2, 0, ALPHA, A, 2, B, 2, BETA, C, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 12
+ CALL DSYR2K( 'U', 'T', 2, 0, ALPHA, A, 1, B, 1, BETA, C, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 12
+ CALL DSYR2K( 'L', 'N', 2, 0, ALPHA, A, 2, B, 2, BETA, C, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 12
+ CALL DSYR2K( 'L', 'T', 2, 0, ALPHA, A, 1, B, 1, BETA, C, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+*
+ 70 IF( OK )THEN
+ WRITE( NOUT, FMT = 9999 )SRNAMT
+ ELSE
+ WRITE( NOUT, FMT = 9998 )SRNAMT
+ END IF
+ RETURN
+*
+ 9999 FORMAT( ' ', A6, ' PASSED THE TESTS OF ERROR-EXITS' )
+ 9998 FORMAT( ' ******* ', A6, ' FAILED THE TESTS OF ERROR-EXITS *****',
+ $ '**' )
+*
+* End of DCHKE.
+*
+ END
+ SUBROUTINE DMAKE( TYPE, UPLO, DIAG, M, N, A, NMAX, AA, LDA, RESET,
+ $ TRANSL )
+*
+* Generates values for an M by N matrix A.
+* Stores the values in the array AA in the data structure required
+* by the routine, with unwanted elements set to rogue value.
+*
+* TYPE is 'GE', 'SY' or 'TR'.
+*
+* Auxiliary routine for test program for Level 3 Blas.
+*
+* -- Written on 8-February-1989.
+* Jack Dongarra, Argonne National Laboratory.
+* Iain Duff, AERE Harwell.
+* Jeremy Du Croz, Numerical Algorithms Group Ltd.
+* Sven Hammarling, Numerical Algorithms Group Ltd.
+*
+* .. Parameters ..
+ DOUBLE PRECISION ZERO, ONE
+ PARAMETER ( ZERO = 0.0D0, ONE = 1.0D0 )
+ DOUBLE PRECISION ROGUE
+ PARAMETER ( ROGUE = -1.0D10 )
+* .. Scalar Arguments ..
+ DOUBLE PRECISION TRANSL
+ INTEGER LDA, M, N, NMAX
+ LOGICAL RESET
+ CHARACTER*1 DIAG, UPLO
+ CHARACTER*2 TYPE
+* .. Array Arguments ..
+ DOUBLE PRECISION A( NMAX, * ), AA( * )
+* .. Local Scalars ..
+ INTEGER I, IBEG, IEND, J
+ LOGICAL GEN, LOWER, SYM, TRI, UNIT, UPPER
+* .. External Functions ..
+ DOUBLE PRECISION DBEG
+ EXTERNAL DBEG
+* .. Executable Statements ..
+ GEN = TYPE.EQ.'GE'
+ SYM = TYPE.EQ.'SY'
+ TRI = TYPE.EQ.'TR'
+ UPPER = ( SYM.OR.TRI ).AND.UPLO.EQ.'U'
+ LOWER = ( SYM.OR.TRI ).AND.UPLO.EQ.'L'
+ UNIT = TRI.AND.DIAG.EQ.'U'
+*
+* Generate data in array A.
+*
+ DO 20 J = 1, N
+ DO 10 I = 1, M
+ IF( GEN.OR.( UPPER.AND.I.LE.J ).OR.( LOWER.AND.I.GE.J ) )
+ $ THEN
+ A( I, J ) = DBEG( RESET ) + TRANSL
+ IF( I.NE.J )THEN
+* Set some elements to zero
+ IF( N.GT.3.AND.J.EQ.N/2 )
+ $ A( I, J ) = ZERO
+ IF( SYM )THEN
+ A( J, I ) = A( I, J )
+ ELSE IF( TRI )THEN
+ A( J, I ) = ZERO
+ END IF
+ END IF
+ END IF
+ 10 CONTINUE
+ IF( TRI )
+ $ A( J, J ) = A( J, J ) + ONE
+ IF( UNIT )
+ $ A( J, J ) = ONE
+ 20 CONTINUE
+*
+* Store elements in array AS in data structure required by routine.
+*
+ IF( TYPE.EQ.'GE' )THEN
+ DO 50 J = 1, N
+ DO 30 I = 1, M
+ AA( I + ( J - 1 )*LDA ) = A( I, J )
+ 30 CONTINUE
+ DO 40 I = M + 1, LDA
+ AA( I + ( J - 1 )*LDA ) = ROGUE
+ 40 CONTINUE
+ 50 CONTINUE
+ ELSE IF( TYPE.EQ.'SY'.OR.TYPE.EQ.'TR' )THEN
+ DO 90 J = 1, N
+ IF( UPPER )THEN
+ IBEG = 1
+ IF( UNIT )THEN
+ IEND = J - 1
+ ELSE
+ IEND = J
+ END IF
+ ELSE
+ IF( UNIT )THEN
+ IBEG = J + 1
+ ELSE
+ IBEG = J
+ END IF
+ IEND = N
+ END IF
+ DO 60 I = 1, IBEG - 1
+ AA( I + ( J - 1 )*LDA ) = ROGUE
+ 60 CONTINUE
+ DO 70 I = IBEG, IEND
+ AA( I + ( J - 1 )*LDA ) = A( I, J )
+ 70 CONTINUE
+ DO 80 I = IEND + 1, LDA
+ AA( I + ( J - 1 )*LDA ) = ROGUE
+ 80 CONTINUE
+ 90 CONTINUE
+ END IF
+ RETURN
+*
+* End of DMAKE.
+*
+ END
+ SUBROUTINE DMMCH( TRANSA, TRANSB, M, N, KK, ALPHA, A, LDA, B, LDB,
+ $ BETA, C, LDC, CT, G, CC, LDCC, EPS, ERR, FATAL,
+ $ NOUT, MV )
+*
+* Checks the results of the computational tests.
+*
+* Auxiliary routine for test program for Level 3 Blas.
+*
+* -- Written on 8-February-1989.
+* Jack Dongarra, Argonne National Laboratory.
+* Iain Duff, AERE Harwell.
+* Jeremy Du Croz, Numerical Algorithms Group Ltd.
+* Sven Hammarling, Numerical Algorithms Group Ltd.
+*
+* .. Parameters ..
+ DOUBLE PRECISION ZERO, ONE
+ PARAMETER ( ZERO = 0.0D0, ONE = 1.0D0 )
+* .. Scalar Arguments ..
+ DOUBLE PRECISION ALPHA, BETA, EPS, ERR
+ INTEGER KK, LDA, LDB, LDC, LDCC, M, N, NOUT
+ LOGICAL FATAL, MV
+ CHARACTER*1 TRANSA, TRANSB
+* .. Array Arguments ..
+ DOUBLE PRECISION A( LDA, * ), B( LDB, * ), C( LDC, * ),
+ $ CC( LDCC, * ), CT( * ), G( * )
+* .. Local Scalars ..
+ DOUBLE PRECISION ERRI
+ INTEGER I, J, K
+ LOGICAL TRANA, TRANB
+* .. Intrinsic Functions ..
+ INTRINSIC ABS, MAX, SQRT
+* .. Executable Statements ..
+ TRANA = TRANSA.EQ.'T'.OR.TRANSA.EQ.'C'
+ TRANB = TRANSB.EQ.'T'.OR.TRANSB.EQ.'C'
+*
+* Compute expected result, one column at a time, in CT using data
+* in A, B and C.
+* Compute gauges in G.
+*
+ DO 120 J = 1, N
+*
+ DO 10 I = 1, M
+ CT( I ) = ZERO
+ G( I ) = ZERO
+ 10 CONTINUE
+ IF( .NOT.TRANA.AND..NOT.TRANB )THEN
+ DO 30 K = 1, KK
+ DO 20 I = 1, M
+ CT( I ) = CT( I ) + A( I, K )*B( K, J )
+ G( I ) = G( I ) + ABS( A( I, K ) )*ABS( B( K, J ) )
+ 20 CONTINUE
+ 30 CONTINUE
+ ELSE IF( TRANA.AND..NOT.TRANB )THEN
+ DO 50 K = 1, KK
+ DO 40 I = 1, M
+ CT( I ) = CT( I ) + A( K, I )*B( K, J )
+ G( I ) = G( I ) + ABS( A( K, I ) )*ABS( B( K, J ) )
+ 40 CONTINUE
+ 50 CONTINUE
+ ELSE IF( .NOT.TRANA.AND.TRANB )THEN
+ DO 70 K = 1, KK
+ DO 60 I = 1, M
+ CT( I ) = CT( I ) + A( I, K )*B( J, K )
+ G( I ) = G( I ) + ABS( A( I, K ) )*ABS( B( J, K ) )
+ 60 CONTINUE
+ 70 CONTINUE
+ ELSE IF( TRANA.AND.TRANB )THEN
+ DO 90 K = 1, KK
+ DO 80 I = 1, M
+ CT( I ) = CT( I ) + A( K, I )*B( J, K )
+ G( I ) = G( I ) + ABS( A( K, I ) )*ABS( B( J, K ) )
+ 80 CONTINUE
+ 90 CONTINUE
+ END IF
+ DO 100 I = 1, M
+ CT( I ) = ALPHA*CT( I ) + BETA*C( I, J )
+ G( I ) = ABS( ALPHA )*G( I ) + ABS( BETA )*ABS( C( I, J ) )
+ 100 CONTINUE
+*
+* Compute the error ratio for this result.
+*
+ ERR = ZERO
+ DO 110 I = 1, M
+ ERRI = ABS( CT( I ) - CC( I, J ) )/EPS
+ IF( G( I ).NE.ZERO )
+ $ ERRI = ERRI/G( I )
+ ERR = MAX( ERR, ERRI )
+ IF( ERR*SQRT( EPS ).GE.ONE )
+ $ GO TO 130
+ 110 CONTINUE
+*
+ 120 CONTINUE
+*
+* If the loop completes, all results are at least half accurate.
+ GO TO 150
+*
+* Report fatal error.
+*
+ 130 FATAL = .TRUE.
+ WRITE( NOUT, FMT = 9999 )
+ DO 140 I = 1, M
+ IF( MV )THEN
+ WRITE( NOUT, FMT = 9998 )I, CT( I ), CC( I, J )
+ ELSE
+ WRITE( NOUT, FMT = 9998 )I, CC( I, J ), CT( I )
+ END IF
+ 140 CONTINUE
+ IF( N.GT.1 )
+ $ WRITE( NOUT, FMT = 9997 )J
+*
+ 150 CONTINUE
+ RETURN
+*
+ 9999 FORMAT( ' ******* FATAL ERROR - COMPUTED RESULT IS LESS THAN HAL',
+ $ 'F ACCURATE *******', /' EXPECTED RESULT COMPU',
+ $ 'TED RESULT' )
+ 9998 FORMAT( 1X, I7, 2G18.6 )
+ 9997 FORMAT( ' THESE ARE THE RESULTS FOR COLUMN ', I3 )
+*
+* End of DMMCH.
+*
+ END
+ LOGICAL FUNCTION LDE( RI, RJ, LR )
+*
+* Tests if two arrays are identical.
+*
+* Auxiliary routine for test program for Level 3 Blas.
+*
+* -- Written on 8-February-1989.
+* Jack Dongarra, Argonne National Laboratory.
+* Iain Duff, AERE Harwell.
+* Jeremy Du Croz, Numerical Algorithms Group Ltd.
+* Sven Hammarling, Numerical Algorithms Group Ltd.
+*
+* .. Scalar Arguments ..
+ INTEGER LR
+* .. Array Arguments ..
+ DOUBLE PRECISION RI( * ), RJ( * )
+* .. Local Scalars ..
+ INTEGER I
+* .. Executable Statements ..
+ DO 10 I = 1, LR
+ IF( RI( I ).NE.RJ( I ) )
+ $ GO TO 20
+ 10 CONTINUE
+ LDE = .TRUE.
+ GO TO 30
+ 20 CONTINUE
+ LDE = .FALSE.
+ 30 RETURN
+*
+* End of LDE.
+*
+ END
+ LOGICAL FUNCTION LDERES( TYPE, UPLO, M, N, AA, AS, LDA )
+*
+* Tests if selected elements in two arrays are equal.
+*
+* TYPE is 'GE' or 'SY'.
+*
+* Auxiliary routine for test program for Level 3 Blas.
+*
+* -- Written on 8-February-1989.
+* Jack Dongarra, Argonne National Laboratory.
+* Iain Duff, AERE Harwell.
+* Jeremy Du Croz, Numerical Algorithms Group Ltd.
+* Sven Hammarling, Numerical Algorithms Group Ltd.
+*
+* .. Scalar Arguments ..
+ INTEGER LDA, M, N
+ CHARACTER*1 UPLO
+ CHARACTER*2 TYPE
+* .. Array Arguments ..
+ DOUBLE PRECISION AA( LDA, * ), AS( LDA, * )
+* .. Local Scalars ..
+ INTEGER I, IBEG, IEND, J
+ LOGICAL UPPER
+* .. Executable Statements ..
+ UPPER = UPLO.EQ.'U'
+ IF( TYPE.EQ.'GE' )THEN
+ DO 20 J = 1, N
+ DO 10 I = M + 1, LDA
+ IF( AA( I, J ).NE.AS( I, J ) )
+ $ GO TO 70
+ 10 CONTINUE
+ 20 CONTINUE
+ ELSE IF( TYPE.EQ.'SY' )THEN
+ DO 50 J = 1, N
+ IF( UPPER )THEN
+ IBEG = 1
+ IEND = J
+ ELSE
+ IBEG = J
+ IEND = N
+ END IF
+ DO 30 I = 1, IBEG - 1
+ IF( AA( I, J ).NE.AS( I, J ) )
+ $ GO TO 70
+ 30 CONTINUE
+ DO 40 I = IEND + 1, LDA
+ IF( AA( I, J ).NE.AS( I, J ) )
+ $ GO TO 70
+ 40 CONTINUE
+ 50 CONTINUE
+ END IF
+*
+ 60 CONTINUE
+ LDERES = .TRUE.
+ GO TO 80
+ 70 CONTINUE
+ LDERES = .FALSE.
+ 80 RETURN
+*
+* End of LDERES.
+*
+ END
+ DOUBLE PRECISION FUNCTION DBEG( RESET )
+*
+* Generates random numbers uniformly distributed between -0.5 and 0.5.
+*
+* Auxiliary routine for test program for Level 3 Blas.
+*
+* -- Written on 8-February-1989.
+* Jack Dongarra, Argonne National Laboratory.
+* Iain Duff, AERE Harwell.
+* Jeremy Du Croz, Numerical Algorithms Group Ltd.
+* Sven Hammarling, Numerical Algorithms Group Ltd.
+*
+* .. Scalar Arguments ..
+ LOGICAL RESET
+* .. Local Scalars ..
+ INTEGER I, IC, MI
+* .. Save statement ..
+ SAVE I, IC, MI
+* .. Executable Statements ..
+ IF( RESET )THEN
+* Initialize local variables.
+ MI = 891
+ I = 7
+ IC = 0
+ RESET = .FALSE.
+ END IF
+*
+* The sequence of values of I is bounded between 1 and 999.
+* If initial I = 1,2,3,6,7 or 9, the period will be 50.
+* If initial I = 4 or 8, the period will be 25.
+* If initial I = 5, the period will be 10.
+* IC is used to break up the period by skipping 1 value of I in 6.
+*
+ IC = IC + 1
+ 10 I = I*MI
+ I = I - 1000*( I/1000 )
+ IF( IC.GE.5 )THEN
+ IC = 0
+ GO TO 10
+ END IF
+ DBEG = ( I - 500 )/1001.0D0
+ RETURN
+*
+* End of DBEG.
+*
+ END
+ DOUBLE PRECISION FUNCTION DDIFF( X, Y )
+*
+* Auxiliary routine for test program for Level 3 Blas.
+*
+* -- Written on 8-February-1989.
+* Jack Dongarra, Argonne National Laboratory.
+* Iain Duff, AERE Harwell.
+* Jeremy Du Croz, Numerical Algorithms Group Ltd.
+* Sven Hammarling, Numerical Algorithms Group Ltd.
+*
+* .. Scalar Arguments ..
+ DOUBLE PRECISION X, Y
+* .. Executable Statements ..
+ DDIFF = X - Y
+ RETURN
+*
+* End of DDIFF.
+*
+ END
+ SUBROUTINE CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+*
+* Tests whether XERBLA has detected an error when it should.
+*
+* Auxiliary routine for test program for Level 3 Blas.
+*
+* -- Written on 8-February-1989.
+* Jack Dongarra, Argonne National Laboratory.
+* Iain Duff, AERE Harwell.
+* Jeremy Du Croz, Numerical Algorithms Group Ltd.
+* Sven Hammarling, Numerical Algorithms Group Ltd.
+*
+* .. Scalar Arguments ..
+ INTEGER INFOT, NOUT
+ LOGICAL LERR, OK
+ CHARACTER*6 SRNAMT
+* .. Executable Statements ..
+ IF( .NOT.LERR )THEN
+ WRITE( NOUT, FMT = 9999 )INFOT, SRNAMT
+ OK = .FALSE.
+ END IF
+ LERR = .FALSE.
+ RETURN
+*
+ 9999 FORMAT( ' ***** ILLEGAL VALUE OF PARAMETER NUMBER ', I2, ' NOT D',
+ $ 'ETECTED BY ', A6, ' *****' )
+*
+* End of CHKXER.
+*
+ END
+ SUBROUTINE XERBLA( SRNAME, INFO )
+*
+* This is a special version of XERBLA to be used only as part of
+* the test program for testing error exits from the Level 3 BLAS
+* routines.
+*
+* XERBLA is an error handler for the Level 3 BLAS routines.
+*
+* It is called by the Level 3 BLAS routines if an input parameter is
+* invalid.
+*
+* Auxiliary routine for test program for Level 3 Blas.
+*
+* -- Written on 8-February-1989.
+* Jack Dongarra, Argonne National Laboratory.
+* Iain Duff, AERE Harwell.
+* Jeremy Du Croz, Numerical Algorithms Group Ltd.
+* Sven Hammarling, Numerical Algorithms Group Ltd.
+*
+* .. Scalar Arguments ..
+ INTEGER INFO
+ CHARACTER*6 SRNAME
+* .. Scalars in Common ..
+ INTEGER INFOT, NOUT
+ LOGICAL LERR, OK
+ CHARACTER*6 SRNAMT
+* .. Common blocks ..
+ COMMON /INFOC/INFOT, NOUT, OK, LERR
+ COMMON /SRNAMC/SRNAMT
+* .. Executable Statements ..
+ LERR = .TRUE.
+ IF( INFO.NE.INFOT )THEN
+ IF( INFOT.NE.0 )THEN
+ WRITE( NOUT, FMT = 9999 )INFO, INFOT
+ ELSE
+ WRITE( NOUT, FMT = 9997 )INFO
+ END IF
+ OK = .FALSE.
+ END IF
+ IF( SRNAME.NE.SRNAMT )THEN
+ WRITE( NOUT, FMT = 9998 )SRNAME, SRNAMT
+ OK = .FALSE.
+ END IF
+ RETURN
+*
+ 9999 FORMAT( ' ******* XERBLA WAS CALLED WITH INFO = ', I6, ' INSTEAD',
+ $ ' OF ', I2, ' *******' )
+ 9998 FORMAT( ' ******* XERBLA WAS CALLED WITH SRNAME = ', A6, ' INSTE',
+ $ 'AD OF ', A6, ' *******' )
+ 9997 FORMAT( ' ******* XERBLA WAS CALLED WITH INFO = ', I6,
+ $ ' *******' )
+*
+* End of XERBLA
+*
+ END
+
diff --git a/blas/testing/runblastest.sh b/blas/testing/runblastest.sh
new file mode 100755
index 000000000..4ffaf0111
--- /dev/null
+++ b/blas/testing/runblastest.sh
@@ -0,0 +1,45 @@
+#!/bin/bash
+
+black='\E[30m'
+red='\E[31m'
+green='\E[32m'
+yellow='\E[33m'
+blue='\E[34m'
+magenta='\E[35m'
+cyan='\E[36m'
+white='\E[37m'
+
+if [ -f $2 ]; then
+ data=$2
+ if [ -f $1.summ ]; then rm $1.summ; fi
+ if [ -f $1.snap ]; then rm $1.snap; fi
+else
+ data=$1
+fi
+
+if ! ./$1 < $data > /dev/null 2> .runtest.log ; then
+ echo -e $red Test $1 failed: $black
+ echo -e $blue
+ cat .runtest.log
+ echo -e $black
+ exit 1
+else
+ if [ -f $1.summ ]; then
+ if [ `grep "FATAL ERROR" $1.summ | wc -l` -gt 0 ]; then
+ echo -e $red "Test $1 failed (FATAL ERROR, read the file $1.summ for details)" $black
+ echo -e $blue
+ cat .runtest.log
+ echo -e $black
+ exit 1;
+ fi
+
+ if [ `grep "FAILED THE TESTS OF ERROR-EXITS" $1.summ | wc -l` -gt 0 ]; then
+ echo -e $red "Test $1 failed (FAILED THE TESTS OF ERROR-EXITS, read the file $1.summ for details)" $black
+ echo -e $blue
+ cat .runtest.log
+ echo -e $black
+ exit 1;
+ fi
+ fi
+ echo -e $green Test $1 passed$black
+fi
diff --git a/blas/testing/sblat1.f b/blas/testing/sblat1.f
new file mode 100644
index 000000000..a982d1852
--- /dev/null
+++ b/blas/testing/sblat1.f
@@ -0,0 +1,769 @@
+ PROGRAM SBLAT1
+* Test program for the REAL Level 1 BLAS.
+* Based upon the original BLAS test routine together with:
+* F06EAF Example Program Text
+* .. Parameters ..
+ INTEGER NOUT
+ PARAMETER (NOUT=6)
+* .. Scalars in Common ..
+ INTEGER ICASE, INCX, INCY, MODE, N
+ LOGICAL PASS
+* .. Local Scalars ..
+ REAL SFAC
+ INTEGER IC
+* .. External Subroutines ..
+ EXTERNAL CHECK0, CHECK1, CHECK2, CHECK3, HEADER
+* .. Common blocks ..
+ COMMON /COMBLA/ICASE, N, INCX, INCY, MODE, PASS
+* .. Data statements ..
+ DATA SFAC/9.765625E-4/
+* .. Executable Statements ..
+ WRITE (NOUT,99999)
+ DO 20 IC = 1, 10
+ ICASE = IC
+ CALL HEADER
+*
+* .. Initialize PASS, INCX, INCY, and MODE for a new case. ..
+* .. the value 9999 for INCX, INCY or MODE will appear in the ..
+* .. detailed output, if any, for cases that do not involve ..
+* .. these parameters ..
+*
+ PASS = .TRUE.
+ INCX = 9999
+ INCY = 9999
+ MODE = 9999
+ IF (ICASE.EQ.3) THEN
+ CALL CHECK0(SFAC)
+ ELSE IF (ICASE.EQ.7 .OR. ICASE.EQ.8 .OR. ICASE.EQ.9 .OR.
+ + ICASE.EQ.10) THEN
+ CALL CHECK1(SFAC)
+ ELSE IF (ICASE.EQ.1 .OR. ICASE.EQ.2 .OR. ICASE.EQ.5 .OR.
+ + ICASE.EQ.6) THEN
+ CALL CHECK2(SFAC)
+ ELSE IF (ICASE.EQ.4) THEN
+ CALL CHECK3(SFAC)
+ END IF
+* -- Print
+ IF (PASS) WRITE (NOUT,99998)
+ 20 CONTINUE
+ STOP
+*
+99999 FORMAT (' Real BLAS Test Program Results',/1X)
+99998 FORMAT (' ----- PASS -----')
+ END
+ SUBROUTINE HEADER
+* .. Parameters ..
+ INTEGER NOUT
+ PARAMETER (NOUT=6)
+* .. Scalars in Common ..
+ INTEGER ICASE, INCX, INCY, MODE, N
+ LOGICAL PASS
+* .. Local Arrays ..
+ CHARACTER*6 L(10)
+* .. Common blocks ..
+ COMMON /COMBLA/ICASE, N, INCX, INCY, MODE, PASS
+* .. Data statements ..
+ DATA L(1)/' SDOT '/
+ DATA L(2)/'SAXPY '/
+ DATA L(3)/'SROTG '/
+ DATA L(4)/' SROT '/
+ DATA L(5)/'SCOPY '/
+ DATA L(6)/'SSWAP '/
+ DATA L(7)/'SNRM2 '/
+ DATA L(8)/'SASUM '/
+ DATA L(9)/'SSCAL '/
+ DATA L(10)/'ISAMAX'/
+* .. Executable Statements ..
+ WRITE (NOUT,99999) ICASE, L(ICASE)
+ RETURN
+*
+99999 FORMAT (/' Test of subprogram number',I3,12X,A6)
+ END
+ SUBROUTINE CHECK0(SFAC)
+* .. Parameters ..
+ INTEGER NOUT
+ PARAMETER (NOUT=6)
+* .. Scalar Arguments ..
+ REAL SFAC
+* .. Scalars in Common ..
+ INTEGER ICASE, INCX, INCY, MODE, N
+ LOGICAL PASS
+* .. Local Scalars ..
+ REAL D12, SA, SB, SC, SS
+ INTEGER K
+* .. Local Arrays ..
+ REAL DA1(8), DATRUE(8), DB1(8), DBTRUE(8), DC1(8),
+ + DS1(8)
+* .. External Subroutines ..
+ EXTERNAL SROTG, STEST1
+* .. Common blocks ..
+ COMMON /COMBLA/ICASE, N, INCX, INCY, MODE, PASS
+* .. Data statements ..
+ DATA DA1/0.3E0, 0.4E0, -0.3E0, -0.4E0, -0.3E0, 0.0E0,
+ + 0.0E0, 1.0E0/
+ DATA DB1/0.4E0, 0.3E0, 0.4E0, 0.3E0, -0.4E0, 0.0E0,
+ + 1.0E0, 0.0E0/
+ DATA DC1/0.6E0, 0.8E0, -0.6E0, 0.8E0, 0.6E0, 1.0E0,
+ + 0.0E0, 1.0E0/
+ DATA DS1/0.8E0, 0.6E0, 0.8E0, -0.6E0, 0.8E0, 0.0E0,
+ + 1.0E0, 0.0E0/
+ DATA DATRUE/0.5E0, 0.5E0, 0.5E0, -0.5E0, -0.5E0,
+ + 0.0E0, 1.0E0, 1.0E0/
+ DATA DBTRUE/0.0E0, 0.6E0, 0.0E0, -0.6E0, 0.0E0,
+ + 0.0E0, 1.0E0, 0.0E0/
+ DATA D12/4096.0E0/
+* .. Executable Statements ..
+*
+* Compute true values which cannot be prestored
+* in decimal notation
+*
+ DBTRUE(1) = 1.0E0/0.6E0
+ DBTRUE(3) = -1.0E0/0.6E0
+ DBTRUE(5) = 1.0E0/0.6E0
+*
+ DO 20 K = 1, 8
+* .. Set N=K for identification in output if any ..
+ N = K
+ IF (ICASE.EQ.3) THEN
+* .. SROTG ..
+ IF (K.GT.8) GO TO 40
+ SA = DA1(K)
+ SB = DB1(K)
+ CALL SROTG(SA,SB,SC,SS)
+ CALL STEST1(SA,DATRUE(K),DATRUE(K),SFAC)
+ CALL STEST1(SB,DBTRUE(K),DBTRUE(K),SFAC)
+ CALL STEST1(SC,DC1(K),DC1(K),SFAC)
+ CALL STEST1(SS,DS1(K),DS1(K),SFAC)
+ ELSE
+ WRITE (NOUT,*) ' Shouldn''t be here in CHECK0'
+ STOP
+ END IF
+ 20 CONTINUE
+ 40 RETURN
+ END
+ SUBROUTINE CHECK1(SFAC)
+* .. Parameters ..
+ INTEGER NOUT
+ PARAMETER (NOUT=6)
+* .. Scalar Arguments ..
+ REAL SFAC
+* .. Scalars in Common ..
+ INTEGER ICASE, INCX, INCY, MODE, N
+ LOGICAL PASS
+* .. Local Scalars ..
+ INTEGER I, LEN, NP1
+* .. Local Arrays ..
+ REAL DTRUE1(5), DTRUE3(5), DTRUE5(8,5,2), DV(8,5,2),
+ + SA(10), STEMP(1), STRUE(8), SX(8)
+ INTEGER ITRUE2(5)
+* .. External Functions ..
+ REAL SASUM, SNRM2
+ INTEGER ISAMAX
+ EXTERNAL SASUM, SNRM2, ISAMAX
+* .. External Subroutines ..
+ EXTERNAL ITEST1, SSCAL, STEST, STEST1
+* .. Intrinsic Functions ..
+ INTRINSIC MAX
+* .. Common blocks ..
+ COMMON /COMBLA/ICASE, N, INCX, INCY, MODE, PASS
+* .. Data statements ..
+ DATA SA/0.3E0, -1.0E0, 0.0E0, 1.0E0, 0.3E0, 0.3E0,
+ + 0.3E0, 0.3E0, 0.3E0, 0.3E0/
+ DATA DV/0.1E0, 2.0E0, 2.0E0, 2.0E0, 2.0E0, 2.0E0,
+ + 2.0E0, 2.0E0, 0.3E0, 3.0E0, 3.0E0, 3.0E0, 3.0E0,
+ + 3.0E0, 3.0E0, 3.0E0, 0.3E0, -0.4E0, 4.0E0,
+ + 4.0E0, 4.0E0, 4.0E0, 4.0E0, 4.0E0, 0.2E0,
+ + -0.6E0, 0.3E0, 5.0E0, 5.0E0, 5.0E0, 5.0E0,
+ + 5.0E0, 0.1E0, -0.3E0, 0.5E0, -0.1E0, 6.0E0,
+ + 6.0E0, 6.0E0, 6.0E0, 0.1E0, 8.0E0, 8.0E0, 8.0E0,
+ + 8.0E0, 8.0E0, 8.0E0, 8.0E0, 0.3E0, 9.0E0, 9.0E0,
+ + 9.0E0, 9.0E0, 9.0E0, 9.0E0, 9.0E0, 0.3E0, 2.0E0,
+ + -0.4E0, 2.0E0, 2.0E0, 2.0E0, 2.0E0, 2.0E0,
+ + 0.2E0, 3.0E0, -0.6E0, 5.0E0, 0.3E0, 2.0E0,
+ + 2.0E0, 2.0E0, 0.1E0, 4.0E0, -0.3E0, 6.0E0,
+ + -0.5E0, 7.0E0, -0.1E0, 3.0E0/
+ DATA DTRUE1/0.0E0, 0.3E0, 0.5E0, 0.7E0, 0.6E0/
+ DATA DTRUE3/0.0E0, 0.3E0, 0.7E0, 1.1E0, 1.0E0/
+ DATA DTRUE5/0.10E0, 2.0E0, 2.0E0, 2.0E0, 2.0E0,
+ + 2.0E0, 2.0E0, 2.0E0, -0.3E0, 3.0E0, 3.0E0,
+ + 3.0E0, 3.0E0, 3.0E0, 3.0E0, 3.0E0, 0.0E0, 0.0E0,
+ + 4.0E0, 4.0E0, 4.0E0, 4.0E0, 4.0E0, 4.0E0,
+ + 0.20E0, -0.60E0, 0.30E0, 5.0E0, 5.0E0, 5.0E0,
+ + 5.0E0, 5.0E0, 0.03E0, -0.09E0, 0.15E0, -0.03E0,
+ + 6.0E0, 6.0E0, 6.0E0, 6.0E0, 0.10E0, 8.0E0,
+ + 8.0E0, 8.0E0, 8.0E0, 8.0E0, 8.0E0, 8.0E0,
+ + 0.09E0, 9.0E0, 9.0E0, 9.0E0, 9.0E0, 9.0E0,
+ + 9.0E0, 9.0E0, 0.09E0, 2.0E0, -0.12E0, 2.0E0,
+ + 2.0E0, 2.0E0, 2.0E0, 2.0E0, 0.06E0, 3.0E0,
+ + -0.18E0, 5.0E0, 0.09E0, 2.0E0, 2.0E0, 2.0E0,
+ + 0.03E0, 4.0E0, -0.09E0, 6.0E0, -0.15E0, 7.0E0,
+ + -0.03E0, 3.0E0/
+ DATA ITRUE2/0, 1, 2, 2, 3/
+* .. Executable Statements ..
+ DO 80 INCX = 1, 2
+ DO 60 NP1 = 1, 5
+ N = NP1 - 1
+ LEN = 2*MAX(N,1)
+* .. Set vector arguments ..
+ DO 20 I = 1, LEN
+ SX(I) = DV(I,NP1,INCX)
+ 20 CONTINUE
+*
+ IF (ICASE.EQ.7) THEN
+* .. SNRM2 ..
+ STEMP(1) = DTRUE1(NP1)
+ CALL STEST1(SNRM2(N,SX,INCX),STEMP,STEMP,SFAC)
+ ELSE IF (ICASE.EQ.8) THEN
+* .. SASUM ..
+ STEMP(1) = DTRUE3(NP1)
+ CALL STEST1(SASUM(N,SX,INCX),STEMP,STEMP,SFAC)
+ ELSE IF (ICASE.EQ.9) THEN
+* .. SSCAL ..
+ CALL SSCAL(N,SA((INCX-1)*5+NP1),SX,INCX)
+ DO 40 I = 1, LEN
+ STRUE(I) = DTRUE5(I,NP1,INCX)
+ 40 CONTINUE
+ CALL STEST(LEN,SX,STRUE,STRUE,SFAC)
+ ELSE IF (ICASE.EQ.10) THEN
+* .. ISAMAX ..
+ CALL ITEST1(ISAMAX(N,SX,INCX),ITRUE2(NP1))
+ ELSE
+ WRITE (NOUT,*) ' Shouldn''t be here in CHECK1'
+ STOP
+ END IF
+ 60 CONTINUE
+ 80 CONTINUE
+ RETURN
+ END
+ SUBROUTINE CHECK2(SFAC)
+* .. Parameters ..
+ INTEGER NOUT
+ PARAMETER (NOUT=6)
+* .. Scalar Arguments ..
+ REAL SFAC
+* .. Scalars in Common ..
+ INTEGER ICASE, INCX, INCY, MODE, N
+ LOGICAL PASS
+* .. Local Scalars ..
+ REAL SA, SC, SS
+ INTEGER I, J, KI, KN, KSIZE, LENX, LENY, MX, MY
+* .. Local Arrays ..
+ REAL DT10X(7,4,4), DT10Y(7,4,4), DT7(4,4),
+ + DT8(7,4,4), DT9X(7,4,4), DT9Y(7,4,4), DX1(7),
+ + DY1(7), SSIZE1(4), SSIZE2(14,2), STX(7), STY(7),
+ + SX(7), SY(7)
+ INTEGER INCXS(4), INCYS(4), LENS(4,2), NS(4)
+* .. External Functions ..
+ REAL SDOT
+ EXTERNAL SDOT
+* .. External Subroutines ..
+ EXTERNAL SAXPY, SCOPY, SSWAP, STEST, STEST1
+* .. Intrinsic Functions ..
+ INTRINSIC ABS, MIN
+* .. Common blocks ..
+ COMMON /COMBLA/ICASE, N, INCX, INCY, MODE, PASS
+* .. Data statements ..
+ DATA SA/0.3E0/
+ DATA INCXS/1, 2, -2, -1/
+ DATA INCYS/1, -2, 1, -2/
+ DATA LENS/1, 1, 2, 4, 1, 1, 3, 7/
+ DATA NS/0, 1, 2, 4/
+ DATA DX1/0.6E0, 0.1E0, -0.5E0, 0.8E0, 0.9E0, -0.3E0,
+ + -0.4E0/
+ DATA DY1/0.5E0, -0.9E0, 0.3E0, 0.7E0, -0.6E0, 0.2E0,
+ + 0.8E0/
+ DATA SC, SS/0.8E0, 0.6E0/
+ DATA DT7/0.0E0, 0.30E0, 0.21E0, 0.62E0, 0.0E0,
+ + 0.30E0, -0.07E0, 0.85E0, 0.0E0, 0.30E0, -0.79E0,
+ + -0.74E0, 0.0E0, 0.30E0, 0.33E0, 1.27E0/
+ DATA DT8/0.5E0, 0.0E0, 0.0E0, 0.0E0, 0.0E0, 0.0E0,
+ + 0.0E0, 0.68E0, 0.0E0, 0.0E0, 0.0E0, 0.0E0,
+ + 0.0E0, 0.0E0, 0.68E0, -0.87E0, 0.0E0, 0.0E0,
+ + 0.0E0, 0.0E0, 0.0E0, 0.68E0, -0.87E0, 0.15E0,
+ + 0.94E0, 0.0E0, 0.0E0, 0.0E0, 0.5E0, 0.0E0,
+ + 0.0E0, 0.0E0, 0.0E0, 0.0E0, 0.0E0, 0.68E0,
+ + 0.0E0, 0.0E0, 0.0E0, 0.0E0, 0.0E0, 0.0E0,
+ + 0.35E0, -0.9E0, 0.48E0, 0.0E0, 0.0E0, 0.0E0,
+ + 0.0E0, 0.38E0, -0.9E0, 0.57E0, 0.7E0, -0.75E0,
+ + 0.2E0, 0.98E0, 0.5E0, 0.0E0, 0.0E0, 0.0E0,
+ + 0.0E0, 0.0E0, 0.0E0, 0.68E0, 0.0E0, 0.0E0,
+ + 0.0E0, 0.0E0, 0.0E0, 0.0E0, 0.35E0, -0.72E0,
+ + 0.0E0, 0.0E0, 0.0E0, 0.0E0, 0.0E0, 0.38E0,
+ + -0.63E0, 0.15E0, 0.88E0, 0.0E0, 0.0E0, 0.0E0,
+ + 0.5E0, 0.0E0, 0.0E0, 0.0E0, 0.0E0, 0.0E0, 0.0E0,
+ + 0.68E0, 0.0E0, 0.0E0, 0.0E0, 0.0E0, 0.0E0,
+ + 0.0E0, 0.68E0, -0.9E0, 0.33E0, 0.0E0, 0.0E0,
+ + 0.0E0, 0.0E0, 0.68E0, -0.9E0, 0.33E0, 0.7E0,
+ + -0.75E0, 0.2E0, 1.04E0/
+ DATA DT9X/0.6E0, 0.0E0, 0.0E0, 0.0E0, 0.0E0, 0.0E0,
+ + 0.0E0, 0.78E0, 0.0E0, 0.0E0, 0.0E0, 0.0E0,
+ + 0.0E0, 0.0E0, 0.78E0, -0.46E0, 0.0E0, 0.0E0,
+ + 0.0E0, 0.0E0, 0.0E0, 0.78E0, -0.46E0, -0.22E0,
+ + 1.06E0, 0.0E0, 0.0E0, 0.0E0, 0.6E0, 0.0E0,
+ + 0.0E0, 0.0E0, 0.0E0, 0.0E0, 0.0E0, 0.78E0,
+ + 0.0E0, 0.0E0, 0.0E0, 0.0E0, 0.0E0, 0.0E0,
+ + 0.66E0, 0.1E0, -0.1E0, 0.0E0, 0.0E0, 0.0E0,
+ + 0.0E0, 0.96E0, 0.1E0, -0.76E0, 0.8E0, 0.90E0,
+ + -0.3E0, -0.02E0, 0.6E0, 0.0E0, 0.0E0, 0.0E0,
+ + 0.0E0, 0.0E0, 0.0E0, 0.78E0, 0.0E0, 0.0E0,
+ + 0.0E0, 0.0E0, 0.0E0, 0.0E0, -0.06E0, 0.1E0,
+ + -0.1E0, 0.0E0, 0.0E0, 0.0E0, 0.0E0, 0.90E0,
+ + 0.1E0, -0.22E0, 0.8E0, 0.18E0, -0.3E0, -0.02E0,
+ + 0.6E0, 0.0E0, 0.0E0, 0.0E0, 0.0E0, 0.0E0, 0.0E0,
+ + 0.78E0, 0.0E0, 0.0E0, 0.0E0, 0.0E0, 0.0E0,
+ + 0.0E0, 0.78E0, 0.26E0, 0.0E0, 0.0E0, 0.0E0,
+ + 0.0E0, 0.0E0, 0.78E0, 0.26E0, -0.76E0, 1.12E0,
+ + 0.0E0, 0.0E0, 0.0E0/
+ DATA DT9Y/0.5E0, 0.0E0, 0.0E0, 0.0E0, 0.0E0, 0.0E0,
+ + 0.0E0, 0.04E0, 0.0E0, 0.0E0, 0.0E0, 0.0E0,
+ + 0.0E0, 0.0E0, 0.04E0, -0.78E0, 0.0E0, 0.0E0,
+ + 0.0E0, 0.0E0, 0.0E0, 0.04E0, -0.78E0, 0.54E0,
+ + 0.08E0, 0.0E0, 0.0E0, 0.0E0, 0.5E0, 0.0E0,
+ + 0.0E0, 0.0E0, 0.0E0, 0.0E0, 0.0E0, 0.04E0,
+ + 0.0E0, 0.0E0, 0.0E0, 0.0E0, 0.0E0, 0.0E0, 0.7E0,
+ + -0.9E0, -0.12E0, 0.0E0, 0.0E0, 0.0E0, 0.0E0,
+ + 0.64E0, -0.9E0, -0.30E0, 0.7E0, -0.18E0, 0.2E0,
+ + 0.28E0, 0.5E0, 0.0E0, 0.0E0, 0.0E0, 0.0E0,
+ + 0.0E0, 0.0E0, 0.04E0, 0.0E0, 0.0E0, 0.0E0,
+ + 0.0E0, 0.0E0, 0.0E0, 0.7E0, -1.08E0, 0.0E0,
+ + 0.0E0, 0.0E0, 0.0E0, 0.0E0, 0.64E0, -1.26E0,
+ + 0.54E0, 0.20E0, 0.0E0, 0.0E0, 0.0E0, 0.5E0,
+ + 0.0E0, 0.0E0, 0.0E0, 0.0E0, 0.0E0, 0.0E0,
+ + 0.04E0, 0.0E0, 0.0E0, 0.0E0, 0.0E0, 0.0E0,
+ + 0.0E0, 0.04E0, -0.9E0, 0.18E0, 0.0E0, 0.0E0,
+ + 0.0E0, 0.0E0, 0.04E0, -0.9E0, 0.18E0, 0.7E0,
+ + -0.18E0, 0.2E0, 0.16E0/
+ DATA DT10X/0.6E0, 0.0E0, 0.0E0, 0.0E0, 0.0E0, 0.0E0,
+ + 0.0E0, 0.5E0, 0.0E0, 0.0E0, 0.0E0, 0.0E0, 0.0E0,
+ + 0.0E0, 0.5E0, -0.9E0, 0.0E0, 0.0E0, 0.0E0,
+ + 0.0E0, 0.0E0, 0.5E0, -0.9E0, 0.3E0, 0.7E0,
+ + 0.0E0, 0.0E0, 0.0E0, 0.6E0, 0.0E0, 0.0E0, 0.0E0,
+ + 0.0E0, 0.0E0, 0.0E0, 0.5E0, 0.0E0, 0.0E0, 0.0E0,
+ + 0.0E0, 0.0E0, 0.0E0, 0.3E0, 0.1E0, 0.5E0, 0.0E0,
+ + 0.0E0, 0.0E0, 0.0E0, 0.8E0, 0.1E0, -0.6E0,
+ + 0.8E0, 0.3E0, -0.3E0, 0.5E0, 0.6E0, 0.0E0,
+ + 0.0E0, 0.0E0, 0.0E0, 0.0E0, 0.0E0, 0.5E0, 0.0E0,
+ + 0.0E0, 0.0E0, 0.0E0, 0.0E0, 0.0E0, -0.9E0,
+ + 0.1E0, 0.5E0, 0.0E0, 0.0E0, 0.0E0, 0.0E0, 0.7E0,
+ + 0.1E0, 0.3E0, 0.8E0, -0.9E0, -0.3E0, 0.5E0,
+ + 0.6E0, 0.0E0, 0.0E0, 0.0E0, 0.0E0, 0.0E0, 0.0E0,
+ + 0.5E0, 0.0E0, 0.0E0, 0.0E0, 0.0E0, 0.0E0, 0.0E0,
+ + 0.5E0, 0.3E0, 0.0E0, 0.0E0, 0.0E0, 0.0E0, 0.0E0,
+ + 0.5E0, 0.3E0, -0.6E0, 0.8E0, 0.0E0, 0.0E0,
+ + 0.0E0/
+ DATA DT10Y/0.5E0, 0.0E0, 0.0E0, 0.0E0, 0.0E0, 0.0E0,
+ + 0.0E0, 0.6E0, 0.0E0, 0.0E0, 0.0E0, 0.0E0, 0.0E0,
+ + 0.0E0, 0.6E0, 0.1E0, 0.0E0, 0.0E0, 0.0E0, 0.0E0,
+ + 0.0E0, 0.6E0, 0.1E0, -0.5E0, 0.8E0, 0.0E0,
+ + 0.0E0, 0.0E0, 0.5E0, 0.0E0, 0.0E0, 0.0E0, 0.0E0,
+ + 0.0E0, 0.0E0, 0.6E0, 0.0E0, 0.0E0, 0.0E0, 0.0E0,
+ + 0.0E0, 0.0E0, -0.5E0, -0.9E0, 0.6E0, 0.0E0,
+ + 0.0E0, 0.0E0, 0.0E0, -0.4E0, -0.9E0, 0.9E0,
+ + 0.7E0, -0.5E0, 0.2E0, 0.6E0, 0.5E0, 0.0E0,
+ + 0.0E0, 0.0E0, 0.0E0, 0.0E0, 0.0E0, 0.6E0, 0.0E0,
+ + 0.0E0, 0.0E0, 0.0E0, 0.0E0, 0.0E0, -0.5E0,
+ + 0.6E0, 0.0E0, 0.0E0, 0.0E0, 0.0E0, 0.0E0,
+ + -0.4E0, 0.9E0, -0.5E0, 0.6E0, 0.0E0, 0.0E0,
+ + 0.0E0, 0.5E0, 0.0E0, 0.0E0, 0.0E0, 0.0E0, 0.0E0,
+ + 0.0E0, 0.6E0, 0.0E0, 0.0E0, 0.0E0, 0.0E0, 0.0E0,
+ + 0.0E0, 0.6E0, -0.9E0, 0.1E0, 0.0E0, 0.0E0,
+ + 0.0E0, 0.0E0, 0.6E0, -0.9E0, 0.1E0, 0.7E0,
+ + -0.5E0, 0.2E0, 0.8E0/
+ DATA SSIZE1/0.0E0, 0.3E0, 1.6E0, 3.2E0/
+ DATA SSIZE2/0.0E0, 0.0E0, 0.0E0, 0.0E0, 0.0E0, 0.0E0,
+ + 0.0E0, 0.0E0, 0.0E0, 0.0E0, 0.0E0, 0.0E0, 0.0E0,
+ + 0.0E0, 1.17E0, 1.17E0, 1.17E0, 1.17E0, 1.17E0,
+ + 1.17E0, 1.17E0, 1.17E0, 1.17E0, 1.17E0, 1.17E0,
+ + 1.17E0, 1.17E0, 1.17E0/
+* .. Executable Statements ..
+*
+ DO 120 KI = 1, 4
+ INCX = INCXS(KI)
+ INCY = INCYS(KI)
+ MX = ABS(INCX)
+ MY = ABS(INCY)
+*
+ DO 100 KN = 1, 4
+ N = NS(KN)
+ KSIZE = MIN(2,KN)
+ LENX = LENS(KN,MX)
+ LENY = LENS(KN,MY)
+* .. Initialize all argument arrays ..
+ DO 20 I = 1, 7
+ SX(I) = DX1(I)
+ SY(I) = DY1(I)
+ 20 CONTINUE
+*
+ IF (ICASE.EQ.1) THEN
+* .. SDOT ..
+ CALL STEST1(SDOT(N,SX,INCX,SY,INCY),DT7(KN,KI),SSIZE1(KN)
+ + ,SFAC)
+ ELSE IF (ICASE.EQ.2) THEN
+* .. SAXPY ..
+ CALL SAXPY(N,SA,SX,INCX,SY,INCY)
+ DO 40 J = 1, LENY
+ STY(J) = DT8(J,KN,KI)
+ 40 CONTINUE
+ CALL STEST(LENY,SY,STY,SSIZE2(1,KSIZE),SFAC)
+ ELSE IF (ICASE.EQ.5) THEN
+* .. SCOPY ..
+ DO 60 I = 1, 7
+ STY(I) = DT10Y(I,KN,KI)
+ 60 CONTINUE
+ CALL SCOPY(N,SX,INCX,SY,INCY)
+ CALL STEST(LENY,SY,STY,SSIZE2(1,1),1.0E0)
+ ELSE IF (ICASE.EQ.6) THEN
+* .. SSWAP ..
+ CALL SSWAP(N,SX,INCX,SY,INCY)
+ DO 80 I = 1, 7
+ STX(I) = DT10X(I,KN,KI)
+ STY(I) = DT10Y(I,KN,KI)
+ 80 CONTINUE
+ CALL STEST(LENX,SX,STX,SSIZE2(1,1),1.0E0)
+ CALL STEST(LENY,SY,STY,SSIZE2(1,1),1.0E0)
+ ELSE
+ WRITE (NOUT,*) ' Shouldn''t be here in CHECK2'
+ STOP
+ END IF
+ 100 CONTINUE
+ 120 CONTINUE
+ RETURN
+ END
+ SUBROUTINE CHECK3(SFAC)
+* .. Parameters ..
+ INTEGER NOUT
+ PARAMETER (NOUT=6)
+* .. Scalar Arguments ..
+ REAL SFAC
+* .. Scalars in Common ..
+ INTEGER ICASE, INCX, INCY, MODE, N
+ LOGICAL PASS
+* .. Local Scalars ..
+ REAL SA, SC, SS
+ INTEGER I, K, KI, KN, KSIZE, LENX, LENY, MX, MY
+* .. Local Arrays ..
+ REAL COPYX(5), COPYY(5), DT9X(7,4,4), DT9Y(7,4,4),
+ + DX1(7), DY1(7), MWPC(11), MWPS(11), MWPSTX(5),
+ + MWPSTY(5), MWPTX(11,5), MWPTY(11,5), MWPX(5),
+ + MWPY(5), SSIZE2(14,2), STX(7), STY(7), SX(7),
+ + SY(7)
+ INTEGER INCXS(4), INCYS(4), LENS(4,2), MWPINX(11),
+ + MWPINY(11), MWPN(11), NS(4)
+* .. External Subroutines ..
+ EXTERNAL SROT, STEST
+* .. Intrinsic Functions ..
+ INTRINSIC ABS, MIN
+* .. Common blocks ..
+ COMMON /COMBLA/ICASE, N, INCX, INCY, MODE, PASS
+* .. Data statements ..
+ DATA SA/0.3E0/
+ DATA INCXS/1, 2, -2, -1/
+ DATA INCYS/1, -2, 1, -2/
+ DATA LENS/1, 1, 2, 4, 1, 1, 3, 7/
+ DATA NS/0, 1, 2, 4/
+ DATA DX1/0.6E0, 0.1E0, -0.5E0, 0.8E0, 0.9E0, -0.3E0,
+ + -0.4E0/
+ DATA DY1/0.5E0, -0.9E0, 0.3E0, 0.7E0, -0.6E0, 0.2E0,
+ + 0.8E0/
+ DATA SC, SS/0.8E0, 0.6E0/
+ DATA DT9X/0.6E0, 0.0E0, 0.0E0, 0.0E0, 0.0E0, 0.0E0,
+ + 0.0E0, 0.78E0, 0.0E0, 0.0E0, 0.0E0, 0.0E0,
+ + 0.0E0, 0.0E0, 0.78E0, -0.46E0, 0.0E0, 0.0E0,
+ + 0.0E0, 0.0E0, 0.0E0, 0.78E0, -0.46E0, -0.22E0,
+ + 1.06E0, 0.0E0, 0.0E0, 0.0E0, 0.6E0, 0.0E0,
+ + 0.0E0, 0.0E0, 0.0E0, 0.0E0, 0.0E0, 0.78E0,
+ + 0.0E0, 0.0E0, 0.0E0, 0.0E0, 0.0E0, 0.0E0,
+ + 0.66E0, 0.1E0, -0.1E0, 0.0E0, 0.0E0, 0.0E0,
+ + 0.0E0, 0.96E0, 0.1E0, -0.76E0, 0.8E0, 0.90E0,
+ + -0.3E0, -0.02E0, 0.6E0, 0.0E0, 0.0E0, 0.0E0,
+ + 0.0E0, 0.0E0, 0.0E0, 0.78E0, 0.0E0, 0.0E0,
+ + 0.0E0, 0.0E0, 0.0E0, 0.0E0, -0.06E0, 0.1E0,
+ + -0.1E0, 0.0E0, 0.0E0, 0.0E0, 0.0E0, 0.90E0,
+ + 0.1E0, -0.22E0, 0.8E0, 0.18E0, -0.3E0, -0.02E0,
+ + 0.6E0, 0.0E0, 0.0E0, 0.0E0, 0.0E0, 0.0E0, 0.0E0,
+ + 0.78E0, 0.0E0, 0.0E0, 0.0E0, 0.0E0, 0.0E0,
+ + 0.0E0, 0.78E0, 0.26E0, 0.0E0, 0.0E0, 0.0E0,
+ + 0.0E0, 0.0E0, 0.78E0, 0.26E0, -0.76E0, 1.12E0,
+ + 0.0E0, 0.0E0, 0.0E0/
+ DATA DT9Y/0.5E0, 0.0E0, 0.0E0, 0.0E0, 0.0E0, 0.0E0,
+ + 0.0E0, 0.04E0, 0.0E0, 0.0E0, 0.0E0, 0.0E0,
+ + 0.0E0, 0.0E0, 0.04E0, -0.78E0, 0.0E0, 0.0E0,
+ + 0.0E0, 0.0E0, 0.0E0, 0.04E0, -0.78E0, 0.54E0,
+ + 0.08E0, 0.0E0, 0.0E0, 0.0E0, 0.5E0, 0.0E0,
+ + 0.0E0, 0.0E0, 0.0E0, 0.0E0, 0.0E0, 0.04E0,
+ + 0.0E0, 0.0E0, 0.0E0, 0.0E0, 0.0E0, 0.0E0, 0.7E0,
+ + -0.9E0, -0.12E0, 0.0E0, 0.0E0, 0.0E0, 0.0E0,
+ + 0.64E0, -0.9E0, -0.30E0, 0.7E0, -0.18E0, 0.2E0,
+ + 0.28E0, 0.5E0, 0.0E0, 0.0E0, 0.0E0, 0.0E0,
+ + 0.0E0, 0.0E0, 0.04E0, 0.0E0, 0.0E0, 0.0E0,
+ + 0.0E0, 0.0E0, 0.0E0, 0.7E0, -1.08E0, 0.0E0,
+ + 0.0E0, 0.0E0, 0.0E0, 0.0E0, 0.64E0, -1.26E0,
+ + 0.54E0, 0.20E0, 0.0E0, 0.0E0, 0.0E0, 0.5E0,
+ + 0.0E0, 0.0E0, 0.0E0, 0.0E0, 0.0E0, 0.0E0,
+ + 0.04E0, 0.0E0, 0.0E0, 0.0E0, 0.0E0, 0.0E0,
+ + 0.0E0, 0.04E0, -0.9E0, 0.18E0, 0.0E0, 0.0E0,
+ + 0.0E0, 0.0E0, 0.04E0, -0.9E0, 0.18E0, 0.7E0,
+ + -0.18E0, 0.2E0, 0.16E0/
+ DATA SSIZE2/0.0E0, 0.0E0, 0.0E0, 0.0E0, 0.0E0, 0.0E0,
+ + 0.0E0, 0.0E0, 0.0E0, 0.0E0, 0.0E0, 0.0E0, 0.0E0,
+ + 0.0E0, 1.17E0, 1.17E0, 1.17E0, 1.17E0, 1.17E0,
+ + 1.17E0, 1.17E0, 1.17E0, 1.17E0, 1.17E0, 1.17E0,
+ + 1.17E0, 1.17E0, 1.17E0/
+* .. Executable Statements ..
+*
+ DO 60 KI = 1, 4
+ INCX = INCXS(KI)
+ INCY = INCYS(KI)
+ MX = ABS(INCX)
+ MY = ABS(INCY)
+*
+ DO 40 KN = 1, 4
+ N = NS(KN)
+ KSIZE = MIN(2,KN)
+ LENX = LENS(KN,MX)
+ LENY = LENS(KN,MY)
+*
+ IF (ICASE.EQ.4) THEN
+* .. SROT ..
+ DO 20 I = 1, 7
+ SX(I) = DX1(I)
+ SY(I) = DY1(I)
+ STX(I) = DT9X(I,KN,KI)
+ STY(I) = DT9Y(I,KN,KI)
+ 20 CONTINUE
+ CALL SROT(N,SX,INCX,SY,INCY,SC,SS)
+ CALL STEST(LENX,SX,STX,SSIZE2(1,KSIZE),SFAC)
+ CALL STEST(LENY,SY,STY,SSIZE2(1,KSIZE),SFAC)
+ ELSE
+ WRITE (NOUT,*) ' Shouldn''t be here in CHECK3'
+ STOP
+ END IF
+ 40 CONTINUE
+ 60 CONTINUE
+*
+ MWPC(1) = 1
+ DO 80 I = 2, 11
+ MWPC(I) = 0
+ 80 CONTINUE
+ MWPS(1) = 0
+ DO 100 I = 2, 6
+ MWPS(I) = 1
+ 100 CONTINUE
+ DO 120 I = 7, 11
+ MWPS(I) = -1
+ 120 CONTINUE
+ MWPINX(1) = 1
+ MWPINX(2) = 1
+ MWPINX(3) = 1
+ MWPINX(4) = -1
+ MWPINX(5) = 1
+ MWPINX(6) = -1
+ MWPINX(7) = 1
+ MWPINX(8) = 1
+ MWPINX(9) = -1
+ MWPINX(10) = 1
+ MWPINX(11) = -1
+ MWPINY(1) = 1
+ MWPINY(2) = 1
+ MWPINY(3) = -1
+ MWPINY(4) = -1
+ MWPINY(5) = 2
+ MWPINY(6) = 1
+ MWPINY(7) = 1
+ MWPINY(8) = -1
+ MWPINY(9) = -1
+ MWPINY(10) = 2
+ MWPINY(11) = 1
+ DO 140 I = 1, 11
+ MWPN(I) = 5
+ 140 CONTINUE
+ MWPN(5) = 3
+ MWPN(10) = 3
+ DO 160 I = 1, 5
+ MWPX(I) = I
+ MWPY(I) = I
+ MWPTX(1,I) = I
+ MWPTY(1,I) = I
+ MWPTX(2,I) = I
+ MWPTY(2,I) = -I
+ MWPTX(3,I) = 6 - I
+ MWPTY(3,I) = I - 6
+ MWPTX(4,I) = I
+ MWPTY(4,I) = -I
+ MWPTX(6,I) = 6 - I
+ MWPTY(6,I) = I - 6
+ MWPTX(7,I) = -I
+ MWPTY(7,I) = I
+ MWPTX(8,I) = I - 6
+ MWPTY(8,I) = 6 - I
+ MWPTX(9,I) = -I
+ MWPTY(9,I) = I
+ MWPTX(11,I) = I - 6
+ MWPTY(11,I) = 6 - I
+ 160 CONTINUE
+ MWPTX(5,1) = 1
+ MWPTX(5,2) = 3
+ MWPTX(5,3) = 5
+ MWPTX(5,4) = 4
+ MWPTX(5,5) = 5
+ MWPTY(5,1) = -1
+ MWPTY(5,2) = 2
+ MWPTY(5,3) = -2
+ MWPTY(5,4) = 4
+ MWPTY(5,5) = -3
+ MWPTX(10,1) = -1
+ MWPTX(10,2) = -3
+ MWPTX(10,3) = -5
+ MWPTX(10,4) = 4
+ MWPTX(10,5) = 5
+ MWPTY(10,1) = 1
+ MWPTY(10,2) = 2
+ MWPTY(10,3) = 2
+ MWPTY(10,4) = 4
+ MWPTY(10,5) = 3
+ DO 200 I = 1, 11
+ INCX = MWPINX(I)
+ INCY = MWPINY(I)
+ DO 180 K = 1, 5
+ COPYX(K) = MWPX(K)
+ COPYY(K) = MWPY(K)
+ MWPSTX(K) = MWPTX(I,K)
+ MWPSTY(K) = MWPTY(I,K)
+ 180 CONTINUE
+ CALL SROT(MWPN(I),COPYX,INCX,COPYY,INCY,MWPC(I),MWPS(I))
+ CALL STEST(5,COPYX,MWPSTX,MWPSTX,SFAC)
+ CALL STEST(5,COPYY,MWPSTY,MWPSTY,SFAC)
+ 200 CONTINUE
+ RETURN
+ END
+ SUBROUTINE STEST(LEN,SCOMP,STRUE,SSIZE,SFAC)
+* ********************************* STEST **************************
+*
+* THIS SUBR COMPARES ARRAYS SCOMP() AND STRUE() OF LENGTH LEN TO
+* SEE IF THE TERM BY TERM DIFFERENCES, MULTIPLIED BY SFAC, ARE
+* NEGLIGIBLE.
+*
+* C. L. LAWSON, JPL, 1974 DEC 10
+*
+* .. Parameters ..
+ INTEGER NOUT
+ PARAMETER (NOUT=6)
+* .. Scalar Arguments ..
+ REAL SFAC
+ INTEGER LEN
+* .. Array Arguments ..
+ REAL SCOMP(LEN), SSIZE(LEN), STRUE(LEN)
+* .. Scalars in Common ..
+ INTEGER ICASE, INCX, INCY, MODE, N
+ LOGICAL PASS
+* .. Local Scalars ..
+ REAL SD
+ INTEGER I
+* .. External Functions ..
+ REAL SDIFF
+ EXTERNAL SDIFF
+* .. Intrinsic Functions ..
+ INTRINSIC ABS
+* .. Common blocks ..
+ COMMON /COMBLA/ICASE, N, INCX, INCY, MODE, PASS
+* .. Executable Statements ..
+*
+ DO 40 I = 1, LEN
+ SD = SCOMP(I) - STRUE(I)
+ IF (SDIFF(ABS(SSIZE(I))+ABS(SFAC*SD),ABS(SSIZE(I))).EQ.0.0E0)
+ + GO TO 40
+*
+* HERE SCOMP(I) IS NOT CLOSE TO STRUE(I).
+*
+ IF ( .NOT. PASS) GO TO 20
+* PRINT FAIL MESSAGE AND HEADER.
+ PASS = .FALSE.
+ WRITE (NOUT,99999)
+ WRITE (NOUT,99998)
+ 20 WRITE (NOUT,99997) ICASE, N, INCX, INCY, MODE, I, SCOMP(I),
+ + STRUE(I), SD, SSIZE(I)
+ 40 CONTINUE
+ RETURN
+*
+99999 FORMAT (' FAIL')
+99998 FORMAT (/' CASE N INCX INCY MODE I ',
+ + ' COMP(I) TRUE(I) DIFFERENCE',
+ + ' SIZE(I)',/1X)
+99997 FORMAT (1X,I4,I3,3I5,I3,2E36.8,2E12.4)
+ END
+ SUBROUTINE STEST1(SCOMP1,STRUE1,SSIZE,SFAC)
+* ************************* STEST1 *****************************
+*
+* THIS IS AN INTERFACE SUBROUTINE TO ACCOMODATE THE FORTRAN
+* REQUIREMENT THAT WHEN A DUMMY ARGUMENT IS AN ARRAY, THE
+* ACTUAL ARGUMENT MUST ALSO BE AN ARRAY OR AN ARRAY ELEMENT.
+*
+* C.L. LAWSON, JPL, 1978 DEC 6
+*
+* .. Scalar Arguments ..
+ REAL SCOMP1, SFAC, STRUE1
+* .. Array Arguments ..
+ REAL SSIZE(*)
+* .. Local Arrays ..
+ REAL SCOMP(1), STRUE(1)
+* .. External Subroutines ..
+ EXTERNAL STEST
+* .. Executable Statements ..
+*
+ SCOMP(1) = SCOMP1
+ STRUE(1) = STRUE1
+ CALL STEST(1,SCOMP,STRUE,SSIZE,SFAC)
+*
+ RETURN
+ END
+ REAL FUNCTION SDIFF(SA,SB)
+* ********************************* SDIFF **************************
+* COMPUTES DIFFERENCE OF TWO NUMBERS. C. L. LAWSON, JPL 1974 FEB 15
+*
+* .. Scalar Arguments ..
+ REAL SA, SB
+* .. Executable Statements ..
+ SDIFF = SA - SB
+ RETURN
+ END
+ SUBROUTINE ITEST1(ICOMP,ITRUE)
+* ********************************* ITEST1 *************************
+*
+* THIS SUBROUTINE COMPARES THE VARIABLES ICOMP AND ITRUE FOR
+* EQUALITY.
+* C. L. LAWSON, JPL, 1974 DEC 10
+*
+* .. Parameters ..
+ INTEGER NOUT
+ PARAMETER (NOUT=6)
+* .. Scalar Arguments ..
+ INTEGER ICOMP, ITRUE
+* .. Scalars in Common ..
+ INTEGER ICASE, INCX, INCY, MODE, N
+ LOGICAL PASS
+* .. Local Scalars ..
+ INTEGER ID
+* .. Common blocks ..
+ COMMON /COMBLA/ICASE, N, INCX, INCY, MODE, PASS
+* .. Executable Statements ..
+*
+ IF (ICOMP.EQ.ITRUE) GO TO 40
+*
+* HERE ICOMP IS NOT EQUAL TO ITRUE.
+*
+ IF ( .NOT. PASS) GO TO 20
+* PRINT FAIL MESSAGE AND HEADER.
+ PASS = .FALSE.
+ WRITE (NOUT,99999)
+ WRITE (NOUT,99998)
+ 20 ID = ICOMP - ITRUE
+ WRITE (NOUT,99997) ICASE, N, INCX, INCY, MODE, ICOMP, ITRUE, ID
+ 40 CONTINUE
+ RETURN
+*
+99999 FORMAT (' FAIL')
+99998 FORMAT (/' CASE N INCX INCY MODE ',
+ + ' COMP TRUE DIFFERENCE',
+ + /1X)
+99997 FORMAT (1X,I4,I3,3I5,2I36,I12)
+ END
diff --git a/blas/testing/sblat2.dat b/blas/testing/sblat2.dat
new file mode 100644
index 000000000..f537d3075
--- /dev/null
+++ b/blas/testing/sblat2.dat
@@ -0,0 +1,34 @@
+'sblat2.summ' NAME OF SUMMARY OUTPUT FILE
+6 UNIT NUMBER OF SUMMARY FILE
+'sblat2.snap' NAME OF SNAPSHOT OUTPUT FILE
+-1 UNIT NUMBER OF SNAPSHOT FILE (NOT USED IF .LT. 0)
+F LOGICAL FLAG, T TO REWIND SNAPSHOT FILE AFTER EACH RECORD.
+F LOGICAL FLAG, T TO STOP ON FAILURES.
+T LOGICAL FLAG, T TO TEST ERROR EXITS.
+16.0 THRESHOLD VALUE OF TEST RATIO
+6 NUMBER OF VALUES OF N
+0 1 2 3 5 9 VALUES OF N
+4 NUMBER OF VALUES OF K
+0 1 2 4 VALUES OF K
+4 NUMBER OF VALUES OF INCX AND INCY
+1 2 -1 -2 VALUES OF INCX AND INCY
+3 NUMBER OF VALUES OF ALPHA
+0.0 1.0 0.7 VALUES OF ALPHA
+3 NUMBER OF VALUES OF BETA
+0.0 1.0 0.9 VALUES OF BETA
+SGEMV T PUT F FOR NO TEST. SAME COLUMNS.
+SGBMV T PUT F FOR NO TEST. SAME COLUMNS.
+SSYMV T PUT F FOR NO TEST. SAME COLUMNS.
+SSBMV T PUT F FOR NO TEST. SAME COLUMNS.
+SSPMV T PUT F FOR NO TEST. SAME COLUMNS.
+STRMV T PUT F FOR NO TEST. SAME COLUMNS.
+STBMV T PUT F FOR NO TEST. SAME COLUMNS.
+STPMV T PUT F FOR NO TEST. SAME COLUMNS.
+STRSV T PUT F FOR NO TEST. SAME COLUMNS.
+STBSV T PUT F FOR NO TEST. SAME COLUMNS.
+STPSV T PUT F FOR NO TEST. SAME COLUMNS.
+SGER T PUT F FOR NO TEST. SAME COLUMNS.
+SSYR T PUT F FOR NO TEST. SAME COLUMNS.
+SSPR T PUT F FOR NO TEST. SAME COLUMNS.
+SSYR2 T PUT F FOR NO TEST. SAME COLUMNS.
+SSPR2 T PUT F FOR NO TEST. SAME COLUMNS.
diff --git a/blas/testing/sblat2.f b/blas/testing/sblat2.f
new file mode 100644
index 000000000..057a85429
--- /dev/null
+++ b/blas/testing/sblat2.f
@@ -0,0 +1,3138 @@
+ PROGRAM SBLAT2
+*
+* Test program for the REAL Level 2 Blas.
+*
+* The program must be driven by a short data file. The first 18 records
+* of the file are read using list-directed input, the last 16 records
+* are read using the format ( A6, L2 ). An annotated example of a data
+* file can be obtained by deleting the first 3 characters from the
+* following 34 lines:
+* 'SBLAT2.SUMM' NAME OF SUMMARY OUTPUT FILE
+* 6 UNIT NUMBER OF SUMMARY FILE
+* 'SBLAT2.SNAP' NAME OF SNAPSHOT OUTPUT FILE
+* -1 UNIT NUMBER OF SNAPSHOT FILE (NOT USED IF .LT. 0)
+* F LOGICAL FLAG, T TO REWIND SNAPSHOT FILE AFTER EACH RECORD.
+* F LOGICAL FLAG, T TO STOP ON FAILURES.
+* T LOGICAL FLAG, T TO TEST ERROR EXITS.
+* 16.0 THRESHOLD VALUE OF TEST RATIO
+* 6 NUMBER OF VALUES OF N
+* 0 1 2 3 5 9 VALUES OF N
+* 4 NUMBER OF VALUES OF K
+* 0 1 2 4 VALUES OF K
+* 4 NUMBER OF VALUES OF INCX AND INCY
+* 1 2 -1 -2 VALUES OF INCX AND INCY
+* 3 NUMBER OF VALUES OF ALPHA
+* 0.0 1.0 0.7 VALUES OF ALPHA
+* 3 NUMBER OF VALUES OF BETA
+* 0.0 1.0 0.9 VALUES OF BETA
+* SGEMV T PUT F FOR NO TEST. SAME COLUMNS.
+* SGBMV T PUT F FOR NO TEST. SAME COLUMNS.
+* SSYMV T PUT F FOR NO TEST. SAME COLUMNS.
+* SSBMV T PUT F FOR NO TEST. SAME COLUMNS.
+* SSPMV T PUT F FOR NO TEST. SAME COLUMNS.
+* STRMV T PUT F FOR NO TEST. SAME COLUMNS.
+* STBMV T PUT F FOR NO TEST. SAME COLUMNS.
+* STPMV T PUT F FOR NO TEST. SAME COLUMNS.
+* STRSV T PUT F FOR NO TEST. SAME COLUMNS.
+* STBSV T PUT F FOR NO TEST. SAME COLUMNS.
+* STPSV T PUT F FOR NO TEST. SAME COLUMNS.
+* SGER T PUT F FOR NO TEST. SAME COLUMNS.
+* SSYR T PUT F FOR NO TEST. SAME COLUMNS.
+* SSPR T PUT F FOR NO TEST. SAME COLUMNS.
+* SSYR2 T PUT F FOR NO TEST. SAME COLUMNS.
+* SSPR2 T PUT F FOR NO TEST. SAME COLUMNS.
+*
+* See:
+*
+* Dongarra J. J., Du Croz J. J., Hammarling S. and Hanson R. J..
+* An extended set of Fortran Basic Linear Algebra Subprograms.
+*
+* Technical Memoranda Nos. 41 (revision 3) and 81, Mathematics
+* and Computer Science Division, Argonne National Laboratory,
+* 9700 South Cass Avenue, Argonne, Illinois 60439, US.
+*
+* Or
+*
+* NAG Technical Reports TR3/87 and TR4/87, Numerical Algorithms
+* Group Ltd., NAG Central Office, 256 Banbury Road, Oxford
+* OX2 7DE, UK, and Numerical Algorithms Group Inc., 1101 31st
+* Street, Suite 100, Downers Grove, Illinois 60515-1263, USA.
+*
+*
+* -- Written on 10-August-1987.
+* Richard Hanson, Sandia National Labs.
+* Jeremy Du Croz, NAG Central Office.
+*
+* .. Parameters ..
+ INTEGER NIN
+ PARAMETER ( NIN = 5 )
+ INTEGER NSUBS
+ PARAMETER ( NSUBS = 16 )
+ REAL ZERO, HALF, ONE
+ PARAMETER ( ZERO = 0.0, HALF = 0.5, ONE = 1.0 )
+ INTEGER NMAX, INCMAX
+ PARAMETER ( NMAX = 65, INCMAX = 2 )
+ INTEGER NINMAX, NIDMAX, NKBMAX, NALMAX, NBEMAX
+ PARAMETER ( NINMAX = 7, NIDMAX = 9, NKBMAX = 7,
+ $ NALMAX = 7, NBEMAX = 7 )
+* .. Local Scalars ..
+ REAL EPS, ERR, THRESH
+ INTEGER I, ISNUM, J, N, NALF, NBET, NIDIM, NINC, NKB,
+ $ NOUT, NTRA
+ LOGICAL FATAL, LTESTT, REWI, SAME, SFATAL, TRACE,
+ $ TSTERR
+ CHARACTER*1 TRANS
+ CHARACTER*6 SNAMET
+ CHARACTER*32 SNAPS, SUMMRY
+* .. Local Arrays ..
+ REAL A( NMAX, NMAX ), AA( NMAX*NMAX ),
+ $ ALF( NALMAX ), AS( NMAX*NMAX ), BET( NBEMAX ),
+ $ G( NMAX ), X( NMAX ), XS( NMAX*INCMAX ),
+ $ XX( NMAX*INCMAX ), Y( NMAX ),
+ $ YS( NMAX*INCMAX ), YT( NMAX ),
+ $ YY( NMAX*INCMAX ), Z( 2*NMAX )
+ INTEGER IDIM( NIDMAX ), INC( NINMAX ), KB( NKBMAX )
+ LOGICAL LTEST( NSUBS )
+ CHARACTER*6 SNAMES( NSUBS )
+* .. External Functions ..
+ REAL SDIFF
+ LOGICAL LSE
+ EXTERNAL SDIFF, LSE
+* .. External Subroutines ..
+ EXTERNAL SCHK1, SCHK2, SCHK3, SCHK4, SCHK5, SCHK6,
+ $ SCHKE, SMVCH
+* .. Intrinsic Functions ..
+ INTRINSIC ABS, MAX, MIN
+* .. Scalars in Common ..
+ INTEGER INFOT, NOUTC
+ LOGICAL LERR, OK
+ CHARACTER*6 SRNAMT
+* .. Common blocks ..
+ COMMON /INFOC/INFOT, NOUTC, OK, LERR
+ COMMON /SRNAMC/SRNAMT
+* .. Data statements ..
+ DATA SNAMES/'SGEMV ', 'SGBMV ', 'SSYMV ', 'SSBMV ',
+ $ 'SSPMV ', 'STRMV ', 'STBMV ', 'STPMV ',
+ $ 'STRSV ', 'STBSV ', 'STPSV ', 'SGER ',
+ $ 'SSYR ', 'SSPR ', 'SSYR2 ', 'SSPR2 '/
+* .. Executable Statements ..
+*
+* Read name and unit number for summary output file and open file.
+*
+ READ( NIN, FMT = * )SUMMRY
+ READ( NIN, FMT = * )NOUT
+ OPEN( NOUT, FILE = SUMMRY, STATUS = 'NEW' )
+ NOUTC = NOUT
+*
+* Read name and unit number for snapshot output file and open file.
+*
+ READ( NIN, FMT = * )SNAPS
+ READ( NIN, FMT = * )NTRA
+ TRACE = NTRA.GE.0
+ IF( TRACE )THEN
+ OPEN( NTRA, FILE = SNAPS, STATUS = 'NEW' )
+ END IF
+* Read the flag that directs rewinding of the snapshot file.
+ READ( NIN, FMT = * )REWI
+ REWI = REWI.AND.TRACE
+* Read the flag that directs stopping on any failure.
+ READ( NIN, FMT = * )SFATAL
+* Read the flag that indicates whether error exits are to be tested.
+ READ( NIN, FMT = * )TSTERR
+* Read the threshold value of the test ratio
+ READ( NIN, FMT = * )THRESH
+*
+* Read and check the parameter values for the tests.
+*
+* Values of N
+ READ( NIN, FMT = * )NIDIM
+ IF( NIDIM.LT.1.OR.NIDIM.GT.NIDMAX )THEN
+ WRITE( NOUT, FMT = 9997 )'N', NIDMAX
+ GO TO 230
+ END IF
+ READ( NIN, FMT = * )( IDIM( I ), I = 1, NIDIM )
+ DO 10 I = 1, NIDIM
+ IF( IDIM( I ).LT.0.OR.IDIM( I ).GT.NMAX )THEN
+ WRITE( NOUT, FMT = 9996 )NMAX
+ GO TO 230
+ END IF
+ 10 CONTINUE
+* Values of K
+ READ( NIN, FMT = * )NKB
+ IF( NKB.LT.1.OR.NKB.GT.NKBMAX )THEN
+ WRITE( NOUT, FMT = 9997 )'K', NKBMAX
+ GO TO 230
+ END IF
+ READ( NIN, FMT = * )( KB( I ), I = 1, NKB )
+ DO 20 I = 1, NKB
+ IF( KB( I ).LT.0 )THEN
+ WRITE( NOUT, FMT = 9995 )
+ GO TO 230
+ END IF
+ 20 CONTINUE
+* Values of INCX and INCY
+ READ( NIN, FMT = * )NINC
+ IF( NINC.LT.1.OR.NINC.GT.NINMAX )THEN
+ WRITE( NOUT, FMT = 9997 )'INCX AND INCY', NINMAX
+ GO TO 230
+ END IF
+ READ( NIN, FMT = * )( INC( I ), I = 1, NINC )
+ DO 30 I = 1, NINC
+ IF( INC( I ).EQ.0.OR.ABS( INC( I ) ).GT.INCMAX )THEN
+ WRITE( NOUT, FMT = 9994 )INCMAX
+ GO TO 230
+ END IF
+ 30 CONTINUE
+* Values of ALPHA
+ READ( NIN, FMT = * )NALF
+ IF( NALF.LT.1.OR.NALF.GT.NALMAX )THEN
+ WRITE( NOUT, FMT = 9997 )'ALPHA', NALMAX
+ GO TO 230
+ END IF
+ READ( NIN, FMT = * )( ALF( I ), I = 1, NALF )
+* Values of BETA
+ READ( NIN, FMT = * )NBET
+ IF( NBET.LT.1.OR.NBET.GT.NBEMAX )THEN
+ WRITE( NOUT, FMT = 9997 )'BETA', NBEMAX
+ GO TO 230
+ END IF
+ READ( NIN, FMT = * )( BET( I ), I = 1, NBET )
+*
+* Report values of parameters.
+*
+ WRITE( NOUT, FMT = 9993 )
+ WRITE( NOUT, FMT = 9992 )( IDIM( I ), I = 1, NIDIM )
+ WRITE( NOUT, FMT = 9991 )( KB( I ), I = 1, NKB )
+ WRITE( NOUT, FMT = 9990 )( INC( I ), I = 1, NINC )
+ WRITE( NOUT, FMT = 9989 )( ALF( I ), I = 1, NALF )
+ WRITE( NOUT, FMT = 9988 )( BET( I ), I = 1, NBET )
+ IF( .NOT.TSTERR )THEN
+ WRITE( NOUT, FMT = * )
+ WRITE( NOUT, FMT = 9980 )
+ END IF
+ WRITE( NOUT, FMT = * )
+ WRITE( NOUT, FMT = 9999 )THRESH
+ WRITE( NOUT, FMT = * )
+*
+* Read names of subroutines and flags which indicate
+* whether they are to be tested.
+*
+ DO 40 I = 1, NSUBS
+ LTEST( I ) = .FALSE.
+ 40 CONTINUE
+ 50 READ( NIN, FMT = 9984, END = 80 )SNAMET, LTESTT
+ DO 60 I = 1, NSUBS
+ IF( SNAMET.EQ.SNAMES( I ) )
+ $ GO TO 70
+ 60 CONTINUE
+ WRITE( NOUT, FMT = 9986 )SNAMET
+ STOP
+ 70 LTEST( I ) = LTESTT
+ GO TO 50
+*
+ 80 CONTINUE
+ CLOSE ( NIN )
+*
+* Compute EPS (the machine precision).
+*
+ EPS = ONE
+ 90 CONTINUE
+ IF( SDIFF( ONE + EPS, ONE ).EQ.ZERO )
+ $ GO TO 100
+ EPS = HALF*EPS
+ GO TO 90
+ 100 CONTINUE
+ EPS = EPS + EPS
+ WRITE( NOUT, FMT = 9998 )EPS
+*
+* Check the reliability of SMVCH using exact data.
+*
+ N = MIN( 32, NMAX )
+ DO 120 J = 1, N
+ DO 110 I = 1, N
+ A( I, J ) = MAX( I - J + 1, 0 )
+ 110 CONTINUE
+ X( J ) = J
+ Y( J ) = ZERO
+ 120 CONTINUE
+ DO 130 J = 1, N
+ YY( J ) = J*( ( J + 1 )*J )/2 - ( ( J + 1 )*J*( J - 1 ) )/3
+ 130 CONTINUE
+* YY holds the exact result. On exit from SMVCH YT holds
+* the result computed by SMVCH.
+ TRANS = 'N'
+ CALL SMVCH( TRANS, N, N, ONE, A, NMAX, X, 1, ZERO, Y, 1, YT, G,
+ $ YY, EPS, ERR, FATAL, NOUT, .TRUE. )
+ SAME = LSE( YY, YT, N )
+ IF( .NOT.SAME.OR.ERR.NE.ZERO )THEN
+ WRITE( NOUT, FMT = 9985 )TRANS, SAME, ERR
+ STOP
+ END IF
+ TRANS = 'T'
+ CALL SMVCH( TRANS, N, N, ONE, A, NMAX, X, -1, ZERO, Y, -1, YT, G,
+ $ YY, EPS, ERR, FATAL, NOUT, .TRUE. )
+ SAME = LSE( YY, YT, N )
+ IF( .NOT.SAME.OR.ERR.NE.ZERO )THEN
+ WRITE( NOUT, FMT = 9985 )TRANS, SAME, ERR
+ STOP
+ END IF
+*
+* Test each subroutine in turn.
+*
+ DO 210 ISNUM = 1, NSUBS
+ WRITE( NOUT, FMT = * )
+ IF( .NOT.LTEST( ISNUM ) )THEN
+* Subprogram is not to be tested.
+ WRITE( NOUT, FMT = 9983 )SNAMES( ISNUM )
+ ELSE
+ SRNAMT = SNAMES( ISNUM )
+* Test error exits.
+ IF( TSTERR )THEN
+ CALL SCHKE( ISNUM, SNAMES( ISNUM ), NOUT )
+ WRITE( NOUT, FMT = * )
+ END IF
+* Test computations.
+ INFOT = 0
+ OK = .TRUE.
+ FATAL = .FALSE.
+ GO TO ( 140, 140, 150, 150, 150, 160, 160,
+ $ 160, 160, 160, 160, 170, 180, 180,
+ $ 190, 190 )ISNUM
+* Test SGEMV, 01, and SGBMV, 02.
+ 140 CALL SCHK1( SNAMES( ISNUM ), EPS, THRESH, NOUT, NTRA, TRACE,
+ $ REWI, FATAL, NIDIM, IDIM, NKB, KB, NALF, ALF,
+ $ NBET, BET, NINC, INC, NMAX, INCMAX, A, AA, AS,
+ $ X, XX, XS, Y, YY, YS, YT, G )
+ GO TO 200
+* Test SSYMV, 03, SSBMV, 04, and SSPMV, 05.
+ 150 CALL SCHK2( SNAMES( ISNUM ), EPS, THRESH, NOUT, NTRA, TRACE,
+ $ REWI, FATAL, NIDIM, IDIM, NKB, KB, NALF, ALF,
+ $ NBET, BET, NINC, INC, NMAX, INCMAX, A, AA, AS,
+ $ X, XX, XS, Y, YY, YS, YT, G )
+ GO TO 200
+* Test STRMV, 06, STBMV, 07, STPMV, 08,
+* STRSV, 09, STBSV, 10, and STPSV, 11.
+ 160 CALL SCHK3( SNAMES( ISNUM ), EPS, THRESH, NOUT, NTRA, TRACE,
+ $ REWI, FATAL, NIDIM, IDIM, NKB, KB, NINC, INC,
+ $ NMAX, INCMAX, A, AA, AS, Y, YY, YS, YT, G, Z )
+ GO TO 200
+* Test SGER, 12.
+ 170 CALL SCHK4( SNAMES( ISNUM ), EPS, THRESH, NOUT, NTRA, TRACE,
+ $ REWI, FATAL, NIDIM, IDIM, NALF, ALF, NINC, INC,
+ $ NMAX, INCMAX, A, AA, AS, X, XX, XS, Y, YY, YS,
+ $ YT, G, Z )
+ GO TO 200
+* Test SSYR, 13, and SSPR, 14.
+ 180 CALL SCHK5( SNAMES( ISNUM ), EPS, THRESH, NOUT, NTRA, TRACE,
+ $ REWI, FATAL, NIDIM, IDIM, NALF, ALF, NINC, INC,
+ $ NMAX, INCMAX, A, AA, AS, X, XX, XS, Y, YY, YS,
+ $ YT, G, Z )
+ GO TO 200
+* Test SSYR2, 15, and SSPR2, 16.
+ 190 CALL SCHK6( SNAMES( ISNUM ), EPS, THRESH, NOUT, NTRA, TRACE,
+ $ REWI, FATAL, NIDIM, IDIM, NALF, ALF, NINC, INC,
+ $ NMAX, INCMAX, A, AA, AS, X, XX, XS, Y, YY, YS,
+ $ YT, G, Z )
+*
+ 200 IF( FATAL.AND.SFATAL )
+ $ GO TO 220
+ END IF
+ 210 CONTINUE
+ WRITE( NOUT, FMT = 9982 )
+ GO TO 240
+*
+ 220 CONTINUE
+ WRITE( NOUT, FMT = 9981 )
+ GO TO 240
+*
+ 230 CONTINUE
+ WRITE( NOUT, FMT = 9987 )
+*
+ 240 CONTINUE
+ IF( TRACE )
+ $ CLOSE ( NTRA )
+ CLOSE ( NOUT )
+ STOP
+*
+ 9999 FORMAT( ' ROUTINES PASS COMPUTATIONAL TESTS IF TEST RATIO IS LES',
+ $ 'S THAN', F8.2 )
+ 9998 FORMAT( ' RELATIVE MACHINE PRECISION IS TAKEN TO BE', 1P, E9.1 )
+ 9997 FORMAT( ' NUMBER OF VALUES OF ', A, ' IS LESS THAN 1 OR GREATER ',
+ $ 'THAN ', I2 )
+ 9996 FORMAT( ' VALUE OF N IS LESS THAN 0 OR GREATER THAN ', I2 )
+ 9995 FORMAT( ' VALUE OF K IS LESS THAN 0' )
+ 9994 FORMAT( ' ABSOLUTE VALUE OF INCX OR INCY IS 0 OR GREATER THAN ',
+ $ I2 )
+ 9993 FORMAT( ' TESTS OF THE REAL LEVEL 2 BLAS', //' THE F',
+ $ 'OLLOWING PARAMETER VALUES WILL BE USED:' )
+ 9992 FORMAT( ' FOR N ', 9I6 )
+ 9991 FORMAT( ' FOR K ', 7I6 )
+ 9990 FORMAT( ' FOR INCX AND INCY ', 7I6 )
+ 9989 FORMAT( ' FOR ALPHA ', 7F6.1 )
+ 9988 FORMAT( ' FOR BETA ', 7F6.1 )
+ 9987 FORMAT( ' AMEND DATA FILE OR INCREASE ARRAY SIZES IN PROGRAM',
+ $ /' ******* TESTS ABANDONED *******' )
+ 9986 FORMAT( ' SUBPROGRAM NAME ', A6, ' NOT RECOGNIZED', /' ******* T',
+ $ 'ESTS ABANDONED *******' )
+ 9985 FORMAT( ' ERROR IN SMVCH - IN-LINE DOT PRODUCTS ARE BEING EVALU',
+ $ 'ATED WRONGLY.', /' SMVCH WAS CALLED WITH TRANS = ', A1,
+ $ ' AND RETURNED SAME = ', L1, ' AND ERR = ', F12.3, '.', /
+ $ ' THIS MAY BE DUE TO FAULTS IN THE ARITHMETIC OR THE COMPILER.'
+ $ , /' ******* TESTS ABANDONED *******' )
+ 9984 FORMAT( A6, L2 )
+ 9983 FORMAT( 1X, A6, ' WAS NOT TESTED' )
+ 9982 FORMAT( /' END OF TESTS' )
+ 9981 FORMAT( /' ******* FATAL ERROR - TESTS ABANDONED *******' )
+ 9980 FORMAT( ' ERROR-EXITS WILL NOT BE TESTED' )
+*
+* End of SBLAT2.
+*
+ END
+ SUBROUTINE SCHK1( SNAME, EPS, THRESH, NOUT, NTRA, TRACE, REWI,
+ $ FATAL, NIDIM, IDIM, NKB, KB, NALF, ALF, NBET,
+ $ BET, NINC, INC, NMAX, INCMAX, A, AA, AS, X, XX,
+ $ XS, Y, YY, YS, YT, G )
+*
+* Tests SGEMV and SGBMV.
+*
+* Auxiliary routine for test program for Level 2 Blas.
+*
+* -- Written on 10-August-1987.
+* Richard Hanson, Sandia National Labs.
+* Jeremy Du Croz, NAG Central Office.
+*
+* .. Parameters ..
+ REAL ZERO, HALF
+ PARAMETER ( ZERO = 0.0, HALF = 0.5 )
+* .. Scalar Arguments ..
+ REAL EPS, THRESH
+ INTEGER INCMAX, NALF, NBET, NIDIM, NINC, NKB, NMAX,
+ $ NOUT, NTRA
+ LOGICAL FATAL, REWI, TRACE
+ CHARACTER*6 SNAME
+* .. Array Arguments ..
+ REAL A( NMAX, NMAX ), AA( NMAX*NMAX ), ALF( NALF ),
+ $ AS( NMAX*NMAX ), BET( NBET ), G( NMAX ),
+ $ X( NMAX ), XS( NMAX*INCMAX ),
+ $ XX( NMAX*INCMAX ), Y( NMAX ),
+ $ YS( NMAX*INCMAX ), YT( NMAX ),
+ $ YY( NMAX*INCMAX )
+ INTEGER IDIM( NIDIM ), INC( NINC ), KB( NKB )
+* .. Local Scalars ..
+ REAL ALPHA, ALS, BETA, BLS, ERR, ERRMAX, TRANSL
+ INTEGER I, IA, IB, IC, IKU, IM, IN, INCX, INCXS, INCY,
+ $ INCYS, IX, IY, KL, KLS, KU, KUS, LAA, LDA,
+ $ LDAS, LX, LY, M, ML, MS, N, NARGS, NC, ND, NK,
+ $ NL, NS
+ LOGICAL BANDED, FULL, NULL, RESET, SAME, TRAN
+ CHARACTER*1 TRANS, TRANSS
+ CHARACTER*3 ICH
+* .. Local Arrays ..
+ LOGICAL ISAME( 13 )
+* .. External Functions ..
+ LOGICAL LSE, LSERES
+ EXTERNAL LSE, LSERES
+* .. External Subroutines ..
+ EXTERNAL SGBMV, SGEMV, SMAKE, SMVCH
+* .. Intrinsic Functions ..
+ INTRINSIC ABS, MAX, MIN
+* .. Scalars in Common ..
+ INTEGER INFOT, NOUTC
+ LOGICAL LERR, OK
+* .. Common blocks ..
+ COMMON /INFOC/INFOT, NOUTC, OK, LERR
+* .. Data statements ..
+ DATA ICH/'NTC'/
+* .. Executable Statements ..
+ FULL = SNAME( 3: 3 ).EQ.'E'
+ BANDED = SNAME( 3: 3 ).EQ.'B'
+* Define the number of arguments.
+ IF( FULL )THEN
+ NARGS = 11
+ ELSE IF( BANDED )THEN
+ NARGS = 13
+ END IF
+*
+ NC = 0
+ RESET = .TRUE.
+ ERRMAX = ZERO
+*
+ DO 120 IN = 1, NIDIM
+ N = IDIM( IN )
+ ND = N/2 + 1
+*
+ DO 110 IM = 1, 2
+ IF( IM.EQ.1 )
+ $ M = MAX( N - ND, 0 )
+ IF( IM.EQ.2 )
+ $ M = MIN( N + ND, NMAX )
+*
+ IF( BANDED )THEN
+ NK = NKB
+ ELSE
+ NK = 1
+ END IF
+ DO 100 IKU = 1, NK
+ IF( BANDED )THEN
+ KU = KB( IKU )
+ KL = MAX( KU - 1, 0 )
+ ELSE
+ KU = N - 1
+ KL = M - 1
+ END IF
+* Set LDA to 1 more than minimum value if room.
+ IF( BANDED )THEN
+ LDA = KL + KU + 1
+ ELSE
+ LDA = M
+ END IF
+ IF( LDA.LT.NMAX )
+ $ LDA = LDA + 1
+* Skip tests if not enough room.
+ IF( LDA.GT.NMAX )
+ $ GO TO 100
+ LAA = LDA*N
+ NULL = N.LE.0.OR.M.LE.0
+*
+* Generate the matrix A.
+*
+ TRANSL = ZERO
+ CALL SMAKE( SNAME( 2: 3 ), ' ', ' ', M, N, A, NMAX, AA,
+ $ LDA, KL, KU, RESET, TRANSL )
+*
+ DO 90 IC = 1, 3
+ TRANS = ICH( IC: IC )
+ TRAN = TRANS.EQ.'T'.OR.TRANS.EQ.'C'
+*
+ IF( TRAN )THEN
+ ML = N
+ NL = M
+ ELSE
+ ML = M
+ NL = N
+ END IF
+*
+ DO 80 IX = 1, NINC
+ INCX = INC( IX )
+ LX = ABS( INCX )*NL
+*
+* Generate the vector X.
+*
+ TRANSL = HALF
+ CALL SMAKE( 'GE', ' ', ' ', 1, NL, X, 1, XX,
+ $ ABS( INCX ), 0, NL - 1, RESET, TRANSL )
+ IF( NL.GT.1 )THEN
+ X( NL/2 ) = ZERO
+ XX( 1 + ABS( INCX )*( NL/2 - 1 ) ) = ZERO
+ END IF
+*
+ DO 70 IY = 1, NINC
+ INCY = INC( IY )
+ LY = ABS( INCY )*ML
+*
+ DO 60 IA = 1, NALF
+ ALPHA = ALF( IA )
+*
+ DO 50 IB = 1, NBET
+ BETA = BET( IB )
+*
+* Generate the vector Y.
+*
+ TRANSL = ZERO
+ CALL SMAKE( 'GE', ' ', ' ', 1, ML, Y, 1,
+ $ YY, ABS( INCY ), 0, ML - 1,
+ $ RESET, TRANSL )
+*
+ NC = NC + 1
+*
+* Save every datum before calling the
+* subroutine.
+*
+ TRANSS = TRANS
+ MS = M
+ NS = N
+ KLS = KL
+ KUS = KU
+ ALS = ALPHA
+ DO 10 I = 1, LAA
+ AS( I ) = AA( I )
+ 10 CONTINUE
+ LDAS = LDA
+ DO 20 I = 1, LX
+ XS( I ) = XX( I )
+ 20 CONTINUE
+ INCXS = INCX
+ BLS = BETA
+ DO 30 I = 1, LY
+ YS( I ) = YY( I )
+ 30 CONTINUE
+ INCYS = INCY
+*
+* Call the subroutine.
+*
+ IF( FULL )THEN
+ IF( TRACE )
+ $ WRITE( NTRA, FMT = 9994 )NC, SNAME,
+ $ TRANS, M, N, ALPHA, LDA, INCX, BETA,
+ $ INCY
+ IF( REWI )
+ $ REWIND NTRA
+ CALL SGEMV( TRANS, M, N, ALPHA, AA,
+ $ LDA, XX, INCX, BETA, YY,
+ $ INCY )
+ ELSE IF( BANDED )THEN
+ IF( TRACE )
+ $ WRITE( NTRA, FMT = 9995 )NC, SNAME,
+ $ TRANS, M, N, KL, KU, ALPHA, LDA,
+ $ INCX, BETA, INCY
+ IF( REWI )
+ $ REWIND NTRA
+ CALL SGBMV( TRANS, M, N, KL, KU, ALPHA,
+ $ AA, LDA, XX, INCX, BETA,
+ $ YY, INCY )
+ END IF
+*
+* Check if error-exit was taken incorrectly.
+*
+ IF( .NOT.OK )THEN
+ WRITE( NOUT, FMT = 9993 )
+ FATAL = .TRUE.
+ GO TO 130
+ END IF
+*
+* See what data changed inside subroutines.
+*
+ ISAME( 1 ) = TRANS.EQ.TRANSS
+ ISAME( 2 ) = MS.EQ.M
+ ISAME( 3 ) = NS.EQ.N
+ IF( FULL )THEN
+ ISAME( 4 ) = ALS.EQ.ALPHA
+ ISAME( 5 ) = LSE( AS, AA, LAA )
+ ISAME( 6 ) = LDAS.EQ.LDA
+ ISAME( 7 ) = LSE( XS, XX, LX )
+ ISAME( 8 ) = INCXS.EQ.INCX
+ ISAME( 9 ) = BLS.EQ.BETA
+ IF( NULL )THEN
+ ISAME( 10 ) = LSE( YS, YY, LY )
+ ELSE
+ ISAME( 10 ) = LSERES( 'GE', ' ', 1,
+ $ ML, YS, YY,
+ $ ABS( INCY ) )
+ END IF
+ ISAME( 11 ) = INCYS.EQ.INCY
+ ELSE IF( BANDED )THEN
+ ISAME( 4 ) = KLS.EQ.KL
+ ISAME( 5 ) = KUS.EQ.KU
+ ISAME( 6 ) = ALS.EQ.ALPHA
+ ISAME( 7 ) = LSE( AS, AA, LAA )
+ ISAME( 8 ) = LDAS.EQ.LDA
+ ISAME( 9 ) = LSE( XS, XX, LX )
+ ISAME( 10 ) = INCXS.EQ.INCX
+ ISAME( 11 ) = BLS.EQ.BETA
+ IF( NULL )THEN
+ ISAME( 12 ) = LSE( YS, YY, LY )
+ ELSE
+ ISAME( 12 ) = LSERES( 'GE', ' ', 1,
+ $ ML, YS, YY,
+ $ ABS( INCY ) )
+ END IF
+ ISAME( 13 ) = INCYS.EQ.INCY
+ END IF
+*
+* If data was incorrectly changed, report
+* and return.
+*
+ SAME = .TRUE.
+ DO 40 I = 1, NARGS
+ SAME = SAME.AND.ISAME( I )
+ IF( .NOT.ISAME( I ) )
+ $ WRITE( NOUT, FMT = 9998 )I
+ 40 CONTINUE
+ IF( .NOT.SAME )THEN
+ FATAL = .TRUE.
+ GO TO 130
+ END IF
+*
+ IF( .NOT.NULL )THEN
+*
+* Check the result.
+*
+ CALL SMVCH( TRANS, M, N, ALPHA, A,
+ $ NMAX, X, INCX, BETA, Y,
+ $ INCY, YT, G, YY, EPS, ERR,
+ $ FATAL, NOUT, .TRUE. )
+ ERRMAX = MAX( ERRMAX, ERR )
+* If got really bad answer, report and
+* return.
+ IF( FATAL )
+ $ GO TO 130
+ ELSE
+* Avoid repeating tests with M.le.0 or
+* N.le.0.
+ GO TO 110
+ END IF
+*
+ 50 CONTINUE
+*
+ 60 CONTINUE
+*
+ 70 CONTINUE
+*
+ 80 CONTINUE
+*
+ 90 CONTINUE
+*
+ 100 CONTINUE
+*
+ 110 CONTINUE
+*
+ 120 CONTINUE
+*
+* Report result.
+*
+ IF( ERRMAX.LT.THRESH )THEN
+ WRITE( NOUT, FMT = 9999 )SNAME, NC
+ ELSE
+ WRITE( NOUT, FMT = 9997 )SNAME, NC, ERRMAX
+ END IF
+ GO TO 140
+*
+ 130 CONTINUE
+ WRITE( NOUT, FMT = 9996 )SNAME
+ IF( FULL )THEN
+ WRITE( NOUT, FMT = 9994 )NC, SNAME, TRANS, M, N, ALPHA, LDA,
+ $ INCX, BETA, INCY
+ ELSE IF( BANDED )THEN
+ WRITE( NOUT, FMT = 9995 )NC, SNAME, TRANS, M, N, KL, KU,
+ $ ALPHA, LDA, INCX, BETA, INCY
+ END IF
+*
+ 140 CONTINUE
+ RETURN
+*
+ 9999 FORMAT( ' ', A6, ' PASSED THE COMPUTATIONAL TESTS (', I6, ' CALL',
+ $ 'S)' )
+ 9998 FORMAT( ' ******* FATAL ERROR - PARAMETER NUMBER ', I2, ' WAS CH',
+ $ 'ANGED INCORRECTLY *******' )
+ 9997 FORMAT( ' ', A6, ' COMPLETED THE COMPUTATIONAL TESTS (', I6, ' C',
+ $ 'ALLS)', /' ******* BUT WITH MAXIMUM TEST RATIO', F8.2,
+ $ ' - SUSPECT *******' )
+ 9996 FORMAT( ' ******* ', A6, ' FAILED ON CALL NUMBER:' )
+ 9995 FORMAT( 1X, I6, ': ', A6, '(''', A1, ''',', 4( I3, ',' ), F4.1,
+ $ ', A,', I3, ', X,', I2, ',', F4.1, ', Y,', I2, ') .' )
+ 9994 FORMAT( 1X, I6, ': ', A6, '(''', A1, ''',', 2( I3, ',' ), F4.1,
+ $ ', A,', I3, ', X,', I2, ',', F4.1, ', Y,', I2,
+ $ ') .' )
+ 9993 FORMAT( ' ******* FATAL ERROR - ERROR-EXIT TAKEN ON VALID CALL *',
+ $ '******' )
+*
+* End of SCHK1.
+*
+ END
+ SUBROUTINE SCHK2( SNAME, EPS, THRESH, NOUT, NTRA, TRACE, REWI,
+ $ FATAL, NIDIM, IDIM, NKB, KB, NALF, ALF, NBET,
+ $ BET, NINC, INC, NMAX, INCMAX, A, AA, AS, X, XX,
+ $ XS, Y, YY, YS, YT, G )
+*
+* Tests SSYMV, SSBMV and SSPMV.
+*
+* Auxiliary routine for test program for Level 2 Blas.
+*
+* -- Written on 10-August-1987.
+* Richard Hanson, Sandia National Labs.
+* Jeremy Du Croz, NAG Central Office.
+*
+* .. Parameters ..
+ REAL ZERO, HALF
+ PARAMETER ( ZERO = 0.0, HALF = 0.5 )
+* .. Scalar Arguments ..
+ REAL EPS, THRESH
+ INTEGER INCMAX, NALF, NBET, NIDIM, NINC, NKB, NMAX,
+ $ NOUT, NTRA
+ LOGICAL FATAL, REWI, TRACE
+ CHARACTER*6 SNAME
+* .. Array Arguments ..
+ REAL A( NMAX, NMAX ), AA( NMAX*NMAX ), ALF( NALF ),
+ $ AS( NMAX*NMAX ), BET( NBET ), G( NMAX ),
+ $ X( NMAX ), XS( NMAX*INCMAX ),
+ $ XX( NMAX*INCMAX ), Y( NMAX ),
+ $ YS( NMAX*INCMAX ), YT( NMAX ),
+ $ YY( NMAX*INCMAX )
+ INTEGER IDIM( NIDIM ), INC( NINC ), KB( NKB )
+* .. Local Scalars ..
+ REAL ALPHA, ALS, BETA, BLS, ERR, ERRMAX, TRANSL
+ INTEGER I, IA, IB, IC, IK, IN, INCX, INCXS, INCY,
+ $ INCYS, IX, IY, K, KS, LAA, LDA, LDAS, LX, LY,
+ $ N, NARGS, NC, NK, NS
+ LOGICAL BANDED, FULL, NULL, PACKED, RESET, SAME
+ CHARACTER*1 UPLO, UPLOS
+ CHARACTER*2 ICH
+* .. Local Arrays ..
+ LOGICAL ISAME( 13 )
+* .. External Functions ..
+ LOGICAL LSE, LSERES
+ EXTERNAL LSE, LSERES
+* .. External Subroutines ..
+ EXTERNAL SMAKE, SMVCH, SSBMV, SSPMV, SSYMV
+* .. Intrinsic Functions ..
+ INTRINSIC ABS, MAX
+* .. Scalars in Common ..
+ INTEGER INFOT, NOUTC
+ LOGICAL LERR, OK
+* .. Common blocks ..
+ COMMON /INFOC/INFOT, NOUTC, OK, LERR
+* .. Data statements ..
+ DATA ICH/'UL'/
+* .. Executable Statements ..
+ FULL = SNAME( 3: 3 ).EQ.'Y'
+ BANDED = SNAME( 3: 3 ).EQ.'B'
+ PACKED = SNAME( 3: 3 ).EQ.'P'
+* Define the number of arguments.
+ IF( FULL )THEN
+ NARGS = 10
+ ELSE IF( BANDED )THEN
+ NARGS = 11
+ ELSE IF( PACKED )THEN
+ NARGS = 9
+ END IF
+*
+ NC = 0
+ RESET = .TRUE.
+ ERRMAX = ZERO
+*
+ DO 110 IN = 1, NIDIM
+ N = IDIM( IN )
+*
+ IF( BANDED )THEN
+ NK = NKB
+ ELSE
+ NK = 1
+ END IF
+ DO 100 IK = 1, NK
+ IF( BANDED )THEN
+ K = KB( IK )
+ ELSE
+ K = N - 1
+ END IF
+* Set LDA to 1 more than minimum value if room.
+ IF( BANDED )THEN
+ LDA = K + 1
+ ELSE
+ LDA = N
+ END IF
+ IF( LDA.LT.NMAX )
+ $ LDA = LDA + 1
+* Skip tests if not enough room.
+ IF( LDA.GT.NMAX )
+ $ GO TO 100
+ IF( PACKED )THEN
+ LAA = ( N*( N + 1 ) )/2
+ ELSE
+ LAA = LDA*N
+ END IF
+ NULL = N.LE.0
+*
+ DO 90 IC = 1, 2
+ UPLO = ICH( IC: IC )
+*
+* Generate the matrix A.
+*
+ TRANSL = ZERO
+ CALL SMAKE( SNAME( 2: 3 ), UPLO, ' ', N, N, A, NMAX, AA,
+ $ LDA, K, K, RESET, TRANSL )
+*
+ DO 80 IX = 1, NINC
+ INCX = INC( IX )
+ LX = ABS( INCX )*N
+*
+* Generate the vector X.
+*
+ TRANSL = HALF
+ CALL SMAKE( 'GE', ' ', ' ', 1, N, X, 1, XX,
+ $ ABS( INCX ), 0, N - 1, RESET, TRANSL )
+ IF( N.GT.1 )THEN
+ X( N/2 ) = ZERO
+ XX( 1 + ABS( INCX )*( N/2 - 1 ) ) = ZERO
+ END IF
+*
+ DO 70 IY = 1, NINC
+ INCY = INC( IY )
+ LY = ABS( INCY )*N
+*
+ DO 60 IA = 1, NALF
+ ALPHA = ALF( IA )
+*
+ DO 50 IB = 1, NBET
+ BETA = BET( IB )
+*
+* Generate the vector Y.
+*
+ TRANSL = ZERO
+ CALL SMAKE( 'GE', ' ', ' ', 1, N, Y, 1, YY,
+ $ ABS( INCY ), 0, N - 1, RESET,
+ $ TRANSL )
+*
+ NC = NC + 1
+*
+* Save every datum before calling the
+* subroutine.
+*
+ UPLOS = UPLO
+ NS = N
+ KS = K
+ ALS = ALPHA
+ DO 10 I = 1, LAA
+ AS( I ) = AA( I )
+ 10 CONTINUE
+ LDAS = LDA
+ DO 20 I = 1, LX
+ XS( I ) = XX( I )
+ 20 CONTINUE
+ INCXS = INCX
+ BLS = BETA
+ DO 30 I = 1, LY
+ YS( I ) = YY( I )
+ 30 CONTINUE
+ INCYS = INCY
+*
+* Call the subroutine.
+*
+ IF( FULL )THEN
+ IF( TRACE )
+ $ WRITE( NTRA, FMT = 9993 )NC, SNAME,
+ $ UPLO, N, ALPHA, LDA, INCX, BETA, INCY
+ IF( REWI )
+ $ REWIND NTRA
+ CALL SSYMV( UPLO, N, ALPHA, AA, LDA, XX,
+ $ INCX, BETA, YY, INCY )
+ ELSE IF( BANDED )THEN
+ IF( TRACE )
+ $ WRITE( NTRA, FMT = 9994 )NC, SNAME,
+ $ UPLO, N, K, ALPHA, LDA, INCX, BETA,
+ $ INCY
+ IF( REWI )
+ $ REWIND NTRA
+ CALL SSBMV( UPLO, N, K, ALPHA, AA, LDA,
+ $ XX, INCX, BETA, YY, INCY )
+ ELSE IF( PACKED )THEN
+ IF( TRACE )
+ $ WRITE( NTRA, FMT = 9995 )NC, SNAME,
+ $ UPLO, N, ALPHA, INCX, BETA, INCY
+ IF( REWI )
+ $ REWIND NTRA
+ CALL SSPMV( UPLO, N, ALPHA, AA, XX, INCX,
+ $ BETA, YY, INCY )
+ END IF
+*
+* Check if error-exit was taken incorrectly.
+*
+ IF( .NOT.OK )THEN
+ WRITE( NOUT, FMT = 9992 )
+ FATAL = .TRUE.
+ GO TO 120
+ END IF
+*
+* See what data changed inside subroutines.
+*
+ ISAME( 1 ) = UPLO.EQ.UPLOS
+ ISAME( 2 ) = NS.EQ.N
+ IF( FULL )THEN
+ ISAME( 3 ) = ALS.EQ.ALPHA
+ ISAME( 4 ) = LSE( AS, AA, LAA )
+ ISAME( 5 ) = LDAS.EQ.LDA
+ ISAME( 6 ) = LSE( XS, XX, LX )
+ ISAME( 7 ) = INCXS.EQ.INCX
+ ISAME( 8 ) = BLS.EQ.BETA
+ IF( NULL )THEN
+ ISAME( 9 ) = LSE( YS, YY, LY )
+ ELSE
+ ISAME( 9 ) = LSERES( 'GE', ' ', 1, N,
+ $ YS, YY, ABS( INCY ) )
+ END IF
+ ISAME( 10 ) = INCYS.EQ.INCY
+ ELSE IF( BANDED )THEN
+ ISAME( 3 ) = KS.EQ.K
+ ISAME( 4 ) = ALS.EQ.ALPHA
+ ISAME( 5 ) = LSE( AS, AA, LAA )
+ ISAME( 6 ) = LDAS.EQ.LDA
+ ISAME( 7 ) = LSE( XS, XX, LX )
+ ISAME( 8 ) = INCXS.EQ.INCX
+ ISAME( 9 ) = BLS.EQ.BETA
+ IF( NULL )THEN
+ ISAME( 10 ) = LSE( YS, YY, LY )
+ ELSE
+ ISAME( 10 ) = LSERES( 'GE', ' ', 1, N,
+ $ YS, YY, ABS( INCY ) )
+ END IF
+ ISAME( 11 ) = INCYS.EQ.INCY
+ ELSE IF( PACKED )THEN
+ ISAME( 3 ) = ALS.EQ.ALPHA
+ ISAME( 4 ) = LSE( AS, AA, LAA )
+ ISAME( 5 ) = LSE( XS, XX, LX )
+ ISAME( 6 ) = INCXS.EQ.INCX
+ ISAME( 7 ) = BLS.EQ.BETA
+ IF( NULL )THEN
+ ISAME( 8 ) = LSE( YS, YY, LY )
+ ELSE
+ ISAME( 8 ) = LSERES( 'GE', ' ', 1, N,
+ $ YS, YY, ABS( INCY ) )
+ END IF
+ ISAME( 9 ) = INCYS.EQ.INCY
+ END IF
+*
+* If data was incorrectly changed, report and
+* return.
+*
+ SAME = .TRUE.
+ DO 40 I = 1, NARGS
+ SAME = SAME.AND.ISAME( I )
+ IF( .NOT.ISAME( I ) )
+ $ WRITE( NOUT, FMT = 9998 )I
+ 40 CONTINUE
+ IF( .NOT.SAME )THEN
+ FATAL = .TRUE.
+ GO TO 120
+ END IF
+*
+ IF( .NOT.NULL )THEN
+*
+* Check the result.
+*
+ CALL SMVCH( 'N', N, N, ALPHA, A, NMAX, X,
+ $ INCX, BETA, Y, INCY, YT, G,
+ $ YY, EPS, ERR, FATAL, NOUT,
+ $ .TRUE. )
+ ERRMAX = MAX( ERRMAX, ERR )
+* If got really bad answer, report and
+* return.
+ IF( FATAL )
+ $ GO TO 120
+ ELSE
+* Avoid repeating tests with N.le.0
+ GO TO 110
+ END IF
+*
+ 50 CONTINUE
+*
+ 60 CONTINUE
+*
+ 70 CONTINUE
+*
+ 80 CONTINUE
+*
+ 90 CONTINUE
+*
+ 100 CONTINUE
+*
+ 110 CONTINUE
+*
+* Report result.
+*
+ IF( ERRMAX.LT.THRESH )THEN
+ WRITE( NOUT, FMT = 9999 )SNAME, NC
+ ELSE
+ WRITE( NOUT, FMT = 9997 )SNAME, NC, ERRMAX
+ END IF
+ GO TO 130
+*
+ 120 CONTINUE
+ WRITE( NOUT, FMT = 9996 )SNAME
+ IF( FULL )THEN
+ WRITE( NOUT, FMT = 9993 )NC, SNAME, UPLO, N, ALPHA, LDA, INCX,
+ $ BETA, INCY
+ ELSE IF( BANDED )THEN
+ WRITE( NOUT, FMT = 9994 )NC, SNAME, UPLO, N, K, ALPHA, LDA,
+ $ INCX, BETA, INCY
+ ELSE IF( PACKED )THEN
+ WRITE( NOUT, FMT = 9995 )NC, SNAME, UPLO, N, ALPHA, INCX,
+ $ BETA, INCY
+ END IF
+*
+ 130 CONTINUE
+ RETURN
+*
+ 9999 FORMAT( ' ', A6, ' PASSED THE COMPUTATIONAL TESTS (', I6, ' CALL',
+ $ 'S)' )
+ 9998 FORMAT( ' ******* FATAL ERROR - PARAMETER NUMBER ', I2, ' WAS CH',
+ $ 'ANGED INCORRECTLY *******' )
+ 9997 FORMAT( ' ', A6, ' COMPLETED THE COMPUTATIONAL TESTS (', I6, ' C',
+ $ 'ALLS)', /' ******* BUT WITH MAXIMUM TEST RATIO', F8.2,
+ $ ' - SUSPECT *******' )
+ 9996 FORMAT( ' ******* ', A6, ' FAILED ON CALL NUMBER:' )
+ 9995 FORMAT( 1X, I6, ': ', A6, '(''', A1, ''',', I3, ',', F4.1, ', AP',
+ $ ', X,', I2, ',', F4.1, ', Y,', I2, ') .' )
+ 9994 FORMAT( 1X, I6, ': ', A6, '(''', A1, ''',', 2( I3, ',' ), F4.1,
+ $ ', A,', I3, ', X,', I2, ',', F4.1, ', Y,', I2,
+ $ ') .' )
+ 9993 FORMAT( 1X, I6, ': ', A6, '(''', A1, ''',', I3, ',', F4.1, ', A,',
+ $ I3, ', X,', I2, ',', F4.1, ', Y,', I2, ') .' )
+ 9992 FORMAT( ' ******* FATAL ERROR - ERROR-EXIT TAKEN ON VALID CALL *',
+ $ '******' )
+*
+* End of SCHK2.
+*
+ END
+ SUBROUTINE SCHK3( SNAME, EPS, THRESH, NOUT, NTRA, TRACE, REWI,
+ $ FATAL, NIDIM, IDIM, NKB, KB, NINC, INC, NMAX,
+ $ INCMAX, A, AA, AS, X, XX, XS, XT, G, Z )
+*
+* Tests STRMV, STBMV, STPMV, STRSV, STBSV and STPSV.
+*
+* Auxiliary routine for test program for Level 2 Blas.
+*
+* -- Written on 10-August-1987.
+* Richard Hanson, Sandia National Labs.
+* Jeremy Du Croz, NAG Central Office.
+*
+* .. Parameters ..
+ REAL ZERO, HALF, ONE
+ PARAMETER ( ZERO = 0.0, HALF = 0.5, ONE = 1.0 )
+* .. Scalar Arguments ..
+ REAL EPS, THRESH
+ INTEGER INCMAX, NIDIM, NINC, NKB, NMAX, NOUT, NTRA
+ LOGICAL FATAL, REWI, TRACE
+ CHARACTER*6 SNAME
+* .. Array Arguments ..
+ REAL A( NMAX, NMAX ), AA( NMAX*NMAX ),
+ $ AS( NMAX*NMAX ), G( NMAX ), X( NMAX ),
+ $ XS( NMAX*INCMAX ), XT( NMAX ),
+ $ XX( NMAX*INCMAX ), Z( NMAX )
+ INTEGER IDIM( NIDIM ), INC( NINC ), KB( NKB )
+* .. Local Scalars ..
+ REAL ERR, ERRMAX, TRANSL
+ INTEGER I, ICD, ICT, ICU, IK, IN, INCX, INCXS, IX, K,
+ $ KS, LAA, LDA, LDAS, LX, N, NARGS, NC, NK, NS
+ LOGICAL BANDED, FULL, NULL, PACKED, RESET, SAME
+ CHARACTER*1 DIAG, DIAGS, TRANS, TRANSS, UPLO, UPLOS
+ CHARACTER*2 ICHD, ICHU
+ CHARACTER*3 ICHT
+* .. Local Arrays ..
+ LOGICAL ISAME( 13 )
+* .. External Functions ..
+ LOGICAL LSE, LSERES
+ EXTERNAL LSE, LSERES
+* .. External Subroutines ..
+ EXTERNAL SMAKE, SMVCH, STBMV, STBSV, STPMV, STPSV,
+ $ STRMV, STRSV
+* .. Intrinsic Functions ..
+ INTRINSIC ABS, MAX
+* .. Scalars in Common ..
+ INTEGER INFOT, NOUTC
+ LOGICAL LERR, OK
+* .. Common blocks ..
+ COMMON /INFOC/INFOT, NOUTC, OK, LERR
+* .. Data statements ..
+ DATA ICHU/'UL'/, ICHT/'NTC'/, ICHD/'UN'/
+* .. Executable Statements ..
+ FULL = SNAME( 3: 3 ).EQ.'R'
+ BANDED = SNAME( 3: 3 ).EQ.'B'
+ PACKED = SNAME( 3: 3 ).EQ.'P'
+* Define the number of arguments.
+ IF( FULL )THEN
+ NARGS = 8
+ ELSE IF( BANDED )THEN
+ NARGS = 9
+ ELSE IF( PACKED )THEN
+ NARGS = 7
+ END IF
+*
+ NC = 0
+ RESET = .TRUE.
+ ERRMAX = ZERO
+* Set up zero vector for SMVCH.
+ DO 10 I = 1, NMAX
+ Z( I ) = ZERO
+ 10 CONTINUE
+*
+ DO 110 IN = 1, NIDIM
+ N = IDIM( IN )
+*
+ IF( BANDED )THEN
+ NK = NKB
+ ELSE
+ NK = 1
+ END IF
+ DO 100 IK = 1, NK
+ IF( BANDED )THEN
+ K = KB( IK )
+ ELSE
+ K = N - 1
+ END IF
+* Set LDA to 1 more than minimum value if room.
+ IF( BANDED )THEN
+ LDA = K + 1
+ ELSE
+ LDA = N
+ END IF
+ IF( LDA.LT.NMAX )
+ $ LDA = LDA + 1
+* Skip tests if not enough room.
+ IF( LDA.GT.NMAX )
+ $ GO TO 100
+ IF( PACKED )THEN
+ LAA = ( N*( N + 1 ) )/2
+ ELSE
+ LAA = LDA*N
+ END IF
+ NULL = N.LE.0
+*
+ DO 90 ICU = 1, 2
+ UPLO = ICHU( ICU: ICU )
+*
+ DO 80 ICT = 1, 3
+ TRANS = ICHT( ICT: ICT )
+*
+ DO 70 ICD = 1, 2
+ DIAG = ICHD( ICD: ICD )
+*
+* Generate the matrix A.
+*
+ TRANSL = ZERO
+ CALL SMAKE( SNAME( 2: 3 ), UPLO, DIAG, N, N, A,
+ $ NMAX, AA, LDA, K, K, RESET, TRANSL )
+*
+ DO 60 IX = 1, NINC
+ INCX = INC( IX )
+ LX = ABS( INCX )*N
+*
+* Generate the vector X.
+*
+ TRANSL = HALF
+ CALL SMAKE( 'GE', ' ', ' ', 1, N, X, 1, XX,
+ $ ABS( INCX ), 0, N - 1, RESET,
+ $ TRANSL )
+ IF( N.GT.1 )THEN
+ X( N/2 ) = ZERO
+ XX( 1 + ABS( INCX )*( N/2 - 1 ) ) = ZERO
+ END IF
+*
+ NC = NC + 1
+*
+* Save every datum before calling the subroutine.
+*
+ UPLOS = UPLO
+ TRANSS = TRANS
+ DIAGS = DIAG
+ NS = N
+ KS = K
+ DO 20 I = 1, LAA
+ AS( I ) = AA( I )
+ 20 CONTINUE
+ LDAS = LDA
+ DO 30 I = 1, LX
+ XS( I ) = XX( I )
+ 30 CONTINUE
+ INCXS = INCX
+*
+* Call the subroutine.
+*
+ IF( SNAME( 4: 5 ).EQ.'MV' )THEN
+ IF( FULL )THEN
+ IF( TRACE )
+ $ WRITE( NTRA, FMT = 9993 )NC, SNAME,
+ $ UPLO, TRANS, DIAG, N, LDA, INCX
+ IF( REWI )
+ $ REWIND NTRA
+ CALL STRMV( UPLO, TRANS, DIAG, N, AA, LDA,
+ $ XX, INCX )
+ ELSE IF( BANDED )THEN
+ IF( TRACE )
+ $ WRITE( NTRA, FMT = 9994 )NC, SNAME,
+ $ UPLO, TRANS, DIAG, N, K, LDA, INCX
+ IF( REWI )
+ $ REWIND NTRA
+ CALL STBMV( UPLO, TRANS, DIAG, N, K, AA,
+ $ LDA, XX, INCX )
+ ELSE IF( PACKED )THEN
+ IF( TRACE )
+ $ WRITE( NTRA, FMT = 9995 )NC, SNAME,
+ $ UPLO, TRANS, DIAG, N, INCX
+ IF( REWI )
+ $ REWIND NTRA
+ CALL STPMV( UPLO, TRANS, DIAG, N, AA, XX,
+ $ INCX )
+ END IF
+ ELSE IF( SNAME( 4: 5 ).EQ.'SV' )THEN
+ IF( FULL )THEN
+ IF( TRACE )
+ $ WRITE( NTRA, FMT = 9993 )NC, SNAME,
+ $ UPLO, TRANS, DIAG, N, LDA, INCX
+ IF( REWI )
+ $ REWIND NTRA
+ CALL STRSV( UPLO, TRANS, DIAG, N, AA, LDA,
+ $ XX, INCX )
+ ELSE IF( BANDED )THEN
+ IF( TRACE )
+ $ WRITE( NTRA, FMT = 9994 )NC, SNAME,
+ $ UPLO, TRANS, DIAG, N, K, LDA, INCX
+ IF( REWI )
+ $ REWIND NTRA
+ CALL STBSV( UPLO, TRANS, DIAG, N, K, AA,
+ $ LDA, XX, INCX )
+ ELSE IF( PACKED )THEN
+ IF( TRACE )
+ $ WRITE( NTRA, FMT = 9995 )NC, SNAME,
+ $ UPLO, TRANS, DIAG, N, INCX
+ IF( REWI )
+ $ REWIND NTRA
+ CALL STPSV( UPLO, TRANS, DIAG, N, AA, XX,
+ $ INCX )
+ END IF
+ END IF
+*
+* Check if error-exit was taken incorrectly.
+*
+ IF( .NOT.OK )THEN
+ WRITE( NOUT, FMT = 9992 )
+ FATAL = .TRUE.
+ GO TO 120
+ END IF
+*
+* See what data changed inside subroutines.
+*
+ ISAME( 1 ) = UPLO.EQ.UPLOS
+ ISAME( 2 ) = TRANS.EQ.TRANSS
+ ISAME( 3 ) = DIAG.EQ.DIAGS
+ ISAME( 4 ) = NS.EQ.N
+ IF( FULL )THEN
+ ISAME( 5 ) = LSE( AS, AA, LAA )
+ ISAME( 6 ) = LDAS.EQ.LDA
+ IF( NULL )THEN
+ ISAME( 7 ) = LSE( XS, XX, LX )
+ ELSE
+ ISAME( 7 ) = LSERES( 'GE', ' ', 1, N, XS,
+ $ XX, ABS( INCX ) )
+ END IF
+ ISAME( 8 ) = INCXS.EQ.INCX
+ ELSE IF( BANDED )THEN
+ ISAME( 5 ) = KS.EQ.K
+ ISAME( 6 ) = LSE( AS, AA, LAA )
+ ISAME( 7 ) = LDAS.EQ.LDA
+ IF( NULL )THEN
+ ISAME( 8 ) = LSE( XS, XX, LX )
+ ELSE
+ ISAME( 8 ) = LSERES( 'GE', ' ', 1, N, XS,
+ $ XX, ABS( INCX ) )
+ END IF
+ ISAME( 9 ) = INCXS.EQ.INCX
+ ELSE IF( PACKED )THEN
+ ISAME( 5 ) = LSE( AS, AA, LAA )
+ IF( NULL )THEN
+ ISAME( 6 ) = LSE( XS, XX, LX )
+ ELSE
+ ISAME( 6 ) = LSERES( 'GE', ' ', 1, N, XS,
+ $ XX, ABS( INCX ) )
+ END IF
+ ISAME( 7 ) = INCXS.EQ.INCX
+ END IF
+*
+* If data was incorrectly changed, report and
+* return.
+*
+ SAME = .TRUE.
+ DO 40 I = 1, NARGS
+ SAME = SAME.AND.ISAME( I )
+ IF( .NOT.ISAME( I ) )
+ $ WRITE( NOUT, FMT = 9998 )I
+ 40 CONTINUE
+ IF( .NOT.SAME )THEN
+ FATAL = .TRUE.
+ GO TO 120
+ END IF
+*
+ IF( .NOT.NULL )THEN
+ IF( SNAME( 4: 5 ).EQ.'MV' )THEN
+*
+* Check the result.
+*
+ CALL SMVCH( TRANS, N, N, ONE, A, NMAX, X,
+ $ INCX, ZERO, Z, INCX, XT, G,
+ $ XX, EPS, ERR, FATAL, NOUT,
+ $ .TRUE. )
+ ELSE IF( SNAME( 4: 5 ).EQ.'SV' )THEN
+*
+* Compute approximation to original vector.
+*
+ DO 50 I = 1, N
+ Z( I ) = XX( 1 + ( I - 1 )*
+ $ ABS( INCX ) )
+ XX( 1 + ( I - 1 )*ABS( INCX ) )
+ $ = X( I )
+ 50 CONTINUE
+ CALL SMVCH( TRANS, N, N, ONE, A, NMAX, Z,
+ $ INCX, ZERO, X, INCX, XT, G,
+ $ XX, EPS, ERR, FATAL, NOUT,
+ $ .FALSE. )
+ END IF
+ ERRMAX = MAX( ERRMAX, ERR )
+* If got really bad answer, report and return.
+ IF( FATAL )
+ $ GO TO 120
+ ELSE
+* Avoid repeating tests with N.le.0.
+ GO TO 110
+ END IF
+*
+ 60 CONTINUE
+*
+ 70 CONTINUE
+*
+ 80 CONTINUE
+*
+ 90 CONTINUE
+*
+ 100 CONTINUE
+*
+ 110 CONTINUE
+*
+* Report result.
+*
+ IF( ERRMAX.LT.THRESH )THEN
+ WRITE( NOUT, FMT = 9999 )SNAME, NC
+ ELSE
+ WRITE( NOUT, FMT = 9997 )SNAME, NC, ERRMAX
+ END IF
+ GO TO 130
+*
+ 120 CONTINUE
+ WRITE( NOUT, FMT = 9996 )SNAME
+ IF( FULL )THEN
+ WRITE( NOUT, FMT = 9993 )NC, SNAME, UPLO, TRANS, DIAG, N, LDA,
+ $ INCX
+ ELSE IF( BANDED )THEN
+ WRITE( NOUT, FMT = 9994 )NC, SNAME, UPLO, TRANS, DIAG, N, K,
+ $ LDA, INCX
+ ELSE IF( PACKED )THEN
+ WRITE( NOUT, FMT = 9995 )NC, SNAME, UPLO, TRANS, DIAG, N, INCX
+ END IF
+*
+ 130 CONTINUE
+ RETURN
+*
+ 9999 FORMAT( ' ', A6, ' PASSED THE COMPUTATIONAL TESTS (', I6, ' CALL',
+ $ 'S)' )
+ 9998 FORMAT( ' ******* FATAL ERROR - PARAMETER NUMBER ', I2, ' WAS CH',
+ $ 'ANGED INCORRECTLY *******' )
+ 9997 FORMAT( ' ', A6, ' COMPLETED THE COMPUTATIONAL TESTS (', I6, ' C',
+ $ 'ALLS)', /' ******* BUT WITH MAXIMUM TEST RATIO', F8.2,
+ $ ' - SUSPECT *******' )
+ 9996 FORMAT( ' ******* ', A6, ' FAILED ON CALL NUMBER:' )
+ 9995 FORMAT( 1X, I6, ': ', A6, '(', 3( '''', A1, ''',' ), I3, ', AP, ',
+ $ 'X,', I2, ') .' )
+ 9994 FORMAT( 1X, I6, ': ', A6, '(', 3( '''', A1, ''',' ), 2( I3, ',' ),
+ $ ' A,', I3, ', X,', I2, ') .' )
+ 9993 FORMAT( 1X, I6, ': ', A6, '(', 3( '''', A1, ''',' ), I3, ', A,',
+ $ I3, ', X,', I2, ') .' )
+ 9992 FORMAT( ' ******* FATAL ERROR - ERROR-EXIT TAKEN ON VALID CALL *',
+ $ '******' )
+*
+* End of SCHK3.
+*
+ END
+ SUBROUTINE SCHK4( SNAME, EPS, THRESH, NOUT, NTRA, TRACE, REWI,
+ $ FATAL, NIDIM, IDIM, NALF, ALF, NINC, INC, NMAX,
+ $ INCMAX, A, AA, AS, X, XX, XS, Y, YY, YS, YT, G,
+ $ Z )
+*
+* Tests SGER.
+*
+* Auxiliary routine for test program for Level 2 Blas.
+*
+* -- Written on 10-August-1987.
+* Richard Hanson, Sandia National Labs.
+* Jeremy Du Croz, NAG Central Office.
+*
+* .. Parameters ..
+ REAL ZERO, HALF, ONE
+ PARAMETER ( ZERO = 0.0, HALF = 0.5, ONE = 1.0 )
+* .. Scalar Arguments ..
+ REAL EPS, THRESH
+ INTEGER INCMAX, NALF, NIDIM, NINC, NMAX, NOUT, NTRA
+ LOGICAL FATAL, REWI, TRACE
+ CHARACTER*6 SNAME
+* .. Array Arguments ..
+ REAL A( NMAX, NMAX ), AA( NMAX*NMAX ), ALF( NALF ),
+ $ AS( NMAX*NMAX ), G( NMAX ), X( NMAX ),
+ $ XS( NMAX*INCMAX ), XX( NMAX*INCMAX ),
+ $ Y( NMAX ), YS( NMAX*INCMAX ), YT( NMAX ),
+ $ YY( NMAX*INCMAX ), Z( NMAX )
+ INTEGER IDIM( NIDIM ), INC( NINC )
+* .. Local Scalars ..
+ REAL ALPHA, ALS, ERR, ERRMAX, TRANSL
+ INTEGER I, IA, IM, IN, INCX, INCXS, INCY, INCYS, IX,
+ $ IY, J, LAA, LDA, LDAS, LX, LY, M, MS, N, NARGS,
+ $ NC, ND, NS
+ LOGICAL NULL, RESET, SAME
+* .. Local Arrays ..
+ REAL W( 1 )
+ LOGICAL ISAME( 13 )
+* .. External Functions ..
+ LOGICAL LSE, LSERES
+ EXTERNAL LSE, LSERES
+* .. External Subroutines ..
+ EXTERNAL SGER, SMAKE, SMVCH
+* .. Intrinsic Functions ..
+ INTRINSIC ABS, MAX, MIN
+* .. Scalars in Common ..
+ INTEGER INFOT, NOUTC
+ LOGICAL LERR, OK
+* .. Common blocks ..
+ COMMON /INFOC/INFOT, NOUTC, OK, LERR
+* .. Executable Statements ..
+* Define the number of arguments.
+ NARGS = 9
+*
+ NC = 0
+ RESET = .TRUE.
+ ERRMAX = ZERO
+*
+ DO 120 IN = 1, NIDIM
+ N = IDIM( IN )
+ ND = N/2 + 1
+*
+ DO 110 IM = 1, 2
+ IF( IM.EQ.1 )
+ $ M = MAX( N - ND, 0 )
+ IF( IM.EQ.2 )
+ $ M = MIN( N + ND, NMAX )
+*
+* Set LDA to 1 more than minimum value if room.
+ LDA = M
+ IF( LDA.LT.NMAX )
+ $ LDA = LDA + 1
+* Skip tests if not enough room.
+ IF( LDA.GT.NMAX )
+ $ GO TO 110
+ LAA = LDA*N
+ NULL = N.LE.0.OR.M.LE.0
+*
+ DO 100 IX = 1, NINC
+ INCX = INC( IX )
+ LX = ABS( INCX )*M
+*
+* Generate the vector X.
+*
+ TRANSL = HALF
+ CALL SMAKE( 'GE', ' ', ' ', 1, M, X, 1, XX, ABS( INCX ),
+ $ 0, M - 1, RESET, TRANSL )
+ IF( M.GT.1 )THEN
+ X( M/2 ) = ZERO
+ XX( 1 + ABS( INCX )*( M/2 - 1 ) ) = ZERO
+ END IF
+*
+ DO 90 IY = 1, NINC
+ INCY = INC( IY )
+ LY = ABS( INCY )*N
+*
+* Generate the vector Y.
+*
+ TRANSL = ZERO
+ CALL SMAKE( 'GE', ' ', ' ', 1, N, Y, 1, YY,
+ $ ABS( INCY ), 0, N - 1, RESET, TRANSL )
+ IF( N.GT.1 )THEN
+ Y( N/2 ) = ZERO
+ YY( 1 + ABS( INCY )*( N/2 - 1 ) ) = ZERO
+ END IF
+*
+ DO 80 IA = 1, NALF
+ ALPHA = ALF( IA )
+*
+* Generate the matrix A.
+*
+ TRANSL = ZERO
+ CALL SMAKE( SNAME( 2: 3 ), ' ', ' ', M, N, A, NMAX,
+ $ AA, LDA, M - 1, N - 1, RESET, TRANSL )
+*
+ NC = NC + 1
+*
+* Save every datum before calling the subroutine.
+*
+ MS = M
+ NS = N
+ ALS = ALPHA
+ DO 10 I = 1, LAA
+ AS( I ) = AA( I )
+ 10 CONTINUE
+ LDAS = LDA
+ DO 20 I = 1, LX
+ XS( I ) = XX( I )
+ 20 CONTINUE
+ INCXS = INCX
+ DO 30 I = 1, LY
+ YS( I ) = YY( I )
+ 30 CONTINUE
+ INCYS = INCY
+*
+* Call the subroutine.
+*
+ IF( TRACE )
+ $ WRITE( NTRA, FMT = 9994 )NC, SNAME, M, N,
+ $ ALPHA, INCX, INCY, LDA
+ IF( REWI )
+ $ REWIND NTRA
+ CALL SGER( M, N, ALPHA, XX, INCX, YY, INCY, AA,
+ $ LDA )
+*
+* Check if error-exit was taken incorrectly.
+*
+ IF( .NOT.OK )THEN
+ WRITE( NOUT, FMT = 9993 )
+ FATAL = .TRUE.
+ GO TO 140
+ END IF
+*
+* See what data changed inside subroutine.
+*
+ ISAME( 1 ) = MS.EQ.M
+ ISAME( 2 ) = NS.EQ.N
+ ISAME( 3 ) = ALS.EQ.ALPHA
+ ISAME( 4 ) = LSE( XS, XX, LX )
+ ISAME( 5 ) = INCXS.EQ.INCX
+ ISAME( 6 ) = LSE( YS, YY, LY )
+ ISAME( 7 ) = INCYS.EQ.INCY
+ IF( NULL )THEN
+ ISAME( 8 ) = LSE( AS, AA, LAA )
+ ELSE
+ ISAME( 8 ) = LSERES( 'GE', ' ', M, N, AS, AA,
+ $ LDA )
+ END IF
+ ISAME( 9 ) = LDAS.EQ.LDA
+*
+* If data was incorrectly changed, report and return.
+*
+ SAME = .TRUE.
+ DO 40 I = 1, NARGS
+ SAME = SAME.AND.ISAME( I )
+ IF( .NOT.ISAME( I ) )
+ $ WRITE( NOUT, FMT = 9998 )I
+ 40 CONTINUE
+ IF( .NOT.SAME )THEN
+ FATAL = .TRUE.
+ GO TO 140
+ END IF
+*
+ IF( .NOT.NULL )THEN
+*
+* Check the result column by column.
+*
+ IF( INCX.GT.0 )THEN
+ DO 50 I = 1, M
+ Z( I ) = X( I )
+ 50 CONTINUE
+ ELSE
+ DO 60 I = 1, M
+ Z( I ) = X( M - I + 1 )
+ 60 CONTINUE
+ END IF
+ DO 70 J = 1, N
+ IF( INCY.GT.0 )THEN
+ W( 1 ) = Y( J )
+ ELSE
+ W( 1 ) = Y( N - J + 1 )
+ END IF
+ CALL SMVCH( 'N', M, 1, ALPHA, Z, NMAX, W, 1,
+ $ ONE, A( 1, J ), 1, YT, G,
+ $ AA( 1 + ( J - 1 )*LDA ), EPS,
+ $ ERR, FATAL, NOUT, .TRUE. )
+ ERRMAX = MAX( ERRMAX, ERR )
+* If got really bad answer, report and return.
+ IF( FATAL )
+ $ GO TO 130
+ 70 CONTINUE
+ ELSE
+* Avoid repeating tests with M.le.0 or N.le.0.
+ GO TO 110
+ END IF
+*
+ 80 CONTINUE
+*
+ 90 CONTINUE
+*
+ 100 CONTINUE
+*
+ 110 CONTINUE
+*
+ 120 CONTINUE
+*
+* Report result.
+*
+ IF( ERRMAX.LT.THRESH )THEN
+ WRITE( NOUT, FMT = 9999 )SNAME, NC
+ ELSE
+ WRITE( NOUT, FMT = 9997 )SNAME, NC, ERRMAX
+ END IF
+ GO TO 150
+*
+ 130 CONTINUE
+ WRITE( NOUT, FMT = 9995 )J
+*
+ 140 CONTINUE
+ WRITE( NOUT, FMT = 9996 )SNAME
+ WRITE( NOUT, FMT = 9994 )NC, SNAME, M, N, ALPHA, INCX, INCY, LDA
+*
+ 150 CONTINUE
+ RETURN
+*
+ 9999 FORMAT( ' ', A6, ' PASSED THE COMPUTATIONAL TESTS (', I6, ' CALL',
+ $ 'S)' )
+ 9998 FORMAT( ' ******* FATAL ERROR - PARAMETER NUMBER ', I2, ' WAS CH',
+ $ 'ANGED INCORRECTLY *******' )
+ 9997 FORMAT( ' ', A6, ' COMPLETED THE COMPUTATIONAL TESTS (', I6, ' C',
+ $ 'ALLS)', /' ******* BUT WITH MAXIMUM TEST RATIO', F8.2,
+ $ ' - SUSPECT *******' )
+ 9996 FORMAT( ' ******* ', A6, ' FAILED ON CALL NUMBER:' )
+ 9995 FORMAT( ' THESE ARE THE RESULTS FOR COLUMN ', I3 )
+ 9994 FORMAT( 1X, I6, ': ', A6, '(', 2( I3, ',' ), F4.1, ', X,', I2,
+ $ ', Y,', I2, ', A,', I3, ') .' )
+ 9993 FORMAT( ' ******* FATAL ERROR - ERROR-EXIT TAKEN ON VALID CALL *',
+ $ '******' )
+*
+* End of SCHK4.
+*
+ END
+ SUBROUTINE SCHK5( SNAME, EPS, THRESH, NOUT, NTRA, TRACE, REWI,
+ $ FATAL, NIDIM, IDIM, NALF, ALF, NINC, INC, NMAX,
+ $ INCMAX, A, AA, AS, X, XX, XS, Y, YY, YS, YT, G,
+ $ Z )
+*
+* Tests SSYR and SSPR.
+*
+* Auxiliary routine for test program for Level 2 Blas.
+*
+* -- Written on 10-August-1987.
+* Richard Hanson, Sandia National Labs.
+* Jeremy Du Croz, NAG Central Office.
+*
+* .. Parameters ..
+ REAL ZERO, HALF, ONE
+ PARAMETER ( ZERO = 0.0, HALF = 0.5, ONE = 1.0 )
+* .. Scalar Arguments ..
+ REAL EPS, THRESH
+ INTEGER INCMAX, NALF, NIDIM, NINC, NMAX, NOUT, NTRA
+ LOGICAL FATAL, REWI, TRACE
+ CHARACTER*6 SNAME
+* .. Array Arguments ..
+ REAL A( NMAX, NMAX ), AA( NMAX*NMAX ), ALF( NALF ),
+ $ AS( NMAX*NMAX ), G( NMAX ), X( NMAX ),
+ $ XS( NMAX*INCMAX ), XX( NMAX*INCMAX ),
+ $ Y( NMAX ), YS( NMAX*INCMAX ), YT( NMAX ),
+ $ YY( NMAX*INCMAX ), Z( NMAX )
+ INTEGER IDIM( NIDIM ), INC( NINC )
+* .. Local Scalars ..
+ REAL ALPHA, ALS, ERR, ERRMAX, TRANSL
+ INTEGER I, IA, IC, IN, INCX, INCXS, IX, J, JA, JJ, LAA,
+ $ LDA, LDAS, LJ, LX, N, NARGS, NC, NS
+ LOGICAL FULL, NULL, PACKED, RESET, SAME, UPPER
+ CHARACTER*1 UPLO, UPLOS
+ CHARACTER*2 ICH
+* .. Local Arrays ..
+ REAL W( 1 )
+ LOGICAL ISAME( 13 )
+* .. External Functions ..
+ LOGICAL LSE, LSERES
+ EXTERNAL LSE, LSERES
+* .. External Subroutines ..
+ EXTERNAL SMAKE, SMVCH, SSPR, SSYR
+* .. Intrinsic Functions ..
+ INTRINSIC ABS, MAX
+* .. Scalars in Common ..
+ INTEGER INFOT, NOUTC
+ LOGICAL LERR, OK
+* .. Common blocks ..
+ COMMON /INFOC/INFOT, NOUTC, OK, LERR
+* .. Data statements ..
+ DATA ICH/'UL'/
+* .. Executable Statements ..
+ FULL = SNAME( 3: 3 ).EQ.'Y'
+ PACKED = SNAME( 3: 3 ).EQ.'P'
+* Define the number of arguments.
+ IF( FULL )THEN
+ NARGS = 7
+ ELSE IF( PACKED )THEN
+ NARGS = 6
+ END IF
+*
+ NC = 0
+ RESET = .TRUE.
+ ERRMAX = ZERO
+*
+ DO 100 IN = 1, NIDIM
+ N = IDIM( IN )
+* Set LDA to 1 more than minimum value if room.
+ LDA = N
+ IF( LDA.LT.NMAX )
+ $ LDA = LDA + 1
+* Skip tests if not enough room.
+ IF( LDA.GT.NMAX )
+ $ GO TO 100
+ IF( PACKED )THEN
+ LAA = ( N*( N + 1 ) )/2
+ ELSE
+ LAA = LDA*N
+ END IF
+*
+ DO 90 IC = 1, 2
+ UPLO = ICH( IC: IC )
+ UPPER = UPLO.EQ.'U'
+*
+ DO 80 IX = 1, NINC
+ INCX = INC( IX )
+ LX = ABS( INCX )*N
+*
+* Generate the vector X.
+*
+ TRANSL = HALF
+ CALL SMAKE( 'GE', ' ', ' ', 1, N, X, 1, XX, ABS( INCX ),
+ $ 0, N - 1, RESET, TRANSL )
+ IF( N.GT.1 )THEN
+ X( N/2 ) = ZERO
+ XX( 1 + ABS( INCX )*( N/2 - 1 ) ) = ZERO
+ END IF
+*
+ DO 70 IA = 1, NALF
+ ALPHA = ALF( IA )
+ NULL = N.LE.0.OR.ALPHA.EQ.ZERO
+*
+* Generate the matrix A.
+*
+ TRANSL = ZERO
+ CALL SMAKE( SNAME( 2: 3 ), UPLO, ' ', N, N, A, NMAX,
+ $ AA, LDA, N - 1, N - 1, RESET, TRANSL )
+*
+ NC = NC + 1
+*
+* Save every datum before calling the subroutine.
+*
+ UPLOS = UPLO
+ NS = N
+ ALS = ALPHA
+ DO 10 I = 1, LAA
+ AS( I ) = AA( I )
+ 10 CONTINUE
+ LDAS = LDA
+ DO 20 I = 1, LX
+ XS( I ) = XX( I )
+ 20 CONTINUE
+ INCXS = INCX
+*
+* Call the subroutine.
+*
+ IF( FULL )THEN
+ IF( TRACE )
+ $ WRITE( NTRA, FMT = 9993 )NC, SNAME, UPLO, N,
+ $ ALPHA, INCX, LDA
+ IF( REWI )
+ $ REWIND NTRA
+ CALL SSYR( UPLO, N, ALPHA, XX, INCX, AA, LDA )
+ ELSE IF( PACKED )THEN
+ IF( TRACE )
+ $ WRITE( NTRA, FMT = 9994 )NC, SNAME, UPLO, N,
+ $ ALPHA, INCX
+ IF( REWI )
+ $ REWIND NTRA
+ CALL SSPR( UPLO, N, ALPHA, XX, INCX, AA )
+ END IF
+*
+* Check if error-exit was taken incorrectly.
+*
+ IF( .NOT.OK )THEN
+ WRITE( NOUT, FMT = 9992 )
+ FATAL = .TRUE.
+ GO TO 120
+ END IF
+*
+* See what data changed inside subroutines.
+*
+ ISAME( 1 ) = UPLO.EQ.UPLOS
+ ISAME( 2 ) = NS.EQ.N
+ ISAME( 3 ) = ALS.EQ.ALPHA
+ ISAME( 4 ) = LSE( XS, XX, LX )
+ ISAME( 5 ) = INCXS.EQ.INCX
+ IF( NULL )THEN
+ ISAME( 6 ) = LSE( AS, AA, LAA )
+ ELSE
+ ISAME( 6 ) = LSERES( SNAME( 2: 3 ), UPLO, N, N, AS,
+ $ AA, LDA )
+ END IF
+ IF( .NOT.PACKED )THEN
+ ISAME( 7 ) = LDAS.EQ.LDA
+ END IF
+*
+* If data was incorrectly changed, report and return.
+*
+ SAME = .TRUE.
+ DO 30 I = 1, NARGS
+ SAME = SAME.AND.ISAME( I )
+ IF( .NOT.ISAME( I ) )
+ $ WRITE( NOUT, FMT = 9998 )I
+ 30 CONTINUE
+ IF( .NOT.SAME )THEN
+ FATAL = .TRUE.
+ GO TO 120
+ END IF
+*
+ IF( .NOT.NULL )THEN
+*
+* Check the result column by column.
+*
+ IF( INCX.GT.0 )THEN
+ DO 40 I = 1, N
+ Z( I ) = X( I )
+ 40 CONTINUE
+ ELSE
+ DO 50 I = 1, N
+ Z( I ) = X( N - I + 1 )
+ 50 CONTINUE
+ END IF
+ JA = 1
+ DO 60 J = 1, N
+ W( 1 ) = Z( J )
+ IF( UPPER )THEN
+ JJ = 1
+ LJ = J
+ ELSE
+ JJ = J
+ LJ = N - J + 1
+ END IF
+ CALL SMVCH( 'N', LJ, 1, ALPHA, Z( JJ ), LJ, W,
+ $ 1, ONE, A( JJ, J ), 1, YT, G,
+ $ AA( JA ), EPS, ERR, FATAL, NOUT,
+ $ .TRUE. )
+ IF( FULL )THEN
+ IF( UPPER )THEN
+ JA = JA + LDA
+ ELSE
+ JA = JA + LDA + 1
+ END IF
+ ELSE
+ JA = JA + LJ
+ END IF
+ ERRMAX = MAX( ERRMAX, ERR )
+* If got really bad answer, report and return.
+ IF( FATAL )
+ $ GO TO 110
+ 60 CONTINUE
+ ELSE
+* Avoid repeating tests if N.le.0.
+ IF( N.LE.0 )
+ $ GO TO 100
+ END IF
+*
+ 70 CONTINUE
+*
+ 80 CONTINUE
+*
+ 90 CONTINUE
+*
+ 100 CONTINUE
+*
+* Report result.
+*
+ IF( ERRMAX.LT.THRESH )THEN
+ WRITE( NOUT, FMT = 9999 )SNAME, NC
+ ELSE
+ WRITE( NOUT, FMT = 9997 )SNAME, NC, ERRMAX
+ END IF
+ GO TO 130
+*
+ 110 CONTINUE
+ WRITE( NOUT, FMT = 9995 )J
+*
+ 120 CONTINUE
+ WRITE( NOUT, FMT = 9996 )SNAME
+ IF( FULL )THEN
+ WRITE( NOUT, FMT = 9993 )NC, SNAME, UPLO, N, ALPHA, INCX, LDA
+ ELSE IF( PACKED )THEN
+ WRITE( NOUT, FMT = 9994 )NC, SNAME, UPLO, N, ALPHA, INCX
+ END IF
+*
+ 130 CONTINUE
+ RETURN
+*
+ 9999 FORMAT( ' ', A6, ' PASSED THE COMPUTATIONAL TESTS (', I6, ' CALL',
+ $ 'S)' )
+ 9998 FORMAT( ' ******* FATAL ERROR - PARAMETER NUMBER ', I2, ' WAS CH',
+ $ 'ANGED INCORRECTLY *******' )
+ 9997 FORMAT( ' ', A6, ' COMPLETED THE COMPUTATIONAL TESTS (', I6, ' C',
+ $ 'ALLS)', /' ******* BUT WITH MAXIMUM TEST RATIO', F8.2,
+ $ ' - SUSPECT *******' )
+ 9996 FORMAT( ' ******* ', A6, ' FAILED ON CALL NUMBER:' )
+ 9995 FORMAT( ' THESE ARE THE RESULTS FOR COLUMN ', I3 )
+ 9994 FORMAT( 1X, I6, ': ', A6, '(''', A1, ''',', I3, ',', F4.1, ', X,',
+ $ I2, ', AP) .' )
+ 9993 FORMAT( 1X, I6, ': ', A6, '(''', A1, ''',', I3, ',', F4.1, ', X,',
+ $ I2, ', A,', I3, ') .' )
+ 9992 FORMAT( ' ******* FATAL ERROR - ERROR-EXIT TAKEN ON VALID CALL *',
+ $ '******' )
+*
+* End of SCHK5.
+*
+ END
+ SUBROUTINE SCHK6( SNAME, EPS, THRESH, NOUT, NTRA, TRACE, REWI,
+ $ FATAL, NIDIM, IDIM, NALF, ALF, NINC, INC, NMAX,
+ $ INCMAX, A, AA, AS, X, XX, XS, Y, YY, YS, YT, G,
+ $ Z )
+*
+* Tests SSYR2 and SSPR2.
+*
+* Auxiliary routine for test program for Level 2 Blas.
+*
+* -- Written on 10-August-1987.
+* Richard Hanson, Sandia National Labs.
+* Jeremy Du Croz, NAG Central Office.
+*
+* .. Parameters ..
+ REAL ZERO, HALF, ONE
+ PARAMETER ( ZERO = 0.0, HALF = 0.5, ONE = 1.0 )
+* .. Scalar Arguments ..
+ REAL EPS, THRESH
+ INTEGER INCMAX, NALF, NIDIM, NINC, NMAX, NOUT, NTRA
+ LOGICAL FATAL, REWI, TRACE
+ CHARACTER*6 SNAME
+* .. Array Arguments ..
+ REAL A( NMAX, NMAX ), AA( NMAX*NMAX ), ALF( NALF ),
+ $ AS( NMAX*NMAX ), G( NMAX ), X( NMAX ),
+ $ XS( NMAX*INCMAX ), XX( NMAX*INCMAX ),
+ $ Y( NMAX ), YS( NMAX*INCMAX ), YT( NMAX ),
+ $ YY( NMAX*INCMAX ), Z( NMAX, 2 )
+ INTEGER IDIM( NIDIM ), INC( NINC )
+* .. Local Scalars ..
+ REAL ALPHA, ALS, ERR, ERRMAX, TRANSL
+ INTEGER I, IA, IC, IN, INCX, INCXS, INCY, INCYS, IX,
+ $ IY, J, JA, JJ, LAA, LDA, LDAS, LJ, LX, LY, N,
+ $ NARGS, NC, NS
+ LOGICAL FULL, NULL, PACKED, RESET, SAME, UPPER
+ CHARACTER*1 UPLO, UPLOS
+ CHARACTER*2 ICH
+* .. Local Arrays ..
+ REAL W( 2 )
+ LOGICAL ISAME( 13 )
+* .. External Functions ..
+ LOGICAL LSE, LSERES
+ EXTERNAL LSE, LSERES
+* .. External Subroutines ..
+ EXTERNAL SMAKE, SMVCH, SSPR2, SSYR2
+* .. Intrinsic Functions ..
+ INTRINSIC ABS, MAX
+* .. Scalars in Common ..
+ INTEGER INFOT, NOUTC
+ LOGICAL LERR, OK
+* .. Common blocks ..
+ COMMON /INFOC/INFOT, NOUTC, OK, LERR
+* .. Data statements ..
+ DATA ICH/'UL'/
+* .. Executable Statements ..
+ FULL = SNAME( 3: 3 ).EQ.'Y'
+ PACKED = SNAME( 3: 3 ).EQ.'P'
+* Define the number of arguments.
+ IF( FULL )THEN
+ NARGS = 9
+ ELSE IF( PACKED )THEN
+ NARGS = 8
+ END IF
+*
+ NC = 0
+ RESET = .TRUE.
+ ERRMAX = ZERO
+*
+ DO 140 IN = 1, NIDIM
+ N = IDIM( IN )
+* Set LDA to 1 more than minimum value if room.
+ LDA = N
+ IF( LDA.LT.NMAX )
+ $ LDA = LDA + 1
+* Skip tests if not enough room.
+ IF( LDA.GT.NMAX )
+ $ GO TO 140
+ IF( PACKED )THEN
+ LAA = ( N*( N + 1 ) )/2
+ ELSE
+ LAA = LDA*N
+ END IF
+*
+ DO 130 IC = 1, 2
+ UPLO = ICH( IC: IC )
+ UPPER = UPLO.EQ.'U'
+*
+ DO 120 IX = 1, NINC
+ INCX = INC( IX )
+ LX = ABS( INCX )*N
+*
+* Generate the vector X.
+*
+ TRANSL = HALF
+ CALL SMAKE( 'GE', ' ', ' ', 1, N, X, 1, XX, ABS( INCX ),
+ $ 0, N - 1, RESET, TRANSL )
+ IF( N.GT.1 )THEN
+ X( N/2 ) = ZERO
+ XX( 1 + ABS( INCX )*( N/2 - 1 ) ) = ZERO
+ END IF
+*
+ DO 110 IY = 1, NINC
+ INCY = INC( IY )
+ LY = ABS( INCY )*N
+*
+* Generate the vector Y.
+*
+ TRANSL = ZERO
+ CALL SMAKE( 'GE', ' ', ' ', 1, N, Y, 1, YY,
+ $ ABS( INCY ), 0, N - 1, RESET, TRANSL )
+ IF( N.GT.1 )THEN
+ Y( N/2 ) = ZERO
+ YY( 1 + ABS( INCY )*( N/2 - 1 ) ) = ZERO
+ END IF
+*
+ DO 100 IA = 1, NALF
+ ALPHA = ALF( IA )
+ NULL = N.LE.0.OR.ALPHA.EQ.ZERO
+*
+* Generate the matrix A.
+*
+ TRANSL = ZERO
+ CALL SMAKE( SNAME( 2: 3 ), UPLO, ' ', N, N, A,
+ $ NMAX, AA, LDA, N - 1, N - 1, RESET,
+ $ TRANSL )
+*
+ NC = NC + 1
+*
+* Save every datum before calling the subroutine.
+*
+ UPLOS = UPLO
+ NS = N
+ ALS = ALPHA
+ DO 10 I = 1, LAA
+ AS( I ) = AA( I )
+ 10 CONTINUE
+ LDAS = LDA
+ DO 20 I = 1, LX
+ XS( I ) = XX( I )
+ 20 CONTINUE
+ INCXS = INCX
+ DO 30 I = 1, LY
+ YS( I ) = YY( I )
+ 30 CONTINUE
+ INCYS = INCY
+*
+* Call the subroutine.
+*
+ IF( FULL )THEN
+ IF( TRACE )
+ $ WRITE( NTRA, FMT = 9993 )NC, SNAME, UPLO, N,
+ $ ALPHA, INCX, INCY, LDA
+ IF( REWI )
+ $ REWIND NTRA
+ CALL SSYR2( UPLO, N, ALPHA, XX, INCX, YY, INCY,
+ $ AA, LDA )
+ ELSE IF( PACKED )THEN
+ IF( TRACE )
+ $ WRITE( NTRA, FMT = 9994 )NC, SNAME, UPLO, N,
+ $ ALPHA, INCX, INCY
+ IF( REWI )
+ $ REWIND NTRA
+ CALL SSPR2( UPLO, N, ALPHA, XX, INCX, YY, INCY,
+ $ AA )
+ END IF
+*
+* Check if error-exit was taken incorrectly.
+*
+ IF( .NOT.OK )THEN
+ WRITE( NOUT, FMT = 9992 )
+ FATAL = .TRUE.
+ GO TO 160
+ END IF
+*
+* See what data changed inside subroutines.
+*
+ ISAME( 1 ) = UPLO.EQ.UPLOS
+ ISAME( 2 ) = NS.EQ.N
+ ISAME( 3 ) = ALS.EQ.ALPHA
+ ISAME( 4 ) = LSE( XS, XX, LX )
+ ISAME( 5 ) = INCXS.EQ.INCX
+ ISAME( 6 ) = LSE( YS, YY, LY )
+ ISAME( 7 ) = INCYS.EQ.INCY
+ IF( NULL )THEN
+ ISAME( 8 ) = LSE( AS, AA, LAA )
+ ELSE
+ ISAME( 8 ) = LSERES( SNAME( 2: 3 ), UPLO, N, N,
+ $ AS, AA, LDA )
+ END IF
+ IF( .NOT.PACKED )THEN
+ ISAME( 9 ) = LDAS.EQ.LDA
+ END IF
+*
+* If data was incorrectly changed, report and return.
+*
+ SAME = .TRUE.
+ DO 40 I = 1, NARGS
+ SAME = SAME.AND.ISAME( I )
+ IF( .NOT.ISAME( I ) )
+ $ WRITE( NOUT, FMT = 9998 )I
+ 40 CONTINUE
+ IF( .NOT.SAME )THEN
+ FATAL = .TRUE.
+ GO TO 160
+ END IF
+*
+ IF( .NOT.NULL )THEN
+*
+* Check the result column by column.
+*
+ IF( INCX.GT.0 )THEN
+ DO 50 I = 1, N
+ Z( I, 1 ) = X( I )
+ 50 CONTINUE
+ ELSE
+ DO 60 I = 1, N
+ Z( I, 1 ) = X( N - I + 1 )
+ 60 CONTINUE
+ END IF
+ IF( INCY.GT.0 )THEN
+ DO 70 I = 1, N
+ Z( I, 2 ) = Y( I )
+ 70 CONTINUE
+ ELSE
+ DO 80 I = 1, N
+ Z( I, 2 ) = Y( N - I + 1 )
+ 80 CONTINUE
+ END IF
+ JA = 1
+ DO 90 J = 1, N
+ W( 1 ) = Z( J, 2 )
+ W( 2 ) = Z( J, 1 )
+ IF( UPPER )THEN
+ JJ = 1
+ LJ = J
+ ELSE
+ JJ = J
+ LJ = N - J + 1
+ END IF
+ CALL SMVCH( 'N', LJ, 2, ALPHA, Z( JJ, 1 ),
+ $ NMAX, W, 1, ONE, A( JJ, J ), 1,
+ $ YT, G, AA( JA ), EPS, ERR, FATAL,
+ $ NOUT, .TRUE. )
+ IF( FULL )THEN
+ IF( UPPER )THEN
+ JA = JA + LDA
+ ELSE
+ JA = JA + LDA + 1
+ END IF
+ ELSE
+ JA = JA + LJ
+ END IF
+ ERRMAX = MAX( ERRMAX, ERR )
+* If got really bad answer, report and return.
+ IF( FATAL )
+ $ GO TO 150
+ 90 CONTINUE
+ ELSE
+* Avoid repeating tests with N.le.0.
+ IF( N.LE.0 )
+ $ GO TO 140
+ END IF
+*
+ 100 CONTINUE
+*
+ 110 CONTINUE
+*
+ 120 CONTINUE
+*
+ 130 CONTINUE
+*
+ 140 CONTINUE
+*
+* Report result.
+*
+ IF( ERRMAX.LT.THRESH )THEN
+ WRITE( NOUT, FMT = 9999 )SNAME, NC
+ ELSE
+ WRITE( NOUT, FMT = 9997 )SNAME, NC, ERRMAX
+ END IF
+ GO TO 170
+*
+ 150 CONTINUE
+ WRITE( NOUT, FMT = 9995 )J
+*
+ 160 CONTINUE
+ WRITE( NOUT, FMT = 9996 )SNAME
+ IF( FULL )THEN
+ WRITE( NOUT, FMT = 9993 )NC, SNAME, UPLO, N, ALPHA, INCX,
+ $ INCY, LDA
+ ELSE IF( PACKED )THEN
+ WRITE( NOUT, FMT = 9994 )NC, SNAME, UPLO, N, ALPHA, INCX, INCY
+ END IF
+*
+ 170 CONTINUE
+ RETURN
+*
+ 9999 FORMAT( ' ', A6, ' PASSED THE COMPUTATIONAL TESTS (', I6, ' CALL',
+ $ 'S)' )
+ 9998 FORMAT( ' ******* FATAL ERROR - PARAMETER NUMBER ', I2, ' WAS CH',
+ $ 'ANGED INCORRECTLY *******' )
+ 9997 FORMAT( ' ', A6, ' COMPLETED THE COMPUTATIONAL TESTS (', I6, ' C',
+ $ 'ALLS)', /' ******* BUT WITH MAXIMUM TEST RATIO', F8.2,
+ $ ' - SUSPECT *******' )
+ 9996 FORMAT( ' ******* ', A6, ' FAILED ON CALL NUMBER:' )
+ 9995 FORMAT( ' THESE ARE THE RESULTS FOR COLUMN ', I3 )
+ 9994 FORMAT( 1X, I6, ': ', A6, '(''', A1, ''',', I3, ',', F4.1, ', X,',
+ $ I2, ', Y,', I2, ', AP) .' )
+ 9993 FORMAT( 1X, I6, ': ', A6, '(''', A1, ''',', I3, ',', F4.1, ', X,',
+ $ I2, ', Y,', I2, ', A,', I3, ') .' )
+ 9992 FORMAT( ' ******* FATAL ERROR - ERROR-EXIT TAKEN ON VALID CALL *',
+ $ '******' )
+*
+* End of SCHK6.
+*
+ END
+ SUBROUTINE SCHKE( ISNUM, SRNAMT, NOUT )
+*
+* Tests the error exits from the Level 2 Blas.
+* Requires a special version of the error-handling routine XERBLA.
+* ALPHA, BETA, A, X and Y should not need to be defined.
+*
+* Auxiliary routine for test program for Level 2 Blas.
+*
+* -- Written on 10-August-1987.
+* Richard Hanson, Sandia National Labs.
+* Jeremy Du Croz, NAG Central Office.
+*
+* .. Scalar Arguments ..
+ INTEGER ISNUM, NOUT
+ CHARACTER*6 SRNAMT
+* .. Scalars in Common ..
+ INTEGER INFOT, NOUTC
+ LOGICAL LERR, OK
+* .. Local Scalars ..
+ REAL ALPHA, BETA
+* .. Local Arrays ..
+ REAL A( 1, 1 ), X( 1 ), Y( 1 )
+* .. External Subroutines ..
+ EXTERNAL CHKXER, SGBMV, SGEMV, SGER, SSBMV, SSPMV, SSPR,
+ $ SSPR2, SSYMV, SSYR, SSYR2, STBMV, STBSV, STPMV,
+ $ STPSV, STRMV, STRSV
+* .. Common blocks ..
+ COMMON /INFOC/INFOT, NOUTC, OK, LERR
+* .. Executable Statements ..
+* OK is set to .FALSE. by the special version of XERBLA or by CHKXER
+* if anything is wrong.
+ OK = .TRUE.
+* LERR is set to .TRUE. by the special version of XERBLA each time
+* it is called, and is then tested and re-set by CHKXER.
+ LERR = .FALSE.
+ GO TO ( 10, 20, 30, 40, 50, 60, 70, 80,
+ $ 90, 100, 110, 120, 130, 140, 150,
+ $ 160 )ISNUM
+ 10 INFOT = 1
+ CALL SGEMV( '/', 0, 0, ALPHA, A, 1, X, 1, BETA, Y, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 2
+ CALL SGEMV( 'N', -1, 0, ALPHA, A, 1, X, 1, BETA, Y, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 3
+ CALL SGEMV( 'N', 0, -1, ALPHA, A, 1, X, 1, BETA, Y, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 6
+ CALL SGEMV( 'N', 2, 0, ALPHA, A, 1, X, 1, BETA, Y, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 8
+ CALL SGEMV( 'N', 0, 0, ALPHA, A, 1, X, 0, BETA, Y, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 11
+ CALL SGEMV( 'N', 0, 0, ALPHA, A, 1, X, 1, BETA, Y, 0 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ GO TO 170
+ 20 INFOT = 1
+ CALL SGBMV( '/', 0, 0, 0, 0, ALPHA, A, 1, X, 1, BETA, Y, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 2
+ CALL SGBMV( 'N', -1, 0, 0, 0, ALPHA, A, 1, X, 1, BETA, Y, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 3
+ CALL SGBMV( 'N', 0, -1, 0, 0, ALPHA, A, 1, X, 1, BETA, Y, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 4
+ CALL SGBMV( 'N', 0, 0, -1, 0, ALPHA, A, 1, X, 1, BETA, Y, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 5
+ CALL SGBMV( 'N', 2, 0, 0, -1, ALPHA, A, 1, X, 1, BETA, Y, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 8
+ CALL SGBMV( 'N', 0, 0, 1, 0, ALPHA, A, 1, X, 1, BETA, Y, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 10
+ CALL SGBMV( 'N', 0, 0, 0, 0, ALPHA, A, 1, X, 0, BETA, Y, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 13
+ CALL SGBMV( 'N', 0, 0, 0, 0, ALPHA, A, 1, X, 1, BETA, Y, 0 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ GO TO 170
+ 30 INFOT = 1
+ CALL SSYMV( '/', 0, ALPHA, A, 1, X, 1, BETA, Y, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 2
+ CALL SSYMV( 'U', -1, ALPHA, A, 1, X, 1, BETA, Y, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 5
+ CALL SSYMV( 'U', 2, ALPHA, A, 1, X, 1, BETA, Y, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 7
+ CALL SSYMV( 'U', 0, ALPHA, A, 1, X, 0, BETA, Y, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 10
+ CALL SSYMV( 'U', 0, ALPHA, A, 1, X, 1, BETA, Y, 0 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ GO TO 170
+ 40 INFOT = 1
+ CALL SSBMV( '/', 0, 0, ALPHA, A, 1, X, 1, BETA, Y, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 2
+ CALL SSBMV( 'U', -1, 0, ALPHA, A, 1, X, 1, BETA, Y, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 3
+ CALL SSBMV( 'U', 0, -1, ALPHA, A, 1, X, 1, BETA, Y, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 6
+ CALL SSBMV( 'U', 0, 1, ALPHA, A, 1, X, 1, BETA, Y, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 8
+ CALL SSBMV( 'U', 0, 0, ALPHA, A, 1, X, 0, BETA, Y, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 11
+ CALL SSBMV( 'U', 0, 0, ALPHA, A, 1, X, 1, BETA, Y, 0 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ GO TO 170
+ 50 INFOT = 1
+ CALL SSPMV( '/', 0, ALPHA, A, X, 1, BETA, Y, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 2
+ CALL SSPMV( 'U', -1, ALPHA, A, X, 1, BETA, Y, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 6
+ CALL SSPMV( 'U', 0, ALPHA, A, X, 0, BETA, Y, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 9
+ CALL SSPMV( 'U', 0, ALPHA, A, X, 1, BETA, Y, 0 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ GO TO 170
+ 60 INFOT = 1
+ CALL STRMV( '/', 'N', 'N', 0, A, 1, X, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 2
+ CALL STRMV( 'U', '/', 'N', 0, A, 1, X, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 3
+ CALL STRMV( 'U', 'N', '/', 0, A, 1, X, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 4
+ CALL STRMV( 'U', 'N', 'N', -1, A, 1, X, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 6
+ CALL STRMV( 'U', 'N', 'N', 2, A, 1, X, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 8
+ CALL STRMV( 'U', 'N', 'N', 0, A, 1, X, 0 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ GO TO 170
+ 70 INFOT = 1
+ CALL STBMV( '/', 'N', 'N', 0, 0, A, 1, X, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 2
+ CALL STBMV( 'U', '/', 'N', 0, 0, A, 1, X, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 3
+ CALL STBMV( 'U', 'N', '/', 0, 0, A, 1, X, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 4
+ CALL STBMV( 'U', 'N', 'N', -1, 0, A, 1, X, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 5
+ CALL STBMV( 'U', 'N', 'N', 0, -1, A, 1, X, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 7
+ CALL STBMV( 'U', 'N', 'N', 0, 1, A, 1, X, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 9
+ CALL STBMV( 'U', 'N', 'N', 0, 0, A, 1, X, 0 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ GO TO 170
+ 80 INFOT = 1
+ CALL STPMV( '/', 'N', 'N', 0, A, X, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 2
+ CALL STPMV( 'U', '/', 'N', 0, A, X, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 3
+ CALL STPMV( 'U', 'N', '/', 0, A, X, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 4
+ CALL STPMV( 'U', 'N', 'N', -1, A, X, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 7
+ CALL STPMV( 'U', 'N', 'N', 0, A, X, 0 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ GO TO 170
+ 90 INFOT = 1
+ CALL STRSV( '/', 'N', 'N', 0, A, 1, X, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 2
+ CALL STRSV( 'U', '/', 'N', 0, A, 1, X, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 3
+ CALL STRSV( 'U', 'N', '/', 0, A, 1, X, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 4
+ CALL STRSV( 'U', 'N', 'N', -1, A, 1, X, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 6
+ CALL STRSV( 'U', 'N', 'N', 2, A, 1, X, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 8
+ CALL STRSV( 'U', 'N', 'N', 0, A, 1, X, 0 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ GO TO 170
+ 100 INFOT = 1
+ CALL STBSV( '/', 'N', 'N', 0, 0, A, 1, X, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 2
+ CALL STBSV( 'U', '/', 'N', 0, 0, A, 1, X, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 3
+ CALL STBSV( 'U', 'N', '/', 0, 0, A, 1, X, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 4
+ CALL STBSV( 'U', 'N', 'N', -1, 0, A, 1, X, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 5
+ CALL STBSV( 'U', 'N', 'N', 0, -1, A, 1, X, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 7
+ CALL STBSV( 'U', 'N', 'N', 0, 1, A, 1, X, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 9
+ CALL STBSV( 'U', 'N', 'N', 0, 0, A, 1, X, 0 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ GO TO 170
+ 110 INFOT = 1
+ CALL STPSV( '/', 'N', 'N', 0, A, X, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 2
+ CALL STPSV( 'U', '/', 'N', 0, A, X, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 3
+ CALL STPSV( 'U', 'N', '/', 0, A, X, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 4
+ CALL STPSV( 'U', 'N', 'N', -1, A, X, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 7
+ CALL STPSV( 'U', 'N', 'N', 0, A, X, 0 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ GO TO 170
+ 120 INFOT = 1
+ CALL SGER( -1, 0, ALPHA, X, 1, Y, 1, A, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 2
+ CALL SGER( 0, -1, ALPHA, X, 1, Y, 1, A, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 5
+ CALL SGER( 0, 0, ALPHA, X, 0, Y, 1, A, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 7
+ CALL SGER( 0, 0, ALPHA, X, 1, Y, 0, A, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 9
+ CALL SGER( 2, 0, ALPHA, X, 1, Y, 1, A, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ GO TO 170
+ 130 INFOT = 1
+ CALL SSYR( '/', 0, ALPHA, X, 1, A, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 2
+ CALL SSYR( 'U', -1, ALPHA, X, 1, A, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 5
+ CALL SSYR( 'U', 0, ALPHA, X, 0, A, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 7
+ CALL SSYR( 'U', 2, ALPHA, X, 1, A, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ GO TO 170
+ 140 INFOT = 1
+ CALL SSPR( '/', 0, ALPHA, X, 1, A )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 2
+ CALL SSPR( 'U', -1, ALPHA, X, 1, A )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 5
+ CALL SSPR( 'U', 0, ALPHA, X, 0, A )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ GO TO 170
+ 150 INFOT = 1
+ CALL SSYR2( '/', 0, ALPHA, X, 1, Y, 1, A, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 2
+ CALL SSYR2( 'U', -1, ALPHA, X, 1, Y, 1, A, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 5
+ CALL SSYR2( 'U', 0, ALPHA, X, 0, Y, 1, A, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 7
+ CALL SSYR2( 'U', 0, ALPHA, X, 1, Y, 0, A, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 9
+ CALL SSYR2( 'U', 2, ALPHA, X, 1, Y, 1, A, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ GO TO 170
+ 160 INFOT = 1
+ CALL SSPR2( '/', 0, ALPHA, X, 1, Y, 1, A )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 2
+ CALL SSPR2( 'U', -1, ALPHA, X, 1, Y, 1, A )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 5
+ CALL SSPR2( 'U', 0, ALPHA, X, 0, Y, 1, A )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 7
+ CALL SSPR2( 'U', 0, ALPHA, X, 1, Y, 0, A )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+*
+ 170 IF( OK )THEN
+ WRITE( NOUT, FMT = 9999 )SRNAMT
+ ELSE
+ WRITE( NOUT, FMT = 9998 )SRNAMT
+ END IF
+ RETURN
+*
+ 9999 FORMAT( ' ', A6, ' PASSED THE TESTS OF ERROR-EXITS' )
+ 9998 FORMAT( ' ******* ', A6, ' FAILED THE TESTS OF ERROR-EXITS *****',
+ $ '**' )
+*
+* End of SCHKE.
+*
+ END
+ SUBROUTINE SMAKE( TYPE, UPLO, DIAG, M, N, A, NMAX, AA, LDA, KL,
+ $ KU, RESET, TRANSL )
+*
+* Generates values for an M by N matrix A within the bandwidth
+* defined by KL and KU.
+* Stores the values in the array AA in the data structure required
+* by the routine, with unwanted elements set to rogue value.
+*
+* TYPE is 'GE', 'GB', 'SY', 'SB', 'SP', 'TR', 'TB' OR 'TP'.
+*
+* Auxiliary routine for test program for Level 2 Blas.
+*
+* -- Written on 10-August-1987.
+* Richard Hanson, Sandia National Labs.
+* Jeremy Du Croz, NAG Central Office.
+*
+* .. Parameters ..
+ REAL ZERO, ONE
+ PARAMETER ( ZERO = 0.0, ONE = 1.0 )
+ REAL ROGUE
+ PARAMETER ( ROGUE = -1.0E10 )
+* .. Scalar Arguments ..
+ REAL TRANSL
+ INTEGER KL, KU, LDA, M, N, NMAX
+ LOGICAL RESET
+ CHARACTER*1 DIAG, UPLO
+ CHARACTER*2 TYPE
+* .. Array Arguments ..
+ REAL A( NMAX, * ), AA( * )
+* .. Local Scalars ..
+ INTEGER I, I1, I2, I3, IBEG, IEND, IOFF, J, KK
+ LOGICAL GEN, LOWER, SYM, TRI, UNIT, UPPER
+* .. External Functions ..
+ REAL SBEG
+ EXTERNAL SBEG
+* .. Intrinsic Functions ..
+ INTRINSIC MAX, MIN
+* .. Executable Statements ..
+ GEN = TYPE( 1: 1 ).EQ.'G'
+ SYM = TYPE( 1: 1 ).EQ.'S'
+ TRI = TYPE( 1: 1 ).EQ.'T'
+ UPPER = ( SYM.OR.TRI ).AND.UPLO.EQ.'U'
+ LOWER = ( SYM.OR.TRI ).AND.UPLO.EQ.'L'
+ UNIT = TRI.AND.DIAG.EQ.'U'
+*
+* Generate data in array A.
+*
+ DO 20 J = 1, N
+ DO 10 I = 1, M
+ IF( GEN.OR.( UPPER.AND.I.LE.J ).OR.( LOWER.AND.I.GE.J ) )
+ $ THEN
+ IF( ( I.LE.J.AND.J - I.LE.KU ).OR.
+ $ ( I.GE.J.AND.I - J.LE.KL ) )THEN
+ A( I, J ) = SBEG( RESET ) + TRANSL
+ ELSE
+ A( I, J ) = ZERO
+ END IF
+ IF( I.NE.J )THEN
+ IF( SYM )THEN
+ A( J, I ) = A( I, J )
+ ELSE IF( TRI )THEN
+ A( J, I ) = ZERO
+ END IF
+ END IF
+ END IF
+ 10 CONTINUE
+ IF( TRI )
+ $ A( J, J ) = A( J, J ) + ONE
+ IF( UNIT )
+ $ A( J, J ) = ONE
+ 20 CONTINUE
+*
+* Store elements in array AS in data structure required by routine.
+*
+ IF( TYPE.EQ.'GE' )THEN
+ DO 50 J = 1, N
+ DO 30 I = 1, M
+ AA( I + ( J - 1 )*LDA ) = A( I, J )
+ 30 CONTINUE
+ DO 40 I = M + 1, LDA
+ AA( I + ( J - 1 )*LDA ) = ROGUE
+ 40 CONTINUE
+ 50 CONTINUE
+ ELSE IF( TYPE.EQ.'GB' )THEN
+ DO 90 J = 1, N
+ DO 60 I1 = 1, KU + 1 - J
+ AA( I1 + ( J - 1 )*LDA ) = ROGUE
+ 60 CONTINUE
+ DO 70 I2 = I1, MIN( KL + KU + 1, KU + 1 + M - J )
+ AA( I2 + ( J - 1 )*LDA ) = A( I2 + J - KU - 1, J )
+ 70 CONTINUE
+ DO 80 I3 = I2, LDA
+ AA( I3 + ( J - 1 )*LDA ) = ROGUE
+ 80 CONTINUE
+ 90 CONTINUE
+ ELSE IF( TYPE.EQ.'SY'.OR.TYPE.EQ.'TR' )THEN
+ DO 130 J = 1, N
+ IF( UPPER )THEN
+ IBEG = 1
+ IF( UNIT )THEN
+ IEND = J - 1
+ ELSE
+ IEND = J
+ END IF
+ ELSE
+ IF( UNIT )THEN
+ IBEG = J + 1
+ ELSE
+ IBEG = J
+ END IF
+ IEND = N
+ END IF
+ DO 100 I = 1, IBEG - 1
+ AA( I + ( J - 1 )*LDA ) = ROGUE
+ 100 CONTINUE
+ DO 110 I = IBEG, IEND
+ AA( I + ( J - 1 )*LDA ) = A( I, J )
+ 110 CONTINUE
+ DO 120 I = IEND + 1, LDA
+ AA( I + ( J - 1 )*LDA ) = ROGUE
+ 120 CONTINUE
+ 130 CONTINUE
+ ELSE IF( TYPE.EQ.'SB'.OR.TYPE.EQ.'TB' )THEN
+ DO 170 J = 1, N
+ IF( UPPER )THEN
+ KK = KL + 1
+ IBEG = MAX( 1, KL + 2 - J )
+ IF( UNIT )THEN
+ IEND = KL
+ ELSE
+ IEND = KL + 1
+ END IF
+ ELSE
+ KK = 1
+ IF( UNIT )THEN
+ IBEG = 2
+ ELSE
+ IBEG = 1
+ END IF
+ IEND = MIN( KL + 1, 1 + M - J )
+ END IF
+ DO 140 I = 1, IBEG - 1
+ AA( I + ( J - 1 )*LDA ) = ROGUE
+ 140 CONTINUE
+ DO 150 I = IBEG, IEND
+ AA( I + ( J - 1 )*LDA ) = A( I + J - KK, J )
+ 150 CONTINUE
+ DO 160 I = IEND + 1, LDA
+ AA( I + ( J - 1 )*LDA ) = ROGUE
+ 160 CONTINUE
+ 170 CONTINUE
+ ELSE IF( TYPE.EQ.'SP'.OR.TYPE.EQ.'TP' )THEN
+ IOFF = 0
+ DO 190 J = 1, N
+ IF( UPPER )THEN
+ IBEG = 1
+ IEND = J
+ ELSE
+ IBEG = J
+ IEND = N
+ END IF
+ DO 180 I = IBEG, IEND
+ IOFF = IOFF + 1
+ AA( IOFF ) = A( I, J )
+ IF( I.EQ.J )THEN
+ IF( UNIT )
+ $ AA( IOFF ) = ROGUE
+ END IF
+ 180 CONTINUE
+ 190 CONTINUE
+ END IF
+ RETURN
+*
+* End of SMAKE.
+*
+ END
+ SUBROUTINE SMVCH( TRANS, M, N, ALPHA, A, NMAX, X, INCX, BETA, Y,
+ $ INCY, YT, G, YY, EPS, ERR, FATAL, NOUT, MV )
+*
+* Checks the results of the computational tests.
+*
+* Auxiliary routine for test program for Level 2 Blas.
+*
+* -- Written on 10-August-1987.
+* Richard Hanson, Sandia National Labs.
+* Jeremy Du Croz, NAG Central Office.
+*
+* .. Parameters ..
+ REAL ZERO, ONE
+ PARAMETER ( ZERO = 0.0, ONE = 1.0 )
+* .. Scalar Arguments ..
+ REAL ALPHA, BETA, EPS, ERR
+ INTEGER INCX, INCY, M, N, NMAX, NOUT
+ LOGICAL FATAL, MV
+ CHARACTER*1 TRANS
+* .. Array Arguments ..
+ REAL A( NMAX, * ), G( * ), X( * ), Y( * ), YT( * ),
+ $ YY( * )
+* .. Local Scalars ..
+ REAL ERRI
+ INTEGER I, INCXL, INCYL, IY, J, JX, KX, KY, ML, NL
+ LOGICAL TRAN
+* .. Intrinsic Functions ..
+ INTRINSIC ABS, MAX, SQRT
+* .. Executable Statements ..
+ TRAN = TRANS.EQ.'T'.OR.TRANS.EQ.'C'
+ IF( TRAN )THEN
+ ML = N
+ NL = M
+ ELSE
+ ML = M
+ NL = N
+ END IF
+ IF( INCX.LT.0 )THEN
+ KX = NL
+ INCXL = -1
+ ELSE
+ KX = 1
+ INCXL = 1
+ END IF
+ IF( INCY.LT.0 )THEN
+ KY = ML
+ INCYL = -1
+ ELSE
+ KY = 1
+ INCYL = 1
+ END IF
+*
+* Compute expected result in YT using data in A, X and Y.
+* Compute gauges in G.
+*
+ IY = KY
+ DO 30 I = 1, ML
+ YT( IY ) = ZERO
+ G( IY ) = ZERO
+ JX = KX
+ IF( TRAN )THEN
+ DO 10 J = 1, NL
+ YT( IY ) = YT( IY ) + A( J, I )*X( JX )
+ G( IY ) = G( IY ) + ABS( A( J, I )*X( JX ) )
+ JX = JX + INCXL
+ 10 CONTINUE
+ ELSE
+ DO 20 J = 1, NL
+ YT( IY ) = YT( IY ) + A( I, J )*X( JX )
+ G( IY ) = G( IY ) + ABS( A( I, J )*X( JX ) )
+ JX = JX + INCXL
+ 20 CONTINUE
+ END IF
+ YT( IY ) = ALPHA*YT( IY ) + BETA*Y( IY )
+ G( IY ) = ABS( ALPHA )*G( IY ) + ABS( BETA*Y( IY ) )
+ IY = IY + INCYL
+ 30 CONTINUE
+*
+* Compute the error ratio for this result.
+*
+ ERR = ZERO
+ DO 40 I = 1, ML
+ ERRI = ABS( YT( I ) - YY( 1 + ( I - 1 )*ABS( INCY ) ) )/EPS
+ IF( G( I ).NE.ZERO )
+ $ ERRI = ERRI/G( I )
+ ERR = MAX( ERR, ERRI )
+ IF( ERR*SQRT( EPS ).GE.ONE )
+ $ GO TO 50
+ 40 CONTINUE
+* If the loop completes, all results are at least half accurate.
+ GO TO 70
+*
+* Report fatal error.
+*
+ 50 FATAL = .TRUE.
+ WRITE( NOUT, FMT = 9999 )
+ DO 60 I = 1, ML
+ IF( MV )THEN
+ WRITE( NOUT, FMT = 9998 )I, YT( I ),
+ $ YY( 1 + ( I - 1 )*ABS( INCY ) )
+ ELSE
+ WRITE( NOUT, FMT = 9998 )I,
+ $ YY( 1 + ( I - 1 )*ABS( INCY ) ), YT(I)
+ END IF
+ 60 CONTINUE
+*
+ 70 CONTINUE
+ RETURN
+*
+ 9999 FORMAT( ' ******* FATAL ERROR - COMPUTED RESULT IS LESS THAN HAL',
+ $ 'F ACCURATE *******', /' EXPECTED RESULT COMPU',
+ $ 'TED RESULT' )
+ 9998 FORMAT( 1X, I7, 2G18.6 )
+*
+* End of SMVCH.
+*
+ END
+ LOGICAL FUNCTION LSE( RI, RJ, LR )
+*
+* Tests if two arrays are identical.
+*
+* Auxiliary routine for test program for Level 2 Blas.
+*
+* -- Written on 10-August-1987.
+* Richard Hanson, Sandia National Labs.
+* Jeremy Du Croz, NAG Central Office.
+*
+* .. Scalar Arguments ..
+ INTEGER LR
+* .. Array Arguments ..
+ REAL RI( * ), RJ( * )
+* .. Local Scalars ..
+ INTEGER I
+* .. Executable Statements ..
+ DO 10 I = 1, LR
+ IF( RI( I ).NE.RJ( I ) )
+ $ GO TO 20
+ 10 CONTINUE
+ LSE = .TRUE.
+ GO TO 30
+ 20 CONTINUE
+ LSE = .FALSE.
+ 30 RETURN
+*
+* End of LSE.
+*
+ END
+ LOGICAL FUNCTION LSERES( TYPE, UPLO, M, N, AA, AS, LDA )
+*
+* Tests if selected elements in two arrays are equal.
+*
+* TYPE is 'GE', 'SY' or 'SP'.
+*
+* Auxiliary routine for test program for Level 2 Blas.
+*
+* -- Written on 10-August-1987.
+* Richard Hanson, Sandia National Labs.
+* Jeremy Du Croz, NAG Central Office.
+*
+* .. Scalar Arguments ..
+ INTEGER LDA, M, N
+ CHARACTER*1 UPLO
+ CHARACTER*2 TYPE
+* .. Array Arguments ..
+ REAL AA( LDA, * ), AS( LDA, * )
+* .. Local Scalars ..
+ INTEGER I, IBEG, IEND, J
+ LOGICAL UPPER
+* .. Executable Statements ..
+ UPPER = UPLO.EQ.'U'
+ IF( TYPE.EQ.'GE' )THEN
+ DO 20 J = 1, N
+ DO 10 I = M + 1, LDA
+ IF( AA( I, J ).NE.AS( I, J ) )
+ $ GO TO 70
+ 10 CONTINUE
+ 20 CONTINUE
+ ELSE IF( TYPE.EQ.'SY' )THEN
+ DO 50 J = 1, N
+ IF( UPPER )THEN
+ IBEG = 1
+ IEND = J
+ ELSE
+ IBEG = J
+ IEND = N
+ END IF
+ DO 30 I = 1, IBEG - 1
+ IF( AA( I, J ).NE.AS( I, J ) )
+ $ GO TO 70
+ 30 CONTINUE
+ DO 40 I = IEND + 1, LDA
+ IF( AA( I, J ).NE.AS( I, J ) )
+ $ GO TO 70
+ 40 CONTINUE
+ 50 CONTINUE
+ END IF
+*
+ 60 CONTINUE
+ LSERES = .TRUE.
+ GO TO 80
+ 70 CONTINUE
+ LSERES = .FALSE.
+ 80 RETURN
+*
+* End of LSERES.
+*
+ END
+ REAL FUNCTION SBEG( RESET )
+*
+* Generates random numbers uniformly distributed between -0.5 and 0.5.
+*
+* Auxiliary routine for test program for Level 2 Blas.
+*
+* -- Written on 10-August-1987.
+* Richard Hanson, Sandia National Labs.
+* Jeremy Du Croz, NAG Central Office.
+*
+* .. Scalar Arguments ..
+ LOGICAL RESET
+* .. Local Scalars ..
+ INTEGER I, IC, MI
+* .. Save statement ..
+ SAVE I, IC, MI
+* .. Intrinsic Functions ..
+ INTRINSIC REAL
+* .. Executable Statements ..
+ IF( RESET )THEN
+* Initialize local variables.
+ MI = 891
+ I = 7
+ IC = 0
+ RESET = .FALSE.
+ END IF
+*
+* The sequence of values of I is bounded between 1 and 999.
+* If initial I = 1,2,3,6,7 or 9, the period will be 50.
+* If initial I = 4 or 8, the period will be 25.
+* If initial I = 5, the period will be 10.
+* IC is used to break up the period by skipping 1 value of I in 6.
+*
+ IC = IC + 1
+ 10 I = I*MI
+ I = I - 1000*( I/1000 )
+ IF( IC.GE.5 )THEN
+ IC = 0
+ GO TO 10
+ END IF
+ SBEG = REAL( I - 500 )/1001.0
+ RETURN
+*
+* End of SBEG.
+*
+ END
+ REAL FUNCTION SDIFF( X, Y )
+*
+* Auxiliary routine for test program for Level 2 Blas.
+*
+* -- Written on 10-August-1987.
+* Richard Hanson, Sandia National Labs.
+*
+* .. Scalar Arguments ..
+ REAL X, Y
+* .. Executable Statements ..
+ SDIFF = X - Y
+ RETURN
+*
+* End of SDIFF.
+*
+ END
+ SUBROUTINE CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+*
+* Tests whether XERBLA has detected an error when it should.
+*
+* Auxiliary routine for test program for Level 2 Blas.
+*
+* -- Written on 10-August-1987.
+* Richard Hanson, Sandia National Labs.
+* Jeremy Du Croz, NAG Central Office.
+*
+* .. Scalar Arguments ..
+ INTEGER INFOT, NOUT
+ LOGICAL LERR, OK
+ CHARACTER*6 SRNAMT
+* .. Executable Statements ..
+ IF( .NOT.LERR )THEN
+ WRITE( NOUT, FMT = 9999 )INFOT, SRNAMT
+ OK = .FALSE.
+ END IF
+ LERR = .FALSE.
+ RETURN
+*
+ 9999 FORMAT( ' ***** ILLEGAL VALUE OF PARAMETER NUMBER ', I2, ' NOT D',
+ $ 'ETECTED BY ', A6, ' *****' )
+*
+* End of CHKXER.
+*
+ END
+ SUBROUTINE XERBLA( SRNAME, INFO )
+*
+* This is a special version of XERBLA to be used only as part of
+* the test program for testing error exits from the Level 2 BLAS
+* routines.
+*
+* XERBLA is an error handler for the Level 2 BLAS routines.
+*
+* It is called by the Level 2 BLAS routines if an input parameter is
+* invalid.
+*
+* Auxiliary routine for test program for Level 2 Blas.
+*
+* -- Written on 10-August-1987.
+* Richard Hanson, Sandia National Labs.
+* Jeremy Du Croz, NAG Central Office.
+*
+* .. Scalar Arguments ..
+ INTEGER INFO
+ CHARACTER*6 SRNAME
+* .. Scalars in Common ..
+ INTEGER INFOT, NOUT
+ LOGICAL LERR, OK
+ CHARACTER*6 SRNAMT
+* .. Common blocks ..
+ COMMON /INFOC/INFOT, NOUT, OK, LERR
+ COMMON /SRNAMC/SRNAMT
+* .. Executable Statements ..
+ LERR = .TRUE.
+ IF( INFO.NE.INFOT )THEN
+ IF( INFOT.NE.0 )THEN
+ WRITE( NOUT, FMT = 9999 )INFO, INFOT
+ ELSE
+ WRITE( NOUT, FMT = 9997 )INFO
+ END IF
+ OK = .FALSE.
+ END IF
+ IF( SRNAME.NE.SRNAMT )THEN
+ WRITE( NOUT, FMT = 9998 )SRNAME, SRNAMT
+ OK = .FALSE.
+ END IF
+ RETURN
+*
+ 9999 FORMAT( ' ******* XERBLA WAS CALLED WITH INFO = ', I6, ' INSTEAD',
+ $ ' OF ', I2, ' *******' )
+ 9998 FORMAT( ' ******* XERBLA WAS CALLED WITH SRNAME = ', A6, ' INSTE',
+ $ 'AD OF ', A6, ' *******' )
+ 9997 FORMAT( ' ******* XERBLA WAS CALLED WITH INFO = ', I6,
+ $ ' *******' )
+*
+* End of XERBLA
+*
+ END
+
diff --git a/blas/testing/sblat3.dat b/blas/testing/sblat3.dat
new file mode 100644
index 000000000..680e73606
--- /dev/null
+++ b/blas/testing/sblat3.dat
@@ -0,0 +1,20 @@
+'sblat3.summ' NAME OF SUMMARY OUTPUT FILE
+6 UNIT NUMBER OF SUMMARY FILE
+'sblat3.snap' NAME OF SNAPSHOT OUTPUT FILE
+-1 UNIT NUMBER OF SNAPSHOT FILE (NOT USED IF .LT. 0)
+F LOGICAL FLAG, T TO REWIND SNAPSHOT FILE AFTER EACH RECORD.
+F LOGICAL FLAG, T TO STOP ON FAILURES.
+T LOGICAL FLAG, T TO TEST ERROR EXITS.
+16.0 THRESHOLD VALUE OF TEST RATIO
+6 NUMBER OF VALUES OF N
+0 1 2 3 5 9 VALUES OF N
+3 NUMBER OF VALUES OF ALPHA
+0.0 1.0 0.7 VALUES OF ALPHA
+3 NUMBER OF VALUES OF BETA
+0.0 1.0 1.3 VALUES OF BETA
+SGEMM T PUT F FOR NO TEST. SAME COLUMNS.
+SSYMM T PUT F FOR NO TEST. SAME COLUMNS.
+STRMM T PUT F FOR NO TEST. SAME COLUMNS.
+STRSM T PUT F FOR NO TEST. SAME COLUMNS.
+SSYRK T PUT F FOR NO TEST. SAME COLUMNS.
+SSYR2K T PUT F FOR NO TEST. SAME COLUMNS.
diff --git a/blas/testing/sblat3.f b/blas/testing/sblat3.f
new file mode 100644
index 000000000..325a9eb92
--- /dev/null
+++ b/blas/testing/sblat3.f
@@ -0,0 +1,2823 @@
+ PROGRAM SBLAT3
+*
+* Test program for the REAL Level 3 Blas.
+*
+* The program must be driven by a short data file. The first 14 records
+* of the file are read using list-directed input, the last 6 records
+* are read using the format ( A6, L2 ). An annotated example of a data
+* file can be obtained by deleting the first 3 characters from the
+* following 20 lines:
+* 'SBLAT3.SUMM' NAME OF SUMMARY OUTPUT FILE
+* 6 UNIT NUMBER OF SUMMARY FILE
+* 'SBLAT3.SNAP' NAME OF SNAPSHOT OUTPUT FILE
+* -1 UNIT NUMBER OF SNAPSHOT FILE (NOT USED IF .LT. 0)
+* F LOGICAL FLAG, T TO REWIND SNAPSHOT FILE AFTER EACH RECORD.
+* F LOGICAL FLAG, T TO STOP ON FAILURES.
+* T LOGICAL FLAG, T TO TEST ERROR EXITS.
+* 16.0 THRESHOLD VALUE OF TEST RATIO
+* 6 NUMBER OF VALUES OF N
+* 0 1 2 3 5 9 VALUES OF N
+* 3 NUMBER OF VALUES OF ALPHA
+* 0.0 1.0 0.7 VALUES OF ALPHA
+* 3 NUMBER OF VALUES OF BETA
+* 0.0 1.0 1.3 VALUES OF BETA
+* SGEMM T PUT F FOR NO TEST. SAME COLUMNS.
+* SSYMM T PUT F FOR NO TEST. SAME COLUMNS.
+* STRMM T PUT F FOR NO TEST. SAME COLUMNS.
+* STRSM T PUT F FOR NO TEST. SAME COLUMNS.
+* SSYRK T PUT F FOR NO TEST. SAME COLUMNS.
+* SSYR2K T PUT F FOR NO TEST. SAME COLUMNS.
+*
+* See:
+*
+* Dongarra J. J., Du Croz J. J., Duff I. S. and Hammarling S.
+* A Set of Level 3 Basic Linear Algebra Subprograms.
+*
+* Technical Memorandum No.88 (Revision 1), Mathematics and
+* Computer Science Division, Argonne National Laboratory, 9700
+* South Cass Avenue, Argonne, Illinois 60439, US.
+*
+* -- Written on 8-February-1989.
+* Jack Dongarra, Argonne National Laboratory.
+* Iain Duff, AERE Harwell.
+* Jeremy Du Croz, Numerical Algorithms Group Ltd.
+* Sven Hammarling, Numerical Algorithms Group Ltd.
+*
+* .. Parameters ..
+ INTEGER NIN
+ PARAMETER ( NIN = 5 )
+ INTEGER NSUBS
+ PARAMETER ( NSUBS = 6 )
+ REAL ZERO, HALF, ONE
+ PARAMETER ( ZERO = 0.0, HALF = 0.5, ONE = 1.0 )
+ INTEGER NMAX
+ PARAMETER ( NMAX = 65 )
+ INTEGER NIDMAX, NALMAX, NBEMAX
+ PARAMETER ( NIDMAX = 9, NALMAX = 7, NBEMAX = 7 )
+* .. Local Scalars ..
+ REAL EPS, ERR, THRESH
+ INTEGER I, ISNUM, J, N, NALF, NBET, NIDIM, NOUT, NTRA
+ LOGICAL FATAL, LTESTT, REWI, SAME, SFATAL, TRACE,
+ $ TSTERR
+ CHARACTER*1 TRANSA, TRANSB
+ CHARACTER*6 SNAMET
+ CHARACTER*32 SNAPS, SUMMRY
+* .. Local Arrays ..
+ REAL AA( NMAX*NMAX ), AB( NMAX, 2*NMAX ),
+ $ ALF( NALMAX ), AS( NMAX*NMAX ),
+ $ BB( NMAX*NMAX ), BET( NBEMAX ),
+ $ BS( NMAX*NMAX ), C( NMAX, NMAX ),
+ $ CC( NMAX*NMAX ), CS( NMAX*NMAX ), CT( NMAX ),
+ $ G( NMAX ), W( 2*NMAX )
+ INTEGER IDIM( NIDMAX )
+ LOGICAL LTEST( NSUBS )
+ CHARACTER*6 SNAMES( NSUBS )
+* .. External Functions ..
+ REAL SDIFF
+ LOGICAL LSE
+ EXTERNAL SDIFF, LSE
+* .. External Subroutines ..
+ EXTERNAL SCHK1, SCHK2, SCHK3, SCHK4, SCHK5, SCHKE, SMMCH
+* .. Intrinsic Functions ..
+ INTRINSIC MAX, MIN
+* .. Scalars in Common ..
+ INTEGER INFOT, NOUTC
+ LOGICAL LERR, OK
+ CHARACTER*6 SRNAMT
+* .. Common blocks ..
+ COMMON /INFOC/INFOT, NOUTC, OK, LERR
+ COMMON /SRNAMC/SRNAMT
+* .. Data statements ..
+ DATA SNAMES/'SGEMM ', 'SSYMM ', 'STRMM ', 'STRSM ',
+ $ 'SSYRK ', 'SSYR2K'/
+* .. Executable Statements ..
+*
+* Read name and unit number for summary output file and open file.
+*
+ READ( NIN, FMT = * )SUMMRY
+ READ( NIN, FMT = * )NOUT
+ OPEN( NOUT, FILE = SUMMRY, STATUS = 'NEW' )
+ NOUTC = NOUT
+*
+* Read name and unit number for snapshot output file and open file.
+*
+ READ( NIN, FMT = * )SNAPS
+ READ( NIN, FMT = * )NTRA
+ TRACE = NTRA.GE.0
+ IF( TRACE )THEN
+ OPEN( NTRA, FILE = SNAPS, STATUS = 'NEW' )
+ END IF
+* Read the flag that directs rewinding of the snapshot file.
+ READ( NIN, FMT = * )REWI
+ REWI = REWI.AND.TRACE
+* Read the flag that directs stopping on any failure.
+ READ( NIN, FMT = * )SFATAL
+* Read the flag that indicates whether error exits are to be tested.
+ READ( NIN, FMT = * )TSTERR
+* Read the threshold value of the test ratio
+ READ( NIN, FMT = * )THRESH
+*
+* Read and check the parameter values for the tests.
+*
+* Values of N
+ READ( NIN, FMT = * )NIDIM
+ IF( NIDIM.LT.1.OR.NIDIM.GT.NIDMAX )THEN
+ WRITE( NOUT, FMT = 9997 )'N', NIDMAX
+ GO TO 220
+ END IF
+ READ( NIN, FMT = * )( IDIM( I ), I = 1, NIDIM )
+ DO 10 I = 1, NIDIM
+ IF( IDIM( I ).LT.0.OR.IDIM( I ).GT.NMAX )THEN
+ WRITE( NOUT, FMT = 9996 )NMAX
+ GO TO 220
+ END IF
+ 10 CONTINUE
+* Values of ALPHA
+ READ( NIN, FMT = * )NALF
+ IF( NALF.LT.1.OR.NALF.GT.NALMAX )THEN
+ WRITE( NOUT, FMT = 9997 )'ALPHA', NALMAX
+ GO TO 220
+ END IF
+ READ( NIN, FMT = * )( ALF( I ), I = 1, NALF )
+* Values of BETA
+ READ( NIN, FMT = * )NBET
+ IF( NBET.LT.1.OR.NBET.GT.NBEMAX )THEN
+ WRITE( NOUT, FMT = 9997 )'BETA', NBEMAX
+ GO TO 220
+ END IF
+ READ( NIN, FMT = * )( BET( I ), I = 1, NBET )
+*
+* Report values of parameters.
+*
+ WRITE( NOUT, FMT = 9995 )
+ WRITE( NOUT, FMT = 9994 )( IDIM( I ), I = 1, NIDIM )
+ WRITE( NOUT, FMT = 9993 )( ALF( I ), I = 1, NALF )
+ WRITE( NOUT, FMT = 9992 )( BET( I ), I = 1, NBET )
+ IF( .NOT.TSTERR )THEN
+ WRITE( NOUT, FMT = * )
+ WRITE( NOUT, FMT = 9984 )
+ END IF
+ WRITE( NOUT, FMT = * )
+ WRITE( NOUT, FMT = 9999 )THRESH
+ WRITE( NOUT, FMT = * )
+*
+* Read names of subroutines and flags which indicate
+* whether they are to be tested.
+*
+ DO 20 I = 1, NSUBS
+ LTEST( I ) = .FALSE.
+ 20 CONTINUE
+ 30 READ( NIN, FMT = 9988, END = 60 )SNAMET, LTESTT
+ DO 40 I = 1, NSUBS
+ IF( SNAMET.EQ.SNAMES( I ) )
+ $ GO TO 50
+ 40 CONTINUE
+ WRITE( NOUT, FMT = 9990 )SNAMET
+ STOP
+ 50 LTEST( I ) = LTESTT
+ GO TO 30
+*
+ 60 CONTINUE
+ CLOSE ( NIN )
+*
+* Compute EPS (the machine precision).
+*
+ EPS = ONE
+ 70 CONTINUE
+ IF( SDIFF( ONE + EPS, ONE ).EQ.ZERO )
+ $ GO TO 80
+ EPS = HALF*EPS
+ GO TO 70
+ 80 CONTINUE
+ EPS = EPS + EPS
+ WRITE( NOUT, FMT = 9998 )EPS
+*
+* Check the reliability of SMMCH using exact data.
+*
+ N = MIN( 32, NMAX )
+ DO 100 J = 1, N
+ DO 90 I = 1, N
+ AB( I, J ) = MAX( I - J + 1, 0 )
+ 90 CONTINUE
+ AB( J, NMAX + 1 ) = J
+ AB( 1, NMAX + J ) = J
+ C( J, 1 ) = ZERO
+ 100 CONTINUE
+ DO 110 J = 1, N
+ CC( J ) = J*( ( J + 1 )*J )/2 - ( ( J + 1 )*J*( J - 1 ) )/3
+ 110 CONTINUE
+* CC holds the exact result. On exit from SMMCH CT holds
+* the result computed by SMMCH.
+ TRANSA = 'N'
+ TRANSB = 'N'
+ CALL SMMCH( TRANSA, TRANSB, N, 1, N, ONE, AB, NMAX,
+ $ AB( 1, NMAX + 1 ), NMAX, ZERO, C, NMAX, CT, G, CC,
+ $ NMAX, EPS, ERR, FATAL, NOUT, .TRUE. )
+ SAME = LSE( CC, CT, N )
+ IF( .NOT.SAME.OR.ERR.NE.ZERO )THEN
+ WRITE( NOUT, FMT = 9989 )TRANSA, TRANSB, SAME, ERR
+ STOP
+ END IF
+ TRANSB = 'T'
+ CALL SMMCH( TRANSA, TRANSB, N, 1, N, ONE, AB, NMAX,
+ $ AB( 1, NMAX + 1 ), NMAX, ZERO, C, NMAX, CT, G, CC,
+ $ NMAX, EPS, ERR, FATAL, NOUT, .TRUE. )
+ SAME = LSE( CC, CT, N )
+ IF( .NOT.SAME.OR.ERR.NE.ZERO )THEN
+ WRITE( NOUT, FMT = 9989 )TRANSA, TRANSB, SAME, ERR
+ STOP
+ END IF
+ DO 120 J = 1, N
+ AB( J, NMAX + 1 ) = N - J + 1
+ AB( 1, NMAX + J ) = N - J + 1
+ 120 CONTINUE
+ DO 130 J = 1, N
+ CC( N - J + 1 ) = J*( ( J + 1 )*J )/2 -
+ $ ( ( J + 1 )*J*( J - 1 ) )/3
+ 130 CONTINUE
+ TRANSA = 'T'
+ TRANSB = 'N'
+ CALL SMMCH( TRANSA, TRANSB, N, 1, N, ONE, AB, NMAX,
+ $ AB( 1, NMAX + 1 ), NMAX, ZERO, C, NMAX, CT, G, CC,
+ $ NMAX, EPS, ERR, FATAL, NOUT, .TRUE. )
+ SAME = LSE( CC, CT, N )
+ IF( .NOT.SAME.OR.ERR.NE.ZERO )THEN
+ WRITE( NOUT, FMT = 9989 )TRANSA, TRANSB, SAME, ERR
+ STOP
+ END IF
+ TRANSB = 'T'
+ CALL SMMCH( TRANSA, TRANSB, N, 1, N, ONE, AB, NMAX,
+ $ AB( 1, NMAX + 1 ), NMAX, ZERO, C, NMAX, CT, G, CC,
+ $ NMAX, EPS, ERR, FATAL, NOUT, .TRUE. )
+ SAME = LSE( CC, CT, N )
+ IF( .NOT.SAME.OR.ERR.NE.ZERO )THEN
+ WRITE( NOUT, FMT = 9989 )TRANSA, TRANSB, SAME, ERR
+ STOP
+ END IF
+*
+* Test each subroutine in turn.
+*
+ DO 200 ISNUM = 1, NSUBS
+ WRITE( NOUT, FMT = * )
+ IF( .NOT.LTEST( ISNUM ) )THEN
+* Subprogram is not to be tested.
+ WRITE( NOUT, FMT = 9987 )SNAMES( ISNUM )
+ ELSE
+ SRNAMT = SNAMES( ISNUM )
+* Test error exits.
+ IF( TSTERR )THEN
+ CALL SCHKE( ISNUM, SNAMES( ISNUM ), NOUT )
+ WRITE( NOUT, FMT = * )
+ END IF
+* Test computations.
+ INFOT = 0
+ OK = .TRUE.
+ FATAL = .FALSE.
+ GO TO ( 140, 150, 160, 160, 170, 180 )ISNUM
+* Test SGEMM, 01.
+ 140 CALL SCHK1( SNAMES( ISNUM ), EPS, THRESH, NOUT, NTRA, TRACE,
+ $ REWI, FATAL, NIDIM, IDIM, NALF, ALF, NBET, BET,
+ $ NMAX, AB, AA, AS, AB( 1, NMAX + 1 ), BB, BS, C,
+ $ CC, CS, CT, G )
+ GO TO 190
+* Test SSYMM, 02.
+ 150 CALL SCHK2( SNAMES( ISNUM ), EPS, THRESH, NOUT, NTRA, TRACE,
+ $ REWI, FATAL, NIDIM, IDIM, NALF, ALF, NBET, BET,
+ $ NMAX, AB, AA, AS, AB( 1, NMAX + 1 ), BB, BS, C,
+ $ CC, CS, CT, G )
+ GO TO 190
+* Test STRMM, 03, STRSM, 04.
+ 160 CALL SCHK3( SNAMES( ISNUM ), EPS, THRESH, NOUT, NTRA, TRACE,
+ $ REWI, FATAL, NIDIM, IDIM, NALF, ALF, NMAX, AB,
+ $ AA, AS, AB( 1, NMAX + 1 ), BB, BS, CT, G, C )
+ GO TO 190
+* Test SSYRK, 05.
+ 170 CALL SCHK4( SNAMES( ISNUM ), EPS, THRESH, NOUT, NTRA, TRACE,
+ $ REWI, FATAL, NIDIM, IDIM, NALF, ALF, NBET, BET,
+ $ NMAX, AB, AA, AS, AB( 1, NMAX + 1 ), BB, BS, C,
+ $ CC, CS, CT, G )
+ GO TO 190
+* Test SSYR2K, 06.
+ 180 CALL SCHK5( SNAMES( ISNUM ), EPS, THRESH, NOUT, NTRA, TRACE,
+ $ REWI, FATAL, NIDIM, IDIM, NALF, ALF, NBET, BET,
+ $ NMAX, AB, AA, AS, BB, BS, C, CC, CS, CT, G, W )
+ GO TO 190
+*
+ 190 IF( FATAL.AND.SFATAL )
+ $ GO TO 210
+ END IF
+ 200 CONTINUE
+ WRITE( NOUT, FMT = 9986 )
+ GO TO 230
+*
+ 210 CONTINUE
+ WRITE( NOUT, FMT = 9985 )
+ GO TO 230
+*
+ 220 CONTINUE
+ WRITE( NOUT, FMT = 9991 )
+*
+ 230 CONTINUE
+ IF( TRACE )
+ $ CLOSE ( NTRA )
+ CLOSE ( NOUT )
+ STOP
+*
+ 9999 FORMAT( ' ROUTINES PASS COMPUTATIONAL TESTS IF TEST RATIO IS LES',
+ $ 'S THAN', F8.2 )
+ 9998 FORMAT( ' RELATIVE MACHINE PRECISION IS TAKEN TO BE', 1P, E9.1 )
+ 9997 FORMAT( ' NUMBER OF VALUES OF ', A, ' IS LESS THAN 1 OR GREATER ',
+ $ 'THAN ', I2 )
+ 9996 FORMAT( ' VALUE OF N IS LESS THAN 0 OR GREATER THAN ', I2 )
+ 9995 FORMAT( ' TESTS OF THE REAL LEVEL 3 BLAS', //' THE F',
+ $ 'OLLOWING PARAMETER VALUES WILL BE USED:' )
+ 9994 FORMAT( ' FOR N ', 9I6 )
+ 9993 FORMAT( ' FOR ALPHA ', 7F6.1 )
+ 9992 FORMAT( ' FOR BETA ', 7F6.1 )
+ 9991 FORMAT( ' AMEND DATA FILE OR INCREASE ARRAY SIZES IN PROGRAM',
+ $ /' ******* TESTS ABANDONED *******' )
+ 9990 FORMAT( ' SUBPROGRAM NAME ', A6, ' NOT RECOGNIZED', /' ******* T',
+ $ 'ESTS ABANDONED *******' )
+ 9989 FORMAT( ' ERROR IN SMMCH - IN-LINE DOT PRODUCTS ARE BEING EVALU',
+ $ 'ATED WRONGLY.', /' SMMCH WAS CALLED WITH TRANSA = ', A1,
+ $ ' AND TRANSB = ', A1, /' AND RETURNED SAME = ', L1, ' AND ',
+ $ 'ERR = ', F12.3, '.', /' THIS MAY BE DUE TO FAULTS IN THE ',
+ $ 'ARITHMETIC OR THE COMPILER.', /' ******* TESTS ABANDONED ',
+ $ '*******' )
+ 9988 FORMAT( A6, L2 )
+ 9987 FORMAT( 1X, A6, ' WAS NOT TESTED' )
+ 9986 FORMAT( /' END OF TESTS' )
+ 9985 FORMAT( /' ******* FATAL ERROR - TESTS ABANDONED *******' )
+ 9984 FORMAT( ' ERROR-EXITS WILL NOT BE TESTED' )
+*
+* End of SBLAT3.
+*
+ END
+ SUBROUTINE SCHK1( SNAME, EPS, THRESH, NOUT, NTRA, TRACE, REWI,
+ $ FATAL, NIDIM, IDIM, NALF, ALF, NBET, BET, NMAX,
+ $ A, AA, AS, B, BB, BS, C, CC, CS, CT, G )
+*
+* Tests SGEMM.
+*
+* Auxiliary routine for test program for Level 3 Blas.
+*
+* -- Written on 8-February-1989.
+* Jack Dongarra, Argonne National Laboratory.
+* Iain Duff, AERE Harwell.
+* Jeremy Du Croz, Numerical Algorithms Group Ltd.
+* Sven Hammarling, Numerical Algorithms Group Ltd.
+*
+* .. Parameters ..
+ REAL ZERO
+ PARAMETER ( ZERO = 0.0 )
+* .. Scalar Arguments ..
+ REAL EPS, THRESH
+ INTEGER NALF, NBET, NIDIM, NMAX, NOUT, NTRA
+ LOGICAL FATAL, REWI, TRACE
+ CHARACTER*6 SNAME
+* .. Array Arguments ..
+ REAL A( NMAX, NMAX ), AA( NMAX*NMAX ), ALF( NALF ),
+ $ AS( NMAX*NMAX ), B( NMAX, NMAX ),
+ $ BB( NMAX*NMAX ), BET( NBET ), BS( NMAX*NMAX ),
+ $ C( NMAX, NMAX ), CC( NMAX*NMAX ),
+ $ CS( NMAX*NMAX ), CT( NMAX ), G( NMAX )
+ INTEGER IDIM( NIDIM )
+* .. Local Scalars ..
+ REAL ALPHA, ALS, BETA, BLS, ERR, ERRMAX
+ INTEGER I, IA, IB, ICA, ICB, IK, IM, IN, K, KS, LAA,
+ $ LBB, LCC, LDA, LDAS, LDB, LDBS, LDC, LDCS, M,
+ $ MA, MB, MS, N, NA, NARGS, NB, NC, NS
+ LOGICAL NULL, RESET, SAME, TRANA, TRANB
+ CHARACTER*1 TRANAS, TRANBS, TRANSA, TRANSB
+ CHARACTER*3 ICH
+* .. Local Arrays ..
+ LOGICAL ISAME( 13 )
+* .. External Functions ..
+ LOGICAL LSE, LSERES
+ EXTERNAL LSE, LSERES
+* .. External Subroutines ..
+ EXTERNAL SGEMM, SMAKE, SMMCH
+* .. Intrinsic Functions ..
+ INTRINSIC MAX
+* .. Scalars in Common ..
+ INTEGER INFOT, NOUTC
+ LOGICAL LERR, OK
+* .. Common blocks ..
+ COMMON /INFOC/INFOT, NOUTC, OK, LERR
+* .. Data statements ..
+ DATA ICH/'NTC'/
+* .. Executable Statements ..
+*
+ NARGS = 13
+ NC = 0
+ RESET = .TRUE.
+ ERRMAX = ZERO
+*
+ DO 110 IM = 1, NIDIM
+ M = IDIM( IM )
+*
+ DO 100 IN = 1, NIDIM
+ N = IDIM( IN )
+* Set LDC to 1 more than minimum value if room.
+ LDC = M
+ IF( LDC.LT.NMAX )
+ $ LDC = LDC + 1
+* Skip tests if not enough room.
+ IF( LDC.GT.NMAX )
+ $ GO TO 100
+ LCC = LDC*N
+ NULL = N.LE.0.OR.M.LE.0
+*
+ DO 90 IK = 1, NIDIM
+ K = IDIM( IK )
+*
+ DO 80 ICA = 1, 3
+ TRANSA = ICH( ICA: ICA )
+ TRANA = TRANSA.EQ.'T'.OR.TRANSA.EQ.'C'
+*
+ IF( TRANA )THEN
+ MA = K
+ NA = M
+ ELSE
+ MA = M
+ NA = K
+ END IF
+* Set LDA to 1 more than minimum value if room.
+ LDA = MA
+ IF( LDA.LT.NMAX )
+ $ LDA = LDA + 1
+* Skip tests if not enough room.
+ IF( LDA.GT.NMAX )
+ $ GO TO 80
+ LAA = LDA*NA
+*
+* Generate the matrix A.
+*
+ CALL SMAKE( 'GE', ' ', ' ', MA, NA, A, NMAX, AA, LDA,
+ $ RESET, ZERO )
+*
+ DO 70 ICB = 1, 3
+ TRANSB = ICH( ICB: ICB )
+ TRANB = TRANSB.EQ.'T'.OR.TRANSB.EQ.'C'
+*
+ IF( TRANB )THEN
+ MB = N
+ NB = K
+ ELSE
+ MB = K
+ NB = N
+ END IF
+* Set LDB to 1 more than minimum value if room.
+ LDB = MB
+ IF( LDB.LT.NMAX )
+ $ LDB = LDB + 1
+* Skip tests if not enough room.
+ IF( LDB.GT.NMAX )
+ $ GO TO 70
+ LBB = LDB*NB
+*
+* Generate the matrix B.
+*
+ CALL SMAKE( 'GE', ' ', ' ', MB, NB, B, NMAX, BB,
+ $ LDB, RESET, ZERO )
+*
+ DO 60 IA = 1, NALF
+ ALPHA = ALF( IA )
+*
+ DO 50 IB = 1, NBET
+ BETA = BET( IB )
+*
+* Generate the matrix C.
+*
+ CALL SMAKE( 'GE', ' ', ' ', M, N, C, NMAX,
+ $ CC, LDC, RESET, ZERO )
+*
+ NC = NC + 1
+*
+* Save every datum before calling the
+* subroutine.
+*
+ TRANAS = TRANSA
+ TRANBS = TRANSB
+ MS = M
+ NS = N
+ KS = K
+ ALS = ALPHA
+ DO 10 I = 1, LAA
+ AS( I ) = AA( I )
+ 10 CONTINUE
+ LDAS = LDA
+ DO 20 I = 1, LBB
+ BS( I ) = BB( I )
+ 20 CONTINUE
+ LDBS = LDB
+ BLS = BETA
+ DO 30 I = 1, LCC
+ CS( I ) = CC( I )
+ 30 CONTINUE
+ LDCS = LDC
+*
+* Call the subroutine.
+*
+ IF( TRACE )
+ $ WRITE( NTRA, FMT = 9995 )NC, SNAME,
+ $ TRANSA, TRANSB, M, N, K, ALPHA, LDA, LDB,
+ $ BETA, LDC
+ IF( REWI )
+ $ REWIND NTRA
+ CALL SGEMM( TRANSA, TRANSB, M, N, K, ALPHA,
+ $ AA, LDA, BB, LDB, BETA, CC, LDC )
+*
+* Check if error-exit was taken incorrectly.
+*
+ IF( .NOT.OK )THEN
+ WRITE( NOUT, FMT = 9994 )
+ FATAL = .TRUE.
+ GO TO 120
+ END IF
+*
+* See what data changed inside subroutines.
+*
+ ISAME( 1 ) = TRANSA.EQ.TRANAS
+ ISAME( 2 ) = TRANSB.EQ.TRANBS
+ ISAME( 3 ) = MS.EQ.M
+ ISAME( 4 ) = NS.EQ.N
+ ISAME( 5 ) = KS.EQ.K
+ ISAME( 6 ) = ALS.EQ.ALPHA
+ ISAME( 7 ) = LSE( AS, AA, LAA )
+ ISAME( 8 ) = LDAS.EQ.LDA
+ ISAME( 9 ) = LSE( BS, BB, LBB )
+ ISAME( 10 ) = LDBS.EQ.LDB
+ ISAME( 11 ) = BLS.EQ.BETA
+ IF( NULL )THEN
+ ISAME( 12 ) = LSE( CS, CC, LCC )
+ ELSE
+ ISAME( 12 ) = LSERES( 'GE', ' ', M, N, CS,
+ $ CC, LDC )
+ END IF
+ ISAME( 13 ) = LDCS.EQ.LDC
+*
+* If data was incorrectly changed, report
+* and return.
+*
+ SAME = .TRUE.
+ DO 40 I = 1, NARGS
+ SAME = SAME.AND.ISAME( I )
+ IF( .NOT.ISAME( I ) )
+ $ WRITE( NOUT, FMT = 9998 )I
+ 40 CONTINUE
+ IF( .NOT.SAME )THEN
+ FATAL = .TRUE.
+ GO TO 120
+ END IF
+*
+ IF( .NOT.NULL )THEN
+*
+* Check the result.
+*
+ CALL SMMCH( TRANSA, TRANSB, M, N, K,
+ $ ALPHA, A, NMAX, B, NMAX, BETA,
+ $ C, NMAX, CT, G, CC, LDC, EPS,
+ $ ERR, FATAL, NOUT, .TRUE. )
+ ERRMAX = MAX( ERRMAX, ERR )
+* If got really bad answer, report and
+* return.
+ IF( FATAL )
+ $ GO TO 120
+ END IF
+*
+ 50 CONTINUE
+*
+ 60 CONTINUE
+*
+ 70 CONTINUE
+*
+ 80 CONTINUE
+*
+ 90 CONTINUE
+*
+ 100 CONTINUE
+*
+ 110 CONTINUE
+*
+* Report result.
+*
+ IF( ERRMAX.LT.THRESH )THEN
+ WRITE( NOUT, FMT = 9999 )SNAME, NC
+ ELSE
+ WRITE( NOUT, FMT = 9997 )SNAME, NC, ERRMAX
+ END IF
+ GO TO 130
+*
+ 120 CONTINUE
+ WRITE( NOUT, FMT = 9996 )SNAME
+ WRITE( NOUT, FMT = 9995 )NC, SNAME, TRANSA, TRANSB, M, N, K,
+ $ ALPHA, LDA, LDB, BETA, LDC
+*
+ 130 CONTINUE
+ RETURN
+*
+ 9999 FORMAT( ' ', A6, ' PASSED THE COMPUTATIONAL TESTS (', I6, ' CALL',
+ $ 'S)' )
+ 9998 FORMAT( ' ******* FATAL ERROR - PARAMETER NUMBER ', I2, ' WAS CH',
+ $ 'ANGED INCORRECTLY *******' )
+ 9997 FORMAT( ' ', A6, ' COMPLETED THE COMPUTATIONAL TESTS (', I6, ' C',
+ $ 'ALLS)', /' ******* BUT WITH MAXIMUM TEST RATIO', F8.2,
+ $ ' - SUSPECT *******' )
+ 9996 FORMAT( ' ******* ', A6, ' FAILED ON CALL NUMBER:' )
+ 9995 FORMAT( 1X, I6, ': ', A6, '(''', A1, ''',''', A1, ''',',
+ $ 3( I3, ',' ), F4.1, ', A,', I3, ', B,', I3, ',', F4.1, ', ',
+ $ 'C,', I3, ').' )
+ 9994 FORMAT( ' ******* FATAL ERROR - ERROR-EXIT TAKEN ON VALID CALL *',
+ $ '******' )
+*
+* End of SCHK1.
+*
+ END
+ SUBROUTINE SCHK2( SNAME, EPS, THRESH, NOUT, NTRA, TRACE, REWI,
+ $ FATAL, NIDIM, IDIM, NALF, ALF, NBET, BET, NMAX,
+ $ A, AA, AS, B, BB, BS, C, CC, CS, CT, G )
+*
+* Tests SSYMM.
+*
+* Auxiliary routine for test program for Level 3 Blas.
+*
+* -- Written on 8-February-1989.
+* Jack Dongarra, Argonne National Laboratory.
+* Iain Duff, AERE Harwell.
+* Jeremy Du Croz, Numerical Algorithms Group Ltd.
+* Sven Hammarling, Numerical Algorithms Group Ltd.
+*
+* .. Parameters ..
+ REAL ZERO
+ PARAMETER ( ZERO = 0.0 )
+* .. Scalar Arguments ..
+ REAL EPS, THRESH
+ INTEGER NALF, NBET, NIDIM, NMAX, NOUT, NTRA
+ LOGICAL FATAL, REWI, TRACE
+ CHARACTER*6 SNAME
+* .. Array Arguments ..
+ REAL A( NMAX, NMAX ), AA( NMAX*NMAX ), ALF( NALF ),
+ $ AS( NMAX*NMAX ), B( NMAX, NMAX ),
+ $ BB( NMAX*NMAX ), BET( NBET ), BS( NMAX*NMAX ),
+ $ C( NMAX, NMAX ), CC( NMAX*NMAX ),
+ $ CS( NMAX*NMAX ), CT( NMAX ), G( NMAX )
+ INTEGER IDIM( NIDIM )
+* .. Local Scalars ..
+ REAL ALPHA, ALS, BETA, BLS, ERR, ERRMAX
+ INTEGER I, IA, IB, ICS, ICU, IM, IN, LAA, LBB, LCC,
+ $ LDA, LDAS, LDB, LDBS, LDC, LDCS, M, MS, N, NA,
+ $ NARGS, NC, NS
+ LOGICAL LEFT, NULL, RESET, SAME
+ CHARACTER*1 SIDE, SIDES, UPLO, UPLOS
+ CHARACTER*2 ICHS, ICHU
+* .. Local Arrays ..
+ LOGICAL ISAME( 13 )
+* .. External Functions ..
+ LOGICAL LSE, LSERES
+ EXTERNAL LSE, LSERES
+* .. External Subroutines ..
+ EXTERNAL SMAKE, SMMCH, SSYMM
+* .. Intrinsic Functions ..
+ INTRINSIC MAX
+* .. Scalars in Common ..
+ INTEGER INFOT, NOUTC
+ LOGICAL LERR, OK
+* .. Common blocks ..
+ COMMON /INFOC/INFOT, NOUTC, OK, LERR
+* .. Data statements ..
+ DATA ICHS/'LR'/, ICHU/'UL'/
+* .. Executable Statements ..
+*
+ NARGS = 12
+ NC = 0
+ RESET = .TRUE.
+ ERRMAX = ZERO
+*
+ DO 100 IM = 1, NIDIM
+ M = IDIM( IM )
+*
+ DO 90 IN = 1, NIDIM
+ N = IDIM( IN )
+* Set LDC to 1 more than minimum value if room.
+ LDC = M
+ IF( LDC.LT.NMAX )
+ $ LDC = LDC + 1
+* Skip tests if not enough room.
+ IF( LDC.GT.NMAX )
+ $ GO TO 90
+ LCC = LDC*N
+ NULL = N.LE.0.OR.M.LE.0
+*
+* Set LDB to 1 more than minimum value if room.
+ LDB = M
+ IF( LDB.LT.NMAX )
+ $ LDB = LDB + 1
+* Skip tests if not enough room.
+ IF( LDB.GT.NMAX )
+ $ GO TO 90
+ LBB = LDB*N
+*
+* Generate the matrix B.
+*
+ CALL SMAKE( 'GE', ' ', ' ', M, N, B, NMAX, BB, LDB, RESET,
+ $ ZERO )
+*
+ DO 80 ICS = 1, 2
+ SIDE = ICHS( ICS: ICS )
+ LEFT = SIDE.EQ.'L'
+*
+ IF( LEFT )THEN
+ NA = M
+ ELSE
+ NA = N
+ END IF
+* Set LDA to 1 more than minimum value if room.
+ LDA = NA
+ IF( LDA.LT.NMAX )
+ $ LDA = LDA + 1
+* Skip tests if not enough room.
+ IF( LDA.GT.NMAX )
+ $ GO TO 80
+ LAA = LDA*NA
+*
+ DO 70 ICU = 1, 2
+ UPLO = ICHU( ICU: ICU )
+*
+* Generate the symmetric matrix A.
+*
+ CALL SMAKE( 'SY', UPLO, ' ', NA, NA, A, NMAX, AA, LDA,
+ $ RESET, ZERO )
+*
+ DO 60 IA = 1, NALF
+ ALPHA = ALF( IA )
+*
+ DO 50 IB = 1, NBET
+ BETA = BET( IB )
+*
+* Generate the matrix C.
+*
+ CALL SMAKE( 'GE', ' ', ' ', M, N, C, NMAX, CC,
+ $ LDC, RESET, ZERO )
+*
+ NC = NC + 1
+*
+* Save every datum before calling the
+* subroutine.
+*
+ SIDES = SIDE
+ UPLOS = UPLO
+ MS = M
+ NS = N
+ ALS = ALPHA
+ DO 10 I = 1, LAA
+ AS( I ) = AA( I )
+ 10 CONTINUE
+ LDAS = LDA
+ DO 20 I = 1, LBB
+ BS( I ) = BB( I )
+ 20 CONTINUE
+ LDBS = LDB
+ BLS = BETA
+ DO 30 I = 1, LCC
+ CS( I ) = CC( I )
+ 30 CONTINUE
+ LDCS = LDC
+*
+* Call the subroutine.
+*
+ IF( TRACE )
+ $ WRITE( NTRA, FMT = 9995 )NC, SNAME, SIDE,
+ $ UPLO, M, N, ALPHA, LDA, LDB, BETA, LDC
+ IF( REWI )
+ $ REWIND NTRA
+ CALL SSYMM( SIDE, UPLO, M, N, ALPHA, AA, LDA,
+ $ BB, LDB, BETA, CC, LDC )
+*
+* Check if error-exit was taken incorrectly.
+*
+ IF( .NOT.OK )THEN
+ WRITE( NOUT, FMT = 9994 )
+ FATAL = .TRUE.
+ GO TO 110
+ END IF
+*
+* See what data changed inside subroutines.
+*
+ ISAME( 1 ) = SIDES.EQ.SIDE
+ ISAME( 2 ) = UPLOS.EQ.UPLO
+ ISAME( 3 ) = MS.EQ.M
+ ISAME( 4 ) = NS.EQ.N
+ ISAME( 5 ) = ALS.EQ.ALPHA
+ ISAME( 6 ) = LSE( AS, AA, LAA )
+ ISAME( 7 ) = LDAS.EQ.LDA
+ ISAME( 8 ) = LSE( BS, BB, LBB )
+ ISAME( 9 ) = LDBS.EQ.LDB
+ ISAME( 10 ) = BLS.EQ.BETA
+ IF( NULL )THEN
+ ISAME( 11 ) = LSE( CS, CC, LCC )
+ ELSE
+ ISAME( 11 ) = LSERES( 'GE', ' ', M, N, CS,
+ $ CC, LDC )
+ END IF
+ ISAME( 12 ) = LDCS.EQ.LDC
+*
+* If data was incorrectly changed, report and
+* return.
+*
+ SAME = .TRUE.
+ DO 40 I = 1, NARGS
+ SAME = SAME.AND.ISAME( I )
+ IF( .NOT.ISAME( I ) )
+ $ WRITE( NOUT, FMT = 9998 )I
+ 40 CONTINUE
+ IF( .NOT.SAME )THEN
+ FATAL = .TRUE.
+ GO TO 110
+ END IF
+*
+ IF( .NOT.NULL )THEN
+*
+* Check the result.
+*
+ IF( LEFT )THEN
+ CALL SMMCH( 'N', 'N', M, N, M, ALPHA, A,
+ $ NMAX, B, NMAX, BETA, C, NMAX,
+ $ CT, G, CC, LDC, EPS, ERR,
+ $ FATAL, NOUT, .TRUE. )
+ ELSE
+ CALL SMMCH( 'N', 'N', M, N, N, ALPHA, B,
+ $ NMAX, A, NMAX, BETA, C, NMAX,
+ $ CT, G, CC, LDC, EPS, ERR,
+ $ FATAL, NOUT, .TRUE. )
+ END IF
+ ERRMAX = MAX( ERRMAX, ERR )
+* If got really bad answer, report and
+* return.
+ IF( FATAL )
+ $ GO TO 110
+ END IF
+*
+ 50 CONTINUE
+*
+ 60 CONTINUE
+*
+ 70 CONTINUE
+*
+ 80 CONTINUE
+*
+ 90 CONTINUE
+*
+ 100 CONTINUE
+*
+* Report result.
+*
+ IF( ERRMAX.LT.THRESH )THEN
+ WRITE( NOUT, FMT = 9999 )SNAME, NC
+ ELSE
+ WRITE( NOUT, FMT = 9997 )SNAME, NC, ERRMAX
+ END IF
+ GO TO 120
+*
+ 110 CONTINUE
+ WRITE( NOUT, FMT = 9996 )SNAME
+ WRITE( NOUT, FMT = 9995 )NC, SNAME, SIDE, UPLO, M, N, ALPHA, LDA,
+ $ LDB, BETA, LDC
+*
+ 120 CONTINUE
+ RETURN
+*
+ 9999 FORMAT( ' ', A6, ' PASSED THE COMPUTATIONAL TESTS (', I6, ' CALL',
+ $ 'S)' )
+ 9998 FORMAT( ' ******* FATAL ERROR - PARAMETER NUMBER ', I2, ' WAS CH',
+ $ 'ANGED INCORRECTLY *******' )
+ 9997 FORMAT( ' ', A6, ' COMPLETED THE COMPUTATIONAL TESTS (', I6, ' C',
+ $ 'ALLS)', /' ******* BUT WITH MAXIMUM TEST RATIO', F8.2,
+ $ ' - SUSPECT *******' )
+ 9996 FORMAT( ' ******* ', A6, ' FAILED ON CALL NUMBER:' )
+ 9995 FORMAT( 1X, I6, ': ', A6, '(', 2( '''', A1, ''',' ), 2( I3, ',' ),
+ $ F4.1, ', A,', I3, ', B,', I3, ',', F4.1, ', C,', I3, ') ',
+ $ ' .' )
+ 9994 FORMAT( ' ******* FATAL ERROR - ERROR-EXIT TAKEN ON VALID CALL *',
+ $ '******' )
+*
+* End of SCHK2.
+*
+ END
+ SUBROUTINE SCHK3( SNAME, EPS, THRESH, NOUT, NTRA, TRACE, REWI,
+ $ FATAL, NIDIM, IDIM, NALF, ALF, NMAX, A, AA, AS,
+ $ B, BB, BS, CT, G, C )
+*
+* Tests STRMM and STRSM.
+*
+* Auxiliary routine for test program for Level 3 Blas.
+*
+* -- Written on 8-February-1989.
+* Jack Dongarra, Argonne National Laboratory.
+* Iain Duff, AERE Harwell.
+* Jeremy Du Croz, Numerical Algorithms Group Ltd.
+* Sven Hammarling, Numerical Algorithms Group Ltd.
+*
+* .. Parameters ..
+ REAL ZERO, ONE
+ PARAMETER ( ZERO = 0.0, ONE = 1.0 )
+* .. Scalar Arguments ..
+ REAL EPS, THRESH
+ INTEGER NALF, NIDIM, NMAX, NOUT, NTRA
+ LOGICAL FATAL, REWI, TRACE
+ CHARACTER*6 SNAME
+* .. Array Arguments ..
+ REAL A( NMAX, NMAX ), AA( NMAX*NMAX ), ALF( NALF ),
+ $ AS( NMAX*NMAX ), B( NMAX, NMAX ),
+ $ BB( NMAX*NMAX ), BS( NMAX*NMAX ),
+ $ C( NMAX, NMAX ), CT( NMAX ), G( NMAX )
+ INTEGER IDIM( NIDIM )
+* .. Local Scalars ..
+ REAL ALPHA, ALS, ERR, ERRMAX
+ INTEGER I, IA, ICD, ICS, ICT, ICU, IM, IN, J, LAA, LBB,
+ $ LDA, LDAS, LDB, LDBS, M, MS, N, NA, NARGS, NC,
+ $ NS
+ LOGICAL LEFT, NULL, RESET, SAME
+ CHARACTER*1 DIAG, DIAGS, SIDE, SIDES, TRANAS, TRANSA, UPLO,
+ $ UPLOS
+ CHARACTER*2 ICHD, ICHS, ICHU
+ CHARACTER*3 ICHT
+* .. Local Arrays ..
+ LOGICAL ISAME( 13 )
+* .. External Functions ..
+ LOGICAL LSE, LSERES
+ EXTERNAL LSE, LSERES
+* .. External Subroutines ..
+ EXTERNAL SMAKE, SMMCH, STRMM, STRSM
+* .. Intrinsic Functions ..
+ INTRINSIC MAX
+* .. Scalars in Common ..
+ INTEGER INFOT, NOUTC
+ LOGICAL LERR, OK
+* .. Common blocks ..
+ COMMON /INFOC/INFOT, NOUTC, OK, LERR
+* .. Data statements ..
+ DATA ICHU/'UL'/, ICHT/'NTC'/, ICHD/'UN'/, ICHS/'LR'/
+* .. Executable Statements ..
+*
+ NARGS = 11
+ NC = 0
+ RESET = .TRUE.
+ ERRMAX = ZERO
+* Set up zero matrix for SMMCH.
+ DO 20 J = 1, NMAX
+ DO 10 I = 1, NMAX
+ C( I, J ) = ZERO
+ 10 CONTINUE
+ 20 CONTINUE
+*
+ DO 140 IM = 1, NIDIM
+ M = IDIM( IM )
+*
+ DO 130 IN = 1, NIDIM
+ N = IDIM( IN )
+* Set LDB to 1 more than minimum value if room.
+ LDB = M
+ IF( LDB.LT.NMAX )
+ $ LDB = LDB + 1
+* Skip tests if not enough room.
+ IF( LDB.GT.NMAX )
+ $ GO TO 130
+ LBB = LDB*N
+ NULL = M.LE.0.OR.N.LE.0
+*
+ DO 120 ICS = 1, 2
+ SIDE = ICHS( ICS: ICS )
+ LEFT = SIDE.EQ.'L'
+ IF( LEFT )THEN
+ NA = M
+ ELSE
+ NA = N
+ END IF
+* Set LDA to 1 more than minimum value if room.
+ LDA = NA
+ IF( LDA.LT.NMAX )
+ $ LDA = LDA + 1
+* Skip tests if not enough room.
+ IF( LDA.GT.NMAX )
+ $ GO TO 130
+ LAA = LDA*NA
+*
+ DO 110 ICU = 1, 2
+ UPLO = ICHU( ICU: ICU )
+*
+ DO 100 ICT = 1, 3
+ TRANSA = ICHT( ICT: ICT )
+*
+ DO 90 ICD = 1, 2
+ DIAG = ICHD( ICD: ICD )
+*
+ DO 80 IA = 1, NALF
+ ALPHA = ALF( IA )
+*
+* Generate the matrix A.
+*
+ CALL SMAKE( 'TR', UPLO, DIAG, NA, NA, A,
+ $ NMAX, AA, LDA, RESET, ZERO )
+*
+* Generate the matrix B.
+*
+ CALL SMAKE( 'GE', ' ', ' ', M, N, B, NMAX,
+ $ BB, LDB, RESET, ZERO )
+*
+ NC = NC + 1
+*
+* Save every datum before calling the
+* subroutine.
+*
+ SIDES = SIDE
+ UPLOS = UPLO
+ TRANAS = TRANSA
+ DIAGS = DIAG
+ MS = M
+ NS = N
+ ALS = ALPHA
+ DO 30 I = 1, LAA
+ AS( I ) = AA( I )
+ 30 CONTINUE
+ LDAS = LDA
+ DO 40 I = 1, LBB
+ BS( I ) = BB( I )
+ 40 CONTINUE
+ LDBS = LDB
+*
+* Call the subroutine.
+*
+ IF( SNAME( 4: 5 ).EQ.'MM' )THEN
+ IF( TRACE )
+ $ WRITE( NTRA, FMT = 9995 )NC, SNAME,
+ $ SIDE, UPLO, TRANSA, DIAG, M, N, ALPHA,
+ $ LDA, LDB
+ IF( REWI )
+ $ REWIND NTRA
+ CALL STRMM( SIDE, UPLO, TRANSA, DIAG, M,
+ $ N, ALPHA, AA, LDA, BB, LDB )
+ ELSE IF( SNAME( 4: 5 ).EQ.'SM' )THEN
+ IF( TRACE )
+ $ WRITE( NTRA, FMT = 9995 )NC, SNAME,
+ $ SIDE, UPLO, TRANSA, DIAG, M, N, ALPHA,
+ $ LDA, LDB
+ IF( REWI )
+ $ REWIND NTRA
+ CALL STRSM( SIDE, UPLO, TRANSA, DIAG, M,
+ $ N, ALPHA, AA, LDA, BB, LDB )
+ END IF
+*
+* Check if error-exit was taken incorrectly.
+*
+ IF( .NOT.OK )THEN
+ WRITE( NOUT, FMT = 9994 )
+ FATAL = .TRUE.
+ GO TO 150
+ END IF
+*
+* See what data changed inside subroutines.
+*
+ ISAME( 1 ) = SIDES.EQ.SIDE
+ ISAME( 2 ) = UPLOS.EQ.UPLO
+ ISAME( 3 ) = TRANAS.EQ.TRANSA
+ ISAME( 4 ) = DIAGS.EQ.DIAG
+ ISAME( 5 ) = MS.EQ.M
+ ISAME( 6 ) = NS.EQ.N
+ ISAME( 7 ) = ALS.EQ.ALPHA
+ ISAME( 8 ) = LSE( AS, AA, LAA )
+ ISAME( 9 ) = LDAS.EQ.LDA
+ IF( NULL )THEN
+ ISAME( 10 ) = LSE( BS, BB, LBB )
+ ELSE
+ ISAME( 10 ) = LSERES( 'GE', ' ', M, N, BS,
+ $ BB, LDB )
+ END IF
+ ISAME( 11 ) = LDBS.EQ.LDB
+*
+* If data was incorrectly changed, report and
+* return.
+*
+ SAME = .TRUE.
+ DO 50 I = 1, NARGS
+ SAME = SAME.AND.ISAME( I )
+ IF( .NOT.ISAME( I ) )
+ $ WRITE( NOUT, FMT = 9998 )I
+ 50 CONTINUE
+ IF( .NOT.SAME )THEN
+ FATAL = .TRUE.
+ GO TO 150
+ END IF
+*
+ IF( .NOT.NULL )THEN
+ IF( SNAME( 4: 5 ).EQ.'MM' )THEN
+*
+* Check the result.
+*
+ IF( LEFT )THEN
+ CALL SMMCH( TRANSA, 'N', M, N, M,
+ $ ALPHA, A, NMAX, B, NMAX,
+ $ ZERO, C, NMAX, CT, G,
+ $ BB, LDB, EPS, ERR,
+ $ FATAL, NOUT, .TRUE. )
+ ELSE
+ CALL SMMCH( 'N', TRANSA, M, N, N,
+ $ ALPHA, B, NMAX, A, NMAX,
+ $ ZERO, C, NMAX, CT, G,
+ $ BB, LDB, EPS, ERR,
+ $ FATAL, NOUT, .TRUE. )
+ END IF
+ ELSE IF( SNAME( 4: 5 ).EQ.'SM' )THEN
+*
+* Compute approximation to original
+* matrix.
+*
+ DO 70 J = 1, N
+ DO 60 I = 1, M
+ C( I, J ) = BB( I + ( J - 1 )*
+ $ LDB )
+ BB( I + ( J - 1 )*LDB ) = ALPHA*
+ $ B( I, J )
+ 60 CONTINUE
+ 70 CONTINUE
+*
+ IF( LEFT )THEN
+ CALL SMMCH( TRANSA, 'N', M, N, M,
+ $ ONE, A, NMAX, C, NMAX,
+ $ ZERO, B, NMAX, CT, G,
+ $ BB, LDB, EPS, ERR,
+ $ FATAL, NOUT, .FALSE. )
+ ELSE
+ CALL SMMCH( 'N', TRANSA, M, N, N,
+ $ ONE, C, NMAX, A, NMAX,
+ $ ZERO, B, NMAX, CT, G,
+ $ BB, LDB, EPS, ERR,
+ $ FATAL, NOUT, .FALSE. )
+ END IF
+ END IF
+ ERRMAX = MAX( ERRMAX, ERR )
+* If got really bad answer, report and
+* return.
+ IF( FATAL )
+ $ GO TO 150
+ END IF
+*
+ 80 CONTINUE
+*
+ 90 CONTINUE
+*
+ 100 CONTINUE
+*
+ 110 CONTINUE
+*
+ 120 CONTINUE
+*
+ 130 CONTINUE
+*
+ 140 CONTINUE
+*
+* Report result.
+*
+ IF( ERRMAX.LT.THRESH )THEN
+ WRITE( NOUT, FMT = 9999 )SNAME, NC
+ ELSE
+ WRITE( NOUT, FMT = 9997 )SNAME, NC, ERRMAX
+ END IF
+ GO TO 160
+*
+ 150 CONTINUE
+ WRITE( NOUT, FMT = 9996 )SNAME
+ WRITE( NOUT, FMT = 9995 )NC, SNAME, SIDE, UPLO, TRANSA, DIAG, M,
+ $ N, ALPHA, LDA, LDB
+*
+ 160 CONTINUE
+ RETURN
+*
+ 9999 FORMAT( ' ', A6, ' PASSED THE COMPUTATIONAL TESTS (', I6, ' CALL',
+ $ 'S)' )
+ 9998 FORMAT( ' ******* FATAL ERROR - PARAMETER NUMBER ', I2, ' WAS CH',
+ $ 'ANGED INCORRECTLY *******' )
+ 9997 FORMAT( ' ', A6, ' COMPLETED THE COMPUTATIONAL TESTS (', I6, ' C',
+ $ 'ALLS)', /' ******* BUT WITH MAXIMUM TEST RATIO', F8.2,
+ $ ' - SUSPECT *******' )
+ 9996 FORMAT( ' ******* ', A6, ' FAILED ON CALL NUMBER:' )
+ 9995 FORMAT( 1X, I6, ': ', A6, '(', 4( '''', A1, ''',' ), 2( I3, ',' ),
+ $ F4.1, ', A,', I3, ', B,', I3, ') .' )
+ 9994 FORMAT( ' ******* FATAL ERROR - ERROR-EXIT TAKEN ON VALID CALL *',
+ $ '******' )
+*
+* End of SCHK3.
+*
+ END
+ SUBROUTINE SCHK4( SNAME, EPS, THRESH, NOUT, NTRA, TRACE, REWI,
+ $ FATAL, NIDIM, IDIM, NALF, ALF, NBET, BET, NMAX,
+ $ A, AA, AS, B, BB, BS, C, CC, CS, CT, G )
+*
+* Tests SSYRK.
+*
+* Auxiliary routine for test program for Level 3 Blas.
+*
+* -- Written on 8-February-1989.
+* Jack Dongarra, Argonne National Laboratory.
+* Iain Duff, AERE Harwell.
+* Jeremy Du Croz, Numerical Algorithms Group Ltd.
+* Sven Hammarling, Numerical Algorithms Group Ltd.
+*
+* .. Parameters ..
+ REAL ZERO
+ PARAMETER ( ZERO = 0.0 )
+* .. Scalar Arguments ..
+ REAL EPS, THRESH
+ INTEGER NALF, NBET, NIDIM, NMAX, NOUT, NTRA
+ LOGICAL FATAL, REWI, TRACE
+ CHARACTER*6 SNAME
+* .. Array Arguments ..
+ REAL A( NMAX, NMAX ), AA( NMAX*NMAX ), ALF( NALF ),
+ $ AS( NMAX*NMAX ), B( NMAX, NMAX ),
+ $ BB( NMAX*NMAX ), BET( NBET ), BS( NMAX*NMAX ),
+ $ C( NMAX, NMAX ), CC( NMAX*NMAX ),
+ $ CS( NMAX*NMAX ), CT( NMAX ), G( NMAX )
+ INTEGER IDIM( NIDIM )
+* .. Local Scalars ..
+ REAL ALPHA, ALS, BETA, BETS, ERR, ERRMAX
+ INTEGER I, IA, IB, ICT, ICU, IK, IN, J, JC, JJ, K, KS,
+ $ LAA, LCC, LDA, LDAS, LDC, LDCS, LJ, MA, N, NA,
+ $ NARGS, NC, NS
+ LOGICAL NULL, RESET, SAME, TRAN, UPPER
+ CHARACTER*1 TRANS, TRANSS, UPLO, UPLOS
+ CHARACTER*2 ICHU
+ CHARACTER*3 ICHT
+* .. Local Arrays ..
+ LOGICAL ISAME( 13 )
+* .. External Functions ..
+ LOGICAL LSE, LSERES
+ EXTERNAL LSE, LSERES
+* .. External Subroutines ..
+ EXTERNAL SMAKE, SMMCH, SSYRK
+* .. Intrinsic Functions ..
+ INTRINSIC MAX
+* .. Scalars in Common ..
+ INTEGER INFOT, NOUTC
+ LOGICAL LERR, OK
+* .. Common blocks ..
+ COMMON /INFOC/INFOT, NOUTC, OK, LERR
+* .. Data statements ..
+ DATA ICHT/'NTC'/, ICHU/'UL'/
+* .. Executable Statements ..
+*
+ NARGS = 10
+ NC = 0
+ RESET = .TRUE.
+ ERRMAX = ZERO
+*
+ DO 100 IN = 1, NIDIM
+ N = IDIM( IN )
+* Set LDC to 1 more than minimum value if room.
+ LDC = N
+ IF( LDC.LT.NMAX )
+ $ LDC = LDC + 1
+* Skip tests if not enough room.
+ IF( LDC.GT.NMAX )
+ $ GO TO 100
+ LCC = LDC*N
+ NULL = N.LE.0
+*
+ DO 90 IK = 1, NIDIM
+ K = IDIM( IK )
+*
+ DO 80 ICT = 1, 3
+ TRANS = ICHT( ICT: ICT )
+ TRAN = TRANS.EQ.'T'.OR.TRANS.EQ.'C'
+ IF( TRAN )THEN
+ MA = K
+ NA = N
+ ELSE
+ MA = N
+ NA = K
+ END IF
+* Set LDA to 1 more than minimum value if room.
+ LDA = MA
+ IF( LDA.LT.NMAX )
+ $ LDA = LDA + 1
+* Skip tests if not enough room.
+ IF( LDA.GT.NMAX )
+ $ GO TO 80
+ LAA = LDA*NA
+*
+* Generate the matrix A.
+*
+ CALL SMAKE( 'GE', ' ', ' ', MA, NA, A, NMAX, AA, LDA,
+ $ RESET, ZERO )
+*
+ DO 70 ICU = 1, 2
+ UPLO = ICHU( ICU: ICU )
+ UPPER = UPLO.EQ.'U'
+*
+ DO 60 IA = 1, NALF
+ ALPHA = ALF( IA )
+*
+ DO 50 IB = 1, NBET
+ BETA = BET( IB )
+*
+* Generate the matrix C.
+*
+ CALL SMAKE( 'SY', UPLO, ' ', N, N, C, NMAX, CC,
+ $ LDC, RESET, ZERO )
+*
+ NC = NC + 1
+*
+* Save every datum before calling the subroutine.
+*
+ UPLOS = UPLO
+ TRANSS = TRANS
+ NS = N
+ KS = K
+ ALS = ALPHA
+ DO 10 I = 1, LAA
+ AS( I ) = AA( I )
+ 10 CONTINUE
+ LDAS = LDA
+ BETS = BETA
+ DO 20 I = 1, LCC
+ CS( I ) = CC( I )
+ 20 CONTINUE
+ LDCS = LDC
+*
+* Call the subroutine.
+*
+ IF( TRACE )
+ $ WRITE( NTRA, FMT = 9994 )NC, SNAME, UPLO,
+ $ TRANS, N, K, ALPHA, LDA, BETA, LDC
+ IF( REWI )
+ $ REWIND NTRA
+ CALL SSYRK( UPLO, TRANS, N, K, ALPHA, AA, LDA,
+ $ BETA, CC, LDC )
+*
+* Check if error-exit was taken incorrectly.
+*
+ IF( .NOT.OK )THEN
+ WRITE( NOUT, FMT = 9993 )
+ FATAL = .TRUE.
+ GO TO 120
+ END IF
+*
+* See what data changed inside subroutines.
+*
+ ISAME( 1 ) = UPLOS.EQ.UPLO
+ ISAME( 2 ) = TRANSS.EQ.TRANS
+ ISAME( 3 ) = NS.EQ.N
+ ISAME( 4 ) = KS.EQ.K
+ ISAME( 5 ) = ALS.EQ.ALPHA
+ ISAME( 6 ) = LSE( AS, AA, LAA )
+ ISAME( 7 ) = LDAS.EQ.LDA
+ ISAME( 8 ) = BETS.EQ.BETA
+ IF( NULL )THEN
+ ISAME( 9 ) = LSE( CS, CC, LCC )
+ ELSE
+ ISAME( 9 ) = LSERES( 'SY', UPLO, N, N, CS,
+ $ CC, LDC )
+ END IF
+ ISAME( 10 ) = LDCS.EQ.LDC
+*
+* If data was incorrectly changed, report and
+* return.
+*
+ SAME = .TRUE.
+ DO 30 I = 1, NARGS
+ SAME = SAME.AND.ISAME( I )
+ IF( .NOT.ISAME( I ) )
+ $ WRITE( NOUT, FMT = 9998 )I
+ 30 CONTINUE
+ IF( .NOT.SAME )THEN
+ FATAL = .TRUE.
+ GO TO 120
+ END IF
+*
+ IF( .NOT.NULL )THEN
+*
+* Check the result column by column.
+*
+ JC = 1
+ DO 40 J = 1, N
+ IF( UPPER )THEN
+ JJ = 1
+ LJ = J
+ ELSE
+ JJ = J
+ LJ = N - J + 1
+ END IF
+ IF( TRAN )THEN
+ CALL SMMCH( 'T', 'N', LJ, 1, K, ALPHA,
+ $ A( 1, JJ ), NMAX,
+ $ A( 1, J ), NMAX, BETA,
+ $ C( JJ, J ), NMAX, CT, G,
+ $ CC( JC ), LDC, EPS, ERR,
+ $ FATAL, NOUT, .TRUE. )
+ ELSE
+ CALL SMMCH( 'N', 'T', LJ, 1, K, ALPHA,
+ $ A( JJ, 1 ), NMAX,
+ $ A( J, 1 ), NMAX, BETA,
+ $ C( JJ, J ), NMAX, CT, G,
+ $ CC( JC ), LDC, EPS, ERR,
+ $ FATAL, NOUT, .TRUE. )
+ END IF
+ IF( UPPER )THEN
+ JC = JC + LDC
+ ELSE
+ JC = JC + LDC + 1
+ END IF
+ ERRMAX = MAX( ERRMAX, ERR )
+* If got really bad answer, report and
+* return.
+ IF( FATAL )
+ $ GO TO 110
+ 40 CONTINUE
+ END IF
+*
+ 50 CONTINUE
+*
+ 60 CONTINUE
+*
+ 70 CONTINUE
+*
+ 80 CONTINUE
+*
+ 90 CONTINUE
+*
+ 100 CONTINUE
+*
+* Report result.
+*
+ IF( ERRMAX.LT.THRESH )THEN
+ WRITE( NOUT, FMT = 9999 )SNAME, NC
+ ELSE
+ WRITE( NOUT, FMT = 9997 )SNAME, NC, ERRMAX
+ END IF
+ GO TO 130
+*
+ 110 CONTINUE
+ IF( N.GT.1 )
+ $ WRITE( NOUT, FMT = 9995 )J
+*
+ 120 CONTINUE
+ WRITE( NOUT, FMT = 9996 )SNAME
+ WRITE( NOUT, FMT = 9994 )NC, SNAME, UPLO, TRANS, N, K, ALPHA,
+ $ LDA, BETA, LDC
+*
+ 130 CONTINUE
+ RETURN
+*
+ 9999 FORMAT( ' ', A6, ' PASSED THE COMPUTATIONAL TESTS (', I6, ' CALL',
+ $ 'S)' )
+ 9998 FORMAT( ' ******* FATAL ERROR - PARAMETER NUMBER ', I2, ' WAS CH',
+ $ 'ANGED INCORRECTLY *******' )
+ 9997 FORMAT( ' ', A6, ' COMPLETED THE COMPUTATIONAL TESTS (', I6, ' C',
+ $ 'ALLS)', /' ******* BUT WITH MAXIMUM TEST RATIO', F8.2,
+ $ ' - SUSPECT *******' )
+ 9996 FORMAT( ' ******* ', A6, ' FAILED ON CALL NUMBER:' )
+ 9995 FORMAT( ' THESE ARE THE RESULTS FOR COLUMN ', I3 )
+ 9994 FORMAT( 1X, I6, ': ', A6, '(', 2( '''', A1, ''',' ), 2( I3, ',' ),
+ $ F4.1, ', A,', I3, ',', F4.1, ', C,', I3, ') .' )
+ 9993 FORMAT( ' ******* FATAL ERROR - ERROR-EXIT TAKEN ON VALID CALL *',
+ $ '******' )
+*
+* End of SCHK4.
+*
+ END
+ SUBROUTINE SCHK5( SNAME, EPS, THRESH, NOUT, NTRA, TRACE, REWI,
+ $ FATAL, NIDIM, IDIM, NALF, ALF, NBET, BET, NMAX,
+ $ AB, AA, AS, BB, BS, C, CC, CS, CT, G, W )
+*
+* Tests SSYR2K.
+*
+* Auxiliary routine for test program for Level 3 Blas.
+*
+* -- Written on 8-February-1989.
+* Jack Dongarra, Argonne National Laboratory.
+* Iain Duff, AERE Harwell.
+* Jeremy Du Croz, Numerical Algorithms Group Ltd.
+* Sven Hammarling, Numerical Algorithms Group Ltd.
+*
+* .. Parameters ..
+ REAL ZERO
+ PARAMETER ( ZERO = 0.0 )
+* .. Scalar Arguments ..
+ REAL EPS, THRESH
+ INTEGER NALF, NBET, NIDIM, NMAX, NOUT, NTRA
+ LOGICAL FATAL, REWI, TRACE
+ CHARACTER*6 SNAME
+* .. Array Arguments ..
+ REAL AA( NMAX*NMAX ), AB( 2*NMAX*NMAX ),
+ $ ALF( NALF ), AS( NMAX*NMAX ), BB( NMAX*NMAX ),
+ $ BET( NBET ), BS( NMAX*NMAX ), C( NMAX, NMAX ),
+ $ CC( NMAX*NMAX ), CS( NMAX*NMAX ), CT( NMAX ),
+ $ G( NMAX ), W( 2*NMAX )
+ INTEGER IDIM( NIDIM )
+* .. Local Scalars ..
+ REAL ALPHA, ALS, BETA, BETS, ERR, ERRMAX
+ INTEGER I, IA, IB, ICT, ICU, IK, IN, J, JC, JJ, JJAB,
+ $ K, KS, LAA, LBB, LCC, LDA, LDAS, LDB, LDBS,
+ $ LDC, LDCS, LJ, MA, N, NA, NARGS, NC, NS
+ LOGICAL NULL, RESET, SAME, TRAN, UPPER
+ CHARACTER*1 TRANS, TRANSS, UPLO, UPLOS
+ CHARACTER*2 ICHU
+ CHARACTER*3 ICHT
+* .. Local Arrays ..
+ LOGICAL ISAME( 13 )
+* .. External Functions ..
+ LOGICAL LSE, LSERES
+ EXTERNAL LSE, LSERES
+* .. External Subroutines ..
+ EXTERNAL SMAKE, SMMCH, SSYR2K
+* .. Intrinsic Functions ..
+ INTRINSIC MAX
+* .. Scalars in Common ..
+ INTEGER INFOT, NOUTC
+ LOGICAL LERR, OK
+* .. Common blocks ..
+ COMMON /INFOC/INFOT, NOUTC, OK, LERR
+* .. Data statements ..
+ DATA ICHT/'NTC'/, ICHU/'UL'/
+* .. Executable Statements ..
+*
+ NARGS = 12
+ NC = 0
+ RESET = .TRUE.
+ ERRMAX = ZERO
+*
+ DO 130 IN = 1, NIDIM
+ N = IDIM( IN )
+* Set LDC to 1 more than minimum value if room.
+ LDC = N
+ IF( LDC.LT.NMAX )
+ $ LDC = LDC + 1
+* Skip tests if not enough room.
+ IF( LDC.GT.NMAX )
+ $ GO TO 130
+ LCC = LDC*N
+ NULL = N.LE.0
+*
+ DO 120 IK = 1, NIDIM
+ K = IDIM( IK )
+*
+ DO 110 ICT = 1, 3
+ TRANS = ICHT( ICT: ICT )
+ TRAN = TRANS.EQ.'T'.OR.TRANS.EQ.'C'
+ IF( TRAN )THEN
+ MA = K
+ NA = N
+ ELSE
+ MA = N
+ NA = K
+ END IF
+* Set LDA to 1 more than minimum value if room.
+ LDA = MA
+ IF( LDA.LT.NMAX )
+ $ LDA = LDA + 1
+* Skip tests if not enough room.
+ IF( LDA.GT.NMAX )
+ $ GO TO 110
+ LAA = LDA*NA
+*
+* Generate the matrix A.
+*
+ IF( TRAN )THEN
+ CALL SMAKE( 'GE', ' ', ' ', MA, NA, AB, 2*NMAX, AA,
+ $ LDA, RESET, ZERO )
+ ELSE
+ CALL SMAKE( 'GE', ' ', ' ', MA, NA, AB, NMAX, AA, LDA,
+ $ RESET, ZERO )
+ END IF
+*
+* Generate the matrix B.
+*
+ LDB = LDA
+ LBB = LAA
+ IF( TRAN )THEN
+ CALL SMAKE( 'GE', ' ', ' ', MA, NA, AB( K + 1 ),
+ $ 2*NMAX, BB, LDB, RESET, ZERO )
+ ELSE
+ CALL SMAKE( 'GE', ' ', ' ', MA, NA, AB( K*NMAX + 1 ),
+ $ NMAX, BB, LDB, RESET, ZERO )
+ END IF
+*
+ DO 100 ICU = 1, 2
+ UPLO = ICHU( ICU: ICU )
+ UPPER = UPLO.EQ.'U'
+*
+ DO 90 IA = 1, NALF
+ ALPHA = ALF( IA )
+*
+ DO 80 IB = 1, NBET
+ BETA = BET( IB )
+*
+* Generate the matrix C.
+*
+ CALL SMAKE( 'SY', UPLO, ' ', N, N, C, NMAX, CC,
+ $ LDC, RESET, ZERO )
+*
+ NC = NC + 1
+*
+* Save every datum before calling the subroutine.
+*
+ UPLOS = UPLO
+ TRANSS = TRANS
+ NS = N
+ KS = K
+ ALS = ALPHA
+ DO 10 I = 1, LAA
+ AS( I ) = AA( I )
+ 10 CONTINUE
+ LDAS = LDA
+ DO 20 I = 1, LBB
+ BS( I ) = BB( I )
+ 20 CONTINUE
+ LDBS = LDB
+ BETS = BETA
+ DO 30 I = 1, LCC
+ CS( I ) = CC( I )
+ 30 CONTINUE
+ LDCS = LDC
+*
+* Call the subroutine.
+*
+ IF( TRACE )
+ $ WRITE( NTRA, FMT = 9994 )NC, SNAME, UPLO,
+ $ TRANS, N, K, ALPHA, LDA, LDB, BETA, LDC
+ IF( REWI )
+ $ REWIND NTRA
+ CALL SSYR2K( UPLO, TRANS, N, K, ALPHA, AA, LDA,
+ $ BB, LDB, BETA, CC, LDC )
+*
+* Check if error-exit was taken incorrectly.
+*
+ IF( .NOT.OK )THEN
+ WRITE( NOUT, FMT = 9993 )
+ FATAL = .TRUE.
+ GO TO 150
+ END IF
+*
+* See what data changed inside subroutines.
+*
+ ISAME( 1 ) = UPLOS.EQ.UPLO
+ ISAME( 2 ) = TRANSS.EQ.TRANS
+ ISAME( 3 ) = NS.EQ.N
+ ISAME( 4 ) = KS.EQ.K
+ ISAME( 5 ) = ALS.EQ.ALPHA
+ ISAME( 6 ) = LSE( AS, AA, LAA )
+ ISAME( 7 ) = LDAS.EQ.LDA
+ ISAME( 8 ) = LSE( BS, BB, LBB )
+ ISAME( 9 ) = LDBS.EQ.LDB
+ ISAME( 10 ) = BETS.EQ.BETA
+ IF( NULL )THEN
+ ISAME( 11 ) = LSE( CS, CC, LCC )
+ ELSE
+ ISAME( 11 ) = LSERES( 'SY', UPLO, N, N, CS,
+ $ CC, LDC )
+ END IF
+ ISAME( 12 ) = LDCS.EQ.LDC
+*
+* If data was incorrectly changed, report and
+* return.
+*
+ SAME = .TRUE.
+ DO 40 I = 1, NARGS
+ SAME = SAME.AND.ISAME( I )
+ IF( .NOT.ISAME( I ) )
+ $ WRITE( NOUT, FMT = 9998 )I
+ 40 CONTINUE
+ IF( .NOT.SAME )THEN
+ FATAL = .TRUE.
+ GO TO 150
+ END IF
+*
+ IF( .NOT.NULL )THEN
+*
+* Check the result column by column.
+*
+ JJAB = 1
+ JC = 1
+ DO 70 J = 1, N
+ IF( UPPER )THEN
+ JJ = 1
+ LJ = J
+ ELSE
+ JJ = J
+ LJ = N - J + 1
+ END IF
+ IF( TRAN )THEN
+ DO 50 I = 1, K
+ W( I ) = AB( ( J - 1 )*2*NMAX + K +
+ $ I )
+ W( K + I ) = AB( ( J - 1 )*2*NMAX +
+ $ I )
+ 50 CONTINUE
+ CALL SMMCH( 'T', 'N', LJ, 1, 2*K,
+ $ ALPHA, AB( JJAB ), 2*NMAX,
+ $ W, 2*NMAX, BETA,
+ $ C( JJ, J ), NMAX, CT, G,
+ $ CC( JC ), LDC, EPS, ERR,
+ $ FATAL, NOUT, .TRUE. )
+ ELSE
+ DO 60 I = 1, K
+ W( I ) = AB( ( K + I - 1 )*NMAX +
+ $ J )
+ W( K + I ) = AB( ( I - 1 )*NMAX +
+ $ J )
+ 60 CONTINUE
+ CALL SMMCH( 'N', 'N', LJ, 1, 2*K,
+ $ ALPHA, AB( JJ ), NMAX, W,
+ $ 2*NMAX, BETA, C( JJ, J ),
+ $ NMAX, CT, G, CC( JC ), LDC,
+ $ EPS, ERR, FATAL, NOUT,
+ $ .TRUE. )
+ END IF
+ IF( UPPER )THEN
+ JC = JC + LDC
+ ELSE
+ JC = JC + LDC + 1
+ IF( TRAN )
+ $ JJAB = JJAB + 2*NMAX
+ END IF
+ ERRMAX = MAX( ERRMAX, ERR )
+* If got really bad answer, report and
+* return.
+ IF( FATAL )
+ $ GO TO 140
+ 70 CONTINUE
+ END IF
+*
+ 80 CONTINUE
+*
+ 90 CONTINUE
+*
+ 100 CONTINUE
+*
+ 110 CONTINUE
+*
+ 120 CONTINUE
+*
+ 130 CONTINUE
+*
+* Report result.
+*
+ IF( ERRMAX.LT.THRESH )THEN
+ WRITE( NOUT, FMT = 9999 )SNAME, NC
+ ELSE
+ WRITE( NOUT, FMT = 9997 )SNAME, NC, ERRMAX
+ END IF
+ GO TO 160
+*
+ 140 CONTINUE
+ IF( N.GT.1 )
+ $ WRITE( NOUT, FMT = 9995 )J
+*
+ 150 CONTINUE
+ WRITE( NOUT, FMT = 9996 )SNAME
+ WRITE( NOUT, FMT = 9994 )NC, SNAME, UPLO, TRANS, N, K, ALPHA,
+ $ LDA, LDB, BETA, LDC
+*
+ 160 CONTINUE
+ RETURN
+*
+ 9999 FORMAT( ' ', A6, ' PASSED THE COMPUTATIONAL TESTS (', I6, ' CALL',
+ $ 'S)' )
+ 9998 FORMAT( ' ******* FATAL ERROR - PARAMETER NUMBER ', I2, ' WAS CH',
+ $ 'ANGED INCORRECTLY *******' )
+ 9997 FORMAT( ' ', A6, ' COMPLETED THE COMPUTATIONAL TESTS (', I6, ' C',
+ $ 'ALLS)', /' ******* BUT WITH MAXIMUM TEST RATIO', F8.2,
+ $ ' - SUSPECT *******' )
+ 9996 FORMAT( ' ******* ', A6, ' FAILED ON CALL NUMBER:' )
+ 9995 FORMAT( ' THESE ARE THE RESULTS FOR COLUMN ', I3 )
+ 9994 FORMAT( 1X, I6, ': ', A6, '(', 2( '''', A1, ''',' ), 2( I3, ',' ),
+ $ F4.1, ', A,', I3, ', B,', I3, ',', F4.1, ', C,', I3, ') ',
+ $ ' .' )
+ 9993 FORMAT( ' ******* FATAL ERROR - ERROR-EXIT TAKEN ON VALID CALL *',
+ $ '******' )
+*
+* End of SCHK5.
+*
+ END
+ SUBROUTINE SCHKE( ISNUM, SRNAMT, NOUT )
+*
+* Tests the error exits from the Level 3 Blas.
+* Requires a special version of the error-handling routine XERBLA.
+* ALPHA, BETA, A, B and C should not need to be defined.
+*
+* Auxiliary routine for test program for Level 3 Blas.
+*
+* -- Written on 8-February-1989.
+* Jack Dongarra, Argonne National Laboratory.
+* Iain Duff, AERE Harwell.
+* Jeremy Du Croz, Numerical Algorithms Group Ltd.
+* Sven Hammarling, Numerical Algorithms Group Ltd.
+*
+* .. Scalar Arguments ..
+ INTEGER ISNUM, NOUT
+ CHARACTER*6 SRNAMT
+* .. Scalars in Common ..
+ INTEGER INFOT, NOUTC
+ LOGICAL LERR, OK
+* .. Local Scalars ..
+ REAL ALPHA, BETA
+* .. Local Arrays ..
+ REAL A( 2, 1 ), B( 2, 1 ), C( 2, 1 )
+* .. External Subroutines ..
+ EXTERNAL CHKXER, SGEMM, SSYMM, SSYR2K, SSYRK, STRMM,
+ $ STRSM
+* .. Common blocks ..
+ COMMON /INFOC/INFOT, NOUTC, OK, LERR
+* .. Executable Statements ..
+* OK is set to .FALSE. by the special version of XERBLA or by CHKXER
+* if anything is wrong.
+ OK = .TRUE.
+* LERR is set to .TRUE. by the special version of XERBLA each time
+* it is called, and is then tested and re-set by CHKXER.
+ LERR = .FALSE.
+ GO TO ( 10, 20, 30, 40, 50, 60 )ISNUM
+ 10 INFOT = 1
+ CALL SGEMM( '/', 'N', 0, 0, 0, ALPHA, A, 1, B, 1, BETA, C, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 1
+ CALL SGEMM( '/', 'T', 0, 0, 0, ALPHA, A, 1, B, 1, BETA, C, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 2
+ CALL SGEMM( 'N', '/', 0, 0, 0, ALPHA, A, 1, B, 1, BETA, C, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 2
+ CALL SGEMM( 'T', '/', 0, 0, 0, ALPHA, A, 1, B, 1, BETA, C, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 3
+ CALL SGEMM( 'N', 'N', -1, 0, 0, ALPHA, A, 1, B, 1, BETA, C, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 3
+ CALL SGEMM( 'N', 'T', -1, 0, 0, ALPHA, A, 1, B, 1, BETA, C, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 3
+ CALL SGEMM( 'T', 'N', -1, 0, 0, ALPHA, A, 1, B, 1, BETA, C, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 3
+ CALL SGEMM( 'T', 'T', -1, 0, 0, ALPHA, A, 1, B, 1, BETA, C, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 4
+ CALL SGEMM( 'N', 'N', 0, -1, 0, ALPHA, A, 1, B, 1, BETA, C, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 4
+ CALL SGEMM( 'N', 'T', 0, -1, 0, ALPHA, A, 1, B, 1, BETA, C, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 4
+ CALL SGEMM( 'T', 'N', 0, -1, 0, ALPHA, A, 1, B, 1, BETA, C, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 4
+ CALL SGEMM( 'T', 'T', 0, -1, 0, ALPHA, A, 1, B, 1, BETA, C, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 5
+ CALL SGEMM( 'N', 'N', 0, 0, -1, ALPHA, A, 1, B, 1, BETA, C, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 5
+ CALL SGEMM( 'N', 'T', 0, 0, -1, ALPHA, A, 1, B, 1, BETA, C, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 5
+ CALL SGEMM( 'T', 'N', 0, 0, -1, ALPHA, A, 1, B, 1, BETA, C, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 5
+ CALL SGEMM( 'T', 'T', 0, 0, -1, ALPHA, A, 1, B, 1, BETA, C, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 8
+ CALL SGEMM( 'N', 'N', 2, 0, 0, ALPHA, A, 1, B, 1, BETA, C, 2 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 8
+ CALL SGEMM( 'N', 'T', 2, 0, 0, ALPHA, A, 1, B, 1, BETA, C, 2 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 8
+ CALL SGEMM( 'T', 'N', 0, 0, 2, ALPHA, A, 1, B, 2, BETA, C, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 8
+ CALL SGEMM( 'T', 'T', 0, 0, 2, ALPHA, A, 1, B, 1, BETA, C, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 10
+ CALL SGEMM( 'N', 'N', 0, 0, 2, ALPHA, A, 1, B, 1, BETA, C, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 10
+ CALL SGEMM( 'T', 'N', 0, 0, 2, ALPHA, A, 2, B, 1, BETA, C, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 10
+ CALL SGEMM( 'N', 'T', 0, 2, 0, ALPHA, A, 1, B, 1, BETA, C, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 10
+ CALL SGEMM( 'T', 'T', 0, 2, 0, ALPHA, A, 1, B, 1, BETA, C, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 13
+ CALL SGEMM( 'N', 'N', 2, 0, 0, ALPHA, A, 2, B, 1, BETA, C, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 13
+ CALL SGEMM( 'N', 'T', 2, 0, 0, ALPHA, A, 2, B, 1, BETA, C, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 13
+ CALL SGEMM( 'T', 'N', 2, 0, 0, ALPHA, A, 1, B, 1, BETA, C, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 13
+ CALL SGEMM( 'T', 'T', 2, 0, 0, ALPHA, A, 1, B, 1, BETA, C, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ GO TO 70
+ 20 INFOT = 1
+ CALL SSYMM( '/', 'U', 0, 0, ALPHA, A, 1, B, 1, BETA, C, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 2
+ CALL SSYMM( 'L', '/', 0, 0, ALPHA, A, 1, B, 1, BETA, C, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 3
+ CALL SSYMM( 'L', 'U', -1, 0, ALPHA, A, 1, B, 1, BETA, C, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 3
+ CALL SSYMM( 'R', 'U', -1, 0, ALPHA, A, 1, B, 1, BETA, C, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 3
+ CALL SSYMM( 'L', 'L', -1, 0, ALPHA, A, 1, B, 1, BETA, C, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 3
+ CALL SSYMM( 'R', 'L', -1, 0, ALPHA, A, 1, B, 1, BETA, C, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 4
+ CALL SSYMM( 'L', 'U', 0, -1, ALPHA, A, 1, B, 1, BETA, C, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 4
+ CALL SSYMM( 'R', 'U', 0, -1, ALPHA, A, 1, B, 1, BETA, C, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 4
+ CALL SSYMM( 'L', 'L', 0, -1, ALPHA, A, 1, B, 1, BETA, C, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 4
+ CALL SSYMM( 'R', 'L', 0, -1, ALPHA, A, 1, B, 1, BETA, C, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 7
+ CALL SSYMM( 'L', 'U', 2, 0, ALPHA, A, 1, B, 2, BETA, C, 2 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 7
+ CALL SSYMM( 'R', 'U', 0, 2, ALPHA, A, 1, B, 1, BETA, C, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 7
+ CALL SSYMM( 'L', 'L', 2, 0, ALPHA, A, 1, B, 2, BETA, C, 2 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 7
+ CALL SSYMM( 'R', 'L', 0, 2, ALPHA, A, 1, B, 1, BETA, C, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 9
+ CALL SSYMM( 'L', 'U', 2, 0, ALPHA, A, 2, B, 1, BETA, C, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 9
+ CALL SSYMM( 'R', 'U', 2, 0, ALPHA, A, 1, B, 1, BETA, C, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 9
+ CALL SSYMM( 'L', 'L', 2, 0, ALPHA, A, 2, B, 1, BETA, C, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 9
+ CALL SSYMM( 'R', 'L', 2, 0, ALPHA, A, 1, B, 1, BETA, C, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 12
+ CALL SSYMM( 'L', 'U', 2, 0, ALPHA, A, 2, B, 2, BETA, C, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 12
+ CALL SSYMM( 'R', 'U', 2, 0, ALPHA, A, 1, B, 2, BETA, C, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 12
+ CALL SSYMM( 'L', 'L', 2, 0, ALPHA, A, 2, B, 2, BETA, C, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 12
+ CALL SSYMM( 'R', 'L', 2, 0, ALPHA, A, 1, B, 2, BETA, C, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ GO TO 70
+ 30 INFOT = 1
+ CALL STRMM( '/', 'U', 'N', 'N', 0, 0, ALPHA, A, 1, B, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 2
+ CALL STRMM( 'L', '/', 'N', 'N', 0, 0, ALPHA, A, 1, B, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 3
+ CALL STRMM( 'L', 'U', '/', 'N', 0, 0, ALPHA, A, 1, B, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 4
+ CALL STRMM( 'L', 'U', 'N', '/', 0, 0, ALPHA, A, 1, B, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 5
+ CALL STRMM( 'L', 'U', 'N', 'N', -1, 0, ALPHA, A, 1, B, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 5
+ CALL STRMM( 'L', 'U', 'T', 'N', -1, 0, ALPHA, A, 1, B, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 5
+ CALL STRMM( 'R', 'U', 'N', 'N', -1, 0, ALPHA, A, 1, B, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 5
+ CALL STRMM( 'R', 'U', 'T', 'N', -1, 0, ALPHA, A, 1, B, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 5
+ CALL STRMM( 'L', 'L', 'N', 'N', -1, 0, ALPHA, A, 1, B, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 5
+ CALL STRMM( 'L', 'L', 'T', 'N', -1, 0, ALPHA, A, 1, B, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 5
+ CALL STRMM( 'R', 'L', 'N', 'N', -1, 0, ALPHA, A, 1, B, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 5
+ CALL STRMM( 'R', 'L', 'T', 'N', -1, 0, ALPHA, A, 1, B, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 6
+ CALL STRMM( 'L', 'U', 'N', 'N', 0, -1, ALPHA, A, 1, B, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 6
+ CALL STRMM( 'L', 'U', 'T', 'N', 0, -1, ALPHA, A, 1, B, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 6
+ CALL STRMM( 'R', 'U', 'N', 'N', 0, -1, ALPHA, A, 1, B, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 6
+ CALL STRMM( 'R', 'U', 'T', 'N', 0, -1, ALPHA, A, 1, B, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 6
+ CALL STRMM( 'L', 'L', 'N', 'N', 0, -1, ALPHA, A, 1, B, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 6
+ CALL STRMM( 'L', 'L', 'T', 'N', 0, -1, ALPHA, A, 1, B, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 6
+ CALL STRMM( 'R', 'L', 'N', 'N', 0, -1, ALPHA, A, 1, B, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 6
+ CALL STRMM( 'R', 'L', 'T', 'N', 0, -1, ALPHA, A, 1, B, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 9
+ CALL STRMM( 'L', 'U', 'N', 'N', 2, 0, ALPHA, A, 1, B, 2 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 9
+ CALL STRMM( 'L', 'U', 'T', 'N', 2, 0, ALPHA, A, 1, B, 2 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 9
+ CALL STRMM( 'R', 'U', 'N', 'N', 0, 2, ALPHA, A, 1, B, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 9
+ CALL STRMM( 'R', 'U', 'T', 'N', 0, 2, ALPHA, A, 1, B, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 9
+ CALL STRMM( 'L', 'L', 'N', 'N', 2, 0, ALPHA, A, 1, B, 2 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 9
+ CALL STRMM( 'L', 'L', 'T', 'N', 2, 0, ALPHA, A, 1, B, 2 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 9
+ CALL STRMM( 'R', 'L', 'N', 'N', 0, 2, ALPHA, A, 1, B, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 9
+ CALL STRMM( 'R', 'L', 'T', 'N', 0, 2, ALPHA, A, 1, B, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 11
+ CALL STRMM( 'L', 'U', 'N', 'N', 2, 0, ALPHA, A, 2, B, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 11
+ CALL STRMM( 'L', 'U', 'T', 'N', 2, 0, ALPHA, A, 2, B, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 11
+ CALL STRMM( 'R', 'U', 'N', 'N', 2, 0, ALPHA, A, 1, B, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 11
+ CALL STRMM( 'R', 'U', 'T', 'N', 2, 0, ALPHA, A, 1, B, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 11
+ CALL STRMM( 'L', 'L', 'N', 'N', 2, 0, ALPHA, A, 2, B, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 11
+ CALL STRMM( 'L', 'L', 'T', 'N', 2, 0, ALPHA, A, 2, B, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 11
+ CALL STRMM( 'R', 'L', 'N', 'N', 2, 0, ALPHA, A, 1, B, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 11
+ CALL STRMM( 'R', 'L', 'T', 'N', 2, 0, ALPHA, A, 1, B, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ GO TO 70
+ 40 INFOT = 1
+ CALL STRSM( '/', 'U', 'N', 'N', 0, 0, ALPHA, A, 1, B, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 2
+ CALL STRSM( 'L', '/', 'N', 'N', 0, 0, ALPHA, A, 1, B, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 3
+ CALL STRSM( 'L', 'U', '/', 'N', 0, 0, ALPHA, A, 1, B, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 4
+ CALL STRSM( 'L', 'U', 'N', '/', 0, 0, ALPHA, A, 1, B, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 5
+ CALL STRSM( 'L', 'U', 'N', 'N', -1, 0, ALPHA, A, 1, B, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 5
+ CALL STRSM( 'L', 'U', 'T', 'N', -1, 0, ALPHA, A, 1, B, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 5
+ CALL STRSM( 'R', 'U', 'N', 'N', -1, 0, ALPHA, A, 1, B, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 5
+ CALL STRSM( 'R', 'U', 'T', 'N', -1, 0, ALPHA, A, 1, B, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 5
+ CALL STRSM( 'L', 'L', 'N', 'N', -1, 0, ALPHA, A, 1, B, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 5
+ CALL STRSM( 'L', 'L', 'T', 'N', -1, 0, ALPHA, A, 1, B, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 5
+ CALL STRSM( 'R', 'L', 'N', 'N', -1, 0, ALPHA, A, 1, B, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 5
+ CALL STRSM( 'R', 'L', 'T', 'N', -1, 0, ALPHA, A, 1, B, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 6
+ CALL STRSM( 'L', 'U', 'N', 'N', 0, -1, ALPHA, A, 1, B, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 6
+ CALL STRSM( 'L', 'U', 'T', 'N', 0, -1, ALPHA, A, 1, B, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 6
+ CALL STRSM( 'R', 'U', 'N', 'N', 0, -1, ALPHA, A, 1, B, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 6
+ CALL STRSM( 'R', 'U', 'T', 'N', 0, -1, ALPHA, A, 1, B, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 6
+ CALL STRSM( 'L', 'L', 'N', 'N', 0, -1, ALPHA, A, 1, B, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 6
+ CALL STRSM( 'L', 'L', 'T', 'N', 0, -1, ALPHA, A, 1, B, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 6
+ CALL STRSM( 'R', 'L', 'N', 'N', 0, -1, ALPHA, A, 1, B, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 6
+ CALL STRSM( 'R', 'L', 'T', 'N', 0, -1, ALPHA, A, 1, B, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 9
+ CALL STRSM( 'L', 'U', 'N', 'N', 2, 0, ALPHA, A, 1, B, 2 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 9
+ CALL STRSM( 'L', 'U', 'T', 'N', 2, 0, ALPHA, A, 1, B, 2 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 9
+ CALL STRSM( 'R', 'U', 'N', 'N', 0, 2, ALPHA, A, 1, B, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 9
+ CALL STRSM( 'R', 'U', 'T', 'N', 0, 2, ALPHA, A, 1, B, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 9
+ CALL STRSM( 'L', 'L', 'N', 'N', 2, 0, ALPHA, A, 1, B, 2 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 9
+ CALL STRSM( 'L', 'L', 'T', 'N', 2, 0, ALPHA, A, 1, B, 2 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 9
+ CALL STRSM( 'R', 'L', 'N', 'N', 0, 2, ALPHA, A, 1, B, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 9
+ CALL STRSM( 'R', 'L', 'T', 'N', 0, 2, ALPHA, A, 1, B, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 11
+ CALL STRSM( 'L', 'U', 'N', 'N', 2, 0, ALPHA, A, 2, B, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 11
+ CALL STRSM( 'L', 'U', 'T', 'N', 2, 0, ALPHA, A, 2, B, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 11
+ CALL STRSM( 'R', 'U', 'N', 'N', 2, 0, ALPHA, A, 1, B, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 11
+ CALL STRSM( 'R', 'U', 'T', 'N', 2, 0, ALPHA, A, 1, B, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 11
+ CALL STRSM( 'L', 'L', 'N', 'N', 2, 0, ALPHA, A, 2, B, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 11
+ CALL STRSM( 'L', 'L', 'T', 'N', 2, 0, ALPHA, A, 2, B, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 11
+ CALL STRSM( 'R', 'L', 'N', 'N', 2, 0, ALPHA, A, 1, B, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 11
+ CALL STRSM( 'R', 'L', 'T', 'N', 2, 0, ALPHA, A, 1, B, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ GO TO 70
+ 50 INFOT = 1
+ CALL SSYRK( '/', 'N', 0, 0, ALPHA, A, 1, BETA, C, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 2
+ CALL SSYRK( 'U', '/', 0, 0, ALPHA, A, 1, BETA, C, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 3
+ CALL SSYRK( 'U', 'N', -1, 0, ALPHA, A, 1, BETA, C, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 3
+ CALL SSYRK( 'U', 'T', -1, 0, ALPHA, A, 1, BETA, C, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 3
+ CALL SSYRK( 'L', 'N', -1, 0, ALPHA, A, 1, BETA, C, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 3
+ CALL SSYRK( 'L', 'T', -1, 0, ALPHA, A, 1, BETA, C, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 4
+ CALL SSYRK( 'U', 'N', 0, -1, ALPHA, A, 1, BETA, C, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 4
+ CALL SSYRK( 'U', 'T', 0, -1, ALPHA, A, 1, BETA, C, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 4
+ CALL SSYRK( 'L', 'N', 0, -1, ALPHA, A, 1, BETA, C, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 4
+ CALL SSYRK( 'L', 'T', 0, -1, ALPHA, A, 1, BETA, C, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 7
+ CALL SSYRK( 'U', 'N', 2, 0, ALPHA, A, 1, BETA, C, 2 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 7
+ CALL SSYRK( 'U', 'T', 0, 2, ALPHA, A, 1, BETA, C, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 7
+ CALL SSYRK( 'L', 'N', 2, 0, ALPHA, A, 1, BETA, C, 2 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 7
+ CALL SSYRK( 'L', 'T', 0, 2, ALPHA, A, 1, BETA, C, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 10
+ CALL SSYRK( 'U', 'N', 2, 0, ALPHA, A, 2, BETA, C, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 10
+ CALL SSYRK( 'U', 'T', 2, 0, ALPHA, A, 1, BETA, C, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 10
+ CALL SSYRK( 'L', 'N', 2, 0, ALPHA, A, 2, BETA, C, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 10
+ CALL SSYRK( 'L', 'T', 2, 0, ALPHA, A, 1, BETA, C, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ GO TO 70
+ 60 INFOT = 1
+ CALL SSYR2K( '/', 'N', 0, 0, ALPHA, A, 1, B, 1, BETA, C, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 2
+ CALL SSYR2K( 'U', '/', 0, 0, ALPHA, A, 1, B, 1, BETA, C, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 3
+ CALL SSYR2K( 'U', 'N', -1, 0, ALPHA, A, 1, B, 1, BETA, C, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 3
+ CALL SSYR2K( 'U', 'T', -1, 0, ALPHA, A, 1, B, 1, BETA, C, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 3
+ CALL SSYR2K( 'L', 'N', -1, 0, ALPHA, A, 1, B, 1, BETA, C, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 3
+ CALL SSYR2K( 'L', 'T', -1, 0, ALPHA, A, 1, B, 1, BETA, C, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 4
+ CALL SSYR2K( 'U', 'N', 0, -1, ALPHA, A, 1, B, 1, BETA, C, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 4
+ CALL SSYR2K( 'U', 'T', 0, -1, ALPHA, A, 1, B, 1, BETA, C, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 4
+ CALL SSYR2K( 'L', 'N', 0, -1, ALPHA, A, 1, B, 1, BETA, C, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 4
+ CALL SSYR2K( 'L', 'T', 0, -1, ALPHA, A, 1, B, 1, BETA, C, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 7
+ CALL SSYR2K( 'U', 'N', 2, 0, ALPHA, A, 1, B, 1, BETA, C, 2 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 7
+ CALL SSYR2K( 'U', 'T', 0, 2, ALPHA, A, 1, B, 1, BETA, C, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 7
+ CALL SSYR2K( 'L', 'N', 2, 0, ALPHA, A, 1, B, 1, BETA, C, 2 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 7
+ CALL SSYR2K( 'L', 'T', 0, 2, ALPHA, A, 1, B, 1, BETA, C, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 9
+ CALL SSYR2K( 'U', 'N', 2, 0, ALPHA, A, 2, B, 1, BETA, C, 2 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 9
+ CALL SSYR2K( 'U', 'T', 0, 2, ALPHA, A, 2, B, 1, BETA, C, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 9
+ CALL SSYR2K( 'L', 'N', 2, 0, ALPHA, A, 2, B, 1, BETA, C, 2 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 9
+ CALL SSYR2K( 'L', 'T', 0, 2, ALPHA, A, 2, B, 1, BETA, C, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 12
+ CALL SSYR2K( 'U', 'N', 2, 0, ALPHA, A, 2, B, 2, BETA, C, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 12
+ CALL SSYR2K( 'U', 'T', 2, 0, ALPHA, A, 1, B, 1, BETA, C, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 12
+ CALL SSYR2K( 'L', 'N', 2, 0, ALPHA, A, 2, B, 2, BETA, C, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 12
+ CALL SSYR2K( 'L', 'T', 2, 0, ALPHA, A, 1, B, 1, BETA, C, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+*
+ 70 IF( OK )THEN
+ WRITE( NOUT, FMT = 9999 )SRNAMT
+ ELSE
+ WRITE( NOUT, FMT = 9998 )SRNAMT
+ END IF
+ RETURN
+*
+ 9999 FORMAT( ' ', A6, ' PASSED THE TESTS OF ERROR-EXITS' )
+ 9998 FORMAT( ' ******* ', A6, ' FAILED THE TESTS OF ERROR-EXITS *****',
+ $ '**' )
+*
+* End of SCHKE.
+*
+ END
+ SUBROUTINE SMAKE( TYPE, UPLO, DIAG, M, N, A, NMAX, AA, LDA, RESET,
+ $ TRANSL )
+*
+* Generates values for an M by N matrix A.
+* Stores the values in the array AA in the data structure required
+* by the routine, with unwanted elements set to rogue value.
+*
+* TYPE is 'GE', 'SY' or 'TR'.
+*
+* Auxiliary routine for test program for Level 3 Blas.
+*
+* -- Written on 8-February-1989.
+* Jack Dongarra, Argonne National Laboratory.
+* Iain Duff, AERE Harwell.
+* Jeremy Du Croz, Numerical Algorithms Group Ltd.
+* Sven Hammarling, Numerical Algorithms Group Ltd.
+*
+* .. Parameters ..
+ REAL ZERO, ONE
+ PARAMETER ( ZERO = 0.0, ONE = 1.0 )
+ REAL ROGUE
+ PARAMETER ( ROGUE = -1.0E10 )
+* .. Scalar Arguments ..
+ REAL TRANSL
+ INTEGER LDA, M, N, NMAX
+ LOGICAL RESET
+ CHARACTER*1 DIAG, UPLO
+ CHARACTER*2 TYPE
+* .. Array Arguments ..
+ REAL A( NMAX, * ), AA( * )
+* .. Local Scalars ..
+ INTEGER I, IBEG, IEND, J
+ LOGICAL GEN, LOWER, SYM, TRI, UNIT, UPPER
+* .. External Functions ..
+ REAL SBEG
+ EXTERNAL SBEG
+* .. Executable Statements ..
+ GEN = TYPE.EQ.'GE'
+ SYM = TYPE.EQ.'SY'
+ TRI = TYPE.EQ.'TR'
+ UPPER = ( SYM.OR.TRI ).AND.UPLO.EQ.'U'
+ LOWER = ( SYM.OR.TRI ).AND.UPLO.EQ.'L'
+ UNIT = TRI.AND.DIAG.EQ.'U'
+*
+* Generate data in array A.
+*
+ DO 20 J = 1, N
+ DO 10 I = 1, M
+ IF( GEN.OR.( UPPER.AND.I.LE.J ).OR.( LOWER.AND.I.GE.J ) )
+ $ THEN
+ A( I, J ) = SBEG( RESET ) + TRANSL
+ IF( I.NE.J )THEN
+* Set some elements to zero
+ IF( N.GT.3.AND.J.EQ.N/2 )
+ $ A( I, J ) = ZERO
+ IF( SYM )THEN
+ A( J, I ) = A( I, J )
+ ELSE IF( TRI )THEN
+ A( J, I ) = ZERO
+ END IF
+ END IF
+ END IF
+ 10 CONTINUE
+ IF( TRI )
+ $ A( J, J ) = A( J, J ) + ONE
+ IF( UNIT )
+ $ A( J, J ) = ONE
+ 20 CONTINUE
+*
+* Store elements in array AS in data structure required by routine.
+*
+ IF( TYPE.EQ.'GE' )THEN
+ DO 50 J = 1, N
+ DO 30 I = 1, M
+ AA( I + ( J - 1 )*LDA ) = A( I, J )
+ 30 CONTINUE
+ DO 40 I = M + 1, LDA
+ AA( I + ( J - 1 )*LDA ) = ROGUE
+ 40 CONTINUE
+ 50 CONTINUE
+ ELSE IF( TYPE.EQ.'SY'.OR.TYPE.EQ.'TR' )THEN
+ DO 90 J = 1, N
+ IF( UPPER )THEN
+ IBEG = 1
+ IF( UNIT )THEN
+ IEND = J - 1
+ ELSE
+ IEND = J
+ END IF
+ ELSE
+ IF( UNIT )THEN
+ IBEG = J + 1
+ ELSE
+ IBEG = J
+ END IF
+ IEND = N
+ END IF
+ DO 60 I = 1, IBEG - 1
+ AA( I + ( J - 1 )*LDA ) = ROGUE
+ 60 CONTINUE
+ DO 70 I = IBEG, IEND
+ AA( I + ( J - 1 )*LDA ) = A( I, J )
+ 70 CONTINUE
+ DO 80 I = IEND + 1, LDA
+ AA( I + ( J - 1 )*LDA ) = ROGUE
+ 80 CONTINUE
+ 90 CONTINUE
+ END IF
+ RETURN
+*
+* End of SMAKE.
+*
+ END
+ SUBROUTINE SMMCH( TRANSA, TRANSB, M, N, KK, ALPHA, A, LDA, B, LDB,
+ $ BETA, C, LDC, CT, G, CC, LDCC, EPS, ERR, FATAL,
+ $ NOUT, MV )
+*
+* Checks the results of the computational tests.
+*
+* Auxiliary routine for test program for Level 3 Blas.
+*
+* -- Written on 8-February-1989.
+* Jack Dongarra, Argonne National Laboratory.
+* Iain Duff, AERE Harwell.
+* Jeremy Du Croz, Numerical Algorithms Group Ltd.
+* Sven Hammarling, Numerical Algorithms Group Ltd.
+*
+* .. Parameters ..
+ REAL ZERO, ONE
+ PARAMETER ( ZERO = 0.0, ONE = 1.0 )
+* .. Scalar Arguments ..
+ REAL ALPHA, BETA, EPS, ERR
+ INTEGER KK, LDA, LDB, LDC, LDCC, M, N, NOUT
+ LOGICAL FATAL, MV
+ CHARACTER*1 TRANSA, TRANSB
+* .. Array Arguments ..
+ REAL A( LDA, * ), B( LDB, * ), C( LDC, * ),
+ $ CC( LDCC, * ), CT( * ), G( * )
+* .. Local Scalars ..
+ REAL ERRI
+ INTEGER I, J, K
+ LOGICAL TRANA, TRANB
+* .. Intrinsic Functions ..
+ INTRINSIC ABS, MAX, SQRT
+* .. Executable Statements ..
+ TRANA = TRANSA.EQ.'T'.OR.TRANSA.EQ.'C'
+ TRANB = TRANSB.EQ.'T'.OR.TRANSB.EQ.'C'
+*
+* Compute expected result, one column at a time, in CT using data
+* in A, B and C.
+* Compute gauges in G.
+*
+ DO 120 J = 1, N
+*
+ DO 10 I = 1, M
+ CT( I ) = ZERO
+ G( I ) = ZERO
+ 10 CONTINUE
+ IF( .NOT.TRANA.AND..NOT.TRANB )THEN
+ DO 30 K = 1, KK
+ DO 20 I = 1, M
+ CT( I ) = CT( I ) + A( I, K )*B( K, J )
+ G( I ) = G( I ) + ABS( A( I, K ) )*ABS( B( K, J ) )
+ 20 CONTINUE
+ 30 CONTINUE
+ ELSE IF( TRANA.AND..NOT.TRANB )THEN
+ DO 50 K = 1, KK
+ DO 40 I = 1, M
+ CT( I ) = CT( I ) + A( K, I )*B( K, J )
+ G( I ) = G( I ) + ABS( A( K, I ) )*ABS( B( K, J ) )
+ 40 CONTINUE
+ 50 CONTINUE
+ ELSE IF( .NOT.TRANA.AND.TRANB )THEN
+ DO 70 K = 1, KK
+ DO 60 I = 1, M
+ CT( I ) = CT( I ) + A( I, K )*B( J, K )
+ G( I ) = G( I ) + ABS( A( I, K ) )*ABS( B( J, K ) )
+ 60 CONTINUE
+ 70 CONTINUE
+ ELSE IF( TRANA.AND.TRANB )THEN
+ DO 90 K = 1, KK
+ DO 80 I = 1, M
+ CT( I ) = CT( I ) + A( K, I )*B( J, K )
+ G( I ) = G( I ) + ABS( A( K, I ) )*ABS( B( J, K ) )
+ 80 CONTINUE
+ 90 CONTINUE
+ END IF
+ DO 100 I = 1, M
+ CT( I ) = ALPHA*CT( I ) + BETA*C( I, J )
+ G( I ) = ABS( ALPHA )*G( I ) + ABS( BETA )*ABS( C( I, J ) )
+ 100 CONTINUE
+*
+* Compute the error ratio for this result.
+*
+ ERR = ZERO
+ DO 110 I = 1, M
+ ERRI = ABS( CT( I ) - CC( I, J ) )/EPS
+ IF( G( I ).NE.ZERO )
+ $ ERRI = ERRI/G( I )
+ ERR = MAX( ERR, ERRI )
+ IF( ERR*SQRT( EPS ).GE.ONE )
+ $ GO TO 130
+ 110 CONTINUE
+*
+ 120 CONTINUE
+*
+* If the loop completes, all results are at least half accurate.
+ GO TO 150
+*
+* Report fatal error.
+*
+ 130 FATAL = .TRUE.
+ WRITE( NOUT, FMT = 9999 )
+ DO 140 I = 1, M
+ IF( MV )THEN
+ WRITE( NOUT, FMT = 9998 )I, CT( I ), CC( I, J )
+ ELSE
+ WRITE( NOUT, FMT = 9998 )I, CC( I, J ), CT( I )
+ END IF
+ 140 CONTINUE
+ IF( N.GT.1 )
+ $ WRITE( NOUT, FMT = 9997 )J
+*
+ 150 CONTINUE
+ RETURN
+*
+ 9999 FORMAT( ' ******* FATAL ERROR - COMPUTED RESULT IS LESS THAN HAL',
+ $ 'F ACCURATE *******', /' EXPECTED RESULT COMPU',
+ $ 'TED RESULT' )
+ 9998 FORMAT( 1X, I7, 2G18.6 )
+ 9997 FORMAT( ' THESE ARE THE RESULTS FOR COLUMN ', I3 )
+*
+* End of SMMCH.
+*
+ END
+ LOGICAL FUNCTION LSE( RI, RJ, LR )
+*
+* Tests if two arrays are identical.
+*
+* Auxiliary routine for test program for Level 3 Blas.
+*
+* -- Written on 8-February-1989.
+* Jack Dongarra, Argonne National Laboratory.
+* Iain Duff, AERE Harwell.
+* Jeremy Du Croz, Numerical Algorithms Group Ltd.
+* Sven Hammarling, Numerical Algorithms Group Ltd.
+*
+* .. Scalar Arguments ..
+ INTEGER LR
+* .. Array Arguments ..
+ REAL RI( * ), RJ( * )
+* .. Local Scalars ..
+ INTEGER I
+* .. Executable Statements ..
+ DO 10 I = 1, LR
+ IF( RI( I ).NE.RJ( I ) )
+ $ GO TO 20
+ 10 CONTINUE
+ LSE = .TRUE.
+ GO TO 30
+ 20 CONTINUE
+ LSE = .FALSE.
+ 30 RETURN
+*
+* End of LSE.
+*
+ END
+ LOGICAL FUNCTION LSERES( TYPE, UPLO, M, N, AA, AS, LDA )
+*
+* Tests if selected elements in two arrays are equal.
+*
+* TYPE is 'GE' or 'SY'.
+*
+* Auxiliary routine for test program for Level 3 Blas.
+*
+* -- Written on 8-February-1989.
+* Jack Dongarra, Argonne National Laboratory.
+* Iain Duff, AERE Harwell.
+* Jeremy Du Croz, Numerical Algorithms Group Ltd.
+* Sven Hammarling, Numerical Algorithms Group Ltd.
+*
+* .. Scalar Arguments ..
+ INTEGER LDA, M, N
+ CHARACTER*1 UPLO
+ CHARACTER*2 TYPE
+* .. Array Arguments ..
+ REAL AA( LDA, * ), AS( LDA, * )
+* .. Local Scalars ..
+ INTEGER I, IBEG, IEND, J
+ LOGICAL UPPER
+* .. Executable Statements ..
+ UPPER = UPLO.EQ.'U'
+ IF( TYPE.EQ.'GE' )THEN
+ DO 20 J = 1, N
+ DO 10 I = M + 1, LDA
+ IF( AA( I, J ).NE.AS( I, J ) )
+ $ GO TO 70
+ 10 CONTINUE
+ 20 CONTINUE
+ ELSE IF( TYPE.EQ.'SY' )THEN
+ DO 50 J = 1, N
+ IF( UPPER )THEN
+ IBEG = 1
+ IEND = J
+ ELSE
+ IBEG = J
+ IEND = N
+ END IF
+ DO 30 I = 1, IBEG - 1
+ IF( AA( I, J ).NE.AS( I, J ) )
+ $ GO TO 70
+ 30 CONTINUE
+ DO 40 I = IEND + 1, LDA
+ IF( AA( I, J ).NE.AS( I, J ) )
+ $ GO TO 70
+ 40 CONTINUE
+ 50 CONTINUE
+ END IF
+*
+ 60 CONTINUE
+ LSERES = .TRUE.
+ GO TO 80
+ 70 CONTINUE
+ LSERES = .FALSE.
+ 80 RETURN
+*
+* End of LSERES.
+*
+ END
+ REAL FUNCTION SBEG( RESET )
+*
+* Generates random numbers uniformly distributed between -0.5 and 0.5.
+*
+* Auxiliary routine for test program for Level 3 Blas.
+*
+* -- Written on 8-February-1989.
+* Jack Dongarra, Argonne National Laboratory.
+* Iain Duff, AERE Harwell.
+* Jeremy Du Croz, Numerical Algorithms Group Ltd.
+* Sven Hammarling, Numerical Algorithms Group Ltd.
+*
+* .. Scalar Arguments ..
+ LOGICAL RESET
+* .. Local Scalars ..
+ INTEGER I, IC, MI
+* .. Save statement ..
+ SAVE I, IC, MI
+* .. Executable Statements ..
+ IF( RESET )THEN
+* Initialize local variables.
+ MI = 891
+ I = 7
+ IC = 0
+ RESET = .FALSE.
+ END IF
+*
+* The sequence of values of I is bounded between 1 and 999.
+* If initial I = 1,2,3,6,7 or 9, the period will be 50.
+* If initial I = 4 or 8, the period will be 25.
+* If initial I = 5, the period will be 10.
+* IC is used to break up the period by skipping 1 value of I in 6.
+*
+ IC = IC + 1
+ 10 I = I*MI
+ I = I - 1000*( I/1000 )
+ IF( IC.GE.5 )THEN
+ IC = 0
+ GO TO 10
+ END IF
+ SBEG = ( I - 500 )/1001.0
+ RETURN
+*
+* End of SBEG.
+*
+ END
+ REAL FUNCTION SDIFF( X, Y )
+*
+* Auxiliary routine for test program for Level 3 Blas.
+*
+* -- Written on 8-February-1989.
+* Jack Dongarra, Argonne National Laboratory.
+* Iain Duff, AERE Harwell.
+* Jeremy Du Croz, Numerical Algorithms Group Ltd.
+* Sven Hammarling, Numerical Algorithms Group Ltd.
+*
+* .. Scalar Arguments ..
+ REAL X, Y
+* .. Executable Statements ..
+ SDIFF = X - Y
+ RETURN
+*
+* End of SDIFF.
+*
+ END
+ SUBROUTINE CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+*
+* Tests whether XERBLA has detected an error when it should.
+*
+* Auxiliary routine for test program for Level 3 Blas.
+*
+* -- Written on 8-February-1989.
+* Jack Dongarra, Argonne National Laboratory.
+* Iain Duff, AERE Harwell.
+* Jeremy Du Croz, Numerical Algorithms Group Ltd.
+* Sven Hammarling, Numerical Algorithms Group Ltd.
+*
+* .. Scalar Arguments ..
+ INTEGER INFOT, NOUT
+ LOGICAL LERR, OK
+ CHARACTER*6 SRNAMT
+* .. Executable Statements ..
+ IF( .NOT.LERR )THEN
+ WRITE( NOUT, FMT = 9999 )INFOT, SRNAMT
+ OK = .FALSE.
+ END IF
+ LERR = .FALSE.
+ RETURN
+*
+ 9999 FORMAT( ' ***** ILLEGAL VALUE OF PARAMETER NUMBER ', I2, ' NOT D',
+ $ 'ETECTED BY ', A6, ' *****' )
+*
+* End of CHKXER.
+*
+ END
+ SUBROUTINE XERBLA( SRNAME, INFO )
+*
+* This is a special version of XERBLA to be used only as part of
+* the test program for testing error exits from the Level 3 BLAS
+* routines.
+*
+* XERBLA is an error handler for the Level 3 BLAS routines.
+*
+* It is called by the Level 3 BLAS routines if an input parameter is
+* invalid.
+*
+* Auxiliary routine for test program for Level 3 Blas.
+*
+* -- Written on 8-February-1989.
+* Jack Dongarra, Argonne National Laboratory.
+* Iain Duff, AERE Harwell.
+* Jeremy Du Croz, Numerical Algorithms Group Ltd.
+* Sven Hammarling, Numerical Algorithms Group Ltd.
+*
+* .. Scalar Arguments ..
+ INTEGER INFO
+ CHARACTER*6 SRNAME
+* .. Scalars in Common ..
+ INTEGER INFOT, NOUT
+ LOGICAL LERR, OK
+ CHARACTER*6 SRNAMT
+* .. Common blocks ..
+ COMMON /INFOC/INFOT, NOUT, OK, LERR
+ COMMON /SRNAMC/SRNAMT
+* .. Executable Statements ..
+ LERR = .TRUE.
+ IF( INFO.NE.INFOT )THEN
+ IF( INFOT.NE.0 )THEN
+ WRITE( NOUT, FMT = 9999 )INFO, INFOT
+ ELSE
+ WRITE( NOUT, FMT = 9997 )INFO
+ END IF
+ OK = .FALSE.
+ END IF
+ IF( SRNAME.NE.SRNAMT )THEN
+ WRITE( NOUT, FMT = 9998 )SRNAME, SRNAMT
+ OK = .FALSE.
+ END IF
+ RETURN
+*
+ 9999 FORMAT( ' ******* XERBLA WAS CALLED WITH INFO = ', I6, ' INSTEAD',
+ $ ' OF ', I2, ' *******' )
+ 9998 FORMAT( ' ******* XERBLA WAS CALLED WITH SRNAME = ', A6, ' INSTE',
+ $ 'AD OF ', A6, ' *******' )
+ 9997 FORMAT( ' ******* XERBLA WAS CALLED WITH INFO = ', I6,
+ $ ' *******' )
+*
+* End of XERBLA
+*
+ END
+
diff --git a/blas/testing/zblat1.f b/blas/testing/zblat1.f
new file mode 100644
index 000000000..e2415e1c4
--- /dev/null
+++ b/blas/testing/zblat1.f
@@ -0,0 +1,681 @@
+ PROGRAM ZBLAT1
+* Test program for the COMPLEX*16 Level 1 BLAS.
+* Based upon the original BLAS test routine together with:
+* F06GAF Example Program Text
+* .. Parameters ..
+ INTEGER NOUT
+ PARAMETER (NOUT=6)
+* .. Scalars in Common ..
+ INTEGER ICASE, INCX, INCY, MODE, N
+ LOGICAL PASS
+* .. Local Scalars ..
+ DOUBLE PRECISION SFAC
+ INTEGER IC
+* .. External Subroutines ..
+ EXTERNAL CHECK1, CHECK2, HEADER
+* .. Common blocks ..
+ COMMON /COMBLA/ICASE, N, INCX, INCY, MODE, PASS
+* .. Data statements ..
+ DATA SFAC/9.765625D-4/
+* .. Executable Statements ..
+ WRITE (NOUT,99999)
+ DO 20 IC = 1, 10
+ ICASE = IC
+ CALL HEADER
+*
+* Initialize PASS, INCX, INCY, and MODE for a new case.
+* The value 9999 for INCX, INCY or MODE will appear in the
+* detailed output, if any, for cases that do not involve
+* these parameters.
+*
+ PASS = .TRUE.
+ INCX = 9999
+ INCY = 9999
+ MODE = 9999
+ IF (ICASE.LE.5) THEN
+ CALL CHECK2(SFAC)
+ ELSE IF (ICASE.GE.6) THEN
+ CALL CHECK1(SFAC)
+ END IF
+* -- Print
+ IF (PASS) WRITE (NOUT,99998)
+ 20 CONTINUE
+ STOP
+*
+99999 FORMAT (' Complex BLAS Test Program Results',/1X)
+99998 FORMAT (' ----- PASS -----')
+ END
+ SUBROUTINE HEADER
+* .. Parameters ..
+ INTEGER NOUT
+ PARAMETER (NOUT=6)
+* .. Scalars in Common ..
+ INTEGER ICASE, INCX, INCY, MODE, N
+ LOGICAL PASS
+* .. Local Arrays ..
+ CHARACTER*6 L(10)
+* .. Common blocks ..
+ COMMON /COMBLA/ICASE, N, INCX, INCY, MODE, PASS
+* .. Data statements ..
+ DATA L(1)/'ZDOTC '/
+ DATA L(2)/'ZDOTU '/
+ DATA L(3)/'ZAXPY '/
+ DATA L(4)/'ZCOPY '/
+ DATA L(5)/'ZSWAP '/
+ DATA L(6)/'DZNRM2'/
+ DATA L(7)/'DZASUM'/
+ DATA L(8)/'ZSCAL '/
+ DATA L(9)/'ZDSCAL'/
+ DATA L(10)/'IZAMAX'/
+* .. Executable Statements ..
+ WRITE (NOUT,99999) ICASE, L(ICASE)
+ RETURN
+*
+99999 FORMAT (/' Test of subprogram number',I3,12X,A6)
+ END
+ SUBROUTINE CHECK1(SFAC)
+* .. Parameters ..
+ INTEGER NOUT
+ PARAMETER (NOUT=6)
+* .. Scalar Arguments ..
+ DOUBLE PRECISION SFAC
+* .. Scalars in Common ..
+ INTEGER ICASE, INCX, INCY, MODE, N
+ LOGICAL PASS
+* .. Local Scalars ..
+ COMPLEX*16 CA
+ DOUBLE PRECISION SA
+ INTEGER I, J, LEN, NP1
+* .. Local Arrays ..
+ COMPLEX*16 CTRUE5(8,5,2), CTRUE6(8,5,2), CV(8,5,2), CX(8),
+ + MWPCS(5), MWPCT(5)
+ DOUBLE PRECISION STRUE2(5), STRUE4(5)
+ INTEGER ITRUE3(5)
+* .. External Functions ..
+ DOUBLE PRECISION DZASUM, DZNRM2
+ INTEGER IZAMAX
+ EXTERNAL DZASUM, DZNRM2, IZAMAX
+* .. External Subroutines ..
+ EXTERNAL ZSCAL, ZDSCAL, CTEST, ITEST1, STEST1
+* .. Intrinsic Functions ..
+ INTRINSIC MAX
+* .. Common blocks ..
+ COMMON /COMBLA/ICASE, N, INCX, INCY, MODE, PASS
+* .. Data statements ..
+ DATA SA, CA/0.3D0, (0.4D0,-0.7D0)/
+ DATA ((CV(I,J,1),I=1,8),J=1,5)/(0.1D0,0.1D0),
+ + (1.0D0,2.0D0), (1.0D0,2.0D0), (1.0D0,2.0D0),
+ + (1.0D0,2.0D0), (1.0D0,2.0D0), (1.0D0,2.0D0),
+ + (1.0D0,2.0D0), (0.3D0,-0.4D0), (3.0D0,4.0D0),
+ + (3.0D0,4.0D0), (3.0D0,4.0D0), (3.0D0,4.0D0),
+ + (3.0D0,4.0D0), (3.0D0,4.0D0), (3.0D0,4.0D0),
+ + (0.1D0,-0.3D0), (0.5D0,-0.1D0), (5.0D0,6.0D0),
+ + (5.0D0,6.0D0), (5.0D0,6.0D0), (5.0D0,6.0D0),
+ + (5.0D0,6.0D0), (5.0D0,6.0D0), (0.1D0,0.1D0),
+ + (-0.6D0,0.1D0), (0.1D0,-0.3D0), (7.0D0,8.0D0),
+ + (7.0D0,8.0D0), (7.0D0,8.0D0), (7.0D0,8.0D0),
+ + (7.0D0,8.0D0), (0.3D0,0.1D0), (0.1D0,0.4D0),
+ + (0.4D0,0.1D0), (0.1D0,0.2D0), (2.0D0,3.0D0),
+ + (2.0D0,3.0D0), (2.0D0,3.0D0), (2.0D0,3.0D0)/
+ DATA ((CV(I,J,2),I=1,8),J=1,5)/(0.1D0,0.1D0),
+ + (4.0D0,5.0D0), (4.0D0,5.0D0), (4.0D0,5.0D0),
+ + (4.0D0,5.0D0), (4.0D0,5.0D0), (4.0D0,5.0D0),
+ + (4.0D0,5.0D0), (0.3D0,-0.4D0), (6.0D0,7.0D0),
+ + (6.0D0,7.0D0), (6.0D0,7.0D0), (6.0D0,7.0D0),
+ + (6.0D0,7.0D0), (6.0D0,7.0D0), (6.0D0,7.0D0),
+ + (0.1D0,-0.3D0), (8.0D0,9.0D0), (0.5D0,-0.1D0),
+ + (2.0D0,5.0D0), (2.0D0,5.0D0), (2.0D0,5.0D0),
+ + (2.0D0,5.0D0), (2.0D0,5.0D0), (0.1D0,0.1D0),
+ + (3.0D0,6.0D0), (-0.6D0,0.1D0), (4.0D0,7.0D0),
+ + (0.1D0,-0.3D0), (7.0D0,2.0D0), (7.0D0,2.0D0),
+ + (7.0D0,2.0D0), (0.3D0,0.1D0), (5.0D0,8.0D0),
+ + (0.1D0,0.4D0), (6.0D0,9.0D0), (0.4D0,0.1D0),
+ + (8.0D0,3.0D0), (0.1D0,0.2D0), (9.0D0,4.0D0)/
+ DATA STRUE2/0.0D0, 0.5D0, 0.6D0, 0.7D0, 0.7D0/
+ DATA STRUE4/0.0D0, 0.7D0, 1.0D0, 1.3D0, 1.7D0/
+ DATA ((CTRUE5(I,J,1),I=1,8),J=1,5)/(0.1D0,0.1D0),
+ + (1.0D0,2.0D0), (1.0D0,2.0D0), (1.0D0,2.0D0),
+ + (1.0D0,2.0D0), (1.0D0,2.0D0), (1.0D0,2.0D0),
+ + (1.0D0,2.0D0), (-0.16D0,-0.37D0), (3.0D0,4.0D0),
+ + (3.0D0,4.0D0), (3.0D0,4.0D0), (3.0D0,4.0D0),
+ + (3.0D0,4.0D0), (3.0D0,4.0D0), (3.0D0,4.0D0),
+ + (-0.17D0,-0.19D0), (0.13D0,-0.39D0),
+ + (5.0D0,6.0D0), (5.0D0,6.0D0), (5.0D0,6.0D0),
+ + (5.0D0,6.0D0), (5.0D0,6.0D0), (5.0D0,6.0D0),
+ + (0.11D0,-0.03D0), (-0.17D0,0.46D0),
+ + (-0.17D0,-0.19D0), (7.0D0,8.0D0), (7.0D0,8.0D0),
+ + (7.0D0,8.0D0), (7.0D0,8.0D0), (7.0D0,8.0D0),
+ + (0.19D0,-0.17D0), (0.32D0,0.09D0),
+ + (0.23D0,-0.24D0), (0.18D0,0.01D0),
+ + (2.0D0,3.0D0), (2.0D0,3.0D0), (2.0D0,3.0D0),
+ + (2.0D0,3.0D0)/
+ DATA ((CTRUE5(I,J,2),I=1,8),J=1,5)/(0.1D0,0.1D0),
+ + (4.0D0,5.0D0), (4.0D0,5.0D0), (4.0D0,5.0D0),
+ + (4.0D0,5.0D0), (4.0D0,5.0D0), (4.0D0,5.0D0),
+ + (4.0D0,5.0D0), (-0.16D0,-0.37D0), (6.0D0,7.0D0),
+ + (6.0D0,7.0D0), (6.0D0,7.0D0), (6.0D0,7.0D0),
+ + (6.0D0,7.0D0), (6.0D0,7.0D0), (6.0D0,7.0D0),
+ + (-0.17D0,-0.19D0), (8.0D0,9.0D0),
+ + (0.13D0,-0.39D0), (2.0D0,5.0D0), (2.0D0,5.0D0),
+ + (2.0D0,5.0D0), (2.0D0,5.0D0), (2.0D0,5.0D0),
+ + (0.11D0,-0.03D0), (3.0D0,6.0D0),
+ + (-0.17D0,0.46D0), (4.0D0,7.0D0),
+ + (-0.17D0,-0.19D0), (7.0D0,2.0D0), (7.0D0,2.0D0),
+ + (7.0D0,2.0D0), (0.19D0,-0.17D0), (5.0D0,8.0D0),
+ + (0.32D0,0.09D0), (6.0D0,9.0D0),
+ + (0.23D0,-0.24D0), (8.0D0,3.0D0),
+ + (0.18D0,0.01D0), (9.0D0,4.0D0)/
+ DATA ((CTRUE6(I,J,1),I=1,8),J=1,5)/(0.1D0,0.1D0),
+ + (1.0D0,2.0D0), (1.0D0,2.0D0), (1.0D0,2.0D0),
+ + (1.0D0,2.0D0), (1.0D0,2.0D0), (1.0D0,2.0D0),
+ + (1.0D0,2.0D0), (0.09D0,-0.12D0), (3.0D0,4.0D0),
+ + (3.0D0,4.0D0), (3.0D0,4.0D0), (3.0D0,4.0D0),
+ + (3.0D0,4.0D0), (3.0D0,4.0D0), (3.0D0,4.0D0),
+ + (0.03D0,-0.09D0), (0.15D0,-0.03D0),
+ + (5.0D0,6.0D0), (5.0D0,6.0D0), (5.0D0,6.0D0),
+ + (5.0D0,6.0D0), (5.0D0,6.0D0), (5.0D0,6.0D0),
+ + (0.03D0,0.03D0), (-0.18D0,0.03D0),
+ + (0.03D0,-0.09D0), (7.0D0,8.0D0), (7.0D0,8.0D0),
+ + (7.0D0,8.0D0), (7.0D0,8.0D0), (7.0D0,8.0D0),
+ + (0.09D0,0.03D0), (0.03D0,0.12D0),
+ + (0.12D0,0.03D0), (0.03D0,0.06D0), (2.0D0,3.0D0),
+ + (2.0D0,3.0D0), (2.0D0,3.0D0), (2.0D0,3.0D0)/
+ DATA ((CTRUE6(I,J,2),I=1,8),J=1,5)/(0.1D0,0.1D0),
+ + (4.0D0,5.0D0), (4.0D0,5.0D0), (4.0D0,5.0D0),
+ + (4.0D0,5.0D0), (4.0D0,5.0D0), (4.0D0,5.0D0),
+ + (4.0D0,5.0D0), (0.09D0,-0.12D0), (6.0D0,7.0D0),
+ + (6.0D0,7.0D0), (6.0D0,7.0D0), (6.0D0,7.0D0),
+ + (6.0D0,7.0D0), (6.0D0,7.0D0), (6.0D0,7.0D0),
+ + (0.03D0,-0.09D0), (8.0D0,9.0D0),
+ + (0.15D0,-0.03D0), (2.0D0,5.0D0), (2.0D0,5.0D0),
+ + (2.0D0,5.0D0), (2.0D0,5.0D0), (2.0D0,5.0D0),
+ + (0.03D0,0.03D0), (3.0D0,6.0D0),
+ + (-0.18D0,0.03D0), (4.0D0,7.0D0),
+ + (0.03D0,-0.09D0), (7.0D0,2.0D0), (7.0D0,2.0D0),
+ + (7.0D0,2.0D0), (0.09D0,0.03D0), (5.0D0,8.0D0),
+ + (0.03D0,0.12D0), (6.0D0,9.0D0), (0.12D0,0.03D0),
+ + (8.0D0,3.0D0), (0.03D0,0.06D0), (9.0D0,4.0D0)/
+ DATA ITRUE3/0, 1, 2, 2, 2/
+* .. Executable Statements ..
+ DO 60 INCX = 1, 2
+ DO 40 NP1 = 1, 5
+ N = NP1 - 1
+ LEN = 2*MAX(N,1)
+* .. Set vector arguments ..
+ DO 20 I = 1, LEN
+ CX(I) = CV(I,NP1,INCX)
+ 20 CONTINUE
+ IF (ICASE.EQ.6) THEN
+* .. DZNRM2 ..
+ CALL STEST1(DZNRM2(N,CX,INCX),STRUE2(NP1),STRUE2(NP1),
+ + SFAC)
+ ELSE IF (ICASE.EQ.7) THEN
+* .. DZASUM ..
+ CALL STEST1(DZASUM(N,CX,INCX),STRUE4(NP1),STRUE4(NP1),
+ + SFAC)
+ ELSE IF (ICASE.EQ.8) THEN
+* .. ZSCAL ..
+ CALL ZSCAL(N,CA,CX,INCX)
+ CALL CTEST(LEN,CX,CTRUE5(1,NP1,INCX),CTRUE5(1,NP1,INCX),
+ + SFAC)
+ ELSE IF (ICASE.EQ.9) THEN
+* .. ZDSCAL ..
+ CALL ZDSCAL(N,SA,CX,INCX)
+ CALL CTEST(LEN,CX,CTRUE6(1,NP1,INCX),CTRUE6(1,NP1,INCX),
+ + SFAC)
+ ELSE IF (ICASE.EQ.10) THEN
+* .. IZAMAX ..
+ CALL ITEST1(IZAMAX(N,CX,INCX),ITRUE3(NP1))
+ ELSE
+ WRITE (NOUT,*) ' Shouldn''t be here in CHECK1'
+ STOP
+ END IF
+*
+ 40 CONTINUE
+ 60 CONTINUE
+*
+ INCX = 1
+ IF (ICASE.EQ.8) THEN
+* ZSCAL
+* Add a test for alpha equal to zero.
+ CA = (0.0D0,0.0D0)
+ DO 80 I = 1, 5
+ MWPCT(I) = (0.0D0,0.0D0)
+ MWPCS(I) = (1.0D0,1.0D0)
+ 80 CONTINUE
+ CALL ZSCAL(5,CA,CX,INCX)
+ CALL CTEST(5,CX,MWPCT,MWPCS,SFAC)
+ ELSE IF (ICASE.EQ.9) THEN
+* ZDSCAL
+* Add a test for alpha equal to zero.
+ SA = 0.0D0
+ DO 100 I = 1, 5
+ MWPCT(I) = (0.0D0,0.0D0)
+ MWPCS(I) = (1.0D0,1.0D0)
+ 100 CONTINUE
+ CALL ZDSCAL(5,SA,CX,INCX)
+ CALL CTEST(5,CX,MWPCT,MWPCS,SFAC)
+* Add a test for alpha equal to one.
+ SA = 1.0D0
+ DO 120 I = 1, 5
+ MWPCT(I) = CX(I)
+ MWPCS(I) = CX(I)
+ 120 CONTINUE
+ CALL ZDSCAL(5,SA,CX,INCX)
+ CALL CTEST(5,CX,MWPCT,MWPCS,SFAC)
+* Add a test for alpha equal to minus one.
+ SA = -1.0D0
+ DO 140 I = 1, 5
+ MWPCT(I) = -CX(I)
+ MWPCS(I) = -CX(I)
+ 140 CONTINUE
+ CALL ZDSCAL(5,SA,CX,INCX)
+ CALL CTEST(5,CX,MWPCT,MWPCS,SFAC)
+ END IF
+ RETURN
+ END
+ SUBROUTINE CHECK2(SFAC)
+* .. Parameters ..
+ INTEGER NOUT
+ PARAMETER (NOUT=6)
+* .. Scalar Arguments ..
+ DOUBLE PRECISION SFAC
+* .. Scalars in Common ..
+ INTEGER ICASE, INCX, INCY, MODE, N
+ LOGICAL PASS
+* .. Local Scalars ..
+ COMPLEX*16 CA
+ INTEGER I, J, KI, KN, KSIZE, LENX, LENY, MX, MY
+* .. Local Arrays ..
+ COMPLEX*16 CDOT(1), CSIZE1(4), CSIZE2(7,2), CSIZE3(14),
+ + CT10X(7,4,4), CT10Y(7,4,4), CT6(4,4), CT7(4,4),
+ + CT8(7,4,4), CX(7), CX1(7), CY(7), CY1(7)
+ INTEGER INCXS(4), INCYS(4), LENS(4,2), NS(4)
+* .. External Functions ..
+ COMPLEX*16 ZDOTC, ZDOTU
+ EXTERNAL ZDOTC, ZDOTU
+* .. External Subroutines ..
+ EXTERNAL ZAXPY, ZCOPY, ZSWAP, CTEST
+* .. Intrinsic Functions ..
+ INTRINSIC ABS, MIN
+* .. Common blocks ..
+ COMMON /COMBLA/ICASE, N, INCX, INCY, MODE, PASS
+* .. Data statements ..
+ DATA CA/(0.4D0,-0.7D0)/
+ DATA INCXS/1, 2, -2, -1/
+ DATA INCYS/1, -2, 1, -2/
+ DATA LENS/1, 1, 2, 4, 1, 1, 3, 7/
+ DATA NS/0, 1, 2, 4/
+ DATA CX1/(0.7D0,-0.8D0), (-0.4D0,-0.7D0),
+ + (-0.1D0,-0.9D0), (0.2D0,-0.8D0),
+ + (-0.9D0,-0.4D0), (0.1D0,0.4D0), (-0.6D0,0.6D0)/
+ DATA CY1/(0.6D0,-0.6D0), (-0.9D0,0.5D0),
+ + (0.7D0,-0.6D0), (0.1D0,-0.5D0), (-0.1D0,-0.2D0),
+ + (-0.5D0,-0.3D0), (0.8D0,-0.7D0)/
+ DATA ((CT8(I,J,1),I=1,7),J=1,4)/(0.6D0,-0.6D0),
+ + (0.0D0,0.0D0), (0.0D0,0.0D0), (0.0D0,0.0D0),
+ + (0.0D0,0.0D0), (0.0D0,0.0D0), (0.0D0,0.0D0),
+ + (0.32D0,-1.41D0), (0.0D0,0.0D0), (0.0D0,0.0D0),
+ + (0.0D0,0.0D0), (0.0D0,0.0D0), (0.0D0,0.0D0),
+ + (0.0D0,0.0D0), (0.32D0,-1.41D0),
+ + (-1.55D0,0.5D0), (0.0D0,0.0D0), (0.0D0,0.0D0),
+ + (0.0D0,0.0D0), (0.0D0,0.0D0), (0.0D0,0.0D0),
+ + (0.32D0,-1.41D0), (-1.55D0,0.5D0),
+ + (0.03D0,-0.89D0), (-0.38D0,-0.96D0),
+ + (0.0D0,0.0D0), (0.0D0,0.0D0), (0.0D0,0.0D0)/
+ DATA ((CT8(I,J,2),I=1,7),J=1,4)/(0.6D0,-0.6D0),
+ + (0.0D0,0.0D0), (0.0D0,0.0D0), (0.0D0,0.0D0),
+ + (0.0D0,0.0D0), (0.0D0,0.0D0), (0.0D0,0.0D0),
+ + (0.32D0,-1.41D0), (0.0D0,0.0D0), (0.0D0,0.0D0),
+ + (0.0D0,0.0D0), (0.0D0,0.0D0), (0.0D0,0.0D0),
+ + (0.0D0,0.0D0), (-0.07D0,-0.89D0),
+ + (-0.9D0,0.5D0), (0.42D0,-1.41D0), (0.0D0,0.0D0),
+ + (0.0D0,0.0D0), (0.0D0,0.0D0), (0.0D0,0.0D0),
+ + (0.78D0,0.06D0), (-0.9D0,0.5D0),
+ + (0.06D0,-0.13D0), (0.1D0,-0.5D0),
+ + (-0.77D0,-0.49D0), (-0.5D0,-0.3D0),
+ + (0.52D0,-1.51D0)/
+ DATA ((CT8(I,J,3),I=1,7),J=1,4)/(0.6D0,-0.6D0),
+ + (0.0D0,0.0D0), (0.0D0,0.0D0), (0.0D0,0.0D0),
+ + (0.0D0,0.0D0), (0.0D0,0.0D0), (0.0D0,0.0D0),
+ + (0.32D0,-1.41D0), (0.0D0,0.0D0), (0.0D0,0.0D0),
+ + (0.0D0,0.0D0), (0.0D0,0.0D0), (0.0D0,0.0D0),
+ + (0.0D0,0.0D0), (-0.07D0,-0.89D0),
+ + (-1.18D0,-0.31D0), (0.0D0,0.0D0), (0.0D0,0.0D0),
+ + (0.0D0,0.0D0), (0.0D0,0.0D0), (0.0D0,0.0D0),
+ + (0.78D0,0.06D0), (-1.54D0,0.97D0),
+ + (0.03D0,-0.89D0), (-0.18D0,-1.31D0),
+ + (0.0D0,0.0D0), (0.0D0,0.0D0), (0.0D0,0.0D0)/
+ DATA ((CT8(I,J,4),I=1,7),J=1,4)/(0.6D0,-0.6D0),
+ + (0.0D0,0.0D0), (0.0D0,0.0D0), (0.0D0,0.0D0),
+ + (0.0D0,0.0D0), (0.0D0,0.0D0), (0.0D0,0.0D0),
+ + (0.32D0,-1.41D0), (0.0D0,0.0D0), (0.0D0,0.0D0),
+ + (0.0D0,0.0D0), (0.0D0,0.0D0), (0.0D0,0.0D0),
+ + (0.0D0,0.0D0), (0.32D0,-1.41D0), (-0.9D0,0.5D0),
+ + (0.05D0,-0.6D0), (0.0D0,0.0D0), (0.0D0,0.0D0),
+ + (0.0D0,0.0D0), (0.0D0,0.0D0), (0.32D0,-1.41D0),
+ + (-0.9D0,0.5D0), (0.05D0,-0.6D0), (0.1D0,-0.5D0),
+ + (-0.77D0,-0.49D0), (-0.5D0,-0.3D0),
+ + (0.32D0,-1.16D0)/
+ DATA CT7/(0.0D0,0.0D0), (-0.06D0,-0.90D0),
+ + (0.65D0,-0.47D0), (-0.34D0,-1.22D0),
+ + (0.0D0,0.0D0), (-0.06D0,-0.90D0),
+ + (-0.59D0,-1.46D0), (-1.04D0,-0.04D0),
+ + (0.0D0,0.0D0), (-0.06D0,-0.90D0),
+ + (-0.83D0,0.59D0), (0.07D0,-0.37D0),
+ + (0.0D0,0.0D0), (-0.06D0,-0.90D0),
+ + (-0.76D0,-1.15D0), (-1.33D0,-1.82D0)/
+ DATA CT6/(0.0D0,0.0D0), (0.90D0,0.06D0),
+ + (0.91D0,-0.77D0), (1.80D0,-0.10D0),
+ + (0.0D0,0.0D0), (0.90D0,0.06D0), (1.45D0,0.74D0),
+ + (0.20D0,0.90D0), (0.0D0,0.0D0), (0.90D0,0.06D0),
+ + (-0.55D0,0.23D0), (0.83D0,-0.39D0),
+ + (0.0D0,0.0D0), (0.90D0,0.06D0), (1.04D0,0.79D0),
+ + (1.95D0,1.22D0)/
+ DATA ((CT10X(I,J,1),I=1,7),J=1,4)/(0.7D0,-0.8D0),
+ + (0.0D0,0.0D0), (0.0D0,0.0D0), (0.0D0,0.0D0),
+ + (0.0D0,0.0D0), (0.0D0,0.0D0), (0.0D0,0.0D0),
+ + (0.6D0,-0.6D0), (0.0D0,0.0D0), (0.0D0,0.0D0),
+ + (0.0D0,0.0D0), (0.0D0,0.0D0), (0.0D0,0.0D0),
+ + (0.0D0,0.0D0), (0.6D0,-0.6D0), (-0.9D0,0.5D0),
+ + (0.0D0,0.0D0), (0.0D0,0.0D0), (0.0D0,0.0D0),
+ + (0.0D0,0.0D0), (0.0D0,0.0D0), (0.6D0,-0.6D0),
+ + (-0.9D0,0.5D0), (0.7D0,-0.6D0), (0.1D0,-0.5D0),
+ + (0.0D0,0.0D0), (0.0D0,0.0D0), (0.0D0,0.0D0)/
+ DATA ((CT10X(I,J,2),I=1,7),J=1,4)/(0.7D0,-0.8D0),
+ + (0.0D0,0.0D0), (0.0D0,0.0D0), (0.0D0,0.0D0),
+ + (0.0D0,0.0D0), (0.0D0,0.0D0), (0.0D0,0.0D0),
+ + (0.6D0,-0.6D0), (0.0D0,0.0D0), (0.0D0,0.0D0),
+ + (0.0D0,0.0D0), (0.0D0,0.0D0), (0.0D0,0.0D0),
+ + (0.0D0,0.0D0), (0.7D0,-0.6D0), (-0.4D0,-0.7D0),
+ + (0.6D0,-0.6D0), (0.0D0,0.0D0), (0.0D0,0.0D0),
+ + (0.0D0,0.0D0), (0.0D0,0.0D0), (0.8D0,-0.7D0),
+ + (-0.4D0,-0.7D0), (-0.1D0,-0.2D0),
+ + (0.2D0,-0.8D0), (0.7D0,-0.6D0), (0.1D0,0.4D0),
+ + (0.6D0,-0.6D0)/
+ DATA ((CT10X(I,J,3),I=1,7),J=1,4)/(0.7D0,-0.8D0),
+ + (0.0D0,0.0D0), (0.0D0,0.0D0), (0.0D0,0.0D0),
+ + (0.0D0,0.0D0), (0.0D0,0.0D0), (0.0D0,0.0D0),
+ + (0.6D0,-0.6D0), (0.0D0,0.0D0), (0.0D0,0.0D0),
+ + (0.0D0,0.0D0), (0.0D0,0.0D0), (0.0D0,0.0D0),
+ + (0.0D0,0.0D0), (-0.9D0,0.5D0), (-0.4D0,-0.7D0),
+ + (0.6D0,-0.6D0), (0.0D0,0.0D0), (0.0D0,0.0D0),
+ + (0.0D0,0.0D0), (0.0D0,0.0D0), (0.1D0,-0.5D0),
+ + (-0.4D0,-0.7D0), (0.7D0,-0.6D0), (0.2D0,-0.8D0),
+ + (-0.9D0,0.5D0), (0.1D0,0.4D0), (0.6D0,-0.6D0)/
+ DATA ((CT10X(I,J,4),I=1,7),J=1,4)/(0.7D0,-0.8D0),
+ + (0.0D0,0.0D0), (0.0D0,0.0D0), (0.0D0,0.0D0),
+ + (0.0D0,0.0D0), (0.0D0,0.0D0), (0.0D0,0.0D0),
+ + (0.6D0,-0.6D0), (0.0D0,0.0D0), (0.0D0,0.0D0),
+ + (0.0D0,0.0D0), (0.0D0,0.0D0), (0.0D0,0.0D0),
+ + (0.0D0,0.0D0), (0.6D0,-0.6D0), (0.7D0,-0.6D0),
+ + (0.0D0,0.0D0), (0.0D0,0.0D0), (0.0D0,0.0D0),
+ + (0.0D0,0.0D0), (0.0D0,0.0D0), (0.6D0,-0.6D0),
+ + (0.7D0,-0.6D0), (-0.1D0,-0.2D0), (0.8D0,-0.7D0),
+ + (0.0D0,0.0D0), (0.0D0,0.0D0), (0.0D0,0.0D0)/
+ DATA ((CT10Y(I,J,1),I=1,7),J=1,4)/(0.6D0,-0.6D0),
+ + (0.0D0,0.0D0), (0.0D0,0.0D0), (0.0D0,0.0D0),
+ + (0.0D0,0.0D0), (0.0D0,0.0D0), (0.0D0,0.0D0),
+ + (0.7D0,-0.8D0), (0.0D0,0.0D0), (0.0D0,0.0D0),
+ + (0.0D0,0.0D0), (0.0D0,0.0D0), (0.0D0,0.0D0),
+ + (0.0D0,0.0D0), (0.7D0,-0.8D0), (-0.4D0,-0.7D0),
+ + (0.0D0,0.0D0), (0.0D0,0.0D0), (0.0D0,0.0D0),
+ + (0.0D0,0.0D0), (0.0D0,0.0D0), (0.7D0,-0.8D0),
+ + (-0.4D0,-0.7D0), (-0.1D0,-0.9D0),
+ + (0.2D0,-0.8D0), (0.0D0,0.0D0), (0.0D0,0.0D0),
+ + (0.0D0,0.0D0)/
+ DATA ((CT10Y(I,J,2),I=1,7),J=1,4)/(0.6D0,-0.6D0),
+ + (0.0D0,0.0D0), (0.0D0,0.0D0), (0.0D0,0.0D0),
+ + (0.0D0,0.0D0), (0.0D0,0.0D0), (0.0D0,0.0D0),
+ + (0.7D0,-0.8D0), (0.0D0,0.0D0), (0.0D0,0.0D0),
+ + (0.0D0,0.0D0), (0.0D0,0.0D0), (0.0D0,0.0D0),
+ + (0.0D0,0.0D0), (-0.1D0,-0.9D0), (-0.9D0,0.5D0),
+ + (0.7D0,-0.8D0), (0.0D0,0.0D0), (0.0D0,0.0D0),
+ + (0.0D0,0.0D0), (0.0D0,0.0D0), (-0.6D0,0.6D0),
+ + (-0.9D0,0.5D0), (-0.9D0,-0.4D0), (0.1D0,-0.5D0),
+ + (-0.1D0,-0.9D0), (-0.5D0,-0.3D0),
+ + (0.7D0,-0.8D0)/
+ DATA ((CT10Y(I,J,3),I=1,7),J=1,4)/(0.6D0,-0.6D0),
+ + (0.0D0,0.0D0), (0.0D0,0.0D0), (0.0D0,0.0D0),
+ + (0.0D0,0.0D0), (0.0D0,0.0D0), (0.0D0,0.0D0),
+ + (0.7D0,-0.8D0), (0.0D0,0.0D0), (0.0D0,0.0D0),
+ + (0.0D0,0.0D0), (0.0D0,0.0D0), (0.0D0,0.0D0),
+ + (0.0D0,0.0D0), (-0.1D0,-0.9D0), (0.7D0,-0.8D0),
+ + (0.0D0,0.0D0), (0.0D0,0.0D0), (0.0D0,0.0D0),
+ + (0.0D0,0.0D0), (0.0D0,0.0D0), (-0.6D0,0.6D0),
+ + (-0.9D0,-0.4D0), (-0.1D0,-0.9D0),
+ + (0.7D0,-0.8D0), (0.0D0,0.0D0), (0.0D0,0.0D0),
+ + (0.0D0,0.0D0)/
+ DATA ((CT10Y(I,J,4),I=1,7),J=1,4)/(0.6D0,-0.6D0),
+ + (0.0D0,0.0D0), (0.0D0,0.0D0), (0.0D0,0.0D0),
+ + (0.0D0,0.0D0), (0.0D0,0.0D0), (0.0D0,0.0D0),
+ + (0.7D0,-0.8D0), (0.0D0,0.0D0), (0.0D0,0.0D0),
+ + (0.0D0,0.0D0), (0.0D0,0.0D0), (0.0D0,0.0D0),
+ + (0.0D0,0.0D0), (0.7D0,-0.8D0), (-0.9D0,0.5D0),
+ + (-0.4D0,-0.7D0), (0.0D0,0.0D0), (0.0D0,0.0D0),
+ + (0.0D0,0.0D0), (0.0D0,0.0D0), (0.7D0,-0.8D0),
+ + (-0.9D0,0.5D0), (-0.4D0,-0.7D0), (0.1D0,-0.5D0),
+ + (-0.1D0,-0.9D0), (-0.5D0,-0.3D0),
+ + (0.2D0,-0.8D0)/
+ DATA CSIZE1/(0.0D0,0.0D0), (0.9D0,0.9D0),
+ + (1.63D0,1.73D0), (2.90D0,2.78D0)/
+ DATA CSIZE3/(0.0D0,0.0D0), (0.0D0,0.0D0),
+ + (0.0D0,0.0D0), (0.0D0,0.0D0), (0.0D0,0.0D0),
+ + (0.0D0,0.0D0), (0.0D0,0.0D0), (1.17D0,1.17D0),
+ + (1.17D0,1.17D0), (1.17D0,1.17D0),
+ + (1.17D0,1.17D0), (1.17D0,1.17D0),
+ + (1.17D0,1.17D0), (1.17D0,1.17D0)/
+ DATA CSIZE2/(0.0D0,0.0D0), (0.0D0,0.0D0),
+ + (0.0D0,0.0D0), (0.0D0,0.0D0), (0.0D0,0.0D0),
+ + (0.0D0,0.0D0), (0.0D0,0.0D0), (1.54D0,1.54D0),
+ + (1.54D0,1.54D0), (1.54D0,1.54D0),
+ + (1.54D0,1.54D0), (1.54D0,1.54D0),
+ + (1.54D0,1.54D0), (1.54D0,1.54D0)/
+* .. Executable Statements ..
+ DO 60 KI = 1, 4
+ INCX = INCXS(KI)
+ INCY = INCYS(KI)
+ MX = ABS(INCX)
+ MY = ABS(INCY)
+*
+ DO 40 KN = 1, 4
+ N = NS(KN)
+ KSIZE = MIN(2,KN)
+ LENX = LENS(KN,MX)
+ LENY = LENS(KN,MY)
+* .. initialize all argument arrays ..
+ DO 20 I = 1, 7
+ CX(I) = CX1(I)
+ CY(I) = CY1(I)
+ 20 CONTINUE
+ IF (ICASE.EQ.1) THEN
+* .. ZDOTC ..
+ CDOT(1) = ZDOTC(N,CX,INCX,CY,INCY)
+ CALL CTEST(1,CDOT,CT6(KN,KI),CSIZE1(KN),SFAC)
+ ELSE IF (ICASE.EQ.2) THEN
+* .. ZDOTU ..
+ CDOT(1) = ZDOTU(N,CX,INCX,CY,INCY)
+ CALL CTEST(1,CDOT,CT7(KN,KI),CSIZE1(KN),SFAC)
+ ELSE IF (ICASE.EQ.3) THEN
+* .. ZAXPY ..
+ CALL ZAXPY(N,CA,CX,INCX,CY,INCY)
+ CALL CTEST(LENY,CY,CT8(1,KN,KI),CSIZE2(1,KSIZE),SFAC)
+ ELSE IF (ICASE.EQ.4) THEN
+* .. ZCOPY ..
+ CALL ZCOPY(N,CX,INCX,CY,INCY)
+ CALL CTEST(LENY,CY,CT10Y(1,KN,KI),CSIZE3,1.0D0)
+ ELSE IF (ICASE.EQ.5) THEN
+* .. ZSWAP ..
+ CALL ZSWAP(N,CX,INCX,CY,INCY)
+ CALL CTEST(LENX,CX,CT10X(1,KN,KI),CSIZE3,1.0D0)
+ CALL CTEST(LENY,CY,CT10Y(1,KN,KI),CSIZE3,1.0D0)
+ ELSE
+ WRITE (NOUT,*) ' Shouldn''t be here in CHECK2'
+ STOP
+ END IF
+*
+ 40 CONTINUE
+ 60 CONTINUE
+ RETURN
+ END
+ SUBROUTINE STEST(LEN,SCOMP,STRUE,SSIZE,SFAC)
+* ********************************* STEST **************************
+*
+* THIS SUBR COMPARES ARRAYS SCOMP() AND STRUE() OF LENGTH LEN TO
+* SEE IF THE TERM BY TERM DIFFERENCES, MULTIPLIED BY SFAC, ARE
+* NEGLIGIBLE.
+*
+* C. L. LAWSON, JPL, 1974 DEC 10
+*
+* .. Parameters ..
+ INTEGER NOUT
+ PARAMETER (NOUT=6)
+* .. Scalar Arguments ..
+ DOUBLE PRECISION SFAC
+ INTEGER LEN
+* .. Array Arguments ..
+ DOUBLE PRECISION SCOMP(LEN), SSIZE(LEN), STRUE(LEN)
+* .. Scalars in Common ..
+ INTEGER ICASE, INCX, INCY, MODE, N
+ LOGICAL PASS
+* .. Local Scalars ..
+ DOUBLE PRECISION SD
+ INTEGER I
+* .. External Functions ..
+ DOUBLE PRECISION SDIFF
+ EXTERNAL SDIFF
+* .. Intrinsic Functions ..
+ INTRINSIC ABS
+* .. Common blocks ..
+ COMMON /COMBLA/ICASE, N, INCX, INCY, MODE, PASS
+* .. Executable Statements ..
+*
+ DO 40 I = 1, LEN
+ SD = SCOMP(I) - STRUE(I)
+ IF (SDIFF(ABS(SSIZE(I))+ABS(SFAC*SD),ABS(SSIZE(I))).EQ.0.0D0)
+ + GO TO 40
+*
+* HERE SCOMP(I) IS NOT CLOSE TO STRUE(I).
+*
+ IF ( .NOT. PASS) GO TO 20
+* PRINT FAIL MESSAGE AND HEADER.
+ PASS = .FALSE.
+ WRITE (NOUT,99999)
+ WRITE (NOUT,99998)
+ 20 WRITE (NOUT,99997) ICASE, N, INCX, INCY, MODE, I, SCOMP(I),
+ + STRUE(I), SD, SSIZE(I)
+ 40 CONTINUE
+ RETURN
+*
+99999 FORMAT (' FAIL')
+99998 FORMAT (/' CASE N INCX INCY MODE I ',
+ + ' COMP(I) TRUE(I) DIFFERENCE',
+ + ' SIZE(I)',/1X)
+99997 FORMAT (1X,I4,I3,3I5,I3,2D36.8,2D12.4)
+ END
+ SUBROUTINE STEST1(SCOMP1,STRUE1,SSIZE,SFAC)
+* ************************* STEST1 *****************************
+*
+* THIS IS AN INTERFACE SUBROUTINE TO ACCOMODATE THE FORTRAN
+* REQUIREMENT THAT WHEN A DUMMY ARGUMENT IS AN ARRAY, THE
+* ACTUAL ARGUMENT MUST ALSO BE AN ARRAY OR AN ARRAY ELEMENT.
+*
+* C.L. LAWSON, JPL, 1978 DEC 6
+*
+* .. Scalar Arguments ..
+ DOUBLE PRECISION SCOMP1, SFAC, STRUE1
+* .. Array Arguments ..
+ DOUBLE PRECISION SSIZE(*)
+* .. Local Arrays ..
+ DOUBLE PRECISION SCOMP(1), STRUE(1)
+* .. External Subroutines ..
+ EXTERNAL STEST
+* .. Executable Statements ..
+*
+ SCOMP(1) = SCOMP1
+ STRUE(1) = STRUE1
+ CALL STEST(1,SCOMP,STRUE,SSIZE,SFAC)
+*
+ RETURN
+ END
+ DOUBLE PRECISION FUNCTION SDIFF(SA,SB)
+* ********************************* SDIFF **************************
+* COMPUTES DIFFERENCE OF TWO NUMBERS. C. L. LAWSON, JPL 1974 FEB 15
+*
+* .. Scalar Arguments ..
+ DOUBLE PRECISION SA, SB
+* .. Executable Statements ..
+ SDIFF = SA - SB
+ RETURN
+ END
+ SUBROUTINE CTEST(LEN,CCOMP,CTRUE,CSIZE,SFAC)
+* **************************** CTEST *****************************
+*
+* C.L. LAWSON, JPL, 1978 DEC 6
+*
+* .. Scalar Arguments ..
+ DOUBLE PRECISION SFAC
+ INTEGER LEN
+* .. Array Arguments ..
+ COMPLEX*16 CCOMP(LEN), CSIZE(LEN), CTRUE(LEN)
+* .. Local Scalars ..
+ INTEGER I
+* .. Local Arrays ..
+ DOUBLE PRECISION SCOMP(20), SSIZE(20), STRUE(20)
+* .. External Subroutines ..
+ EXTERNAL STEST
+* .. Intrinsic Functions ..
+ INTRINSIC DIMAG, DBLE
+* .. Executable Statements ..
+ DO 20 I = 1, LEN
+ SCOMP(2*I-1) = DBLE(CCOMP(I))
+ SCOMP(2*I) = DIMAG(CCOMP(I))
+ STRUE(2*I-1) = DBLE(CTRUE(I))
+ STRUE(2*I) = DIMAG(CTRUE(I))
+ SSIZE(2*I-1) = DBLE(CSIZE(I))
+ SSIZE(2*I) = DIMAG(CSIZE(I))
+ 20 CONTINUE
+*
+ CALL STEST(2*LEN,SCOMP,STRUE,SSIZE,SFAC)
+ RETURN
+ END
+ SUBROUTINE ITEST1(ICOMP,ITRUE)
+* ********************************* ITEST1 *************************
+*
+* THIS SUBROUTINE COMPARES THE VARIABLES ICOMP AND ITRUE FOR
+* EQUALITY.
+* C. L. LAWSON, JPL, 1974 DEC 10
+*
+* .. Parameters ..
+ INTEGER NOUT
+ PARAMETER (NOUT=6)
+* .. Scalar Arguments ..
+ INTEGER ICOMP, ITRUE
+* .. Scalars in Common ..
+ INTEGER ICASE, INCX, INCY, MODE, N
+ LOGICAL PASS
+* .. Local Scalars ..
+ INTEGER ID
+* .. Common blocks ..
+ COMMON /COMBLA/ICASE, N, INCX, INCY, MODE, PASS
+* .. Executable Statements ..
+ IF (ICOMP.EQ.ITRUE) GO TO 40
+*
+* HERE ICOMP IS NOT EQUAL TO ITRUE.
+*
+ IF ( .NOT. PASS) GO TO 20
+* PRINT FAIL MESSAGE AND HEADER.
+ PASS = .FALSE.
+ WRITE (NOUT,99999)
+ WRITE (NOUT,99998)
+ 20 ID = ICOMP - ITRUE
+ WRITE (NOUT,99997) ICASE, N, INCX, INCY, MODE, ICOMP, ITRUE, ID
+ 40 CONTINUE
+ RETURN
+*
+99999 FORMAT (' FAIL')
+99998 FORMAT (/' CASE N INCX INCY MODE ',
+ + ' COMP TRUE DIFFERENCE',
+ + /1X)
+99997 FORMAT (1X,I4,I3,3I5,2I36,I12)
+ END
diff --git a/blas/testing/zblat2.dat b/blas/testing/zblat2.dat
new file mode 100644
index 000000000..c9224409f
--- /dev/null
+++ b/blas/testing/zblat2.dat
@@ -0,0 +1,35 @@
+'zblat2.summ' NAME OF SUMMARY OUTPUT FILE
+6 UNIT NUMBER OF SUMMARY FILE
+'cbla2t.snap' NAME OF SNAPSHOT OUTPUT FILE
+-1 UNIT NUMBER OF SNAPSHOT FILE (NOT USED IF .LT. 0)
+F LOGICAL FLAG, T TO REWIND SNAPSHOT FILE AFTER EACH RECORD.
+F LOGICAL FLAG, T TO STOP ON FAILURES.
+T LOGICAL FLAG, T TO TEST ERROR EXITS.
+16.0 THRESHOLD VALUE OF TEST RATIO
+6 NUMBER OF VALUES OF N
+0 1 2 3 5 9 VALUES OF N
+4 NUMBER OF VALUES OF K
+0 1 2 4 VALUES OF K
+4 NUMBER OF VALUES OF INCX AND INCY
+1 2 -1 -2 VALUES OF INCX AND INCY
+3 NUMBER OF VALUES OF ALPHA
+(0.0,0.0) (1.0,0.0) (0.7,-0.9) VALUES OF ALPHA
+3 NUMBER OF VALUES OF BETA
+(0.0,0.0) (1.0,0.0) (1.3,-1.1) VALUES OF BETA
+ZGEMV T PUT F FOR NO TEST. SAME COLUMNS.
+ZGBMV T PUT F FOR NO TEST. SAME COLUMNS.
+ZHEMV T PUT F FOR NO TEST. SAME COLUMNS.
+ZHBMV T PUT F FOR NO TEST. SAME COLUMNS.
+ZHPMV T PUT F FOR NO TEST. SAME COLUMNS.
+ZTRMV T PUT F FOR NO TEST. SAME COLUMNS.
+ZTBMV T PUT F FOR NO TEST. SAME COLUMNS.
+ZTPMV T PUT F FOR NO TEST. SAME COLUMNS.
+ZTRSV T PUT F FOR NO TEST. SAME COLUMNS.
+ZTBSV T PUT F FOR NO TEST. SAME COLUMNS.
+ZTPSV T PUT F FOR NO TEST. SAME COLUMNS.
+ZGERC T PUT F FOR NO TEST. SAME COLUMNS.
+ZGERU T PUT F FOR NO TEST. SAME COLUMNS.
+ZHER T PUT F FOR NO TEST. SAME COLUMNS.
+ZHPR T PUT F FOR NO TEST. SAME COLUMNS.
+ZHER2 T PUT F FOR NO TEST. SAME COLUMNS.
+ZHPR2 T PUT F FOR NO TEST. SAME COLUMNS.
diff --git a/blas/testing/zblat2.f b/blas/testing/zblat2.f
new file mode 100644
index 000000000..e65cdcc70
--- /dev/null
+++ b/blas/testing/zblat2.f
@@ -0,0 +1,3249 @@
+ PROGRAM ZBLAT2
+*
+* Test program for the COMPLEX*16 Level 2 Blas.
+*
+* The program must be driven by a short data file. The first 18 records
+* of the file are read using list-directed input, the last 17 records
+* are read using the format ( A6, L2 ). An annotated example of a data
+* file can be obtained by deleting the first 3 characters from the
+* following 35 lines:
+* 'ZBLAT2.SUMM' NAME OF SUMMARY OUTPUT FILE
+* 6 UNIT NUMBER OF SUMMARY FILE
+* 'CBLA2T.SNAP' NAME OF SNAPSHOT OUTPUT FILE
+* -1 UNIT NUMBER OF SNAPSHOT FILE (NOT USED IF .LT. 0)
+* F LOGICAL FLAG, T TO REWIND SNAPSHOT FILE AFTER EACH RECORD.
+* F LOGICAL FLAG, T TO STOP ON FAILURES.
+* T LOGICAL FLAG, T TO TEST ERROR EXITS.
+* 16.0 THRESHOLD VALUE OF TEST RATIO
+* 6 NUMBER OF VALUES OF N
+* 0 1 2 3 5 9 VALUES OF N
+* 4 NUMBER OF VALUES OF K
+* 0 1 2 4 VALUES OF K
+* 4 NUMBER OF VALUES OF INCX AND INCY
+* 1 2 -1 -2 VALUES OF INCX AND INCY
+* 3 NUMBER OF VALUES OF ALPHA
+* (0.0,0.0) (1.0,0.0) (0.7,-0.9) VALUES OF ALPHA
+* 3 NUMBER OF VALUES OF BETA
+* (0.0,0.0) (1.0,0.0) (1.3,-1.1) VALUES OF BETA
+* ZGEMV T PUT F FOR NO TEST. SAME COLUMNS.
+* ZGBMV T PUT F FOR NO TEST. SAME COLUMNS.
+* ZHEMV T PUT F FOR NO TEST. SAME COLUMNS.
+* ZHBMV T PUT F FOR NO TEST. SAME COLUMNS.
+* ZHPMV T PUT F FOR NO TEST. SAME COLUMNS.
+* ZTRMV T PUT F FOR NO TEST. SAME COLUMNS.
+* ZTBMV T PUT F FOR NO TEST. SAME COLUMNS.
+* ZTPMV T PUT F FOR NO TEST. SAME COLUMNS.
+* ZTRSV T PUT F FOR NO TEST. SAME COLUMNS.
+* ZTBSV T PUT F FOR NO TEST. SAME COLUMNS.
+* ZTPSV T PUT F FOR NO TEST. SAME COLUMNS.
+* ZGERC T PUT F FOR NO TEST. SAME COLUMNS.
+* ZGERU T PUT F FOR NO TEST. SAME COLUMNS.
+* ZHER T PUT F FOR NO TEST. SAME COLUMNS.
+* ZHPR T PUT F FOR NO TEST. SAME COLUMNS.
+* ZHER2 T PUT F FOR NO TEST. SAME COLUMNS.
+* ZHPR2 T PUT F FOR NO TEST. SAME COLUMNS.
+*
+* See:
+*
+* Dongarra J. J., Du Croz J. J., Hammarling S. and Hanson R. J..
+* An extended set of Fortran Basic Linear Algebra Subprograms.
+*
+* Technical Memoranda Nos. 41 (revision 3) and 81, Mathematics
+* and Computer Science Division, Argonne National Laboratory,
+* 9700 South Cass Avenue, Argonne, Illinois 60439, US.
+*
+* Or
+*
+* NAG Technical Reports TR3/87 and TR4/87, Numerical Algorithms
+* Group Ltd., NAG Central Office, 256 Banbury Road, Oxford
+* OX2 7DE, UK, and Numerical Algorithms Group Inc., 1101 31st
+* Street, Suite 100, Downers Grove, Illinois 60515-1263, USA.
+*
+*
+* -- Written on 10-August-1987.
+* Richard Hanson, Sandia National Labs.
+* Jeremy Du Croz, NAG Central Office.
+*
+* .. Parameters ..
+ INTEGER NIN
+ PARAMETER ( NIN = 5 )
+ INTEGER NSUBS
+ PARAMETER ( NSUBS = 17 )
+ COMPLEX*16 ZERO, ONE
+ PARAMETER ( ZERO = ( 0.0D0, 0.0D0 ),
+ $ ONE = ( 1.0D0, 0.0D0 ) )
+ DOUBLE PRECISION RZERO, RHALF, RONE
+ PARAMETER ( RZERO = 0.0D0, RHALF = 0.5D0, RONE = 1.0D0 )
+ INTEGER NMAX, INCMAX
+ PARAMETER ( NMAX = 65, INCMAX = 2 )
+ INTEGER NINMAX, NIDMAX, NKBMAX, NALMAX, NBEMAX
+ PARAMETER ( NINMAX = 7, NIDMAX = 9, NKBMAX = 7,
+ $ NALMAX = 7, NBEMAX = 7 )
+* .. Local Scalars ..
+ DOUBLE PRECISION EPS, ERR, THRESH
+ INTEGER I, ISNUM, J, N, NALF, NBET, NIDIM, NINC, NKB,
+ $ NOUT, NTRA
+ LOGICAL FATAL, LTESTT, REWI, SAME, SFATAL, TRACE,
+ $ TSTERR
+ CHARACTER*1 TRANS
+ CHARACTER*6 SNAMET
+ CHARACTER*32 SNAPS, SUMMRY
+* .. Local Arrays ..
+ COMPLEX*16 A( NMAX, NMAX ), AA( NMAX*NMAX ),
+ $ ALF( NALMAX ), AS( NMAX*NMAX ), BET( NBEMAX ),
+ $ X( NMAX ), XS( NMAX*INCMAX ),
+ $ XX( NMAX*INCMAX ), Y( NMAX ),
+ $ YS( NMAX*INCMAX ), YT( NMAX ),
+ $ YY( NMAX*INCMAX ), Z( 2*NMAX )
+ DOUBLE PRECISION G( NMAX )
+ INTEGER IDIM( NIDMAX ), INC( NINMAX ), KB( NKBMAX )
+ LOGICAL LTEST( NSUBS )
+ CHARACTER*6 SNAMES( NSUBS )
+* .. External Functions ..
+ DOUBLE PRECISION DDIFF
+ LOGICAL LZE
+ EXTERNAL DDIFF, LZE
+* .. External Subroutines ..
+ EXTERNAL ZCHK1, ZCHK2, ZCHK3, ZCHK4, ZCHK5, ZCHK6,
+ $ ZCHKE, ZMVCH
+* .. Intrinsic Functions ..
+ INTRINSIC ABS, MAX, MIN
+* .. Scalars in Common ..
+ INTEGER INFOT, NOUTC
+ LOGICAL LERR, OK
+ CHARACTER*6 SRNAMT
+* .. Common blocks ..
+ COMMON /INFOC/INFOT, NOUTC, OK, LERR
+ COMMON /SRNAMC/SRNAMT
+* .. Data statements ..
+ DATA SNAMES/'ZGEMV ', 'ZGBMV ', 'ZHEMV ', 'ZHBMV ',
+ $ 'ZHPMV ', 'ZTRMV ', 'ZTBMV ', 'ZTPMV ',
+ $ 'ZTRSV ', 'ZTBSV ', 'ZTPSV ', 'ZGERC ',
+ $ 'ZGERU ', 'ZHER ', 'ZHPR ', 'ZHER2 ',
+ $ 'ZHPR2 '/
+* .. Executable Statements ..
+*
+* Read name and unit number for summary output file and open file.
+*
+ READ( NIN, FMT = * )SUMMRY
+ READ( NIN, FMT = * )NOUT
+ OPEN( NOUT, FILE = SUMMRY, STATUS = 'NEW' )
+ NOUTC = NOUT
+*
+* Read name and unit number for snapshot output file and open file.
+*
+ READ( NIN, FMT = * )SNAPS
+ READ( NIN, FMT = * )NTRA
+ TRACE = NTRA.GE.0
+ IF( TRACE )THEN
+ OPEN( NTRA, FILE = SNAPS, STATUS = 'NEW' )
+ END IF
+* Read the flag that directs rewinding of the snapshot file.
+ READ( NIN, FMT = * )REWI
+ REWI = REWI.AND.TRACE
+* Read the flag that directs stopping on any failure.
+ READ( NIN, FMT = * )SFATAL
+* Read the flag that indicates whether error exits are to be tested.
+ READ( NIN, FMT = * )TSTERR
+* Read the threshold value of the test ratio
+ READ( NIN, FMT = * )THRESH
+*
+* Read and check the parameter values for the tests.
+*
+* Values of N
+ READ( NIN, FMT = * )NIDIM
+ IF( NIDIM.LT.1.OR.NIDIM.GT.NIDMAX )THEN
+ WRITE( NOUT, FMT = 9997 )'N', NIDMAX
+ GO TO 230
+ END IF
+ READ( NIN, FMT = * )( IDIM( I ), I = 1, NIDIM )
+ DO 10 I = 1, NIDIM
+ IF( IDIM( I ).LT.0.OR.IDIM( I ).GT.NMAX )THEN
+ WRITE( NOUT, FMT = 9996 )NMAX
+ GO TO 230
+ END IF
+ 10 CONTINUE
+* Values of K
+ READ( NIN, FMT = * )NKB
+ IF( NKB.LT.1.OR.NKB.GT.NKBMAX )THEN
+ WRITE( NOUT, FMT = 9997 )'K', NKBMAX
+ GO TO 230
+ END IF
+ READ( NIN, FMT = * )( KB( I ), I = 1, NKB )
+ DO 20 I = 1, NKB
+ IF( KB( I ).LT.0 )THEN
+ WRITE( NOUT, FMT = 9995 )
+ GO TO 230
+ END IF
+ 20 CONTINUE
+* Values of INCX and INCY
+ READ( NIN, FMT = * )NINC
+ IF( NINC.LT.1.OR.NINC.GT.NINMAX )THEN
+ WRITE( NOUT, FMT = 9997 )'INCX AND INCY', NINMAX
+ GO TO 230
+ END IF
+ READ( NIN, FMT = * )( INC( I ), I = 1, NINC )
+ DO 30 I = 1, NINC
+ IF( INC( I ).EQ.0.OR.ABS( INC( I ) ).GT.INCMAX )THEN
+ WRITE( NOUT, FMT = 9994 )INCMAX
+ GO TO 230
+ END IF
+ 30 CONTINUE
+* Values of ALPHA
+ READ( NIN, FMT = * )NALF
+ IF( NALF.LT.1.OR.NALF.GT.NALMAX )THEN
+ WRITE( NOUT, FMT = 9997 )'ALPHA', NALMAX
+ GO TO 230
+ END IF
+ READ( NIN, FMT = * )( ALF( I ), I = 1, NALF )
+* Values of BETA
+ READ( NIN, FMT = * )NBET
+ IF( NBET.LT.1.OR.NBET.GT.NBEMAX )THEN
+ WRITE( NOUT, FMT = 9997 )'BETA', NBEMAX
+ GO TO 230
+ END IF
+ READ( NIN, FMT = * )( BET( I ), I = 1, NBET )
+*
+* Report values of parameters.
+*
+ WRITE( NOUT, FMT = 9993 )
+ WRITE( NOUT, FMT = 9992 )( IDIM( I ), I = 1, NIDIM )
+ WRITE( NOUT, FMT = 9991 )( KB( I ), I = 1, NKB )
+ WRITE( NOUT, FMT = 9990 )( INC( I ), I = 1, NINC )
+ WRITE( NOUT, FMT = 9989 )( ALF( I ), I = 1, NALF )
+ WRITE( NOUT, FMT = 9988 )( BET( I ), I = 1, NBET )
+ IF( .NOT.TSTERR )THEN
+ WRITE( NOUT, FMT = * )
+ WRITE( NOUT, FMT = 9980 )
+ END IF
+ WRITE( NOUT, FMT = * )
+ WRITE( NOUT, FMT = 9999 )THRESH
+ WRITE( NOUT, FMT = * )
+*
+* Read names of subroutines and flags which indicate
+* whether they are to be tested.
+*
+ DO 40 I = 1, NSUBS
+ LTEST( I ) = .FALSE.
+ 40 CONTINUE
+ 50 READ( NIN, FMT = 9984, END = 80 )SNAMET, LTESTT
+ DO 60 I = 1, NSUBS
+ IF( SNAMET.EQ.SNAMES( I ) )
+ $ GO TO 70
+ 60 CONTINUE
+ WRITE( NOUT, FMT = 9986 )SNAMET
+ STOP
+ 70 LTEST( I ) = LTESTT
+ GO TO 50
+*
+ 80 CONTINUE
+ CLOSE ( NIN )
+*
+* Compute EPS (the machine precision).
+*
+ EPS = RONE
+ 90 CONTINUE
+ IF( DDIFF( RONE + EPS, RONE ).EQ.RZERO )
+ $ GO TO 100
+ EPS = RHALF*EPS
+ GO TO 90
+ 100 CONTINUE
+ EPS = EPS + EPS
+ WRITE( NOUT, FMT = 9998 )EPS
+*
+* Check the reliability of ZMVCH using exact data.
+*
+ N = MIN( 32, NMAX )
+ DO 120 J = 1, N
+ DO 110 I = 1, N
+ A( I, J ) = MAX( I - J + 1, 0 )
+ 110 CONTINUE
+ X( J ) = J
+ Y( J ) = ZERO
+ 120 CONTINUE
+ DO 130 J = 1, N
+ YY( J ) = J*( ( J + 1 )*J )/2 - ( ( J + 1 )*J*( J - 1 ) )/3
+ 130 CONTINUE
+* YY holds the exact result. On exit from ZMVCH YT holds
+* the result computed by ZMVCH.
+ TRANS = 'N'
+ CALL ZMVCH( TRANS, N, N, ONE, A, NMAX, X, 1, ZERO, Y, 1, YT, G,
+ $ YY, EPS, ERR, FATAL, NOUT, .TRUE. )
+ SAME = LZE( YY, YT, N )
+ IF( .NOT.SAME.OR.ERR.NE.RZERO )THEN
+ WRITE( NOUT, FMT = 9985 )TRANS, SAME, ERR
+ STOP
+ END IF
+ TRANS = 'T'
+ CALL ZMVCH( TRANS, N, N, ONE, A, NMAX, X, -1, ZERO, Y, -1, YT, G,
+ $ YY, EPS, ERR, FATAL, NOUT, .TRUE. )
+ SAME = LZE( YY, YT, N )
+ IF( .NOT.SAME.OR.ERR.NE.RZERO )THEN
+ WRITE( NOUT, FMT = 9985 )TRANS, SAME, ERR
+ STOP
+ END IF
+*
+* Test each subroutine in turn.
+*
+ DO 210 ISNUM = 1, NSUBS
+ WRITE( NOUT, FMT = * )
+ IF( .NOT.LTEST( ISNUM ) )THEN
+* Subprogram is not to be tested.
+ WRITE( NOUT, FMT = 9983 )SNAMES( ISNUM )
+ ELSE
+ SRNAMT = SNAMES( ISNUM )
+* Test error exits.
+ IF( TSTERR )THEN
+ CALL ZCHKE( ISNUM, SNAMES( ISNUM ), NOUT )
+ WRITE( NOUT, FMT = * )
+ END IF
+* Test computations.
+ INFOT = 0
+ OK = .TRUE.
+ FATAL = .FALSE.
+ GO TO ( 140, 140, 150, 150, 150, 160, 160,
+ $ 160, 160, 160, 160, 170, 170, 180,
+ $ 180, 190, 190 )ISNUM
+* Test ZGEMV, 01, and ZGBMV, 02.
+ 140 CALL ZCHK1( SNAMES( ISNUM ), EPS, THRESH, NOUT, NTRA, TRACE,
+ $ REWI, FATAL, NIDIM, IDIM, NKB, KB, NALF, ALF,
+ $ NBET, BET, NINC, INC, NMAX, INCMAX, A, AA, AS,
+ $ X, XX, XS, Y, YY, YS, YT, G )
+ GO TO 200
+* Test ZHEMV, 03, ZHBMV, 04, and ZHPMV, 05.
+ 150 CALL ZCHK2( SNAMES( ISNUM ), EPS, THRESH, NOUT, NTRA, TRACE,
+ $ REWI, FATAL, NIDIM, IDIM, NKB, KB, NALF, ALF,
+ $ NBET, BET, NINC, INC, NMAX, INCMAX, A, AA, AS,
+ $ X, XX, XS, Y, YY, YS, YT, G )
+ GO TO 200
+* Test ZTRMV, 06, ZTBMV, 07, ZTPMV, 08,
+* ZTRSV, 09, ZTBSV, 10, and ZTPSV, 11.
+ 160 CALL ZCHK3( SNAMES( ISNUM ), EPS, THRESH, NOUT, NTRA, TRACE,
+ $ REWI, FATAL, NIDIM, IDIM, NKB, KB, NINC, INC,
+ $ NMAX, INCMAX, A, AA, AS, Y, YY, YS, YT, G, Z )
+ GO TO 200
+* Test ZGERC, 12, ZGERU, 13.
+ 170 CALL ZCHK4( SNAMES( ISNUM ), EPS, THRESH, NOUT, NTRA, TRACE,
+ $ REWI, FATAL, NIDIM, IDIM, NALF, ALF, NINC, INC,
+ $ NMAX, INCMAX, A, AA, AS, X, XX, XS, Y, YY, YS,
+ $ YT, G, Z )
+ GO TO 200
+* Test ZHER, 14, and ZHPR, 15.
+ 180 CALL ZCHK5( SNAMES( ISNUM ), EPS, THRESH, NOUT, NTRA, TRACE,
+ $ REWI, FATAL, NIDIM, IDIM, NALF, ALF, NINC, INC,
+ $ NMAX, INCMAX, A, AA, AS, X, XX, XS, Y, YY, YS,
+ $ YT, G, Z )
+ GO TO 200
+* Test ZHER2, 16, and ZHPR2, 17.
+ 190 CALL ZCHK6( SNAMES( ISNUM ), EPS, THRESH, NOUT, NTRA, TRACE,
+ $ REWI, FATAL, NIDIM, IDIM, NALF, ALF, NINC, INC,
+ $ NMAX, INCMAX, A, AA, AS, X, XX, XS, Y, YY, YS,
+ $ YT, G, Z )
+*
+ 200 IF( FATAL.AND.SFATAL )
+ $ GO TO 220
+ END IF
+ 210 CONTINUE
+ WRITE( NOUT, FMT = 9982 )
+ GO TO 240
+*
+ 220 CONTINUE
+ WRITE( NOUT, FMT = 9981 )
+ GO TO 240
+*
+ 230 CONTINUE
+ WRITE( NOUT, FMT = 9987 )
+*
+ 240 CONTINUE
+ IF( TRACE )
+ $ CLOSE ( NTRA )
+ CLOSE ( NOUT )
+ STOP
+*
+ 9999 FORMAT( ' ROUTINES PASS COMPUTATIONAL TESTS IF TEST RATIO IS LES',
+ $ 'S THAN', F8.2 )
+ 9998 FORMAT( ' RELATIVE MACHINE PRECISION IS TAKEN TO BE', 1P, D9.1 )
+ 9997 FORMAT( ' NUMBER OF VALUES OF ', A, ' IS LESS THAN 1 OR GREATER ',
+ $ 'THAN ', I2 )
+ 9996 FORMAT( ' VALUE OF N IS LESS THAN 0 OR GREATER THAN ', I2 )
+ 9995 FORMAT( ' VALUE OF K IS LESS THAN 0' )
+ 9994 FORMAT( ' ABSOLUTE VALUE OF INCX OR INCY IS 0 OR GREATER THAN ',
+ $ I2 )
+ 9993 FORMAT( ' TESTS OF THE COMPLEX*16 LEVEL 2 BLAS', //' THE F',
+ $ 'OLLOWING PARAMETER VALUES WILL BE USED:' )
+ 9992 FORMAT( ' FOR N ', 9I6 )
+ 9991 FORMAT( ' FOR K ', 7I6 )
+ 9990 FORMAT( ' FOR INCX AND INCY ', 7I6 )
+ 9989 FORMAT( ' FOR ALPHA ',
+ $ 7( '(', F4.1, ',', F4.1, ') ', : ) )
+ 9988 FORMAT( ' FOR BETA ',
+ $ 7( '(', F4.1, ',', F4.1, ') ', : ) )
+ 9987 FORMAT( ' AMEND DATA FILE OR INCREASE ARRAY SIZES IN PROGRAM',
+ $ /' ******* TESTS ABANDONED *******' )
+ 9986 FORMAT( ' SUBPROGRAM NAME ', A6, ' NOT RECOGNIZED', /' ******* T',
+ $ 'ESTS ABANDONED *******' )
+ 9985 FORMAT( ' ERROR IN ZMVCH - IN-LINE DOT PRODUCTS ARE BEING EVALU',
+ $ 'ATED WRONGLY.', /' ZMVCH WAS CALLED WITH TRANS = ', A1,
+ $ ' AND RETURNED SAME = ', L1, ' AND ERR = ', F12.3, '.', /
+ $ ' THIS MAY BE DUE TO FAULTS IN THE ARITHMETIC OR THE COMPILER.'
+ $ , /' ******* TESTS ABANDONED *******' )
+ 9984 FORMAT( A6, L2 )
+ 9983 FORMAT( 1X, A6, ' WAS NOT TESTED' )
+ 9982 FORMAT( /' END OF TESTS' )
+ 9981 FORMAT( /' ******* FATAL ERROR - TESTS ABANDONED *******' )
+ 9980 FORMAT( ' ERROR-EXITS WILL NOT BE TESTED' )
+*
+* End of ZBLAT2.
+*
+ END
+ SUBROUTINE ZCHK1( SNAME, EPS, THRESH, NOUT, NTRA, TRACE, REWI,
+ $ FATAL, NIDIM, IDIM, NKB, KB, NALF, ALF, NBET,
+ $ BET, NINC, INC, NMAX, INCMAX, A, AA, AS, X, XX,
+ $ XS, Y, YY, YS, YT, G )
+*
+* Tests ZGEMV and ZGBMV.
+*
+* Auxiliary routine for test program for Level 2 Blas.
+*
+* -- Written on 10-August-1987.
+* Richard Hanson, Sandia National Labs.
+* Jeremy Du Croz, NAG Central Office.
+*
+* .. Parameters ..
+ COMPLEX*16 ZERO, HALF
+ PARAMETER ( ZERO = ( 0.0D0, 0.0D0 ),
+ $ HALF = ( 0.5D0, 0.0D0 ) )
+ DOUBLE PRECISION RZERO
+ PARAMETER ( RZERO = 0.0D0 )
+* .. Scalar Arguments ..
+ DOUBLE PRECISION EPS, THRESH
+ INTEGER INCMAX, NALF, NBET, NIDIM, NINC, NKB, NMAX,
+ $ NOUT, NTRA
+ LOGICAL FATAL, REWI, TRACE
+ CHARACTER*6 SNAME
+* .. Array Arguments ..
+ COMPLEX*16 A( NMAX, NMAX ), AA( NMAX*NMAX ), ALF( NALF ),
+ $ AS( NMAX*NMAX ), BET( NBET ), X( NMAX ),
+ $ XS( NMAX*INCMAX ), XX( NMAX*INCMAX ),
+ $ Y( NMAX ), YS( NMAX*INCMAX ), YT( NMAX ),
+ $ YY( NMAX*INCMAX )
+ DOUBLE PRECISION G( NMAX )
+ INTEGER IDIM( NIDIM ), INC( NINC ), KB( NKB )
+* .. Local Scalars ..
+ COMPLEX*16 ALPHA, ALS, BETA, BLS, TRANSL
+ DOUBLE PRECISION ERR, ERRMAX
+ INTEGER I, IA, IB, IC, IKU, IM, IN, INCX, INCXS, INCY,
+ $ INCYS, IX, IY, KL, KLS, KU, KUS, LAA, LDA,
+ $ LDAS, LX, LY, M, ML, MS, N, NARGS, NC, ND, NK,
+ $ NL, NS
+ LOGICAL BANDED, FULL, NULL, RESET, SAME, TRAN
+ CHARACTER*1 TRANS, TRANSS
+ CHARACTER*3 ICH
+* .. Local Arrays ..
+ LOGICAL ISAME( 13 )
+* .. External Functions ..
+ LOGICAL LZE, LZERES
+ EXTERNAL LZE, LZERES
+* .. External Subroutines ..
+ EXTERNAL ZGBMV, ZGEMV, ZMAKE, ZMVCH
+* .. Intrinsic Functions ..
+ INTRINSIC ABS, MAX, MIN
+* .. Scalars in Common ..
+ INTEGER INFOT, NOUTC
+ LOGICAL LERR, OK
+* .. Common blocks ..
+ COMMON /INFOC/INFOT, NOUTC, OK, LERR
+* .. Data statements ..
+ DATA ICH/'NTC'/
+* .. Executable Statements ..
+ FULL = SNAME( 3: 3 ).EQ.'E'
+ BANDED = SNAME( 3: 3 ).EQ.'B'
+* Define the number of arguments.
+ IF( FULL )THEN
+ NARGS = 11
+ ELSE IF( BANDED )THEN
+ NARGS = 13
+ END IF
+*
+ NC = 0
+ RESET = .TRUE.
+ ERRMAX = RZERO
+*
+ DO 120 IN = 1, NIDIM
+ N = IDIM( IN )
+ ND = N/2 + 1
+*
+ DO 110 IM = 1, 2
+ IF( IM.EQ.1 )
+ $ M = MAX( N - ND, 0 )
+ IF( IM.EQ.2 )
+ $ M = MIN( N + ND, NMAX )
+*
+ IF( BANDED )THEN
+ NK = NKB
+ ELSE
+ NK = 1
+ END IF
+ DO 100 IKU = 1, NK
+ IF( BANDED )THEN
+ KU = KB( IKU )
+ KL = MAX( KU - 1, 0 )
+ ELSE
+ KU = N - 1
+ KL = M - 1
+ END IF
+* Set LDA to 1 more than minimum value if room.
+ IF( BANDED )THEN
+ LDA = KL + KU + 1
+ ELSE
+ LDA = M
+ END IF
+ IF( LDA.LT.NMAX )
+ $ LDA = LDA + 1
+* Skip tests if not enough room.
+ IF( LDA.GT.NMAX )
+ $ GO TO 100
+ LAA = LDA*N
+ NULL = N.LE.0.OR.M.LE.0
+*
+* Generate the matrix A.
+*
+ TRANSL = ZERO
+ CALL ZMAKE( SNAME( 2: 3 ), ' ', ' ', M, N, A, NMAX, AA,
+ $ LDA, KL, KU, RESET, TRANSL )
+*
+ DO 90 IC = 1, 3
+ TRANS = ICH( IC: IC )
+ TRAN = TRANS.EQ.'T'.OR.TRANS.EQ.'C'
+*
+ IF( TRAN )THEN
+ ML = N
+ NL = M
+ ELSE
+ ML = M
+ NL = N
+ END IF
+*
+ DO 80 IX = 1, NINC
+ INCX = INC( IX )
+ LX = ABS( INCX )*NL
+*
+* Generate the vector X.
+*
+ TRANSL = HALF
+ CALL ZMAKE( 'GE', ' ', ' ', 1, NL, X, 1, XX,
+ $ ABS( INCX ), 0, NL - 1, RESET, TRANSL )
+ IF( NL.GT.1 )THEN
+ X( NL/2 ) = ZERO
+ XX( 1 + ABS( INCX )*( NL/2 - 1 ) ) = ZERO
+ END IF
+*
+ DO 70 IY = 1, NINC
+ INCY = INC( IY )
+ LY = ABS( INCY )*ML
+*
+ DO 60 IA = 1, NALF
+ ALPHA = ALF( IA )
+*
+ DO 50 IB = 1, NBET
+ BETA = BET( IB )
+*
+* Generate the vector Y.
+*
+ TRANSL = ZERO
+ CALL ZMAKE( 'GE', ' ', ' ', 1, ML, Y, 1,
+ $ YY, ABS( INCY ), 0, ML - 1,
+ $ RESET, TRANSL )
+*
+ NC = NC + 1
+*
+* Save every datum before calling the
+* subroutine.
+*
+ TRANSS = TRANS
+ MS = M
+ NS = N
+ KLS = KL
+ KUS = KU
+ ALS = ALPHA
+ DO 10 I = 1, LAA
+ AS( I ) = AA( I )
+ 10 CONTINUE
+ LDAS = LDA
+ DO 20 I = 1, LX
+ XS( I ) = XX( I )
+ 20 CONTINUE
+ INCXS = INCX
+ BLS = BETA
+ DO 30 I = 1, LY
+ YS( I ) = YY( I )
+ 30 CONTINUE
+ INCYS = INCY
+*
+* Call the subroutine.
+*
+ IF( FULL )THEN
+ IF( TRACE )
+ $ WRITE( NTRA, FMT = 9994 )NC, SNAME,
+ $ TRANS, M, N, ALPHA, LDA, INCX, BETA,
+ $ INCY
+ IF( REWI )
+ $ REWIND NTRA
+ CALL ZGEMV( TRANS, M, N, ALPHA, AA,
+ $ LDA, XX, INCX, BETA, YY,
+ $ INCY )
+ ELSE IF( BANDED )THEN
+ IF( TRACE )
+ $ WRITE( NTRA, FMT = 9995 )NC, SNAME,
+ $ TRANS, M, N, KL, KU, ALPHA, LDA,
+ $ INCX, BETA, INCY
+ IF( REWI )
+ $ REWIND NTRA
+ CALL ZGBMV( TRANS, M, N, KL, KU, ALPHA,
+ $ AA, LDA, XX, INCX, BETA,
+ $ YY, INCY )
+ END IF
+*
+* Check if error-exit was taken incorrectly.
+*
+ IF( .NOT.OK )THEN
+ WRITE( NOUT, FMT = 9993 )
+ FATAL = .TRUE.
+ GO TO 130
+ END IF
+*
+* See what data changed inside subroutines.
+*
+ ISAME( 1 ) = TRANS.EQ.TRANSS
+ ISAME( 2 ) = MS.EQ.M
+ ISAME( 3 ) = NS.EQ.N
+ IF( FULL )THEN
+ ISAME( 4 ) = ALS.EQ.ALPHA
+ ISAME( 5 ) = LZE( AS, AA, LAA )
+ ISAME( 6 ) = LDAS.EQ.LDA
+ ISAME( 7 ) = LZE( XS, XX, LX )
+ ISAME( 8 ) = INCXS.EQ.INCX
+ ISAME( 9 ) = BLS.EQ.BETA
+ IF( NULL )THEN
+ ISAME( 10 ) = LZE( YS, YY, LY )
+ ELSE
+ ISAME( 10 ) = LZERES( 'GE', ' ', 1,
+ $ ML, YS, YY,
+ $ ABS( INCY ) )
+ END IF
+ ISAME( 11 ) = INCYS.EQ.INCY
+ ELSE IF( BANDED )THEN
+ ISAME( 4 ) = KLS.EQ.KL
+ ISAME( 5 ) = KUS.EQ.KU
+ ISAME( 6 ) = ALS.EQ.ALPHA
+ ISAME( 7 ) = LZE( AS, AA, LAA )
+ ISAME( 8 ) = LDAS.EQ.LDA
+ ISAME( 9 ) = LZE( XS, XX, LX )
+ ISAME( 10 ) = INCXS.EQ.INCX
+ ISAME( 11 ) = BLS.EQ.BETA
+ IF( NULL )THEN
+ ISAME( 12 ) = LZE( YS, YY, LY )
+ ELSE
+ ISAME( 12 ) = LZERES( 'GE', ' ', 1,
+ $ ML, YS, YY,
+ $ ABS( INCY ) )
+ END IF
+ ISAME( 13 ) = INCYS.EQ.INCY
+ END IF
+*
+* If data was incorrectly changed, report
+* and return.
+*
+ SAME = .TRUE.
+ DO 40 I = 1, NARGS
+ SAME = SAME.AND.ISAME( I )
+ IF( .NOT.ISAME( I ) )
+ $ WRITE( NOUT, FMT = 9998 )I
+ 40 CONTINUE
+ IF( .NOT.SAME )THEN
+ FATAL = .TRUE.
+ GO TO 130
+ END IF
+*
+ IF( .NOT.NULL )THEN
+*
+* Check the result.
+*
+ CALL ZMVCH( TRANS, M, N, ALPHA, A,
+ $ NMAX, X, INCX, BETA, Y,
+ $ INCY, YT, G, YY, EPS, ERR,
+ $ FATAL, NOUT, .TRUE. )
+ ERRMAX = MAX( ERRMAX, ERR )
+* If got really bad answer, report and
+* return.
+ IF( FATAL )
+ $ GO TO 130
+ ELSE
+* Avoid repeating tests with M.le.0 or
+* N.le.0.
+ GO TO 110
+ END IF
+*
+ 50 CONTINUE
+*
+ 60 CONTINUE
+*
+ 70 CONTINUE
+*
+ 80 CONTINUE
+*
+ 90 CONTINUE
+*
+ 100 CONTINUE
+*
+ 110 CONTINUE
+*
+ 120 CONTINUE
+*
+* Report result.
+*
+ IF( ERRMAX.LT.THRESH )THEN
+ WRITE( NOUT, FMT = 9999 )SNAME, NC
+ ELSE
+ WRITE( NOUT, FMT = 9997 )SNAME, NC, ERRMAX
+ END IF
+ GO TO 140
+*
+ 130 CONTINUE
+ WRITE( NOUT, FMT = 9996 )SNAME
+ IF( FULL )THEN
+ WRITE( NOUT, FMT = 9994 )NC, SNAME, TRANS, M, N, ALPHA, LDA,
+ $ INCX, BETA, INCY
+ ELSE IF( BANDED )THEN
+ WRITE( NOUT, FMT = 9995 )NC, SNAME, TRANS, M, N, KL, KU,
+ $ ALPHA, LDA, INCX, BETA, INCY
+ END IF
+*
+ 140 CONTINUE
+ RETURN
+*
+ 9999 FORMAT( ' ', A6, ' PASSED THE COMPUTATIONAL TESTS (', I6, ' CALL',
+ $ 'S)' )
+ 9998 FORMAT( ' ******* FATAL ERROR - PARAMETER NUMBER ', I2, ' WAS CH',
+ $ 'ANGED INCORRECTLY *******' )
+ 9997 FORMAT( ' ', A6, ' COMPLETED THE COMPUTATIONAL TESTS (', I6, ' C',
+ $ 'ALLS)', /' ******* BUT WITH MAXIMUM TEST RATIO', F8.2,
+ $ ' - SUSPECT *******' )
+ 9996 FORMAT( ' ******* ', A6, ' FAILED ON CALL NUMBER:' )
+ 9995 FORMAT( 1X, I6, ': ', A6, '(''', A1, ''',', 4( I3, ',' ), '(',
+ $ F4.1, ',', F4.1, '), A,', I3, ', X,', I2, ',(', F4.1, ',',
+ $ F4.1, '), Y,', I2, ') .' )
+ 9994 FORMAT( 1X, I6, ': ', A6, '(''', A1, ''',', 2( I3, ',' ), '(',
+ $ F4.1, ',', F4.1, '), A,', I3, ', X,', I2, ',(', F4.1, ',',
+ $ F4.1, '), Y,', I2, ') .' )
+ 9993 FORMAT( ' ******* FATAL ERROR - ERROR-EXIT TAKEN ON VALID CALL *',
+ $ '******' )
+*
+* End of ZCHK1.
+*
+ END
+ SUBROUTINE ZCHK2( SNAME, EPS, THRESH, NOUT, NTRA, TRACE, REWI,
+ $ FATAL, NIDIM, IDIM, NKB, KB, NALF, ALF, NBET,
+ $ BET, NINC, INC, NMAX, INCMAX, A, AA, AS, X, XX,
+ $ XS, Y, YY, YS, YT, G )
+*
+* Tests ZHEMV, ZHBMV and ZHPMV.
+*
+* Auxiliary routine for test program for Level 2 Blas.
+*
+* -- Written on 10-August-1987.
+* Richard Hanson, Sandia National Labs.
+* Jeremy Du Croz, NAG Central Office.
+*
+* .. Parameters ..
+ COMPLEX*16 ZERO, HALF
+ PARAMETER ( ZERO = ( 0.0D0, 0.0D0 ),
+ $ HALF = ( 0.5D0, 0.0D0 ) )
+ DOUBLE PRECISION RZERO
+ PARAMETER ( RZERO = 0.0D0 )
+* .. Scalar Arguments ..
+ DOUBLE PRECISION EPS, THRESH
+ INTEGER INCMAX, NALF, NBET, NIDIM, NINC, NKB, NMAX,
+ $ NOUT, NTRA
+ LOGICAL FATAL, REWI, TRACE
+ CHARACTER*6 SNAME
+* .. Array Arguments ..
+ COMPLEX*16 A( NMAX, NMAX ), AA( NMAX*NMAX ), ALF( NALF ),
+ $ AS( NMAX*NMAX ), BET( NBET ), X( NMAX ),
+ $ XS( NMAX*INCMAX ), XX( NMAX*INCMAX ),
+ $ Y( NMAX ), YS( NMAX*INCMAX ), YT( NMAX ),
+ $ YY( NMAX*INCMAX )
+ DOUBLE PRECISION G( NMAX )
+ INTEGER IDIM( NIDIM ), INC( NINC ), KB( NKB )
+* .. Local Scalars ..
+ COMPLEX*16 ALPHA, ALS, BETA, BLS, TRANSL
+ DOUBLE PRECISION ERR, ERRMAX
+ INTEGER I, IA, IB, IC, IK, IN, INCX, INCXS, INCY,
+ $ INCYS, IX, IY, K, KS, LAA, LDA, LDAS, LX, LY,
+ $ N, NARGS, NC, NK, NS
+ LOGICAL BANDED, FULL, NULL, PACKED, RESET, SAME
+ CHARACTER*1 UPLO, UPLOS
+ CHARACTER*2 ICH
+* .. Local Arrays ..
+ LOGICAL ISAME( 13 )
+* .. External Functions ..
+ LOGICAL LZE, LZERES
+ EXTERNAL LZE, LZERES
+* .. External Subroutines ..
+ EXTERNAL ZHBMV, ZHEMV, ZHPMV, ZMAKE, ZMVCH
+* .. Intrinsic Functions ..
+ INTRINSIC ABS, MAX
+* .. Scalars in Common ..
+ INTEGER INFOT, NOUTC
+ LOGICAL LERR, OK
+* .. Common blocks ..
+ COMMON /INFOC/INFOT, NOUTC, OK, LERR
+* .. Data statements ..
+ DATA ICH/'UL'/
+* .. Executable Statements ..
+ FULL = SNAME( 3: 3 ).EQ.'E'
+ BANDED = SNAME( 3: 3 ).EQ.'B'
+ PACKED = SNAME( 3: 3 ).EQ.'P'
+* Define the number of arguments.
+ IF( FULL )THEN
+ NARGS = 10
+ ELSE IF( BANDED )THEN
+ NARGS = 11
+ ELSE IF( PACKED )THEN
+ NARGS = 9
+ END IF
+*
+ NC = 0
+ RESET = .TRUE.
+ ERRMAX = RZERO
+*
+ DO 110 IN = 1, NIDIM
+ N = IDIM( IN )
+*
+ IF( BANDED )THEN
+ NK = NKB
+ ELSE
+ NK = 1
+ END IF
+ DO 100 IK = 1, NK
+ IF( BANDED )THEN
+ K = KB( IK )
+ ELSE
+ K = N - 1
+ END IF
+* Set LDA to 1 more than minimum value if room.
+ IF( BANDED )THEN
+ LDA = K + 1
+ ELSE
+ LDA = N
+ END IF
+ IF( LDA.LT.NMAX )
+ $ LDA = LDA + 1
+* Skip tests if not enough room.
+ IF( LDA.GT.NMAX )
+ $ GO TO 100
+ IF( PACKED )THEN
+ LAA = ( N*( N + 1 ) )/2
+ ELSE
+ LAA = LDA*N
+ END IF
+ NULL = N.LE.0
+*
+ DO 90 IC = 1, 2
+ UPLO = ICH( IC: IC )
+*
+* Generate the matrix A.
+*
+ TRANSL = ZERO
+ CALL ZMAKE( SNAME( 2: 3 ), UPLO, ' ', N, N, A, NMAX, AA,
+ $ LDA, K, K, RESET, TRANSL )
+*
+ DO 80 IX = 1, NINC
+ INCX = INC( IX )
+ LX = ABS( INCX )*N
+*
+* Generate the vector X.
+*
+ TRANSL = HALF
+ CALL ZMAKE( 'GE', ' ', ' ', 1, N, X, 1, XX,
+ $ ABS( INCX ), 0, N - 1, RESET, TRANSL )
+ IF( N.GT.1 )THEN
+ X( N/2 ) = ZERO
+ XX( 1 + ABS( INCX )*( N/2 - 1 ) ) = ZERO
+ END IF
+*
+ DO 70 IY = 1, NINC
+ INCY = INC( IY )
+ LY = ABS( INCY )*N
+*
+ DO 60 IA = 1, NALF
+ ALPHA = ALF( IA )
+*
+ DO 50 IB = 1, NBET
+ BETA = BET( IB )
+*
+* Generate the vector Y.
+*
+ TRANSL = ZERO
+ CALL ZMAKE( 'GE', ' ', ' ', 1, N, Y, 1, YY,
+ $ ABS( INCY ), 0, N - 1, RESET,
+ $ TRANSL )
+*
+ NC = NC + 1
+*
+* Save every datum before calling the
+* subroutine.
+*
+ UPLOS = UPLO
+ NS = N
+ KS = K
+ ALS = ALPHA
+ DO 10 I = 1, LAA
+ AS( I ) = AA( I )
+ 10 CONTINUE
+ LDAS = LDA
+ DO 20 I = 1, LX
+ XS( I ) = XX( I )
+ 20 CONTINUE
+ INCXS = INCX
+ BLS = BETA
+ DO 30 I = 1, LY
+ YS( I ) = YY( I )
+ 30 CONTINUE
+ INCYS = INCY
+*
+* Call the subroutine.
+*
+ IF( FULL )THEN
+ IF( TRACE )
+ $ WRITE( NTRA, FMT = 9993 )NC, SNAME,
+ $ UPLO, N, ALPHA, LDA, INCX, BETA, INCY
+ IF( REWI )
+ $ REWIND NTRA
+ CALL ZHEMV( UPLO, N, ALPHA, AA, LDA, XX,
+ $ INCX, BETA, YY, INCY )
+ ELSE IF( BANDED )THEN
+ IF( TRACE )
+ $ WRITE( NTRA, FMT = 9994 )NC, SNAME,
+ $ UPLO, N, K, ALPHA, LDA, INCX, BETA,
+ $ INCY
+ IF( REWI )
+ $ REWIND NTRA
+ CALL ZHBMV( UPLO, N, K, ALPHA, AA, LDA,
+ $ XX, INCX, BETA, YY, INCY )
+ ELSE IF( PACKED )THEN
+ IF( TRACE )
+ $ WRITE( NTRA, FMT = 9995 )NC, SNAME,
+ $ UPLO, N, ALPHA, INCX, BETA, INCY
+ IF( REWI )
+ $ REWIND NTRA
+ CALL ZHPMV( UPLO, N, ALPHA, AA, XX, INCX,
+ $ BETA, YY, INCY )
+ END IF
+*
+* Check if error-exit was taken incorrectly.
+*
+ IF( .NOT.OK )THEN
+ WRITE( NOUT, FMT = 9992 )
+ FATAL = .TRUE.
+ GO TO 120
+ END IF
+*
+* See what data changed inside subroutines.
+*
+ ISAME( 1 ) = UPLO.EQ.UPLOS
+ ISAME( 2 ) = NS.EQ.N
+ IF( FULL )THEN
+ ISAME( 3 ) = ALS.EQ.ALPHA
+ ISAME( 4 ) = LZE( AS, AA, LAA )
+ ISAME( 5 ) = LDAS.EQ.LDA
+ ISAME( 6 ) = LZE( XS, XX, LX )
+ ISAME( 7 ) = INCXS.EQ.INCX
+ ISAME( 8 ) = BLS.EQ.BETA
+ IF( NULL )THEN
+ ISAME( 9 ) = LZE( YS, YY, LY )
+ ELSE
+ ISAME( 9 ) = LZERES( 'GE', ' ', 1, N,
+ $ YS, YY, ABS( INCY ) )
+ END IF
+ ISAME( 10 ) = INCYS.EQ.INCY
+ ELSE IF( BANDED )THEN
+ ISAME( 3 ) = KS.EQ.K
+ ISAME( 4 ) = ALS.EQ.ALPHA
+ ISAME( 5 ) = LZE( AS, AA, LAA )
+ ISAME( 6 ) = LDAS.EQ.LDA
+ ISAME( 7 ) = LZE( XS, XX, LX )
+ ISAME( 8 ) = INCXS.EQ.INCX
+ ISAME( 9 ) = BLS.EQ.BETA
+ IF( NULL )THEN
+ ISAME( 10 ) = LZE( YS, YY, LY )
+ ELSE
+ ISAME( 10 ) = LZERES( 'GE', ' ', 1, N,
+ $ YS, YY, ABS( INCY ) )
+ END IF
+ ISAME( 11 ) = INCYS.EQ.INCY
+ ELSE IF( PACKED )THEN
+ ISAME( 3 ) = ALS.EQ.ALPHA
+ ISAME( 4 ) = LZE( AS, AA, LAA )
+ ISAME( 5 ) = LZE( XS, XX, LX )
+ ISAME( 6 ) = INCXS.EQ.INCX
+ ISAME( 7 ) = BLS.EQ.BETA
+ IF( NULL )THEN
+ ISAME( 8 ) = LZE( YS, YY, LY )
+ ELSE
+ ISAME( 8 ) = LZERES( 'GE', ' ', 1, N,
+ $ YS, YY, ABS( INCY ) )
+ END IF
+ ISAME( 9 ) = INCYS.EQ.INCY
+ END IF
+*
+* If data was incorrectly changed, report and
+* return.
+*
+ SAME = .TRUE.
+ DO 40 I = 1, NARGS
+ SAME = SAME.AND.ISAME( I )
+ IF( .NOT.ISAME( I ) )
+ $ WRITE( NOUT, FMT = 9998 )I
+ 40 CONTINUE
+ IF( .NOT.SAME )THEN
+ FATAL = .TRUE.
+ GO TO 120
+ END IF
+*
+ IF( .NOT.NULL )THEN
+*
+* Check the result.
+*
+ CALL ZMVCH( 'N', N, N, ALPHA, A, NMAX, X,
+ $ INCX, BETA, Y, INCY, YT, G,
+ $ YY, EPS, ERR, FATAL, NOUT,
+ $ .TRUE. )
+ ERRMAX = MAX( ERRMAX, ERR )
+* If got really bad answer, report and
+* return.
+ IF( FATAL )
+ $ GO TO 120
+ ELSE
+* Avoid repeating tests with N.le.0
+ GO TO 110
+ END IF
+*
+ 50 CONTINUE
+*
+ 60 CONTINUE
+*
+ 70 CONTINUE
+*
+ 80 CONTINUE
+*
+ 90 CONTINUE
+*
+ 100 CONTINUE
+*
+ 110 CONTINUE
+*
+* Report result.
+*
+ IF( ERRMAX.LT.THRESH )THEN
+ WRITE( NOUT, FMT = 9999 )SNAME, NC
+ ELSE
+ WRITE( NOUT, FMT = 9997 )SNAME, NC, ERRMAX
+ END IF
+ GO TO 130
+*
+ 120 CONTINUE
+ WRITE( NOUT, FMT = 9996 )SNAME
+ IF( FULL )THEN
+ WRITE( NOUT, FMT = 9993 )NC, SNAME, UPLO, N, ALPHA, LDA, INCX,
+ $ BETA, INCY
+ ELSE IF( BANDED )THEN
+ WRITE( NOUT, FMT = 9994 )NC, SNAME, UPLO, N, K, ALPHA, LDA,
+ $ INCX, BETA, INCY
+ ELSE IF( PACKED )THEN
+ WRITE( NOUT, FMT = 9995 )NC, SNAME, UPLO, N, ALPHA, INCX,
+ $ BETA, INCY
+ END IF
+*
+ 130 CONTINUE
+ RETURN
+*
+ 9999 FORMAT( ' ', A6, ' PASSED THE COMPUTATIONAL TESTS (', I6, ' CALL',
+ $ 'S)' )
+ 9998 FORMAT( ' ******* FATAL ERROR - PARAMETER NUMBER ', I2, ' WAS CH',
+ $ 'ANGED INCORRECTLY *******' )
+ 9997 FORMAT( ' ', A6, ' COMPLETED THE COMPUTATIONAL TESTS (', I6, ' C',
+ $ 'ALLS)', /' ******* BUT WITH MAXIMUM TEST RATIO', F8.2,
+ $ ' - SUSPECT *******' )
+ 9996 FORMAT( ' ******* ', A6, ' FAILED ON CALL NUMBER:' )
+ 9995 FORMAT( 1X, I6, ': ', A6, '(''', A1, ''',', I3, ',(', F4.1, ',',
+ $ F4.1, '), AP, X,', I2, ',(', F4.1, ',', F4.1, '), Y,', I2,
+ $ ') .' )
+ 9994 FORMAT( 1X, I6, ': ', A6, '(''', A1, ''',', 2( I3, ',' ), '(',
+ $ F4.1, ',', F4.1, '), A,', I3, ', X,', I2, ',(', F4.1, ',',
+ $ F4.1, '), Y,', I2, ') .' )
+ 9993 FORMAT( 1X, I6, ': ', A6, '(''', A1, ''',', I3, ',(', F4.1, ',',
+ $ F4.1, '), A,', I3, ', X,', I2, ',(', F4.1, ',', F4.1, '), ',
+ $ 'Y,', I2, ') .' )
+ 9992 FORMAT( ' ******* FATAL ERROR - ERROR-EXIT TAKEN ON VALID CALL *',
+ $ '******' )
+*
+* End of ZCHK2.
+*
+ END
+ SUBROUTINE ZCHK3( SNAME, EPS, THRESH, NOUT, NTRA, TRACE, REWI,
+ $ FATAL, NIDIM, IDIM, NKB, KB, NINC, INC, NMAX,
+ $ INCMAX, A, AA, AS, X, XX, XS, XT, G, Z )
+*
+* Tests ZTRMV, ZTBMV, ZTPMV, ZTRSV, ZTBSV and ZTPSV.
+*
+* Auxiliary routine for test program for Level 2 Blas.
+*
+* -- Written on 10-August-1987.
+* Richard Hanson, Sandia National Labs.
+* Jeremy Du Croz, NAG Central Office.
+*
+* .. Parameters ..
+ COMPLEX*16 ZERO, HALF, ONE
+ PARAMETER ( ZERO = ( 0.0D0, 0.0D0 ),
+ $ HALF = ( 0.5D0, 0.0D0 ),
+ $ ONE = ( 1.0D0, 0.0D0 ) )
+ DOUBLE PRECISION RZERO
+ PARAMETER ( RZERO = 0.0D0 )
+* .. Scalar Arguments ..
+ DOUBLE PRECISION EPS, THRESH
+ INTEGER INCMAX, NIDIM, NINC, NKB, NMAX, NOUT, NTRA
+ LOGICAL FATAL, REWI, TRACE
+ CHARACTER*6 SNAME
+* .. Array Arguments ..
+ COMPLEX*16 A( NMAX, NMAX ), AA( NMAX*NMAX ),
+ $ AS( NMAX*NMAX ), X( NMAX ), XS( NMAX*INCMAX ),
+ $ XT( NMAX ), XX( NMAX*INCMAX ), Z( NMAX )
+ DOUBLE PRECISION G( NMAX )
+ INTEGER IDIM( NIDIM ), INC( NINC ), KB( NKB )
+* .. Local Scalars ..
+ COMPLEX*16 TRANSL
+ DOUBLE PRECISION ERR, ERRMAX
+ INTEGER I, ICD, ICT, ICU, IK, IN, INCX, INCXS, IX, K,
+ $ KS, LAA, LDA, LDAS, LX, N, NARGS, NC, NK, NS
+ LOGICAL BANDED, FULL, NULL, PACKED, RESET, SAME
+ CHARACTER*1 DIAG, DIAGS, TRANS, TRANSS, UPLO, UPLOS
+ CHARACTER*2 ICHD, ICHU
+ CHARACTER*3 ICHT
+* .. Local Arrays ..
+ LOGICAL ISAME( 13 )
+* .. External Functions ..
+ LOGICAL LZE, LZERES
+ EXTERNAL LZE, LZERES
+* .. External Subroutines ..
+ EXTERNAL ZMAKE, ZMVCH, ZTBMV, ZTBSV, ZTPMV, ZTPSV,
+ $ ZTRMV, ZTRSV
+* .. Intrinsic Functions ..
+ INTRINSIC ABS, MAX
+* .. Scalars in Common ..
+ INTEGER INFOT, NOUTC
+ LOGICAL LERR, OK
+* .. Common blocks ..
+ COMMON /INFOC/INFOT, NOUTC, OK, LERR
+* .. Data statements ..
+ DATA ICHU/'UL'/, ICHT/'NTC'/, ICHD/'UN'/
+* .. Executable Statements ..
+ FULL = SNAME( 3: 3 ).EQ.'R'
+ BANDED = SNAME( 3: 3 ).EQ.'B'
+ PACKED = SNAME( 3: 3 ).EQ.'P'
+* Define the number of arguments.
+ IF( FULL )THEN
+ NARGS = 8
+ ELSE IF( BANDED )THEN
+ NARGS = 9
+ ELSE IF( PACKED )THEN
+ NARGS = 7
+ END IF
+*
+ NC = 0
+ RESET = .TRUE.
+ ERRMAX = RZERO
+* Set up zero vector for ZMVCH.
+ DO 10 I = 1, NMAX
+ Z( I ) = ZERO
+ 10 CONTINUE
+*
+ DO 110 IN = 1, NIDIM
+ N = IDIM( IN )
+*
+ IF( BANDED )THEN
+ NK = NKB
+ ELSE
+ NK = 1
+ END IF
+ DO 100 IK = 1, NK
+ IF( BANDED )THEN
+ K = KB( IK )
+ ELSE
+ K = N - 1
+ END IF
+* Set LDA to 1 more than minimum value if room.
+ IF( BANDED )THEN
+ LDA = K + 1
+ ELSE
+ LDA = N
+ END IF
+ IF( LDA.LT.NMAX )
+ $ LDA = LDA + 1
+* Skip tests if not enough room.
+ IF( LDA.GT.NMAX )
+ $ GO TO 100
+ IF( PACKED )THEN
+ LAA = ( N*( N + 1 ) )/2
+ ELSE
+ LAA = LDA*N
+ END IF
+ NULL = N.LE.0
+*
+ DO 90 ICU = 1, 2
+ UPLO = ICHU( ICU: ICU )
+*
+ DO 80 ICT = 1, 3
+ TRANS = ICHT( ICT: ICT )
+*
+ DO 70 ICD = 1, 2
+ DIAG = ICHD( ICD: ICD )
+*
+* Generate the matrix A.
+*
+ TRANSL = ZERO
+ CALL ZMAKE( SNAME( 2: 3 ), UPLO, DIAG, N, N, A,
+ $ NMAX, AA, LDA, K, K, RESET, TRANSL )
+*
+ DO 60 IX = 1, NINC
+ INCX = INC( IX )
+ LX = ABS( INCX )*N
+*
+* Generate the vector X.
+*
+ TRANSL = HALF
+ CALL ZMAKE( 'GE', ' ', ' ', 1, N, X, 1, XX,
+ $ ABS( INCX ), 0, N - 1, RESET,
+ $ TRANSL )
+ IF( N.GT.1 )THEN
+ X( N/2 ) = ZERO
+ XX( 1 + ABS( INCX )*( N/2 - 1 ) ) = ZERO
+ END IF
+*
+ NC = NC + 1
+*
+* Save every datum before calling the subroutine.
+*
+ UPLOS = UPLO
+ TRANSS = TRANS
+ DIAGS = DIAG
+ NS = N
+ KS = K
+ DO 20 I = 1, LAA
+ AS( I ) = AA( I )
+ 20 CONTINUE
+ LDAS = LDA
+ DO 30 I = 1, LX
+ XS( I ) = XX( I )
+ 30 CONTINUE
+ INCXS = INCX
+*
+* Call the subroutine.
+*
+ IF( SNAME( 4: 5 ).EQ.'MV' )THEN
+ IF( FULL )THEN
+ IF( TRACE )
+ $ WRITE( NTRA, FMT = 9993 )NC, SNAME,
+ $ UPLO, TRANS, DIAG, N, LDA, INCX
+ IF( REWI )
+ $ REWIND NTRA
+ CALL ZTRMV( UPLO, TRANS, DIAG, N, AA, LDA,
+ $ XX, INCX )
+ ELSE IF( BANDED )THEN
+ IF( TRACE )
+ $ WRITE( NTRA, FMT = 9994 )NC, SNAME,
+ $ UPLO, TRANS, DIAG, N, K, LDA, INCX
+ IF( REWI )
+ $ REWIND NTRA
+ CALL ZTBMV( UPLO, TRANS, DIAG, N, K, AA,
+ $ LDA, XX, INCX )
+ ELSE IF( PACKED )THEN
+ IF( TRACE )
+ $ WRITE( NTRA, FMT = 9995 )NC, SNAME,
+ $ UPLO, TRANS, DIAG, N, INCX
+ IF( REWI )
+ $ REWIND NTRA
+ CALL ZTPMV( UPLO, TRANS, DIAG, N, AA, XX,
+ $ INCX )
+ END IF
+ ELSE IF( SNAME( 4: 5 ).EQ.'SV' )THEN
+ IF( FULL )THEN
+ IF( TRACE )
+ $ WRITE( NTRA, FMT = 9993 )NC, SNAME,
+ $ UPLO, TRANS, DIAG, N, LDA, INCX
+ IF( REWI )
+ $ REWIND NTRA
+ CALL ZTRSV( UPLO, TRANS, DIAG, N, AA, LDA,
+ $ XX, INCX )
+ ELSE IF( BANDED )THEN
+ IF( TRACE )
+ $ WRITE( NTRA, FMT = 9994 )NC, SNAME,
+ $ UPLO, TRANS, DIAG, N, K, LDA, INCX
+ IF( REWI )
+ $ REWIND NTRA
+ CALL ZTBSV( UPLO, TRANS, DIAG, N, K, AA,
+ $ LDA, XX, INCX )
+ ELSE IF( PACKED )THEN
+ IF( TRACE )
+ $ WRITE( NTRA, FMT = 9995 )NC, SNAME,
+ $ UPLO, TRANS, DIAG, N, INCX
+ IF( REWI )
+ $ REWIND NTRA
+ CALL ZTPSV( UPLO, TRANS, DIAG, N, AA, XX,
+ $ INCX )
+ END IF
+ END IF
+*
+* Check if error-exit was taken incorrectly.
+*
+ IF( .NOT.OK )THEN
+ WRITE( NOUT, FMT = 9992 )
+ FATAL = .TRUE.
+ GO TO 120
+ END IF
+*
+* See what data changed inside subroutines.
+*
+ ISAME( 1 ) = UPLO.EQ.UPLOS
+ ISAME( 2 ) = TRANS.EQ.TRANSS
+ ISAME( 3 ) = DIAG.EQ.DIAGS
+ ISAME( 4 ) = NS.EQ.N
+ IF( FULL )THEN
+ ISAME( 5 ) = LZE( AS, AA, LAA )
+ ISAME( 6 ) = LDAS.EQ.LDA
+ IF( NULL )THEN
+ ISAME( 7 ) = LZE( XS, XX, LX )
+ ELSE
+ ISAME( 7 ) = LZERES( 'GE', ' ', 1, N, XS,
+ $ XX, ABS( INCX ) )
+ END IF
+ ISAME( 8 ) = INCXS.EQ.INCX
+ ELSE IF( BANDED )THEN
+ ISAME( 5 ) = KS.EQ.K
+ ISAME( 6 ) = LZE( AS, AA, LAA )
+ ISAME( 7 ) = LDAS.EQ.LDA
+ IF( NULL )THEN
+ ISAME( 8 ) = LZE( XS, XX, LX )
+ ELSE
+ ISAME( 8 ) = LZERES( 'GE', ' ', 1, N, XS,
+ $ XX, ABS( INCX ) )
+ END IF
+ ISAME( 9 ) = INCXS.EQ.INCX
+ ELSE IF( PACKED )THEN
+ ISAME( 5 ) = LZE( AS, AA, LAA )
+ IF( NULL )THEN
+ ISAME( 6 ) = LZE( XS, XX, LX )
+ ELSE
+ ISAME( 6 ) = LZERES( 'GE', ' ', 1, N, XS,
+ $ XX, ABS( INCX ) )
+ END IF
+ ISAME( 7 ) = INCXS.EQ.INCX
+ END IF
+*
+* If data was incorrectly changed, report and
+* return.
+*
+ SAME = .TRUE.
+ DO 40 I = 1, NARGS
+ SAME = SAME.AND.ISAME( I )
+ IF( .NOT.ISAME( I ) )
+ $ WRITE( NOUT, FMT = 9998 )I
+ 40 CONTINUE
+ IF( .NOT.SAME )THEN
+ FATAL = .TRUE.
+ GO TO 120
+ END IF
+*
+ IF( .NOT.NULL )THEN
+ IF( SNAME( 4: 5 ).EQ.'MV' )THEN
+*
+* Check the result.
+*
+ CALL ZMVCH( TRANS, N, N, ONE, A, NMAX, X,
+ $ INCX, ZERO, Z, INCX, XT, G,
+ $ XX, EPS, ERR, FATAL, NOUT,
+ $ .TRUE. )
+ ELSE IF( SNAME( 4: 5 ).EQ.'SV' )THEN
+*
+* Compute approximation to original vector.
+*
+ DO 50 I = 1, N
+ Z( I ) = XX( 1 + ( I - 1 )*
+ $ ABS( INCX ) )
+ XX( 1 + ( I - 1 )*ABS( INCX ) )
+ $ = X( I )
+ 50 CONTINUE
+ CALL ZMVCH( TRANS, N, N, ONE, A, NMAX, Z,
+ $ INCX, ZERO, X, INCX, XT, G,
+ $ XX, EPS, ERR, FATAL, NOUT,
+ $ .FALSE. )
+ END IF
+ ERRMAX = MAX( ERRMAX, ERR )
+* If got really bad answer, report and return.
+ IF( FATAL )
+ $ GO TO 120
+ ELSE
+* Avoid repeating tests with N.le.0.
+ GO TO 110
+ END IF
+*
+ 60 CONTINUE
+*
+ 70 CONTINUE
+*
+ 80 CONTINUE
+*
+ 90 CONTINUE
+*
+ 100 CONTINUE
+*
+ 110 CONTINUE
+*
+* Report result.
+*
+ IF( ERRMAX.LT.THRESH )THEN
+ WRITE( NOUT, FMT = 9999 )SNAME, NC
+ ELSE
+ WRITE( NOUT, FMT = 9997 )SNAME, NC, ERRMAX
+ END IF
+ GO TO 130
+*
+ 120 CONTINUE
+ WRITE( NOUT, FMT = 9996 )SNAME
+ IF( FULL )THEN
+ WRITE( NOUT, FMT = 9993 )NC, SNAME, UPLO, TRANS, DIAG, N, LDA,
+ $ INCX
+ ELSE IF( BANDED )THEN
+ WRITE( NOUT, FMT = 9994 )NC, SNAME, UPLO, TRANS, DIAG, N, K,
+ $ LDA, INCX
+ ELSE IF( PACKED )THEN
+ WRITE( NOUT, FMT = 9995 )NC, SNAME, UPLO, TRANS, DIAG, N, INCX
+ END IF
+*
+ 130 CONTINUE
+ RETURN
+*
+ 9999 FORMAT( ' ', A6, ' PASSED THE COMPUTATIONAL TESTS (', I6, ' CALL',
+ $ 'S)' )
+ 9998 FORMAT( ' ******* FATAL ERROR - PARAMETER NUMBER ', I2, ' WAS CH',
+ $ 'ANGED INCORRECTLY *******' )
+ 9997 FORMAT( ' ', A6, ' COMPLETED THE COMPUTATIONAL TESTS (', I6, ' C',
+ $ 'ALLS)', /' ******* BUT WITH MAXIMUM TEST RATIO', F8.2,
+ $ ' - SUSPECT *******' )
+ 9996 FORMAT( ' ******* ', A6, ' FAILED ON CALL NUMBER:' )
+ 9995 FORMAT( 1X, I6, ': ', A6, '(', 3( '''', A1, ''',' ), I3, ', AP, ',
+ $ 'X,', I2, ') .' )
+ 9994 FORMAT( 1X, I6, ': ', A6, '(', 3( '''', A1, ''',' ), 2( I3, ',' ),
+ $ ' A,', I3, ', X,', I2, ') .' )
+ 9993 FORMAT( 1X, I6, ': ', A6, '(', 3( '''', A1, ''',' ), I3, ', A,',
+ $ I3, ', X,', I2, ') .' )
+ 9992 FORMAT( ' ******* FATAL ERROR - ERROR-EXIT TAKEN ON VALID CALL *',
+ $ '******' )
+*
+* End of ZCHK3.
+*
+ END
+ SUBROUTINE ZCHK4( SNAME, EPS, THRESH, NOUT, NTRA, TRACE, REWI,
+ $ FATAL, NIDIM, IDIM, NALF, ALF, NINC, INC, NMAX,
+ $ INCMAX, A, AA, AS, X, XX, XS, Y, YY, YS, YT, G,
+ $ Z )
+*
+* Tests ZGERC and ZGERU.
+*
+* Auxiliary routine for test program for Level 2 Blas.
+*
+* -- Written on 10-August-1987.
+* Richard Hanson, Sandia National Labs.
+* Jeremy Du Croz, NAG Central Office.
+*
+* .. Parameters ..
+ COMPLEX*16 ZERO, HALF, ONE
+ PARAMETER ( ZERO = ( 0.0D0, 0.0D0 ),
+ $ HALF = ( 0.5D0, 0.0D0 ),
+ $ ONE = ( 1.0D0, 0.0D0 ) )
+ DOUBLE PRECISION RZERO
+ PARAMETER ( RZERO = 0.0D0 )
+* .. Scalar Arguments ..
+ DOUBLE PRECISION EPS, THRESH
+ INTEGER INCMAX, NALF, NIDIM, NINC, NMAX, NOUT, NTRA
+ LOGICAL FATAL, REWI, TRACE
+ CHARACTER*6 SNAME
+* .. Array Arguments ..
+ COMPLEX*16 A( NMAX, NMAX ), AA( NMAX*NMAX ), ALF( NALF ),
+ $ AS( NMAX*NMAX ), X( NMAX ), XS( NMAX*INCMAX ),
+ $ XX( NMAX*INCMAX ), Y( NMAX ),
+ $ YS( NMAX*INCMAX ), YT( NMAX ),
+ $ YY( NMAX*INCMAX ), Z( NMAX )
+ DOUBLE PRECISION G( NMAX )
+ INTEGER IDIM( NIDIM ), INC( NINC )
+* .. Local Scalars ..
+ COMPLEX*16 ALPHA, ALS, TRANSL
+ DOUBLE PRECISION ERR, ERRMAX
+ INTEGER I, IA, IM, IN, INCX, INCXS, INCY, INCYS, IX,
+ $ IY, J, LAA, LDA, LDAS, LX, LY, M, MS, N, NARGS,
+ $ NC, ND, NS
+ LOGICAL CONJ, NULL, RESET, SAME
+* .. Local Arrays ..
+ COMPLEX*16 W( 1 )
+ LOGICAL ISAME( 13 )
+* .. External Functions ..
+ LOGICAL LZE, LZERES
+ EXTERNAL LZE, LZERES
+* .. External Subroutines ..
+ EXTERNAL ZGERC, ZGERU, ZMAKE, ZMVCH
+* .. Intrinsic Functions ..
+ INTRINSIC ABS, DCONJG, MAX, MIN
+* .. Scalars in Common ..
+ INTEGER INFOT, NOUTC
+ LOGICAL LERR, OK
+* .. Common blocks ..
+ COMMON /INFOC/INFOT, NOUTC, OK, LERR
+* .. Executable Statements ..
+ CONJ = SNAME( 5: 5 ).EQ.'C'
+* Define the number of arguments.
+ NARGS = 9
+*
+ NC = 0
+ RESET = .TRUE.
+ ERRMAX = RZERO
+*
+ DO 120 IN = 1, NIDIM
+ N = IDIM( IN )
+ ND = N/2 + 1
+*
+ DO 110 IM = 1, 2
+ IF( IM.EQ.1 )
+ $ M = MAX( N - ND, 0 )
+ IF( IM.EQ.2 )
+ $ M = MIN( N + ND, NMAX )
+*
+* Set LDA to 1 more than minimum value if room.
+ LDA = M
+ IF( LDA.LT.NMAX )
+ $ LDA = LDA + 1
+* Skip tests if not enough room.
+ IF( LDA.GT.NMAX )
+ $ GO TO 110
+ LAA = LDA*N
+ NULL = N.LE.0.OR.M.LE.0
+*
+ DO 100 IX = 1, NINC
+ INCX = INC( IX )
+ LX = ABS( INCX )*M
+*
+* Generate the vector X.
+*
+ TRANSL = HALF
+ CALL ZMAKE( 'GE', ' ', ' ', 1, M, X, 1, XX, ABS( INCX ),
+ $ 0, M - 1, RESET, TRANSL )
+ IF( M.GT.1 )THEN
+ X( M/2 ) = ZERO
+ XX( 1 + ABS( INCX )*( M/2 - 1 ) ) = ZERO
+ END IF
+*
+ DO 90 IY = 1, NINC
+ INCY = INC( IY )
+ LY = ABS( INCY )*N
+*
+* Generate the vector Y.
+*
+ TRANSL = ZERO
+ CALL ZMAKE( 'GE', ' ', ' ', 1, N, Y, 1, YY,
+ $ ABS( INCY ), 0, N - 1, RESET, TRANSL )
+ IF( N.GT.1 )THEN
+ Y( N/2 ) = ZERO
+ YY( 1 + ABS( INCY )*( N/2 - 1 ) ) = ZERO
+ END IF
+*
+ DO 80 IA = 1, NALF
+ ALPHA = ALF( IA )
+*
+* Generate the matrix A.
+*
+ TRANSL = ZERO
+ CALL ZMAKE( SNAME( 2: 3 ), ' ', ' ', M, N, A, NMAX,
+ $ AA, LDA, M - 1, N - 1, RESET, TRANSL )
+*
+ NC = NC + 1
+*
+* Save every datum before calling the subroutine.
+*
+ MS = M
+ NS = N
+ ALS = ALPHA
+ DO 10 I = 1, LAA
+ AS( I ) = AA( I )
+ 10 CONTINUE
+ LDAS = LDA
+ DO 20 I = 1, LX
+ XS( I ) = XX( I )
+ 20 CONTINUE
+ INCXS = INCX
+ DO 30 I = 1, LY
+ YS( I ) = YY( I )
+ 30 CONTINUE
+ INCYS = INCY
+*
+* Call the subroutine.
+*
+ IF( TRACE )
+ $ WRITE( NTRA, FMT = 9994 )NC, SNAME, M, N,
+ $ ALPHA, INCX, INCY, LDA
+ IF( CONJ )THEN
+ IF( REWI )
+ $ REWIND NTRA
+ CALL ZGERC( M, N, ALPHA, XX, INCX, YY, INCY, AA,
+ $ LDA )
+ ELSE
+ IF( REWI )
+ $ REWIND NTRA
+ CALL ZGERU( M, N, ALPHA, XX, INCX, YY, INCY, AA,
+ $ LDA )
+ END IF
+*
+* Check if error-exit was taken incorrectly.
+*
+ IF( .NOT.OK )THEN
+ WRITE( NOUT, FMT = 9993 )
+ FATAL = .TRUE.
+ GO TO 140
+ END IF
+*
+* See what data changed inside subroutine.
+*
+ ISAME( 1 ) = MS.EQ.M
+ ISAME( 2 ) = NS.EQ.N
+ ISAME( 3 ) = ALS.EQ.ALPHA
+ ISAME( 4 ) = LZE( XS, XX, LX )
+ ISAME( 5 ) = INCXS.EQ.INCX
+ ISAME( 6 ) = LZE( YS, YY, LY )
+ ISAME( 7 ) = INCYS.EQ.INCY
+ IF( NULL )THEN
+ ISAME( 8 ) = LZE( AS, AA, LAA )
+ ELSE
+ ISAME( 8 ) = LZERES( 'GE', ' ', M, N, AS, AA,
+ $ LDA )
+ END IF
+ ISAME( 9 ) = LDAS.EQ.LDA
+*
+* If data was incorrectly changed, report and return.
+*
+ SAME = .TRUE.
+ DO 40 I = 1, NARGS
+ SAME = SAME.AND.ISAME( I )
+ IF( .NOT.ISAME( I ) )
+ $ WRITE( NOUT, FMT = 9998 )I
+ 40 CONTINUE
+ IF( .NOT.SAME )THEN
+ FATAL = .TRUE.
+ GO TO 140
+ END IF
+*
+ IF( .NOT.NULL )THEN
+*
+* Check the result column by column.
+*
+ IF( INCX.GT.0 )THEN
+ DO 50 I = 1, M
+ Z( I ) = X( I )
+ 50 CONTINUE
+ ELSE
+ DO 60 I = 1, M
+ Z( I ) = X( M - I + 1 )
+ 60 CONTINUE
+ END IF
+ DO 70 J = 1, N
+ IF( INCY.GT.0 )THEN
+ W( 1 ) = Y( J )
+ ELSE
+ W( 1 ) = Y( N - J + 1 )
+ END IF
+ IF( CONJ )
+ $ W( 1 ) = DCONJG( W( 1 ) )
+ CALL ZMVCH( 'N', M, 1, ALPHA, Z, NMAX, W, 1,
+ $ ONE, A( 1, J ), 1, YT, G,
+ $ AA( 1 + ( J - 1 )*LDA ), EPS,
+ $ ERR, FATAL, NOUT, .TRUE. )
+ ERRMAX = MAX( ERRMAX, ERR )
+* If got really bad answer, report and return.
+ IF( FATAL )
+ $ GO TO 130
+ 70 CONTINUE
+ ELSE
+* Avoid repeating tests with M.le.0 or N.le.0.
+ GO TO 110
+ END IF
+*
+ 80 CONTINUE
+*
+ 90 CONTINUE
+*
+ 100 CONTINUE
+*
+ 110 CONTINUE
+*
+ 120 CONTINUE
+*
+* Report result.
+*
+ IF( ERRMAX.LT.THRESH )THEN
+ WRITE( NOUT, FMT = 9999 )SNAME, NC
+ ELSE
+ WRITE( NOUT, FMT = 9997 )SNAME, NC, ERRMAX
+ END IF
+ GO TO 150
+*
+ 130 CONTINUE
+ WRITE( NOUT, FMT = 9995 )J
+*
+ 140 CONTINUE
+ WRITE( NOUT, FMT = 9996 )SNAME
+ WRITE( NOUT, FMT = 9994 )NC, SNAME, M, N, ALPHA, INCX, INCY, LDA
+*
+ 150 CONTINUE
+ RETURN
+*
+ 9999 FORMAT( ' ', A6, ' PASSED THE COMPUTATIONAL TESTS (', I6, ' CALL',
+ $ 'S)' )
+ 9998 FORMAT( ' ******* FATAL ERROR - PARAMETER NUMBER ', I2, ' WAS CH',
+ $ 'ANGED INCORRECTLY *******' )
+ 9997 FORMAT( ' ', A6, ' COMPLETED THE COMPUTATIONAL TESTS (', I6, ' C',
+ $ 'ALLS)', /' ******* BUT WITH MAXIMUM TEST RATIO', F8.2,
+ $ ' - SUSPECT *******' )
+ 9996 FORMAT( ' ******* ', A6, ' FAILED ON CALL NUMBER:' )
+ 9995 FORMAT( ' THESE ARE THE RESULTS FOR COLUMN ', I3 )
+ 9994 FORMAT( 1X, I6, ': ', A6, '(', 2( I3, ',' ), '(', F4.1, ',', F4.1,
+ $ '), X,', I2, ', Y,', I2, ', A,', I3, ') ',
+ $ ' .' )
+ 9993 FORMAT( ' ******* FATAL ERROR - ERROR-EXIT TAKEN ON VALID CALL *',
+ $ '******' )
+*
+* End of ZCHK4.
+*
+ END
+ SUBROUTINE ZCHK5( SNAME, EPS, THRESH, NOUT, NTRA, TRACE, REWI,
+ $ FATAL, NIDIM, IDIM, NALF, ALF, NINC, INC, NMAX,
+ $ INCMAX, A, AA, AS, X, XX, XS, Y, YY, YS, YT, G,
+ $ Z )
+*
+* Tests ZHER and ZHPR.
+*
+* Auxiliary routine for test program for Level 2 Blas.
+*
+* -- Written on 10-August-1987.
+* Richard Hanson, Sandia National Labs.
+* Jeremy Du Croz, NAG Central Office.
+*
+* .. Parameters ..
+ COMPLEX*16 ZERO, HALF, ONE
+ PARAMETER ( ZERO = ( 0.0D0, 0.0D0 ),
+ $ HALF = ( 0.5D0, 0.0D0 ),
+ $ ONE = ( 1.0D0, 0.0D0 ) )
+ DOUBLE PRECISION RZERO
+ PARAMETER ( RZERO = 0.0D0 )
+* .. Scalar Arguments ..
+ DOUBLE PRECISION EPS, THRESH
+ INTEGER INCMAX, NALF, NIDIM, NINC, NMAX, NOUT, NTRA
+ LOGICAL FATAL, REWI, TRACE
+ CHARACTER*6 SNAME
+* .. Array Arguments ..
+ COMPLEX*16 A( NMAX, NMAX ), AA( NMAX*NMAX ), ALF( NALF ),
+ $ AS( NMAX*NMAX ), X( NMAX ), XS( NMAX*INCMAX ),
+ $ XX( NMAX*INCMAX ), Y( NMAX ),
+ $ YS( NMAX*INCMAX ), YT( NMAX ),
+ $ YY( NMAX*INCMAX ), Z( NMAX )
+ DOUBLE PRECISION G( NMAX )
+ INTEGER IDIM( NIDIM ), INC( NINC )
+* .. Local Scalars ..
+ COMPLEX*16 ALPHA, TRANSL
+ DOUBLE PRECISION ERR, ERRMAX, RALPHA, RALS
+ INTEGER I, IA, IC, IN, INCX, INCXS, IX, J, JA, JJ, LAA,
+ $ LDA, LDAS, LJ, LX, N, NARGS, NC, NS
+ LOGICAL FULL, NULL, PACKED, RESET, SAME, UPPER
+ CHARACTER*1 UPLO, UPLOS
+ CHARACTER*2 ICH
+* .. Local Arrays ..
+ COMPLEX*16 W( 1 )
+ LOGICAL ISAME( 13 )
+* .. External Functions ..
+ LOGICAL LZE, LZERES
+ EXTERNAL LZE, LZERES
+* .. External Subroutines ..
+ EXTERNAL ZHER, ZHPR, ZMAKE, ZMVCH
+* .. Intrinsic Functions ..
+ INTRINSIC ABS, DBLE, DCMPLX, DCONJG, MAX
+* .. Scalars in Common ..
+ INTEGER INFOT, NOUTC
+ LOGICAL LERR, OK
+* .. Common blocks ..
+ COMMON /INFOC/INFOT, NOUTC, OK, LERR
+* .. Data statements ..
+ DATA ICH/'UL'/
+* .. Executable Statements ..
+ FULL = SNAME( 3: 3 ).EQ.'E'
+ PACKED = SNAME( 3: 3 ).EQ.'P'
+* Define the number of arguments.
+ IF( FULL )THEN
+ NARGS = 7
+ ELSE IF( PACKED )THEN
+ NARGS = 6
+ END IF
+*
+ NC = 0
+ RESET = .TRUE.
+ ERRMAX = RZERO
+*
+ DO 100 IN = 1, NIDIM
+ N = IDIM( IN )
+* Set LDA to 1 more than minimum value if room.
+ LDA = N
+ IF( LDA.LT.NMAX )
+ $ LDA = LDA + 1
+* Skip tests if not enough room.
+ IF( LDA.GT.NMAX )
+ $ GO TO 100
+ IF( PACKED )THEN
+ LAA = ( N*( N + 1 ) )/2
+ ELSE
+ LAA = LDA*N
+ END IF
+*
+ DO 90 IC = 1, 2
+ UPLO = ICH( IC: IC )
+ UPPER = UPLO.EQ.'U'
+*
+ DO 80 IX = 1, NINC
+ INCX = INC( IX )
+ LX = ABS( INCX )*N
+*
+* Generate the vector X.
+*
+ TRANSL = HALF
+ CALL ZMAKE( 'GE', ' ', ' ', 1, N, X, 1, XX, ABS( INCX ),
+ $ 0, N - 1, RESET, TRANSL )
+ IF( N.GT.1 )THEN
+ X( N/2 ) = ZERO
+ XX( 1 + ABS( INCX )*( N/2 - 1 ) ) = ZERO
+ END IF
+*
+ DO 70 IA = 1, NALF
+ RALPHA = DBLE( ALF( IA ) )
+ ALPHA = DCMPLX( RALPHA, RZERO )
+ NULL = N.LE.0.OR.RALPHA.EQ.RZERO
+*
+* Generate the matrix A.
+*
+ TRANSL = ZERO
+ CALL ZMAKE( SNAME( 2: 3 ), UPLO, ' ', N, N, A, NMAX,
+ $ AA, LDA, N - 1, N - 1, RESET, TRANSL )
+*
+ NC = NC + 1
+*
+* Save every datum before calling the subroutine.
+*
+ UPLOS = UPLO
+ NS = N
+ RALS = RALPHA
+ DO 10 I = 1, LAA
+ AS( I ) = AA( I )
+ 10 CONTINUE
+ LDAS = LDA
+ DO 20 I = 1, LX
+ XS( I ) = XX( I )
+ 20 CONTINUE
+ INCXS = INCX
+*
+* Call the subroutine.
+*
+ IF( FULL )THEN
+ IF( TRACE )
+ $ WRITE( NTRA, FMT = 9993 )NC, SNAME, UPLO, N,
+ $ RALPHA, INCX, LDA
+ IF( REWI )
+ $ REWIND NTRA
+ CALL ZHER( UPLO, N, RALPHA, XX, INCX, AA, LDA )
+ ELSE IF( PACKED )THEN
+ IF( TRACE )
+ $ WRITE( NTRA, FMT = 9994 )NC, SNAME, UPLO, N,
+ $ RALPHA, INCX
+ IF( REWI )
+ $ REWIND NTRA
+ CALL ZHPR( UPLO, N, RALPHA, XX, INCX, AA )
+ END IF
+*
+* Check if error-exit was taken incorrectly.
+*
+ IF( .NOT.OK )THEN
+ WRITE( NOUT, FMT = 9992 )
+ FATAL = .TRUE.
+ GO TO 120
+ END IF
+*
+* See what data changed inside subroutines.
+*
+ ISAME( 1 ) = UPLO.EQ.UPLOS
+ ISAME( 2 ) = NS.EQ.N
+ ISAME( 3 ) = RALS.EQ.RALPHA
+ ISAME( 4 ) = LZE( XS, XX, LX )
+ ISAME( 5 ) = INCXS.EQ.INCX
+ IF( NULL )THEN
+ ISAME( 6 ) = LZE( AS, AA, LAA )
+ ELSE
+ ISAME( 6 ) = LZERES( SNAME( 2: 3 ), UPLO, N, N, AS,
+ $ AA, LDA )
+ END IF
+ IF( .NOT.PACKED )THEN
+ ISAME( 7 ) = LDAS.EQ.LDA
+ END IF
+*
+* If data was incorrectly changed, report and return.
+*
+ SAME = .TRUE.
+ DO 30 I = 1, NARGS
+ SAME = SAME.AND.ISAME( I )
+ IF( .NOT.ISAME( I ) )
+ $ WRITE( NOUT, FMT = 9998 )I
+ 30 CONTINUE
+ IF( .NOT.SAME )THEN
+ FATAL = .TRUE.
+ GO TO 120
+ END IF
+*
+ IF( .NOT.NULL )THEN
+*
+* Check the result column by column.
+*
+ IF( INCX.GT.0 )THEN
+ DO 40 I = 1, N
+ Z( I ) = X( I )
+ 40 CONTINUE
+ ELSE
+ DO 50 I = 1, N
+ Z( I ) = X( N - I + 1 )
+ 50 CONTINUE
+ END IF
+ JA = 1
+ DO 60 J = 1, N
+ W( 1 ) = DCONJG( Z( J ) )
+ IF( UPPER )THEN
+ JJ = 1
+ LJ = J
+ ELSE
+ JJ = J
+ LJ = N - J + 1
+ END IF
+ CALL ZMVCH( 'N', LJ, 1, ALPHA, Z( JJ ), LJ, W,
+ $ 1, ONE, A( JJ, J ), 1, YT, G,
+ $ AA( JA ), EPS, ERR, FATAL, NOUT,
+ $ .TRUE. )
+ IF( FULL )THEN
+ IF( UPPER )THEN
+ JA = JA + LDA
+ ELSE
+ JA = JA + LDA + 1
+ END IF
+ ELSE
+ JA = JA + LJ
+ END IF
+ ERRMAX = MAX( ERRMAX, ERR )
+* If got really bad answer, report and return.
+ IF( FATAL )
+ $ GO TO 110
+ 60 CONTINUE
+ ELSE
+* Avoid repeating tests if N.le.0.
+ IF( N.LE.0 )
+ $ GO TO 100
+ END IF
+*
+ 70 CONTINUE
+*
+ 80 CONTINUE
+*
+ 90 CONTINUE
+*
+ 100 CONTINUE
+*
+* Report result.
+*
+ IF( ERRMAX.LT.THRESH )THEN
+ WRITE( NOUT, FMT = 9999 )SNAME, NC
+ ELSE
+ WRITE( NOUT, FMT = 9997 )SNAME, NC, ERRMAX
+ END IF
+ GO TO 130
+*
+ 110 CONTINUE
+ WRITE( NOUT, FMT = 9995 )J
+*
+ 120 CONTINUE
+ WRITE( NOUT, FMT = 9996 )SNAME
+ IF( FULL )THEN
+ WRITE( NOUT, FMT = 9993 )NC, SNAME, UPLO, N, RALPHA, INCX, LDA
+ ELSE IF( PACKED )THEN
+ WRITE( NOUT, FMT = 9994 )NC, SNAME, UPLO, N, RALPHA, INCX
+ END IF
+*
+ 130 CONTINUE
+ RETURN
+*
+ 9999 FORMAT( ' ', A6, ' PASSED THE COMPUTATIONAL TESTS (', I6, ' CALL',
+ $ 'S)' )
+ 9998 FORMAT( ' ******* FATAL ERROR - PARAMETER NUMBER ', I2, ' WAS CH',
+ $ 'ANGED INCORRECTLY *******' )
+ 9997 FORMAT( ' ', A6, ' COMPLETED THE COMPUTATIONAL TESTS (', I6, ' C',
+ $ 'ALLS)', /' ******* BUT WITH MAXIMUM TEST RATIO', F8.2,
+ $ ' - SUSPECT *******' )
+ 9996 FORMAT( ' ******* ', A6, ' FAILED ON CALL NUMBER:' )
+ 9995 FORMAT( ' THESE ARE THE RESULTS FOR COLUMN ', I3 )
+ 9994 FORMAT( 1X, I6, ': ', A6, '(''', A1, ''',', I3, ',', F4.1, ', X,',
+ $ I2, ', AP) .' )
+ 9993 FORMAT( 1X, I6, ': ', A6, '(''', A1, ''',', I3, ',', F4.1, ', X,',
+ $ I2, ', A,', I3, ') .' )
+ 9992 FORMAT( ' ******* FATAL ERROR - ERROR-EXIT TAKEN ON VALID CALL *',
+ $ '******' )
+*
+* End of ZCHK5.
+*
+ END
+ SUBROUTINE ZCHK6( SNAME, EPS, THRESH, NOUT, NTRA, TRACE, REWI,
+ $ FATAL, NIDIM, IDIM, NALF, ALF, NINC, INC, NMAX,
+ $ INCMAX, A, AA, AS, X, XX, XS, Y, YY, YS, YT, G,
+ $ Z )
+*
+* Tests ZHER2 and ZHPR2.
+*
+* Auxiliary routine for test program for Level 2 Blas.
+*
+* -- Written on 10-August-1987.
+* Richard Hanson, Sandia National Labs.
+* Jeremy Du Croz, NAG Central Office.
+*
+* .. Parameters ..
+ COMPLEX*16 ZERO, HALF, ONE
+ PARAMETER ( ZERO = ( 0.0D0, 0.0D0 ),
+ $ HALF = ( 0.5D0, 0.0D0 ),
+ $ ONE = ( 1.0D0, 0.0D0 ) )
+ DOUBLE PRECISION RZERO
+ PARAMETER ( RZERO = 0.0D0 )
+* .. Scalar Arguments ..
+ DOUBLE PRECISION EPS, THRESH
+ INTEGER INCMAX, NALF, NIDIM, NINC, NMAX, NOUT, NTRA
+ LOGICAL FATAL, REWI, TRACE
+ CHARACTER*6 SNAME
+* .. Array Arguments ..
+ COMPLEX*16 A( NMAX, NMAX ), AA( NMAX*NMAX ), ALF( NALF ),
+ $ AS( NMAX*NMAX ), X( NMAX ), XS( NMAX*INCMAX ),
+ $ XX( NMAX*INCMAX ), Y( NMAX ),
+ $ YS( NMAX*INCMAX ), YT( NMAX ),
+ $ YY( NMAX*INCMAX ), Z( NMAX, 2 )
+ DOUBLE PRECISION G( NMAX )
+ INTEGER IDIM( NIDIM ), INC( NINC )
+* .. Local Scalars ..
+ COMPLEX*16 ALPHA, ALS, TRANSL
+ DOUBLE PRECISION ERR, ERRMAX
+ INTEGER I, IA, IC, IN, INCX, INCXS, INCY, INCYS, IX,
+ $ IY, J, JA, JJ, LAA, LDA, LDAS, LJ, LX, LY, N,
+ $ NARGS, NC, NS
+ LOGICAL FULL, NULL, PACKED, RESET, SAME, UPPER
+ CHARACTER*1 UPLO, UPLOS
+ CHARACTER*2 ICH
+* .. Local Arrays ..
+ COMPLEX*16 W( 2 )
+ LOGICAL ISAME( 13 )
+* .. External Functions ..
+ LOGICAL LZE, LZERES
+ EXTERNAL LZE, LZERES
+* .. External Subroutines ..
+ EXTERNAL ZHER2, ZHPR2, ZMAKE, ZMVCH
+* .. Intrinsic Functions ..
+ INTRINSIC ABS, DCONJG, MAX
+* .. Scalars in Common ..
+ INTEGER INFOT, NOUTC
+ LOGICAL LERR, OK
+* .. Common blocks ..
+ COMMON /INFOC/INFOT, NOUTC, OK, LERR
+* .. Data statements ..
+ DATA ICH/'UL'/
+* .. Executable Statements ..
+ FULL = SNAME( 3: 3 ).EQ.'E'
+ PACKED = SNAME( 3: 3 ).EQ.'P'
+* Define the number of arguments.
+ IF( FULL )THEN
+ NARGS = 9
+ ELSE IF( PACKED )THEN
+ NARGS = 8
+ END IF
+*
+ NC = 0
+ RESET = .TRUE.
+ ERRMAX = RZERO
+*
+ DO 140 IN = 1, NIDIM
+ N = IDIM( IN )
+* Set LDA to 1 more than minimum value if room.
+ LDA = N
+ IF( LDA.LT.NMAX )
+ $ LDA = LDA + 1
+* Skip tests if not enough room.
+ IF( LDA.GT.NMAX )
+ $ GO TO 140
+ IF( PACKED )THEN
+ LAA = ( N*( N + 1 ) )/2
+ ELSE
+ LAA = LDA*N
+ END IF
+*
+ DO 130 IC = 1, 2
+ UPLO = ICH( IC: IC )
+ UPPER = UPLO.EQ.'U'
+*
+ DO 120 IX = 1, NINC
+ INCX = INC( IX )
+ LX = ABS( INCX )*N
+*
+* Generate the vector X.
+*
+ TRANSL = HALF
+ CALL ZMAKE( 'GE', ' ', ' ', 1, N, X, 1, XX, ABS( INCX ),
+ $ 0, N - 1, RESET, TRANSL )
+ IF( N.GT.1 )THEN
+ X( N/2 ) = ZERO
+ XX( 1 + ABS( INCX )*( N/2 - 1 ) ) = ZERO
+ END IF
+*
+ DO 110 IY = 1, NINC
+ INCY = INC( IY )
+ LY = ABS( INCY )*N
+*
+* Generate the vector Y.
+*
+ TRANSL = ZERO
+ CALL ZMAKE( 'GE', ' ', ' ', 1, N, Y, 1, YY,
+ $ ABS( INCY ), 0, N - 1, RESET, TRANSL )
+ IF( N.GT.1 )THEN
+ Y( N/2 ) = ZERO
+ YY( 1 + ABS( INCY )*( N/2 - 1 ) ) = ZERO
+ END IF
+*
+ DO 100 IA = 1, NALF
+ ALPHA = ALF( IA )
+ NULL = N.LE.0.OR.ALPHA.EQ.ZERO
+*
+* Generate the matrix A.
+*
+ TRANSL = ZERO
+ CALL ZMAKE( SNAME( 2: 3 ), UPLO, ' ', N, N, A,
+ $ NMAX, AA, LDA, N - 1, N - 1, RESET,
+ $ TRANSL )
+*
+ NC = NC + 1
+*
+* Save every datum before calling the subroutine.
+*
+ UPLOS = UPLO
+ NS = N
+ ALS = ALPHA
+ DO 10 I = 1, LAA
+ AS( I ) = AA( I )
+ 10 CONTINUE
+ LDAS = LDA
+ DO 20 I = 1, LX
+ XS( I ) = XX( I )
+ 20 CONTINUE
+ INCXS = INCX
+ DO 30 I = 1, LY
+ YS( I ) = YY( I )
+ 30 CONTINUE
+ INCYS = INCY
+*
+* Call the subroutine.
+*
+ IF( FULL )THEN
+ IF( TRACE )
+ $ WRITE( NTRA, FMT = 9993 )NC, SNAME, UPLO, N,
+ $ ALPHA, INCX, INCY, LDA
+ IF( REWI )
+ $ REWIND NTRA
+ CALL ZHER2( UPLO, N, ALPHA, XX, INCX, YY, INCY,
+ $ AA, LDA )
+ ELSE IF( PACKED )THEN
+ IF( TRACE )
+ $ WRITE( NTRA, FMT = 9994 )NC, SNAME, UPLO, N,
+ $ ALPHA, INCX, INCY
+ IF( REWI )
+ $ REWIND NTRA
+ CALL ZHPR2( UPLO, N, ALPHA, XX, INCX, YY, INCY,
+ $ AA )
+ END IF
+*
+* Check if error-exit was taken incorrectly.
+*
+ IF( .NOT.OK )THEN
+ WRITE( NOUT, FMT = 9992 )
+ FATAL = .TRUE.
+ GO TO 160
+ END IF
+*
+* See what data changed inside subroutines.
+*
+ ISAME( 1 ) = UPLO.EQ.UPLOS
+ ISAME( 2 ) = NS.EQ.N
+ ISAME( 3 ) = ALS.EQ.ALPHA
+ ISAME( 4 ) = LZE( XS, XX, LX )
+ ISAME( 5 ) = INCXS.EQ.INCX
+ ISAME( 6 ) = LZE( YS, YY, LY )
+ ISAME( 7 ) = INCYS.EQ.INCY
+ IF( NULL )THEN
+ ISAME( 8 ) = LZE( AS, AA, LAA )
+ ELSE
+ ISAME( 8 ) = LZERES( SNAME( 2: 3 ), UPLO, N, N,
+ $ AS, AA, LDA )
+ END IF
+ IF( .NOT.PACKED )THEN
+ ISAME( 9 ) = LDAS.EQ.LDA
+ END IF
+*
+* If data was incorrectly changed, report and return.
+*
+ SAME = .TRUE.
+ DO 40 I = 1, NARGS
+ SAME = SAME.AND.ISAME( I )
+ IF( .NOT.ISAME( I ) )
+ $ WRITE( NOUT, FMT = 9998 )I
+ 40 CONTINUE
+ IF( .NOT.SAME )THEN
+ FATAL = .TRUE.
+ GO TO 160
+ END IF
+*
+ IF( .NOT.NULL )THEN
+*
+* Check the result column by column.
+*
+ IF( INCX.GT.0 )THEN
+ DO 50 I = 1, N
+ Z( I, 1 ) = X( I )
+ 50 CONTINUE
+ ELSE
+ DO 60 I = 1, N
+ Z( I, 1 ) = X( N - I + 1 )
+ 60 CONTINUE
+ END IF
+ IF( INCY.GT.0 )THEN
+ DO 70 I = 1, N
+ Z( I, 2 ) = Y( I )
+ 70 CONTINUE
+ ELSE
+ DO 80 I = 1, N
+ Z( I, 2 ) = Y( N - I + 1 )
+ 80 CONTINUE
+ END IF
+ JA = 1
+ DO 90 J = 1, N
+ W( 1 ) = ALPHA*DCONJG( Z( J, 2 ) )
+ W( 2 ) = DCONJG( ALPHA )*DCONJG( Z( J, 1 ) )
+ IF( UPPER )THEN
+ JJ = 1
+ LJ = J
+ ELSE
+ JJ = J
+ LJ = N - J + 1
+ END IF
+ CALL ZMVCH( 'N', LJ, 2, ONE, Z( JJ, 1 ),
+ $ NMAX, W, 1, ONE, A( JJ, J ), 1,
+ $ YT, G, AA( JA ), EPS, ERR, FATAL,
+ $ NOUT, .TRUE. )
+ IF( FULL )THEN
+ IF( UPPER )THEN
+ JA = JA + LDA
+ ELSE
+ JA = JA + LDA + 1
+ END IF
+ ELSE
+ JA = JA + LJ
+ END IF
+ ERRMAX = MAX( ERRMAX, ERR )
+* If got really bad answer, report and return.
+ IF( FATAL )
+ $ GO TO 150
+ 90 CONTINUE
+ ELSE
+* Avoid repeating tests with N.le.0.
+ IF( N.LE.0 )
+ $ GO TO 140
+ END IF
+*
+ 100 CONTINUE
+*
+ 110 CONTINUE
+*
+ 120 CONTINUE
+*
+ 130 CONTINUE
+*
+ 140 CONTINUE
+*
+* Report result.
+*
+ IF( ERRMAX.LT.THRESH )THEN
+ WRITE( NOUT, FMT = 9999 )SNAME, NC
+ ELSE
+ WRITE( NOUT, FMT = 9997 )SNAME, NC, ERRMAX
+ END IF
+ GO TO 170
+*
+ 150 CONTINUE
+ WRITE( NOUT, FMT = 9995 )J
+*
+ 160 CONTINUE
+ WRITE( NOUT, FMT = 9996 )SNAME
+ IF( FULL )THEN
+ WRITE( NOUT, FMT = 9993 )NC, SNAME, UPLO, N, ALPHA, INCX,
+ $ INCY, LDA
+ ELSE IF( PACKED )THEN
+ WRITE( NOUT, FMT = 9994 )NC, SNAME, UPLO, N, ALPHA, INCX, INCY
+ END IF
+*
+ 170 CONTINUE
+ RETURN
+*
+ 9999 FORMAT( ' ', A6, ' PASSED THE COMPUTATIONAL TESTS (', I6, ' CALL',
+ $ 'S)' )
+ 9998 FORMAT( ' ******* FATAL ERROR - PARAMETER NUMBER ', I2, ' WAS CH',
+ $ 'ANGED INCORRECTLY *******' )
+ 9997 FORMAT( ' ', A6, ' COMPLETED THE COMPUTATIONAL TESTS (', I6, ' C',
+ $ 'ALLS)', /' ******* BUT WITH MAXIMUM TEST RATIO', F8.2,
+ $ ' - SUSPECT *******' )
+ 9996 FORMAT( ' ******* ', A6, ' FAILED ON CALL NUMBER:' )
+ 9995 FORMAT( ' THESE ARE THE RESULTS FOR COLUMN ', I3 )
+ 9994 FORMAT( 1X, I6, ': ', A6, '(''', A1, ''',', I3, ',(', F4.1, ',',
+ $ F4.1, '), X,', I2, ', Y,', I2, ', AP) ',
+ $ ' .' )
+ 9993 FORMAT( 1X, I6, ': ', A6, '(''', A1, ''',', I3, ',(', F4.1, ',',
+ $ F4.1, '), X,', I2, ', Y,', I2, ', A,', I3, ') ',
+ $ ' .' )
+ 9992 FORMAT( ' ******* FATAL ERROR - ERROR-EXIT TAKEN ON VALID CALL *',
+ $ '******' )
+*
+* End of ZCHK6.
+*
+ END
+ SUBROUTINE ZCHKE( ISNUM, SRNAMT, NOUT )
+*
+* Tests the error exits from the Level 2 Blas.
+* Requires a special version of the error-handling routine XERBLA.
+* ALPHA, RALPHA, BETA, A, X and Y should not need to be defined.
+*
+* Auxiliary routine for test program for Level 2 Blas.
+*
+* -- Written on 10-August-1987.
+* Richard Hanson, Sandia National Labs.
+* Jeremy Du Croz, NAG Central Office.
+*
+* .. Scalar Arguments ..
+ INTEGER ISNUM, NOUT
+ CHARACTER*6 SRNAMT
+* .. Scalars in Common ..
+ INTEGER INFOT, NOUTC
+ LOGICAL LERR, OK
+* .. Local Scalars ..
+ COMPLEX*16 ALPHA, BETA
+ DOUBLE PRECISION RALPHA
+* .. Local Arrays ..
+ COMPLEX*16 A( 1, 1 ), X( 1 ), Y( 1 )
+* .. External Subroutines ..
+ EXTERNAL CHKXER, ZGBMV, ZGEMV, ZGERC, ZGERU, ZHBMV,
+ $ ZHEMV, ZHER, ZHER2, ZHPMV, ZHPR, ZHPR2, ZTBMV,
+ $ ZTBSV, ZTPMV, ZTPSV, ZTRMV, ZTRSV
+* .. Common blocks ..
+ COMMON /INFOC/INFOT, NOUTC, OK, LERR
+* .. Executable Statements ..
+* OK is set to .FALSE. by the special version of XERBLA or by CHKXER
+* if anything is wrong.
+ OK = .TRUE.
+* LERR is set to .TRUE. by the special version of XERBLA each time
+* it is called, and is then tested and re-set by CHKXER.
+ LERR = .FALSE.
+ GO TO ( 10, 20, 30, 40, 50, 60, 70, 80,
+ $ 90, 100, 110, 120, 130, 140, 150, 160,
+ $ 170 )ISNUM
+ 10 INFOT = 1
+ CALL ZGEMV( '/', 0, 0, ALPHA, A, 1, X, 1, BETA, Y, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 2
+ CALL ZGEMV( 'N', -1, 0, ALPHA, A, 1, X, 1, BETA, Y, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 3
+ CALL ZGEMV( 'N', 0, -1, ALPHA, A, 1, X, 1, BETA, Y, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 6
+ CALL ZGEMV( 'N', 2, 0, ALPHA, A, 1, X, 1, BETA, Y, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 8
+ CALL ZGEMV( 'N', 0, 0, ALPHA, A, 1, X, 0, BETA, Y, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 11
+ CALL ZGEMV( 'N', 0, 0, ALPHA, A, 1, X, 1, BETA, Y, 0 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ GO TO 180
+ 20 INFOT = 1
+ CALL ZGBMV( '/', 0, 0, 0, 0, ALPHA, A, 1, X, 1, BETA, Y, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 2
+ CALL ZGBMV( 'N', -1, 0, 0, 0, ALPHA, A, 1, X, 1, BETA, Y, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 3
+ CALL ZGBMV( 'N', 0, -1, 0, 0, ALPHA, A, 1, X, 1, BETA, Y, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 4
+ CALL ZGBMV( 'N', 0, 0, -1, 0, ALPHA, A, 1, X, 1, BETA, Y, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 5
+ CALL ZGBMV( 'N', 2, 0, 0, -1, ALPHA, A, 1, X, 1, BETA, Y, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 8
+ CALL ZGBMV( 'N', 0, 0, 1, 0, ALPHA, A, 1, X, 1, BETA, Y, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 10
+ CALL ZGBMV( 'N', 0, 0, 0, 0, ALPHA, A, 1, X, 0, BETA, Y, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 13
+ CALL ZGBMV( 'N', 0, 0, 0, 0, ALPHA, A, 1, X, 1, BETA, Y, 0 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ GO TO 180
+ 30 INFOT = 1
+ CALL ZHEMV( '/', 0, ALPHA, A, 1, X, 1, BETA, Y, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 2
+ CALL ZHEMV( 'U', -1, ALPHA, A, 1, X, 1, BETA, Y, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 5
+ CALL ZHEMV( 'U', 2, ALPHA, A, 1, X, 1, BETA, Y, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 7
+ CALL ZHEMV( 'U', 0, ALPHA, A, 1, X, 0, BETA, Y, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 10
+ CALL ZHEMV( 'U', 0, ALPHA, A, 1, X, 1, BETA, Y, 0 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ GO TO 180
+ 40 INFOT = 1
+ CALL ZHBMV( '/', 0, 0, ALPHA, A, 1, X, 1, BETA, Y, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 2
+ CALL ZHBMV( 'U', -1, 0, ALPHA, A, 1, X, 1, BETA, Y, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 3
+ CALL ZHBMV( 'U', 0, -1, ALPHA, A, 1, X, 1, BETA, Y, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 6
+ CALL ZHBMV( 'U', 0, 1, ALPHA, A, 1, X, 1, BETA, Y, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 8
+ CALL ZHBMV( 'U', 0, 0, ALPHA, A, 1, X, 0, BETA, Y, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 11
+ CALL ZHBMV( 'U', 0, 0, ALPHA, A, 1, X, 1, BETA, Y, 0 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ GO TO 180
+ 50 INFOT = 1
+ CALL ZHPMV( '/', 0, ALPHA, A, X, 1, BETA, Y, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 2
+ CALL ZHPMV( 'U', -1, ALPHA, A, X, 1, BETA, Y, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 6
+ CALL ZHPMV( 'U', 0, ALPHA, A, X, 0, BETA, Y, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 9
+ CALL ZHPMV( 'U', 0, ALPHA, A, X, 1, BETA, Y, 0 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ GO TO 180
+ 60 INFOT = 1
+ CALL ZTRMV( '/', 'N', 'N', 0, A, 1, X, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 2
+ CALL ZTRMV( 'U', '/', 'N', 0, A, 1, X, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 3
+ CALL ZTRMV( 'U', 'N', '/', 0, A, 1, X, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 4
+ CALL ZTRMV( 'U', 'N', 'N', -1, A, 1, X, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 6
+ CALL ZTRMV( 'U', 'N', 'N', 2, A, 1, X, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 8
+ CALL ZTRMV( 'U', 'N', 'N', 0, A, 1, X, 0 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ GO TO 180
+ 70 INFOT = 1
+ CALL ZTBMV( '/', 'N', 'N', 0, 0, A, 1, X, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 2
+ CALL ZTBMV( 'U', '/', 'N', 0, 0, A, 1, X, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 3
+ CALL ZTBMV( 'U', 'N', '/', 0, 0, A, 1, X, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 4
+ CALL ZTBMV( 'U', 'N', 'N', -1, 0, A, 1, X, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 5
+ CALL ZTBMV( 'U', 'N', 'N', 0, -1, A, 1, X, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 7
+ CALL ZTBMV( 'U', 'N', 'N', 0, 1, A, 1, X, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 9
+ CALL ZTBMV( 'U', 'N', 'N', 0, 0, A, 1, X, 0 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ GO TO 180
+ 80 INFOT = 1
+ CALL ZTPMV( '/', 'N', 'N', 0, A, X, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 2
+ CALL ZTPMV( 'U', '/', 'N', 0, A, X, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 3
+ CALL ZTPMV( 'U', 'N', '/', 0, A, X, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 4
+ CALL ZTPMV( 'U', 'N', 'N', -1, A, X, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 7
+ CALL ZTPMV( 'U', 'N', 'N', 0, A, X, 0 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ GO TO 180
+ 90 INFOT = 1
+ CALL ZTRSV( '/', 'N', 'N', 0, A, 1, X, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 2
+ CALL ZTRSV( 'U', '/', 'N', 0, A, 1, X, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 3
+ CALL ZTRSV( 'U', 'N', '/', 0, A, 1, X, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 4
+ CALL ZTRSV( 'U', 'N', 'N', -1, A, 1, X, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 6
+ CALL ZTRSV( 'U', 'N', 'N', 2, A, 1, X, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 8
+ CALL ZTRSV( 'U', 'N', 'N', 0, A, 1, X, 0 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ GO TO 180
+ 100 INFOT = 1
+ CALL ZTBSV( '/', 'N', 'N', 0, 0, A, 1, X, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 2
+ CALL ZTBSV( 'U', '/', 'N', 0, 0, A, 1, X, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 3
+ CALL ZTBSV( 'U', 'N', '/', 0, 0, A, 1, X, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 4
+ CALL ZTBSV( 'U', 'N', 'N', -1, 0, A, 1, X, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 5
+ CALL ZTBSV( 'U', 'N', 'N', 0, -1, A, 1, X, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 7
+ CALL ZTBSV( 'U', 'N', 'N', 0, 1, A, 1, X, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 9
+ CALL ZTBSV( 'U', 'N', 'N', 0, 0, A, 1, X, 0 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ GO TO 180
+ 110 INFOT = 1
+ CALL ZTPSV( '/', 'N', 'N', 0, A, X, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 2
+ CALL ZTPSV( 'U', '/', 'N', 0, A, X, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 3
+ CALL ZTPSV( 'U', 'N', '/', 0, A, X, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 4
+ CALL ZTPSV( 'U', 'N', 'N', -1, A, X, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 7
+ CALL ZTPSV( 'U', 'N', 'N', 0, A, X, 0 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ GO TO 180
+ 120 INFOT = 1
+ CALL ZGERC( -1, 0, ALPHA, X, 1, Y, 1, A, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 2
+ CALL ZGERC( 0, -1, ALPHA, X, 1, Y, 1, A, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 5
+ CALL ZGERC( 0, 0, ALPHA, X, 0, Y, 1, A, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 7
+ CALL ZGERC( 0, 0, ALPHA, X, 1, Y, 0, A, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 9
+ CALL ZGERC( 2, 0, ALPHA, X, 1, Y, 1, A, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ GO TO 180
+ 130 INFOT = 1
+ CALL ZGERU( -1, 0, ALPHA, X, 1, Y, 1, A, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 2
+ CALL ZGERU( 0, -1, ALPHA, X, 1, Y, 1, A, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 5
+ CALL ZGERU( 0, 0, ALPHA, X, 0, Y, 1, A, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 7
+ CALL ZGERU( 0, 0, ALPHA, X, 1, Y, 0, A, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 9
+ CALL ZGERU( 2, 0, ALPHA, X, 1, Y, 1, A, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ GO TO 180
+ 140 INFOT = 1
+ CALL ZHER( '/', 0, RALPHA, X, 1, A, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 2
+ CALL ZHER( 'U', -1, RALPHA, X, 1, A, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 5
+ CALL ZHER( 'U', 0, RALPHA, X, 0, A, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 7
+ CALL ZHER( 'U', 2, RALPHA, X, 1, A, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ GO TO 180
+ 150 INFOT = 1
+ CALL ZHPR( '/', 0, RALPHA, X, 1, A )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 2
+ CALL ZHPR( 'U', -1, RALPHA, X, 1, A )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 5
+ CALL ZHPR( 'U', 0, RALPHA, X, 0, A )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ GO TO 180
+ 160 INFOT = 1
+ CALL ZHER2( '/', 0, ALPHA, X, 1, Y, 1, A, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 2
+ CALL ZHER2( 'U', -1, ALPHA, X, 1, Y, 1, A, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 5
+ CALL ZHER2( 'U', 0, ALPHA, X, 0, Y, 1, A, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 7
+ CALL ZHER2( 'U', 0, ALPHA, X, 1, Y, 0, A, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 9
+ CALL ZHER2( 'U', 2, ALPHA, X, 1, Y, 1, A, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ GO TO 180
+ 170 INFOT = 1
+ CALL ZHPR2( '/', 0, ALPHA, X, 1, Y, 1, A )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 2
+ CALL ZHPR2( 'U', -1, ALPHA, X, 1, Y, 1, A )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 5
+ CALL ZHPR2( 'U', 0, ALPHA, X, 0, Y, 1, A )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 7
+ CALL ZHPR2( 'U', 0, ALPHA, X, 1, Y, 0, A )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+*
+ 180 IF( OK )THEN
+ WRITE( NOUT, FMT = 9999 )SRNAMT
+ ELSE
+ WRITE( NOUT, FMT = 9998 )SRNAMT
+ END IF
+ RETURN
+*
+ 9999 FORMAT( ' ', A6, ' PASSED THE TESTS OF ERROR-EXITS' )
+ 9998 FORMAT( ' ******* ', A6, ' FAILED THE TESTS OF ERROR-EXITS *****',
+ $ '**' )
+*
+* End of ZCHKE.
+*
+ END
+ SUBROUTINE ZMAKE( TYPE, UPLO, DIAG, M, N, A, NMAX, AA, LDA, KL,
+ $ KU, RESET, TRANSL )
+*
+* Generates values for an M by N matrix A within the bandwidth
+* defined by KL and KU.
+* Stores the values in the array AA in the data structure required
+* by the routine, with unwanted elements set to rogue value.
+*
+* TYPE is 'GE', 'GB', 'HE', 'HB', 'HP', 'TR', 'TB' OR 'TP'.
+*
+* Auxiliary routine for test program for Level 2 Blas.
+*
+* -- Written on 10-August-1987.
+* Richard Hanson, Sandia National Labs.
+* Jeremy Du Croz, NAG Central Office.
+*
+* .. Parameters ..
+ COMPLEX*16 ZERO, ONE
+ PARAMETER ( ZERO = ( 0.0D0, 0.0D0 ),
+ $ ONE = ( 1.0D0, 0.0D0 ) )
+ COMPLEX*16 ROGUE
+ PARAMETER ( ROGUE = ( -1.0D10, 1.0D10 ) )
+ DOUBLE PRECISION RZERO
+ PARAMETER ( RZERO = 0.0D0 )
+ DOUBLE PRECISION RROGUE
+ PARAMETER ( RROGUE = -1.0D10 )
+* .. Scalar Arguments ..
+ COMPLEX*16 TRANSL
+ INTEGER KL, KU, LDA, M, N, NMAX
+ LOGICAL RESET
+ CHARACTER*1 DIAG, UPLO
+ CHARACTER*2 TYPE
+* .. Array Arguments ..
+ COMPLEX*16 A( NMAX, * ), AA( * )
+* .. Local Scalars ..
+ INTEGER I, I1, I2, I3, IBEG, IEND, IOFF, J, JJ, KK
+ LOGICAL GEN, LOWER, SYM, TRI, UNIT, UPPER
+* .. External Functions ..
+ COMPLEX*16 ZBEG
+ EXTERNAL ZBEG
+* .. Intrinsic Functions ..
+ INTRINSIC DBLE, DCMPLX, DCONJG, MAX, MIN
+* .. Executable Statements ..
+ GEN = TYPE( 1: 1 ).EQ.'G'
+ SYM = TYPE( 1: 1 ).EQ.'H'
+ TRI = TYPE( 1: 1 ).EQ.'T'
+ UPPER = ( SYM.OR.TRI ).AND.UPLO.EQ.'U'
+ LOWER = ( SYM.OR.TRI ).AND.UPLO.EQ.'L'
+ UNIT = TRI.AND.DIAG.EQ.'U'
+*
+* Generate data in array A.
+*
+ DO 20 J = 1, N
+ DO 10 I = 1, M
+ IF( GEN.OR.( UPPER.AND.I.LE.J ).OR.( LOWER.AND.I.GE.J ) )
+ $ THEN
+ IF( ( I.LE.J.AND.J - I.LE.KU ).OR.
+ $ ( I.GE.J.AND.I - J.LE.KL ) )THEN
+ A( I, J ) = ZBEG( RESET ) + TRANSL
+ ELSE
+ A( I, J ) = ZERO
+ END IF
+ IF( I.NE.J )THEN
+ IF( SYM )THEN
+ A( J, I ) = DCONJG( A( I, J ) )
+ ELSE IF( TRI )THEN
+ A( J, I ) = ZERO
+ END IF
+ END IF
+ END IF
+ 10 CONTINUE
+ IF( SYM )
+ $ A( J, J ) = DCMPLX( DBLE( A( J, J ) ), RZERO )
+ IF( TRI )
+ $ A( J, J ) = A( J, J ) + ONE
+ IF( UNIT )
+ $ A( J, J ) = ONE
+ 20 CONTINUE
+*
+* Store elements in array AS in data structure required by routine.
+*
+ IF( TYPE.EQ.'GE' )THEN
+ DO 50 J = 1, N
+ DO 30 I = 1, M
+ AA( I + ( J - 1 )*LDA ) = A( I, J )
+ 30 CONTINUE
+ DO 40 I = M + 1, LDA
+ AA( I + ( J - 1 )*LDA ) = ROGUE
+ 40 CONTINUE
+ 50 CONTINUE
+ ELSE IF( TYPE.EQ.'GB' )THEN
+ DO 90 J = 1, N
+ DO 60 I1 = 1, KU + 1 - J
+ AA( I1 + ( J - 1 )*LDA ) = ROGUE
+ 60 CONTINUE
+ DO 70 I2 = I1, MIN( KL + KU + 1, KU + 1 + M - J )
+ AA( I2 + ( J - 1 )*LDA ) = A( I2 + J - KU - 1, J )
+ 70 CONTINUE
+ DO 80 I3 = I2, LDA
+ AA( I3 + ( J - 1 )*LDA ) = ROGUE
+ 80 CONTINUE
+ 90 CONTINUE
+ ELSE IF( TYPE.EQ.'HE'.OR.TYPE.EQ.'TR' )THEN
+ DO 130 J = 1, N
+ IF( UPPER )THEN
+ IBEG = 1
+ IF( UNIT )THEN
+ IEND = J - 1
+ ELSE
+ IEND = J
+ END IF
+ ELSE
+ IF( UNIT )THEN
+ IBEG = J + 1
+ ELSE
+ IBEG = J
+ END IF
+ IEND = N
+ END IF
+ DO 100 I = 1, IBEG - 1
+ AA( I + ( J - 1 )*LDA ) = ROGUE
+ 100 CONTINUE
+ DO 110 I = IBEG, IEND
+ AA( I + ( J - 1 )*LDA ) = A( I, J )
+ 110 CONTINUE
+ DO 120 I = IEND + 1, LDA
+ AA( I + ( J - 1 )*LDA ) = ROGUE
+ 120 CONTINUE
+ IF( SYM )THEN
+ JJ = J + ( J - 1 )*LDA
+ AA( JJ ) = DCMPLX( DBLE( AA( JJ ) ), RROGUE )
+ END IF
+ 130 CONTINUE
+ ELSE IF( TYPE.EQ.'HB'.OR.TYPE.EQ.'TB' )THEN
+ DO 170 J = 1, N
+ IF( UPPER )THEN
+ KK = KL + 1
+ IBEG = MAX( 1, KL + 2 - J )
+ IF( UNIT )THEN
+ IEND = KL
+ ELSE
+ IEND = KL + 1
+ END IF
+ ELSE
+ KK = 1
+ IF( UNIT )THEN
+ IBEG = 2
+ ELSE
+ IBEG = 1
+ END IF
+ IEND = MIN( KL + 1, 1 + M - J )
+ END IF
+ DO 140 I = 1, IBEG - 1
+ AA( I + ( J - 1 )*LDA ) = ROGUE
+ 140 CONTINUE
+ DO 150 I = IBEG, IEND
+ AA( I + ( J - 1 )*LDA ) = A( I + J - KK, J )
+ 150 CONTINUE
+ DO 160 I = IEND + 1, LDA
+ AA( I + ( J - 1 )*LDA ) = ROGUE
+ 160 CONTINUE
+ IF( SYM )THEN
+ JJ = KK + ( J - 1 )*LDA
+ AA( JJ ) = DCMPLX( DBLE( AA( JJ ) ), RROGUE )
+ END IF
+ 170 CONTINUE
+ ELSE IF( TYPE.EQ.'HP'.OR.TYPE.EQ.'TP' )THEN
+ IOFF = 0
+ DO 190 J = 1, N
+ IF( UPPER )THEN
+ IBEG = 1
+ IEND = J
+ ELSE
+ IBEG = J
+ IEND = N
+ END IF
+ DO 180 I = IBEG, IEND
+ IOFF = IOFF + 1
+ AA( IOFF ) = A( I, J )
+ IF( I.EQ.J )THEN
+ IF( UNIT )
+ $ AA( IOFF ) = ROGUE
+ IF( SYM )
+ $ AA( IOFF ) = DCMPLX( DBLE( AA( IOFF ) ), RROGUE )
+ END IF
+ 180 CONTINUE
+ 190 CONTINUE
+ END IF
+ RETURN
+*
+* End of ZMAKE.
+*
+ END
+ SUBROUTINE ZMVCH( TRANS, M, N, ALPHA, A, NMAX, X, INCX, BETA, Y,
+ $ INCY, YT, G, YY, EPS, ERR, FATAL, NOUT, MV )
+*
+* Checks the results of the computational tests.
+*
+* Auxiliary routine for test program for Level 2 Blas.
+*
+* -- Written on 10-August-1987.
+* Richard Hanson, Sandia National Labs.
+* Jeremy Du Croz, NAG Central Office.
+*
+* .. Parameters ..
+ COMPLEX*16 ZERO
+ PARAMETER ( ZERO = ( 0.0D0, 0.0D0 ) )
+ DOUBLE PRECISION RZERO, RONE
+ PARAMETER ( RZERO = 0.0D0, RONE = 1.0D0 )
+* .. Scalar Arguments ..
+ COMPLEX*16 ALPHA, BETA
+ DOUBLE PRECISION EPS, ERR
+ INTEGER INCX, INCY, M, N, NMAX, NOUT
+ LOGICAL FATAL, MV
+ CHARACTER*1 TRANS
+* .. Array Arguments ..
+ COMPLEX*16 A( NMAX, * ), X( * ), Y( * ), YT( * ), YY( * )
+ DOUBLE PRECISION G( * )
+* .. Local Scalars ..
+ COMPLEX*16 C
+ DOUBLE PRECISION ERRI
+ INTEGER I, INCXL, INCYL, IY, J, JX, KX, KY, ML, NL
+ LOGICAL CTRAN, TRAN
+* .. Intrinsic Functions ..
+ INTRINSIC ABS, DBLE, DCONJG, DIMAG, MAX, SQRT
+* .. Statement Functions ..
+ DOUBLE PRECISION ABS1
+* .. Statement Function definitions ..
+ ABS1( C ) = ABS( DBLE( C ) ) + ABS( DIMAG( C ) )
+* .. Executable Statements ..
+ TRAN = TRANS.EQ.'T'
+ CTRAN = TRANS.EQ.'C'
+ IF( TRAN.OR.CTRAN )THEN
+ ML = N
+ NL = M
+ ELSE
+ ML = M
+ NL = N
+ END IF
+ IF( INCX.LT.0 )THEN
+ KX = NL
+ INCXL = -1
+ ELSE
+ KX = 1
+ INCXL = 1
+ END IF
+ IF( INCY.LT.0 )THEN
+ KY = ML
+ INCYL = -1
+ ELSE
+ KY = 1
+ INCYL = 1
+ END IF
+*
+* Compute expected result in YT using data in A, X and Y.
+* Compute gauges in G.
+*
+ IY = KY
+ DO 40 I = 1, ML
+ YT( IY ) = ZERO
+ G( IY ) = RZERO
+ JX = KX
+ IF( TRAN )THEN
+ DO 10 J = 1, NL
+ YT( IY ) = YT( IY ) + A( J, I )*X( JX )
+ G( IY ) = G( IY ) + ABS1( A( J, I ) )*ABS1( X( JX ) )
+ JX = JX + INCXL
+ 10 CONTINUE
+ ELSE IF( CTRAN )THEN
+ DO 20 J = 1, NL
+ YT( IY ) = YT( IY ) + DCONJG( A( J, I ) )*X( JX )
+ G( IY ) = G( IY ) + ABS1( A( J, I ) )*ABS1( X( JX ) )
+ JX = JX + INCXL
+ 20 CONTINUE
+ ELSE
+ DO 30 J = 1, NL
+ YT( IY ) = YT( IY ) + A( I, J )*X( JX )
+ G( IY ) = G( IY ) + ABS1( A( I, J ) )*ABS1( X( JX ) )
+ JX = JX + INCXL
+ 30 CONTINUE
+ END IF
+ YT( IY ) = ALPHA*YT( IY ) + BETA*Y( IY )
+ G( IY ) = ABS1( ALPHA )*G( IY ) + ABS1( BETA )*ABS1( Y( IY ) )
+ IY = IY + INCYL
+ 40 CONTINUE
+*
+* Compute the error ratio for this result.
+*
+ ERR = ZERO
+ DO 50 I = 1, ML
+ ERRI = ABS( YT( I ) - YY( 1 + ( I - 1 )*ABS( INCY ) ) )/EPS
+ IF( G( I ).NE.RZERO )
+ $ ERRI = ERRI/G( I )
+ ERR = MAX( ERR, ERRI )
+ IF( ERR*SQRT( EPS ).GE.RONE )
+ $ GO TO 60
+ 50 CONTINUE
+* If the loop completes, all results are at least half accurate.
+ GO TO 80
+*
+* Report fatal error.
+*
+ 60 FATAL = .TRUE.
+ WRITE( NOUT, FMT = 9999 )
+ DO 70 I = 1, ML
+ IF( MV )THEN
+ WRITE( NOUT, FMT = 9998 )I, YT( I ),
+ $ YY( 1 + ( I - 1 )*ABS( INCY ) )
+ ELSE
+ WRITE( NOUT, FMT = 9998 )I,
+ $ YY( 1 + ( I - 1 )*ABS( INCY ) ), YT( I )
+ END IF
+ 70 CONTINUE
+*
+ 80 CONTINUE
+ RETURN
+*
+ 9999 FORMAT( ' ******* FATAL ERROR - COMPUTED RESULT IS LESS THAN HAL',
+ $ 'F ACCURATE *******', /' EXPECTED RE',
+ $ 'SULT COMPUTED RESULT' )
+ 9998 FORMAT( 1X, I7, 2( ' (', G15.6, ',', G15.6, ')' ) )
+*
+* End of ZMVCH.
+*
+ END
+ LOGICAL FUNCTION LZE( RI, RJ, LR )
+*
+* Tests if two arrays are identical.
+*
+* Auxiliary routine for test program for Level 2 Blas.
+*
+* -- Written on 10-August-1987.
+* Richard Hanson, Sandia National Labs.
+* Jeremy Du Croz, NAG Central Office.
+*
+* .. Scalar Arguments ..
+ INTEGER LR
+* .. Array Arguments ..
+ COMPLEX*16 RI( * ), RJ( * )
+* .. Local Scalars ..
+ INTEGER I
+* .. Executable Statements ..
+ DO 10 I = 1, LR
+ IF( RI( I ).NE.RJ( I ) )
+ $ GO TO 20
+ 10 CONTINUE
+ LZE = .TRUE.
+ GO TO 30
+ 20 CONTINUE
+ LZE = .FALSE.
+ 30 RETURN
+*
+* End of LZE.
+*
+ END
+ LOGICAL FUNCTION LZERES( TYPE, UPLO, M, N, AA, AS, LDA )
+*
+* Tests if selected elements in two arrays are equal.
+*
+* TYPE is 'GE', 'HE' or 'HP'.
+*
+* Auxiliary routine for test program for Level 2 Blas.
+*
+* -- Written on 10-August-1987.
+* Richard Hanson, Sandia National Labs.
+* Jeremy Du Croz, NAG Central Office.
+*
+* .. Scalar Arguments ..
+ INTEGER LDA, M, N
+ CHARACTER*1 UPLO
+ CHARACTER*2 TYPE
+* .. Array Arguments ..
+ COMPLEX*16 AA( LDA, * ), AS( LDA, * )
+* .. Local Scalars ..
+ INTEGER I, IBEG, IEND, J
+ LOGICAL UPPER
+* .. Executable Statements ..
+ UPPER = UPLO.EQ.'U'
+ IF( TYPE.EQ.'GE' )THEN
+ DO 20 J = 1, N
+ DO 10 I = M + 1, LDA
+ IF( AA( I, J ).NE.AS( I, J ) )
+ $ GO TO 70
+ 10 CONTINUE
+ 20 CONTINUE
+ ELSE IF( TYPE.EQ.'HE' )THEN
+ DO 50 J = 1, N
+ IF( UPPER )THEN
+ IBEG = 1
+ IEND = J
+ ELSE
+ IBEG = J
+ IEND = N
+ END IF
+ DO 30 I = 1, IBEG - 1
+ IF( AA( I, J ).NE.AS( I, J ) )
+ $ GO TO 70
+ 30 CONTINUE
+ DO 40 I = IEND + 1, LDA
+ IF( AA( I, J ).NE.AS( I, J ) )
+ $ GO TO 70
+ 40 CONTINUE
+ 50 CONTINUE
+ END IF
+*
+ 60 CONTINUE
+ LZERES = .TRUE.
+ GO TO 80
+ 70 CONTINUE
+ LZERES = .FALSE.
+ 80 RETURN
+*
+* End of LZERES.
+*
+ END
+ COMPLEX*16 FUNCTION ZBEG( RESET )
+*
+* Generates complex numbers as pairs of random numbers uniformly
+* distributed between -0.5 and 0.5.
+*
+* Auxiliary routine for test program for Level 2 Blas.
+*
+* -- Written on 10-August-1987.
+* Richard Hanson, Sandia National Labs.
+* Jeremy Du Croz, NAG Central Office.
+*
+* .. Scalar Arguments ..
+ LOGICAL RESET
+* .. Local Scalars ..
+ INTEGER I, IC, J, MI, MJ
+* .. Save statement ..
+ SAVE I, IC, J, MI, MJ
+* .. Intrinsic Functions ..
+ INTRINSIC DCMPLX
+* .. Executable Statements ..
+ IF( RESET )THEN
+* Initialize local variables.
+ MI = 891
+ MJ = 457
+ I = 7
+ J = 7
+ IC = 0
+ RESET = .FALSE.
+ END IF
+*
+* The sequence of values of I or J is bounded between 1 and 999.
+* If initial I or J = 1,2,3,6,7 or 9, the period will be 50.
+* If initial I or J = 4 or 8, the period will be 25.
+* If initial I or J = 5, the period will be 10.
+* IC is used to break up the period by skipping 1 value of I or J
+* in 6.
+*
+ IC = IC + 1
+ 10 I = I*MI
+ J = J*MJ
+ I = I - 1000*( I/1000 )
+ J = J - 1000*( J/1000 )
+ IF( IC.GE.5 )THEN
+ IC = 0
+ GO TO 10
+ END IF
+ ZBEG = DCMPLX( ( I - 500 )/1001.0D0, ( J - 500 )/1001.0D0 )
+ RETURN
+*
+* End of ZBEG.
+*
+ END
+ DOUBLE PRECISION FUNCTION DDIFF( X, Y )
+*
+* Auxiliary routine for test program for Level 2 Blas.
+*
+* -- Written on 10-August-1987.
+* Richard Hanson, Sandia National Labs.
+*
+* .. Scalar Arguments ..
+ DOUBLE PRECISION X, Y
+* .. Executable Statements ..
+ DDIFF = X - Y
+ RETURN
+*
+* End of DDIFF.
+*
+ END
+ SUBROUTINE CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+*
+* Tests whether XERBLA has detected an error when it should.
+*
+* Auxiliary routine for test program for Level 2 Blas.
+*
+* -- Written on 10-August-1987.
+* Richard Hanson, Sandia National Labs.
+* Jeremy Du Croz, NAG Central Office.
+*
+* .. Scalar Arguments ..
+ INTEGER INFOT, NOUT
+ LOGICAL LERR, OK
+ CHARACTER*6 SRNAMT
+* .. Executable Statements ..
+ IF( .NOT.LERR )THEN
+ WRITE( NOUT, FMT = 9999 )INFOT, SRNAMT
+ OK = .FALSE.
+ END IF
+ LERR = .FALSE.
+ RETURN
+*
+ 9999 FORMAT( ' ***** ILLEGAL VALUE OF PARAMETER NUMBER ', I2, ' NOT D',
+ $ 'ETECTED BY ', A6, ' *****' )
+*
+* End of CHKXER.
+*
+ END
+ SUBROUTINE XERBLA( SRNAME, INFO )
+*
+* This is a special version of XERBLA to be used only as part of
+* the test program for testing error exits from the Level 2 BLAS
+* routines.
+*
+* XERBLA is an error handler for the Level 2 BLAS routines.
+*
+* It is called by the Level 2 BLAS routines if an input parameter is
+* invalid.
+*
+* Auxiliary routine for test program for Level 2 Blas.
+*
+* -- Written on 10-August-1987.
+* Richard Hanson, Sandia National Labs.
+* Jeremy Du Croz, NAG Central Office.
+*
+* .. Scalar Arguments ..
+ INTEGER INFO
+ CHARACTER*6 SRNAME
+* .. Scalars in Common ..
+ INTEGER INFOT, NOUT
+ LOGICAL LERR, OK
+ CHARACTER*6 SRNAMT
+* .. Common blocks ..
+ COMMON /INFOC/INFOT, NOUT, OK, LERR
+ COMMON /SRNAMC/SRNAMT
+* .. Executable Statements ..
+ LERR = .TRUE.
+ IF( INFO.NE.INFOT )THEN
+ IF( INFOT.NE.0 )THEN
+ WRITE( NOUT, FMT = 9999 )INFO, INFOT
+ ELSE
+ WRITE( NOUT, FMT = 9997 )INFO
+ END IF
+ OK = .FALSE.
+ END IF
+ IF( SRNAME.NE.SRNAMT )THEN
+ WRITE( NOUT, FMT = 9998 )SRNAME, SRNAMT
+ OK = .FALSE.
+ END IF
+ RETURN
+*
+ 9999 FORMAT( ' ******* XERBLA WAS CALLED WITH INFO = ', I6, ' INSTEAD',
+ $ ' OF ', I2, ' *******' )
+ 9998 FORMAT( ' ******* XERBLA WAS CALLED WITH SRNAME = ', A6, ' INSTE',
+ $ 'AD OF ', A6, ' *******' )
+ 9997 FORMAT( ' ******* XERBLA WAS CALLED WITH INFO = ', I6,
+ $ ' *******' )
+*
+* End of XERBLA
+*
+ END
+
diff --git a/blas/testing/zblat3.dat b/blas/testing/zblat3.dat
new file mode 100644
index 000000000..ede516f4b
--- /dev/null
+++ b/blas/testing/zblat3.dat
@@ -0,0 +1,23 @@
+'zblat3.summ' NAME OF SUMMARY OUTPUT FILE
+6 UNIT NUMBER OF SUMMARY FILE
+'zblat3.snap' NAME OF SNAPSHOT OUTPUT FILE
+-1 UNIT NUMBER OF SNAPSHOT FILE (NOT USED IF .LT. 0)
+F LOGICAL FLAG, T TO REWIND SNAPSHOT FILE AFTER EACH RECORD.
+F LOGICAL FLAG, T TO STOP ON FAILURES.
+F LOGICAL FLAG, T TO TEST ERROR EXITS.
+16.0 THRESHOLD VALUE OF TEST RATIO
+6 NUMBER OF VALUES OF N
+0 1 2 3 5 9 VALUES OF N
+3 NUMBER OF VALUES OF ALPHA
+(0.0,0.0) (1.0,0.0) (0.7,-0.9) VALUES OF ALPHA
+3 NUMBER OF VALUES OF BETA
+(0.0,0.0) (1.0,0.0) (1.3,-1.1) VALUES OF BETA
+ZGEMM T PUT F FOR NO TEST. SAME COLUMNS.
+ZHEMM T PUT F FOR NO TEST. SAME COLUMNS.
+ZSYMM T PUT F FOR NO TEST. SAME COLUMNS.
+ZTRMM T PUT F FOR NO TEST. SAME COLUMNS.
+ZTRSM T PUT F FOR NO TEST. SAME COLUMNS.
+ZHERK T PUT F FOR NO TEST. SAME COLUMNS.
+ZSYRK T PUT F FOR NO TEST. SAME COLUMNS.
+ZHER2K T PUT F FOR NO TEST. SAME COLUMNS.
+ZSYR2K T PUT F FOR NO TEST. SAME COLUMNS.
diff --git a/blas/testing/zblat3.f b/blas/testing/zblat3.f
new file mode 100644
index 000000000..d6a522f2a
--- /dev/null
+++ b/blas/testing/zblat3.f
@@ -0,0 +1,3445 @@
+ PROGRAM ZBLAT3
+*
+* Test program for the COMPLEX*16 Level 3 Blas.
+*
+* The program must be driven by a short data file. The first 14 records
+* of the file are read using list-directed input, the last 9 records
+* are read using the format ( A6, L2 ). An annotated example of a data
+* file can be obtained by deleting the first 3 characters from the
+* following 23 lines:
+* 'ZBLAT3.SUMM' NAME OF SUMMARY OUTPUT FILE
+* 6 UNIT NUMBER OF SUMMARY FILE
+* 'ZBLAT3.SNAP' NAME OF SNAPSHOT OUTPUT FILE
+* -1 UNIT NUMBER OF SNAPSHOT FILE (NOT USED IF .LT. 0)
+* F LOGICAL FLAG, T TO REWIND SNAPSHOT FILE AFTER EACH RECORD.
+* F LOGICAL FLAG, T TO STOP ON FAILURES.
+* T LOGICAL FLAG, T TO TEST ERROR EXITS.
+* 16.0 THRESHOLD VALUE OF TEST RATIO
+* 6 NUMBER OF VALUES OF N
+* 0 1 2 3 5 9 VALUES OF N
+* 3 NUMBER OF VALUES OF ALPHA
+* (0.0,0.0) (1.0,0.0) (0.7,-0.9) VALUES OF ALPHA
+* 3 NUMBER OF VALUES OF BETA
+* (0.0,0.0) (1.0,0.0) (1.3,-1.1) VALUES OF BETA
+* ZGEMM T PUT F FOR NO TEST. SAME COLUMNS.
+* ZHEMM T PUT F FOR NO TEST. SAME COLUMNS.
+* ZSYMM T PUT F FOR NO TEST. SAME COLUMNS.
+* ZTRMM T PUT F FOR NO TEST. SAME COLUMNS.
+* ZTRSM T PUT F FOR NO TEST. SAME COLUMNS.
+* ZHERK T PUT F FOR NO TEST. SAME COLUMNS.
+* ZSYRK T PUT F FOR NO TEST. SAME COLUMNS.
+* ZHER2K T PUT F FOR NO TEST. SAME COLUMNS.
+* ZSYR2K T PUT F FOR NO TEST. SAME COLUMNS.
+*
+* See:
+*
+* Dongarra J. J., Du Croz J. J., Duff I. S. and Hammarling S.
+* A Set of Level 3 Basic Linear Algebra Subprograms.
+*
+* Technical Memorandum No.88 (Revision 1), Mathematics and
+* Computer Science Division, Argonne National Laboratory, 9700
+* South Cass Avenue, Argonne, Illinois 60439, US.
+*
+* -- Written on 8-February-1989.
+* Jack Dongarra, Argonne National Laboratory.
+* Iain Duff, AERE Harwell.
+* Jeremy Du Croz, Numerical Algorithms Group Ltd.
+* Sven Hammarling, Numerical Algorithms Group Ltd.
+*
+* .. Parameters ..
+ INTEGER NIN
+ PARAMETER ( NIN = 5 )
+ INTEGER NSUBS
+ PARAMETER ( NSUBS = 9 )
+ COMPLEX*16 ZERO, ONE
+ PARAMETER ( ZERO = ( 0.0D0, 0.0D0 ),
+ $ ONE = ( 1.0D0, 0.0D0 ) )
+ DOUBLE PRECISION RZERO, RHALF, RONE
+ PARAMETER ( RZERO = 0.0D0, RHALF = 0.5D0, RONE = 1.0D0 )
+ INTEGER NMAX
+ PARAMETER ( NMAX = 65 )
+ INTEGER NIDMAX, NALMAX, NBEMAX
+ PARAMETER ( NIDMAX = 9, NALMAX = 7, NBEMAX = 7 )
+* .. Local Scalars ..
+ DOUBLE PRECISION EPS, ERR, THRESH
+ INTEGER I, ISNUM, J, N, NALF, NBET, NIDIM, NOUT, NTRA
+ LOGICAL FATAL, LTESTT, REWI, SAME, SFATAL, TRACE,
+ $ TSTERR
+ CHARACTER*1 TRANSA, TRANSB
+ CHARACTER*6 SNAMET
+ CHARACTER*32 SNAPS, SUMMRY
+* .. Local Arrays ..
+ COMPLEX*16 AA( NMAX*NMAX ), AB( NMAX, 2*NMAX ),
+ $ ALF( NALMAX ), AS( NMAX*NMAX ),
+ $ BB( NMAX*NMAX ), BET( NBEMAX ),
+ $ BS( NMAX*NMAX ), C( NMAX, NMAX ),
+ $ CC( NMAX*NMAX ), CS( NMAX*NMAX ), CT( NMAX ),
+ $ W( 2*NMAX )
+ DOUBLE PRECISION G( NMAX )
+ INTEGER IDIM( NIDMAX )
+ LOGICAL LTEST( NSUBS )
+ CHARACTER*6 SNAMES( NSUBS )
+* .. External Functions ..
+ DOUBLE PRECISION DDIFF
+ LOGICAL LZE
+ EXTERNAL DDIFF, LZE
+* .. External Subroutines ..
+ EXTERNAL ZCHK1, ZCHK2, ZCHK3, ZCHK4, ZCHK5, ZCHKE, ZMMCH
+* .. Intrinsic Functions ..
+ INTRINSIC MAX, MIN
+* .. Scalars in Common ..
+ INTEGER INFOT, NOUTC
+ LOGICAL LERR, OK
+ CHARACTER*6 SRNAMT
+* .. Common blocks ..
+ COMMON /INFOC/INFOT, NOUTC, OK, LERR
+ COMMON /SRNAMC/SRNAMT
+* .. Data statements ..
+ DATA SNAMES/'ZGEMM ', 'ZHEMM ', 'ZSYMM ', 'ZTRMM ',
+ $ 'ZTRSM ', 'ZHERK ', 'ZSYRK ', 'ZHER2K',
+ $ 'ZSYR2K'/
+* .. Executable Statements ..
+*
+* Read name and unit number for summary output file and open file.
+*
+ READ( NIN, FMT = * )SUMMRY
+ READ( NIN, FMT = * )NOUT
+ OPEN( NOUT, FILE = SUMMRY, STATUS = 'NEW' )
+ NOUTC = NOUT
+*
+* Read name and unit number for snapshot output file and open file.
+*
+ READ( NIN, FMT = * )SNAPS
+ READ( NIN, FMT = * )NTRA
+ TRACE = NTRA.GE.0
+ IF( TRACE )THEN
+ OPEN( NTRA, FILE = SNAPS, STATUS = 'NEW' )
+ END IF
+* Read the flag that directs rewinding of the snapshot file.
+ READ( NIN, FMT = * )REWI
+ REWI = REWI.AND.TRACE
+* Read the flag that directs stopping on any failure.
+ READ( NIN, FMT = * )SFATAL
+* Read the flag that indicates whether error exits are to be tested.
+ READ( NIN, FMT = * )TSTERR
+* Read the threshold value of the test ratio
+ READ( NIN, FMT = * )THRESH
+*
+* Read and check the parameter values for the tests.
+*
+* Values of N
+ READ( NIN, FMT = * )NIDIM
+ IF( NIDIM.LT.1.OR.NIDIM.GT.NIDMAX )THEN
+ WRITE( NOUT, FMT = 9997 )'N', NIDMAX
+ GO TO 220
+ END IF
+ READ( NIN, FMT = * )( IDIM( I ), I = 1, NIDIM )
+ DO 10 I = 1, NIDIM
+ IF( IDIM( I ).LT.0.OR.IDIM( I ).GT.NMAX )THEN
+ WRITE( NOUT, FMT = 9996 )NMAX
+ GO TO 220
+ END IF
+ 10 CONTINUE
+* Values of ALPHA
+ READ( NIN, FMT = * )NALF
+ IF( NALF.LT.1.OR.NALF.GT.NALMAX )THEN
+ WRITE( NOUT, FMT = 9997 )'ALPHA', NALMAX
+ GO TO 220
+ END IF
+ READ( NIN, FMT = * )( ALF( I ), I = 1, NALF )
+* Values of BETA
+ READ( NIN, FMT = * )NBET
+ IF( NBET.LT.1.OR.NBET.GT.NBEMAX )THEN
+ WRITE( NOUT, FMT = 9997 )'BETA', NBEMAX
+ GO TO 220
+ END IF
+ READ( NIN, FMT = * )( BET( I ), I = 1, NBET )
+*
+* Report values of parameters.
+*
+ WRITE( NOUT, FMT = 9995 )
+ WRITE( NOUT, FMT = 9994 )( IDIM( I ), I = 1, NIDIM )
+ WRITE( NOUT, FMT = 9993 )( ALF( I ), I = 1, NALF )
+ WRITE( NOUT, FMT = 9992 )( BET( I ), I = 1, NBET )
+ IF( .NOT.TSTERR )THEN
+ WRITE( NOUT, FMT = * )
+ WRITE( NOUT, FMT = 9984 )
+ END IF
+ WRITE( NOUT, FMT = * )
+ WRITE( NOUT, FMT = 9999 )THRESH
+ WRITE( NOUT, FMT = * )
+*
+* Read names of subroutines and flags which indicate
+* whether they are to be tested.
+*
+ DO 20 I = 1, NSUBS
+ LTEST( I ) = .FALSE.
+ 20 CONTINUE
+ 30 READ( NIN, FMT = 9988, END = 60 )SNAMET, LTESTT
+ DO 40 I = 1, NSUBS
+ IF( SNAMET.EQ.SNAMES( I ) )
+ $ GO TO 50
+ 40 CONTINUE
+ WRITE( NOUT, FMT = 9990 )SNAMET
+ STOP
+ 50 LTEST( I ) = LTESTT
+ GO TO 30
+*
+ 60 CONTINUE
+ CLOSE ( NIN )
+*
+* Compute EPS (the machine precision).
+*
+ EPS = RONE
+ 70 CONTINUE
+ IF( DDIFF( RONE + EPS, RONE ).EQ.RZERO )
+ $ GO TO 80
+ EPS = RHALF*EPS
+ GO TO 70
+ 80 CONTINUE
+ EPS = EPS + EPS
+ WRITE( NOUT, FMT = 9998 )EPS
+*
+* Check the reliability of ZMMCH using exact data.
+*
+ N = MIN( 32, NMAX )
+ DO 100 J = 1, N
+ DO 90 I = 1, N
+ AB( I, J ) = MAX( I - J + 1, 0 )
+ 90 CONTINUE
+ AB( J, NMAX + 1 ) = J
+ AB( 1, NMAX + J ) = J
+ C( J, 1 ) = ZERO
+ 100 CONTINUE
+ DO 110 J = 1, N
+ CC( J ) = J*( ( J + 1 )*J )/2 - ( ( J + 1 )*J*( J - 1 ) )/3
+ 110 CONTINUE
+* CC holds the exact result. On exit from ZMMCH CT holds
+* the result computed by ZMMCH.
+ TRANSA = 'N'
+ TRANSB = 'N'
+ CALL ZMMCH( TRANSA, TRANSB, N, 1, N, ONE, AB, NMAX,
+ $ AB( 1, NMAX + 1 ), NMAX, ZERO, C, NMAX, CT, G, CC,
+ $ NMAX, EPS, ERR, FATAL, NOUT, .TRUE. )
+ SAME = LZE( CC, CT, N )
+ IF( .NOT.SAME.OR.ERR.NE.RZERO )THEN
+ WRITE( NOUT, FMT = 9989 )TRANSA, TRANSB, SAME, ERR
+ STOP
+ END IF
+ TRANSB = 'C'
+ CALL ZMMCH( TRANSA, TRANSB, N, 1, N, ONE, AB, NMAX,
+ $ AB( 1, NMAX + 1 ), NMAX, ZERO, C, NMAX, CT, G, CC,
+ $ NMAX, EPS, ERR, FATAL, NOUT, .TRUE. )
+ SAME = LZE( CC, CT, N )
+ IF( .NOT.SAME.OR.ERR.NE.RZERO )THEN
+ WRITE( NOUT, FMT = 9989 )TRANSA, TRANSB, SAME, ERR
+ STOP
+ END IF
+ DO 120 J = 1, N
+ AB( J, NMAX + 1 ) = N - J + 1
+ AB( 1, NMAX + J ) = N - J + 1
+ 120 CONTINUE
+ DO 130 J = 1, N
+ CC( N - J + 1 ) = J*( ( J + 1 )*J )/2 -
+ $ ( ( J + 1 )*J*( J - 1 ) )/3
+ 130 CONTINUE
+ TRANSA = 'C'
+ TRANSB = 'N'
+ CALL ZMMCH( TRANSA, TRANSB, N, 1, N, ONE, AB, NMAX,
+ $ AB( 1, NMAX + 1 ), NMAX, ZERO, C, NMAX, CT, G, CC,
+ $ NMAX, EPS, ERR, FATAL, NOUT, .TRUE. )
+ SAME = LZE( CC, CT, N )
+ IF( .NOT.SAME.OR.ERR.NE.RZERO )THEN
+ WRITE( NOUT, FMT = 9989 )TRANSA, TRANSB, SAME, ERR
+ STOP
+ END IF
+ TRANSB = 'C'
+ CALL ZMMCH( TRANSA, TRANSB, N, 1, N, ONE, AB, NMAX,
+ $ AB( 1, NMAX + 1 ), NMAX, ZERO, C, NMAX, CT, G, CC,
+ $ NMAX, EPS, ERR, FATAL, NOUT, .TRUE. )
+ SAME = LZE( CC, CT, N )
+ IF( .NOT.SAME.OR.ERR.NE.RZERO )THEN
+ WRITE( NOUT, FMT = 9989 )TRANSA, TRANSB, SAME, ERR
+ STOP
+ END IF
+*
+* Test each subroutine in turn.
+*
+ DO 200 ISNUM = 1, NSUBS
+ WRITE( NOUT, FMT = * )
+ IF( .NOT.LTEST( ISNUM ) )THEN
+* Subprogram is not to be tested.
+ WRITE( NOUT, FMT = 9987 )SNAMES( ISNUM )
+ ELSE
+ SRNAMT = SNAMES( ISNUM )
+* Test error exits.
+ IF( TSTERR )THEN
+ CALL ZCHKE( ISNUM, SNAMES( ISNUM ), NOUT )
+ WRITE( NOUT, FMT = * )
+ END IF
+* Test computations.
+ INFOT = 0
+ OK = .TRUE.
+ FATAL = .FALSE.
+ GO TO ( 140, 150, 150, 160, 160, 170, 170,
+ $ 180, 180 )ISNUM
+* Test ZGEMM, 01.
+ 140 CALL ZCHK1( SNAMES( ISNUM ), EPS, THRESH, NOUT, NTRA, TRACE,
+ $ REWI, FATAL, NIDIM, IDIM, NALF, ALF, NBET, BET,
+ $ NMAX, AB, AA, AS, AB( 1, NMAX + 1 ), BB, BS, C,
+ $ CC, CS, CT, G )
+ GO TO 190
+* Test ZHEMM, 02, ZSYMM, 03.
+ 150 CALL ZCHK2( SNAMES( ISNUM ), EPS, THRESH, NOUT, NTRA, TRACE,
+ $ REWI, FATAL, NIDIM, IDIM, NALF, ALF, NBET, BET,
+ $ NMAX, AB, AA, AS, AB( 1, NMAX + 1 ), BB, BS, C,
+ $ CC, CS, CT, G )
+ GO TO 190
+* Test ZTRMM, 04, ZTRSM, 05.
+ 160 CALL ZCHK3( SNAMES( ISNUM ), EPS, THRESH, NOUT, NTRA, TRACE,
+ $ REWI, FATAL, NIDIM, IDIM, NALF, ALF, NMAX, AB,
+ $ AA, AS, AB( 1, NMAX + 1 ), BB, BS, CT, G, C )
+ GO TO 190
+* Test ZHERK, 06, ZSYRK, 07.
+ 170 CALL ZCHK4( SNAMES( ISNUM ), EPS, THRESH, NOUT, NTRA, TRACE,
+ $ REWI, FATAL, NIDIM, IDIM, NALF, ALF, NBET, BET,
+ $ NMAX, AB, AA, AS, AB( 1, NMAX + 1 ), BB, BS, C,
+ $ CC, CS, CT, G )
+ GO TO 190
+* Test ZHER2K, 08, ZSYR2K, 09.
+ 180 CALL ZCHK5( SNAMES( ISNUM ), EPS, THRESH, NOUT, NTRA, TRACE,
+ $ REWI, FATAL, NIDIM, IDIM, NALF, ALF, NBET, BET,
+ $ NMAX, AB, AA, AS, BB, BS, C, CC, CS, CT, G, W )
+ GO TO 190
+*
+ 190 IF( FATAL.AND.SFATAL )
+ $ GO TO 210
+ END IF
+ 200 CONTINUE
+ WRITE( NOUT, FMT = 9986 )
+ GO TO 230
+*
+ 210 CONTINUE
+ WRITE( NOUT, FMT = 9985 )
+ GO TO 230
+*
+ 220 CONTINUE
+ WRITE( NOUT, FMT = 9991 )
+*
+ 230 CONTINUE
+ IF( TRACE )
+ $ CLOSE ( NTRA )
+ CLOSE ( NOUT )
+ STOP
+*
+ 9999 FORMAT( ' ROUTINES PASS COMPUTATIONAL TESTS IF TEST RATIO IS LES',
+ $ 'S THAN', F8.2 )
+ 9998 FORMAT( ' RELATIVE MACHINE PRECISION IS TAKEN TO BE', 1P, D9.1 )
+ 9997 FORMAT( ' NUMBER OF VALUES OF ', A, ' IS LESS THAN 1 OR GREATER ',
+ $ 'THAN ', I2 )
+ 9996 FORMAT( ' VALUE OF N IS LESS THAN 0 OR GREATER THAN ', I2 )
+ 9995 FORMAT( ' TESTS OF THE COMPLEX*16 LEVEL 3 BLAS', //' THE F',
+ $ 'OLLOWING PARAMETER VALUES WILL BE USED:' )
+ 9994 FORMAT( ' FOR N ', 9I6 )
+ 9993 FORMAT( ' FOR ALPHA ',
+ $ 7( '(', F4.1, ',', F4.1, ') ', : ) )
+ 9992 FORMAT( ' FOR BETA ',
+ $ 7( '(', F4.1, ',', F4.1, ') ', : ) )
+ 9991 FORMAT( ' AMEND DATA FILE OR INCREASE ARRAY SIZES IN PROGRAM',
+ $ /' ******* TESTS ABANDONED *******' )
+ 9990 FORMAT( ' SUBPROGRAM NAME ', A6, ' NOT RECOGNIZED', /' ******* T',
+ $ 'ESTS ABANDONED *******' )
+ 9989 FORMAT( ' ERROR IN ZMMCH - IN-LINE DOT PRODUCTS ARE BEING EVALU',
+ $ 'ATED WRONGLY.', /' ZMMCH WAS CALLED WITH TRANSA = ', A1,
+ $ ' AND TRANSB = ', A1, /' AND RETURNED SAME = ', L1, ' AND ',
+ $ 'ERR = ', F12.3, '.', /' THIS MAY BE DUE TO FAULTS IN THE ',
+ $ 'ARITHMETIC OR THE COMPILER.', /' ******* TESTS ABANDONED ',
+ $ '*******' )
+ 9988 FORMAT( A6, L2 )
+ 9987 FORMAT( 1X, A6, ' WAS NOT TESTED' )
+ 9986 FORMAT( /' END OF TESTS' )
+ 9985 FORMAT( /' ******* FATAL ERROR - TESTS ABANDONED *******' )
+ 9984 FORMAT( ' ERROR-EXITS WILL NOT BE TESTED' )
+*
+* End of ZBLAT3.
+*
+ END
+ SUBROUTINE ZCHK1( SNAME, EPS, THRESH, NOUT, NTRA, TRACE, REWI,
+ $ FATAL, NIDIM, IDIM, NALF, ALF, NBET, BET, NMAX,
+ $ A, AA, AS, B, BB, BS, C, CC, CS, CT, G )
+*
+* Tests ZGEMM.
+*
+* Auxiliary routine for test program for Level 3 Blas.
+*
+* -- Written on 8-February-1989.
+* Jack Dongarra, Argonne National Laboratory.
+* Iain Duff, AERE Harwell.
+* Jeremy Du Croz, Numerical Algorithms Group Ltd.
+* Sven Hammarling, Numerical Algorithms Group Ltd.
+*
+* .. Parameters ..
+ COMPLEX*16 ZERO
+ PARAMETER ( ZERO = ( 0.0D0, 0.0D0 ) )
+ DOUBLE PRECISION RZERO
+ PARAMETER ( RZERO = 0.0D0 )
+* .. Scalar Arguments ..
+ DOUBLE PRECISION EPS, THRESH
+ INTEGER NALF, NBET, NIDIM, NMAX, NOUT, NTRA
+ LOGICAL FATAL, REWI, TRACE
+ CHARACTER*6 SNAME
+* .. Array Arguments ..
+ COMPLEX*16 A( NMAX, NMAX ), AA( NMAX*NMAX ), ALF( NALF ),
+ $ AS( NMAX*NMAX ), B( NMAX, NMAX ),
+ $ BB( NMAX*NMAX ), BET( NBET ), BS( NMAX*NMAX ),
+ $ C( NMAX, NMAX ), CC( NMAX*NMAX ),
+ $ CS( NMAX*NMAX ), CT( NMAX )
+ DOUBLE PRECISION G( NMAX )
+ INTEGER IDIM( NIDIM )
+* .. Local Scalars ..
+ COMPLEX*16 ALPHA, ALS, BETA, BLS
+ DOUBLE PRECISION ERR, ERRMAX
+ INTEGER I, IA, IB, ICA, ICB, IK, IM, IN, K, KS, LAA,
+ $ LBB, LCC, LDA, LDAS, LDB, LDBS, LDC, LDCS, M,
+ $ MA, MB, MS, N, NA, NARGS, NB, NC, NS
+ LOGICAL NULL, RESET, SAME, TRANA, TRANB
+ CHARACTER*1 TRANAS, TRANBS, TRANSA, TRANSB
+ CHARACTER*3 ICH
+* .. Local Arrays ..
+ LOGICAL ISAME( 13 )
+* .. External Functions ..
+ LOGICAL LZE, LZERES
+ EXTERNAL LZE, LZERES
+* .. External Subroutines ..
+ EXTERNAL ZGEMM, ZMAKE, ZMMCH
+* .. Intrinsic Functions ..
+ INTRINSIC MAX
+* .. Scalars in Common ..
+ INTEGER INFOT, NOUTC
+ LOGICAL LERR, OK
+* .. Common blocks ..
+ COMMON /INFOC/INFOT, NOUTC, OK, LERR
+* .. Data statements ..
+ DATA ICH/'NTC'/
+* .. Executable Statements ..
+*
+ NARGS = 13
+ NC = 0
+ RESET = .TRUE.
+ ERRMAX = RZERO
+*
+ DO 110 IM = 1, NIDIM
+ M = IDIM( IM )
+*
+ DO 100 IN = 1, NIDIM
+ N = IDIM( IN )
+* Set LDC to 1 more than minimum value if room.
+ LDC = M
+ IF( LDC.LT.NMAX )
+ $ LDC = LDC + 1
+* Skip tests if not enough room.
+ IF( LDC.GT.NMAX )
+ $ GO TO 100
+ LCC = LDC*N
+ NULL = N.LE.0.OR.M.LE.0
+*
+ DO 90 IK = 1, NIDIM
+ K = IDIM( IK )
+*
+ DO 80 ICA = 1, 3
+ TRANSA = ICH( ICA: ICA )
+ TRANA = TRANSA.EQ.'T'.OR.TRANSA.EQ.'C'
+*
+ IF( TRANA )THEN
+ MA = K
+ NA = M
+ ELSE
+ MA = M
+ NA = K
+ END IF
+* Set LDA to 1 more than minimum value if room.
+ LDA = MA
+ IF( LDA.LT.NMAX )
+ $ LDA = LDA + 1
+* Skip tests if not enough room.
+ IF( LDA.GT.NMAX )
+ $ GO TO 80
+ LAA = LDA*NA
+*
+* Generate the matrix A.
+*
+ CALL ZMAKE( 'GE', ' ', ' ', MA, NA, A, NMAX, AA, LDA,
+ $ RESET, ZERO )
+*
+ DO 70 ICB = 1, 3
+ TRANSB = ICH( ICB: ICB )
+ TRANB = TRANSB.EQ.'T'.OR.TRANSB.EQ.'C'
+*
+ IF( TRANB )THEN
+ MB = N
+ NB = K
+ ELSE
+ MB = K
+ NB = N
+ END IF
+* Set LDB to 1 more than minimum value if room.
+ LDB = MB
+ IF( LDB.LT.NMAX )
+ $ LDB = LDB + 1
+* Skip tests if not enough room.
+ IF( LDB.GT.NMAX )
+ $ GO TO 70
+ LBB = LDB*NB
+*
+* Generate the matrix B.
+*
+ CALL ZMAKE( 'GE', ' ', ' ', MB, NB, B, NMAX, BB,
+ $ LDB, RESET, ZERO )
+*
+ DO 60 IA = 1, NALF
+ ALPHA = ALF( IA )
+*
+ DO 50 IB = 1, NBET
+ BETA = BET( IB )
+*
+* Generate the matrix C.
+*
+ CALL ZMAKE( 'GE', ' ', ' ', M, N, C, NMAX,
+ $ CC, LDC, RESET, ZERO )
+*
+ NC = NC + 1
+*
+* Save every datum before calling the
+* subroutine.
+*
+ TRANAS = TRANSA
+ TRANBS = TRANSB
+ MS = M
+ NS = N
+ KS = K
+ ALS = ALPHA
+ DO 10 I = 1, LAA
+ AS( I ) = AA( I )
+ 10 CONTINUE
+ LDAS = LDA
+ DO 20 I = 1, LBB
+ BS( I ) = BB( I )
+ 20 CONTINUE
+ LDBS = LDB
+ BLS = BETA
+ DO 30 I = 1, LCC
+ CS( I ) = CC( I )
+ 30 CONTINUE
+ LDCS = LDC
+*
+* Call the subroutine.
+*
+ IF( TRACE )
+ $ WRITE( NTRA, FMT = 9995 )NC, SNAME,
+ $ TRANSA, TRANSB, M, N, K, ALPHA, LDA, LDB,
+ $ BETA, LDC
+ IF( REWI )
+ $ REWIND NTRA
+ CALL ZGEMM( TRANSA, TRANSB, M, N, K, ALPHA,
+ $ AA, LDA, BB, LDB, BETA, CC, LDC )
+*
+* Check if error-exit was taken incorrectly.
+*
+ IF( .NOT.OK )THEN
+ WRITE( NOUT, FMT = 9994 )
+ FATAL = .TRUE.
+ GO TO 120
+ END IF
+*
+* See what data changed inside subroutines.
+*
+ ISAME( 1 ) = TRANSA.EQ.TRANAS
+ ISAME( 2 ) = TRANSB.EQ.TRANBS
+ ISAME( 3 ) = MS.EQ.M
+ ISAME( 4 ) = NS.EQ.N
+ ISAME( 5 ) = KS.EQ.K
+ ISAME( 6 ) = ALS.EQ.ALPHA
+ ISAME( 7 ) = LZE( AS, AA, LAA )
+ ISAME( 8 ) = LDAS.EQ.LDA
+ ISAME( 9 ) = LZE( BS, BB, LBB )
+ ISAME( 10 ) = LDBS.EQ.LDB
+ ISAME( 11 ) = BLS.EQ.BETA
+ IF( NULL )THEN
+ ISAME( 12 ) = LZE( CS, CC, LCC )
+ ELSE
+ ISAME( 12 ) = LZERES( 'GE', ' ', M, N, CS,
+ $ CC, LDC )
+ END IF
+ ISAME( 13 ) = LDCS.EQ.LDC
+*
+* If data was incorrectly changed, report
+* and return.
+*
+ SAME = .TRUE.
+ DO 40 I = 1, NARGS
+ SAME = SAME.AND.ISAME( I )
+ IF( .NOT.ISAME( I ) )
+ $ WRITE( NOUT, FMT = 9998 )I
+ 40 CONTINUE
+ IF( .NOT.SAME )THEN
+ FATAL = .TRUE.
+ GO TO 120
+ END IF
+*
+ IF( .NOT.NULL )THEN
+*
+* Check the result.
+*
+ CALL ZMMCH( TRANSA, TRANSB, M, N, K,
+ $ ALPHA, A, NMAX, B, NMAX, BETA,
+ $ C, NMAX, CT, G, CC, LDC, EPS,
+ $ ERR, FATAL, NOUT, .TRUE. )
+ ERRMAX = MAX( ERRMAX, ERR )
+* If got really bad answer, report and
+* return.
+ IF( FATAL )
+ $ GO TO 120
+ END IF
+*
+ 50 CONTINUE
+*
+ 60 CONTINUE
+*
+ 70 CONTINUE
+*
+ 80 CONTINUE
+*
+ 90 CONTINUE
+*
+ 100 CONTINUE
+*
+ 110 CONTINUE
+*
+* Report result.
+*
+ IF( ERRMAX.LT.THRESH )THEN
+ WRITE( NOUT, FMT = 9999 )SNAME, NC
+ ELSE
+ WRITE( NOUT, FMT = 9997 )SNAME, NC, ERRMAX
+ END IF
+ GO TO 130
+*
+ 120 CONTINUE
+ WRITE( NOUT, FMT = 9996 )SNAME
+ WRITE( NOUT, FMT = 9995 )NC, SNAME, TRANSA, TRANSB, M, N, K,
+ $ ALPHA, LDA, LDB, BETA, LDC
+*
+ 130 CONTINUE
+ RETURN
+*
+ 9999 FORMAT( ' ', A6, ' PASSED THE COMPUTATIONAL TESTS (', I6, ' CALL',
+ $ 'S)' )
+ 9998 FORMAT( ' ******* FATAL ERROR - PARAMETER NUMBER ', I2, ' WAS CH',
+ $ 'ANGED INCORRECTLY *******' )
+ 9997 FORMAT( ' ', A6, ' COMPLETED THE COMPUTATIONAL TESTS (', I6, ' C',
+ $ 'ALLS)', /' ******* BUT WITH MAXIMUM TEST RATIO', F8.2,
+ $ ' - SUSPECT *******' )
+ 9996 FORMAT( ' ******* ', A6, ' FAILED ON CALL NUMBER:' )
+ 9995 FORMAT( 1X, I6, ': ', A6, '(''', A1, ''',''', A1, ''',',
+ $ 3( I3, ',' ), '(', F4.1, ',', F4.1, '), A,', I3, ', B,', I3,
+ $ ',(', F4.1, ',', F4.1, '), C,', I3, ').' )
+ 9994 FORMAT( ' ******* FATAL ERROR - ERROR-EXIT TAKEN ON VALID CALL *',
+ $ '******' )
+*
+* End of ZCHK1.
+*
+ END
+ SUBROUTINE ZCHK2( SNAME, EPS, THRESH, NOUT, NTRA, TRACE, REWI,
+ $ FATAL, NIDIM, IDIM, NALF, ALF, NBET, BET, NMAX,
+ $ A, AA, AS, B, BB, BS, C, CC, CS, CT, G )
+*
+* Tests ZHEMM and ZSYMM.
+*
+* Auxiliary routine for test program for Level 3 Blas.
+*
+* -- Written on 8-February-1989.
+* Jack Dongarra, Argonne National Laboratory.
+* Iain Duff, AERE Harwell.
+* Jeremy Du Croz, Numerical Algorithms Group Ltd.
+* Sven Hammarling, Numerical Algorithms Group Ltd.
+*
+* .. Parameters ..
+ COMPLEX*16 ZERO
+ PARAMETER ( ZERO = ( 0.0D0, 0.0D0 ) )
+ DOUBLE PRECISION RZERO
+ PARAMETER ( RZERO = 0.0D0 )
+* .. Scalar Arguments ..
+ DOUBLE PRECISION EPS, THRESH
+ INTEGER NALF, NBET, NIDIM, NMAX, NOUT, NTRA
+ LOGICAL FATAL, REWI, TRACE
+ CHARACTER*6 SNAME
+* .. Array Arguments ..
+ COMPLEX*16 A( NMAX, NMAX ), AA( NMAX*NMAX ), ALF( NALF ),
+ $ AS( NMAX*NMAX ), B( NMAX, NMAX ),
+ $ BB( NMAX*NMAX ), BET( NBET ), BS( NMAX*NMAX ),
+ $ C( NMAX, NMAX ), CC( NMAX*NMAX ),
+ $ CS( NMAX*NMAX ), CT( NMAX )
+ DOUBLE PRECISION G( NMAX )
+ INTEGER IDIM( NIDIM )
+* .. Local Scalars ..
+ COMPLEX*16 ALPHA, ALS, BETA, BLS
+ DOUBLE PRECISION ERR, ERRMAX
+ INTEGER I, IA, IB, ICS, ICU, IM, IN, LAA, LBB, LCC,
+ $ LDA, LDAS, LDB, LDBS, LDC, LDCS, M, MS, N, NA,
+ $ NARGS, NC, NS
+ LOGICAL CONJ, LEFT, NULL, RESET, SAME
+ CHARACTER*1 SIDE, SIDES, UPLO, UPLOS
+ CHARACTER*2 ICHS, ICHU
+* .. Local Arrays ..
+ LOGICAL ISAME( 13 )
+* .. External Functions ..
+ LOGICAL LZE, LZERES
+ EXTERNAL LZE, LZERES
+* .. External Subroutines ..
+ EXTERNAL ZHEMM, ZMAKE, ZMMCH, ZSYMM
+* .. Intrinsic Functions ..
+ INTRINSIC MAX
+* .. Scalars in Common ..
+ INTEGER INFOT, NOUTC
+ LOGICAL LERR, OK
+* .. Common blocks ..
+ COMMON /INFOC/INFOT, NOUTC, OK, LERR
+* .. Data statements ..
+ DATA ICHS/'LR'/, ICHU/'UL'/
+* .. Executable Statements ..
+ CONJ = SNAME( 2: 3 ).EQ.'HE'
+*
+ NARGS = 12
+ NC = 0
+ RESET = .TRUE.
+ ERRMAX = RZERO
+*
+ DO 100 IM = 1, NIDIM
+ M = IDIM( IM )
+*
+ DO 90 IN = 1, NIDIM
+ N = IDIM( IN )
+* Set LDC to 1 more than minimum value if room.
+ LDC = M
+ IF( LDC.LT.NMAX )
+ $ LDC = LDC + 1
+* Skip tests if not enough room.
+ IF( LDC.GT.NMAX )
+ $ GO TO 90
+ LCC = LDC*N
+ NULL = N.LE.0.OR.M.LE.0
+* Set LDB to 1 more than minimum value if room.
+ LDB = M
+ IF( LDB.LT.NMAX )
+ $ LDB = LDB + 1
+* Skip tests if not enough room.
+ IF( LDB.GT.NMAX )
+ $ GO TO 90
+ LBB = LDB*N
+*
+* Generate the matrix B.
+*
+ CALL ZMAKE( 'GE', ' ', ' ', M, N, B, NMAX, BB, LDB, RESET,
+ $ ZERO )
+*
+ DO 80 ICS = 1, 2
+ SIDE = ICHS( ICS: ICS )
+ LEFT = SIDE.EQ.'L'
+*
+ IF( LEFT )THEN
+ NA = M
+ ELSE
+ NA = N
+ END IF
+* Set LDA to 1 more than minimum value if room.
+ LDA = NA
+ IF( LDA.LT.NMAX )
+ $ LDA = LDA + 1
+* Skip tests if not enough room.
+ IF( LDA.GT.NMAX )
+ $ GO TO 80
+ LAA = LDA*NA
+*
+ DO 70 ICU = 1, 2
+ UPLO = ICHU( ICU: ICU )
+*
+* Generate the hermitian or symmetric matrix A.
+*
+ CALL ZMAKE( SNAME( 2: 3 ), UPLO, ' ', NA, NA, A, NMAX,
+ $ AA, LDA, RESET, ZERO )
+*
+ DO 60 IA = 1, NALF
+ ALPHA = ALF( IA )
+*
+ DO 50 IB = 1, NBET
+ BETA = BET( IB )
+*
+* Generate the matrix C.
+*
+ CALL ZMAKE( 'GE', ' ', ' ', M, N, C, NMAX, CC,
+ $ LDC, RESET, ZERO )
+*
+ NC = NC + 1
+*
+* Save every datum before calling the
+* subroutine.
+*
+ SIDES = SIDE
+ UPLOS = UPLO
+ MS = M
+ NS = N
+ ALS = ALPHA
+ DO 10 I = 1, LAA
+ AS( I ) = AA( I )
+ 10 CONTINUE
+ LDAS = LDA
+ DO 20 I = 1, LBB
+ BS( I ) = BB( I )
+ 20 CONTINUE
+ LDBS = LDB
+ BLS = BETA
+ DO 30 I = 1, LCC
+ CS( I ) = CC( I )
+ 30 CONTINUE
+ LDCS = LDC
+*
+* Call the subroutine.
+*
+ IF( TRACE )
+ $ WRITE( NTRA, FMT = 9995 )NC, SNAME, SIDE,
+ $ UPLO, M, N, ALPHA, LDA, LDB, BETA, LDC
+ IF( REWI )
+ $ REWIND NTRA
+ IF( CONJ )THEN
+ CALL ZHEMM( SIDE, UPLO, M, N, ALPHA, AA, LDA,
+ $ BB, LDB, BETA, CC, LDC )
+ ELSE
+ CALL ZSYMM( SIDE, UPLO, M, N, ALPHA, AA, LDA,
+ $ BB, LDB, BETA, CC, LDC )
+ END IF
+*
+* Check if error-exit was taken incorrectly.
+*
+ IF( .NOT.OK )THEN
+ WRITE( NOUT, FMT = 9994 )
+ FATAL = .TRUE.
+ GO TO 110
+ END IF
+*
+* See what data changed inside subroutines.
+*
+ ISAME( 1 ) = SIDES.EQ.SIDE
+ ISAME( 2 ) = UPLOS.EQ.UPLO
+ ISAME( 3 ) = MS.EQ.M
+ ISAME( 4 ) = NS.EQ.N
+ ISAME( 5 ) = ALS.EQ.ALPHA
+ ISAME( 6 ) = LZE( AS, AA, LAA )
+ ISAME( 7 ) = LDAS.EQ.LDA
+ ISAME( 8 ) = LZE( BS, BB, LBB )
+ ISAME( 9 ) = LDBS.EQ.LDB
+ ISAME( 10 ) = BLS.EQ.BETA
+ IF( NULL )THEN
+ ISAME( 11 ) = LZE( CS, CC, LCC )
+ ELSE
+ ISAME( 11 ) = LZERES( 'GE', ' ', M, N, CS,
+ $ CC, LDC )
+ END IF
+ ISAME( 12 ) = LDCS.EQ.LDC
+*
+* If data was incorrectly changed, report and
+* return.
+*
+ SAME = .TRUE.
+ DO 40 I = 1, NARGS
+ SAME = SAME.AND.ISAME( I )
+ IF( .NOT.ISAME( I ) )
+ $ WRITE( NOUT, FMT = 9998 )I
+ 40 CONTINUE
+ IF( .NOT.SAME )THEN
+ FATAL = .TRUE.
+ GO TO 110
+ END IF
+*
+ IF( .NOT.NULL )THEN
+*
+* Check the result.
+*
+ IF( LEFT )THEN
+ CALL ZMMCH( 'N', 'N', M, N, M, ALPHA, A,
+ $ NMAX, B, NMAX, BETA, C, NMAX,
+ $ CT, G, CC, LDC, EPS, ERR,
+ $ FATAL, NOUT, .TRUE. )
+ ELSE
+ CALL ZMMCH( 'N', 'N', M, N, N, ALPHA, B,
+ $ NMAX, A, NMAX, BETA, C, NMAX,
+ $ CT, G, CC, LDC, EPS, ERR,
+ $ FATAL, NOUT, .TRUE. )
+ END IF
+ ERRMAX = MAX( ERRMAX, ERR )
+* If got really bad answer, report and
+* return.
+ IF( FATAL )
+ $ GO TO 110
+ END IF
+*
+ 50 CONTINUE
+*
+ 60 CONTINUE
+*
+ 70 CONTINUE
+*
+ 80 CONTINUE
+*
+ 90 CONTINUE
+*
+ 100 CONTINUE
+*
+* Report result.
+*
+ IF( ERRMAX.LT.THRESH )THEN
+ WRITE( NOUT, FMT = 9999 )SNAME, NC
+ ELSE
+ WRITE( NOUT, FMT = 9997 )SNAME, NC, ERRMAX
+ END IF
+ GO TO 120
+*
+ 110 CONTINUE
+ WRITE( NOUT, FMT = 9996 )SNAME
+ WRITE( NOUT, FMT = 9995 )NC, SNAME, SIDE, UPLO, M, N, ALPHA, LDA,
+ $ LDB, BETA, LDC
+*
+ 120 CONTINUE
+ RETURN
+*
+ 9999 FORMAT( ' ', A6, ' PASSED THE COMPUTATIONAL TESTS (', I6, ' CALL',
+ $ 'S)' )
+ 9998 FORMAT( ' ******* FATAL ERROR - PARAMETER NUMBER ', I2, ' WAS CH',
+ $ 'ANGED INCORRECTLY *******' )
+ 9997 FORMAT( ' ', A6, ' COMPLETED THE COMPUTATIONAL TESTS (', I6, ' C',
+ $ 'ALLS)', /' ******* BUT WITH MAXIMUM TEST RATIO', F8.2,
+ $ ' - SUSPECT *******' )
+ 9996 FORMAT( ' ******* ', A6, ' FAILED ON CALL NUMBER:' )
+ 9995 FORMAT( 1X, I6, ': ', A6, '(', 2( '''', A1, ''',' ), 2( I3, ',' ),
+ $ '(', F4.1, ',', F4.1, '), A,', I3, ', B,', I3, ',(', F4.1,
+ $ ',', F4.1, '), C,', I3, ') .' )
+ 9994 FORMAT( ' ******* FATAL ERROR - ERROR-EXIT TAKEN ON VALID CALL *',
+ $ '******' )
+*
+* End of ZCHK2.
+*
+ END
+ SUBROUTINE ZCHK3( SNAME, EPS, THRESH, NOUT, NTRA, TRACE, REWI,
+ $ FATAL, NIDIM, IDIM, NALF, ALF, NMAX, A, AA, AS,
+ $ B, BB, BS, CT, G, C )
+*
+* Tests ZTRMM and ZTRSM.
+*
+* Auxiliary routine for test program for Level 3 Blas.
+*
+* -- Written on 8-February-1989.
+* Jack Dongarra, Argonne National Laboratory.
+* Iain Duff, AERE Harwell.
+* Jeremy Du Croz, Numerical Algorithms Group Ltd.
+* Sven Hammarling, Numerical Algorithms Group Ltd.
+*
+* .. Parameters ..
+ COMPLEX*16 ZERO, ONE
+ PARAMETER ( ZERO = ( 0.0D0, 0.0D0 ),
+ $ ONE = ( 1.0D0, 0.0D0 ) )
+ DOUBLE PRECISION RZERO
+ PARAMETER ( RZERO = 0.0D0 )
+* .. Scalar Arguments ..
+ DOUBLE PRECISION EPS, THRESH
+ INTEGER NALF, NIDIM, NMAX, NOUT, NTRA
+ LOGICAL FATAL, REWI, TRACE
+ CHARACTER*6 SNAME
+* .. Array Arguments ..
+ COMPLEX*16 A( NMAX, NMAX ), AA( NMAX*NMAX ), ALF( NALF ),
+ $ AS( NMAX*NMAX ), B( NMAX, NMAX ),
+ $ BB( NMAX*NMAX ), BS( NMAX*NMAX ),
+ $ C( NMAX, NMAX ), CT( NMAX )
+ DOUBLE PRECISION G( NMAX )
+ INTEGER IDIM( NIDIM )
+* .. Local Scalars ..
+ COMPLEX*16 ALPHA, ALS
+ DOUBLE PRECISION ERR, ERRMAX
+ INTEGER I, IA, ICD, ICS, ICT, ICU, IM, IN, J, LAA, LBB,
+ $ LDA, LDAS, LDB, LDBS, M, MS, N, NA, NARGS, NC,
+ $ NS
+ LOGICAL LEFT, NULL, RESET, SAME
+ CHARACTER*1 DIAG, DIAGS, SIDE, SIDES, TRANAS, TRANSA, UPLO,
+ $ UPLOS
+ CHARACTER*2 ICHD, ICHS, ICHU
+ CHARACTER*3 ICHT
+* .. Local Arrays ..
+ LOGICAL ISAME( 13 )
+* .. External Functions ..
+ LOGICAL LZE, LZERES
+ EXTERNAL LZE, LZERES
+* .. External Subroutines ..
+ EXTERNAL ZMAKE, ZMMCH, ZTRMM, ZTRSM
+* .. Intrinsic Functions ..
+ INTRINSIC MAX
+* .. Scalars in Common ..
+ INTEGER INFOT, NOUTC
+ LOGICAL LERR, OK
+* .. Common blocks ..
+ COMMON /INFOC/INFOT, NOUTC, OK, LERR
+* .. Data statements ..
+ DATA ICHU/'UL'/, ICHT/'NTC'/, ICHD/'UN'/, ICHS/'LR'/
+* .. Executable Statements ..
+*
+ NARGS = 11
+ NC = 0
+ RESET = .TRUE.
+ ERRMAX = RZERO
+* Set up zero matrix for ZMMCH.
+ DO 20 J = 1, NMAX
+ DO 10 I = 1, NMAX
+ C( I, J ) = ZERO
+ 10 CONTINUE
+ 20 CONTINUE
+*
+ DO 140 IM = 1, NIDIM
+ M = IDIM( IM )
+*
+ DO 130 IN = 1, NIDIM
+ N = IDIM( IN )
+* Set LDB to 1 more than minimum value if room.
+ LDB = M
+ IF( LDB.LT.NMAX )
+ $ LDB = LDB + 1
+* Skip tests if not enough room.
+ IF( LDB.GT.NMAX )
+ $ GO TO 130
+ LBB = LDB*N
+ NULL = M.LE.0.OR.N.LE.0
+*
+ DO 120 ICS = 1, 2
+ SIDE = ICHS( ICS: ICS )
+ LEFT = SIDE.EQ.'L'
+ IF( LEFT )THEN
+ NA = M
+ ELSE
+ NA = N
+ END IF
+* Set LDA to 1 more than minimum value if room.
+ LDA = NA
+ IF( LDA.LT.NMAX )
+ $ LDA = LDA + 1
+* Skip tests if not enough room.
+ IF( LDA.GT.NMAX )
+ $ GO TO 130
+ LAA = LDA*NA
+*
+ DO 110 ICU = 1, 2
+ UPLO = ICHU( ICU: ICU )
+*
+ DO 100 ICT = 1, 3
+ TRANSA = ICHT( ICT: ICT )
+*
+ DO 90 ICD = 1, 2
+ DIAG = ICHD( ICD: ICD )
+*
+ DO 80 IA = 1, NALF
+ ALPHA = ALF( IA )
+*
+* Generate the matrix A.
+*
+ CALL ZMAKE( 'TR', UPLO, DIAG, NA, NA, A,
+ $ NMAX, AA, LDA, RESET, ZERO )
+*
+* Generate the matrix B.
+*
+ CALL ZMAKE( 'GE', ' ', ' ', M, N, B, NMAX,
+ $ BB, LDB, RESET, ZERO )
+*
+ NC = NC + 1
+*
+* Save every datum before calling the
+* subroutine.
+*
+ SIDES = SIDE
+ UPLOS = UPLO
+ TRANAS = TRANSA
+ DIAGS = DIAG
+ MS = M
+ NS = N
+ ALS = ALPHA
+ DO 30 I = 1, LAA
+ AS( I ) = AA( I )
+ 30 CONTINUE
+ LDAS = LDA
+ DO 40 I = 1, LBB
+ BS( I ) = BB( I )
+ 40 CONTINUE
+ LDBS = LDB
+*
+* Call the subroutine.
+*
+ IF( SNAME( 4: 5 ).EQ.'MM' )THEN
+ IF( TRACE )
+ $ WRITE( NTRA, FMT = 9995 )NC, SNAME,
+ $ SIDE, UPLO, TRANSA, DIAG, M, N, ALPHA,
+ $ LDA, LDB
+ IF( REWI )
+ $ REWIND NTRA
+ CALL ZTRMM( SIDE, UPLO, TRANSA, DIAG, M,
+ $ N, ALPHA, AA, LDA, BB, LDB )
+ ELSE IF( SNAME( 4: 5 ).EQ.'SM' )THEN
+ IF( TRACE )
+ $ WRITE( NTRA, FMT = 9995 )NC, SNAME,
+ $ SIDE, UPLO, TRANSA, DIAG, M, N, ALPHA,
+ $ LDA, LDB
+ IF( REWI )
+ $ REWIND NTRA
+ CALL ZTRSM( SIDE, UPLO, TRANSA, DIAG, M,
+ $ N, ALPHA, AA, LDA, BB, LDB )
+ END IF
+*
+* Check if error-exit was taken incorrectly.
+*
+ IF( .NOT.OK )THEN
+ WRITE( NOUT, FMT = 9994 )
+ FATAL = .TRUE.
+ GO TO 150
+ END IF
+*
+* See what data changed inside subroutines.
+*
+ ISAME( 1 ) = SIDES.EQ.SIDE
+ ISAME( 2 ) = UPLOS.EQ.UPLO
+ ISAME( 3 ) = TRANAS.EQ.TRANSA
+ ISAME( 4 ) = DIAGS.EQ.DIAG
+ ISAME( 5 ) = MS.EQ.M
+ ISAME( 6 ) = NS.EQ.N
+ ISAME( 7 ) = ALS.EQ.ALPHA
+ ISAME( 8 ) = LZE( AS, AA, LAA )
+ ISAME( 9 ) = LDAS.EQ.LDA
+ IF( NULL )THEN
+ ISAME( 10 ) = LZE( BS, BB, LBB )
+ ELSE
+ ISAME( 10 ) = LZERES( 'GE', ' ', M, N, BS,
+ $ BB, LDB )
+ END IF
+ ISAME( 11 ) = LDBS.EQ.LDB
+*
+* If data was incorrectly changed, report and
+* return.
+*
+ SAME = .TRUE.
+ DO 50 I = 1, NARGS
+ SAME = SAME.AND.ISAME( I )
+ IF( .NOT.ISAME( I ) )
+ $ WRITE( NOUT, FMT = 9998 )I
+ 50 CONTINUE
+ IF( .NOT.SAME )THEN
+ FATAL = .TRUE.
+ GO TO 150
+ END IF
+*
+ IF( .NOT.NULL )THEN
+ IF( SNAME( 4: 5 ).EQ.'MM' )THEN
+*
+* Check the result.
+*
+ IF( LEFT )THEN
+ CALL ZMMCH( TRANSA, 'N', M, N, M,
+ $ ALPHA, A, NMAX, B, NMAX,
+ $ ZERO, C, NMAX, CT, G,
+ $ BB, LDB, EPS, ERR,
+ $ FATAL, NOUT, .TRUE. )
+ ELSE
+ CALL ZMMCH( 'N', TRANSA, M, N, N,
+ $ ALPHA, B, NMAX, A, NMAX,
+ $ ZERO, C, NMAX, CT, G,
+ $ BB, LDB, EPS, ERR,
+ $ FATAL, NOUT, .TRUE. )
+ END IF
+ ELSE IF( SNAME( 4: 5 ).EQ.'SM' )THEN
+*
+* Compute approximation to original
+* matrix.
+*
+ DO 70 J = 1, N
+ DO 60 I = 1, M
+ C( I, J ) = BB( I + ( J - 1 )*
+ $ LDB )
+ BB( I + ( J - 1 )*LDB ) = ALPHA*
+ $ B( I, J )
+ 60 CONTINUE
+ 70 CONTINUE
+*
+ IF( LEFT )THEN
+ CALL ZMMCH( TRANSA, 'N', M, N, M,
+ $ ONE, A, NMAX, C, NMAX,
+ $ ZERO, B, NMAX, CT, G,
+ $ BB, LDB, EPS, ERR,
+ $ FATAL, NOUT, .FALSE. )
+ ELSE
+ CALL ZMMCH( 'N', TRANSA, M, N, N,
+ $ ONE, C, NMAX, A, NMAX,
+ $ ZERO, B, NMAX, CT, G,
+ $ BB, LDB, EPS, ERR,
+ $ FATAL, NOUT, .FALSE. )
+ END IF
+ END IF
+ ERRMAX = MAX( ERRMAX, ERR )
+* If got really bad answer, report and
+* return.
+ IF( FATAL )
+ $ GO TO 150
+ END IF
+*
+ 80 CONTINUE
+*
+ 90 CONTINUE
+*
+ 100 CONTINUE
+*
+ 110 CONTINUE
+*
+ 120 CONTINUE
+*
+ 130 CONTINUE
+*
+ 140 CONTINUE
+*
+* Report result.
+*
+ IF( ERRMAX.LT.THRESH )THEN
+ WRITE( NOUT, FMT = 9999 )SNAME, NC
+ ELSE
+ WRITE( NOUT, FMT = 9997 )SNAME, NC, ERRMAX
+ END IF
+ GO TO 160
+*
+ 150 CONTINUE
+ WRITE( NOUT, FMT = 9996 )SNAME
+ WRITE( NOUT, FMT = 9995 )NC, SNAME, SIDE, UPLO, TRANSA, DIAG, M,
+ $ N, ALPHA, LDA, LDB
+*
+ 160 CONTINUE
+ RETURN
+*
+ 9999 FORMAT( ' ', A6, ' PASSED THE COMPUTATIONAL TESTS (', I6, ' CALL',
+ $ 'S)' )
+ 9998 FORMAT( ' ******* FATAL ERROR - PARAMETER NUMBER ', I2, ' WAS CH',
+ $ 'ANGED INCORRECTLY *******' )
+ 9997 FORMAT( ' ', A6, ' COMPLETED THE COMPUTATIONAL TESTS (', I6, ' C',
+ $ 'ALLS)', /' ******* BUT WITH MAXIMUM TEST RATIO', F8.2,
+ $ ' - SUSPECT *******' )
+ 9996 FORMAT( ' ******* ', A6, ' FAILED ON CALL NUMBER:' )
+ 9995 FORMAT( 1X, I6, ': ', A6, '(', 4( '''', A1, ''',' ), 2( I3, ',' ),
+ $ '(', F4.1, ',', F4.1, '), A,', I3, ', B,', I3, ') ',
+ $ ' .' )
+ 9994 FORMAT( ' ******* FATAL ERROR - ERROR-EXIT TAKEN ON VALID CALL *',
+ $ '******' )
+*
+* End of ZCHK3.
+*
+ END
+ SUBROUTINE ZCHK4( SNAME, EPS, THRESH, NOUT, NTRA, TRACE, REWI,
+ $ FATAL, NIDIM, IDIM, NALF, ALF, NBET, BET, NMAX,
+ $ A, AA, AS, B, BB, BS, C, CC, CS, CT, G )
+*
+* Tests ZHERK and ZSYRK.
+*
+* Auxiliary routine for test program for Level 3 Blas.
+*
+* -- Written on 8-February-1989.
+* Jack Dongarra, Argonne National Laboratory.
+* Iain Duff, AERE Harwell.
+* Jeremy Du Croz, Numerical Algorithms Group Ltd.
+* Sven Hammarling, Numerical Algorithms Group Ltd.
+*
+* .. Parameters ..
+ COMPLEX*16 ZERO
+ PARAMETER ( ZERO = ( 0.0D0, 0.0D0 ) )
+ DOUBLE PRECISION RONE, RZERO
+ PARAMETER ( RONE = 1.0D0, RZERO = 0.0D0 )
+* .. Scalar Arguments ..
+ DOUBLE PRECISION EPS, THRESH
+ INTEGER NALF, NBET, NIDIM, NMAX, NOUT, NTRA
+ LOGICAL FATAL, REWI, TRACE
+ CHARACTER*6 SNAME
+* .. Array Arguments ..
+ COMPLEX*16 A( NMAX, NMAX ), AA( NMAX*NMAX ), ALF( NALF ),
+ $ AS( NMAX*NMAX ), B( NMAX, NMAX ),
+ $ BB( NMAX*NMAX ), BET( NBET ), BS( NMAX*NMAX ),
+ $ C( NMAX, NMAX ), CC( NMAX*NMAX ),
+ $ CS( NMAX*NMAX ), CT( NMAX )
+ DOUBLE PRECISION G( NMAX )
+ INTEGER IDIM( NIDIM )
+* .. Local Scalars ..
+ COMPLEX*16 ALPHA, ALS, BETA, BETS
+ DOUBLE PRECISION ERR, ERRMAX, RALPHA, RALS, RBETA, RBETS
+ INTEGER I, IA, IB, ICT, ICU, IK, IN, J, JC, JJ, K, KS,
+ $ LAA, LCC, LDA, LDAS, LDC, LDCS, LJ, MA, N, NA,
+ $ NARGS, NC, NS
+ LOGICAL CONJ, NULL, RESET, SAME, TRAN, UPPER
+ CHARACTER*1 TRANS, TRANSS, TRANST, UPLO, UPLOS
+ CHARACTER*2 ICHT, ICHU
+* .. Local Arrays ..
+ LOGICAL ISAME( 13 )
+* .. External Functions ..
+ LOGICAL LZE, LZERES
+ EXTERNAL LZE, LZERES
+* .. External Subroutines ..
+ EXTERNAL ZHERK, ZMAKE, ZMMCH, ZSYRK
+* .. Intrinsic Functions ..
+ INTRINSIC DCMPLX, MAX, DBLE
+* .. Scalars in Common ..
+ INTEGER INFOT, NOUTC
+ LOGICAL LERR, OK
+* .. Common blocks ..
+ COMMON /INFOC/INFOT, NOUTC, OK, LERR
+* .. Data statements ..
+ DATA ICHT/'NC'/, ICHU/'UL'/
+* .. Executable Statements ..
+ CONJ = SNAME( 2: 3 ).EQ.'HE'
+*
+ NARGS = 10
+ NC = 0
+ RESET = .TRUE.
+ ERRMAX = RZERO
+*
+ DO 100 IN = 1, NIDIM
+ N = IDIM( IN )
+* Set LDC to 1 more than minimum value if room.
+ LDC = N
+ IF( LDC.LT.NMAX )
+ $ LDC = LDC + 1
+* Skip tests if not enough room.
+ IF( LDC.GT.NMAX )
+ $ GO TO 100
+ LCC = LDC*N
+*
+ DO 90 IK = 1, NIDIM
+ K = IDIM( IK )
+*
+ DO 80 ICT = 1, 2
+ TRANS = ICHT( ICT: ICT )
+ TRAN = TRANS.EQ.'C'
+ IF( TRAN.AND..NOT.CONJ )
+ $ TRANS = 'T'
+ IF( TRAN )THEN
+ MA = K
+ NA = N
+ ELSE
+ MA = N
+ NA = K
+ END IF
+* Set LDA to 1 more than minimum value if room.
+ LDA = MA
+ IF( LDA.LT.NMAX )
+ $ LDA = LDA + 1
+* Skip tests if not enough room.
+ IF( LDA.GT.NMAX )
+ $ GO TO 80
+ LAA = LDA*NA
+*
+* Generate the matrix A.
+*
+ CALL ZMAKE( 'GE', ' ', ' ', MA, NA, A, NMAX, AA, LDA,
+ $ RESET, ZERO )
+*
+ DO 70 ICU = 1, 2
+ UPLO = ICHU( ICU: ICU )
+ UPPER = UPLO.EQ.'U'
+*
+ DO 60 IA = 1, NALF
+ ALPHA = ALF( IA )
+ IF( CONJ )THEN
+ RALPHA = DBLE( ALPHA )
+ ALPHA = DCMPLX( RALPHA, RZERO )
+ END IF
+*
+ DO 50 IB = 1, NBET
+ BETA = BET( IB )
+ IF( CONJ )THEN
+ RBETA = DBLE( BETA )
+ BETA = DCMPLX( RBETA, RZERO )
+ END IF
+ NULL = N.LE.0
+ IF( CONJ )
+ $ NULL = NULL.OR.( ( K.LE.0.OR.RALPHA.EQ.
+ $ RZERO ).AND.RBETA.EQ.RONE )
+*
+* Generate the matrix C.
+*
+ CALL ZMAKE( SNAME( 2: 3 ), UPLO, ' ', N, N, C,
+ $ NMAX, CC, LDC, RESET, ZERO )
+*
+ NC = NC + 1
+*
+* Save every datum before calling the subroutine.
+*
+ UPLOS = UPLO
+ TRANSS = TRANS
+ NS = N
+ KS = K
+ IF( CONJ )THEN
+ RALS = RALPHA
+ ELSE
+ ALS = ALPHA
+ END IF
+ DO 10 I = 1, LAA
+ AS( I ) = AA( I )
+ 10 CONTINUE
+ LDAS = LDA
+ IF( CONJ )THEN
+ RBETS = RBETA
+ ELSE
+ BETS = BETA
+ END IF
+ DO 20 I = 1, LCC
+ CS( I ) = CC( I )
+ 20 CONTINUE
+ LDCS = LDC
+*
+* Call the subroutine.
+*
+ IF( CONJ )THEN
+ IF( TRACE )
+ $ WRITE( NTRA, FMT = 9994 )NC, SNAME, UPLO,
+ $ TRANS, N, K, RALPHA, LDA, RBETA, LDC
+ IF( REWI )
+ $ REWIND NTRA
+ CALL ZHERK( UPLO, TRANS, N, K, RALPHA, AA,
+ $ LDA, RBETA, CC, LDC )
+ ELSE
+ IF( TRACE )
+ $ WRITE( NTRA, FMT = 9993 )NC, SNAME, UPLO,
+ $ TRANS, N, K, ALPHA, LDA, BETA, LDC
+ IF( REWI )
+ $ REWIND NTRA
+ CALL ZSYRK( UPLO, TRANS, N, K, ALPHA, AA,
+ $ LDA, BETA, CC, LDC )
+ END IF
+*
+* Check if error-exit was taken incorrectly.
+*
+ IF( .NOT.OK )THEN
+ WRITE( NOUT, FMT = 9992 )
+ FATAL = .TRUE.
+ GO TO 120
+ END IF
+*
+* See what data changed inside subroutines.
+*
+ ISAME( 1 ) = UPLOS.EQ.UPLO
+ ISAME( 2 ) = TRANSS.EQ.TRANS
+ ISAME( 3 ) = NS.EQ.N
+ ISAME( 4 ) = KS.EQ.K
+ IF( CONJ )THEN
+ ISAME( 5 ) = RALS.EQ.RALPHA
+ ELSE
+ ISAME( 5 ) = ALS.EQ.ALPHA
+ END IF
+ ISAME( 6 ) = LZE( AS, AA, LAA )
+ ISAME( 7 ) = LDAS.EQ.LDA
+ IF( CONJ )THEN
+ ISAME( 8 ) = RBETS.EQ.RBETA
+ ELSE
+ ISAME( 8 ) = BETS.EQ.BETA
+ END IF
+ IF( NULL )THEN
+ ISAME( 9 ) = LZE( CS, CC, LCC )
+ ELSE
+ ISAME( 9 ) = LZERES( SNAME( 2: 3 ), UPLO, N,
+ $ N, CS, CC, LDC )
+ END IF
+ ISAME( 10 ) = LDCS.EQ.LDC
+*
+* If data was incorrectly changed, report and
+* return.
+*
+ SAME = .TRUE.
+ DO 30 I = 1, NARGS
+ SAME = SAME.AND.ISAME( I )
+ IF( .NOT.ISAME( I ) )
+ $ WRITE( NOUT, FMT = 9998 )I
+ 30 CONTINUE
+ IF( .NOT.SAME )THEN
+ FATAL = .TRUE.
+ GO TO 120
+ END IF
+*
+ IF( .NOT.NULL )THEN
+*
+* Check the result column by column.
+*
+ IF( CONJ )THEN
+ TRANST = 'C'
+ ELSE
+ TRANST = 'T'
+ END IF
+ JC = 1
+ DO 40 J = 1, N
+ IF( UPPER )THEN
+ JJ = 1
+ LJ = J
+ ELSE
+ JJ = J
+ LJ = N - J + 1
+ END IF
+ IF( TRAN )THEN
+ CALL ZMMCH( TRANST, 'N', LJ, 1, K,
+ $ ALPHA, A( 1, JJ ), NMAX,
+ $ A( 1, J ), NMAX, BETA,
+ $ C( JJ, J ), NMAX, CT, G,
+ $ CC( JC ), LDC, EPS, ERR,
+ $ FATAL, NOUT, .TRUE. )
+ ELSE
+ CALL ZMMCH( 'N', TRANST, LJ, 1, K,
+ $ ALPHA, A( JJ, 1 ), NMAX,
+ $ A( J, 1 ), NMAX, BETA,
+ $ C( JJ, J ), NMAX, CT, G,
+ $ CC( JC ), LDC, EPS, ERR,
+ $ FATAL, NOUT, .TRUE. )
+ END IF
+ IF( UPPER )THEN
+ JC = JC + LDC
+ ELSE
+ JC = JC + LDC + 1
+ END IF
+ ERRMAX = MAX( ERRMAX, ERR )
+* If got really bad answer, report and
+* return.
+ IF( FATAL )
+ $ GO TO 110
+ 40 CONTINUE
+ END IF
+*
+ 50 CONTINUE
+*
+ 60 CONTINUE
+*
+ 70 CONTINUE
+*
+ 80 CONTINUE
+*
+ 90 CONTINUE
+*
+ 100 CONTINUE
+*
+* Report result.
+*
+ IF( ERRMAX.LT.THRESH )THEN
+ WRITE( NOUT, FMT = 9999 )SNAME, NC
+ ELSE
+ WRITE( NOUT, FMT = 9997 )SNAME, NC, ERRMAX
+ END IF
+ GO TO 130
+*
+ 110 CONTINUE
+ IF( N.GT.1 )
+ $ WRITE( NOUT, FMT = 9995 )J
+*
+ 120 CONTINUE
+ WRITE( NOUT, FMT = 9996 )SNAME
+ IF( CONJ )THEN
+ WRITE( NOUT, FMT = 9994 )NC, SNAME, UPLO, TRANS, N, K, RALPHA,
+ $ LDA, RBETA, LDC
+ ELSE
+ WRITE( NOUT, FMT = 9993 )NC, SNAME, UPLO, TRANS, N, K, ALPHA,
+ $ LDA, BETA, LDC
+ END IF
+*
+ 130 CONTINUE
+ RETURN
+*
+ 9999 FORMAT( ' ', A6, ' PASSED THE COMPUTATIONAL TESTS (', I6, ' CALL',
+ $ 'S)' )
+ 9998 FORMAT( ' ******* FATAL ERROR - PARAMETER NUMBER ', I2, ' WAS CH',
+ $ 'ANGED INCORRECTLY *******' )
+ 9997 FORMAT( ' ', A6, ' COMPLETED THE COMPUTATIONAL TESTS (', I6, ' C',
+ $ 'ALLS)', /' ******* BUT WITH MAXIMUM TEST RATIO', F8.2,
+ $ ' - SUSPECT *******' )
+ 9996 FORMAT( ' ******* ', A6, ' FAILED ON CALL NUMBER:' )
+ 9995 FORMAT( ' THESE ARE THE RESULTS FOR COLUMN ', I3 )
+ 9994 FORMAT( 1X, I6, ': ', A6, '(', 2( '''', A1, ''',' ), 2( I3, ',' ),
+ $ F4.1, ', A,', I3, ',', F4.1, ', C,', I3, ') ',
+ $ ' .' )
+ 9993 FORMAT( 1X, I6, ': ', A6, '(', 2( '''', A1, ''',' ), 2( I3, ',' ),
+ $ '(', F4.1, ',', F4.1, ') , A,', I3, ',(', F4.1, ',', F4.1,
+ $ '), C,', I3, ') .' )
+ 9992 FORMAT( ' ******* FATAL ERROR - ERROR-EXIT TAKEN ON VALID CALL *',
+ $ '******' )
+*
+* End of ZCHK4.
+*
+ END
+ SUBROUTINE ZCHK5( SNAME, EPS, THRESH, NOUT, NTRA, TRACE, REWI,
+ $ FATAL, NIDIM, IDIM, NALF, ALF, NBET, BET, NMAX,
+ $ AB, AA, AS, BB, BS, C, CC, CS, CT, G, W )
+*
+* Tests ZHER2K and ZSYR2K.
+*
+* Auxiliary routine for test program for Level 3 Blas.
+*
+* -- Written on 8-February-1989.
+* Jack Dongarra, Argonne National Laboratory.
+* Iain Duff, AERE Harwell.
+* Jeremy Du Croz, Numerical Algorithms Group Ltd.
+* Sven Hammarling, Numerical Algorithms Group Ltd.
+*
+* .. Parameters ..
+ COMPLEX*16 ZERO, ONE
+ PARAMETER ( ZERO = ( 0.0D0, 0.0D0 ),
+ $ ONE = ( 1.0D0, 0.0D0 ) )
+ DOUBLE PRECISION RONE, RZERO
+ PARAMETER ( RONE = 1.0D0, RZERO = 0.0D0 )
+* .. Scalar Arguments ..
+ DOUBLE PRECISION EPS, THRESH
+ INTEGER NALF, NBET, NIDIM, NMAX, NOUT, NTRA
+ LOGICAL FATAL, REWI, TRACE
+ CHARACTER*6 SNAME
+* .. Array Arguments ..
+ COMPLEX*16 AA( NMAX*NMAX ), AB( 2*NMAX*NMAX ),
+ $ ALF( NALF ), AS( NMAX*NMAX ), BB( NMAX*NMAX ),
+ $ BET( NBET ), BS( NMAX*NMAX ), C( NMAX, NMAX ),
+ $ CC( NMAX*NMAX ), CS( NMAX*NMAX ), CT( NMAX ),
+ $ W( 2*NMAX )
+ DOUBLE PRECISION G( NMAX )
+ INTEGER IDIM( NIDIM )
+* .. Local Scalars ..
+ COMPLEX*16 ALPHA, ALS, BETA, BETS
+ DOUBLE PRECISION ERR, ERRMAX, RBETA, RBETS
+ INTEGER I, IA, IB, ICT, ICU, IK, IN, J, JC, JJ, JJAB,
+ $ K, KS, LAA, LBB, LCC, LDA, LDAS, LDB, LDBS,
+ $ LDC, LDCS, LJ, MA, N, NA, NARGS, NC, NS
+ LOGICAL CONJ, NULL, RESET, SAME, TRAN, UPPER
+ CHARACTER*1 TRANS, TRANSS, TRANST, UPLO, UPLOS
+ CHARACTER*2 ICHT, ICHU
+* .. Local Arrays ..
+ LOGICAL ISAME( 13 )
+* .. External Functions ..
+ LOGICAL LZE, LZERES
+ EXTERNAL LZE, LZERES
+* .. External Subroutines ..
+ EXTERNAL ZHER2K, ZMAKE, ZMMCH, ZSYR2K
+* .. Intrinsic Functions ..
+ INTRINSIC DCMPLX, DCONJG, MAX, DBLE
+* .. Scalars in Common ..
+ INTEGER INFOT, NOUTC
+ LOGICAL LERR, OK
+* .. Common blocks ..
+ COMMON /INFOC/INFOT, NOUTC, OK, LERR
+* .. Data statements ..
+ DATA ICHT/'NC'/, ICHU/'UL'/
+* .. Executable Statements ..
+ CONJ = SNAME( 2: 3 ).EQ.'HE'
+*
+ NARGS = 12
+ NC = 0
+ RESET = .TRUE.
+ ERRMAX = RZERO
+*
+ DO 130 IN = 1, NIDIM
+ N = IDIM( IN )
+* Set LDC to 1 more than minimum value if room.
+ LDC = N
+ IF( LDC.LT.NMAX )
+ $ LDC = LDC + 1
+* Skip tests if not enough room.
+ IF( LDC.GT.NMAX )
+ $ GO TO 130
+ LCC = LDC*N
+*
+ DO 120 IK = 1, NIDIM
+ K = IDIM( IK )
+*
+ DO 110 ICT = 1, 2
+ TRANS = ICHT( ICT: ICT )
+ TRAN = TRANS.EQ.'C'
+ IF( TRAN.AND..NOT.CONJ )
+ $ TRANS = 'T'
+ IF( TRAN )THEN
+ MA = K
+ NA = N
+ ELSE
+ MA = N
+ NA = K
+ END IF
+* Set LDA to 1 more than minimum value if room.
+ LDA = MA
+ IF( LDA.LT.NMAX )
+ $ LDA = LDA + 1
+* Skip tests if not enough room.
+ IF( LDA.GT.NMAX )
+ $ GO TO 110
+ LAA = LDA*NA
+*
+* Generate the matrix A.
+*
+ IF( TRAN )THEN
+ CALL ZMAKE( 'GE', ' ', ' ', MA, NA, AB, 2*NMAX, AA,
+ $ LDA, RESET, ZERO )
+ ELSE
+ CALL ZMAKE( 'GE', ' ', ' ', MA, NA, AB, NMAX, AA, LDA,
+ $ RESET, ZERO )
+ END IF
+*
+* Generate the matrix B.
+*
+ LDB = LDA
+ LBB = LAA
+ IF( TRAN )THEN
+ CALL ZMAKE( 'GE', ' ', ' ', MA, NA, AB( K + 1 ),
+ $ 2*NMAX, BB, LDB, RESET, ZERO )
+ ELSE
+ CALL ZMAKE( 'GE', ' ', ' ', MA, NA, AB( K*NMAX + 1 ),
+ $ NMAX, BB, LDB, RESET, ZERO )
+ END IF
+*
+ DO 100 ICU = 1, 2
+ UPLO = ICHU( ICU: ICU )
+ UPPER = UPLO.EQ.'U'
+*
+ DO 90 IA = 1, NALF
+ ALPHA = ALF( IA )
+*
+ DO 80 IB = 1, NBET
+ BETA = BET( IB )
+ IF( CONJ )THEN
+ RBETA = DBLE( BETA )
+ BETA = DCMPLX( RBETA, RZERO )
+ END IF
+ NULL = N.LE.0
+ IF( CONJ )
+ $ NULL = NULL.OR.( ( K.LE.0.OR.ALPHA.EQ.
+ $ ZERO ).AND.RBETA.EQ.RONE )
+*
+* Generate the matrix C.
+*
+ CALL ZMAKE( SNAME( 2: 3 ), UPLO, ' ', N, N, C,
+ $ NMAX, CC, LDC, RESET, ZERO )
+*
+ NC = NC + 1
+*
+* Save every datum before calling the subroutine.
+*
+ UPLOS = UPLO
+ TRANSS = TRANS
+ NS = N
+ KS = K
+ ALS = ALPHA
+ DO 10 I = 1, LAA
+ AS( I ) = AA( I )
+ 10 CONTINUE
+ LDAS = LDA
+ DO 20 I = 1, LBB
+ BS( I ) = BB( I )
+ 20 CONTINUE
+ LDBS = LDB
+ IF( CONJ )THEN
+ RBETS = RBETA
+ ELSE
+ BETS = BETA
+ END IF
+ DO 30 I = 1, LCC
+ CS( I ) = CC( I )
+ 30 CONTINUE
+ LDCS = LDC
+*
+* Call the subroutine.
+*
+ IF( CONJ )THEN
+ IF( TRACE )
+ $ WRITE( NTRA, FMT = 9994 )NC, SNAME, UPLO,
+ $ TRANS, N, K, ALPHA, LDA, LDB, RBETA, LDC
+ IF( REWI )
+ $ REWIND NTRA
+ CALL ZHER2K( UPLO, TRANS, N, K, ALPHA, AA,
+ $ LDA, BB, LDB, RBETA, CC, LDC )
+ ELSE
+ IF( TRACE )
+ $ WRITE( NTRA, FMT = 9993 )NC, SNAME, UPLO,
+ $ TRANS, N, K, ALPHA, LDA, LDB, BETA, LDC
+ IF( REWI )
+ $ REWIND NTRA
+ CALL ZSYR2K( UPLO, TRANS, N, K, ALPHA, AA,
+ $ LDA, BB, LDB, BETA, CC, LDC )
+ END IF
+*
+* Check if error-exit was taken incorrectly.
+*
+ IF( .NOT.OK )THEN
+ WRITE( NOUT, FMT = 9992 )
+ FATAL = .TRUE.
+ GO TO 150
+ END IF
+*
+* See what data changed inside subroutines.
+*
+ ISAME( 1 ) = UPLOS.EQ.UPLO
+ ISAME( 2 ) = TRANSS.EQ.TRANS
+ ISAME( 3 ) = NS.EQ.N
+ ISAME( 4 ) = KS.EQ.K
+ ISAME( 5 ) = ALS.EQ.ALPHA
+ ISAME( 6 ) = LZE( AS, AA, LAA )
+ ISAME( 7 ) = LDAS.EQ.LDA
+ ISAME( 8 ) = LZE( BS, BB, LBB )
+ ISAME( 9 ) = LDBS.EQ.LDB
+ IF( CONJ )THEN
+ ISAME( 10 ) = RBETS.EQ.RBETA
+ ELSE
+ ISAME( 10 ) = BETS.EQ.BETA
+ END IF
+ IF( NULL )THEN
+ ISAME( 11 ) = LZE( CS, CC, LCC )
+ ELSE
+ ISAME( 11 ) = LZERES( 'HE', UPLO, N, N, CS,
+ $ CC, LDC )
+ END IF
+ ISAME( 12 ) = LDCS.EQ.LDC
+*
+* If data was incorrectly changed, report and
+* return.
+*
+ SAME = .TRUE.
+ DO 40 I = 1, NARGS
+ SAME = SAME.AND.ISAME( I )
+ IF( .NOT.ISAME( I ) )
+ $ WRITE( NOUT, FMT = 9998 )I
+ 40 CONTINUE
+ IF( .NOT.SAME )THEN
+ FATAL = .TRUE.
+ GO TO 150
+ END IF
+*
+ IF( .NOT.NULL )THEN
+*
+* Check the result column by column.
+*
+ IF( CONJ )THEN
+ TRANST = 'C'
+ ELSE
+ TRANST = 'T'
+ END IF
+ JJAB = 1
+ JC = 1
+ DO 70 J = 1, N
+ IF( UPPER )THEN
+ JJ = 1
+ LJ = J
+ ELSE
+ JJ = J
+ LJ = N - J + 1
+ END IF
+ IF( TRAN )THEN
+ DO 50 I = 1, K
+ W( I ) = ALPHA*AB( ( J - 1 )*2*
+ $ NMAX + K + I )
+ IF( CONJ )THEN
+ W( K + I ) = DCONJG( ALPHA )*
+ $ AB( ( J - 1 )*2*
+ $ NMAX + I )
+ ELSE
+ W( K + I ) = ALPHA*
+ $ AB( ( J - 1 )*2*
+ $ NMAX + I )
+ END IF
+ 50 CONTINUE
+ CALL ZMMCH( TRANST, 'N', LJ, 1, 2*K,
+ $ ONE, AB( JJAB ), 2*NMAX, W,
+ $ 2*NMAX, BETA, C( JJ, J ),
+ $ NMAX, CT, G, CC( JC ), LDC,
+ $ EPS, ERR, FATAL, NOUT,
+ $ .TRUE. )
+ ELSE
+ DO 60 I = 1, K
+ IF( CONJ )THEN
+ W( I ) = ALPHA*DCONJG( AB( ( K +
+ $ I - 1 )*NMAX + J ) )
+ W( K + I ) = DCONJG( ALPHA*
+ $ AB( ( I - 1 )*NMAX +
+ $ J ) )
+ ELSE
+ W( I ) = ALPHA*AB( ( K + I - 1 )*
+ $ NMAX + J )
+ W( K + I ) = ALPHA*
+ $ AB( ( I - 1 )*NMAX +
+ $ J )
+ END IF
+ 60 CONTINUE
+ CALL ZMMCH( 'N', 'N', LJ, 1, 2*K, ONE,
+ $ AB( JJ ), NMAX, W, 2*NMAX,
+ $ BETA, C( JJ, J ), NMAX, CT,
+ $ G, CC( JC ), LDC, EPS, ERR,
+ $ FATAL, NOUT, .TRUE. )
+ END IF
+ IF( UPPER )THEN
+ JC = JC + LDC
+ ELSE
+ JC = JC + LDC + 1
+ IF( TRAN )
+ $ JJAB = JJAB + 2*NMAX
+ END IF
+ ERRMAX = MAX( ERRMAX, ERR )
+* If got really bad answer, report and
+* return.
+ IF( FATAL )
+ $ GO TO 140
+ 70 CONTINUE
+ END IF
+*
+ 80 CONTINUE
+*
+ 90 CONTINUE
+*
+ 100 CONTINUE
+*
+ 110 CONTINUE
+*
+ 120 CONTINUE
+*
+ 130 CONTINUE
+*
+* Report result.
+*
+ IF( ERRMAX.LT.THRESH )THEN
+ WRITE( NOUT, FMT = 9999 )SNAME, NC
+ ELSE
+ WRITE( NOUT, FMT = 9997 )SNAME, NC, ERRMAX
+ END IF
+ GO TO 160
+*
+ 140 CONTINUE
+ IF( N.GT.1 )
+ $ WRITE( NOUT, FMT = 9995 )J
+*
+ 150 CONTINUE
+ WRITE( NOUT, FMT = 9996 )SNAME
+ IF( CONJ )THEN
+ WRITE( NOUT, FMT = 9994 )NC, SNAME, UPLO, TRANS, N, K, ALPHA,
+ $ LDA, LDB, RBETA, LDC
+ ELSE
+ WRITE( NOUT, FMT = 9993 )NC, SNAME, UPLO, TRANS, N, K, ALPHA,
+ $ LDA, LDB, BETA, LDC
+ END IF
+*
+ 160 CONTINUE
+ RETURN
+*
+ 9999 FORMAT( ' ', A6, ' PASSED THE COMPUTATIONAL TESTS (', I6, ' CALL',
+ $ 'S)' )
+ 9998 FORMAT( ' ******* FATAL ERROR - PARAMETER NUMBER ', I2, ' WAS CH',
+ $ 'ANGED INCORRECTLY *******' )
+ 9997 FORMAT( ' ', A6, ' COMPLETED THE COMPUTATIONAL TESTS (', I6, ' C',
+ $ 'ALLS)', /' ******* BUT WITH MAXIMUM TEST RATIO', F8.2,
+ $ ' - SUSPECT *******' )
+ 9996 FORMAT( ' ******* ', A6, ' FAILED ON CALL NUMBER:' )
+ 9995 FORMAT( ' THESE ARE THE RESULTS FOR COLUMN ', I3 )
+ 9994 FORMAT( 1X, I6, ': ', A6, '(', 2( '''', A1, ''',' ), 2( I3, ',' ),
+ $ '(', F4.1, ',', F4.1, '), A,', I3, ', B,', I3, ',', F4.1,
+ $ ', C,', I3, ') .' )
+ 9993 FORMAT( 1X, I6, ': ', A6, '(', 2( '''', A1, ''',' ), 2( I3, ',' ),
+ $ '(', F4.1, ',', F4.1, '), A,', I3, ', B,', I3, ',(', F4.1,
+ $ ',', F4.1, '), C,', I3, ') .' )
+ 9992 FORMAT( ' ******* FATAL ERROR - ERROR-EXIT TAKEN ON VALID CALL *',
+ $ '******' )
+*
+* End of ZCHK5.
+*
+ END
+ SUBROUTINE ZCHKE( ISNUM, SRNAMT, NOUT )
+*
+* Tests the error exits from the Level 3 Blas.
+* Requires a special version of the error-handling routine XERBLA.
+* ALPHA, RALPHA, BETA, RBETA, A, B and C should not need to be defined.
+*
+* Auxiliary routine for test program for Level 3 Blas.
+*
+* -- Written on 8-February-1989.
+* Jack Dongarra, Argonne National Laboratory.
+* Iain Duff, AERE Harwell.
+* Jeremy Du Croz, Numerical Algorithms Group Ltd.
+* Sven Hammarling, Numerical Algorithms Group Ltd.
+*
+* .. Scalar Arguments ..
+ INTEGER ISNUM, NOUT
+ CHARACTER*6 SRNAMT
+* .. Scalars in Common ..
+ INTEGER INFOT, NOUTC
+ LOGICAL LERR, OK
+* .. Local Scalars ..
+ COMPLEX*16 ALPHA, BETA
+ DOUBLE PRECISION RALPHA, RBETA
+* .. Local Arrays ..
+ COMPLEX*16 A( 2, 1 ), B( 2, 1 ), C( 2, 1 )
+* .. External Subroutines ..
+ EXTERNAL ZGEMM, ZHEMM, ZHER2K, ZHERK, CHKXER, ZSYMM,
+ $ ZSYR2K, ZSYRK, ZTRMM, ZTRSM
+* .. Common blocks ..
+ COMMON /INFOC/INFOT, NOUTC, OK, LERR
+* .. Executable Statements ..
+* OK is set to .FALSE. by the special version of XERBLA or by CHKXER
+* if anything is wrong.
+ OK = .TRUE.
+* LERR is set to .TRUE. by the special version of XERBLA each time
+* it is called, and is then tested and re-set by CHKXER.
+ LERR = .FALSE.
+ GO TO ( 10, 20, 30, 40, 50, 60, 70, 80,
+ $ 90 )ISNUM
+ 10 INFOT = 1
+ CALL ZGEMM( '/', 'N', 0, 0, 0, ALPHA, A, 1, B, 1, BETA, C, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 1
+ CALL ZGEMM( '/', 'C', 0, 0, 0, ALPHA, A, 1, B, 1, BETA, C, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 1
+ CALL ZGEMM( '/', 'T', 0, 0, 0, ALPHA, A, 1, B, 1, BETA, C, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 2
+ CALL ZGEMM( 'N', '/', 0, 0, 0, ALPHA, A, 1, B, 1, BETA, C, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 2
+ CALL ZGEMM( 'C', '/', 0, 0, 0, ALPHA, A, 1, B, 1, BETA, C, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 2
+ CALL ZGEMM( 'T', '/', 0, 0, 0, ALPHA, A, 1, B, 1, BETA, C, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 3
+ CALL ZGEMM( 'N', 'N', -1, 0, 0, ALPHA, A, 1, B, 1, BETA, C, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 3
+ CALL ZGEMM( 'N', 'C', -1, 0, 0, ALPHA, A, 1, B, 1, BETA, C, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 3
+ CALL ZGEMM( 'N', 'T', -1, 0, 0, ALPHA, A, 1, B, 1, BETA, C, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 3
+ CALL ZGEMM( 'C', 'N', -1, 0, 0, ALPHA, A, 1, B, 1, BETA, C, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 3
+ CALL ZGEMM( 'C', 'C', -1, 0, 0, ALPHA, A, 1, B, 1, BETA, C, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 3
+ CALL ZGEMM( 'C', 'T', -1, 0, 0, ALPHA, A, 1, B, 1, BETA, C, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 3
+ CALL ZGEMM( 'T', 'N', -1, 0, 0, ALPHA, A, 1, B, 1, BETA, C, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 3
+ CALL ZGEMM( 'T', 'C', -1, 0, 0, ALPHA, A, 1, B, 1, BETA, C, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 3
+ CALL ZGEMM( 'T', 'T', -1, 0, 0, ALPHA, A, 1, B, 1, BETA, C, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 4
+ CALL ZGEMM( 'N', 'N', 0, -1, 0, ALPHA, A, 1, B, 1, BETA, C, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 4
+ CALL ZGEMM( 'N', 'C', 0, -1, 0, ALPHA, A, 1, B, 1, BETA, C, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 4
+ CALL ZGEMM( 'N', 'T', 0, -1, 0, ALPHA, A, 1, B, 1, BETA, C, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 4
+ CALL ZGEMM( 'C', 'N', 0, -1, 0, ALPHA, A, 1, B, 1, BETA, C, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 4
+ CALL ZGEMM( 'C', 'C', 0, -1, 0, ALPHA, A, 1, B, 1, BETA, C, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 4
+ CALL ZGEMM( 'C', 'T', 0, -1, 0, ALPHA, A, 1, B, 1, BETA, C, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 4
+ CALL ZGEMM( 'T', 'N', 0, -1, 0, ALPHA, A, 1, B, 1, BETA, C, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 4
+ CALL ZGEMM( 'T', 'C', 0, -1, 0, ALPHA, A, 1, B, 1, BETA, C, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 4
+ CALL ZGEMM( 'T', 'T', 0, -1, 0, ALPHA, A, 1, B, 1, BETA, C, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 5
+ CALL ZGEMM( 'N', 'N', 0, 0, -1, ALPHA, A, 1, B, 1, BETA, C, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 5
+ CALL ZGEMM( 'N', 'C', 0, 0, -1, ALPHA, A, 1, B, 1, BETA, C, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 5
+ CALL ZGEMM( 'N', 'T', 0, 0, -1, ALPHA, A, 1, B, 1, BETA, C, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 5
+ CALL ZGEMM( 'C', 'N', 0, 0, -1, ALPHA, A, 1, B, 1, BETA, C, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 5
+ CALL ZGEMM( 'C', 'C', 0, 0, -1, ALPHA, A, 1, B, 1, BETA, C, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 5
+ CALL ZGEMM( 'C', 'T', 0, 0, -1, ALPHA, A, 1, B, 1, BETA, C, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 5
+ CALL ZGEMM( 'T', 'N', 0, 0, -1, ALPHA, A, 1, B, 1, BETA, C, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 5
+ CALL ZGEMM( 'T', 'C', 0, 0, -1, ALPHA, A, 1, B, 1, BETA, C, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 5
+ CALL ZGEMM( 'T', 'T', 0, 0, -1, ALPHA, A, 1, B, 1, BETA, C, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 8
+ CALL ZGEMM( 'N', 'N', 2, 0, 0, ALPHA, A, 1, B, 1, BETA, C, 2 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 8
+ CALL ZGEMM( 'N', 'C', 2, 0, 0, ALPHA, A, 1, B, 1, BETA, C, 2 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 8
+ CALL ZGEMM( 'N', 'T', 2, 0, 0, ALPHA, A, 1, B, 1, BETA, C, 2 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 8
+ CALL ZGEMM( 'C', 'N', 0, 0, 2, ALPHA, A, 1, B, 2, BETA, C, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 8
+ CALL ZGEMM( 'C', 'C', 0, 0, 2, ALPHA, A, 1, B, 1, BETA, C, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 8
+ CALL ZGEMM( 'C', 'T', 0, 0, 2, ALPHA, A, 1, B, 1, BETA, C, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 8
+ CALL ZGEMM( 'T', 'N', 0, 0, 2, ALPHA, A, 1, B, 2, BETA, C, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 8
+ CALL ZGEMM( 'T', 'C', 0, 0, 2, ALPHA, A, 1, B, 1, BETA, C, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 8
+ CALL ZGEMM( 'T', 'T', 0, 0, 2, ALPHA, A, 1, B, 1, BETA, C, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 10
+ CALL ZGEMM( 'N', 'N', 0, 0, 2, ALPHA, A, 1, B, 1, BETA, C, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 10
+ CALL ZGEMM( 'C', 'N', 0, 0, 2, ALPHA, A, 2, B, 1, BETA, C, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 10
+ CALL ZGEMM( 'T', 'N', 0, 0, 2, ALPHA, A, 2, B, 1, BETA, C, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 10
+ CALL ZGEMM( 'N', 'C', 0, 2, 0, ALPHA, A, 1, B, 1, BETA, C, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 10
+ CALL ZGEMM( 'C', 'C', 0, 2, 0, ALPHA, A, 1, B, 1, BETA, C, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 10
+ CALL ZGEMM( 'T', 'C', 0, 2, 0, ALPHA, A, 1, B, 1, BETA, C, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 10
+ CALL ZGEMM( 'N', 'T', 0, 2, 0, ALPHA, A, 1, B, 1, BETA, C, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 10
+ CALL ZGEMM( 'C', 'T', 0, 2, 0, ALPHA, A, 1, B, 1, BETA, C, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 10
+ CALL ZGEMM( 'T', 'T', 0, 2, 0, ALPHA, A, 1, B, 1, BETA, C, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 13
+ CALL ZGEMM( 'N', 'N', 2, 0, 0, ALPHA, A, 2, B, 1, BETA, C, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 13
+ CALL ZGEMM( 'N', 'C', 2, 0, 0, ALPHA, A, 2, B, 1, BETA, C, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 13
+ CALL ZGEMM( 'N', 'T', 2, 0, 0, ALPHA, A, 2, B, 1, BETA, C, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 13
+ CALL ZGEMM( 'C', 'N', 2, 0, 0, ALPHA, A, 1, B, 1, BETA, C, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 13
+ CALL ZGEMM( 'C', 'C', 2, 0, 0, ALPHA, A, 1, B, 1, BETA, C, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 13
+ CALL ZGEMM( 'C', 'T', 2, 0, 0, ALPHA, A, 1, B, 1, BETA, C, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 13
+ CALL ZGEMM( 'T', 'N', 2, 0, 0, ALPHA, A, 1, B, 1, BETA, C, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 13
+ CALL ZGEMM( 'T', 'C', 2, 0, 0, ALPHA, A, 1, B, 1, BETA, C, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 13
+ CALL ZGEMM( 'T', 'T', 2, 0, 0, ALPHA, A, 1, B, 1, BETA, C, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ GO TO 100
+ 20 INFOT = 1
+ CALL ZHEMM( '/', 'U', 0, 0, ALPHA, A, 1, B, 1, BETA, C, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 2
+ CALL ZHEMM( 'L', '/', 0, 0, ALPHA, A, 1, B, 1, BETA, C, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 3
+ CALL ZHEMM( 'L', 'U', -1, 0, ALPHA, A, 1, B, 1, BETA, C, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 3
+ CALL ZHEMM( 'R', 'U', -1, 0, ALPHA, A, 1, B, 1, BETA, C, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 3
+ CALL ZHEMM( 'L', 'L', -1, 0, ALPHA, A, 1, B, 1, BETA, C, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 3
+ CALL ZHEMM( 'R', 'L', -1, 0, ALPHA, A, 1, B, 1, BETA, C, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 4
+ CALL ZHEMM( 'L', 'U', 0, -1, ALPHA, A, 1, B, 1, BETA, C, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 4
+ CALL ZHEMM( 'R', 'U', 0, -1, ALPHA, A, 1, B, 1, BETA, C, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 4
+ CALL ZHEMM( 'L', 'L', 0, -1, ALPHA, A, 1, B, 1, BETA, C, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 4
+ CALL ZHEMM( 'R', 'L', 0, -1, ALPHA, A, 1, B, 1, BETA, C, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 7
+ CALL ZHEMM( 'L', 'U', 2, 0, ALPHA, A, 1, B, 2, BETA, C, 2 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 7
+ CALL ZHEMM( 'R', 'U', 0, 2, ALPHA, A, 1, B, 1, BETA, C, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 7
+ CALL ZHEMM( 'L', 'L', 2, 0, ALPHA, A, 1, B, 2, BETA, C, 2 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 7
+ CALL ZHEMM( 'R', 'L', 0, 2, ALPHA, A, 1, B, 1, BETA, C, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 9
+ CALL ZHEMM( 'L', 'U', 2, 0, ALPHA, A, 2, B, 1, BETA, C, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 9
+ CALL ZHEMM( 'R', 'U', 2, 0, ALPHA, A, 1, B, 1, BETA, C, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 9
+ CALL ZHEMM( 'L', 'L', 2, 0, ALPHA, A, 2, B, 1, BETA, C, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 9
+ CALL ZHEMM( 'R', 'L', 2, 0, ALPHA, A, 1, B, 1, BETA, C, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 12
+ CALL ZHEMM( 'L', 'U', 2, 0, ALPHA, A, 2, B, 2, BETA, C, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 12
+ CALL ZHEMM( 'R', 'U', 2, 0, ALPHA, A, 1, B, 2, BETA, C, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 12
+ CALL ZHEMM( 'L', 'L', 2, 0, ALPHA, A, 2, B, 2, BETA, C, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 12
+ CALL ZHEMM( 'R', 'L', 2, 0, ALPHA, A, 1, B, 2, BETA, C, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ GO TO 100
+ 30 INFOT = 1
+ CALL ZSYMM( '/', 'U', 0, 0, ALPHA, A, 1, B, 1, BETA, C, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 2
+ CALL ZSYMM( 'L', '/', 0, 0, ALPHA, A, 1, B, 1, BETA, C, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 3
+ CALL ZSYMM( 'L', 'U', -1, 0, ALPHA, A, 1, B, 1, BETA, C, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 3
+ CALL ZSYMM( 'R', 'U', -1, 0, ALPHA, A, 1, B, 1, BETA, C, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 3
+ CALL ZSYMM( 'L', 'L', -1, 0, ALPHA, A, 1, B, 1, BETA, C, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 3
+ CALL ZSYMM( 'R', 'L', -1, 0, ALPHA, A, 1, B, 1, BETA, C, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 4
+ CALL ZSYMM( 'L', 'U', 0, -1, ALPHA, A, 1, B, 1, BETA, C, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 4
+ CALL ZSYMM( 'R', 'U', 0, -1, ALPHA, A, 1, B, 1, BETA, C, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 4
+ CALL ZSYMM( 'L', 'L', 0, -1, ALPHA, A, 1, B, 1, BETA, C, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 4
+ CALL ZSYMM( 'R', 'L', 0, -1, ALPHA, A, 1, B, 1, BETA, C, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 7
+ CALL ZSYMM( 'L', 'U', 2, 0, ALPHA, A, 1, B, 2, BETA, C, 2 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 7
+ CALL ZSYMM( 'R', 'U', 0, 2, ALPHA, A, 1, B, 1, BETA, C, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 7
+ CALL ZSYMM( 'L', 'L', 2, 0, ALPHA, A, 1, B, 2, BETA, C, 2 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 7
+ CALL ZSYMM( 'R', 'L', 0, 2, ALPHA, A, 1, B, 1, BETA, C, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 9
+ CALL ZSYMM( 'L', 'U', 2, 0, ALPHA, A, 2, B, 1, BETA, C, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 9
+ CALL ZSYMM( 'R', 'U', 2, 0, ALPHA, A, 1, B, 1, BETA, C, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 9
+ CALL ZSYMM( 'L', 'L', 2, 0, ALPHA, A, 2, B, 1, BETA, C, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 9
+ CALL ZSYMM( 'R', 'L', 2, 0, ALPHA, A, 1, B, 1, BETA, C, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 12
+ CALL ZSYMM( 'L', 'U', 2, 0, ALPHA, A, 2, B, 2, BETA, C, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 12
+ CALL ZSYMM( 'R', 'U', 2, 0, ALPHA, A, 1, B, 2, BETA, C, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 12
+ CALL ZSYMM( 'L', 'L', 2, 0, ALPHA, A, 2, B, 2, BETA, C, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 12
+ CALL ZSYMM( 'R', 'L', 2, 0, ALPHA, A, 1, B, 2, BETA, C, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ GO TO 100
+ 40 INFOT = 1
+ CALL ZTRMM( '/', 'U', 'N', 'N', 0, 0, ALPHA, A, 1, B, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 2
+ CALL ZTRMM( 'L', '/', 'N', 'N', 0, 0, ALPHA, A, 1, B, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 3
+ CALL ZTRMM( 'L', 'U', '/', 'N', 0, 0, ALPHA, A, 1, B, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 4
+ CALL ZTRMM( 'L', 'U', 'N', '/', 0, 0, ALPHA, A, 1, B, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 5
+ CALL ZTRMM( 'L', 'U', 'N', 'N', -1, 0, ALPHA, A, 1, B, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 5
+ CALL ZTRMM( 'L', 'U', 'C', 'N', -1, 0, ALPHA, A, 1, B, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 5
+ CALL ZTRMM( 'L', 'U', 'T', 'N', -1, 0, ALPHA, A, 1, B, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 5
+ CALL ZTRMM( 'R', 'U', 'N', 'N', -1, 0, ALPHA, A, 1, B, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 5
+ CALL ZTRMM( 'R', 'U', 'C', 'N', -1, 0, ALPHA, A, 1, B, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 5
+ CALL ZTRMM( 'R', 'U', 'T', 'N', -1, 0, ALPHA, A, 1, B, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 5
+ CALL ZTRMM( 'L', 'L', 'N', 'N', -1, 0, ALPHA, A, 1, B, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 5
+ CALL ZTRMM( 'L', 'L', 'C', 'N', -1, 0, ALPHA, A, 1, B, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 5
+ CALL ZTRMM( 'L', 'L', 'T', 'N', -1, 0, ALPHA, A, 1, B, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 5
+ CALL ZTRMM( 'R', 'L', 'N', 'N', -1, 0, ALPHA, A, 1, B, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 5
+ CALL ZTRMM( 'R', 'L', 'C', 'N', -1, 0, ALPHA, A, 1, B, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 5
+ CALL ZTRMM( 'R', 'L', 'T', 'N', -1, 0, ALPHA, A, 1, B, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 6
+ CALL ZTRMM( 'L', 'U', 'N', 'N', 0, -1, ALPHA, A, 1, B, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 6
+ CALL ZTRMM( 'L', 'U', 'C', 'N', 0, -1, ALPHA, A, 1, B, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 6
+ CALL ZTRMM( 'L', 'U', 'T', 'N', 0, -1, ALPHA, A, 1, B, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 6
+ CALL ZTRMM( 'R', 'U', 'N', 'N', 0, -1, ALPHA, A, 1, B, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 6
+ CALL ZTRMM( 'R', 'U', 'C', 'N', 0, -1, ALPHA, A, 1, B, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 6
+ CALL ZTRMM( 'R', 'U', 'T', 'N', 0, -1, ALPHA, A, 1, B, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 6
+ CALL ZTRMM( 'L', 'L', 'N', 'N', 0, -1, ALPHA, A, 1, B, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 6
+ CALL ZTRMM( 'L', 'L', 'C', 'N', 0, -1, ALPHA, A, 1, B, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 6
+ CALL ZTRMM( 'L', 'L', 'T', 'N', 0, -1, ALPHA, A, 1, B, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 6
+ CALL ZTRMM( 'R', 'L', 'N', 'N', 0, -1, ALPHA, A, 1, B, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 6
+ CALL ZTRMM( 'R', 'L', 'C', 'N', 0, -1, ALPHA, A, 1, B, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 6
+ CALL ZTRMM( 'R', 'L', 'T', 'N', 0, -1, ALPHA, A, 1, B, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 9
+ CALL ZTRMM( 'L', 'U', 'N', 'N', 2, 0, ALPHA, A, 1, B, 2 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 9
+ CALL ZTRMM( 'L', 'U', 'C', 'N', 2, 0, ALPHA, A, 1, B, 2 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 9
+ CALL ZTRMM( 'L', 'U', 'T', 'N', 2, 0, ALPHA, A, 1, B, 2 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 9
+ CALL ZTRMM( 'R', 'U', 'N', 'N', 0, 2, ALPHA, A, 1, B, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 9
+ CALL ZTRMM( 'R', 'U', 'C', 'N', 0, 2, ALPHA, A, 1, B, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 9
+ CALL ZTRMM( 'R', 'U', 'T', 'N', 0, 2, ALPHA, A, 1, B, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 9
+ CALL ZTRMM( 'L', 'L', 'N', 'N', 2, 0, ALPHA, A, 1, B, 2 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 9
+ CALL ZTRMM( 'L', 'L', 'C', 'N', 2, 0, ALPHA, A, 1, B, 2 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 9
+ CALL ZTRMM( 'L', 'L', 'T', 'N', 2, 0, ALPHA, A, 1, B, 2 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 9
+ CALL ZTRMM( 'R', 'L', 'N', 'N', 0, 2, ALPHA, A, 1, B, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 9
+ CALL ZTRMM( 'R', 'L', 'C', 'N', 0, 2, ALPHA, A, 1, B, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 9
+ CALL ZTRMM( 'R', 'L', 'T', 'N', 0, 2, ALPHA, A, 1, B, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 11
+ CALL ZTRMM( 'L', 'U', 'N', 'N', 2, 0, ALPHA, A, 2, B, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 11
+ CALL ZTRMM( 'L', 'U', 'C', 'N', 2, 0, ALPHA, A, 2, B, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 11
+ CALL ZTRMM( 'L', 'U', 'T', 'N', 2, 0, ALPHA, A, 2, B, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 11
+ CALL ZTRMM( 'R', 'U', 'N', 'N', 2, 0, ALPHA, A, 1, B, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 11
+ CALL ZTRMM( 'R', 'U', 'C', 'N', 2, 0, ALPHA, A, 1, B, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 11
+ CALL ZTRMM( 'R', 'U', 'T', 'N', 2, 0, ALPHA, A, 1, B, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 11
+ CALL ZTRMM( 'L', 'L', 'N', 'N', 2, 0, ALPHA, A, 2, B, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 11
+ CALL ZTRMM( 'L', 'L', 'C', 'N', 2, 0, ALPHA, A, 2, B, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 11
+ CALL ZTRMM( 'L', 'L', 'T', 'N', 2, 0, ALPHA, A, 2, B, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 11
+ CALL ZTRMM( 'R', 'L', 'N', 'N', 2, 0, ALPHA, A, 1, B, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 11
+ CALL ZTRMM( 'R', 'L', 'C', 'N', 2, 0, ALPHA, A, 1, B, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 11
+ CALL ZTRMM( 'R', 'L', 'T', 'N', 2, 0, ALPHA, A, 1, B, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ GO TO 100
+ 50 INFOT = 1
+ CALL ZTRSM( '/', 'U', 'N', 'N', 0, 0, ALPHA, A, 1, B, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 2
+ CALL ZTRSM( 'L', '/', 'N', 'N', 0, 0, ALPHA, A, 1, B, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 3
+ CALL ZTRSM( 'L', 'U', '/', 'N', 0, 0, ALPHA, A, 1, B, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 4
+ CALL ZTRSM( 'L', 'U', 'N', '/', 0, 0, ALPHA, A, 1, B, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 5
+ CALL ZTRSM( 'L', 'U', 'N', 'N', -1, 0, ALPHA, A, 1, B, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 5
+ CALL ZTRSM( 'L', 'U', 'C', 'N', -1, 0, ALPHA, A, 1, B, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 5
+ CALL ZTRSM( 'L', 'U', 'T', 'N', -1, 0, ALPHA, A, 1, B, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 5
+ CALL ZTRSM( 'R', 'U', 'N', 'N', -1, 0, ALPHA, A, 1, B, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 5
+ CALL ZTRSM( 'R', 'U', 'C', 'N', -1, 0, ALPHA, A, 1, B, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 5
+ CALL ZTRSM( 'R', 'U', 'T', 'N', -1, 0, ALPHA, A, 1, B, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 5
+ CALL ZTRSM( 'L', 'L', 'N', 'N', -1, 0, ALPHA, A, 1, B, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 5
+ CALL ZTRSM( 'L', 'L', 'C', 'N', -1, 0, ALPHA, A, 1, B, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 5
+ CALL ZTRSM( 'L', 'L', 'T', 'N', -1, 0, ALPHA, A, 1, B, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 5
+ CALL ZTRSM( 'R', 'L', 'N', 'N', -1, 0, ALPHA, A, 1, B, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 5
+ CALL ZTRSM( 'R', 'L', 'C', 'N', -1, 0, ALPHA, A, 1, B, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 5
+ CALL ZTRSM( 'R', 'L', 'T', 'N', -1, 0, ALPHA, A, 1, B, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 6
+ CALL ZTRSM( 'L', 'U', 'N', 'N', 0, -1, ALPHA, A, 1, B, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 6
+ CALL ZTRSM( 'L', 'U', 'C', 'N', 0, -1, ALPHA, A, 1, B, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 6
+ CALL ZTRSM( 'L', 'U', 'T', 'N', 0, -1, ALPHA, A, 1, B, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 6
+ CALL ZTRSM( 'R', 'U', 'N', 'N', 0, -1, ALPHA, A, 1, B, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 6
+ CALL ZTRSM( 'R', 'U', 'C', 'N', 0, -1, ALPHA, A, 1, B, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 6
+ CALL ZTRSM( 'R', 'U', 'T', 'N', 0, -1, ALPHA, A, 1, B, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 6
+ CALL ZTRSM( 'L', 'L', 'N', 'N', 0, -1, ALPHA, A, 1, B, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 6
+ CALL ZTRSM( 'L', 'L', 'C', 'N', 0, -1, ALPHA, A, 1, B, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 6
+ CALL ZTRSM( 'L', 'L', 'T', 'N', 0, -1, ALPHA, A, 1, B, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 6
+ CALL ZTRSM( 'R', 'L', 'N', 'N', 0, -1, ALPHA, A, 1, B, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 6
+ CALL ZTRSM( 'R', 'L', 'C', 'N', 0, -1, ALPHA, A, 1, B, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 6
+ CALL ZTRSM( 'R', 'L', 'T', 'N', 0, -1, ALPHA, A, 1, B, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 9
+ CALL ZTRSM( 'L', 'U', 'N', 'N', 2, 0, ALPHA, A, 1, B, 2 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 9
+ CALL ZTRSM( 'L', 'U', 'C', 'N', 2, 0, ALPHA, A, 1, B, 2 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 9
+ CALL ZTRSM( 'L', 'U', 'T', 'N', 2, 0, ALPHA, A, 1, B, 2 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 9
+ CALL ZTRSM( 'R', 'U', 'N', 'N', 0, 2, ALPHA, A, 1, B, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 9
+ CALL ZTRSM( 'R', 'U', 'C', 'N', 0, 2, ALPHA, A, 1, B, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 9
+ CALL ZTRSM( 'R', 'U', 'T', 'N', 0, 2, ALPHA, A, 1, B, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 9
+ CALL ZTRSM( 'L', 'L', 'N', 'N', 2, 0, ALPHA, A, 1, B, 2 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 9
+ CALL ZTRSM( 'L', 'L', 'C', 'N', 2, 0, ALPHA, A, 1, B, 2 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 9
+ CALL ZTRSM( 'L', 'L', 'T', 'N', 2, 0, ALPHA, A, 1, B, 2 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 9
+ CALL ZTRSM( 'R', 'L', 'N', 'N', 0, 2, ALPHA, A, 1, B, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 9
+ CALL ZTRSM( 'R', 'L', 'C', 'N', 0, 2, ALPHA, A, 1, B, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 9
+ CALL ZTRSM( 'R', 'L', 'T', 'N', 0, 2, ALPHA, A, 1, B, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 11
+ CALL ZTRSM( 'L', 'U', 'N', 'N', 2, 0, ALPHA, A, 2, B, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 11
+ CALL ZTRSM( 'L', 'U', 'C', 'N', 2, 0, ALPHA, A, 2, B, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 11
+ CALL ZTRSM( 'L', 'U', 'T', 'N', 2, 0, ALPHA, A, 2, B, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 11
+ CALL ZTRSM( 'R', 'U', 'N', 'N', 2, 0, ALPHA, A, 1, B, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 11
+ CALL ZTRSM( 'R', 'U', 'C', 'N', 2, 0, ALPHA, A, 1, B, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 11
+ CALL ZTRSM( 'R', 'U', 'T', 'N', 2, 0, ALPHA, A, 1, B, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 11
+ CALL ZTRSM( 'L', 'L', 'N', 'N', 2, 0, ALPHA, A, 2, B, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 11
+ CALL ZTRSM( 'L', 'L', 'C', 'N', 2, 0, ALPHA, A, 2, B, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 11
+ CALL ZTRSM( 'L', 'L', 'T', 'N', 2, 0, ALPHA, A, 2, B, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 11
+ CALL ZTRSM( 'R', 'L', 'N', 'N', 2, 0, ALPHA, A, 1, B, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 11
+ CALL ZTRSM( 'R', 'L', 'C', 'N', 2, 0, ALPHA, A, 1, B, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 11
+ CALL ZTRSM( 'R', 'L', 'T', 'N', 2, 0, ALPHA, A, 1, B, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ GO TO 100
+ 60 INFOT = 1
+ CALL ZHERK( '/', 'N', 0, 0, RALPHA, A, 1, RBETA, C, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 2
+ CALL ZHERK( 'U', 'T', 0, 0, RALPHA, A, 1, RBETA, C, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 3
+ CALL ZHERK( 'U', 'N', -1, 0, RALPHA, A, 1, RBETA, C, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 3
+ CALL ZHERK( 'U', 'C', -1, 0, RALPHA, A, 1, RBETA, C, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 3
+ CALL ZHERK( 'L', 'N', -1, 0, RALPHA, A, 1, RBETA, C, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 3
+ CALL ZHERK( 'L', 'C', -1, 0, RALPHA, A, 1, RBETA, C, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 4
+ CALL ZHERK( 'U', 'N', 0, -1, RALPHA, A, 1, RBETA, C, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 4
+ CALL ZHERK( 'U', 'C', 0, -1, RALPHA, A, 1, RBETA, C, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 4
+ CALL ZHERK( 'L', 'N', 0, -1, RALPHA, A, 1, RBETA, C, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 4
+ CALL ZHERK( 'L', 'C', 0, -1, RALPHA, A, 1, RBETA, C, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 7
+ CALL ZHERK( 'U', 'N', 2, 0, RALPHA, A, 1, RBETA, C, 2 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 7
+ CALL ZHERK( 'U', 'C', 0, 2, RALPHA, A, 1, RBETA, C, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 7
+ CALL ZHERK( 'L', 'N', 2, 0, RALPHA, A, 1, RBETA, C, 2 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 7
+ CALL ZHERK( 'L', 'C', 0, 2, RALPHA, A, 1, RBETA, C, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 10
+ CALL ZHERK( 'U', 'N', 2, 0, RALPHA, A, 2, RBETA, C, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 10
+ CALL ZHERK( 'U', 'C', 2, 0, RALPHA, A, 1, RBETA, C, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 10
+ CALL ZHERK( 'L', 'N', 2, 0, RALPHA, A, 2, RBETA, C, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 10
+ CALL ZHERK( 'L', 'C', 2, 0, RALPHA, A, 1, RBETA, C, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ GO TO 100
+ 70 INFOT = 1
+ CALL ZSYRK( '/', 'N', 0, 0, ALPHA, A, 1, BETA, C, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 2
+ CALL ZSYRK( 'U', 'C', 0, 0, ALPHA, A, 1, BETA, C, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 3
+ CALL ZSYRK( 'U', 'N', -1, 0, ALPHA, A, 1, BETA, C, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 3
+ CALL ZSYRK( 'U', 'T', -1, 0, ALPHA, A, 1, BETA, C, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 3
+ CALL ZSYRK( 'L', 'N', -1, 0, ALPHA, A, 1, BETA, C, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 3
+ CALL ZSYRK( 'L', 'T', -1, 0, ALPHA, A, 1, BETA, C, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 4
+ CALL ZSYRK( 'U', 'N', 0, -1, ALPHA, A, 1, BETA, C, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 4
+ CALL ZSYRK( 'U', 'T', 0, -1, ALPHA, A, 1, BETA, C, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 4
+ CALL ZSYRK( 'L', 'N', 0, -1, ALPHA, A, 1, BETA, C, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 4
+ CALL ZSYRK( 'L', 'T', 0, -1, ALPHA, A, 1, BETA, C, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 7
+ CALL ZSYRK( 'U', 'N', 2, 0, ALPHA, A, 1, BETA, C, 2 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 7
+ CALL ZSYRK( 'U', 'T', 0, 2, ALPHA, A, 1, BETA, C, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 7
+ CALL ZSYRK( 'L', 'N', 2, 0, ALPHA, A, 1, BETA, C, 2 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 7
+ CALL ZSYRK( 'L', 'T', 0, 2, ALPHA, A, 1, BETA, C, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 10
+ CALL ZSYRK( 'U', 'N', 2, 0, ALPHA, A, 2, BETA, C, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 10
+ CALL ZSYRK( 'U', 'T', 2, 0, ALPHA, A, 1, BETA, C, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 10
+ CALL ZSYRK( 'L', 'N', 2, 0, ALPHA, A, 2, BETA, C, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 10
+ CALL ZSYRK( 'L', 'T', 2, 0, ALPHA, A, 1, BETA, C, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ GO TO 100
+ 80 INFOT = 1
+ CALL ZHER2K( '/', 'N', 0, 0, ALPHA, A, 1, B, 1, RBETA, C, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 2
+ CALL ZHER2K( 'U', 'T', 0, 0, ALPHA, A, 1, B, 1, RBETA, C, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 3
+ CALL ZHER2K( 'U', 'N', -1, 0, ALPHA, A, 1, B, 1, RBETA, C, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 3
+ CALL ZHER2K( 'U', 'C', -1, 0, ALPHA, A, 1, B, 1, RBETA, C, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 3
+ CALL ZHER2K( 'L', 'N', -1, 0, ALPHA, A, 1, B, 1, RBETA, C, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 3
+ CALL ZHER2K( 'L', 'C', -1, 0, ALPHA, A, 1, B, 1, RBETA, C, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 4
+ CALL ZHER2K( 'U', 'N', 0, -1, ALPHA, A, 1, B, 1, RBETA, C, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 4
+ CALL ZHER2K( 'U', 'C', 0, -1, ALPHA, A, 1, B, 1, RBETA, C, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 4
+ CALL ZHER2K( 'L', 'N', 0, -1, ALPHA, A, 1, B, 1, RBETA, C, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 4
+ CALL ZHER2K( 'L', 'C', 0, -1, ALPHA, A, 1, B, 1, RBETA, C, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 7
+ CALL ZHER2K( 'U', 'N', 2, 0, ALPHA, A, 1, B, 1, RBETA, C, 2 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 7
+ CALL ZHER2K( 'U', 'C', 0, 2, ALPHA, A, 1, B, 1, RBETA, C, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 7
+ CALL ZHER2K( 'L', 'N', 2, 0, ALPHA, A, 1, B, 1, RBETA, C, 2 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 7
+ CALL ZHER2K( 'L', 'C', 0, 2, ALPHA, A, 1, B, 1, RBETA, C, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 9
+ CALL ZHER2K( 'U', 'N', 2, 0, ALPHA, A, 2, B, 1, RBETA, C, 2 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 9
+ CALL ZHER2K( 'U', 'C', 0, 2, ALPHA, A, 2, B, 1, RBETA, C, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 9
+ CALL ZHER2K( 'L', 'N', 2, 0, ALPHA, A, 2, B, 1, RBETA, C, 2 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 9
+ CALL ZHER2K( 'L', 'C', 0, 2, ALPHA, A, 2, B, 1, RBETA, C, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 12
+ CALL ZHER2K( 'U', 'N', 2, 0, ALPHA, A, 2, B, 2, RBETA, C, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 12
+ CALL ZHER2K( 'U', 'C', 2, 0, ALPHA, A, 1, B, 1, RBETA, C, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 12
+ CALL ZHER2K( 'L', 'N', 2, 0, ALPHA, A, 2, B, 2, RBETA, C, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 12
+ CALL ZHER2K( 'L', 'C', 2, 0, ALPHA, A, 1, B, 1, RBETA, C, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ GO TO 100
+ 90 INFOT = 1
+ CALL ZSYR2K( '/', 'N', 0, 0, ALPHA, A, 1, B, 1, BETA, C, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 2
+ CALL ZSYR2K( 'U', 'C', 0, 0, ALPHA, A, 1, B, 1, BETA, C, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 3
+ CALL ZSYR2K( 'U', 'N', -1, 0, ALPHA, A, 1, B, 1, BETA, C, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 3
+ CALL ZSYR2K( 'U', 'T', -1, 0, ALPHA, A, 1, B, 1, BETA, C, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 3
+ CALL ZSYR2K( 'L', 'N', -1, 0, ALPHA, A, 1, B, 1, BETA, C, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 3
+ CALL ZSYR2K( 'L', 'T', -1, 0, ALPHA, A, 1, B, 1, BETA, C, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 4
+ CALL ZSYR2K( 'U', 'N', 0, -1, ALPHA, A, 1, B, 1, BETA, C, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 4
+ CALL ZSYR2K( 'U', 'T', 0, -1, ALPHA, A, 1, B, 1, BETA, C, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 4
+ CALL ZSYR2K( 'L', 'N', 0, -1, ALPHA, A, 1, B, 1, BETA, C, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 4
+ CALL ZSYR2K( 'L', 'T', 0, -1, ALPHA, A, 1, B, 1, BETA, C, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 7
+ CALL ZSYR2K( 'U', 'N', 2, 0, ALPHA, A, 1, B, 1, BETA, C, 2 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 7
+ CALL ZSYR2K( 'U', 'T', 0, 2, ALPHA, A, 1, B, 1, BETA, C, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 7
+ CALL ZSYR2K( 'L', 'N', 2, 0, ALPHA, A, 1, B, 1, BETA, C, 2 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 7
+ CALL ZSYR2K( 'L', 'T', 0, 2, ALPHA, A, 1, B, 1, BETA, C, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 9
+ CALL ZSYR2K( 'U', 'N', 2, 0, ALPHA, A, 2, B, 1, BETA, C, 2 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 9
+ CALL ZSYR2K( 'U', 'T', 0, 2, ALPHA, A, 2, B, 1, BETA, C, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 9
+ CALL ZSYR2K( 'L', 'N', 2, 0, ALPHA, A, 2, B, 1, BETA, C, 2 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 9
+ CALL ZSYR2K( 'L', 'T', 0, 2, ALPHA, A, 2, B, 1, BETA, C, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 12
+ CALL ZSYR2K( 'U', 'N', 2, 0, ALPHA, A, 2, B, 2, BETA, C, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 12
+ CALL ZSYR2K( 'U', 'T', 2, 0, ALPHA, A, 1, B, 1, BETA, C, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 12
+ CALL ZSYR2K( 'L', 'N', 2, 0, ALPHA, A, 2, B, 2, BETA, C, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+ INFOT = 12
+ CALL ZSYR2K( 'L', 'T', 2, 0, ALPHA, A, 1, B, 1, BETA, C, 1 )
+ CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+*
+ 100 IF( OK )THEN
+ WRITE( NOUT, FMT = 9999 )SRNAMT
+ ELSE
+ WRITE( NOUT, FMT = 9998 )SRNAMT
+ END IF
+ RETURN
+*
+ 9999 FORMAT( ' ', A6, ' PASSED THE TESTS OF ERROR-EXITS' )
+ 9998 FORMAT( ' ******* ', A6, ' FAILED THE TESTS OF ERROR-EXITS *****',
+ $ '**' )
+*
+* End of ZCHKE.
+*
+ END
+ SUBROUTINE ZMAKE( TYPE, UPLO, DIAG, M, N, A, NMAX, AA, LDA, RESET,
+ $ TRANSL )
+*
+* Generates values for an M by N matrix A.
+* Stores the values in the array AA in the data structure required
+* by the routine, with unwanted elements set to rogue value.
+*
+* TYPE is 'GE', 'HE', 'SY' or 'TR'.
+*
+* Auxiliary routine for test program for Level 3 Blas.
+*
+* -- Written on 8-February-1989.
+* Jack Dongarra, Argonne National Laboratory.
+* Iain Duff, AERE Harwell.
+* Jeremy Du Croz, Numerical Algorithms Group Ltd.
+* Sven Hammarling, Numerical Algorithms Group Ltd.
+*
+* .. Parameters ..
+ COMPLEX*16 ZERO, ONE
+ PARAMETER ( ZERO = ( 0.0D0, 0.0D0 ),
+ $ ONE = ( 1.0D0, 0.0D0 ) )
+ COMPLEX*16 ROGUE
+ PARAMETER ( ROGUE = ( -1.0D10, 1.0D10 ) )
+ DOUBLE PRECISION RZERO
+ PARAMETER ( RZERO = 0.0D0 )
+ DOUBLE PRECISION RROGUE
+ PARAMETER ( RROGUE = -1.0D10 )
+* .. Scalar Arguments ..
+ COMPLEX*16 TRANSL
+ INTEGER LDA, M, N, NMAX
+ LOGICAL RESET
+ CHARACTER*1 DIAG, UPLO
+ CHARACTER*2 TYPE
+* .. Array Arguments ..
+ COMPLEX*16 A( NMAX, * ), AA( * )
+* .. Local Scalars ..
+ INTEGER I, IBEG, IEND, J, JJ
+ LOGICAL GEN, HER, LOWER, SYM, TRI, UNIT, UPPER
+* .. External Functions ..
+ COMPLEX*16 ZBEG
+ EXTERNAL ZBEG
+* .. Intrinsic Functions ..
+ INTRINSIC DCMPLX, DCONJG, DBLE
+* .. Executable Statements ..
+ GEN = TYPE.EQ.'GE'
+ HER = TYPE.EQ.'HE'
+ SYM = TYPE.EQ.'SY'
+ TRI = TYPE.EQ.'TR'
+ UPPER = ( HER.OR.SYM.OR.TRI ).AND.UPLO.EQ.'U'
+ LOWER = ( HER.OR.SYM.OR.TRI ).AND.UPLO.EQ.'L'
+ UNIT = TRI.AND.DIAG.EQ.'U'
+*
+* Generate data in array A.
+*
+ DO 20 J = 1, N
+ DO 10 I = 1, M
+ IF( GEN.OR.( UPPER.AND.I.LE.J ).OR.( LOWER.AND.I.GE.J ) )
+ $ THEN
+ A( I, J ) = ZBEG( RESET ) + TRANSL
+ IF( I.NE.J )THEN
+* Set some elements to zero
+ IF( N.GT.3.AND.J.EQ.N/2 )
+ $ A( I, J ) = ZERO
+ IF( HER )THEN
+ A( J, I ) = DCONJG( A( I, J ) )
+ ELSE IF( SYM )THEN
+ A( J, I ) = A( I, J )
+ ELSE IF( TRI )THEN
+ A( J, I ) = ZERO
+ END IF
+ END IF
+ END IF
+ 10 CONTINUE
+ IF( HER )
+ $ A( J, J ) = DCMPLX( DBLE( A( J, J ) ), RZERO )
+ IF( TRI )
+ $ A( J, J ) = A( J, J ) + ONE
+ IF( UNIT )
+ $ A( J, J ) = ONE
+ 20 CONTINUE
+*
+* Store elements in array AS in data structure required by routine.
+*
+ IF( TYPE.EQ.'GE' )THEN
+ DO 50 J = 1, N
+ DO 30 I = 1, M
+ AA( I + ( J - 1 )*LDA ) = A( I, J )
+ 30 CONTINUE
+ DO 40 I = M + 1, LDA
+ AA( I + ( J - 1 )*LDA ) = ROGUE
+ 40 CONTINUE
+ 50 CONTINUE
+ ELSE IF( TYPE.EQ.'HE'.OR.TYPE.EQ.'SY'.OR.TYPE.EQ.'TR' )THEN
+ DO 90 J = 1, N
+ IF( UPPER )THEN
+ IBEG = 1
+ IF( UNIT )THEN
+ IEND = J - 1
+ ELSE
+ IEND = J
+ END IF
+ ELSE
+ IF( UNIT )THEN
+ IBEG = J + 1
+ ELSE
+ IBEG = J
+ END IF
+ IEND = N
+ END IF
+ DO 60 I = 1, IBEG - 1
+ AA( I + ( J - 1 )*LDA ) = ROGUE
+ 60 CONTINUE
+ DO 70 I = IBEG, IEND
+ AA( I + ( J - 1 )*LDA ) = A( I, J )
+ 70 CONTINUE
+ DO 80 I = IEND + 1, LDA
+ AA( I + ( J - 1 )*LDA ) = ROGUE
+ 80 CONTINUE
+ IF( HER )THEN
+ JJ = J + ( J - 1 )*LDA
+ AA( JJ ) = DCMPLX( DBLE( AA( JJ ) ), RROGUE )
+ END IF
+ 90 CONTINUE
+ END IF
+ RETURN
+*
+* End of ZMAKE.
+*
+ END
+ SUBROUTINE ZMMCH( TRANSA, TRANSB, M, N, KK, ALPHA, A, LDA, B, LDB,
+ $ BETA, C, LDC, CT, G, CC, LDCC, EPS, ERR, FATAL,
+ $ NOUT, MV )
+*
+* Checks the results of the computational tests.
+*
+* Auxiliary routine for test program for Level 3 Blas.
+*
+* -- Written on 8-February-1989.
+* Jack Dongarra, Argonne National Laboratory.
+* Iain Duff, AERE Harwell.
+* Jeremy Du Croz, Numerical Algorithms Group Ltd.
+* Sven Hammarling, Numerical Algorithms Group Ltd.
+*
+* .. Parameters ..
+ COMPLEX*16 ZERO
+ PARAMETER ( ZERO = ( 0.0D0, 0.0D0 ) )
+ DOUBLE PRECISION RZERO, RONE
+ PARAMETER ( RZERO = 0.0D0, RONE = 1.0D0 )
+* .. Scalar Arguments ..
+ COMPLEX*16 ALPHA, BETA
+ DOUBLE PRECISION EPS, ERR
+ INTEGER KK, LDA, LDB, LDC, LDCC, M, N, NOUT
+ LOGICAL FATAL, MV
+ CHARACTER*1 TRANSA, TRANSB
+* .. Array Arguments ..
+ COMPLEX*16 A( LDA, * ), B( LDB, * ), C( LDC, * ),
+ $ CC( LDCC, * ), CT( * )
+ DOUBLE PRECISION G( * )
+* .. Local Scalars ..
+ COMPLEX*16 CL
+ DOUBLE PRECISION ERRI
+ INTEGER I, J, K
+ LOGICAL CTRANA, CTRANB, TRANA, TRANB
+* .. Intrinsic Functions ..
+ INTRINSIC ABS, DIMAG, DCONJG, MAX, DBLE, SQRT
+* .. Statement Functions ..
+ DOUBLE PRECISION ABS1
+* .. Statement Function definitions ..
+ ABS1( CL ) = ABS( DBLE( CL ) ) + ABS( DIMAG( CL ) )
+* .. Executable Statements ..
+ TRANA = TRANSA.EQ.'T'.OR.TRANSA.EQ.'C'
+ TRANB = TRANSB.EQ.'T'.OR.TRANSB.EQ.'C'
+ CTRANA = TRANSA.EQ.'C'
+ CTRANB = TRANSB.EQ.'C'
+*
+* Compute expected result, one column at a time, in CT using data
+* in A, B and C.
+* Compute gauges in G.
+*
+ DO 220 J = 1, N
+*
+ DO 10 I = 1, M
+ CT( I ) = ZERO
+ G( I ) = RZERO
+ 10 CONTINUE
+ IF( .NOT.TRANA.AND..NOT.TRANB )THEN
+ DO 30 K = 1, KK
+ DO 20 I = 1, M
+ CT( I ) = CT( I ) + A( I, K )*B( K, J )
+ G( I ) = G( I ) + ABS1( A( I, K ) )*ABS1( B( K, J ) )
+ 20 CONTINUE
+ 30 CONTINUE
+ ELSE IF( TRANA.AND..NOT.TRANB )THEN
+ IF( CTRANA )THEN
+ DO 50 K = 1, KK
+ DO 40 I = 1, M
+ CT( I ) = CT( I ) + DCONJG( A( K, I ) )*B( K, J )
+ G( I ) = G( I ) + ABS1( A( K, I ) )*
+ $ ABS1( B( K, J ) )
+ 40 CONTINUE
+ 50 CONTINUE
+ ELSE
+ DO 70 K = 1, KK
+ DO 60 I = 1, M
+ CT( I ) = CT( I ) + A( K, I )*B( K, J )
+ G( I ) = G( I ) + ABS1( A( K, I ) )*
+ $ ABS1( B( K, J ) )
+ 60 CONTINUE
+ 70 CONTINUE
+ END IF
+ ELSE IF( .NOT.TRANA.AND.TRANB )THEN
+ IF( CTRANB )THEN
+ DO 90 K = 1, KK
+ DO 80 I = 1, M
+ CT( I ) = CT( I ) + A( I, K )*DCONJG( B( J, K ) )
+ G( I ) = G( I ) + ABS1( A( I, K ) )*
+ $ ABS1( B( J, K ) )
+ 80 CONTINUE
+ 90 CONTINUE
+ ELSE
+ DO 110 K = 1, KK
+ DO 100 I = 1, M
+ CT( I ) = CT( I ) + A( I, K )*B( J, K )
+ G( I ) = G( I ) + ABS1( A( I, K ) )*
+ $ ABS1( B( J, K ) )
+ 100 CONTINUE
+ 110 CONTINUE
+ END IF
+ ELSE IF( TRANA.AND.TRANB )THEN
+ IF( CTRANA )THEN
+ IF( CTRANB )THEN
+ DO 130 K = 1, KK
+ DO 120 I = 1, M
+ CT( I ) = CT( I ) + DCONJG( A( K, I ) )*
+ $ DCONJG( B( J, K ) )
+ G( I ) = G( I ) + ABS1( A( K, I ) )*
+ $ ABS1( B( J, K ) )
+ 120 CONTINUE
+ 130 CONTINUE
+ ELSE
+ DO 150 K = 1, KK
+ DO 140 I = 1, M
+ CT( I ) = CT( I ) + DCONJG( A( K, I ) )*
+ $ B( J, K )
+ G( I ) = G( I ) + ABS1( A( K, I ) )*
+ $ ABS1( B( J, K ) )
+ 140 CONTINUE
+ 150 CONTINUE
+ END IF
+ ELSE
+ IF( CTRANB )THEN
+ DO 170 K = 1, KK
+ DO 160 I = 1, M
+ CT( I ) = CT( I ) + A( K, I )*
+ $ DCONJG( B( J, K ) )
+ G( I ) = G( I ) + ABS1( A( K, I ) )*
+ $ ABS1( B( J, K ) )
+ 160 CONTINUE
+ 170 CONTINUE
+ ELSE
+ DO 190 K = 1, KK
+ DO 180 I = 1, M
+ CT( I ) = CT( I ) + A( K, I )*B( J, K )
+ G( I ) = G( I ) + ABS1( A( K, I ) )*
+ $ ABS1( B( J, K ) )
+ 180 CONTINUE
+ 190 CONTINUE
+ END IF
+ END IF
+ END IF
+ DO 200 I = 1, M
+ CT( I ) = ALPHA*CT( I ) + BETA*C( I, J )
+ G( I ) = ABS1( ALPHA )*G( I ) +
+ $ ABS1( BETA )*ABS1( C( I, J ) )
+ 200 CONTINUE
+*
+* Compute the error ratio for this result.
+*
+ ERR = ZERO
+ DO 210 I = 1, M
+ ERRI = ABS1( CT( I ) - CC( I, J ) )/EPS
+ IF( G( I ).NE.RZERO )
+ $ ERRI = ERRI/G( I )
+ ERR = MAX( ERR, ERRI )
+ IF( ERR*SQRT( EPS ).GE.RONE )
+ $ GO TO 230
+ 210 CONTINUE
+*
+ 220 CONTINUE
+*
+* If the loop completes, all results are at least half accurate.
+ GO TO 250
+*
+* Report fatal error.
+*
+ 230 FATAL = .TRUE.
+ WRITE( NOUT, FMT = 9999 )
+ DO 240 I = 1, M
+ IF( MV )THEN
+ WRITE( NOUT, FMT = 9998 )I, CT( I ), CC( I, J )
+ ELSE
+ WRITE( NOUT, FMT = 9998 )I, CC( I, J ), CT( I )
+ END IF
+ 240 CONTINUE
+ IF( N.GT.1 )
+ $ WRITE( NOUT, FMT = 9997 )J
+*
+ 250 CONTINUE
+ RETURN
+*
+ 9999 FORMAT( ' ******* FATAL ERROR - COMPUTED RESULT IS LESS THAN HAL',
+ $ 'F ACCURATE *******', /' EXPECTED RE',
+ $ 'SULT COMPUTED RESULT' )
+ 9998 FORMAT( 1X, I7, 2( ' (', G15.6, ',', G15.6, ')' ) )
+ 9997 FORMAT( ' THESE ARE THE RESULTS FOR COLUMN ', I3 )
+*
+* End of ZMMCH.
+*
+ END
+ LOGICAL FUNCTION LZE( RI, RJ, LR )
+*
+* Tests if two arrays are identical.
+*
+* Auxiliary routine for test program for Level 3 Blas.
+*
+* -- Written on 8-February-1989.
+* Jack Dongarra, Argonne National Laboratory.
+* Iain Duff, AERE Harwell.
+* Jeremy Du Croz, Numerical Algorithms Group Ltd.
+* Sven Hammarling, Numerical Algorithms Group Ltd.
+*
+* .. Scalar Arguments ..
+ INTEGER LR
+* .. Array Arguments ..
+ COMPLEX*16 RI( * ), RJ( * )
+* .. Local Scalars ..
+ INTEGER I
+* .. Executable Statements ..
+ DO 10 I = 1, LR
+ IF( RI( I ).NE.RJ( I ) )
+ $ GO TO 20
+ 10 CONTINUE
+ LZE = .TRUE.
+ GO TO 30
+ 20 CONTINUE
+ LZE = .FALSE.
+ 30 RETURN
+*
+* End of LZE.
+*
+ END
+ LOGICAL FUNCTION LZERES( TYPE, UPLO, M, N, AA, AS, LDA )
+*
+* Tests if selected elements in two arrays are equal.
+*
+* TYPE is 'GE' or 'HE' or 'SY'.
+*
+* Auxiliary routine for test program for Level 3 Blas.
+*
+* -- Written on 8-February-1989.
+* Jack Dongarra, Argonne National Laboratory.
+* Iain Duff, AERE Harwell.
+* Jeremy Du Croz, Numerical Algorithms Group Ltd.
+* Sven Hammarling, Numerical Algorithms Group Ltd.
+*
+* .. Scalar Arguments ..
+ INTEGER LDA, M, N
+ CHARACTER*1 UPLO
+ CHARACTER*2 TYPE
+* .. Array Arguments ..
+ COMPLEX*16 AA( LDA, * ), AS( LDA, * )
+* .. Local Scalars ..
+ INTEGER I, IBEG, IEND, J
+ LOGICAL UPPER
+* .. Executable Statements ..
+ UPPER = UPLO.EQ.'U'
+ IF( TYPE.EQ.'GE' )THEN
+ DO 20 J = 1, N
+ DO 10 I = M + 1, LDA
+ IF( AA( I, J ).NE.AS( I, J ) )
+ $ GO TO 70
+ 10 CONTINUE
+ 20 CONTINUE
+ ELSE IF( TYPE.EQ.'HE'.OR.TYPE.EQ.'SY' )THEN
+ DO 50 J = 1, N
+ IF( UPPER )THEN
+ IBEG = 1
+ IEND = J
+ ELSE
+ IBEG = J
+ IEND = N
+ END IF
+ DO 30 I = 1, IBEG - 1
+ IF( AA( I, J ).NE.AS( I, J ) )
+ $ GO TO 70
+ 30 CONTINUE
+ DO 40 I = IEND + 1, LDA
+ IF( AA( I, J ).NE.AS( I, J ) )
+ $ GO TO 70
+ 40 CONTINUE
+ 50 CONTINUE
+ END IF
+*
+ 60 CONTINUE
+ LZERES = .TRUE.
+ GO TO 80
+ 70 CONTINUE
+ LZERES = .FALSE.
+ 80 RETURN
+*
+* End of LZERES.
+*
+ END
+ COMPLEX*16 FUNCTION ZBEG( RESET )
+*
+* Generates complex numbers as pairs of random numbers uniformly
+* distributed between -0.5 and 0.5.
+*
+* Auxiliary routine for test program for Level 3 Blas.
+*
+* -- Written on 8-February-1989.
+* Jack Dongarra, Argonne National Laboratory.
+* Iain Duff, AERE Harwell.
+* Jeremy Du Croz, Numerical Algorithms Group Ltd.
+* Sven Hammarling, Numerical Algorithms Group Ltd.
+*
+* .. Scalar Arguments ..
+ LOGICAL RESET
+* .. Local Scalars ..
+ INTEGER I, IC, J, MI, MJ
+* .. Save statement ..
+ SAVE I, IC, J, MI, MJ
+* .. Intrinsic Functions ..
+ INTRINSIC DCMPLX
+* .. Executable Statements ..
+ IF( RESET )THEN
+* Initialize local variables.
+ MI = 891
+ MJ = 457
+ I = 7
+ J = 7
+ IC = 0
+ RESET = .FALSE.
+ END IF
+*
+* The sequence of values of I or J is bounded between 1 and 999.
+* If initial I or J = 1,2,3,6,7 or 9, the period will be 50.
+* If initial I or J = 4 or 8, the period will be 25.
+* If initial I or J = 5, the period will be 10.
+* IC is used to break up the period by skipping 1 value of I or J
+* in 6.
+*
+ IC = IC + 1
+ 10 I = I*MI
+ J = J*MJ
+ I = I - 1000*( I/1000 )
+ J = J - 1000*( J/1000 )
+ IF( IC.GE.5 )THEN
+ IC = 0
+ GO TO 10
+ END IF
+ ZBEG = DCMPLX( ( I - 500 )/1001.0D0, ( J - 500 )/1001.0D0 )
+ RETURN
+*
+* End of ZBEG.
+*
+ END
+ DOUBLE PRECISION FUNCTION DDIFF( X, Y )
+*
+* Auxiliary routine for test program for Level 3 Blas.
+*
+* -- Written on 8-February-1989.
+* Jack Dongarra, Argonne National Laboratory.
+* Iain Duff, AERE Harwell.
+* Jeremy Du Croz, Numerical Algorithms Group Ltd.
+* Sven Hammarling, Numerical Algorithms Group Ltd.
+*
+* .. Scalar Arguments ..
+ DOUBLE PRECISION X, Y
+* .. Executable Statements ..
+ DDIFF = X - Y
+ RETURN
+*
+* End of DDIFF.
+*
+ END
+ SUBROUTINE CHKXER( SRNAMT, INFOT, NOUT, LERR, OK )
+*
+* Tests whether XERBLA has detected an error when it should.
+*
+* Auxiliary routine for test program for Level 3 Blas.
+*
+* -- Written on 8-February-1989.
+* Jack Dongarra, Argonne National Laboratory.
+* Iain Duff, AERE Harwell.
+* Jeremy Du Croz, Numerical Algorithms Group Ltd.
+* Sven Hammarling, Numerical Algorithms Group Ltd.
+*
+* .. Scalar Arguments ..
+ INTEGER INFOT, NOUT
+ LOGICAL LERR, OK
+ CHARACTER*6 SRNAMT
+* .. Executable Statements ..
+ IF( .NOT.LERR )THEN
+ WRITE( NOUT, FMT = 9999 )INFOT, SRNAMT
+ OK = .FALSE.
+ END IF
+ LERR = .FALSE.
+ RETURN
+*
+ 9999 FORMAT( ' ***** ILLEGAL VALUE OF PARAMETER NUMBER ', I2, ' NOT D',
+ $ 'ETECTED BY ', A6, ' *****' )
+*
+* End of CHKXER.
+*
+ END
+ SUBROUTINE XERBLA( SRNAME, INFO )
+*
+* This is a special version of XERBLA to be used only as part of
+* the test program for testing error exits from the Level 3 BLAS
+* routines.
+*
+* XERBLA is an error handler for the Level 3 BLAS routines.
+*
+* It is called by the Level 3 BLAS routines if an input parameter is
+* invalid.
+*
+* Auxiliary routine for test program for Level 3 Blas.
+*
+* -- Written on 8-February-1989.
+* Jack Dongarra, Argonne National Laboratory.
+* Iain Duff, AERE Harwell.
+* Jeremy Du Croz, Numerical Algorithms Group Ltd.
+* Sven Hammarling, Numerical Algorithms Group Ltd.
+*
+* .. Scalar Arguments ..
+ INTEGER INFO
+ CHARACTER*6 SRNAME
+* .. Scalars in Common ..
+ INTEGER INFOT, NOUT
+ LOGICAL LERR, OK
+ CHARACTER*6 SRNAMT
+* .. Common blocks ..
+ COMMON /INFOC/INFOT, NOUT, OK, LERR
+ COMMON /SRNAMC/SRNAMT
+* .. Executable Statements ..
+ LERR = .TRUE.
+ IF( INFO.NE.INFOT )THEN
+ IF( INFOT.NE.0 )THEN
+ WRITE( NOUT, FMT = 9999 )INFO, INFOT
+ ELSE
+ WRITE( NOUT, FMT = 9997 )INFO
+ END IF
+ OK = .FALSE.
+ END IF
+ IF( SRNAME.NE.SRNAMT )THEN
+ WRITE( NOUT, FMT = 9998 )SRNAME, SRNAMT
+ OK = .FALSE.
+ END IF
+ RETURN
+*
+ 9999 FORMAT( ' ******* XERBLA WAS CALLED WITH INFO = ', I6, ' INSTEAD',
+ $ ' OF ', I2, ' *******' )
+ 9998 FORMAT( ' ******* XERBLA WAS CALLED WITH SRNAME = ', A6, ' INSTE',
+ $ 'AD OF ', A6, ' *******' )
+ 9997 FORMAT( ' ******* XERBLA WAS CALLED WITH INFO = ', I6,
+ $ ' *******' )
+*
+* End of XERBLA
+*
+ END
+
diff --git a/blas/xerbla.cpp b/blas/xerbla.cpp
new file mode 100644
index 000000000..0d57710fe
--- /dev/null
+++ b/blas/xerbla.cpp
@@ -0,0 +1,23 @@
+
+#include <iostream>
+
+#if (defined __GNUC__)
+#define EIGEN_WEAK_LINKING __attribute__ ((weak))
+#else
+#define EIGEN_WEAK_LINKING
+#endif
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+EIGEN_WEAK_LINKING int xerbla_(const char * msg, int *info, int)
+{
+ std::cerr << "Eigen BLAS ERROR #" << *info << ": " << msg << "\n";
+ return 0;
+}
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/blas/zhbmv.f b/blas/zhbmv.f
new file mode 100644
index 000000000..bca0da5fc
--- /dev/null
+++ b/blas/zhbmv.f
@@ -0,0 +1,310 @@
+ SUBROUTINE ZHBMV(UPLO,N,K,ALPHA,A,LDA,X,INCX,BETA,Y,INCY)
+* .. Scalar Arguments ..
+ DOUBLE COMPLEX ALPHA,BETA
+ INTEGER INCX,INCY,K,LDA,N
+ CHARACTER UPLO
+* ..
+* .. Array Arguments ..
+ DOUBLE COMPLEX A(LDA,*),X(*),Y(*)
+* ..
+*
+* Purpose
+* =======
+*
+* ZHBMV performs the matrix-vector operation
+*
+* y := alpha*A*x + beta*y,
+*
+* where alpha and beta are scalars, x and y are n element vectors and
+* A is an n by n hermitian band matrix, with k super-diagonals.
+*
+* Arguments
+* ==========
+*
+* UPLO - CHARACTER*1.
+* On entry, UPLO specifies whether the upper or lower
+* triangular part of the band matrix A is being supplied as
+* follows:
+*
+* UPLO = 'U' or 'u' The upper triangular part of A is
+* being supplied.
+*
+* UPLO = 'L' or 'l' The lower triangular part of A is
+* being supplied.
+*
+* Unchanged on exit.
+*
+* N - INTEGER.
+* On entry, N specifies the order of the matrix A.
+* N must be at least zero.
+* Unchanged on exit.
+*
+* K - INTEGER.
+* On entry, K specifies the number of super-diagonals of the
+* matrix A. K must satisfy 0 .le. K.
+* Unchanged on exit.
+*
+* ALPHA - COMPLEX*16 .
+* On entry, ALPHA specifies the scalar alpha.
+* Unchanged on exit.
+*
+* A - COMPLEX*16 array of DIMENSION ( LDA, n ).
+* Before entry with UPLO = 'U' or 'u', the leading ( k + 1 )
+* by n part of the array A must contain the upper triangular
+* band part of the hermitian matrix, supplied column by
+* column, with the leading diagonal of the matrix in row
+* ( k + 1 ) of the array, the first super-diagonal starting at
+* position 2 in row k, and so on. The top left k by k triangle
+* of the array A is not referenced.
+* The following program segment will transfer the upper
+* triangular part of a hermitian band matrix from conventional
+* full matrix storage to band storage:
+*
+* DO 20, J = 1, N
+* M = K + 1 - J
+* DO 10, I = MAX( 1, J - K ), J
+* A( M + I, J ) = matrix( I, J )
+* 10 CONTINUE
+* 20 CONTINUE
+*
+* Before entry with UPLO = 'L' or 'l', the leading ( k + 1 )
+* by n part of the array A must contain the lower triangular
+* band part of the hermitian matrix, supplied column by
+* column, with the leading diagonal of the matrix in row 1 of
+* the array, the first sub-diagonal starting at position 1 in
+* row 2, and so on. The bottom right k by k triangle of the
+* array A is not referenced.
+* The following program segment will transfer the lower
+* triangular part of a hermitian band matrix from conventional
+* full matrix storage to band storage:
+*
+* DO 20, J = 1, N
+* M = 1 - J
+* DO 10, I = J, MIN( N, J + K )
+* A( M + I, J ) = matrix( I, J )
+* 10 CONTINUE
+* 20 CONTINUE
+*
+* Note that the imaginary parts of the diagonal elements need
+* not be set and are assumed to be zero.
+* Unchanged on exit.
+*
+* LDA - INTEGER.
+* On entry, LDA specifies the first dimension of A as declared
+* in the calling (sub) program. LDA must be at least
+* ( k + 1 ).
+* Unchanged on exit.
+*
+* X - COMPLEX*16 array of DIMENSION at least
+* ( 1 + ( n - 1 )*abs( INCX ) ).
+* Before entry, the incremented array X must contain the
+* vector x.
+* Unchanged on exit.
+*
+* INCX - INTEGER.
+* On entry, INCX specifies the increment for the elements of
+* X. INCX must not be zero.
+* Unchanged on exit.
+*
+* BETA - COMPLEX*16 .
+* On entry, BETA specifies the scalar beta.
+* Unchanged on exit.
+*
+* Y - COMPLEX*16 array of DIMENSION at least
+* ( 1 + ( n - 1 )*abs( INCY ) ).
+* Before entry, the incremented array Y must contain the
+* vector y. On exit, Y is overwritten by the updated vector y.
+*
+* INCY - INTEGER.
+* On entry, INCY specifies the increment for the elements of
+* Y. INCY must not be zero.
+* Unchanged on exit.
+*
+* Further Details
+* ===============
+*
+* Level 2 Blas routine.
+*
+* -- Written on 22-October-1986.
+* Jack Dongarra, Argonne National Lab.
+* Jeremy Du Croz, Nag Central Office.
+* Sven Hammarling, Nag Central Office.
+* Richard Hanson, Sandia National Labs.
+*
+* =====================================================================
+*
+* .. Parameters ..
+ DOUBLE COMPLEX ONE
+ PARAMETER (ONE= (1.0D+0,0.0D+0))
+ DOUBLE COMPLEX ZERO
+ PARAMETER (ZERO= (0.0D+0,0.0D+0))
+* ..
+* .. Local Scalars ..
+ DOUBLE COMPLEX TEMP1,TEMP2
+ INTEGER I,INFO,IX,IY,J,JX,JY,KPLUS1,KX,KY,L
+* ..
+* .. External Functions ..
+ LOGICAL LSAME
+ EXTERNAL LSAME
+* ..
+* .. External Subroutines ..
+ EXTERNAL XERBLA
+* ..
+* .. Intrinsic Functions ..
+ INTRINSIC DBLE,DCONJG,MAX,MIN
+* ..
+*
+* Test the input parameters.
+*
+ INFO = 0
+ IF (.NOT.LSAME(UPLO,'U') .AND. .NOT.LSAME(UPLO,'L')) THEN
+ INFO = 1
+ ELSE IF (N.LT.0) THEN
+ INFO = 2
+ ELSE IF (K.LT.0) THEN
+ INFO = 3
+ ELSE IF (LDA.LT. (K+1)) THEN
+ INFO = 6
+ ELSE IF (INCX.EQ.0) THEN
+ INFO = 8
+ ELSE IF (INCY.EQ.0) THEN
+ INFO = 11
+ END IF
+ IF (INFO.NE.0) THEN
+ CALL XERBLA('ZHBMV ',INFO)
+ RETURN
+ END IF
+*
+* Quick return if possible.
+*
+ IF ((N.EQ.0) .OR. ((ALPHA.EQ.ZERO).AND. (BETA.EQ.ONE))) RETURN
+*
+* Set up the start points in X and Y.
+*
+ IF (INCX.GT.0) THEN
+ KX = 1
+ ELSE
+ KX = 1 - (N-1)*INCX
+ END IF
+ IF (INCY.GT.0) THEN
+ KY = 1
+ ELSE
+ KY = 1 - (N-1)*INCY
+ END IF
+*
+* Start the operations. In this version the elements of the array A
+* are accessed sequentially with one pass through A.
+*
+* First form y := beta*y.
+*
+ IF (BETA.NE.ONE) THEN
+ IF (INCY.EQ.1) THEN
+ IF (BETA.EQ.ZERO) THEN
+ DO 10 I = 1,N
+ Y(I) = ZERO
+ 10 CONTINUE
+ ELSE
+ DO 20 I = 1,N
+ Y(I) = BETA*Y(I)
+ 20 CONTINUE
+ END IF
+ ELSE
+ IY = KY
+ IF (BETA.EQ.ZERO) THEN
+ DO 30 I = 1,N
+ Y(IY) = ZERO
+ IY = IY + INCY
+ 30 CONTINUE
+ ELSE
+ DO 40 I = 1,N
+ Y(IY) = BETA*Y(IY)
+ IY = IY + INCY
+ 40 CONTINUE
+ END IF
+ END IF
+ END IF
+ IF (ALPHA.EQ.ZERO) RETURN
+ IF (LSAME(UPLO,'U')) THEN
+*
+* Form y when upper triangle of A is stored.
+*
+ KPLUS1 = K + 1
+ IF ((INCX.EQ.1) .AND. (INCY.EQ.1)) THEN
+ DO 60 J = 1,N
+ TEMP1 = ALPHA*X(J)
+ TEMP2 = ZERO
+ L = KPLUS1 - J
+ DO 50 I = MAX(1,J-K),J - 1
+ Y(I) = Y(I) + TEMP1*A(L+I,J)
+ TEMP2 = TEMP2 + DCONJG(A(L+I,J))*X(I)
+ 50 CONTINUE
+ Y(J) = Y(J) + TEMP1*DBLE(A(KPLUS1,J)) + ALPHA*TEMP2
+ 60 CONTINUE
+ ELSE
+ JX = KX
+ JY = KY
+ DO 80 J = 1,N
+ TEMP1 = ALPHA*X(JX)
+ TEMP2 = ZERO
+ IX = KX
+ IY = KY
+ L = KPLUS1 - J
+ DO 70 I = MAX(1,J-K),J - 1
+ Y(IY) = Y(IY) + TEMP1*A(L+I,J)
+ TEMP2 = TEMP2 + DCONJG(A(L+I,J))*X(IX)
+ IX = IX + INCX
+ IY = IY + INCY
+ 70 CONTINUE
+ Y(JY) = Y(JY) + TEMP1*DBLE(A(KPLUS1,J)) + ALPHA*TEMP2
+ JX = JX + INCX
+ JY = JY + INCY
+ IF (J.GT.K) THEN
+ KX = KX + INCX
+ KY = KY + INCY
+ END IF
+ 80 CONTINUE
+ END IF
+ ELSE
+*
+* Form y when lower triangle of A is stored.
+*
+ IF ((INCX.EQ.1) .AND. (INCY.EQ.1)) THEN
+ DO 100 J = 1,N
+ TEMP1 = ALPHA*X(J)
+ TEMP2 = ZERO
+ Y(J) = Y(J) + TEMP1*DBLE(A(1,J))
+ L = 1 - J
+ DO 90 I = J + 1,MIN(N,J+K)
+ Y(I) = Y(I) + TEMP1*A(L+I,J)
+ TEMP2 = TEMP2 + DCONJG(A(L+I,J))*X(I)
+ 90 CONTINUE
+ Y(J) = Y(J) + ALPHA*TEMP2
+ 100 CONTINUE
+ ELSE
+ JX = KX
+ JY = KY
+ DO 120 J = 1,N
+ TEMP1 = ALPHA*X(JX)
+ TEMP2 = ZERO
+ Y(JY) = Y(JY) + TEMP1*DBLE(A(1,J))
+ L = 1 - J
+ IX = JX
+ IY = JY
+ DO 110 I = J + 1,MIN(N,J+K)
+ IX = IX + INCX
+ IY = IY + INCY
+ Y(IY) = Y(IY) + TEMP1*A(L+I,J)
+ TEMP2 = TEMP2 + DCONJG(A(L+I,J))*X(IX)
+ 110 CONTINUE
+ Y(JY) = Y(JY) + ALPHA*TEMP2
+ JX = JX + INCX
+ JY = JY + INCY
+ 120 CONTINUE
+ END IF
+ END IF
+*
+ RETURN
+*
+* End of ZHBMV .
+*
+ END
diff --git a/blas/zhpmv.f b/blas/zhpmv.f
new file mode 100644
index 000000000..b686108b3
--- /dev/null
+++ b/blas/zhpmv.f
@@ -0,0 +1,272 @@
+ SUBROUTINE ZHPMV(UPLO,N,ALPHA,AP,X,INCX,BETA,Y,INCY)
+* .. Scalar Arguments ..
+ DOUBLE COMPLEX ALPHA,BETA
+ INTEGER INCX,INCY,N
+ CHARACTER UPLO
+* ..
+* .. Array Arguments ..
+ DOUBLE COMPLEX AP(*),X(*),Y(*)
+* ..
+*
+* Purpose
+* =======
+*
+* ZHPMV performs the matrix-vector operation
+*
+* y := alpha*A*x + beta*y,
+*
+* where alpha and beta are scalars, x and y are n element vectors and
+* A is an n by n hermitian matrix, supplied in packed form.
+*
+* Arguments
+* ==========
+*
+* UPLO - CHARACTER*1.
+* On entry, UPLO specifies whether the upper or lower
+* triangular part of the matrix A is supplied in the packed
+* array AP as follows:
+*
+* UPLO = 'U' or 'u' The upper triangular part of A is
+* supplied in AP.
+*
+* UPLO = 'L' or 'l' The lower triangular part of A is
+* supplied in AP.
+*
+* Unchanged on exit.
+*
+* N - INTEGER.
+* On entry, N specifies the order of the matrix A.
+* N must be at least zero.
+* Unchanged on exit.
+*
+* ALPHA - COMPLEX*16 .
+* On entry, ALPHA specifies the scalar alpha.
+* Unchanged on exit.
+*
+* AP - COMPLEX*16 array of DIMENSION at least
+* ( ( n*( n + 1 ) )/2 ).
+* Before entry with UPLO = 'U' or 'u', the array AP must
+* contain the upper triangular part of the hermitian matrix
+* packed sequentially, column by column, so that AP( 1 )
+* contains a( 1, 1 ), AP( 2 ) and AP( 3 ) contain a( 1, 2 )
+* and a( 2, 2 ) respectively, and so on.
+* Before entry with UPLO = 'L' or 'l', the array AP must
+* contain the lower triangular part of the hermitian matrix
+* packed sequentially, column by column, so that AP( 1 )
+* contains a( 1, 1 ), AP( 2 ) and AP( 3 ) contain a( 2, 1 )
+* and a( 3, 1 ) respectively, and so on.
+* Note that the imaginary parts of the diagonal elements need
+* not be set and are assumed to be zero.
+* Unchanged on exit.
+*
+* X - COMPLEX*16 array of dimension at least
+* ( 1 + ( n - 1 )*abs( INCX ) ).
+* Before entry, the incremented array X must contain the n
+* element vector x.
+* Unchanged on exit.
+*
+* INCX - INTEGER.
+* On entry, INCX specifies the increment for the elements of
+* X. INCX must not be zero.
+* Unchanged on exit.
+*
+* BETA - COMPLEX*16 .
+* On entry, BETA specifies the scalar beta. When BETA is
+* supplied as zero then Y need not be set on input.
+* Unchanged on exit.
+*
+* Y - COMPLEX*16 array of dimension at least
+* ( 1 + ( n - 1 )*abs( INCY ) ).
+* Before entry, the incremented array Y must contain the n
+* element vector y. On exit, Y is overwritten by the updated
+* vector y.
+*
+* INCY - INTEGER.
+* On entry, INCY specifies the increment for the elements of
+* Y. INCY must not be zero.
+* Unchanged on exit.
+*
+* Further Details
+* ===============
+*
+* Level 2 Blas routine.
+*
+* -- Written on 22-October-1986.
+* Jack Dongarra, Argonne National Lab.
+* Jeremy Du Croz, Nag Central Office.
+* Sven Hammarling, Nag Central Office.
+* Richard Hanson, Sandia National Labs.
+*
+* =====================================================================
+*
+* .. Parameters ..
+ DOUBLE COMPLEX ONE
+ PARAMETER (ONE= (1.0D+0,0.0D+0))
+ DOUBLE COMPLEX ZERO
+ PARAMETER (ZERO= (0.0D+0,0.0D+0))
+* ..
+* .. Local Scalars ..
+ DOUBLE COMPLEX TEMP1,TEMP2
+ INTEGER I,INFO,IX,IY,J,JX,JY,K,KK,KX,KY
+* ..
+* .. External Functions ..
+ LOGICAL LSAME
+ EXTERNAL LSAME
+* ..
+* .. External Subroutines ..
+ EXTERNAL XERBLA
+* ..
+* .. Intrinsic Functions ..
+ INTRINSIC DBLE,DCONJG
+* ..
+*
+* Test the input parameters.
+*
+ INFO = 0
+ IF (.NOT.LSAME(UPLO,'U') .AND. .NOT.LSAME(UPLO,'L')) THEN
+ INFO = 1
+ ELSE IF (N.LT.0) THEN
+ INFO = 2
+ ELSE IF (INCX.EQ.0) THEN
+ INFO = 6
+ ELSE IF (INCY.EQ.0) THEN
+ INFO = 9
+ END IF
+ IF (INFO.NE.0) THEN
+ CALL XERBLA('ZHPMV ',INFO)
+ RETURN
+ END IF
+*
+* Quick return if possible.
+*
+ IF ((N.EQ.0) .OR. ((ALPHA.EQ.ZERO).AND. (BETA.EQ.ONE))) RETURN
+*
+* Set up the start points in X and Y.
+*
+ IF (INCX.GT.0) THEN
+ KX = 1
+ ELSE
+ KX = 1 - (N-1)*INCX
+ END IF
+ IF (INCY.GT.0) THEN
+ KY = 1
+ ELSE
+ KY = 1 - (N-1)*INCY
+ END IF
+*
+* Start the operations. In this version the elements of the array AP
+* are accessed sequentially with one pass through AP.
+*
+* First form y := beta*y.
+*
+ IF (BETA.NE.ONE) THEN
+ IF (INCY.EQ.1) THEN
+ IF (BETA.EQ.ZERO) THEN
+ DO 10 I = 1,N
+ Y(I) = ZERO
+ 10 CONTINUE
+ ELSE
+ DO 20 I = 1,N
+ Y(I) = BETA*Y(I)
+ 20 CONTINUE
+ END IF
+ ELSE
+ IY = KY
+ IF (BETA.EQ.ZERO) THEN
+ DO 30 I = 1,N
+ Y(IY) = ZERO
+ IY = IY + INCY
+ 30 CONTINUE
+ ELSE
+ DO 40 I = 1,N
+ Y(IY) = BETA*Y(IY)
+ IY = IY + INCY
+ 40 CONTINUE
+ END IF
+ END IF
+ END IF
+ IF (ALPHA.EQ.ZERO) RETURN
+ KK = 1
+ IF (LSAME(UPLO,'U')) THEN
+*
+* Form y when AP contains the upper triangle.
+*
+ IF ((INCX.EQ.1) .AND. (INCY.EQ.1)) THEN
+ DO 60 J = 1,N
+ TEMP1 = ALPHA*X(J)
+ TEMP2 = ZERO
+ K = KK
+ DO 50 I = 1,J - 1
+ Y(I) = Y(I) + TEMP1*AP(K)
+ TEMP2 = TEMP2 + DCONJG(AP(K))*X(I)
+ K = K + 1
+ 50 CONTINUE
+ Y(J) = Y(J) + TEMP1*DBLE(AP(KK+J-1)) + ALPHA*TEMP2
+ KK = KK + J
+ 60 CONTINUE
+ ELSE
+ JX = KX
+ JY = KY
+ DO 80 J = 1,N
+ TEMP1 = ALPHA*X(JX)
+ TEMP2 = ZERO
+ IX = KX
+ IY = KY
+ DO 70 K = KK,KK + J - 2
+ Y(IY) = Y(IY) + TEMP1*AP(K)
+ TEMP2 = TEMP2 + DCONJG(AP(K))*X(IX)
+ IX = IX + INCX
+ IY = IY + INCY
+ 70 CONTINUE
+ Y(JY) = Y(JY) + TEMP1*DBLE(AP(KK+J-1)) + ALPHA*TEMP2
+ JX = JX + INCX
+ JY = JY + INCY
+ KK = KK + J
+ 80 CONTINUE
+ END IF
+ ELSE
+*
+* Form y when AP contains the lower triangle.
+*
+ IF ((INCX.EQ.1) .AND. (INCY.EQ.1)) THEN
+ DO 100 J = 1,N
+ TEMP1 = ALPHA*X(J)
+ TEMP2 = ZERO
+ Y(J) = Y(J) + TEMP1*DBLE(AP(KK))
+ K = KK + 1
+ DO 90 I = J + 1,N
+ Y(I) = Y(I) + TEMP1*AP(K)
+ TEMP2 = TEMP2 + DCONJG(AP(K))*X(I)
+ K = K + 1
+ 90 CONTINUE
+ Y(J) = Y(J) + ALPHA*TEMP2
+ KK = KK + (N-J+1)
+ 100 CONTINUE
+ ELSE
+ JX = KX
+ JY = KY
+ DO 120 J = 1,N
+ TEMP1 = ALPHA*X(JX)
+ TEMP2 = ZERO
+ Y(JY) = Y(JY) + TEMP1*DBLE(AP(KK))
+ IX = JX
+ IY = JY
+ DO 110 K = KK + 1,KK + N - J
+ IX = IX + INCX
+ IY = IY + INCY
+ Y(IY) = Y(IY) + TEMP1*AP(K)
+ TEMP2 = TEMP2 + DCONJG(AP(K))*X(IX)
+ 110 CONTINUE
+ Y(JY) = Y(JY) + ALPHA*TEMP2
+ JX = JX + INCX
+ JY = JY + INCY
+ KK = KK + (N-J+1)
+ 120 CONTINUE
+ END IF
+ END IF
+*
+ RETURN
+*
+* End of ZHPMV .
+*
+ END
diff --git a/blas/zhpr.f b/blas/zhpr.f
new file mode 100644
index 000000000..40efbc7d5
--- /dev/null
+++ b/blas/zhpr.f
@@ -0,0 +1,220 @@
+ SUBROUTINE ZHPR(UPLO,N,ALPHA,X,INCX,AP)
+* .. Scalar Arguments ..
+ DOUBLE PRECISION ALPHA
+ INTEGER INCX,N
+ CHARACTER UPLO
+* ..
+* .. Array Arguments ..
+ DOUBLE COMPLEX AP(*),X(*)
+* ..
+*
+* Purpose
+* =======
+*
+* ZHPR performs the hermitian rank 1 operation
+*
+* A := alpha*x*conjg( x' ) + A,
+*
+* where alpha is a real scalar, x is an n element vector and A is an
+* n by n hermitian matrix, supplied in packed form.
+*
+* Arguments
+* ==========
+*
+* UPLO - CHARACTER*1.
+* On entry, UPLO specifies whether the upper or lower
+* triangular part of the matrix A is supplied in the packed
+* array AP as follows:
+*
+* UPLO = 'U' or 'u' The upper triangular part of A is
+* supplied in AP.
+*
+* UPLO = 'L' or 'l' The lower triangular part of A is
+* supplied in AP.
+*
+* Unchanged on exit.
+*
+* N - INTEGER.
+* On entry, N specifies the order of the matrix A.
+* N must be at least zero.
+* Unchanged on exit.
+*
+* ALPHA - DOUBLE PRECISION.
+* On entry, ALPHA specifies the scalar alpha.
+* Unchanged on exit.
+*
+* X - COMPLEX*16 array of dimension at least
+* ( 1 + ( n - 1 )*abs( INCX ) ).
+* Before entry, the incremented array X must contain the n
+* element vector x.
+* Unchanged on exit.
+*
+* INCX - INTEGER.
+* On entry, INCX specifies the increment for the elements of
+* X. INCX must not be zero.
+* Unchanged on exit.
+*
+* AP - COMPLEX*16 array of DIMENSION at least
+* ( ( n*( n + 1 ) )/2 ).
+* Before entry with UPLO = 'U' or 'u', the array AP must
+* contain the upper triangular part of the hermitian matrix
+* packed sequentially, column by column, so that AP( 1 )
+* contains a( 1, 1 ), AP( 2 ) and AP( 3 ) contain a( 1, 2 )
+* and a( 2, 2 ) respectively, and so on. On exit, the array
+* AP is overwritten by the upper triangular part of the
+* updated matrix.
+* Before entry with UPLO = 'L' or 'l', the array AP must
+* contain the lower triangular part of the hermitian matrix
+* packed sequentially, column by column, so that AP( 1 )
+* contains a( 1, 1 ), AP( 2 ) and AP( 3 ) contain a( 2, 1 )
+* and a( 3, 1 ) respectively, and so on. On exit, the array
+* AP is overwritten by the lower triangular part of the
+* updated matrix.
+* Note that the imaginary parts of the diagonal elements need
+* not be set, they are assumed to be zero, and on exit they
+* are set to zero.
+*
+* Further Details
+* ===============
+*
+* Level 2 Blas routine.
+*
+* -- Written on 22-October-1986.
+* Jack Dongarra, Argonne National Lab.
+* Jeremy Du Croz, Nag Central Office.
+* Sven Hammarling, Nag Central Office.
+* Richard Hanson, Sandia National Labs.
+*
+* =====================================================================
+*
+* .. Parameters ..
+ DOUBLE COMPLEX ZERO
+ PARAMETER (ZERO= (0.0D+0,0.0D+0))
+* ..
+* .. Local Scalars ..
+ DOUBLE COMPLEX TEMP
+ INTEGER I,INFO,IX,J,JX,K,KK,KX
+* ..
+* .. External Functions ..
+ LOGICAL LSAME
+ EXTERNAL LSAME
+* ..
+* .. External Subroutines ..
+ EXTERNAL XERBLA
+* ..
+* .. Intrinsic Functions ..
+ INTRINSIC DBLE,DCONJG
+* ..
+*
+* Test the input parameters.
+*
+ INFO = 0
+ IF (.NOT.LSAME(UPLO,'U') .AND. .NOT.LSAME(UPLO,'L')) THEN
+ INFO = 1
+ ELSE IF (N.LT.0) THEN
+ INFO = 2
+ ELSE IF (INCX.EQ.0) THEN
+ INFO = 5
+ END IF
+ IF (INFO.NE.0) THEN
+ CALL XERBLA('ZHPR ',INFO)
+ RETURN
+ END IF
+*
+* Quick return if possible.
+*
+ IF ((N.EQ.0) .OR. (ALPHA.EQ.DBLE(ZERO))) RETURN
+*
+* Set the start point in X if the increment is not unity.
+*
+ IF (INCX.LE.0) THEN
+ KX = 1 - (N-1)*INCX
+ ELSE IF (INCX.NE.1) THEN
+ KX = 1
+ END IF
+*
+* Start the operations. In this version the elements of the array AP
+* are accessed sequentially with one pass through AP.
+*
+ KK = 1
+ IF (LSAME(UPLO,'U')) THEN
+*
+* Form A when upper triangle is stored in AP.
+*
+ IF (INCX.EQ.1) THEN
+ DO 20 J = 1,N
+ IF (X(J).NE.ZERO) THEN
+ TEMP = ALPHA*DCONJG(X(J))
+ K = KK
+ DO 10 I = 1,J - 1
+ AP(K) = AP(K) + X(I)*TEMP
+ K = K + 1
+ 10 CONTINUE
+ AP(KK+J-1) = DBLE(AP(KK+J-1)) + DBLE(X(J)*TEMP)
+ ELSE
+ AP(KK+J-1) = DBLE(AP(KK+J-1))
+ END IF
+ KK = KK + J
+ 20 CONTINUE
+ ELSE
+ JX = KX
+ DO 40 J = 1,N
+ IF (X(JX).NE.ZERO) THEN
+ TEMP = ALPHA*DCONJG(X(JX))
+ IX = KX
+ DO 30 K = KK,KK + J - 2
+ AP(K) = AP(K) + X(IX)*TEMP
+ IX = IX + INCX
+ 30 CONTINUE
+ AP(KK+J-1) = DBLE(AP(KK+J-1)) + DBLE(X(JX)*TEMP)
+ ELSE
+ AP(KK+J-1) = DBLE(AP(KK+J-1))
+ END IF
+ JX = JX + INCX
+ KK = KK + J
+ 40 CONTINUE
+ END IF
+ ELSE
+*
+* Form A when lower triangle is stored in AP.
+*
+ IF (INCX.EQ.1) THEN
+ DO 60 J = 1,N
+ IF (X(J).NE.ZERO) THEN
+ TEMP = ALPHA*DCONJG(X(J))
+ AP(KK) = DBLE(AP(KK)) + DBLE(TEMP*X(J))
+ K = KK + 1
+ DO 50 I = J + 1,N
+ AP(K) = AP(K) + X(I)*TEMP
+ K = K + 1
+ 50 CONTINUE
+ ELSE
+ AP(KK) = DBLE(AP(KK))
+ END IF
+ KK = KK + N - J + 1
+ 60 CONTINUE
+ ELSE
+ JX = KX
+ DO 80 J = 1,N
+ IF (X(JX).NE.ZERO) THEN
+ TEMP = ALPHA*DCONJG(X(JX))
+ AP(KK) = DBLE(AP(KK)) + DBLE(TEMP*X(JX))
+ IX = JX
+ DO 70 K = KK + 1,KK + N - J
+ IX = IX + INCX
+ AP(K) = AP(K) + X(IX)*TEMP
+ 70 CONTINUE
+ ELSE
+ AP(KK) = DBLE(AP(KK))
+ END IF
+ JX = JX + INCX
+ KK = KK + N - J + 1
+ 80 CONTINUE
+ END IF
+ END IF
+*
+ RETURN
+*
+* End of ZHPR .
+*
+ END
diff --git a/blas/zhpr2.f b/blas/zhpr2.f
new file mode 100644
index 000000000..99977462e
--- /dev/null
+++ b/blas/zhpr2.f
@@ -0,0 +1,255 @@
+ SUBROUTINE ZHPR2(UPLO,N,ALPHA,X,INCX,Y,INCY,AP)
+* .. Scalar Arguments ..
+ DOUBLE COMPLEX ALPHA
+ INTEGER INCX,INCY,N
+ CHARACTER UPLO
+* ..
+* .. Array Arguments ..
+ DOUBLE COMPLEX AP(*),X(*),Y(*)
+* ..
+*
+* Purpose
+* =======
+*
+* ZHPR2 performs the hermitian rank 2 operation
+*
+* A := alpha*x*conjg( y' ) + conjg( alpha )*y*conjg( x' ) + A,
+*
+* where alpha is a scalar, x and y are n element vectors and A is an
+* n by n hermitian matrix, supplied in packed form.
+*
+* Arguments
+* ==========
+*
+* UPLO - CHARACTER*1.
+* On entry, UPLO specifies whether the upper or lower
+* triangular part of the matrix A is supplied in the packed
+* array AP as follows:
+*
+* UPLO = 'U' or 'u' The upper triangular part of A is
+* supplied in AP.
+*
+* UPLO = 'L' or 'l' The lower triangular part of A is
+* supplied in AP.
+*
+* Unchanged on exit.
+*
+* N - INTEGER.
+* On entry, N specifies the order of the matrix A.
+* N must be at least zero.
+* Unchanged on exit.
+*
+* ALPHA - COMPLEX*16 .
+* On entry, ALPHA specifies the scalar alpha.
+* Unchanged on exit.
+*
+* X - COMPLEX*16 array of dimension at least
+* ( 1 + ( n - 1 )*abs( INCX ) ).
+* Before entry, the incremented array X must contain the n
+* element vector x.
+* Unchanged on exit.
+*
+* INCX - INTEGER.
+* On entry, INCX specifies the increment for the elements of
+* X. INCX must not be zero.
+* Unchanged on exit.
+*
+* Y - COMPLEX*16 array of dimension at least
+* ( 1 + ( n - 1 )*abs( INCY ) ).
+* Before entry, the incremented array Y must contain the n
+* element vector y.
+* Unchanged on exit.
+*
+* INCY - INTEGER.
+* On entry, INCY specifies the increment for the elements of
+* Y. INCY must not be zero.
+* Unchanged on exit.
+*
+* AP - COMPLEX*16 array of DIMENSION at least
+* ( ( n*( n + 1 ) )/2 ).
+* Before entry with UPLO = 'U' or 'u', the array AP must
+* contain the upper triangular part of the hermitian matrix
+* packed sequentially, column by column, so that AP( 1 )
+* contains a( 1, 1 ), AP( 2 ) and AP( 3 ) contain a( 1, 2 )
+* and a( 2, 2 ) respectively, and so on. On exit, the array
+* AP is overwritten by the upper triangular part of the
+* updated matrix.
+* Before entry with UPLO = 'L' or 'l', the array AP must
+* contain the lower triangular part of the hermitian matrix
+* packed sequentially, column by column, so that AP( 1 )
+* contains a( 1, 1 ), AP( 2 ) and AP( 3 ) contain a( 2, 1 )
+* and a( 3, 1 ) respectively, and so on. On exit, the array
+* AP is overwritten by the lower triangular part of the
+* updated matrix.
+* Note that the imaginary parts of the diagonal elements need
+* not be set, they are assumed to be zero, and on exit they
+* are set to zero.
+*
+* Further Details
+* ===============
+*
+* Level 2 Blas routine.
+*
+* -- Written on 22-October-1986.
+* Jack Dongarra, Argonne National Lab.
+* Jeremy Du Croz, Nag Central Office.
+* Sven Hammarling, Nag Central Office.
+* Richard Hanson, Sandia National Labs.
+*
+* =====================================================================
+*
+* .. Parameters ..
+ DOUBLE COMPLEX ZERO
+ PARAMETER (ZERO= (0.0D+0,0.0D+0))
+* ..
+* .. Local Scalars ..
+ DOUBLE COMPLEX TEMP1,TEMP2
+ INTEGER I,INFO,IX,IY,J,JX,JY,K,KK,KX,KY
+* ..
+* .. External Functions ..
+ LOGICAL LSAME
+ EXTERNAL LSAME
+* ..
+* .. External Subroutines ..
+ EXTERNAL XERBLA
+* ..
+* .. Intrinsic Functions ..
+ INTRINSIC DBLE,DCONJG
+* ..
+*
+* Test the input parameters.
+*
+ INFO = 0
+ IF (.NOT.LSAME(UPLO,'U') .AND. .NOT.LSAME(UPLO,'L')) THEN
+ INFO = 1
+ ELSE IF (N.LT.0) THEN
+ INFO = 2
+ ELSE IF (INCX.EQ.0) THEN
+ INFO = 5
+ ELSE IF (INCY.EQ.0) THEN
+ INFO = 7
+ END IF
+ IF (INFO.NE.0) THEN
+ CALL XERBLA('ZHPR2 ',INFO)
+ RETURN
+ END IF
+*
+* Quick return if possible.
+*
+ IF ((N.EQ.0) .OR. (ALPHA.EQ.ZERO)) RETURN
+*
+* Set up the start points in X and Y if the increments are not both
+* unity.
+*
+ IF ((INCX.NE.1) .OR. (INCY.NE.1)) THEN
+ IF (INCX.GT.0) THEN
+ KX = 1
+ ELSE
+ KX = 1 - (N-1)*INCX
+ END IF
+ IF (INCY.GT.0) THEN
+ KY = 1
+ ELSE
+ KY = 1 - (N-1)*INCY
+ END IF
+ JX = KX
+ JY = KY
+ END IF
+*
+* Start the operations. In this version the elements of the array AP
+* are accessed sequentially with one pass through AP.
+*
+ KK = 1
+ IF (LSAME(UPLO,'U')) THEN
+*
+* Form A when upper triangle is stored in AP.
+*
+ IF ((INCX.EQ.1) .AND. (INCY.EQ.1)) THEN
+ DO 20 J = 1,N
+ IF ((X(J).NE.ZERO) .OR. (Y(J).NE.ZERO)) THEN
+ TEMP1 = ALPHA*DCONJG(Y(J))
+ TEMP2 = DCONJG(ALPHA*X(J))
+ K = KK
+ DO 10 I = 1,J - 1
+ AP(K) = AP(K) + X(I)*TEMP1 + Y(I)*TEMP2
+ K = K + 1
+ 10 CONTINUE
+ AP(KK+J-1) = DBLE(AP(KK+J-1)) +
+ + DBLE(X(J)*TEMP1+Y(J)*TEMP2)
+ ELSE
+ AP(KK+J-1) = DBLE(AP(KK+J-1))
+ END IF
+ KK = KK + J
+ 20 CONTINUE
+ ELSE
+ DO 40 J = 1,N
+ IF ((X(JX).NE.ZERO) .OR. (Y(JY).NE.ZERO)) THEN
+ TEMP1 = ALPHA*DCONJG(Y(JY))
+ TEMP2 = DCONJG(ALPHA*X(JX))
+ IX = KX
+ IY = KY
+ DO 30 K = KK,KK + J - 2
+ AP(K) = AP(K) + X(IX)*TEMP1 + Y(IY)*TEMP2
+ IX = IX + INCX
+ IY = IY + INCY
+ 30 CONTINUE
+ AP(KK+J-1) = DBLE(AP(KK+J-1)) +
+ + DBLE(X(JX)*TEMP1+Y(JY)*TEMP2)
+ ELSE
+ AP(KK+J-1) = DBLE(AP(KK+J-1))
+ END IF
+ JX = JX + INCX
+ JY = JY + INCY
+ KK = KK + J
+ 40 CONTINUE
+ END IF
+ ELSE
+*
+* Form A when lower triangle is stored in AP.
+*
+ IF ((INCX.EQ.1) .AND. (INCY.EQ.1)) THEN
+ DO 60 J = 1,N
+ IF ((X(J).NE.ZERO) .OR. (Y(J).NE.ZERO)) THEN
+ TEMP1 = ALPHA*DCONJG(Y(J))
+ TEMP2 = DCONJG(ALPHA*X(J))
+ AP(KK) = DBLE(AP(KK)) +
+ + DBLE(X(J)*TEMP1+Y(J)*TEMP2)
+ K = KK + 1
+ DO 50 I = J + 1,N
+ AP(K) = AP(K) + X(I)*TEMP1 + Y(I)*TEMP2
+ K = K + 1
+ 50 CONTINUE
+ ELSE
+ AP(KK) = DBLE(AP(KK))
+ END IF
+ KK = KK + N - J + 1
+ 60 CONTINUE
+ ELSE
+ DO 80 J = 1,N
+ IF ((X(JX).NE.ZERO) .OR. (Y(JY).NE.ZERO)) THEN
+ TEMP1 = ALPHA*DCONJG(Y(JY))
+ TEMP2 = DCONJG(ALPHA*X(JX))
+ AP(KK) = DBLE(AP(KK)) +
+ + DBLE(X(JX)*TEMP1+Y(JY)*TEMP2)
+ IX = JX
+ IY = JY
+ DO 70 K = KK + 1,KK + N - J
+ IX = IX + INCX
+ IY = IY + INCY
+ AP(K) = AP(K) + X(IX)*TEMP1 + Y(IY)*TEMP2
+ 70 CONTINUE
+ ELSE
+ AP(KK) = DBLE(AP(KK))
+ END IF
+ JX = JX + INCX
+ JY = JY + INCY
+ KK = KK + N - J + 1
+ 80 CONTINUE
+ END IF
+ END IF
+*
+ RETURN
+*
+* End of ZHPR2 .
+*
+ END
diff --git a/blas/ztbmv.f b/blas/ztbmv.f
new file mode 100644
index 000000000..7c85c1b55
--- /dev/null
+++ b/blas/ztbmv.f
@@ -0,0 +1,366 @@
+ SUBROUTINE ZTBMV(UPLO,TRANS,DIAG,N,K,A,LDA,X,INCX)
+* .. Scalar Arguments ..
+ INTEGER INCX,K,LDA,N
+ CHARACTER DIAG,TRANS,UPLO
+* ..
+* .. Array Arguments ..
+ DOUBLE COMPLEX A(LDA,*),X(*)
+* ..
+*
+* Purpose
+* =======
+*
+* ZTBMV performs one of the matrix-vector operations
+*
+* x := A*x, or x := A'*x, or x := conjg( A' )*x,
+*
+* where x is an n element vector and A is an n by n unit, or non-unit,
+* upper or lower triangular band matrix, with ( k + 1 ) diagonals.
+*
+* Arguments
+* ==========
+*
+* UPLO - CHARACTER*1.
+* On entry, UPLO specifies whether the matrix is an upper or
+* lower triangular matrix as follows:
+*
+* UPLO = 'U' or 'u' A is an upper triangular matrix.
+*
+* UPLO = 'L' or 'l' A is a lower triangular matrix.
+*
+* Unchanged on exit.
+*
+* TRANS - CHARACTER*1.
+* On entry, TRANS specifies the operation to be performed as
+* follows:
+*
+* TRANS = 'N' or 'n' x := A*x.
+*
+* TRANS = 'T' or 't' x := A'*x.
+*
+* TRANS = 'C' or 'c' x := conjg( A' )*x.
+*
+* Unchanged on exit.
+*
+* DIAG - CHARACTER*1.
+* On entry, DIAG specifies whether or not A is unit
+* triangular as follows:
+*
+* DIAG = 'U' or 'u' A is assumed to be unit triangular.
+*
+* DIAG = 'N' or 'n' A is not assumed to be unit
+* triangular.
+*
+* Unchanged on exit.
+*
+* N - INTEGER.
+* On entry, N specifies the order of the matrix A.
+* N must be at least zero.
+* Unchanged on exit.
+*
+* K - INTEGER.
+* On entry with UPLO = 'U' or 'u', K specifies the number of
+* super-diagonals of the matrix A.
+* On entry with UPLO = 'L' or 'l', K specifies the number of
+* sub-diagonals of the matrix A.
+* K must satisfy 0 .le. K.
+* Unchanged on exit.
+*
+* A - COMPLEX*16 array of DIMENSION ( LDA, n ).
+* Before entry with UPLO = 'U' or 'u', the leading ( k + 1 )
+* by n part of the array A must contain the upper triangular
+* band part of the matrix of coefficients, supplied column by
+* column, with the leading diagonal of the matrix in row
+* ( k + 1 ) of the array, the first super-diagonal starting at
+* position 2 in row k, and so on. The top left k by k triangle
+* of the array A is not referenced.
+* The following program segment will transfer an upper
+* triangular band matrix from conventional full matrix storage
+* to band storage:
+*
+* DO 20, J = 1, N
+* M = K + 1 - J
+* DO 10, I = MAX( 1, J - K ), J
+* A( M + I, J ) = matrix( I, J )
+* 10 CONTINUE
+* 20 CONTINUE
+*
+* Before entry with UPLO = 'L' or 'l', the leading ( k + 1 )
+* by n part of the array A must contain the lower triangular
+* band part of the matrix of coefficients, supplied column by
+* column, with the leading diagonal of the matrix in row 1 of
+* the array, the first sub-diagonal starting at position 1 in
+* row 2, and so on. The bottom right k by k triangle of the
+* array A is not referenced.
+* The following program segment will transfer a lower
+* triangular band matrix from conventional full matrix storage
+* to band storage:
+*
+* DO 20, J = 1, N
+* M = 1 - J
+* DO 10, I = J, MIN( N, J + K )
+* A( M + I, J ) = matrix( I, J )
+* 10 CONTINUE
+* 20 CONTINUE
+*
+* Note that when DIAG = 'U' or 'u' the elements of the array A
+* corresponding to the diagonal elements of the matrix are not
+* referenced, but are assumed to be unity.
+* Unchanged on exit.
+*
+* LDA - INTEGER.
+* On entry, LDA specifies the first dimension of A as declared
+* in the calling (sub) program. LDA must be at least
+* ( k + 1 ).
+* Unchanged on exit.
+*
+* X - COMPLEX*16 array of dimension at least
+* ( 1 + ( n - 1 )*abs( INCX ) ).
+* Before entry, the incremented array X must contain the n
+* element vector x. On exit, X is overwritten with the
+* tranformed vector x.
+*
+* INCX - INTEGER.
+* On entry, INCX specifies the increment for the elements of
+* X. INCX must not be zero.
+* Unchanged on exit.
+*
+* Further Details
+* ===============
+*
+* Level 2 Blas routine.
+*
+* -- Written on 22-October-1986.
+* Jack Dongarra, Argonne National Lab.
+* Jeremy Du Croz, Nag Central Office.
+* Sven Hammarling, Nag Central Office.
+* Richard Hanson, Sandia National Labs.
+*
+* =====================================================================
+*
+* .. Parameters ..
+ DOUBLE COMPLEX ZERO
+ PARAMETER (ZERO= (0.0D+0,0.0D+0))
+* ..
+* .. Local Scalars ..
+ DOUBLE COMPLEX TEMP
+ INTEGER I,INFO,IX,J,JX,KPLUS1,KX,L
+ LOGICAL NOCONJ,NOUNIT
+* ..
+* .. External Functions ..
+ LOGICAL LSAME
+ EXTERNAL LSAME
+* ..
+* .. External Subroutines ..
+ EXTERNAL XERBLA
+* ..
+* .. Intrinsic Functions ..
+ INTRINSIC DCONJG,MAX,MIN
+* ..
+*
+* Test the input parameters.
+*
+ INFO = 0
+ IF (.NOT.LSAME(UPLO,'U') .AND. .NOT.LSAME(UPLO,'L')) THEN
+ INFO = 1
+ ELSE IF (.NOT.LSAME(TRANS,'N') .AND. .NOT.LSAME(TRANS,'T') .AND.
+ + .NOT.LSAME(TRANS,'C')) THEN
+ INFO = 2
+ ELSE IF (.NOT.LSAME(DIAG,'U') .AND. .NOT.LSAME(DIAG,'N')) THEN
+ INFO = 3
+ ELSE IF (N.LT.0) THEN
+ INFO = 4
+ ELSE IF (K.LT.0) THEN
+ INFO = 5
+ ELSE IF (LDA.LT. (K+1)) THEN
+ INFO = 7
+ ELSE IF (INCX.EQ.0) THEN
+ INFO = 9
+ END IF
+ IF (INFO.NE.0) THEN
+ CALL XERBLA('ZTBMV ',INFO)
+ RETURN
+ END IF
+*
+* Quick return if possible.
+*
+ IF (N.EQ.0) RETURN
+*
+ NOCONJ = LSAME(TRANS,'T')
+ NOUNIT = LSAME(DIAG,'N')
+*
+* Set up the start point in X if the increment is not unity. This
+* will be ( N - 1 )*INCX too small for descending loops.
+*
+ IF (INCX.LE.0) THEN
+ KX = 1 - (N-1)*INCX
+ ELSE IF (INCX.NE.1) THEN
+ KX = 1
+ END IF
+*
+* Start the operations. In this version the elements of A are
+* accessed sequentially with one pass through A.
+*
+ IF (LSAME(TRANS,'N')) THEN
+*
+* Form x := A*x.
+*
+ IF (LSAME(UPLO,'U')) THEN
+ KPLUS1 = K + 1
+ IF (INCX.EQ.1) THEN
+ DO 20 J = 1,N
+ IF (X(J).NE.ZERO) THEN
+ TEMP = X(J)
+ L = KPLUS1 - J
+ DO 10 I = MAX(1,J-K),J - 1
+ X(I) = X(I) + TEMP*A(L+I,J)
+ 10 CONTINUE
+ IF (NOUNIT) X(J) = X(J)*A(KPLUS1,J)
+ END IF
+ 20 CONTINUE
+ ELSE
+ JX = KX
+ DO 40 J = 1,N
+ IF (X(JX).NE.ZERO) THEN
+ TEMP = X(JX)
+ IX = KX
+ L = KPLUS1 - J
+ DO 30 I = MAX(1,J-K),J - 1
+ X(IX) = X(IX) + TEMP*A(L+I,J)
+ IX = IX + INCX
+ 30 CONTINUE
+ IF (NOUNIT) X(JX) = X(JX)*A(KPLUS1,J)
+ END IF
+ JX = JX + INCX
+ IF (J.GT.K) KX = KX + INCX
+ 40 CONTINUE
+ END IF
+ ELSE
+ IF (INCX.EQ.1) THEN
+ DO 60 J = N,1,-1
+ IF (X(J).NE.ZERO) THEN
+ TEMP = X(J)
+ L = 1 - J
+ DO 50 I = MIN(N,J+K),J + 1,-1
+ X(I) = X(I) + TEMP*A(L+I,J)
+ 50 CONTINUE
+ IF (NOUNIT) X(J) = X(J)*A(1,J)
+ END IF
+ 60 CONTINUE
+ ELSE
+ KX = KX + (N-1)*INCX
+ JX = KX
+ DO 80 J = N,1,-1
+ IF (X(JX).NE.ZERO) THEN
+ TEMP = X(JX)
+ IX = KX
+ L = 1 - J
+ DO 70 I = MIN(N,J+K),J + 1,-1
+ X(IX) = X(IX) + TEMP*A(L+I,J)
+ IX = IX - INCX
+ 70 CONTINUE
+ IF (NOUNIT) X(JX) = X(JX)*A(1,J)
+ END IF
+ JX = JX - INCX
+ IF ((N-J).GE.K) KX = KX - INCX
+ 80 CONTINUE
+ END IF
+ END IF
+ ELSE
+*
+* Form x := A'*x or x := conjg( A' )*x.
+*
+ IF (LSAME(UPLO,'U')) THEN
+ KPLUS1 = K + 1
+ IF (INCX.EQ.1) THEN
+ DO 110 J = N,1,-1
+ TEMP = X(J)
+ L = KPLUS1 - J
+ IF (NOCONJ) THEN
+ IF (NOUNIT) TEMP = TEMP*A(KPLUS1,J)
+ DO 90 I = J - 1,MAX(1,J-K),-1
+ TEMP = TEMP + A(L+I,J)*X(I)
+ 90 CONTINUE
+ ELSE
+ IF (NOUNIT) TEMP = TEMP*DCONJG(A(KPLUS1,J))
+ DO 100 I = J - 1,MAX(1,J-K),-1
+ TEMP = TEMP + DCONJG(A(L+I,J))*X(I)
+ 100 CONTINUE
+ END IF
+ X(J) = TEMP
+ 110 CONTINUE
+ ELSE
+ KX = KX + (N-1)*INCX
+ JX = KX
+ DO 140 J = N,1,-1
+ TEMP = X(JX)
+ KX = KX - INCX
+ IX = KX
+ L = KPLUS1 - J
+ IF (NOCONJ) THEN
+ IF (NOUNIT) TEMP = TEMP*A(KPLUS1,J)
+ DO 120 I = J - 1,MAX(1,J-K),-1
+ TEMP = TEMP + A(L+I,J)*X(IX)
+ IX = IX - INCX
+ 120 CONTINUE
+ ELSE
+ IF (NOUNIT) TEMP = TEMP*DCONJG(A(KPLUS1,J))
+ DO 130 I = J - 1,MAX(1,J-K),-1
+ TEMP = TEMP + DCONJG(A(L+I,J))*X(IX)
+ IX = IX - INCX
+ 130 CONTINUE
+ END IF
+ X(JX) = TEMP
+ JX = JX - INCX
+ 140 CONTINUE
+ END IF
+ ELSE
+ IF (INCX.EQ.1) THEN
+ DO 170 J = 1,N
+ TEMP = X(J)
+ L = 1 - J
+ IF (NOCONJ) THEN
+ IF (NOUNIT) TEMP = TEMP*A(1,J)
+ DO 150 I = J + 1,MIN(N,J+K)
+ TEMP = TEMP + A(L+I,J)*X(I)
+ 150 CONTINUE
+ ELSE
+ IF (NOUNIT) TEMP = TEMP*DCONJG(A(1,J))
+ DO 160 I = J + 1,MIN(N,J+K)
+ TEMP = TEMP + DCONJG(A(L+I,J))*X(I)
+ 160 CONTINUE
+ END IF
+ X(J) = TEMP
+ 170 CONTINUE
+ ELSE
+ JX = KX
+ DO 200 J = 1,N
+ TEMP = X(JX)
+ KX = KX + INCX
+ IX = KX
+ L = 1 - J
+ IF (NOCONJ) THEN
+ IF (NOUNIT) TEMP = TEMP*A(1,J)
+ DO 180 I = J + 1,MIN(N,J+K)
+ TEMP = TEMP + A(L+I,J)*X(IX)
+ IX = IX + INCX
+ 180 CONTINUE
+ ELSE
+ IF (NOUNIT) TEMP = TEMP*DCONJG(A(1,J))
+ DO 190 I = J + 1,MIN(N,J+K)
+ TEMP = TEMP + DCONJG(A(L+I,J))*X(IX)
+ IX = IX + INCX
+ 190 CONTINUE
+ END IF
+ X(JX) = TEMP
+ JX = JX + INCX
+ 200 CONTINUE
+ END IF
+ END IF
+ END IF
+*
+ RETURN
+*
+* End of ZTBMV .
+*
+ END
diff --git a/blas/ztpmv.f b/blas/ztpmv.f
new file mode 100644
index 000000000..5a7b3b8b7
--- /dev/null
+++ b/blas/ztpmv.f
@@ -0,0 +1,329 @@
+ SUBROUTINE ZTPMV(UPLO,TRANS,DIAG,N,AP,X,INCX)
+* .. Scalar Arguments ..
+ INTEGER INCX,N
+ CHARACTER DIAG,TRANS,UPLO
+* ..
+* .. Array Arguments ..
+ DOUBLE COMPLEX AP(*),X(*)
+* ..
+*
+* Purpose
+* =======
+*
+* ZTPMV performs one of the matrix-vector operations
+*
+* x := A*x, or x := A'*x, or x := conjg( A' )*x,
+*
+* where x is an n element vector and A is an n by n unit, or non-unit,
+* upper or lower triangular matrix, supplied in packed form.
+*
+* Arguments
+* ==========
+*
+* UPLO - CHARACTER*1.
+* On entry, UPLO specifies whether the matrix is an upper or
+* lower triangular matrix as follows:
+*
+* UPLO = 'U' or 'u' A is an upper triangular matrix.
+*
+* UPLO = 'L' or 'l' A is a lower triangular matrix.
+*
+* Unchanged on exit.
+*
+* TRANS - CHARACTER*1.
+* On entry, TRANS specifies the operation to be performed as
+* follows:
+*
+* TRANS = 'N' or 'n' x := A*x.
+*
+* TRANS = 'T' or 't' x := A'*x.
+*
+* TRANS = 'C' or 'c' x := conjg( A' )*x.
+*
+* Unchanged on exit.
+*
+* DIAG - CHARACTER*1.
+* On entry, DIAG specifies whether or not A is unit
+* triangular as follows:
+*
+* DIAG = 'U' or 'u' A is assumed to be unit triangular.
+*
+* DIAG = 'N' or 'n' A is not assumed to be unit
+* triangular.
+*
+* Unchanged on exit.
+*
+* N - INTEGER.
+* On entry, N specifies the order of the matrix A.
+* N must be at least zero.
+* Unchanged on exit.
+*
+* AP - COMPLEX*16 array of DIMENSION at least
+* ( ( n*( n + 1 ) )/2 ).
+* Before entry with UPLO = 'U' or 'u', the array AP must
+* contain the upper triangular matrix packed sequentially,
+* column by column, so that AP( 1 ) contains a( 1, 1 ),
+* AP( 2 ) and AP( 3 ) contain a( 1, 2 ) and a( 2, 2 )
+* respectively, and so on.
+* Before entry with UPLO = 'L' or 'l', the array AP must
+* contain the lower triangular matrix packed sequentially,
+* column by column, so that AP( 1 ) contains a( 1, 1 ),
+* AP( 2 ) and AP( 3 ) contain a( 2, 1 ) and a( 3, 1 )
+* respectively, and so on.
+* Note that when DIAG = 'U' or 'u', the diagonal elements of
+* A are not referenced, but are assumed to be unity.
+* Unchanged on exit.
+*
+* X - COMPLEX*16 array of dimension at least
+* ( 1 + ( n - 1 )*abs( INCX ) ).
+* Before entry, the incremented array X must contain the n
+* element vector x. On exit, X is overwritten with the
+* tranformed vector x.
+*
+* INCX - INTEGER.
+* On entry, INCX specifies the increment for the elements of
+* X. INCX must not be zero.
+* Unchanged on exit.
+*
+* Further Details
+* ===============
+*
+* Level 2 Blas routine.
+*
+* -- Written on 22-October-1986.
+* Jack Dongarra, Argonne National Lab.
+* Jeremy Du Croz, Nag Central Office.
+* Sven Hammarling, Nag Central Office.
+* Richard Hanson, Sandia National Labs.
+*
+* =====================================================================
+*
+* .. Parameters ..
+ DOUBLE COMPLEX ZERO
+ PARAMETER (ZERO= (0.0D+0,0.0D+0))
+* ..
+* .. Local Scalars ..
+ DOUBLE COMPLEX TEMP
+ INTEGER I,INFO,IX,J,JX,K,KK,KX
+ LOGICAL NOCONJ,NOUNIT
+* ..
+* .. External Functions ..
+ LOGICAL LSAME
+ EXTERNAL LSAME
+* ..
+* .. External Subroutines ..
+ EXTERNAL XERBLA
+* ..
+* .. Intrinsic Functions ..
+ INTRINSIC DCONJG
+* ..
+*
+* Test the input parameters.
+*
+ INFO = 0
+ IF (.NOT.LSAME(UPLO,'U') .AND. .NOT.LSAME(UPLO,'L')) THEN
+ INFO = 1
+ ELSE IF (.NOT.LSAME(TRANS,'N') .AND. .NOT.LSAME(TRANS,'T') .AND.
+ + .NOT.LSAME(TRANS,'C')) THEN
+ INFO = 2
+ ELSE IF (.NOT.LSAME(DIAG,'U') .AND. .NOT.LSAME(DIAG,'N')) THEN
+ INFO = 3
+ ELSE IF (N.LT.0) THEN
+ INFO = 4
+ ELSE IF (INCX.EQ.0) THEN
+ INFO = 7
+ END IF
+ IF (INFO.NE.0) THEN
+ CALL XERBLA('ZTPMV ',INFO)
+ RETURN
+ END IF
+*
+* Quick return if possible.
+*
+ IF (N.EQ.0) RETURN
+*
+ NOCONJ = LSAME(TRANS,'T')
+ NOUNIT = LSAME(DIAG,'N')
+*
+* Set up the start point in X if the increment is not unity. This
+* will be ( N - 1 )*INCX too small for descending loops.
+*
+ IF (INCX.LE.0) THEN
+ KX = 1 - (N-1)*INCX
+ ELSE IF (INCX.NE.1) THEN
+ KX = 1
+ END IF
+*
+* Start the operations. In this version the elements of AP are
+* accessed sequentially with one pass through AP.
+*
+ IF (LSAME(TRANS,'N')) THEN
+*
+* Form x:= A*x.
+*
+ IF (LSAME(UPLO,'U')) THEN
+ KK = 1
+ IF (INCX.EQ.1) THEN
+ DO 20 J = 1,N
+ IF (X(J).NE.ZERO) THEN
+ TEMP = X(J)
+ K = KK
+ DO 10 I = 1,J - 1
+ X(I) = X(I) + TEMP*AP(K)
+ K = K + 1
+ 10 CONTINUE
+ IF (NOUNIT) X(J) = X(J)*AP(KK+J-1)
+ END IF
+ KK = KK + J
+ 20 CONTINUE
+ ELSE
+ JX = KX
+ DO 40 J = 1,N
+ IF (X(JX).NE.ZERO) THEN
+ TEMP = X(JX)
+ IX = KX
+ DO 30 K = KK,KK + J - 2
+ X(IX) = X(IX) + TEMP*AP(K)
+ IX = IX + INCX
+ 30 CONTINUE
+ IF (NOUNIT) X(JX) = X(JX)*AP(KK+J-1)
+ END IF
+ JX = JX + INCX
+ KK = KK + J
+ 40 CONTINUE
+ END IF
+ ELSE
+ KK = (N* (N+1))/2
+ IF (INCX.EQ.1) THEN
+ DO 60 J = N,1,-1
+ IF (X(J).NE.ZERO) THEN
+ TEMP = X(J)
+ K = KK
+ DO 50 I = N,J + 1,-1
+ X(I) = X(I) + TEMP*AP(K)
+ K = K - 1
+ 50 CONTINUE
+ IF (NOUNIT) X(J) = X(J)*AP(KK-N+J)
+ END IF
+ KK = KK - (N-J+1)
+ 60 CONTINUE
+ ELSE
+ KX = KX + (N-1)*INCX
+ JX = KX
+ DO 80 J = N,1,-1
+ IF (X(JX).NE.ZERO) THEN
+ TEMP = X(JX)
+ IX = KX
+ DO 70 K = KK,KK - (N- (J+1)),-1
+ X(IX) = X(IX) + TEMP*AP(K)
+ IX = IX - INCX
+ 70 CONTINUE
+ IF (NOUNIT) X(JX) = X(JX)*AP(KK-N+J)
+ END IF
+ JX = JX - INCX
+ KK = KK - (N-J+1)
+ 80 CONTINUE
+ END IF
+ END IF
+ ELSE
+*
+* Form x := A'*x or x := conjg( A' )*x.
+*
+ IF (LSAME(UPLO,'U')) THEN
+ KK = (N* (N+1))/2
+ IF (INCX.EQ.1) THEN
+ DO 110 J = N,1,-1
+ TEMP = X(J)
+ K = KK - 1
+ IF (NOCONJ) THEN
+ IF (NOUNIT) TEMP = TEMP*AP(KK)
+ DO 90 I = J - 1,1,-1
+ TEMP = TEMP + AP(K)*X(I)
+ K = K - 1
+ 90 CONTINUE
+ ELSE
+ IF (NOUNIT) TEMP = TEMP*DCONJG(AP(KK))
+ DO 100 I = J - 1,1,-1
+ TEMP = TEMP + DCONJG(AP(K))*X(I)
+ K = K - 1
+ 100 CONTINUE
+ END IF
+ X(J) = TEMP
+ KK = KK - J
+ 110 CONTINUE
+ ELSE
+ JX = KX + (N-1)*INCX
+ DO 140 J = N,1,-1
+ TEMP = X(JX)
+ IX = JX
+ IF (NOCONJ) THEN
+ IF (NOUNIT) TEMP = TEMP*AP(KK)
+ DO 120 K = KK - 1,KK - J + 1,-1
+ IX = IX - INCX
+ TEMP = TEMP + AP(K)*X(IX)
+ 120 CONTINUE
+ ELSE
+ IF (NOUNIT) TEMP = TEMP*DCONJG(AP(KK))
+ DO 130 K = KK - 1,KK - J + 1,-1
+ IX = IX - INCX
+ TEMP = TEMP + DCONJG(AP(K))*X(IX)
+ 130 CONTINUE
+ END IF
+ X(JX) = TEMP
+ JX = JX - INCX
+ KK = KK - J
+ 140 CONTINUE
+ END IF
+ ELSE
+ KK = 1
+ IF (INCX.EQ.1) THEN
+ DO 170 J = 1,N
+ TEMP = X(J)
+ K = KK + 1
+ IF (NOCONJ) THEN
+ IF (NOUNIT) TEMP = TEMP*AP(KK)
+ DO 150 I = J + 1,N
+ TEMP = TEMP + AP(K)*X(I)
+ K = K + 1
+ 150 CONTINUE
+ ELSE
+ IF (NOUNIT) TEMP = TEMP*DCONJG(AP(KK))
+ DO 160 I = J + 1,N
+ TEMP = TEMP + DCONJG(AP(K))*X(I)
+ K = K + 1
+ 160 CONTINUE
+ END IF
+ X(J) = TEMP
+ KK = KK + (N-J+1)
+ 170 CONTINUE
+ ELSE
+ JX = KX
+ DO 200 J = 1,N
+ TEMP = X(JX)
+ IX = JX
+ IF (NOCONJ) THEN
+ IF (NOUNIT) TEMP = TEMP*AP(KK)
+ DO 180 K = KK + 1,KK + N - J
+ IX = IX + INCX
+ TEMP = TEMP + AP(K)*X(IX)
+ 180 CONTINUE
+ ELSE
+ IF (NOUNIT) TEMP = TEMP*DCONJG(AP(KK))
+ DO 190 K = KK + 1,KK + N - J
+ IX = IX + INCX
+ TEMP = TEMP + DCONJG(AP(K))*X(IX)
+ 190 CONTINUE
+ END IF
+ X(JX) = TEMP
+ JX = JX + INCX
+ KK = KK + (N-J+1)
+ 200 CONTINUE
+ END IF
+ END IF
+ END IF
+*
+ RETURN
+*
+* End of ZTPMV .
+*
+ END
diff --git a/blas/ztpsv.f b/blas/ztpsv.f
new file mode 100644
index 000000000..b56e1d8c4
--- /dev/null
+++ b/blas/ztpsv.f
@@ -0,0 +1,332 @@
+ SUBROUTINE ZTPSV(UPLO,TRANS,DIAG,N,AP,X,INCX)
+* .. Scalar Arguments ..
+ INTEGER INCX,N
+ CHARACTER DIAG,TRANS,UPLO
+* ..
+* .. Array Arguments ..
+ DOUBLE COMPLEX AP(*),X(*)
+* ..
+*
+* Purpose
+* =======
+*
+* ZTPSV solves one of the systems of equations
+*
+* A*x = b, or A'*x = b, or conjg( A' )*x = b,
+*
+* where b and x are n element vectors and A is an n by n unit, or
+* non-unit, upper or lower triangular matrix, supplied in packed form.
+*
+* No test for singularity or near-singularity is included in this
+* routine. Such tests must be performed before calling this routine.
+*
+* Arguments
+* ==========
+*
+* UPLO - CHARACTER*1.
+* On entry, UPLO specifies whether the matrix is an upper or
+* lower triangular matrix as follows:
+*
+* UPLO = 'U' or 'u' A is an upper triangular matrix.
+*
+* UPLO = 'L' or 'l' A is a lower triangular matrix.
+*
+* Unchanged on exit.
+*
+* TRANS - CHARACTER*1.
+* On entry, TRANS specifies the equations to be solved as
+* follows:
+*
+* TRANS = 'N' or 'n' A*x = b.
+*
+* TRANS = 'T' or 't' A'*x = b.
+*
+* TRANS = 'C' or 'c' conjg( A' )*x = b.
+*
+* Unchanged on exit.
+*
+* DIAG - CHARACTER*1.
+* On entry, DIAG specifies whether or not A is unit
+* triangular as follows:
+*
+* DIAG = 'U' or 'u' A is assumed to be unit triangular.
+*
+* DIAG = 'N' or 'n' A is not assumed to be unit
+* triangular.
+*
+* Unchanged on exit.
+*
+* N - INTEGER.
+* On entry, N specifies the order of the matrix A.
+* N must be at least zero.
+* Unchanged on exit.
+*
+* AP - COMPLEX*16 array of DIMENSION at least
+* ( ( n*( n + 1 ) )/2 ).
+* Before entry with UPLO = 'U' or 'u', the array AP must
+* contain the upper triangular matrix packed sequentially,
+* column by column, so that AP( 1 ) contains a( 1, 1 ),
+* AP( 2 ) and AP( 3 ) contain a( 1, 2 ) and a( 2, 2 )
+* respectively, and so on.
+* Before entry with UPLO = 'L' or 'l', the array AP must
+* contain the lower triangular matrix packed sequentially,
+* column by column, so that AP( 1 ) contains a( 1, 1 ),
+* AP( 2 ) and AP( 3 ) contain a( 2, 1 ) and a( 3, 1 )
+* respectively, and so on.
+* Note that when DIAG = 'U' or 'u', the diagonal elements of
+* A are not referenced, but are assumed to be unity.
+* Unchanged on exit.
+*
+* X - COMPLEX*16 array of dimension at least
+* ( 1 + ( n - 1 )*abs( INCX ) ).
+* Before entry, the incremented array X must contain the n
+* element right-hand side vector b. On exit, X is overwritten
+* with the solution vector x.
+*
+* INCX - INTEGER.
+* On entry, INCX specifies the increment for the elements of
+* X. INCX must not be zero.
+* Unchanged on exit.
+*
+* Further Details
+* ===============
+*
+* Level 2 Blas routine.
+*
+* -- Written on 22-October-1986.
+* Jack Dongarra, Argonne National Lab.
+* Jeremy Du Croz, Nag Central Office.
+* Sven Hammarling, Nag Central Office.
+* Richard Hanson, Sandia National Labs.
+*
+* =====================================================================
+*
+* .. Parameters ..
+ DOUBLE COMPLEX ZERO
+ PARAMETER (ZERO= (0.0D+0,0.0D+0))
+* ..
+* .. Local Scalars ..
+ DOUBLE COMPLEX TEMP
+ INTEGER I,INFO,IX,J,JX,K,KK,KX
+ LOGICAL NOCONJ,NOUNIT
+* ..
+* .. External Functions ..
+ LOGICAL LSAME
+ EXTERNAL LSAME
+* ..
+* .. External Subroutines ..
+ EXTERNAL XERBLA
+* ..
+* .. Intrinsic Functions ..
+ INTRINSIC DCONJG
+* ..
+*
+* Test the input parameters.
+*
+ INFO = 0
+ IF (.NOT.LSAME(UPLO,'U') .AND. .NOT.LSAME(UPLO,'L')) THEN
+ INFO = 1
+ ELSE IF (.NOT.LSAME(TRANS,'N') .AND. .NOT.LSAME(TRANS,'T') .AND.
+ + .NOT.LSAME(TRANS,'C')) THEN
+ INFO = 2
+ ELSE IF (.NOT.LSAME(DIAG,'U') .AND. .NOT.LSAME(DIAG,'N')) THEN
+ INFO = 3
+ ELSE IF (N.LT.0) THEN
+ INFO = 4
+ ELSE IF (INCX.EQ.0) THEN
+ INFO = 7
+ END IF
+ IF (INFO.NE.0) THEN
+ CALL XERBLA('ZTPSV ',INFO)
+ RETURN
+ END IF
+*
+* Quick return if possible.
+*
+ IF (N.EQ.0) RETURN
+*
+ NOCONJ = LSAME(TRANS,'T')
+ NOUNIT = LSAME(DIAG,'N')
+*
+* Set up the start point in X if the increment is not unity. This
+* will be ( N - 1 )*INCX too small for descending loops.
+*
+ IF (INCX.LE.0) THEN
+ KX = 1 - (N-1)*INCX
+ ELSE IF (INCX.NE.1) THEN
+ KX = 1
+ END IF
+*
+* Start the operations. In this version the elements of AP are
+* accessed sequentially with one pass through AP.
+*
+ IF (LSAME(TRANS,'N')) THEN
+*
+* Form x := inv( A )*x.
+*
+ IF (LSAME(UPLO,'U')) THEN
+ KK = (N* (N+1))/2
+ IF (INCX.EQ.1) THEN
+ DO 20 J = N,1,-1
+ IF (X(J).NE.ZERO) THEN
+ IF (NOUNIT) X(J) = X(J)/AP(KK)
+ TEMP = X(J)
+ K = KK - 1
+ DO 10 I = J - 1,1,-1
+ X(I) = X(I) - TEMP*AP(K)
+ K = K - 1
+ 10 CONTINUE
+ END IF
+ KK = KK - J
+ 20 CONTINUE
+ ELSE
+ JX = KX + (N-1)*INCX
+ DO 40 J = N,1,-1
+ IF (X(JX).NE.ZERO) THEN
+ IF (NOUNIT) X(JX) = X(JX)/AP(KK)
+ TEMP = X(JX)
+ IX = JX
+ DO 30 K = KK - 1,KK - J + 1,-1
+ IX = IX - INCX
+ X(IX) = X(IX) - TEMP*AP(K)
+ 30 CONTINUE
+ END IF
+ JX = JX - INCX
+ KK = KK - J
+ 40 CONTINUE
+ END IF
+ ELSE
+ KK = 1
+ IF (INCX.EQ.1) THEN
+ DO 60 J = 1,N
+ IF (X(J).NE.ZERO) THEN
+ IF (NOUNIT) X(J) = X(J)/AP(KK)
+ TEMP = X(J)
+ K = KK + 1
+ DO 50 I = J + 1,N
+ X(I) = X(I) - TEMP*AP(K)
+ K = K + 1
+ 50 CONTINUE
+ END IF
+ KK = KK + (N-J+1)
+ 60 CONTINUE
+ ELSE
+ JX = KX
+ DO 80 J = 1,N
+ IF (X(JX).NE.ZERO) THEN
+ IF (NOUNIT) X(JX) = X(JX)/AP(KK)
+ TEMP = X(JX)
+ IX = JX
+ DO 70 K = KK + 1,KK + N - J
+ IX = IX + INCX
+ X(IX) = X(IX) - TEMP*AP(K)
+ 70 CONTINUE
+ END IF
+ JX = JX + INCX
+ KK = KK + (N-J+1)
+ 80 CONTINUE
+ END IF
+ END IF
+ ELSE
+*
+* Form x := inv( A' )*x or x := inv( conjg( A' ) )*x.
+*
+ IF (LSAME(UPLO,'U')) THEN
+ KK = 1
+ IF (INCX.EQ.1) THEN
+ DO 110 J = 1,N
+ TEMP = X(J)
+ K = KK
+ IF (NOCONJ) THEN
+ DO 90 I = 1,J - 1
+ TEMP = TEMP - AP(K)*X(I)
+ K = K + 1
+ 90 CONTINUE
+ IF (NOUNIT) TEMP = TEMP/AP(KK+J-1)
+ ELSE
+ DO 100 I = 1,J - 1
+ TEMP = TEMP - DCONJG(AP(K))*X(I)
+ K = K + 1
+ 100 CONTINUE
+ IF (NOUNIT) TEMP = TEMP/DCONJG(AP(KK+J-1))
+ END IF
+ X(J) = TEMP
+ KK = KK + J
+ 110 CONTINUE
+ ELSE
+ JX = KX
+ DO 140 J = 1,N
+ TEMP = X(JX)
+ IX = KX
+ IF (NOCONJ) THEN
+ DO 120 K = KK,KK + J - 2
+ TEMP = TEMP - AP(K)*X(IX)
+ IX = IX + INCX
+ 120 CONTINUE
+ IF (NOUNIT) TEMP = TEMP/AP(KK+J-1)
+ ELSE
+ DO 130 K = KK,KK + J - 2
+ TEMP = TEMP - DCONJG(AP(K))*X(IX)
+ IX = IX + INCX
+ 130 CONTINUE
+ IF (NOUNIT) TEMP = TEMP/DCONJG(AP(KK+J-1))
+ END IF
+ X(JX) = TEMP
+ JX = JX + INCX
+ KK = KK + J
+ 140 CONTINUE
+ END IF
+ ELSE
+ KK = (N* (N+1))/2
+ IF (INCX.EQ.1) THEN
+ DO 170 J = N,1,-1
+ TEMP = X(J)
+ K = KK
+ IF (NOCONJ) THEN
+ DO 150 I = N,J + 1,-1
+ TEMP = TEMP - AP(K)*X(I)
+ K = K - 1
+ 150 CONTINUE
+ IF (NOUNIT) TEMP = TEMP/AP(KK-N+J)
+ ELSE
+ DO 160 I = N,J + 1,-1
+ TEMP = TEMP - DCONJG(AP(K))*X(I)
+ K = K - 1
+ 160 CONTINUE
+ IF (NOUNIT) TEMP = TEMP/DCONJG(AP(KK-N+J))
+ END IF
+ X(J) = TEMP
+ KK = KK - (N-J+1)
+ 170 CONTINUE
+ ELSE
+ KX = KX + (N-1)*INCX
+ JX = KX
+ DO 200 J = N,1,-1
+ TEMP = X(JX)
+ IX = KX
+ IF (NOCONJ) THEN
+ DO 180 K = KK,KK - (N- (J+1)),-1
+ TEMP = TEMP - AP(K)*X(IX)
+ IX = IX - INCX
+ 180 CONTINUE
+ IF (NOUNIT) TEMP = TEMP/AP(KK-N+J)
+ ELSE
+ DO 190 K = KK,KK - (N- (J+1)),-1
+ TEMP = TEMP - DCONJG(AP(K))*X(IX)
+ IX = IX - INCX
+ 190 CONTINUE
+ IF (NOUNIT) TEMP = TEMP/DCONJG(AP(KK-N+J))
+ END IF
+ X(JX) = TEMP
+ JX = JX - INCX
+ KK = KK - (N-J+1)
+ 200 CONTINUE
+ END IF
+ END IF
+ END IF
+*
+ RETURN
+*
+* End of ZTPSV .
+*
+ END
diff --git a/cmake/CMakeDetermineVSServicePack.cmake b/cmake/CMakeDetermineVSServicePack.cmake
new file mode 100644
index 000000000..b89462308
--- /dev/null
+++ b/cmake/CMakeDetermineVSServicePack.cmake
@@ -0,0 +1,103 @@
+# - Includes a public function for assisting users in trying to determine the
+# Visual Studio service pack in use.
+#
+# Sets the passed in variable to one of the following values or an empty
+# string if unknown.
+# vc80
+# vc80sp1
+# vc90
+# vc90sp1
+#
+# Usage:
+# ===========================
+#
+# if(MSVC)
+# include(CMakeDetermineVSServicePack)
+# DetermineVSServicePack( my_service_pack )
+#
+# if( my_service_pack )
+# message(STATUS "Detected: ${my_service_pack}")
+# endif()
+# endif()
+#
+# ===========================
+
+#=============================================================================
+# Copyright 2009-2010 Kitware, Inc.
+# Copyright 2009-2010 Philip Lowman <philip@yhbt.com>
+#
+# Distributed under the OSI-approved BSD License (the "License");
+# see accompanying file Copyright.txt for details.
+#
+# This software is distributed WITHOUT ANY WARRANTY; without even the
+# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+# See the License for more information.
+#=============================================================================
+# (To distribute this file outside of CMake, substitute the full
+# License text for the above reference.)
+
+# [INTERNAL]
+# Please do not call this function directly
+function(_DetermineVSServicePackFromCompiler _OUT_VAR _cl_version)
+ if (${_cl_version} VERSION_EQUAL "14.00.50727.42")
+ set(_version "vc80")
+ elseif(${_cl_version} VERSION_EQUAL "14.00.50727.762")
+ set(_version "vc80sp1")
+ elseif(${_cl_version} VERSION_EQUAL "15.00.21022.08")
+ set(_version "vc90")
+ elseif(${_cl_version} VERSION_EQUAL "15.00.30729.01")
+ set(_version "vc90sp1")
+ elseif(${_cl_version} VERSION_EQUAL "16.00.30319.01")
+ set(_version "vc100")
+ else()
+ set(_version "")
+ endif()
+ set(${_OUT_VAR} ${_version} PARENT_SCOPE)
+endfunction()
+
+#
+# A function to call to determine the Visual Studio service pack
+# in use. See documentation above.
+function(DetermineVSServicePack _pack)
+ if(NOT DETERMINED_VS_SERVICE_PACK OR NOT ${_pack})
+ if(${CMAKE_BUILD_TOOL} STREQUAL "nmake")
+ EXECUTE_PROCESS(COMMAND ${CMAKE_CXX_COMPILER} "/?"
+ ERROR_VARIABLE _output)
+ set(DETERMINED_VS_SERVICE_PACK ${_output})
+ else()
+ file(WRITE "${CMAKE_BINARY_DIR}/return0.cc"
+ "int main() { return 0; }\n")
+
+ try_compile(DETERMINED_VS_SERVICE_PACK
+ "${CMAKE_BINARY_DIR}"
+ "${CMAKE_BINARY_DIR}/return0.cc"
+ OUTPUT_VARIABLE _output
+ COPY_FILE "${CMAKE_BINARY_DIR}/return0.cc")
+
+ file(REMOVE "${CMAKE_BINARY_DIR}/return0.cc")
+ endif()
+
+ if(DETERMINED_VS_SERVICE_PACK AND _output)
+ string(REGEX MATCH "Compiler Version [0-9]+.[0-9]+.[0-9]+.[0-9]+"
+ _cl_version "${_output}")
+ if(_cl_version)
+ string(REGEX MATCHALL "[0-9]+"
+ _cl_version_list "${_cl_version}")
+ list(GET _cl_version_list 0 _major)
+ list(GET _cl_version_list 1 _minor)
+ list(GET _cl_version_list 2 _patch)
+ list(GET _cl_version_list 3 _tweak)
+
+ set(_cl_version_string ${_major}.${_minor}.${_patch}.${_tweak})
+
+ # Call helper function to determine VS version
+ _DetermineVSServicePackFromCompiler(_sp "${_cl_version_string}")
+ if(_sp)
+ #set(${_pack} "${_sp}(${_cl_version_string})" CACHE INTERNAL
+ set(${_pack} "${_sp}" CACHE INTERNAL
+ "The Visual Studio Release with Service Pack")
+ endif()
+ endif()
+ endif()
+ endif()
+endfunction()
diff --git a/cmake/EigenConfigureTesting.cmake b/cmake/EigenConfigureTesting.cmake
new file mode 100644
index 000000000..cf8f32c01
--- /dev/null
+++ b/cmake/EigenConfigureTesting.cmake
@@ -0,0 +1,79 @@
+include(EigenTesting)
+include(CheckCXXSourceCompiles)
+
+# configure the "site" and "buildname"
+ei_set_sitename()
+
+# retrieve and store the build string
+ei_set_build_string()
+
+add_custom_target(buildtests)
+add_custom_target(check COMMAND "ctest")
+add_dependencies(check buildtests)
+
+# check whether /bin/bash exists
+find_file(EIGEN_BIN_BASH_EXISTS "/bin/bash" PATHS "/" NO_DEFAULT_PATH)
+
+# CMake/Ctest does not allow us to change the build command,
+# so we have to workaround by directly editing the generated DartConfiguration.tcl file
+# save CMAKE_MAKE_PROGRAM
+set(CMAKE_MAKE_PROGRAM_SAVE ${CMAKE_MAKE_PROGRAM})
+# and set a fake one
+set(CMAKE_MAKE_PROGRAM "@EIGEN_MAKECOMMAND_PLACEHOLDER@")
+
+# This call activates testing and generates the DartConfiguration.tcl
+include(CTest)
+
+# overwrite default DartConfiguration.tcl
+# The worarounds are different for each version of the MSVC IDE
+if(MSVC_IDE)
+ if(MSVC_VERSION EQUAL 1600) # MSVC 2010
+ set(EIGEN_MAKECOMMAND_PLACEHOLDER "${CMAKE_MAKE_PROGRAM_SAVE} buildtests.vcxproj /p:Configuration=\${CTEST_CONFIGURATION_TYPE} \n# ")
+ else() # MSVC 2008 (TODO check MSVC 2005)
+ set(EIGEN_MAKECOMMAND_PLACEHOLDER "${CMAKE_MAKE_PROGRAM_SAVE} Eigen.sln /build \"Release\" /project buildtests \n# ")
+ endif()
+else()
+ # for make and nmake
+ set(EIGEN_MAKECOMMAND_PLACEHOLDER "${CMAKE_MAKE_PROGRAM_SAVE} buildtests")
+endif()
+
+# copy ctest properties, which currently
+# o raise the warning levels
+configure_file(${CMAKE_BINARY_DIR}/DartConfiguration.tcl ${CMAKE_BINARY_DIR}/DartConfiguration.tcl)
+
+# restore default CMAKE_MAKE_PROGRAM
+set(CMAKE_MAKE_PROGRAM ${CMAKE_MAKE_PROGRAM_SAVE})
+# un-set temporary variables so that it is like they never existed.
+# CMake 2.6.3 introduces the more logical unset() syntax for this.
+set(CMAKE_MAKE_PROGRAM_SAVE)
+set(EIGEN_MAKECOMMAND_PLACEHOLDER)
+
+configure_file(${CMAKE_SOURCE_DIR}/CTestCustom.cmake.in ${CMAKE_BINARY_DIR}/CTestCustom.cmake)
+
+# some documentation of this function would be nice
+ei_init_testing()
+
+# configure Eigen related testing options
+option(EIGEN_NO_ASSERTION_CHECKING "Disable checking of assertions using exceptions" OFF)
+option(EIGEN_DEBUG_ASSERTS "Enable advanced debuging of assertions" OFF)
+
+if(CMAKE_COMPILER_IS_GNUCXX)
+ option(EIGEN_COVERAGE_TESTING "Enable/disable gcov" OFF)
+ if(EIGEN_COVERAGE_TESTING)
+ set(COVERAGE_FLAGS "-fprofile-arcs -ftest-coverage")
+ set(CTEST_CUSTOM_COVERAGE_EXCLUDE "/test/")
+ else(EIGEN_COVERAGE_TESTING)
+ set(COVERAGE_FLAGS "")
+ endif(EIGEN_COVERAGE_TESTING)
+ if(EIGEN_TEST_C++0x)
+ set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=gnu++0x")
+ endif(EIGEN_TEST_C++0x)
+ if(CMAKE_SYSTEM_NAME MATCHES Linux)
+ set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${COVERAGE_FLAGS} -g2")
+ set(CMAKE_CXX_FLAGS_RELWITHDEBINFO "${CMAKE_CXX_FLAGS_RELWITHDEBINFO} ${COVERAGE_FLAGS} -O2 -g2")
+ set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} ${COVERAGE_FLAGS} -fno-inline-functions")
+ set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} ${COVERAGE_FLAGS} -O0 -g3")
+ endif(CMAKE_SYSTEM_NAME MATCHES Linux)
+elseif(MSVC)
+ set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /D_CRT_SECURE_NO_WARNINGS /D_SCL_SECURE_NO_WARNINGS")
+endif(CMAKE_COMPILER_IS_GNUCXX)
diff --git a/cmake/EigenDetermineOSVersion.cmake b/cmake/EigenDetermineOSVersion.cmake
new file mode 100644
index 000000000..3c48d4c37
--- /dev/null
+++ b/cmake/EigenDetermineOSVersion.cmake
@@ -0,0 +1,46 @@
+# The utility function DetermineOSVersion aims at providing an
+# improved version of the CMake variable ${CMAKE_SYSTEM} on Windows
+# machines.
+#
+# Usage:
+# include(EigenDetermineOSVersion)
+# DetermineOSVersion(OS_VERSION)
+# message("OS: ${OS_VERSION}")
+
+# - A little helper variable which should not be directly called
+function(DetermineShortWindowsName WIN_VERSION win_num_version)
+ if (${win_num_version} VERSION_EQUAL "6.1")
+ set(_version "win7")
+ elseif(${win_num_version} VERSION_EQUAL "6.0")
+ set(_version "winVista")
+ elseif(${win_num_version} VERSION_EQUAL "5.2")
+ set(_version "winXpProf")
+ elseif(${win_num_version} VERSION_EQUAL "5.1")
+ set(_version "winXp")
+ elseif(${win_num_version} VERSION_EQUAL "5.0")
+ set(_version "win2000Prof")
+ else()
+ set(_version "unknownWin")
+ endif()
+ set(${WIN_VERSION} ${_version} PARENT_SCOPE)
+endfunction()
+
+function(DetermineOSVersion OS_VERSION)
+ if (WIN32)
+ file (TO_NATIVE_PATH "$ENV{COMSPEC}" SHELL)
+ exec_program( ${SHELL} ARGS "/c" "ver" OUTPUT_VARIABLE ver_output)
+
+ string(REGEX MATCHALL "[0-9]+"
+ ver_list "${ver_output}")
+ list(GET ver_list 0 _major)
+ list(GET ver_list 1 _minor)
+
+ set(win_num_version ${_major}.${_minor})
+ DetermineShortWindowsName(win_version "${win_num_version}")
+ if(win_version)
+ set(${OS_VERSION} ${win_version} PARENT_SCOPE)
+ endif()
+ else()
+ set(${OS_VERSION} ${CMAKE_SYSTEM} PARENT_SCOPE)
+ endif()
+endfunction()
diff --git a/cmake/EigenTesting.cmake b/cmake/EigenTesting.cmake
new file mode 100644
index 000000000..266043974
--- /dev/null
+++ b/cmake/EigenTesting.cmake
@@ -0,0 +1,477 @@
+
+macro(ei_add_property prop value)
+ get_property(previous GLOBAL PROPERTY ${prop})
+ if ((NOT previous) OR (previous STREQUAL ""))
+ set_property(GLOBAL PROPERTY ${prop} "${value}")
+ else()
+ set_property(GLOBAL PROPERTY ${prop} "${previous} ${value}")
+ endif()
+endmacro(ei_add_property)
+
+#internal. See documentation of ei_add_test for details.
+macro(ei_add_test_internal testname testname_with_suffix)
+ set(targetname ${testname_with_suffix})
+
+ set(filename ${testname}.cpp)
+ add_executable(${targetname} ${filename})
+ if (targetname MATCHES "^eigen2_")
+ add_dependencies(eigen2_buildtests ${targetname})
+ else()
+ add_dependencies(buildtests ${targetname})
+ endif()
+
+ if(EIGEN_NO_ASSERTION_CHECKING)
+ ei_add_target_property(${targetname} COMPILE_FLAGS "-DEIGEN_NO_ASSERTION_CHECKING=1")
+ else(EIGEN_NO_ASSERTION_CHECKING)
+ if(EIGEN_DEBUG_ASSERTS)
+ ei_add_target_property(${targetname} COMPILE_FLAGS "-DEIGEN_DEBUG_ASSERTS=1")
+ endif(EIGEN_DEBUG_ASSERTS)
+ endif(EIGEN_NO_ASSERTION_CHECKING)
+
+ ei_add_target_property(${targetname} COMPILE_FLAGS "-DEIGEN_TEST_MAX_SIZE=${EIGEN_TEST_MAX_SIZE}")
+
+ ei_add_target_property(${targetname} COMPILE_FLAGS "-DEIGEN_TEST_FUNC=${testname}")
+
+ if(MSVC AND NOT EIGEN_SPLIT_LARGE_TESTS)
+ ei_add_target_property(${targetname} COMPILE_FLAGS "/bigobj")
+ endif()
+
+ # let the user pass flags.
+ if(${ARGC} GREATER 2)
+ ei_add_target_property(${targetname} COMPILE_FLAGS "${ARGV2}")
+ endif(${ARGC} GREATER 2)
+
+ if(EIGEN_TEST_CUSTOM_CXX_FLAGS)
+ ei_add_target_property(${targetname} COMPILE_FLAGS "${EIGEN_TEST_CUSTOM_CXX_FLAGS}")
+ endif()
+
+ if(EIGEN_STANDARD_LIBRARIES_TO_LINK_TO)
+ target_link_libraries(${targetname} ${EIGEN_STANDARD_LIBRARIES_TO_LINK_TO})
+ endif()
+ if(EXTERNAL_LIBS)
+ target_link_libraries(${targetname} ${EXTERNAL_LIBS})
+ endif()
+ if(EIGEN_TEST_CUSTOM_LINKER_FLAGS)
+ target_link_libraries(${targetname} ${EIGEN_TEST_CUSTOM_LINKER_FLAGS})
+ endif()
+
+ if(${ARGC} GREATER 3)
+ set(libs_to_link ${ARGV3})
+ # it could be that some cmake module provides a bad library string " " (just spaces),
+ # and that severely breaks target_link_libraries ("can't link to -l-lstdc++" errors).
+ # so we check for strings containing only spaces.
+ string(STRIP "${libs_to_link}" libs_to_link_stripped)
+ string(LENGTH "${libs_to_link_stripped}" libs_to_link_stripped_length)
+ if(${libs_to_link_stripped_length} GREATER 0)
+ # notice: no double quotes around ${libs_to_link} here. It may be a list.
+ target_link_libraries(${targetname} ${libs_to_link})
+ endif()
+ endif()
+
+ if(EIGEN_BIN_BASH_EXISTS)
+ add_test(${testname_with_suffix} "${Eigen_SOURCE_DIR}/test/runtest.sh" "${testname_with_suffix}")
+ else()
+ add_test(${testname_with_suffix} "${targetname}")
+ endif()
+
+endmacro(ei_add_test_internal)
+
+# Macro to add a test
+#
+# the unique mandatory parameter testname must correspond to a file
+# <testname>.cpp which follows this pattern:
+#
+# #include "main.h"
+# void test_<testname>() { ... }
+#
+# Depending on the contents of that file, this macro can have 2 behaviors,
+# see below.
+#
+# The optional 2nd parameter is libraries to link to.
+#
+# A. Default behavior
+#
+# this macro adds an executable <testname> as well as a ctest test
+# named <testname> too.
+#
+# On platforms with bash simply run:
+# "ctest -V" or "ctest -V -R <testname>"
+# On other platform use ctest as usual
+#
+# B. Multi-part behavior
+#
+# If the source file matches the regexp
+# CALL_SUBTEST_[0-9]+|EIGEN_TEST_PART_[0-9]+
+# then it is interpreted as a multi-part test. The behavior then depends on the
+# CMake option EIGEN_SPLIT_LARGE_TESTS, which is ON by default.
+#
+# If EIGEN_SPLIT_LARGE_TESTS is OFF, the behavior is the same as in A (the multi-part
+# aspect is ignored).
+#
+# If EIGEN_SPLIT_LARGE_TESTS is ON, the test is split into multiple executables
+# test_<testname>_<N>
+# where N runs from 1 to the greatest occurence found in the source file. Each of these
+# executables is built passing -DEIGEN_TEST_PART_N. This allows to split large tests
+# into smaller executables.
+#
+# Moreover, targets <testname> are still generated, they
+# have the effect of building all the parts of the test.
+#
+# Again, ctest -R allows to run all matching tests.
+macro(ei_add_test testname)
+ get_property(EIGEN_TESTS_LIST GLOBAL PROPERTY EIGEN_TESTS_LIST)
+ set(EIGEN_TESTS_LIST "${EIGEN_TESTS_LIST}${testname}\n")
+ set_property(GLOBAL PROPERTY EIGEN_TESTS_LIST "${EIGEN_TESTS_LIST}")
+
+ file(READ "${testname}.cpp" test_source)
+ set(parts 0)
+ string(REGEX MATCHALL "CALL_SUBTEST_[0-9]+|EIGEN_TEST_PART_[0-9]+|EIGEN_SUFFIXES(;[0-9]+)+"
+ occurences "${test_source}")
+ string(REGEX REPLACE "CALL_SUBTEST_|EIGEN_TEST_PART_|EIGEN_SUFFIXES" "" suffixes "${occurences}")
+ list(REMOVE_DUPLICATES suffixes)
+ if(EIGEN_SPLIT_LARGE_TESTS AND suffixes)
+ add_custom_target(${testname})
+ foreach(suffix ${suffixes})
+ ei_add_test_internal(${testname} ${testname}_${suffix}
+ "${ARGV1} -DEIGEN_TEST_PART_${suffix}=1" "${ARGV2}")
+ add_dependencies(${testname} ${testname}_${suffix})
+ endforeach(suffix)
+ else(EIGEN_SPLIT_LARGE_TESTS AND suffixes)
+ set(symbols_to_enable_all_parts "")
+ foreach(suffix ${suffixes})
+ set(symbols_to_enable_all_parts
+ "${symbols_to_enable_all_parts} -DEIGEN_TEST_PART_${suffix}=1")
+ endforeach(suffix)
+ ei_add_test_internal(${testname} ${testname} "${ARGV1} ${symbols_to_enable_all_parts}" "${ARGV2}")
+ endif(EIGEN_SPLIT_LARGE_TESTS AND suffixes)
+endmacro(ei_add_test)
+
+
+# adds a failtest, i.e. a test that succeed if the program fails to compile
+# note that the test runner for these is CMake itself, when passed -DEIGEN_FAILTEST=ON
+# so here we're just running CMake commands immediately, we're not adding any targets.
+macro(ei_add_failtest testname)
+ get_property(EIGEN_FAILTEST_FAILURE_COUNT GLOBAL PROPERTY EIGEN_FAILTEST_FAILURE_COUNT)
+ get_property(EIGEN_FAILTEST_COUNT GLOBAL PROPERTY EIGEN_FAILTEST_COUNT)
+
+ message(STATUS "Checking failtest: ${testname}")
+ set(filename "${testname}.cpp")
+ file(READ "${filename}" test_source)
+
+ try_compile(succeeds_when_it_should_fail
+ "${CMAKE_CURRENT_BINARY_DIR}"
+ "${CMAKE_CURRENT_SOURCE_DIR}/${filename}"
+ COMPILE_DEFINITIONS "-DEIGEN_SHOULD_FAIL_TO_BUILD")
+ if (succeeds_when_it_should_fail)
+ message(STATUS "FAILED: ${testname} build succeeded when it should have failed")
+ endif()
+
+ try_compile(succeeds_when_it_should_succeed
+ "${CMAKE_CURRENT_BINARY_DIR}"
+ "${CMAKE_CURRENT_SOURCE_DIR}/${filename}"
+ COMPILE_DEFINITIONS)
+ if (NOT succeeds_when_it_should_succeed)
+ message(STATUS "FAILED: ${testname} build failed when it should have succeeded")
+ endif()
+
+ if (succeeds_when_it_should_fail OR NOT succeeds_when_it_should_succeed)
+ math(EXPR EIGEN_FAILTEST_FAILURE_COUNT ${EIGEN_FAILTEST_FAILURE_COUNT}+1)
+ endif()
+
+ math(EXPR EIGEN_FAILTEST_COUNT ${EIGEN_FAILTEST_COUNT}+1)
+
+ set_property(GLOBAL PROPERTY EIGEN_FAILTEST_FAILURE_COUNT ${EIGEN_FAILTEST_FAILURE_COUNT})
+ set_property(GLOBAL PROPERTY EIGEN_FAILTEST_COUNT ${EIGEN_FAILTEST_COUNT})
+endmacro(ei_add_failtest)
+
+# print a summary of the different options
+macro(ei_testing_print_summary)
+ message(STATUS "************************************************************")
+ message(STATUS "*** Eigen's unit tests configuration summary ***")
+ message(STATUS "************************************************************")
+ message(STATUS "")
+ message(STATUS "Build type: ${CMAKE_BUILD_TYPE}")
+ message(STATUS "Build site: ${SITE}")
+ message(STATUS "Build string: ${BUILDNAME}")
+ get_property(EIGEN_TESTING_SUMMARY GLOBAL PROPERTY EIGEN_TESTING_SUMMARY)
+ get_property(EIGEN_TESTED_BACKENDS GLOBAL PROPERTY EIGEN_TESTED_BACKENDS)
+ get_property(EIGEN_MISSING_BACKENDS GLOBAL PROPERTY EIGEN_MISSING_BACKENDS)
+ message(STATUS "Enabled backends: ${EIGEN_TESTED_BACKENDS}")
+ message(STATUS "Disabled backends: ${EIGEN_MISSING_BACKENDS}")
+
+ if(EIGEN_DEFAULT_TO_ROW_MAJOR)
+ message(STATUS "Default order: Row-major")
+ else()
+ message(STATUS "Default order: Column-major")
+ endif()
+
+ if(EIGEN_TEST_NO_EXPLICIT_ALIGNMENT)
+ message(STATUS "Explicit alignment (hence vectorization) disabled")
+ elseif(EIGEN_TEST_NO_EXPLICIT_VECTORIZATION)
+ message(STATUS "Explicit vectorization disabled (alignment kept enabled)")
+ else()
+
+ message(STATUS "Maximal matrix/vector size: ${EIGEN_TEST_MAX_SIZE}")
+
+ if(EIGEN_TEST_SSE2)
+ message(STATUS "SSE2: ON")
+ else()
+ message(STATUS "SSE2: Using architecture defaults")
+ endif()
+
+ if(EIGEN_TEST_SSE3)
+ message(STATUS "SSE3: ON")
+ else()
+ message(STATUS "SSE3: Using architecture defaults")
+ endif()
+
+ if(EIGEN_TEST_SSSE3)
+ message(STATUS "SSSE3: ON")
+ else()
+ message(STATUS "SSSE3: Using architecture defaults")
+ endif()
+
+ if(EIGEN_TEST_SSE4_1)
+ message(STATUS "SSE4.1: ON")
+ else()
+ message(STATUS "SSE4.1: Using architecture defaults")
+ endif()
+
+ if(EIGEN_TEST_SSE4_2)
+ message(STATUS "SSE4.2: ON")
+ else()
+ message(STATUS "SSE4.2: Using architecture defaults")
+ endif()
+
+ if(EIGEN_TEST_ALTIVEC)
+ message(STATUS "Altivec: ON")
+ else()
+ message(STATUS "Altivec: Using architecture defaults")
+ endif()
+
+ if(EIGEN_TEST_NEON)
+ message(STATUS "ARM NEON: ON")
+ else()
+ message(STATUS "ARM NEON: Using architecture defaults")
+ endif()
+
+ endif() # vectorization / alignment options
+
+ message(STATUS "\n${EIGEN_TESTING_SUMMARY}")
+
+ message(STATUS "************************************************************")
+endmacro(ei_testing_print_summary)
+
+macro(ei_init_testing)
+ define_property(GLOBAL PROPERTY EIGEN_TESTED_BACKENDS BRIEF_DOCS " " FULL_DOCS " ")
+ define_property(GLOBAL PROPERTY EIGEN_MISSING_BACKENDS BRIEF_DOCS " " FULL_DOCS " ")
+ define_property(GLOBAL PROPERTY EIGEN_TESTING_SUMMARY BRIEF_DOCS " " FULL_DOCS " ")
+ define_property(GLOBAL PROPERTY EIGEN_TESTS_LIST BRIEF_DOCS " " FULL_DOCS " ")
+
+ set_property(GLOBAL PROPERTY EIGEN_TESTED_BACKENDS "")
+ set_property(GLOBAL PROPERTY EIGEN_MISSING_BACKENDS "")
+ set_property(GLOBAL PROPERTY EIGEN_TESTING_SUMMARY "")
+ set_property(GLOBAL PROPERTY EIGEN_TESTS_LIST "")
+
+ define_property(GLOBAL PROPERTY EIGEN_FAILTEST_FAILURE_COUNT BRIEF_DOCS " " FULL_DOCS " ")
+ define_property(GLOBAL PROPERTY EIGEN_FAILTEST_COUNT BRIEF_DOCS " " FULL_DOCS " ")
+
+ set_property(GLOBAL PROPERTY EIGEN_FAILTEST_FAILURE_COUNT "0")
+ set_property(GLOBAL PROPERTY EIGEN_FAILTEST_COUNT "0")
+
+ # uncomment anytime you change the ei_get_compilerver_from_cxx_version_string macro
+ # ei_test_get_compilerver_from_cxx_version_string()
+endmacro(ei_init_testing)
+
+macro(ei_set_sitename)
+ # if the sitename is not yet set, try to set it
+ if(NOT ${SITE} OR ${SITE} STREQUAL "")
+ set(eigen_computername $ENV{COMPUTERNAME})
+ set(eigen_hostname $ENV{HOSTNAME})
+ if(eigen_hostname)
+ set(SITE ${eigen_hostname})
+ elseif(eigen_computername)
+ set(SITE ${eigen_computername})
+ endif()
+ endif()
+ # in case it is already set, enforce lower case
+ if(SITE)
+ string(TOLOWER ${SITE} SITE)
+ endif()
+endmacro(ei_set_sitename)
+
+macro(ei_get_compilerver VAR)
+ if(MSVC)
+ # on windows system, we use a modified CMake script
+ include(CMakeDetermineVSServicePack)
+ DetermineVSServicePack( my_service_pack )
+
+ if( my_service_pack )
+ set(${VAR} ${my_service_pack})
+ else()
+ set(${VAR} "na")
+ endif()
+ else()
+ # on all other system we rely on ${CMAKE_CXX_COMPILER}
+ # supporting a "--version" flag
+ execute_process(COMMAND ${CMAKE_CXX_COMPILER} --version
+ COMMAND head -n 1
+ OUTPUT_VARIABLE eigen_cxx_compiler_version_string OUTPUT_STRIP_TRAILING_WHITESPACE)
+
+ ei_get_compilerver_from_cxx_version_string(${eigen_cxx_compiler_version_string} CNAME CVER)
+
+ set(${VAR} "${CNAME}-${CVER}")
+ endif()
+endmacro(ei_get_compilerver)
+
+# Extract compiler name and version from a raw version string
+# WARNING: if you edit thid macro, then please test it by uncommenting
+# the testing macro call in ei_init_testing() of the EigenTesting.cmake file.
+# See also the ei_test_get_compilerver_from_cxx_version_string macro at the end of the file
+macro(ei_get_compilerver_from_cxx_version_string VERSTRING CNAME CVER)
+ # extract possible compiler names
+ string(REGEX MATCH "g\\+\\+" ei_has_gpp ${VERSTRING})
+ string(REGEX MATCH "llvm|LLVM" ei_has_llvm ${VERSTRING})
+ string(REGEX MATCH "gcc|GCC" ei_has_gcc ${VERSTRING})
+ string(REGEX MATCH "icpc|ICC" ei_has_icpc ${VERSTRING})
+ string(REGEX MATCH "clang|CLANG" ei_has_clang ${VERSTRING})
+
+ # combine them
+ if((ei_has_llvm) AND (ei_has_gpp OR ei_has_gcc))
+ set(${CNAME} "llvm-g++")
+ elseif((ei_has_llvm) AND (ei_has_clang))
+ set(${CNAME} "llvm-clang++")
+ elseif(ei_has_icpc)
+ set(${CNAME} "icpc")
+ elseif(ei_has_gpp OR ei_has_gcc)
+ set(${CNAME} "g++")
+ else()
+ set(${CNAME} "_")
+ endif()
+
+ # extract possible version numbers
+ # first try to extract 3 isolated numbers:
+ string(REGEX MATCH " [0-9]+\\.[0-9]+\\.[0-9]+" eicver ${VERSTRING})
+ if(NOT eicver)
+ # try to extract 2 isolated ones:
+ string(REGEX MATCH " [0-9]+\\.[0-9]+" eicver ${VERSTRING})
+ if(NOT eicver)
+ # try to extract 3:
+ string(REGEX MATCH "[^0-9][0-9]+\\.[0-9]+\\.[0-9]+" eicver ${VERSTRING})
+ if(NOT eicver)
+ # try to extract 2:
+ string(REGEX MATCH "[^0-9][0-9]+\\.[0-9]+" eicver ${VERSTRING})
+ else()
+ set(eicver " _")
+ endif()
+ endif()
+ endif()
+
+ string(REGEX REPLACE ".(.*)" "\\1" ${CVER} ${eicver})
+
+endmacro(ei_get_compilerver_from_cxx_version_string)
+
+macro(ei_get_cxxflags VAR)
+ set(${VAR} "")
+ ei_is_64bit_env(IS_64BIT_ENV)
+ if(EIGEN_TEST_NEON)
+ set(${VAR} NEON)
+ elseif(EIGEN_TEST_ALTIVEC)
+ set(${VAR} ALVEC)
+ elseif(EIGEN_TEST_SSE4_2)
+ set(${VAR} SSE42)
+ elseif(EIGEN_TEST_SSE4_1)
+ set(${VAR} SSE41)
+ elseif(EIGEN_TEST_SSSE3)
+ set(${VAR} SSSE3)
+ elseif(EIGEN_TEST_SSE3)
+ set(${VAR} SSE3)
+ elseif(EIGEN_TEST_SSE2 OR IS_64BIT_ENV)
+ set(${VAR} SSE2)
+ endif()
+
+ if(EIGEN_TEST_OPENMP)
+ if (${VAR} STREQUAL "")
+ set(${VAR} OMP)
+ else()
+ set(${VAR} ${${VAR}}-OMP)
+ endif()
+ endif()
+
+ if(EIGEN_DEFAULT_TO_ROW_MAJOR)
+ if (${VAR} STREQUAL "")
+ set(${VAR} ROW)
+ else()
+ set(${VAR} ${${VAR}}-ROWMAJ)
+ endif()
+ endif()
+endmacro(ei_get_cxxflags)
+
+macro(ei_set_build_string)
+ ei_get_compilerver(LOCAL_COMPILER_VERSION)
+ ei_get_cxxflags(LOCAL_COMPILER_FLAGS)
+
+ include(EigenDetermineOSVersion)
+ DetermineOSVersion(OS_VERSION)
+
+ set(TMP_BUILD_STRING ${OS_VERSION}-${LOCAL_COMPILER_VERSION})
+
+ if (NOT ${LOCAL_COMPILER_FLAGS} STREQUAL "")
+ set(TMP_BUILD_STRING ${TMP_BUILD_STRING}-${LOCAL_COMPILER_FLAGS})
+ endif()
+
+ ei_is_64bit_env(IS_64BIT_ENV)
+ if(NOT IS_64BIT_ENV)
+ set(TMP_BUILD_STRING ${TMP_BUILD_STRING}-32bit)
+ else()
+ set(TMP_BUILD_STRING ${TMP_BUILD_STRING}-64bit)
+ endif()
+
+ string(TOLOWER ${TMP_BUILD_STRING} BUILDNAME)
+endmacro(ei_set_build_string)
+
+macro(ei_is_64bit_env VAR)
+
+ file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/is64.cpp"
+ "int main() { return (sizeof(int*) == 8 ? 1 : 0); }
+ ")
+ try_run(run_res compile_res
+ ${CMAKE_CURRENT_BINARY_DIR} "${CMAKE_CURRENT_BINARY_DIR}/is64.cpp"
+ RUN_OUTPUT_VARIABLE run_output)
+
+ if(compile_res AND run_res)
+ set(${VAR} ${run_res})
+ elseif(CMAKE_CL_64)
+ set(${VAR} 1)
+ elseif("$ENV{Platform}" STREQUAL "X64") # nmake 64 bit
+ set(${VAR} 1)
+ endif()
+endmacro(ei_is_64bit_env)
+
+
+# helper macro for testing ei_get_compilerver_from_cxx_version_string
+# STR: raw version string
+# REFNAME: expected compiler name
+# REFVER: expected compiler version
+macro(ei_test1_get_compilerver_from_cxx_version_string STR REFNAME REFVER)
+ ei_get_compilerver_from_cxx_version_string(${STR} CNAME CVER)
+ if((NOT ${REFNAME} STREQUAL ${CNAME}) OR (NOT ${REFVER} STREQUAL ${CVER}))
+ message("STATUS ei_get_compilerver_from_cxx_version_string error:")
+ message("Expected \"${REFNAME}-${REFVER}\", got \"${CNAME}-${CVER}\"")
+ endif()
+endmacro(ei_test1_get_compilerver_from_cxx_version_string)
+
+# macro for testing ei_get_compilerver_from_cxx_version_string
+# feel free to add more version strings
+macro(ei_test_get_compilerver_from_cxx_version_string)
+ ei_test1_get_compilerver_from_cxx_version_string("g++ (SUSE Linux) 4.5.3 20110428 [gcc-4_5-branch revision 173117]" "g++" "4.5.3")
+ ei_test1_get_compilerver_from_cxx_version_string("c++ (GCC) 4.5.1 20100924 (Red Hat 4.5.1-4)" "g++" "4.5.1")
+ ei_test1_get_compilerver_from_cxx_version_string("icpc (ICC) 11.0 20081105" "icpc" "11.0")
+ ei_test1_get_compilerver_from_cxx_version_string("g++-3.4 (GCC) 3.4.6" "g++" "3.4.6")
+ ei_test1_get_compilerver_from_cxx_version_string("SUSE Linux clang version 3.0 (branches/release_30 145598) (based on LLVM 3.0)" "llvm-clang++" "3.0")
+ ei_test1_get_compilerver_from_cxx_version_string("icpc (ICC) 12.0.5 20110719" "icpc" "12.0.5")
+ ei_test1_get_compilerver_from_cxx_version_string("Apple clang version 2.1 (tags/Apple/clang-163.7.1) (based on LLVM 3.0svn)" "llvm-clang++" "2.1")
+ ei_test1_get_compilerver_from_cxx_version_string("i686-apple-darwin11-llvm-g++-4.2 (GCC) 4.2.1 (Based on Apple Inc. build 5658) (LLVM build 2335.15.00)" "llvm-g++" "4.2.1")
+ ei_test1_get_compilerver_from_cxx_version_string("g++-mp-4.4 (GCC) 4.4.6" "g++" "4.4.6")
+ ei_test1_get_compilerver_from_cxx_version_string("g++-mp-4.4 (GCC) 2011" "g++" "4.4")
+endmacro(ei_test_get_compilerver_from_cxx_version_string)
diff --git a/cmake/FindAdolc.cmake b/cmake/FindAdolc.cmake
new file mode 100644
index 000000000..1a7ff3628
--- /dev/null
+++ b/cmake/FindAdolc.cmake
@@ -0,0 +1,20 @@
+
+if (ADOLC_INCLUDES AND ADOLC_LIBRARIES)
+ set(ADOLC_FIND_QUIETLY TRUE)
+endif (ADOLC_INCLUDES AND ADOLC_LIBRARIES)
+
+find_path(ADOLC_INCLUDES
+ NAMES
+ adolc/adouble.h
+ PATHS
+ $ENV{ADOLCDIR}
+ ${INCLUDE_INSTALL_DIR}
+)
+
+find_library(ADOLC_LIBRARIES adolc PATHS $ENV{ADOLCDIR} ${LIB_INSTALL_DIR})
+
+include(FindPackageHandleStandardArgs)
+find_package_handle_standard_args(ADOLC DEFAULT_MSG
+ ADOLC_INCLUDES ADOLC_LIBRARIES)
+
+mark_as_advanced(ADOLC_INCLUDES ADOLC_LIBRARIES)
diff --git a/cmake/FindBLAS.cmake b/cmake/FindBLAS.cmake
new file mode 100644
index 000000000..68c4e0724
--- /dev/null
+++ b/cmake/FindBLAS.cmake
@@ -0,0 +1,419 @@
+# Find BLAS library
+#
+# This module finds an installed library that implements the BLAS
+# linear-algebra interface (see http://www.netlib.org/blas/).
+# The list of libraries searched for is mainly taken
+# from the autoconf macro file, acx_blas.m4 (distributed at
+# http://ac-archive.sourceforge.net/ac-archive/acx_blas.html).
+#
+# This module sets the following variables:
+# BLAS_FOUND - set to true if a library implementing the BLAS interface
+# is found
+# BLAS_INCLUDE_DIR - Directories containing the BLAS header files
+# BLAS_DEFINITIONS - Compilation options to use BLAS
+# BLAS_LINKER_FLAGS - Linker flags to use BLAS (excluding -l
+# and -L).
+# BLAS_LIBRARIES_DIR - Directories containing the BLAS libraries.
+# May be null if BLAS_LIBRARIES contains libraries name using full path.
+# BLAS_LIBRARIES - List of libraries to link against BLAS interface.
+# May be null if the compiler supports auto-link (e.g. VC++).
+# BLAS_USE_FILE - The name of the cmake module to include to compile
+# applications or libraries using BLAS.
+#
+# This module was modified by CGAL team:
+# - find libraries for a C++ compiler, instead of Fortran
+# - added BLAS_INCLUDE_DIR, BLAS_DEFINITIONS and BLAS_LIBRARIES_DIR
+# - removed BLAS95_LIBRARIES
+
+include(CheckFunctionExists)
+
+
+# This macro checks for the existence of the combination of fortran libraries
+# given by _list. If the combination is found, this macro checks (using the
+# check_function_exists macro) whether can link against that library
+# combination using the name of a routine given by _name using the linker
+# flags given by _flags. If the combination of libraries is found and passes
+# the link test, LIBRARIES is set to the list of complete library paths that
+# have been found and DEFINITIONS to the required definitions.
+# Otherwise, LIBRARIES is set to FALSE.
+# N.B. _prefix is the prefix applied to the names of all cached variables that
+# are generated internally and marked advanced by this macro.
+macro(check_fortran_libraries DEFINITIONS LIBRARIES _prefix _name _flags _list _path)
+ #message("DEBUG: check_fortran_libraries(${_list} in ${_path})")
+
+ # Check for the existence of the libraries given by _list
+ set(_libraries_found TRUE)
+ set(_libraries_work FALSE)
+ set(${DEFINITIONS} "")
+ set(${LIBRARIES} "")
+ set(_combined_name)
+ foreach(_library ${_list})
+ set(_combined_name ${_combined_name}_${_library})
+
+ if(_libraries_found)
+ # search first in ${_path}
+ find_library(${_prefix}_${_library}_LIBRARY
+ NAMES ${_library}
+ PATHS ${_path} NO_DEFAULT_PATH
+ )
+ # if not found, search in environment variables and system
+ if ( WIN32 )
+ find_library(${_prefix}_${_library}_LIBRARY
+ NAMES ${_library}
+ PATHS ENV LIB
+ )
+ elseif ( APPLE )
+ find_library(${_prefix}_${_library}_LIBRARY
+ NAMES ${_library}
+ PATHS /usr/local/lib /usr/lib /usr/local/lib64 /usr/lib64 ENV DYLD_LIBRARY_PATH
+ )
+ else ()
+ find_library(${_prefix}_${_library}_LIBRARY
+ NAMES ${_library}
+ PATHS /usr/local/lib /usr/lib /usr/local/lib64 /usr/lib64 ENV LD_LIBRARY_PATH
+ )
+ endif()
+ mark_as_advanced(${_prefix}_${_library}_LIBRARY)
+ set(${LIBRARIES} ${${LIBRARIES}} ${${_prefix}_${_library}_LIBRARY})
+ set(_libraries_found ${${_prefix}_${_library}_LIBRARY})
+ endif(_libraries_found)
+ endforeach(_library ${_list})
+ if(_libraries_found)
+ set(_libraries_found ${${LIBRARIES}})
+ endif()
+
+ # Test this combination of libraries with the Fortran/f2c interface.
+ # We test the Fortran interface first as it is well standardized.
+ if(_libraries_found AND NOT _libraries_work)
+ set(${DEFINITIONS} "-D${_prefix}_USE_F2C")
+ set(${LIBRARIES} ${_libraries_found})
+ # Some C++ linkers require the f2c library to link with Fortran libraries.
+ # I do not know which ones, thus I just add the f2c library if it is available.
+ find_package( F2C QUIET )
+ if ( F2C_FOUND )
+ set(${DEFINITIONS} ${${DEFINITIONS}} ${F2C_DEFINITIONS})
+ set(${LIBRARIES} ${${LIBRARIES}} ${F2C_LIBRARIES})
+ endif()
+ set(CMAKE_REQUIRED_DEFINITIONS ${${DEFINITIONS}})
+ set(CMAKE_REQUIRED_LIBRARIES ${_flags} ${${LIBRARIES}})
+ #message("DEBUG: CMAKE_REQUIRED_DEFINITIONS = ${CMAKE_REQUIRED_DEFINITIONS}")
+ #message("DEBUG: CMAKE_REQUIRED_LIBRARIES = ${CMAKE_REQUIRED_LIBRARIES}")
+ # Check if function exists with f2c calling convention (ie a trailing underscore)
+ check_function_exists(${_name}_ ${_prefix}_${_name}_${_combined_name}_f2c_WORKS)
+ set(CMAKE_REQUIRED_DEFINITIONS} "")
+ set(CMAKE_REQUIRED_LIBRARIES "")
+ mark_as_advanced(${_prefix}_${_name}_${_combined_name}_f2c_WORKS)
+ set(_libraries_work ${${_prefix}_${_name}_${_combined_name}_f2c_WORKS})
+ endif(_libraries_found AND NOT _libraries_work)
+
+ # If not found, test this combination of libraries with a C interface.
+ # A few implementations (ie ACML) provide a C interface. Unfortunately, there is no standard.
+ if(_libraries_found AND NOT _libraries_work)
+ set(${DEFINITIONS} "")
+ set(${LIBRARIES} ${_libraries_found})
+ set(CMAKE_REQUIRED_DEFINITIONS "")
+ set(CMAKE_REQUIRED_LIBRARIES ${_flags} ${${LIBRARIES}})
+ #message("DEBUG: CMAKE_REQUIRED_LIBRARIES = ${CMAKE_REQUIRED_LIBRARIES}")
+ check_function_exists(${_name} ${_prefix}_${_name}${_combined_name}_WORKS)
+ set(CMAKE_REQUIRED_LIBRARIES "")
+ mark_as_advanced(${_prefix}_${_name}${_combined_name}_WORKS)
+ set(_libraries_work ${${_prefix}_${_name}${_combined_name}_WORKS})
+ endif(_libraries_found AND NOT _libraries_work)
+
+ # on failure
+ if(NOT _libraries_work)
+ set(${DEFINITIONS} "")
+ set(${LIBRARIES} FALSE)
+ endif()
+ #message("DEBUG: ${DEFINITIONS} = ${${DEFINITIONS}}")
+ #message("DEBUG: ${LIBRARIES} = ${${LIBRARIES}}")
+endmacro(check_fortran_libraries)
+
+
+#
+# main
+#
+
+# Is it already configured?
+if (BLAS_LIBRARIES_DIR OR BLAS_LIBRARIES)
+
+ set(BLAS_FOUND TRUE)
+
+else()
+
+ # reset variables
+ set( BLAS_INCLUDE_DIR "" )
+ set( BLAS_DEFINITIONS "" )
+ set( BLAS_LINKER_FLAGS "" )
+ set( BLAS_LIBRARIES "" )
+ set( BLAS_LIBRARIES_DIR "" )
+
+ #
+ # If Unix, search for BLAS function in possible libraries
+ #
+
+ # BLAS in ATLAS library? (http://math-atlas.sourceforge.net/)
+ if(NOT BLAS_LIBRARIES)
+ check_fortran_libraries(
+ BLAS_DEFINITIONS
+ BLAS_LIBRARIES
+ BLAS
+ sgemm
+ ""
+ "cblas;f77blas;atlas"
+ "${CGAL_TAUCS_LIBRARIES_DIR} ENV BLAS_LIB_DIR"
+ )
+ endif()
+
+ # BLAS in PhiPACK libraries? (requires generic BLAS lib, too)
+ if(NOT BLAS_LIBRARIES)
+ check_fortran_libraries(
+ BLAS_DEFINITIONS
+ BLAS_LIBRARIES
+ BLAS
+ sgemm
+ ""
+ "sgemm;dgemm;blas"
+ "${CGAL_TAUCS_LIBRARIES_DIR} ENV BLAS_LIB_DIR"
+ )
+ endif()
+
+ # BLAS in Alpha CXML library?
+ if(NOT BLAS_LIBRARIES)
+ check_fortran_libraries(
+ BLAS_DEFINITIONS
+ BLAS_LIBRARIES
+ BLAS
+ sgemm
+ ""
+ "cxml"
+ "${CGAL_TAUCS_LIBRARIES_DIR} ENV BLAS_LIB_DIR"
+ )
+ endif()
+
+ # BLAS in Alpha DXML library? (now called CXML, see above)
+ if(NOT BLAS_LIBRARIES)
+ check_fortran_libraries(
+ BLAS_DEFINITIONS
+ BLAS_LIBRARIES
+ BLAS
+ sgemm
+ ""
+ "dxml"
+ "${CGAL_TAUCS_LIBRARIES_DIR} ENV BLAS_LIB_DIR"
+ )
+ endif()
+
+ # BLAS in Sun Performance library?
+ if(NOT BLAS_LIBRARIES)
+ check_fortran_libraries(
+ BLAS_DEFINITIONS
+ BLAS_LIBRARIES
+ BLAS
+ sgemm
+ "-xlic_lib=sunperf"
+ "sunperf;sunmath"
+ "${CGAL_TAUCS_LIBRARIES_DIR} ENV BLAS_LIB_DIR"
+ )
+ if(BLAS_LIBRARIES)
+ # Extra linker flag
+ set(BLAS_LINKER_FLAGS "-xlic_lib=sunperf")
+ endif()
+ endif()
+
+ # BLAS in SCSL library? (SGI/Cray Scientific Library)
+ if(NOT BLAS_LIBRARIES)
+ check_fortran_libraries(
+ BLAS_DEFINITIONS
+ BLAS_LIBRARIES
+ BLAS
+ sgemm
+ ""
+ "scsl"
+ "${CGAL_TAUCS_LIBRARIES_DIR} ENV BLAS_LIB_DIR"
+ )
+ endif()
+
+ # BLAS in SGIMATH library?
+ if(NOT BLAS_LIBRARIES)
+ check_fortran_libraries(
+ BLAS_DEFINITIONS
+ BLAS_LIBRARIES
+ BLAS
+ sgemm
+ ""
+ "complib.sgimath"
+ "${CGAL_TAUCS_LIBRARIES_DIR} ENV BLAS_LIB_DIR"
+ )
+ endif()
+
+ # BLAS in IBM ESSL library? (requires generic BLAS lib, too)
+ if(NOT BLAS_LIBRARIES)
+ check_fortran_libraries(
+ BLAS_DEFINITIONS
+ BLAS_LIBRARIES
+ BLAS
+ sgemm
+ ""
+ "essl;blas"
+ "${CGAL_TAUCS_LIBRARIES_DIR} ENV BLAS_LIB_DIR"
+ )
+ endif()
+
+ #BLAS in intel mkl 10 library? (em64t 64bit)
+ if(NOT BLAS_LIBRARIES)
+ check_fortran_libraries(
+ BLAS_DEFINITIONS
+ BLAS_LIBRARIES
+ BLAS
+ sgemm
+ ""
+ "mkl_intel_lp64;mkl_intel_thread;mkl_core;guide;pthread"
+ "${CGAL_TAUCS_LIBRARIES_DIR} ENV BLAS_LIB_DIR"
+ )
+ endif()
+
+ ### windows version of intel mkl 10?
+ if(NOT BLAS_LIBRARIES)
+ check_fortran_libraries(
+ BLAS_DEFINITIONS
+ BLAS_LIBRARIES
+ BLAS
+ SGEMM
+ ""
+ "mkl_c_dll;mkl_intel_thread_dll;mkl_core_dll;libguide40"
+ "${CGAL_TAUCS_LIBRARIES_DIR} ENV BLAS_LIB_DIR"
+ )
+ endif()
+
+ #older versions of intel mkl libs
+
+ # BLAS in intel mkl library? (shared)
+ if(NOT BLAS_LIBRARIES)
+ check_fortran_libraries(
+ BLAS_DEFINITIONS
+ BLAS_LIBRARIES
+ BLAS
+ sgemm
+ ""
+ "mkl;guide;pthread"
+ "${CGAL_TAUCS_LIBRARIES_DIR} ENV BLAS_LIB_DIR"
+ )
+ endif()
+
+ #BLAS in intel mkl library? (static, 32bit)
+ if(NOT BLAS_LIBRARIES)
+ check_fortran_libraries(
+ BLAS_DEFINITIONS
+ BLAS_LIBRARIES
+ BLAS
+ sgemm
+ ""
+ "mkl_ia32;guide;pthread"
+ "${CGAL_TAUCS_LIBRARIES_DIR} ENV BLAS_LIB_DIR"
+ )
+ endif()
+
+ #BLAS in intel mkl library? (static, em64t 64bit)
+ if(NOT BLAS_LIBRARIES)
+ check_fortran_libraries(
+ BLAS_DEFINITIONS
+ BLAS_LIBRARIES
+ BLAS
+ sgemm
+ ""
+ "mkl_em64t;guide;pthread"
+ "${CGAL_TAUCS_LIBRARIES_DIR} ENV BLAS_LIB_DIR"
+ )
+ endif()
+
+ #BLAS in acml library?
+ if(NOT BLAS_LIBRARIES)
+ check_fortran_libraries(
+ BLAS_DEFINITIONS
+ BLAS_LIBRARIES
+ BLAS
+ sgemm
+ ""
+ "acml"
+ "${CGAL_TAUCS_LIBRARIES_DIR} ENV BLAS_LIB_DIR"
+ )
+ endif()
+
+ # Apple BLAS library?
+ if(NOT BLAS_LIBRARIES)
+ check_fortran_libraries(
+ BLAS_DEFINITIONS
+ BLAS_LIBRARIES
+ BLAS
+ sgemm
+ ""
+ "Accelerate"
+ "${CGAL_TAUCS_LIBRARIES_DIR} ENV BLAS_LIB_DIR"
+ )
+ endif()
+
+ if ( NOT BLAS_LIBRARIES )
+ check_fortran_libraries(
+ BLAS_DEFINITIONS
+ BLAS_LIBRARIES
+ BLAS
+ sgemm
+ ""
+ "vecLib"
+ "${CGAL_TAUCS_LIBRARIES_DIR} ENV BLAS_LIB_DIR"
+ )
+ endif ( NOT BLAS_LIBRARIES )
+
+ # Generic BLAS library?
+ # This configuration *must* be the last try as this library is notably slow.
+ if ( NOT BLAS_LIBRARIES )
+ check_fortran_libraries(
+ BLAS_DEFINITIONS
+ BLAS_LIBRARIES
+ BLAS
+ sgemm
+ ""
+ "blas"
+ "${CGAL_TAUCS_LIBRARIES_DIR} ENV BLAS_LIB_DIR"
+ )
+ endif()
+
+ if(BLAS_LIBRARIES_DIR OR BLAS_LIBRARIES)
+ set(BLAS_FOUND TRUE)
+ else()
+ set(BLAS_FOUND FALSE)
+ endif()
+
+ if(NOT BLAS_FIND_QUIETLY)
+ if(BLAS_FOUND)
+ message(STATUS "A library with BLAS API found.")
+ else(BLAS_FOUND)
+ if(BLAS_FIND_REQUIRED)
+ message(FATAL_ERROR "A required library with BLAS API not found. Please specify library location.")
+ else()
+ message(STATUS "A library with BLAS API not found. Please specify library location.")
+ endif()
+ endif(BLAS_FOUND)
+ endif(NOT BLAS_FIND_QUIETLY)
+
+ # Add variables to cache
+ set( BLAS_INCLUDE_DIR "${BLAS_INCLUDE_DIR}"
+ CACHE PATH "Directories containing the BLAS header files" FORCE )
+ set( BLAS_DEFINITIONS "${BLAS_DEFINITIONS}"
+ CACHE STRING "Compilation options to use BLAS" FORCE )
+ set( BLAS_LINKER_FLAGS "${BLAS_LINKER_FLAGS}"
+ CACHE STRING "Linker flags to use BLAS" FORCE )
+ set( BLAS_LIBRARIES "${BLAS_LIBRARIES}"
+ CACHE FILEPATH "BLAS libraries name" FORCE )
+ set( BLAS_LIBRARIES_DIR "${BLAS_LIBRARIES_DIR}"
+ CACHE PATH "Directories containing the BLAS libraries" FORCE )
+
+ #message("DEBUG: BLAS_INCLUDE_DIR = ${BLAS_INCLUDE_DIR}")
+ #message("DEBUG: BLAS_DEFINITIONS = ${BLAS_DEFINITIONS}")
+ #message("DEBUG: BLAS_LINKER_FLAGS = ${BLAS_LINKER_FLAGS}")
+ #message("DEBUG: BLAS_LIBRARIES = ${BLAS_LIBRARIES}")
+ #message("DEBUG: BLAS_LIBRARIES_DIR = ${BLAS_LIBRARIES_DIR}")
+ #message("DEBUG: BLAS_FOUND = ${BLAS_FOUND}")
+
+endif(BLAS_LIBRARIES_DIR OR BLAS_LIBRARIES)
diff --git a/cmake/FindCholmod.cmake b/cmake/FindCholmod.cmake
new file mode 100644
index 000000000..9095bea31
--- /dev/null
+++ b/cmake/FindCholmod.cmake
@@ -0,0 +1,80 @@
+# Cholmod lib usually requires linking to a blas and lapack library.
+# It is up to the user of this module to find a BLAS and link to it.
+
+if (CHOLMOD_INCLUDES AND CHOLMOD_LIBRARIES)
+ set(CHOLMOD_FIND_QUIETLY TRUE)
+endif (CHOLMOD_INCLUDES AND CHOLMOD_LIBRARIES)
+
+find_path(CHOLMOD_INCLUDES
+ NAMES
+ cholmod.h
+ PATHS
+ $ENV{CHOLMODDIR}
+ ${INCLUDE_INSTALL_DIR}
+ PATH_SUFFIXES
+ suitesparse
+ ufsparse
+)
+
+find_library(CHOLMOD_LIBRARIES cholmod PATHS $ENV{CHOLMODDIR} ${LIB_INSTALL_DIR})
+
+if(CHOLMOD_LIBRARIES)
+
+ get_filename_component(CHOLMOD_LIBDIR ${CHOLMOD_LIBRARIES} PATH)
+
+ find_library(AMD_LIBRARY amd PATHS ${CHOLMOD_LIBDIR} $ENV{CHOLMODDIR} ${LIB_INSTALL_DIR})
+ if (AMD_LIBRARY)
+ set(CHOLMOD_LIBRARIES ${CHOLMOD_LIBRARIES} ${AMD_LIBRARY})
+ else ()
+ set(CHOLMOD_LIBRARIES FALSE)
+ endif ()
+
+endif(CHOLMOD_LIBRARIES)
+
+if(CHOLMOD_LIBRARIES)
+
+ find_library(COLAMD_LIBRARY colamd PATHS ${CHOLMOD_LIBDIR} $ENV{CHOLMODDIR} ${LIB_INSTALL_DIR})
+ if (COLAMD_LIBRARY)
+ set(CHOLMOD_LIBRARIES ${CHOLMOD_LIBRARIES} ${COLAMD_LIBRARY})
+ else ()
+ set(CHOLMOD_LIBRARIES FALSE)
+ endif ()
+
+endif(CHOLMOD_LIBRARIES)
+
+if(CHOLMOD_LIBRARIES)
+
+ find_library(CAMD_LIBRARY camd PATHS ${CHOLMOD_LIBDIR} $ENV{CHOLMODDIR} ${LIB_INSTALL_DIR})
+ if (CAMD_LIBRARY)
+ set(CHOLMOD_LIBRARIES ${CHOLMOD_LIBRARIES} ${CAMD_LIBRARY})
+ else ()
+ set(CHOLMOD_LIBRARIES FALSE)
+ endif ()
+
+endif(CHOLMOD_LIBRARIES)
+
+if(CHOLMOD_LIBRARIES)
+
+ find_library(CCOLAMD_LIBRARY ccolamd PATHS ${CHOLMOD_LIBDIR} $ENV{CHOLMODDIR} ${LIB_INSTALL_DIR})
+ if (CCOLAMD_LIBRARY)
+ set(CHOLMOD_LIBRARIES ${CHOLMOD_LIBRARIES} ${CCOLAMD_LIBRARY})
+ else ()
+ set(CHOLMOD_LIBRARIES FALSE)
+ endif ()
+
+endif(CHOLMOD_LIBRARIES)
+
+if(CHOLMOD_LIBRARIES)
+
+ find_library(CHOLMOD_METIS_LIBRARY metis PATHS ${CHOLMOD_LIBDIR} $ENV{CHOLMODDIR} ${LIB_INSTALL_DIR})
+ if (CHOLMOD_METIS_LIBRARY)
+ set(CHOLMOD_LIBRARIES ${CHOLMOD_LIBRARIES} ${CHOLMOD_METIS_LIBRARY})
+ endif ()
+
+endif(CHOLMOD_LIBRARIES)
+
+include(FindPackageHandleStandardArgs)
+find_package_handle_standard_args(CHOLMOD DEFAULT_MSG
+ CHOLMOD_INCLUDES CHOLMOD_LIBRARIES)
+
+mark_as_advanced(CHOLMOD_INCLUDES CHOLMOD_LIBRARIES AMD_LIBRARY COLAMD_LIBRARY)
diff --git a/cmake/FindEigen2.cmake b/cmake/FindEigen2.cmake
new file mode 100644
index 000000000..a834b8872
--- /dev/null
+++ b/cmake/FindEigen2.cmake
@@ -0,0 +1,80 @@
+# - Try to find Eigen2 lib
+#
+# This module supports requiring a minimum version, e.g. you can do
+# find_package(Eigen2 2.0.3)
+# to require version 2.0.3 to newer of Eigen2.
+#
+# Once done this will define
+#
+# EIGEN2_FOUND - system has eigen lib with correct version
+# EIGEN2_INCLUDE_DIR - the eigen include directory
+# EIGEN2_VERSION - eigen version
+
+# Copyright (c) 2006, 2007 Montel Laurent, <montel@kde.org>
+# Copyright (c) 2008, 2009 Gael Guennebaud, <g.gael@free.fr>
+# Redistribution and use is allowed according to the terms of the BSD license.
+
+if(NOT Eigen2_FIND_VERSION)
+ if(NOT Eigen2_FIND_VERSION_MAJOR)
+ set(Eigen2_FIND_VERSION_MAJOR 2)
+ endif(NOT Eigen2_FIND_VERSION_MAJOR)
+ if(NOT Eigen2_FIND_VERSION_MINOR)
+ set(Eigen2_FIND_VERSION_MINOR 0)
+ endif(NOT Eigen2_FIND_VERSION_MINOR)
+ if(NOT Eigen2_FIND_VERSION_PATCH)
+ set(Eigen2_FIND_VERSION_PATCH 0)
+ endif(NOT Eigen2_FIND_VERSION_PATCH)
+
+ set(Eigen2_FIND_VERSION "${Eigen2_FIND_VERSION_MAJOR}.${Eigen2_FIND_VERSION_MINOR}.${Eigen2_FIND_VERSION_PATCH}")
+endif(NOT Eigen2_FIND_VERSION)
+
+macro(_eigen2_check_version)
+ file(READ "${EIGEN2_INCLUDE_DIR}/Eigen/src/Core/util/Macros.h" _eigen2_version_header)
+
+ string(REGEX MATCH "define[ \t]+EIGEN_WORLD_VERSION[ \t]+([0-9]+)" _eigen2_world_version_match "${_eigen2_version_header}")
+ set(EIGEN2_WORLD_VERSION "${CMAKE_MATCH_1}")
+ string(REGEX MATCH "define[ \t]+EIGEN_MAJOR_VERSION[ \t]+([0-9]+)" _eigen2_major_version_match "${_eigen2_version_header}")
+ set(EIGEN2_MAJOR_VERSION "${CMAKE_MATCH_1}")
+ string(REGEX MATCH "define[ \t]+EIGEN_MINOR_VERSION[ \t]+([0-9]+)" _eigen2_minor_version_match "${_eigen2_version_header}")
+ set(EIGEN2_MINOR_VERSION "${CMAKE_MATCH_1}")
+
+ set(EIGEN2_VERSION ${EIGEN2_WORLD_VERSION}.${EIGEN2_MAJOR_VERSION}.${EIGEN2_MINOR_VERSION})
+ if((${EIGEN2_WORLD_VERSION} NOTEQUAL 2) OR (${EIGEN2_MAJOR_VERSION} GREATER 10) OR (${EIGEN2_VERSION} VERSION_LESS ${Eigen2_FIND_VERSION}))
+ set(EIGEN2_VERSION_OK FALSE)
+ else()
+ set(EIGEN2_VERSION_OK TRUE)
+ endif()
+
+ if(NOT EIGEN2_VERSION_OK)
+
+ message(STATUS "Eigen2 version ${EIGEN2_VERSION} found in ${EIGEN2_INCLUDE_DIR}, "
+ "but at least version ${Eigen2_FIND_VERSION} is required")
+ endif(NOT EIGEN2_VERSION_OK)
+endmacro(_eigen2_check_version)
+
+if (EIGEN2_INCLUDE_DIR)
+
+ # in cache already
+ _eigen2_check_version()
+ set(EIGEN2_FOUND ${EIGEN2_VERSION_OK})
+
+else (EIGEN2_INCLUDE_DIR)
+
+find_path(EIGEN2_INCLUDE_DIR NAMES Eigen/Core
+ PATHS
+ ${INCLUDE_INSTALL_DIR}
+ ${KDE4_INCLUDE_DIR}
+ PATH_SUFFIXES eigen2
+ )
+
+if(EIGEN2_INCLUDE_DIR)
+ _eigen2_check_version()
+endif(EIGEN2_INCLUDE_DIR)
+
+include(FindPackageHandleStandardArgs)
+find_package_handle_standard_args(Eigen2 DEFAULT_MSG EIGEN2_INCLUDE_DIR EIGEN2_VERSION_OK)
+
+mark_as_advanced(EIGEN2_INCLUDE_DIR)
+
+endif(EIGEN2_INCLUDE_DIR)
+
diff --git a/cmake/FindEigen3.cmake b/cmake/FindEigen3.cmake
new file mode 100644
index 000000000..9c546a05d
--- /dev/null
+++ b/cmake/FindEigen3.cmake
@@ -0,0 +1,81 @@
+# - Try to find Eigen3 lib
+#
+# This module supports requiring a minimum version, e.g. you can do
+# find_package(Eigen3 3.1.2)
+# to require version 3.1.2 or newer of Eigen3.
+#
+# Once done this will define
+#
+# EIGEN3_FOUND - system has eigen lib with correct version
+# EIGEN3_INCLUDE_DIR - the eigen include directory
+# EIGEN3_VERSION - eigen version
+
+# Copyright (c) 2006, 2007 Montel Laurent, <montel@kde.org>
+# Copyright (c) 2008, 2009 Gael Guennebaud, <g.gael@free.fr>
+# Copyright (c) 2009 Benoit Jacob <jacob.benoit.1@gmail.com>
+# Redistribution and use is allowed according to the terms of the 2-clause BSD license.
+
+if(NOT Eigen3_FIND_VERSION)
+ if(NOT Eigen3_FIND_VERSION_MAJOR)
+ set(Eigen3_FIND_VERSION_MAJOR 2)
+ endif(NOT Eigen3_FIND_VERSION_MAJOR)
+ if(NOT Eigen3_FIND_VERSION_MINOR)
+ set(Eigen3_FIND_VERSION_MINOR 91)
+ endif(NOT Eigen3_FIND_VERSION_MINOR)
+ if(NOT Eigen3_FIND_VERSION_PATCH)
+ set(Eigen3_FIND_VERSION_PATCH 0)
+ endif(NOT Eigen3_FIND_VERSION_PATCH)
+
+ set(Eigen3_FIND_VERSION "${Eigen3_FIND_VERSION_MAJOR}.${Eigen3_FIND_VERSION_MINOR}.${Eigen3_FIND_VERSION_PATCH}")
+endif(NOT Eigen3_FIND_VERSION)
+
+macro(_eigen3_check_version)
+ file(READ "${EIGEN3_INCLUDE_DIR}/Eigen/src/Core/util/Macros.h" _eigen3_version_header)
+
+ string(REGEX MATCH "define[ \t]+EIGEN_WORLD_VERSION[ \t]+([0-9]+)" _eigen3_world_version_match "${_eigen3_version_header}")
+ set(EIGEN3_WORLD_VERSION "${CMAKE_MATCH_1}")
+ string(REGEX MATCH "define[ \t]+EIGEN_MAJOR_VERSION[ \t]+([0-9]+)" _eigen3_major_version_match "${_eigen3_version_header}")
+ set(EIGEN3_MAJOR_VERSION "${CMAKE_MATCH_1}")
+ string(REGEX MATCH "define[ \t]+EIGEN_MINOR_VERSION[ \t]+([0-9]+)" _eigen3_minor_version_match "${_eigen3_version_header}")
+ set(EIGEN3_MINOR_VERSION "${CMAKE_MATCH_1}")
+
+ set(EIGEN3_VERSION ${EIGEN3_WORLD_VERSION}.${EIGEN3_MAJOR_VERSION}.${EIGEN3_MINOR_VERSION})
+ if(${EIGEN3_VERSION} VERSION_LESS ${Eigen3_FIND_VERSION})
+ set(EIGEN3_VERSION_OK FALSE)
+ else(${EIGEN3_VERSION} VERSION_LESS ${Eigen3_FIND_VERSION})
+ set(EIGEN3_VERSION_OK TRUE)
+ endif(${EIGEN3_VERSION} VERSION_LESS ${Eigen3_FIND_VERSION})
+
+ if(NOT EIGEN3_VERSION_OK)
+
+ message(STATUS "Eigen3 version ${EIGEN3_VERSION} found in ${EIGEN3_INCLUDE_DIR}, "
+ "but at least version ${Eigen3_FIND_VERSION} is required")
+ endif(NOT EIGEN3_VERSION_OK)
+endmacro(_eigen3_check_version)
+
+if (EIGEN3_INCLUDE_DIR)
+
+ # in cache already
+ _eigen3_check_version()
+ set(EIGEN3_FOUND ${EIGEN3_VERSION_OK})
+
+else (EIGEN3_INCLUDE_DIR)
+
+ find_path(EIGEN3_INCLUDE_DIR NAMES signature_of_eigen3_matrix_library
+ PATHS
+ ${CMAKE_INSTALL_PREFIX}/include
+ ${KDE4_INCLUDE_DIR}
+ PATH_SUFFIXES eigen3 eigen
+ )
+
+ if(EIGEN3_INCLUDE_DIR)
+ _eigen3_check_version()
+ endif(EIGEN3_INCLUDE_DIR)
+
+ include(FindPackageHandleStandardArgs)
+ find_package_handle_standard_args(Eigen3 DEFAULT_MSG EIGEN3_INCLUDE_DIR EIGEN3_VERSION_OK)
+
+ mark_as_advanced(EIGEN3_INCLUDE_DIR)
+
+endif(EIGEN3_INCLUDE_DIR)
+
diff --git a/cmake/FindFFTW.cmake b/cmake/FindFFTW.cmake
new file mode 100644
index 000000000..a9e9925e7
--- /dev/null
+++ b/cmake/FindFFTW.cmake
@@ -0,0 +1,119 @@
+# - Find the FFTW library
+#
+# Usage:
+# find_package(FFTW [REQUIRED] [QUIET] )
+#
+# It sets the following variables:
+# FFTW_FOUND ... true if fftw is found on the system
+# FFTW_LIBRARIES ... full path to fftw library
+# FFTW_INCLUDES ... fftw include directory
+#
+# The following variables will be checked by the function
+# FFTW_USE_STATIC_LIBS ... if true, only static libraries are found
+# FFTW_ROOT ... if set, the libraries are exclusively searched
+# under this path
+# FFTW_LIBRARY ... fftw library to use
+# FFTW_INCLUDE_DIR ... fftw include directory
+#
+
+#If environment variable FFTWDIR is specified, it has same effect as FFTW_ROOT
+if( NOT FFTW_ROOT AND ENV{FFTWDIR} )
+ set( FFTW_ROOT $ENV{FFTWDIR} )
+endif()
+
+# Check if we can use PkgConfig
+find_package(PkgConfig)
+
+#Determine from PKG
+if( PKG_CONFIG_FOUND AND NOT FFTW_ROOT )
+ pkg_check_modules( PKG_FFTW QUIET "fftw3" )
+endif()
+
+#Check whether to search static or dynamic libs
+set( CMAKE_FIND_LIBRARY_SUFFIXES_SAV ${CMAKE_FIND_LIBRARY_SUFFIXES} )
+
+if( ${FFTW_USE_STATIC_LIBS} )
+ set( CMAKE_FIND_LIBRARY_SUFFIXES ${CMAKE_STATIC_LIBRARY_SUFFIX} )
+else()
+ set( CMAKE_FIND_LIBRARY_SUFFIXES ${CMAKE_SHARED_LIBRARY_SUFFIX} )
+endif()
+
+if( FFTW_ROOT )
+
+ #find libs
+ find_library(
+ FFTW_LIB
+ NAMES "fftw3"
+ PATHS ${FFTW_ROOT}
+ PATH_SUFFIXES "lib" "lib64"
+ NO_DEFAULT_PATH
+ )
+
+ find_library(
+ FFTWF_LIB
+ NAMES "fftw3f"
+ PATHS ${FFTW_ROOT}
+ PATH_SUFFIXES "lib" "lib64"
+ NO_DEFAULT_PATH
+ )
+
+ find_library(
+ FFTWL_LIB
+ NAMES "fftw3l"
+ PATHS ${FFTW_ROOT}
+ PATH_SUFFIXES "lib" "lib64"
+ NO_DEFAULT_PATH
+ )
+
+ #find includes
+ find_path(
+ FFTW_INCLUDES
+ NAMES "fftw3.h"
+ PATHS ${FFTW_ROOT}
+ PATH_SUFFIXES "include"
+ NO_DEFAULT_PATH
+ )
+
+else()
+
+ find_library(
+ FFTW_LIB
+ NAMES "fftw3"
+ PATHS ${PKG_FFTW_LIBRARY_DIRS} ${LIB_INSTALL_DIR}
+ )
+
+ find_library(
+ FFTWF_LIB
+ NAMES "fftw3f"
+ PATHS ${PKG_FFTW_LIBRARY_DIRS} ${LIB_INSTALL_DIR}
+ )
+
+
+ find_library(
+ FFTWL_LIB
+ NAMES "fftw3l"
+ PATHS ${PKG_FFTW_LIBRARY_DIRS} ${LIB_INSTALL_DIR}
+ )
+
+ find_path(
+ FFTW_INCLUDES
+ NAMES "fftw3.h"
+ PATHS ${PKG_FFTW_INCLUDE_DIRS} ${INCLUDE_INSTALL_DIR}
+ )
+
+endif( FFTW_ROOT )
+
+set(FFTW_LIBRARIES ${FFTW_LIB} ${FFTWF_LIB})
+
+if(FFTWL_LIB)
+ set(FFTW_LIBRARIES ${FFTW_LIBRARIES} ${FFTWL_LIB})
+endif()
+
+set( CMAKE_FIND_LIBRARY_SUFFIXES ${CMAKE_FIND_LIBRARY_SUFFIXES_SAV} )
+
+include(FindPackageHandleStandardArgs)
+find_package_handle_standard_args(FFTW DEFAULT_MSG
+ FFTW_INCLUDES FFTW_LIBRARIES)
+
+mark_as_advanced(FFTW_INCLUDES FFTW_LIBRARIES)
+
diff --git a/cmake/FindGLEW.cmake b/cmake/FindGLEW.cmake
new file mode 100644
index 000000000..54da20f12
--- /dev/null
+++ b/cmake/FindGLEW.cmake
@@ -0,0 +1,105 @@
+# Copyright (c) 2009 Boudewijn Rempt <boud@valdyas.org>
+#
+# Redistribution and use is allowed according to the terms of the BSD license.
+# For details see the accompanying COPYING-CMAKE-SCRIPTS file.
+#
+# - try to find glew library and include files
+# GLEW_INCLUDE_DIR, where to find GL/glew.h, etc.
+# GLEW_LIBRARIES, the libraries to link against
+# GLEW_FOUND, If false, do not try to use GLEW.
+# Also defined, but not for general use are:
+# GLEW_GLEW_LIBRARY = the full path to the glew library.
+
+IF (WIN32)
+
+ IF(CYGWIN)
+
+ FIND_PATH( GLEW_INCLUDE_DIR GL/glew.h)
+
+ FIND_LIBRARY( GLEW_GLEW_LIBRARY glew32
+ ${OPENGL_LIBRARY_DIR}
+ /usr/lib/w32api
+ /usr/X11R6/lib
+ )
+
+
+ ELSE(CYGWIN)
+
+ FIND_PATH( GLEW_INCLUDE_DIR GL/glew.h
+ $ENV{GLEW_ROOT_PATH}/include
+ )
+
+ FIND_LIBRARY( GLEW_GLEW_LIBRARY
+ NAMES glew glew32
+ PATHS
+ $ENV{GLEW_ROOT_PATH}/lib
+ ${OPENGL_LIBRARY_DIR}
+ )
+
+ ENDIF(CYGWIN)
+
+ELSE (WIN32)
+
+ IF (APPLE)
+# These values for Apple could probably do with improvement.
+ FIND_PATH( GLEW_INCLUDE_DIR glew.h
+ /System/Library/Frameworks/GLEW.framework/Versions/A/Headers
+ ${OPENGL_LIBRARY_DIR}
+ )
+ SET(GLEW_GLEW_LIBRARY "-framework GLEW" CACHE STRING "GLEW library for OSX")
+ SET(GLEW_cocoa_LIBRARY "-framework Cocoa" CACHE STRING "Cocoa framework for OSX")
+ ELSE (APPLE)
+
+ FIND_PATH( GLEW_INCLUDE_DIR GL/glew.h
+ /usr/include/GL
+ /usr/openwin/share/include
+ /usr/openwin/include
+ /usr/X11R6/include
+ /usr/include/X11
+ /opt/graphics/OpenGL/include
+ /opt/graphics/OpenGL/contrib/libglew
+ )
+
+ FIND_LIBRARY( GLEW_GLEW_LIBRARY GLEW
+ /usr/openwin/lib
+ /usr/X11R6/lib
+ )
+
+ ENDIF (APPLE)
+
+ENDIF (WIN32)
+
+SET( GLEW_FOUND "NO" )
+IF(GLEW_INCLUDE_DIR)
+ IF(GLEW_GLEW_LIBRARY)
+ # Is -lXi and -lXmu required on all platforms that have it?
+ # If not, we need some way to figure out what platform we are on.
+ SET( GLEW_LIBRARIES
+ ${GLEW_GLEW_LIBRARY}
+ ${GLEW_cocoa_LIBRARY}
+ )
+ SET( GLEW_FOUND "YES" )
+
+#The following deprecated settings are for backwards compatibility with CMake1.4
+ SET (GLEW_LIBRARY ${GLEW_LIBRARIES})
+ SET (GLEW_INCLUDE_PATH ${GLEW_INCLUDE_DIR})
+
+ ENDIF(GLEW_GLEW_LIBRARY)
+ENDIF(GLEW_INCLUDE_DIR)
+
+IF(GLEW_FOUND)
+ IF(NOT GLEW_FIND_QUIETLY)
+ MESSAGE(STATUS "Found Glew: ${GLEW_LIBRARIES}")
+ ENDIF(NOT GLEW_FIND_QUIETLY)
+ELSE(GLEW_FOUND)
+ IF(GLEW_FIND_REQUIRED)
+ MESSAGE(FATAL_ERROR "Could not find Glew")
+ ENDIF(GLEW_FIND_REQUIRED)
+ENDIF(GLEW_FOUND)
+
+MARK_AS_ADVANCED(
+ GLEW_INCLUDE_DIR
+ GLEW_GLEW_LIBRARY
+ GLEW_Xmu_LIBRARY
+ GLEW_Xi_LIBRARY
+)
diff --git a/cmake/FindGMP.cmake b/cmake/FindGMP.cmake
new file mode 100644
index 000000000..1f0273960
--- /dev/null
+++ b/cmake/FindGMP.cmake
@@ -0,0 +1,21 @@
+# Try to find the GNU Multiple Precision Arithmetic Library (GMP)
+# See http://gmplib.org/
+
+if (GMP_INCLUDES AND GMP_LIBRARIES)
+ set(GMP_FIND_QUIETLY TRUE)
+endif (GMP_INCLUDES AND GMP_LIBRARIES)
+
+find_path(GMP_INCLUDES
+ NAMES
+ gmp.h
+ PATHS
+ $ENV{GMPDIR}
+ ${INCLUDE_INSTALL_DIR}
+)
+
+find_library(GMP_LIBRARIES gmp PATHS $ENV{GMPDIR} ${LIB_INSTALL_DIR})
+
+include(FindPackageHandleStandardArgs)
+find_package_handle_standard_args(GMP DEFAULT_MSG
+ GMP_INCLUDES GMP_LIBRARIES)
+mark_as_advanced(GMP_INCLUDES GMP_LIBRARIES)
diff --git a/cmake/FindGSL.cmake b/cmake/FindGSL.cmake
new file mode 100644
index 000000000..bf411a7f9
--- /dev/null
+++ b/cmake/FindGSL.cmake
@@ -0,0 +1,170 @@
+# Try to find gnu scientific library GSL
+# See
+# http://www.gnu.org/software/gsl/ and
+# http://gnuwin32.sourceforge.net/packages/gsl.htm
+#
+# Once run this will define:
+#
+# GSL_FOUND = system has GSL lib
+#
+# GSL_LIBRARIES = full path to the libraries
+# on Unix/Linux with additional linker flags from "gsl-config --libs"
+#
+# CMAKE_GSL_CXX_FLAGS = Unix compiler flags for GSL, essentially "`gsl-config --cxxflags`"
+#
+# GSL_INCLUDE_DIR = where to find headers
+#
+# GSL_LINK_DIRECTORIES = link directories, useful for rpath on Unix
+# GSL_EXE_LINKER_FLAGS = rpath on Unix
+#
+# Felix Woelk 07/2004
+# Jan Woetzel
+#
+# www.mip.informatik.uni-kiel.de
+# --------------------------------
+
+IF(WIN32)
+ # JW tested with gsl-1.8, Windows XP, MSVS 7.1
+ SET(GSL_POSSIBLE_ROOT_DIRS
+ ${GSL_ROOT_DIR}
+ $ENV{GSL_ROOT_DIR}
+ ${GSL_DIR}
+ ${GSL_HOME}
+ $ENV{GSL_DIR}
+ $ENV{GSL_HOME}
+ $ENV{EXTRA}
+ "C:/Program Files/GnuWin32"
+ )
+ FIND_PATH(GSL_INCLUDE_DIR
+ NAMES gsl/gsl_cdf.h gsl/gsl_randist.h
+ PATHS ${GSL_POSSIBLE_ROOT_DIRS}
+ PATH_SUFFIXES include
+ DOC "GSL header include dir"
+ )
+
+ FIND_LIBRARY(GSL_GSL_LIBRARY
+ NAMES libgsl.dll.a gsl libgsl
+ PATHS ${GSL_POSSIBLE_ROOT_DIRS}
+ PATH_SUFFIXES lib
+ DOC "GSL library" )
+
+ if(NOT GSL_GSL_LIBRARY)
+ FIND_FILE(GSL_GSL_LIBRARY
+ NAMES libgsl.dll.a
+ PATHS ${GSL_POSSIBLE_ROOT_DIRS}
+ PATH_SUFFIXES lib
+ DOC "GSL library")
+ endif(NOT GSL_GSL_LIBRARY)
+
+ FIND_LIBRARY(GSL_GSLCBLAS_LIBRARY
+ NAMES libgslcblas.dll.a gslcblas libgslcblas
+ PATHS ${GSL_POSSIBLE_ROOT_DIRS}
+ PATH_SUFFIXES lib
+ DOC "GSL cblas library dir" )
+
+ if(NOT GSL_GSLCBLAS_LIBRARY)
+ FIND_FILE(GSL_GSLCBLAS_LIBRARY
+ NAMES libgslcblas.dll.a
+ PATHS ${GSL_POSSIBLE_ROOT_DIRS}
+ PATH_SUFFIXES lib
+ DOC "GSL library")
+ endif(NOT GSL_GSLCBLAS_LIBRARY)
+
+ SET(GSL_LIBRARIES ${GSL_GSL_LIBRARY})
+
+ #MESSAGE("DBG\n"
+ # "GSL_GSL_LIBRARY=${GSL_GSL_LIBRARY}\n"
+ # "GSL_GSLCBLAS_LIBRARY=${GSL_GSLCBLAS_LIBRARY}\n"
+ # "GSL_LIBRARIES=${GSL_LIBRARIES}")
+
+
+ELSE(WIN32)
+
+ IF(UNIX)
+ SET(GSL_CONFIG_PREFER_PATH
+ "$ENV{GSL_DIR}/bin"
+ "$ENV{GSL_DIR}"
+ "$ENV{GSL_HOME}/bin"
+ "$ENV{GSL_HOME}"
+ CACHE STRING "preferred path to GSL (gsl-config)")
+ FIND_PROGRAM(GSL_CONFIG gsl-config
+ ${GSL_CONFIG_PREFER_PATH}
+ /usr/bin/
+ )
+ # MESSAGE("DBG GSL_CONFIG ${GSL_CONFIG}")
+
+ IF (GSL_CONFIG)
+ # set CXXFLAGS to be fed into CXX_FLAGS by the user:
+ SET(GSL_CXX_FLAGS "`${GSL_CONFIG} --cflags`")
+
+ # set INCLUDE_DIRS to prefix+include
+ EXEC_PROGRAM(${GSL_CONFIG}
+ ARGS --prefix
+ OUTPUT_VARIABLE GSL_PREFIX)
+ SET(GSL_INCLUDE_DIR ${GSL_PREFIX}/include CACHE STRING INTERNAL)
+
+ # set link libraries and link flags
+ #SET(GSL_LIBRARIES "`${GSL_CONFIG} --libs`")
+ EXEC_PROGRAM(${GSL_CONFIG}
+ ARGS --libs
+ OUTPUT_VARIABLE GSL_LIBRARIES )
+
+ # extract link dirs for rpath
+ EXEC_PROGRAM(${GSL_CONFIG}
+ ARGS --libs
+ OUTPUT_VARIABLE GSL_CONFIG_LIBS )
+
+ # extract version
+ EXEC_PROGRAM(${GSL_CONFIG}
+ ARGS --version
+ OUTPUT_VARIABLE GSL_FULL_VERSION )
+
+ # split version as major/minor
+ STRING(REGEX MATCH "(.)\\..*" GSL_VERSION_MAJOR_ "${GSL_FULL_VERSION}")
+ SET(GSL_VERSION_MAJOR ${CMAKE_MATCH_1})
+ STRING(REGEX MATCH ".\\.(.*)" GSL_VERSION_MINOR_ "${GSL_FULL_VERSION}")
+ SET(GSL_VERSION_MINOR ${CMAKE_MATCH_1})
+
+ # split off the link dirs (for rpath)
+ # use regular expression to match wildcard equivalent "-L*<endchar>"
+ # with <endchar> is a space or a semicolon
+ STRING(REGEX MATCHALL "[-][L]([^ ;])+"
+ GSL_LINK_DIRECTORIES_WITH_PREFIX
+ "${GSL_CONFIG_LIBS}" )
+ # MESSAGE("DBG GSL_LINK_DIRECTORIES_WITH_PREFIX=${GSL_LINK_DIRECTORIES_WITH_PREFIX}")
+
+ # remove prefix -L because we need the pure directory for LINK_DIRECTORIES
+
+ IF (GSL_LINK_DIRECTORIES_WITH_PREFIX)
+ STRING(REGEX REPLACE "[-][L]" "" GSL_LINK_DIRECTORIES ${GSL_LINK_DIRECTORIES_WITH_PREFIX} )
+ ENDIF (GSL_LINK_DIRECTORIES_WITH_PREFIX)
+ SET(GSL_EXE_LINKER_FLAGS "-Wl,-rpath,${GSL_LINK_DIRECTORIES}" CACHE STRING INTERNAL)
+ # MESSAGE("DBG GSL_LINK_DIRECTORIES=${GSL_LINK_DIRECTORIES}")
+ # MESSAGE("DBG GSL_EXE_LINKER_FLAGS=${GSL_EXE_LINKER_FLAGS}")
+
+ # ADD_DEFINITIONS("-DHAVE_GSL")
+ # SET(GSL_DEFINITIONS "-DHAVE_GSL")
+ MARK_AS_ADVANCED(
+ GSL_CXX_FLAGS
+ GSL_INCLUDE_DIR
+ GSL_LIBRARIES
+ GSL_LINK_DIRECTORIES
+ GSL_DEFINITIONS
+ )
+ MESSAGE(STATUS "Using GSL from ${GSL_PREFIX}")
+
+ ELSE(GSL_CONFIG)
+ MESSAGE("FindGSL.cmake: gsl-config not found. Please set it manually. GSL_CONFIG=${GSL_CONFIG}")
+ ENDIF(GSL_CONFIG)
+
+ ENDIF(UNIX)
+ENDIF(WIN32)
+
+
+IF(GSL_LIBRARIES)
+ IF(GSL_INCLUDE_DIR OR GSL_CXX_FLAGS)
+
+ SET(GSL_FOUND 1)
+
+ ENDIF(GSL_INCLUDE_DIR OR GSL_CXX_FLAGS)
+ENDIF(GSL_LIBRARIES)
diff --git a/cmake/FindGoogleHash.cmake b/cmake/FindGoogleHash.cmake
new file mode 100644
index 000000000..f6a81a02c
--- /dev/null
+++ b/cmake/FindGoogleHash.cmake
@@ -0,0 +1,23 @@
+
+if (GOOGLEHASH_INCLUDES AND GOOGLEHASH_LIBRARIES)
+ set(GOOGLEHASH_FIND_QUIETLY TRUE)
+endif (GOOGLEHASH_INCLUDES AND GOOGLEHASH_LIBRARIES)
+
+find_path(GOOGLEHASH_INCLUDES
+ NAMES
+ google/dense_hash_map
+ PATHS
+ ${INCLUDE_INSTALL_DIR}
+)
+
+if(GOOGLEHASH_INCLUDES)
+ # let's make sure it compiles with the current compiler
+ file(WRITE ${CMAKE_BINARY_DIR}/googlehash_test.cpp
+ "#include <google/sparse_hash_map>\n#include <google/dense_hash_map>\nint main(int argc, char** argv) { google::dense_hash_map<int,float> a; google::sparse_hash_map<int,float> b; return 0;}\n")
+ try_compile(GOOGLEHASH_COMPILE ${CMAKE_BINARY_DIR} ${CMAKE_BINARY_DIR}/googlehash_test.cpp OUTPUT_VARIABLE GOOGLEHASH_COMPILE_RESULT)
+endif(GOOGLEHASH_INCLUDES)
+
+include(FindPackageHandleStandardArgs)
+find_package_handle_standard_args(GOOGLEHASH DEFAULT_MSG GOOGLEHASH_INCLUDES GOOGLEHASH_COMPILE)
+
+mark_as_advanced(GOOGLEHASH_INCLUDES)
diff --git a/cmake/FindLAPACK.cmake b/cmake/FindLAPACK.cmake
new file mode 100644
index 000000000..2fcae2199
--- /dev/null
+++ b/cmake/FindLAPACK.cmake
@@ -0,0 +1,273 @@
+# Find LAPACK library
+#
+# This module finds an installed library that implements the LAPACK
+# linear-algebra interface (see http://www.netlib.org/lapack/).
+# The approach follows mostly that taken for the autoconf macro file, acx_lapack.m4
+# (distributed at http://ac-archive.sourceforge.net/ac-archive/acx_lapack.html).
+#
+# This module sets the following variables:
+# LAPACK_FOUND - set to true if a library implementing the LAPACK interface
+# is found
+# LAPACK_INCLUDE_DIR - Directories containing the LAPACK header files
+# LAPACK_DEFINITIONS - Compilation options to use LAPACK
+# LAPACK_LINKER_FLAGS - Linker flags to use LAPACK (excluding -l
+# and -L).
+# LAPACK_LIBRARIES_DIR - Directories containing the LAPACK libraries.
+# May be null if LAPACK_LIBRARIES contains libraries name using full path.
+# LAPACK_LIBRARIES - List of libraries to link against LAPACK interface.
+# May be null if the compiler supports auto-link (e.g. VC++).
+# LAPACK_USE_FILE - The name of the cmake module to include to compile
+# applications or libraries using LAPACK.
+#
+# This module was modified by CGAL team:
+# - find libraries for a C++ compiler, instead of Fortran
+# - added LAPACK_INCLUDE_DIR, LAPACK_DEFINITIONS and LAPACK_LIBRARIES_DIR
+# - removed LAPACK95_LIBRARIES
+
+
+include(CheckFunctionExists)
+
+# This macro checks for the existence of the combination of fortran libraries
+# given by _list. If the combination is found, this macro checks (using the
+# check_function_exists macro) whether can link against that library
+# combination using the name of a routine given by _name using the linker
+# flags given by _flags. If the combination of libraries is found and passes
+# the link test, LIBRARIES is set to the list of complete library paths that
+# have been found and DEFINITIONS to the required definitions.
+# Otherwise, LIBRARIES is set to FALSE.
+# N.B. _prefix is the prefix applied to the names of all cached variables that
+# are generated internally and marked advanced by this macro.
+macro(check_lapack_libraries DEFINITIONS LIBRARIES _prefix _name _flags _list _blas _path)
+ #message("DEBUG: check_lapack_libraries(${_list} in ${_path} with ${_blas})")
+
+ # Check for the existence of the libraries given by _list
+ set(_libraries_found TRUE)
+ set(_libraries_work FALSE)
+ set(${DEFINITIONS} "")
+ set(${LIBRARIES} "")
+ set(_combined_name)
+ foreach(_library ${_list})
+ set(_combined_name ${_combined_name}_${_library})
+
+ if(_libraries_found)
+ # search first in ${_path}
+ find_library(${_prefix}_${_library}_LIBRARY
+ NAMES ${_library}
+ PATHS ${_path} NO_DEFAULT_PATH
+ )
+ # if not found, search in environment variables and system
+ if ( WIN32 )
+ find_library(${_prefix}_${_library}_LIBRARY
+ NAMES ${_library}
+ PATHS ENV LIB
+ )
+ elseif ( APPLE )
+ find_library(${_prefix}_${_library}_LIBRARY
+ NAMES ${_library}
+ PATHS /usr/local/lib /usr/lib /usr/local/lib64 /usr/lib64 ENV DYLD_LIBRARY_PATH
+ )
+ else ()
+ find_library(${_prefix}_${_library}_LIBRARY
+ NAMES ${_library}
+ PATHS /usr/local/lib /usr/lib /usr/local/lib64 /usr/lib64 ENV LD_LIBRARY_PATH
+ )
+ endif()
+ mark_as_advanced(${_prefix}_${_library}_LIBRARY)
+ set(${LIBRARIES} ${${LIBRARIES}} ${${_prefix}_${_library}_LIBRARY})
+ set(_libraries_found ${${_prefix}_${_library}_LIBRARY})
+ endif(_libraries_found)
+ endforeach(_library ${_list})
+ if(_libraries_found)
+ set(_libraries_found ${${LIBRARIES}})
+ endif()
+
+ # Test this combination of libraries with the Fortran/f2c interface.
+ # We test the Fortran interface first as it is well standardized.
+ if(_libraries_found AND NOT _libraries_work)
+ set(${DEFINITIONS} "-D${_prefix}_USE_F2C")
+ set(${LIBRARIES} ${_libraries_found})
+ # Some C++ linkers require the f2c library to link with Fortran libraries.
+ # I do not know which ones, thus I just add the f2c library if it is available.
+ find_package( F2C QUIET )
+ if ( F2C_FOUND )
+ set(${DEFINITIONS} ${${DEFINITIONS}} ${F2C_DEFINITIONS})
+ set(${LIBRARIES} ${${LIBRARIES}} ${F2C_LIBRARIES})
+ endif()
+ set(CMAKE_REQUIRED_DEFINITIONS ${${DEFINITIONS}})
+ set(CMAKE_REQUIRED_LIBRARIES ${_flags} ${${LIBRARIES}} ${_blas})
+ #message("DEBUG: CMAKE_REQUIRED_DEFINITIONS = ${CMAKE_REQUIRED_DEFINITIONS}")
+ #message("DEBUG: CMAKE_REQUIRED_LIBRARIES = ${CMAKE_REQUIRED_LIBRARIES}")
+ # Check if function exists with f2c calling convention (ie a trailing underscore)
+ check_function_exists(${_name}_ ${_prefix}_${_name}_${_combined_name}_f2c_WORKS)
+ set(CMAKE_REQUIRED_DEFINITIONS} "")
+ set(CMAKE_REQUIRED_LIBRARIES "")
+ mark_as_advanced(${_prefix}_${_name}_${_combined_name}_f2c_WORKS)
+ set(_libraries_work ${${_prefix}_${_name}_${_combined_name}_f2c_WORKS})
+ endif(_libraries_found AND NOT _libraries_work)
+
+ # If not found, test this combination of libraries with a C interface.
+ # A few implementations (ie ACML) provide a C interface. Unfortunately, there is no standard.
+ if(_libraries_found AND NOT _libraries_work)
+ set(${DEFINITIONS} "")
+ set(${LIBRARIES} ${_libraries_found})
+ set(CMAKE_REQUIRED_DEFINITIONS "")
+ set(CMAKE_REQUIRED_LIBRARIES ${_flags} ${${LIBRARIES}} ${_blas})
+ #message("DEBUG: CMAKE_REQUIRED_LIBRARIES = ${CMAKE_REQUIRED_LIBRARIES}")
+ check_function_exists(${_name} ${_prefix}_${_name}${_combined_name}_WORKS)
+ set(CMAKE_REQUIRED_LIBRARIES "")
+ mark_as_advanced(${_prefix}_${_name}${_combined_name}_WORKS)
+ set(_libraries_work ${${_prefix}_${_name}${_combined_name}_WORKS})
+ endif(_libraries_found AND NOT _libraries_work)
+
+ # on failure
+ if(NOT _libraries_work)
+ set(${DEFINITIONS} "")
+ set(${LIBRARIES} FALSE)
+ endif()
+ #message("DEBUG: ${DEFINITIONS} = ${${DEFINITIONS}}")
+ #message("DEBUG: ${LIBRARIES} = ${${LIBRARIES}}")
+endmacro(check_lapack_libraries)
+
+
+#
+# main
+#
+
+# LAPACK requires BLAS
+if(LAPACK_FIND_QUIETLY OR NOT LAPACK_FIND_REQUIRED)
+ find_package(BLAS)
+else()
+ find_package(BLAS REQUIRED)
+endif()
+
+if (NOT BLAS_FOUND)
+
+ message(STATUS "LAPACK requires BLAS.")
+ set(LAPACK_FOUND FALSE)
+
+# Is it already configured?
+elseif (LAPACK_LIBRARIES_DIR OR LAPACK_LIBRARIES)
+
+ set(LAPACK_FOUND TRUE)
+
+else()
+
+ # reset variables
+ set( LAPACK_INCLUDE_DIR "" )
+ set( LAPACK_DEFINITIONS "" )
+ set( LAPACK_LINKER_FLAGS "" ) # unused (yet)
+ set( LAPACK_LIBRARIES "" )
+ set( LAPACK_LIBRARIES_DIR "" )
+
+ #
+ # If Unix, search for LAPACK function in possible libraries
+ #
+
+ #intel mkl lapack?
+ if(NOT LAPACK_LIBRARIES)
+ check_lapack_libraries(
+ LAPACK_DEFINITIONS
+ LAPACK_LIBRARIES
+ LAPACK
+ cheev
+ ""
+ "mkl_lapack"
+ "${BLAS_LIBRARIES}"
+ "${CGAL_TAUCS_LIBRARIES_DIR} ENV LAPACK_LIB_DIR"
+ )
+ endif()
+
+ #acml lapack?
+ if(NOT LAPACK_LIBRARIES)
+ check_lapack_libraries(
+ LAPACK_DEFINITIONS
+ LAPACK_LIBRARIES
+ LAPACK
+ cheev
+ ""
+ "acml"
+ "${BLAS_LIBRARIES}"
+ "${CGAL_TAUCS_LIBRARIES_DIR} ENV LAPACK_LIB_DIR"
+ )
+ endif()
+
+ # Apple LAPACK library?
+ if(NOT LAPACK_LIBRARIES)
+ check_lapack_libraries(
+ LAPACK_DEFINITIONS
+ LAPACK_LIBRARIES
+ LAPACK
+ cheev
+ ""
+ "Accelerate"
+ "${BLAS_LIBRARIES}"
+ "${CGAL_TAUCS_LIBRARIES_DIR} ENV LAPACK_LIB_DIR"
+ )
+ endif()
+
+ if ( NOT LAPACK_LIBRARIES )
+ check_lapack_libraries(
+ LAPACK_DEFINITIONS
+ LAPACK_LIBRARIES
+ LAPACK
+ cheev
+ ""
+ "vecLib"
+ "${BLAS_LIBRARIES}"
+ "${CGAL_TAUCS_LIBRARIES_DIR} ENV LAPACK_LIB_DIR"
+ )
+ endif ( NOT LAPACK_LIBRARIES )
+
+ # Generic LAPACK library?
+ # This configuration *must* be the last try as this library is notably slow.
+ if ( NOT LAPACK_LIBRARIES )
+ check_lapack_libraries(
+ LAPACK_DEFINITIONS
+ LAPACK_LIBRARIES
+ LAPACK
+ cheev
+ ""
+ "lapack"
+ "${BLAS_LIBRARIES}"
+ "${CGAL_TAUCS_LIBRARIES_DIR} ENV LAPACK_LIB_DIR"
+ )
+ endif()
+
+ if(LAPACK_LIBRARIES_DIR OR LAPACK_LIBRARIES)
+ set(LAPACK_FOUND TRUE)
+ else()
+ set(LAPACK_FOUND FALSE)
+ endif()
+
+ if(NOT LAPACK_FIND_QUIETLY)
+ if(LAPACK_FOUND)
+ message(STATUS "A library with LAPACK API found.")
+ else(LAPACK_FOUND)
+ if(LAPACK_FIND_REQUIRED)
+ message(FATAL_ERROR "A required library with LAPACK API not found. Please specify library location.")
+ else()
+ message(STATUS "A library with LAPACK API not found. Please specify library location.")
+ endif()
+ endif(LAPACK_FOUND)
+ endif(NOT LAPACK_FIND_QUIETLY)
+
+ # Add variables to cache
+ set( LAPACK_INCLUDE_DIR "${LAPACK_INCLUDE_DIR}"
+ CACHE PATH "Directories containing the LAPACK header files" FORCE )
+ set( LAPACK_DEFINITIONS "${LAPACK_DEFINITIONS}"
+ CACHE STRING "Compilation options to use LAPACK" FORCE )
+ set( LAPACK_LINKER_FLAGS "${LAPACK_LINKER_FLAGS}"
+ CACHE STRING "Linker flags to use LAPACK" FORCE )
+ set( LAPACK_LIBRARIES "${LAPACK_LIBRARIES}"
+ CACHE FILEPATH "LAPACK libraries name" FORCE )
+ set( LAPACK_LIBRARIES_DIR "${LAPACK_LIBRARIES_DIR}"
+ CACHE PATH "Directories containing the LAPACK libraries" FORCE )
+
+ #message("DEBUG: LAPACK_INCLUDE_DIR = ${LAPACK_INCLUDE_DIR}")
+ #message("DEBUG: LAPACK_DEFINITIONS = ${LAPACK_DEFINITIONS}")
+ #message("DEBUG: LAPACK_LINKER_FLAGS = ${LAPACK_LINKER_FLAGS}")
+ #message("DEBUG: LAPACK_LIBRARIES = ${LAPACK_LIBRARIES}")
+ #message("DEBUG: LAPACK_LIBRARIES_DIR = ${LAPACK_LIBRARIES_DIR}")
+ #message("DEBUG: LAPACK_FOUND = ${LAPACK_FOUND}")
+
+endif(NOT BLAS_FOUND)
diff --git a/cmake/FindMPFR.cmake b/cmake/FindMPFR.cmake
new file mode 100644
index 000000000..aa4c2cd7d
--- /dev/null
+++ b/cmake/FindMPFR.cmake
@@ -0,0 +1,83 @@
+# Try to find the MPFR library
+# See http://www.mpfr.org/
+#
+# This module supports requiring a minimum version, e.g. you can do
+# find_package(MPFR 2.3.0)
+# to require version 2.3.0 to newer of MPFR.
+#
+# Once done this will define
+#
+# MPFR_FOUND - system has MPFR lib with correct version
+# MPFR_INCLUDES - the MPFR include directory
+# MPFR_LIBRARIES - the MPFR library
+# MPFR_VERSION - MPFR version
+
+# Copyright (c) 2006, 2007 Montel Laurent, <montel@kde.org>
+# Copyright (c) 2008, 2009 Gael Guennebaud, <g.gael@free.fr>
+# Copyright (c) 2010 Jitse Niesen, <jitse@maths.leeds.ac.uk>
+# Redistribution and use is allowed according to the terms of the BSD license.
+
+# Set MPFR_INCLUDES
+
+find_path(MPFR_INCLUDES
+ NAMES
+ mpfr.h
+ PATHS
+ $ENV{GMPDIR}
+ ${INCLUDE_INSTALL_DIR}
+)
+
+# Set MPFR_FIND_VERSION to 1.0.0 if no minimum version is specified
+
+if(NOT MPFR_FIND_VERSION)
+ if(NOT MPFR_FIND_VERSION_MAJOR)
+ set(MPFR_FIND_VERSION_MAJOR 1)
+ endif(NOT MPFR_FIND_VERSION_MAJOR)
+ if(NOT MPFR_FIND_VERSION_MINOR)
+ set(MPFR_FIND_VERSION_MINOR 0)
+ endif(NOT MPFR_FIND_VERSION_MINOR)
+ if(NOT MPFR_FIND_VERSION_PATCH)
+ set(MPFR_FIND_VERSION_PATCH 0)
+ endif(NOT MPFR_FIND_VERSION_PATCH)
+
+ set(MPFR_FIND_VERSION "${MPFR_FIND_VERSION_MAJOR}.${MPFR_FIND_VERSION_MINOR}.${MPFR_FIND_VERSION_PATCH}")
+endif(NOT MPFR_FIND_VERSION)
+
+
+if(MPFR_INCLUDES)
+
+ # Set MPFR_VERSION
+
+ file(READ "${MPFR_INCLUDES}/mpfr.h" _mpfr_version_header)
+
+ string(REGEX MATCH "define[ \t]+MPFR_VERSION_MAJOR[ \t]+([0-9]+)" _mpfr_major_version_match "${_mpfr_version_header}")
+ set(MPFR_MAJOR_VERSION "${CMAKE_MATCH_1}")
+ string(REGEX MATCH "define[ \t]+MPFR_VERSION_MINOR[ \t]+([0-9]+)" _mpfr_minor_version_match "${_mpfr_version_header}")
+ set(MPFR_MINOR_VERSION "${CMAKE_MATCH_1}")
+ string(REGEX MATCH "define[ \t]+MPFR_VERSION_PATCHLEVEL[ \t]+([0-9]+)" _mpfr_patchlevel_version_match "${_mpfr_version_header}")
+ set(MPFR_PATCHLEVEL_VERSION "${CMAKE_MATCH_1}")
+
+ set(MPFR_VERSION ${MPFR_MAJOR_VERSION}.${MPFR_MINOR_VERSION}.${MPFR_PATCHLEVEL_VERSION})
+
+ # Check whether found version exceeds minimum version
+
+ if(${MPFR_VERSION} VERSION_LESS ${MPFR_FIND_VERSION})
+ set(MPFR_VERSION_OK FALSE)
+ message(STATUS "MPFR version ${MPFR_VERSION} found in ${MPFR_INCLUDES}, "
+ "but at least version ${MPFR_FIND_VERSION} is required")
+ else(${MPFR_VERSION} VERSION_LESS ${MPFR_FIND_VERSION})
+ set(MPFR_VERSION_OK TRUE)
+ endif(${MPFR_VERSION} VERSION_LESS ${MPFR_FIND_VERSION})
+
+endif(MPFR_INCLUDES)
+
+# Set MPFR_LIBRARIES
+
+find_library(MPFR_LIBRARIES mpfr PATHS $ENV{GMPDIR} ${LIB_INSTALL_DIR})
+
+# Epilogue
+
+include(FindPackageHandleStandardArgs)
+find_package_handle_standard_args(MPFR DEFAULT_MSG
+ MPFR_INCLUDES MPFR_LIBRARIES MPFR_VERSION_OK)
+mark_as_advanced(MPFR_INCLUDES MPFR_LIBRARIES)
diff --git a/cmake/FindMetis.cmake b/cmake/FindMetis.cmake
new file mode 100644
index 000000000..e4d6ef258
--- /dev/null
+++ b/cmake/FindMetis.cmake
@@ -0,0 +1,24 @@
+# Pastix requires METIS or METIS (partitioning and reordering tools)
+
+if (METIS_INCLUDES AND METIS_LIBRARIES)
+ set(METIS_FIND_QUIETLY TRUE)
+endif (METIS_INCLUDES AND METIS_LIBRARIES)
+
+find_path(METIS_INCLUDES
+ NAMES
+ metis.h
+ PATHS
+ $ENV{METISDIR}
+ ${INCLUDE_INSTALL_DIR}
+ PATH_SUFFIXES
+ metis
+)
+
+
+find_library(METIS_LIBRARIES metis PATHS $ENV{METISDIR} ${LIB_INSTALL_DIR})
+
+include(FindPackageHandleStandardArgs)
+find_package_handle_standard_args(METIS DEFAULT_MSG
+ METIS_INCLUDES METIS_LIBRARIES)
+
+mark_as_advanced(METIS_INCLUDES METIS_LIBRARIES)
diff --git a/cmake/FindPastix.cmake b/cmake/FindPastix.cmake
new file mode 100644
index 000000000..e2e6c810d
--- /dev/null
+++ b/cmake/FindPastix.cmake
@@ -0,0 +1,25 @@
+# Pastix lib requires linking to a blas library.
+# It is up to the user of this module to find a BLAS and link to it.
+# Pastix requires SCOTCH or METIS (partitioning and reordering tools) as well
+
+if (PASTIX_INCLUDES AND PASTIX_LIBRARIES)
+ set(PASTIX_FIND_QUIETLY TRUE)
+endif (PASTIX_INCLUDES AND PASTIX_LIBRARIES)
+
+find_path(PASTIX_INCLUDES
+ NAMES
+ pastix_nompi.h
+ PATHS
+ $ENV{PASTIXDIR}
+ ${INCLUDE_INSTALL_DIR}
+)
+
+find_library(PASTIX_LIBRARIES pastix PATHS $ENV{PASTIXDIR} ${LIB_INSTALL_DIR})
+
+
+
+include(FindPackageHandleStandardArgs)
+find_package_handle_standard_args(PASTIX DEFAULT_MSG
+ PASTIX_INCLUDES PASTIX_LIBRARIES)
+
+mark_as_advanced(PASTIX_INCLUDES PASTIX_LIBRARIES)
diff --git a/cmake/FindScotch.cmake b/cmake/FindScotch.cmake
new file mode 100644
index 000000000..530340b16
--- /dev/null
+++ b/cmake/FindScotch.cmake
@@ -0,0 +1,24 @@
+# Pastix requires SCOTCH or METIS (partitioning and reordering tools)
+
+if (SCOTCH_INCLUDES AND SCOTCH_LIBRARIES)
+ set(SCOTCH_FIND_QUIETLY TRUE)
+endif (SCOTCH_INCLUDES AND SCOTCH_LIBRARIES)
+
+find_path(SCOTCH_INCLUDES
+ NAMES
+ scotch.h
+ PATHS
+ $ENV{SCOTCHDIR}
+ ${INCLUDE_INSTALL_DIR}
+ PATH_SUFFIXES
+ scotch
+)
+
+
+find_library(SCOTCH_LIBRARIES scotch PATHS $ENV{SCOTCHDIR} ${LIB_INSTALL_DIR})
+
+include(FindPackageHandleStandardArgs)
+find_package_handle_standard_args(SCOTCH DEFAULT_MSG
+ SCOTCH_INCLUDES SCOTCH_LIBRARIES)
+
+mark_as_advanced(SCOTCH_INCLUDES SCOTCH_LIBRARIES)
diff --git a/cmake/FindStandardMathLibrary.cmake b/cmake/FindStandardMathLibrary.cmake
new file mode 100644
index 000000000..711b0e4b4
--- /dev/null
+++ b/cmake/FindStandardMathLibrary.cmake
@@ -0,0 +1,64 @@
+# - Try to find how to link to the standard math library, if anything at all is needed to do.
+# On most platforms this is automatic, but for example it's not automatic on QNX.
+#
+# Once done this will define
+#
+# STANDARD_MATH_LIBRARY_FOUND - we found how to successfully link to the standard math library
+# STANDARD_MATH_LIBRARY - the name of the standard library that one has to link to.
+# -- this will be left empty if it's automatic (most platforms).
+# -- this will be set to "m" on platforms where one must explicitly
+# pass the "-lm" linker flag.
+#
+# Copyright (c) 2010 Benoit Jacob <jacob.benoit.1@gmail.com>
+# Redistribution and use is allowed according to the terms of the 2-clause BSD license.
+
+
+include(CheckCXXSourceCompiles)
+
+# a little test program for c++ math functions.
+# notice the std:: is required on some platforms such as QNX
+
+set(find_standard_math_library_test_program
+"#include<cmath>
+int main() { std::sin(0.0); std::log(0.0f); }")
+
+# first try compiling/linking the test program without any linker flags
+
+set(CMAKE_REQUIRED_FLAGS "")
+set(CMAKE_REQUIRED_LIBRARIES "")
+CHECK_CXX_SOURCE_COMPILES(
+ "${find_standard_math_library_test_program}"
+ standard_math_library_linked_to_automatically
+)
+
+if(standard_math_library_linked_to_automatically)
+
+ # the test program linked successfully without any linker flag.
+ set(STANDARD_MATH_LIBRARY "")
+ set(STANDARD_MATH_LIBRARY_FOUND TRUE)
+
+else()
+
+ # the test program did not link successfully without any linker flag.
+ # This is a very uncommon case that so far we only saw on QNX. The next try is the
+ # standard name 'm' for the standard math library.
+
+ set(CMAKE_REQUIRED_LIBRARIES "m")
+ CHECK_CXX_SOURCE_COMPILES(
+ "${find_standard_math_library_test_program}"
+ standard_math_library_linked_to_as_m)
+
+ if(standard_math_library_linked_to_as_m)
+
+ # the test program linked successfully when linking to the 'm' library
+ set(STANDARD_MATH_LIBRARY "m")
+ set(STANDARD_MATH_LIBRARY_FOUND TRUE)
+
+ else()
+
+ # the test program still doesn't link successfully
+ set(STANDARD_MATH_LIBRARY_FOUND FALSE)
+
+ endif()
+
+endif()
diff --git a/cmake/FindSuperLU.cmake b/cmake/FindSuperLU.cmake
new file mode 100644
index 000000000..ca72b4498
--- /dev/null
+++ b/cmake/FindSuperLU.cmake
@@ -0,0 +1,25 @@
+
+# Umfpack lib usually requires linking to a blas library.
+# It is up to the user of this module to find a BLAS and link to it.
+
+if (SUPERLU_INCLUDES AND SUPERLU_LIBRARIES)
+ set(SUPERLU_FIND_QUIETLY TRUE)
+endif (SUPERLU_INCLUDES AND SUPERLU_LIBRARIES)
+
+find_path(SUPERLU_INCLUDES
+ NAMES
+ supermatrix.h
+ PATHS
+ $ENV{SUPERLUDIR}
+ ${INCLUDE_INSTALL_DIR}
+ PATH_SUFFIXES
+ superlu
+)
+
+find_library(SUPERLU_LIBRARIES superlu PATHS $ENV{SUPERLUDIR} ${LIB_INSTALL_DIR})
+
+include(FindPackageHandleStandardArgs)
+find_package_handle_standard_args(SUPERLU DEFAULT_MSG
+ SUPERLU_INCLUDES SUPERLU_LIBRARIES)
+
+mark_as_advanced(SUPERLU_INCLUDES SUPERLU_LIBRARIES)
diff --git a/cmake/FindUmfpack.cmake b/cmake/FindUmfpack.cmake
new file mode 100644
index 000000000..d42c3c4a2
--- /dev/null
+++ b/cmake/FindUmfpack.cmake
@@ -0,0 +1,50 @@
+# Umfpack lib usually requires linking to a blas library.
+# It is up to the user of this module to find a BLAS and link to it.
+
+if (UMFPACK_INCLUDES AND UMFPACK_LIBRARIES)
+ set(UMFPACK_FIND_QUIETLY TRUE)
+endif (UMFPACK_INCLUDES AND UMFPACK_LIBRARIES)
+
+find_path(UMFPACK_INCLUDES
+ NAMES
+ umfpack.h
+ PATHS
+ $ENV{UMFPACKDIR}
+ ${INCLUDE_INSTALL_DIR}
+ PATH_SUFFIXES
+ suitesparse
+ ufsparse
+)
+
+find_library(UMFPACK_LIBRARIES umfpack PATHS $ENV{UMFPACKDIR} ${LIB_INSTALL_DIR})
+
+if(UMFPACK_LIBRARIES)
+
+ get_filename_component(UMFPACK_LIBDIR ${UMFPACK_LIBRARIES} PATH)
+
+ find_library(AMD_LIBRARY amd PATHS ${UMFPACK_LIBDIR} $ENV{UMFPACKDIR} ${LIB_INSTALL_DIR})
+ if (AMD_LIBRARY)
+ set(UMFPACK_LIBRARIES ${UMFPACK_LIBRARIES} ${AMD_LIBRARY})
+ #else (AMD_LIBRARY)
+ # set(UMFPACK_LIBRARIES FALSE)
+ endif (AMD_LIBRARY)
+
+endif(UMFPACK_LIBRARIES)
+
+if(UMFPACK_LIBRARIES)
+
+ find_library(COLAMD_LIBRARY colamd PATHS ${UMFPACK_LIBDIR} $ENV{UMFPACKDIR} ${LIB_INSTALL_DIR})
+ if (COLAMD_LIBRARY)
+ set(UMFPACK_LIBRARIES ${UMFPACK_LIBRARIES} ${COLAMD_LIBRARY})
+ #else (COLAMD_LIBRARY)
+ # set(UMFPACK_LIBRARIES FALSE)
+ endif (COLAMD_LIBRARY)
+
+endif(UMFPACK_LIBRARIES)
+
+
+include(FindPackageHandleStandardArgs)
+find_package_handle_standard_args(UMFPACK DEFAULT_MSG
+ UMFPACK_INCLUDES UMFPACK_LIBRARIES)
+
+mark_as_advanced(UMFPACK_INCLUDES UMFPACK_LIBRARIES AMD_LIBRARY COLAMD_LIBRARY)
diff --git a/cmake/RegexUtils.cmake b/cmake/RegexUtils.cmake
new file mode 100644
index 000000000..b59dfc340
--- /dev/null
+++ b/cmake/RegexUtils.cmake
@@ -0,0 +1,19 @@
+function(escape_string_as_regex _str_out _str_in)
+ STRING(REGEX REPLACE "\\\\" "\\\\\\\\" FILETEST2 "${_str_in}")
+ STRING(REGEX REPLACE "([.$+*?|-])" "\\\\\\1" FILETEST2 "${FILETEST2}")
+ STRING(REGEX REPLACE "\\^" "\\\\^" FILETEST2 "${FILETEST2}")
+ STRING(REGEX REPLACE "\\(" "\\\\(" FILETEST2 "${FILETEST2}")
+ STRING(REGEX REPLACE "\\)" "\\\\)" FILETEST2 "${FILETEST2}")
+ STRING(REGEX REPLACE "\\[" "\\\\[" FILETEST2 "${FILETEST2}")
+ STRING(REGEX REPLACE "\\]" "\\\\]" FILETEST2 "${FILETEST2}")
+ SET(${_str_out} "${FILETEST2}" PARENT_SCOPE)
+endfunction()
+
+function(test_escape_string_as_regex)
+ SET(test1 "\\.^$-+*()[]?|")
+ escape_string_as_regex(test2 "${test1}")
+ SET(testRef "\\\\\\.\\^\\$\\-\\+\\*\\(\\)\\[\\]\\?\\|")
+ if(NOT test2 STREQUAL testRef)
+ message("Error in the escape_string_for_regex function : \n ${test1} was escaped as ${test2}, should be ${testRef}")
+ endif(NOT test2 STREQUAL testRef)
+endfunction() \ No newline at end of file
diff --git a/cmake/language_support.cmake b/cmake/language_support.cmake
new file mode 100644
index 000000000..3414e6ea6
--- /dev/null
+++ b/cmake/language_support.cmake
@@ -0,0 +1,64 @@
+# cmake/modules/language_support.cmake
+#
+# Temporary additional general language support is contained within this
+# file.
+
+# This additional function definition is needed to provide a workaround for
+# CMake bug 9220.
+
+# On debian testing (cmake 2.6.2), I get return code zero when calling
+# cmake the first time, but cmake crashes when running a second time
+# as follows:
+#
+# -- The Fortran compiler identification is unknown
+# CMake Error at /usr/share/cmake-2.6/Modules/CMakeFortranInformation.cmake:7 (GET_FILENAME_COMPONENT):
+# get_filename_component called with incorrect number of arguments
+# Call Stack (most recent call first):
+# CMakeLists.txt:3 (enable_language)
+#
+# My workaround is to invoke cmake twice. If both return codes are zero,
+# it is safe to invoke ENABLE_LANGUAGE(Fortran OPTIONAL)
+
+function(workaround_9220 language language_works)
+ #message("DEBUG: language = ${language}")
+ set(text
+ "project(test NONE)
+ cmake_minimum_required(VERSION 2.6.0)
+ enable_language(${language} OPTIONAL)
+ ")
+ file(REMOVE_RECURSE ${CMAKE_BINARY_DIR}/language_tests/${language})
+ file(MAKE_DIRECTORY ${CMAKE_BINARY_DIR}/language_tests/${language})
+ file(WRITE ${CMAKE_BINARY_DIR}/language_tests/${language}/CMakeLists.txt
+ ${text})
+ execute_process(
+ COMMAND ${CMAKE_COMMAND} .
+ WORKING_DIRECTORY ${CMAKE_BINARY_DIR}/language_tests/${language}
+ RESULT_VARIABLE return_code
+ OUTPUT_QUIET
+ ERROR_QUIET
+ )
+
+ if(return_code EQUAL 0)
+ # Second run
+ execute_process (
+ COMMAND ${CMAKE_COMMAND} .
+ WORKING_DIRECTORY ${CMAKE_BINARY_DIR}/language_tests/${language}
+ RESULT_VARIABLE return_code
+ OUTPUT_QUIET
+ ERROR_QUIET
+ )
+ if(return_code EQUAL 0)
+ set(${language_works} ON PARENT_SCOPE)
+ else(return_code EQUAL 0)
+ set(${language_works} OFF PARENT_SCOPE)
+ endif(return_code EQUAL 0)
+ else(return_code EQUAL 0)
+ set(${language_works} OFF PARENT_SCOPE)
+ endif(return_code EQUAL 0)
+endfunction(workaround_9220)
+
+# Temporary tests of the above function.
+#workaround_9220(CXX CXX_language_works)
+#message("CXX_language_works = ${CXX_language_works}")
+#workaround_9220(CXXp CXXp_language_works)
+#message("CXXp_language_works = ${CXXp_language_works}")
diff --git a/debug/gdb/__init__.py b/debug/gdb/__init__.py
new file mode 100644
index 000000000..bb7b160de
--- /dev/null
+++ b/debug/gdb/__init__.py
@@ -0,0 +1 @@
+# Intentionally empty
diff --git a/debug/gdb/printers.py b/debug/gdb/printers.py
new file mode 100644
index 000000000..9187acb33
--- /dev/null
+++ b/debug/gdb/printers.py
@@ -0,0 +1,208 @@
+# -*- coding: utf-8 -*-
+# This file is part of Eigen, a lightweight C++ template library
+# for linear algebra.
+#
+# Copyright (C) 2009 Benjamin Schindler <bschindler@inf.ethz.ch>
+#
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+# Pretty printers for Eigen::Matrix
+# This is still pretty basic as the python extension to gdb is still pretty basic.
+# It cannot handle complex eigen types and it doesn't support any of the other eigen types
+# Such as quaternion or some other type.
+# This code supports fixed size as well as dynamic size matrices
+
+# To use it:
+#
+# * Create a directory and put the file as well as an empty __init__.py in
+# that directory.
+# * Create a ~/.gdbinit file, that contains the following:
+# python
+# import sys
+# sys.path.insert(0, '/path/to/eigen/printer/directory')
+# from printers import register_eigen_printers
+# register_eigen_printers (None)
+# end
+
+import gdb
+import re
+import itertools
+
+
+class EigenMatrixPrinter:
+ "Print Eigen Matrix or Array of some kind"
+
+ def __init__(self, variety, val):
+ "Extract all the necessary information"
+
+ # Save the variety (presumably "Matrix" or "Array") for later usage
+ self.variety = variety
+
+ # The gdb extension does not support value template arguments - need to extract them by hand
+ type = val.type
+ if type.code == gdb.TYPE_CODE_REF:
+ type = type.target()
+ self.type = type.unqualified().strip_typedefs()
+ tag = self.type.tag
+ regex = re.compile('\<.*\>')
+ m = regex.findall(tag)[0][1:-1]
+ template_params = m.split(',')
+ template_params = map(lambda x:x.replace(" ", ""), template_params)
+
+ if template_params[1] == '-0x00000000000000001' or template_params[1] == '-0x000000001':
+ self.rows = val['m_storage']['m_rows']
+ else:
+ self.rows = int(template_params[1])
+
+ if template_params[2] == '-0x00000000000000001' or template_params[2] == '-0x000000001':
+ self.cols = val['m_storage']['m_cols']
+ else:
+ self.cols = int(template_params[2])
+
+ self.options = 0 # default value
+ if len(template_params) > 3:
+ self.options = template_params[3];
+
+ self.rowMajor = (int(self.options) & 0x1)
+
+ self.innerType = self.type.template_argument(0)
+
+ self.val = val
+
+ # Fixed size matrices have a struct as their storage, so we need to walk through this
+ self.data = self.val['m_storage']['m_data']
+ if self.data.type.code == gdb.TYPE_CODE_STRUCT:
+ self.data = self.data['array']
+ self.data = self.data.cast(self.innerType.pointer())
+
+ class _iterator:
+ def __init__ (self, rows, cols, dataPtr, rowMajor):
+ self.rows = rows
+ self.cols = cols
+ self.dataPtr = dataPtr
+ self.currentRow = 0
+ self.currentCol = 0
+ self.rowMajor = rowMajor
+
+ def __iter__ (self):
+ return self
+
+ def next(self):
+
+ row = self.currentRow
+ col = self.currentCol
+ if self.rowMajor == 0:
+ if self.currentCol >= self.cols:
+ raise StopIteration
+
+ self.currentRow = self.currentRow + 1
+ if self.currentRow >= self.rows:
+ self.currentRow = 0
+ self.currentCol = self.currentCol + 1
+ else:
+ if self.currentRow >= self.rows:
+ raise StopIteration
+
+ self.currentCol = self.currentCol + 1
+ if self.currentCol >= self.cols:
+ self.currentCol = 0
+ self.currentRow = self.currentRow + 1
+
+
+ item = self.dataPtr.dereference()
+ self.dataPtr = self.dataPtr + 1
+ if (self.cols == 1): #if it's a column vector
+ return ('[%d]' % (row,), item)
+ elif (self.rows == 1): #if it's a row vector
+ return ('[%d]' % (col,), item)
+ return ('[%d,%d]' % (row, col), item)
+
+ def children(self):
+
+ return self._iterator(self.rows, self.cols, self.data, self.rowMajor)
+
+ def to_string(self):
+ return "Eigen::%s<%s,%d,%d,%s> (data ptr: %s)" % (self.variety, self.innerType, self.rows, self.cols, "RowMajor" if self.rowMajor else "ColMajor", self.data)
+
+class EigenQuaternionPrinter:
+ "Print an Eigen Quaternion"
+
+ def __init__(self, val):
+ "Extract all the necessary information"
+ # The gdb extension does not support value template arguments - need to extract them by hand
+ type = val.type
+ if type.code == gdb.TYPE_CODE_REF:
+ type = type.target()
+ self.type = type.unqualified().strip_typedefs()
+ self.innerType = self.type.template_argument(0)
+ self.val = val
+
+ # Quaternions have a struct as their storage, so we need to walk through this
+ self.data = self.val['m_coeffs']['m_storage']['m_data']['array']
+ self.data = self.data.cast(self.innerType.pointer())
+
+ class _iterator:
+ def __init__ (self, dataPtr):
+ self.dataPtr = dataPtr
+ self.currentElement = 0
+ self.elementNames = ['x', 'y', 'z', 'w']
+
+ def __iter__ (self):
+ return self
+
+ def next(self):
+ element = self.currentElement
+
+ if self.currentElement >= 4: #there are 4 elements in a quanternion
+ raise StopIteration
+
+ self.currentElement = self.currentElement + 1
+
+ item = self.dataPtr.dereference()
+ self.dataPtr = self.dataPtr + 1
+ return ('[%s]' % (self.elementNames[element],), item)
+
+ def children(self):
+
+ return self._iterator(self.data)
+
+ def to_string(self):
+ return "Eigen::Quaternion<%s> (data ptr: %s)" % (self.innerType, self.data)
+
+def build_eigen_dictionary ():
+ pretty_printers_dict[re.compile('^Eigen::Quaternion<.*>$')] = lambda val: EigenQuaternionPrinter(val)
+ pretty_printers_dict[re.compile('^Eigen::Matrix<.*>$')] = lambda val: EigenMatrixPrinter("Matrix", val)
+ pretty_printers_dict[re.compile('^Eigen::Array<.*>$')] = lambda val: EigenMatrixPrinter("Array", val)
+
+def register_eigen_printers(obj):
+ "Register eigen pretty-printers with objfile Obj"
+
+ if obj == None:
+ obj = gdb
+ obj.pretty_printers.append(lookup_function)
+
+def lookup_function(val):
+ "Look-up and return a pretty-printer that can print va."
+
+ type = val.type
+
+ if type.code == gdb.TYPE_CODE_REF:
+ type = type.target()
+
+ type = type.unqualified().strip_typedefs()
+
+ typename = type.tag
+ if typename == None:
+ return None
+
+ for function in pretty_printers_dict:
+ if function.search(typename):
+ return pretty_printers_dict[function](val)
+
+ return None
+
+pretty_printers_dict = {}
+
+build_eigen_dictionary ()
diff --git a/debug/msvc/eigen_autoexp_part.dat b/debug/msvc/eigen_autoexp_part.dat
new file mode 100644
index 000000000..07aa43739
--- /dev/null
+++ b/debug/msvc/eigen_autoexp_part.dat
@@ -0,0 +1,295 @@
+; ***************************************************************
+; * Eigen Visualizer
+; *
+; * Author: Hauke Heibel <hauke.heibel@gmail.com>
+; *
+; * Support the enhanced debugging of the following Eigen
+; * types (*: any, +:fixed dimension) :
+; *
+; * - Eigen::Matrix<*,4,1,*,*,*> and Eigen::Matrix<*,1,4,*,*,*>
+; * - Eigen::Matrix<*,3,1,*,*,*> and Eigen::Matrix<*,1,3,*,*,*>
+; * - Eigen::Matrix<*,2,1,*,*,*> and Eigen::Matrix<*,1,2,*,*,*>
+; * - Eigen::Matrix<*,-1,-1,*,*,*>
+; * - Eigen::Matrix<*,+,-1,*,*,*>
+; * - Eigen::Matrix<*,-1,+,*,*,*>
+; * - Eigen::Matrix<*,+,+,*,*,*>
+; *
+; * Matrices are displayed properly independantly of the memory
+; * alignment (RowMajor vs. ColMajor).
+; *
+; * This file is distributed WITHOUT ANY WARRANTY. Please ensure
+; * that your original autoexp.dat file is copied to a safe
+; * place before proceeding with its modification.
+; ***************************************************************
+
+[Visualizer]
+
+; Fixed size 4-vectors
+Eigen::Matrix<*,4,1,*,*,*>|Eigen::Matrix<*,1,4,*,*,*>{
+ children
+ (
+ #(
+ [internals]: [$c,!],
+ x : ($c.m_storage.m_data.array)[0],
+ y : ($c.m_storage.m_data.array)[1],
+ z : ($c.m_storage.m_data.array)[2],
+ w : ($c.m_storage.m_data.array)[3]
+ )
+ )
+
+ preview
+ (
+ #(
+ "[",
+ 4,
+ "](",
+ #array(expr: $e.m_storage.m_data.array[$i], size: 4),
+ ")"
+ )
+ )
+}
+
+; Fixed size 3-vectors
+Eigen::Matrix<*,3,1,*,*,*>|Eigen::Matrix<*,1,3,*,*,*>{
+ children
+ (
+ #(
+ [internals]: [$c,!],
+ x : ($c.m_storage.m_data.array)[0],
+ y : ($c.m_storage.m_data.array)[1],
+ z : ($c.m_storage.m_data.array)[2]
+ )
+ )
+
+ preview
+ (
+ #(
+ "[",
+ 3,
+ "](",
+ #array(expr: $e.m_storage.m_data.array[$i], size: 3),
+ ")"
+ )
+ )
+}
+
+; Fixed size 2-vectors
+Eigen::Matrix<*,2,1,*,*,*>|Eigen::Matrix<*,1,2,*,*,*>{
+ children
+ (
+ #(
+ [internals]: [$c,!],
+ x : ($c.m_storage.m_data.array)[0],
+ y : ($c.m_storage.m_data.array)[1]
+ )
+ )
+
+ preview
+ (
+ #(
+ "[",
+ 2,
+ "](",
+ #array(expr: $e.m_storage.m_data.array[$i], size: 2),
+ ")"
+ )
+ )
+}
+
+; Fixed size 1-vectors
+Eigen::Matrix<*,1,1,*,*,*>|Eigen::Matrix<*,1,1,*,*,*>{
+ children
+ (
+ #(
+ [internals]: [$c,!],
+ x : ($c.m_storage.m_data.array)[0]
+ )
+ )
+
+ preview
+ (
+ #(
+ "[",
+ 1,
+ "](",
+ #array(expr: $e.m_storage.m_data.array[$i], size: 1),
+ ")"
+ )
+ )
+}
+
+; Dynamic matrices (ColMajor and RowMajor support)
+Eigen::Matrix<*,-1,-1,*,*,*>{
+ children
+ (
+ #(
+ [internals]: [$c,!],
+ rows: $c.m_storage.m_rows,
+ cols: $c.m_storage.m_cols,
+ ; Check for RowMajorBit
+ #if ($c.Flags & 0x1) (
+ #array(
+ rank: 2,
+ base: 0,
+ expr: ($c.m_storage.m_data)[($i % $c.m_storage.m_rows)*$c.m_storage.m_cols + (($i- $i % $c.m_storage.m_rows)/$c.m_storage.m_rows)],
+ size: ($r==1)*$c.m_storage.m_rows+($r==0)*$c.m_storage.m_cols
+ )
+ ) #else (
+ #array(
+ rank: 2,
+ base: 0,
+ expr: ($c.m_storage.m_data)[$i],
+ size: ($r==1)*$c.m_storage.m_rows+($r==0)*$c.m_storage.m_cols
+ )
+ )
+ )
+ )
+
+ preview
+ (
+ #(
+ "[",
+ $c.m_storage.m_rows,
+ ",",
+ $c.m_storage.m_cols,
+ "](",
+ #array(
+ expr : [($c.m_storage.m_data)[$i],g],
+ size : $c.m_storage.m_rows*$c.m_storage.m_cols
+ ),
+ ")"
+ )
+ )
+}
+
+; Fixed rows, dynamic columns matrix (ColMajor and RowMajor support)
+Eigen::Matrix<*,*,-1,*,*,*>{
+ children
+ (
+ #(
+ [internals]: [$c,!],
+ rows: $c.RowsAtCompileTime,
+ cols: $c.m_storage.m_cols,
+ ; Check for RowMajorBit
+ #if ($c.Flags & 0x1) (
+ #array(
+ rank: 2,
+ base: 0,
+ expr: ($c.m_storage.m_data)[($i % $c.RowsAtCompileTime)*$c.m_storage.m_cols + (($i- $i % $c.RowsAtCompileTime)/$c.RowsAtCompileTime)],
+ size: ($r==1)*$c.RowsAtCompileTime+($r==0)*$c.m_storage.m_cols
+ )
+ ) #else (
+ #array(
+ rank: 2,
+ base: 0,
+ expr: ($c.m_storage.m_data)[$i],
+ size: ($r==1)*$c.RowsAtCompileTime+($r==0)*$c.m_storage.m_cols
+ )
+ )
+ )
+ )
+
+ preview
+ (
+ #(
+ "[",
+ $c.RowsAtCompileTime,
+ ",",
+ $c.m_storage.m_cols,
+ "](",
+ #array(
+ expr : [($c.m_storage.m_data)[$i],g],
+ size : $c.RowsAtCompileTime*$c.m_storage.m_cols
+ ),
+ ")"
+ )
+ )
+}
+
+; Dynamic rows, fixed columns matrix (ColMajor and RowMajor support)
+Eigen::Matrix<*,-1,*,*,*,*>{
+ children
+ (
+ #(
+ [internals]: [$c,!],
+ rows: $c.m_storage.m_rows,
+ cols: $c.ColsAtCompileTime,
+ ; Check for RowMajorBit
+ #if ($c.Flags & 0x1) (
+ #array(
+ rank: 2,
+ base: 0,
+ expr: ($c.m_storage.m_data)[($i % $c.m_storage.m_rows)*$c.ColsAtCompileTime + (($i- $i % $c.m_storage.m_rows)/$c.m_storage.m_rows)],
+ size: ($r==1)*$c.m_storage.m_rows+($r==0)*$c.ColsAtCompileTime
+ )
+ ) #else (
+ #array(
+ rank: 2,
+ base: 0,
+ expr: ($c.m_storage.m_data)[$i],
+ size: ($r==1)*$c.m_storage.m_rows+($r==0)*$c.ColsAtCompileTime
+ )
+ )
+ )
+ )
+
+ preview
+ (
+ #(
+ "[",
+ $c.m_storage.m_rows,
+ ",",
+ $c.ColsAtCompileTime,
+ "](",
+ #array(
+ expr : [($c.m_storage.m_data)[$i],g],
+ size : $c.m_storage.m_rows*$c.ColsAtCompileTime
+ ),
+ ")"
+ )
+ )
+}
+
+; Fixed size matrix (ColMajor and RowMajor support)
+Eigen::Matrix<*,*,*,*,*,*>{
+ children
+ (
+ #(
+ [internals]: [$c,!],
+ rows: $c.RowsAtCompileTime,
+ cols: $c.ColsAtCompileTime,
+ ; Check for RowMajorBit
+ #if ($c.Flags & 0x1) (
+ #array(
+ rank: 2,
+ base: 0,
+ expr: ($c.m_storage.m_data.array)[($i % $c.RowsAtCompileTime)*$c.ColsAtCompileTime + (($i- $i % $c.RowsAtCompileTime)/$c.RowsAtCompileTime)],
+ size: ($r==1)*$c.RowsAtCompileTime+($r==0)*$c.ColsAtCompileTime
+ )
+ ) #else (
+ #array(
+ rank: 2,
+ base: 0,
+ expr: ($c.m_storage.m_data.array)[$i],
+ size: ($r==1)*$c.RowsAtCompileTime+($r==0)*$c.ColsAtCompileTime
+ )
+ )
+ )
+ )
+
+ preview
+ (
+ #(
+ "[",
+ $c.RowsAtCompileTime,
+ ",",
+ $c.ColsAtCompileTime,
+ "](",
+ #array(
+ expr : [($c.m_storage.m_data.array)[$i],g],
+ size : $c.RowsAtCompileTime*$c.ColsAtCompileTime
+ ),
+ ")"
+ )
+ )
+}
diff --git a/demos/CMakeLists.txt b/demos/CMakeLists.txt
new file mode 100644
index 000000000..b0d2eddbb
--- /dev/null
+++ b/demos/CMakeLists.txt
@@ -0,0 +1,13 @@
+project(EigenDemos)
+
+add_custom_target(demos)
+
+if(NOT EIGEN_TEST_NOQT)
+ find_package(Qt4)
+ if(QT4_FOUND)
+ add_subdirectory(mandelbrot)
+ add_subdirectory(opengl)
+ else(QT4_FOUND)
+ message(STATUS "Qt4 not found, so disabling the mandelbrot and opengl demos")
+ endif(QT4_FOUND)
+endif()
diff --git a/demos/mandelbrot/CMakeLists.txt b/demos/mandelbrot/CMakeLists.txt
new file mode 100644
index 000000000..5c500e064
--- /dev/null
+++ b/demos/mandelbrot/CMakeLists.txt
@@ -0,0 +1,21 @@
+find_package(Qt4 REQUIRED)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+if (CMAKE_COMPILER_IS_GNUCXX)
+ set ( CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -O2")
+ add_definitions ( "-DNDEBUG" )
+endif (CMAKE_COMPILER_IS_GNUCXX)
+
+include_directories( ${QT_INCLUDE_DIR} )
+
+set(mandelbrot_SRCS
+ mandelbrot.cpp
+)
+
+qt4_automoc(${mandelbrot_SRCS})
+
+add_executable(mandelbrot ${mandelbrot_SRCS})
+add_dependencies(demos mandelbrot)
+
+target_link_libraries(mandelbrot ${QT_QTCORE_LIBRARY} ${QT_QTGUI_LIBRARY})
diff --git a/demos/mandelbrot/README b/demos/mandelbrot/README
new file mode 100644
index 000000000..a451d6551
--- /dev/null
+++ b/demos/mandelbrot/README
@@ -0,0 +1,10 @@
+*** Mandelbrot demo ***
+
+Controls:
+* Left mouse button to center view at a point.
+* Drag vertically with left mouse button to zoom in and out.
+
+Be sure to enable SSE2 or AltiVec to improve performance.
+
+The number of iterations, and the choice between single and double precision, are
+determined at runtime depending on the zoom level.
diff --git a/demos/mandelbrot/mandelbrot.cpp b/demos/mandelbrot/mandelbrot.cpp
new file mode 100644
index 000000000..5d575d5b6
--- /dev/null
+++ b/demos/mandelbrot/mandelbrot.cpp
@@ -0,0 +1,213 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra.
+//
+// Copyright (C) 2008 Benoit Jacob <jacob.benoit.1@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 "mandelbrot.h"
+#include <iostream>
+#include<QtGui/QPainter>
+#include<QtGui/QImage>
+#include<QtGui/QMouseEvent>
+#include<QtCore/QTime>
+
+void MandelbrotWidget::resizeEvent(QResizeEvent *)
+{
+ if(size < width() * height())
+ {
+ std::cout << "reallocate buffer" << std::endl;
+ size = width() * height();
+ if(buffer) delete[]buffer;
+ buffer = new unsigned char[4*size];
+ }
+}
+
+template<typename T> struct iters_before_test { enum { ret = 8 }; };
+template<> struct iters_before_test<double> { enum { ret = 16 }; };
+
+template<typename Real> void MandelbrotThread::render(int img_width, int img_height)
+{
+ enum { packetSize = Eigen::internal::packet_traits<Real>::size }; // number of reals in a Packet
+ typedef Eigen::Array<Real, packetSize, 1> Packet; // wrap a Packet as a vector
+
+ enum { iters_before_test = iters_before_test<Real>::ret };
+ max_iter = (max_iter / iters_before_test) * iters_before_test;
+ const int alignedWidth = (img_width/packetSize)*packetSize;
+ unsigned char *const buffer = widget->buffer;
+ const double xradius = widget->xradius;
+ const double yradius = xradius * img_height / img_width;
+ const int threadcount = widget->threadcount;
+ typedef Eigen::Array<Real, 2, 1> Vector2;
+ Vector2 start(widget->center.x() - widget->xradius, widget->center.y() - yradius);
+ Vector2 step(2*widget->xradius/img_width, 2*yradius/img_height);
+ total_iter = 0;
+
+ for(int y = id; y < img_height; y += threadcount)
+ {
+ int pix = y * img_width;
+
+ // for each pixel, we're going to do the iteration z := z^2 + c where z and c are complex numbers,
+ // starting with z = c = complex coord of the pixel. pzi and pzr denote the real and imaginary parts of z.
+ // pci and pcr denote the real and imaginary parts of c.
+
+ Packet pzi_start, pci_start;
+ for(int i = 0; i < packetSize; i++) pzi_start[i] = pci_start[i] = start.y() + y * step.y();
+
+ for(int x = 0; x < alignedWidth; x += packetSize, pix += packetSize)
+ {
+ Packet pcr, pci = pci_start, pzr, pzi = pzi_start, pzr_buf;
+ for(int i = 0; i < packetSize; i++) pzr[i] = pcr[i] = start.x() + (x+i) * step.x();
+
+ // do the iterations. Every iters_before_test iterations we check for divergence,
+ // in which case we can stop iterating.
+ int j = 0;
+ typedef Eigen::Matrix<int, packetSize, 1> Packeti;
+ Packeti pix_iter = Packeti::Zero(), // number of iteration per pixel in the packet
+ pix_dont_diverge; // whether or not each pixel has already diverged
+ do
+ {
+ for(int i = 0; i < iters_before_test/4; i++) // peel the inner loop by 4
+ {
+# define ITERATE \
+ pzr_buf = pzr; \
+ pzr = pzr.square(); \
+ pzr -= pzi.square(); \
+ pzr += pcr; \
+ pzi = (2*pzr_buf)*pzi; \
+ pzi += pci;
+ ITERATE ITERATE ITERATE ITERATE
+ }
+ pix_dont_diverge = ((pzr.square() + pzi.square())
+ .eval() // temporary fix as what follows is not yet vectorized by Eigen
+ <= Packet::Constant(4))
+ // the 4 here is not a magic value, it's a math fact that if
+ // the square modulus is >4 then divergence is inevitable.
+ .template cast<int>();
+ pix_iter += iters_before_test * pix_dont_diverge;
+ j++;
+ total_iter += iters_before_test * packetSize;
+ }
+ while(j < max_iter/iters_before_test && pix_dont_diverge.any()); // any() is not yet vectorized by Eigen
+
+ // compute pixel colors
+ for(int i = 0; i < packetSize; i++)
+ {
+ buffer[4*(pix+i)] = 255*pix_iter[i]/max_iter;
+ buffer[4*(pix+i)+1] = 0;
+ buffer[4*(pix+i)+2] = 0;
+ }
+ }
+
+ // if the width is not a multiple of packetSize, fill the remainder in black
+ for(int x = alignedWidth; x < img_width; x++, pix++)
+ buffer[4*pix] = buffer[4*pix+1] = buffer[4*pix+2] = 0;
+ }
+ return;
+}
+
+void MandelbrotThread::run()
+{
+ setTerminationEnabled(true);
+ double resolution = widget->xradius*2/widget->width();
+ max_iter = 128;
+ if(resolution < 1e-4f) max_iter += 128 * ( - 4 - std::log10(resolution));
+ int img_width = widget->width()/widget->draft;
+ int img_height = widget->height()/widget->draft;
+ single_precision = resolution > 1e-7f;
+
+ if(single_precision)
+ render<float>(img_width, img_height);
+ else
+ render<double>(img_width, img_height);
+}
+
+void MandelbrotWidget::paintEvent(QPaintEvent *)
+{
+ static float max_speed = 0;
+ long long total_iter = 0;
+
+ QTime time;
+ time.start();
+ for(int th = 0; th < threadcount; th++)
+ threads[th]->start(QThread::LowPriority);
+ for(int th = 0; th < threadcount; th++)
+ {
+ threads[th]->wait();
+ total_iter += threads[th]->total_iter;
+ }
+ int elapsed = time.elapsed();
+
+ if(draft == 1)
+ {
+ float speed = elapsed ? float(total_iter)*1000/elapsed : 0;
+ max_speed = std::max(max_speed, speed);
+ std::cout << threadcount << " threads, "
+ << elapsed << " ms, "
+ << speed << " iters/s (max " << max_speed << ")" << std::endl;
+ int packetSize = threads[0]->single_precision
+ ? int(Eigen::internal::packet_traits<float>::size)
+ : int(Eigen::internal::packet_traits<double>::size);
+ setWindowTitle(QString("resolution ")+QString::number(xradius*2/width(), 'e', 2)
+ +QString(", %1 iterations per pixel, ").arg(threads[0]->max_iter)
+ +(threads[0]->single_precision ? QString("single ") : QString("double "))
+ +QString("precision, ")
+ +(packetSize==1 ? QString("no vectorization")
+ : QString("vectorized (%1 per packet)").arg(packetSize)));
+ }
+
+ QImage image(buffer, width()/draft, height()/draft, QImage::Format_RGB32);
+ QPainter painter(this);
+ painter.drawImage(QPoint(0, 0), image.scaled(width(), height()));
+
+ if(draft>1)
+ {
+ draft /= 2;
+ setWindowTitle(QString("recomputing at 1/%1 resolution...").arg(draft));
+ update();
+ }
+}
+
+void MandelbrotWidget::mousePressEvent(QMouseEvent *event)
+{
+ if( event->buttons() & Qt::LeftButton )
+ {
+ lastpos = event->pos();
+ double yradius = xradius * height() / width();
+ center = Eigen::Vector2d(center.x() + (event->pos().x() - width()/2) * xradius * 2 / width(),
+ center.y() + (event->pos().y() - height()/2) * yradius * 2 / height());
+ draft = 16;
+ for(int th = 0; th < threadcount; th++)
+ threads[th]->terminate();
+ update();
+ }
+}
+
+void MandelbrotWidget::mouseMoveEvent(QMouseEvent *event)
+{
+ QPoint delta = event->pos() - lastpos;
+ lastpos = event->pos();
+ if( event->buttons() & Qt::LeftButton )
+ {
+ double t = 1 + 5 * double(delta.y()) / height();
+ if(t < 0.5) t = 0.5;
+ if(t > 2) t = 2;
+ xradius *= t;
+ draft = 16;
+ for(int th = 0; th < threadcount; th++)
+ threads[th]->terminate();
+ update();
+ }
+}
+
+int main(int argc, char *argv[])
+{
+ QApplication app(argc, argv);
+ MandelbrotWidget w;
+ w.show();
+ return app.exec();
+}
+
+#include "mandelbrot.moc"
diff --git a/demos/mandelbrot/mandelbrot.h b/demos/mandelbrot/mandelbrot.h
new file mode 100644
index 000000000..a687fd016
--- /dev/null
+++ b/demos/mandelbrot/mandelbrot.h
@@ -0,0 +1,71 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra.
+//
+// Copyright (C) 2008 Benoit Jacob <jacob.benoit.1@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 MANDELBROT_H
+#define MANDELBROT_H
+
+#include <Eigen/Core>
+#include <QtGui/QApplication>
+#include <QtGui/QWidget>
+#include <QtCore/QThread>
+
+class MandelbrotWidget;
+
+class MandelbrotThread : public QThread
+{
+ friend class MandelbrotWidget;
+ MandelbrotWidget *widget;
+ long long total_iter;
+ int id, max_iter;
+ bool single_precision;
+
+ public:
+ MandelbrotThread(MandelbrotWidget *w, int i) : widget(w), id(i) {}
+ void run();
+ template<typename Real> void render(int img_width, int img_height);
+};
+
+class MandelbrotWidget : public QWidget
+{
+ Q_OBJECT
+
+ friend class MandelbrotThread;
+ Eigen::Vector2d center;
+ double xradius;
+ int size;
+ unsigned char *buffer;
+ QPoint lastpos;
+ int draft;
+ MandelbrotThread **threads;
+ int threadcount;
+
+ protected:
+ void resizeEvent(QResizeEvent *);
+ void paintEvent(QPaintEvent *);
+ void mousePressEvent(QMouseEvent *event);
+ void mouseMoveEvent(QMouseEvent *event);
+
+ public:
+ MandelbrotWidget() : QWidget(), center(0,0), xradius(2),
+ size(0), buffer(0), draft(16)
+ {
+ setAutoFillBackground(false);
+ threadcount = QThread::idealThreadCount();
+ threads = new MandelbrotThread*[threadcount];
+ for(int th = 0; th < threadcount; th++) threads[th] = new MandelbrotThread(this, th);
+ }
+ ~MandelbrotWidget()
+ {
+ if(buffer) delete[]buffer;
+ for(int th = 0; th < threadcount; th++) delete threads[th];
+ delete[] threads;
+ }
+};
+
+#endif // MANDELBROT_H
diff --git a/demos/mix_eigen_and_c/README b/demos/mix_eigen_and_c/README
new file mode 100644
index 000000000..21dba8679
--- /dev/null
+++ b/demos/mix_eigen_and_c/README
@@ -0,0 +1,9 @@
+This is an example of how one can wrap some of Eigen into a C library.
+
+To try this with GCC, do:
+
+ g++ -c binary_library.cpp -O2 -msse2 -I ../..
+ gcc example.c binary_library.o -o example -lstdc++
+ ./example
+
+TODO: add CMakeLists, add more explanations here \ No newline at end of file
diff --git a/demos/mix_eigen_and_c/binary_library.cpp b/demos/mix_eigen_and_c/binary_library.cpp
new file mode 100644
index 000000000..15a2d03e9
--- /dev/null
+++ b/demos/mix_eigen_and_c/binary_library.cpp
@@ -0,0 +1,185 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra.
+//
+// Copyright (C) 2009 Benoit Jacob <jacob.benoit.1@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/.
+
+// This C++ file compiles to binary code that can be linked to by your C program,
+// thanks to the extern "C" syntax used in the declarations in binary_library.h.
+
+#include "binary_library.h"
+
+#include <Eigen/Core>
+
+using namespace Eigen;
+
+/************************* pointer conversion methods **********************************************/
+
+////// class MatrixXd //////
+
+inline MatrixXd& c_to_eigen(C_MatrixXd* ptr)
+{
+ return *reinterpret_cast<MatrixXd*>(ptr);
+}
+
+inline const MatrixXd& c_to_eigen(const C_MatrixXd* ptr)
+{
+ return *reinterpret_cast<const MatrixXd*>(ptr);
+}
+
+inline C_MatrixXd* eigen_to_c(MatrixXd& ref)
+{
+ return reinterpret_cast<C_MatrixXd*>(&ref);
+}
+
+inline const C_MatrixXd* eigen_to_c(const MatrixXd& ref)
+{
+ return reinterpret_cast<const C_MatrixXd*>(&ref);
+}
+
+////// class Map<MatrixXd> //////
+
+inline Map<MatrixXd>& c_to_eigen(C_Map_MatrixXd* ptr)
+{
+ return *reinterpret_cast<Map<MatrixXd>*>(ptr);
+}
+
+inline const Map<MatrixXd>& c_to_eigen(const C_Map_MatrixXd* ptr)
+{
+ return *reinterpret_cast<const Map<MatrixXd>*>(ptr);
+}
+
+inline C_Map_MatrixXd* eigen_to_c(Map<MatrixXd>& ref)
+{
+ return reinterpret_cast<C_Map_MatrixXd*>(&ref);
+}
+
+inline const C_Map_MatrixXd* eigen_to_c(const Map<MatrixXd>& ref)
+{
+ return reinterpret_cast<const C_Map_MatrixXd*>(&ref);
+}
+
+
+/************************* implementation of classes **********************************************/
+
+
+////// class MatrixXd //////
+
+
+C_MatrixXd* MatrixXd_new(int rows, int cols)
+{
+ return eigen_to_c(*new MatrixXd(rows,cols));
+}
+
+void MatrixXd_delete(C_MatrixXd *m)
+{
+ delete &c_to_eigen(m);
+}
+
+double* MatrixXd_data(C_MatrixXd *m)
+{
+ return c_to_eigen(m).data();
+}
+
+void MatrixXd_set_zero(C_MatrixXd *m)
+{
+ c_to_eigen(m).setZero();
+}
+
+void MatrixXd_resize(C_MatrixXd *m, int rows, int cols)
+{
+ c_to_eigen(m).resize(rows,cols);
+}
+
+void MatrixXd_copy(C_MatrixXd *dst, const C_MatrixXd *src)
+{
+ c_to_eigen(dst) = c_to_eigen(src);
+}
+
+void MatrixXd_copy_map(C_MatrixXd *dst, const C_Map_MatrixXd *src)
+{
+ c_to_eigen(dst) = c_to_eigen(src);
+}
+
+void MatrixXd_set_coeff(C_MatrixXd *m, int i, int j, double coeff)
+{
+ c_to_eigen(m)(i,j) = coeff;
+}
+
+double MatrixXd_get_coeff(const C_MatrixXd *m, int i, int j)
+{
+ return c_to_eigen(m)(i,j);
+}
+
+void MatrixXd_print(const C_MatrixXd *m)
+{
+ std::cout << c_to_eigen(m) << std::endl;
+}
+
+void MatrixXd_multiply(const C_MatrixXd *m1, const C_MatrixXd *m2, C_MatrixXd *result)
+{
+ c_to_eigen(result) = c_to_eigen(m1) * c_to_eigen(m2);
+}
+
+void MatrixXd_add(const C_MatrixXd *m1, const C_MatrixXd *m2, C_MatrixXd *result)
+{
+ c_to_eigen(result) = c_to_eigen(m1) + c_to_eigen(m2);
+}
+
+
+
+////// class Map_MatrixXd //////
+
+
+C_Map_MatrixXd* Map_MatrixXd_new(double *array, int rows, int cols)
+{
+ return eigen_to_c(*new Map<MatrixXd>(array,rows,cols));
+}
+
+void Map_MatrixXd_delete(C_Map_MatrixXd *m)
+{
+ delete &c_to_eigen(m);
+}
+
+void Map_MatrixXd_set_zero(C_Map_MatrixXd *m)
+{
+ c_to_eigen(m).setZero();
+}
+
+void Map_MatrixXd_copy(C_Map_MatrixXd *dst, const C_Map_MatrixXd *src)
+{
+ c_to_eigen(dst) = c_to_eigen(src);
+}
+
+void Map_MatrixXd_copy_matrix(C_Map_MatrixXd *dst, const C_MatrixXd *src)
+{
+ c_to_eigen(dst) = c_to_eigen(src);
+}
+
+void Map_MatrixXd_set_coeff(C_Map_MatrixXd *m, int i, int j, double coeff)
+{
+ c_to_eigen(m)(i,j) = coeff;
+}
+
+double Map_MatrixXd_get_coeff(const C_Map_MatrixXd *m, int i, int j)
+{
+ return c_to_eigen(m)(i,j);
+}
+
+void Map_MatrixXd_print(const C_Map_MatrixXd *m)
+{
+ std::cout << c_to_eigen(m) << std::endl;
+}
+
+void Map_MatrixXd_multiply(const C_Map_MatrixXd *m1, const C_Map_MatrixXd *m2, C_Map_MatrixXd *result)
+{
+ c_to_eigen(result) = c_to_eigen(m1) * c_to_eigen(m2);
+}
+
+void Map_MatrixXd_add(const C_Map_MatrixXd *m1, const C_Map_MatrixXd *m2, C_Map_MatrixXd *result)
+{
+ c_to_eigen(result) = c_to_eigen(m1) + c_to_eigen(m2);
+}
diff --git a/demos/mix_eigen_and_c/binary_library.h b/demos/mix_eigen_and_c/binary_library.h
new file mode 100644
index 000000000..0b983ad3a
--- /dev/null
+++ b/demos/mix_eigen_and_c/binary_library.h
@@ -0,0 +1,71 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra.
+//
+// Copyright (C) 2009 Benoit Jacob <jacob.benoit.1@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/.
+
+// This is a pure C header, no C++ here.
+// The functions declared here will be implemented in C++ but
+// we don't have to know, because thanks to the extern "C" syntax,
+// they will be compiled to C object code.
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+ // just dummy empty structs to give different pointer types,
+ // instead of using void* which would be type unsafe
+ struct C_MatrixXd {};
+ struct C_Map_MatrixXd {};
+
+ // the C_MatrixXd class, wraps some of the functionality
+ // of Eigen::MatrixXd.
+ struct C_MatrixXd* MatrixXd_new(int rows, int cols);
+ void MatrixXd_delete (struct C_MatrixXd *m);
+ double* MatrixXd_data (struct C_MatrixXd *m);
+ void MatrixXd_set_zero (struct C_MatrixXd *m);
+ void MatrixXd_resize (struct C_MatrixXd *m, int rows, int cols);
+ void MatrixXd_copy (struct C_MatrixXd *dst,
+ const struct C_MatrixXd *src);
+ void MatrixXd_copy_map (struct C_MatrixXd *dst,
+ const struct C_Map_MatrixXd *src);
+ void MatrixXd_set_coeff (struct C_MatrixXd *m,
+ int i, int j, double coeff);
+ double MatrixXd_get_coeff (const struct C_MatrixXd *m,
+ int i, int j);
+ void MatrixXd_print (const struct C_MatrixXd *m);
+ void MatrixXd_add (const struct C_MatrixXd *m1,
+ const struct C_MatrixXd *m2,
+ struct C_MatrixXd *result);
+ void MatrixXd_multiply (const struct C_MatrixXd *m1,
+ const struct C_MatrixXd *m2,
+ struct C_MatrixXd *result);
+
+ // the C_Map_MatrixXd class, wraps some of the functionality
+ // of Eigen::Map<MatrixXd>
+ struct C_Map_MatrixXd* Map_MatrixXd_new(double *array, int rows, int cols);
+ void Map_MatrixXd_delete (struct C_Map_MatrixXd *m);
+ void Map_MatrixXd_set_zero (struct C_Map_MatrixXd *m);
+ void Map_MatrixXd_copy (struct C_Map_MatrixXd *dst,
+ const struct C_Map_MatrixXd *src);
+ void Map_MatrixXd_copy_matrix(struct C_Map_MatrixXd *dst,
+ const struct C_MatrixXd *src);
+ void Map_MatrixXd_set_coeff (struct C_Map_MatrixXd *m,
+ int i, int j, double coeff);
+ double Map_MatrixXd_get_coeff (const struct C_Map_MatrixXd *m,
+ int i, int j);
+ void Map_MatrixXd_print (const struct C_Map_MatrixXd *m);
+ void Map_MatrixXd_add (const struct C_Map_MatrixXd *m1,
+ const struct C_Map_MatrixXd *m2,
+ struct C_Map_MatrixXd *result);
+ void Map_MatrixXd_multiply (const struct C_Map_MatrixXd *m1,
+ const struct C_Map_MatrixXd *m2,
+ struct C_Map_MatrixXd *result);
+
+#ifdef __cplusplus
+} // end extern "C"
+#endif \ No newline at end of file
diff --git a/demos/mix_eigen_and_c/example.c b/demos/mix_eigen_and_c/example.c
new file mode 100644
index 000000000..508eb5467
--- /dev/null
+++ b/demos/mix_eigen_and_c/example.c
@@ -0,0 +1,65 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra.
+//
+// Copyright (C) 2009 Benoit Jacob <jacob.benoit.1@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 "binary_library.h"
+#include "stdio.h"
+
+void demo_MatrixXd()
+{
+ struct C_MatrixXd *matrix1, *matrix2, *result;
+ printf("*** demo_MatrixXd ***\n");
+
+ matrix1 = MatrixXd_new(3, 3);
+ MatrixXd_set_zero(matrix1);
+ MatrixXd_set_coeff(matrix1, 0, 1, 2.5);
+ MatrixXd_set_coeff(matrix1, 1, 0, 1.4);
+ printf("Here is matrix1:\n");
+ MatrixXd_print(matrix1);
+
+ matrix2 = MatrixXd_new(3, 3);
+ MatrixXd_multiply(matrix1, matrix1, matrix2);
+ printf("Here is matrix1*matrix1:\n");
+ MatrixXd_print(matrix2);
+
+ MatrixXd_delete(matrix1);
+ MatrixXd_delete(matrix2);
+}
+
+// this helper function takes a plain C array and prints it in one line
+void print_array(double *array, int n)
+{
+ struct C_Map_MatrixXd *m = Map_MatrixXd_new(array, 1, n);
+ Map_MatrixXd_print(m);
+ Map_MatrixXd_delete(m);
+}
+
+void demo_Map_MatrixXd()
+{
+ struct C_Map_MatrixXd *map;
+ double array[5];
+ int i;
+ printf("*** demo_Map_MatrixXd ***\n");
+
+ for(i = 0; i < 5; ++i) array[i] = i;
+ printf("Initially, the array is:\n");
+ print_array(array, 5);
+
+ map = Map_MatrixXd_new(array, 5, 1);
+ Map_MatrixXd_add(map, map, map);
+ Map_MatrixXd_delete(map);
+
+ printf("Now the array is:\n");
+ print_array(array, 5);
+}
+
+int main()
+{
+ demo_MatrixXd();
+ demo_Map_MatrixXd();
+}
diff --git a/demos/opengl/CMakeLists.txt b/demos/opengl/CMakeLists.txt
new file mode 100644
index 000000000..b98a30c01
--- /dev/null
+++ b/demos/opengl/CMakeLists.txt
@@ -0,0 +1,20 @@
+find_package(Qt4 REQUIRED)
+find_package(OpenGL REQUIRED)
+
+set(QT_USE_QTOPENGL TRUE)
+include(${QT_USE_FILE})
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+include_directories( ${QT_INCLUDE_DIR} )
+
+set(quaternion_demo_SRCS gpuhelper.cpp icosphere.cpp camera.cpp trackball.cpp quaternion_demo.cpp)
+
+qt4_automoc(${quaternion_demo_SRCS})
+
+add_executable(quaternion_demo ${quaternion_demo_SRCS})
+add_dependencies(demos quaternion_demo)
+
+target_link_libraries(quaternion_demo
+ ${QT_QTCORE_LIBRARY} ${QT_QTGUI_LIBRARY}
+ ${QT_QTOPENGL_LIBRARY} ${OPENGL_LIBRARIES} )
diff --git a/demos/opengl/README b/demos/opengl/README
new file mode 100644
index 000000000..8fb16496c
--- /dev/null
+++ b/demos/opengl/README
@@ -0,0 +1,13 @@
+
+Navigation:
+ left button: rotate around the target
+ middle button: zoom
+ left button + ctrl quake rotate (rotate around camera position)
+ middle button + ctrl walk (progress along camera's z direction)
+ left button: pan (translate in the XY camera's plane)
+
+R : move the camera to initial position
+A : start/stop animation
+C : clear the animation
+G : add a key frame
+
diff --git a/demos/opengl/camera.cpp b/demos/opengl/camera.cpp
new file mode 100644
index 000000000..8a2344c85
--- /dev/null
+++ b/demos/opengl/camera.cpp
@@ -0,0 +1,264 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra.
+//
+// Copyright (C) 2008 Gael Guennebaud <gael.guennebaud@inria.fr>
+//
+// This Source Code Form is subject to the terms of the Mozilla
+// Public License v. 2.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 "camera.h"
+
+#include "gpuhelper.h"
+#include <GL/glu.h>
+
+#include "Eigen/LU"
+using namespace Eigen;
+
+Camera::Camera()
+ : mViewIsUptodate(false), mProjIsUptodate(false)
+{
+ mViewMatrix.setIdentity();
+
+ mFovY = M_PI/3.;
+ mNearDist = 1.;
+ mFarDist = 50000.;
+
+ mVpX = 0;
+ mVpY = 0;
+
+ setPosition(Vector3f::Constant(100.));
+ setTarget(Vector3f::Zero());
+}
+
+Camera& Camera::operator=(const Camera& other)
+{
+ mViewIsUptodate = false;
+ mProjIsUptodate = false;
+
+ mVpX = other.mVpX;
+ mVpY = other.mVpY;
+ mVpWidth = other.mVpWidth;
+ mVpHeight = other.mVpHeight;
+
+ mTarget = other.mTarget;
+ mFovY = other.mFovY;
+ mNearDist = other.mNearDist;
+ mFarDist = other.mFarDist;
+
+ mViewMatrix = other.mViewMatrix;
+ mProjectionMatrix = other.mProjectionMatrix;
+
+ return *this;
+}
+
+Camera::Camera(const Camera& other)
+{
+ *this = other;
+}
+
+Camera::~Camera()
+{
+}
+
+
+void Camera::setViewport(uint offsetx, uint offsety, uint width, uint height)
+{
+ mVpX = offsetx;
+ mVpY = offsety;
+ mVpWidth = width;
+ mVpHeight = height;
+
+ mProjIsUptodate = false;
+}
+
+void Camera::setViewport(uint width, uint height)
+{
+ mVpWidth = width;
+ mVpHeight = height;
+
+ mProjIsUptodate = false;
+}
+
+void Camera::setFovY(float value)
+{
+ mFovY = value;
+ mProjIsUptodate = false;
+}
+
+Vector3f Camera::direction(void) const
+{
+ return - (orientation() * Vector3f::UnitZ());
+}
+Vector3f Camera::up(void) const
+{
+ return orientation() * Vector3f::UnitY();
+}
+Vector3f Camera::right(void) const
+{
+ return orientation() * Vector3f::UnitX();
+}
+
+void Camera::setDirection(const Vector3f& newDirection)
+{
+ // TODO implement it computing the rotation between newDirection and current dir ?
+ Vector3f up = this->up();
+
+ Matrix3f camAxes;
+
+ camAxes.col(2) = (-newDirection).normalized();
+ camAxes.col(0) = up.cross( camAxes.col(2) ).normalized();
+ camAxes.col(1) = camAxes.col(2).cross( camAxes.col(0) ).normalized();
+ setOrientation(Quaternionf(camAxes));
+
+ mViewIsUptodate = false;
+}
+
+void Camera::setTarget(const Vector3f& target)
+{
+ mTarget = target;
+ if (!mTarget.isApprox(position()))
+ {
+ Vector3f newDirection = mTarget - position();
+ setDirection(newDirection.normalized());
+ }
+}
+
+void Camera::setPosition(const Vector3f& p)
+{
+ mFrame.position = p;
+ mViewIsUptodate = false;
+}
+
+void Camera::setOrientation(const Quaternionf& q)
+{
+ mFrame.orientation = q;
+ mViewIsUptodate = false;
+}
+
+void Camera::setFrame(const Frame& f)
+{
+ mFrame = f;
+ mViewIsUptodate = false;
+}
+
+void Camera::rotateAroundTarget(const Quaternionf& q)
+{
+ Matrix4f mrot, mt, mtm;
+
+ // update the transform matrix
+ updateViewMatrix();
+ Vector3f t = mViewMatrix * mTarget;
+
+ mViewMatrix = Translation3f(t)
+ * q
+ * Translation3f(-t)
+ * mViewMatrix;
+
+ Quaternionf qa(mViewMatrix.linear());
+ qa = qa.conjugate();
+ setOrientation(qa);
+ setPosition(- (qa * mViewMatrix.translation()) );
+
+ mViewIsUptodate = true;
+}
+
+void Camera::localRotate(const Quaternionf& q)
+{
+ float dist = (position() - mTarget).norm();
+ setOrientation(orientation() * q);
+ mTarget = position() + dist * direction();
+ mViewIsUptodate = false;
+}
+
+void Camera::zoom(float d)
+{
+ float dist = (position() - mTarget).norm();
+ if(dist > d)
+ {
+ setPosition(position() + direction() * d);
+ mViewIsUptodate = false;
+ }
+}
+
+void Camera::localTranslate(const Vector3f& t)
+{
+ Vector3f trans = orientation() * t;
+ setPosition( position() + trans );
+ setTarget( mTarget + trans );
+
+ mViewIsUptodate = false;
+}
+
+void Camera::updateViewMatrix(void) const
+{
+ if(!mViewIsUptodate)
+ {
+ Quaternionf q = orientation().conjugate();
+ mViewMatrix.linear() = q.toRotationMatrix();
+ mViewMatrix.translation() = - (mViewMatrix.linear() * position());
+
+ mViewIsUptodate = true;
+ }
+}
+
+const Affine3f& Camera::viewMatrix(void) const
+{
+ updateViewMatrix();
+ return mViewMatrix;
+}
+
+void Camera::updateProjectionMatrix(void) const
+{
+ if(!mProjIsUptodate)
+ {
+ mProjectionMatrix.setIdentity();
+ float aspect = float(mVpWidth)/float(mVpHeight);
+ float theta = mFovY*0.5;
+ float range = mFarDist - mNearDist;
+ float invtan = 1./tan(theta);
+
+ mProjectionMatrix(0,0) = invtan / aspect;
+ mProjectionMatrix(1,1) = invtan;
+ mProjectionMatrix(2,2) = -(mNearDist + mFarDist) / range;
+ mProjectionMatrix(3,2) = -1;
+ mProjectionMatrix(2,3) = -2 * mNearDist * mFarDist / range;
+ mProjectionMatrix(3,3) = 0;
+
+ mProjIsUptodate = true;
+ }
+}
+
+const Matrix4f& Camera::projectionMatrix(void) const
+{
+ updateProjectionMatrix();
+ return mProjectionMatrix;
+}
+
+void Camera::activateGL(void)
+{
+ glViewport(vpX(), vpY(), vpWidth(), vpHeight());
+ gpu.loadMatrix(projectionMatrix(),GL_PROJECTION);
+ gpu.loadMatrix(viewMatrix().matrix(),GL_MODELVIEW);
+}
+
+
+Vector3f Camera::unProject(const Vector2f& uv, float depth) const
+{
+ Matrix4f inv = mViewMatrix.inverse().matrix();
+ return unProject(uv, depth, inv);
+}
+
+Vector3f Camera::unProject(const Vector2f& uv, float depth, const Matrix4f& invModelview) const
+{
+ updateViewMatrix();
+ updateProjectionMatrix();
+
+ Vector3f a(2.*uv.x()/float(mVpWidth)-1., 2.*uv.y()/float(mVpHeight)-1., 1.);
+ a.x() *= depth/mProjectionMatrix(0,0);
+ a.y() *= depth/mProjectionMatrix(1,1);
+ a.z() = -depth;
+ // FIXME /\/|
+ Vector4f b = invModelview * Vector4f(a.x(), a.y(), a.z(), 1.);
+ return Vector3f(b.x(), b.y(), b.z());
+}
diff --git a/demos/opengl/camera.h b/demos/opengl/camera.h
new file mode 100644
index 000000000..15714d2e6
--- /dev/null
+++ b/demos/opengl/camera.h
@@ -0,0 +1,118 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra.
+//
+// Copyright (C) 2008 Gael Guennebaud <gael.guennebaud@inria.fr>
+//
+// This Source Code Form is subject to the terms of the Mozilla
+// Public License v. 2.0. If a copy of the MPL was not distributed
+// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+#ifndef EIGEN_CAMERA_H
+#define EIGEN_CAMERA_H
+
+#include <Eigen/Geometry>
+#include <QObject>
+// #include <frame.h>
+
+class Frame
+{
+ public:
+ EIGEN_MAKE_ALIGNED_OPERATOR_NEW
+
+ inline Frame(const Eigen::Vector3f& pos = Eigen::Vector3f::Zero(),
+ const Eigen::Quaternionf& o = Eigen::Quaternionf())
+ : orientation(o), position(pos)
+ {}
+ Frame lerp(float alpha, const Frame& other) const
+ {
+ return Frame((1.f-alpha)*position + alpha * other.position,
+ orientation.slerp(alpha,other.orientation));
+ }
+
+ Eigen::Quaternionf orientation;
+ Eigen::Vector3f position;
+};
+
+class Camera
+{
+ public:
+ EIGEN_MAKE_ALIGNED_OPERATOR_NEW
+
+ Camera(void);
+
+ Camera(const Camera& other);
+
+ virtual ~Camera();
+
+ Camera& operator=(const Camera& other);
+
+ void setViewport(uint offsetx, uint offsety, uint width, uint height);
+ void setViewport(uint width, uint height);
+
+ inline uint vpX(void) const { return mVpX; }
+ inline uint vpY(void) const { return mVpY; }
+ inline uint vpWidth(void) const { return mVpWidth; }
+ inline uint vpHeight(void) const { return mVpHeight; }
+
+ inline float fovY(void) const { return mFovY; }
+ void setFovY(float value);
+
+ void setPosition(const Eigen::Vector3f& pos);
+ inline const Eigen::Vector3f& position(void) const { return mFrame.position; }
+
+ void setOrientation(const Eigen::Quaternionf& q);
+ inline const Eigen::Quaternionf& orientation(void) const { return mFrame.orientation; }
+
+ void setFrame(const Frame& f);
+ const Frame& frame(void) const { return mFrame; }
+
+ void setDirection(const Eigen::Vector3f& newDirection);
+ Eigen::Vector3f direction(void) const;
+ void setUp(const Eigen::Vector3f& vectorUp);
+ Eigen::Vector3f up(void) const;
+ Eigen::Vector3f right(void) const;
+
+ void setTarget(const Eigen::Vector3f& target);
+ inline const Eigen::Vector3f& target(void) { return mTarget; }
+
+ const Eigen::Affine3f& viewMatrix(void) const;
+ const Eigen::Matrix4f& projectionMatrix(void) const;
+
+ void rotateAroundTarget(const Eigen::Quaternionf& q);
+ void localRotate(const Eigen::Quaternionf& q);
+ void zoom(float d);
+
+ void localTranslate(const Eigen::Vector3f& t);
+
+ /** Setup OpenGL matrices and viewport */
+ void activateGL(void);
+
+ Eigen::Vector3f unProject(const Eigen::Vector2f& uv, float depth, const Eigen::Matrix4f& invModelview) const;
+ Eigen::Vector3f unProject(const Eigen::Vector2f& uv, float depth) const;
+
+ protected:
+ void updateViewMatrix(void) const;
+ void updateProjectionMatrix(void) const;
+
+ protected:
+
+ uint mVpX, mVpY;
+ uint mVpWidth, mVpHeight;
+
+ Frame mFrame;
+
+ mutable Eigen::Affine3f mViewMatrix;
+ mutable Eigen::Matrix4f mProjectionMatrix;
+
+ mutable bool mViewIsUptodate;
+ mutable bool mProjIsUptodate;
+
+ // used by rotateAroundTarget
+ Eigen::Vector3f mTarget;
+
+ float mFovY;
+ float mNearDist;
+ float mFarDist;
+};
+
+#endif // EIGEN_CAMERA_H
diff --git a/demos/opengl/gpuhelper.cpp b/demos/opengl/gpuhelper.cpp
new file mode 100644
index 000000000..fd236b11c
--- /dev/null
+++ b/demos/opengl/gpuhelper.cpp
@@ -0,0 +1,126 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra.
+//
+// Copyright (C) 2008 Gael Guennebaud <gael.guennebaud@inria.fr>
+//
+// This Source Code Form is subject to the terms of the Mozilla
+// Public License v. 2.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 "gpuhelper.h"
+#include "icosphere.h"
+#include <GL/glu.h>
+// PLEASE don't look at this old code... ;)
+
+#include <fstream>
+#include <algorithm>
+
+GpuHelper gpu;
+
+GpuHelper::GpuHelper()
+{
+ mVpWidth = mVpHeight = 0;
+ mCurrentMatrixTarget = 0;
+ mInitialized = false;
+}
+
+GpuHelper::~GpuHelper()
+{
+}
+
+void GpuHelper::pushProjectionMode2D(ProjectionMode2D pm)
+{
+ // switch to 2D projection
+ pushMatrix(Matrix4f::Identity(),GL_PROJECTION);
+
+ if(pm==PM_Normalized)
+ {
+ //glOrtho(-1., 1., -1., 1., 0., 1.);
+ }
+ else if(pm==PM_Viewport)
+ {
+ GLint vp[4];
+ glGetIntegerv(GL_VIEWPORT, vp);
+ glOrtho(0., vp[2], 0., vp[3], -1., 1.);
+ }
+
+ pushMatrix(Matrix4f::Identity(),GL_MODELVIEW);
+}
+
+void GpuHelper::popProjectionMode2D(void)
+{
+ popMatrix(GL_PROJECTION);
+ popMatrix(GL_MODELVIEW);
+}
+
+void GpuHelper::drawVector(const Vector3f& position, const Vector3f& vec, const Color& color, float aspect /* = 50.*/)
+{
+ static GLUquadricObj *cylindre = gluNewQuadric();
+ glColor4fv(color.data());
+ float length = vec.norm();
+ pushMatrix(GL_MODELVIEW);
+ glTranslatef(position.x(), position.y(), position.z());
+ Vector3f ax = Matrix3f::Identity().col(2).cross(vec);
+ ax.normalize();
+ Vector3f tmp = vec;
+ tmp.normalize();
+ float angle = 180.f/M_PI * acos(tmp.z());
+ if (angle>1e-3)
+ glRotatef(angle, ax.x(), ax.y(), ax.z());
+ gluCylinder(cylindre, length/aspect, length/aspect, 0.8*length, 10, 10);
+ glTranslatef(0.0,0.0,0.8*length);
+ gluCylinder(cylindre, 2.0*length/aspect, 0.0, 0.2*length, 10, 10);
+
+ popMatrix(GL_MODELVIEW);
+}
+
+void GpuHelper::drawVectorBox(const Vector3f& position, const Vector3f& vec, const Color& color, float aspect)
+{
+ static GLUquadricObj *cylindre = gluNewQuadric();
+ glColor4fv(color.data());
+ float length = vec.norm();
+ pushMatrix(GL_MODELVIEW);
+ glTranslatef(position.x(), position.y(), position.z());
+ Vector3f ax = Matrix3f::Identity().col(2).cross(vec);
+ ax.normalize();
+ Vector3f tmp = vec;
+ tmp.normalize();
+ float angle = 180.f/M_PI * acos(tmp.z());
+ if (angle>1e-3)
+ glRotatef(angle, ax.x(), ax.y(), ax.z());
+ gluCylinder(cylindre, length/aspect, length/aspect, 0.8*length, 10, 10);
+ glTranslatef(0.0,0.0,0.8*length);
+ glScalef(4.0*length/aspect,4.0*length/aspect,4.0*length/aspect);
+ drawUnitCube();
+ popMatrix(GL_MODELVIEW);
+}
+
+void GpuHelper::drawUnitCube(void)
+{
+ static float vertices[][3] = {
+ {-0.5,-0.5,-0.5},
+ { 0.5,-0.5,-0.5},
+ {-0.5, 0.5,-0.5},
+ { 0.5, 0.5,-0.5},
+ {-0.5,-0.5, 0.5},
+ { 0.5,-0.5, 0.5},
+ {-0.5, 0.5, 0.5},
+ { 0.5, 0.5, 0.5}};
+
+ glBegin(GL_QUADS);
+ glNormal3f(0,0,-1); glVertex3fv(vertices[0]); glVertex3fv(vertices[2]); glVertex3fv(vertices[3]); glVertex3fv(vertices[1]);
+ glNormal3f(0,0, 1); glVertex3fv(vertices[4]); glVertex3fv(vertices[5]); glVertex3fv(vertices[7]); glVertex3fv(vertices[6]);
+ glNormal3f(0,-1,0); glVertex3fv(vertices[0]); glVertex3fv(vertices[1]); glVertex3fv(vertices[5]); glVertex3fv(vertices[4]);
+ glNormal3f(0, 1,0); glVertex3fv(vertices[2]); glVertex3fv(vertices[6]); glVertex3fv(vertices[7]); glVertex3fv(vertices[3]);
+ glNormal3f(-1,0,0); glVertex3fv(vertices[0]); glVertex3fv(vertices[4]); glVertex3fv(vertices[6]); glVertex3fv(vertices[2]);
+ glNormal3f( 1,0,0); glVertex3fv(vertices[1]); glVertex3fv(vertices[3]); glVertex3fv(vertices[7]); glVertex3fv(vertices[5]);
+ glEnd();
+}
+
+void GpuHelper::drawUnitSphere(int level)
+{
+ static IcoSphere sphere;
+ sphere.draw(level);
+}
+
+
diff --git a/demos/opengl/gpuhelper.h b/demos/opengl/gpuhelper.h
new file mode 100644
index 000000000..9ff98e9dc
--- /dev/null
+++ b/demos/opengl/gpuhelper.h
@@ -0,0 +1,207 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra.
+//
+// Copyright (C) 2008 Gael Guennebaud <gael.guennebaud@inria.fr>
+//
+// This Source Code Form is subject to the terms of the Mozilla
+// Public License v. 2.0. If a copy of the MPL was not distributed
+// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+#ifndef EIGEN_GPUHELPER_H
+#define EIGEN_GPUHELPER_H
+
+#include <Eigen/Geometry>
+#include <GL/gl.h>
+#include <vector>
+
+using namespace Eigen;
+
+typedef Vector4f Color;
+
+class GpuHelper
+{
+ public:
+
+ GpuHelper();
+
+ ~GpuHelper();
+
+ enum ProjectionMode2D { PM_Normalized = 1, PM_Viewport = 2 };
+ void pushProjectionMode2D(ProjectionMode2D pm);
+ void popProjectionMode2D();
+
+ /** Multiply the OpenGL matrix \a matrixTarget by the matrix \a mat.
+ Essentially, this helper function automatically calls glMatrixMode(matrixTarget) if required
+ and does a proper call to the right glMultMatrix*() function according to the scalar type
+ and storage order.
+ \warning glMatrixMode() must never be called directly. If your're unsure, use forceMatrixMode().
+ \sa Matrix, loadMatrix(), forceMatrixMode()
+ */
+ template<typename Scalar, int _Flags>
+ void multMatrix(const Matrix<Scalar,4,4, _Flags, 4,4>& mat, GLenum matrixTarget);
+
+ /** Load the matrix \a mat to the OpenGL matrix \a matrixTarget.
+ Essentially, this helper function automatically calls glMatrixMode(matrixTarget) if required
+ and does a proper call to the right glLoadMatrix*() or glLoadIdentity() function according to the scalar type
+ and storage order.
+ \warning glMatrixMode() must never be called directly. If your're unsure, use forceMatrixMode().
+ \sa Matrix, multMatrix(), forceMatrixMode()
+ */
+ template<typename Scalar, int _Flags>
+ void loadMatrix(const Eigen::Matrix<Scalar,4,4, _Flags, 4,4>& mat, GLenum matrixTarget);
+
+ template<typename Scalar, typename Derived>
+ void loadMatrix(
+ const Eigen::CwiseNullaryOp<Eigen::internal::scalar_identity_op<Scalar>,Derived>&,
+ GLenum matrixTarget);
+
+ /** Make the matrix \a matrixTarget the current OpenGL matrix target.
+ Call this function before loadMatrix() or multMatrix() if you cannot guarantee that glMatrixMode()
+ has never been called after the last loadMatrix() or multMatrix() calls.
+ \todo provides a debug mode checking the sanity of the cached matrix mode.
+ */
+ inline void forceMatrixTarget(GLenum matrixTarget) {glMatrixMode(mCurrentMatrixTarget=matrixTarget);}
+
+ inline void setMatrixTarget(GLenum matrixTarget);
+
+ /** Push the OpenGL matrix \a matrixTarget and load \a mat.
+ */
+ template<typename Scalar, int _Flags>
+ inline void pushMatrix(const Matrix<Scalar,4,4, _Flags, 4,4>& mat, GLenum matrixTarget);
+
+ template<typename Scalar, typename Derived>
+ void pushMatrix(
+ const Eigen::CwiseNullaryOp<Eigen::internal::scalar_identity_op<Scalar>,Derived>&,
+ GLenum matrixTarget);
+
+ /** Push and clone the OpenGL matrix \a matrixTarget
+ */
+ inline void pushMatrix(GLenum matrixTarget);
+
+ /** Pop the OpenGL matrix \a matrixTarget
+ */
+ inline void popMatrix(GLenum matrixTarget);
+
+ void drawVector(const Vector3f& position, const Vector3f& vec, const Color& color, float aspect = 50.);
+ void drawVectorBox(const Vector3f& position, const Vector3f& vec, const Color& color, float aspect = 50.);
+ void drawUnitCube(void);
+ void drawUnitSphere(int level=0);
+
+ /// draw the \a nofElement first elements
+ inline void draw(GLenum mode, uint nofElement);
+
+ /// draw a range of elements
+ inline void draw(GLenum mode, uint start, uint end);
+
+ /// draw an indexed subset
+ inline void draw(GLenum mode, const std::vector<uint>* pIndexes);
+
+protected:
+
+ void update(void);
+
+ GLuint mColorBufferId;
+ int mVpWidth, mVpHeight;
+ GLenum mCurrentMatrixTarget;
+ bool mInitialized;
+};
+
+/** Singleton shortcut
+*/
+extern GpuHelper gpu;
+
+
+/** \internal
+*/
+template<bool RowMajor, int _Flags> struct GlMatrixHelper;
+
+template<int _Flags> struct GlMatrixHelper<false,_Flags>
+{
+ static void loadMatrix(const Matrix<float, 4,4, _Flags, 4,4>& mat) { glLoadMatrixf(mat.data()); }
+ static void loadMatrix(const Matrix<double,4,4, _Flags, 4,4>& mat) { glLoadMatrixd(mat.data()); }
+ static void multMatrix(const Matrix<float, 4,4, _Flags, 4,4>& mat) { glMultMatrixf(mat.data()); }
+ static void multMatrix(const Matrix<double,4,4, _Flags, 4,4>& mat) { glMultMatrixd(mat.data()); }
+};
+
+template<int _Flags> struct GlMatrixHelper<true,_Flags>
+{
+ static void loadMatrix(const Matrix<float, 4,4, _Flags, 4,4>& mat) { glLoadMatrixf(mat.transpose().eval().data()); }
+ static void loadMatrix(const Matrix<double,4,4, _Flags, 4,4>& mat) { glLoadMatrixd(mat.transpose().eval().data()); }
+ static void multMatrix(const Matrix<float, 4,4, _Flags, 4,4>& mat) { glMultMatrixf(mat.transpose().eval().data()); }
+ static void multMatrix(const Matrix<double,4,4, _Flags, 4,4>& mat) { glMultMatrixd(mat.transpose().eval().data()); }
+};
+
+inline void GpuHelper::setMatrixTarget(GLenum matrixTarget)
+{
+ if (matrixTarget != mCurrentMatrixTarget)
+ glMatrixMode(mCurrentMatrixTarget=matrixTarget);
+}
+
+template<typename Scalar, int _Flags>
+void GpuHelper::multMatrix(const Matrix<Scalar,4,4, _Flags, 4,4>& mat, GLenum matrixTarget)
+{
+ setMatrixTarget(matrixTarget);
+ GlMatrixHelper<_Flags&Eigen::RowMajorBit, _Flags>::multMatrix(mat);
+}
+
+template<typename Scalar, typename Derived>
+void GpuHelper::loadMatrix(
+ const Eigen::CwiseNullaryOp<Eigen::internal::scalar_identity_op<Scalar>,Derived>&,
+ GLenum matrixTarget)
+{
+ setMatrixTarget(matrixTarget);
+ glLoadIdentity();
+}
+
+template<typename Scalar, int _Flags>
+void GpuHelper::loadMatrix(const Eigen::Matrix<Scalar,4,4, _Flags, 4,4>& mat, GLenum matrixTarget)
+{
+ setMatrixTarget(matrixTarget);
+ GlMatrixHelper<(_Flags&Eigen::RowMajorBit)!=0, _Flags>::loadMatrix(mat);
+}
+
+inline void GpuHelper::pushMatrix(GLenum matrixTarget)
+{
+ setMatrixTarget(matrixTarget);
+ glPushMatrix();
+}
+
+template<typename Scalar, int _Flags>
+inline void GpuHelper::pushMatrix(const Matrix<Scalar,4,4, _Flags, 4,4>& mat, GLenum matrixTarget)
+{
+ pushMatrix(matrixTarget);
+ GlMatrixHelper<_Flags&Eigen::RowMajorBit,_Flags>::loadMatrix(mat);
+}
+
+template<typename Scalar, typename Derived>
+void GpuHelper::pushMatrix(
+ const Eigen::CwiseNullaryOp<Eigen::internal::scalar_identity_op<Scalar>,Derived>&,
+ GLenum matrixTarget)
+{
+ pushMatrix(matrixTarget);
+ glLoadIdentity();
+}
+
+inline void GpuHelper::popMatrix(GLenum matrixTarget)
+{
+ setMatrixTarget(matrixTarget);
+ glPopMatrix();
+}
+
+inline void GpuHelper::draw(GLenum mode, uint nofElement)
+{
+ glDrawArrays(mode, 0, nofElement);
+}
+
+
+inline void GpuHelper::draw(GLenum mode, const std::vector<uint>* pIndexes)
+{
+ glDrawElements(mode, pIndexes->size(), GL_UNSIGNED_INT, &(pIndexes->front()));
+}
+
+inline void GpuHelper::draw(GLenum mode, uint start, uint end)
+{
+ glDrawArrays(mode, start, end-start);
+}
+
+#endif // EIGEN_GPUHELPER_H
diff --git a/demos/opengl/icosphere.cpp b/demos/opengl/icosphere.cpp
new file mode 100644
index 000000000..39444cbb6
--- /dev/null
+++ b/demos/opengl/icosphere.cpp
@@ -0,0 +1,120 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra.
+//
+// Copyright (C) 2008 Gael Guennebaud <gael.guennebaud@inria.fr>
+//
+// This Source Code Form is subject to the terms of the Mozilla
+// Public License v. 2.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 "icosphere.h"
+
+#include <GL/gl.h>
+#include <map>
+
+using namespace Eigen;
+
+//--------------------------------------------------------------------------------
+// icosahedron data
+//--------------------------------------------------------------------------------
+#define X .525731112119133606
+#define Z .850650808352039932
+
+static GLfloat vdata[12][3] = {
+ {-X, 0.0, Z}, {X, 0.0, Z}, {-X, 0.0, -Z}, {X, 0.0, -Z},
+ {0.0, Z, X}, {0.0, Z, -X}, {0.0, -Z, X}, {0.0, -Z, -X},
+ {Z, X, 0.0}, {-Z, X, 0.0}, {Z, -X, 0.0}, {-Z, -X, 0.0}
+};
+
+static GLint tindices[20][3] = {
+ {0,4,1}, {0,9,4}, {9,5,4}, {4,5,8}, {4,8,1},
+ {8,10,1}, {8,3,10}, {5,3,8}, {5,2,3}, {2,7,3},
+ {7,10,3}, {7,6,10}, {7,11,6}, {11,0,6}, {0,1,6},
+ {6,1,10}, {9,0,11}, {9,11,2}, {9,2,5}, {7,2,11} };
+//--------------------------------------------------------------------------------
+
+IcoSphere::IcoSphere(unsigned int levels)
+{
+ // init with an icosahedron
+ for (int i = 0; i < 12; i++)
+ mVertices.push_back(Map<Vector3f>(vdata[i]));
+ mIndices.push_back(new std::vector<int>);
+ std::vector<int>& indices = *mIndices.back();
+ for (int i = 0; i < 20; i++)
+ {
+ for (int k = 0; k < 3; k++)
+ indices.push_back(tindices[i][k]);
+ }
+ mListIds.push_back(0);
+
+ while(mIndices.size()<levels)
+ _subdivide();
+}
+
+const std::vector<int>& IcoSphere::indices(int level) const
+{
+ while (level>=int(mIndices.size()))
+ const_cast<IcoSphere*>(this)->_subdivide();
+ return *mIndices[level];
+}
+
+void IcoSphere::_subdivide(void)
+{
+ typedef unsigned long long Key;
+ std::map<Key,int> edgeMap;
+ const std::vector<int>& indices = *mIndices.back();
+ mIndices.push_back(new std::vector<int>);
+ std::vector<int>& refinedIndices = *mIndices.back();
+ int end = indices.size();
+ for (int i=0; i<end; i+=3)
+ {
+ int ids0[3], // indices of outer vertices
+ ids1[3]; // indices of edge vertices
+ for (int k=0; k<3; ++k)
+ {
+ int k1 = (k+1)%3;
+ int e0 = indices[i+k];
+ int e1 = indices[i+k1];
+ ids0[k] = e0;
+ if (e1>e0)
+ std::swap(e0,e1);
+ Key edgeKey = Key(e0) | (Key(e1)<<32);
+ std::map<Key,int>::iterator it = edgeMap.find(edgeKey);
+ if (it==edgeMap.end())
+ {
+ ids1[k] = mVertices.size();
+ edgeMap[edgeKey] = ids1[k];
+ mVertices.push_back( (mVertices[e0]+mVertices[e1]).normalized() );
+ }
+ else
+ ids1[k] = it->second;
+ }
+ refinedIndices.push_back(ids0[0]); refinedIndices.push_back(ids1[0]); refinedIndices.push_back(ids1[2]);
+ refinedIndices.push_back(ids0[1]); refinedIndices.push_back(ids1[1]); refinedIndices.push_back(ids1[0]);
+ refinedIndices.push_back(ids0[2]); refinedIndices.push_back(ids1[2]); refinedIndices.push_back(ids1[1]);
+ refinedIndices.push_back(ids1[0]); refinedIndices.push_back(ids1[1]); refinedIndices.push_back(ids1[2]);
+ }
+ mListIds.push_back(0);
+}
+
+void IcoSphere::draw(int level)
+{
+ while (level>=int(mIndices.size()))
+ const_cast<IcoSphere*>(this)->_subdivide();
+ if (mListIds[level]==0)
+ {
+ mListIds[level] = glGenLists(1);
+ glNewList(mListIds[level], GL_COMPILE);
+ glVertexPointer(3, GL_FLOAT, 0, mVertices[0].data());
+ glNormalPointer(GL_FLOAT, 0, mVertices[0].data());
+ glEnableClientState(GL_VERTEX_ARRAY);
+ glEnableClientState(GL_NORMAL_ARRAY);
+ glDrawElements(GL_TRIANGLES, mIndices[level]->size(), GL_UNSIGNED_INT, &(mIndices[level]->at(0)));
+ glDisableClientState(GL_VERTEX_ARRAY);
+ glDisableClientState(GL_NORMAL_ARRAY);
+ glEndList();
+ }
+ glCallList(mListIds[level]);
+}
+
+
diff --git a/demos/opengl/icosphere.h b/demos/opengl/icosphere.h
new file mode 100644
index 000000000..b0210edc5
--- /dev/null
+++ b/demos/opengl/icosphere.h
@@ -0,0 +1,30 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra.
+//
+// Copyright (C) 2008 Gael Guennebaud <gael.guennebaud@inria.fr>
+//
+// This Source Code Form is subject to the terms of the Mozilla
+// Public License v. 2.0. If a copy of the MPL was not distributed
+// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+#ifndef EIGEN_ICOSPHERE_H
+#define EIGEN_ICOSPHERE_H
+
+#include <Eigen/Core>
+#include <vector>
+
+class IcoSphere
+{
+ public:
+ IcoSphere(unsigned int levels=1);
+ const std::vector<Eigen::Vector3f>& vertices() const { return mVertices; }
+ const std::vector<int>& indices(int level) const;
+ void draw(int level);
+ protected:
+ void _subdivide();
+ std::vector<Eigen::Vector3f> mVertices;
+ std::vector<std::vector<int>*> mIndices;
+ std::vector<int> mListIds;
+};
+
+#endif // EIGEN_ICOSPHERE_H
diff --git a/demos/opengl/quaternion_demo.cpp b/demos/opengl/quaternion_demo.cpp
new file mode 100644
index 000000000..04165619b
--- /dev/null
+++ b/demos/opengl/quaternion_demo.cpp
@@ -0,0 +1,656 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra.
+//
+// Copyright (C) 2008 Gael Guennebaud <gael.guennebaud@inria.fr>
+//
+// This Source Code Form is subject to the terms of the Mozilla
+// Public License v. 2.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 "quaternion_demo.h"
+#include "icosphere.h"
+
+#include <Eigen/Geometry>
+#include <Eigen/QR>
+#include <Eigen/LU>
+
+#include <iostream>
+#include <QEvent>
+#include <QMouseEvent>
+#include <QInputDialog>
+#include <QGridLayout>
+#include <QButtonGroup>
+#include <QRadioButton>
+#include <QDockWidget>
+#include <QPushButton>
+#include <QGroupBox>
+
+using namespace Eigen;
+
+class FancySpheres
+{
+ public:
+ EIGEN_MAKE_ALIGNED_OPERATOR_NEW
+
+ FancySpheres()
+ {
+ const int levels = 4;
+ const float scale = 0.33;
+ float radius = 100;
+ std::vector<int> parents;
+
+ // leval 0
+ mCenters.push_back(Vector3f::Zero());
+ parents.push_back(-1);
+ mRadii.push_back(radius);
+
+ // generate level 1 using icosphere vertices
+ radius *= 0.45;
+ {
+ float dist = mRadii[0]*0.9;
+ for (int i=0; i<12; ++i)
+ {
+ mCenters.push_back(mIcoSphere.vertices()[i] * dist);
+ mRadii.push_back(radius);
+ parents.push_back(0);
+ }
+ }
+
+ static const float angles [10] = {
+ 0, 0,
+ M_PI, 0.*M_PI,
+ M_PI, 0.5*M_PI,
+ M_PI, 1.*M_PI,
+ M_PI, 1.5*M_PI
+ };
+
+ // generate other levels
+ int start = 1;
+ for (int l=1; l<levels; l++)
+ {
+ radius *= scale;
+ int end = mCenters.size();
+ for (int i=start; i<end; ++i)
+ {
+ Vector3f c = mCenters[i];
+ Vector3f ax0 = (c - mCenters[parents[i]]).normalized();
+ Vector3f ax1 = ax0.unitOrthogonal();
+ Quaternionf q;
+ q.setFromTwoVectors(Vector3f::UnitZ(), ax0);
+ Affine3f t = Translation3f(c) * q * Scaling(mRadii[i]+radius);
+ for (int j=0; j<5; ++j)
+ {
+ Vector3f newC = c + ( (AngleAxisf(angles[j*2+1], ax0)
+ * AngleAxisf(angles[j*2+0] * (l==1 ? 0.35 : 0.5), ax1)) * ax0)
+ * (mRadii[i] + radius*0.8);
+ mCenters.push_back(newC);
+ mRadii.push_back(radius);
+ parents.push_back(i);
+ }
+ }
+ start = end;
+ }
+ }
+
+ void draw()
+ {
+ int end = mCenters.size();
+ glEnable(GL_NORMALIZE);
+ for (int i=0; i<end; ++i)
+ {
+ Affine3f t = Translation3f(mCenters[i]) * Scaling(mRadii[i]);
+ gpu.pushMatrix(GL_MODELVIEW);
+ gpu.multMatrix(t.matrix(),GL_MODELVIEW);
+ mIcoSphere.draw(2);
+ gpu.popMatrix(GL_MODELVIEW);
+ }
+ glDisable(GL_NORMALIZE);
+ }
+ protected:
+ std::vector<Vector3f> mCenters;
+ std::vector<float> mRadii;
+ IcoSphere mIcoSphere;
+};
+
+
+// generic linear interpolation method
+template<typename T> T lerp(float t, const T& a, const T& b)
+{
+ return a*(1-t) + b*t;
+}
+
+// quaternion slerp
+template<> Quaternionf lerp(float t, const Quaternionf& a, const Quaternionf& b)
+{ return a.slerp(t,b); }
+
+// linear interpolation of a frame using the type OrientationType
+// to perform the interpolation of the orientations
+template<typename OrientationType>
+inline static Frame lerpFrame(float alpha, const Frame& a, const Frame& b)
+{
+ return Frame(lerp(alpha,a.position,b.position),
+ Quaternionf(lerp(alpha,OrientationType(a.orientation),OrientationType(b.orientation))));
+}
+
+template<typename _Scalar> class EulerAngles
+{
+public:
+ enum { Dim = 3 };
+ typedef _Scalar Scalar;
+ typedef Matrix<Scalar,3,3> Matrix3;
+ typedef Matrix<Scalar,3,1> Vector3;
+ typedef Quaternion<Scalar> QuaternionType;
+
+protected:
+
+ Vector3 m_angles;
+
+public:
+
+ EulerAngles() {}
+ inline EulerAngles(Scalar a0, Scalar a1, Scalar a2) : m_angles(a0, a1, a2) {}
+ inline EulerAngles(const QuaternionType& q) { *this = q; }
+
+ const Vector3& coeffs() const { return m_angles; }
+ Vector3& coeffs() { return m_angles; }
+
+ EulerAngles& operator=(const QuaternionType& q)
+ {
+ Matrix3 m = q.toRotationMatrix();
+ return *this = m;
+ }
+
+ EulerAngles& operator=(const Matrix3& m)
+ {
+ // mat = cy*cz -cy*sz sy
+ // cz*sx*sy+cx*sz cx*cz-sx*sy*sz -cy*sx
+ // -cx*cz*sy+sx*sz cz*sx+cx*sy*sz cx*cy
+ m_angles.coeffRef(1) = std::asin(m.coeff(0,2));
+ m_angles.coeffRef(0) = std::atan2(-m.coeff(1,2),m.coeff(2,2));
+ m_angles.coeffRef(2) = std::atan2(-m.coeff(0,1),m.coeff(0,0));
+ return *this;
+ }
+
+ Matrix3 toRotationMatrix(void) const
+ {
+ Vector3 c = m_angles.array().cos();
+ Vector3 s = m_angles.array().sin();
+ Matrix3 res;
+ res << c.y()*c.z(), -c.y()*s.z(), s.y(),
+ c.z()*s.x()*s.y()+c.x()*s.z(), c.x()*c.z()-s.x()*s.y()*s.z(), -c.y()*s.x(),
+ -c.x()*c.z()*s.y()+s.x()*s.z(), c.z()*s.x()+c.x()*s.y()*s.z(), c.x()*c.y();
+ return res;
+ }
+
+ operator QuaternionType() { return QuaternionType(toRotationMatrix()); }
+};
+
+// Euler angles slerp
+template<> EulerAngles<float> lerp(float t, const EulerAngles<float>& a, const EulerAngles<float>& b)
+{
+ EulerAngles<float> res;
+ res.coeffs() = lerp(t, a.coeffs(), b.coeffs());
+ return res;
+}
+
+
+RenderingWidget::RenderingWidget()
+{
+ mAnimate = false;
+ mCurrentTrackingMode = TM_NO_TRACK;
+ mNavMode = NavTurnAround;
+ mLerpMode = LerpQuaternion;
+ mRotationMode = RotationStable;
+ mTrackball.setCamera(&mCamera);
+
+ // required to capture key press events
+ setFocusPolicy(Qt::ClickFocus);
+}
+
+void RenderingWidget::grabFrame(void)
+{
+ // ask user for a time
+ bool ok = false;
+ double t = 0;
+ if (!m_timeline.empty())
+ t = (--m_timeline.end())->first + 1.;
+ t = QInputDialog::getDouble(this, "Eigen's RenderingWidget", "time value: ",
+ t, 0, 1e3, 1, &ok);
+ if (ok)
+ {
+ Frame aux;
+ aux.orientation = mCamera.viewMatrix().linear();
+ aux.position = mCamera.viewMatrix().translation();
+ m_timeline[t] = aux;
+ }
+}
+
+void RenderingWidget::drawScene()
+{
+ static FancySpheres sFancySpheres;
+ float length = 50;
+ gpu.drawVector(Vector3f::Zero(), length*Vector3f::UnitX(), Color(1,0,0,1));
+ gpu.drawVector(Vector3f::Zero(), length*Vector3f::UnitY(), Color(0,1,0,1));
+ gpu.drawVector(Vector3f::Zero(), length*Vector3f::UnitZ(), Color(0,0,1,1));
+
+ // draw the fractal object
+ float sqrt3 = internal::sqrt(3.);
+ glLightfv(GL_LIGHT0, GL_AMBIENT, Vector4f(0.5,0.5,0.5,1).data());
+ glLightfv(GL_LIGHT0, GL_DIFFUSE, Vector4f(0.5,1,0.5,1).data());
+ glLightfv(GL_LIGHT0, GL_SPECULAR, Vector4f(1,1,1,1).data());
+ glLightfv(GL_LIGHT0, GL_POSITION, Vector4f(-sqrt3,-sqrt3,sqrt3,0).data());
+
+ glLightfv(GL_LIGHT1, GL_AMBIENT, Vector4f(0,0,0,1).data());
+ glLightfv(GL_LIGHT1, GL_DIFFUSE, Vector4f(1,0.5,0.5,1).data());
+ glLightfv(GL_LIGHT1, GL_SPECULAR, Vector4f(1,1,1,1).data());
+ glLightfv(GL_LIGHT1, GL_POSITION, Vector4f(-sqrt3,sqrt3,-sqrt3,0).data());
+
+ glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT, Vector4f(0.7, 0.7, 0.7, 1).data());
+ glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, Vector4f(0.8, 0.75, 0.6, 1).data());
+ glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, Vector4f(1, 1, 1, 1).data());
+ glMaterialf(GL_FRONT_AND_BACK, GL_SHININESS, 64);
+
+ glEnable(GL_LIGHTING);
+ glEnable(GL_LIGHT0);
+ glEnable(GL_LIGHT1);
+
+ sFancySpheres.draw();
+ glVertexPointer(3, GL_FLOAT, 0, mVertices[0].data());
+ glNormalPointer(GL_FLOAT, 0, mNormals[0].data());
+ glEnableClientState(GL_VERTEX_ARRAY);
+ glEnableClientState(GL_NORMAL_ARRAY);
+ glDrawArrays(GL_TRIANGLES, 0, mVertices.size());
+ glDisableClientState(GL_VERTEX_ARRAY);
+ glDisableClientState(GL_NORMAL_ARRAY);
+
+ glDisable(GL_LIGHTING);
+}
+
+void RenderingWidget::animate()
+{
+ m_alpha += double(m_timer.interval()) * 1e-3;
+
+ TimeLine::const_iterator hi = m_timeline.upper_bound(m_alpha);
+ TimeLine::const_iterator lo = hi;
+ --lo;
+
+ Frame currentFrame;
+
+ if(hi==m_timeline.end())
+ {
+ // end
+ currentFrame = lo->second;
+ stopAnimation();
+ }
+ else if(hi==m_timeline.begin())
+ {
+ // start
+ currentFrame = hi->second;
+ }
+ else
+ {
+ float s = (m_alpha - lo->first)/(hi->first - lo->first);
+ if (mLerpMode==LerpEulerAngles)
+ currentFrame = ::lerpFrame<EulerAngles<float> >(s, lo->second, hi->second);
+ else if (mLerpMode==LerpQuaternion)
+ currentFrame = ::lerpFrame<Eigen::Quaternionf>(s, lo->second, hi->second);
+ else
+ {
+ std::cerr << "Invalid rotation interpolation mode (abort)\n";
+ exit(2);
+ }
+ currentFrame.orientation.coeffs().normalize();
+ }
+
+ currentFrame.orientation = currentFrame.orientation.inverse();
+ currentFrame.position = - (currentFrame.orientation * currentFrame.position);
+ mCamera.setFrame(currentFrame);
+
+ updateGL();
+}
+
+void RenderingWidget::keyPressEvent(QKeyEvent * e)
+{
+ switch(e->key())
+ {
+ case Qt::Key_Up:
+ mCamera.zoom(2);
+ break;
+ case Qt::Key_Down:
+ mCamera.zoom(-2);
+ break;
+ // add a frame
+ case Qt::Key_G:
+ grabFrame();
+ break;
+ // clear the time line
+ case Qt::Key_C:
+ m_timeline.clear();
+ break;
+ // move the camera to initial pos
+ case Qt::Key_R:
+ resetCamera();
+ break;
+ // start/stop the animation
+ case Qt::Key_A:
+ if (mAnimate)
+ {
+ stopAnimation();
+ }
+ else
+ {
+ m_alpha = 0;
+ connect(&m_timer, SIGNAL(timeout()), this, SLOT(animate()));
+ m_timer.start(1000/30);
+ mAnimate = true;
+ }
+ break;
+ default:
+ break;
+ }
+
+ updateGL();
+}
+
+void RenderingWidget::stopAnimation()
+{
+ disconnect(&m_timer, SIGNAL(timeout()), this, SLOT(animate()));
+ m_timer.stop();
+ mAnimate = false;
+ m_alpha = 0;
+}
+
+void RenderingWidget::mousePressEvent(QMouseEvent* e)
+{
+ mMouseCoords = Vector2i(e->pos().x(), e->pos().y());
+ bool fly = (mNavMode==NavFly) || (e->modifiers()&Qt::ControlModifier);
+ switch(e->button())
+ {
+ case Qt::LeftButton:
+ if(fly)
+ {
+ mCurrentTrackingMode = TM_LOCAL_ROTATE;
+ mTrackball.start(Trackball::Local);
+ }
+ else
+ {
+ mCurrentTrackingMode = TM_ROTATE_AROUND;
+ mTrackball.start(Trackball::Around);
+ }
+ mTrackball.track(mMouseCoords);
+ break;
+ case Qt::MidButton:
+ if(fly)
+ mCurrentTrackingMode = TM_FLY_Z;
+ else
+ mCurrentTrackingMode = TM_ZOOM;
+ break;
+ case Qt::RightButton:
+ mCurrentTrackingMode = TM_FLY_PAN;
+ break;
+ default:
+ break;
+ }
+}
+void RenderingWidget::mouseReleaseEvent(QMouseEvent*)
+{
+ mCurrentTrackingMode = TM_NO_TRACK;
+ updateGL();
+}
+
+void RenderingWidget::mouseMoveEvent(QMouseEvent* e)
+{
+ // tracking
+ if(mCurrentTrackingMode != TM_NO_TRACK)
+ {
+ float dx = float(e->x() - mMouseCoords.x()) / float(mCamera.vpWidth());
+ float dy = - float(e->y() - mMouseCoords.y()) / float(mCamera.vpHeight());
+
+ // speedup the transformations
+ if(e->modifiers() & Qt::ShiftModifier)
+ {
+ dx *= 10.;
+ dy *= 10.;
+ }
+
+ switch(mCurrentTrackingMode)
+ {
+ case TM_ROTATE_AROUND:
+ case TM_LOCAL_ROTATE:
+ if (mRotationMode==RotationStable)
+ {
+ // use the stable trackball implementation mapping
+ // the 2D coordinates to 3D points on a sphere.
+ mTrackball.track(Vector2i(e->pos().x(), e->pos().y()));
+ }
+ else
+ {
+ // standard approach mapping the x and y displacements as rotations
+ // around the camera's X and Y axes.
+ Quaternionf q = AngleAxisf( dx*M_PI, Vector3f::UnitY())
+ * AngleAxisf(-dy*M_PI, Vector3f::UnitX());
+ if (mCurrentTrackingMode==TM_LOCAL_ROTATE)
+ mCamera.localRotate(q);
+ else
+ mCamera.rotateAroundTarget(q);
+ }
+ break;
+ case TM_ZOOM :
+ mCamera.zoom(dy*100);
+ break;
+ case TM_FLY_Z :
+ mCamera.localTranslate(Vector3f(0, 0, -dy*200));
+ break;
+ case TM_FLY_PAN :
+ mCamera.localTranslate(Vector3f(dx*200, dy*200, 0));
+ break;
+ default:
+ break;
+ }
+
+ updateGL();
+ }
+
+ mMouseCoords = Vector2i(e->pos().x(), e->pos().y());
+}
+
+void RenderingWidget::paintGL()
+{
+ glEnable(GL_DEPTH_TEST);
+ glDisable(GL_CULL_FACE);
+ glPolygonMode(GL_FRONT_AND_BACK,GL_FILL);
+ glDisable(GL_COLOR_MATERIAL);
+ glDisable(GL_BLEND);
+ glDisable(GL_ALPHA_TEST);
+ glDisable(GL_TEXTURE_1D);
+ glDisable(GL_TEXTURE_2D);
+ glDisable(GL_TEXTURE_3D);
+
+ // Clear buffers
+ glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
+
+ mCamera.activateGL();
+
+ drawScene();
+}
+
+void RenderingWidget::initializeGL()
+{
+ glClearColor(1., 1., 1., 0.);
+ glLightModeli(GL_LIGHT_MODEL_LOCAL_VIEWER, 1);
+ glDepthMask(GL_TRUE);
+ glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
+
+ mCamera.setPosition(Vector3f(-200, -200, -200));
+ mCamera.setTarget(Vector3f(0, 0, 0));
+ mInitFrame.orientation = mCamera.orientation().inverse();
+ mInitFrame.position = mCamera.viewMatrix().translation();
+}
+
+void RenderingWidget::resizeGL(int width, int height)
+{
+ mCamera.setViewport(width,height);
+}
+
+void RenderingWidget::setNavMode(int m)
+{
+ mNavMode = NavMode(m);
+}
+
+void RenderingWidget::setLerpMode(int m)
+{
+ mLerpMode = LerpMode(m);
+}
+
+void RenderingWidget::setRotationMode(int m)
+{
+ mRotationMode = RotationMode(m);
+}
+
+void RenderingWidget::resetCamera()
+{
+ if (mAnimate)
+ stopAnimation();
+ m_timeline.clear();
+ Frame aux0 = mCamera.frame();
+ aux0.orientation = aux0.orientation.inverse();
+ aux0.position = mCamera.viewMatrix().translation();
+ m_timeline[0] = aux0;
+
+ Vector3f currentTarget = mCamera.target();
+ mCamera.setTarget(Vector3f::Zero());
+
+ // compute the rotation duration to move the camera to the target
+ Frame aux1 = mCamera.frame();
+ aux1.orientation = aux1.orientation.inverse();
+ aux1.position = mCamera.viewMatrix().translation();
+ float duration = aux0.orientation.angularDistance(aux1.orientation) * 0.9;
+ if (duration<0.1) duration = 0.1;
+
+ // put the camera at that time step:
+ aux1 = aux0.lerp(duration/2,mInitFrame);
+ // and make it look at the target again
+ aux1.orientation = aux1.orientation.inverse();
+ aux1.position = - (aux1.orientation * aux1.position);
+ mCamera.setFrame(aux1);
+ mCamera.setTarget(Vector3f::Zero());
+
+ // add this camera keyframe
+ aux1.orientation = aux1.orientation.inverse();
+ aux1.position = mCamera.viewMatrix().translation();
+ m_timeline[duration] = aux1;
+
+ m_timeline[2] = mInitFrame;
+ m_alpha = 0;
+ animate();
+ connect(&m_timer, SIGNAL(timeout()), this, SLOT(animate()));
+ m_timer.start(1000/30);
+ mAnimate = true;
+}
+
+QWidget* RenderingWidget::createNavigationControlWidget()
+{
+ QWidget* panel = new QWidget();
+ QVBoxLayout* layout = new QVBoxLayout();
+
+ {
+ QPushButton* but = new QPushButton("reset");
+ but->setToolTip("move the camera to initial position (with animation)");
+ layout->addWidget(but);
+ connect(but, SIGNAL(clicked()), this, SLOT(resetCamera()));
+ }
+ {
+ // navigation mode
+ QGroupBox* box = new QGroupBox("navigation mode");
+ QVBoxLayout* boxLayout = new QVBoxLayout;
+ QButtonGroup* group = new QButtonGroup(panel);
+ QRadioButton* but;
+ but = new QRadioButton("turn around");
+ but->setToolTip("look around an object");
+ group->addButton(but, NavTurnAround);
+ boxLayout->addWidget(but);
+ but = new QRadioButton("fly");
+ but->setToolTip("free navigation like a spaceship\n(this mode can also be enabled pressing the \"shift\" key)");
+ group->addButton(but, NavFly);
+ boxLayout->addWidget(but);
+ group->button(mNavMode)->setChecked(true);
+ connect(group, SIGNAL(buttonClicked(int)), this, SLOT(setNavMode(int)));
+ box->setLayout(boxLayout);
+ layout->addWidget(box);
+ }
+ {
+ // track ball, rotation mode
+ QGroupBox* box = new QGroupBox("rotation mode");
+ QVBoxLayout* boxLayout = new QVBoxLayout;
+ QButtonGroup* group = new QButtonGroup(panel);
+ QRadioButton* but;
+ but = new QRadioButton("stable trackball");
+ group->addButton(but, RotationStable);
+ boxLayout->addWidget(but);
+ but->setToolTip("use the stable trackball implementation mapping\nthe 2D coordinates to 3D points on a sphere");
+ but = new QRadioButton("standard rotation");
+ group->addButton(but, RotationStandard);
+ boxLayout->addWidget(but);
+ but->setToolTip("standard approach mapping the x and y displacements\nas rotations around the camera's X and Y axes");
+ group->button(mRotationMode)->setChecked(true);
+ connect(group, SIGNAL(buttonClicked(int)), this, SLOT(setRotationMode(int)));
+ box->setLayout(boxLayout);
+ layout->addWidget(box);
+ }
+ {
+ // interpolation mode
+ QGroupBox* box = new QGroupBox("spherical interpolation");
+ QVBoxLayout* boxLayout = new QVBoxLayout;
+ QButtonGroup* group = new QButtonGroup(panel);
+ QRadioButton* but;
+ but = new QRadioButton("quaternion slerp");
+ group->addButton(but, LerpQuaternion);
+ boxLayout->addWidget(but);
+ but->setToolTip("use quaternion spherical interpolation\nto interpolate orientations");
+ but = new QRadioButton("euler angles");
+ group->addButton(but, LerpEulerAngles);
+ boxLayout->addWidget(but);
+ but->setToolTip("use Euler angles to interpolate orientations");
+ group->button(mNavMode)->setChecked(true);
+ connect(group, SIGNAL(buttonClicked(int)), this, SLOT(setLerpMode(int)));
+ box->setLayout(boxLayout);
+ layout->addWidget(box);
+ }
+ layout->addItem(new QSpacerItem(0,0,QSizePolicy::Minimum,QSizePolicy::Expanding));
+ panel->setLayout(layout);
+ return panel;
+}
+
+QuaternionDemo::QuaternionDemo()
+{
+ mRenderingWidget = new RenderingWidget();
+ setCentralWidget(mRenderingWidget);
+
+ QDockWidget* panel = new QDockWidget("navigation", this);
+ panel->setAllowedAreas((QFlags<Qt::DockWidgetArea>)(Qt::RightDockWidgetArea | Qt::LeftDockWidgetArea));
+ addDockWidget(Qt::RightDockWidgetArea, panel);
+ panel->setWidget(mRenderingWidget->createNavigationControlWidget());
+}
+
+int main(int argc, char *argv[])
+{
+ std::cout << "Navigation:\n";
+ std::cout << " left button: rotate around the target\n";
+ std::cout << " middle button: zoom\n";
+ std::cout << " left button + ctrl quake rotate (rotate around camera position)\n";
+ std::cout << " middle button + ctrl walk (progress along camera's z direction)\n";
+ std::cout << " left button: pan (translate in the XY camera's plane)\n\n";
+ std::cout << "R : move the camera to initial position\n";
+ std::cout << "A : start/stop animation\n";
+ std::cout << "C : clear the animation\n";
+ std::cout << "G : add a key frame\n";
+
+ QApplication app(argc, argv);
+ QuaternionDemo demo;
+ demo.resize(600,500);
+ demo.show();
+ return app.exec();
+}
+
+#include "quaternion_demo.moc"
+
diff --git a/demos/opengl/quaternion_demo.h b/demos/opengl/quaternion_demo.h
new file mode 100644
index 000000000..dbff46c39
--- /dev/null
+++ b/demos/opengl/quaternion_demo.h
@@ -0,0 +1,114 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra.
+//
+// Copyright (C) 2008 Gael Guennebaud <gael.guennebaud@inria.fr>
+//
+// This Source Code Form is subject to the terms of the Mozilla
+// Public License v. 2.0. If a copy of the MPL was not distributed
+// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+#ifndef EIGEN_QUATERNION_DEMO_H
+#define EIGEN_QUATERNION_DEMO_H
+
+#include "gpuhelper.h"
+#include "camera.h"
+#include "trackball.h"
+#include <map>
+#include <QTimer>
+#include <QtGui/QApplication>
+#include <QtOpenGL/QGLWidget>
+#include <QtGui/QMainWindow>
+
+class RenderingWidget : public QGLWidget
+{
+ Q_OBJECT
+
+ typedef std::map<float,Frame> TimeLine;
+ TimeLine m_timeline;
+ Frame lerpFrame(float t);
+
+ Frame mInitFrame;
+ bool mAnimate;
+ float m_alpha;
+
+ enum TrackMode {
+ TM_NO_TRACK=0, TM_ROTATE_AROUND, TM_ZOOM,
+ TM_LOCAL_ROTATE, TM_FLY_Z, TM_FLY_PAN
+ };
+
+ enum NavMode {
+ NavTurnAround,
+ NavFly
+ };
+
+ enum LerpMode {
+ LerpQuaternion,
+ LerpEulerAngles
+ };
+
+ enum RotationMode {
+ RotationStable,
+ RotationStandard
+ };
+
+ Camera mCamera;
+ TrackMode mCurrentTrackingMode;
+ NavMode mNavMode;
+ LerpMode mLerpMode;
+ RotationMode mRotationMode;
+ Vector2i mMouseCoords;
+ Trackball mTrackball;
+
+ QTimer m_timer;
+
+ void setupCamera();
+
+ std::vector<Vector3f> mVertices;
+ std::vector<Vector3f> mNormals;
+ std::vector<int> mIndices;
+
+ protected slots:
+
+ virtual void animate(void);
+ virtual void drawScene(void);
+
+ virtual void grabFrame(void);
+ virtual void stopAnimation();
+
+ virtual void setNavMode(int);
+ virtual void setLerpMode(int);
+ virtual void setRotationMode(int);
+ virtual void resetCamera();
+
+ protected:
+
+ virtual void initializeGL();
+ virtual void resizeGL(int width, int height);
+ virtual void paintGL();
+
+ //--------------------------------------------------------------------------------
+ virtual void mousePressEvent(QMouseEvent * e);
+ virtual void mouseReleaseEvent(QMouseEvent * e);
+ virtual void mouseMoveEvent(QMouseEvent * e);
+ virtual void keyPressEvent(QKeyEvent * e);
+ //--------------------------------------------------------------------------------
+
+ public:
+ EIGEN_MAKE_ALIGNED_OPERATOR_NEW
+
+ RenderingWidget();
+ ~RenderingWidget() { }
+
+ QWidget* createNavigationControlWidget();
+};
+
+class QuaternionDemo : public QMainWindow
+{
+ Q_OBJECT
+ public:
+ QuaternionDemo();
+ protected:
+ RenderingWidget* mRenderingWidget;
+};
+
+#endif // EIGEN_QUATERNION_DEMO_H
diff --git a/demos/opengl/trackball.cpp b/demos/opengl/trackball.cpp
new file mode 100644
index 000000000..77ac790c8
--- /dev/null
+++ b/demos/opengl/trackball.cpp
@@ -0,0 +1,59 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra.
+//
+// Copyright (C) 2008 Gael Guennebaud <gael.guennebaud@inria.fr>
+//
+// This Source Code Form is subject to the terms of the Mozilla
+// Public License v. 2.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 "trackball.h"
+#include "camera.h"
+
+using namespace Eigen;
+
+void Trackball::track(const Vector2i& point2D)
+{
+ if (mpCamera==0)
+ return;
+ Vector3f newPoint3D;
+ bool newPointOk = mapToSphere(point2D, newPoint3D);
+
+ if (mLastPointOk && newPointOk)
+ {
+ Vector3f axis = mLastPoint3D.cross(newPoint3D).normalized();
+ float cos_angle = mLastPoint3D.dot(newPoint3D);
+ if ( internal::abs(cos_angle) < 1.0 )
+ {
+ float angle = 2. * acos(cos_angle);
+ if (mMode==Around)
+ mpCamera->rotateAroundTarget(Quaternionf(AngleAxisf(angle, axis)));
+ else
+ mpCamera->localRotate(Quaternionf(AngleAxisf(-angle, axis)));
+ }
+ }
+
+ mLastPoint3D = newPoint3D;
+ mLastPointOk = newPointOk;
+}
+
+bool Trackball::mapToSphere(const Vector2i& p2, Vector3f& v3)
+{
+ if ((p2.x() >= 0) && (p2.x() <= int(mpCamera->vpWidth())) &&
+ (p2.y() >= 0) && (p2.y() <= int(mpCamera->vpHeight())) )
+ {
+ double x = (double)(p2.x() - 0.5*mpCamera->vpWidth()) / (double)mpCamera->vpWidth();
+ double y = (double)(0.5*mpCamera->vpHeight() - p2.y()) / (double)mpCamera->vpHeight();
+ double sinx = sin(M_PI * x * 0.5);
+ double siny = sin(M_PI * y * 0.5);
+ double sinx2siny2 = sinx * sinx + siny * siny;
+
+ v3.x() = sinx;
+ v3.y() = siny;
+ v3.z() = sinx2siny2 < 1.0 ? sqrt(1.0 - sinx2siny2) : 0.0;
+
+ return true;
+ }
+ else
+ return false;
+}
diff --git a/demos/opengl/trackball.h b/demos/opengl/trackball.h
new file mode 100644
index 000000000..1ea842f11
--- /dev/null
+++ b/demos/opengl/trackball.h
@@ -0,0 +1,42 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra.
+//
+// Copyright (C) 2008 Gael Guennebaud <gael.guennebaud@inria.fr>
+//
+// This Source Code Form is subject to the terms of the Mozilla
+// Public License v. 2.0. If a copy of the MPL was not distributed
+// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+#ifndef EIGEN_TRACKBALL_H
+#define EIGEN_TRACKBALL_H
+
+#include <Eigen/Geometry>
+
+class Camera;
+
+class Trackball
+{
+ public:
+
+ enum Mode {Around, Local};
+
+ Trackball() : mpCamera(0) {}
+
+ void start(Mode m = Around) { mMode = m; mLastPointOk = false; }
+
+ void setCamera(Camera* pCam) { mpCamera = pCam; }
+
+ void track(const Eigen::Vector2i& newPoint2D);
+
+ protected:
+
+ bool mapToSphere( const Eigen::Vector2i& p2, Eigen::Vector3f& v3);
+
+ Camera* mpCamera;
+ Eigen::Vector3f mLastPoint3D;
+ Mode mMode;
+ bool mLastPointOk;
+
+};
+
+#endif // EIGEN_TRACKBALL_H
diff --git a/doc/A05_PortingFrom2To3.dox b/doc/A05_PortingFrom2To3.dox
new file mode 100644
index 000000000..10ce96870
--- /dev/null
+++ b/doc/A05_PortingFrom2To3.dox
@@ -0,0 +1,319 @@
+namespace Eigen {
+
+/** \page Eigen2ToEigen3 Porting from Eigen2 to Eigen3
+
+This page lists the most important API changes between Eigen2 and Eigen3,
+and gives tips to help porting your application from Eigen2 to Eigen3.
+
+\b Table \b of \b contents
+ - \ref CompatibilitySupport
+ - \ref Using
+ - \ref ComplexDot
+ - \ref VectorBlocks
+ - \ref Corners
+ - \ref CoefficientWiseOperations
+ - \ref PartAndExtract
+ - \ref TriangularSolveInPlace
+ - \ref Decompositions
+ - \ref LinearSolvers
+ - \ref GeometryModule
+ - \ref Transform
+ - \ref LazyVsNoalias
+ - \ref AlignMacros
+ - \ref AlignedMap
+ - \ref StdContainers
+ - \ref eiPrefix
+
+\section CompatibilitySupport Eigen2 compatibility support
+
+In order to ease the switch from Eigen2 to Eigen3, Eigen3 features \ref Eigen2SupportModes "Eigen2 support modes".
+
+The quick way to enable this is to define the \c EIGEN2_SUPPORT preprocessor token \b before including any Eigen header (typically it should be set in your project options).
+
+A more powerful, \em staged migration path is also provided, which may be useful to migrate larger projects from Eigen2 to Eigen3. This is explained in the \ref Eigen2SupportModes "Eigen 2 support modes" page.
+
+\section Using The USING_PART_OF_NAMESPACE_EIGEN macro
+
+The USING_PART_OF_NAMESPACE_EIGEN macro has been removed. In Eigen 3, just do:
+\code
+using namespace Eigen;
+\endcode
+
+\section ComplexDot Dot products over complex numbers
+
+This is the single trickiest change between Eigen 2 and Eigen 3. It only affects code using \c std::complex numbers as scalar type.
+
+Eigen 2's dot product was linear in the first variable. Eigen 3's dot product is linear in the second variable. In other words, the Eigen 2 code \code x.dot(y) \endcode is equivalent to the Eigen 3 code \code y.dot(x) \endcode In yet other words, dot products are complex-conjugated in Eigen 3 compared to Eigen 2. The switch to the new convention was commanded by common usage, especially with the notation \f$ x^Ty \f$ for dot products of column-vectors.
+
+\section VectorBlocks Vector blocks
+
+<table class="manual">
+<tr><th>Eigen 2</th><th>Eigen 3</th></th>
+<tr><td>\code
+vector.start(length)
+vector.start<length>()
+vector.end(length)
+vector.end<length>()
+\endcode</td><td>\code
+vector.head(length)
+vector.head<length>()
+vector.tail(length)
+vector.tail<length>()
+\endcode</td></tr>
+</table>
+
+
+\section Corners Matrix Corners
+
+<table class="manual">
+<tr><th>Eigen 2</th><th>Eigen 3</th></th>
+<tr><td>\code
+matrix.corner(TopLeft,r,c)
+matrix.corner(TopRight,r,c)
+matrix.corner(BottomLeft,r,c)
+matrix.corner(BottomRight,r,c)
+matrix.corner<r,c>(TopLeft)
+matrix.corner<r,c>(TopRight)
+matrix.corner<r,c>(BottomLeft)
+matrix.corner<r,c>(BottomRight)
+\endcode</td><td>\code
+matrix.topLeftCorner(r,c)
+matrix.topRightCorner(r,c)
+matrix.bottomLeftCorner(r,c)
+matrix.bottomRightCorner(r,c)
+matrix.topLeftCorner<r,c>()
+matrix.topRightCorner<r,c>()
+matrix.bottomLeftCorner<r,c>()
+matrix.bottomRightCorner<r,c>()
+\endcode</td>
+</tr>
+</table>
+
+Notice that Eigen3 also provides these new convenience methods: topRows(), bottomRows(), leftCols(), rightCols(). See in class DenseBase.
+
+\section CoefficientWiseOperations Coefficient wise operations
+
+In Eigen2, coefficient wise operations which have no proper mathematical definition (as a coefficient wise product)
+were achieved using the .cwise() prefix, e.g.:
+\code a.cwise() * b \endcode
+In Eigen3 this .cwise() prefix has been superseded by a new kind of matrix type called
+Array for which all operations are performed coefficient wise. You can easily view a matrix as an array and vice versa using
+the MatrixBase::array() and ArrayBase::matrix() functions respectively. Here is an example:
+\code
+Vector4f a, b, c;
+c = a.array() * b.array();
+\endcode
+Note that the .array() function is not at all a synonym of the deprecated .cwise() prefix.
+While the .cwise() prefix changed the behavior of the following operator, the array() function performs
+a permanent conversion to the array world. Therefore, for binary operations such as the coefficient wise product,
+both sides must be converted to an \em array as in the above example. On the other hand, when you
+concatenate multiple coefficient wise operations you only have to do the conversion once, e.g.:
+\code
+Vector4f a, b, c;
+c = a.array().abs().pow(3) * b.array().abs().sin();
+\endcode
+With Eigen2 you would have written:
+\code
+c = (a.cwise().abs().cwise().pow(3)).cwise() * (b.cwise().abs().cwise().sin());
+\endcode
+
+\section PartAndExtract Triangular and self-adjoint matrices
+
+In Eigen 2 you had to play with the part, extract, and marked functions to deal with triangular and selfadjoint matrices. In Eigen 3, all these functions have been removed in favor of the concept of \em views:
+
+<table class="manual">
+<tr><th>Eigen 2</th><th>Eigen 3</th></tr>
+<tr><td>\code
+A.part<UpperTriangular>();
+A.part<StrictlyLowerTriangular>(); \endcode</td>
+<td>\code
+A.triangularView<Upper>()
+A.triangularView<StrictlyLower>()\endcode</td></tr>
+<tr><td>\code
+A.extract<UpperTriangular>();
+A.extract<StrictlyLowerTriangular>();\endcode</td>
+<td>\code
+A.triangularView<Upper>()
+A.triangularView<StrictlyLower>()\endcode</td></tr>
+<tr><td>\code
+A.marked<UpperTriangular>();
+A.marked<StrictlyLowerTriangular>();\endcode</td>
+<td>\code
+A.triangularView<Upper>()
+A.triangularView<StrictlyLower>()\endcode</td></tr>
+<tr><td colspan="2"></td></tr>
+<tr><td>\code
+A.part<SelfAdfjoint|UpperTriangular>();
+A.extract<SelfAdfjoint|LowerTriangular>();\endcode</td>
+<td>\code
+A.selfadjointView<Upper>()
+A.selfadjointView<Lower>()\endcode</td></tr>
+<tr><td colspan="2"></td></tr>
+<tr><td>\code
+UpperTriangular
+LowerTriangular
+UnitUpperTriangular
+UnitLowerTriangular
+StrictlyUpperTriangular
+StrictlyLowerTriangular
+\endcode</td><td>\code
+Upper
+Lower
+UnitUpper
+UnitLower
+StrictlyUpper
+StrictlyLower
+\endcode</td>
+</tr>
+</table>
+
+\sa class TriangularView, class SelfAdjointView
+
+\section TriangularSolveInPlace Triangular in-place solving
+
+<table class="manual">
+<tr><th>Eigen 2</th><th>Eigen 3</th></tr>
+<tr><td>\code A.triangularSolveInPlace<XxxTriangular>(Y);\endcode</td><td>\code A.triangularView<Xxx>().solveInPlace(Y);\endcode</td></tr>
+</table>
+
+
+\section Decompositions Matrix decompositions
+
+Some of Eigen 2's matrix decompositions have been renamed in Eigen 3, while some others have been removed and are replaced by other decompositions in Eigen 3.
+
+<table class="manual">
+ <tr>
+ <th>Eigen 2</th>
+ <th>Eigen 3</th>
+ <th>Notes</th>
+ </tr>
+ <tr>
+ <td>LU</td>
+ <td>FullPivLU</td>
+ <td class="alt">See also the new PartialPivLU, it's much faster</td>
+ </tr>
+ <tr>
+ <td>QR</td>
+ <td>HouseholderQR</td>
+ <td class="alt">See also the new ColPivHouseholderQR, it's more reliable</td>
+ </tr>
+ <tr>
+ <td>SVD</td>
+ <td>JacobiSVD</td>
+ <td class="alt">We currently don't have a bidiagonalizing SVD; of course this is planned.</td>
+ </tr>
+ <tr>
+ <td>EigenSolver and friends</td>
+ <td>\code #include<Eigen/Eigenvalues> \endcode </td>
+ <td class="alt">Moved to separate module</td>
+ </tr>
+</table>
+
+\section LinearSolvers Linear solvers
+
+<table class="manual">
+<tr><th>Eigen 2</th><th>Eigen 3</th><th>Notes</th></tr>
+<tr><td>\code A.lu();\endcode</td>
+<td>\code A.fullPivLu();\endcode</td>
+<td class="alt">Now A.lu() returns a PartialPivLU</td></tr>
+<tr><td>\code A.lu().solve(B,&X);\endcode</td>
+<td>\code X = A.lu().solve(B);
+ X = A.fullPivLu().solve(B);\endcode</td>
+<td class="alt">The returned by value is fully optimized</td></tr>
+<tr><td>\code A.llt().solve(B,&X);\endcode</td>
+<td>\code X = A.llt().solve(B);
+ X = A.selfadjointView<Lower>.llt().solve(B);
+ X = A.selfadjointView<Upper>.llt().solve(B);\endcode</td>
+<td class="alt">The returned by value is fully optimized and \n
+the selfadjointView API allows you to select the \n
+triangular part to work on (default is lower part)</td></tr>
+<tr><td>\code A.llt().solveInPlace(B);\endcode</td>
+<td>\code B = A.llt().solve(B);
+ B = A.selfadjointView<Lower>.llt().solve(B);
+ B = A.selfadjointView<Upper>.llt().solve(B);\endcode</td>
+<td class="alt">In place solving</td></tr>
+<tr><td>\code A.ldlt().solve(B,&X);\endcode</td>
+<td>\code X = A.ldlt().solve(B);
+ X = A.selfadjointView<Lower>.ldlt().solve(B);
+ X = A.selfadjointView<Upper>.ldlt().solve(B);\endcode</td>
+<td class="alt">The returned by value is fully optimized and \n
+the selfadjointView API allows you to select the \n
+triangular part to work on</td></tr>
+</table>
+
+\section GeometryModule Changes in the Geometry module
+
+The Geometry module is the one that changed the most. If you rely heavily on it, it's probably a good idea to use the \ref Eigen2SupportModes "Eigen 2 support modes" to perform your migration.
+
+\section Transform The Transform class
+
+In Eigen 2, the Transform class didn't really know whether it was a projective or affine transformation. In Eigen 3, it takes a new \a Mode template parameter, which indicates whether it's \a Projective or \a Affine transform. There is no default value.
+
+The Transform3f (etc) typedefs are no more. In Eigen 3, the Transform typedefs explicitly refer to the \a Projective and \a Affine modes:
+
+<table class="manual">
+<tr><th>Eigen 2</th><th>Eigen 3</th><th>Notes</th></tr>
+<tr>
+ <td> Transform3f </td>
+ <td> Affine3f or Projective3f </td>
+ <td> Of course 3f is just an example here </td>
+</tr>
+</table>
+
+
+\section LazyVsNoalias Lazy evaluation and noalias
+
+In Eigen all operations are performed in a lazy fashion except the matrix products which are always evaluated into a temporary by default.
+In Eigen2, lazy evaluation could be enforced by tagging a product using the .lazy() function. However, in complex expressions it was not
+easy to determine where to put the lazy() function. In Eigen3, the lazy() feature has been superseded by the MatrixBase::noalias() function
+which can be used on the left hand side of an assignment when no aliasing can occur. Here is an example:
+\code
+MatrixXf a, b, c;
+...
+c.noalias() += 2 * a.transpose() * b;
+\endcode
+However, the noalias mechanism does not cover all the features of the old .lazy(). Indeed, in some extremely rare cases,
+it might be useful to explicit request for a lay product, i.e., for a product which will be evaluated one coefficient at once, on request,
+just like any other expressions. To this end you can use the MatrixBase::lazyProduct() function, however we strongly discourage you to
+use it unless you are sure of what you are doing, i.e., you have rigourosly measured a speed improvement.
+
+\section AlignMacros Alignment-related macros
+
+The EIGEN_ALIGN_128 macro has been renamed to EIGEN_ALIGN16. Don't be surprised, it's just that we switched to counting in bytes ;-)
+
+The EIGEN_DONT_ALIGN option still exists in Eigen 3, but it has a new cousin: EIGEN_DONT_ALIGN_STATICALLY. It allows to get rid of all static alignment issues while keeping alignment of dynamic-size heap-allocated arrays, thus keeping vectorization for dynamic-size objects.
+
+\section AlignedMap Aligned Map objects
+
+A common issue with Eigen 2 was that when mapping an array with Map, there was no way to tell Eigen that your array was aligned. There was a ForceAligned option but it didn't mean that; it was just confusing and has been removed.
+
+New in Eigen3 is the #Aligned option. See the documentation of class Map. Use it like this:
+\code
+Map<Vector4f, Aligned> myMappedVector(some_aligned_array);
+\endcode
+There also are related convenience static methods, which actually are the preferred way as they take care of such things as constness:
+\code
+result = Vector4f::MapAligned(some_aligned_array);
+\endcode
+
+\section StdContainers STL Containers
+
+In Eigen2, #include<Eigen/StdVector> tweaked std::vector to automatically align elements. The problem was that that was quite invasive. In Eigen3, we only override standard behavior if you use Eigen::aligned_allocator<T> as your allocator type. So for example, if you use std::vector<Matrix4f>, you need to do the following change (note that aligned_allocator is under namespace Eigen):
+
+<table class="manual">
+<tr><th>Eigen 2</th><th>Eigen 3</th></tr>
+<tr>
+ <td> \code std::vector<Matrix4f> \endcode </td>
+ <td> \code std::vector<Matrix4f, aligned_allocator<Matrix4f> > \endcode </td>
+</tr>
+</table>
+
+\section eiPrefix Internal ei_ prefix
+
+In Eigen2, global internal functions and structures were prefixed by \c ei_. In Eigen3, they all have been moved into the more explicit \c internal namespace. So, e.g., \c ei_sqrt(x) now becomes \c internal::sqrt(x). Of course it is not recommended to rely on Eigen's internal features.
+
+
+
+*/
+
+}
diff --git a/doc/A10_Eigen2SupportModes.dox b/doc/A10_Eigen2SupportModes.dox
new file mode 100644
index 000000000..c20b64eed
--- /dev/null
+++ b/doc/A10_Eigen2SupportModes.dox
@@ -0,0 +1,101 @@
+namespace Eigen {
+
+/** \page Eigen2SupportModes Eigen 2 support modes
+
+This page documents the Eigen2 support modes, a powerful tool to help migrating your project from Eigen 2 to Eigen 3.
+Don't miss our page on \ref Eigen2ToEigen3 "API changes" between Eigen 2 and Eigen 3.
+
+\b Table \b of \b contents
+ - \ref EIGEN2_SUPPORT_Macro
+ - \ref StagedMigrationPathOverview
+ - \ref Stage10
+ - \ref Stage20
+ - \ref Stage30
+ - \ref Stage40
+ - \ref FinallyDropAllEigen2Support
+ - \ref ABICompatibility
+
+\section EIGEN2_SUPPORT_Macro The quick way: define EIGEN2_SUPPORT
+
+By defining EIGEN2_SUPPORT before including any Eigen 3 header, you get back a large part of the Eigen 2 API, while keeping the Eigen 3 API and ABI unchanged.
+
+This defaults to the \ref Stage30 "stage 30" described below.
+
+The rest of this page describes an optional, more powerful \em staged migration path.
+
+\section StagedMigrationPathOverview Overview of the staged migration path
+
+The primary reason why EIGEN2_SUPPORT alone may not be enough to migrate a large project from Eigen 2 to Eigen 3 is that some of the Eigen 2 API is inherently incompatible with the Eigen 3 API. This happens when the same identifier is used in Eigen 2 and in Eigen 3 with different meanings. To help migrate projects that rely on such API, we provide a staged migration path allowing to perform the migration \em incrementally.
+
+It goes as follows:
+\li Step 0: start with a project using Eigen 2.
+\li Step 1: build your project against Eigen 3 with \ref Stage10 "Eigen 2 support stage 10". This mode enables maximum compatibility with the Eigen 2 API, with just a few exceptions.
+\li Step 2: build your project against Eigen 3 with \ref Stage20 "Eigen 2 support stage 20". This mode forces you to add eigen2_ prefixes to the Eigen2 identifiers that conflict with Eigen 3 API.
+\li Step 3: build your project against Eigen 3 with \ref Stage30 "Eigen 2 support stage 30". This mode enables the full Eigen 3 API.
+\li Step 4: build your project against Eigen 3 with \ref Stage40 "Eigen 2 support stage 40". This mode enables the full Eigen 3 strictness on matters, such as const-correctness, where Eigen 2 was looser.
+\li Step 5: build your project against Eigen 3 without any Eigen 2 support mode.
+
+\section Stage10 Stage 10: define EIGEN2_SUPPORT_STAGE10_FULL_EIGEN2_API
+
+Enable this mode by defining the EIGEN2_SUPPORT_STAGE10_FULL_EIGEN2_API preprocessor macro before including any Eigen 3 header.
+
+This mode maximizes support for the Eigen 2 API. As a result, it does not offer the full Eigen 3 API. Also, it doesn't offer quite 100% of the Eigen 2 API.
+
+The part of the Eigen 3 API that is not present in this mode, is Eigen 3's Geometry module. Indeed, this mode completely replaces it by a copy of Eigen 2's Geometry module.
+
+The parts of the API that are still not 100% Eigen 2 compatible in this mode are:
+\li Dot products over complex numbers. Eigen 2's dot product was linear in the first variable. Eigen 3's dot product is linear in the second variable. In other words, the Eigen 2 code \code x.dot(y) \endcode is equivalent to the Eigen 3 code \code y.dot(x) \endcode In yet other words, dot products are complex-conjugated in Eigen 3 compared to Eigen 2. The switch to the new convention was commanded by common usage, especially with the notation \f$ x^Ty \f$ for dot products of column-vectors.
+\li The Sparse module.
+\li Certain fine details of linear algebraic decompositions. For example, LDLT decomposition is now pivoting in Eigen 3 whereas it wasn't in Eigen 2, so code that was relying on its underlying matrix structure will break.
+\li Usage of Eigen types in STL containers, \ref Eigen2ToEigen3 "as explained on this page".
+
+\section Stage20 Stage 20: define EIGEN2_SUPPORT_STAGE20_RESOLVE_API_CONFLICTS
+
+Enable this mode by defining the EIGEN2_SUPPORT_STAGE10_FULL_EIGEN2_API preprocessor macro before including any Eigen 3 header.
+
+This mode removes the Eigen 2 API that is directly conflicting with Eigen 3 API. Instead, these bits of Eigen 2 API remain available with eigen2_ prefixes. The main examples of such API are:
+\li the whole Geometry module. For example, replace \c Quaternion by \c eigen2_Quaternion, replace \c Transform3f by \c eigen2_Transform3f, etc.
+\li the lu() method to obtain a LU decomposition. Replace by eigen2_lu().
+
+There is also one more eigen2_-prefixed identifier that you should know about, even though its use is not checked at compile time by this mode: the dot() method. As was discussed above, over complex numbers, its meaning is different between Eigen 2 and Eigen 3. You can use eigen2_dot() to get the Eigen 2 behavior.
+
+\section Stage30 Stage 30: define EIGEN2_SUPPORT_STAGE30_FULL_EIGEN3_API
+
+Enable this mode by defining the EIGEN2_SUPPORT_STAGE30_FULL_EIGEN3_API preprocessor macro before including any Eigen 3 header. Also, this mode is what you get by default when you just define EIGEN2_SUPPORT.
+
+This mode gives you the full unaltered Eigen 3 API, while still keeping as much support as possible for the Eigen 2 API.
+
+The eigen2_-prefixed identifiers are still available, but at this stage you should now replace them by Eigen 3 identifiers. Have a look at our page on \ref Eigen2ToEigen3 "API changes" between Eigen 2 and Eigen 3.
+
+\section Stage40 Stage 40: define EIGEN2_SUPPORT_STAGE40_FULL_EIGEN3_STRICTNESS
+
+Enable this mode by defining the EIGEN2_SUPPORT_STAGE40_FULL_EIGEN3_STRICTNESS preprocessor macro before including any Eigen 3 header.
+
+This mode tightens the last bits of strictness, especially const-correctness, that had to be loosened to support what Eigen 2 allowed. For example, this code compiled in Eigen 2:
+\code
+const float array[4];
+x = Map<Vector4f>(array);
+\endcode
+That allowed to circumvent constness. This is no longer allowed in Eigen 3. If you have to map const data in Eigen 3, map it as a const-qualified type. However, rather than explictly constructing Map objects, we strongly encourage you to use the static Map methods instead, as they take care of all of this for you:
+\code
+const float array[4];
+x = Vector4f::Map(array);
+\endcode
+This lets Eigen do the right thing for you and works equally well in Eigen 2 and in Eigen 3.
+
+\section FinallyDropAllEigen2Support Finally drop all Eigen 2 support
+
+Stage 40 is the first where it's "comfortable" to stay for a little longer period, since it preserves 100% Eigen 3 compatibility. However, we still encourage you to complete your migration as quickly as possible. While we do run the Eigen 2 test suite against Eigen 3's stage 10 support mode, we can't guarantee the same level of support and quality assurance for Eigen 2 support as we do for Eigen 3 itself, especially not in the long term. \ref Eigen2ToEigen3 "This page" describes a large part of the changes that you may need to perform.
+
+\section ABICompatibility What about ABI compatibility?
+
+It goes as follows:
+\li Stage 10 already is ABI compatible with Eigen 3 for the basic (Matrix, Array, SparseMatrix...) types. However, since this stage uses a copy of Eigen 2's Geometry module instead of Eigen 3's own Geometry module, the ABI in the Geometry module is not Eigen 3 compatible.
+\li Stage 20 removes the Eigen 3-incompatible Eigen 2 Geometry module (it remains available with eigen2_ prefix). So at this stage, all the identifiers that exist in Eigen 3 have the Eigen 3 ABI (and API).
+\li Stage 30 introduces the remaining Eigen 3 identifiers. So at this stage, you have the full Eigen 3 ABI.
+\li Stage 40 is no different than Stage 30 in these matters.
+
+
+*/
+
+}
diff --git a/doc/AsciiQuickReference.txt b/doc/AsciiQuickReference.txt
new file mode 100644
index 000000000..d2e973f5d
--- /dev/null
+++ b/doc/AsciiQuickReference.txt
@@ -0,0 +1,170 @@
+// A simple quickref for Eigen. Add anything that's missing.
+// Main author: Keir Mierle
+
+#include <Eigen/Core>
+#include <Eigen/Array>
+
+Matrix<double, 3, 3> A; // Fixed rows and cols. Same as Matrix3d.
+Matrix<double, 3, Dynamic> B; // Fixed rows, dynamic cols.
+Matrix<double, Dynamic, Dynamic> C; // Full dynamic. Same as MatrixXd.
+Matrix<double, 3, 3, RowMajor> E; // Row major; default is column-major.
+Matrix3f P, Q, R; // 3x3 float matrix.
+Vector3f x, y, z; // 3x1 float matrix.
+RowVector3f a, b, c; // 1x3 float matrix.
+double s;
+
+// Basic usage
+// Eigen // Matlab // comments
+x.size() // length(x) // vector size
+C.rows() // size(C)(1) // number of rows
+C.cols() // size(C)(2) // number of columns
+x(i) // x(i+1) // Matlab is 1-based
+C(i,j) // C(i+1,j+1) //
+
+A.resize(4, 4); // Runtime error if assertions are on.
+B.resize(4, 9); // Runtime error if assertions are on.
+A.resize(3, 3); // Ok; size didn't change.
+B.resize(3, 9); // Ok; only dynamic cols changed.
+
+A << 1, 2, 3, // Initialize A. The elements can also be
+ 4, 5, 6, // matrices, which are stacked along cols
+ 7, 8, 9; // and then the rows are stacked.
+B << A, A, A; // B is three horizontally stacked A's.
+A.fill(10); // Fill A with all 10's.
+A.setRandom(); // Fill A with uniform random numbers in (-1, 1).
+ // Requires #include <Eigen/Array>.
+A.setIdentity(); // Fill A with the identity.
+
+// Matrix slicing and blocks. All expressions listed here are read/write.
+// Templated size versions are faster. Note that Matlab is 1-based (a size N
+// vector is x(1)...x(N)).
+// Eigen // Matlab
+x.head(n) // x(1:n)
+x.head<n>() // x(1:n)
+x.tail(n) // N = rows(x); x(N - n: N)
+x.tail<n>() // N = rows(x); x(N - n: N)
+x.segment(i, n) // x(i+1 : i+n)
+x.segment<n>(i) // x(i+1 : i+n)
+P.block(i, j, rows, cols) // P(i+1 : i+rows, j+1 : j+cols)
+P.block<rows, cols>(i, j) // P(i+1 : i+rows, j+1 : j+cols)
+P.topLeftCorner(rows, cols) // P(1:rows, 1:cols)
+P.topRightCorner(rows, cols) // [m n]=size(P); P(1:rows, n-cols+1:n)
+P.bottomLeftCorner(rows, cols) // [m n]=size(P); P(m-rows+1:m, 1:cols)
+P.bottomRightCorner(rows, cols) // [m n]=size(P); P(m-rows+1:m, n-cols+1:n)
+P.topLeftCorner<rows,cols>() // P(1:rows, 1:cols)
+P.topRightCorner<rows,cols>() // [m n]=size(P); P(1:rows, n-cols+1:n)
+P.bottomLeftCorner<rows,cols>() // [m n]=size(P); P(m-rows+1:m, 1:cols)
+P.bottomRightCorner<rows,cols>() // [m n]=size(P); P(m-rows+1:m, n-cols+1:n)
+
+// Of particular note is Eigen's swap function which is highly optimized.
+// Eigen // Matlab
+R.row(i) = P.col(j); // R(i, :) = P(:, i)
+R.col(j1).swap(mat1.col(j2)); // R(:, [j1 j2]) = R(:, [j2, j1])
+
+// Views, transpose, etc; all read-write except for .adjoint().
+// Eigen // Matlab
+R.adjoint() // R'
+R.transpose() // R.' or conj(R')
+R.diagonal() // diag(R)
+x.asDiagonal() // diag(x)
+
+// All the same as Matlab, but matlab doesn't have *= style operators.
+// Matrix-vector. Matrix-matrix. Matrix-scalar.
+y = M*x; R = P*Q; R = P*s;
+a = b*M; R = P - Q; R = s*P;
+a *= M; R = P + Q; R = P/s;
+ R *= Q; R = s*P;
+ R += Q; R *= s;
+ R -= Q; R /= s;
+
+ // Vectorized operations on each element independently
+ // (most require #include <Eigen/Array>)
+// Eigen // Matlab
+R = P.cwiseProduct(Q); // R = P .* Q
+R = P.array() * s.array();// R = P .* s
+R = P.cwiseQuotient(Q); // R = P ./ Q
+R = P.array() / Q.array();// R = P ./ Q
+R = P.array() + s.array();// R = P + s
+R = P.array() - s.array();// R = P - s
+R.array() += s; // R = R + s
+R.array() -= s; // R = R - s
+R.array() < Q.array(); // R < Q
+R.array() <= Q.array(); // R <= Q
+R.cwiseInverse(); // 1 ./ P
+R.array().inverse(); // 1 ./ P
+R.array().sin() // sin(P)
+R.array().cos() // cos(P)
+R.array().pow(s) // P .^ s
+R.array().square() // P .^ 2
+R.array().cube() // P .^ 3
+R.cwiseSqrt() // sqrt(P)
+R.array().sqrt() // sqrt(P)
+R.array().exp() // exp(P)
+R.array().log() // log(P)
+R.cwiseMax(P) // max(R, P)
+R.array().max(P.array()) // max(R, P)
+R.cwiseMin(P) // min(R, P)
+R.array().min(P.array()) // min(R, P)
+R.cwiseAbs() // abs(P)
+R.array().abs() // abs(P)
+R.cwiseAbs2() // abs(P.^2)
+R.array().abs2() // abs(P.^2)
+(R.array() < s).select(P,Q); // (R < s ? P : Q)
+
+// Reductions.
+int r, c;
+// Eigen // Matlab
+R.minCoeff() // min(R(:))
+R.maxCoeff() // max(R(:))
+s = R.minCoeff(&r, &c) // [aa, bb] = min(R); [cc, dd] = min(aa);
+ // r = bb(dd); c = dd; s = cc
+s = R.maxCoeff(&r, &c) // [aa, bb] = max(R); [cc, dd] = max(aa);
+ // row = bb(dd); col = dd; s = cc
+R.sum() // sum(R(:))
+R.colwise.sum() // sum(R)
+R.rowwise.sum() // sum(R, 2) or sum(R')'
+R.prod() // prod(R(:))
+R.colwise.prod() // prod(R)
+R.rowwise.prod() // prod(R, 2) or prod(R')'
+R.trace() // trace(R)
+R.all() // all(R(:))
+R.colwise().all() // all(R)
+R.rowwise().all() // all(R, 2)
+R.any() // any(R(:))
+R.colwise().any() // any(R)
+R.rowwise().any() // any(R, 2)
+
+// Dot products, norms, etc.
+// Eigen // Matlab
+x.norm() // norm(x). Note that norm(R) doesn't work in Eigen.
+x.squaredNorm() // dot(x, x) Note the equivalence is not true for complex
+x.dot(y) // dot(x, y)
+x.cross(y) // cross(x, y) Requires #include <Eigen/Geometry>
+
+// Eigen can map existing memory into Eigen matrices.
+float array[3];
+Map<Vector3f>(array, 3).fill(10);
+int data[4] = 1, 2, 3, 4;
+Matrix2i mat2x2(data);
+MatrixXi mat2x2 = Map<Matrix2i>(data);
+MatrixXi mat2x2 = Map<MatrixXi>(data, 2, 2);
+
+// Solve Ax = b. Result stored in x. Matlab: x = A \ b.
+bool solved;
+solved = A.ldlt().solve(b, &x)); // A sym. p.s.d. #include <Eigen/Cholesky>
+solved = A.llt() .solve(b, &x)); // A sym. p.d. #include <Eigen/Cholesky>
+solved = A.lu() .solve(b, &x)); // Stable and fast. #include <Eigen/LU>
+solved = A.qr() .solve(b, &x)); // No pivoting. #include <Eigen/QR>
+solved = A.svd() .solve(b, &x)); // Stable, slowest. #include <Eigen/SVD>
+// .ldlt() -> .matrixL() and .matrixD()
+// .llt() -> .matrixL()
+// .lu() -> .matrixL() and .matrixU()
+// .qr() -> .matrixQ() and .matrixR()
+// .svd() -> .matrixU(), .singularValues(), and .matrixV()
+
+// Eigenvalue problems
+// Eigen // Matlab
+A.eigenvalues(); // eig(A);
+EigenSolver<Matrix3d> eig(A); // [vec val] = eig(A)
+eig.eigenvalues(); // diag(val)
+eig.eigenvectors(); // vec
diff --git a/doc/B01_Experimental.dox b/doc/B01_Experimental.dox
new file mode 100644
index 000000000..6d8b90d5a
--- /dev/null
+++ b/doc/B01_Experimental.dox
@@ -0,0 +1,55 @@
+namespace Eigen {
+
+/** \page Experimental Experimental parts of Eigen
+
+\b Table \b of \b contents
+ - \ref summary
+ - \ref modules
+ - \ref core
+
+\section summary Summary
+
+With the 2.0 release, Eigen's API is, to a large extent, stable. However, we wish to retain the freedom to make API incompatible changes. To that effect, we call many parts of Eigen "experimental" which means that they are not subject to API stability guarantee.
+
+Our goal is that for the 2.1 release (expected in July 2009) most of these parts become API-stable too.
+
+We are aware that API stability is a major concern for our users. That's why it's a priority for us to reach it, but at the same time we're being serious about not calling Eigen API-stable too early.
+
+Experimental features may at any time:
+\li be removed;
+\li be subject to an API incompatible change;
+\li introduce API or ABI incompatible changes in your own code if you let them affect your API or ABI.
+
+\section modules Experimental modules
+
+The following modules are considered entirely experimental, and we make no firm API stability guarantee about them for the time being:
+\li SVD
+\li QR
+\li Cholesky
+\li Sparse
+\li Geometry (this one should be mostly stable, but it's a little too early to make a formal guarantee)
+
+\section core Experimental parts of the Core module
+
+In the Core module, the only classes subject to ABI stability guarantee (meaning that you can use it for data members in your public ABI) is:
+\li Matrix
+\li Map
+
+All other classes offer no ABI guarantee, e.g. the layout of their data can be changed.
+
+The only classes subject to (even partial) API stability guarantee (meaning that you can safely construct and use objects) are:
+\li MatrixBase : partial API stability (see below)
+\li Matrix : full API stability (except for experimental stuff inherited from MatrixBase)
+\li Map : full API stability (except for experimental stuff inherited from MatrixBase)
+
+All other classes offer no direct API guarantee, e.g. their methods can be changed; however notice that most classes inherit MatrixBase and that this is where most of their API comes from -- so in practice most of the API is stable.
+
+A few MatrixBase methods are considered experimental, hence not part of any API stability guarantee:
+\li all methods documented as internal
+\li all methods hidden in the Doxygen documentation
+\li all methods marked as experimental
+\li all methods defined in experimental modules
+
+*/
+
+}
diff --git a/doc/C00_QuickStartGuide.dox b/doc/C00_QuickStartGuide.dox
new file mode 100644
index 000000000..8534cb0c3
--- /dev/null
+++ b/doc/C00_QuickStartGuide.dox
@@ -0,0 +1,99 @@
+namespace Eigen {
+
+/** \page GettingStarted Getting started
+ \ingroup Tutorial
+
+This is a very short guide on how to get started with Eigen. It has a dual purpose. It serves as a minimal introduction to the Eigen library for people who want to start coding as soon as possible. You can also read this page as the first part of the Tutorial, which explains the library in more detail; in this case you will continue with \ref TutorialMatrixClass.
+
+\section GettingStartedInstallation How to "install" Eigen?
+
+In order to use Eigen, you just need to download and extract Eigen's source code (see <a href="http://eigen.tuxfamily.org/index.php?title=Main_Page#Download">the wiki</a> for download instructions). In fact, the header files in the \c Eigen subdirectory are the only files required to compile programs using Eigen. The header files are the same for all platforms. It is not necessary to use CMake or install anything.
+
+
+\section GettingStartedFirstProgram A simple first program
+
+Here is a rather simple program to get you started.
+
+\include QuickStart_example.cpp
+
+We will explain the program after telling you how to compile it.
+
+
+\section GettingStartedCompiling Compiling and running your first program
+
+There is no library to link to. The only thing that you need to keep in mind when compiling the above program is that the compiler must be able to find the Eigen header files. The directory in which you placed Eigen's source code must be in the include path. With GCC you use the -I option to achieve this, so you can compile the program with a command like this:
+
+\code g++ -I /path/to/eigen/ my_program.cpp -o my_program \endcode
+
+On Linux or Mac OS X, another option is to symlink or copy the Eigen folder into /usr/local/include/. This way, you can compile the program with:
+
+\code g++ my_program.cpp -o my_program \endcode
+
+When you run the program, it produces the following output:
+
+\include QuickStart_example.out
+
+
+\section GettingStartedExplanation Explanation of the first program
+
+The Eigen header files define many types, but for simple applications it may be enough to use only the \c MatrixXd type. This represents a matrix of arbitrary size (hence the \c X in \c MatrixXd), in which every entry is a \c double (hence the \c d in \c MatrixXd). See the \ref QuickRef_Types "quick reference guide" for an overview of the different types you can use to represent a matrix.
+
+The \c Eigen/Dense header file defines all member functions for the MatrixXd type and related types (see also the \ref QuickRef_Headers "table of header files"). All classes and functions defined in this header file (and other Eigen header files) are in the \c Eigen namespace.
+
+The first line of the \c main function declares a variable of type \c MatrixXd and specifies that it is a matrix with 2 rows and 2 columns (the entries are not initialized). The statement <tt>m(0,0) = 3</tt> sets the entry in the top-left corner to 3. You need to use round parentheses to refer to entries in the matrix. As usual in computer science, the index of the first index is 0, as opposed to the convention in mathematics that the first index is 1.
+
+The following three statements sets the other three entries. The final line outputs the matrix \c m to the standard output stream.
+
+
+\section GettingStartedExample2 Example 2: Matrices and vectors
+
+Here is another example, which combines matrices with vectors. Concentrate on the left-hand program for now; we will talk about the right-hand program later.
+
+<table class="manual">
+<tr><th>Size set at run time:</th><th>Size set at compile time:</th></tr>
+<tr><td>
+\include QuickStart_example2_dynamic.cpp
+</td>
+<td>
+\include QuickStart_example2_fixed.cpp
+</td></tr></table>
+
+The output is as follows:
+
+\include QuickStart_example2_dynamic.out
+
+
+\section GettingStartedExplanation2 Explanation of the second example
+
+The second example starts by declaring a 3-by-3 matrix \c m which is initialized using the \link DenseBase::Random(Index,Index) Random() \endlink method with random values between -1 and 1. The next line applies a linear mapping such that the values are between 10 and 110. The function call \link DenseBase::Constant(Index,Index,const Scalar&) MatrixXd::Constant\endlink(3,3,1.2) returns a 3-by-3 matrix expression having all coefficients equal to 1.2. The rest is standard arithmetics.
+
+The next line of the \c main function introduces a new type: \c VectorXd. This represents a (column) vector of arbitrary size. Here, the vector \c v is created to contain \c 3 coefficients which are left unitialized. The one but last line uses the so-called comma-initializer, explained in \ref TutorialAdvancedInitialization, to set all coefficients of the vector \c v to be as follows:
+
+\f[
+v =
+\begin{bmatrix}
+ 1 \\
+ 2 \\
+ 3
+\end{bmatrix}.
+\f]
+
+The final line of the program multiplies the matrix \c m with the vector \c v and outputs the result.
+
+Now look back at the second example program. We presented two versions of it. In the version in the left column, the matrix is of type \c MatrixXd which represents matrices of arbitrary size. The version in the right column is similar, except that the matrix is of type \c Matrix3d, which represents matrices of a fixed size (here 3-by-3). Because the type already encodes the size of the matrix, it is not necessary to specify the size in the constructor; compare <tt>MatrixXd m(3,3)</tt> with <tt>Matrix3d m</tt>. Similarly, we have \c VectorXd on the left (arbitrary size) versus \c Vector3d on the right (fixed size). Note that here the coefficients of vector \c v are directly set in the constructor, though the same syntax of the left example could be used too.
+
+The use of fixed-size matrices and vectors has two advantages. The compiler emits better (faster) code because it knows the size of the matrices and vectors. Specifying the size in the type also allows for more rigorous checking at compile-time. For instance, the compiler will complain if you try to multiply a \c Matrix4d (a 4-by-4 matrix) with a \c Vector3d (a vector of size 3). However, the use of many types increases compilation time and the size of the executable. The size of the matrix may also not be known at compile-time. A rule of thumb is to use fixed-size matrices for size 4-by-4 and smaller.
+
+
+\section GettingStartedConclusion Where to go from here?
+
+It's worth taking the time to read the \ref TutorialMatrixClass "long tutorial".
+
+However if you think you don't need it, you can directly use the classes documentation and our \ref QuickRefPage.
+
+\li \b Next: \ref TutorialMatrixClass
+
+*/
+
+}
+
diff --git a/doc/C01_TutorialMatrixClass.dox b/doc/C01_TutorialMatrixClass.dox
new file mode 100644
index 000000000..4860616e5
--- /dev/null
+++ b/doc/C01_TutorialMatrixClass.dox
@@ -0,0 +1,284 @@
+namespace Eigen {
+
+/** \page TutorialMatrixClass Tutorial page 1 - The %Matrix class
+
+\ingroup Tutorial
+
+\li \b Previous: \ref GettingStarted
+\li \b Next: \ref TutorialMatrixArithmetic
+
+We assume that you have already read the quick \link GettingStarted "getting started" \endlink tutorial.
+This page is the first one in a much longer multi-page tutorial.
+
+\b Table \b of \b contents
+ - \ref TutorialMatrixFirst3Params
+ - \ref TutorialMatrixVectors
+ - \ref TutorialMatrixDynamic
+ - \ref TutorialMatrixConstructors
+ - \ref TutorialMatrixCoeffAccessors
+ - \ref TutorialMatrixCommaInitializer
+ - \ref TutorialMatrixSizesResizing
+ - \ref TutorialMatrixAssignment
+ - \ref TutorialMatrixFixedVsDynamic
+ - \ref TutorialMatrixOptTemplParams
+ - \ref TutorialMatrixTypedefs
+
+In Eigen, all matrices and vectors are objects of the Matrix template class.
+Vectors are just a special case of matrices, with either 1 row or 1 column.
+
+\section TutorialMatrixFirst3Params The first three template parameters of Matrix
+
+The Matrix class takes six template parameters, but for now it's enough to
+learn about the first three first parameters. The three remaining parameters have default
+values, which for now we will leave untouched, and which we
+\ref TutorialMatrixOptTemplParams "discuss below".
+
+The three mandatory template parameters of Matrix are:
+\code
+Matrix<typename Scalar, int RowsAtCompileTime, int ColsAtCompileTime>
+\endcode
+\li \c Scalar is the scalar type, i.e. the type of the coefficients.
+ That is, if you want a matrix of floats, choose \c float here.
+ See \ref TopicScalarTypes "Scalar types" for a list of all supported
+ scalar types and for how to extend support to new types.
+\li \c RowsAtCompileTime and \c ColsAtCompileTime are the number of rows
+ and columns of the matrix as known at compile time (see
+ \ref TutorialMatrixDynamic "below" for what to do if the number is not
+ known at compile time).
+
+We offer a lot of convenience typedefs to cover the usual cases. For example, \c Matrix4f is
+a 4x4 matrix of floats. Here is how it is defined by Eigen:
+\code
+typedef Matrix<float, 4, 4> Matrix4f;
+\endcode
+We discuss \ref TutorialMatrixTypedefs "below" these convenience typedefs.
+
+\section TutorialMatrixVectors Vectors
+
+As mentioned above, in Eigen, vectors are just a special case of
+matrices, with either 1 row or 1 column. The case where they have 1 column is the most common;
+such vectors are called column-vectors, often abbreviated as just vectors. In the other case
+where they have 1 row, they are called row-vectors.
+
+For example, the convenience typedef \c Vector3f is a (column) vector of 3 floats. It is defined as follows by Eigen:
+\code
+typedef Matrix<float, 3, 1> Vector3f;
+\endcode
+We also offer convenience typedefs for row-vectors, for example:
+\code
+typedef Matrix<int, 1, 2> RowVector2i;
+\endcode
+
+\section TutorialMatrixDynamic The special value Dynamic
+
+Of course, Eigen is not limited to matrices whose dimensions are known at compile time.
+The \c RowsAtCompileTime and \c ColsAtCompileTime template parameters can take the special
+value \c Dynamic which indicates that the size is unknown at compile time, so must
+be handled as a run-time variable. In Eigen terminology, such a size is referred to as a
+\em dynamic \em size; while a size that is known at compile time is called a
+\em fixed \em size. For example, the convenience typedef \c MatrixXd, meaning
+a matrix of doubles with dynamic size, is defined as follows:
+\code
+typedef Matrix<double, Dynamic, Dynamic> MatrixXd;
+\endcode
+And similarly, we define a self-explanatory typedef \c VectorXi as follows:
+\code
+typedef Matrix<int, Dynamic, 1> VectorXi;
+\endcode
+You can perfectly have e.g. a fixed number of rows with a dynamic number of columns, as in:
+\code
+Matrix<float, 3, Dynamic>
+\endcode
+
+\section TutorialMatrixConstructors Constructors
+
+A default constructor is always available, never performs any dynamic memory allocation, and never initializes the matrix coefficients. You can do:
+\code
+Matrix3f a;
+MatrixXf b;
+\endcode
+Here,
+\li \c a is a 3x3 matrix, with a static float[9] array of uninitialized coefficients,
+\li \c b is a dynamic-size matrix whose size is currently 0x0, and whose array of
+coefficients hasn't yet been allocated at all.
+
+Constructors taking sizes are also available. For matrices, the number of rows is always passed first.
+For vectors, just pass the vector size. They allocate the array of coefficients
+with the given size, but don't initialize the coefficients themselves:
+\code
+MatrixXf a(10,15);
+VectorXf b(30);
+\endcode
+Here,
+\li \c a is a 10x15 dynamic-size matrix, with allocated but currently uninitialized coefficients.
+\li \c b is a dynamic-size vector of size 30, with allocated but currently uninitialized coefficients.
+
+In order to offer a uniform API across fixed-size and dynamic-size matrices, it is legal to use these
+constructors on fixed-size matrices, even if passing the sizes is useless in this case. So this is legal:
+\code
+Matrix3f a(3,3);
+\endcode
+and is a no-operation.
+
+Finally, we also offer some constructors to initialize the coefficients of small fixed-size vectors up to size 4:
+\code
+Vector2d a(5.0, 6.0);
+Vector3d b(5.0, 6.0, 7.0);
+Vector4d c(5.0, 6.0, 7.0, 8.0);
+\endcode
+
+\section TutorialMatrixCoeffAccessors Coefficient accessors
+
+The primary coefficient accessors and mutators in Eigen are the overloaded parenthesis operators.
+For matrices, the row index is always passed first. For vectors, just pass one index.
+The numbering starts at 0. This example is self-explanatory:
+
+<table class="example">
+<tr><th>Example:</th><th>Output:</th></tr>
+<tr><td>
+\include tut_matrix_coefficient_accessors.cpp
+</td>
+<td>
+\verbinclude tut_matrix_coefficient_accessors.out
+</td></tr></table>
+
+Note that the syntax <tt> m(index) </tt>
+is not restricted to vectors, it is also available for general matrices, meaning index-based access
+in the array of coefficients. This however depends on the matrix's storage order. All Eigen matrices default to
+column-major storage order, but this can be changed to row-major, see \ref TopicStorageOrders "Storage orders".
+
+The operator[] is also overloaded for index-based access in vectors, but keep in mind that C++ doesn't allow operator[] to
+take more than one argument. We restrict operator[] to vectors, because an awkwardness in the C++ language
+would make matrix[i,j] compile to the same thing as matrix[j] !
+
+\section TutorialMatrixCommaInitializer Comma-initialization
+
+%Matrix and vector coefficients can be conveniently set using the so-called \em comma-initializer syntax.
+For now, it is enough to know this example:
+
+<table class="example">
+<tr><th>Example:</th><th>Output:</th></tr>
+<tr>
+<td>\include Tutorial_commainit_01.cpp </td>
+<td>\verbinclude Tutorial_commainit_01.out </td>
+</tr></table>
+
+
+The right-hand side can also contain matrix expressions as discussed in \ref TutorialAdvancedInitialization "this page".
+
+\section TutorialMatrixSizesResizing Resizing
+
+The current size of a matrix can be retrieved by \link EigenBase::rows() rows()\endlink, \link EigenBase::cols() cols() \endlink and \link EigenBase::size() size()\endlink. These methods return the number of rows, the number of columns and the number of coefficients, respectively. Resizing a dynamic-size matrix is done by the \link PlainObjectBase::resize(Index,Index) resize() \endlink method.
+
+<table class="example">
+<tr><th>Example:</th><th>Output:</th></tr>
+<tr>
+<td>\include tut_matrix_resize.cpp </td>
+<td>\verbinclude tut_matrix_resize.out </td>
+</tr></table>
+
+The resize() method is a no-operation if the actual matrix size doesn't change; otherwise it is destructive: the values of the coefficients may change.
+If you want a conservative variant of resize() which does not change the coefficients, use \link PlainObjectBase::conservativeResize() conservativeResize()\endlink, see \ref TopicResizing "this page" for more details.
+
+All these methods are still available on fixed-size matrices, for the sake of API uniformity. Of course, you can't actually
+resize a fixed-size matrix. Trying to change a fixed size to an actually different value will trigger an assertion failure;
+but the following code is legal:
+
+<table class="example">
+<tr><th>Example:</th><th>Output:</th></tr>
+<tr>
+<td>\include tut_matrix_resize_fixed_size.cpp </td>
+<td>\verbinclude tut_matrix_resize_fixed_size.out </td>
+</tr></table>
+
+
+\section TutorialMatrixAssignment Assignment and resizing
+
+Assignment is the action of copying a matrix into another, using \c operator=. Eigen resizes the matrix on the left-hand side automatically so that it matches the size of the matrix on the right-hand size. For example:
+
+<table class="example">
+<tr><th>Example:</th><th>Output:</th></tr>
+<tr>
+<td>\include tut_matrix_assignment_resizing.cpp </td>
+<td>\verbinclude tut_matrix_assignment_resizing.out </td>
+</tr></table>
+
+Of course, if the left-hand side is of fixed size, resizing it is not allowed.
+
+If you do not want this automatic resizing to happen (for example for debugging purposes), you can disable it, see
+\ref TopicResizing "this page".
+
+
+\section TutorialMatrixFixedVsDynamic Fixed vs. Dynamic size
+
+When should one use fixed sizes (e.g. \c Matrix4f), and when should one prefer dynamic sizes (e.g. \c MatrixXf)?
+The simple answer is: use fixed
+sizes for very small sizes where you can, and use dynamic sizes for larger sizes or where you have to. For small sizes,
+especially for sizes smaller than (roughly) 16, using fixed sizes is hugely beneficial
+to performance, as it allows Eigen to avoid dynamic memory allocation and to unroll
+loops. Internally, a fixed-size Eigen matrix is just a plain static array, i.e. doing
+\code Matrix4f mymatrix; \endcode
+really amounts to just doing
+\code float mymatrix[16]; \endcode
+so this really has zero runtime cost. By contrast, the array of a dynamic-size matrix
+is always allocated on the heap, so doing
+\code MatrixXf mymatrix(rows,columns); \endcode
+amounts to doing
+\code float *mymatrix = new float[rows*columns]; \endcode
+and in addition to that, the MatrixXf object stores its number of rows and columns as
+member variables.
+
+The limitation of using fixed sizes, of course, is that this is only possible
+when you know the sizes at compile time. Also, for large enough sizes, say for sizes
+greater than (roughly) 32, the performance benefit of using fixed sizes becomes negligible.
+Worse, trying to create a very large matrix using fixed sizes could result in a stack overflow,
+since Eigen will try to allocate the array as a static array, which by default goes on the stack.
+Finally, depending on circumstances, Eigen can also be more aggressive trying to vectorize
+(use SIMD instructions) when dynamic sizes are used, see \ref TopicVectorization "Vectorization".
+
+\section TutorialMatrixOptTemplParams Optional template parameters
+
+We mentioned at the beginning of this page that the Matrix class takes six template parameters,
+but so far we only discussed the first three. The remaining three parameters are optional. Here is
+the complete list of template parameters:
+\code
+Matrix<typename Scalar,
+ int RowsAtCompileTime,
+ int ColsAtCompileTime,
+ int Options = 0,
+ int MaxRowsAtCompileTime = RowsAtCompileTime,
+ int MaxColsAtCompileTime = ColsAtCompileTime>
+\endcode
+\li \c Options is a bit field. Here, we discuss only one bit: \c RowMajor. It specifies that the matrices
+ of this type use row-major storage order; by default, the storage order is column-major. See the page on
+ \ref TopicStorageOrders "storage orders". For example, this type means row-major 3x3 matrices:
+ \code
+ Matrix<float, 3, 3, RowMajor>
+ \endcode
+\li \c MaxRowsAtCompileTime and \c MaxColsAtCompileTime are useful when you want to specify that, even though
+ the exact sizes of your matrices are not known at compile time, a fixed upper bound is known at
+ compile time. The biggest reason why you might want to do that is to avoid dynamic memory allocation.
+ For example the following matrix type uses a static array of 12 floats, without dynamic memory allocation:
+ \code
+ Matrix<float, Dynamic, Dynamic, 0, 3, 4>
+ \endcode
+
+\section TutorialMatrixTypedefs Convenience typedefs
+
+Eigen defines the following Matrix typedefs:
+\li MatrixNt for Matrix<type, N, N>. For example, MatrixXi for Matrix<int, Dynamic, Dynamic>.
+\li VectorNt for Matrix<type, N, 1>. For example, Vector2f for Matrix<float, 2, 1>.
+\li RowVectorNt for Matrix<type, 1, N>. For example, RowVector3d for Matrix<double, 1, 3>.
+
+Where:
+\li N can be any one of \c 2, \c 3, \c 4, or \c X (meaning \c Dynamic).
+\li t can be any one of \c i (meaning int), \c f (meaning float), \c d (meaning double),
+ \c cf (meaning complex<float>), or \c cd (meaning complex<double>). The fact that typedefs are only
+ defined for these five types doesn't mean that they are the only supported scalar types. For example,
+ all standard integer types are supported, see \ref TopicScalarTypes "Scalar types".
+
+\li \b Next: \ref TutorialMatrixArithmetic
+
+*/
+
+}
diff --git a/doc/C02_TutorialMatrixArithmetic.dox b/doc/C02_TutorialMatrixArithmetic.dox
new file mode 100644
index 000000000..b04821a87
--- /dev/null
+++ b/doc/C02_TutorialMatrixArithmetic.dox
@@ -0,0 +1,229 @@
+namespace Eigen {
+
+/** \page TutorialMatrixArithmetic Tutorial page 2 - %Matrix and vector arithmetic
+ \ingroup Tutorial
+
+\li \b Previous: \ref TutorialMatrixClass
+\li \b Next: \ref TutorialArrayClass
+
+This tutorial aims to provide an overview and some details on how to perform arithmetic
+between matrices, vectors and scalars with Eigen.
+
+\b Table \b of \b contents
+ - \ref TutorialArithmeticIntroduction
+ - \ref TutorialArithmeticAddSub
+ - \ref TutorialArithmeticScalarMulDiv
+ - \ref TutorialArithmeticMentionXprTemplates
+ - \ref TutorialArithmeticTranspose
+ - \ref TutorialArithmeticMatrixMul
+ - \ref TutorialArithmeticDotAndCross
+ - \ref TutorialArithmeticRedux
+ - \ref TutorialArithmeticValidity
+
+\section TutorialArithmeticIntroduction Introduction
+
+Eigen offers matrix/vector arithmetic operations either through overloads of common C++ arithmetic operators such as +, -, *,
+or through special methods such as dot(), cross(), etc.
+For the Matrix class (matrices and vectors), operators are only overloaded to support
+linear-algebraic operations. For example, \c matrix1 \c * \c matrix2 means matrix-matrix product,
+and \c vector \c + \c scalar is just not allowed. If you want to perform all kinds of array operations,
+not linear algebra, see the \ref TutorialArrayClass "next page".
+
+\section TutorialArithmeticAddSub Addition and subtraction
+
+The left hand side and right hand side must, of course, have the same numbers of rows and of columns. They must
+also have the same \c Scalar type, as Eigen doesn't do automatic type promotion. The operators at hand here are:
+\li binary operator + as in \c a+b
+\li binary operator - as in \c a-b
+\li unary operator - as in \c -a
+\li compound operator += as in \c a+=b
+\li compound operator -= as in \c a-=b
+
+<table class="example">
+<tr><th>Example:</th><th>Output:</th></tr>
+<tr><td>
+\include tut_arithmetic_add_sub.cpp
+</td>
+<td>
+\verbinclude tut_arithmetic_add_sub.out
+</td></tr></table>
+
+\section TutorialArithmeticScalarMulDiv Scalar multiplication and division
+
+Multiplication and division by a scalar is very simple too. The operators at hand here are:
+\li binary operator * as in \c matrix*scalar
+\li binary operator * as in \c scalar*matrix
+\li binary operator / as in \c matrix/scalar
+\li compound operator *= as in \c matrix*=scalar
+\li compound operator /= as in \c matrix/=scalar
+
+<table class="example">
+<tr><th>Example:</th><th>Output:</th></tr>
+<tr><td>
+\include tut_arithmetic_scalar_mul_div.cpp
+</td>
+<td>
+\verbinclude tut_arithmetic_scalar_mul_div.out
+</td></tr></table>
+
+
+\section TutorialArithmeticMentionXprTemplates A note about expression templates
+
+This is an advanced topic that we explain on \ref TopicEigenExpressionTemplates "this page",
+but it is useful to just mention it now. In Eigen, arithmetic operators such as \c operator+ don't
+perform any computation by themselves, they just return an "expression object" describing the computation to be
+performed. The actual computation happens later, when the whole expression is evaluated, typically in \c operator=.
+While this might sound heavy, any modern optimizing compiler is able to optimize away that abstraction and
+the result is perfectly optimized code. For example, when you do:
+\code
+VectorXf a(50), b(50), c(50), d(50);
+...
+a = 3*b + 4*c + 5*d;
+\endcode
+Eigen compiles it to just one for loop, so that the arrays are traversed only once. Simplifying (e.g. ignoring
+SIMD optimizations), this loop looks like this:
+\code
+for(int i = 0; i < 50; ++i)
+ a[i] = 3*b[i] + 4*c[i] + 5*d[i];
+\endcode
+Thus, you should not be afraid of using relatively large arithmetic expressions with Eigen: it only gives Eigen
+more opportunities for optimization.
+
+\section TutorialArithmeticTranspose Transposition and conjugation
+
+The transpose \f$ a^T \f$, conjugate \f$ \bar{a} \f$, and adjoint (i.e., conjugate transpose) \f$ a^* \f$ of a matrix or vector \f$ a \f$ are obtained by the member functions \link DenseBase::transpose() transpose()\endlink, \link MatrixBase::conjugate() conjugate()\endlink, and \link MatrixBase::adjoint() adjoint()\endlink, respectively.
+
+<table class="example">
+<tr><th>Example:</th><th>Output:</th></tr>
+<tr><td>
+\include tut_arithmetic_transpose_conjugate.cpp
+</td>
+<td>
+\verbinclude tut_arithmetic_transpose_conjugate.out
+</td></tr></table>
+
+For real matrices, \c conjugate() is a no-operation, and so \c adjoint() is equivalent to \c transpose().
+
+As for basic arithmetic operators, \c transpose() and \c adjoint() simply return a proxy object without doing the actual transposition. If you do <tt>b = a.transpose()</tt>, then the transpose is evaluated at the same time as the result is written into \c b. However, there is a complication here. If you do <tt>a = a.transpose()</tt>, then Eigen starts writing the result into \c a before the evaluation of the transpose is finished. Therefore, the instruction <tt>a = a.transpose()</tt> does not replace \c a with its transpose, as one would expect:
+<table class="example">
+<tr><th>Example:</th><th>Output:</th></tr>
+<tr><td>
+\include tut_arithmetic_transpose_aliasing.cpp
+</td>
+<td>
+\verbinclude tut_arithmetic_transpose_aliasing.out
+</td></tr></table>
+This is the so-called \ref TopicAliasing "aliasing issue". In "debug mode", i.e., when \ref TopicAssertions "assertions" have not been disabled, such common pitfalls are automatically detected.
+
+For \em in-place transposition, as for instance in <tt>a = a.transpose()</tt>, simply use the \link DenseBase::transposeInPlace() transposeInPlace()\endlink function:
+<table class="example">
+<tr><th>Example:</th><th>Output:</th></tr>
+<tr><td>
+\include tut_arithmetic_transpose_inplace.cpp
+</td>
+<td>
+\verbinclude tut_arithmetic_transpose_inplace.out
+</td></tr></table>
+There is also the \link MatrixBase::adjointInPlace() adjointInPlace()\endlink function for complex matrices.
+
+\section TutorialArithmeticMatrixMul Matrix-matrix and matrix-vector multiplication
+
+Matrix-matrix multiplication is again done with \c operator*. Since vectors are a special
+case of matrices, they are implicitly handled there too, so matrix-vector product is really just a special
+case of matrix-matrix product, and so is vector-vector outer product. Thus, all these cases are handled by just
+two operators:
+\li binary operator * as in \c a*b
+\li compound operator *= as in \c a*=b (this multiplies on the right: \c a*=b is equivalent to <tt>a = a*b</tt>)
+
+<table class="example">
+<tr><th>Example:</th><th>Output:</th></tr>
+<tr><td>
+\include tut_arithmetic_matrix_mul.cpp
+</td>
+<td>
+\verbinclude tut_arithmetic_matrix_mul.out
+</td></tr></table>
+
+Note: if you read the above paragraph on expression templates and are worried that doing \c m=m*m might cause
+aliasing issues, be reassured for now: Eigen treats matrix multiplication as a special case and takes care of
+introducing a temporary here, so it will compile \c m=m*m as:
+\code
+tmp = m*m;
+m = tmp;
+\endcode
+If you know your matrix product can be safely evaluated into the destination matrix without aliasing issue, then you can use the \link MatrixBase::noalias() noalias()\endlink function to avoid the temporary, e.g.:
+\code
+c.noalias() += a * b;
+\endcode
+For more details on this topic, see the page on \ref TopicAliasing "aliasing".
+
+\b Note: for BLAS users worried about performance, expressions such as <tt>c.noalias() -= 2 * a.adjoint() * b;</tt> are fully optimized and trigger a single gemm-like function call.
+
+\section TutorialArithmeticDotAndCross Dot product and cross product
+
+For dot product and cross product, you need the \link MatrixBase::dot() dot()\endlink and \link MatrixBase::cross() cross()\endlink methods. Of course, the dot product can also be obtained as a 1x1 matrix as u.adjoint()*v.
+<table class="example">
+<tr><th>Example:</th><th>Output:</th></tr>
+<tr><td>
+\include tut_arithmetic_dot_cross.cpp
+</td>
+<td>
+\verbinclude tut_arithmetic_dot_cross.out
+</td></tr></table>
+
+Remember that cross product is only for vectors of size 3. Dot product is for vectors of any sizes.
+When using complex numbers, Eigen's dot product is conjugate-linear in the first variable and linear in the
+second variable.
+
+\section TutorialArithmeticRedux Basic arithmetic reduction operations
+Eigen also provides some reduction operations to reduce a given matrix or vector to a single value such as the sum (computed by \link DenseBase::sum() sum()\endlink), product (\link DenseBase::prod() prod()\endlink), or the maximum (\link DenseBase::maxCoeff() maxCoeff()\endlink) and minimum (\link DenseBase::minCoeff() minCoeff()\endlink) of all its coefficients.
+
+<table class="example">
+<tr><th>Example:</th><th>Output:</th></tr>
+<tr><td>
+\include tut_arithmetic_redux_basic.cpp
+</td>
+<td>
+\verbinclude tut_arithmetic_redux_basic.out
+</td></tr></table>
+
+The \em trace of a matrix, as returned by the function \link MatrixBase::trace() trace()\endlink, is the sum of the diagonal coefficients and can also be computed as efficiently using <tt>a.diagonal().sum()</tt>, as we will see later on.
+
+There also exist variants of the \c minCoeff and \c maxCoeff functions returning the coordinates of the respective coefficient via the arguments:
+
+<table class="example">
+<tr><th>Example:</th><th>Output:</th></tr>
+<tr><td>
+\include tut_arithmetic_redux_minmax.cpp
+</td>
+<td>
+\verbinclude tut_arithmetic_redux_minmax.out
+</td></tr></table>
+
+
+\section TutorialArithmeticValidity Validity of operations
+Eigen checks the validity of the operations that you perform. When possible,
+it checks them at compile time, producing compilation errors. These error messages can be long and ugly,
+but Eigen writes the important message in UPPERCASE_LETTERS_SO_IT_STANDS_OUT. For example:
+\code
+ Matrix3f m;
+ Vector4f v;
+ v = m*v; // Compile-time error: YOU_MIXED_MATRICES_OF_DIFFERENT_SIZES
+\endcode
+
+Of course, in many cases, for example when checking dynamic sizes, the check cannot be performed at compile time.
+Eigen then uses runtime assertions. This means that the program will abort with an error message when executing an illegal operation if it is run in "debug mode", and it will probably crash if assertions are turned off.
+
+\code
+ MatrixXf m(3,3);
+ VectorXf v(4);
+ v = m * v; // Run-time assertion failure here: "invalid matrix product"
+\endcode
+
+For more details on this topic, see \ref TopicAssertions "this page".
+
+\li \b Next: \ref TutorialArrayClass
+
+*/
+
+}
diff --git a/doc/C03_TutorialArrayClass.dox b/doc/C03_TutorialArrayClass.dox
new file mode 100644
index 000000000..a1d8d6985
--- /dev/null
+++ b/doc/C03_TutorialArrayClass.dox
@@ -0,0 +1,205 @@
+namespace Eigen {
+
+/** \page TutorialArrayClass Tutorial page 3 - The %Array class and coefficient-wise operations
+ \ingroup Tutorial
+
+\li \b Previous: \ref TutorialMatrixArithmetic
+\li \b Next: \ref TutorialBlockOperations
+
+This tutorial aims to provide an overview and explanations on how to use
+Eigen's Array class.
+
+\b Table \b of \b contents
+ - \ref TutorialArrayClassIntro
+ - \ref TutorialArrayClassTypes
+ - \ref TutorialArrayClassAccess
+ - \ref TutorialArrayClassAddSub
+ - \ref TutorialArrayClassMult
+ - \ref TutorialArrayClassCwiseOther
+ - \ref TutorialArrayClassConvert
+
+\section TutorialArrayClassIntro What is the Array class?
+
+The Array class provides general-purpose arrays, as opposed to the Matrix class which
+is intended for linear algebra. Furthermore, the Array class provides an easy way to
+perform coefficient-wise operations, which might not have a linear algebraic meaning,
+such as adding a constant to every coefficient in the array or multiplying two arrays coefficient-wise.
+
+
+\section TutorialArrayClassTypes Array types
+Array is a class template taking the same template parameters as Matrix.
+As with Matrix, the first three template parameters are mandatory:
+\code
+Array<typename Scalar, int RowsAtCompileTime, int ColsAtCompileTime>
+\endcode
+The last three template parameters are optional. Since this is exactly the same as for Matrix,
+we won't explain it again here and just refer to \ref TutorialMatrixClass.
+
+Eigen also provides typedefs for some common cases, in a way that is similar to the Matrix typedefs
+but with some slight differences, as the word "array" is used for both 1-dimensional and 2-dimensional arrays.
+We adopt the convention that typedefs of the form ArrayNt stand for 1-dimensional arrays, where N and t are
+the size and the scalar type, as in the Matrix typedefs explained on \ref TutorialMatrixClass "this page". For 2-dimensional arrays, we
+use typedefs of the form ArrayNNt. Some examples are shown in the following table:
+
+<table class="manual">
+ <tr>
+ <th>Type </th>
+ <th>Typedef </th>
+ </tr>
+ <tr>
+ <td> \code Array<float,Dynamic,1> \endcode </td>
+ <td> \code ArrayXf \endcode </td>
+ </tr>
+ <tr>
+ <td> \code Array<float,3,1> \endcode </td>
+ <td> \code Array3f \endcode </td>
+ </tr>
+ <tr>
+ <td> \code Array<double,Dynamic,Dynamic> \endcode </td>
+ <td> \code ArrayXXd \endcode </td>
+ </tr>
+ <tr>
+ <td> \code Array<double,3,3> \endcode </td>
+ <td> \code Array33d \endcode </td>
+ </tr>
+</table>
+
+
+\section TutorialArrayClassAccess Accessing values inside an Array
+
+The parenthesis operator is overloaded to provide write and read access to the coefficients of an array, just as with matrices.
+Furthermore, the \c << operator can be used to initialize arrays (via the comma initializer) or to print them.
+
+<table class="example">
+<tr><th>Example:</th><th>Output:</th></tr>
+<tr><td>
+\include Tutorial_ArrayClass_accessors.cpp
+</td>
+<td>
+\verbinclude Tutorial_ArrayClass_accessors.out
+</td></tr></table>
+
+For more information about the comma initializer, see \ref TutorialAdvancedInitialization.
+
+
+\section TutorialArrayClassAddSub Addition and subtraction
+
+Adding and subtracting two arrays is the same as for matrices.
+The operation is valid if both arrays have the same size, and the addition or subtraction is done coefficient-wise.
+
+Arrays also support expressions of the form <tt>array + scalar</tt> which add a scalar to each coefficient in the array.
+This provides a functionality that is not directly available for Matrix objects.
+
+<table class="example">
+<tr><th>Example:</th><th>Output:</th></tr>
+<tr><td>
+\include Tutorial_ArrayClass_addition.cpp
+</td>
+<td>
+\verbinclude Tutorial_ArrayClass_addition.out
+</td></tr></table>
+
+
+\section TutorialArrayClassMult Array multiplication
+
+First of all, of course you can multiply an array by a scalar, this works in the same way as matrices. Where arrays
+are fundamentally different from matrices, is when you multiply two together. Matrices interpret
+multiplication as matrix product and arrays interpret multiplication as coefficient-wise product. Thus, two
+arrays can be multiplied if and only if they have the same dimensions.
+
+<table class="example">
+<tr><th>Example:</th><th>Output:</th></tr>
+<tr><td>
+\include Tutorial_ArrayClass_mult.cpp
+</td>
+<td>
+\verbinclude Tutorial_ArrayClass_mult.out
+</td></tr></table>
+
+
+\section TutorialArrayClassCwiseOther Other coefficient-wise operations
+
+The Array class defines other coefficient-wise operations besides the addition, subtraction and multiplication
+operators described above. For example, the \link ArrayBase::abs() .abs() \endlink method takes the absolute
+value of each coefficient, while \link ArrayBase::sqrt() .sqrt() \endlink computes the square root of the
+coefficients. If you have two arrays of the same size, you can call \link ArrayBase::min() .min() \endlink to
+construct the array whose coefficients are the minimum of the corresponding coefficients of the two given
+arrays. These operations are illustrated in the following example.
+
+<table class="example">
+<tr><th>Example:</th><th>Output:</th></tr>
+<tr><td>
+\include Tutorial_ArrayClass_cwise_other.cpp
+</td>
+<td>
+\verbinclude Tutorial_ArrayClass_cwise_other.out
+</td></tr></table>
+
+More coefficient-wise operations can be found in the \ref QuickRefPage.
+
+
+\section TutorialArrayClassConvert Converting between array and matrix expressions
+
+When should you use objects of the Matrix class and when should you use objects of the Array class? You cannot
+apply Matrix operations on arrays, or Array operations on matrices. Thus, if you need to do linear algebraic
+operations such as matrix multiplication, then you should use matrices; if you need to do coefficient-wise
+operations, then you should use arrays. However, sometimes it is not that simple, but you need to use both
+Matrix and Array operations. In that case, you need to convert a matrix to an array or reversely. This gives
+access to all operations regardless of the choice of declaring objects as arrays or as matrices.
+
+\link MatrixBase Matrix expressions \endlink have an \link MatrixBase::array() .array() \endlink method that
+'converts' them into \link ArrayBase array expressions\endlink, so that coefficient-wise operations
+can be applied easily. Conversely, \link ArrayBase array expressions \endlink
+have a \link ArrayBase::matrix() .matrix() \endlink method. As with all Eigen expression abstractions,
+this doesn't have any runtime cost (provided that you let your compiler optimize).
+Both \link MatrixBase::array() .array() \endlink and \link ArrayBase::matrix() .matrix() \endlink
+can be used as rvalues and as lvalues.
+
+Mixing matrices and arrays in an expression is forbidden with Eigen. For instance, you cannot add a matrix and
+array directly; the operands of a \c + operator should either both be matrices or both be arrays. However,
+it is easy to convert from one to the other with \link MatrixBase::array() .array() \endlink and
+\link ArrayBase::matrix() .matrix()\endlink. The exception to this rule is the assignment operator: it is
+allowed to assign a matrix expression to an array variable, or to assign an array expression to a matrix
+variable.
+
+The following example shows how to use array operations on a Matrix object by employing the
+\link MatrixBase::array() .array() \endlink method. For example, the statement
+<tt>result = m.array() * n.array()</tt> takes two matrices \c m and \c n, converts them both to an array, uses
+* to multiply them coefficient-wise and assigns the result to the matrix variable \c result (this is legal
+because Eigen allows assigning array expressions to matrix variables).
+
+As a matter of fact, this usage case is so common that Eigen provides a \link MatrixBase::cwiseProduct()
+.cwiseProduct() \endlink method for matrices to compute the coefficient-wise product. This is also shown in
+the example program.
+
+<table class="example">
+<tr><th>Example:</th><th>Output:</th></tr>
+<tr><td>
+\include Tutorial_ArrayClass_interop_matrix.cpp
+</td>
+<td>
+\verbinclude Tutorial_ArrayClass_interop_matrix.out
+</td></tr></table>
+
+Similarly, if \c array1 and \c array2 are arrays, then the expression <tt>array1.matrix() * array2.matrix()</tt>
+computes their matrix product.
+
+Here is a more advanced example. The expression <tt>(m.array() + 4).matrix() * m</tt> adds 4 to every
+coefficient in the matrix \c m and then computes the matrix product of the result with \c m. Similarly, the
+expression <tt>(m.array() * n.array()).matrix() * m</tt> computes the coefficient-wise product of the matrices
+\c m and \c n and then the matrix product of the result with \c m.
+
+<table class="example">
+<tr><th>Example:</th><th>Output:</th></tr>
+<tr><td>
+\include Tutorial_ArrayClass_interop.cpp
+</td>
+<td>
+\verbinclude Tutorial_ArrayClass_interop.out
+</td></tr></table>
+
+\li \b Next: \ref TutorialBlockOperations
+
+*/
+
+}
diff --git a/doc/C04_TutorialBlockOperations.dox b/doc/C04_TutorialBlockOperations.dox
new file mode 100644
index 000000000..eac0eaa59
--- /dev/null
+++ b/doc/C04_TutorialBlockOperations.dox
@@ -0,0 +1,239 @@
+namespace Eigen {
+
+/** \page TutorialBlockOperations Tutorial page 4 - %Block operations
+ \ingroup Tutorial
+
+\li \b Previous: \ref TutorialArrayClass
+\li \b Next: \ref TutorialAdvancedInitialization
+
+This tutorial page explains the essentials of block operations.
+A block is a rectangular part of a matrix or array. Blocks expressions can be used both
+as rvalues and as lvalues. As usual with Eigen expressions, this abstraction has zero runtime cost
+provided that you let your compiler optimize.
+
+\b Table \b of \b contents
+ - \ref TutorialBlockOperationsUsing
+ - \ref TutorialBlockOperationsSyntaxColumnRows
+ - \ref TutorialBlockOperationsSyntaxCorners
+ - \ref TutorialBlockOperationsSyntaxVectors
+
+
+\section TutorialBlockOperationsUsing Using block operations
+
+The most general block operation in Eigen is called \link DenseBase::block() .block() \endlink.
+There are two versions, whose syntax is as follows:
+
+<table class="manual">
+<tr><th>\b %Block \b operation</td>
+<th>Version constructing a \n dynamic-size block expression</th>
+<th>Version constructing a \n fixed-size block expression</th></tr>
+<tr><td>%Block of size <tt>(p,q)</tt>, starting at <tt>(i,j)</tt></td>
+ <td>\code
+matrix.block(i,j,p,q);\endcode </td>
+ <td>\code
+matrix.block<p,q>(i,j);\endcode </td>
+</tr>
+</table>
+
+As always in Eigen, indices start at 0.
+
+Both versions can be used on fixed-size and dynamic-size matrices and arrays.
+These two expressions are semantically equivalent.
+The only difference is that the fixed-size version will typically give you faster code if the block size is small,
+but requires this size to be known at compile time.
+
+The following program uses the dynamic-size and fixed-size versions to print the values of several blocks inside a
+matrix.
+
+<table class="example">
+<tr><th>Example:</th><th>Output:</th></tr>
+<tr><td>
+\include Tutorial_BlockOperations_print_block.cpp
+</td>
+<td>
+\verbinclude Tutorial_BlockOperations_print_block.out
+</td></tr></table>
+
+In the above example the \link DenseBase::block() .block() \endlink function was employed as a \em rvalue, i.e.
+it was only read from. However, blocks can also be used as \em lvalues, meaning that you can assign to a block.
+
+This is illustrated in the following example. This example also demonstrates blocks in arrays, which works exactly like the above-demonstrated blocks in matrices.
+
+<table class="example">
+<tr><th>Example:</th><th>Output:</th></tr>
+<tr><td>
+\include Tutorial_BlockOperations_block_assignment.cpp
+</td>
+<td>
+\verbinclude Tutorial_BlockOperations_block_assignment.out
+</td></tr></table>
+
+While the \link DenseBase::block() .block() \endlink method can be used for any block operation, there are
+other methods for special cases, providing more specialized API and/or better performance. On the topic of performance, all what
+matters is that you give Eigen as much information as possible at compile time. For example, if your block is a single whole column in a matrix,
+using the specialized \link DenseBase::col() .col() \endlink function described below lets Eigen know that, which can give it optimization opportunities.
+
+The rest of this page describes these specialized methods.
+
+\section TutorialBlockOperationsSyntaxColumnRows Columns and rows
+
+Individual columns and rows are special cases of blocks. Eigen provides methods to easily address them:
+\link DenseBase::col() .col() \endlink and \link DenseBase::row() .row()\endlink.
+
+<table class="manual">
+<tr><th>%Block operation</th>
+<th>Method</th>
+<tr><td>i<sup>th</sup> row
+ \link DenseBase::row() * \endlink</td>
+ <td>\code
+matrix.row(i);\endcode </td>
+</tr>
+<tr><td>j<sup>th</sup> column
+ \link DenseBase::col() * \endlink</td>
+ <td>\code
+matrix.col(j);\endcode </td>
+</tr>
+</table>
+
+The argument for \p col() and \p row() is the index of the column or row to be accessed. As always in Eigen, indices start at 0.
+
+<table class="example">
+<tr><th>Example:</th><th>Output:</th></tr>
+<tr><td>
+\include Tutorial_BlockOperations_colrow.cpp
+</td>
+<td>
+\verbinclude Tutorial_BlockOperations_colrow.out
+</td></tr></table>
+
+That example also demonstrates that block expressions (here columns) can be used in arithmetic like any other expression.
+
+
+\section TutorialBlockOperationsSyntaxCorners Corner-related operations
+
+Eigen also provides special methods for blocks that are flushed against one of the corners or sides of a
+matrix or array. For instance, \link DenseBase::topLeftCorner() .topLeftCorner() \endlink can be used to refer
+to a block in the top-left corner of a matrix.
+
+The different possibilities are summarized in the following table:
+
+<table class="manual">
+<tr><th>%Block \b operation</td>
+<th>Version constructing a \n dynamic-size block expression</th>
+<th>Version constructing a \n fixed-size block expression</th></tr>
+<tr><td>Top-left p by q block \link DenseBase::topLeftCorner() * \endlink</td>
+ <td>\code
+matrix.topLeftCorner(p,q);\endcode </td>
+ <td>\code
+matrix.topLeftCorner<p,q>();\endcode </td>
+</tr>
+<tr><td>Bottom-left p by q block
+ \link DenseBase::bottomLeftCorner() * \endlink</td>
+ <td>\code
+matrix.bottomLeftCorner(p,q);\endcode </td>
+ <td>\code
+matrix.bottomLeftCorner<p,q>();\endcode </td>
+</tr>
+<tr><td>Top-right p by q block
+ \link DenseBase::topRightCorner() * \endlink</td>
+ <td>\code
+matrix.topRightCorner(p,q);\endcode </td>
+ <td>\code
+matrix.topRightCorner<p,q>();\endcode </td>
+</tr>
+<tr><td>Bottom-right p by q block
+ \link DenseBase::bottomRightCorner() * \endlink</td>
+ <td>\code
+matrix.bottomRightCorner(p,q);\endcode </td>
+ <td>\code
+matrix.bottomRightCorner<p,q>();\endcode </td>
+</tr>
+<tr><td>%Block containing the first q rows
+ \link DenseBase::topRows() * \endlink</td>
+ <td>\code
+matrix.topRows(q);\endcode </td>
+ <td>\code
+matrix.topRows<q>();\endcode </td>
+</tr>
+<tr><td>%Block containing the last q rows
+ \link DenseBase::bottomRows() * \endlink</td>
+ <td>\code
+matrix.bottomRows(q);\endcode </td>
+ <td>\code
+matrix.bottomRows<q>();\endcode </td>
+</tr>
+<tr><td>%Block containing the first p columns
+ \link DenseBase::leftCols() * \endlink</td>
+ <td>\code
+matrix.leftCols(p);\endcode </td>
+ <td>\code
+matrix.leftCols<p>();\endcode </td>
+</tr>
+<tr><td>%Block containing the last q columns
+ \link DenseBase::rightCols() * \endlink</td>
+ <td>\code
+matrix.rightCols(q);\endcode </td>
+ <td>\code
+matrix.rightCols<q>();\endcode </td>
+</tr>
+</table>
+
+Here is a simple example illustrating the use of the operations presented above:
+
+<table class="example">
+<tr><th>Example:</th><th>Output:</th></tr>
+<tr><td>
+\include Tutorial_BlockOperations_corner.cpp
+</td>
+<td>
+\verbinclude Tutorial_BlockOperations_corner.out
+</td></tr></table>
+
+
+\section TutorialBlockOperationsSyntaxVectors Block operations for vectors
+
+Eigen also provides a set of block operations designed specifically for the special case of vectors and one-dimensional arrays:
+
+<table class="manual">
+<tr><th> %Block operation</th>
+<th>Version constructing a \n dynamic-size block expression</th>
+<th>Version constructing a \n fixed-size block expression</th></tr>
+<tr><td>%Block containing the first \p n elements
+ \link DenseBase::head() * \endlink</td>
+ <td>\code
+vector.head(n);\endcode </td>
+ <td>\code
+vector.head<n>();\endcode </td>
+</tr>
+<tr><td>%Block containing the last \p n elements
+ \link DenseBase::tail() * \endlink</td>
+ <td>\code
+vector.tail(n);\endcode </td>
+ <td>\code
+vector.tail<n>();\endcode </td>
+</tr>
+<tr><td>%Block containing \p n elements, starting at position \p i
+ \link DenseBase::segment() * \endlink</td>
+ <td>\code
+vector.segment(i,n);\endcode </td>
+ <td>\code
+vector.segment<n>(i);\endcode </td>
+</tr>
+</table>
+
+
+An example is presented below:
+<table class="example">
+<tr><th>Example:</th><th>Output:</th></tr>
+<tr><td>
+\include Tutorial_BlockOperations_vector.cpp
+</td>
+<td>
+\verbinclude Tutorial_BlockOperations_vector.out
+</td></tr></table>
+
+\li \b Next: \ref TutorialAdvancedInitialization
+
+*/
+
+}
diff --git a/doc/C05_TutorialAdvancedInitialization.dox b/doc/C05_TutorialAdvancedInitialization.dox
new file mode 100644
index 000000000..4f27f1e4d
--- /dev/null
+++ b/doc/C05_TutorialAdvancedInitialization.dox
@@ -0,0 +1,172 @@
+namespace Eigen {
+
+/** \page TutorialAdvancedInitialization Tutorial page 5 - Advanced initialization
+ \ingroup Tutorial
+
+\li \b Previous: \ref TutorialBlockOperations
+\li \b Next: \ref TutorialLinearAlgebra
+
+This page discusses several advanced methods for initializing matrices. It gives more details on the
+comma-initializer, which was introduced before. It also explains how to get special matrices such as the
+identity matrix and the zero matrix.
+
+\b Table \b of \b contents
+ - \ref TutorialAdvancedInitializationCommaInitializer
+ - \ref TutorialAdvancedInitializationSpecialMatrices
+ - \ref TutorialAdvancedInitializationTemporaryObjects
+
+
+\section TutorialAdvancedInitializationCommaInitializer The comma initializer
+
+Eigen offers a comma initializer syntax which allows the user to easily set all the coefficients of a matrix,
+vector or array. Simply list the coefficients, starting at the top-left corner and moving from left to right
+and from the top to the bottom. The size of the object needs to be specified beforehand. If you list too few
+or too many coefficients, Eigen will complain.
+
+<table class="example">
+<tr><th>Example:</th><th>Output:</th></tr>
+<tr><td>
+\include Tutorial_commainit_01.cpp
+</td>
+<td>
+\verbinclude Tutorial_commainit_01.out
+</td></tr></table>
+
+Moreover, the elements of the initialization list may themselves be vectors or matrices. A common use is
+to join vectors or matrices together. For example, here is how to join two row vectors together. Remember
+that you have to set the size before you can use the comma initializer.
+
+<table class="example">
+<tr><th>Example:</th><th>Output:</th></tr>
+<tr><td>
+\include Tutorial_AdvancedInitialization_Join.cpp
+</td>
+<td>
+\verbinclude Tutorial_AdvancedInitialization_Join.out
+</td></tr></table>
+
+We can use the same technique to initialize matrices with a block structure.
+
+<table class="example">
+<tr><th>Example:</th><th>Output:</th></tr>
+<tr><td>
+\include Tutorial_AdvancedInitialization_Block.cpp
+</td>
+<td>
+\verbinclude Tutorial_AdvancedInitialization_Block.out
+</td></tr></table>
+
+The comma initializer can also be used to fill block expressions such as <tt>m.row(i)</tt>. Here is a more
+complicated way to get the same result as in the first example above:
+
+<table class="example">
+<tr><th>Example:</th><th>Output:</th></tr>
+<tr><td>
+\include Tutorial_commainit_01b.cpp
+</td>
+<td>
+\verbinclude Tutorial_commainit_01b.out
+</td></tr></table>
+
+
+\section TutorialAdvancedInitializationSpecialMatrices Special matrices and arrays
+
+The Matrix and Array classes have static methods like \link DenseBase::Zero() Zero()\endlink, which can be
+used to initialize all coefficients to zero. There are three variants. The first variant takes no arguments
+and can only be used for fixed-size objects. If you want to initialize a dynamic-size object to zero, you need
+to specify the size. Thus, the second variant requires one argument and can be used for one-dimensional
+dynamic-size objects, while the third variant requires two arguments and can be used for two-dimensional
+objects. All three variants are illustrated in the following example:
+
+<table class="example">
+<tr><th>Example:</th><th>Output:</th></tr>
+<tr><td>
+\include Tutorial_AdvancedInitialization_Zero.cpp
+</td>
+<td>
+\verbinclude Tutorial_AdvancedInitialization_Zero.out
+</td></tr></table>
+
+Similarly, the static method \link DenseBase::Constant() Constant\endlink(value) sets all coefficients to \c value.
+If the size of the object needs to be specified, the additional arguments go before the \c value
+argument, as in <tt>MatrixXd::Constant(rows, cols, value)</tt>. The method \link DenseBase::Random() Random()
+\endlink fills the matrix or array with random coefficients. The identity matrix can be obtained by calling
+\link MatrixBase::Identity() Identity()\endlink; this method is only available for Matrix, not for Array,
+because "identity matrix" is a linear algebra concept. The method
+\link DenseBase::LinSpaced LinSpaced\endlink(size, low, high) is only available for vectors and
+one-dimensional arrays; it yields a vector of the specified size whose coefficients are equally spaced between
+\c low and \c high. The method \c LinSpaced() is illustrated in the following example, which prints a table
+with angles in degrees, the corresponding angle in radians, and their sine and cosine.
+
+<table class="example">
+<tr><th>Example:</th><th>Output:</th></tr>
+<tr><td>
+\include Tutorial_AdvancedInitialization_LinSpaced.cpp
+</td>
+<td>
+\verbinclude Tutorial_AdvancedInitialization_LinSpaced.out
+</td></tr></table>
+
+This example shows that objects like the ones returned by LinSpaced() can be assigned to variables (and
+expressions). Eigen defines utility functions like \link DenseBase::setZero() setZero()\endlink,
+\link MatrixBase::setIdentity() \endlink and \link DenseBase::setLinSpaced() \endlink to do this
+conveniently. The following example contrasts three ways to construct the matrix
+\f$ J = \bigl[ \begin{smallmatrix} O & I \\ I & O \end{smallmatrix} \bigr] \f$: using static methods and
+assignment, using static methods and the comma-initializer, or using the setXxx() methods.
+
+<table class="example">
+<tr><th>Example:</th><th>Output:</th></tr>
+<tr><td>
+\include Tutorial_AdvancedInitialization_ThreeWays.cpp
+</td>
+<td>
+\verbinclude Tutorial_AdvancedInitialization_ThreeWays.out
+</td></tr></table>
+
+A summary of all pre-defined matrix, vector and array objects can be found in the \ref QuickRefPage.
+
+
+\section TutorialAdvancedInitializationTemporaryObjects Usage as temporary objects
+
+As shown above, static methods as Zero() and Constant() can be used to initialize variables at the time of
+declaration or at the right-hand side of an assignment operator. You can think of these methods as returning a
+matrix or array; in fact, they return so-called \ref TopicEigenExpressionTemplates "expression objects" which
+evaluate to a matrix or array when needed, so that this syntax does not incur any overhead.
+
+These expressions can also be used as a temporary object. The second example in
+the \ref GettingStarted guide, which we reproduce here, already illustrates this.
+
+<table class="example">
+<tr><th>Example:</th><th>Output:</th></tr>
+<tr><td>
+\include QuickStart_example2_dynamic.cpp
+</td>
+<td>
+\verbinclude QuickStart_example2_dynamic.out
+</td></tr></table>
+
+The expression <tt>m + MatrixXf::Constant(3,3,1.2)</tt> constructs the 3-by-3 matrix expression with all its coefficients
+equal to 1.2 plus the corresponding coefficient of \a m.
+
+The comma-initializer, too, can also be used to construct temporary objects. The following example constructs a random
+matrix of size 2-by-3, and then multiplies this matrix on the left with
+\f$ \bigl[ \begin{smallmatrix} 0 & 1 \\ 1 & 0 \end{smallmatrix} \bigr] \f$.
+
+<table class="example">
+<tr><th>Example:</th><th>Output:</th></tr>
+<tr><td>
+\include Tutorial_AdvancedInitialization_CommaTemporary.cpp
+</td>
+<td>
+\verbinclude Tutorial_AdvancedInitialization_CommaTemporary.out
+</td></tr></table>
+
+The \link CommaInitializer::finished() finished() \endlink method is necessary here to get the actual matrix
+object once the comma initialization of our temporary submatrix is done.
+
+
+\li \b Next: \ref TutorialLinearAlgebra
+
+*/
+
+}
diff --git a/doc/C06_TutorialLinearAlgebra.dox b/doc/C06_TutorialLinearAlgebra.dox
new file mode 100644
index 000000000..e8b3b7953
--- /dev/null
+++ b/doc/C06_TutorialLinearAlgebra.dox
@@ -0,0 +1,269 @@
+namespace Eigen {
+
+/** \page TutorialLinearAlgebra Tutorial page 6 - Linear algebra and decompositions
+ \ingroup Tutorial
+
+\li \b Previous: \ref TutorialAdvancedInitialization
+\li \b Next: \ref TutorialReductionsVisitorsBroadcasting
+
+This tutorial explains how to solve linear systems, compute various decompositions such as LU,
+QR, %SVD, eigendecompositions... for more advanced topics, don't miss our special page on
+\ref TopicLinearAlgebraDecompositions "this topic".
+
+\b Table \b of \b contents
+ - \ref TutorialLinAlgBasicSolve
+ - \ref TutorialLinAlgSolutionExists
+ - \ref TutorialLinAlgEigensolving
+ - \ref TutorialLinAlgInverse
+ - \ref TutorialLinAlgLeastsquares
+ - \ref TutorialLinAlgSeparateComputation
+ - \ref TutorialLinAlgRankRevealing
+
+
+\section TutorialLinAlgBasicSolve Basic linear solving
+
+\b The \b problem: You have a system of equations, that you have written as a single matrix equation
+ \f[ Ax \: = \: b \f]
+Where \a A and \a b are matrices (\a b could be a vector, as a special case). You want to find a solution \a x.
+
+\b The \b solution: You can choose between various decompositions, depending on what your matrix \a A looks like,
+and depending on whether you favor speed or accuracy. However, let's start with an example that works in all cases,
+and is a good compromise:
+<table class="example">
+<tr><th>Example:</th><th>Output:</th></tr>
+<tr>
+ <td>\include TutorialLinAlgExSolveColPivHouseholderQR.cpp </td>
+ <td>\verbinclude TutorialLinAlgExSolveColPivHouseholderQR.out </td>
+</tr>
+</table>
+
+In this example, the colPivHouseholderQr() method returns an object of class ColPivHouseholderQR. Since here the
+matrix is of type Matrix3f, this line could have been replaced by:
+\code
+ColPivHouseholderQR<Matrix3f> dec(A);
+Vector3f x = dec.solve(b);
+\endcode
+
+Here, ColPivHouseholderQR is a QR decomposition with column pivoting. It's a good compromise for this tutorial, as it
+works for all matrices while being quite fast. Here is a table of some other decompositions that you can choose from,
+depending on your matrix and the trade-off you want to make:
+
+<table class="manual">
+ <tr>
+ <th>Decomposition</th>
+ <th>Method</th>
+ <th>Requirements on the matrix</th>
+ <th>Speed</th>
+ <th>Accuracy</th>
+ </tr>
+ <tr>
+ <td>PartialPivLU</td>
+ <td>partialPivLu()</td>
+ <td>Invertible</td>
+ <td>++</td>
+ <td>+</td>
+ </tr>
+ <tr class="alt">
+ <td>FullPivLU</td>
+ <td>fullPivLu()</td>
+ <td>None</td>
+ <td>-</td>
+ <td>+++</td>
+ </tr>
+ <tr>
+ <td>HouseholderQR</td>
+ <td>householderQr()</td>
+ <td>None</td>
+ <td>++</td>
+ <td>+</td>
+ </tr>
+ <tr class="alt">
+ <td>ColPivHouseholderQR</td>
+ <td>colPivHouseholderQr()</td>
+ <td>None</td>
+ <td>+</td>
+ <td>++</td>
+ </tr>
+ <tr>
+ <td>FullPivHouseholderQR</td>
+ <td>fullPivHouseholderQr()</td>
+ <td>None</td>
+ <td>-</td>
+ <td>+++</td>
+ </tr>
+ <tr class="alt">
+ <td>LLT</td>
+ <td>llt()</td>
+ <td>Positive definite</td>
+ <td>+++</td>
+ <td>+</td>
+ </tr>
+ <tr>
+ <td>LDLT</td>
+ <td>ldlt()</td>
+ <td>Positive or negative semidefinite</td>
+ <td>+++</td>
+ <td>++</td>
+ </tr>
+</table>
+
+All of these decompositions offer a solve() method that works as in the above example.
+
+For example, if your matrix is positive definite, the above table says that a very good
+choice is then the LDLT decomposition. Here's an example, also demonstrating that using a general
+matrix (not a vector) as right hand side is possible.
+
+<table class="example">
+<tr><th>Example:</th><th>Output:</th></tr>
+<tr>
+ <td>\include TutorialLinAlgExSolveLDLT.cpp </td>
+ <td>\verbinclude TutorialLinAlgExSolveLDLT.out </td>
+</tr>
+</table>
+
+For a \ref TopicLinearAlgebraDecompositions "much more complete table" comparing all decompositions supported by Eigen (notice that Eigen
+supports many other decompositions), see our special page on
+\ref TopicLinearAlgebraDecompositions "this topic".
+
+\section TutorialLinAlgSolutionExists Checking if a solution really exists
+
+Only you know what error margin you want to allow for a solution to be considered valid.
+So Eigen lets you do this computation for yourself, if you want to, as in this example:
+
+<table class="example">
+<tr><th>Example:</th><th>Output:</th></tr>
+<tr>
+ <td>\include TutorialLinAlgExComputeSolveError.cpp </td>
+ <td>\verbinclude TutorialLinAlgExComputeSolveError.out </td>
+</tr>
+</table>
+
+\section TutorialLinAlgEigensolving Computing eigenvalues and eigenvectors
+
+You need an eigendecomposition here, see available such decompositions on \ref TopicLinearAlgebraDecompositions "this page".
+Make sure to check if your matrix is self-adjoint, as is often the case in these problems. Here's an example using
+SelfAdjointEigenSolver, it could easily be adapted to general matrices using EigenSolver or ComplexEigenSolver.
+
+The computation of eigenvalues and eigenvectors does not necessarily converge, but such failure to converge is
+very rare. The call to info() is to check for this possibility.
+
+<table class="example">
+<tr><th>Example:</th><th>Output:</th></tr>
+<tr>
+ <td>\include TutorialLinAlgSelfAdjointEigenSolver.cpp </td>
+ <td>\verbinclude TutorialLinAlgSelfAdjointEigenSolver.out </td>
+</tr>
+</table>
+
+\section TutorialLinAlgInverse Computing inverse and determinant
+
+First of all, make sure that you really want this. While inverse and determinant are fundamental mathematical concepts,
+in \em numerical linear algebra they are not as popular as in pure mathematics. Inverse computations are often
+advantageously replaced by solve() operations, and the determinant is often \em not a good way of checking if a matrix
+is invertible.
+
+However, for \em very \em small matrices, the above is not true, and inverse and determinant can be very useful.
+
+While certain decompositions, such as PartialPivLU and FullPivLU, offer inverse() and determinant() methods, you can also
+call inverse() and determinant() directly on a matrix. If your matrix is of a very small fixed size (at most 4x4) this
+allows Eigen to avoid performing a LU decomposition, and instead use formulas that are more efficient on such small matrices.
+
+Here is an example:
+<table class="example">
+<tr><th>Example:</th><th>Output:</th></tr>
+<tr>
+ <td>\include TutorialLinAlgInverseDeterminant.cpp </td>
+ <td>\verbinclude TutorialLinAlgInverseDeterminant.out </td>
+</tr>
+</table>
+
+\section TutorialLinAlgLeastsquares Least squares solving
+
+The best way to do least squares solving is with a SVD decomposition. Eigen provides one as the JacobiSVD class, and its solve()
+is doing least-squares solving.
+
+Here is an example:
+<table class="example">
+<tr><th>Example:</th><th>Output:</th></tr>
+<tr>
+ <td>\include TutorialLinAlgSVDSolve.cpp </td>
+ <td>\verbinclude TutorialLinAlgSVDSolve.out </td>
+</tr>
+</table>
+
+Another way, potentially faster but less reliable, is to use a LDLT decomposition
+of the normal matrix. In any case, just read any reference text on least squares, and it will be very easy for you
+to implement any linear least squares computation on top of Eigen.
+
+\section TutorialLinAlgSeparateComputation Separating the computation from the construction
+
+In the above examples, the decomposition was computed at the same time that the decomposition object was constructed.
+There are however situations where you might want to separate these two things, for example if you don't know,
+at the time of the construction, the matrix that you will want to decompose; or if you want to reuse an existing
+decomposition object.
+
+What makes this possible is that:
+\li all decompositions have a default constructor,
+\li all decompositions have a compute(matrix) method that does the computation, and that may be called again
+ on an already-computed decomposition, reinitializing it.
+
+For example:
+
+<table class="example">
+<tr><th>Example:</th><th>Output:</th></tr>
+<tr>
+ <td>\include TutorialLinAlgComputeTwice.cpp </td>
+ <td>\verbinclude TutorialLinAlgComputeTwice.out </td>
+</tr>
+</table>
+
+Finally, you can tell the decomposition constructor to preallocate storage for decomposing matrices of a given size,
+so that when you subsequently decompose such matrices, no dynamic memory allocation is performed (of course, if you
+are using fixed-size matrices, no dynamic memory allocation happens at all). This is done by just
+passing the size to the decomposition constructor, as in this example:
+\code
+HouseholderQR<MatrixXf> qr(50,50);
+MatrixXf A = MatrixXf::Random(50,50);
+qr.compute(A); // no dynamic memory allocation
+\endcode
+
+\section TutorialLinAlgRankRevealing Rank-revealing decompositions
+
+Certain decompositions are rank-revealing, i.e. are able to compute the rank of a matrix. These are typically
+also the decompositions that behave best in the face of a non-full-rank matrix (which in the square case means a
+singular matrix). On \ref TopicLinearAlgebraDecompositions "this table" you can see for all our decompositions
+whether they are rank-revealing or not.
+
+Rank-revealing decompositions offer at least a rank() method. They can also offer convenience methods such as isInvertible(),
+and some are also providing methods to compute the kernel (null-space) and image (column-space) of the matrix, as is the
+case with FullPivLU:
+
+<table class="example">
+<tr><th>Example:</th><th>Output:</th></tr>
+<tr>
+ <td>\include TutorialLinAlgRankRevealing.cpp </td>
+ <td>\verbinclude TutorialLinAlgRankRevealing.out </td>
+</tr>
+</table>
+
+Of course, any rank computation depends on the choice of an arbitrary threshold, since practically no
+floating-point matrix is \em exactly rank-deficient. Eigen picks a sensible default threshold, which depends
+on the decomposition but is typically the diagonal size times machine epsilon. While this is the best default we
+could pick, only you know what is the right threshold for your application. You can set this by calling setThreshold()
+on your decomposition object before calling rank() or any other method that needs to use such a threshold.
+The decomposition itself, i.e. the compute() method, is independent of the threshold. You don't need to recompute the
+decomposition after you've changed the threshold.
+
+<table class="example">
+<tr><th>Example:</th><th>Output:</th></tr>
+<tr>
+ <td>\include TutorialLinAlgSetThreshold.cpp </td>
+ <td>\verbinclude TutorialLinAlgSetThreshold.out </td>
+</tr>
+</table>
+
+\li \b Next: \ref TutorialReductionsVisitorsBroadcasting
+
+*/
+
+}
diff --git a/doc/C07_TutorialReductionsVisitorsBroadcasting.dox b/doc/C07_TutorialReductionsVisitorsBroadcasting.dox
new file mode 100644
index 000000000..f3879b8b9
--- /dev/null
+++ b/doc/C07_TutorialReductionsVisitorsBroadcasting.dox
@@ -0,0 +1,273 @@
+namespace Eigen {
+
+/** \page TutorialReductionsVisitorsBroadcasting Tutorial page 7 - Reductions, visitors and broadcasting
+ \ingroup Tutorial
+
+\li \b Previous: \ref TutorialLinearAlgebra
+\li \b Next: \ref TutorialGeometry
+
+This tutorial explains Eigen's reductions, visitors and broadcasting and how they are used with
+\link MatrixBase matrices \endlink and \link ArrayBase arrays \endlink.
+
+\b Table \b of \b contents
+ - \ref TutorialReductionsVisitorsBroadcastingReductions
+ - \ref TutorialReductionsVisitorsBroadcastingReductionsNorm
+ - \ref TutorialReductionsVisitorsBroadcastingReductionsBool
+ - \ref TutorialReductionsVisitorsBroadcastingReductionsUserdefined
+ - \ref TutorialReductionsVisitorsBroadcastingVisitors
+ - \ref TutorialReductionsVisitorsBroadcastingPartialReductions
+ - \ref TutorialReductionsVisitorsBroadcastingPartialReductionsCombined
+ - \ref TutorialReductionsVisitorsBroadcastingBroadcasting
+ - \ref TutorialReductionsVisitorsBroadcastingBroadcastingCombined
+
+
+\section TutorialReductionsVisitorsBroadcastingReductions Reductions
+In Eigen, a reduction is a function taking a matrix or array, and returning a single
+scalar value. One of the most used reductions is \link DenseBase::sum() .sum() \endlink,
+returning the sum of all the coefficients inside a given matrix or array.
+
+<table class="example">
+<tr><th>Example:</th><th>Output:</th></tr>
+<tr><td>
+\include tut_arithmetic_redux_basic.cpp
+</td>
+<td>
+\verbinclude tut_arithmetic_redux_basic.out
+</td></tr></table>
+
+The \em trace of a matrix, as returned by the function \c trace(), is the sum of the diagonal coefficients and can equivalently be computed <tt>a.diagonal().sum()</tt>.
+
+
+\subsection TutorialReductionsVisitorsBroadcastingReductionsNorm Norm computations
+
+The (Euclidean a.k.a. \f$\ell^2\f$) squared norm of a vector can be obtained \link MatrixBase::squaredNorm() squaredNorm() \endlink. It is equal to the dot product of the vector by itself, and equivalently to the sum of squared absolute values of its coefficients.
+
+Eigen also provides the \link MatrixBase::norm() norm() \endlink method, which returns the square root of \link MatrixBase::squaredNorm() squaredNorm() \endlink.
+
+These operations can also operate on matrices; in that case, a n-by-p matrix is seen as a vector of size (n*p), so for example the \link MatrixBase::norm() norm() \endlink method returns the "Frobenius" or "Hilbert-Schmidt" norm. We refrain from speaking of the \f$\ell^2\f$ norm of a matrix because that can mean different things.
+
+If you want other \f$\ell^p\f$ norms, use the \link MatrixBase::lpNorm() lpNnorm<p>() \endlink method. The template parameter \a p can take the special value \a Infinity if you want the \f$\ell^\infty\f$ norm, which is the maximum of the absolute values of the coefficients.
+
+The following example demonstrates these methods.
+
+<table class="example">
+<tr><th>Example:</th><th>Output:</th></tr>
+<tr><td>
+\include Tutorial_ReductionsVisitorsBroadcasting_reductions_norm.cpp
+</td>
+<td>
+\verbinclude Tutorial_ReductionsVisitorsBroadcasting_reductions_norm.out
+</td></tr></table>
+
+\subsection TutorialReductionsVisitorsBroadcastingReductionsBool Boolean reductions
+
+The following reductions operate on boolean values:
+ - \link DenseBase::all() all() \endlink returns \b true if all of the coefficients in a given Matrix or Array evaluate to \b true .
+ - \link DenseBase::any() any() \endlink returns \b true if at least one of the coefficients in a given Matrix or Array evaluates to \b true .
+ - \link DenseBase::count() count() \endlink returns the number of coefficients in a given Matrix or Array that evaluate to \b true.
+
+These are typically used in conjunction with the coefficient-wise comparison and equality operators provided by Array. For instance, <tt>array > 0</tt> is an %Array of the same size as \c array , with \b true at those positions where the corresponding coefficient of \c array is positive. Thus, <tt>(array > 0).all()</tt> tests whether all coefficients of \c array are positive. This can be seen in the following example:
+
+<table class="example">
+<tr><th>Example:</th><th>Output:</th></tr>
+<tr><td>
+\include Tutorial_ReductionsVisitorsBroadcasting_reductions_bool.cpp
+</td>
+<td>
+\verbinclude Tutorial_ReductionsVisitorsBroadcasting_reductions_bool.out
+</td></tr></table>
+
+\subsection TutorialReductionsVisitorsBroadcastingReductionsUserdefined User defined reductions
+
+TODO
+
+In the meantime you can have a look at the DenseBase::redux() function.
+
+\section TutorialReductionsVisitorsBroadcastingVisitors Visitors
+Visitors are useful when one wants to obtain the location of a coefficient inside
+a Matrix or Array. The simplest examples are
+\link MatrixBase::maxCoeff() maxCoeff(&x,&y) \endlink and
+\link MatrixBase::minCoeff() minCoeff(&x,&y)\endlink, which can be used to find
+the location of the greatest or smallest coefficient in a Matrix or
+Array.
+
+The arguments passed to a visitor are pointers to the variables where the
+row and column position are to be stored. These variables should be of type
+\link DenseBase::Index Index \endlink, as shown below:
+
+<table class="example">
+<tr><th>Example:</th><th>Output:</th></tr>
+<tr><td>
+\include Tutorial_ReductionsVisitorsBroadcasting_visitors.cpp
+</td>
+<td>
+\verbinclude Tutorial_ReductionsVisitorsBroadcasting_visitors.out
+</td></tr></table>
+
+Note that both functions also return the value of the minimum or maximum coefficient if needed,
+as if it was a typical reduction operation.
+
+\section TutorialReductionsVisitorsBroadcastingPartialReductions Partial reductions
+Partial reductions are reductions that can operate column- or row-wise on a Matrix or
+Array, applying the reduction operation on each column or row and
+returning a column or row-vector with the corresponding values. Partial reductions are applied
+with \link DenseBase::colwise() colwise() \endlink or \link DenseBase::rowwise() rowwise() \endlink.
+
+A simple example is obtaining the maximum of the elements
+in each column in a given matrix, storing the result in a row-vector:
+
+<table class="example">
+<tr><th>Example:</th><th>Output:</th></tr>
+<tr><td>
+\include Tutorial_ReductionsVisitorsBroadcasting_colwise.cpp
+</td>
+<td>
+\verbinclude Tutorial_ReductionsVisitorsBroadcasting_colwise.out
+</td></tr></table>
+
+The same operation can be performed row-wise:
+
+<table class="example">
+<tr><th>Example:</th><th>Output:</th></tr>
+<tr><td>
+\include Tutorial_ReductionsVisitorsBroadcasting_rowwise.cpp
+</td>
+<td>
+\verbinclude Tutorial_ReductionsVisitorsBroadcasting_rowwise.out
+</td></tr></table>
+
+<b>Note that column-wise operations return a 'row-vector' while row-wise operations
+return a 'column-vector'</b>
+
+\subsection TutorialReductionsVisitorsBroadcastingPartialReductionsCombined Combining partial reductions with other operations
+It is also possible to use the result of a partial reduction to do further processing.
+Here is another example that finds the column whose sum of elements is the maximum
+ within a matrix. With column-wise partial reductions this can be coded as:
+
+<table class="example">
+<tr><th>Example:</th><th>Output:</th></tr>
+<tr><td>
+\include Tutorial_ReductionsVisitorsBroadcasting_maxnorm.cpp
+</td>
+<td>
+\verbinclude Tutorial_ReductionsVisitorsBroadcasting_maxnorm.out
+</td></tr></table>
+
+The previous example applies the \link DenseBase::sum() sum() \endlink reduction on each column
+though the \link DenseBase::colwise() colwise() \endlink visitor, obtaining a new matrix whose
+size is 1x4.
+
+Therefore, if
+\f[
+\mbox{m} = \begin{bmatrix} 1 & 2 & 6 & 9 \\
+ 3 & 1 & 7 & 2 \end{bmatrix}
+\f]
+
+then
+
+\f[
+\mbox{m.colwise().sum()} = \begin{bmatrix} 4 & 3 & 13 & 11 \end{bmatrix}
+\f]
+
+The \link DenseBase::maxCoeff() maxCoeff() \endlink reduction is finally applied
+to obtain the column index where the maximum sum is found,
+which is the column index 2 (third column) in this case.
+
+
+\section TutorialReductionsVisitorsBroadcastingBroadcasting Broadcasting
+The concept behind broadcasting is similar to partial reductions, with the difference that broadcasting
+constructs an expression where a vector (column or row) is interpreted as a matrix by replicating it in
+one direction.
+
+A simple example is to add a certain column-vector to each column in a matrix.
+This can be accomplished with:
+
+<table class="example">
+<tr><th>Example:</th><th>Output:</th></tr>
+<tr><td>
+\include Tutorial_ReductionsVisitorsBroadcasting_broadcast_simple.cpp
+</td>
+<td>
+\verbinclude Tutorial_ReductionsVisitorsBroadcasting_broadcast_simple.out
+</td></tr></table>
+
+We can interpret the instruction <tt>mat.colwise() += v</tt> in two equivalent ways. It adds the vector \c v
+to every column of the matrix. Alternatively, it can be interpreted as repeating the vector \c v four times to
+form a four-by-two matrix which is then added to \c mat:
+\f[
+\begin{bmatrix} 1 & 2 & 6 & 9 \\ 3 & 1 & 7 & 2 \end{bmatrix}
++ \begin{bmatrix} 0 & 0 & 0 & 0 \\ 1 & 1 & 1 & 1 \end{bmatrix}
+= \begin{bmatrix} 1 & 2 & 6 & 9 \\ 4 & 2 & 8 & 3 \end{bmatrix}.
+\f]
+The operators <tt>-=</tt>, <tt>+</tt> and <tt>-</tt> can also be used column-wise and row-wise. On arrays, we
+can also use the operators <tt>*=</tt>, <tt>/=</tt>, <tt>*</tt> and <tt>/</tt> to perform coefficient-wise
+multiplication and division column-wise or row-wise. These operators are not available on matrices because it
+is not clear what they would do. If you want multiply column 0 of a matrix \c mat with \c v(0), column 1 with
+\c v(1), and so on, then use <tt>mat = mat * v.asDiagonal()</tt>.
+
+It is important to point out that the vector to be added column-wise or row-wise must be of type Vector,
+and cannot be a Matrix. If this is not met then you will get compile-time error. This also means that
+broadcasting operations can only be applied with an object of type Vector, when operating with Matrix.
+The same applies for the Array class, where the equivalent for VectorXf is ArrayXf. As always, you should
+not mix arrays and matrices in the same expression.
+
+To perform the same operation row-wise we can do:
+
+<table class="example">
+<tr><th>Example:</th><th>Output:</th></tr>
+<tr><td>
+\include Tutorial_ReductionsVisitorsBroadcasting_broadcast_simple_rowwise.cpp
+</td>
+<td>
+\verbinclude Tutorial_ReductionsVisitorsBroadcasting_broadcast_simple_rowwise.out
+</td></tr></table>
+
+\subsection TutorialReductionsVisitorsBroadcastingBroadcastingCombined Combining broadcasting with other operations
+Broadcasting can also be combined with other operations, such as Matrix or Array operations,
+reductions and partial reductions.
+
+Now that broadcasting, reductions and partial reductions have been introduced, we can dive into a more advanced example that finds
+the nearest neighbour of a vector <tt>v</tt> within the columns of matrix <tt>m</tt>. The Euclidean distance will be used in this example,
+computing the squared Euclidean distance with the partial reduction named \link MatrixBase::squaredNorm() squaredNorm() \endlink:
+
+<table class="example">
+<tr><th>Example:</th><th>Output:</th></tr>
+<tr><td>
+\include Tutorial_ReductionsVisitorsBroadcasting_broadcast_1nn.cpp
+</td>
+<td>
+\verbinclude Tutorial_ReductionsVisitorsBroadcasting_broadcast_1nn.out
+</td></tr></table>
+
+The line that does the job is
+\code
+ (m.colwise() - v).colwise().squaredNorm().minCoeff(&index);
+\endcode
+
+We will go step by step to understand what is happening:
+
+ - <tt>m.colwise() - v</tt> is a broadcasting operation, subtracting <tt>v</tt> from each column in <tt>m</tt>. The result of this operation
+is a new matrix whose size is the same as matrix <tt>m</tt>: \f[
+ \mbox{m.colwise() - v} =
+ \begin{bmatrix}
+ -1 & 21 & 4 & 7 \\
+ 0 & 8 & 4 & -1
+ \end{bmatrix}
+\f]
+
+ - <tt>(m.colwise() - v).colwise().squaredNorm()</tt> is a partial reduction, computing the squared norm column-wise. The result of
+this operation is a row-vector where each coefficient is the squared Euclidean distance between each column in <tt>m</tt> and <tt>v</tt>: \f[
+ \mbox{(m.colwise() - v).colwise().squaredNorm()} =
+ \begin{bmatrix}
+ 1 & 505 & 32 & 50
+ \end{bmatrix}
+\f]
+
+ - Finally, <tt>minCoeff(&index)</tt> is used to obtain the index of the column in <tt>m</tt> that is closest to <tt>v</tt> in terms of Euclidean
+distance.
+
+\li \b Next: \ref TutorialGeometry
+
+*/
+
+}
diff --git a/doc/C08_TutorialGeometry.dox b/doc/C08_TutorialGeometry.dox
new file mode 100644
index 000000000..b9e9eba12
--- /dev/null
+++ b/doc/C08_TutorialGeometry.dox
@@ -0,0 +1,251 @@
+namespace Eigen {
+
+/** \page TutorialGeometry Tutorial page 8 - Geometry
+ \ingroup Tutorial
+
+\li \b Previous: \ref TutorialReductionsVisitorsBroadcasting
+\li \b Next: \ref TutorialSparse
+
+In this tutorial, we will briefly introduce the many possibilities offered by the \ref Geometry_Module "geometry module", namely 2D and 3D rotations and projective or affine transformations.
+
+\b Table \b of \b contents
+ - \ref TutorialGeoElementaryTransformations
+ - \ref TutorialGeoCommontransformationAPI
+ - \ref TutorialGeoTransform
+ - \ref TutorialGeoEulerAngles
+
+Eigen's Geometry module provides two different kinds of geometric transformations:
+ - Abstract transformations, such as rotations (represented by \ref AngleAxis "angle and axis" or by a \ref Quaternion "quaternion"), \ref Translation "translations", \ref Scaling "scalings". These transformations are NOT represented as matrices, but you can nevertheless mix them with matrices and vectors in expressions, and convert them to matrices if you wish.
+ - Projective or affine transformation matrices: see the Transform class. These are really matrices.
+
+\note If you are working with OpenGL 4x4 matrices then Affine3f and Affine3d are what you want. Since Eigen defaults to column-major storage, you can directly use the Transform::data() method to pass your transformation matrix to OpenGL.
+
+You can construct a Transform from an abstract transformation, like this:
+\code
+ Transform t(AngleAxis(angle,axis));
+\endcode
+or like this:
+\code
+ Transform t;
+ t = AngleAxis(angle,axis);
+\endcode
+But note that unfortunately, because of how C++ works, you can \b not do this:
+\code
+ Transform t = AngleAxis(angle,axis);
+\endcode
+<span class="note">\b Explanation: In the C++ language, this would require Transform to have a non-explicit conversion constructor from AngleAxis, but we really don't want to allow implicit casting here.
+</span>
+
+\section TutorialGeoElementaryTransformations Transformation types
+
+<table class="manual">
+<tr><th>Transformation type</th><th>Typical initialization code</th></tr>
+<tr><td>
+\ref Rotation2D "2D rotation" from an angle</td><td>\code
+Rotation2D<float> rot2(angle_in_radian);\endcode</td></tr>
+<tr class="alt"><td>
+3D rotation as an \ref AngleAxis "angle + axis"</td><td>\code
+AngleAxis<float> aa(angle_in_radian, Vector3f(ax,ay,az));\endcode
+<span class="note">The axis vector must be normalized.</span></td></tr>
+<tr><td>
+3D rotation as a \ref Quaternion "quaternion"</td><td>\code
+Quaternion<float> q; q = AngleAxis<float>(angle_in_radian, axis);\endcode</td></tr>
+<tr class="alt"><td>
+N-D Scaling</td><td>\code
+Scaling(sx, sy)
+Scaling(sx, sy, sz)
+Scaling(s)
+Scaling(vecN)\endcode</td></tr>
+<tr><td>
+N-D Translation</td><td>\code
+Translation<float,2>(tx, ty)
+Translation<float,3>(tx, ty, tz)
+Translation<float,N>(s)
+Translation<float,N>(vecN)\endcode</td></tr>
+<tr class="alt"><td>
+N-D \ref TutorialGeoTransform "Affine transformation"</td><td>\code
+Transform<float,N,Affine> t = concatenation_of_any_transformations;
+Transform<float,3,Affine> t = Translation3f(p) * AngleAxisf(a,axis) * Scaling(s);\endcode</td></tr>
+<tr><td>
+N-D Linear transformations \n
+<em class=note>(pure rotations, \n scaling, etc.)</em></td><td>\code
+Matrix<float,N> t = concatenation_of_rotations_and_scalings;
+Matrix<float,2> t = Rotation2Df(a) * Scaling(s);
+Matrix<float,3> t = AngleAxisf(a,axis) * Scaling(s);\endcode</td></tr>
+</table>
+
+<strong>Notes on rotations</strong>\n To transform more than a single vector the preferred
+representations are rotation matrices, while for other usages Quaternion is the
+representation of choice as they are compact, fast and stable. Finally Rotation2D and
+AngleAxis are mainly convenient types to create other rotation objects.
+
+<strong>Notes on Translation and Scaling</strong>\n Like AngleAxis, these classes were
+designed to simplify the creation/initialization of linear (Matrix) and affine (Transform)
+transformations. Nevertheless, unlike AngleAxis which is inefficient to use, these classes
+might still be interesting to write generic and efficient algorithms taking as input any
+kind of transformations.
+
+Any of the above transformation types can be converted to any other types of the same nature,
+or to a more generic type. Here are some additional examples:
+<table class="manual">
+<tr><td>\code
+Rotation2Df r; r = Matrix2f(..); // assumes a pure rotation matrix
+AngleAxisf aa; aa = Quaternionf(..);
+AngleAxisf aa; aa = Matrix3f(..); // assumes a pure rotation matrix
+Matrix2f m; m = Rotation2Df(..);
+Matrix3f m; m = Quaternionf(..); Matrix3f m; m = Scaling(..);
+Affine3f m; m = AngleAxis3f(..); Affine3f m; m = Scaling(..);
+Affine3f m; m = Translation3f(..); Affine3f m; m = Matrix3f(..);
+\endcode</td></tr>
+</table>
+
+
+<a href="#" class="top">top</a>\section TutorialGeoCommontransformationAPI Common API across transformation types
+
+To some extent, Eigen's \ref Geometry_Module "geometry module" allows you to write
+generic algorithms working on any kind of transformation representations:
+<table class="manual">
+<tr><td>
+Concatenation of two transformations</td><td>\code
+gen1 * gen2;\endcode</td></tr>
+<tr class="alt"><td>Apply the transformation to a vector</td><td>\code
+vec2 = gen1 * vec1;\endcode</td></tr>
+<tr><td>Get the inverse of the transformation</td><td>\code
+gen2 = gen1.inverse();\endcode</td></tr>
+<tr class="alt"><td>Spherical interpolation \n (Rotation2D and Quaternion only)</td><td>\code
+rot3 = rot1.slerp(alpha,rot2);\endcode</td></tr>
+</table>
+
+
+
+<a href="#" class="top">top</a>\section TutorialGeoTransform Affine transformations
+Generic affine transformations are represented by the Transform class which internaly
+is a (Dim+1)^2 matrix. In Eigen we have chosen to not distinghish between points and
+vectors such that all points are actually represented by displacement vectors from the
+origin ( \f$ \mathbf{p} \equiv \mathbf{p}-0 \f$ ). With that in mind, real points and
+vector distinguish when the transformation is applied.
+<table class="manual">
+<tr><td>
+Apply the transformation to a \b point </td><td>\code
+VectorNf p1, p2;
+p2 = t * p1;\endcode</td></tr>
+<tr class="alt"><td>
+Apply the transformation to a \b vector </td><td>\code
+VectorNf vec1, vec2;
+vec2 = t.linear() * vec1;\endcode</td></tr>
+<tr><td>
+Apply a \em general transformation \n to a \b normal \b vector
+(<a href="http://www.cgafaq.info/wiki/Transforming_normals">explanations</a>)</td><td>\code
+VectorNf n1, n2;
+MatrixNf normalMatrix = t.linear().inverse().transpose();
+n2 = (normalMatrix * n1).normalized();\endcode</td></tr>
+<tr class="alt"><td>
+Apply a transformation with \em pure \em rotation \n to a \b normal \b vector
+(no scaling, no shear)</td><td>\code
+n2 = t.linear() * n1;\endcode</td></tr>
+<tr><td>
+OpenGL compatibility \b 3D </td><td>\code
+glLoadMatrixf(t.data());\endcode</td></tr>
+<tr class="alt"><td>
+OpenGL compatibility \b 2D </td><td>\code
+Affine3f aux(Affine3f::Identity());
+aux.linear().topLeftCorner<2,2>() = t.linear();
+aux.translation().start<2>() = t.translation();
+glLoadMatrixf(aux.data());\endcode</td></tr>
+</table>
+
+\b Component \b accessors
+<table class="manual">
+<tr><td>
+full read-write access to the internal matrix</td><td>\code
+t.matrix() = matN1xN1; // N1 means N+1
+matN1xN1 = t.matrix();
+\endcode</td></tr>
+<tr class="alt"><td>
+coefficient accessors</td><td>\code
+t(i,j) = scalar; <=> t.matrix()(i,j) = scalar;
+scalar = t(i,j); <=> scalar = t.matrix()(i,j);
+\endcode</td></tr>
+<tr><td>
+translation part</td><td>\code
+t.translation() = vecN;
+vecN = t.translation();
+\endcode</td></tr>
+<tr class="alt"><td>
+linear part</td><td>\code
+t.linear() = matNxN;
+matNxN = t.linear();
+\endcode</td></tr>
+<tr><td>
+extract the rotation matrix</td><td>\code
+matNxN = t.extractRotation();
+\endcode</td></tr>
+</table>
+
+
+\b Transformation \b creation \n
+While transformation objects can be created and updated concatenating elementary transformations,
+the Transform class also features a procedural API:
+<table class="manual">
+<tr><th></th><th>procedural API</th><th>equivalent natural API </th></tr>
+<tr><td>Translation</td><td>\code
+t.translate(Vector_(tx,ty,..));
+t.pretranslate(Vector_(tx,ty,..));
+\endcode</td><td>\code
+t *= Translation_(tx,ty,..);
+t = Translation_(tx,ty,..) * t;
+\endcode</td></tr>
+<tr class="alt"><td>\b Rotation \n <em class="note">In 2D and for the procedural API, any_rotation can also \n be an angle in radian</em></td><td>\code
+t.rotate(any_rotation);
+t.prerotate(any_rotation);
+\endcode</td><td>\code
+t *= any_rotation;
+t = any_rotation * t;
+\endcode</td></tr>
+<tr><td>Scaling</td><td>\code
+t.scale(Vector_(sx,sy,..));
+t.scale(s);
+t.prescale(Vector_(sx,sy,..));
+t.prescale(s);
+\endcode</td><td>\code
+t *= Scaling(sx,sy,..);
+t *= Scaling(s);
+t = Scaling(sx,sy,..) * t;
+t = Scaling(s) * t;
+\endcode</td></tr>
+<tr class="alt"><td>Shear transformation \n ( \b 2D \b only ! )</td><td>\code
+t.shear(sx,sy);
+t.preshear(sx,sy);
+\endcode</td><td></td></tr>
+</table>
+
+Note that in both API, any many transformations can be concatenated in a single expression as shown in the two following equivalent examples:
+<table class="manual">
+<tr><td>\code
+t.pretranslate(..).rotate(..).translate(..).scale(..);
+\endcode</td></tr>
+<tr><td>\code
+t = Translation_(..) * t * RotationType(..) * Translation_(..) * Scaling(..);
+\endcode</td></tr>
+</table>
+
+
+
+<a href="#" class="top">top</a>\section TutorialGeoEulerAngles Euler angles
+<table class="manual">
+<tr><td style="max-width:30em;">
+Euler angles might be convenient to create rotation objects.
+On the other hand, since there exist 24 different conventions, they are pretty confusing to use. This example shows how
+to create a rotation matrix according to the 2-1-2 convention.</td><td>\code
+Matrix3f m;
+m = AngleAxisf(angle1, Vector3f::UnitZ())
+* * AngleAxisf(angle2, Vector3f::UnitY())
+* * AngleAxisf(angle3, Vector3f::UnitZ());
+\endcode</td></tr>
+</table>
+
+\li \b Next: \ref TutorialSparse
+
+*/
+
+}
diff --git a/doc/C09_TutorialSparse.dox b/doc/C09_TutorialSparse.dox
new file mode 100644
index 000000000..34154bd0d
--- /dev/null
+++ b/doc/C09_TutorialSparse.dox
@@ -0,0 +1,455 @@
+namespace Eigen {
+
+/** \page TutorialSparse Tutorial page 9 - Sparse Matrix
+ \ingroup Tutorial
+
+\li \b Previous: \ref TutorialGeometry
+\li \b Next: \ref TutorialMapClass
+
+\b Table \b of \b contents \n
+ - \ref TutorialSparseIntro
+ - \ref TutorialSparseExample "Example"
+ - \ref TutorialSparseSparseMatrix
+ - \ref TutorialSparseFilling
+ - \ref TutorialSparseDirectSolvers
+ - \ref TutorialSparseFeatureSet
+ - \ref TutorialSparse_BasicOps
+ - \ref TutorialSparse_Products
+ - \ref TutorialSparse_TriangularSelfadjoint
+ - \ref TutorialSparse_Submat
+
+
+<hr>
+
+Manipulating and solving sparse problems involves various modules which are summarized below:
+
+<table class="manual">
+<tr><th>Module</th><th>Header file</th><th>Contents</th></tr>
+<tr><td>\link Sparse_Module SparseCore \endlink</td><td>\code#include <Eigen/SparseCore>\endcode</td><td>SparseMatrix and SparseVector classes, matrix assembly, basic sparse linear algebra (including sparse triangular solvers)</td></tr>
+<tr><td>\link SparseCholesky_Module SparseCholesky \endlink</td><td>\code#include <Eigen/SparseCholesky>\endcode</td><td>Direct sparse LLT and LDLT Cholesky factorization to solve sparse self-adjoint positive definite problems</td></tr>
+<tr><td>\link IterativeLinearSolvers_Module IterativeLinearSolvers \endlink</td><td>\code#include <Eigen/IterativeLinearSolvers>\endcode</td><td>Iterative solvers to solve large general linear square problems (including self-adjoint positive definite problems)</td></tr>
+<tr><td></td><td>\code#include <Eigen/Sparse>\endcode</td><td>Includes all the above modules</td></tr>
+</table>
+
+\section TutorialSparseIntro Sparse matrix representation
+
+In many applications (e.g., finite element methods) it is common to deal with very large matrices where only a few coefficients are different from zero. In such cases, memory consumption can be reduced and performance increased by using a specialized representation storing only the nonzero coefficients. Such a matrix is called a sparse matrix.
+
+\b The \b %SparseMatrix \b class
+
+The class SparseMatrix is the main sparse matrix representation of Eigen's sparse module; it offers high performance and low memory usage.
+It implements a more versatile variant of the widely-used Compressed Column (or Row) Storage scheme.
+It consists of four compact arrays:
+ - \c Values: stores the coefficient values of the non-zeros.
+ - \c InnerIndices: stores the row (resp. column) indices of the non-zeros.
+ - \c OuterStarts: stores for each column (resp. row) the index of the first non-zero in the previous two arrays.
+ - \c InnerNNZs: stores the number of non-zeros of each column (resp. row).
+The word \c inner refers to an \em inner \em vector that is a column for a column-major matrix, or a row for a row-major matrix.
+The word \c outer refers to the other direction.
+
+This storage scheme is better explained on an example. The following matrix
+<table class="manual">
+<tr><td> 0</td><td>3</td><td> 0</td><td>0</td><td> 0</td></tr>
+<tr><td>22</td><td>0</td><td> 0</td><td>0</td><td>17</td></tr>
+<tr><td> 7</td><td>5</td><td> 0</td><td>1</td><td> 0</td></tr>
+<tr><td> 0</td><td>0</td><td> 0</td><td>0</td><td> 0</td></tr>
+<tr><td> 0</td><td>0</td><td>14</td><td>0</td><td> 8</td></tr>
+</table>
+
+and one of its possible sparse, \b column \b major representation:
+<table class="manual">
+<tr><td>Values:</td> <td>22</td><td>7</td><td>_</td><td>3</td><td>5</td><td>14</td><td>_</td><td>_</td><td>1</td><td>_</td><td>17</td><td>8</td></tr>
+<tr><td>InnerIndices:</td> <td> 1</td><td>2</td><td>_</td><td>0</td><td>2</td><td> 4</td><td>_</td><td>_</td><td>2</td><td>_</td><td> 1</td><td>4</td></tr>
+</table>
+<table class="manual">
+<tr><td>OuterStarts:</td><td>0</td><td>3</td><td>5</td><td>8</td><td>10</td><td>\em 12 </td></tr>
+<tr><td>InnerNNZs:</td> <td>2</td><td>2</td><td>1</td><td>1</td><td> 2</td><td></td></tr>
+</table>
+
+Currently the elements of a given inner vector are guaranteed to be always sorted by increasing inner indices.
+The \c "_" indicates available free space to quickly insert new elements.
+Assuming no reallocation is needed, the insertion of a random element is therefore in O(nnz_j) where nnz_j is the number of nonzeros of the respective inner vector.
+On the other hand, inserting elements with increasing inner indices in a given inner vector is much more efficient since this only requires to increase the respective \c InnerNNZs entry that is a O(1) operation.
+
+The case where no empty space is available is a special case, and is refered as the \em compressed mode.
+It corresponds to the widely used Compressed Column (or Row) Storage schemes (CCS or CRS).
+Any SparseMatrix can be turned to this form by calling the SparseMatrix::makeCompressed() function.
+In this case, one can remark that the \c InnerNNZs array is redundant with \c OuterStarts because we the equality: \c InnerNNZs[j] = \c OuterStarts[j+1]-\c OuterStarts[j].
+Therefore, in practice a call to SparseMatrix::makeCompressed() frees this buffer.
+
+It is worth noting that most of our wrappers to external libraries requires compressed matrices as inputs.
+
+The results of %Eigen's operations always produces \b compressed sparse matrices.
+On the other hand, the insertion of a new element into a SparseMatrix converts this later to the \b uncompressed mode.
+
+Here is the previous matrix represented in compressed mode:
+<table class="manual">
+<tr><td>Values:</td> <td>22</td><td>7</td><td>3</td><td>5</td><td>14</td><td>1</td><td>17</td><td>8</td></tr>
+<tr><td>InnerIndices:</td> <td> 1</td><td>2</td><td>0</td><td>2</td><td> 4</td><td>2</td><td> 1</td><td>4</td></tr>
+</table>
+<table class="manual">
+<tr><td>OuterStarts:</td><td>0</td><td>2</td><td>4</td><td>5</td><td>6</td><td>\em 8 </td></tr>
+</table>
+
+A SparseVector is a special case of a SparseMatrix where only the \c Values and \c InnerIndices arrays are stored.
+There is no notion of compressed/uncompressed mode for a SparseVector.
+
+
+\section TutorialSparseExample First example
+
+Before describing each individual class, let's start with the following typical example: solving the Lapace equation \f$ \nabla u = 0 \f$ on a regular 2D grid using a finite difference scheme and Dirichlet boundary conditions.
+Such problem can be mathematically expressed as a linear problem of the form \f$ Ax=b \f$ where \f$ x \f$ is the vector of \c m unknowns (in our case, the values of the pixels), \f$ b \f$ is the right hand side vector resulting from the boundary conditions, and \f$ A \f$ is an \f$ m \times m \f$ matrix containing only a few non-zero elements resulting from the discretization of the Laplacian operator.
+
+<table class="manual">
+<tr><td>
+\include Tutorial_sparse_example.cpp
+</td>
+<td>
+\image html Tutorial_sparse_example.jpeg
+</td></tr></table>
+
+In this example, we start by defining a column-major sparse matrix type of double \c SparseMatrix<double>, and a triplet list of the same scalar type \c Triplet<double>. A triplet is a simple object representing a non-zero entry as the triplet: \c row index, \c column index, \c value.
+
+In the main function, we declare a list \c coefficients of triplets (as a std vector) and the right hand side vector \f$ b \f$ which are filled by the \a buildProblem function.
+The raw and flat list of non-zero entries is then converted to a true SparseMatrix object \c A.
+Note that the elements of the list do not have to be sorted, and possible duplicate entries will be summed up.
+
+The last step consists of effectively solving the assembled problem.
+Since the resulting matrix \c A is symmetric by construction, we can perform a direct Cholesky factorization via the SimplicialLDLT class which behaves like its LDLT counterpart for dense objects.
+
+The resulting vector \c x contains the pixel values as a 1D array which is saved to a jpeg file shown on the right of the code above.
+
+Describing the \a buildProblem and \a save functions is out of the scope of this tutorial. They are given \ref TutorialSparse_example_details "here" for the curious and reproducibility purpose.
+
+
+
+
+\section TutorialSparseSparseMatrix The SparseMatrix class
+
+\b %Matrix \b and \b vector \b properties \n
+
+The SparseMatrix and SparseVector classes take three template arguments:
+ * the scalar type (e.g., double)
+ * the storage order (ColMajor or RowMajor, the default is RowMajor)
+ * the inner index type (default is \c int).
+
+As for dense Matrix objects, constructors takes the size of the object.
+Here are some examples:
+
+\code
+SparseMatrix<std::complex<float> > mat(1000,2000); // declares a 1000x2000 column-major compressed sparse matrix of complex<float>
+SparseMatrix<double,RowMajor> mat(1000,2000); // declares a 1000x2000 row-major compressed sparse matrix of double
+SparseVector<std::complex<float> > vec(1000); // declares a column sparse vector of complex<float> of size 1000
+SparseVector<double,RowMajor> vec(1000); // declares a row sparse vector of double of size 1000
+\endcode
+
+In the rest of the tutorial, \c mat and \c vec represent any sparse-matrix and sparse-vector objects, respectively.
+
+The dimensions of a matrix can be queried using the following functions:
+<table class="manual">
+<tr><td>Standard \n dimensions</td><td>\code
+mat.rows()
+mat.cols()\endcode</td>
+<td>\code
+vec.size() \endcode</td>
+</tr>
+<tr><td>Sizes along the \n inner/outer dimensions</td><td>\code
+mat.innerSize()
+mat.outerSize()\endcode</td>
+<td></td>
+</tr>
+<tr><td>Number of non \n zero coefficients</td><td>\code
+mat.nonZeros() \endcode</td>
+<td>\code
+vec.nonZeros() \endcode</td></tr>
+</table>
+
+
+\b Iterating \b over \b the \b nonzero \b coefficients \n
+
+Random access to the elements of a sparse object can be done through the \c coeffRef(i,j) function.
+However, this function involves a quite expensive binary search.
+In most cases, one only wants to iterate over the non-zeros elements. This is achieved by a standard loop over the outer dimension, and then by iterating over the non-zeros of the current inner vector via an InnerIterator. Thus, the non-zero entries have to be visited in the same order than the storage order.
+Here is an example:
+<table class="manual">
+<tr><td>
+\code
+SparseMatrix<double> mat(rows,cols);
+for (int k=0; k<mat.outerSize(); ++k)
+ for (SparseMatrix<double>::InnerIterator it(mat,k); it; ++it)
+ {
+ it.value();
+ it.row(); // row index
+ it.col(); // col index (here it is equal to k)
+ it.index(); // inner index, here it is equal to it.row()
+ }
+\endcode
+</td><td>
+\code
+SparseVector<double> vec(size);
+for (SparseVector<double>::InnerIterator it(vec); it; ++it)
+{
+ it.value(); // == vec[ it.index() ]
+ it.index();
+}
+\endcode
+</td></tr>
+</table>
+For a writable expression, the referenced value can be modified using the valueRef() function.
+If the type of the sparse matrix or vector depends on a template parameter, then the \c typename keyword is
+required to indicate that \c InnerIterator denotes a type; see \ref TopicTemplateKeyword for details.
+
+
+\section TutorialSparseFilling Filling a sparse matrix
+
+Because of the special storage scheme of a SparseMatrix, special care has to be taken when adding new nonzero entries.
+For instance, the cost of a single purely random insertion into a SparseMatrix is \c O(nnz), where \c nnz is the current number of non-zero coefficients.
+
+The simplest way to create a sparse matrix while guaranteeing good performance is thus to first build a list of so-called \em triplets, and then convert it to a SparseMatrix.
+
+Here is a typical usage example:
+\code
+typedef Eigen::Triplet<double> T;
+std::vector<T> tripletList;
+triplets.reserve(estimation_of_entries);
+for(...)
+{
+ // ...
+ tripletList.push_back(T(i,j,v_ij));
+}
+SparseMatrixType mat(rows,cols);
+mat.setFromTriplets(tripletList.begin(), tripletList.end());
+// mat is ready to go!
+\endcode
+The \c std::vector of triplets might contain the elements in arbitrary order, and might even contain duplicated elements that will be summed up by setFromTriplets().
+See the SparseMatrix::setFromTriplets() function and class Triplet for more details.
+
+
+In some cases, however, slightly higher performance, and lower memory consumption can be reached by directly inserting the non-zeros into the destination matrix.
+A typical scenario of this approach is illustrated bellow:
+\code
+1: SparseMatrix<double> mat(rows,cols); // default is column major
+2: mat.reserve(VectorXi::Constant(cols,6));
+3: for each i,j such that v_ij != 0
+4: mat.insert(i,j) = v_ij; // alternative: mat.coeffRef(i,j) += v_ij;
+5: mat.makeCompressed(); // optional
+\endcode
+
+- The key ingredient here is the line 2 where we reserve room for 6 non-zeros per column. In many cases, the number of non-zeros per column or row can easily be known in advance. If it varies significantly for each inner vector, then it is possible to specify a reserve size for each inner vector by providing a vector object with an operator[](int j) returning the reserve size of the \c j-th inner vector (e.g., via a VectorXi or std::vector<int>). If only a rought estimate of the number of nonzeros per inner-vector can be obtained, it is highly recommended to overestimate it rather than the opposite. If this line is omitted, then the first insertion of a new element will reserve room for 2 elements per inner vector.
+- The line 4 performs a sorted insertion. In this example, the ideal case is when the \c j-th column is not full and contains non-zeros whose inner-indices are smaller than \c i. In this case, this operation boils down to trivial O(1) operation.
+- When calling insert(i,j) the element \c i \c ,j must not already exists, otherwise use the coeffRef(i,j) method that will allow to, e.g., accumulate values. This method first performs a binary search and finally calls insert(i,j) if the element does not already exist. It is more flexible than insert() but also more costly.
+- The line 5 suppresses the remaining empty space and transforms the matrix into a compressed column storage.
+
+
+\section TutorialSparseDirectSolvers Solving linear problems
+
+%Eigen currently provides a limited set of built-in solvers, as well as wrappers to external solver libraries.
+They are summarized in the following table:
+
+<table class="manual">
+<tr><th>Class</th><th>Module</th><th>Solver kind</th><th>Matrix kind</th><th>Features related to performance</th>
+ <th>Dependencies,License</th><th class="width20em"><p>Notes</p></th></tr>
+<tr><td>SimplicialLLT </td><td>\link SparseCholesky_Module SparseCholesky \endlink</td><td>Direct LLt factorization</td><td>SPD</td><td>Fill-in reducing</td>
+ <td>built-in, LGPL</td>
+ <td>SimplicialLDLT is often preferable</td></tr>
+<tr><td>SimplicialLDLT </td><td>\link SparseCholesky_Module SparseCholesky \endlink</td><td>Direct LDLt factorization</td><td>SPD</td><td>Fill-in reducing</td>
+ <td>built-in, LGPL</td>
+ <td>Recommended for very sparse and not too large problems (e.g., 2D Poisson eq.)</td></tr>
+<tr><td>ConjugateGradient</td><td>\link IterativeLinearSolvers_Module IterativeLinearSolvers \endlink</td><td>Classic iterative CG</td><td>SPD</td><td>Preconditionning</td>
+ <td>built-in, LGPL</td>
+ <td>Recommended for large symmetric problems (e.g., 3D Poisson eq.)</td></tr>
+<tr><td>BiCGSTAB</td><td>\link IterativeLinearSolvers_Module IterativeLinearSolvers \endlink</td><td>Iterative stabilized bi-conjugate gradient</td><td>Square</td><td>Preconditionning</td>
+ <td>built-in, LGPL</td>
+ <td>Might not always converge</td></tr>
+
+
+<tr><td>PastixLLT \n PastixLDLT \n PastixLU</td><td>\link PaStiXSupport_Module PaStiXSupport \endlink</td><td>Direct LLt, LDLt, LU factorizations</td><td>SPD \n SPD \n Square</td><td>Fill-in reducing, Leverage fast dense algebra, Multithreading</td>
+ <td>Requires the <a href="http://pastix.gforge.inria.fr">PaStiX</a> package, \b CeCILL-C </td>
+ <td>optimized for tough problems and symmetric patterns</td></tr>
+<tr><td>CholmodSupernodalLLT</td><td>\link CholmodSupport_Module CholmodSupport \endlink</td><td>Direct LLt factorization</td><td>SPD</td><td>Fill-in reducing, Leverage fast dense algebra</td>
+ <td>Requires the <a href="http://www.cise.ufl.edu/research/sparse/SuiteSparse/">SuiteSparse</a> package, \b GPL </td>
+ <td></td></tr>
+<tr><td>UmfPackLU</td><td>\link UmfPackSupport_Module UmfPackSupport \endlink</td><td>Direct LU factorization</td><td>Square</td><td>Fill-in reducing, Leverage fast dense algebra</td>
+ <td>Requires the <a href="http://www.cise.ufl.edu/research/sparse/SuiteSparse/">SuiteSparse</a> package, \b GPL </td>
+ <td></td></tr>
+<tr><td>SuperLU</td><td>\link SuperLUSupport_Module SuperLUSupport \endlink</td><td>Direct LU factorization</td><td>Square</td><td>Fill-in reducing, Leverage fast dense algebra</td>
+ <td>Requires the <a href="http://crd-legacy.lbl.gov/~xiaoye/SuperLU/">SuperLU</a> library, (BSD-like)</td>
+ <td></td></tr>
+</table>
+
+Here \c SPD means symmetric positive definite.
+
+All these solvers follow the same general concept.
+Here is a typical and general example:
+\code
+#include <Eigen/RequiredModuleName>
+// ...
+SparseMatrix<double> A;
+// fill A
+VectorXd b, x;
+// fill b
+// solve Ax = b
+SolverClassName<SparseMatrix<double> > solver;
+solver.compute(A);
+if(solver.info()!=Succeeded) {
+ // decomposition failed
+ return;
+}
+x = solver.solve(b);
+if(solver.info()!=Succeeded) {
+ // solving failed
+ return;
+}
+// solve for another right hand side:
+x1 = solver.solve(b1);
+\endcode
+
+For \c SPD solvers, a second optional template argument allows to specify which triangular part have to be used, e.g.:
+
+\code
+#include <Eigen/IterativeLinearSolvers>
+
+ConjugateGradient<SparseMatrix<double>, Eigen::Upper> solver;
+x = solver.compute(A).solve(b);
+\endcode
+In the above example, only the upper triangular part of the input matrix A is considered for solving. The opposite triangle might either be empty or contain arbitrary values.
+
+In the case where multiple problems with the same sparcity pattern have to be solved, then the "compute" step can be decomposed as follow:
+\code
+SolverClassName<SparseMatrix<double> > solver;
+solver.analyzePattern(A); // for this step the numerical values of A are not used
+solver.factorize(A);
+x1 = solver.solve(b1);
+x2 = solver.solve(b2);
+...
+A = ...; // modify the values of the nonzeros of A, the nonzeros pattern must stay unchanged
+solver.factorize(A);
+x1 = solver.solve(b1);
+x2 = solver.solve(b2);
+...
+\endcode
+The compute() method is equivalent to calling both analyzePattern() and factorize().
+
+Finally, each solver provides some specific features, such as determinant, access to the factors, controls of the iterations, and so on.
+More details are availble in the documentations of the respective classes.
+
+
+\section TutorialSparseFeatureSet Supported operators and functions
+
+Because of their special storage format, sparse matrices cannot offer the same level of flexbility than dense matrices.
+In Eigen's sparse module we chose to expose only the subset of the dense matrix API which can be efficiently implemented.
+In the following \em sm denotes a sparse matrix, \em sv a sparse vector, \em dm a dense matrix, and \em dv a dense vector.
+
+\subsection TutorialSparse_BasicOps Basic operations
+
+%Sparse expressions support most of the unary and binary coefficient wise operations:
+\code
+sm1.real() sm1.imag() -sm1 0.5*sm1
+sm1+sm2 sm1-sm2 sm1.cwiseProduct(sm2)
+\endcode
+However, a strong restriction is that the storage orders must match. For instance, in the following example:
+\code
+sm4 = sm1 + sm2 + sm3;
+\endcode
+sm1, sm2, and sm3 must all be row-major or all column major.
+On the other hand, there is no restriction on the target matrix sm4.
+For instance, this means that for computing \f$ A^T + A \f$, the matrix \f$ A^T \f$ must be evaluated into a temporary matrix of compatible storage order:
+\code
+SparseMatrix<double> A, B;
+B = SparseMatrix<double>(A.transpose()) + A;
+\endcode
+
+Binary coefficient wise operators can also mix sparse and dense expressions:
+\code
+sm2 = sm1.cwiseProduct(dm1);
+dm2 = sm1 + dm1;
+\endcode
+
+
+%Sparse expressions also support transposition:
+\code
+sm1 = sm2.transpose();
+sm1 = sm2.adjoint();
+\endcode
+However, there is no transposeInPlace() method.
+
+
+\subsection TutorialSparse_Products Matrix products
+
+%Eigen supports various kind of sparse matrix products which are summarize below:
+ - \b sparse-dense:
+ \code
+dv2 = sm1 * dv1;
+dm2 = dm1 * sm1.adjoint();
+dm2 = 2. * sm1 * dm1;
+ \endcode
+ - \b symmetric \b sparse-dense. The product of a sparse symmetric matrix with a dense matrix (or vector) can also be optimized by specifying the symmetry with selfadjointView():
+ \code
+dm2 = sm1.selfadjointView<>() * dm1; // if all coefficients of A are stored
+dm2 = A.selfadjointView<Upper>() * dm1; // if only the upper part of A is stored
+dm2 = A.selfadjointView<Lower>() * dm1; // if only the lower part of A is stored
+ \endcode
+ - \b sparse-sparse. For sparse-sparse products, two different algorithms are available. The default one is conservative and preserve the explicit zeros that might appear:
+ \code
+sm3 = sm1 * sm2;
+sm3 = 4 * sm1.adjoint() * sm2;
+ \endcode
+ The second algorithm prunes on the fly the explicit zeros, or the values smaller than a given threshold. It is enabled and controlled through the prune() functions:
+ \code
+sm3 = (sm1 * sm2).prune(); // removes numerical zeros
+sm3 = (sm1 * sm2).prune(ref); // removes elements much smaller than ref
+sm3 = (sm1 * sm2).prune(ref,epsilon); // removes elements smaller than ref*epsilon
+ \endcode
+
+ - \b permutations. Finally, permutations can be applied to sparse matrices too:
+ \code
+PermutationMatrix<Dynamic,Dynamic> P = ...;
+sm2 = P * sm1;
+sm2 = sm1 * P.inverse();
+sm2 = sm1.transpose() * P;
+ \endcode
+
+
+\subsection TutorialSparse_TriangularSelfadjoint Triangular and selfadjoint views
+
+Just as with dense matrices, the triangularView() function can be used to address a triangular part of the matrix, and perform triangular solves with a dense right hand side:
+\code
+dm2 = sm1.triangularView<Lower>(dm1);
+dv2 = sm1.transpose().triangularView<Upper>(dv1);
+\endcode
+
+The selfadjointView() function permits various operations:
+ - optimized sparse-dense matrix products:
+ \code
+dm2 = sm1.selfadjointView<>() * dm1; // if all coefficients of A are stored
+dm2 = A.selfadjointView<Upper>() * dm1; // if only the upper part of A is stored
+dm2 = A.selfadjointView<Lower>() * dm1; // if only the lower part of A is stored
+ \endcode
+ - copy of triangular parts:
+ \code
+sm2 = sm1.selfadjointView<Upper>(); // makes a full selfadjoint matrix from the upper triangular part
+sm2.selfadjointView<Lower>() = sm1.selfadjointView<Upper>(); // copies the upper triangular part to the lower triangular part
+ \endcode
+ - application of symmetric permutations:
+ \code
+PermutationMatrix<Dynamic,Dynamic> P = ...;
+sm2 = A.selfadjointView<Upper>().twistedBy(P); // compute P S P' from the upper triangular part of A, and make it a full matrix
+sm2.selfadjointView<Lower>() = A.selfadjointView<Lower>().twistedBy(P); // compute P S P' from the lower triangular part of A, and then only compute the lower part
+ \endcode
+
+\subsection TutorialSparse_Submat Sub-matrices
+
+%Sparse matrices does not support yet the addressing of arbitrary sub matrices. Currently, one can only reference a set of contiguous \em inner vectors, i.e., a set of contiguous rows for a row-major matrix, or a set of contiguous columns for a column major matrix:
+\code
+ sm1.innerVector(j); // returns an expression of the j-th column (resp. row) of the matrix if sm1 is col-major (resp. row-major)
+ sm1.innerVectors(j, nb); // returns an expression of the nb columns (resp. row) starting from the j-th column (resp. row)
+ // of the matrix if sm1 is col-major (resp. row-major)
+ sm1.middleRows(j, nb); // for row major matrices only, get a range of nb rows
+ sm1.middleCols(j, nb); // for column major matrices only, get a range of nb columns
+\endcode
+
+\li \b Next: \ref TutorialMapClass
+
+*/
+
+}
diff --git a/doc/C10_TutorialMapClass.dox b/doc/C10_TutorialMapClass.dox
new file mode 100644
index 000000000..09e792792
--- /dev/null
+++ b/doc/C10_TutorialMapClass.dox
@@ -0,0 +1,96 @@
+namespace Eigen {
+
+/** \page TutorialMapClass Tutorial page 10 - Interfacing with C/C++ arrays and external libraries: the %Map class
+
+\ingroup Tutorial
+
+\li \b Previous: \ref TutorialSparse
+\li \b Next: \ref TODO
+
+This tutorial page explains how to work with "raw" C++ arrays. This can be useful in a variety of contexts, particularly when "importing" vectors and matrices from other libraries into Eigen.
+
+\b Table \b of \b contents
+ - \ref TutorialMapIntroduction
+ - \ref TutorialMapTypes
+ - \ref TutorialMapUsing
+ - \ref TutorialMapPlacementNew
+
+\section TutorialMapIntroduction Introduction
+
+Occasionally you may have a pre-defined array of numbers that you want to use within Eigen as a vector or matrix. While one option is to make a copy of the data, most commonly you probably want to re-use this memory as an Eigen type. Fortunately, this is very easy with the Map class.
+
+\section TutorialMapTypes Map types and declaring Map variables
+
+A Map object has a type defined by its Eigen equivalent:
+\code
+Map<Matrix<typename Scalar, int RowsAtCompileTime, int ColsAtCompileTime> >
+\endcode
+Note that, in this default case, a Map requires just a single template parameter.
+
+To construct a Map variable, you need two other pieces of information: a pointer to the region of memory defining the array of coefficients, and the desired shape of the matrix or vector. For example, to define a matrix of \c float with sizes determined at compile time, you might do the following:
+\code
+Map<MatrixXf> mf(pf,rows,columns);
+\endcode
+where \c pf is a \c float \c * pointing to the array of memory. A fixed-size read-only vector of integers might be declared as
+\code
+Map<const Vector4i> mi(pi);
+\endcode
+where \c pi is an \c int \c *. In this case the size does not have to be passed to the constructor, because it is already specified by the Matrix/Array type.
+
+Note that Map does not have a default constructor; you \em must pass a pointer to intialize the object. However, you can work around this requirement (see \ref TutorialMapPlacementNew).
+
+Map is flexible enough to accomodate a variety of different data representations. There are two other (optional) template parameters:
+\code
+Map<typename MatrixType,
+ int MapOptions,
+ typename StrideType>
+\endcode
+\li \c MapOptions specifies whether the pointer is \c #Aligned, or \c #Unaligned. The default is \c #Unaligned.
+\li \c StrideType allows you to specify a custom layout for the memory array, using the Stride class. One example would be to specify that the data array is organized in row-major format:
+<table class="example">
+<tr><th>Example:</th><th>Output:</th></tr>
+<tr>
+<td>\include Tutorial_Map_rowmajor.cpp </td>
+<td>\verbinclude Tutorial_Map_rowmajor.out </td>
+</table>
+However, Stride is even more flexible than this; for details, see the documentation for the Map and Stride classes.
+
+\section TutorialMapUsing Using Map variables
+
+You can use a Map object just like any other Eigen type:
+<table class="example">
+<tr><th>Example:</th><th>Output:</th></tr>
+<tr>
+<td>\include Tutorial_Map_using.cpp </td>
+<td>\verbinclude Tutorial_Map_using.out </td>
+</table>
+
+However, when writing functions taking Eigen types, it is important to realize that a Map type is \em not identical to its Dense equivalent. See \ref TopicFunctionTakingEigenTypesMultiarguments for details.
+
+\section TutorialMapPlacementNew Changing the mapped array
+
+It is possible to change the array of a Map object after declaration, using the C++ "placement new" syntax:
+<table class="example">
+<tr><th>Example:</th><th>Output:</th></tr>
+<tr>
+<td>\include Map_placement_new.cpp </td>
+<td>\verbinclude Map_placement_new.out </td>
+</table>
+Despite appearances, this does not invoke the memory allocator, because the syntax specifies the location for storing the result.
+
+This syntax makes it possible to declare a Map object without first knowing the mapped array's location in memory:
+\code
+Map<Matrix3f> A(NULL); // don't try to use this matrix yet!
+VectorXf b(n_matrices);
+for (int i = 0; i < n_matrices; i++)
+{
+ new (&A) Map<Matrix3f>(get_matrix_pointer(i));
+ b(i) = A.trace();
+}
+\endcode
+
+\li \b Next: \ref TODO
+
+*/
+
+}
diff --git a/doc/CMakeLists.txt b/doc/CMakeLists.txt
new file mode 100644
index 000000000..96bff41bf
--- /dev/null
+++ b/doc/CMakeLists.txt
@@ -0,0 +1,78 @@
+project(EigenDoc)
+
+set_directory_properties(PROPERTIES EXCLUDE_FROM_ALL TRUE)
+
+project(EigenDoc)
+
+if(CMAKE_COMPILER_IS_GNUCXX)
+ if(CMAKE_SYSTEM_NAME MATCHES Linux)
+ set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -O1 -g1")
+ endif(CMAKE_SYSTEM_NAME MATCHES Linux)
+endif(CMAKE_COMPILER_IS_GNUCXX)
+
+configure_file(
+ ${Eigen_SOURCE_DIR}/unsupported/doc/Doxyfile.in
+ ${CMAKE_CURRENT_BINARY_DIR}/Doxyfile-unsupported
+)
+
+configure_file(
+ ${CMAKE_CURRENT_SOURCE_DIR}/Doxyfile.in
+ ${CMAKE_CURRENT_BINARY_DIR}/Doxyfile
+)
+
+configure_file(
+ ${CMAKE_CURRENT_SOURCE_DIR}/eigendoxy_header.html.in
+ ${CMAKE_CURRENT_BINARY_DIR}/eigendoxy_header.html
+)
+
+configure_file(
+ ${CMAKE_CURRENT_SOURCE_DIR}/eigendoxy_footer.html.in
+ ${CMAKE_CURRENT_BINARY_DIR}/eigendoxy_footer.html
+)
+
+set(examples_targets "")
+set(snippets_targets "")
+
+add_definitions("-DEIGEN_MAKING_DOCS")
+
+add_subdirectory(examples)
+add_subdirectory(special_examples)
+add_subdirectory(snippets)
+
+add_custom_target(
+ doc-eigen-prerequisites
+ ALL
+ COMMAND ${CMAKE_COMMAND} -E make_directory ${CMAKE_CURRENT_BINARY_DIR}/html/
+ COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_CURRENT_SOURCE_DIR}/eigendoxy_tabs.css
+ ${CMAKE_CURRENT_BINARY_DIR}/html/
+ COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_CURRENT_SOURCE_DIR}/Eigen_Silly_Professor_64x64.png
+ ${CMAKE_CURRENT_BINARY_DIR}/html/
+ COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_CURRENT_SOURCE_DIR}/AsciiQuickReference.txt
+ ${CMAKE_CURRENT_BINARY_DIR}/html/
+ WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
+)
+
+add_custom_target(
+ doc-unsupported-prerequisites
+ ALL
+ COMMAND ${CMAKE_COMMAND} -E make_directory ${Eigen_BINARY_DIR}/doc/html/unsupported
+ COMMAND ${CMAKE_COMMAND} -E copy ${Eigen_SOURCE_DIR}/doc/eigendoxy_tabs.css
+ ${Eigen_BINARY_DIR}/doc/html/unsupported/
+ COMMAND ${CMAKE_COMMAND} -E copy ${Eigen_SOURCE_DIR}/doc/Eigen_Silly_Professor_64x64.png
+ ${Eigen_BINARY_DIR}/doc/html/unsupported/
+ WORKING_DIRECTORY ${Eigen_BINARY_DIR}/doc
+)
+
+add_dependencies(doc-eigen-prerequisites all_snippets all_examples)
+add_dependencies(doc-unsupported-prerequisites unsupported_snippets unsupported_examples)
+
+add_custom_target(doc ALL
+ COMMAND doxygen Doxyfile-unsupported
+ COMMAND doxygen
+ COMMAND doxygen Doxyfile-unsupported # run doxygen twice to get proper eigen <=> unsupported cross references
+ COMMAND ${CMAKE_COMMAND} -E rename html eigen-doc
+ COMMAND ${CMAKE_COMMAND} -E tar cvfz eigen-doc/eigen-doc.tgz eigen-doc/*.html eigen-doc/*.map eigen-doc/*.png eigen-doc/*.css eigen-doc/*.js eigen-doc/*.txt eigen-doc/unsupported
+ COMMAND ${CMAKE_COMMAND} -E rename eigen-doc html
+ WORKING_DIRECTORY ${Eigen_BINARY_DIR}/doc)
+
+add_dependencies(doc doc-eigen-prerequisites doc-unsupported-prerequisites)
diff --git a/doc/D01_StlContainers.dox b/doc/D01_StlContainers.dox
new file mode 100644
index 000000000..b5dbf0698
--- /dev/null
+++ b/doc/D01_StlContainers.dox
@@ -0,0 +1,65 @@
+namespace Eigen {
+
+/** \page TopicStlContainers Using STL Containers with Eigen
+
+\b Table \b of \b contents
+ - \ref summary
+ - \ref allocator
+ - \ref vector
+
+\section summary Executive summary
+
+Using STL containers on \ref TopicFixedSizeVectorizable "fixed-size vectorizable Eigen types", or classes having members of such types, requires taking the following two steps:
+
+\li A 16-byte-aligned allocator must be used. Eigen does provide one ready for use: aligned_allocator.
+\li If you want to use the std::vector container, you need to \#include <Eigen/StdVector>.
+
+These issues arise only with \ref TopicFixedSizeVectorizable "fixed-size vectorizable Eigen types" and \ref TopicStructHavingEigenMembers "structures having such Eigen objects as member". For other Eigen types, such as Vector3f or MatrixXd, no special care is needed when using STL containers.
+
+\section allocator Using an aligned allocator
+
+STL containers take an optional template parameter, the allocator type. When using STL containers on \ref TopicFixedSizeVectorizable "fixed-size vectorizable Eigen types", you need tell the container to use an allocator that will always allocate memory at 16-byte-aligned locations. Fortunately, Eigen does provide such an allocator: Eigen::aligned_allocator.
+
+For example, instead of
+\code
+std::map<int, Eigen::Vector4f>
+\endcode
+you need to use
+\code
+std::map<int, Eigen::Vector4f, std::less<int>,
+ Eigen::aligned_allocator<std::pair<const int, Eigen::Vector4f> > >
+\endcode
+Note that the third parameter "std::less<int>" is just the default value, but we have to include it because we want to specify the fourth parameter, which is the allocator type.
+
+\section vector The case of std::vector
+
+The situation with std::vector was even worse (explanation below) so we had to specialize it for the Eigen::aligned_allocator type. In practice you \b must use the Eigen::aligned_allocator (not another aligned allocator), \b and \#include <Eigen/StdVector>.
+
+Here is an example:
+\code
+#include<Eigen/StdVector>
+\/* ... *\/
+std::vector<Eigen::Vector4f,Eigen::aligned_allocator<Eigen::Vector4f> >
+\endcode
+
+\subsection vector_spec An alternative - specializing std::vector for Eigen types
+
+As an alternative to the recommended approach described above, you have the option to specialize std::vector for Eigen types requiring alignment.
+The advantage is that you won't need to declare std::vector all over with Eigen::allocator. One drawback on the other hand side is that
+the specialization needs to be defined before all code pieces in which e.g. std::vector<Vector2d> is used. Otherwise, without knowing the specialization
+the compiler will compile that particular instance with the default std::allocator and you program is most likely to crash.
+
+Here is an example:
+\code
+#include<Eigen/StdVector>
+\/* ... *\/
+EIGEN_DEFINE_STL_VECTOR_SPECIALIZATION(Matrix2d)
+std::vector<Eigen::Vector2d>
+\endcode
+
+<span class="note">\b Explanation: The resize() method of std::vector takes a value_type argument (defaulting to value_type()). So with std::vector<Eigen::Vector4f>, some Eigen::Vector4f objects will be passed by value, which discards any alignment modifiers, so a Eigen::Vector4f can be created at an unaligned location. In order to avoid that, the only solution we saw was to specialize std::vector to make it work on a slight modification of, here, Eigen::Vector4f, that is able to deal properly with this situation.
+</span>
+
+*/
+
+}
diff --git a/doc/D03_WrongStackAlignment.dox b/doc/D03_WrongStackAlignment.dox
new file mode 100644
index 000000000..b0e42edce
--- /dev/null
+++ b/doc/D03_WrongStackAlignment.dox
@@ -0,0 +1,56 @@
+namespace Eigen {
+
+/** \page TopicWrongStackAlignment Compiler making a wrong assumption on stack alignment
+
+<h4>It appears that this was a GCC bug that has been fixed in GCC 4.5.
+If you hit this issue, please upgrade to GCC 4.5 and report to us, so we can update this page.</h4>
+
+This is an issue that, so far, we met only with GCC on Windows: for instance, MinGW and TDM-GCC.
+
+By default, in a function like this,
+
+\code
+void foo()
+{
+ Eigen::Quaternionf q;
+ //...
+}
+\endcode
+
+GCC assumes that the stack is already 16-byte-aligned so that the object \a q will be created at a 16-byte-aligned location. For this reason, it doesn't take any special care to explicitly align the object \a q, as Eigen requires.
+
+The problem is that, in some particular cases, this assumption can be wrong on Windows, where the stack is only guaranteed to have 4-byte alignment. Indeed, even though GCC takes care of aligning the stack in the main function and does its best to keep it aligned, when a function is called from another thread or from a binary compiled with another compiler, the stack alignment can be corrupted. This results in the object 'q' being created at an unaligned location, making your program crash with the \ref TopicUnalignedArrayAssert "assertion on unaligned arrays". So far we found the three following solutions.
+
+
+\section sec_sol1 Local solution
+
+A local solution is to mark such a function with this attribute:
+\code
+__attribute__((force_align_arg_pointer)) void foo()
+{
+ Eigen::Quaternionf q;
+ //...
+}
+\endcode
+Read <a href="http://gcc.gnu.org/onlinedocs/gcc-4.4.0/gcc/Function-Attributes.html#Function-Attributes">this GCC documentation</a> to understand what this does. Of course this should only be done on GCC on Windows, so for portability you'll have to encapsulate this in a macro which you leave empty on other platforms. The advantage of this solution is that you can finely select which function might have a corrupted stack alignment. Of course on the downside this has to be done for every such function, so you may prefer one of the following two global solutions.
+
+
+\section sec_sol2 Global solutions
+
+A global solution is to edit your project so that when compiling with GCC on Windows, you pass this option to GCC:
+\code
+-mincoming-stack-boundary=2
+\endcode
+Explanation: this tells GCC that the stack is only required to be aligned to 2^2=4 bytes, so that GCC now knows that it really must take extra care to honor the 16 byte alignment of \ref TopicFixedSizeVectorizable "fixed-size vectorizable Eigen types" when needed.
+
+Another global solution is to pass this option to gcc:
+\code
+-mstackrealign
+\endcode
+which has the same effect than adding the \c force_align_arg_pointer attribute to all functions.
+
+These global solutions are easy to use, but note that they may slowdown your program because they lead to extra prologue/epilogue instructions for every function.
+
+*/
+
+}
diff --git a/doc/D07_PassingByValue.dox b/doc/D07_PassingByValue.dox
new file mode 100644
index 000000000..b1e5e683b
--- /dev/null
+++ b/doc/D07_PassingByValue.dox
@@ -0,0 +1,40 @@
+namespace Eigen {
+
+/** \page TopicPassingByValue Passing Eigen objects by value to functions
+
+Passing objects by value is almost always a very bad idea in C++, as this means useless copies, and one should pass them by reference instead.
+
+With Eigen, this is even more important: passing \ref TopicFixedSizeVectorizable "fixed-size vectorizable Eigen objects" by value is not only inefficient, it can be illegal or make your program crash! And the reason is that these Eigen objects have alignment modifiers that aren't respected when they are passed by value.
+
+So for example, a function like this, where v is passed by value:
+
+\code
+void my_function(Eigen::Vector2d v);
+\endcode
+
+needs to be rewritten as follows, passing v by reference:
+
+\code
+void my_function(const Eigen::Vector2d& v);
+\endcode
+
+Likewise if you have a class having a Eigen object as member:
+
+\code
+struct Foo
+{
+ Eigen::Vector2d v;
+};
+void my_function(Foo v);
+\endcode
+
+This function also needs to be rewritten like this:
+\code
+void my_function(const Foo& v);
+\endcode
+
+Note that on the other hand, there is no problem with functions that return objects by value.
+
+*/
+
+}
diff --git a/doc/D09_StructHavingEigenMembers.dox b/doc/D09_StructHavingEigenMembers.dox
new file mode 100644
index 000000000..51789ca9c
--- /dev/null
+++ b/doc/D09_StructHavingEigenMembers.dox
@@ -0,0 +1,198 @@
+namespace Eigen {
+
+/** \page TopicStructHavingEigenMembers Structures Having Eigen Members
+
+\b Table \b of \b contents
+ - \ref summary
+ - \ref what
+ - \ref how
+ - \ref why
+ - \ref movetotop
+ - \ref bugineigen
+ - \ref conditional
+ - \ref othersolutions
+
+\section summary Executive Summary
+
+If you define a structure having members of \ref TopicFixedSizeVectorizable "fixed-size vectorizable Eigen types", you must overload its "operator new" so that it generates 16-bytes-aligned pointers. Fortunately, Eigen provides you with a macro EIGEN_MAKE_ALIGNED_OPERATOR_NEW that does that for you.
+
+\section what What kind of code needs to be changed?
+
+The kind of code that needs to be changed is this:
+
+\code
+class Foo
+{
+ ...
+ Eigen::Vector2d v;
+ ...
+};
+
+...
+
+Foo *foo = new Foo;
+\endcode
+
+In other words: you have a class that has as a member a \ref TopicFixedSizeVectorizable "fixed-size vectorizable Eigen object", and then you dynamically create an object of that class.
+
+\section how How should such code be modified?
+
+Very easy, you just need to put a EIGEN_MAKE_ALIGNED_OPERATOR_NEW macro in a public part of your class, like this:
+
+\code
+class Foo
+{
+ ...
+ Eigen::Vector2d v;
+ ...
+public:
+ EIGEN_MAKE_ALIGNED_OPERATOR_NEW
+};
+
+...
+
+Foo *foo = new Foo;
+\endcode
+
+This macro makes "new Foo" always return an aligned pointer.
+
+If this approach is too intrusive, see also the \ref othersolutions.
+
+\section why Why is this needed?
+
+OK let's say that your code looks like this:
+
+\code
+class Foo
+{
+ ...
+ Eigen::Vector2d v;
+ ...
+};
+
+...
+
+Foo *foo = new Foo;
+\endcode
+
+A Eigen::Vector2d consists of 2 doubles, which is 128 bits. Which is exactly the size of a SSE packet, which makes it possible to use SSE for all sorts of operations on this vector. But SSE instructions (at least the ones that Eigen uses, which are the fast ones) require 128-bit alignment. Otherwise you get a segmentation fault.
+
+For this reason, Eigen takes care by itself to require 128-bit alignment for Eigen::Vector2d, by doing two things:
+\li Eigen requires 128-bit alignment for the Eigen::Vector2d's array (of 2 doubles). With GCC, this is done with a __attribute__ ((aligned(16))).
+\li Eigen overloads the "operator new" of Eigen::Vector2d so it will always return 128-bit aligned pointers.
+
+Thus, normally, you don't have to worry about anything, Eigen handles alignment for you...
+
+... except in one case. When you have a class Foo like above, and you dynamically allocate a new Foo as above, then, since Foo doesn't have aligned "operator new", the returned pointer foo is not necessarily 128-bit aligned.
+
+The alignment attribute of the member v is then relative to the start of the class, foo. If the foo pointer wasn't aligned, then foo->v won't be aligned either!
+
+The solution is to let class Foo have an aligned "operator new", as we showed in the previous section.
+
+\section movetotop Should I then put all the members of Eigen types at the beginning of my class?
+
+That's not required. Since Eigen takes care of declaring 128-bit alignment, all members that need it are automatically 128-bit aligned relatively to the class. So code like this works fine:
+
+\code
+class Foo
+{
+ double x;
+ Eigen::Vector2d v;
+public:
+ EIGEN_MAKE_ALIGNED_OPERATOR_NEW
+};
+\endcode
+
+\section dynamicsize What about dynamic-size matrices and vectors?
+
+Dynamic-size matrices and vectors, such as Eigen::VectorXd, allocate dynamically their own array of coefficients, so they take care of requiring absolute alignment automatically. So they don't cause this issue. The issue discussed here is only with \ref TopicFixedSizeVectorizable "fixed-size vectorizable matrices and vectors".
+
+\section bugineigen So is this a bug in Eigen?
+
+No, it's not our bug. It's more like an inherent problem of the C++98 language specification, and seems to be taken care of in the upcoming language revision: <a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2341.pdf">see this document</a>.
+
+\section conditional What if I want to do this conditionnally (depending on template parameters) ?
+
+For this situation, we offer the macro EIGEN_MAKE_ALIGNED_OPERATOR_NEW_IF(NeedsToAlign). It will generate aligned operators like EIGEN_MAKE_ALIGNED_OPERATOR_NEW if NeedsToAlign is true. It will generate operators with the default alignment if NeedsToAlign is false.
+
+Example:
+
+\code
+template<int n> class Foo
+{
+ typedef Eigen::Matrix<float,n,1> Vector;
+ enum { NeedsToAlign = (sizeof(Vector)%16)==0 };
+ ...
+ Vector v;
+ ...
+public:
+ EIGEN_MAKE_ALIGNED_OPERATOR_NEW_IF(NeedsToAlign)
+};
+
+...
+
+Foo<4> *foo4 = new Foo<4>; // foo4 is guaranteed to be 128bit-aligned
+Foo<3> *foo3 = new Foo<3>; // foo3 has only the system default alignment guarantee
+\endcode
+
+
+\section othersolutions Other solutions
+
+In case putting the EIGEN_MAKE_ALIGNED_OPERATOR_NEW macro everywhere is too intrusive, there exists at least two other solutions.
+
+\subsection othersolutions1 Disabling alignment
+
+The first is to disable alignment requirement for the fixed size members:
+\code
+class Foo
+{
+ ...
+ Eigen::Matrix<double,2,1,Eigen::DontAlign> v;
+ ...
+};
+\endcode
+This has for effect to disable vectorization when using \c v.
+If a function of Foo uses it several times, then it still possible to re-enable vectorization by copying it into an aligned temporary vector:
+\code
+void Foo::bar()
+{
+ Eigen::Vector2d av(v);
+ // use av instead of v
+ ...
+ // if av changed, then do:
+ v = av;
+}
+\endcode
+
+\subsection othersolutions2 Private structure
+
+The second consist in storing the fixed-size objects into a private struct which will be dynamically allocated at the construction time of the main object:
+
+\code
+struct Foo_d
+{
+ EIGEN_MAKE_ALIGNED_OPERATOR_NEW
+ Vector2d v;
+ ...
+};
+
+
+struct Foo {
+ Foo() { init_d(); }
+ ~Foo() { delete d; }
+ void bar()
+ {
+ // use d->v instead of v
+ ...
+ }
+private:
+ void init_d() { d = new Foo_d; }
+ Foo_d* d;
+};
+\endcode
+
+The clear advantage here is that the class Foo remains unchanged regarding alignment issues. The drawback is that a heap allocation will be required whatsoever.
+
+*/
+
+}
diff --git a/doc/D11_UnalignedArrayAssert.dox b/doc/D11_UnalignedArrayAssert.dox
new file mode 100644
index 000000000..d173ee5f4
--- /dev/null
+++ b/doc/D11_UnalignedArrayAssert.dox
@@ -0,0 +1,121 @@
+namespace Eigen {
+
+/** \page TopicUnalignedArrayAssert Explanation of the assertion on unaligned arrays
+
+Hello! You are seeing this webpage because your program terminated on an assertion failure like this one:
+<pre>
+my_program: path/to/eigen/Eigen/src/Core/DenseStorage.h:44:
+Eigen::internal::matrix_array<T, Size, MatrixOptions, Align>::internal::matrix_array()
+[with T = double, int Size = 2, int MatrixOptions = 2, bool Align = true]:
+Assertion `(reinterpret_cast<size_t>(array) & 0xf) == 0 && "this assertion
+is explained here: http://eigen.tuxfamily.org/dox/UnalignedArrayAssert.html
+**** READ THIS WEB PAGE !!! ****"' failed.
+</pre>
+
+There are 4 known causes for this issue. Please read on to understand them and learn how to fix them.
+
+\b Table \b of \b contents
+ - \ref where
+ - \ref c1
+ - \ref c2
+ - \ref c3
+ - \ref c4
+ - \ref explanation
+ - \ref getrid
+
+\section where Where in my own code is the cause of the problem?
+
+First of all, you need to find out where in your own code this assertion was triggered from. At first glance, the error message doesn't look helpful, as it refers to a file inside Eigen! However, since your program crashed, if you can reproduce the crash, you can get a backtrace using any debugger. For example, if you're using GCC, you can use the GDB debugger as follows:
+\code
+$ gdb ./my_program # Start GDB on your program
+> run # Start running your program
+... # Now reproduce the crash!
+> bt # Obtain the backtrace
+\endcode
+Now that you know precisely where in your own code the problem is happening, read on to understand what you need to change.
+
+\section c1 Cause 1: Structures having Eigen objects as members
+
+If you have code like this,
+
+\code
+class Foo
+{
+ //...
+ Eigen::Vector2d v;
+ //...
+};
+//...
+Foo *foo = new Foo;
+\endcode
+
+then you need to read this separate page: \ref TopicStructHavingEigenMembers "Structures Having Eigen Members".
+
+Note that here, Eigen::Vector2d is only used as an example, more generally the issue arises for all \ref TopicFixedSizeVectorizable "fixed-size vectorizable Eigen types".
+
+\section c2 Cause 2: STL Containers
+
+If you use STL Containers such as std::vector, std::map, ..., with Eigen objects, or with classes containing Eigen objects, like this,
+
+\code
+std::vector<Eigen::Matrix2f> my_vector;
+struct my_class { ... Eigen::Matrix2f m; ... };
+std::map<int, my_class> my_map;
+\endcode
+
+then you need to read this separate page: \ref TopicStlContainers "Using STL Containers with Eigen".
+
+Note that here, Eigen::Matrix2f is only used as an example, more generally the issue arises for all \ref TopicFixedSizeVectorizable "fixed-size vectorizable Eigen types" and \ref TopicStructHavingEigenMembers "structures having such Eigen objects as member".
+
+\section c3 Cause 3: Passing Eigen objects by value
+
+If some function in your code is getting an Eigen object passed by value, like this,
+
+\code
+void func(Eigen::Vector4d v);
+\endcode
+
+then you need to read this separate page: \ref TopicPassingByValue "Passing Eigen objects by value to functions".
+
+Note that here, Eigen::Vector4d is only used as an example, more generally the issue arises for all \ref TopicFixedSizeVectorizable "fixed-size vectorizable Eigen types".
+
+\section c4 Cause 4: Compiler making a wrong assumption on stack alignment (for instance GCC on Windows)
+
+This is a must-read for people using GCC on Windows (like MinGW or TDM-GCC). If you have this assertion failure in an innocent function declaring a local variable like this:
+
+\code
+void foo()
+{
+ Eigen::Quaternionf q;
+ //...
+}
+\endcode
+
+then you need to read this separate page: \ref TopicWrongStackAlignment "Compiler making a wrong assumption on stack alignment".
+
+Note that here, Eigen::Quaternionf is only used as an example, more generally the issue arises for all \ref TopicFixedSizeVectorizable "fixed-size vectorizable Eigen types".
+
+\section explanation General explanation of this assertion
+
+\ref TopicFixedSizeVectorizable "fixed-size vectorizable Eigen objects" must absolutely be created at 16-byte-aligned locations, otherwise SIMD instructions adressing them will crash.
+
+Eigen normally takes care of these alignment issues for you, by setting an alignment attribute on them and by overloading their "operator new".
+
+However there are a few corner cases where these alignment settings get overridden: they are the possible causes for this assertion.
+
+\section getrid I don't care about vectorization, how do I get rid of that stuff?
+
+Two possibilities:
+<ul>
+ <li>Define EIGEN_DONT_ALIGN_STATICALLY. That disables all 128-bit static alignment code, while keeping 128-bit heap alignment. This has the effect of
+ disabling vectorization for fixed-size objects (like Matrix4d) while keeping vectorization of dynamic-size objects
+ (like MatrixXd). But do note that this breaks ABI compatibility with the default behavior of 128-bit static alignment.</li>
+ <li>Or define both EIGEN_DONT_VECTORIZE and EIGEN_DISABLE_UNALIGNED_ARRAY_ASSERT. This keeps the
+ 128-bit alignment code and thus preserves ABI compatibility, but completely disables vectorization.</li>
+</ul>
+
+For more information, see <a href="http://eigen.tuxfamily.org/index.php?title=FAQ#I_disabled_vectorization.2C_but_I.27m_still_getting_annoyed_about_alignment_issues.21">this FAQ</a>.
+
+*/
+
+}
diff --git a/doc/Doxyfile.in b/doc/Doxyfile.in
new file mode 100644
index 000000000..e9e89d486
--- /dev/null
+++ b/doc/Doxyfile.in
@@ -0,0 +1,1484 @@
+# This file describes the settings to be used by the documentation system
+# doxygen (www.doxygen.org) for a project
+#
+# All text after a hash (#) is considered a comment and will be ignored
+# The format is:
+# TAG = value [value, ...]
+# For lists items can also be appended using:
+# TAG += value [value, ...]
+# Values that contain spaces should be placed between quotes (" ")
+
+#---------------------------------------------------------------------------
+# Project related configuration options
+#---------------------------------------------------------------------------
+
+# This tag specifies the encoding used for all characters in the config file
+# that follow. The default is UTF-8 which is also the encoding used for all
+# text before the first occurrence of this tag. Doxygen uses libiconv (or the
+# iconv built into libc) for the transcoding. See
+# http://www.gnu.org/software/libiconv for the list of possible encodings.
+
+DOXYFILE_ENCODING = UTF-8
+
+# The PROJECT_NAME tag is a single word (or a sequence of words surrounded
+# by quotes) that should identify the project.
+
+PROJECT_NAME = Eigen
+
+# The PROJECT_NUMBER tag can be used to enter a project or revision number.
+# This could be handy for archiving the generated documentation or
+# if some version control system is used.
+
+#EIGEN_VERSION is set in the root CMakeLists.txt
+PROJECT_NUMBER = "${EIGEN_VERSION}"
+
+# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute)
+# base path where the generated documentation will be put.
+# If a relative path is entered, it will be relative to the location
+# where doxygen was started. If left blank the current directory will be used.
+
+OUTPUT_DIRECTORY = "${Eigen_BINARY_DIR}/doc"
+
+# If the CREATE_SUBDIRS tag is set to YES, then doxygen will create
+# 4096 sub-directories (in 2 levels) under the output directory of each output
+# format and will distribute the generated files over these directories.
+# Enabling this option can be useful when feeding doxygen a huge amount of
+# source files, where putting all generated files in the same directory would
+# otherwise cause performance problems for the file system.
+
+CREATE_SUBDIRS = NO
+
+# The OUTPUT_LANGUAGE tag is used to specify the language in which all
+# documentation generated by doxygen is written. Doxygen will use this
+# information to generate all constant output in the proper language.
+# The default language is English, other supported languages are:
+# Afrikaans, Arabic, Brazilian, Catalan, Chinese, Chinese-Traditional,
+# Croatian, Czech, Danish, Dutch, Farsi, Finnish, French, German, Greek,
+# Hungarian, Italian, Japanese, Japanese-en (Japanese with English messages),
+# Korean, Korean-en, Lithuanian, Norwegian, Macedonian, Persian, Polish,
+# Portuguese, Romanian, Russian, Serbian, Slovak, Slovene, Spanish, Swedish,
+# and Ukrainian.
+
+OUTPUT_LANGUAGE = English
+
+# If the BRIEF_MEMBER_DESC tag is set to YES (the default) Doxygen will
+# include brief member descriptions after the members that are listed in
+# the file and class documentation (similar to JavaDoc).
+# Set to NO to disable this.
+
+BRIEF_MEMBER_DESC = YES
+
+# If the REPEAT_BRIEF tag is set to YES (the default) Doxygen will prepend
+# the brief description of a member or function before the detailed description.
+# Note: if both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the
+# brief descriptions will be completely suppressed.
+
+REPEAT_BRIEF = YES
+
+# This tag implements a quasi-intelligent brief description abbreviator
+# that is used to form the text in various listings. Each string
+# in this list, if found as the leading text of the brief description, will be
+# stripped from the text and the result after processing the whole list, is
+# used as the annotated text. Otherwise, the brief description is used as-is.
+# If left blank, the following values are used ("$name" is automatically
+# replaced with the name of the entity): "The $name class" "The $name widget"
+# "The $name file" "is" "provides" "specifies" "contains"
+# "represents" "a" "an" "the"
+
+ABBREVIATE_BRIEF = "The $name class" \
+ "The $name widget" \
+ "The $name file" \
+ is \
+ provides \
+ specifies \
+ contains \
+ represents \
+ a \
+ an \
+ the
+
+# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then
+# Doxygen will generate a detailed section even if there is only a brief
+# description.
+
+ALWAYS_DETAILED_SEC = NO
+
+# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all
+# inherited members of a class in the documentation of that class as if those
+# members were ordinary class members. Constructors, destructors and assignment
+# operators of the base classes will not be shown.
+
+INLINE_INHERITED_MEMB = YES
+
+# If the FULL_PATH_NAMES tag is set to YES then Doxygen will prepend the full
+# path before files name in the file list and in the header files. If set
+# to NO the shortest path that makes the file name unique will be used.
+
+FULL_PATH_NAMES = NO
+
+# If the FULL_PATH_NAMES tag is set to YES then the STRIP_FROM_PATH tag
+# can be used to strip a user-defined part of the path. Stripping is
+# only done if one of the specified strings matches the left-hand part of
+# the path. The tag can be used to show relative paths in the file list.
+# If left blank the directory from which doxygen is run is used as the
+# path to strip.
+
+STRIP_FROM_PATH =
+
+# The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of
+# the path mentioned in the documentation of a class, which tells
+# the reader which header file to include in order to use a class.
+# If left blank only the name of the header file containing the class
+# definition is used. Otherwise one should specify the include paths that
+# are normally passed to the compiler using the -I flag.
+
+STRIP_FROM_INC_PATH =
+
+# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter
+# (but less readable) file names. This can be useful is your file systems
+# doesn't support long names like on DOS, Mac, or CD-ROM.
+
+SHORT_NAMES = NO
+
+# If the JAVADOC_AUTOBRIEF tag is set to YES then Doxygen
+# will interpret the first line (until the first dot) of a JavaDoc-style
+# comment as the brief description. If set to NO, the JavaDoc
+# comments will behave just like regular Qt-style comments
+# (thus requiring an explicit @brief command for a brief description.)
+
+JAVADOC_AUTOBRIEF = NO
+
+# If the QT_AUTOBRIEF tag is set to YES then Doxygen will
+# interpret the first line (until the first dot) of a Qt-style
+# comment as the brief description. If set to NO, the comments
+# will behave just like regular Qt-style comments (thus requiring
+# an explicit \brief command for a brief description.)
+
+QT_AUTOBRIEF = NO
+
+# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make Doxygen
+# treat a multi-line C++ special comment block (i.e. a block of //! or ///
+# comments) as a brief description. This used to be the default behaviour.
+# The new default is to treat a multi-line C++ comment block as a detailed
+# description. Set this tag to YES if you prefer the old behaviour instead.
+
+MULTILINE_CPP_IS_BRIEF = NO
+
+# If the DETAILS_AT_TOP tag is set to YES then Doxygen
+# will output the detailed description near the top, like JavaDoc.
+# If set to NO, the detailed description appears after the member
+# documentation.
+
+DETAILS_AT_TOP = YES
+
+# If the INHERIT_DOCS tag is set to YES (the default) then an undocumented
+# member inherits the documentation from any documented member that it
+# re-implements.
+
+INHERIT_DOCS = YES
+
+# If the SEPARATE_MEMBER_PAGES tag is set to YES, then doxygen will produce
+# a new page for each member. If set to NO, the documentation of a member will
+# be part of the file/class/namespace that contains it.
+
+SEPARATE_MEMBER_PAGES = NO
+
+# The TAB_SIZE tag can be used to set the number of spaces in a tab.
+# Doxygen uses this value to replace tabs by spaces in code fragments.
+
+TAB_SIZE = 8
+
+# This tag can be used to specify a number of aliases that acts
+# as commands in the documentation. An alias has the form "name=value".
+# For example adding "sideeffect=\par Side Effects:\n" will allow you to
+# put the command \sideeffect (or @sideeffect) in the documentation, which
+# will result in a user-defined paragraph with heading "Side Effects:".
+# You can put \n's in the value part of an alias to insert newlines.
+
+ALIASES = "only_for_vectors=This is only for vectors (either row-vectors or column-vectors), i.e. matrices which are known at compile-time to have either one row or one column." \
+ "array_module=This is defined in the %Array module. \code #include <Eigen/Array> \endcode" \
+ "cholesky_module=This is defined in the %Cholesky module. \code #include <Eigen/Cholesky> \endcode" \
+ "eigenvalues_module=This is defined in the %Eigenvalues module. \code #include <Eigen/Eigenvalues> \endcode" \
+ "geometry_module=This is defined in the %Geometry module. \code #include <Eigen/Geometry> \endcode" \
+ "householder_module=This is defined in the %Householder module. \code #include <Eigen/Householder> \endcode" \
+ "jacobi_module=This is defined in the %Jacobi module. \code #include <Eigen/Jacobi> \endcode" \
+ "lu_module=This is defined in the %LU module. \code #include <Eigen/LU> \endcode" \
+ "qr_module=This is defined in the %QR module. \code #include <Eigen/QR> \endcode" \
+ "svd_module=This is defined in the %SVD module. \code #include <Eigen/SVD> \endcode" \
+ "label=\bug" \
+ "matrixworld=<a href='#matrixonly' style='color:green;text-decoration: none;'>*</a>" \
+ "arrayworld=<a href='#arrayonly' style='color:blue;text-decoration: none;'>*</a>" \
+ "note_about_arbitrary_choice_of_solution=If there exists more than one solution, this method will arbitrarily choose one." \
+ "note_about_using_kernel_to_study_multiple_solutions=If you need a complete analysis of the space of solutions, take the one solution obtained by this method and add to it elements of the kernel, as determined by kernel()." \
+ "note_about_checking_solutions=This method just tries to find as good a solution as possible. If you want to check whether a solution exists or if it is accurate, just call this function to get a result and then compute the error of this result, or use MatrixBase::isApprox() directly, for instance like this: \code bool a_solution_exists = (A*result).isApprox(b, precision); \endcode This method avoids dividing by zero, so that the non-existence of a solution doesn't by itself mean that you'll get \c inf or \c nan values." \
+ "note_try_to_help_rvo=This function returns the result by value. In order to make that efficient, it is implemented as just a return statement using a special constructor, hopefully allowing the compiler to perform a RVO (return value optimization)."
+
+# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C
+# sources only. Doxygen will then generate output that is more tailored for C.
+# For instance, some of the names that are used will be different. The list
+# of all members will be omitted, etc.
+
+OPTIMIZE_OUTPUT_FOR_C = NO
+
+# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java
+# sources only. Doxygen will then generate output that is more tailored for
+# Java. For instance, namespaces will be presented as packages, qualified
+# scopes will look different, etc.
+
+OPTIMIZE_OUTPUT_JAVA = NO
+
+# Set the OPTIMIZE_FOR_FORTRAN tag to YES if your project consists of Fortran
+# sources only. Doxygen will then generate output that is more tailored for
+# Fortran.
+
+OPTIMIZE_FOR_FORTRAN = NO
+
+# Set the OPTIMIZE_OUTPUT_VHDL tag to YES if your project consists of VHDL
+# sources. Doxygen will then generate output that is tailored for
+# VHDL.
+
+OPTIMIZE_OUTPUT_VHDL = NO
+
+# If you use STL classes (i.e. std::string, std::vector, etc.) but do not want
+# to include (a tag file for) the STL sources as input, then you should
+# set this tag to YES in order to let doxygen match functions declarations and
+# definitions whose arguments contain STL classes (e.g. func(std::string); v.s.
+# func(std::string) {}). This also make the inheritance and collaboration
+# diagrams that involve STL classes more complete and accurate.
+
+BUILTIN_STL_SUPPORT = NO
+
+# If you use Microsoft's C++/CLI language, you should set this option to YES to
+# enable parsing support.
+
+CPP_CLI_SUPPORT = NO
+
+# Set the SIP_SUPPORT tag to YES if your project consists of sip sources only.
+# Doxygen will parse them like normal C++ but will assume all classes use public
+# instead of private inheritance when no explicit protection keyword is present.
+
+SIP_SUPPORT = NO
+
+# For Microsoft's IDL there are propget and propput attributes to indicate getter
+# and setter methods for a property. Setting this option to YES (the default)
+# will make doxygen to replace the get and set methods by a property in the
+# documentation. This will only work if the methods are indeed getting or
+# setting a simple type. If this is not the case, or you want to show the
+# methods anyway, you should set this option to NO.
+
+IDL_PROPERTY_SUPPORT = YES
+
+# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC
+# tag is set to YES, then doxygen will reuse the documentation of the first
+# member in the group (if any) for the other members of the group. By default
+# all members of a group must be documented explicitly.
+
+DISTRIBUTE_GROUP_DOC = NO
+
+# Set the SUBGROUPING tag to YES (the default) to allow class member groups of
+# the same type (for instance a group of public functions) to be put as a
+# subgroup of that type (e.g. under the Public Functions section). Set it to
+# NO to prevent subgrouping. Alternatively, this can be done per class using
+# the \nosubgrouping command.
+
+SUBGROUPING = YES
+
+# When TYPEDEF_HIDES_STRUCT is enabled, a typedef of a struct, union, or enum
+# is documented as struct, union, or enum with the name of the typedef. So
+# typedef struct TypeS {} TypeT, will appear in the documentation as a struct
+# with name TypeT. When disabled the typedef will appear as a member of a file,
+# namespace, or class. And the struct will be named TypeS. This can typically
+# be useful for C code in case the coding convention dictates that all compound
+# types are typedef'ed and only the typedef is referenced, never the tag name.
+
+TYPEDEF_HIDES_STRUCT = NO
+
+#---------------------------------------------------------------------------
+# Build related configuration options
+#---------------------------------------------------------------------------
+
+# If the EXTRACT_ALL tag is set to YES doxygen will assume all entities in
+# documentation are documented, even if no documentation was available.
+# Private class members and static file members will be hidden unless
+# the EXTRACT_PRIVATE and EXTRACT_STATIC tags are set to YES
+
+EXTRACT_ALL = YES
+
+# If the EXTRACT_PRIVATE tag is set to YES all private members of a class
+# will be included in the documentation.
+
+EXTRACT_PRIVATE = NO
+
+# If the EXTRACT_STATIC tag is set to YES all static members of a file
+# will be included in the documentation.
+
+EXTRACT_STATIC = NO
+
+# If the EXTRACT_LOCAL_CLASSES tag is set to YES classes (and structs)
+# defined locally in source files will be included in the documentation.
+# If set to NO only classes defined in header files are included.
+
+EXTRACT_LOCAL_CLASSES = NO
+
+# This flag is only useful for Objective-C code. When set to YES local
+# methods, which are defined in the implementation section but not in
+# the interface are included in the documentation.
+# If set to NO (the default) only methods in the interface are included.
+
+EXTRACT_LOCAL_METHODS = NO
+
+# If this flag is set to YES, the members of anonymous namespaces will be
+# extracted and appear in the documentation as a namespace called
+# 'anonymous_namespace{file}', where file will be replaced with the base
+# name of the file that contains the anonymous namespace. By default
+# anonymous namespace are hidden.
+
+EXTRACT_ANON_NSPACES = NO
+
+# If the HIDE_UNDOC_MEMBERS tag is set to YES, Doxygen will hide all
+# undocumented members of documented classes, files or namespaces.
+# If set to NO (the default) these members will be included in the
+# various overviews, but no documentation section is generated.
+# This option has no effect if EXTRACT_ALL is enabled.
+
+HIDE_UNDOC_MEMBERS = YES
+
+# If the HIDE_UNDOC_CLASSES tag is set to YES, Doxygen will hide all
+# undocumented classes that are normally visible in the class hierarchy.
+# If set to NO (the default) these classes will be included in the various
+# overviews. This option has no effect if EXTRACT_ALL is enabled.
+
+HIDE_UNDOC_CLASSES = YES
+
+# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, Doxygen will hide all
+# friend (class|struct|union) declarations.
+# If set to NO (the default) these declarations will be included in the
+# documentation.
+
+HIDE_FRIEND_COMPOUNDS = YES
+
+# If the HIDE_IN_BODY_DOCS tag is set to YES, Doxygen will hide any
+# documentation blocks found inside the body of a function.
+# If set to NO (the default) these blocks will be appended to the
+# function's detailed documentation block.
+
+HIDE_IN_BODY_DOCS = NO
+
+# The INTERNAL_DOCS tag determines if documentation
+# that is typed after a \internal command is included. If the tag is set
+# to NO (the default) then the documentation will be excluded.
+# Set it to YES to include the internal documentation.
+
+INTERNAL_DOCS = NO
+
+# If the CASE_SENSE_NAMES tag is set to NO then Doxygen will only generate
+# file names in lower-case letters. If set to YES upper-case letters are also
+# allowed. This is useful if you have classes or files whose names only differ
+# in case and if your file system supports case sensitive file names. Windows
+# and Mac users are advised to set this option to NO.
+
+CASE_SENSE_NAMES = YES
+
+# If the HIDE_SCOPE_NAMES tag is set to NO (the default) then Doxygen
+# will show members with their full class and namespace scopes in the
+# documentation. If set to YES the scope will be hidden.
+
+HIDE_SCOPE_NAMES = YES
+
+# If the SHOW_INCLUDE_FILES tag is set to YES (the default) then Doxygen
+# will put a list of the files that are included by a file in the documentation
+# of that file.
+
+SHOW_INCLUDE_FILES = YES
+
+# If the INLINE_INFO tag is set to YES (the default) then a tag [inline]
+# is inserted in the documentation for inline members.
+
+INLINE_INFO = YES
+
+# If the SORT_MEMBER_DOCS tag is set to YES (the default) then doxygen
+# will sort the (detailed) documentation of file and class members
+# alphabetically by member name. If set to NO the members will appear in
+# declaration order.
+
+SORT_MEMBER_DOCS = YES
+
+# If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the
+# brief documentation of file, namespace and class members alphabetically
+# by member name. If set to NO (the default) the members will appear in
+# declaration order.
+
+SORT_BRIEF_DOCS = YES
+
+# If the SORT_GROUP_NAMES tag is set to YES then doxygen will sort the
+# hierarchy of group names into alphabetical order. If set to NO (the default)
+# the group names will appear in their defined order.
+
+SORT_GROUP_NAMES = NO
+
+# If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be
+# sorted by fully-qualified names, including namespaces. If set to
+# NO (the default), the class list will be sorted only by class name,
+# not including the namespace part.
+# Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES.
+# Note: This option applies only to the class list, not to the
+# alphabetical list.
+
+SORT_BY_SCOPE_NAME = NO
+
+# The GENERATE_TODOLIST tag can be used to enable (YES) or
+# disable (NO) the todo list. This list is created by putting \todo
+# commands in the documentation.
+
+GENERATE_TODOLIST = NO
+
+# The GENERATE_TESTLIST tag can be used to enable (YES) or
+# disable (NO) the test list. This list is created by putting \test
+# commands in the documentation.
+
+GENERATE_TESTLIST = NO
+
+# The GENERATE_BUGLIST tag can be used to enable (YES) or
+# disable (NO) the bug list. This list is created by putting \bug
+# commands in the documentation.
+
+GENERATE_BUGLIST = NO
+
+# The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or
+# disable (NO) the deprecated list. This list is created by putting
+# \deprecated commands in the documentation.
+
+GENERATE_DEPRECATEDLIST= NO
+
+# The ENABLED_SECTIONS tag can be used to enable conditional
+# documentation sections, marked by \if sectionname ... \endif.
+
+ENABLED_SECTIONS =
+
+# The MAX_INITIALIZER_LINES tag determines the maximum number of lines
+# the initial value of a variable or define consists of for it to appear in
+# the documentation. If the initializer consists of more lines than specified
+# here it will be hidden. Use a value of 0 to hide initializers completely.
+# The appearance of the initializer of individual variables and defines in the
+# documentation can be controlled using \showinitializer or \hideinitializer
+# command in the documentation regardless of this setting.
+
+MAX_INITIALIZER_LINES = 0
+
+# Set the SHOW_USED_FILES tag to NO to disable the list of files generated
+# at the bottom of the documentation of classes and structs. If set to YES the
+# list will mention the files that were used to generate the documentation.
+
+SHOW_USED_FILES = YES
+
+# If the sources in your project are distributed over multiple directories
+# then setting the SHOW_DIRECTORIES tag to YES will show the directory hierarchy
+# in the documentation. The default is NO.
+
+SHOW_DIRECTORIES = NO
+
+# Set the SHOW_FILES tag to NO to disable the generation of the Files page.
+# This will remove the Files entry from the Quick Index and from the
+# Folder Tree View (if specified). The default is YES.
+
+SHOW_FILES = YES
+
+# Set the SHOW_NAMESPACES tag to NO to disable the generation of the
+# Namespaces page. This will remove the Namespaces entry from the Quick Index
+# and from the Folder Tree View (if specified). The default is YES.
+
+SHOW_NAMESPACES = YES
+
+# The FILE_VERSION_FILTER tag can be used to specify a program or script that
+# doxygen should invoke to get the current version for each file (typically from
+# the version control system). Doxygen will invoke the program by executing (via
+# popen()) the command <command> <input-file>, where <command> is the value of
+# the FILE_VERSION_FILTER tag, and <input-file> is the name of an input file
+# provided by doxygen. Whatever the program writes to standard output
+# is used as the file version. See the manual for examples.
+
+FILE_VERSION_FILTER =
+
+#---------------------------------------------------------------------------
+# configuration options related to warning and progress messages
+#---------------------------------------------------------------------------
+
+# The QUIET tag can be used to turn on/off the messages that are generated
+# by doxygen. Possible values are YES and NO. If left blank NO is used.
+
+QUIET = NO
+
+# The WARNINGS tag can be used to turn on/off the warning messages that are
+# generated by doxygen. Possible values are YES and NO. If left blank
+# NO is used.
+
+WARNINGS = YES
+
+# If WARN_IF_UNDOCUMENTED is set to YES, then doxygen will generate warnings
+# for undocumented members. If EXTRACT_ALL is set to YES then this flag will
+# automatically be disabled.
+
+WARN_IF_UNDOCUMENTED = NO
+
+# If WARN_IF_DOC_ERROR is set to YES, doxygen will generate warnings for
+# potential errors in the documentation, such as not documenting some
+# parameters in a documented function, or documenting parameters that
+# don't exist or using markup commands wrongly.
+
+WARN_IF_DOC_ERROR = YES
+
+# This WARN_NO_PARAMDOC option can be abled to get warnings for
+# functions that are documented, but have no documentation for their parameters
+# or return value. If set to NO (the default) doxygen will only warn about
+# wrong or incomplete parameter documentation, but not about the absence of
+# documentation.
+
+WARN_NO_PARAMDOC = NO
+
+# The WARN_FORMAT tag determines the format of the warning messages that
+# doxygen can produce. The string should contain the $file, $line, and $text
+# tags, which will be replaced by the file and line number from which the
+# warning originated and the warning text. Optionally the format may contain
+# $version, which will be replaced by the version of the file (if it could
+# be obtained via FILE_VERSION_FILTER)
+
+WARN_FORMAT = "$file:$line: $text"
+
+# The WARN_LOGFILE tag can be used to specify a file to which warning
+# and error messages should be written. If left blank the output is written
+# to stderr.
+
+WARN_LOGFILE =
+
+#---------------------------------------------------------------------------
+# configuration options related to the input files
+#---------------------------------------------------------------------------
+
+# The INPUT tag can be used to specify the files and/or directories that contain
+# documented source files. You may enter file names like "myfile.cpp" or
+# directories like "/usr/src/myproject". Separate the files or directories
+# with spaces.
+
+INPUT = "${Eigen_SOURCE_DIR}/Eigen" \
+ "${Eigen_SOURCE_DIR}/doc"
+
+# This tag can be used to specify the character encoding of the source files
+# that doxygen parses. Internally doxygen uses the UTF-8 encoding, which is
+# also the default input encoding. Doxygen uses libiconv (or the iconv built
+# into libc) for the transcoding. See http://www.gnu.org/software/libiconv for
+# the list of possible encodings.
+
+INPUT_ENCODING = UTF-8
+
+# If the value of the INPUT tag contains directories, you can use the
+# FILE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp
+# and *.h) to filter out the source-files in the directories. If left
+# blank the following patterns are tested:
+# *.c *.cc *.cxx *.cpp *.c++ *.java *.ii *.ixx *.ipp *.i++ *.inl *.h *.hh *.hxx
+# *.hpp *.h++ *.idl *.odl *.cs *.php *.php3 *.inc *.m *.mm *.py *.f90
+
+FILE_PATTERNS = *
+
+# The RECURSIVE tag can be used to turn specify whether or not subdirectories
+# should be searched for input files as well. Possible values are YES and NO.
+# If left blank NO is used.
+
+RECURSIVE = YES
+
+# The EXCLUDE tag can be used to specify files and/or directories that should
+# excluded from the INPUT source files. This way you can easily exclude a
+# subdirectory from a directory tree whose root is specified with the INPUT tag.
+
+EXCLUDE = "${Eigen_SOURCE_DIR}/Eigen/Eigen2Support" \
+ "${Eigen_SOURCE_DIR}/Eigen/src/Eigen2Support" \
+ "${Eigen_SOURCE_DIR}/doc/examples" \
+ "${Eigen_SOURCE_DIR}/doc/special_examples" \
+ "${Eigen_SOURCE_DIR}/doc/snippets"
+
+# The EXCLUDE_SYMLINKS tag can be used select whether or not files or
+# directories that are symbolic links (a Unix filesystem feature) are excluded
+# from the input.
+
+EXCLUDE_SYMLINKS = NO
+
+# If the value of the INPUT tag contains directories, you can use the
+# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude
+# certain files from those directories. Note that the wildcards are matched
+# against the file with absolute path, so to exclude all test directories
+# for example use the pattern */test/*
+
+EXCLUDE_PATTERNS = CMake* \
+ *.txt \
+ *.sh \
+ *.orig \
+ *.diff \
+ diff \
+ *~ \
+ *. \
+ *.sln \
+ *.sdf \
+ *.tmp \
+ *.vcxproj \
+ *.filters \
+ *.user \
+ *.suo
+
+# The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names
+# (namespaces, classes, functions, etc.) that should be excluded from the
+# output. The symbol name can be a fully qualified name, a word, or if the
+# wildcard * is used, a substring. Examples: ANamespace, AClass,
+# AClass::ANamespace, ANamespace::*Test
+
+# This could used to clean up the "class hierarchy" page
+EXCLUDE_SYMBOLS = internal::* Flagged* *InnerIterator* DenseStorage<*
+
+# The EXAMPLE_PATH tag can be used to specify one or more files or
+# directories that contain example code fragments that are included (see
+# the \include command).
+
+EXAMPLE_PATH = "${Eigen_SOURCE_DIR}/doc/snippets" \
+ "${Eigen_BINARY_DIR}/doc/snippets" \
+ "${Eigen_SOURCE_DIR}/doc/examples" \
+ "${Eigen_BINARY_DIR}/doc/examples" \
+ "${Eigen_SOURCE_DIR}/doc/special_examples" \
+ "${Eigen_BINARY_DIR}/doc/special_examples"
+
+# If the value of the EXAMPLE_PATH tag contains directories, you can use the
+# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp
+# and *.h) to filter out the source-files in the directories. If left
+# blank all files are included.
+
+EXAMPLE_PATTERNS = *
+
+# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be
+# searched for input files to be used with the \include or \dontinclude
+# commands irrespective of the value of the RECURSIVE tag.
+# Possible values are YES and NO. If left blank NO is used.
+
+EXAMPLE_RECURSIVE = NO
+
+# The IMAGE_PATH tag can be used to specify one or more files or
+# directories that contain image that are included in the documentation (see
+# the \image command).
+
+IMAGE_PATH =
+
+# The INPUT_FILTER tag can be used to specify a program that doxygen should
+# invoke to filter for each input file. Doxygen will invoke the filter program
+# by executing (via popen()) the command <filter> <input-file>, where <filter>
+# is the value of the INPUT_FILTER tag, and <input-file> is the name of an
+# input file. Doxygen will then use the output that the filter program writes
+# to standard output. If FILTER_PATTERNS is specified, this tag will be
+# ignored.
+
+INPUT_FILTER =
+
+# The FILTER_PATTERNS tag can be used to specify filters on a per file pattern
+# basis. Doxygen will compare the file name with each pattern and apply the
+# filter if there is a match. The filters are a list of the form:
+# pattern=filter (like *.cpp=my_cpp_filter). See INPUT_FILTER for further
+# info on how filters are used. If FILTER_PATTERNS is empty, INPUT_FILTER
+# is applied to all files.
+
+FILTER_PATTERNS =
+
+# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using
+# INPUT_FILTER) will be used to filter the input files when producing source
+# files to browse (i.e. when SOURCE_BROWSER is set to YES).
+
+FILTER_SOURCE_FILES = NO
+
+#---------------------------------------------------------------------------
+# configuration options related to source browsing
+#---------------------------------------------------------------------------
+
+# If the SOURCE_BROWSER tag is set to YES then a list of source files will
+# be generated. Documented entities will be cross-referenced with these sources.
+# Note: To get rid of all source code in the generated output, make sure also
+# VERBATIM_HEADERS is set to NO.
+
+SOURCE_BROWSER = NO
+
+# Setting the INLINE_SOURCES tag to YES will include the body
+# of functions and classes directly in the documentation.
+
+INLINE_SOURCES = NO
+
+# Setting the STRIP_CODE_COMMENTS tag to YES (the default) will instruct
+# doxygen to hide any special comment blocks from generated source code
+# fragments. Normal C and C++ comments will always remain visible.
+
+STRIP_CODE_COMMENTS = YES
+
+# If the REFERENCED_BY_RELATION tag is set to YES
+# then for each documented function all documented
+# functions referencing it will be listed.
+
+REFERENCED_BY_RELATION = YES
+
+# If the REFERENCES_RELATION tag is set to YES
+# then for each documented function all documented entities
+# called/used by that function will be listed.
+
+REFERENCES_RELATION = YES
+
+# If the REFERENCES_LINK_SOURCE tag is set to YES (the default)
+# and SOURCE_BROWSER tag is set to YES, then the hyperlinks from
+# functions in REFERENCES_RELATION and REFERENCED_BY_RELATION lists will
+# link to the source code. Otherwise they will link to the documentstion.
+
+REFERENCES_LINK_SOURCE = YES
+
+# If the USE_HTAGS tag is set to YES then the references to source code
+# will point to the HTML generated by the htags(1) tool instead of doxygen
+# built-in source browser. The htags tool is part of GNU's global source
+# tagging system (see http://www.gnu.org/software/global/global.html). You
+# will need version 4.8.6 or higher.
+
+USE_HTAGS = NO
+
+# If the VERBATIM_HEADERS tag is set to YES (the default) then Doxygen
+# will generate a verbatim copy of the header file for each class for
+# which an include is specified. Set to NO to disable this.
+
+VERBATIM_HEADERS = YES
+
+#---------------------------------------------------------------------------
+# configuration options related to the alphabetical class index
+#---------------------------------------------------------------------------
+
+# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index
+# of all compounds will be generated. Enable this if the project
+# contains a lot of classes, structs, unions or interfaces.
+
+ALPHABETICAL_INDEX = NO
+
+# If the alphabetical index is enabled (see ALPHABETICAL_INDEX) then
+# the COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns
+# in which this list will be split (can be a number in the range [1..20])
+
+COLS_IN_ALPHA_INDEX = 5
+
+# In case all classes in a project start with a common prefix, all
+# classes will be put under the same header in the alphabetical index.
+# The IGNORE_PREFIX tag can be used to specify one or more prefixes that
+# should be ignored while generating the index headers.
+
+IGNORE_PREFIX =
+
+#---------------------------------------------------------------------------
+# configuration options related to the HTML output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_HTML tag is set to YES (the default) Doxygen will
+# generate HTML output.
+
+GENERATE_HTML = YES
+
+# The HTML_OUTPUT tag is used to specify where the HTML docs will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be
+# put in front of it. If left blank `html' will be used as the default path.
+
+HTML_OUTPUT = html
+
+# The HTML_FILE_EXTENSION tag can be used to specify the file extension for
+# each generated HTML page (for example: .htm,.php,.asp). If it is left blank
+# doxygen will generate files with .html extension.
+
+HTML_FILE_EXTENSION = .html
+
+# The HTML_HEADER tag can be used to specify a personal HTML header for
+# each generated HTML page. If it is left blank doxygen will generate a
+# standard header.
+
+HTML_HEADER = "${Eigen_BINARY_DIR}/doc/eigendoxy_header.html"
+
+# The HTML_FOOTER tag can be used to specify a personal HTML footer for
+# each generated HTML page. If it is left blank doxygen will generate a
+# standard footer.
+
+# the footer has not been customized yet, so let's use the default one
+# ${Eigen_BINARY_DIR}/doc/eigendoxy_footer.html
+HTML_FOOTER =
+
+# The HTML_STYLESHEET tag can be used to specify a user-defined cascading
+# style sheet that is used by each HTML page. It can be used to
+# fine-tune the look of the HTML output. If the tag is left blank doxygen
+# will generate a default style sheet. Note that doxygen will try to copy
+# the style sheet file to the HTML output directory, so don't put your own
+# stylesheet in the HTML output directory as well, or it will be erased!
+
+HTML_STYLESHEET = "${Eigen_SOURCE_DIR}/doc/eigendoxy.css"
+
+# If the HTML_ALIGN_MEMBERS tag is set to YES, the members of classes,
+# files or namespaces will be aligned in HTML using tables. If set to
+# NO a bullet list will be used.
+
+HTML_ALIGN_MEMBERS = YES
+
+# If the GENERATE_HTMLHELP tag is set to YES, additional index files
+# will be generated that can be used as input for tools like the
+# Microsoft HTML help workshop to generate a compiled HTML help file (.chm)
+# of the generated HTML documentation.
+
+GENERATE_HTMLHELP = NO
+
+# If the GENERATE_DOCSET tag is set to YES, additional index files
+# will be generated that can be used as input for Apple's Xcode 3
+# integrated development environment, introduced with OSX 10.5 (Leopard).
+# To create a documentation set, doxygen will generate a Makefile in the
+# HTML output directory. Running make will produce the docset in that
+# directory and running "make install" will install the docset in
+# ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find
+# it at startup.
+
+GENERATE_DOCSET = NO
+
+# When GENERATE_DOCSET tag is set to YES, this tag determines the name of the
+# feed. A documentation feed provides an umbrella under which multiple
+# documentation sets from a single provider (such as a company or product suite)
+# can be grouped.
+
+DOCSET_FEEDNAME = "Doxygen generated docs"
+
+# When GENERATE_DOCSET tag is set to YES, this tag specifies a string that
+# should uniquely identify the documentation set bundle. This should be a
+# reverse domain-name style string, e.g. com.mycompany.MyDocSet. Doxygen
+# will append .docset to the name.
+
+DOCSET_BUNDLE_ID = org.doxygen.Project
+
+# If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML
+# documentation will contain sections that can be hidden and shown after the
+# page has loaded. For this to work a browser that supports
+# JavaScript and DHTML is required (for instance Mozilla 1.0+, Firefox
+# Netscape 6.0+, Internet explorer 5.0+, Konqueror, or Safari).
+
+HTML_DYNAMIC_SECTIONS = YES
+
+# If the GENERATE_HTMLHELP tag is set to YES, the CHM_FILE tag can
+# be used to specify the file name of the resulting .chm file. You
+# can add a path in front of the file if the result should not be
+# written to the html output directory.
+
+CHM_FILE =
+
+# If the GENERATE_HTMLHELP tag is set to YES, the HHC_LOCATION tag can
+# be used to specify the location (absolute path including file name) of
+# the HTML help compiler (hhc.exe). If non-empty doxygen will try to run
+# the HTML help compiler on the generated index.hhp.
+
+HHC_LOCATION =
+
+# If the GENERATE_HTMLHELP tag is set to YES, the GENERATE_CHI flag
+# controls if a separate .chi index file is generated (YES) or that
+# it should be included in the master .chm file (NO).
+
+GENERATE_CHI = NO
+
+# If the GENERATE_HTMLHELP tag is set to YES, the CHM_INDEX_ENCODING
+# is used to encode HtmlHelp index (hhk), content (hhc) and project file
+# content.
+
+CHM_INDEX_ENCODING =
+
+# If the GENERATE_HTMLHELP tag is set to YES, the BINARY_TOC flag
+# controls whether a binary table of contents is generated (YES) or a
+# normal table of contents (NO) in the .chm file.
+
+BINARY_TOC = NO
+
+# The TOC_EXPAND flag can be set to YES to add extra items for group members
+# to the contents of the HTML help documentation and to the tree view.
+
+TOC_EXPAND = NO
+
+# The DISABLE_INDEX tag can be used to turn on/off the condensed index at
+# top of each HTML page. The value NO (the default) enables the index and
+# the value YES disables it.
+
+DISABLE_INDEX = NO
+
+# This tag can be used to set the number of enum values (range [1..20])
+# that doxygen will group on one line in the generated HTML documentation.
+
+ENUM_VALUES_PER_LINE = 1
+
+# The GENERATE_TREEVIEW tag is used to specify whether a tree-like index
+# structure should be generated to display hierarchical information.
+# If the tag value is set to FRAME, a side panel will be generated
+# containing a tree-like index structure (just like the one that
+# is generated for HTML Help). For this to work a browser that supports
+# JavaScript, DHTML, CSS and frames is required (for instance Mozilla 1.0+,
+# Netscape 6.0+, Internet explorer 5.0+, or Konqueror). Windows users are
+# probably better off using the HTML help feature. Other possible values
+# for this tag are: HIERARCHIES, which will generate the Groups, Directories,
+# and Class Hiererachy pages using a tree view instead of an ordered list;
+# ALL, which combines the behavior of FRAME and HIERARCHIES; and NONE, which
+# disables this behavior completely. For backwards compatibility with previous
+# releases of Doxygen, the values YES and NO are equivalent to FRAME and NONE
+# respectively.
+
+GENERATE_TREEVIEW = NO
+
+# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be
+# used to set the initial width (in pixels) of the frame in which the tree
+# is shown.
+
+TREEVIEW_WIDTH = 250
+
+# Use this tag to change the font size of Latex formulas included
+# as images in the HTML documentation. The default is 10. Note that
+# when you change the font size after a successful doxygen run you need
+# to manually remove any form_*.png images from the HTML output directory
+# to force them to be regenerated.
+
+FORMULA_FONTSIZE = 12
+
+#---------------------------------------------------------------------------
+# configuration options related to the LaTeX output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_LATEX tag is set to YES (the default) Doxygen will
+# generate Latex output.
+
+GENERATE_LATEX = NO
+
+# The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be
+# put in front of it. If left blank `latex' will be used as the default path.
+
+LATEX_OUTPUT = latex
+
+# The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be
+# invoked. If left blank `latex' will be used as the default command name.
+
+LATEX_CMD_NAME = latex
+
+# The MAKEINDEX_CMD_NAME tag can be used to specify the command name to
+# generate index for LaTeX. If left blank `makeindex' will be used as the
+# default command name.
+
+MAKEINDEX_CMD_NAME = makeindex
+
+# If the COMPACT_LATEX tag is set to YES Doxygen generates more compact
+# LaTeX documents. This may be useful for small projects and may help to
+# save some trees in general.
+
+COMPACT_LATEX = NO
+
+# The PAPER_TYPE tag can be used to set the paper type that is used
+# by the printer. Possible values are: a4, a4wide, letter, legal and
+# executive. If left blank a4wide will be used.
+
+PAPER_TYPE = a4wide
+
+# The EXTRA_PACKAGES tag can be to specify one or more names of LaTeX
+# packages that should be included in the LaTeX output.
+
+EXTRA_PACKAGES = amssymb \
+ amsmath
+
+# The LATEX_HEADER tag can be used to specify a personal LaTeX header for
+# the generated latex document. The header should contain everything until
+# the first chapter. If it is left blank doxygen will generate a
+# standard header. Notice: only use this tag if you know what you are doing!
+
+LATEX_HEADER =
+
+# If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated
+# is prepared for conversion to pdf (using ps2pdf). The pdf file will
+# contain links (just like the HTML output) instead of page references
+# This makes the output suitable for online browsing using a pdf viewer.
+
+PDF_HYPERLINKS = NO
+
+# If the USE_PDFLATEX tag is set to YES, pdflatex will be used instead of
+# plain latex in the generated Makefile. Set this option to YES to get a
+# higher quality PDF documentation.
+
+USE_PDFLATEX = NO
+
+# If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \\batchmode.
+# command to the generated LaTeX files. This will instruct LaTeX to keep
+# running if errors occur, instead of asking the user for help.
+# This option is also used when generating formulas in HTML.
+
+LATEX_BATCHMODE = NO
+
+# If LATEX_HIDE_INDICES is set to YES then doxygen will not
+# include the index chapters (such as File Index, Compound Index, etc.)
+# in the output.
+
+LATEX_HIDE_INDICES = NO
+
+#---------------------------------------------------------------------------
+# configuration options related to the RTF output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_RTF tag is set to YES Doxygen will generate RTF output
+# The RTF output is optimized for Word 97 and may not look very pretty with
+# other RTF readers or editors.
+
+GENERATE_RTF = NO
+
+# The RTF_OUTPUT tag is used to specify where the RTF docs will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be
+# put in front of it. If left blank `rtf' will be used as the default path.
+
+RTF_OUTPUT = rtf
+
+# If the COMPACT_RTF tag is set to YES Doxygen generates more compact
+# RTF documents. This may be useful for small projects and may help to
+# save some trees in general.
+
+COMPACT_RTF = NO
+
+# If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated
+# will contain hyperlink fields. The RTF file will
+# contain links (just like the HTML output) instead of page references.
+# This makes the output suitable for online browsing using WORD or other
+# programs which support those fields.
+# Note: wordpad (write) and others do not support links.
+
+RTF_HYPERLINKS = NO
+
+# Load stylesheet definitions from file. Syntax is similar to doxygen's
+# config file, i.e. a series of assignments. You only have to provide
+# replacements, missing definitions are set to their default value.
+
+RTF_STYLESHEET_FILE =
+
+# Set optional variables used in the generation of an rtf document.
+# Syntax is similar to doxygen's config file.
+
+RTF_EXTENSIONS_FILE =
+
+#---------------------------------------------------------------------------
+# configuration options related to the man page output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_MAN tag is set to YES (the default) Doxygen will
+# generate man pages
+
+GENERATE_MAN = NO
+
+# The MAN_OUTPUT tag is used to specify where the man pages will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be
+# put in front of it. If left blank `man' will be used as the default path.
+
+MAN_OUTPUT = man
+
+# The MAN_EXTENSION tag determines the extension that is added to
+# the generated man pages (default is the subroutine's section .3)
+
+MAN_EXTENSION = .3
+
+# If the MAN_LINKS tag is set to YES and Doxygen generates man output,
+# then it will generate one additional man file for each entity
+# documented in the real man page(s). These additional files
+# only source the real man page, but without them the man command
+# would be unable to find the correct page. The default is NO.
+
+MAN_LINKS = NO
+
+#---------------------------------------------------------------------------
+# configuration options related to the XML output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_XML tag is set to YES Doxygen will
+# generate an XML file that captures the structure of
+# the code including all documentation.
+
+GENERATE_XML = NO
+
+# The XML_OUTPUT tag is used to specify where the XML pages will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be
+# put in front of it. If left blank `xml' will be used as the default path.
+
+XML_OUTPUT = xml
+
+# The XML_SCHEMA tag can be used to specify an XML schema,
+# which can be used by a validating XML parser to check the
+# syntax of the XML files.
+
+XML_SCHEMA =
+
+# The XML_DTD tag can be used to specify an XML DTD,
+# which can be used by a validating XML parser to check the
+# syntax of the XML files.
+
+XML_DTD =
+
+# If the XML_PROGRAMLISTING tag is set to YES Doxygen will
+# dump the program listings (including syntax highlighting
+# and cross-referencing information) to the XML output. Note that
+# enabling this will significantly increase the size of the XML output.
+
+XML_PROGRAMLISTING = YES
+
+#---------------------------------------------------------------------------
+# configuration options for the AutoGen Definitions output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_AUTOGEN_DEF tag is set to YES Doxygen will
+# generate an AutoGen Definitions (see autogen.sf.net) file
+# that captures the structure of the code including all
+# documentation. Note that this feature is still experimental
+# and incomplete at the moment.
+
+GENERATE_AUTOGEN_DEF = NO
+
+#---------------------------------------------------------------------------
+# configuration options related to the Perl module output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_PERLMOD tag is set to YES Doxygen will
+# generate a Perl module file that captures the structure of
+# the code including all documentation. Note that this
+# feature is still experimental and incomplete at the
+# moment.
+
+GENERATE_PERLMOD = NO
+
+# If the PERLMOD_LATEX tag is set to YES Doxygen will generate
+# the necessary Makefile rules, Perl scripts and LaTeX code to be able
+# to generate PDF and DVI output from the Perl module output.
+
+PERLMOD_LATEX = NO
+
+# If the PERLMOD_PRETTY tag is set to YES the Perl module output will be
+# nicely formatted so it can be parsed by a human reader. This is useful
+# if you want to understand what is going on. On the other hand, if this
+# tag is set to NO the size of the Perl module output will be much smaller
+# and Perl will parse it just the same.
+
+PERLMOD_PRETTY = YES
+
+# The names of the make variables in the generated doxyrules.make file
+# are prefixed with the string contained in PERLMOD_MAKEVAR_PREFIX.
+# This is useful so different doxyrules.make files included by the same
+# Makefile don't overwrite each other's variables.
+
+PERLMOD_MAKEVAR_PREFIX =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the preprocessor
+#---------------------------------------------------------------------------
+
+# If the ENABLE_PREPROCESSING tag is set to YES (the default) Doxygen will
+# evaluate all C-preprocessor directives found in the sources and include
+# files.
+
+ENABLE_PREPROCESSING = YES
+
+# If the MACRO_EXPANSION tag is set to YES Doxygen will expand all macro
+# names in the source code. If set to NO (the default) only conditional
+# compilation will be performed. Macro expansion can be done in a controlled
+# way by setting EXPAND_ONLY_PREDEF to YES.
+
+MACRO_EXPANSION = YES
+
+# If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES
+# then the macro expansion is limited to the macros specified with the
+# PREDEFINED and EXPAND_AS_DEFINED tags.
+
+EXPAND_ONLY_PREDEF = YES
+
+# If the SEARCH_INCLUDES tag is set to YES (the default) the includes files
+# in the INCLUDE_PATH (see below) will be search if a #include is found.
+
+SEARCH_INCLUDES = YES
+
+# The INCLUDE_PATH tag can be used to specify one or more directories that
+# contain include files that are not input files but should be processed by
+# the preprocessor.
+
+INCLUDE_PATH = "${Eigen_SOURCE_DIR}/Eigen/src/plugins"
+
+# You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard
+# patterns (like *.h and *.hpp) to filter out the header-files in the
+# directories. If left blank, the patterns specified with FILE_PATTERNS will
+# be used.
+
+INCLUDE_FILE_PATTERNS =
+
+# The PREDEFINED tag can be used to specify one or more macro names that
+# are defined before the preprocessor is started (similar to the -D option of
+# gcc). The argument of the tag is a list of macros of the form: name
+# or name=definition (no spaces). If the definition and the = are
+# omitted =1 is assumed. To prevent a macro definition from being
+# undefined via #undef or recursively expanded use the := operator
+# instead of the = operator.
+
+PREDEFINED = EIGEN_EMPTY_STRUCT \
+ EIGEN_PARSED_BY_DOXYGEN \
+ EIGEN_VECTORIZE \
+ EIGEN_QT_SUPPORT \
+ EIGEN_STRONG_INLINE=inline \
+ EIGEN2_SUPPORT_STAGE=99
+
+# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then
+# this tag can be used to specify a list of macro names that should be expanded.
+# The macro definition that is found in the sources will be used.
+# Use the PREDEFINED tag if you want to use a different macro definition.
+
+EXPAND_AS_DEFINED = EIGEN_MAKE_TYPEDEFS \
+ EIGEN_MAKE_FIXED_TYPEDEFS \
+ EIGEN_MAKE_TYPEDEFS_ALL_SIZES \
+ EIGEN_MAKE_CWISE_BINARY_OP \
+ EIGEN_CWISE_UNOP_RETURN_TYPE \
+ EIGEN_CWISE_BINOP_RETURN_TYPE \
+ EIGEN_CWISE_PRODUCT_RETURN_TYPE \
+ EIGEN_CURRENT_STORAGE_BASE_CLASS \
+ _EIGEN_GENERIC_PUBLIC_INTERFACE \
+ EIGEN2_SUPPORT
+
+# If the SKIP_FUNCTION_MACROS tag is set to YES (the default) then
+# doxygen's preprocessor will remove all function-like macros that are alone
+# on a line, have an all uppercase name, and do not end with a semicolon. Such
+# function macros are typically used for boiler-plate code, and will confuse
+# the parser if not removed.
+
+SKIP_FUNCTION_MACROS = YES
+
+#---------------------------------------------------------------------------
+# Configuration::additions related to external references
+#---------------------------------------------------------------------------
+
+# The TAGFILES option can be used to specify one or more tagfiles.
+# Optionally an initial location of the external documentation
+# can be added for each tagfile. The format of a tag file without
+# this location is as follows:
+# TAGFILES = file1 file2 ...
+# Adding location for the tag files is done as follows:
+# TAGFILES = file1=loc1 "file2 = loc2" ...
+# where "loc1" and "loc2" can be relative or absolute paths or
+# URLs. If a location is present for each tag, the installdox tool
+# does not have to be run to correct the links.
+# Note that each tag file must have a unique name
+# (where the name does NOT include the path)
+# If a tag file is not located in the directory in which doxygen
+# is run, you must also specify the path to the tagfile here.
+
+TAGFILES = "${Eigen_BINARY_DIR}/doc/eigen-unsupported.doxytags"=unsupported
+
+# When a file name is specified after GENERATE_TAGFILE, doxygen will create
+# a tag file that is based on the input files it reads.
+
+GENERATE_TAGFILE = "${Eigen_BINARY_DIR}/doc/eigen.doxytags"
+
+# If the ALLEXTERNALS tag is set to YES all external classes will be listed
+# in the class index. If set to NO only the inherited external classes
+# will be listed.
+
+ALLEXTERNALS = NO
+
+# If the EXTERNAL_GROUPS tag is set to YES all external groups will be listed
+# in the modules index. If set to NO, only the current project's groups will
+# be listed.
+
+EXTERNAL_GROUPS = YES
+
+# The PERL_PATH should be the absolute path and name of the perl script
+# interpreter (i.e. the result of `which perl').
+
+PERL_PATH = /usr/bin/perl
+
+#---------------------------------------------------------------------------
+# Configuration options related to the dot tool
+#---------------------------------------------------------------------------
+
+# If the CLASS_DIAGRAMS tag is set to YES (the default) Doxygen will
+# generate a inheritance diagram (in HTML, RTF and LaTeX) for classes with base
+# or super classes. Setting the tag to NO turns the diagrams off. Note that
+# this option is superseded by the HAVE_DOT option below. This is only a
+# fallback. It is recommended to install and use dot, since it yields more
+# powerful graphs.
+
+CLASS_DIAGRAMS = YES
+
+# You can define message sequence charts within doxygen comments using the \msc
+# command. Doxygen will then run the mscgen tool (see
+# http://www.mcternan.me.uk/mscgen/) to produce the chart and insert it in the
+# documentation. The MSCGEN_PATH tag allows you to specify the directory where
+# the mscgen tool resides. If left empty the tool is assumed to be found in the
+# default search path.
+
+MSCGEN_PATH =
+
+# If set to YES, the inheritance and collaboration graphs will hide
+# inheritance and usage relations if the target is undocumented
+# or is not a class.
+
+HIDE_UNDOC_RELATIONS = NO
+
+# If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is
+# available from the path. This tool is part of Graphviz, a graph visualization
+# toolkit from AT&T and Lucent Bell Labs. The other options in this section
+# have no effect if this option is set to NO (the default)
+
+HAVE_DOT = YES
+
+# By default doxygen will write a font called FreeSans.ttf to the output
+# directory and reference it in all dot files that doxygen generates. This
+# font does not include all possible unicode characters however, so when you need
+# these (or just want a differently looking font) you can specify the font name
+# using DOT_FONTNAME. You need need to make sure dot is able to find the font,
+# which can be done by putting it in a standard location or by setting the
+# DOTFONTPATH environment variable or by setting DOT_FONTPATH to the directory
+# containing the font.
+
+DOT_FONTNAME = FreeSans
+
+# By default doxygen will tell dot to use the output directory to look for the
+# FreeSans.ttf font (which doxygen will put there itself). If you specify a
+# different font using DOT_FONTNAME you can set the path where dot
+# can find it using this tag.
+
+DOT_FONTPATH =
+
+# If the CLASS_GRAPH and HAVE_DOT tags are set to YES then doxygen
+# will generate a graph for each documented class showing the direct and
+# indirect inheritance relations. Setting this tag to YES will force the
+# the CLASS_DIAGRAMS tag to NO.
+
+CLASS_GRAPH = YES
+
+# If the COLLABORATION_GRAPH and HAVE_DOT tags are set to YES then doxygen
+# will generate a graph for each documented class showing the direct and
+# indirect implementation dependencies (inheritance, containment, and
+# class references variables) of the class with other documented classes.
+
+COLLABORATION_GRAPH = NO
+
+# If the GROUP_GRAPHS and HAVE_DOT tags are set to YES then doxygen
+# will generate a graph for groups, showing the direct groups dependencies
+
+GROUP_GRAPHS = NO
+
+# If the UML_LOOK tag is set to YES doxygen will generate inheritance and
+# collaboration diagrams in a style similar to the OMG's Unified Modeling
+# Language.
+
+UML_LOOK = YES
+
+# If set to YES, the inheritance and collaboration graphs will show the
+# relations between templates and their instances.
+
+TEMPLATE_RELATIONS = NO
+
+# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDE_GRAPH, and HAVE_DOT
+# tags are set to YES then doxygen will generate a graph for each documented
+# file showing the direct and indirect include dependencies of the file with
+# other documented files.
+
+INCLUDE_GRAPH = NO
+
+# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDED_BY_GRAPH, and
+# HAVE_DOT tags are set to YES then doxygen will generate a graph for each
+# documented header file showing the documented files that directly or
+# indirectly include this file.
+
+INCLUDED_BY_GRAPH = NO
+
+# If the CALL_GRAPH and HAVE_DOT options are set to YES then
+# doxygen will generate a call dependency graph for every global function
+# or class method. Note that enabling this option will significantly increase
+# the time of a run. So in most cases it will be better to enable call graphs
+# for selected functions only using the \callgraph command.
+
+CALL_GRAPH = NO
+
+# If the CALLER_GRAPH and HAVE_DOT tags are set to YES then
+# doxygen will generate a caller dependency graph for every global function
+# or class method. Note that enabling this option will significantly increase
+# the time of a run. So in most cases it will be better to enable caller
+# graphs for selected functions only using the \callergraph command.
+
+CALLER_GRAPH = NO
+
+# If the GRAPHICAL_HIERARCHY and HAVE_DOT tags are set to YES then doxygen
+# will graphical hierarchy of all classes instead of a textual one.
+
+GRAPHICAL_HIERARCHY = NO
+
+# If the DIRECTORY_GRAPH, SHOW_DIRECTORIES and HAVE_DOT tags are set to YES
+# then doxygen will show the dependencies a directory has on other directories
+# in a graphical way. The dependency relations are determined by the #include
+# relations between the files in the directories.
+
+DIRECTORY_GRAPH = NO
+
+# The DOT_IMAGE_FORMAT tag can be used to set the image format of the images
+# generated by dot. Possible values are png, jpg, or gif
+# If left blank png will be used.
+
+DOT_IMAGE_FORMAT = png
+
+# The tag DOT_PATH can be used to specify the path where the dot tool can be
+# found. If left blank, it is assumed the dot tool can be found in the path.
+
+DOT_PATH =
+
+# The DOTFILE_DIRS tag can be used to specify one or more directories that
+# contain dot files that are included in the documentation (see the
+# \dotfile command).
+
+DOTFILE_DIRS =
+
+# The DOT_GRAPH_MAX_NODES tag can be used to set the maximum number of
+# nodes that will be shown in the graph. If the number of nodes in a graph
+# becomes larger than this value, doxygen will truncate the graph, which is
+# visualized by representing a node as a red box. Note that doxygen if the
+# number of direct children of the root node in a graph is already larger than
+# DOT_GRAPH_MAX_NODES then the graph will not be shown at all. Also note
+# that the size of a graph can be further restricted by MAX_DOT_GRAPH_DEPTH.
+
+DOT_GRAPH_MAX_NODES = 50
+
+# The MAX_DOT_GRAPH_DEPTH tag can be used to set the maximum depth of the
+# graphs generated by dot. A depth value of 3 means that only nodes reachable
+# from the root by following a path via at most 3 edges will be shown. Nodes
+# that lay further from the root node will be omitted. Note that setting this
+# option to 1 or 2 may greatly reduce the computation time needed for large
+# code bases. Also note that the size of a graph can be further restricted by
+# DOT_GRAPH_MAX_NODES. Using a depth of 0 means no depth restriction.
+
+MAX_DOT_GRAPH_DEPTH = 0
+
+# Set the DOT_TRANSPARENT tag to YES to generate images with a transparent
+# background. This is enabled by default, which results in a transparent
+# background. Warning: Depending on the platform used, enabling this option
+# may lead to badly anti-aliased labels on the edges of a graph (i.e. they
+# become hard to read).
+
+DOT_TRANSPARENT = NO
+
+# Set the DOT_MULTI_TARGETS tag to YES allow dot to generate multiple output
+# files in one run (i.e. multiple -o and -T options on the command line). This
+# makes dot run faster, but since only newer versions of dot (>1.8.10)
+# support this, this feature is disabled by default.
+
+DOT_MULTI_TARGETS = NO
+
+# If the GENERATE_LEGEND tag is set to YES (the default) Doxygen will
+# generate a legend page explaining the meaning of the various boxes and
+# arrows in the dot generated graphs.
+
+GENERATE_LEGEND = YES
+
+# If the DOT_CLEANUP tag is set to YES (the default) Doxygen will
+# remove the intermediate dot files that are used to generate
+# the various graphs.
+
+DOT_CLEANUP = YES
+
+#---------------------------------------------------------------------------
+# Configuration::additions related to the search engine
+#---------------------------------------------------------------------------
+
+# The SEARCHENGINE tag specifies whether or not a search engine should be
+# used. If set to NO the values of all tags below this one will be ignored.
+
+SEARCHENGINE = NO
diff --git a/doc/Eigen_Silly_Professor_64x64.png b/doc/Eigen_Silly_Professor_64x64.png
new file mode 100644
index 000000000..079d45b1d
--- /dev/null
+++ b/doc/Eigen_Silly_Professor_64x64.png
Binary files differ
diff --git a/doc/I00_CustomizingEigen.dox b/doc/I00_CustomizingEigen.dox
new file mode 100644
index 000000000..aa4514d68
--- /dev/null
+++ b/doc/I00_CustomizingEigen.dox
@@ -0,0 +1,191 @@
+namespace Eigen {
+
+/** \page TopicCustomizingEigen Customizing/Extending Eigen
+
+Eigen can be extended in several ways, for instance, by defining global methods, \ref ExtendingMatrixBase "by adding custom methods to MatrixBase", adding support to \ref CustomScalarType "custom types" etc.
+
+\b Table \b of \b contents
+ - \ref ExtendingMatrixBase
+ - \ref InheritingFromMatrix
+ - \ref CustomScalarType
+
+\section ExtendingMatrixBase Extending MatrixBase (and other classes)
+
+In this section we will see how to add custom methods to MatrixBase. Since all expressions and matrix types inherit MatrixBase, adding a method to MatrixBase make it immediately available to all expressions ! A typical use case is, for instance, to make Eigen compatible with another API.
+
+You certainly know that in C++ it is not possible to add methods to an existing class. So how that's possible ? Here the trick is to include in the declaration of MatrixBase a file defined by the preprocessor token \c EIGEN_MATRIXBASE_PLUGIN:
+\code
+class MatrixBase {
+ // ...
+ #ifdef EIGEN_MATRIXBASE_PLUGIN
+ #include EIGEN_MATRIXBASE_PLUGIN
+ #endif
+};
+\endcode
+Therefore to extend MatrixBase with your own methods you just have to create a file with your method declaration and define EIGEN_MATRIXBASE_PLUGIN before you include any Eigen's header file.
+
+You can extend many of the other classes used in Eigen by defining similarly named preprocessor symbols. For instance, define \c EIGEN_ARRAYBASE_PLUGIN if you want to extend the ArrayBase class. A full list of classes that can be extended in this way and the corresponding preprocessor symbols can be found on our page \ref TopicPreprocessorDirectives.
+
+Here is an example of an extension file for adding methods to MatrixBase: \n
+\b MatrixBaseAddons.h
+\code
+inline Scalar at(uint i, uint j) const { return this->operator()(i,j); }
+inline Scalar& at(uint i, uint j) { return this->operator()(i,j); }
+inline Scalar at(uint i) const { return this->operator[](i); }
+inline Scalar& at(uint i) { return this->operator[](i); }
+
+inline RealScalar squaredLength() const { return squaredNorm(); }
+inline RealScalar length() const { return norm(); }
+inline RealScalar invLength(void) const { return fast_inv_sqrt(squaredNorm()); }
+
+template<typename OtherDerived>
+inline Scalar squaredDistanceTo(const MatrixBase<OtherDerived>& other) const
+{ return (derived() - other.derived()).squaredNorm(); }
+
+template<typename OtherDerived>
+inline RealScalar distanceTo(const MatrixBase<OtherDerived>& other) const
+{ return internal::sqrt(derived().squaredDistanceTo(other)); }
+
+inline void scaleTo(RealScalar l) { RealScalar vl = norm(); if (vl>1e-9) derived() *= (l/vl); }
+
+inline Transpose<Derived> transposed() {return this->transpose();}
+inline const Transpose<Derived> transposed() const {return this->transpose();}
+
+inline uint minComponentId(void) const { int i; this->minCoeff(&i); return i; }
+inline uint maxComponentId(void) const { int i; this->maxCoeff(&i); return i; }
+
+template<typename OtherDerived>
+void makeFloor(const MatrixBase<OtherDerived>& other) { derived() = derived().cwiseMin(other.derived()); }
+template<typename OtherDerived>
+void makeCeil(const MatrixBase<OtherDerived>& other) { derived() = derived().cwiseMax(other.derived()); }
+
+const CwiseUnaryOp<internal::scalar_add_op<Scalar>, Derived>
+operator+(const Scalar& scalar) const
+{ return CwiseUnaryOp<internal::scalar_add_op<Scalar>, Derived>(derived(), internal::scalar_add_op<Scalar>(scalar)); }
+
+friend const CwiseUnaryOp<internal::scalar_add_op<Scalar>, Derived>
+operator+(const Scalar& scalar, const MatrixBase<Derived>& mat)
+{ return CwiseUnaryOp<internal::scalar_add_op<Scalar>, Derived>(mat.derived(), internal::scalar_add_op<Scalar>(scalar)); }
+\endcode
+
+Then one can the following declaration in the config.h or whatever prerequisites header file of his project:
+\code
+#define EIGEN_MATRIXBASE_PLUGIN "MatrixBaseAddons.h"
+\endcode
+
+\section InheritingFromMatrix Inheriting from Matrix
+
+Before inheriting from Matrix, be really, i mean REALLY sure that using
+EIGEN_MATRIX_PLUGIN is not what you really want (see previous section).
+If you just need to add few members to Matrix, this is the way to go.
+
+An example of when you actually need to inherit Matrix, is when you have
+several layers of heritage such as MyVerySpecificVector1,MyVerySpecificVector1 -> MyVector1 -> Matrix and.
+MyVerySpecificVector3,MyVerySpecificVector4 -> MyVector2 -> Matrix.
+
+In order for your object to work within the %Eigen framework, you need to
+define a few members in your inherited class.
+
+Here is a minimalistic example:\n
+\code
+class MyVectorType : public Eigen::VectorXd
+{
+public:
+ MyVectorType(void):Eigen::VectorXd() {}
+
+ typedef Eigen::VectorXd Base;
+
+ // This constructor allows you to construct MyVectorType from Eigen expressions
+ template<typename OtherDerived>
+ MyVectorType(const Eigen::MatrixBase<OtherDerived>& other)
+ : Eigen::Vector3d(other)
+ { }
+
+ // This method allows you to assign Eigen expressions to MyVectorType
+ template<typename OtherDerived>
+ MyVectorType & operator= (const Eigen::MatrixBase <OtherDerived>& other)
+ {
+ this->Base::operator=(other);
+ return *this;
+ }
+};
+\endcode
+
+This is the kind of error you can get if you don't provide those methods
+\code
+error: no match for ‘operator=’ in ‘delta =
+(((Eigen::MatrixBase<Eigen::Matrix<std::complex<float>, 10000, 1, 2, 10000,
+1> >*)(& delta)) + 8u)->Eigen::MatrixBase<Derived>::cwise [with Derived =
+Eigen::Matrix<std::complex<float>, 10000, 1, 2, 10000,
+1>]().Eigen::Cwise<ExpressionType>::operator* [with OtherDerived =
+Eigen::Matrix<std::complex<float>, 10000, 1, 2, 10000, 1>, ExpressionType =
+Eigen::Matrix<std::complex<float>, 10000, 1, 2, 10000, 1>](((const
+Eigen::MatrixBase<Eigen::Matrix<std::complex<float>, 10000, 1, 2, 10000, 1>
+>&)(((const Eigen::MatrixBase<Eigen::Matrix<std::complex<float>, 10000, 1,
+>2, 10000, 1> >*)((const spectral1d*)where)) + 8u)))’
+\endcode
+
+\anchor user_defined_scalars \section CustomScalarType Using custom scalar types
+
+By default, Eigen currently supports standard floating-point types (\c float, \c double, \c std::complex<float>, \c std::complex<double>, \c long \c double), as well as all integrale types (e.g., \c int, \c unsigned \c int, \c short, etc.), and \c bool.
+On x86-64 systems, \c long \c double permits to locally enforces the use of x87 registers with extended accuracy (in comparison to SSE).
+
+In order to add support for a custom type \c T you need:
+-# make sure the common operator (+,-,*,/,etc.) are supported by the type \c T
+-# add a specialization of struct Eigen::NumTraits<T> (see \ref NumTraits)
+-# define the math functions that makes sense for your type. This includes standard ones like sqrt, pow, sin, tan, conj, real, imag, etc, as well as abs2 which is Eigen specific.
+ (see the file Eigen/src/Core/MathFunctions.h)
+
+The math function should be defined in the same namespace than \c T, or in the \c std namespace though that second appraoch is not recommended.
+
+Here is a concrete example adding support for the Adolc's \c adouble type. <a href="https://projects.coin-or.org/ADOL-C">Adolc</a> is an automatic differentiation library. The type \c adouble is basically a real value tracking the values of any number of partial derivatives.
+
+\code
+#ifndef ADOLCSUPPORT_H
+#define ADOLCSUPPORT_H
+
+#define ADOLC_TAPELESS
+#include <adolc/adouble.h>
+#include <Eigen/Core>
+
+namespace Eigen {
+
+template<> struct NumTraits<adtl::adouble>
+ : NumTraits<double> // permits to get the epsilon, dummy_precision, lowest, highest functions
+{
+ typedef adtl::adouble Real;
+ typedef adtl::adouble NonInteger;
+ typedef adtl::adouble Nested;
+
+ enum {
+ IsComplex = 0,
+ IsInteger = 0,
+ IsSigned = 1,
+ RequireInitialization = 1,
+ ReadCost = 1,
+ AddCost = 3,
+ MulCost = 3
+ };
+};
+
+}
+
+namespace adtl {
+
+inline const adouble& conj(const adouble& x) { return x; }
+inline const adouble& real(const adouble& x) { return x; }
+inline adouble imag(const adouble&) { return 0.; }
+inline adouble abs(const adouble& x) { return fabs(x); }
+inline adouble abs2(const adouble& x) { return x*x; }
+
+}
+
+#endif // ADOLCSUPPORT_H
+\endcode
+
+
+\sa \ref TopicPreprocessorDirectives
+
+*/
+
+}
diff --git a/doc/I01_TopicLazyEvaluation.dox b/doc/I01_TopicLazyEvaluation.dox
new file mode 100644
index 000000000..393bc41d8
--- /dev/null
+++ b/doc/I01_TopicLazyEvaluation.dox
@@ -0,0 +1,65 @@
+namespace Eigen {
+
+/** \page TopicLazyEvaluation Lazy Evaluation and Aliasing
+
+Executive summary: Eigen has intelligent compile-time mechanisms to enable lazy evaluation and removing temporaries where appropriate.
+It will handle aliasing automatically in most cases, for example with matrix products. The automatic behavior can be overridden
+manually by using the MatrixBase::eval() and MatrixBase::noalias() methods.
+
+When you write a line of code involving a complex expression such as
+
+\code mat1 = mat2 + mat3 * (mat4 + mat5); \endcode
+
+Eigen determines automatically, for each sub-expression, whether to evaluate it into a temporary variable. Indeed, in certain cases it is better to evaluate immediately a sub-expression into a temporary variable, while in other cases it is better to avoid that.
+
+A traditional math library without expression templates always evaluates all sub-expressions into temporaries. So with this code,
+
+\code vec1 = vec2 + vec3; \endcode
+
+a traditional library would evaluate \c vec2 + vec3 into a temporary \c vec4 and then copy \c vec4 into \c vec1. This is of course inefficient: the arrays are traversed twice, so there are a lot of useless load/store operations.
+
+Expression-templates-based libraries can avoid evaluating sub-expressions into temporaries, which in many cases results in large speed improvements. This is called <i>lazy evaluation</i> as an expression is getting evaluated as late as possible, instead of immediately. However, most other expression-templates-based libraries <i>always</i> choose lazy evaluation. There are two problems with that: first, lazy evaluation is not always a good choice for performance; second, lazy evaluation can be very dangerous, for example with matrix products: doing <tt>matrix = matrix*matrix</tt> gives a wrong result if the matrix product is lazy-evaluated, because of the way matrix product works.
+
+For these reasons, Eigen has intelligent compile-time mechanisms to determine automatically when to use lazy evaluation, and when on the contrary it should evaluate immediately into a temporary variable.
+
+So in the basic example,
+
+\code matrix1 = matrix2 + matrix3; \endcode
+
+Eigen chooses lazy evaluation. Thus the arrays are traversed only once, producing optimized code. If you really want to force immediate evaluation, use \link MatrixBase::eval() eval()\endlink:
+
+\code matrix1 = (matrix2 + matrix3).eval(); \endcode
+
+Here is now a more involved example:
+
+\code matrix1 = -matrix2 + matrix3 + 5 * matrix4; \endcode
+
+Eigen chooses lazy evaluation at every stage in that example, which is clearly the correct choice. In fact, lazy evaluation is the "default choice" and Eigen will choose it except in a few circumstances.
+
+<b>The first circumstance</b> in which Eigen chooses immediate evaluation, is when it sees an assignment <tt>a = b;</tt> and the expression \c b has the evaluate-before-assigning \link flags flag\endlink. The most important example of such an expression is the \link GeneralProduct matrix product expression\endlink. For example, when you do
+
+\code matrix = matrix * matrix; \endcode
+
+Eigen first evaluates <tt>matrix * matrix</tt> into a temporary matrix, and then copies it into the original \c matrix. This guarantees a correct result as we saw above that lazy evaluation gives wrong results with matrix products. It also doesn't cost much, as the cost of the matrix product itself is much higher.
+
+What if you know that the result does no alias the operand of the product and want to force lazy evaluation? Then use \link MatrixBase::noalias() .noalias()\endlink instead. Here is an example:
+
+\code matrix1.noalias() = matrix2 * matrix2; \endcode
+
+Here, since we know that matrix2 is not the same matrix as matrix1, we know that lazy evaluation is not dangerous, so we may force lazy evaluation. Concretely, the effect of noalias() here is to bypass the evaluate-before-assigning \link flags flag\endlink.
+
+<b>The second circumstance</b> in which Eigen chooses immediate evaluation, is when it sees a nested expression such as <tt>a + b</tt> where \c b is already an expression having the evaluate-before-nesting \link flags flag\endlink. Again, the most important example of such an expression is the \link GeneralProduct matrix product expression\endlink. For example, when you do
+
+\code matrix1 = matrix2 + matrix3 * matrix4; \endcode
+
+the product <tt>matrix3 * matrix4</tt> gets evaluated immediately into a temporary matrix. Indeed, experiments showed that it is often beneficial for performance to evaluate immediately matrix products when they are nested into bigger expressions.
+
+<b>The third circumstance</b> in which Eigen chooses immediate evaluation, is when its cost model shows that the total cost of an operation is reduced if a sub-expression gets evaluated into a temporary. Indeed, in certain cases, an intermediate result is sufficiently costly to compute and is reused sufficiently many times, that is worth "caching". Here is an example:
+
+\code matrix1 = matrix2 * (matrix3 + matrix4); \endcode
+
+Here, provided the matrices have at least 2 rows and 2 columns, each coefficienct of the expression <tt>matrix3 + matrix4</tt> is going to be used several times in the matrix product. Instead of computing the sum everytime, it is much better to compute it once and store it in a temporary variable. Eigen understands this and evaluates <tt>matrix3 + matrix4</tt> into a temporary variable before evaluating the product.
+
+*/
+
+}
diff --git a/doc/I02_HiPerformance.dox b/doc/I02_HiPerformance.dox
new file mode 100644
index 000000000..ac1c2ca2b
--- /dev/null
+++ b/doc/I02_HiPerformance.dox
@@ -0,0 +1,128 @@
+
+namespace Eigen {
+
+/** \page TopicWritingEfficientProductExpression Writing efficient matrix product expressions
+
+In general achieving good performance with Eigen does no require any special effort:
+simply write your expressions in the most high level way. This is especially true
+for small fixed size matrices. For large matrices, however, it might be useful to
+take some care when writing your expressions in order to minimize useless evaluations
+and optimize the performance.
+In this page we will give a brief overview of the Eigen's internal mechanism to simplify
+and evaluate complex product expressions, and discuss the current limitations.
+In particular we will focus on expressions matching level 2 and 3 BLAS routines, i.e,
+all kind of matrix products and triangular solvers.
+
+Indeed, in Eigen we have implemented a set of highly optimized routines which are very similar
+to BLAS's ones. Unlike BLAS, those routines are made available to user via a high level and
+natural API. Each of these routines can compute in a single evaluation a wide variety of expressions.
+Given an expression, the challenge is then to map it to a minimal set of routines.
+As explained latter, this mechanism has some limitations, and knowing them will allow
+you to write faster code by making your expressions more Eigen friendly.
+
+\section GEMM General Matrix-Matrix product (GEMM)
+
+Let's start with the most common primitive: the matrix product of general dense matrices.
+In the BLAS world this corresponds to the GEMM routine. Our equivalent primitive can
+perform the following operation:
+\f$ C.noalias() += \alpha op1(A) op2(B) \f$
+where A, B, and C are column and/or row major matrices (or sub-matrices),
+alpha is a scalar value, and op1, op2 can be transpose, adjoint, conjugate, or the identity.
+When Eigen detects a matrix product, it analyzes both sides of the product to extract a
+unique scalar factor alpha, and for each side, its effective storage order, shape, and conjugation states.
+More precisely each side is simplified by iteratively removing trivial expressions such as scalar multiple,
+negation and conjugation. Transpose and Block expressions are not evaluated and they only modify the storage order
+and shape. All other expressions are immediately evaluated.
+For instance, the following expression:
+\code m1.noalias() -= s4 * (s1 * m2.adjoint() * (-(s3*m3).conjugate()*s2)) \endcode
+is automatically simplified to:
+\code m1.noalias() += (s1*s2*conj(s3)*s4) * m2.adjoint() * m3.conjugate() \endcode
+which exactly matches our GEMM routine.
+
+\subsection GEMM_Limitations Limitations
+Unfortunately, this simplification mechanism is not perfect yet and not all expressions which could be
+handled by a single GEMM-like call are correctly detected.
+<table class="manual" style="width:100%">
+<tr>
+<th>Not optimal expression</th>
+<th>Evaluated as</th>
+<th>Optimal version (single evaluation)</th>
+<th>Comments</th>
+</tr>
+<tr>
+<td>\code
+m1 += m2 * m3; \endcode</td>
+<td>\code
+temp = m2 * m3;
+m1 += temp; \endcode</td>
+<td>\code
+m1.noalias() += m2 * m3; \endcode</td>
+<td>Use .noalias() to tell Eigen the result and right-hand-sides do not alias.
+ Otherwise the product m2 * m3 is evaluated into a temporary.</td>
+</tr>
+<tr class="alt">
+<td></td>
+<td></td>
+<td>\code
+m1.noalias() += s1 * (m2 * m3); \endcode</td>
+<td>This is a special feature of Eigen. Here the product between a scalar
+ and a matrix product does not evaluate the matrix product but instead it
+ returns a matrix product expression tracking the scalar scaling factor. <br>
+ Without this optimization, the matrix product would be evaluated into a
+ temporary as in the next example.</td>
+</tr>
+<tr>
+<td>\code
+m1.noalias() += (m2 * m3).adjoint(); \endcode</td>
+<td>\code
+temp = m2 * m3;
+m1 += temp.adjoint(); \endcode</td>
+<td>\code
+m1.noalias() += m3.adjoint()
+ * m2.adjoint(); \endcode</td>
+<td>This is because the product expression has the EvalBeforeNesting bit which
+ enforces the evaluation of the product by the Tranpose expression.</td>
+</tr>
+<tr class="alt">
+<td>\code
+m1 = m1 + m2 * m3; \endcode</td>
+<td>\code
+temp = m2 * m3;
+m1 = m1 + temp; \endcode</td>
+<td>\code m1.noalias() += m2 * m3; \endcode</td>
+<td>Here there is no way to detect at compile time that the two m1 are the same,
+ and so the matrix product will be immediately evaluated.</td>
+</tr>
+<tr>
+<td>\code
+m1.noalias() = m4 + m2 * m3; \endcode</td>
+<td>\code
+temp = m2 * m3;
+m1 = m4 + temp; \endcode</td>
+<td>\code
+m1 = m4;
+m1.noalias() += m2 * m3; \endcode</td>
+<td>First of all, here the .noalias() in the first expression is useless because
+ m2*m3 will be evaluated anyway. However, note how this expression can be rewritten
+ so that no temporary is required. (tip: for very small fixed size matrix
+ it is slighlty better to rewrite it like this: m1.noalias() = m2 * m3; m1 += m4;</td>
+</tr>
+<tr class="alt">
+<td>\code
+m1.noalias() += (s1*m2).block(..) * m3; \endcode</td>
+<td>\code
+temp = (s1*m2).block(..);
+m1 += temp * m3; \endcode</td>
+<td>\code
+m1.noalias() += s1 * m2.block(..) * m3; \endcode</td>
+<td>This is because our expression analyzer is currently not able to extract trivial
+ expressions nested in a Block expression. Therefore the nested scalar
+ multiple cannot be properly extracted.</td>
+</tr>
+</table>
+
+Of course all these remarks hold for all other kind of products involving triangular or selfadjoint matrices.
+
+*/
+
+}
diff --git a/doc/I03_InsideEigenExample.dox b/doc/I03_InsideEigenExample.dox
new file mode 100644
index 000000000..3245a01c0
--- /dev/null
+++ b/doc/I03_InsideEigenExample.dox
@@ -0,0 +1,500 @@
+namespace Eigen {
+
+/** \page TopicInsideEigenExample What happens inside Eigen, on a simple example
+
+\b Table \b of \b contents
+ - \ref WhyInteresting
+ - \ref ConstructingVectors
+ - \ref ConstructionOfSumXpr
+ - \ref Assignment
+\n
+
+<hr>
+
+
+Consider the following example program:
+
+\code
+#include<Eigen/Core>
+
+int main()
+{
+ int size = 50;
+ // VectorXf is a vector of floats, with dynamic size.
+ Eigen::VectorXf u(size), v(size), w(size);
+ u = v + w;
+}
+\endcode
+
+The goal of this page is to understand how Eigen compiles it, assuming that SSE2 vectorization is enabled (GCC option -msse2).
+
+\section WhyInteresting Why it's interesting
+
+Maybe you think, that the above example program is so simple, that compiling it shouldn't involve anything interesting. So before starting, let us explain what is nontrivial in compiling it correctly -- that is, producing optimized code -- so that the complexity of Eigen, that we'll explain here, is really useful.
+
+Look at the line of code
+\code
+ u = v + w; // (*)
+\endcode
+
+The first important thing about compiling it, is that the arrays should be traversed only once, like
+\code
+ for(int i = 0; i < size; i++) u[i] = v[i] + w[i];
+\endcode
+The problem is that if we make a naive C++ library where the VectorXf class has an operator+ returning a VectorXf, then the line of code (*) will amount to:
+\code
+ VectorXf tmp = v + w;
+ VectorXf u = tmp;
+\endcode
+Obviously, the introduction of the temporary \a tmp here is useless. It has a very bad effect on performance, first because the creation of \a tmp requires a dynamic memory allocation in this context, and second as there are now two for loops:
+\code
+ for(int i = 0; i < size; i++) tmp[i] = v[i] + w[i];
+ for(int i = 0; i < size; i++) u[i] = tmp[i];
+\endcode
+Traversing the arrays twice instead of once is terrible for performance, as it means that we do many redundant memory accesses.
+
+The second important thing about compiling the above program, is to make correct use of SSE2 instructions. Notice that Eigen also supports AltiVec and that all the discussion that we make here applies also to AltiVec.
+
+SSE2, like AltiVec, is a set of instructions allowing to perform computations on packets of 128 bits at once. Since a float is 32 bits, this means that SSE2 instructions can handle 4 floats at once. This means that, if correctly used, they can make our computation go up to 4x faster.
+
+However, in the above program, we have chosen size=50, so our vectors consist of 50 float's, and 50 is not a multiple of 4. This means that we cannot hope to do all of that computation using SSE2 instructions. The second best thing, to which we should aim, is to handle the 48 first coefficients with SSE2 instructions, since 48 is the biggest multiple of 4 below 50, and then handle separately, without SSE2, the 49th and 50th coefficients. Something like this:
+
+\code
+ for(int i = 0; i < 4*(size/4); i+=4) u.packet(i) = v.packet(i) + w.packet(i);
+ for(int i = 4*(size/4); i < size; i++) u[i] = v[i] + w[i];
+\endcode
+
+So let us look line by line at our example program, and let's follow Eigen as it compiles it.
+
+\section ConstructingVectors Constructing vectors
+
+Let's analyze the first line:
+
+\code
+ Eigen::VectorXf u(size), v(size), w(size);
+\endcode
+
+First of all, VectorXf is the following typedef:
+\code
+ typedef Matrix<float, Dynamic, 1> VectorXf;
+\endcode
+
+The class template Matrix is declared in src/Core/util/ForwardDeclarations.h with 6 template parameters, but the last 3 are automatically determined by the first 3. So you don't need to worry about them for now. Here, Matrix\<float, Dynamic, 1\> means a matrix of floats, with a dynamic number of rows and 1 column.
+
+The Matrix class inherits a base class, MatrixBase. Don't worry about it, for now it suffices to say that MatrixBase is what unifies matrices/vectors and all the expressions types -- more on that below.
+
+When we do
+\code
+ Eigen::VectorXf u(size);
+\endcode
+the constructor that is called is Matrix::Matrix(int), in src/Core/Matrix.h. Besides some assertions, all it does is to construct the \a m_storage member, which is of type DenseStorage\<float, Dynamic, Dynamic, 1\>.
+
+You may wonder, isn't it overengineering to have the storage in a separate class? The reason is that the Matrix class template covers all kinds of matrices and vector: both fixed-size and dynamic-size. The storage method is not the same in these two cases. For fixed-size, the matrix coefficients are stored as a plain member array. For dynamic-size, the coefficients will be stored as a pointer to a dynamically-allocated array. Because of this, we need to abstract storage away from the Matrix class. That's DenseStorage.
+
+Let's look at this constructor, in src/Core/DenseStorage.h. You can see that there are many partial template specializations of DenseStorages here, treating separately the cases where dimensions are Dynamic or fixed at compile-time. The partial specialization that we are looking at is:
+\code
+template<typename T, int _Cols> class DenseStorage<T, Dynamic, Dynamic, _Cols>
+\endcode
+
+Here, the constructor called is DenseStorage::DenseStorage(int size, int rows, int columns)
+with size=50, rows=50, columns=1.
+
+Here is this constructor:
+\code
+inline DenseStorage(int size, int rows, int) : m_data(internal::aligned_new<T>(size)), m_rows(rows) {}
+\endcode
+
+Here, the \a m_data member is the actual array of coefficients of the matrix. As you see, it is dynamically allocated. Rather than calling new[] or malloc(), as you can see, we have our own internal::aligned_new defined in src/Core/util/Memory.h. What it does is that if vectorization is enabled, then it uses a platform-specific call to allocate a 128-bit-aligned array, as that is very useful for vectorization with both SSE2 and AltiVec. If vectorization is disabled, it amounts to the standard new[].
+
+As you can see, the constructor also sets the \a m_rows member to \a size. Notice that there is no \a m_columns member: indeed, in this partial specialization of DenseStorage, we know the number of columns at compile-time, since the _Cols template parameter is different from Dynamic. Namely, in our case, _Cols is 1, which is to say that our vector is just a matrix with 1 column. Hence, there is no need to store the number of columns as a runtime variable.
+
+When you call VectorXf::data() to get the pointer to the array of coefficients, it returns DenseStorage::data() which returns the \a m_data member.
+
+When you call VectorXf::size() to get the size of the vector, this is actually a method in the base class MatrixBase. It determines that the vector is a column-vector, since ColsAtCompileTime==1 (this comes from the template parameters in the typedef VectorXf). It deduces that the size is the number of rows, so it returns VectorXf::rows(), which returns DenseStorage::rows(), which returns the \a m_rows member, which was set to \a size by the constructor.
+
+\section ConstructionOfSumXpr Construction of the sum expression
+
+Now that our vectors are constructed, let's move on to the next line:
+
+\code
+u = v + w;
+\endcode
+
+The executive summary is that operator+ returns a "sum of vectors" expression, but doesn't actually perform the computation. It is the operator=, whose call occurs thereafter, that does the computation.
+
+Let us now see what Eigen does when it sees this:
+
+\code
+v + w
+\endcode
+
+Here, v and w are of type VectorXf, which is a typedef for a specialization of Matrix (as we explained above), which is a subclass of MatrixBase. So what is being called is
+
+\code
+MatrixBase::operator+(const MatrixBase&)
+\endcode
+
+The return type of this operator is
+\code
+CwiseBinaryOp<internal::scalar_sum_op<float>, VectorXf, VectorXf>
+\endcode
+The CwiseBinaryOp class is our first encounter with an expression template. As we said, the operator+ doesn't by itself perform any computation, it just returns an abstract "sum of vectors" expression. Since there are also "difference of vectors" and "coefficient-wise product of vectors" expressions, we unify them all as "coefficient-wise binary operations", which we abbreviate as "CwiseBinaryOp". "Coefficient-wise" means that the operations is performed coefficient by coefficient. "binary" means that there are two operands -- we are adding two vectors with one another.
+
+Now you might ask, what if we did something like
+
+\code
+v + w + u;
+\endcode
+
+The first v + w would return a CwiseBinaryOp as above, so in order for this to compile, we'd need to define an operator+ also in the class CwiseBinaryOp... at this point it starts looking like a nightmare: are we going to have to define all operators in each of the expression classes (as you guessed, CwiseBinaryOp is only one of many) ? This looks like a dead end!
+
+The solution is that CwiseBinaryOp itself, as well as Matrix and all the other expression types, is a subclass of MatrixBase. So it is enough to define once and for all the operators in class MatrixBase.
+
+Since MatrixBase is the common base class of different subclasses, the aspects that depend on the subclass must be abstracted from MatrixBase. This is called polymorphism.
+
+The classical approach to polymorphism in C++ is by means of virtual functions. This is dynamic polymorphism. Here we don't want dynamic polymorphism because the whole design of Eigen is based around the assumption that all the complexity, all the abstraction, gets resolved at compile-time. This is crucial: if the abstraction can't get resolved at compile-time, Eigen's compile-time optimization mechanisms become useless, not to mention that if that abstraction has to be resolved at runtime it'll incur an overhead by itself.
+
+Here, what we want is to have a single class MatrixBase as the base of many subclasses, in such a way that each MatrixBase object (be it a matrix, or vector, or any kind of expression) knows at compile-time (as opposed to run-time) of which particular subclass it is an object (i.e. whether it is a matrix, or an expression, and what kind of expression).
+
+The solution is the <a href="http://en.wikipedia.org/wiki/Curiously_Recurring_Template_Pattern">Curiously Recurring Template Pattern</a>. Let's do the break now. Hopefully you can read this wikipedia page during the break if needed, but it won't be allowed during the exam.
+
+In short, MatrixBase takes a template parameter \a Derived. Whenever we define a subclass Subclass, we actually make Subclass inherit MatrixBase\<Subclass\>. The point is that different subclasses inherit different MatrixBase types. Thanks to this, whenever we have an object of a subclass, and we call on it some MatrixBase method, we still remember even from inside the MatrixBase method which particular subclass we're talking about.
+
+This means that we can put almost all the methods and operators in the base class MatrixBase, and have only the bare minimum in the subclasses. If you look at the subclasses in Eigen, like for instance the CwiseBinaryOp class, they have very few methods. There are coeff() and sometimes coeffRef() methods for access to the coefficients, there are rows() and cols() methods returning the number of rows and columns, but there isn't much more than that. All the meat is in MatrixBase, so it only needs to be coded once for all kinds of expressions, matrices, and vectors.
+
+So let's end this digression and come back to the piece of code from our example program that we were currently analyzing,
+
+\code
+v + w
+\endcode
+
+Now that MatrixBase is a good friend, let's write fully the prototype of the operator+ that gets called here (this code is from src/Core/MatrixBase.h):
+
+\code
+template<typename Derived>
+class MatrixBase
+{
+ // ...
+
+ template<typename OtherDerived>
+ const CwiseBinaryOp<internal::scalar_sum_op<typename internal::traits<Derived>::Scalar>, Derived, OtherDerived>
+ operator+(const MatrixBase<OtherDerived> &other) const;
+
+ // ...
+};
+\endcode
+
+Here of course, \a Derived and \a OtherDerived are VectorXf.
+
+As we said, CwiseBinaryOp is also used for other operations such as substration, so it takes another template parameter determining the operation that will be applied to coefficients. This template parameter is a functor, that is, a class in which we have an operator() so it behaves like a function. Here, the functor used is internal::scalar_sum_op. It is defined in src/Core/Functors.h.
+
+Let us now explain the internal::traits here. The internal::scalar_sum_op class takes one template parameter: the type of the numbers to handle. Here of course we want to pass the scalar type (a.k.a. numeric type) of VectorXf, which is \c float. How do we determine which is the scalar type of \a Derived ? Throughout Eigen, all matrix and expression types define a typedef \a Scalar which gives its scalar type. For example, VectorXf::Scalar is a typedef for \c float. So here, if life was easy, we could find the numeric type of \a Derived as just
+\code
+typename Derived::Scalar
+\endcode
+Unfortunately, we can't do that here, as the compiler would complain that the type Derived hasn't yet been defined. So we use a workaround: in src/Core/util/ForwardDeclarations.h, we declared (not defined!) all our subclasses, like Matrix, and we also declared the following class template:
+\code
+template<typename T> struct internal::traits;
+\endcode
+In src/Core/Matrix.h, right \em before the definition of class Matrix, we define a partial specialization of internal::traits for T=Matrix\<any template parameters\>. In this specialization of internal::traits, we define the Scalar typedef. So when we actually define Matrix, it is legal to refer to "typename internal::traits\<Matrix\>::Scalar".
+
+Anyway, we have declared our operator+. In our case, where \a Derived and \a OtherDerived are VectorXf, the above declaration amounts to:
+\code
+class MatrixBase<VectorXf>
+{
+ // ...
+
+ const CwiseBinaryOp<internal::scalar_sum_op<float>, VectorXf, VectorXf>
+ operator+(const MatrixBase<VectorXf> &other) const;
+
+ // ...
+};
+\endcode
+
+Let's now jump to src/Core/CwiseBinaryOp.h to see how it is defined. As you can see there, all it does is to return a CwiseBinaryOp object, and this object is just storing references to the left-hand-side and right-hand-side expressions -- here, these are the vectors \a v and \a w. Well, the CwiseBinaryOp object is also storing an instance of the (empty) functor class, but you shouldn't worry about it as that is a minor implementation detail.
+
+Thus, the operator+ hasn't performed any actual computation. To summarize, the operation \a v + \a w just returned an object of type CwiseBinaryOp which did nothing else than just storing references to \a v and \a w.
+
+\section Assignment The assignment
+
+At this point, the expression \a v + \a w has finished evaluating, so, in the process of compiling the line of code
+\code
+u = v + w;
+\endcode
+we now enter the operator=.
+
+What operator= is being called here? The vector u is an object of class VectorXf, i.e. Matrix. In src/Core/Matrix.h, inside the definition of class Matrix, we see this:
+\code
+ template<typename OtherDerived>
+ inline Matrix& operator=(const MatrixBase<OtherDerived>& other)
+ {
+ eigen_assert(m_storage.data()!=0 && "you cannot use operator= with a non initialized matrix (instead use set()");
+ return Base::operator=(other.derived());
+ }
+\endcode
+Here, Base is a typedef for MatrixBase\<Matrix\>. So, what is being called is the operator= of MatrixBase. Let's see its prototype in src/Core/MatrixBase.h:
+\code
+ template<typename OtherDerived>
+ Derived& operator=(const MatrixBase<OtherDerived>& other);
+\endcode
+Here, \a Derived is VectorXf (since u is a VectorXf) and \a OtherDerived is CwiseBinaryOp. More specifically, as explained in the previous section, \a OtherDerived is:
+\code
+CwiseBinaryOp<internal::scalar_sum_op<float>, VectorXf, VectorXf>
+\endcode
+So the full prototype of the operator= being called is:
+\code
+VectorXf& MatrixBase<VectorXf>::operator=(const MatrixBase<CwiseBinaryOp<internal::scalar_sum_op<float>, VectorXf, VectorXf> > & other);
+\endcode
+This operator= literally reads "copying a sum of two VectorXf's into another VectorXf".
+
+Let's now look at the implementation of this operator=. It resides in the file src/Core/Assign.h.
+
+What we can see there is:
+\code
+template<typename Derived>
+template<typename OtherDerived>
+inline Derived& MatrixBase<Derived>
+ ::operator=(const MatrixBase<OtherDerived>& other)
+{
+ return internal::assign_selector<Derived,OtherDerived>::run(derived(), other.derived());
+}
+\endcode
+
+OK so our next task is to understand internal::assign_selector :)
+
+Here is its declaration (all that is still in the same file src/Core/Assign.h)
+\code
+template<typename Derived, typename OtherDerived,
+ bool EvalBeforeAssigning = int(OtherDerived::Flags) & EvalBeforeAssigningBit,
+ bool NeedToTranspose = Derived::IsVectorAtCompileTime
+ && OtherDerived::IsVectorAtCompileTime
+ && int(Derived::RowsAtCompileTime) == int(OtherDerived::ColsAtCompileTime)
+ && int(Derived::ColsAtCompileTime) == int(OtherDerived::RowsAtCompileTime)
+ && int(Derived::SizeAtCompileTime) != 1>
+struct internal::assign_selector;
+\endcode
+
+So internal::assign_selector takes 4 template parameters, but the 2 last ones are automatically determined by the 2 first ones.
+
+EvalBeforeAssigning is here to enforce the EvalBeforeAssigningBit. As explained <a href="TopicLazyEvaluation.html">here</a>, certain expressions have this flag which makes them automatically evaluate into temporaries before assigning them to another expression. This is the case of the Product expression, in order to avoid strange aliasing effects when doing "m = m * m;" However, of course here our CwiseBinaryOp expression doesn't have the EvalBeforeAssigningBit: we said since the beginning that we didn't want a temporary to be introduced here. So if you go to src/Core/CwiseBinaryOp.h, you'll see that the Flags in internal::traits\<CwiseBinaryOp\> don't include the EvalBeforeAssigningBit. The Flags member of CwiseBinaryOp is then imported from the internal::traits by the EIGEN_GENERIC_PUBLIC_INTERFACE macro. Anyway, here the template parameter EvalBeforeAssigning has the value \c false.
+
+NeedToTranspose is here for the case where the user wants to copy a row-vector into a column-vector. We allow this as a special exception to the general rule that in assignments we require the dimesions to match. Anyway, here both the left-hand and right-hand sides are column vectors, in the sense that ColsAtCompileTime is equal to 1. So NeedToTranspose is \c false too.
+
+So, here we are in the partial specialization:
+\code
+internal::assign_selector<Derived, OtherDerived, false, false>
+\endcode
+
+Here's how it is defined:
+\code
+template<typename Derived, typename OtherDerived>
+struct internal::assign_selector<Derived,OtherDerived,false,false> {
+ static Derived& run(Derived& dst, const OtherDerived& other) { return dst.lazyAssign(other.derived()); }
+};
+\endcode
+
+OK so now our next job is to understand how lazyAssign works :)
+
+\code
+template<typename Derived>
+template<typename OtherDerived>
+inline Derived& MatrixBase<Derived>
+ ::lazyAssign(const MatrixBase<OtherDerived>& other)
+{
+ EIGEN_STATIC_ASSERT_SAME_MATRIX_SIZE(Derived,OtherDerived)
+ eigen_assert(rows() == other.rows() && cols() == other.cols());
+ internal::assign_impl<Derived, OtherDerived>::run(derived(),other.derived());
+ return derived();
+}
+\endcode
+
+What do we see here? Some assertions, and then the only interesting line is:
+\code
+ internal::assign_impl<Derived, OtherDerived>::run(derived(),other.derived());
+\endcode
+
+OK so now we want to know what is inside internal::assign_impl.
+
+Here is its declaration:
+\code
+template<typename Derived1, typename Derived2,
+ int Vectorization = internal::assign_traits<Derived1, Derived2>::Vectorization,
+ int Unrolling = internal::assign_traits<Derived1, Derived2>::Unrolling>
+struct internal::assign_impl;
+\endcode
+Again, internal::assign_selector takes 4 template parameters, but the 2 last ones are automatically determined by the 2 first ones.
+
+These two parameters \a Vectorization and \a Unrolling are determined by a helper class internal::assign_traits. Its job is to determine which vectorization strategy to use (that is \a Vectorization) and which unrolling strategy to use (that is \a Unrolling).
+
+We'll not enter into the details of how these strategies are chosen (this is in the implementation of internal::assign_traits at the top of the same file). Let's just say that here \a Vectorization has the value \a LinearVectorization, and \a Unrolling has the value \a NoUnrolling (the latter is obvious since our vectors have dynamic size so there's no way to unroll the loop at compile-time).
+
+So the partial specialization of internal::assign_impl that we're looking at is:
+\code
+internal::assign_impl<Derived1, Derived2, LinearVectorization, NoUnrolling>
+\endcode
+
+Here is how it's defined:
+\code
+template<typename Derived1, typename Derived2>
+struct internal::assign_impl<Derived1, Derived2, LinearVectorization, NoUnrolling>
+{
+ static void run(Derived1 &dst, const Derived2 &src)
+ {
+ const int size = dst.size();
+ const int packetSize = internal::packet_traits<typename Derived1::Scalar>::size;
+ const int alignedStart = internal::assign_traits<Derived1,Derived2>::DstIsAligned ? 0
+ : internal::first_aligned(&dst.coeffRef(0), size);
+ const int alignedEnd = alignedStart + ((size-alignedStart)/packetSize)*packetSize;
+
+ for(int index = 0; index < alignedStart; index++)
+ dst.copyCoeff(index, src);
+
+ for(int index = alignedStart; index < alignedEnd; index += packetSize)
+ {
+ dst.template copyPacket<Derived2, Aligned, internal::assign_traits<Derived1,Derived2>::SrcAlignment>(index, src);
+ }
+
+ for(int index = alignedEnd; index < size; index++)
+ dst.copyCoeff(index, src);
+ }
+};
+\endcode
+
+Here's how it works. \a LinearVectorization means that the left-hand and right-hand side expression can be accessed linearly i.e. you can refer to their coefficients by one integer \a index, as opposed to having to refer to its coefficients by two integers \a row, \a column.
+
+As we said at the beginning, vectorization works with blocks of 4 floats. Here, \a PacketSize is 4.
+
+There are two potential problems that we need to deal with:
+\li first, vectorization works much better if the packets are 128-bit-aligned. This is especially important for write access. So when writing to the coefficients of \a dst, we want to group these coefficients by packets of 4 such that each of these packets is 128-bit-aligned. In general, this requires to skip a few coefficients at the beginning of \a dst. This is the purpose of \a alignedStart. We then copy these first few coefficients one by one, not by packets. However, in our case, the \a dst expression is a VectorXf and remember that in the construction of the vectors we allocated aligned arrays. Thanks to \a DstIsAligned, Eigen remembers that without having to do any runtime check, so \a alignedStart is zero and this part is avoided altogether.
+\li second, the number of coefficients to copy is not in general a multiple of \a packetSize. Here, there are 50 coefficients to copy and \a packetSize is 4. So we'll have to copy the last 2 coefficients one by one, not by packets. Here, \a alignedEnd is 48.
+
+Now come the actual loops.
+
+First, the vectorized part: the 48 first coefficients out of 50 will be copied by packets of 4:
+\code
+ for(int index = alignedStart; index < alignedEnd; index += packetSize)
+ {
+ dst.template copyPacket<Derived2, Aligned, internal::assign_traits<Derived1,Derived2>::SrcAlignment>(index, src);
+ }
+\endcode
+
+What is copyPacket? It is defined in src/Core/Coeffs.h:
+\code
+template<typename Derived>
+template<typename OtherDerived, int StoreMode, int LoadMode>
+inline void MatrixBase<Derived>::copyPacket(int index, const MatrixBase<OtherDerived>& other)
+{
+ eigen_internal_assert(index >= 0 && index < size());
+ derived().template writePacket<StoreMode>(index,
+ other.derived().template packet<LoadMode>(index));
+}
+\endcode
+
+OK, what are writePacket() and packet() here?
+
+First, writePacket() here is a method on the left-hand side VectorXf. So we go to src/Core/Matrix.h to look at its definition:
+\code
+template<int StoreMode>
+inline void writePacket(int index, const PacketScalar& x)
+{
+ internal::pstoret<Scalar, PacketScalar, StoreMode>(m_storage.data() + index, x);
+}
+\endcode
+Here, \a StoreMode is \a #Aligned, indicating that we are doing a 128-bit-aligned write access, \a PacketScalar is a type representing a "SSE packet of 4 floats" and internal::pstoret is a function writing such a packet in memory. Their definitions are architecture-specific, we find them in src/Core/arch/SSE/PacketMath.h:
+
+The line in src/Core/arch/SSE/PacketMath.h that determines the PacketScalar type (via a typedef in Matrix.h) is:
+\code
+template<> struct internal::packet_traits<float> { typedef __m128 type; enum {size=4}; };
+\endcode
+Here, __m128 is a SSE-specific type. Notice that the enum \a size here is what was used to define \a packetSize above.
+
+And here is the implementation of internal::pstoret:
+\code
+template<> inline void internal::pstore(float* to, const __m128& from) { _mm_store_ps(to, from); }
+\endcode
+Here, __mm_store_ps is a SSE-specific intrinsic function, representing a single SSE instruction. The difference between internal::pstore and internal::pstoret is that internal::pstoret is a dispatcher handling both the aligned and unaligned cases, you find its definition in src/Core/GenericPacketMath.h:
+\code
+template<typename Scalar, typename Packet, int LoadMode>
+inline void internal::pstoret(Scalar* to, const Packet& from)
+{
+ if(LoadMode == Aligned)
+ internal::pstore(to, from);
+ else
+ internal::pstoreu(to, from);
+}
+\endcode
+
+OK, that explains how writePacket() works. Now let's look into the packet() call. Remember that we are analyzing this line of code inside copyPacket():
+\code
+derived().template writePacket<StoreMode>(index,
+ other.derived().template packet<LoadMode>(index));
+\endcode
+
+Here, \a other is our sum expression \a v + \a w. The .derived() is just casting from MatrixBase to the subclass which here is CwiseBinaryOp. So let's go to src/Core/CwiseBinaryOp.h:
+\code
+class CwiseBinaryOp
+{
+ // ...
+ template<int LoadMode>
+ inline PacketScalar packet(int index) const
+ {
+ return m_functor.packetOp(m_lhs.template packet<LoadMode>(index), m_rhs.template packet<LoadMode>(index));
+ }
+};
+\endcode
+Here, \a m_lhs is the vector \a v, and \a m_rhs is the vector \a w. So the packet() function here is Matrix::packet(). The template parameter \a LoadMode is \a #Aligned. So we're looking at
+\code
+class Matrix
+{
+ // ...
+ template<int LoadMode>
+ inline PacketScalar packet(int index) const
+ {
+ return internal::ploadt<Scalar, LoadMode>(m_storage.data() + index);
+ }
+};
+\endcode
+We let you look up the definition of internal::ploadt in GenericPacketMath.h and the internal::pload in src/Core/arch/SSE/PacketMath.h. It is very similar to the above for internal::pstore.
+
+Let's go back to CwiseBinaryOp::packet(). Once the packets from the vectors \a v and \a w have been returned, what does this function do? It calls m_functor.packetOp() on them. What is m_functor? Here we must remember what particular template specialization of CwiseBinaryOp we're dealing with:
+\code
+CwiseBinaryOp<internal::scalar_sum_op<float>, VectorXf, VectorXf>
+\endcode
+So m_functor is an object of the empty class internal::scalar_sum_op<float>. As we mentioned above, don't worry about why we constructed an object of this empty class at all -- it's an implementation detail, the point is that some other functors need to store member data.
+
+Anyway, internal::scalar_sum_op is defined in src/Core/Functors.h:
+\code
+template<typename Scalar> struct internal::scalar_sum_op EIGEN_EMPTY_STRUCT {
+ inline const Scalar operator() (const Scalar& a, const Scalar& b) const { return a + b; }
+ template<typename PacketScalar>
+ inline const PacketScalar packetOp(const PacketScalar& a, const PacketScalar& b) const
+ { return internal::padd(a,b); }
+};
+\endcode
+As you can see, all what packetOp() does is to call internal::padd on the two packets. Here is the definition of internal::padd from src/Core/arch/SSE/PacketMath.h:
+\code
+template<> inline __m128 internal::padd(const __m128& a, const __m128& b) { return _mm_add_ps(a,b); }
+\endcode
+Here, _mm_add_ps is a SSE-specific intrinsic function, representing a single SSE instruction.
+
+To summarize, the loop
+\code
+ for(int index = alignedStart; index < alignedEnd; index += packetSize)
+ {
+ dst.template copyPacket<Derived2, Aligned, internal::assign_traits<Derived1,Derived2>::SrcAlignment>(index, src);
+ }
+\endcode
+has been compiled to the following code: for \a index going from 0 to the 11 ( = 48/4 - 1), read the i-th packet (of 4 floats) from the vector v and the i-th packet from the vector w using two __mm_load_ps SSE instructions, then add them together using a __mm_add_ps instruction, then store the result using a __mm_store_ps instruction.
+
+There remains the second loop handling the last few (here, the last 2) coefficients:
+\code
+ for(int index = alignedEnd; index < size; index++)
+ dst.copyCoeff(index, src);
+\endcode
+However, it works just like the one we just explained, it is just simpler because there is no SSE vectorization involved here. copyPacket() becomes copyCoeff(), packet() becomes coeff(), writePacket() becomes coeffRef(). If you followed us this far, you can probably understand this part by yourself.
+
+We see that all the C++ abstraction of Eigen goes away during compilation and that we indeed are precisely controlling which assembly instructions we emit. Such is the beauty of C++! Since we have such precise control over the emitted assembly instructions, but such complex logic to choose the right instructions, we can say that Eigen really behaves like an optimizing compiler. If you prefer, you could say that Eigen behaves like a script for the compiler. In a sense, C++ template metaprogramming is scripting the compiler -- and it's been shown that this scripting language is Turing-complete. See <a href="http://en.wikipedia.org/wiki/Template_metaprogramming"> Wikipedia</a>.
+
+*/
+
+}
diff --git a/doc/I05_FixedSizeVectorizable.dox b/doc/I05_FixedSizeVectorizable.dox
new file mode 100644
index 000000000..192ea7406
--- /dev/null
+++ b/doc/I05_FixedSizeVectorizable.dox
@@ -0,0 +1,38 @@
+namespace Eigen {
+
+/** \page TopicFixedSizeVectorizable Fixed-size vectorizable Eigen objects
+
+The goal of this page is to explain what we mean by "fixed-size vectorizable".
+
+\section summary Executive Summary
+
+An Eigen object is called "fixed-size vectorizable" if it has fixed size and that size is a multiple of 16 bytes.
+
+Examples include:
+\li Eigen::Vector2d
+\li Eigen::Vector4d
+\li Eigen::Vector4f
+\li Eigen::Matrix2d
+\li Eigen::Matrix2f
+\li Eigen::Matrix4d
+\li Eigen::Matrix4f
+\li Eigen::Affine3d
+\li Eigen::Affine3f
+\li Eigen::Quaterniond
+\li Eigen::Quaternionf
+
+\section explanation Explanation
+
+First, "fixed-size" should be clear: an Eigen object has fixed size if its number of rows and its number of columns are fixed at compile-time. So for example Matrix3f has fixed size, but MatrixXf doesn't (the opposite of fixed-size is dynamic-size).
+
+The array of coefficients of a fixed-size Eigen object is a plain "static array", it is not dynamically allocated. For example, the data behind a Matrix4f is just a "float array[16]".
+
+Fixed-size objects are typically very small, which means that we want to handle them with zero runtime overhead -- both in terms of memory usage and of speed.
+
+Now, vectorization (both SSE and AltiVec) works with 128-bit packets. Moreover, for performance reasons, these packets need to be have 128-bit alignment.
+
+So it turns out that the only way that fixed-size Eigen objects can be vectorized, is if their size is a multiple of 128 bits, or 16 bytes. Eigen will then request 16-byte alignment for these objects, and henceforth rely on these objects being aligned so no runtime check for alignment is performed.
+
+*/
+
+}
diff --git a/doc/I06_TopicEigenExpressionTemplates.dox b/doc/I06_TopicEigenExpressionTemplates.dox
new file mode 100644
index 000000000..b31fd47f9
--- /dev/null
+++ b/doc/I06_TopicEigenExpressionTemplates.dox
@@ -0,0 +1,12 @@
+namespace Eigen {
+
+/** \page TopicEigenExpressionTemplates Expression templates in Eigen
+
+
+TODO: write this dox page!
+
+Is linked from the tutorial on arithmetic ops.
+
+*/
+
+}
diff --git a/doc/I07_TopicScalarTypes.dox b/doc/I07_TopicScalarTypes.dox
new file mode 100644
index 000000000..2ff03c198
--- /dev/null
+++ b/doc/I07_TopicScalarTypes.dox
@@ -0,0 +1,12 @@
+namespace Eigen {
+
+/** \page TopicScalarTypes Scalar types
+
+
+TODO: write this dox page!
+
+Is linked from the tutorial on the Matrix class.
+
+*/
+
+}
diff --git a/doc/I08_Resizing.dox b/doc/I08_Resizing.dox
new file mode 100644
index 000000000..c323e17ad
--- /dev/null
+++ b/doc/I08_Resizing.dox
@@ -0,0 +1,11 @@
+namespace Eigen {
+
+/** \page TopicResizing Resizing
+
+
+TODO: write this dox page!
+
+Is linked from the tutorial on the Matrix class.
+
+*/
+}
diff --git a/doc/I09_Vectorization.dox b/doc/I09_Vectorization.dox
new file mode 100644
index 000000000..274d0451b
--- /dev/null
+++ b/doc/I09_Vectorization.dox
@@ -0,0 +1,9 @@
+namespace Eigen {
+
+/** \page TopicVectorization Vectorization
+
+
+TODO: write this dox page!
+
+*/
+}
diff --git a/doc/I10_Assertions.dox b/doc/I10_Assertions.dox
new file mode 100644
index 000000000..d5697fcee
--- /dev/null
+++ b/doc/I10_Assertions.dox
@@ -0,0 +1,13 @@
+namespace Eigen {
+
+/** \page TopicAssertions Assertions
+
+
+TODO: write this dox page!
+
+Is linked from the tutorial on matrix arithmetic.
+
+\sa Section \ref TopicPreprocessorDirectivesAssertions on page \ref TopicPreprocessorDirectives.
+
+*/
+}
diff --git a/doc/I11_Aliasing.dox b/doc/I11_Aliasing.dox
new file mode 100644
index 000000000..7c111991c
--- /dev/null
+++ b/doc/I11_Aliasing.dox
@@ -0,0 +1,214 @@
+namespace Eigen {
+
+/** \page TopicAliasing Aliasing
+
+In Eigen, aliasing refers to assignment statement in which the same matrix (or array or vector) appears on the
+left and on the right of the assignment operators. Statements like <tt>mat = 2 * mat;</tt> or <tt>mat =
+mat.transpose();</tt> exhibit aliasing. The aliasing in the first example is harmless, but the aliasing in the
+second example leads to unexpected results. This page explains what aliasing is, when it is harmful, and what
+to do about it.
+
+<b>Table of contents</b>
+ - \ref TopicAliasingExamples
+ - \ref TopicAliasingSolution
+ - \ref TopicAliasingCwise
+ - \ref TopicAliasingMatrixMult
+ - \ref TopicAliasingSummary
+
+
+\section TopicAliasingExamples Examples
+
+Here is a simple example exhibiting aliasing:
+
+<table class="example">
+<tr><th>Example</th><th>Output</th></tr>
+<tr><td>
+\include TopicAliasing_block.cpp
+</td>
+<td>
+\verbinclude TopicAliasing_block.out
+</td></tr></table>
+
+The output is not what one would expect. The problem is the assignment
+\code
+mat.bottomRightCorner(2,2) = mat.topLeftCorner(2,2);
+\endcode
+This assignment exhibits aliasing: the coefficient \c mat(1,1) appears both in the block
+<tt>mat.bottomRightCorner(2,2)</tt> on the left-hand side of the assignment and the block
+<tt>mat.topLeftCorner(2,2)</tt> on the right-hand side. After the assignment, the (2,2) entry in the bottom
+right corner should have the value of \c mat(1,1) before the assignment, which is 5. However, the output shows
+that \c mat(2,2) is actually 1. The problem is that Eigen uses lazy evaluation (see
+\ref TopicEigenExpressionTemplates) for <tt>mat.topLeftCorner(2,2)</tt>. The result is similar to
+\code
+mat(1,1) = mat(0,0);
+mat(1,2) = mat(0,1);
+mat(2,1) = mat(1,0);
+mat(2,2) = mat(1,1);
+\endcode
+Thus, \c mat(2,2) is assigned the \e new value of \c mat(1,1) instead of the old value. The next section
+explains how to solve this problem by calling \link DenseBase::eval() eval()\endlink.
+
+Note that if \c mat were a bigger, then the blocks would not overlap, and there would be no aliasing
+problem. This means that in general aliasing cannot be detected at compile time. However, Eigen does detect
+some instances of aliasing, albeit at run time. The following example exhibiting aliasing was mentioned in
+\ref TutorialMatrixArithmetic :
+
+<table class="example">
+<tr><th>Example</th><th>Output</th></tr>
+<tr><td>
+\include tut_arithmetic_transpose_aliasing.cpp
+</td>
+<td>
+\verbinclude tut_arithmetic_transpose_aliasing.out
+</td></tr></table>
+
+Again, the output shows the aliasing issue. However, by default Eigen uses a run-time assertion to detect this
+and exits with a message like
+
+\verbatim
+void Eigen::DenseBase<Derived>::checkTransposeAliasing(const OtherDerived&) const
+[with OtherDerived = Eigen::Transpose<Eigen::Matrix<int, 2, 2, 0, 2, 2> >, Derived = Eigen::Matrix<int, 2, 2, 0, 2, 2>]:
+Assertion `(!internal::check_transpose_aliasing_selector<Scalar,internal::blas_traits<Derived>::IsTransposed,OtherDerived>::run(internal::extract_data(derived()), other))
+&& "aliasing detected during tranposition, use transposeInPlace() or evaluate the rhs into a temporary using .eval()"' failed.
+\endverbatim
+
+The user can turn Eigen's run-time assertions like the one to detect this aliasing problem off by defining the
+EIGEN_NO_DEBUG macro, and the above program was compiled with this macro turned off in order to illustrate the
+aliasing problem. See \ref TopicAssertions for more information about Eigen's run-time assertions.
+
+
+\section TopicAliasingSolution Resolving aliasing issues
+
+If you understand the cause of the aliasing issue, then it is obvious what must happen to solve it: Eigen has
+to evaluate the right-hand side fully into a temporary matrix/array and then assign it to the left-hand
+side. The function \link DenseBase::eval() eval() \endlink does precisely that.
+
+For example, here is the corrected version of the first example above:
+
+<table class="example">
+<tr><th>Example</th><th>Output</th></tr>
+<tr><td>
+\include TopicAliasing_block_correct.cpp
+</td>
+<td>
+\verbinclude TopicAliasing_block_correct.out
+</td></tr></table>
+
+Now, \c mat(2,2) equals 5 after the assignment, as it should be.
+
+The same solution also works for the second example, with the transpose: simply replace the line
+<tt>a = a.transpose();</tt> with <tt>a = a.transpose().eval();</tt>. However, in this common case there is a
+better solution. Eigen provides the special-purpose function
+\link DenseBase::transposeInPlace() transposeInPlace() \endlink which replaces a matrix by its transpose.
+This is shown below:
+
+<table class="example">
+<tr><th>Example</th><th>Output</th></tr>
+<tr><td>
+\include tut_arithmetic_transpose_inplace.cpp
+</td>
+<td>
+\verbinclude tut_arithmetic_transpose_inplace.out
+</td></tr></table>
+
+If an xxxInPlace() function is available, then it is best to use it, because it indicates more clearly what you
+are doing. This may also allow Eigen to optimize more aggressively. These are some of the xxxInPlace()
+functions provided:
+
+<table class="manual">
+<tr><th>Original function</th><th>In-place function</th></tr>
+<tr> <td> MatrixBase::adjoint() </td> <td> MatrixBase::adjointInPlace() </td> </tr>
+<tr class="alt"> <td> DenseBase::reverse() </td> <td> DenseBase::reverseInPlace() </td> </tr>
+<tr> <td> LDLT::solve() </td> <td> LDLT::solveInPlace() </td> </tr>
+<tr class="alt"> <td> LLT::solve() </td> <td> LLT::solveInPlace() </td> </tr>
+<tr> <td> TriangularView::solve() </td> <td> TriangularView::solveInPlace() </td> </tr>
+<tr class="alt"> <td> DenseBase::transpose() </td> <td> DenseBase::transposeInPlace() </td> </tr>
+</table>
+
+
+\section TopicAliasingCwise Aliasing and component-wise operations
+
+As explained above, it may be dangerous if the same matrix or array occurs on both the left-hand side and the
+right-hand side of an assignment operator, and it is then often necessary to evaluate the right-hand side
+explicitly. However, applying component-wise operations (such as matrix addition, scalar multiplication and
+array multiplication) is safe.
+
+The following example has only component-wise operations. Thus, there is no need for .eval() even though
+the same matrix appears on both sides of the assignments.
+
+<table class="example">
+<tr><th>Example</th><th>Output</th></tr>
+<tr><td>
+\include TopicAliasing_cwise.cpp
+</td>
+<td>
+\verbinclude TopicAliasing_cwise.out
+</td></tr></table>
+
+In general, an assignment is safe if the (i,j) entry of the expression on the right-hand side depends only on
+the (i,j) entry of the matrix or array on the left-hand side and not on any other entries. In that case it is
+not necessary to evaluate the right-hand side explicitly.
+
+
+\section TopicAliasingMatrixMult Aliasing and matrix multiplication
+
+Matrix multiplication is the only operation in Eigen that assumes aliasing by default. Thus, if \c matA is a
+matrix, then the statement <tt>matA = matA * matA;</tt> is safe. All other operations in Eigen assume that
+there are no aliasing problems, either because the result is assigned to a different matrix or because it is a
+component-wise operation.
+
+<table class="example">
+<tr><th>Example</th><th>Output</th></tr>
+<tr><td>
+\include TopicAliasing_mult1.cpp
+</td>
+<td>
+\verbinclude TopicAliasing_mult1.out
+</td></tr></table>
+
+However, this comes at a price. When executing the expression <tt>matA = matA * matA</tt>, Eigen evaluates the
+product in a temporary matrix which is assigned to \c matA after the computation. This is fine. But Eigen does
+the same when the product is assigned to a different matrix (e.g., <tt>matB = matA * matA</tt>). In that case,
+it is more efficient to evaluate the product directly into \c matB instead of evaluating it first into a
+temporary matrix and copying that matrix to \c matB.
+
+The user can indicate with the \link MatrixBase::noalias() noalias()\endlink function that there is no
+aliasing, as follows: <tt>matB.noalias() = matA * matA</tt>. This allows Eigen to evaluate the matrix product
+<tt>matA * matA</tt> directly into \c matB.
+
+<table class="example">
+<tr><th>Example</th><th>Output</th></tr>
+<tr><td>
+\include TopicAliasing_mult2.cpp
+</td>
+<td>
+\verbinclude TopicAliasing_mult2.out
+</td></tr></table>
+
+Of course, you should not use \c noalias() when there is in fact aliasing taking place. If you do, then you
+may get wrong results:
+
+<table class="example">
+<tr><th>Example</th><th>Output</th></tr>
+<tr><td>
+\include TopicAliasing_mult3.cpp
+</td>
+<td>
+\verbinclude TopicAliasing_mult3.out
+</td></tr></table>
+
+
+\section TopicAliasingSummary Summary
+
+Aliasing occurs when the same matrix or array coefficients appear both on the left- and the right-hand side of
+an assignment operator.
+ - Aliasing is harmless with coefficient-wise computations; this includes scalar multiplication and matrix or
+ array addition.
+ - When you multiply two matrices, Eigen assumes that aliasing occurs. If you know that there is no aliasing,
+ then you can use \link MatrixBase::noalias() noalias()\endlink.
+ - In all other situations, Eigen assumes that there is no aliasing issue and thus gives the wrong result if
+ aliasing does in fact occur. To prevent this, you have to use \link DenseBase::eval() eval() \endlink or
+ one of the xxxInPlace() functions.
+
+*/
+}
diff --git a/doc/I12_ClassHierarchy.dox b/doc/I12_ClassHierarchy.dox
new file mode 100644
index 000000000..700d01802
--- /dev/null
+++ b/doc/I12_ClassHierarchy.dox
@@ -0,0 +1,133 @@
+namespace Eigen {
+
+/** \page TopicClassHierarchy The class hierarchy
+
+This page explains the design of the core classes in Eigen's class hierarchy and how they fit together. Casual
+users probably need not concern themselves with these details, but it may be useful for both advanced users
+and Eigen developers.
+
+<b>Table of contents</b>
+ - \ref TopicClassHierarchyPrinciples
+ - \ref TopicClassHierarchyCoreClasses
+ - \ref TopicClassHierarchyBaseClasses
+ - \ref TopicClassHierarchyInheritanceDiagrams
+
+
+\section TopicClassHierarchyPrinciples Principles
+
+Eigen's class hierarchy is designed so that virtual functions are avoided where their overhead would
+significantly impair performance. Instead, Eigen achieves polymorphism with the Curiously Recurring Template
+Pattern (CRTP). In this pattern, the base class (for instance, \c MatrixBase) is in fact a template class, and
+the derived class (for instance, \c Matrix) inherits the base class with the derived class itself as a
+template argument (in this case, \c Matrix inherits from \c MatrixBase&lt;Matrix&gt;). This allows Eigen to
+resolve the polymorphic function calls at compile time.
+
+In addition, the design avoids multiple inheritance. One reason for this is that in our experience, some
+compilers (like MSVC) fail to perform empty base class optimization, which is crucial for our fixed-size
+types.
+
+
+\section TopicClassHierarchyCoreClasses The core classes
+
+These are the classes that you need to know about if you want to write functions that accept or return Eigen
+objects.
+
+ - Matrix means plain dense matrix. If \c m is a \c %Matrix, then, for instance, \c m+m is no longer a
+ \c %Matrix, it is a "matrix expression".
+ - MatrixBase means dense matrix expression. This means that a \c %MatrixBase is something that can be
+ added, matrix-multiplied, LU-decomposed, QR-decomposed... All matrix expression classes, including
+ \c %Matrix itself, inherit \c %MatrixBase.
+ - Array means plain dense array. If \c x is an \c %Array, then, for instance, \c x+x is no longer an
+ \c %Array, it is an "array expression".
+ - ArrayBase means dense array expression. This means that an \c %ArrayBase is something that can be
+ added, array-multiplied, and on which you can perform all sorts of array operations... All array
+ expression classes, including \c %Array itself, inherit \c %ArrayBase.
+ - DenseBase means dense (matrix or array) expression. Both \c %ArrayBase and \c %MatrixBase inherit
+ \c %DenseBase. \c %DenseBase is where all the methods go that apply to dense expressions regardless of
+ whether they are matrix or array expressions. For example, the \link DenseBase::block() block(...) \endlink
+ methods are in \c %DenseBase.
+
+\section TopicClassHierarchyBaseClasses Base classes
+
+These classes serve as base classes for the five core classes mentioned above. They are more internal and so
+less interesting for users of the Eigen library.
+
+ - PlainObjectBase means dense (matrix or array) plain object, i.e. something that stores its own dense
+ array of coefficients. This is where, for instance, the \link PlainObjectBase::resize() resize() \endlink
+ methods go. \c %PlainObjectBase is inherited by \c %Matrix and by \c %Array. But above, we said that
+ \c %Matrix inherits \c %MatrixBase and \c %Array inherits \c %ArrayBase. So does that mean multiple
+ inheritance? No, because \c %PlainObjectBase \e itself inherits \c %MatrixBase or \c %ArrayBase depending
+ on whether we are in the matrix or array case. When we said above that \c %Matrix inherited
+ \c %MatrixBase, we omitted to say it does so indirectly via \c %PlainObjectBase. Same for \c %Array.
+ - DenseCoeffsBase means something that has dense coefficient accessors. It is a base class for
+ \c %DenseBase. The reason for \c %DenseCoeffsBase to exist is that the set of available coefficient
+ accessors is very different depending on whether a dense expression has direct memory access or not (the
+ \c DirectAccessBit flag). For example, if \c x is a plain matrix, then \c x has direct access, and
+ \c x.transpose() and \c x.block(...) also have direct access, because their coefficients can be read right
+ off memory, but for example, \c x+x does not have direct memory access, because obtaining any of its
+ coefficients requires a computation (an addition), it can't be just read off memory.
+ - EigenBase means anything that can be evaluated into a plain dense matrix or array (even if that would
+ be a bad idea). \c %EigenBase is really the absolute base class for anything that remotely looks like a
+ matrix or array. It is a base class for \c %DenseCoeffsBase, so it sits below all our dense class
+ hierarchy, but it is not limited to dense expressions. For example, \c %EigenBase is also inherited by
+ diagonal matrices, sparse matrices, etc...
+
+
+\section TopicClassHierarchyInheritanceDiagrams Inheritance diagrams
+
+The inheritance diagram for Matrix looks as follows:
+
+<pre>
+EigenBase&lt;%Matrix&gt;
+ <-- DenseCoeffsBase&lt;%Matrix&gt; (direct access case)
+ <-- DenseBase&lt;%Matrix&gt;
+ <-- MatrixBase&lt;%Matrix&gt;
+ <-- PlainObjectBase&lt;%Matrix&gt; (matrix case)
+ <-- Matrix
+</pre>
+
+The inheritance diagram for Array looks as follows:
+
+<pre>
+EigenBase&lt;%Array&gt;
+ <-- DenseCoeffsBase&lt;%Array&gt; (direct access case)
+ <-- DenseBase&lt;%Array&gt;
+ <-- ArrayBase&lt;%Array&gt;
+ <-- PlainObjectBase&lt;%Array&gt; (array case)
+ <-- Array
+</pre>
+
+The inheritance diagram for some other matrix expression class, here denoted by \c SomeMatrixXpr, looks as
+follows:
+
+<pre>
+EigenBase&lt;SomeMatrixXpr&gt;
+ <-- DenseCoeffsBase&lt;SomeMatrixXpr&gt; (direct access or no direct access case)
+ <-- DenseBase&lt;SomeMatrixXpr&gt;
+ <-- MatrixBase&lt;SomeMatrixXpr&gt;
+ <-- SomeMatrixXpr
+</pre>
+
+The inheritance diagram for some other array expression class, here denoted by \c SomeArrayXpr, looks as
+follows:
+
+<pre>
+EigenBase&lt;SomeArrayXpr&gt;
+ <-- DenseCoeffsBase&lt;SomeArrayXpr&gt; (direct access or no direct access case)
+ <-- DenseBase&lt;SomeArrayXpr&gt;
+ <-- ArrayBase&lt;SomeArrayXpr&gt;
+ <-- SomeArrayXpr
+</pre>
+
+Finally, consider an example of something that is not a dense expression, for instance a diagonal matrix. The
+corresponding inheritance diagram is:
+
+<pre>
+EigenBase&lt;%DiagonalMatrix&gt;
+ <-- DiagonalBase&lt;%DiagonalMatrix&gt;
+ <-- DiagonalMatrix
+</pre>
+
+
+*/
+}
diff --git a/doc/I13_FunctionsTakingEigenTypes.dox b/doc/I13_FunctionsTakingEigenTypes.dox
new file mode 100644
index 000000000..f9e6fafed
--- /dev/null
+++ b/doc/I13_FunctionsTakingEigenTypes.dox
@@ -0,0 +1,188 @@
+namespace Eigen {
+
+/** \page TopicFunctionTakingEigenTypes Writing Functions Taking Eigen Types as Parameters
+
+Eigen's use of expression templates results in potentially every expression being of a different type. If you pass such an expression to a function taking a parameter of type Matrix, your expression will implicitly be evaluated into a temporary Matrix, which will then be passed to the function. This means that you lose the benefit of expression templates. Concretely, this has two drawbacks:
+ \li The evaluation into a temporary may be useless and inefficient;
+ \li This only allows the function to read from the expression, not to write to it.
+
+Fortunately, all this myriad of expression types have in common that they all inherit a few common, templated base classes. By letting your function take templated parameters of these base types, you can let them play nicely with Eigen's expression templates.
+
+<b>Table of contents</b>
+ - \ref TopicFirstExamples
+ - \ref TopicPlainFunctionsWorking
+ - \ref TopicPlainFunctionsFailing
+ - \ref TopicResizingInGenericImplementations
+ - \ref TopicSummary
+
+\section TopicFirstExamples Some First Examples
+
+This section will provide simple examples for different types of objects Eigen is offering. Before starting with the actual examples, we need to recapitulate which base objects we can work with (see also \ref TopicClassHierarchy).
+
+ \li MatrixBase: The common base class for all dense matrix expressions (as opposed to array expressions, as opposed to sparse and special matrix classes). Use it in functions that are meant to work only on dense matrices.
+ \li ArrayBase: The common base class for all dense array expressions (as opposed to matrix expressions, etc). Use it in functions that are meant to work only on arrays.
+ \li DenseBase: The common base class for all dense matrix expression, that is, the base class for both \c MatrixBase and \c ArrayBase. It can be used in functions that are meant to work on both matrices and arrays.
+ \li EigenBase: The base class unifying all types of objects that can be evaluated into dense matrices or arrays, for example special matrix classes such as diagonal matrices, permutation matrices, etc. It can be used in functions that are meant to work on any such general type.
+
+<b> %EigenBase Example </b><br/><br/>
+Prints the dimensions of the most generic object present in Eigen. It coulde be any matrix expressions, any dense or sparse matrix and any array.
+<table class="example">
+<tr><th>Example:</th><th>Output:</th></tr>
+<tr><td>
+\include function_taking_eigenbase.cpp
+</td>
+<td>
+\verbinclude function_taking_eigenbase.out
+</td></tr></table>
+<b> %DenseBase Example </b><br/><br/>
+Prints a sub-block of the dense expression. Accepts any dense matrix or array expression, but no sparse objects and no special matrix classes such as DiagonalMatrix.
+\code
+template <typename Derived>
+void print_block(const DenseBase<Derived>& b, int x, int y, int r, int c)
+{
+ std::cout << "block: " << b.block(x,y,r,c) << std::endl;
+}
+\endcode
+<b> %ArrayBase Example </b><br/><br/>
+Prints the maximum coefficient of the array or array-expression.
+\code
+template <typename Derived>
+void print_max_coeff(const ArrayBase<Derived> &a)
+{
+ std::cout << "max: " << a.maxCoeff() << std::endl;
+}
+\endcode
+<b> %MatrixBase Example </b><br/><br/>
+Prints the inverse condition number of the given matrix or matrix-expression.
+\code
+template <typename Derived>
+void print_inv_cond(const MatrixBase<Derived>& a)
+{
+ const typename JacobiSVD<typename Derived::PlainObject>::SingularValuesType&
+ sing_vals = a.jacobiSvd().singularValues();
+ std::cout << "inv cond: " << sing_vals(sing_vals.size()-1) / sing_vals(0) << std::endl;
+}
+\endcode
+<b> Multiple templated arguments example </b><br/><br/>
+Calculate the Euclidean distance between two points.
+\code
+template <typename DerivedA,typename DerivedB>
+typename DerivedA::Scalar squaredist(const MatrixBase<DerivedA>& p1,const MatrixBase<DerivedB>& p2)
+{
+ return (p1-p2).squaredNorm();
+}
+\endcode
+Notice that we used two template parameters, one per argument. This permits the function to handle inputs of different types, e.g.,
+\code
+squaredist(v1,2*v2)
+\endcode
+where the first argument \c v1 is a vector and the second argument \c 2*v2 is an expression.
+<br/><br/>
+
+These examples are just intended to give the reader a first impression of how functions can be written which take a plain and constant Matrix or Array argument. They are also intended to give the reader an idea about the most common base classes being the optimal candidates for functions. In the next section we will look in more detail at an example and the different ways it can be implemented, while discussing each implementation's problems and advantages. For the discussion below, Matrix and Array as well as MatrixBase and ArrayBase can be exchanged and all arguments still hold.
+
+\section TopicPlainFunctionsWorking In which cases do functions taking plain Matrix or Array arguments work?
+
+Let's assume one wants to write a function computing the covariance matrix of two input matrices where each row is an observation. The implementation of this function might look like this
+\code
+MatrixXf cov(const MatrixXf& x, const MatrixXf& y)
+{
+ const float num_observations = static_cast<float>(x.rows());
+ const RowVectorXf x_mean = x.colwise().sum() / num_observations;
+ const RowVectorXf y_mean = y.colwise().sum() / num_observations;
+ return (x.rowwise() - x_mean).transpose() * (y.rowwise() - y_mean) / num_observations;
+}
+\endcode
+and contrary to what one might think at first, this implementation is fine unless you require a genric implementation that works with double matrices too and unless you do not care about temporary objects. Why is that the case? Where are temporaries involved? How can code as given below compile?
+\code
+MatrixXf x,y,z;
+MatrixXf C = cov(x,y+z);
+\endcode
+In this special case, the example is fine and will be working because both parameters are declared as \e const references. The compiler creates a temporary and evaluates the expression x+z into this temporary. Once the function is processed, the temporary is released and the result is assigned to C.
+
+\b Note: Functions taking \e const references to Matrix (or Array) can process expressions at the cost of temporaries.
+
+\section TopicPlainFunctionsFailing In which cases do functions taking a plain Matrix or Array argument fail?
+
+Here, we consider a slightly modified version of the function given above. This time, we do not want to return the result but pass an additional non-const paramter which allows us to store the result. A first naive implementation might look as follows.
+\code
+// Note: This code is flawed!
+void cov(const MatrixXf& x, const MatrixXf& y, MatrixXf& C)
+{
+ const float num_observations = static_cast<float>(x.rows());
+ const RowVectorXf x_mean = x.colwise().sum() / num_observations;
+ const RowVectorXf y_mean = y.colwise().sum() / num_observations;
+ C = (x.rowwise() - x_mean).transpose() * (y.rowwise() - y_mean) / num_observations;
+}
+\endcode
+When trying to execute the following code
+\code
+MatrixXf C = MatrixXf::Zero(3,6);
+cov(x,y, C.block(0,0,3,3));
+\endcode
+the compiler will fail, because it is not possible to convert the expression returned by \c MatrixXf::block() into a non-const \c MatrixXf&. This is the case because the compiler wants to protect you from writing your result to a temporary object. In this special case this protection is not intended -- we want to write to a temporary object. So how can we overcome this problem?
+
+The solution which is preferred at the moment is based on a little \em hack. One needs to pass a const reference to the matrix and internally the constness needs to be cast away. The correct implementation for C98 compliant compilers would be
+\code
+template <typename Derived, typename OtherDerived>
+void cov(const MatrixBase<Derived>& x, const MatrixBase<Derived>& y, MatrixBase<OtherDerived> const & C)
+{
+ typedef typename Derived::Scalar Scalar;
+ typedef typename internal::plain_row_type<Derived>::type RowVectorType;
+
+ const Scalar num_observations = static_cast<Scalar>(x.rows());
+
+ const RowVectorType x_mean = x.colwise().sum() / num_observations;
+ const RowVectorType y_mean = y.colwise().sum() / num_observations;
+
+ const_cast< MatrixBase<OtherDerived>& >(C) =
+ (x.rowwise() - x_mean).transpose() * (y.rowwise() - y_mean) / num_observations;
+}
+\endcode
+The implementation above does now not only work with temporary expressions but it also allows to use the function with matrices of arbitrary floating point scalar types.
+
+\b Note: The const cast hack will only work with templated functions. It will not work with the MatrixXf implementation because it is not possible to cast a Block expression to a Matrix reference!
+
+
+
+\section TopicResizingInGenericImplementations How to resize matrices in generic implementations?
+
+One might think we are done now, right? This is not completely true because in order for our covariance function to be generically applicable, we want the follwing code to work
+\code
+MatrixXf x = MatrixXf::Random(100,3);
+MatrixXf y = MatrixXf::Random(100,3);
+MatrixXf C;
+cov(x, y, C);
+\endcode
+This is not the case anymore, when we are using an implementation taking MatrixBase as a parameter. In general, Eigen supports automatic resizing but it is not possible to do so on expressions. Why should resizing of a matrix Block be allowed? It is a reference to a sub-matrix and we definitely don't want to resize that. So how can we incorporate resizing if we cannot resize on MatrixBase? The solution is to resize the derived object as in this implementation.
+\code
+template <typename Derived, typename OtherDerived>
+void cov(const MatrixBase<Derived>& x, const MatrixBase<Derived>& y, MatrixBase<OtherDerived> const & C_)
+{
+ typedef typename Derived::Scalar Scalar;
+ typedef typename internal::plain_row_type<Derived>::type RowVectorType;
+
+ const Scalar num_observations = static_cast<Scalar>(x.rows());
+
+ const RowVectorType x_mean = x.colwise().sum() / num_observations;
+ const RowVectorType y_mean = y.colwise().sum() / num_observations;
+
+ MatrixBase<OtherDerived>& C = const_cast< MatrixBase<OtherDerived>& >(C_);
+
+ C.derived().resize(x.cols(),x.cols()); // resize the derived object
+ C = (x.rowwise() - x_mean).transpose() * (y.rowwise() - y_mean) / num_observations;
+}
+\endcode
+This implementation is now working for parameters being expressions and for parameters being matrices and having the wrong size. Resizing the expressions does not do any harm in this case unless they actually require resizing. That means, passing an expression with the wrong dimensions will result in a run-time error (in debug mode only) while passing expressions of the correct size will just work fine.
+
+\b Note: In the above discussion the terms Matrix and Array and MatrixBase and ArrayBase can be exchanged and all arguments still hold.
+
+\section TopicSummary Summary
+
+ - To summarize, the implementation of functions taking non-writable (const referenced) objects is not a big issue and does not lead to problematic situations in terms of compiling and running your program. However, a naive implementation is likely to introduce unnecessary temporary objects in your code. In order to avoid evaluating parameters into temporaries, pass them as (const) references to MatrixBase or ArrayBase (so templatize your function).
+
+ - Functions taking writable (non-const) parameters must take const references and cast away constness within the function body.
+
+ - Functions that take as parameters MatrixBase (or ArrayBase) objects, and potentially need to resize them (in the case where they are resizable), must call resize() on the derived class, as returned by derived().
+*/
+}
diff --git a/doc/I14_PreprocessorDirectives.dox b/doc/I14_PreprocessorDirectives.dox
new file mode 100644
index 000000000..f29f0720c
--- /dev/null
+++ b/doc/I14_PreprocessorDirectives.dox
@@ -0,0 +1,112 @@
+namespace Eigen {
+
+/** \page TopicPreprocessorDirectives Preprocessor directives
+
+You can control some aspects of %Eigen by defining the preprocessor tokens using \c \#define. These macros
+should be defined before any %Eigen headers are included. Often they are best set in the project options.
+
+This page lists the preprocesor tokens recognised by %Eigen.
+
+<b>Table of contents</b>
+ - \ref TopicPreprocessorDirectivesMajor
+ - \ref TopicPreprocessorDirectivesAssertions
+ - \ref TopicPreprocessorDirectivesPerformance
+ - \ref TopicPreprocessorDirectivesPlugins
+ - \ref TopicPreprocessorDirectivesDevelopers
+
+
+\section TopicPreprocessorDirectivesMajor Macros with major effects
+
+These macros have a major effect and typically break the API (Application Programming Interface) and/or the
+ABI (Application Binary Interface). This can be rather dangerous: if parts of your program are compiled with
+one option, and other parts (or libraries that you use) are compiled with another option, your program may
+fail to link or exhibit subtle bugs. Nevertheless, these options can be useful for people who know what they
+are doing.
+
+ - \b EIGEN2_SUPPORT - if defined, enables the Eigen2 compatibility mode. This is meant to ease the transition
+ of Eigen2 to Eigen3 (see \ref Eigen2ToEigen3). Not defined by default.
+ - \b EIGEN2_SUPPORT_STAGEnn_xxx (for various values of nn and xxx) - staged migration path from Eigen2 to
+ Eigen3; see \ref Eigen2SupportModes.
+ - \b EIGEN_DEFAULT_DENSE_INDEX_TYPE - the type for column and row indices in matrices, vectors and array
+ (DenseBase::Index). Set to \c std::ptrdiff_t by default.
+ - \b EIGEN_DEFAULT_IO_FORMAT - the IOFormat to use when printing a matrix if no #IOFormat is specified.
+ Defaults to the #IOFormat constructed by the default constructor IOFormat().
+ - \b EIGEN_INITIALIZE_MATRICES_BY_ZERO - if defined, all entries of newly constructed matrices and arrays are
+ initializes to zero, as are new entries in matrices and arrays after resizing. Not defined by default.
+ - \b EIGEN_NO_AUTOMATIC_RESIZING - if defined, the matrices (or arrays) on both sides of an assignment
+ <tt>a = b</tt> have to be of the same size; otherwise, %Eigen automatically resizes \c a so that it is of
+ the correct size. Not defined by default.
+
+
+\section TopicPreprocessorDirectivesAssertions Assertions
+
+The %Eigen library contains many assertions to guard against programming errors, both at compile time and at
+run time. However, these assertions do cost time and can thus be turned off.
+
+ - \b EIGEN_NO_DEBUG - disables %Eigen's assertions if defined. Not defined by default, unless the
+ \c NDEBUG macro is defined (this is a standard C++ macro which disables all asserts).
+ - \b EIGEN_NO_STATIC_ASSERT - if defined, compile-time static assertions are replaced by runtime assertions;
+ this saves compilation time. Not defined by default.
+ - \b eigen_assert - macro with one argument that is used inside %Eigen for assertions. By default, it is
+ basically defined to be \c assert, which aborts the program if the assertion is violated. Redefine this
+ macro if you want to do something else, like throwing an exception.
+ - \b EIGEN_MPL2_ONLY - disable non MPL2 compatible features, or in other words disable the features which
+ are still under the LGPL.
+
+
+\section TopicPreprocessorDirectivesPerformance Alignment, vectorization and performance tweaking
+
+ - \b EIGEN_DONT_ALIGN - disables alignment completely. %Eigen will not try to align its objects and does not
+ expect that any objects passed to it are aligned. This will turn off vectorization. Not defined by default.
+ - \b EIGEN_DONT_ALIGN_STATICALLY - disables alignment of arrays on the stack. Not defined by default, unless
+ \c EIGEN_DONT_ALIGN is defined.
+ - \b EIGEN_DONT_VECTORIZE - disables explicit vectorization when defined. Not defined by default, unless
+ alignment is disabled by %Eigen's platform test or the user defining \c EIGEN_DONT_ALIGN.
+ - \b EIGEN_FAST_MATH - enables some optimizations which might affect the accuracy of the result. The only
+ optimization this currently includes is single precision sin() and cos() in the present of SSE
+ vectorization. Defined by default.
+ - \b EIGEN_UNROLLING_LIMIT - defines the size of a loop to enable meta unrolling. Set it to zero to disable
+ unrolling. The size of a loop here is expressed in %Eigen's own notion of "number of FLOPS", it does not
+ correspond to the number of iterations or the number of instructions. The default is value 100.
+
+
+\section TopicPreprocessorDirectivesPlugins Plugins
+
+It is possible to add new methods to many fundamental classes in %Eigen by writing a plugin. As explained in
+the section \ref ExtendingMatrixBase, the plugin is specified by defining a \c EIGEN_xxx_PLUGIN macro. The
+following macros are supported; none of them are defined by default.
+
+ - \b EIGEN_ARRAY_PLUGIN - filename of plugin for extending the Array class.
+ - \b EIGEN_ARRAYBASE_PLUGIN - filename of plugin for extending the ArrayBase class.
+ - \b EIGEN_CWISE_PLUGIN - filename of plugin for extending the Cwise class.
+ - \b EIGEN_DENSEBASE_PLUGIN - filename of plugin for extending the DenseBase class.
+ - \b EIGEN_DYNAMICSPARSEMATRIX_PLUGIN - filename of plugin for extending the DynamicSparseMatrix class.
+ - \b EIGEN_MATRIX_PLUGIN - filename of plugin for extending the Matrix class.
+ - \b EIGEN_MATRIXBASE_PLUGIN - filename of plugin for extending the MatrixBase class.
+ - \b EIGEN_PLAINOBJECTBASE_PLUGIN - filename of plugin for extending the PlainObjectBase class.
+ - \b EIGEN_QUATERNIONBASE_PLUGIN - filename of plugin for extending the QuaternionBase class.
+ - \b EIGEN_SPARSEMATRIX_PLUGIN - filename of plugin for extending the SparseMatrix class.
+ - \b EIGEN_SPARSEMATRIXBASE_PLUGIN - filename of plugin for extending the SparseMatrixBase class.
+ - \b EIGEN_SPARSEVECTOR_PLUGIN - filename of plugin for extending the SparseVector class.
+ - \b EIGEN_TRANSFORM_PLUGIN - filename of plugin for extending the Transform class.
+ - \b EIGEN_FUNCTORS_PLUGIN - filename of plugin for adding new functors and specializations of functor_traits.
+
+
+\section TopicPreprocessorDirectivesDevelopers Macros for Eigen developers
+
+These macros are mainly meant for people developing %Eigen and for testing purposes. Even though, they might be useful for power users and the curious for debugging and testing purpose, they \b should \b not \b be \b used by real-word code.
+
+ - \b EIGEN_DEFAULT_TO_ROW_MAJOR - when defined, the default storage order for matrices becomes row-major
+ instead of column-major. Not defined by default.
+ - \b EIGEN_INTERNAL_DEBUGGING - if defined, enables assertions in %Eigen's internal routines. This is useful
+ for debugging %Eigen itself. Not defined by default.
+ - \b EIGEN_NO_MALLOC - if defined, any request from inside the %Eigen to allocate memory from the heap
+ results in an assertion failure. This is useful to check that some routine does not allocate memory
+ dynamically. Not defined by default.
+ - \b EIGEN_RUNTIME_NO_MALLOC - if defined, a new switch is introduced which can be turned on and off by
+ calling <tt>set_is_malloc_allowed(bool)</tt>. If malloc is not allowed and %Eigen tries to allocate memory
+ dynamically anyway, an assertion failure results. Not defined by default.
+
+*/
+
+}
diff --git a/doc/I15_StorageOrders.dox b/doc/I15_StorageOrders.dox
new file mode 100644
index 000000000..7418912a6
--- /dev/null
+++ b/doc/I15_StorageOrders.dox
@@ -0,0 +1,89 @@
+namespace Eigen {
+
+/** \page TopicStorageOrders Storage orders
+
+There are two different storage orders for matrices and two-dimensional arrays: column-major and row-major.
+This page explains these storage orders and how to specify which one should be used.
+
+<b>Table of contents</b>
+ - \ref TopicStorageOrdersIntro
+ - \ref TopicStorageOrdersInEigen
+ - \ref TopicStorageOrdersWhich
+
+
+\section TopicStorageOrdersIntro Column-major and row-major storage
+
+The entries of a matrix form a two-dimensional grid. However, when the matrix is stored in memory, the entries
+have to somehow be laid out linearly. There are two main ways to do this, by row and by column.
+
+We say that a matrix is stored in \b row-major order if it is stored row by row. The entire first row is
+stored first, followed by the entire second row, and so on. Consider for example the matrix
+
+\f[
+A = \begin{bmatrix}
+8 & 2 & 2 & 9 \\
+9 & 1 & 4 & 4 \\
+3 & 5 & 4 & 5
+\end{bmatrix}.
+\f]
+
+If this matrix is stored in row-major order, then the entries are laid out in memory as follows:
+
+\code 8 2 2 9 9 1 4 4 3 5 4 5 \endcode
+
+On the other hand, a matrix is stored in \b column-major order if it is stored column by column, starting with
+the entire first column, followed by the entire second column, and so on. If the above matrix is stored in
+column-major order, it is laid out as follows:
+
+\code 8 9 3 2 1 5 2 4 4 9 4 5 \endcode
+
+This example is illustrated by the following Eigen code. It uses the PlainObjectBase::data() function, which
+returns a pointer to the memory location of the first entry of the matrix.
+
+<table class="example">
+<tr><th>Example</th><th>Output</th></tr>
+<tr><td>
+\include TopicStorageOrders_example.cpp
+</td>
+<td>
+\verbinclude TopicStorageOrders_example.out
+</td></tr></table>
+
+
+\section TopicStorageOrdersInEigen Storage orders in Eigen
+
+The storage order of a matrix or a two-dimensional array can be set by specifying the \c Options template
+parameter for Matrix or Array. As \ref TutorialMatrixClass explains, the %Matrix class template has six
+template parameters, of which three are compulsory (\c Scalar, \c RowsAtCompileTime and \c ColsAtCompileTime)
+and three are optional (\c Options, \c MaxRowsAtCompileTime and \c MaxColsAtCompileTime). If the \c Options
+parameter is set to \c RowMajor, then the matrix or array is stored in row-major order; if it is set to
+\c ColMajor, then it is stored in column-major order. This mechanism is used in the above Eigen program to
+specify the storage order.
+
+If the storage order is not specified, then Eigen defaults to storing the entry in column-major. This is also
+the case if one of the convenience typedefs (\c Matrix3f, \c ArrayXXd, etc.) is used.
+
+Matrices and arrays using one storage order can be assigned to matrices and arrays using the other storage
+order, as happens in the above program when \c Arowmajor is initialized using \c Acolmajor. Eigen will reorder
+the entries automatically. More generally, row-major and column-major matrices can be mixed in an expression
+as we want.
+
+
+\section TopicStorageOrdersWhich Which storage order to choose?
+
+So, which storage order should you use in your program? There is no simple answer to this question; it depends
+on your application. Here are some points to keep in mind:
+
+ - Your users may expect you to use a specific storage order. Alternatively, you may use other libraries than
+ Eigen, and these other libraries may expect a certain storage order. In these cases it may be easiest and
+ fastest to use this storage order in your whole program.
+ - Algorithms that traverse a matrix row by row will go faster when the matrix is stored in row-major order
+ because of better data locality. Similarly, column-by-column traversal is faster for column-major
+ matrices. It may be worthwhile to experiment a bit to find out what is faster for your particular
+ application.
+ - The default in Eigen is column-major. Naturally, most of the development and testing of the Eigen library
+ is thus done with column-major matrices. This means that, even though we aim to support column-major and
+ row-major storage orders transparently, the Eigen library may well work best with column-major matrices.
+
+*/
+}
diff --git a/doc/I16_TemplateKeyword.dox b/doc/I16_TemplateKeyword.dox
new file mode 100644
index 000000000..324532310
--- /dev/null
+++ b/doc/I16_TemplateKeyword.dox
@@ -0,0 +1,136 @@
+namespace Eigen {
+
+/** \page TopicTemplateKeyword The template and typename keywords in C++
+
+There are two uses for the \c template and \c typename keywords in C++. One of them is fairly well known
+amongst programmers: to define templates. The other use is more obscure: to specify that an expression refers
+to a template function or a type. This regularly trips up programmers that use the %Eigen library, often
+leading to error messages from the compiler that are difficult to understand.
+
+<b>Table of contents</b>
+ - \ref TopicTemplateKeywordToDefineTemplates
+ - \ref TopicTemplateKeywordExample
+ - \ref TopicTemplateKeywordExplanation
+ - \ref TopicTemplateKeywordResources
+
+
+\section TopicTemplateKeywordToDefineTemplates Using the template and typename keywords to define templates
+
+The \c template and \c typename keywords are routinely used to define templates. This is not the topic of this
+page as we assume that the reader is aware of this (otherwise consult a C++ book). The following example
+should illustrate this use of the \c template keyword.
+
+\code
+template <typename T>
+bool isPositive(T x)
+{
+ return x > 0;
+}
+\endcode
+
+We could just as well have written <tt>template &lt;class T&gt;</tt>; the keywords \c typename and \c class have the
+same meaning in this context.
+
+
+\section TopicTemplateKeywordExample An example showing the second use of the template keyword
+
+Let us illustrate the second use of the \c template keyword with an example. Suppose we want to write a
+function which copies all entries in the upper triangular part of a matrix into another matrix, while keeping
+the lower triangular part unchanged. A straightforward implementation would be as follows:
+
+<table class="example">
+<tr><th>Example:</th><th>Output:</th></tr>
+<tr><td>
+\include TemplateKeyword_simple.cpp
+</td>
+<td>
+\verbinclude TemplateKeyword_simple.out
+</td></tr></table>
+
+That works fine, but it is not very flexible. First, it only works with dynamic-size matrices of
+single-precision floats; the function \c copyUpperTriangularPart() does not accept static-size matrices or
+matrices with double-precision numbers. Second, if you use an expression such as
+<tt>mat.topLeftCorner(3,3)</tt> as the parameter \c src, then this is copied into a temporary variable of type
+MatrixXf; this copy can be avoided.
+
+As explained in \ref TopicFunctionTakingEigenTypes, both issues can be resolved by making
+\c copyUpperTriangularPart() accept any object of type MatrixBase. This leads to the following code:
+
+<table class="example">
+<tr><th>Example:</th><th>Output:</th></tr>
+<tr><td>
+\include TemplateKeyword_flexible.cpp
+</td>
+<td>
+\verbinclude TemplateKeyword_flexible.out
+</td></tr></table>
+
+The one line in the body of the function \c copyUpperTriangularPart() shows the second, more obscure use of
+the \c template keyword in C++. Even though it may look strange, the \c template keywords are necessary
+according to the standard. Without it, the compiler may reject the code with an error message like "no match
+for operator<".
+
+
+\section TopicTemplateKeywordExplanation Explanation
+
+The reason that the \c template keyword is necessary in the last example has to do with the rules for how
+templates are supposed to be compiled in C++. The compiler has to check the code for correct syntax at the
+point where the template is defined, without knowing the actual value of the template arguments (\c Derived1
+and \c Derived2 in the example). That means that the compiler cannot know that <tt>dst.triangularPart</tt> is
+a member template and that the following &lt; symbol is part of the delimiter for the template
+parameter. Another possibility would be that <tt>dst.triangularPart</tt> is a member variable with the &lt;
+symbol refering to the <tt>operator&lt;()</tt> function. In fact, the compiler should choose the second
+possibility, according to the standard. If <tt>dst.triangularPart</tt> is a member template (as in our case),
+the programmer should specify this explicitly with the \c template keyword and write <tt>dst.template
+triangularPart</tt>.
+
+The precise rules are rather complicated, but ignoring some subtleties we can summarize them as follows:
+- A <em>dependent name</em> is name that depends (directly or indirectly) on a template parameter. In the
+ example, \c dst is a dependent name because it is of type <tt>MatrixBase&lt;Derived1&gt;</tt> which depends
+ on the template parameter \c Derived1.
+- If the code contains either one of the contructions <tt>xxx.yyy</tt> or <tt>xxx-&gt;yyy</tt> and \c xxx is a
+ dependent name and \c yyy refers to a member template, then the \c template keyword must be used before
+ \c yyy, leading to <tt>xxx.template yyy</tt> or <tt>xxx-&gt;template yyy</tt>.
+- If the code contains the contruction <tt>xxx::yyy</tt> and \c xxx is a dependent name and \c yyy refers to a
+ member typedef, then the \c typename keyword must be used before the whole construction, leading to
+ <tt>typename xxx::yyy</tt>.
+
+As an example where the \c typename keyword is required, consider the following code in \ref TutorialSparse
+for iterating over the non-zero entries of a sparse matrix type:
+
+\code
+SparseMatrixType mat(rows,cols);
+for (int k=0; k<mat.outerSize(); ++k)
+ for (SparseMatrixType::InnerIterator it(mat,k); it; ++it)
+ {
+ /* ... */
+ }
+\endcode
+
+If \c SparseMatrixType depends on a template parameter, then the \c typename keyword is required:
+
+\code
+template <typename T>
+void iterateOverSparseMatrix(const SparseMatrix<T>& mat;
+{
+ for (int k=0; k<m1.outerSize(); ++k)
+ for (typename SparseMatrix<T>::InnerIterator it(mat,k); it; ++it)
+ {
+ /* ... */
+ }
+}
+\endcode
+
+
+\section TopicTemplateKeywordResources Resources for further reading
+
+For more information and a fuller explanation of this topic, the reader may consult the following sources:
+- The book "C++ Template Metaprogramming" by David Abrahams and Aleksey Gurtovoy contains a very good
+ explanation in Appendix B ("The typename and template Keywords") which formed the basis for this page.
+- http://pages.cs.wisc.edu/~driscoll/typename.html
+- http://www.parashift.com/c++-faq-lite/templates.html#faq-35.18
+- http://www.comeaucomputing.com/techtalk/templates/#templateprefix
+- http://www.comeaucomputing.com/techtalk/templates/#typename
+
+*/
+}
diff --git a/doc/Overview.dox b/doc/Overview.dox
new file mode 100644
index 000000000..2657c85bc
--- /dev/null
+++ b/doc/Overview.dox
@@ -0,0 +1,60 @@
+namespace Eigen {
+
+o /** \mainpage Eigen
+
+<div class="eimainmenu">
+ \ref GettingStarted "Getting started"
+ | \ref TutorialMatrixClass "Tutorial"
+ | \ref QuickRefPage "Short reference"
+</div>
+
+This is the API documentation for Eigen3. You can <a href="eigen-doc.tgz">download</a> it as a tgz archive for offline reading.
+
+Eigen2 users: here is a \ref Eigen2ToEigen3 guide to help porting your application.
+
+For a first contact with Eigen, the best place is to have a look at the \ref GettingStarted "tutorial". The \ref QuickRefPage "short reference" page gives you a quite complete description of the API in a very condensed format that is specially useful to recall the syntax of a particular feature, or to have a quick look at the API. For Matlab users, there is also a <a href="AsciiQuickReference.txt">ASCII quick reference</a> with Matlab translations. The \e Modules and \e Classes tabs at the top of this page give you access to the API documentation of individual classes and functions.
+
+\b Table \b of \b contents
+ - \ref Eigen2ToEigen3
+ - \ref GettingStarted
+ - \b Tutorial
+ - \ref TutorialMatrixClass
+ - \ref TutorialMatrixArithmetic
+ - \ref TutorialArrayClass
+ - \ref TutorialBlockOperations
+ - \ref TutorialAdvancedInitialization
+ - \ref TutorialLinearAlgebra
+ - \ref TutorialReductionsVisitorsBroadcasting
+ - \ref TutorialGeometry
+ - \ref TutorialSparse
+ - \ref TutorialMapClass
+ - \ref QuickRefPage
+ - <b>Advanced topics</b>
+ - \ref TopicAliasing
+ - \ref TopicLazyEvaluation
+ - \ref TopicLinearAlgebraDecompositions
+ - \ref TopicCustomizingEigen
+ - \ref TopicMultiThreading
+ - \ref TopicPreprocessorDirectives
+ - \ref TopicStorageOrders
+ - \ref TopicInsideEigenExample
+ - \ref TopicWritingEfficientProductExpression
+ - \ref TopicClassHierarchy
+ - \ref TopicFunctionTakingEigenTypes
+ - \ref TopicTemplateKeyword
+ - \ref TopicUsingIntelMKL
+ - <b>Topics related to alignment issues</b>
+ - \ref TopicUnalignedArrayAssert
+ - \ref TopicFixedSizeVectorizable
+ - \ref TopicStlContainers
+ - \ref TopicStructHavingEigenMembers
+ - \ref TopicPassingByValue
+ - \ref TopicWrongStackAlignment
+
+
+
+Want more? Checkout the \ref Unsupported_modules "unsupported modules" <a href="unsupported/index.html">documentation</a>.
+
+*/
+
+}
diff --git a/doc/QuickReference.dox b/doc/QuickReference.dox
new file mode 100644
index 000000000..3310d390a
--- /dev/null
+++ b/doc/QuickReference.dox
@@ -0,0 +1,737 @@
+namespace Eigen {
+
+/** \page QuickRefPage Quick reference guide
+
+\b Table \b of \b contents
+ - \ref QuickRef_Headers
+ - \ref QuickRef_Types
+ - \ref QuickRef_Map
+ - \ref QuickRef_ArithmeticOperators
+ - \ref QuickRef_Coeffwise
+ - \ref QuickRef_Reductions
+ - \ref QuickRef_Blocks
+ - \ref QuickRef_Misc
+ - \ref QuickRef_DiagTriSymm
+\n
+
+<hr>
+
+<a href="#" class="top">top</a>
+\section QuickRef_Headers Modules and Header files
+
+The Eigen library is divided in a Core module and several additional modules. Each module has a corresponding header file which has to be included in order to use the module. The \c %Dense and \c Eigen header files are provided to conveniently gain access to several modules at once.
+
+<table class="manual">
+<tr><th>Module</th><th>Header file</th><th>Contents</th></tr>
+<tr><td>\link Core_Module Core \endlink</td><td>\code#include <Eigen/Core>\endcode</td><td>Matrix and Array classes, basic linear algebra (including triangular and selfadjoint products), array manipulation</td></tr>
+<tr class="alt"><td>\link Geometry_Module Geometry \endlink</td><td>\code#include <Eigen/Geometry>\endcode</td><td>Transform, Translation, Scaling, Rotation2D and 3D rotations (Quaternion, AngleAxis)</td></tr>
+<tr><td>\link LU_Module LU \endlink</td><td>\code#include <Eigen/LU>\endcode</td><td>Inverse, determinant, LU decompositions with solver (FullPivLU, PartialPivLU)</td></tr>
+<tr><td>\link Cholesky_Module Cholesky \endlink</td><td>\code#include <Eigen/Cholesky>\endcode</td><td>LLT and LDLT Cholesky factorization with solver</td></tr>
+<tr class="alt"><td>\link Householder_Module Householder \endlink</td><td>\code#include <Eigen/Householder>\endcode</td><td>Householder transformations; this module is used by several linear algebra modules</td></tr>
+<tr><td>\link SVD_Module SVD \endlink</td><td>\code#include <Eigen/SVD>\endcode</td><td>SVD decomposition with least-squares solver (JacobiSVD)</td></tr>
+<tr class="alt"><td>\link QR_Module QR \endlink</td><td>\code#include <Eigen/QR>\endcode</td><td>QR decomposition with solver (HouseholderQR, ColPivHouseholderQR, FullPivHouseholderQR)</td></tr>
+<tr><td>\link Eigenvalues_Module Eigenvalues \endlink</td><td>\code#include <Eigen/Eigenvalues>\endcode</td><td>Eigenvalue, eigenvector decompositions (EigenSolver, SelfAdjointEigenSolver, ComplexEigenSolver)</td></tr>
+<tr class="alt"><td>\link Sparse_Module Sparse \endlink</td><td>\code#include <Eigen/Sparse>\endcode</td><td>%Sparse matrix storage and related basic linear algebra (SparseMatrix, DynamicSparseMatrix, SparseVector)</td></tr>
+<tr><td></td><td>\code#include <Eigen/Dense>\endcode</td><td>Includes Core, Geometry, LU, Cholesky, SVD, QR, and Eigenvalues header files</td></tr>
+<tr class="alt"><td></td><td>\code#include <Eigen/Eigen>\endcode</td><td>Includes %Dense and %Sparse header files (the whole Eigen library)</td></tr>
+</table>
+
+<a href="#" class="top">top</a>
+\section QuickRef_Types Array, matrix and vector types
+
+
+\b Recall: Eigen provides two kinds of dense objects: mathematical matrices and vectors which are both represented by the template class Matrix, and general 1D and 2D arrays represented by the template class Array:
+\code
+typedef Matrix<Scalar, RowsAtCompileTime, ColsAtCompileTime, Options> MyMatrixType;
+typedef Array<Scalar, RowsAtCompileTime, ColsAtCompileTime, Options> MyArrayType;
+\endcode
+
+\li \c Scalar is the scalar type of the coefficients (e.g., \c float, \c double, \c bool, \c int, etc.).
+\li \c RowsAtCompileTime and \c ColsAtCompileTime are the number of rows and columns of the matrix as known at compile-time or \c Dynamic.
+\li \c Options can be \c ColMajor or \c RowMajor, default is \c ColMajor. (see class Matrix for more options)
+
+All combinations are allowed: you can have a matrix with a fixed number of rows and a dynamic number of columns, etc. The following are all valid:
+\code
+Matrix<double, 6, Dynamic> // Dynamic number of columns (heap allocation)
+Matrix<double, Dynamic, 2> // Dynamic number of rows (heap allocation)
+Matrix<double, Dynamic, Dynamic, RowMajor> // Fully dynamic, row major (heap allocation)
+Matrix<double, 13, 3> // Fully fixed (static allocation)
+\endcode
+
+In most cases, you can simply use one of the convenience typedefs for \ref matrixtypedefs "matrices" and \ref arraytypedefs "arrays". Some examples:
+<table class="example">
+<tr><th>Matrices</th><th>Arrays</th></tr>
+<tr><td>\code
+Matrix<float,Dynamic,Dynamic> <=> MatrixXf
+Matrix<double,Dynamic,1> <=> VectorXd
+Matrix<int,1,Dynamic> <=> RowVectorXi
+Matrix<float,3,3> <=> Matrix3f
+Matrix<float,4,1> <=> Vector4f
+\endcode</td><td>\code
+Array<float,Dynamic,Dynamic> <=> ArrayXXf
+Array<double,Dynamic,1> <=> ArrayXd
+Array<int,1,Dynamic> <=> RowArrayXi
+Array<float,3,3> <=> Array33f
+Array<float,4,1> <=> Array4f
+\endcode</td></tr>
+</table>
+
+Conversion between the matrix and array worlds:
+\code
+Array44f a1, a1;
+Matrix4f m1, m2;
+m1 = a1 * a2; // coeffwise product, implicit conversion from array to matrix.
+a1 = m1 * m2; // matrix product, implicit conversion from matrix to array.
+a2 = a1 + m1.array(); // mixing array and matrix is forbidden
+m2 = a1.matrix() + m1; // and explicit conversion is required.
+ArrayWrapper<Matrix4f> m1a(m1); // m1a is an alias for m1.array(), they share the same coefficients
+MatrixWrapper<Array44f> a1m(a1);
+\endcode
+
+In the rest of this document we will use the following symbols to emphasize the features which are specifics to a given kind of object:
+\li <a name="matrixonly"><a/>\matrixworld linear algebra matrix and vector only
+\li <a name="arrayonly"><a/>\arrayworld array objects only
+
+\subsection QuickRef_Basics Basic matrix manipulation
+
+<table class="manual">
+<tr><th></th><th>1D objects</th><th>2D objects</th><th>Notes</th></tr>
+<tr><td>Constructors</td>
+<td>\code
+Vector4d v4;
+Vector2f v1(x, y);
+Array3i v2(x, y, z);
+Vector4d v3(x, y, z, w);
+
+VectorXf v5; // empty object
+ArrayXf v6(size);
+\endcode</td><td>\code
+Matrix4f m1;
+
+
+
+
+MatrixXf m5; // empty object
+MatrixXf m6(nb_rows, nb_columns);
+\endcode</td><td class="note">
+By default, the coefficients \n are left uninitialized</td></tr>
+<tr class="alt"><td>Comma initializer</td>
+<td>\code
+Vector3f v1; v1 << x, y, z;
+ArrayXf v2(4); v2 << 1, 2, 3, 4;
+
+\endcode</td><td>\code
+Matrix3f m1; m1 << 1, 2, 3,
+ 4, 5, 6,
+ 7, 8, 9;
+\endcode</td><td></td></tr>
+
+<tr><td>Comma initializer (bis)</td>
+<td colspan="2">
+\include Tutorial_commainit_02.cpp
+</td>
+<td>
+output:
+\verbinclude Tutorial_commainit_02.out
+</td>
+</tr>
+
+<tr class="alt"><td>Runtime info</td>
+<td>\code
+vector.size();
+
+vector.innerStride();
+vector.data();
+\endcode</td><td>\code
+matrix.rows(); matrix.cols();
+matrix.innerSize(); matrix.outerSize();
+matrix.innerStride(); matrix.outerStride();
+matrix.data();
+\endcode</td><td class="note">Inner/Outer* are storage order dependent</td></tr>
+<tr><td>Compile-time info</td>
+<td colspan="2">\code
+ObjectType::Scalar ObjectType::RowsAtCompileTime
+ObjectType::RealScalar ObjectType::ColsAtCompileTime
+ObjectType::Index ObjectType::SizeAtCompileTime
+\endcode</td><td></td></tr>
+<tr class="alt"><td>Resizing</td>
+<td>\code
+vector.resize(size);
+
+
+vector.resizeLike(other_vector);
+vector.conservativeResize(size);
+\endcode</td><td>\code
+matrix.resize(nb_rows, nb_cols);
+matrix.resize(Eigen::NoChange, nb_cols);
+matrix.resize(nb_rows, Eigen::NoChange);
+matrix.resizeLike(other_matrix);
+matrix.conservativeResize(nb_rows, nb_cols);
+\endcode</td><td class="note">no-op if the new sizes match,<br/>otherwise data are lost<br/><br/>resizing with data preservation</td></tr>
+
+<tr><td>Coeff access with \n range checking</td>
+<td>\code
+vector(i) vector.x()
+vector[i] vector.y()
+ vector.z()
+ vector.w()
+\endcode</td><td>\code
+matrix(i,j)
+\endcode</td><td class="note">Range checking is disabled if \n NDEBUG or EIGEN_NO_DEBUG is defined</td></tr>
+
+<tr class="alt"><td>Coeff access without \n range checking</td>
+<td>\code
+vector.coeff(i)
+vector.coeffRef(i)
+\endcode</td><td>\code
+matrix.coeff(i,j)
+matrix.coeffRef(i,j)
+\endcode</td><td></td></tr>
+
+<tr><td>Assignment/copy</td>
+<td colspan="2">\code
+object = expression;
+object_of_float = expression_of_double.cast<float>();
+\endcode</td><td class="note">the destination is automatically resized (if possible)</td></tr>
+
+</table>
+
+\subsection QuickRef_PredefMat Predefined Matrices
+
+<table class="manual">
+<tr>
+ <th>Fixed-size matrix or vector</th>
+ <th>Dynamic-size matrix</th>
+ <th>Dynamic-size vector</th>
+</tr>
+<tr style="border-bottom-style: none;">
+ <td>
+\code
+typedef {Matrix3f|Array33f} FixedXD;
+FixedXD x;
+
+x = FixedXD::Zero();
+x = FixedXD::Ones();
+x = FixedXD::Constant(value);
+x = FixedXD::Random();
+x = FixedXD::LinSpaced(size, low, high);
+
+x.setZero();
+x.setOnes();
+x.setConstant(value);
+x.setRandom();
+x.setLinSpaced(size, low, high);
+\endcode
+ </td>
+ <td>
+\code
+typedef {MatrixXf|ArrayXXf} Dynamic2D;
+Dynamic2D x;
+
+x = Dynamic2D::Zero(rows, cols);
+x = Dynamic2D::Ones(rows, cols);
+x = Dynamic2D::Constant(rows, cols, value);
+x = Dynamic2D::Random(rows, cols);
+N/A
+
+x.setZero(rows, cols);
+x.setOnes(rows, cols);
+x.setConstant(rows, cols, value);
+x.setRandom(rows, cols);
+N/A
+\endcode
+ </td>
+ <td>
+\code
+typedef {VectorXf|ArrayXf} Dynamic1D;
+Dynamic1D x;
+
+x = Dynamic1D::Zero(size);
+x = Dynamic1D::Ones(size);
+x = Dynamic1D::Constant(size, value);
+x = Dynamic1D::Random(size);
+x = Dynamic1D::LinSpaced(size, low, high);
+
+x.setZero(size);
+x.setOnes(size);
+x.setConstant(size, value);
+x.setRandom(size);
+x.setLinSpaced(size, low, high);
+\endcode
+ </td>
+</tr>
+
+<tr><td colspan="3">Identity and \link MatrixBase::Unit basis vectors \endlink \matrixworld</td></tr>
+<tr style="border-bottom-style: none;">
+ <td>
+\code
+x = FixedXD::Identity();
+x.setIdentity();
+
+Vector3f::UnitX() // 1 0 0
+Vector3f::UnitY() // 0 1 0
+Vector3f::UnitZ() // 0 0 1
+\endcode
+ </td>
+ <td>
+\code
+x = Dynamic2D::Identity(rows, cols);
+x.setIdentity(rows, cols);
+
+
+
+N/A
+\endcode
+ </td>
+ <td>\code
+N/A
+
+
+VectorXf::Unit(size,i)
+VectorXf::Unit(4,1) == Vector4f(0,1,0,0)
+ == Vector4f::UnitY()
+\endcode
+ </td>
+</tr>
+</table>
+
+
+
+\subsection QuickRef_Map Mapping external arrays
+
+<table class="manual">
+<tr>
+<td>Contiguous \n memory</td>
+<td>\code
+float data[] = {1,2,3,4};
+Map<Vector3f> v1(data); // uses v1 as a Vector3f object
+Map<ArrayXf> v2(data,3); // uses v2 as a ArrayXf object
+Map<Array22f> m1(data); // uses m1 as a Array22f object
+Map<MatrixXf> m2(data,2,2); // uses m2 as a MatrixXf object
+\endcode</td>
+</tr>
+<tr>
+<td>Typical usage \n of strides</td>
+<td>\code
+float data[] = {1,2,3,4,5,6,7,8,9};
+Map<VectorXf,0,InnerStride<2> > v1(data,3); // = [1,3,5]
+Map<VectorXf,0,InnerStride<> > v2(data,3,InnerStride<>(3)); // = [1,4,7]
+Map<MatrixXf,0,OuterStride<3> > m2(data,2,3); // both lines |1,4,7|
+Map<MatrixXf,0,OuterStride<> > m1(data,2,3,OuterStride<>(3)); // are equal to: |2,5,8|
+\endcode</td>
+</tr>
+</table>
+
+
+<a href="#" class="top">top</a>
+\section QuickRef_ArithmeticOperators Arithmetic Operators
+
+<table class="manual">
+<tr><td>
+add \n subtract</td><td>\code
+mat3 = mat1 + mat2; mat3 += mat1;
+mat3 = mat1 - mat2; mat3 -= mat1;\endcode
+</td></tr>
+<tr class="alt"><td>
+scalar product</td><td>\code
+mat3 = mat1 * s1; mat3 *= s1; mat3 = s1 * mat1;
+mat3 = mat1 / s1; mat3 /= s1;\endcode
+</td></tr>
+<tr><td>
+matrix/vector \n products \matrixworld</td><td>\code
+col2 = mat1 * col1;
+row2 = row1 * mat1; row1 *= mat1;
+mat3 = mat1 * mat2; mat3 *= mat1; \endcode
+</td></tr>
+<tr class="alt"><td>
+transposition \n adjoint \matrixworld</td><td>\code
+mat1 = mat2.transpose(); mat1.transposeInPlace();
+mat1 = mat2.adjoint(); mat1.adjointInPlace();
+\endcode
+</td></tr>
+<tr><td>
+\link MatrixBase::dot() dot \endlink product \n inner product \matrixworld</td><td>\code
+scalar = vec1.dot(vec2);
+scalar = col1.adjoint() * col2;
+scalar = (col1.adjoint() * col2).value();\endcode
+</td></tr>
+<tr class="alt"><td>
+outer product \matrixworld</td><td>\code
+mat = col1 * col2.transpose();\endcode
+</td></tr>
+
+<tr><td>
+\link MatrixBase::norm() norm \endlink \n \link MatrixBase::normalized() normalization \endlink \matrixworld</td><td>\code
+scalar = vec1.norm(); scalar = vec1.squaredNorm()
+vec2 = vec1.normalized(); vec1.normalize(); // inplace \endcode
+</td></tr>
+
+<tr class="alt"><td>
+\link MatrixBase::cross() cross product \endlink \matrixworld</td><td>\code
+#include <Eigen/Geometry>
+vec3 = vec1.cross(vec2);\endcode</td></tr>
+</table>
+
+<a href="#" class="top">top</a>
+\section QuickRef_Coeffwise Coefficient-wise \& Array operators
+Coefficient-wise operators for matrices and vectors:
+<table class="manual">
+<tr><th>Matrix API \matrixworld</th><th>Via Array conversions</th></tr>
+<tr><td>\code
+mat1.cwiseMin(mat2)
+mat1.cwiseMax(mat2)
+mat1.cwiseAbs2()
+mat1.cwiseAbs()
+mat1.cwiseSqrt()
+mat1.cwiseProduct(mat2)
+mat1.cwiseQuotient(mat2)\endcode
+</td><td>\code
+mat1.array().min(mat2.array())
+mat1.array().max(mat2.array())
+mat1.array().abs2()
+mat1.array().abs()
+mat1.array().sqrt()
+mat1.array() * mat2.array()
+mat1.array() / mat2.array()
+\endcode</td></tr>
+</table>
+
+It is also very simple to apply any user defined function \c foo using DenseBase::unaryExpr together with std::ptr_fun:
+\code mat1.unaryExpr(std::ptr_fun(foo))\endcode
+
+Array operators:\arrayworld
+
+<table class="manual">
+<tr><td>Arithmetic operators</td><td>\code
+array1 * array2 array1 / array2 array1 *= array2 array1 /= array2
+array1 + scalar array1 - scalar array1 += scalar array1 -= scalar
+\endcode</td></tr>
+<tr><td>Comparisons</td><td>\code
+array1 < array2 array1 > array2 array1 < scalar array1 > scalar
+array1 <= array2 array1 >= array2 array1 <= scalar array1 >= scalar
+array1 == array2 array1 != array2 array1 == scalar array1 != scalar
+\endcode</td></tr>
+<tr><td>Trigo, power, and \n misc functions \n and the STL variants</td><td>\code
+array1.min(array2)
+array1.max(array2)
+array1.abs2()
+array1.abs() std::abs(array1)
+array1.sqrt() std::sqrt(array1)
+array1.log() std::log(array1)
+array1.exp() std::exp(array1)
+array1.pow(exponent) std::pow(array1,exponent)
+array1.square()
+array1.cube()
+array1.inverse()
+array1.sin() std::sin(array1)
+array1.cos() std::cos(array1)
+array1.tan() std::tan(array1)
+array1.asin() std::asin(array1)
+array1.acos() std::acos(array1)
+\endcode
+</td></tr>
+</table>
+
+<a href="#" class="top">top</a>
+\section QuickRef_Reductions Reductions
+
+Eigen provides several reduction methods such as:
+\link DenseBase::minCoeff() minCoeff() \endlink, \link DenseBase::maxCoeff() maxCoeff() \endlink,
+\link DenseBase::sum() sum() \endlink, \link DenseBase::prod() prod() \endlink,
+\link MatrixBase::trace() trace() \endlink \matrixworld,
+\link MatrixBase::norm() norm() \endlink \matrixworld, \link MatrixBase::squaredNorm() squaredNorm() \endlink \matrixworld,
+\link DenseBase::all() all() \endlink, and \link DenseBase::any() any() \endlink.
+All reduction operations can be done matrix-wise,
+\link DenseBase::colwise() column-wise \endlink or
+\link DenseBase::rowwise() row-wise \endlink. Usage example:
+<table class="manual">
+<tr><td rowspan="3" style="border-right-style:dashed;vertical-align:middle">\code
+ 5 3 1
+mat = 2 7 8
+ 9 4 6 \endcode
+</td> <td>\code mat.minCoeff(); \endcode</td><td>\code 1 \endcode</td></tr>
+<tr class="alt"><td>\code mat.colwise().minCoeff(); \endcode</td><td>\code 2 3 1 \endcode</td></tr>
+<tr style="vertical-align:middle"><td>\code mat.rowwise().minCoeff(); \endcode</td><td>\code
+1
+2
+4
+\endcode</td></tr>
+</table>
+
+Special versions of \link DenseBase::minCoeff(Index*,Index*) minCoeff \endlink and \link DenseBase::maxCoeff(Index*,Index*) maxCoeff \endlink:
+\code
+int i, j;
+s = vector.minCoeff(&i); // s == vector[i]
+s = matrix.maxCoeff(&i, &j); // s == matrix(i,j)
+\endcode
+Typical use cases of all() and any():
+\code
+if((array1 > 0).all()) ... // if all coefficients of array1 are greater than 0 ...
+if((array1 < array2).any()) ... // if there exist a pair i,j such that array1(i,j) < array2(i,j) ...
+\endcode
+
+
+<a href="#" class="top">top</a>\section QuickRef_Blocks Sub-matrices
+
+Read-write access to a \link DenseBase::col(Index) column \endlink
+or a \link DenseBase::row(Index) row \endlink of a matrix (or array):
+\code
+mat1.row(i) = mat2.col(j);
+mat1.col(j1).swap(mat1.col(j2));
+\endcode
+
+Read-write access to sub-vectors:
+<table class="manual">
+<tr>
+<th>Default versions</th>
+<th>Optimized versions when the size \n is known at compile time</th></tr>
+<th></th>
+
+<tr><td>\code vec1.head(n)\endcode</td><td>\code vec1.head<n>()\endcode</td><td>the first \c n coeffs </td></tr>
+<tr><td>\code vec1.tail(n)\endcode</td><td>\code vec1.tail<n>()\endcode</td><td>the last \c n coeffs </td></tr>
+<tr><td>\code vec1.segment(pos,n)\endcode</td><td>\code vec1.segment<n>(pos)\endcode</td>
+ <td>the \c n coeffs in \n the range [\c pos : \c pos + \c n [</td></tr>
+<tr class="alt"><td colspan="3">
+
+Read-write access to sub-matrices:</td></tr>
+<tr>
+ <td>\code mat1.block(i,j,rows,cols)\endcode
+ \link DenseBase::block(Index,Index,Index,Index) (more) \endlink</td>
+ <td>\code mat1.block<rows,cols>(i,j)\endcode
+ \link DenseBase::block(Index,Index) (more) \endlink</td>
+ <td>the \c rows x \c cols sub-matrix \n starting from position (\c i,\c j)</td></tr>
+<tr><td>\code
+ mat1.topLeftCorner(rows,cols)
+ mat1.topRightCorner(rows,cols)
+ mat1.bottomLeftCorner(rows,cols)
+ mat1.bottomRightCorner(rows,cols)\endcode
+ <td>\code
+ mat1.topLeftCorner<rows,cols>()
+ mat1.topRightCorner<rows,cols>()
+ mat1.bottomLeftCorner<rows,cols>()
+ mat1.bottomRightCorner<rows,cols>()\endcode
+ <td>the \c rows x \c cols sub-matrix \n taken in one of the four corners</td></tr>
+ <tr><td>\code
+ mat1.topRows(rows)
+ mat1.bottomRows(rows)
+ mat1.leftCols(cols)
+ mat1.rightCols(cols)\endcode
+ <td>\code
+ mat1.topRows<rows>()
+ mat1.bottomRows<rows>()
+ mat1.leftCols<cols>()
+ mat1.rightCols<cols>()\endcode
+ <td>specialized versions of block() \n when the block fit two corners</td></tr>
+</table>
+
+
+
+<a href="#" class="top">top</a>\section QuickRef_Misc Miscellaneous operations
+
+\subsection QuickRef_Reverse Reverse
+Vectors, rows, and/or columns of a matrix can be reversed (see DenseBase::reverse(), DenseBase::reverseInPlace(), VectorwiseOp::reverse()).
+\code
+vec.reverse() mat.colwise().reverse() mat.rowwise().reverse()
+vec.reverseInPlace()
+\endcode
+
+\subsection QuickRef_Replicate Replicate
+Vectors, matrices, rows, and/or columns can be replicated in any direction (see DenseBase::replicate(), VectorwiseOp::replicate())
+\code
+vec.replicate(times) vec.replicate<Times>
+mat.replicate(vertical_times, horizontal_times) mat.replicate<VerticalTimes, HorizontalTimes>()
+mat.colwise().replicate(vertical_times, horizontal_times) mat.colwise().replicate<VerticalTimes, HorizontalTimes>()
+mat.rowwise().replicate(vertical_times, horizontal_times) mat.rowwise().replicate<VerticalTimes, HorizontalTimes>()
+\endcode
+
+
+<a href="#" class="top">top</a>\section QuickRef_DiagTriSymm Diagonal, Triangular, and Self-adjoint matrices
+(matrix world \matrixworld)
+
+\subsection QuickRef_Diagonal Diagonal matrices
+
+<table class="example">
+<tr><th>Operation</th><th>Code</th></tr>
+<tr><td>
+view a vector \link MatrixBase::asDiagonal() as a diagonal matrix \endlink \n </td><td>\code
+mat1 = vec1.asDiagonal();\endcode
+</td></tr>
+<tr><td>
+Declare a diagonal matrix</td><td>\code
+DiagonalMatrix<Scalar,SizeAtCompileTime> diag1(size);
+diag1.diagonal() = vector;\endcode
+</td></tr>
+<tr><td>Access the \link MatrixBase::diagonal() diagonal \endlink and \link MatrixBase::diagonal(Index) super/sub diagonals \endlink of a matrix as a vector (read/write)</td>
+ <td>\code
+vec1 = mat1.diagonal(); mat1.diagonal() = vec1; // main diagonal
+vec1 = mat1.diagonal(+n); mat1.diagonal(+n) = vec1; // n-th super diagonal
+vec1 = mat1.diagonal(-n); mat1.diagonal(-n) = vec1; // n-th sub diagonal
+vec1 = mat1.diagonal<1>(); mat1.diagonal<1>() = vec1; // first super diagonal
+vec1 = mat1.diagonal<-2>(); mat1.diagonal<-2>() = vec1; // second sub diagonal
+\endcode</td>
+</tr>
+
+<tr><td>Optimized products and inverse</td>
+ <td>\code
+mat3 = scalar * diag1 * mat1;
+mat3 += scalar * mat1 * vec1.asDiagonal();
+mat3 = vec1.asDiagonal().inverse() * mat1
+mat3 = mat1 * diag1.inverse()
+\endcode</td>
+</tr>
+
+</table>
+
+\subsection QuickRef_TriangularView Triangular views
+
+TriangularView gives a view on a triangular part of a dense matrix and allows to perform optimized operations on it. The opposite triangular part is never referenced and can be used to store other information.
+
+\note The .triangularView() template member function requires the \c template keyword if it is used on an
+object of a type that depends on a template parameter; see \ref TopicTemplateKeyword for details.
+
+<table class="example">
+<tr><th>Operation</th><th>Code</th></tr>
+<tr><td>
+Reference to a triangular with optional \n
+unit or null diagonal (read/write):
+</td><td>\code
+m.triangularView<Xxx>()
+\endcode \n
+\c Xxx = ::Upper, ::Lower, ::StrictlyUpper, ::StrictlyLower, ::UnitUpper, ::UnitLower
+</td></tr>
+<tr><td>
+Writing to a specific triangular part:\n (only the referenced triangular part is evaluated)
+</td><td>\code
+m1.triangularView<Eigen::Lower>() = m2 + m3 \endcode
+</td></tr>
+<tr><td>
+Conversion to a dense matrix setting the opposite triangular part to zero:
+</td><td>\code
+m2 = m1.triangularView<Eigen::UnitUpper>()\endcode
+</td></tr>
+<tr><td>
+Products:
+</td><td>\code
+m3 += s1 * m1.adjoint().triangularView<Eigen::UnitUpper>() * m2
+m3 -= s1 * m2.conjugate() * m1.adjoint().triangularView<Eigen::Lower>() \endcode
+</td></tr>
+<tr><td>
+Solving linear equations:\n
+\f$ M_2 := L_1^{-1} M_2 \f$ \n
+\f$ M_3 := {L_1^*}^{-1} M_3 \f$ \n
+\f$ M_4 := M_4 U_1^{-1} \f$
+</td><td>\n \code
+L1.triangularView<Eigen::UnitLower>().solveInPlace(M2)
+L1.triangularView<Eigen::Lower>().adjoint().solveInPlace(M3)
+U1.triangularView<Eigen::Upper>().solveInPlace<OnTheRight>(M4)\endcode
+</td></tr>
+</table>
+
+\subsection QuickRef_SelfadjointMatrix Symmetric/selfadjoint views
+
+Just as for triangular matrix, you can reference any triangular part of a square matrix to see it as a selfadjoint
+matrix and perform special and optimized operations. Again the opposite triangular part is never referenced and can be
+used to store other information.
+
+\note The .selfadjointView() template member function requires the \c template keyword if it is used on an
+object of a type that depends on a template parameter; see \ref TopicTemplateKeyword for details.
+
+<table class="example">
+<tr><th>Operation</th><th>Code</th></tr>
+<tr><td>
+Conversion to a dense matrix:
+</td><td>\code
+m2 = m.selfadjointView<Eigen::Lower>();\endcode
+</td></tr>
+<tr><td>
+Product with another general matrix or vector:
+</td><td>\code
+m3 = s1 * m1.conjugate().selfadjointView<Eigen::Upper>() * m3;
+m3 -= s1 * m3.adjoint() * m1.selfadjointView<Eigen::Lower>();\endcode
+</td></tr>
+<tr><td>
+Rank 1 and rank K update: \n
+\f$ upper(M_1) \mathrel{{+}{=}} s_1 M_2 M_2^* \f$ \n
+\f$ lower(M_1) \mathbin{{-}{=}} M_2^* M_2 \f$
+</td><td>\n \code
+M1.selfadjointView<Eigen::Upper>().rankUpdate(M2,s1);
+M1.selfadjointView<Eigen::Lower>().rankUpdate(M2.adjoint(),-1); \endcode
+</td></tr>
+<tr><td>
+Rank 2 update: (\f$ M \mathrel{{+}{=}} s u v^* + s v u^* \f$)
+</td><td>\code
+M.selfadjointView<Eigen::Upper>().rankUpdate(u,v,s);
+\endcode
+</td></tr>
+<tr><td>
+Solving linear equations:\n(\f$ M_2 := M_1^{-1} M_2 \f$)
+</td><td>\code
+// via a standard Cholesky factorization
+m2 = m1.selfadjointView<Eigen::Upper>().llt().solve(m2);
+// via a Cholesky factorization with pivoting
+m2 = m1.selfadjointView<Eigen::Lower>().ldlt().solve(m2);
+\endcode
+</td></tr>
+</table>
+
+*/
+
+/*
+<table class="tutorial_code">
+<tr><td>
+\link MatrixBase::asDiagonal() make a diagonal matrix \endlink \n from a vector </td><td>\code
+mat1 = vec1.asDiagonal();\endcode
+</td></tr>
+<tr><td>
+Declare a diagonal matrix</td><td>\code
+DiagonalMatrix<Scalar,SizeAtCompileTime> diag1(size);
+diag1.diagonal() = vector;\endcode
+</td></tr>
+<tr><td>Access \link MatrixBase::diagonal() the diagonal and super/sub diagonals of a matrix \endlink as a vector (read/write)</td>
+ <td>\code
+vec1 = mat1.diagonal(); mat1.diagonal() = vec1; // main diagonal
+vec1 = mat1.diagonal(+n); mat1.diagonal(+n) = vec1; // n-th super diagonal
+vec1 = mat1.diagonal(-n); mat1.diagonal(-n) = vec1; // n-th sub diagonal
+vec1 = mat1.diagonal<1>(); mat1.diagonal<1>() = vec1; // first super diagonal
+vec1 = mat1.diagonal<-2>(); mat1.diagonal<-2>() = vec1; // second sub diagonal
+\endcode</td>
+</tr>
+
+<tr><td>View on a triangular part of a matrix (read/write)</td>
+ <td>\code
+mat2 = mat1.triangularView<Xxx>();
+// Xxx = Upper, Lower, StrictlyUpper, StrictlyLower, UnitUpper, UnitLower
+mat1.triangularView<Upper>() = mat2 + mat3; // only the upper part is evaluated and referenced
+\endcode</td></tr>
+
+<tr><td>View a triangular part as a symmetric/self-adjoint matrix (read/write)</td>
+ <td>\code
+mat2 = mat1.selfadjointView<Xxx>(); // Xxx = Upper or Lower
+mat1.selfadjointView<Upper>() = mat2 + mat2.adjoint(); // evaluated and write to the upper triangular part only
+\endcode</td></tr>
+
+</table>
+
+Optimized products:
+\code
+mat3 += scalar * vec1.asDiagonal() * mat1
+mat3 += scalar * mat1 * vec1.asDiagonal()
+mat3.noalias() += scalar * mat1.triangularView<Xxx>() * mat2
+mat3.noalias() += scalar * mat2 * mat1.triangularView<Xxx>()
+mat3.noalias() += scalar * mat1.selfadjointView<Upper or Lower>() * mat2
+mat3.noalias() += scalar * mat2 * mat1.selfadjointView<Upper or Lower>()
+mat1.selfadjointView<Upper or Lower>().rankUpdate(mat2);
+mat1.selfadjointView<Upper or Lower>().rankUpdate(mat2.adjoint(), scalar);
+\endcode
+
+Inverse products: (all are optimized)
+\code
+mat3 = vec1.asDiagonal().inverse() * mat1
+mat3 = mat1 * diag1.inverse()
+mat1.triangularView<Xxx>().solveInPlace(mat2)
+mat1.triangularView<Xxx>().solveInPlace<OnTheRight>(mat2)
+mat2 = mat1.selfadjointView<Upper or Lower>().llt().solve(mat2)
+\endcode
+
+*/
+}
diff --git a/doc/SparseQuickReference.dox b/doc/SparseQuickReference.dox
new file mode 100644
index 000000000..7d6eb0fa9
--- /dev/null
+++ b/doc/SparseQuickReference.dox
@@ -0,0 +1,198 @@
+namespace Eigen {
+/** \page SparseQuickRefPage Quick reference guide for sparse matrices
+
+\b Table \b of \b contents
+ - \ref Constructors
+ - \ref SparseMatrixInsertion
+ - \ref SparseBasicInfos
+ - \ref SparseBasicOps
+ - \ref SparseInterops
+ - \ref sparsepermutation
+ - \ref sparsesubmatrices
+ - \ref sparseselfadjointview
+\n
+
+<hr>
+
+In this page, we give a quick summary of the main operations available for sparse matrices in the class SparseMatrix. First, it is recommended to read first the introductory tutorial at \ref TutorialSparse. The important point to have in mind when working on sparse matrices is how they are stored :
+i.e either row major or column major. The default is column major. Most arithmetic operations on sparse matrices will assert that they have the same storage order. Moreover, when interacting with external libraries that are not yet supported by Eigen, it is important to know how to send the required matrix pointers.
+
+\section Constructors Constructors and assignments
+SparseMatrix is the core class to build and manipulate sparse matrices in Eigen. It takes as template parameters the Scalar type and the storage order, either RowMajor or ColumnMajor. The default is ColumnMajor.
+
+\code
+ SparseMatrix<double> sm1(1000,1000); // 1000x1000 compressed sparse matrix of double.
+ SparseMatrix<std::complex<double>,RowMajor> sm2; // Compressed row major matrix of complex double.
+\endcode
+The copy constructor and assignment can be used to convert matrices from a storage order to another
+\code
+ SparseMatrix<double,Colmajor> sm1;
+ // Eventually fill the matrix sm1 ...
+ SparseMatrix<double,Rowmajor> sm2(sm1), sm3; // Initialize sm2 with sm1.
+ sm3 = sm1; // Assignment and evaluations modify the storage order.
+ \endcode
+
+\section SparseMatrixInsertion Allocating and inserting values
+resize() and reserve() are used to set the size and allocate space for nonzero elements
+ \code
+ sm1.resize(m,n); //Change sm to a mxn matrix.
+ sm1.reserve(nnz); // Allocate room for nnz nonzeros elements.
+ \endcode
+Note that when calling reserve(), it is not required that nnz is the exact number of nonzero elements in the final matrix. However, an exact estimation will avoid multiple reallocations during the insertion phase.
+
+Insertions of values in the sparse matrix can be done directly by looping over nonzero elements and use the insert() function
+\code
+// Direct insertion of the value v_ij;
+ sm1.insert(i, j) = v_ij; // It is assumed that v_ij does not already exist in the matrix.
+\endcode
+
+After insertion, a value at (i,j) can be modified using coeffRef()
+\code
+ // Update the value v_ij
+ sm1.coeffRef(i,j) = v_ij;
+ sm1.coeffRef(i,j) += v_ij;
+ sm1.coeffRef(i,j) -= v_ij;
+ ...
+\endcode
+
+The recommended way to insert values is to build a list of triplets (row, col, val) and then call setFromTriplets().
+\code
+ sm1.setFromTriplets(TripletList.begin(), TripletList.end());
+\endcode
+A complete example is available at \ref TutorialSparseFilling.
+
+The following functions can be used to set constant or random values in the matrix.
+\code
+ sm1.setZero(); // Reset the matrix with zero elements
+ ...
+\endcode
+
+\section SparseBasicInfos Matrix properties
+Beyond the functions rows() and cols() that are used to get the number of rows and columns, there are some useful functions that are available to easily get some informations from the matrix.
+<table class="manual">
+<tr>
+ <td> \code
+ sm1.rows(); // Number of rows
+ sm1.cols(); // Number of columns
+ sm1.nonZeros(); // Number of non zero values
+ sm1.outerSize(); // Number of columns (resp. rows) for a column major (resp. row major )
+ sm1.innerSize(); // Number of rows (resp. columns) for a row major (resp. column major)
+ sm1.norm(); // (Euclidian ??) norm of the matrix
+ sm1.squaredNorm(); //
+ sm1.isVector(); // Check if sm1 is a sparse vector or a sparse matrix
+ ...
+ \endcode </td>
+</tr>
+</table>
+
+\section SparseBasicOps Arithmetic operations
+It is easy to perform arithmetic operations on sparse matrices provided that the dimensions are adequate and that the matrices have the same storage order. Note that the evaluation can always be done in a matrix with a different storage order.
+<table class="manual">
+<tr><th> Operations </th> <th> Code </th> <th> Notes </th></tr>
+
+<tr>
+ <td> add subtract </td>
+ <td> \code
+ sm3 = sm1 + sm2;
+ sm3 = sm1 - sm2;
+ sm2 += sm1;
+ sm2 -= sm1; \endcode
+ </td>
+ <td>
+ sm1 and sm2 should have the same storage order
+ </td>
+</tr>
+
+<tr class="alt"><td>
+ scalar product</td><td>\code
+ sm3 = sm1 * s1; sm3 *= s1;
+ sm3 = s1 * sm1 + s2 * sm2; sm3 /= s1;\endcode
+ </td>
+ <td>
+ Many combinations are possible if the dimensions and the storage order agree.
+</tr>
+
+<tr>
+ <td> Product </td>
+ <td> \code
+ sm3 = sm1 * sm2;
+ dm2 = sm1 * dm1;
+ dv2 = sm1 * dv1;
+ \endcode </td>
+ <td>
+ </td>
+</tr>
+
+<tr class='alt'>
+ <td> transposition, adjoint</td>
+ <td> \code
+ sm2 = sm1.transpose();
+ sm2 = sm1.adjoint();
+ \endcode </td>
+ <td>
+ Note that the transposition change the storage order. There is no support for transposeInPlace().
+ </td>
+</tr>
+
+<tr>
+ <td>
+ Component-wise ops
+ </td>
+ <td>\code
+ sm1.cwiseProduct(sm2);
+ sm1.cwiseQuotient(sm2);
+ sm1.cwiseMin(sm2);
+ sm1.cwiseMax(sm2);
+ sm1.cwiseAbs();
+ sm1.cwiseSqrt();
+ \endcode</td>
+ <td>
+ sm1 and sm2 should have the same storage order
+ </td>
+</tr>
+</table>
+
+
+\section SparseInterops Low-level storage
+There are a set of low-levels functions to get the standard compressed storage pointers. The matrix should be in compressed mode which can be checked by calling isCompressed(); makeCompressed() should do the job otherwise.
+\code
+ // Scalar pointer to the values of the matrix, size nnz
+ sm1.valuePtr();
+ // Index pointer to get the row indices (resp. column indices) for column major (resp. row major) matrix, size nnz
+ sm1.innerIndexPtr();
+ // Index pointer to the beginning of each row (resp. column) in valuePtr() and innerIndexPtr() for column major (row major). The size is outersize()+1;
+ sm1.outerIndexPtr();
+\endcode
+These pointers can therefore be easily used to send the matrix to some external libraries/solvers that are not yet supported by Eigen.
+
+\section sparsepermutation Permutations, submatrices and Selfadjoint Views
+In many cases, it is necessary to reorder the rows and/or the columns of the sparse matrix for several purposes : fill-in reducing during matrix decomposition, better data locality for sparse matrix-vector products... The class PermutationMatrix is available to this end.
+ \code
+ PermutationMatrix<Dynamic, Dynamic, int> perm;
+ // Reserve and fill the values of perm;
+ perm.inverse(n); // Compute eventually the inverse permutation
+ sm1.twistedBy(perm) //Apply the permutation on rows and columns
+ sm2 = sm1 * perm; // ??? Apply the permutation on columns ???;
+ sm2 = perm * sm1; // ??? Apply the permutation on rows ???;
+ \endcode
+
+\section sparsesubmatrices Sub-matrices
+The following functions are useful to extract a block of rows (resp. columns) from a row-major (resp. column major) sparse matrix. Note that because of the particular storage, it is not ?? efficient ?? to extract a submatrix comprising a certain number of subrows and subcolumns.
+ \code
+ sm1.innerVector(outer); // Returns the outer -th column (resp. row) of the matrix if sm is col-major (resp. row-major)
+ sm1.innerVectors(outer); // Returns the outer -th column (resp. row) of the matrix if mat is col-major (resp. row-major)
+ sm1.middleRows(start, numRows); // For row major matrices, get a range of numRows rows
+ sm1.middleCols(start, numCols); // For column major matrices, get a range of numCols cols
+ \endcode
+ Examples :
+
+\section sparseselfadjointview Sparse triangular and selfadjoint Views
+ \code
+ sm2 = sm1.triangularview<Lower>(); // Get the lower triangular part of the matrix.
+ dv2 = sm1.triangularView<Upper>().solve(dv1); // Solve the linear system with the uppper triangular part.
+ sm2 = sm1.selfadjointview<Lower>(); // Build a selfadjoint matrix from the lower part of sm1.
+ \endcode
+
+
+*/
+}
diff --git a/doc/TopicLinearAlgebraDecompositions.dox b/doc/TopicLinearAlgebraDecompositions.dox
new file mode 100644
index 000000000..faa564b93
--- /dev/null
+++ b/doc/TopicLinearAlgebraDecompositions.dox
@@ -0,0 +1,260 @@
+namespace Eigen {
+
+/** \page TopicLinearAlgebraDecompositions Linear algebra and decompositions
+
+
+\section TopicLinAlgBigTable Catalogue of decompositions offered by Eigen
+
+<table class="manual-vl">
+
+ <tr>
+ <th class="meta"></th>
+ <th class="meta" colspan="5">Generic information, not Eigen-specific</th>
+ <th class="meta" colspan="3">Eigen-specific</th>
+ </tr>
+
+ <tr>
+ <th>Decomposition</th>
+ <th>Requirements on the matrix</th>
+ <th>Speed</th>
+ <th>Algorithm reliability and accuracy</th>
+ <th>Rank-revealing</th>
+ <th>Allows to compute (besides linear solving)</th>
+ <th>Linear solver provided by Eigen</th>
+ <th>Maturity of Eigen's implementation</th>
+ <th>Optimizations</th>
+ </tr>
+
+ <tr>
+ <td>PartialPivLU</td>
+ <td>Invertible</td>
+ <td>Fast</td>
+ <td>Depends on condition number</td>
+ <td>-</td>
+ <td>-</td>
+ <td>Yes</td>
+ <td>Excellent</td>
+ <td>Blocking, Implicit MT</td>
+ </tr>
+
+ <tr class="alt">
+ <td>FullPivLU</td>
+ <td>-</td>
+ <td>Slow</td>
+ <td>Proven</td>
+ <td>Yes</td>
+ <td>-</td>
+ <td>Yes</td>
+ <td>Excellent</td>
+ <td>-</td>
+ </tr>
+
+ <tr>
+ <td>HouseholderQR</td>
+ <td>-</td>
+ <td>Fast</td>
+ <td>Depends on condition number</td>
+ <td>-</td>
+ <td>Orthogonalization</td>
+ <td>Yes</td>
+ <td>Excellent</td>
+ <td>Blocking</td>
+ </tr>
+
+ <tr class="alt">
+ <td>ColPivHouseholderQR</td>
+ <td>-</td>
+ <td>Fast</td>
+ <td>Good</td>
+ <td>Yes</td>
+ <td>Orthogonalization</td>
+ <td>Yes</td>
+ <td>Excellent</td>
+ <td><em>Soon: blocking</em></td>
+ </tr>
+
+ <tr>
+ <td>FullPivHouseholderQR</td>
+ <td>-</td>
+ <td>Slow</td>
+ <td>Proven</td>
+ <td>Yes</td>
+ <td>Orthogonalization</td>
+ <td>Yes</td>
+ <td>Average</td>
+ <td>-</td>
+ </tr>
+
+ <tr class="alt">
+ <td>LLT</td>
+ <td>Positive definite</td>
+ <td>Very fast</td>
+ <td>Depends on condition number</td>
+ <td>-</td>
+ <td>-</td>
+ <td>Yes</td>
+ <td>Excellent</td>
+ <td>Blocking</td>
+ </tr>
+
+ <tr>
+ <td>LDLT</td>
+ <td>Positive or negative semidefinite<sup><a href="#note1">1</a></sup></td>
+ <td>Very fast</td>
+ <td>Good</td>
+ <td>-</td>
+ <td>-</td>
+ <td>Yes</td>
+ <td>Excellent</td>
+ <td><em>Soon: blocking</em></td>
+ </tr>
+
+ <tr><th class="inter" colspan="9">\n Singular values and eigenvalues decompositions</th></tr>
+
+ <tr>
+ <td>JacobiSVD (two-sided)</td>
+ <td>-</td>
+ <td>Slow (but fast for small matrices)</td>
+ <td>Excellent-Proven<sup><a href="#note3">3</a></sup></td>
+ <td>Yes</td>
+ <td>Singular values/vectors, least squares</td>
+ <td>Yes (and does least squares)</td>
+ <td>Excellent</td>
+ <td>R-SVD</td>
+ </tr>
+
+ <tr class="alt">
+ <td>SelfAdjointEigenSolver</td>
+ <td>Self-adjoint</td>
+ <td>Fast-average<sup><a href="#note2">2</a></sup></td>
+ <td>Good</td>
+ <td>Yes</td>
+ <td>Eigenvalues/vectors</td>
+ <td>-</td>
+ <td>Good</td>
+ <td><em>Closed forms for 2x2 and 3x3</em></td>
+ </tr>
+
+ <tr>
+ <td>ComplexEigenSolver</td>
+ <td>Square</td>
+ <td>Slow-very slow<sup><a href="#note2">2</a></sup></td>
+ <td>Depends on condition number</td>
+ <td>Yes</td>
+ <td>Eigenvalues/vectors</td>
+ <td>-</td>
+ <td>Average</td>
+ <td>-</td>
+ </tr>
+
+ <tr class="alt">
+ <td>EigenSolver</td>
+ <td>Square and real</td>
+ <td>Average-slow<sup><a href="#note2">2</a></sup></td>
+ <td>Depends on condition number</td>
+ <td>Yes</td>
+ <td>Eigenvalues/vectors</td>
+ <td>-</td>
+ <td>Average</td>
+ <td>-</td>
+ </tr>
+
+ <tr>
+ <td>GeneralizedSelfAdjointEigenSolver</td>
+ <td>Square</td>
+ <td>Fast-average<sup><a href="#note2">2</a></sup></td>
+ <td>Depends on condition number</td>
+ <td>-</td>
+ <td>Generalized eigenvalues/vectors</td>
+ <td>-</td>
+ <td>Good</td>
+ <td>-</td>
+ </tr>
+
+ <tr><th class="inter" colspan="9">\n Helper decompositions</th></tr>
+
+ <tr>
+ <td>RealSchur</td>
+ <td>Square and real</td>
+ <td>Average-slow<sup><a href="#note2">2</a></sup></td>
+ <td>Depends on condition number</td>
+ <td>Yes</td>
+ <td>-</td>
+ <td>-</td>
+ <td>Average</td>
+ <td>-</td>
+ </tr>
+
+ <tr class="alt">
+ <td>ComplexSchur</td>
+ <td>Square</td>
+ <td>Slow-very slow<sup><a href="#note2">2</a></sup></td>
+ <td>Depends on condition number</td>
+ <td>Yes</td>
+ <td>-</td>
+ <td>-</td>
+ <td>Average</td>
+ <td>-</td>
+ </tr>
+
+ <tr class="alt">
+ <td>Tridiagonalization</td>
+ <td>Self-adjoint</td>
+ <td>Fast</td>
+ <td>Good</td>
+ <td>-</td>
+ <td>-</td>
+ <td>-</td>
+ <td>Good</td>
+ <td><em>Soon: blocking</em></td>
+ </tr>
+
+ <tr>
+ <td>HessenbergDecomposition</td>
+ <td>Square</td>
+ <td>Average</td>
+ <td>Good</td>
+ <td>-</td>
+ <td>-</td>
+ <td>-</td>
+ <td>Good</td>
+ <td><em>Soon: blocking</em></td>
+ </tr>
+
+</table>
+
+\b Notes:
+<ul>
+<li><a name="note1">\b 1: </a>There exist two variants of the LDLT algorithm. Eigen's one produces a pure diagonal D matrix, and therefore it cannot handle indefinite matrices, unlike Lapack's one which produces a block diagonal D matrix.</li>
+<li><a name="note2">\b 2: </a>Eigenvalues, SVD and Schur decompositions rely on iterative algorithms. Their convergence speed depends on how well the eigenvalues are separated.</li>
+<li><a name="note3">\b 3: </a>Our JacobiSVD is two-sided, making for proven and optimal precision for square matrices. For non-square matrices, we have to use a QR preconditioner first. The default choice, ColPivHouseholderQR, is already very reliable, but if you want it to be proven, use FullPivHouseholderQR instead.
+</ul>
+
+\section TopicLinAlgTerminology Terminology
+
+<dl>
+ <dt><b>Selfadjoint</b></dt>
+ <dd>For a real matrix, selfadjoint is a synonym for symmetric. For a complex matrix, selfadjoint is a synonym for \em hermitian.
+ More generally, a matrix \f$ A \f$ is selfadjoint if and only if it is equal to its adjoint \f$ A^* \f$. The adjoint is also called the \em conjugate \em transpose. </dd>
+ <dt><b>Positive/negative definite</b></dt>
+ <dd>A selfadjoint matrix \f$ A \f$ is positive definite if \f$ v^* A v > 0 \f$ for any non zero vector \f$ v \f$.
+ In the same vein, it is negative definite if \f$ v^* A v < 0 \f$ for any non zero vector \f$ v \f$ </dd>
+ <dt><b>Positive/negative semidefinite</b></dt>
+ <dd>A selfadjoint matrix \f$ A \f$ is positive semi-definite if \f$ v^* A v \ge 0 \f$ for any non zero vector \f$ v \f$.
+ In the same vein, it is negative semi-definite if \f$ v^* A v \le 0 \f$ for any non zero vector \f$ v \f$ </dd>
+
+ <dt><b>Blocking</b></dt>
+ <dd>Means the algorithm can work per block, whence guaranteeing a good scaling of the performance for large matrices.</dd>
+ <dt><b>Implicit Multi Threading (MT)</b></dt>
+ <dd>Means the algorithm can take advantage of multicore processors via OpenMP. "Implicit" means the algortihm itself is not parallelized, but that it relies on parallelized matrix-matrix product rountines.</dd>
+ <dt><b>Explicit Multi Threading (MT)</b></dt>
+ <dd>Means the algorithm is explicitely parallelized to take advantage of multicore processors via OpenMP.</dd>
+ <dt><b>Meta-unroller</b></dt>
+ <dd>Means the algorithm is automatically and explicitly unrolled for very small fixed size matrices.</dd>
+ <dt><b></b></dt>
+ <dd></dd>
+</dl>
+
+*/
+
+}
diff --git a/doc/TopicMultithreading.dox b/doc/TopicMultithreading.dox
new file mode 100644
index 000000000..f7d082668
--- /dev/null
+++ b/doc/TopicMultithreading.dox
@@ -0,0 +1,46 @@
+namespace Eigen {
+
+/** \page TopicMultiThreading Eigen and multi-threading
+
+\section TopicMultiThreading_MakingEigenMT Make Eigen run in parallel
+
+Some Eigen's algorithms can exploit the multiple cores present in your hardware. To this end, it is enough to enable OpenMP on your compiler, for instance:
+ * GCC: \c -fopenmp
+ * ICC: \c -openmp
+ * MSVC: check the respective option in the build properties.
+You can control the number of thread that will be used using either the OpenMP API or Eiegn's API using the following priority:
+\code
+ OMP_NUM_THREADS=n ./my_program
+ omp_set_num_threads(n);
+ Eigen::setNbThreads(n);
+\endcode
+Unless setNbThreads has been called, Eigen uses the number of threads specified by OpenMP. You can restore this bahavior by calling \code setNbThreads(0); \endcode
+You can query the number of threads that will be used with:
+\code
+n = Eigen::nbThreads(n);
+\endcode
+You can disable Eigen's multi threading at compile time by defining the EIGEN_DONT_PARALLELIZE preprocessor token.
+
+Currently, the following algorithms can make use of multi-threading:
+ * general matrix - matrix products
+ * PartialPivLU
+
+\section TopicMultiThreading_UsingEigenWithMT Using Eigen in a multi-threaded application
+
+In the case your own application is multithreaded, and multiple threads make calls to Eigen, then you have to initialize Eigen by calling the following routine \b before creating the threads:
+\code
+#include <Eigen/Core>
+
+int main(int argc, char** argv)
+{
+ Eigen::initParallel();
+
+ ...
+}
+\endcode
+
+In the case your application is parallelized with OpenMP, you might want to disable Eigen's own parallization as detailed in the previous section.
+
+*/
+
+}
diff --git a/doc/TutorialSparse_example_details.dox b/doc/TutorialSparse_example_details.dox
new file mode 100644
index 000000000..0438da8bb
--- /dev/null
+++ b/doc/TutorialSparse_example_details.dox
@@ -0,0 +1,4 @@
+/**
+\page TutorialSparse_example_details
+\include Tutorial_sparse_example_details.cpp
+*/
diff --git a/doc/UsingIntelMKL.dox b/doc/UsingIntelMKL.dox
new file mode 100644
index 000000000..379ee3ffd
--- /dev/null
+++ b/doc/UsingIntelMKL.dox
@@ -0,0 +1,168 @@
+/*
+ Copyright (c) 2011, Intel Corporation. All rights reserved.
+ Copyright (C) 2011 Gael Guennebaud <gael.guennebaud@inria.fr>
+
+ 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 : Documentation on the use of Intel MKL through Eigen
+ ********************************************************************************
+*/
+
+namespace Eigen {
+
+/** \page TopicUsingIntelMKL Using Intel® Math Kernel Library from Eigen
+
+\section TopicUsingIntelMKL_Intro Eigen and Intel® Math Kernel Library (Intel® MKL)
+
+Since Eigen version 3.1 and later, users can benefit from built-in Intel MKL optimizations with an installed copy of Intel MKL 10.3 (or later).
+<a href="http://eigen.tuxfamily.org/Counter/redirect_to_mkl.php"> Intel MKL </a> provides highly optimized multi-threaded mathematical routines for x86-compatible architectures.
+Intel MKL is available on Linux, Mac and Windows for both Intel64 and IA32 architectures.
+
+\warning Be aware that Intel® MKL is a proprietary software. It is the responsibility of the users to buy MKL licenses for their products. Moreover, the license of the user product has to allow linking to proprietary software that excludes any unmodified versions of the GPL. As a consequence, this also means that Eigen has to be used through the LGPL3+ license.
+
+Using Intel MKL through Eigen is easy:
+-# define the \c EIGEN_USE_MKL_ALL macro before including any Eigen's header
+-# link your program to MKL libraries (see the <a href="http://software.intel.com/en-us/articles/intel-mkl-link-line-advisor/">MKL linking advisor</a>)
+-# on a 64bits system, you must use the LP64 interface (not the ILP64 one)
+
+When doing so, a number of Eigen's algorithms are silently substituted with calls to Intel MKL routines.
+These substitutions apply only for \b Dynamic \b or \b large enough objects with one of the following four standard scalar types: \c float, \c double, \c complex<float>, and \c complex<double>.
+Operations on other scalar types or mixing reals and complexes will continue to use the built-in algorithms.
+
+In addition you can coarsely select choose which parts will be substituted by defining one or multiple of the following macros:
+
+<table class="manual">
+<tr><td>\c EIGEN_USE_BLAS </td><td>Enables the use of external BLAS level 2 and 3 routines (currently works with Intel MKL only)</td></tr>
+<tr class="alt"><td>\c EIGEN_USE_LAPACKE </td><td>Enables the use of external Lapack routines via the <a href="http://www.netlib.org/lapack/lapacke.html">Intel Lapacke</a> C interface to Lapack (currently works with Intel MKL only)</td></tr>
+<tr><td>\c EIGEN_USE_LAPACKE_STRICT </td><td>Same as \c EIGEN_USE_LAPACKE but algorithm of lower robustness are disabled. This currently concerns only JacobiSVD which otherwise would be replaced by \c gesvd that is less robust than Jacobi rotations.</td></tr>
+<tr class="alt"><td>\c EIGEN_USE_MKL_VML </td><td>Enables the use of Intel VML (vector operations)</td></tr>
+<tr><td>\c EIGEN_USE_MKL_ALL </td><td>Defines \c EIGEN_USE_BLAS, \c EIGEN_USE_LAPACKE, and \c EIGEN_USE_MKL_VML </td></tr>
+</table>
+
+Finally, the PARDISO sparse solver shipped with Intel MKL can be used through the \ref PardisoLU, \ref PardisoLLT and \ref PardisoLDLT classes of the \ref PARDISOSupport_Module.
+
+
+\section TopicUsingIntelMKL_SupportedFeatures List of supported features
+
+The breadth of Eigen functionality covered by Intel MKL is listed in the table below.
+<table class="manual">
+<tr><th>Functional domain</th><th>Code example</th><th>MKL routines</th></tr>
+<tr><td>Matrix-matrix operations \n \c EIGEN_USE_BLAS </td><td>\code
+m1*m2.transpose();
+m1.selfadjointView<Lower>()*m2;
+m1*m2.triangularView<Upper>();
+m1.selfadjointView<Lower>().rankUpdate(m2,1.0);
+\endcode</td><td>\code
+?gemm
+?symm/?hemm
+?trmm
+dsyrk/ssyrk
+\endcode</td></tr>
+<tr class="alt"><td>Matrix-vector operations \n \c EIGEN_USE_BLAS </td><td>\code
+m1.adjoint()*b;
+m1.selfadjointView<Lower>()*b;
+m1.triangularView<Upper>()*b;
+\endcode</td><td>\code
+?gemv
+?symv/?hemv
+?trmv
+\endcode</td></tr>
+<tr><td>LU decomposition \n \c EIGEN_USE_LAPACKE \n \c EIGEN_USE_LAPACKE_STRICT </td><td>\code
+v1 = m1.lu().solve(v2);
+\endcode</td><td>\code
+?getrf
+\endcode</td></tr>
+<tr class="alt"><td>Cholesky decomposition \n \c EIGEN_USE_LAPACKE \n \c EIGEN_USE_LAPACKE_STRICT </td><td>\code
+v1 = m2.selfadjointView<Upper>().llt().solve(v2);
+\endcode</td><td>\code
+?potrf
+\endcode</td></tr>
+<tr><td>QR decomposition \n \c EIGEN_USE_LAPACKE \n \c EIGEN_USE_LAPACKE_STRICT </td><td>\code
+m1.householderQr();
+m1.colPivHouseholderQr();
+\endcode</td><td>\code
+?geqrf
+?geqp3
+\endcode</td></tr>
+<tr class="alt"><td>Singular value decomposition \n \c EIGEN_USE_LAPACKE </td><td>\code
+JacobiSVD<MatrixXd> svd;
+svd.compute(m1, ComputeThinV);
+\endcode</td><td>\code
+?gesvd
+\endcode</td></tr>
+<tr><td>Eigen-value decompositions \n \c EIGEN_USE_LAPACKE \n \c EIGEN_USE_LAPACKE_STRICT </td><td>\code
+EigenSolver<MatrixXd> es(m1);
+ComplexEigenSolver<MatrixXcd> ces(m1);
+SelfAdjointEigenSolver<MatrixXd> saes(m1+m1.transpose());
+GeneralizedSelfAdjointEigenSolver<MatrixXd>
+ gsaes(m1+m1.transpose(),m2+m2.transpose());
+\endcode</td><td>\code
+?gees
+?gees
+?syev/?heev
+?syev/?heev,
+?potrf
+\endcode</td></tr>
+<tr class="alt"><td>Schur decomposition \n \c EIGEN_USE_LAPACKE \n \c EIGEN_USE_LAPACKE_STRICT </td><td>\code
+RealSchur<MatrixXd> schurR(m1);
+ComplexSchur<MatrixXcd> schurC(m1);
+\endcode</td><td>\code
+?gees
+\endcode</td></tr>
+<tr><td>Vector Math \n \c EIGEN_USE_MKL_VML </td><td>\code
+v2=v1.array().sin();
+v2=v1.array().asin();
+v2=v1.array().cos();
+v2=v1.array().acos();
+v2=v1.array().tan();
+v2=v1.array().exp();
+v2=v1.array().log();
+v2=v1.array().sqrt();
+v2=v1.array().square();
+v2=v1.array().pow(1.5);
+\endcode</td><td>\code
+v?Sin
+v?Asin
+v?Cos
+v?Acos
+v?Tan
+v?Exp
+v?Ln
+v?Sqrt
+v?Sqr
+v?Powx
+\endcode</td></tr>
+</table>
+In the examples, m1 and m2 are dense matrices and v1 and v2 are dense vectors.
+
+
+\section TopicUsingIntelMKL_Links Links
+- Intel MKL can be purchased and downloaded <a href="http://eigen.tuxfamily.org/Counter/redirect_to_mkl.php">here</a>.
+- Intel MKL is also bundled with <a href="http://software.intel.com/en-us/articles/intel-composer-xe/">Intel Composer XE</a>.
+
+
+*/
+
+} \ No newline at end of file
diff --git a/doc/eigendoxy.css b/doc/eigendoxy.css
new file mode 100644
index 000000000..c6c16286d
--- /dev/null
+++ b/doc/eigendoxy.css
@@ -0,0 +1,911 @@
+/* The standard CSS for doxygen */
+
+body, table, div, p, dl {
+ font-family: Lucida Grande, Verdana, Geneva, Arial, sans-serif;
+ font-size: 12px;
+}
+
+/* @group Heading Levels */
+
+h1 {
+ font-size: 150%;
+}
+
+h2 {
+ font-size: 120%;
+}
+
+h3 {
+ font-size: 100%;
+}
+
+dt {
+ font-weight: bold;
+}
+
+div.multicol {
+ -moz-column-gap: 1em;
+ -webkit-column-gap: 1em;
+ -moz-column-count: 3;
+ -webkit-column-count: 3;
+}
+
+p.startli, p.startdd, p.starttd {
+ margin-top: 2px;
+}
+
+p.endli {
+ margin-bottom: 0px;
+}
+
+p.enddd {
+ margin-bottom: 4px;
+}
+
+p.endtd {
+ margin-bottom: 2px;
+}
+
+/* @end */
+
+caption {
+ font-weight: bold;
+}
+
+span.legend {
+ font-size: 70%;
+ text-align: center;
+}
+
+h3.version {
+ font-size: 90%;
+ text-align: center;
+}
+
+div.qindex, div.navtab{
+ background-color: #EBEFF6;
+ border: 1px solid #A3B4D7;
+ text-align: center;
+ margin: 2px;
+ padding: 2px;
+}
+
+div.qindex, div.navpath {
+ width: 100%;
+ line-height: 140%;
+}
+
+div.navtab {
+ margin-right: 15px;
+}
+
+/* @group Link Styling */
+
+a {
+ color: #3D578C;
+ font-weight: normal;
+ text-decoration: none;
+}
+
+.contents a:visited {
+ color: #4665A2;
+}
+
+a:hover {
+ text-decoration: underline;
+}
+
+a.qindex {
+ font-weight: bold;
+}
+
+a.qindexHL {
+ font-weight: bold;
+ background-color: #9CAFD4;
+ color: #ffffff;
+ border: 1px double #869DCA;
+}
+
+.contents a.qindexHL:visited {
+ color: #ffffff;
+}
+
+a.el {
+ font-weight: bold;
+}
+
+a.elRef {
+}
+
+a.code {
+ color: #4665A2;
+}
+
+a.codeRef {
+ color: #4665A2;
+}
+
+/* @end */
+
+dl.el {
+ margin-left: -1cm;
+}
+
+.fragment {
+ font-family: monospace, fixed;
+ font-size: 105%;
+}
+
+pre.fragment {
+ border: 1px solid #C4CFE5;
+ background-color: #FBFCFD;
+ padding: 4px 6px;
+ margin: 4px 8px 4px 2px;
+ overflow: auto;
+ /*word-wrap: break-word;*/
+ font-size: 9pt;
+ line-height: 125%;
+}
+
+div.ah {
+ background-color: black;
+ font-weight: bold;
+ color: #ffffff;
+ margin-bottom: 3px;
+ margin-top: 3px;
+ padding: 0.2em;
+ border: solid thin #333;
+ border-radius: 0.5em;
+ -webkit-border-radius: .5em;
+ -moz-border-radius: .5em;
+ box-shadow: 2px 2px 3px #999;
+ -webkit-box-shadow: 2px 2px 3px #999;
+ -moz-box-shadow: rgba(0, 0, 0, 0.15) 2px 2px 2px;
+ background-image: -webkit-gradient(linear, left top, left bottom, from(#eee), to(#000),color-stop(0.3, #444));
+ background-image: -moz-linear-gradient(center top, #eee 0%, #444 40%, #000);
+}
+
+div.groupHeader {
+ margin-left: 16px;
+ margin-top: 12px;
+ font-weight: bold;
+}
+
+div.groupText {
+ margin-left: 16px;
+ font-style: italic;
+}
+
+body {
+ background: white;
+ color: black;
+ margin: 0;
+}
+
+div.contents {
+ margin-top: 10px;
+ margin-left: 10px;
+ margin-right: 10px;
+}
+
+td.indexkey {
+ background-color: #EBEFF6;
+ font-weight: bold;
+ border: 1px solid #C4CFE5;
+ margin: 2px 0px 2px 0;
+ padding: 2px 10px;
+}
+
+td.indexvalue {
+ background-color: #EBEFF6;
+ border: 1px solid #C4CFE5;
+ padding: 2px 10px;
+ margin: 2px 0px;
+}
+
+tr.memlist {
+ background-color: #EEF1F7;
+}
+
+p.formulaDsp {
+ text-align: center;
+}
+
+img.formulaDsp {
+
+}
+
+img.formulaInl {
+ vertical-align: middle;
+}
+
+div.center {
+ text-align: center;
+ margin-top: 0px;
+ margin-bottom: 0px;
+ padding: 0px;
+}
+
+div.center img {
+ border: 0px;
+}
+
+address.footer {
+ text-align: right;
+ padding-right: 12px;
+}
+
+img.footer {
+ border: 0px;
+ vertical-align: middle;
+}
+
+/* @group Code Colorization */
+
+span.keyword {
+ color: #008000
+}
+
+span.keywordtype {
+ color: #604020
+}
+
+span.keywordflow {
+ color: #e08000
+}
+
+span.comment {
+ color: #800000
+}
+
+span.preprocessor {
+ color: #806020
+}
+
+span.stringliteral {
+ color: #002080
+}
+
+span.charliteral {
+ color: #008080
+}
+
+span.vhdldigit {
+ color: #ff00ff
+}
+
+span.vhdlchar {
+ color: #000000
+}
+
+span.vhdlkeyword {
+ color: #700070
+}
+
+span.vhdllogic {
+ color: #ff0000
+}
+
+/* @end */
+
+/*
+.search {
+ color: #003399;
+ font-weight: bold;
+}
+
+form.search {
+ margin-bottom: 0px;
+ margin-top: 0px;
+}
+
+input.search {
+ font-size: 75%;
+ color: #000080;
+ font-weight: normal;
+ background-color: #e8eef2;
+}
+*/
+
+td.tiny {
+ font-size: 75%;
+}
+
+.dirtab {
+ padding: 4px;
+ border-collapse: collapse;
+ border: 1px solid #A3B4D7;
+}
+
+th.dirtab {
+ background: #EBEFF6;
+ font-weight: bold;
+}
+
+hr {
+ height: 0px;
+ border: none;
+ border-top: 1px solid #4A6AAA;
+}
+
+hr.footer {
+ height: 1px;
+}
+
+/* @group Member Descriptions */
+
+table.memberdecls {
+ border-spacing: 0px;
+ padding: 0px;
+}
+
+.mdescLeft, .mdescRight,
+.memItemLeft, .memItemRight,
+.memTemplItemLeft, .memTemplItemRight, .memTemplParams {
+ background-color: #F9FAFC;
+ border: none;
+ margin: 4px;
+ padding: 1px 0 0 8px;
+}
+
+.mdescLeft, .mdescRight {
+ padding: 0px 8px 4px 8px;
+ color: #555;
+}
+
+.memItemLeft, .memItemRight, .memTemplParams {
+ border-top: 1px solid #C4CFE5;
+}
+
+.memItemLeft, .memTemplItemLeft {
+ white-space: nowrap;
+}
+
+.memTemplParams {
+ color: #4665A2;
+ white-space: nowrap;
+}
+
+/* @end */
+
+/* @group Member Details */
+
+/* Styles for detailed member documentation */
+
+.memtemplate {
+ font-size: 80%;
+ color: #4665A2;
+ font-weight: normal;
+ margin-left: 9px;
+}
+
+.memnav {
+ background-color: #EBEFF6;
+ border: 1px solid #A3B4D7;
+ text-align: center;
+ margin: 2px;
+ margin-right: 15px;
+ padding: 2px;
+}
+
+.memitem {
+ padding: 0;
+ margin-bottom: 10px;
+}
+
+.memname {
+ white-space: nowrap;
+ font-weight: bold;
+ margin-left: 6px;
+}
+
+.memproto {
+ border-top: 1px solid #A8B8D9;
+ border-left: 1px solid #A8B8D9;
+ border-right: 1px solid #A8B8D9;
+ padding: 6px 0px 6px 0px;
+ color: #253555;
+ font-weight: bold;
+ text-shadow: 0px 1px 1px rgba(255, 255, 255, 0.9);
+ /* opera specific markup */
+ box-shadow: 5px 5px 5px rgba(0, 0, 0, 0.15);
+ border-top-right-radius: 8px;
+ border-top-left-radius: 8px;
+ /* firefox specific markup */
+ -moz-box-shadow: rgba(0, 0, 0, 0.15) 5px 5px 5px;
+ -moz-border-radius-topright: 8px;
+ -moz-border-radius-topleft: 8px;
+ /* webkit specific markup */
+ -webkit-box-shadow: 5px 5px 5px rgba(0, 0, 0, 0.15);
+ -webkit-border-top-right-radius: 8px;
+ -webkit-border-top-left-radius: 8px;
+ background-image:url('nav_f.png');
+ background-repeat:repeat-x;
+ background-color: #E2E8F2;
+
+}
+
+.memdoc {
+ border-bottom: 1px solid #A8B8D9;
+ border-left: 1px solid #A8B8D9;
+ border-right: 1px solid #A8B8D9;
+ padding: 2px 5px;
+ background-color: #FBFCFD;
+ border-top-width: 0;
+ /* opera specific markup */
+ border-bottom-left-radius: 8px;
+ border-bottom-right-radius: 8px;
+ box-shadow: 5px 5px 5px rgba(0, 0, 0, 0.15);
+ /* firefox specific markup */
+ -moz-border-radius-bottomleft: 8px;
+ -moz-border-radius-bottomright: 8px;
+ -moz-box-shadow: rgba(0, 0, 0, 0.15) 5px 5px 5px;
+ background-image: -moz-linear-gradient(center top, #FFFFFF 0%, #FFFFFF 60%, #F7F8FB 95%, #EEF1F7);
+ /* webkit specific markup */
+ -webkit-border-bottom-left-radius: 8px;
+ -webkit-border-bottom-right-radius: 8px;
+ -webkit-box-shadow: 5px 5px 5px rgba(0, 0, 0, 0.15);
+ background-image: -webkit-gradient(linear,center top,center bottom,from(#FFFFFF), color-stop(0.6,#FFFFFF), color-stop(0.60,#FFFFFF), color-stop(0.95,#F7F8FB), to(#EEF1F7));
+}
+
+.paramkey {
+ text-align: right;
+}
+
+.paramtype {
+ white-space: nowrap;
+}
+
+.paramname {
+ color: #602020;
+ white-space: nowrap;
+}
+.paramname em {
+ font-style: normal;
+}
+
+.params, .retval, .exception, .tparams {
+ border-spacing: 6px 2px;
+}
+
+.params .paramname, .retval .paramname {
+ font-weight: bold;
+ vertical-align: top;
+}
+
+.params .paramtype {
+ font-style: italic;
+ vertical-align: top;
+}
+
+.params .paramdir {
+ font-family: "courier new",courier,monospace;
+ vertical-align: top;
+}
+
+
+
+
+/* @end */
+
+/* @group Directory (tree) */
+
+/* for the tree view */
+
+.ftvtree {
+ font-family: sans-serif;
+ margin: 0px;
+}
+
+/* these are for tree view when used as main index */
+
+.directory {
+ font-size: 9pt;
+ font-weight: bold;
+ margin: 5px;
+}
+
+.directory h3 {
+ margin: 0px;
+ margin-top: 1em;
+ font-size: 11pt;
+}
+
+/*
+The following two styles can be used to replace the root node title
+with an image of your choice. Simply uncomment the next two styles,
+specify the name of your image and be sure to set 'height' to the
+proper pixel height of your image.
+*/
+
+/*
+.directory h3.swap {
+ height: 61px;
+ background-repeat: no-repeat;
+ background-image: url("yourimage.gif");
+}
+.directory h3.swap span {
+ display: none;
+}
+*/
+
+.directory > h3 {
+ margin-top: 0;
+}
+
+.directory p {
+ margin: 0px;
+ white-space: nowrap;
+}
+
+.directory div {
+ display: none;
+ margin: 0px;
+}
+
+.directory img {
+ vertical-align: -30%;
+}
+
+/* these are for tree view when not used as main index */
+
+.directory-alt {
+ font-size: 100%;
+ font-weight: bold;
+}
+
+.directory-alt h3 {
+ margin: 0px;
+ margin-top: 1em;
+ font-size: 11pt;
+}
+
+.directory-alt > h3 {
+ margin-top: 0;
+}
+
+.directory-alt p {
+ margin: 0px;
+ white-space: nowrap;
+}
+
+.directory-alt div {
+ display: none;
+ margin: 0px;
+}
+
+.directory-alt img {
+ vertical-align: -30%;
+}
+
+/* @end */
+
+div.dynheader {
+ margin-top: 8px;
+}
+
+address {
+ font-style: normal;
+ color: #2A3D61;
+}
+
+table.doxtable {
+ border-collapse:collapse;
+}
+
+table.doxtable td, table.doxtable th {
+ border: 1px solid #2D4068;
+ padding: 3px 7px 2px;
+}
+
+table.doxtable th {
+ background-color: #374F7F;
+ color: #FFFFFF;
+ font-size: 110%;
+ padding-bottom: 4px;
+ padding-top: 5px;
+ text-align:left;
+}
+
+.tabsearch {
+ top: 0px;
+ left: 10px;
+ height: 36px;
+ background-image: url('tab_b.png');
+ z-index: 101;
+ overflow: hidden;
+ font-size: 13px;
+}
+
+.navpath ul
+{
+ font-size: 11px;
+ background-image:url('tab_b.png');
+ background-repeat:repeat-x;
+ height:30px;
+ line-height:30px;
+ color:#8AA0CC;
+ border:solid 1px #C2CDE4;
+ overflow:hidden;
+ margin:0px;
+ padding:0px;
+}
+
+.navpath li
+{
+ list-style-type:none;
+ float:left;
+ padding-left:10px;
+ padding-right: 15px;
+ background-image:url('bc_s.png');
+ background-repeat:no-repeat;
+ background-position:right;
+ color:#364D7C;
+}
+
+.navpath a
+{
+ height:32px;
+ display:block;
+ text-decoration: none;
+ outline: none;
+}
+
+.navpath a:hover
+{
+ color:#6884BD;
+}
+
+div.summary
+{
+ float: right;
+ font-size: 8pt;
+ padding-right: 5px;
+ width: 50%;
+ text-align: right;
+}
+
+div.summary a
+{
+ white-space: nowrap;
+}
+
+div.header
+{
+ background-image:url('nav_h.png');
+ background-repeat:repeat-x;
+ background-color: #F9FAFC;
+ margin: 0px;
+ border-bottom: 1px solid #C4CFE5;
+}
+
+div.headertitle
+{
+ padding: 5px 5px 5px 10px;
+}
+
+
+
+/******** Eigen specific CSS code ************/
+
+
+body {
+ max-width:60em;
+ margin-left:5%;
+ margin-top:2%;
+ font-family: Lucida Grande, Verdana, Geneva, Arial, sans-serif;
+}
+
+img {
+ border: 0;
+}
+
+a.logo {
+ float:right;
+ margin:10px;
+}
+
+div.fragment {
+ display:table; /* this allows the element to be larger than its parent */
+ padding: 0pt;
+}
+pre.fragment {
+ border: 1px solid #cccccc;
+
+ margin: 2px 0px 2px 0px ;
+ padding: 3px 5px 3px 5px;
+}
+
+/* Common style for all Eigen's tables */
+
+table.example, table.manual, table.manual-vl {
+ max-width:100%;
+ border-collapse: collapse;
+ border-style: solid;
+ border-width: 1px;
+ border-color: #cccccc;
+ font-size: 1em;
+
+ box-shadow: 5px 5px 5px rgba(0, 0, 0, 0.15);
+ -moz-box-shadow: 5px 5px 5px rgba(0, 0, 0, 0.15);
+ -webkit-box-shadow: 5px 5px 5px rgba(0, 0, 0, 0.15);
+}
+
+table.example th, table.manual th, table.manual-vl th {
+ padding: 0.5em 0.5em 0.5em 0.5em;
+ text-align: left;
+ padding-right: 1em;
+ color: #555555;
+ background-color: #F4F4E5;
+
+ background-image: -webkit-gradient(linear,center top,center bottom,from(#FFFFFF), color-stop(0.3,#FFFFFF), color-stop(0.30,#FFFFFF), color-stop(0.98,#F4F4E5), to(#ECECDE));
+ background-image: -moz-linear-gradient(center top, #FFFFFF 0%, #FFFFFF 30%, #F4F4E5 98%, #ECECDE);
+ filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#FFFFFF', endColorstr='#F4F4E5');
+}
+
+table.example td, table.manual td, table.manual-vl td {
+ vertical-align:top;
+ border-width: 1px;
+ border-color: #cccccc;
+}
+
+/* header of headers */
+table th.meta {
+ text-align:center;
+ font-size: 1.2em;
+ background-color:#FFFFFF;
+}
+
+/* intermediate header */
+table th.inter {
+ text-align:left;
+ background-color:#FFFFFF;
+ background-image:none;
+ border-style:solid solid solid solid;
+ border-width: 1px;
+ border-color: #cccccc;
+}
+
+/** class for exemple / output tables **/
+
+table.example {
+}
+
+table.example th {
+}
+
+table.example td {
+ padding: 0.5em 0.5em 0.5em 0.5em;
+ vertical-align:top;
+}
+
+/* standard class for the manual */
+
+table.manual, table.manual-vl {
+ padding: 0.2em 0em 0.5em 0em;
+}
+
+table.manual th, table.manual-vl th {
+ margin: 0em 0em 0.3em 0em;
+}
+
+table.manual td, table.manual-vl td {
+ padding: 0.3em 0.5em 0.3em 0.5em;
+ vertical-align:top;
+ border-width: 1px;
+}
+
+table.manual td.alt, table.manual tr.alt, table.manual-vl td.alt, table.manual-vl tr.alt {
+ background-color: #F4F4E5;
+}
+
+table.manual-vl th, table.manual-vl td, table.manual-vl td.alt {
+ border-color: #cccccc;
+ border-width: 1px;
+ border-style: none solid none solid;
+}
+
+table.manual-vl th.inter {
+ border-style: solid solid solid solid;
+}
+
+h2 {
+ margin-top:2em;
+ border-style: none none solid none;
+ border-width: 1px;
+ border-color: #cccccc;
+}
+
+
+/**** old Eigen's styles ****/
+
+th {
+ /*text-align: left;
+ padding-right: 1em;*/
+ /* border: #cccccc dashed; */
+ /* border-style: dashed; */
+ /* border-width: 0 0 3px 0; */
+}
+/*
+table.noborder {
+ border-collapse: separate;
+ border-bottom-style : none;
+ border-left-style : none;
+ border-right-style : none;
+ border-top-style : none ;
+ border-spacing : 0px 0px;
+ margin: 4pt 0 0 0;
+ padding: 0 0 0 0;
+
+ -webkit-box-shadow: 5px 5px 5px rgba(0, 0, 0, 0.15);
+ -moz-box-shadow: rgba(0, 0, 0, 0.15) 5px 5px 5px;
+}
+
+table.noborder td {
+ border-bottom-style : none;
+ border-left-style : none;
+ border-right-style : none;
+ border-top-style : none;
+ border-spacing : 0px 0px;
+ margin: 0 0 0 0;
+ vertical-align: top;
+}
+
+table.tutorial_code {
+ width: 90%;
+ -webkit-box-shadow: 5px 5px 5px rgba(0, 0, 0, 0.15);
+ -moz-box-shadow: rgba(0, 0, 0, 0.15) 5px 5px 5px;
+}
+
+table.tutorial_code tr {
+ border: 1px dashed #888888;
+}
+*/
+
+table.tutorial_code td {
+ border-color: transparent; /* required for Firefox */
+ padding: 3pt 5pt 3pt 5pt;
+ vertical-align: top;
+}
+
+
+/* Whenever doxygen meets a '\n' or a '<BR/>', it will put
+ * the text containing the characted into a <p class="starttd">.
+ * This little hack togehter with table.tutorial_code td.note
+ * aims at fixing this issue. */
+table.tutorial_code td.note p.starttd {
+ margin: 0px;
+ border: none;
+ padding: 0px;
+}
+/*
+div.fragment {
+ font-family: monospace, fixed;
+ font-size: 95%;
+
+ border: none;
+ padding: 0pt;
+}
+
+pre.fragment {
+ margin: 0pt;
+ border: 1px solid #cccccc;
+ padding: 2px 5px 2px 5px;
+
+ background-color: #f5f5f5;
+}
+*/
+
+div.eimainmenu {
+ text-align: center;
+}
+
+/* center version number on main page */
+h3.version {
+ text-align: center;
+}
+
+
+td.width20em p.endtd {
+ width: 20em;
+}
diff --git a/doc/eigendoxy_footer.html.in b/doc/eigendoxy_footer.html.in
new file mode 100644
index 000000000..e70829fb0
--- /dev/null
+++ b/doc/eigendoxy_footer.html.in
@@ -0,0 +1,5 @@
+
+<hr class="footer"/><address class="footer"><small>
+<a href="http://www.doxygen.org/index.html"><img class="footer" src="$relpath$doxygen.png" alt="doxygen"/></a></small></address>
+</body>
+</html> \ No newline at end of file
diff --git a/doc/eigendoxy_header.html.in b/doc/eigendoxy_header.html.in
new file mode 100644
index 000000000..a4fe47f27
--- /dev/null
+++ b/doc/eigendoxy_header.html.in
@@ -0,0 +1,14 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+<meta http-equiv="Content-Type" content="text/xhtml;charset=UTF-8"/>
+<title>$title</title>
+<link href="$relpath$eigendoxy_tabs.css" rel="stylesheet" type="text/css">
+<link href="$relpath$search/search.css" rel="stylesheet" type="text/css"/>
+<script type="text/javaScript" src="$relpath$search/search.js"></script>
+<link href="$relpath$eigendoxy.css" rel="stylesheet" type="text/css">
+</head>
+<body onload='searchBox.OnSelectItem(0);'>
+<a name="top"></a>
+<a class="logo" href="http://eigen.tuxfamily.org/">
+<img class="logo" src="Eigen_Silly_Professor_64x64.png" width=64 height=64 alt="Eigen's silly professor"/></a>
diff --git a/doc/eigendoxy_tabs.css b/doc/eigendoxy_tabs.css
new file mode 100644
index 000000000..21920562a
--- /dev/null
+++ b/doc/eigendoxy_tabs.css
@@ -0,0 +1,59 @@
+.tabs, .tabs2, .tabs3 {
+ background-image: url('tab_b.png');
+ width: 100%;
+ z-index: 101;
+ font-size: 13px;
+}
+
+.tabs2 {
+ font-size: 10px;
+}
+.tabs3 {
+ font-size: 9px;
+}
+
+.tablist {
+ margin: 0;
+ padding: 0;
+ display: table;
+}
+
+.tablist li {
+ float: left;
+ display: table-cell;
+ background-image: url('tab_b.png');
+ line-height: 36px;
+ list-style: none;
+}
+
+.tablist a {
+ display: block;
+ padding: 0 20px;
+ font-weight: bold;
+ background-image:url('tab_s.png');
+ background-repeat:no-repeat;
+ background-position:right;
+ color: #283A5D;
+ text-shadow: 0px 1px 1px rgba(255, 255, 255, 0.9);
+ text-decoration: none;
+ outline: none;
+}
+
+.tabs3 .tablist a {
+ padding: 0 10px;
+}
+
+.tablist a:hover {
+ background-image: url('tab_h.png');
+ background-repeat:repeat-x;
+ color: #fff;
+ text-shadow: 0px 1px 1px rgba(0, 0, 0, 1.0);
+ text-decoration: none;
+}
+
+.tablist li.current a {
+ background-image: url('tab_a.png');
+ background-repeat:repeat-x;
+ color: #fff;
+ text-shadow: 0px 1px 1px rgba(0, 0, 0, 1.0);
+}
diff --git a/doc/examples/.krazy b/doc/examples/.krazy
new file mode 100644
index 000000000..00b99405d
--- /dev/null
+++ b/doc/examples/.krazy
@@ -0,0 +1,2 @@
+EXCLUDE copyright
+EXCLUDE license
diff --git a/doc/examples/CMakeLists.txt b/doc/examples/CMakeLists.txt
new file mode 100644
index 000000000..13ec0c123
--- /dev/null
+++ b/doc/examples/CMakeLists.txt
@@ -0,0 +1,20 @@
+file(GLOB examples_SRCS "*.cpp")
+
+add_custom_target(all_examples)
+
+foreach(example_src ${examples_SRCS})
+ get_filename_component(example ${example_src} NAME_WE)
+ add_executable(${example} ${example_src})
+ if(EIGEN_STANDARD_LIBRARIES_TO_LINK_TO)
+ target_link_libraries(${example} ${EIGEN_STANDARD_LIBRARIES_TO_LINK_TO})
+ endif()
+ get_target_property(example_executable
+ ${example} LOCATION)
+ add_custom_command(
+ TARGET ${example}
+ POST_BUILD
+ COMMAND ${example_executable}
+ ARGS >${CMAKE_CURRENT_BINARY_DIR}/${example}.out
+ )
+ add_dependencies(all_examples ${example})
+endforeach(example_src)
diff --git a/doc/examples/DenseBase_middleCols_int.cpp b/doc/examples/DenseBase_middleCols_int.cpp
new file mode 100644
index 000000000..0ebd955ec
--- /dev/null
+++ b/doc/examples/DenseBase_middleCols_int.cpp
@@ -0,0 +1,15 @@
+#include <Eigen/Core>
+#include <iostream>
+
+using namespace Eigen;
+using namespace std;
+
+int main(void)
+{
+ int const N = 5;
+ MatrixXi A(N,N);
+ A.setRandom();
+ cout << "A =\n" << A << '\n' << endl;
+ cout << "A(1..3,:) =\n" << A.middleCols(1,3) << endl;
+ return 0;
+}
diff --git a/doc/examples/DenseBase_middleRows_int.cpp b/doc/examples/DenseBase_middleRows_int.cpp
new file mode 100644
index 000000000..a6fe9e844
--- /dev/null
+++ b/doc/examples/DenseBase_middleRows_int.cpp
@@ -0,0 +1,15 @@
+#include <Eigen/Core>
+#include <iostream>
+
+using namespace Eigen;
+using namespace std;
+
+int main(void)
+{
+ int const N = 5;
+ MatrixXi A(N,N);
+ A.setRandom();
+ cout << "A =\n" << A << '\n' << endl;
+ cout << "A(2..3,:) =\n" << A.middleRows(2,2) << endl;
+ return 0;
+}
diff --git a/doc/examples/DenseBase_template_int_middleCols.cpp b/doc/examples/DenseBase_template_int_middleCols.cpp
new file mode 100644
index 000000000..6191d79c8
--- /dev/null
+++ b/doc/examples/DenseBase_template_int_middleCols.cpp
@@ -0,0 +1,15 @@
+#include <Eigen/Core>
+#include <iostream>
+
+using namespace Eigen;
+using namespace std;
+
+int main(void)
+{
+ int const N = 5;
+ MatrixXi A(N,N);
+ A.setRandom();
+ cout << "A =\n" << A << '\n' << endl;
+ cout << "A(:,1..3) =\n" << A.middleCols<3>(1) << endl;
+ return 0;
+}
diff --git a/doc/examples/DenseBase_template_int_middleRows.cpp b/doc/examples/DenseBase_template_int_middleRows.cpp
new file mode 100644
index 000000000..7e8b6573f
--- /dev/null
+++ b/doc/examples/DenseBase_template_int_middleRows.cpp
@@ -0,0 +1,15 @@
+#include <Eigen/Core>
+#include <iostream>
+
+using namespace Eigen;
+using namespace std;
+
+int main(void)
+{
+ int const N = 5;
+ MatrixXi A(N,N);
+ A.setRandom();
+ cout << "A =\n" << A << '\n' << endl;
+ cout << "A(1..3,:) =\n" << A.middleRows<3>(1) << endl;
+ return 0;
+}
diff --git a/doc/examples/MatrixBase_cwise_const.cpp b/doc/examples/MatrixBase_cwise_const.cpp
new file mode 100644
index 000000000..23700e0b6
--- /dev/null
+++ b/doc/examples/MatrixBase_cwise_const.cpp
@@ -0,0 +1,18 @@
+#define EIGEN2_SUPPORT
+#include <Eigen/Core>
+#include <iostream>
+
+using namespace Eigen;
+using namespace std;
+
+int main()
+{
+ Matrix3i m = Matrix3i::Random();
+ cout << "Here is the matrix m:" << endl << m << endl;
+ Matrix3i n = Matrix3i::Random();
+ cout << "And here is the matrix n:" << endl << n << endl;
+ cout << "The coefficient-wise product of m and n is:" << endl;
+ cout << m.cwise() * n << endl;
+ cout << "Taking the cube of the coefficients of m yields:" << endl;
+ cout << m.cwise().pow(3) << endl;
+}
diff --git a/doc/examples/QuickStart_example.cpp b/doc/examples/QuickStart_example.cpp
new file mode 100644
index 000000000..7238c0c43
--- /dev/null
+++ b/doc/examples/QuickStart_example.cpp
@@ -0,0 +1,14 @@
+#include <iostream>
+#include <Eigen/Dense>
+
+using Eigen::MatrixXd;
+
+int main()
+{
+ MatrixXd m(2,2);
+ m(0,0) = 3;
+ m(1,0) = 2.5;
+ m(0,1) = -1;
+ m(1,1) = m(1,0) + m(0,1);
+ std::cout << m << std::endl;
+}
diff --git a/doc/examples/QuickStart_example2_dynamic.cpp b/doc/examples/QuickStart_example2_dynamic.cpp
new file mode 100644
index 000000000..672ac82e9
--- /dev/null
+++ b/doc/examples/QuickStart_example2_dynamic.cpp
@@ -0,0 +1,15 @@
+#include <iostream>
+#include <Eigen/Dense>
+
+using namespace Eigen;
+using namespace std;
+
+int main()
+{
+ MatrixXf m = MatrixXf::Random(3,3);
+ m = (m + MatrixXf::Constant(3,3,1.2)) * 50;
+ cout << "m =" << endl << m << endl;
+ VectorXf v(3);
+ v << 1, 2, 3;
+ cout << "m * v =" << endl << m * v << endl;
+}
diff --git a/doc/examples/QuickStart_example2_fixed.cpp b/doc/examples/QuickStart_example2_fixed.cpp
new file mode 100644
index 000000000..edf3268cd
--- /dev/null
+++ b/doc/examples/QuickStart_example2_fixed.cpp
@@ -0,0 +1,15 @@
+#include <iostream>
+#include <Eigen/Dense>
+
+using namespace Eigen;
+using namespace std;
+
+int main()
+{
+ Matrix3f m = Matrix3f::Random();
+ m = (m + Matrix3f::Constant(1.2)) * 50;
+ cout << "m =" << endl << m << endl;
+ Vector3f v(1,2,3);
+
+ cout << "m * v =" << endl << m * v << endl;
+}
diff --git a/doc/examples/TemplateKeyword_flexible.cpp b/doc/examples/TemplateKeyword_flexible.cpp
new file mode 100644
index 000000000..9d85292dd
--- /dev/null
+++ b/doc/examples/TemplateKeyword_flexible.cpp
@@ -0,0 +1,22 @@
+#include <Eigen/Dense>
+#include <iostream>
+
+using namespace Eigen;
+
+template <typename Derived1, typename Derived2>
+void copyUpperTriangularPart(MatrixBase<Derived1>& dst, const MatrixBase<Derived2>& src)
+{
+ /* Note the 'template' keywords in the following line! */
+ dst.template triangularView<Upper>() = src.template triangularView<Upper>();
+}
+
+int main()
+{
+ MatrixXi m1 = MatrixXi::Ones(5,5);
+ MatrixXi m2 = MatrixXi::Random(4,4);
+ std::cout << "m2 before copy:" << std::endl;
+ std::cout << m2 << std::endl << std::endl;
+ copyUpperTriangularPart(m2, m1.topLeftCorner(4,4));
+ std::cout << "m2 after copy:" << std::endl;
+ std::cout << m2 << std::endl << std::endl;
+}
diff --git a/doc/examples/TemplateKeyword_simple.cpp b/doc/examples/TemplateKeyword_simple.cpp
new file mode 100644
index 000000000..6998c1769
--- /dev/null
+++ b/doc/examples/TemplateKeyword_simple.cpp
@@ -0,0 +1,20 @@
+#include <Eigen/Dense>
+#include <iostream>
+
+using namespace Eigen;
+
+void copyUpperTriangularPart(MatrixXf& dst, const MatrixXf& src)
+{
+ dst.triangularView<Upper>() = src.triangularView<Upper>();
+}
+
+int main()
+{
+ MatrixXf m1 = MatrixXf::Ones(4,4);
+ MatrixXf m2 = MatrixXf::Random(4,4);
+ std::cout << "m2 before copy:" << std::endl;
+ std::cout << m2 << std::endl << std::endl;
+ copyUpperTriangularPart(m2, m1);
+ std::cout << "m2 after copy:" << std::endl;
+ std::cout << m2 << std::endl << std::endl;
+}
diff --git a/doc/examples/TutorialLinAlgComputeTwice.cpp b/doc/examples/TutorialLinAlgComputeTwice.cpp
new file mode 100644
index 000000000..06ba6461a
--- /dev/null
+++ b/doc/examples/TutorialLinAlgComputeTwice.cpp
@@ -0,0 +1,23 @@
+#include <iostream>
+#include <Eigen/Dense>
+
+using namespace std;
+using namespace Eigen;
+
+int main()
+{
+ Matrix2f A, b;
+ LLT<Matrix2f> llt;
+ A << 2, -1, -1, 3;
+ b << 1, 2, 3, 1;
+ cout << "Here is the matrix A:\n" << A << endl;
+ cout << "Here is the right hand side b:\n" << b << endl;
+ cout << "Computing LLT decomposition..." << endl;
+ llt.compute(A);
+ cout << "The solution is:\n" << llt.solve(b) << endl;
+ A(1,1)++;
+ cout << "The matrix A is now:\n" << A << endl;
+ cout << "Computing LLT decomposition..." << endl;
+ llt.compute(A);
+ cout << "The solution is now:\n" << llt.solve(b) << endl;
+}
diff --git a/doc/examples/TutorialLinAlgExComputeSolveError.cpp b/doc/examples/TutorialLinAlgExComputeSolveError.cpp
new file mode 100644
index 000000000..f362fb71a
--- /dev/null
+++ b/doc/examples/TutorialLinAlgExComputeSolveError.cpp
@@ -0,0 +1,14 @@
+#include <iostream>
+#include <Eigen/Dense>
+
+using namespace std;
+using namespace Eigen;
+
+int main()
+{
+ MatrixXd A = MatrixXd::Random(100,100);
+ MatrixXd b = MatrixXd::Random(100,50);
+ MatrixXd x = A.fullPivLu().solve(b);
+ double relative_error = (A*x - b).norm() / b.norm(); // norm() is L2 norm
+ cout << "The relative error is:\n" << relative_error << endl;
+}
diff --git a/doc/examples/TutorialLinAlgExSolveColPivHouseholderQR.cpp b/doc/examples/TutorialLinAlgExSolveColPivHouseholderQR.cpp
new file mode 100644
index 000000000..3a99a94d7
--- /dev/null
+++ b/doc/examples/TutorialLinAlgExSolveColPivHouseholderQR.cpp
@@ -0,0 +1,17 @@
+#include <iostream>
+#include <Eigen/Dense>
+
+using namespace std;
+using namespace Eigen;
+
+int main()
+{
+ Matrix3f A;
+ Vector3f b;
+ A << 1,2,3, 4,5,6, 7,8,10;
+ b << 3, 3, 4;
+ cout << "Here is the matrix A:\n" << A << endl;
+ cout << "Here is the vector b:\n" << b << endl;
+ Vector3f x = A.colPivHouseholderQr().solve(b);
+ cout << "The solution is:\n" << x << endl;
+}
diff --git a/doc/examples/TutorialLinAlgExSolveLDLT.cpp b/doc/examples/TutorialLinAlgExSolveLDLT.cpp
new file mode 100644
index 000000000..f8beacd27
--- /dev/null
+++ b/doc/examples/TutorialLinAlgExSolveLDLT.cpp
@@ -0,0 +1,16 @@
+#include <iostream>
+#include <Eigen/Dense>
+
+using namespace std;
+using namespace Eigen;
+
+int main()
+{
+ Matrix2f A, b;
+ A << 2, -1, -1, 3;
+ b << 1, 2, 3, 1;
+ cout << "Here is the matrix A:\n" << A << endl;
+ cout << "Here is the right hand side b:\n" << b << endl;
+ Matrix2f x = A.ldlt().solve(b);
+ cout << "The solution is:\n" << x << endl;
+}
diff --git a/doc/examples/TutorialLinAlgInverseDeterminant.cpp b/doc/examples/TutorialLinAlgInverseDeterminant.cpp
new file mode 100644
index 000000000..43970ff05
--- /dev/null
+++ b/doc/examples/TutorialLinAlgInverseDeterminant.cpp
@@ -0,0 +1,16 @@
+#include <iostream>
+#include <Eigen/Dense>
+
+using namespace std;
+using namespace Eigen;
+
+int main()
+{
+ Matrix3f A;
+ A << 1, 2, 1,
+ 2, 1, 0,
+ -1, 1, 2;
+ cout << "Here is the matrix A:\n" << A << endl;
+ cout << "The determinant of A is " << A.determinant() << endl;
+ cout << "The inverse of A is:\n" << A.inverse() << endl;
+} \ No newline at end of file
diff --git a/doc/examples/TutorialLinAlgRankRevealing.cpp b/doc/examples/TutorialLinAlgRankRevealing.cpp
new file mode 100644
index 000000000..c5165077f
--- /dev/null
+++ b/doc/examples/TutorialLinAlgRankRevealing.cpp
@@ -0,0 +1,20 @@
+#include <iostream>
+#include <Eigen/Dense>
+
+using namespace std;
+using namespace Eigen;
+
+int main()
+{
+ Matrix3f A;
+ A << 1, 2, 5,
+ 2, 1, 4,
+ 3, 0, 3;
+ cout << "Here is the matrix A:\n" << A << endl;
+ FullPivLU<Matrix3f> lu_decomp(A);
+ cout << "The rank of A is " << lu_decomp.rank() << endl;
+ cout << "Here is a matrix whose columns form a basis of the null-space of A:\n"
+ << lu_decomp.kernel() << endl;
+ cout << "Here is a matrix whose columns form a basis of the column-space of A:\n"
+ << lu_decomp.image(A) << endl; // yes, have to pass the original A
+}
diff --git a/doc/examples/TutorialLinAlgSVDSolve.cpp b/doc/examples/TutorialLinAlgSVDSolve.cpp
new file mode 100644
index 000000000..9fbc031de
--- /dev/null
+++ b/doc/examples/TutorialLinAlgSVDSolve.cpp
@@ -0,0 +1,15 @@
+#include <iostream>
+#include <Eigen/Dense>
+
+using namespace std;
+using namespace Eigen;
+
+int main()
+{
+ MatrixXf A = MatrixXf::Random(3, 2);
+ cout << "Here is the matrix A:\n" << A << endl;
+ VectorXf b = VectorXf::Random(3);
+ cout << "Here is the right hand side b:\n" << b << endl;
+ cout << "The least-squares solution is:\n"
+ << A.jacobiSvd(ComputeThinU | ComputeThinV).solve(b) << endl;
+}
diff --git a/doc/examples/TutorialLinAlgSelfAdjointEigenSolver.cpp b/doc/examples/TutorialLinAlgSelfAdjointEigenSolver.cpp
new file mode 100644
index 000000000..8d1d1ed65
--- /dev/null
+++ b/doc/examples/TutorialLinAlgSelfAdjointEigenSolver.cpp
@@ -0,0 +1,18 @@
+#include <iostream>
+#include <Eigen/Dense>
+
+using namespace std;
+using namespace Eigen;
+
+int main()
+{
+ Matrix2f A;
+ A << 1, 2, 2, 3;
+ cout << "Here is the matrix A:\n" << A << endl;
+ SelfAdjointEigenSolver<Matrix2f> eigensolver(A);
+ if (eigensolver.info() != Success) abort();
+ cout << "The eigenvalues of A are:\n" << eigensolver.eigenvalues() << endl;
+ cout << "Here's a matrix whose columns are eigenvectors of A \n"
+ << "corresponding to these eigenvalues:\n"
+ << eigensolver.eigenvectors() << endl;
+}
diff --git a/doc/examples/TutorialLinAlgSetThreshold.cpp b/doc/examples/TutorialLinAlgSetThreshold.cpp
new file mode 100644
index 000000000..3956b13a3
--- /dev/null
+++ b/doc/examples/TutorialLinAlgSetThreshold.cpp
@@ -0,0 +1,16 @@
+#include <iostream>
+#include <Eigen/Dense>
+
+using namespace std;
+using namespace Eigen;
+
+int main()
+{
+ Matrix2d A;
+ A << 2, 1,
+ 2, 0.9999999999;
+ FullPivLU<Matrix2d> lu(A);
+ cout << "By default, the rank of A is found to be " << lu.rank() << endl;
+ lu.setThreshold(1e-5);
+ cout << "With threshold 1e-5, the rank of A is found to be " << lu.rank() << endl;
+}
diff --git a/doc/examples/Tutorial_ArrayClass_accessors.cpp b/doc/examples/Tutorial_ArrayClass_accessors.cpp
new file mode 100644
index 000000000..dc720ff58
--- /dev/null
+++ b/doc/examples/Tutorial_ArrayClass_accessors.cpp
@@ -0,0 +1,24 @@
+#include <Eigen/Dense>
+#include <iostream>
+
+using namespace Eigen;
+using namespace std;
+
+int main()
+{
+ ArrayXXf m(2,2);
+
+ // assign some values coefficient by coefficient
+ m(0,0) = 1.0; m(0,1) = 2.0;
+ m(1,0) = 3.0; m(1,1) = m(0,1) + m(1,0);
+
+ // print values to standard output
+ cout << m << endl << endl;
+
+ // using the comma-initializer is also allowed
+ m << 1.0,2.0,
+ 3.0,4.0;
+
+ // print values to standard output
+ cout << m << endl;
+}
diff --git a/doc/examples/Tutorial_ArrayClass_addition.cpp b/doc/examples/Tutorial_ArrayClass_addition.cpp
new file mode 100644
index 000000000..480ffb00f
--- /dev/null
+++ b/doc/examples/Tutorial_ArrayClass_addition.cpp
@@ -0,0 +1,23 @@
+#include <Eigen/Dense>
+#include <iostream>
+
+using namespace Eigen;
+using namespace std;
+
+int main()
+{
+ ArrayXXf a(3,3);
+ ArrayXXf b(3,3);
+ a << 1,2,3,
+ 4,5,6,
+ 7,8,9;
+ b << 1,2,3,
+ 1,2,3,
+ 1,2,3;
+
+ // Adding two arrays
+ cout << "a + b = " << endl << a + b << endl << endl;
+
+ // Subtracting a scalar from an array
+ cout << "a - 2 = " << endl << a - 2 << endl;
+}
diff --git a/doc/examples/Tutorial_ArrayClass_cwise_other.cpp b/doc/examples/Tutorial_ArrayClass_cwise_other.cpp
new file mode 100644
index 000000000..d9046c63d
--- /dev/null
+++ b/doc/examples/Tutorial_ArrayClass_cwise_other.cpp
@@ -0,0 +1,19 @@
+#include <Eigen/Dense>
+#include <iostream>
+
+using namespace Eigen;
+using namespace std;
+
+int main()
+{
+ ArrayXf a = ArrayXf::Random(5);
+ a *= 2;
+ cout << "a =" << endl
+ << a << endl;
+ cout << "a.abs() =" << endl
+ << a.abs() << endl;
+ cout << "a.abs().sqrt() =" << endl
+ << a.abs().sqrt() << endl;
+ cout << "a.min(a.abs().sqrt()) =" << endl
+ << a.min(a.abs().sqrt()) << endl;
+}
diff --git a/doc/examples/Tutorial_ArrayClass_interop.cpp b/doc/examples/Tutorial_ArrayClass_interop.cpp
new file mode 100644
index 000000000..371f07068
--- /dev/null
+++ b/doc/examples/Tutorial_ArrayClass_interop.cpp
@@ -0,0 +1,22 @@
+#include <Eigen/Dense>
+#include <iostream>
+
+using namespace Eigen;
+using namespace std;
+
+int main()
+{
+ MatrixXf m(2,2);
+ MatrixXf n(2,2);
+ MatrixXf result(2,2);
+
+ m << 1,2,
+ 3,4;
+ n << 5,6,
+ 7,8;
+
+ result = (m.array() + 4).matrix() * m;
+ cout << "-- Combination 1: --" << endl << result << endl << endl;
+ result = (m.array() * n.array()).matrix() * m;
+ cout << "-- Combination 2: --" << endl << result << endl << endl;
+}
diff --git a/doc/examples/Tutorial_ArrayClass_interop_matrix.cpp b/doc/examples/Tutorial_ArrayClass_interop_matrix.cpp
new file mode 100644
index 000000000..101427511
--- /dev/null
+++ b/doc/examples/Tutorial_ArrayClass_interop_matrix.cpp
@@ -0,0 +1,26 @@
+#include <Eigen/Dense>
+#include <iostream>
+
+using namespace Eigen;
+using namespace std;
+
+int main()
+{
+ MatrixXf m(2,2);
+ MatrixXf n(2,2);
+ MatrixXf result(2,2);
+
+ m << 1,2,
+ 3,4;
+ n << 5,6,
+ 7,8;
+
+ result = m * n;
+ cout << "-- Matrix m*n: --" << endl << result << endl << endl;
+ result = m.array() * n.array();
+ cout << "-- Array m*n: --" << endl << result << endl << endl;
+ result = m.cwiseProduct(n);
+ cout << "-- With cwiseProduct: --" << endl << result << endl << endl;
+ result = m.array() + 4;
+ cout << "-- Array m + 4: --" << endl << result << endl << endl;
+}
diff --git a/doc/examples/Tutorial_ArrayClass_mult.cpp b/doc/examples/Tutorial_ArrayClass_mult.cpp
new file mode 100644
index 000000000..6cb439ff7
--- /dev/null
+++ b/doc/examples/Tutorial_ArrayClass_mult.cpp
@@ -0,0 +1,16 @@
+#include <Eigen/Dense>
+#include <iostream>
+
+using namespace Eigen;
+using namespace std;
+
+int main()
+{
+ ArrayXXf a(2,2);
+ ArrayXXf b(2,2);
+ a << 1,2,
+ 3,4;
+ b << 5,6,
+ 7,8;
+ cout << "a * b = " << endl << a * b << endl;
+}
diff --git a/doc/examples/Tutorial_BlockOperations_block_assignment.cpp b/doc/examples/Tutorial_BlockOperations_block_assignment.cpp
new file mode 100644
index 000000000..76f49f2fb
--- /dev/null
+++ b/doc/examples/Tutorial_BlockOperations_block_assignment.cpp
@@ -0,0 +1,18 @@
+#include <Eigen/Dense>
+#include <iostream>
+
+using namespace std;
+using namespace Eigen;
+
+int main()
+{
+ Array22f m;
+ m << 1,2,
+ 3,4;
+ Array44f a = Array44f::Constant(0.6);
+ cout << "Here is the array a:" << endl << a << endl << endl;
+ a.block<2,2>(1,1) = m;
+ cout << "Here is now a with m copied into its central 2x2 block:" << endl << a << endl << endl;
+ a.block(0,0,2,3) = a.block(2,1,2,3);
+ cout << "Here is now a with bottom-right 2x3 block copied into top-left 2x2 block:" << endl << a << endl << endl;
+}
diff --git a/doc/examples/Tutorial_BlockOperations_colrow.cpp b/doc/examples/Tutorial_BlockOperations_colrow.cpp
new file mode 100644
index 000000000..2e7eb009b
--- /dev/null
+++ b/doc/examples/Tutorial_BlockOperations_colrow.cpp
@@ -0,0 +1,17 @@
+#include <Eigen/Dense>
+#include <iostream>
+
+using namespace std;
+
+int main()
+{
+ Eigen::MatrixXf m(3,3);
+ m << 1,2,3,
+ 4,5,6,
+ 7,8,9;
+ cout << "Here is the matrix m:" << endl << m << endl;
+ cout << "2nd Row: " << m.row(1) << endl;
+ m.col(2) += 3 * m.col(0);
+ cout << "After adding 3 times the first column into the third column, the matrix m is:\n";
+ cout << m << endl;
+}
diff --git a/doc/examples/Tutorial_BlockOperations_corner.cpp b/doc/examples/Tutorial_BlockOperations_corner.cpp
new file mode 100644
index 000000000..3a31507aa
--- /dev/null
+++ b/doc/examples/Tutorial_BlockOperations_corner.cpp
@@ -0,0 +1,17 @@
+#include <Eigen/Dense>
+#include <iostream>
+
+using namespace std;
+
+int main()
+{
+ Eigen::Matrix4f m;
+ m << 1, 2, 3, 4,
+ 5, 6, 7, 8,
+ 9, 10,11,12,
+ 13,14,15,16;
+ cout << "m.leftCols(2) =" << endl << m.leftCols(2) << endl << endl;
+ cout << "m.bottomRows<2>() =" << endl << m.bottomRows<2>() << endl << endl;
+ m.topLeftCorner(1,3) = m.bottomRightCorner(3,1).transpose();
+ cout << "After assignment, m = " << endl << m << endl;
+}
diff --git a/doc/examples/Tutorial_BlockOperations_print_block.cpp b/doc/examples/Tutorial_BlockOperations_print_block.cpp
new file mode 100644
index 000000000..edea4aefe
--- /dev/null
+++ b/doc/examples/Tutorial_BlockOperations_print_block.cpp
@@ -0,0 +1,20 @@
+#include <Eigen/Dense>
+#include <iostream>
+
+using namespace std;
+
+int main()
+{
+ Eigen::MatrixXf m(4,4);
+ m << 1, 2, 3, 4,
+ 5, 6, 7, 8,
+ 9,10,11,12,
+ 13,14,15,16;
+ cout << "Block in the middle" << endl;
+ cout << m.block<2,2>(1,1) << endl << endl;
+ for (int i = 1; i <= 3; ++i)
+ {
+ cout << "Block of size " << i << "x" << i << endl;
+ cout << m.block(0,0,i,i) << endl << endl;
+ }
+}
diff --git a/doc/examples/Tutorial_BlockOperations_vector.cpp b/doc/examples/Tutorial_BlockOperations_vector.cpp
new file mode 100644
index 000000000..4a0b02342
--- /dev/null
+++ b/doc/examples/Tutorial_BlockOperations_vector.cpp
@@ -0,0 +1,14 @@
+#include <Eigen/Dense>
+#include <iostream>
+
+using namespace std;
+
+int main()
+{
+ Eigen::ArrayXf v(6);
+ v << 1, 2, 3, 4, 5, 6;
+ cout << "v.head(3) =" << endl << v.head(3) << endl << endl;
+ cout << "v.tail<3>() = " << endl << v.tail<3>() << endl << endl;
+ v.segment(1,4) *= 2;
+ cout << "after 'v.segment(1,4) *= 2', v =" << endl << v << endl;
+}
diff --git a/doc/examples/Tutorial_PartialLU_solve.cpp b/doc/examples/Tutorial_PartialLU_solve.cpp
new file mode 100644
index 000000000..a5608792f
--- /dev/null
+++ b/doc/examples/Tutorial_PartialLU_solve.cpp
@@ -0,0 +1,18 @@
+#include <Eigen/Core>
+#include <Eigen/LU>
+#include <iostream>
+
+using namespace std;
+using namespace Eigen;
+
+int main()
+{
+ Matrix3f A;
+ Vector3f b;
+ A << 1,2,3, 4,5,6, 7,8,10;
+ b << 3, 3, 4;
+ cout << "Here is the matrix A:" << endl << A << endl;
+ cout << "Here is the vector b:" << endl << b << endl;
+ Vector3f x = A.lu().solve(b);
+ cout << "The solution is:" << endl << x << endl;
+}
diff --git a/doc/examples/Tutorial_ReductionsVisitorsBroadcasting_broadcast_1nn.cpp b/doc/examples/Tutorial_ReductionsVisitorsBroadcasting_broadcast_1nn.cpp
new file mode 100644
index 000000000..334b4d852
--- /dev/null
+++ b/doc/examples/Tutorial_ReductionsVisitorsBroadcasting_broadcast_1nn.cpp
@@ -0,0 +1,24 @@
+#include <iostream>
+#include <Eigen/Dense>
+
+using namespace std;
+using namespace Eigen;
+
+int main()
+{
+ Eigen::MatrixXf m(2,4);
+ Eigen::VectorXf v(2);
+
+ m << 1, 23, 6, 9,
+ 3, 11, 7, 2;
+
+ v << 2,
+ 3;
+
+ MatrixXf::Index index;
+ // find nearest neighbour
+ (m.colwise() - v).colwise().squaredNorm().minCoeff(&index);
+
+ cout << "Nearest neighbour is column " << index << ":" << endl;
+ cout << m.col(index) << endl;
+}
diff --git a/doc/examples/Tutorial_ReductionsVisitorsBroadcasting_broadcast_simple.cpp b/doc/examples/Tutorial_ReductionsVisitorsBroadcasting_broadcast_simple.cpp
new file mode 100644
index 000000000..e6c87c6a4
--- /dev/null
+++ b/doc/examples/Tutorial_ReductionsVisitorsBroadcasting_broadcast_simple.cpp
@@ -0,0 +1,21 @@
+#include <iostream>
+#include <Eigen/Dense>
+
+using namespace std;
+int main()
+{
+ Eigen::MatrixXf mat(2,4);
+ Eigen::VectorXf v(2);
+
+ mat << 1, 2, 6, 9,
+ 3, 1, 7, 2;
+
+ v << 0,
+ 1;
+
+ //add v to each column of m
+ mat.colwise() += v;
+
+ std::cout << "Broadcasting result: " << std::endl;
+ std::cout << mat << std::endl;
+}
diff --git a/doc/examples/Tutorial_ReductionsVisitorsBroadcasting_broadcast_simple_rowwise.cpp b/doc/examples/Tutorial_ReductionsVisitorsBroadcasting_broadcast_simple_rowwise.cpp
new file mode 100644
index 000000000..d87c96ab1
--- /dev/null
+++ b/doc/examples/Tutorial_ReductionsVisitorsBroadcasting_broadcast_simple_rowwise.cpp
@@ -0,0 +1,20 @@
+#include <iostream>
+#include <Eigen/Dense>
+
+using namespace std;
+int main()
+{
+ Eigen::MatrixXf mat(2,4);
+ Eigen::VectorXf v(4);
+
+ mat << 1, 2, 6, 9,
+ 3, 1, 7, 2;
+
+ v << 0,1,2,3;
+
+ //add v to each row of m
+ mat.rowwise() += v.transpose();
+
+ std::cout << "Broadcasting result: " << std::endl;
+ std::cout << mat << std::endl;
+}
diff --git a/doc/examples/Tutorial_ReductionsVisitorsBroadcasting_colwise.cpp b/doc/examples/Tutorial_ReductionsVisitorsBroadcasting_colwise.cpp
new file mode 100644
index 000000000..df6825663
--- /dev/null
+++ b/doc/examples/Tutorial_ReductionsVisitorsBroadcasting_colwise.cpp
@@ -0,0 +1,13 @@
+#include <iostream>
+#include <Eigen/Dense>
+
+using namespace std;
+int main()
+{
+ Eigen::MatrixXf mat(2,4);
+ mat << 1, 2, 6, 9,
+ 3, 1, 7, 2;
+
+ std::cout << "Column's maximum: " << std::endl
+ << mat.colwise().maxCoeff() << std::endl;
+}
diff --git a/doc/examples/Tutorial_ReductionsVisitorsBroadcasting_maxnorm.cpp b/doc/examples/Tutorial_ReductionsVisitorsBroadcasting_maxnorm.cpp
new file mode 100644
index 000000000..049c747b0
--- /dev/null
+++ b/doc/examples/Tutorial_ReductionsVisitorsBroadcasting_maxnorm.cpp
@@ -0,0 +1,20 @@
+#include <iostream>
+#include <Eigen/Dense>
+
+using namespace std;
+using namespace Eigen;
+int main()
+{
+ MatrixXf mat(2,4);
+ mat << 1, 2, 6, 9,
+ 3, 1, 7, 2;
+
+ MatrixXf::Index maxIndex;
+ float maxNorm = mat.colwise().sum().maxCoeff(&maxIndex);
+
+ std::cout << "Maximum sum at position " << maxIndex << std::endl;
+
+ std::cout << "The corresponding vector is: " << std::endl;
+ std::cout << mat.col( maxIndex ) << std::endl;
+ std::cout << "And its sum is is: " << maxNorm << std::endl;
+}
diff --git a/doc/examples/Tutorial_ReductionsVisitorsBroadcasting_reductions_bool.cpp b/doc/examples/Tutorial_ReductionsVisitorsBroadcasting_reductions_bool.cpp
new file mode 100644
index 000000000..0cca37f36
--- /dev/null
+++ b/doc/examples/Tutorial_ReductionsVisitorsBroadcasting_reductions_bool.cpp
@@ -0,0 +1,21 @@
+#include <Eigen/Dense>
+#include <iostream>
+
+using namespace std;
+using namespace Eigen;
+
+int main()
+{
+ ArrayXXf a(2,2);
+
+ a << 1,2,
+ 3,4;
+
+ cout << "(a > 0).all() = " << (a > 0).all() << endl;
+ cout << "(a > 0).any() = " << (a > 0).any() << endl;
+ cout << "(a > 0).count() = " << (a > 0).count() << endl;
+ cout << endl;
+ cout << "(a > 2).all() = " << (a > 2).all() << endl;
+ cout << "(a > 2).any() = " << (a > 2).any() << endl;
+ cout << "(a > 2).count() = " << (a > 2).count() << endl;
+}
diff --git a/doc/examples/Tutorial_ReductionsVisitorsBroadcasting_reductions_norm.cpp b/doc/examples/Tutorial_ReductionsVisitorsBroadcasting_reductions_norm.cpp
new file mode 100644
index 000000000..740439fb3
--- /dev/null
+++ b/doc/examples/Tutorial_ReductionsVisitorsBroadcasting_reductions_norm.cpp
@@ -0,0 +1,28 @@
+#include <Eigen/Dense>
+#include <iostream>
+
+using namespace std;
+using namespace Eigen;
+
+int main()
+{
+ VectorXf v(2);
+ MatrixXf m(2,2), n(2,2);
+
+ v << -1,
+ 2;
+
+ m << 1,-2,
+ -3,4;
+
+ cout << "v.squaredNorm() = " << v.squaredNorm() << endl;
+ cout << "v.norm() = " << v.norm() << endl;
+ cout << "v.lpNorm<1>() = " << v.lpNorm<1>() << endl;
+ cout << "v.lpNorm<Infinity>() = " << v.lpNorm<Infinity>() << endl;
+
+ cout << endl;
+ cout << "m.squaredNorm() = " << m.squaredNorm() << endl;
+ cout << "m.norm() = " << m.norm() << endl;
+ cout << "m.lpNorm<1>() = " << m.lpNorm<1>() << endl;
+ cout << "m.lpNorm<Infinity>() = " << m.lpNorm<Infinity>() << endl;
+}
diff --git a/doc/examples/Tutorial_ReductionsVisitorsBroadcasting_rowwise.cpp b/doc/examples/Tutorial_ReductionsVisitorsBroadcasting_rowwise.cpp
new file mode 100644
index 000000000..80427c9f7
--- /dev/null
+++ b/doc/examples/Tutorial_ReductionsVisitorsBroadcasting_rowwise.cpp
@@ -0,0 +1,13 @@
+#include <iostream>
+#include <Eigen/Dense>
+
+using namespace std;
+int main()
+{
+ Eigen::MatrixXf mat(2,4);
+ mat << 1, 2, 6, 9,
+ 3, 1, 7, 2;
+
+ std::cout << "Row's maximum: " << std::endl
+ << mat.rowwise().maxCoeff() << std::endl;
+}
diff --git a/doc/examples/Tutorial_ReductionsVisitorsBroadcasting_visitors.cpp b/doc/examples/Tutorial_ReductionsVisitorsBroadcasting_visitors.cpp
new file mode 100644
index 000000000..b54e9aa31
--- /dev/null
+++ b/doc/examples/Tutorial_ReductionsVisitorsBroadcasting_visitors.cpp
@@ -0,0 +1,26 @@
+#include <iostream>
+#include <Eigen/Dense>
+
+using namespace std;
+using namespace Eigen;
+
+int main()
+{
+ Eigen::MatrixXf m(2,2);
+
+ m << 1, 2,
+ 3, 4;
+
+ //get location of maximum
+ MatrixXf::Index maxRow, maxCol;
+ float max = m.maxCoeff(&maxRow, &maxCol);
+
+ //get location of minimum
+ MatrixXf::Index minRow, minCol;
+ float min = m.minCoeff(&minRow, &minCol);
+
+ cout << "Max: " << max << ", at: " <<
+ maxRow << "," << maxCol << endl;
+ cout << "Min: " << min << ", at: " <<
+ minRow << "," << minCol << endl;
+}
diff --git a/doc/examples/Tutorial_simple_example_dynamic_size.cpp b/doc/examples/Tutorial_simple_example_dynamic_size.cpp
new file mode 100644
index 000000000..0f0280e0e
--- /dev/null
+++ b/doc/examples/Tutorial_simple_example_dynamic_size.cpp
@@ -0,0 +1,22 @@
+#include <Eigen/Core>
+#include <iostream>
+
+using namespace Eigen;
+
+int main()
+{
+ for (int size=1; size<=4; ++size)
+ {
+ MatrixXi m(size,size+1); // a (size)x(size+1)-matrix of int's
+ for (int j=0; j<m.cols(); ++j) // loop over columns
+ for (int i=0; i<m.rows(); ++i) // loop over rows
+ m(i,j) = i+j*m.rows(); // to access matrix coefficients,
+ // use operator()(int,int)
+ std::cout << m << "\n\n";
+ }
+
+ VectorXf v(4); // a vector of 4 float's
+ // to access vector coefficients, use either operator () or operator []
+ v[0] = 1; v[1] = 2; v(2) = 3; v(3) = 4;
+ std::cout << "\nv:\n" << v << std::endl;
+}
diff --git a/doc/examples/Tutorial_simple_example_fixed_size.cpp b/doc/examples/Tutorial_simple_example_fixed_size.cpp
new file mode 100644
index 000000000..bc4f95d79
--- /dev/null
+++ b/doc/examples/Tutorial_simple_example_fixed_size.cpp
@@ -0,0 +1,15 @@
+#include <Eigen/Core>
+#include <iostream>
+
+using namespace Eigen;
+
+int main()
+{
+ Matrix3f m3;
+ m3 << 1, 2, 3, 4, 5, 6, 7, 8, 9;
+ Matrix4f m4 = Matrix4f::Identity();
+ Vector4i v4(1, 2, 3, 4);
+
+ std::cout << "m3\n" << m3 << "\nm4:\n"
+ << m4 << "\nv4:\n" << v4 << std::endl;
+}
diff --git a/doc/examples/class_Block.cpp b/doc/examples/class_Block.cpp
new file mode 100644
index 000000000..ace719afc
--- /dev/null
+++ b/doc/examples/class_Block.cpp
@@ -0,0 +1,27 @@
+#include <Eigen/Core>
+#include <iostream>
+using namespace Eigen;
+using namespace std;
+
+template<typename Derived>
+Eigen::Block<Derived>
+topLeftCorner(MatrixBase<Derived>& m, int rows, int cols)
+{
+ return Eigen::Block<Derived>(m.derived(), 0, 0, rows, cols);
+}
+
+template<typename Derived>
+const Eigen::Block<const Derived>
+topLeftCorner(const MatrixBase<Derived>& m, int rows, int cols)
+{
+ return Eigen::Block<const Derived>(m.derived(), 0, 0, rows, cols);
+}
+
+int main(int, char**)
+{
+ Matrix4d m = Matrix4d::Identity();
+ cout << topLeftCorner(4*m, 2, 3) << endl; // calls the const version
+ topLeftCorner(m, 2, 3) *= 5; // calls the non-const version
+ cout << "Now the matrix m is:" << endl << m << endl;
+ return 0;
+}
diff --git a/doc/examples/class_CwiseBinaryOp.cpp b/doc/examples/class_CwiseBinaryOp.cpp
new file mode 100644
index 000000000..682af46de
--- /dev/null
+++ b/doc/examples/class_CwiseBinaryOp.cpp
@@ -0,0 +1,18 @@
+#include <Eigen/Core>
+#include <iostream>
+using namespace Eigen;
+using namespace std;
+
+// define a custom template binary functor
+template<typename Scalar> struct MakeComplexOp {
+ EIGEN_EMPTY_STRUCT_CTOR(MakeComplexOp)
+ typedef complex<Scalar> result_type;
+ complex<Scalar> operator()(const Scalar& a, const Scalar& b) const { return complex<Scalar>(a,b); }
+};
+
+int main(int, char**)
+{
+ Matrix4d m1 = Matrix4d::Random(), m2 = Matrix4d::Random();
+ cout << m1.binaryExpr(m2, MakeComplexOp<double>()) << endl;
+ return 0;
+}
diff --git a/doc/examples/class_CwiseUnaryOp.cpp b/doc/examples/class_CwiseUnaryOp.cpp
new file mode 100644
index 000000000..a5fcc153d
--- /dev/null
+++ b/doc/examples/class_CwiseUnaryOp.cpp
@@ -0,0 +1,19 @@
+#include <Eigen/Core>
+#include <iostream>
+using namespace Eigen;
+using namespace std;
+
+// define a custom template unary functor
+template<typename Scalar>
+struct CwiseClampOp {
+ CwiseClampOp(const Scalar& inf, const Scalar& sup) : m_inf(inf), m_sup(sup) {}
+ const Scalar operator()(const Scalar& x) const { return x<m_inf ? m_inf : (x>m_sup ? m_sup : x); }
+ Scalar m_inf, m_sup;
+};
+
+int main(int, char**)
+{
+ Matrix4d m1 = Matrix4d::Random();
+ cout << m1 << endl << "becomes: " << endl << m1.unaryExpr(CwiseClampOp<double>(-0.5,0.5)) << endl;
+ return 0;
+}
diff --git a/doc/examples/class_CwiseUnaryOp_ptrfun.cpp b/doc/examples/class_CwiseUnaryOp_ptrfun.cpp
new file mode 100644
index 000000000..36706d8ed
--- /dev/null
+++ b/doc/examples/class_CwiseUnaryOp_ptrfun.cpp
@@ -0,0 +1,20 @@
+#include <Eigen/Core>
+#include <iostream>
+using namespace Eigen;
+using namespace std;
+
+// define function to be applied coefficient-wise
+double ramp(double x)
+{
+ if (x > 0)
+ return x;
+ else
+ return 0;
+}
+
+int main(int, char**)
+{
+ Matrix4d m1 = Matrix4d::Random();
+ cout << m1 << endl << "becomes: " << endl << m1.unaryExpr(ptr_fun(ramp)) << endl;
+ return 0;
+}
diff --git a/doc/examples/class_FixedBlock.cpp b/doc/examples/class_FixedBlock.cpp
new file mode 100644
index 000000000..9978b32e8
--- /dev/null
+++ b/doc/examples/class_FixedBlock.cpp
@@ -0,0 +1,27 @@
+#include <Eigen/Core>
+#include <iostream>
+using namespace Eigen;
+using namespace std;
+
+template<typename Derived>
+Eigen::Block<Derived, 2, 2>
+topLeft2x2Corner(MatrixBase<Derived>& m)
+{
+ return Eigen::Block<Derived, 2, 2>(m.derived(), 0, 0);
+}
+
+template<typename Derived>
+const Eigen::Block<const Derived, 2, 2>
+topLeft2x2Corner(const MatrixBase<Derived>& m)
+{
+ return Eigen::Block<const Derived, 2, 2>(m.derived(), 0, 0);
+}
+
+int main(int, char**)
+{
+ Matrix3d m = Matrix3d::Identity();
+ cout << topLeft2x2Corner(4*m) << endl; // calls the const version
+ topLeft2x2Corner(m) *= 2; // calls the non-const version
+ cout << "Now the matrix m is:" << endl << m << endl;
+ return 0;
+}
diff --git a/doc/examples/class_FixedVectorBlock.cpp b/doc/examples/class_FixedVectorBlock.cpp
new file mode 100644
index 000000000..c88c9fbf1
--- /dev/null
+++ b/doc/examples/class_FixedVectorBlock.cpp
@@ -0,0 +1,27 @@
+#include <Eigen/Core>
+#include <iostream>
+using namespace Eigen;
+using namespace std;
+
+template<typename Derived>
+Eigen::VectorBlock<Derived, 2>
+firstTwo(MatrixBase<Derived>& v)
+{
+ return Eigen::VectorBlock<Derived, 2>(v.derived(), 0);
+}
+
+template<typename Derived>
+const Eigen::VectorBlock<const Derived, 2>
+firstTwo(const MatrixBase<Derived>& v)
+{
+ return Eigen::VectorBlock<const Derived, 2>(v.derived(), 0);
+}
+
+int main(int, char**)
+{
+ Matrix<int,1,6> v; v << 1,2,3,4,5,6;
+ cout << firstTwo(4*v) << endl; // calls the const version
+ firstTwo(v) *= 2; // calls the non-const version
+ cout << "Now the vector v is:" << endl << v << endl;
+ return 0;
+}
diff --git a/doc/examples/class_VectorBlock.cpp b/doc/examples/class_VectorBlock.cpp
new file mode 100644
index 000000000..dc213df20
--- /dev/null
+++ b/doc/examples/class_VectorBlock.cpp
@@ -0,0 +1,27 @@
+#include <Eigen/Core>
+#include <iostream>
+using namespace Eigen;
+using namespace std;
+
+template<typename Derived>
+Eigen::VectorBlock<Derived>
+segmentFromRange(MatrixBase<Derived>& v, int start, int end)
+{
+ return Eigen::VectorBlock<Derived>(v.derived(), start, end-start);
+}
+
+template<typename Derived>
+const Eigen::VectorBlock<const Derived>
+segmentFromRange(const MatrixBase<Derived>& v, int start, int end)
+{
+ return Eigen::VectorBlock<const Derived>(v.derived(), start, end-start);
+}
+
+int main(int, char**)
+{
+ Matrix<int,1,6> v; v << 1,2,3,4,5,6;
+ cout << segmentFromRange(2*v, 2, 4) << endl; // calls the const version
+ segmentFromRange(v, 1, 3) *= 5; // calls the non-const version
+ cout << "Now the vector v is:" << endl << v << endl;
+ return 0;
+}
diff --git a/doc/examples/function_taking_eigenbase.cpp b/doc/examples/function_taking_eigenbase.cpp
new file mode 100644
index 000000000..49d94b3d6
--- /dev/null
+++ b/doc/examples/function_taking_eigenbase.cpp
@@ -0,0 +1,18 @@
+#include <iostream>
+#include <Eigen/Core>
+using namespace Eigen;
+
+template <typename Derived>
+void print_size(const EigenBase<Derived>& b)
+{
+ std::cout << "size (rows, cols): " << b.size() << " (" << b.rows()
+ << ", " << b.cols() << ")" << std::endl;
+}
+
+int main()
+{
+ Vector3f v;
+ print_size(v);
+ // v.asDiagonal() returns a 3x3 diagonal matrix pseudo-expression
+ print_size(v.asDiagonal());
+}
diff --git a/doc/examples/tut_arithmetic_add_sub.cpp b/doc/examples/tut_arithmetic_add_sub.cpp
new file mode 100644
index 000000000..e97477b6e
--- /dev/null
+++ b/doc/examples/tut_arithmetic_add_sub.cpp
@@ -0,0 +1,22 @@
+#include <iostream>
+#include <Eigen/Dense>
+
+using namespace Eigen;
+
+int main()
+{
+ Matrix2d a;
+ a << 1, 2,
+ 3, 4;
+ MatrixXd b(2,2);
+ b << 2, 3,
+ 1, 4;
+ std::cout << "a + b =\n" << a + b << std::endl;
+ std::cout << "a - b =\n" << a - b << std::endl;
+ std::cout << "Doing a += b;" << std::endl;
+ a += b;
+ std::cout << "Now a =\n" << a << std::endl;
+ Vector3d v(1,2,3);
+ Vector3d w(1,0,0);
+ std::cout << "-v + w - v =\n" << -v + w - v << std::endl;
+}
diff --git a/doc/examples/tut_arithmetic_dot_cross.cpp b/doc/examples/tut_arithmetic_dot_cross.cpp
new file mode 100644
index 000000000..631c9a5e0
--- /dev/null
+++ b/doc/examples/tut_arithmetic_dot_cross.cpp
@@ -0,0 +1,15 @@
+#include <iostream>
+#include <Eigen/Dense>
+
+using namespace Eigen;
+using namespace std;
+int main()
+{
+ Vector3d v(1,2,3);
+ Vector3d w(0,1,2);
+
+ cout << "Dot product: " << v.dot(w) << endl;
+ double dp = v.adjoint()*w; // automatic conversion of the inner product to a scalar
+ cout << "Dot product via a matrix product: " << dp << endl;
+ cout << "Cross product:\n" << v.cross(w) << endl;
+}
diff --git a/doc/examples/tut_arithmetic_matrix_mul.cpp b/doc/examples/tut_arithmetic_matrix_mul.cpp
new file mode 100644
index 000000000..f21390241
--- /dev/null
+++ b/doc/examples/tut_arithmetic_matrix_mul.cpp
@@ -0,0 +1,19 @@
+#include <iostream>
+#include <Eigen/Dense>
+
+using namespace Eigen;
+int main()
+{
+ Matrix2d mat;
+ mat << 1, 2,
+ 3, 4;
+ Vector2d u(-1,1), v(2,0);
+ std::cout << "Here is mat*mat:\n" << mat*mat << std::endl;
+ std::cout << "Here is mat*u:\n" << mat*u << std::endl;
+ std::cout << "Here is u^T*mat:\n" << u.transpose()*mat << std::endl;
+ std::cout << "Here is u^T*v:\n" << u.transpose()*v << std::endl;
+ std::cout << "Here is u*v^T:\n" << u*v.transpose() << std::endl;
+ std::cout << "Let's multiply mat by itself" << std::endl;
+ mat = mat*mat;
+ std::cout << "Now mat is mat:\n" << mat << std::endl;
+}
diff --git a/doc/examples/tut_arithmetic_redux_basic.cpp b/doc/examples/tut_arithmetic_redux_basic.cpp
new file mode 100644
index 000000000..5632fb52e
--- /dev/null
+++ b/doc/examples/tut_arithmetic_redux_basic.cpp
@@ -0,0 +1,16 @@
+#include <iostream>
+#include <Eigen/Dense>
+
+using namespace std;
+int main()
+{
+ Eigen::Matrix2d mat;
+ mat << 1, 2,
+ 3, 4;
+ cout << "Here is mat.sum(): " << mat.sum() << endl;
+ cout << "Here is mat.prod(): " << mat.prod() << endl;
+ cout << "Here is mat.mean(): " << mat.mean() << endl;
+ cout << "Here is mat.minCoeff(): " << mat.minCoeff() << endl;
+ cout << "Here is mat.maxCoeff(): " << mat.maxCoeff() << endl;
+ cout << "Here is mat.trace(): " << mat.trace() << endl;
+}
diff --git a/doc/examples/tut_arithmetic_scalar_mul_div.cpp b/doc/examples/tut_arithmetic_scalar_mul_div.cpp
new file mode 100644
index 000000000..d5f65b53e
--- /dev/null
+++ b/doc/examples/tut_arithmetic_scalar_mul_div.cpp
@@ -0,0 +1,17 @@
+#include <iostream>
+#include <Eigen/Dense>
+
+using namespace Eigen;
+
+int main()
+{
+ Matrix2d a;
+ a << 1, 2,
+ 3, 4;
+ Vector3d v(1,2,3);
+ std::cout << "a * 2.5 =\n" << a * 2.5 << std::endl;
+ std::cout << "0.1 * v =\n" << 0.1 * v << std::endl;
+ std::cout << "Doing v *= 2;" << std::endl;
+ v *= 2;
+ std::cout << "Now v =\n" << v << std::endl;
+}
diff --git a/doc/examples/tut_matrix_coefficient_accessors.cpp b/doc/examples/tut_matrix_coefficient_accessors.cpp
new file mode 100644
index 000000000..c2da17158
--- /dev/null
+++ b/doc/examples/tut_matrix_coefficient_accessors.cpp
@@ -0,0 +1,18 @@
+#include <iostream>
+#include <Eigen/Dense>
+
+using namespace Eigen;
+
+int main()
+{
+ MatrixXd m(2,2);
+ m(0,0) = 3;
+ m(1,0) = 2.5;
+ m(0,1) = -1;
+ m(1,1) = m(1,0) + m(0,1);
+ std::cout << "Here is the matrix m:\n" << m << std::endl;
+ VectorXd v(2);
+ v(0) = 4;
+ v(1) = v(0) - 1;
+ std::cout << "Here is the vector v:\n" << v << std::endl;
+}
diff --git a/doc/examples/tut_matrix_resize.cpp b/doc/examples/tut_matrix_resize.cpp
new file mode 100644
index 000000000..0392c3aa5
--- /dev/null
+++ b/doc/examples/tut_matrix_resize.cpp
@@ -0,0 +1,18 @@
+#include <iostream>
+#include <Eigen/Dense>
+
+using namespace Eigen;
+
+int main()
+{
+ MatrixXd m(2,5);
+ m.resize(4,3);
+ std::cout << "The matrix m is of size "
+ << m.rows() << "x" << m.cols() << std::endl;
+ std::cout << "It has " << m.size() << " coefficients" << std::endl;
+ VectorXd v(2);
+ v.resize(5);
+ std::cout << "The vector v is of size " << v.size() << std::endl;
+ std::cout << "As a matrix, v is of size "
+ << v.rows() << "x" << v.cols() << std::endl;
+}
diff --git a/doc/examples/tut_matrix_resize_fixed_size.cpp b/doc/examples/tut_matrix_resize_fixed_size.cpp
new file mode 100644
index 000000000..dcbdfa783
--- /dev/null
+++ b/doc/examples/tut_matrix_resize_fixed_size.cpp
@@ -0,0 +1,12 @@
+#include <iostream>
+#include <Eigen/Dense>
+
+using namespace Eigen;
+
+int main()
+{
+ Matrix4d m;
+ m.resize(4,4); // no operation
+ std::cout << "The matrix m is of size "
+ << m.rows() << "x" << m.cols() << std::endl;
+}
diff --git a/doc/snippets/.krazy b/doc/snippets/.krazy
new file mode 100644
index 000000000..00b99405d
--- /dev/null
+++ b/doc/snippets/.krazy
@@ -0,0 +1,2 @@
+EXCLUDE copyright
+EXCLUDE license
diff --git a/doc/snippets/AngleAxis_mimic_euler.cpp b/doc/snippets/AngleAxis_mimic_euler.cpp
new file mode 100644
index 000000000..456de7f7e
--- /dev/null
+++ b/doc/snippets/AngleAxis_mimic_euler.cpp
@@ -0,0 +1,5 @@
+Matrix3f m;
+m = AngleAxisf(0.25*M_PI, Vector3f::UnitX())
+ * AngleAxisf(0.5*M_PI, Vector3f::UnitY())
+ * AngleAxisf(0.33*M_PI, Vector3f::UnitZ());
+cout << m << endl << "is unitary: " << m.isUnitary() << endl;
diff --git a/doc/snippets/CMakeLists.txt b/doc/snippets/CMakeLists.txt
new file mode 100644
index 000000000..92a22ea61
--- /dev/null
+++ b/doc/snippets/CMakeLists.txt
@@ -0,0 +1,30 @@
+file(GLOB snippets_SRCS "*.cpp")
+
+add_custom_target(all_snippets)
+
+foreach(snippet_src ${snippets_SRCS})
+ get_filename_component(snippet ${snippet_src} NAME_WE)
+ set(compile_snippet_target compile_${snippet})
+ set(compile_snippet_src ${compile_snippet_target}.cpp)
+ file(READ ${snippet_src} snippet_source_code)
+ configure_file(${CMAKE_CURRENT_SOURCE_DIR}/compile_snippet.cpp.in
+ ${CMAKE_CURRENT_BINARY_DIR}/${compile_snippet_src})
+ add_executable(${compile_snippet_target}
+ ${CMAKE_CURRENT_BINARY_DIR}/${compile_snippet_src})
+ if(EIGEN_STANDARD_LIBRARIES_TO_LINK_TO)
+ target_link_libraries(${compile_snippet_target} ${EIGEN_STANDARD_LIBRARIES_TO_LINK_TO})
+ endif()
+ get_target_property(compile_snippet_executable
+ ${compile_snippet_target} LOCATION)
+ add_custom_command(
+ TARGET ${compile_snippet_target}
+ POST_BUILD
+ COMMAND ${compile_snippet_executable}
+ ARGS >${CMAKE_CURRENT_BINARY_DIR}/${snippet}.out
+ )
+ add_dependencies(all_snippets ${compile_snippet_target})
+ set_source_files_properties(${CMAKE_CURRENT_BINARY_DIR}/${compile_snippet_src}
+ PROPERTIES OBJECT_DEPENDS ${snippet_src})
+endforeach(snippet_src)
+
+ei_add_target_property(compile_tut_arithmetic_transpose_aliasing COMPILE_FLAGS -DEIGEN_NO_DEBUG) \ No newline at end of file
diff --git a/doc/snippets/ColPivHouseholderQR_solve.cpp b/doc/snippets/ColPivHouseholderQR_solve.cpp
new file mode 100644
index 000000000..b7b204a18
--- /dev/null
+++ b/doc/snippets/ColPivHouseholderQR_solve.cpp
@@ -0,0 +1,8 @@
+Matrix3f m = Matrix3f::Random();
+Matrix3f y = Matrix3f::Random();
+cout << "Here is the matrix m:" << endl << m << endl;
+cout << "Here is the matrix y:" << endl << y << endl;
+Matrix3f x;
+x = m.colPivHouseholderQr().solve(y);
+assert(y.isApprox(m*x));
+cout << "Here is a solution x to the equation mx=y:" << endl << x << endl;
diff --git a/doc/snippets/ComplexEigenSolver_compute.cpp b/doc/snippets/ComplexEigenSolver_compute.cpp
new file mode 100644
index 000000000..11d6bd399
--- /dev/null
+++ b/doc/snippets/ComplexEigenSolver_compute.cpp
@@ -0,0 +1,16 @@
+MatrixXcf A = MatrixXcf::Random(4,4);
+cout << "Here is a random 4x4 matrix, A:" << endl << A << endl << endl;
+
+ComplexEigenSolver<MatrixXcf> ces;
+ces.compute(A);
+cout << "The eigenvalues of A are:" << endl << ces.eigenvalues() << endl;
+cout << "The matrix of eigenvectors, V, is:" << endl << ces.eigenvectors() << endl << endl;
+
+complex<float> lambda = ces.eigenvalues()[0];
+cout << "Consider the first eigenvalue, lambda = " << lambda << endl;
+VectorXcf v = ces.eigenvectors().col(0);
+cout << "If v is the corresponding eigenvector, then lambda * v = " << endl << lambda * v << endl;
+cout << "... and A * v = " << endl << A * v << endl << endl;
+
+cout << "Finally, V * D * V^(-1) = " << endl
+ << ces.eigenvectors() * ces.eigenvalues().asDiagonal() * ces.eigenvectors().inverse() << endl;
diff --git a/doc/snippets/ComplexEigenSolver_eigenvalues.cpp b/doc/snippets/ComplexEigenSolver_eigenvalues.cpp
new file mode 100644
index 000000000..5509bd897
--- /dev/null
+++ b/doc/snippets/ComplexEigenSolver_eigenvalues.cpp
@@ -0,0 +1,4 @@
+MatrixXcf ones = MatrixXcf::Ones(3,3);
+ComplexEigenSolver<MatrixXcf> ces(ones, /* computeEigenvectors = */ false);
+cout << "The eigenvalues of the 3x3 matrix of ones are:"
+ << endl << ces.eigenvalues() << endl;
diff --git a/doc/snippets/ComplexEigenSolver_eigenvectors.cpp b/doc/snippets/ComplexEigenSolver_eigenvectors.cpp
new file mode 100644
index 000000000..bb1c2ccf1
--- /dev/null
+++ b/doc/snippets/ComplexEigenSolver_eigenvectors.cpp
@@ -0,0 +1,4 @@
+MatrixXcf ones = MatrixXcf::Ones(3,3);
+ComplexEigenSolver<MatrixXcf> ces(ones);
+cout << "The first eigenvector of the 3x3 matrix of ones is:"
+ << endl << ces.eigenvectors().col(1) << endl;
diff --git a/doc/snippets/ComplexSchur_compute.cpp b/doc/snippets/ComplexSchur_compute.cpp
new file mode 100644
index 000000000..3a5170101
--- /dev/null
+++ b/doc/snippets/ComplexSchur_compute.cpp
@@ -0,0 +1,6 @@
+MatrixXcf A = MatrixXcf::Random(4,4);
+ComplexSchur<MatrixXcf> schur(4);
+schur.compute(A);
+cout << "The matrix T in the decomposition of A is:" << endl << schur.matrixT() << endl;
+schur.compute(A.inverse());
+cout << "The matrix T in the decomposition of A^(-1) is:" << endl << schur.matrixT() << endl;
diff --git a/doc/snippets/ComplexSchur_matrixT.cpp b/doc/snippets/ComplexSchur_matrixT.cpp
new file mode 100644
index 000000000..8380571ac
--- /dev/null
+++ b/doc/snippets/ComplexSchur_matrixT.cpp
@@ -0,0 +1,4 @@
+MatrixXcf A = MatrixXcf::Random(4,4);
+cout << "Here is a random 4x4 matrix, A:" << endl << A << endl << endl;
+ComplexSchur<MatrixXcf> schurOfA(A, false); // false means do not compute U
+cout << "The triangular matrix T is:" << endl << schurOfA.matrixT() << endl;
diff --git a/doc/snippets/ComplexSchur_matrixU.cpp b/doc/snippets/ComplexSchur_matrixU.cpp
new file mode 100644
index 000000000..ba3d9c22e
--- /dev/null
+++ b/doc/snippets/ComplexSchur_matrixU.cpp
@@ -0,0 +1,4 @@
+MatrixXcf A = MatrixXcf::Random(4,4);
+cout << "Here is a random 4x4 matrix, A:" << endl << A << endl << endl;
+ComplexSchur<MatrixXcf> schurOfA(A);
+cout << "The unitary matrix U is:" << endl << schurOfA.matrixU() << endl;
diff --git a/doc/snippets/Cwise_abs.cpp b/doc/snippets/Cwise_abs.cpp
new file mode 100644
index 000000000..0aeec3a40
--- /dev/null
+++ b/doc/snippets/Cwise_abs.cpp
@@ -0,0 +1,2 @@
+Array3d v(1,-2,-3);
+cout << v.abs() << endl;
diff --git a/doc/snippets/Cwise_abs2.cpp b/doc/snippets/Cwise_abs2.cpp
new file mode 100644
index 000000000..2c4f9b344
--- /dev/null
+++ b/doc/snippets/Cwise_abs2.cpp
@@ -0,0 +1,2 @@
+Array3d v(1,-2,-3);
+cout << v.abs2() << endl;
diff --git a/doc/snippets/Cwise_acos.cpp b/doc/snippets/Cwise_acos.cpp
new file mode 100644
index 000000000..34432cbac
--- /dev/null
+++ b/doc/snippets/Cwise_acos.cpp
@@ -0,0 +1,2 @@
+Array3d v(0, sqrt(2.)/2, 1);
+cout << v.acos() << endl;
diff --git a/doc/snippets/Cwise_boolean_and.cpp b/doc/snippets/Cwise_boolean_and.cpp
new file mode 100644
index 000000000..df6b60d92
--- /dev/null
+++ b/doc/snippets/Cwise_boolean_and.cpp
@@ -0,0 +1,2 @@
+Array3d v(-1,2,1), w(-3,2,3);
+cout << ((v<w) && (v<0)) << endl;
diff --git a/doc/snippets/Cwise_boolean_or.cpp b/doc/snippets/Cwise_boolean_or.cpp
new file mode 100644
index 000000000..83eb0068e
--- /dev/null
+++ b/doc/snippets/Cwise_boolean_or.cpp
@@ -0,0 +1,2 @@
+Array3d v(-1,2,1), w(-3,2,3);
+cout << ((v<w) || (v<0)) << endl;
diff --git a/doc/snippets/Cwise_cos.cpp b/doc/snippets/Cwise_cos.cpp
new file mode 100644
index 000000000..f589f0724
--- /dev/null
+++ b/doc/snippets/Cwise_cos.cpp
@@ -0,0 +1,2 @@
+Array3d v(M_PI, M_PI/2, M_PI/3);
+cout << v.cos() << endl;
diff --git a/doc/snippets/Cwise_cube.cpp b/doc/snippets/Cwise_cube.cpp
new file mode 100644
index 000000000..85e41dcce
--- /dev/null
+++ b/doc/snippets/Cwise_cube.cpp
@@ -0,0 +1,2 @@
+Array3d v(2,3,4);
+cout << v.cube() << endl;
diff --git a/doc/snippets/Cwise_equal_equal.cpp b/doc/snippets/Cwise_equal_equal.cpp
new file mode 100644
index 000000000..0ba96f660
--- /dev/null
+++ b/doc/snippets/Cwise_equal_equal.cpp
@@ -0,0 +1,2 @@
+Array3d v(1,2,3), w(3,2,1);
+cout << (v==w) << endl;
diff --git a/doc/snippets/Cwise_exp.cpp b/doc/snippets/Cwise_exp.cpp
new file mode 100644
index 000000000..db23618f9
--- /dev/null
+++ b/doc/snippets/Cwise_exp.cpp
@@ -0,0 +1,2 @@
+Array3d v(1,2,3);
+cout << v.exp() << endl;
diff --git a/doc/snippets/Cwise_greater.cpp b/doc/snippets/Cwise_greater.cpp
new file mode 100644
index 000000000..40ad0296d
--- /dev/null
+++ b/doc/snippets/Cwise_greater.cpp
@@ -0,0 +1,2 @@
+Array3d v(1,2,3), w(3,2,1);
+cout << (v>w) << endl;
diff --git a/doc/snippets/Cwise_greater_equal.cpp b/doc/snippets/Cwise_greater_equal.cpp
new file mode 100644
index 000000000..6a08f8948
--- /dev/null
+++ b/doc/snippets/Cwise_greater_equal.cpp
@@ -0,0 +1,2 @@
+Array3d v(1,2,3), w(3,2,1);
+cout << (v>=w) << endl;
diff --git a/doc/snippets/Cwise_inverse.cpp b/doc/snippets/Cwise_inverse.cpp
new file mode 100644
index 000000000..3967a7ecf
--- /dev/null
+++ b/doc/snippets/Cwise_inverse.cpp
@@ -0,0 +1,2 @@
+Array3d v(2,3,4);
+cout << v.inverse() << endl;
diff --git a/doc/snippets/Cwise_less.cpp b/doc/snippets/Cwise_less.cpp
new file mode 100644
index 000000000..cafd3b6e0
--- /dev/null
+++ b/doc/snippets/Cwise_less.cpp
@@ -0,0 +1,2 @@
+Array3d v(1,2,3), w(3,2,1);
+cout << (v<w) << endl;
diff --git a/doc/snippets/Cwise_less_equal.cpp b/doc/snippets/Cwise_less_equal.cpp
new file mode 100644
index 000000000..1600e397e
--- /dev/null
+++ b/doc/snippets/Cwise_less_equal.cpp
@@ -0,0 +1,2 @@
+Array3d v(1,2,3), w(3,2,1);
+cout << (v<=w) << endl;
diff --git a/doc/snippets/Cwise_log.cpp b/doc/snippets/Cwise_log.cpp
new file mode 100644
index 000000000..f7aca72fd
--- /dev/null
+++ b/doc/snippets/Cwise_log.cpp
@@ -0,0 +1,2 @@
+Array3d v(1,2,3);
+cout << v.log() << endl;
diff --git a/doc/snippets/Cwise_max.cpp b/doc/snippets/Cwise_max.cpp
new file mode 100644
index 000000000..6602881e8
--- /dev/null
+++ b/doc/snippets/Cwise_max.cpp
@@ -0,0 +1,2 @@
+Array3d v(2,3,4), w(4,2,3);
+cout << v.max(w) << endl;
diff --git a/doc/snippets/Cwise_min.cpp b/doc/snippets/Cwise_min.cpp
new file mode 100644
index 000000000..1c01c764e
--- /dev/null
+++ b/doc/snippets/Cwise_min.cpp
@@ -0,0 +1,2 @@
+Array3d v(2,3,4), w(4,2,3);
+cout << v.min(w) << endl;
diff --git a/doc/snippets/Cwise_minus.cpp b/doc/snippets/Cwise_minus.cpp
new file mode 100644
index 000000000..b89b9fbb7
--- /dev/null
+++ b/doc/snippets/Cwise_minus.cpp
@@ -0,0 +1,2 @@
+Array3d v(1,2,3);
+cout << v-5 << endl;
diff --git a/doc/snippets/Cwise_minus_equal.cpp b/doc/snippets/Cwise_minus_equal.cpp
new file mode 100644
index 000000000..dfde49dc3
--- /dev/null
+++ b/doc/snippets/Cwise_minus_equal.cpp
@@ -0,0 +1,3 @@
+Array3d v(1,2,3);
+v -= 5;
+cout << v << endl;
diff --git a/doc/snippets/Cwise_not_equal.cpp b/doc/snippets/Cwise_not_equal.cpp
new file mode 100644
index 000000000..57a407aac
--- /dev/null
+++ b/doc/snippets/Cwise_not_equal.cpp
@@ -0,0 +1,2 @@
+Array3d v(1,2,3), w(3,2,1);
+cout << (v!=w) << endl;
diff --git a/doc/snippets/Cwise_plus.cpp b/doc/snippets/Cwise_plus.cpp
new file mode 100644
index 000000000..9d4732743
--- /dev/null
+++ b/doc/snippets/Cwise_plus.cpp
@@ -0,0 +1,2 @@
+Array3d v(1,2,3);
+cout << v+5 << endl;
diff --git a/doc/snippets/Cwise_plus_equal.cpp b/doc/snippets/Cwise_plus_equal.cpp
new file mode 100644
index 000000000..d744b1e89
--- /dev/null
+++ b/doc/snippets/Cwise_plus_equal.cpp
@@ -0,0 +1,3 @@
+Array3d v(1,2,3);
+v += 5;
+cout << v << endl;
diff --git a/doc/snippets/Cwise_pow.cpp b/doc/snippets/Cwise_pow.cpp
new file mode 100644
index 000000000..a723ed8b5
--- /dev/null
+++ b/doc/snippets/Cwise_pow.cpp
@@ -0,0 +1,2 @@
+Array3d v(8,27,64);
+cout << v.pow(0.333333) << endl;
diff --git a/doc/snippets/Cwise_product.cpp b/doc/snippets/Cwise_product.cpp
new file mode 100644
index 000000000..714d66d21
--- /dev/null
+++ b/doc/snippets/Cwise_product.cpp
@@ -0,0 +1,4 @@
+Array33i a = Array33i::Random(), b = Array33i::Random();
+Array33i c = a * b;
+cout << "a:\n" << a << "\nb:\n" << b << "\nc:\n" << c << endl;
+
diff --git a/doc/snippets/Cwise_quotient.cpp b/doc/snippets/Cwise_quotient.cpp
new file mode 100644
index 000000000..7cb9f7f2a
--- /dev/null
+++ b/doc/snippets/Cwise_quotient.cpp
@@ -0,0 +1,2 @@
+Array3d v(2,3,4), w(4,2,3);
+cout << v/w << endl;
diff --git a/doc/snippets/Cwise_sin.cpp b/doc/snippets/Cwise_sin.cpp
new file mode 100644
index 000000000..46fa908cb
--- /dev/null
+++ b/doc/snippets/Cwise_sin.cpp
@@ -0,0 +1,2 @@
+Array3d v(M_PI, M_PI/2, M_PI/3);
+cout << v.sin() << endl;
diff --git a/doc/snippets/Cwise_slash_equal.cpp b/doc/snippets/Cwise_slash_equal.cpp
new file mode 100644
index 000000000..2efd32d84
--- /dev/null
+++ b/doc/snippets/Cwise_slash_equal.cpp
@@ -0,0 +1,3 @@
+Array3d v(3,2,4), w(5,4,2);
+v /= w;
+cout << v << endl;
diff --git a/doc/snippets/Cwise_sqrt.cpp b/doc/snippets/Cwise_sqrt.cpp
new file mode 100644
index 000000000..97bafe8b3
--- /dev/null
+++ b/doc/snippets/Cwise_sqrt.cpp
@@ -0,0 +1,2 @@
+Array3d v(1,2,4);
+cout << v.sqrt() << endl;
diff --git a/doc/snippets/Cwise_square.cpp b/doc/snippets/Cwise_square.cpp
new file mode 100644
index 000000000..f704c5e0b
--- /dev/null
+++ b/doc/snippets/Cwise_square.cpp
@@ -0,0 +1,2 @@
+Array3d v(2,3,4);
+cout << v.square() << endl;
diff --git a/doc/snippets/Cwise_tan.cpp b/doc/snippets/Cwise_tan.cpp
new file mode 100644
index 000000000..b758ef04a
--- /dev/null
+++ b/doc/snippets/Cwise_tan.cpp
@@ -0,0 +1,2 @@
+Array3d v(M_PI, M_PI/2, M_PI/3);
+cout << v.tan() << endl;
diff --git a/doc/snippets/Cwise_times_equal.cpp b/doc/snippets/Cwise_times_equal.cpp
new file mode 100644
index 000000000..147556c73
--- /dev/null
+++ b/doc/snippets/Cwise_times_equal.cpp
@@ -0,0 +1,3 @@
+Array3d v(1,2,3), w(2,3,0);
+v *= w;
+cout << v << endl;
diff --git a/doc/snippets/DenseBase_LinSpaced.cpp b/doc/snippets/DenseBase_LinSpaced.cpp
new file mode 100644
index 000000000..8e54b17fc
--- /dev/null
+++ b/doc/snippets/DenseBase_LinSpaced.cpp
@@ -0,0 +1,2 @@
+cout << VectorXi::LinSpaced(4,7,10).transpose() << endl;
+cout << VectorXd::LinSpaced(5,0.0,1.0).transpose() << endl;
diff --git a/doc/snippets/DenseBase_LinSpaced_seq.cpp b/doc/snippets/DenseBase_LinSpaced_seq.cpp
new file mode 100644
index 000000000..f55c5085d
--- /dev/null
+++ b/doc/snippets/DenseBase_LinSpaced_seq.cpp
@@ -0,0 +1,2 @@
+cout << VectorXi::LinSpaced(Sequential,4,7,10).transpose() << endl;
+cout << VectorXd::LinSpaced(Sequential,5,0.0,1.0).transpose() << endl;
diff --git a/doc/snippets/DenseBase_setLinSpaced.cpp b/doc/snippets/DenseBase_setLinSpaced.cpp
new file mode 100644
index 000000000..50871dfcc
--- /dev/null
+++ b/doc/snippets/DenseBase_setLinSpaced.cpp
@@ -0,0 +1,3 @@
+VectorXf v;
+v.setLinSpaced(5,0.5f,1.5f).transpose();
+cout << v << endl;
diff --git a/doc/snippets/DirectionWise_replicate.cpp b/doc/snippets/DirectionWise_replicate.cpp
new file mode 100644
index 000000000..d92d4a350
--- /dev/null
+++ b/doc/snippets/DirectionWise_replicate.cpp
@@ -0,0 +1,4 @@
+MatrixXi m = MatrixXi::Random(2,3);
+cout << "Here is the matrix m:" << endl << m << endl;
+cout << "m.colwise().replicate<3>() = ..." << endl;
+cout << m.colwise().replicate<3>() << endl;
diff --git a/doc/snippets/DirectionWise_replicate_int.cpp b/doc/snippets/DirectionWise_replicate_int.cpp
new file mode 100644
index 000000000..f9b1b5355
--- /dev/null
+++ b/doc/snippets/DirectionWise_replicate_int.cpp
@@ -0,0 +1,4 @@
+Vector3i v = Vector3i::Random();
+cout << "Here is the vector v:" << endl << v << endl;
+cout << "v.rowwise().replicate(5) = ..." << endl;
+cout << v.rowwise().replicate(5) << endl;
diff --git a/doc/snippets/EigenSolver_EigenSolver_MatrixType.cpp b/doc/snippets/EigenSolver_EigenSolver_MatrixType.cpp
new file mode 100644
index 000000000..c1d9fa879
--- /dev/null
+++ b/doc/snippets/EigenSolver_EigenSolver_MatrixType.cpp
@@ -0,0 +1,16 @@
+MatrixXd A = MatrixXd::Random(6,6);
+cout << "Here is a random 6x6 matrix, A:" << endl << A << endl << endl;
+
+EigenSolver<MatrixXd> es(A);
+cout << "The eigenvalues of A are:" << endl << es.eigenvalues() << endl;
+cout << "The matrix of eigenvectors, V, is:" << endl << es.eigenvectors() << endl << endl;
+
+complex<double> lambda = es.eigenvalues()[0];
+cout << "Consider the first eigenvalue, lambda = " << lambda << endl;
+VectorXcd v = es.eigenvectors().col(0);
+cout << "If v is the corresponding eigenvector, then lambda * v = " << endl << lambda * v << endl;
+cout << "... and A * v = " << endl << A.cast<complex<double> >() * v << endl << endl;
+
+MatrixXcd D = es.eigenvalues().asDiagonal();
+MatrixXcd V = es.eigenvectors();
+cout << "Finally, V * D * V^(-1) = " << endl << V * D * V.inverse() << endl;
diff --git a/doc/snippets/EigenSolver_compute.cpp b/doc/snippets/EigenSolver_compute.cpp
new file mode 100644
index 000000000..a5c96e9b4
--- /dev/null
+++ b/doc/snippets/EigenSolver_compute.cpp
@@ -0,0 +1,6 @@
+EigenSolver<MatrixXf> es;
+MatrixXf A = MatrixXf::Random(4,4);
+es.compute(A, /* computeEigenvectors = */ false);
+cout << "The eigenvalues of A are: " << es.eigenvalues().transpose() << endl;
+es.compute(A + MatrixXf::Identity(4,4), false); // re-use es to compute eigenvalues of A+I
+cout << "The eigenvalues of A+I are: " << es.eigenvalues().transpose() << endl;
diff --git a/doc/snippets/EigenSolver_eigenvalues.cpp b/doc/snippets/EigenSolver_eigenvalues.cpp
new file mode 100644
index 000000000..ed28869a0
--- /dev/null
+++ b/doc/snippets/EigenSolver_eigenvalues.cpp
@@ -0,0 +1,4 @@
+MatrixXd ones = MatrixXd::Ones(3,3);
+EigenSolver<MatrixXd> es(ones, false);
+cout << "The eigenvalues of the 3x3 matrix of ones are:"
+ << endl << es.eigenvalues() << endl;
diff --git a/doc/snippets/EigenSolver_eigenvectors.cpp b/doc/snippets/EigenSolver_eigenvectors.cpp
new file mode 100644
index 000000000..0fad4dadb
--- /dev/null
+++ b/doc/snippets/EigenSolver_eigenvectors.cpp
@@ -0,0 +1,4 @@
+MatrixXd ones = MatrixXd::Ones(3,3);
+EigenSolver<MatrixXd> es(ones);
+cout << "The first eigenvector of the 3x3 matrix of ones is:"
+ << endl << es.eigenvectors().col(1) << endl;
diff --git a/doc/snippets/EigenSolver_pseudoEigenvectors.cpp b/doc/snippets/EigenSolver_pseudoEigenvectors.cpp
new file mode 100644
index 000000000..85e2569df
--- /dev/null
+++ b/doc/snippets/EigenSolver_pseudoEigenvectors.cpp
@@ -0,0 +1,9 @@
+MatrixXd A = MatrixXd::Random(6,6);
+cout << "Here is a random 6x6 matrix, A:" << endl << A << endl << endl;
+
+EigenSolver<MatrixXd> es(A);
+MatrixXd D = es.pseudoEigenvalueMatrix();
+MatrixXd V = es.pseudoEigenvectors();
+cout << "The pseudo-eigenvalue matrix D is:" << endl << D << endl;
+cout << "The pseudo-eigenvector matrix V is:" << endl << V << endl;
+cout << "Finally, V * D * V^(-1) = " << endl << V * D * V.inverse() << endl;
diff --git a/doc/snippets/FullPivHouseholderQR_solve.cpp b/doc/snippets/FullPivHouseholderQR_solve.cpp
new file mode 100644
index 000000000..23bc0749d
--- /dev/null
+++ b/doc/snippets/FullPivHouseholderQR_solve.cpp
@@ -0,0 +1,8 @@
+Matrix3f m = Matrix3f::Random();
+Matrix3f y = Matrix3f::Random();
+cout << "Here is the matrix m:" << endl << m << endl;
+cout << "Here is the matrix y:" << endl << y << endl;
+Matrix3f x;
+x = m.fullPivHouseholderQr().solve(y);
+assert(y.isApprox(m*x));
+cout << "Here is a solution x to the equation mx=y:" << endl << x << endl;
diff --git a/doc/snippets/FullPivLU_image.cpp b/doc/snippets/FullPivLU_image.cpp
new file mode 100644
index 000000000..817bc1e2d
--- /dev/null
+++ b/doc/snippets/FullPivLU_image.cpp
@@ -0,0 +1,9 @@
+Matrix3d m;
+m << 1,1,0,
+ 1,3,2,
+ 0,1,1;
+cout << "Here is the matrix m:" << endl << m << endl;
+cout << "Notice that the middle column is the sum of the two others, so the "
+ << "columns are linearly dependent." << endl;
+cout << "Here is a matrix whose columns have the same span but are linearly independent:"
+ << endl << m.fullPivLu().image(m) << endl;
diff --git a/doc/snippets/FullPivLU_kernel.cpp b/doc/snippets/FullPivLU_kernel.cpp
new file mode 100644
index 000000000..7086e01e2
--- /dev/null
+++ b/doc/snippets/FullPivLU_kernel.cpp
@@ -0,0 +1,7 @@
+MatrixXf m = MatrixXf::Random(3,5);
+cout << "Here is the matrix m:" << endl << m << endl;
+MatrixXf ker = m.fullPivLu().kernel();
+cout << "Here is a matrix whose columns form a basis of the kernel of m:"
+ << endl << ker << endl;
+cout << "By definition of the kernel, m*ker is zero:"
+ << endl << m*ker << endl;
diff --git a/doc/snippets/FullPivLU_solve.cpp b/doc/snippets/FullPivLU_solve.cpp
new file mode 100644
index 000000000..c1f88235e
--- /dev/null
+++ b/doc/snippets/FullPivLU_solve.cpp
@@ -0,0 +1,11 @@
+Matrix<float,2,3> m = Matrix<float,2,3>::Random();
+Matrix2f y = Matrix2f::Random();
+cout << "Here is the matrix m:" << endl << m << endl;
+cout << "Here is the matrix y:" << endl << y << endl;
+Matrix<float,3,2> x = m.fullPivLu().solve(y);
+if((m*x).isApprox(y))
+{
+ cout << "Here is a solution x to the equation mx=y:" << endl << x << endl;
+}
+else
+ cout << "The equation mx=y does not have any solution." << endl;
diff --git a/doc/snippets/HessenbergDecomposition_compute.cpp b/doc/snippets/HessenbergDecomposition_compute.cpp
new file mode 100644
index 000000000..50e37833a
--- /dev/null
+++ b/doc/snippets/HessenbergDecomposition_compute.cpp
@@ -0,0 +1,6 @@
+MatrixXcf A = MatrixXcf::Random(4,4);
+HessenbergDecomposition<MatrixXcf> hd(4);
+hd.compute(A);
+cout << "The matrix H in the decomposition of A is:" << endl << hd.matrixH() << endl;
+hd.compute(2*A); // re-use hd to compute and store decomposition of 2A
+cout << "The matrix H in the decomposition of 2A is:" << endl << hd.matrixH() << endl;
diff --git a/doc/snippets/HessenbergDecomposition_matrixH.cpp b/doc/snippets/HessenbergDecomposition_matrixH.cpp
new file mode 100644
index 000000000..af0136668
--- /dev/null
+++ b/doc/snippets/HessenbergDecomposition_matrixH.cpp
@@ -0,0 +1,8 @@
+Matrix4f A = MatrixXf::Random(4,4);
+cout << "Here is a random 4x4 matrix:" << endl << A << endl;
+HessenbergDecomposition<MatrixXf> hessOfA(A);
+MatrixXf H = hessOfA.matrixH();
+cout << "The Hessenberg matrix H is:" << endl << H << endl;
+MatrixXf Q = hessOfA.matrixQ();
+cout << "The orthogonal matrix Q is:" << endl << Q << endl;
+cout << "Q H Q^T is:" << endl << Q * H * Q.transpose() << endl;
diff --git a/doc/snippets/HessenbergDecomposition_packedMatrix.cpp b/doc/snippets/HessenbergDecomposition_packedMatrix.cpp
new file mode 100644
index 000000000..4fa5957e8
--- /dev/null
+++ b/doc/snippets/HessenbergDecomposition_packedMatrix.cpp
@@ -0,0 +1,9 @@
+Matrix4d A = Matrix4d::Random(4,4);
+cout << "Here is a random 4x4 matrix:" << endl << A << endl;
+HessenbergDecomposition<Matrix4d> hessOfA(A);
+Matrix4d pm = hessOfA.packedMatrix();
+cout << "The packed matrix M is:" << endl << pm << endl;
+cout << "The upper Hessenberg part corresponds to the matrix H, which is:"
+ << endl << hessOfA.matrixH() << endl;
+Vector3d hc = hessOfA.householderCoefficients();
+cout << "The vector of Householder coefficients is:" << endl << hc << endl;
diff --git a/doc/snippets/HouseholderQR_solve.cpp b/doc/snippets/HouseholderQR_solve.cpp
new file mode 100644
index 000000000..8cce6ce6c
--- /dev/null
+++ b/doc/snippets/HouseholderQR_solve.cpp
@@ -0,0 +1,9 @@
+typedef Matrix<float,3,3> Matrix3x3;
+Matrix3x3 m = Matrix3x3::Random();
+Matrix3f y = Matrix3f::Random();
+cout << "Here is the matrix m:" << endl << m << endl;
+cout << "Here is the matrix y:" << endl << y << endl;
+Matrix3f x;
+x = m.householderQr().solve(y);
+assert(y.isApprox(m*x));
+cout << "Here is a solution x to the equation mx=y:" << endl << x << endl;
diff --git a/doc/snippets/HouseholderSequence_HouseholderSequence.cpp b/doc/snippets/HouseholderSequence_HouseholderSequence.cpp
new file mode 100644
index 000000000..2632b83b9
--- /dev/null
+++ b/doc/snippets/HouseholderSequence_HouseholderSequence.cpp
@@ -0,0 +1,31 @@
+Matrix3d v = Matrix3d::Random();
+cout << "The matrix v is:" << endl;
+cout << v << endl;
+
+Vector3d v0(1, v(1,0), v(2,0));
+cout << "The first Householder vector is: v_0 = " << v0.transpose() << endl;
+Vector3d v1(0, 1, v(2,1));
+cout << "The second Householder vector is: v_1 = " << v1.transpose() << endl;
+Vector3d v2(0, 0, 1);
+cout << "The third Householder vector is: v_2 = " << v2.transpose() << endl;
+
+Vector3d h = Vector3d::Random();
+cout << "The Householder coefficients are: h = " << h.transpose() << endl;
+
+Matrix3d H0 = Matrix3d::Identity() - h(0) * v0 * v0.adjoint();
+cout << "The first Householder reflection is represented by H_0 = " << endl;
+cout << H0 << endl;
+Matrix3d H1 = Matrix3d::Identity() - h(1) * v1 * v1.adjoint();
+cout << "The second Householder reflection is represented by H_1 = " << endl;
+cout << H1 << endl;
+Matrix3d H2 = Matrix3d::Identity() - h(2) * v2 * v2.adjoint();
+cout << "The third Householder reflection is represented by H_2 = " << endl;
+cout << H2 << endl;
+cout << "Their product is H_0 H_1 H_2 = " << endl;
+cout << H0 * H1 * H2 << endl;
+
+HouseholderSequence<Matrix3d, Vector3d> hhSeq(v, h);
+Matrix3d hhSeqAsMatrix(hhSeq);
+cout << "If we construct a HouseholderSequence from v and h" << endl;
+cout << "and convert it to a matrix, we get:" << endl;
+cout << hhSeqAsMatrix << endl;
diff --git a/doc/snippets/IOFormat.cpp b/doc/snippets/IOFormat.cpp
new file mode 100644
index 000000000..735f5dd85
--- /dev/null
+++ b/doc/snippets/IOFormat.cpp
@@ -0,0 +1,14 @@
+std::string sep = "\n----------------------------------------\n";
+Matrix3d m1;
+m1 << 1.111111, 2, 3.33333, 4, 5, 6, 7, 8.888888, 9;
+
+IOFormat CommaInitFmt(StreamPrecision, DontAlignCols, ", ", ", ", "", "", " << ", ";");
+IOFormat CleanFmt(4, 0, ", ", "\n", "[", "]");
+IOFormat OctaveFmt(StreamPrecision, 0, ", ", ";\n", "", "", "[", "]");
+IOFormat HeavyFmt(FullPrecision, 0, ", ", ";\n", "[", "]", "[", "]");
+
+std::cout << m1 << sep;
+std::cout << m1.format(CommaInitFmt) << sep;
+std::cout << m1.format(CleanFmt) << sep;
+std::cout << m1.format(OctaveFmt) << sep;
+std::cout << m1.format(HeavyFmt) << sep;
diff --git a/doc/snippets/JacobiSVD_basic.cpp b/doc/snippets/JacobiSVD_basic.cpp
new file mode 100644
index 000000000..ab24b9bca
--- /dev/null
+++ b/doc/snippets/JacobiSVD_basic.cpp
@@ -0,0 +1,9 @@
+MatrixXf m = MatrixXf::Random(3,2);
+cout << "Here is the matrix m:" << endl << m << endl;
+JacobiSVD<MatrixXf> svd(m, ComputeThinU | ComputeThinV);
+cout << "Its singular values are:" << endl << svd.singularValues() << endl;
+cout << "Its left singular vectors are the columns of the thin U matrix:" << endl << svd.matrixU() << endl;
+cout << "Its right singular vectors are the columns of the thin V matrix:" << endl << svd.matrixV() << endl;
+Vector3f rhs(1, 0, 0);
+cout << "Now consider this rhs vector:" << endl << rhs << endl;
+cout << "A least-squares solution of m*x = rhs is:" << endl << svd.solve(rhs) << endl;
diff --git a/doc/snippets/Jacobi_makeGivens.cpp b/doc/snippets/Jacobi_makeGivens.cpp
new file mode 100644
index 000000000..4b733c306
--- /dev/null
+++ b/doc/snippets/Jacobi_makeGivens.cpp
@@ -0,0 +1,6 @@
+Vector2f v = Vector2f::Random();
+JacobiRotation<float> G;
+G.makeGivens(v.x(), v.y());
+cout << "Here is the vector v:" << endl << v << endl;
+v.applyOnTheLeft(0, 1, G.adjoint());
+cout << "Here is the vector J' * v:" << endl << v << endl; \ No newline at end of file
diff --git a/doc/snippets/Jacobi_makeJacobi.cpp b/doc/snippets/Jacobi_makeJacobi.cpp
new file mode 100644
index 000000000..0cc331d9f
--- /dev/null
+++ b/doc/snippets/Jacobi_makeJacobi.cpp
@@ -0,0 +1,8 @@
+Matrix2f m = Matrix2f::Random();
+m = (m + m.adjoint()).eval();
+JacobiRotation<float> J;
+J.makeJacobi(m, 0, 1);
+cout << "Here is the matrix m:" << endl << m << endl;
+m.applyOnTheLeft(0, 1, J.adjoint());
+m.applyOnTheRight(0, 1, J);
+cout << "Here is the matrix J' * m * J:" << endl << m << endl; \ No newline at end of file
diff --git a/doc/snippets/LLT_example.cpp b/doc/snippets/LLT_example.cpp
new file mode 100644
index 000000000..46fb40704
--- /dev/null
+++ b/doc/snippets/LLT_example.cpp
@@ -0,0 +1,12 @@
+MatrixXd A(3,3);
+A << 4,-1,2, -1,6,0, 2,0,5;
+cout << "The matrix A is" << endl << A << endl;
+
+LLT<MatrixXd> lltOfA(A); // compute the Cholesky decomposition of A
+MatrixXd L = lltOfA.matrixL(); // retrieve factor L in the decomposition
+// The previous two lines can also be written as "L = A.llt().matrixL()"
+
+cout << "The Cholesky factor L is" << endl << L << endl;
+cout << "To check this, let us compute L * L.transpose()" << endl;
+cout << L * L.transpose() << endl;
+cout << "This should equal the matrix A" << endl;
diff --git a/doc/snippets/LLT_solve.cpp b/doc/snippets/LLT_solve.cpp
new file mode 100644
index 000000000..7095d2cc3
--- /dev/null
+++ b/doc/snippets/LLT_solve.cpp
@@ -0,0 +1,8 @@
+typedef Matrix<float,Dynamic,2> DataMatrix;
+// let's generate some samples on the 3D plane of equation z = 2x+3y (with some noise)
+DataMatrix samples = DataMatrix::Random(12,2);
+VectorXf elevations = 2*samples.col(0) + 3*samples.col(1) + VectorXf::Random(12)*0.1;
+// and let's solve samples * [x y]^T = elevations in least square sense:
+Matrix<float,2,1> xy
+ = (samples.adjoint() * samples).llt().solve((samples.adjoint()*elevations));
+cout << xy << endl;
diff --git a/doc/snippets/Map_general_stride.cpp b/doc/snippets/Map_general_stride.cpp
new file mode 100644
index 000000000..0657e7f84
--- /dev/null
+++ b/doc/snippets/Map_general_stride.cpp
@@ -0,0 +1,5 @@
+int array[24];
+for(int i = 0; i < 24; ++i) array[i] = i;
+cout << Map<MatrixXi, 0, Stride<Dynamic,2> >
+ (array, 3, 3, Stride<Dynamic,2>(8, 2))
+ << endl;
diff --git a/doc/snippets/Map_inner_stride.cpp b/doc/snippets/Map_inner_stride.cpp
new file mode 100644
index 000000000..d95ae9b3e
--- /dev/null
+++ b/doc/snippets/Map_inner_stride.cpp
@@ -0,0 +1,5 @@
+int array[12];
+for(int i = 0; i < 12; ++i) array[i] = i;
+cout << Map<VectorXi, 0, InnerStride<2> >
+ (array, 6) // the inner stride has already been passed as template parameter
+ << endl;
diff --git a/doc/snippets/Map_outer_stride.cpp b/doc/snippets/Map_outer_stride.cpp
new file mode 100644
index 000000000..2f6f052c3
--- /dev/null
+++ b/doc/snippets/Map_outer_stride.cpp
@@ -0,0 +1,3 @@
+int array[12];
+for(int i = 0; i < 12; ++i) array[i] = i;
+cout << Map<MatrixXi, 0, OuterStride<> >(array, 3, 3, OuterStride<>(4)) << endl;
diff --git a/doc/snippets/Map_placement_new.cpp b/doc/snippets/Map_placement_new.cpp
new file mode 100644
index 000000000..2e40eca32
--- /dev/null
+++ b/doc/snippets/Map_placement_new.cpp
@@ -0,0 +1,5 @@
+int data[] = {1,2,3,4,5,6,7,8,9};
+Map<RowVectorXi> v(data,4);
+cout << "The mapped vector v is: " << v << "\n";
+new (&v) Map<RowVectorXi>(data+4,5);
+cout << "Now v is: " << v << "\n"; \ No newline at end of file
diff --git a/doc/snippets/Map_simple.cpp b/doc/snippets/Map_simple.cpp
new file mode 100644
index 000000000..423bb52ad
--- /dev/null
+++ b/doc/snippets/Map_simple.cpp
@@ -0,0 +1,3 @@
+int array[9];
+for(int i = 0; i < 9; ++i) array[i] = i;
+cout << Map<Matrix3i>(array) << endl;
diff --git a/doc/snippets/MatrixBase_adjoint.cpp b/doc/snippets/MatrixBase_adjoint.cpp
new file mode 100644
index 000000000..4680d5938
--- /dev/null
+++ b/doc/snippets/MatrixBase_adjoint.cpp
@@ -0,0 +1,3 @@
+Matrix2cf m = Matrix2cf::Random();
+cout << "Here is the 2x2 complex matrix m:" << endl << m << endl;
+cout << "Here is the adjoint of m:" << endl << m.adjoint() << endl;
diff --git a/doc/snippets/MatrixBase_all.cpp b/doc/snippets/MatrixBase_all.cpp
new file mode 100644
index 000000000..46f26f189
--- /dev/null
+++ b/doc/snippets/MatrixBase_all.cpp
@@ -0,0 +1,7 @@
+Vector3f boxMin(Vector3f::Zero()), boxMax(Vector3f::Ones());
+Vector3f p0 = Vector3f::Random(), p1 = Vector3f::Random().cwiseAbs();
+// let's check if p0 and p1 are inside the axis aligned box defined by the corners boxMin,boxMax:
+cout << "Is (" << p0.transpose() << ") inside the box: "
+ << ((boxMin.array()<p0.array()).all() && (boxMax.array()>p0.array()).all()) << endl;
+cout << "Is (" << p1.transpose() << ") inside the box: "
+ << ((boxMin.array()<p1.array()).all() && (boxMax.array()>p1.array()).all()) << endl;
diff --git a/doc/snippets/MatrixBase_array.cpp b/doc/snippets/MatrixBase_array.cpp
new file mode 100644
index 000000000..f215086db
--- /dev/null
+++ b/doc/snippets/MatrixBase_array.cpp
@@ -0,0 +1,4 @@
+Vector3d v(1,2,3);
+v.array() += 3;
+v.array() -= 2;
+cout << v << endl;
diff --git a/doc/snippets/MatrixBase_array_const.cpp b/doc/snippets/MatrixBase_array_const.cpp
new file mode 100644
index 000000000..cd3b26a7c
--- /dev/null
+++ b/doc/snippets/MatrixBase_array_const.cpp
@@ -0,0 +1,4 @@
+Vector3d v(-1,2,-3);
+cout << "the absolute values:" << endl << v.array().abs() << endl;
+cout << "the absolute values plus one:" << endl << v.array().abs()+1 << endl;
+cout << "sum of the squares: " << v.array().square().sum() << endl;
diff --git a/doc/snippets/MatrixBase_asDiagonal.cpp b/doc/snippets/MatrixBase_asDiagonal.cpp
new file mode 100644
index 000000000..b01082db1
--- /dev/null
+++ b/doc/snippets/MatrixBase_asDiagonal.cpp
@@ -0,0 +1 @@
+cout << Matrix3i(Vector3i(2,5,6).asDiagonal()) << endl;
diff --git a/doc/snippets/MatrixBase_block_int_int.cpp b/doc/snippets/MatrixBase_block_int_int.cpp
new file mode 100644
index 000000000..f99b6d4ca
--- /dev/null
+++ b/doc/snippets/MatrixBase_block_int_int.cpp
@@ -0,0 +1,5 @@
+Matrix4i m = Matrix4i::Random();
+cout << "Here is the matrix m:" << endl << m << endl;
+cout << "Here is m.block<2,2>(1,1):" << endl << m.block<2,2>(1,1) << endl;
+m.block<2,2>(1,1).setZero();
+cout << "Now the matrix m is:" << endl << m << endl;
diff --git a/doc/snippets/MatrixBase_block_int_int_int_int.cpp b/doc/snippets/MatrixBase_block_int_int_int_int.cpp
new file mode 100644
index 000000000..7238cbbed
--- /dev/null
+++ b/doc/snippets/MatrixBase_block_int_int_int_int.cpp
@@ -0,0 +1,5 @@
+Matrix4i m = Matrix4i::Random();
+cout << "Here is the matrix m:" << endl << m << endl;
+cout << "Here is m.block(1, 1, 2, 2):" << endl << m.block(1, 1, 2, 2) << endl;
+m.block(1, 1, 2, 2).setZero();
+cout << "Now the matrix m is:" << endl << m << endl;
diff --git a/doc/snippets/MatrixBase_bottomLeftCorner_int_int.cpp b/doc/snippets/MatrixBase_bottomLeftCorner_int_int.cpp
new file mode 100644
index 000000000..ebae95e1d
--- /dev/null
+++ b/doc/snippets/MatrixBase_bottomLeftCorner_int_int.cpp
@@ -0,0 +1,6 @@
+Matrix4i m = Matrix4i::Random();
+cout << "Here is the matrix m:" << endl << m << endl;
+cout << "Here is m.bottomLeftCorner(2, 2):" << endl;
+cout << m.bottomLeftCorner(2, 2) << endl;
+m.bottomLeftCorner(2, 2).setZero();
+cout << "Now the matrix m is:" << endl << m << endl;
diff --git a/doc/snippets/MatrixBase_bottomRightCorner_int_int.cpp b/doc/snippets/MatrixBase_bottomRightCorner_int_int.cpp
new file mode 100644
index 000000000..bf05093af
--- /dev/null
+++ b/doc/snippets/MatrixBase_bottomRightCorner_int_int.cpp
@@ -0,0 +1,6 @@
+Matrix4i m = Matrix4i::Random();
+cout << "Here is the matrix m:" << endl << m << endl;
+cout << "Here is m.bottomRightCorner(2, 2):" << endl;
+cout << m.bottomRightCorner(2, 2) << endl;
+m.bottomRightCorner(2, 2).setZero();
+cout << "Now the matrix m is:" << endl << m << endl;
diff --git a/doc/snippets/MatrixBase_bottomRows_int.cpp b/doc/snippets/MatrixBase_bottomRows_int.cpp
new file mode 100644
index 000000000..47ca92ec3
--- /dev/null
+++ b/doc/snippets/MatrixBase_bottomRows_int.cpp
@@ -0,0 +1,6 @@
+Array44i a = Array44i::Random();
+cout << "Here is the array a:" << endl << a << endl;
+cout << "Here is a.bottomRows(2):" << endl;
+cout << a.bottomRows(2) << endl;
+a.bottomRows(2).setZero();
+cout << "Now the array a is:" << endl << a << endl;
diff --git a/doc/snippets/MatrixBase_cast.cpp b/doc/snippets/MatrixBase_cast.cpp
new file mode 100644
index 000000000..016880b40
--- /dev/null
+++ b/doc/snippets/MatrixBase_cast.cpp
@@ -0,0 +1,3 @@
+Matrix2d md = Matrix2d::Identity() * 0.45;
+Matrix2f mf = Matrix2f::Identity();
+cout << md + mf.cast<double>() << endl;
diff --git a/doc/snippets/MatrixBase_col.cpp b/doc/snippets/MatrixBase_col.cpp
new file mode 100644
index 000000000..87c91b129
--- /dev/null
+++ b/doc/snippets/MatrixBase_col.cpp
@@ -0,0 +1,3 @@
+Matrix3d m = Matrix3d::Identity();
+m.col(1) = Vector3d(4,5,6);
+cout << m << endl;
diff --git a/doc/snippets/MatrixBase_colwise.cpp b/doc/snippets/MatrixBase_colwise.cpp
new file mode 100644
index 000000000..a048beffa
--- /dev/null
+++ b/doc/snippets/MatrixBase_colwise.cpp
@@ -0,0 +1,5 @@
+Matrix3d m = Matrix3d::Random();
+cout << "Here is the matrix m:" << endl << m << endl;
+cout << "Here is the sum of each column:" << endl << m.colwise().sum() << endl;
+cout << "Here is the maximum absolute value of each column:"
+ << endl << m.cwiseAbs().colwise().maxCoeff() << endl;
diff --git a/doc/snippets/MatrixBase_computeInverseAndDetWithCheck.cpp b/doc/snippets/MatrixBase_computeInverseAndDetWithCheck.cpp
new file mode 100644
index 000000000..a7b084fd0
--- /dev/null
+++ b/doc/snippets/MatrixBase_computeInverseAndDetWithCheck.cpp
@@ -0,0 +1,13 @@
+Matrix3d m = Matrix3d::Random();
+cout << "Here is the matrix m:" << endl << m << endl;
+Matrix3d inverse;
+bool invertible;
+double determinant;
+m.computeInverseAndDetWithCheck(inverse,determinant,invertible);
+cout << "Its determinant is " << determinant << endl;
+if(invertible) {
+ cout << "It is invertible, and its inverse is:" << endl << inverse << endl;
+}
+else {
+ cout << "It is not invertible." << endl;
+}
diff --git a/doc/snippets/MatrixBase_computeInverseWithCheck.cpp b/doc/snippets/MatrixBase_computeInverseWithCheck.cpp
new file mode 100644
index 000000000..873a9f870
--- /dev/null
+++ b/doc/snippets/MatrixBase_computeInverseWithCheck.cpp
@@ -0,0 +1,11 @@
+Matrix3d m = Matrix3d::Random();
+cout << "Here is the matrix m:" << endl << m << endl;
+Matrix3d inverse;
+bool invertible;
+m.computeInverseWithCheck(inverse,invertible);
+if(invertible) {
+ cout << "It is invertible, and its inverse is:" << endl << inverse << endl;
+}
+else {
+ cout << "It is not invertible." << endl;
+}
diff --git a/doc/snippets/MatrixBase_cwiseAbs.cpp b/doc/snippets/MatrixBase_cwiseAbs.cpp
new file mode 100644
index 000000000..28a31600f
--- /dev/null
+++ b/doc/snippets/MatrixBase_cwiseAbs.cpp
@@ -0,0 +1,4 @@
+MatrixXd m(2,3);
+m << 2, -4, 6,
+ -5, 1, 0;
+cout << m.cwiseAbs() << endl;
diff --git a/doc/snippets/MatrixBase_cwiseAbs2.cpp b/doc/snippets/MatrixBase_cwiseAbs2.cpp
new file mode 100644
index 000000000..889a2e2ba
--- /dev/null
+++ b/doc/snippets/MatrixBase_cwiseAbs2.cpp
@@ -0,0 +1,4 @@
+MatrixXd m(2,3);
+m << 2, -4, 6,
+ -5, 1, 0;
+cout << m.cwiseAbs2() << endl;
diff --git a/doc/snippets/MatrixBase_cwiseEqual.cpp b/doc/snippets/MatrixBase_cwiseEqual.cpp
new file mode 100644
index 000000000..eb3656f4c
--- /dev/null
+++ b/doc/snippets/MatrixBase_cwiseEqual.cpp
@@ -0,0 +1,7 @@
+MatrixXi m(2,2);
+m << 1, 0,
+ 1, 1;
+cout << "Comparing m with identity matrix:" << endl;
+cout << m.cwiseEqual(MatrixXi::Identity(2,2)) << endl;
+int count = m.cwiseEqual(MatrixXi::Identity(2,2)).count();
+cout << "Number of coefficients that are equal: " << count << endl;
diff --git a/doc/snippets/MatrixBase_cwiseInverse.cpp b/doc/snippets/MatrixBase_cwiseInverse.cpp
new file mode 100644
index 000000000..23e08f7b9
--- /dev/null
+++ b/doc/snippets/MatrixBase_cwiseInverse.cpp
@@ -0,0 +1,4 @@
+MatrixXd m(2,3);
+m << 2, 0.5, 1,
+ 3, 0.25, 1;
+cout << m.cwiseInverse() << endl;
diff --git a/doc/snippets/MatrixBase_cwiseMax.cpp b/doc/snippets/MatrixBase_cwiseMax.cpp
new file mode 100644
index 000000000..3c956818b
--- /dev/null
+++ b/doc/snippets/MatrixBase_cwiseMax.cpp
@@ -0,0 +1,2 @@
+Vector3d v(2,3,4), w(4,2,3);
+cout << v.cwiseMax(w) << endl;
diff --git a/doc/snippets/MatrixBase_cwiseMin.cpp b/doc/snippets/MatrixBase_cwiseMin.cpp
new file mode 100644
index 000000000..82fc761e2
--- /dev/null
+++ b/doc/snippets/MatrixBase_cwiseMin.cpp
@@ -0,0 +1,2 @@
+Vector3d v(2,3,4), w(4,2,3);
+cout << v.cwiseMin(w) << endl;
diff --git a/doc/snippets/MatrixBase_cwiseNotEqual.cpp b/doc/snippets/MatrixBase_cwiseNotEqual.cpp
new file mode 100644
index 000000000..6a2e4fb6c
--- /dev/null
+++ b/doc/snippets/MatrixBase_cwiseNotEqual.cpp
@@ -0,0 +1,7 @@
+MatrixXi m(2,2);
+m << 1, 0,
+ 1, 1;
+cout << "Comparing m with identity matrix:" << endl;
+cout << m.cwiseNotEqual(MatrixXi::Identity(2,2)) << endl;
+int count = m.cwiseNotEqual(MatrixXi::Identity(2,2)).count();
+cout << "Number of coefficients that are not equal: " << count << endl;
diff --git a/doc/snippets/MatrixBase_cwiseProduct.cpp b/doc/snippets/MatrixBase_cwiseProduct.cpp
new file mode 100644
index 000000000..1db3a1132
--- /dev/null
+++ b/doc/snippets/MatrixBase_cwiseProduct.cpp
@@ -0,0 +1,4 @@
+Matrix3i a = Matrix3i::Random(), b = Matrix3i::Random();
+Matrix3i c = a.cwiseProduct(b);
+cout << "a:\n" << a << "\nb:\n" << b << "\nc:\n" << c << endl;
+
diff --git a/doc/snippets/MatrixBase_cwiseQuotient.cpp b/doc/snippets/MatrixBase_cwiseQuotient.cpp
new file mode 100644
index 000000000..969121208
--- /dev/null
+++ b/doc/snippets/MatrixBase_cwiseQuotient.cpp
@@ -0,0 +1,2 @@
+Vector3d v(2,3,4), w(4,2,3);
+cout << v.cwiseQuotient(w) << endl;
diff --git a/doc/snippets/MatrixBase_cwiseSqrt.cpp b/doc/snippets/MatrixBase_cwiseSqrt.cpp
new file mode 100644
index 000000000..4bfd75d50
--- /dev/null
+++ b/doc/snippets/MatrixBase_cwiseSqrt.cpp
@@ -0,0 +1,2 @@
+Vector3d v(1,2,4);
+cout << v.cwiseSqrt() << endl;
diff --git a/doc/snippets/MatrixBase_diagonal.cpp b/doc/snippets/MatrixBase_diagonal.cpp
new file mode 100644
index 000000000..cd63413f3
--- /dev/null
+++ b/doc/snippets/MatrixBase_diagonal.cpp
@@ -0,0 +1,4 @@
+Matrix3i m = Matrix3i::Random();
+cout << "Here is the matrix m:" << endl << m << endl;
+cout << "Here are the coefficients on the main diagonal of m:" << endl
+ << m.diagonal() << endl;
diff --git a/doc/snippets/MatrixBase_diagonal_int.cpp b/doc/snippets/MatrixBase_diagonal_int.cpp
new file mode 100644
index 000000000..7b66abf67
--- /dev/null
+++ b/doc/snippets/MatrixBase_diagonal_int.cpp
@@ -0,0 +1,5 @@
+Matrix4i m = Matrix4i::Random();
+cout << "Here is the matrix m:" << endl << m << endl;
+cout << "Here are the coefficients on the 1st super-diagonal and 2nd sub-diagonal of m:" << endl
+ << m.diagonal(1).transpose() << endl
+ << m.diagonal(-2).transpose() << endl;
diff --git a/doc/snippets/MatrixBase_diagonal_template_int.cpp b/doc/snippets/MatrixBase_diagonal_template_int.cpp
new file mode 100644
index 000000000..0e73d1c16
--- /dev/null
+++ b/doc/snippets/MatrixBase_diagonal_template_int.cpp
@@ -0,0 +1,5 @@
+Matrix4i m = Matrix4i::Random();
+cout << "Here is the matrix m:" << endl << m << endl;
+cout << "Here are the coefficients on the 1st super-diagonal and 2nd sub-diagonal of m:" << endl
+ << m.diagonal<1>().transpose() << endl
+ << m.diagonal<-2>().transpose() << endl;
diff --git a/doc/snippets/MatrixBase_eigenvalues.cpp b/doc/snippets/MatrixBase_eigenvalues.cpp
new file mode 100644
index 000000000..039f88701
--- /dev/null
+++ b/doc/snippets/MatrixBase_eigenvalues.cpp
@@ -0,0 +1,3 @@
+MatrixXd ones = MatrixXd::Ones(3,3);
+VectorXcd eivals = ones.eigenvalues();
+cout << "The eigenvalues of the 3x3 matrix of ones are:" << endl << eivals << endl;
diff --git a/doc/snippets/MatrixBase_end_int.cpp b/doc/snippets/MatrixBase_end_int.cpp
new file mode 100644
index 000000000..03c54a931
--- /dev/null
+++ b/doc/snippets/MatrixBase_end_int.cpp
@@ -0,0 +1,5 @@
+RowVector4i v = RowVector4i::Random();
+cout << "Here is the vector v:" << endl << v << endl;
+cout << "Here is v.tail(2):" << endl << v.tail(2) << endl;
+v.tail(2).setZero();
+cout << "Now the vector v is:" << endl << v << endl;
diff --git a/doc/snippets/MatrixBase_eval.cpp b/doc/snippets/MatrixBase_eval.cpp
new file mode 100644
index 000000000..1df3aa01d
--- /dev/null
+++ b/doc/snippets/MatrixBase_eval.cpp
@@ -0,0 +1,12 @@
+Matrix2f M = Matrix2f::Random();
+Matrix2f m;
+m = M;
+cout << "Here is the matrix m:" << endl << m << endl;
+cout << "Now we want to copy a column into a row." << endl;
+cout << "If we do m.col(1) = m.row(0), then m becomes:" << endl;
+m.col(1) = m.row(0);
+cout << m << endl << "which is wrong!" << endl;
+cout << "Now let us instead do m.col(1) = m.row(0).eval(). Then m becomes" << endl;
+m = M;
+m.col(1) = m.row(0).eval();
+cout << m << endl << "which is right." << endl;
diff --git a/doc/snippets/MatrixBase_extract.cpp b/doc/snippets/MatrixBase_extract.cpp
new file mode 100644
index 000000000..c96220f72
--- /dev/null
+++ b/doc/snippets/MatrixBase_extract.cpp
@@ -0,0 +1,13 @@
+#ifndef _MSC_VER
+ #warning deprecated
+#endif
+/* deprecated
+Matrix3i m = Matrix3i::Random();
+cout << "Here is the matrix m:" << endl << m << endl;
+cout << "Here is the upper-triangular matrix extracted from m:" << endl
+ << m.part<Eigen::UpperTriangular>() << endl;
+cout << "Here is the strictly-upper-triangular matrix extracted from m:" << endl
+ << m.part<Eigen::StrictlyUpperTriangular>() << endl;
+cout << "Here is the unit-lower-triangular matrix extracted from m:" << endl
+ << m.part<Eigen::UnitLowerTriangular>() << endl;
+*/ \ No newline at end of file
diff --git a/doc/snippets/MatrixBase_fixedBlock_int_int.cpp b/doc/snippets/MatrixBase_fixedBlock_int_int.cpp
new file mode 100644
index 000000000..320112748
--- /dev/null
+++ b/doc/snippets/MatrixBase_fixedBlock_int_int.cpp
@@ -0,0 +1,5 @@
+Matrix4d m = Vector4d(1,2,3,4).asDiagonal();
+cout << "Here is the matrix m:" << endl << m << endl;
+cout << "Here is m.fixed<2, 2>(2, 2):" << endl << m.block<2, 2>(2, 2) << endl;
+m.block<2, 2>(2, 0) = m.block<2, 2>(2, 2);
+cout << "Now the matrix m is:" << endl << m << endl;
diff --git a/doc/snippets/MatrixBase_identity.cpp b/doc/snippets/MatrixBase_identity.cpp
new file mode 100644
index 000000000..b5c1e59c9
--- /dev/null
+++ b/doc/snippets/MatrixBase_identity.cpp
@@ -0,0 +1 @@
+cout << Matrix<double, 3, 4>::Identity() << endl;
diff --git a/doc/snippets/MatrixBase_identity_int_int.cpp b/doc/snippets/MatrixBase_identity_int_int.cpp
new file mode 100644
index 000000000..918649d64
--- /dev/null
+++ b/doc/snippets/MatrixBase_identity_int_int.cpp
@@ -0,0 +1 @@
+cout << MatrixXd::Identity(4, 3) << endl;
diff --git a/doc/snippets/MatrixBase_inverse.cpp b/doc/snippets/MatrixBase_inverse.cpp
new file mode 100644
index 000000000..a56142ee0
--- /dev/null
+++ b/doc/snippets/MatrixBase_inverse.cpp
@@ -0,0 +1,3 @@
+Matrix3d m = Matrix3d::Random();
+cout << "Here is the matrix m:" << endl << m << endl;
+cout << "Its inverse is:" << endl << m.inverse() << endl;
diff --git a/doc/snippets/MatrixBase_isDiagonal.cpp b/doc/snippets/MatrixBase_isDiagonal.cpp
new file mode 100644
index 000000000..5b1d59977
--- /dev/null
+++ b/doc/snippets/MatrixBase_isDiagonal.cpp
@@ -0,0 +1,6 @@
+Matrix3d m = 10000 * Matrix3d::Identity();
+m(0,2) = 1;
+cout << "Here's the matrix m:" << endl << m << endl;
+cout << "m.isDiagonal() returns: " << m.isDiagonal() << endl;
+cout << "m.isDiagonal(1e-3) returns: " << m.isDiagonal(1e-3) << endl;
+
diff --git a/doc/snippets/MatrixBase_isIdentity.cpp b/doc/snippets/MatrixBase_isIdentity.cpp
new file mode 100644
index 000000000..17b756c97
--- /dev/null
+++ b/doc/snippets/MatrixBase_isIdentity.cpp
@@ -0,0 +1,5 @@
+Matrix3d m = Matrix3d::Identity();
+m(0,2) = 1e-4;
+cout << "Here's the matrix m:" << endl << m << endl;
+cout << "m.isIdentity() returns: " << m.isIdentity() << endl;
+cout << "m.isIdentity(1e-3) returns: " << m.isIdentity(1e-3) << endl;
diff --git a/doc/snippets/MatrixBase_isOnes.cpp b/doc/snippets/MatrixBase_isOnes.cpp
new file mode 100644
index 000000000..f82f62809
--- /dev/null
+++ b/doc/snippets/MatrixBase_isOnes.cpp
@@ -0,0 +1,5 @@
+Matrix3d m = Matrix3d::Ones();
+m(0,2) += 1e-4;
+cout << "Here's the matrix m:" << endl << m << endl;
+cout << "m.isOnes() returns: " << m.isOnes() << endl;
+cout << "m.isOnes(1e-3) returns: " << m.isOnes(1e-3) << endl;
diff --git a/doc/snippets/MatrixBase_isOrthogonal.cpp b/doc/snippets/MatrixBase_isOrthogonal.cpp
new file mode 100644
index 000000000..b22af066c
--- /dev/null
+++ b/doc/snippets/MatrixBase_isOrthogonal.cpp
@@ -0,0 +1,6 @@
+Vector3d v(1,0,0);
+Vector3d w(1e-4,0,1);
+cout << "Here's the vector v:" << endl << v << endl;
+cout << "Here's the vector w:" << endl << w << endl;
+cout << "v.isOrthogonal(w) returns: " << v.isOrthogonal(w) << endl;
+cout << "v.isOrthogonal(w,1e-3) returns: " << v.isOrthogonal(w,1e-3) << endl;
diff --git a/doc/snippets/MatrixBase_isUnitary.cpp b/doc/snippets/MatrixBase_isUnitary.cpp
new file mode 100644
index 000000000..3877da347
--- /dev/null
+++ b/doc/snippets/MatrixBase_isUnitary.cpp
@@ -0,0 +1,5 @@
+Matrix3d m = Matrix3d::Identity();
+m(0,2) = 1e-4;
+cout << "Here's the matrix m:" << endl << m << endl;
+cout << "m.isUnitary() returns: " << m.isUnitary() << endl;
+cout << "m.isUnitary(1e-3) returns: " << m.isUnitary(1e-3) << endl;
diff --git a/doc/snippets/MatrixBase_isZero.cpp b/doc/snippets/MatrixBase_isZero.cpp
new file mode 100644
index 000000000..c2cfe2201
--- /dev/null
+++ b/doc/snippets/MatrixBase_isZero.cpp
@@ -0,0 +1,5 @@
+Matrix3d m = Matrix3d::Zero();
+m(0,2) = 1e-4;
+cout << "Here's the matrix m:" << endl << m << endl;
+cout << "m.isZero() returns: " << m.isZero() << endl;
+cout << "m.isZero(1e-3) returns: " << m.isZero(1e-3) << endl;
diff --git a/doc/snippets/MatrixBase_leftCols_int.cpp b/doc/snippets/MatrixBase_leftCols_int.cpp
new file mode 100644
index 000000000..6ea984e4e
--- /dev/null
+++ b/doc/snippets/MatrixBase_leftCols_int.cpp
@@ -0,0 +1,6 @@
+Array44i a = Array44i::Random();
+cout << "Here is the array a:" << endl << a << endl;
+cout << "Here is a.leftCols(2):" << endl;
+cout << a.leftCols(2) << endl;
+a.leftCols(2).setZero();
+cout << "Now the array a is:" << endl << a << endl;
diff --git a/doc/snippets/MatrixBase_marked.cpp b/doc/snippets/MatrixBase_marked.cpp
new file mode 100644
index 000000000..f60712178
--- /dev/null
+++ b/doc/snippets/MatrixBase_marked.cpp
@@ -0,0 +1,14 @@
+#ifndef _MSC_VER
+ #warning deprecated
+#endif
+/*
+Matrix3d m = Matrix3d::Zero();
+m.part<Eigen::UpperTriangular>().setOnes();
+cout << "Here is the matrix m:" << endl << m << endl;
+Matrix3d n = Matrix3d::Ones();
+n.part<Eigen::LowerTriangular>() *= 2;
+cout << "Here is the matrix n:" << endl << n << endl;
+cout << "And now here is m.inverse()*n, taking advantage of the fact that"
+ " m is upper-triangular:" << endl
+ << m.marked<Eigen::UpperTriangular>().solveTriangular(n);
+*/ \ No newline at end of file
diff --git a/doc/snippets/MatrixBase_noalias.cpp b/doc/snippets/MatrixBase_noalias.cpp
new file mode 100644
index 000000000..3b54a79a6
--- /dev/null
+++ b/doc/snippets/MatrixBase_noalias.cpp
@@ -0,0 +1,3 @@
+Matrix2d a, b, c; a << 1,2,3,4; b << 5,6,7,8;
+c.noalias() = a * b; // this computes the product directly to c
+cout << c << endl;
diff --git a/doc/snippets/MatrixBase_ones.cpp b/doc/snippets/MatrixBase_ones.cpp
new file mode 100644
index 000000000..02c767c95
--- /dev/null
+++ b/doc/snippets/MatrixBase_ones.cpp
@@ -0,0 +1,2 @@
+cout << Matrix2d::Ones() << endl;
+cout << 6 * RowVector4i::Ones() << endl;
diff --git a/doc/snippets/MatrixBase_ones_int.cpp b/doc/snippets/MatrixBase_ones_int.cpp
new file mode 100644
index 000000000..2ef188e7d
--- /dev/null
+++ b/doc/snippets/MatrixBase_ones_int.cpp
@@ -0,0 +1,2 @@
+cout << 6 * RowVectorXi::Ones(4) << endl;
+cout << VectorXf::Ones(2) << endl;
diff --git a/doc/snippets/MatrixBase_ones_int_int.cpp b/doc/snippets/MatrixBase_ones_int_int.cpp
new file mode 100644
index 000000000..60f5a31eb
--- /dev/null
+++ b/doc/snippets/MatrixBase_ones_int_int.cpp
@@ -0,0 +1 @@
+cout << MatrixXi::Ones(2,3) << endl;
diff --git a/doc/snippets/MatrixBase_operatorNorm.cpp b/doc/snippets/MatrixBase_operatorNorm.cpp
new file mode 100644
index 000000000..355246f0d
--- /dev/null
+++ b/doc/snippets/MatrixBase_operatorNorm.cpp
@@ -0,0 +1,3 @@
+MatrixXd ones = MatrixXd::Ones(3,3);
+cout << "The operator norm of the 3x3 matrix of ones is "
+ << ones.operatorNorm() << endl;
diff --git a/doc/snippets/MatrixBase_part.cpp b/doc/snippets/MatrixBase_part.cpp
new file mode 100644
index 000000000..d3e7f482e
--- /dev/null
+++ b/doc/snippets/MatrixBase_part.cpp
@@ -0,0 +1,13 @@
+#ifndef _MSC_VER
+ #warning deprecated
+#endif
+/*
+Matrix3d m = Matrix3d::Zero();
+m.part<Eigen::StrictlyUpperTriangular>().setOnes();
+cout << "Here is the matrix m:" << endl << m << endl;
+cout << "And let us now compute m*m.adjoint() in a very optimized way" << endl
+ << "taking advantage of the symmetry." << endl;
+Matrix3d n;
+n.part<Eigen::SelfAdjoint>() = (m*m.adjoint()).lazy();
+cout << "The result is:" << endl << n << endl;
+*/ \ No newline at end of file
diff --git a/doc/snippets/MatrixBase_prod.cpp b/doc/snippets/MatrixBase_prod.cpp
new file mode 100644
index 000000000..d2f27bdc3
--- /dev/null
+++ b/doc/snippets/MatrixBase_prod.cpp
@@ -0,0 +1,3 @@
+Matrix3d m = Matrix3d::Random();
+cout << "Here is the matrix m:" << endl << m << endl;
+cout << "Here is the product of all the coefficients:" << endl << m.prod() << endl;
diff --git a/doc/snippets/MatrixBase_random.cpp b/doc/snippets/MatrixBase_random.cpp
new file mode 100644
index 000000000..65fc524f1
--- /dev/null
+++ b/doc/snippets/MatrixBase_random.cpp
@@ -0,0 +1 @@
+cout << 100 * Matrix2i::Random() << endl;
diff --git a/doc/snippets/MatrixBase_random_int.cpp b/doc/snippets/MatrixBase_random_int.cpp
new file mode 100644
index 000000000..f161d03c2
--- /dev/null
+++ b/doc/snippets/MatrixBase_random_int.cpp
@@ -0,0 +1 @@
+cout << VectorXi::Random(2) << endl;
diff --git a/doc/snippets/MatrixBase_random_int_int.cpp b/doc/snippets/MatrixBase_random_int_int.cpp
new file mode 100644
index 000000000..3f0f7dd5d
--- /dev/null
+++ b/doc/snippets/MatrixBase_random_int_int.cpp
@@ -0,0 +1 @@
+cout << MatrixXi::Random(2,3) << endl;
diff --git a/doc/snippets/MatrixBase_replicate.cpp b/doc/snippets/MatrixBase_replicate.cpp
new file mode 100644
index 000000000..3ce52bcd5
--- /dev/null
+++ b/doc/snippets/MatrixBase_replicate.cpp
@@ -0,0 +1,4 @@
+MatrixXi m = MatrixXi::Random(2,3);
+cout << "Here is the matrix m:" << endl << m << endl;
+cout << "m.replicate<3,2>() = ..." << endl;
+cout << m.replicate<3,2>() << endl;
diff --git a/doc/snippets/MatrixBase_replicate_int_int.cpp b/doc/snippets/MatrixBase_replicate_int_int.cpp
new file mode 100644
index 000000000..b1dbc70bc
--- /dev/null
+++ b/doc/snippets/MatrixBase_replicate_int_int.cpp
@@ -0,0 +1,4 @@
+Vector3i v = Vector3i::Random();
+cout << "Here is the vector v:" << endl << v << endl;
+cout << "v.replicate(2,5) = ..." << endl;
+cout << v.replicate(2,5) << endl;
diff --git a/doc/snippets/MatrixBase_reverse.cpp b/doc/snippets/MatrixBase_reverse.cpp
new file mode 100644
index 000000000..f545a2837
--- /dev/null
+++ b/doc/snippets/MatrixBase_reverse.cpp
@@ -0,0 +1,8 @@
+MatrixXi m = MatrixXi::Random(3,4);
+cout << "Here is the matrix m:" << endl << m << endl;
+cout << "Here is the reverse of m:" << endl << m.reverse() << endl;
+cout << "Here is the coefficient (1,0) in the reverse of m:" << endl
+ << m.reverse()(1,0) << endl;
+cout << "Let us overwrite this coefficient with the value 4." << endl;
+m.reverse()(1,0) = 4;
+cout << "Now the matrix m is:" << endl << m << endl;
diff --git a/doc/snippets/MatrixBase_rightCols_int.cpp b/doc/snippets/MatrixBase_rightCols_int.cpp
new file mode 100644
index 000000000..cb513401b
--- /dev/null
+++ b/doc/snippets/MatrixBase_rightCols_int.cpp
@@ -0,0 +1,6 @@
+Array44i a = Array44i::Random();
+cout << "Here is the array a:" << endl << a << endl;
+cout << "Here is a.rightCols(2):" << endl;
+cout << a.rightCols(2) << endl;
+a.rightCols(2).setZero();
+cout << "Now the array a is:" << endl << a << endl;
diff --git a/doc/snippets/MatrixBase_row.cpp b/doc/snippets/MatrixBase_row.cpp
new file mode 100644
index 000000000..b15e6260c
--- /dev/null
+++ b/doc/snippets/MatrixBase_row.cpp
@@ -0,0 +1,3 @@
+Matrix3d m = Matrix3d::Identity();
+m.row(1) = Vector3d(4,5,6);
+cout << m << endl;
diff --git a/doc/snippets/MatrixBase_rowwise.cpp b/doc/snippets/MatrixBase_rowwise.cpp
new file mode 100644
index 000000000..ae93964ea
--- /dev/null
+++ b/doc/snippets/MatrixBase_rowwise.cpp
@@ -0,0 +1,5 @@
+Matrix3d m = Matrix3d::Random();
+cout << "Here is the matrix m:" << endl << m << endl;
+cout << "Here is the sum of each row:" << endl << m.rowwise().sum() << endl;
+cout << "Here is the maximum absolute value of each row:"
+ << endl << m.cwiseAbs().rowwise().maxCoeff() << endl;
diff --git a/doc/snippets/MatrixBase_segment_int_int.cpp b/doc/snippets/MatrixBase_segment_int_int.cpp
new file mode 100644
index 000000000..70cd6d266
--- /dev/null
+++ b/doc/snippets/MatrixBase_segment_int_int.cpp
@@ -0,0 +1,5 @@
+RowVector4i v = RowVector4i::Random();
+cout << "Here is the vector v:" << endl << v << endl;
+cout << "Here is v.segment(1, 2):" << endl << v.segment(1, 2) << endl;
+v.segment(1, 2).setZero();
+cout << "Now the vector v is:" << endl << v << endl;
diff --git a/doc/snippets/MatrixBase_select.cpp b/doc/snippets/MatrixBase_select.cpp
new file mode 100644
index 000000000..ae5477f02
--- /dev/null
+++ b/doc/snippets/MatrixBase_select.cpp
@@ -0,0 +1,6 @@
+MatrixXi m(3, 3);
+m << 1, 2, 3,
+ 4, 5, 6,
+ 7, 8, 9;
+m = (m.array() >= 5).select(-m, m);
+cout << m << endl;
diff --git a/doc/snippets/MatrixBase_set.cpp b/doc/snippets/MatrixBase_set.cpp
new file mode 100644
index 000000000..50ecf5fb9
--- /dev/null
+++ b/doc/snippets/MatrixBase_set.cpp
@@ -0,0 +1,13 @@
+Matrix3i m1;
+m1 << 1, 2, 3,
+ 4, 5, 6,
+ 7, 8, 9;
+cout << m1 << endl << endl;
+Matrix3i m2 = Matrix3i::Identity();
+m2.block(0,0, 2,2) << 10, 11, 12, 13;
+cout << m2 << endl << endl;
+Vector2i v1;
+v1 << 14, 15;
+m2 << v1.transpose(), 16,
+ v1, m1.block(1,1,2,2);
+cout << m2 << endl;
diff --git a/doc/snippets/MatrixBase_setIdentity.cpp b/doc/snippets/MatrixBase_setIdentity.cpp
new file mode 100644
index 000000000..4fd0aa24a
--- /dev/null
+++ b/doc/snippets/MatrixBase_setIdentity.cpp
@@ -0,0 +1,3 @@
+Matrix4i m = Matrix4i::Zero();
+m.block<3,3>(1,0).setIdentity();
+cout << m << endl;
diff --git a/doc/snippets/MatrixBase_setOnes.cpp b/doc/snippets/MatrixBase_setOnes.cpp
new file mode 100644
index 000000000..4cef9c1eb
--- /dev/null
+++ b/doc/snippets/MatrixBase_setOnes.cpp
@@ -0,0 +1,3 @@
+Matrix4i m = Matrix4i::Random();
+m.row(1).setOnes();
+cout << m << endl;
diff --git a/doc/snippets/MatrixBase_setRandom.cpp b/doc/snippets/MatrixBase_setRandom.cpp
new file mode 100644
index 000000000..e2c257d44
--- /dev/null
+++ b/doc/snippets/MatrixBase_setRandom.cpp
@@ -0,0 +1,3 @@
+Matrix4i m = Matrix4i::Zero();
+m.col(1).setRandom();
+cout << m << endl;
diff --git a/doc/snippets/MatrixBase_setZero.cpp b/doc/snippets/MatrixBase_setZero.cpp
new file mode 100644
index 000000000..9b5b9583c
--- /dev/null
+++ b/doc/snippets/MatrixBase_setZero.cpp
@@ -0,0 +1,3 @@
+Matrix4i m = Matrix4i::Random();
+m.row(1).setZero();
+cout << m << endl;
diff --git a/doc/snippets/MatrixBase_start_int.cpp b/doc/snippets/MatrixBase_start_int.cpp
new file mode 100644
index 000000000..c261d2b4e
--- /dev/null
+++ b/doc/snippets/MatrixBase_start_int.cpp
@@ -0,0 +1,5 @@
+RowVector4i v = RowVector4i::Random();
+cout << "Here is the vector v:" << endl << v << endl;
+cout << "Here is v.head(2):" << endl << v.head(2) << endl;
+v.head(2).setZero();
+cout << "Now the vector v is:" << endl << v << endl;
diff --git a/doc/snippets/MatrixBase_template_int_bottomRows.cpp b/doc/snippets/MatrixBase_template_int_bottomRows.cpp
new file mode 100644
index 000000000..f9ea892da
--- /dev/null
+++ b/doc/snippets/MatrixBase_template_int_bottomRows.cpp
@@ -0,0 +1,6 @@
+Array44i a = Array44i::Random();
+cout << "Here is the array a:" << endl << a << endl;
+cout << "Here is a.bottomRows<2>():" << endl;
+cout << a.bottomRows<2>() << endl;
+a.bottomRows<2>().setZero();
+cout << "Now the array a is:" << endl << a << endl;
diff --git a/doc/snippets/MatrixBase_template_int_end.cpp b/doc/snippets/MatrixBase_template_int_end.cpp
new file mode 100644
index 000000000..f5ccb00f6
--- /dev/null
+++ b/doc/snippets/MatrixBase_template_int_end.cpp
@@ -0,0 +1,5 @@
+RowVector4i v = RowVector4i::Random();
+cout << "Here is the vector v:" << endl << v << endl;
+cout << "Here is v.tail(2):" << endl << v.tail<2>() << endl;
+v.tail<2>().setZero();
+cout << "Now the vector v is:" << endl << v << endl;
diff --git a/doc/snippets/MatrixBase_template_int_int_bottomLeftCorner.cpp b/doc/snippets/MatrixBase_template_int_int_bottomLeftCorner.cpp
new file mode 100644
index 000000000..847892a27
--- /dev/null
+++ b/doc/snippets/MatrixBase_template_int_int_bottomLeftCorner.cpp
@@ -0,0 +1,6 @@
+Matrix4i m = Matrix4i::Random();
+cout << "Here is the matrix m:" << endl << m << endl;
+cout << "Here is m.bottomLeftCorner<2,2>():" << endl;
+cout << m.bottomLeftCorner<2,2>() << endl;
+m.bottomLeftCorner<2,2>().setZero();
+cout << "Now the matrix m is:" << endl << m << endl;
diff --git a/doc/snippets/MatrixBase_template_int_int_bottomRightCorner.cpp b/doc/snippets/MatrixBase_template_int_int_bottomRightCorner.cpp
new file mode 100644
index 000000000..abacb014e
--- /dev/null
+++ b/doc/snippets/MatrixBase_template_int_int_bottomRightCorner.cpp
@@ -0,0 +1,6 @@
+Matrix4i m = Matrix4i::Random();
+cout << "Here is the matrix m:" << endl << m << endl;
+cout << "Here is m.bottomRightCorner<2,2>():" << endl;
+cout << m.bottomRightCorner<2,2>() << endl;
+m.bottomRightCorner<2,2>().setZero();
+cout << "Now the matrix m is:" << endl << m << endl;
diff --git a/doc/snippets/MatrixBase_template_int_int_topLeftCorner.cpp b/doc/snippets/MatrixBase_template_int_int_topLeftCorner.cpp
new file mode 100644
index 000000000..1899d902d
--- /dev/null
+++ b/doc/snippets/MatrixBase_template_int_int_topLeftCorner.cpp
@@ -0,0 +1,6 @@
+Matrix4i m = Matrix4i::Random();
+cout << "Here is the matrix m:" << endl << m << endl;
+cout << "Here is m.topLeftCorner<2,2>():" << endl;
+cout << m.topLeftCorner<2,2>() << endl;
+m.topLeftCorner<2,2>().setZero();
+cout << "Now the matrix m is:" << endl << m << endl;
diff --git a/doc/snippets/MatrixBase_template_int_int_topRightCorner.cpp b/doc/snippets/MatrixBase_template_int_int_topRightCorner.cpp
new file mode 100644
index 000000000..c3a177110
--- /dev/null
+++ b/doc/snippets/MatrixBase_template_int_int_topRightCorner.cpp
@@ -0,0 +1,6 @@
+Matrix4i m = Matrix4i::Random();
+cout << "Here is the matrix m:" << endl << m << endl;
+cout << "Here is m.topRightCorner<2,2>():" << endl;
+cout << m.topRightCorner<2,2>() << endl;
+m.topRightCorner<2,2>().setZero();
+cout << "Now the matrix m is:" << endl << m << endl;
diff --git a/doc/snippets/MatrixBase_template_int_leftCols.cpp b/doc/snippets/MatrixBase_template_int_leftCols.cpp
new file mode 100644
index 000000000..1c425d917
--- /dev/null
+++ b/doc/snippets/MatrixBase_template_int_leftCols.cpp
@@ -0,0 +1,6 @@
+Array44i a = Array44i::Random();
+cout << "Here is the array a:" << endl << a << endl;
+cout << "Here is a.leftCols<2>():" << endl;
+cout << a.leftCols<2>() << endl;
+a.leftCols<2>().setZero();
+cout << "Now the array a is:" << endl << a << endl;
diff --git a/doc/snippets/MatrixBase_template_int_rightCols.cpp b/doc/snippets/MatrixBase_template_int_rightCols.cpp
new file mode 100644
index 000000000..fc8c0d93c
--- /dev/null
+++ b/doc/snippets/MatrixBase_template_int_rightCols.cpp
@@ -0,0 +1,6 @@
+Array44i a = Array44i::Random();
+cout << "Here is the array a:" << endl << a << endl;
+cout << "Here is a.rightCols<2>():" << endl;
+cout << a.rightCols<2>() << endl;
+a.rightCols<2>().setZero();
+cout << "Now the array a is:" << endl << a << endl;
diff --git a/doc/snippets/MatrixBase_template_int_segment.cpp b/doc/snippets/MatrixBase_template_int_segment.cpp
new file mode 100644
index 000000000..e448b4022
--- /dev/null
+++ b/doc/snippets/MatrixBase_template_int_segment.cpp
@@ -0,0 +1,5 @@
+RowVector4i v = RowVector4i::Random();
+cout << "Here is the vector v:" << endl << v << endl;
+cout << "Here is v.segment<2>(1):" << endl << v.segment<2>(1) << endl;
+v.segment<2>(2).setZero();
+cout << "Now the vector v is:" << endl << v << endl;
diff --git a/doc/snippets/MatrixBase_template_int_start.cpp b/doc/snippets/MatrixBase_template_int_start.cpp
new file mode 100644
index 000000000..d336b3716
--- /dev/null
+++ b/doc/snippets/MatrixBase_template_int_start.cpp
@@ -0,0 +1,5 @@
+RowVector4i v = RowVector4i::Random();
+cout << "Here is the vector v:" << endl << v << endl;
+cout << "Here is v.head(2):" << endl << v.head<2>() << endl;
+v.head<2>().setZero();
+cout << "Now the vector v is:" << endl << v << endl;
diff --git a/doc/snippets/MatrixBase_template_int_topRows.cpp b/doc/snippets/MatrixBase_template_int_topRows.cpp
new file mode 100644
index 000000000..0110251a5
--- /dev/null
+++ b/doc/snippets/MatrixBase_template_int_topRows.cpp
@@ -0,0 +1,6 @@
+Array44i a = Array44i::Random();
+cout << "Here is the array a:" << endl << a << endl;
+cout << "Here is a.topRows<2>():" << endl;
+cout << a.topRows<2>() << endl;
+a.topRows<2>().setZero();
+cout << "Now the array a is:" << endl << a << endl;
diff --git a/doc/snippets/MatrixBase_topLeftCorner_int_int.cpp b/doc/snippets/MatrixBase_topLeftCorner_int_int.cpp
new file mode 100644
index 000000000..e52cb3bdb
--- /dev/null
+++ b/doc/snippets/MatrixBase_topLeftCorner_int_int.cpp
@@ -0,0 +1,6 @@
+Matrix4i m = Matrix4i::Random();
+cout << "Here is the matrix m:" << endl << m << endl;
+cout << "Here is m.topLeftCorner(2, 2):" << endl;
+cout << m.topLeftCorner(2, 2) << endl;
+m.topLeftCorner(2, 2).setZero();
+cout << "Now the matrix m is:" << endl << m << endl;
diff --git a/doc/snippets/MatrixBase_topRightCorner_int_int.cpp b/doc/snippets/MatrixBase_topRightCorner_int_int.cpp
new file mode 100644
index 000000000..811fa563e
--- /dev/null
+++ b/doc/snippets/MatrixBase_topRightCorner_int_int.cpp
@@ -0,0 +1,6 @@
+Matrix4i m = Matrix4i::Random();
+cout << "Here is the matrix m:" << endl << m << endl;
+cout << "Here is m.topRightCorner(2, 2):" << endl;
+cout << m.topRightCorner(2, 2) << endl;
+m.topRightCorner(2, 2).setZero();
+cout << "Now the matrix m is:" << endl << m << endl;
diff --git a/doc/snippets/MatrixBase_topRows_int.cpp b/doc/snippets/MatrixBase_topRows_int.cpp
new file mode 100644
index 000000000..f2d75f1cb
--- /dev/null
+++ b/doc/snippets/MatrixBase_topRows_int.cpp
@@ -0,0 +1,6 @@
+Array44i a = Array44i::Random();
+cout << "Here is the array a:" << endl << a << endl;
+cout << "Here is a.topRows(2):" << endl;
+cout << a.topRows(2) << endl;
+a.topRows(2).setZero();
+cout << "Now the array a is:" << endl << a << endl;
diff --git a/doc/snippets/MatrixBase_transpose.cpp b/doc/snippets/MatrixBase_transpose.cpp
new file mode 100644
index 000000000..88eea83c4
--- /dev/null
+++ b/doc/snippets/MatrixBase_transpose.cpp
@@ -0,0 +1,8 @@
+Matrix2i m = Matrix2i::Random();
+cout << "Here is the matrix m:" << endl << m << endl;
+cout << "Here is the transpose of m:" << endl << m.transpose() << endl;
+cout << "Here is the coefficient (1,0) in the transpose of m:" << endl
+ << m.transpose()(1,0) << endl;
+cout << "Let us overwrite this coefficient with the value 0." << endl;
+m.transpose()(1,0) = 0;
+cout << "Now the matrix m is:" << endl << m << endl;
diff --git a/doc/snippets/MatrixBase_zero.cpp b/doc/snippets/MatrixBase_zero.cpp
new file mode 100644
index 000000000..606493677
--- /dev/null
+++ b/doc/snippets/MatrixBase_zero.cpp
@@ -0,0 +1,2 @@
+cout << Matrix2d::Zero() << endl;
+cout << RowVector4i::Zero() << endl;
diff --git a/doc/snippets/MatrixBase_zero_int.cpp b/doc/snippets/MatrixBase_zero_int.cpp
new file mode 100644
index 000000000..370a9ba0a
--- /dev/null
+++ b/doc/snippets/MatrixBase_zero_int.cpp
@@ -0,0 +1,2 @@
+cout << RowVectorXi::Zero(4) << endl;
+cout << VectorXf::Zero(2) << endl;
diff --git a/doc/snippets/MatrixBase_zero_int_int.cpp b/doc/snippets/MatrixBase_zero_int_int.cpp
new file mode 100644
index 000000000..4099c5d4d
--- /dev/null
+++ b/doc/snippets/MatrixBase_zero_int_int.cpp
@@ -0,0 +1 @@
+cout << MatrixXi::Zero(2,3) << endl;
diff --git a/doc/snippets/Matrix_resize_NoChange_int.cpp b/doc/snippets/Matrix_resize_NoChange_int.cpp
new file mode 100644
index 000000000..acdf18c46
--- /dev/null
+++ b/doc/snippets/Matrix_resize_NoChange_int.cpp
@@ -0,0 +1,3 @@
+MatrixXd m(3,4);
+m.resize(NoChange, 5);
+cout << "m: " << m.rows() << " rows, " << m.cols() << " cols" << endl;
diff --git a/doc/snippets/Matrix_resize_int.cpp b/doc/snippets/Matrix_resize_int.cpp
new file mode 100644
index 000000000..044c78989
--- /dev/null
+++ b/doc/snippets/Matrix_resize_int.cpp
@@ -0,0 +1,6 @@
+VectorXd v(10);
+v.resize(3);
+RowVector3d w;
+w.resize(3); // this is legal, but has no effect
+cout << "v: " << v.rows() << " rows, " << v.cols() << " cols" << endl;
+cout << "w: " << w.rows() << " rows, " << w.cols() << " cols" << endl;
diff --git a/doc/snippets/Matrix_resize_int_NoChange.cpp b/doc/snippets/Matrix_resize_int_NoChange.cpp
new file mode 100644
index 000000000..5c37c9067
--- /dev/null
+++ b/doc/snippets/Matrix_resize_int_NoChange.cpp
@@ -0,0 +1,3 @@
+MatrixXd m(3,4);
+m.resize(5, NoChange);
+cout << "m: " << m.rows() << " rows, " << m.cols() << " cols" << endl;
diff --git a/doc/snippets/Matrix_resize_int_int.cpp b/doc/snippets/Matrix_resize_int_int.cpp
new file mode 100644
index 000000000..bfd474159
--- /dev/null
+++ b/doc/snippets/Matrix_resize_int_int.cpp
@@ -0,0 +1,9 @@
+MatrixXd m(2,3);
+m << 1,2,3,4,5,6;
+cout << "here's the 2x3 matrix m:" << endl << m << endl;
+cout << "let's resize m to 3x2. This is a conservative resizing because 2*3==3*2." << endl;
+m.resize(3,2);
+cout << "here's the 3x2 matrix m:" << endl << m << endl;
+cout << "now let's resize m to size 2x2. This is NOT a conservative resizing, so it becomes uninitialized:" << endl;
+m.resize(2,2);
+cout << m << endl;
diff --git a/doc/snippets/Matrix_setConstant_int.cpp b/doc/snippets/Matrix_setConstant_int.cpp
new file mode 100644
index 000000000..ff5a86c98
--- /dev/null
+++ b/doc/snippets/Matrix_setConstant_int.cpp
@@ -0,0 +1,3 @@
+VectorXf v;
+v.setConstant(3, 5);
+cout << v << endl;
diff --git a/doc/snippets/Matrix_setConstant_int_int.cpp b/doc/snippets/Matrix_setConstant_int_int.cpp
new file mode 100644
index 000000000..32b950cfd
--- /dev/null
+++ b/doc/snippets/Matrix_setConstant_int_int.cpp
@@ -0,0 +1,3 @@
+MatrixXf m;
+m.setConstant(3, 3, 5);
+cout << m << endl;
diff --git a/doc/snippets/Matrix_setIdentity_int_int.cpp b/doc/snippets/Matrix_setIdentity_int_int.cpp
new file mode 100644
index 000000000..a65967199
--- /dev/null
+++ b/doc/snippets/Matrix_setIdentity_int_int.cpp
@@ -0,0 +1,3 @@
+MatrixXf m;
+m.setIdentity(3, 3);
+cout << m << endl;
diff --git a/doc/snippets/Matrix_setOnes_int.cpp b/doc/snippets/Matrix_setOnes_int.cpp
new file mode 100644
index 000000000..752cb35b2
--- /dev/null
+++ b/doc/snippets/Matrix_setOnes_int.cpp
@@ -0,0 +1,3 @@
+VectorXf v;
+v.setOnes(3);
+cout << v << endl;
diff --git a/doc/snippets/Matrix_setOnes_int_int.cpp b/doc/snippets/Matrix_setOnes_int_int.cpp
new file mode 100644
index 000000000..1ffb66bbd
--- /dev/null
+++ b/doc/snippets/Matrix_setOnes_int_int.cpp
@@ -0,0 +1,3 @@
+MatrixXf m;
+m.setOnes(3, 3);
+cout << m << endl;
diff --git a/doc/snippets/Matrix_setRandom_int.cpp b/doc/snippets/Matrix_setRandom_int.cpp
new file mode 100644
index 000000000..e160dd7df
--- /dev/null
+++ b/doc/snippets/Matrix_setRandom_int.cpp
@@ -0,0 +1,3 @@
+VectorXf v;
+v.setRandom(3);
+cout << v << endl;
diff --git a/doc/snippets/Matrix_setRandom_int_int.cpp b/doc/snippets/Matrix_setRandom_int_int.cpp
new file mode 100644
index 000000000..80cda11d7
--- /dev/null
+++ b/doc/snippets/Matrix_setRandom_int_int.cpp
@@ -0,0 +1,3 @@
+MatrixXf m;
+m.setRandom(3, 3);
+cout << m << endl;
diff --git a/doc/snippets/Matrix_setZero_int.cpp b/doc/snippets/Matrix_setZero_int.cpp
new file mode 100644
index 000000000..0fb16c1f3
--- /dev/null
+++ b/doc/snippets/Matrix_setZero_int.cpp
@@ -0,0 +1,3 @@
+VectorXf v;
+v.setZero(3);
+cout << v << endl;
diff --git a/doc/snippets/Matrix_setZero_int_int.cpp b/doc/snippets/Matrix_setZero_int_int.cpp
new file mode 100644
index 000000000..ad883b916
--- /dev/null
+++ b/doc/snippets/Matrix_setZero_int_int.cpp
@@ -0,0 +1,3 @@
+MatrixXf m;
+m.setZero(3, 3);
+cout << m << endl;
diff --git a/doc/snippets/PartialPivLU_solve.cpp b/doc/snippets/PartialPivLU_solve.cpp
new file mode 100644
index 000000000..fa3570ab8
--- /dev/null
+++ b/doc/snippets/PartialPivLU_solve.cpp
@@ -0,0 +1,7 @@
+MatrixXd A = MatrixXd::Random(3,3);
+MatrixXd B = MatrixXd::Random(3,2);
+cout << "Here is the invertible matrix A:" << endl << A << endl;
+cout << "Here is the matrix B:" << endl << B << endl;
+MatrixXd X = A.lu().solve(B);
+cout << "Here is the (unique) solution X to the equation AX=B:" << endl << X << endl;
+cout << "Relative error: " << (A*X-B).norm() / B.norm() << endl;
diff --git a/doc/snippets/PartialRedux_count.cpp b/doc/snippets/PartialRedux_count.cpp
new file mode 100644
index 000000000..c7b3097e4
--- /dev/null
+++ b/doc/snippets/PartialRedux_count.cpp
@@ -0,0 +1,3 @@
+Matrix3d m = Matrix3d::Random();
+cout << "Here is the matrix m:" << endl << m << endl;
+cout << "Here is the count of elements larger or equal than 0.5 of each row:" << endl << (m.array() >= 0.5).rowwise().count() << endl;
diff --git a/doc/snippets/PartialRedux_maxCoeff.cpp b/doc/snippets/PartialRedux_maxCoeff.cpp
new file mode 100644
index 000000000..e8fd3820d
--- /dev/null
+++ b/doc/snippets/PartialRedux_maxCoeff.cpp
@@ -0,0 +1,3 @@
+Matrix3d m = Matrix3d::Random();
+cout << "Here is the matrix m:" << endl << m << endl;
+cout << "Here is the maximum of each column:" << endl << m.colwise().maxCoeff() << endl;
diff --git a/doc/snippets/PartialRedux_minCoeff.cpp b/doc/snippets/PartialRedux_minCoeff.cpp
new file mode 100644
index 000000000..d717bc0d1
--- /dev/null
+++ b/doc/snippets/PartialRedux_minCoeff.cpp
@@ -0,0 +1,3 @@
+Matrix3d m = Matrix3d::Random();
+cout << "Here is the matrix m:" << endl << m << endl;
+cout << "Here is the minimum of each column:" << endl << m.colwise().minCoeff() << endl;
diff --git a/doc/snippets/PartialRedux_norm.cpp b/doc/snippets/PartialRedux_norm.cpp
new file mode 100644
index 000000000..dbcf290a0
--- /dev/null
+++ b/doc/snippets/PartialRedux_norm.cpp
@@ -0,0 +1,3 @@
+Matrix3d m = Matrix3d::Random();
+cout << "Here is the matrix m:" << endl << m << endl;
+cout << "Here is the norm of each column:" << endl << m.colwise().norm() << endl;
diff --git a/doc/snippets/PartialRedux_prod.cpp b/doc/snippets/PartialRedux_prod.cpp
new file mode 100644
index 000000000..aacf09cbb
--- /dev/null
+++ b/doc/snippets/PartialRedux_prod.cpp
@@ -0,0 +1,3 @@
+Matrix3d m = Matrix3d::Random();
+cout << "Here is the matrix m:" << endl << m << endl;
+cout << "Here is the product of each row:" << endl << m.rowwise().prod() << endl;
diff --git a/doc/snippets/PartialRedux_squaredNorm.cpp b/doc/snippets/PartialRedux_squaredNorm.cpp
new file mode 100644
index 000000000..9f3293e65
--- /dev/null
+++ b/doc/snippets/PartialRedux_squaredNorm.cpp
@@ -0,0 +1,3 @@
+Matrix3d m = Matrix3d::Random();
+cout << "Here is the matrix m:" << endl << m << endl;
+cout << "Here is the square norm of each row:" << endl << m.rowwise().squaredNorm() << endl;
diff --git a/doc/snippets/PartialRedux_sum.cpp b/doc/snippets/PartialRedux_sum.cpp
new file mode 100644
index 000000000..ec82d3e41
--- /dev/null
+++ b/doc/snippets/PartialRedux_sum.cpp
@@ -0,0 +1,3 @@
+Matrix3d m = Matrix3d::Random();
+cout << "Here is the matrix m:" << endl << m << endl;
+cout << "Here is the sum of each row:" << endl << m.rowwise().sum() << endl;
diff --git a/doc/snippets/RealSchur_RealSchur_MatrixType.cpp b/doc/snippets/RealSchur_RealSchur_MatrixType.cpp
new file mode 100644
index 000000000..a5530dcc8
--- /dev/null
+++ b/doc/snippets/RealSchur_RealSchur_MatrixType.cpp
@@ -0,0 +1,10 @@
+MatrixXd A = MatrixXd::Random(6,6);
+cout << "Here is a random 6x6 matrix, A:" << endl << A << endl << endl;
+
+RealSchur<MatrixXd> schur(A);
+cout << "The orthogonal matrix U is:" << endl << schur.matrixU() << endl;
+cout << "The quasi-triangular matrix T is:" << endl << schur.matrixT() << endl << endl;
+
+MatrixXd U = schur.matrixU();
+MatrixXd T = schur.matrixT();
+cout << "U * T * U^T = " << endl << U * T * U.transpose() << endl;
diff --git a/doc/snippets/RealSchur_compute.cpp b/doc/snippets/RealSchur_compute.cpp
new file mode 100644
index 000000000..20c2611b8
--- /dev/null
+++ b/doc/snippets/RealSchur_compute.cpp
@@ -0,0 +1,6 @@
+MatrixXf A = MatrixXf::Random(4,4);
+RealSchur<MatrixXf> schur(4);
+schur.compute(A, /* computeU = */ false);
+cout << "The matrix T in the decomposition of A is:" << endl << schur.matrixT() << endl;
+schur.compute(A.inverse(), /* computeU = */ false);
+cout << "The matrix T in the decomposition of A^(-1) is:" << endl << schur.matrixT() << endl;
diff --git a/doc/snippets/SelfAdjointEigenSolver_SelfAdjointEigenSolver.cpp b/doc/snippets/SelfAdjointEigenSolver_SelfAdjointEigenSolver.cpp
new file mode 100644
index 000000000..73a7f6252
--- /dev/null
+++ b/doc/snippets/SelfAdjointEigenSolver_SelfAdjointEigenSolver.cpp
@@ -0,0 +1,7 @@
+SelfAdjointEigenSolver<Matrix4f> es;
+Matrix4f X = Matrix4f::Random(4,4);
+Matrix4f A = X + X.transpose();
+es.compute(A);
+cout << "The eigenvalues of A are: " << es.eigenvalues().transpose() << endl;
+es.compute(A + Matrix4f::Identity(4,4)); // re-use es to compute eigenvalues of A+I
+cout << "The eigenvalues of A+I are: " << es.eigenvalues().transpose() << endl;
diff --git a/doc/snippets/SelfAdjointEigenSolver_SelfAdjointEigenSolver_MatrixType.cpp b/doc/snippets/SelfAdjointEigenSolver_SelfAdjointEigenSolver_MatrixType.cpp
new file mode 100644
index 000000000..3599b17a0
--- /dev/null
+++ b/doc/snippets/SelfAdjointEigenSolver_SelfAdjointEigenSolver_MatrixType.cpp
@@ -0,0 +1,17 @@
+MatrixXd X = MatrixXd::Random(5,5);
+MatrixXd A = X + X.transpose();
+cout << "Here is a random symmetric 5x5 matrix, A:" << endl << A << endl << endl;
+
+SelfAdjointEigenSolver<MatrixXd> es(A);
+cout << "The eigenvalues of A are:" << endl << es.eigenvalues() << endl;
+cout << "The matrix of eigenvectors, V, is:" << endl << es.eigenvectors() << endl << endl;
+
+double lambda = es.eigenvalues()[0];
+cout << "Consider the first eigenvalue, lambda = " << lambda << endl;
+VectorXd v = es.eigenvectors().col(0);
+cout << "If v is the corresponding eigenvector, then lambda * v = " << endl << lambda * v << endl;
+cout << "... and A * v = " << endl << A * v << endl << endl;
+
+MatrixXd D = es.eigenvalues().asDiagonal();
+MatrixXd V = es.eigenvectors();
+cout << "Finally, V * D * V^(-1) = " << endl << V * D * V.inverse() << endl;
diff --git a/doc/snippets/SelfAdjointEigenSolver_SelfAdjointEigenSolver_MatrixType2.cpp b/doc/snippets/SelfAdjointEigenSolver_SelfAdjointEigenSolver_MatrixType2.cpp
new file mode 100644
index 000000000..bbb821e02
--- /dev/null
+++ b/doc/snippets/SelfAdjointEigenSolver_SelfAdjointEigenSolver_MatrixType2.cpp
@@ -0,0 +1,16 @@
+MatrixXd X = MatrixXd::Random(5,5);
+MatrixXd A = X + X.transpose();
+cout << "Here is a random symmetric matrix, A:" << endl << A << endl;
+X = MatrixXd::Random(5,5);
+MatrixXd B = X * X.transpose();
+cout << "and a random postive-definite matrix, B:" << endl << B << endl << endl;
+
+GeneralizedSelfAdjointEigenSolver<MatrixXd> es(A,B);
+cout << "The eigenvalues of the pencil (A,B) are:" << endl << es.eigenvalues() << endl;
+cout << "The matrix of eigenvectors, V, is:" << endl << es.eigenvectors() << endl << endl;
+
+double lambda = es.eigenvalues()[0];
+cout << "Consider the first eigenvalue, lambda = " << lambda << endl;
+VectorXd v = es.eigenvectors().col(0);
+cout << "If v is the corresponding eigenvector, then A * v = " << endl << A * v << endl;
+cout << "... and lambda * B * v = " << endl << lambda * B * v << endl << endl;
diff --git a/doc/snippets/SelfAdjointEigenSolver_compute_MatrixType.cpp b/doc/snippets/SelfAdjointEigenSolver_compute_MatrixType.cpp
new file mode 100644
index 000000000..2975cc3f2
--- /dev/null
+++ b/doc/snippets/SelfAdjointEigenSolver_compute_MatrixType.cpp
@@ -0,0 +1,7 @@
+SelfAdjointEigenSolver<MatrixXf> es(4);
+MatrixXf X = MatrixXf::Random(4,4);
+MatrixXf A = X + X.transpose();
+es.compute(A);
+cout << "The eigenvalues of A are: " << es.eigenvalues().transpose() << endl;
+es.compute(A + MatrixXf::Identity(4,4)); // re-use es to compute eigenvalues of A+I
+cout << "The eigenvalues of A+I are: " << es.eigenvalues().transpose() << endl;
diff --git a/doc/snippets/SelfAdjointEigenSolver_compute_MatrixType2.cpp b/doc/snippets/SelfAdjointEigenSolver_compute_MatrixType2.cpp
new file mode 100644
index 000000000..07c92a1e4
--- /dev/null
+++ b/doc/snippets/SelfAdjointEigenSolver_compute_MatrixType2.cpp
@@ -0,0 +1,9 @@
+MatrixXd X = MatrixXd::Random(5,5);
+MatrixXd A = X * X.transpose();
+X = MatrixXd::Random(5,5);
+MatrixXd B = X * X.transpose();
+
+GeneralizedSelfAdjointEigenSolver<MatrixXd> es(A,B,EigenvaluesOnly);
+cout << "The eigenvalues of the pencil (A,B) are:" << endl << es.eigenvalues() << endl;
+es.compute(B,A,false);
+cout << "The eigenvalues of the pencil (B,A) are:" << endl << es.eigenvalues() << endl;
diff --git a/doc/snippets/SelfAdjointEigenSolver_eigenvalues.cpp b/doc/snippets/SelfAdjointEigenSolver_eigenvalues.cpp
new file mode 100644
index 000000000..0ff33c68d
--- /dev/null
+++ b/doc/snippets/SelfAdjointEigenSolver_eigenvalues.cpp
@@ -0,0 +1,4 @@
+MatrixXd ones = MatrixXd::Ones(3,3);
+SelfAdjointEigenSolver<MatrixXd> es(ones);
+cout << "The eigenvalues of the 3x3 matrix of ones are:"
+ << endl << es.eigenvalues() << endl;
diff --git a/doc/snippets/SelfAdjointEigenSolver_eigenvectors.cpp b/doc/snippets/SelfAdjointEigenSolver_eigenvectors.cpp
new file mode 100644
index 000000000..cfc8b0d54
--- /dev/null
+++ b/doc/snippets/SelfAdjointEigenSolver_eigenvectors.cpp
@@ -0,0 +1,4 @@
+MatrixXd ones = MatrixXd::Ones(3,3);
+SelfAdjointEigenSolver<MatrixXd> es(ones);
+cout << "The first eigenvector of the 3x3 matrix of ones is:"
+ << endl << es.eigenvectors().col(1) << endl;
diff --git a/doc/snippets/SelfAdjointEigenSolver_operatorInverseSqrt.cpp b/doc/snippets/SelfAdjointEigenSolver_operatorInverseSqrt.cpp
new file mode 100644
index 000000000..114c65fb3
--- /dev/null
+++ b/doc/snippets/SelfAdjointEigenSolver_operatorInverseSqrt.cpp
@@ -0,0 +1,9 @@
+MatrixXd X = MatrixXd::Random(4,4);
+MatrixXd A = X * X.transpose();
+cout << "Here is a random positive-definite matrix, A:" << endl << A << endl << endl;
+
+SelfAdjointEigenSolver<MatrixXd> es(A);
+cout << "The inverse square root of A is: " << endl;
+cout << es.operatorInverseSqrt() << endl;
+cout << "We can also compute it with operatorSqrt() and inverse(). That yields: " << endl;
+cout << es.operatorSqrt().inverse() << endl;
diff --git a/doc/snippets/SelfAdjointEigenSolver_operatorSqrt.cpp b/doc/snippets/SelfAdjointEigenSolver_operatorSqrt.cpp
new file mode 100644
index 000000000..eeacca74b
--- /dev/null
+++ b/doc/snippets/SelfAdjointEigenSolver_operatorSqrt.cpp
@@ -0,0 +1,8 @@
+MatrixXd X = MatrixXd::Random(4,4);
+MatrixXd A = X * X.transpose();
+cout << "Here is a random positive-definite matrix, A:" << endl << A << endl << endl;
+
+SelfAdjointEigenSolver<MatrixXd> es(A);
+MatrixXd sqrtA = es.operatorSqrt();
+cout << "The square root of A is: " << endl << sqrtA << endl;
+cout << "If we square this, we get: " << endl << sqrtA*sqrtA << endl;
diff --git a/doc/snippets/SelfAdjointView_eigenvalues.cpp b/doc/snippets/SelfAdjointView_eigenvalues.cpp
new file mode 100644
index 000000000..be1986778
--- /dev/null
+++ b/doc/snippets/SelfAdjointView_eigenvalues.cpp
@@ -0,0 +1,3 @@
+MatrixXd ones = MatrixXd::Ones(3,3);
+VectorXd eivals = ones.selfadjointView<Lower>().eigenvalues();
+cout << "The eigenvalues of the 3x3 matrix of ones are:" << endl << eivals << endl;
diff --git a/doc/snippets/SelfAdjointView_operatorNorm.cpp b/doc/snippets/SelfAdjointView_operatorNorm.cpp
new file mode 100644
index 000000000..f380f5594
--- /dev/null
+++ b/doc/snippets/SelfAdjointView_operatorNorm.cpp
@@ -0,0 +1,3 @@
+MatrixXd ones = MatrixXd::Ones(3,3);
+cout << "The operator norm of the 3x3 matrix of ones is "
+ << ones.selfadjointView<Lower>().operatorNorm() << endl;
diff --git a/doc/snippets/TopicAliasing_block.cpp b/doc/snippets/TopicAliasing_block.cpp
new file mode 100644
index 000000000..03282f4f0
--- /dev/null
+++ b/doc/snippets/TopicAliasing_block.cpp
@@ -0,0 +1,7 @@
+MatrixXi mat(3,3);
+mat << 1, 2, 3, 4, 5, 6, 7, 8, 9;
+cout << "Here is the matrix mat:\n" << mat << endl;
+
+// This assignment shows the aliasing problem
+mat.bottomRightCorner(2,2) = mat.topLeftCorner(2,2);
+cout << "After the assignment, mat = \n" << mat << endl;
diff --git a/doc/snippets/TopicAliasing_block_correct.cpp b/doc/snippets/TopicAliasing_block_correct.cpp
new file mode 100644
index 000000000..6fee5801e
--- /dev/null
+++ b/doc/snippets/TopicAliasing_block_correct.cpp
@@ -0,0 +1,7 @@
+MatrixXi mat(3,3);
+mat << 1, 2, 3, 4, 5, 6, 7, 8, 9;
+cout << "Here is the matrix mat:\n" << mat << endl;
+
+// The eval() solves the aliasing problem
+mat.bottomRightCorner(2,2) = mat.topLeftCorner(2,2).eval();
+cout << "After the assignment, mat = \n" << mat << endl;
diff --git a/doc/snippets/TopicAliasing_cwise.cpp b/doc/snippets/TopicAliasing_cwise.cpp
new file mode 100644
index 000000000..7049f6c56
--- /dev/null
+++ b/doc/snippets/TopicAliasing_cwise.cpp
@@ -0,0 +1,20 @@
+MatrixXf mat(2,2);
+mat << 1, 2, 4, 7;
+cout << "Here is the matrix mat:\n" << mat << endl << endl;
+
+mat = 2 * mat;
+cout << "After 'mat = 2 * mat', mat = \n" << mat << endl << endl;
+
+
+mat = mat - MatrixXf::Identity(2,2);
+cout << "After the subtraction, it becomes\n" << mat << endl << endl;
+
+
+ArrayXXf arr = mat;
+arr = arr.square();
+cout << "After squaring, it becomes\n" << arr << endl << endl;
+
+// Combining all operations in one statement:
+mat << 1, 2, 4, 7;
+mat = (2 * mat - MatrixXf::Identity(2,2)).array().square();
+cout << "Doing everything at once yields\n" << mat << endl << endl;
diff --git a/doc/snippets/TopicAliasing_mult1.cpp b/doc/snippets/TopicAliasing_mult1.cpp
new file mode 100644
index 000000000..cd7e9004c
--- /dev/null
+++ b/doc/snippets/TopicAliasing_mult1.cpp
@@ -0,0 +1,4 @@
+MatrixXf matA(2,2);
+matA << 2, 0, 0, 2;
+matA = matA * matA;
+cout << matA;
diff --git a/doc/snippets/TopicAliasing_mult2.cpp b/doc/snippets/TopicAliasing_mult2.cpp
new file mode 100644
index 000000000..a3ff56851
--- /dev/null
+++ b/doc/snippets/TopicAliasing_mult2.cpp
@@ -0,0 +1,10 @@
+MatrixXf matA(2,2), matB(2,2);
+matA << 2, 0, 0, 2;
+
+// Simple but not quite as efficient
+matB = matA * matA;
+cout << matB << endl << endl;
+
+// More complicated but also more efficient
+matB.noalias() = matA * matA;
+cout << matB;
diff --git a/doc/snippets/TopicAliasing_mult3.cpp b/doc/snippets/TopicAliasing_mult3.cpp
new file mode 100644
index 000000000..1d12a6c67
--- /dev/null
+++ b/doc/snippets/TopicAliasing_mult3.cpp
@@ -0,0 +1,4 @@
+MatrixXf matA(2,2);
+matA << 2, 0, 0, 2;
+matA.noalias() = matA * matA;
+cout << matA;
diff --git a/doc/snippets/TopicStorageOrders_example.cpp b/doc/snippets/TopicStorageOrders_example.cpp
new file mode 100644
index 000000000..0623ef0c2
--- /dev/null
+++ b/doc/snippets/TopicStorageOrders_example.cpp
@@ -0,0 +1,18 @@
+Matrix<int, 3, 4, ColMajor> Acolmajor;
+Acolmajor << 8, 2, 2, 9,
+ 9, 1, 4, 4,
+ 3, 5, 4, 5;
+cout << "The matrix A:" << endl;
+cout << Acolmajor << endl << endl;
+
+cout << "In memory (column-major):" << endl;
+for (int i = 0; i < Acolmajor.size(); i++)
+ cout << *(Acolmajor.data() + i) << " ";
+cout << endl << endl;
+
+Matrix<int, 3, 4, RowMajor> Arowmajor = Acolmajor;
+cout << "In memory (row-major):" << endl;
+for (int i = 0; i < Arowmajor.size(); i++)
+ cout << *(Arowmajor.data() + i) << " ";
+cout << endl;
+
diff --git a/doc/snippets/Tridiagonalization_Tridiagonalization_MatrixType.cpp b/doc/snippets/Tridiagonalization_Tridiagonalization_MatrixType.cpp
new file mode 100644
index 000000000..a26012433
--- /dev/null
+++ b/doc/snippets/Tridiagonalization_Tridiagonalization_MatrixType.cpp
@@ -0,0 +1,9 @@
+MatrixXd X = MatrixXd::Random(5,5);
+MatrixXd A = X + X.transpose();
+cout << "Here is a random symmetric 5x5 matrix:" << endl << A << endl << endl;
+Tridiagonalization<MatrixXd> triOfA(A);
+MatrixXd Q = triOfA.matrixQ();
+cout << "The orthogonal matrix Q is:" << endl << Q << endl;
+MatrixXd T = triOfA.matrixT();
+cout << "The tridiagonal matrix T is:" << endl << T << endl << endl;
+cout << "Q * T * Q^T = " << endl << Q * T * Q.transpose() << endl;
diff --git a/doc/snippets/Tridiagonalization_compute.cpp b/doc/snippets/Tridiagonalization_compute.cpp
new file mode 100644
index 000000000..0062a99e8
--- /dev/null
+++ b/doc/snippets/Tridiagonalization_compute.cpp
@@ -0,0 +1,9 @@
+Tridiagonalization<MatrixXf> tri;
+MatrixXf X = MatrixXf::Random(4,4);
+MatrixXf A = X + X.transpose();
+tri.compute(A);
+cout << "The matrix T in the tridiagonal decomposition of A is: " << endl;
+cout << tri.matrixT() << endl;
+tri.compute(2*A); // re-use tri to compute eigenvalues of 2A
+cout << "The matrix T in the tridiagonal decomposition of 2A is: " << endl;
+cout << tri.matrixT() << endl;
diff --git a/doc/snippets/Tridiagonalization_decomposeInPlace.cpp b/doc/snippets/Tridiagonalization_decomposeInPlace.cpp
new file mode 100644
index 000000000..93dcfca1d
--- /dev/null
+++ b/doc/snippets/Tridiagonalization_decomposeInPlace.cpp
@@ -0,0 +1,10 @@
+MatrixXd X = MatrixXd::Random(5,5);
+MatrixXd A = X + X.transpose();
+cout << "Here is a random symmetric 5x5 matrix:" << endl << A << endl << endl;
+
+VectorXd diag(5);
+VectorXd subdiag(4);
+internal::tridiagonalization_inplace(A, diag, subdiag, true);
+cout << "The orthogonal matrix Q is:" << endl << A << endl;
+cout << "The diagonal of the tridiagonal matrix T is:" << endl << diag << endl;
+cout << "The subdiagonal of the tridiagonal matrix T is:" << endl << subdiag << endl;
diff --git a/doc/snippets/Tridiagonalization_diagonal.cpp b/doc/snippets/Tridiagonalization_diagonal.cpp
new file mode 100644
index 000000000..6eec82169
--- /dev/null
+++ b/doc/snippets/Tridiagonalization_diagonal.cpp
@@ -0,0 +1,13 @@
+MatrixXcd X = MatrixXcd::Random(4,4);
+MatrixXcd A = X + X.adjoint();
+cout << "Here is a random self-adjoint 4x4 matrix:" << endl << A << endl << endl;
+
+Tridiagonalization<MatrixXcd> triOfA(A);
+MatrixXd T = triOfA.matrixT();
+cout << "The tridiagonal matrix T is:" << endl << T << endl << endl;
+
+cout << "We can also extract the diagonals of T directly ..." << endl;
+VectorXd diag = triOfA.diagonal();
+cout << "The diagonal is:" << endl << diag << endl;
+VectorXd subdiag = triOfA.subDiagonal();
+cout << "The subdiagonal is:" << endl << subdiag << endl;
diff --git a/doc/snippets/Tridiagonalization_householderCoefficients.cpp b/doc/snippets/Tridiagonalization_householderCoefficients.cpp
new file mode 100644
index 000000000..e5d872880
--- /dev/null
+++ b/doc/snippets/Tridiagonalization_householderCoefficients.cpp
@@ -0,0 +1,6 @@
+Matrix4d X = Matrix4d::Random(4,4);
+Matrix4d A = X + X.transpose();
+cout << "Here is a random symmetric 4x4 matrix:" << endl << A << endl;
+Tridiagonalization<Matrix4d> triOfA(A);
+Vector3d hc = triOfA.householderCoefficients();
+cout << "The vector of Householder coefficients is:" << endl << hc << endl;
diff --git a/doc/snippets/Tridiagonalization_packedMatrix.cpp b/doc/snippets/Tridiagonalization_packedMatrix.cpp
new file mode 100644
index 000000000..0f55d0c28
--- /dev/null
+++ b/doc/snippets/Tridiagonalization_packedMatrix.cpp
@@ -0,0 +1,8 @@
+Matrix4d X = Matrix4d::Random(4,4);
+Matrix4d A = X + X.transpose();
+cout << "Here is a random symmetric 4x4 matrix:" << endl << A << endl;
+Tridiagonalization<Matrix4d> triOfA(A);
+Matrix4d pm = triOfA.packedMatrix();
+cout << "The packed matrix M is:" << endl << pm << endl;
+cout << "The diagonal and subdiagonal corresponds to the matrix T, which is:"
+ << endl << triOfA.matrixT() << endl;
diff --git a/doc/snippets/Tutorial_AdvancedInitialization_Block.cpp b/doc/snippets/Tutorial_AdvancedInitialization_Block.cpp
new file mode 100644
index 000000000..96e40acfb
--- /dev/null
+++ b/doc/snippets/Tutorial_AdvancedInitialization_Block.cpp
@@ -0,0 +1,5 @@
+MatrixXf matA(2, 2);
+matA << 1, 2, 3, 4;
+MatrixXf matB(4, 4);
+matB << matA, matA/10, matA/10, matA;
+std::cout << matB << std::endl;
diff --git a/doc/snippets/Tutorial_AdvancedInitialization_CommaTemporary.cpp b/doc/snippets/Tutorial_AdvancedInitialization_CommaTemporary.cpp
new file mode 100644
index 000000000..50cff4cb6
--- /dev/null
+++ b/doc/snippets/Tutorial_AdvancedInitialization_CommaTemporary.cpp
@@ -0,0 +1,4 @@
+MatrixXf mat = MatrixXf::Random(2, 3);
+std::cout << mat << std::endl << std::endl;
+mat = (MatrixXf(2,2) << 0, 1, 1, 0).finished() * mat;
+std::cout << mat << std::endl;
diff --git a/doc/snippets/Tutorial_AdvancedInitialization_Join.cpp b/doc/snippets/Tutorial_AdvancedInitialization_Join.cpp
new file mode 100644
index 000000000..84e8715cb
--- /dev/null
+++ b/doc/snippets/Tutorial_AdvancedInitialization_Join.cpp
@@ -0,0 +1,11 @@
+RowVectorXd vec1(3);
+vec1 << 1, 2, 3;
+std::cout << "vec1 = " << vec1 << std::endl;
+
+RowVectorXd vec2(4);
+vec2 << 1, 4, 9, 16;;
+std::cout << "vec2 = " << vec2 << std::endl;
+
+RowVectorXd joined(7);
+joined << vec1, vec2;
+std::cout << "joined = " << joined << std::endl;
diff --git a/doc/snippets/Tutorial_AdvancedInitialization_LinSpaced.cpp b/doc/snippets/Tutorial_AdvancedInitialization_LinSpaced.cpp
new file mode 100644
index 000000000..c6a73ab8c
--- /dev/null
+++ b/doc/snippets/Tutorial_AdvancedInitialization_LinSpaced.cpp
@@ -0,0 +1,7 @@
+ArrayXXf table(10, 4);
+table.col(0) = ArrayXf::LinSpaced(10, 0, 90);
+table.col(1) = M_PI / 180 * table.col(0);
+table.col(2) = table.col(1).sin();
+table.col(3) = table.col(1).cos();
+std::cout << " Degrees Radians Sine Cosine\n";
+std::cout << table << std::endl;
diff --git a/doc/snippets/Tutorial_AdvancedInitialization_ThreeWays.cpp b/doc/snippets/Tutorial_AdvancedInitialization_ThreeWays.cpp
new file mode 100644
index 000000000..cb7457652
--- /dev/null
+++ b/doc/snippets/Tutorial_AdvancedInitialization_ThreeWays.cpp
@@ -0,0 +1,20 @@
+const int size = 6;
+MatrixXd mat1(size, size);
+mat1.topLeftCorner(size/2, size/2) = MatrixXd::Zero(size/2, size/2);
+mat1.topRightCorner(size/2, size/2) = MatrixXd::Identity(size/2, size/2);
+mat1.bottomLeftCorner(size/2, size/2) = MatrixXd::Identity(size/2, size/2);
+mat1.bottomRightCorner(size/2, size/2) = MatrixXd::Zero(size/2, size/2);
+std::cout << mat1 << std::endl << std::endl;
+
+MatrixXd mat2(size, size);
+mat2.topLeftCorner(size/2, size/2).setZero();
+mat2.topRightCorner(size/2, size/2).setIdentity();
+mat2.bottomLeftCorner(size/2, size/2).setIdentity();
+mat2.bottomRightCorner(size/2, size/2).setZero();
+std::cout << mat2 << std::endl << std::endl;
+
+MatrixXd mat3(size, size);
+mat3 << MatrixXd::Zero(size/2, size/2), MatrixXd::Identity(size/2, size/2),
+ MatrixXd::Identity(size/2, size/2), MatrixXd::Zero(size/2, size/2);
+std::cout << mat3 << std::endl;
+
diff --git a/doc/snippets/Tutorial_AdvancedInitialization_Zero.cpp b/doc/snippets/Tutorial_AdvancedInitialization_Zero.cpp
new file mode 100644
index 000000000..76a36a319
--- /dev/null
+++ b/doc/snippets/Tutorial_AdvancedInitialization_Zero.cpp
@@ -0,0 +1,13 @@
+std::cout << "A fixed-size array:\n";
+Array33f a1 = Array33f::Zero();
+std::cout << a1 << "\n\n";
+
+
+std::cout << "A one-dimensional dynamic-size array:\n";
+ArrayXf a2 = ArrayXf::Zero(3);
+std::cout << a2 << "\n\n";
+
+
+std::cout << "A two-dimensional dynamic-size array:\n";
+ArrayXXf a3 = ArrayXXf::Zero(3, 4);
+std::cout << a3 << "\n";
diff --git a/doc/snippets/Tutorial_Map_rowmajor.cpp b/doc/snippets/Tutorial_Map_rowmajor.cpp
new file mode 100644
index 000000000..fd45ace03
--- /dev/null
+++ b/doc/snippets/Tutorial_Map_rowmajor.cpp
@@ -0,0 +1,7 @@
+int array[8];
+for(int i = 0; i < 8; ++i) array[i] = i;
+cout << "Column-major:\n" << Map<Matrix<int,2,4> >(array) << endl;
+cout << "Row-major:\n" << Map<Matrix<int,2,4,RowMajor> >(array) << endl;
+cout << "Row-major using stride:\n" <<
+ Map<Matrix<int,2,4>, Unaligned, Stride<1,4> >(array) << endl;
+
diff --git a/doc/snippets/Tutorial_Map_using.cpp b/doc/snippets/Tutorial_Map_using.cpp
new file mode 100644
index 000000000..e5e499f1f
--- /dev/null
+++ b/doc/snippets/Tutorial_Map_using.cpp
@@ -0,0 +1,21 @@
+typedef Matrix<float,1,Dynamic> MatrixType;
+typedef Map<MatrixType> MapType;
+typedef Map<const MatrixType> MapTypeConst; // a read-only map
+const int n_dims = 5;
+
+MatrixType m1(n_dims), m2(n_dims);
+m1.setRandom();
+m2.setRandom();
+float *p = &m2(0); // get the address storing the data for m2
+MapType m2map(p,m2.size()); // m2map shares data with m2
+MapTypeConst m2mapconst(p,m2.size()); // a read-only accessor for m2
+
+cout << "m1: " << m1 << endl;
+cout << "m2: " << m2 << endl;
+cout << "Squared euclidean distance: " << (m1-m2).squaredNorm() << endl;
+cout << "Squared euclidean distance, using map: " <<
+ (m1-m2map).squaredNorm() << endl;
+m2map(3) = 7; // this will change m2, since they share the same array
+cout << "Updated m2: " << m2 << endl;
+cout << "m2 coefficient 2, constant accessor: " << m2mapconst(2) << endl;
+/* m2mapconst(2) = 5; */ // this yields a compile-time error
diff --git a/doc/snippets/Tutorial_commainit_01.cpp b/doc/snippets/Tutorial_commainit_01.cpp
new file mode 100644
index 000000000..47ba31dc9
--- /dev/null
+++ b/doc/snippets/Tutorial_commainit_01.cpp
@@ -0,0 +1,5 @@
+Matrix3f m;
+m << 1, 2, 3,
+ 4, 5, 6,
+ 7, 8, 9;
+std::cout << m;
diff --git a/doc/snippets/Tutorial_commainit_01b.cpp b/doc/snippets/Tutorial_commainit_01b.cpp
new file mode 100644
index 000000000..2adb2e213
--- /dev/null
+++ b/doc/snippets/Tutorial_commainit_01b.cpp
@@ -0,0 +1,5 @@
+Matrix3f m;
+m.row(0) << 1, 2, 3;
+m.block(1,0,2,2) << 4, 5, 7, 8;
+m.col(2).tail(2) << 6, 9;
+std::cout << m;
diff --git a/doc/snippets/Tutorial_commainit_02.cpp b/doc/snippets/Tutorial_commainit_02.cpp
new file mode 100644
index 000000000..c960d6ab5
--- /dev/null
+++ b/doc/snippets/Tutorial_commainit_02.cpp
@@ -0,0 +1,7 @@
+int rows=5, cols=5;
+MatrixXf m(rows,cols);
+m << (Matrix3f() << 1, 2, 3, 4, 5, 6, 7, 8, 9).finished(),
+ MatrixXf::Zero(3,cols-3),
+ MatrixXf::Zero(rows-3,3),
+ MatrixXf::Identity(rows-3,cols-3);
+cout << m;
diff --git a/doc/snippets/Tutorial_solve_matrix_inverse.cpp b/doc/snippets/Tutorial_solve_matrix_inverse.cpp
new file mode 100644
index 000000000..fff324446
--- /dev/null
+++ b/doc/snippets/Tutorial_solve_matrix_inverse.cpp
@@ -0,0 +1,6 @@
+Matrix3f A;
+Vector3f b;
+A << 1,2,3, 4,5,6, 7,8,10;
+b << 3, 3, 4;
+Vector3f x = A.inverse() * b;
+cout << "The solution is:" << endl << x << endl;
diff --git a/doc/snippets/Tutorial_solve_multiple_rhs.cpp b/doc/snippets/Tutorial_solve_multiple_rhs.cpp
new file mode 100644
index 000000000..5411a44ab
--- /dev/null
+++ b/doc/snippets/Tutorial_solve_multiple_rhs.cpp
@@ -0,0 +1,10 @@
+Matrix3f A(3,3);
+A << 1,2,3, 4,5,6, 7,8,10;
+Matrix<float,3,2> B;
+B << 3,1, 3,1, 4,1;
+Matrix<float,3,2> X;
+X = A.fullPivLu().solve(B);
+cout << "The solution with right-hand side (3,3,4) is:" << endl;
+cout << X.col(0) << endl;
+cout << "The solution with right-hand side (1,1,1) is:" << endl;
+cout << X.col(1) << endl;
diff --git a/doc/snippets/Tutorial_solve_reuse_decomposition.cpp b/doc/snippets/Tutorial_solve_reuse_decomposition.cpp
new file mode 100644
index 000000000..3ca06453a
--- /dev/null
+++ b/doc/snippets/Tutorial_solve_reuse_decomposition.cpp
@@ -0,0 +1,13 @@
+Matrix3f A(3,3);
+A << 1,2,3, 4,5,6, 7,8,10;
+PartialPivLU<Matrix3f> luOfA(A); // compute LU decomposition of A
+Vector3f b;
+b << 3,3,4;
+Vector3f x;
+x = luOfA.solve(b);
+cout << "The solution with right-hand side (3,3,4) is:" << endl;
+cout << x << endl;
+b << 1,1,1;
+x = luOfA.solve(b);
+cout << "The solution with right-hand side (1,1,1) is:" << endl;
+cout << x << endl;
diff --git a/doc/snippets/Tutorial_solve_singular.cpp b/doc/snippets/Tutorial_solve_singular.cpp
new file mode 100644
index 000000000..abff1ef73
--- /dev/null
+++ b/doc/snippets/Tutorial_solve_singular.cpp
@@ -0,0 +1,9 @@
+Matrix3f A;
+Vector3f b;
+A << 1,2,3, 4,5,6, 7,8,9;
+b << 3, 3, 4;
+cout << "Here is the matrix A:" << endl << A << endl;
+cout << "Here is the vector b:" << endl << b << endl;
+Vector3f x;
+x = A.lu().solve(b);
+cout << "The solution is:" << endl << x << endl;
diff --git a/doc/snippets/Tutorial_solve_triangular.cpp b/doc/snippets/Tutorial_solve_triangular.cpp
new file mode 100644
index 000000000..9d13f22ec
--- /dev/null
+++ b/doc/snippets/Tutorial_solve_triangular.cpp
@@ -0,0 +1,8 @@
+Matrix3f A;
+Vector3f b;
+A << 1,2,3, 0,5,6, 0,0,10;
+b << 3, 3, 4;
+cout << "Here is the matrix A:" << endl << A << endl;
+cout << "Here is the vector b:" << endl << b << endl;
+Vector3f x = A.triangularView<Upper>().solve(b);
+cout << "The solution is:" << endl << x << endl;
diff --git a/doc/snippets/Tutorial_solve_triangular_inplace.cpp b/doc/snippets/Tutorial_solve_triangular_inplace.cpp
new file mode 100644
index 000000000..16ae633a3
--- /dev/null
+++ b/doc/snippets/Tutorial_solve_triangular_inplace.cpp
@@ -0,0 +1,6 @@
+Matrix3f A;
+Vector3f b;
+A << 1,2,3, 0,5,6, 0,0,10;
+b << 3, 3, 4;
+A.triangularView<Upper>().solveInPlace(b);
+cout << "The solution is:" << endl << b << endl;
diff --git a/doc/snippets/Vectorwise_reverse.cpp b/doc/snippets/Vectorwise_reverse.cpp
new file mode 100644
index 000000000..2f6a35080
--- /dev/null
+++ b/doc/snippets/Vectorwise_reverse.cpp
@@ -0,0 +1,10 @@
+MatrixXi m = MatrixXi::Random(3,4);
+cout << "Here is the matrix m:" << endl << m << endl;
+cout << "Here is the rowwise reverse of m:" << endl << m.rowwise().reverse() << endl;
+cout << "Here is the colwise reverse of m:" << endl << m.colwise().reverse() << endl;
+
+cout << "Here is the coefficient (1,0) in the rowise reverse of m:" << endl
+<< m.rowwise().reverse()(1,0) << endl;
+cout << "Let us overwrite this coefficient with the value 4." << endl;
+//m.colwise().reverse()(1,0) = 4;
+cout << "Now the matrix m is:" << endl << m << endl;
diff --git a/doc/snippets/class_FullPivLU.cpp b/doc/snippets/class_FullPivLU.cpp
new file mode 100644
index 000000000..fce7fac09
--- /dev/null
+++ b/doc/snippets/class_FullPivLU.cpp
@@ -0,0 +1,16 @@
+typedef Matrix<double, 5, 3> Matrix5x3;
+typedef Matrix<double, 5, 5> Matrix5x5;
+Matrix5x3 m = Matrix5x3::Random();
+cout << "Here is the matrix m:" << endl << m << endl;
+Eigen::FullPivLU<Matrix5x3> lu(m);
+cout << "Here is, up to permutations, its LU decomposition matrix:"
+ << endl << lu.matrixLU() << endl;
+cout << "Here is the L part:" << endl;
+Matrix5x5 l = Matrix5x5::Identity();
+l.block<5,3>(0,0).triangularView<StrictlyLower>() = lu.matrixLU();
+cout << l << endl;
+cout << "Here is the U part:" << endl;
+Matrix5x3 u = lu.matrixLU().triangularView<Upper>();
+cout << u << endl;
+cout << "Let us now reconstruct the original matrix m:" << endl;
+cout << lu.permutationP().inverse() * l * u * lu.permutationQ().inverse() << endl;
diff --git a/doc/snippets/compile_snippet.cpp.in b/doc/snippets/compile_snippet.cpp.in
new file mode 100644
index 000000000..894cd526c
--- /dev/null
+++ b/doc/snippets/compile_snippet.cpp.in
@@ -0,0 +1,12 @@
+#include <Eigen/Dense>
+#include <iostream>
+
+using namespace Eigen;
+using namespace std;
+
+int main(int, char**)
+{
+ cout.precision(3);
+ ${snippet_source_code}
+ return 0;
+}
diff --git a/doc/snippets/tut_arithmetic_redux_minmax.cpp b/doc/snippets/tut_arithmetic_redux_minmax.cpp
new file mode 100644
index 000000000..f4ae7f406
--- /dev/null
+++ b/doc/snippets/tut_arithmetic_redux_minmax.cpp
@@ -0,0 +1,12 @@
+ Matrix3f m = Matrix3f::Random();
+ std::ptrdiff_t i, j;
+ float minOfM = m.minCoeff(&i,&j);
+ cout << "Here is the matrix m:\n" << m << endl;
+ cout << "Its minimum coefficient (" << minOfM
+ << ") is at position (" << i << "," << j << ")\n\n";
+
+ RowVector4i v = RowVector4i::Random();
+ int maxOfV = v.maxCoeff(&i);
+ cout << "Here is the vector v: " << v << endl;
+ cout << "Its maximum coefficient (" << maxOfV
+ << ") is at position " << i << endl;
diff --git a/doc/snippets/tut_arithmetic_transpose_aliasing.cpp b/doc/snippets/tut_arithmetic_transpose_aliasing.cpp
new file mode 100644
index 000000000..c8e4746d0
--- /dev/null
+++ b/doc/snippets/tut_arithmetic_transpose_aliasing.cpp
@@ -0,0 +1,5 @@
+Matrix2i a; a << 1, 2, 3, 4;
+cout << "Here is the matrix a:\n" << a << endl;
+
+a = a.transpose(); // !!! do NOT do this !!!
+cout << "and the result of the aliasing effect:\n" << a << endl; \ No newline at end of file
diff --git a/doc/snippets/tut_arithmetic_transpose_conjugate.cpp b/doc/snippets/tut_arithmetic_transpose_conjugate.cpp
new file mode 100644
index 000000000..88496b22d
--- /dev/null
+++ b/doc/snippets/tut_arithmetic_transpose_conjugate.cpp
@@ -0,0 +1,12 @@
+MatrixXcf a = MatrixXcf::Random(2,2);
+cout << "Here is the matrix a\n" << a << endl;
+
+cout << "Here is the matrix a^T\n" << a.transpose() << endl;
+
+
+cout << "Here is the conjugate of a\n" << a.conjugate() << endl;
+
+
+cout << "Here is the matrix a^*\n" << a.adjoint() << endl;
+
+
diff --git a/doc/snippets/tut_arithmetic_transpose_inplace.cpp b/doc/snippets/tut_arithmetic_transpose_inplace.cpp
new file mode 100644
index 000000000..7a069ff23
--- /dev/null
+++ b/doc/snippets/tut_arithmetic_transpose_inplace.cpp
@@ -0,0 +1,6 @@
+MatrixXf a(2,3); a << 1, 2, 3, 4, 5, 6;
+cout << "Here is the initial matrix a:\n" << a << endl;
+
+
+a.transposeInPlace();
+cout << "and after being transposed:\n" << a << endl; \ No newline at end of file
diff --git a/doc/snippets/tut_matrix_assignment_resizing.cpp b/doc/snippets/tut_matrix_assignment_resizing.cpp
new file mode 100644
index 000000000..cf189983f
--- /dev/null
+++ b/doc/snippets/tut_matrix_assignment_resizing.cpp
@@ -0,0 +1,5 @@
+MatrixXf a(2,2);
+std::cout << "a is of size " << a.rows() << "x" << a.cols() << std::endl;
+MatrixXf b(3,3);
+a = b;
+std::cout << "a is now of size " << a.rows() << "x" << a.cols() << std::endl;
diff --git a/doc/special_examples/CMakeLists.txt b/doc/special_examples/CMakeLists.txt
new file mode 100644
index 000000000..eeeae1d2a
--- /dev/null
+++ b/doc/special_examples/CMakeLists.txt
@@ -0,0 +1,20 @@
+
+if(NOT EIGEN_TEST_NOQT)
+ find_package(Qt4)
+ if(QT4_FOUND)
+ include(${QT_USE_FILE})
+ endif()
+endif(NOT EIGEN_TEST_NOQT)
+
+
+if(QT4_FOUND)
+ add_executable(Tutorial_sparse_example Tutorial_sparse_example.cpp Tutorial_sparse_example_details.cpp)
+ target_link_libraries(Tutorial_sparse_example ${EIGEN_STANDARD_LIBRARIES_TO_LINK_TO} ${QT_QTCORE_LIBRARY} ${QT_QTGUI_LIBRARY})
+
+ add_custom_command(
+ TARGET Tutorial_sparse_example
+ POST_BUILD
+ COMMAND Tutorial_sparse_example
+ ARGS ${CMAKE_CURRENT_BINARY_DIR}/../html/Tutorial_sparse_example.jpeg
+ )
+endif(QT4_FOUND)
diff --git a/doc/special_examples/Tutorial_sparse_example.cpp b/doc/special_examples/Tutorial_sparse_example.cpp
new file mode 100644
index 000000000..002f19f01
--- /dev/null
+++ b/doc/special_examples/Tutorial_sparse_example.cpp
@@ -0,0 +1,32 @@
+#include <Eigen/Sparse>
+#include <vector>
+
+typedef Eigen::SparseMatrix<double> SpMat; // declares a column-major sparse matrix type of double
+typedef Eigen::Triplet<double> T;
+
+void buildProblem(std::vector<T>& coefficients, Eigen::VectorXd& b, int n);
+void saveAsBitmap(const Eigen::VectorXd& x, int n, const char* filename);
+
+int main(int argc, char** argv)
+{
+ int n = 300; // size of the image
+ int m = n*n; // number of unknows (=number of pixels)
+
+ // Assembly:
+ std::vector<T> coefficients; // list of non-zeros coefficients
+ Eigen::VectorXd b(m); // the right hand side-vector resulting from the constraints
+ buildProblem(coefficients, b, n);
+
+ SpMat A(m,m);
+ A.setFromTriplets(coefficients.begin(), coefficients.end());
+
+ // Solving:
+ Eigen::SimplicialCholesky<SpMat> chol(A); // performs a Cholesky factorization of A
+ Eigen::VectorXd x = chol.solve(b); // use the factorization to solve for the given right hand side
+
+ // Export the result to a file:
+ saveAsBitmap(x, n, argv[1]);
+
+ return 0;
+}
+
diff --git a/doc/special_examples/Tutorial_sparse_example_details.cpp b/doc/special_examples/Tutorial_sparse_example_details.cpp
new file mode 100644
index 000000000..8c3020b63
--- /dev/null
+++ b/doc/special_examples/Tutorial_sparse_example_details.cpp
@@ -0,0 +1,44 @@
+#include <Eigen/Sparse>
+#include <vector>
+#include <QImage>
+
+typedef Eigen::SparseMatrix<double> SpMat; // declares a column-major sparse matrix type of double
+typedef Eigen::Triplet<double> T;
+
+void insertCoefficient(int id, int i, int j, double w, std::vector<T>& coeffs,
+ Eigen::VectorXd& b, const Eigen::VectorXd& boundary)
+{
+ int n = boundary.size();
+ int id1 = i+j*n;
+
+ if(i==-1 || i==n) b(id) -= w * boundary(j); // constrained coeffcieint
+ else if(j==-1 || j==n) b(id) -= w * boundary(i); // constrained coeffcieint
+ else coeffs.push_back(T(id,id1,w)); // unknown coefficient
+}
+
+void buildProblem(std::vector<T>& coefficients, Eigen::VectorXd& b, int n)
+{
+ b.setZero();
+ Eigen::ArrayXd boundary = Eigen::ArrayXd::LinSpaced(n, 0,M_PI).sin().pow(2);
+ for(int j=0; j<n; ++j)
+ {
+ for(int i=0; i<n; ++i)
+ {
+ int id = i+j*n;
+ insertCoefficient(id, i-1,j, -1, coefficients, b, boundary);
+ insertCoefficient(id, i+1,j, -1, coefficients, b, boundary);
+ insertCoefficient(id, i,j-1, -1, coefficients, b, boundary);
+ insertCoefficient(id, i,j+1, -1, coefficients, b, boundary);
+ insertCoefficient(id, i,j, 4, coefficients, b, boundary);
+ }
+ }
+}
+
+void saveAsBitmap(const Eigen::VectorXd& x, int n, const char* filename)
+{
+ Eigen::Array<unsigned char,Eigen::Dynamic,Eigen::Dynamic> bits = (x*255).cast<unsigned char>();
+ QImage img(bits.data(), n,n,QImage::Format_Indexed8);
+ img.setColorCount(256);
+ for(int i=0;i<256;i++) img.setColor(i,qRgb(i,i,i));
+ img.save(filename);
+}
diff --git a/doc/tutorial.cpp b/doc/tutorial.cpp
new file mode 100644
index 000000000..62be7c270
--- /dev/null
+++ b/doc/tutorial.cpp
@@ -0,0 +1,62 @@
+#include <Eigen/Array>
+
+int main(int argc, char *argv[])
+{
+ std::cout.precision(2);
+
+ // demo static functions
+ Eigen::Matrix3f m3 = Eigen::Matrix3f::Random();
+ Eigen::Matrix4f m4 = Eigen::Matrix4f::Identity();
+
+ std::cout << "*** Step 1 ***\nm3:\n" << m3 << "\nm4:\n" << m4 << std::endl;
+
+ // demo non-static set... functions
+ m4.setZero();
+ m3.diagonal().setOnes();
+
+ std::cout << "*** Step 2 ***\nm3:\n" << m3 << "\nm4:\n" << m4 << std::endl;
+
+ // demo fixed-size block() expression as lvalue and as rvalue
+ m4.block<3,3>(0,1) = m3;
+ m3.row(2) = m4.block<1,3>(2,0);
+
+ std::cout << "*** Step 3 ***\nm3:\n" << m3 << "\nm4:\n" << m4 << std::endl;
+
+ // demo dynamic-size block()
+ {
+ int rows = 3, cols = 3;
+ m4.block(0,1,3,3).setIdentity();
+ std::cout << "*** Step 4 ***\nm4:\n" << m4 << std::endl;
+ }
+
+ // demo vector blocks
+ m4.diagonal().block(1,2).setOnes();
+ std::cout << "*** Step 5 ***\nm4.diagonal():\n" << m4.diagonal() << std::endl;
+ std::cout << "m4.diagonal().start(3)\n" << m4.diagonal().start(3) << std::endl;
+
+ // demo coeff-wise operations
+ m4 = m4.cwise()*m4;
+ m3 = m3.cwise().cos();
+ std::cout << "*** Step 6 ***\nm3:\n" << m3 << "\nm4:\n" << m4 << std::endl;
+
+ // sums of coefficients
+ std::cout << "*** Step 7 ***\n m4.sum(): " << m4.sum() << std::endl;
+ std::cout << "m4.col(2).sum(): " << m4.col(2).sum() << std::endl;
+ std::cout << "m4.colwise().sum():\n" << m4.colwise().sum() << std::endl;
+ std::cout << "m4.rowwise().sum():\n" << m4.rowwise().sum() << std::endl;
+
+ // demo intelligent auto-evaluation
+ m4 = m4 * m4; // auto-evaluates so no aliasing problem (performance penalty is low)
+ Eigen::Matrix4f other = (m4 * m4).lazy(); // forces lazy evaluation
+ m4 = m4 + m4; // here Eigen goes for lazy evaluation, as with most expressions
+ m4 = -m4 + m4 + 5 * m4; // same here, Eigen chooses lazy evaluation for all that.
+ m4 = m4 * (m4 + m4); // here Eigen chooses to first evaluate m4 + m4 into a temporary.
+ // indeed, here it is an optimization to cache this intermediate result.
+ m3 = m3 * m4.block<3,3>(1,1); // here Eigen chooses NOT to evaluate block() into a temporary
+ // because accessing coefficients of that block expression is not more costly than accessing
+ // coefficients of a plain matrix.
+ m4 = m4 * m4.transpose(); // same here, lazy evaluation of the transpose.
+ m4 = m4 * m4.transpose().eval(); // forces immediate evaluation of the transpose
+
+ std::cout << "*** Step 8 ***\nm3:\n" << m3 << "\nm4:\n" << m4 << std::endl;
+}
diff --git a/eigen3.pc.in b/eigen3.pc.in
new file mode 100644
index 000000000..c5855de33
--- /dev/null
+++ b/eigen3.pc.in
@@ -0,0 +1,6 @@
+Name: Eigen3
+Description: A C++ template library for linear algebra: vectors, matrices, and related algorithms
+Requires:
+Version: ${EIGEN_VERSION_NUMBER}
+Libs:
+Cflags: -I${INCLUDE_INSTALL_DIR}
diff --git a/failtest/CMakeLists.txt b/failtest/CMakeLists.txt
new file mode 100644
index 000000000..5afa2ac82
--- /dev/null
+++ b/failtest/CMakeLists.txt
@@ -0,0 +1,37 @@
+message(STATUS "Running the failtests")
+
+ei_add_failtest("failtest_sanity_check")
+
+ei_add_failtest("block_nonconst_ctor_on_const_xpr_0")
+ei_add_failtest("block_nonconst_ctor_on_const_xpr_1")
+ei_add_failtest("block_nonconst_ctor_on_const_xpr_2")
+ei_add_failtest("transpose_nonconst_ctor_on_const_xpr")
+ei_add_failtest("diagonal_nonconst_ctor_on_const_xpr")
+
+ei_add_failtest("const_qualified_block_method_retval_0")
+ei_add_failtest("const_qualified_block_method_retval_1")
+ei_add_failtest("const_qualified_transpose_method_retval")
+ei_add_failtest("const_qualified_diagonal_method_retval")
+
+ei_add_failtest("map_nonconst_ctor_on_const_ptr_0")
+ei_add_failtest("map_nonconst_ctor_on_const_ptr_1")
+ei_add_failtest("map_nonconst_ctor_on_const_ptr_2")
+ei_add_failtest("map_nonconst_ctor_on_const_ptr_3")
+ei_add_failtest("map_nonconst_ctor_on_const_ptr_4")
+
+ei_add_failtest("map_on_const_type_actually_const_0")
+ei_add_failtest("map_on_const_type_actually_const_1")
+ei_add_failtest("block_on_const_type_actually_const_0")
+ei_add_failtest("block_on_const_type_actually_const_1")
+ei_add_failtest("transpose_on_const_type_actually_const")
+ei_add_failtest("diagonal_on_const_type_actually_const")
+
+if (EIGEN_FAILTEST_FAILURE_COUNT)
+ message(FATAL_ERROR
+ "${EIGEN_FAILTEST_FAILURE_COUNT} out of ${EIGEN_FAILTEST_COUNT} failtests FAILED. "
+ "To debug these failures, manually compile these programs in ${CMAKE_CURRENT_SOURCE_DIR}, "
+ "with and without #define EIGEN_SHOULD_FAIL_TO_BUILD.")
+else()
+ message(STATUS "Failtest SUCCESS: all ${EIGEN_FAILTEST_COUNT} failtests passed.")
+ message(STATUS "")
+endif()
diff --git a/failtest/block_nonconst_ctor_on_const_xpr_0.cpp b/failtest/block_nonconst_ctor_on_const_xpr_0.cpp
new file mode 100644
index 000000000..40b82014f
--- /dev/null
+++ b/failtest/block_nonconst_ctor_on_const_xpr_0.cpp
@@ -0,0 +1,15 @@
+#include "../Eigen/Core"
+
+#ifdef EIGEN_SHOULD_FAIL_TO_BUILD
+#define CV_QUALIFIER const
+#else
+#define CV_QUALIFIER
+#endif
+
+using namespace Eigen;
+
+void foo(CV_QUALIFIER Matrix3d &m){
+ Block<Matrix3d,3,3> b(m,0,0);
+}
+
+int main() {}
diff --git a/failtest/block_nonconst_ctor_on_const_xpr_1.cpp b/failtest/block_nonconst_ctor_on_const_xpr_1.cpp
new file mode 100644
index 000000000..ef6d53702
--- /dev/null
+++ b/failtest/block_nonconst_ctor_on_const_xpr_1.cpp
@@ -0,0 +1,15 @@
+#include "../Eigen/Core"
+
+#ifdef EIGEN_SHOULD_FAIL_TO_BUILD
+#define CV_QUALIFIER const
+#else
+#define CV_QUALIFIER
+#endif
+
+using namespace Eigen;
+
+void foo(CV_QUALIFIER Matrix3d &m){
+ Block<Matrix3d> b(m,0,0,3,3);
+}
+
+int main() {}
diff --git a/failtest/block_nonconst_ctor_on_const_xpr_2.cpp b/failtest/block_nonconst_ctor_on_const_xpr_2.cpp
new file mode 100644
index 000000000..43f18aecf
--- /dev/null
+++ b/failtest/block_nonconst_ctor_on_const_xpr_2.cpp
@@ -0,0 +1,16 @@
+#include "../Eigen/Core"
+
+#ifdef EIGEN_SHOULD_FAIL_TO_BUILD
+#define CV_QUALIFIER const
+#else
+#define CV_QUALIFIER
+#endif
+
+using namespace Eigen;
+
+void foo(CV_QUALIFIER Matrix3d &m){
+ // row/column constructor
+ Block<Matrix3d,3,1> b(m,0);
+}
+
+int main() {}
diff --git a/failtest/block_on_const_type_actually_const_0.cpp b/failtest/block_on_const_type_actually_const_0.cpp
new file mode 100644
index 000000000..009bebece
--- /dev/null
+++ b/failtest/block_on_const_type_actually_const_0.cpp
@@ -0,0 +1,16 @@
+#include "../Eigen/Core"
+
+#ifdef EIGEN_SHOULD_FAIL_TO_BUILD
+#define CV_QUALIFIER const
+#else
+#define CV_QUALIFIER
+#endif
+
+using namespace Eigen;
+
+void foo(){
+ Matrix3f m;
+ Block<CV_QUALIFIER Matrix3f>(m, 0, 0, 3, 3).coeffRef(0, 0) = 1.0f;
+}
+
+int main() {}
diff --git a/failtest/block_on_const_type_actually_const_1.cpp b/failtest/block_on_const_type_actually_const_1.cpp
new file mode 100644
index 000000000..4c3e93ffe
--- /dev/null
+++ b/failtest/block_on_const_type_actually_const_1.cpp
@@ -0,0 +1,16 @@
+#include "../Eigen/Core"
+
+#ifdef EIGEN_SHOULD_FAIL_TO_BUILD
+#define CV_QUALIFIER const
+#else
+#define CV_QUALIFIER
+#endif
+
+using namespace Eigen;
+
+void foo(){
+ MatrixXf m;
+ Block<CV_QUALIFIER MatrixXf, 3, 3>(m, 0, 0).coeffRef(0, 0) = 1.0f;
+}
+
+int main() {}
diff --git a/failtest/const_qualified_block_method_retval_0.cpp b/failtest/const_qualified_block_method_retval_0.cpp
new file mode 100644
index 000000000..a6bd5fee2
--- /dev/null
+++ b/failtest/const_qualified_block_method_retval_0.cpp
@@ -0,0 +1,15 @@
+#include "../Eigen/Core"
+
+#ifdef EIGEN_SHOULD_FAIL_TO_BUILD
+#define CV_QUALIFIER const
+#else
+#define CV_QUALIFIER
+#endif
+
+using namespace Eigen;
+
+void foo(CV_QUALIFIER Matrix3d &m){
+ Block<Matrix3d,3,3> b(m.block<3,3>(0,0));
+}
+
+int main() {}
diff --git a/failtest/const_qualified_block_method_retval_1.cpp b/failtest/const_qualified_block_method_retval_1.cpp
new file mode 100644
index 000000000..ef40c247c
--- /dev/null
+++ b/failtest/const_qualified_block_method_retval_1.cpp
@@ -0,0 +1,15 @@
+#include "../Eigen/Core"
+
+#ifdef EIGEN_SHOULD_FAIL_TO_BUILD
+#define CV_QUALIFIER const
+#else
+#define CV_QUALIFIER
+#endif
+
+using namespace Eigen;
+
+void foo(CV_QUALIFIER Matrix3d &m){
+ Block<Matrix3d> b(m.block(0,0,3,3));
+}
+
+int main() {}
diff --git a/failtest/const_qualified_diagonal_method_retval.cpp b/failtest/const_qualified_diagonal_method_retval.cpp
new file mode 100644
index 000000000..809594aab
--- /dev/null
+++ b/failtest/const_qualified_diagonal_method_retval.cpp
@@ -0,0 +1,15 @@
+#include "../Eigen/Core"
+
+#ifdef EIGEN_SHOULD_FAIL_TO_BUILD
+#define CV_QUALIFIER const
+#else
+#define CV_QUALIFIER
+#endif
+
+using namespace Eigen;
+
+void foo(CV_QUALIFIER Matrix3d &m){
+ Diagonal<Matrix3d> b(m.diagonal());
+}
+
+int main() {}
diff --git a/failtest/const_qualified_transpose_method_retval.cpp b/failtest/const_qualified_transpose_method_retval.cpp
new file mode 100644
index 000000000..2d7f19cab
--- /dev/null
+++ b/failtest/const_qualified_transpose_method_retval.cpp
@@ -0,0 +1,15 @@
+#include "../Eigen/Core"
+
+#ifdef EIGEN_SHOULD_FAIL_TO_BUILD
+#define CV_QUALIFIER const
+#else
+#define CV_QUALIFIER
+#endif
+
+using namespace Eigen;
+
+void foo(CV_QUALIFIER Matrix3d &m){
+ Transpose<Matrix3d> b(m.transpose());
+}
+
+int main() {}
diff --git a/failtest/diagonal_nonconst_ctor_on_const_xpr.cpp b/failtest/diagonal_nonconst_ctor_on_const_xpr.cpp
new file mode 100644
index 000000000..76398a2c2
--- /dev/null
+++ b/failtest/diagonal_nonconst_ctor_on_const_xpr.cpp
@@ -0,0 +1,15 @@
+#include "../Eigen/Core"
+
+#ifdef EIGEN_SHOULD_FAIL_TO_BUILD
+#define CV_QUALIFIER const
+#else
+#define CV_QUALIFIER
+#endif
+
+using namespace Eigen;
+
+void foo(CV_QUALIFIER Matrix3d &m){
+ Diagonal<Matrix3d> d(m);
+}
+
+int main() {}
diff --git a/failtest/diagonal_on_const_type_actually_const.cpp b/failtest/diagonal_on_const_type_actually_const.cpp
new file mode 100644
index 000000000..d4b2fd9b8
--- /dev/null
+++ b/failtest/diagonal_on_const_type_actually_const.cpp
@@ -0,0 +1,16 @@
+#include "../Eigen/Core"
+
+#ifdef EIGEN_SHOULD_FAIL_TO_BUILD
+#define CV_QUALIFIER const
+#else
+#define CV_QUALIFIER
+#endif
+
+using namespace Eigen;
+
+void foo(){
+ MatrixXf m;
+ Diagonal<CV_QUALIFIER MatrixXf>(m).coeffRef(0) = 1.0f;
+}
+
+int main() {}
diff --git a/failtest/failtest_sanity_check.cpp b/failtest/failtest_sanity_check.cpp
new file mode 100644
index 000000000..769fa942d
--- /dev/null
+++ b/failtest/failtest_sanity_check.cpp
@@ -0,0 +1,5 @@
+#ifdef EIGEN_SHOULD_FAIL_TO_BUILD
+This is just some text that won't compile as a C++ file, as a basic sanity check for failtest.
+#else
+int main() {}
+#endif
diff --git a/failtest/map_nonconst_ctor_on_const_ptr_0.cpp b/failtest/map_nonconst_ctor_on_const_ptr_0.cpp
new file mode 100644
index 000000000..d75686f58
--- /dev/null
+++ b/failtest/map_nonconst_ctor_on_const_ptr_0.cpp
@@ -0,0 +1,15 @@
+#include "../Eigen/Core"
+
+#ifdef EIGEN_SHOULD_FAIL_TO_BUILD
+#define CV_QUALIFIER const
+#else
+#define CV_QUALIFIER
+#endif
+
+using namespace Eigen;
+
+void foo(CV_QUALIFIER float *ptr){
+ Map<Matrix3f> m(ptr);
+}
+
+int main() {}
diff --git a/failtest/map_nonconst_ctor_on_const_ptr_1.cpp b/failtest/map_nonconst_ctor_on_const_ptr_1.cpp
new file mode 100644
index 000000000..eda134dc8
--- /dev/null
+++ b/failtest/map_nonconst_ctor_on_const_ptr_1.cpp
@@ -0,0 +1,15 @@
+#include "../Eigen/Core"
+
+#ifdef EIGEN_SHOULD_FAIL_TO_BUILD
+#define CV_QUALIFIER const
+#else
+#define CV_QUALIFIER
+#endif
+
+using namespace Eigen;
+
+void foo(CV_QUALIFIER float *ptr, DenseIndex size){
+ Map<ArrayXf> m(ptr, size);
+}
+
+int main() {}
diff --git a/failtest/map_nonconst_ctor_on_const_ptr_2.cpp b/failtest/map_nonconst_ctor_on_const_ptr_2.cpp
new file mode 100644
index 000000000..06b4b6275
--- /dev/null
+++ b/failtest/map_nonconst_ctor_on_const_ptr_2.cpp
@@ -0,0 +1,15 @@
+#include "../Eigen/Core"
+
+#ifdef EIGEN_SHOULD_FAIL_TO_BUILD
+#define CV_QUALIFIER const
+#else
+#define CV_QUALIFIER
+#endif
+
+using namespace Eigen;
+
+void foo(CV_QUALIFIER float *ptr, DenseIndex rows, DenseIndex cols){
+ Map<MatrixXf> m(ptr, rows, cols);
+}
+
+int main() {}
diff --git a/failtest/map_nonconst_ctor_on_const_ptr_3.cpp b/failtest/map_nonconst_ctor_on_const_ptr_3.cpp
new file mode 100644
index 000000000..830f6f0c9
--- /dev/null
+++ b/failtest/map_nonconst_ctor_on_const_ptr_3.cpp
@@ -0,0 +1,15 @@
+#include "../Eigen/Core"
+
+#ifdef EIGEN_SHOULD_FAIL_TO_BUILD
+#define CV_QUALIFIER const
+#else
+#define CV_QUALIFIER
+#endif
+
+using namespace Eigen;
+
+void foo(CV_QUALIFIER float *ptr, DenseIndex rows, DenseIndex cols){
+ Map<MatrixXf, Aligned, InnerStride<2> > m(ptr, rows, cols, InnerStride<2>());
+}
+
+int main() {}
diff --git a/failtest/map_nonconst_ctor_on_const_ptr_4.cpp b/failtest/map_nonconst_ctor_on_const_ptr_4.cpp
new file mode 100644
index 000000000..c3e8c952c
--- /dev/null
+++ b/failtest/map_nonconst_ctor_on_const_ptr_4.cpp
@@ -0,0 +1,15 @@
+#include "../Eigen/Core"
+
+#ifdef EIGEN_SHOULD_FAIL_TO_BUILD
+#define CV_QUALIFIER
+#else
+#define CV_QUALIFIER const
+#endif
+
+using namespace Eigen;
+
+void foo(const float *ptr, DenseIndex rows, DenseIndex cols){
+ Map<CV_QUALIFIER MatrixXf, Unaligned, OuterStride<> > m(ptr, rows, cols, OuterStride<>(2));
+}
+
+int main() {}
diff --git a/failtest/map_on_const_type_actually_const_0.cpp b/failtest/map_on_const_type_actually_const_0.cpp
new file mode 100644
index 000000000..8cb6aa0cd
--- /dev/null
+++ b/failtest/map_on_const_type_actually_const_0.cpp
@@ -0,0 +1,15 @@
+#include "../Eigen/Core"
+
+#ifdef EIGEN_SHOULD_FAIL_TO_BUILD
+#define CV_QUALIFIER const
+#else
+#define CV_QUALIFIER
+#endif
+
+using namespace Eigen;
+
+void foo(float *ptr){
+ Map<CV_QUALIFIER MatrixXf>(ptr, 1, 1).coeffRef(0,0) = 1.0f;
+}
+
+int main() {}
diff --git a/failtest/map_on_const_type_actually_const_1.cpp b/failtest/map_on_const_type_actually_const_1.cpp
new file mode 100644
index 000000000..04e067c34
--- /dev/null
+++ b/failtest/map_on_const_type_actually_const_1.cpp
@@ -0,0 +1,15 @@
+#include "../Eigen/Core"
+
+#ifdef EIGEN_SHOULD_FAIL_TO_BUILD
+#define CV_QUALIFIER const
+#else
+#define CV_QUALIFIER
+#endif
+
+using namespace Eigen;
+
+void foo(float *ptr){
+ Map<CV_QUALIFIER Vector3f>(ptr).coeffRef(0) = 1.0f;
+}
+
+int main() {}
diff --git a/failtest/transpose_nonconst_ctor_on_const_xpr.cpp b/failtest/transpose_nonconst_ctor_on_const_xpr.cpp
new file mode 100644
index 000000000..4223e7fd7
--- /dev/null
+++ b/failtest/transpose_nonconst_ctor_on_const_xpr.cpp
@@ -0,0 +1,15 @@
+#include "../Eigen/Core"
+
+#ifdef EIGEN_SHOULD_FAIL_TO_BUILD
+#define CV_QUALIFIER const
+#else
+#define CV_QUALIFIER
+#endif
+
+using namespace Eigen;
+
+void foo(CV_QUALIFIER Matrix3d &m){
+ Transpose<Matrix3d> t(m);
+}
+
+int main() {}
diff --git a/failtest/transpose_on_const_type_actually_const.cpp b/failtest/transpose_on_const_type_actually_const.cpp
new file mode 100644
index 000000000..d0b7d0df6
--- /dev/null
+++ b/failtest/transpose_on_const_type_actually_const.cpp
@@ -0,0 +1,16 @@
+#include "../Eigen/Core"
+
+#ifdef EIGEN_SHOULD_FAIL_TO_BUILD
+#define CV_QUALIFIER const
+#else
+#define CV_QUALIFIER
+#endif
+
+using namespace Eigen;
+
+void foo(){
+ MatrixXf m;
+ Transpose<CV_QUALIFIER MatrixXf>(m).coeffRef(0, 0) = 1.0f;
+}
+
+int main() {}
diff --git a/lapack/CMakeLists.txt b/lapack/CMakeLists.txt
new file mode 100644
index 000000000..062845a3f
--- /dev/null
+++ b/lapack/CMakeLists.txt
@@ -0,0 +1,374 @@
+
+project(EigenLapack CXX)
+
+include("../cmake/language_support.cmake")
+
+workaround_9220(Fortran EIGEN_Fortran_COMPILER_WORKS)
+
+if(EIGEN_Fortran_COMPILER_WORKS)
+ enable_language(Fortran OPTIONAL)
+endif()
+
+add_custom_target(lapack)
+include_directories(../blas)
+
+set(EigenLapack_SRCS
+single.cpp double.cpp complex_single.cpp complex_double.cpp ../blas/xerbla.cpp
+)
+
+if(EIGEN_Fortran_COMPILER_WORKS)
+
+get_filename_component(eigen_full_path_to_reference_to_reference_lapack "./reference/" ABSOLUTE)
+if(EXISTS ${eigen_full_path_to_reference_to_reference_lapack})
+set(EigenLapack_SRCS ${EigenLapack_SRCS}
+# reference/dpotrf.f reference/zpotrf.f reference/cpotrf.f reference/spotrf.f
+# reference/dpotrs.f reference/spotrs.f reference/zpotrs.f reference/cpotrs.f
+# reference/dgetrf.f reference/cgetrf.f reference/sgetrf.f reference/zgetrf.f
+# reference/cgetrs.f reference/dgetrs.f reference/sgetrs.f reference/zgetrs.f
+# reference/dsyev.f reference/ssyev.f
+
+reference/dlamch.f reference/ilaver.f reference/lsame.f reference/slamch.f reference/second_NONE.f reference/dsecnd_NONE.f
+reference/cbdsqr.f reference/ctbrfs.f reference/dorml2.f reference/sla_porfsx_extended.f reference/zggglm.f
+reference/cgbbrd.f reference/ctbtrs.f reference/dormlq.f reference/sla_porpvgrw.f reference/zgghrd.f
+reference/cgbcon.f reference/ctfsm.f reference/dormql.f reference/slapy2.f reference/zgglse.f
+reference/cgbequb.f reference/ctftri.f reference/dormqr.f reference/slapy3.f reference/zggqrf.f
+reference/cgbequ.f reference/ctfttp.f reference/dormr2.f reference/slaqgb.f reference/zggrqf.f
+reference/cgbrfs.f reference/ctfttr.f reference/dormr3.f reference/slaqge.f reference/zggsvd.f
+reference/cgbrfsx.f reference/ctgevc.f reference/dormrq.f reference/slaqp2.f reference/zggsvp.f
+reference/cgbsv.f reference/ctgex2.f reference/dormrz.f reference/slaqps.f reference/zgtcon.f
+reference/cgbsvx.f reference/ctgexc.f reference/dormtr.f reference/slaqr0.f reference/zgtrfs.f
+reference/cgbsvxx.f reference/ctgsen.f reference/dpbcon.f reference/slaqr1.f reference/zgtsv.f
+reference/cgbtf2.f reference/ctgsja.f reference/dpbequ.f reference/slaqr2.f reference/zgtsvx.f
+reference/cgbtrf.f reference/ctgsna.f reference/dpbrfs.f reference/slaqr3.f reference/zgttrf.f
+reference/cgbtrs.f reference/ctgsy2.f reference/dpbstf.f reference/slaqr4.f reference/zgttrs.f
+reference/cgebak.f reference/ctgsyl.f reference/dpbsv.f reference/slaqr5.f reference/zgtts2.f
+reference/cgebal.f reference/ctpcon.f reference/dpbsvx.f reference/slaqsb.f reference/zhbevd.f
+reference/cgebd2.f reference/ctprfs.f reference/dpbtf2.f reference/slaqsp.f reference/zhbev.f
+reference/cgebrd.f reference/ctptri.f reference/dpbtrf.f reference/slaqsy.f reference/zhbevx.f
+reference/cgecon.f reference/ctptrs.f reference/dpbtrs.f reference/slaqtr.f reference/zhbgst.f
+reference/cgeequb.f reference/ctpttf.f reference/dpftrf.f reference/slar1v.f reference/zhbgvd.f
+reference/cgeequ.f reference/ctpttr.f reference/dpftri.f reference/slar2v.f reference/zhbgv.f
+reference/cgees.f reference/ctrcon.f reference/dpftrs.f reference/slarfb.f reference/zhbgvx.f
+reference/cgeesx.f reference/ctrevc.f reference/dpocon.f reference/slarf.f reference/zhbtrd.f
+reference/cgeev.f reference/ctrexc.f reference/dpoequb.f reference/slarfg.f reference/zhecon.f
+reference/cgeevx.f reference/ctrrfs.f reference/dpoequ.f reference/slarfp.f reference/zheequb.f
+reference/cgegs.f reference/ctrsen.f reference/dporfs.f reference/slarft.f reference/zheevd.f
+reference/cgegv.f reference/ctrsna.f reference/dporfsx.f reference/slarfx.f reference/zheev.f
+reference/cgehd2.f reference/ctrsyl.f reference/dposv.f reference/slargv.f reference/zheevr.f
+reference/cgehrd.f reference/ctrti2.f reference/dposvx.f reference/slarnv.f reference/zheevx.f
+reference/cgelq2.f reference/ctrtri.f reference/dposvxx.f reference/sla_rpvgrw.f reference/zhegs2.f
+reference/cgelqf.f reference/ctrtrs.f reference/dpotf2.f reference/slarra.f reference/zhegst.f
+reference/cgelsd.f reference/ctrttf.f
+reference/slarrb.f reference/zhegvd.f
+reference/cgels.f reference/ctrttp.f reference/dpotri.f reference/slarrc.f reference/zhegv.f
+reference/cgelss.f reference/ctzrqf.f reference/slarrd.f reference/zhegvx.f
+reference/cgelsx.f reference/ctzrzf.f reference/dppcon.f reference/slarre.f reference/zherfs.f
+reference/cgelsy.f reference/cung2l.f reference/dppequ.f reference/slarrf.f reference/zherfsx.f
+reference/cgeql2.f reference/cung2r.f reference/dpprfs.f reference/slarrj.f reference/zhesv.f
+reference/cgeqlf.f reference/cungbr.f reference/dppsv.f reference/slarrk.f reference/zhesvx.f
+reference/cgeqp3.f reference/cunghr.f reference/dppsvx.f reference/slarrr.f reference/zhesvxx.f
+reference/cgeqpf.f reference/cungl2.f reference/dpptrf.f reference/slarrv.f reference/zhetd2.f
+reference/cgeqr2.f reference/cunglq.f reference/dpptri.f reference/slarscl2.f reference/zhetf2.f
+reference/cgeqrf.f reference/cungql.f reference/dpptrs.f reference/slartg.f reference/zhetrd.f
+reference/cgerfs.f reference/cungqr.f reference/dpstf2.f reference/slartv.f reference/zhetrf.f
+reference/cgerfsx.f reference/cungr2.f reference/dpstrf.f reference/slaruv.f reference/zhetri.f
+reference/cgerq2.f reference/cungrq.f reference/dptcon.f reference/slarzb.f reference/zhetrs.f
+reference/cgerqf.f reference/cungtr.f reference/dpteqr.f reference/slarz.f reference/zhfrk.f
+reference/cgesc2.f reference/cunm2l.f reference/dptrfs.f reference/slarzt.f reference/zhgeqz.f
+reference/cgesdd.f reference/cunm2r.f reference/dptsv.f reference/slas2.f reference/zhpcon.f
+reference/cgesvd.f reference/cunmbr.f reference/dptsvx.f reference/slascl2.f reference/zhpevd.f
+reference/cgesv.f reference/cunmhr.f reference/dpttrf.f reference/slascl.f reference/zhpev.f
+reference/cgesvx.f reference/cunml2.f reference/dpttrs.f reference/slasd0.f reference/zhpevx.f
+reference/cgesvxx.f reference/cunmlq.f reference/dptts2.f reference/slasd1.f reference/zhpgst.f
+reference/cgetc2.f reference/cunmql.f reference/drscl.f reference/slasd2.f reference/zhpgvd.f
+reference/cgetf2.f reference/cunmqr.f reference/dsbevd.f reference/slasd3.f reference/zhpgv.f
+reference/cunmr2.f reference/dsbev.f reference/slasd4.f reference/zhpgvx.f
+reference/cgetri.f reference/cunmr3.f reference/dsbevx.f reference/slasd5.f reference/zhprfs.f
+ reference/cunmrq.f reference/dsbgst.f reference/slasd6.f reference/zhpsv.f
+reference/cggbak.f reference/cunmrz.f reference/dsbgvd.f reference/slasd7.f reference/zhpsvx.f
+reference/cggbal.f reference/cunmtr.f reference/dsbgv.f reference/slasd8.f reference/zhptrd.f
+reference/cgges.f reference/cupgtr.f reference/dsbgvx.f reference/slasda.f reference/zhptrf.f
+reference/cggesx.f reference/cupmtr.f reference/dsbtrd.f reference/slasdq.f reference/zhptri.f
+reference/cggev.f reference/dbdsdc.f reference/dsfrk.f reference/slasdt.f reference/zhptrs.f
+reference/cggevx.f reference/dbdsqr.f reference/dsgesv.f reference/slaset.f reference/zhsein.f
+reference/cggglm.f reference/ddisna.f reference/dspcon.f reference/slasq1.f reference/zhseqr.f
+reference/cgghrd.f reference/dgbbrd.f reference/dspevd.f reference/slasq2.f reference/zlabrd.f
+reference/cgglse.f reference/dgbcon.f reference/dspev.f reference/slasq3.f reference/zlacgv.f
+reference/cggqrf.f reference/dgbequb.f reference/dspevx.f reference/slasq4.f reference/zlacn2.f
+reference/cggrqf.f reference/dgbequ.f reference/dspgst.f reference/slasq5.f reference/zlacon.f
+reference/cggsvd.f reference/dgbrfs.f reference/dspgvd.f reference/slasq6.f reference/zlacp2.f
+reference/cggsvp.f reference/dgbrfsx.f reference/dspgv.f reference/slasr.f reference/zlacpy.f
+reference/cgtcon.f reference/dgbsv.f reference/dspgvx.f reference/slasrt.f reference/zlacrm.f
+reference/cgtrfs.f reference/dgbsvx.f reference/dsposv.f reference/slassq.f reference/zlacrt.f
+reference/cgtsv.f reference/dgbsvxx.f reference/dsprfs.f reference/slasv2.f reference/zladiv.f
+reference/cgtsvx.f reference/dgbtf2.f reference/dspsv.f reference/slaswp.f reference/zlaed0.f
+reference/cgttrf.f reference/dgbtrf.f reference/dspsvx.f reference/slasy2.f reference/zlaed7.f
+reference/cgttrs.f reference/dgbtrs.f reference/dsptrd.f reference/sla_syamv.f reference/zlaed8.f
+reference/cgtts2.f reference/dgebak.f reference/dsptrf.f reference/slasyf.f reference/zlaein.f
+reference/chbevd.f reference/dgebal.f reference/dsptri.f reference/sla_syrcond.f reference/zlaesy.f
+reference/chbev.f reference/dgebd2.f reference/dsptrs.f reference/sla_syrfsx_extended.f reference/zlaev2.f
+reference/chbevx.f reference/dgebrd.f reference/dstebz.f reference/sla_syrpvgrw.f reference/zlag2c.f
+reference/chbgst.f reference/dgecon.f reference/dstedc.f reference/slatbs.f reference/zla_gbamv.f
+reference/chbgvd.f reference/dgeequb.f reference/dstegr.f reference/slatdf.f reference/zla_gbrcond_c.f
+reference/chbgv.f reference/dgeequ.f reference/dstein.f reference/slatps.f reference/zla_gbrcond_x.f
+reference/chbgvx.f reference/dgees.f reference/dstemr.f reference/slatrd.f reference/zla_gbrfsx_extended.f
+reference/chbtrd.f reference/dgeesx.f reference/dsteqr.f reference/slatrs.f reference/zla_gbrpvgrw.f
+reference/checon.f reference/dgeev.f reference/dsterf.f reference/slatrz.f reference/zla_geamv.f
+reference/cheequb.f reference/dgeevx.f reference/dstevd.f reference/slatzm.f reference/zla_gercond_c.f
+reference/cheevd.f reference/dgegs.f reference/dstev.f reference/slauu2.f reference/zla_gercond_x.f
+reference/cheev.f reference/dgegv.f reference/dstevr.f reference/slauum.f reference/zla_gerfsx_extended.f
+reference/cheevr.f reference/dgehd2.f reference/dstevx.f reference/sla_wwaddw.f reference/zlags2.f
+reference/cheevx.f reference/dgehrd.f reference/dsycon.f reference/sopgtr.f reference/zlagtm.f
+reference/chegs2.f reference/dgejsv.f reference/dsyequb.f reference/sopmtr.f reference/zla_heamv.f
+reference/chegst.f reference/dgelq2.f reference/dsyevd.f reference/sorg2l.f reference/zlahef.f
+reference/chegvd.f reference/dgelqf.f reference/sorg2r.f reference/zla_hercond_c.f
+reference/chegv.f reference/dgelsd.f reference/dsyevr.f reference/sorgbr.f reference/zla_hercond_x.f
+reference/chegvx.f reference/dgels.f reference/dsyevx.f reference/sorghr.f reference/zla_herfsx_extended.f
+reference/cherfs.f reference/dgelss.f reference/dsygs2.f reference/sorgl2.f reference/zla_herpvgrw.f
+reference/cherfsx.f reference/dgelsx.f reference/dsygst.f reference/sorglq.f reference/zlahqr.f
+reference/chesv.f reference/dgelsy.f reference/dsygvd.f reference/sorgql.f reference/zlahr2.f
+reference/chesvx.f reference/dgeql2.f reference/dsygv.f reference/sorgqr.f reference/zlahrd.f
+reference/chesvxx.f reference/dgeqlf.f reference/dsygvx.f reference/sorgr2.f reference/zlaic1.f
+reference/chetd2.f reference/dgeqp3.f reference/dsyrfs.f reference/sorgrq.f reference/zla_lin_berr.f
+reference/chetf2.f reference/dgeqpf.f reference/dsyrfsx.f reference/sorgtr.f reference/zlals0.f
+reference/chetrd.f reference/dgeqr2.f reference/dsysv.f reference/sorm2l.f reference/zlalsa.f
+reference/chetrf.f reference/dgeqrf.f reference/dsysvx.f reference/sorm2r.f reference/zlalsd.f
+reference/chetri.f reference/dgerfs.f reference/dsysvxx.f reference/sormbr.f reference/zlangb.f
+reference/chetrs.f reference/dgerfsx.f reference/dsytd2.f reference/sormhr.f reference/zlange.f
+reference/chfrk.f reference/dgerq2.f reference/dsytf2.f reference/sorml2.f reference/zlangt.f
+reference/chgeqz.f reference/dgerqf.f reference/dsytrd.f reference/sormlq.f reference/zlanhb.f
+reference/chla_transtype.f reference/dgesc2.f reference/dsytrf.f reference/sormql.f reference/zlanhe.f
+reference/chpcon.f reference/dgesdd.f reference/dsytri.f reference/sormqr.f reference/zlanhf.f
+reference/chpevd.f reference/dgesvd.f reference/dsytrs.f reference/sormr2.f reference/zlanhp.f
+reference/chpev.f reference/dgesv.f reference/dtbcon.f reference/sormr3.f reference/zlanhs.f
+reference/chpevx.f reference/dgesvj.f reference/dtbrfs.f reference/sormrq.f reference/zlanht.f
+reference/chpgst.f reference/dgesvx.f reference/dtbtrs.f reference/sormrz.f reference/zlansb.f
+reference/chpgvd.f reference/dgesvxx.f reference/dtfsm.f reference/sormtr.f reference/zlansp.f
+reference/chpgv.f reference/dgetc2.f reference/dtftri.f reference/spbcon.f reference/zlansy.f
+reference/chpgvx.f reference/dgetf2.f reference/dtfttp.f reference/spbequ.f reference/zlantb.f
+reference/chprfs.f
+reference/dtfttr.f reference/spbrfs.f reference/zlantp.f
+reference/chpsv.f reference/dgetri.f reference/dtgevc.f reference/spbstf.f reference/zlantr.f
+reference/chpsvx.f reference/dtgex2.f reference/spbsv.f reference/zlapll.f
+reference/chptrd.f reference/dggbak.f reference/dtgexc.f reference/spbsvx.f reference/zlapmt.f
+reference/chptrf.f reference/dggbal.f reference/dtgsen.f reference/spbtf2.f reference/zla_porcond_c.f
+reference/chptri.f reference/dgges.f reference/dtgsja.f reference/spbtrf.f reference/zla_porcond_x.f
+reference/chptrs.f reference/dggesx.f reference/dtgsna.f reference/spbtrs.f reference/zla_porfsx_extended.f
+reference/chsein.f reference/dggev.f reference/dtgsy2.f reference/spftrf.f reference/zla_porpvgrw.f
+reference/chseqr.f reference/dggevx.f reference/dtgsyl.f reference/spftri.f reference/zlaqgb.f
+reference/clabrd.f reference/dggglm.f reference/dtpcon.f reference/spftrs.f reference/zlaqge.f
+reference/clacgv.f reference/dgghrd.f reference/dtprfs.f reference/spocon.f reference/zlaqhb.f
+reference/clacn2.f reference/dgglse.f reference/dtptri.f reference/spoequb.f reference/zlaqhe.f
+reference/clacon.f reference/dggqrf.f reference/dtptrs.f reference/spoequ.f reference/zlaqhp.f
+reference/clacp2.f reference/dggrqf.f reference/dtpttf.f reference/sporfs.f reference/zlaqp2.f
+reference/clacpy.f reference/dggsvd.f reference/dtpttr.f reference/sporfsx.f reference/zlaqps.f
+reference/clacrm.f reference/dggsvp.f reference/dtrcon.f reference/sposv.f reference/zlaqr0.f
+reference/clacrt.f reference/dgsvj0.f reference/dtrevc.f reference/sposvx.f reference/zlaqr1.f
+reference/cladiv.f reference/dgsvj1.f reference/dtrexc.f reference/sposvxx.f reference/zlaqr2.f
+reference/claed0.f reference/dgtcon.f reference/dtrrfs.f reference/spotf2.f reference/zlaqr3.f
+reference/claed7.f reference/dgtrfs.f reference/dtrsen.f
+reference/zlaqr4.f
+reference/claed8.f reference/dgtsv.f reference/dtrsna.f reference/spotri.f reference/zlaqr5.f
+reference/claein.f reference/dgtsvx.f reference/dtrsyl.f reference/zlaqsb.f
+reference/claesy.f reference/dgttrf.f reference/dtrti2.f reference/sppcon.f reference/zlaqsp.f
+reference/claev2.f reference/dgttrs.f reference/dtrtri.f reference/sppequ.f reference/zlaqsy.f
+reference/clag2z.f reference/dgtts2.f reference/dtrtrs.f reference/spprfs.f reference/zlar1v.f
+reference/cla_gbamv.f reference/dhgeqz.f reference/dtrttf.f reference/sppsv.f reference/zlar2v.f
+reference/cla_gbrcond_c.f reference/dhsein.f reference/dtrttp.f reference/sppsvx.f reference/zlarcm.f
+reference/cla_gbrcond_x.f reference/dhseqr.f reference/dtzrqf.f reference/spptrf.f reference/zlarfb.f
+reference/cla_gbrfsx_extended.f reference/disnan.f reference/dtzrzf.f reference/spptri.f reference/zlarf.f
+reference/cla_gbrpvgrw.f reference/dlabad.f reference/dzsum1.f reference/spptrs.f reference/zlarfg.f
+reference/cla_geamv.f reference/dlabrd.f reference/icmax1.f reference/spstf2.f reference/zlarfp.f
+reference/cla_gercond_c.f reference/dlacn2.f reference/ieeeck.f reference/spstrf.f reference/zlarft.f
+reference/cla_gercond_x.f reference/dlacon.f reference/ilaclc.f reference/sptcon.f reference/zlarfx.f
+reference/cla_gerfsx_extended.f reference/dlacpy.f reference/ilaclr.f reference/spteqr.f reference/zlargv.f
+reference/clags2.f reference/dladiv.f reference/iladiag.f reference/sptrfs.f reference/zlarnv.f
+reference/clagtm.f reference/dlae2.f reference/iladlc.f reference/sptsv.f reference/zla_rpvgrw.f
+reference/cla_heamv.f reference/dlaebz.f reference/iladlr.f reference/sptsvx.f reference/zlarrv.f
+reference/clahef.f reference/dlaed0.f reference/ilaenv.f reference/spttrf.f reference/zlarscl2.f
+reference/cla_hercond_c.f reference/dlaed1.f reference/ilaprec.f reference/spttrs.f reference/zlartg.f
+reference/cla_hercond_x.f reference/dlaed2.f reference/ilaslc.f reference/sptts2.f reference/zlartv.f
+reference/cla_herfsx_extended.f reference/dlaed3.f reference/ilaslr.f reference/srscl.f reference/zlarzb.f
+reference/cla_herpvgrw.f reference/dlaed4.f reference/ilatrans.f reference/ssbevd.f reference/zlarz.f
+reference/clahqr.f reference/dlaed5.f reference/ilauplo.f reference/ssbev.f reference/zlarzt.f
+reference/clahr2.f reference/dlaed6.f reference/ilaver.f reference/ssbevx.f reference/zlascl2.f
+reference/clahrd.f reference/dlaed7.f reference/ilazlc.f reference/ssbgst.f reference/zlascl.f
+reference/claic1.f reference/dlaed8.f reference/ilazlr.f reference/ssbgvd.f reference/zlaset.f
+reference/cla_lin_berr.f reference/dlaed9.f reference/iparmq.f reference/ssbgv.f reference/zlasr.f
+reference/clals0.f reference/dlaeda.f reference/izmax1.f reference/ssbgvx.f reference/zlassq.f
+reference/clalsa.f reference/dlaein.f reference/lsamen.f reference/ssbtrd.f reference/zlaswp.f
+reference/clalsd.f reference/dlaev2.f reference/sbdsdc.f reference/ssfrk.f reference/zla_syamv.f
+reference/clangb.f reference/dlaexc.f reference/sbdsqr.f reference/sspcon.f reference/zlasyf.f
+reference/clange.f reference/dlag2.f reference/scsum1.f reference/sspevd.f reference/zla_syrcond_c.f
+reference/clangt.f reference/dlag2s.f reference/sdisna.f reference/sspev.f reference/zla_syrcond_x.f
+reference/clanhb.f reference/dla_gbamv.f reference/sgbbrd.f reference/sspevx.f reference/zla_syrfsx_extended.f
+reference/clanhe.f reference/dla_gbrcond.f reference/sgbcon.f reference/sspgst.f reference/zla_syrpvgrw.f
+reference/clanhf.f reference/dla_gbrfsx_extended.f reference/sgbequb.f reference/sspgvd.f reference/zlat2c.f
+reference/clanhp.f reference/dla_gbrpvgrw.f reference/sgbequ.f reference/sspgv.f reference/zlatbs.f
+reference/clanhs.f reference/dla_geamv.f reference/sgbrfs.f reference/sspgvx.f reference/zlatdf.f
+reference/clanht.f reference/dla_gercond.f reference/sgbrfsx.f reference/ssprfs.f reference/zlatps.f
+reference/clansb.f reference/dla_gerfsx_extended.f reference/sgbsv.f reference/sspsv.f reference/zlatrd.f
+reference/clansp.f reference/dlags2.f reference/sgbsvx.f reference/sspsvx.f reference/zlatrs.f
+reference/clansy.f reference/dlagtf.f reference/sgbsvxx.f reference/ssptrd.f reference/zlatrz.f
+reference/clantb.f reference/dlagtm.f reference/sgbtf2.f reference/ssptrf.f reference/zlatzm.f
+reference/clantp.f reference/dlagts.f reference/sgbtrf.f reference/ssptri.f reference/zlauu2.f
+reference/clantr.f reference/dlagv2.f reference/sgbtrs.f reference/ssptrs.f reference/zlauum.f
+reference/clapll.f reference/dlahqr.f reference/sgebak.f reference/sstebz.f reference/zla_wwaddw.f
+reference/clapmt.f reference/dlahr2.f reference/sgebal.f reference/sstedc.f reference/zpbcon.f
+reference/cla_porcond_c.f reference/dlahrd.f reference/sgebd2.f reference/sstegr.f reference/zpbequ.f
+reference/cla_porcond_x.f reference/dlaic1.f reference/sgebrd.f reference/sstein.f reference/zpbrfs.f
+reference/cla_porfsx_extended.f reference/dlaisnan.f reference/sgecon.f reference/sstemr.f reference/zpbstf.f
+reference/cla_porpvgrw.f reference/dla_lin_berr.f reference/sgeequb.f reference/ssteqr.f reference/zpbsv.f
+reference/claqgb.f reference/dlaln2.f reference/sgeequ.f reference/ssterf.f reference/zpbsvx.f
+reference/claqge.f reference/dlals0.f reference/sgees.f reference/sstevd.f reference/zpbtf2.f
+reference/claqhb.f reference/dlalsa.f reference/sgeesx.f reference/sstev.f reference/zpbtrf.f
+reference/claqhe.f reference/dlalsd.f reference/sgeev.f reference/sstevr.f reference/zpbtrs.f
+reference/claqhp.f reference/dlamrg.f reference/sgeevx.f reference/sstevx.f reference/zpftrf.f
+reference/claqp2.f reference/dlaneg.f reference/sgegs.f reference/ssycon.f reference/zpftri.f
+reference/claqps.f reference/dlangb.f reference/sgegv.f reference/ssyequb.f reference/zpftrs.f
+reference/claqr0.f reference/dlange.f reference/sgehd2.f reference/ssyevd.f reference/zpocon.f
+reference/claqr1.f reference/dlangt.f reference/sgehrd.f reference/zpoequb.f
+reference/claqr2.f reference/dlanhs.f reference/sgejsv.f reference/ssyevr.f reference/zpoequ.f
+reference/claqr3.f reference/dlansb.f reference/sgelq2.f reference/ssyevx.f reference/zporfs.f
+reference/claqr4.f reference/dlansf.f reference/sgelqf.f reference/ssygs2.f reference/zporfsx.f
+reference/claqr5.f reference/dlansp.f reference/sgelsd.f reference/ssygst.f reference/zposv.f
+reference/claqsb.f reference/dlanst.f reference/sgels.f reference/ssygvd.f reference/zposvx.f
+reference/claqsp.f reference/dlansy.f reference/sgelss.f reference/ssygv.f reference/zposvxx.f
+reference/claqsy.f reference/dlantb.f reference/sgelsx.f reference/ssygvx.f reference/zpotf2.f
+reference/clar1v.f reference/dlantp.f reference/sgelsy.f reference/ssyrfs.f
+reference/clar2v.f reference/dlantr.f reference/sgeql2.f reference/ssyrfsx.f reference/zpotri.f
+reference/clarcm.f reference/dlanv2.f reference/sgeqlf.f reference/ssysv.f
+reference/clarfb.f reference/dlapll.f reference/sgeqp3.f reference/ssysvx.f reference/zppcon.f
+reference/clarf.f reference/dlapmt.f reference/sgeqpf.f reference/ssysvxx.f reference/zppequ.f
+reference/clarfg.f reference/dla_porcond.f reference/sgeqr2.f reference/ssytd2.f reference/zpprfs.f
+reference/clarfp.f reference/dla_porfsx_extended.f reference/sgeqrf.f reference/ssytf2.f reference/zppsv.f
+reference/clarft.f reference/dla_porpvgrw.f reference/sgerfs.f reference/ssytrd.f reference/zppsvx.f
+reference/clarfx.f reference/dlapy2.f reference/sgerfsx.f reference/ssytrf.f reference/zpptrf.f
+reference/clargv.f reference/dlapy3.f reference/sgerq2.f reference/ssytri.f reference/zpptri.f
+reference/clarnv.f reference/dlaqgb.f reference/sgerqf.f reference/ssytrs.f reference/zpptrs.f
+reference/cla_rpvgrw.f reference/dlaqge.f reference/sgesc2.f reference/stbcon.f reference/zpstf2.f
+reference/clarrv.f reference/dlaqp2.f reference/sgesdd.f reference/stbrfs.f reference/zpstrf.f
+reference/clarscl2.f reference/dlaqps.f reference/sgesvd.f reference/stbtrs.f reference/zptcon.f
+reference/clartg.f reference/dlaqr0.f reference/sgesv.f reference/stfsm.f reference/zpteqr.f
+reference/clartv.f reference/dlaqr1.f reference/sgesvj.f reference/stftri.f reference/zptrfs.f
+reference/clarzb.f reference/dlaqr2.f reference/sgesvx.f reference/stfttp.f reference/zptsv.f
+reference/clarz.f reference/dlaqr3.f reference/sgesvxx.f reference/stfttr.f reference/zptsvx.f
+reference/clarzt.f reference/dlaqr4.f reference/sgetc2.f reference/stgevc.f reference/zpttrf.f
+reference/clascl2.f reference/dlaqr5.f reference/sgetf2.f reference/stgex2.f reference/zpttrs.f
+reference/clascl.f reference/dlaqsb.f
+reference/stgexc.f reference/zptts2.f
+reference/claset.f reference/dlaqsp.f reference/sgetri.f reference/stgsen.f reference/zrot.f
+reference/clasr.f reference/dlaqsy.f reference/stgsja.f reference/zspcon.f
+reference/classq.f reference/dlaqtr.f reference/sggbak.f reference/stgsna.f reference/zspmv.f
+reference/claswp.f reference/dlar1v.f reference/sggbal.f reference/stgsy2.f reference/zspr.f
+reference/cla_syamv.f reference/dlar2v.f reference/sgges.f reference/stgsyl.f reference/zsprfs.f
+reference/clasyf.f reference/dlarfb.f reference/sggesx.f reference/stpcon.f reference/zspsv.f
+reference/cla_syrcond_c.f reference/dlarf.f reference/sggev.f reference/stprfs.f reference/zspsvx.f
+reference/cla_syrcond_x.f reference/dlarfg.f reference/sggevx.f reference/stptri.f reference/zsptrf.f
+reference/cla_syrfsx_extended.f reference/dlarfp.f reference/sggglm.f reference/stptrs.f reference/zsptri.f
+reference/cla_syrpvgrw.f reference/dlarft.f reference/sgghrd.f reference/stpttf.f reference/zsptrs.f
+reference/clatbs.f reference/dlarfx.f reference/sgglse.f reference/stpttr.f reference/zstedc.f
+reference/clatdf.f reference/dlargv.f reference/sggqrf.f reference/strcon.f reference/zstegr.f
+reference/clatps.f reference/dlarnv.f reference/sggrqf.f reference/strevc.f reference/zstein.f
+reference/clatrd.f reference/dla_rpvgrw.f reference/sggsvd.f reference/strexc.f reference/zstemr.f
+reference/clatrs.f reference/dlarra.f reference/sggsvp.f reference/strrfs.f reference/zsteqr.f
+reference/clatrz.f reference/dlarrb.f reference/sgsvj0.f reference/strsen.f reference/zsycon.f
+reference/clatzm.f reference/dlarrc.f reference/sgsvj1.f reference/strsna.f reference/zsyequb.f
+reference/clauu2.f reference/dlarrd.f reference/sgtcon.f reference/strsyl.f reference/zsymv.f
+reference/clauum.f reference/dlarre.f reference/sgtrfs.f reference/strti2.f reference/zsyr.f
+reference/cla_wwaddw.f reference/dlarrf.f reference/sgtsv.f reference/strtri.f reference/zsyrfs.f
+reference/cpbcon.f reference/dlarrj.f reference/sgtsvx.f reference/strtrs.f reference/zsyrfsx.f
+reference/cpbequ.f reference/dlarrk.f reference/sgttrf.f reference/strttf.f reference/zsysv.f
+reference/cpbrfs.f reference/dlarrr.f reference/sgttrs.f reference/strttp.f reference/zsysvx.f
+reference/cpbstf.f reference/dlarrv.f reference/sgtts2.f reference/stzrqf.f reference/zsysvxx.f
+reference/cpbsv.f reference/dlarscl2.f reference/shgeqz.f reference/stzrzf.f reference/zsytf2.f
+reference/cpbsvx.f reference/dlartg.f reference/shsein.f reference/xerbla_array.f reference/zsytrf.f
+reference/cpbtf2.f reference/dlartv.f reference/shseqr.f reference/xerbla.f reference/zsytri.f
+reference/cpbtrf.f reference/dlaruv.f reference/sisnan.f reference/zbdsqr.f reference/zsytrs.f
+reference/cpbtrs.f reference/dlarzb.f reference/slabad.f reference/zcgesv.f reference/ztbcon.f
+reference/cpftrf.f reference/dlarz.f reference/slabrd.f reference/zcposv.f reference/ztbrfs.f
+reference/cpftri.f reference/dlarzt.f reference/slacn2.f reference/zdrscl.f reference/ztbtrs.f
+reference/cpftrs.f reference/dlas2.f reference/slacon.f reference/zgbbrd.f reference/ztfsm.f
+reference/cpocon.f reference/dlascl2.f reference/slacpy.f reference/zgbcon.f reference/ztftri.f
+reference/cpoequb.f reference/dlascl.f reference/sladiv.f reference/zgbequb.f reference/ztfttp.f
+reference/cpoequ.f reference/dlasd0.f reference/slae2.f reference/zgbequ.f reference/ztfttr.f
+reference/cporfs.f reference/dlasd1.f reference/slaebz.f reference/zgbrfs.f reference/ztgevc.f
+reference/cporfsx.f reference/dlasd2.f reference/slaed0.f reference/zgbrfsx.f reference/ztgex2.f
+reference/cposv.f reference/dlasd3.f reference/slaed1.f reference/zgbsv.f reference/ztgexc.f
+reference/cposvx.f reference/dlasd4.f reference/slaed2.f reference/zgbsvx.f reference/ztgsen.f
+reference/cposvxx.f reference/dlasd5.f reference/slaed3.f reference/zgbsvxx.f reference/ztgsja.f
+reference/cpotf2.f reference/dlasd6.f reference/slaed4.f reference/zgbtf2.f reference/ztgsna.f
+reference/dlasd7.f reference/slaed5.f reference/zgbtrf.f reference/ztgsy2.f
+reference/cpotri.f reference/dlasd8.f reference/slaed6.f reference/zgbtrs.f reference/ztgsyl.f
+ reference/dlasda.f reference/slaed7.f reference/zgebak.f reference/ztpcon.f
+reference/cppcon.f reference/dlasdq.f reference/slaed8.f reference/zgebal.f reference/ztprfs.f
+reference/cppequ.f reference/dlasdt.f reference/slaed9.f reference/zgebd2.f reference/ztptri.f
+reference/cpprfs.f reference/dlaset.f reference/slaeda.f reference/zgebrd.f reference/ztptrs.f
+reference/cppsv.f reference/dlasq1.f reference/slaein.f reference/zgecon.f reference/ztpttf.f
+reference/cppsvx.f reference/dlasq2.f reference/slaev2.f reference/zgeequb.f reference/ztpttr.f
+reference/cpptrf.f reference/dlasq3.f reference/slaexc.f reference/zgeequ.f reference/ztrcon.f
+reference/cpptri.f reference/dlasq4.f reference/slag2d.f reference/zgees.f reference/ztrevc.f
+reference/cpptrs.f reference/dlasq5.f reference/slag2.f reference/zgeesx.f reference/ztrexc.f
+reference/cpstf2.f reference/dlasq6.f reference/sla_gbamv.f reference/zgeev.f reference/ztrrfs.f
+reference/cpstrf.f reference/dlasr.f reference/sla_gbrcond.f reference/zgeevx.f reference/ztrsen.f
+reference/cptcon.f reference/dlasrt.f reference/sla_gbrfsx_extended.f reference/zgegs.f reference/ztrsna.f
+reference/cpteqr.f reference/dlassq.f reference/sla_gbrpvgrw.f reference/zgegv.f reference/ztrsyl.f
+reference/cptrfs.f reference/dlasv2.f reference/sla_geamv.f reference/zgehd2.f reference/ztrti2.f
+reference/cptsv.f reference/dlaswp.f reference/sla_gercond.f reference/zgehrd.f reference/ztrtri.f
+reference/cptsvx.f reference/dlasy2.f reference/sla_gerfsx_extended.f reference/zgelq2.f reference/ztrtrs.f
+reference/cpttrf.f reference/dla_syamv.f reference/slags2.f reference/zgelqf.f reference/ztrttf.f
+reference/cpttrs.f reference/dlasyf.f reference/slagtf.f reference/zgelsd.f reference/ztrttp.f
+reference/cptts2.f reference/dla_syrcond.f reference/slagtm.f reference/zgels.f reference/ztzrqf.f
+reference/crot.f reference/dla_syrfsx_extended.f reference/slagts.f reference/zgelss.f reference/ztzrzf.f
+reference/cspcon.f reference/dla_syrpvgrw.f reference/slagv2.f reference/zgelsx.f reference/zung2l.f
+reference/cspmv.f reference/dlat2s.f reference/slahqr.f reference/zgelsy.f reference/zung2r.f
+reference/cspr.f reference/dlatbs.f reference/slahr2.f reference/zgeql2.f reference/zungbr.f
+reference/csprfs.f reference/dlatdf.f reference/slahrd.f reference/zgeqlf.f reference/zunghr.f
+reference/cspsv.f reference/dlatps.f reference/slaic1.f reference/zgeqp3.f reference/zungl2.f
+reference/cspsvx.f reference/dlatrd.f reference/slaisnan.f reference/zgeqpf.f reference/zunglq.f
+reference/csptrf.f reference/dlatrs.f reference/sla_lin_berr.f reference/zgeqr2.f reference/zungql.f
+reference/csptri.f reference/dlatrz.f reference/slaln2.f reference/zgeqrf.f reference/zungqr.f
+reference/csptrs.f reference/dlatzm.f reference/slals0.f reference/zgerfs.f reference/zungr2.f
+reference/csrscl.f reference/dlauu2.f reference/slalsa.f reference/zgerfsx.f reference/zungrq.f
+reference/cstedc.f reference/dlauum.f reference/slalsd.f reference/zgerq2.f reference/zungtr.f
+reference/cstegr.f reference/dla_wwaddw.f reference/slamrg.f reference/zgerqf.f reference/zunm2l.f
+reference/cstein.f reference/dopgtr.f reference/slaneg.f reference/zgesc2.f reference/zunm2r.f
+reference/cstemr.f reference/dopmtr.f reference/slangb.f reference/zgesdd.f reference/zunmbr.f
+reference/csteqr.f reference/dorg2l.f reference/slange.f reference/zgesvd.f reference/zunmhr.f
+reference/csycon.f reference/dorg2r.f reference/slangt.f reference/zgesv.f reference/zunml2.f
+reference/csyequb.f reference/dorgbr.f reference/slanhs.f reference/zgesvx.f reference/zunmlq.f
+reference/csymv.f reference/dorghr.f reference/slansb.f reference/zgesvxx.f reference/zunmql.f
+reference/csyr.f reference/dorgl2.f reference/slansf.f reference/zgetc2.f reference/zunmqr.f
+reference/csyrfs.f reference/dorglq.f reference/slansp.f reference/zgetf2.f reference/zunmr2.f
+reference/csyrfsx.f reference/dorgql.f reference/slanst.f
+reference/zunmr3.f
+reference/csysv.f reference/dorgqr.f reference/slansy.f reference/zgetri.f reference/zunmrq.f
+reference/csysvx.f reference/dorgr2.f reference/slantb.f reference/zunmrz.f
+reference/csysvxx.f reference/dorgrq.f reference/slantp.f reference/zggbak.f reference/zunmtr.f
+reference/csytf2.f reference/dorgtr.f reference/slantr.f reference/zggbal.f reference/zupgtr.f
+reference/csytrf.f reference/dorm2l.f reference/slanv2.f reference/zgges.f reference/zupmtr.f
+reference/csytri.f reference/dorm2r.f reference/slapll.f reference/zggesx.f
+reference/csytrs.f reference/dormbr.f reference/slapmt.f reference/zggev.f
+reference/ctbcon.f reference/dormhr.f reference/sla_porcond.f reference/zggevx.f
+)
+endif()
+
+endif(EIGEN_Fortran_COMPILER_WORKS)
+
+add_library(eigen_lapack_static ${EigenLapack_SRCS})
+add_library(eigen_lapack SHARED ${EigenLapack_SRCS})
+
+if(EIGEN_STANDARD_LIBRARIES_TO_LINK_TO)
+ target_link_libraries(eigen_lapack_static ${EIGEN_STANDARD_LIBRARIES_TO_LINK_TO})
+ target_link_libraries(eigen_lapack ${EIGEN_STANDARD_LIBRARIES_TO_LINK_TO})
+endif()
+
+add_dependencies(lapack eigen_lapack eigen_lapack_static)
+
+install(TARGETS eigen_lapack eigen_lapack_static
+ RUNTIME DESTINATION bin
+ LIBRARY DESTINATION lib
+ ARCHIVE DESTINATION lib)
+
+# add_subdirectory(testing)
+
diff --git a/lapack/cholesky.cpp b/lapack/cholesky.cpp
new file mode 100644
index 000000000..604fa437a
--- /dev/null
+++ b/lapack/cholesky.cpp
@@ -0,0 +1,72 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra.
+//
+// Copyright (C) 2010-2011 Gael Guennebaud <gael.guennebaud@inria.fr>
+//
+// This Source Code Form is subject to the terms of the Mozilla
+// Public License v. 2.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 "lapack_common.h"
+#include <Eigen/Cholesky>
+
+// POTRF computes the Cholesky factorization of a real symmetric positive definite matrix A.
+EIGEN_LAPACK_FUNC(potrf,(char* uplo, int *n, RealScalar *pa, int *lda, int *info))
+{
+ *info = 0;
+ if(UPLO(*uplo)==INVALID) *info = -1;
+ else if(*n<0) *info = -2;
+ else if(*lda<std::max(1,*n)) *info = -4;
+ if(*info!=0)
+ {
+ int e = -*info;
+ return xerbla_(SCALAR_SUFFIX_UP"POTRF", &e, 6);
+ }
+
+ Scalar* a = reinterpret_cast<Scalar*>(pa);
+ MatrixType A(a,*n,*n,*lda);
+ int ret;
+ if(UPLO(*uplo)==UP) ret = internal::llt_inplace<Scalar, Upper>::blocked(A);
+ else ret = internal::llt_inplace<Scalar, Lower>::blocked(A);
+
+ if(ret>=0)
+ *info = ret+1;
+
+ return 0;
+}
+
+// POTRS solves a system of linear equations A*X = B with a symmetric
+// positive definite matrix A using the Cholesky factorization
+// A = U**T*U or A = L*L**T computed by DPOTRF.
+EIGEN_LAPACK_FUNC(potrs,(char* uplo, int *n, int *nrhs, RealScalar *pa, int *lda, RealScalar *pb, int *ldb, int *info))
+{
+ *info = 0;
+ if(UPLO(*uplo)==INVALID) *info = -1;
+ else if(*n<0) *info = -2;
+ else if(*nrhs<0) *info = -3;
+ else if(*lda<std::max(1,*n)) *info = -5;
+ else if(*ldb<std::max(1,*n)) *info = -7;
+ if(*info!=0)
+ {
+ int e = -*info;
+ return xerbla_(SCALAR_SUFFIX_UP"POTRS", &e, 6);
+ }
+
+ Scalar* a = reinterpret_cast<Scalar*>(pa);
+ Scalar* b = reinterpret_cast<Scalar*>(pb);
+ MatrixType A(a,*n,*n,*lda);
+ MatrixType B(b,*n,*nrhs,*ldb);
+
+ if(UPLO(*uplo)==UP)
+ {
+ A.triangularView<Upper>().adjoint().solveInPlace(B);
+ A.triangularView<Upper>().solveInPlace(B);
+ }
+ else
+ {
+ A.triangularView<Lower>().solveInPlace(B);
+ A.triangularView<Lower>().adjoint().solveInPlace(B);
+ }
+
+ return 0;
+}
diff --git a/lapack/complex_double.cpp b/lapack/complex_double.cpp
new file mode 100644
index 000000000..424d2b8ca
--- /dev/null
+++ b/lapack/complex_double.cpp
@@ -0,0 +1,17 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra.
+//
+// Copyright (C) 2009-2011 Gael Guennebaud <gael.guennebaud@inria.fr>
+//
+// This Source Code Form is subject to the terms of the Mozilla
+// Public License v. 2.0. If a copy of the MPL was not distributed
+// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+#define SCALAR std::complex<double>
+#define SCALAR_SUFFIX z
+#define SCALAR_SUFFIX_UP "Z"
+#define REAL_SCALAR_SUFFIX d
+#define ISCOMPLEX 1
+
+#include "cholesky.cpp"
+#include "lu.cpp"
diff --git a/lapack/complex_single.cpp b/lapack/complex_single.cpp
new file mode 100644
index 000000000..c0b2d29ae
--- /dev/null
+++ b/lapack/complex_single.cpp
@@ -0,0 +1,17 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra.
+//
+// Copyright (C) 2009-2011 Gael Guennebaud <gael.guennebaud@inria.fr>
+//
+// This Source Code Form is subject to the terms of the Mozilla
+// Public License v. 2.0. If a copy of the MPL was not distributed
+// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+#define SCALAR std::complex<float>
+#define SCALAR_SUFFIX c
+#define SCALAR_SUFFIX_UP "C"
+#define REAL_SCALAR_SUFFIX s
+#define ISCOMPLEX 1
+
+#include "cholesky.cpp"
+#include "lu.cpp"
diff --git a/lapack/double.cpp b/lapack/double.cpp
new file mode 100644
index 000000000..d86549e19
--- /dev/null
+++ b/lapack/double.cpp
@@ -0,0 +1,17 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra.
+//
+// Copyright (C) 2009-2011 Gael Guennebaud <gael.guennebaud@inria.fr>
+//
+// This Source Code Form is subject to the terms of the Mozilla
+// Public License v. 2.0. If a copy of the MPL was not distributed
+// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+#define SCALAR double
+#define SCALAR_SUFFIX d
+#define SCALAR_SUFFIX_UP "D"
+#define ISCOMPLEX 0
+
+#include "cholesky.cpp"
+#include "lu.cpp"
+#include "eigenvalues.cpp"
diff --git a/lapack/eigenvalues.cpp b/lapack/eigenvalues.cpp
new file mode 100644
index 000000000..a1526ebcd
--- /dev/null
+++ b/lapack/eigenvalues.cpp
@@ -0,0 +1,79 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra.
+//
+// Copyright (C) 2011 Gael Guennebaud <gael.guennebaud@inria.fr>
+//
+// This Source Code Form is subject to the terms of the Mozilla
+// Public License v. 2.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 "common.h"
+#include <Eigen/Eigenvalues>
+
+// computes an LU factorization of a general M-by-N matrix A using partial pivoting with row interchanges
+EIGEN_LAPACK_FUNC(syev,(char *jobz, char *uplo, int* n, Scalar* a, int *lda, Scalar* w, Scalar* /*work*/, int* lwork, int *info))
+{
+ // TODO exploit the work buffer
+ bool query_size = *lwork==-1;
+
+ *info = 0;
+ if(*jobz!='N' && *jobz!='V') *info = -1;
+ else if(UPLO(*uplo)==INVALID) *info = -2;
+ else if(*n<0) *info = -3;
+ else if(*lda<std::max(1,*n)) *info = -5;
+ else if((!query_size) && *lwork<std::max(1,3**n-1)) *info = -8;
+
+// if(*info==0)
+// {
+// int nb = ILAENV( 1, 'SSYTRD', UPLO, N, -1, -1, -1 )
+// LWKOPT = MAX( 1, ( NB+2 )*N )
+// WORK( 1 ) = LWKOPT
+// *
+// IF( LWORK.LT.MAX( 1, 3*N-1 ) .AND. .NOT.LQUERY )
+// $ INFO = -8
+// END IF
+// *
+// IF( INFO.NE.0 ) THEN
+// CALL XERBLA( 'SSYEV ', -INFO )
+// RETURN
+// ELSE IF( LQUERY ) THEN
+// RETURN
+// END IF
+
+ if(*info!=0)
+ {
+ int e = -*info;
+ return xerbla_(SCALAR_SUFFIX_UP"SYEV ", &e, 6);
+ }
+
+ if(query_size)
+ {
+ *lwork = 0;
+ return 0;
+ }
+
+ if(*n==0)
+ return 0;
+
+ PlainMatrixType mat(*n,*n);
+ if(UPLO(*uplo)==UP) mat = matrix(a,*n,*n,*lda).adjoint();
+ else mat = matrix(a,*n,*n,*lda);
+
+ bool computeVectors = *jobz=='V' || *jobz=='v';
+ SelfAdjointEigenSolver<PlainMatrixType> eig(mat,computeVectors?ComputeEigenvectors:EigenvaluesOnly);
+
+ if(eig.info()==NoConvergence)
+ {
+ vector(w,*n).setZero();
+ if(computeVectors)
+ matrix(a,*n,*n,*lda).setIdentity();
+ //*info = 1;
+ return 0;
+ }
+
+ vector(w,*n) = eig.eigenvalues();
+ if(computeVectors)
+ matrix(a,*n,*n,*lda) = eig.eigenvectors();
+
+ return 0;
+}
diff --git a/lapack/lapack_common.h b/lapack/lapack_common.h
new file mode 100644
index 000000000..e558c1409
--- /dev/null
+++ b/lapack/lapack_common.h
@@ -0,0 +1,23 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra.
+//
+// Copyright (C) 2010-2011 Gael Guennebaud <gael.guennebaud@inria.fr>
+//
+// This Source Code Form is subject to the terms of the Mozilla
+// Public License v. 2.0. If a copy of the MPL was not distributed
+// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+#ifndef EIGEN_LAPACK_COMMON_H
+#define EIGEN_LAPACK_COMMON_H
+
+#include "../blas/common.h"
+
+#define EIGEN_LAPACK_FUNC(FUNC,ARGLIST) \
+ extern "C" { int EIGEN_BLAS_FUNC(FUNC) ARGLIST; } \
+ int EIGEN_BLAS_FUNC(FUNC) ARGLIST
+
+typedef Eigen::Map<Eigen::Transpositions<Eigen::Dynamic,Eigen::Dynamic,int> > PivotsType;
+
+
+
+#endif // EIGEN_LAPACK_COMMON_H
diff --git a/lapack/lu.cpp b/lapack/lu.cpp
new file mode 100644
index 000000000..311511674
--- /dev/null
+++ b/lapack/lu.cpp
@@ -0,0 +1,89 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra.
+//
+// Copyright (C) 2010-2011 Gael Guennebaud <gael.guennebaud@inria.fr>
+//
+// This Source Code Form is subject to the terms of the Mozilla
+// Public License v. 2.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 "common.h"
+#include <Eigen/LU>
+
+// computes an LU factorization of a general M-by-N matrix A using partial pivoting with row interchanges
+EIGEN_LAPACK_FUNC(getrf,(int *m, int *n, RealScalar *pa, int *lda, int *ipiv, int *info))
+{
+ *info = 0;
+ if(*m<0) *info = -1;
+ else if(*n<0) *info = -2;
+ else if(*lda<std::max(1,*m)) *info = -4;
+ if(*info!=0)
+ {
+ int e = -*info;
+ return xerbla_(SCALAR_SUFFIX_UP"GETRF", &e, 6);
+ }
+
+ if(*m==0 || *n==0)
+ return 0;
+
+ Scalar* a = reinterpret_cast<Scalar*>(pa);
+ int nb_transpositions;
+ int ret = Eigen::internal::partial_lu_impl<Scalar,ColMajor,int>
+ ::blocked_lu(*m, *n, a, *lda, ipiv, nb_transpositions);
+
+ for(int i=0; i<std::min(*m,*n); ++i)
+ ipiv[i]++;
+
+ if(ret>=0)
+ *info = ret+1;
+
+ return 0;
+}
+
+//GETRS solves a system of linear equations
+// A * X = B or A' * X = B
+// with a general N-by-N matrix A using the LU factorization computed by GETRF
+EIGEN_LAPACK_FUNC(getrs,(char *trans, int *n, int *nrhs, RealScalar *pa, int *lda, int *ipiv, RealScalar *pb, int *ldb, int *info))
+{
+ *info = 0;
+ if(OP(*trans)==INVALID) *info = -1;
+ else if(*n<0) *info = -2;
+ else if(*nrhs<0) *info = -3;
+ else if(*lda<std::max(1,*n)) *info = -5;
+ else if(*ldb<std::max(1,*n)) *info = -8;
+ if(*info!=0)
+ {
+ int e = -*info;
+ return xerbla_(SCALAR_SUFFIX_UP"GETRS", &e, 6);
+ }
+
+ Scalar* a = reinterpret_cast<Scalar*>(pa);
+ Scalar* b = reinterpret_cast<Scalar*>(pb);
+ MatrixType lu(a,*n,*n,*lda);
+ MatrixType B(b,*n,*nrhs,*ldb);
+
+ for(int i=0; i<*n; ++i)
+ ipiv[i]--;
+ if(OP(*trans)==NOTR)
+ {
+ B = PivotsType(ipiv,*n) * B;
+ lu.triangularView<UnitLower>().solveInPlace(B);
+ lu.triangularView<Upper>().solveInPlace(B);
+ }
+ else if(OP(*trans)==TR)
+ {
+ lu.triangularView<Upper>().transpose().solveInPlace(B);
+ lu.triangularView<UnitLower>().transpose().solveInPlace(B);
+ B = PivotsType(ipiv,*n).transpose() * B;
+ }
+ else if(OP(*trans)==ADJ)
+ {
+ lu.triangularView<Upper>().adjoint().solveInPlace(B);
+ lu.triangularView<UnitLower>().adjoint().solveInPlace(B);
+ B = PivotsType(ipiv,*n).transpose() * B;
+ }
+ for(int i=0; i<*n; ++i)
+ ipiv[i]++;
+
+ return 0;
+}
diff --git a/lapack/single.cpp b/lapack/single.cpp
new file mode 100644
index 000000000..a64ed44e1
--- /dev/null
+++ b/lapack/single.cpp
@@ -0,0 +1,17 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra.
+//
+// Copyright (C) 2009-2011 Gael Guennebaud <gael.guennebaud@inria.fr>
+//
+// This Source Code Form is subject to the terms of the Mozilla
+// Public License v. 2.0. If a copy of the MPL was not distributed
+// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+#define SCALAR float
+#define SCALAR_SUFFIX s
+#define SCALAR_SUFFIX_UP "S"
+#define ISCOMPLEX 0
+
+#include "cholesky.cpp"
+#include "lu.cpp"
+#include "eigenvalues.cpp"
diff --git a/scripts/CMakeLists.txt b/scripts/CMakeLists.txt
new file mode 100644
index 000000000..0d9a631a9
--- /dev/null
+++ b/scripts/CMakeLists.txt
@@ -0,0 +1,6 @@
+get_property(EIGEN_TESTS_LIST GLOBAL PROPERTY EIGEN_TESTS_LIST)
+configure_file(buildtests.in ${CMAKE_BINARY_DIR}/buildtests.sh @ONLY)
+
+configure_file(check.in ${CMAKE_BINARY_DIR}/check.sh COPYONLY)
+configure_file(debug.in ${CMAKE_BINARY_DIR}/debug.sh COPYONLY)
+configure_file(release.in ${CMAKE_BINARY_DIR}/release.sh COPYONLY)
diff --git a/scripts/buildtests.in b/scripts/buildtests.in
new file mode 100755
index 000000000..7026373cf
--- /dev/null
+++ b/scripts/buildtests.in
@@ -0,0 +1,22 @@
+#!/bin/bash
+
+if [[ $# != 1 || $1 == *help ]]
+then
+ echo "usage: ./check regexp"
+ echo " Builds tests matching the regexp."
+ echo " The EIGEN_MAKE_ARGS environment variable allows to pass args to 'make'."
+ echo " For example, to launch 5 concurrent builds, use EIGEN_MAKE_ARGS='-j5'"
+ exit 0
+fi
+
+TESTSLIST="@EIGEN_TESTS_LIST@"
+targets_to_make=`echo "$TESTSLIST" | egrep "$1" | xargs echo`
+
+if [ -n "${EIGEN_MAKE_ARGS:+x}" ]
+then
+ make $targets_to_make ${EIGEN_MAKE_ARGS}
+else
+ make $targets_to_make
+fi
+exit $?
+
diff --git a/scripts/check.in b/scripts/check.in
new file mode 100755
index 000000000..a90061a57
--- /dev/null
+++ b/scripts/check.in
@@ -0,0 +1,21 @@
+#!/bin/bash
+# check : shorthand for make and ctest -R
+
+if [[ $# != 1 || $1 == *help ]]
+then
+ echo "usage: ./check regexp"
+ echo " Builds and runs tests matching the regexp."
+ echo " The EIGEN_MAKE_ARGS environment variable allows to pass args to 'make'."
+ echo " For example, to launch 5 concurrent builds, use EIGEN_MAKE_ARGS='-j5'"
+ echo " The EIGEN_CTEST_ARGS environment variable allows to pass args to 'ctest'."
+ echo " For example, with CTest 2.8, you can use EIGEN_CTEST_ARGS='-j5'."
+ exit 0
+fi
+
+if [ -n "${EIGEN_CTEST_ARGS:+x}" ]
+then
+ ./buildtests.sh "$1" && ctest -R "$1" ${EIGEN_CTEST_ARGS}
+else
+ ./buildtests.sh "$1" && ctest -R "$1"
+fi
+exit $?
diff --git a/scripts/debug.in b/scripts/debug.in
new file mode 100755
index 000000000..d339d3d1f
--- /dev/null
+++ b/scripts/debug.in
@@ -0,0 +1,3 @@
+#!/bin/sh
+
+cmake -DCMAKE_BUILD_TYPE=Debug .
diff --git a/scripts/eigen_gen_credits.cpp b/scripts/eigen_gen_credits.cpp
new file mode 100644
index 000000000..f2e81631d
--- /dev/null
+++ b/scripts/eigen_gen_credits.cpp
@@ -0,0 +1,232 @@
+#include <string>
+#include <sstream>
+#include <iostream>
+#include <fstream>
+#include <iomanip>
+#include <map>
+#include <list>
+
+using namespace std;
+
+// this function takes a line that may contain a name and/or email address,
+// and returns just the name, while fixing the "bad cases".
+std::string contributor_name(const std::string& line)
+{
+ string result;
+
+ // let's first take care of the case of isolated email addresses, like
+ // "user@localhost.localdomain" entries
+ if(line.find("markb@localhost.localdomain") != string::npos)
+ {
+ return "Mark Borgerding";
+ }
+
+ if(line.find("kayhman@contact.intra.cea.fr") != string::npos)
+ {
+ return "Guillaume Saupin";
+ }
+
+ // from there on we assume that we have a entry of the form
+ // either:
+ // Bla bli Blurp
+ // or:
+ // Bla bli Blurp <bblurp@email.com>
+
+ size_t position_of_email_address = line.find_first_of('<');
+ if(position_of_email_address != string::npos)
+ {
+ // there is an e-mail address in <...>.
+
+ // Hauke once committed as "John Smith", fix that.
+ if(line.find("hauke.heibel") != string::npos)
+ result = "Hauke Heibel";
+ else
+ {
+ // just remove the e-mail address
+ result = line.substr(0, position_of_email_address);
+ }
+ }
+ else
+ {
+ // there is no e-mail address in <...>.
+
+ if(line.find("convert-repo") != string::npos)
+ result = "";
+ else
+ result = line;
+ }
+
+ // remove trailing spaces
+ size_t length = result.length();
+ while(length >= 1 && result[length-1] == ' ') result.erase(--length);
+
+ return result;
+}
+
+// parses hg churn output to generate a contributors map.
+map<string,int> contributors_map_from_churn_output(const char *filename)
+{
+ map<string,int> contributors_map;
+
+ string line;
+ ifstream churn_out;
+ churn_out.open(filename, ios::in);
+ while(!getline(churn_out,line).eof())
+ {
+ // remove the histograms "******" that hg churn may draw at the end of some lines
+ size_t first_star = line.find_first_of('*');
+ if(first_star != string::npos) line.erase(first_star);
+
+ // remove trailing spaces
+ size_t length = line.length();
+ while(length >= 1 && line[length-1] == ' ') line.erase(--length);
+
+ // now the last space indicates where the number starts
+ size_t last_space = line.find_last_of(' ');
+
+ // get the number (of changesets or of modified lines for each contributor)
+ int number;
+ istringstream(line.substr(last_space+1)) >> number;
+
+ // get the name of the contributor
+ line.erase(last_space);
+ string name = contributor_name(line);
+
+ map<string,int>::iterator it = contributors_map.find(name);
+ // if new contributor, insert
+ if(it == contributors_map.end())
+ contributors_map.insert(pair<string,int>(name, number));
+ // if duplicate, just add the number
+ else
+ it->second += number;
+ }
+ churn_out.close();
+
+ return contributors_map;
+}
+
+// find the last name, i.e. the last word.
+// for "van den Schbling" types of last names, that's not a problem, that's actually what we want.
+string lastname(const string& name)
+{
+ size_t last_space = name.find_last_of(' ');
+ if(last_space >= name.length()-1) return name;
+ else return name.substr(last_space+1);
+}
+
+struct contributor
+{
+ string name;
+ int changedlines;
+ int changesets;
+ string url;
+ string misc;
+
+ contributor() : changedlines(0), changesets(0) {}
+
+ bool operator < (const contributor& other)
+ {
+ return lastname(name).compare(lastname(other.name)) < 0;
+ }
+};
+
+void add_online_info_into_contributors_list(list<contributor>& contributors_list, const char *filename)
+{
+ string line;
+ ifstream online_info;
+ online_info.open(filename, ios::in);
+ while(!getline(online_info,line).eof())
+ {
+ string hgname, realname, url, misc;
+
+ size_t last_bar = line.find_last_of('|');
+ if(last_bar == string::npos) continue;
+ if(last_bar < line.length())
+ misc = line.substr(last_bar+1);
+ line.erase(last_bar);
+
+ last_bar = line.find_last_of('|');
+ if(last_bar == string::npos) continue;
+ if(last_bar < line.length())
+ url = line.substr(last_bar+1);
+ line.erase(last_bar);
+
+ last_bar = line.find_last_of('|');
+ if(last_bar == string::npos) continue;
+ if(last_bar < line.length())
+ realname = line.substr(last_bar+1);
+ line.erase(last_bar);
+
+ hgname = line;
+
+ // remove the example line
+ if(hgname.find("MercurialName") != string::npos) continue;
+
+ list<contributor>::iterator it;
+ for(it=contributors_list.begin(); it != contributors_list.end() && it->name != hgname; ++it)
+ {}
+
+ if(it == contributors_list.end())
+ {
+ contributor c;
+ c.name = realname;
+ c.url = url;
+ c.misc = misc;
+ contributors_list.push_back(c);
+ }
+ else
+ {
+ it->name = realname;
+ it->url = url;
+ it->misc = misc;
+ }
+ }
+}
+
+int main()
+{
+ // parse the hg churn output files
+ map<string,int> contributors_map_for_changedlines = contributors_map_from_churn_output("churn-changedlines.out");
+ //map<string,int> contributors_map_for_changesets = contributors_map_from_churn_output("churn-changesets.out");
+
+ // merge into the contributors list
+ list<contributor> contributors_list;
+ map<string,int>::iterator it;
+ for(it=contributors_map_for_changedlines.begin(); it != contributors_map_for_changedlines.end(); ++it)
+ {
+ contributor c;
+ c.name = it->first;
+ c.changedlines = it->second;
+ c.changesets = 0; //contributors_map_for_changesets.find(it->first)->second;
+ contributors_list.push_back(c);
+ }
+
+ add_online_info_into_contributors_list(contributors_list, "online-info.out");
+
+ contributors_list.sort();
+
+ cout << "{| cellpadding=\"5\"\n";
+ cout << "!\n";
+ cout << "! Lines changed\n";
+ cout << "!\n";
+
+ list<contributor>::iterator itc;
+ int i = 0;
+ for(itc=contributors_list.begin(); itc != contributors_list.end(); ++itc)
+ {
+ if(itc->name.length() == 0) continue;
+ if(i%2) cout << "|-\n";
+ else cout << "|- style=\"background:#FFFFD0\"\n";
+ if(itc->url.length())
+ cout << "| [" << itc->url << " " << itc->name << "]\n";
+ else
+ cout << "| " << itc->name << "\n";
+ if(itc->changedlines)
+ cout << "| " << itc->changedlines << "\n";
+ else
+ cout << "| (no information)\n";
+ cout << "| " << itc->misc << "\n";
+ i++;
+ }
+ cout << "|}" << endl;
+}
diff --git a/scripts/eigen_gen_docs b/scripts/eigen_gen_docs
new file mode 100644
index 000000000..921d600ed
--- /dev/null
+++ b/scripts/eigen_gen_docs
@@ -0,0 +1,22 @@
+#!/bin/sh
+
+# configuration
+# You should call this script with USER set as you want, else some default
+# will be used
+USER=${USER:-'orzel'}
+
+#ulimit -v 1024000
+
+# step 1 : build
+mkdir build -p
+(cd build && cmake .. && make doc) || { echo "make failed"; exit 1; }
+
+#step 2 : upload
+# (the '/' at the end of path is very important, see rsync documentation)
+rsync -az --no-p --delete build/doc/html/ $USER@ssh.tuxfamily.org:eigen/eigen.tuxfamily.org-web/htdocs/dox-devel/ || { echo "upload failed"; exit 1; }
+
+#step 3 : fix the perm
+ssh $USER@ssh.tuxfamily.org 'chmod -R g+w /home/eigen/eigen.tuxfamily.org-web/htdocs/dox-devel' || { echo "perm failed"; exit 1; }
+
+echo "Uploaded successfully"
+
diff --git a/scripts/release.in b/scripts/release.in
new file mode 100755
index 000000000..db2d9d940
--- /dev/null
+++ b/scripts/release.in
@@ -0,0 +1,3 @@
+#!/bin/sh
+
+cmake -DCMAKE_BUILD_TYPE=Release .
diff --git a/scripts/relicense.py b/scripts/relicense.py
new file mode 100644
index 000000000..8a5265f1f
--- /dev/null
+++ b/scripts/relicense.py
@@ -0,0 +1,69 @@
+# This file is part of Eigen, a lightweight C++ template library
+# for linear algebra.
+#
+# Copyright (C) 2012 Keir Mierle <mierle@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/.
+#
+# Author: mierle@gmail.com (Keir Mierle)
+#
+# Make the long-awaited conversion to MPL.
+
+lgpl3_header = '''
+// Eigen is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 3 of the License, or (at your option) any later version.
+//
+// Alternatively, you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 2 of
+// the License, or (at your option) any later version.
+//
+// Eigen is distributed in the hope that it will be useful, but WITHOUT ANY
+// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+// FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License or the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public
+// License and a copy of the GNU General Public License along with
+// Eigen. If not, see <http://www.gnu.org/licenses/>.
+'''
+
+mpl2_header = """
+// This Source Code Form is subject to the terms of the Mozilla
+// Public License v. 2.0. If a copy of the MPL was not distributed
+// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
+"""
+
+import os
+import sys
+
+exclusions = set(['relicense.py'])
+
+def update(text):
+ if text.find(lgpl3_header) == -1:
+ return text, False
+ return text.replace(lgpl3_header, mpl2_header), True
+
+rootdir = sys.argv[1]
+for root, sub_folders, files in os.walk(rootdir):
+ for basename in files:
+ if basename in exclusions:
+ print 'SKIPPED', filename
+ continue
+ filename = os.path.join(root, basename)
+ fo = file(filename)
+ text = fo.read()
+ fo.close()
+
+ text, updated = update(text)
+ if updated:
+ fo = file(filename, "w")
+ fo.write(text)
+ fo.close()
+ print 'UPDATED', filename
+ else:
+ print ' ', filename
diff --git a/signature_of_eigen3_matrix_library b/signature_of_eigen3_matrix_library
new file mode 100644
index 000000000..80aaf4621
--- /dev/null
+++ b/signature_of_eigen3_matrix_library
@@ -0,0 +1 @@
+This file is just there as a signature to help identify directories containing Eigen3. When writing a script looking for Eigen3, just look for this file. This is especially useful to help disambiguate with Eigen2...
diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt
new file mode 100644
index 000000000..6f8fc4ae3
--- /dev/null
+++ b/test/CMakeLists.txt
@@ -0,0 +1,243 @@
+
+# generate split test header file
+message(STATUS ${CMAKE_CURRENT_BINARY_DIR})
+file(WRITE ${CMAKE_CURRENT_BINARY_DIR}/split_test_helper.h "")
+foreach(i RANGE 1 999)
+ file(APPEND ${CMAKE_CURRENT_BINARY_DIR}/split_test_helper.h
+ "#ifdef EIGEN_TEST_PART_${i}\n"
+ "#define CALL_SUBTEST_${i}(FUNC) CALL_SUBTEST(FUNC)\n"
+ "#else\n"
+ "#define CALL_SUBTEST_${i}(FUNC)\n"
+ "#endif\n\n"
+ )
+endforeach()
+
+# configure blas/lapack (use Eigen's ones)
+set(BLAS_FOUND TRUE)
+set(LAPACK_FOUND TRUE)
+set(BLAS_LIBRARIES eigen_blas)
+set(LAPACK_LIBRARIES eigen_lapack)
+
+set(EIGEN_TEST_MATRIX_DIR "" CACHE STRING "Enable testing of realword sparse matrices contained in the specified path")
+if(EIGEN_TEST_MATRIX_DIR)
+ if(NOT WIN32)
+ message(STATUS "Test realworld sparse matrices: ${EIGEN_TEST_MATRIX_DIR}")
+ add_definitions( -DTEST_REAL_CASES="${EIGEN_TEST_MATRIX_DIR}" )
+ else(NOT WIN32)
+ message(STATUS "REAL CASES CAN NOT BE CURRENTLY TESTED ON WIN32")
+ endif(NOT WIN32)
+endif(EIGEN_TEST_MATRIX_DIR)
+
+set(SPARSE_LIBS " ")
+
+find_package(Cholmod)
+if(CHOLMOD_FOUND AND BLAS_FOUND AND LAPACK_FOUND)
+ add_definitions("-DEIGEN_CHOLMOD_SUPPORT")
+ include_directories(${CHOLMOD_INCLUDES})
+ set(SPARSE_LIBS ${SPARSE_LIBS} ${CHOLMOD_LIBRARIES} ${BLAS_LIBRARIES} ${LAPACK_LIBRARIES})
+ set(CHOLMOD_ALL_LIBS ${CHOLMOD_LIBRARIES} ${BLAS_LIBRARIES} ${LAPACK_LIBRARIES})
+ ei_add_property(EIGEN_TESTED_BACKENDS "Cholmod, ")
+else()
+ ei_add_property(EIGEN_MISSING_BACKENDS "Cholmod, ")
+endif()
+
+find_package(Umfpack)
+if(UMFPACK_FOUND AND BLAS_FOUND)
+ add_definitions("-DEIGEN_UMFPACK_SUPPORT")
+ include_directories(${UMFPACK_INCLUDES})
+ set(SPARSE_LIBS ${SPARSE_LIBS} ${UMFPACK_LIBRARIES} ${BLAS_LIBRARIES})
+ set(UMFPACK_ALL_LIBS ${UMFPACK_LIBRARIES} ${BLAS_LIBRARIES})
+ ei_add_property(EIGEN_TESTED_BACKENDS "UmfPack, ")
+else()
+ ei_add_property(EIGEN_MISSING_BACKENDS "UmfPack, ")
+endif()
+
+find_package(SuperLU)
+if(SUPERLU_FOUND AND BLAS_FOUND)
+ add_definitions("-DEIGEN_SUPERLU_SUPPORT")
+ include_directories(${SUPERLU_INCLUDES})
+ set(SPARSE_LIBS ${SPARSE_LIBS} ${SUPERLU_LIBRARIES} ${BLAS_LIBRARIES})
+ set(SUPERLU_ALL_LIBS ${SUPERLU_LIBRARIES} ${BLAS_LIBRARIES})
+ ei_add_property(EIGEN_TESTED_BACKENDS "SuperLU, ")
+else()
+ ei_add_property(EIGEN_MISSING_BACKENDS "SuperLU, ")
+endif()
+
+
+find_package(Pastix)
+find_package(Scotch)
+find_package(Metis)
+if(PASTIX_FOUND AND BLAS_FOUND)
+ add_definitions("-DEIGEN_PASTIX_SUPPORT")
+ include_directories(${PASTIX_INCLUDES})
+ if(SCOTCH_FOUND)
+ include_directories(${SCOTCH_INCLUDES})
+ set(PASTIX_LIBRARIES ${PASTIX_LIBRARIES} ${SCOTCH_LIBRARIES})
+ elseif(METIS_FOUND)
+ include_directories(${METIS_INCLUDES})
+ set(PASTIX_LIBRARIES ${PASTIX_LIBRARIES} ${METIS_LIBRARIES})
+ else(SCOTCH_FOUND)
+ ei_add_property(EIGEN_MISSING_BACKENDS "PaStiX, ")
+ endif(SCOTCH_FOUND)
+ set(SPARSE_LIBS ${SPARSE_LIBS} ${PASTIX_LIBRARIES} ${ORDERING_LIBRARIES} ${BLAS_LIBRARIES})
+ set(PASTIX_ALL_LIBS ${PASTIX_LIBRARIES} ${BLAS_LIBRARIES})
+ ei_add_property(EIGEN_TESTED_BACKENDS "PaStiX, ")
+else()
+ ei_add_property(EIGEN_MISSING_BACKENDS "PaStiX, ")
+endif()
+
+option(EIGEN_TEST_NOQT "Disable Qt support in unit tests" OFF)
+if(NOT EIGEN_TEST_NOQT)
+ find_package(Qt4)
+ if(QT4_FOUND)
+ include(${QT_USE_FILE})
+ ei_add_property(EIGEN_TESTED_BACKENDS "Qt4 support, ")
+ else()
+ ei_add_property(EIGEN_MISSING_BACKENDS "Qt4 support, ")
+ endif()
+endif(NOT EIGEN_TEST_NOQT)
+
+if(TEST_LIB)
+ add_definitions("-DEIGEN_EXTERN_INSTANTIATIONS=1")
+endif(TEST_LIB)
+
+ei_add_test(meta)
+ei_add_test(sizeof)
+ei_add_test(dynalloc)
+ei_add_test(nomalloc)
+ei_add_test(first_aligned)
+ei_add_test(mixingtypes)
+ei_add_test(packetmath)
+ei_add_test(unalignedassert)
+ei_add_test(vectorization_logic)
+ei_add_test(basicstuff)
+ei_add_test(linearstructure)
+ei_add_test(integer_types)
+ei_add_test(cwiseop)
+ei_add_test(unalignedcount)
+ei_add_test(exceptions)
+ei_add_test(redux)
+ei_add_test(visitor)
+ei_add_test(block)
+ei_add_test(corners)
+ei_add_test(product_small)
+ei_add_test(product_large)
+ei_add_test(product_extra)
+ei_add_test(diagonalmatrices)
+ei_add_test(adjoint)
+ei_add_test(diagonal)
+ei_add_test(miscmatrices)
+ei_add_test(commainitializer)
+ei_add_test(smallvectors)
+ei_add_test(map)
+ei_add_test(mapstride)
+ei_add_test(mapstaticmethods)
+ei_add_test(array)
+ei_add_test(array_for_matrix)
+ei_add_test(array_replicate)
+ei_add_test(array_reverse)
+ei_add_test(triangular)
+ei_add_test(selfadjoint)
+ei_add_test(product_selfadjoint)
+ei_add_test(product_symm)
+ei_add_test(product_syrk)
+ei_add_test(product_trmv)
+ei_add_test(product_trmm)
+ei_add_test(product_trsolve)
+ei_add_test(product_mmtr)
+ei_add_test(product_notemporary)
+ei_add_test(stable_norm)
+ei_add_test(bandmatrix)
+ei_add_test(cholesky)
+ei_add_test(lu)
+ei_add_test(determinant)
+ei_add_test(inverse)
+ei_add_test(qr)
+ei_add_test(qr_colpivoting)
+ei_add_test(qr_fullpivoting)
+ei_add_test(upperbidiagonalization)
+ei_add_test(hessenberg)
+ei_add_test(schur_real)
+ei_add_test(schur_complex)
+ei_add_test(eigensolver_selfadjoint)
+ei_add_test(eigensolver_generic)
+ei_add_test(eigensolver_complex)
+ei_add_test(jacobi)
+ei_add_test(jacobisvd)
+ei_add_test(geo_orthomethods)
+ei_add_test(geo_homogeneous)
+ei_add_test(geo_quaternion)
+ei_add_test(geo_transformations)
+ei_add_test(geo_eulerangles)
+ei_add_test(geo_hyperplane)
+ei_add_test(geo_parametrizedline)
+ei_add_test(geo_alignedbox)
+ei_add_test(stdvector)
+ei_add_test(stdvector_overload)
+ei_add_test(stdlist)
+ei_add_test(stddeque)
+ei_add_test(resize)
+if(QT4_FOUND)
+ ei_add_test(qtvector "" "${QT_QTCORE_LIBRARY}")
+endif(QT4_FOUND)
+ei_add_test(sparse_vector)
+ei_add_test(sparse_basic)
+ei_add_test(sparse_product)
+ei_add_test(sparse_solvers)
+ei_add_test(umeyama)
+ei_add_test(householder)
+ei_add_test(swap)
+ei_add_test(conservative_resize)
+ei_add_test(permutationmatrices)
+ei_add_test(sparse_permutations)
+ei_add_test(eigen2support)
+ei_add_test(nullary)
+ei_add_test(nesting_ops "${CMAKE_CXX_FLAGS_DEBUG}")
+ei_add_test(zerosized)
+ei_add_test(dontalign)
+ei_add_test(sizeoverflow)
+ei_add_test(prec_inverse_4x4)
+ei_add_test(vectorwiseop)
+
+ei_add_test(simplicial_cholesky)
+ei_add_test(conjugate_gradient)
+ei_add_test(bicgstab)
+
+
+if(UMFPACK_FOUND)
+ ei_add_test(umfpack_support "" "${UMFPACK_ALL_LIBS}")
+endif()
+
+if(SUPERLU_FOUND)
+ ei_add_test(superlu_support "" "${SUPERLU_ALL_LIBS}")
+endif()
+
+if(CHOLMOD_FOUND)
+ ei_add_test(cholmod_support "" "${CHOLMOD_ALL_LIBS}")
+endif()
+
+if(PARDISO_FOUND)
+ ei_add_test(pardiso_support "" "${PARDISO_ALL_LIBS}")
+endif()
+
+if(PASTIX_FOUND AND (SCOTCH_FOUND OR METIS_FOUND))
+ ei_add_test(pastix_support "" "${PASTIX_ALL_LIBS}")
+endif()
+
+string(TOLOWER "${CMAKE_CXX_COMPILER}" cmake_cxx_compiler_tolower)
+if(cmake_cxx_compiler_tolower MATCHES "qcc")
+ set(CXX_IS_QCC "ON")
+endif()
+
+ei_add_property(EIGEN_TESTING_SUMMARY "CXX: ${CMAKE_CXX_COMPILER}\n")
+if(CMAKE_COMPILER_IS_GNUCXX AND NOT CXX_IS_QCC)
+ execute_process(COMMAND ${CMAKE_CXX_COMPILER} --version COMMAND head -n 1 OUTPUT_VARIABLE EIGEN_CXX_VERSION_STRING OUTPUT_STRIP_TRAILING_WHITESPACE)
+ ei_add_property(EIGEN_TESTING_SUMMARY "CXX_VERSION: ${EIGEN_CXX_VERSION_STRING}\n")
+endif()
+ei_add_property(EIGEN_TESTING_SUMMARY "CXX_FLAGS: ${CMAKE_CXX_FLAGS}\n")
+ei_add_property(EIGEN_TESTING_SUMMARY "Sparse lib flags: ${SPARSE_LIBS}\n")
+
+option(EIGEN_TEST_EIGEN2 "Run whole Eigen2 test suite against EIGEN2_SUPPORT" OFF)
+if(EIGEN_TEST_EIGEN2)
+ add_subdirectory(eigen2)
+endif()
diff --git a/test/adjoint.cpp b/test/adjoint.cpp
new file mode 100644
index 000000000..b6cf0a68b
--- /dev/null
+++ b/test/adjoint.cpp
@@ -0,0 +1,141 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra.
+//
+// Copyright (C) 2006-2008 Benoit Jacob <jacob.benoit.1@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/.
+
+#define EIGEN_NO_STATIC_ASSERT
+
+#include "main.h"
+
+template<typename MatrixType> void adjoint(const MatrixType& m)
+{
+ /* this test covers the following files:
+ Transpose.h Conjugate.h Dot.h
+ */
+ typedef typename MatrixType::Index Index;
+ typedef typename MatrixType::Scalar Scalar;
+ typedef typename NumTraits<Scalar>::Real RealScalar;
+ typedef Matrix<Scalar, MatrixType::RowsAtCompileTime, 1> VectorType;
+ typedef Matrix<Scalar, MatrixType::RowsAtCompileTime, MatrixType::RowsAtCompileTime> SquareMatrixType;
+
+ Index rows = m.rows();
+ Index cols = m.cols();
+
+ MatrixType m1 = MatrixType::Random(rows, cols),
+ m2 = MatrixType::Random(rows, cols),
+ m3(rows, cols),
+ square = SquareMatrixType::Random(rows, rows);
+ VectorType v1 = VectorType::Random(rows),
+ v2 = VectorType::Random(rows),
+ v3 = VectorType::Random(rows),
+ vzero = VectorType::Zero(rows);
+
+ Scalar s1 = internal::random<Scalar>(),
+ s2 = internal::random<Scalar>();
+
+ // check basic compatibility of adjoint, transpose, conjugate
+ VERIFY_IS_APPROX(m1.transpose().conjugate().adjoint(), m1);
+ VERIFY_IS_APPROX(m1.adjoint().conjugate().transpose(), m1);
+
+ // check multiplicative behavior
+ VERIFY_IS_APPROX((m1.adjoint() * m2).adjoint(), m2.adjoint() * m1);
+ VERIFY_IS_APPROX((s1 * m1).adjoint(), internal::conj(s1) * m1.adjoint());
+
+ // check basic properties of dot, norm, norm2
+ typedef typename NumTraits<Scalar>::Real RealScalar;
+
+ RealScalar ref = NumTraits<Scalar>::IsInteger ? RealScalar(0) : (std::max)((s1 * v1 + s2 * v2).norm(),v3.norm());
+ VERIFY(test_isApproxWithRef((s1 * v1 + s2 * v2).dot(v3), internal::conj(s1) * v1.dot(v3) + internal::conj(s2) * v2.dot(v3), ref));
+ VERIFY(test_isApproxWithRef(v3.dot(s1 * v1 + s2 * v2), s1*v3.dot(v1)+s2*v3.dot(v2), ref));
+ VERIFY_IS_APPROX(internal::conj(v1.dot(v2)), v2.dot(v1));
+ VERIFY_IS_APPROX(internal::real(v1.dot(v1)), v1.squaredNorm());
+ if(!NumTraits<Scalar>::IsInteger) {
+ VERIFY_IS_APPROX(v1.squaredNorm(), v1.norm() * v1.norm());
+ // check normalized() and normalize()
+ VERIFY_IS_APPROX(v1, v1.norm() * v1.normalized());
+ v3 = v1;
+ v3.normalize();
+ VERIFY_IS_APPROX(v1, v1.norm() * v3);
+ VERIFY_IS_APPROX(v3, v1.normalized());
+ VERIFY_IS_APPROX(v3.norm(), RealScalar(1));
+ }
+ VERIFY_IS_MUCH_SMALLER_THAN(internal::abs(vzero.dot(v1)), static_cast<RealScalar>(1));
+
+ // check compatibility of dot and adjoint
+
+ ref = NumTraits<Scalar>::IsInteger ? 0 : (std::max)((std::max)(v1.norm(),v2.norm()),(std::max)((square * v2).norm(),(square.adjoint() * v1).norm()));
+ VERIFY(test_isApproxWithRef(v1.dot(square * v2), (square.adjoint() * v1).dot(v2), ref));
+
+ // like in testBasicStuff, test operator() to check const-qualification
+ Index r = internal::random<Index>(0, rows-1),
+ c = internal::random<Index>(0, cols-1);
+ VERIFY_IS_APPROX(m1.conjugate()(r,c), internal::conj(m1(r,c)));
+ VERIFY_IS_APPROX(m1.adjoint()(c,r), internal::conj(m1(r,c)));
+
+ if(!NumTraits<Scalar>::IsInteger)
+ {
+ // check that Random().normalized() works: tricky as the random xpr must be evaluated by
+ // normalized() in order to produce a consistent result.
+ VERIFY_IS_APPROX(VectorType::Random(rows).normalized().norm(), RealScalar(1));
+ }
+
+ // check inplace transpose
+ m3 = m1;
+ m3.transposeInPlace();
+ VERIFY_IS_APPROX(m3,m1.transpose());
+ m3.transposeInPlace();
+ VERIFY_IS_APPROX(m3,m1);
+
+ // check inplace adjoint
+ m3 = m1;
+ m3.adjointInPlace();
+ VERIFY_IS_APPROX(m3,m1.adjoint());
+ m3.transposeInPlace();
+ VERIFY_IS_APPROX(m3,m1.conjugate());
+
+ // check mixed dot product
+ typedef Matrix<RealScalar, MatrixType::RowsAtCompileTime, 1> RealVectorType;
+ RealVectorType rv1 = RealVectorType::Random(rows);
+ VERIFY_IS_APPROX(v1.dot(rv1.template cast<Scalar>()), v1.dot(rv1));
+ VERIFY_IS_APPROX(rv1.template cast<Scalar>().dot(v1), rv1.dot(v1));
+}
+
+void test_adjoint()
+{
+ for(int i = 0; i < g_repeat; i++) {
+ CALL_SUBTEST_1( adjoint(Matrix<float, 1, 1>()) );
+ CALL_SUBTEST_2( adjoint(Matrix3d()) );
+ CALL_SUBTEST_3( adjoint(Matrix4f()) );
+ CALL_SUBTEST_4( adjoint(MatrixXcf(internal::random<int>(1,EIGEN_TEST_MAX_SIZE/2), internal::random<int>(1,EIGEN_TEST_MAX_SIZE/2))) );
+ CALL_SUBTEST_5( adjoint(MatrixXi(internal::random<int>(1,EIGEN_TEST_MAX_SIZE), internal::random<int>(1,EIGEN_TEST_MAX_SIZE))) );
+ CALL_SUBTEST_6( adjoint(MatrixXf(internal::random<int>(1,EIGEN_TEST_MAX_SIZE), internal::random<int>(1,EIGEN_TEST_MAX_SIZE))) );
+ }
+ // test a large static matrix only once
+ CALL_SUBTEST_7( adjoint(Matrix<float, 100, 100>()) );
+
+#ifdef EIGEN_TEST_PART_4
+ {
+ MatrixXcf a(10,10), b(10,10);
+ VERIFY_RAISES_ASSERT(a = a.transpose());
+ VERIFY_RAISES_ASSERT(a = a.transpose() + b);
+ VERIFY_RAISES_ASSERT(a = b + a.transpose());
+ VERIFY_RAISES_ASSERT(a = a.conjugate().transpose());
+ VERIFY_RAISES_ASSERT(a = a.adjoint());
+ VERIFY_RAISES_ASSERT(a = a.adjoint() + b);
+ VERIFY_RAISES_ASSERT(a = b + a.adjoint());
+
+ // no assertion should be triggered for these cases:
+ a.transpose() = a.transpose();
+ a.transpose() += a.transpose();
+ a.transpose() += a.transpose() + b;
+ a.transpose() = a.adjoint();
+ a.transpose() += a.adjoint();
+ a.transpose() += a.adjoint() + b;
+ }
+#endif
+}
+
diff --git a/test/array.cpp b/test/array.cpp
new file mode 100644
index 000000000..3548fa641
--- /dev/null
+++ b/test/array.cpp
@@ -0,0 +1,303 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra.
+//
+// Copyright (C) 2008-2009 Gael Guennebaud <gael.guennebaud@inria.fr>
+//
+// This Source Code Form is subject to the terms of the Mozilla
+// Public License v. 2.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 "main.h"
+
+template<typename ArrayType> void array(const ArrayType& m)
+{
+ typedef typename ArrayType::Index Index;
+ typedef typename ArrayType::Scalar Scalar;
+ typedef typename NumTraits<Scalar>::Real RealScalar;
+ typedef Array<Scalar, ArrayType::RowsAtCompileTime, 1> ColVectorType;
+ typedef Array<Scalar, 1, ArrayType::ColsAtCompileTime> RowVectorType;
+
+ Index rows = m.rows();
+ Index cols = m.cols();
+
+ ArrayType m1 = ArrayType::Random(rows, cols),
+ m2 = ArrayType::Random(rows, cols),
+ m3(rows, cols);
+
+ ColVectorType cv1 = ColVectorType::Random(rows);
+ RowVectorType rv1 = RowVectorType::Random(cols);
+
+ Scalar s1 = internal::random<Scalar>(),
+ s2 = internal::random<Scalar>();
+
+ // scalar addition
+ VERIFY_IS_APPROX(m1 + s1, s1 + m1);
+ VERIFY_IS_APPROX(m1 + s1, ArrayType::Constant(rows,cols,s1) + m1);
+ VERIFY_IS_APPROX(s1 - m1, (-m1)+s1 );
+ VERIFY_IS_APPROX(m1 - s1, m1 - ArrayType::Constant(rows,cols,s1));
+ VERIFY_IS_APPROX(s1 - m1, ArrayType::Constant(rows,cols,s1) - m1);
+ VERIFY_IS_APPROX((m1*Scalar(2)) - s2, (m1+m1) - ArrayType::Constant(rows,cols,s2) );
+ m3 = m1;
+ m3 += s2;
+ VERIFY_IS_APPROX(m3, m1 + s2);
+ m3 = m1;
+ m3 -= s1;
+ VERIFY_IS_APPROX(m3, m1 - s1);
+
+ // scalar operators via Maps
+ m3 = m1;
+ ArrayType::Map(m1.data(), m1.rows(), m1.cols()) -= ArrayType::Map(m2.data(), m2.rows(), m2.cols());
+ VERIFY_IS_APPROX(m1, m3 - m2);
+
+ m3 = m1;
+ ArrayType::Map(m1.data(), m1.rows(), m1.cols()) += ArrayType::Map(m2.data(), m2.rows(), m2.cols());
+ VERIFY_IS_APPROX(m1, m3 + m2);
+
+ m3 = m1;
+ ArrayType::Map(m1.data(), m1.rows(), m1.cols()) *= ArrayType::Map(m2.data(), m2.rows(), m2.cols());
+ VERIFY_IS_APPROX(m1, m3 * m2);
+
+ m3 = m1;
+ m2 = ArrayType::Random(rows,cols);
+ m2 = (m2==0).select(1,m2);
+ ArrayType::Map(m1.data(), m1.rows(), m1.cols()) /= ArrayType::Map(m2.data(), m2.rows(), m2.cols());
+ VERIFY_IS_APPROX(m1, m3 / m2);
+
+ // reductions
+ VERIFY_IS_APPROX(m1.colwise().sum().sum(), m1.sum());
+ VERIFY_IS_APPROX(m1.rowwise().sum().sum(), m1.sum());
+ if (!internal::isApprox(m1.sum(), (m1+m2).sum(), test_precision<Scalar>()))
+ VERIFY_IS_NOT_APPROX(((m1+m2).rowwise().sum()).sum(), m1.sum());
+ VERIFY_IS_APPROX(m1.colwise().sum(), m1.colwise().redux(internal::scalar_sum_op<Scalar>()));
+
+ // vector-wise ops
+ m3 = m1;
+ VERIFY_IS_APPROX(m3.colwise() += cv1, m1.colwise() + cv1);
+ m3 = m1;
+ VERIFY_IS_APPROX(m3.colwise() -= cv1, m1.colwise() - cv1);
+ m3 = m1;
+ VERIFY_IS_APPROX(m3.rowwise() += rv1, m1.rowwise() + rv1);
+ m3 = m1;
+ VERIFY_IS_APPROX(m3.rowwise() -= rv1, m1.rowwise() - rv1);
+}
+
+template<typename ArrayType> void comparisons(const ArrayType& m)
+{
+ typedef typename ArrayType::Index Index;
+ typedef typename ArrayType::Scalar Scalar;
+ typedef typename NumTraits<Scalar>::Real RealScalar;
+ typedef Array<Scalar, ArrayType::RowsAtCompileTime, 1> VectorType;
+
+ Index rows = m.rows();
+ Index cols = m.cols();
+
+ Index r = internal::random<Index>(0, rows-1),
+ c = internal::random<Index>(0, cols-1);
+
+ ArrayType m1 = ArrayType::Random(rows, cols),
+ m2 = ArrayType::Random(rows, cols),
+ m3(rows, cols);
+
+ VERIFY(((m1 + Scalar(1)) > m1).all());
+ VERIFY(((m1 - Scalar(1)) < m1).all());
+ if (rows*cols>1)
+ {
+ m3 = m1;
+ m3(r,c) += 1;
+ VERIFY(! (m1 < m3).all() );
+ VERIFY(! (m1 > m3).all() );
+ }
+
+ // comparisons to scalar
+ VERIFY( (m1 != (m1(r,c)+1) ).any() );
+ VERIFY( (m1 > (m1(r,c)-1) ).any() );
+ VERIFY( (m1 < (m1(r,c)+1) ).any() );
+ VERIFY( (m1 == m1(r,c) ).any() );
+
+ // test Select
+ VERIFY_IS_APPROX( (m1<m2).select(m1,m2), m1.cwiseMin(m2) );
+ VERIFY_IS_APPROX( (m1>m2).select(m1,m2), m1.cwiseMax(m2) );
+ Scalar mid = (m1.cwiseAbs().minCoeff() + m1.cwiseAbs().maxCoeff())/Scalar(2);
+ for (int j=0; j<cols; ++j)
+ for (int i=0; i<rows; ++i)
+ m3(i,j) = internal::abs(m1(i,j))<mid ? 0 : m1(i,j);
+ VERIFY_IS_APPROX( (m1.abs()<ArrayType::Constant(rows,cols,mid))
+ .select(ArrayType::Zero(rows,cols),m1), m3);
+ // shorter versions:
+ VERIFY_IS_APPROX( (m1.abs()<ArrayType::Constant(rows,cols,mid))
+ .select(0,m1), m3);
+ VERIFY_IS_APPROX( (m1.abs()>=ArrayType::Constant(rows,cols,mid))
+ .select(m1,0), m3);
+ // even shorter version:
+ VERIFY_IS_APPROX( (m1.abs()<mid).select(0,m1), m3);
+
+ // count
+ VERIFY(((m1.abs()+1)>RealScalar(0.1)).count() == rows*cols);
+
+ // and/or
+ VERIFY( (m1<RealScalar(0) && m1>RealScalar(0)).count() == 0);
+ VERIFY( (m1<RealScalar(0) || m1>=RealScalar(0)).count() == rows*cols);
+ RealScalar a = m1.abs().mean();
+ VERIFY( (m1<-a || m1>a).count() == (m1.abs()>a).count());
+
+ typedef Array<typename ArrayType::Index, Dynamic, 1> ArrayOfIndices;
+
+ // TODO allows colwise/rowwise for array
+ VERIFY_IS_APPROX(((m1.abs()+1)>RealScalar(0.1)).colwise().count(), ArrayOfIndices::Constant(cols,rows).transpose());
+ VERIFY_IS_APPROX(((m1.abs()+1)>RealScalar(0.1)).rowwise().count(), ArrayOfIndices::Constant(rows, cols));
+}
+
+template<typename ArrayType> void array_real(const ArrayType& m)
+{
+ typedef typename ArrayType::Index Index;
+ typedef typename ArrayType::Scalar Scalar;
+ typedef typename NumTraits<Scalar>::Real RealScalar;
+
+ Index rows = m.rows();
+ Index cols = m.cols();
+
+ ArrayType m1 = ArrayType::Random(rows, cols),
+ m2 = ArrayType::Random(rows, cols),
+ m3(rows, cols);
+
+ Scalar s1 = internal::random<Scalar>();
+
+ // these tests are mostly to check possible compilation issues.
+ VERIFY_IS_APPROX(m1.sin(), std::sin(m1));
+ VERIFY_IS_APPROX(m1.sin(), internal::sin(m1));
+ VERIFY_IS_APPROX(m1.cos(), std::cos(m1));
+ VERIFY_IS_APPROX(m1.cos(), internal::cos(m1));
+ VERIFY_IS_APPROX(m1.asin(), std::asin(m1));
+ VERIFY_IS_APPROX(m1.asin(), internal::asin(m1));
+ VERIFY_IS_APPROX(m1.acos(), std::acos(m1));
+ VERIFY_IS_APPROX(m1.acos(), internal::acos(m1));
+ VERIFY_IS_APPROX(m1.tan(), std::tan(m1));
+ VERIFY_IS_APPROX(m1.tan(), internal::tan(m1));
+
+ VERIFY_IS_APPROX(internal::cos(m1+RealScalar(3)*m2), internal::cos((m1+RealScalar(3)*m2).eval()));
+ VERIFY_IS_APPROX(std::cos(m1+RealScalar(3)*m2), std::cos((m1+RealScalar(3)*m2).eval()));
+
+ VERIFY_IS_APPROX(m1.abs().sqrt(), std::sqrt(std::abs(m1)));
+ VERIFY_IS_APPROX(m1.abs().sqrt(), internal::sqrt(internal::abs(m1)));
+ VERIFY_IS_APPROX(m1.abs(), internal::sqrt(internal::abs2(m1)));
+
+ VERIFY_IS_APPROX(internal::abs2(internal::real(m1)) + internal::abs2(internal::imag(m1)), internal::abs2(m1));
+ VERIFY_IS_APPROX(internal::abs2(std::real(m1)) + internal::abs2(std::imag(m1)), internal::abs2(m1));
+ if(!NumTraits<Scalar>::IsComplex)
+ VERIFY_IS_APPROX(internal::real(m1), m1);
+
+ VERIFY_IS_APPROX(m1.abs().log(), std::log(std::abs(m1)));
+ VERIFY_IS_APPROX(m1.abs().log(), internal::log(internal::abs(m1)));
+
+ VERIFY_IS_APPROX(m1.exp(), std::exp(m1));
+ VERIFY_IS_APPROX(m1.exp() * m2.exp(), std::exp(m1+m2));
+ VERIFY_IS_APPROX(m1.exp(), internal::exp(m1));
+ VERIFY_IS_APPROX(m1.exp() / m2.exp(), std::exp(m1-m2));
+
+ VERIFY_IS_APPROX(m1.pow(2), m1.square());
+ VERIFY_IS_APPROX(std::pow(m1,2), m1.square());
+
+ ArrayType exponents = ArrayType::Constant(rows, cols, RealScalar(2));
+ VERIFY_IS_APPROX(std::pow(m1,exponents), m1.square());
+
+ m3 = m1.abs();
+ VERIFY_IS_APPROX(m3.pow(RealScalar(0.5)), m3.sqrt());
+ VERIFY_IS_APPROX(std::pow(m3,RealScalar(0.5)), m3.sqrt());
+
+ // scalar by array division
+ const RealScalar tiny = std::sqrt(std::numeric_limits<RealScalar>::epsilon());
+ s1 += Scalar(tiny);
+ m1 += ArrayType::Constant(rows,cols,Scalar(tiny));
+ VERIFY_IS_APPROX(s1/m1, s1 * m1.inverse());
+}
+
+template<typename ArrayType> void array_complex(const ArrayType& m)
+{
+ typedef typename ArrayType::Index Index;
+
+ Index rows = m.rows();
+ Index cols = m.cols();
+
+ ArrayType m1 = ArrayType::Random(rows, cols),
+ m2(rows, cols);
+
+ for (Index i = 0; i < m.rows(); ++i)
+ for (Index j = 0; j < m.cols(); ++j)
+ m2(i,j) = std::sqrt(m1(i,j));
+
+ VERIFY_IS_APPROX(m1.sqrt(), m2);
+ VERIFY_IS_APPROX(m1.sqrt(), std::sqrt(m1));
+ VERIFY_IS_APPROX(m1.sqrt(), internal::sqrt(m1));
+}
+
+template<typename ArrayType> void min_max(const ArrayType& m)
+{
+ typedef typename ArrayType::Index Index;
+ typedef typename ArrayType::Scalar Scalar;
+
+ Index rows = m.rows();
+ Index cols = m.cols();
+
+ ArrayType m1 = ArrayType::Random(rows, cols);
+
+ // min/max with array
+ Scalar maxM1 = m1.maxCoeff();
+ Scalar minM1 = m1.minCoeff();
+
+ VERIFY_IS_APPROX(ArrayType::Constant(rows,cols, minM1), (m1.min)(ArrayType::Constant(rows,cols, minM1)));
+ VERIFY_IS_APPROX(m1, (m1.min)(ArrayType::Constant(rows,cols, maxM1)));
+
+ VERIFY_IS_APPROX(ArrayType::Constant(rows,cols, maxM1), (m1.max)(ArrayType::Constant(rows,cols, maxM1)));
+ VERIFY_IS_APPROX(m1, (m1.max)(ArrayType::Constant(rows,cols, minM1)));
+
+ // min/max with scalar input
+ VERIFY_IS_APPROX(ArrayType::Constant(rows,cols, minM1), (m1.min)( minM1));
+ VERIFY_IS_APPROX(m1, (m1.min)( maxM1));
+
+ VERIFY_IS_APPROX(ArrayType::Constant(rows,cols, maxM1), (m1.max)( maxM1));
+ VERIFY_IS_APPROX(m1, (m1.max)( minM1));
+
+}
+
+void test_array()
+{
+ for(int i = 0; i < g_repeat; i++) {
+ CALL_SUBTEST_1( array(Array<float, 1, 1>()) );
+ CALL_SUBTEST_2( array(Array22f()) );
+ CALL_SUBTEST_3( array(Array44d()) );
+ CALL_SUBTEST_4( array(ArrayXXcf(internal::random<int>(1,EIGEN_TEST_MAX_SIZE), internal::random<int>(1,EIGEN_TEST_MAX_SIZE))) );
+ CALL_SUBTEST_5( array(ArrayXXf(internal::random<int>(1,EIGEN_TEST_MAX_SIZE), internal::random<int>(1,EIGEN_TEST_MAX_SIZE))) );
+ CALL_SUBTEST_6( array(ArrayXXi(internal::random<int>(1,EIGEN_TEST_MAX_SIZE), internal::random<int>(1,EIGEN_TEST_MAX_SIZE))) );
+ }
+ for(int i = 0; i < g_repeat; i++) {
+ CALL_SUBTEST_1( comparisons(Array<float, 1, 1>()) );
+ CALL_SUBTEST_2( comparisons(Array22f()) );
+ CALL_SUBTEST_3( comparisons(Array44d()) );
+ CALL_SUBTEST_5( comparisons(ArrayXXf(internal::random<int>(1,EIGEN_TEST_MAX_SIZE), internal::random<int>(1,EIGEN_TEST_MAX_SIZE))) );
+ CALL_SUBTEST_6( comparisons(ArrayXXi(internal::random<int>(1,EIGEN_TEST_MAX_SIZE), internal::random<int>(1,EIGEN_TEST_MAX_SIZE))) );
+ }
+ for(int i = 0; i < g_repeat; i++) {
+ CALL_SUBTEST_1( min_max(Array<float, 1, 1>()) );
+ CALL_SUBTEST_2( min_max(Array22f()) );
+ CALL_SUBTEST_3( min_max(Array44d()) );
+ CALL_SUBTEST_5( min_max(ArrayXXf(internal::random<int>(1,EIGEN_TEST_MAX_SIZE), internal::random<int>(1,EIGEN_TEST_MAX_SIZE))) );
+ CALL_SUBTEST_6( min_max(ArrayXXi(internal::random<int>(1,EIGEN_TEST_MAX_SIZE), internal::random<int>(1,EIGEN_TEST_MAX_SIZE))) );
+ }
+ for(int i = 0; i < g_repeat; i++) {
+ CALL_SUBTEST_1( array_real(Array<float, 1, 1>()) );
+ CALL_SUBTEST_2( array_real(Array22f()) );
+ CALL_SUBTEST_3( array_real(Array44d()) );
+ CALL_SUBTEST_5( array_real(ArrayXXf(internal::random<int>(1,EIGEN_TEST_MAX_SIZE), internal::random<int>(1,EIGEN_TEST_MAX_SIZE))) );
+ }
+ for(int i = 0; i < g_repeat; i++) {
+ CALL_SUBTEST_4( array_complex(ArrayXXcf(internal::random<int>(1,EIGEN_TEST_MAX_SIZE), internal::random<int>(1,EIGEN_TEST_MAX_SIZE))) );
+ }
+
+ VERIFY((internal::is_same< internal::global_math_functions_filtering_base<int>::type, int >::value));
+ VERIFY((internal::is_same< internal::global_math_functions_filtering_base<float>::type, float >::value));
+ VERIFY((internal::is_same< internal::global_math_functions_filtering_base<Array2i>::type, ArrayBase<Array2i> >::value));
+ typedef CwiseUnaryOp<internal::scalar_sum_op<double>, ArrayXd > Xpr;
+ VERIFY((internal::is_same< internal::global_math_functions_filtering_base<Xpr>::type,
+ ArrayBase<Xpr>
+ >::value));
+}
diff --git a/test/array_for_matrix.cpp b/test/array_for_matrix.cpp
new file mode 100644
index 000000000..4b637c3a6
--- /dev/null
+++ b/test/array_for_matrix.cpp
@@ -0,0 +1,205 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra.
+//
+// Copyright (C) 2008-2009 Gael Guennebaud <gael.guennebaud@inria.fr>
+//
+// This Source Code Form is subject to the terms of the Mozilla
+// Public License v. 2.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 "main.h"
+
+template<typename MatrixType> void array_for_matrix(const MatrixType& m)
+{
+ typedef typename MatrixType::Index Index;
+ typedef typename MatrixType::Scalar Scalar;
+ typedef typename NumTraits<Scalar>::Real RealScalar;
+ typedef Matrix<Scalar, MatrixType::RowsAtCompileTime, 1> ColVectorType;
+ typedef Matrix<Scalar, 1, MatrixType::ColsAtCompileTime> RowVectorType;
+
+ Index rows = m.rows();
+ Index cols = m.cols();
+
+ MatrixType m1 = MatrixType::Random(rows, cols),
+ m2 = MatrixType::Random(rows, cols),
+ m3(rows, cols);
+
+ ColVectorType cv1 = ColVectorType::Random(rows);
+ RowVectorType rv1 = RowVectorType::Random(cols);
+
+ Scalar s1 = internal::random<Scalar>(),
+ s2 = internal::random<Scalar>();
+
+ // scalar addition
+ VERIFY_IS_APPROX(m1.array() + s1, s1 + m1.array());
+ VERIFY_IS_APPROX((m1.array() + s1).matrix(), MatrixType::Constant(rows,cols,s1) + m1);
+ VERIFY_IS_APPROX(((m1*Scalar(2)).array() - s2).matrix(), (m1+m1) - MatrixType::Constant(rows,cols,s2) );
+ m3 = m1;
+ m3.array() += s2;
+ VERIFY_IS_APPROX(m3, (m1.array() + s2).matrix());
+ m3 = m1;
+ m3.array() -= s1;
+ VERIFY_IS_APPROX(m3, (m1.array() - s1).matrix());
+
+ // reductions
+ VERIFY_IS_MUCH_SMALLER_THAN(m1.colwise().sum().sum() - m1.sum(), m1.cwiseAbs().maxCoeff());
+ VERIFY_IS_MUCH_SMALLER_THAN(m1.rowwise().sum().sum() - m1.sum(), m1.cwiseAbs().maxCoeff());
+ VERIFY_IS_MUCH_SMALLER_THAN(m1.colwise().sum() + m2.colwise().sum() - (m1+m2).colwise().sum(), (m1+m2).cwiseAbs().maxCoeff());
+ VERIFY_IS_MUCH_SMALLER_THAN(m1.rowwise().sum() - m2.rowwise().sum() - (m1-m2).rowwise().sum(), (m1-m2).cwiseAbs().maxCoeff());
+ VERIFY_IS_APPROX(m1.colwise().sum(), m1.colwise().redux(internal::scalar_sum_op<Scalar>()));
+
+ // vector-wise ops
+ m3 = m1;
+ VERIFY_IS_APPROX(m3.colwise() += cv1, m1.colwise() + cv1);
+ m3 = m1;
+ VERIFY_IS_APPROX(m3.colwise() -= cv1, m1.colwise() - cv1);
+ m3 = m1;
+ VERIFY_IS_APPROX(m3.rowwise() += rv1, m1.rowwise() + rv1);
+ m3 = m1;
+ VERIFY_IS_APPROX(m3.rowwise() -= rv1, m1.rowwise() - rv1);
+
+ // empty objects
+ VERIFY_IS_APPROX(m1.block(0,0,0,cols).colwise().sum(), RowVectorType::Zero(cols));
+ VERIFY_IS_APPROX(m1.block(0,0,rows,0).rowwise().prod(), ColVectorType::Ones(rows));
+
+ // verify the const accessors exist
+ const Scalar& ref_m1 = m.matrix().array().coeffRef(0);
+ const Scalar& ref_m2 = m.matrix().array().coeffRef(0,0);
+ const Scalar& ref_a1 = m.array().matrix().coeffRef(0);
+ const Scalar& ref_a2 = m.array().matrix().coeffRef(0,0);
+ VERIFY(&ref_a1 == &ref_m1);
+ VERIFY(&ref_a2 == &ref_m2);
+}
+
+template<typename MatrixType> void comparisons(const MatrixType& m)
+{
+ typedef typename MatrixType::Index Index;
+ typedef typename MatrixType::Scalar Scalar;
+ typedef typename NumTraits<Scalar>::Real RealScalar;
+ typedef Matrix<Scalar, MatrixType::RowsAtCompileTime, 1> VectorType;
+
+ Index rows = m.rows();
+ Index cols = m.cols();
+
+ Index r = internal::random<Index>(0, rows-1),
+ c = internal::random<Index>(0, cols-1);
+
+ MatrixType m1 = MatrixType::Random(rows, cols),
+ m2 = MatrixType::Random(rows, cols),
+ m3(rows, cols);
+
+ VERIFY(((m1.array() + Scalar(1)) > m1.array()).all());
+ VERIFY(((m1.array() - Scalar(1)) < m1.array()).all());
+ if (rows*cols>1)
+ {
+ m3 = m1;
+ m3(r,c) += 1;
+ VERIFY(! (m1.array() < m3.array()).all() );
+ VERIFY(! (m1.array() > m3.array()).all() );
+ }
+
+ // comparisons to scalar
+ VERIFY( (m1.array() != (m1(r,c)+1) ).any() );
+ VERIFY( (m1.array() > (m1(r,c)-1) ).any() );
+ VERIFY( (m1.array() < (m1(r,c)+1) ).any() );
+ VERIFY( (m1.array() == m1(r,c) ).any() );
+
+ // test Select
+ VERIFY_IS_APPROX( (m1.array()<m2.array()).select(m1,m2), m1.cwiseMin(m2) );
+ VERIFY_IS_APPROX( (m1.array()>m2.array()).select(m1,m2), m1.cwiseMax(m2) );
+ Scalar mid = (m1.cwiseAbs().minCoeff() + m1.cwiseAbs().maxCoeff())/Scalar(2);
+ for (int j=0; j<cols; ++j)
+ for (int i=0; i<rows; ++i)
+ m3(i,j) = internal::abs(m1(i,j))<mid ? 0 : m1(i,j);
+ VERIFY_IS_APPROX( (m1.array().abs()<MatrixType::Constant(rows,cols,mid).array())
+ .select(MatrixType::Zero(rows,cols),m1), m3);
+ // shorter versions:
+ VERIFY_IS_APPROX( (m1.array().abs()<MatrixType::Constant(rows,cols,mid).array())
+ .select(0,m1), m3);
+ VERIFY_IS_APPROX( (m1.array().abs()>=MatrixType::Constant(rows,cols,mid).array())
+ .select(m1,0), m3);
+ // even shorter version:
+ VERIFY_IS_APPROX( (m1.array().abs()<mid).select(0,m1), m3);
+
+ // count
+ VERIFY(((m1.array().abs()+1)>RealScalar(0.1)).count() == rows*cols);
+
+ typedef Matrix<typename MatrixType::Index, Dynamic, 1> VectorOfIndices;
+
+ // TODO allows colwise/rowwise for array
+ VERIFY_IS_APPROX(((m1.array().abs()+1)>RealScalar(0.1)).matrix().colwise().count(), VectorOfIndices::Constant(cols,rows).transpose());
+ VERIFY_IS_APPROX(((m1.array().abs()+1)>RealScalar(0.1)).matrix().rowwise().count(), VectorOfIndices::Constant(rows, cols));
+}
+
+template<typename VectorType> void lpNorm(const VectorType& v)
+{
+ VectorType u = VectorType::Random(v.size());
+
+ VERIFY_IS_APPROX(u.template lpNorm<Infinity>(), u.cwiseAbs().maxCoeff());
+ VERIFY_IS_APPROX(u.template lpNorm<1>(), u.cwiseAbs().sum());
+ VERIFY_IS_APPROX(u.template lpNorm<2>(), internal::sqrt(u.array().abs().square().sum()));
+ VERIFY_IS_APPROX(internal::pow(u.template lpNorm<5>(), typename VectorType::RealScalar(5)), u.array().abs().pow(5).sum());
+}
+
+template<typename MatrixType> void cwise_min_max(const MatrixType& m)
+{
+ typedef typename MatrixType::Index Index;
+ typedef typename MatrixType::Scalar Scalar;
+
+ Index rows = m.rows();
+ Index cols = m.cols();
+
+ MatrixType m1 = MatrixType::Random(rows, cols);
+
+ // min/max with array
+ Scalar maxM1 = m1.maxCoeff();
+ Scalar minM1 = m1.minCoeff();
+
+ VERIFY_IS_APPROX(MatrixType::Constant(rows,cols, minM1), m1.cwiseMin(MatrixType::Constant(rows,cols, minM1)));
+ VERIFY_IS_APPROX(m1, m1.cwiseMin(MatrixType::Constant(rows,cols, maxM1)));
+
+ VERIFY_IS_APPROX(MatrixType::Constant(rows,cols, maxM1), m1.cwiseMax(MatrixType::Constant(rows,cols, maxM1)));
+ VERIFY_IS_APPROX(m1, m1.cwiseMax(MatrixType::Constant(rows,cols, minM1)));
+
+ // min/max with scalar input
+ VERIFY_IS_APPROX(MatrixType::Constant(rows,cols, minM1), m1.cwiseMin( minM1));
+ VERIFY_IS_APPROX(m1, m1.cwiseMin( maxM1));
+
+ VERIFY_IS_APPROX(MatrixType::Constant(rows,cols, maxM1), m1.cwiseMax( maxM1));
+ VERIFY_IS_APPROX(m1, m1.cwiseMax( minM1));
+
+}
+
+void test_array_for_matrix()
+{
+ for(int i = 0; i < g_repeat; i++) {
+ CALL_SUBTEST_1( array_for_matrix(Matrix<float, 1, 1>()) );
+ CALL_SUBTEST_2( array_for_matrix(Matrix2f()) );
+ CALL_SUBTEST_3( array_for_matrix(Matrix4d()) );
+ CALL_SUBTEST_4( array_for_matrix(MatrixXcf(internal::random<int>(1,EIGEN_TEST_MAX_SIZE), internal::random<int>(1,EIGEN_TEST_MAX_SIZE))) );
+ CALL_SUBTEST_5( array_for_matrix(MatrixXf(internal::random<int>(1,EIGEN_TEST_MAX_SIZE), internal::random<int>(1,EIGEN_TEST_MAX_SIZE))) );
+ CALL_SUBTEST_6( array_for_matrix(MatrixXi(internal::random<int>(1,EIGEN_TEST_MAX_SIZE), internal::random<int>(1,EIGEN_TEST_MAX_SIZE))) );
+ }
+ for(int i = 0; i < g_repeat; i++) {
+ CALL_SUBTEST_1( comparisons(Matrix<float, 1, 1>()) );
+ CALL_SUBTEST_2( comparisons(Matrix2f()) );
+ CALL_SUBTEST_3( comparisons(Matrix4d()) );
+ CALL_SUBTEST_5( comparisons(MatrixXf(internal::random<int>(1,EIGEN_TEST_MAX_SIZE), internal::random<int>(1,EIGEN_TEST_MAX_SIZE))) );
+ CALL_SUBTEST_6( comparisons(MatrixXi(internal::random<int>(1,EIGEN_TEST_MAX_SIZE), internal::random<int>(1,EIGEN_TEST_MAX_SIZE))) );
+ }
+ for(int i = 0; i < g_repeat; i++) {
+ CALL_SUBTEST_1( cwise_min_max(Matrix<float, 1, 1>()) );
+ CALL_SUBTEST_2( cwise_min_max(Matrix2f()) );
+ CALL_SUBTEST_3( cwise_min_max(Matrix4d()) );
+ CALL_SUBTEST_5( cwise_min_max(MatrixXf(internal::random<int>(1,EIGEN_TEST_MAX_SIZE), internal::random<int>(1,EIGEN_TEST_MAX_SIZE))) );
+ CALL_SUBTEST_6( cwise_min_max(MatrixXi(internal::random<int>(1,EIGEN_TEST_MAX_SIZE), internal::random<int>(1,EIGEN_TEST_MAX_SIZE))) );
+ }
+ for(int i = 0; i < g_repeat; i++) {
+ CALL_SUBTEST_1( lpNorm(Matrix<float, 1, 1>()) );
+ CALL_SUBTEST_2( lpNorm(Vector2f()) );
+ CALL_SUBTEST_7( lpNorm(Vector3d()) );
+ CALL_SUBTEST_8( lpNorm(Vector4f()) );
+ CALL_SUBTEST_5( lpNorm(VectorXf(internal::random<int>(1,EIGEN_TEST_MAX_SIZE))) );
+ CALL_SUBTEST_4( lpNorm(VectorXcf(internal::random<int>(1,EIGEN_TEST_MAX_SIZE))) );
+ }
+}
diff --git a/test/array_replicate.cpp b/test/array_replicate.cpp
new file mode 100644
index 000000000..94da7425b
--- /dev/null
+++ b/test/array_replicate.cpp
@@ -0,0 +1,70 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra.
+//
+// Copyright (C) 2009 Gael Guennebaud <gael.guennebaud@inria.fr>
+//
+// This Source Code Form is subject to the terms of the Mozilla
+// Public License v. 2.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 "main.h"
+
+template<typename MatrixType> void replicate(const MatrixType& m)
+{
+ /* this test covers the following files:
+ Replicate.cpp
+ */
+ typedef typename MatrixType::Index Index;
+ typedef typename MatrixType::Scalar Scalar;
+ typedef typename NumTraits<Scalar>::Real RealScalar;
+ typedef Matrix<Scalar, MatrixType::RowsAtCompileTime, 1> VectorType;
+ typedef Matrix<Scalar, Dynamic, Dynamic> MatrixX;
+ typedef Matrix<Scalar, Dynamic, 1> VectorX;
+
+ Index rows = m.rows();
+ Index cols = m.cols();
+
+ MatrixType m1 = MatrixType::Random(rows, cols),
+ m2 = MatrixType::Random(rows, cols);
+
+ VectorType v1 = VectorType::Random(rows);
+
+ MatrixX x1, x2;
+ VectorX vx1;
+
+ int f1 = internal::random<int>(1,10),
+ f2 = internal::random<int>(1,10);
+
+ x1.resize(rows*f1,cols*f2);
+ for(int j=0; j<f2; j++)
+ for(int i=0; i<f1; i++)
+ x1.block(i*rows,j*cols,rows,cols) = m1;
+ VERIFY_IS_APPROX(x1, m1.replicate(f1,f2));
+
+ x2.resize(2*rows,3*cols);
+ x2 << m2, m2, m2,
+ m2, m2, m2;
+ VERIFY_IS_APPROX(x2, (m2.template replicate<2,3>()));
+
+ x2.resize(rows,f1);
+ for (int j=0; j<f1; ++j)
+ x2.col(j) = v1;
+ VERIFY_IS_APPROX(x2, v1.rowwise().replicate(f1));
+
+ vx1.resize(rows*f2);
+ for (int j=0; j<f2; ++j)
+ vx1.segment(j*rows,rows) = v1;
+ VERIFY_IS_APPROX(vx1, v1.colwise().replicate(f2));
+}
+
+void test_array_replicate()
+{
+ for(int i = 0; i < g_repeat; i++) {
+ CALL_SUBTEST_1( replicate(Matrix<float, 1, 1>()) );
+ CALL_SUBTEST_2( replicate(Vector2f()) );
+ CALL_SUBTEST_3( replicate(Vector3d()) );
+ CALL_SUBTEST_4( replicate(Vector4f()) );
+ CALL_SUBTEST_5( replicate(VectorXf(16)) );
+ CALL_SUBTEST_6( replicate(VectorXcd(10)) );
+ }
+}
diff --git a/test/array_reverse.cpp b/test/array_reverse.cpp
new file mode 100644
index 000000000..fbe7a9901
--- /dev/null
+++ b/test/array_reverse.cpp
@@ -0,0 +1,128 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra.
+//
+// Copyright (C) 2006-2008 Benoit Jacob <jacob.benoit.1@gmail.com>
+// Copyright (C) 2009 Ricard Marxer <email@ricardmarxer.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 "main.h"
+#include <iostream>
+
+using namespace std;
+
+template<typename MatrixType> void reverse(const MatrixType& m)
+{
+ typedef typename MatrixType::Index Index;
+ typedef typename MatrixType::Scalar Scalar;
+ typedef Matrix<Scalar, MatrixType::RowsAtCompileTime, 1> VectorType;
+
+ Index rows = m.rows();
+ Index cols = m.cols();
+
+ // this test relies a lot on Random.h, and there's not much more that we can do
+ // to test it, hence I consider that we will have tested Random.h
+ MatrixType m1 = MatrixType::Random(rows, cols);
+ VectorType v1 = VectorType::Random(rows);
+
+ MatrixType m1_r = m1.reverse();
+ // Verify that MatrixBase::reverse() works
+ for ( int i = 0; i < rows; i++ ) {
+ for ( int j = 0; j < cols; j++ ) {
+ VERIFY_IS_APPROX(m1_r(i, j), m1(rows - 1 - i, cols - 1 - j));
+ }
+ }
+
+ Reverse<MatrixType> m1_rd(m1);
+ // Verify that a Reverse default (in both directions) of an expression works
+ for ( int i = 0; i < rows; i++ ) {
+ for ( int j = 0; j < cols; j++ ) {
+ VERIFY_IS_APPROX(m1_rd(i, j), m1(rows - 1 - i, cols - 1 - j));
+ }
+ }
+
+ Reverse<MatrixType, BothDirections> m1_rb(m1);
+ // Verify that a Reverse in both directions of an expression works
+ for ( int i = 0; i < rows; i++ ) {
+ for ( int j = 0; j < cols; j++ ) {
+ VERIFY_IS_APPROX(m1_rb(i, j), m1(rows - 1 - i, cols - 1 - j));
+ }
+ }
+
+ Reverse<MatrixType, Vertical> m1_rv(m1);
+ // Verify that a Reverse in the vertical directions of an expression works
+ for ( int i = 0; i < rows; i++ ) {
+ for ( int j = 0; j < cols; j++ ) {
+ VERIFY_IS_APPROX(m1_rv(i, j), m1(rows - 1 - i, j));
+ }
+ }
+
+ Reverse<MatrixType, Horizontal> m1_rh(m1);
+ // Verify that a Reverse in the horizontal directions of an expression works
+ for ( int i = 0; i < rows; i++ ) {
+ for ( int j = 0; j < cols; j++ ) {
+ VERIFY_IS_APPROX(m1_rh(i, j), m1(i, cols - 1 - j));
+ }
+ }
+
+ VectorType v1_r = v1.reverse();
+ // Verify that a VectorType::reverse() of an expression works
+ for ( int i = 0; i < rows; i++ ) {
+ VERIFY_IS_APPROX(v1_r(i), v1(rows - 1 - i));
+ }
+
+ MatrixType m1_cr = m1.colwise().reverse();
+ // Verify that PartialRedux::reverse() works (for colwise())
+ for ( int i = 0; i < rows; i++ ) {
+ for ( int j = 0; j < cols; j++ ) {
+ VERIFY_IS_APPROX(m1_cr(i, j), m1(rows - 1 - i, j));
+ }
+ }
+
+ MatrixType m1_rr = m1.rowwise().reverse();
+ // Verify that PartialRedux::reverse() works (for rowwise())
+ for ( int i = 0; i < rows; i++ ) {
+ for ( int j = 0; j < cols; j++ ) {
+ VERIFY_IS_APPROX(m1_rr(i, j), m1(i, cols - 1 - j));
+ }
+ }
+
+ Scalar x = internal::random<Scalar>();
+
+ Index r = internal::random<Index>(0, rows-1),
+ c = internal::random<Index>(0, cols-1);
+
+ m1.reverse()(r, c) = x;
+ VERIFY_IS_APPROX(x, m1(rows - 1 - r, cols - 1 - c));
+
+ /*
+ m1.colwise().reverse()(r, c) = x;
+ VERIFY_IS_APPROX(x, m1(rows - 1 - r, c));
+
+ m1.rowwise().reverse()(r, c) = x;
+ VERIFY_IS_APPROX(x, m1(r, cols - 1 - c));
+ */
+}
+
+void test_array_reverse()
+{
+ for(int i = 0; i < g_repeat; i++) {
+ CALL_SUBTEST_1( reverse(Matrix<float, 1, 1>()) );
+ CALL_SUBTEST_2( reverse(Matrix2f()) );
+ CALL_SUBTEST_3( reverse(Matrix4f()) );
+ CALL_SUBTEST_4( reverse(Matrix4d()) );
+ CALL_SUBTEST_5( reverse(MatrixXcf(3, 3)) );
+ CALL_SUBTEST_6( reverse(MatrixXi(6, 3)) );
+ CALL_SUBTEST_7( reverse(MatrixXcd(20, 20)) );
+ CALL_SUBTEST_8( reverse(Matrix<float, 100, 100>()) );
+ CALL_SUBTEST_9( reverse(Matrix<float,Dynamic,Dynamic,RowMajor>(6,3)) );
+ }
+#ifdef EIGEN_TEST_PART_3
+ Vector4f x; x << 1, 2, 3, 4;
+ Vector4f y; y << 4, 3, 2, 1;
+ VERIFY(x.reverse()[1] == 3);
+ VERIFY(x.reverse() == y);
+#endif
+}
diff --git a/test/bandmatrix.cpp b/test/bandmatrix.cpp
new file mode 100644
index 000000000..5e4e8e07b
--- /dev/null
+++ b/test/bandmatrix.cpp
@@ -0,0 +1,74 @@
+// This file is triangularView of Eigen, a lightweight C++ template library
+// for linear algebra.
+//
+// Copyright (C) 2008-2009 Gael Guennebaud <gael.guennebaud@inria.fr>
+//
+// This Source Code Form is subject to the terms of the Mozilla
+// Public License v. 2.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 "main.h"
+
+template<typename MatrixType> void bandmatrix(const MatrixType& _m)
+{
+ typedef typename MatrixType::Index Index;
+ typedef typename MatrixType::Scalar Scalar;
+ typedef typename NumTraits<Scalar>::Real RealScalar;
+ typedef Matrix<Scalar,Dynamic,Dynamic> DenseMatrixType;
+
+ Index rows = _m.rows();
+ Index cols = _m.cols();
+ Index supers = _m.supers();
+ Index subs = _m.subs();
+
+ MatrixType m(rows,cols,supers,subs);
+
+ DenseMatrixType dm1(rows,cols);
+ dm1.setZero();
+
+ m.diagonal().setConstant(123);
+ dm1.diagonal().setConstant(123);
+ for (int i=1; i<=m.supers();++i)
+ {
+ m.diagonal(i).setConstant(static_cast<RealScalar>(i));
+ dm1.diagonal(i).setConstant(static_cast<RealScalar>(i));
+ }
+ for (int i=1; i<=m.subs();++i)
+ {
+ m.diagonal(-i).setConstant(-static_cast<RealScalar>(i));
+ dm1.diagonal(-i).setConstant(-static_cast<RealScalar>(i));
+ }
+ //std::cerr << m.m_data << "\n\n" << m.toDense() << "\n\n" << dm1 << "\n\n\n\n";
+ VERIFY_IS_APPROX(dm1,m.toDenseMatrix());
+
+ for (int i=0; i<cols; ++i)
+ {
+ m.col(i).setConstant(static_cast<RealScalar>(i+1));
+ dm1.col(i).setConstant(static_cast<RealScalar>(i+1));
+ }
+ Index d = (std::min)(rows,cols);
+ Index a = std::max<Index>(0,cols-d-supers);
+ Index b = std::max<Index>(0,rows-d-subs);
+ if(a>0) dm1.block(0,d+supers,rows,a).setZero();
+ dm1.block(0,supers+1,cols-supers-1-a,cols-supers-1-a).template triangularView<Upper>().setZero();
+ dm1.block(subs+1,0,rows-subs-1-b,rows-subs-1-b).template triangularView<Lower>().setZero();
+ if(b>0) dm1.block(d+subs,0,b,cols).setZero();
+ //std::cerr << m.m_data << "\n\n" << m.toDense() << "\n\n" << dm1 << "\n\n";
+ VERIFY_IS_APPROX(dm1,m.toDenseMatrix());
+
+}
+
+using Eigen::internal::BandMatrix;
+
+void test_bandmatrix()
+{
+ typedef BandMatrix<float>::Index Index;
+
+ for(int i = 0; i < 10*g_repeat ; i++) {
+ Index rows = internal::random<Index>(1,10);
+ Index cols = internal::random<Index>(1,10);
+ Index sups = internal::random<Index>(0,cols-1);
+ Index subs = internal::random<Index>(0,rows-1);
+ CALL_SUBTEST(bandmatrix(BandMatrix<float>(rows,cols,sups,subs)) );
+ }
+}
diff --git a/test/basicstuff.cpp b/test/basicstuff.cpp
new file mode 100644
index 000000000..48db531c1
--- /dev/null
+++ b/test/basicstuff.cpp
@@ -0,0 +1,215 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra.
+//
+// Copyright (C) 2006-2008 Benoit Jacob <jacob.benoit.1@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/.
+
+#define EIGEN_NO_STATIC_ASSERT
+
+#include "main.h"
+
+template<typename MatrixType> void basicStuff(const MatrixType& m)
+{
+ typedef typename MatrixType::Index Index;
+ typedef typename MatrixType::Scalar Scalar;
+ typedef Matrix<Scalar, MatrixType::RowsAtCompileTime, 1> VectorType;
+ typedef Matrix<Scalar, MatrixType::RowsAtCompileTime, MatrixType::RowsAtCompileTime> SquareMatrixType;
+
+ Index rows = m.rows();
+ Index cols = m.cols();
+
+ // this test relies a lot on Random.h, and there's not much more that we can do
+ // to test it, hence I consider that we will have tested Random.h
+ MatrixType m1 = MatrixType::Random(rows, cols),
+ m2 = MatrixType::Random(rows, cols),
+ m3(rows, cols),
+ mzero = MatrixType::Zero(rows, cols),
+ square = Matrix<Scalar, MatrixType::RowsAtCompileTime, MatrixType::RowsAtCompileTime>::Random(rows, rows);
+ VectorType v1 = VectorType::Random(rows),
+ vzero = VectorType::Zero(rows);
+ SquareMatrixType sm1 = SquareMatrixType::Random(rows,rows), sm2(rows,rows);
+
+ Scalar x = 0;
+ while(x == Scalar(0)) x = internal::random<Scalar>();
+
+ Index r = internal::random<Index>(0, rows-1),
+ c = internal::random<Index>(0, cols-1);
+
+ m1.coeffRef(r,c) = x;
+ VERIFY_IS_APPROX(x, m1.coeff(r,c));
+ m1(r,c) = x;
+ VERIFY_IS_APPROX(x, m1(r,c));
+ v1.coeffRef(r) = x;
+ VERIFY_IS_APPROX(x, v1.coeff(r));
+ v1(r) = x;
+ VERIFY_IS_APPROX(x, v1(r));
+ v1[r] = x;
+ VERIFY_IS_APPROX(x, v1[r]);
+
+ VERIFY_IS_APPROX( v1, v1);
+ VERIFY_IS_NOT_APPROX( v1, 2*v1);
+ VERIFY_IS_MUCH_SMALLER_THAN( vzero, v1);
+ if(!NumTraits<Scalar>::IsInteger)
+ VERIFY_IS_MUCH_SMALLER_THAN( vzero, v1.norm());
+ VERIFY_IS_NOT_MUCH_SMALLER_THAN(v1, v1);
+ VERIFY_IS_APPROX( vzero, v1-v1);
+ VERIFY_IS_APPROX( m1, m1);
+ VERIFY_IS_NOT_APPROX( m1, 2*m1);
+ VERIFY_IS_MUCH_SMALLER_THAN( mzero, m1);
+ VERIFY_IS_NOT_MUCH_SMALLER_THAN(m1, m1);
+ VERIFY_IS_APPROX( mzero, m1-m1);
+
+ // always test operator() on each read-only expression class,
+ // in order to check const-qualifiers.
+ // indeed, if an expression class (here Zero) is meant to be read-only,
+ // hence has no _write() method, the corresponding MatrixBase method (here zero())
+ // should return a const-qualified object so that it is the const-qualified
+ // operator() that gets called, which in turn calls _read().
+ VERIFY_IS_MUCH_SMALLER_THAN(MatrixType::Zero(rows,cols)(r,c), static_cast<Scalar>(1));
+
+ // now test copying a row-vector into a (column-)vector and conversely.
+ square.col(r) = square.row(r).eval();
+ Matrix<Scalar, 1, MatrixType::RowsAtCompileTime> rv(rows);
+ Matrix<Scalar, MatrixType::RowsAtCompileTime, 1> cv(rows);
+ rv = square.row(r);
+ cv = square.col(r);
+
+ VERIFY_IS_APPROX(rv, cv.transpose());
+
+ if(cols!=1 && rows!=1 && MatrixType::SizeAtCompileTime!=Dynamic)
+ {
+ VERIFY_RAISES_ASSERT(m1 = (m2.block(0,0, rows-1, cols-1)));
+ }
+
+ if(cols!=1 && rows!=1)
+ {
+ VERIFY_RAISES_ASSERT(m1[0]);
+ VERIFY_RAISES_ASSERT((m1+m1)[0]);
+ }
+
+ VERIFY_IS_APPROX(m3 = m1,m1);
+ MatrixType m4;
+ VERIFY_IS_APPROX(m4 = m1,m1);
+
+ m3.real() = m1.real();
+ VERIFY_IS_APPROX(static_cast<const MatrixType&>(m3).real(), static_cast<const MatrixType&>(m1).real());
+ VERIFY_IS_APPROX(static_cast<const MatrixType&>(m3).real(), m1.real());
+
+ // check == / != operators
+ VERIFY(m1==m1);
+ VERIFY(m1!=m2);
+ VERIFY(!(m1==m2));
+ VERIFY(!(m1!=m1));
+ m1 = m2;
+ VERIFY(m1==m2);
+ VERIFY(!(m1!=m2));
+
+ // check automatic transposition
+ sm2.setZero();
+ for(typename MatrixType::Index i=0;i<rows;++i)
+ sm2.col(i) = sm1.row(i);
+ VERIFY_IS_APPROX(sm2,sm1.transpose());
+
+ sm2.setZero();
+ for(typename MatrixType::Index i=0;i<rows;++i)
+ sm2.col(i).noalias() = sm1.row(i);
+ VERIFY_IS_APPROX(sm2,sm1.transpose());
+
+ sm2.setZero();
+ for(typename MatrixType::Index i=0;i<rows;++i)
+ sm2.col(i).noalias() += sm1.row(i);
+ VERIFY_IS_APPROX(sm2,sm1.transpose());
+
+ sm2.setZero();
+ for(typename MatrixType::Index i=0;i<rows;++i)
+ sm2.col(i).noalias() -= sm1.row(i);
+ VERIFY_IS_APPROX(sm2,-sm1.transpose());
+}
+
+template<typename MatrixType> void basicStuffComplex(const MatrixType& m)
+{
+ typedef typename MatrixType::Index Index;
+ typedef typename MatrixType::Scalar Scalar;
+ typedef typename NumTraits<Scalar>::Real RealScalar;
+ typedef Matrix<RealScalar, MatrixType::RowsAtCompileTime, MatrixType::ColsAtCompileTime> RealMatrixType;
+
+ Index rows = m.rows();
+ Index cols = m.cols();
+
+ Scalar s1 = internal::random<Scalar>(),
+ s2 = internal::random<Scalar>();
+
+ VERIFY(internal::real(s1)==internal::real_ref(s1));
+ VERIFY(internal::imag(s1)==internal::imag_ref(s1));
+ internal::real_ref(s1) = internal::real(s2);
+ internal::imag_ref(s1) = internal::imag(s2);
+ VERIFY(internal::isApprox(s1, s2, NumTraits<RealScalar>::epsilon()));
+ // extended precision in Intel FPUs means that s1 == s2 in the line above is not guaranteed.
+
+ RealMatrixType rm1 = RealMatrixType::Random(rows,cols),
+ rm2 = RealMatrixType::Random(rows,cols);
+ MatrixType cm(rows,cols);
+ cm.real() = rm1;
+ cm.imag() = rm2;
+ VERIFY_IS_APPROX(static_cast<const MatrixType&>(cm).real(), rm1);
+ VERIFY_IS_APPROX(static_cast<const MatrixType&>(cm).imag(), rm2);
+ rm1.setZero();
+ rm2.setZero();
+ rm1 = cm.real();
+ rm2 = cm.imag();
+ VERIFY_IS_APPROX(static_cast<const MatrixType&>(cm).real(), rm1);
+ VERIFY_IS_APPROX(static_cast<const MatrixType&>(cm).imag(), rm2);
+ cm.real().setZero();
+ VERIFY(static_cast<const MatrixType&>(cm).real().isZero());
+ VERIFY(!static_cast<const MatrixType&>(cm).imag().isZero());
+}
+
+#ifdef EIGEN_TEST_PART_2
+void casting()
+{
+ Matrix4f m = Matrix4f::Random(), m2;
+ Matrix4d n = m.cast<double>();
+ VERIFY(m.isApprox(n.cast<float>()));
+ m2 = m.cast<float>(); // check the specialization when NewType == Type
+ VERIFY(m.isApprox(m2));
+}
+#endif
+
+template <typename Scalar>
+void fixedSizeMatrixConstruction()
+{
+ const Scalar raw[3] = {1,2,3};
+ Matrix<Scalar,3,1> m(raw);
+ Array<Scalar,3,1> a(raw);
+ VERIFY(m(0) == 1);
+ VERIFY(m(1) == 2);
+ VERIFY(m(2) == 3);
+ VERIFY(a(0) == 1);
+ VERIFY(a(1) == 2);
+ VERIFY(a(2) == 3);
+}
+
+void test_basicstuff()
+{
+ for(int i = 0; i < g_repeat; i++) {
+ CALL_SUBTEST_1( basicStuff(Matrix<float, 1, 1>()) );
+ CALL_SUBTEST_2( basicStuff(Matrix4d()) );
+ CALL_SUBTEST_3( basicStuff(MatrixXcf(internal::random<int>(1,EIGEN_TEST_MAX_SIZE), internal::random<int>(1,EIGEN_TEST_MAX_SIZE))) );
+ CALL_SUBTEST_4( basicStuff(MatrixXi(internal::random<int>(1,EIGEN_TEST_MAX_SIZE), internal::random<int>(1,EIGEN_TEST_MAX_SIZE))) );
+ CALL_SUBTEST_5( basicStuff(MatrixXcd(internal::random<int>(1,EIGEN_TEST_MAX_SIZE), internal::random<int>(1,EIGEN_TEST_MAX_SIZE))) );
+ CALL_SUBTEST_6( basicStuff(Matrix<float, 100, 100>()) );
+ CALL_SUBTEST_7( basicStuff(Matrix<long double,Dynamic,Dynamic>(internal::random<int>(1,EIGEN_TEST_MAX_SIZE),internal::random<int>(1,EIGEN_TEST_MAX_SIZE))) );
+
+ CALL_SUBTEST_3( basicStuffComplex(MatrixXcf(internal::random<int>(1,EIGEN_TEST_MAX_SIZE), internal::random<int>(1,EIGEN_TEST_MAX_SIZE))) );
+ CALL_SUBTEST_5( basicStuffComplex(MatrixXcd(internal::random<int>(1,EIGEN_TEST_MAX_SIZE), internal::random<int>(1,EIGEN_TEST_MAX_SIZE))) );
+ }
+
+ CALL_SUBTEST_1(fixedSizeMatrixConstruction<unsigned char>());
+ CALL_SUBTEST_1(fixedSizeMatrixConstruction<double>());
+ CALL_SUBTEST_1(fixedSizeMatrixConstruction<double>());
+
+ CALL_SUBTEST_2(casting());
+}
diff --git a/test/bicgstab.cpp b/test/bicgstab.cpp
new file mode 100644
index 000000000..f327e2fac
--- /dev/null
+++ b/test/bicgstab.cpp
@@ -0,0 +1,30 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra.
+//
+// Copyright (C) 2011 Gael Guennebaud <g.gael@free.fr>
+//
+// This Source Code Form is subject to the terms of the Mozilla
+// Public License v. 2.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 "sparse_solver.h"
+#include <Eigen/IterativeLinearSolvers>
+
+template<typename T> void test_bicgstab_T()
+{
+ BiCGSTAB<SparseMatrix<T>, DiagonalPreconditioner<T> > bicgstab_colmajor_diag;
+ BiCGSTAB<SparseMatrix<T>, IdentityPreconditioner > bicgstab_colmajor_I;
+ BiCGSTAB<SparseMatrix<T>, IncompleteLUT<T> > bicgstab_colmajor_ilut;
+ //BiCGSTAB<SparseMatrix<T>, SSORPreconditioner<T> > bicgstab_colmajor_ssor;
+
+ CALL_SUBTEST( check_sparse_square_solving(bicgstab_colmajor_diag) );
+// CALL_SUBTEST( check_sparse_square_solving(bicgstab_colmajor_I) );
+ CALL_SUBTEST( check_sparse_square_solving(bicgstab_colmajor_ilut) );
+ //CALL_SUBTEST( check_sparse_square_solving(bicgstab_colmajor_ssor) );
+}
+
+void test_bicgstab()
+{
+ CALL_SUBTEST_1(test_bicgstab_T<double>());
+ CALL_SUBTEST_2(test_bicgstab_T<std::complex<double> >());
+}
diff --git a/test/block.cpp b/test/block.cpp
new file mode 100644
index 000000000..0969262ca
--- /dev/null
+++ b/test/block.cpp
@@ -0,0 +1,222 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra.
+//
+// Copyright (C) 2006-2010 Benoit Jacob <jacob.benoit.1@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/.
+
+#define EIGEN_NO_STATIC_ASSERT // otherwise we fail at compile time on unused paths
+#include "main.h"
+
+template<typename MatrixType> void block(const MatrixType& m)
+{
+ typedef typename MatrixType::Index Index;
+ typedef typename MatrixType::Scalar Scalar;
+ typedef typename MatrixType::RealScalar RealScalar;
+ typedef Matrix<Scalar, MatrixType::RowsAtCompileTime, 1> VectorType;
+ typedef Matrix<Scalar, 1, MatrixType::ColsAtCompileTime> RowVectorType;
+ typedef Matrix<Scalar, Dynamic, Dynamic> DynamicMatrixType;
+ typedef Matrix<Scalar, Dynamic, 1> DynamicVectorType;
+
+ Index rows = m.rows();
+ Index cols = m.cols();
+
+ MatrixType m1 = MatrixType::Random(rows, cols),
+ m1_copy = m1,
+ m2 = MatrixType::Random(rows, cols),
+ m3(rows, cols),
+ ones = MatrixType::Ones(rows, cols);
+ VectorType v1 = VectorType::Random(rows);
+
+ Scalar s1 = internal::random<Scalar>();
+
+ Index r1 = internal::random<Index>(0,rows-1);
+ Index r2 = internal::random<Index>(r1,rows-1);
+ Index c1 = internal::random<Index>(0,cols-1);
+ Index c2 = internal::random<Index>(c1,cols-1);
+
+ //check row() and col()
+ VERIFY_IS_EQUAL(m1.col(c1).transpose(), m1.transpose().row(c1));
+ //check operator(), both constant and non-constant, on row() and col()
+ m1 = m1_copy;
+ m1.row(r1) += s1 * m1_copy.row(r2);
+ VERIFY_IS_APPROX(m1.row(r1), m1_copy.row(r1) + s1 * m1_copy.row(r2));
+ // check nested block xpr on lhs
+ m1.row(r1).row(0) += s1 * m1_copy.row(r2);
+ VERIFY_IS_APPROX(m1.row(r1), m1_copy.row(r1) + Scalar(2) * s1 * m1_copy.row(r2));
+ m1 = m1_copy;
+ m1.col(c1) += s1 * m1_copy.col(c2);
+ VERIFY_IS_APPROX(m1.col(c1), m1_copy.col(c1) + s1 * m1_copy.col(c2));
+ m1.col(c1).col(0) += s1 * m1_copy.col(c2);
+ VERIFY_IS_APPROX(m1.col(c1), m1_copy.col(c1) + Scalar(2) * s1 * m1_copy.col(c2));
+
+ //check block()
+ Matrix<Scalar,Dynamic,Dynamic> b1(1,1); b1(0,0) = m1(r1,c1);
+
+ RowVectorType br1(m1.block(r1,0,1,cols));
+ VectorType bc1(m1.block(0,c1,rows,1));
+ VERIFY_IS_EQUAL(b1, m1.block(r1,c1,1,1));
+ VERIFY_IS_EQUAL(m1.row(r1), br1);
+ VERIFY_IS_EQUAL(m1.col(c1), bc1);
+ //check operator(), both constant and non-constant, on block()
+ m1.block(r1,c1,r2-r1+1,c2-c1+1) = s1 * m2.block(0, 0, r2-r1+1,c2-c1+1);
+ m1.block(r1,c1,r2-r1+1,c2-c1+1)(r2-r1,c2-c1) = m2.block(0, 0, r2-r1+1,c2-c1+1)(0,0);
+
+ enum {
+ BlockRows = 2,
+ BlockCols = 5
+ };
+ if (rows>=5 && cols>=8)
+ {
+ // test fixed block() as lvalue
+ m1.template block<BlockRows,BlockCols>(1,1) *= s1;
+ // test operator() on fixed block() both as constant and non-constant
+ m1.template block<BlockRows,BlockCols>(1,1)(0, 3) = m1.template block<2,5>(1,1)(1,2);
+ // check that fixed block() and block() agree
+ Matrix<Scalar,Dynamic,Dynamic> b = m1.template block<BlockRows,BlockCols>(3,3);
+ VERIFY_IS_EQUAL(b, m1.block(3,3,BlockRows,BlockCols));
+ }
+
+ if (rows>2)
+ {
+ // test sub vectors
+ VERIFY_IS_EQUAL(v1.template head<2>(), v1.block(0,0,2,1));
+ VERIFY_IS_EQUAL(v1.template head<2>(), v1.head(2));
+ VERIFY_IS_EQUAL(v1.template head<2>(), v1.segment(0,2));
+ VERIFY_IS_EQUAL(v1.template head<2>(), v1.template segment<2>(0));
+ Index i = rows-2;
+ VERIFY_IS_EQUAL(v1.template tail<2>(), v1.block(i,0,2,1));
+ VERIFY_IS_EQUAL(v1.template tail<2>(), v1.tail(2));
+ VERIFY_IS_EQUAL(v1.template tail<2>(), v1.segment(i,2));
+ VERIFY_IS_EQUAL(v1.template tail<2>(), v1.template segment<2>(i));
+ i = internal::random<Index>(0,rows-2);
+ VERIFY_IS_EQUAL(v1.segment(i,2), v1.template segment<2>(i));
+ }
+
+ // stress some basic stuffs with block matrices
+ VERIFY(internal::real(ones.col(c1).sum()) == RealScalar(rows));
+ VERIFY(internal::real(ones.row(r1).sum()) == RealScalar(cols));
+
+ VERIFY(internal::real(ones.col(c1).dot(ones.col(c2))) == RealScalar(rows));
+ VERIFY(internal::real(ones.row(r1).dot(ones.row(r2))) == RealScalar(cols));
+
+ // now test some block-inside-of-block.
+
+ // expressions with direct access
+ VERIFY_IS_EQUAL( (m1.block(r1,c1,rows-r1,cols-c1).block(r2-r1,c2-c1,rows-r2,cols-c2)) , (m1.block(r2,c2,rows-r2,cols-c2)) );
+ VERIFY_IS_EQUAL( (m1.block(r1,c1,r2-r1+1,c2-c1+1).row(0)) , (m1.row(r1).segment(c1,c2-c1+1)) );
+ VERIFY_IS_EQUAL( (m1.block(r1,c1,r2-r1+1,c2-c1+1).col(0)) , (m1.col(c1).segment(r1,r2-r1+1)) );
+ VERIFY_IS_EQUAL( (m1.block(r1,c1,r2-r1+1,c2-c1+1).transpose().col(0)) , (m1.row(r1).segment(c1,c2-c1+1)).transpose() );
+ VERIFY_IS_EQUAL( (m1.transpose().block(c1,r1,c2-c1+1,r2-r1+1).col(0)) , (m1.row(r1).segment(c1,c2-c1+1)).transpose() );
+
+ // expressions without direct access
+ VERIFY_IS_EQUAL( ((m1+m2).block(r1,c1,rows-r1,cols-c1).block(r2-r1,c2-c1,rows-r2,cols-c2)) , ((m1+m2).block(r2,c2,rows-r2,cols-c2)) );
+ VERIFY_IS_EQUAL( ((m1+m2).block(r1,c1,r2-r1+1,c2-c1+1).row(0)) , ((m1+m2).row(r1).segment(c1,c2-c1+1)) );
+ VERIFY_IS_EQUAL( ((m1+m2).block(r1,c1,r2-r1+1,c2-c1+1).col(0)) , ((m1+m2).col(c1).segment(r1,r2-r1+1)) );
+ VERIFY_IS_EQUAL( ((m1+m2).block(r1,c1,r2-r1+1,c2-c1+1).transpose().col(0)) , ((m1+m2).row(r1).segment(c1,c2-c1+1)).transpose() );
+ VERIFY_IS_EQUAL( ((m1+m2).transpose().block(c1,r1,c2-c1+1,r2-r1+1).col(0)) , ((m1+m2).row(r1).segment(c1,c2-c1+1)).transpose() );
+
+ // evaluation into plain matrices from expressions with direct access (stress MapBase)
+ DynamicMatrixType dm;
+ DynamicVectorType dv;
+ dm.setZero();
+ dm = m1.block(r1,c1,rows-r1,cols-c1).block(r2-r1,c2-c1,rows-r2,cols-c2);
+ VERIFY_IS_EQUAL(dm, (m1.block(r2,c2,rows-r2,cols-c2)));
+ dm.setZero();
+ dv.setZero();
+ dm = m1.block(r1,c1,r2-r1+1,c2-c1+1).row(0).transpose();
+ dv = m1.row(r1).segment(c1,c2-c1+1);
+ VERIFY_IS_EQUAL(dv, dm);
+ dm.setZero();
+ dv.setZero();
+ dm = m1.col(c1).segment(r1,r2-r1+1);
+ dv = m1.block(r1,c1,r2-r1+1,c2-c1+1).col(0);
+ VERIFY_IS_EQUAL(dv, dm);
+ dm.setZero();
+ dv.setZero();
+ dm = m1.block(r1,c1,r2-r1+1,c2-c1+1).transpose().col(0);
+ dv = m1.row(r1).segment(c1,c2-c1+1);
+ VERIFY_IS_EQUAL(dv, dm);
+ dm.setZero();
+ dv.setZero();
+ dm = m1.row(r1).segment(c1,c2-c1+1).transpose();
+ dv = m1.transpose().block(c1,r1,c2-c1+1,r2-r1+1).col(0);
+ VERIFY_IS_EQUAL(dv, dm);
+}
+
+
+template<typename MatrixType>
+void compare_using_data_and_stride(const MatrixType& m)
+{
+ typedef typename MatrixType::Index Index;
+ Index rows = m.rows();
+ Index cols = m.cols();
+ Index size = m.size();
+ Index innerStride = m.innerStride();
+ Index outerStride = m.outerStride();
+ Index rowStride = m.rowStride();
+ Index colStride = m.colStride();
+ const typename MatrixType::Scalar* data = m.data();
+
+ for(int j=0;j<cols;++j)
+ for(int i=0;i<rows;++i)
+ VERIFY(m.coeff(i,j) == data[i*rowStride + j*colStride]);
+
+ if(!MatrixType::IsVectorAtCompileTime)
+ {
+ for(int j=0;j<cols;++j)
+ for(int i=0;i<rows;++i)
+ VERIFY(m.coeff(i,j) == data[(MatrixType::Flags&RowMajorBit)
+ ? i*outerStride + j*innerStride
+ : j*outerStride + i*innerStride]);
+ }
+
+ if(MatrixType::IsVectorAtCompileTime)
+ {
+ VERIFY(innerStride == int((&m.coeff(1))-(&m.coeff(0))));
+ for (int i=0;i<size;++i)
+ VERIFY(m.coeff(i) == data[i*innerStride]);
+ }
+}
+
+template<typename MatrixType>
+void data_and_stride(const MatrixType& m)
+{
+ typedef typename MatrixType::Index Index;
+ Index rows = m.rows();
+ Index cols = m.cols();
+
+ Index r1 = internal::random<Index>(0,rows-1);
+ Index r2 = internal::random<Index>(r1,rows-1);
+ Index c1 = internal::random<Index>(0,cols-1);
+ Index c2 = internal::random<Index>(c1,cols-1);
+
+ MatrixType m1 = MatrixType::Random(rows, cols);
+ compare_using_data_and_stride(m1.block(r1, c1, r2-r1+1, c2-c1+1));
+ compare_using_data_and_stride(m1.transpose().block(c1, r1, c2-c1+1, r2-r1+1));
+ compare_using_data_and_stride(m1.row(r1));
+ compare_using_data_and_stride(m1.col(c1));
+ compare_using_data_and_stride(m1.row(r1).transpose());
+ compare_using_data_and_stride(m1.col(c1).transpose());
+}
+
+void test_block()
+{
+ for(int i = 0; i < g_repeat; i++) {
+ CALL_SUBTEST_1( block(Matrix<float, 1, 1>()) );
+ CALL_SUBTEST_2( block(Matrix4d()) );
+ CALL_SUBTEST_3( block(MatrixXcf(3, 3)) );
+ CALL_SUBTEST_4( block(MatrixXi(8, 12)) );
+ CALL_SUBTEST_5( block(MatrixXcd(20, 20)) );
+ CALL_SUBTEST_6( block(MatrixXf(20, 20)) );
+
+ CALL_SUBTEST_8( block(Matrix<float,Dynamic,4>(3, 4)) );
+
+#ifndef EIGEN_DEFAULT_TO_ROW_MAJOR
+ CALL_SUBTEST_6( data_and_stride(MatrixXf(internal::random(5,50), internal::random(5,50))) );
+ CALL_SUBTEST_7( data_and_stride(Matrix<int,Dynamic,Dynamic,RowMajor>(internal::random(5,50), internal::random(5,50))) );
+#endif
+ }
+}
diff --git a/test/cholesky.cpp b/test/cholesky.cpp
new file mode 100644
index 000000000..14e01c006
--- /dev/null
+++ b/test/cholesky.cpp
@@ -0,0 +1,310 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra.
+//
+// Copyright (C) 2008 Gael Guennebaud <gael.guennebaud@inria.fr>
+//
+// This Source Code Form is subject to the terms of the Mozilla
+// Public License v. 2.0. If a copy of the MPL was not distributed
+// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+#ifndef EIGEN_NO_ASSERTION_CHECKING
+#define EIGEN_NO_ASSERTION_CHECKING
+#endif
+
+static int nb_temporaries;
+
+#define EIGEN_DENSE_STORAGE_CTOR_PLUGIN { if(size!=0) nb_temporaries++; }
+
+#include "main.h"
+#include <Eigen/Cholesky>
+#include <Eigen/QR>
+
+#define VERIFY_EVALUATION_COUNT(XPR,N) {\
+ nb_temporaries = 0; \
+ XPR; \
+ if(nb_temporaries!=N) std::cerr << "nb_temporaries == " << nb_temporaries << "\n"; \
+ VERIFY( (#XPR) && nb_temporaries==N ); \
+ }
+
+template<typename MatrixType,template <typename,int> class CholType> void test_chol_update(const MatrixType& symm)
+{
+ typedef typename MatrixType::Scalar Scalar;
+ typedef typename MatrixType::RealScalar RealScalar;
+ typedef Matrix<Scalar, MatrixType::RowsAtCompileTime, 1> VectorType;
+
+ MatrixType symmLo = symm.template triangularView<Lower>();
+ MatrixType symmUp = symm.template triangularView<Upper>();
+ MatrixType symmCpy = symm;
+
+ CholType<MatrixType,Lower> chollo(symmLo);
+ CholType<MatrixType,Upper> cholup(symmUp);
+
+ for (int k=0; k<10; ++k)
+ {
+ VectorType vec = VectorType::Random(symm.rows());
+ RealScalar sigma = internal::random<RealScalar>();
+ symmCpy += sigma * vec * vec.adjoint();
+
+ // we are doing some downdates, so it might be the case that the matrix is not SPD anymore
+ CholType<MatrixType,Lower> chol(symmCpy);
+ if(chol.info()!=Success)
+ break;
+
+ chollo.rankUpdate(vec, sigma);
+ VERIFY_IS_APPROX(symmCpy, chollo.reconstructedMatrix());
+
+ cholup.rankUpdate(vec, sigma);
+ VERIFY_IS_APPROX(symmCpy, cholup.reconstructedMatrix());
+ }
+}
+
+template<typename MatrixType> void cholesky(const MatrixType& m)
+{
+ typedef typename MatrixType::Index Index;
+ /* this test covers the following files:
+ LLT.h LDLT.h
+ */
+ Index rows = m.rows();
+ Index cols = m.cols();
+
+ typedef typename MatrixType::Scalar Scalar;
+ typedef typename NumTraits<Scalar>::Real RealScalar;
+ typedef Matrix<Scalar, MatrixType::RowsAtCompileTime, MatrixType::RowsAtCompileTime> SquareMatrixType;
+ typedef Matrix<Scalar, MatrixType::RowsAtCompileTime, 1> VectorType;
+
+ MatrixType a0 = MatrixType::Random(rows,cols);
+ VectorType vecB = VectorType::Random(rows), vecX(rows);
+ MatrixType matB = MatrixType::Random(rows,cols), matX(rows,cols);
+ SquareMatrixType symm = a0 * a0.adjoint();
+ // let's make sure the matrix is not singular or near singular
+ for (int k=0; k<3; ++k)
+ {
+ MatrixType a1 = MatrixType::Random(rows,cols);
+ symm += a1 * a1.adjoint();
+ }
+
+ SquareMatrixType symmUp = symm.template triangularView<Upper>();
+ SquareMatrixType symmLo = symm.template triangularView<Lower>();
+
+ // to test if really Cholesky only uses the upper triangular part, uncomment the following
+ // FIXME: currently that fails !!
+ //symm.template part<StrictlyLower>().setZero();
+
+ {
+ LLT<SquareMatrixType,Lower> chollo(symmLo);
+ VERIFY_IS_APPROX(symm, chollo.reconstructedMatrix());
+ vecX = chollo.solve(vecB);
+ VERIFY_IS_APPROX(symm * vecX, vecB);
+ matX = chollo.solve(matB);
+ VERIFY_IS_APPROX(symm * matX, matB);
+
+ // test the upper mode
+ LLT<SquareMatrixType,Upper> cholup(symmUp);
+ VERIFY_IS_APPROX(symm, cholup.reconstructedMatrix());
+ vecX = cholup.solve(vecB);
+ VERIFY_IS_APPROX(symm * vecX, vecB);
+ matX = cholup.solve(matB);
+ VERIFY_IS_APPROX(symm * matX, matB);
+
+ MatrixType neg = -symmLo;
+ chollo.compute(neg);
+ VERIFY(chollo.info()==NumericalIssue);
+
+ VERIFY_IS_APPROX(MatrixType(chollo.matrixL().transpose().conjugate()), MatrixType(chollo.matrixU()));
+ VERIFY_IS_APPROX(MatrixType(chollo.matrixU().transpose().conjugate()), MatrixType(chollo.matrixL()));
+ VERIFY_IS_APPROX(MatrixType(cholup.matrixL().transpose().conjugate()), MatrixType(cholup.matrixU()));
+ VERIFY_IS_APPROX(MatrixType(cholup.matrixU().transpose().conjugate()), MatrixType(cholup.matrixL()));
+ }
+
+ // LDLT
+ {
+ int sign = internal::random<int>()%2 ? 1 : -1;
+
+ if(sign == -1)
+ {
+ symm = -symm; // test a negative matrix
+ }
+
+ SquareMatrixType symmUp = symm.template triangularView<Upper>();
+ SquareMatrixType symmLo = symm.template triangularView<Lower>();
+
+ LDLT<SquareMatrixType,Lower> ldltlo(symmLo);
+ VERIFY_IS_APPROX(symm, ldltlo.reconstructedMatrix());
+ vecX = ldltlo.solve(vecB);
+ VERIFY_IS_APPROX(symm * vecX, vecB);
+ matX = ldltlo.solve(matB);
+ VERIFY_IS_APPROX(symm * matX, matB);
+
+ LDLT<SquareMatrixType,Upper> ldltup(symmUp);
+ VERIFY_IS_APPROX(symm, ldltup.reconstructedMatrix());
+ vecX = ldltup.solve(vecB);
+ VERIFY_IS_APPROX(symm * vecX, vecB);
+ matX = ldltup.solve(matB);
+ VERIFY_IS_APPROX(symm * matX, matB);
+
+ VERIFY_IS_APPROX(MatrixType(ldltlo.matrixL().transpose().conjugate()), MatrixType(ldltlo.matrixU()));
+ VERIFY_IS_APPROX(MatrixType(ldltlo.matrixU().transpose().conjugate()), MatrixType(ldltlo.matrixL()));
+ VERIFY_IS_APPROX(MatrixType(ldltup.matrixL().transpose().conjugate()), MatrixType(ldltup.matrixU()));
+ VERIFY_IS_APPROX(MatrixType(ldltup.matrixU().transpose().conjugate()), MatrixType(ldltup.matrixL()));
+
+ if(MatrixType::RowsAtCompileTime==Dynamic)
+ {
+ // note : each inplace permutation requires a small temporary vector (mask)
+
+ // check inplace solve
+ matX = matB;
+ VERIFY_EVALUATION_COUNT(matX = ldltlo.solve(matX), 0);
+ VERIFY_IS_APPROX(matX, ldltlo.solve(matB).eval());
+
+
+ matX = matB;
+ VERIFY_EVALUATION_COUNT(matX = ldltup.solve(matX), 0);
+ VERIFY_IS_APPROX(matX, ldltup.solve(matB).eval());
+ }
+
+ // restore
+ if(sign == -1)
+ symm = -symm;
+ }
+
+ // test some special use cases of SelfCwiseBinaryOp:
+ MatrixType m1 = MatrixType::Random(rows,cols), m2(rows,cols);
+ m2 = m1;
+ m2 += symmLo.template selfadjointView<Lower>().llt().solve(matB);
+ VERIFY_IS_APPROX(m2, m1 + symmLo.template selfadjointView<Lower>().llt().solve(matB));
+ m2 = m1;
+ m2 -= symmLo.template selfadjointView<Lower>().llt().solve(matB);
+ VERIFY_IS_APPROX(m2, m1 - symmLo.template selfadjointView<Lower>().llt().solve(matB));
+ m2 = m1;
+ m2.noalias() += symmLo.template selfadjointView<Lower>().llt().solve(matB);
+ VERIFY_IS_APPROX(m2, m1 + symmLo.template selfadjointView<Lower>().llt().solve(matB));
+ m2 = m1;
+ m2.noalias() -= symmLo.template selfadjointView<Lower>().llt().solve(matB);
+ VERIFY_IS_APPROX(m2, m1 - symmLo.template selfadjointView<Lower>().llt().solve(matB));
+
+ // update/downdate
+ CALL_SUBTEST(( test_chol_update<SquareMatrixType,LLT>(symm) ));
+ CALL_SUBTEST(( test_chol_update<SquareMatrixType,LDLT>(symm) ));
+}
+
+template<typename MatrixType> void cholesky_cplx(const MatrixType& m)
+{
+ // classic test
+ cholesky(m);
+
+ // test mixing real/scalar types
+
+ typedef typename MatrixType::Index Index;
+
+ Index rows = m.rows();
+ Index cols = m.cols();
+
+ typedef typename MatrixType::Scalar Scalar;
+ typedef typename NumTraits<Scalar>::Real RealScalar;
+ typedef Matrix<RealScalar, MatrixType::RowsAtCompileTime, MatrixType::RowsAtCompileTime> RealMatrixType;
+ typedef Matrix<Scalar, MatrixType::RowsAtCompileTime, 1> VectorType;
+
+ RealMatrixType a0 = RealMatrixType::Random(rows,cols);
+ VectorType vecB = VectorType::Random(rows), vecX(rows);
+ MatrixType matB = MatrixType::Random(rows,cols), matX(rows,cols);
+ RealMatrixType symm = a0 * a0.adjoint();
+ // let's make sure the matrix is not singular or near singular
+ for (int k=0; k<3; ++k)
+ {
+ RealMatrixType a1 = RealMatrixType::Random(rows,cols);
+ symm += a1 * a1.adjoint();
+ }
+
+ {
+ RealMatrixType symmLo = symm.template triangularView<Lower>();
+
+ LLT<RealMatrixType,Lower> chollo(symmLo);
+ VERIFY_IS_APPROX(symm, chollo.reconstructedMatrix());
+ vecX = chollo.solve(vecB);
+ VERIFY_IS_APPROX(symm * vecX, vecB);
+// matX = chollo.solve(matB);
+// VERIFY_IS_APPROX(symm * matX, matB);
+ }
+
+ // LDLT
+ {
+ int sign = internal::random<int>()%2 ? 1 : -1;
+
+ if(sign == -1)
+ {
+ symm = -symm; // test a negative matrix
+ }
+
+ RealMatrixType symmLo = symm.template triangularView<Lower>();
+
+ LDLT<RealMatrixType,Lower> ldltlo(symmLo);
+ VERIFY_IS_APPROX(symm, ldltlo.reconstructedMatrix());
+ vecX = ldltlo.solve(vecB);
+ VERIFY_IS_APPROX(symm * vecX, vecB);
+// matX = ldltlo.solve(matB);
+// VERIFY_IS_APPROX(symm * matX, matB);
+ }
+}
+
+// regression test for bug 241
+template<typename MatrixType> void cholesky_bug241(const MatrixType& m)
+{
+ eigen_assert(m.rows() == 2 && m.cols() == 2);
+
+ typedef typename MatrixType::Scalar Scalar;
+ typedef Matrix<Scalar, MatrixType::RowsAtCompileTime, 1> VectorType;
+
+ MatrixType matA;
+ matA << 1, 1, 1, 1;
+ VectorType vecB;
+ vecB << 1, 1;
+ VectorType vecX = matA.ldlt().solve(vecB);
+ VERIFY_IS_APPROX(matA * vecX, vecB);
+}
+
+template<typename MatrixType> void cholesky_verify_assert()
+{
+ MatrixType tmp;
+
+ LLT<MatrixType> llt;
+ VERIFY_RAISES_ASSERT(llt.matrixL())
+ VERIFY_RAISES_ASSERT(llt.matrixU())
+ VERIFY_RAISES_ASSERT(llt.solve(tmp))
+ VERIFY_RAISES_ASSERT(llt.solveInPlace(&tmp))
+
+ LDLT<MatrixType> ldlt;
+ VERIFY_RAISES_ASSERT(ldlt.matrixL())
+ VERIFY_RAISES_ASSERT(ldlt.permutationP())
+ VERIFY_RAISES_ASSERT(ldlt.vectorD())
+ VERIFY_RAISES_ASSERT(ldlt.isPositive())
+ VERIFY_RAISES_ASSERT(ldlt.isNegative())
+ VERIFY_RAISES_ASSERT(ldlt.solve(tmp))
+ VERIFY_RAISES_ASSERT(ldlt.solveInPlace(&tmp))
+}
+
+void test_cholesky()
+{
+ int s;
+ for(int i = 0; i < g_repeat; i++) {
+ CALL_SUBTEST_1( cholesky(Matrix<double,1,1>()) );
+ CALL_SUBTEST_3( cholesky(Matrix2d()) );
+ CALL_SUBTEST_3( cholesky_bug241(Matrix2d()) );
+ CALL_SUBTEST_4( cholesky(Matrix3f()) );
+ CALL_SUBTEST_5( cholesky(Matrix4d()) );
+ s = internal::random<int>(1,EIGEN_TEST_MAX_SIZE);
+ CALL_SUBTEST_2( cholesky(MatrixXd(s,s)) );
+ s = internal::random<int>(1,EIGEN_TEST_MAX_SIZE/2);
+ CALL_SUBTEST_6( cholesky_cplx(MatrixXcd(s,s)) );
+ }
+
+ CALL_SUBTEST_4( cholesky_verify_assert<Matrix3f>() );
+ CALL_SUBTEST_7( cholesky_verify_assert<Matrix3d>() );
+ CALL_SUBTEST_8( cholesky_verify_assert<MatrixXf>() );
+ CALL_SUBTEST_2( cholesky_verify_assert<MatrixXd>() );
+
+ // Test problem size constructors
+ CALL_SUBTEST_9( LLT<MatrixXf>(10) );
+ CALL_SUBTEST_9( LDLT<MatrixXf>(10) );
+
+ EIGEN_UNUSED_VARIABLE(s)
+}
diff --git a/test/cholmod_support.cpp b/test/cholmod_support.cpp
new file mode 100644
index 000000000..8f8be3c0e
--- /dev/null
+++ b/test/cholmod_support.cpp
@@ -0,0 +1,56 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra.
+//
+// Copyright (C) 2011 Gael Guennebaud <g.gael@free.fr>
+//
+// This Source Code Form is subject to the terms of the Mozilla
+// Public License v. 2.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 "sparse_solver.h"
+
+#include <Eigen/CholmodSupport>
+
+template<typename T> void test_cholmod_T()
+{
+ CholmodDecomposition<SparseMatrix<T>, Lower> g_chol_colmajor_lower; g_chol_colmajor_lower.setMode(CholmodSupernodalLLt);
+ CholmodDecomposition<SparseMatrix<T>, Upper> g_chol_colmajor_upper; g_chol_colmajor_upper.setMode(CholmodSupernodalLLt);
+ CholmodDecomposition<SparseMatrix<T>, Lower> g_llt_colmajor_lower; g_llt_colmajor_lower.setMode(CholmodSimplicialLLt);
+ CholmodDecomposition<SparseMatrix<T>, Upper> g_llt_colmajor_upper; g_llt_colmajor_upper.setMode(CholmodSimplicialLLt);
+ CholmodDecomposition<SparseMatrix<T>, Lower> g_ldlt_colmajor_lower; g_ldlt_colmajor_lower.setMode(CholmodLDLt);
+ CholmodDecomposition<SparseMatrix<T>, Upper> g_ldlt_colmajor_upper; g_ldlt_colmajor_upper.setMode(CholmodLDLt);
+
+ CholmodSupernodalLLT<SparseMatrix<T>, Lower> chol_colmajor_lower;
+ CholmodSupernodalLLT<SparseMatrix<T>, Upper> chol_colmajor_upper;
+ CholmodSimplicialLLT<SparseMatrix<T>, Lower> llt_colmajor_lower;
+ CholmodSimplicialLLT<SparseMatrix<T>, Upper> llt_colmajor_upper;
+ CholmodSimplicialLDLT<SparseMatrix<T>, Lower> ldlt_colmajor_lower;
+ CholmodSimplicialLDLT<SparseMatrix<T>, Upper> ldlt_colmajor_upper;
+
+ check_sparse_spd_solving(g_chol_colmajor_lower);
+ check_sparse_spd_solving(g_chol_colmajor_upper);
+ check_sparse_spd_solving(g_llt_colmajor_lower);
+ check_sparse_spd_solving(g_llt_colmajor_upper);
+ check_sparse_spd_solving(g_ldlt_colmajor_lower);
+ check_sparse_spd_solving(g_ldlt_colmajor_upper);
+
+ check_sparse_spd_solving(chol_colmajor_lower);
+ check_sparse_spd_solving(chol_colmajor_upper);
+ check_sparse_spd_solving(llt_colmajor_lower);
+ check_sparse_spd_solving(llt_colmajor_upper);
+ check_sparse_spd_solving(ldlt_colmajor_lower);
+ check_sparse_spd_solving(ldlt_colmajor_upper);
+
+// check_sparse_spd_determinant(chol_colmajor_lower);
+// check_sparse_spd_determinant(chol_colmajor_upper);
+// check_sparse_spd_determinant(llt_colmajor_lower);
+// check_sparse_spd_determinant(llt_colmajor_upper);
+// check_sparse_spd_determinant(ldlt_colmajor_lower);
+// check_sparse_spd_determinant(ldlt_colmajor_upper);
+}
+
+void test_cholmod_support()
+{
+ CALL_SUBTEST_1(test_cholmod_T<double>());
+ CALL_SUBTEST_2(test_cholmod_T<std::complex<double> >());
+}
diff --git a/test/commainitializer.cpp b/test/commainitializer.cpp
new file mode 100644
index 000000000..99102b966
--- /dev/null
+++ b/test/commainitializer.cpp
@@ -0,0 +1,46 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra.
+//
+// Copyright (C) 2008 Gael Guennebaud <gael.guennebaud@inria.fr>
+//
+// This Source Code Form is subject to the terms of the Mozilla
+// Public License v. 2.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 "main.h"
+
+void test_commainitializer()
+{
+ Matrix3d m3;
+ Matrix4d m4;
+
+ VERIFY_RAISES_ASSERT( (m3 << 1, 2, 3, 4, 5, 6, 7, 8) );
+
+ #ifndef _MSC_VER
+ VERIFY_RAISES_ASSERT( (m3 << 1, 2, 3, 4, 5, 6, 7, 8, 9, 10) );
+ #endif
+
+ double data[] = {1, 2, 3, 4, 5, 6, 7, 8, 9};
+ Matrix3d ref = Map<Matrix<double,3,3,RowMajor> >(data);
+
+ m3 = Matrix3d::Random();
+ m3 << 1, 2, 3, 4, 5, 6, 7, 8, 9;
+ VERIFY_IS_APPROX(m3, ref );
+
+ Vector3d vec[3];
+ vec[0] << 1, 4, 7;
+ vec[1] << 2, 5, 8;
+ vec[2] << 3, 6, 9;
+ m3 = Matrix3d::Random();
+ m3 << vec[0], vec[1], vec[2];
+ VERIFY_IS_APPROX(m3, ref);
+
+ vec[0] << 1, 2, 3;
+ vec[1] << 4, 5, 6;
+ vec[2] << 7, 8, 9;
+ m3 = Matrix3d::Random();
+ m3 << vec[0].transpose(),
+ 4, 5, 6,
+ vec[2].transpose();
+ VERIFY_IS_APPROX(m3, ref);
+}
diff --git a/test/conjugate_gradient.cpp b/test/conjugate_gradient.cpp
new file mode 100644
index 000000000..869051b31
--- /dev/null
+++ b/test/conjugate_gradient.cpp
@@ -0,0 +1,30 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra.
+//
+// Copyright (C) 2011 Gael Guennebaud <g.gael@free.fr>
+//
+// This Source Code Form is subject to the terms of the Mozilla
+// Public License v. 2.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 "sparse_solver.h"
+#include <Eigen/IterativeLinearSolvers>
+
+template<typename T> void test_conjugate_gradient_T()
+{
+ ConjugateGradient<SparseMatrix<T>, Lower> cg_colmajor_lower_diag;
+ ConjugateGradient<SparseMatrix<T>, Upper> cg_colmajor_upper_diag;
+ ConjugateGradient<SparseMatrix<T>, Lower, IdentityPreconditioner> cg_colmajor_lower_I;
+ ConjugateGradient<SparseMatrix<T>, Upper, IdentityPreconditioner> cg_colmajor_upper_I;
+
+ CALL_SUBTEST( check_sparse_spd_solving(cg_colmajor_lower_diag) );
+ CALL_SUBTEST( check_sparse_spd_solving(cg_colmajor_upper_diag) );
+ CALL_SUBTEST( check_sparse_spd_solving(cg_colmajor_lower_I) );
+ CALL_SUBTEST( check_sparse_spd_solving(cg_colmajor_upper_I) );
+}
+
+void test_conjugate_gradient()
+{
+ CALL_SUBTEST_1(test_conjugate_gradient_T<double>());
+ CALL_SUBTEST_2(test_conjugate_gradient_T<std::complex<double> >());
+}
diff --git a/test/conservative_resize.cpp b/test/conservative_resize.cpp
new file mode 100644
index 000000000..4d11e4075
--- /dev/null
+++ b/test/conservative_resize.cpp
@@ -0,0 +1,114 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra.
+//
+// Copyright (C) 2009 Hauke Heibel <hauke.heibel@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 "main.h"
+
+#include <Eigen/Core>
+
+using namespace Eigen;
+
+template <typename Scalar, int Storage>
+void run_matrix_tests()
+{
+ typedef Matrix<Scalar, Eigen::Dynamic, Eigen::Dynamic, Storage> MatrixType;
+ typedef typename MatrixType::Index Index;
+
+ MatrixType m, n;
+
+ // boundary cases ...
+ m = n = MatrixType::Random(50,50);
+ m.conservativeResize(1,50);
+ VERIFY_IS_APPROX(m, n.block(0,0,1,50));
+
+ m = n = MatrixType::Random(50,50);
+ m.conservativeResize(50,1);
+ VERIFY_IS_APPROX(m, n.block(0,0,50,1));
+
+ m = n = MatrixType::Random(50,50);
+ m.conservativeResize(50,50);
+ VERIFY_IS_APPROX(m, n.block(0,0,50,50));
+
+ // random shrinking ...
+ for (int i=0; i<25; ++i)
+ {
+ const Index rows = internal::random<Index>(1,50);
+ const Index cols = internal::random<Index>(1,50);
+ m = n = MatrixType::Random(50,50);
+ m.conservativeResize(rows,cols);
+ VERIFY_IS_APPROX(m, n.block(0,0,rows,cols));
+ }
+
+ // random growing with zeroing ...
+ for (int i=0; i<25; ++i)
+ {
+ const Index rows = internal::random<Index>(50,75);
+ const Index cols = internal::random<Index>(50,75);
+ m = n = MatrixType::Random(50,50);
+ m.conservativeResizeLike(MatrixType::Zero(rows,cols));
+ VERIFY_IS_APPROX(m.block(0,0,n.rows(),n.cols()), n);
+ VERIFY( rows<=50 || m.block(50,0,rows-50,cols).sum() == Scalar(0) );
+ VERIFY( cols<=50 || m.block(0,50,rows,cols-50).sum() == Scalar(0) );
+ }
+}
+
+template <typename Scalar>
+void run_vector_tests()
+{
+ typedef Matrix<Scalar, 1, Eigen::Dynamic> MatrixType;
+
+ MatrixType m, n;
+
+ // boundary cases ...
+ m = n = MatrixType::Random(50);
+ m.conservativeResize(1);
+ VERIFY_IS_APPROX(m, n.segment(0,1));
+
+ m = n = MatrixType::Random(50);
+ m.conservativeResize(50);
+ VERIFY_IS_APPROX(m, n.segment(0,50));
+
+ // random shrinking ...
+ for (int i=0; i<50; ++i)
+ {
+ const int size = internal::random<int>(1,50);
+ m = n = MatrixType::Random(50);
+ m.conservativeResize(size);
+ VERIFY_IS_APPROX(m, n.segment(0,size));
+ }
+
+ // random growing with zeroing ...
+ for (int i=0; i<50; ++i)
+ {
+ const int size = internal::random<int>(50,100);
+ m = n = MatrixType::Random(50);
+ m.conservativeResizeLike(MatrixType::Zero(size));
+ VERIFY_IS_APPROX(m.segment(0,50), n);
+ VERIFY( size<=50 || m.segment(50,size-50).sum() == Scalar(0) );
+ }
+}
+
+void test_conservative_resize()
+{
+ CALL_SUBTEST_1((run_matrix_tests<int, Eigen::RowMajor>()));
+ CALL_SUBTEST_1((run_matrix_tests<int, Eigen::ColMajor>()));
+ CALL_SUBTEST_2((run_matrix_tests<float, Eigen::RowMajor>()));
+ CALL_SUBTEST_2((run_matrix_tests<float, Eigen::ColMajor>()));
+ CALL_SUBTEST_3((run_matrix_tests<double, Eigen::RowMajor>()));
+ CALL_SUBTEST_3((run_matrix_tests<double, Eigen::ColMajor>()));
+ CALL_SUBTEST_4((run_matrix_tests<std::complex<float>, Eigen::RowMajor>()));
+ CALL_SUBTEST_4((run_matrix_tests<std::complex<float>, Eigen::ColMajor>()));
+ CALL_SUBTEST_5((run_matrix_tests<std::complex<double>, Eigen::RowMajor>()));
+ CALL_SUBTEST_6((run_matrix_tests<std::complex<double>, Eigen::ColMajor>()));
+
+ CALL_SUBTEST_1((run_vector_tests<int>()));
+ CALL_SUBTEST_2((run_vector_tests<float>()));
+ CALL_SUBTEST_3((run_vector_tests<double>()));
+ CALL_SUBTEST_4((run_vector_tests<std::complex<float> >()));
+ CALL_SUBTEST_5((run_vector_tests<std::complex<double> >()));
+}
diff --git a/test/corners.cpp b/test/corners.cpp
new file mode 100644
index 000000000..4705c5f05
--- /dev/null
+++ b/test/corners.cpp
@@ -0,0 +1,98 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra.
+//
+// Copyright (C) 2006-2010 Benoit Jacob <jacob.benoit.1@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 "main.h"
+
+#define COMPARE_CORNER(A,B) \
+ VERIFY_IS_EQUAL(matrix.A, matrix.B); \
+ VERIFY_IS_EQUAL(const_matrix.A, const_matrix.B);
+
+template<typename MatrixType> void corners(const MatrixType& m)
+{
+ typedef typename MatrixType::Index Index;
+ Index rows = m.rows();
+ Index cols = m.cols();
+
+ Index r = internal::random<Index>(1,rows);
+ Index c = internal::random<Index>(1,cols);
+
+ MatrixType matrix = MatrixType::Random(rows,cols);
+ const MatrixType const_matrix = MatrixType::Random(rows,cols);
+
+ COMPARE_CORNER(topLeftCorner(r,c), block(0,0,r,c));
+ COMPARE_CORNER(topRightCorner(r,c), block(0,cols-c,r,c));
+ COMPARE_CORNER(bottomLeftCorner(r,c), block(rows-r,0,r,c));
+ COMPARE_CORNER(bottomRightCorner(r,c), block(rows-r,cols-c,r,c));
+
+ Index sr = internal::random<Index>(1,rows) - 1;
+ Index nr = internal::random<Index>(1,rows-sr);
+ Index sc = internal::random<Index>(1,cols) - 1;
+ Index nc = internal::random<Index>(1,cols-sc);
+
+ COMPARE_CORNER(topRows(r), block(0,0,r,cols));
+ COMPARE_CORNER(middleRows(sr,nr), block(sr,0,nr,cols));
+ COMPARE_CORNER(bottomRows(r), block(rows-r,0,r,cols));
+ COMPARE_CORNER(leftCols(c), block(0,0,rows,c));
+ COMPARE_CORNER(middleCols(sc,nc), block(0,sc,rows,nc));
+ COMPARE_CORNER(rightCols(c), block(0,cols-c,rows,c));
+}
+
+template<typename MatrixType, int CRows, int CCols, int SRows, int SCols> void corners_fixedsize()
+{
+ MatrixType matrix = MatrixType::Random();
+ const MatrixType const_matrix = MatrixType::Random();
+
+ enum {
+ rows = MatrixType::RowsAtCompileTime,
+ cols = MatrixType::ColsAtCompileTime,
+ r = CRows,
+ c = CCols,
+ sr = SRows,
+ sc = SCols
+ };
+
+ VERIFY_IS_EQUAL((matrix.template topLeftCorner<r,c>()), (matrix.template block<r,c>(0,0)));
+ VERIFY_IS_EQUAL((matrix.template topRightCorner<r,c>()), (matrix.template block<r,c>(0,cols-c)));
+ VERIFY_IS_EQUAL((matrix.template bottomLeftCorner<r,c>()), (matrix.template block<r,c>(rows-r,0)));
+ VERIFY_IS_EQUAL((matrix.template bottomRightCorner<r,c>()), (matrix.template block<r,c>(rows-r,cols-c)));
+
+ VERIFY_IS_EQUAL((matrix.template topRows<r>()), (matrix.template block<r,cols>(0,0)));
+ VERIFY_IS_EQUAL((matrix.template middleRows<r>(sr)), (matrix.template block<r,cols>(sr,0)));
+ VERIFY_IS_EQUAL((matrix.template bottomRows<r>()), (matrix.template block<r,cols>(rows-r,0)));
+ VERIFY_IS_EQUAL((matrix.template leftCols<c>()), (matrix.template block<rows,c>(0,0)));
+ VERIFY_IS_EQUAL((matrix.template middleCols<c>(sc)), (matrix.template block<rows,c>(0,sc)));
+ VERIFY_IS_EQUAL((matrix.template rightCols<c>()), (matrix.template block<rows,c>(0,cols-c)));
+
+ VERIFY_IS_EQUAL((const_matrix.template topLeftCorner<r,c>()), (const_matrix.template block<r,c>(0,0)));
+ VERIFY_IS_EQUAL((const_matrix.template topRightCorner<r,c>()), (const_matrix.template block<r,c>(0,cols-c)));
+ VERIFY_IS_EQUAL((const_matrix.template bottomLeftCorner<r,c>()), (const_matrix.template block<r,c>(rows-r,0)));
+ VERIFY_IS_EQUAL((const_matrix.template bottomRightCorner<r,c>()), (const_matrix.template block<r,c>(rows-r,cols-c)));
+
+ VERIFY_IS_EQUAL((const_matrix.template topRows<r>()), (const_matrix.template block<r,cols>(0,0)));
+ VERIFY_IS_EQUAL((const_matrix.template middleRows<r>(sr)), (const_matrix.template block<r,cols>(sr,0)));
+ VERIFY_IS_EQUAL((const_matrix.template bottomRows<r>()), (const_matrix.template block<r,cols>(rows-r,0)));
+ VERIFY_IS_EQUAL((const_matrix.template leftCols<c>()), (const_matrix.template block<rows,c>(0,0)));
+ VERIFY_IS_EQUAL((const_matrix.template middleCols<c>(sc)), (const_matrix.template block<rows,c>(0,sc)));
+ VERIFY_IS_EQUAL((const_matrix.template rightCols<c>()), (const_matrix.template block<rows,c>(0,cols-c)));
+}
+
+void test_corners()
+{
+ for(int i = 0; i < g_repeat; i++) {
+ CALL_SUBTEST_1( corners(Matrix<float, 1, 1>()) );
+ CALL_SUBTEST_2( corners(Matrix4d()) );
+ CALL_SUBTEST_3( corners(Matrix<int,10,12>()) );
+ CALL_SUBTEST_4( corners(MatrixXcf(5, 7)) );
+ CALL_SUBTEST_5( corners(MatrixXf(21, 20)) );
+
+ CALL_SUBTEST_1(( corners_fixedsize<Matrix<float, 1, 1>, 1, 1, 0, 0>() ));
+ CALL_SUBTEST_2(( corners_fixedsize<Matrix4d,2,2,1,1>() ));
+ CALL_SUBTEST_3(( corners_fixedsize<Matrix<int,10,12>,4,7,5,2>() ));
+ }
+}
diff --git a/test/cwiseop.cpp b/test/cwiseop.cpp
new file mode 100644
index 000000000..ca6e4211c
--- /dev/null
+++ b/test/cwiseop.cpp
@@ -0,0 +1,165 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra.
+//
+// Copyright (C) 2008 Gael Guennebaud <gael.guennebaud@inria.fr>
+// Copyright (C) 2006-2008 Benoit Jacob <jacob.benoit.1@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/.
+
+#define EIGEN2_SUPPORT
+#define EIGEN_NO_STATIC_ASSERT
+#include "main.h"
+#include <functional>
+
+#ifdef min
+#undef min
+#endif
+
+#ifdef max
+#undef max
+#endif
+
+using namespace std;
+
+template<typename Scalar> struct AddIfNull {
+ const Scalar operator() (const Scalar a, const Scalar b) const {return a<=1e-3 ? b : a;}
+ enum { Cost = NumTraits<Scalar>::AddCost };
+};
+
+template<typename MatrixType> void cwiseops(const MatrixType& m)
+{
+ typedef typename MatrixType::Index Index;
+ typedef typename MatrixType::Scalar Scalar;
+ typedef typename NumTraits<Scalar>::Real RealScalar;
+ typedef Matrix<Scalar, MatrixType::RowsAtCompileTime, 1> VectorType;
+
+ Index rows = m.rows();
+ Index cols = m.cols();
+
+ MatrixType m1 = MatrixType::Random(rows, cols),
+ m2 = MatrixType::Random(rows, cols),
+ m3(rows, cols),
+ m4(rows, cols),
+ mzero = MatrixType::Zero(rows, cols),
+ mones = MatrixType::Ones(rows, cols),
+ identity = Matrix<Scalar, MatrixType::RowsAtCompileTime, MatrixType::RowsAtCompileTime>
+ ::Identity(rows, rows);
+ VectorType vzero = VectorType::Zero(rows),
+ vones = VectorType::Ones(rows),
+ v3(rows);
+
+ Index r = internal::random<Index>(0, rows-1),
+ c = internal::random<Index>(0, cols-1);
+
+ Scalar s1 = internal::random<Scalar>();
+
+ // test Zero, Ones, Constant, and the set* variants
+ m3 = MatrixType::Constant(rows, cols, s1);
+ for (int j=0; j<cols; ++j)
+ for (int i=0; i<rows; ++i)
+ {
+ VERIFY_IS_APPROX(mzero(i,j), Scalar(0));
+ VERIFY_IS_APPROX(mones(i,j), Scalar(1));
+ VERIFY_IS_APPROX(m3(i,j), s1);
+ }
+ VERIFY(mzero.isZero());
+ VERIFY(mones.isOnes());
+ VERIFY(m3.isConstant(s1));
+ VERIFY(identity.isIdentity());
+ VERIFY_IS_APPROX(m4.setConstant(s1), m3);
+ VERIFY_IS_APPROX(m4.setConstant(rows,cols,s1), m3);
+ VERIFY_IS_APPROX(m4.setZero(), mzero);
+ VERIFY_IS_APPROX(m4.setZero(rows,cols), mzero);
+ VERIFY_IS_APPROX(m4.setOnes(), mones);
+ VERIFY_IS_APPROX(m4.setOnes(rows,cols), mones);
+ m4.fill(s1);
+ VERIFY_IS_APPROX(m4, m3);
+
+ VERIFY_IS_APPROX(v3.setConstant(rows, s1), VectorType::Constant(rows,s1));
+ VERIFY_IS_APPROX(v3.setZero(rows), vzero);
+ VERIFY_IS_APPROX(v3.setOnes(rows), vones);
+
+ m2 = m2.template binaryExpr<AddIfNull<Scalar> >(mones);
+
+ VERIFY_IS_APPROX(m1.cwise().pow(2), m1.cwise().abs2());
+ VERIFY_IS_APPROX(m1.cwise().pow(2), m1.cwise().square());
+ VERIFY_IS_APPROX(m1.cwise().pow(3), m1.cwise().cube());
+
+ VERIFY_IS_APPROX(m1 + mones, m1.cwise()+Scalar(1));
+ VERIFY_IS_APPROX(m1 - mones, m1.cwise()-Scalar(1));
+ m3 = m1; m3.cwise() += 1;
+ VERIFY_IS_APPROX(m1 + mones, m3);
+ m3 = m1; m3.cwise() -= 1;
+ VERIFY_IS_APPROX(m1 - mones, m3);
+
+ VERIFY_IS_APPROX(m2, m2.cwise() * mones);
+ VERIFY_IS_APPROX(m1.cwise() * m2, m2.cwise() * m1);
+ m3 = m1;
+ m3.cwise() *= m2;
+ VERIFY_IS_APPROX(m3, m1.cwise() * m2);
+
+ VERIFY_IS_APPROX(mones, m2.cwise()/m2);
+ if(!NumTraits<Scalar>::IsInteger)
+ {
+ VERIFY_IS_APPROX(m1.cwise() / m2, m1.cwise() * (m2.cwise().inverse()));
+ m3 = m1.cwise().abs().cwise().sqrt();
+ VERIFY_IS_APPROX(m3.cwise().square(), m1.cwise().abs());
+ VERIFY_IS_APPROX(m1.cwise().square().cwise().sqrt(), m1.cwise().abs());
+ VERIFY_IS_APPROX(m1.cwise().abs().cwise().log().cwise().exp() , m1.cwise().abs());
+
+ VERIFY_IS_APPROX(m1.cwise().pow(2), m1.cwise().square());
+ m3 = (m1.cwise().abs().cwise()<=RealScalar(0.01)).select(mones,m1);
+ VERIFY_IS_APPROX(m3.cwise().pow(-1), m3.cwise().inverse());
+ m3 = m1.cwise().abs();
+ VERIFY_IS_APPROX(m3.cwise().pow(RealScalar(0.5)), m3.cwise().sqrt());
+
+// VERIFY_IS_APPROX(m1.cwise().tan(), m1.cwise().sin().cwise() / m1.cwise().cos());
+ VERIFY_IS_APPROX(mones, m1.cwise().sin().cwise().square() + m1.cwise().cos().cwise().square());
+ m3 = m1;
+ m3.cwise() /= m2;
+ VERIFY_IS_APPROX(m3, m1.cwise() / m2);
+ }
+
+ // check min
+ VERIFY_IS_APPROX( m1.cwise().min(m2), m2.cwise().min(m1) );
+ VERIFY_IS_APPROX( m1.cwise().min(m1+mones), m1 );
+ VERIFY_IS_APPROX( m1.cwise().min(m1-mones), m1-mones );
+
+ // check max
+ VERIFY_IS_APPROX( m1.cwise().max(m2), m2.cwise().max(m1) );
+ VERIFY_IS_APPROX( m1.cwise().max(m1-mones), m1 );
+ VERIFY_IS_APPROX( m1.cwise().max(m1+mones), m1+mones );
+
+ VERIFY( (m1.cwise() == m1).all() );
+ VERIFY( (m1.cwise() != m2).any() );
+ VERIFY(!(m1.cwise() == (m1+mones)).any() );
+ if (rows*cols>1)
+ {
+ m3 = m1;
+ m3(r,c) += 1;
+ VERIFY( (m1.cwise() == m3).any() );
+ VERIFY( !(m1.cwise() == m3).all() );
+ }
+ VERIFY( (m1.cwise().min(m2).cwise() <= m2).all() );
+ VERIFY( (m1.cwise().max(m2).cwise() >= m2).all() );
+ VERIFY( (m1.cwise().min(m2).cwise() < (m1+mones)).all() );
+ VERIFY( (m1.cwise().max(m2).cwise() > (m1-mones)).all() );
+
+ VERIFY( (m1.cwise()<m1.unaryExpr(bind2nd(plus<Scalar>(), Scalar(1)))).all() );
+ VERIFY( !(m1.cwise()<m1.unaryExpr(bind2nd(minus<Scalar>(), Scalar(1)))).all() );
+ VERIFY( !(m1.cwise()>m1.unaryExpr(bind2nd(plus<Scalar>(), Scalar(1)))).any() );
+}
+
+void test_cwiseop()
+{
+ for(int i = 0; i < g_repeat ; i++) {
+ CALL_SUBTEST_1( cwiseops(Matrix<float, 1, 1>()) );
+ CALL_SUBTEST_2( cwiseops(Matrix4d()) );
+ CALL_SUBTEST_3( cwiseops(MatrixXf(internal::random<int>(1,EIGEN_TEST_MAX_SIZE), internal::random<int>(1,EIGEN_TEST_MAX_SIZE))) );
+ CALL_SUBTEST_4( cwiseops(MatrixXf(internal::random<int>(1,EIGEN_TEST_MAX_SIZE), internal::random<int>(1,EIGEN_TEST_MAX_SIZE))) );
+ CALL_SUBTEST_5( cwiseops(MatrixXi(internal::random<int>(1,EIGEN_TEST_MAX_SIZE), internal::random<int>(1,EIGEN_TEST_MAX_SIZE))) );
+ CALL_SUBTEST_6( cwiseops(MatrixXd(internal::random<int>(1,EIGEN_TEST_MAX_SIZE), internal::random<int>(1,EIGEN_TEST_MAX_SIZE))) );
+ }
+}
diff --git a/test/determinant.cpp b/test/determinant.cpp
new file mode 100644
index 000000000..e93f2f297
--- /dev/null
+++ b/test/determinant.cpp
@@ -0,0 +1,67 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra.
+//
+// Copyright (C) 2008 Benoit Jacob <jacob.benoit.1@gmail.com>
+// Copyright (C) 2008 Gael Guennebaud <gael.guennebaud@inria.fr>
+//
+// This Source Code Form is subject to the terms of the Mozilla
+// Public License v. 2.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 "main.h"
+#include <Eigen/LU>
+
+template<typename MatrixType> void determinant(const MatrixType& m)
+{
+ /* this test covers the following files:
+ Determinant.h
+ */
+ typedef typename MatrixType::Index Index;
+ Index size = m.rows();
+
+ MatrixType m1(size, size), m2(size, size);
+ m1.setRandom();
+ m2.setRandom();
+ typedef typename MatrixType::Scalar Scalar;
+ Scalar x = internal::random<Scalar>();
+ VERIFY_IS_APPROX(MatrixType::Identity(size, size).determinant(), Scalar(1));
+ VERIFY_IS_APPROX((m1*m2).eval().determinant(), m1.determinant() * m2.determinant());
+ if(size==1) return;
+ Index i = internal::random<Index>(0, size-1);
+ Index j;
+ do {
+ j = internal::random<Index>(0, size-1);
+ } while(j==i);
+ m2 = m1;
+ m2.row(i).swap(m2.row(j));
+ VERIFY_IS_APPROX(m2.determinant(), -m1.determinant());
+ m2 = m1;
+ m2.col(i).swap(m2.col(j));
+ VERIFY_IS_APPROX(m2.determinant(), -m1.determinant());
+ VERIFY_IS_APPROX(m2.determinant(), m2.transpose().determinant());
+ VERIFY_IS_APPROX(internal::conj(m2.determinant()), m2.adjoint().determinant());
+ m2 = m1;
+ m2.row(i) += x*m2.row(j);
+ VERIFY_IS_APPROX(m2.determinant(), m1.determinant());
+ m2 = m1;
+ m2.row(i) *= x;
+ VERIFY_IS_APPROX(m2.determinant(), m1.determinant() * x);
+
+ // check empty matrix
+ VERIFY_IS_APPROX(m2.block(0,0,0,0).determinant(), Scalar(1));
+}
+
+void test_determinant()
+{
+ int s;
+ for(int i = 0; i < g_repeat; i++) {
+ CALL_SUBTEST_1( determinant(Matrix<float, 1, 1>()) );
+ CALL_SUBTEST_2( determinant(Matrix<double, 2, 2>()) );
+ CALL_SUBTEST_3( determinant(Matrix<double, 3, 3>()) );
+ CALL_SUBTEST_4( determinant(Matrix<double, 4, 4>()) );
+ CALL_SUBTEST_5( determinant(Matrix<std::complex<double>, 10, 10>()) );
+ s = internal::random<int>(1,EIGEN_TEST_MAX_SIZE/4);
+ CALL_SUBTEST_6( determinant(MatrixXd(s, s)) );
+ }
+ EIGEN_UNUSED_VARIABLE(s)
+}
diff --git a/test/diagonal.cpp b/test/diagonal.cpp
new file mode 100644
index 000000000..95cd10372
--- /dev/null
+++ b/test/diagonal.cpp
@@ -0,0 +1,83 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra.
+//
+// Copyright (C) 2006-2010 Benoit Jacob <jacob.benoit.1@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 "main.h"
+
+template<typename MatrixType> void diagonal(const MatrixType& m)
+{
+ typedef typename MatrixType::Index Index;
+ typedef typename MatrixType::Scalar Scalar;
+ typedef typename MatrixType::RealScalar RealScalar;
+ typedef Matrix<Scalar, MatrixType::RowsAtCompileTime, 1> VectorType;
+ typedef Matrix<Scalar, 1, MatrixType::ColsAtCompileTime> RowVectorType;
+
+ Index rows = m.rows();
+ Index cols = m.cols();
+
+ MatrixType m1 = MatrixType::Random(rows, cols),
+ m2 = MatrixType::Random(rows, cols);
+
+ //check diagonal()
+ VERIFY_IS_APPROX(m1.diagonal(), m1.transpose().diagonal());
+ m2.diagonal() = 2 * m1.diagonal();
+ m2.diagonal()[0] *= 3;
+
+ if (rows>2)
+ {
+ enum {
+ N1 = MatrixType::RowsAtCompileTime>1 ? 1 : 0,
+ N2 = MatrixType::RowsAtCompileTime>2 ? -2 : 0
+ };
+
+ // check sub/super diagonal
+ if(m1.template diagonal<N1>().RowsAtCompileTime!=Dynamic)
+ {
+ VERIFY(m1.template diagonal<N1>().RowsAtCompileTime == m1.diagonal(N1).size());
+ }
+ if(m1.template diagonal<N2>().RowsAtCompileTime!=Dynamic)
+ {
+ VERIFY(m1.template diagonal<N2>().RowsAtCompileTime == m1.diagonal(N2).size());
+ }
+
+ m2.template diagonal<N1>() = 2 * m1.template diagonal<N1>();
+ VERIFY_IS_APPROX(m2.template diagonal<N1>(), static_cast<Scalar>(2) * m1.diagonal(N1));
+ m2.template diagonal<N1>()[0] *= 3;
+ VERIFY_IS_APPROX(m2.template diagonal<N1>()[0], static_cast<Scalar>(6) * m1.template diagonal<N1>()[0]);
+
+
+ m2.template diagonal<N2>() = 2 * m1.template diagonal<N2>();
+ m2.template diagonal<N2>()[0] *= 3;
+ VERIFY_IS_APPROX(m2.template diagonal<N2>()[0], static_cast<Scalar>(6) * m1.template diagonal<N2>()[0]);
+
+ m2.diagonal(N1) = 2 * m1.diagonal(N1);
+ VERIFY_IS_APPROX(m2.diagonal<N1>(), static_cast<Scalar>(2) * m1.diagonal(N1));
+ m2.diagonal(N1)[0] *= 3;
+ VERIFY_IS_APPROX(m2.diagonal(N1)[0], static_cast<Scalar>(6) * m1.diagonal(N1)[0]);
+
+ m2.diagonal(N2) = 2 * m1.diagonal(N2);
+ VERIFY_IS_APPROX(m2.diagonal<N2>(), static_cast<Scalar>(2) * m1.diagonal(N2));
+ m2.diagonal(N2)[0] *= 3;
+ VERIFY_IS_APPROX(m2.diagonal(N2)[0], static_cast<Scalar>(6) * m1.diagonal(N2)[0]);
+ }
+}
+
+void test_diagonal()
+{
+ for(int i = 0; i < g_repeat; i++) {
+ CALL_SUBTEST_1( diagonal(Matrix<float, 1, 1>()) );
+ CALL_SUBTEST_1( diagonal(Matrix<float, 4, 9>()) );
+ CALL_SUBTEST_1( diagonal(Matrix<float, 7, 3>()) );
+ CALL_SUBTEST_2( diagonal(Matrix4d()) );
+ CALL_SUBTEST_2( diagonal(MatrixXcf(internal::random<int>(1,EIGEN_TEST_MAX_SIZE), internal::random<int>(1,EIGEN_TEST_MAX_SIZE))) );
+ CALL_SUBTEST_2( diagonal(MatrixXi(internal::random<int>(1,EIGEN_TEST_MAX_SIZE), internal::random<int>(1,EIGEN_TEST_MAX_SIZE))) );
+ CALL_SUBTEST_2( diagonal(MatrixXcd(internal::random<int>(1,EIGEN_TEST_MAX_SIZE), internal::random<int>(1,EIGEN_TEST_MAX_SIZE))) );
+ CALL_SUBTEST_1( diagonal(MatrixXf(internal::random<int>(1,EIGEN_TEST_MAX_SIZE), internal::random<int>(1,EIGEN_TEST_MAX_SIZE))) );
+ CALL_SUBTEST_1( diagonal(Matrix<float,Dynamic,4>(3, 4)) );
+ }
+}
diff --git a/test/diagonalmatrices.cpp b/test/diagonalmatrices.cpp
new file mode 100644
index 000000000..3f5776dfc
--- /dev/null
+++ b/test/diagonalmatrices.cpp
@@ -0,0 +1,94 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra.
+//
+// Copyright (C) 2009 Benoit Jacob <jacob.benoit.1@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 "main.h"
+using namespace std;
+template<typename MatrixType> void diagonalmatrices(const MatrixType& m)
+{
+ typedef typename MatrixType::Index Index;
+ typedef typename MatrixType::Scalar Scalar;
+ typedef typename MatrixType::RealScalar RealScalar;
+ enum { Rows = MatrixType::RowsAtCompileTime, Cols = MatrixType::ColsAtCompileTime };
+ typedef Matrix<Scalar, Rows, 1> VectorType;
+ typedef Matrix<Scalar, 1, Cols> RowVectorType;
+ typedef Matrix<Scalar, Rows, Rows> SquareMatrixType;
+ typedef DiagonalMatrix<Scalar, Rows> LeftDiagonalMatrix;
+ typedef DiagonalMatrix<Scalar, Cols> RightDiagonalMatrix;
+ typedef Matrix<Scalar, Rows==Dynamic?Dynamic:2*Rows, Cols==Dynamic?Dynamic:2*Cols> BigMatrix;
+ Index rows = m.rows();
+ Index cols = m.cols();
+
+ MatrixType m1 = MatrixType::Random(rows, cols),
+ m2 = MatrixType::Random(rows, cols);
+ VectorType v1 = VectorType::Random(rows),
+ v2 = VectorType::Random(rows);
+ RowVectorType rv1 = RowVectorType::Random(cols),
+ rv2 = RowVectorType::Random(cols);
+ LeftDiagonalMatrix ldm1(v1), ldm2(v2);
+ RightDiagonalMatrix rdm1(rv1), rdm2(rv2);
+
+ SquareMatrixType sq_m1 (v1.asDiagonal());
+ VERIFY_IS_APPROX(sq_m1, v1.asDiagonal().toDenseMatrix());
+ sq_m1 = v1.asDiagonal();
+ VERIFY_IS_APPROX(sq_m1, v1.asDiagonal().toDenseMatrix());
+ SquareMatrixType sq_m2 = v1.asDiagonal();
+ VERIFY_IS_APPROX(sq_m1, sq_m2);
+
+ ldm1 = v1.asDiagonal();
+ LeftDiagonalMatrix ldm3(v1);
+ VERIFY_IS_APPROX(ldm1.diagonal(), ldm3.diagonal());
+ LeftDiagonalMatrix ldm4 = v1.asDiagonal();
+ VERIFY_IS_APPROX(ldm1.diagonal(), ldm4.diagonal());
+
+ sq_m1.block(0,0,rows,rows) = ldm1;
+ VERIFY_IS_APPROX(sq_m1, ldm1.toDenseMatrix());
+ sq_m1.transpose() = ldm1;
+ VERIFY_IS_APPROX(sq_m1, ldm1.toDenseMatrix());
+
+ Index i = internal::random<Index>(0, rows-1);
+ Index j = internal::random<Index>(0, cols-1);
+
+ VERIFY_IS_APPROX( ((ldm1 * m1)(i,j)) , ldm1.diagonal()(i) * m1(i,j) );
+ VERIFY_IS_APPROX( ((ldm1 * (m1+m2))(i,j)) , ldm1.diagonal()(i) * (m1+m2)(i,j) );
+ VERIFY_IS_APPROX( ((m1 * rdm1)(i,j)) , rdm1.diagonal()(j) * m1(i,j) );
+ VERIFY_IS_APPROX( ((v1.asDiagonal() * m1)(i,j)) , v1(i) * m1(i,j) );
+ VERIFY_IS_APPROX( ((m1 * rv1.asDiagonal())(i,j)) , rv1(j) * m1(i,j) );
+ VERIFY_IS_APPROX( (((v1+v2).asDiagonal() * m1)(i,j)) , (v1+v2)(i) * m1(i,j) );
+ VERIFY_IS_APPROX( (((v1+v2).asDiagonal() * (m1+m2))(i,j)) , (v1+v2)(i) * (m1+m2)(i,j) );
+ VERIFY_IS_APPROX( ((m1 * (rv1+rv2).asDiagonal())(i,j)) , (rv1+rv2)(j) * m1(i,j) );
+ VERIFY_IS_APPROX( (((m1+m2) * (rv1+rv2).asDiagonal())(i,j)) , (rv1+rv2)(j) * (m1+m2)(i,j) );
+
+ BigMatrix big;
+ big.setZero(2*rows, 2*cols);
+
+ big.block(i,j,rows,cols) = m1;
+ big.block(i,j,rows,cols) = v1.asDiagonal() * big.block(i,j,rows,cols);
+
+ VERIFY_IS_APPROX((big.block(i,j,rows,cols)) , v1.asDiagonal() * m1 );
+
+ big.block(i,j,rows,cols) = m1;
+ big.block(i,j,rows,cols) = big.block(i,j,rows,cols) * rv1.asDiagonal();
+ VERIFY_IS_APPROX((big.block(i,j,rows,cols)) , m1 * rv1.asDiagonal() );
+
+}
+
+void test_diagonalmatrices()
+{
+ for(int i = 0; i < g_repeat; i++) {
+ CALL_SUBTEST_1( diagonalmatrices(Matrix<float, 1, 1>()) );
+ CALL_SUBTEST_2( diagonalmatrices(Matrix3f()) );
+ CALL_SUBTEST_3( diagonalmatrices(Matrix<double,3,3,RowMajor>()) );
+ CALL_SUBTEST_4( diagonalmatrices(Matrix4d()) );
+ CALL_SUBTEST_5( diagonalmatrices(Matrix<float,4,4,RowMajor>()) );
+ CALL_SUBTEST_6( diagonalmatrices(MatrixXcf(internal::random<int>(1,EIGEN_TEST_MAX_SIZE), internal::random<int>(1,EIGEN_TEST_MAX_SIZE))) );
+ CALL_SUBTEST_7( diagonalmatrices(MatrixXi(internal::random<int>(1,EIGEN_TEST_MAX_SIZE), internal::random<int>(1,EIGEN_TEST_MAX_SIZE))) );
+ CALL_SUBTEST_8( diagonalmatrices(Matrix<double,Dynamic,Dynamic,RowMajor>(internal::random<int>(1,EIGEN_TEST_MAX_SIZE), internal::random<int>(1,EIGEN_TEST_MAX_SIZE))) );
+ CALL_SUBTEST_9( diagonalmatrices(MatrixXf(internal::random<int>(1,EIGEN_TEST_MAX_SIZE), internal::random<int>(1,EIGEN_TEST_MAX_SIZE))) );
+ }
+}
diff --git a/test/dontalign.cpp b/test/dontalign.cpp
new file mode 100644
index 000000000..4643cfed6
--- /dev/null
+++ b/test/dontalign.cpp
@@ -0,0 +1,63 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra.
+//
+// Copyright (C) 2011 Benoit Jacob <jacob.benoit.1@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/.
+
+#if defined EIGEN_TEST_PART_1 || defined EIGEN_TEST_PART_2 || defined EIGEN_TEST_PART_3 || defined EIGEN_TEST_PART_4
+#define EIGEN_DONT_ALIGN
+#elif defined EIGEN_TEST_PART_5 || defined EIGEN_TEST_PART_6 || defined EIGEN_TEST_PART_7 || defined EIGEN_TEST_PART_8
+#define EIGEN_DONT_ALIGN_STATICALLY
+#endif
+
+#include "main.h"
+#include <Eigen/Dense>
+
+template<typename MatrixType>
+void dontalign(const MatrixType& m)
+{
+ typedef typename MatrixType::Index Index;
+ typedef typename MatrixType::Scalar Scalar;
+ typedef Matrix<Scalar, MatrixType::RowsAtCompileTime, 1> VectorType;
+ typedef Matrix<Scalar, MatrixType::RowsAtCompileTime, MatrixType::RowsAtCompileTime> SquareMatrixType;
+
+ Index rows = m.rows();
+ Index cols = m.cols();
+
+ MatrixType a = MatrixType::Random(rows,cols);
+ SquareMatrixType square = SquareMatrixType::Random(rows,rows);
+ VectorType v = VectorType::Random(rows);
+
+ VERIFY_IS_APPROX(v, square * square.colPivHouseholderQr().solve(v));
+ square = square.inverse().eval();
+ a = square * a;
+ square = square*square;
+ v = square * v;
+ v = a.adjoint() * v;
+ VERIFY(square.determinant() != Scalar(0));
+
+ // bug 219: MapAligned() was giving an assert with EIGEN_DONT_ALIGN, because Map Flags were miscomputed
+ Scalar* array = internal::aligned_new<Scalar>(rows);
+ v = VectorType::MapAligned(array, rows);
+ internal::aligned_delete(array, rows);
+}
+
+void test_dontalign()
+{
+#if defined EIGEN_TEST_PART_1 || defined EIGEN_TEST_PART_5
+ dontalign(Matrix3d());
+ dontalign(Matrix4f());
+#elif defined EIGEN_TEST_PART_2 || defined EIGEN_TEST_PART_6
+ dontalign(Matrix3cd());
+ dontalign(Matrix4cf());
+#elif defined EIGEN_TEST_PART_3 || defined EIGEN_TEST_PART_7
+ dontalign(Matrix<float, 32, 32>());
+ dontalign(Matrix<std::complex<float>, 32, 32>());
+#elif defined EIGEN_TEST_PART_4 || defined EIGEN_TEST_PART_8
+ dontalign(MatrixXd(32, 32));
+ dontalign(MatrixXcf(32, 32));
+#endif
+}
diff --git a/test/dynalloc.cpp b/test/dynalloc.cpp
new file mode 100644
index 000000000..c7ccbffef
--- /dev/null
+++ b/test/dynalloc.cpp
@@ -0,0 +1,133 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra.
+//
+// Copyright (C) 2008 Gael Guennebaud <gael.guennebaud@inria.fr>
+//
+// This Source Code Form is subject to the terms of the Mozilla
+// Public License v. 2.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 "main.h"
+
+#if EIGEN_ALIGN
+#define ALIGNMENT 16
+#else
+#define ALIGNMENT 1
+#endif
+
+void check_handmade_aligned_malloc()
+{
+ for(int i = 1; i < 1000; i++)
+ {
+ char *p = (char*)internal::handmade_aligned_malloc(i);
+ VERIFY(size_t(p)%ALIGNMENT==0);
+ // if the buffer is wrongly allocated this will give a bad write --> check with valgrind
+ for(int j = 0; j < i; j++) p[j]=0;
+ internal::handmade_aligned_free(p);
+ }
+}
+
+void check_aligned_malloc()
+{
+ for(int i = 1; i < 1000; i++)
+ {
+ char *p = (char*)internal::aligned_malloc(i);
+ VERIFY(size_t(p)%ALIGNMENT==0);
+ // if the buffer is wrongly allocated this will give a bad write --> check with valgrind
+ for(int j = 0; j < i; j++) p[j]=0;
+ internal::aligned_free(p);
+ }
+}
+
+void check_aligned_new()
+{
+ for(int i = 1; i < 1000; i++)
+ {
+ float *p = internal::aligned_new<float>(i);
+ VERIFY(size_t(p)%ALIGNMENT==0);
+ // if the buffer is wrongly allocated this will give a bad write --> check with valgrind
+ for(int j = 0; j < i; j++) p[j]=0;
+ internal::aligned_delete(p,i);
+ }
+}
+
+void check_aligned_stack_alloc()
+{
+ for(int i = 1; i < 1000; i++)
+ {
+ ei_declare_aligned_stack_constructed_variable(float,p,i,0);
+ VERIFY(size_t(p)%ALIGNMENT==0);
+ // if the buffer is wrongly allocated this will give a bad write --> check with valgrind
+ for(int j = 0; j < i; j++) p[j]=0;
+ }
+}
+
+
+// test compilation with both a struct and a class...
+struct MyStruct
+{
+ EIGEN_MAKE_ALIGNED_OPERATOR_NEW
+ char dummychar;
+ Vector4f avec;
+};
+
+class MyClassA
+{
+ public:
+ EIGEN_MAKE_ALIGNED_OPERATOR_NEW
+ char dummychar;
+ Vector4f avec;
+};
+
+template<typename T> void check_dynaligned()
+{
+ T* obj = new T;
+ VERIFY(size_t(obj)%ALIGNMENT==0);
+ delete obj;
+}
+
+void test_dynalloc()
+{
+ // low level dynamic memory allocation
+ CALL_SUBTEST(check_handmade_aligned_malloc());
+ CALL_SUBTEST(check_aligned_malloc());
+ CALL_SUBTEST(check_aligned_new());
+ CALL_SUBTEST(check_aligned_stack_alloc());
+
+ for (int i=0; i<g_repeat*100; ++i)
+ {
+ CALL_SUBTEST(check_dynaligned<Vector4f>() );
+ CALL_SUBTEST(check_dynaligned<Vector2d>() );
+ CALL_SUBTEST(check_dynaligned<Matrix4f>() );
+ CALL_SUBTEST(check_dynaligned<Vector4d>() );
+ CALL_SUBTEST(check_dynaligned<Vector4i>() );
+ }
+
+ // check static allocation, who knows ?
+ #if EIGEN_ALIGN_STATICALLY
+ {
+ MyStruct foo0; VERIFY(size_t(foo0.avec.data())%ALIGNMENT==0);
+ MyClassA fooA; VERIFY(size_t(fooA.avec.data())%ALIGNMENT==0);
+ }
+
+ // dynamic allocation, single object
+ for (int i=0; i<g_repeat*100; ++i)
+ {
+ MyStruct *foo0 = new MyStruct(); VERIFY(size_t(foo0->avec.data())%ALIGNMENT==0);
+ MyClassA *fooA = new MyClassA(); VERIFY(size_t(fooA->avec.data())%ALIGNMENT==0);
+ delete foo0;
+ delete fooA;
+ }
+
+ // dynamic allocation, array
+ const int N = 10;
+ for (int i=0; i<g_repeat*100; ++i)
+ {
+ MyStruct *foo0 = new MyStruct[N]; VERIFY(size_t(foo0->avec.data())%ALIGNMENT==0);
+ MyClassA *fooA = new MyClassA[N]; VERIFY(size_t(fooA->avec.data())%ALIGNMENT==0);
+ delete[] foo0;
+ delete[] fooA;
+ }
+ #endif
+
+}
diff --git a/test/eigen2/CMakeLists.txt b/test/eigen2/CMakeLists.txt
new file mode 100644
index 000000000..84931e037
--- /dev/null
+++ b/test/eigen2/CMakeLists.txt
@@ -0,0 +1,60 @@
+add_custom_target(eigen2_buildtests)
+add_custom_target(eigen2_check COMMAND "ctest -R eigen2")
+add_dependencies(eigen2_check eigen2_buildtests)
+add_dependencies(buildtests eigen2_buildtests)
+
+add_definitions("-DEIGEN2_SUPPORT_STAGE10_FULL_EIGEN2_API")
+
+ei_add_test(eigen2_meta)
+ei_add_test(eigen2_sizeof)
+ei_add_test(eigen2_dynalloc)
+ei_add_test(eigen2_nomalloc)
+#ei_add_test(eigen2_first_aligned)
+ei_add_test(eigen2_mixingtypes)
+#ei_add_test(eigen2_packetmath)
+ei_add_test(eigen2_unalignedassert)
+#ei_add_test(eigen2_vectorization_logic)
+ei_add_test(eigen2_basicstuff)
+ei_add_test(eigen2_linearstructure)
+ei_add_test(eigen2_cwiseop)
+ei_add_test(eigen2_sum)
+ei_add_test(eigen2_product_small)
+ei_add_test(eigen2_product_large ${EI_OFLAG})
+ei_add_test(eigen2_adjoint)
+ei_add_test(eigen2_submatrices)
+ei_add_test(eigen2_miscmatrices)
+ei_add_test(eigen2_commainitializer)
+ei_add_test(eigen2_smallvectors)
+ei_add_test(eigen2_map)
+ei_add_test(eigen2_array)
+ei_add_test(eigen2_triangular)
+ei_add_test(eigen2_cholesky " " "${GSL_LIBRARIES}")
+ei_add_test(eigen2_lu ${EI_OFLAG})
+ei_add_test(eigen2_determinant ${EI_OFLAG})
+ei_add_test(eigen2_inverse)
+ei_add_test(eigen2_qr)
+ei_add_test(eigen2_eigensolver " " "${GSL_LIBRARIES}")
+ei_add_test(eigen2_svd)
+ei_add_test(eigen2_geometry)
+ei_add_test(eigen2_geometry_with_eigen2_prefix)
+ei_add_test(eigen2_hyperplane)
+ei_add_test(eigen2_parametrizedline)
+ei_add_test(eigen2_alignedbox)
+ei_add_test(eigen2_regression)
+ei_add_test(eigen2_stdvector)
+ei_add_test(eigen2_newstdvector)
+if(QT4_FOUND)
+ ei_add_test(eigen2_qtvector " " "${QT_QTCORE_LIBRARY}")
+endif(QT4_FOUND)
+# no support for eigen2 sparse module
+# if(NOT EIGEN_DEFAULT_TO_ROW_MAJOR)
+# ei_add_test(eigen2_sparse_vector)
+# ei_add_test(eigen2_sparse_basic)
+# ei_add_test(eigen2_sparse_solvers " " "${SPARSE_LIBS}")
+# ei_add_test(eigen2_sparse_product)
+# endif()
+ei_add_test(eigen2_swap)
+ei_add_test(eigen2_visitor)
+ei_add_test(eigen2_bug_132)
+
+ei_add_test(eigen2_prec_inverse_4x4 ${EI_OFLAG})
diff --git a/test/eigen2/eigen2_adjoint.cpp b/test/eigen2/eigen2_adjoint.cpp
new file mode 100644
index 000000000..8ec9c9202
--- /dev/null
+++ b/test/eigen2/eigen2_adjoint.cpp
@@ -0,0 +1,101 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra. Eigen itself is part of the KDE project.
+//
+// Copyright (C) 2006-2008 Benoit Jacob <jacob.benoit.1@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 "main.h"
+
+template<typename MatrixType> void adjoint(const MatrixType& m)
+{
+ /* this test covers the following files:
+ Transpose.h Conjugate.h Dot.h
+ */
+
+ typedef typename MatrixType::Scalar Scalar;
+ typedef typename NumTraits<Scalar>::Real RealScalar;
+ typedef Matrix<Scalar, MatrixType::RowsAtCompileTime, 1> VectorType;
+ typedef Matrix<Scalar, MatrixType::RowsAtCompileTime, MatrixType::RowsAtCompileTime> SquareMatrixType;
+ int rows = m.rows();
+ int cols = m.cols();
+
+ RealScalar largerEps = test_precision<RealScalar>();
+ if (ei_is_same_type<RealScalar,float>::ret)
+ largerEps = RealScalar(1e-3f);
+
+ MatrixType m1 = MatrixType::Random(rows, cols),
+ m2 = MatrixType::Random(rows, cols),
+ m3(rows, cols),
+ mzero = MatrixType::Zero(rows, cols),
+ identity = SquareMatrixType::Identity(rows, rows),
+ square = SquareMatrixType::Random(rows, rows);
+ VectorType v1 = VectorType::Random(rows),
+ v2 = VectorType::Random(rows),
+ v3 = VectorType::Random(rows),
+ vzero = VectorType::Zero(rows);
+
+ Scalar s1 = ei_random<Scalar>(),
+ s2 = ei_random<Scalar>();
+
+ // check basic compatibility of adjoint, transpose, conjugate
+ VERIFY_IS_APPROX(m1.transpose().conjugate().adjoint(), m1);
+ VERIFY_IS_APPROX(m1.adjoint().conjugate().transpose(), m1);
+
+ // check multiplicative behavior
+ VERIFY_IS_APPROX((m1.adjoint() * m2).adjoint(), m2.adjoint() * m1);
+ VERIFY_IS_APPROX((s1 * m1).adjoint(), ei_conj(s1) * m1.adjoint());
+
+ // check basic properties of dot, norm, norm2
+ typedef typename NumTraits<Scalar>::Real RealScalar;
+ VERIFY(ei_isApprox((s1 * v1 + s2 * v2).eigen2_dot(v3), s1 * v1.eigen2_dot(v3) + s2 * v2.eigen2_dot(v3), largerEps));
+ VERIFY(ei_isApprox(v3.eigen2_dot(s1 * v1 + s2 * v2), ei_conj(s1)*v3.eigen2_dot(v1)+ei_conj(s2)*v3.eigen2_dot(v2), largerEps));
+ VERIFY_IS_APPROX(ei_conj(v1.eigen2_dot(v2)), v2.eigen2_dot(v1));
+ VERIFY_IS_APPROX(ei_real(v1.eigen2_dot(v1)), v1.squaredNorm());
+ if(NumTraits<Scalar>::HasFloatingPoint)
+ VERIFY_IS_APPROX(v1.squaredNorm(), v1.norm() * v1.norm());
+ VERIFY_IS_MUCH_SMALLER_THAN(ei_abs(vzero.eigen2_dot(v1)), static_cast<RealScalar>(1));
+ if(NumTraits<Scalar>::HasFloatingPoint)
+ VERIFY_IS_MUCH_SMALLER_THAN(vzero.norm(), static_cast<RealScalar>(1));
+
+ // check compatibility of dot and adjoint
+ VERIFY(ei_isApprox(v1.eigen2_dot(square * v2), (square.adjoint() * v1).eigen2_dot(v2), largerEps));
+
+ // like in testBasicStuff, test operator() to check const-qualification
+ int r = ei_random<int>(0, rows-1),
+ c = ei_random<int>(0, cols-1);
+ VERIFY_IS_APPROX(m1.conjugate()(r,c), ei_conj(m1(r,c)));
+ VERIFY_IS_APPROX(m1.adjoint()(c,r), ei_conj(m1(r,c)));
+
+ if(NumTraits<Scalar>::HasFloatingPoint)
+ {
+ // check that Random().normalized() works: tricky as the random xpr must be evaluated by
+ // normalized() in order to produce a consistent result.
+ VERIFY_IS_APPROX(VectorType::Random(rows).normalized().norm(), RealScalar(1));
+ }
+
+ // check inplace transpose
+ m3 = m1;
+ m3.transposeInPlace();
+ VERIFY_IS_APPROX(m3,m1.transpose());
+ m3.transposeInPlace();
+ VERIFY_IS_APPROX(m3,m1);
+
+}
+
+void test_eigen2_adjoint()
+{
+ for(int i = 0; i < g_repeat; i++) {
+ CALL_SUBTEST_1( adjoint(Matrix<float, 1, 1>()) );
+ CALL_SUBTEST_2( adjoint(Matrix3d()) );
+ CALL_SUBTEST_3( adjoint(Matrix4f()) );
+ CALL_SUBTEST_4( adjoint(MatrixXcf(4, 4)) );
+ CALL_SUBTEST_5( adjoint(MatrixXi(8, 12)) );
+ CALL_SUBTEST_6( adjoint(MatrixXf(21, 21)) );
+ }
+ // test a large matrix only once
+ CALL_SUBTEST_7( adjoint(Matrix<float, 100, 100>()) );
+}
+
diff --git a/test/eigen2/eigen2_alignedbox.cpp b/test/eigen2/eigen2_alignedbox.cpp
new file mode 100644
index 000000000..35043b958
--- /dev/null
+++ b/test/eigen2/eigen2_alignedbox.cpp
@@ -0,0 +1,60 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra. Eigen itself is part of the KDE project.
+//
+// Copyright (C) 2008 Gael Guennebaud <g.gael@free.fr>
+//
+// This Source Code Form is subject to the terms of the Mozilla
+// Public License v. 2.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 "main.h"
+#include <Eigen/Geometry>
+#include <Eigen/LU>
+#include <Eigen/QR>
+
+template<typename BoxType> void alignedbox(const BoxType& _box)
+{
+ /* this test covers the following files:
+ AlignedBox.h
+ */
+
+ const int dim = _box.dim();
+ typedef typename BoxType::Scalar Scalar;
+ typedef typename NumTraits<Scalar>::Real RealScalar;
+ typedef Matrix<Scalar, BoxType::AmbientDimAtCompileTime, 1> VectorType;
+
+ VectorType p0 = VectorType::Random(dim);
+ VectorType p1 = VectorType::Random(dim);
+ RealScalar s1 = ei_random<RealScalar>(0,1);
+
+ BoxType b0(dim);
+ BoxType b1(VectorType::Random(dim),VectorType::Random(dim));
+ BoxType b2;
+
+ b0.extend(p0);
+ b0.extend(p1);
+ VERIFY(b0.contains(p0*s1+(Scalar(1)-s1)*p1));
+ VERIFY(!b0.contains(p0 + (1+s1)*(p1-p0)));
+
+ (b2 = b0).extend(b1);
+ VERIFY(b2.contains(b0));
+ VERIFY(b2.contains(b1));
+ VERIFY_IS_APPROX(b2.clamp(b0), b0);
+
+ // casting
+ const int Dim = BoxType::AmbientDimAtCompileTime;
+ typedef typename GetDifferentType<Scalar>::type OtherScalar;
+ AlignedBox<OtherScalar,Dim> hp1f = b0.template cast<OtherScalar>();
+ VERIFY_IS_APPROX(hp1f.template cast<Scalar>(),b0);
+ AlignedBox<Scalar,Dim> hp1d = b0.template cast<Scalar>();
+ VERIFY_IS_APPROX(hp1d.template cast<Scalar>(),b0);
+}
+
+void test_eigen2_alignedbox()
+{
+ for(int i = 0; i < g_repeat; i++) {
+ CALL_SUBTEST_1( alignedbox(AlignedBox<float,2>()) );
+ CALL_SUBTEST_2( alignedbox(AlignedBox<float,3>()) );
+ CALL_SUBTEST_3( alignedbox(AlignedBox<double,4>()) );
+ }
+}
diff --git a/test/eigen2/eigen2_array.cpp b/test/eigen2/eigen2_array.cpp
new file mode 100644
index 000000000..c1ff40ce7
--- /dev/null
+++ b/test/eigen2/eigen2_array.cpp
@@ -0,0 +1,142 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra. Eigen itself is part of the KDE project.
+//
+// Copyright (C) 2008 Gael Guennebaud <g.gael@free.fr>
+//
+// This Source Code Form is subject to the terms of the Mozilla
+// Public License v. 2.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 "main.h"
+#include <Eigen/Array>
+
+template<typename MatrixType> void array(const MatrixType& m)
+{
+ /* this test covers the following files:
+ Array.cpp
+ */
+
+ typedef typename MatrixType::Scalar Scalar;
+ typedef typename NumTraits<Scalar>::Real RealScalar;
+ typedef Matrix<Scalar, MatrixType::RowsAtCompileTime, 1> VectorType;
+
+ int rows = m.rows();
+ int cols = m.cols();
+
+ MatrixType m1 = MatrixType::Random(rows, cols),
+ m2 = MatrixType::Random(rows, cols),
+ m3(rows, cols);
+
+ Scalar s1 = ei_random<Scalar>(),
+ s2 = ei_random<Scalar>();
+
+ // scalar addition
+ VERIFY_IS_APPROX(m1.cwise() + s1, s1 + m1.cwise());
+ VERIFY_IS_APPROX(m1.cwise() + s1, MatrixType::Constant(rows,cols,s1) + m1);
+ VERIFY_IS_APPROX((m1*Scalar(2)).cwise() - s2, (m1+m1) - MatrixType::Constant(rows,cols,s2) );
+ m3 = m1;
+ m3.cwise() += s2;
+ VERIFY_IS_APPROX(m3, m1.cwise() + s2);
+ m3 = m1;
+ m3.cwise() -= s1;
+ VERIFY_IS_APPROX(m3, m1.cwise() - s1);
+
+ // reductions
+ VERIFY_IS_APPROX(m1.colwise().sum().sum(), m1.sum());
+ VERIFY_IS_APPROX(m1.rowwise().sum().sum(), m1.sum());
+ if (!ei_isApprox(m1.sum(), (m1+m2).sum()))
+ VERIFY_IS_NOT_APPROX(((m1+m2).rowwise().sum()).sum(), m1.sum());
+ VERIFY_IS_APPROX(m1.colwise().sum(), m1.colwise().redux(internal::scalar_sum_op<Scalar>()));
+}
+
+template<typename MatrixType> void comparisons(const MatrixType& m)
+{
+ typedef typename MatrixType::Scalar Scalar;
+ typedef typename NumTraits<Scalar>::Real RealScalar;
+ typedef Matrix<Scalar, MatrixType::RowsAtCompileTime, 1> VectorType;
+
+ int rows = m.rows();
+ int cols = m.cols();
+
+ int r = ei_random<int>(0, rows-1),
+ c = ei_random<int>(0, cols-1);
+
+ MatrixType m1 = MatrixType::Random(rows, cols),
+ m2 = MatrixType::Random(rows, cols),
+ m3(rows, cols);
+
+ VERIFY(((m1.cwise() + Scalar(1)).cwise() > m1).all());
+ VERIFY(((m1.cwise() - Scalar(1)).cwise() < m1).all());
+ if (rows*cols>1)
+ {
+ m3 = m1;
+ m3(r,c) += 1;
+ VERIFY(! (m1.cwise() < m3).all() );
+ VERIFY(! (m1.cwise() > m3).all() );
+ }
+
+ // comparisons to scalar
+ VERIFY( (m1.cwise() != (m1(r,c)+1) ).any() );
+ VERIFY( (m1.cwise() > (m1(r,c)-1) ).any() );
+ VERIFY( (m1.cwise() < (m1(r,c)+1) ).any() );
+ VERIFY( (m1.cwise() == m1(r,c) ).any() );
+
+ // test Select
+ VERIFY_IS_APPROX( (m1.cwise()<m2).select(m1,m2), m1.cwise().min(m2) );
+ VERIFY_IS_APPROX( (m1.cwise()>m2).select(m1,m2), m1.cwise().max(m2) );
+ Scalar mid = (m1.cwise().abs().minCoeff() + m1.cwise().abs().maxCoeff())/Scalar(2);
+ for (int j=0; j<cols; ++j)
+ for (int i=0; i<rows; ++i)
+ m3(i,j) = ei_abs(m1(i,j))<mid ? 0 : m1(i,j);
+ VERIFY_IS_APPROX( (m1.cwise().abs().cwise()<MatrixType::Constant(rows,cols,mid))
+ .select(MatrixType::Zero(rows,cols),m1), m3);
+ // shorter versions:
+ VERIFY_IS_APPROX( (m1.cwise().abs().cwise()<MatrixType::Constant(rows,cols,mid))
+ .select(0,m1), m3);
+ VERIFY_IS_APPROX( (m1.cwise().abs().cwise()>=MatrixType::Constant(rows,cols,mid))
+ .select(m1,0), m3);
+ // even shorter version:
+ VERIFY_IS_APPROX( (m1.cwise().abs().cwise()<mid).select(0,m1), m3);
+
+ // count
+ VERIFY(((m1.cwise().abs().cwise()+1).cwise()>RealScalar(0.1)).count() == rows*cols);
+ VERIFY_IS_APPROX(((m1.cwise().abs().cwise()+1).cwise()>RealScalar(0.1)).colwise().count().template cast<int>(), RowVectorXi::Constant(cols,rows));
+ VERIFY_IS_APPROX(((m1.cwise().abs().cwise()+1).cwise()>RealScalar(0.1)).rowwise().count().template cast<int>(), VectorXi::Constant(rows, cols));
+}
+
+template<typename VectorType> void lpNorm(const VectorType& v)
+{
+ VectorType u = VectorType::Random(v.size());
+
+ VERIFY_IS_APPROX(u.template lpNorm<Infinity>(), u.cwise().abs().maxCoeff());
+ VERIFY_IS_APPROX(u.template lpNorm<1>(), u.cwise().abs().sum());
+ VERIFY_IS_APPROX(u.template lpNorm<2>(), ei_sqrt(u.cwise().abs().cwise().square().sum()));
+ VERIFY_IS_APPROX(ei_pow(u.template lpNorm<5>(), typename VectorType::RealScalar(5)), u.cwise().abs().cwise().pow(5).sum());
+}
+
+void test_eigen2_array()
+{
+ for(int i = 0; i < g_repeat; i++) {
+ CALL_SUBTEST_1( array(Matrix<float, 1, 1>()) );
+ CALL_SUBTEST_2( array(Matrix2f()) );
+ CALL_SUBTEST_3( array(Matrix4d()) );
+ CALL_SUBTEST_4( array(MatrixXcf(3, 3)) );
+ CALL_SUBTEST_5( array(MatrixXf(8, 12)) );
+ CALL_SUBTEST_6( array(MatrixXi(8, 12)) );
+ }
+ for(int i = 0; i < g_repeat; i++) {
+ CALL_SUBTEST_1( comparisons(Matrix<float, 1, 1>()) );
+ CALL_SUBTEST_2( comparisons(Matrix2f()) );
+ CALL_SUBTEST_3( comparisons(Matrix4d()) );
+ CALL_SUBTEST_5( comparisons(MatrixXf(8, 12)) );
+ CALL_SUBTEST_6( comparisons(MatrixXi(8, 12)) );
+ }
+ for(int i = 0; i < g_repeat; i++) {
+ CALL_SUBTEST_1( lpNorm(Matrix<float, 1, 1>()) );
+ CALL_SUBTEST_2( lpNorm(Vector2f()) );
+ CALL_SUBTEST_3( lpNorm(Vector3d()) );
+ CALL_SUBTEST_4( lpNorm(Vector4f()) );
+ CALL_SUBTEST_5( lpNorm(VectorXf(16)) );
+ CALL_SUBTEST_7( lpNorm(VectorXcd(10)) );
+ }
+}
diff --git a/test/eigen2/eigen2_basicstuff.cpp b/test/eigen2/eigen2_basicstuff.cpp
new file mode 100644
index 000000000..4fa16d5ae
--- /dev/null
+++ b/test/eigen2/eigen2_basicstuff.cpp
@@ -0,0 +1,108 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra. Eigen itself is part of the KDE project.
+//
+// Copyright (C) 2006-2008 Benoit Jacob <jacob.benoit.1@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 "main.h"
+
+template<typename MatrixType> void basicStuff(const MatrixType& m)
+{
+ typedef typename MatrixType::Scalar Scalar;
+ typedef Matrix<Scalar, MatrixType::RowsAtCompileTime, 1> VectorType;
+
+ int rows = m.rows();
+ int cols = m.cols();
+
+ // this test relies a lot on Random.h, and there's not much more that we can do
+ // to test it, hence I consider that we will have tested Random.h
+ MatrixType m1 = MatrixType::Random(rows, cols),
+ m2 = MatrixType::Random(rows, cols),
+ m3(rows, cols),
+ mzero = MatrixType::Zero(rows, cols),
+ identity = Matrix<Scalar, MatrixType::RowsAtCompileTime, MatrixType::RowsAtCompileTime>
+ ::Identity(rows, rows),
+ square = Matrix<Scalar, MatrixType::RowsAtCompileTime, MatrixType::RowsAtCompileTime>::Random(rows, rows);
+ VectorType v1 = VectorType::Random(rows),
+ v2 = VectorType::Random(rows),
+ vzero = VectorType::Zero(rows);
+
+ Scalar x = ei_random<Scalar>();
+
+ int r = ei_random<int>(0, rows-1),
+ c = ei_random<int>(0, cols-1);
+
+ m1.coeffRef(r,c) = x;
+ VERIFY_IS_APPROX(x, m1.coeff(r,c));
+ m1(r,c) = x;
+ VERIFY_IS_APPROX(x, m1(r,c));
+ v1.coeffRef(r) = x;
+ VERIFY_IS_APPROX(x, v1.coeff(r));
+ v1(r) = x;
+ VERIFY_IS_APPROX(x, v1(r));
+ v1[r] = x;
+ VERIFY_IS_APPROX(x, v1[r]);
+
+ VERIFY_IS_APPROX( v1, v1);
+ VERIFY_IS_NOT_APPROX( v1, 2*v1);
+ VERIFY_IS_MUCH_SMALLER_THAN( vzero, v1);
+ if(NumTraits<Scalar>::HasFloatingPoint)
+ VERIFY_IS_MUCH_SMALLER_THAN( vzero, v1.norm());
+ VERIFY_IS_NOT_MUCH_SMALLER_THAN(v1, v1);
+ VERIFY_IS_APPROX( vzero, v1-v1);
+ VERIFY_IS_APPROX( m1, m1);
+ VERIFY_IS_NOT_APPROX( m1, 2*m1);
+ VERIFY_IS_MUCH_SMALLER_THAN( mzero, m1);
+ VERIFY_IS_NOT_MUCH_SMALLER_THAN(m1, m1);
+ VERIFY_IS_APPROX( mzero, m1-m1);
+
+ // always test operator() on each read-only expression class,
+ // in order to check const-qualifiers.
+ // indeed, if an expression class (here Zero) is meant to be read-only,
+ // hence has no _write() method, the corresponding MatrixBase method (here zero())
+ // should return a const-qualified object so that it is the const-qualified
+ // operator() that gets called, which in turn calls _read().
+ VERIFY_IS_MUCH_SMALLER_THAN(MatrixType::Zero(rows,cols)(r,c), static_cast<Scalar>(1));
+
+ // now test copying a row-vector into a (column-)vector and conversely.
+ square.col(r) = square.row(r).eval();
+ Matrix<Scalar, 1, MatrixType::RowsAtCompileTime> rv(rows);
+ Matrix<Scalar, MatrixType::RowsAtCompileTime, 1> cv(rows);
+ rv = square.row(r);
+ cv = square.col(r);
+ VERIFY_IS_APPROX(rv, cv.transpose());
+
+ if(cols!=1 && rows!=1 && MatrixType::SizeAtCompileTime!=Dynamic)
+ {
+ VERIFY_RAISES_ASSERT(m1 = (m2.block(0,0, rows-1, cols-1)));
+ }
+
+ VERIFY_IS_APPROX(m3 = m1,m1);
+ MatrixType m4;
+ VERIFY_IS_APPROX(m4 = m1,m1);
+
+ // test swap
+ m3 = m1;
+ m1.swap(m2);
+ VERIFY_IS_APPROX(m3, m2);
+ if(rows*cols>=3)
+ {
+ VERIFY_IS_NOT_APPROX(m3, m1);
+ }
+}
+
+void test_eigen2_basicstuff()
+{
+ for(int i = 0; i < g_repeat; i++) {
+ CALL_SUBTEST_1( basicStuff(Matrix<float, 1, 1>()) );
+ CALL_SUBTEST_2( basicStuff(Matrix4d()) );
+ CALL_SUBTEST_3( basicStuff(MatrixXcf(3, 3)) );
+ CALL_SUBTEST_4( basicStuff(MatrixXi(8, 12)) );
+ CALL_SUBTEST_5( basicStuff(MatrixXcd(20, 20)) );
+ CALL_SUBTEST_6( basicStuff(Matrix<float, 100, 100>()) );
+ CALL_SUBTEST_7( basicStuff(Matrix<long double,Dynamic,Dynamic>(10,10)) );
+ }
+}
diff --git a/test/eigen2/eigen2_bug_132.cpp b/test/eigen2/eigen2_bug_132.cpp
new file mode 100644
index 000000000..7fe3610ce
--- /dev/null
+++ b/test/eigen2/eigen2_bug_132.cpp
@@ -0,0 +1,26 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra. Eigen itself is part of the KDE project.
+//
+// Copyright (C) 2010 Benoit Jacob <jacob.benoit.1@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 "main.h"
+
+void test_eigen2_bug_132() {
+ int size = 100;
+ MatrixXd A(size, size);
+ VectorXd b(size), c(size);
+ {
+ VectorXd y = A.transpose() * (b-c); // bug 132: infinite recursion in coeffRef
+ VectorXd z = (b-c).transpose() * A; // bug 132: infinite recursion in coeffRef
+ }
+
+ // the following ones weren't failing, but let's include them for completeness:
+ {
+ VectorXd y = A * (b-c);
+ VectorXd z = (b-c).transpose() * A.transpose();
+ }
+}
diff --git a/test/eigen2/eigen2_cholesky.cpp b/test/eigen2/eigen2_cholesky.cpp
new file mode 100644
index 000000000..9c4b6f561
--- /dev/null
+++ b/test/eigen2/eigen2_cholesky.cpp
@@ -0,0 +1,113 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra. Eigen itself is part of the KDE project.
+//
+// Copyright (C) 2008 Gael Guennebaud <g.gael@free.fr>
+//
+// This Source Code Form is subject to the terms of the Mozilla
+// Public License v. 2.0. If a copy of the MPL was not distributed
+// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+#define EIGEN_NO_ASSERTION_CHECKING
+#include "main.h"
+#include <Eigen/Cholesky>
+#include <Eigen/LU>
+
+#ifdef HAS_GSL
+#include "gsl_helper.h"
+#endif
+
+template<typename MatrixType> void cholesky(const MatrixType& m)
+{
+ /* this test covers the following files:
+ LLT.h LDLT.h
+ */
+ int rows = m.rows();
+ int cols = m.cols();
+
+ typedef typename MatrixType::Scalar Scalar;
+ typedef typename NumTraits<Scalar>::Real RealScalar;
+ typedef Matrix<Scalar, MatrixType::RowsAtCompileTime, MatrixType::RowsAtCompileTime> SquareMatrixType;
+ typedef Matrix<Scalar, MatrixType::RowsAtCompileTime, 1> VectorType;
+
+ MatrixType a0 = MatrixType::Random(rows,cols);
+ VectorType vecB = VectorType::Random(rows), vecX(rows);
+ MatrixType matB = MatrixType::Random(rows,cols), matX(rows,cols);
+ SquareMatrixType symm = a0 * a0.adjoint();
+ // let's make sure the matrix is not singular or near singular
+ MatrixType a1 = MatrixType::Random(rows,cols);
+ symm += a1 * a1.adjoint();
+
+ #ifdef HAS_GSL
+ if (ei_is_same_type<RealScalar,double>::ret)
+ {
+ typedef GslTraits<Scalar> Gsl;
+ typename Gsl::Matrix gMatA=0, gSymm=0;
+ typename Gsl::Vector gVecB=0, gVecX=0;
+ convert<MatrixType>(symm, gSymm);
+ convert<MatrixType>(symm, gMatA);
+ convert<VectorType>(vecB, gVecB);
+ convert<VectorType>(vecB, gVecX);
+ Gsl::cholesky(gMatA);
+ Gsl::cholesky_solve(gMatA, gVecB, gVecX);
+ VectorType vecX(rows), _vecX, _vecB;
+ convert(gVecX, _vecX);
+ symm.llt().solve(vecB, &vecX);
+ Gsl::prod(gSymm, gVecX, gVecB);
+ convert(gVecB, _vecB);
+ // test gsl itself !
+ VERIFY_IS_APPROX(vecB, _vecB);
+ VERIFY_IS_APPROX(vecX, _vecX);
+
+ Gsl::free(gMatA);
+ Gsl::free(gSymm);
+ Gsl::free(gVecB);
+ Gsl::free(gVecX);
+ }
+ #endif
+
+ {
+ LDLT<SquareMatrixType> ldlt(symm);
+ VERIFY(ldlt.isPositiveDefinite());
+ // in eigen3, LDLT is pivoting
+ //VERIFY_IS_APPROX(symm, ldlt.matrixL() * ldlt.vectorD().asDiagonal() * ldlt.matrixL().adjoint());
+ ldlt.solve(vecB, &vecX);
+ VERIFY_IS_APPROX(symm * vecX, vecB);
+ ldlt.solve(matB, &matX);
+ VERIFY_IS_APPROX(symm * matX, matB);
+ }
+
+ {
+ LLT<SquareMatrixType> chol(symm);
+ VERIFY(chol.isPositiveDefinite());
+ VERIFY_IS_APPROX(symm, chol.matrixL() * chol.matrixL().adjoint());
+ chol.solve(vecB, &vecX);
+ VERIFY_IS_APPROX(symm * vecX, vecB);
+ chol.solve(matB, &matX);
+ VERIFY_IS_APPROX(symm * matX, matB);
+ }
+
+#if 0 // cholesky is not rank-revealing anyway
+ // test isPositiveDefinite on non definite matrix
+ if (rows>4)
+ {
+ SquareMatrixType symm = a0.block(0,0,rows,cols-4) * a0.block(0,0,rows,cols-4).adjoint();
+ LLT<SquareMatrixType> chol(symm);
+ VERIFY(!chol.isPositiveDefinite());
+ LDLT<SquareMatrixType> cholnosqrt(symm);
+ VERIFY(!cholnosqrt.isPositiveDefinite());
+ }
+#endif
+}
+
+void test_eigen2_cholesky()
+{
+ for(int i = 0; i < g_repeat; i++) {
+ CALL_SUBTEST_1( cholesky(Matrix<double,1,1>()) );
+ CALL_SUBTEST_2( cholesky(Matrix2d()) );
+ CALL_SUBTEST_3( cholesky(Matrix3f()) );
+ CALL_SUBTEST_4( cholesky(Matrix4d()) );
+ CALL_SUBTEST_5( cholesky(MatrixXcd(7,7)) );
+ CALL_SUBTEST_6( cholesky(MatrixXf(17,17)) );
+ CALL_SUBTEST_7( cholesky(MatrixXd(33,33)) );
+ }
+}
diff --git a/test/eigen2/eigen2_commainitializer.cpp b/test/eigen2/eigen2_commainitializer.cpp
new file mode 100644
index 000000000..e0f901e0b
--- /dev/null
+++ b/test/eigen2/eigen2_commainitializer.cpp
@@ -0,0 +1,46 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra. Eigen itself is part of the KDE project.
+//
+// Copyright (C) 2008 Gael Guennebaud <g.gael@free.fr>
+//
+// This Source Code Form is subject to the terms of the Mozilla
+// Public License v. 2.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 "main.h"
+
+void test_eigen2_commainitializer()
+{
+ Matrix3d m3;
+ Matrix4d m4;
+
+ VERIFY_RAISES_ASSERT( (m3 << 1, 2, 3, 4, 5, 6, 7, 8) );
+
+ #ifndef _MSC_VER
+ VERIFY_RAISES_ASSERT( (m3 << 1, 2, 3, 4, 5, 6, 7, 8, 9, 10) );
+ #endif
+
+ double data[] = {1, 2, 3, 4, 5, 6, 7, 8, 9};
+ Matrix3d ref = Map<Matrix<double,3,3,RowMajor> >(data);
+
+ m3 = Matrix3d::Random();
+ m3 << 1, 2, 3, 4, 5, 6, 7, 8, 9;
+ VERIFY_IS_APPROX(m3, ref );
+
+ Vector3d vec[3];
+ vec[0] << 1, 4, 7;
+ vec[1] << 2, 5, 8;
+ vec[2] << 3, 6, 9;
+ m3 = Matrix3d::Random();
+ m3 << vec[0], vec[1], vec[2];
+ VERIFY_IS_APPROX(m3, ref);
+
+ vec[0] << 1, 2, 3;
+ vec[1] << 4, 5, 6;
+ vec[2] << 7, 8, 9;
+ m3 = Matrix3d::Random();
+ m3 << vec[0].transpose(),
+ 4, 5, 6,
+ vec[2].transpose();
+ VERIFY_IS_APPROX(m3, ref);
+}
diff --git a/test/eigen2/eigen2_cwiseop.cpp b/test/eigen2/eigen2_cwiseop.cpp
new file mode 100644
index 000000000..4391d19b4
--- /dev/null
+++ b/test/eigen2/eigen2_cwiseop.cpp
@@ -0,0 +1,158 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra. Eigen itself is part of the KDE project.
+//
+// Copyright (C) 2008 Gael Guennebaud <g.gael@free.fr>
+// Copyright (C) 2006-2008 Benoit Jacob <jacob.benoit.1@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 "main.h"
+#include <functional>
+#include <Eigen/Array>
+
+using namespace std;
+
+template<typename Scalar> struct AddIfNull {
+ const Scalar operator() (const Scalar a, const Scalar b) const {return a<=1e-3 ? b : a;}
+ enum { Cost = NumTraits<Scalar>::AddCost };
+};
+
+template<typename MatrixType> void cwiseops(const MatrixType& m)
+{
+ typedef typename MatrixType::Scalar Scalar;
+ typedef typename NumTraits<Scalar>::Real RealScalar;
+ typedef Matrix<Scalar, MatrixType::RowsAtCompileTime, 1> VectorType;
+
+ int rows = m.rows();
+ int cols = m.cols();
+
+ MatrixType m1 = MatrixType::Random(rows, cols),
+ m2 = MatrixType::Random(rows, cols),
+ m3(rows, cols),
+ m4(rows, cols),
+ mzero = MatrixType::Zero(rows, cols),
+ mones = MatrixType::Ones(rows, cols),
+ identity = Matrix<Scalar, MatrixType::RowsAtCompileTime, MatrixType::RowsAtCompileTime>
+ ::Identity(rows, rows),
+ square = Matrix<Scalar, MatrixType::RowsAtCompileTime, MatrixType::RowsAtCompileTime>::Random(rows, rows);
+ VectorType v1 = VectorType::Random(rows),
+ v2 = VectorType::Random(rows),
+ vzero = VectorType::Zero(rows),
+ vones = VectorType::Ones(rows),
+ v3(rows);
+
+ int r = ei_random<int>(0, rows-1),
+ c = ei_random<int>(0, cols-1);
+
+ Scalar s1 = ei_random<Scalar>();
+
+ // test Zero, Ones, Constant, and the set* variants
+ m3 = MatrixType::Constant(rows, cols, s1);
+ for (int j=0; j<cols; ++j)
+ for (int i=0; i<rows; ++i)
+ {
+ VERIFY_IS_APPROX(mzero(i,j), Scalar(0));
+ VERIFY_IS_APPROX(mones(i,j), Scalar(1));
+ VERIFY_IS_APPROX(m3(i,j), s1);
+ }
+ VERIFY(mzero.isZero());
+ VERIFY(mones.isOnes());
+ VERIFY(m3.isConstant(s1));
+ VERIFY(identity.isIdentity());
+ VERIFY_IS_APPROX(m4.setConstant(s1), m3);
+ VERIFY_IS_APPROX(m4.setConstant(rows,cols,s1), m3);
+ VERIFY_IS_APPROX(m4.setZero(), mzero);
+ VERIFY_IS_APPROX(m4.setZero(rows,cols), mzero);
+ VERIFY_IS_APPROX(m4.setOnes(), mones);
+ VERIFY_IS_APPROX(m4.setOnes(rows,cols), mones);
+ m4.fill(s1);
+ VERIFY_IS_APPROX(m4, m3);
+
+ VERIFY_IS_APPROX(v3.setConstant(rows, s1), VectorType::Constant(rows,s1));
+ VERIFY_IS_APPROX(v3.setZero(rows), vzero);
+ VERIFY_IS_APPROX(v3.setOnes(rows), vones);
+
+ m2 = m2.template binaryExpr<AddIfNull<Scalar> >(mones);
+
+ VERIFY_IS_APPROX(m1.cwise().pow(2), m1.cwise().abs2());
+ VERIFY_IS_APPROX(m1.cwise().pow(2), m1.cwise().square());
+ VERIFY_IS_APPROX(m1.cwise().pow(3), m1.cwise().cube());
+
+ VERIFY_IS_APPROX(m1 + mones, m1.cwise()+Scalar(1));
+ VERIFY_IS_APPROX(m1 - mones, m1.cwise()-Scalar(1));
+ m3 = m1; m3.cwise() += 1;
+ VERIFY_IS_APPROX(m1 + mones, m3);
+ m3 = m1; m3.cwise() -= 1;
+ VERIFY_IS_APPROX(m1 - mones, m3);
+
+ VERIFY_IS_APPROX(m2, m2.cwise() * mones);
+ VERIFY_IS_APPROX(m1.cwise() * m2, m2.cwise() * m1);
+ m3 = m1;
+ m3.cwise() *= m2;
+ VERIFY_IS_APPROX(m3, m1.cwise() * m2);
+
+ VERIFY_IS_APPROX(mones, m2.cwise()/m2);
+ if(NumTraits<Scalar>::HasFloatingPoint)
+ {
+ VERIFY_IS_APPROX(m1.cwise() / m2, m1.cwise() * (m2.cwise().inverse()));
+ m3 = m1.cwise().abs().cwise().sqrt();
+ VERIFY_IS_APPROX(m3.cwise().square(), m1.cwise().abs());
+ VERIFY_IS_APPROX(m1.cwise().square().cwise().sqrt(), m1.cwise().abs());
+ VERIFY_IS_APPROX(m1.cwise().abs().cwise().log().cwise().exp() , m1.cwise().abs());
+
+ VERIFY_IS_APPROX(m1.cwise().pow(2), m1.cwise().square());
+ m3 = (m1.cwise().abs().cwise()<=RealScalar(0.01)).select(mones,m1);
+ VERIFY_IS_APPROX(m3.cwise().pow(-1), m3.cwise().inverse());
+ m3 = m1.cwise().abs();
+ VERIFY_IS_APPROX(m3.cwise().pow(RealScalar(0.5)), m3.cwise().sqrt());
+
+// VERIFY_IS_APPROX(m1.cwise().tan(), m1.cwise().sin().cwise() / m1.cwise().cos());
+ VERIFY_IS_APPROX(mones, m1.cwise().sin().cwise().square() + m1.cwise().cos().cwise().square());
+ m3 = m1;
+ m3.cwise() /= m2;
+ VERIFY_IS_APPROX(m3, m1.cwise() / m2);
+ }
+
+ // check min
+ VERIFY_IS_APPROX( m1.cwise().min(m2), m2.cwise().min(m1) );
+ VERIFY_IS_APPROX( m1.cwise().min(m1+mones), m1 );
+ VERIFY_IS_APPROX( m1.cwise().min(m1-mones), m1-mones );
+
+ // check max
+ VERIFY_IS_APPROX( m1.cwise().max(m2), m2.cwise().max(m1) );
+ VERIFY_IS_APPROX( m1.cwise().max(m1-mones), m1 );
+ VERIFY_IS_APPROX( m1.cwise().max(m1+mones), m1+mones );
+
+ VERIFY( (m1.cwise() == m1).all() );
+ VERIFY( (m1.cwise() != m2).any() );
+ VERIFY(!(m1.cwise() == (m1+mones)).any() );
+ if (rows*cols>1)
+ {
+ m3 = m1;
+ m3(r,c) += 1;
+ VERIFY( (m1.cwise() == m3).any() );
+ VERIFY( !(m1.cwise() == m3).all() );
+ }
+ VERIFY( (m1.cwise().min(m2).cwise() <= m2).all() );
+ VERIFY( (m1.cwise().max(m2).cwise() >= m2).all() );
+ VERIFY( (m1.cwise().min(m2).cwise() < (m1+mones)).all() );
+ VERIFY( (m1.cwise().max(m2).cwise() > (m1-mones)).all() );
+
+ VERIFY( (m1.cwise()<m1.unaryExpr(bind2nd(plus<Scalar>(), Scalar(1)))).all() );
+ VERIFY( !(m1.cwise()<m1.unaryExpr(bind2nd(minus<Scalar>(), Scalar(1)))).all() );
+ VERIFY( !(m1.cwise()>m1.unaryExpr(bind2nd(plus<Scalar>(), Scalar(1)))).any() );
+}
+
+void test_eigen2_cwiseop()
+{
+ for(int i = 0; i < g_repeat ; i++) {
+ CALL_SUBTEST_1( cwiseops(Matrix<float, 1, 1>()) );
+ CALL_SUBTEST_2( cwiseops(Matrix4d()) );
+ CALL_SUBTEST_3( cwiseops(MatrixXf(3, 3)) );
+ CALL_SUBTEST_3( cwiseops(MatrixXf(22, 22)) );
+ CALL_SUBTEST_4( cwiseops(MatrixXi(8, 12)) );
+ CALL_SUBTEST_5( cwiseops(MatrixXd(20, 20)) );
+ }
+}
diff --git a/test/eigen2/eigen2_determinant.cpp b/test/eigen2/eigen2_determinant.cpp
new file mode 100644
index 000000000..c7b4ad053
--- /dev/null
+++ b/test/eigen2/eigen2_determinant.cpp
@@ -0,0 +1,61 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra. Eigen itself is part of the KDE project.
+//
+// Copyright (C) 2008 Benoit Jacob <jacob.benoit.1@gmail.com>
+// Copyright (C) 2008 Gael Guennebaud <g.gael@free.fr>
+//
+// This Source Code Form is subject to the terms of the Mozilla
+// Public License v. 2.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 "main.h"
+#include <Eigen/LU>
+
+template<typename MatrixType> void determinant(const MatrixType& m)
+{
+ /* this test covers the following files:
+ Determinant.h
+ */
+ int size = m.rows();
+
+ MatrixType m1(size, size), m2(size, size);
+ m1.setRandom();
+ m2.setRandom();
+ typedef typename MatrixType::Scalar Scalar;
+ Scalar x = ei_random<Scalar>();
+ VERIFY_IS_APPROX(MatrixType::Identity(size, size).determinant(), Scalar(1));
+ VERIFY_IS_APPROX((m1*m2).determinant(), m1.determinant() * m2.determinant());
+ if(size==1) return;
+ int i = ei_random<int>(0, size-1);
+ int j;
+ do {
+ j = ei_random<int>(0, size-1);
+ } while(j==i);
+ m2 = m1;
+ m2.row(i).swap(m2.row(j));
+ VERIFY_IS_APPROX(m2.determinant(), -m1.determinant());
+ m2 = m1;
+ m2.col(i).swap(m2.col(j));
+ VERIFY_IS_APPROX(m2.determinant(), -m1.determinant());
+ VERIFY_IS_APPROX(m2.determinant(), m2.transpose().determinant());
+ VERIFY_IS_APPROX(ei_conj(m2.determinant()), m2.adjoint().determinant());
+ m2 = m1;
+ m2.row(i) += x*m2.row(j);
+ VERIFY_IS_APPROX(m2.determinant(), m1.determinant());
+ m2 = m1;
+ m2.row(i) *= x;
+ VERIFY_IS_APPROX(m2.determinant(), m1.determinant() * x);
+}
+
+void test_eigen2_determinant()
+{
+ for(int i = 0; i < g_repeat; i++) {
+ CALL_SUBTEST_1( determinant(Matrix<float, 1, 1>()) );
+ CALL_SUBTEST_2( determinant(Matrix<double, 2, 2>()) );
+ CALL_SUBTEST_3( determinant(Matrix<double, 3, 3>()) );
+ CALL_SUBTEST_4( determinant(Matrix<double, 4, 4>()) );
+ CALL_SUBTEST_5( determinant(Matrix<std::complex<double>, 10, 10>()) );
+ CALL_SUBTEST_6( determinant(MatrixXd(20, 20)) );
+ }
+ CALL_SUBTEST_6( determinant(MatrixXd(200, 200)) );
+}
diff --git a/test/eigen2/eigen2_dynalloc.cpp b/test/eigen2/eigen2_dynalloc.cpp
new file mode 100644
index 000000000..1891a9e33
--- /dev/null
+++ b/test/eigen2/eigen2_dynalloc.cpp
@@ -0,0 +1,131 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra. Eigen itself is part of the KDE project.
+//
+// Copyright (C) 2008 Gael Guennebaud <g.gael@free.fr>
+//
+// This Source Code Form is subject to the terms of the Mozilla
+// Public License v. 2.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 "main.h"
+
+#if EIGEN_ARCH_WANTS_ALIGNMENT
+#define ALIGNMENT 16
+#else
+#define ALIGNMENT 1
+#endif
+
+void check_handmade_aligned_malloc()
+{
+ for(int i = 1; i < 1000; i++)
+ {
+ char *p = (char*)ei_handmade_aligned_malloc(i);
+ VERIFY(std::size_t(p)%ALIGNMENT==0);
+ // if the buffer is wrongly allocated this will give a bad write --> check with valgrind
+ for(int j = 0; j < i; j++) p[j]=0;
+ ei_handmade_aligned_free(p);
+ }
+}
+
+void check_aligned_malloc()
+{
+ for(int i = 1; i < 1000; i++)
+ {
+ char *p = (char*)ei_aligned_malloc(i);
+ VERIFY(std::size_t(p)%ALIGNMENT==0);
+ // if the buffer is wrongly allocated this will give a bad write --> check with valgrind
+ for(int j = 0; j < i; j++) p[j]=0;
+ ei_aligned_free(p);
+ }
+}
+
+void check_aligned_new()
+{
+ for(int i = 1; i < 1000; i++)
+ {
+ float *p = ei_aligned_new<float>(i);
+ VERIFY(std::size_t(p)%ALIGNMENT==0);
+ // if the buffer is wrongly allocated this will give a bad write --> check with valgrind
+ for(int j = 0; j < i; j++) p[j]=0;
+ ei_aligned_delete(p,i);
+ }
+}
+
+void check_aligned_stack_alloc()
+{
+ for(int i = 1; i < 1000; i++)
+ {
+ ei_declare_aligned_stack_constructed_variable(float, p, i, 0);
+ VERIFY(std::size_t(p)%ALIGNMENT==0);
+ // if the buffer is wrongly allocated this will give a bad write --> check with valgrind
+ for(int j = 0; j < i; j++) p[j]=0;
+ }
+}
+
+
+// test compilation with both a struct and a class...
+struct MyStruct
+{
+ EIGEN_MAKE_ALIGNED_OPERATOR_NEW
+ char dummychar;
+ Vector4f avec;
+};
+
+class MyClassA
+{
+ public:
+ EIGEN_MAKE_ALIGNED_OPERATOR_NEW
+ char dummychar;
+ Vector4f avec;
+};
+
+template<typename T> void check_dynaligned()
+{
+ T* obj = new T;
+ VERIFY(std::size_t(obj)%ALIGNMENT==0);
+ delete obj;
+}
+
+void test_eigen2_dynalloc()
+{
+ // low level dynamic memory allocation
+ CALL_SUBTEST(check_handmade_aligned_malloc());
+ CALL_SUBTEST(check_aligned_malloc());
+ CALL_SUBTEST(check_aligned_new());
+ CALL_SUBTEST(check_aligned_stack_alloc());
+
+ for (int i=0; i<g_repeat*100; ++i)
+ {
+ CALL_SUBTEST( check_dynaligned<Vector4f>() );
+ CALL_SUBTEST( check_dynaligned<Vector2d>() );
+ CALL_SUBTEST( check_dynaligned<Matrix4f>() );
+ CALL_SUBTEST( check_dynaligned<Vector4d>() );
+ CALL_SUBTEST( check_dynaligned<Vector4i>() );
+ }
+
+ // check static allocation, who knows ?
+ {
+ MyStruct foo0; VERIFY(std::size_t(foo0.avec.data())%ALIGNMENT==0);
+ MyClassA fooA; VERIFY(std::size_t(fooA.avec.data())%ALIGNMENT==0);
+ }
+
+ // dynamic allocation, single object
+ for (int i=0; i<g_repeat*100; ++i)
+ {
+ MyStruct *foo0 = new MyStruct(); VERIFY(std::size_t(foo0->avec.data())%ALIGNMENT==0);
+ MyClassA *fooA = new MyClassA(); VERIFY(std::size_t(fooA->avec.data())%ALIGNMENT==0);
+ delete foo0;
+ delete fooA;
+ }
+
+ // dynamic allocation, array
+ const int N = 10;
+ for (int i=0; i<g_repeat*100; ++i)
+ {
+ MyStruct *foo0 = new MyStruct[N]; VERIFY(std::size_t(foo0->avec.data())%ALIGNMENT==0);
+ MyClassA *fooA = new MyClassA[N]; VERIFY(std::size_t(fooA->avec.data())%ALIGNMENT==0);
+ delete[] foo0;
+ delete[] fooA;
+ }
+
+}
diff --git a/test/eigen2/eigen2_eigensolver.cpp b/test/eigen2/eigen2_eigensolver.cpp
new file mode 100644
index 000000000..48b4ace43
--- /dev/null
+++ b/test/eigen2/eigen2_eigensolver.cpp
@@ -0,0 +1,146 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra. Eigen itself is part of the KDE project.
+//
+// Copyright (C) 2008 Gael Guennebaud <g.gael@free.fr>
+//
+// This Source Code Form is subject to the terms of the Mozilla
+// Public License v. 2.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 "main.h"
+#include <Eigen/QR>
+
+#ifdef HAS_GSL
+#include "gsl_helper.h"
+#endif
+
+template<typename MatrixType> void selfadjointeigensolver(const MatrixType& m)
+{
+ /* this test covers the following files:
+ EigenSolver.h, SelfAdjointEigenSolver.h (and indirectly: Tridiagonalization.h)
+ */
+ int rows = m.rows();
+ int cols = m.cols();
+
+ typedef typename MatrixType::Scalar Scalar;
+ typedef typename NumTraits<Scalar>::Real RealScalar;
+ typedef Matrix<Scalar, MatrixType::RowsAtCompileTime, 1> VectorType;
+ typedef Matrix<RealScalar, MatrixType::RowsAtCompileTime, 1> RealVectorType;
+ typedef typename std::complex<typename NumTraits<typename MatrixType::Scalar>::Real> Complex;
+
+ RealScalar largerEps = 10*test_precision<RealScalar>();
+
+ MatrixType a = MatrixType::Random(rows,cols);
+ MatrixType a1 = MatrixType::Random(rows,cols);
+ MatrixType symmA = a.adjoint() * a + a1.adjoint() * a1;
+
+ MatrixType b = MatrixType::Random(rows,cols);
+ MatrixType b1 = MatrixType::Random(rows,cols);
+ MatrixType symmB = b.adjoint() * b + b1.adjoint() * b1;
+
+ SelfAdjointEigenSolver<MatrixType> eiSymm(symmA);
+ // generalized eigen pb
+ SelfAdjointEigenSolver<MatrixType> eiSymmGen(symmA, symmB);
+
+ #ifdef HAS_GSL
+ if (ei_is_same_type<RealScalar,double>::ret)
+ {
+ typedef GslTraits<Scalar> Gsl;
+ typename Gsl::Matrix gEvec=0, gSymmA=0, gSymmB=0;
+ typename GslTraits<RealScalar>::Vector gEval=0;
+ RealVectorType _eval;
+ MatrixType _evec;
+ convert<MatrixType>(symmA, gSymmA);
+ convert<MatrixType>(symmB, gSymmB);
+ convert<MatrixType>(symmA, gEvec);
+ gEval = GslTraits<RealScalar>::createVector(rows);
+
+ Gsl::eigen_symm(gSymmA, gEval, gEvec);
+ convert(gEval, _eval);
+ convert(gEvec, _evec);
+
+ // test gsl itself !
+ VERIFY((symmA * _evec).isApprox(_evec * _eval.asDiagonal(), largerEps));
+
+ // compare with eigen
+ VERIFY_IS_APPROX(_eval, eiSymm.eigenvalues());
+ VERIFY_IS_APPROX(_evec.cwise().abs(), eiSymm.eigenvectors().cwise().abs());
+
+ // generalized pb
+ Gsl::eigen_symm_gen(gSymmA, gSymmB, gEval, gEvec);
+ convert(gEval, _eval);
+ convert(gEvec, _evec);
+ // test GSL itself:
+ VERIFY((symmA * _evec).isApprox(symmB * (_evec * _eval.asDiagonal()), largerEps));
+
+ // compare with eigen
+ MatrixType normalized_eivec = eiSymmGen.eigenvectors()*eiSymmGen.eigenvectors().colwise().norm().asDiagonal().inverse();
+ VERIFY_IS_APPROX(_eval, eiSymmGen.eigenvalues());
+ VERIFY_IS_APPROX(_evec.cwiseAbs(), normalized_eivec.cwiseAbs());
+
+ Gsl::free(gSymmA);
+ Gsl::free(gSymmB);
+ GslTraits<RealScalar>::free(gEval);
+ Gsl::free(gEvec);
+ }
+ #endif
+
+ VERIFY((symmA * eiSymm.eigenvectors()).isApprox(
+ eiSymm.eigenvectors() * eiSymm.eigenvalues().asDiagonal(), largerEps));
+
+ // generalized eigen problem Ax = lBx
+ VERIFY((symmA * eiSymmGen.eigenvectors()).isApprox(
+ symmB * (eiSymmGen.eigenvectors() * eiSymmGen.eigenvalues().asDiagonal()), largerEps));
+
+ MatrixType sqrtSymmA = eiSymm.operatorSqrt();
+ VERIFY_IS_APPROX(symmA, sqrtSymmA*sqrtSymmA);
+ VERIFY_IS_APPROX(sqrtSymmA, symmA*eiSymm.operatorInverseSqrt());
+}
+
+template<typename MatrixType> void eigensolver(const MatrixType& m)
+{
+ /* this test covers the following files:
+ EigenSolver.h
+ */
+ int rows = m.rows();
+ int cols = m.cols();
+
+ typedef typename MatrixType::Scalar Scalar;
+ typedef typename NumTraits<Scalar>::Real RealScalar;
+ typedef Matrix<Scalar, MatrixType::RowsAtCompileTime, 1> VectorType;
+ typedef Matrix<RealScalar, MatrixType::RowsAtCompileTime, 1> RealVectorType;
+ typedef typename std::complex<typename NumTraits<typename MatrixType::Scalar>::Real> Complex;
+
+ // RealScalar largerEps = 10*test_precision<RealScalar>();
+
+ MatrixType a = MatrixType::Random(rows,cols);
+ MatrixType a1 = MatrixType::Random(rows,cols);
+ MatrixType symmA = a.adjoint() * a + a1.adjoint() * a1;
+
+ EigenSolver<MatrixType> ei0(symmA);
+ VERIFY_IS_APPROX(symmA * ei0.pseudoEigenvectors(), ei0.pseudoEigenvectors() * ei0.pseudoEigenvalueMatrix());
+ VERIFY_IS_APPROX((symmA.template cast<Complex>()) * (ei0.pseudoEigenvectors().template cast<Complex>()),
+ (ei0.pseudoEigenvectors().template cast<Complex>()) * (ei0.eigenvalues().asDiagonal()));
+
+ EigenSolver<MatrixType> ei1(a);
+ VERIFY_IS_APPROX(a * ei1.pseudoEigenvectors(), ei1.pseudoEigenvectors() * ei1.pseudoEigenvalueMatrix());
+ VERIFY_IS_APPROX(a.template cast<Complex>() * ei1.eigenvectors(),
+ ei1.eigenvectors() * ei1.eigenvalues().asDiagonal());
+
+}
+
+void test_eigen2_eigensolver()
+{
+ for(int i = 0; i < g_repeat; i++) {
+ // very important to test a 3x3 matrix since we provide a special path for it
+ CALL_SUBTEST_1( selfadjointeigensolver(Matrix3f()) );
+ CALL_SUBTEST_2( selfadjointeigensolver(Matrix4d()) );
+ CALL_SUBTEST_3( selfadjointeigensolver(MatrixXf(7,7)) );
+ CALL_SUBTEST_4( selfadjointeigensolver(MatrixXcd(5,5)) );
+ CALL_SUBTEST_5( selfadjointeigensolver(MatrixXd(19,19)) );
+
+ CALL_SUBTEST_6( eigensolver(Matrix4f()) );
+ CALL_SUBTEST_5( eigensolver(MatrixXd(17,17)) );
+ }
+}
+
diff --git a/test/eigen2/eigen2_first_aligned.cpp b/test/eigen2/eigen2_first_aligned.cpp
new file mode 100644
index 000000000..51bb3cad1
--- /dev/null
+++ b/test/eigen2/eigen2_first_aligned.cpp
@@ -0,0 +1,49 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra.
+//
+// Copyright (C) 2009 Benoit Jacob <jacob.benoit.1@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 "main.h"
+
+template<typename Scalar>
+void test_eigen2_first_aligned_helper(Scalar *array, int size)
+{
+ const int packet_size = sizeof(Scalar) * ei_packet_traits<Scalar>::size;
+ VERIFY(((std::size_t(array) + sizeof(Scalar) * ei_alignmentOffset(array, size)) % packet_size) == 0);
+}
+
+template<typename Scalar>
+void test_eigen2_none_aligned_helper(Scalar *array, int size)
+{
+ VERIFY(ei_packet_traits<Scalar>::size == 1 || ei_alignmentOffset(array, size) == size);
+}
+
+struct some_non_vectorizable_type { float x; };
+
+void test_eigen2_first_aligned()
+{
+ EIGEN_ALIGN_128 float array_float[100];
+ test_first_aligned_helper(array_float, 50);
+ test_first_aligned_helper(array_float+1, 50);
+ test_first_aligned_helper(array_float+2, 50);
+ test_first_aligned_helper(array_float+3, 50);
+ test_first_aligned_helper(array_float+4, 50);
+ test_first_aligned_helper(array_float+5, 50);
+
+ EIGEN_ALIGN_128 double array_double[100];
+ test_first_aligned_helper(array_double, 50);
+ test_first_aligned_helper(array_double+1, 50);
+ test_first_aligned_helper(array_double+2, 50);
+
+ double *array_double_plus_4_bytes = (double*)(std::size_t(array_double)+4);
+ test_none_aligned_helper(array_double_plus_4_bytes, 50);
+ test_none_aligned_helper(array_double_plus_4_bytes+1, 50);
+
+ some_non_vectorizable_type array_nonvec[100];
+ test_first_aligned_helper(array_nonvec, 100);
+ test_none_aligned_helper(array_nonvec, 100);
+}
diff --git a/test/eigen2/eigen2_geometry.cpp b/test/eigen2/eigen2_geometry.cpp
new file mode 100644
index 000000000..70b4ab5f1
--- /dev/null
+++ b/test/eigen2/eigen2_geometry.cpp
@@ -0,0 +1,431 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra. Eigen itself is part of the KDE project.
+//
+// Copyright (C) 2008 Gael Guennebaud <g.gael@free.fr>
+//
+// This Source Code Form is subject to the terms of the Mozilla
+// Public License v. 2.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 "main.h"
+#include <Eigen/Geometry>
+#include <Eigen/LU>
+#include <Eigen/SVD>
+
+template<typename Scalar> void geometry(void)
+{
+ /* this test covers the following files:
+ Cross.h Quaternion.h, Transform.cpp
+ */
+
+ typedef Matrix<Scalar,2,2> Matrix2;
+ typedef Matrix<Scalar,3,3> Matrix3;
+ typedef Matrix<Scalar,4,4> Matrix4;
+ typedef Matrix<Scalar,2,1> Vector2;
+ typedef Matrix<Scalar,3,1> Vector3;
+ typedef Matrix<Scalar,4,1> Vector4;
+ typedef Quaternion<Scalar> Quaternionx;
+ typedef AngleAxis<Scalar> AngleAxisx;
+ typedef Transform<Scalar,2> Transform2;
+ typedef Transform<Scalar,3> Transform3;
+ typedef Scaling<Scalar,2> Scaling2;
+ typedef Scaling<Scalar,3> Scaling3;
+ typedef Translation<Scalar,2> Translation2;
+ typedef Translation<Scalar,3> Translation3;
+
+ Scalar largeEps = test_precision<Scalar>();
+ if (ei_is_same_type<Scalar,float>::ret)
+ largeEps = 1e-2f;
+
+ Vector3 v0 = Vector3::Random(),
+ v1 = Vector3::Random(),
+ v2 = Vector3::Random();
+ Vector2 u0 = Vector2::Random();
+ Matrix3 matrot1;
+
+ Scalar a = ei_random<Scalar>(-Scalar(M_PI), Scalar(M_PI));
+
+ // cross product
+ VERIFY_IS_MUCH_SMALLER_THAN(v1.cross(v2).eigen2_dot(v1), Scalar(1));
+ Matrix3 m;
+ m << v0.normalized(),
+ (v0.cross(v1)).normalized(),
+ (v0.cross(v1).cross(v0)).normalized();
+ VERIFY(m.isUnitary());
+
+ // Quaternion: Identity(), setIdentity();
+ Quaternionx q1, q2;
+ q2.setIdentity();
+ VERIFY_IS_APPROX(Quaternionx(Quaternionx::Identity()).coeffs(), q2.coeffs());
+ q1.coeffs().setRandom();
+ VERIFY_IS_APPROX(q1.coeffs(), (q1*q2).coeffs());
+
+ // unitOrthogonal
+ VERIFY_IS_MUCH_SMALLER_THAN(u0.unitOrthogonal().eigen2_dot(u0), Scalar(1));
+ VERIFY_IS_MUCH_SMALLER_THAN(v0.unitOrthogonal().eigen2_dot(v0), Scalar(1));
+ VERIFY_IS_APPROX(u0.unitOrthogonal().norm(), Scalar(1));
+ VERIFY_IS_APPROX(v0.unitOrthogonal().norm(), Scalar(1));
+
+
+ VERIFY_IS_APPROX(v0, AngleAxisx(a, v0.normalized()) * v0);
+ VERIFY_IS_APPROX(-v0, AngleAxisx(Scalar(M_PI), v0.unitOrthogonal()) * v0);
+ VERIFY_IS_APPROX(ei_cos(a)*v0.squaredNorm(), v0.eigen2_dot(AngleAxisx(a, v0.unitOrthogonal()) * v0));
+ m = AngleAxisx(a, v0.normalized()).toRotationMatrix().adjoint();
+ VERIFY_IS_APPROX(Matrix3::Identity(), m * AngleAxisx(a, v0.normalized()));
+ VERIFY_IS_APPROX(Matrix3::Identity(), AngleAxisx(a, v0.normalized()) * m);
+
+ q1 = AngleAxisx(a, v0.normalized());
+ q2 = AngleAxisx(a, v1.normalized());
+
+ // angular distance
+ Scalar refangle = ei_abs(AngleAxisx(q1.inverse()*q2).angle());
+ if (refangle>Scalar(M_PI))
+ refangle = Scalar(2)*Scalar(M_PI) - refangle;
+
+ if((q1.coeffs()-q2.coeffs()).norm() > 10*largeEps)
+ {
+ VERIFY(ei_isApprox(q1.angularDistance(q2), refangle, largeEps));
+ }
+
+ // rotation matrix conversion
+ VERIFY_IS_APPROX(q1 * v2, q1.toRotationMatrix() * v2);
+ VERIFY_IS_APPROX(q1 * q2 * v2,
+ q1.toRotationMatrix() * q2.toRotationMatrix() * v2);
+
+ VERIFY( (q2*q1).isApprox(q1*q2, largeEps) || !(q2 * q1 * v2).isApprox(
+ q1.toRotationMatrix() * q2.toRotationMatrix() * v2));
+
+ q2 = q1.toRotationMatrix();
+ VERIFY_IS_APPROX(q1*v1,q2*v1);
+
+ matrot1 = AngleAxisx(Scalar(0.1), Vector3::UnitX())
+ * AngleAxisx(Scalar(0.2), Vector3::UnitY())
+ * AngleAxisx(Scalar(0.3), Vector3::UnitZ());
+ VERIFY_IS_APPROX(matrot1 * v1,
+ AngleAxisx(Scalar(0.1), Vector3(1,0,0)).toRotationMatrix()
+ * (AngleAxisx(Scalar(0.2), Vector3(0,1,0)).toRotationMatrix()
+ * (AngleAxisx(Scalar(0.3), Vector3(0,0,1)).toRotationMatrix() * v1)));
+
+ // angle-axis conversion
+ AngleAxisx aa = q1;
+ VERIFY_IS_APPROX(q1 * v1, Quaternionx(aa) * v1);
+ VERIFY_IS_NOT_APPROX(q1 * v1, Quaternionx(AngleAxisx(aa.angle()*2,aa.axis())) * v1);
+
+ // from two vector creation
+ VERIFY_IS_APPROX(v2.normalized(),(q2.setFromTwoVectors(v1,v2)*v1).normalized());
+ VERIFY_IS_APPROX(v2.normalized(),(q2.setFromTwoVectors(v1,v2)*v1).normalized());
+
+ // inverse and conjugate
+ VERIFY_IS_APPROX(q1 * (q1.inverse() * v1), v1);
+ VERIFY_IS_APPROX(q1 * (q1.conjugate() * v1), v1);
+
+ // AngleAxis
+ VERIFY_IS_APPROX(AngleAxisx(a,v1.normalized()).toRotationMatrix(),
+ Quaternionx(AngleAxisx(a,v1.normalized())).toRotationMatrix());
+
+ AngleAxisx aa1;
+ m = q1.toRotationMatrix();
+ aa1 = m;
+ VERIFY_IS_APPROX(AngleAxisx(m).toRotationMatrix(),
+ Quaternionx(m).toRotationMatrix());
+
+ // Transform
+ // TODO complete the tests !
+ a = 0;
+ while (ei_abs(a)<Scalar(0.1))
+ a = ei_random<Scalar>(-Scalar(0.4)*Scalar(M_PI), Scalar(0.4)*Scalar(M_PI));
+ q1 = AngleAxisx(a, v0.normalized());
+ Transform3 t0, t1, t2;
+ // first test setIdentity() and Identity()
+ t0.setIdentity();
+ VERIFY_IS_APPROX(t0.matrix(), Transform3::MatrixType::Identity());
+ t0.matrix().setZero();
+ t0 = Transform3::Identity();
+ VERIFY_IS_APPROX(t0.matrix(), Transform3::MatrixType::Identity());
+
+ t0.linear() = q1.toRotationMatrix();
+ t1.setIdentity();
+ t1.linear() = q1.toRotationMatrix();
+
+ v0 << 50, 2, 1;//= ei_random_matrix<Vector3>().cwiseProduct(Vector3(10,2,0.5));
+ t0.scale(v0);
+ t1.prescale(v0);
+
+ VERIFY_IS_APPROX( (t0 * Vector3(1,0,0)).norm(), v0.x());
+ //VERIFY(!ei_isApprox((t1 * Vector3(1,0,0)).norm(), v0.x()));
+
+ t0.setIdentity();
+ t1.setIdentity();
+ v1 << 1, 2, 3;
+ t0.linear() = q1.toRotationMatrix();
+ t0.pretranslate(v0);
+ t0.scale(v1);
+ t1.linear() = q1.conjugate().toRotationMatrix();
+ t1.prescale(v1.cwise().inverse());
+ t1.translate(-v0);
+
+ VERIFY((t0.matrix() * t1.matrix()).isIdentity(test_precision<Scalar>()));
+
+ t1.fromPositionOrientationScale(v0, q1, v1);
+ VERIFY_IS_APPROX(t1.matrix(), t0.matrix());
+ VERIFY_IS_APPROX(t1*v1, t0*v1);
+
+ t0.setIdentity(); t0.scale(v0).rotate(q1.toRotationMatrix());
+ t1.setIdentity(); t1.scale(v0).rotate(q1);
+ VERIFY_IS_APPROX(t0.matrix(), t1.matrix());
+
+ t0.setIdentity(); t0.scale(v0).rotate(AngleAxisx(q1));
+ VERIFY_IS_APPROX(t0.matrix(), t1.matrix());
+
+ VERIFY_IS_APPROX(t0.scale(a).matrix(), t1.scale(Vector3::Constant(a)).matrix());
+ VERIFY_IS_APPROX(t0.prescale(a).matrix(), t1.prescale(Vector3::Constant(a)).matrix());
+
+ // More transform constructors, operator=, operator*=
+
+ Matrix3 mat3 = Matrix3::Random();
+ Matrix4 mat4;
+ mat4 << mat3 , Vector3::Zero() , Vector4::Zero().transpose();
+ Transform3 tmat3(mat3), tmat4(mat4);
+ tmat4.matrix()(3,3) = Scalar(1);
+ VERIFY_IS_APPROX(tmat3.matrix(), tmat4.matrix());
+
+ Scalar a3 = ei_random<Scalar>(-Scalar(M_PI), Scalar(M_PI));
+ Vector3 v3 = Vector3::Random().normalized();
+ AngleAxisx aa3(a3, v3);
+ Transform3 t3(aa3);
+ Transform3 t4;
+ t4 = aa3;
+ VERIFY_IS_APPROX(t3.matrix(), t4.matrix());
+ t4.rotate(AngleAxisx(-a3,v3));
+ VERIFY_IS_APPROX(t4.matrix(), Matrix4::Identity());
+ t4 *= aa3;
+ VERIFY_IS_APPROX(t3.matrix(), t4.matrix());
+
+ v3 = Vector3::Random();
+ Translation3 tv3(v3);
+ Transform3 t5(tv3);
+ t4 = tv3;
+ VERIFY_IS_APPROX(t5.matrix(), t4.matrix());
+ t4.translate(-v3);
+ VERIFY_IS_APPROX(t4.matrix(), Matrix4::Identity());
+ t4 *= tv3;
+ VERIFY_IS_APPROX(t5.matrix(), t4.matrix());
+
+ Scaling3 sv3(v3);
+ Transform3 t6(sv3);
+ t4 = sv3;
+ VERIFY_IS_APPROX(t6.matrix(), t4.matrix());
+ t4.scale(v3.cwise().inverse());
+ VERIFY_IS_APPROX(t4.matrix(), Matrix4::Identity());
+ t4 *= sv3;
+ VERIFY_IS_APPROX(t6.matrix(), t4.matrix());
+
+ // matrix * transform
+ VERIFY_IS_APPROX(Transform3(t3.matrix()*t4).matrix(), Transform3(t3*t4).matrix());
+
+ // chained Transform product
+ VERIFY_IS_APPROX(((t3*t4)*t5).matrix(), (t3*(t4*t5)).matrix());
+
+ // check that Transform product doesn't have aliasing problems
+ t5 = t4;
+ t5 = t5*t5;
+ VERIFY_IS_APPROX(t5, t4*t4);
+
+ // 2D transformation
+ Transform2 t20, t21;
+ Vector2 v20 = Vector2::Random();
+ Vector2 v21 = Vector2::Random();
+ for (int k=0; k<2; ++k)
+ if (ei_abs(v21[k])<Scalar(1e-3)) v21[k] = Scalar(1e-3);
+ t21.setIdentity();
+ t21.linear() = Rotation2D<Scalar>(a).toRotationMatrix();
+ VERIFY_IS_APPROX(t20.fromPositionOrientationScale(v20,a,v21).matrix(),
+ t21.pretranslate(v20).scale(v21).matrix());
+
+ t21.setIdentity();
+ t21.linear() = Rotation2D<Scalar>(-a).toRotationMatrix();
+ VERIFY( (t20.fromPositionOrientationScale(v20,a,v21)
+ * (t21.prescale(v21.cwise().inverse()).translate(-v20))).matrix().isIdentity(test_precision<Scalar>()) );
+
+ // Transform - new API
+ // 3D
+ t0.setIdentity();
+ t0.rotate(q1).scale(v0).translate(v0);
+ // mat * scaling and mat * translation
+ t1 = (Matrix3(q1) * Scaling3(v0)) * Translation3(v0);
+ VERIFY_IS_APPROX(t0.matrix(), t1.matrix());
+ // mat * transformation and scaling * translation
+ t1 = Matrix3(q1) * (Scaling3(v0) * Translation3(v0));
+ VERIFY_IS_APPROX(t0.matrix(), t1.matrix());
+
+ t0.setIdentity();
+ t0.prerotate(q1).prescale(v0).pretranslate(v0);
+ // translation * scaling and transformation * mat
+ t1 = (Translation3(v0) * Scaling3(v0)) * Matrix3(q1);
+ VERIFY_IS_APPROX(t0.matrix(), t1.matrix());
+ // scaling * mat and translation * mat
+ t1 = Translation3(v0) * (Scaling3(v0) * Matrix3(q1));
+ VERIFY_IS_APPROX(t0.matrix(), t1.matrix());
+
+ t0.setIdentity();
+ t0.scale(v0).translate(v0).rotate(q1);
+ // translation * mat and scaling * transformation
+ t1 = Scaling3(v0) * (Translation3(v0) * Matrix3(q1));
+ VERIFY_IS_APPROX(t0.matrix(), t1.matrix());
+ // transformation * scaling
+ t0.scale(v0);
+ t1 = t1 * Scaling3(v0);
+ VERIFY_IS_APPROX(t0.matrix(), t1.matrix());
+ // transformation * translation
+ t0.translate(v0);
+ t1 = t1 * Translation3(v0);
+ VERIFY_IS_APPROX(t0.matrix(), t1.matrix());
+ // translation * transformation
+ t0.pretranslate(v0);
+ t1 = Translation3(v0) * t1;
+ VERIFY_IS_APPROX(t0.matrix(), t1.matrix());
+
+ // transform * quaternion
+ t0.rotate(q1);
+ t1 = t1 * q1;
+ VERIFY_IS_APPROX(t0.matrix(), t1.matrix());
+
+ // translation * quaternion
+ t0.translate(v1).rotate(q1);
+ t1 = t1 * (Translation3(v1) * q1);
+ VERIFY_IS_APPROX(t0.matrix(), t1.matrix());
+
+ // scaling * quaternion
+ t0.scale(v1).rotate(q1);
+ t1 = t1 * (Scaling3(v1) * q1);
+ VERIFY_IS_APPROX(t0.matrix(), t1.matrix());
+
+ // quaternion * transform
+ t0.prerotate(q1);
+ t1 = q1 * t1;
+ VERIFY_IS_APPROX(t0.matrix(), t1.matrix());
+
+ // quaternion * translation
+ t0.rotate(q1).translate(v1);
+ t1 = t1 * (q1 * Translation3(v1));
+ VERIFY_IS_APPROX(t0.matrix(), t1.matrix());
+
+ // quaternion * scaling
+ t0.rotate(q1).scale(v1);
+ t1 = t1 * (q1 * Scaling3(v1));
+ VERIFY_IS_APPROX(t0.matrix(), t1.matrix());
+
+ // translation * vector
+ t0.setIdentity();
+ t0.translate(v0);
+ VERIFY_IS_APPROX(t0 * v1, Translation3(v0) * v1);
+
+ // scaling * vector
+ t0.setIdentity();
+ t0.scale(v0);
+ VERIFY_IS_APPROX(t0 * v1, Scaling3(v0) * v1);
+
+ // test transform inversion
+ t0.setIdentity();
+ t0.translate(v0);
+ t0.linear().setRandom();
+ VERIFY_IS_APPROX(t0.inverse(Affine), t0.matrix().inverse());
+ t0.setIdentity();
+ t0.translate(v0).rotate(q1);
+ VERIFY_IS_APPROX(t0.inverse(Isometry), t0.matrix().inverse());
+
+ // test extract rotation and scaling
+ t0.setIdentity();
+ t0.translate(v0).rotate(q1).scale(v1);
+ VERIFY_IS_APPROX(t0.rotation() * v1, Matrix3(q1) * v1);
+
+ Matrix3 mat_rotation, mat_scaling;
+ t0.setIdentity();
+ t0.translate(v0).rotate(q1).scale(v1);
+ t0.computeRotationScaling(&mat_rotation, &mat_scaling);
+ VERIFY_IS_APPROX(t0.linear(), mat_rotation * mat_scaling);
+ VERIFY_IS_APPROX(mat_rotation*mat_rotation.adjoint(), Matrix3::Identity());
+ VERIFY_IS_APPROX(mat_rotation.determinant(), Scalar(1));
+ t0.computeScalingRotation(&mat_scaling, &mat_rotation);
+ VERIFY_IS_APPROX(t0.linear(), mat_scaling * mat_rotation);
+ VERIFY_IS_APPROX(mat_rotation*mat_rotation.adjoint(), Matrix3::Identity());
+ VERIFY_IS_APPROX(mat_rotation.determinant(), Scalar(1));
+
+ // test casting
+ Transform<float,3> t1f = t1.template cast<float>();
+ VERIFY_IS_APPROX(t1f.template cast<Scalar>(),t1);
+ Transform<double,3> t1d = t1.template cast<double>();
+ VERIFY_IS_APPROX(t1d.template cast<Scalar>(),t1);
+
+ Translation3 tr1(v0);
+ Translation<float,3> tr1f = tr1.template cast<float>();
+ VERIFY_IS_APPROX(tr1f.template cast<Scalar>(),tr1);
+ Translation<double,3> tr1d = tr1.template cast<double>();
+ VERIFY_IS_APPROX(tr1d.template cast<Scalar>(),tr1);
+
+ Scaling3 sc1(v0);
+ Scaling<float,3> sc1f = sc1.template cast<float>();
+ VERIFY_IS_APPROX(sc1f.template cast<Scalar>(),sc1);
+ Scaling<double,3> sc1d = sc1.template cast<double>();
+ VERIFY_IS_APPROX(sc1d.template cast<Scalar>(),sc1);
+
+ Quaternion<float> q1f = q1.template cast<float>();
+ VERIFY_IS_APPROX(q1f.template cast<Scalar>(),q1);
+ Quaternion<double> q1d = q1.template cast<double>();
+ VERIFY_IS_APPROX(q1d.template cast<Scalar>(),q1);
+
+ AngleAxis<float> aa1f = aa1.template cast<float>();
+ VERIFY_IS_APPROX(aa1f.template cast<Scalar>(),aa1);
+ AngleAxis<double> aa1d = aa1.template cast<double>();
+ VERIFY_IS_APPROX(aa1d.template cast<Scalar>(),aa1);
+
+ Rotation2D<Scalar> r2d1(ei_random<Scalar>());
+ Rotation2D<float> r2d1f = r2d1.template cast<float>();
+ VERIFY_IS_APPROX(r2d1f.template cast<Scalar>(),r2d1);
+ Rotation2D<double> r2d1d = r2d1.template cast<double>();
+ VERIFY_IS_APPROX(r2d1d.template cast<Scalar>(),r2d1);
+
+ m = q1;
+// m.col(1) = Vector3(0,ei_random<Scalar>(),ei_random<Scalar>()).normalized();
+// m.col(0) = Vector3(-1,0,0).normalized();
+// m.col(2) = m.col(0).cross(m.col(1));
+ #define VERIFY_EULER(I,J,K, X,Y,Z) { \
+ Vector3 ea = m.eulerAngles(I,J,K); \
+ Matrix3 m1 = Matrix3(AngleAxisx(ea[0], Vector3::Unit##X()) * AngleAxisx(ea[1], Vector3::Unit##Y()) * AngleAxisx(ea[2], Vector3::Unit##Z())); \
+ VERIFY_IS_APPROX(m, Matrix3(AngleAxisx(ea[0], Vector3::Unit##X()) * AngleAxisx(ea[1], Vector3::Unit##Y()) * AngleAxisx(ea[2], Vector3::Unit##Z()))); \
+ }
+ VERIFY_EULER(0,1,2, X,Y,Z);
+ VERIFY_EULER(0,1,0, X,Y,X);
+ VERIFY_EULER(0,2,1, X,Z,Y);
+ VERIFY_EULER(0,2,0, X,Z,X);
+
+ VERIFY_EULER(1,2,0, Y,Z,X);
+ VERIFY_EULER(1,2,1, Y,Z,Y);
+ VERIFY_EULER(1,0,2, Y,X,Z);
+ VERIFY_EULER(1,0,1, Y,X,Y);
+
+ VERIFY_EULER(2,0,1, Z,X,Y);
+ VERIFY_EULER(2,0,2, Z,X,Z);
+ VERIFY_EULER(2,1,0, Z,Y,X);
+ VERIFY_EULER(2,1,2, Z,Y,Z);
+
+ // colwise/rowwise cross product
+ mat3.setRandom();
+ Vector3 vec3 = Vector3::Random();
+ Matrix3 mcross;
+ int i = ei_random<int>(0,2);
+ mcross = mat3.colwise().cross(vec3);
+ VERIFY_IS_APPROX(mcross.col(i), mat3.col(i).cross(vec3));
+ mcross = mat3.rowwise().cross(vec3);
+ VERIFY_IS_APPROX(mcross.row(i), mat3.row(i).cross(vec3));
+
+
+}
+
+void test_eigen2_geometry()
+{
+ for(int i = 0; i < g_repeat; i++) {
+ CALL_SUBTEST_1( geometry<float>() );
+ CALL_SUBTEST_2( geometry<double>() );
+ }
+}
diff --git a/test/eigen2/eigen2_geometry_with_eigen2_prefix.cpp b/test/eigen2/eigen2_geometry_with_eigen2_prefix.cpp
new file mode 100644
index 000000000..f83b57249
--- /dev/null
+++ b/test/eigen2/eigen2_geometry_with_eigen2_prefix.cpp
@@ -0,0 +1,434 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra. Eigen itself is part of the KDE project.
+//
+// Copyright (C) 2008 Gael Guennebaud <g.gael@free.fr>
+//
+// This Source Code Form is subject to the terms of the Mozilla
+// Public License v. 2.0. If a copy of the MPL was not distributed
+// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+#define EIGEN2_SUPPORT_STAGE15_RESOLVE_API_CONFLICTS_WARN
+
+#include "main.h"
+#include <Eigen/Geometry>
+#include <Eigen/LU>
+#include <Eigen/SVD>
+
+template<typename Scalar> void geometry(void)
+{
+ /* this test covers the following files:
+ Cross.h Quaternion.h, Transform.cpp
+ */
+
+ typedef Matrix<Scalar,2,2> Matrix2;
+ typedef Matrix<Scalar,3,3> Matrix3;
+ typedef Matrix<Scalar,4,4> Matrix4;
+ typedef Matrix<Scalar,2,1> Vector2;
+ typedef Matrix<Scalar,3,1> Vector3;
+ typedef Matrix<Scalar,4,1> Vector4;
+ typedef eigen2_Quaternion<Scalar> Quaternionx;
+ typedef eigen2_AngleAxis<Scalar> AngleAxisx;
+ typedef eigen2_Transform<Scalar,2> Transform2;
+ typedef eigen2_Transform<Scalar,3> Transform3;
+ typedef eigen2_Scaling<Scalar,2> Scaling2;
+ typedef eigen2_Scaling<Scalar,3> Scaling3;
+ typedef eigen2_Translation<Scalar,2> Translation2;
+ typedef eigen2_Translation<Scalar,3> Translation3;
+
+ Scalar largeEps = test_precision<Scalar>();
+ if (ei_is_same_type<Scalar,float>::ret)
+ largeEps = 1e-2f;
+
+ Vector3 v0 = Vector3::Random(),
+ v1 = Vector3::Random(),
+ v2 = Vector3::Random();
+ Vector2 u0 = Vector2::Random();
+ Matrix3 matrot1;
+
+ Scalar a = ei_random<Scalar>(-Scalar(M_PI), Scalar(M_PI));
+
+ // cross product
+ VERIFY_IS_MUCH_SMALLER_THAN(v1.cross(v2).eigen2_dot(v1), Scalar(1));
+ Matrix3 m;
+ m << v0.normalized(),
+ (v0.cross(v1)).normalized(),
+ (v0.cross(v1).cross(v0)).normalized();
+ VERIFY(m.isUnitary());
+
+ // Quaternion: Identity(), setIdentity();
+ Quaternionx q1, q2;
+ q2.setIdentity();
+ VERIFY_IS_APPROX(Quaternionx(Quaternionx::Identity()).coeffs(), q2.coeffs());
+ q1.coeffs().setRandom();
+ VERIFY_IS_APPROX(q1.coeffs(), (q1*q2).coeffs());
+
+ // unitOrthogonal
+ VERIFY_IS_MUCH_SMALLER_THAN(u0.unitOrthogonal().eigen2_dot(u0), Scalar(1));
+ VERIFY_IS_MUCH_SMALLER_THAN(v0.unitOrthogonal().eigen2_dot(v0), Scalar(1));
+ VERIFY_IS_APPROX(u0.unitOrthogonal().norm(), Scalar(1));
+ VERIFY_IS_APPROX(v0.unitOrthogonal().norm(), Scalar(1));
+
+
+ VERIFY_IS_APPROX(v0, AngleAxisx(a, v0.normalized()) * v0);
+ VERIFY_IS_APPROX(-v0, AngleAxisx(Scalar(M_PI), v0.unitOrthogonal()) * v0);
+ VERIFY_IS_APPROX(ei_cos(a)*v0.squaredNorm(), v0.eigen2_dot(AngleAxisx(a, v0.unitOrthogonal()) * v0));
+ m = AngleAxisx(a, v0.normalized()).toRotationMatrix().adjoint();
+ VERIFY_IS_APPROX(Matrix3::Identity(), m * AngleAxisx(a, v0.normalized()));
+ VERIFY_IS_APPROX(Matrix3::Identity(), AngleAxisx(a, v0.normalized()) * m);
+
+ q1 = AngleAxisx(a, v0.normalized());
+ q2 = AngleAxisx(a, v1.normalized());
+
+ // angular distance
+ Scalar refangle = ei_abs(AngleAxisx(q1.inverse()*q2).angle());
+ if (refangle>Scalar(M_PI))
+ refangle = Scalar(2)*Scalar(M_PI) - refangle;
+
+ if((q1.coeffs()-q2.coeffs()).norm() > 10*largeEps)
+ {
+ VERIFY(ei_isApprox(q1.angularDistance(q2), refangle, largeEps));
+ }
+
+ // rotation matrix conversion
+ VERIFY_IS_APPROX(q1 * v2, q1.toRotationMatrix() * v2);
+ VERIFY_IS_APPROX(q1 * q2 * v2,
+ q1.toRotationMatrix() * q2.toRotationMatrix() * v2);
+
+ VERIFY( (q2*q1).isApprox(q1*q2, largeEps) || !(q2 * q1 * v2).isApprox(
+ q1.toRotationMatrix() * q2.toRotationMatrix() * v2));
+
+ q2 = q1.toRotationMatrix();
+ VERIFY_IS_APPROX(q1*v1,q2*v1);
+
+ matrot1 = AngleAxisx(Scalar(0.1), Vector3::UnitX())
+ * AngleAxisx(Scalar(0.2), Vector3::UnitY())
+ * AngleAxisx(Scalar(0.3), Vector3::UnitZ());
+ VERIFY_IS_APPROX(matrot1 * v1,
+ AngleAxisx(Scalar(0.1), Vector3(1,0,0)).toRotationMatrix()
+ * (AngleAxisx(Scalar(0.2), Vector3(0,1,0)).toRotationMatrix()
+ * (AngleAxisx(Scalar(0.3), Vector3(0,0,1)).toRotationMatrix() * v1)));
+
+ // angle-axis conversion
+ AngleAxisx aa = q1;
+ VERIFY_IS_APPROX(q1 * v1, Quaternionx(aa) * v1);
+ VERIFY_IS_NOT_APPROX(q1 * v1, Quaternionx(AngleAxisx(aa.angle()*2,aa.axis())) * v1);
+
+ // from two vector creation
+ VERIFY_IS_APPROX(v2.normalized(),(q2.setFromTwoVectors(v1,v2)*v1).normalized());
+ VERIFY_IS_APPROX(v2.normalized(),(q2.setFromTwoVectors(v1,v2)*v1).normalized());
+
+ // inverse and conjugate
+ VERIFY_IS_APPROX(q1 * (q1.inverse() * v1), v1);
+ VERIFY_IS_APPROX(q1 * (q1.conjugate() * v1), v1);
+
+ // AngleAxis
+ VERIFY_IS_APPROX(AngleAxisx(a,v1.normalized()).toRotationMatrix(),
+ Quaternionx(AngleAxisx(a,v1.normalized())).toRotationMatrix());
+
+ AngleAxisx aa1;
+ m = q1.toRotationMatrix();
+ aa1 = m;
+ VERIFY_IS_APPROX(AngleAxisx(m).toRotationMatrix(),
+ Quaternionx(m).toRotationMatrix());
+
+ // Transform
+ // TODO complete the tests !
+ a = 0;
+ while (ei_abs(a)<Scalar(0.1))
+ a = ei_random<Scalar>(-Scalar(0.4)*Scalar(M_PI), Scalar(0.4)*Scalar(M_PI));
+ q1 = AngleAxisx(a, v0.normalized());
+ Transform3 t0, t1, t2;
+ // first test setIdentity() and Identity()
+ t0.setIdentity();
+ VERIFY_IS_APPROX(t0.matrix(), Transform3::MatrixType::Identity());
+ t0.matrix().setZero();
+ t0 = Transform3::Identity();
+ VERIFY_IS_APPROX(t0.matrix(), Transform3::MatrixType::Identity());
+
+ t0.linear() = q1.toRotationMatrix();
+ t1.setIdentity();
+ t1.linear() = q1.toRotationMatrix();
+
+ v0 << 50, 2, 1;//= ei_random_matrix<Vector3>().cwiseProduct(Vector3(10,2,0.5));
+ t0.scale(v0);
+ t1.prescale(v0);
+
+ VERIFY_IS_APPROX( (t0 * Vector3(1,0,0)).norm(), v0.x());
+ //VERIFY(!ei_isApprox((t1 * Vector3(1,0,0)).norm(), v0.x()));
+
+ t0.setIdentity();
+ t1.setIdentity();
+ v1 << 1, 2, 3;
+ t0.linear() = q1.toRotationMatrix();
+ t0.pretranslate(v0);
+ t0.scale(v1);
+ t1.linear() = q1.conjugate().toRotationMatrix();
+ t1.prescale(v1.cwise().inverse());
+ t1.translate(-v0);
+
+ VERIFY((t0.matrix() * t1.matrix()).isIdentity(test_precision<Scalar>()));
+
+ t1.fromPositionOrientationScale(v0, q1, v1);
+ VERIFY_IS_APPROX(t1.matrix(), t0.matrix());
+ VERIFY_IS_APPROX(t1*v1, t0*v1);
+
+ t0.setIdentity(); t0.scale(v0).rotate(q1.toRotationMatrix());
+ t1.setIdentity(); t1.scale(v0).rotate(q1);
+ VERIFY_IS_APPROX(t0.matrix(), t1.matrix());
+
+ t0.setIdentity(); t0.scale(v0).rotate(AngleAxisx(q1));
+ VERIFY_IS_APPROX(t0.matrix(), t1.matrix());
+
+ VERIFY_IS_APPROX(t0.scale(a).matrix(), t1.scale(Vector3::Constant(a)).matrix());
+ VERIFY_IS_APPROX(t0.prescale(a).matrix(), t1.prescale(Vector3::Constant(a)).matrix());
+
+ // More transform constructors, operator=, operator*=
+
+ Matrix3 mat3 = Matrix3::Random();
+ Matrix4 mat4;
+ mat4 << mat3 , Vector3::Zero() , Vector4::Zero().transpose();
+ Transform3 tmat3(mat3), tmat4(mat4);
+ tmat4.matrix()(3,3) = Scalar(1);
+ VERIFY_IS_APPROX(tmat3.matrix(), tmat4.matrix());
+
+ Scalar a3 = ei_random<Scalar>(-Scalar(M_PI), Scalar(M_PI));
+ Vector3 v3 = Vector3::Random().normalized();
+ AngleAxisx aa3(a3, v3);
+ Transform3 t3(aa3);
+ Transform3 t4;
+ t4 = aa3;
+ VERIFY_IS_APPROX(t3.matrix(), t4.matrix());
+ t4.rotate(AngleAxisx(-a3,v3));
+ VERIFY_IS_APPROX(t4.matrix(), Matrix4::Identity());
+ t4 *= aa3;
+ VERIFY_IS_APPROX(t3.matrix(), t4.matrix());
+
+ v3 = Vector3::Random();
+ Translation3 tv3(v3);
+ Transform3 t5(tv3);
+ t4 = tv3;
+ VERIFY_IS_APPROX(t5.matrix(), t4.matrix());
+ t4.translate(-v3);
+ VERIFY_IS_APPROX(t4.matrix(), Matrix4::Identity());
+ t4 *= tv3;
+ VERIFY_IS_APPROX(t5.matrix(), t4.matrix());
+
+ Scaling3 sv3(v3);
+ Transform3 t6(sv3);
+ t4 = sv3;
+ VERIFY_IS_APPROX(t6.matrix(), t4.matrix());
+ t4.scale(v3.cwise().inverse());
+ VERIFY_IS_APPROX(t4.matrix(), Matrix4::Identity());
+ t4 *= sv3;
+ VERIFY_IS_APPROX(t6.matrix(), t4.matrix());
+
+ // matrix * transform
+ VERIFY_IS_APPROX(Transform3(t3.matrix()*t4).matrix(), Transform3(t3*t4).matrix());
+
+ // chained Transform product
+ VERIFY_IS_APPROX(((t3*t4)*t5).matrix(), (t3*(t4*t5)).matrix());
+
+ // check that Transform product doesn't have aliasing problems
+ t5 = t4;
+ t5 = t5*t5;
+ VERIFY_IS_APPROX(t5, t4*t4);
+
+ // 2D transformation
+ Transform2 t20, t21;
+ Vector2 v20 = Vector2::Random();
+ Vector2 v21 = Vector2::Random();
+ for (int k=0; k<2; ++k)
+ if (ei_abs(v21[k])<Scalar(1e-3)) v21[k] = Scalar(1e-3);
+ t21.setIdentity();
+ t21.linear() = Rotation2D<Scalar>(a).toRotationMatrix();
+ VERIFY_IS_APPROX(t20.fromPositionOrientationScale(v20,a,v21).matrix(),
+ t21.pretranslate(v20).scale(v21).matrix());
+
+ t21.setIdentity();
+ t21.linear() = Rotation2D<Scalar>(-a).toRotationMatrix();
+ VERIFY( (t20.fromPositionOrientationScale(v20,a,v21)
+ * (t21.prescale(v21.cwise().inverse()).translate(-v20))).matrix().isIdentity(test_precision<Scalar>()) );
+
+ // Transform - new API
+ // 3D
+ t0.setIdentity();
+ t0.rotate(q1).scale(v0).translate(v0);
+ // mat * scaling and mat * translation
+ t1 = (Matrix3(q1) * Scaling3(v0)) * Translation3(v0);
+ VERIFY_IS_APPROX(t0.matrix(), t1.matrix());
+ // mat * transformation and scaling * translation
+ t1 = Matrix3(q1) * (Scaling3(v0) * Translation3(v0));
+ VERIFY_IS_APPROX(t0.matrix(), t1.matrix());
+
+ t0.setIdentity();
+ t0.prerotate(q1).prescale(v0).pretranslate(v0);
+ // translation * scaling and transformation * mat
+ t1 = (Translation3(v0) * Scaling3(v0)) * Matrix3(q1);
+ VERIFY_IS_APPROX(t0.matrix(), t1.matrix());
+ // scaling * mat and translation * mat
+ t1 = Translation3(v0) * (Scaling3(v0) * Matrix3(q1));
+ VERIFY_IS_APPROX(t0.matrix(), t1.matrix());
+
+ t0.setIdentity();
+ t0.scale(v0).translate(v0).rotate(q1);
+ // translation * mat and scaling * transformation
+ t1 = Scaling3(v0) * (Translation3(v0) * Matrix3(q1));
+ VERIFY_IS_APPROX(t0.matrix(), t1.matrix());
+ // transformation * scaling
+ t0.scale(v0);
+ t1 = t1 * Scaling3(v0);
+ VERIFY_IS_APPROX(t0.matrix(), t1.matrix());
+ // transformation * translation
+ t0.translate(v0);
+ t1 = t1 * Translation3(v0);
+ VERIFY_IS_APPROX(t0.matrix(), t1.matrix());
+ // translation * transformation
+ t0.pretranslate(v0);
+ t1 = Translation3(v0) * t1;
+ VERIFY_IS_APPROX(t0.matrix(), t1.matrix());
+
+ // transform * quaternion
+ t0.rotate(q1);
+ t1 = t1 * q1;
+ VERIFY_IS_APPROX(t0.matrix(), t1.matrix());
+
+ // translation * quaternion
+ t0.translate(v1).rotate(q1);
+ t1 = t1 * (Translation3(v1) * q1);
+ VERIFY_IS_APPROX(t0.matrix(), t1.matrix());
+
+ // scaling * quaternion
+ t0.scale(v1).rotate(q1);
+ t1 = t1 * (Scaling3(v1) * q1);
+ VERIFY_IS_APPROX(t0.matrix(), t1.matrix());
+
+ // quaternion * transform
+ t0.prerotate(q1);
+ t1 = q1 * t1;
+ VERIFY_IS_APPROX(t0.matrix(), t1.matrix());
+
+ // quaternion * translation
+ t0.rotate(q1).translate(v1);
+ t1 = t1 * (q1 * Translation3(v1));
+ VERIFY_IS_APPROX(t0.matrix(), t1.matrix());
+
+ // quaternion * scaling
+ t0.rotate(q1).scale(v1);
+ t1 = t1 * (q1 * Scaling3(v1));
+ VERIFY_IS_APPROX(t0.matrix(), t1.matrix());
+
+ // translation * vector
+ t0.setIdentity();
+ t0.translate(v0);
+ VERIFY_IS_APPROX(t0 * v1, Translation3(v0) * v1);
+
+ // scaling * vector
+ t0.setIdentity();
+ t0.scale(v0);
+ VERIFY_IS_APPROX(t0 * v1, Scaling3(v0) * v1);
+
+ // test transform inversion
+ t0.setIdentity();
+ t0.translate(v0);
+ t0.linear().setRandom();
+ VERIFY_IS_APPROX(t0.inverse(Affine), t0.matrix().inverse());
+ t0.setIdentity();
+ t0.translate(v0).rotate(q1);
+ VERIFY_IS_APPROX(t0.inverse(Isometry), t0.matrix().inverse());
+
+ // test extract rotation and scaling
+ t0.setIdentity();
+ t0.translate(v0).rotate(q1).scale(v1);
+ VERIFY_IS_APPROX(t0.rotation() * v1, Matrix3(q1) * v1);
+
+ Matrix3 mat_rotation, mat_scaling;
+ t0.setIdentity();
+ t0.translate(v0).rotate(q1).scale(v1);
+ t0.computeRotationScaling(&mat_rotation, &mat_scaling);
+ VERIFY_IS_APPROX(t0.linear(), mat_rotation * mat_scaling);
+ VERIFY_IS_APPROX(mat_rotation*mat_rotation.adjoint(), Matrix3::Identity());
+ VERIFY_IS_APPROX(mat_rotation.determinant(), Scalar(1));
+ t0.computeScalingRotation(&mat_scaling, &mat_rotation);
+ VERIFY_IS_APPROX(t0.linear(), mat_scaling * mat_rotation);
+ VERIFY_IS_APPROX(mat_rotation*mat_rotation.adjoint(), Matrix3::Identity());
+ VERIFY_IS_APPROX(mat_rotation.determinant(), Scalar(1));
+
+ // test casting
+ eigen2_Transform<float,3> t1f = t1.template cast<float>();
+ VERIFY_IS_APPROX(t1f.template cast<Scalar>(),t1);
+ eigen2_Transform<double,3> t1d = t1.template cast<double>();
+ VERIFY_IS_APPROX(t1d.template cast<Scalar>(),t1);
+
+ Translation3 tr1(v0);
+ eigen2_Translation<float,3> tr1f = tr1.template cast<float>();
+ VERIFY_IS_APPROX(tr1f.template cast<Scalar>(),tr1);
+ eigen2_Translation<double,3> tr1d = tr1.template cast<double>();
+ VERIFY_IS_APPROX(tr1d.template cast<Scalar>(),tr1);
+
+ Scaling3 sc1(v0);
+ eigen2_Scaling<float,3> sc1f = sc1.template cast<float>();
+ VERIFY_IS_APPROX(sc1f.template cast<Scalar>(),sc1);
+ eigen2_Scaling<double,3> sc1d = sc1.template cast<double>();
+ VERIFY_IS_APPROX(sc1d.template cast<Scalar>(),sc1);
+
+ eigen2_Quaternion<float> q1f = q1.template cast<float>();
+ VERIFY_IS_APPROX(q1f.template cast<Scalar>(),q1);
+ eigen2_Quaternion<double> q1d = q1.template cast<double>();
+ VERIFY_IS_APPROX(q1d.template cast<Scalar>(),q1);
+
+ eigen2_AngleAxis<float> aa1f = aa1.template cast<float>();
+ VERIFY_IS_APPROX(aa1f.template cast<Scalar>(),aa1);
+ eigen2_AngleAxis<double> aa1d = aa1.template cast<double>();
+ VERIFY_IS_APPROX(aa1d.template cast<Scalar>(),aa1);
+
+ eigen2_Rotation2D<Scalar> r2d1(ei_random<Scalar>());
+ eigen2_Rotation2D<float> r2d1f = r2d1.template cast<float>();
+ VERIFY_IS_APPROX(r2d1f.template cast<Scalar>(),r2d1);
+ eigen2_Rotation2D<double> r2d1d = r2d1.template cast<double>();
+ VERIFY_IS_APPROX(r2d1d.template cast<Scalar>(),r2d1);
+
+ m = q1;
+// m.col(1) = Vector3(0,ei_random<Scalar>(),ei_random<Scalar>()).normalized();
+// m.col(0) = Vector3(-1,0,0).normalized();
+// m.col(2) = m.col(0).cross(m.col(1));
+ #define VERIFY_EULER(I,J,K, X,Y,Z) { \
+ Vector3 ea = m.eulerAngles(I,J,K); \
+ Matrix3 m1 = Matrix3(AngleAxisx(ea[0], Vector3::Unit##X()) * AngleAxisx(ea[1], Vector3::Unit##Y()) * AngleAxisx(ea[2], Vector3::Unit##Z())); \
+ VERIFY_IS_APPROX(m, Matrix3(AngleAxisx(ea[0], Vector3::Unit##X()) * AngleAxisx(ea[1], Vector3::Unit##Y()) * AngleAxisx(ea[2], Vector3::Unit##Z()))); \
+ }
+ VERIFY_EULER(0,1,2, X,Y,Z);
+ VERIFY_EULER(0,1,0, X,Y,X);
+ VERIFY_EULER(0,2,1, X,Z,Y);
+ VERIFY_EULER(0,2,0, X,Z,X);
+
+ VERIFY_EULER(1,2,0, Y,Z,X);
+ VERIFY_EULER(1,2,1, Y,Z,Y);
+ VERIFY_EULER(1,0,2, Y,X,Z);
+ VERIFY_EULER(1,0,1, Y,X,Y);
+
+ VERIFY_EULER(2,0,1, Z,X,Y);
+ VERIFY_EULER(2,0,2, Z,X,Z);
+ VERIFY_EULER(2,1,0, Z,Y,X);
+ VERIFY_EULER(2,1,2, Z,Y,Z);
+
+ // colwise/rowwise cross product
+ mat3.setRandom();
+ Vector3 vec3 = Vector3::Random();
+ Matrix3 mcross;
+ int i = ei_random<int>(0,2);
+ mcross = mat3.colwise().cross(vec3);
+ VERIFY_IS_APPROX(mcross.col(i), mat3.col(i).cross(vec3));
+ mcross = mat3.rowwise().cross(vec3);
+ VERIFY_IS_APPROX(mcross.row(i), mat3.row(i).cross(vec3));
+
+
+}
+
+void test_eigen2_geometry_with_eigen2_prefix()
+{
+ std::cout << "eigen2 support: " << EIGEN2_SUPPORT_STAGE << std::endl;
+ for(int i = 0; i < g_repeat; i++) {
+ CALL_SUBTEST_1( geometry<float>() );
+ CALL_SUBTEST_2( geometry<double>() );
+ }
+}
diff --git a/test/eigen2/eigen2_hyperplane.cpp b/test/eigen2/eigen2_hyperplane.cpp
new file mode 100644
index 000000000..f3f85e14d
--- /dev/null
+++ b/test/eigen2/eigen2_hyperplane.cpp
@@ -0,0 +1,126 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra. Eigen itself is part of the KDE project.
+//
+// Copyright (C) 2008 Gael Guennebaud <g.gael@free.fr>
+// Copyright (C) 2008 Benoit Jacob <jacob.benoit.1@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 "main.h"
+#include <Eigen/Geometry>
+#include <Eigen/LU>
+#include <Eigen/QR>
+
+template<typename HyperplaneType> void hyperplane(const HyperplaneType& _plane)
+{
+ /* this test covers the following files:
+ Hyperplane.h
+ */
+
+ const int dim = _plane.dim();
+ typedef typename HyperplaneType::Scalar Scalar;
+ typedef typename NumTraits<Scalar>::Real RealScalar;
+ typedef Matrix<Scalar, HyperplaneType::AmbientDimAtCompileTime, 1> VectorType;
+ typedef Matrix<Scalar, HyperplaneType::AmbientDimAtCompileTime,
+ HyperplaneType::AmbientDimAtCompileTime> MatrixType;
+
+ VectorType p0 = VectorType::Random(dim);
+ VectorType p1 = VectorType::Random(dim);
+
+ VectorType n0 = VectorType::Random(dim).normalized();
+ VectorType n1 = VectorType::Random(dim).normalized();
+
+ HyperplaneType pl0(n0, p0);
+ HyperplaneType pl1(n1, p1);
+ HyperplaneType pl2 = pl1;
+
+ Scalar s0 = ei_random<Scalar>();
+ Scalar s1 = ei_random<Scalar>();
+
+ VERIFY_IS_APPROX( n1.eigen2_dot(n1), Scalar(1) );
+
+ VERIFY_IS_MUCH_SMALLER_THAN( pl0.absDistance(p0), Scalar(1) );
+ VERIFY_IS_APPROX( pl1.signedDistance(p1 + n1 * s0), s0 );
+ VERIFY_IS_MUCH_SMALLER_THAN( pl1.signedDistance(pl1.projection(p0)), Scalar(1) );
+ VERIFY_IS_MUCH_SMALLER_THAN( pl1.absDistance(p1 + pl1.normal().unitOrthogonal() * s1), Scalar(1) );
+
+ // transform
+ if (!NumTraits<Scalar>::IsComplex)
+ {
+ MatrixType rot = MatrixType::Random(dim,dim).qr().matrixQ();
+ Scaling<Scalar,HyperplaneType::AmbientDimAtCompileTime> scaling(VectorType::Random());
+ Translation<Scalar,HyperplaneType::AmbientDimAtCompileTime> translation(VectorType::Random());
+
+ pl2 = pl1;
+ VERIFY_IS_MUCH_SMALLER_THAN( pl2.transform(rot).absDistance(rot * p1), Scalar(1) );
+ pl2 = pl1;
+ VERIFY_IS_MUCH_SMALLER_THAN( pl2.transform(rot,Isometry).absDistance(rot * p1), Scalar(1) );
+ pl2 = pl1;
+ VERIFY_IS_MUCH_SMALLER_THAN( pl2.transform(rot*scaling).absDistance((rot*scaling) * p1), Scalar(1) );
+ pl2 = pl1;
+ VERIFY_IS_MUCH_SMALLER_THAN( pl2.transform(rot*scaling*translation)
+ .absDistance((rot*scaling*translation) * p1), Scalar(1) );
+ pl2 = pl1;
+ VERIFY_IS_MUCH_SMALLER_THAN( pl2.transform(rot*translation,Isometry)
+ .absDistance((rot*translation) * p1), Scalar(1) );
+ }
+
+ // casting
+ const int Dim = HyperplaneType::AmbientDimAtCompileTime;
+ typedef typename GetDifferentType<Scalar>::type OtherScalar;
+ Hyperplane<OtherScalar,Dim> hp1f = pl1.template cast<OtherScalar>();
+ VERIFY_IS_APPROX(hp1f.template cast<Scalar>(),pl1);
+ Hyperplane<Scalar,Dim> hp1d = pl1.template cast<Scalar>();
+ VERIFY_IS_APPROX(hp1d.template cast<Scalar>(),pl1);
+}
+
+template<typename Scalar> void lines()
+{
+ typedef Hyperplane<Scalar, 2> HLine;
+ typedef ParametrizedLine<Scalar, 2> PLine;
+ typedef Matrix<Scalar,2,1> Vector;
+ typedef Matrix<Scalar,3,1> CoeffsType;
+
+ for(int i = 0; i < 10; i++)
+ {
+ Vector center = Vector::Random();
+ Vector u = Vector::Random();
+ Vector v = Vector::Random();
+ Scalar a = ei_random<Scalar>();
+ while (ei_abs(a-1) < 1e-4) a = ei_random<Scalar>();
+ while (u.norm() < 1e-4) u = Vector::Random();
+ while (v.norm() < 1e-4) v = Vector::Random();
+
+ HLine line_u = HLine::Through(center + u, center + a*u);
+ HLine line_v = HLine::Through(center + v, center + a*v);
+
+ // the line equations should be normalized so that a^2+b^2=1
+ VERIFY_IS_APPROX(line_u.normal().norm(), Scalar(1));
+ VERIFY_IS_APPROX(line_v.normal().norm(), Scalar(1));
+
+ Vector result = line_u.intersection(line_v);
+
+ // the lines should intersect at the point we called "center"
+ VERIFY_IS_APPROX(result, center);
+
+ // check conversions between two types of lines
+ PLine pl(line_u); // gcc 3.3 will commit suicide if we don't name this variable
+ CoeffsType converted_coeffs(HLine(pl).coeffs());
+ converted_coeffs *= line_u.coeffs()(0)/converted_coeffs(0);
+ VERIFY(line_u.coeffs().isApprox(converted_coeffs));
+ }
+}
+
+void test_eigen2_hyperplane()
+{
+ for(int i = 0; i < g_repeat; i++) {
+ CALL_SUBTEST_1( hyperplane(Hyperplane<float,2>()) );
+ CALL_SUBTEST_2( hyperplane(Hyperplane<float,3>()) );
+ CALL_SUBTEST_3( hyperplane(Hyperplane<double,4>()) );
+ CALL_SUBTEST_4( hyperplane(Hyperplane<std::complex<double>,5>()) );
+ CALL_SUBTEST_5( lines<float>() );
+ CALL_SUBTEST_6( lines<double>() );
+ }
+}
diff --git a/test/eigen2/eigen2_inverse.cpp b/test/eigen2/eigen2_inverse.cpp
new file mode 100644
index 000000000..5de1dfefa
--- /dev/null
+++ b/test/eigen2/eigen2_inverse.cpp
@@ -0,0 +1,63 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra. Eigen itself is part of the KDE project.
+//
+// Copyright (C) 2008 Gael Guennebaud <g.gael@free.fr>
+// Copyright (C) 2008 Benoit Jacob <jacob.benoit.1@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 "main.h"
+#include <Eigen/LU>
+
+template<typename MatrixType> void inverse(const MatrixType& m)
+{
+ /* this test covers the following files:
+ Inverse.h
+ */
+ int rows = m.rows();
+ int cols = m.cols();
+
+ typedef typename MatrixType::Scalar Scalar;
+ typedef typename NumTraits<Scalar>::Real RealScalar;
+ typedef Matrix<Scalar, MatrixType::ColsAtCompileTime, 1> VectorType;
+
+ MatrixType m1 = MatrixType::Random(rows, cols),
+ m2(rows, cols),
+ mzero = MatrixType::Zero(rows, cols),
+ identity = MatrixType::Identity(rows, rows);
+
+ while(ei_abs(m1.determinant()) < RealScalar(0.1) && rows <= 8)
+ {
+ m1 = MatrixType::Random(rows, cols);
+ }
+
+ m2 = m1.inverse();
+ VERIFY_IS_APPROX(m1, m2.inverse() );
+
+ m1.computeInverse(&m2);
+ VERIFY_IS_APPROX(m1, m2.inverse() );
+
+ VERIFY_IS_APPROX((Scalar(2)*m2).inverse(), m2.inverse()*Scalar(0.5));
+
+ VERIFY_IS_APPROX(identity, m1.inverse() * m1 );
+ VERIFY_IS_APPROX(identity, m1 * m1.inverse() );
+
+ VERIFY_IS_APPROX(m1, m1.inverse().inverse() );
+
+ // since for the general case we implement separately row-major and col-major, test that
+ VERIFY_IS_APPROX(m1.transpose().inverse(), m1.inverse().transpose());
+}
+
+void test_eigen2_inverse()
+{
+ for(int i = 0; i < g_repeat; i++) {
+ CALL_SUBTEST_1( inverse(Matrix<double,1,1>()) );
+ CALL_SUBTEST_2( inverse(Matrix2d()) );
+ CALL_SUBTEST_3( inverse(Matrix3f()) );
+ CALL_SUBTEST_4( inverse(Matrix4f()) );
+ CALL_SUBTEST_5( inverse(MatrixXf(8,8)) );
+ CALL_SUBTEST_6( inverse(MatrixXcd(7,7)) );
+ }
+}
diff --git a/test/eigen2/eigen2_linearstructure.cpp b/test/eigen2/eigen2_linearstructure.cpp
new file mode 100644
index 000000000..22f02c396
--- /dev/null
+++ b/test/eigen2/eigen2_linearstructure.cpp
@@ -0,0 +1,84 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra. Eigen itself is part of the KDE project.
+//
+// Copyright (C) 2006-2008 Benoit Jacob <jacob.benoit.1@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 "main.h"
+
+template<typename MatrixType> void linearStructure(const MatrixType& m)
+{
+ /* this test covers the following files:
+ Sum.h Difference.h Opposite.h ScalarMultiple.h
+ */
+
+ typedef typename MatrixType::Scalar Scalar;
+ typedef Matrix<Scalar, MatrixType::RowsAtCompileTime, 1> VectorType;
+
+ int rows = m.rows();
+ int cols = m.cols();
+
+ // this test relies a lot on Random.h, and there's not much more that we can do
+ // to test it, hence I consider that we will have tested Random.h
+ MatrixType m1 = MatrixType::Random(rows, cols),
+ m2 = MatrixType::Random(rows, cols),
+ m3(rows, cols),
+ mzero = MatrixType::Zero(rows, cols);
+
+ Scalar s1 = ei_random<Scalar>();
+ while (ei_abs(s1)<1e-3) s1 = ei_random<Scalar>();
+
+ int r = ei_random<int>(0, rows-1),
+ c = ei_random<int>(0, cols-1);
+
+ VERIFY_IS_APPROX(-(-m1), m1);
+ VERIFY_IS_APPROX(m1+m1, 2*m1);
+ VERIFY_IS_APPROX(m1+m2-m1, m2);
+ VERIFY_IS_APPROX(-m2+m1+m2, m1);
+ VERIFY_IS_APPROX(m1*s1, s1*m1);
+ VERIFY_IS_APPROX((m1+m2)*s1, s1*m1+s1*m2);
+ VERIFY_IS_APPROX((-m1+m2)*s1, -s1*m1+s1*m2);
+ m3 = m2; m3 += m1;
+ VERIFY_IS_APPROX(m3, m1+m2);
+ m3 = m2; m3 -= m1;
+ VERIFY_IS_APPROX(m3, m2-m1);
+ m3 = m2; m3 *= s1;
+ VERIFY_IS_APPROX(m3, s1*m2);
+ if(NumTraits<Scalar>::HasFloatingPoint)
+ {
+ m3 = m2; m3 /= s1;
+ VERIFY_IS_APPROX(m3, m2/s1);
+ }
+
+ // again, test operator() to check const-qualification
+ VERIFY_IS_APPROX((-m1)(r,c), -(m1(r,c)));
+ VERIFY_IS_APPROX((m1-m2)(r,c), (m1(r,c))-(m2(r,c)));
+ VERIFY_IS_APPROX((m1+m2)(r,c), (m1(r,c))+(m2(r,c)));
+ VERIFY_IS_APPROX((s1*m1)(r,c), s1*(m1(r,c)));
+ VERIFY_IS_APPROX((m1*s1)(r,c), (m1(r,c))*s1);
+ if(NumTraits<Scalar>::HasFloatingPoint)
+ VERIFY_IS_APPROX((m1/s1)(r,c), (m1(r,c))/s1);
+
+ // use .block to disable vectorization and compare to the vectorized version
+ VERIFY_IS_APPROX(m1+m1.block(0,0,rows,cols), m1+m1);
+ VERIFY_IS_APPROX(m1.cwise() * m1.block(0,0,rows,cols), m1.cwise() * m1);
+ VERIFY_IS_APPROX(m1 - m1.block(0,0,rows,cols), m1 - m1);
+ VERIFY_IS_APPROX(m1.block(0,0,rows,cols) * s1, m1 * s1);
+}
+
+void test_eigen2_linearstructure()
+{
+ for(int i = 0; i < g_repeat; i++) {
+ CALL_SUBTEST_1( linearStructure(Matrix<float, 1, 1>()) );
+ CALL_SUBTEST_2( linearStructure(Matrix2f()) );
+ CALL_SUBTEST_3( linearStructure(Vector3d()) );
+ CALL_SUBTEST_4( linearStructure(Matrix4d()) );
+ CALL_SUBTEST_5( linearStructure(MatrixXcf(3, 3)) );
+ CALL_SUBTEST_6( linearStructure(MatrixXf(8, 12)) );
+ CALL_SUBTEST_7( linearStructure(MatrixXi(8, 12)) );
+ CALL_SUBTEST_8( linearStructure(MatrixXcd(20, 20)) );
+ }
+}
diff --git a/test/eigen2/eigen2_lu.cpp b/test/eigen2/eigen2_lu.cpp
new file mode 100644
index 000000000..e993b1c7c
--- /dev/null
+++ b/test/eigen2/eigen2_lu.cpp
@@ -0,0 +1,122 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra. Eigen itself is part of the KDE project.
+//
+// Copyright (C) 2008 Benoit Jacob <jacob.benoit.1@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 "main.h"
+#include <Eigen/LU>
+
+template<typename Derived>
+void doSomeRankPreservingOperations(Eigen::MatrixBase<Derived>& m)
+{
+ typedef typename Derived::RealScalar RealScalar;
+ for(int a = 0; a < 3*(m.rows()+m.cols()); a++)
+ {
+ RealScalar d = Eigen::ei_random<RealScalar>(-1,1);
+ int i = Eigen::ei_random<int>(0,m.rows()-1); // i is a random row number
+ int j;
+ do {
+ j = Eigen::ei_random<int>(0,m.rows()-1);
+ } while (i==j); // j is another one (must be different)
+ m.row(i) += d * m.row(j);
+
+ i = Eigen::ei_random<int>(0,m.cols()-1); // i is a random column number
+ do {
+ j = Eigen::ei_random<int>(0,m.cols()-1);
+ } while (i==j); // j is another one (must be different)
+ m.col(i) += d * m.col(j);
+ }
+}
+
+template<typename MatrixType> void lu_non_invertible()
+{
+ /* this test covers the following files:
+ LU.h
+ */
+ // NOTE there seems to be a problem with too small sizes -- could easily lie in the doSomeRankPreservingOperations function
+ int rows = ei_random<int>(20,200), cols = ei_random<int>(20,200), cols2 = ei_random<int>(20,200);
+ int rank = ei_random<int>(1, std::min(rows, cols)-1);
+
+ MatrixType m1(rows, cols), m2(cols, cols2), m3(rows, cols2), k(1,1);
+ m1 = MatrixType::Random(rows,cols);
+ if(rows <= cols)
+ for(int i = rank; i < rows; i++) m1.row(i).setZero();
+ else
+ for(int i = rank; i < cols; i++) m1.col(i).setZero();
+ doSomeRankPreservingOperations(m1);
+
+ LU<MatrixType> lu(m1);
+ typename LU<MatrixType>::KernelResultType m1kernel = lu.kernel();
+ typename LU<MatrixType>::ImageResultType m1image = lu.image();
+
+ VERIFY(rank == lu.rank());
+ VERIFY(cols - lu.rank() == lu.dimensionOfKernel());
+ VERIFY(!lu.isInjective());
+ VERIFY(!lu.isInvertible());
+ VERIFY(lu.isSurjective() == (lu.rank() == rows));
+ VERIFY((m1 * m1kernel).isMuchSmallerThan(m1));
+ VERIFY(m1image.lu().rank() == rank);
+ MatrixType sidebyside(m1.rows(), m1.cols() + m1image.cols());
+ sidebyside << m1, m1image;
+ VERIFY(sidebyside.lu().rank() == rank);
+ m2 = MatrixType::Random(cols,cols2);
+ m3 = m1*m2;
+ m2 = MatrixType::Random(cols,cols2);
+ lu.solve(m3, &m2);
+ VERIFY_IS_APPROX(m3, m1*m2);
+ /* solve now always returns true
+ m3 = MatrixType::Random(rows,cols2);
+ VERIFY(!lu.solve(m3, &m2));
+ */
+}
+
+template<typename MatrixType> void lu_invertible()
+{
+ /* this test covers the following files:
+ LU.h
+ */
+ typedef typename NumTraits<typename MatrixType::Scalar>::Real RealScalar;
+ int size = ei_random<int>(10,200);
+
+ MatrixType m1(size, size), m2(size, size), m3(size, size);
+ m1 = MatrixType::Random(size,size);
+
+ if (ei_is_same_type<RealScalar,float>::ret)
+ {
+ // let's build a matrix more stable to inverse
+ MatrixType a = MatrixType::Random(size,size*2);
+ m1 += a * a.adjoint();
+ }
+
+ LU<MatrixType> lu(m1);
+ VERIFY(0 == lu.dimensionOfKernel());
+ VERIFY(size == lu.rank());
+ VERIFY(lu.isInjective());
+ VERIFY(lu.isSurjective());
+ VERIFY(lu.isInvertible());
+ VERIFY(lu.image().lu().isInvertible());
+ m3 = MatrixType::Random(size,size);
+ lu.solve(m3, &m2);
+ VERIFY_IS_APPROX(m3, m1*m2);
+ VERIFY_IS_APPROX(m2, lu.inverse()*m3);
+ m3 = MatrixType::Random(size,size);
+ VERIFY(lu.solve(m3, &m2));
+}
+
+void test_eigen2_lu()
+{
+ for(int i = 0; i < g_repeat; i++) {
+ CALL_SUBTEST_1( lu_non_invertible<MatrixXf>() );
+ CALL_SUBTEST_2( lu_non_invertible<MatrixXd>() );
+ CALL_SUBTEST_3( lu_non_invertible<MatrixXcf>() );
+ CALL_SUBTEST_4( lu_non_invertible<MatrixXcd>() );
+ CALL_SUBTEST_1( lu_invertible<MatrixXf>() );
+ CALL_SUBTEST_2( lu_invertible<MatrixXd>() );
+ CALL_SUBTEST_3( lu_invertible<MatrixXcf>() );
+ CALL_SUBTEST_4( lu_invertible<MatrixXcd>() );
+ }
+}
diff --git a/test/eigen2/eigen2_map.cpp b/test/eigen2/eigen2_map.cpp
new file mode 100644
index 000000000..4a1c4e11a
--- /dev/null
+++ b/test/eigen2/eigen2_map.cpp
@@ -0,0 +1,114 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra. Eigen itself is part of the KDE project.
+//
+// Copyright (C) 2007-2010 Benoit Jacob <jacob.benoit.1@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 "main.h"
+
+template<typename VectorType> void map_class_vector(const VectorType& m)
+{
+ typedef typename VectorType::Scalar Scalar;
+
+ int size = m.size();
+
+ // test Map.h
+ Scalar* array1 = ei_aligned_new<Scalar>(size);
+ Scalar* array2 = ei_aligned_new<Scalar>(size);
+ Scalar* array3 = new Scalar[size+1];
+ Scalar* array3unaligned = std::size_t(array3)%16 == 0 ? array3+1 : array3;
+
+ Map<VectorType, Aligned>(array1, size) = VectorType::Random(size);
+ Map<VectorType>(array2, size) = Map<VectorType>(array1, size);
+ Map<VectorType>(array3unaligned, size) = Map<VectorType>((const Scalar*)array1, size); // test non-const-correctness support in eigen2
+ VectorType ma1 = Map<VectorType>(array1, size);
+ VectorType ma2 = Map<VectorType, Aligned>(array2, size);
+ VectorType ma3 = Map<VectorType>(array3unaligned, size);
+ VERIFY_IS_APPROX(ma1, ma2);
+ VERIFY_IS_APPROX(ma1, ma3);
+
+ ei_aligned_delete(array1, size);
+ ei_aligned_delete(array2, size);
+ delete[] array3;
+}
+
+template<typename MatrixType> void map_class_matrix(const MatrixType& m)
+{
+ typedef typename MatrixType::Scalar Scalar;
+
+ int rows = m.rows(), cols = m.cols(), size = rows*cols;
+
+ // test Map.h
+ Scalar* array1 = ei_aligned_new<Scalar>(size);
+ for(int i = 0; i < size; i++) array1[i] = Scalar(1);
+ Scalar* array2 = ei_aligned_new<Scalar>(size);
+ for(int i = 0; i < size; i++) array2[i] = Scalar(1);
+ Scalar* array3 = new Scalar[size+1];
+ for(int i = 0; i < size+1; i++) array3[i] = Scalar(1);
+ Scalar* array3unaligned = std::size_t(array3)%16 == 0 ? array3+1 : array3;
+ Map<MatrixType, Aligned>(array1, rows, cols) = MatrixType::Ones(rows,cols);
+ Map<MatrixType>(array2, rows, cols) = Map<MatrixType>((const Scalar*)array1, rows, cols); // test non-const-correctness support in eigen2
+ Map<MatrixType>(array3unaligned, rows, cols) = Map<MatrixType>(array1, rows, cols);
+ MatrixType ma1 = Map<MatrixType>(array1, rows, cols);
+ MatrixType ma2 = Map<MatrixType, Aligned>(array2, rows, cols);
+ VERIFY_IS_APPROX(ma1, ma2);
+ MatrixType ma3 = Map<MatrixType>(array3unaligned, rows, cols);
+ VERIFY_IS_APPROX(ma1, ma3);
+
+ ei_aligned_delete(array1, size);
+ ei_aligned_delete(array2, size);
+ delete[] array3;
+}
+
+template<typename VectorType> void map_static_methods(const VectorType& m)
+{
+ typedef typename VectorType::Scalar Scalar;
+
+ int size = m.size();
+
+ // test Map.h
+ Scalar* array1 = ei_aligned_new<Scalar>(size);
+ Scalar* array2 = ei_aligned_new<Scalar>(size);
+ Scalar* array3 = new Scalar[size+1];
+ Scalar* array3unaligned = std::size_t(array3)%16 == 0 ? array3+1 : array3;
+
+ VectorType::MapAligned(array1, size) = VectorType::Random(size);
+ VectorType::Map(array2, size) = VectorType::Map(array1, size);
+ VectorType::Map(array3unaligned, size) = VectorType::Map(array1, size);
+ VectorType ma1 = VectorType::Map(array1, size);
+ VectorType ma2 = VectorType::MapAligned(array2, size);
+ VectorType ma3 = VectorType::Map(array3unaligned, size);
+ VERIFY_IS_APPROX(ma1, ma2);
+ VERIFY_IS_APPROX(ma1, ma3);
+
+ ei_aligned_delete(array1, size);
+ ei_aligned_delete(array2, size);
+ delete[] array3;
+}
+
+
+void test_eigen2_map()
+{
+ for(int i = 0; i < g_repeat; i++) {
+ CALL_SUBTEST_1( map_class_vector(Matrix<float, 1, 1>()) );
+ CALL_SUBTEST_2( map_class_vector(Vector4d()) );
+ CALL_SUBTEST_3( map_class_vector(RowVector4f()) );
+ CALL_SUBTEST_4( map_class_vector(VectorXcf(8)) );
+ CALL_SUBTEST_5( map_class_vector(VectorXi(12)) );
+
+ CALL_SUBTEST_1( map_class_matrix(Matrix<float, 1, 1>()) );
+ CALL_SUBTEST_2( map_class_matrix(Matrix4d()) );
+ CALL_SUBTEST_6( map_class_matrix(Matrix<float,3,5>()) );
+ CALL_SUBTEST_4( map_class_matrix(MatrixXcf(ei_random<int>(1,10),ei_random<int>(1,10))) );
+ CALL_SUBTEST_5( map_class_matrix(MatrixXi(ei_random<int>(1,10),ei_random<int>(1,10))) );
+
+ CALL_SUBTEST_1( map_static_methods(Matrix<double, 1, 1>()) );
+ CALL_SUBTEST_2( map_static_methods(Vector3f()) );
+ CALL_SUBTEST_7( map_static_methods(RowVector3d()) );
+ CALL_SUBTEST_4( map_static_methods(VectorXcd(8)) );
+ CALL_SUBTEST_5( map_static_methods(VectorXf(12)) );
+ }
+}
diff --git a/test/eigen2/eigen2_meta.cpp b/test/eigen2/eigen2_meta.cpp
new file mode 100644
index 000000000..1d01bd84d
--- /dev/null
+++ b/test/eigen2/eigen2_meta.cpp
@@ -0,0 +1,60 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra. Eigen itself is part of the KDE project.
+//
+// Copyright (C) 2008 Gael Guennebaud <g.gael@free.fr>
+//
+// This Source Code Form is subject to the terms of the Mozilla
+// Public License v. 2.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 "main.h"
+
+void test_eigen2_meta()
+{
+ typedef float & FloatRef;
+ typedef const float & ConstFloatRef;
+
+ VERIFY((ei_meta_if<(3<4),ei_meta_true, ei_meta_false>::ret::ret));
+ VERIFY(( ei_is_same_type<float,float>::ret));
+ VERIFY((!ei_is_same_type<float,double>::ret));
+ VERIFY((!ei_is_same_type<float,float&>::ret));
+ VERIFY((!ei_is_same_type<float,const float&>::ret));
+
+ VERIFY(( ei_is_same_type<float,ei_cleantype<const float&>::type >::ret));
+ VERIFY(( ei_is_same_type<float,ei_cleantype<const float*>::type >::ret));
+ VERIFY(( ei_is_same_type<float,ei_cleantype<const float*&>::type >::ret));
+ VERIFY(( ei_is_same_type<float,ei_cleantype<float**>::type >::ret));
+ VERIFY(( ei_is_same_type<float,ei_cleantype<float**&>::type >::ret));
+ VERIFY(( ei_is_same_type<float,ei_cleantype<float* const *&>::type >::ret));
+ VERIFY(( ei_is_same_type<float,ei_cleantype<float* const>::type >::ret));
+
+ VERIFY(( ei_is_same_type<float*,ei_unconst<const float*>::type >::ret));
+ VERIFY(( ei_is_same_type<float&,ei_unconst<const float&>::type >::ret));
+ VERIFY(( ei_is_same_type<float&,ei_unconst<ConstFloatRef>::type >::ret));
+
+ VERIFY(( ei_is_same_type<float&,ei_unconst<float&>::type >::ret));
+ VERIFY(( ei_is_same_type<float,ei_unref<float&>::type >::ret));
+ VERIFY(( ei_is_same_type<const float,ei_unref<const float&>::type >::ret));
+ VERIFY(( ei_is_same_type<float,ei_unpointer<float*>::type >::ret));
+ VERIFY(( ei_is_same_type<const float,ei_unpointer<const float*>::type >::ret));
+ VERIFY(( ei_is_same_type<float,ei_unpointer<float* const >::type >::ret));
+
+ VERIFY(ei_meta_sqrt<1>::ret == 1);
+ #define VERIFY_META_SQRT(X) VERIFY(ei_meta_sqrt<X>::ret == int(ei_sqrt(double(X))))
+ VERIFY_META_SQRT(2);
+ VERIFY_META_SQRT(3);
+ VERIFY_META_SQRT(4);
+ VERIFY_META_SQRT(5);
+ VERIFY_META_SQRT(6);
+ VERIFY_META_SQRT(8);
+ VERIFY_META_SQRT(9);
+ VERIFY_META_SQRT(15);
+ VERIFY_META_SQRT(16);
+ VERIFY_META_SQRT(17);
+ VERIFY_META_SQRT(255);
+ VERIFY_META_SQRT(256);
+ VERIFY_META_SQRT(257);
+ VERIFY_META_SQRT(1023);
+ VERIFY_META_SQRT(1024);
+ VERIFY_META_SQRT(1025);
+}
diff --git a/test/eigen2/eigen2_miscmatrices.cpp b/test/eigen2/eigen2_miscmatrices.cpp
new file mode 100644
index 000000000..8bbb20cc8
--- /dev/null
+++ b/test/eigen2/eigen2_miscmatrices.cpp
@@ -0,0 +1,48 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra. Eigen itself is part of the KDE project.
+//
+// Copyright (C) 2006-2008 Benoit Jacob <jacob.benoit.1@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 "main.h"
+
+template<typename MatrixType> void miscMatrices(const MatrixType& m)
+{
+ /* this test covers the following files:
+ DiagonalMatrix.h Ones.h
+ */
+
+ typedef typename MatrixType::Scalar Scalar;
+ typedef Matrix<Scalar, MatrixType::RowsAtCompileTime, 1> VectorType;
+ typedef Matrix<Scalar, 1, MatrixType::ColsAtCompileTime> RowVectorType;
+ int rows = m.rows();
+ int cols = m.cols();
+
+ int r = ei_random<int>(0, rows-1), r2 = ei_random<int>(0, rows-1), c = ei_random<int>(0, cols-1);
+ VERIFY_IS_APPROX(MatrixType::Ones(rows,cols)(r,c), static_cast<Scalar>(1));
+ MatrixType m1 = MatrixType::Ones(rows,cols);
+ VERIFY_IS_APPROX(m1(r,c), static_cast<Scalar>(1));
+ VectorType v1 = VectorType::Random(rows);
+ v1[0];
+ Matrix<Scalar, MatrixType::RowsAtCompileTime, MatrixType::RowsAtCompileTime>
+ square = v1.asDiagonal();
+ if(r==r2) VERIFY_IS_APPROX(square(r,r2), v1[r]);
+ else VERIFY_IS_MUCH_SMALLER_THAN(square(r,r2), static_cast<Scalar>(1));
+ square = MatrixType::Zero(rows, rows);
+ square.diagonal() = VectorType::Ones(rows);
+ VERIFY_IS_APPROX(square, MatrixType::Identity(rows, rows));
+}
+
+void test_eigen2_miscmatrices()
+{
+ for(int i = 0; i < g_repeat; i++) {
+ CALL_SUBTEST_1( miscMatrices(Matrix<float, 1, 1>()) );
+ CALL_SUBTEST_2( miscMatrices(Matrix4d()) );
+ CALL_SUBTEST_3( miscMatrices(MatrixXcf(3, 3)) );
+ CALL_SUBTEST_4( miscMatrices(MatrixXi(8, 12)) );
+ CALL_SUBTEST_5( miscMatrices(MatrixXcd(20, 20)) );
+ }
+}
diff --git a/test/eigen2/eigen2_mixingtypes.cpp b/test/eigen2/eigen2_mixingtypes.cpp
new file mode 100644
index 000000000..fb5ac5dda
--- /dev/null
+++ b/test/eigen2/eigen2_mixingtypes.cpp
@@ -0,0 +1,77 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra. Eigen itself is part of the KDE project.
+//
+// Copyright (C) 2008 Gael Guennebaud <g.gael@free.fr>
+// Copyright (C) 2008 Benoit Jacob <jacob.benoit.1@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 EIGEN_NO_STATIC_ASSERT
+#define EIGEN_NO_STATIC_ASSERT // turn static asserts into runtime asserts in order to check them
+#endif
+
+#ifndef EIGEN_DONT_VECTORIZE
+#define EIGEN_DONT_VECTORIZE // SSE intrinsics aren't designed to allow mixing types
+#endif
+
+#include "main.h"
+
+
+template<int SizeAtCompileType> void mixingtypes(int size = SizeAtCompileType)
+{
+ typedef Matrix<float, SizeAtCompileType, SizeAtCompileType> Mat_f;
+ typedef Matrix<double, SizeAtCompileType, SizeAtCompileType> Mat_d;
+ typedef Matrix<std::complex<float>, SizeAtCompileType, SizeAtCompileType> Mat_cf;
+ typedef Matrix<std::complex<double>, SizeAtCompileType, SizeAtCompileType> Mat_cd;
+ typedef Matrix<float, SizeAtCompileType, 1> Vec_f;
+ typedef Matrix<double, SizeAtCompileType, 1> Vec_d;
+ typedef Matrix<std::complex<float>, SizeAtCompileType, 1> Vec_cf;
+ typedef Matrix<std::complex<double>, SizeAtCompileType, 1> Vec_cd;
+
+ Mat_f mf(size,size);
+ Mat_d md(size,size);
+ Mat_cf mcf(size,size);
+ Mat_cd mcd(size,size);
+ Vec_f vf(size,1);
+ Vec_d vd(size,1);
+ Vec_cf vcf(size,1);
+ Vec_cd vcd(size,1);
+
+ mf+mf;
+ VERIFY_RAISES_ASSERT(mf+md);
+ VERIFY_RAISES_ASSERT(mf+mcf);
+ VERIFY_RAISES_ASSERT(vf=vd);
+ VERIFY_RAISES_ASSERT(vf+=vd);
+ VERIFY_RAISES_ASSERT(mcd=md);
+
+ mf*mf;
+ md*mcd;
+ mcd*md;
+ mf*vcf;
+ mcf*vf;
+ mcf *= mf;
+ vcd = md*vcd;
+ vcf = mcf*vf;
+#if 0
+ // these are know generating hard build errors in eigen3
+ VERIFY_RAISES_ASSERT(mf*md);
+ VERIFY_RAISES_ASSERT(mcf*mcd);
+ VERIFY_RAISES_ASSERT(mcf*vcd);
+ VERIFY_RAISES_ASSERT(vcf = mf*vf);
+
+ vf.eigen2_dot(vf);
+ VERIFY_RAISES_ASSERT(vd.eigen2_dot(vf));
+ VERIFY_RAISES_ASSERT(vcf.eigen2_dot(vf)); // yeah eventually we should allow this but i'm too lazy to make that change now in Dot.h
+ // especially as that might be rewritten as cwise product .sum() which would make that automatic.
+#endif
+}
+
+void test_eigen2_mixingtypes()
+{
+ // check that our operator new is indeed called:
+ CALL_SUBTEST_1(mixingtypes<3>());
+ CALL_SUBTEST_2(mixingtypes<4>());
+ CALL_SUBTEST_3(mixingtypes<Dynamic>(20));
+}
diff --git a/test/eigen2/eigen2_newstdvector.cpp b/test/eigen2/eigen2_newstdvector.cpp
new file mode 100644
index 000000000..5f9009901
--- /dev/null
+++ b/test/eigen2/eigen2_newstdvector.cpp
@@ -0,0 +1,149 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra.
+//
+// Copyright (C) 2008 Benoit Jacob <jacob.benoit.1@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/.
+
+#define EIGEN_USE_NEW_STDVECTOR
+#include "main.h"
+#include <Eigen/StdVector>
+#include <Eigen/Geometry>
+
+template<typename MatrixType>
+void check_stdvector_matrix(const MatrixType& m)
+{
+ int rows = m.rows();
+ int cols = m.cols();
+ MatrixType x = MatrixType::Random(rows,cols), y = MatrixType::Random(rows,cols);
+ std::vector<MatrixType,Eigen::aligned_allocator<MatrixType> > v(10, MatrixType(rows,cols)), w(20, y);
+ v[5] = x;
+ w[6] = v[5];
+ VERIFY_IS_APPROX(w[6], v[5]);
+ v = w;
+ for(int i = 0; i < 20; i++)
+ {
+ VERIFY_IS_APPROX(w[i], v[i]);
+ }
+
+ v.resize(21);
+ v[20] = x;
+ VERIFY_IS_APPROX(v[20], x);
+ v.resize(22,y);
+ VERIFY_IS_APPROX(v[21], y);
+ v.push_back(x);
+ VERIFY_IS_APPROX(v[22], x);
+ VERIFY((std::size_t)&(v[22]) == (std::size_t)&(v[21]) + sizeof(MatrixType));
+
+ // do a lot of push_back such that the vector gets internally resized
+ // (with memory reallocation)
+ MatrixType* ref = &w[0];
+ for(int i=0; i<30 || ((ref==&w[0]) && i<300); ++i)
+ v.push_back(w[i%w.size()]);
+ for(unsigned int i=23; i<v.size(); ++i)
+ {
+ VERIFY(v[i]==w[(i-23)%w.size()]);
+ }
+}
+
+template<typename TransformType>
+void check_stdvector_transform(const TransformType&)
+{
+ typedef typename TransformType::MatrixType MatrixType;
+ TransformType x(MatrixType::Random()), y(MatrixType::Random());
+ std::vector<TransformType,Eigen::aligned_allocator<TransformType> > v(10), w(20, y);
+ v[5] = x;
+ w[6] = v[5];
+ VERIFY_IS_APPROX(w[6], v[5]);
+ v = w;
+ for(int i = 0; i < 20; i++)
+ {
+ VERIFY_IS_APPROX(w[i], v[i]);
+ }
+
+ v.resize(21);
+ v[20] = x;
+ VERIFY_IS_APPROX(v[20], x);
+ v.resize(22,y);
+ VERIFY_IS_APPROX(v[21], y);
+ v.push_back(x);
+ VERIFY_IS_APPROX(v[22], x);
+ VERIFY((std::size_t)&(v[22]) == (std::size_t)&(v[21]) + sizeof(TransformType));
+
+ // do a lot of push_back such that the vector gets internally resized
+ // (with memory reallocation)
+ TransformType* ref = &w[0];
+ for(int i=0; i<30 || ((ref==&w[0]) && i<300); ++i)
+ v.push_back(w[i%w.size()]);
+ for(unsigned int i=23; i<v.size(); ++i)
+ {
+ VERIFY(v[i].matrix()==w[(i-23)%w.size()].matrix());
+ }
+}
+
+template<typename QuaternionType>
+void check_stdvector_quaternion(const QuaternionType&)
+{
+ typedef typename QuaternionType::Coefficients Coefficients;
+ QuaternionType x(Coefficients::Random()), y(Coefficients::Random());
+ std::vector<QuaternionType,Eigen::aligned_allocator<QuaternionType> > v(10), w(20, y);
+ v[5] = x;
+ w[6] = v[5];
+ VERIFY_IS_APPROX(w[6], v[5]);
+ v = w;
+ for(int i = 0; i < 20; i++)
+ {
+ VERIFY_IS_APPROX(w[i], v[i]);
+ }
+
+ v.resize(21);
+ v[20] = x;
+ VERIFY_IS_APPROX(v[20], x);
+ v.resize(22,y);
+ VERIFY_IS_APPROX(v[21], y);
+ v.push_back(x);
+ VERIFY_IS_APPROX(v[22], x);
+ VERIFY((std::size_t)&(v[22]) == (std::size_t)&(v[21]) + sizeof(QuaternionType));
+
+ // do a lot of push_back such that the vector gets internally resized
+ // (with memory reallocation)
+ QuaternionType* ref = &w[0];
+ for(int i=0; i<30 || ((ref==&w[0]) && i<300); ++i)
+ v.push_back(w[i%w.size()]);
+ for(unsigned int i=23; i<v.size(); ++i)
+ {
+ VERIFY(v[i].coeffs()==w[(i-23)%w.size()].coeffs());
+ }
+}
+
+void test_eigen2_newstdvector()
+{
+ // some non vectorizable fixed sizes
+ CALL_SUBTEST_1(check_stdvector_matrix(Vector2f()));
+ CALL_SUBTEST_1(check_stdvector_matrix(Matrix3f()));
+ CALL_SUBTEST_1(check_stdvector_matrix(Matrix3d()));
+
+ // some vectorizable fixed sizes
+ CALL_SUBTEST_2(check_stdvector_matrix(Matrix2f()));
+ CALL_SUBTEST_2(check_stdvector_matrix(Vector4f()));
+ CALL_SUBTEST_2(check_stdvector_matrix(Matrix4f()));
+ CALL_SUBTEST_2(check_stdvector_matrix(Matrix4d()));
+
+ // some dynamic sizes
+ CALL_SUBTEST_3(check_stdvector_matrix(MatrixXd(1,1)));
+ CALL_SUBTEST_3(check_stdvector_matrix(VectorXd(20)));
+ CALL_SUBTEST_3(check_stdvector_matrix(RowVectorXf(20)));
+ CALL_SUBTEST_3(check_stdvector_matrix(MatrixXcf(10,10)));
+
+ // some Transform
+ CALL_SUBTEST_4(check_stdvector_transform(Transform2f()));
+ CALL_SUBTEST_4(check_stdvector_transform(Transform3f()));
+ CALL_SUBTEST_4(check_stdvector_transform(Transform3d()));
+ //CALL_SUBTEST(check_stdvector_transform(Transform4d()));
+
+ // some Quaternion
+ CALL_SUBTEST_5(check_stdvector_quaternion(Quaternionf()));
+ CALL_SUBTEST_5(check_stdvector_quaternion(Quaterniond()));
+}
diff --git a/test/eigen2/eigen2_nomalloc.cpp b/test/eigen2/eigen2_nomalloc.cpp
new file mode 100644
index 000000000..e234abe4b
--- /dev/null
+++ b/test/eigen2/eigen2_nomalloc.cpp
@@ -0,0 +1,63 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra. Eigen itself is part of the KDE project.
+//
+// Copyright (C) 2008 Gael Guennebaud <g.gael@free.fr>
+// Copyright (C) 2006-2008 Benoit Jacob <jacob.benoit.1@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/.
+
+// this hack is needed to make this file compiles with -pedantic (gcc)
+#ifdef __GNUC__
+#define throw(X)
+#endif
+// discard stack allocation as that too bypasses malloc
+#define EIGEN_STACK_ALLOCATION_LIMIT 0
+// any heap allocation will raise an assert
+#define EIGEN_NO_MALLOC
+
+#include "main.h"
+
+template<typename MatrixType> void nomalloc(const MatrixType& m)
+{
+ /* this test check no dynamic memory allocation are issued with fixed-size matrices
+ */
+
+ typedef typename MatrixType::Scalar Scalar;
+ typedef Matrix<Scalar, MatrixType::RowsAtCompileTime, 1> VectorType;
+
+ int rows = m.rows();
+ int cols = m.cols();
+
+ MatrixType m1 = MatrixType::Random(rows, cols),
+ m2 = MatrixType::Random(rows, cols),
+ m3(rows, cols),
+ mzero = MatrixType::Zero(rows, cols),
+ identity = Matrix<Scalar, MatrixType::RowsAtCompileTime, MatrixType::RowsAtCompileTime>
+ ::Identity(rows, rows),
+ square = Matrix<Scalar, MatrixType::RowsAtCompileTime, MatrixType::RowsAtCompileTime>
+ ::Random(rows, rows);
+ VectorType v1 = VectorType::Random(rows),
+ v2 = VectorType::Random(rows),
+ vzero = VectorType::Zero(rows);
+
+ Scalar s1 = ei_random<Scalar>();
+
+ int r = ei_random<int>(0, rows-1),
+ c = ei_random<int>(0, cols-1);
+
+ VERIFY_IS_APPROX((m1+m2)*s1, s1*m1+s1*m2);
+ VERIFY_IS_APPROX((m1+m2)(r,c), (m1(r,c))+(m2(r,c)));
+ VERIFY_IS_APPROX(m1.cwise() * m1.block(0,0,rows,cols), m1.cwise() * m1);
+ VERIFY_IS_APPROX((m1*m1.transpose())*m2, m1*(m1.transpose()*m2));
+}
+
+void test_eigen2_nomalloc()
+{
+ // check that our operator new is indeed called:
+ VERIFY_RAISES_ASSERT(MatrixXd dummy = MatrixXd::Random(3,3));
+ CALL_SUBTEST_1( nomalloc(Matrix<float, 1, 1>()) );
+ CALL_SUBTEST_2( nomalloc(Matrix4d()) );
+ CALL_SUBTEST_3( nomalloc(Matrix<float,32,32>()) );
+}
diff --git a/test/eigen2/eigen2_packetmath.cpp b/test/eigen2/eigen2_packetmath.cpp
new file mode 100644
index 000000000..b1f325fe7
--- /dev/null
+++ b/test/eigen2/eigen2_packetmath.cpp
@@ -0,0 +1,132 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra. Eigen itself is part of the KDE project.
+//
+// Copyright (C) 2006-2008 Benoit Jacob <jacob.benoit.1@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 "main.h"
+
+// using namespace Eigen;
+
+template<typename Scalar> bool areApprox(const Scalar* a, const Scalar* b, int size)
+{
+ for (int i=0; i<size; ++i)
+ if (!ei_isApprox(a[i],b[i])) return false;
+ return true;
+}
+
+#define CHECK_CWISE(REFOP, POP) { \
+ for (int i=0; i<PacketSize; ++i) \
+ ref[i] = REFOP(data1[i], data1[i+PacketSize]); \
+ ei_pstore(data2, POP(ei_pload(data1), ei_pload(data1+PacketSize))); \
+ VERIFY(areApprox(ref, data2, PacketSize) && #POP); \
+}
+
+#define REF_ADD(a,b) ((a)+(b))
+#define REF_SUB(a,b) ((a)-(b))
+#define REF_MUL(a,b) ((a)*(b))
+#define REF_DIV(a,b) ((a)/(b))
+
+namespace std {
+
+template<> const complex<float>& min(const complex<float>& a, const complex<float>& b)
+{ return a.real() < b.real() ? a : b; }
+
+template<> const complex<float>& max(const complex<float>& a, const complex<float>& b)
+{ return a.real() < b.real() ? b : a; }
+
+}
+
+template<typename Scalar> void packetmath()
+{
+ typedef typename ei_packet_traits<Scalar>::type Packet;
+ const int PacketSize = ei_packet_traits<Scalar>::size;
+
+ const int size = PacketSize*4;
+ EIGEN_ALIGN_128 Scalar data1[ei_packet_traits<Scalar>::size*4];
+ EIGEN_ALIGN_128 Scalar data2[ei_packet_traits<Scalar>::size*4];
+ EIGEN_ALIGN_128 Packet packets[PacketSize*2];
+ EIGEN_ALIGN_128 Scalar ref[ei_packet_traits<Scalar>::size*4];
+ for (int i=0; i<size; ++i)
+ {
+ data1[i] = ei_random<Scalar>();
+ data2[i] = ei_random<Scalar>();
+ }
+
+ ei_pstore(data2, ei_pload(data1));
+ VERIFY(areApprox(data1, data2, PacketSize) && "aligned load/store");
+
+ for (int offset=0; offset<PacketSize; ++offset)
+ {
+ ei_pstore(data2, ei_ploadu(data1+offset));
+ VERIFY(areApprox(data1+offset, data2, PacketSize) && "ei_ploadu");
+ }
+
+ for (int offset=0; offset<PacketSize; ++offset)
+ {
+ ei_pstoreu(data2+offset, ei_pload(data1));
+ VERIFY(areApprox(data1, data2+offset, PacketSize) && "ei_pstoreu");
+ }
+
+ for (int offset=0; offset<PacketSize; ++offset)
+ {
+ packets[0] = ei_pload(data1);
+ packets[1] = ei_pload(data1+PacketSize);
+ if (offset==0) ei_palign<0>(packets[0], packets[1]);
+ else if (offset==1) ei_palign<1>(packets[0], packets[1]);
+ else if (offset==2) ei_palign<2>(packets[0], packets[1]);
+ else if (offset==3) ei_palign<3>(packets[0], packets[1]);
+ ei_pstore(data2, packets[0]);
+
+ for (int i=0; i<PacketSize; ++i)
+ ref[i] = data1[i+offset];
+
+ typedef Matrix<Scalar, PacketSize, 1> Vector;
+ VERIFY(areApprox(ref, data2, PacketSize) && "ei_palign");
+ }
+
+ CHECK_CWISE(REF_ADD, ei_padd);
+ CHECK_CWISE(REF_SUB, ei_psub);
+ CHECK_CWISE(REF_MUL, ei_pmul);
+ #ifndef EIGEN_VECTORIZE_ALTIVEC
+ if (!ei_is_same_type<Scalar,int>::ret)
+ CHECK_CWISE(REF_DIV, ei_pdiv);
+ #endif
+ CHECK_CWISE(std::min, ei_pmin);
+ CHECK_CWISE(std::max, ei_pmax);
+
+ for (int i=0; i<PacketSize; ++i)
+ ref[i] = data1[0];
+ ei_pstore(data2, ei_pset1(data1[0]));
+ VERIFY(areApprox(ref, data2, PacketSize) && "ei_pset1");
+
+ VERIFY(ei_isApprox(data1[0], ei_pfirst(ei_pload(data1))) && "ei_pfirst");
+
+ ref[0] = 0;
+ for (int i=0; i<PacketSize; ++i)
+ ref[0] += data1[i];
+ VERIFY(ei_isApprox(ref[0], ei_predux(ei_pload(data1))) && "ei_predux");
+
+ for (int j=0; j<PacketSize; ++j)
+ {
+ ref[j] = 0;
+ for (int i=0; i<PacketSize; ++i)
+ ref[j] += data1[i+j*PacketSize];
+ packets[j] = ei_pload(data1+j*PacketSize);
+ }
+ ei_pstore(data2, ei_preduxp(packets));
+ VERIFY(areApprox(ref, data2, PacketSize) && "ei_preduxp");
+}
+
+void test_eigen2_packetmath()
+{
+ for(int i = 0; i < g_repeat; i++) {
+ CALL_SUBTEST_1( packetmath<float>() );
+ CALL_SUBTEST_2( packetmath<double>() );
+ CALL_SUBTEST_3( packetmath<int>() );
+ CALL_SUBTEST_4( packetmath<std::complex<float> >() );
+ }
+}
diff --git a/test/eigen2/eigen2_parametrizedline.cpp b/test/eigen2/eigen2_parametrizedline.cpp
new file mode 100644
index 000000000..814728870
--- /dev/null
+++ b/test/eigen2/eigen2_parametrizedline.cpp
@@ -0,0 +1,62 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra. Eigen itself is part of the KDE project.
+//
+// Copyright (C) 2008 Gael Guennebaud <g.gael@free.fr>
+// Copyright (C) 2008 Benoit Jacob <jacob.benoit.1@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 "main.h"
+#include <Eigen/Geometry>
+#include <Eigen/LU>
+#include <Eigen/QR>
+
+template<typename LineType> void parametrizedline(const LineType& _line)
+{
+ /* this test covers the following files:
+ ParametrizedLine.h
+ */
+
+ const int dim = _line.dim();
+ typedef typename LineType::Scalar Scalar;
+ typedef typename NumTraits<Scalar>::Real RealScalar;
+ typedef Matrix<Scalar, LineType::AmbientDimAtCompileTime, 1> VectorType;
+ typedef Matrix<Scalar, LineType::AmbientDimAtCompileTime,
+ LineType::AmbientDimAtCompileTime> MatrixType;
+
+ VectorType p0 = VectorType::Random(dim);
+ VectorType p1 = VectorType::Random(dim);
+
+ VectorType d0 = VectorType::Random(dim).normalized();
+
+ LineType l0(p0, d0);
+
+ Scalar s0 = ei_random<Scalar>();
+ Scalar s1 = ei_abs(ei_random<Scalar>());
+
+ VERIFY_IS_MUCH_SMALLER_THAN( l0.distance(p0), RealScalar(1) );
+ VERIFY_IS_MUCH_SMALLER_THAN( l0.distance(p0+s0*d0), RealScalar(1) );
+ VERIFY_IS_APPROX( (l0.projection(p1)-p1).norm(), l0.distance(p1) );
+ VERIFY_IS_MUCH_SMALLER_THAN( l0.distance(l0.projection(p1)), RealScalar(1) );
+ VERIFY_IS_APPROX( Scalar(l0.distance((p0+s0*d0) + d0.unitOrthogonal() * s1)), s1 );
+
+ // casting
+ const int Dim = LineType::AmbientDimAtCompileTime;
+ typedef typename GetDifferentType<Scalar>::type OtherScalar;
+ ParametrizedLine<OtherScalar,Dim> hp1f = l0.template cast<OtherScalar>();
+ VERIFY_IS_APPROX(hp1f.template cast<Scalar>(),l0);
+ ParametrizedLine<Scalar,Dim> hp1d = l0.template cast<Scalar>();
+ VERIFY_IS_APPROX(hp1d.template cast<Scalar>(),l0);
+}
+
+void test_eigen2_parametrizedline()
+{
+ for(int i = 0; i < g_repeat; i++) {
+ CALL_SUBTEST_1( parametrizedline(ParametrizedLine<float,2>()) );
+ CALL_SUBTEST_2( parametrizedline(ParametrizedLine<float,3>()) );
+ CALL_SUBTEST_3( parametrizedline(ParametrizedLine<double,4>()) );
+ CALL_SUBTEST_4( parametrizedline(ParametrizedLine<std::complex<double>,5>()) );
+ }
+}
diff --git a/test/eigen2/eigen2_prec_inverse_4x4.cpp b/test/eigen2/eigen2_prec_inverse_4x4.cpp
new file mode 100644
index 000000000..8bfa55694
--- /dev/null
+++ b/test/eigen2/eigen2_prec_inverse_4x4.cpp
@@ -0,0 +1,84 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra.
+//
+// Copyright (C) 2009 Benoit Jacob <jacob.benoit.1@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 "main.h"
+#include <Eigen/LU>
+#include <algorithm>
+
+template<typename T> std::string type_name() { return "other"; }
+template<> std::string type_name<float>() { return "float"; }
+template<> std::string type_name<double>() { return "double"; }
+template<> std::string type_name<int>() { return "int"; }
+template<> std::string type_name<std::complex<float> >() { return "complex<float>"; }
+template<> std::string type_name<std::complex<double> >() { return "complex<double>"; }
+template<> std::string type_name<std::complex<int> >() { return "complex<int>"; }
+
+#define EIGEN_DEBUG_VAR(x) std::cerr << #x << " = " << x << std::endl;
+
+template<typename T> inline typename NumTraits<T>::Real epsilon()
+{
+ return std::numeric_limits<typename NumTraits<T>::Real>::epsilon();
+}
+
+template<typename MatrixType> void inverse_permutation_4x4()
+{
+ typedef typename MatrixType::Scalar Scalar;
+ typedef typename MatrixType::RealScalar RealScalar;
+ Vector4i indices(0,1,2,3);
+ for(int i = 0; i < 24; ++i)
+ {
+ MatrixType m = MatrixType::Zero();
+ m(indices(0),0) = 1;
+ m(indices(1),1) = 1;
+ m(indices(2),2) = 1;
+ m(indices(3),3) = 1;
+ MatrixType inv = m.inverse();
+ double error = double( (m*inv-MatrixType::Identity()).norm() / epsilon<Scalar>() );
+ VERIFY(error == 0.0);
+ std::next_permutation(indices.data(),indices.data()+4);
+ }
+}
+
+template<typename MatrixType> void inverse_general_4x4(int repeat)
+{
+ typedef typename MatrixType::Scalar Scalar;
+ typedef typename MatrixType::RealScalar RealScalar;
+ double error_sum = 0., error_max = 0.;
+ for(int i = 0; i < repeat; ++i)
+ {
+ MatrixType m;
+ RealScalar absdet;
+ do {
+ m = MatrixType::Random();
+ absdet = ei_abs(m.determinant());
+ } while(absdet < 10 * epsilon<Scalar>());
+ MatrixType inv = m.inverse();
+ double error = double( (m*inv-MatrixType::Identity()).norm() * absdet / epsilon<Scalar>() );
+ error_sum += error;
+ error_max = std::max(error_max, error);
+ }
+ std::cerr << "inverse_general_4x4, Scalar = " << type_name<Scalar>() << std::endl;
+ double error_avg = error_sum / repeat;
+ EIGEN_DEBUG_VAR(error_avg);
+ EIGEN_DEBUG_VAR(error_max);
+ VERIFY(error_avg < (NumTraits<Scalar>::IsComplex ? 8.0 : 1.25));
+ VERIFY(error_max < (NumTraits<Scalar>::IsComplex ? 64.0 : 20.0));
+}
+
+void test_eigen2_prec_inverse_4x4()
+{
+ CALL_SUBTEST_1((inverse_permutation_4x4<Matrix4f>()));
+ CALL_SUBTEST_1(( inverse_general_4x4<Matrix4f>(200000 * g_repeat) ));
+
+ CALL_SUBTEST_2((inverse_permutation_4x4<Matrix<double,4,4,RowMajor> >()));
+ CALL_SUBTEST_2(( inverse_general_4x4<Matrix<double,4,4,RowMajor> >(200000 * g_repeat) ));
+
+ CALL_SUBTEST_3((inverse_permutation_4x4<Matrix4cf>()));
+ CALL_SUBTEST_3((inverse_general_4x4<Matrix4cf>(50000 * g_repeat)));
+}
diff --git a/test/eigen2/eigen2_product_large.cpp b/test/eigen2/eigen2_product_large.cpp
new file mode 100644
index 000000000..5149ef748
--- /dev/null
+++ b/test/eigen2/eigen2_product_large.cpp
@@ -0,0 +1,45 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra. Eigen itself is part of the KDE project.
+//
+// Copyright (C) 2006-2008 Benoit Jacob <jacob.benoit.1@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 "product.h"
+
+void test_eigen2_product_large()
+{
+ for(int i = 0; i < g_repeat; i++) {
+ CALL_SUBTEST_1( product(MatrixXf(ei_random<int>(1,320), ei_random<int>(1,320))) );
+ CALL_SUBTEST_2( product(MatrixXd(ei_random<int>(1,320), ei_random<int>(1,320))) );
+ CALL_SUBTEST_3( product(MatrixXi(ei_random<int>(1,320), ei_random<int>(1,320))) );
+ CALL_SUBTEST_4( product(MatrixXcf(ei_random<int>(1,50), ei_random<int>(1,50))) );
+ CALL_SUBTEST_5( product(Matrix<float,Dynamic,Dynamic,RowMajor>(ei_random<int>(1,320), ei_random<int>(1,320))) );
+ }
+
+#ifdef EIGEN_TEST_PART_6
+ {
+ // test a specific issue in DiagonalProduct
+ int N = 1000000;
+ VectorXf v = VectorXf::Ones(N);
+ MatrixXf m = MatrixXf::Ones(N,3);
+ m = (v+v).asDiagonal() * m;
+ VERIFY_IS_APPROX(m, MatrixXf::Constant(N,3,2));
+ }
+
+ {
+ // test deferred resizing in Matrix::operator=
+ MatrixXf a = MatrixXf::Random(10,4), b = MatrixXf::Random(4,10), c = a;
+ VERIFY_IS_APPROX((a = a * b), (c * b).eval());
+ }
+
+ {
+ MatrixXf mat1(10,10); mat1.setRandom();
+ MatrixXf mat2(32,10); mat2.setRandom();
+ MatrixXf result = mat1.row(2)*mat2.transpose();
+ VERIFY_IS_APPROX(result, (mat1.row(2)*mat2.transpose()).eval());
+ }
+#endif
+}
diff --git a/test/eigen2/eigen2_product_small.cpp b/test/eigen2/eigen2_product_small.cpp
new file mode 100644
index 000000000..4cd8c102f
--- /dev/null
+++ b/test/eigen2/eigen2_product_small.cpp
@@ -0,0 +1,22 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra. Eigen itself is part of the KDE project.
+//
+// Copyright (C) 2006-2008 Benoit Jacob <jacob.benoit.1@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/.
+
+#define EIGEN_NO_STATIC_ASSERT
+#include "product.h"
+
+void test_eigen2_product_small()
+{
+ for(int i = 0; i < g_repeat; i++) {
+ CALL_SUBTEST_1( product(Matrix<float, 3, 2>()) );
+ CALL_SUBTEST_2( product(Matrix<int, 3, 5>()) );
+ CALL_SUBTEST_3( product(Matrix3d()) );
+ CALL_SUBTEST_4( product(Matrix4d()) );
+ CALL_SUBTEST_5( product(Matrix4f()) );
+ }
+}
diff --git a/test/eigen2/eigen2_qr.cpp b/test/eigen2/eigen2_qr.cpp
new file mode 100644
index 000000000..76977e4c1
--- /dev/null
+++ b/test/eigen2/eigen2_qr.cpp
@@ -0,0 +1,69 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra. Eigen itself is part of the KDE project.
+//
+// Copyright (C) 2008 Gael Guennebaud <g.gael@free.fr>
+//
+// This Source Code Form is subject to the terms of the Mozilla
+// Public License v. 2.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 "main.h"
+#include <Eigen/QR>
+
+template<typename MatrixType> void qr(const MatrixType& m)
+{
+ /* this test covers the following files:
+ QR.h
+ */
+ int rows = m.rows();
+ int cols = m.cols();
+
+ typedef typename MatrixType::Scalar Scalar;
+ typedef Matrix<Scalar, MatrixType::ColsAtCompileTime, MatrixType::ColsAtCompileTime> SquareMatrixType;
+ typedef Matrix<Scalar, MatrixType::ColsAtCompileTime, 1> VectorType;
+
+ MatrixType a = MatrixType::Random(rows,cols);
+ QR<MatrixType> qrOfA(a);
+ VERIFY_IS_APPROX(a, qrOfA.matrixQ() * qrOfA.matrixR());
+ VERIFY_IS_NOT_APPROX(a+MatrixType::Identity(rows, cols), qrOfA.matrixQ() * qrOfA.matrixR());
+
+ #if 0 // eigenvalues module not yet ready
+ SquareMatrixType b = a.adjoint() * a;
+
+ // check tridiagonalization
+ Tridiagonalization<SquareMatrixType> tridiag(b);
+ VERIFY_IS_APPROX(b, tridiag.matrixQ() * tridiag.matrixT() * tridiag.matrixQ().adjoint());
+
+ // check hessenberg decomposition
+ HessenbergDecomposition<SquareMatrixType> hess(b);
+ VERIFY_IS_APPROX(b, hess.matrixQ() * hess.matrixH() * hess.matrixQ().adjoint());
+ VERIFY_IS_APPROX(tridiag.matrixT(), hess.matrixH());
+ b = SquareMatrixType::Random(cols,cols);
+ hess.compute(b);
+ VERIFY_IS_APPROX(b, hess.matrixQ() * hess.matrixH() * hess.matrixQ().adjoint());
+ #endif
+}
+
+void test_eigen2_qr()
+{
+ for(int i = 0; i < 1; i++) {
+ CALL_SUBTEST_1( qr(Matrix2f()) );
+ CALL_SUBTEST_2( qr(Matrix4d()) );
+ CALL_SUBTEST_3( qr(MatrixXf(12,8)) );
+ CALL_SUBTEST_4( qr(MatrixXcd(5,5)) );
+ CALL_SUBTEST_4( qr(MatrixXcd(7,3)) );
+ }
+
+#ifdef EIGEN_TEST_PART_5
+ // small isFullRank test
+ {
+ Matrix3d mat;
+ mat << 1, 45, 1, 2, 2, 2, 1, 2, 3;
+ VERIFY(mat.qr().isFullRank());
+ mat << 1, 1, 1, 2, 2, 2, 1, 2, 3;
+ //always returns true in eigen2support
+ //VERIFY(!mat.qr().isFullRank());
+ }
+
+#endif
+}
diff --git a/test/eigen2/eigen2_qtvector.cpp b/test/eigen2/eigen2_qtvector.cpp
new file mode 100644
index 000000000..6cfb58a26
--- /dev/null
+++ b/test/eigen2/eigen2_qtvector.cpp
@@ -0,0 +1,158 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra. Eigen itself is part of the KDE project.
+//
+// Copyright (C) 2008 Gael Guennebaud <g.gael@free.fr>
+// Copyright (C) 2008 Benoit Jacob <jacob.benoit.1@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/.
+
+#define EIGEN_WORK_AROUND_QT_BUG_CALLING_WRONG_OPERATOR_NEW_FIXED_IN_QT_4_5
+
+#include "main.h"
+
+#include <Eigen/Geometry>
+#include <Eigen/QtAlignedMalloc>
+
+#include <QtCore/QVector>
+
+template<typename MatrixType>
+void check_qtvector_matrix(const MatrixType& m)
+{
+ int rows = m.rows();
+ int cols = m.cols();
+ MatrixType x = MatrixType::Random(rows,cols), y = MatrixType::Random(rows,cols);
+ QVector<MatrixType> v(10, MatrixType(rows,cols)), w(20, y);
+ for(int i = 0; i < 20; i++)
+ {
+ VERIFY_IS_APPROX(w[i], y);
+ }
+ v[5] = x;
+ w[6] = v[5];
+ VERIFY_IS_APPROX(w[6], v[5]);
+ v = w;
+ for(int i = 0; i < 20; i++)
+ {
+ VERIFY_IS_APPROX(w[i], v[i]);
+ }
+
+ v.resize(21);
+ v[20] = x;
+ VERIFY_IS_APPROX(v[20], x);
+ v.fill(y,22);
+ VERIFY_IS_APPROX(v[21], y);
+ v.push_back(x);
+ VERIFY_IS_APPROX(v[22], x);
+ VERIFY((size_t)&(v[22]) == (size_t)&(v[21]) + sizeof(MatrixType));
+
+ // do a lot of push_back such that the vector gets internally resized
+ // (with memory reallocation)
+ MatrixType* ref = &w[0];
+ for(int i=0; i<30 || ((ref==&w[0]) && i<300); ++i)
+ v.push_back(w[i%w.size()]);
+ for(int i=23; i<v.size(); ++i)
+ {
+ VERIFY(v[i]==w[(i-23)%w.size()]);
+ }
+}
+
+template<typename TransformType>
+void check_qtvector_transform(const TransformType&)
+{
+ typedef typename TransformType::MatrixType MatrixType;
+ TransformType x(MatrixType::Random()), y(MatrixType::Random());
+ QVector<TransformType> v(10), w(20, y);
+ v[5] = x;
+ w[6] = v[5];
+ VERIFY_IS_APPROX(w[6], v[5]);
+ v = w;
+ for(int i = 0; i < 20; i++)
+ {
+ VERIFY_IS_APPROX(w[i], v[i]);
+ }
+
+ v.resize(21);
+ v[20] = x;
+ VERIFY_IS_APPROX(v[20], x);
+ v.fill(y,22);
+ VERIFY_IS_APPROX(v[21], y);
+ v.push_back(x);
+ VERIFY_IS_APPROX(v[22], x);
+ VERIFY((size_t)&(v[22]) == (size_t)&(v[21]) + sizeof(TransformType));
+
+ // do a lot of push_back such that the vector gets internally resized
+ // (with memory reallocation)
+ TransformType* ref = &w[0];
+ for(int i=0; i<30 || ((ref==&w[0]) && i<300); ++i)
+ v.push_back(w[i%w.size()]);
+ for(unsigned int i=23; int(i)<v.size(); ++i)
+ {
+ VERIFY(v[i].matrix()==w[(i-23)%w.size()].matrix());
+ }
+}
+
+template<typename QuaternionType>
+void check_qtvector_quaternion(const QuaternionType&)
+{
+ typedef typename QuaternionType::Coefficients Coefficients;
+ QuaternionType x(Coefficients::Random()), y(Coefficients::Random());
+ QVector<QuaternionType> v(10), w(20, y);
+ v[5] = x;
+ w[6] = v[5];
+ VERIFY_IS_APPROX(w[6], v[5]);
+ v = w;
+ for(int i = 0; i < 20; i++)
+ {
+ VERIFY_IS_APPROX(w[i], v[i]);
+ }
+
+ v.resize(21);
+ v[20] = x;
+ VERIFY_IS_APPROX(v[20], x);
+ v.fill(y,22);
+ VERIFY_IS_APPROX(v[21], y);
+ v.push_back(x);
+ VERIFY_IS_APPROX(v[22], x);
+ VERIFY((size_t)&(v[22]) == (size_t)&(v[21]) + sizeof(QuaternionType));
+
+ // do a lot of push_back such that the vector gets internally resized
+ // (with memory reallocation)
+ QuaternionType* ref = &w[0];
+ for(int i=0; i<30 || ((ref==&w[0]) && i<300); ++i)
+ v.push_back(w[i%w.size()]);
+ for(unsigned int i=23; int(i)<v.size(); ++i)
+ {
+ VERIFY(v[i].coeffs()==w[(i-23)%w.size()].coeffs());
+ }
+}
+
+void test_eigen2_qtvector()
+{
+ // some non vectorizable fixed sizes
+ CALL_SUBTEST_1(check_qtvector_matrix(Vector2f()));
+ CALL_SUBTEST_1(check_qtvector_matrix(Matrix3f()));
+ CALL_SUBTEST_1(check_qtvector_matrix(Matrix3d()));
+
+ // some vectorizable fixed sizes
+ CALL_SUBTEST_2(check_qtvector_matrix(Matrix2f()));
+ CALL_SUBTEST_2(check_qtvector_matrix(Vector4f()));
+ CALL_SUBTEST_2(check_qtvector_matrix(Matrix4f()));
+ CALL_SUBTEST_2(check_qtvector_matrix(Matrix4d()));
+
+ // some dynamic sizes
+ CALL_SUBTEST_3(check_qtvector_matrix(MatrixXd(1,1)));
+ CALL_SUBTEST_3(check_qtvector_matrix(VectorXd(20)));
+ CALL_SUBTEST_3(check_qtvector_matrix(RowVectorXf(20)));
+ CALL_SUBTEST_3(check_qtvector_matrix(MatrixXcf(10,10)));
+
+ // some Transform
+ CALL_SUBTEST_4(check_qtvector_transform(Transform2f()));
+ CALL_SUBTEST_4(check_qtvector_transform(Transform3f()));
+ CALL_SUBTEST_4(check_qtvector_transform(Transform3d()));
+ //CALL_SUBTEST_4(check_qtvector_transform(Transform4d()));
+
+ // some Quaternion
+ CALL_SUBTEST_5(check_qtvector_quaternion(Quaternionf()));
+ CALL_SUBTEST_5(check_qtvector_quaternion(Quaternionf()));
+}
diff --git a/test/eigen2/eigen2_regression.cpp b/test/eigen2/eigen2_regression.cpp
new file mode 100644
index 000000000..c68b58da8
--- /dev/null
+++ b/test/eigen2/eigen2_regression.cpp
@@ -0,0 +1,136 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra. Eigen itself is part of the KDE project.
+//
+// Copyright (C) 2008 Benoit Jacob <jacob.benoit.1@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 "main.h"
+#include <Eigen/LeastSquares>
+
+template<typename VectorType,
+ typename HyperplaneType>
+void makeNoisyCohyperplanarPoints(int numPoints,
+ VectorType **points,
+ HyperplaneType *hyperplane,
+ typename VectorType::Scalar noiseAmplitude)
+{
+ typedef typename VectorType::Scalar Scalar;
+ const int size = points[0]->size();
+ // pick a random hyperplane, store the coefficients of its equation
+ hyperplane->coeffs().resize(size + 1);
+ for(int j = 0; j < size + 1; j++)
+ {
+ do {
+ hyperplane->coeffs().coeffRef(j) = ei_random<Scalar>();
+ } while(ei_abs(hyperplane->coeffs().coeff(j)) < 0.5);
+ }
+
+ // now pick numPoints random points on this hyperplane
+ for(int i = 0; i < numPoints; i++)
+ {
+ VectorType& cur_point = *(points[i]);
+ do
+ {
+ cur_point = VectorType::Random(size)/*.normalized()*/;
+ // project cur_point onto the hyperplane
+ Scalar x = - (hyperplane->coeffs().start(size).cwise()*cur_point).sum();
+ cur_point *= hyperplane->coeffs().coeff(size) / x;
+ } while( cur_point.norm() < 0.5
+ || cur_point.norm() > 2.0 );
+ }
+
+ // add some noise to these points
+ for(int i = 0; i < numPoints; i++ )
+ *(points[i]) += noiseAmplitude * VectorType::Random(size);
+}
+
+template<typename VectorType>
+void check_linearRegression(int numPoints,
+ VectorType **points,
+ const VectorType& original,
+ typename VectorType::Scalar tolerance)
+{
+ int size = points[0]->size();
+ assert(size==2);
+ VectorType result(size);
+ linearRegression(numPoints, points, &result, 1);
+ typename VectorType::Scalar error = (result - original).norm() / original.norm();
+ VERIFY(ei_abs(error) < ei_abs(tolerance));
+}
+
+template<typename VectorType,
+ typename HyperplaneType>
+void check_fitHyperplane(int numPoints,
+ VectorType **points,
+ const HyperplaneType& original,
+ typename VectorType::Scalar tolerance)
+{
+ int size = points[0]->size();
+ HyperplaneType result(size);
+ fitHyperplane(numPoints, points, &result);
+ result.coeffs() *= original.coeffs().coeff(size)/result.coeffs().coeff(size);
+ typename VectorType::Scalar error = (result.coeffs() - original.coeffs()).norm() / original.coeffs().norm();
+ std::cout << ei_abs(error) << " xxx " << ei_abs(tolerance) << std::endl;
+ VERIFY(ei_abs(error) < ei_abs(tolerance));
+}
+
+void test_eigen2_regression()
+{
+ for(int i = 0; i < g_repeat; i++)
+ {
+#ifdef EIGEN_TEST_PART_1
+ {
+ Vector2f points2f [1000];
+ Vector2f *points2f_ptrs [1000];
+ for(int i = 0; i < 1000; i++) points2f_ptrs[i] = &(points2f[i]);
+ Vector2f coeffs2f;
+ Hyperplane<float,2> coeffs3f;
+ makeNoisyCohyperplanarPoints(1000, points2f_ptrs, &coeffs3f, 0.01f);
+ coeffs2f[0] = -coeffs3f.coeffs()[0]/coeffs3f.coeffs()[1];
+ coeffs2f[1] = -coeffs3f.coeffs()[2]/coeffs3f.coeffs()[1];
+ CALL_SUBTEST(check_linearRegression(10, points2f_ptrs, coeffs2f, 0.05f));
+ CALL_SUBTEST(check_linearRegression(100, points2f_ptrs, coeffs2f, 0.01f));
+ CALL_SUBTEST(check_linearRegression(1000, points2f_ptrs, coeffs2f, 0.002f));
+ }
+#endif
+#ifdef EIGEN_TEST_PART_2
+ {
+ Vector2f points2f [1000];
+ Vector2f *points2f_ptrs [1000];
+ for(int i = 0; i < 1000; i++) points2f_ptrs[i] = &(points2f[i]);
+ Hyperplane<float,2> coeffs3f;
+ makeNoisyCohyperplanarPoints(1000, points2f_ptrs, &coeffs3f, 0.01f);
+ CALL_SUBTEST(check_fitHyperplane(10, points2f_ptrs, coeffs3f, 0.05f));
+ CALL_SUBTEST(check_fitHyperplane(100, points2f_ptrs, coeffs3f, 0.01f));
+ CALL_SUBTEST(check_fitHyperplane(1000, points2f_ptrs, coeffs3f, 0.002f));
+ }
+#endif
+#ifdef EIGEN_TEST_PART_3
+ {
+ Vector4d points4d [1000];
+ Vector4d *points4d_ptrs [1000];
+ for(int i = 0; i < 1000; i++) points4d_ptrs[i] = &(points4d[i]);
+ Hyperplane<double,4> coeffs5d;
+ makeNoisyCohyperplanarPoints(1000, points4d_ptrs, &coeffs5d, 0.01);
+ CALL_SUBTEST(check_fitHyperplane(10, points4d_ptrs, coeffs5d, 0.05));
+ CALL_SUBTEST(check_fitHyperplane(100, points4d_ptrs, coeffs5d, 0.01));
+ CALL_SUBTEST(check_fitHyperplane(1000, points4d_ptrs, coeffs5d, 0.002));
+ }
+#endif
+#ifdef EIGEN_TEST_PART_4
+ {
+ VectorXcd *points11cd_ptrs[1000];
+ for(int i = 0; i < 1000; i++) points11cd_ptrs[i] = new VectorXcd(11);
+ Hyperplane<std::complex<double>,Dynamic> *coeffs12cd = new Hyperplane<std::complex<double>,Dynamic>(11);
+ makeNoisyCohyperplanarPoints(1000, points11cd_ptrs, coeffs12cd, 0.01);
+ CALL_SUBTEST(check_fitHyperplane(100, points11cd_ptrs, *coeffs12cd, 0.025));
+ CALL_SUBTEST(check_fitHyperplane(1000, points11cd_ptrs, *coeffs12cd, 0.006));
+ delete coeffs12cd;
+ for(int i = 0; i < 1000; i++) delete points11cd_ptrs[i];
+ }
+#endif
+ }
+}
diff --git a/test/eigen2/eigen2_sizeof.cpp b/test/eigen2/eigen2_sizeof.cpp
new file mode 100644
index 000000000..ec1af5a06
--- /dev/null
+++ b/test/eigen2/eigen2_sizeof.cpp
@@ -0,0 +1,31 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra. Eigen itself is part of the KDE project.
+//
+// Copyright (C) 2008 Gael Guennebaud <g.gael@free.fr>
+//
+// This Source Code Form is subject to the terms of the Mozilla
+// Public License v. 2.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 "main.h"
+
+template<typename MatrixType> void verifySizeOf(const MatrixType&)
+{
+ typedef typename MatrixType::Scalar Scalar;
+ if (MatrixType::RowsAtCompileTime!=Dynamic && MatrixType::ColsAtCompileTime!=Dynamic)
+ VERIFY(sizeof(MatrixType)==sizeof(Scalar)*MatrixType::SizeAtCompileTime);
+ else
+ VERIFY(sizeof(MatrixType)==sizeof(Scalar*) + 2 * sizeof(typename MatrixType::Index));
+}
+
+void test_eigen2_sizeof()
+{
+ CALL_SUBTEST( verifySizeOf(Matrix<float, 1, 1>()) );
+ CALL_SUBTEST( verifySizeOf(Matrix4d()) );
+ CALL_SUBTEST( verifySizeOf(Matrix<double, 4, 2>()) );
+ CALL_SUBTEST( verifySizeOf(Matrix<bool, 7, 5>()) );
+ CALL_SUBTEST( verifySizeOf(MatrixXcf(3, 3)) );
+ CALL_SUBTEST( verifySizeOf(MatrixXi(8, 12)) );
+ CALL_SUBTEST( verifySizeOf(MatrixXcd(20, 20)) );
+ CALL_SUBTEST( verifySizeOf(Matrix<float, 100, 100>()) );
+}
diff --git a/test/eigen2/eigen2_smallvectors.cpp b/test/eigen2/eigen2_smallvectors.cpp
new file mode 100644
index 000000000..03962b17d
--- /dev/null
+++ b/test/eigen2/eigen2_smallvectors.cpp
@@ -0,0 +1,42 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra. Eigen itself is part of the KDE project.
+//
+// Copyright (C) 2006-2008 Benoit Jacob <jacob.benoit.1@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 "main.h"
+
+template<typename Scalar> void smallVectors()
+{
+ typedef Matrix<Scalar, 1, 2> V2;
+ typedef Matrix<Scalar, 3, 1> V3;
+ typedef Matrix<Scalar, 1, 4> V4;
+ Scalar x1 = ei_random<Scalar>(),
+ x2 = ei_random<Scalar>(),
+ x3 = ei_random<Scalar>(),
+ x4 = ei_random<Scalar>();
+ V2 v2(x1, x2);
+ V3 v3(x1, x2, x3);
+ V4 v4(x1, x2, x3, x4);
+ VERIFY_IS_APPROX(x1, v2.x());
+ VERIFY_IS_APPROX(x1, v3.x());
+ VERIFY_IS_APPROX(x1, v4.x());
+ VERIFY_IS_APPROX(x2, v2.y());
+ VERIFY_IS_APPROX(x2, v3.y());
+ VERIFY_IS_APPROX(x2, v4.y());
+ VERIFY_IS_APPROX(x3, v3.z());
+ VERIFY_IS_APPROX(x3, v4.z());
+ VERIFY_IS_APPROX(x4, v4.w());
+}
+
+void test_eigen2_smallvectors()
+{
+ for(int i = 0; i < g_repeat; i++) {
+ CALL_SUBTEST( smallVectors<int>() );
+ CALL_SUBTEST( smallVectors<float>() );
+ CALL_SUBTEST( smallVectors<double>() );
+ }
+}
diff --git a/test/eigen2/eigen2_sparse_basic.cpp b/test/eigen2/eigen2_sparse_basic.cpp
new file mode 100644
index 000000000..049077670
--- /dev/null
+++ b/test/eigen2/eigen2_sparse_basic.cpp
@@ -0,0 +1,317 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra. Eigen itself is part of the KDE project.
+//
+// Copyright (C) 2008 Daniel Gomez Ferro <dgomezferro@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 "sparse.h"
+
+template<typename SetterType,typename DenseType, typename Scalar, int Options>
+bool test_random_setter(SparseMatrix<Scalar,Options>& sm, const DenseType& ref, const std::vector<Vector2i>& nonzeroCoords)
+{
+ typedef SparseMatrix<Scalar,Options> SparseType;
+ {
+ sm.setZero();
+ SetterType w(sm);
+ std::vector<Vector2i> remaining = nonzeroCoords;
+ while(!remaining.empty())
+ {
+ int i = ei_random<int>(0,remaining.size()-1);
+ w(remaining[i].x(),remaining[i].y()) = ref.coeff(remaining[i].x(),remaining[i].y());
+ remaining[i] = remaining.back();
+ remaining.pop_back();
+ }
+ }
+ return sm.isApprox(ref);
+}
+
+template<typename SetterType,typename DenseType, typename T>
+bool test_random_setter(DynamicSparseMatrix<T>& sm, const DenseType& ref, const std::vector<Vector2i>& nonzeroCoords)
+{
+ sm.setZero();
+ std::vector<Vector2i> remaining = nonzeroCoords;
+ while(!remaining.empty())
+ {
+ int i = ei_random<int>(0,remaining.size()-1);
+ sm.coeffRef(remaining[i].x(),remaining[i].y()) = ref.coeff(remaining[i].x(),remaining[i].y());
+ remaining[i] = remaining.back();
+ remaining.pop_back();
+ }
+ return sm.isApprox(ref);
+}
+
+template<typename SparseMatrixType> void sparse_basic(const SparseMatrixType& ref)
+{
+ const int rows = ref.rows();
+ const int cols = ref.cols();
+ typedef typename SparseMatrixType::Scalar Scalar;
+ enum { Flags = SparseMatrixType::Flags };
+
+ double density = std::max(8./(rows*cols), 0.01);
+ typedef Matrix<Scalar,Dynamic,Dynamic> DenseMatrix;
+ typedef Matrix<Scalar,Dynamic,1> DenseVector;
+ Scalar eps = 1e-6;
+
+ SparseMatrixType m(rows, cols);
+ DenseMatrix refMat = DenseMatrix::Zero(rows, cols);
+ DenseVector vec1 = DenseVector::Random(rows);
+ Scalar s1 = ei_random<Scalar>();
+
+ std::vector<Vector2i> zeroCoords;
+ std::vector<Vector2i> nonzeroCoords;
+ initSparse<Scalar>(density, refMat, m, 0, &zeroCoords, &nonzeroCoords);
+
+ if (zeroCoords.size()==0 || nonzeroCoords.size()==0)
+ return;
+
+ // test coeff and coeffRef
+ for (int i=0; i<(int)zeroCoords.size(); ++i)
+ {
+ VERIFY_IS_MUCH_SMALLER_THAN( m.coeff(zeroCoords[i].x(),zeroCoords[i].y()), eps );
+ if(ei_is_same_type<SparseMatrixType,SparseMatrix<Scalar,Flags> >::ret)
+ VERIFY_RAISES_ASSERT( m.coeffRef(zeroCoords[0].x(),zeroCoords[0].y()) = 5 );
+ }
+ VERIFY_IS_APPROX(m, refMat);
+
+ m.coeffRef(nonzeroCoords[0].x(), nonzeroCoords[0].y()) = Scalar(5);
+ refMat.coeffRef(nonzeroCoords[0].x(), nonzeroCoords[0].y()) = Scalar(5);
+
+ VERIFY_IS_APPROX(m, refMat);
+ /*
+ // test InnerIterators and Block expressions
+ for (int t=0; t<10; ++t)
+ {
+ int j = ei_random<int>(0,cols-1);
+ int i = ei_random<int>(0,rows-1);
+ int w = ei_random<int>(1,cols-j-1);
+ int h = ei_random<int>(1,rows-i-1);
+
+// VERIFY_IS_APPROX(m.block(i,j,h,w), refMat.block(i,j,h,w));
+ for(int c=0; c<w; c++)
+ {
+ VERIFY_IS_APPROX(m.block(i,j,h,w).col(c), refMat.block(i,j,h,w).col(c));
+ for(int r=0; r<h; r++)
+ {
+// VERIFY_IS_APPROX(m.block(i,j,h,w).col(c).coeff(r), refMat.block(i,j,h,w).col(c).coeff(r));
+ }
+ }
+// for(int r=0; r<h; r++)
+// {
+// VERIFY_IS_APPROX(m.block(i,j,h,w).row(r), refMat.block(i,j,h,w).row(r));
+// for(int c=0; c<w; c++)
+// {
+// VERIFY_IS_APPROX(m.block(i,j,h,w).row(r).coeff(c), refMat.block(i,j,h,w).row(r).coeff(c));
+// }
+// }
+ }
+
+ for(int c=0; c<cols; c++)
+ {
+ VERIFY_IS_APPROX(m.col(c) + m.col(c), (m + m).col(c));
+ VERIFY_IS_APPROX(m.col(c) + m.col(c), refMat.col(c) + refMat.col(c));
+ }
+
+ for(int r=0; r<rows; r++)
+ {
+ VERIFY_IS_APPROX(m.row(r) + m.row(r), (m + m).row(r));
+ VERIFY_IS_APPROX(m.row(r) + m.row(r), refMat.row(r) + refMat.row(r));
+ }
+ */
+
+ // test SparseSetters
+ // coherent setter
+ // TODO extend the MatrixSetter
+// {
+// m.setZero();
+// VERIFY_IS_NOT_APPROX(m, refMat);
+// SparseSetter<SparseMatrixType, FullyCoherentAccessPattern> w(m);
+// for (int i=0; i<nonzeroCoords.size(); ++i)
+// {
+// w->coeffRef(nonzeroCoords[i].x(),nonzeroCoords[i].y()) = refMat.coeff(nonzeroCoords[i].x(),nonzeroCoords[i].y());
+// }
+// }
+// VERIFY_IS_APPROX(m, refMat);
+
+ // random setter
+// {
+// m.setZero();
+// VERIFY_IS_NOT_APPROX(m, refMat);
+// SparseSetter<SparseMatrixType, RandomAccessPattern> w(m);
+// std::vector<Vector2i> remaining = nonzeroCoords;
+// while(!remaining.empty())
+// {
+// int i = ei_random<int>(0,remaining.size()-1);
+// w->coeffRef(remaining[i].x(),remaining[i].y()) = refMat.coeff(remaining[i].x(),remaining[i].y());
+// remaining[i] = remaining.back();
+// remaining.pop_back();
+// }
+// }
+// VERIFY_IS_APPROX(m, refMat);
+
+ VERIFY(( test_random_setter<RandomSetter<SparseMatrixType, StdMapTraits> >(m,refMat,nonzeroCoords) ));
+ #ifdef EIGEN_UNORDERED_MAP_SUPPORT
+ VERIFY(( test_random_setter<RandomSetter<SparseMatrixType, StdUnorderedMapTraits> >(m,refMat,nonzeroCoords) ));
+ #endif
+ #ifdef _DENSE_HASH_MAP_H_
+ VERIFY(( test_random_setter<RandomSetter<SparseMatrixType, GoogleDenseHashMapTraits> >(m,refMat,nonzeroCoords) ));
+ #endif
+ #ifdef _SPARSE_HASH_MAP_H_
+ VERIFY(( test_random_setter<RandomSetter<SparseMatrixType, GoogleSparseHashMapTraits> >(m,refMat,nonzeroCoords) ));
+ #endif
+
+ // test fillrand
+ {
+ DenseMatrix m1(rows,cols);
+ m1.setZero();
+ SparseMatrixType m2(rows,cols);
+ m2.startFill();
+ for (int j=0; j<cols; ++j)
+ {
+ for (int k=0; k<rows/2; ++k)
+ {
+ int i = ei_random<int>(0,rows-1);
+ if (m1.coeff(i,j)==Scalar(0))
+ m2.fillrand(i,j) = m1(i,j) = ei_random<Scalar>();
+ }
+ }
+ m2.endFill();
+ VERIFY_IS_APPROX(m2,m1);
+ }
+
+ // test RandomSetter
+ /*{
+ SparseMatrixType m1(rows,cols), m2(rows,cols);
+ DenseMatrix refM1 = DenseMatrix::Zero(rows, rows);
+ initSparse<Scalar>(density, refM1, m1);
+ {
+ Eigen::RandomSetter<SparseMatrixType > setter(m2);
+ for (int j=0; j<m1.outerSize(); ++j)
+ for (typename SparseMatrixType::InnerIterator i(m1,j); i; ++i)
+ setter(i.index(), j) = i.value();
+ }
+ VERIFY_IS_APPROX(m1, m2);
+ }*/
+// std::cerr << m.transpose() << "\n\n" << refMat.transpose() << "\n\n";
+// VERIFY_IS_APPROX(m, refMat);
+
+ // test basic computations
+ {
+ DenseMatrix refM1 = DenseMatrix::Zero(rows, rows);
+ DenseMatrix refM2 = DenseMatrix::Zero(rows, rows);
+ DenseMatrix refM3 = DenseMatrix::Zero(rows, rows);
+ DenseMatrix refM4 = DenseMatrix::Zero(rows, rows);
+ SparseMatrixType m1(rows, rows);
+ SparseMatrixType m2(rows, rows);
+ SparseMatrixType m3(rows, rows);
+ SparseMatrixType m4(rows, rows);
+ initSparse<Scalar>(density, refM1, m1);
+ initSparse<Scalar>(density, refM2, m2);
+ initSparse<Scalar>(density, refM3, m3);
+ initSparse<Scalar>(density, refM4, m4);
+
+ VERIFY_IS_APPROX(m1+m2, refM1+refM2);
+ VERIFY_IS_APPROX(m1+m2+m3, refM1+refM2+refM3);
+ VERIFY_IS_APPROX(m3.cwise()*(m1+m2), refM3.cwise()*(refM1+refM2));
+ VERIFY_IS_APPROX(m1*s1-m2, refM1*s1-refM2);
+
+ VERIFY_IS_APPROX(m1*=s1, refM1*=s1);
+ VERIFY_IS_APPROX(m1/=s1, refM1/=s1);
+
+ VERIFY_IS_APPROX(m1+=m2, refM1+=refM2);
+ VERIFY_IS_APPROX(m1-=m2, refM1-=refM2);
+
+ VERIFY_IS_APPROX(m1.col(0).eigen2_dot(refM2.row(0)), refM1.col(0).eigen2_dot(refM2.row(0)));
+
+ refM4.setRandom();
+ // sparse cwise* dense
+ VERIFY_IS_APPROX(m3.cwise()*refM4, refM3.cwise()*refM4);
+// VERIFY_IS_APPROX(m3.cwise()/refM4, refM3.cwise()/refM4);
+ }
+
+ // test innerVector()
+ {
+ DenseMatrix refMat2 = DenseMatrix::Zero(rows, rows);
+ SparseMatrixType m2(rows, rows);
+ initSparse<Scalar>(density, refMat2, m2);
+ int j0 = ei_random(0,rows-1);
+ int j1 = ei_random(0,rows-1);
+ VERIFY_IS_APPROX(m2.innerVector(j0), refMat2.col(j0));
+ VERIFY_IS_APPROX(m2.innerVector(j0)+m2.innerVector(j1), refMat2.col(j0)+refMat2.col(j1));
+ //m2.innerVector(j0) = 2*m2.innerVector(j1);
+ //refMat2.col(j0) = 2*refMat2.col(j1);
+ //VERIFY_IS_APPROX(m2, refMat2);
+ }
+
+ // test innerVectors()
+ {
+ DenseMatrix refMat2 = DenseMatrix::Zero(rows, rows);
+ SparseMatrixType m2(rows, rows);
+ initSparse<Scalar>(density, refMat2, m2);
+ int j0 = ei_random(0,rows-2);
+ int j1 = ei_random(0,rows-2);
+ int n0 = ei_random<int>(1,rows-std::max(j0,j1));
+ VERIFY_IS_APPROX(m2.innerVectors(j0,n0), refMat2.block(0,j0,rows,n0));
+ VERIFY_IS_APPROX(m2.innerVectors(j0,n0)+m2.innerVectors(j1,n0),
+ refMat2.block(0,j0,rows,n0)+refMat2.block(0,j1,rows,n0));
+ //m2.innerVectors(j0,n0) = m2.innerVectors(j0,n0) + m2.innerVectors(j1,n0);
+ //refMat2.block(0,j0,rows,n0) = refMat2.block(0,j0,rows,n0) + refMat2.block(0,j1,rows,n0);
+ }
+
+ // test transpose
+ {
+ DenseMatrix refMat2 = DenseMatrix::Zero(rows, rows);
+ SparseMatrixType m2(rows, rows);
+ initSparse<Scalar>(density, refMat2, m2);
+ VERIFY_IS_APPROX(m2.transpose().eval(), refMat2.transpose().eval());
+ VERIFY_IS_APPROX(m2.transpose(), refMat2.transpose());
+ }
+
+ // test prune
+ {
+ SparseMatrixType m2(rows, rows);
+ DenseMatrix refM2(rows, rows);
+ refM2.setZero();
+ int countFalseNonZero = 0;
+ int countTrueNonZero = 0;
+ m2.startFill();
+ for (int j=0; j<m2.outerSize(); ++j)
+ for (int i=0; i<m2.innerSize(); ++i)
+ {
+ float x = ei_random<float>(0,1);
+ if (x<0.1)
+ {
+ // do nothing
+ }
+ else if (x<0.5)
+ {
+ countFalseNonZero++;
+ m2.fill(i,j) = Scalar(0);
+ }
+ else
+ {
+ countTrueNonZero++;
+ m2.fill(i,j) = refM2(i,j) = Scalar(1);
+ }
+ }
+ m2.endFill();
+ VERIFY(countFalseNonZero+countTrueNonZero == m2.nonZeros());
+ VERIFY_IS_APPROX(m2, refM2);
+ m2.prune(1);
+ VERIFY(countTrueNonZero==m2.nonZeros());
+ VERIFY_IS_APPROX(m2, refM2);
+ }
+}
+
+void test_eigen2_sparse_basic()
+{
+ for(int i = 0; i < g_repeat; i++) {
+ CALL_SUBTEST_1( sparse_basic(SparseMatrix<double>(8, 8)) );
+ CALL_SUBTEST_2( sparse_basic(SparseMatrix<std::complex<double> >(16, 16)) );
+ CALL_SUBTEST_1( sparse_basic(SparseMatrix<double>(33, 33)) );
+
+ CALL_SUBTEST_3( sparse_basic(DynamicSparseMatrix<double>(8, 8)) );
+ }
+}
diff --git a/test/eigen2/eigen2_sparse_product.cpp b/test/eigen2/eigen2_sparse_product.cpp
new file mode 100644
index 000000000..d28e76dff
--- /dev/null
+++ b/test/eigen2/eigen2_sparse_product.cpp
@@ -0,0 +1,115 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra. Eigen itself is part of the KDE project.
+//
+// Copyright (C) 2008 Daniel Gomez Ferro <dgomezferro@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 "sparse.h"
+
+template<typename SparseMatrixType> void sparse_product(const SparseMatrixType& ref)
+{
+ const int rows = ref.rows();
+ const int cols = ref.cols();
+ typedef typename SparseMatrixType::Scalar Scalar;
+ enum { Flags = SparseMatrixType::Flags };
+
+ double density = std::max(8./(rows*cols), 0.01);
+ typedef Matrix<Scalar,Dynamic,Dynamic> DenseMatrix;
+ typedef Matrix<Scalar,Dynamic,1> DenseVector;
+
+ // test matrix-matrix product
+ {
+ DenseMatrix refMat2 = DenseMatrix::Zero(rows, rows);
+ DenseMatrix refMat3 = DenseMatrix::Zero(rows, rows);
+ DenseMatrix refMat4 = DenseMatrix::Zero(rows, rows);
+ DenseMatrix dm4 = DenseMatrix::Zero(rows, rows);
+ SparseMatrixType m2(rows, rows);
+ SparseMatrixType m3(rows, rows);
+ SparseMatrixType m4(rows, rows);
+ initSparse<Scalar>(density, refMat2, m2);
+ initSparse<Scalar>(density, refMat3, m3);
+ initSparse<Scalar>(density, refMat4, m4);
+ VERIFY_IS_APPROX(m4=m2*m3, refMat4=refMat2*refMat3);
+ VERIFY_IS_APPROX(m4=m2.transpose()*m3, refMat4=refMat2.transpose()*refMat3);
+ VERIFY_IS_APPROX(m4=m2.transpose()*m3.transpose(), refMat4=refMat2.transpose()*refMat3.transpose());
+ VERIFY_IS_APPROX(m4=m2*m3.transpose(), refMat4=refMat2*refMat3.transpose());
+
+ // sparse * dense
+ VERIFY_IS_APPROX(dm4=m2*refMat3, refMat4=refMat2*refMat3);
+ VERIFY_IS_APPROX(dm4=m2*refMat3.transpose(), refMat4=refMat2*refMat3.transpose());
+ VERIFY_IS_APPROX(dm4=m2.transpose()*refMat3, refMat4=refMat2.transpose()*refMat3);
+ VERIFY_IS_APPROX(dm4=m2.transpose()*refMat3.transpose(), refMat4=refMat2.transpose()*refMat3.transpose());
+
+ // dense * sparse
+ VERIFY_IS_APPROX(dm4=refMat2*m3, refMat4=refMat2*refMat3);
+ VERIFY_IS_APPROX(dm4=refMat2*m3.transpose(), refMat4=refMat2*refMat3.transpose());
+ VERIFY_IS_APPROX(dm4=refMat2.transpose()*m3, refMat4=refMat2.transpose()*refMat3);
+ VERIFY_IS_APPROX(dm4=refMat2.transpose()*m3.transpose(), refMat4=refMat2.transpose()*refMat3.transpose());
+
+ VERIFY_IS_APPROX(m3=m3*m3, refMat3=refMat3*refMat3);
+ }
+
+ // test matrix - diagonal product
+ if(false) // it compiles, but the precision is terrible. probably doesn't matter in this branch....
+ {
+ DenseMatrix refM2 = DenseMatrix::Zero(rows, rows);
+ DenseMatrix refM3 = DenseMatrix::Zero(rows, rows);
+ DiagonalMatrix<DenseVector> d1(DenseVector::Random(rows));
+ SparseMatrixType m2(rows, rows);
+ SparseMatrixType m3(rows, rows);
+ initSparse<Scalar>(density, refM2, m2);
+ initSparse<Scalar>(density, refM3, m3);
+ VERIFY_IS_APPROX(m3=m2*d1, refM3=refM2*d1);
+ VERIFY_IS_APPROX(m3=m2.transpose()*d1, refM3=refM2.transpose()*d1);
+ VERIFY_IS_APPROX(m3=d1*m2, refM3=d1*refM2);
+ VERIFY_IS_APPROX(m3=d1*m2.transpose(), refM3=d1 * refM2.transpose());
+ }
+
+ // test self adjoint products
+ {
+ DenseMatrix b = DenseMatrix::Random(rows, rows);
+ DenseMatrix x = DenseMatrix::Random(rows, rows);
+ DenseMatrix refX = DenseMatrix::Random(rows, rows);
+ DenseMatrix refUp = DenseMatrix::Zero(rows, rows);
+ DenseMatrix refLo = DenseMatrix::Zero(rows, rows);
+ DenseMatrix refS = DenseMatrix::Zero(rows, rows);
+ SparseMatrixType mUp(rows, rows);
+ SparseMatrixType mLo(rows, rows);
+ SparseMatrixType mS(rows, rows);
+ do {
+ initSparse<Scalar>(density, refUp, mUp, ForceRealDiag|/*ForceNonZeroDiag|*/MakeUpperTriangular);
+ } while (refUp.isZero());
+ refLo = refUp.transpose().conjugate();
+ mLo = mUp.transpose().conjugate();
+ refS = refUp + refLo;
+ refS.diagonal() *= 0.5;
+ mS = mUp + mLo;
+ for (int k=0; k<mS.outerSize(); ++k)
+ for (typename SparseMatrixType::InnerIterator it(mS,k); it; ++it)
+ if (it.index() == k)
+ it.valueRef() *= 0.5;
+
+ VERIFY_IS_APPROX(refS.adjoint(), refS);
+ VERIFY_IS_APPROX(mS.transpose().conjugate(), mS);
+ VERIFY_IS_APPROX(mS, refS);
+ VERIFY_IS_APPROX(x=mS*b, refX=refS*b);
+ VERIFY_IS_APPROX(x=mUp.template marked<UpperTriangular|SelfAdjoint>()*b, refX=refS*b);
+ VERIFY_IS_APPROX(x=mLo.template marked<LowerTriangular|SelfAdjoint>()*b, refX=refS*b);
+ VERIFY_IS_APPROX(x=mS.template marked<SelfAdjoint>()*b, refX=refS*b);
+ }
+
+}
+
+void test_eigen2_sparse_product()
+{
+ for(int i = 0; i < g_repeat; i++) {
+ CALL_SUBTEST_1( sparse_product(SparseMatrix<double>(8, 8)) );
+ CALL_SUBTEST_2( sparse_product(SparseMatrix<std::complex<double> >(16, 16)) );
+ CALL_SUBTEST_1( sparse_product(SparseMatrix<double>(33, 33)) );
+
+ CALL_SUBTEST_3( sparse_product(DynamicSparseMatrix<double>(8, 8)) );
+ }
+}
diff --git a/test/eigen2/eigen2_sparse_solvers.cpp b/test/eigen2/eigen2_sparse_solvers.cpp
new file mode 100644
index 000000000..3aef27ab4
--- /dev/null
+++ b/test/eigen2/eigen2_sparse_solvers.cpp
@@ -0,0 +1,200 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra. Eigen itself is part of the KDE project.
+//
+// Copyright (C) 2008 Daniel Gomez Ferro <dgomezferro@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 "sparse.h"
+
+template<typename Scalar> void
+initSPD(double density,
+ Matrix<Scalar,Dynamic,Dynamic>& refMat,
+ SparseMatrix<Scalar>& sparseMat)
+{
+ Matrix<Scalar,Dynamic,Dynamic> aux(refMat.rows(),refMat.cols());
+ initSparse(density,refMat,sparseMat);
+ refMat = refMat * refMat.adjoint();
+ for (int k=0; k<2; ++k)
+ {
+ initSparse(density,aux,sparseMat,ForceNonZeroDiag);
+ refMat += aux * aux.adjoint();
+ }
+ sparseMat.startFill();
+ for (int j=0 ; j<sparseMat.cols(); ++j)
+ for (int i=j ; i<sparseMat.rows(); ++i)
+ if (refMat(i,j)!=Scalar(0))
+ sparseMat.fill(i,j) = refMat(i,j);
+ sparseMat.endFill();
+}
+
+template<typename Scalar> void sparse_solvers(int rows, int cols)
+{
+ double density = std::max(8./(rows*cols), 0.01);
+ typedef Matrix<Scalar,Dynamic,Dynamic> DenseMatrix;
+ typedef Matrix<Scalar,Dynamic,1> DenseVector;
+ // Scalar eps = 1e-6;
+
+ DenseVector vec1 = DenseVector::Random(rows);
+
+ std::vector<Vector2i> zeroCoords;
+ std::vector<Vector2i> nonzeroCoords;
+
+ // test triangular solver
+ {
+ DenseVector vec2 = vec1, vec3 = vec1;
+ SparseMatrix<Scalar> m2(rows, cols);
+ DenseMatrix refMat2 = DenseMatrix::Zero(rows, cols);
+
+ // lower
+ initSparse<Scalar>(density, refMat2, m2, ForceNonZeroDiag|MakeLowerTriangular, &zeroCoords, &nonzeroCoords);
+ VERIFY_IS_APPROX(refMat2.template marked<LowerTriangular>().solveTriangular(vec2),
+ m2.template marked<LowerTriangular>().solveTriangular(vec3));
+
+ // lower - transpose
+ initSparse<Scalar>(density, refMat2, m2, ForceNonZeroDiag|MakeLowerTriangular, &zeroCoords, &nonzeroCoords);
+ VERIFY_IS_APPROX(refMat2.template marked<LowerTriangular>().transpose().solveTriangular(vec2),
+ m2.template marked<LowerTriangular>().transpose().solveTriangular(vec3));
+
+ // upper
+ initSparse<Scalar>(density, refMat2, m2, ForceNonZeroDiag|MakeUpperTriangular, &zeroCoords, &nonzeroCoords);
+ VERIFY_IS_APPROX(refMat2.template marked<UpperTriangular>().solveTriangular(vec2),
+ m2.template marked<UpperTriangular>().solveTriangular(vec3));
+
+ // upper - transpose
+ initSparse<Scalar>(density, refMat2, m2, ForceNonZeroDiag|MakeUpperTriangular, &zeroCoords, &nonzeroCoords);
+ VERIFY_IS_APPROX(refMat2.template marked<UpperTriangular>().transpose().solveTriangular(vec2),
+ m2.template marked<UpperTriangular>().transpose().solveTriangular(vec3));
+ }
+
+ // test LLT
+ {
+ // TODO fix the issue with complex (see SparseLLT::solveInPlace)
+ SparseMatrix<Scalar> m2(rows, cols);
+ DenseMatrix refMat2(rows, cols);
+
+ DenseVector b = DenseVector::Random(cols);
+ DenseVector refX(cols), x(cols);
+
+ initSPD(density, refMat2, m2);
+
+ refMat2.llt().solve(b, &refX);
+ typedef SparseMatrix<Scalar,LowerTriangular|SelfAdjoint> SparseSelfAdjointMatrix;
+ if (!NumTraits<Scalar>::IsComplex)
+ {
+ x = b;
+ SparseLLT<SparseSelfAdjointMatrix> (m2).solveInPlace(x);
+ VERIFY(refX.isApprox(x,test_precision<Scalar>()) && "LLT: default");
+ }
+ #ifdef EIGEN_CHOLMOD_SUPPORT
+ x = b;
+ SparseLLT<SparseSelfAdjointMatrix,Cholmod>(m2).solveInPlace(x);
+ VERIFY(refX.isApprox(x,test_precision<Scalar>()) && "LLT: cholmod");
+ #endif
+ if (!NumTraits<Scalar>::IsComplex)
+ {
+ #ifdef EIGEN_TAUCS_SUPPORT
+ x = b;
+ SparseLLT<SparseSelfAdjointMatrix,Taucs>(m2,IncompleteFactorization).solveInPlace(x);
+ VERIFY(refX.isApprox(x,test_precision<Scalar>()) && "LLT: taucs (IncompleteFactorization)");
+ x = b;
+ SparseLLT<SparseSelfAdjointMatrix,Taucs>(m2,SupernodalMultifrontal).solveInPlace(x);
+ VERIFY(refX.isApprox(x,test_precision<Scalar>()) && "LLT: taucs (SupernodalMultifrontal)");
+ x = b;
+ SparseLLT<SparseSelfAdjointMatrix,Taucs>(m2,SupernodalLeftLooking).solveInPlace(x);
+ VERIFY(refX.isApprox(x,test_precision<Scalar>()) && "LLT: taucs (SupernodalLeftLooking)");
+ #endif
+ }
+ }
+
+ // test LDLT
+ if (!NumTraits<Scalar>::IsComplex)
+ {
+ // TODO fix the issue with complex (see SparseLDLT::solveInPlace)
+ SparseMatrix<Scalar> m2(rows, cols);
+ DenseMatrix refMat2(rows, cols);
+
+ DenseVector b = DenseVector::Random(cols);
+ DenseVector refX(cols), x(cols);
+
+ //initSPD(density, refMat2, m2);
+ initSparse<Scalar>(density, refMat2, m2, ForceNonZeroDiag|MakeUpperTriangular, 0, 0);
+ refMat2 += refMat2.adjoint();
+ refMat2.diagonal() *= 0.5;
+
+ refMat2.ldlt().solve(b, &refX);
+ typedef SparseMatrix<Scalar,UpperTriangular|SelfAdjoint> SparseSelfAdjointMatrix;
+ x = b;
+ SparseLDLT<SparseSelfAdjointMatrix> ldlt(m2);
+ if (ldlt.succeeded())
+ ldlt.solveInPlace(x);
+ VERIFY(refX.isApprox(x,test_precision<Scalar>()) && "LDLT: default");
+ }
+
+ // test LU
+ {
+ static int count = 0;
+ SparseMatrix<Scalar> m2(rows, cols);
+ DenseMatrix refMat2(rows, cols);
+
+ DenseVector b = DenseVector::Random(cols);
+ DenseVector refX(cols), x(cols);
+
+ initSparse<Scalar>(density, refMat2, m2, ForceNonZeroDiag, &zeroCoords, &nonzeroCoords);
+
+ LU<DenseMatrix> refLu(refMat2);
+ refLu.solve(b, &refX);
+ #if defined(EIGEN_SUPERLU_SUPPORT) || defined(EIGEN_UMFPACK_SUPPORT)
+ Scalar refDet = refLu.determinant();
+ #endif
+ x.setZero();
+ // // SparseLU<SparseMatrix<Scalar> > (m2).solve(b,&x);
+ // // VERIFY(refX.isApprox(x,test_precision<Scalar>()) && "LU: default");
+ #ifdef EIGEN_SUPERLU_SUPPORT
+ {
+ x.setZero();
+ SparseLU<SparseMatrix<Scalar>,SuperLU> slu(m2);
+ if (slu.succeeded())
+ {
+ if (slu.solve(b,&x)) {
+ VERIFY(refX.isApprox(x,test_precision<Scalar>()) && "LU: SuperLU");
+ }
+ // std::cerr << refDet << " == " << slu.determinant() << "\n";
+ if (count==0) {
+ VERIFY_IS_APPROX(refDet,slu.determinant()); // FIXME det is not very stable for complex
+ }
+ }
+ }
+ #endif
+ #ifdef EIGEN_UMFPACK_SUPPORT
+ {
+ // check solve
+ x.setZero();
+ SparseLU<SparseMatrix<Scalar>,UmfPack> slu(m2);
+ if (slu.succeeded()) {
+ if (slu.solve(b,&x)) {
+ if (count==0) {
+ VERIFY(refX.isApprox(x,test_precision<Scalar>()) && "LU: umfpack"); // FIXME solve is not very stable for complex
+ }
+ }
+ VERIFY_IS_APPROX(refDet,slu.determinant());
+ // TODO check the extracted data
+ //std::cerr << slu.matrixL() << "\n";
+ }
+ }
+ #endif
+ count++;
+ }
+
+}
+
+void test_eigen2_sparse_solvers()
+{
+ for(int i = 0; i < g_repeat; i++) {
+ CALL_SUBTEST_1( sparse_solvers<double>(8, 8) );
+ CALL_SUBTEST_2( sparse_solvers<std::complex<double> >(16, 16) );
+ CALL_SUBTEST_1( sparse_solvers<double>(101, 101) );
+ }
+}
diff --git a/test/eigen2/eigen2_sparse_vector.cpp b/test/eigen2/eigen2_sparse_vector.cpp
new file mode 100644
index 000000000..e6d2d77a1
--- /dev/null
+++ b/test/eigen2/eigen2_sparse_vector.cpp
@@ -0,0 +1,84 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra. Eigen itself is part of the KDE project.
+//
+// Copyright (C) 2008 Daniel Gomez Ferro <dgomezferro@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 "sparse.h"
+
+template<typename Scalar> void sparse_vector(int rows, int cols)
+{
+ double densityMat = std::max(8./(rows*cols), 0.01);
+ double densityVec = std::max(8./float(rows), 0.1);
+ typedef Matrix<Scalar,Dynamic,Dynamic> DenseMatrix;
+ typedef Matrix<Scalar,Dynamic,1> DenseVector;
+ typedef SparseVector<Scalar> SparseVectorType;
+ typedef SparseMatrix<Scalar> SparseMatrixType;
+ Scalar eps = 1e-6;
+
+ SparseMatrixType m1(rows,cols);
+ SparseVectorType v1(rows), v2(rows), v3(rows);
+ DenseMatrix refM1 = DenseMatrix::Zero(rows, cols);
+ DenseVector refV1 = DenseVector::Random(rows),
+ refV2 = DenseVector::Random(rows),
+ refV3 = DenseVector::Random(rows);
+
+ std::vector<int> zerocoords, nonzerocoords;
+ initSparse<Scalar>(densityVec, refV1, v1, &zerocoords, &nonzerocoords);
+ initSparse<Scalar>(densityMat, refM1, m1);
+
+ initSparse<Scalar>(densityVec, refV2, v2);
+ initSparse<Scalar>(densityVec, refV3, v3);
+
+ Scalar s1 = ei_random<Scalar>();
+
+ // test coeff and coeffRef
+ for (unsigned int i=0; i<zerocoords.size(); ++i)
+ {
+ VERIFY_IS_MUCH_SMALLER_THAN( v1.coeff(zerocoords[i]), eps );
+ //VERIFY_RAISES_ASSERT( v1.coeffRef(zerocoords[i]) = 5 );
+ }
+ {
+ VERIFY(int(nonzerocoords.size()) == v1.nonZeros());
+ int j=0;
+ for (typename SparseVectorType::InnerIterator it(v1); it; ++it,++j)
+ {
+ VERIFY(nonzerocoords[j]==it.index());
+ VERIFY(it.value()==v1.coeff(it.index()));
+ VERIFY(it.value()==refV1.coeff(it.index()));
+ }
+ }
+ VERIFY_IS_APPROX(v1, refV1);
+
+ v1.coeffRef(nonzerocoords[0]) = Scalar(5);
+ refV1.coeffRef(nonzerocoords[0]) = Scalar(5);
+ VERIFY_IS_APPROX(v1, refV1);
+
+ VERIFY_IS_APPROX(v1+v2, refV1+refV2);
+ VERIFY_IS_APPROX(v1+v2+v3, refV1+refV2+refV3);
+
+ VERIFY_IS_APPROX(v1*s1-v2, refV1*s1-refV2);
+
+ VERIFY_IS_APPROX(v1*=s1, refV1*=s1);
+ VERIFY_IS_APPROX(v1/=s1, refV1/=s1);
+
+ VERIFY_IS_APPROX(v1+=v2, refV1+=refV2);
+ VERIFY_IS_APPROX(v1-=v2, refV1-=refV2);
+
+ VERIFY_IS_APPROX(v1.eigen2_dot(v2), refV1.eigen2_dot(refV2));
+ VERIFY_IS_APPROX(v1.eigen2_dot(refV2), refV1.eigen2_dot(refV2));
+
+}
+
+void test_eigen2_sparse_vector()
+{
+ for(int i = 0; i < g_repeat; i++) {
+ CALL_SUBTEST_1( sparse_vector<double>(8, 8) );
+ CALL_SUBTEST_2( sparse_vector<std::complex<double> >(16, 16) );
+ CALL_SUBTEST_1( sparse_vector<double>(299, 535) );
+ }
+}
+
diff --git a/test/eigen2/eigen2_stdvector.cpp b/test/eigen2/eigen2_stdvector.cpp
new file mode 100644
index 000000000..6ab05c20a
--- /dev/null
+++ b/test/eigen2/eigen2_stdvector.cpp
@@ -0,0 +1,148 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra. Eigen itself is part of the KDE project.
+//
+// Copyright (C) 2008 Benoit Jacob <jacob.benoit.1@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 <Eigen/StdVector>
+#include "main.h"
+#include <Eigen/Geometry>
+
+template<typename MatrixType>
+void check_stdvector_matrix(const MatrixType& m)
+{
+ int rows = m.rows();
+ int cols = m.cols();
+ MatrixType x = MatrixType::Random(rows,cols), y = MatrixType::Random(rows,cols);
+ std::vector<MatrixType, aligned_allocator<MatrixType> > v(10, MatrixType(rows,cols)), w(20, y);
+ v[5] = x;
+ w[6] = v[5];
+ VERIFY_IS_APPROX(w[6], v[5]);
+ v = w;
+ for(int i = 0; i < 20; i++)
+ {
+ VERIFY_IS_APPROX(w[i], v[i]);
+ }
+
+ v.resize(21);
+ v[20] = x;
+ VERIFY_IS_APPROX(v[20], x);
+ v.resize(22,y);
+ VERIFY_IS_APPROX(v[21], y);
+ v.push_back(x);
+ VERIFY_IS_APPROX(v[22], x);
+ VERIFY((std::size_t)&(v[22]) == (std::size_t)&(v[21]) + sizeof(MatrixType));
+
+ // do a lot of push_back such that the vector gets internally resized
+ // (with memory reallocation)
+ MatrixType* ref = &w[0];
+ for(int i=0; i<30 || ((ref==&w[0]) && i<300); ++i)
+ v.push_back(w[i%w.size()]);
+ for(unsigned int i=23; i<v.size(); ++i)
+ {
+ VERIFY(v[i]==w[(i-23)%w.size()]);
+ }
+}
+
+template<typename TransformType>
+void check_stdvector_transform(const TransformType&)
+{
+ typedef typename TransformType::MatrixType MatrixType;
+ TransformType x(MatrixType::Random()), y(MatrixType::Random());
+ std::vector<TransformType, aligned_allocator<TransformType> > v(10), w(20, y);
+ v[5] = x;
+ w[6] = v[5];
+ VERIFY_IS_APPROX(w[6], v[5]);
+ v = w;
+ for(int i = 0; i < 20; i++)
+ {
+ VERIFY_IS_APPROX(w[i], v[i]);
+ }
+
+ v.resize(21);
+ v[20] = x;
+ VERIFY_IS_APPROX(v[20], x);
+ v.resize(22,y);
+ VERIFY_IS_APPROX(v[21], y);
+ v.push_back(x);
+ VERIFY_IS_APPROX(v[22], x);
+ VERIFY((std::size_t)&(v[22]) == (std::size_t)&(v[21]) + sizeof(TransformType));
+
+ // do a lot of push_back such that the vector gets internally resized
+ // (with memory reallocation)
+ TransformType* ref = &w[0];
+ for(int i=0; i<30 || ((ref==&w[0]) && i<300); ++i)
+ v.push_back(w[i%w.size()]);
+ for(unsigned int i=23; i<v.size(); ++i)
+ {
+ VERIFY(v[i].matrix()==w[(i-23)%w.size()].matrix());
+ }
+}
+
+template<typename QuaternionType>
+void check_stdvector_quaternion(const QuaternionType&)
+{
+ typedef typename QuaternionType::Coefficients Coefficients;
+ QuaternionType x(Coefficients::Random()), y(Coefficients::Random());
+ std::vector<QuaternionType, aligned_allocator<QuaternionType> > v(10), w(20, y);
+ v[5] = x;
+ w[6] = v[5];
+ VERIFY_IS_APPROX(w[6], v[5]);
+ v = w;
+ for(int i = 0; i < 20; i++)
+ {
+ VERIFY_IS_APPROX(w[i], v[i]);
+ }
+
+ v.resize(21);
+ v[20] = x;
+ VERIFY_IS_APPROX(v[20], x);
+ v.resize(22,y);
+ VERIFY_IS_APPROX(v[21], y);
+ v.push_back(x);
+ VERIFY_IS_APPROX(v[22], x);
+ VERIFY((std::size_t)&(v[22]) == (std::size_t)&(v[21]) + sizeof(QuaternionType));
+
+ // do a lot of push_back such that the vector gets internally resized
+ // (with memory reallocation)
+ QuaternionType* ref = &w[0];
+ for(int i=0; i<30 || ((ref==&w[0]) && i<300); ++i)
+ v.push_back(w[i%w.size()]);
+ for(unsigned int i=23; i<v.size(); ++i)
+ {
+ VERIFY(v[i].coeffs()==w[(i-23)%w.size()].coeffs());
+ }
+}
+
+void test_eigen2_stdvector()
+{
+ // some non vectorizable fixed sizes
+ CALL_SUBTEST_1(check_stdvector_matrix(Vector2f()));
+ CALL_SUBTEST_1(check_stdvector_matrix(Matrix3f()));
+ CALL_SUBTEST_1(check_stdvector_matrix(Matrix3d()));
+
+ // some vectorizable fixed sizes
+ CALL_SUBTEST_2(check_stdvector_matrix(Matrix2f()));
+ CALL_SUBTEST_2(check_stdvector_matrix(Vector4f()));
+ CALL_SUBTEST_2(check_stdvector_matrix(Matrix4f()));
+ CALL_SUBTEST_2(check_stdvector_matrix(Matrix4d()));
+
+ // some dynamic sizes
+ CALL_SUBTEST_3(check_stdvector_matrix(MatrixXd(1,1)));
+ CALL_SUBTEST_3(check_stdvector_matrix(VectorXd(20)));
+ CALL_SUBTEST_3(check_stdvector_matrix(RowVectorXf(20)));
+ CALL_SUBTEST_3(check_stdvector_matrix(MatrixXcf(10,10)));
+
+ // some Transform
+ CALL_SUBTEST_4(check_stdvector_transform(Transform2f()));
+ CALL_SUBTEST_4(check_stdvector_transform(Transform3f()));
+ CALL_SUBTEST_4(check_stdvector_transform(Transform3d()));
+ //CALL_SUBTEST_4(check_stdvector_transform(Transform4d()));
+
+ // some Quaternion
+ CALL_SUBTEST_5(check_stdvector_quaternion(Quaternionf()));
+ CALL_SUBTEST_5(check_stdvector_quaternion(Quaternionf()));
+}
diff --git a/test/eigen2/eigen2_submatrices.cpp b/test/eigen2/eigen2_submatrices.cpp
new file mode 100644
index 000000000..c5d3f243d
--- /dev/null
+++ b/test/eigen2/eigen2_submatrices.cpp
@@ -0,0 +1,148 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra. Eigen itself is part of the KDE project.
+//
+// Copyright (C) 2006-2008 Benoit Jacob <jacob.benoit.1@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 "main.h"
+
+// check minor separately in order to avoid the possible creation of a zero-sized
+// array. Comes from a compilation error with gcc-3.4 or gcc-4 with -ansi -pedantic.
+// Another solution would be to declare the array like this: T m_data[Size==0?1:Size]; in ei_matrix_storage
+// but this is probably not bad to raise such an error at compile time...
+template<typename Scalar, int _Rows, int _Cols> struct CheckMinor
+{
+ typedef Matrix<Scalar, _Rows, _Cols> MatrixType;
+ CheckMinor(MatrixType& m1, int r1, int c1)
+ {
+ int rows = m1.rows();
+ int cols = m1.cols();
+
+ Matrix<Scalar, Dynamic, Dynamic> mi = m1.minor(0,0).eval();
+ VERIFY_IS_APPROX(mi, m1.block(1,1,rows-1,cols-1));
+ mi = m1.minor(r1,c1);
+ VERIFY_IS_APPROX(mi.transpose(), m1.transpose().minor(c1,r1));
+ //check operator(), both constant and non-constant, on minor()
+ m1.minor(r1,c1)(0,0) = m1.minor(0,0)(0,0);
+ }
+};
+
+template<typename Scalar> struct CheckMinor<Scalar,1,1>
+{
+ typedef Matrix<Scalar, 1, 1> MatrixType;
+ CheckMinor(MatrixType&, int, int) {}
+};
+
+template<typename MatrixType> void submatrices(const MatrixType& m)
+{
+ /* this test covers the following files:
+ Row.h Column.h Block.h Minor.h DiagonalCoeffs.h
+ */
+ typedef typename MatrixType::Scalar Scalar;
+ typedef typename MatrixType::RealScalar RealScalar;
+ typedef Matrix<Scalar, MatrixType::RowsAtCompileTime, 1> VectorType;
+ typedef Matrix<Scalar, 1, MatrixType::ColsAtCompileTime> RowVectorType;
+ int rows = m.rows();
+ int cols = m.cols();
+
+ MatrixType m1 = MatrixType::Random(rows, cols),
+ m2 = MatrixType::Random(rows, cols),
+ m3(rows, cols),
+ mzero = MatrixType::Zero(rows, cols),
+ ones = MatrixType::Ones(rows, cols),
+ identity = Matrix<Scalar, MatrixType::RowsAtCompileTime, MatrixType::RowsAtCompileTime>
+ ::Identity(rows, rows),
+ square = Matrix<Scalar, MatrixType::RowsAtCompileTime, MatrixType::RowsAtCompileTime>
+ ::Random(rows, rows);
+ VectorType v1 = VectorType::Random(rows),
+ v2 = VectorType::Random(rows),
+ v3 = VectorType::Random(rows),
+ vzero = VectorType::Zero(rows);
+
+ Scalar s1 = ei_random<Scalar>();
+
+ int r1 = ei_random<int>(0,rows-1);
+ int r2 = ei_random<int>(r1,rows-1);
+ int c1 = ei_random<int>(0,cols-1);
+ int c2 = ei_random<int>(c1,cols-1);
+
+ //check row() and col()
+ VERIFY_IS_APPROX(m1.col(c1).transpose(), m1.transpose().row(c1));
+ VERIFY_IS_APPROX(square.row(r1).eigen2_dot(m1.col(c1)), (square.lazy() * m1.conjugate())(r1,c1));
+ //check operator(), both constant and non-constant, on row() and col()
+ m1.row(r1) += s1 * m1.row(r2);
+ m1.col(c1) += s1 * m1.col(c2);
+
+ //check block()
+ Matrix<Scalar,Dynamic,Dynamic> b1(1,1); b1(0,0) = m1(r1,c1);
+ RowVectorType br1(m1.block(r1,0,1,cols));
+ VectorType bc1(m1.block(0,c1,rows,1));
+ VERIFY_IS_APPROX(b1, m1.block(r1,c1,1,1));
+ VERIFY_IS_APPROX(m1.row(r1), br1);
+ VERIFY_IS_APPROX(m1.col(c1), bc1);
+ //check operator(), both constant and non-constant, on block()
+ m1.block(r1,c1,r2-r1+1,c2-c1+1) = s1 * m2.block(0, 0, r2-r1+1,c2-c1+1);
+ m1.block(r1,c1,r2-r1+1,c2-c1+1)(r2-r1,c2-c1) = m2.block(0, 0, r2-r1+1,c2-c1+1)(0,0);
+
+ //check minor()
+ CheckMinor<Scalar, MatrixType::RowsAtCompileTime, MatrixType::ColsAtCompileTime> checkminor(m1,r1,c1);
+
+ //check diagonal()
+ VERIFY_IS_APPROX(m1.diagonal(), m1.transpose().diagonal());
+ m2.diagonal() = 2 * m1.diagonal();
+ m2.diagonal()[0] *= 3;
+ VERIFY_IS_APPROX(m2.diagonal()[0], static_cast<Scalar>(6) * m1.diagonal()[0]);
+
+ enum {
+ BlockRows = EIGEN_SIZE_MIN_PREFER_FIXED(MatrixType::RowsAtCompileTime,2),
+ BlockCols = EIGEN_SIZE_MIN_PREFER_FIXED(MatrixType::ColsAtCompileTime,5)
+ };
+ if (rows>=5 && cols>=8)
+ {
+ // test fixed block() as lvalue
+ m1.template block<BlockRows,BlockCols>(1,1) *= s1;
+ // test operator() on fixed block() both as constant and non-constant
+ m1.template block<BlockRows,BlockCols>(1,1)(0, 3) = m1.template block<2,5>(1,1)(1,2);
+ // check that fixed block() and block() agree
+ Matrix<Scalar,Dynamic,Dynamic> b = m1.template block<BlockRows,BlockCols>(3,3);
+ VERIFY_IS_APPROX(b, m1.block(3,3,BlockRows,BlockCols));
+ }
+
+ if (rows>2)
+ {
+ // test sub vectors
+ VERIFY_IS_APPROX(v1.template start<2>(), v1.block(0,0,2,1));
+ VERIFY_IS_APPROX(v1.template start<2>(), v1.start(2));
+ VERIFY_IS_APPROX(v1.template start<2>(), v1.segment(0,2));
+ VERIFY_IS_APPROX(v1.template start<2>(), v1.template segment<2>(0));
+ int i = rows-2;
+ VERIFY_IS_APPROX(v1.template end<2>(), v1.block(i,0,2,1));
+ VERIFY_IS_APPROX(v1.template end<2>(), v1.end(2));
+ VERIFY_IS_APPROX(v1.template end<2>(), v1.segment(i,2));
+ VERIFY_IS_APPROX(v1.template end<2>(), v1.template segment<2>(i));
+ i = ei_random(0,rows-2);
+ VERIFY_IS_APPROX(v1.segment(i,2), v1.template segment<2>(i));
+ }
+
+ // stress some basic stuffs with block matrices
+ VERIFY(ei_real(ones.col(c1).sum()) == RealScalar(rows));
+ VERIFY(ei_real(ones.row(r1).sum()) == RealScalar(cols));
+
+ VERIFY(ei_real(ones.col(c1).eigen2_dot(ones.col(c2))) == RealScalar(rows));
+ VERIFY(ei_real(ones.row(r1).eigen2_dot(ones.row(r2))) == RealScalar(cols));
+}
+
+void test_eigen2_submatrices()
+{
+ for(int i = 0; i < g_repeat; i++) {
+ CALL_SUBTEST_1( submatrices(Matrix<float, 1, 1>()) );
+ CALL_SUBTEST_2( submatrices(Matrix4d()) );
+ CALL_SUBTEST_3( submatrices(MatrixXcf(3, 3)) );
+ CALL_SUBTEST_4( submatrices(MatrixXi(8, 12)) );
+ CALL_SUBTEST_5( submatrices(MatrixXcd(20, 20)) );
+ CALL_SUBTEST_6( submatrices(MatrixXf(20, 20)) );
+ }
+}
diff --git a/test/eigen2/eigen2_sum.cpp b/test/eigen2/eigen2_sum.cpp
new file mode 100644
index 000000000..b47057caa
--- /dev/null
+++ b/test/eigen2/eigen2_sum.cpp
@@ -0,0 +1,71 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra. Eigen itself is part of the KDE project.
+//
+// Copyright (C) 2008 Benoit Jacob <jacob.benoit.1@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 "main.h"
+
+template<typename MatrixType> void matrixSum(const MatrixType& m)
+{
+ typedef typename MatrixType::Scalar Scalar;
+
+ int rows = m.rows();
+ int cols = m.cols();
+
+ MatrixType m1 = MatrixType::Random(rows, cols);
+
+ VERIFY_IS_MUCH_SMALLER_THAN(MatrixType::Zero(rows, cols).sum(), Scalar(1));
+ VERIFY_IS_APPROX(MatrixType::Ones(rows, cols).sum(), Scalar(float(rows*cols))); // the float() here to shut up excessive MSVC warning about int->complex conversion being lossy
+ Scalar x = Scalar(0);
+ for(int i = 0; i < rows; i++) for(int j = 0; j < cols; j++) x += m1(i,j);
+ VERIFY_IS_APPROX(m1.sum(), x);
+}
+
+template<typename VectorType> void vectorSum(const VectorType& w)
+{
+ typedef typename VectorType::Scalar Scalar;
+ int size = w.size();
+
+ VectorType v = VectorType::Random(size);
+ for(int i = 1; i < size; i++)
+ {
+ Scalar s = Scalar(0);
+ for(int j = 0; j < i; j++) s += v[j];
+ VERIFY_IS_APPROX(s, v.start(i).sum());
+ }
+
+ for(int i = 0; i < size-1; i++)
+ {
+ Scalar s = Scalar(0);
+ for(int j = i; j < size; j++) s += v[j];
+ VERIFY_IS_APPROX(s, v.end(size-i).sum());
+ }
+
+ for(int i = 0; i < size/2; i++)
+ {
+ Scalar s = Scalar(0);
+ for(int j = i; j < size-i; j++) s += v[j];
+ VERIFY_IS_APPROX(s, v.segment(i, size-2*i).sum());
+ }
+}
+
+void test_eigen2_sum()
+{
+ for(int i = 0; i < g_repeat; i++) {
+ CALL_SUBTEST_1( matrixSum(Matrix<float, 1, 1>()) );
+ CALL_SUBTEST_2( matrixSum(Matrix2f()) );
+ CALL_SUBTEST_3( matrixSum(Matrix4d()) );
+ CALL_SUBTEST_4( matrixSum(MatrixXcf(3, 3)) );
+ CALL_SUBTEST_5( matrixSum(MatrixXf(8, 12)) );
+ CALL_SUBTEST_6( matrixSum(MatrixXi(8, 12)) );
+ }
+ for(int i = 0; i < g_repeat; i++) {
+ CALL_SUBTEST_5( vectorSum(VectorXf(5)) );
+ CALL_SUBTEST_7( vectorSum(VectorXd(10)) );
+ CALL_SUBTEST_5( vectorSum(VectorXf(33)) );
+ }
+}
diff --git a/test/eigen2/eigen2_svd.cpp b/test/eigen2/eigen2_svd.cpp
new file mode 100644
index 000000000..d4689a56f
--- /dev/null
+++ b/test/eigen2/eigen2_svd.cpp
@@ -0,0 +1,87 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra. Eigen itself is part of the KDE project.
+//
+// Copyright (C) 2008 Gael Guennebaud <g.gael@free.fr>
+//
+// This Source Code Form is subject to the terms of the Mozilla
+// Public License v. 2.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 "main.h"
+#include <Eigen/SVD>
+
+template<typename MatrixType> void svd(const MatrixType& m)
+{
+ /* this test covers the following files:
+ SVD.h
+ */
+ int rows = m.rows();
+ int cols = m.cols();
+
+ typedef typename MatrixType::Scalar Scalar;
+ typedef typename NumTraits<Scalar>::Real RealScalar;
+ MatrixType a = MatrixType::Random(rows,cols);
+ Matrix<Scalar, MatrixType::RowsAtCompileTime, 1> b =
+ Matrix<Scalar, MatrixType::RowsAtCompileTime, 1>::Random(rows,1);
+ Matrix<Scalar, MatrixType::ColsAtCompileTime, 1> x(cols,1), x2(cols,1);
+
+ RealScalar largerEps = test_precision<RealScalar>();
+ if (ei_is_same_type<RealScalar,float>::ret)
+ largerEps = 1e-3f;
+
+ {
+ SVD<MatrixType> svd(a);
+ MatrixType sigma = MatrixType::Zero(rows,cols);
+ MatrixType matU = MatrixType::Zero(rows,rows);
+ sigma.block(0,0,cols,cols) = svd.singularValues().asDiagonal();
+ matU.block(0,0,rows,cols) = svd.matrixU();
+ VERIFY_IS_APPROX(a, matU * sigma * svd.matrixV().transpose());
+ }
+
+
+ if (rows==cols)
+ {
+ if (ei_is_same_type<RealScalar,float>::ret)
+ {
+ MatrixType a1 = MatrixType::Random(rows,cols);
+ a += a * a.adjoint() + a1 * a1.adjoint();
+ }
+ SVD<MatrixType> svd(a);
+ svd.solve(b, &x);
+ VERIFY_IS_APPROX(a * x,b);
+ }
+
+
+ if(rows==cols)
+ {
+ SVD<MatrixType> svd(a);
+ MatrixType unitary, positive;
+ svd.computeUnitaryPositive(&unitary, &positive);
+ VERIFY_IS_APPROX(unitary * unitary.adjoint(), MatrixType::Identity(unitary.rows(),unitary.rows()));
+ VERIFY_IS_APPROX(positive, positive.adjoint());
+ for(int i = 0; i < rows; i++) VERIFY(positive.diagonal()[i] >= 0); // cheap necessary (not sufficient) condition for positivity
+ VERIFY_IS_APPROX(unitary*positive, a);
+
+ svd.computePositiveUnitary(&positive, &unitary);
+ VERIFY_IS_APPROX(unitary * unitary.adjoint(), MatrixType::Identity(unitary.rows(),unitary.rows()));
+ VERIFY_IS_APPROX(positive, positive.adjoint());
+ for(int i = 0; i < rows; i++) VERIFY(positive.diagonal()[i] >= 0); // cheap necessary (not sufficient) condition for positivity
+ VERIFY_IS_APPROX(positive*unitary, a);
+ }
+}
+
+void test_eigen2_svd()
+{
+ for(int i = 0; i < g_repeat; i++) {
+ CALL_SUBTEST_1( svd(Matrix3f()) );
+ CALL_SUBTEST_2( svd(Matrix4d()) );
+ CALL_SUBTEST_3( svd(MatrixXf(7,7)) );
+ CALL_SUBTEST_4( svd(MatrixXd(14,7)) );
+ // complex are not implemented yet
+// CALL_SUBTEST( svd(MatrixXcd(6,6)) );
+// CALL_SUBTEST( svd(MatrixXcf(3,3)) );
+ SVD<MatrixXf> s;
+ MatrixXf m = MatrixXf::Random(10,1);
+ s.compute(m);
+ }
+}
diff --git a/test/eigen2/eigen2_swap.cpp b/test/eigen2/eigen2_swap.cpp
new file mode 100644
index 000000000..f3a8846d9
--- /dev/null
+++ b/test/eigen2/eigen2_swap.cpp
@@ -0,0 +1,83 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra.
+//
+// Copyright (C) 2009 Benoit Jacob <jacob.benoit.1@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/.
+
+#define EIGEN_NO_STATIC_ASSERT
+#include "main.h"
+
+template<typename T>
+struct other_matrix_type
+{
+ typedef int type;
+};
+
+template<typename _Scalar, int _Rows, int _Cols, int _Options, int _MaxRows, int _MaxCols>
+struct other_matrix_type<Matrix<_Scalar, _Rows, _Cols, _Options, _MaxRows, _MaxCols> >
+{
+ typedef Matrix<_Scalar, _Rows, _Cols, _Options^RowMajor, _MaxRows, _MaxCols> type;
+};
+
+template<typename MatrixType> void swap(const MatrixType& m)
+{
+ typedef typename other_matrix_type<MatrixType>::type OtherMatrixType;
+ typedef typename MatrixType::Scalar Scalar;
+
+ ei_assert((!ei_is_same_type<MatrixType,OtherMatrixType>::ret));
+ int rows = m.rows();
+ int cols = m.cols();
+
+ // construct 3 matrix guaranteed to be distinct
+ MatrixType m1 = MatrixType::Random(rows,cols);
+ MatrixType m2 = MatrixType::Random(rows,cols) + Scalar(100) * MatrixType::Identity(rows,cols);
+ OtherMatrixType m3 = OtherMatrixType::Random(rows,cols) + Scalar(200) * OtherMatrixType::Identity(rows,cols);
+
+ MatrixType m1_copy = m1;
+ MatrixType m2_copy = m2;
+ OtherMatrixType m3_copy = m3;
+
+ // test swapping 2 matrices of same type
+ m1.swap(m2);
+ VERIFY_IS_APPROX(m1,m2_copy);
+ VERIFY_IS_APPROX(m2,m1_copy);
+ m1 = m1_copy;
+ m2 = m2_copy;
+
+ // test swapping 2 matrices of different types
+ m1.swap(m3);
+ VERIFY_IS_APPROX(m1,m3_copy);
+ VERIFY_IS_APPROX(m3,m1_copy);
+ m1 = m1_copy;
+ m3 = m3_copy;
+
+ // test swapping matrix with expression
+ m1.swap(m2.block(0,0,rows,cols));
+ VERIFY_IS_APPROX(m1,m2_copy);
+ VERIFY_IS_APPROX(m2,m1_copy);
+ m1 = m1_copy;
+ m2 = m2_copy;
+
+ // test swapping two expressions of different types
+ m1.transpose().swap(m3.transpose());
+ VERIFY_IS_APPROX(m1,m3_copy);
+ VERIFY_IS_APPROX(m3,m1_copy);
+ m1 = m1_copy;
+ m3 = m3_copy;
+
+ // test assertion on mismatching size -- matrix case
+ VERIFY_RAISES_ASSERT(m1.swap(m1.row(0)));
+ // test assertion on mismatching size -- xpr case
+ VERIFY_RAISES_ASSERT(m1.row(0).swap(m1));
+}
+
+void test_eigen2_swap()
+{
+ CALL_SUBTEST_1( swap(Matrix3f()) ); // fixed size, no vectorization
+ CALL_SUBTEST_1( swap(Matrix4d()) ); // fixed size, possible vectorization
+ CALL_SUBTEST_1( swap(MatrixXd(3,3)) ); // dyn size, no vectorization
+ CALL_SUBTEST_1( swap(MatrixXf(30,30)) ); // dyn size, possible vectorization
+}
diff --git a/test/eigen2/eigen2_triangular.cpp b/test/eigen2/eigen2_triangular.cpp
new file mode 100644
index 000000000..3748c7d71
--- /dev/null
+++ b/test/eigen2/eigen2_triangular.cpp
@@ -0,0 +1,158 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra. Eigen itself is part of the KDE project.
+//
+// Copyright (C) 2008 Gael Guennebaud <gael.guennebaud@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 "main.h"
+
+template<typename MatrixType> void triangular(const MatrixType& m)
+{
+ typedef typename MatrixType::Scalar Scalar;
+ typedef typename NumTraits<Scalar>::Real RealScalar;
+ typedef Matrix<Scalar, MatrixType::RowsAtCompileTime, 1> VectorType;
+
+ RealScalar largerEps = 10*test_precision<RealScalar>();
+
+ int rows = m.rows();
+ int cols = m.cols();
+
+ MatrixType m1 = MatrixType::Random(rows, cols),
+ m2 = MatrixType::Random(rows, cols),
+ m3(rows, cols),
+ m4(rows, cols),
+ r1(rows, cols),
+ r2(rows, cols),
+ mzero = MatrixType::Zero(rows, cols),
+ mones = MatrixType::Ones(rows, cols),
+ identity = Matrix<Scalar, MatrixType::RowsAtCompileTime, MatrixType::RowsAtCompileTime>
+ ::Identity(rows, rows),
+ square = Matrix<Scalar, MatrixType::RowsAtCompileTime, MatrixType::RowsAtCompileTime>
+ ::Random(rows, rows);
+ VectorType v1 = VectorType::Random(rows),
+ v2 = VectorType::Random(rows),
+ vzero = VectorType::Zero(rows);
+
+ MatrixType m1up = m1.template part<Eigen::UpperTriangular>();
+ MatrixType m2up = m2.template part<Eigen::UpperTriangular>();
+
+ if (rows*cols>1)
+ {
+ VERIFY(m1up.isUpperTriangular());
+ VERIFY(m2up.transpose().isLowerTriangular());
+ VERIFY(!m2.isLowerTriangular());
+ }
+
+// VERIFY_IS_APPROX(m1up.transpose() * m2, m1.upper().transpose().lower() * m2);
+
+ // test overloaded operator+=
+ r1.setZero();
+ r2.setZero();
+ r1.template part<Eigen::UpperTriangular>() += m1;
+ r2 += m1up;
+ VERIFY_IS_APPROX(r1,r2);
+
+ // test overloaded operator=
+ m1.setZero();
+ m1.template part<Eigen::UpperTriangular>() = (m2.transpose() * m2).lazy();
+ m3 = m2.transpose() * m2;
+ VERIFY_IS_APPROX(m3.template part<Eigen::LowerTriangular>().transpose(), m1);
+
+ // test overloaded operator=
+ m1.setZero();
+ m1.template part<Eigen::LowerTriangular>() = (m2.transpose() * m2).lazy();
+ VERIFY_IS_APPROX(m3.template part<Eigen::LowerTriangular>(), m1);
+
+ VERIFY_IS_APPROX(m3.template part<Diagonal>(), m3.diagonal().asDiagonal());
+
+ m1 = MatrixType::Random(rows, cols);
+ for (int i=0; i<rows; ++i)
+ while (ei_abs2(m1(i,i))<1e-3) m1(i,i) = ei_random<Scalar>();
+
+ Transpose<MatrixType> trm4(m4);
+ // test back and forward subsitution
+ m3 = m1.template part<Eigen::LowerTriangular>();
+ VERIFY(m3.template marked<Eigen::LowerTriangular>().solveTriangular(m3).cwise().abs().isIdentity(test_precision<RealScalar>()));
+ VERIFY(m3.transpose().template marked<Eigen::UpperTriangular>()
+ .solveTriangular(m3.transpose()).cwise().abs().isIdentity(test_precision<RealScalar>()));
+ // check M * inv(L) using in place API
+ m4 = m3;
+ m3.transpose().template marked<Eigen::UpperTriangular>().solveTriangularInPlace(trm4);
+ VERIFY(m4.cwise().abs().isIdentity(test_precision<RealScalar>()));
+
+ m3 = m1.template part<Eigen::UpperTriangular>();
+ VERIFY(m3.template marked<Eigen::UpperTriangular>().solveTriangular(m3).cwise().abs().isIdentity(test_precision<RealScalar>()));
+ VERIFY(m3.transpose().template marked<Eigen::LowerTriangular>()
+ .solveTriangular(m3.transpose()).cwise().abs().isIdentity(test_precision<RealScalar>()));
+ // check M * inv(U) using in place API
+ m4 = m3;
+ m3.transpose().template marked<Eigen::LowerTriangular>().solveTriangularInPlace(trm4);
+ VERIFY(m4.cwise().abs().isIdentity(test_precision<RealScalar>()));
+
+ m3 = m1.template part<Eigen::UpperTriangular>();
+ VERIFY(m2.isApprox(m3 * (m3.template marked<Eigen::UpperTriangular>().solveTriangular(m2)), largerEps));
+ m3 = m1.template part<Eigen::LowerTriangular>();
+ VERIFY(m2.isApprox(m3 * (m3.template marked<Eigen::LowerTriangular>().solveTriangular(m2)), largerEps));
+
+ VERIFY((m1.template part<Eigen::UpperTriangular>() * m2.template part<Eigen::UpperTriangular>()).isUpperTriangular());
+
+ // test swap
+ m1.setOnes();
+ m2.setZero();
+ m2.template part<Eigen::UpperTriangular>().swap(m1);
+ m3.setZero();
+ m3.template part<Eigen::UpperTriangular>().setOnes();
+ VERIFY_IS_APPROX(m2,m3);
+
+}
+
+void selfadjoint()
+{
+ Matrix2i m;
+ m << 1, 2,
+ 3, 4;
+
+ Matrix2i m1 = Matrix2i::Zero();
+ m1.part<SelfAdjoint>() = m;
+ Matrix2i ref1;
+ ref1 << 1, 2,
+ 2, 4;
+ VERIFY(m1 == ref1);
+
+ Matrix2i m2 = Matrix2i::Zero();
+ m2.part<SelfAdjoint>() = m.part<UpperTriangular>();
+ Matrix2i ref2;
+ ref2 << 1, 2,
+ 2, 4;
+ VERIFY(m2 == ref2);
+
+ Matrix2i m3 = Matrix2i::Zero();
+ m3.part<SelfAdjoint>() = m.part<LowerTriangular>();
+ Matrix2i ref3;
+ ref3 << 1, 0,
+ 0, 4;
+ VERIFY(m3 == ref3);
+
+ // example inspired from bug 159
+ int array[] = {1, 2, 3, 4};
+ Matrix2i::Map(array).part<SelfAdjoint>() = Matrix2i::Random().part<LowerTriangular>();
+
+ std::cout << "hello\n" << array << std::endl;
+}
+
+void test_eigen2_triangular()
+{
+ CALL_SUBTEST_8( selfadjoint() );
+ for(int i = 0; i < g_repeat ; i++) {
+ CALL_SUBTEST_1( triangular(Matrix<float, 1, 1>()) );
+ CALL_SUBTEST_2( triangular(Matrix<float, 2, 2>()) );
+ CALL_SUBTEST_3( triangular(Matrix3d()) );
+ CALL_SUBTEST_4( triangular(MatrixXcf(4, 4)) );
+ CALL_SUBTEST_5( triangular(Matrix<std::complex<float>,8, 8>()) );
+ CALL_SUBTEST_6( triangular(MatrixXd(17,17)) );
+ CALL_SUBTEST_7( triangular(Matrix<float,Dynamic,Dynamic,RowMajor>(5, 5)) );
+ }
+}
diff --git a/test/eigen2/eigen2_unalignedassert.cpp b/test/eigen2/eigen2_unalignedassert.cpp
new file mode 100644
index 000000000..d10b6f538
--- /dev/null
+++ b/test/eigen2/eigen2_unalignedassert.cpp
@@ -0,0 +1,116 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra. Eigen itself is part of the KDE project.
+//
+// Copyright (C) 2008 Benoit Jacob <jacob.benoit.1@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 "main.h"
+
+struct Good1
+{
+ MatrixXd m; // good: m will allocate its own array, taking care of alignment.
+ Good1() : m(20,20) {}
+};
+
+struct Good2
+{
+ Matrix3d m; // good: m's size isn't a multiple of 16 bytes, so m doesn't have to be aligned
+};
+
+struct Good3
+{
+ Vector2f m; // good: same reason
+};
+
+struct Bad4
+{
+ Vector2d m; // bad: sizeof(m)%16==0 so alignment is required
+};
+
+struct Bad5
+{
+ Matrix<float, 2, 6> m; // bad: same reason
+};
+
+struct Bad6
+{
+ Matrix<double, 3, 4> m; // bad: same reason
+};
+
+struct Good7
+{
+ EIGEN_MAKE_ALIGNED_OPERATOR_NEW
+ Vector2d m;
+ float f; // make the struct have sizeof%16!=0 to make it a little more tricky when we allow an array of 2 such objects
+};
+
+struct Good8
+{
+ EIGEN_MAKE_ALIGNED_OPERATOR_NEW
+ float f; // try the f at first -- the EIGEN_ALIGN_128 attribute of m should make that still work
+ Matrix4f m;
+};
+
+struct Good9
+{
+ Matrix<float,2,2,DontAlign> m; // good: no alignment requested
+ float f;
+};
+
+template<bool Align> struct Depends
+{
+ EIGEN_MAKE_ALIGNED_OPERATOR_NEW_IF(Align)
+ Vector2d m;
+ float f;
+};
+
+template<typename T>
+void check_unalignedassert_good()
+{
+ T *x, *y;
+ x = new T;
+ delete x;
+ y = new T[2];
+ delete[] y;
+}
+
+#if EIGEN_ARCH_WANTS_ALIGNMENT
+template<typename T>
+void check_unalignedassert_bad()
+{
+ float buf[sizeof(T)+16];
+ float *unaligned = buf;
+ while((reinterpret_cast<std::size_t>(unaligned)&0xf)==0) ++unaligned; // make sure unaligned is really unaligned
+ T *x = ::new(static_cast<void*>(unaligned)) T;
+ x->~T();
+}
+#endif
+
+void unalignedassert()
+{
+ check_unalignedassert_good<Good1>();
+ check_unalignedassert_good<Good2>();
+ check_unalignedassert_good<Good3>();
+#if EIGEN_ARCH_WANTS_ALIGNMENT
+ VERIFY_RAISES_ASSERT(check_unalignedassert_bad<Bad4>());
+ VERIFY_RAISES_ASSERT(check_unalignedassert_bad<Bad5>());
+ VERIFY_RAISES_ASSERT(check_unalignedassert_bad<Bad6>());
+#endif
+
+ check_unalignedassert_good<Good7>();
+ check_unalignedassert_good<Good8>();
+ check_unalignedassert_good<Good9>();
+ check_unalignedassert_good<Depends<true> >();
+
+#if EIGEN_ARCH_WANTS_ALIGNMENT
+ VERIFY_RAISES_ASSERT(check_unalignedassert_bad<Depends<false> >());
+#endif
+}
+
+void test_eigen2_unalignedassert()
+{
+ CALL_SUBTEST(unalignedassert());
+}
diff --git a/test/eigen2/eigen2_visitor.cpp b/test/eigen2/eigen2_visitor.cpp
new file mode 100644
index 000000000..4781991de
--- /dev/null
+++ b/test/eigen2/eigen2_visitor.cpp
@@ -0,0 +1,116 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra.
+//
+// Copyright (C) 2008 Benoit Jacob <jacob.benoit.1@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 "main.h"
+
+template<typename MatrixType> void matrixVisitor(const MatrixType& p)
+{
+ typedef typename MatrixType::Scalar Scalar;
+
+ int rows = p.rows();
+ int cols = p.cols();
+
+ // construct a random matrix where all coefficients are different
+ MatrixType m;
+ m = MatrixType::Random(rows, cols);
+ for(int i = 0; i < m.size(); i++)
+ for(int i2 = 0; i2 < i; i2++)
+ while(m(i) == m(i2)) // yes, ==
+ m(i) = ei_random<Scalar>();
+
+ Scalar minc = Scalar(1000), maxc = Scalar(-1000);
+ int minrow=0,mincol=0,maxrow=0,maxcol=0;
+ for(int j = 0; j < cols; j++)
+ for(int i = 0; i < rows; i++)
+ {
+ if(m(i,j) < minc)
+ {
+ minc = m(i,j);
+ minrow = i;
+ mincol = j;
+ }
+ if(m(i,j) > maxc)
+ {
+ maxc = m(i,j);
+ maxrow = i;
+ maxcol = j;
+ }
+ }
+ int eigen_minrow, eigen_mincol, eigen_maxrow, eigen_maxcol;
+ Scalar eigen_minc, eigen_maxc;
+ eigen_minc = m.minCoeff(&eigen_minrow,&eigen_mincol);
+ eigen_maxc = m.maxCoeff(&eigen_maxrow,&eigen_maxcol);
+ VERIFY(minrow == eigen_minrow);
+ VERIFY(maxrow == eigen_maxrow);
+ VERIFY(mincol == eigen_mincol);
+ VERIFY(maxcol == eigen_maxcol);
+ VERIFY_IS_APPROX(minc, eigen_minc);
+ VERIFY_IS_APPROX(maxc, eigen_maxc);
+ VERIFY_IS_APPROX(minc, m.minCoeff());
+ VERIFY_IS_APPROX(maxc, m.maxCoeff());
+}
+
+template<typename VectorType> void vectorVisitor(const VectorType& w)
+{
+ typedef typename VectorType::Scalar Scalar;
+
+ int size = w.size();
+
+ // construct a random vector where all coefficients are different
+ VectorType v;
+ v = VectorType::Random(size);
+ for(int i = 0; i < size; i++)
+ for(int i2 = 0; i2 < i; i2++)
+ while(v(i) == v(i2)) // yes, ==
+ v(i) = ei_random<Scalar>();
+
+ Scalar minc = Scalar(1000), maxc = Scalar(-1000);
+ int minidx=0,maxidx=0;
+ for(int i = 0; i < size; i++)
+ {
+ if(v(i) < minc)
+ {
+ minc = v(i);
+ minidx = i;
+ }
+ if(v(i) > maxc)
+ {
+ maxc = v(i);
+ maxidx = i;
+ }
+ }
+ int eigen_minidx, eigen_maxidx;
+ Scalar eigen_minc, eigen_maxc;
+ eigen_minc = v.minCoeff(&eigen_minidx);
+ eigen_maxc = v.maxCoeff(&eigen_maxidx);
+ VERIFY(minidx == eigen_minidx);
+ VERIFY(maxidx == eigen_maxidx);
+ VERIFY_IS_APPROX(minc, eigen_minc);
+ VERIFY_IS_APPROX(maxc, eigen_maxc);
+ VERIFY_IS_APPROX(minc, v.minCoeff());
+ VERIFY_IS_APPROX(maxc, v.maxCoeff());
+}
+
+void test_eigen2_visitor()
+{
+ for(int i = 0; i < g_repeat; i++) {
+ CALL_SUBTEST_1( matrixVisitor(Matrix<float, 1, 1>()) );
+ CALL_SUBTEST_2( matrixVisitor(Matrix2f()) );
+ CALL_SUBTEST_3( matrixVisitor(Matrix4d()) );
+ CALL_SUBTEST_4( matrixVisitor(MatrixXd(8, 12)) );
+ CALL_SUBTEST_5( matrixVisitor(Matrix<double,Dynamic,Dynamic,RowMajor>(20, 20)) );
+ CALL_SUBTEST_6( matrixVisitor(MatrixXi(8, 12)) );
+ }
+ for(int i = 0; i < g_repeat; i++) {
+ CALL_SUBTEST_7( vectorVisitor(Vector4f()) );
+ CALL_SUBTEST_4( vectorVisitor(VectorXd(10)) );
+ CALL_SUBTEST_4( vectorVisitor(RowVectorXd(10)) );
+ CALL_SUBTEST_8( vectorVisitor(VectorXf(33)) );
+ }
+}
diff --git a/test/eigen2/gsl_helper.h b/test/eigen2/gsl_helper.h
new file mode 100644
index 000000000..d1d854533
--- /dev/null
+++ b/test/eigen2/gsl_helper.h
@@ -0,0 +1,175 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra. Eigen itself is part of the KDE project.
+//
+// Copyright (C) 2008 Gael Guennebaud <g.gael@free.fr>
+//
+// This Source Code Form is subject to the terms of the Mozilla
+// Public License v. 2.0. If a copy of the MPL was not distributed
+// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+#ifndef EIGEN_GSL_HELPER
+#define EIGEN_GSL_HELPER
+
+#include <Eigen/Core>
+
+#include <gsl/gsl_blas.h>
+#include <gsl/gsl_multifit.h>
+#include <gsl/gsl_eigen.h>
+#include <gsl/gsl_linalg.h>
+#include <gsl/gsl_complex.h>
+#include <gsl/gsl_complex_math.h>
+
+namespace Eigen {
+
+template<typename Scalar, bool IsComplex = NumTraits<Scalar>::IsComplex> struct GslTraits
+{
+ typedef gsl_matrix* Matrix;
+ typedef gsl_vector* Vector;
+ static Matrix createMatrix(int rows, int cols) { return gsl_matrix_alloc(rows,cols); }
+ static Vector createVector(int size) { return gsl_vector_alloc(size); }
+ static void free(Matrix& m) { gsl_matrix_free(m); m=0; }
+ static void free(Vector& m) { gsl_vector_free(m); m=0; }
+ static void prod(const Matrix& m, const Vector& v, Vector& x) { gsl_blas_dgemv(CblasNoTrans,1,m,v,0,x); }
+ static void cholesky(Matrix& m) { gsl_linalg_cholesky_decomp(m); }
+ static void cholesky_solve(const Matrix& m, const Vector& b, Vector& x) { gsl_linalg_cholesky_solve(m,b,x); }
+ static void eigen_symm(const Matrix& m, Vector& eval, Matrix& evec)
+ {
+ gsl_eigen_symmv_workspace * w = gsl_eigen_symmv_alloc(m->size1);
+ Matrix a = createMatrix(m->size1, m->size2);
+ gsl_matrix_memcpy(a, m);
+ gsl_eigen_symmv(a,eval,evec,w);
+ gsl_eigen_symmv_sort(eval, evec, GSL_EIGEN_SORT_VAL_ASC);
+ gsl_eigen_symmv_free(w);
+ free(a);
+ }
+ static void eigen_symm_gen(const Matrix& m, const Matrix& _b, Vector& eval, Matrix& evec)
+ {
+ gsl_eigen_gensymmv_workspace * w = gsl_eigen_gensymmv_alloc(m->size1);
+ Matrix a = createMatrix(m->size1, m->size2);
+ Matrix b = createMatrix(_b->size1, _b->size2);
+ gsl_matrix_memcpy(a, m);
+ gsl_matrix_memcpy(b, _b);
+ gsl_eigen_gensymmv(a,b,eval,evec,w);
+ gsl_eigen_symmv_sort(eval, evec, GSL_EIGEN_SORT_VAL_ASC);
+ gsl_eigen_gensymmv_free(w);
+ free(a);
+ }
+};
+
+template<typename Scalar> struct GslTraits<Scalar,true>
+{
+ typedef gsl_matrix_complex* Matrix;
+ typedef gsl_vector_complex* Vector;
+ static Matrix createMatrix(int rows, int cols) { return gsl_matrix_complex_alloc(rows,cols); }
+ static Vector createVector(int size) { return gsl_vector_complex_alloc(size); }
+ static void free(Matrix& m) { gsl_matrix_complex_free(m); m=0; }
+ static void free(Vector& m) { gsl_vector_complex_free(m); m=0; }
+ static void cholesky(Matrix& m) { gsl_linalg_complex_cholesky_decomp(m); }
+ static void cholesky_solve(const Matrix& m, const Vector& b, Vector& x) { gsl_linalg_complex_cholesky_solve(m,b,x); }
+ static void prod(const Matrix& m, const Vector& v, Vector& x)
+ { gsl_blas_zgemv(CblasNoTrans,gsl_complex_rect(1,0),m,v,gsl_complex_rect(0,0),x); }
+ static void eigen_symm(const Matrix& m, gsl_vector* &eval, Matrix& evec)
+ {
+ gsl_eigen_hermv_workspace * w = gsl_eigen_hermv_alloc(m->size1);
+ Matrix a = createMatrix(m->size1, m->size2);
+ gsl_matrix_complex_memcpy(a, m);
+ gsl_eigen_hermv(a,eval,evec,w);
+ gsl_eigen_hermv_sort(eval, evec, GSL_EIGEN_SORT_VAL_ASC);
+ gsl_eigen_hermv_free(w);
+ free(a);
+ }
+ static void eigen_symm_gen(const Matrix& m, const Matrix& _b, gsl_vector* &eval, Matrix& evec)
+ {
+ gsl_eigen_genhermv_workspace * w = gsl_eigen_genhermv_alloc(m->size1);
+ Matrix a = createMatrix(m->size1, m->size2);
+ Matrix b = createMatrix(_b->size1, _b->size2);
+ gsl_matrix_complex_memcpy(a, m);
+ gsl_matrix_complex_memcpy(b, _b);
+ gsl_eigen_genhermv(a,b,eval,evec,w);
+ gsl_eigen_hermv_sort(eval, evec, GSL_EIGEN_SORT_VAL_ASC);
+ gsl_eigen_genhermv_free(w);
+ free(a);
+ }
+};
+
+template<typename MatrixType>
+void convert(const MatrixType& m, gsl_matrix* &res)
+{
+// if (res)
+// gsl_matrix_free(res);
+ res = gsl_matrix_alloc(m.rows(), m.cols());
+ for (int i=0 ; i<m.rows() ; ++i)
+ for (int j=0 ; j<m.cols(); ++j)
+ gsl_matrix_set(res, i, j, m(i,j));
+}
+
+template<typename MatrixType>
+void convert(const gsl_matrix* m, MatrixType& res)
+{
+ res.resize(int(m->size1), int(m->size2));
+ for (int i=0 ; i<res.rows() ; ++i)
+ for (int j=0 ; j<res.cols(); ++j)
+ res(i,j) = gsl_matrix_get(m,i,j);
+}
+
+template<typename VectorType>
+void convert(const VectorType& m, gsl_vector* &res)
+{
+ if (res) gsl_vector_free(res);
+ res = gsl_vector_alloc(m.size());
+ for (int i=0 ; i<m.size() ; ++i)
+ gsl_vector_set(res, i, m[i]);
+}
+
+template<typename VectorType>
+void convert(const gsl_vector* m, VectorType& res)
+{
+ res.resize (m->size);
+ for (int i=0 ; i<res.rows() ; ++i)
+ res[i] = gsl_vector_get(m, i);
+}
+
+template<typename MatrixType>
+void convert(const MatrixType& m, gsl_matrix_complex* &res)
+{
+ res = gsl_matrix_complex_alloc(m.rows(), m.cols());
+ for (int i=0 ; i<m.rows() ; ++i)
+ for (int j=0 ; j<m.cols(); ++j)
+ {
+ gsl_matrix_complex_set(res, i, j,
+ gsl_complex_rect(m(i,j).real(), m(i,j).imag()));
+ }
+}
+
+template<typename MatrixType>
+void convert(const gsl_matrix_complex* m, MatrixType& res)
+{
+ res.resize(int(m->size1), int(m->size2));
+ for (int i=0 ; i<res.rows() ; ++i)
+ for (int j=0 ; j<res.cols(); ++j)
+ res(i,j) = typename MatrixType::Scalar(
+ GSL_REAL(gsl_matrix_complex_get(m,i,j)),
+ GSL_IMAG(gsl_matrix_complex_get(m,i,j)));
+}
+
+template<typename VectorType>
+void convert(const VectorType& m, gsl_vector_complex* &res)
+{
+ res = gsl_vector_complex_alloc(m.size());
+ for (int i=0 ; i<m.size() ; ++i)
+ gsl_vector_complex_set(res, i, gsl_complex_rect(m[i].real(), m[i].imag()));
+}
+
+template<typename VectorType>
+void convert(const gsl_vector_complex* m, VectorType& res)
+{
+ res.resize(m->size);
+ for (int i=0 ; i<res.rows() ; ++i)
+ res[i] = typename VectorType::Scalar(
+ GSL_REAL(gsl_vector_complex_get(m, i)),
+ GSL_IMAG(gsl_vector_complex_get(m, i)));
+}
+
+}
+
+#endif // EIGEN_GSL_HELPER
diff --git a/test/eigen2/main.h b/test/eigen2/main.h
new file mode 100644
index 000000000..ad2ba1994
--- /dev/null
+++ b/test/eigen2/main.h
@@ -0,0 +1,399 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra. Eigen itself is part of the KDE project.
+//
+// Copyright (C) 2006-2008 Benoit Jacob <jacob.benoit.1@gmail.com>
+// Copyright (C) 2008 Gael Guennebaud <g.gael@free.fr>
+//
+// This Source Code Form is subject to the terms of the Mozilla
+// Public License v. 2.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 <cstdlib>
+#include <ctime>
+#include <iostream>
+#include <string>
+#include <vector>
+
+#ifndef EIGEN_TEST_FUNC
+#error EIGEN_TEST_FUNC must be defined
+#endif
+
+#define DEFAULT_REPEAT 10
+
+namespace Eigen
+{
+ static std::vector<std::string> g_test_stack;
+ static int g_repeat;
+}
+
+#define EI_PP_MAKE_STRING2(S) #S
+#define EI_PP_MAKE_STRING(S) EI_PP_MAKE_STRING2(S)
+
+#define EI_PP_CAT2(a,b) a ## b
+#define EI_PP_CAT(a,b) EI_PP_CAT2(a,b)
+
+#ifndef EIGEN_NO_ASSERTION_CHECKING
+
+ namespace Eigen
+ {
+ static const bool should_raise_an_assert = false;
+
+ // Used to avoid to raise two exceptions at a time in which
+ // case the exception is not properly caught.
+ // This may happen when a second exceptions is raise in a destructor.
+ static bool no_more_assert = false;
+
+ struct eigen_assert_exception
+ {
+ eigen_assert_exception(void) {}
+ ~eigen_assert_exception() { Eigen::no_more_assert = false; }
+ };
+ }
+
+ // If EIGEN_DEBUG_ASSERTS is defined and if no assertion is raised while
+ // one should have been, then the list of excecuted assertions is printed out.
+ //
+ // EIGEN_DEBUG_ASSERTS is not enabled by default as it
+ // significantly increases the compilation time
+ // and might even introduce side effects that would hide
+ // some memory errors.
+ #ifdef EIGEN_DEBUG_ASSERTS
+
+ namespace Eigen
+ {
+ static bool ei_push_assert = false;
+ static std::vector<std::string> eigen_assert_list;
+ }
+
+ #define eigen_assert(a) \
+ if( (!(a)) && (!no_more_assert) ) \
+ { \
+ Eigen::no_more_assert = true; \
+ throw Eigen::eigen_assert_exception(); \
+ } \
+ else if (Eigen::ei_push_assert) \
+ { \
+ eigen_assert_list.push_back(std::string(EI_PP_MAKE_STRING(__FILE__)" ("EI_PP_MAKE_STRING(__LINE__)") : "#a) ); \
+ }
+
+ #define VERIFY_RAISES_ASSERT(a) \
+ { \
+ Eigen::no_more_assert = false; \
+ try { \
+ Eigen::eigen_assert_list.clear(); \
+ Eigen::ei_push_assert = true; \
+ a; \
+ Eigen::ei_push_assert = false; \
+ std::cerr << "One of the following asserts should have been raised:\n"; \
+ for (uint ai=0 ; ai<eigen_assert_list.size() ; ++ai) \
+ std::cerr << " " << eigen_assert_list[ai] << "\n"; \
+ VERIFY(Eigen::should_raise_an_assert && # a); \
+ } catch (Eigen::eigen_assert_exception e) { \
+ Eigen::ei_push_assert = false; VERIFY(true); \
+ } \
+ }
+
+ #else // EIGEN_DEBUG_ASSERTS
+
+ #undef eigen_assert
+
+ // see bug 89. The copy_bool here is working around a bug in gcc <= 4.3
+ #define eigen_assert(a) \
+ if( (!Eigen::internal::copy_bool(a)) && (!no_more_assert) ) \
+ { \
+ Eigen::no_more_assert = true; \
+ throw Eigen::eigen_assert_exception(); \
+ }
+
+ #define VERIFY_RAISES_ASSERT(a) { \
+ Eigen::no_more_assert = false; \
+ try { a; VERIFY(Eigen::should_raise_an_assert && # a); } \
+ catch (Eigen::eigen_assert_exception e) { VERIFY(true); } \
+ }
+
+ #endif // EIGEN_DEBUG_ASSERTS
+
+ #define EIGEN_USE_CUSTOM_ASSERT
+
+#else // EIGEN_NO_ASSERTION_CHECKING
+
+ #define VERIFY_RAISES_ASSERT(a) {}
+
+#endif // EIGEN_NO_ASSERTION_CHECKING
+
+
+#define EIGEN_INTERNAL_DEBUGGING
+#define EIGEN_NICE_RANDOM
+#include <Eigen/Array>
+
+
+#define VERIFY(a) do { if (!(a)) { \
+ std::cerr << "Test " << g_test_stack.back() << " failed in "EI_PP_MAKE_STRING(__FILE__) << " (" << EI_PP_MAKE_STRING(__LINE__) << ")" \
+ << std::endl << " " << EI_PP_MAKE_STRING(a) << std::endl << std::endl; \
+ abort(); \
+ } } while (0)
+
+#define VERIFY_IS_APPROX(a, b) VERIFY(test_ei_isApprox(a, b))
+#define VERIFY_IS_NOT_APPROX(a, b) VERIFY(!test_ei_isApprox(a, b))
+#define VERIFY_IS_MUCH_SMALLER_THAN(a, b) VERIFY(test_ei_isMuchSmallerThan(a, b))
+#define VERIFY_IS_NOT_MUCH_SMALLER_THAN(a, b) VERIFY(!test_ei_isMuchSmallerThan(a, b))
+#define VERIFY_IS_APPROX_OR_LESS_THAN(a, b) VERIFY(test_ei_isApproxOrLessThan(a, b))
+#define VERIFY_IS_NOT_APPROX_OR_LESS_THAN(a, b) VERIFY(!test_ei_isApproxOrLessThan(a, b))
+
+#define CALL_SUBTEST(FUNC) do { \
+ g_test_stack.push_back(EI_PP_MAKE_STRING(FUNC)); \
+ FUNC; \
+ g_test_stack.pop_back(); \
+ } while (0)
+
+namespace Eigen {
+
+template<typename T> inline typename NumTraits<T>::Real test_precision();
+template<> inline int test_precision<int>() { return 0; }
+template<> inline float test_precision<float>() { return 1e-3f; }
+template<> inline double test_precision<double>() { return 1e-6; }
+template<> inline float test_precision<std::complex<float> >() { return test_precision<float>(); }
+template<> inline double test_precision<std::complex<double> >() { return test_precision<double>(); }
+template<> inline long double test_precision<long double>() { return 1e-6; }
+
+inline bool test_ei_isApprox(const int& a, const int& b)
+{ return ei_isApprox(a, b, test_precision<int>()); }
+inline bool test_ei_isMuchSmallerThan(const int& a, const int& b)
+{ return ei_isMuchSmallerThan(a, b, test_precision<int>()); }
+inline bool test_ei_isApproxOrLessThan(const int& a, const int& b)
+{ return ei_isApproxOrLessThan(a, b, test_precision<int>()); }
+
+inline bool test_ei_isApprox(const float& a, const float& b)
+{ return ei_isApprox(a, b, test_precision<float>()); }
+inline bool test_ei_isMuchSmallerThan(const float& a, const float& b)
+{ return ei_isMuchSmallerThan(a, b, test_precision<float>()); }
+inline bool test_ei_isApproxOrLessThan(const float& a, const float& b)
+{ return ei_isApproxOrLessThan(a, b, test_precision<float>()); }
+
+inline bool test_ei_isApprox(const double& a, const double& b)
+{ return ei_isApprox(a, b, test_precision<double>()); }
+inline bool test_ei_isMuchSmallerThan(const double& a, const double& b)
+{ return ei_isMuchSmallerThan(a, b, test_precision<double>()); }
+inline bool test_ei_isApproxOrLessThan(const double& a, const double& b)
+{ return ei_isApproxOrLessThan(a, b, test_precision<double>()); }
+
+inline bool test_ei_isApprox(const std::complex<float>& a, const std::complex<float>& b)
+{ return ei_isApprox(a, b, test_precision<std::complex<float> >()); }
+inline bool test_ei_isMuchSmallerThan(const std::complex<float>& a, const std::complex<float>& b)
+{ return ei_isMuchSmallerThan(a, b, test_precision<std::complex<float> >()); }
+
+inline bool test_ei_isApprox(const std::complex<double>& a, const std::complex<double>& b)
+{ return ei_isApprox(a, b, test_precision<std::complex<double> >()); }
+inline bool test_ei_isMuchSmallerThan(const std::complex<double>& a, const std::complex<double>& b)
+{ return ei_isMuchSmallerThan(a, b, test_precision<std::complex<double> >()); }
+
+inline bool test_ei_isApprox(const long double& a, const long double& b)
+{ return ei_isApprox(a, b, test_precision<long double>()); }
+inline bool test_ei_isMuchSmallerThan(const long double& a, const long double& b)
+{ return ei_isMuchSmallerThan(a, b, test_precision<long double>()); }
+inline bool test_ei_isApproxOrLessThan(const long double& a, const long double& b)
+{ return ei_isApproxOrLessThan(a, b, test_precision<long double>()); }
+
+template<typename Type1, typename Type2>
+inline bool test_ei_isApprox(const Type1& a, const Type2& b)
+{
+ return a.isApprox(b, test_precision<typename Type1::Scalar>());
+}
+
+template<typename Derived1, typename Derived2>
+inline bool test_ei_isMuchSmallerThan(const MatrixBase<Derived1>& m1,
+ const MatrixBase<Derived2>& m2)
+{
+ return m1.isMuchSmallerThan(m2, test_precision<typename ei_traits<Derived1>::Scalar>());
+}
+
+template<typename Derived>
+inline bool test_ei_isMuchSmallerThan(const MatrixBase<Derived>& m,
+ const typename NumTraits<typename ei_traits<Derived>::Scalar>::Real& s)
+{
+ return m.isMuchSmallerThan(s, test_precision<typename ei_traits<Derived>::Scalar>());
+}
+
+} // end namespace Eigen
+
+template<typename T> struct GetDifferentType;
+
+template<> struct GetDifferentType<float> { typedef double type; };
+template<> struct GetDifferentType<double> { typedef float type; };
+template<typename T> struct GetDifferentType<std::complex<T> >
+{ typedef std::complex<typename GetDifferentType<T>::type> type; };
+
+// forward declaration of the main test function
+void EI_PP_CAT(test_,EIGEN_TEST_FUNC)();
+
+using namespace Eigen;
+
+#ifdef EIGEN_TEST_PART_1
+#define CALL_SUBTEST_1(FUNC) CALL_SUBTEST(FUNC)
+#else
+#define CALL_SUBTEST_1(FUNC)
+#endif
+
+#ifdef EIGEN_TEST_PART_2
+#define CALL_SUBTEST_2(FUNC) CALL_SUBTEST(FUNC)
+#else
+#define CALL_SUBTEST_2(FUNC)
+#endif
+
+#ifdef EIGEN_TEST_PART_3
+#define CALL_SUBTEST_3(FUNC) CALL_SUBTEST(FUNC)
+#else
+#define CALL_SUBTEST_3(FUNC)
+#endif
+
+#ifdef EIGEN_TEST_PART_4
+#define CALL_SUBTEST_4(FUNC) CALL_SUBTEST(FUNC)
+#else
+#define CALL_SUBTEST_4(FUNC)
+#endif
+
+#ifdef EIGEN_TEST_PART_5
+#define CALL_SUBTEST_5(FUNC) CALL_SUBTEST(FUNC)
+#else
+#define CALL_SUBTEST_5(FUNC)
+#endif
+
+#ifdef EIGEN_TEST_PART_6
+#define CALL_SUBTEST_6(FUNC) CALL_SUBTEST(FUNC)
+#else
+#define CALL_SUBTEST_6(FUNC)
+#endif
+
+#ifdef EIGEN_TEST_PART_7
+#define CALL_SUBTEST_7(FUNC) CALL_SUBTEST(FUNC)
+#else
+#define CALL_SUBTEST_7(FUNC)
+#endif
+
+#ifdef EIGEN_TEST_PART_8
+#define CALL_SUBTEST_8(FUNC) CALL_SUBTEST(FUNC)
+#else
+#define CALL_SUBTEST_8(FUNC)
+#endif
+
+#ifdef EIGEN_TEST_PART_9
+#define CALL_SUBTEST_9(FUNC) CALL_SUBTEST(FUNC)
+#else
+#define CALL_SUBTEST_9(FUNC)
+#endif
+
+#ifdef EIGEN_TEST_PART_10
+#define CALL_SUBTEST_10(FUNC) CALL_SUBTEST(FUNC)
+#else
+#define CALL_SUBTEST_10(FUNC)
+#endif
+
+#ifdef EIGEN_TEST_PART_11
+#define CALL_SUBTEST_11(FUNC) CALL_SUBTEST(FUNC)
+#else
+#define CALL_SUBTEST_11(FUNC)
+#endif
+
+#ifdef EIGEN_TEST_PART_12
+#define CALL_SUBTEST_12(FUNC) CALL_SUBTEST(FUNC)
+#else
+#define CALL_SUBTEST_12(FUNC)
+#endif
+
+#ifdef EIGEN_TEST_PART_13
+#define CALL_SUBTEST_13(FUNC) CALL_SUBTEST(FUNC)
+#else
+#define CALL_SUBTEST_13(FUNC)
+#endif
+
+#ifdef EIGEN_TEST_PART_14
+#define CALL_SUBTEST_14(FUNC) CALL_SUBTEST(FUNC)
+#else
+#define CALL_SUBTEST_14(FUNC)
+#endif
+
+#ifdef EIGEN_TEST_PART_15
+#define CALL_SUBTEST_15(FUNC) CALL_SUBTEST(FUNC)
+#else
+#define CALL_SUBTEST_15(FUNC)
+#endif
+
+#ifdef EIGEN_TEST_PART_16
+#define CALL_SUBTEST_16(FUNC) CALL_SUBTEST(FUNC)
+#else
+#define CALL_SUBTEST_16(FUNC)
+#endif
+
+
+
+int main(int argc, char *argv[])
+{
+ bool has_set_repeat = false;
+ bool has_set_seed = false;
+ bool need_help = false;
+ unsigned int seed = 0;
+ int repeat = DEFAULT_REPEAT;
+
+ for(int i = 1; i < argc; i++)
+ {
+ if(argv[i][0] == 'r')
+ {
+ if(has_set_repeat)
+ {
+ std::cout << "Argument " << argv[i] << " conflicting with a former argument" << std::endl;
+ return 1;
+ }
+ repeat = std::atoi(argv[i]+1);
+ has_set_repeat = true;
+ if(repeat <= 0)
+ {
+ std::cout << "Invalid \'repeat\' value " << argv[i]+1 << std::endl;
+ return 1;
+ }
+ }
+ else if(argv[i][0] == 's')
+ {
+ if(has_set_seed)
+ {
+ std::cout << "Argument " << argv[i] << " conflicting with a former argument" << std::endl;
+ return 1;
+ }
+ seed = int(std::strtoul(argv[i]+1, 0, 10));
+ has_set_seed = true;
+ bool ok = seed!=0;
+ if(!ok)
+ {
+ std::cout << "Invalid \'seed\' value " << argv[i]+1 << std::endl;
+ return 1;
+ }
+ }
+ else
+ {
+ need_help = true;
+ }
+ }
+
+ if(need_help)
+ {
+ std::cout << "This test application takes the following optional arguments:" << std::endl;
+ std::cout << " rN Repeat each test N times (default: " << DEFAULT_REPEAT << ")" << std::endl;
+ std::cout << " sN Use N as seed for random numbers (default: based on current time)" << std::endl;
+ return 1;
+ }
+
+ if(!has_set_seed) seed = (unsigned int) std::time(NULL);
+ if(!has_set_repeat) repeat = DEFAULT_REPEAT;
+
+ std::cout << "Initializing random number generator with seed " << seed << std::endl;
+ std::srand(seed);
+ std::cout << "Repeating each test " << repeat << " times" << std::endl;
+
+ Eigen::g_repeat = repeat;
+ Eigen::g_test_stack.push_back(EI_PP_MAKE_STRING(EIGEN_TEST_FUNC));
+
+ EI_PP_CAT(test_,EIGEN_TEST_FUNC)();
+ return 0;
+}
+
+
+
diff --git a/test/eigen2/product.h b/test/eigen2/product.h
new file mode 100644
index 000000000..2c9604d9a
--- /dev/null
+++ b/test/eigen2/product.h
@@ -0,0 +1,132 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra. Eigen itself is part of the KDE project.
+//
+// Copyright (C) 2006-2008 Benoit Jacob <jacob.benoit.1@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 "main.h"
+#include <Eigen/Array>
+#include <Eigen/QR>
+
+template<typename Derived1, typename Derived2>
+bool areNotApprox(const MatrixBase<Derived1>& m1, const MatrixBase<Derived2>& m2, typename Derived1::RealScalar epsilon = precision<typename Derived1::RealScalar>())
+{
+ return !((m1-m2).cwise().abs2().maxCoeff() < epsilon * epsilon
+ * std::max(m1.cwise().abs2().maxCoeff(), m2.cwise().abs2().maxCoeff()));
+}
+
+template<typename MatrixType> void product(const MatrixType& m)
+{
+ /* this test covers the following files:
+ Identity.h Product.h
+ */
+
+ typedef typename MatrixType::Scalar Scalar;
+ typedef typename NumTraits<Scalar>::FloatingPoint FloatingPoint;
+ typedef Matrix<Scalar, MatrixType::RowsAtCompileTime, 1> RowVectorType;
+ typedef Matrix<Scalar, MatrixType::ColsAtCompileTime, 1> ColVectorType;
+ typedef Matrix<Scalar, MatrixType::RowsAtCompileTime, MatrixType::RowsAtCompileTime> RowSquareMatrixType;
+ typedef Matrix<Scalar, MatrixType::ColsAtCompileTime, MatrixType::ColsAtCompileTime> ColSquareMatrixType;
+ typedef Matrix<Scalar, MatrixType::RowsAtCompileTime, MatrixType::ColsAtCompileTime,
+ MatrixType::Options^RowMajor> OtherMajorMatrixType;
+
+ int rows = m.rows();
+ int cols = m.cols();
+
+ // this test relies a lot on Random.h, and there's not much more that we can do
+ // to test it, hence I consider that we will have tested Random.h
+ MatrixType m1 = MatrixType::Random(rows, cols),
+ m2 = MatrixType::Random(rows, cols),
+ m3(rows, cols),
+ mzero = MatrixType::Zero(rows, cols);
+ RowSquareMatrixType
+ identity = RowSquareMatrixType::Identity(rows, rows),
+ square = RowSquareMatrixType::Random(rows, rows),
+ res = RowSquareMatrixType::Random(rows, rows);
+ ColSquareMatrixType
+ square2 = ColSquareMatrixType::Random(cols, cols),
+ res2 = ColSquareMatrixType::Random(cols, cols);
+ RowVectorType v1 = RowVectorType::Random(rows),
+ v2 = RowVectorType::Random(rows),
+ vzero = RowVectorType::Zero(rows);
+ ColVectorType vc2 = ColVectorType::Random(cols), vcres(cols);
+ OtherMajorMatrixType tm1 = m1;
+
+ Scalar s1 = ei_random<Scalar>();
+
+ int r = ei_random<int>(0, rows-1),
+ c = ei_random<int>(0, cols-1);
+
+ // begin testing Product.h: only associativity for now
+ // (we use Transpose.h but this doesn't count as a test for it)
+
+ VERIFY_IS_APPROX((m1*m1.transpose())*m2, m1*(m1.transpose()*m2));
+ m3 = m1;
+ m3 *= m1.transpose() * m2;
+ VERIFY_IS_APPROX(m3, m1 * (m1.transpose()*m2));
+ VERIFY_IS_APPROX(m3, m1.lazy() * (m1.transpose()*m2));
+
+ // continue testing Product.h: distributivity
+ VERIFY_IS_APPROX(square*(m1 + m2), square*m1+square*m2);
+ VERIFY_IS_APPROX(square*(m1 - m2), square*m1-square*m2);
+
+ // continue testing Product.h: compatibility with ScalarMultiple.h
+ VERIFY_IS_APPROX(s1*(square*m1), (s1*square)*m1);
+ VERIFY_IS_APPROX(s1*(square*m1), square*(m1*s1));
+
+ // again, test operator() to check const-qualification
+ s1 += (square.lazy() * m1)(r,c);
+
+ // test Product.h together with Identity.h
+ VERIFY_IS_APPROX(v1, identity*v1);
+ VERIFY_IS_APPROX(v1.transpose(), v1.transpose() * identity);
+ // again, test operator() to check const-qualification
+ VERIFY_IS_APPROX(MatrixType::Identity(rows, cols)(r,c), static_cast<Scalar>(r==c));
+
+ if (rows!=cols)
+ VERIFY_RAISES_ASSERT(m3 = m1*m1);
+
+ // test the previous tests were not screwed up because operator* returns 0
+ // (we use the more accurate default epsilon)
+ if (NumTraits<Scalar>::HasFloatingPoint && std::min(rows,cols)>1)
+ {
+ VERIFY(areNotApprox(m1.transpose()*m2,m2.transpose()*m1));
+ }
+
+ // test optimized operator+= path
+ res = square;
+ res += (m1 * m2.transpose()).lazy();
+ VERIFY_IS_APPROX(res, square + m1 * m2.transpose());
+ if (NumTraits<Scalar>::HasFloatingPoint && std::min(rows,cols)>1)
+ {
+ VERIFY(areNotApprox(res,square + m2 * m1.transpose()));
+ }
+ vcres = vc2;
+ vcres += (m1.transpose() * v1).lazy();
+ VERIFY_IS_APPROX(vcres, vc2 + m1.transpose() * v1);
+ tm1 = m1;
+ VERIFY_IS_APPROX(tm1.transpose() * v1, m1.transpose() * v1);
+ VERIFY_IS_APPROX(v1.transpose() * tm1, v1.transpose() * m1);
+
+ // test submatrix and matrix/vector product
+ for (int i=0; i<rows; ++i)
+ res.row(i) = m1.row(i) * m2.transpose();
+ VERIFY_IS_APPROX(res, m1 * m2.transpose());
+ // the other way round:
+ for (int i=0; i<rows; ++i)
+ res.col(i) = m1 * m2.transpose().col(i);
+ VERIFY_IS_APPROX(res, m1 * m2.transpose());
+
+ res2 = square2;
+ res2 += (m1.transpose() * m2).lazy();
+ VERIFY_IS_APPROX(res2, square2 + m1.transpose() * m2);
+
+ if (NumTraits<Scalar>::HasFloatingPoint && std::min(rows,cols)>1)
+ {
+ VERIFY(areNotApprox(res2,square2 + m2.transpose() * m1));
+ }
+}
+
diff --git a/test/eigen2/runtest.sh b/test/eigen2/runtest.sh
new file mode 100755
index 000000000..bc693af13
--- /dev/null
+++ b/test/eigen2/runtest.sh
@@ -0,0 +1,28 @@
+#!/bin/bash
+
+black='\E[30m'
+red='\E[31m'
+green='\E[32m'
+yellow='\E[33m'
+blue='\E[34m'
+magenta='\E[35m'
+cyan='\E[36m'
+white='\E[37m'
+
+if make test_$1 > /dev/null 2> .runtest.log ; then
+ if ! ./test_$1 r20 > /dev/null 2> .runtest.log ; then
+ echo -e $red Test $1 failed: $black
+ echo -e $blue
+ cat .runtest.log
+ echo -e $black
+ exit 1
+ else
+ echo -e $green Test $1 passed$black
+ fi
+else
+ echo -e $red Build of target $1 failed: $black
+ echo -e $blue
+ cat .runtest.log
+ echo -e $black
+ exit 1
+fi
diff --git a/test/eigen2/sparse.h b/test/eigen2/sparse.h
new file mode 100644
index 000000000..e12f89990
--- /dev/null
+++ b/test/eigen2/sparse.h
@@ -0,0 +1,154 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra. Eigen itself is part of the KDE project.
+//
+// Copyright (C) 2008 Daniel Gomez Ferro <dgomezferro@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 EIGEN_TESTSPARSE_H
+
+#include "main.h"
+
+#if EIGEN_GNUC_AT_LEAST(4,0) && !defined __ICC
+#include <tr1/unordered_map>
+#define EIGEN_UNORDERED_MAP_SUPPORT
+namespace std {
+ using std::tr1::unordered_map;
+}
+#endif
+
+#ifdef EIGEN_GOOGLEHASH_SUPPORT
+ #include <google/sparse_hash_map>
+#endif
+
+#include <Eigen/Cholesky>
+#include <Eigen/LU>
+#include <Eigen/Sparse>
+
+enum {
+ ForceNonZeroDiag = 1,
+ MakeLowerTriangular = 2,
+ MakeUpperTriangular = 4,
+ ForceRealDiag = 8
+};
+
+/* Initializes both a sparse and dense matrix with same random values,
+ * and a ratio of \a density non zero entries.
+ * \param flags is a union of ForceNonZeroDiag, MakeLowerTriangular and MakeUpperTriangular
+ * allowing to control the shape of the matrix.
+ * \param zeroCoords and nonzeroCoords allows to get the coordinate lists of the non zero,
+ * and zero coefficients respectively.
+ */
+template<typename Scalar> void
+initSparse(double density,
+ Matrix<Scalar,Dynamic,Dynamic>& refMat,
+ SparseMatrix<Scalar>& sparseMat,
+ int flags = 0,
+ std::vector<Vector2i>* zeroCoords = 0,
+ std::vector<Vector2i>* nonzeroCoords = 0)
+{
+ sparseMat.startFill(int(refMat.rows()*refMat.cols()*density));
+ for(int j=0; j<refMat.cols(); j++)
+ {
+ for(int i=0; i<refMat.rows(); i++)
+ {
+ Scalar v = (ei_random<double>(0,1) < density) ? ei_random<Scalar>() : Scalar(0);
+ if ((flags&ForceNonZeroDiag) && (i==j))
+ {
+ v = ei_random<Scalar>()*Scalar(3.);
+ v = v*v + Scalar(5.);
+ }
+ if ((flags & MakeLowerTriangular) && j>i)
+ v = Scalar(0);
+ else if ((flags & MakeUpperTriangular) && j<i)
+ v = Scalar(0);
+
+ if ((flags&ForceRealDiag) && (i==j))
+ v = ei_real(v);
+
+ if (v!=Scalar(0))
+ {
+ sparseMat.fill(i,j) = v;
+ if (nonzeroCoords)
+ nonzeroCoords->push_back(Vector2i(i,j));
+ }
+ else if (zeroCoords)
+ {
+ zeroCoords->push_back(Vector2i(i,j));
+ }
+ refMat(i,j) = v;
+ }
+ }
+ sparseMat.endFill();
+}
+
+template<typename Scalar> void
+initSparse(double density,
+ Matrix<Scalar,Dynamic,Dynamic>& refMat,
+ DynamicSparseMatrix<Scalar>& sparseMat,
+ int flags = 0,
+ std::vector<Vector2i>* zeroCoords = 0,
+ std::vector<Vector2i>* nonzeroCoords = 0)
+{
+ sparseMat.startFill(int(refMat.rows()*refMat.cols()*density));
+ for(int j=0; j<refMat.cols(); j++)
+ {
+ for(int i=0; i<refMat.rows(); i++)
+ {
+ Scalar v = (ei_random<double>(0,1) < density) ? ei_random<Scalar>() : Scalar(0);
+ if ((flags&ForceNonZeroDiag) && (i==j))
+ {
+ v = ei_random<Scalar>()*Scalar(3.);
+ v = v*v + Scalar(5.);
+ }
+ if ((flags & MakeLowerTriangular) && j>i)
+ v = Scalar(0);
+ else if ((flags & MakeUpperTriangular) && j<i)
+ v = Scalar(0);
+
+ if ((flags&ForceRealDiag) && (i==j))
+ v = ei_real(v);
+
+ if (v!=Scalar(0))
+ {
+ sparseMat.fill(i,j) = v;
+ if (nonzeroCoords)
+ nonzeroCoords->push_back(Vector2i(i,j));
+ }
+ else if (zeroCoords)
+ {
+ zeroCoords->push_back(Vector2i(i,j));
+ }
+ refMat(i,j) = v;
+ }
+ }
+ sparseMat.endFill();
+}
+
+template<typename Scalar> void
+initSparse(double density,
+ Matrix<Scalar,Dynamic,1>& refVec,
+ SparseVector<Scalar>& sparseVec,
+ std::vector<int>* zeroCoords = 0,
+ std::vector<int>* nonzeroCoords = 0)
+{
+ sparseVec.reserve(int(refVec.size()*density));
+ sparseVec.setZero();
+ for(int i=0; i<refVec.size(); i++)
+ {
+ Scalar v = (ei_random<double>(0,1) < density) ? ei_random<Scalar>() : Scalar(0);
+ if (v!=Scalar(0))
+ {
+ sparseVec.fill(i) = v;
+ if (nonzeroCoords)
+ nonzeroCoords->push_back(i);
+ }
+ else if (zeroCoords)
+ zeroCoords->push_back(i);
+ refVec[i] = v;
+ }
+}
+
+#endif // EIGEN_TESTSPARSE_H
diff --git a/test/eigen2/testsuite.cmake b/test/eigen2/testsuite.cmake
new file mode 100644
index 000000000..12b6bfa2e
--- /dev/null
+++ b/test/eigen2/testsuite.cmake
@@ -0,0 +1,197 @@
+
+####################################################################
+#
+# Usage:
+# - create a new folder, let's call it cdash
+# - in that folder, do:
+# ctest -S path/to/eigen2/test/testsuite.cmake[,option1=value1[,option2=value2]]
+#
+# Options:
+# - EIGEN_CXX: compiler, eg.: g++-4.2
+# default: default c++ compiler
+# - EIGEN_SITE: eg, INRIA-Bdx_pc-gael, or the name of the contributor, etc.
+# default: hostname
+# - EIGEN_BUILD_STRING: a string which identify the system/compiler. It should be formed like that:
+# <OS_name>-<OS_version>-<arch>-<compiler-version>
+# with:
+# <OS_name> = opensuse, debian, osx, windows, cygwin, freebsd, solaris, etc.
+# <OS_version> = 11.1, XP, vista, leopard, etc.
+# <arch> = i386, x86_64, ia64, powerpc, etc.
+# <compiler-version> = gcc-4.3.2, icc-11.0, MSVC-2008, etc.
+# - EIGEN_EXPLICIT_VECTORIZATION: novec, SSE2, Altivec
+# default: SSE2 for x86_64 systems, novec otherwise
+# Its value is automatically appended to EIGEN_BUILD_STRING
+# - EIGEN_CMAKE_DIR: path to cmake executable
+# - EIGEN_MODE: dashboard model, can be Experimental, Nightly, or Continuous
+# default: Nightly
+# - EIGEN_WORK_DIR: directory used to download the source files and make the builds
+# default: folder which contains this script
+# - EIGEN_CMAKE_ARGS: additional arguments passed to cmake
+# - CTEST_SOURCE_DIRECTORY: path to eigen's src (use a new and empty folder, not the one you are working on)
+# default: <EIGEN_WORK_DIR>/src
+# - CTEST_BINARY_DIRECTORY: build directory
+# default: <EIGEN_WORK_DIR>/nightly-<EIGEN_CXX>
+#
+# Here is an example running several compilers on a linux system:
+# #!/bin/bash
+# ARCH=`uname -m`
+# SITE=`hostname`
+# VERSION=opensuse-11.1
+# WORK_DIR=/home/gael/Coding/eigen2/cdash
+# # get the last version of the script
+# wget http://bitbucket.org/eigen/eigen/raw/tip/test/testsuite.cmake -o $WORK_DIR/testsuite.cmake
+# COMMON="ctest -S $WORK_DIR/testsuite.cmake,EIGEN_WORK_DIR=$WORK_DIR,EIGEN_SITE=$SITE,EIGEN_MODE=$1,EIGEN_BUILD_STRING=$OS_VERSION-$ARCH"
+# $COMMON-gcc-3.4.6,EIGEN_CXX=g++-3.4
+# $COMMON-gcc-4.0.1,EIGEN_CXX=g++-4.0.1
+# $COMMON-gcc-4.3.2,EIGEN_CXX=g++-4.3,EIGEN_EXPLICIT_VECTORIZATION=novec
+# $COMMON-gcc-4.3.2,EIGEN_CXX=g++-4.3,EIGEN_EXPLICIT_VECTORIZATION=SSE2
+# $COMMON-icc-11.0,EIGEN_CXX=icpc
+#
+####################################################################
+
+# process the arguments
+
+set(ARGLIST ${CTEST_SCRIPT_ARG})
+while(${ARGLIST} MATCHES ".+.*")
+
+ # pick first
+ string(REGEX MATCH "([^,]*)(,.*)?" DUMMY ${ARGLIST})
+ SET(TOP ${CMAKE_MATCH_1})
+
+ # remove first
+ string(REGEX MATCHALL "[^,]*,(.*)" DUMMY ${ARGLIST})
+ SET(ARGLIST ${CMAKE_MATCH_1})
+
+ # decompose as a pair key=value
+ string(REGEX MATCH "([^=]*)(=.*)?" DUMMY ${TOP})
+ SET(KEY ${CMAKE_MATCH_1})
+
+ string(REGEX MATCH "[^=]*=(.*)" DUMMY ${TOP})
+ SET(VALUE ${CMAKE_MATCH_1})
+
+ # set the variable to the specified value
+ if(VALUE)
+ SET(${KEY} ${VALUE})
+ else(VALUE)
+ SET(${KEY} ON)
+ endif(VALUE)
+
+endwhile(${ARGLIST} MATCHES ".+.*")
+
+####################################################################
+# Automatically set some user variables if they have not been defined manually
+####################################################################
+cmake_minimum_required(VERSION 2.6 FATAL_ERROR)
+
+if(NOT EIGEN_SITE)
+ site_name(EIGEN_SITE)
+endif(NOT EIGEN_SITE)
+
+if(NOT EIGEN_CMAKE_DIR)
+ SET(EIGEN_CMAKE_DIR "")
+endif(NOT EIGEN_CMAKE_DIR)
+
+if(NOT EIGEN_BUILD_STRING)
+
+ # let's try to find all information we need to make the build string ourself
+
+ # OS
+ build_name(EIGEN_OS_VERSION)
+
+ # arch
+ set(EIGEN_ARCH ${CMAKE_SYSTEM_PROCESSOR})
+ if(WIN32)
+ set(EIGEN_ARCH $ENV{PROCESSOR_ARCHITECTURE})
+ else(WIN32)
+ execute_process(COMMAND uname -m OUTPUT_VARIABLE EIGEN_ARCH OUTPUT_STRIP_TRAILING_WHITESPACE)
+ endif(WIN32)
+
+ set(EIGEN_BUILD_STRING ${EIGEN_OS_VERSION}${EIGEN_ARCH}-${EIGEN_CXX})
+
+endif(NOT EIGEN_BUILD_STRING)
+
+if(DEFINED EIGEN_EXPLICIT_VECTORIZATION)
+ set(EIGEN_BUILD_STRING ${EIGEN_BUILD_STRING}-${EIGEN_EXPLICIT_VECTORIZATION})
+endif(DEFINED EIGEN_EXPLICIT_VECTORIZATION)
+
+if(NOT EIGEN_WORK_DIR)
+ set(EIGEN_WORK_DIR ${CTEST_SCRIPT_DIRECTORY})
+endif(NOT EIGEN_WORK_DIR)
+
+if(NOT CTEST_SOURCE_DIRECTORY)
+ SET (CTEST_SOURCE_DIRECTORY "${EIGEN_WORK_DIR}/src")
+endif(NOT CTEST_SOURCE_DIRECTORY)
+
+if(NOT CTEST_BINARY_DIRECTORY)
+ SET (CTEST_BINARY_DIRECTORY "${EIGEN_WORK_DIR}/nightly_${EIGEN_CXX}")
+endif(NOT CTEST_BINARY_DIRECTORY)
+
+if(NOT EIGEN_MODE)
+ set(EIGEN_MODE Nightly)
+endif(NOT EIGEN_MODE)
+
+## mandatory variables (the default should be ok in most cases):
+
+SET (CTEST_CVS_COMMAND "hg")
+SET (CTEST_CVS_CHECKOUT "${CTEST_CVS_COMMAND} clone -r 2.0 http://bitbucket.org/eigen/eigen \"${CTEST_SOURCE_DIRECTORY}\"")
+
+# which ctest command to use for running the dashboard
+SET (CTEST_COMMAND "${EIGEN_CMAKE_DIR}ctest -D ${EIGEN_MODE}")
+
+# what cmake command to use for configuring this dashboard
+SET (CTEST_CMAKE_COMMAND "${EIGEN_CMAKE_DIR}cmake -DEIGEN_BUILD_TESTS=on ")
+
+####################################################################
+# The values in this section are optional you can either
+# have them or leave them commented out
+####################################################################
+
+# this make sure we get consistent outputs
+SET($ENV{LC_MESSAGES} "en_EN")
+
+# should ctest wipe the binary tree before running
+SET(CTEST_START_WITH_EMPTY_BINARY_DIRECTORY TRUE)
+SET(CTEST_BACKUP_AND_RESTORE TRUE)
+
+# this is the initial cache to use for the binary tree, be careful to escape
+# any quotes inside of this string if you use it
+if(WIN32 AND NOT UNIX)
+ #message(SEND_ERROR "win32")
+ set(CTEST_CMAKE_COMMAND "${CTEST_CMAKE_COMMAND} -G \"NMake Makefiles\" -DCMAKE_MAKE_PROGRAM=nmake")
+ SET (CTEST_INITIAL_CACHE "
+ MAKECOMMAND:STRING=nmake -i
+ CMAKE_MAKE_PROGRAM:FILEPATH=nmake
+ CMAKE_GENERATOR:INTERNAL=NMake Makefiles
+ BUILDNAME:STRING=${EIGEN_BUILD_STRING}
+ SITE:STRING=${EIGEN_SITE}
+ ")
+else(WIN32 AND NOT UNIX)
+ SET (CTEST_INITIAL_CACHE "
+ BUILDNAME:STRING=${EIGEN_BUILD_STRING}
+ SITE:STRING=${EIGEN_SITE}
+ ")
+endif(WIN32 AND NOT UNIX)
+
+# set any extra environment variables to use during the execution of the script here:
+
+if(EIGEN_CXX)
+ set(CTEST_ENVIRONMENT "CXX=${EIGEN_CXX}")
+endif(EIGEN_CXX)
+
+if(DEFINED EIGEN_EXPLICIT_VECTORIZATION)
+ if(EIGEN_EXPLICIT_VECTORIZATION MATCHES SSE2)
+ set(CTEST_CMAKE_COMMAND "${CTEST_CMAKE_COMMAND} -DEIGEN_TEST_SSE2=ON")
+ elseif(EIGEN_EXPLICIT_VECTORIZATION MATCHES SSE3)
+ set(CTEST_CMAKE_COMMAND "${CTEST_CMAKE_COMMAND} -DEIGEN_TEST_SSE2=ON -DEIGEN_TEST_SSE3=ON")
+ elseif(EIGEN_EXPLICIT_VECTORIZATION MATCHES Altivec)
+ set(CTEST_CMAKE_COMMAND "${CTEST_CMAKE_COMMAND} -DEIGEN_TEST_ALTIVEC=ON")
+ elseif(EIGEN_EXPLICIT_VECTORIZATION MATCHES novec)
+ set(CTEST_CMAKE_COMMAND "${CTEST_CMAKE_COMMAND} -DEIGEN_TEST_NO_EXPLICIT_VECTORIZATION=ON")
+ else(EIGEN_EXPLICIT_VECTORIZATION MATCHES SSE2)
+ message(FATAL_ERROR "Invalid value for EIGEN_EXPLICIT_VECTORIZATION (${EIGEN_EXPLICIT_VECTORIZATION}), must be: novec, SSE2, SSE3, Altivec")
+ endif(EIGEN_EXPLICIT_VECTORIZATION MATCHES SSE2)
+endif(DEFINED EIGEN_EXPLICIT_VECTORIZATION)
+
+if(DEFINED EIGEN_CMAKE_ARGS)
+ set(CTEST_CMAKE_COMMAND "${CTEST_CMAKE_COMMAND} ${EIGEN_CMAKE_ARGS}")
+endif(DEFINED EIGEN_CMAKE_ARGS)
diff --git a/test/eigen2support.cpp b/test/eigen2support.cpp
new file mode 100644
index 000000000..7e02bdf5b
--- /dev/null
+++ b/test/eigen2support.cpp
@@ -0,0 +1,64 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra.
+//
+// Copyright (C) 2009 Gael Guennebaud <gael.guennebaud@inria.fr>
+//
+// This Source Code Form is subject to the terms of the Mozilla
+// Public License v. 2.0. If a copy of the MPL was not distributed
+// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+#define EIGEN2_SUPPORT
+
+#include "main.h"
+
+template<typename MatrixType> void eigen2support(const MatrixType& m)
+{
+ typedef typename MatrixType::Index Index;
+ typedef typename MatrixType::Scalar Scalar;
+
+ Index rows = m.rows();
+ Index cols = m.cols();
+
+ MatrixType m1 = MatrixType::Random(rows, cols),
+ m3(rows, cols);
+
+ Scalar s1 = internal::random<Scalar>(),
+ s2 = internal::random<Scalar>();
+
+ // scalar addition
+ VERIFY_IS_APPROX(m1.cwise() + s1, s1 + m1.cwise());
+ VERIFY_IS_APPROX(m1.cwise() + s1, MatrixType::Constant(rows,cols,s1) + m1);
+ VERIFY_IS_APPROX((m1*Scalar(2)).cwise() - s2, (m1+m1) - MatrixType::Constant(rows,cols,s2) );
+ m3 = m1;
+ m3.cwise() += s2;
+ VERIFY_IS_APPROX(m3, m1.cwise() + s2);
+ m3 = m1;
+ m3.cwise() -= s1;
+ VERIFY_IS_APPROX(m3, m1.cwise() - s1);
+
+ VERIFY_IS_EQUAL((m1.corner(TopLeft,1,1)), (m1.block(0,0,1,1)));
+ VERIFY_IS_EQUAL((m1.template corner<1,1>(TopLeft)), (m1.template block<1,1>(0,0)));
+ VERIFY_IS_EQUAL((m1.col(0).start(1)), (m1.col(0).segment(0,1)));
+ VERIFY_IS_EQUAL((m1.col(0).template start<1>()), (m1.col(0).segment(0,1)));
+ VERIFY_IS_EQUAL((m1.col(0).end(1)), (m1.col(0).segment(rows-1,1)));
+ VERIFY_IS_EQUAL((m1.col(0).template end<1>()), (m1.col(0).segment(rows-1,1)));
+
+ using namespace internal;
+ VERIFY_IS_EQUAL(ei_cos(s1), cos(s1));
+ VERIFY_IS_EQUAL(ei_real(s1), real(s1));
+ VERIFY_IS_EQUAL(ei_abs2(s1), abs2(s1));
+
+ m1.minor(0,0);
+}
+
+void test_eigen2support()
+{
+ for(int i = 0; i < g_repeat; i++) {
+ CALL_SUBTEST_1( eigen2support(Matrix<double,1,1>()) );
+ CALL_SUBTEST_2( eigen2support(MatrixXd(1,1)) );
+ CALL_SUBTEST_4( eigen2support(Matrix3f()) );
+ CALL_SUBTEST_5( eigen2support(Matrix4d()) );
+ CALL_SUBTEST_2( eigen2support(MatrixXf(200,200)) );
+ CALL_SUBTEST_6( eigen2support(MatrixXcd(100,100)) );
+ }
+}
diff --git a/test/eigensolver_complex.cpp b/test/eigensolver_complex.cpp
new file mode 100644
index 000000000..0c2059512
--- /dev/null
+++ b/test/eigensolver_complex.cpp
@@ -0,0 +1,115 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra.
+//
+// Copyright (C) 2008-2009 Gael Guennebaud <gael.guennebaud@inria.fr>
+// Copyright (C) 2010 Jitse Niesen <jitse@maths.leeds.ac.uk>
+//
+// This Source Code Form is subject to the terms of the Mozilla
+// Public License v. 2.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 "main.h"
+#include <limits>
+#include <Eigen/Eigenvalues>
+#include <Eigen/LU>
+
+/* Check that two column vectors are approximately equal upto permutations,
+ by checking that the k-th power sums are equal for k = 1, ..., vec1.rows() */
+template<typename VectorType>
+void verify_is_approx_upto_permutation(const VectorType& vec1, const VectorType& vec2)
+{
+ typedef typename NumTraits<typename VectorType::Scalar>::Real RealScalar;
+
+ VERIFY(vec1.cols() == 1);
+ VERIFY(vec2.cols() == 1);
+ VERIFY(vec1.rows() == vec2.rows());
+ for (int k = 1; k <= vec1.rows(); ++k)
+ {
+ VERIFY_IS_APPROX(vec1.array().pow(RealScalar(k)).sum(), vec2.array().pow(RealScalar(k)).sum());
+ }
+}
+
+
+template<typename MatrixType> void eigensolver(const MatrixType& m)
+{
+ typedef typename MatrixType::Index Index;
+ /* this test covers the following files:
+ ComplexEigenSolver.h, and indirectly ComplexSchur.h
+ */
+ Index rows = m.rows();
+ Index cols = m.cols();
+
+ typedef typename MatrixType::Scalar Scalar;
+ typedef typename NumTraits<Scalar>::Real RealScalar;
+ typedef Matrix<Scalar, MatrixType::RowsAtCompileTime, 1> VectorType;
+ typedef Matrix<RealScalar, MatrixType::RowsAtCompileTime, 1> RealVectorType;
+ typedef typename std::complex<typename NumTraits<typename MatrixType::Scalar>::Real> Complex;
+
+ MatrixType a = MatrixType::Random(rows,cols);
+ MatrixType symmA = a.adjoint() * a;
+
+ ComplexEigenSolver<MatrixType> ei0(symmA);
+ VERIFY_IS_EQUAL(ei0.info(), Success);
+ VERIFY_IS_APPROX(symmA * ei0.eigenvectors(), ei0.eigenvectors() * ei0.eigenvalues().asDiagonal());
+
+ ComplexEigenSolver<MatrixType> ei1(a);
+ VERIFY_IS_EQUAL(ei1.info(), Success);
+ VERIFY_IS_APPROX(a * ei1.eigenvectors(), ei1.eigenvectors() * ei1.eigenvalues().asDiagonal());
+ // Note: If MatrixType is real then a.eigenvalues() uses EigenSolver and thus
+ // another algorithm so results may differ slightly
+ verify_is_approx_upto_permutation(a.eigenvalues(), ei1.eigenvalues());
+
+ ComplexEigenSolver<MatrixType> eiNoEivecs(a, false);
+ VERIFY_IS_EQUAL(eiNoEivecs.info(), Success);
+ VERIFY_IS_APPROX(ei1.eigenvalues(), eiNoEivecs.eigenvalues());
+
+ // Regression test for issue #66
+ MatrixType z = MatrixType::Zero(rows,cols);
+ ComplexEigenSolver<MatrixType> eiz(z);
+ VERIFY((eiz.eigenvalues().cwiseEqual(0)).all());
+
+ MatrixType id = MatrixType::Identity(rows, cols);
+ VERIFY_IS_APPROX(id.operatorNorm(), RealScalar(1));
+
+ if (rows > 1)
+ {
+ // Test matrix with NaN
+ a(0,0) = std::numeric_limits<typename MatrixType::RealScalar>::quiet_NaN();
+ ComplexEigenSolver<MatrixType> eiNaN(a);
+ VERIFY_IS_EQUAL(eiNaN.info(), NoConvergence);
+ }
+}
+
+template<typename MatrixType> void eigensolver_verify_assert(const MatrixType& m)
+{
+ ComplexEigenSolver<MatrixType> eig;
+ VERIFY_RAISES_ASSERT(eig.eigenvectors());
+ VERIFY_RAISES_ASSERT(eig.eigenvalues());
+
+ MatrixType a = MatrixType::Random(m.rows(),m.cols());
+ eig.compute(a, false);
+ VERIFY_RAISES_ASSERT(eig.eigenvectors());
+}
+
+void test_eigensolver_complex()
+{
+ int s;
+ for(int i = 0; i < g_repeat; i++) {
+ CALL_SUBTEST_1( eigensolver(Matrix4cf()) );
+ s = internal::random<int>(1,EIGEN_TEST_MAX_SIZE/4);
+ CALL_SUBTEST_2( eigensolver(MatrixXcd(s,s)) );
+ CALL_SUBTEST_3( eigensolver(Matrix<std::complex<float>, 1, 1>()) );
+ CALL_SUBTEST_4( eigensolver(Matrix3f()) );
+ }
+
+ CALL_SUBTEST_1( eigensolver_verify_assert(Matrix4cf()) );
+ s = internal::random<int>(1,EIGEN_TEST_MAX_SIZE/4);
+ CALL_SUBTEST_2( eigensolver_verify_assert(MatrixXcd(s,s)) );
+ CALL_SUBTEST_3( eigensolver_verify_assert(Matrix<std::complex<float>, 1, 1>()) );
+ CALL_SUBTEST_4( eigensolver_verify_assert(Matrix3f()) );
+
+ // Test problem size constructors
+ CALL_SUBTEST_5(ComplexEigenSolver<MatrixXf>(s));
+
+ EIGEN_UNUSED_VARIABLE(s)
+}
diff --git a/test/eigensolver_generic.cpp b/test/eigensolver_generic.cpp
new file mode 100644
index 000000000..0b55ccd93
--- /dev/null
+++ b/test/eigensolver_generic.cpp
@@ -0,0 +1,115 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra.
+//
+// Copyright (C) 2008 Gael Guennebaud <gael.guennebaud@inria.fr>
+// Copyright (C) 2010 Jitse Niesen <jitse@maths.leeds.ac.uk>
+//
+// This Source Code Form is subject to the terms of the Mozilla
+// Public License v. 2.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 "main.h"
+#include <limits>
+#include <Eigen/Eigenvalues>
+
+template<typename MatrixType> void eigensolver(const MatrixType& m)
+{
+ typedef typename MatrixType::Index Index;
+ /* this test covers the following files:
+ EigenSolver.h
+ */
+ Index rows = m.rows();
+ Index cols = m.cols();
+
+ typedef typename MatrixType::Scalar Scalar;
+ typedef typename NumTraits<Scalar>::Real RealScalar;
+ typedef Matrix<Scalar, MatrixType::RowsAtCompileTime, 1> VectorType;
+ typedef Matrix<RealScalar, MatrixType::RowsAtCompileTime, 1> RealVectorType;
+ typedef typename std::complex<typename NumTraits<typename MatrixType::Scalar>::Real> Complex;
+
+ MatrixType a = MatrixType::Random(rows,cols);
+ MatrixType a1 = MatrixType::Random(rows,cols);
+ MatrixType symmA = a.adjoint() * a + a1.adjoint() * a1;
+
+ EigenSolver<MatrixType> ei0(symmA);
+ VERIFY_IS_EQUAL(ei0.info(), Success);
+ VERIFY_IS_APPROX(symmA * ei0.pseudoEigenvectors(), ei0.pseudoEigenvectors() * ei0.pseudoEigenvalueMatrix());
+ VERIFY_IS_APPROX((symmA.template cast<Complex>()) * (ei0.pseudoEigenvectors().template cast<Complex>()),
+ (ei0.pseudoEigenvectors().template cast<Complex>()) * (ei0.eigenvalues().asDiagonal()));
+
+ EigenSolver<MatrixType> ei1(a);
+ VERIFY_IS_EQUAL(ei1.info(), Success);
+ VERIFY_IS_APPROX(a * ei1.pseudoEigenvectors(), ei1.pseudoEigenvectors() * ei1.pseudoEigenvalueMatrix());
+ VERIFY_IS_APPROX(a.template cast<Complex>() * ei1.eigenvectors(),
+ ei1.eigenvectors() * ei1.eigenvalues().asDiagonal());
+ VERIFY_IS_APPROX(ei1.eigenvectors().colwise().norm(), RealVectorType::Ones(rows).transpose());
+ VERIFY_IS_APPROX(a.eigenvalues(), ei1.eigenvalues());
+
+ EigenSolver<MatrixType> eiNoEivecs(a, false);
+ VERIFY_IS_EQUAL(eiNoEivecs.info(), Success);
+ VERIFY_IS_APPROX(ei1.eigenvalues(), eiNoEivecs.eigenvalues());
+ VERIFY_IS_APPROX(ei1.pseudoEigenvalueMatrix(), eiNoEivecs.pseudoEigenvalueMatrix());
+
+ MatrixType id = MatrixType::Identity(rows, cols);
+ VERIFY_IS_APPROX(id.operatorNorm(), RealScalar(1));
+
+ if (rows > 2)
+ {
+ // Test matrix with NaN
+ a(0,0) = std::numeric_limits<typename MatrixType::RealScalar>::quiet_NaN();
+ EigenSolver<MatrixType> eiNaN(a);
+ VERIFY_IS_EQUAL(eiNaN.info(), NoConvergence);
+ }
+}
+
+template<typename MatrixType> void eigensolver_verify_assert(const MatrixType& m)
+{
+ EigenSolver<MatrixType> eig;
+ VERIFY_RAISES_ASSERT(eig.eigenvectors());
+ VERIFY_RAISES_ASSERT(eig.pseudoEigenvectors());
+ VERIFY_RAISES_ASSERT(eig.pseudoEigenvalueMatrix());
+ VERIFY_RAISES_ASSERT(eig.eigenvalues());
+
+ MatrixType a = MatrixType::Random(m.rows(),m.cols());
+ eig.compute(a, false);
+ VERIFY_RAISES_ASSERT(eig.eigenvectors());
+ VERIFY_RAISES_ASSERT(eig.pseudoEigenvectors());
+}
+
+void test_eigensolver_generic()
+{
+ int s;
+ for(int i = 0; i < g_repeat; i++) {
+ CALL_SUBTEST_1( eigensolver(Matrix4f()) );
+ s = internal::random<int>(1,EIGEN_TEST_MAX_SIZE/4);
+ CALL_SUBTEST_2( eigensolver(MatrixXd(s,s)) );
+
+ // some trivial but implementation-wise tricky cases
+ CALL_SUBTEST_2( eigensolver(MatrixXd(1,1)) );
+ CALL_SUBTEST_2( eigensolver(MatrixXd(2,2)) );
+ CALL_SUBTEST_3( eigensolver(Matrix<double,1,1>()) );
+ CALL_SUBTEST_4( eigensolver(Matrix2d()) );
+ }
+
+ CALL_SUBTEST_1( eigensolver_verify_assert(Matrix4f()) );
+ s = internal::random<int>(1,EIGEN_TEST_MAX_SIZE/4);
+ CALL_SUBTEST_2( eigensolver_verify_assert(MatrixXd(s,s)) );
+ CALL_SUBTEST_3( eigensolver_verify_assert(Matrix<double,1,1>()) );
+ CALL_SUBTEST_4( eigensolver_verify_assert(Matrix2d()) );
+
+ // Test problem size constructors
+ CALL_SUBTEST_5(EigenSolver<MatrixXf>(s));
+
+ // regression test for bug 410
+ CALL_SUBTEST_2(
+ {
+ MatrixXd A(1,1);
+ A(0,0) = std::sqrt(-1.);
+ Eigen::EigenSolver<MatrixXd> solver(A);
+ MatrixXd V(1, 1);
+ V(0,0) = solver.eigenvectors()(0,0).real();
+ }
+ );
+
+ EIGEN_UNUSED_VARIABLE(s)
+}
diff --git a/test/eigensolver_selfadjoint.cpp b/test/eigensolver_selfadjoint.cpp
new file mode 100644
index 000000000..02dbdb429
--- /dev/null
+++ b/test/eigensolver_selfadjoint.cpp
@@ -0,0 +1,146 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra.
+//
+// Copyright (C) 2008 Gael Guennebaud <gael.guennebaud@inria.fr>
+// Copyright (C) 2010 Jitse Niesen <jitse@maths.leeds.ac.uk>
+//
+// This Source Code Form is subject to the terms of the Mozilla
+// Public License v. 2.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 "main.h"
+#include <limits>
+#include <Eigen/Eigenvalues>
+
+template<typename MatrixType> void selfadjointeigensolver(const MatrixType& m)
+{
+ typedef typename MatrixType::Index Index;
+ /* this test covers the following files:
+ EigenSolver.h, SelfAdjointEigenSolver.h (and indirectly: Tridiagonalization.h)
+ */
+ Index rows = m.rows();
+ Index cols = m.cols();
+
+ typedef typename MatrixType::Scalar Scalar;
+ typedef typename NumTraits<Scalar>::Real RealScalar;
+ typedef Matrix<Scalar, MatrixType::RowsAtCompileTime, 1> VectorType;
+ typedef Matrix<RealScalar, MatrixType::RowsAtCompileTime, 1> RealVectorType;
+ typedef typename std::complex<typename NumTraits<typename MatrixType::Scalar>::Real> Complex;
+
+ RealScalar largerEps = 10*test_precision<RealScalar>();
+
+ MatrixType a = MatrixType::Random(rows,cols);
+ MatrixType a1 = MatrixType::Random(rows,cols);
+ MatrixType symmA = a.adjoint() * a + a1.adjoint() * a1;
+ symmA.template triangularView<StrictlyUpper>().setZero();
+
+ MatrixType b = MatrixType::Random(rows,cols);
+ MatrixType b1 = MatrixType::Random(rows,cols);
+ MatrixType symmB = b.adjoint() * b + b1.adjoint() * b1;
+ symmB.template triangularView<StrictlyUpper>().setZero();
+
+ SelfAdjointEigenSolver<MatrixType> eiSymm(symmA);
+ SelfAdjointEigenSolver<MatrixType> eiDirect;
+ eiDirect.computeDirect(symmA);
+ // generalized eigen pb
+ GeneralizedSelfAdjointEigenSolver<MatrixType> eiSymmGen(symmA, symmB);
+
+ VERIFY_IS_EQUAL(eiSymm.info(), Success);
+ VERIFY((symmA.template selfadjointView<Lower>() * eiSymm.eigenvectors()).isApprox(
+ eiSymm.eigenvectors() * eiSymm.eigenvalues().asDiagonal(), largerEps));
+ VERIFY_IS_APPROX(symmA.template selfadjointView<Lower>().eigenvalues(), eiSymm.eigenvalues());
+
+ VERIFY_IS_EQUAL(eiDirect.info(), Success);
+ VERIFY((symmA.template selfadjointView<Lower>() * eiDirect.eigenvectors()).isApprox(
+ eiDirect.eigenvectors() * eiDirect.eigenvalues().asDiagonal(), largerEps));
+ VERIFY_IS_APPROX(symmA.template selfadjointView<Lower>().eigenvalues(), eiDirect.eigenvalues());
+
+ SelfAdjointEigenSolver<MatrixType> eiSymmNoEivecs(symmA, false);
+ VERIFY_IS_EQUAL(eiSymmNoEivecs.info(), Success);
+ VERIFY_IS_APPROX(eiSymm.eigenvalues(), eiSymmNoEivecs.eigenvalues());
+
+ // generalized eigen problem Ax = lBx
+ eiSymmGen.compute(symmA, symmB,Ax_lBx);
+ VERIFY_IS_EQUAL(eiSymmGen.info(), Success);
+ VERIFY((symmA.template selfadjointView<Lower>() * eiSymmGen.eigenvectors()).isApprox(
+ symmB.template selfadjointView<Lower>() * (eiSymmGen.eigenvectors() * eiSymmGen.eigenvalues().asDiagonal()), largerEps));
+
+ // generalized eigen problem BAx = lx
+ eiSymmGen.compute(symmA, symmB,BAx_lx);
+ VERIFY_IS_EQUAL(eiSymmGen.info(), Success);
+ VERIFY((symmB.template selfadjointView<Lower>() * (symmA.template selfadjointView<Lower>() * eiSymmGen.eigenvectors())).isApprox(
+ (eiSymmGen.eigenvectors() * eiSymmGen.eigenvalues().asDiagonal()), largerEps));
+
+ // generalized eigen problem ABx = lx
+ eiSymmGen.compute(symmA, symmB,ABx_lx);
+ VERIFY_IS_EQUAL(eiSymmGen.info(), Success);
+ VERIFY((symmA.template selfadjointView<Lower>() * (symmB.template selfadjointView<Lower>() * eiSymmGen.eigenvectors())).isApprox(
+ (eiSymmGen.eigenvectors() * eiSymmGen.eigenvalues().asDiagonal()), largerEps));
+
+
+ MatrixType sqrtSymmA = eiSymm.operatorSqrt();
+ VERIFY_IS_APPROX(MatrixType(symmA.template selfadjointView<Lower>()), sqrtSymmA*sqrtSymmA);
+ VERIFY_IS_APPROX(sqrtSymmA, symmA.template selfadjointView<Lower>()*eiSymm.operatorInverseSqrt());
+
+ MatrixType id = MatrixType::Identity(rows, cols);
+ VERIFY_IS_APPROX(id.template selfadjointView<Lower>().operatorNorm(), RealScalar(1));
+
+ SelfAdjointEigenSolver<MatrixType> eiSymmUninitialized;
+ VERIFY_RAISES_ASSERT(eiSymmUninitialized.info());
+ VERIFY_RAISES_ASSERT(eiSymmUninitialized.eigenvalues());
+ VERIFY_RAISES_ASSERT(eiSymmUninitialized.eigenvectors());
+ VERIFY_RAISES_ASSERT(eiSymmUninitialized.operatorSqrt());
+ VERIFY_RAISES_ASSERT(eiSymmUninitialized.operatorInverseSqrt());
+
+ eiSymmUninitialized.compute(symmA, false);
+ VERIFY_RAISES_ASSERT(eiSymmUninitialized.eigenvectors());
+ VERIFY_RAISES_ASSERT(eiSymmUninitialized.operatorSqrt());
+ VERIFY_RAISES_ASSERT(eiSymmUninitialized.operatorInverseSqrt());
+
+ // test Tridiagonalization's methods
+ Tridiagonalization<MatrixType> tridiag(symmA);
+ // FIXME tridiag.matrixQ().adjoint() does not work
+ VERIFY_IS_APPROX(MatrixType(symmA.template selfadjointView<Lower>()), tridiag.matrixQ() * tridiag.matrixT().eval() * MatrixType(tridiag.matrixQ()).adjoint());
+
+ if (rows > 1)
+ {
+ // Test matrix with NaN
+ symmA(0,0) = std::numeric_limits<typename MatrixType::RealScalar>::quiet_NaN();
+ SelfAdjointEigenSolver<MatrixType> eiSymmNaN(symmA);
+ VERIFY_IS_EQUAL(eiSymmNaN.info(), NoConvergence);
+ }
+}
+
+void test_eigensolver_selfadjoint()
+{
+ int s;
+ for(int i = 0; i < g_repeat; i++) {
+ // very important to test 3x3 and 2x2 matrices since we provide special paths for them
+ CALL_SUBTEST_1( selfadjointeigensolver(Matrix2d()) );
+ CALL_SUBTEST_1( selfadjointeigensolver(Matrix3f()) );
+ CALL_SUBTEST_2( selfadjointeigensolver(Matrix4d()) );
+ s = internal::random<int>(1,EIGEN_TEST_MAX_SIZE/4);
+ CALL_SUBTEST_3( selfadjointeigensolver(MatrixXf(s,s)) );
+ s = internal::random<int>(1,EIGEN_TEST_MAX_SIZE/4);
+ CALL_SUBTEST_4( selfadjointeigensolver(MatrixXd(s,s)) );
+ s = internal::random<int>(1,EIGEN_TEST_MAX_SIZE/4);
+ CALL_SUBTEST_5( selfadjointeigensolver(MatrixXcd(s,s)) );
+
+ s = internal::random<int>(1,EIGEN_TEST_MAX_SIZE/4);
+ CALL_SUBTEST_9( selfadjointeigensolver(Matrix<std::complex<double>,Dynamic,Dynamic,RowMajor>(s,s)) );
+
+ // some trivial but implementation-wise tricky cases
+ CALL_SUBTEST_4( selfadjointeigensolver(MatrixXd(1,1)) );
+ CALL_SUBTEST_4( selfadjointeigensolver(MatrixXd(2,2)) );
+ CALL_SUBTEST_6( selfadjointeigensolver(Matrix<double,1,1>()) );
+ CALL_SUBTEST_7( selfadjointeigensolver(Matrix<double,2,2>()) );
+ }
+
+ // Test problem size constructors
+ s = internal::random<int>(1,EIGEN_TEST_MAX_SIZE/4);
+ CALL_SUBTEST_8(SelfAdjointEigenSolver<MatrixXf>(s));
+ CALL_SUBTEST_8(Tridiagonalization<MatrixXf>(s));
+
+ EIGEN_UNUSED_VARIABLE(s)
+}
+
diff --git a/test/exceptions.cpp b/test/exceptions.cpp
new file mode 100644
index 000000000..8c48b2f7b
--- /dev/null
+++ b/test/exceptions.cpp
@@ -0,0 +1,109 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra.
+//
+// Copyright (C) 2011 Gael Guennebaud <gael.guennebaud@inria.fr>
+//
+// This Source Code Form is subject to the terms of the Mozilla
+// Public License v. 2.0. If a copy of the MPL was not distributed
+// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+
+// Various sanity tests with exceptions:
+// - no memory leak when a custom scalar type trow an exceptions
+// - todo: complete the list of tests!
+
+#define EIGEN_STACK_ALLOCATION_LIMIT 100000000
+
+#include "main.h"
+
+struct my_exception
+{
+ my_exception() {}
+ ~my_exception() {}
+};
+
+class ScalarWithExceptions
+{
+ public:
+ ScalarWithExceptions() { init(); }
+ ScalarWithExceptions(const float& _v) { init(); *v = _v; }
+ ScalarWithExceptions(const ScalarWithExceptions& other) { init(); *v = *(other.v); }
+ ~ScalarWithExceptions() {
+ delete v;
+ instances--;
+ }
+
+ void init() {
+ v = new float;
+ instances++;
+ }
+
+ ScalarWithExceptions operator+(const ScalarWithExceptions& other) const
+ {
+ countdown--;
+ if(countdown<=0)
+ throw my_exception();
+ return ScalarWithExceptions(*v+*other.v);
+ }
+
+ ScalarWithExceptions operator-(const ScalarWithExceptions& other) const
+ { return ScalarWithExceptions(*v-*other.v); }
+
+ ScalarWithExceptions operator*(const ScalarWithExceptions& other) const
+ { return ScalarWithExceptions((*v)*(*other.v)); }
+
+ ScalarWithExceptions& operator+=(const ScalarWithExceptions& other)
+ { *v+=*other.v; return *this; }
+ ScalarWithExceptions& operator-=(const ScalarWithExceptions& other)
+ { *v-=*other.v; return *this; }
+ ScalarWithExceptions& operator=(const ScalarWithExceptions& other)
+ { *v = *(other.v); return *this; }
+
+ bool operator==(const ScalarWithExceptions& other) const
+ { return *v==*other.v; }
+ bool operator!=(const ScalarWithExceptions& other) const
+ { return *v!=*other.v; }
+
+ float* v;
+ static int instances;
+ static int countdown;
+};
+
+int ScalarWithExceptions::instances = 0;
+int ScalarWithExceptions::countdown = 0;
+
+
+#define CHECK_MEMLEAK(OP) { \
+ ScalarWithExceptions::countdown = 100; \
+ int before = ScalarWithExceptions::instances; \
+ bool exception_thrown = false; \
+ try { OP; } \
+ catch (my_exception) { \
+ exception_thrown = true; \
+ VERIFY(ScalarWithExceptions::instances==before && "memory leak detected in " && EIGEN_MAKESTRING(OP)); \
+ } \
+ VERIFY(exception_thrown && " no exception thrown in " && EIGEN_MAKESTRING(OP)); \
+ }
+
+void memoryleak()
+{
+ typedef Eigen::Matrix<ScalarWithExceptions,Dynamic,1> VectorType;
+ typedef Eigen::Matrix<ScalarWithExceptions,Dynamic,Dynamic> MatrixType;
+
+ {
+ int n = 50;
+ VectorType v0(n), v1(n);
+ MatrixType m0(n,n), m1(n,n), m2(n,n);
+ v0.setOnes(); v1.setOnes();
+ m0.setOnes(); m1.setOnes(); m2.setOnes();
+ CHECK_MEMLEAK(v0 = m0 * m1 * v1);
+ CHECK_MEMLEAK(m2 = m0 * m1 * m2);
+ CHECK_MEMLEAK((v0+v1).dot(v0+v1));
+ }
+ VERIFY(ScalarWithExceptions::instances==0 && "global memory leak detected in " && EIGEN_MAKESTRING(OP)); \
+}
+
+void test_exceptions()
+{
+ CALL_SUBTEST( memoryleak() );
+}
diff --git a/test/first_aligned.cpp b/test/first_aligned.cpp
new file mode 100644
index 000000000..467f94510
--- /dev/null
+++ b/test/first_aligned.cpp
@@ -0,0 +1,51 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra.
+//
+// Copyright (C) 2009 Benoit Jacob <jacob.benoit.1@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 "main.h"
+
+template<typename Scalar>
+void test_first_aligned_helper(Scalar *array, int size)
+{
+ const int packet_size = sizeof(Scalar) * internal::packet_traits<Scalar>::size;
+ VERIFY(((size_t(array) + sizeof(Scalar) * internal::first_aligned(array, size)) % packet_size) == 0);
+}
+
+template<typename Scalar>
+void test_none_aligned_helper(Scalar *array, int size)
+{
+ EIGEN_UNUSED_VARIABLE(array);
+ EIGEN_UNUSED_VARIABLE(size);
+ VERIFY(internal::packet_traits<Scalar>::size == 1 || internal::first_aligned(array, size) == size);
+}
+
+struct some_non_vectorizable_type { float x; };
+
+void test_first_aligned()
+{
+ EIGEN_ALIGN16 float array_float[100];
+ test_first_aligned_helper(array_float, 50);
+ test_first_aligned_helper(array_float+1, 50);
+ test_first_aligned_helper(array_float+2, 50);
+ test_first_aligned_helper(array_float+3, 50);
+ test_first_aligned_helper(array_float+4, 50);
+ test_first_aligned_helper(array_float+5, 50);
+
+ EIGEN_ALIGN16 double array_double[100];
+ test_first_aligned_helper(array_double, 50);
+ test_first_aligned_helper(array_double+1, 50);
+ test_first_aligned_helper(array_double+2, 50);
+
+ double *array_double_plus_4_bytes = (double*)(size_t(array_double)+4);
+ test_none_aligned_helper(array_double_plus_4_bytes, 50);
+ test_none_aligned_helper(array_double_plus_4_bytes+1, 50);
+
+ some_non_vectorizable_type array_nonvec[100];
+ test_first_aligned_helper(array_nonvec, 100);
+ test_none_aligned_helper(array_nonvec, 100);
+}
diff --git a/test/geo_alignedbox.cpp b/test/geo_alignedbox.cpp
new file mode 100644
index 000000000..5886f9181
--- /dev/null
+++ b/test/geo_alignedbox.cpp
@@ -0,0 +1,171 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra.
+//
+// Copyright (C) 2008-2009 Gael Guennebaud <gael.guennebaud@inria.fr>
+//
+// This Source Code Form is subject to the terms of the Mozilla
+// Public License v. 2.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 "main.h"
+#include <Eigen/Geometry>
+#include <Eigen/LU>
+#include <Eigen/QR>
+
+#include<iostream>
+using namespace std;
+
+template<typename BoxType> void alignedbox(const BoxType& _box)
+{
+ /* this test covers the following files:
+ AlignedBox.h
+ */
+ typedef typename BoxType::Index Index;
+ typedef typename BoxType::Scalar Scalar;
+ typedef typename NumTraits<Scalar>::Real RealScalar;
+ typedef Matrix<Scalar, BoxType::AmbientDimAtCompileTime, 1> VectorType;
+
+ const Index dim = _box.dim();
+
+ VectorType p0 = VectorType::Random(dim);
+ VectorType p1 = VectorType::Random(dim);
+ while( p1 == p0 ){
+ p1 = VectorType::Random(dim); }
+ RealScalar s1 = internal::random<RealScalar>(0,1);
+
+ BoxType b0(dim);
+ BoxType b1(VectorType::Random(dim),VectorType::Random(dim));
+ BoxType b2;
+
+ b0.extend(p0);
+ b0.extend(p1);
+ VERIFY(b0.contains(p0*s1+(Scalar(1)-s1)*p1));
+
+ (b2 = b0).extend(b1);
+ VERIFY(b2.contains(b0));
+ VERIFY(b2.contains(b1));
+ VERIFY_IS_APPROX(b2.clamp(b0), b0);
+
+
+ // alignment -- make sure there is no memory alignment assertion
+ BoxType *bp0 = new BoxType(dim);
+ BoxType *bp1 = new BoxType(dim);
+ bp0->extend(*bp1);
+ delete bp0;
+ delete bp1;
+
+ // sampling
+ for( int i=0; i<10; ++i )
+ {
+ VectorType r = b0.sample();
+ VERIFY(b0.contains(r));
+ }
+
+}
+
+
+
+template<typename BoxType>
+void alignedboxCastTests(const BoxType& _box)
+{
+ // casting
+ typedef typename BoxType::Index Index;
+ typedef typename BoxType::Scalar Scalar;
+ typedef typename NumTraits<Scalar>::Real RealScalar;
+ typedef Matrix<Scalar, BoxType::AmbientDimAtCompileTime, 1> VectorType;
+
+ const Index dim = _box.dim();
+
+ VectorType p0 = VectorType::Random(dim);
+ VectorType p1 = VectorType::Random(dim);
+
+ BoxType b0(dim);
+
+ b0.extend(p0);
+ b0.extend(p1);
+
+ const int Dim = BoxType::AmbientDimAtCompileTime;
+ typedef typename GetDifferentType<Scalar>::type OtherScalar;
+ AlignedBox<OtherScalar,Dim> hp1f = b0.template cast<OtherScalar>();
+ VERIFY_IS_APPROX(hp1f.template cast<Scalar>(),b0);
+ AlignedBox<Scalar,Dim> hp1d = b0.template cast<Scalar>();
+ VERIFY_IS_APPROX(hp1d.template cast<Scalar>(),b0);
+}
+
+
+void specificTest1()
+{
+ Vector2f m; m << -1.0f, -2.0f;
+ Vector2f M; M << 1.0f, 5.0f;
+
+ typedef AlignedBox2f BoxType;
+ BoxType box( m, M );
+
+ Vector2f sides = M-m;
+ VERIFY_IS_APPROX(sides, box.sizes() );
+ VERIFY_IS_APPROX(sides[1], box.sizes()[1] );
+ VERIFY_IS_APPROX(sides[1], box.sizes().maxCoeff() );
+ VERIFY_IS_APPROX(sides[0], box.sizes().minCoeff() );
+
+ VERIFY_IS_APPROX( 14.0f, box.volume() );
+ VERIFY_IS_APPROX( 53.0f, box.diagonal().squaredNorm() );
+ VERIFY_IS_APPROX( internal::sqrt( 53.0f ), box.diagonal().norm() );
+
+ VERIFY_IS_APPROX( m, box.corner( BoxType::BottomLeft ) );
+ VERIFY_IS_APPROX( M, box.corner( BoxType::TopRight ) );
+ Vector2f bottomRight; bottomRight << M[0], m[1];
+ Vector2f topLeft; topLeft << m[0], M[1];
+ VERIFY_IS_APPROX( bottomRight, box.corner( BoxType::BottomRight ) );
+ VERIFY_IS_APPROX( topLeft, box.corner( BoxType::TopLeft ) );
+}
+
+
+void specificTest2()
+{
+ Vector3i m; m << -1, -2, 0;
+ Vector3i M; M << 1, 5, 3;
+
+ typedef AlignedBox3i BoxType;
+ BoxType box( m, M );
+
+ Vector3i sides = M-m;
+ VERIFY_IS_APPROX(sides, box.sizes() );
+ VERIFY_IS_APPROX(sides[1], box.sizes()[1] );
+ VERIFY_IS_APPROX(sides[1], box.sizes().maxCoeff() );
+ VERIFY_IS_APPROX(sides[0], box.sizes().minCoeff() );
+
+ VERIFY_IS_APPROX( 42, box.volume() );
+ VERIFY_IS_APPROX( 62, box.diagonal().squaredNorm() );
+
+ VERIFY_IS_APPROX( m, box.corner( BoxType::BottomLeftFloor ) );
+ VERIFY_IS_APPROX( M, box.corner( BoxType::TopRightCeil ) );
+ Vector3i bottomRightFloor; bottomRightFloor << M[0], m[1], m[2];
+ Vector3i topLeftFloor; topLeftFloor << m[0], M[1], m[2];
+ VERIFY_IS_APPROX( bottomRightFloor, box.corner( BoxType::BottomRightFloor ) );
+ VERIFY_IS_APPROX( topLeftFloor, box.corner( BoxType::TopLeftFloor ) );
+}
+
+
+void test_geo_alignedbox()
+{
+ for(int i = 0; i < g_repeat; i++)
+ {
+ CALL_SUBTEST_1( alignedbox(AlignedBox2f()) );
+ CALL_SUBTEST_2( alignedboxCastTests(AlignedBox2f()) );
+
+ CALL_SUBTEST_3( alignedbox(AlignedBox3f()) );
+ CALL_SUBTEST_4( alignedboxCastTests(AlignedBox3f()) );
+
+ CALL_SUBTEST_5( alignedbox(AlignedBox4d()) );
+ CALL_SUBTEST_6( alignedboxCastTests(AlignedBox4d()) );
+
+ CALL_SUBTEST_7( alignedbox(AlignedBox1d()) );
+ CALL_SUBTEST_8( alignedboxCastTests(AlignedBox1d()) );
+
+ CALL_SUBTEST_9( alignedbox(AlignedBox1i()) );
+ CALL_SUBTEST_10( alignedbox(AlignedBox2i()) );
+ CALL_SUBTEST_11( alignedbox(AlignedBox3i()) );
+ }
+ CALL_SUBTEST_12( specificTest1() );
+ CALL_SUBTEST_13( specificTest2() );
+}
diff --git a/test/geo_eulerangles.cpp b/test/geo_eulerangles.cpp
new file mode 100644
index 000000000..9bf149d2a
--- /dev/null
+++ b/test/geo_eulerangles.cpp
@@ -0,0 +1,54 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra.
+//
+// Copyright (C) 2008-2009 Gael Guennebaud <gael.guennebaud@inria.fr>
+//
+// This Source Code Form is subject to the terms of the Mozilla
+// Public License v. 2.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 "main.h"
+#include <Eigen/Geometry>
+#include <Eigen/LU>
+#include <Eigen/SVD>
+
+template<typename Scalar> void eulerangles(void)
+{
+ typedef Matrix<Scalar,3,3> Matrix3;
+ typedef Matrix<Scalar,3,1> Vector3;
+ typedef Quaternion<Scalar> Quaternionx;
+ typedef AngleAxis<Scalar> AngleAxisx;
+
+ Scalar a = internal::random<Scalar>(-Scalar(M_PI), Scalar(M_PI));
+ Quaternionx q1;
+ q1 = AngleAxisx(a, Vector3::Random().normalized());
+ Matrix3 m;
+ m = q1;
+
+ #define VERIFY_EULER(I,J,K, X,Y,Z) { \
+ Vector3 ea = m.eulerAngles(I,J,K); \
+ VERIFY_IS_APPROX(m, Matrix3(AngleAxisx(ea[0], Vector3::Unit##X()) * AngleAxisx(ea[1], Vector3::Unit##Y()) * AngleAxisx(ea[2], Vector3::Unit##Z()))); \
+ }
+ VERIFY_EULER(0,1,2, X,Y,Z);
+ VERIFY_EULER(0,1,0, X,Y,X);
+ VERIFY_EULER(0,2,1, X,Z,Y);
+ VERIFY_EULER(0,2,0, X,Z,X);
+
+ VERIFY_EULER(1,2,0, Y,Z,X);
+ VERIFY_EULER(1,2,1, Y,Z,Y);
+ VERIFY_EULER(1,0,2, Y,X,Z);
+ VERIFY_EULER(1,0,1, Y,X,Y);
+
+ VERIFY_EULER(2,0,1, Z,X,Y);
+ VERIFY_EULER(2,0,2, Z,X,Z);
+ VERIFY_EULER(2,1,0, Z,Y,X);
+ VERIFY_EULER(2,1,2, Z,Y,Z);
+}
+
+void test_geo_eulerangles()
+{
+ for(int i = 0; i < g_repeat; i++) {
+ CALL_SUBTEST_1( eulerangles<float>() );
+ CALL_SUBTEST_2( eulerangles<double>() );
+ }
+}
diff --git a/test/geo_homogeneous.cpp b/test/geo_homogeneous.cpp
new file mode 100644
index 000000000..c91bde819
--- /dev/null
+++ b/test/geo_homogeneous.cpp
@@ -0,0 +1,103 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra.
+//
+// Copyright (C) 2009 Gael Guennebaud <gael.guennebaud@inria.fr>
+//
+// This Source Code Form is subject to the terms of the Mozilla
+// Public License v. 2.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 "main.h"
+#include <Eigen/Geometry>
+
+template<typename Scalar,int Size> void homogeneous(void)
+{
+ /* this test covers the following files:
+ Homogeneous.h
+ */
+
+ typedef Matrix<Scalar,Size,Size> MatrixType;
+ typedef Matrix<Scalar,Size,1, ColMajor> VectorType;
+
+ typedef Matrix<Scalar,Size+1,Size> HMatrixType;
+ typedef Matrix<Scalar,Size+1,1> HVectorType;
+
+ typedef Matrix<Scalar,Size,Size+1> T1MatrixType;
+ typedef Matrix<Scalar,Size+1,Size+1> T2MatrixType;
+ typedef Matrix<Scalar,Size+1,Size> T3MatrixType;
+
+ VectorType v0 = VectorType::Random(),
+ ones = VectorType::Ones();
+
+ HVectorType hv0 = HVectorType::Random();
+
+ MatrixType m0 = MatrixType::Random();
+
+ HMatrixType hm0 = HMatrixType::Random();
+
+ hv0 << v0, 1;
+ VERIFY_IS_APPROX(v0.homogeneous(), hv0);
+ VERIFY_IS_APPROX(v0, hv0.hnormalized());
+
+ hm0 << m0, ones.transpose();
+ VERIFY_IS_APPROX(m0.colwise().homogeneous(), hm0);
+ VERIFY_IS_APPROX(m0, hm0.colwise().hnormalized());
+ hm0.row(Size-1).setRandom();
+ for(int j=0; j<Size; ++j)
+ m0.col(j) = hm0.col(j).head(Size) / hm0(Size,j);
+ VERIFY_IS_APPROX(m0, hm0.colwise().hnormalized());
+
+ T1MatrixType t1 = T1MatrixType::Random();
+ VERIFY_IS_APPROX(t1 * (v0.homogeneous().eval()), t1 * v0.homogeneous());
+ VERIFY_IS_APPROX(t1 * (m0.colwise().homogeneous().eval()), t1 * m0.colwise().homogeneous());
+
+ T2MatrixType t2 = T2MatrixType::Random();
+ VERIFY_IS_APPROX(t2 * (v0.homogeneous().eval()), t2 * v0.homogeneous());
+ VERIFY_IS_APPROX(t2 * (m0.colwise().homogeneous().eval()), t2 * m0.colwise().homogeneous());
+
+ VERIFY_IS_APPROX((v0.transpose().rowwise().homogeneous().eval()) * t2,
+ v0.transpose().rowwise().homogeneous() * t2);
+ m0.transpose().rowwise().homogeneous().eval();
+ VERIFY_IS_APPROX((m0.transpose().rowwise().homogeneous().eval()) * t2,
+ m0.transpose().rowwise().homogeneous() * t2);
+
+ T3MatrixType t3 = T3MatrixType::Random();
+ VERIFY_IS_APPROX((v0.transpose().rowwise().homogeneous().eval()) * t3,
+ v0.transpose().rowwise().homogeneous() * t3);
+ VERIFY_IS_APPROX((m0.transpose().rowwise().homogeneous().eval()) * t3,
+ m0.transpose().rowwise().homogeneous() * t3);
+
+ // test product with a Transform object
+ Transform<Scalar, Size, Affine> aff;
+ Transform<Scalar, Size, AffineCompact> caff;
+ Transform<Scalar, Size, Projective> proj;
+ Matrix<Scalar, Size, Dynamic> pts;
+ Matrix<Scalar, Size+1, Dynamic> pts1, pts2;
+
+ aff.affine().setRandom();
+ proj = caff = aff;
+ pts.setRandom(Size,internal::random<int>(1,20));
+
+ pts1 = pts.colwise().homogeneous();
+ VERIFY_IS_APPROX(aff * pts.colwise().homogeneous(), (aff * pts1).colwise().hnormalized());
+ VERIFY_IS_APPROX(caff * pts.colwise().homogeneous(), (caff * pts1).colwise().hnormalized());
+ VERIFY_IS_APPROX(proj * pts.colwise().homogeneous(), (proj * pts1));
+
+ VERIFY_IS_APPROX((aff * pts1).colwise().hnormalized(), aff * pts);
+ VERIFY_IS_APPROX((caff * pts1).colwise().hnormalized(), caff * pts);
+
+ pts2 = pts1;
+ pts2.row(Size).setRandom();
+ VERIFY_IS_APPROX((aff * pts2).colwise().hnormalized(), aff * pts2.colwise().hnormalized());
+ VERIFY_IS_APPROX((caff * pts2).colwise().hnormalized(), caff * pts2.colwise().hnormalized());
+ VERIFY_IS_APPROX((proj * pts2).colwise().hnormalized(), (proj * pts2.colwise().hnormalized().colwise().homogeneous()).colwise().hnormalized());
+}
+
+void test_geo_homogeneous()
+{
+ for(int i = 0; i < g_repeat; i++) {
+ CALL_SUBTEST_1(( homogeneous<float,1>() ));
+ CALL_SUBTEST_2(( homogeneous<double,3>() ));
+ CALL_SUBTEST_3(( homogeneous<double,8>() ));
+ }
+}
diff --git a/test/geo_hyperplane.cpp b/test/geo_hyperplane.cpp
new file mode 100644
index 000000000..3fc80c4c7
--- /dev/null
+++ b/test/geo_hyperplane.cpp
@@ -0,0 +1,157 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra.
+//
+// Copyright (C) 2008 Gael Guennebaud <gael.guennebaud@inria.fr>
+// Copyright (C) 2008 Benoit Jacob <jacob.benoit.1@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 "main.h"
+#include <Eigen/Geometry>
+#include <Eigen/LU>
+#include <Eigen/QR>
+
+template<typename HyperplaneType> void hyperplane(const HyperplaneType& _plane)
+{
+ /* this test covers the following files:
+ Hyperplane.h
+ */
+ typedef typename HyperplaneType::Index Index;
+ const Index dim = _plane.dim();
+ enum { Options = HyperplaneType::Options };
+ typedef typename HyperplaneType::Scalar Scalar;
+ typedef typename NumTraits<Scalar>::Real RealScalar;
+ typedef Matrix<Scalar, HyperplaneType::AmbientDimAtCompileTime, 1> VectorType;
+ typedef Matrix<Scalar, HyperplaneType::AmbientDimAtCompileTime,
+ HyperplaneType::AmbientDimAtCompileTime> MatrixType;
+
+ VectorType p0 = VectorType::Random(dim);
+ VectorType p1 = VectorType::Random(dim);
+
+ VectorType n0 = VectorType::Random(dim).normalized();
+ VectorType n1 = VectorType::Random(dim).normalized();
+
+ HyperplaneType pl0(n0, p0);
+ HyperplaneType pl1(n1, p1);
+ HyperplaneType pl2 = pl1;
+
+ Scalar s0 = internal::random<Scalar>();
+ Scalar s1 = internal::random<Scalar>();
+
+ VERIFY_IS_APPROX( n1.dot(n1), Scalar(1) );
+
+ VERIFY_IS_MUCH_SMALLER_THAN( pl0.absDistance(p0), Scalar(1) );
+ VERIFY_IS_APPROX( pl1.signedDistance(p1 + n1 * s0), s0 );
+ VERIFY_IS_MUCH_SMALLER_THAN( pl1.signedDistance(pl1.projection(p0)), Scalar(1) );
+ VERIFY_IS_MUCH_SMALLER_THAN( pl1.absDistance(p1 + pl1.normal().unitOrthogonal() * s1), Scalar(1) );
+
+ // transform
+ if (!NumTraits<Scalar>::IsComplex)
+ {
+ MatrixType rot = MatrixType::Random(dim,dim).householderQr().householderQ();
+ DiagonalMatrix<Scalar,HyperplaneType::AmbientDimAtCompileTime> scaling(VectorType::Random());
+ Translation<Scalar,HyperplaneType::AmbientDimAtCompileTime> translation(VectorType::Random());
+
+ pl2 = pl1;
+ VERIFY_IS_MUCH_SMALLER_THAN( pl2.transform(rot).absDistance(rot * p1), Scalar(1) );
+ pl2 = pl1;
+ VERIFY_IS_MUCH_SMALLER_THAN( pl2.transform(rot,Isometry).absDistance(rot * p1), Scalar(1) );
+ pl2 = pl1;
+ VERIFY_IS_MUCH_SMALLER_THAN( pl2.transform(rot*scaling).absDistance((rot*scaling) * p1), Scalar(1) );
+ pl2 = pl1;
+ VERIFY_IS_MUCH_SMALLER_THAN( pl2.transform(rot*scaling*translation)
+ .absDistance((rot*scaling*translation) * p1), Scalar(1) );
+ pl2 = pl1;
+ VERIFY_IS_MUCH_SMALLER_THAN( pl2.transform(rot*translation,Isometry)
+ .absDistance((rot*translation) * p1), Scalar(1) );
+ }
+
+ // casting
+ const int Dim = HyperplaneType::AmbientDimAtCompileTime;
+ typedef typename GetDifferentType<Scalar>::type OtherScalar;
+ Hyperplane<OtherScalar,Dim,Options> hp1f = pl1.template cast<OtherScalar>();
+ VERIFY_IS_APPROX(hp1f.template cast<Scalar>(),pl1);
+ Hyperplane<Scalar,Dim,Options> hp1d = pl1.template cast<Scalar>();
+ VERIFY_IS_APPROX(hp1d.template cast<Scalar>(),pl1);
+}
+
+template<typename Scalar> void lines()
+{
+ typedef Hyperplane<Scalar, 2> HLine;
+ typedef ParametrizedLine<Scalar, 2> PLine;
+ typedef Matrix<Scalar,2,1> Vector;
+ typedef Matrix<Scalar,3,1> CoeffsType;
+
+ for(int i = 0; i < 10; i++)
+ {
+ Vector center = Vector::Random();
+ Vector u = Vector::Random();
+ Vector v = Vector::Random();
+ Scalar a = internal::random<Scalar>();
+ while (internal::abs(a-1) < 1e-4) a = internal::random<Scalar>();
+ while (u.norm() < 1e-4) u = Vector::Random();
+ while (v.norm() < 1e-4) v = Vector::Random();
+
+ HLine line_u = HLine::Through(center + u, center + a*u);
+ HLine line_v = HLine::Through(center + v, center + a*v);
+
+ // the line equations should be normalized so that a^2+b^2=1
+ VERIFY_IS_APPROX(line_u.normal().norm(), Scalar(1));
+ VERIFY_IS_APPROX(line_v.normal().norm(), Scalar(1));
+
+ Vector result = line_u.intersection(line_v);
+
+ // the lines should intersect at the point we called "center"
+ VERIFY_IS_APPROX(result, center);
+
+ // check conversions between two types of lines
+ PLine pl(line_u); // gcc 3.3 will commit suicide if we don't name this variable
+ CoeffsType converted_coeffs = HLine(pl).coeffs();
+ converted_coeffs *= (line_u.coeffs()[0])/(converted_coeffs[0]);
+ VERIFY(line_u.coeffs().isApprox(converted_coeffs));
+ }
+}
+
+template<typename Scalar> void hyperplane_alignment()
+{
+ typedef Hyperplane<Scalar,3,AutoAlign> Plane3a;
+ typedef Hyperplane<Scalar,3,DontAlign> Plane3u;
+
+ EIGEN_ALIGN16 Scalar array1[4];
+ EIGEN_ALIGN16 Scalar array2[4];
+ EIGEN_ALIGN16 Scalar array3[4+1];
+ Scalar* array3u = array3+1;
+
+ Plane3a *p1 = ::new(reinterpret_cast<void*>(array1)) Plane3a;
+ Plane3u *p2 = ::new(reinterpret_cast<void*>(array2)) Plane3u;
+ Plane3u *p3 = ::new(reinterpret_cast<void*>(array3u)) Plane3u;
+
+ p1->coeffs().setRandom();
+ *p2 = *p1;
+ *p3 = *p1;
+
+ VERIFY_IS_APPROX(p1->coeffs(), p2->coeffs());
+ VERIFY_IS_APPROX(p1->coeffs(), p3->coeffs());
+
+ #if defined(EIGEN_VECTORIZE) && EIGEN_ALIGN_STATICALLY
+ if(internal::packet_traits<Scalar>::Vectorizable)
+ VERIFY_RAISES_ASSERT((::new(reinterpret_cast<void*>(array3u)) Plane3a));
+ #endif
+}
+
+
+void test_geo_hyperplane()
+{
+ for(int i = 0; i < g_repeat; i++) {
+ CALL_SUBTEST_1( hyperplane(Hyperplane<float,2>()) );
+ CALL_SUBTEST_2( hyperplane(Hyperplane<float,3>()) );
+ CALL_SUBTEST_2( hyperplane(Hyperplane<float,3,DontAlign>()) );
+ CALL_SUBTEST_2( hyperplane_alignment<float>() );
+ CALL_SUBTEST_3( hyperplane(Hyperplane<double,4>()) );
+ CALL_SUBTEST_4( hyperplane(Hyperplane<std::complex<double>,5>()) );
+ CALL_SUBTEST_1( lines<float>() );
+ CALL_SUBTEST_3( lines<double>() );
+ }
+}
diff --git a/test/geo_orthomethods.cpp b/test/geo_orthomethods.cpp
new file mode 100644
index 000000000..c836dae40
--- /dev/null
+++ b/test/geo_orthomethods.cpp
@@ -0,0 +1,121 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra.
+//
+// Copyright (C) 2008-2009 Gael Guennebaud <gael.guennebaud@inria.fr>
+//
+// This Source Code Form is subject to the terms of the Mozilla
+// Public License v. 2.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 "main.h"
+#include <Eigen/Geometry>
+#include <Eigen/LU>
+#include <Eigen/SVD>
+
+/* this test covers the following files:
+ Geometry/OrthoMethods.h
+*/
+
+template<typename Scalar> void orthomethods_3()
+{
+ typedef typename NumTraits<Scalar>::Real RealScalar;
+ typedef Matrix<Scalar,3,3> Matrix3;
+ typedef Matrix<Scalar,3,1> Vector3;
+
+ typedef Matrix<Scalar,4,1> Vector4;
+
+ Vector3 v0 = Vector3::Random(),
+ v1 = Vector3::Random(),
+ v2 = Vector3::Random();
+
+ // cross product
+ VERIFY_IS_MUCH_SMALLER_THAN(v1.cross(v2).dot(v1), Scalar(1));
+ VERIFY_IS_MUCH_SMALLER_THAN(v1.dot(v1.cross(v2)), Scalar(1));
+ VERIFY_IS_MUCH_SMALLER_THAN(v1.cross(v2).dot(v2), Scalar(1));
+ VERIFY_IS_MUCH_SMALLER_THAN(v2.dot(v1.cross(v2)), Scalar(1));
+ Matrix3 mat3;
+ mat3 << v0.normalized(),
+ (v0.cross(v1)).normalized(),
+ (v0.cross(v1).cross(v0)).normalized();
+ VERIFY(mat3.isUnitary());
+
+
+ // colwise/rowwise cross product
+ mat3.setRandom();
+ Vector3 vec3 = Vector3::Random();
+ Matrix3 mcross;
+ int i = internal::random<int>(0,2);
+ mcross = mat3.colwise().cross(vec3);
+ VERIFY_IS_APPROX(mcross.col(i), mat3.col(i).cross(vec3));
+ mcross = mat3.rowwise().cross(vec3);
+ VERIFY_IS_APPROX(mcross.row(i), mat3.row(i).cross(vec3));
+
+ // cross3
+ Vector4 v40 = Vector4::Random(),
+ v41 = Vector4::Random(),
+ v42 = Vector4::Random();
+ v40.w() = v41.w() = v42.w() = 0;
+ v42.template head<3>() = v40.template head<3>().cross(v41.template head<3>());
+ VERIFY_IS_APPROX(v40.cross3(v41), v42);
+
+ // check mixed product
+ typedef Matrix<RealScalar, 3, 1> RealVector3;
+ RealVector3 rv1 = RealVector3::Random();
+ VERIFY_IS_APPROX(v1.cross(rv1.template cast<Scalar>()), v1.cross(rv1));
+ VERIFY_IS_APPROX(rv1.template cast<Scalar>().cross(v1), rv1.cross(v1));
+}
+
+template<typename Scalar, int Size> void orthomethods(int size=Size)
+{
+ typedef typename NumTraits<Scalar>::Real RealScalar;
+ typedef Matrix<Scalar,Size,1> VectorType;
+ typedef Matrix<Scalar,3,Size> Matrix3N;
+ typedef Matrix<Scalar,Size,3> MatrixN3;
+ typedef Matrix<Scalar,3,1> Vector3;
+
+ VectorType v0 = VectorType::Random(size);
+
+ // unitOrthogonal
+ VERIFY_IS_MUCH_SMALLER_THAN(v0.unitOrthogonal().dot(v0), Scalar(1));
+ VERIFY_IS_APPROX(v0.unitOrthogonal().norm(), RealScalar(1));
+
+ if (size>=3)
+ {
+ v0.template head<2>().setZero();
+ v0.tail(size-2).setRandom();
+
+ VERIFY_IS_MUCH_SMALLER_THAN(v0.unitOrthogonal().dot(v0), Scalar(1));
+ VERIFY_IS_APPROX(v0.unitOrthogonal().norm(), RealScalar(1));
+ }
+
+ // colwise/rowwise cross product
+ Vector3 vec3 = Vector3::Random();
+ int i = internal::random<int>(0,size-1);
+
+ Matrix3N mat3N(3,size), mcross3N(3,size);
+ mat3N.setRandom();
+ mcross3N = mat3N.colwise().cross(vec3);
+ VERIFY_IS_APPROX(mcross3N.col(i), mat3N.col(i).cross(vec3));
+
+ MatrixN3 matN3(size,3), mcrossN3(size,3);
+ matN3.setRandom();
+ mcrossN3 = matN3.rowwise().cross(vec3);
+ VERIFY_IS_APPROX(mcrossN3.row(i), matN3.row(i).cross(vec3));
+}
+
+void test_geo_orthomethods()
+{
+ for(int i = 0; i < g_repeat; i++) {
+ CALL_SUBTEST_1( orthomethods_3<float>() );
+ CALL_SUBTEST_2( orthomethods_3<double>() );
+ CALL_SUBTEST_4( orthomethods_3<std::complex<double> >() );
+ CALL_SUBTEST_1( (orthomethods<float,2>()) );
+ CALL_SUBTEST_2( (orthomethods<double,2>()) );
+ CALL_SUBTEST_1( (orthomethods<float,3>()) );
+ CALL_SUBTEST_2( (orthomethods<double,3>()) );
+ CALL_SUBTEST_3( (orthomethods<float,7>()) );
+ CALL_SUBTEST_4( (orthomethods<std::complex<double>,8>()) );
+ CALL_SUBTEST_5( (orthomethods<float,Dynamic>(36)) );
+ CALL_SUBTEST_6( (orthomethods<double,Dynamic>(35)) );
+ }
+}
diff --git a/test/geo_parametrizedline.cpp b/test/geo_parametrizedline.cpp
new file mode 100644
index 000000000..4e1f845dd
--- /dev/null
+++ b/test/geo_parametrizedline.cpp
@@ -0,0 +1,105 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra.
+//
+// Copyright (C) 2008 Gael Guennebaud <gael.guennebaud@inria.fr>
+// Copyright (C) 2008 Benoit Jacob <jacob.benoit.1@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 "main.h"
+#include <Eigen/Geometry>
+#include <Eigen/LU>
+#include <Eigen/QR>
+
+template<typename LineType> void parametrizedline(const LineType& _line)
+{
+ /* this test covers the following files:
+ ParametrizedLine.h
+ */
+ typedef typename LineType::Index Index;
+ const Index dim = _line.dim();
+ typedef typename LineType::Scalar Scalar;
+ typedef typename NumTraits<Scalar>::Real RealScalar;
+ typedef Matrix<Scalar, LineType::AmbientDimAtCompileTime, 1> VectorType;
+ typedef Matrix<Scalar, LineType::AmbientDimAtCompileTime,
+ LineType::AmbientDimAtCompileTime> MatrixType;
+ typedef Hyperplane<Scalar,LineType::AmbientDimAtCompileTime> HyperplaneType;
+
+ VectorType p0 = VectorType::Random(dim);
+ VectorType p1 = VectorType::Random(dim);
+
+ VectorType d0 = VectorType::Random(dim).normalized();
+
+ LineType l0(p0, d0);
+
+ Scalar s0 = internal::random<Scalar>();
+ Scalar s1 = internal::abs(internal::random<Scalar>());
+
+ VERIFY_IS_MUCH_SMALLER_THAN( l0.distance(p0), RealScalar(1) );
+ VERIFY_IS_MUCH_SMALLER_THAN( l0.distance(p0+s0*d0), RealScalar(1) );
+ VERIFY_IS_APPROX( (l0.projection(p1)-p1).norm(), l0.distance(p1) );
+ VERIFY_IS_MUCH_SMALLER_THAN( l0.distance(l0.projection(p1)), RealScalar(1) );
+ VERIFY_IS_APPROX( Scalar(l0.distance((p0+s0*d0) + d0.unitOrthogonal() * s1)), s1 );
+
+ // casting
+ const int Dim = LineType::AmbientDimAtCompileTime;
+ typedef typename GetDifferentType<Scalar>::type OtherScalar;
+ ParametrizedLine<OtherScalar,Dim> hp1f = l0.template cast<OtherScalar>();
+ VERIFY_IS_APPROX(hp1f.template cast<Scalar>(),l0);
+ ParametrizedLine<Scalar,Dim> hp1d = l0.template cast<Scalar>();
+ VERIFY_IS_APPROX(hp1d.template cast<Scalar>(),l0);
+
+ // intersections
+ VectorType p2 = VectorType::Random(dim);
+ VectorType n2 = VectorType::Random(dim).normalized();
+ HyperplaneType hp(p2,n2);
+ Scalar t = l0.intersectionParameter(hp);
+ VectorType pi = l0.pointAt(t);
+ VERIFY_IS_MUCH_SMALLER_THAN(hp.signedDistance(pi), RealScalar(1));
+ VERIFY_IS_MUCH_SMALLER_THAN(l0.distance(pi), RealScalar(1));
+ VERIFY_IS_APPROX(l0.intersectionPoint(hp), pi);
+}
+
+template<typename Scalar> void parametrizedline_alignment()
+{
+ typedef ParametrizedLine<Scalar,4,AutoAlign> Line4a;
+ typedef ParametrizedLine<Scalar,4,DontAlign> Line4u;
+
+ EIGEN_ALIGN16 Scalar array1[8];
+ EIGEN_ALIGN16 Scalar array2[8];
+ EIGEN_ALIGN16 Scalar array3[8+1];
+ Scalar* array3u = array3+1;
+
+ Line4a *p1 = ::new(reinterpret_cast<void*>(array1)) Line4a;
+ Line4u *p2 = ::new(reinterpret_cast<void*>(array2)) Line4u;
+ Line4u *p3 = ::new(reinterpret_cast<void*>(array3u)) Line4u;
+
+ p1->origin().setRandom();
+ p1->direction().setRandom();
+ *p2 = *p1;
+ *p3 = *p1;
+
+ VERIFY_IS_APPROX(p1->origin(), p2->origin());
+ VERIFY_IS_APPROX(p1->origin(), p3->origin());
+ VERIFY_IS_APPROX(p1->direction(), p2->direction());
+ VERIFY_IS_APPROX(p1->direction(), p3->direction());
+
+ #if defined(EIGEN_VECTORIZE) && EIGEN_ALIGN_STATICALLY
+ if(internal::packet_traits<Scalar>::Vectorizable)
+ VERIFY_RAISES_ASSERT((::new(reinterpret_cast<void*>(array3u)) Line4a));
+ #endif
+}
+
+void test_geo_parametrizedline()
+{
+ for(int i = 0; i < g_repeat; i++) {
+ CALL_SUBTEST_1( parametrizedline(ParametrizedLine<float,2>()) );
+ CALL_SUBTEST_2( parametrizedline(ParametrizedLine<float,3>()) );
+ CALL_SUBTEST_2( parametrizedline_alignment<float>() );
+ CALL_SUBTEST_3( parametrizedline(ParametrizedLine<double,4>()) );
+ CALL_SUBTEST_3( parametrizedline_alignment<double>() );
+ CALL_SUBTEST_4( parametrizedline(ParametrizedLine<std::complex<double>,5>()) );
+ }
+}
diff --git a/test/geo_quaternion.cpp b/test/geo_quaternion.cpp
new file mode 100644
index 000000000..6e6922864
--- /dev/null
+++ b/test/geo_quaternion.cpp
@@ -0,0 +1,255 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra.
+//
+// Copyright (C) 2008-2009 Gael Guennebaud <gael.guennebaud@inria.fr>
+// Copyright (C) 2009 Mathieu Gautier <mathieu.gautier@cea.fr>
+//
+// This Source Code Form is subject to the terms of the Mozilla
+// Public License v. 2.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 "main.h"
+#include <Eigen/Geometry>
+#include <Eigen/LU>
+#include <Eigen/SVD>
+
+template<typename T> T bounded_acos(T v)
+{
+ using std::acos;
+ using std::min;
+ using std::max;
+ return acos((max)(T(-1),(min)(v,T(1))));
+}
+
+template<typename QuatType> void check_slerp(const QuatType& q0, const QuatType& q1)
+{
+ typedef typename QuatType::Scalar Scalar;
+ typedef Matrix<Scalar,3,1> VectorType;
+ typedef AngleAxis<Scalar> AA;
+
+ Scalar largeEps = test_precision<Scalar>();
+
+ Scalar theta_tot = AA(q1*q0.inverse()).angle();
+ if(theta_tot>M_PI)
+ theta_tot = 2.*M_PI-theta_tot;
+ for(Scalar t=0; t<=1.001; t+=0.1)
+ {
+ QuatType q = q0.slerp(t,q1);
+ Scalar theta = AA(q*q0.inverse()).angle();
+ VERIFY(internal::abs(q.norm() - 1) < largeEps);
+ if(theta_tot==0) VERIFY(theta_tot==0);
+ else VERIFY(internal::abs(theta/theta_tot - t) < largeEps);
+ }
+}
+
+template<typename Scalar, int Options> void quaternion(void)
+{
+ /* this test covers the following files:
+ Quaternion.h
+ */
+
+ typedef Matrix<Scalar,3,3> Matrix3;
+ typedef Matrix<Scalar,3,1> Vector3;
+ typedef Matrix<Scalar,4,1> Vector4;
+ typedef Quaternion<Scalar,Options> Quaternionx;
+ typedef AngleAxis<Scalar> AngleAxisx;
+
+ Scalar largeEps = test_precision<Scalar>();
+ if (internal::is_same<Scalar,float>::value)
+ largeEps = 1e-3f;
+
+ Scalar eps = internal::random<Scalar>() * Scalar(1e-2);
+
+ Vector3 v0 = Vector3::Random(),
+ v1 = Vector3::Random(),
+ v2 = Vector3::Random(),
+ v3 = Vector3::Random();
+
+ Scalar a = internal::random<Scalar>(-Scalar(M_PI), Scalar(M_PI)),
+ b = internal::random<Scalar>(-Scalar(M_PI), Scalar(M_PI));
+
+ // Quaternion: Identity(), setIdentity();
+ Quaternionx q1, q2;
+ q2.setIdentity();
+ VERIFY_IS_APPROX(Quaternionx(Quaternionx::Identity()).coeffs(), q2.coeffs());
+ q1.coeffs().setRandom();
+ VERIFY_IS_APPROX(q1.coeffs(), (q1*q2).coeffs());
+
+ // concatenation
+ q1 *= q2;
+
+ q1 = AngleAxisx(a, v0.normalized());
+ q2 = AngleAxisx(a, v1.normalized());
+
+ // angular distance
+ Scalar refangle = internal::abs(AngleAxisx(q1.inverse()*q2).angle());
+ if (refangle>Scalar(M_PI))
+ refangle = Scalar(2)*Scalar(M_PI) - refangle;
+
+ if((q1.coeffs()-q2.coeffs()).norm() > 10*largeEps)
+ {
+ VERIFY_IS_MUCH_SMALLER_THAN(internal::abs(q1.angularDistance(q2) - refangle), Scalar(1));
+ }
+
+ // rotation matrix conversion
+ VERIFY_IS_APPROX(q1 * v2, q1.toRotationMatrix() * v2);
+ VERIFY_IS_APPROX(q1 * q2 * v2,
+ q1.toRotationMatrix() * q2.toRotationMatrix() * v2);
+
+ VERIFY( (q2*q1).isApprox(q1*q2, largeEps)
+ || !(q2 * q1 * v2).isApprox(q1.toRotationMatrix() * q2.toRotationMatrix() * v2));
+
+ q2 = q1.toRotationMatrix();
+ VERIFY_IS_APPROX(q1*v1,q2*v1);
+
+
+ // angle-axis conversion
+ AngleAxisx aa = AngleAxisx(q1);
+ VERIFY_IS_APPROX(q1 * v1, Quaternionx(aa) * v1);
+
+ // Do not execute the test if the rotation angle is almost zero, or
+ // the rotation axis and v1 are almost parallel.
+ if (internal::abs(aa.angle()) > 5*test_precision<Scalar>()
+ && (aa.axis() - v1.normalized()).norm() < 1.99
+ && (aa.axis() + v1.normalized()).norm() < 1.99)
+ {
+ VERIFY_IS_NOT_APPROX(q1 * v1, Quaternionx(AngleAxisx(aa.angle()*2,aa.axis())) * v1);
+ }
+
+ // from two vector creation
+ VERIFY_IS_APPROX( v2.normalized(),(q2.setFromTwoVectors(v1, v2)*v1).normalized());
+ VERIFY_IS_APPROX( v1.normalized(),(q2.setFromTwoVectors(v1, v1)*v1).normalized());
+ VERIFY_IS_APPROX(-v1.normalized(),(q2.setFromTwoVectors(v1,-v1)*v1).normalized());
+ if (internal::is_same<Scalar,double>::value)
+ {
+ v3 = (v1.array()+eps).matrix();
+ VERIFY_IS_APPROX( v3.normalized(),(q2.setFromTwoVectors(v1, v3)*v1).normalized());
+ VERIFY_IS_APPROX(-v3.normalized(),(q2.setFromTwoVectors(v1,-v3)*v1).normalized());
+ }
+
+ // from two vector creation static function
+ VERIFY_IS_APPROX( v2.normalized(),(Quaternionx::FromTwoVectors(v1, v2)*v1).normalized());
+ VERIFY_IS_APPROX( v1.normalized(),(Quaternionx::FromTwoVectors(v1, v1)*v1).normalized());
+ VERIFY_IS_APPROX(-v1.normalized(),(Quaternionx::FromTwoVectors(v1,-v1)*v1).normalized());
+ if (internal::is_same<Scalar,double>::value)
+ {
+ v3 = (v1.array()+eps).matrix();
+ VERIFY_IS_APPROX( v3.normalized(),(Quaternionx::FromTwoVectors(v1, v3)*v1).normalized());
+ VERIFY_IS_APPROX(-v3.normalized(),(Quaternionx::FromTwoVectors(v1,-v3)*v1).normalized());
+ }
+
+ // inverse and conjugate
+ VERIFY_IS_APPROX(q1 * (q1.inverse() * v1), v1);
+ VERIFY_IS_APPROX(q1 * (q1.conjugate() * v1), v1);
+
+ // test casting
+ Quaternion<float> q1f = q1.template cast<float>();
+ VERIFY_IS_APPROX(q1f.template cast<Scalar>(),q1);
+ Quaternion<double> q1d = q1.template cast<double>();
+ VERIFY_IS_APPROX(q1d.template cast<Scalar>(),q1);
+
+ // test bug 369 - improper alignment.
+ Quaternionx *q = new Quaternionx;
+ delete q;
+
+ q1 = AngleAxisx(a, v0.normalized());
+ q2 = AngleAxisx(b, v1.normalized());
+ check_slerp(q1,q2);
+
+ q1 = AngleAxisx(b, v1.normalized());
+ q2 = AngleAxisx(b+M_PI, v1.normalized());
+ check_slerp(q1,q2);
+
+ q1 = AngleAxisx(b, v1.normalized());
+ q2 = AngleAxisx(-b, -v1.normalized());
+ check_slerp(q1,q2);
+
+ q1.coeffs() = Vector4::Random().normalized();
+ q2.coeffs() = -q1.coeffs();
+ check_slerp(q1,q2);
+}
+
+template<typename Scalar> void mapQuaternion(void){
+ typedef Map<Quaternion<Scalar>, Aligned> MQuaternionA;
+ typedef Map<Quaternion<Scalar> > MQuaternionUA;
+ typedef Map<const Quaternion<Scalar> > MCQuaternionUA;
+ typedef Quaternion<Scalar> Quaternionx;
+
+ EIGEN_ALIGN16 Scalar array1[4];
+ EIGEN_ALIGN16 Scalar array2[4];
+ EIGEN_ALIGN16 Scalar array3[4+1];
+ Scalar* array3unaligned = array3+1;
+
+// std::cerr << array1 << " " << array2 << " " << array3 << "\n";
+ MQuaternionA(array1).coeffs().setRandom();
+ (MQuaternionA(array2)) = MQuaternionA(array1);
+ (MQuaternionUA(array3unaligned)) = MQuaternionA(array1);
+
+ Quaternionx q1 = MQuaternionA(array1);
+ Quaternionx q2 = MQuaternionA(array2);
+ Quaternionx q3 = MQuaternionUA(array3unaligned);
+ Quaternionx q4 = MCQuaternionUA(array3unaligned);
+
+ VERIFY_IS_APPROX(q1.coeffs(), q2.coeffs());
+ VERIFY_IS_APPROX(q1.coeffs(), q3.coeffs());
+ VERIFY_IS_APPROX(q4.coeffs(), q3.coeffs());
+ #ifdef EIGEN_VECTORIZE
+ if(internal::packet_traits<Scalar>::Vectorizable)
+ VERIFY_RAISES_ASSERT((MQuaternionA(array3unaligned)));
+ #endif
+}
+
+template<typename Scalar> void quaternionAlignment(void){
+ typedef Quaternion<Scalar,AutoAlign> QuaternionA;
+ typedef Quaternion<Scalar,DontAlign> QuaternionUA;
+
+ EIGEN_ALIGN16 Scalar array1[4];
+ EIGEN_ALIGN16 Scalar array2[4];
+ EIGEN_ALIGN16 Scalar array3[4+1];
+ Scalar* arrayunaligned = array3+1;
+
+ QuaternionA *q1 = ::new(reinterpret_cast<void*>(array1)) QuaternionA;
+ QuaternionUA *q2 = ::new(reinterpret_cast<void*>(array2)) QuaternionUA;
+ QuaternionUA *q3 = ::new(reinterpret_cast<void*>(arrayunaligned)) QuaternionUA;
+
+ q1->coeffs().setRandom();
+ *q2 = *q1;
+ *q3 = *q1;
+
+ VERIFY_IS_APPROX(q1->coeffs(), q2->coeffs());
+ VERIFY_IS_APPROX(q1->coeffs(), q3->coeffs());
+ #if defined(EIGEN_VECTORIZE) && EIGEN_ALIGN_STATICALLY
+ if(internal::packet_traits<Scalar>::Vectorizable)
+ VERIFY_RAISES_ASSERT((::new(reinterpret_cast<void*>(arrayunaligned)) QuaternionA));
+ #endif
+}
+
+template<typename PlainObjectType> void check_const_correctness(const PlainObjectType&)
+{
+ // there's a lot that we can't test here while still having this test compile!
+ // the only possible approach would be to run a script trying to compile stuff and checking that it fails.
+ // CMake can help with that.
+
+ // verify that map-to-const don't have LvalueBit
+ typedef typename internal::add_const<PlainObjectType>::type ConstPlainObjectType;
+ VERIFY( !(internal::traits<Map<ConstPlainObjectType> >::Flags & LvalueBit) );
+ VERIFY( !(internal::traits<Map<ConstPlainObjectType, Aligned> >::Flags & LvalueBit) );
+ VERIFY( !(Map<ConstPlainObjectType>::Flags & LvalueBit) );
+ VERIFY( !(Map<ConstPlainObjectType, Aligned>::Flags & LvalueBit) );
+}
+
+void test_geo_quaternion()
+{
+ for(int i = 0; i < g_repeat; i++) {
+ CALL_SUBTEST_1(( quaternion<float,AutoAlign>() ));
+ CALL_SUBTEST_1( check_const_correctness(Quaternionf()) );
+ CALL_SUBTEST_2(( quaternion<double,AutoAlign>() ));
+ CALL_SUBTEST_2( check_const_correctness(Quaterniond()) );
+ CALL_SUBTEST_3(( quaternion<float,DontAlign>() ));
+ CALL_SUBTEST_4(( quaternion<double,DontAlign>() ));
+ CALL_SUBTEST_5(( quaternionAlignment<float>() ));
+ CALL_SUBTEST_6(( quaternionAlignment<double>() ));
+ CALL_SUBTEST_1( mapQuaternion<float>() );
+ CALL_SUBTEST_2( mapQuaternion<double>() );
+ }
+}
diff --git a/test/geo_transformations.cpp b/test/geo_transformations.cpp
new file mode 100644
index 000000000..f4d65aabc
--- /dev/null
+++ b/test/geo_transformations.cpp
@@ -0,0 +1,487 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra.
+//
+// Copyright (C) 2008-2009 Gael Guennebaud <gael.guennebaud@inria.fr>
+//
+// This Source Code Form is subject to the terms of the Mozilla
+// Public License v. 2.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 "main.h"
+#include <Eigen/Geometry>
+#include <Eigen/LU>
+#include <Eigen/SVD>
+
+template<typename Scalar, int Mode, int Options> void non_projective_only()
+{
+ /* this test covers the following files:
+ Cross.h Quaternion.h, Transform.cpp
+ */
+ typedef Matrix<Scalar,2,2> Matrix2;
+ typedef Matrix<Scalar,3,3> Matrix3;
+ typedef Matrix<Scalar,4,4> Matrix4;
+ typedef Matrix<Scalar,2,1> Vector2;
+ typedef Matrix<Scalar,3,1> Vector3;
+ typedef Matrix<Scalar,4,1> Vector4;
+ typedef Quaternion<Scalar> Quaternionx;
+ typedef AngleAxis<Scalar> AngleAxisx;
+ typedef Transform<Scalar,2,Mode,Options> Transform2;
+ typedef Transform<Scalar,3,Mode,Options> Transform3;
+ typedef Transform<Scalar,2,Isometry,Options> Isometry2;
+ typedef Transform<Scalar,3,Isometry,Options> Isometry3;
+ typedef typename Transform3::MatrixType MatrixType;
+ typedef DiagonalMatrix<Scalar,2> AlignedScaling2;
+ typedef DiagonalMatrix<Scalar,3> AlignedScaling3;
+ typedef Translation<Scalar,2> Translation2;
+ typedef Translation<Scalar,3> Translation3;
+
+ Vector3 v0 = Vector3::Random(),
+ v1 = Vector3::Random();
+
+ Transform3 t0, t1, t2;
+
+ Scalar a = internal::random<Scalar>(-Scalar(M_PI), Scalar(M_PI));
+
+ Quaternionx q1, q2;
+
+ q1 = AngleAxisx(a, v0.normalized());
+
+ t0 = Transform3::Identity();
+ VERIFY_IS_APPROX(t0.matrix(), Transform3::MatrixType::Identity());
+
+ t0.linear() = q1.toRotationMatrix();
+
+ v0 << 50, 2, 1;
+ t0.scale(v0);
+
+ VERIFY_IS_APPROX( (t0 * Vector3(1,0,0)).template head<3>().norm(), v0.x());
+
+ t0.setIdentity();
+ t1.setIdentity();
+ v1 << 1, 2, 3;
+ t0.linear() = q1.toRotationMatrix();
+ t0.pretranslate(v0);
+ t0.scale(v1);
+ t1.linear() = q1.conjugate().toRotationMatrix();
+ t1.prescale(v1.cwiseInverse());
+ t1.translate(-v0);
+
+ VERIFY((t0 * t1).matrix().isIdentity(test_precision<Scalar>()));
+
+ t1.fromPositionOrientationScale(v0, q1, v1);
+ VERIFY_IS_APPROX(t1.matrix(), t0.matrix());
+ VERIFY_IS_APPROX(t1*v1, t0*v1);
+
+ // translation * vector
+ t0.setIdentity();
+ t0.translate(v0);
+ VERIFY_IS_APPROX((t0 * v1).template head<3>(), Translation3(v0) * v1);
+
+ // AlignedScaling * vector
+ t0.setIdentity();
+ t0.scale(v0);
+ VERIFY_IS_APPROX((t0 * v1).template head<3>(), AlignedScaling3(v0) * v1);
+}
+
+template<typename Scalar, int Mode, int Options> void transformations()
+{
+ /* this test covers the following files:
+ Cross.h Quaternion.h, Transform.cpp
+ */
+ typedef Matrix<Scalar,2,2> Matrix2;
+ typedef Matrix<Scalar,3,3> Matrix3;
+ typedef Matrix<Scalar,4,4> Matrix4;
+ typedef Matrix<Scalar,2,1> Vector2;
+ typedef Matrix<Scalar,3,1> Vector3;
+ typedef Matrix<Scalar,4,1> Vector4;
+ typedef Quaternion<Scalar> Quaternionx;
+ typedef AngleAxis<Scalar> AngleAxisx;
+ typedef Transform<Scalar,2,Mode,Options> Transform2;
+ typedef Transform<Scalar,3,Mode,Options> Transform3;
+ typedef Transform<Scalar,2,Isometry,Options> Isometry2;
+ typedef Transform<Scalar,3,Isometry,Options> Isometry3;
+ typedef typename Transform3::MatrixType MatrixType;
+ typedef DiagonalMatrix<Scalar,2> AlignedScaling2;
+ typedef DiagonalMatrix<Scalar,3> AlignedScaling3;
+ typedef Translation<Scalar,2> Translation2;
+ typedef Translation<Scalar,3> Translation3;
+
+ Vector3 v0 = Vector3::Random(),
+ v1 = Vector3::Random();
+ Matrix3 matrot1, m;
+
+ Scalar a = internal::random<Scalar>(-Scalar(M_PI), Scalar(M_PI));
+ Scalar s0 = internal::random<Scalar>();
+
+ VERIFY_IS_APPROX(v0, AngleAxisx(a, v0.normalized()) * v0);
+ VERIFY_IS_APPROX(-v0, AngleAxisx(Scalar(M_PI), v0.unitOrthogonal()) * v0);
+ VERIFY_IS_APPROX(internal::cos(a)*v0.squaredNorm(), v0.dot(AngleAxisx(a, v0.unitOrthogonal()) * v0));
+ m = AngleAxisx(a, v0.normalized()).toRotationMatrix().adjoint();
+ VERIFY_IS_APPROX(Matrix3::Identity(), m * AngleAxisx(a, v0.normalized()));
+ VERIFY_IS_APPROX(Matrix3::Identity(), AngleAxisx(a, v0.normalized()) * m);
+
+ Quaternionx q1, q2;
+ q1 = AngleAxisx(a, v0.normalized());
+ q2 = AngleAxisx(a, v1.normalized());
+
+ // rotation matrix conversion
+ matrot1 = AngleAxisx(Scalar(0.1), Vector3::UnitX())
+ * AngleAxisx(Scalar(0.2), Vector3::UnitY())
+ * AngleAxisx(Scalar(0.3), Vector3::UnitZ());
+ VERIFY_IS_APPROX(matrot1 * v1,
+ AngleAxisx(Scalar(0.1), Vector3(1,0,0)).toRotationMatrix()
+ * (AngleAxisx(Scalar(0.2), Vector3(0,1,0)).toRotationMatrix()
+ * (AngleAxisx(Scalar(0.3), Vector3(0,0,1)).toRotationMatrix() * v1)));
+
+ // angle-axis conversion
+ AngleAxisx aa = AngleAxisx(q1);
+ VERIFY_IS_APPROX(q1 * v1, Quaternionx(aa) * v1);
+ VERIFY_IS_NOT_APPROX(q1 * v1, Quaternionx(AngleAxisx(aa.angle()*2,aa.axis())) * v1);
+
+ aa.fromRotationMatrix(aa.toRotationMatrix());
+ VERIFY_IS_APPROX(q1 * v1, Quaternionx(aa) * v1);
+ VERIFY_IS_NOT_APPROX(q1 * v1, Quaternionx(AngleAxisx(aa.angle()*2,aa.axis())) * v1);
+
+ // AngleAxis
+ VERIFY_IS_APPROX(AngleAxisx(a,v1.normalized()).toRotationMatrix(),
+ Quaternionx(AngleAxisx(a,v1.normalized())).toRotationMatrix());
+
+ AngleAxisx aa1;
+ m = q1.toRotationMatrix();
+ aa1 = m;
+ VERIFY_IS_APPROX(AngleAxisx(m).toRotationMatrix(),
+ Quaternionx(m).toRotationMatrix());
+
+ // Transform
+ // TODO complete the tests !
+ a = 0;
+ while (internal::abs(a)<Scalar(0.1))
+ a = internal::random<Scalar>(-Scalar(0.4)*Scalar(M_PI), Scalar(0.4)*Scalar(M_PI));
+ q1 = AngleAxisx(a, v0.normalized());
+ Transform3 t0, t1, t2;
+
+ // first test setIdentity() and Identity()
+ t0.setIdentity();
+ VERIFY_IS_APPROX(t0.matrix(), Transform3::MatrixType::Identity());
+ t0.matrix().setZero();
+ t0 = Transform3::Identity();
+ VERIFY_IS_APPROX(t0.matrix(), Transform3::MatrixType::Identity());
+
+ t0.setIdentity();
+ t1.setIdentity();
+ v1 << 1, 2, 3;
+ t0.linear() = q1.toRotationMatrix();
+ t0.pretranslate(v0);
+ t0.scale(v1);
+ t1.linear() = q1.conjugate().toRotationMatrix();
+ t1.prescale(v1.cwiseInverse());
+ t1.translate(-v0);
+
+ VERIFY((t0 * t1).matrix().isIdentity(test_precision<Scalar>()));
+
+ t1.fromPositionOrientationScale(v0, q1, v1);
+ VERIFY_IS_APPROX(t1.matrix(), t0.matrix());
+
+ t0.setIdentity(); t0.scale(v0).rotate(q1.toRotationMatrix());
+ t1.setIdentity(); t1.scale(v0).rotate(q1);
+ VERIFY_IS_APPROX(t0.matrix(), t1.matrix());
+
+ t0.setIdentity(); t0.scale(v0).rotate(AngleAxisx(q1));
+ VERIFY_IS_APPROX(t0.matrix(), t1.matrix());
+
+ VERIFY_IS_APPROX(t0.scale(a).matrix(), t1.scale(Vector3::Constant(a)).matrix());
+ VERIFY_IS_APPROX(t0.prescale(a).matrix(), t1.prescale(Vector3::Constant(a)).matrix());
+
+ // More transform constructors, operator=, operator*=
+
+ Matrix3 mat3 = Matrix3::Random();
+ Matrix4 mat4;
+ mat4 << mat3 , Vector3::Zero() , Vector4::Zero().transpose();
+ Transform3 tmat3(mat3), tmat4(mat4);
+ if(Mode!=int(AffineCompact))
+ tmat4.matrix()(3,3) = Scalar(1);
+ VERIFY_IS_APPROX(tmat3.matrix(), tmat4.matrix());
+
+ Scalar a3 = internal::random<Scalar>(-Scalar(M_PI), Scalar(M_PI));
+ Vector3 v3 = Vector3::Random().normalized();
+ AngleAxisx aa3(a3, v3);
+ Transform3 t3(aa3);
+ Transform3 t4;
+ t4 = aa3;
+ VERIFY_IS_APPROX(t3.matrix(), t4.matrix());
+ t4.rotate(AngleAxisx(-a3,v3));
+ VERIFY_IS_APPROX(t4.matrix(), MatrixType::Identity());
+ t4 *= aa3;
+ VERIFY_IS_APPROX(t3.matrix(), t4.matrix());
+
+ v3 = Vector3::Random();
+ Translation3 tv3(v3);
+ Transform3 t5(tv3);
+ t4 = tv3;
+ VERIFY_IS_APPROX(t5.matrix(), t4.matrix());
+ t4.translate(-v3);
+ VERIFY_IS_APPROX(t4.matrix(), MatrixType::Identity());
+ t4 *= tv3;
+ VERIFY_IS_APPROX(t5.matrix(), t4.matrix());
+
+ AlignedScaling3 sv3(v3);
+ Transform3 t6(sv3);
+ t4 = sv3;
+ VERIFY_IS_APPROX(t6.matrix(), t4.matrix());
+ t4.scale(v3.cwiseInverse());
+ VERIFY_IS_APPROX(t4.matrix(), MatrixType::Identity());
+ t4 *= sv3;
+ VERIFY_IS_APPROX(t6.matrix(), t4.matrix());
+
+ // matrix * transform
+ VERIFY_IS_APPROX((t3.matrix()*t4).matrix(), (t3*t4).matrix());
+
+ // chained Transform product
+ VERIFY_IS_APPROX(((t3*t4)*t5).matrix(), (t3*(t4*t5)).matrix());
+
+ // check that Transform product doesn't have aliasing problems
+ t5 = t4;
+ t5 = t5*t5;
+ VERIFY_IS_APPROX(t5, t4*t4);
+
+ // 2D transformation
+ Transform2 t20, t21;
+ Vector2 v20 = Vector2::Random();
+ Vector2 v21 = Vector2::Random();
+ for (int k=0; k<2; ++k)
+ if (internal::abs(v21[k])<Scalar(1e-3)) v21[k] = Scalar(1e-3);
+ t21.setIdentity();
+ t21.linear() = Rotation2D<Scalar>(a).toRotationMatrix();
+ VERIFY_IS_APPROX(t20.fromPositionOrientationScale(v20,a,v21).matrix(),
+ t21.pretranslate(v20).scale(v21).matrix());
+
+ t21.setIdentity();
+ t21.linear() = Rotation2D<Scalar>(-a).toRotationMatrix();
+ VERIFY( (t20.fromPositionOrientationScale(v20,a,v21)
+ * (t21.prescale(v21.cwiseInverse()).translate(-v20))).matrix().isIdentity(test_precision<Scalar>()) );
+
+ // Transform - new API
+ // 3D
+ t0.setIdentity();
+ t0.rotate(q1).scale(v0).translate(v0);
+ // mat * aligned scaling and mat * translation
+ t1 = (Matrix3(q1) * AlignedScaling3(v0)) * Translation3(v0);
+ VERIFY_IS_APPROX(t0.matrix(), t1.matrix());
+ t1 = (Matrix3(q1) * Eigen::Scaling(v0)) * Translation3(v0);
+ VERIFY_IS_APPROX(t0.matrix(), t1.matrix());
+ t1 = (q1 * Eigen::Scaling(v0)) * Translation3(v0);
+ VERIFY_IS_APPROX(t0.matrix(), t1.matrix());
+ // mat * transformation and aligned scaling * translation
+ t1 = Matrix3(q1) * (AlignedScaling3(v0) * Translation3(v0));
+ VERIFY_IS_APPROX(t0.matrix(), t1.matrix());
+
+
+ t0.setIdentity();
+ t0.scale(s0).translate(v0);
+ t1 = Eigen::Scaling(s0) * Translation3(v0);
+ VERIFY_IS_APPROX(t0.matrix(), t1.matrix());
+ t0.prescale(s0);
+ t1 = Eigen::Scaling(s0) * t1;
+ VERIFY_IS_APPROX(t0.matrix(), t1.matrix());
+
+ t0 = t3;
+ t0.scale(s0);
+ t1 = t3 * Eigen::Scaling(s0,s0,s0);
+ VERIFY_IS_APPROX(t0.matrix(), t1.matrix());
+ t0.prescale(s0);
+ t1 = Eigen::Scaling(s0,s0,s0) * t1;
+ VERIFY_IS_APPROX(t0.matrix(), t1.matrix());
+
+
+ t0.setIdentity();
+ t0.prerotate(q1).prescale(v0).pretranslate(v0);
+ // translation * aligned scaling and transformation * mat
+ t1 = (Translation3(v0) * AlignedScaling3(v0)) * Transform3(q1);
+ VERIFY_IS_APPROX(t0.matrix(), t1.matrix());
+ // scaling * mat and translation * mat
+ t1 = Translation3(v0) * (AlignedScaling3(v0) * Transform3(q1));
+ VERIFY_IS_APPROX(t0.matrix(), t1.matrix());
+
+ t0.setIdentity();
+ t0.scale(v0).translate(v0).rotate(q1);
+ // translation * mat and aligned scaling * transformation
+ t1 = AlignedScaling3(v0) * (Translation3(v0) * Transform3(q1));
+ VERIFY_IS_APPROX(t0.matrix(), t1.matrix());
+ // transformation * aligned scaling
+ t0.scale(v0);
+ t1 *= AlignedScaling3(v0);
+ VERIFY_IS_APPROX(t0.matrix(), t1.matrix());
+ // transformation * translation
+ t0.translate(v0);
+ t1 = t1 * Translation3(v0);
+ VERIFY_IS_APPROX(t0.matrix(), t1.matrix());
+ // translation * transformation
+ t0.pretranslate(v0);
+ t1 = Translation3(v0) * t1;
+ VERIFY_IS_APPROX(t0.matrix(), t1.matrix());
+
+ // transform * quaternion
+ t0.rotate(q1);
+ t1 = t1 * q1;
+ VERIFY_IS_APPROX(t0.matrix(), t1.matrix());
+
+ // translation * quaternion
+ t0.translate(v1).rotate(q1);
+ t1 = t1 * (Translation3(v1) * q1);
+ VERIFY_IS_APPROX(t0.matrix(), t1.matrix());
+
+ // aligned scaling * quaternion
+ t0.scale(v1).rotate(q1);
+ t1 = t1 * (AlignedScaling3(v1) * q1);
+ VERIFY_IS_APPROX(t0.matrix(), t1.matrix());
+
+ // quaternion * transform
+ t0.prerotate(q1);
+ t1 = q1 * t1;
+ VERIFY_IS_APPROX(t0.matrix(), t1.matrix());
+
+ // quaternion * translation
+ t0.rotate(q1).translate(v1);
+ t1 = t1 * (q1 * Translation3(v1));
+ VERIFY_IS_APPROX(t0.matrix(), t1.matrix());
+
+ // quaternion * aligned scaling
+ t0.rotate(q1).scale(v1);
+ t1 = t1 * (q1 * AlignedScaling3(v1));
+ VERIFY_IS_APPROX(t0.matrix(), t1.matrix());
+
+ // test transform inversion
+ t0.setIdentity();
+ t0.translate(v0);
+ t0.linear().setRandom();
+ Matrix4 t044 = Matrix4::Zero();
+ t044(3,3) = 1;
+ t044.block(0,0,t0.matrix().rows(),4) = t0.matrix();
+ VERIFY_IS_APPROX(t0.inverse(Affine).matrix(), t044.inverse().block(0,0,t0.matrix().rows(),4));
+ t0.setIdentity();
+ t0.translate(v0).rotate(q1);
+ t044 = Matrix4::Zero();
+ t044(3,3) = 1;
+ t044.block(0,0,t0.matrix().rows(),4) = t0.matrix();
+ VERIFY_IS_APPROX(t0.inverse(Isometry).matrix(), t044.inverse().block(0,0,t0.matrix().rows(),4));
+
+ Matrix3 mat_rotation, mat_scaling;
+ t0.setIdentity();
+ t0.translate(v0).rotate(q1).scale(v1);
+ t0.computeRotationScaling(&mat_rotation, &mat_scaling);
+ VERIFY_IS_APPROX(t0.linear(), mat_rotation * mat_scaling);
+ VERIFY_IS_APPROX(mat_rotation*mat_rotation.adjoint(), Matrix3::Identity());
+ VERIFY_IS_APPROX(mat_rotation.determinant(), Scalar(1));
+ t0.computeScalingRotation(&mat_scaling, &mat_rotation);
+ VERIFY_IS_APPROX(t0.linear(), mat_scaling * mat_rotation);
+ VERIFY_IS_APPROX(mat_rotation*mat_rotation.adjoint(), Matrix3::Identity());
+ VERIFY_IS_APPROX(mat_rotation.determinant(), Scalar(1));
+
+ // test casting
+ Transform<float,3,Mode> t1f = t1.template cast<float>();
+ VERIFY_IS_APPROX(t1f.template cast<Scalar>(),t1);
+ Transform<double,3,Mode> t1d = t1.template cast<double>();
+ VERIFY_IS_APPROX(t1d.template cast<Scalar>(),t1);
+
+ Translation3 tr1(v0);
+ Translation<float,3> tr1f = tr1.template cast<float>();
+ VERIFY_IS_APPROX(tr1f.template cast<Scalar>(),tr1);
+ Translation<double,3> tr1d = tr1.template cast<double>();
+ VERIFY_IS_APPROX(tr1d.template cast<Scalar>(),tr1);
+
+ AngleAxis<float> aa1f = aa1.template cast<float>();
+ VERIFY_IS_APPROX(aa1f.template cast<Scalar>(),aa1);
+ AngleAxis<double> aa1d = aa1.template cast<double>();
+ VERIFY_IS_APPROX(aa1d.template cast<Scalar>(),aa1);
+
+ Rotation2D<Scalar> r2d1(internal::random<Scalar>());
+ Rotation2D<float> r2d1f = r2d1.template cast<float>();
+ VERIFY_IS_APPROX(r2d1f.template cast<Scalar>(),r2d1);
+ Rotation2D<double> r2d1d = r2d1.template cast<double>();
+ VERIFY_IS_APPROX(r2d1d.template cast<Scalar>(),r2d1);
+
+ t20 = Translation2(v20) * (Rotation2D<Scalar>(s0) * Scaling(s0));
+ t21 = Translation2(v20) * Rotation2D<Scalar>(s0) * Scaling(s0);
+ VERIFY_IS_APPROX(t20,t21);
+}
+
+template<typename Scalar> void transform_alignment()
+{
+ typedef Transform<Scalar,3,Projective,AutoAlign> Projective3a;
+ typedef Transform<Scalar,3,Projective,DontAlign> Projective3u;
+
+ EIGEN_ALIGN16 Scalar array1[16];
+ EIGEN_ALIGN16 Scalar array2[16];
+ EIGEN_ALIGN16 Scalar array3[16+1];
+ Scalar* array3u = array3+1;
+
+ Projective3a *p1 = ::new(reinterpret_cast<void*>(array1)) Projective3a;
+ Projective3u *p2 = ::new(reinterpret_cast<void*>(array2)) Projective3u;
+ Projective3u *p3 = ::new(reinterpret_cast<void*>(array3u)) Projective3u;
+
+ p1->matrix().setRandom();
+ *p2 = *p1;
+ *p3 = *p1;
+
+ VERIFY_IS_APPROX(p1->matrix(), p2->matrix());
+ VERIFY_IS_APPROX(p1->matrix(), p3->matrix());
+
+ VERIFY_IS_APPROX( (*p1) * (*p1), (*p2)*(*p3));
+
+ #if defined(EIGEN_VECTORIZE) && EIGEN_ALIGN_STATICALLY
+ if(internal::packet_traits<Scalar>::Vectorizable)
+ VERIFY_RAISES_ASSERT((::new(reinterpret_cast<void*>(array3u)) Projective3a));
+ #endif
+}
+
+template<typename Scalar, int Dim, int Options> void transform_products()
+{
+ typedef Matrix<Scalar,Dim+1,Dim+1> Mat;
+ typedef Transform<Scalar,Dim,Projective,Options> Proj;
+ typedef Transform<Scalar,Dim,Affine,Options> Aff;
+ typedef Transform<Scalar,Dim,AffineCompact,Options> AffC;
+
+ Proj p; p.matrix().setRandom();
+ Aff a; a.linear().setRandom(); a.translation().setRandom();
+ AffC ac = a;
+
+ Mat p_m(p.matrix()), a_m(a.matrix());
+
+ VERIFY_IS_APPROX((p*p).matrix(), p_m*p_m);
+ VERIFY_IS_APPROX((a*a).matrix(), a_m*a_m);
+ VERIFY_IS_APPROX((p*a).matrix(), p_m*a_m);
+ VERIFY_IS_APPROX((a*p).matrix(), a_m*p_m);
+ VERIFY_IS_APPROX((ac*a).matrix(), a_m*a_m);
+ VERIFY_IS_APPROX((a*ac).matrix(), a_m*a_m);
+ VERIFY_IS_APPROX((p*ac).matrix(), p_m*a_m);
+ VERIFY_IS_APPROX((ac*p).matrix(), a_m*p_m);
+}
+
+void test_geo_transformations()
+{
+ for(int i = 0; i < g_repeat; i++) {
+ CALL_SUBTEST_1(( transformations<double,Affine,AutoAlign>() ));
+ CALL_SUBTEST_1(( non_projective_only<double,Affine,AutoAlign>() ));
+
+ CALL_SUBTEST_2(( transformations<float,AffineCompact,AutoAlign>() ));
+ CALL_SUBTEST_2(( non_projective_only<float,AffineCompact,AutoAlign>() ));
+ CALL_SUBTEST_2(( transform_alignment<float>() ));
+
+ CALL_SUBTEST_3(( transformations<double,Projective,AutoAlign>() ));
+ CALL_SUBTEST_3(( transformations<double,Projective,DontAlign>() ));
+ CALL_SUBTEST_3(( transform_alignment<double>() ));
+
+ CALL_SUBTEST_4(( transformations<float,Affine,RowMajor|AutoAlign>() ));
+ CALL_SUBTEST_4(( non_projective_only<float,Affine,RowMajor>() ));
+
+ CALL_SUBTEST_5(( transformations<double,AffineCompact,RowMajor|AutoAlign>() ));
+ CALL_SUBTEST_5(( non_projective_only<double,AffineCompact,RowMajor>() ));
+
+ CALL_SUBTEST_6(( transformations<double,Projective,RowMajor|AutoAlign>() ));
+ CALL_SUBTEST_6(( transformations<double,Projective,RowMajor|DontAlign>() ));
+
+
+ CALL_SUBTEST_7(( transform_products<double,3,RowMajor|AutoAlign>() ));
+ CALL_SUBTEST_7(( transform_products<float,2,AutoAlign>() ));
+ }
+}
diff --git a/test/hessenberg.cpp b/test/hessenberg.cpp
new file mode 100644
index 000000000..96bc19e2e
--- /dev/null
+++ b/test/hessenberg.cpp
@@ -0,0 +1,62 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra.
+//
+// Copyright (C) 2009 Gael Guennebaud <gael.guennebaud@inria.fr>
+// Copyright (C) 2010 Jitse Niesen <jitse@maths.leeds.ac.uk>
+//
+// This Source Code Form is subject to the terms of the Mozilla
+// Public License v. 2.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 "main.h"
+#include <Eigen/Eigenvalues>
+
+template<typename Scalar,int Size> void hessenberg(int size = Size)
+{
+ typedef Matrix<Scalar,Size,Size> MatrixType;
+
+ // Test basic functionality: A = U H U* and H is Hessenberg
+ for(int counter = 0; counter < g_repeat; ++counter) {
+ MatrixType m = MatrixType::Random(size,size);
+ HessenbergDecomposition<MatrixType> hess(m);
+ MatrixType Q = hess.matrixQ();
+ MatrixType H = hess.matrixH();
+ VERIFY_IS_APPROX(m, Q * H * Q.adjoint());
+ for(int row = 2; row < size; ++row) {
+ for(int col = 0; col < row-1; ++col) {
+ VERIFY(H(row,col) == (typename MatrixType::Scalar)0);
+ }
+ }
+ }
+
+ // Test whether compute() and constructor returns same result
+ MatrixType A = MatrixType::Random(size, size);
+ HessenbergDecomposition<MatrixType> cs1;
+ cs1.compute(A);
+ HessenbergDecomposition<MatrixType> cs2(A);
+ VERIFY_IS_EQUAL(cs1.matrixH().eval(), cs2.matrixH().eval());
+ MatrixType cs1Q = cs1.matrixQ();
+ MatrixType cs2Q = cs2.matrixQ();
+ VERIFY_IS_EQUAL(cs1Q, cs2Q);
+
+ // Test assertions for when used uninitialized
+ HessenbergDecomposition<MatrixType> hessUninitialized;
+ VERIFY_RAISES_ASSERT( hessUninitialized.matrixH() );
+ VERIFY_RAISES_ASSERT( hessUninitialized.matrixQ() );
+ VERIFY_RAISES_ASSERT( hessUninitialized.householderCoefficients() );
+ VERIFY_RAISES_ASSERT( hessUninitialized.packedMatrix() );
+
+ // TODO: Add tests for packedMatrix() and householderCoefficients()
+}
+
+void test_hessenberg()
+{
+ CALL_SUBTEST_1(( hessenberg<std::complex<double>,1>() ));
+ CALL_SUBTEST_2(( hessenberg<std::complex<double>,2>() ));
+ CALL_SUBTEST_3(( hessenberg<std::complex<float>,4>() ));
+ CALL_SUBTEST_4(( hessenberg<float,Dynamic>(internal::random<int>(1,EIGEN_TEST_MAX_SIZE)) ));
+ CALL_SUBTEST_5(( hessenberg<std::complex<double>,Dynamic>(internal::random<int>(1,EIGEN_TEST_MAX_SIZE)) ));
+
+ // Test problem size constructors
+ CALL_SUBTEST_6(HessenbergDecomposition<MatrixXf>(10));
+}
diff --git a/test/householder.cpp b/test/householder.cpp
new file mode 100644
index 000000000..203dce46c
--- /dev/null
+++ b/test/householder.cpp
@@ -0,0 +1,123 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra.
+//
+// Copyright (C) 2009-2010 Benoit Jacob <jacob.benoit.1@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 "main.h"
+#include <Eigen/QR>
+
+template<typename MatrixType> void householder(const MatrixType& m)
+{
+ typedef typename MatrixType::Index Index;
+ static bool even = true;
+ even = !even;
+ /* this test covers the following files:
+ Householder.h
+ */
+ Index rows = m.rows();
+ Index cols = m.cols();
+
+ typedef typename MatrixType::Scalar Scalar;
+ typedef typename NumTraits<Scalar>::Real RealScalar;
+ typedef Matrix<Scalar, MatrixType::RowsAtCompileTime, 1> VectorType;
+ typedef Matrix<Scalar, internal::decrement_size<MatrixType::RowsAtCompileTime>::ret, 1> EssentialVectorType;
+ typedef Matrix<Scalar, MatrixType::RowsAtCompileTime, MatrixType::RowsAtCompileTime> SquareMatrixType;
+ typedef Matrix<Scalar, Dynamic, MatrixType::ColsAtCompileTime> HBlockMatrixType;
+ typedef Matrix<Scalar, Dynamic, 1> HCoeffsVectorType;
+
+ typedef Matrix<Scalar, MatrixType::ColsAtCompileTime, MatrixType::ColsAtCompileTime> RightSquareMatrixType;
+ typedef Matrix<Scalar, MatrixType::RowsAtCompileTime, Dynamic> VBlockMatrixType;
+ typedef Matrix<Scalar, MatrixType::ColsAtCompileTime, MatrixType::RowsAtCompileTime> TMatrixType;
+
+ Matrix<Scalar, EIGEN_SIZE_MAX(MatrixType::RowsAtCompileTime,MatrixType::ColsAtCompileTime), 1> _tmp((std::max)(rows,cols));
+ Scalar* tmp = &_tmp.coeffRef(0,0);
+
+ Scalar beta;
+ RealScalar alpha;
+ EssentialVectorType essential;
+
+ VectorType v1 = VectorType::Random(rows), v2;
+ v2 = v1;
+ v1.makeHouseholder(essential, beta, alpha);
+ v1.applyHouseholderOnTheLeft(essential,beta,tmp);
+ VERIFY_IS_APPROX(v1.norm(), v2.norm());
+ if(rows>=2) VERIFY_IS_MUCH_SMALLER_THAN(v1.tail(rows-1).norm(), v1.norm());
+ v1 = VectorType::Random(rows);
+ v2 = v1;
+ v1.applyHouseholderOnTheLeft(essential,beta,tmp);
+ VERIFY_IS_APPROX(v1.norm(), v2.norm());
+
+ MatrixType m1(rows, cols),
+ m2(rows, cols);
+
+ v1 = VectorType::Random(rows);
+ if(even) v1.tail(rows-1).setZero();
+ m1.colwise() = v1;
+ m2 = m1;
+ m1.col(0).makeHouseholder(essential, beta, alpha);
+ m1.applyHouseholderOnTheLeft(essential,beta,tmp);
+ VERIFY_IS_APPROX(m1.norm(), m2.norm());
+ if(rows>=2) VERIFY_IS_MUCH_SMALLER_THAN(m1.block(1,0,rows-1,cols).norm(), m1.norm());
+ VERIFY_IS_MUCH_SMALLER_THAN(internal::imag(m1(0,0)), internal::real(m1(0,0)));
+ VERIFY_IS_APPROX(internal::real(m1(0,0)), alpha);
+
+ v1 = VectorType::Random(rows);
+ if(even) v1.tail(rows-1).setZero();
+ SquareMatrixType m3(rows,rows), m4(rows,rows);
+ m3.rowwise() = v1.transpose();
+ m4 = m3;
+ m3.row(0).makeHouseholder(essential, beta, alpha);
+ m3.applyHouseholderOnTheRight(essential,beta,tmp);
+ VERIFY_IS_APPROX(m3.norm(), m4.norm());
+ if(rows>=2) VERIFY_IS_MUCH_SMALLER_THAN(m3.block(0,1,rows,rows-1).norm(), m3.norm());
+ VERIFY_IS_MUCH_SMALLER_THAN(internal::imag(m3(0,0)), internal::real(m3(0,0)));
+ VERIFY_IS_APPROX(internal::real(m3(0,0)), alpha);
+
+ // test householder sequence on the left with a shift
+
+ Index shift = internal::random<Index>(0, std::max<Index>(rows-2,0));
+ Index brows = rows - shift;
+ m1.setRandom(rows, cols);
+ HBlockMatrixType hbm = m1.block(shift,0,brows,cols);
+ HouseholderQR<HBlockMatrixType> qr(hbm);
+ m2 = m1;
+ m2.block(shift,0,brows,cols) = qr.matrixQR();
+ HCoeffsVectorType hc = qr.hCoeffs().conjugate();
+ HouseholderSequence<MatrixType, HCoeffsVectorType> hseq(m2, hc);
+ hseq.setLength(hc.size()).setShift(shift);
+ VERIFY(hseq.length() == hc.size());
+ VERIFY(hseq.shift() == shift);
+
+ MatrixType m5 = m2;
+ m5.block(shift,0,brows,cols).template triangularView<StrictlyLower>().setZero();
+ VERIFY_IS_APPROX(hseq * m5, m1); // test applying hseq directly
+ m3 = hseq;
+ VERIFY_IS_APPROX(m3 * m5, m1); // test evaluating hseq to a dense matrix, then applying
+
+ // test householder sequence on the right with a shift
+
+ TMatrixType tm2 = m2.transpose();
+ HouseholderSequence<TMatrixType, HCoeffsVectorType, OnTheRight> rhseq(tm2, hc);
+ rhseq.setLength(hc.size()).setShift(shift);
+ VERIFY_IS_APPROX(rhseq * m5, m1); // test applying rhseq directly
+ m3 = rhseq;
+ VERIFY_IS_APPROX(m3 * m5, m1); // test evaluating rhseq to a dense matrix, then applying
+}
+
+void test_householder()
+{
+ for(int i = 0; i < g_repeat; i++) {
+ CALL_SUBTEST_1( householder(Matrix<double,2,2>()) );
+ CALL_SUBTEST_2( householder(Matrix<float,2,3>()) );
+ CALL_SUBTEST_3( householder(Matrix<double,3,5>()) );
+ CALL_SUBTEST_4( householder(Matrix<float,4,4>()) );
+ CALL_SUBTEST_5( householder(MatrixXd(internal::random<int>(1,EIGEN_TEST_MAX_SIZE),internal::random<int>(1,EIGEN_TEST_MAX_SIZE))) );
+ CALL_SUBTEST_6( householder(MatrixXcf(internal::random<int>(1,EIGEN_TEST_MAX_SIZE),internal::random<int>(1,EIGEN_TEST_MAX_SIZE))) );
+ CALL_SUBTEST_7( householder(MatrixXf(internal::random<int>(1,EIGEN_TEST_MAX_SIZE),internal::random<int>(1,EIGEN_TEST_MAX_SIZE))) );
+ CALL_SUBTEST_8( householder(Matrix<double,1,1>()) );
+ }
+}
diff --git a/test/integer_types.cpp b/test/integer_types.cpp
new file mode 100644
index 000000000..950f8e9be
--- /dev/null
+++ b/test/integer_types.cpp
@@ -0,0 +1,161 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra.
+//
+// Copyright (C) 2010 Benoit Jacob <jacob.benoit.1@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/.
+
+#define EIGEN_NO_STATIC_ASSERT
+
+#include "main.h"
+
+#undef VERIFY_IS_APPROX
+#define VERIFY_IS_APPROX(a, b) VERIFY((a)==(b));
+#undef VERIFY_IS_NOT_APPROX
+#define VERIFY_IS_NOT_APPROX(a, b) VERIFY((a)!=(b));
+
+template<typename MatrixType> void signed_integer_type_tests(const MatrixType& m)
+{
+ typedef typename MatrixType::Index Index;
+ typedef typename MatrixType::Scalar Scalar;
+
+ enum { is_signed = (Scalar(-1) > Scalar(0)) ? 0 : 1 };
+ VERIFY(is_signed == 1);
+
+ Index rows = m.rows();
+ Index cols = m.cols();
+
+ MatrixType m1(rows, cols),
+ m2 = MatrixType::Random(rows, cols),
+ mzero = MatrixType::Zero(rows, cols);
+
+ do {
+ m1 = MatrixType::Random(rows, cols);
+ } while(m1 == mzero || m1 == m2);
+
+ // check linear structure
+
+ Scalar s1;
+ do {
+ s1 = internal::random<Scalar>();
+ } while(s1 == 0);
+
+ VERIFY_IS_EQUAL(-(-m1), m1);
+ VERIFY_IS_EQUAL(-m2+m1+m2, m1);
+ VERIFY_IS_EQUAL((-m1+m2)*s1, -s1*m1+s1*m2);
+}
+
+template<typename MatrixType> void integer_type_tests(const MatrixType& m)
+{
+ typedef typename MatrixType::Index Index;
+ typedef typename MatrixType::Scalar Scalar;
+
+ VERIFY(NumTraits<Scalar>::IsInteger);
+ enum { is_signed = (Scalar(-1) > Scalar(0)) ? 0 : 1 };
+ VERIFY(int(NumTraits<Scalar>::IsSigned) == is_signed);
+
+ typedef Matrix<Scalar, MatrixType::RowsAtCompileTime, 1> VectorType;
+
+ Index rows = m.rows();
+ Index cols = m.cols();
+
+ // this test relies a lot on Random.h, and there's not much more that we can do
+ // to test it, hence I consider that we will have tested Random.h
+ MatrixType m1(rows, cols),
+ m2 = MatrixType::Random(rows, cols),
+ m3(rows, cols),
+ mzero = MatrixType::Zero(rows, cols);
+
+ typedef Matrix<Scalar, MatrixType::RowsAtCompileTime, MatrixType::RowsAtCompileTime> SquareMatrixType;
+ SquareMatrixType identity = SquareMatrixType::Identity(rows, rows),
+ square = SquareMatrixType::Random(rows, rows);
+ VectorType v1(rows),
+ v2 = VectorType::Random(rows),
+ vzero = VectorType::Zero(rows);
+
+ do {
+ m1 = MatrixType::Random(rows, cols);
+ } while(m1 == mzero || m1 == m2);
+
+ do {
+ v1 = VectorType::Random(rows);
+ } while(v1 == vzero || v1 == v2);
+
+ VERIFY_IS_APPROX( v1, v1);
+ VERIFY_IS_NOT_APPROX( v1, 2*v1);
+ VERIFY_IS_APPROX( vzero, v1-v1);
+ VERIFY_IS_APPROX( m1, m1);
+ VERIFY_IS_NOT_APPROX( m1, 2*m1);
+ VERIFY_IS_APPROX( mzero, m1-m1);
+
+ VERIFY_IS_APPROX(m3 = m1,m1);
+ MatrixType m4;
+ VERIFY_IS_APPROX(m4 = m1,m1);
+
+ m3.real() = m1.real();
+ VERIFY_IS_APPROX(static_cast<const MatrixType&>(m3).real(), static_cast<const MatrixType&>(m1).real());
+ VERIFY_IS_APPROX(static_cast<const MatrixType&>(m3).real(), m1.real());
+
+ // check == / != operators
+ VERIFY(m1==m1);
+ VERIFY(m1!=m2);
+ VERIFY(!(m1==m2));
+ VERIFY(!(m1!=m1));
+ m1 = m2;
+ VERIFY(m1==m2);
+ VERIFY(!(m1!=m2));
+
+ // check linear structure
+
+ Scalar s1;
+ do {
+ s1 = internal::random<Scalar>();
+ } while(s1 == 0);
+
+ VERIFY_IS_EQUAL(m1+m1, 2*m1);
+ VERIFY_IS_EQUAL(m1+m2-m1, m2);
+ VERIFY_IS_EQUAL(m1*s1, s1*m1);
+ VERIFY_IS_EQUAL((m1+m2)*s1, s1*m1+s1*m2);
+ m3 = m2; m3 += m1;
+ VERIFY_IS_EQUAL(m3, m1+m2);
+ m3 = m2; m3 -= m1;
+ VERIFY_IS_EQUAL(m3, m2-m1);
+ m3 = m2; m3 *= s1;
+ VERIFY_IS_EQUAL(m3, s1*m2);
+
+ // check matrix product.
+
+ VERIFY_IS_APPROX(identity * m1, m1);
+ VERIFY_IS_APPROX(square * (m1 + m2), square * m1 + square * m2);
+ VERIFY_IS_APPROX((m1 + m2).transpose() * square, m1.transpose() * square + m2.transpose() * square);
+ VERIFY_IS_APPROX((m1 * m2.transpose()) * m1, m1 * (m2.transpose() * m1));
+}
+
+void test_integer_types()
+{
+ for(int i = 0; i < g_repeat; i++) {
+ CALL_SUBTEST_1( integer_type_tests(Matrix<unsigned int, 1, 1>()) );
+ CALL_SUBTEST_1( integer_type_tests(Matrix<unsigned long, 3, 4>()) );
+
+ CALL_SUBTEST_2( integer_type_tests(Matrix<long, 2, 2>()) );
+ CALL_SUBTEST_2( signed_integer_type_tests(Matrix<long, 2, 2>()) );
+
+ CALL_SUBTEST_3( integer_type_tests(Matrix<char, 2, Dynamic>(2, 10)) );
+ CALL_SUBTEST_3( signed_integer_type_tests(Matrix<signed char, 2, Dynamic>(2, 10)) );
+
+ CALL_SUBTEST_4( integer_type_tests(Matrix<unsigned char, 3, 3>()) );
+ CALL_SUBTEST_4( integer_type_tests(Matrix<unsigned char, Dynamic, Dynamic>(20, 20)) );
+
+ CALL_SUBTEST_5( integer_type_tests(Matrix<short, Dynamic, 4>(7, 4)) );
+ CALL_SUBTEST_5( signed_integer_type_tests(Matrix<short, Dynamic, 4>(7, 4)) );
+
+ CALL_SUBTEST_6( integer_type_tests(Matrix<unsigned short, 4, 4>()) );
+
+ CALL_SUBTEST_7( integer_type_tests(Matrix<long long, 11, 13>()) );
+ CALL_SUBTEST_7( signed_integer_type_tests(Matrix<long long, 11, 13>()) );
+
+ CALL_SUBTEST_8( integer_type_tests(Matrix<unsigned long long, Dynamic, 5>(1, 5)) );
+ }
+}
diff --git a/test/inverse.cpp b/test/inverse.cpp
new file mode 100644
index 000000000..cff42dd8d
--- /dev/null
+++ b/test/inverse.cpp
@@ -0,0 +1,102 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra.
+//
+// Copyright (C) 2008 Gael Guennebaud <gael.guennebaud@inria.fr>
+// Copyright (C) 2008 Benoit Jacob <jacob.benoit.1@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 "main.h"
+#include <Eigen/LU>
+
+template<typename MatrixType> void inverse(const MatrixType& m)
+{
+ typedef typename MatrixType::Index Index;
+ /* this test covers the following files:
+ Inverse.h
+ */
+ Index rows = m.rows();
+ Index cols = m.cols();
+
+ typedef typename MatrixType::Scalar Scalar;
+ typedef typename NumTraits<Scalar>::Real RealScalar;
+ typedef Matrix<Scalar, MatrixType::ColsAtCompileTime, 1> VectorType;
+
+ MatrixType m1(rows, cols),
+ m2(rows, cols),
+ identity = MatrixType::Identity(rows, rows);
+ createRandomPIMatrixOfRank(rows,rows,rows,m1);
+ m2 = m1.inverse();
+ VERIFY_IS_APPROX(m1, m2.inverse() );
+
+ VERIFY_IS_APPROX((Scalar(2)*m2).inverse(), m2.inverse()*Scalar(0.5));
+
+ VERIFY_IS_APPROX(identity, m1.inverse() * m1 );
+ VERIFY_IS_APPROX(identity, m1 * m1.inverse() );
+
+ VERIFY_IS_APPROX(m1, m1.inverse().inverse() );
+
+ // since for the general case we implement separately row-major and col-major, test that
+ VERIFY_IS_APPROX(MatrixType(m1.transpose().inverse()), MatrixType(m1.inverse().transpose()));
+
+#if !defined(EIGEN_TEST_PART_5) && !defined(EIGEN_TEST_PART_6)
+ //computeInverseAndDetWithCheck tests
+ //First: an invertible matrix
+ bool invertible;
+ RealScalar det;
+
+ m2.setZero();
+ m1.computeInverseAndDetWithCheck(m2, det, invertible);
+ VERIFY(invertible);
+ VERIFY_IS_APPROX(identity, m1*m2);
+ VERIFY_IS_APPROX(det, m1.determinant());
+
+ m2.setZero();
+ m1.computeInverseWithCheck(m2, invertible);
+ VERIFY(invertible);
+ VERIFY_IS_APPROX(identity, m1*m2);
+
+ //Second: a rank one matrix (not invertible, except for 1x1 matrices)
+ VectorType v3 = VectorType::Random(rows);
+ MatrixType m3 = v3*v3.transpose(), m4(rows,cols);
+ m3.computeInverseAndDetWithCheck(m4, det, invertible);
+ VERIFY( rows==1 ? invertible : !invertible );
+ VERIFY_IS_MUCH_SMALLER_THAN(internal::abs(det-m3.determinant()), RealScalar(1));
+ m3.computeInverseWithCheck(m4, invertible);
+ VERIFY( rows==1 ? invertible : !invertible );
+#endif
+
+ // check in-place inversion
+ if(MatrixType::RowsAtCompileTime>=2 && MatrixType::RowsAtCompileTime<=4)
+ {
+ // in-place is forbidden
+ VERIFY_RAISES_ASSERT(m1 = m1.inverse());
+ }
+ else
+ {
+ m2 = m1.inverse();
+ m1 = m1.inverse();
+ VERIFY_IS_APPROX(m1,m2);
+ }
+}
+
+void test_inverse()
+{
+ int s;
+ for(int i = 0; i < g_repeat; i++) {
+ CALL_SUBTEST_1( inverse(Matrix<double,1,1>()) );
+ CALL_SUBTEST_2( inverse(Matrix2d()) );
+ CALL_SUBTEST_3( inverse(Matrix3f()) );
+ CALL_SUBTEST_4( inverse(Matrix4f()) );
+ CALL_SUBTEST_4( inverse(Matrix<float,4,4,DontAlign>()) );
+ s = internal::random<int>(50,320);
+ CALL_SUBTEST_5( inverse(MatrixXf(s,s)) );
+ s = internal::random<int>(25,100);
+ CALL_SUBTEST_6( inverse(MatrixXcd(s,s)) );
+ CALL_SUBTEST_7( inverse(Matrix4d()) );
+ CALL_SUBTEST_7( inverse(Matrix<double,4,4,DontAlign>()) );
+ }
+ EIGEN_UNUSED_VARIABLE(s)
+}
diff --git a/test/jacobi.cpp b/test/jacobi.cpp
new file mode 100644
index 000000000..f64f5d08f
--- /dev/null
+++ b/test/jacobi.cpp
@@ -0,0 +1,81 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra.
+//
+// Copyright (C) 2008 Gael Guennebaud <gael.guennebaud@inria.fr>
+// Copyright (C) 2009 Benoit Jacob <jacob.benoit.1@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 "main.h"
+#include <Eigen/SVD>
+
+template<typename MatrixType, typename JacobiScalar>
+void jacobi(const MatrixType& m = MatrixType())
+{
+ typedef typename MatrixType::Scalar Scalar;
+ typedef typename MatrixType::Index Index;
+ Index rows = m.rows();
+ Index cols = m.cols();
+
+ enum {
+ RowsAtCompileTime = MatrixType::RowsAtCompileTime,
+ ColsAtCompileTime = MatrixType::ColsAtCompileTime
+ };
+
+ typedef Matrix<JacobiScalar, 2, 1> JacobiVector;
+
+ const MatrixType a(MatrixType::Random(rows, cols));
+
+ JacobiVector v = JacobiVector::Random().normalized();
+ JacobiScalar c = v.x(), s = v.y();
+ JacobiRotation<JacobiScalar> rot(c, s);
+
+ {
+ Index p = internal::random<Index>(0, rows-1);
+ Index q;
+ do {
+ q = internal::random<Index>(0, rows-1);
+ } while (q == p);
+
+ MatrixType b = a;
+ b.applyOnTheLeft(p, q, rot);
+ VERIFY_IS_APPROX(b.row(p), c * a.row(p) + internal::conj(s) * a.row(q));
+ VERIFY_IS_APPROX(b.row(q), -s * a.row(p) + internal::conj(c) * a.row(q));
+ }
+
+ {
+ Index p = internal::random<Index>(0, cols-1);
+ Index q;
+ do {
+ q = internal::random<Index>(0, cols-1);
+ } while (q == p);
+
+ MatrixType b = a;
+ b.applyOnTheRight(p, q, rot);
+ VERIFY_IS_APPROX(b.col(p), c * a.col(p) - s * a.col(q));
+ VERIFY_IS_APPROX(b.col(q), internal::conj(s) * a.col(p) + internal::conj(c) * a.col(q));
+ }
+}
+
+void test_jacobi()
+{
+ for(int i = 0; i < g_repeat; i++) {
+ CALL_SUBTEST_1(( jacobi<Matrix3f, float>() ));
+ CALL_SUBTEST_2(( jacobi<Matrix4d, double>() ));
+ CALL_SUBTEST_3(( jacobi<Matrix4cf, float>() ));
+ CALL_SUBTEST_3(( jacobi<Matrix4cf, std::complex<float> >() ));
+
+ int r = internal::random<int>(2, internal::random<int>(1,EIGEN_TEST_MAX_SIZE)/2),
+ c = internal::random<int>(2, internal::random<int>(1,EIGEN_TEST_MAX_SIZE)/2);
+ CALL_SUBTEST_4(( jacobi<MatrixXf, float>(MatrixXf(r,c)) ));
+ CALL_SUBTEST_5(( jacobi<MatrixXcd, double>(MatrixXcd(r,c)) ));
+ CALL_SUBTEST_5(( jacobi<MatrixXcd, std::complex<double> >(MatrixXcd(r,c)) ));
+ // complex<float> is really important to test as it is the only way to cover conjugation issues in certain unaligned paths
+ CALL_SUBTEST_6(( jacobi<MatrixXcf, float>(MatrixXcf(r,c)) ));
+ CALL_SUBTEST_6(( jacobi<MatrixXcf, std::complex<float> >(MatrixXcf(r,c)) ));
+ (void) r;
+ (void) c;
+ }
+}
diff --git a/test/jacobisvd.cpp b/test/jacobisvd.cpp
new file mode 100644
index 000000000..f6c567829
--- /dev/null
+++ b/test/jacobisvd.cpp
@@ -0,0 +1,350 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra.
+//
+// Copyright (C) 2008 Gael Guennebaud <gael.guennebaud@inria.fr>
+// Copyright (C) 2009 Benoit Jacob <jacob.benoit.1@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/.
+
+// discard stack allocation as that too bypasses malloc
+#define EIGEN_STACK_ALLOCATION_LIMIT 0
+#define EIGEN_RUNTIME_NO_MALLOC
+#include "main.h"
+#include <Eigen/SVD>
+
+template<typename MatrixType, int QRPreconditioner>
+void jacobisvd_check_full(const MatrixType& m, const JacobiSVD<MatrixType, QRPreconditioner>& svd)
+{
+ typedef typename MatrixType::Index Index;
+ Index rows = m.rows();
+ Index cols = m.cols();
+
+ enum {
+ RowsAtCompileTime = MatrixType::RowsAtCompileTime,
+ ColsAtCompileTime = MatrixType::ColsAtCompileTime
+ };
+
+ typedef typename MatrixType::Scalar Scalar;
+ typedef typename NumTraits<Scalar>::Real RealScalar;
+ typedef Matrix<Scalar, RowsAtCompileTime, RowsAtCompileTime> MatrixUType;
+ typedef Matrix<Scalar, ColsAtCompileTime, ColsAtCompileTime> MatrixVType;
+ typedef Matrix<Scalar, RowsAtCompileTime, 1> ColVectorType;
+ typedef Matrix<Scalar, ColsAtCompileTime, 1> InputVectorType;
+
+ MatrixType sigma = MatrixType::Zero(rows,cols);
+ sigma.diagonal() = svd.singularValues().template cast<Scalar>();
+ MatrixUType u = svd.matrixU();
+ MatrixVType v = svd.matrixV();
+
+ VERIFY_IS_APPROX(m, u * sigma * v.adjoint());
+ VERIFY_IS_UNITARY(u);
+ VERIFY_IS_UNITARY(v);
+}
+
+template<typename MatrixType, int QRPreconditioner>
+void jacobisvd_compare_to_full(const MatrixType& m,
+ unsigned int computationOptions,
+ const JacobiSVD<MatrixType, QRPreconditioner>& referenceSvd)
+{
+ typedef typename MatrixType::Index Index;
+ Index rows = m.rows();
+ Index cols = m.cols();
+ Index diagSize = (std::min)(rows, cols);
+
+ JacobiSVD<MatrixType, QRPreconditioner> svd(m, computationOptions);
+
+ VERIFY_IS_APPROX(svd.singularValues(), referenceSvd.singularValues());
+ if(computationOptions & ComputeFullU)
+ VERIFY_IS_APPROX(svd.matrixU(), referenceSvd.matrixU());
+ if(computationOptions & ComputeThinU)
+ VERIFY_IS_APPROX(svd.matrixU(), referenceSvd.matrixU().leftCols(diagSize));
+ if(computationOptions & ComputeFullV)
+ VERIFY_IS_APPROX(svd.matrixV(), referenceSvd.matrixV());
+ if(computationOptions & ComputeThinV)
+ VERIFY_IS_APPROX(svd.matrixV(), referenceSvd.matrixV().leftCols(diagSize));
+}
+
+template<typename MatrixType, int QRPreconditioner>
+void jacobisvd_solve(const MatrixType& m, unsigned int computationOptions)
+{
+ typedef typename MatrixType::Scalar Scalar;
+ typedef typename MatrixType::Index Index;
+ Index rows = m.rows();
+ Index cols = m.cols();
+
+ enum {
+ RowsAtCompileTime = MatrixType::RowsAtCompileTime,
+ ColsAtCompileTime = MatrixType::ColsAtCompileTime
+ };
+
+ typedef Matrix<Scalar, RowsAtCompileTime, Dynamic> RhsType;
+ typedef Matrix<Scalar, ColsAtCompileTime, Dynamic> SolutionType;
+
+ RhsType rhs = RhsType::Random(rows, internal::random<Index>(1, cols));
+ JacobiSVD<MatrixType, QRPreconditioner> svd(m, computationOptions);
+ SolutionType x = svd.solve(rhs);
+ // evaluate normal equation which works also for least-squares solutions
+ VERIFY_IS_APPROX(m.adjoint()*m*x,m.adjoint()*rhs);
+}
+
+template<typename MatrixType, int QRPreconditioner>
+void jacobisvd_test_all_computation_options(const MatrixType& m)
+{
+ if (QRPreconditioner == NoQRPreconditioner && m.rows() != m.cols())
+ return;
+ JacobiSVD<MatrixType, QRPreconditioner> fullSvd(m, ComputeFullU|ComputeFullV);
+
+ jacobisvd_check_full(m, fullSvd);
+ jacobisvd_solve<MatrixType, QRPreconditioner>(m, ComputeFullU | ComputeFullV);
+
+ if(QRPreconditioner == FullPivHouseholderQRPreconditioner)
+ return;
+
+ jacobisvd_compare_to_full(m, ComputeFullU, fullSvd);
+ jacobisvd_compare_to_full(m, ComputeFullV, fullSvd);
+ jacobisvd_compare_to_full(m, 0, fullSvd);
+
+ if (MatrixType::ColsAtCompileTime == Dynamic) {
+ // thin U/V are only available with dynamic number of columns
+ jacobisvd_compare_to_full(m, ComputeFullU|ComputeThinV, fullSvd);
+ jacobisvd_compare_to_full(m, ComputeThinV, fullSvd);
+ jacobisvd_compare_to_full(m, ComputeThinU|ComputeFullV, fullSvd);
+ jacobisvd_compare_to_full(m, ComputeThinU , fullSvd);
+ jacobisvd_compare_to_full(m, ComputeThinU|ComputeThinV, fullSvd);
+ jacobisvd_solve<MatrixType, QRPreconditioner>(m, ComputeFullU | ComputeThinV);
+ jacobisvd_solve<MatrixType, QRPreconditioner>(m, ComputeThinU | ComputeFullV);
+ jacobisvd_solve<MatrixType, QRPreconditioner>(m, ComputeThinU | ComputeThinV);
+
+ // test reconstruction
+ typedef typename MatrixType::Index Index;
+ Index diagSize = (std::min)(m.rows(), m.cols());
+ JacobiSVD<MatrixType, QRPreconditioner> svd(m, ComputeThinU | ComputeThinV);
+ VERIFY_IS_APPROX(m, svd.matrixU().leftCols(diagSize) * svd.singularValues().asDiagonal() * svd.matrixV().leftCols(diagSize).adjoint());
+ }
+}
+
+template<typename MatrixType>
+void jacobisvd(const MatrixType& a = MatrixType(), bool pickrandom = true)
+{
+ MatrixType m = pickrandom ? MatrixType::Random(a.rows(), a.cols()) : a;
+
+ jacobisvd_test_all_computation_options<MatrixType, FullPivHouseholderQRPreconditioner>(m);
+ jacobisvd_test_all_computation_options<MatrixType, ColPivHouseholderQRPreconditioner>(m);
+ jacobisvd_test_all_computation_options<MatrixType, HouseholderQRPreconditioner>(m);
+ jacobisvd_test_all_computation_options<MatrixType, NoQRPreconditioner>(m);
+}
+
+template<typename MatrixType> void jacobisvd_verify_assert(const MatrixType& m)
+{
+ typedef typename MatrixType::Scalar Scalar;
+ typedef typename MatrixType::Index Index;
+ Index rows = m.rows();
+ Index cols = m.cols();
+
+ enum {
+ RowsAtCompileTime = MatrixType::RowsAtCompileTime,
+ ColsAtCompileTime = MatrixType::ColsAtCompileTime
+ };
+
+ typedef Matrix<Scalar, RowsAtCompileTime, 1> RhsType;
+
+ RhsType rhs(rows);
+
+ JacobiSVD<MatrixType> svd;
+ VERIFY_RAISES_ASSERT(svd.matrixU())
+ VERIFY_RAISES_ASSERT(svd.singularValues())
+ VERIFY_RAISES_ASSERT(svd.matrixV())
+ VERIFY_RAISES_ASSERT(svd.solve(rhs))
+
+ MatrixType a = MatrixType::Zero(rows, cols);
+ a.setZero();
+ svd.compute(a, 0);
+ VERIFY_RAISES_ASSERT(svd.matrixU())
+ VERIFY_RAISES_ASSERT(svd.matrixV())
+ svd.singularValues();
+ VERIFY_RAISES_ASSERT(svd.solve(rhs))
+
+ if (ColsAtCompileTime == Dynamic)
+ {
+ svd.compute(a, ComputeThinU);
+ svd.matrixU();
+ VERIFY_RAISES_ASSERT(svd.matrixV())
+ VERIFY_RAISES_ASSERT(svd.solve(rhs))
+
+ svd.compute(a, ComputeThinV);
+ svd.matrixV();
+ VERIFY_RAISES_ASSERT(svd.matrixU())
+ VERIFY_RAISES_ASSERT(svd.solve(rhs))
+
+ JacobiSVD<MatrixType, FullPivHouseholderQRPreconditioner> svd_fullqr;
+ VERIFY_RAISES_ASSERT(svd_fullqr.compute(a, ComputeFullU|ComputeThinV))
+ VERIFY_RAISES_ASSERT(svd_fullqr.compute(a, ComputeThinU|ComputeThinV))
+ VERIFY_RAISES_ASSERT(svd_fullqr.compute(a, ComputeThinU|ComputeFullV))
+ }
+ else
+ {
+ VERIFY_RAISES_ASSERT(svd.compute(a, ComputeThinU))
+ VERIFY_RAISES_ASSERT(svd.compute(a, ComputeThinV))
+ }
+}
+
+template<typename MatrixType>
+void jacobisvd_method()
+{
+ enum { Size = MatrixType::RowsAtCompileTime };
+ typedef typename MatrixType::RealScalar RealScalar;
+ typedef Matrix<RealScalar, Size, 1> RealVecType;
+ MatrixType m = MatrixType::Identity();
+ VERIFY_IS_APPROX(m.jacobiSvd().singularValues(), RealVecType::Ones());
+ VERIFY_RAISES_ASSERT(m.jacobiSvd().matrixU());
+ VERIFY_RAISES_ASSERT(m.jacobiSvd().matrixV());
+ VERIFY_IS_APPROX(m.jacobiSvd(ComputeFullU|ComputeFullV).solve(m), m);
+}
+
+// work around stupid msvc error when constructing at compile time an expression that involves
+// a division by zero, even if the numeric type has floating point
+template<typename Scalar>
+EIGEN_DONT_INLINE Scalar zero() { return Scalar(0); }
+
+// workaround aggressive optimization in ICC
+template<typename T> EIGEN_DONT_INLINE T sub(T a, T b) { return a - b; }
+
+template<typename MatrixType>
+void jacobisvd_inf_nan()
+{
+ // all this function does is verify we don't iterate infinitely on nan/inf values
+
+ JacobiSVD<MatrixType> svd;
+ typedef typename MatrixType::Scalar Scalar;
+ Scalar some_inf = Scalar(1) / zero<Scalar>();
+ VERIFY(sub(some_inf, some_inf) != sub(some_inf, some_inf));
+ svd.compute(MatrixType::Constant(10,10,some_inf), ComputeFullU | ComputeFullV);
+
+ Scalar some_nan = zero<Scalar>() / zero<Scalar>();
+ VERIFY(some_nan != some_nan);
+ svd.compute(MatrixType::Constant(10,10,some_nan), ComputeFullU | ComputeFullV);
+
+ MatrixType m = MatrixType::Zero(10,10);
+ m(internal::random<int>(0,9), internal::random<int>(0,9)) = some_inf;
+ svd.compute(m, ComputeFullU | ComputeFullV);
+
+ m = MatrixType::Zero(10,10);
+ m(internal::random<int>(0,9), internal::random<int>(0,9)) = some_nan;
+ svd.compute(m, ComputeFullU | ComputeFullV);
+}
+
+// Regression test for bug 286: JacobiSVD loops indefinitely with some
+// matrices containing denormal numbers.
+void jacobisvd_bug286()
+{
+#if defined __INTEL_COMPILER
+// shut up warning #239: floating point underflow
+#pragma warning push
+#pragma warning disable 239
+#endif
+ Matrix2d M;
+ M << -7.90884e-313, -4.94e-324,
+ 0, 5.60844e-313;
+#if defined __INTEL_COMPILER
+#pragma warning pop
+#endif
+ JacobiSVD<Matrix2d> svd;
+ svd.compute(M); // just check we don't loop indefinitely
+}
+
+void jacobisvd_preallocate()
+{
+ Vector3f v(3.f, 2.f, 1.f);
+ MatrixXf m = v.asDiagonal();
+
+ internal::set_is_malloc_allowed(false);
+ VERIFY_RAISES_ASSERT(VectorXf v(10);)
+ JacobiSVD<MatrixXf> svd;
+ internal::set_is_malloc_allowed(true);
+ svd.compute(m);
+ VERIFY_IS_APPROX(svd.singularValues(), v);
+
+ JacobiSVD<MatrixXf> svd2(3,3);
+ internal::set_is_malloc_allowed(false);
+ svd2.compute(m);
+ internal::set_is_malloc_allowed(true);
+ VERIFY_IS_APPROX(svd2.singularValues(), v);
+ VERIFY_RAISES_ASSERT(svd2.matrixU());
+ VERIFY_RAISES_ASSERT(svd2.matrixV());
+ svd2.compute(m, ComputeFullU | ComputeFullV);
+ VERIFY_IS_APPROX(svd2.matrixU(), Matrix3f::Identity());
+ VERIFY_IS_APPROX(svd2.matrixV(), Matrix3f::Identity());
+ internal::set_is_malloc_allowed(false);
+ svd2.compute(m);
+ internal::set_is_malloc_allowed(true);
+
+ JacobiSVD<MatrixXf> svd3(3,3,ComputeFullU|ComputeFullV);
+ internal::set_is_malloc_allowed(false);
+ svd2.compute(m);
+ internal::set_is_malloc_allowed(true);
+ VERIFY_IS_APPROX(svd2.singularValues(), v);
+ VERIFY_IS_APPROX(svd2.matrixU(), Matrix3f::Identity());
+ VERIFY_IS_APPROX(svd2.matrixV(), Matrix3f::Identity());
+ internal::set_is_malloc_allowed(false);
+ svd2.compute(m, ComputeFullU|ComputeFullV);
+ internal::set_is_malloc_allowed(true);
+}
+
+void test_jacobisvd()
+{
+ CALL_SUBTEST_3(( jacobisvd_verify_assert(Matrix3f()) ));
+ CALL_SUBTEST_4(( jacobisvd_verify_assert(Matrix4d()) ));
+ CALL_SUBTEST_7(( jacobisvd_verify_assert(MatrixXf(10,12)) ));
+ CALL_SUBTEST_8(( jacobisvd_verify_assert(MatrixXcd(7,5)) ));
+
+ for(int i = 0; i < g_repeat; i++) {
+ Matrix2cd m;
+ m << 0, 1,
+ 0, 1;
+ CALL_SUBTEST_1(( jacobisvd(m, false) ));
+ m << 1, 0,
+ 1, 0;
+ CALL_SUBTEST_1(( jacobisvd(m, false) ));
+
+ Matrix2d n;
+ n << 0, 0,
+ 0, 0;
+ CALL_SUBTEST_2(( jacobisvd(n, false) ));
+ n << 0, 0,
+ 0, 1;
+ CALL_SUBTEST_2(( jacobisvd(n, false) ));
+
+ CALL_SUBTEST_3(( jacobisvd<Matrix3f>() ));
+ CALL_SUBTEST_4(( jacobisvd<Matrix4d>() ));
+ CALL_SUBTEST_5(( jacobisvd<Matrix<float,3,5> >() ));
+ CALL_SUBTEST_6(( jacobisvd<Matrix<double,Dynamic,2> >(Matrix<double,Dynamic,2>(10,2)) ));
+
+ int r = internal::random<int>(1, 30),
+ c = internal::random<int>(1, 30);
+ CALL_SUBTEST_7(( jacobisvd<MatrixXf>(MatrixXf(r,c)) ));
+ CALL_SUBTEST_8(( jacobisvd<MatrixXcd>(MatrixXcd(r,c)) ));
+ (void) r;
+ (void) c;
+
+ // Test on inf/nan matrix
+ CALL_SUBTEST_7( jacobisvd_inf_nan<MatrixXf>() );
+ }
+
+ CALL_SUBTEST_7(( jacobisvd<MatrixXf>(MatrixXf(internal::random<int>(EIGEN_TEST_MAX_SIZE/4, EIGEN_TEST_MAX_SIZE/2), internal::random<int>(EIGEN_TEST_MAX_SIZE/4, EIGEN_TEST_MAX_SIZE/2))) ));
+ CALL_SUBTEST_8(( jacobisvd<MatrixXcd>(MatrixXcd(internal::random<int>(EIGEN_TEST_MAX_SIZE/4, EIGEN_TEST_MAX_SIZE/3), internal::random<int>(EIGEN_TEST_MAX_SIZE/4, EIGEN_TEST_MAX_SIZE/3))) ));
+
+ // test matrixbase method
+ CALL_SUBTEST_1(( jacobisvd_method<Matrix2cd>() ));
+ CALL_SUBTEST_3(( jacobisvd_method<Matrix3f>() ));
+
+ // Test problem size constructors
+ CALL_SUBTEST_7( JacobiSVD<MatrixXf>(10,10) );
+
+ // Check that preallocation avoids subsequent mallocs
+ CALL_SUBTEST_9( jacobisvd_preallocate() );
+
+ // Regression check for bug 286
+ CALL_SUBTEST_2( jacobisvd_bug286() );
+}
diff --git a/test/linearstructure.cpp b/test/linearstructure.cpp
new file mode 100644
index 000000000..fd071c995
--- /dev/null
+++ b/test/linearstructure.cpp
@@ -0,0 +1,83 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra.
+//
+// Copyright (C) 2006-2008 Benoit Jacob <jacob.benoit.1@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 "main.h"
+
+template<typename MatrixType> void linearStructure(const MatrixType& m)
+{
+ /* this test covers the following files:
+ CwiseUnaryOp.h, CwiseBinaryOp.h, SelfCwiseBinaryOp.h
+ */
+ typedef typename MatrixType::Index Index;
+ typedef typename MatrixType::Scalar Scalar;
+
+ Index rows = m.rows();
+ Index cols = m.cols();
+
+ // this test relies a lot on Random.h, and there's not much more that we can do
+ // to test it, hence I consider that we will have tested Random.h
+ MatrixType m1 = MatrixType::Random(rows, cols),
+ m2 = MatrixType::Random(rows, cols),
+ m3(rows, cols);
+
+ Scalar s1 = internal::random<Scalar>();
+ while (internal::abs(s1)<1e-3) s1 = internal::random<Scalar>();
+
+ Index r = internal::random<Index>(0, rows-1),
+ c = internal::random<Index>(0, cols-1);
+
+ VERIFY_IS_APPROX(-(-m1), m1);
+ VERIFY_IS_APPROX(m1+m1, 2*m1);
+ VERIFY_IS_APPROX(m1+m2-m1, m2);
+ VERIFY_IS_APPROX(-m2+m1+m2, m1);
+ VERIFY_IS_APPROX(m1*s1, s1*m1);
+ VERIFY_IS_APPROX((m1+m2)*s1, s1*m1+s1*m2);
+ VERIFY_IS_APPROX((-m1+m2)*s1, -s1*m1+s1*m2);
+ m3 = m2; m3 += m1;
+ VERIFY_IS_APPROX(m3, m1+m2);
+ m3 = m2; m3 -= m1;
+ VERIFY_IS_APPROX(m3, m2-m1);
+ m3 = m2; m3 *= s1;
+ VERIFY_IS_APPROX(m3, s1*m2);
+ if(!NumTraits<Scalar>::IsInteger)
+ {
+ m3 = m2; m3 /= s1;
+ VERIFY_IS_APPROX(m3, m2/s1);
+ }
+
+ // again, test operator() to check const-qualification
+ VERIFY_IS_APPROX((-m1)(r,c), -(m1(r,c)));
+ VERIFY_IS_APPROX((m1-m2)(r,c), (m1(r,c))-(m2(r,c)));
+ VERIFY_IS_APPROX((m1+m2)(r,c), (m1(r,c))+(m2(r,c)));
+ VERIFY_IS_APPROX((s1*m1)(r,c), s1*(m1(r,c)));
+ VERIFY_IS_APPROX((m1*s1)(r,c), (m1(r,c))*s1);
+ if(!NumTraits<Scalar>::IsInteger)
+ VERIFY_IS_APPROX((m1/s1)(r,c), (m1(r,c))/s1);
+
+ // use .block to disable vectorization and compare to the vectorized version
+ VERIFY_IS_APPROX(m1+m1.block(0,0,rows,cols), m1+m1);
+ VERIFY_IS_APPROX(m1.cwiseProduct(m1.block(0,0,rows,cols)), m1.cwiseProduct(m1));
+ VERIFY_IS_APPROX(m1 - m1.block(0,0,rows,cols), m1 - m1);
+ VERIFY_IS_APPROX(m1.block(0,0,rows,cols) * s1, m1 * s1);
+}
+
+void test_linearstructure()
+{
+ for(int i = 0; i < g_repeat; i++) {
+ CALL_SUBTEST_1( linearStructure(Matrix<float, 1, 1>()) );
+ CALL_SUBTEST_2( linearStructure(Matrix2f()) );
+ CALL_SUBTEST_3( linearStructure(Vector3d()) );
+ CALL_SUBTEST_4( linearStructure(Matrix4d()) );
+ CALL_SUBTEST_5( linearStructure(MatrixXcf(internal::random<int>(1,EIGEN_TEST_MAX_SIZE/2), internal::random<int>(1,EIGEN_TEST_MAX_SIZE/2))) );
+ CALL_SUBTEST_6( linearStructure(MatrixXf (internal::random<int>(1,EIGEN_TEST_MAX_SIZE), internal::random<int>(1,EIGEN_TEST_MAX_SIZE))) );
+ CALL_SUBTEST_7( linearStructure(MatrixXi (internal::random<int>(1,EIGEN_TEST_MAX_SIZE), internal::random<int>(1,EIGEN_TEST_MAX_SIZE))) );
+ CALL_SUBTEST_8( linearStructure(MatrixXcd(internal::random<int>(1,EIGEN_TEST_MAX_SIZE/2), internal::random<int>(1,EIGEN_TEST_MAX_SIZE/2))) );
+ CALL_SUBTEST_9( linearStructure(ArrayXXf (internal::random<int>(1,EIGEN_TEST_MAX_SIZE), internal::random<int>(1,EIGEN_TEST_MAX_SIZE))) );
+ }
+}
diff --git a/test/lu.cpp b/test/lu.cpp
new file mode 100644
index 000000000..6cbcb0a95
--- /dev/null
+++ b/test/lu.cpp
@@ -0,0 +1,207 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra.
+//
+// Copyright (C) 2008-2009 Benoit Jacob <jacob.benoit.1@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 "main.h"
+#include <Eigen/LU>
+using namespace std;
+
+template<typename MatrixType> void lu_non_invertible()
+{
+ typedef typename MatrixType::Index Index;
+ typedef typename MatrixType::Scalar Scalar;
+ typedef typename MatrixType::RealScalar RealScalar;
+ /* this test covers the following files:
+ LU.h
+ */
+ Index rows, cols, cols2;
+ if(MatrixType::RowsAtCompileTime==Dynamic)
+ {
+ rows = internal::random<Index>(2,EIGEN_TEST_MAX_SIZE);
+ }
+ else
+ {
+ rows = MatrixType::RowsAtCompileTime;
+ }
+ if(MatrixType::ColsAtCompileTime==Dynamic)
+ {
+ cols = internal::random<Index>(2,EIGEN_TEST_MAX_SIZE);
+ cols2 = internal::random<int>(2,EIGEN_TEST_MAX_SIZE);
+ }
+ else
+ {
+ cols2 = cols = MatrixType::ColsAtCompileTime;
+ }
+
+ enum {
+ RowsAtCompileTime = MatrixType::RowsAtCompileTime,
+ ColsAtCompileTime = MatrixType::ColsAtCompileTime
+ };
+ typedef typename internal::kernel_retval_base<FullPivLU<MatrixType> >::ReturnType KernelMatrixType;
+ typedef typename internal::image_retval_base<FullPivLU<MatrixType> >::ReturnType ImageMatrixType;
+ typedef Matrix<typename MatrixType::Scalar, ColsAtCompileTime, ColsAtCompileTime>
+ CMatrixType;
+ typedef Matrix<typename MatrixType::Scalar, RowsAtCompileTime, RowsAtCompileTime>
+ RMatrixType;
+
+ Index rank = internal::random<Index>(1, (std::min)(rows, cols)-1);
+
+ // The image of the zero matrix should consist of a single (zero) column vector
+ VERIFY((MatrixType::Zero(rows,cols).fullPivLu().image(MatrixType::Zero(rows,cols)).cols() == 1));
+
+ MatrixType m1(rows, cols), m3(rows, cols2);
+ CMatrixType m2(cols, cols2);
+ createRandomPIMatrixOfRank(rank, rows, cols, m1);
+
+ FullPivLU<MatrixType> lu;
+
+ // The special value 0.01 below works well in tests. Keep in mind that we're only computing the rank
+ // of singular values are either 0 or 1.
+ // So it's not clear at all that the epsilon should play any role there.
+ lu.setThreshold(RealScalar(0.01));
+ lu.compute(m1);
+
+ MatrixType u(rows,cols);
+ u = lu.matrixLU().template triangularView<Upper>();
+ RMatrixType l = RMatrixType::Identity(rows,rows);
+ l.block(0,0,rows,(std::min)(rows,cols)).template triangularView<StrictlyLower>()
+ = lu.matrixLU().block(0,0,rows,(std::min)(rows,cols));
+
+ VERIFY_IS_APPROX(lu.permutationP() * m1 * lu.permutationQ(), l*u);
+
+ KernelMatrixType m1kernel = lu.kernel();
+ ImageMatrixType m1image = lu.image(m1);
+
+ VERIFY_IS_APPROX(m1, lu.reconstructedMatrix());
+ VERIFY(rank == lu.rank());
+ VERIFY(cols - lu.rank() == lu.dimensionOfKernel());
+ VERIFY(!lu.isInjective());
+ VERIFY(!lu.isInvertible());
+ VERIFY(!lu.isSurjective());
+ VERIFY((m1 * m1kernel).isMuchSmallerThan(m1));
+ VERIFY(m1image.fullPivLu().rank() == rank);
+ VERIFY_IS_APPROX(m1 * m1.adjoint() * m1image, m1image);
+
+ m2 = CMatrixType::Random(cols,cols2);
+ m3 = m1*m2;
+ m2 = CMatrixType::Random(cols,cols2);
+ // test that the code, which does resize(), may be applied to an xpr
+ m2.block(0,0,m2.rows(),m2.cols()) = lu.solve(m3);
+ VERIFY_IS_APPROX(m3, m1*m2);
+}
+
+template<typename MatrixType> void lu_invertible()
+{
+ /* this test covers the following files:
+ LU.h
+ */
+ typedef typename MatrixType::Scalar Scalar;
+ typedef typename NumTraits<typename MatrixType::Scalar>::Real RealScalar;
+ int size = internal::random<int>(1,EIGEN_TEST_MAX_SIZE);
+
+ MatrixType m1(size, size), m2(size, size), m3(size, size);
+ FullPivLU<MatrixType> lu;
+ lu.setThreshold(RealScalar(0.01));
+ do {
+ m1 = MatrixType::Random(size,size);
+ lu.compute(m1);
+ } while(!lu.isInvertible());
+
+ VERIFY_IS_APPROX(m1, lu.reconstructedMatrix());
+ VERIFY(0 == lu.dimensionOfKernel());
+ VERIFY(lu.kernel().cols() == 1); // the kernel() should consist of a single (zero) column vector
+ VERIFY(size == lu.rank());
+ VERIFY(lu.isInjective());
+ VERIFY(lu.isSurjective());
+ VERIFY(lu.isInvertible());
+ VERIFY(lu.image(m1).fullPivLu().isInvertible());
+ m3 = MatrixType::Random(size,size);
+ m2 = lu.solve(m3);
+ VERIFY_IS_APPROX(m3, m1*m2);
+ VERIFY_IS_APPROX(m2, lu.inverse()*m3);
+}
+
+template<typename MatrixType> void lu_partial_piv()
+{
+ /* this test covers the following files:
+ PartialPivLU.h
+ */
+ typedef typename MatrixType::Index Index;
+ typedef typename MatrixType::Scalar Scalar;
+ typedef typename NumTraits<typename MatrixType::Scalar>::Real RealScalar;
+ Index rows = internal::random<Index>(1,4);
+ Index cols = rows;
+
+ MatrixType m1(cols, rows);
+ m1.setRandom();
+ PartialPivLU<MatrixType> plu(m1);
+
+ VERIFY_IS_APPROX(m1, plu.reconstructedMatrix());
+}
+
+template<typename MatrixType> void lu_verify_assert()
+{
+ MatrixType tmp;
+
+ FullPivLU<MatrixType> lu;
+ VERIFY_RAISES_ASSERT(lu.matrixLU())
+ VERIFY_RAISES_ASSERT(lu.permutationP())
+ VERIFY_RAISES_ASSERT(lu.permutationQ())
+ VERIFY_RAISES_ASSERT(lu.kernel())
+ VERIFY_RAISES_ASSERT(lu.image(tmp))
+ VERIFY_RAISES_ASSERT(lu.solve(tmp))
+ VERIFY_RAISES_ASSERT(lu.determinant())
+ VERIFY_RAISES_ASSERT(lu.rank())
+ VERIFY_RAISES_ASSERT(lu.dimensionOfKernel())
+ VERIFY_RAISES_ASSERT(lu.isInjective())
+ VERIFY_RAISES_ASSERT(lu.isSurjective())
+ VERIFY_RAISES_ASSERT(lu.isInvertible())
+ VERIFY_RAISES_ASSERT(lu.inverse())
+
+ PartialPivLU<MatrixType> plu;
+ VERIFY_RAISES_ASSERT(plu.matrixLU())
+ VERIFY_RAISES_ASSERT(plu.permutationP())
+ VERIFY_RAISES_ASSERT(plu.solve(tmp))
+ VERIFY_RAISES_ASSERT(plu.determinant())
+ VERIFY_RAISES_ASSERT(plu.inverse())
+}
+
+void test_lu()
+{
+ for(int i = 0; i < g_repeat; i++) {
+ CALL_SUBTEST_1( lu_non_invertible<Matrix3f>() );
+ CALL_SUBTEST_1( lu_verify_assert<Matrix3f>() );
+
+ CALL_SUBTEST_2( (lu_non_invertible<Matrix<double, 4, 6> >()) );
+ CALL_SUBTEST_2( (lu_verify_assert<Matrix<double, 4, 6> >()) );
+
+ CALL_SUBTEST_3( lu_non_invertible<MatrixXf>() );
+ CALL_SUBTEST_3( lu_invertible<MatrixXf>() );
+ CALL_SUBTEST_3( lu_verify_assert<MatrixXf>() );
+
+ CALL_SUBTEST_4( lu_non_invertible<MatrixXd>() );
+ CALL_SUBTEST_4( lu_invertible<MatrixXd>() );
+ CALL_SUBTEST_4( lu_partial_piv<MatrixXd>() );
+ CALL_SUBTEST_4( lu_verify_assert<MatrixXd>() );
+
+ CALL_SUBTEST_5( lu_non_invertible<MatrixXcf>() );
+ CALL_SUBTEST_5( lu_invertible<MatrixXcf>() );
+ CALL_SUBTEST_5( lu_verify_assert<MatrixXcf>() );
+
+ CALL_SUBTEST_6( lu_non_invertible<MatrixXcd>() );
+ CALL_SUBTEST_6( lu_invertible<MatrixXcd>() );
+ CALL_SUBTEST_6( lu_partial_piv<MatrixXcd>() );
+ CALL_SUBTEST_6( lu_verify_assert<MatrixXcd>() );
+
+ CALL_SUBTEST_7(( lu_non_invertible<Matrix<float,Dynamic,16> >() ));
+
+ // Test problem size constructors
+ CALL_SUBTEST_9( PartialPivLU<MatrixXf>(10) );
+ CALL_SUBTEST_9( FullPivLU<MatrixXf>(10, 20); );
+ }
+}
diff --git a/test/main.h b/test/main.h
new file mode 100644
index 000000000..2da327c17
--- /dev/null
+++ b/test/main.h
@@ -0,0 +1,472 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra.
+//
+// Copyright (C) 2006-2008 Benoit Jacob <jacob.benoit.1@gmail.com>
+// Copyright (C) 2008 Gael Guennebaud <gael.guennebaud@inria.fr>
+//
+// This Source Code Form is subject to the terms of the Mozilla
+// Public License v. 2.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 <cstdlib>
+#include <cerrno>
+#include <ctime>
+#include <iostream>
+#include <fstream>
+#include <string>
+#include <vector>
+#include <typeinfo>
+#include <limits>
+#include <algorithm>
+#include <sstream>
+#include <complex>
+#include <deque>
+#include <queue>
+
+#define min(A,B) please_protect_your_min_with_parentheses
+#define max(A,B) please_protect_your_max_with_parentheses
+
+#define FORBIDDEN_IDENTIFIER (this_identifier_is_forbidden_to_avoid_clashes) this_identifier_is_forbidden_to_avoid_clashes
+// B0 is defined in POSIX header termios.h
+#define B0 FORBIDDEN_IDENTIFIER
+
+// the following file is automatically generated by cmake
+#include "split_test_helper.h"
+
+#ifdef NDEBUG
+#undef NDEBUG
+#endif
+
+// bounds integer values for AltiVec
+#ifdef __ALTIVEC__
+#define EIGEN_MAKING_DOCS
+#endif
+
+#ifndef EIGEN_TEST_FUNC
+#error EIGEN_TEST_FUNC must be defined
+#endif
+
+#define DEFAULT_REPEAT 10
+
+#ifdef __ICC
+// disable warning #279: controlling expression is constant
+#pragma warning disable 279
+#endif
+
+namespace Eigen
+{
+ static std::vector<std::string> g_test_stack;
+ static int g_repeat;
+ static unsigned int g_seed;
+ static bool g_has_set_repeat, g_has_set_seed;
+}
+
+#define EI_PP_MAKE_STRING2(S) #S
+#define EI_PP_MAKE_STRING(S) EI_PP_MAKE_STRING2(S)
+
+#define EIGEN_DEFAULT_IO_FORMAT IOFormat(4, 0, " ", "\n", "", "", "", "")
+
+#ifndef EIGEN_NO_ASSERTION_CHECKING
+
+ namespace Eigen
+ {
+ static const bool should_raise_an_assert = false;
+
+ // Used to avoid to raise two exceptions at a time in which
+ // case the exception is not properly caught.
+ // This may happen when a second exceptions is triggered in a destructor.
+ static bool no_more_assert = false;
+ static bool report_on_cerr_on_assert_failure = true;
+
+ struct eigen_assert_exception
+ {
+ eigen_assert_exception(void) {}
+ ~eigen_assert_exception() { Eigen::no_more_assert = false; }
+ };
+ }
+ // If EIGEN_DEBUG_ASSERTS is defined and if no assertion is triggered while
+ // one should have been, then the list of excecuted assertions is printed out.
+ //
+ // EIGEN_DEBUG_ASSERTS is not enabled by default as it
+ // significantly increases the compilation time
+ // and might even introduce side effects that would hide
+ // some memory errors.
+ #ifdef EIGEN_DEBUG_ASSERTS
+
+ namespace Eigen
+ {
+ namespace internal
+ {
+ static bool push_assert = false;
+ }
+ static std::vector<std::string> eigen_assert_list;
+ }
+ #define eigen_assert(a) \
+ if( (!(a)) && (!no_more_assert) ) \
+ { \
+ if(report_on_cerr_on_assert_failure) \
+ std::cerr << #a << " " __FILE__ << "(" << __LINE__ << ")\n"; \
+ Eigen::no_more_assert = true; \
+ throw Eigen::eigen_assert_exception(); \
+ } \
+ else if (Eigen::internal::push_assert) \
+ { \
+ eigen_assert_list.push_back(std::string(EI_PP_MAKE_STRING(__FILE__) " (" EI_PP_MAKE_STRING(__LINE__) ") : " #a) ); \
+ }
+
+ #define VERIFY_RAISES_ASSERT(a) \
+ { \
+ Eigen::no_more_assert = false; \
+ Eigen::eigen_assert_list.clear(); \
+ Eigen::internal::push_assert = true; \
+ Eigen::report_on_cerr_on_assert_failure = false; \
+ try { \
+ a; \
+ std::cerr << "One of the following asserts should have been triggered:\n"; \
+ for (uint ai=0 ; ai<eigen_assert_list.size() ; ++ai) \
+ std::cerr << " " << eigen_assert_list[ai] << "\n"; \
+ VERIFY(Eigen::should_raise_an_assert && # a); \
+ } catch (Eigen::eigen_assert_exception) { \
+ Eigen::internal::push_assert = false; VERIFY(true); \
+ } \
+ Eigen::report_on_cerr_on_assert_failure = true; \
+ Eigen::internal::push_assert = false; \
+ }
+
+ #else // EIGEN_DEBUG_ASSERTS
+ // see bug 89. The copy_bool here is working around a bug in gcc <= 4.3
+ #define eigen_assert(a) \
+ if( (!Eigen::internal::copy_bool(a)) && (!no_more_assert) )\
+ { \
+ Eigen::no_more_assert = true; \
+ if(report_on_cerr_on_assert_failure) \
+ eigen_plain_assert(a); \
+ else \
+ throw Eigen::eigen_assert_exception(); \
+ }
+ #define VERIFY_RAISES_ASSERT(a) { \
+ Eigen::no_more_assert = false; \
+ Eigen::report_on_cerr_on_assert_failure = false; \
+ try { \
+ a; \
+ VERIFY(Eigen::should_raise_an_assert && # a); \
+ } \
+ catch (Eigen::eigen_assert_exception&) { VERIFY(true); } \
+ Eigen::report_on_cerr_on_assert_failure = true; \
+ }
+
+ #endif // EIGEN_DEBUG_ASSERTS
+
+ #define EIGEN_USE_CUSTOM_ASSERT
+
+#else // EIGEN_NO_ASSERTION_CHECKING
+
+ #define VERIFY_RAISES_ASSERT(a) {}
+
+#endif // EIGEN_NO_ASSERTION_CHECKING
+
+
+#define EIGEN_INTERNAL_DEBUGGING
+#include <Eigen/QR> // required for createRandomPIMatrixOfRank
+
+static void verify_impl(bool condition, const char *testname, const char *file, int line, const char *condition_as_string)
+{
+ if (!condition)
+ {
+ std::cerr << "Test " << testname << " failed in " << file << " (" << line << ")" \
+ << std::endl << " " << condition_as_string << std::endl << std::endl; \
+ abort();
+ }
+}
+
+#define VERIFY(a) ::verify_impl(a, g_test_stack.back().c_str(), __FILE__, __LINE__, EI_PP_MAKE_STRING(a))
+
+#define VERIFY_IS_EQUAL(a, b) VERIFY(test_is_equal(a, b))
+#define VERIFY_IS_APPROX(a, b) VERIFY(test_isApprox(a, b))
+#define VERIFY_IS_NOT_APPROX(a, b) VERIFY(!test_isApprox(a, b))
+#define VERIFY_IS_MUCH_SMALLER_THAN(a, b) VERIFY(test_isMuchSmallerThan(a, b))
+#define VERIFY_IS_NOT_MUCH_SMALLER_THAN(a, b) VERIFY(!test_isMuchSmallerThan(a, b))
+#define VERIFY_IS_APPROX_OR_LESS_THAN(a, b) VERIFY(test_isApproxOrLessThan(a, b))
+#define VERIFY_IS_NOT_APPROX_OR_LESS_THAN(a, b) VERIFY(!test_isApproxOrLessThan(a, b))
+
+#define VERIFY_IS_UNITARY(a) VERIFY(test_isUnitary(a))
+
+#define CALL_SUBTEST(FUNC) do { \
+ g_test_stack.push_back(EI_PP_MAKE_STRING(FUNC)); \
+ FUNC; \
+ g_test_stack.pop_back(); \
+ } while (0)
+
+
+namespace Eigen {
+
+template<typename T> inline typename NumTraits<T>::Real test_precision() { return NumTraits<T>::dummy_precision(); }
+template<> inline float test_precision<float>() { return 1e-3f; }
+template<> inline double test_precision<double>() { return 1e-6; }
+template<> inline float test_precision<std::complex<float> >() { return test_precision<float>(); }
+template<> inline double test_precision<std::complex<double> >() { return test_precision<double>(); }
+template<> inline long double test_precision<long double>() { return 1e-6; }
+
+inline bool test_isApprox(const int& a, const int& b)
+{ return internal::isApprox(a, b, test_precision<int>()); }
+inline bool test_isMuchSmallerThan(const int& a, const int& b)
+{ return internal::isMuchSmallerThan(a, b, test_precision<int>()); }
+inline bool test_isApproxOrLessThan(const int& a, const int& b)
+{ return internal::isApproxOrLessThan(a, b, test_precision<int>()); }
+
+inline bool test_isApprox(const float& a, const float& b)
+{ return internal::isApprox(a, b, test_precision<float>()); }
+inline bool test_isMuchSmallerThan(const float& a, const float& b)
+{ return internal::isMuchSmallerThan(a, b, test_precision<float>()); }
+inline bool test_isApproxOrLessThan(const float& a, const float& b)
+{ return internal::isApproxOrLessThan(a, b, test_precision<float>()); }
+inline bool test_isApprox(const double& a, const double& b)
+{ return internal::isApprox(a, b, test_precision<double>()); }
+
+inline bool test_isMuchSmallerThan(const double& a, const double& b)
+{ return internal::isMuchSmallerThan(a, b, test_precision<double>()); }
+inline bool test_isApproxOrLessThan(const double& a, const double& b)
+{ return internal::isApproxOrLessThan(a, b, test_precision<double>()); }
+
+inline bool test_isApprox(const std::complex<float>& a, const std::complex<float>& b)
+{ return internal::isApprox(a, b, test_precision<std::complex<float> >()); }
+inline bool test_isMuchSmallerThan(const std::complex<float>& a, const std::complex<float>& b)
+{ return internal::isMuchSmallerThan(a, b, test_precision<std::complex<float> >()); }
+
+inline bool test_isApprox(const std::complex<double>& a, const std::complex<double>& b)
+{ return internal::isApprox(a, b, test_precision<std::complex<double> >()); }
+inline bool test_isMuchSmallerThan(const std::complex<double>& a, const std::complex<double>& b)
+{ return internal::isMuchSmallerThan(a, b, test_precision<std::complex<double> >()); }
+
+inline bool test_isApprox(const long double& a, const long double& b)
+{
+ bool ret = internal::isApprox(a, b, test_precision<long double>());
+ if (!ret) std::cerr
+ << std::endl << " actual = " << a
+ << std::endl << " expected = " << b << std::endl << std::endl;
+ return ret;
+}
+
+inline bool test_isMuchSmallerThan(const long double& a, const long double& b)
+{ return internal::isMuchSmallerThan(a, b, test_precision<long double>()); }
+inline bool test_isApproxOrLessThan(const long double& a, const long double& b)
+{ return internal::isApproxOrLessThan(a, b, test_precision<long double>()); }
+
+template<typename Type1, typename Type2>
+inline bool test_isApprox(const Type1& a, const Type2& b)
+{
+ return a.isApprox(b, test_precision<typename Type1::Scalar>());
+}
+
+// The idea behind this function is to compare the two scalars a and b where
+// the scalar ref is a hint about the expected order of magnitude of a and b.
+// Therefore, if for some reason a and b are very small compared to ref,
+// we won't issue a false negative.
+// This test could be: abs(a-b) <= eps * ref
+// However, it seems that simply comparing a+ref and b+ref is more sensitive to true error.
+template<typename Scalar,typename ScalarRef>
+inline bool test_isApproxWithRef(const Scalar& a, const Scalar& b, const ScalarRef& ref)
+{
+ return test_isApprox(a+ref, b+ref);
+}
+
+template<typename Derived1, typename Derived2>
+inline bool test_isMuchSmallerThan(const MatrixBase<Derived1>& m1,
+ const MatrixBase<Derived2>& m2)
+{
+ return m1.isMuchSmallerThan(m2, test_precision<typename internal::traits<Derived1>::Scalar>());
+}
+
+template<typename Derived>
+inline bool test_isMuchSmallerThan(const MatrixBase<Derived>& m,
+ const typename NumTraits<typename internal::traits<Derived>::Scalar>::Real& s)
+{
+ return m.isMuchSmallerThan(s, test_precision<typename internal::traits<Derived>::Scalar>());
+}
+
+template<typename Derived>
+inline bool test_isUnitary(const MatrixBase<Derived>& m)
+{
+ return m.isUnitary(test_precision<typename internal::traits<Derived>::Scalar>());
+}
+
+template<typename T, typename U>
+bool test_is_equal(const T& actual, const U& expected)
+{
+ if (actual==expected)
+ return true;
+ // false:
+ std::cerr
+ << std::endl << " actual = " << actual
+ << std::endl << " expected = " << expected << std::endl << std::endl;
+ return false;
+}
+
+/** Creates a random Partial Isometry matrix of given rank.
+ *
+ * A partial isometry is a matrix all of whose singular values are either 0 or 1.
+ * This is very useful to test rank-revealing algorithms.
+ */
+template<typename MatrixType>
+void createRandomPIMatrixOfRank(typename MatrixType::Index desired_rank, typename MatrixType::Index rows, typename MatrixType::Index cols, MatrixType& m)
+{
+ typedef typename internal::traits<MatrixType>::Index Index;
+ typedef typename internal::traits<MatrixType>::Scalar Scalar;
+ enum { Rows = MatrixType::RowsAtCompileTime, Cols = MatrixType::ColsAtCompileTime };
+
+ typedef Matrix<Scalar, Dynamic, 1> VectorType;
+ typedef Matrix<Scalar, Rows, Rows> MatrixAType;
+ typedef Matrix<Scalar, Cols, Cols> MatrixBType;
+
+ if(desired_rank == 0)
+ {
+ m.setZero(rows,cols);
+ return;
+ }
+
+ if(desired_rank == 1)
+ {
+ // here we normalize the vectors to get a partial isometry
+ m = VectorType::Random(rows).normalized() * VectorType::Random(cols).normalized().transpose();
+ return;
+ }
+
+ MatrixAType a = MatrixAType::Random(rows,rows);
+ MatrixType d = MatrixType::Identity(rows,cols);
+ MatrixBType b = MatrixBType::Random(cols,cols);
+
+ // set the diagonal such that only desired_rank non-zero entries reamain
+ const Index diag_size = (std::min)(d.rows(),d.cols());
+ if(diag_size != desired_rank)
+ d.diagonal().segment(desired_rank, diag_size-desired_rank) = VectorType::Zero(diag_size-desired_rank);
+
+ HouseholderQR<MatrixAType> qra(a);
+ HouseholderQR<MatrixBType> qrb(b);
+ m = qra.householderQ() * d * qrb.householderQ();
+}
+
+template<typename PermutationVectorType>
+void randomPermutationVector(PermutationVectorType& v, typename PermutationVectorType::Index size)
+{
+ typedef typename PermutationVectorType::Index Index;
+ typedef typename PermutationVectorType::Scalar Scalar;
+ v.resize(size);
+ for(Index i = 0; i < size; ++i) v(i) = Scalar(i);
+ if(size == 1) return;
+ for(Index n = 0; n < 3 * size; ++n)
+ {
+ Index i = internal::random<Index>(0, size-1);
+ Index j;
+ do j = internal::random<Index>(0, size-1); while(j==i);
+ std::swap(v(i), v(j));
+ }
+}
+
+} // end namespace Eigen
+
+template<typename T> struct GetDifferentType;
+
+template<> struct GetDifferentType<float> { typedef double type; };
+template<> struct GetDifferentType<double> { typedef float type; };
+template<typename T> struct GetDifferentType<std::complex<T> >
+{ typedef std::complex<typename GetDifferentType<T>::type> type; };
+
+template<typename T> std::string type_name() { return "other"; }
+template<> std::string type_name<float>() { return "float"; }
+template<> std::string type_name<double>() { return "double"; }
+template<> std::string type_name<int>() { return "int"; }
+template<> std::string type_name<std::complex<float> >() { return "complex<float>"; }
+template<> std::string type_name<std::complex<double> >() { return "complex<double>"; }
+template<> std::string type_name<std::complex<int> >() { return "complex<int>"; }
+
+// forward declaration of the main test function
+void EIGEN_CAT(test_,EIGEN_TEST_FUNC)();
+
+using namespace Eigen;
+
+void set_repeat_from_string(const char *str)
+{
+ errno = 0;
+ g_repeat = int(strtoul(str, 0, 10));
+ if(errno || g_repeat <= 0)
+ {
+ std::cout << "Invalid repeat value " << str << std::endl;
+ exit(EXIT_FAILURE);
+ }
+ g_has_set_repeat = true;
+}
+
+void set_seed_from_string(const char *str)
+{
+ errno = 0;
+ g_seed = strtoul(str, 0, 10);
+ if(errno || g_seed == 0)
+ {
+ std::cout << "Invalid seed value " << str << std::endl;
+ exit(EXIT_FAILURE);
+ }
+ g_has_set_seed = true;
+}
+
+int main(int argc, char *argv[])
+{
+ g_has_set_repeat = false;
+ g_has_set_seed = false;
+ bool need_help = false;
+
+ for(int i = 1; i < argc; i++)
+ {
+ if(argv[i][0] == 'r')
+ {
+ if(g_has_set_repeat)
+ {
+ std::cout << "Argument " << argv[i] << " conflicting with a former argument" << std::endl;
+ return 1;
+ }
+ set_repeat_from_string(argv[i]+1);
+ }
+ else if(argv[i][0] == 's')
+ {
+ if(g_has_set_seed)
+ {
+ std::cout << "Argument " << argv[i] << " conflicting with a former argument" << std::endl;
+ return 1;
+ }
+ set_seed_from_string(argv[i]+1);
+ }
+ else
+ {
+ need_help = true;
+ }
+ }
+
+ if(need_help)
+ {
+ std::cout << "This test application takes the following optional arguments:" << std::endl;
+ std::cout << " rN Repeat each test N times (default: " << DEFAULT_REPEAT << ")" << std::endl;
+ std::cout << " sN Use N as seed for random numbers (default: based on current time)" << std::endl;
+ std::cout << std::endl;
+ std::cout << "If defined, the environment variables EIGEN_REPEAT and EIGEN_SEED" << std::endl;
+ std::cout << "will be used as default values for these parameters." << std::endl;
+ return 1;
+ }
+
+ char *env_EIGEN_REPEAT = getenv("EIGEN_REPEAT");
+ if(!g_has_set_repeat && env_EIGEN_REPEAT)
+ set_repeat_from_string(env_EIGEN_REPEAT);
+ char *env_EIGEN_SEED = getenv("EIGEN_SEED");
+ if(!g_has_set_seed && env_EIGEN_SEED)
+ set_seed_from_string(env_EIGEN_SEED);
+
+ if(!g_has_set_seed) g_seed = (unsigned int) time(NULL);
+ if(!g_has_set_repeat) g_repeat = DEFAULT_REPEAT;
+
+ std::cout << "Initializing random number generator with seed " << g_seed << std::endl;
+ srand(g_seed);
+ std::cout << "Repeating each test " << g_repeat << " times" << std::endl;
+
+ Eigen::g_test_stack.push_back(EI_PP_MAKE_STRING(EIGEN_TEST_FUNC));
+
+ EIGEN_CAT(test_,EIGEN_TEST_FUNC)();
+ return 0;
+}
diff --git a/test/map.cpp b/test/map.cpp
new file mode 100644
index 000000000..fe983e802
--- /dev/null
+++ b/test/map.cpp
@@ -0,0 +1,144 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra.
+//
+// Copyright (C) 2006-2010 Benoit Jacob <jacob.benoit.1@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 EIGEN_NO_STATIC_ASSERT
+#define EIGEN_NO_STATIC_ASSERT // turn static asserts into runtime asserts in order to check them
+#endif
+
+#include "main.h"
+
+template<typename VectorType> void map_class_vector(const VectorType& m)
+{
+ typedef typename VectorType::Index Index;
+ typedef typename VectorType::Scalar Scalar;
+
+ Index size = m.size();
+
+ // test Map.h
+ Scalar* array1 = internal::aligned_new<Scalar>(size);
+ Scalar* array2 = internal::aligned_new<Scalar>(size);
+ Scalar* array3 = new Scalar[size+1];
+ Scalar* array3unaligned = size_t(array3)%16 == 0 ? array3+1 : array3;
+
+ Map<VectorType, Aligned>(array1, size) = VectorType::Random(size);
+ Map<VectorType, Aligned>(array2, size) = Map<VectorType,Aligned>(array1, size);
+ Map<VectorType>(array3unaligned, size) = Map<VectorType>(array1, size);
+ VectorType ma1 = Map<VectorType, Aligned>(array1, size);
+ VectorType ma2 = Map<VectorType, Aligned>(array2, size);
+ VectorType ma3 = Map<VectorType>(array3unaligned, size);
+ VERIFY_IS_EQUAL(ma1, ma2);
+ VERIFY_IS_EQUAL(ma1, ma3);
+ #ifdef EIGEN_VECTORIZE
+ if(internal::packet_traits<Scalar>::Vectorizable)
+ VERIFY_RAISES_ASSERT((Map<VectorType,Aligned>(array3unaligned, size)))
+ #endif
+
+ internal::aligned_delete(array1, size);
+ internal::aligned_delete(array2, size);
+ delete[] array3;
+}
+
+template<typename MatrixType> void map_class_matrix(const MatrixType& m)
+{
+ typedef typename MatrixType::Index Index;
+ typedef typename MatrixType::Scalar Scalar;
+
+ Index rows = m.rows(), cols = m.cols(), size = rows*cols;
+
+ // test Map.h
+ Scalar* array1 = internal::aligned_new<Scalar>(size);
+ for(int i = 0; i < size; i++) array1[i] = Scalar(1);
+ Scalar* array2 = internal::aligned_new<Scalar>(size);
+ for(int i = 0; i < size; i++) array2[i] = Scalar(1);
+ Scalar* array3 = new Scalar[size+1];
+ for(int i = 0; i < size+1; i++) array3[i] = Scalar(1);
+ Scalar* array3unaligned = size_t(array3)%16 == 0 ? array3+1 : array3;
+ Map<MatrixType, Aligned>(array1, rows, cols) = MatrixType::Ones(rows,cols);
+ Map<MatrixType>(array2, rows, cols) = Map<MatrixType>(array1, rows, cols);
+ Map<MatrixType>(array3unaligned, rows, cols) = Map<MatrixType>(array1, rows, cols);
+ MatrixType ma1 = Map<MatrixType>(array1, rows, cols);
+ MatrixType ma2 = Map<MatrixType, Aligned>(array2, rows, cols);
+ VERIFY_IS_EQUAL(ma1, ma2);
+ MatrixType ma3 = Map<MatrixType>(array3unaligned, rows, cols);
+ VERIFY_IS_EQUAL(ma1, ma3);
+
+ internal::aligned_delete(array1, size);
+ internal::aligned_delete(array2, size);
+ delete[] array3;
+}
+
+template<typename VectorType> void map_static_methods(const VectorType& m)
+{
+ typedef typename VectorType::Index Index;
+ typedef typename VectorType::Scalar Scalar;
+
+ Index size = m.size();
+
+ // test Map.h
+ Scalar* array1 = internal::aligned_new<Scalar>(size);
+ Scalar* array2 = internal::aligned_new<Scalar>(size);
+ Scalar* array3 = new Scalar[size+1];
+ Scalar* array3unaligned = size_t(array3)%16 == 0 ? array3+1 : array3;
+
+ VectorType::MapAligned(array1, size) = VectorType::Random(size);
+ VectorType::Map(array2, size) = VectorType::Map(array1, size);
+ VectorType::Map(array3unaligned, size) = VectorType::Map(array1, size);
+ VectorType ma1 = VectorType::Map(array1, size);
+ VectorType ma2 = VectorType::MapAligned(array2, size);
+ VectorType ma3 = VectorType::Map(array3unaligned, size);
+ VERIFY_IS_EQUAL(ma1, ma2);
+ VERIFY_IS_EQUAL(ma1, ma3);
+
+ internal::aligned_delete(array1, size);
+ internal::aligned_delete(array2, size);
+ delete[] array3;
+}
+
+template<typename PlainObjectType> void check_const_correctness(const PlainObjectType&)
+{
+ typedef typename PlainObjectType::Index Index;
+ typedef typename PlainObjectType::Scalar Scalar;
+
+ // there's a lot that we can't test here while still having this test compile!
+ // the only possible approach would be to run a script trying to compile stuff and checking that it fails.
+ // CMake can help with that.
+
+ // verify that map-to-const don't have LvalueBit
+ typedef typename internal::add_const<PlainObjectType>::type ConstPlainObjectType;
+ VERIFY( !(internal::traits<Map<ConstPlainObjectType> >::Flags & LvalueBit) );
+ VERIFY( !(internal::traits<Map<ConstPlainObjectType, Aligned> >::Flags & LvalueBit) );
+ VERIFY( !(Map<ConstPlainObjectType>::Flags & LvalueBit) );
+ VERIFY( !(Map<ConstPlainObjectType, Aligned>::Flags & LvalueBit) );
+}
+
+void test_map()
+{
+ for(int i = 0; i < g_repeat; i++) {
+ CALL_SUBTEST_1( map_class_vector(Matrix<float, 1, 1>()) );
+ CALL_SUBTEST_1( check_const_correctness(Matrix<float, 1, 1>()) );
+ CALL_SUBTEST_2( map_class_vector(Vector4d()) );
+ CALL_SUBTEST_2( check_const_correctness(Matrix4d()) );
+ CALL_SUBTEST_3( map_class_vector(RowVector4f()) );
+ CALL_SUBTEST_4( map_class_vector(VectorXcf(8)) );
+ CALL_SUBTEST_5( map_class_vector(VectorXi(12)) );
+ CALL_SUBTEST_5( check_const_correctness(VectorXi(12)) );
+
+ CALL_SUBTEST_1( map_class_matrix(Matrix<float, 1, 1>()) );
+ CALL_SUBTEST_2( map_class_matrix(Matrix4d()) );
+ CALL_SUBTEST_11( map_class_matrix(Matrix<float,3,5>()) );
+ CALL_SUBTEST_4( map_class_matrix(MatrixXcf(internal::random<int>(1,10),internal::random<int>(1,10))) );
+ CALL_SUBTEST_5( map_class_matrix(MatrixXi(internal::random<int>(1,10),internal::random<int>(1,10))) );
+
+ CALL_SUBTEST_6( map_static_methods(Matrix<double, 1, 1>()) );
+ CALL_SUBTEST_7( map_static_methods(Vector3f()) );
+ CALL_SUBTEST_8( map_static_methods(RowVector3d()) );
+ CALL_SUBTEST_9( map_static_methods(VectorXcd(8)) );
+ CALL_SUBTEST_10( map_static_methods(VectorXf(12)) );
+ }
+}
diff --git a/test/mapstaticmethods.cpp b/test/mapstaticmethods.cpp
new file mode 100644
index 000000000..5b512bde4
--- /dev/null
+++ b/test/mapstaticmethods.cpp
@@ -0,0 +1,173 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra.
+//
+// Copyright (C) 2011 Benoit Jacob <jacob.benoit.1@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 "main.h"
+
+float *ptr;
+const float *const_ptr;
+
+template<typename PlainObjectType,
+ bool IsDynamicSize = PlainObjectType::SizeAtCompileTime == Dynamic,
+ bool IsVector = PlainObjectType::IsVectorAtCompileTime
+>
+struct mapstaticmethods_impl {};
+
+template<typename PlainObjectType, bool IsVector>
+struct mapstaticmethods_impl<PlainObjectType, false, IsVector>
+{
+ static void run(const PlainObjectType& m)
+ {
+ mapstaticmethods_impl<PlainObjectType, true, IsVector>::run(m);
+
+ int i = internal::random<int>(2,5), j = internal::random<int>(2,5);
+
+ PlainObjectType::Map(ptr).setZero();
+ PlainObjectType::MapAligned(ptr).setZero();
+ PlainObjectType::Map(const_ptr).sum();
+ PlainObjectType::MapAligned(const_ptr).sum();
+
+ PlainObjectType::Map(ptr, InnerStride<>(i)).setZero();
+ PlainObjectType::MapAligned(ptr, InnerStride<>(i)).setZero();
+ PlainObjectType::Map(const_ptr, InnerStride<>(i)).sum();
+ PlainObjectType::MapAligned(const_ptr, InnerStride<>(i)).sum();
+
+ PlainObjectType::Map(ptr, InnerStride<2>()).setZero();
+ PlainObjectType::MapAligned(ptr, InnerStride<3>()).setZero();
+ PlainObjectType::Map(const_ptr, InnerStride<4>()).sum();
+ PlainObjectType::MapAligned(const_ptr, InnerStride<5>()).sum();
+
+ PlainObjectType::Map(ptr, OuterStride<>(i)).setZero();
+ PlainObjectType::MapAligned(ptr, OuterStride<>(i)).setZero();
+ PlainObjectType::Map(const_ptr, OuterStride<>(i)).sum();
+ PlainObjectType::MapAligned(const_ptr, OuterStride<>(i)).sum();
+
+ PlainObjectType::Map(ptr, OuterStride<2>()).setZero();
+ PlainObjectType::MapAligned(ptr, OuterStride<3>()).setZero();
+ PlainObjectType::Map(const_ptr, OuterStride<4>()).sum();
+ PlainObjectType::MapAligned(const_ptr, OuterStride<5>()).sum();
+
+ PlainObjectType::Map(ptr, Stride<Dynamic, Dynamic>(i,j)).setZero();
+ PlainObjectType::MapAligned(ptr, Stride<2,Dynamic>(2,i)).setZero();
+ PlainObjectType::Map(const_ptr, Stride<Dynamic,3>(i,3)).sum();
+ PlainObjectType::MapAligned(const_ptr, Stride<Dynamic, Dynamic>(i,j)).sum();
+
+ PlainObjectType::Map(ptr, Stride<2,3>()).setZero();
+ PlainObjectType::MapAligned(ptr, Stride<3,4>()).setZero();
+ PlainObjectType::Map(const_ptr, Stride<2,4>()).sum();
+ PlainObjectType::MapAligned(const_ptr, Stride<5,3>()).sum();
+ }
+};
+
+template<typename PlainObjectType>
+struct mapstaticmethods_impl<PlainObjectType, true, false>
+{
+ static void run(const PlainObjectType& m)
+ {
+ int rows = m.rows(), cols = m.cols();
+
+ int i = internal::random<int>(2,5), j = internal::random<int>(2,5);
+
+ PlainObjectType::Map(ptr, rows, cols).setZero();
+ PlainObjectType::MapAligned(ptr, rows, cols).setZero();
+ PlainObjectType::Map(const_ptr, rows, cols).sum();
+ PlainObjectType::MapAligned(const_ptr, rows, cols).sum();
+
+ PlainObjectType::Map(ptr, rows, cols, InnerStride<>(i)).setZero();
+ PlainObjectType::MapAligned(ptr, rows, cols, InnerStride<>(i)).setZero();
+ PlainObjectType::Map(const_ptr, rows, cols, InnerStride<>(i)).sum();
+ PlainObjectType::MapAligned(const_ptr, rows, cols, InnerStride<>(i)).sum();
+
+ PlainObjectType::Map(ptr, rows, cols, InnerStride<2>()).setZero();
+ PlainObjectType::MapAligned(ptr, rows, cols, InnerStride<3>()).setZero();
+ PlainObjectType::Map(const_ptr, rows, cols, InnerStride<4>()).sum();
+ PlainObjectType::MapAligned(const_ptr, rows, cols, InnerStride<5>()).sum();
+
+ PlainObjectType::Map(ptr, rows, cols, OuterStride<>(i)).setZero();
+ PlainObjectType::MapAligned(ptr, rows, cols, OuterStride<>(i)).setZero();
+ PlainObjectType::Map(const_ptr, rows, cols, OuterStride<>(i)).sum();
+ PlainObjectType::MapAligned(const_ptr, rows, cols, OuterStride<>(i)).sum();
+
+ PlainObjectType::Map(ptr, rows, cols, OuterStride<2>()).setZero();
+ PlainObjectType::MapAligned(ptr, rows, cols, OuterStride<3>()).setZero();
+ PlainObjectType::Map(const_ptr, rows, cols, OuterStride<4>()).sum();
+ PlainObjectType::MapAligned(const_ptr, rows, cols, OuterStride<5>()).sum();
+
+ PlainObjectType::Map(ptr, rows, cols, Stride<Dynamic, Dynamic>(i,j)).setZero();
+ PlainObjectType::MapAligned(ptr, rows, cols, Stride<2,Dynamic>(2,i)).setZero();
+ PlainObjectType::Map(const_ptr, rows, cols, Stride<Dynamic,3>(i,3)).sum();
+ PlainObjectType::MapAligned(const_ptr, rows, cols, Stride<Dynamic, Dynamic>(i,j)).sum();
+
+ PlainObjectType::Map(ptr, rows, cols, Stride<2,3>()).setZero();
+ PlainObjectType::MapAligned(ptr, rows, cols, Stride<3,4>()).setZero();
+ PlainObjectType::Map(const_ptr, rows, cols, Stride<2,4>()).sum();
+ PlainObjectType::MapAligned(const_ptr, rows, cols, Stride<5,3>()).sum();
+ }
+};
+
+template<typename PlainObjectType>
+struct mapstaticmethods_impl<PlainObjectType, true, true>
+{
+ static void run(const PlainObjectType& v)
+ {
+ int size = v.size();
+
+ int i = internal::random<int>(2,5);
+
+ PlainObjectType::Map(ptr, size).setZero();
+ PlainObjectType::MapAligned(ptr, size).setZero();
+ PlainObjectType::Map(const_ptr, size).sum();
+ PlainObjectType::MapAligned(const_ptr, size).sum();
+
+ PlainObjectType::Map(ptr, size, InnerStride<>(i)).setZero();
+ PlainObjectType::MapAligned(ptr, size, InnerStride<>(i)).setZero();
+ PlainObjectType::Map(const_ptr, size, InnerStride<>(i)).sum();
+ PlainObjectType::MapAligned(const_ptr, size, InnerStride<>(i)).sum();
+
+ PlainObjectType::Map(ptr, size, InnerStride<2>()).setZero();
+ PlainObjectType::MapAligned(ptr, size, InnerStride<3>()).setZero();
+ PlainObjectType::Map(const_ptr, size, InnerStride<4>()).sum();
+ PlainObjectType::MapAligned(const_ptr, size, InnerStride<5>()).sum();
+ }
+};
+
+template<typename PlainObjectType>
+void mapstaticmethods(const PlainObjectType& m)
+{
+ mapstaticmethods_impl<PlainObjectType>::run(m);
+ VERIFY(true); // just to avoid 'unused function' warning
+}
+
+void test_mapstaticmethods()
+{
+ ptr = internal::aligned_new<float>(1000);
+ for(int i = 0; i < 1000; i++) ptr[i] = float(i);
+
+ const_ptr = ptr;
+
+ CALL_SUBTEST_1(( mapstaticmethods(Matrix<float, 1, 1>()) ));
+ CALL_SUBTEST_1(( mapstaticmethods(Vector2f()) ));
+ CALL_SUBTEST_2(( mapstaticmethods(Vector3f()) ));
+ CALL_SUBTEST_2(( mapstaticmethods(Matrix2f()) ));
+ CALL_SUBTEST_3(( mapstaticmethods(Matrix4f()) ));
+ CALL_SUBTEST_3(( mapstaticmethods(Array4f()) ));
+ CALL_SUBTEST_4(( mapstaticmethods(Array3f()) ));
+ CALL_SUBTEST_4(( mapstaticmethods(Array33f()) ));
+ CALL_SUBTEST_5(( mapstaticmethods(Array44f()) ));
+ CALL_SUBTEST_5(( mapstaticmethods(VectorXf(1)) ));
+ CALL_SUBTEST_5(( mapstaticmethods(VectorXf(8)) ));
+ CALL_SUBTEST_6(( mapstaticmethods(MatrixXf(1,1)) ));
+ CALL_SUBTEST_6(( mapstaticmethods(MatrixXf(5,7)) ));
+ CALL_SUBTEST_7(( mapstaticmethods(ArrayXf(1)) ));
+ CALL_SUBTEST_7(( mapstaticmethods(ArrayXf(5)) ));
+ CALL_SUBTEST_8(( mapstaticmethods(ArrayXXf(1,1)) ));
+ CALL_SUBTEST_8(( mapstaticmethods(ArrayXXf(8,6)) ));
+
+ internal::aligned_delete(ptr, 1000);
+}
+
diff --git a/test/mapstride.cpp b/test/mapstride.cpp
new file mode 100644
index 000000000..fe35b9d23
--- /dev/null
+++ b/test/mapstride.cpp
@@ -0,0 +1,146 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra.
+//
+// Copyright (C) 2010 Benoit Jacob <jacob.benoit.1@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 "main.h"
+
+template<int Alignment,typename VectorType> void map_class_vector(const VectorType& m)
+{
+ typedef typename VectorType::Index Index;
+ typedef typename VectorType::Scalar Scalar;
+
+ Index size = m.size();
+
+ VectorType v = VectorType::Random(size);
+
+ Index arraysize = 3*size;
+
+ Scalar* a_array = internal::aligned_new<Scalar>(arraysize+1);
+ Scalar* array = a_array;
+ if(Alignment!=Aligned)
+ array = (Scalar*)(ptrdiff_t(a_array) + (internal::packet_traits<Scalar>::AlignedOnScalar?sizeof(Scalar):sizeof(typename NumTraits<Scalar>::Real)));
+
+ {
+ Map<VectorType, Alignment, InnerStride<3> > map(array, size);
+ map = v;
+ for(int i = 0; i < size; ++i)
+ {
+ VERIFY(array[3*i] == v[i]);
+ VERIFY(map[i] == v[i]);
+ }
+ }
+
+ {
+ Map<VectorType, Unaligned, InnerStride<Dynamic> > map(array, size, InnerStride<Dynamic>(2));
+ map = v;
+ for(int i = 0; i < size; ++i)
+ {
+ VERIFY(array[2*i] == v[i]);
+ VERIFY(map[i] == v[i]);
+ }
+ }
+
+ internal::aligned_delete(a_array, arraysize+1);
+}
+
+template<int Alignment,typename MatrixType> void map_class_matrix(const MatrixType& _m)
+{
+ typedef typename MatrixType::Index Index;
+ typedef typename MatrixType::Scalar Scalar;
+
+ Index rows = _m.rows(), cols = _m.cols();
+
+ MatrixType m = MatrixType::Random(rows,cols);
+
+ Index arraysize = 2*(rows+4)*(cols+4);
+
+ Scalar* a_array = internal::aligned_new<Scalar>(arraysize+1);
+ Scalar* array = a_array;
+ if(Alignment!=Aligned)
+ array = (Scalar*)(ptrdiff_t(a_array) + (internal::packet_traits<Scalar>::AlignedOnScalar?sizeof(Scalar):sizeof(typename NumTraits<Scalar>::Real)));
+
+ // test no inner stride and some dynamic outer stride
+ {
+ Map<MatrixType, Alignment, OuterStride<Dynamic> > map(array, rows, cols, OuterStride<Dynamic>(m.innerSize()+1));
+ map = m;
+ VERIFY(map.outerStride() == map.innerSize()+1);
+ for(int i = 0; i < m.outerSize(); ++i)
+ for(int j = 0; j < m.innerSize(); ++j)
+ {
+ VERIFY(array[map.outerStride()*i+j] == m.coeffByOuterInner(i,j));
+ VERIFY(map.coeffByOuterInner(i,j) == m.coeffByOuterInner(i,j));
+ }
+ }
+
+ // test no inner stride and an outer stride of +4. This is quite important as for fixed-size matrices,
+ // this allows to hit the special case where it's vectorizable.
+ {
+ enum {
+ InnerSize = MatrixType::InnerSizeAtCompileTime,
+ OuterStrideAtCompileTime = InnerSize==Dynamic ? Dynamic : InnerSize+4
+ };
+ Map<MatrixType, Alignment, OuterStride<OuterStrideAtCompileTime> >
+ map(array, rows, cols, OuterStride<OuterStrideAtCompileTime>(m.innerSize()+4));
+ map = m;
+ VERIFY(map.outerStride() == map.innerSize()+4);
+ for(int i = 0; i < m.outerSize(); ++i)
+ for(int j = 0; j < m.innerSize(); ++j)
+ {
+ VERIFY(array[map.outerStride()*i+j] == m.coeffByOuterInner(i,j));
+ VERIFY(map.coeffByOuterInner(i,j) == m.coeffByOuterInner(i,j));
+ }
+ }
+
+ // test both inner stride and outer stride
+ {
+ Map<MatrixType, Alignment, Stride<Dynamic,Dynamic> > map(array, rows, cols, Stride<Dynamic,Dynamic>(2*m.innerSize()+1, 2));
+ map = m;
+ VERIFY(map.outerStride() == 2*map.innerSize()+1);
+ VERIFY(map.innerStride() == 2);
+ for(int i = 0; i < m.outerSize(); ++i)
+ for(int j = 0; j < m.innerSize(); ++j)
+ {
+ VERIFY(array[map.outerStride()*i+map.innerStride()*j] == m.coeffByOuterInner(i,j));
+ VERIFY(map.coeffByOuterInner(i,j) == m.coeffByOuterInner(i,j));
+ }
+ }
+
+ internal::aligned_delete(a_array, arraysize+1);
+}
+
+void test_mapstride()
+{
+ for(int i = 0; i < g_repeat; i++) {
+ EIGEN_UNUSED int maxn = 30;
+ CALL_SUBTEST_1( map_class_vector<Aligned>(Matrix<float, 1, 1>()) );
+ CALL_SUBTEST_1( map_class_vector<Unaligned>(Matrix<float, 1, 1>()) );
+ CALL_SUBTEST_2( map_class_vector<Aligned>(Vector4d()) );
+ CALL_SUBTEST_2( map_class_vector<Unaligned>(Vector4d()) );
+ CALL_SUBTEST_3( map_class_vector<Aligned>(RowVector4f()) );
+ CALL_SUBTEST_3( map_class_vector<Unaligned>(RowVector4f()) );
+ CALL_SUBTEST_4( map_class_vector<Aligned>(VectorXcf(internal::random<int>(1,maxn))) );
+ CALL_SUBTEST_4( map_class_vector<Unaligned>(VectorXcf(internal::random<int>(1,maxn))) );
+ CALL_SUBTEST_5( map_class_vector<Aligned>(VectorXi(internal::random<int>(1,maxn))) );
+ CALL_SUBTEST_5( map_class_vector<Unaligned>(VectorXi(internal::random<int>(1,maxn))) );
+
+ CALL_SUBTEST_1( map_class_matrix<Aligned>(Matrix<float, 1, 1>()) );
+ CALL_SUBTEST_1( map_class_matrix<Unaligned>(Matrix<float, 1, 1>()) );
+ CALL_SUBTEST_2( map_class_matrix<Aligned>(Matrix4d()) );
+ CALL_SUBTEST_2( map_class_matrix<Unaligned>(Matrix4d()) );
+ CALL_SUBTEST_3( map_class_matrix<Aligned>(Matrix<float,3,5>()) );
+ CALL_SUBTEST_3( map_class_matrix<Unaligned>(Matrix<float,3,5>()) );
+ CALL_SUBTEST_3( map_class_matrix<Aligned>(Matrix<float,4,8>()) );
+ CALL_SUBTEST_3( map_class_matrix<Unaligned>(Matrix<float,4,8>()) );
+ CALL_SUBTEST_4( map_class_matrix<Aligned>(MatrixXcf(internal::random<int>(1,maxn),internal::random<int>(1,maxn))) );
+ CALL_SUBTEST_4( map_class_matrix<Unaligned>(MatrixXcf(internal::random<int>(1,maxn),internal::random<int>(1,maxn))) );
+ CALL_SUBTEST_5( map_class_matrix<Aligned>(MatrixXi(internal::random<int>(1,maxn),internal::random<int>(1,maxn))) );
+ CALL_SUBTEST_5( map_class_matrix<Unaligned>(MatrixXi(internal::random<int>(1,maxn),internal::random<int>(1,maxn))) );
+ CALL_SUBTEST_6( map_class_matrix<Aligned>(MatrixXcd(internal::random<int>(1,maxn),internal::random<int>(1,maxn))) );
+ CALL_SUBTEST_6( map_class_matrix<Unaligned>(MatrixXcd(internal::random<int>(1,maxn),internal::random<int>(1,maxn))) );
+ }
+}
diff --git a/test/meta.cpp b/test/meta.cpp
new file mode 100644
index 000000000..dc1d128d5
--- /dev/null
+++ b/test/meta.cpp
@@ -0,0 +1,76 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra.
+//
+// Copyright (C) 2008 Gael Guennebaud <gael.guennebaud@inria.fr>
+//
+// This Source Code Form is subject to the terms of the Mozilla
+// Public License v. 2.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 "main.h"
+
+void test_meta()
+{
+ typedef float & FloatRef;
+ typedef const float & ConstFloatRef;
+
+ VERIFY((internal::conditional<(3<4),internal::true_type, internal::false_type>::type::value));
+ VERIFY(( internal::is_same<float,float>::value));
+ VERIFY((!internal::is_same<float,double>::value));
+ VERIFY((!internal::is_same<float,float&>::value));
+ VERIFY((!internal::is_same<float,const float&>::value));
+
+ VERIFY(( internal::is_same<float,internal::remove_all<const float&>::type >::value));
+ VERIFY(( internal::is_same<float,internal::remove_all<const float*>::type >::value));
+ VERIFY(( internal::is_same<float,internal::remove_all<const float*&>::type >::value));
+ VERIFY(( internal::is_same<float,internal::remove_all<float**>::type >::value));
+ VERIFY(( internal::is_same<float,internal::remove_all<float**&>::type >::value));
+ VERIFY(( internal::is_same<float,internal::remove_all<float* const *&>::type >::value));
+ VERIFY(( internal::is_same<float,internal::remove_all<float* const>::type >::value));
+
+ // test add_const
+ VERIFY(( internal::is_same< internal::add_const<float>::type, const float >::value));
+ VERIFY(( internal::is_same< internal::add_const<float*>::type, float* const>::value));
+ VERIFY(( internal::is_same< internal::add_const<float const*>::type, float const* const>::value));
+ VERIFY(( internal::is_same< internal::add_const<float&>::type, float& >::value));
+
+ // test remove_const
+ VERIFY(( internal::is_same< internal::remove_const<float const* const>::type, float const* >::value));
+ VERIFY(( internal::is_same< internal::remove_const<float const*>::type, float const* >::value));
+ VERIFY(( internal::is_same< internal::remove_const<float* const>::type, float* >::value));
+
+ // test add_const_on_value_type
+ VERIFY(( internal::is_same< internal::add_const_on_value_type<float&>::type, float const& >::value));
+ VERIFY(( internal::is_same< internal::add_const_on_value_type<float*>::type, float const* >::value));
+
+ VERIFY(( internal::is_same< internal::add_const_on_value_type<float>::type, const float >::value));
+ VERIFY(( internal::is_same< internal::add_const_on_value_type<const float>::type, const float >::value));
+
+ VERIFY(( internal::is_same< internal::add_const_on_value_type<const float* const>::type, const float* const>::value));
+ VERIFY(( internal::is_same< internal::add_const_on_value_type<float* const>::type, const float* const>::value));
+
+ VERIFY(( internal::is_same<float,internal::remove_reference<float&>::type >::value));
+ VERIFY(( internal::is_same<const float,internal::remove_reference<const float&>::type >::value));
+ VERIFY(( internal::is_same<float,internal::remove_pointer<float*>::type >::value));
+ VERIFY(( internal::is_same<const float,internal::remove_pointer<const float*>::type >::value));
+ VERIFY(( internal::is_same<float,internal::remove_pointer<float* const >::type >::value));
+
+ VERIFY(internal::meta_sqrt<1>::ret == 1);
+ #define VERIFY_META_SQRT(X) VERIFY(internal::meta_sqrt<X>::ret == int(internal::sqrt(double(X))))
+ VERIFY_META_SQRT(2);
+ VERIFY_META_SQRT(3);
+ VERIFY_META_SQRT(4);
+ VERIFY_META_SQRT(5);
+ VERIFY_META_SQRT(6);
+ VERIFY_META_SQRT(8);
+ VERIFY_META_SQRT(9);
+ VERIFY_META_SQRT(15);
+ VERIFY_META_SQRT(16);
+ VERIFY_META_SQRT(17);
+ VERIFY_META_SQRT(255);
+ VERIFY_META_SQRT(256);
+ VERIFY_META_SQRT(257);
+ VERIFY_META_SQRT(1023);
+ VERIFY_META_SQRT(1024);
+ VERIFY_META_SQRT(1025);
+}
diff --git a/test/miscmatrices.cpp b/test/miscmatrices.cpp
new file mode 100644
index 000000000..af0481cfe
--- /dev/null
+++ b/test/miscmatrices.cpp
@@ -0,0 +1,48 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra.
+//
+// Copyright (C) 2006-2008 Benoit Jacob <jacob.benoit.1@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 "main.h"
+
+template<typename MatrixType> void miscMatrices(const MatrixType& m)
+{
+ /* this test covers the following files:
+ DiagonalMatrix.h Ones.h
+ */
+ typedef typename MatrixType::Index Index;
+ typedef typename MatrixType::Scalar Scalar;
+ typedef Matrix<Scalar, MatrixType::RowsAtCompileTime, 1> VectorType;
+ typedef Matrix<Scalar, 1, MatrixType::ColsAtCompileTime> RowVectorType;
+ Index rows = m.rows();
+ Index cols = m.cols();
+
+ Index r = internal::random<Index>(0, rows-1), r2 = internal::random<Index>(0, rows-1), c = internal::random<Index>(0, cols-1);
+ VERIFY_IS_APPROX(MatrixType::Ones(rows,cols)(r,c), static_cast<Scalar>(1));
+ MatrixType m1 = MatrixType::Ones(rows,cols);
+ VERIFY_IS_APPROX(m1(r,c), static_cast<Scalar>(1));
+ VectorType v1 = VectorType::Random(rows);
+ v1[0];
+ Matrix<Scalar, MatrixType::RowsAtCompileTime, MatrixType::RowsAtCompileTime>
+ square(v1.asDiagonal());
+ if(r==r2) VERIFY_IS_APPROX(square(r,r2), v1[r]);
+ else VERIFY_IS_MUCH_SMALLER_THAN(square(r,r2), static_cast<Scalar>(1));
+ square = MatrixType::Zero(rows, rows);
+ square.diagonal() = VectorType::Ones(rows);
+ VERIFY_IS_APPROX(square, MatrixType::Identity(rows, rows));
+}
+
+void test_miscmatrices()
+{
+ for(int i = 0; i < g_repeat; i++) {
+ CALL_SUBTEST_1( miscMatrices(Matrix<float, 1, 1>()) );
+ CALL_SUBTEST_2( miscMatrices(Matrix4d()) );
+ CALL_SUBTEST_3( miscMatrices(MatrixXcf(3, 3)) );
+ CALL_SUBTEST_4( miscMatrices(MatrixXi(8, 12)) );
+ CALL_SUBTEST_5( miscMatrices(MatrixXcd(20, 20)) );
+ }
+}
diff --git a/test/mixingtypes.cpp b/test/mixingtypes.cpp
new file mode 100644
index 000000000..6c2f74875
--- /dev/null
+++ b/test/mixingtypes.cpp
@@ -0,0 +1,132 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra.
+//
+// Copyright (C) 2008 Gael Guennebaud <gael.guennebaud@inria.fr>
+// Copyright (C) 2008 Benoit Jacob <jacob.benoit.1@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/.
+
+// work around "uninitialized" warnings and give that option some testing
+#define EIGEN_INITIALIZE_MATRICES_BY_ZERO
+
+#ifndef EIGEN_NO_STATIC_ASSERT
+#define EIGEN_NO_STATIC_ASSERT // turn static asserts into runtime asserts in order to check them
+#endif
+
+// #ifndef EIGEN_DONT_VECTORIZE
+// #define EIGEN_DONT_VECTORIZE // SSE intrinsics aren't designed to allow mixing types
+// #endif
+
+#include "main.h"
+
+using namespace std;
+
+template<int SizeAtCompileType> void mixingtypes(int size = SizeAtCompileType)
+{
+ typedef std::complex<float> CF;
+ typedef std::complex<double> CD;
+ typedef Matrix<float, SizeAtCompileType, SizeAtCompileType> Mat_f;
+ typedef Matrix<double, SizeAtCompileType, SizeAtCompileType> Mat_d;
+ typedef Matrix<std::complex<float>, SizeAtCompileType, SizeAtCompileType> Mat_cf;
+ typedef Matrix<std::complex<double>, SizeAtCompileType, SizeAtCompileType> Mat_cd;
+ typedef Matrix<float, SizeAtCompileType, 1> Vec_f;
+ typedef Matrix<double, SizeAtCompileType, 1> Vec_d;
+ typedef Matrix<std::complex<float>, SizeAtCompileType, 1> Vec_cf;
+ typedef Matrix<std::complex<double>, SizeAtCompileType, 1> Vec_cd;
+
+ Mat_f mf = Mat_f::Random(size,size);
+ Mat_d md = mf.template cast<double>();
+ Mat_cf mcf = Mat_cf::Random(size,size);
+ Mat_cd mcd = mcf.template cast<complex<double> >();
+ Vec_f vf = Vec_f::Random(size,1);
+ Vec_d vd = vf.template cast<double>();
+ Vec_cf vcf = Vec_cf::Random(size,1);
+ Vec_cd vcd = vcf.template cast<complex<double> >();
+ float sf = internal::random<float>();
+ double sd = internal::random<double>();
+ complex<float> scf = internal::random<complex<float> >();
+ complex<double> scd = internal::random<complex<double> >();
+
+
+ mf+mf;
+ VERIFY_RAISES_ASSERT(mf+md);
+ VERIFY_RAISES_ASSERT(mf+mcf);
+ VERIFY_RAISES_ASSERT(vf=vd);
+ VERIFY_RAISES_ASSERT(vf+=vd);
+ VERIFY_RAISES_ASSERT(mcd=md);
+
+ // check scalar products
+ VERIFY_IS_APPROX(vcf * sf , vcf * complex<float>(sf));
+ VERIFY_IS_APPROX(sd * vcd, complex<double>(sd) * vcd);
+ VERIFY_IS_APPROX(vf * scf , vf.template cast<complex<float> >() * scf);
+ VERIFY_IS_APPROX(scd * vd, scd * vd.template cast<complex<double> >());
+
+ // check dot product
+ vf.dot(vf);
+#if 0 // we get other compilation errors here than just static asserts
+ VERIFY_RAISES_ASSERT(vd.dot(vf));
+#endif
+ VERIFY_IS_APPROX(vcf.dot(vf), vcf.dot(vf.template cast<complex<float> >()));
+
+ // check diagonal product
+ VERIFY_IS_APPROX(vf.asDiagonal() * mcf, vf.template cast<complex<float> >().asDiagonal() * mcf);
+ VERIFY_IS_APPROX(vcd.asDiagonal() * md, vcd.asDiagonal() * md.template cast<complex<double> >());
+ VERIFY_IS_APPROX(mcf * vf.asDiagonal(), mcf * vf.template cast<complex<float> >().asDiagonal());
+ VERIFY_IS_APPROX(md * vcd.asDiagonal(), md.template cast<complex<double> >() * vcd.asDiagonal());
+// vd.asDiagonal() * mf; // does not even compile
+// vcd.asDiagonal() * mf; // does not even compile
+
+ // check inner product
+ VERIFY_IS_APPROX((vf.transpose() * vcf).value(), (vf.template cast<complex<float> >().transpose() * vcf).value());
+
+ // check outer product
+ VERIFY_IS_APPROX((vf * vcf.transpose()).eval(), (vf.template cast<complex<float> >() * vcf.transpose()).eval());
+
+ // coeff wise product
+
+ VERIFY_IS_APPROX((vf * vcf.transpose()).eval(), (vf.template cast<complex<float> >() * vcf.transpose()).eval());
+
+ Mat_cd mcd2 = mcd;
+ VERIFY_IS_APPROX(mcd.array() *= md.array(), mcd2.array() *= md.array().template cast<std::complex<double> >());
+
+ // check matrix-matrix products
+
+ VERIFY_IS_APPROX(sd*md*mcd, (sd*md).template cast<CD>().eval()*mcd);
+ VERIFY_IS_APPROX(sd*mcd*md, sd*mcd*md.template cast<CD>());
+ VERIFY_IS_APPROX(scd*md*mcd, scd*md.template cast<CD>().eval()*mcd);
+ VERIFY_IS_APPROX(scd*mcd*md, scd*mcd*md.template cast<CD>());
+
+ VERIFY_IS_APPROX(sf*mf*mcf, sf*mf.template cast<CF>()*mcf);
+ VERIFY_IS_APPROX(sf*mcf*mf, sf*mcf*mf.template cast<CF>());
+ VERIFY_IS_APPROX(scf*mf*mcf, scf*mf.template cast<CF>()*mcf);
+ VERIFY_IS_APPROX(scf*mcf*mf, scf*mcf*mf.template cast<CF>());
+
+ VERIFY_IS_APPROX(sf*mf*vcf, (sf*mf).template cast<CF>().eval()*vcf);
+ VERIFY_IS_APPROX(scf*mf*vcf,(scf*mf.template cast<CF>()).eval()*vcf);
+ VERIFY_IS_APPROX(sf*mcf*vf, sf*mcf*vf.template cast<CF>());
+ VERIFY_IS_APPROX(scf*mcf*vf,scf*mcf*vf.template cast<CF>());
+
+ VERIFY_IS_APPROX(sf*vcf.adjoint()*mf, sf*vcf.adjoint()*mf.template cast<CF>().eval());
+ VERIFY_IS_APPROX(scf*vcf.adjoint()*mf, scf*vcf.adjoint()*mf.template cast<CF>().eval());
+ VERIFY_IS_APPROX(sf*vf.adjoint()*mcf, sf*vf.adjoint().template cast<CF>().eval()*mcf);
+ VERIFY_IS_APPROX(scf*vf.adjoint()*mcf, scf*vf.adjoint().template cast<CF>().eval()*mcf);
+
+ VERIFY_IS_APPROX(sd*md*vcd, (sd*md).template cast<CD>().eval()*vcd);
+ VERIFY_IS_APPROX(scd*md*vcd,(scd*md.template cast<CD>()).eval()*vcd);
+ VERIFY_IS_APPROX(sd*mcd*vd, sd*mcd*vd.template cast<CD>().eval());
+ VERIFY_IS_APPROX(scd*mcd*vd,scd*mcd*vd.template cast<CD>().eval());
+
+ VERIFY_IS_APPROX(sd*vcd.adjoint()*md, sd*vcd.adjoint()*md.template cast<CD>().eval());
+ VERIFY_IS_APPROX(scd*vcd.adjoint()*md, scd*vcd.adjoint()*md.template cast<CD>().eval());
+ VERIFY_IS_APPROX(sd*vd.adjoint()*mcd, sd*vd.adjoint().template cast<CD>().eval()*mcd);
+ VERIFY_IS_APPROX(scd*vd.adjoint()*mcd, scd*vd.adjoint().template cast<CD>().eval()*mcd);
+}
+
+void test_mixingtypes()
+{
+ CALL_SUBTEST_1(mixingtypes<3>());
+ CALL_SUBTEST_2(mixingtypes<4>());
+ CALL_SUBTEST_3(mixingtypes<Dynamic>(internal::random<int>(1,EIGEN_TEST_MAX_SIZE)));
+}
diff --git a/test/nesting_ops.cpp b/test/nesting_ops.cpp
new file mode 100644
index 000000000..938ebcb7a
--- /dev/null
+++ b/test/nesting_ops.cpp
@@ -0,0 +1,41 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra.
+//
+// Copyright (C) 2010 Hauke Heibel <hauke.heibel@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 "main.h"
+
+template <typename MatrixType> void run_nesting_ops(const MatrixType& _m)
+{
+ typename MatrixType::Nested m(_m);
+ typedef typename MatrixType::Scalar Scalar;
+
+#ifdef NDEBUG
+ const bool is_debug = false;
+#else
+ const bool is_debug = true;
+#endif
+
+ // Make really sure that we are in debug mode! We don't want any type of
+ // inlining for these tests to pass.
+ VERIFY(is_debug);
+
+ // The only intention of these tests is to ensure that this code does
+ // not trigger any asserts or segmentation faults... more to come.
+ VERIFY_IS_APPROX( (m.transpose() * m).diagonal().sum(), (m.transpose() * m).diagonal().sum() );
+ VERIFY_IS_APPROX( (m.transpose() * m).diagonal().array().abs().sum(), (m.transpose() * m).diagonal().array().abs().sum() );
+
+ VERIFY_IS_APPROX( (m.transpose() * m).array().abs().sum(), (m.transpose() * m).array().abs().sum() );
+}
+
+void test_nesting_ops()
+{
+ CALL_SUBTEST_1(run_nesting_ops(MatrixXf::Random(25,25)));
+ CALL_SUBTEST_2(run_nesting_ops(MatrixXd::Random(25,25)));
+ CALL_SUBTEST_3(run_nesting_ops(Matrix4f::Random()));
+ CALL_SUBTEST_4(run_nesting_ops(Matrix4d::Random()));
+}
diff --git a/test/nomalloc.cpp b/test/nomalloc.cpp
new file mode 100644
index 000000000..d4ffcefcb
--- /dev/null
+++ b/test/nomalloc.cpp
@@ -0,0 +1,174 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra.
+//
+// Copyright (C) 2008 Gael Guennebaud <gael.guennebaud@inria.fr>
+// Copyright (C) 2006-2008 Benoit Jacob <jacob.benoit.1@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/.
+
+// this hack is needed to make this file compiles with -pedantic (gcc)
+#ifdef __GNUC__
+#define throw(X)
+#endif
+// discard stack allocation as that too bypasses malloc
+#define EIGEN_STACK_ALLOCATION_LIMIT 0
+// any heap allocation will raise an assert
+#define EIGEN_NO_MALLOC
+
+#include "main.h"
+#include <Eigen/Cholesky>
+#include <Eigen/Eigenvalues>
+#include <Eigen/LU>
+#include <Eigen/QR>
+#include <Eigen/SVD>
+
+template<typename MatrixType> void nomalloc(const MatrixType& m)
+{
+ /* this test check no dynamic memory allocation are issued with fixed-size matrices
+ */
+ typedef typename MatrixType::Index Index;
+ typedef typename MatrixType::Scalar Scalar;
+ typedef Matrix<Scalar, MatrixType::RowsAtCompileTime, 1> VectorType;
+
+ Index rows = m.rows();
+ Index cols = m.cols();
+
+ MatrixType m1 = MatrixType::Random(rows, cols),
+ m2 = MatrixType::Random(rows, cols),
+ m3(rows, cols);
+
+ Scalar s1 = internal::random<Scalar>();
+
+ Index r = internal::random<Index>(0, rows-1),
+ c = internal::random<Index>(0, cols-1);
+
+ VERIFY_IS_APPROX((m1+m2)*s1, s1*m1+s1*m2);
+ VERIFY_IS_APPROX((m1+m2)(r,c), (m1(r,c))+(m2(r,c)));
+ VERIFY_IS_APPROX(m1.cwiseProduct(m1.block(0,0,rows,cols)), (m1.array()*m1.array()).matrix());
+ VERIFY_IS_APPROX((m1*m1.transpose())*m2, m1*(m1.transpose()*m2));
+
+ m2.col(0).noalias() = m1 * m1.col(0);
+ m2.col(0).noalias() -= m1.adjoint() * m1.col(0);
+ m2.col(0).noalias() -= m1 * m1.row(0).adjoint();
+ m2.col(0).noalias() -= m1.adjoint() * m1.row(0).adjoint();
+
+ m2.row(0).noalias() = m1.row(0) * m1;
+ m2.row(0).noalias() -= m1.row(0) * m1.adjoint();
+ m2.row(0).noalias() -= m1.col(0).adjoint() * m1;
+ m2.row(0).noalias() -= m1.col(0).adjoint() * m1.adjoint();
+ VERIFY_IS_APPROX(m2,m2);
+
+ m2.col(0).noalias() = m1.template triangularView<Upper>() * m1.col(0);
+ m2.col(0).noalias() -= m1.adjoint().template triangularView<Upper>() * m1.col(0);
+ m2.col(0).noalias() -= m1.template triangularView<Upper>() * m1.row(0).adjoint();
+ m2.col(0).noalias() -= m1.adjoint().template triangularView<Upper>() * m1.row(0).adjoint();
+
+ m2.row(0).noalias() = m1.row(0) * m1.template triangularView<Upper>();
+ m2.row(0).noalias() -= m1.row(0) * m1.adjoint().template triangularView<Upper>();
+ m2.row(0).noalias() -= m1.col(0).adjoint() * m1.template triangularView<Upper>();
+ m2.row(0).noalias() -= m1.col(0).adjoint() * m1.adjoint().template triangularView<Upper>();
+ VERIFY_IS_APPROX(m2,m2);
+
+ m2.col(0).noalias() = m1.template selfadjointView<Upper>() * m1.col(0);
+ m2.col(0).noalias() -= m1.adjoint().template selfadjointView<Upper>() * m1.col(0);
+ m2.col(0).noalias() -= m1.template selfadjointView<Upper>() * m1.row(0).adjoint();
+ m2.col(0).noalias() -= m1.adjoint().template selfadjointView<Upper>() * m1.row(0).adjoint();
+
+ m2.row(0).noalias() = m1.row(0) * m1.template selfadjointView<Upper>();
+ m2.row(0).noalias() -= m1.row(0) * m1.adjoint().template selfadjointView<Upper>();
+ m2.row(0).noalias() -= m1.col(0).adjoint() * m1.template selfadjointView<Upper>();
+ m2.row(0).noalias() -= m1.col(0).adjoint() * m1.adjoint().template selfadjointView<Upper>();
+ VERIFY_IS_APPROX(m2,m2);
+
+ m2.template selfadjointView<Lower>().rankUpdate(m1.col(0),-1);
+ m2.template selfadjointView<Lower>().rankUpdate(m1.row(0),-1);
+
+ // The following fancy matrix-matrix products are not safe yet regarding static allocation
+// m1 += m1.template triangularView<Upper>() * m2.col(;
+// m1.template selfadjointView<Lower>().rankUpdate(m2);
+// m1 += m1.template triangularView<Upper>() * m2;
+// m1 += m1.template selfadjointView<Lower>() * m2;
+// VERIFY_IS_APPROX(m1,m1);
+}
+
+template<typename Scalar>
+void ctms_decompositions()
+{
+ const int maxSize = 16;
+ const int size = 12;
+
+ typedef Eigen::Matrix<Scalar,
+ Eigen::Dynamic, Eigen::Dynamic,
+ 0,
+ maxSize, maxSize> Matrix;
+
+ typedef Eigen::Matrix<Scalar,
+ Eigen::Dynamic, 1,
+ 0,
+ maxSize, 1> Vector;
+
+ typedef Eigen::Matrix<std::complex<Scalar>,
+ Eigen::Dynamic, Eigen::Dynamic,
+ 0,
+ maxSize, maxSize> ComplexMatrix;
+
+ const Matrix A(Matrix::Random(size, size)), B(Matrix::Random(size, size));
+ Matrix X(size,size);
+ const ComplexMatrix complexA(ComplexMatrix::Random(size, size));
+ const Matrix saA = A.adjoint() * A;
+ const Vector b(Vector::Random(size));
+ Vector x(size);
+
+ // Cholesky module
+ Eigen::LLT<Matrix> LLT; LLT.compute(A);
+ X = LLT.solve(B);
+ x = LLT.solve(b);
+ Eigen::LDLT<Matrix> LDLT; LDLT.compute(A);
+ X = LDLT.solve(B);
+ x = LDLT.solve(b);
+
+ // Eigenvalues module
+ Eigen::HessenbergDecomposition<ComplexMatrix> hessDecomp; hessDecomp.compute(complexA);
+ Eigen::ComplexSchur<ComplexMatrix> cSchur(size); cSchur.compute(complexA);
+ Eigen::ComplexEigenSolver<ComplexMatrix> cEigSolver; cEigSolver.compute(complexA);
+ Eigen::EigenSolver<Matrix> eigSolver; eigSolver.compute(A);
+ Eigen::SelfAdjointEigenSolver<Matrix> saEigSolver(size); saEigSolver.compute(saA);
+ Eigen::Tridiagonalization<Matrix> tridiag; tridiag.compute(saA);
+
+ // LU module
+ Eigen::PartialPivLU<Matrix> ppLU; ppLU.compute(A);
+ X = ppLU.solve(B);
+ x = ppLU.solve(b);
+ Eigen::FullPivLU<Matrix> fpLU; fpLU.compute(A);
+ X = fpLU.solve(B);
+ x = fpLU.solve(b);
+
+ // QR module
+ Eigen::HouseholderQR<Matrix> hQR; hQR.compute(A);
+ X = hQR.solve(B);
+ x = hQR.solve(b);
+ Eigen::ColPivHouseholderQR<Matrix> cpQR; cpQR.compute(A);
+ X = cpQR.solve(B);
+ x = cpQR.solve(b);
+ Eigen::FullPivHouseholderQR<Matrix> fpQR; fpQR.compute(A);
+ // FIXME X = fpQR.solve(B);
+ x = fpQR.solve(b);
+
+ // SVD module
+ Eigen::JacobiSVD<Matrix> jSVD; jSVD.compute(A, ComputeFullU | ComputeFullV);
+}
+
+void test_nomalloc()
+{
+ // check that our operator new is indeed called:
+ VERIFY_RAISES_ASSERT(MatrixXd dummy(MatrixXd::Random(3,3)));
+ CALL_SUBTEST_1(nomalloc(Matrix<float, 1, 1>()) );
+ CALL_SUBTEST_2(nomalloc(Matrix4d()) );
+ CALL_SUBTEST_3(nomalloc(Matrix<float,32,32>()) );
+
+ // Check decomposition modules with dynamic matrices that have a known compile-time max size (ctms)
+ CALL_SUBTEST_4(ctms_decompositions<float>());
+
+}
diff --git a/test/nullary.cpp b/test/nullary.cpp
new file mode 100644
index 000000000..1220e3f97
--- /dev/null
+++ b/test/nullary.cpp
@@ -0,0 +1,123 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra.
+//
+// Copyright (C) 2010-2011 Jitse Niesen <jitse@maths.leeds.ac.uk>
+//
+// This Source Code Form is subject to the terms of the Mozilla
+// Public License v. 2.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 "main.h"
+
+template<typename MatrixType>
+bool equalsIdentity(const MatrixType& A)
+{
+ typedef typename MatrixType::Index Index;
+ typedef typename MatrixType::Scalar Scalar;
+ Scalar zero = static_cast<Scalar>(0);
+
+ bool offDiagOK = true;
+ for (Index i = 0; i < A.rows(); ++i) {
+ for (Index j = i+1; j < A.cols(); ++j) {
+ offDiagOK = offDiagOK && (A(i,j) == zero);
+ }
+ }
+ for (Index i = 0; i < A.rows(); ++i) {
+ for (Index j = 0; j < (std::min)(i, A.cols()); ++j) {
+ offDiagOK = offDiagOK && (A(i,j) == zero);
+ }
+ }
+
+ bool diagOK = (A.diagonal().array() == 1).all();
+ return offDiagOK && diagOK;
+}
+
+template<typename VectorType>
+void testVectorType(const VectorType& base)
+{
+ typedef typename internal::traits<VectorType>::Index Index;
+ typedef typename internal::traits<VectorType>::Scalar Scalar;
+
+ const Index size = base.size();
+
+ Scalar high = internal::random<Scalar>(-500,500);
+ Scalar low = (size == 1 ? high : internal::random<Scalar>(-500,500));
+ if (low>high) std::swap(low,high);
+
+ const Scalar step = ((size == 1) ? 1 : (high-low)/(size-1));
+
+ // check whether the result yields what we expect it to do
+ VectorType m(base);
+ m.setLinSpaced(size,low,high);
+
+ VectorType n(size);
+ for (int i=0; i<size; ++i)
+ n(i) = low+i*step;
+
+ VERIFY_IS_APPROX(m,n);
+
+ // random access version
+ m = VectorType::LinSpaced(size,low,high);
+ VERIFY_IS_APPROX(m,n);
+
+ // Assignment of a RowVectorXd to a MatrixXd (regression test for bug #79).
+ VERIFY( (MatrixXd(RowVectorXd::LinSpaced(3, 0, 1)) - RowVector3d(0, 0.5, 1)).norm() < std::numeric_limits<Scalar>::epsilon() );
+
+ // These guys sometimes fail! This is not good. Any ideas how to fix them!?
+ //VERIFY( m(m.size()-1) == high );
+ //VERIFY( m(0) == low );
+
+ // sequential access version
+ m = VectorType::LinSpaced(Sequential,size,low,high);
+ VERIFY_IS_APPROX(m,n);
+
+ // These guys sometimes fail! This is not good. Any ideas how to fix them!?
+ //VERIFY( m(m.size()-1) == high );
+ //VERIFY( m(0) == low );
+
+ // check whether everything works with row and col major vectors
+ Matrix<Scalar,Dynamic,1> row_vector(size);
+ Matrix<Scalar,1,Dynamic> col_vector(size);
+ row_vector.setLinSpaced(size,low,high);
+ col_vector.setLinSpaced(size,low,high);
+ VERIFY( row_vector.isApprox(col_vector.transpose(), NumTraits<Scalar>::epsilon()));
+
+ Matrix<Scalar,Dynamic,1> size_changer(size+50);
+ size_changer.setLinSpaced(size,low,high);
+ VERIFY( size_changer.size() == size );
+
+ typedef Matrix<Scalar,1,1> ScalarMatrix;
+ ScalarMatrix scalar;
+ scalar.setLinSpaced(1,low,high);
+ VERIFY_IS_APPROX( scalar, ScalarMatrix::Constant(high) );
+ VERIFY_IS_APPROX( ScalarMatrix::LinSpaced(1,low,high), ScalarMatrix::Constant(high) );
+}
+
+template<typename MatrixType>
+void testMatrixType(const MatrixType& m)
+{
+ typedef typename MatrixType::Index Index;
+ const Index rows = m.rows();
+ const Index cols = m.cols();
+
+ MatrixType A;
+ A.setIdentity(rows, cols);
+ VERIFY(equalsIdentity(A));
+ VERIFY(equalsIdentity(MatrixType::Identity(rows, cols)));
+}
+
+void test_nullary()
+{
+ CALL_SUBTEST_1( testMatrixType(Matrix2d()) );
+ CALL_SUBTEST_2( testMatrixType(MatrixXcf(internal::random<int>(1,300),internal::random<int>(1,300))) );
+ CALL_SUBTEST_3( testMatrixType(MatrixXf(internal::random<int>(1,300),internal::random<int>(1,300))) );
+
+ for(int i = 0; i < g_repeat; i++) {
+ CALL_SUBTEST_4( testVectorType(VectorXd(internal::random<int>(1,300))) );
+ CALL_SUBTEST_5( testVectorType(Vector4d()) ); // regression test for bug 232
+ CALL_SUBTEST_6( testVectorType(Vector3d()) );
+ CALL_SUBTEST_7( testVectorType(VectorXf(internal::random<int>(1,300))) );
+ CALL_SUBTEST_8( testVectorType(Vector3f()) );
+ CALL_SUBTEST_8( testVectorType(Matrix<float,1,1>()) );
+ }
+}
diff --git a/test/packetmath.cpp b/test/packetmath.cpp
new file mode 100644
index 000000000..c1464e994
--- /dev/null
+++ b/test/packetmath.cpp
@@ -0,0 +1,345 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra.
+//
+// Copyright (C) 2008-2009 Gael Guennebaud <gael.guennebaud@inria.fr>
+// Copyright (C) 2006-2008 Benoit Jacob <jacob.benoit.1@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 "main.h"
+
+// using namespace Eigen;
+
+namespace Eigen {
+namespace internal {
+template<typename T> T negate(const T& x) { return -x; }
+}
+}
+
+template<typename Scalar> bool isApproxAbs(const Scalar& a, const Scalar& b, const typename NumTraits<Scalar>::Real& refvalue)
+{
+ return internal::isMuchSmallerThan(a-b, refvalue);
+}
+
+template<typename Scalar> bool areApproxAbs(const Scalar* a, const Scalar* b, int size, const typename NumTraits<Scalar>::Real& refvalue)
+{
+ for (int i=0; i<size; ++i)
+ {
+ if (!isApproxAbs(a[i],b[i],refvalue))
+ {
+ std::cout << "[" << Map<const Matrix<Scalar,1,Dynamic> >(a,size) << "]" << " != " << Map<const Matrix<Scalar,1,Dynamic> >(b,size) << "\n";
+ return false;
+ }
+ }
+ return true;
+}
+
+template<typename Scalar> bool areApprox(const Scalar* a, const Scalar* b, int size)
+{
+ for (int i=0; i<size; ++i)
+ {
+ if (!internal::isApprox(a[i],b[i]))
+ {
+ std::cout << "[" << Map<const Matrix<Scalar,1,Dynamic> >(a,size) << "]" << " != " << Map<const Matrix<Scalar,1,Dynamic> >(b,size) << "\n";
+ return false;
+ }
+ }
+ return true;
+}
+
+
+#define CHECK_CWISE2(REFOP, POP) { \
+ for (int i=0; i<PacketSize; ++i) \
+ ref[i] = REFOP(data1[i], data1[i+PacketSize]); \
+ internal::pstore(data2, POP(internal::pload<Packet>(data1), internal::pload<Packet>(data1+PacketSize))); \
+ VERIFY(areApprox(ref, data2, PacketSize) && #POP); \
+}
+
+#define CHECK_CWISE1(REFOP, POP) { \
+ for (int i=0; i<PacketSize; ++i) \
+ ref[i] = REFOP(data1[i]); \
+ internal::pstore(data2, POP(internal::pload<Packet>(data1))); \
+ VERIFY(areApprox(ref, data2, PacketSize) && #POP); \
+}
+
+template<bool Cond,typename Packet>
+struct packet_helper
+{
+ template<typename T>
+ inline Packet load(const T* from) const { return internal::pload<Packet>(from); }
+
+ template<typename T>
+ inline void store(T* to, const Packet& x) const { internal::pstore(to,x); }
+};
+
+template<typename Packet>
+struct packet_helper<false,Packet>
+{
+ template<typename T>
+ inline T load(const T* from) const { return *from; }
+
+ template<typename T>
+ inline void store(T* to, const T& x) const { *to = x; }
+};
+
+#define CHECK_CWISE1_IF(COND, REFOP, POP) if(COND) { \
+ packet_helper<COND,Packet> h; \
+ for (int i=0; i<PacketSize; ++i) \
+ ref[i] = REFOP(data1[i]); \
+ h.store(data2, POP(h.load(data1))); \
+ VERIFY(areApprox(ref, data2, PacketSize) && #POP); \
+}
+
+#define REF_ADD(a,b) ((a)+(b))
+#define REF_SUB(a,b) ((a)-(b))
+#define REF_MUL(a,b) ((a)*(b))
+#define REF_DIV(a,b) ((a)/(b))
+
+template<typename Scalar> void packetmath()
+{
+ typedef typename internal::packet_traits<Scalar>::type Packet;
+ const int PacketSize = internal::packet_traits<Scalar>::size;
+ typedef typename NumTraits<Scalar>::Real RealScalar;
+
+ const int size = PacketSize*4;
+ EIGEN_ALIGN16 Scalar data1[internal::packet_traits<Scalar>::size*4];
+ EIGEN_ALIGN16 Scalar data2[internal::packet_traits<Scalar>::size*4];
+ EIGEN_ALIGN16 Packet packets[PacketSize*2];
+ EIGEN_ALIGN16 Scalar ref[internal::packet_traits<Scalar>::size*4];
+ RealScalar refvalue = 0;
+ for (int i=0; i<size; ++i)
+ {
+ data1[i] = internal::random<Scalar>()/RealScalar(PacketSize);
+ data2[i] = internal::random<Scalar>()/RealScalar(PacketSize);
+ refvalue = (std::max)(refvalue,internal::abs(data1[i]));
+ }
+
+ internal::pstore(data2, internal::pload<Packet>(data1));
+ VERIFY(areApprox(data1, data2, PacketSize) && "aligned load/store");
+
+ for (int offset=0; offset<PacketSize; ++offset)
+ {
+ internal::pstore(data2, internal::ploadu<Packet>(data1+offset));
+ VERIFY(areApprox(data1+offset, data2, PacketSize) && "internal::ploadu");
+ }
+
+ for (int offset=0; offset<PacketSize; ++offset)
+ {
+ internal::pstoreu(data2+offset, internal::pload<Packet>(data1));
+ VERIFY(areApprox(data1, data2+offset, PacketSize) && "internal::pstoreu");
+ }
+
+ for (int offset=0; offset<PacketSize; ++offset)
+ {
+ packets[0] = internal::pload<Packet>(data1);
+ packets[1] = internal::pload<Packet>(data1+PacketSize);
+ if (offset==0) internal::palign<0>(packets[0], packets[1]);
+ else if (offset==1) internal::palign<1>(packets[0], packets[1]);
+ else if (offset==2) internal::palign<2>(packets[0], packets[1]);
+ else if (offset==3) internal::palign<3>(packets[0], packets[1]);
+ internal::pstore(data2, packets[0]);
+
+ for (int i=0; i<PacketSize; ++i)
+ ref[i] = data1[i+offset];
+
+ typedef Matrix<Scalar, PacketSize, 1> Vector;
+ VERIFY(areApprox(ref, data2, PacketSize) && "internal::palign");
+ }
+
+ CHECK_CWISE2(REF_ADD, internal::padd);
+ CHECK_CWISE2(REF_SUB, internal::psub);
+ CHECK_CWISE2(REF_MUL, internal::pmul);
+ #ifndef EIGEN_VECTORIZE_ALTIVEC
+ if (!internal::is_same<Scalar,int>::value)
+ CHECK_CWISE2(REF_DIV, internal::pdiv);
+ #endif
+ CHECK_CWISE1(internal::negate, internal::pnegate);
+ CHECK_CWISE1(internal::conj, internal::pconj);
+
+ for(int offset=0;offset<3;++offset)
+ {
+ for (int i=0; i<PacketSize; ++i)
+ ref[i] = data1[offset];
+ internal::pstore(data2, internal::pset1<Packet>(data1[offset]));
+ VERIFY(areApprox(ref, data2, PacketSize) && "internal::pset1");
+ }
+
+ VERIFY(internal::isApprox(data1[0], internal::pfirst(internal::pload<Packet>(data1))) && "internal::pfirst");
+
+ if(PacketSize>1)
+ {
+ for(int offset=0;offset<4;++offset)
+ {
+ for(int i=0;i<PacketSize/2;++i)
+ ref[2*i+0] = ref[2*i+1] = data1[offset+i];
+ internal::pstore(data2,internal::ploaddup<Packet>(data1+offset));
+ VERIFY(areApprox(ref, data2, PacketSize) && "ploaddup");
+ }
+ }
+
+ ref[0] = 0;
+ for (int i=0; i<PacketSize; ++i)
+ ref[0] += data1[i];
+ VERIFY(isApproxAbs(ref[0], internal::predux(internal::pload<Packet>(data1)), refvalue) && "internal::predux");
+
+ ref[0] = 1;
+ for (int i=0; i<PacketSize; ++i)
+ ref[0] *= data1[i];
+ VERIFY(internal::isApprox(ref[0], internal::predux_mul(internal::pload<Packet>(data1))) && "internal::predux_mul");
+
+ for (int j=0; j<PacketSize; ++j)
+ {
+ ref[j] = 0;
+ for (int i=0; i<PacketSize; ++i)
+ ref[j] += data1[i+j*PacketSize];
+ packets[j] = internal::pload<Packet>(data1+j*PacketSize);
+ }
+ internal::pstore(data2, internal::preduxp(packets));
+ VERIFY(areApproxAbs(ref, data2, PacketSize, refvalue) && "internal::preduxp");
+
+ for (int i=0; i<PacketSize; ++i)
+ ref[i] = data1[PacketSize-i-1];
+ internal::pstore(data2, internal::preverse(internal::pload<Packet>(data1)));
+ VERIFY(areApprox(ref, data2, PacketSize) && "internal::preverse");
+}
+
+template<typename Scalar> void packetmath_real()
+{
+ typedef typename internal::packet_traits<Scalar>::type Packet;
+ const int PacketSize = internal::packet_traits<Scalar>::size;
+
+ const int size = PacketSize*4;
+ EIGEN_ALIGN16 Scalar data1[internal::packet_traits<Scalar>::size*4];
+ EIGEN_ALIGN16 Scalar data2[internal::packet_traits<Scalar>::size*4];
+ EIGEN_ALIGN16 Scalar ref[internal::packet_traits<Scalar>::size*4];
+
+ for (int i=0; i<size; ++i)
+ {
+ data1[i] = internal::random<Scalar>(-1e3,1e3);
+ data2[i] = internal::random<Scalar>(-1e3,1e3);
+ }
+ CHECK_CWISE1_IF(internal::packet_traits<Scalar>::HasSin, internal::sin, internal::psin);
+ CHECK_CWISE1_IF(internal::packet_traits<Scalar>::HasCos, internal::cos, internal::pcos);
+ CHECK_CWISE1_IF(internal::packet_traits<Scalar>::HasTan, internal::tan, internal::ptan);
+
+ for (int i=0; i<size; ++i)
+ {
+ data1[i] = internal::random<Scalar>(-1,1);
+ data2[i] = internal::random<Scalar>(-1,1);
+ }
+ CHECK_CWISE1_IF(internal::packet_traits<Scalar>::HasASin, internal::asin, internal::pasin);
+ CHECK_CWISE1_IF(internal::packet_traits<Scalar>::HasACos, internal::acos, internal::pacos);
+
+ for (int i=0; i<size; ++i)
+ {
+ data1[i] = internal::random<Scalar>(-87,88);
+ data2[i] = internal::random<Scalar>(-87,88);
+ }
+ CHECK_CWISE1_IF(internal::packet_traits<Scalar>::HasExp, internal::exp, internal::pexp);
+
+ for (int i=0; i<size; ++i)
+ {
+ data1[i] = internal::random<Scalar>(0,1e6);
+ data2[i] = internal::random<Scalar>(0,1e6);
+ }
+ CHECK_CWISE1_IF(internal::packet_traits<Scalar>::HasLog, internal::log, internal::plog);
+ CHECK_CWISE1_IF(internal::packet_traits<Scalar>::HasSqrt, internal::sqrt, internal::psqrt);
+
+ ref[0] = data1[0];
+ for (int i=0; i<PacketSize; ++i)
+ ref[0] = (std::min)(ref[0],data1[i]);
+ VERIFY(internal::isApprox(ref[0], internal::predux_min(internal::pload<Packet>(data1))) && "internal::predux_min");
+
+ CHECK_CWISE2((std::min), internal::pmin);
+ CHECK_CWISE2((std::max), internal::pmax);
+ CHECK_CWISE1(internal::abs, internal::pabs);
+
+ ref[0] = data1[0];
+ for (int i=0; i<PacketSize; ++i)
+ ref[0] = (std::max)(ref[0],data1[i]);
+ VERIFY(internal::isApprox(ref[0], internal::predux_max(internal::pload<Packet>(data1))) && "internal::predux_max");
+
+ for (int i=0; i<PacketSize; ++i)
+ ref[i] = data1[0]+Scalar(i);
+ internal::pstore(data2, internal::plset(data1[0]));
+ VERIFY(areApprox(ref, data2, PacketSize) && "internal::plset");
+}
+
+template<typename Scalar,bool ConjLhs,bool ConjRhs> void test_conj_helper(Scalar* data1, Scalar* data2, Scalar* ref, Scalar* pval)
+{
+ typedef typename internal::packet_traits<Scalar>::type Packet;
+ const int PacketSize = internal::packet_traits<Scalar>::size;
+
+ internal::conj_if<ConjLhs> cj0;
+ internal::conj_if<ConjRhs> cj1;
+ internal::conj_helper<Scalar,Scalar,ConjLhs,ConjRhs> cj;
+ internal::conj_helper<Packet,Packet,ConjLhs,ConjRhs> pcj;
+
+ for(int i=0;i<PacketSize;++i)
+ {
+ ref[i] = cj0(data1[i]) * cj1(data2[i]);
+ VERIFY(internal::isApprox(ref[i], cj.pmul(data1[i],data2[i])) && "conj_helper pmul");
+ }
+ internal::pstore(pval,pcj.pmul(internal::pload<Packet>(data1),internal::pload<Packet>(data2)));
+ VERIFY(areApprox(ref, pval, PacketSize) && "conj_helper pmul");
+
+ for(int i=0;i<PacketSize;++i)
+ {
+ Scalar tmp = ref[i];
+ ref[i] += cj0(data1[i]) * cj1(data2[i]);
+ VERIFY(internal::isApprox(ref[i], cj.pmadd(data1[i],data2[i],tmp)) && "conj_helper pmadd");
+ }
+ internal::pstore(pval,pcj.pmadd(internal::pload<Packet>(data1),internal::pload<Packet>(data2),internal::pload<Packet>(pval)));
+ VERIFY(areApprox(ref, pval, PacketSize) && "conj_helper pmadd");
+}
+
+template<typename Scalar> void packetmath_complex()
+{
+ typedef typename internal::packet_traits<Scalar>::type Packet;
+ const int PacketSize = internal::packet_traits<Scalar>::size;
+
+ const int size = PacketSize*4;
+ EIGEN_ALIGN16 Scalar data1[PacketSize*4];
+ EIGEN_ALIGN16 Scalar data2[PacketSize*4];
+ EIGEN_ALIGN16 Scalar ref[PacketSize*4];
+ EIGEN_ALIGN16 Scalar pval[PacketSize*4];
+
+ for (int i=0; i<size; ++i)
+ {
+ data1[i] = internal::random<Scalar>() * Scalar(1e2);
+ data2[i] = internal::random<Scalar>() * Scalar(1e2);
+ }
+
+ test_conj_helper<Scalar,false,false> (data1,data2,ref,pval);
+ test_conj_helper<Scalar,false,true> (data1,data2,ref,pval);
+ test_conj_helper<Scalar,true,false> (data1,data2,ref,pval);
+ test_conj_helper<Scalar,true,true> (data1,data2,ref,pval);
+
+ {
+ for(int i=0;i<PacketSize;++i)
+ ref[i] = Scalar(std::imag(data1[i]),std::real(data1[i]));
+ internal::pstore(pval,internal::pcplxflip(internal::pload<Packet>(data1)));
+ VERIFY(areApprox(ref, pval, PacketSize) && "pcplxflip");
+ }
+
+
+}
+
+void test_packetmath()
+{
+ for(int i = 0; i < g_repeat; i++) {
+ CALL_SUBTEST_1( packetmath<float>() );
+ CALL_SUBTEST_2( packetmath<double>() );
+ CALL_SUBTEST_3( packetmath<int>() );
+ CALL_SUBTEST_1( packetmath<std::complex<float> >() );
+ CALL_SUBTEST_2( packetmath<std::complex<double> >() );
+
+ CALL_SUBTEST_1( packetmath_real<float>() );
+ CALL_SUBTEST_2( packetmath_real<double>() );
+
+ CALL_SUBTEST_1( packetmath_complex<std::complex<float> >() );
+ CALL_SUBTEST_2( packetmath_complex<std::complex<double> >() );
+ }
+}
diff --git a/test/pardiso_support.cpp b/test/pardiso_support.cpp
new file mode 100644
index 000000000..67efad6d8
--- /dev/null
+++ b/test/pardiso_support.cpp
@@ -0,0 +1,29 @@
+/*
+ Intel Copyright (C) ....
+*/
+
+#include "sparse_solver.h"
+#include <Eigen/PardisoSupport>
+
+template<typename T> void test_pardiso_T()
+{
+ PardisoLLT < SparseMatrix<T, RowMajor>, Lower> pardiso_llt_lower;
+ PardisoLLT < SparseMatrix<T, RowMajor>, Upper> pardiso_llt_upper;
+ PardisoLDLT < SparseMatrix<T, RowMajor>, Lower> pardiso_ldlt_lower;
+ PardisoLDLT < SparseMatrix<T, RowMajor>, Upper> pardiso_ldlt_upper;
+ PardisoLU < SparseMatrix<T, RowMajor> > pardiso_lu;
+
+ check_sparse_spd_solving(pardiso_llt_lower);
+ check_sparse_spd_solving(pardiso_llt_upper);
+ check_sparse_spd_solving(pardiso_ldlt_lower);
+ check_sparse_spd_solving(pardiso_ldlt_upper);
+ check_sparse_square_solving(pardiso_lu);
+}
+
+void test_pardiso_support()
+{
+ CALL_SUBTEST_1(test_pardiso_T<float>());
+ CALL_SUBTEST_2(test_pardiso_T<double>());
+ CALL_SUBTEST_3(test_pardiso_T< std::complex<float> >());
+ CALL_SUBTEST_4(test_pardiso_T< std::complex<double> >());
+}
diff --git a/test/pastix_support.cpp b/test/pastix_support.cpp
new file mode 100644
index 000000000..0e57227f9
--- /dev/null
+++ b/test/pastix_support.cpp
@@ -0,0 +1,44 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra.
+//
+// Copyright (C) 2008-2012 Gael Guennebaud <gael.guennebaud@inria.fr>
+// Copyright (C) 2012 Désiré Nuentsa-Wakam <desire.nuentsa_wakam@inria.fr>
+//
+// This Source Code Form is subject to the terms of the Mozilla
+// Public License v. 2.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 "sparse_solver.h"
+#include <Eigen/PaStiXSupport>
+#include <unsupported/Eigen/SparseExtra>
+
+
+template<typename T> void test_pastix_T()
+{
+ PastixLLT< SparseMatrix<T, ColMajor>, Eigen::Lower > pastix_llt_lower;
+ PastixLDLT< SparseMatrix<T, ColMajor>, Eigen::Lower > pastix_ldlt_lower;
+ PastixLLT< SparseMatrix<T, ColMajor>, Eigen::Upper > pastix_llt_upper;
+ PastixLDLT< SparseMatrix<T, ColMajor>, Eigen::Upper > pastix_ldlt_upper;
+ PastixLU< SparseMatrix<T, ColMajor> > pastix_lu;
+
+ check_sparse_spd_solving(pastix_llt_lower);
+ check_sparse_spd_solving(pastix_ldlt_lower);
+ check_sparse_spd_solving(pastix_llt_upper);
+ check_sparse_spd_solving(pastix_ldlt_upper);
+ check_sparse_square_solving(pastix_lu);
+}
+
+// There is no support for selfadjoint matrices with PaStiX.
+// Complex symmetric matrices should pass though
+template<typename T> void test_pastix_T_LU()
+{
+ PastixLU< SparseMatrix<T, ColMajor> > pastix_lu;
+ check_sparse_square_solving(pastix_lu);
+}
+
+void test_pastix_support()
+{
+ CALL_SUBTEST_1(test_pastix_T<float>());
+ CALL_SUBTEST_2(test_pastix_T<double>());
+ CALL_SUBTEST_3( (test_pastix_T_LU<std::complex<float> >()) );
+ CALL_SUBTEST_4(test_pastix_T_LU<std::complex<double> >());
+} \ No newline at end of file
diff --git a/test/permutationmatrices.cpp b/test/permutationmatrices.cpp
new file mode 100644
index 000000000..00f666ccd
--- /dev/null
+++ b/test/permutationmatrices.cpp
@@ -0,0 +1,117 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra.
+//
+// Copyright (C) 2009 Benoit Jacob <jacob.benoit.1@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 "main.h"
+
+using namespace std;
+template<typename MatrixType> void permutationmatrices(const MatrixType& m)
+{
+ typedef typename MatrixType::Index Index;
+ typedef typename MatrixType::Scalar Scalar;
+ typedef typename MatrixType::RealScalar RealScalar;
+ enum { Rows = MatrixType::RowsAtCompileTime, Cols = MatrixType::ColsAtCompileTime,
+ Options = MatrixType::Options };
+ typedef PermutationMatrix<Rows> LeftPermutationType;
+ typedef Matrix<int, Rows, 1> LeftPermutationVectorType;
+ typedef Map<LeftPermutationType> MapLeftPerm;
+ typedef PermutationMatrix<Cols> RightPermutationType;
+ typedef Matrix<int, Cols, 1> RightPermutationVectorType;
+ typedef Map<RightPermutationType> MapRightPerm;
+
+ Index rows = m.rows();
+ Index cols = m.cols();
+
+ MatrixType m_original = MatrixType::Random(rows,cols);
+ LeftPermutationVectorType lv;
+ randomPermutationVector(lv, rows);
+ LeftPermutationType lp(lv);
+ RightPermutationVectorType rv;
+ randomPermutationVector(rv, cols);
+ RightPermutationType rp(rv);
+ MatrixType m_permuted = lp * m_original * rp;
+
+ for (int i=0; i<rows; i++)
+ for (int j=0; j<cols; j++)
+ VERIFY_IS_APPROX(m_permuted(lv(i),j), m_original(i,rv(j)));
+
+ Matrix<Scalar,Rows,Rows> lm(lp);
+ Matrix<Scalar,Cols,Cols> rm(rp);
+
+ VERIFY_IS_APPROX(m_permuted, lm*m_original*rm);
+
+ VERIFY_IS_APPROX(lp.inverse()*m_permuted*rp.inverse(), m_original);
+ VERIFY_IS_APPROX(lv.asPermutation().inverse()*m_permuted*rv.asPermutation().inverse(), m_original);
+ VERIFY_IS_APPROX(MapLeftPerm(lv.data(),lv.size()).inverse()*m_permuted*MapRightPerm(rv.data(),rv.size()).inverse(), m_original);
+
+ VERIFY((lp*lp.inverse()).toDenseMatrix().isIdentity());
+ VERIFY((lv.asPermutation()*lv.asPermutation().inverse()).toDenseMatrix().isIdentity());
+ VERIFY((MapLeftPerm(lv.data(),lv.size())*MapLeftPerm(lv.data(),lv.size()).inverse()).toDenseMatrix().isIdentity());
+
+ LeftPermutationVectorType lv2;
+ randomPermutationVector(lv2, rows);
+ LeftPermutationType lp2(lv2);
+ Matrix<Scalar,Rows,Rows> lm2(lp2);
+ VERIFY_IS_APPROX((lp*lp2).toDenseMatrix().template cast<Scalar>(), lm*lm2);
+ VERIFY_IS_APPROX((lv.asPermutation()*lv2.asPermutation()).toDenseMatrix().template cast<Scalar>(), lm*lm2);
+ VERIFY_IS_APPROX((MapLeftPerm(lv.data(),lv.size())*MapLeftPerm(lv2.data(),lv2.size())).toDenseMatrix().template cast<Scalar>(), lm*lm2);
+
+ LeftPermutationType identityp;
+ identityp.setIdentity(rows);
+ VERIFY_IS_APPROX(m_original, identityp*m_original);
+
+ // check inplace permutations
+ m_permuted = m_original;
+ m_permuted = lp.inverse() * m_permuted;
+ VERIFY_IS_APPROX(m_permuted, lp.inverse()*m_original);
+
+ m_permuted = m_original;
+ m_permuted = m_permuted * rp.inverse();
+ VERIFY_IS_APPROX(m_permuted, m_original*rp.inverse());
+
+ m_permuted = m_original;
+ m_permuted = lp * m_permuted;
+ VERIFY_IS_APPROX(m_permuted, lp*m_original);
+
+ m_permuted = m_original;
+ m_permuted = m_permuted * rp;
+ VERIFY_IS_APPROX(m_permuted, m_original*rp);
+
+ if(rows>1 && cols>1)
+ {
+ lp2 = lp;
+ Index i = internal::random<Index>(0, rows-1);
+ Index j;
+ do j = internal::random<Index>(0, rows-1); while(j==i);
+ lp2.applyTranspositionOnTheLeft(i, j);
+ lm = lp;
+ lm.row(i).swap(lm.row(j));
+ VERIFY_IS_APPROX(lm, lp2.toDenseMatrix().template cast<Scalar>());
+
+ RightPermutationType rp2 = rp;
+ i = internal::random<Index>(0, cols-1);
+ do j = internal::random<Index>(0, cols-1); while(j==i);
+ rp2.applyTranspositionOnTheRight(i, j);
+ rm = rp;
+ rm.col(i).swap(rm.col(j));
+ VERIFY_IS_APPROX(rm, rp2.toDenseMatrix().template cast<Scalar>());
+ }
+}
+
+void test_permutationmatrices()
+{
+ for(int i = 0; i < g_repeat; i++) {
+ CALL_SUBTEST_1( permutationmatrices(Matrix<float, 1, 1>()) );
+ CALL_SUBTEST_2( permutationmatrices(Matrix3f()) );
+ CALL_SUBTEST_3( permutationmatrices(Matrix<double,3,3,RowMajor>()) );
+ CALL_SUBTEST_4( permutationmatrices(Matrix4d()) );
+ CALL_SUBTEST_5( permutationmatrices(Matrix<double,40,60>()) );
+ CALL_SUBTEST_6( permutationmatrices(Matrix<double,Dynamic,Dynamic,RowMajor>(20, 30)) );
+ CALL_SUBTEST_7( permutationmatrices(MatrixXcf(15, 10)) );
+ }
+}
diff --git a/test/prec_inverse_4x4.cpp b/test/prec_inverse_4x4.cpp
new file mode 100644
index 000000000..f7d0aff70
--- /dev/null
+++ b/test/prec_inverse_4x4.cpp
@@ -0,0 +1,68 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra.
+//
+// Copyright (C) 2009 Benoit Jacob <jacob.benoit.1@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 "main.h"
+#include <Eigen/LU>
+#include <algorithm>
+
+template<typename MatrixType> void inverse_permutation_4x4()
+{
+ typedef typename MatrixType::Scalar Scalar;
+ typedef typename MatrixType::RealScalar RealScalar;
+ Vector4i indices(0,1,2,3);
+ for(int i = 0; i < 24; ++i)
+ {
+ MatrixType m = PermutationMatrix<4>(indices);
+ MatrixType inv = m.inverse();
+ double error = double( (m*inv-MatrixType::Identity()).norm() / NumTraits<Scalar>::epsilon() );
+ EIGEN_DEBUG_VAR(error)
+ VERIFY(error == 0.0);
+ std::next_permutation(indices.data(),indices.data()+4);
+ }
+}
+
+template<typename MatrixType> void inverse_general_4x4(int repeat)
+{
+ typedef typename MatrixType::Scalar Scalar;
+ typedef typename MatrixType::RealScalar RealScalar;
+ double error_sum = 0., error_max = 0.;
+ for(int i = 0; i < repeat; ++i)
+ {
+ MatrixType m;
+ RealScalar absdet;
+ do {
+ m = MatrixType::Random();
+ absdet = internal::abs(m.determinant());
+ } while(absdet < NumTraits<Scalar>::epsilon());
+ MatrixType inv = m.inverse();
+ double error = double( (m*inv-MatrixType::Identity()).norm() * absdet / NumTraits<Scalar>::epsilon() );
+ error_sum += error;
+ error_max = (std::max)(error_max, error);
+ }
+ std::cerr << "inverse_general_4x4, Scalar = " << type_name<Scalar>() << std::endl;
+ double error_avg = error_sum / repeat;
+ EIGEN_DEBUG_VAR(error_avg);
+ EIGEN_DEBUG_VAR(error_max);
+ // FIXME that 1.25 used to be a 1.0 until the NumTraits changes on 28 April 2010, what's going wrong??
+ // FIXME that 1.25 used to be 1.2 until we tested gcc 4.1 on 30 June 2010 and got 1.21.
+ VERIFY(error_avg < (NumTraits<Scalar>::IsComplex ? 8.0 : 1.25));
+ VERIFY(error_max < (NumTraits<Scalar>::IsComplex ? 64.0 : 20.0));
+}
+
+void test_prec_inverse_4x4()
+{
+ CALL_SUBTEST_1((inverse_permutation_4x4<Matrix4f>()));
+ CALL_SUBTEST_1(( inverse_general_4x4<Matrix4f>(200000 * g_repeat) ));
+
+ CALL_SUBTEST_2((inverse_permutation_4x4<Matrix<double,4,4,RowMajor> >()));
+ CALL_SUBTEST_2(( inverse_general_4x4<Matrix<double,4,4,RowMajor> >(200000 * g_repeat) ));
+
+ CALL_SUBTEST_3((inverse_permutation_4x4<Matrix4cf>()));
+ CALL_SUBTEST_3((inverse_general_4x4<Matrix4cf>(50000 * g_repeat)));
+}
diff --git a/test/product.h b/test/product.h
new file mode 100644
index 000000000..4aa9fd56d
--- /dev/null
+++ b/test/product.h
@@ -0,0 +1,143 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra.
+//
+// Copyright (C) 2006-2008 Benoit Jacob <jacob.benoit.1@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 "main.h"
+#include <Eigen/QR>
+
+template<typename Derived1, typename Derived2>
+bool areNotApprox(const MatrixBase<Derived1>& m1, const MatrixBase<Derived2>& m2, typename Derived1::RealScalar epsilon = NumTraits<typename Derived1::RealScalar>::dummy_precision())
+{
+ return !((m1-m2).cwiseAbs2().maxCoeff() < epsilon * epsilon
+ * (std::max)(m1.cwiseAbs2().maxCoeff(), m2.cwiseAbs2().maxCoeff()));
+}
+
+template<typename MatrixType> void product(const MatrixType& m)
+{
+ /* this test covers the following files:
+ Identity.h Product.h
+ */
+ typedef typename MatrixType::Index Index;
+ typedef typename MatrixType::Scalar Scalar;
+ typedef typename NumTraits<Scalar>::NonInteger NonInteger;
+ typedef Matrix<Scalar, MatrixType::RowsAtCompileTime, 1> RowVectorType;
+ typedef Matrix<Scalar, MatrixType::ColsAtCompileTime, 1> ColVectorType;
+ typedef Matrix<Scalar, MatrixType::RowsAtCompileTime, MatrixType::RowsAtCompileTime> RowSquareMatrixType;
+ typedef Matrix<Scalar, MatrixType::ColsAtCompileTime, MatrixType::ColsAtCompileTime> ColSquareMatrixType;
+ typedef Matrix<Scalar, MatrixType::RowsAtCompileTime, MatrixType::ColsAtCompileTime,
+ MatrixType::Flags&RowMajorBit?ColMajor:RowMajor> OtherMajorMatrixType;
+
+ Index rows = m.rows();
+ Index cols = m.cols();
+
+ // this test relies a lot on Random.h, and there's not much more that we can do
+ // to test it, hence I consider that we will have tested Random.h
+ MatrixType m1 = MatrixType::Random(rows, cols),
+ m2 = MatrixType::Random(rows, cols),
+ m3(rows, cols);
+ RowSquareMatrixType
+ identity = RowSquareMatrixType::Identity(rows, rows),
+ square = RowSquareMatrixType::Random(rows, rows),
+ res = RowSquareMatrixType::Random(rows, rows);
+ ColSquareMatrixType
+ square2 = ColSquareMatrixType::Random(cols, cols),
+ res2 = ColSquareMatrixType::Random(cols, cols);
+ RowVectorType v1 = RowVectorType::Random(rows);
+ ColVectorType vc2 = ColVectorType::Random(cols), vcres(cols);
+ OtherMajorMatrixType tm1 = m1;
+
+ Scalar s1 = internal::random<Scalar>();
+
+ Index r = internal::random<Index>(0, rows-1),
+ c = internal::random<Index>(0, cols-1),
+ c2 = internal::random<Index>(0, cols-1);
+
+ // begin testing Product.h: only associativity for now
+ // (we use Transpose.h but this doesn't count as a test for it)
+ VERIFY_IS_APPROX((m1*m1.transpose())*m2, m1*(m1.transpose()*m2));
+ m3 = m1;
+ m3 *= m1.transpose() * m2;
+ VERIFY_IS_APPROX(m3, m1 * (m1.transpose()*m2));
+ VERIFY_IS_APPROX(m3, m1 * (m1.transpose()*m2));
+
+ // continue testing Product.h: distributivity
+ VERIFY_IS_APPROX(square*(m1 + m2), square*m1+square*m2);
+ VERIFY_IS_APPROX(square*(m1 - m2), square*m1-square*m2);
+
+ // continue testing Product.h: compatibility with ScalarMultiple.h
+ VERIFY_IS_APPROX(s1*(square*m1), (s1*square)*m1);
+ VERIFY_IS_APPROX(s1*(square*m1), square*(m1*s1));
+
+ // test Product.h together with Identity.h
+ VERIFY_IS_APPROX(v1, identity*v1);
+ VERIFY_IS_APPROX(v1.transpose(), v1.transpose() * identity);
+ // again, test operator() to check const-qualification
+ VERIFY_IS_APPROX(MatrixType::Identity(rows, cols)(r,c), static_cast<Scalar>(r==c));
+
+ if (rows!=cols)
+ VERIFY_RAISES_ASSERT(m3 = m1*m1);
+
+ // test the previous tests were not screwed up because operator* returns 0
+ // (we use the more accurate default epsilon)
+ if (!NumTraits<Scalar>::IsInteger && (std::min)(rows,cols)>1)
+ {
+ VERIFY(areNotApprox(m1.transpose()*m2,m2.transpose()*m1));
+ }
+
+ // test optimized operator+= path
+ res = square;
+ res.noalias() += m1 * m2.transpose();
+ VERIFY_IS_APPROX(res, square + m1 * m2.transpose());
+ if (!NumTraits<Scalar>::IsInteger && (std::min)(rows,cols)>1)
+ {
+ VERIFY(areNotApprox(res,square + m2 * m1.transpose()));
+ }
+ vcres = vc2;
+ vcres.noalias() += m1.transpose() * v1;
+ VERIFY_IS_APPROX(vcres, vc2 + m1.transpose() * v1);
+
+ // test optimized operator-= path
+ res = square;
+ res.noalias() -= m1 * m2.transpose();
+ VERIFY_IS_APPROX(res, square - (m1 * m2.transpose()));
+ if (!NumTraits<Scalar>::IsInteger && (std::min)(rows,cols)>1)
+ {
+ VERIFY(areNotApprox(res,square - m2 * m1.transpose()));
+ }
+ vcres = vc2;
+ vcres.noalias() -= m1.transpose() * v1;
+ VERIFY_IS_APPROX(vcres, vc2 - m1.transpose() * v1);
+
+ tm1 = m1;
+ VERIFY_IS_APPROX(tm1.transpose() * v1, m1.transpose() * v1);
+ VERIFY_IS_APPROX(v1.transpose() * tm1, v1.transpose() * m1);
+
+ // test submatrix and matrix/vector product
+ for (int i=0; i<rows; ++i)
+ res.row(i) = m1.row(i) * m2.transpose();
+ VERIFY_IS_APPROX(res, m1 * m2.transpose());
+ // the other way round:
+ for (int i=0; i<rows; ++i)
+ res.col(i) = m1 * m2.transpose().col(i);
+ VERIFY_IS_APPROX(res, m1 * m2.transpose());
+
+ res2 = square2;
+ res2.noalias() += m1.transpose() * m2;
+ VERIFY_IS_APPROX(res2, square2 + m1.transpose() * m2);
+ if (!NumTraits<Scalar>::IsInteger && (std::min)(rows,cols)>1)
+ {
+ VERIFY(areNotApprox(res2,square2 + m2.transpose() * m1));
+ }
+
+ VERIFY_IS_APPROX(res.col(r).noalias() = square.adjoint() * square.col(r), (square.adjoint() * square.col(r)).eval());
+ VERIFY_IS_APPROX(res.col(r).noalias() = square * square.col(r), (square * square.col(r)).eval());
+
+ // inner product
+ Scalar x = square2.row(c) * square2.col(c2);
+ VERIFY_IS_APPROX(x, square2.row(c).transpose().cwiseProduct(square2.col(c2)).sum());
+}
diff --git a/test/product_extra.cpp b/test/product_extra.cpp
new file mode 100644
index 000000000..9a6bf0792
--- /dev/null
+++ b/test/product_extra.cpp
@@ -0,0 +1,148 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra.
+//
+// Copyright (C) 2006-2008 Benoit Jacob <jacob.benoit.1@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 "main.h"
+
+template<typename MatrixType> void product_extra(const MatrixType& m)
+{
+ typedef typename MatrixType::Index Index;
+ typedef typename MatrixType::Scalar Scalar;
+ typedef typename NumTraits<Scalar>::NonInteger NonInteger;
+ typedef Matrix<Scalar, 1, Dynamic> RowVectorType;
+ typedef Matrix<Scalar, Dynamic, 1> ColVectorType;
+ typedef Matrix<Scalar, Dynamic, Dynamic,
+ MatrixType::Flags&RowMajorBit> OtherMajorMatrixType;
+
+ Index rows = m.rows();
+ Index cols = m.cols();
+
+ MatrixType m1 = MatrixType::Random(rows, cols),
+ m2 = MatrixType::Random(rows, cols),
+ m3(rows, cols),
+ mzero = MatrixType::Zero(rows, cols),
+ identity = MatrixType::Identity(rows, rows),
+ square = MatrixType::Random(rows, rows),
+ res = MatrixType::Random(rows, rows),
+ square2 = MatrixType::Random(cols, cols),
+ res2 = MatrixType::Random(cols, cols);
+ RowVectorType v1 = RowVectorType::Random(rows), vrres(rows);
+ ColVectorType vc2 = ColVectorType::Random(cols), vcres(cols);
+ OtherMajorMatrixType tm1 = m1;
+
+ Scalar s1 = internal::random<Scalar>(),
+ s2 = internal::random<Scalar>(),
+ s3 = internal::random<Scalar>();
+
+ VERIFY_IS_APPROX(m3.noalias() = m1 * m2.adjoint(), m1 * m2.adjoint().eval());
+ VERIFY_IS_APPROX(m3.noalias() = m1.adjoint() * square.adjoint(), m1.adjoint().eval() * square.adjoint().eval());
+ VERIFY_IS_APPROX(m3.noalias() = m1.adjoint() * m2, m1.adjoint().eval() * m2);
+ VERIFY_IS_APPROX(m3.noalias() = (s1 * m1.adjoint()) * m2, (s1 * m1.adjoint()).eval() * m2);
+ VERIFY_IS_APPROX(m3.noalias() = ((s1 * m1).adjoint()) * m2, (internal::conj(s1) * m1.adjoint()).eval() * m2);
+ VERIFY_IS_APPROX(m3.noalias() = (- m1.adjoint() * s1) * (s3 * m2), (- m1.adjoint() * s1).eval() * (s3 * m2).eval());
+ VERIFY_IS_APPROX(m3.noalias() = (s2 * m1.adjoint() * s1) * m2, (s2 * m1.adjoint() * s1).eval() * m2);
+ VERIFY_IS_APPROX(m3.noalias() = (-m1*s2) * s1*m2.adjoint(), (-m1*s2).eval() * (s1*m2.adjoint()).eval());
+
+ // a very tricky case where a scale factor has to be automatically conjugated:
+ VERIFY_IS_APPROX( m1.adjoint() * (s1*m2).conjugate(), (m1.adjoint()).eval() * ((s1*m2).conjugate()).eval());
+
+
+ // test all possible conjugate combinations for the four matrix-vector product cases:
+
+ VERIFY_IS_APPROX((-m1.conjugate() * s2) * (s1 * vc2),
+ (-m1.conjugate()*s2).eval() * (s1 * vc2).eval());
+ VERIFY_IS_APPROX((-m1 * s2) * (s1 * vc2.conjugate()),
+ (-m1*s2).eval() * (s1 * vc2.conjugate()).eval());
+ VERIFY_IS_APPROX((-m1.conjugate() * s2) * (s1 * vc2.conjugate()),
+ (-m1.conjugate()*s2).eval() * (s1 * vc2.conjugate()).eval());
+
+ VERIFY_IS_APPROX((s1 * vc2.transpose()) * (-m1.adjoint() * s2),
+ (s1 * vc2.transpose()).eval() * (-m1.adjoint()*s2).eval());
+ VERIFY_IS_APPROX((s1 * vc2.adjoint()) * (-m1.transpose() * s2),
+ (s1 * vc2.adjoint()).eval() * (-m1.transpose()*s2).eval());
+ VERIFY_IS_APPROX((s1 * vc2.adjoint()) * (-m1.adjoint() * s2),
+ (s1 * vc2.adjoint()).eval() * (-m1.adjoint()*s2).eval());
+
+ VERIFY_IS_APPROX((-m1.adjoint() * s2) * (s1 * v1.transpose()),
+ (-m1.adjoint()*s2).eval() * (s1 * v1.transpose()).eval());
+ VERIFY_IS_APPROX((-m1.transpose() * s2) * (s1 * v1.adjoint()),
+ (-m1.transpose()*s2).eval() * (s1 * v1.adjoint()).eval());
+ VERIFY_IS_APPROX((-m1.adjoint() * s2) * (s1 * v1.adjoint()),
+ (-m1.adjoint()*s2).eval() * (s1 * v1.adjoint()).eval());
+
+ VERIFY_IS_APPROX((s1 * v1) * (-m1.conjugate() * s2),
+ (s1 * v1).eval() * (-m1.conjugate()*s2).eval());
+ VERIFY_IS_APPROX((s1 * v1.conjugate()) * (-m1 * s2),
+ (s1 * v1.conjugate()).eval() * (-m1*s2).eval());
+ VERIFY_IS_APPROX((s1 * v1.conjugate()) * (-m1.conjugate() * s2),
+ (s1 * v1.conjugate()).eval() * (-m1.conjugate()*s2).eval());
+
+ VERIFY_IS_APPROX((-m1.adjoint() * s2) * (s1 * v1.adjoint()),
+ (-m1.adjoint()*s2).eval() * (s1 * v1.adjoint()).eval());
+
+ // test the vector-matrix product with non aligned starts
+ Index i = internal::random<Index>(0,m1.rows()-2);
+ Index j = internal::random<Index>(0,m1.cols()-2);
+ Index r = internal::random<Index>(1,m1.rows()-i);
+ Index c = internal::random<Index>(1,m1.cols()-j);
+ Index i2 = internal::random<Index>(0,m1.rows()-1);
+ Index j2 = internal::random<Index>(0,m1.cols()-1);
+
+ VERIFY_IS_APPROX(m1.col(j2).adjoint() * m1.block(0,j,m1.rows(),c), m1.col(j2).adjoint().eval() * m1.block(0,j,m1.rows(),c).eval());
+ VERIFY_IS_APPROX(m1.block(i,0,r,m1.cols()) * m1.row(i2).adjoint(), m1.block(i,0,r,m1.cols()).eval() * m1.row(i2).adjoint().eval());
+
+ // regression test
+ MatrixType tmp = m1 * m1.adjoint() * s1;
+ VERIFY_IS_APPROX(tmp, m1 * m1.adjoint() * s1);
+}
+
+// Regression test for bug reported at http://forum.kde.org/viewtopic.php?f=74&t=96947
+void mat_mat_scalar_scalar_product()
+{
+ Eigen::Matrix2Xd dNdxy(2, 3);
+ dNdxy << -0.5, 0.5, 0,
+ -0.3, 0, 0.3;
+ double det = 6.0, wt = 0.5;
+ VERIFY_IS_APPROX(dNdxy.transpose()*dNdxy*det*wt, det*wt*dNdxy.transpose()*dNdxy);
+}
+
+void zero_sized_objects()
+{
+ // Bug 127
+ //
+ // a product of the form lhs*rhs with
+ //
+ // lhs:
+ // rows = 1, cols = 4
+ // RowsAtCompileTime = 1, ColsAtCompileTime = -1
+ // MaxRowsAtCompileTime = 1, MaxColsAtCompileTime = 5
+ //
+ // rhs:
+ // rows = 4, cols = 0
+ // RowsAtCompileTime = -1, ColsAtCompileTime = -1
+ // MaxRowsAtCompileTime = 5, MaxColsAtCompileTime = 1
+ //
+ // was failing on a runtime assertion, because it had been mis-compiled as a dot product because Product.h was using the
+ // max-sizes to detect size 1 indicating vectors, and that didn't account for 0-sized object with max-size 1.
+
+ Matrix<float,1,Dynamic,RowMajor,1,5> a(1,4);
+ Matrix<float,Dynamic,Dynamic,ColMajor,5,1> b(4,0);
+ a*b;
+}
+
+void test_product_extra()
+{
+ for(int i = 0; i < g_repeat; i++) {
+ CALL_SUBTEST_1( product_extra(MatrixXf(internal::random<int>(1,EIGEN_TEST_MAX_SIZE), internal::random<int>(1,EIGEN_TEST_MAX_SIZE))) );
+ CALL_SUBTEST_2( product_extra(MatrixXd(internal::random<int>(1,EIGEN_TEST_MAX_SIZE), internal::random<int>(1,EIGEN_TEST_MAX_SIZE))) );
+ CALL_SUBTEST_2( mat_mat_scalar_scalar_product() );
+ CALL_SUBTEST_3( product_extra(MatrixXcf(internal::random<int>(1,EIGEN_TEST_MAX_SIZE/2), internal::random<int>(1,EIGEN_TEST_MAX_SIZE/2))) );
+ CALL_SUBTEST_4( product_extra(MatrixXcd(internal::random<int>(1,EIGEN_TEST_MAX_SIZE/2), internal::random<int>(1,EIGEN_TEST_MAX_SIZE/2))) );
+ CALL_SUBTEST_5( zero_sized_objects() );
+ }
+}
diff --git a/test/product_large.cpp b/test/product_large.cpp
new file mode 100644
index 000000000..03d7bd8ed
--- /dev/null
+++ b/test/product_large.cpp
@@ -0,0 +1,64 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra.
+//
+// Copyright (C) 2006-2008 Benoit Jacob <jacob.benoit.1@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 "product.h"
+
+void test_product_large()
+{
+ for(int i = 0; i < g_repeat; i++) {
+ CALL_SUBTEST_1( product(MatrixXf(internal::random<int>(1,EIGEN_TEST_MAX_SIZE), internal::random<int>(1,EIGEN_TEST_MAX_SIZE))) );
+ CALL_SUBTEST_2( product(MatrixXd(internal::random<int>(1,EIGEN_TEST_MAX_SIZE), internal::random<int>(1,EIGEN_TEST_MAX_SIZE))) );
+ CALL_SUBTEST_3( product(MatrixXi(internal::random<int>(1,EIGEN_TEST_MAX_SIZE), internal::random<int>(1,EIGEN_TEST_MAX_SIZE))) );
+ CALL_SUBTEST_4( product(MatrixXcf(internal::random<int>(1,EIGEN_TEST_MAX_SIZE/2), internal::random<int>(1,EIGEN_TEST_MAX_SIZE/2))) );
+ CALL_SUBTEST_5( product(Matrix<float,Dynamic,Dynamic,RowMajor>(internal::random<int>(1,EIGEN_TEST_MAX_SIZE), internal::random<int>(1,EIGEN_TEST_MAX_SIZE))) );
+ }
+
+#if defined EIGEN_TEST_PART_6
+ {
+ // test a specific issue in DiagonalProduct
+ int N = 1000000;
+ VectorXf v = VectorXf::Ones(N);
+ MatrixXf m = MatrixXf::Ones(N,3);
+ m = (v+v).asDiagonal() * m;
+ VERIFY_IS_APPROX(m, MatrixXf::Constant(N,3,2));
+ }
+
+ {
+ // test deferred resizing in Matrix::operator=
+ MatrixXf a = MatrixXf::Random(10,4), b = MatrixXf::Random(4,10), c = a;
+ VERIFY_IS_APPROX((a = a * b), (c * b).eval());
+ }
+
+ {
+ // check the functions to setup blocking sizes compile and do not segfault
+ // FIXME check they do what they are supposed to do !!
+ std::ptrdiff_t l1 = internal::random<int>(10000,20000);
+ std::ptrdiff_t l2 = internal::random<int>(1000000,2000000);
+ setCpuCacheSizes(l1,l2);
+ VERIFY(l1==l1CacheSize());
+ VERIFY(l2==l2CacheSize());
+ std::ptrdiff_t k1 = internal::random<int>(10,100)*16;
+ std::ptrdiff_t m1 = internal::random<int>(10,100)*16;
+ std::ptrdiff_t n1 = internal::random<int>(10,100)*16;
+ // only makes sure it compiles fine
+ internal::computeProductBlockingSizes<float,float>(k1,m1,n1);
+ }
+
+ {
+ // test regression in row-vector by matrix (bad Map type)
+ MatrixXf mat1(10,32); mat1.setRandom();
+ MatrixXf mat2(32,32); mat2.setRandom();
+ MatrixXf r1 = mat1.row(2)*mat2.transpose();
+ VERIFY_IS_APPROX(r1, (mat1.row(2)*mat2.transpose()).eval());
+
+ MatrixXf r2 = mat1.row(2)*mat2;
+ VERIFY_IS_APPROX(r2, (mat1.row(2)*mat2).eval());
+ }
+#endif
+}
diff --git a/test/product_mmtr.cpp b/test/product_mmtr.cpp
new file mode 100644
index 000000000..879cfe16a
--- /dev/null
+++ b/test/product_mmtr.cpp
@@ -0,0 +1,65 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra.
+//
+// Copyright (C) 2010 Gael Guennebaud <gael.guennebaud@inria.fr>
+//
+// This Source Code Form is subject to the terms of the Mozilla
+// Public License v. 2.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 "main.h"
+
+#define CHECK_MMTR(DEST, TRI, OP) { \
+ ref2 = ref1 = DEST; \
+ DEST.template triangularView<TRI>() OP; \
+ ref1 OP; \
+ ref2.template triangularView<TRI>() = ref1; \
+ VERIFY_IS_APPROX(DEST,ref2); \
+ }
+
+template<typename Scalar> void mmtr(int size)
+{
+ typedef typename NumTraits<Scalar>::Real RealScalar;
+
+ typedef Matrix<Scalar,Dynamic,Dynamic,ColMajor> MatrixColMaj;
+ typedef Matrix<Scalar,Dynamic,Dynamic,RowMajor> MatrixRowMaj;
+
+ DenseIndex othersize = internal::random<DenseIndex>(1,200);
+
+ MatrixColMaj matc(size, size);
+ MatrixRowMaj matr(size, size);
+ MatrixColMaj ref1(size, size), ref2(size, size);
+
+ MatrixColMaj soc(size,othersize); soc.setRandom();
+ MatrixColMaj osc(othersize,size); osc.setRandom();
+ MatrixRowMaj sor(size,othersize); sor.setRandom();
+ MatrixRowMaj osr(othersize,size); osr.setRandom();
+
+ Scalar s = internal::random<Scalar>();
+
+ CHECK_MMTR(matc, Lower, = s*soc*sor.adjoint());
+ CHECK_MMTR(matc, Upper, = s*(soc*soc.adjoint()));
+ CHECK_MMTR(matr, Lower, = s*soc*soc.adjoint());
+ CHECK_MMTR(matr, Upper, = soc*(s*sor.adjoint()));
+
+ CHECK_MMTR(matc, Lower, += s*soc*soc.adjoint());
+ CHECK_MMTR(matc, Upper, += s*(soc*sor.transpose()));
+ CHECK_MMTR(matr, Lower, += s*sor*soc.adjoint());
+ CHECK_MMTR(matr, Upper, += soc*(s*soc.adjoint()));
+
+ CHECK_MMTR(matc, Lower, -= s*soc*soc.adjoint());
+ CHECK_MMTR(matc, Upper, -= s*(osc.transpose()*osc.conjugate()));
+ CHECK_MMTR(matr, Lower, -= s*soc*soc.adjoint());
+ CHECK_MMTR(matr, Upper, -= soc*(s*soc.adjoint()));
+}
+
+void test_product_mmtr()
+{
+ for(int i = 0; i < g_repeat ; i++)
+ {
+ CALL_SUBTEST_1((mmtr<float>(internal::random<int>(1,EIGEN_TEST_MAX_SIZE))));
+ CALL_SUBTEST_2((mmtr<double>(internal::random<int>(1,EIGEN_TEST_MAX_SIZE))));
+ CALL_SUBTEST_3((mmtr<std::complex<float> >(internal::random<int>(1,EIGEN_TEST_MAX_SIZE/2))));
+ CALL_SUBTEST_4((mmtr<std::complex<double> >(internal::random<int>(1,EIGEN_TEST_MAX_SIZE/2))));
+ }
+}
diff --git a/test/product_notemporary.cpp b/test/product_notemporary.cpp
new file mode 100644
index 000000000..cf9dbdd03
--- /dev/null
+++ b/test/product_notemporary.cpp
@@ -0,0 +1,138 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra.
+//
+// Copyright (C) 2006-2008 Benoit Jacob <jacob.benoit.1@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/.
+
+static int nb_temporaries;
+
+void on_temporary_creation(int size) {
+ // here's a great place to set a breakpoint when debugging failures in this test!
+ if(size!=0) nb_temporaries++;
+}
+
+
+#define EIGEN_DENSE_STORAGE_CTOR_PLUGIN { on_temporary_creation(size); }
+
+#include "main.h"
+
+#define VERIFY_EVALUATION_COUNT(XPR,N) {\
+ nb_temporaries = 0; \
+ XPR; \
+ if(nb_temporaries!=N) std::cerr << "nb_temporaries == " << nb_temporaries << "\n"; \
+ VERIFY( (#XPR) && nb_temporaries==N ); \
+ }
+
+template<typename MatrixType> void product_notemporary(const MatrixType& m)
+{
+ /* This test checks the number of temporaries created
+ * during the evaluation of a complex expression */
+ typedef typename MatrixType::Index Index;
+ typedef typename MatrixType::Scalar Scalar;
+ typedef typename MatrixType::RealScalar RealScalar;
+ typedef Matrix<Scalar, 1, Dynamic> RowVectorType;
+ typedef Matrix<Scalar, Dynamic, 1> ColVectorType;
+ typedef Matrix<Scalar, Dynamic, Dynamic, ColMajor> ColMajorMatrixType;
+ typedef Matrix<Scalar, Dynamic, Dynamic, RowMajor> RowMajorMatrixType;
+
+ Index rows = m.rows();
+ Index cols = m.cols();
+
+ ColMajorMatrixType m1 = MatrixType::Random(rows, cols),
+ m2 = MatrixType::Random(rows, cols),
+ m3(rows, cols);
+ RowVectorType rv1 = RowVectorType::Random(rows), rvres(rows);
+ ColVectorType cv1 = ColVectorType::Random(cols), cvres(cols);
+ RowMajorMatrixType rm3(rows, cols);
+
+ Scalar s1 = internal::random<Scalar>(),
+ s2 = internal::random<Scalar>(),
+ s3 = internal::random<Scalar>();
+
+ Index c0 = internal::random<Index>(4,cols-8),
+ c1 = internal::random<Index>(8,cols-c0),
+ r0 = internal::random<Index>(4,cols-8),
+ r1 = internal::random<Index>(8,rows-r0);
+
+ VERIFY_EVALUATION_COUNT( m3 = (m1 * m2.adjoint()), 1);
+ VERIFY_EVALUATION_COUNT( m3.noalias() = m1 * m2.adjoint(), 0);
+
+ VERIFY_EVALUATION_COUNT( m3.noalias() = s1 * (m1 * m2.transpose()), 0);
+
+ VERIFY_EVALUATION_COUNT( m3.noalias() = s1 * m1 * s2 * m2.adjoint(), 0);
+ VERIFY_EVALUATION_COUNT( m3.noalias() = s1 * m1 * s2 * (m1*s3+m2*s2).adjoint(), 1);
+ VERIFY_EVALUATION_COUNT( m3.noalias() = (s1 * m1).adjoint() * s2 * m2, 0);
+ VERIFY_EVALUATION_COUNT( m3.noalias() += s1 * (-m1*s3).adjoint() * (s2 * m2 * s3), 0);
+ VERIFY_EVALUATION_COUNT( m3.noalias() -= s1 * (m1.transpose() * m2), 0);
+
+ VERIFY_EVALUATION_COUNT(( m3.block(r0,r0,r1,r1).noalias() += -m1.block(r0,c0,r1,c1) * (s2*m2.block(r0,c0,r1,c1)).adjoint() ), 0);
+ VERIFY_EVALUATION_COUNT(( m3.block(r0,r0,r1,r1).noalias() -= s1 * m1.block(r0,c0,r1,c1) * m2.block(c0,r0,c1,r1) ), 0);
+
+ // NOTE this is because the Block expression is not handled yet by our expression analyser
+ VERIFY_EVALUATION_COUNT(( m3.block(r0,r0,r1,r1).noalias() = s1 * m1.block(r0,c0,r1,c1) * (s1*m2).block(c0,r0,c1,r1) ), 1);
+
+ VERIFY_EVALUATION_COUNT( m3.noalias() -= (s1 * m1).template triangularView<Lower>() * m2, 0);
+ VERIFY_EVALUATION_COUNT( rm3.noalias() = (s1 * m1.adjoint()).template triangularView<Upper>() * (m2+m2), 1);
+ VERIFY_EVALUATION_COUNT( rm3.noalias() = (s1 * m1.adjoint()).template triangularView<UnitUpper>() * m2.adjoint(), 0);
+
+ // NOTE this is because the blas_traits require innerstride==1 to avoid a temporary, but that doesn't seem to be actually needed for the triangular products
+ VERIFY_EVALUATION_COUNT( rm3.col(c0).noalias() = (s1 * m1.adjoint()).template triangularView<UnitUpper>() * (s2*m2.row(c0)).adjoint(), 1);
+
+ VERIFY_EVALUATION_COUNT( m1.template triangularView<Lower>().solveInPlace(m3), 0);
+ VERIFY_EVALUATION_COUNT( m1.adjoint().template triangularView<Lower>().solveInPlace(m3.transpose()), 0);
+
+ VERIFY_EVALUATION_COUNT( m3.noalias() -= (s1 * m1).adjoint().template selfadjointView<Lower>() * (-m2*s3).adjoint(), 0);
+ VERIFY_EVALUATION_COUNT( m3.noalias() = s2 * m2.adjoint() * (s1 * m1.adjoint()).template selfadjointView<Upper>(), 0);
+ VERIFY_EVALUATION_COUNT( rm3.noalias() = (s1 * m1.adjoint()).template selfadjointView<Lower>() * m2.adjoint(), 0);
+
+ // NOTE this is because the blas_traits require innerstride==1 to avoid a temporary, but that doesn't seem to be actually needed for the triangular products
+ VERIFY_EVALUATION_COUNT( m3.col(c0).noalias() = (s1 * m1).adjoint().template selfadjointView<Lower>() * (-m2.row(c0)*s3).adjoint(), 1);
+ VERIFY_EVALUATION_COUNT( m3.col(c0).noalias() -= (s1 * m1).adjoint().template selfadjointView<Upper>() * (-m2.row(c0)*s3).adjoint(), 1);
+
+ VERIFY_EVALUATION_COUNT( m3.block(r0,c0,r1,c1).noalias() += m1.block(r0,r0,r1,r1).template selfadjointView<Upper>() * (s1*m2.block(r0,c0,r1,c1)), 0);
+ VERIFY_EVALUATION_COUNT( m3.block(r0,c0,r1,c1).noalias() = m1.block(r0,r0,r1,r1).template selfadjointView<Upper>() * m2.block(r0,c0,r1,c1), 0);
+
+ VERIFY_EVALUATION_COUNT( m3.template selfadjointView<Lower>().rankUpdate(m2.adjoint()), 0);
+
+ // Here we will get 1 temporary for each resize operation of the lhs operator; resize(r1,c1) would lead to zero temporaries
+ m3.resize(1,1);
+ VERIFY_EVALUATION_COUNT( m3.noalias() = m1.block(r0,r0,r1,r1).template selfadjointView<Lower>() * m2.block(r0,c0,r1,c1), 1);
+ m3.resize(1,1);
+ VERIFY_EVALUATION_COUNT( m3.noalias() = m1.block(r0,r0,r1,r1).template triangularView<UnitUpper>() * m2.block(r0,c0,r1,c1), 1);
+
+ // Zero temporaries for lazy products ...
+ VERIFY_EVALUATION_COUNT( Scalar tmp = 0; tmp += Scalar(RealScalar(1)) / (m3.transpose().lazyProduct(m3)).diagonal().sum(), 0 );
+
+ // ... and even no temporary for even deeply (>=2) nested products
+ VERIFY_EVALUATION_COUNT( Scalar tmp = 0; tmp += Scalar(RealScalar(1)) / (m3.transpose() * m3).diagonal().sum(), 0 );
+ VERIFY_EVALUATION_COUNT( Scalar tmp = 0; tmp += Scalar(RealScalar(1)) / (m3.transpose() * m3).diagonal().array().abs().sum(), 0 );
+
+ // Zero temporaries for ... CoeffBasedProductMode
+ // - does not work with GCC because of the <..>, we'ld need variadic macros ...
+ //VERIFY_EVALUATION_COUNT( m3.col(0).head<5>() * m3.col(0).transpose() + m3.col(0).head<5>() * m3.col(0).transpose(), 0 );
+
+ // Check matrix * vectors
+ VERIFY_EVALUATION_COUNT( cvres.noalias() = m1 * cv1, 0 );
+ VERIFY_EVALUATION_COUNT( cvres.noalias() -= m1 * cv1, 0 );
+ VERIFY_EVALUATION_COUNT( cvres.noalias() -= m1 * m2.col(0), 0 );
+ VERIFY_EVALUATION_COUNT( cvres.noalias() -= m1 * rv1.adjoint(), 0 );
+ VERIFY_EVALUATION_COUNT( cvres.noalias() -= m1 * m2.row(0).transpose(), 0 );
+}
+
+void test_product_notemporary()
+{
+ int s;
+ for(int i = 0; i < g_repeat; i++) {
+ s = internal::random<int>(16,EIGEN_TEST_MAX_SIZE);
+ CALL_SUBTEST_1( product_notemporary(MatrixXf(s, s)) );
+ s = internal::random<int>(16,EIGEN_TEST_MAX_SIZE);
+ CALL_SUBTEST_2( product_notemporary(MatrixXd(s, s)) );
+ s = internal::random<int>(16,EIGEN_TEST_MAX_SIZE/2);
+ CALL_SUBTEST_3( product_notemporary(MatrixXcf(s,s)) );
+ s = internal::random<int>(16,EIGEN_TEST_MAX_SIZE/2);
+ CALL_SUBTEST_4( product_notemporary(MatrixXcd(s,s)) );
+ }
+}
diff --git a/test/product_selfadjoint.cpp b/test/product_selfadjoint.cpp
new file mode 100644
index 000000000..95693b155
--- /dev/null
+++ b/test/product_selfadjoint.cpp
@@ -0,0 +1,81 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra.
+//
+// Copyright (C) 2008-2009 Gael Guennebaud <gael.guennebaud@inria.fr>
+//
+// This Source Code Form is subject to the terms of the Mozilla
+// Public License v. 2.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 "main.h"
+
+template<typename MatrixType> void product_selfadjoint(const MatrixType& m)
+{
+ typedef typename MatrixType::Index Index;
+ typedef typename MatrixType::Scalar Scalar;
+ typedef typename NumTraits<Scalar>::Real RealScalar;
+ typedef Matrix<Scalar, MatrixType::RowsAtCompileTime, 1> VectorType;
+ typedef Matrix<Scalar, 1, MatrixType::RowsAtCompileTime> RowVectorType;
+
+ typedef Matrix<Scalar, MatrixType::RowsAtCompileTime, Dynamic, RowMajor> RhsMatrixType;
+
+ Index rows = m.rows();
+ Index cols = m.cols();
+
+ MatrixType m1 = MatrixType::Random(rows, cols),
+ m2 = MatrixType::Random(rows, cols),
+ m3;
+ VectorType v1 = VectorType::Random(rows),
+ v2 = VectorType::Random(rows),
+ v3(rows);
+ RowVectorType r1 = RowVectorType::Random(rows),
+ r2 = RowVectorType::Random(rows);
+ RhsMatrixType m4 = RhsMatrixType::Random(rows,10);
+
+ Scalar s1 = internal::random<Scalar>(),
+ s2 = internal::random<Scalar>(),
+ s3 = internal::random<Scalar>();
+
+ m1 = (m1.adjoint() + m1).eval();
+
+ // rank2 update
+ m2 = m1.template triangularView<Lower>();
+ m2.template selfadjointView<Lower>().rankUpdate(v1,v2);
+ VERIFY_IS_APPROX(m2, (m1 + v1 * v2.adjoint()+ v2 * v1.adjoint()).template triangularView<Lower>().toDenseMatrix());
+
+ m2 = m1.template triangularView<Upper>();
+ m2.template selfadjointView<Upper>().rankUpdate(-v1,s2*v2,s3);
+ VERIFY_IS_APPROX(m2, (m1 + (s3*(-v1)*(s2*v2).adjoint()+internal::conj(s3)*(s2*v2)*(-v1).adjoint())).template triangularView<Upper>().toDenseMatrix());
+
+ m2 = m1.template triangularView<Upper>();
+ m2.template selfadjointView<Upper>().rankUpdate(-s2*r1.adjoint(),r2.adjoint()*s3,s1);
+ VERIFY_IS_APPROX(m2, (m1 + s1*(-s2*r1.adjoint())*(r2.adjoint()*s3).adjoint() + internal::conj(s1)*(r2.adjoint()*s3) * (-s2*r1.adjoint()).adjoint()).template triangularView<Upper>().toDenseMatrix());
+
+ if (rows>1)
+ {
+ m2 = m1.template triangularView<Lower>();
+ m2.block(1,1,rows-1,cols-1).template selfadjointView<Lower>().rankUpdate(v1.tail(rows-1),v2.head(cols-1));
+ m3 = m1;
+ m3.block(1,1,rows-1,cols-1) += v1.tail(rows-1) * v2.head(cols-1).adjoint()+ v2.head(cols-1) * v1.tail(rows-1).adjoint();
+ VERIFY_IS_APPROX(m2, m3.template triangularView<Lower>().toDenseMatrix());
+ }
+}
+
+void test_product_selfadjoint()
+{
+ int s;
+ for(int i = 0; i < g_repeat ; i++) {
+ CALL_SUBTEST_1( product_selfadjoint(Matrix<float, 1, 1>()) );
+ CALL_SUBTEST_2( product_selfadjoint(Matrix<float, 2, 2>()) );
+ CALL_SUBTEST_3( product_selfadjoint(Matrix3d()) );
+ s = internal::random<int>(1,EIGEN_TEST_MAX_SIZE/2);
+ CALL_SUBTEST_4( product_selfadjoint(MatrixXcf(s, s)) );
+ s = internal::random<int>(1,EIGEN_TEST_MAX_SIZE/2);
+ CALL_SUBTEST_5( product_selfadjoint(MatrixXcd(s,s)) );
+ s = internal::random<int>(1,EIGEN_TEST_MAX_SIZE);
+ CALL_SUBTEST_6( product_selfadjoint(MatrixXd(s,s)) );
+ s = internal::random<int>(1,EIGEN_TEST_MAX_SIZE);
+ CALL_SUBTEST_7( product_selfadjoint(Matrix<float,Dynamic,Dynamic,RowMajor>(s,s)) );
+ }
+ EIGEN_UNUSED_VARIABLE(s)
+}
diff --git a/test/product_small.cpp b/test/product_small.cpp
new file mode 100644
index 000000000..8b132abb6
--- /dev/null
+++ b/test/product_small.cpp
@@ -0,0 +1,50 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra.
+//
+// Copyright (C) 2006-2008 Benoit Jacob <jacob.benoit.1@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/.
+
+#define EIGEN_NO_STATIC_ASSERT
+#include "product.h"
+
+// regression test for bug 447
+void product1x1()
+{
+ Matrix<float,1,3> matAstatic;
+ Matrix<float,3,1> matBstatic;
+ matAstatic.setRandom();
+ matBstatic.setRandom();
+ VERIFY_IS_APPROX( (matAstatic * matBstatic).coeff(0,0),
+ matAstatic.cwiseProduct(matBstatic.transpose()).sum() );
+
+ MatrixXf matAdynamic(1,3);
+ MatrixXf matBdynamic(3,1);
+ matAdynamic.setRandom();
+ matBdynamic.setRandom();
+ VERIFY_IS_APPROX( (matAdynamic * matBdynamic).coeff(0,0),
+ matAdynamic.cwiseProduct(matBdynamic.transpose()).sum() );
+}
+
+
+void test_product_small()
+{
+ for(int i = 0; i < g_repeat; i++) {
+ CALL_SUBTEST_1( product(Matrix<float, 3, 2>()) );
+ CALL_SUBTEST_2( product(Matrix<int, 3, 5>()) );
+ CALL_SUBTEST_3( product(Matrix3d()) );
+ CALL_SUBTEST_4( product(Matrix4d()) );
+ CALL_SUBTEST_5( product(Matrix4f()) );
+ CALL_SUBTEST_6( product1x1() );
+ }
+
+#ifdef EIGEN_TEST_PART_6
+ {
+ // test compilation of (outer_product) * vector
+ Vector3f v = Vector3f::Random();
+ VERIFY_IS_APPROX( (v * v.transpose()) * v, (v * v.transpose()).eval() * v);
+ }
+#endif
+}
diff --git a/test/product_symm.cpp b/test/product_symm.cpp
new file mode 100644
index 000000000..2f7a0d231
--- /dev/null
+++ b/test/product_symm.cpp
@@ -0,0 +1,96 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra.
+//
+// Copyright (C) 2008-2009 Gael Guennebaud <gael.guennebaud@inria.fr>
+//
+// This Source Code Form is subject to the terms of the Mozilla
+// Public License v. 2.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 "main.h"
+
+template<typename Scalar, int Size, int OtherSize> void symm(int size = Size, int othersize = OtherSize)
+{
+ typedef typename NumTraits<Scalar>::Real RealScalar;
+
+ typedef Matrix<Scalar, Size, Size> MatrixType;
+ typedef Matrix<Scalar, Size, OtherSize> Rhs1;
+ typedef Matrix<Scalar, OtherSize, Size> Rhs2;
+ enum { order = OtherSize==1 ? 0 : RowMajor };
+ typedef Matrix<Scalar, Size, OtherSize,order> Rhs3;
+ typedef typename MatrixType::Index Index;
+
+ Index rows = size;
+ Index cols = size;
+
+ MatrixType m1 = MatrixType::Random(rows, cols),
+ m2 = MatrixType::Random(rows, cols), m3;
+
+ m1 = (m1+m1.adjoint()).eval();
+
+ Rhs1 rhs1 = Rhs1::Random(cols, othersize), rhs12(cols, othersize), rhs13(cols, othersize);
+ Rhs2 rhs2 = Rhs2::Random(othersize, rows), rhs22(othersize, rows), rhs23(othersize, rows);
+ Rhs3 rhs3 = Rhs3::Random(cols, othersize), rhs32(cols, othersize), rhs33(cols, othersize);
+
+ Scalar s1 = internal::random<Scalar>(),
+ s2 = internal::random<Scalar>();
+
+ m2 = m1.template triangularView<Lower>();
+ m3 = m2.template selfadjointView<Lower>();
+ VERIFY_IS_EQUAL(m1, m3);
+ VERIFY_IS_APPROX(rhs12 = (s1*m2).template selfadjointView<Lower>() * (s2*rhs1),
+ rhs13 = (s1*m1) * (s2*rhs1));
+
+ m2 = m1.template triangularView<Upper>(); rhs12.setRandom(); rhs13 = rhs12;
+ m3 = m2.template selfadjointView<Upper>();
+ VERIFY_IS_EQUAL(m1, m3);
+ VERIFY_IS_APPROX(rhs12 += (s1*m2).template selfadjointView<Upper>() * (s2*rhs1),
+ rhs13 += (s1*m1) * (s2*rhs1));
+
+ m2 = m1.template triangularView<Lower>();
+ VERIFY_IS_APPROX(rhs12 = (s1*m2).template selfadjointView<Lower>() * (s2*rhs2.adjoint()),
+ rhs13 = (s1*m1) * (s2*rhs2.adjoint()));
+
+ m2 = m1.template triangularView<Upper>();
+ VERIFY_IS_APPROX(rhs12 = (s1*m2).template selfadjointView<Upper>() * (s2*rhs2.adjoint()),
+ rhs13 = (s1*m1) * (s2*rhs2.adjoint()));
+
+ m2 = m1.template triangularView<Upper>();
+ VERIFY_IS_APPROX(rhs12 = (s1*m2.adjoint()).template selfadjointView<Lower>() * (s2*rhs2.adjoint()),
+ rhs13 = (s1*m1.adjoint()) * (s2*rhs2.adjoint()));
+
+ // test row major = <...>
+ m2 = m1.template triangularView<Lower>(); rhs12.setRandom(); rhs13 = rhs12;
+ VERIFY_IS_APPROX(rhs12 -= (s1*m2).template selfadjointView<Lower>() * (s2*rhs3),
+ rhs13 -= (s1*m1) * (s2 * rhs3));
+
+ m2 = m1.template triangularView<Upper>();
+ VERIFY_IS_APPROX(rhs12 = (s1*m2.adjoint()).template selfadjointView<Lower>() * (s2*rhs3).conjugate(),
+ rhs13 = (s1*m1.adjoint()) * (s2*rhs3).conjugate());
+
+
+ m2 = m1.template triangularView<Upper>(); rhs13 = rhs12;
+ VERIFY_IS_APPROX(rhs12.noalias() += s1 * ((m2.adjoint()).template selfadjointView<Lower>() * (s2*rhs3).conjugate()),
+ rhs13 += (s1*m1.adjoint()) * (s2*rhs3).conjugate());
+
+ m2 = m1.template triangularView<Lower>();
+ VERIFY_IS_APPROX(rhs22 = (rhs2) * (m2).template selfadjointView<Lower>(), rhs23 = (rhs2) * (m1));
+ VERIFY_IS_APPROX(rhs22 = (s2*rhs2) * (s1*m2).template selfadjointView<Lower>(), rhs23 = (s2*rhs2) * (s1*m1));
+
+}
+
+void test_product_symm()
+{
+ for(int i = 0; i < g_repeat ; i++)
+ {
+ CALL_SUBTEST_1(( symm<float,Dynamic,Dynamic>(internal::random<int>(1,EIGEN_TEST_MAX_SIZE),internal::random<int>(1,EIGEN_TEST_MAX_SIZE)) ));
+ CALL_SUBTEST_2(( symm<double,Dynamic,Dynamic>(internal::random<int>(1,EIGEN_TEST_MAX_SIZE),internal::random<int>(1,EIGEN_TEST_MAX_SIZE)) ));
+ CALL_SUBTEST_3(( symm<std::complex<float>,Dynamic,Dynamic>(internal::random<int>(1,EIGEN_TEST_MAX_SIZE/2),internal::random<int>(1,EIGEN_TEST_MAX_SIZE/2)) ));
+ CALL_SUBTEST_4(( symm<std::complex<double>,Dynamic,Dynamic>(internal::random<int>(1,EIGEN_TEST_MAX_SIZE/2),internal::random<int>(1,EIGEN_TEST_MAX_SIZE/2)) ));
+
+ CALL_SUBTEST_5(( symm<float,Dynamic,1>(internal::random<int>(1,EIGEN_TEST_MAX_SIZE)) ));
+ CALL_SUBTEST_6(( symm<double,Dynamic,1>(internal::random<int>(1,EIGEN_TEST_MAX_SIZE)) ));
+ CALL_SUBTEST_7(( symm<std::complex<float>,Dynamic,1>(internal::random<int>(1,EIGEN_TEST_MAX_SIZE)) ));
+ CALL_SUBTEST_8(( symm<std::complex<double>,Dynamic,1>(internal::random<int>(1,EIGEN_TEST_MAX_SIZE)) ));
+ }
+}
diff --git a/test/product_syrk.cpp b/test/product_syrk.cpp
new file mode 100644
index 000000000..5855c2181
--- /dev/null
+++ b/test/product_syrk.cpp
@@ -0,0 +1,98 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra.
+//
+// Copyright (C) 2008-2009 Gael Guennebaud <gael.guennebaud@inria.fr>
+//
+// This Source Code Form is subject to the terms of the Mozilla
+// Public License v. 2.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 "main.h"
+
+template<typename MatrixType> void syrk(const MatrixType& m)
+{
+ typedef typename MatrixType::Index Index;
+ typedef typename MatrixType::Scalar Scalar;
+ typedef typename NumTraits<Scalar>::Real RealScalar;
+ typedef Matrix<Scalar, MatrixType::ColsAtCompileTime, Dynamic> Rhs1;
+ typedef Matrix<Scalar, Dynamic, MatrixType::RowsAtCompileTime> Rhs2;
+ typedef Matrix<Scalar, MatrixType::ColsAtCompileTime, Dynamic,RowMajor> Rhs3;
+
+ Index rows = m.rows();
+ Index cols = m.cols();
+
+ MatrixType m1 = MatrixType::Random(rows, cols),
+ m2 = MatrixType::Random(rows, cols);
+
+ Rhs1 rhs1 = Rhs1::Random(internal::random<int>(1,320), cols);
+ Rhs2 rhs2 = Rhs2::Random(rows, internal::random<int>(1,320));
+ Rhs3 rhs3 = Rhs3::Random(internal::random<int>(1,320), rows);
+
+ Scalar s1 = internal::random<Scalar>();
+
+ Index c = internal::random<Index>(0,cols-1);
+
+ m2.setZero();
+ VERIFY_IS_APPROX((m2.template selfadjointView<Lower>().rankUpdate(rhs2,s1)._expression()),
+ ((s1 * rhs2 * rhs2.adjoint()).eval().template triangularView<Lower>().toDenseMatrix()));
+
+ m2.setZero();
+ VERIFY_IS_APPROX(m2.template selfadjointView<Upper>().rankUpdate(rhs2,s1)._expression(),
+ (s1 * rhs2 * rhs2.adjoint()).eval().template triangularView<Upper>().toDenseMatrix());
+
+ m2.setZero();
+ VERIFY_IS_APPROX(m2.template selfadjointView<Lower>().rankUpdate(rhs1.adjoint(),s1)._expression(),
+ (s1 * rhs1.adjoint() * rhs1).eval().template triangularView<Lower>().toDenseMatrix());
+
+ m2.setZero();
+ VERIFY_IS_APPROX(m2.template selfadjointView<Upper>().rankUpdate(rhs1.adjoint(),s1)._expression(),
+ (s1 * rhs1.adjoint() * rhs1).eval().template triangularView<Upper>().toDenseMatrix());
+
+ m2.setZero();
+ VERIFY_IS_APPROX(m2.template selfadjointView<Lower>().rankUpdate(rhs3.adjoint(),s1)._expression(),
+ (s1 * rhs3.adjoint() * rhs3).eval().template triangularView<Lower>().toDenseMatrix());
+
+ m2.setZero();
+ VERIFY_IS_APPROX(m2.template selfadjointView<Upper>().rankUpdate(rhs3.adjoint(),s1)._expression(),
+ (s1 * rhs3.adjoint() * rhs3).eval().template triangularView<Upper>().toDenseMatrix());
+
+ m2.setZero();
+ VERIFY_IS_APPROX((m2.template selfadjointView<Lower>().rankUpdate(m1.col(c),s1)._expression()),
+ ((s1 * m1.col(c) * m1.col(c).adjoint()).eval().template triangularView<Lower>().toDenseMatrix()));
+
+ m2.setZero();
+ VERIFY_IS_APPROX((m2.template selfadjointView<Upper>().rankUpdate(m1.col(c),s1)._expression()),
+ ((s1 * m1.col(c) * m1.col(c).adjoint()).eval().template triangularView<Upper>().toDenseMatrix()));
+
+ m2.setZero();
+ VERIFY_IS_APPROX((m2.template selfadjointView<Lower>().rankUpdate(m1.col(c).conjugate(),s1)._expression()),
+ ((s1 * m1.col(c).conjugate() * m1.col(c).conjugate().adjoint()).eval().template triangularView<Lower>().toDenseMatrix()));
+
+ m2.setZero();
+ VERIFY_IS_APPROX((m2.template selfadjointView<Upper>().rankUpdate(m1.col(c).conjugate(),s1)._expression()),
+ ((s1 * m1.col(c).conjugate() * m1.col(c).conjugate().adjoint()).eval().template triangularView<Upper>().toDenseMatrix()));
+
+ m2.setZero();
+ VERIFY_IS_APPROX((m2.template selfadjointView<Lower>().rankUpdate(m1.row(c),s1)._expression()),
+ ((s1 * m1.row(c).transpose() * m1.row(c).transpose().adjoint()).eval().template triangularView<Lower>().toDenseMatrix()));
+
+ m2.setZero();
+ VERIFY_IS_APPROX((m2.template selfadjointView<Upper>().rankUpdate(m1.row(c).adjoint(),s1)._expression()),
+ ((s1 * m1.row(c).adjoint() * m1.row(c).adjoint().adjoint()).eval().template triangularView<Upper>().toDenseMatrix()));
+}
+
+void test_product_syrk()
+{
+ for(int i = 0; i < g_repeat ; i++)
+ {
+ int s;
+ s = internal::random<int>(1,EIGEN_TEST_MAX_SIZE);
+ CALL_SUBTEST_1( syrk(MatrixXf(s, s)) );
+ s = internal::random<int>(1,EIGEN_TEST_MAX_SIZE);
+ CALL_SUBTEST_2( syrk(MatrixXd(s, s)) );
+ s = internal::random<int>(1,EIGEN_TEST_MAX_SIZE/2);
+ CALL_SUBTEST_3( syrk(MatrixXcf(s, s)) );
+ s = internal::random<int>(1,EIGEN_TEST_MAX_SIZE/2);
+ CALL_SUBTEST_4( syrk(MatrixXcd(s, s)) );
+ }
+}
diff --git a/test/product_trmm.cpp b/test/product_trmm.cpp
new file mode 100644
index 000000000..64244c18f
--- /dev/null
+++ b/test/product_trmm.cpp
@@ -0,0 +1,108 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra.
+//
+// Copyright (C) 2008-2009 Gael Guennebaud <gael.guennebaud@inria.fr>
+//
+// This Source Code Form is subject to the terms of the Mozilla
+// Public License v. 2.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 "main.h"
+
+template<typename Scalar, int Mode, int TriOrder, int OtherOrder, int ResOrder, int OtherCols>
+void trmm(int rows=internal::random<int>(1,EIGEN_TEST_MAX_SIZE),
+ int cols=internal::random<int>(1,EIGEN_TEST_MAX_SIZE),
+ int otherCols = OtherCols==Dynamic?internal::random<int>(1,EIGEN_TEST_MAX_SIZE):OtherCols)
+{
+ typedef typename NumTraits<Scalar>::Real RealScalar;
+
+ typedef Matrix<Scalar,Dynamic,Dynamic,TriOrder> TriMatrix;
+ typedef Matrix<Scalar,Dynamic,OtherCols,OtherCols==1?ColMajor:OtherOrder> OnTheRight;
+ typedef Matrix<Scalar,OtherCols,Dynamic,OtherCols==1?RowMajor:OtherOrder> OnTheLeft;
+
+ typedef Matrix<Scalar,Dynamic,OtherCols,OtherCols==1?ColMajor:ResOrder> ResXS;
+ typedef Matrix<Scalar,OtherCols,Dynamic,OtherCols==1?RowMajor:ResOrder> ResSX;
+
+ TriMatrix mat(rows,cols), tri(rows,cols), triTr(cols,rows);
+
+ OnTheRight ge_right(cols,otherCols);
+ OnTheLeft ge_left(otherCols,rows);
+ ResSX ge_sx, ge_sx_save;
+ ResXS ge_xs, ge_xs_save;
+
+ Scalar s1 = internal::random<Scalar>(),
+ s2 = internal::random<Scalar>();
+
+ mat.setRandom();
+ tri = mat.template triangularView<Mode>();
+ triTr = mat.transpose().template triangularView<Mode>();
+ ge_right.setRandom();
+ ge_left.setRandom();
+
+ VERIFY_IS_APPROX( ge_xs = mat.template triangularView<Mode>() * ge_right, tri * ge_right);
+ VERIFY_IS_APPROX( ge_sx = ge_left * mat.template triangularView<Mode>(), ge_left * tri);
+
+ VERIFY_IS_APPROX( ge_xs.noalias() = mat.template triangularView<Mode>() * ge_right, tri * ge_right);
+ VERIFY_IS_APPROX( ge_sx.noalias() = ge_left * mat.template triangularView<Mode>(), ge_left * tri);
+
+ VERIFY_IS_APPROX( ge_xs.noalias() = (s1*mat.adjoint()).template triangularView<Mode>() * (s2*ge_left.transpose()), s1*triTr.conjugate() * (s2*ge_left.transpose()));
+ VERIFY_IS_APPROX( ge_sx.noalias() = ge_right.transpose() * mat.adjoint().template triangularView<Mode>(), ge_right.transpose() * triTr.conjugate());
+
+ VERIFY_IS_APPROX( ge_xs.noalias() = (s1*mat.adjoint()).template triangularView<Mode>() * (s2*ge_left.adjoint()), s1*triTr.conjugate() * (s2*ge_left.adjoint()));
+ VERIFY_IS_APPROX( ge_sx.noalias() = ge_right.adjoint() * mat.adjoint().template triangularView<Mode>(), ge_right.adjoint() * triTr.conjugate());
+
+ ge_xs_save = ge_xs;
+ VERIFY_IS_APPROX( (ge_xs_save + s1*triTr.conjugate() * (s2*ge_left.adjoint())).eval(), ge_xs.noalias() += (s1*mat.adjoint()).template triangularView<Mode>() * (s2*ge_left.adjoint()) );
+ ge_sx_save = ge_sx;
+ VERIFY_IS_APPROX( ge_sx_save - (ge_right.adjoint() * (-s1 * triTr).conjugate()).eval(), ge_sx.noalias() -= (ge_right.adjoint() * (-s1 * mat).adjoint().template triangularView<Mode>()).eval());
+
+ VERIFY_IS_APPROX( ge_xs = (s1*mat).adjoint().template triangularView<Mode>() * ge_left.adjoint(), internal::conj(s1) * triTr.conjugate() * ge_left.adjoint());
+
+ // TODO check with sub-matrix expressions ?
+}
+
+template<typename Scalar, int Mode, int TriOrder>
+void trmv(int rows=internal::random<int>(1,EIGEN_TEST_MAX_SIZE), int cols=internal::random<int>(1,EIGEN_TEST_MAX_SIZE))
+{
+ trmm<Scalar,Mode,TriOrder,ColMajor,ColMajor,1>(rows,cols,1);
+}
+
+template<typename Scalar, int Mode, int TriOrder, int OtherOrder, int ResOrder>
+void trmm(int rows=internal::random<int>(1,EIGEN_TEST_MAX_SIZE), int cols=internal::random<int>(1,EIGEN_TEST_MAX_SIZE), int otherCols = internal::random<int>(1,EIGEN_TEST_MAX_SIZE))
+{
+ trmm<Scalar,Mode,TriOrder,OtherOrder,ResOrder,Dynamic>(rows,cols,otherCols);
+}
+
+#define CALL_ALL_ORDERS(NB,SCALAR,MODE) \
+ EIGEN_CAT(CALL_SUBTEST_,NB)((trmm<SCALAR, MODE, ColMajor,ColMajor,ColMajor>())); \
+ EIGEN_CAT(CALL_SUBTEST_,NB)((trmm<SCALAR, MODE, ColMajor,ColMajor,RowMajor>())); \
+ EIGEN_CAT(CALL_SUBTEST_,NB)((trmm<SCALAR, MODE, ColMajor,RowMajor,ColMajor>())); \
+ EIGEN_CAT(CALL_SUBTEST_,NB)((trmm<SCALAR, MODE, ColMajor,RowMajor,RowMajor>())); \
+ EIGEN_CAT(CALL_SUBTEST_,NB)((trmm<SCALAR, MODE, RowMajor,ColMajor,ColMajor>())); \
+ EIGEN_CAT(CALL_SUBTEST_,NB)((trmm<SCALAR, MODE, RowMajor,ColMajor,RowMajor>())); \
+ EIGEN_CAT(CALL_SUBTEST_,NB)((trmm<SCALAR, MODE, RowMajor,RowMajor,ColMajor>())); \
+ EIGEN_CAT(CALL_SUBTEST_,NB)((trmm<SCALAR, MODE, RowMajor,RowMajor,RowMajor>())); \
+ \
+ EIGEN_CAT(CALL_SUBTEST_1,NB)((trmv<SCALAR, MODE, ColMajor>())); \
+ EIGEN_CAT(CALL_SUBTEST_1,NB)((trmv<SCALAR, MODE, RowMajor>()));
+
+
+#define CALL_ALL(NB,SCALAR) \
+ CALL_ALL_ORDERS(EIGEN_CAT(1,NB),SCALAR,Upper) \
+ CALL_ALL_ORDERS(EIGEN_CAT(2,NB),SCALAR,UnitUpper) \
+ CALL_ALL_ORDERS(EIGEN_CAT(3,NB),SCALAR,StrictlyUpper) \
+ CALL_ALL_ORDERS(EIGEN_CAT(1,NB),SCALAR,Lower) \
+ CALL_ALL_ORDERS(EIGEN_CAT(2,NB),SCALAR,UnitLower) \
+ CALL_ALL_ORDERS(EIGEN_CAT(3,NB),SCALAR,StrictlyLower)
+
+
+void test_product_trmm()
+{
+ for(int i = 0; i < g_repeat ; i++)
+ {
+ CALL_ALL(1,float); // EIGEN_SUFFIXES;11;111;21;121;31;131
+ CALL_ALL(2,double); // EIGEN_SUFFIXES;12;112;22;122;32;132
+ CALL_ALL(3,std::complex<float>); // EIGEN_SUFFIXES;13;113;23;123;33;133
+ CALL_ALL(4,std::complex<double>); // EIGEN_SUFFIXES;14;114;24;124;34;134
+ }
+}
diff --git a/test/product_trmv.cpp b/test/product_trmv.cpp
new file mode 100644
index 000000000..435018e8e
--- /dev/null
+++ b/test/product_trmv.cpp
@@ -0,0 +1,89 @@
+// This file is triangularView of Eigen, a lightweight C++ template library
+// for linear algebra.
+//
+// Copyright (C) 2008-2009 Gael Guennebaud <gael.guennebaud@inria.fr>
+//
+// This Source Code Form is subject to the terms of the Mozilla
+// Public License v. 2.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 "main.h"
+
+template<typename MatrixType> void trmv(const MatrixType& m)
+{
+ typedef typename MatrixType::Index Index;
+ typedef typename MatrixType::Scalar Scalar;
+ typedef typename NumTraits<Scalar>::Real RealScalar;
+ typedef Matrix<Scalar, MatrixType::RowsAtCompileTime, 1> VectorType;
+
+ RealScalar largerEps = 10*test_precision<RealScalar>();
+
+ Index rows = m.rows();
+ Index cols = m.cols();
+
+ MatrixType m1 = MatrixType::Random(rows, cols),
+ m3(rows, cols);
+ VectorType v1 = VectorType::Random(rows);
+
+ Scalar s1 = internal::random<Scalar>();
+
+ m1 = MatrixType::Random(rows, cols);
+
+ // check with a column-major matrix
+ m3 = m1.template triangularView<Eigen::Lower>();
+ VERIFY((m3 * v1).isApprox(m1.template triangularView<Eigen::Lower>() * v1, largerEps));
+ m3 = m1.template triangularView<Eigen::Upper>();
+ VERIFY((m3 * v1).isApprox(m1.template triangularView<Eigen::Upper>() * v1, largerEps));
+ m3 = m1.template triangularView<Eigen::UnitLower>();
+ VERIFY((m3 * v1).isApprox(m1.template triangularView<Eigen::UnitLower>() * v1, largerEps));
+ m3 = m1.template triangularView<Eigen::UnitUpper>();
+ VERIFY((m3 * v1).isApprox(m1.template triangularView<Eigen::UnitUpper>() * v1, largerEps));
+
+ // check conjugated and scalar multiple expressions (col-major)
+ m3 = m1.template triangularView<Eigen::Lower>();
+ VERIFY(((s1*m3).conjugate() * v1).isApprox((s1*m1).conjugate().template triangularView<Eigen::Lower>() * v1, largerEps));
+ m3 = m1.template triangularView<Eigen::Upper>();
+ VERIFY((m3.conjugate() * v1.conjugate()).isApprox(m1.conjugate().template triangularView<Eigen::Upper>() * v1.conjugate(), largerEps));
+
+ // check with a row-major matrix
+ m3 = m1.template triangularView<Eigen::Upper>();
+ VERIFY((m3.transpose() * v1).isApprox(m1.transpose().template triangularView<Eigen::Lower>() * v1, largerEps));
+ m3 = m1.template triangularView<Eigen::Lower>();
+ VERIFY((m3.transpose() * v1).isApprox(m1.transpose().template triangularView<Eigen::Upper>() * v1, largerEps));
+ m3 = m1.template triangularView<Eigen::UnitUpper>();
+ VERIFY((m3.transpose() * v1).isApprox(m1.transpose().template triangularView<Eigen::UnitLower>() * v1, largerEps));
+ m3 = m1.template triangularView<Eigen::UnitLower>();
+ VERIFY((m3.transpose() * v1).isApprox(m1.transpose().template triangularView<Eigen::UnitUpper>() * v1, largerEps));
+
+ // check conjugated and scalar multiple expressions (row-major)
+ m3 = m1.template triangularView<Eigen::Upper>();
+ VERIFY((m3.adjoint() * v1).isApprox(m1.adjoint().template triangularView<Eigen::Lower>() * v1, largerEps));
+ m3 = m1.template triangularView<Eigen::Lower>();
+ VERIFY((m3.adjoint() * (s1*v1.conjugate())).isApprox(m1.adjoint().template triangularView<Eigen::Upper>() * (s1*v1.conjugate()), largerEps));
+ m3 = m1.template triangularView<Eigen::UnitUpper>();
+
+ // check transposed cases:
+ m3 = m1.template triangularView<Eigen::Lower>();
+ VERIFY((v1.transpose() * m3).isApprox(v1.transpose() * m1.template triangularView<Eigen::Lower>(), largerEps));
+ VERIFY((v1.adjoint() * m3).isApprox(v1.adjoint() * m1.template triangularView<Eigen::Lower>(), largerEps));
+ VERIFY((v1.adjoint() * m3.adjoint()).isApprox(v1.adjoint() * m1.template triangularView<Eigen::Lower>().adjoint(), largerEps));
+
+ // TODO check with sub-matrices
+}
+
+void test_product_trmv()
+{
+ int s;
+ for(int i = 0; i < g_repeat ; i++) {
+ CALL_SUBTEST_1( trmv(Matrix<float, 1, 1>()) );
+ CALL_SUBTEST_2( trmv(Matrix<float, 2, 2>()) );
+ CALL_SUBTEST_3( trmv(Matrix3d()) );
+ s = internal::random<int>(1,EIGEN_TEST_MAX_SIZE/2);
+ CALL_SUBTEST_4( trmv(MatrixXcf(s,s)) );
+ s = internal::random<int>(1,EIGEN_TEST_MAX_SIZE/2);
+ CALL_SUBTEST_5( trmv(MatrixXcd(s,s)) );
+ s = internal::random<int>(1,EIGEN_TEST_MAX_SIZE);
+ CALL_SUBTEST_6( trmv(Matrix<float,Dynamic,Dynamic,RowMajor>(s, s)) );
+ }
+ EIGEN_UNUSED_VARIABLE(s);
+}
diff --git a/test/product_trsolve.cpp b/test/product_trsolve.cpp
new file mode 100644
index 000000000..69892b3a8
--- /dev/null
+++ b/test/product_trsolve.cpp
@@ -0,0 +1,93 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra.
+//
+// Copyright (C) 2008-2009 Gael Guennebaud <gael.guennebaud@inria.fr>
+//
+// This Source Code Form is subject to the terms of the Mozilla
+// Public License v. 2.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 "main.h"
+
+#define VERIFY_TRSM(TRI,XB) { \
+ (XB).setRandom(); ref = (XB); \
+ (TRI).solveInPlace(XB); \
+ VERIFY_IS_APPROX((TRI).toDenseMatrix() * (XB), ref); \
+ (XB).setRandom(); ref = (XB); \
+ (XB) = (TRI).solve(XB); \
+ VERIFY_IS_APPROX((TRI).toDenseMatrix() * (XB), ref); \
+ }
+
+#define VERIFY_TRSM_ONTHERIGHT(TRI,XB) { \
+ (XB).setRandom(); ref = (XB); \
+ (TRI).transpose().template solveInPlace<OnTheRight>(XB.transpose()); \
+ VERIFY_IS_APPROX((XB).transpose() * (TRI).transpose().toDenseMatrix(), ref.transpose()); \
+ (XB).setRandom(); ref = (XB); \
+ (XB).transpose() = (TRI).transpose().template solve<OnTheRight>(XB.transpose()); \
+ VERIFY_IS_APPROX((XB).transpose() * (TRI).transpose().toDenseMatrix(), ref.transpose()); \
+ }
+
+template<typename Scalar,int Size, int Cols> void trsolve(int size=Size,int cols=Cols)
+{
+ typedef typename NumTraits<Scalar>::Real RealScalar;
+
+ Matrix<Scalar,Size,Size,ColMajor> cmLhs(size,size);
+ Matrix<Scalar,Size,Size,RowMajor> rmLhs(size,size);
+
+ enum { colmajor = Size==1 ? RowMajor : ColMajor,
+ rowmajor = Cols==1 ? ColMajor : RowMajor };
+ Matrix<Scalar,Size,Cols,colmajor> cmRhs(size,cols);
+ Matrix<Scalar,Size,Cols,rowmajor> rmRhs(size,cols);
+ Matrix<Scalar,Dynamic,Dynamic,colmajor> ref(size,cols);
+
+ cmLhs.setRandom(); cmLhs *= static_cast<RealScalar>(0.1); cmLhs.diagonal().array() += static_cast<RealScalar>(1);
+ rmLhs.setRandom(); rmLhs *= static_cast<RealScalar>(0.1); rmLhs.diagonal().array() += static_cast<RealScalar>(1);
+
+ VERIFY_TRSM(cmLhs.conjugate().template triangularView<Lower>(), cmRhs);
+ VERIFY_TRSM(cmLhs.adjoint() .template triangularView<Lower>(), cmRhs);
+ VERIFY_TRSM(cmLhs .template triangularView<Upper>(), cmRhs);
+ VERIFY_TRSM(cmLhs .template triangularView<Lower>(), rmRhs);
+ VERIFY_TRSM(cmLhs.conjugate().template triangularView<Upper>(), rmRhs);
+ VERIFY_TRSM(cmLhs.adjoint() .template triangularView<Upper>(), rmRhs);
+
+ VERIFY_TRSM(cmLhs.conjugate().template triangularView<UnitLower>(), cmRhs);
+ VERIFY_TRSM(cmLhs .template triangularView<UnitUpper>(), rmRhs);
+
+ VERIFY_TRSM(rmLhs .template triangularView<Lower>(), cmRhs);
+ VERIFY_TRSM(rmLhs.conjugate().template triangularView<UnitUpper>(), rmRhs);
+
+
+ VERIFY_TRSM_ONTHERIGHT(cmLhs.conjugate().template triangularView<Lower>(), cmRhs);
+ VERIFY_TRSM_ONTHERIGHT(cmLhs .template triangularView<Upper>(), cmRhs);
+ VERIFY_TRSM_ONTHERIGHT(cmLhs .template triangularView<Lower>(), rmRhs);
+ VERIFY_TRSM_ONTHERIGHT(cmLhs.conjugate().template triangularView<Upper>(), rmRhs);
+
+ VERIFY_TRSM_ONTHERIGHT(cmLhs.conjugate().template triangularView<UnitLower>(), cmRhs);
+ VERIFY_TRSM_ONTHERIGHT(cmLhs .template triangularView<UnitUpper>(), rmRhs);
+
+ VERIFY_TRSM_ONTHERIGHT(rmLhs .template triangularView<Lower>(), cmRhs);
+ VERIFY_TRSM_ONTHERIGHT(rmLhs.conjugate().template triangularView<UnitUpper>(), rmRhs);
+
+ int c = internal::random<int>(0,cols-1);
+ VERIFY_TRSM(rmLhs.template triangularView<Lower>(), rmRhs.col(c));
+ VERIFY_TRSM(cmLhs.template triangularView<Lower>(), rmRhs.col(c));
+}
+
+void test_product_trsolve()
+{
+ for(int i = 0; i < g_repeat ; i++)
+ {
+ // matrices
+ CALL_SUBTEST_1((trsolve<float,Dynamic,Dynamic>(internal::random<int>(1,EIGEN_TEST_MAX_SIZE),internal::random<int>(1,EIGEN_TEST_MAX_SIZE))));
+ CALL_SUBTEST_2((trsolve<double,Dynamic,Dynamic>(internal::random<int>(1,EIGEN_TEST_MAX_SIZE),internal::random<int>(1,EIGEN_TEST_MAX_SIZE))));
+ CALL_SUBTEST_3((trsolve<std::complex<float>,Dynamic,Dynamic>(internal::random<int>(1,EIGEN_TEST_MAX_SIZE/2),internal::random<int>(1,EIGEN_TEST_MAX_SIZE/2))));
+ CALL_SUBTEST_4((trsolve<std::complex<double>,Dynamic,Dynamic>(internal::random<int>(1,EIGEN_TEST_MAX_SIZE/2),internal::random<int>(1,EIGEN_TEST_MAX_SIZE/2))));
+
+ // vectors
+ CALL_SUBTEST_1((trsolve<float,Dynamic,1>(internal::random<int>(1,EIGEN_TEST_MAX_SIZE))));
+ CALL_SUBTEST_5((trsolve<std::complex<double>,Dynamic,1>(internal::random<int>(1,EIGEN_TEST_MAX_SIZE))));
+ CALL_SUBTEST_6((trsolve<float,1,1>()));
+ CALL_SUBTEST_7((trsolve<float,1,2>()));
+ CALL_SUBTEST_8((trsolve<std::complex<float>,4,1>()));
+ }
+}
diff --git a/test/qr.cpp b/test/qr.cpp
new file mode 100644
index 000000000..37fb7aa4d
--- /dev/null
+++ b/test/qr.cpp
@@ -0,0 +1,126 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra.
+//
+// Copyright (C) 2008 Gael Guennebaud <gael.guennebaud@inria.fr>
+//
+// This Source Code Form is subject to the terms of the Mozilla
+// Public License v. 2.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 "main.h"
+#include <Eigen/QR>
+
+template<typename MatrixType> void qr(const MatrixType& m)
+{
+ typedef typename MatrixType::Index Index;
+
+ Index rows = m.rows();
+ Index cols = m.cols();
+
+ typedef typename MatrixType::Scalar Scalar;
+ typedef Matrix<Scalar, MatrixType::RowsAtCompileTime, MatrixType::RowsAtCompileTime> MatrixQType;
+ typedef Matrix<Scalar, MatrixType::ColsAtCompileTime, 1> VectorType;
+
+ MatrixType a = MatrixType::Random(rows,cols);
+ HouseholderQR<MatrixType> qrOfA(a);
+
+ MatrixQType q = qrOfA.householderQ();
+ VERIFY_IS_UNITARY(q);
+
+ MatrixType r = qrOfA.matrixQR().template triangularView<Upper>();
+ VERIFY_IS_APPROX(a, qrOfA.householderQ() * r);
+}
+
+template<typename MatrixType, int Cols2> void qr_fixedsize()
+{
+ enum { Rows = MatrixType::RowsAtCompileTime, Cols = MatrixType::ColsAtCompileTime };
+ typedef typename MatrixType::Scalar Scalar;
+ Matrix<Scalar,Rows,Cols> m1 = Matrix<Scalar,Rows,Cols>::Random();
+ HouseholderQR<Matrix<Scalar,Rows,Cols> > qr(m1);
+
+ Matrix<Scalar,Rows,Cols> r = qr.matrixQR();
+ // FIXME need better way to construct trapezoid
+ for(int i = 0; i < Rows; i++) for(int j = 0; j < Cols; j++) if(i>j) r(i,j) = Scalar(0);
+
+ VERIFY_IS_APPROX(m1, qr.householderQ() * r);
+
+ Matrix<Scalar,Cols,Cols2> m2 = Matrix<Scalar,Cols,Cols2>::Random(Cols,Cols2);
+ Matrix<Scalar,Rows,Cols2> m3 = m1*m2;
+ m2 = Matrix<Scalar,Cols,Cols2>::Random(Cols,Cols2);
+ m2 = qr.solve(m3);
+ VERIFY_IS_APPROX(m3, m1*m2);
+}
+
+template<typename MatrixType> void qr_invertible()
+{
+ typedef typename NumTraits<typename MatrixType::Scalar>::Real RealScalar;
+ typedef typename MatrixType::Scalar Scalar;
+
+ int size = internal::random<int>(10,50);
+
+ MatrixType m1(size, size), m2(size, size), m3(size, size);
+ m1 = MatrixType::Random(size,size);
+
+ if (internal::is_same<RealScalar,float>::value)
+ {
+ // let's build a matrix more stable to inverse
+ MatrixType a = MatrixType::Random(size,size*2);
+ m1 += a * a.adjoint();
+ }
+
+ HouseholderQR<MatrixType> qr(m1);
+ m3 = MatrixType::Random(size,size);
+ m2 = qr.solve(m3);
+ VERIFY_IS_APPROX(m3, m1*m2);
+
+ // now construct a matrix with prescribed determinant
+ m1.setZero();
+ for(int i = 0; i < size; i++) m1(i,i) = internal::random<Scalar>();
+ RealScalar absdet = internal::abs(m1.diagonal().prod());
+ m3 = qr.householderQ(); // get a unitary
+ m1 = m3 * m1 * m3;
+ qr.compute(m1);
+ VERIFY_IS_APPROX(absdet, qr.absDeterminant());
+ VERIFY_IS_APPROX(internal::log(absdet), qr.logAbsDeterminant());
+}
+
+template<typename MatrixType> void qr_verify_assert()
+{
+ MatrixType tmp;
+
+ HouseholderQR<MatrixType> qr;
+ VERIFY_RAISES_ASSERT(qr.matrixQR())
+ VERIFY_RAISES_ASSERT(qr.solve(tmp))
+ VERIFY_RAISES_ASSERT(qr.householderQ())
+ VERIFY_RAISES_ASSERT(qr.absDeterminant())
+ VERIFY_RAISES_ASSERT(qr.logAbsDeterminant())
+}
+
+void test_qr()
+{
+ for(int i = 0; i < g_repeat; i++) {
+ CALL_SUBTEST_1( qr(MatrixXf(internal::random<int>(1,EIGEN_TEST_MAX_SIZE),internal::random<int>(1,EIGEN_TEST_MAX_SIZE))) );
+ CALL_SUBTEST_2( qr(MatrixXcd(internal::random<int>(1,EIGEN_TEST_MAX_SIZE/2),internal::random<int>(1,EIGEN_TEST_MAX_SIZE/2))) );
+ CALL_SUBTEST_3(( qr_fixedsize<Matrix<float,3,4>, 2 >() ));
+ CALL_SUBTEST_4(( qr_fixedsize<Matrix<double,6,2>, 4 >() ));
+ CALL_SUBTEST_5(( qr_fixedsize<Matrix<double,2,5>, 7 >() ));
+ CALL_SUBTEST_11( qr(Matrix<float,1,1>()) );
+ }
+
+ for(int i = 0; i < g_repeat; i++) {
+ CALL_SUBTEST_1( qr_invertible<MatrixXf>() );
+ CALL_SUBTEST_6( qr_invertible<MatrixXd>() );
+ CALL_SUBTEST_7( qr_invertible<MatrixXcf>() );
+ CALL_SUBTEST_8( qr_invertible<MatrixXcd>() );
+ }
+
+ CALL_SUBTEST_9(qr_verify_assert<Matrix3f>());
+ CALL_SUBTEST_10(qr_verify_assert<Matrix3d>());
+ CALL_SUBTEST_1(qr_verify_assert<MatrixXf>());
+ CALL_SUBTEST_6(qr_verify_assert<MatrixXd>());
+ CALL_SUBTEST_7(qr_verify_assert<MatrixXcf>());
+ CALL_SUBTEST_8(qr_verify_assert<MatrixXcd>());
+
+ // Test problem size constructors
+ CALL_SUBTEST_12(HouseholderQR<MatrixXf>(10, 20));
+}
diff --git a/test/qr_colpivoting.cpp b/test/qr_colpivoting.cpp
new file mode 100644
index 000000000..dd0812819
--- /dev/null
+++ b/test/qr_colpivoting.cpp
@@ -0,0 +1,150 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra.
+//
+// Copyright (C) 2008 Gael Guennebaud <gael.guennebaud@inria.fr>
+// Copyright (C) 2009 Benoit Jacob <jacob.benoit.1@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 "main.h"
+#include <Eigen/QR>
+
+template<typename MatrixType> void qr()
+{
+ typedef typename MatrixType::Index Index;
+
+ Index rows = internal::random<Index>(2,EIGEN_TEST_MAX_SIZE), cols = internal::random<Index>(2,EIGEN_TEST_MAX_SIZE), cols2 = internal::random<Index>(2,EIGEN_TEST_MAX_SIZE);
+ Index rank = internal::random<Index>(1, (std::min)(rows, cols)-1);
+
+ typedef typename MatrixType::Scalar Scalar;
+ typedef typename MatrixType::RealScalar RealScalar;
+ typedef Matrix<Scalar, MatrixType::RowsAtCompileTime, MatrixType::RowsAtCompileTime> MatrixQType;
+ typedef Matrix<Scalar, MatrixType::ColsAtCompileTime, 1> VectorType;
+ MatrixType m1;
+ createRandomPIMatrixOfRank(rank,rows,cols,m1);
+ ColPivHouseholderQR<MatrixType> qr(m1);
+ VERIFY(rank == qr.rank());
+ VERIFY(cols - qr.rank() == qr.dimensionOfKernel());
+ VERIFY(!qr.isInjective());
+ VERIFY(!qr.isInvertible());
+ VERIFY(!qr.isSurjective());
+
+ MatrixQType q = qr.householderQ();
+ VERIFY_IS_UNITARY(q);
+
+ MatrixType r = qr.matrixQR().template triangularView<Upper>();
+ MatrixType c = q * r * qr.colsPermutation().inverse();
+ VERIFY_IS_APPROX(m1, c);
+
+ MatrixType m2 = MatrixType::Random(cols,cols2);
+ MatrixType m3 = m1*m2;
+ m2 = MatrixType::Random(cols,cols2);
+ m2 = qr.solve(m3);
+ VERIFY_IS_APPROX(m3, m1*m2);
+}
+
+template<typename MatrixType, int Cols2> void qr_fixedsize()
+{
+ enum { Rows = MatrixType::RowsAtCompileTime, Cols = MatrixType::ColsAtCompileTime };
+ typedef typename MatrixType::Scalar Scalar;
+ int rank = internal::random<int>(1, (std::min)(int(Rows), int(Cols))-1);
+ Matrix<Scalar,Rows,Cols> m1;
+ createRandomPIMatrixOfRank(rank,Rows,Cols,m1);
+ ColPivHouseholderQR<Matrix<Scalar,Rows,Cols> > qr(m1);
+ VERIFY(rank == qr.rank());
+ VERIFY(Cols - qr.rank() == qr.dimensionOfKernel());
+ VERIFY(qr.isInjective() == (rank == Rows));
+ VERIFY(qr.isSurjective() == (rank == Cols));
+ VERIFY(qr.isInvertible() == (qr.isInjective() && qr.isSurjective()));
+
+ Matrix<Scalar,Rows,Cols> r = qr.matrixQR().template triangularView<Upper>();
+ Matrix<Scalar,Rows,Cols> c = qr.householderQ() * r * qr.colsPermutation().inverse();
+ VERIFY_IS_APPROX(m1, c);
+
+ Matrix<Scalar,Cols,Cols2> m2 = Matrix<Scalar,Cols,Cols2>::Random(Cols,Cols2);
+ Matrix<Scalar,Rows,Cols2> m3 = m1*m2;
+ m2 = Matrix<Scalar,Cols,Cols2>::Random(Cols,Cols2);
+ m2 = qr.solve(m3);
+ VERIFY_IS_APPROX(m3, m1*m2);
+}
+
+template<typename MatrixType> void qr_invertible()
+{
+ typedef typename NumTraits<typename MatrixType::Scalar>::Real RealScalar;
+ typedef typename MatrixType::Scalar Scalar;
+
+ int size = internal::random<int>(10,50);
+
+ MatrixType m1(size, size), m2(size, size), m3(size, size);
+ m1 = MatrixType::Random(size,size);
+
+ if (internal::is_same<RealScalar,float>::value)
+ {
+ // let's build a matrix more stable to inverse
+ MatrixType a = MatrixType::Random(size,size*2);
+ m1 += a * a.adjoint();
+ }
+
+ ColPivHouseholderQR<MatrixType> qr(m1);
+ m3 = MatrixType::Random(size,size);
+ m2 = qr.solve(m3);
+ //VERIFY_IS_APPROX(m3, m1*m2);
+
+ // now construct a matrix with prescribed determinant
+ m1.setZero();
+ for(int i = 0; i < size; i++) m1(i,i) = internal::random<Scalar>();
+ RealScalar absdet = internal::abs(m1.diagonal().prod());
+ m3 = qr.householderQ(); // get a unitary
+ m1 = m3 * m1 * m3;
+ qr.compute(m1);
+ VERIFY_IS_APPROX(absdet, qr.absDeterminant());
+ VERIFY_IS_APPROX(internal::log(absdet), qr.logAbsDeterminant());
+}
+
+template<typename MatrixType> void qr_verify_assert()
+{
+ MatrixType tmp;
+
+ ColPivHouseholderQR<MatrixType> qr;
+ VERIFY_RAISES_ASSERT(qr.matrixQR())
+ VERIFY_RAISES_ASSERT(qr.solve(tmp))
+ VERIFY_RAISES_ASSERT(qr.householderQ())
+ VERIFY_RAISES_ASSERT(qr.dimensionOfKernel())
+ VERIFY_RAISES_ASSERT(qr.isInjective())
+ VERIFY_RAISES_ASSERT(qr.isSurjective())
+ VERIFY_RAISES_ASSERT(qr.isInvertible())
+ VERIFY_RAISES_ASSERT(qr.inverse())
+ VERIFY_RAISES_ASSERT(qr.absDeterminant())
+ VERIFY_RAISES_ASSERT(qr.logAbsDeterminant())
+}
+
+void test_qr_colpivoting()
+{
+ for(int i = 0; i < g_repeat; i++) {
+ CALL_SUBTEST_1( qr<MatrixXf>() );
+ CALL_SUBTEST_2( qr<MatrixXd>() );
+ CALL_SUBTEST_3( qr<MatrixXcd>() );
+ CALL_SUBTEST_4(( qr_fixedsize<Matrix<float,3,5>, 4 >() ));
+ CALL_SUBTEST_5(( qr_fixedsize<Matrix<double,6,2>, 3 >() ));
+ CALL_SUBTEST_5(( qr_fixedsize<Matrix<double,1,1>, 1 >() ));
+ }
+
+ for(int i = 0; i < g_repeat; i++) {
+ CALL_SUBTEST_1( qr_invertible<MatrixXf>() );
+ CALL_SUBTEST_2( qr_invertible<MatrixXd>() );
+ CALL_SUBTEST_6( qr_invertible<MatrixXcf>() );
+ CALL_SUBTEST_3( qr_invertible<MatrixXcd>() );
+ }
+
+ CALL_SUBTEST_7(qr_verify_assert<Matrix3f>());
+ CALL_SUBTEST_8(qr_verify_assert<Matrix3d>());
+ CALL_SUBTEST_1(qr_verify_assert<MatrixXf>());
+ CALL_SUBTEST_2(qr_verify_assert<MatrixXd>());
+ CALL_SUBTEST_6(qr_verify_assert<MatrixXcf>());
+ CALL_SUBTEST_3(qr_verify_assert<MatrixXcd>());
+
+ // Test problem size constructors
+ CALL_SUBTEST_9(ColPivHouseholderQR<MatrixXf>(10, 20));
+}
diff --git a/test/qr_fullpivoting.cpp b/test/qr_fullpivoting.cpp
new file mode 100644
index 000000000..e5c9790c8
--- /dev/null
+++ b/test/qr_fullpivoting.cpp
@@ -0,0 +1,132 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra.
+//
+// Copyright (C) 2008 Gael Guennebaud <gael.guennebaud@inria.fr>
+// Copyright (C) 2009 Benoit Jacob <jacob.benoit.1@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 "main.h"
+#include <Eigen/QR>
+
+template<typename MatrixType> void qr()
+{
+ typedef typename MatrixType::Index Index;
+
+ Index rows = internal::random<Index>(20,200), cols = internal::random<int>(20,200), cols2 = internal::random<int>(20,200);
+ Index rank = internal::random<Index>(1, (std::min)(rows, cols)-1);
+
+ typedef typename MatrixType::Scalar Scalar;
+ typedef Matrix<Scalar, MatrixType::RowsAtCompileTime, MatrixType::RowsAtCompileTime> MatrixQType;
+ typedef Matrix<Scalar, MatrixType::ColsAtCompileTime, 1> VectorType;
+ MatrixType m1;
+ createRandomPIMatrixOfRank(rank,rows,cols,m1);
+ FullPivHouseholderQR<MatrixType> qr(m1);
+ VERIFY(rank == qr.rank());
+ VERIFY(cols - qr.rank() == qr.dimensionOfKernel());
+ VERIFY(!qr.isInjective());
+ VERIFY(!qr.isInvertible());
+ VERIFY(!qr.isSurjective());
+
+ MatrixType r = qr.matrixQR();
+
+ MatrixQType q = qr.matrixQ();
+ VERIFY_IS_UNITARY(q);
+
+ // FIXME need better way to construct trapezoid
+ for(int i = 0; i < rows; i++) for(int j = 0; j < cols; j++) if(i>j) r(i,j) = Scalar(0);
+
+ MatrixType c = qr.matrixQ() * r * qr.colsPermutation().inverse();
+
+ VERIFY_IS_APPROX(m1, c);
+
+ MatrixType m2 = MatrixType::Random(cols,cols2);
+ MatrixType m3 = m1*m2;
+ m2 = MatrixType::Random(cols,cols2);
+ m2 = qr.solve(m3);
+ VERIFY_IS_APPROX(m3, m1*m2);
+}
+
+template<typename MatrixType> void qr_invertible()
+{
+ typedef typename NumTraits<typename MatrixType::Scalar>::Real RealScalar;
+ typedef typename MatrixType::Scalar Scalar;
+
+ int size = internal::random<int>(10,50);
+
+ MatrixType m1(size, size), m2(size, size), m3(size, size);
+ m1 = MatrixType::Random(size,size);
+
+ if (internal::is_same<RealScalar,float>::value)
+ {
+ // let's build a matrix more stable to inverse
+ MatrixType a = MatrixType::Random(size,size*2);
+ m1 += a * a.adjoint();
+ }
+
+ FullPivHouseholderQR<MatrixType> qr(m1);
+ VERIFY(qr.isInjective());
+ VERIFY(qr.isInvertible());
+ VERIFY(qr.isSurjective());
+
+ m3 = MatrixType::Random(size,size);
+ m2 = qr.solve(m3);
+ VERIFY_IS_APPROX(m3, m1*m2);
+
+ // now construct a matrix with prescribed determinant
+ m1.setZero();
+ for(int i = 0; i < size; i++) m1(i,i) = internal::random<Scalar>();
+ RealScalar absdet = internal::abs(m1.diagonal().prod());
+ m3 = qr.matrixQ(); // get a unitary
+ m1 = m3 * m1 * m3;
+ qr.compute(m1);
+ VERIFY_IS_APPROX(absdet, qr.absDeterminant());
+ VERIFY_IS_APPROX(internal::log(absdet), qr.logAbsDeterminant());
+}
+
+template<typename MatrixType> void qr_verify_assert()
+{
+ MatrixType tmp;
+
+ FullPivHouseholderQR<MatrixType> qr;
+ VERIFY_RAISES_ASSERT(qr.matrixQR())
+ VERIFY_RAISES_ASSERT(qr.solve(tmp))
+ VERIFY_RAISES_ASSERT(qr.matrixQ())
+ VERIFY_RAISES_ASSERT(qr.dimensionOfKernel())
+ VERIFY_RAISES_ASSERT(qr.isInjective())
+ VERIFY_RAISES_ASSERT(qr.isSurjective())
+ VERIFY_RAISES_ASSERT(qr.isInvertible())
+ VERIFY_RAISES_ASSERT(qr.inverse())
+ VERIFY_RAISES_ASSERT(qr.absDeterminant())
+ VERIFY_RAISES_ASSERT(qr.logAbsDeterminant())
+}
+
+void test_qr_fullpivoting()
+{
+ for(int i = 0; i < 1; i++) {
+ // FIXME : very weird bug here
+// CALL_SUBTEST(qr(Matrix2f()) );
+ CALL_SUBTEST_1( qr<MatrixXf>() );
+ CALL_SUBTEST_2( qr<MatrixXd>() );
+ CALL_SUBTEST_3( qr<MatrixXcd>() );
+ }
+
+ for(int i = 0; i < g_repeat; i++) {
+ CALL_SUBTEST_1( qr_invertible<MatrixXf>() );
+ CALL_SUBTEST_2( qr_invertible<MatrixXd>() );
+ CALL_SUBTEST_4( qr_invertible<MatrixXcf>() );
+ CALL_SUBTEST_3( qr_invertible<MatrixXcd>() );
+ }
+
+ CALL_SUBTEST_5(qr_verify_assert<Matrix3f>());
+ CALL_SUBTEST_6(qr_verify_assert<Matrix3d>());
+ CALL_SUBTEST_1(qr_verify_assert<MatrixXf>());
+ CALL_SUBTEST_2(qr_verify_assert<MatrixXd>());
+ CALL_SUBTEST_4(qr_verify_assert<MatrixXcf>());
+ CALL_SUBTEST_3(qr_verify_assert<MatrixXcd>());
+
+ // Test problem size constructors
+ CALL_SUBTEST_7(FullPivHouseholderQR<MatrixXf>(10, 20));
+}
diff --git a/test/qtvector.cpp b/test/qtvector.cpp
new file mode 100644
index 000000000..2be885e48
--- /dev/null
+++ b/test/qtvector.cpp
@@ -0,0 +1,158 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra.
+//
+// Copyright (C) 2008 Gael Guennebaud <gael.guennebaud@inria.fr>
+// Copyright (C) 2008 Benoit Jacob <jacob.benoit.1@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/.
+
+#define EIGEN_WORK_AROUND_QT_BUG_CALLING_WRONG_OPERATOR_NEW_FIXED_IN_QT_4_5
+
+#include "main.h"
+#include <QtCore/QVector>
+#include <Eigen/Geometry>
+#include <Eigen/QtAlignedMalloc>
+
+template<typename MatrixType>
+void check_qtvector_matrix(const MatrixType& m)
+{
+ typedef typename MatrixType::Index Index;
+
+ Index rows = m.rows();
+ Index cols = m.cols();
+ MatrixType x = MatrixType::Random(rows,cols), y = MatrixType::Random(rows,cols);
+ QVector<MatrixType> v(10, MatrixType(rows,cols)), w(20, y);
+ for(int i = 0; i < 20; i++)
+ {
+ VERIFY_IS_APPROX(w[i], y);
+ }
+ v[5] = x;
+ w[6] = v[5];
+ VERIFY_IS_APPROX(w[6], v[5]);
+ v = w;
+ for(int i = 0; i < 20; i++)
+ {
+ VERIFY_IS_APPROX(w[i], v[i]);
+ }
+
+ v.resize(21);
+ v[20] = x;
+ VERIFY_IS_APPROX(v[20], x);
+ v.fill(y,22);
+ VERIFY_IS_APPROX(v[21], y);
+ v.push_back(x);
+ VERIFY_IS_APPROX(v[22], x);
+ VERIFY((size_t)&(v[22]) == (size_t)&(v[21]) + sizeof(MatrixType));
+
+ // do a lot of push_back such that the vector gets internally resized
+ // (with memory reallocation)
+ MatrixType* ref = &w[0];
+ for(int i=0; i<30 || ((ref==&w[0]) && i<300); ++i)
+ v.push_back(w[i%w.size()]);
+ for(int i=23; i<v.size(); ++i)
+ {
+ VERIFY(v[i]==w[(i-23)%w.size()]);
+ }
+}
+
+template<typename TransformType>
+void check_qtvector_transform(const TransformType&)
+{
+ typedef typename TransformType::MatrixType MatrixType;
+ TransformType x(MatrixType::Random()), y(MatrixType::Random());
+ QVector<TransformType> v(10), w(20, y);
+ v[5] = x;
+ w[6] = v[5];
+ VERIFY_IS_APPROX(w[6], v[5]);
+ v = w;
+ for(int i = 0; i < 20; i++)
+ {
+ VERIFY_IS_APPROX(w[i], v[i]);
+ }
+
+ v.resize(21);
+ v[20] = x;
+ VERIFY_IS_APPROX(v[20], x);
+ v.fill(y,22);
+ VERIFY_IS_APPROX(v[21], y);
+ v.push_back(x);
+ VERIFY_IS_APPROX(v[22], x);
+ VERIFY((size_t)&(v[22]) == (size_t)&(v[21]) + sizeof(TransformType));
+
+ // do a lot of push_back such that the vector gets internally resized
+ // (with memory reallocation)
+ TransformType* ref = &w[0];
+ for(int i=0; i<30 || ((ref==&w[0]) && i<300); ++i)
+ v.push_back(w[i%w.size()]);
+ for(unsigned int i=23; int(i)<v.size(); ++i)
+ {
+ VERIFY(v[i].matrix()==w[(i-23)%w.size()].matrix());
+ }
+}
+
+template<typename QuaternionType>
+void check_qtvector_quaternion(const QuaternionType&)
+{
+ typedef typename QuaternionType::Coefficients Coefficients;
+ QuaternionType x(Coefficients::Random()), y(Coefficients::Random());
+ QVector<QuaternionType> v(10), w(20, y);
+ v[5] = x;
+ w[6] = v[5];
+ VERIFY_IS_APPROX(w[6], v[5]);
+ v = w;
+ for(int i = 0; i < 20; i++)
+ {
+ VERIFY_IS_APPROX(w[i], v[i]);
+ }
+
+ v.resize(21);
+ v[20] = x;
+ VERIFY_IS_APPROX(v[20], x);
+ v.fill(y,22);
+ VERIFY_IS_APPROX(v[21], y);
+ v.push_back(x);
+ VERIFY_IS_APPROX(v[22], x);
+ VERIFY((size_t)&(v[22]) == (size_t)&(v[21]) + sizeof(QuaternionType));
+
+ // do a lot of push_back such that the vector gets internally resized
+ // (with memory reallocation)
+ QuaternionType* ref = &w[0];
+ for(int i=0; i<30 || ((ref==&w[0]) && i<300); ++i)
+ v.push_back(w[i%w.size()]);
+ for(unsigned int i=23; int(i)<v.size(); ++i)
+ {
+ VERIFY(v[i].coeffs()==w[(i-23)%w.size()].coeffs());
+ }
+}
+
+void test_qtvector()
+{
+ // some non vectorizable fixed sizes
+ CALL_SUBTEST(check_qtvector_matrix(Vector2f()));
+ CALL_SUBTEST(check_qtvector_matrix(Matrix3f()));
+ CALL_SUBTEST(check_qtvector_matrix(Matrix3d()));
+
+ // some vectorizable fixed sizes
+ CALL_SUBTEST(check_qtvector_matrix(Matrix2f()));
+ CALL_SUBTEST(check_qtvector_matrix(Vector4f()));
+ CALL_SUBTEST(check_qtvector_matrix(Matrix4f()));
+ CALL_SUBTEST(check_qtvector_matrix(Matrix4d()));
+
+ // some dynamic sizes
+ CALL_SUBTEST(check_qtvector_matrix(MatrixXd(1,1)));
+ CALL_SUBTEST(check_qtvector_matrix(VectorXd(20)));
+ CALL_SUBTEST(check_qtvector_matrix(RowVectorXf(20)));
+ CALL_SUBTEST(check_qtvector_matrix(MatrixXcf(10,10)));
+
+ // some Transform
+ CALL_SUBTEST(check_qtvector_transform(Affine2f()));
+ CALL_SUBTEST(check_qtvector_transform(Affine3f()));
+ CALL_SUBTEST(check_qtvector_transform(Affine3d()));
+ //CALL_SUBTEST(check_qtvector_transform(Transform4d()));
+
+ // some Quaternion
+ CALL_SUBTEST(check_qtvector_quaternion(Quaternionf()));
+ CALL_SUBTEST(check_qtvector_quaternion(Quaternionf()));
+}
diff --git a/test/redux.cpp b/test/redux.cpp
new file mode 100644
index 000000000..e07d4b1e4
--- /dev/null
+++ b/test/redux.cpp
@@ -0,0 +1,158 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra.
+//
+// Copyright (C) 2008 Benoit Jacob <jacob.benoit.1@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 "main.h"
+
+template<typename MatrixType> void matrixRedux(const MatrixType& m)
+{
+ typedef typename MatrixType::Index Index;
+ typedef typename MatrixType::Scalar Scalar;
+ typedef typename MatrixType::RealScalar RealScalar;
+
+ Index rows = m.rows();
+ Index cols = m.cols();
+
+ MatrixType m1 = MatrixType::Random(rows, cols);
+
+ // The entries of m1 are uniformly distributed in [0,1], so m1.prod() is very small. This may lead to test
+ // failures if we underflow into denormals. Thus, we scale so that entires are close to 1.
+ MatrixType m1_for_prod = MatrixType::Ones(rows, cols) + Scalar(0.2) * m1;
+
+ VERIFY_IS_MUCH_SMALLER_THAN(MatrixType::Zero(rows, cols).sum(), Scalar(1));
+ VERIFY_IS_APPROX(MatrixType::Ones(rows, cols).sum(), Scalar(float(rows*cols))); // the float() here to shut up excessive MSVC warning about int->complex conversion being lossy
+ Scalar s(0), p(1), minc(internal::real(m1.coeff(0))), maxc(internal::real(m1.coeff(0)));
+ for(int j = 0; j < cols; j++)
+ for(int i = 0; i < rows; i++)
+ {
+ s += m1(i,j);
+ p *= m1_for_prod(i,j);
+ minc = (std::min)(internal::real(minc), internal::real(m1(i,j)));
+ maxc = (std::max)(internal::real(maxc), internal::real(m1(i,j)));
+ }
+ const Scalar mean = s/Scalar(RealScalar(rows*cols));
+
+ VERIFY_IS_APPROX(m1.sum(), s);
+ VERIFY_IS_APPROX(m1.mean(), mean);
+ VERIFY_IS_APPROX(m1_for_prod.prod(), p);
+ VERIFY_IS_APPROX(m1.real().minCoeff(), internal::real(minc));
+ VERIFY_IS_APPROX(m1.real().maxCoeff(), internal::real(maxc));
+
+ // test slice vectorization assuming assign is ok
+ Index r0 = internal::random<Index>(0,rows-1);
+ Index c0 = internal::random<Index>(0,cols-1);
+ Index r1 = internal::random<Index>(r0+1,rows)-r0;
+ Index c1 = internal::random<Index>(c0+1,cols)-c0;
+ VERIFY_IS_APPROX(m1.block(r0,c0,r1,c1).sum(), m1.block(r0,c0,r1,c1).eval().sum());
+ VERIFY_IS_APPROX(m1.block(r0,c0,r1,c1).mean(), m1.block(r0,c0,r1,c1).eval().mean());
+ VERIFY_IS_APPROX(m1_for_prod.block(r0,c0,r1,c1).prod(), m1_for_prod.block(r0,c0,r1,c1).eval().prod());
+ VERIFY_IS_APPROX(m1.block(r0,c0,r1,c1).real().minCoeff(), m1.block(r0,c0,r1,c1).real().eval().minCoeff());
+ VERIFY_IS_APPROX(m1.block(r0,c0,r1,c1).real().maxCoeff(), m1.block(r0,c0,r1,c1).real().eval().maxCoeff());
+
+ // test empty objects
+ VERIFY_IS_APPROX(m1.block(r0,c0,0,0).sum(), Scalar(0));
+ VERIFY_IS_APPROX(m1.block(r0,c0,0,0).prod(), Scalar(1));
+}
+
+template<typename VectorType> void vectorRedux(const VectorType& w)
+{
+ typedef typename VectorType::Index Index;
+ typedef typename VectorType::Scalar Scalar;
+ typedef typename NumTraits<Scalar>::Real RealScalar;
+ Index size = w.size();
+
+ VectorType v = VectorType::Random(size);
+ VectorType v_for_prod = VectorType::Ones(size) + Scalar(0.2) * v; // see comment above declaration of m1_for_prod
+
+ for(int i = 1; i < size; i++)
+ {
+ Scalar s(0), p(1);
+ RealScalar minc(internal::real(v.coeff(0))), maxc(internal::real(v.coeff(0)));
+ for(int j = 0; j < i; j++)
+ {
+ s += v[j];
+ p *= v_for_prod[j];
+ minc = (std::min)(minc, internal::real(v[j]));
+ maxc = (std::max)(maxc, internal::real(v[j]));
+ }
+ VERIFY_IS_MUCH_SMALLER_THAN(internal::abs(s - v.head(i).sum()), Scalar(1));
+ VERIFY_IS_APPROX(p, v_for_prod.head(i).prod());
+ VERIFY_IS_APPROX(minc, v.real().head(i).minCoeff());
+ VERIFY_IS_APPROX(maxc, v.real().head(i).maxCoeff());
+ }
+
+ for(int i = 0; i < size-1; i++)
+ {
+ Scalar s(0), p(1);
+ RealScalar minc(internal::real(v.coeff(i))), maxc(internal::real(v.coeff(i)));
+ for(int j = i; j < size; j++)
+ {
+ s += v[j];
+ p *= v_for_prod[j];
+ minc = (std::min)(minc, internal::real(v[j]));
+ maxc = (std::max)(maxc, internal::real(v[j]));
+ }
+ VERIFY_IS_MUCH_SMALLER_THAN(internal::abs(s - v.tail(size-i).sum()), Scalar(1));
+ VERIFY_IS_APPROX(p, v_for_prod.tail(size-i).prod());
+ VERIFY_IS_APPROX(minc, v.real().tail(size-i).minCoeff());
+ VERIFY_IS_APPROX(maxc, v.real().tail(size-i).maxCoeff());
+ }
+
+ for(int i = 0; i < size/2; i++)
+ {
+ Scalar s(0), p(1);
+ RealScalar minc(internal::real(v.coeff(i))), maxc(internal::real(v.coeff(i)));
+ for(int j = i; j < size-i; j++)
+ {
+ s += v[j];
+ p *= v_for_prod[j];
+ minc = (std::min)(minc, internal::real(v[j]));
+ maxc = (std::max)(maxc, internal::real(v[j]));
+ }
+ VERIFY_IS_MUCH_SMALLER_THAN(internal::abs(s - v.segment(i, size-2*i).sum()), Scalar(1));
+ VERIFY_IS_APPROX(p, v_for_prod.segment(i, size-2*i).prod());
+ VERIFY_IS_APPROX(minc, v.real().segment(i, size-2*i).minCoeff());
+ VERIFY_IS_APPROX(maxc, v.real().segment(i, size-2*i).maxCoeff());
+ }
+
+ // test empty objects
+ VERIFY_IS_APPROX(v.head(0).sum(), Scalar(0));
+ VERIFY_IS_APPROX(v.tail(0).prod(), Scalar(1));
+ VERIFY_RAISES_ASSERT(v.head(0).mean());
+ VERIFY_RAISES_ASSERT(v.head(0).minCoeff());
+ VERIFY_RAISES_ASSERT(v.head(0).maxCoeff());
+}
+
+void test_redux()
+{
+ // the max size cannot be too large, otherwise reduxion operations obviously generate large errors.
+ int maxsize = (std::min)(100,EIGEN_TEST_MAX_SIZE);
+ EIGEN_UNUSED_VARIABLE(maxsize);
+ for(int i = 0; i < g_repeat; i++) {
+ CALL_SUBTEST_1( matrixRedux(Matrix<float, 1, 1>()) );
+ CALL_SUBTEST_1( matrixRedux(Array<float, 1, 1>()) );
+ CALL_SUBTEST_2( matrixRedux(Matrix2f()) );
+ CALL_SUBTEST_2( matrixRedux(Array2f()) );
+ CALL_SUBTEST_3( matrixRedux(Matrix4d()) );
+ CALL_SUBTEST_3( matrixRedux(Array4d()) );
+ CALL_SUBTEST_4( matrixRedux(MatrixXcf(internal::random<int>(1,maxsize), internal::random<int>(1,maxsize))) );
+ CALL_SUBTEST_4( matrixRedux(ArrayXXcf(internal::random<int>(1,maxsize), internal::random<int>(1,maxsize))) );
+ CALL_SUBTEST_5( matrixRedux(MatrixXd (internal::random<int>(1,maxsize), internal::random<int>(1,maxsize))) );
+ CALL_SUBTEST_5( matrixRedux(ArrayXXd (internal::random<int>(1,maxsize), internal::random<int>(1,maxsize))) );
+ CALL_SUBTEST_6( matrixRedux(MatrixXi (internal::random<int>(1,maxsize), internal::random<int>(1,maxsize))) );
+ CALL_SUBTEST_6( matrixRedux(ArrayXXi (internal::random<int>(1,maxsize), internal::random<int>(1,maxsize))) );
+ }
+ for(int i = 0; i < g_repeat; i++) {
+ CALL_SUBTEST_7( vectorRedux(Vector4f()) );
+ CALL_SUBTEST_7( vectorRedux(Array4f()) );
+ CALL_SUBTEST_5( vectorRedux(VectorXd(internal::random<int>(1,maxsize))) );
+ CALL_SUBTEST_5( vectorRedux(ArrayXd(internal::random<int>(1,maxsize))) );
+ CALL_SUBTEST_8( vectorRedux(VectorXf(internal::random<int>(1,maxsize))) );
+ CALL_SUBTEST_8( vectorRedux(ArrayXf(internal::random<int>(1,maxsize))) );
+ }
+}
diff --git a/test/resize.cpp b/test/resize.cpp
new file mode 100644
index 000000000..4adaafe56
--- /dev/null
+++ b/test/resize.cpp
@@ -0,0 +1,41 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra.
+//
+// Copyright (C) 2009 Keir Mierle <mierle@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 "main.h"
+
+template<DenseIndex rows, DenseIndex cols>
+void resizeLikeTest()
+{
+ MatrixXf A(rows, cols);
+ MatrixXf B;
+ Matrix<double, rows, cols> C;
+ B.resizeLike(A);
+ C.resizeLike(B); // Shouldn't crash.
+ VERIFY(B.rows() == rows && B.cols() == cols);
+
+ VectorXf x(rows);
+ RowVectorXf y;
+ y.resizeLike(x);
+ VERIFY(y.rows() == 1 && y.cols() == rows);
+
+ y.resize(cols);
+ x.resizeLike(y);
+ VERIFY(x.rows() == cols && x.cols() == 1);
+}
+
+void resizeLikeTest12() { resizeLikeTest<1,2>(); }
+void resizeLikeTest1020() { resizeLikeTest<10,20>(); }
+void resizeLikeTest31() { resizeLikeTest<3,1>(); }
+
+void test_resize()
+{
+ CALL_SUBTEST(resizeLikeTest12() );
+ CALL_SUBTEST(resizeLikeTest1020() );
+ CALL_SUBTEST(resizeLikeTest31() );
+}
diff --git a/test/runtest.sh b/test/runtest.sh
new file mode 100755
index 000000000..2be250819
--- /dev/null
+++ b/test/runtest.sh
@@ -0,0 +1,20 @@
+#!/bin/bash
+
+black='\E[30m'
+red='\E[31m'
+green='\E[32m'
+yellow='\E[33m'
+blue='\E[34m'
+magenta='\E[35m'
+cyan='\E[36m'
+white='\E[37m'
+
+if ! ./$1 > /dev/null 2> .runtest.log ; then
+ echo -e $red Test $1 failed: $black
+ echo -e $blue
+ cat .runtest.log
+ echo -e $black
+ exit 1
+else
+echo -e $green Test $1 passed$black
+fi
diff --git a/test/schur_complex.cpp b/test/schur_complex.cpp
new file mode 100644
index 000000000..a6f66ab02
--- /dev/null
+++ b/test/schur_complex.cpp
@@ -0,0 +1,74 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra.
+//
+// Copyright (C) 2010 Jitse Niesen <jitse@maths.leeds.ac.uk>
+//
+// This Source Code Form is subject to the terms of the Mozilla
+// Public License v. 2.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 "main.h"
+#include <limits>
+#include <Eigen/Eigenvalues>
+
+template<typename MatrixType> void schur(int size = MatrixType::ColsAtCompileTime)
+{
+ typedef typename ComplexSchur<MatrixType>::ComplexScalar ComplexScalar;
+ typedef typename ComplexSchur<MatrixType>::ComplexMatrixType ComplexMatrixType;
+
+ // Test basic functionality: T is triangular and A = U T U*
+ for(int counter = 0; counter < g_repeat; ++counter) {
+ MatrixType A = MatrixType::Random(size, size);
+ ComplexSchur<MatrixType> schurOfA(A);
+ VERIFY_IS_EQUAL(schurOfA.info(), Success);
+ ComplexMatrixType U = schurOfA.matrixU();
+ ComplexMatrixType T = schurOfA.matrixT();
+ for(int row = 1; row < size; ++row) {
+ for(int col = 0; col < row; ++col) {
+ VERIFY(T(row,col) == (typename MatrixType::Scalar)0);
+ }
+ }
+ VERIFY_IS_APPROX(A.template cast<ComplexScalar>(), U * T * U.adjoint());
+ }
+
+ // Test asserts when not initialized
+ ComplexSchur<MatrixType> csUninitialized;
+ VERIFY_RAISES_ASSERT(csUninitialized.matrixT());
+ VERIFY_RAISES_ASSERT(csUninitialized.matrixU());
+ VERIFY_RAISES_ASSERT(csUninitialized.info());
+
+ // Test whether compute() and constructor returns same result
+ MatrixType A = MatrixType::Random(size, size);
+ ComplexSchur<MatrixType> cs1;
+ cs1.compute(A);
+ ComplexSchur<MatrixType> cs2(A);
+ VERIFY_IS_EQUAL(cs1.info(), Success);
+ VERIFY_IS_EQUAL(cs2.info(), Success);
+ VERIFY_IS_EQUAL(cs1.matrixT(), cs2.matrixT());
+ VERIFY_IS_EQUAL(cs1.matrixU(), cs2.matrixU());
+
+ // Test computation of only T, not U
+ ComplexSchur<MatrixType> csOnlyT(A, false);
+ VERIFY_IS_EQUAL(csOnlyT.info(), Success);
+ VERIFY_IS_EQUAL(cs1.matrixT(), csOnlyT.matrixT());
+ VERIFY_RAISES_ASSERT(csOnlyT.matrixU());
+
+ if (size > 1)
+ {
+ // Test matrix with NaN
+ A(0,0) = std::numeric_limits<typename MatrixType::RealScalar>::quiet_NaN();
+ ComplexSchur<MatrixType> csNaN(A);
+ VERIFY_IS_EQUAL(csNaN.info(), NoConvergence);
+ }
+}
+
+void test_schur_complex()
+{
+ CALL_SUBTEST_1(( schur<Matrix4cd>() ));
+ CALL_SUBTEST_2(( schur<MatrixXcf>(internal::random<int>(1,EIGEN_TEST_MAX_SIZE/4)) ));
+ CALL_SUBTEST_3(( schur<Matrix<std::complex<float>, 1, 1> >() ));
+ CALL_SUBTEST_4(( schur<Matrix<float, 3, 3, Eigen::RowMajor> >() ));
+
+ // Test problem size constructors
+ CALL_SUBTEST_5(ComplexSchur<MatrixXf>(10));
+}
diff --git a/test/schur_real.cpp b/test/schur_real.cpp
new file mode 100644
index 000000000..e6351d94a
--- /dev/null
+++ b/test/schur_real.cpp
@@ -0,0 +1,93 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra.
+//
+// Copyright (C) 2010 Jitse Niesen <jitse@maths.leeds.ac.uk>
+//
+// This Source Code Form is subject to the terms of the Mozilla
+// Public License v. 2.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 "main.h"
+#include <limits>
+#include <Eigen/Eigenvalues>
+
+template<typename MatrixType> void verifyIsQuasiTriangular(const MatrixType& T)
+{
+ typedef typename MatrixType::Index Index;
+
+ const Index size = T.cols();
+ typedef typename MatrixType::Scalar Scalar;
+
+ // Check T is lower Hessenberg
+ for(int row = 2; row < size; ++row) {
+ for(int col = 0; col < row - 1; ++col) {
+ VERIFY(T(row,col) == Scalar(0));
+ }
+ }
+
+ // Check that any non-zero on the subdiagonal is followed by a zero and is
+ // part of a 2x2 diagonal block with imaginary eigenvalues.
+ for(int row = 1; row < size; ++row) {
+ if (T(row,row-1) != Scalar(0)) {
+ VERIFY(row == size-1 || T(row+1,row) == 0);
+ Scalar tr = T(row-1,row-1) + T(row,row);
+ Scalar det = T(row-1,row-1) * T(row,row) - T(row-1,row) * T(row,row-1);
+ VERIFY(4 * det > tr * tr);
+ }
+ }
+}
+
+template<typename MatrixType> void schur(int size = MatrixType::ColsAtCompileTime)
+{
+ // Test basic functionality: T is quasi-triangular and A = U T U*
+ for(int counter = 0; counter < g_repeat; ++counter) {
+ MatrixType A = MatrixType::Random(size, size);
+ RealSchur<MatrixType> schurOfA(A);
+ VERIFY_IS_EQUAL(schurOfA.info(), Success);
+ MatrixType U = schurOfA.matrixU();
+ MatrixType T = schurOfA.matrixT();
+ verifyIsQuasiTriangular(T);
+ VERIFY_IS_APPROX(A, U * T * U.transpose());
+ }
+
+ // Test asserts when not initialized
+ RealSchur<MatrixType> rsUninitialized;
+ VERIFY_RAISES_ASSERT(rsUninitialized.matrixT());
+ VERIFY_RAISES_ASSERT(rsUninitialized.matrixU());
+ VERIFY_RAISES_ASSERT(rsUninitialized.info());
+
+ // Test whether compute() and constructor returns same result
+ MatrixType A = MatrixType::Random(size, size);
+ RealSchur<MatrixType> rs1;
+ rs1.compute(A);
+ RealSchur<MatrixType> rs2(A);
+ VERIFY_IS_EQUAL(rs1.info(), Success);
+ VERIFY_IS_EQUAL(rs2.info(), Success);
+ VERIFY_IS_EQUAL(rs1.matrixT(), rs2.matrixT());
+ VERIFY_IS_EQUAL(rs1.matrixU(), rs2.matrixU());
+
+ // Test computation of only T, not U
+ RealSchur<MatrixType> rsOnlyT(A, false);
+ VERIFY_IS_EQUAL(rsOnlyT.info(), Success);
+ VERIFY_IS_EQUAL(rs1.matrixT(), rsOnlyT.matrixT());
+ VERIFY_RAISES_ASSERT(rsOnlyT.matrixU());
+
+ if (size > 2)
+ {
+ // Test matrix with NaN
+ A(0,0) = std::numeric_limits<typename MatrixType::Scalar>::quiet_NaN();
+ RealSchur<MatrixType> rsNaN(A);
+ VERIFY_IS_EQUAL(rsNaN.info(), NoConvergence);
+ }
+}
+
+void test_schur_real()
+{
+ CALL_SUBTEST_1(( schur<Matrix4f>() ));
+ CALL_SUBTEST_2(( schur<MatrixXd>(internal::random<int>(1,EIGEN_TEST_MAX_SIZE/4)) ));
+ CALL_SUBTEST_3(( schur<Matrix<float, 1, 1> >() ));
+ CALL_SUBTEST_4(( schur<Matrix<double, 3, 3, Eigen::RowMajor> >() ));
+
+ // Test problem size constructors
+ CALL_SUBTEST_5(RealSchur<MatrixXf>(10));
+}
diff --git a/test/selfadjoint.cpp b/test/selfadjoint.cpp
new file mode 100644
index 000000000..6d3ec6536
--- /dev/null
+++ b/test/selfadjoint.cpp
@@ -0,0 +1,62 @@
+// This file is triangularView of Eigen, a lightweight C++ template library
+// for linear algebra.
+//
+// Copyright (C) 2010 Gael Guennebaud <gael.guennebaud@inria.fr>
+//
+// This Source Code Form is subject to the terms of the Mozilla
+// Public License v. 2.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 "main.h"
+
+// This file tests the basic selfadjointView API,
+// the related products and decompositions are tested in specific files.
+
+template<typename MatrixType> void selfadjoint(const MatrixType& m)
+{
+ typedef typename MatrixType::Index Index;
+ typedef typename MatrixType::Scalar Scalar;
+ typedef typename NumTraits<Scalar>::Real RealScalar;
+
+ Index rows = m.rows();
+ Index cols = m.cols();
+
+ MatrixType m1 = MatrixType::Random(rows, cols),
+ m3(rows, cols);
+
+ m1.diagonal() = m1.diagonal().real().template cast<Scalar>();
+
+ // check selfadjoint to dense
+ m3 = m1.template selfadjointView<Upper>();
+ VERIFY_IS_APPROX(MatrixType(m3.template triangularView<Upper>()), MatrixType(m1.template triangularView<Upper>()));
+ VERIFY_IS_APPROX(m3, m3.adjoint());
+
+
+ m3 = m1.template selfadjointView<Lower>();
+ VERIFY_IS_APPROX(MatrixType(m3.template triangularView<Lower>()), MatrixType(m1.template triangularView<Lower>()));
+ VERIFY_IS_APPROX(m3, m3.adjoint());
+}
+
+void bug_159()
+{
+ Matrix3d m = Matrix3d::Random().selfadjointView<Lower>();
+ EIGEN_UNUSED_VARIABLE(m)
+}
+
+void test_selfadjoint()
+{
+ for(int i = 0; i < g_repeat ; i++)
+ {
+ int s = internal::random<int>(1,EIGEN_TEST_MAX_SIZE); EIGEN_UNUSED_VARIABLE(s);
+
+ CALL_SUBTEST_1( selfadjoint(Matrix<float, 1, 1>()) );
+ CALL_SUBTEST_2( selfadjoint(Matrix<float, 2, 2>()) );
+ CALL_SUBTEST_3( selfadjoint(Matrix3cf()) );
+ CALL_SUBTEST_4( selfadjoint(MatrixXcd(s,s)) );
+ CALL_SUBTEST_5( selfadjoint(Matrix<float,Dynamic,Dynamic,RowMajor>(s, s)) );
+
+ EIGEN_UNUSED_VARIABLE(s)
+ }
+
+ CALL_SUBTEST_1( bug_159() );
+}
diff --git a/test/simplicial_cholesky.cpp b/test/simplicial_cholesky.cpp
new file mode 100644
index 000000000..e93a52e9c
--- /dev/null
+++ b/test/simplicial_cholesky.cpp
@@ -0,0 +1,40 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra.
+//
+// Copyright (C) 2011 Gael Guennebaud <g.gael@free.fr>
+//
+// This Source Code Form is subject to the terms of the Mozilla
+// Public License v. 2.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 "sparse_solver.h"
+
+template<typename T> void test_simplicial_cholesky_T()
+{
+ SimplicialCholesky<SparseMatrix<T>, Lower> chol_colmajor_lower;
+ SimplicialCholesky<SparseMatrix<T>, Upper> chol_colmajor_upper;
+ SimplicialLLT<SparseMatrix<T>, Lower> llt_colmajor_lower;
+ SimplicialLDLT<SparseMatrix<T>, Upper> llt_colmajor_upper;
+ SimplicialLDLT<SparseMatrix<T>, Lower> ldlt_colmajor_lower;
+ SimplicialLDLT<SparseMatrix<T>, Upper> ldlt_colmajor_upper;
+
+ check_sparse_spd_solving(chol_colmajor_lower);
+ check_sparse_spd_solving(chol_colmajor_upper);
+ check_sparse_spd_solving(llt_colmajor_lower);
+ check_sparse_spd_solving(llt_colmajor_upper);
+ check_sparse_spd_solving(ldlt_colmajor_lower);
+ check_sparse_spd_solving(ldlt_colmajor_upper);
+
+ check_sparse_spd_determinant(chol_colmajor_lower);
+ check_sparse_spd_determinant(chol_colmajor_upper);
+ check_sparse_spd_determinant(llt_colmajor_lower);
+ check_sparse_spd_determinant(llt_colmajor_upper);
+ check_sparse_spd_determinant(ldlt_colmajor_lower);
+ check_sparse_spd_determinant(ldlt_colmajor_upper);
+}
+
+void test_simplicial_cholesky()
+{
+ CALL_SUBTEST_1(test_simplicial_cholesky_T<double>());
+ CALL_SUBTEST_2(test_simplicial_cholesky_T<std::complex<double> >());
+}
diff --git a/test/sizeof.cpp b/test/sizeof.cpp
new file mode 100644
index 000000000..68463c9b6
--- /dev/null
+++ b/test/sizeof.cpp
@@ -0,0 +1,34 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra.
+//
+// Copyright (C) 2008 Gael Guennebaud <gael.guennebaud@inria.fr>
+//
+// This Source Code Form is subject to the terms of the Mozilla
+// Public License v. 2.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 "main.h"
+
+template<typename MatrixType> void verifySizeOf(const MatrixType&)
+{
+ typedef typename MatrixType::Scalar Scalar;
+ if (MatrixType::RowsAtCompileTime!=Dynamic && MatrixType::ColsAtCompileTime!=Dynamic)
+ VERIFY(sizeof(MatrixType)==sizeof(Scalar)*size_t(MatrixType::SizeAtCompileTime));
+ else
+ VERIFY(sizeof(MatrixType)==sizeof(Scalar*) + 2 * sizeof(typename MatrixType::Index));
+}
+
+void test_sizeof()
+{
+ CALL_SUBTEST(verifySizeOf(Matrix<float, 1, 1>()) );
+ CALL_SUBTEST(verifySizeOf(Matrix4d()) );
+ CALL_SUBTEST(verifySizeOf(Matrix<double, 4, 2>()) );
+ CALL_SUBTEST(verifySizeOf(Matrix<bool, 7, 5>()) );
+ CALL_SUBTEST(verifySizeOf(MatrixXcf(3, 3)) );
+ CALL_SUBTEST(verifySizeOf(MatrixXi(8, 12)) );
+ CALL_SUBTEST(verifySizeOf(MatrixXcd(20, 20)) );
+ CALL_SUBTEST(verifySizeOf(Matrix<float, 100, 100>()) );
+
+ VERIFY(sizeof(std::complex<float>) == 2*sizeof(float));
+ VERIFY(sizeof(std::complex<double>) == 2*sizeof(double));
+}
diff --git a/test/sizeoverflow.cpp b/test/sizeoverflow.cpp
new file mode 100644
index 000000000..16d6f8d04
--- /dev/null
+++ b/test/sizeoverflow.cpp
@@ -0,0 +1,66 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra.
+//
+// Copyright (C) 2011 Benoit Jacob <jacob.benoit.1@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 "main.h"
+
+#define VERIFY_THROWS_BADALLOC(a) { \
+ bool threw = false; \
+ try { \
+ a; \
+ } \
+ catch (std::bad_alloc&) { threw = true; } \
+ VERIFY(threw && "should have thrown bad_alloc: " #a); \
+ }
+
+typedef DenseIndex Index;
+
+template<typename MatrixType>
+void triggerMatrixBadAlloc(Index rows, Index cols)
+{
+ VERIFY_THROWS_BADALLOC( MatrixType m(rows, cols) );
+ VERIFY_THROWS_BADALLOC( MatrixType m; m.resize(rows, cols) );
+ VERIFY_THROWS_BADALLOC( MatrixType m; m.conservativeResize(rows, cols) );
+}
+
+template<typename VectorType>
+void triggerVectorBadAlloc(Index size)
+{
+ VERIFY_THROWS_BADALLOC( VectorType v(size) );
+ VERIFY_THROWS_BADALLOC( VectorType v; v.resize(size) );
+ VERIFY_THROWS_BADALLOC( VectorType v; v.conservativeResize(size) );
+}
+
+void test_sizeoverflow()
+{
+ // there are 2 levels of overflow checking. first in PlainObjectBase.h we check for overflow in rows*cols computations.
+ // this is tested in tests of the form times_itself_gives_0 * times_itself_gives_0
+ // Then in Memory.h we check for overflow in size * sizeof(T) computations.
+ // this is tested in tests of the form times_4_gives_0 * sizeof(float)
+
+ size_t times_itself_gives_0 = size_t(1) << (8 * sizeof(Index) / 2);
+ VERIFY(times_itself_gives_0 * times_itself_gives_0 == 0);
+
+ size_t times_4_gives_0 = size_t(1) << (8 * sizeof(Index) - 2);
+ VERIFY(times_4_gives_0 * 4 == 0);
+
+ size_t times_8_gives_0 = size_t(1) << (8 * sizeof(Index) - 3);
+ VERIFY(times_8_gives_0 * 8 == 0);
+
+ triggerMatrixBadAlloc<MatrixXf>(times_itself_gives_0, times_itself_gives_0);
+ triggerMatrixBadAlloc<MatrixXf>(times_itself_gives_0 / 4, times_itself_gives_0);
+ triggerMatrixBadAlloc<MatrixXf>(times_4_gives_0, 1);
+
+ triggerMatrixBadAlloc<MatrixXd>(times_itself_gives_0, times_itself_gives_0);
+ triggerMatrixBadAlloc<MatrixXd>(times_itself_gives_0 / 8, times_itself_gives_0);
+ triggerMatrixBadAlloc<MatrixXd>(times_8_gives_0, 1);
+
+ triggerVectorBadAlloc<VectorXf>(times_4_gives_0);
+
+ triggerVectorBadAlloc<VectorXd>(times_8_gives_0);
+}
diff --git a/test/smallvectors.cpp b/test/smallvectors.cpp
new file mode 100644
index 000000000..781511397
--- /dev/null
+++ b/test/smallvectors.cpp
@@ -0,0 +1,67 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra.
+//
+// Copyright (C) 2006-2008 Benoit Jacob <jacob.benoit.1@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/.
+
+#define EIGEN_NO_STATIC_ASSERT
+#include "main.h"
+
+template<typename Scalar> void smallVectors()
+{
+ typedef Matrix<Scalar, 1, 2> V2;
+ typedef Matrix<Scalar, 3, 1> V3;
+ typedef Matrix<Scalar, 1, 4> V4;
+ typedef Matrix<Scalar, Dynamic, 1> VX;
+ Scalar x1 = internal::random<Scalar>(),
+ x2 = internal::random<Scalar>(),
+ x3 = internal::random<Scalar>(),
+ x4 = internal::random<Scalar>();
+ V2 v2(x1, x2);
+ V3 v3(x1, x2, x3);
+ V4 v4(x1, x2, x3, x4);
+ VERIFY_IS_APPROX(x1, v2.x());
+ VERIFY_IS_APPROX(x1, v3.x());
+ VERIFY_IS_APPROX(x1, v4.x());
+ VERIFY_IS_APPROX(x2, v2.y());
+ VERIFY_IS_APPROX(x2, v3.y());
+ VERIFY_IS_APPROX(x2, v4.y());
+ VERIFY_IS_APPROX(x3, v3.z());
+ VERIFY_IS_APPROX(x3, v4.z());
+ VERIFY_IS_APPROX(x4, v4.w());
+
+ if (!NumTraits<Scalar>::IsInteger)
+ {
+ VERIFY_RAISES_ASSERT(V3(2, 1))
+ VERIFY_RAISES_ASSERT(V3(3, 2))
+ VERIFY_RAISES_ASSERT(V3(Scalar(3), 1))
+ VERIFY_RAISES_ASSERT(V3(3, Scalar(1)))
+ VERIFY_RAISES_ASSERT(V3(Scalar(3), Scalar(1)))
+ VERIFY_RAISES_ASSERT(V3(Scalar(123), Scalar(123)))
+
+ VERIFY_RAISES_ASSERT(V4(1, 3))
+ VERIFY_RAISES_ASSERT(V4(2, 4))
+ VERIFY_RAISES_ASSERT(V4(1, Scalar(4)))
+ VERIFY_RAISES_ASSERT(V4(Scalar(1), 4))
+ VERIFY_RAISES_ASSERT(V4(Scalar(1), Scalar(4)))
+ VERIFY_RAISES_ASSERT(V4(Scalar(123), Scalar(123)))
+
+ VERIFY_RAISES_ASSERT(VX(3, 2))
+ VERIFY_RAISES_ASSERT(VX(Scalar(3), 1))
+ VERIFY_RAISES_ASSERT(VX(3, Scalar(1)))
+ VERIFY_RAISES_ASSERT(VX(Scalar(3), Scalar(1)))
+ VERIFY_RAISES_ASSERT(VX(Scalar(123), Scalar(123)))
+ }
+}
+
+void test_smallvectors()
+{
+ for(int i = 0; i < g_repeat; i++) {
+ CALL_SUBTEST(smallVectors<int>() );
+ CALL_SUBTEST(smallVectors<float>() );
+ CALL_SUBTEST(smallVectors<double>() );
+ }
+}
diff --git a/test/sparse.h b/test/sparse.h
new file mode 100644
index 000000000..4db0004aa
--- /dev/null
+++ b/test/sparse.h
@@ -0,0 +1,182 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra.
+//
+// Copyright (C) 2008-2011 Gael Guennebaud <gael.guennebaud@inria.fr>
+//
+// This Source Code Form is subject to the terms of the Mozilla
+// Public License v. 2.0. If a copy of the MPL was not distributed
+// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+#ifndef EIGEN_TESTSPARSE_H
+#define EIGEN_TESTSPARSE_H
+
+#define EIGEN_YES_I_KNOW_SPARSE_MODULE_IS_NOT_STABLE_YET
+
+#include "main.h"
+
+#if EIGEN_GNUC_AT_LEAST(4,0) && !defined __ICC && !defined(__clang__)
+
+#ifdef min
+#undef min
+#endif
+
+#ifdef max
+#undef max
+#endif
+
+#include <tr1/unordered_map>
+#define EIGEN_UNORDERED_MAP_SUPPORT
+namespace std {
+ using std::tr1::unordered_map;
+}
+#endif
+
+#ifdef EIGEN_GOOGLEHASH_SUPPORT
+ #include <google/sparse_hash_map>
+#endif
+
+#include <Eigen/Cholesky>
+#include <Eigen/LU>
+#include <Eigen/Sparse>
+
+enum {
+ ForceNonZeroDiag = 1,
+ MakeLowerTriangular = 2,
+ MakeUpperTriangular = 4,
+ ForceRealDiag = 8
+};
+
+/* Initializes both a sparse and dense matrix with same random values,
+ * and a ratio of \a density non zero entries.
+ * \param flags is a union of ForceNonZeroDiag, MakeLowerTriangular and MakeUpperTriangular
+ * allowing to control the shape of the matrix.
+ * \param zeroCoords and nonzeroCoords allows to get the coordinate lists of the non zero,
+ * and zero coefficients respectively.
+ */
+template<typename Scalar,int Opt1,int Opt2,typename Index> void
+initSparse(double density,
+ Matrix<Scalar,Dynamic,Dynamic,Opt1>& refMat,
+ SparseMatrix<Scalar,Opt2,Index>& sparseMat,
+ int flags = 0,
+ std::vector<Vector2i>* zeroCoords = 0,
+ std::vector<Vector2i>* nonzeroCoords = 0)
+{
+ enum { IsRowMajor = SparseMatrix<Scalar,Opt2,Index>::IsRowMajor };
+ sparseMat.setZero();
+ //sparseMat.reserve(int(refMat.rows()*refMat.cols()*density));
+ sparseMat.reserve(VectorXi::Constant(IsRowMajor ? refMat.rows() : refMat.cols(), int((1.5*density)*(IsRowMajor?refMat.cols():refMat.rows()))));
+
+ for(int j=0; j<sparseMat.outerSize(); j++)
+ {
+ //sparseMat.startVec(j);
+ for(int i=0; i<sparseMat.innerSize(); i++)
+ {
+ int ai(i), aj(j);
+ if(IsRowMajor)
+ std::swap(ai,aj);
+ Scalar v = (internal::random<double>(0,1) < density) ? internal::random<Scalar>() : Scalar(0);
+ if ((flags&ForceNonZeroDiag) && (i==j))
+ {
+ v = internal::random<Scalar>()*Scalar(3.);
+ v = v*v + Scalar(5.);
+ }
+ if ((flags & MakeLowerTriangular) && aj>ai)
+ v = Scalar(0);
+ else if ((flags & MakeUpperTriangular) && aj<ai)
+ v = Scalar(0);
+
+ if ((flags&ForceRealDiag) && (i==j))
+ v = internal::real(v);
+
+ if (v!=Scalar(0))
+ {
+ //sparseMat.insertBackByOuterInner(j,i) = v;
+ sparseMat.insertByOuterInner(j,i) = v;
+ if (nonzeroCoords)
+ nonzeroCoords->push_back(Vector2i(ai,aj));
+ }
+ else if (zeroCoords)
+ {
+ zeroCoords->push_back(Vector2i(ai,aj));
+ }
+ refMat(ai,aj) = v;
+ }
+ }
+ //sparseMat.finalize();
+}
+
+template<typename Scalar,int Opt1,int Opt2,typename Index> void
+initSparse(double density,
+ Matrix<Scalar,Dynamic,Dynamic, Opt1>& refMat,
+ DynamicSparseMatrix<Scalar, Opt2, Index>& sparseMat,
+ int flags = 0,
+ std::vector<Vector2i>* zeroCoords = 0,
+ std::vector<Vector2i>* nonzeroCoords = 0)
+{
+ enum { IsRowMajor = DynamicSparseMatrix<Scalar,Opt2,Index>::IsRowMajor };
+ sparseMat.setZero();
+ sparseMat.reserve(int(refMat.rows()*refMat.cols()*density));
+ for(int j=0; j<sparseMat.outerSize(); j++)
+ {
+ sparseMat.startVec(j); // not needed for DynamicSparseMatrix
+ for(int i=0; i<sparseMat.innerSize(); i++)
+ {
+ int ai(i), aj(j);
+ if(IsRowMajor)
+ std::swap(ai,aj);
+ Scalar v = (internal::random<double>(0,1) < density) ? internal::random<Scalar>() : Scalar(0);
+ if ((flags&ForceNonZeroDiag) && (i==j))
+ {
+ v = internal::random<Scalar>()*Scalar(3.);
+ v = v*v + Scalar(5.);
+ }
+ if ((flags & MakeLowerTriangular) && aj>ai)
+ v = Scalar(0);
+ else if ((flags & MakeUpperTriangular) && aj<ai)
+ v = Scalar(0);
+
+ if ((flags&ForceRealDiag) && (i==j))
+ v = internal::real(v);
+
+ if (v!=Scalar(0))
+ {
+ sparseMat.insertBackByOuterInner(j,i) = v;
+ if (nonzeroCoords)
+ nonzeroCoords->push_back(Vector2i(ai,aj));
+ }
+ else if (zeroCoords)
+ {
+ zeroCoords->push_back(Vector2i(ai,aj));
+ }
+ refMat(ai,aj) = v;
+ }
+ }
+ sparseMat.finalize();
+}
+
+template<typename Scalar> void
+initSparse(double density,
+ Matrix<Scalar,Dynamic,1>& refVec,
+ SparseVector<Scalar>& sparseVec,
+ std::vector<int>* zeroCoords = 0,
+ std::vector<int>* nonzeroCoords = 0)
+{
+ sparseVec.reserve(int(refVec.size()*density));
+ sparseVec.setZero();
+ for(int i=0; i<refVec.size(); i++)
+ {
+ Scalar v = (internal::random<double>(0,1) < density) ? internal::random<Scalar>() : Scalar(0);
+ if (v!=Scalar(0))
+ {
+ sparseVec.insertBack(i) = v;
+ if (nonzeroCoords)
+ nonzeroCoords->push_back(i);
+ }
+ else if (zeroCoords)
+ zeroCoords->push_back(i);
+ refVec[i] = v;
+ }
+}
+
+#include <unsupported/Eigen/SparseExtra>
+#endif // EIGEN_TESTSPARSE_H
diff --git a/test/sparse_basic.cpp b/test/sparse_basic.cpp
new file mode 100644
index 000000000..8897a9dca
--- /dev/null
+++ b/test/sparse_basic.cpp
@@ -0,0 +1,395 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra.
+//
+// Copyright (C) 2008-2011 Gael Guennebaud <gael.guennebaud@inria.fr>
+// Copyright (C) 2008 Daniel Gomez Ferro <dgomezferro@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 "sparse.h"
+
+template<typename SparseMatrixType> void sparse_basic(const SparseMatrixType& ref)
+{
+ typedef typename SparseMatrixType::Index Index;
+
+ const Index rows = ref.rows();
+ const Index cols = ref.cols();
+ typedef typename SparseMatrixType::Scalar Scalar;
+ enum { Flags = SparseMatrixType::Flags };
+
+ double density = (std::max)(8./(rows*cols), 0.01);
+ typedef Matrix<Scalar,Dynamic,Dynamic> DenseMatrix;
+ typedef Matrix<Scalar,Dynamic,1> DenseVector;
+ Scalar eps = 1e-6;
+
+ SparseMatrixType m(rows, cols);
+ DenseMatrix refMat = DenseMatrix::Zero(rows, cols);
+ DenseVector vec1 = DenseVector::Random(rows);
+ Scalar s1 = internal::random<Scalar>();
+
+ std::vector<Vector2i> zeroCoords;
+ std::vector<Vector2i> nonzeroCoords;
+ initSparse<Scalar>(density, refMat, m, 0, &zeroCoords, &nonzeroCoords);
+
+ if (zeroCoords.size()==0 || nonzeroCoords.size()==0)
+ return;
+
+ // test coeff and coeffRef
+ for (int i=0; i<(int)zeroCoords.size(); ++i)
+ {
+ VERIFY_IS_MUCH_SMALLER_THAN( m.coeff(zeroCoords[i].x(),zeroCoords[i].y()), eps );
+ if(internal::is_same<SparseMatrixType,SparseMatrix<Scalar,Flags> >::value)
+ VERIFY_RAISES_ASSERT( m.coeffRef(zeroCoords[0].x(),zeroCoords[0].y()) = 5 );
+ }
+ VERIFY_IS_APPROX(m, refMat);
+
+ m.coeffRef(nonzeroCoords[0].x(), nonzeroCoords[0].y()) = Scalar(5);
+ refMat.coeffRef(nonzeroCoords[0].x(), nonzeroCoords[0].y()) = Scalar(5);
+
+ VERIFY_IS_APPROX(m, refMat);
+ /*
+ // test InnerIterators and Block expressions
+ for (int t=0; t<10; ++t)
+ {
+ int j = internal::random<int>(0,cols-1);
+ int i = internal::random<int>(0,rows-1);
+ int w = internal::random<int>(1,cols-j-1);
+ int h = internal::random<int>(1,rows-i-1);
+
+// VERIFY_IS_APPROX(m.block(i,j,h,w), refMat.block(i,j,h,w));
+ for(int c=0; c<w; c++)
+ {
+ VERIFY_IS_APPROX(m.block(i,j,h,w).col(c), refMat.block(i,j,h,w).col(c));
+ for(int r=0; r<h; r++)
+ {
+// VERIFY_IS_APPROX(m.block(i,j,h,w).col(c).coeff(r), refMat.block(i,j,h,w).col(c).coeff(r));
+ }
+ }
+// for(int r=0; r<h; r++)
+// {
+// VERIFY_IS_APPROX(m.block(i,j,h,w).row(r), refMat.block(i,j,h,w).row(r));
+// for(int c=0; c<w; c++)
+// {
+// VERIFY_IS_APPROX(m.block(i,j,h,w).row(r).coeff(c), refMat.block(i,j,h,w).row(r).coeff(c));
+// }
+// }
+ }
+
+ for(int c=0; c<cols; c++)
+ {
+ VERIFY_IS_APPROX(m.col(c) + m.col(c), (m + m).col(c));
+ VERIFY_IS_APPROX(m.col(c) + m.col(c), refMat.col(c) + refMat.col(c));
+ }
+
+ for(int r=0; r<rows; r++)
+ {
+ VERIFY_IS_APPROX(m.row(r) + m.row(r), (m + m).row(r));
+ VERIFY_IS_APPROX(m.row(r) + m.row(r), refMat.row(r) + refMat.row(r));
+ }
+ */
+
+ // test insert (inner random)
+ {
+ DenseMatrix m1(rows,cols);
+ m1.setZero();
+ SparseMatrixType m2(rows,cols);
+ if(internal::random<int>()%2)
+ m2.reserve(VectorXi::Constant(m2.outerSize(), 2));
+ for (int j=0; j<cols; ++j)
+ {
+ for (int k=0; k<rows/2; ++k)
+ {
+ int i = internal::random<int>(0,rows-1);
+ if (m1.coeff(i,j)==Scalar(0))
+ m2.insert(i,j) = m1(i,j) = internal::random<Scalar>();
+ }
+ }
+ m2.finalize();
+ VERIFY_IS_APPROX(m2,m1);
+ }
+
+ // test insert (fully random)
+ {
+ DenseMatrix m1(rows,cols);
+ m1.setZero();
+ SparseMatrixType m2(rows,cols);
+ if(internal::random<int>()%2)
+ m2.reserve(VectorXi::Constant(m2.outerSize(), 2));
+ for (int k=0; k<rows*cols; ++k)
+ {
+ int i = internal::random<int>(0,rows-1);
+ int j = internal::random<int>(0,cols-1);
+ if ((m1.coeff(i,j)==Scalar(0)) && (internal::random<int>()%2))
+ m2.insert(i,j) = m1(i,j) = internal::random<Scalar>();
+ else
+ {
+ Scalar v = internal::random<Scalar>();
+ m2.coeffRef(i,j) += v;
+ m1(i,j) += v;
+ }
+ }
+ VERIFY_IS_APPROX(m2,m1);
+ }
+
+ // test insert (un-compressed)
+ for(int mode=0;mode<4;++mode)
+ {
+ DenseMatrix m1(rows,cols);
+ m1.setZero();
+ SparseMatrixType m2(rows,cols);
+ VectorXi r(VectorXi::Constant(m2.outerSize(), ((mode%2)==0) ? m2.innerSize() : std::max<int>(1,m2.innerSize()/8)));
+ m2.reserve(r);
+ for (int k=0; k<rows*cols; ++k)
+ {
+ int i = internal::random<int>(0,rows-1);
+ int j = internal::random<int>(0,cols-1);
+ if (m1.coeff(i,j)==Scalar(0))
+ m2.insert(i,j) = m1(i,j) = internal::random<Scalar>();
+ if(mode==3)
+ m2.reserve(r);
+ }
+ if(internal::random<int>()%2)
+ m2.makeCompressed();
+ VERIFY_IS_APPROX(m2,m1);
+ }
+
+ // test basic computations
+ {
+ DenseMatrix refM1 = DenseMatrix::Zero(rows, rows);
+ DenseMatrix refM2 = DenseMatrix::Zero(rows, rows);
+ DenseMatrix refM3 = DenseMatrix::Zero(rows, rows);
+ DenseMatrix refM4 = DenseMatrix::Zero(rows, rows);
+ SparseMatrixType m1(rows, rows);
+ SparseMatrixType m2(rows, rows);
+ SparseMatrixType m3(rows, rows);
+ SparseMatrixType m4(rows, rows);
+ initSparse<Scalar>(density, refM1, m1);
+ initSparse<Scalar>(density, refM2, m2);
+ initSparse<Scalar>(density, refM3, m3);
+ initSparse<Scalar>(density, refM4, m4);
+
+ VERIFY_IS_APPROX(m1+m2, refM1+refM2);
+ VERIFY_IS_APPROX(m1+m2+m3, refM1+refM2+refM3);
+ VERIFY_IS_APPROX(m3.cwiseProduct(m1+m2), refM3.cwiseProduct(refM1+refM2));
+ VERIFY_IS_APPROX(m1*s1-m2, refM1*s1-refM2);
+
+ VERIFY_IS_APPROX(m1*=s1, refM1*=s1);
+ VERIFY_IS_APPROX(m1/=s1, refM1/=s1);
+
+ VERIFY_IS_APPROX(m1+=m2, refM1+=refM2);
+ VERIFY_IS_APPROX(m1-=m2, refM1-=refM2);
+
+ if(SparseMatrixType::IsRowMajor)
+ VERIFY_IS_APPROX(m1.innerVector(0).dot(refM2.row(0)), refM1.row(0).dot(refM2.row(0)));
+ else
+ VERIFY_IS_APPROX(m1.innerVector(0).dot(refM2.row(0)), refM1.col(0).dot(refM2.row(0)));
+
+ VERIFY_IS_APPROX(m1.conjugate(), refM1.conjugate());
+ VERIFY_IS_APPROX(m1.real(), refM1.real());
+
+ refM4.setRandom();
+ // sparse cwise* dense
+ VERIFY_IS_APPROX(m3.cwiseProduct(refM4), refM3.cwiseProduct(refM4));
+// VERIFY_IS_APPROX(m3.cwise()/refM4, refM3.cwise()/refM4);
+ }
+
+ // test transpose
+ {
+ DenseMatrix refMat2 = DenseMatrix::Zero(rows, rows);
+ SparseMatrixType m2(rows, rows);
+ initSparse<Scalar>(density, refMat2, m2);
+ VERIFY_IS_APPROX(m2.transpose().eval(), refMat2.transpose().eval());
+ VERIFY_IS_APPROX(m2.transpose(), refMat2.transpose());
+
+ VERIFY_IS_APPROX(SparseMatrixType(m2.adjoint()), refMat2.adjoint());
+ }
+
+ // test innerVector()
+ {
+ DenseMatrix refMat2 = DenseMatrix::Zero(rows, rows);
+ SparseMatrixType m2(rows, rows);
+ initSparse<Scalar>(density, refMat2, m2);
+ int j0 = internal::random<int>(0,rows-1);
+ int j1 = internal::random<int>(0,rows-1);
+ if(SparseMatrixType::IsRowMajor)
+ VERIFY_IS_APPROX(m2.innerVector(j0), refMat2.row(j0));
+ else
+ VERIFY_IS_APPROX(m2.innerVector(j0), refMat2.col(j0));
+
+ if(SparseMatrixType::IsRowMajor)
+ VERIFY_IS_APPROX(m2.innerVector(j0)+m2.innerVector(j1), refMat2.row(j0)+refMat2.row(j1));
+ else
+ VERIFY_IS_APPROX(m2.innerVector(j0)+m2.innerVector(j1), refMat2.col(j0)+refMat2.col(j1));
+
+ SparseMatrixType m3(rows,rows);
+ m3.reserve(VectorXi::Constant(rows,rows/2));
+ for(int j=0; j<rows; ++j)
+ for(int k=0; k<j; ++k)
+ m3.insertByOuterInner(j,k) = k+1;
+ for(int j=0; j<rows; ++j)
+ {
+ VERIFY(j==internal::real(m3.innerVector(j).nonZeros()));
+ if(j>0)
+ VERIFY(j==internal::real(m3.innerVector(j).lastCoeff()));
+ }
+ m3.makeCompressed();
+ for(int j=0; j<rows; ++j)
+ {
+ VERIFY(j==internal::real(m3.innerVector(j).nonZeros()));
+ if(j>0)
+ VERIFY(j==internal::real(m3.innerVector(j).lastCoeff()));
+ }
+
+ //m2.innerVector(j0) = 2*m2.innerVector(j1);
+ //refMat2.col(j0) = 2*refMat2.col(j1);
+ //VERIFY_IS_APPROX(m2, refMat2);
+ }
+
+ // test innerVectors()
+ {
+ DenseMatrix refMat2 = DenseMatrix::Zero(rows, rows);
+ SparseMatrixType m2(rows, rows);
+ initSparse<Scalar>(density, refMat2, m2);
+ int j0 = internal::random<int>(0,rows-2);
+ int j1 = internal::random<int>(0,rows-2);
+ int n0 = internal::random<int>(1,rows-(std::max)(j0,j1));
+ if(SparseMatrixType::IsRowMajor)
+ VERIFY_IS_APPROX(m2.innerVectors(j0,n0), refMat2.block(j0,0,n0,cols));
+ else
+ VERIFY_IS_APPROX(m2.innerVectors(j0,n0), refMat2.block(0,j0,rows,n0));
+ if(SparseMatrixType::IsRowMajor)
+ VERIFY_IS_APPROX(m2.innerVectors(j0,n0)+m2.innerVectors(j1,n0),
+ refMat2.block(j0,0,n0,cols)+refMat2.block(j1,0,n0,cols));
+ else
+ VERIFY_IS_APPROX(m2.innerVectors(j0,n0)+m2.innerVectors(j1,n0),
+ refMat2.block(0,j0,rows,n0)+refMat2.block(0,j1,rows,n0));
+ //m2.innerVectors(j0,n0) = m2.innerVectors(j0,n0) + m2.innerVectors(j1,n0);
+ //refMat2.block(0,j0,rows,n0) = refMat2.block(0,j0,rows,n0) + refMat2.block(0,j1,rows,n0);
+ }
+
+ // test prune
+ {
+ SparseMatrixType m2(rows, rows);
+ DenseMatrix refM2(rows, rows);
+ refM2.setZero();
+ int countFalseNonZero = 0;
+ int countTrueNonZero = 0;
+ for (int j=0; j<m2.outerSize(); ++j)
+ {
+ m2.startVec(j);
+ for (int i=0; i<m2.innerSize(); ++i)
+ {
+ float x = internal::random<float>(0,1);
+ if (x<0.1)
+ {
+ // do nothing
+ }
+ else if (x<0.5)
+ {
+ countFalseNonZero++;
+ m2.insertBackByOuterInner(j,i) = Scalar(0);
+ }
+ else
+ {
+ countTrueNonZero++;
+ m2.insertBackByOuterInner(j,i) = Scalar(1);
+ if(SparseMatrixType::IsRowMajor)
+ refM2(j,i) = Scalar(1);
+ else
+ refM2(i,j) = Scalar(1);
+ }
+ }
+ }
+ m2.finalize();
+ VERIFY(countFalseNonZero+countTrueNonZero == m2.nonZeros());
+ VERIFY_IS_APPROX(m2, refM2);
+ m2.prune(Scalar(1));
+ VERIFY(countTrueNonZero==m2.nonZeros());
+ VERIFY_IS_APPROX(m2, refM2);
+ }
+
+ // test setFromTriplets
+ {
+ typedef Triplet<Scalar,Index> TripletType;
+ std::vector<TripletType> triplets;
+ int ntriplets = rows*cols;
+ triplets.reserve(ntriplets);
+ DenseMatrix refMat(rows,cols);
+ refMat.setZero();
+ for(int i=0;i<ntriplets;++i)
+ {
+ int r = internal::random<int>(0,rows-1);
+ int c = internal::random<int>(0,cols-1);
+ Scalar v = internal::random<Scalar>();
+ triplets.push_back(TripletType(r,c,v));
+ refMat(r,c) += v;
+ }
+ SparseMatrixType m(rows,cols);
+ m.setFromTriplets(triplets.begin(), triplets.end());
+ VERIFY_IS_APPROX(m, refMat);
+ }
+
+ // test triangularView
+ {
+ DenseMatrix refMat2(rows, rows), refMat3(rows, rows);
+ SparseMatrixType m2(rows, rows), m3(rows, rows);
+ initSparse<Scalar>(density, refMat2, m2);
+ refMat3 = refMat2.template triangularView<Lower>();
+ m3 = m2.template triangularView<Lower>();
+ VERIFY_IS_APPROX(m3, refMat3);
+
+ refMat3 = refMat2.template triangularView<Upper>();
+ m3 = m2.template triangularView<Upper>();
+ VERIFY_IS_APPROX(m3, refMat3);
+
+ refMat3 = refMat2.template triangularView<UnitUpper>();
+ m3 = m2.template triangularView<UnitUpper>();
+ VERIFY_IS_APPROX(m3, refMat3);
+
+ refMat3 = refMat2.template triangularView<UnitLower>();
+ m3 = m2.template triangularView<UnitLower>();
+ VERIFY_IS_APPROX(m3, refMat3);
+ }
+
+ // test selfadjointView
+ if(!SparseMatrixType::IsRowMajor)
+ {
+ DenseMatrix refMat2(rows, rows), refMat3(rows, rows);
+ SparseMatrixType m2(rows, rows), m3(rows, rows);
+ initSparse<Scalar>(density, refMat2, m2);
+ refMat3 = refMat2.template selfadjointView<Lower>();
+ m3 = m2.template selfadjointView<Lower>();
+ VERIFY_IS_APPROX(m3, refMat3);
+ }
+
+ // test sparseView
+ {
+ DenseMatrix refMat2 = DenseMatrix::Zero(rows, rows);
+ SparseMatrixType m2(rows, rows);
+ initSparse<Scalar>(density, refMat2, m2);
+ VERIFY_IS_APPROX(m2.eval(), refMat2.sparseView().eval());
+ }
+
+ // test diagonal
+ {
+ DenseMatrix refMat2 = DenseMatrix::Zero(rows, rows);
+ SparseMatrixType m2(rows, rows);
+ initSparse<Scalar>(density, refMat2, m2);
+ VERIFY_IS_APPROX(m2.diagonal(), refMat2.diagonal().eval());
+ }
+}
+
+void test_sparse_basic()
+{
+ for(int i = 0; i < g_repeat; i++) {
+ int s = Eigen::internal::random<int>(1,50);
+ CALL_SUBTEST_1(( sparse_basic(SparseMatrix<double>(8, 8)) ));
+ CALL_SUBTEST_2(( sparse_basic(SparseMatrix<std::complex<double>, ColMajor>(s, s)) ));
+ CALL_SUBTEST_2(( sparse_basic(SparseMatrix<std::complex<double>, RowMajor>(s, s)) ));
+ CALL_SUBTEST_1(( sparse_basic(SparseMatrix<double>(s, s)) ));
+ CALL_SUBTEST_1(( sparse_basic(SparseMatrix<double,ColMajor,long int>(s, s)) ));
+ CALL_SUBTEST_1(( sparse_basic(SparseMatrix<double,RowMajor,long int>(s, s)) ));
+ }
+}
diff --git a/test/sparse_permutations.cpp b/test/sparse_permutations.cpp
new file mode 100644
index 000000000..e4ce1d679
--- /dev/null
+++ b/test/sparse_permutations.cpp
@@ -0,0 +1,187 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra.
+//
+// Copyright (C) 2011 Gael Guennebaud <gael.guennebaud@inria.fr>
+//
+// This Source Code Form is subject to the terms of the Mozilla
+// Public License v. 2.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 "sparse.h"
+
+template<int OtherStorage, typename SparseMatrixType> void sparse_permutations(const SparseMatrixType& ref)
+{
+ typedef typename SparseMatrixType::Index Index;
+
+ const Index rows = ref.rows();
+ const Index cols = ref.cols();
+ typedef typename SparseMatrixType::Scalar Scalar;
+ typedef typename SparseMatrixType::Index Index;
+ typedef SparseMatrix<Scalar, OtherStorage, Index> OtherSparseMatrixType;
+ typedef Matrix<Scalar,Dynamic,Dynamic> DenseMatrix;
+ typedef Matrix<Index,Dynamic,1> VectorI;
+
+ double density = (std::max)(8./(rows*cols), 0.01);
+
+ SparseMatrixType mat(rows, cols), up(rows,cols), lo(rows,cols);
+ OtherSparseMatrixType res;
+ DenseMatrix mat_d = DenseMatrix::Zero(rows, cols), up_sym_d, lo_sym_d, res_d;
+
+ initSparse<Scalar>(density, mat_d, mat, 0);
+
+ up = mat.template triangularView<Upper>();
+ lo = mat.template triangularView<Lower>();
+
+ up_sym_d = mat_d.template selfadjointView<Upper>();
+ lo_sym_d = mat_d.template selfadjointView<Lower>();
+
+ VERIFY_IS_APPROX(mat, mat_d);
+ VERIFY_IS_APPROX(up, DenseMatrix(mat_d.template triangularView<Upper>()));
+ VERIFY_IS_APPROX(lo, DenseMatrix(mat_d.template triangularView<Lower>()));
+
+ PermutationMatrix<Dynamic> p, p_null;
+ VectorI pi;
+ randomPermutationVector(pi, cols);
+ p.indices() = pi;
+
+ res = mat*p;
+ res_d = mat_d*p;
+ VERIFY(res.isApprox(res_d) && "mat*p");
+
+ res = p*mat;
+ res_d = p*mat_d;
+ VERIFY(res.isApprox(res_d) && "p*mat");
+
+ res = mat*p.inverse();
+ res_d = mat*p.inverse();
+ VERIFY(res.isApprox(res_d) && "mat*inv(p)");
+
+ res = p.inverse()*mat;
+ res_d = p.inverse()*mat_d;
+ VERIFY(res.isApprox(res_d) && "inv(p)*mat");
+
+ res = mat.twistedBy(p);
+ res_d = (p * mat_d) * p.inverse();
+ VERIFY(res.isApprox(res_d) && "p*mat*inv(p)");
+
+
+ res = mat.template selfadjointView<Upper>().twistedBy(p_null);
+ res_d = up_sym_d;
+ VERIFY(res.isApprox(res_d) && "full selfadjoint upper to full");
+
+ res = mat.template selfadjointView<Lower>().twistedBy(p_null);
+ res_d = lo_sym_d;
+ VERIFY(res.isApprox(res_d) && "full selfadjoint lower to full");
+
+
+ res = up.template selfadjointView<Upper>().twistedBy(p_null);
+ res_d = up_sym_d;
+ VERIFY(res.isApprox(res_d) && "upper selfadjoint to full");
+
+ res = lo.template selfadjointView<Lower>().twistedBy(p_null);
+ res_d = lo_sym_d;
+ VERIFY(res.isApprox(res_d) && "lower selfadjoint full");
+
+
+ res = mat.template selfadjointView<Upper>();
+ res_d = up_sym_d;
+ VERIFY(res.isApprox(res_d) && "full selfadjoint upper to full");
+
+ res = mat.template selfadjointView<Lower>();
+ res_d = lo_sym_d;
+ VERIFY(res.isApprox(res_d) && "full selfadjoint lower to full");
+
+ res = up.template selfadjointView<Upper>();
+ res_d = up_sym_d;
+ VERIFY(res.isApprox(res_d) && "upper selfadjoint to full");
+
+ res = lo.template selfadjointView<Lower>();
+ res_d = lo_sym_d;
+ VERIFY(res.isApprox(res_d) && "lower selfadjoint full");
+
+
+ res.template selfadjointView<Upper>() = mat.template selfadjointView<Upper>();
+ res_d = up_sym_d.template triangularView<Upper>();
+ VERIFY(res.isApprox(res_d) && "full selfadjoint upper to upper");
+
+ res.template selfadjointView<Lower>() = mat.template selfadjointView<Upper>();
+ res_d = up_sym_d.template triangularView<Lower>();
+ VERIFY(res.isApprox(res_d) && "full selfadjoint upper to lower");
+
+ res.template selfadjointView<Upper>() = mat.template selfadjointView<Lower>();
+ res_d = lo_sym_d.template triangularView<Upper>();
+ VERIFY(res.isApprox(res_d) && "full selfadjoint lower to upper");
+
+ res.template selfadjointView<Lower>() = mat.template selfadjointView<Lower>();
+ res_d = lo_sym_d.template triangularView<Lower>();
+ VERIFY(res.isApprox(res_d) && "full selfadjoint lower to lower");
+
+
+
+ res.template selfadjointView<Upper>() = mat.template selfadjointView<Upper>().twistedBy(p);
+ res_d = ((p * up_sym_d) * p.inverse()).eval().template triangularView<Upper>();
+ VERIFY(res.isApprox(res_d) && "full selfadjoint upper twisted to upper");
+
+ res.template selfadjointView<Upper>() = mat.template selfadjointView<Lower>().twistedBy(p);
+ res_d = ((p * lo_sym_d) * p.inverse()).eval().template triangularView<Upper>();
+ VERIFY(res.isApprox(res_d) && "full selfadjoint lower twisted to upper");
+
+ res.template selfadjointView<Lower>() = mat.template selfadjointView<Lower>().twistedBy(p);
+ res_d = ((p * lo_sym_d) * p.inverse()).eval().template triangularView<Lower>();
+ VERIFY(res.isApprox(res_d) && "full selfadjoint lower twisted to lower");
+
+ res.template selfadjointView<Lower>() = mat.template selfadjointView<Upper>().twistedBy(p);
+ res_d = ((p * up_sym_d) * p.inverse()).eval().template triangularView<Lower>();
+ VERIFY(res.isApprox(res_d) && "full selfadjoint upper twisted to lower");
+
+
+ res.template selfadjointView<Upper>() = up.template selfadjointView<Upper>().twistedBy(p);
+ res_d = ((p * up_sym_d) * p.inverse()).eval().template triangularView<Upper>();
+ VERIFY(res.isApprox(res_d) && "upper selfadjoint twisted to upper");
+
+ res.template selfadjointView<Upper>() = lo.template selfadjointView<Lower>().twistedBy(p);
+ res_d = ((p * lo_sym_d) * p.inverse()).eval().template triangularView<Upper>();
+ VERIFY(res.isApprox(res_d) && "lower selfadjoint twisted to upper");
+
+ res.template selfadjointView<Lower>() = lo.template selfadjointView<Lower>().twistedBy(p);
+ res_d = ((p * lo_sym_d) * p.inverse()).eval().template triangularView<Lower>();
+ VERIFY(res.isApprox(res_d) && "lower selfadjoint twisted to lower");
+
+ res.template selfadjointView<Lower>() = up.template selfadjointView<Upper>().twistedBy(p);
+ res_d = ((p * up_sym_d) * p.inverse()).eval().template triangularView<Lower>();
+ VERIFY(res.isApprox(res_d) && "upper selfadjoint twisted to lower");
+
+
+ res = mat.template selfadjointView<Upper>().twistedBy(p);
+ res_d = (p * up_sym_d) * p.inverse();
+ VERIFY(res.isApprox(res_d) && "full selfadjoint upper twisted to full");
+
+ res = mat.template selfadjointView<Lower>().twistedBy(p);
+ res_d = (p * lo_sym_d) * p.inverse();
+ VERIFY(res.isApprox(res_d) && "full selfadjoint lower twisted to full");
+
+ res = up.template selfadjointView<Upper>().twistedBy(p);
+ res_d = (p * up_sym_d) * p.inverse();
+ VERIFY(res.isApprox(res_d) && "upper selfadjoint twisted to full");
+
+ res = lo.template selfadjointView<Lower>().twistedBy(p);
+ res_d = (p * lo_sym_d) * p.inverse();
+ VERIFY(res.isApprox(res_d) && "lower selfadjoint twisted to full");
+}
+
+template<typename Scalar> void sparse_permutations_all(int size)
+{
+ CALL_SUBTEST(( sparse_permutations<ColMajor>(SparseMatrix<Scalar, ColMajor>(size,size)) ));
+ CALL_SUBTEST(( sparse_permutations<ColMajor>(SparseMatrix<Scalar, RowMajor>(size,size)) ));
+ CALL_SUBTEST(( sparse_permutations<RowMajor>(SparseMatrix<Scalar, ColMajor>(size,size)) ));
+ CALL_SUBTEST(( sparse_permutations<RowMajor>(SparseMatrix<Scalar, RowMajor>(size,size)) ));
+}
+
+void test_sparse_permutations()
+{
+ for(int i = 0; i < g_repeat; i++) {
+ int s = Eigen::internal::random<int>(1,50);
+ CALL_SUBTEST_1(( sparse_permutations_all<double>(s) ));
+ CALL_SUBTEST_2(( sparse_permutations_all<std::complex<double> >(s) ));
+ }
+}
diff --git a/test/sparse_product.cpp b/test/sparse_product.cpp
new file mode 100644
index 000000000..17a955c9d
--- /dev/null
+++ b/test/sparse_product.cpp
@@ -0,0 +1,204 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra.
+//
+// Copyright (C) 2008-2011 Gael Guennebaud <gael.guennebaud@inria.fr>
+//
+// This Source Code Form is subject to the terms of the Mozilla
+// Public License v. 2.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 "sparse.h"
+
+template<typename SparseMatrixType, typename DenseMatrix, bool IsRowMajor=SparseMatrixType::IsRowMajor> struct test_outer;
+
+template<typename SparseMatrixType, typename DenseMatrix> struct test_outer<SparseMatrixType,DenseMatrix,false> {
+ static void run(SparseMatrixType& m2, SparseMatrixType& m4, DenseMatrix& refMat2, DenseMatrix& refMat4) {
+ int c = internal::random(0,m2.cols()-1);
+ int c1 = internal::random(0,m2.cols()-1);
+ VERIFY_IS_APPROX(m4=m2.col(c)*refMat2.col(c1).transpose(), refMat4=refMat2.col(c)*refMat2.col(c1).transpose());
+ VERIFY_IS_APPROX(m4=refMat2.col(c1)*m2.col(c).transpose(), refMat4=refMat2.col(c1)*refMat2.col(c).transpose());
+ }
+};
+
+template<typename SparseMatrixType, typename DenseMatrix> struct test_outer<SparseMatrixType,DenseMatrix,true> {
+ static void run(SparseMatrixType& m2, SparseMatrixType& m4, DenseMatrix& refMat2, DenseMatrix& refMat4) {
+ int r = internal::random(0,m2.rows()-1);
+ int c1 = internal::random(0,m2.cols()-1);
+ VERIFY_IS_APPROX(m4=m2.row(r).transpose()*refMat2.col(c1).transpose(), refMat4=refMat2.row(r).transpose()*refMat2.col(c1).transpose());
+ VERIFY_IS_APPROX(m4=refMat2.col(c1)*m2.row(r), refMat4=refMat2.col(c1)*refMat2.row(r));
+ }
+};
+
+// (m2,m4,refMat2,refMat4,dv1);
+// VERIFY_IS_APPROX(m4=m2.innerVector(c)*dv1.transpose(), refMat4=refMat2.colVector(c)*dv1.transpose());
+// VERIFY_IS_APPROX(m4=dv1*mcm.col(c).transpose(), refMat4=dv1*refMat2.col(c).transpose());
+
+template<typename SparseMatrixType> void sparse_product()
+{
+ typedef typename SparseMatrixType::Index Index;
+ Index n = 100;
+ const Index rows = internal::random<int>(1,n);
+ const Index cols = internal::random<int>(1,n);
+ const Index depth = internal::random<int>(1,n);
+ typedef typename SparseMatrixType::Scalar Scalar;
+ enum { Flags = SparseMatrixType::Flags };
+
+ double density = (std::max)(8./(rows*cols), 0.01);
+ typedef Matrix<Scalar,Dynamic,Dynamic> DenseMatrix;
+ typedef Matrix<Scalar,Dynamic,1> DenseVector;
+
+ Scalar s1 = internal::random<Scalar>();
+ Scalar s2 = internal::random<Scalar>();
+
+ // test matrix-matrix product
+ {
+ DenseMatrix refMat2 = DenseMatrix::Zero(rows, depth);
+ DenseMatrix refMat2t = DenseMatrix::Zero(depth, rows);
+ DenseMatrix refMat3 = DenseMatrix::Zero(depth, cols);
+ DenseMatrix refMat3t = DenseMatrix::Zero(cols, depth);
+ DenseMatrix refMat4 = DenseMatrix::Zero(rows, cols);
+ DenseMatrix refMat4t = DenseMatrix::Zero(cols, rows);
+ DenseMatrix refMat5 = DenseMatrix::Random(depth, cols);
+ DenseMatrix refMat6 = DenseMatrix::Random(rows, rows);
+ DenseMatrix dm4 = DenseMatrix::Zero(rows, rows);
+// DenseVector dv1 = DenseVector::Random(rows);
+ SparseMatrixType m2 (rows, depth);
+ SparseMatrixType m2t(depth, rows);
+ SparseMatrixType m3 (depth, cols);
+ SparseMatrixType m3t(cols, depth);
+ SparseMatrixType m4 (rows, cols);
+ SparseMatrixType m4t(cols, rows);
+ SparseMatrixType m6(rows, rows);
+ initSparse(density, refMat2, m2);
+ initSparse(density, refMat2t, m2t);
+ initSparse(density, refMat3, m3);
+ initSparse(density, refMat3t, m3t);
+ initSparse(density, refMat4, m4);
+ initSparse(density, refMat4t, m4t);
+ initSparse(density, refMat6, m6);
+
+// int c = internal::random<int>(0,depth-1);
+
+ // sparse * sparse
+ VERIFY_IS_APPROX(m4=m2*m3, refMat4=refMat2*refMat3);
+ VERIFY_IS_APPROX(m4=m2t.transpose()*m3, refMat4=refMat2t.transpose()*refMat3);
+ VERIFY_IS_APPROX(m4=m2t.transpose()*m3t.transpose(), refMat4=refMat2t.transpose()*refMat3t.transpose());
+ VERIFY_IS_APPROX(m4=m2*m3t.transpose(), refMat4=refMat2*refMat3t.transpose());
+
+ VERIFY_IS_APPROX(m4 = m2*m3/s1, refMat4 = refMat2*refMat3/s1);
+ VERIFY_IS_APPROX(m4 = m2*m3*s1, refMat4 = refMat2*refMat3*s1);
+ VERIFY_IS_APPROX(m4 = s2*m2*m3*s1, refMat4 = s2*refMat2*refMat3*s1);
+
+ VERIFY_IS_APPROX(m4=(m2*m3).pruned(0), refMat4=refMat2*refMat3);
+ VERIFY_IS_APPROX(m4=(m2t.transpose()*m3).pruned(0), refMat4=refMat2t.transpose()*refMat3);
+ VERIFY_IS_APPROX(m4=(m2t.transpose()*m3t.transpose()).pruned(0), refMat4=refMat2t.transpose()*refMat3t.transpose());
+ VERIFY_IS_APPROX(m4=(m2*m3t.transpose()).pruned(0), refMat4=refMat2*refMat3t.transpose());
+
+ // test aliasing
+ m4 = m2; refMat4 = refMat2;
+ VERIFY_IS_APPROX(m4=m4*m3, refMat4=refMat4*refMat3);
+
+ // sparse * dense
+ VERIFY_IS_APPROX(dm4=m2*refMat3, refMat4=refMat2*refMat3);
+ VERIFY_IS_APPROX(dm4=m2*refMat3t.transpose(), refMat4=refMat2*refMat3t.transpose());
+ VERIFY_IS_APPROX(dm4=m2t.transpose()*refMat3, refMat4=refMat2t.transpose()*refMat3);
+ VERIFY_IS_APPROX(dm4=m2t.transpose()*refMat3t.transpose(), refMat4=refMat2t.transpose()*refMat3t.transpose());
+
+ VERIFY_IS_APPROX(dm4=m2*(refMat3+refMat3), refMat4=refMat2*(refMat3+refMat3));
+ VERIFY_IS_APPROX(dm4=m2t.transpose()*(refMat3+refMat5)*0.5, refMat4=refMat2t.transpose()*(refMat3+refMat5)*0.5);
+
+ // dense * sparse
+ VERIFY_IS_APPROX(dm4=refMat2*m3, refMat4=refMat2*refMat3);
+ VERIFY_IS_APPROX(dm4=refMat2*m3t.transpose(), refMat4=refMat2*refMat3t.transpose());
+ VERIFY_IS_APPROX(dm4=refMat2t.transpose()*m3, refMat4=refMat2t.transpose()*refMat3);
+ VERIFY_IS_APPROX(dm4=refMat2t.transpose()*m3t.transpose(), refMat4=refMat2t.transpose()*refMat3t.transpose());
+
+ // sparse * dense and dense * sparse outer product
+ test_outer<SparseMatrixType,DenseMatrix>::run(m2,m4,refMat2,refMat4);
+
+ VERIFY_IS_APPROX(m6=m6*m6, refMat6=refMat6*refMat6);
+ }
+
+ // test matrix - diagonal product
+ {
+ DenseMatrix refM2 = DenseMatrix::Zero(rows, rows);
+ DenseMatrix refM3 = DenseMatrix::Zero(rows, rows);
+ DiagonalMatrix<Scalar,Dynamic> d1(DenseVector::Random(rows));
+ SparseMatrixType m2(rows, rows);
+ SparseMatrixType m3(rows, rows);
+ initSparse<Scalar>(density, refM2, m2);
+ initSparse<Scalar>(density, refM3, m3);
+ VERIFY_IS_APPROX(m3=m2*d1, refM3=refM2*d1);
+ VERIFY_IS_APPROX(m3=m2.transpose()*d1, refM3=refM2.transpose()*d1);
+ VERIFY_IS_APPROX(m3=d1*m2, refM3=d1*refM2);
+ VERIFY_IS_APPROX(m3=d1*m2.transpose(), refM3=d1 * refM2.transpose());
+ }
+
+ // test self adjoint products
+ {
+ DenseMatrix b = DenseMatrix::Random(rows, rows);
+ DenseMatrix x = DenseMatrix::Random(rows, rows);
+ DenseMatrix refX = DenseMatrix::Random(rows, rows);
+ DenseMatrix refUp = DenseMatrix::Zero(rows, rows);
+ DenseMatrix refLo = DenseMatrix::Zero(rows, rows);
+ DenseMatrix refS = DenseMatrix::Zero(rows, rows);
+ SparseMatrixType mUp(rows, rows);
+ SparseMatrixType mLo(rows, rows);
+ SparseMatrixType mS(rows, rows);
+ do {
+ initSparse<Scalar>(density, refUp, mUp, ForceRealDiag|/*ForceNonZeroDiag|*/MakeUpperTriangular);
+ } while (refUp.isZero());
+ refLo = refUp.adjoint();
+ mLo = mUp.adjoint();
+ refS = refUp + refLo;
+ refS.diagonal() *= 0.5;
+ mS = mUp + mLo;
+ // TODO be able to address the diagonal....
+ for (int k=0; k<mS.outerSize(); ++k)
+ for (typename SparseMatrixType::InnerIterator it(mS,k); it; ++it)
+ if (it.index() == k)
+ it.valueRef() *= 0.5;
+
+ VERIFY_IS_APPROX(refS.adjoint(), refS);
+ VERIFY_IS_APPROX(mS.adjoint(), mS);
+ VERIFY_IS_APPROX(mS, refS);
+ VERIFY_IS_APPROX(x=mS*b, refX=refS*b);
+
+ VERIFY_IS_APPROX(x=mUp.template selfadjointView<Upper>()*b, refX=refS*b);
+ VERIFY_IS_APPROX(x=mLo.template selfadjointView<Lower>()*b, refX=refS*b);
+ VERIFY_IS_APPROX(x=mS.template selfadjointView<Upper|Lower>()*b, refX=refS*b);
+ }
+}
+
+// New test for Bug in SparseTimeDenseProduct
+template<typename SparseMatrixType, typename DenseMatrixType> void sparse_product_regression_test()
+{
+ // This code does not compile with afflicted versions of the bug
+ SparseMatrixType sm1(3,2);
+ DenseMatrixType m2(2,2);
+ sm1.setZero();
+ m2.setZero();
+
+ DenseMatrixType m3 = sm1*m2;
+
+
+ // This code produces a segfault with afflicted versions of another SparseTimeDenseProduct
+ // bug
+
+ SparseMatrixType sm2(20000,2);
+ sm2.setZero();
+ DenseMatrixType m4(sm2*m2);
+
+ VERIFY_IS_APPROX( m4(0,0), 0.0 );
+}
+
+void test_sparse_product()
+{
+ for(int i = 0; i < g_repeat; i++) {
+ CALL_SUBTEST_1( (sparse_product<SparseMatrix<double,ColMajor> >()) );
+ CALL_SUBTEST_1( (sparse_product<SparseMatrix<double,RowMajor> >()) );
+ CALL_SUBTEST_2( (sparse_product<SparseMatrix<std::complex<double>, ColMajor > >()) );
+ CALL_SUBTEST_2( (sparse_product<SparseMatrix<std::complex<double>, RowMajor > >()) );
+ CALL_SUBTEST_4( (sparse_product_regression_test<SparseMatrix<double,RowMajor>, Matrix<double, Dynamic, Dynamic, RowMajor> >()) );
+ }
+}
diff --git a/test/sparse_solver.h b/test/sparse_solver.h
new file mode 100644
index 000000000..75fa85082
--- /dev/null
+++ b/test/sparse_solver.h
@@ -0,0 +1,309 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra.
+//
+// Copyright (C) 2011 Gael Guennebaud <g.gael@free.fr>
+//
+// This Source Code Form is subject to the terms of the Mozilla
+// Public License v. 2.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 "sparse.h"
+#include <Eigen/SparseCore>
+
+template<typename Solver, typename Rhs, typename DenseMat, typename DenseRhs>
+void check_sparse_solving(Solver& solver, const typename Solver::MatrixType& A, const Rhs& b, const DenseMat& dA, const DenseRhs& db)
+{
+ typedef typename Solver::MatrixType Mat;
+ typedef typename Mat::Scalar Scalar;
+
+ DenseRhs refX = dA.lu().solve(db);
+
+ Rhs x(b.rows(), b.cols());
+ Rhs oldb = b;
+
+ solver.compute(A);
+ if (solver.info() != Success)
+ {
+ std::cerr << "sparse solver testing: factorization failed (check_sparse_solving)\n";
+ exit(0);
+ return;
+ }
+ x = solver.solve(b);
+ if (solver.info() != Success)
+ {
+ std::cerr << "sparse solver testing: solving failed\n";
+ return;
+ }
+ VERIFY(oldb.isApprox(b) && "sparse solver testing: the rhs should not be modified!");
+
+ VERIFY(x.isApprox(refX,test_precision<Scalar>()));
+
+ x.setZero();
+ // test the analyze/factorize API
+ solver.analyzePattern(A);
+ solver.factorize(A);
+ if (solver.info() != Success)
+ {
+ std::cerr << "sparse solver testing: factorization failed (check_sparse_solving)\n";
+ exit(0);
+ return;
+ }
+ x = solver.solve(b);
+ if (solver.info() != Success)
+ {
+ std::cerr << "sparse solver testing: solving failed\n";
+ return;
+ }
+ VERIFY(oldb.isApprox(b) && "sparse solver testing: the rhs should not be modified!");
+
+ VERIFY(x.isApprox(refX,test_precision<Scalar>()));
+
+ // test Block as the result and rhs:
+ {
+ DenseRhs x(db.rows(), db.cols());
+ DenseRhs b(db), oldb(db);
+ x.setZero();
+ x.block(0,0,x.rows(),x.cols()) = solver.solve(b.block(0,0,b.rows(),b.cols()));
+ VERIFY(oldb.isApprox(b) && "sparse solver testing: the rhs should not be modified!");
+ VERIFY(x.isApprox(refX,test_precision<Scalar>()));
+ }
+}
+
+template<typename Solver, typename Rhs>
+void check_sparse_solving_real_cases(Solver& solver, const typename Solver::MatrixType& A, const Rhs& b, const Rhs& refX)
+{
+ typedef typename Solver::MatrixType Mat;
+ typedef typename Mat::Scalar Scalar;
+ typedef typename Mat::RealScalar RealScalar;
+
+ Rhs x(b.rows(), b.cols());
+
+ solver.compute(A);
+ if (solver.info() != Success)
+ {
+ std::cerr << "sparse solver testing: factorization failed (check_sparse_solving_real_cases)\n";
+ exit(0);
+ return;
+ }
+ x = solver.solve(b);
+ if (solver.info() != Success)
+ {
+ std::cerr << "sparse solver testing: solving failed\n";
+ return;
+ }
+
+ RealScalar res_error;
+ // Compute the norm of the relative error
+ if(refX.size() != 0)
+ res_error = (refX - x).norm()/refX.norm();
+ else
+ {
+ // Compute the relative residual norm
+ res_error = (b - A * x).norm()/b.norm();
+ }
+ if (res_error > test_precision<Scalar>() ){
+ std::cerr << "Test " << g_test_stack.back() << " failed in "EI_PP_MAKE_STRING(__FILE__)
+ << " (" << EI_PP_MAKE_STRING(__LINE__) << ")" << std::endl << std::endl;
+ abort();
+ }
+
+}
+template<typename Solver, typename DenseMat>
+void check_sparse_determinant(Solver& solver, const typename Solver::MatrixType& A, const DenseMat& dA)
+{
+ typedef typename Solver::MatrixType Mat;
+ typedef typename Mat::Scalar Scalar;
+ typedef typename Mat::RealScalar RealScalar;
+
+ solver.compute(A);
+ if (solver.info() != Success)
+ {
+ std::cerr << "sparse solver testing: factorization failed (check_sparse_determinant)\n";
+ return;
+ }
+
+ Scalar refDet = dA.determinant();
+ VERIFY_IS_APPROX(refDet,solver.determinant());
+}
+
+
+template<typename Solver, typename DenseMat>
+int generate_sparse_spd_problem(Solver& , typename Solver::MatrixType& A, typename Solver::MatrixType& halfA, DenseMat& dA, int maxSize = 300)
+{
+ typedef typename Solver::MatrixType Mat;
+ typedef typename Mat::Scalar Scalar;
+ typedef Matrix<Scalar,Dynamic,Dynamic> DenseMatrix;
+
+ int size = internal::random<int>(1,maxSize);
+ double density = (std::max)(8./(size*size), 0.01);
+
+ Mat M(size, size);
+ DenseMatrix dM(size, size);
+
+ initSparse<Scalar>(density, dM, M, ForceNonZeroDiag);
+
+ A = M * M.adjoint();
+ dA = dM * dM.adjoint();
+
+ halfA.resize(size,size);
+ halfA.template selfadjointView<Solver::UpLo>().rankUpdate(M);
+
+ return size;
+}
+
+
+#ifdef TEST_REAL_CASES
+template<typename Scalar>
+inline std::string get_matrixfolder()
+{
+ std::string mat_folder = TEST_REAL_CASES;
+ if( internal::is_same<Scalar, std::complex<float> >::value || internal::is_same<Scalar, std::complex<double> >::value )
+ mat_folder = mat_folder + static_cast<string>("/complex/");
+ else
+ mat_folder = mat_folder + static_cast<string>("/real/");
+ return mat_folder;
+}
+#endif
+
+template<typename Solver> void check_sparse_spd_solving(Solver& solver)
+{
+ typedef typename Solver::MatrixType Mat;
+ typedef typename Mat::Scalar Scalar;
+ typedef typename Mat::Index Index;
+ typedef SparseMatrix<Scalar,ColMajor> SpMat;
+ typedef Matrix<Scalar,Dynamic,Dynamic> DenseMatrix;
+ typedef Matrix<Scalar,Dynamic,1> DenseVector;
+
+ // generate the problem
+ Mat A, halfA;
+ DenseMatrix dA;
+ int size = generate_sparse_spd_problem(solver, A, halfA, dA);
+
+ // generate the right hand sides
+ int rhsCols = internal::random<int>(1,16);
+ double density = (std::max)(8./(size*rhsCols), 0.1);
+ SpMat B(size,rhsCols);
+ DenseVector b = DenseVector::Random(size);
+ DenseMatrix dB(size,rhsCols);
+ initSparse<Scalar>(density, dB, B, ForceNonZeroDiag);
+
+ for (int i = 0; i < g_repeat; i++) {
+ check_sparse_solving(solver, A, b, dA, b);
+ check_sparse_solving(solver, halfA, b, dA, b);
+ check_sparse_solving(solver, A, dB, dA, dB);
+ check_sparse_solving(solver, halfA, dB, dA, dB);
+ check_sparse_solving(solver, A, B, dA, dB);
+ check_sparse_solving(solver, halfA, B, dA, dB);
+ }
+
+ // First, get the folder
+#ifdef TEST_REAL_CASES
+ if (internal::is_same<Scalar, float>::value
+ || internal::is_same<Scalar, std::complex<float> >::value)
+ return ;
+
+ std::string mat_folder = get_matrixfolder<Scalar>();
+ MatrixMarketIterator<Scalar> it(mat_folder);
+ for (; it; ++it)
+ {
+ if (it.sym() == SPD){
+ Mat halfA;
+ PermutationMatrix<Dynamic, Dynamic, Index> pnull;
+ halfA.template selfadjointView<Solver::UpLo>() = it.matrix().template triangularView<Eigen::Lower>().twistedBy(pnull);
+
+ std::cout<< " ==== SOLVING WITH MATRIX " << it.matname() << " ==== \n";
+ check_sparse_solving_real_cases(solver, it.matrix(), it.rhs(), it.refX());
+ check_sparse_solving_real_cases(solver, halfA, it.rhs(), it.refX());
+ }
+ }
+#endif
+}
+
+template<typename Solver> void check_sparse_spd_determinant(Solver& solver)
+{
+ typedef typename Solver::MatrixType Mat;
+ typedef typename Mat::Scalar Scalar;
+ typedef Matrix<Scalar,Dynamic,Dynamic> DenseMatrix;
+
+ // generate the problem
+ Mat A, halfA;
+ DenseMatrix dA;
+ generate_sparse_spd_problem(solver, A, halfA, dA, 30);
+
+ for (int i = 0; i < g_repeat; i++) {
+ check_sparse_determinant(solver, A, dA);
+ check_sparse_determinant(solver, halfA, dA );
+ }
+}
+
+template<typename Solver, typename DenseMat>
+int generate_sparse_square_problem(Solver&, typename Solver::MatrixType& A, DenseMat& dA, int maxSize = 300)
+{
+ typedef typename Solver::MatrixType Mat;
+ typedef typename Mat::Scalar Scalar;
+ typedef Matrix<Scalar,Dynamic,Dynamic> DenseMatrix;
+
+ int size = internal::random<int>(1,maxSize);
+ double density = (std::max)(8./(size*size), 0.01);
+
+ A.resize(size,size);
+ dA.resize(size,size);
+
+ initSparse<Scalar>(density, dA, A, ForceNonZeroDiag);
+
+ return size;
+}
+
+template<typename Solver> void check_sparse_square_solving(Solver& solver)
+{
+ typedef typename Solver::MatrixType Mat;
+ typedef typename Mat::Scalar Scalar;
+ typedef Matrix<Scalar,Dynamic,Dynamic> DenseMatrix;
+ typedef Matrix<Scalar,Dynamic,1> DenseVector;
+
+ int rhsCols = internal::random<int>(1,16);
+
+ Mat A;
+ DenseMatrix dA;
+ int size = generate_sparse_square_problem(solver, A, dA);
+
+ DenseVector b = DenseVector::Random(size);
+ DenseMatrix dB = DenseMatrix::Random(size,rhsCols);
+ A.makeCompressed();
+ for (int i = 0; i < g_repeat; i++) {
+ check_sparse_solving(solver, A, b, dA, b);
+ check_sparse_solving(solver, A, dB, dA, dB);
+ }
+
+ // First, get the folder
+#ifdef TEST_REAL_CASES
+ if (internal::is_same<Scalar, float>::value
+ || internal::is_same<Scalar, std::complex<float> >::value)
+ return ;
+
+ std::string mat_folder = get_matrixfolder<Scalar>();
+ MatrixMarketIterator<Scalar> it(mat_folder);
+ for (; it; ++it)
+ {
+ std::cout<< " ==== SOLVING WITH MATRIX " << it.matname() << " ==== \n";
+ check_sparse_solving_real_cases(solver, it.matrix(), it.rhs(), it.refX());
+ }
+#endif
+
+}
+
+template<typename Solver> void check_sparse_square_determinant(Solver& solver)
+{
+ typedef typename Solver::MatrixType Mat;
+ typedef typename Mat::Scalar Scalar;
+ typedef Matrix<Scalar,Dynamic,Dynamic> DenseMatrix;
+
+ // generate the problem
+ Mat A;
+ DenseMatrix dA;
+ generate_sparse_square_problem(solver, A, dA, 30);
+ A.makeCompressed();
+ for (int i = 0; i < g_repeat; i++) {
+ check_sparse_determinant(solver, A, dA);
+ }
+}
diff --git a/test/sparse_solvers.cpp b/test/sparse_solvers.cpp
new file mode 100644
index 000000000..3a8873d43
--- /dev/null
+++ b/test/sparse_solvers.cpp
@@ -0,0 +1,112 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra.
+//
+// Copyright (C) 2008-2010 Gael Guennebaud <gael.guennebaud@inria.fr>
+//
+// This Source Code Form is subject to the terms of the Mozilla
+// Public License v. 2.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 "sparse.h"
+
+template<typename Scalar> void
+initSPD(double density,
+ Matrix<Scalar,Dynamic,Dynamic>& refMat,
+ SparseMatrix<Scalar>& sparseMat)
+{
+ Matrix<Scalar,Dynamic,Dynamic> aux(refMat.rows(),refMat.cols());
+ initSparse(density,refMat,sparseMat);
+ refMat = refMat * refMat.adjoint();
+ for (int k=0; k<2; ++k)
+ {
+ initSparse(density,aux,sparseMat,ForceNonZeroDiag);
+ refMat += aux * aux.adjoint();
+ }
+ sparseMat.setZero();
+ for (int j=0 ; j<sparseMat.cols(); ++j)
+ for (int i=j ; i<sparseMat.rows(); ++i)
+ if (refMat(i,j)!=Scalar(0))
+ sparseMat.insert(i,j) = refMat(i,j);
+ sparseMat.finalize();
+}
+
+template<typename Scalar> void sparse_solvers(int rows, int cols)
+{
+ double density = (std::max)(8./(rows*cols), 0.01);
+ typedef Matrix<Scalar,Dynamic,Dynamic> DenseMatrix;
+ typedef Matrix<Scalar,Dynamic,1> DenseVector;
+ // Scalar eps = 1e-6;
+
+ DenseVector vec1 = DenseVector::Random(rows);
+
+ std::vector<Vector2i> zeroCoords;
+ std::vector<Vector2i> nonzeroCoords;
+
+ // test triangular solver
+ {
+ DenseVector vec2 = vec1, vec3 = vec1;
+ SparseMatrix<Scalar> m2(rows, cols);
+ DenseMatrix refMat2 = DenseMatrix::Zero(rows, cols);
+
+ // lower - dense
+ initSparse<Scalar>(density, refMat2, m2, ForceNonZeroDiag|MakeLowerTriangular, &zeroCoords, &nonzeroCoords);
+ VERIFY_IS_APPROX(refMat2.template triangularView<Lower>().solve(vec2),
+ m2.template triangularView<Lower>().solve(vec3));
+
+ // upper - dense
+ initSparse<Scalar>(density, refMat2, m2, ForceNonZeroDiag|MakeUpperTriangular, &zeroCoords, &nonzeroCoords);
+ VERIFY_IS_APPROX(refMat2.template triangularView<Upper>().solve(vec2),
+ m2.template triangularView<Upper>().solve(vec3));
+ VERIFY_IS_APPROX(refMat2.conjugate().template triangularView<Upper>().solve(vec2),
+ m2.conjugate().template triangularView<Upper>().solve(vec3));
+ {
+ SparseMatrix<Scalar> cm2(m2);
+ //Index rows, Index cols, Index nnz, Index* outerIndexPtr, Index* innerIndexPtr, Scalar* valuePtr
+ MappedSparseMatrix<Scalar> mm2(rows, cols, cm2.nonZeros(), cm2.outerIndexPtr(), cm2.innerIndexPtr(), cm2.valuePtr());
+ VERIFY_IS_APPROX(refMat2.conjugate().template triangularView<Upper>().solve(vec2),
+ mm2.conjugate().template triangularView<Upper>().solve(vec3));
+ }
+
+ // lower - transpose
+ initSparse<Scalar>(density, refMat2, m2, ForceNonZeroDiag|MakeLowerTriangular, &zeroCoords, &nonzeroCoords);
+ VERIFY_IS_APPROX(refMat2.transpose().template triangularView<Upper>().solve(vec2),
+ m2.transpose().template triangularView<Upper>().solve(vec3));
+
+ // upper - transpose
+ initSparse<Scalar>(density, refMat2, m2, ForceNonZeroDiag|MakeUpperTriangular, &zeroCoords, &nonzeroCoords);
+ VERIFY_IS_APPROX(refMat2.transpose().template triangularView<Lower>().solve(vec2),
+ m2.transpose().template triangularView<Lower>().solve(vec3));
+
+ SparseMatrix<Scalar> matB(rows, rows);
+ DenseMatrix refMatB = DenseMatrix::Zero(rows, rows);
+
+ // lower - sparse
+ initSparse<Scalar>(density, refMat2, m2, ForceNonZeroDiag|MakeLowerTriangular);
+ initSparse<Scalar>(density, refMatB, matB);
+ refMat2.template triangularView<Lower>().solveInPlace(refMatB);
+ m2.template triangularView<Lower>().solveInPlace(matB);
+ VERIFY_IS_APPROX(matB.toDense(), refMatB);
+
+ // upper - sparse
+ initSparse<Scalar>(density, refMat2, m2, ForceNonZeroDiag|MakeUpperTriangular);
+ initSparse<Scalar>(density, refMatB, matB);
+ refMat2.template triangularView<Upper>().solveInPlace(refMatB);
+ m2.template triangularView<Upper>().solveInPlace(matB);
+ VERIFY_IS_APPROX(matB, refMatB);
+
+ // test deprecated API
+ initSparse<Scalar>(density, refMat2, m2, ForceNonZeroDiag|MakeLowerTriangular, &zeroCoords, &nonzeroCoords);
+ VERIFY_IS_APPROX(refMat2.template triangularView<Lower>().solve(vec2),
+ m2.template triangularView<Lower>().solve(vec3));
+ }
+}
+
+void test_sparse_solvers()
+{
+ for(int i = 0; i < g_repeat; i++) {
+ CALL_SUBTEST_1(sparse_solvers<double>(8, 8) );
+ int s = internal::random<int>(1,300);
+ CALL_SUBTEST_2(sparse_solvers<std::complex<double> >(s,s) );
+ CALL_SUBTEST_1(sparse_solvers<double>(s,s) );
+ }
+}
diff --git a/test/sparse_vector.cpp b/test/sparse_vector.cpp
new file mode 100644
index 000000000..7201afe5b
--- /dev/null
+++ b/test/sparse_vector.cpp
@@ -0,0 +1,91 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra.
+//
+// Copyright (C) 2008-2011 Gael Guennebaud <gael.guennebaud@inria.fr>
+//
+// This Source Code Form is subject to the terms of the Mozilla
+// Public License v. 2.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 "sparse.h"
+
+template<typename Scalar> void sparse_vector(int rows, int cols)
+{
+ double densityMat = (std::max)(8./(rows*cols), 0.01);
+ double densityVec = (std::max)(8./float(rows), 0.1);
+ typedef Matrix<Scalar,Dynamic,Dynamic> DenseMatrix;
+ typedef Matrix<Scalar,Dynamic,1> DenseVector;
+ typedef SparseVector<Scalar> SparseVectorType;
+ typedef SparseMatrix<Scalar> SparseMatrixType;
+ Scalar eps = 1e-6;
+
+ SparseMatrixType m1(rows,rows);
+ SparseVectorType v1(rows), v2(rows), v3(rows);
+ DenseMatrix refM1 = DenseMatrix::Zero(rows, rows);
+ DenseVector refV1 = DenseVector::Random(rows),
+ refV2 = DenseVector::Random(rows),
+ refV3 = DenseVector::Random(rows);
+
+ std::vector<int> zerocoords, nonzerocoords;
+ initSparse<Scalar>(densityVec, refV1, v1, &zerocoords, &nonzerocoords);
+ initSparse<Scalar>(densityMat, refM1, m1);
+
+ initSparse<Scalar>(densityVec, refV2, v2);
+ initSparse<Scalar>(densityVec, refV3, v3);
+
+ Scalar s1 = internal::random<Scalar>();
+
+ // test coeff and coeffRef
+ for (unsigned int i=0; i<zerocoords.size(); ++i)
+ {
+ VERIFY_IS_MUCH_SMALLER_THAN( v1.coeff(zerocoords[i]), eps );
+ //VERIFY_RAISES_ASSERT( v1.coeffRef(zerocoords[i]) = 5 );
+ }
+ {
+ VERIFY(int(nonzerocoords.size()) == v1.nonZeros());
+ int j=0;
+ for (typename SparseVectorType::InnerIterator it(v1); it; ++it,++j)
+ {
+ VERIFY(nonzerocoords[j]==it.index());
+ VERIFY(it.value()==v1.coeff(it.index()));
+ VERIFY(it.value()==refV1.coeff(it.index()));
+ }
+ }
+ VERIFY_IS_APPROX(v1, refV1);
+
+ v1.coeffRef(nonzerocoords[0]) = Scalar(5);
+ refV1.coeffRef(nonzerocoords[0]) = Scalar(5);
+ VERIFY_IS_APPROX(v1, refV1);
+
+ VERIFY_IS_APPROX(v1+v2, refV1+refV2);
+ VERIFY_IS_APPROX(v1+v2+v3, refV1+refV2+refV3);
+
+ VERIFY_IS_APPROX(v1*s1-v2, refV1*s1-refV2);
+
+ VERIFY_IS_APPROX(v1*=s1, refV1*=s1);
+ VERIFY_IS_APPROX(v1/=s1, refV1/=s1);
+
+ VERIFY_IS_APPROX(v1+=v2, refV1+=refV2);
+ VERIFY_IS_APPROX(v1-=v2, refV1-=refV2);
+
+ VERIFY_IS_APPROX(v1.dot(v2), refV1.dot(refV2));
+ VERIFY_IS_APPROX(v1.dot(refV2), refV1.dot(refV2));
+
+ VERIFY_IS_APPROX(v1.dot(m1*v2), refV1.dot(refM1*refV2));
+ int i = internal::random<int>(0,rows-1);
+ VERIFY_IS_APPROX(v1.dot(m1.col(i)), refV1.dot(refM1.col(i)));
+
+
+ VERIFY_IS_APPROX(v1.squaredNorm(), refV1.squaredNorm());
+
+}
+
+void test_sparse_vector()
+{
+ for(int i = 0; i < g_repeat; i++) {
+ CALL_SUBTEST_1( sparse_vector<double>(8, 8) );
+ CALL_SUBTEST_2( sparse_vector<std::complex<double> >(16, 16) );
+ CALL_SUBTEST_1( sparse_vector<double>(299, 535) );
+ }
+}
+
diff --git a/test/stable_norm.cpp b/test/stable_norm.cpp
new file mode 100644
index 000000000..a25dbf51c
--- /dev/null
+++ b/test/stable_norm.cpp
@@ -0,0 +1,110 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra.
+//
+// Copyright (C) 2009 Gael Guennebaud <gael.guennebaud@inria.fr>
+//
+// This Source Code Form is subject to the terms of the Mozilla
+// Public License v. 2.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 "main.h"
+
+template<typename T> bool isNotNaN(const T& x)
+{
+ return x==x;
+}
+
+// workaround aggressive optimization in ICC
+template<typename T> EIGEN_DONT_INLINE T sub(T a, T b) { return a - b; }
+
+template<typename T> bool isFinite(const T& x)
+{
+ return isNotNaN(sub(x,x));
+}
+
+template<typename T> EIGEN_DONT_INLINE T copy(const T& x)
+{
+ return x;
+}
+
+template<typename MatrixType> void stable_norm(const MatrixType& m)
+{
+ /* this test covers the following files:
+ StableNorm.h
+ */
+ typedef typename MatrixType::Index Index;
+ typedef typename MatrixType::Scalar Scalar;
+ typedef typename NumTraits<Scalar>::Real RealScalar;
+
+ // Check the basic machine-dependent constants.
+ {
+ int ibeta, it, iemin, iemax;
+
+ ibeta = std::numeric_limits<RealScalar>::radix; // base for floating-point numbers
+ it = std::numeric_limits<RealScalar>::digits; // number of base-beta digits in mantissa
+ iemin = std::numeric_limits<RealScalar>::min_exponent; // minimum exponent
+ iemax = std::numeric_limits<RealScalar>::max_exponent; // maximum exponent
+
+ VERIFY( (!(iemin > 1 - 2*it || 1+it>iemax || (it==2 && ibeta<5) || (it<=4 && ibeta <= 3 ) || it<2))
+ && "the stable norm algorithm cannot be guaranteed on this computer");
+ }
+
+
+ Index rows = m.rows();
+ Index cols = m.cols();
+
+ Scalar big = internal::random<Scalar>() * ((std::numeric_limits<RealScalar>::max)() * RealScalar(1e-4));
+ Scalar small = internal::random<Scalar>() * ((std::numeric_limits<RealScalar>::min)() * RealScalar(1e4));
+
+ MatrixType vzero = MatrixType::Zero(rows, cols),
+ vrand = MatrixType::Random(rows, cols),
+ vbig(rows, cols),
+ vsmall(rows,cols);
+
+ vbig.fill(big);
+ vsmall.fill(small);
+
+ VERIFY_IS_MUCH_SMALLER_THAN(vzero.norm(), static_cast<RealScalar>(1));
+ VERIFY_IS_APPROX(vrand.stableNorm(), vrand.norm());
+ VERIFY_IS_APPROX(vrand.blueNorm(), vrand.norm());
+ VERIFY_IS_APPROX(vrand.hypotNorm(), vrand.norm());
+
+ RealScalar size = static_cast<RealScalar>(m.size());
+
+ // test isFinite
+ VERIFY(!isFinite( std::numeric_limits<RealScalar>::infinity()));
+ VERIFY(!isFinite(internal::sqrt(-internal::abs(big))));
+
+ // test overflow
+ VERIFY(isFinite(internal::sqrt(size)*internal::abs(big)));
+ VERIFY_IS_NOT_APPROX(internal::sqrt(copy(vbig.squaredNorm())), internal::abs(internal::sqrt(size)*big)); // here the default norm must fail
+ VERIFY_IS_APPROX(vbig.stableNorm(), internal::sqrt(size)*internal::abs(big));
+ VERIFY_IS_APPROX(vbig.blueNorm(), internal::sqrt(size)*internal::abs(big));
+ VERIFY_IS_APPROX(vbig.hypotNorm(), internal::sqrt(size)*internal::abs(big));
+
+ // test underflow
+ VERIFY(isFinite(internal::sqrt(size)*internal::abs(small)));
+ VERIFY_IS_NOT_APPROX(internal::sqrt(copy(vsmall.squaredNorm())), internal::abs(internal::sqrt(size)*small)); // here the default norm must fail
+ VERIFY_IS_APPROX(vsmall.stableNorm(), internal::sqrt(size)*internal::abs(small));
+ VERIFY_IS_APPROX(vsmall.blueNorm(), internal::sqrt(size)*internal::abs(small));
+ VERIFY_IS_APPROX(vsmall.hypotNorm(), internal::sqrt(size)*internal::abs(small));
+
+// Test compilation of cwise() version
+ VERIFY_IS_APPROX(vrand.colwise().stableNorm(), vrand.colwise().norm());
+ VERIFY_IS_APPROX(vrand.colwise().blueNorm(), vrand.colwise().norm());
+ VERIFY_IS_APPROX(vrand.colwise().hypotNorm(), vrand.colwise().norm());
+ VERIFY_IS_APPROX(vrand.rowwise().stableNorm(), vrand.rowwise().norm());
+ VERIFY_IS_APPROX(vrand.rowwise().blueNorm(), vrand.rowwise().norm());
+ VERIFY_IS_APPROX(vrand.rowwise().hypotNorm(), vrand.rowwise().norm());
+}
+
+void test_stable_norm()
+{
+ for(int i = 0; i < g_repeat; i++) {
+ CALL_SUBTEST_1( stable_norm(Matrix<float, 1, 1>()) );
+ CALL_SUBTEST_2( stable_norm(Vector4d()) );
+ CALL_SUBTEST_3( stable_norm(VectorXd(internal::random<int>(10,2000))) );
+ CALL_SUBTEST_4( stable_norm(VectorXf(internal::random<int>(10,2000))) );
+ CALL_SUBTEST_5( stable_norm(VectorXcd(internal::random<int>(10,2000))) );
+ }
+}
diff --git a/test/stddeque.cpp b/test/stddeque.cpp
new file mode 100644
index 000000000..bb4b476f3
--- /dev/null
+++ b/test/stddeque.cpp
@@ -0,0 +1,132 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra.
+//
+// Copyright (C) 2008 Benoit Jacob <jacob.benoit.1@gmail.com>
+// Copyright (C) 2010 Hauke Heibel <hauke.heibel@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 "main.h"
+#include <Eigen/StdDeque>
+#include <Eigen/Geometry>
+
+template<typename MatrixType>
+void check_stddeque_matrix(const MatrixType& m)
+{
+ typedef typename MatrixType::Index Index;
+
+ Index rows = m.rows();
+ Index cols = m.cols();
+ MatrixType x = MatrixType::Random(rows,cols), y = MatrixType::Random(rows,cols);
+ std::deque<MatrixType,Eigen::aligned_allocator<MatrixType> > v(10, MatrixType(rows,cols)), w(20, y);
+ v.front() = x;
+ w.front() = w.back();
+ VERIFY_IS_APPROX(w.front(), w.back());
+ v = w;
+
+ typename std::deque<MatrixType,Eigen::aligned_allocator<MatrixType> >::iterator vi = v.begin();
+ typename std::deque<MatrixType,Eigen::aligned_allocator<MatrixType> >::iterator wi = w.begin();
+ for(int i = 0; i < 20; i++)
+ {
+ VERIFY_IS_APPROX(*vi, *wi);
+ ++vi;
+ ++wi;
+ }
+
+ v.resize(21);
+ v.back() = x;
+ VERIFY_IS_APPROX(v.back(), x);
+ v.resize(22,y);
+ VERIFY_IS_APPROX(v.back(), y);
+ v.push_back(x);
+ VERIFY_IS_APPROX(v.back(), x);
+}
+
+template<typename TransformType>
+void check_stddeque_transform(const TransformType&)
+{
+ typedef typename TransformType::MatrixType MatrixType;
+ TransformType x(MatrixType::Random()), y(MatrixType::Random());
+ std::deque<TransformType,Eigen::aligned_allocator<TransformType> > v(10), w(20, y);
+ v.front() = x;
+ w.front() = w.back();
+ VERIFY_IS_APPROX(w.front(), w.back());
+ v = w;
+
+ typename std::deque<TransformType,Eigen::aligned_allocator<TransformType> >::iterator vi = v.begin();
+ typename std::deque<TransformType,Eigen::aligned_allocator<TransformType> >::iterator wi = w.begin();
+ for(int i = 0; i < 20; i++)
+ {
+ VERIFY_IS_APPROX(*vi, *wi);
+ ++vi;
+ ++wi;
+ }
+
+ v.resize(21);
+ v.back() = x;
+ VERIFY_IS_APPROX(v.back(), x);
+ v.resize(22,y);
+ VERIFY_IS_APPROX(v.back(), y);
+ v.push_back(x);
+ VERIFY_IS_APPROX(v.back(), x);
+}
+
+template<typename QuaternionType>
+void check_stddeque_quaternion(const QuaternionType&)
+{
+ typedef typename QuaternionType::Coefficients Coefficients;
+ QuaternionType x(Coefficients::Random()), y(Coefficients::Random());
+ std::deque<QuaternionType,Eigen::aligned_allocator<QuaternionType> > v(10), w(20, y);
+ v.front() = x;
+ w.front() = w.back();
+ VERIFY_IS_APPROX(w.front(), w.back());
+ v = w;
+
+ typename std::deque<QuaternionType,Eigen::aligned_allocator<QuaternionType> >::iterator vi = v.begin();
+ typename std::deque<QuaternionType,Eigen::aligned_allocator<QuaternionType> >::iterator wi = w.begin();
+ for(int i = 0; i < 20; i++)
+ {
+ VERIFY_IS_APPROX(*vi, *wi);
+ ++vi;
+ ++wi;
+ }
+
+ v.resize(21);
+ v.back() = x;
+ VERIFY_IS_APPROX(v.back(), x);
+ v.resize(22,y);
+ VERIFY_IS_APPROX(v.back(), y);
+ v.push_back(x);
+ VERIFY_IS_APPROX(v.back(), x);
+}
+
+void test_stddeque()
+{
+ // some non vectorizable fixed sizes
+ CALL_SUBTEST_1(check_stddeque_matrix(Vector2f()));
+ CALL_SUBTEST_1(check_stddeque_matrix(Matrix3f()));
+ CALL_SUBTEST_2(check_stddeque_matrix(Matrix3d()));
+
+ // some vectorizable fixed sizes
+ CALL_SUBTEST_1(check_stddeque_matrix(Matrix2f()));
+ CALL_SUBTEST_1(check_stddeque_matrix(Vector4f()));
+ CALL_SUBTEST_1(check_stddeque_matrix(Matrix4f()));
+ CALL_SUBTEST_2(check_stddeque_matrix(Matrix4d()));
+
+ // some dynamic sizes
+ CALL_SUBTEST_3(check_stddeque_matrix(MatrixXd(1,1)));
+ CALL_SUBTEST_3(check_stddeque_matrix(VectorXd(20)));
+ CALL_SUBTEST_3(check_stddeque_matrix(RowVectorXf(20)));
+ CALL_SUBTEST_3(check_stddeque_matrix(MatrixXcf(10,10)));
+
+ // some Transform
+ CALL_SUBTEST_4(check_stddeque_transform(Affine2f()));
+ CALL_SUBTEST_4(check_stddeque_transform(Affine3f()));
+ CALL_SUBTEST_4(check_stddeque_transform(Affine3d()));
+
+ // some Quaternion
+ CALL_SUBTEST_5(check_stddeque_quaternion(Quaternionf()));
+ CALL_SUBTEST_5(check_stddeque_quaternion(Quaterniond()));
+}
diff --git a/test/stdlist.cpp b/test/stdlist.cpp
new file mode 100644
index 000000000..17cce779a
--- /dev/null
+++ b/test/stdlist.cpp
@@ -0,0 +1,132 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra.
+//
+// Copyright (C) 2008 Benoit Jacob <jacob.benoit.1@gmail.com>
+// Copyright (C) 2010 Hauke Heibel <hauke.heibel@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 "main.h"
+#include <Eigen/StdList>
+#include <Eigen/Geometry>
+
+template<typename MatrixType>
+void check_stdlist_matrix(const MatrixType& m)
+{
+ typedef typename MatrixType::Index Index;
+
+ Index rows = m.rows();
+ Index cols = m.cols();
+ MatrixType x = MatrixType::Random(rows,cols), y = MatrixType::Random(rows,cols);
+ std::list<MatrixType,Eigen::aligned_allocator<MatrixType> > v(10, MatrixType(rows,cols)), w(20, y);
+ v.front() = x;
+ w.front() = w.back();
+ VERIFY_IS_APPROX(w.front(), w.back());
+ v = w;
+
+ typename std::list<MatrixType,Eigen::aligned_allocator<MatrixType> >::iterator vi = v.begin();
+ typename std::list<MatrixType,Eigen::aligned_allocator<MatrixType> >::iterator wi = w.begin();
+ for(int i = 0; i < 20; i++)
+ {
+ VERIFY_IS_APPROX(*vi, *wi);
+ ++vi;
+ ++wi;
+ }
+
+ v.resize(21);
+ v.back() = x;
+ VERIFY_IS_APPROX(v.back(), x);
+ v.resize(22,y);
+ VERIFY_IS_APPROX(v.back(), y);
+ v.push_back(x);
+ VERIFY_IS_APPROX(v.back(), x);
+}
+
+template<typename TransformType>
+void check_stdlist_transform(const TransformType&)
+{
+ typedef typename TransformType::MatrixType MatrixType;
+ TransformType x(MatrixType::Random()), y(MatrixType::Random());
+ std::list<TransformType,Eigen::aligned_allocator<TransformType> > v(10), w(20, y);
+ v.front() = x;
+ w.front() = w.back();
+ VERIFY_IS_APPROX(w.front(), w.back());
+ v = w;
+
+ typename std::list<TransformType,Eigen::aligned_allocator<TransformType> >::iterator vi = v.begin();
+ typename std::list<TransformType,Eigen::aligned_allocator<TransformType> >::iterator wi = w.begin();
+ for(int i = 0; i < 20; i++)
+ {
+ VERIFY_IS_APPROX(*vi, *wi);
+ ++vi;
+ ++wi;
+ }
+
+ v.resize(21);
+ v.back() = x;
+ VERIFY_IS_APPROX(v.back(), x);
+ v.resize(22,y);
+ VERIFY_IS_APPROX(v.back(), y);
+ v.push_back(x);
+ VERIFY_IS_APPROX(v.back(), x);
+}
+
+template<typename QuaternionType>
+void check_stdlist_quaternion(const QuaternionType&)
+{
+ typedef typename QuaternionType::Coefficients Coefficients;
+ QuaternionType x(Coefficients::Random()), y(Coefficients::Random());
+ std::list<QuaternionType,Eigen::aligned_allocator<QuaternionType> > v(10), w(20, y);
+ v.front() = x;
+ w.front() = w.back();
+ VERIFY_IS_APPROX(w.front(), w.back());
+ v = w;
+
+ typename std::list<QuaternionType,Eigen::aligned_allocator<QuaternionType> >::iterator vi = v.begin();
+ typename std::list<QuaternionType,Eigen::aligned_allocator<QuaternionType> >::iterator wi = w.begin();
+ for(int i = 0; i < 20; i++)
+ {
+ VERIFY_IS_APPROX(*vi, *wi);
+ ++vi;
+ ++wi;
+ }
+
+ v.resize(21);
+ v.back() = x;
+ VERIFY_IS_APPROX(v.back(), x);
+ v.resize(22,y);
+ VERIFY_IS_APPROX(v.back(), y);
+ v.push_back(x);
+ VERIFY_IS_APPROX(v.back(), x);
+}
+
+void test_stdlist()
+{
+ // some non vectorizable fixed sizes
+ CALL_SUBTEST_1(check_stdlist_matrix(Vector2f()));
+ CALL_SUBTEST_1(check_stdlist_matrix(Matrix3f()));
+ CALL_SUBTEST_2(check_stdlist_matrix(Matrix3d()));
+
+ // some vectorizable fixed sizes
+ CALL_SUBTEST_1(check_stdlist_matrix(Matrix2f()));
+ CALL_SUBTEST_1(check_stdlist_matrix(Vector4f()));
+ CALL_SUBTEST_1(check_stdlist_matrix(Matrix4f()));
+ CALL_SUBTEST_2(check_stdlist_matrix(Matrix4d()));
+
+ // some dynamic sizes
+ CALL_SUBTEST_3(check_stdlist_matrix(MatrixXd(1,1)));
+ CALL_SUBTEST_3(check_stdlist_matrix(VectorXd(20)));
+ CALL_SUBTEST_3(check_stdlist_matrix(RowVectorXf(20)));
+ CALL_SUBTEST_3(check_stdlist_matrix(MatrixXcf(10,10)));
+
+ // some Transform
+ CALL_SUBTEST_4(check_stdlist_transform(Affine2f()));
+ CALL_SUBTEST_4(check_stdlist_transform(Affine3f()));
+ CALL_SUBTEST_4(check_stdlist_transform(Affine3d()));
+
+ // some Quaternion
+ CALL_SUBTEST_5(check_stdlist_quaternion(Quaternionf()));
+ CALL_SUBTEST_5(check_stdlist_quaternion(Quaterniond()));
+}
diff --git a/test/stdvector.cpp b/test/stdvector.cpp
new file mode 100644
index 000000000..6e173c678
--- /dev/null
+++ b/test/stdvector.cpp
@@ -0,0 +1,148 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra.
+//
+// Copyright (C) 2008 Benoit Jacob <jacob.benoit.1@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 "main.h"
+#include <Eigen/StdVector>
+#include <Eigen/Geometry>
+
+template<typename MatrixType>
+void check_stdvector_matrix(const MatrixType& m)
+{
+ typename MatrixType::Index rows = m.rows();
+ typename MatrixType::Index cols = m.cols();
+ MatrixType x = MatrixType::Random(rows,cols), y = MatrixType::Random(rows,cols);
+ std::vector<MatrixType,Eigen::aligned_allocator<MatrixType> > v(10, MatrixType(rows,cols)), w(20, y);
+ v[5] = x;
+ w[6] = v[5];
+ VERIFY_IS_APPROX(w[6], v[5]);
+ v = w;
+ for(int i = 0; i < 20; i++)
+ {
+ VERIFY_IS_APPROX(w[i], v[i]);
+ }
+
+ v.resize(21);
+ v[20] = x;
+ VERIFY_IS_APPROX(v[20], x);
+ v.resize(22,y);
+ VERIFY_IS_APPROX(v[21], y);
+ v.push_back(x);
+ VERIFY_IS_APPROX(v[22], x);
+ VERIFY((size_t)&(v[22]) == (size_t)&(v[21]) + sizeof(MatrixType));
+
+ // do a lot of push_back such that the vector gets internally resized
+ // (with memory reallocation)
+ MatrixType* ref = &w[0];
+ for(int i=0; i<30 || ((ref==&w[0]) && i<300); ++i)
+ v.push_back(w[i%w.size()]);
+ for(unsigned int i=23; i<v.size(); ++i)
+ {
+ VERIFY(v[i]==w[(i-23)%w.size()]);
+ }
+}
+
+template<typename TransformType>
+void check_stdvector_transform(const TransformType&)
+{
+ typedef typename TransformType::MatrixType MatrixType;
+ TransformType x(MatrixType::Random()), y(MatrixType::Random());
+ std::vector<TransformType,Eigen::aligned_allocator<TransformType> > v(10), w(20, y);
+ v[5] = x;
+ w[6] = v[5];
+ VERIFY_IS_APPROX(w[6], v[5]);
+ v = w;
+ for(int i = 0; i < 20; i++)
+ {
+ VERIFY_IS_APPROX(w[i], v[i]);
+ }
+
+ v.resize(21);
+ v[20] = x;
+ VERIFY_IS_APPROX(v[20], x);
+ v.resize(22,y);
+ VERIFY_IS_APPROX(v[21], y);
+ v.push_back(x);
+ VERIFY_IS_APPROX(v[22], x);
+ VERIFY((size_t)&(v[22]) == (size_t)&(v[21]) + sizeof(TransformType));
+
+ // do a lot of push_back such that the vector gets internally resized
+ // (with memory reallocation)
+ TransformType* ref = &w[0];
+ for(int i=0; i<30 || ((ref==&w[0]) && i<300); ++i)
+ v.push_back(w[i%w.size()]);
+ for(unsigned int i=23; i<v.size(); ++i)
+ {
+ VERIFY(v[i].matrix()==w[(i-23)%w.size()].matrix());
+ }
+}
+
+template<typename QuaternionType>
+void check_stdvector_quaternion(const QuaternionType&)
+{
+ typedef typename QuaternionType::Coefficients Coefficients;
+ QuaternionType x(Coefficients::Random()), y(Coefficients::Random());
+ std::vector<QuaternionType,Eigen::aligned_allocator<QuaternionType> > v(10), w(20, y);
+ v[5] = x;
+ w[6] = v[5];
+ VERIFY_IS_APPROX(w[6], v[5]);
+ v = w;
+ for(int i = 0; i < 20; i++)
+ {
+ VERIFY_IS_APPROX(w[i], v[i]);
+ }
+
+ v.resize(21);
+ v[20] = x;
+ VERIFY_IS_APPROX(v[20], x);
+ v.resize(22,y);
+ VERIFY_IS_APPROX(v[21], y);
+ v.push_back(x);
+ VERIFY_IS_APPROX(v[22], x);
+ VERIFY((size_t)&(v[22]) == (size_t)&(v[21]) + sizeof(QuaternionType));
+
+ // do a lot of push_back such that the vector gets internally resized
+ // (with memory reallocation)
+ QuaternionType* ref = &w[0];
+ for(int i=0; i<30 || ((ref==&w[0]) && i<300); ++i)
+ v.push_back(w[i%w.size()]);
+ for(unsigned int i=23; i<v.size(); ++i)
+ {
+ VERIFY(v[i].coeffs()==w[(i-23)%w.size()].coeffs());
+ }
+}
+
+void test_stdvector()
+{
+ // some non vectorizable fixed sizes
+ CALL_SUBTEST_1(check_stdvector_matrix(Vector2f()));
+ CALL_SUBTEST_1(check_stdvector_matrix(Matrix3f()));
+ CALL_SUBTEST_2(check_stdvector_matrix(Matrix3d()));
+
+ // some vectorizable fixed sizes
+ CALL_SUBTEST_1(check_stdvector_matrix(Matrix2f()));
+ CALL_SUBTEST_1(check_stdvector_matrix(Vector4f()));
+ CALL_SUBTEST_1(check_stdvector_matrix(Matrix4f()));
+ CALL_SUBTEST_2(check_stdvector_matrix(Matrix4d()));
+
+ // some dynamic sizes
+ CALL_SUBTEST_3(check_stdvector_matrix(MatrixXd(1,1)));
+ CALL_SUBTEST_3(check_stdvector_matrix(VectorXd(20)));
+ CALL_SUBTEST_3(check_stdvector_matrix(RowVectorXf(20)));
+ CALL_SUBTEST_3(check_stdvector_matrix(MatrixXcf(10,10)));
+
+ // some Transform
+ CALL_SUBTEST_4(check_stdvector_transform(Projective2f()));
+ CALL_SUBTEST_4(check_stdvector_transform(Projective3f()));
+ CALL_SUBTEST_4(check_stdvector_transform(Projective3d()));
+ //CALL_SUBTEST(heck_stdvector_transform(Projective4d()));
+
+ // some Quaternion
+ CALL_SUBTEST_5(check_stdvector_quaternion(Quaternionf()));
+ CALL_SUBTEST_5(check_stdvector_quaternion(Quaterniond()));
+}
diff --git a/test/stdvector_overload.cpp b/test/stdvector_overload.cpp
new file mode 100644
index 000000000..736ff0ee7
--- /dev/null
+++ b/test/stdvector_overload.cpp
@@ -0,0 +1,161 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra.
+//
+// Copyright (C) 2008 Benoit Jacob <jacob.benoit.1@gmail.com>
+// Copyright (C) 2010 Hauke Heibel <hauke.heibel@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 "main.h"
+
+#include <Eigen/StdVector>
+#include <Eigen/Geometry>
+
+EIGEN_DEFINE_STL_VECTOR_SPECIALIZATION(Vector4f)
+
+EIGEN_DEFINE_STL_VECTOR_SPECIALIZATION(Matrix2f)
+EIGEN_DEFINE_STL_VECTOR_SPECIALIZATION(Matrix4f)
+EIGEN_DEFINE_STL_VECTOR_SPECIALIZATION(Matrix4d)
+
+EIGEN_DEFINE_STL_VECTOR_SPECIALIZATION(Affine3f)
+EIGEN_DEFINE_STL_VECTOR_SPECIALIZATION(Affine3d)
+
+EIGEN_DEFINE_STL_VECTOR_SPECIALIZATION(Quaternionf)
+EIGEN_DEFINE_STL_VECTOR_SPECIALIZATION(Quaterniond)
+
+template<typename MatrixType>
+void check_stdvector_matrix(const MatrixType& m)
+{
+ typename MatrixType::Index rows = m.rows();
+ typename MatrixType::Index cols = m.cols();
+ MatrixType x = MatrixType::Random(rows,cols), y = MatrixType::Random(rows,cols);
+ std::vector<MatrixType> v(10, MatrixType(rows,cols)), w(20, y);
+ v[5] = x;
+ w[6] = v[5];
+ VERIFY_IS_APPROX(w[6], v[5]);
+ v = w;
+ for(int i = 0; i < 20; i++)
+ {
+ VERIFY_IS_APPROX(w[i], v[i]);
+ }
+
+ v.resize(21);
+ v[20] = x;
+ VERIFY_IS_APPROX(v[20], x);
+ v.resize(22,y);
+ VERIFY_IS_APPROX(v[21], y);
+ v.push_back(x);
+ VERIFY_IS_APPROX(v[22], x);
+ VERIFY((size_t)&(v[22]) == (size_t)&(v[21]) + sizeof(MatrixType));
+
+ // do a lot of push_back such that the vector gets internally resized
+ // (with memory reallocation)
+ MatrixType* ref = &w[0];
+ for(int i=0; i<30 || ((ref==&w[0]) && i<300); ++i)
+ v.push_back(w[i%w.size()]);
+ for(unsigned int i=23; i<v.size(); ++i)
+ {
+ VERIFY(v[i]==w[(i-23)%w.size()]);
+ }
+}
+
+template<typename TransformType>
+void check_stdvector_transform(const TransformType&)
+{
+ typedef typename TransformType::MatrixType MatrixType;
+ TransformType x(MatrixType::Random()), y(MatrixType::Random());
+ std::vector<TransformType> v(10), w(20, y);
+ v[5] = x;
+ w[6] = v[5];
+ VERIFY_IS_APPROX(w[6], v[5]);
+ v = w;
+ for(int i = 0; i < 20; i++)
+ {
+ VERIFY_IS_APPROX(w[i], v[i]);
+ }
+
+ v.resize(21);
+ v[20] = x;
+ VERIFY_IS_APPROX(v[20], x);
+ v.resize(22,y);
+ VERIFY_IS_APPROX(v[21], y);
+ v.push_back(x);
+ VERIFY_IS_APPROX(v[22], x);
+ VERIFY((size_t)&(v[22]) == (size_t)&(v[21]) + sizeof(TransformType));
+
+ // do a lot of push_back such that the vector gets internally resized
+ // (with memory reallocation)
+ TransformType* ref = &w[0];
+ for(int i=0; i<30 || ((ref==&w[0]) && i<300); ++i)
+ v.push_back(w[i%w.size()]);
+ for(unsigned int i=23; i<v.size(); ++i)
+ {
+ VERIFY(v[i].matrix()==w[(i-23)%w.size()].matrix());
+ }
+}
+
+template<typename QuaternionType>
+void check_stdvector_quaternion(const QuaternionType&)
+{
+ typedef typename QuaternionType::Coefficients Coefficients;
+ QuaternionType x(Coefficients::Random()), y(Coefficients::Random());
+ std::vector<QuaternionType> v(10), w(20, y);
+ v[5] = x;
+ w[6] = v[5];
+ VERIFY_IS_APPROX(w[6], v[5]);
+ v = w;
+ for(int i = 0; i < 20; i++)
+ {
+ VERIFY_IS_APPROX(w[i], v[i]);
+ }
+
+ v.resize(21);
+ v[20] = x;
+ VERIFY_IS_APPROX(v[20], x);
+ v.resize(22,y);
+ VERIFY_IS_APPROX(v[21], y);
+ v.push_back(x);
+ VERIFY_IS_APPROX(v[22], x);
+ VERIFY((size_t)&(v[22]) == (size_t)&(v[21]) + sizeof(QuaternionType));
+
+ // do a lot of push_back such that the vector gets internally resized
+ // (with memory reallocation)
+ QuaternionType* ref = &w[0];
+ for(int i=0; i<30 || ((ref==&w[0]) && i<300); ++i)
+ v.push_back(w[i%w.size()]);
+ for(unsigned int i=23; i<v.size(); ++i)
+ {
+ VERIFY(v[i].coeffs()==w[(i-23)%w.size()].coeffs());
+ }
+}
+
+void test_stdvector_overload()
+{
+ // some non vectorizable fixed sizes
+ CALL_SUBTEST_1(check_stdvector_matrix(Vector2f()));
+ CALL_SUBTEST_1(check_stdvector_matrix(Matrix3f()));
+ CALL_SUBTEST_2(check_stdvector_matrix(Matrix3d()));
+
+ // some vectorizable fixed sizes
+ CALL_SUBTEST_1(check_stdvector_matrix(Matrix2f()));
+ CALL_SUBTEST_1(check_stdvector_matrix(Vector4f()));
+ CALL_SUBTEST_1(check_stdvector_matrix(Matrix4f()));
+ CALL_SUBTEST_2(check_stdvector_matrix(Matrix4d()));
+
+ // some dynamic sizes
+ CALL_SUBTEST_3(check_stdvector_matrix(MatrixXd(1,1)));
+ CALL_SUBTEST_3(check_stdvector_matrix(VectorXd(20)));
+ CALL_SUBTEST_3(check_stdvector_matrix(RowVectorXf(20)));
+ CALL_SUBTEST_3(check_stdvector_matrix(MatrixXcf(10,10)));
+
+ // some Transform
+ CALL_SUBTEST_4(check_stdvector_transform(Affine2f())); // does not need the specialization (2+1)^2 = 9
+ CALL_SUBTEST_4(check_stdvector_transform(Affine3f()));
+ CALL_SUBTEST_4(check_stdvector_transform(Affine3d()));
+
+ // some Quaternion
+ CALL_SUBTEST_5(check_stdvector_quaternion(Quaternionf()));
+ CALL_SUBTEST_5(check_stdvector_quaternion(Quaterniond()));
+}
diff --git a/test/superlu_support.cpp b/test/superlu_support.cpp
new file mode 100644
index 000000000..3b16135bc
--- /dev/null
+++ b/test/superlu_support.cpp
@@ -0,0 +1,22 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra.
+//
+// Copyright (C) 2011 Gael Guennebaud <g.gael@free.fr>
+//
+// This Source Code Form is subject to the terms of the Mozilla
+// Public License v. 2.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 "sparse_solver.h"
+
+#include <Eigen/SuperLUSupport>
+
+void test_superlu_support()
+{
+ SuperLU<SparseMatrix<double> > superlu_double_colmajor;
+ SuperLU<SparseMatrix<std::complex<double> > > superlu_cplxdouble_colmajor;
+ CALL_SUBTEST_1( check_sparse_square_solving(superlu_double_colmajor) );
+ CALL_SUBTEST_2( check_sparse_square_solving(superlu_cplxdouble_colmajor) );
+ CALL_SUBTEST_1( check_sparse_square_determinant(superlu_double_colmajor) );
+ CALL_SUBTEST_2( check_sparse_square_determinant(superlu_cplxdouble_colmajor) );
+}
diff --git a/test/swap.cpp b/test/swap.cpp
new file mode 100644
index 000000000..36b353148
--- /dev/null
+++ b/test/swap.cpp
@@ -0,0 +1,83 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra.
+//
+// Copyright (C) 2009 Benoit Jacob <jacob.benoit.1@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/.
+
+#define EIGEN_NO_STATIC_ASSERT
+#include "main.h"
+
+template<typename T>
+struct other_matrix_type
+{
+ typedef int type;
+};
+
+template<typename _Scalar, int _Rows, int _Cols, int _Options, int _MaxRows, int _MaxCols>
+struct other_matrix_type<Matrix<_Scalar, _Rows, _Cols, _Options, _MaxRows, _MaxCols> >
+{
+ typedef Matrix<_Scalar, _Rows, _Cols, _Options^RowMajor, _MaxRows, _MaxCols> type;
+};
+
+template<typename MatrixType> void swap(const MatrixType& m)
+{
+ typedef typename other_matrix_type<MatrixType>::type OtherMatrixType;
+ typedef typename MatrixType::Scalar Scalar;
+
+ eigen_assert((!internal::is_same<MatrixType,OtherMatrixType>::value));
+ typename MatrixType::Index rows = m.rows();
+ typename MatrixType::Index cols = m.cols();
+
+ // construct 3 matrix guaranteed to be distinct
+ MatrixType m1 = MatrixType::Random(rows,cols);
+ MatrixType m2 = MatrixType::Random(rows,cols) + Scalar(100) * MatrixType::Identity(rows,cols);
+ OtherMatrixType m3 = OtherMatrixType::Random(rows,cols) + Scalar(200) * OtherMatrixType::Identity(rows,cols);
+
+ MatrixType m1_copy = m1;
+ MatrixType m2_copy = m2;
+ OtherMatrixType m3_copy = m3;
+
+ // test swapping 2 matrices of same type
+ m1.swap(m2);
+ VERIFY_IS_APPROX(m1,m2_copy);
+ VERIFY_IS_APPROX(m2,m1_copy);
+ m1 = m1_copy;
+ m2 = m2_copy;
+
+ // test swapping 2 matrices of different types
+ m1.swap(m3);
+ VERIFY_IS_APPROX(m1,m3_copy);
+ VERIFY_IS_APPROX(m3,m1_copy);
+ m1 = m1_copy;
+ m3 = m3_copy;
+
+ // test swapping matrix with expression
+ m1.swap(m2.block(0,0,rows,cols));
+ VERIFY_IS_APPROX(m1,m2_copy);
+ VERIFY_IS_APPROX(m2,m1_copy);
+ m1 = m1_copy;
+ m2 = m2_copy;
+
+ // test swapping two expressions of different types
+ m1.transpose().swap(m3.transpose());
+ VERIFY_IS_APPROX(m1,m3_copy);
+ VERIFY_IS_APPROX(m3,m1_copy);
+ m1 = m1_copy;
+ m3 = m3_copy;
+
+ // test assertion on mismatching size -- matrix case
+ VERIFY_RAISES_ASSERT(m1.swap(m1.row(0)));
+ // test assertion on mismatching size -- xpr case
+ VERIFY_RAISES_ASSERT(m1.row(0).swap(m1));
+}
+
+void test_swap()
+{
+ CALL_SUBTEST_1( swap(Matrix3f()) ); // fixed size, no vectorization
+ CALL_SUBTEST_2( swap(Matrix4d()) ); // fixed size, possible vectorization
+ CALL_SUBTEST_3( swap(MatrixXd(3,3)) ); // dyn size, no vectorization
+ CALL_SUBTEST_4( swap(MatrixXf(30,30)) ); // dyn size, possible vectorization
+}
diff --git a/test/testsuite.cmake b/test/testsuite.cmake
new file mode 100644
index 000000000..3bec56b3f
--- /dev/null
+++ b/test/testsuite.cmake
@@ -0,0 +1,229 @@
+
+####################################################################
+#
+# Usage:
+# - create a new folder, let's call it cdash
+# - in that folder, do:
+# ctest -S path/to/eigen/test/testsuite.cmake[,option1=value1[,option2=value2]]
+#
+# Options:
+# - EIGEN_CXX: compiler, eg.: g++-4.2
+# default: default c++ compiler
+# - EIGEN_SITE: eg, INRIA-Bdx_pc-gael, or the name of the contributor, etc.
+# default: hostname
+# - EIGEN_BUILD_STRING: a string which identify the system/compiler. It should be formed like that:
+# <OS_name>-<OS_version>-<arch>-<compiler-version>
+# with:
+# <OS_name> = opensuse, debian, osx, windows, cygwin, freebsd, solaris, etc.
+# <OS_version> = 11.1, XP, vista, leopard, etc.
+# <arch> = i386, x86_64, ia64, powerpc, etc.
+# <compiler-version> = gcc-4.3.2, icc-11.0, MSVC-2008, etc.
+# - EIGEN_EXPLICIT_VECTORIZATION: novec, SSE2, Altivec
+# default: SSE2 for x86_64 systems, novec otherwise
+# Its value is automatically appended to EIGEN_BUILD_STRING
+# - EIGEN_CMAKE_DIR: path to cmake executable
+# - EIGEN_MODE: dashboard model, can be Experimental, Nightly, or Continuous
+# default: Nightly
+# - EIGEN_WORK_DIR: directory used to download the source files and make the builds
+# default: folder which contains this script
+# - EIGEN_CMAKE_ARGS: additional arguments passed to cmake
+# - EIGEN_GENERATOR_TYPE: allows to overwrite the generator type
+# default: nmake (windows
+# See http://www.cmake.org/cmake/help/cmake2.6docs.html#section_Generators for a complete
+# list of supported generators.
+# - EIGEN_NO_UPDATE: allows to submit dash boards from local repositories
+# This might be interesting in case you want to submit dashboards
+# including local changes.
+# - CTEST_SOURCE_DIRECTORY: path to eigen's src (use a new and empty folder, not the one you are working on)
+# default: <EIGEN_WORK_DIR>/src
+# - CTEST_BINARY_DIRECTORY: build directory
+# default: <EIGEN_WORK_DIR>/nightly-<EIGEN_CXX>
+#
+# Here is an example running several compilers on a linux system:
+# #!/bin/bash
+# ARCH=`uname -m`
+# SITE=`hostname`
+# VERSION=opensuse-11.1
+# WORK_DIR=/home/gael/Coding/eigen/cdash
+# # get the last version of the script
+# wget http://bitbucket.org/eigen/eigen/raw/tip/test/testsuite.cmake -o $WORK_DIR/testsuite.cmake
+# COMMON="ctest -S $WORK_DIR/testsuite.cmake,EIGEN_WORK_DIR=$WORK_DIR,EIGEN_SITE=$SITE,EIGEN_MODE=$1,EIGEN_BUILD_STRING=$OS_VERSION-$ARCH"
+# $COMMON-gcc-3.4.6,EIGEN_CXX=g++-3.4
+# $COMMON-gcc-4.0.1,EIGEN_CXX=g++-4.0.1
+# $COMMON-gcc-4.3.2,EIGEN_CXX=g++-4.3,EIGEN_EXPLICIT_VECTORIZATION=novec
+# $COMMON-gcc-4.3.2,EIGEN_CXX=g++-4.3,EIGEN_EXPLICIT_VECTORIZATION=SSE2
+# $COMMON-icc-11.0,EIGEN_CXX=icpc
+#
+####################################################################
+
+# process the arguments
+
+set(ARGLIST ${CTEST_SCRIPT_ARG})
+while(${ARGLIST} MATCHES ".+.*")
+
+ # pick first
+ string(REGEX MATCH "([^,]*)(,.*)?" DUMMY ${ARGLIST})
+ SET(TOP ${CMAKE_MATCH_1})
+
+ # remove first
+ string(REGEX MATCHALL "[^,]*,(.*)" DUMMY ${ARGLIST})
+ SET(ARGLIST ${CMAKE_MATCH_1})
+
+ # decompose as a pair key=value
+ string(REGEX MATCH "([^=]*)(=.*)?" DUMMY ${TOP})
+ SET(KEY ${CMAKE_MATCH_1})
+
+ string(REGEX MATCH "[^=]*=(.*)" DUMMY ${TOP})
+ SET(VALUE ${CMAKE_MATCH_1})
+
+ # set the variable to the specified value
+ if(VALUE)
+ SET(${KEY} ${VALUE})
+ else(VALUE)
+ SET(${KEY} ON)
+ endif(VALUE)
+
+endwhile(${ARGLIST} MATCHES ".+.*")
+
+####################################################################
+# Automatically set some user variables if they have not been defined manually
+####################################################################
+cmake_minimum_required(VERSION 2.6 FATAL_ERROR)
+
+if(NOT EIGEN_SITE)
+ site_name(EIGEN_SITE)
+endif(NOT EIGEN_SITE)
+
+if(NOT EIGEN_CMAKE_DIR)
+ SET(EIGEN_CMAKE_DIR "")
+endif(NOT EIGEN_CMAKE_DIR)
+
+if(NOT EIGEN_BUILD_STRING)
+
+ # let's try to find all information we need to make the build string ourself
+
+ # OS
+ build_name(EIGEN_OS_VERSION)
+
+ # arch
+ set(EIGEN_ARCH ${CMAKE_SYSTEM_PROCESSOR})
+ if(WIN32)
+ set(EIGEN_ARCH $ENV{PROCESSOR_ARCHITECTURE})
+ else(WIN32)
+ execute_process(COMMAND uname -m OUTPUT_VARIABLE EIGEN_ARCH OUTPUT_STRIP_TRAILING_WHITESPACE)
+ endif(WIN32)
+
+ set(EIGEN_BUILD_STRING ${EIGEN_OS_VERSION}${EIGEN_ARCH}-${EIGEN_CXX})
+
+endif(NOT EIGEN_BUILD_STRING)
+
+if(DEFINED EIGEN_EXPLICIT_VECTORIZATION)
+ set(EIGEN_BUILD_STRING ${EIGEN_BUILD_STRING}-${EIGEN_EXPLICIT_VECTORIZATION})
+endif(DEFINED EIGEN_EXPLICIT_VECTORIZATION)
+
+if(NOT EIGEN_WORK_DIR)
+ set(EIGEN_WORK_DIR ${CTEST_SCRIPT_DIRECTORY})
+endif(NOT EIGEN_WORK_DIR)
+
+if(NOT CTEST_SOURCE_DIRECTORY)
+ SET (CTEST_SOURCE_DIRECTORY "${EIGEN_WORK_DIR}/src")
+endif(NOT CTEST_SOURCE_DIRECTORY)
+
+if(NOT CTEST_BINARY_DIRECTORY)
+ SET (CTEST_BINARY_DIRECTORY "${EIGEN_WORK_DIR}/nightly_${EIGEN_CXX}")
+endif(NOT CTEST_BINARY_DIRECTORY)
+
+if(NOT EIGEN_MODE)
+ set(EIGEN_MODE Nightly)
+endif(NOT EIGEN_MODE)
+
+## mandatory variables (the default should be ok in most cases):
+
+if(NOT EIGEN_NO_UPDATE)
+ SET (CTEST_CVS_COMMAND "hg")
+ SET (CTEST_CVS_CHECKOUT "${CTEST_CVS_COMMAND} clone http://bitbucket.org/eigen/eigen \"${CTEST_SOURCE_DIRECTORY}\"")
+ SET(CTEST_BACKUP_AND_RESTORE TRUE) # the backup is CVS related ...
+endif(NOT EIGEN_NO_UPDATE)
+
+# which ctest command to use for running the dashboard
+SET (CTEST_COMMAND "${EIGEN_CMAKE_DIR}ctest -D ${EIGEN_MODE} --no-compress-output")
+if($ENV{EIGEN_CTEST_ARGS})
+SET (CTEST_COMMAND "${CTEST_COMMAND} $ENV{EIGEN_CTEST_ARGS}")
+endif($ENV{EIGEN_CTEST_ARGS})
+# what cmake command to use for configuring this dashboard
+SET (CTEST_CMAKE_COMMAND "${EIGEN_CMAKE_DIR}cmake -DEIGEN_LEAVE_TEST_IN_ALL_TARGET=ON")
+
+####################################################################
+# The values in this section are optional you can either
+# have them or leave them commented out
+####################################################################
+
+# this make sure we get consistent outputs
+SET($ENV{LC_MESSAGES} "en_EN")
+
+# should ctest wipe the binary tree before running
+SET(CTEST_START_WITH_EMPTY_BINARY_DIRECTORY TRUE)
+
+# raise the warning/error limit
+set(CTEST_CUSTOM_MAXIMUM_NUMBER_OF_WARNINGS "33331")
+set(CTEST_CUSTOM_MAXIMUM_NUMBER_OF_ERRORS "33331")
+
+# this is the initial cache to use for the binary tree, be careful to escape
+# any quotes inside of this string if you use it
+if(WIN32 AND NOT UNIX)
+ #message(SEND_ERROR "win32")
+ if(EIGEN_GENERATOR_TYPE)
+ set(CTEST_CMAKE_COMMAND "${CTEST_CMAKE_COMMAND} -G \"${EIGEN_GENERATOR_TYPE}\"")
+ SET (CTEST_INITIAL_CACHE "
+ CMAKE_BUILD_TYPE:STRING=Release
+ BUILDNAME:STRING=${EIGEN_BUILD_STRING}
+ SITE:STRING=${EIGEN_SITE}
+ ")
+ else(EIGEN_GENERATOR_TYPE)
+ set(CTEST_CMAKE_COMMAND "${CTEST_CMAKE_COMMAND} -G \"NMake Makefiles\" -DCMAKE_MAKE_PROGRAM=nmake")
+ SET (CTEST_INITIAL_CACHE "
+ MAKECOMMAND:STRING=nmake /i
+ CMAKE_MAKE_PROGRAM:FILEPATH=nmake
+ CMAKE_GENERATOR:INTERNAL=NMake Makefiles
+ CMAKE_BUILD_TYPE:STRING=Release
+ BUILDNAME:STRING=${EIGEN_BUILD_STRING}
+ SITE:STRING=${EIGEN_SITE}
+ ")
+ endif(EIGEN_GENERATOR_TYPE)
+else(WIN32 AND NOT UNIX)
+ SET (CTEST_INITIAL_CACHE "
+ BUILDNAME:STRING=${EIGEN_BUILD_STRING}
+ SITE:STRING=${EIGEN_SITE}
+ ")
+endif(WIN32 AND NOT UNIX)
+
+# set any extra environment variables to use during the execution of the script here:
+# setting this variable on windows machines causes trouble ...
+
+if(EIGEN_CXX AND NOT WIN32)
+ set(CTEST_ENVIRONMENT "CXX=${EIGEN_CXX}")
+endif(EIGEN_CXX AND NOT WIN32)
+
+if(DEFINED EIGEN_EXPLICIT_VECTORIZATION)
+ if(EIGEN_EXPLICIT_VECTORIZATION MATCHES SSE2)
+ set(CTEST_CMAKE_COMMAND "${CTEST_CMAKE_COMMAND} -DEIGEN_TEST_SSE2=ON")
+ elseif(EIGEN_EXPLICIT_VECTORIZATION MATCHES SSE3)
+ set(CTEST_CMAKE_COMMAND "${CTEST_CMAKE_COMMAND} -DEIGEN_TEST_SSE2=ON -DEIGEN_TEST_SSE3=ON")
+ elseif(EIGEN_EXPLICIT_VECTORIZATION MATCHES SSSE3)
+ set(CTEST_CMAKE_COMMAND "${CTEST_CMAKE_COMMAND} -DEIGEN_TEST_SSE2=ON -DEIGEN_TEST_SSE3=ON -DEIGEN_TEST_SSSE3=ON")
+ elseif(EIGEN_EXPLICIT_VECTORIZATION MATCHES SSE4_1)
+ set(CTEST_CMAKE_COMMAND "${CTEST_CMAKE_COMMAND} -DEIGEN_TEST_SSE2=ON -DEIGEN_TEST_SSE3=ON -DEIGEN_TEST_SSSE3=ON -DEIGEN_TEST_SSE4_1=ON")
+ elseif(EIGEN_EXPLICIT_VECTORIZATION MATCHES SSE4_2)
+ set(CTEST_CMAKE_COMMAND "${CTEST_CMAKE_COMMAND} -DEIGEN_TEST_SSE2=ON -DEIGEN_TEST_SSE3=ON -DEIGEN_TEST_SSSE3=ON -DEIGEN_TEST_SSE4_1=ON -DEIGEN_TEST_SSE4_2=ON")
+ elseif(EIGEN_EXPLICIT_VECTORIZATION MATCHES Altivec)
+ set(CTEST_CMAKE_COMMAND "${CTEST_CMAKE_COMMAND} -DEIGEN_TEST_ALTIVEC=ON")
+ elseif(EIGEN_EXPLICIT_VECTORIZATION MATCHES novec)
+ set(CTEST_CMAKE_COMMAND "${CTEST_CMAKE_COMMAND} -DEIGEN_TEST_NO_EXPLICIT_VECTORIZATION=ON")
+ else(EIGEN_EXPLICIT_VECTORIZATION MATCHES SSE2)
+ message(FATAL_ERROR "Invalid value for EIGEN_EXPLICIT_VECTORIZATION (${EIGEN_EXPLICIT_VECTORIZATION}), must be: novec, SSE2, SSE3, Altivec")
+ endif(EIGEN_EXPLICIT_VECTORIZATION MATCHES SSE2)
+endif(DEFINED EIGEN_EXPLICIT_VECTORIZATION)
+
+if(DEFINED EIGEN_CMAKE_ARGS)
+ set(CTEST_CMAKE_COMMAND "${CTEST_CMAKE_COMMAND} ${EIGEN_CMAKE_ARGS}")
+endif(DEFINED EIGEN_CMAKE_ARGS)
diff --git a/test/triangular.cpp b/test/triangular.cpp
new file mode 100644
index 000000000..0e8ee5487
--- /dev/null
+++ b/test/triangular.cpp
@@ -0,0 +1,235 @@
+// This file is triangularView of Eigen, a lightweight C++ template library
+// for linear algebra.
+//
+// Copyright (C) 2008-2009 Gael Guennebaud <gael.guennebaud@inria.fr>
+//
+// This Source Code Form is subject to the terms of the Mozilla
+// Public License v. 2.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 "main.h"
+
+
+
+template<typename MatrixType> void triangular_square(const MatrixType& m)
+{
+ typedef typename MatrixType::Scalar Scalar;
+ typedef typename NumTraits<Scalar>::Real RealScalar;
+ typedef Matrix<Scalar, MatrixType::RowsAtCompileTime, 1> VectorType;
+
+ RealScalar largerEps = 10*test_precision<RealScalar>();
+
+ typename MatrixType::Index rows = m.rows();
+ typename MatrixType::Index cols = m.cols();
+
+ MatrixType m1 = MatrixType::Random(rows, cols),
+ m2 = MatrixType::Random(rows, cols),
+ m3(rows, cols),
+ m4(rows, cols),
+ r1(rows, cols),
+ r2(rows, cols);
+ VectorType v2 = VectorType::Random(rows);
+
+ MatrixType m1up = m1.template triangularView<Upper>();
+ MatrixType m2up = m2.template triangularView<Upper>();
+
+ if (rows*cols>1)
+ {
+ VERIFY(m1up.isUpperTriangular());
+ VERIFY(m2up.transpose().isLowerTriangular());
+ VERIFY(!m2.isLowerTriangular());
+ }
+
+// VERIFY_IS_APPROX(m1up.transpose() * m2, m1.upper().transpose().lower() * m2);
+
+ // test overloaded operator+=
+ r1.setZero();
+ r2.setZero();
+ r1.template triangularView<Upper>() += m1;
+ r2 += m1up;
+ VERIFY_IS_APPROX(r1,r2);
+
+ // test overloaded operator=
+ m1.setZero();
+ m1.template triangularView<Upper>() = m2.transpose() + m2;
+ m3 = m2.transpose() + m2;
+ VERIFY_IS_APPROX(m3.template triangularView<Lower>().transpose().toDenseMatrix(), m1);
+
+ // test overloaded operator=
+ m1.setZero();
+ m1.template triangularView<Lower>() = m2.transpose() + m2;
+ VERIFY_IS_APPROX(m3.template triangularView<Lower>().toDenseMatrix(), m1);
+
+ VERIFY_IS_APPROX(m3.template triangularView<Lower>().conjugate().toDenseMatrix(),
+ m3.conjugate().template triangularView<Lower>().toDenseMatrix());
+
+ m1 = MatrixType::Random(rows, cols);
+ for (int i=0; i<rows; ++i)
+ while (internal::abs2(m1(i,i))<1e-1) m1(i,i) = internal::random<Scalar>();
+
+ Transpose<MatrixType> trm4(m4);
+ // test back and forward subsitution with a vector as the rhs
+ m3 = m1.template triangularView<Upper>();
+ VERIFY(v2.isApprox(m3.adjoint() * (m1.adjoint().template triangularView<Lower>().solve(v2)), largerEps));
+ m3 = m1.template triangularView<Lower>();
+ VERIFY(v2.isApprox(m3.transpose() * (m1.transpose().template triangularView<Upper>().solve(v2)), largerEps));
+ m3 = m1.template triangularView<Upper>();
+ VERIFY(v2.isApprox(m3 * (m1.template triangularView<Upper>().solve(v2)), largerEps));
+ m3 = m1.template triangularView<Lower>();
+ VERIFY(v2.isApprox(m3.conjugate() * (m1.conjugate().template triangularView<Lower>().solve(v2)), largerEps));
+
+ // test back and forward subsitution with a matrix as the rhs
+ m3 = m1.template triangularView<Upper>();
+ VERIFY(m2.isApprox(m3.adjoint() * (m1.adjoint().template triangularView<Lower>().solve(m2)), largerEps));
+ m3 = m1.template triangularView<Lower>();
+ VERIFY(m2.isApprox(m3.transpose() * (m1.transpose().template triangularView<Upper>().solve(m2)), largerEps));
+ m3 = m1.template triangularView<Upper>();
+ VERIFY(m2.isApprox(m3 * (m1.template triangularView<Upper>().solve(m2)), largerEps));
+ m3 = m1.template triangularView<Lower>();
+ VERIFY(m2.isApprox(m3.conjugate() * (m1.conjugate().template triangularView<Lower>().solve(m2)), largerEps));
+
+ // check M * inv(L) using in place API
+ m4 = m3;
+ m1.transpose().template triangularView<Eigen::Upper>().solveInPlace(trm4);
+ VERIFY_IS_APPROX(m4 * m1.template triangularView<Eigen::Lower>(), m3);
+
+ // check M * inv(U) using in place API
+ m3 = m1.template triangularView<Upper>();
+ m4 = m3;
+ m3.transpose().template triangularView<Eigen::Lower>().solveInPlace(trm4);
+ VERIFY_IS_APPROX(m4 * m1.template triangularView<Eigen::Upper>(), m3);
+
+ // check solve with unit diagonal
+ m3 = m1.template triangularView<UnitUpper>();
+ VERIFY(m2.isApprox(m3 * (m1.template triangularView<UnitUpper>().solve(m2)), largerEps));
+
+// VERIFY(( m1.template triangularView<Upper>()
+// * m2.template triangularView<Upper>()).isUpperTriangular());
+
+ // test swap
+ m1.setOnes();
+ m2.setZero();
+ m2.template triangularView<Upper>().swap(m1);
+ m3.setZero();
+ m3.template triangularView<Upper>().setOnes();
+ VERIFY_IS_APPROX(m2,m3);
+
+}
+
+
+template<typename MatrixType> void triangular_rect(const MatrixType& m)
+{
+ typedef const typename MatrixType::Index Index;
+ typedef typename MatrixType::Scalar Scalar;
+ typedef typename NumTraits<Scalar>::Real RealScalar;
+ enum { Rows = MatrixType::RowsAtCompileTime, Cols = MatrixType::ColsAtCompileTime };
+ typedef Matrix<Scalar, Rows, 1> VectorType;
+ typedef Matrix<Scalar, Rows, Rows> RMatrixType;
+
+
+ Index rows = m.rows();
+ Index cols = m.cols();
+
+ MatrixType m1 = MatrixType::Random(rows, cols),
+ m2 = MatrixType::Random(rows, cols),
+ m3(rows, cols),
+ m4(rows, cols),
+ r1(rows, cols),
+ r2(rows, cols);
+
+ MatrixType m1up = m1.template triangularView<Upper>();
+ MatrixType m2up = m2.template triangularView<Upper>();
+
+ if (rows>1 && cols>1)
+ {
+ VERIFY(m1up.isUpperTriangular());
+ VERIFY(m2up.transpose().isLowerTriangular());
+ VERIFY(!m2.isLowerTriangular());
+ }
+
+ // test overloaded operator+=
+ r1.setZero();
+ r2.setZero();
+ r1.template triangularView<Upper>() += m1;
+ r2 += m1up;
+ VERIFY_IS_APPROX(r1,r2);
+
+ // test overloaded operator=
+ m1.setZero();
+ m1.template triangularView<Upper>() = 3 * m2;
+ m3 = 3 * m2;
+ VERIFY_IS_APPROX(m3.template triangularView<Upper>().toDenseMatrix(), m1);
+
+
+ m1.setZero();
+ m1.template triangularView<Lower>() = 3 * m2;
+ VERIFY_IS_APPROX(m3.template triangularView<Lower>().toDenseMatrix(), m1);
+
+ m1.setZero();
+ m1.template triangularView<StrictlyUpper>() = 3 * m2;
+ VERIFY_IS_APPROX(m3.template triangularView<StrictlyUpper>().toDenseMatrix(), m1);
+
+
+ m1.setZero();
+ m1.template triangularView<StrictlyLower>() = 3 * m2;
+ VERIFY_IS_APPROX(m3.template triangularView<StrictlyLower>().toDenseMatrix(), m1);
+ m1.setRandom();
+ m2 = m1.template triangularView<Upper>();
+ VERIFY(m2.isUpperTriangular());
+ VERIFY(!m2.isLowerTriangular());
+ m2 = m1.template triangularView<StrictlyUpper>();
+ VERIFY(m2.isUpperTriangular());
+ VERIFY(m2.diagonal().isMuchSmallerThan(RealScalar(1)));
+ m2 = m1.template triangularView<UnitUpper>();
+ VERIFY(m2.isUpperTriangular());
+ m2.diagonal().array() -= Scalar(1);
+ VERIFY(m2.diagonal().isMuchSmallerThan(RealScalar(1)));
+ m2 = m1.template triangularView<Lower>();
+ VERIFY(m2.isLowerTriangular());
+ VERIFY(!m2.isUpperTriangular());
+ m2 = m1.template triangularView<StrictlyLower>();
+ VERIFY(m2.isLowerTriangular());
+ VERIFY(m2.diagonal().isMuchSmallerThan(RealScalar(1)));
+ m2 = m1.template triangularView<UnitLower>();
+ VERIFY(m2.isLowerTriangular());
+ m2.diagonal().array() -= Scalar(1);
+ VERIFY(m2.diagonal().isMuchSmallerThan(RealScalar(1)));
+ // test swap
+ m1.setOnes();
+ m2.setZero();
+ m2.template triangularView<Upper>().swap(m1);
+ m3.setZero();
+ m3.template triangularView<Upper>().setOnes();
+ VERIFY_IS_APPROX(m2,m3);
+}
+
+void bug_159()
+{
+ Matrix3d m = Matrix3d::Random().triangularView<Lower>();
+ EIGEN_UNUSED_VARIABLE(m)
+}
+
+void test_triangular()
+{
+ int maxsize = (std::min)(EIGEN_TEST_MAX_SIZE,20);
+ for(int i = 0; i < g_repeat ; i++)
+ {
+ int r = internal::random<int>(2,maxsize); EIGEN_UNUSED_VARIABLE(r);
+ int c = internal::random<int>(2,maxsize); EIGEN_UNUSED_VARIABLE(c);
+
+ CALL_SUBTEST_1( triangular_square(Matrix<float, 1, 1>()) );
+ CALL_SUBTEST_2( triangular_square(Matrix<float, 2, 2>()) );
+ CALL_SUBTEST_3( triangular_square(Matrix3d()) );
+ CALL_SUBTEST_4( triangular_square(Matrix<std::complex<float>,8, 8>()) );
+ CALL_SUBTEST_5( triangular_square(MatrixXcd(r,r)) );
+ CALL_SUBTEST_6( triangular_square(Matrix<float,Dynamic,Dynamic,RowMajor>(r, r)) );
+
+ CALL_SUBTEST_7( triangular_rect(Matrix<float, 4, 5>()) );
+ CALL_SUBTEST_8( triangular_rect(Matrix<double, 6, 2>()) );
+ CALL_SUBTEST_9( triangular_rect(MatrixXcf(r, c)) );
+ CALL_SUBTEST_5( triangular_rect(MatrixXcd(r, c)) );
+ CALL_SUBTEST_6( triangular_rect(Matrix<float,Dynamic,Dynamic,RowMajor>(r, c)) );
+ }
+
+ CALL_SUBTEST_1( bug_159() );
+}
diff --git a/test/umeyama.cpp b/test/umeyama.cpp
new file mode 100644
index 000000000..b6c9be3a5
--- /dev/null
+++ b/test/umeyama.cpp
@@ -0,0 +1,183 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra.
+//
+// Copyright (C) 2009 Hauke Heibel <hauke.heibel@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 "main.h"
+
+#include <Eigen/Core>
+#include <Eigen/Geometry>
+
+#include <Eigen/LU> // required for MatrixBase::determinant
+#include <Eigen/SVD> // required for SVD
+
+using namespace Eigen;
+
+// Constructs a random matrix from the unitary group U(size).
+template <typename T>
+Eigen::Matrix<T, Eigen::Dynamic, Eigen::Dynamic> randMatrixUnitary(int size)
+{
+ typedef T Scalar;
+ typedef typename NumTraits<Scalar>::Real RealScalar;
+
+ typedef Eigen::Matrix<Scalar, Eigen::Dynamic, Eigen::Dynamic> MatrixType;
+
+ MatrixType Q;
+
+ int max_tries = 40;
+ double is_unitary = false;
+
+ while (!is_unitary && max_tries > 0)
+ {
+ // initialize random matrix
+ Q = MatrixType::Random(size, size);
+
+ // orthogonalize columns using the Gram-Schmidt algorithm
+ for (int col = 0; col < size; ++col)
+ {
+ typename MatrixType::ColXpr colVec = Q.col(col);
+ for (int prevCol = 0; prevCol < col; ++prevCol)
+ {
+ typename MatrixType::ColXpr prevColVec = Q.col(prevCol);
+ colVec -= colVec.dot(prevColVec)*prevColVec;
+ }
+ Q.col(col) = colVec.normalized();
+ }
+
+ // this additional orthogonalization is not necessary in theory but should enhance
+ // the numerical orthogonality of the matrix
+ for (int row = 0; row < size; ++row)
+ {
+ typename MatrixType::RowXpr rowVec = Q.row(row);
+ for (int prevRow = 0; prevRow < row; ++prevRow)
+ {
+ typename MatrixType::RowXpr prevRowVec = Q.row(prevRow);
+ rowVec -= rowVec.dot(prevRowVec)*prevRowVec;
+ }
+ Q.row(row) = rowVec.normalized();
+ }
+
+ // final check
+ is_unitary = Q.isUnitary();
+ --max_tries;
+ }
+
+ if (max_tries == 0)
+ eigen_assert(false && "randMatrixUnitary: Could not construct unitary matrix!");
+
+ return Q;
+}
+
+// Constructs a random matrix from the special unitary group SU(size).
+template <typename T>
+Eigen::Matrix<T, Eigen::Dynamic, Eigen::Dynamic> randMatrixSpecialUnitary(int size)
+{
+ typedef T Scalar;
+ typedef typename NumTraits<Scalar>::Real RealScalar;
+
+ typedef Eigen::Matrix<Scalar, Eigen::Dynamic, Eigen::Dynamic> MatrixType;
+
+ // initialize unitary matrix
+ MatrixType Q = randMatrixUnitary<Scalar>(size);
+
+ // tweak the first column to make the determinant be 1
+ Q.col(0) *= internal::conj(Q.determinant());
+
+ return Q;
+}
+
+template <typename MatrixType>
+void run_test(int dim, int num_elements)
+{
+ typedef typename internal::traits<MatrixType>::Scalar Scalar;
+ typedef Matrix<Scalar, Eigen::Dynamic, Eigen::Dynamic> MatrixX;
+ typedef Matrix<Scalar, Eigen::Dynamic, 1> VectorX;
+
+ // MUST be positive because in any other case det(cR_t) may become negative for
+ // odd dimensions!
+ const Scalar c = internal::abs(internal::random<Scalar>());
+
+ MatrixX R = randMatrixSpecialUnitary<Scalar>(dim);
+ VectorX t = Scalar(50)*VectorX::Random(dim,1);
+
+ MatrixX cR_t = MatrixX::Identity(dim+1,dim+1);
+ cR_t.block(0,0,dim,dim) = c*R;
+ cR_t.block(0,dim,dim,1) = t;
+
+ MatrixX src = MatrixX::Random(dim+1, num_elements);
+ src.row(dim) = Matrix<Scalar, 1, Dynamic>::Constant(num_elements, Scalar(1));
+
+ MatrixX dst = cR_t*src;
+
+ MatrixX cR_t_umeyama = umeyama(src.block(0,0,dim,num_elements), dst.block(0,0,dim,num_elements));
+
+ const Scalar error = ( cR_t_umeyama*src - dst ).norm() / dst.norm();
+ VERIFY(error < Scalar(40)*std::numeric_limits<Scalar>::epsilon());
+}
+
+template<typename Scalar, int Dimension>
+void run_fixed_size_test(int num_elements)
+{
+ typedef Matrix<Scalar, Dimension+1, Dynamic> MatrixX;
+ typedef Matrix<Scalar, Dimension+1, Dimension+1> HomMatrix;
+ typedef Matrix<Scalar, Dimension, Dimension> FixedMatrix;
+ typedef Matrix<Scalar, Dimension, 1> FixedVector;
+
+ const int dim = Dimension;
+
+ // MUST be positive because in any other case det(cR_t) may become negative for
+ // odd dimensions!
+ const Scalar c = internal::abs(internal::random<Scalar>());
+
+ FixedMatrix R = randMatrixSpecialUnitary<Scalar>(dim);
+ FixedVector t = Scalar(50)*FixedVector::Random(dim,1);
+
+ HomMatrix cR_t = HomMatrix::Identity(dim+1,dim+1);
+ cR_t.block(0,0,dim,dim) = c*R;
+ cR_t.block(0,dim,dim,1) = t;
+
+ MatrixX src = MatrixX::Random(dim+1, num_elements);
+ src.row(dim) = Matrix<Scalar, 1, Dynamic>::Constant(num_elements, Scalar(1));
+
+ MatrixX dst = cR_t*src;
+
+ Block<MatrixX, Dimension, Dynamic> src_block(src,0,0,dim,num_elements);
+ Block<MatrixX, Dimension, Dynamic> dst_block(dst,0,0,dim,num_elements);
+
+ HomMatrix cR_t_umeyama = umeyama(src_block, dst_block);
+
+ const Scalar error = ( cR_t_umeyama*src - dst ).array().square().sum();
+
+ VERIFY(error < Scalar(10)*std::numeric_limits<Scalar>::epsilon());
+}
+
+void test_umeyama()
+{
+ for (int i=0; i<g_repeat; ++i)
+ {
+ const int num_elements = internal::random<int>(40,500);
+
+ // works also for dimensions bigger than 3...
+ for (int dim=2; dim<8; ++dim)
+ {
+ CALL_SUBTEST_1(run_test<MatrixXd>(dim, num_elements));
+ CALL_SUBTEST_2(run_test<MatrixXf>(dim, num_elements));
+ }
+
+ CALL_SUBTEST_3((run_fixed_size_test<float, 2>(num_elements)));
+ CALL_SUBTEST_4((run_fixed_size_test<float, 3>(num_elements)));
+ CALL_SUBTEST_5((run_fixed_size_test<float, 4>(num_elements)));
+
+ CALL_SUBTEST_6((run_fixed_size_test<double, 2>(num_elements)));
+ CALL_SUBTEST_7((run_fixed_size_test<double, 3>(num_elements)));
+ CALL_SUBTEST_8((run_fixed_size_test<double, 4>(num_elements)));
+ }
+
+ // Those two calls don't compile and result in meaningful error messages!
+ // umeyama(MatrixXcf(),MatrixXcf());
+ // umeyama(MatrixXcd(),MatrixXcd());
+}
diff --git a/test/umfpack_support.cpp b/test/umfpack_support.cpp
new file mode 100644
index 000000000..9eb84c14b
--- /dev/null
+++ b/test/umfpack_support.cpp
@@ -0,0 +1,31 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra.
+//
+// Copyright (C) 2011 Gael Guennebaud <g.gael@free.fr>
+//
+// This Source Code Form is subject to the terms of the Mozilla
+// Public License v. 2.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 "sparse_solver.h"
+
+#include <Eigen/UmfPackSupport>
+
+template<typename T> void test_umfpack_support_T()
+{
+ UmfPackLU<SparseMatrix<T, ColMajor> > umfpack_colmajor;
+ UmfPackLU<SparseMatrix<T, RowMajor> > umfpack_rowmajor;
+
+ check_sparse_square_solving(umfpack_colmajor);
+ check_sparse_square_solving(umfpack_rowmajor);
+
+ check_sparse_square_determinant(umfpack_colmajor);
+ check_sparse_square_determinant(umfpack_rowmajor);
+}
+
+void test_umfpack_support()
+{
+ CALL_SUBTEST_1(test_umfpack_support_T<double>());
+ CALL_SUBTEST_2(test_umfpack_support_T<std::complex<double> >());
+}
+
diff --git a/test/unalignedassert.cpp b/test/unalignedassert.cpp
new file mode 100644
index 000000000..601dbf214
--- /dev/null
+++ b/test/unalignedassert.cpp
@@ -0,0 +1,127 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra.
+//
+// Copyright (C) 2008 Benoit Jacob <jacob.benoit.1@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 "main.h"
+
+struct TestNew1
+{
+ MatrixXd m; // good: m will allocate its own array, taking care of alignment.
+ TestNew1() : m(20,20) {}
+};
+
+struct TestNew2
+{
+ Matrix3d m; // good: m's size isn't a multiple of 16 bytes, so m doesn't have to be 16-byte aligned,
+ // 8-byte alignment is good enough here, which we'll get automatically
+};
+
+struct TestNew3
+{
+ Vector2f m; // good: m's size isn't a multiple of 16 bytes, so m doesn't have to be 16-byte aligned
+};
+
+struct TestNew4
+{
+ EIGEN_MAKE_ALIGNED_OPERATOR_NEW
+ Vector2d m;
+ float f; // make the struct have sizeof%16!=0 to make it a little more tricky when we allow an array of 2 such objects
+};
+
+struct TestNew5
+{
+ EIGEN_MAKE_ALIGNED_OPERATOR_NEW
+ float f; // try the f at first -- the EIGEN_ALIGN16 attribute of m should make that still work
+ Matrix4f m;
+};
+
+struct TestNew6
+{
+ Matrix<float,2,2,DontAlign> m; // good: no alignment requested
+ float f;
+};
+
+template<bool Align> struct Depends
+{
+ EIGEN_MAKE_ALIGNED_OPERATOR_NEW_IF(Align)
+ Vector2d m;
+ float f;
+};
+
+template<typename T>
+void check_unalignedassert_good()
+{
+ T *x, *y;
+ x = new T;
+ delete x;
+ y = new T[2];
+ delete[] y;
+}
+
+#if EIGEN_ALIGN_STATICALLY
+template<typename T>
+void construct_at_boundary(int boundary)
+{
+ char buf[sizeof(T)+256];
+ size_t _buf = reinterpret_cast<size_t>(buf);
+ _buf += (16 - (_buf % 16)); // make 16-byte aligned
+ _buf += boundary; // make exact boundary-aligned
+ T *x = ::new(reinterpret_cast<void*>(_buf)) T;
+ x[0].setZero(); // just in order to silence warnings
+ x->~T();
+}
+#endif
+
+void unalignedassert()
+{
+ #if EIGEN_ALIGN_STATICALLY
+ construct_at_boundary<Vector2f>(4);
+ construct_at_boundary<Vector3f>(4);
+ construct_at_boundary<Vector4f>(16);
+ construct_at_boundary<Matrix2f>(16);
+ construct_at_boundary<Matrix3f>(4);
+ construct_at_boundary<Matrix4f>(16);
+
+ construct_at_boundary<Vector2d>(16);
+ construct_at_boundary<Vector3d>(4);
+ construct_at_boundary<Vector4d>(16);
+ construct_at_boundary<Matrix2d>(16);
+ construct_at_boundary<Matrix3d>(4);
+ construct_at_boundary<Matrix4d>(16);
+
+ construct_at_boundary<Vector2cf>(16);
+ construct_at_boundary<Vector3cf>(4);
+ construct_at_boundary<Vector2cd>(16);
+ construct_at_boundary<Vector3cd>(16);
+ #endif
+
+ check_unalignedassert_good<TestNew1>();
+ check_unalignedassert_good<TestNew2>();
+ check_unalignedassert_good<TestNew3>();
+
+ check_unalignedassert_good<TestNew4>();
+ check_unalignedassert_good<TestNew5>();
+ check_unalignedassert_good<TestNew6>();
+ check_unalignedassert_good<Depends<true> >();
+
+#if EIGEN_ALIGN_STATICALLY
+ VERIFY_RAISES_ASSERT(construct_at_boundary<Vector4f>(8));
+ VERIFY_RAISES_ASSERT(construct_at_boundary<Matrix4f>(8));
+ VERIFY_RAISES_ASSERT(construct_at_boundary<Vector2d>(8));
+ VERIFY_RAISES_ASSERT(construct_at_boundary<Vector4d>(8));
+ VERIFY_RAISES_ASSERT(construct_at_boundary<Matrix2d>(8));
+ VERIFY_RAISES_ASSERT(construct_at_boundary<Matrix4d>(8));
+ VERIFY_RAISES_ASSERT(construct_at_boundary<Vector2cf>(8));
+ VERIFY_RAISES_ASSERT(construct_at_boundary<Vector2cd>(8));
+#endif
+}
+
+void test_unalignedassert()
+{
+ CALL_SUBTEST(unalignedassert());
+}
diff --git a/test/unalignedcount.cpp b/test/unalignedcount.cpp
new file mode 100644
index 000000000..5451159e6
--- /dev/null
+++ b/test/unalignedcount.cpp
@@ -0,0 +1,44 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra.
+//
+// Copyright (C) 2009 Gael Guennebaud <gael.guennebaud@inria.fr>
+//
+// This Source Code Form is subject to the terms of the Mozilla
+// Public License v. 2.0. If a copy of the MPL was not distributed
+// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+static int nb_load;
+static int nb_loadu;
+static int nb_store;
+static int nb_storeu;
+
+#define EIGEN_DEBUG_ALIGNED_LOAD { nb_load++; }
+#define EIGEN_DEBUG_UNALIGNED_LOAD { nb_loadu++; }
+#define EIGEN_DEBUG_ALIGNED_STORE { nb_store++; }
+#define EIGEN_DEBUG_UNALIGNED_STORE { nb_storeu++; }
+
+#define VERIFY_ALIGNED_UNALIGNED_COUNT(XPR,AL,UL,AS,US) {\
+ nb_load = nb_loadu = nb_store = nb_storeu = 0; \
+ XPR; \
+ if(!(nb_load==AL && nb_loadu==UL && nb_store==AS && nb_storeu==US)) \
+ std::cerr << " >> " << nb_load << ", " << nb_loadu << ", " << nb_store << ", " << nb_storeu << "\n"; \
+ VERIFY( (#XPR) && nb_load==AL && nb_loadu==UL && nb_store==AS && nb_storeu==US ); \
+ }
+
+
+#include "main.h"
+
+void test_unalignedcount()
+{
+ #ifdef EIGEN_VECTORIZE_SSE
+ VectorXf a(40), b(40);
+ VERIFY_ALIGNED_UNALIGNED_COUNT(a += b, 20, 0, 10, 0);
+ VERIFY_ALIGNED_UNALIGNED_COUNT(a.segment(0,40) += b.segment(0,40), 10, 10, 10, 0);
+ VERIFY_ALIGNED_UNALIGNED_COUNT(a.segment(0,40) -= b.segment(0,40), 10, 10, 10, 0);
+ VERIFY_ALIGNED_UNALIGNED_COUNT(a.segment(0,40) *= 3.5, 10, 0, 10, 0);
+ VERIFY_ALIGNED_UNALIGNED_COUNT(a.segment(0,40) /= 3.5, 10, 0, 10, 0);
+ #else
+ // The following line is to eliminate "variable not used" warnings
+ nb_load = nb_loadu = nb_store = nb_storeu = 0;
+ #endif
+}
diff --git a/test/upperbidiagonalization.cpp b/test/upperbidiagonalization.cpp
new file mode 100644
index 000000000..db6ce383e
--- /dev/null
+++ b/test/upperbidiagonalization.cpp
@@ -0,0 +1,41 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra.
+//
+// Copyright (C) 2010 Benoit Jacob <jacob.benoit.1@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 "main.h"
+#include <Eigen/SVD>
+
+template<typename MatrixType> void upperbidiag(const MatrixType& m)
+{
+ const typename MatrixType::Index rows = m.rows();
+ const typename MatrixType::Index cols = m.cols();
+
+ typedef typename MatrixType::Scalar Scalar;
+ typedef Matrix<typename MatrixType::RealScalar, MatrixType::RowsAtCompileTime, MatrixType::ColsAtCompileTime> RealMatrixType;
+
+ MatrixType a = MatrixType::Random(rows,cols);
+ internal::UpperBidiagonalization<MatrixType> ubd(a);
+ RealMatrixType b(rows, cols);
+ b.setZero();
+ b.block(0,0,cols,cols) = ubd.bidiagonal();
+ MatrixType c = ubd.householderU() * b * ubd.householderV().adjoint();
+ VERIFY_IS_APPROX(a,c);
+}
+
+void test_upperbidiagonalization()
+{
+ for(int i = 0; i < g_repeat; i++) {
+ CALL_SUBTEST_1( upperbidiag(MatrixXf(3,3)) );
+ CALL_SUBTEST_2( upperbidiag(MatrixXd(17,12)) );
+ CALL_SUBTEST_3( upperbidiag(MatrixXcf(20,20)) );
+ CALL_SUBTEST_4( upperbidiag(MatrixXcd(16,15)) );
+ CALL_SUBTEST_5( upperbidiag(Matrix<float,6,4>()) );
+ CALL_SUBTEST_6( upperbidiag(Matrix<float,5,5>()) );
+ CALL_SUBTEST_7( upperbidiag(Matrix<double,4,3>()) );
+ }
+}
diff --git a/test/vectorization_logic.cpp b/test/vectorization_logic.cpp
new file mode 100644
index 000000000..aee68a87f
--- /dev/null
+++ b/test/vectorization_logic.cpp
@@ -0,0 +1,235 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra.
+//
+// Copyright (C) 2008 Gael Guennebaud <gael.guennebaud@inria.fr>
+//
+// This Source Code Form is subject to the terms of the Mozilla
+// Public License v. 2.0. If a copy of the MPL was not distributed
+// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+#define EIGEN_DEBUG_ASSIGN
+#include "main.h"
+#include <typeinfo>
+
+std::string demangle_traversal(int t)
+{
+ if(t==DefaultTraversal) return "DefaultTraversal";
+ if(t==LinearTraversal) return "LinearTraversal";
+ if(t==InnerVectorizedTraversal) return "InnerVectorizedTraversal";
+ if(t==LinearVectorizedTraversal) return "LinearVectorizedTraversal";
+ if(t==SliceVectorizedTraversal) return "SliceVectorizedTraversal";
+ return "?";
+}
+std::string demangle_unrolling(int t)
+{
+ if(t==NoUnrolling) return "NoUnrolling";
+ if(t==InnerUnrolling) return "InnerUnrolling";
+ if(t==CompleteUnrolling) return "CompleteUnrolling";
+ return "?";
+}
+
+template<typename Dst, typename Src>
+bool test_assign(const Dst&, const Src&, int traversal, int unrolling)
+{
+ internal::assign_traits<Dst,Src>::debug();
+ bool res = internal::assign_traits<Dst,Src>::Traversal==traversal
+ && internal::assign_traits<Dst,Src>::Unrolling==unrolling;
+ if(!res)
+ {
+ std::cerr << " Expected Traversal == " << demangle_traversal(traversal)
+ << " got " << demangle_traversal(internal::assign_traits<Dst,Src>::Traversal) << "\n";
+ std::cerr << " Expected Unrolling == " << demangle_unrolling(unrolling)
+ << " got " << demangle_unrolling(internal::assign_traits<Dst,Src>::Unrolling) << "\n";
+ }
+ return res;
+}
+
+template<typename Dst, typename Src>
+bool test_assign(int traversal, int unrolling)
+{
+ internal::assign_traits<Dst,Src>::debug();
+ bool res = internal::assign_traits<Dst,Src>::Traversal==traversal
+ && internal::assign_traits<Dst,Src>::Unrolling==unrolling;
+ if(!res)
+ {
+ std::cerr << " Expected Traversal == " << demangle_traversal(traversal)
+ << " got " << demangle_traversal(internal::assign_traits<Dst,Src>::Traversal) << "\n";
+ std::cerr << " Expected Unrolling == " << demangle_unrolling(unrolling)
+ << " got " << demangle_unrolling(internal::assign_traits<Dst,Src>::Unrolling) << "\n";
+ }
+ return res;
+}
+
+template<typename Xpr>
+bool test_redux(const Xpr&, int traversal, int unrolling)
+{
+ typedef internal::redux_traits<internal::scalar_sum_op<typename Xpr::Scalar>,Xpr> traits;
+ bool res = traits::Traversal==traversal && traits::Unrolling==unrolling;
+ if(!res)
+ {
+ std::cerr << " Expected Traversal == " << demangle_traversal(traversal)
+ << " got " << demangle_traversal(traits::Traversal) << "\n";
+ std::cerr << " Expected Unrolling == " << demangle_unrolling(unrolling)
+ << " got " << demangle_unrolling(traits::Unrolling) << "\n";
+ }
+ return res;
+}
+
+template<typename Scalar, bool Enable = internal::packet_traits<Scalar>::Vectorizable> struct vectorization_logic
+{
+ enum {
+ PacketSize = internal::packet_traits<Scalar>::size
+ };
+ static void run()
+ {
+
+ typedef Matrix<Scalar,PacketSize,1> Vector1;
+ typedef Matrix<Scalar,Dynamic,1> VectorX;
+ typedef Matrix<Scalar,Dynamic,Dynamic> MatrixXX;
+ typedef Matrix<Scalar,PacketSize,PacketSize> Matrix11;
+ typedef Matrix<Scalar,2*PacketSize,2*PacketSize> Matrix22;
+ typedef Matrix<Scalar,(Matrix11::Flags&RowMajorBit)?16:4*PacketSize,(Matrix11::Flags&RowMajorBit)?4*PacketSize:16> Matrix44;
+ typedef Matrix<Scalar,(Matrix11::Flags&RowMajorBit)?16:4*PacketSize,(Matrix11::Flags&RowMajorBit)?4*PacketSize:16,DontAlign|EIGEN_DEFAULT_MATRIX_STORAGE_ORDER_OPTION> Matrix44u;
+ typedef Matrix<Scalar,4*PacketSize,16,ColMajor> Matrix44c;
+ typedef Matrix<Scalar,4*PacketSize,16,RowMajor> Matrix44r;
+
+ typedef Matrix<Scalar,
+ (PacketSize==8 ? 4 : PacketSize==4 ? 2 : PacketSize==2 ? 1 : /*PacketSize==1 ?*/ 1),
+ (PacketSize==8 ? 2 : PacketSize==4 ? 2 : PacketSize==2 ? 2 : /*PacketSize==1 ?*/ 1)
+ > Matrix1;
+
+ typedef Matrix<Scalar,
+ (PacketSize==8 ? 4 : PacketSize==4 ? 2 : PacketSize==2 ? 1 : /*PacketSize==1 ?*/ 1),
+ (PacketSize==8 ? 2 : PacketSize==4 ? 2 : PacketSize==2 ? 2 : /*PacketSize==1 ?*/ 1),
+ DontAlign|((Matrix1::Flags&RowMajorBit)?RowMajor:ColMajor)> Matrix1u;
+
+ // this type is made such that it can only be vectorized when viewed as a linear 1D vector
+ typedef Matrix<Scalar,
+ (PacketSize==8 ? 4 : PacketSize==4 ? 6 : PacketSize==2 ? ((Matrix11::Flags&RowMajorBit)?2:3) : /*PacketSize==1 ?*/ 1),
+ (PacketSize==8 ? 6 : PacketSize==4 ? 2 : PacketSize==2 ? ((Matrix11::Flags&RowMajorBit)?3:2) : /*PacketSize==1 ?*/ 3)
+ > Matrix3;
+
+ #if !EIGEN_GCC_AND_ARCH_DOESNT_WANT_STACK_ALIGNMENT
+ VERIFY(test_assign(Vector1(),Vector1(),
+ InnerVectorizedTraversal,CompleteUnrolling));
+ VERIFY(test_assign(Vector1(),Vector1()+Vector1(),
+ InnerVectorizedTraversal,CompleteUnrolling));
+ VERIFY(test_assign(Vector1(),Vector1().cwiseProduct(Vector1()),
+ InnerVectorizedTraversal,CompleteUnrolling));
+ VERIFY(test_assign(Vector1(),Vector1().template cast<Scalar>(),
+ InnerVectorizedTraversal,CompleteUnrolling));
+
+
+ VERIFY(test_assign(Vector1(),Vector1(),
+ InnerVectorizedTraversal,CompleteUnrolling));
+ VERIFY(test_assign(Vector1(),Vector1()+Vector1(),
+ InnerVectorizedTraversal,CompleteUnrolling));
+ VERIFY(test_assign(Vector1(),Vector1().cwiseProduct(Vector1()),
+ InnerVectorizedTraversal,CompleteUnrolling));
+
+ VERIFY(test_assign(Matrix44(),Matrix44()+Matrix44(),
+ InnerVectorizedTraversal,InnerUnrolling));
+
+ VERIFY(test_assign(Matrix44u(),Matrix44()+Matrix44(),
+ LinearTraversal,NoUnrolling));
+
+ VERIFY(test_assign(Matrix1u(),Matrix1()+Matrix1(),
+ LinearTraversal,CompleteUnrolling));
+
+ VERIFY(test_assign(Matrix44c().col(1),Matrix44c().col(2)+Matrix44c().col(3),
+ InnerVectorizedTraversal,CompleteUnrolling));
+
+ VERIFY(test_assign(Matrix44r().row(2),Matrix44r().row(1)+Matrix44r().row(1),
+ InnerVectorizedTraversal,CompleteUnrolling));
+
+ if(PacketSize>1)
+ {
+ typedef Matrix<Scalar,3,3,ColMajor> Matrix33c;
+ VERIFY(test_assign(Matrix33c().row(2),Matrix33c().row(1)+Matrix33c().row(1),
+ LinearTraversal,CompleteUnrolling));
+ VERIFY(test_assign(Matrix33c().col(0),Matrix33c().col(1)+Matrix33c().col(1),
+ LinearTraversal,CompleteUnrolling));
+
+ VERIFY(test_assign(Matrix3(),Matrix3().cwiseQuotient(Matrix3()),
+ LinearVectorizedTraversal,CompleteUnrolling));
+
+ VERIFY(test_assign(Matrix<Scalar,17,17>(),Matrix<Scalar,17,17>()+Matrix<Scalar,17,17>(),
+ LinearTraversal,NoUnrolling));
+
+ VERIFY(test_assign(Matrix11(),Matrix<Scalar,17,17>().template block<PacketSize,PacketSize>(2,3)+Matrix<Scalar,17,17>().template block<PacketSize,PacketSize>(10,4),
+ DefaultTraversal,CompleteUnrolling));
+ }
+
+ VERIFY(test_redux(Matrix3(),
+ LinearVectorizedTraversal,CompleteUnrolling));
+
+ VERIFY(test_redux(Matrix44(),
+ LinearVectorizedTraversal,NoUnrolling));
+
+ VERIFY(test_redux(Matrix44().template block<(Matrix1::Flags&RowMajorBit)?4:PacketSize,(Matrix1::Flags&RowMajorBit)?PacketSize:4>(1,2),
+ DefaultTraversal,CompleteUnrolling));
+
+ VERIFY(test_redux(Matrix44c().template block<2*PacketSize,1>(1,2),
+ LinearVectorizedTraversal,CompleteUnrolling));
+
+ VERIFY(test_redux(Matrix44r().template block<1,2*PacketSize>(2,1),
+ LinearVectorizedTraversal,CompleteUnrolling));
+
+ VERIFY((test_assign<
+ Map<Matrix22, Aligned, OuterStride<3*PacketSize> >,
+ Matrix22
+ >(InnerVectorizedTraversal,CompleteUnrolling)));
+
+ VERIFY((test_assign<
+ Map<Matrix22, Aligned, InnerStride<3*PacketSize> >,
+ Matrix22
+ >(DefaultTraversal,CompleteUnrolling)));
+
+ VERIFY((test_assign(Matrix11(), Matrix11()*Matrix11(), InnerVectorizedTraversal, CompleteUnrolling)));
+ #endif
+
+ VERIFY(test_assign(MatrixXX(10,10),MatrixXX(20,20).block(10,10,2,3),
+ SliceVectorizedTraversal,NoUnrolling));
+
+ VERIFY(test_redux(VectorX(10),
+ LinearVectorizedTraversal,NoUnrolling));
+
+
+ }
+};
+
+template<typename Scalar> struct vectorization_logic<Scalar,false>
+{
+ static void run() {}
+};
+
+void test_vectorization_logic()
+{
+
+#ifdef EIGEN_VECTORIZE
+
+ CALL_SUBTEST( vectorization_logic<float>::run() );
+ CALL_SUBTEST( vectorization_logic<double>::run() );
+ CALL_SUBTEST( vectorization_logic<std::complex<float> >::run() );
+ CALL_SUBTEST( vectorization_logic<std::complex<double> >::run() );
+
+ if(internal::packet_traits<float>::Vectorizable)
+ {
+ VERIFY(test_assign(Matrix<float,3,3>(),Matrix<float,3,3>()+Matrix<float,3,3>(),
+ LinearTraversal,CompleteUnrolling));
+
+ VERIFY(test_redux(Matrix<float,5,2>(),
+ DefaultTraversal,CompleteUnrolling));
+ }
+
+ if(internal::packet_traits<double>::Vectorizable)
+ {
+ VERIFY(test_assign(Matrix<double,3,3>(),Matrix<double,3,3>()+Matrix<double,3,3>(),
+ LinearTraversal,CompleteUnrolling));
+
+ VERIFY(test_redux(Matrix<double,7,3>(),
+ DefaultTraversal,CompleteUnrolling));
+ }
+#endif // EIGEN_VECTORIZE
+
+}
diff --git a/test/vectorwiseop.cpp b/test/vectorwiseop.cpp
new file mode 100644
index 000000000..b938e3957
--- /dev/null
+++ b/test/vectorwiseop.cpp
@@ -0,0 +1,172 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra.
+//
+// Copyright (C) 2011 Benoit Jacob <jacob.benoit.1@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/.
+
+#define EIGEN_NO_STATIC_ASSERT
+
+#include "main.h"
+
+template<typename ArrayType> void vectorwiseop_array(const ArrayType& m)
+{
+ typedef typename ArrayType::Index Index;
+ typedef typename ArrayType::Scalar Scalar;
+ typedef typename NumTraits<Scalar>::Real RealScalar;
+ typedef Array<Scalar, ArrayType::RowsAtCompileTime, 1> ColVectorType;
+ typedef Array<Scalar, 1, ArrayType::ColsAtCompileTime> RowVectorType;
+
+ Index rows = m.rows();
+ Index cols = m.cols();
+ Index r = internal::random<Index>(0, rows-1),
+ c = internal::random<Index>(0, cols-1);
+
+ ArrayType m1 = ArrayType::Random(rows, cols),
+ m2(rows, cols),
+ m3(rows, cols);
+
+ ColVectorType colvec = ColVectorType::Random(rows);
+ RowVectorType rowvec = RowVectorType::Random(cols);
+
+ // test addition
+
+ m2 = m1;
+ m2.colwise() += colvec;
+ VERIFY_IS_APPROX(m2, m1.colwise() + colvec);
+ VERIFY_IS_APPROX(m2.col(c), m1.col(c) + colvec);
+
+ VERIFY_RAISES_ASSERT(m2.colwise() += colvec.transpose());
+ VERIFY_RAISES_ASSERT(m1.colwise() + colvec.transpose());
+
+ m2 = m1;
+ m2.rowwise() += rowvec;
+ VERIFY_IS_APPROX(m2, m1.rowwise() + rowvec);
+ VERIFY_IS_APPROX(m2.row(r), m1.row(r) + rowvec);
+
+ VERIFY_RAISES_ASSERT(m2.rowwise() += rowvec.transpose());
+ VERIFY_RAISES_ASSERT(m1.rowwise() + rowvec.transpose());
+
+ // test substraction
+
+ m2 = m1;
+ m2.colwise() -= colvec;
+ VERIFY_IS_APPROX(m2, m1.colwise() - colvec);
+ VERIFY_IS_APPROX(m2.col(c), m1.col(c) - colvec);
+
+ VERIFY_RAISES_ASSERT(m2.colwise() -= colvec.transpose());
+ VERIFY_RAISES_ASSERT(m1.colwise() - colvec.transpose());
+
+ m2 = m1;
+ m2.rowwise() -= rowvec;
+ VERIFY_IS_APPROX(m2, m1.rowwise() - rowvec);
+ VERIFY_IS_APPROX(m2.row(r), m1.row(r) - rowvec);
+
+ VERIFY_RAISES_ASSERT(m2.rowwise() -= rowvec.transpose());
+ VERIFY_RAISES_ASSERT(m1.rowwise() - rowvec.transpose());
+
+ // test multiplication
+
+ m2 = m1;
+ m2.colwise() *= colvec;
+ VERIFY_IS_APPROX(m2, m1.colwise() * colvec);
+ VERIFY_IS_APPROX(m2.col(c), m1.col(c) * colvec);
+
+ VERIFY_RAISES_ASSERT(m2.colwise() *= colvec.transpose());
+ VERIFY_RAISES_ASSERT(m1.colwise() * colvec.transpose());
+
+ m2 = m1;
+ m2.rowwise() *= rowvec;
+ VERIFY_IS_APPROX(m2, m1.rowwise() * rowvec);
+ VERIFY_IS_APPROX(m2.row(r), m1.row(r) * rowvec);
+
+ VERIFY_RAISES_ASSERT(m2.rowwise() *= rowvec.transpose());
+ VERIFY_RAISES_ASSERT(m1.rowwise() * rowvec.transpose());
+
+ // test quotient
+
+ m2 = m1;
+ m2.colwise() /= colvec;
+ VERIFY_IS_APPROX(m2, m1.colwise() / colvec);
+ VERIFY_IS_APPROX(m2.col(c), m1.col(c) / colvec);
+
+ VERIFY_RAISES_ASSERT(m2.colwise() /= colvec.transpose());
+ VERIFY_RAISES_ASSERT(m1.colwise() / colvec.transpose());
+
+ m2 = m1;
+ m2.rowwise() /= rowvec;
+ VERIFY_IS_APPROX(m2, m1.rowwise() / rowvec);
+ VERIFY_IS_APPROX(m2.row(r), m1.row(r) / rowvec);
+
+ VERIFY_RAISES_ASSERT(m2.rowwise() /= rowvec.transpose());
+ VERIFY_RAISES_ASSERT(m1.rowwise() / rowvec.transpose());
+}
+
+template<typename MatrixType> void vectorwiseop_matrix(const MatrixType& m)
+{
+ typedef typename MatrixType::Index Index;
+ typedef typename MatrixType::Scalar Scalar;
+ typedef typename NumTraits<Scalar>::Real RealScalar;
+ typedef Matrix<Scalar, MatrixType::RowsAtCompileTime, 1> ColVectorType;
+ typedef Matrix<Scalar, 1, MatrixType::ColsAtCompileTime> RowVectorType;
+
+ Index rows = m.rows();
+ Index cols = m.cols();
+ Index r = internal::random<Index>(0, rows-1),
+ c = internal::random<Index>(0, cols-1);
+
+ MatrixType m1 = MatrixType::Random(rows, cols),
+ m2(rows, cols),
+ m3(rows, cols);
+
+ ColVectorType colvec = ColVectorType::Random(rows);
+ RowVectorType rowvec = RowVectorType::Random(cols);
+
+ // test addition
+
+ m2 = m1;
+ m2.colwise() += colvec;
+ VERIFY_IS_APPROX(m2, m1.colwise() + colvec);
+ VERIFY_IS_APPROX(m2.col(c), m1.col(c) + colvec);
+
+ VERIFY_RAISES_ASSERT(m2.colwise() += colvec.transpose());
+ VERIFY_RAISES_ASSERT(m1.colwise() + colvec.transpose());
+
+ m2 = m1;
+ m2.rowwise() += rowvec;
+ VERIFY_IS_APPROX(m2, m1.rowwise() + rowvec);
+ VERIFY_IS_APPROX(m2.row(r), m1.row(r) + rowvec);
+
+ VERIFY_RAISES_ASSERT(m2.rowwise() += rowvec.transpose());
+ VERIFY_RAISES_ASSERT(m1.rowwise() + rowvec.transpose());
+
+ // test substraction
+
+ m2 = m1;
+ m2.colwise() -= colvec;
+ VERIFY_IS_APPROX(m2, m1.colwise() - colvec);
+ VERIFY_IS_APPROX(m2.col(c), m1.col(c) - colvec);
+
+ VERIFY_RAISES_ASSERT(m2.colwise() -= colvec.transpose());
+ VERIFY_RAISES_ASSERT(m1.colwise() - colvec.transpose());
+
+ m2 = m1;
+ m2.rowwise() -= rowvec;
+ VERIFY_IS_APPROX(m2, m1.rowwise() - rowvec);
+ VERIFY_IS_APPROX(m2.row(r), m1.row(r) - rowvec);
+
+ VERIFY_RAISES_ASSERT(m2.rowwise() -= rowvec.transpose());
+ VERIFY_RAISES_ASSERT(m1.rowwise() - rowvec.transpose());
+}
+
+void test_vectorwiseop()
+{
+ CALL_SUBTEST_1(vectorwiseop_array(Array22cd()));
+ CALL_SUBTEST_2(vectorwiseop_array(Array<double, 3, 2>()));
+ CALL_SUBTEST_3(vectorwiseop_array(ArrayXXf(3, 4)));
+ CALL_SUBTEST_4(vectorwiseop_matrix(Matrix4cf()));
+ CALL_SUBTEST_5(vectorwiseop_matrix(Matrix<float,4,5>()));
+ CALL_SUBTEST_6(vectorwiseop_matrix(MatrixXd(7,2)));
+}
diff --git a/test/visitor.cpp b/test/visitor.cpp
new file mode 100644
index 000000000..087306258
--- /dev/null
+++ b/test/visitor.cpp
@@ -0,0 +1,118 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra.
+//
+// Copyright (C) 2008 Benoit Jacob <jacob.benoit.1@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 "main.h"
+
+template<typename MatrixType> void matrixVisitor(const MatrixType& p)
+{
+ typedef typename MatrixType::Scalar Scalar;
+ typedef typename MatrixType::Index Index;
+
+ Index rows = p.rows();
+ Index cols = p.cols();
+
+ // construct a random matrix where all coefficients are different
+ MatrixType m;
+ m = MatrixType::Random(rows, cols);
+ for(Index i = 0; i < m.size(); i++)
+ for(Index i2 = 0; i2 < i; i2++)
+ while(m(i) == m(i2)) // yes, ==
+ m(i) = internal::random<Scalar>();
+
+ Scalar minc = Scalar(1000), maxc = Scalar(-1000);
+ Index minrow=0,mincol=0,maxrow=0,maxcol=0;
+ for(Index j = 0; j < cols; j++)
+ for(Index i = 0; i < rows; i++)
+ {
+ if(m(i,j) < minc)
+ {
+ minc = m(i,j);
+ minrow = i;
+ mincol = j;
+ }
+ if(m(i,j) > maxc)
+ {
+ maxc = m(i,j);
+ maxrow = i;
+ maxcol = j;
+ }
+ }
+ Index eigen_minrow, eigen_mincol, eigen_maxrow, eigen_maxcol;
+ Scalar eigen_minc, eigen_maxc;
+ eigen_minc = m.minCoeff(&eigen_minrow,&eigen_mincol);
+ eigen_maxc = m.maxCoeff(&eigen_maxrow,&eigen_maxcol);
+ VERIFY(minrow == eigen_minrow);
+ VERIFY(maxrow == eigen_maxrow);
+ VERIFY(mincol == eigen_mincol);
+ VERIFY(maxcol == eigen_maxcol);
+ VERIFY_IS_APPROX(minc, eigen_minc);
+ VERIFY_IS_APPROX(maxc, eigen_maxc);
+ VERIFY_IS_APPROX(minc, m.minCoeff());
+ VERIFY_IS_APPROX(maxc, m.maxCoeff());
+}
+
+template<typename VectorType> void vectorVisitor(const VectorType& w)
+{
+ typedef typename VectorType::Scalar Scalar;
+ typedef typename VectorType::Index Index;
+
+ Index size = w.size();
+
+ // construct a random vector where all coefficients are different
+ VectorType v;
+ v = VectorType::Random(size);
+ for(Index i = 0; i < size; i++)
+ for(Index i2 = 0; i2 < i; i2++)
+ while(v(i) == v(i2)) // yes, ==
+ v(i) = internal::random<Scalar>();
+
+ Scalar minc = Scalar(1000), maxc = Scalar(-1000);
+ Index minidx=0,maxidx=0;
+ for(Index i = 0; i < size; i++)
+ {
+ if(v(i) < minc)
+ {
+ minc = v(i);
+ minidx = i;
+ }
+ if(v(i) > maxc)
+ {
+ maxc = v(i);
+ maxidx = i;
+ }
+ }
+ Index eigen_minidx, eigen_maxidx;
+ Scalar eigen_minc, eigen_maxc;
+ eigen_minc = v.minCoeff(&eigen_minidx);
+ eigen_maxc = v.maxCoeff(&eigen_maxidx);
+ VERIFY(minidx == eigen_minidx);
+ VERIFY(maxidx == eigen_maxidx);
+ VERIFY_IS_APPROX(minc, eigen_minc);
+ VERIFY_IS_APPROX(maxc, eigen_maxc);
+ VERIFY_IS_APPROX(minc, v.minCoeff());
+ VERIFY_IS_APPROX(maxc, v.maxCoeff());
+}
+
+void test_visitor()
+{
+ for(int i = 0; i < g_repeat; i++) {
+ CALL_SUBTEST_1( matrixVisitor(Matrix<float, 1, 1>()) );
+ CALL_SUBTEST_2( matrixVisitor(Matrix2f()) );
+ CALL_SUBTEST_3( matrixVisitor(Matrix4d()) );
+ CALL_SUBTEST_4( matrixVisitor(MatrixXd(8, 12)) );
+ CALL_SUBTEST_5( matrixVisitor(Matrix<double,Dynamic,Dynamic,RowMajor>(20, 20)) );
+ CALL_SUBTEST_6( matrixVisitor(MatrixXi(8, 12)) );
+ }
+ for(int i = 0; i < g_repeat; i++) {
+ CALL_SUBTEST_7( vectorVisitor(Vector4f()) );
+ CALL_SUBTEST_8( vectorVisitor(VectorXd(10)) );
+ CALL_SUBTEST_9( vectorVisitor(RowVectorXd(10)) );
+ CALL_SUBTEST_10( vectorVisitor(VectorXf(33)) );
+ }
+}
diff --git a/test/zerosized.cpp b/test/zerosized.cpp
new file mode 100644
index 000000000..6905e584e
--- /dev/null
+++ b/test/zerosized.cpp
@@ -0,0 +1,59 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra.
+//
+// Copyright (C) 2011 Benoit Jacob <jacob.benoit.1@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 "main.h"
+
+template<typename MatrixType> void zeroSizedMatrix()
+{
+ MatrixType t1;
+
+ if (MatrixType::SizeAtCompileTime == Dynamic)
+ {
+ if (MatrixType::RowsAtCompileTime == Dynamic)
+ VERIFY(t1.rows() == 0);
+ if (MatrixType::ColsAtCompileTime == Dynamic)
+ VERIFY(t1.cols() == 0);
+
+ if (MatrixType::RowsAtCompileTime == Dynamic && MatrixType::ColsAtCompileTime == Dynamic)
+ {
+ MatrixType t2(0, 0);
+ VERIFY(t2.rows() == 0);
+ VERIFY(t2.cols() == 0);
+ }
+ }
+}
+
+template<typename VectorType> void zeroSizedVector()
+{
+ VectorType t1;
+
+ if (VectorType::SizeAtCompileTime == Dynamic)
+ {
+ VERIFY(t1.size() == 0);
+ VectorType t2(DenseIndex(0)); // DenseIndex disambiguates with 0-the-null-pointer (error with gcc 4.4 and MSVC8)
+ VERIFY(t2.size() == 0);
+ }
+}
+
+void test_zerosized()
+{
+ zeroSizedMatrix<Matrix2d>();
+ zeroSizedMatrix<Matrix3i>();
+ zeroSizedMatrix<Matrix<float, 2, Dynamic> >();
+ zeroSizedMatrix<MatrixXf>();
+ zeroSizedMatrix<Matrix<float, 0, 0> >();
+ zeroSizedMatrix<Matrix<float, Dynamic, 0, 0, 0, 0> >();
+ zeroSizedMatrix<Matrix<float, 0, Dynamic, 0, 0, 0> >();
+ zeroSizedMatrix<Matrix<float, Dynamic, Dynamic, 0, 0, 0> >();
+
+ zeroSizedVector<Vector2d>();
+ zeroSizedVector<Vector3i>();
+ zeroSizedVector<VectorXf>();
+ zeroSizedVector<Matrix<float, 0, 1> >();
+}
diff --git a/unsupported/CMakeLists.txt b/unsupported/CMakeLists.txt
new file mode 100644
index 000000000..4fef40a86
--- /dev/null
+++ b/unsupported/CMakeLists.txt
@@ -0,0 +1,7 @@
+add_subdirectory(Eigen)
+add_subdirectory(doc EXCLUDE_FROM_ALL)
+if(EIGEN_LEAVE_TEST_IN_ALL_TARGET)
+ add_subdirectory(test) # can't do EXCLUDE_FROM_ALL here, breaks CTest
+else()
+ add_subdirectory(test EXCLUDE_FROM_ALL)
+endif()
diff --git a/unsupported/Eigen/AdolcForward b/unsupported/Eigen/AdolcForward
new file mode 100644
index 000000000..b96f9450e
--- /dev/null
+++ b/unsupported/Eigen/AdolcForward
@@ -0,0 +1,156 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra.
+//
+// Copyright (C) 2008-2009 Gael Guennebaud <g.gael@free.fr>
+//
+// This Source Code Form is subject to the terms of the Mozilla
+// Public License v. 2.0. If a copy of the MPL was not distributed
+// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+#ifndef EIGEN_ADLOC_FORWARD
+#define EIGEN_ADLOC_FORWARD
+
+//--------------------------------------------------------------------------------
+//
+// This file provides support for adolc's adouble type in forward mode.
+// ADOL-C is a C++ automatic differentiation library,
+// see https://projects.coin-or.org/ADOL-C for more information.
+//
+// Note that the maximal number of directions is controlled by
+// the preprocessor token NUMBER_DIRECTIONS. The default is 2.
+//
+//--------------------------------------------------------------------------------
+
+#define ADOLC_TAPELESS
+#ifndef NUMBER_DIRECTIONS
+# define NUMBER_DIRECTIONS 2
+#endif
+#include <adolc/adouble.h>
+
+// adolc defines some very stupid macros:
+#if defined(malloc)
+# undef malloc
+#endif
+
+#if defined(calloc)
+# undef calloc
+#endif
+
+#if defined(realloc)
+# undef realloc
+#endif
+
+#include <Eigen/Core>
+
+namespace Eigen {
+
+/** \ingroup Unsupported_modules
+ * \defgroup AdolcForward_Module Adolc forward module
+ * This module provides support for adolc's adouble type in forward mode.
+ * ADOL-C is a C++ automatic differentiation library,
+ * see https://projects.coin-or.org/ADOL-C for more information.
+ * It mainly consists in:
+ * - a struct Eigen::NumTraits<adtl::adouble> specialization
+ * - overloads of internal::* math function for adtl::adouble type.
+ *
+ * Note that the maximal number of directions is controlled by
+ * the preprocessor token NUMBER_DIRECTIONS. The default is 2.
+ *
+ * \code
+ * #include <unsupported/Eigen/AdolcSupport>
+ * \endcode
+ */
+ //@{
+
+} // namespace Eigen
+
+// Eigen's require a few additional functions which must be defined in the same namespace
+// than the custom scalar type own namespace
+namespace adtl {
+
+inline const adouble& conj(const adouble& x) { return x; }
+inline const adouble& real(const adouble& x) { return x; }
+inline adouble imag(const adouble&) { return 0.; }
+inline adouble abs(const adouble& x) { return fabs(x); }
+inline adouble abs2(const adouble& x) { return x*x; }
+
+}
+
+namespace Eigen {
+
+template<> struct NumTraits<adtl::adouble>
+ : NumTraits<double>
+{
+ typedef adtl::adouble Real;
+ typedef adtl::adouble NonInteger;
+ typedef adtl::adouble Nested;
+ enum {
+ IsComplex = 0,
+ IsInteger = 0,
+ IsSigned = 1,
+ RequireInitialization = 1,
+ ReadCost = 1,
+ AddCost = 1,
+ MulCost = 1
+ };
+};
+
+template<typename Functor> class AdolcForwardJacobian : public Functor
+{
+ typedef adtl::adouble ActiveScalar;
+public:
+
+ AdolcForwardJacobian() : Functor() {}
+ AdolcForwardJacobian(const Functor& f) : Functor(f) {}
+
+ // forward constructors
+ template<typename T0>
+ AdolcForwardJacobian(const T0& a0) : Functor(a0) {}
+ template<typename T0, typename T1>
+ AdolcForwardJacobian(const T0& a0, const T1& a1) : Functor(a0, a1) {}
+ template<typename T0, typename T1, typename T2>
+ AdolcForwardJacobian(const T0& a0, const T1& a1, const T1& a2) : Functor(a0, a1, a2) {}
+
+ typedef typename Functor::InputType InputType;
+ typedef typename Functor::ValueType ValueType;
+ typedef typename Functor::JacobianType JacobianType;
+
+ typedef Matrix<ActiveScalar, InputType::SizeAtCompileTime, 1> ActiveInput;
+ typedef Matrix<ActiveScalar, ValueType::SizeAtCompileTime, 1> ActiveValue;
+
+ void operator() (const InputType& x, ValueType* v, JacobianType* _jac) const
+ {
+ eigen_assert(v!=0);
+ if (!_jac)
+ {
+ Functor::operator()(x, v);
+ return;
+ }
+
+ JacobianType& jac = *_jac;
+
+ ActiveInput ax = x.template cast<ActiveScalar>();
+ ActiveValue av(jac.rows());
+
+ for (int j=0; j<jac.cols(); j++)
+ for (int i=0; i<jac.cols(); i++)
+ ax[i].setADValue(j, i==j ? 1 : 0);
+
+ Functor::operator()(ax, &av);
+
+ for (int i=0; i<jac.rows(); i++)
+ {
+ (*v)[i] = av[i].getValue();
+ for (int j=0; j<jac.cols(); j++)
+ jac.coeffRef(i,j) = av[i].getADValue(j);
+ }
+ }
+protected:
+
+};
+
+//@}
+
+}
+
+#endif // EIGEN_ADLOC_FORWARD
diff --git a/unsupported/Eigen/AlignedVector3 b/unsupported/Eigen/AlignedVector3
new file mode 100644
index 000000000..8ad0eb477
--- /dev/null
+++ b/unsupported/Eigen/AlignedVector3
@@ -0,0 +1,189 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra.
+//
+// Copyright (C) 2009 Gael Guennebaud <g.gael@free.fr>
+//
+// This Source Code Form is subject to the terms of the Mozilla
+// Public License v. 2.0. If a copy of the MPL was not distributed
+// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+#ifndef EIGEN_ALIGNED_VECTOR3
+#define EIGEN_ALIGNED_VECTOR3
+
+#include <Eigen/Geometry>
+
+namespace Eigen {
+
+/** \ingroup Unsupported_modules
+ * \defgroup AlignedVector3_Module Aligned vector3 module
+ *
+ * \code
+ * #include <unsupported/Eigen/AlignedVector3>
+ * \endcode
+ */
+ //@{
+
+
+/** \class AlignedVector3
+ *
+ * \brief A vectorization friendly 3D vector
+ *
+ * This class represents a 3D vector internally using a 4D vector
+ * such that vectorization can be seamlessly enabled. Of course,
+ * the same result can be achieved by directly using a 4D vector.
+ * This class makes this process simpler.
+ *
+ */
+// TODO specialize Cwise
+template<typename _Scalar> class AlignedVector3;
+
+namespace internal {
+template<typename _Scalar> struct traits<AlignedVector3<_Scalar> >
+ : traits<Matrix<_Scalar,3,1,0,4,1> >
+{
+};
+}
+
+template<typename _Scalar> class AlignedVector3
+ : public MatrixBase<AlignedVector3<_Scalar> >
+{
+ typedef Matrix<_Scalar,4,1> CoeffType;
+ CoeffType m_coeffs;
+ public:
+
+ typedef MatrixBase<AlignedVector3<_Scalar> > Base;
+ EIGEN_DENSE_PUBLIC_INTERFACE(AlignedVector3)
+ using Base::operator*;
+
+ inline Index rows() const { return 3; }
+ inline Index cols() const { return 1; }
+
+ inline const Scalar& coeff(Index row, Index col) const
+ { return m_coeffs.coeff(row, col); }
+
+ inline Scalar& coeffRef(Index row, Index col)
+ { return m_coeffs.coeffRef(row, col); }
+
+ inline const Scalar& coeff(Index index) const
+ { return m_coeffs.coeff(index); }
+
+ inline Scalar& coeffRef(Index index)
+ { return m_coeffs.coeffRef(index);}
+
+
+ inline AlignedVector3(const Scalar& x, const Scalar& y, const Scalar& z)
+ : m_coeffs(x, y, z, Scalar(0))
+ {}
+
+ inline AlignedVector3(const AlignedVector3& other)
+ : Base(), m_coeffs(other.m_coeffs)
+ {}
+
+ template<typename XprType, int Size=XprType::SizeAtCompileTime>
+ struct generic_assign_selector {};
+
+ template<typename XprType> struct generic_assign_selector<XprType,4>
+ {
+ inline static void run(AlignedVector3& dest, const XprType& src)
+ {
+ dest.m_coeffs = src;
+ }
+ };
+
+ template<typename XprType> struct generic_assign_selector<XprType,3>
+ {
+ inline static void run(AlignedVector3& dest, const XprType& src)
+ {
+ dest.m_coeffs.template head<3>() = src;
+ dest.m_coeffs.w() = Scalar(0);
+ }
+ };
+
+ template<typename Derived>
+ inline explicit AlignedVector3(const MatrixBase<Derived>& other)
+ {
+ generic_assign_selector<Derived>::run(*this,other.derived());
+ }
+
+ inline AlignedVector3& operator=(const AlignedVector3& other)
+ { m_coeffs = other.m_coeffs; return *this; }
+
+
+ inline AlignedVector3 operator+(const AlignedVector3& other) const
+ { return AlignedVector3(m_coeffs + other.m_coeffs); }
+
+ inline AlignedVector3& operator+=(const AlignedVector3& other)
+ { m_coeffs += other.m_coeffs; return *this; }
+
+ inline AlignedVector3 operator-(const AlignedVector3& other) const
+ { return AlignedVector3(m_coeffs - other.m_coeffs); }
+
+ inline AlignedVector3 operator-=(const AlignedVector3& other)
+ { m_coeffs -= other.m_coeffs; return *this; }
+
+ inline AlignedVector3 operator*(const Scalar& s) const
+ { return AlignedVector3(m_coeffs * s); }
+
+ inline friend AlignedVector3 operator*(const Scalar& s,const AlignedVector3& vec)
+ { return AlignedVector3(s * vec.m_coeffs); }
+
+ inline AlignedVector3& operator*=(const Scalar& s)
+ { m_coeffs *= s; return *this; }
+
+ inline AlignedVector3 operator/(const Scalar& s) const
+ { return AlignedVector3(m_coeffs / s); }
+
+ inline AlignedVector3& operator/=(const Scalar& s)
+ { m_coeffs /= s; return *this; }
+
+ inline Scalar dot(const AlignedVector3& other) const
+ {
+ eigen_assert(m_coeffs.w()==Scalar(0));
+ eigen_assert(other.m_coeffs.w()==Scalar(0));
+ return m_coeffs.dot(other.m_coeffs);
+ }
+
+ inline void normalize()
+ {
+ m_coeffs /= norm();
+ }
+
+ inline AlignedVector3 normalized()
+ {
+ return AlignedVector3(m_coeffs / norm());
+ }
+
+ inline Scalar sum() const
+ {
+ eigen_assert(m_coeffs.w()==Scalar(0));
+ return m_coeffs.sum();
+ }
+
+ inline Scalar squaredNorm() const
+ {
+ eigen_assert(m_coeffs.w()==Scalar(0));
+ return m_coeffs.squaredNorm();
+ }
+
+ inline Scalar norm() const
+ {
+ return internal::sqrt(squaredNorm());
+ }
+
+ inline AlignedVector3 cross(const AlignedVector3& other) const
+ {
+ return AlignedVector3(m_coeffs.cross3(other.m_coeffs));
+ }
+
+ template<typename Derived>
+ inline bool isApprox(const MatrixBase<Derived>& other, RealScalar eps=NumTraits<Scalar>::dummy_precision()) const
+ {
+ return m_coeffs.template head<3>().isApprox(other,eps);
+ }
+};
+
+//@}
+
+}
+
+#endif // EIGEN_ALIGNED_VECTOR3
diff --git a/unsupported/Eigen/AutoDiff b/unsupported/Eigen/AutoDiff
new file mode 100644
index 000000000..3c73b424e
--- /dev/null
+++ b/unsupported/Eigen/AutoDiff
@@ -0,0 +1,40 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra.
+//
+// Copyright (C) 2008-2009 Gael Guennebaud <g.gael@free.fr>
+//
+// This Source Code Form is subject to the terms of the Mozilla
+// Public License v. 2.0. If a copy of the MPL was not distributed
+// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+#ifndef EIGEN_AUTODIFF_MODULE
+#define EIGEN_AUTODIFF_MODULE
+
+namespace Eigen {
+
+/** \ingroup Unsupported_modules
+ * \defgroup AutoDiff_Module Auto Diff module
+ *
+ * This module features forward automatic differentation via a simple
+ * templated scalar type wrapper AutoDiffScalar.
+ *
+ * Warning : this should NOT be confused with numerical differentiation, which
+ * is a different method and has its own module in Eigen : \ref NumericalDiff_Module.
+ *
+ * \code
+ * #include <unsupported/Eigen/AutoDiff>
+ * \endcode
+ */
+//@{
+
+}
+
+#include "src/AutoDiff/AutoDiffScalar.h"
+// #include "src/AutoDiff/AutoDiffVector.h"
+#include "src/AutoDiff/AutoDiffJacobian.h"
+
+namespace Eigen {
+//@}
+}
+
+#endif // EIGEN_AUTODIFF_MODULE
diff --git a/unsupported/Eigen/BVH b/unsupported/Eigen/BVH
new file mode 100644
index 000000000..860a7dd89
--- /dev/null
+++ b/unsupported/Eigen/BVH
@@ -0,0 +1,95 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra.
+//
+// Copyright (C) 2009 Ilya Baran <ibaran@mit.edu>
+//
+// This Source Code Form is subject to the terms of the Mozilla
+// Public License v. 2.0. If a copy of the MPL was not distributed
+// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+#ifndef EIGEN_BVH_MODULE_H
+#define EIGEN_BVH_MODULE_H
+
+#include <Eigen/Core>
+#include <Eigen/Geometry>
+#include <Eigen/StdVector>
+#include <algorithm>
+#include <queue>
+
+namespace Eigen {
+
+/** \ingroup Unsupported_modules
+ * \defgroup BVH_Module BVH module
+ * \brief This module provides generic bounding volume hierarchy algorithms
+ * and reference tree implementations.
+ *
+ *
+ * \code
+ * #include <unsupported/Eigen/BVH>
+ * \endcode
+ *
+ * A bounding volume hierarchy (BVH) can accelerate many geometric queries. This module provides a generic implementation
+ * of the two basic algorithms over a BVH: intersection of a query object against all objects in the hierarchy and minimization
+ * of a function over the objects in the hierarchy. It also provides intersection and minimization over a cartesian product of
+ * two BVH's. A BVH accelerates intersection by using the fact that if a query object does not intersect a volume, then it cannot
+ * intersect any object contained in that volume. Similarly, a BVH accelerates minimization because the minimum of a function
+ * over a volume is no greater than the minimum of a function over any object contained in it.
+ *
+ * Some sample queries that can be written in terms of intersection are:
+ * - Determine all points where a ray intersects a triangle mesh
+ * - Given a set of points, determine which are contained in a query sphere
+ * - Given a set of spheres, determine which contain the query point
+ * - Given a set of disks, determine if any is completely contained in a query rectangle (represent each 2D disk as a point \f$(x,y,r)\f$
+ * in 3D and represent the rectangle as a pyramid based on the original rectangle and shrinking in the \f$r\f$ direction)
+ * - Given a set of points, count how many pairs are \f$d\pm\epsilon\f$ apart (done by looking at the cartesian product of the set
+ * of points with itself)
+ *
+ * Some sample queries that can be written in terms of function minimization over a set of objects are:
+ * - Find the intersection between a ray and a triangle mesh closest to the ray origin (function is infinite off the ray)
+ * - Given a polyline and a query point, determine the closest point on the polyline to the query
+ * - Find the diameter of a point cloud (done by looking at the cartesian product and using negative distance as the function)
+ * - Determine how far two meshes are from colliding (this is also a cartesian product query)
+ *
+ * This implementation decouples the basic algorithms both from the type of hierarchy (and the types of the bounding volumes) and
+ * from the particulars of the query. To enable abstraction from the BVH, the BVH is required to implement a generic mechanism
+ * for traversal. To abstract from the query, the query is responsible for keeping track of results.
+ *
+ * To be used in the algorithms, a hierarchy must implement the following traversal mechanism (see KdBVH for a sample implementation): \code
+ typedef Volume //the type of bounding volume
+ typedef Object //the type of object in the hierarchy
+ typedef Index //a reference to a node in the hierarchy--typically an int or a pointer
+ typedef VolumeIterator //an iterator type over node children--returns Index
+ typedef ObjectIterator //an iterator over object (leaf) children--returns const Object &
+ Index getRootIndex() const //returns the index of the hierarchy root
+ const Volume &getVolume(Index index) const //returns the bounding volume of the node at given index
+ void getChildren(Index index, VolumeIterator &outVBegin, VolumeIterator &outVEnd,
+ ObjectIterator &outOBegin, ObjectIterator &outOEnd) const
+ //getChildren takes a node index and makes [outVBegin, outVEnd) range over its node children
+ //and [outOBegin, outOEnd) range over its object children
+ \endcode
+ *
+ * To use the hierarchy, call BVIntersect or BVMinimize, passing it a BVH (or two, for cartesian product) and a minimizer or intersector.
+ * For an intersection query on a single BVH, the intersector encapsulates the query and must provide two functions:
+ * \code
+ bool intersectVolume(const Volume &volume) //returns true if the query intersects the volume
+ bool intersectObject(const Object &object) //returns true if the intersection search should terminate immediately
+ \endcode
+ * The guarantee that BVIntersect provides is that intersectObject will be called on every object whose bounding volume
+ * intersects the query (but possibly on other objects too) unless the search is terminated prematurely. It is the
+ * responsibility of the intersectObject function to keep track of the results in whatever manner is appropriate.
+ * The cartesian product intersection and the BVMinimize queries are similar--see their individual documentation.
+ *
+ * The following is a simple but complete example for how to use the BVH to accelerate the search for a closest red-blue point pair:
+ * \include BVH_Example.cpp
+ * Output: \verbinclude BVH_Example.out
+ */
+}
+
+//@{
+
+#include "src/BVH/BVAlgorithms.h"
+#include "src/BVH/KdBVH.h"
+
+//@}
+
+#endif // EIGEN_BVH_MODULE_H
diff --git a/unsupported/Eigen/CMakeLists.txt b/unsupported/Eigen/CMakeLists.txt
new file mode 100644
index 000000000..e961e72c5
--- /dev/null
+++ b/unsupported/Eigen/CMakeLists.txt
@@ -0,0 +1,11 @@
+set(Eigen_HEADERS AdolcForward BVH IterativeSolvers MatrixFunctions MoreVectorization AutoDiff AlignedVector3 Polynomials
+ FFT NonLinearOptimization SparseExtra IterativeSolvers
+ NumericalDiff Skyline MPRealSupport OpenGLSupport KroneckerProduct Splines
+ )
+
+install(FILES
+ ${Eigen_HEADERS}
+ DESTINATION ${INCLUDE_INSTALL_DIR}/unsupported/Eigen COMPONENT Devel
+ )
+
+add_subdirectory(src)
diff --git a/unsupported/Eigen/FFT b/unsupported/Eigen/FFT
new file mode 100644
index 000000000..d233c6d5f
--- /dev/null
+++ b/unsupported/Eigen/FFT
@@ -0,0 +1,418 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra.
+//
+// Copyright (C) 2009 Mark Borgerding mark a borgerding net
+//
+// This Source Code Form is subject to the terms of the Mozilla
+// Public License v. 2.0. If a copy of the MPL was not distributed
+// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+#ifndef EIGEN_FFT_H
+#define EIGEN_FFT_H
+
+#include <complex>
+#include <vector>
+#include <map>
+#include <Eigen/Core>
+
+
+/** \ingroup Unsupported_modules
+ * \defgroup FFT_Module Fast Fourier Transform module
+ *
+ * \code
+ * #include <unsupported/Eigen/FFT>
+ * \endcode
+ *
+ * This module provides Fast Fourier transformation, with a configurable backend
+ * implementation.
+ *
+ * The default implementation is based on kissfft. It is a small, free, and
+ * reasonably efficient default.
+ *
+ * There are currently two implementation backend:
+ *
+ * - fftw (http://www.fftw.org) : faster, GPL -- incompatible with Eigen in LGPL form, bigger code size.
+ * - MKL (http://en.wikipedia.org/wiki/Math_Kernel_Library) : fastest, commercial -- may be incompatible with Eigen in GPL form.
+ *
+ * \section FFTDesign Design
+ *
+ * The following design decisions were made concerning scaling and
+ * half-spectrum for real FFT.
+ *
+ * The intent is to facilitate generic programming and ease migrating code
+ * from Matlab/octave.
+ * We think the default behavior of Eigen/FFT should favor correctness and
+ * generality over speed. Of course, the caller should be able to "opt-out" from this
+ * behavior and get the speed increase if they want it.
+ *
+ * 1) %Scaling:
+ * Other libraries (FFTW,IMKL,KISSFFT) do not perform scaling, so there
+ * is a constant gain incurred after the forward&inverse transforms , so
+ * IFFT(FFT(x)) = Kx; this is done to avoid a vector-by-value multiply.
+ * The downside is that algorithms that worked correctly in Matlab/octave
+ * don't behave the same way once implemented in C++.
+ *
+ * How Eigen/FFT differs: invertible scaling is performed so IFFT( FFT(x) ) = x.
+ *
+ * 2) Real FFT half-spectrum
+ * Other libraries use only half the frequency spectrum (plus one extra
+ * sample for the Nyquist bin) for a real FFT, the other half is the
+ * conjugate-symmetric of the first half. This saves them a copy and some
+ * memory. The downside is the caller needs to have special logic for the
+ * number of bins in complex vs real.
+ *
+ * How Eigen/FFT differs: The full spectrum is returned from the forward
+ * transform. This facilitates generic template programming by obviating
+ * separate specializations for real vs complex. On the inverse
+ * transform, only half the spectrum is actually used if the output type is real.
+ */
+
+
+#ifdef EIGEN_FFTW_DEFAULT
+// FFTW: faster, GPL -- incompatible with Eigen in LGPL form, bigger code size
+# include <fftw3.h>
+# include "src/FFT/ei_fftw_impl.h"
+ namespace Eigen {
+ //template <typename T> typedef struct internal::fftw_impl default_fft_impl; this does not work
+ template <typename T> struct default_fft_impl : public internal::fftw_impl<T> {};
+ }
+#elif defined EIGEN_MKL_DEFAULT
+// TODO
+// intel Math Kernel Library: fastest, commercial -- may be incompatible with Eigen in GPL form
+# include "src/FFT/ei_imklfft_impl.h"
+ namespace Eigen {
+ template <typename T> struct default_fft_impl : public internal::imklfft_impl {};
+ }
+#else
+// internal::kissfft_impl: small, free, reasonably efficient default, derived from kissfft
+//
+# include "src/FFT/ei_kissfft_impl.h"
+ namespace Eigen {
+ template <typename T>
+ struct default_fft_impl : public internal::kissfft_impl<T> {};
+ }
+#endif
+
+namespace Eigen {
+
+
+//
+template<typename T_SrcMat,typename T_FftIfc> struct fft_fwd_proxy;
+template<typename T_SrcMat,typename T_FftIfc> struct fft_inv_proxy;
+
+namespace internal {
+template<typename T_SrcMat,typename T_FftIfc>
+struct traits< fft_fwd_proxy<T_SrcMat,T_FftIfc> >
+{
+ typedef typename T_SrcMat::PlainObject ReturnType;
+};
+template<typename T_SrcMat,typename T_FftIfc>
+struct traits< fft_inv_proxy<T_SrcMat,T_FftIfc> >
+{
+ typedef typename T_SrcMat::PlainObject ReturnType;
+};
+}
+
+template<typename T_SrcMat,typename T_FftIfc>
+struct fft_fwd_proxy
+ : public ReturnByValue<fft_fwd_proxy<T_SrcMat,T_FftIfc> >
+{
+ typedef DenseIndex Index;
+
+ fft_fwd_proxy(const T_SrcMat& src,T_FftIfc & fft, Index nfft) : m_src(src),m_ifc(fft), m_nfft(nfft) {}
+
+ template<typename T_DestMat> void evalTo(T_DestMat& dst) const;
+
+ Index rows() const { return m_src.rows(); }
+ Index cols() const { return m_src.cols(); }
+protected:
+ const T_SrcMat & m_src;
+ T_FftIfc & m_ifc;
+ Index m_nfft;
+private:
+ fft_fwd_proxy& operator=(const fft_fwd_proxy&);
+};
+
+template<typename T_SrcMat,typename T_FftIfc>
+struct fft_inv_proxy
+ : public ReturnByValue<fft_inv_proxy<T_SrcMat,T_FftIfc> >
+{
+ typedef DenseIndex Index;
+
+ fft_inv_proxy(const T_SrcMat& src,T_FftIfc & fft, Index nfft) : m_src(src),m_ifc(fft), m_nfft(nfft) {}
+
+ template<typename T_DestMat> void evalTo(T_DestMat& dst) const;
+
+ Index rows() const { return m_src.rows(); }
+ Index cols() const { return m_src.cols(); }
+protected:
+ const T_SrcMat & m_src;
+ T_FftIfc & m_ifc;
+ Index m_nfft;
+private:
+ fft_inv_proxy& operator=(const fft_inv_proxy&);
+};
+
+
+template <typename T_Scalar,
+ typename T_Impl=default_fft_impl<T_Scalar> >
+class FFT
+{
+ public:
+ typedef T_Impl impl_type;
+ typedef DenseIndex Index;
+ typedef typename impl_type::Scalar Scalar;
+ typedef typename impl_type::Complex Complex;
+
+ enum Flag {
+ Default=0, // goof proof
+ Unscaled=1,
+ HalfSpectrum=2,
+ // SomeOtherSpeedOptimization=4
+ Speedy=32767
+ };
+
+ FFT( const impl_type & impl=impl_type() , Flag flags=Default ) :m_impl(impl),m_flag(flags) { }
+
+ inline
+ bool HasFlag(Flag f) const { return (m_flag & (int)f) == f;}
+
+ inline
+ void SetFlag(Flag f) { m_flag |= (int)f;}
+
+ inline
+ void ClearFlag(Flag f) { m_flag &= (~(int)f);}
+
+ inline
+ void fwd( Complex * dst, const Scalar * src, Index nfft)
+ {
+ m_impl.fwd(dst,src,static_cast<int>(nfft));
+ if ( HasFlag(HalfSpectrum) == false)
+ ReflectSpectrum(dst,nfft);
+ }
+
+ inline
+ void fwd( Complex * dst, const Complex * src, Index nfft)
+ {
+ m_impl.fwd(dst,src,static_cast<int>(nfft));
+ }
+
+ /*
+ inline
+ void fwd2(Complex * dst, const Complex * src, int n0,int n1)
+ {
+ m_impl.fwd2(dst,src,n0,n1);
+ }
+ */
+
+ template <typename _Input>
+ inline
+ void fwd( std::vector<Complex> & dst, const std::vector<_Input> & src)
+ {
+ if ( NumTraits<_Input>::IsComplex == 0 && HasFlag(HalfSpectrum) )
+ dst.resize( (src.size()>>1)+1); // half the bins + Nyquist bin
+ else
+ dst.resize(src.size());
+ fwd(&dst[0],&src[0],src.size());
+ }
+
+ template<typename InputDerived, typename ComplexDerived>
+ inline
+ void fwd( MatrixBase<ComplexDerived> & dst, const MatrixBase<InputDerived> & src, Index nfft=-1)
+ {
+ typedef typename ComplexDerived::Scalar dst_type;
+ typedef typename InputDerived::Scalar src_type;
+ EIGEN_STATIC_ASSERT_VECTOR_ONLY(InputDerived)
+ EIGEN_STATIC_ASSERT_VECTOR_ONLY(ComplexDerived)
+ EIGEN_STATIC_ASSERT_SAME_VECTOR_SIZE(ComplexDerived,InputDerived) // size at compile-time
+ EIGEN_STATIC_ASSERT((internal::is_same<dst_type, Complex>::value),
+ YOU_MIXED_DIFFERENT_NUMERIC_TYPES__YOU_NEED_TO_USE_THE_CAST_METHOD_OF_MATRIXBASE_TO_CAST_NUMERIC_TYPES_EXPLICITLY)
+ EIGEN_STATIC_ASSERT(int(InputDerived::Flags)&int(ComplexDerived::Flags)&DirectAccessBit,
+ THIS_METHOD_IS_ONLY_FOR_EXPRESSIONS_WITH_DIRECT_MEMORY_ACCESS_SUCH_AS_MAP_OR_PLAIN_MATRICES)
+
+ if (nfft<1)
+ nfft = src.size();
+
+ if ( NumTraits< src_type >::IsComplex == 0 && HasFlag(HalfSpectrum) )
+ dst.derived().resize( (nfft>>1)+1);
+ else
+ dst.derived().resize(nfft);
+
+ if ( src.innerStride() != 1 || src.size() < nfft ) {
+ Matrix<src_type,1,Dynamic> tmp;
+ if (src.size()<nfft) {
+ tmp.setZero(nfft);
+ tmp.block(0,0,src.size(),1 ) = src;
+ }else{
+ tmp = src;
+ }
+ fwd( &dst[0],&tmp[0],nfft );
+ }else{
+ fwd( &dst[0],&src[0],nfft );
+ }
+ }
+
+ template<typename InputDerived>
+ inline
+ fft_fwd_proxy< MatrixBase<InputDerived>, FFT<T_Scalar,T_Impl> >
+ fwd( const MatrixBase<InputDerived> & src, Index nfft=-1)
+ {
+ return fft_fwd_proxy< MatrixBase<InputDerived> ,FFT<T_Scalar,T_Impl> >( src, *this,nfft );
+ }
+
+ template<typename InputDerived>
+ inline
+ fft_inv_proxy< MatrixBase<InputDerived>, FFT<T_Scalar,T_Impl> >
+ inv( const MatrixBase<InputDerived> & src, Index nfft=-1)
+ {
+ return fft_inv_proxy< MatrixBase<InputDerived> ,FFT<T_Scalar,T_Impl> >( src, *this,nfft );
+ }
+
+ inline
+ void inv( Complex * dst, const Complex * src, Index nfft)
+ {
+ m_impl.inv( dst,src,static_cast<int>(nfft) );
+ if ( HasFlag( Unscaled ) == false)
+ scale(dst,Scalar(1./nfft),nfft); // scale the time series
+ }
+
+ inline
+ void inv( Scalar * dst, const Complex * src, Index nfft)
+ {
+ m_impl.inv( dst,src,static_cast<int>(nfft) );
+ if ( HasFlag( Unscaled ) == false)
+ scale(dst,Scalar(1./nfft),nfft); // scale the time series
+ }
+
+ template<typename OutputDerived, typename ComplexDerived>
+ inline
+ void inv( MatrixBase<OutputDerived> & dst, const MatrixBase<ComplexDerived> & src, Index nfft=-1)
+ {
+ typedef typename ComplexDerived::Scalar src_type;
+ typedef typename OutputDerived::Scalar dst_type;
+ const bool realfft= (NumTraits<dst_type>::IsComplex == 0);
+ EIGEN_STATIC_ASSERT_VECTOR_ONLY(OutputDerived)
+ EIGEN_STATIC_ASSERT_VECTOR_ONLY(ComplexDerived)
+ EIGEN_STATIC_ASSERT_SAME_VECTOR_SIZE(ComplexDerived,OutputDerived) // size at compile-time
+ EIGEN_STATIC_ASSERT((internal::is_same<src_type, Complex>::value),
+ YOU_MIXED_DIFFERENT_NUMERIC_TYPES__YOU_NEED_TO_USE_THE_CAST_METHOD_OF_MATRIXBASE_TO_CAST_NUMERIC_TYPES_EXPLICITLY)
+ EIGEN_STATIC_ASSERT(int(OutputDerived::Flags)&int(ComplexDerived::Flags)&DirectAccessBit,
+ THIS_METHOD_IS_ONLY_FOR_EXPRESSIONS_WITH_DIRECT_MEMORY_ACCESS_SUCH_AS_MAP_OR_PLAIN_MATRICES)
+
+ if (nfft<1) { //automatic FFT size determination
+ if ( realfft && HasFlag(HalfSpectrum) )
+ nfft = 2*(src.size()-1); //assume even fft size
+ else
+ nfft = src.size();
+ }
+ dst.derived().resize( nfft );
+
+ // check for nfft that does not fit the input data size
+ Index resize_input= ( realfft && HasFlag(HalfSpectrum) )
+ ? ( (nfft/2+1) - src.size() )
+ : ( nfft - src.size() );
+
+ if ( src.innerStride() != 1 || resize_input ) {
+ // if the vector is strided, then we need to copy it to a packed temporary
+ Matrix<src_type,1,Dynamic> tmp;
+ if ( resize_input ) {
+ size_t ncopy = (std::min)(src.size(),src.size() + resize_input);
+ tmp.setZero(src.size() + resize_input);
+ if ( realfft && HasFlag(HalfSpectrum) ) {
+ // pad at the Nyquist bin
+ tmp.head(ncopy) = src.head(ncopy);
+ tmp(ncopy-1) = real(tmp(ncopy-1)); // enforce real-only Nyquist bin
+ }else{
+ size_t nhead,ntail;
+ nhead = 1+ncopy/2-1; // range [0:pi)
+ ntail = ncopy/2-1; // range (-pi:0)
+ tmp.head(nhead) = src.head(nhead);
+ tmp.tail(ntail) = src.tail(ntail);
+ if (resize_input<0) { //shrinking -- create the Nyquist bin as the average of the two bins that fold into it
+ tmp(nhead) = ( src(nfft/2) + src( src.size() - nfft/2 ) )*src_type(.5);
+ }else{ // expanding -- split the old Nyquist bin into two halves
+ tmp(nhead) = src(nhead) * src_type(.5);
+ tmp(tmp.size()-nhead) = tmp(nhead);
+ }
+ }
+ }else{
+ tmp = src;
+ }
+ inv( &dst[0],&tmp[0], nfft);
+ }else{
+ inv( &dst[0],&src[0], nfft);
+ }
+ }
+
+ template <typename _Output>
+ inline
+ void inv( std::vector<_Output> & dst, const std::vector<Complex> & src,Index nfft=-1)
+ {
+ if (nfft<1)
+ nfft = ( NumTraits<_Output>::IsComplex == 0 && HasFlag(HalfSpectrum) ) ? 2*(src.size()-1) : src.size();
+ dst.resize( nfft );
+ inv( &dst[0],&src[0],nfft);
+ }
+
+
+ /*
+ // TODO: multi-dimensional FFTs
+ inline
+ void inv2(Complex * dst, const Complex * src, int n0,int n1)
+ {
+ m_impl.inv2(dst,src,n0,n1);
+ if ( HasFlag( Unscaled ) == false)
+ scale(dst,1./(n0*n1),n0*n1);
+ }
+ */
+
+ inline
+ impl_type & impl() {return m_impl;}
+ private:
+
+ template <typename T_Data>
+ inline
+ void scale(T_Data * x,Scalar s,Index nx)
+ {
+#if 1
+ for (int k=0;k<nx;++k)
+ *x++ *= s;
+#else
+ if ( ((ptrdiff_t)x) & 15 )
+ Matrix<T_Data, Dynamic, 1>::Map(x,nx) *= s;
+ else
+ Matrix<T_Data, Dynamic, 1>::MapAligned(x,nx) *= s;
+ //Matrix<T_Data, Dynamic, Dynamic>::Map(x,nx) * s;
+#endif
+ }
+
+ inline
+ void ReflectSpectrum(Complex * freq, Index nfft)
+ {
+ // create the implicit right-half spectrum (conjugate-mirror of the left-half)
+ Index nhbins=(nfft>>1)+1;
+ for (Index k=nhbins;k < nfft; ++k )
+ freq[k] = conj(freq[nfft-k]);
+ }
+
+ impl_type m_impl;
+ int m_flag;
+};
+
+template<typename T_SrcMat,typename T_FftIfc>
+template<typename T_DestMat> inline
+void fft_fwd_proxy<T_SrcMat,T_FftIfc>::evalTo(T_DestMat& dst) const
+{
+ m_ifc.fwd( dst, m_src, m_nfft);
+}
+
+template<typename T_SrcMat,typename T_FftIfc>
+template<typename T_DestMat> inline
+void fft_inv_proxy<T_SrcMat,T_FftIfc>::evalTo(T_DestMat& dst) const
+{
+ m_ifc.inv( dst, m_src, m_nfft);
+}
+
+}
+#endif
+/* vim: set filetype=cpp et sw=2 ts=2 ai: */
diff --git a/unsupported/Eigen/IterativeSolvers b/unsupported/Eigen/IterativeSolvers
new file mode 100644
index 000000000..6c6946d91
--- /dev/null
+++ b/unsupported/Eigen/IterativeSolvers
@@ -0,0 +1,40 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra.
+//
+// Copyright (C) 2008-2009 Gael Guennebaud <g.gael@free.fr>
+//
+// This Source Code Form is subject to the terms of the Mozilla
+// Public License v. 2.0. If 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_SOLVERS_MODULE_H
+#define EIGEN_ITERATIVE_SOLVERS_MODULE_H
+
+#include <Eigen/Sparse>
+
+/** \ingroup Unsupported_modules
+ * \defgroup IterativeSolvers_Module Iterative solvers module
+ * This module aims to provide various iterative linear and non linear solver algorithms.
+ * It currently provides:
+ * - a constrained conjugate gradient
+ * - a Householder GMRES implementation
+ * \code
+ * #include <unsupported/Eigen/IterativeSolvers>
+ * \endcode
+ */
+//@{
+
+#include "../../Eigen/src/misc/Solve.h"
+#include "../../Eigen/src/misc/SparseSolve.h"
+
+#include "src/IterativeSolvers/IterationController.h"
+#include "src/IterativeSolvers/ConstrainedConjGrad.h"
+#include "src/IterativeSolvers/IncompleteLU.h"
+#include "../../Eigen/Jacobi"
+#include "../../Eigen/Householder"
+#include "src/IterativeSolvers/GMRES.h"
+//#include "src/IterativeSolvers/SSORPreconditioner.h"
+
+//@}
+
+#endif // EIGEN_ITERATIVE_SOLVERS_MODULE_H
diff --git a/unsupported/Eigen/KroneckerProduct b/unsupported/Eigen/KroneckerProduct
new file mode 100644
index 000000000..796e386ad
--- /dev/null
+++ b/unsupported/Eigen/KroneckerProduct
@@ -0,0 +1,26 @@
+#ifndef EIGEN_KRONECKER_PRODUCT_MODULE_H
+#define EIGEN_KRONECKER_PRODUCT_MODULE_H
+
+#include "../../Eigen/Core"
+
+#include "../../Eigen/src/Core/util/DisableStupidWarnings.h"
+
+namespace Eigen {
+
+/** \ingroup Unsupported_modules
+ * \defgroup KroneckerProduct_Module KroneckerProduct module
+ *
+ * This module contains an experimental Kronecker product implementation.
+ *
+ * \code
+ * #include <Eigen/KroneckerProduct>
+ * \endcode
+ */
+
+} // namespace Eigen
+
+#include "src/KroneckerProduct/KroneckerTensorProduct.h"
+
+#include "../../Eigen/src/Core/util/ReenableStupidWarnings.h"
+
+#endif // EIGEN_KRONECKER_PRODUCT_MODULE_H
diff --git a/unsupported/Eigen/MPRealSupport b/unsupported/Eigen/MPRealSupport
new file mode 100644
index 000000000..3895623fe
--- /dev/null
+++ b/unsupported/Eigen/MPRealSupport
@@ -0,0 +1,148 @@
+// This file is part of a joint effort between Eigen, a lightweight C++ template library
+// for linear algebra, and MPFR C++, a C++ interface to MPFR library (http://www.holoborodko.com/pavel/)
+//
+// Copyright (C) 2010 Pavel Holoborodko <pavel@holoborodko.com>
+// Copyright (C) 2010 Konstantin Holoborodko <konstantin@holoborodko.com>
+// Copyright (C) 2010 Gael Guennebaud <gael.guennebaud@inria.fr>
+//
+// This Source Code Form is subject to the terms of the Mozilla
+// Public License v. 2.0. If a copy of the MPL was not distributed
+// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
+//
+// Contributors:
+// Brian Gladman, Helmut Jarausch, Fokko Beekhof, Ulrich Mutze, Heinz van Saanen, Pere Constans
+
+#ifndef EIGEN_MPREALSUPPORT_MODULE_H
+#define EIGEN_MPREALSUPPORT_MODULE_H
+
+#include <ctime>
+#include <mpreal.h>
+#include <Eigen/Core>
+
+namespace Eigen {
+
+ /** \ingroup Unsupported_modules
+ * \defgroup MPRealSupport_Module MPFRC++ Support module
+ *
+ * \code
+ * #include <Eigen/MPRealSupport>
+ * \endcode
+ *
+ * This module provides support for multi precision floating point numbers
+ * via the <a href="http://www.holoborodko.com/pavel/mpfr">MPFR C++</a>
+ * library which itself is built upon <a href="http://www.mpfr.org/">MPFR</a>/<a href="http://gmplib.org/">GMP</a>.
+ *
+ * You can find a copy of MPFR C++ that is known to be compatible in the unsupported/test/mpreal folder.
+ *
+ * Here is an example:
+ *
+\code
+#include <iostream>
+#include <Eigen/MPRealSupport>
+#include <Eigen/LU>
+using namespace mpfr;
+using namespace Eigen;
+int main()
+{
+ // set precision to 256 bits (double has only 53 bits)
+ mpreal::set_default_prec(256);
+ // Declare matrix and vector types with multi-precision scalar type
+ typedef Matrix<mpreal,Dynamic,Dynamic> MatrixXmp;
+ typedef Matrix<mpreal,Dynamic,1> VectorXmp;
+
+ MatrixXmp A = MatrixXmp::Random(100,100);
+ VectorXmp b = VectorXmp::Random(100);
+
+ // Solve Ax=b using LU
+ VectorXmp x = A.lu().solve(b);
+ std::cout << "relative error: " << (A*x - b).norm() / b.norm() << std::endl;
+ return 0;
+}
+\endcode
+ *
+ */
+
+ template<> struct NumTraits<mpfr::mpreal>
+ : GenericNumTraits<mpfr::mpreal>
+ {
+ enum {
+ IsInteger = 0,
+ IsSigned = 1,
+ IsComplex = 0,
+ RequireInitialization = 1,
+ ReadCost = 10,
+ AddCost = 10,
+ MulCost = 40
+ };
+
+ typedef mpfr::mpreal Real;
+ typedef mpfr::mpreal NonInteger;
+
+ inline static mpfr::mpreal highest() { return mpfr::mpreal_max(mpfr::mpreal::get_default_prec()); }
+ inline static mpfr::mpreal lowest() { return -mpfr::mpreal_max(mpfr::mpreal::get_default_prec()); }
+
+ inline static Real epsilon()
+ {
+ return mpfr::machine_epsilon(mpfr::mpreal::get_default_prec());
+ }
+ inline static Real dummy_precision()
+ {
+ unsigned int weak_prec = ((mpfr::mpreal::get_default_prec()-1)*90)/100;
+ return mpfr::machine_epsilon(weak_prec);
+ }
+ };
+
+namespace internal {
+
+ template<> mpfr::mpreal random<mpfr::mpreal>()
+ {
+#if (MPFR_VERSION >= MPFR_VERSION_NUM(3,0,0))
+ static gmp_randstate_t state;
+ static bool isFirstTime = true;
+
+ if(isFirstTime)
+ {
+ gmp_randinit_default(state);
+ gmp_randseed_ui(state,(unsigned)time(NULL));
+ isFirstTime = false;
+ }
+
+ return mpfr::urandom(state)*2-1;
+#else
+ return mpfr::mpreal(random<double>());
+#endif
+ }
+
+ template<> mpfr::mpreal random<mpfr::mpreal>(const mpfr::mpreal& a, const mpfr::mpreal& b)
+ {
+ return a + (b-a) * random<mpfr::mpreal>();
+ }
+
+ bool isMuchSmallerThan(const mpfr::mpreal& a, const mpfr::mpreal& b, const mpfr::mpreal& prec)
+ {
+ return mpfr::abs(a) <= mpfr::abs(b) * prec;
+ }
+
+ inline bool isApprox(const mpfr::mpreal& a, const mpfr::mpreal& b, const mpfr::mpreal& prec)
+ {
+ return mpfr::abs(a - b) <= (mpfr::min)(mpfr::abs(a), mpfr::abs(b)) * prec;
+ }
+
+ inline bool isApproxOrLessThan(const mpfr::mpreal& a, const mpfr::mpreal& b, const mpfr::mpreal& prec)
+ {
+ return a <= b || isApprox(a, b, prec);
+ }
+
+ template<> inline long double cast<mpfr::mpreal,long double>(const mpfr::mpreal& x)
+ { return x.toLDouble(); }
+ template<> inline double cast<mpfr::mpreal,double>(const mpfr::mpreal& x)
+ { return x.toDouble(); }
+ template<> inline long cast<mpfr::mpreal,long>(const mpfr::mpreal& x)
+ { return x.toLong(); }
+ template<> inline int cast<mpfr::mpreal,int>(const mpfr::mpreal& x)
+ { return int(x.toLong()); }
+
+} // end namespace internal
+}
+
+#endif // EIGEN_MPREALSUPPORT_MODULE_H
diff --git a/unsupported/Eigen/MatrixFunctions b/unsupported/Eigen/MatrixFunctions
new file mode 100644
index 000000000..56ab71cd3
--- /dev/null
+++ b/unsupported/Eigen/MatrixFunctions
@@ -0,0 +1,380 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra.
+//
+// Copyright (C) 2009 Jitse Niesen <jitse@maths.leeds.ac.uk>
+//
+// This Source Code Form is subject to the terms of the Mozilla
+// Public License v. 2.0. If a copy of the MPL was not distributed
+// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+#ifndef EIGEN_MATRIX_FUNCTIONS
+#define EIGEN_MATRIX_FUNCTIONS
+
+#include <cfloat>
+#include <list>
+#include <functional>
+#include <iterator>
+
+#include <Eigen/Core>
+#include <Eigen/LU>
+#include <Eigen/Eigenvalues>
+
+/** \ingroup Unsupported_modules
+ * \defgroup MatrixFunctions_Module Matrix functions module
+ * \brief This module aims to provide various methods for the computation of
+ * matrix functions.
+ *
+ * To use this module, add
+ * \code
+ * #include <unsupported/Eigen/MatrixFunctions>
+ * \endcode
+ * at the start of your source file.
+ *
+ * This module defines the following MatrixBase methods.
+ * - \ref matrixbase_cos "MatrixBase::cos()", for computing the matrix cosine
+ * - \ref matrixbase_cosh "MatrixBase::cosh()", for computing the matrix hyperbolic cosine
+ * - \ref matrixbase_exp "MatrixBase::exp()", for computing the matrix exponential
+ * - \ref matrixbase_log "MatrixBase::log()", for computing the matrix logarithm
+ * - \ref matrixbase_matrixfunction "MatrixBase::matrixFunction()", for computing general matrix functions
+ * - \ref matrixbase_sin "MatrixBase::sin()", for computing the matrix sine
+ * - \ref matrixbase_sinh "MatrixBase::sinh()", for computing the matrix hyperbolic sine
+ * - \ref matrixbase_sqrt "MatrixBase::sqrt()", for computing the matrix square root
+ *
+ * These methods are the main entry points to this module.
+ *
+ * %Matrix functions are defined as follows. Suppose that \f$ f \f$
+ * is an entire function (that is, a function on the complex plane
+ * that is everywhere complex differentiable). Then its Taylor
+ * series
+ * \f[ f(0) + f'(0) x + \frac{f''(0)}{2} x^2 + \frac{f'''(0)}{3!} x^3 + \cdots \f]
+ * converges to \f$ f(x) \f$. In this case, we can define the matrix
+ * function by the same series:
+ * \f[ f(M) = f(0) + f'(0) M + \frac{f''(0)}{2} M^2 + \frac{f'''(0)}{3!} M^3 + \cdots \f]
+ *
+ */
+
+#include "src/MatrixFunctions/MatrixExponential.h"
+#include "src/MatrixFunctions/MatrixFunction.h"
+#include "src/MatrixFunctions/MatrixSquareRoot.h"
+#include "src/MatrixFunctions/MatrixLogarithm.h"
+
+
+
+/**
+\page matrixbaseextra MatrixBase methods defined in the MatrixFunctions module
+\ingroup MatrixFunctions_Module
+
+The remainder of the page documents the following MatrixBase methods
+which are defined in the MatrixFunctions module.
+
+
+
+\section matrixbase_cos MatrixBase::cos()
+
+Compute the matrix cosine.
+
+\code
+const MatrixFunctionReturnValue<Derived> MatrixBase<Derived>::cos() const
+\endcode
+
+\param[in] M a square matrix.
+\returns expression representing \f$ \cos(M) \f$.
+
+This function calls \ref matrixbase_matrixfunction "matrixFunction()" with StdStemFunctions::cos().
+
+\sa \ref matrixbase_sin "sin()" for an example.
+
+
+
+\section matrixbase_cosh MatrixBase::cosh()
+
+Compute the matrix hyberbolic cosine.
+
+\code
+const MatrixFunctionReturnValue<Derived> MatrixBase<Derived>::cosh() const
+\endcode
+
+\param[in] M a square matrix.
+\returns expression representing \f$ \cosh(M) \f$
+
+This function calls \ref matrixbase_matrixfunction "matrixFunction()" with StdStemFunctions::cosh().
+
+\sa \ref matrixbase_sinh "sinh()" for an example.
+
+
+
+\section matrixbase_exp MatrixBase::exp()
+
+Compute the matrix exponential.
+
+\code
+const MatrixExponentialReturnValue<Derived> MatrixBase<Derived>::exp() const
+\endcode
+
+\param[in] M matrix whose exponential is to be computed.
+\returns expression representing the matrix exponential of \p M.
+
+The matrix exponential of \f$ M \f$ is defined by
+\f[ \exp(M) = \sum_{k=0}^\infty \frac{M^k}{k!}. \f]
+The matrix exponential can be used to solve linear ordinary
+differential equations: the solution of \f$ y' = My \f$ with the
+initial condition \f$ y(0) = y_0 \f$ is given by
+\f$ y(t) = \exp(M) y_0 \f$.
+
+The cost of the computation is approximately \f$ 20 n^3 \f$ for
+matrices of size \f$ n \f$. The number 20 depends weakly on the
+norm of the matrix.
+
+The matrix exponential is computed using the scaling-and-squaring
+method combined with Pad&eacute; approximation. The matrix is first
+rescaled, then the exponential of the reduced matrix is computed
+approximant, and then the rescaling is undone by repeated
+squaring. The degree of the Pad&eacute; approximant is chosen such
+that the approximation error is less than the round-off
+error. However, errors may accumulate during the squaring phase.
+
+Details of the algorithm can be found in: Nicholas J. Higham, "The
+scaling and squaring method for the matrix exponential revisited,"
+<em>SIAM J. %Matrix Anal. Applic.</em>, <b>26</b>:1179&ndash;1193,
+2005.
+
+Example: The following program checks that
+\f[ \exp \left[ \begin{array}{ccc}
+ 0 & \frac14\pi & 0 \\
+ -\frac14\pi & 0 & 0 \\
+ 0 & 0 & 0
+ \end{array} \right] = \left[ \begin{array}{ccc}
+ \frac12\sqrt2 & -\frac12\sqrt2 & 0 \\
+ \frac12\sqrt2 & \frac12\sqrt2 & 0 \\
+ 0 & 0 & 1
+ \end{array} \right]. \f]
+This corresponds to a rotation of \f$ \frac14\pi \f$ radians around
+the z-axis.
+
+\include MatrixExponential.cpp
+Output: \verbinclude MatrixExponential.out
+
+\note \p M has to be a matrix of \c float, \c double, \c long double
+\c complex<float>, \c complex<double>, or \c complex<long double> .
+
+
+\section matrixbase_log MatrixBase::log()
+
+Compute the matrix logarithm.
+
+\code
+const MatrixLogarithmReturnValue<Derived> MatrixBase<Derived>::log() const
+\endcode
+
+\param[in] M invertible matrix whose logarithm is to be computed.
+\returns expression representing the matrix logarithm root of \p M.
+
+The matrix logarithm of \f$ M \f$ is a matrix \f$ X \f$ such that
+\f$ \exp(X) = M \f$ where exp denotes the matrix exponential. As for
+the scalar logarithm, the equation \f$ \exp(X) = M \f$ may have
+multiple solutions; this function returns a matrix whose eigenvalues
+have imaginary part in the interval \f$ (-\pi,\pi] \f$.
+
+In the real case, the matrix \f$ M \f$ should be invertible and
+it should have no eigenvalues which are real and negative (pairs of
+complex conjugate eigenvalues are allowed). In the complex case, it
+only needs to be invertible.
+
+This function computes the matrix logarithm using the Schur-Parlett
+algorithm as implemented by MatrixBase::matrixFunction(). The
+logarithm of an atomic block is computed by MatrixLogarithmAtomic,
+which uses direct computation for 1-by-1 and 2-by-2 blocks and an
+inverse scaling-and-squaring algorithm for bigger blocks, with the
+square roots computed by MatrixBase::sqrt().
+
+Details of the algorithm can be found in Section 11.6.2 of:
+Nicholas J. Higham,
+<em>Functions of Matrices: Theory and Computation</em>,
+SIAM 2008. ISBN 978-0-898716-46-7.
+
+Example: The following program checks that
+\f[ \log \left[ \begin{array}{ccc}
+ \frac12\sqrt2 & -\frac12\sqrt2 & 0 \\
+ \frac12\sqrt2 & \frac12\sqrt2 & 0 \\
+ 0 & 0 & 1
+ \end{array} \right] = \left[ \begin{array}{ccc}
+ 0 & \frac14\pi & 0 \\
+ -\frac14\pi & 0 & 0 \\
+ 0 & 0 & 0
+ \end{array} \right]. \f]
+This corresponds to a rotation of \f$ \frac14\pi \f$ radians around
+the z-axis. This is the inverse of the example used in the
+documentation of \ref matrixbase_exp "exp()".
+
+\include MatrixLogarithm.cpp
+Output: \verbinclude MatrixLogarithm.out
+
+\note \p M has to be a matrix of \c float, \c double, \c long double
+\c complex<float>, \c complex<double>, or \c complex<long double> .
+
+\sa MatrixBase::exp(), MatrixBase::matrixFunction(),
+ class MatrixLogarithmAtomic, MatrixBase::sqrt().
+
+
+\section matrixbase_matrixfunction MatrixBase::matrixFunction()
+
+Compute a matrix function.
+
+\code
+const MatrixFunctionReturnValue<Derived> MatrixBase<Derived>::matrixFunction(typename internal::stem_function<typename internal::traits<Derived>::Scalar>::type f) const
+\endcode
+
+\param[in] M argument of matrix function, should be a square matrix.
+\param[in] f an entire function; \c f(x,n) should compute the n-th
+derivative of f at x.
+\returns expression representing \p f applied to \p M.
+
+Suppose that \p M is a matrix whose entries have type \c Scalar.
+Then, the second argument, \p f, should be a function with prototype
+\code
+ComplexScalar f(ComplexScalar, int)
+\endcode
+where \c ComplexScalar = \c std::complex<Scalar> if \c Scalar is
+real (e.g., \c float or \c double) and \c ComplexScalar =
+\c Scalar if \c Scalar is complex. The return value of \c f(x,n)
+should be \f$ f^{(n)}(x) \f$, the n-th derivative of f at x.
+
+This routine uses the algorithm described in:
+Philip Davies and Nicholas J. Higham,
+"A Schur-Parlett algorithm for computing matrix functions",
+<em>SIAM J. %Matrix Anal. Applic.</em>, <b>25</b>:464&ndash;485, 2003.
+
+The actual work is done by the MatrixFunction class.
+
+Example: The following program checks that
+\f[ \exp \left[ \begin{array}{ccc}
+ 0 & \frac14\pi & 0 \\
+ -\frac14\pi & 0 & 0 \\
+ 0 & 0 & 0
+ \end{array} \right] = \left[ \begin{array}{ccc}
+ \frac12\sqrt2 & -\frac12\sqrt2 & 0 \\
+ \frac12\sqrt2 & \frac12\sqrt2 & 0 \\
+ 0 & 0 & 1
+ \end{array} \right]. \f]
+This corresponds to a rotation of \f$ \frac14\pi \f$ radians around
+the z-axis. This is the same example as used in the documentation
+of \ref matrixbase_exp "exp()".
+
+\include MatrixFunction.cpp
+Output: \verbinclude MatrixFunction.out
+
+Note that the function \c expfn is defined for complex numbers
+\c x, even though the matrix \c A is over the reals. Instead of
+\c expfn, we could also have used StdStemFunctions::exp:
+\code
+A.matrixFunction(StdStemFunctions<std::complex<double> >::exp, &B);
+\endcode
+
+
+
+\section matrixbase_sin MatrixBase::sin()
+
+Compute the matrix sine.
+
+\code
+const MatrixFunctionReturnValue<Derived> MatrixBase<Derived>::sin() const
+\endcode
+
+\param[in] M a square matrix.
+\returns expression representing \f$ \sin(M) \f$.
+
+This function calls \ref matrixbase_matrixfunction "matrixFunction()" with StdStemFunctions::sin().
+
+Example: \include MatrixSine.cpp
+Output: \verbinclude MatrixSine.out
+
+
+
+\section matrixbase_sinh MatrixBase::sinh()
+
+Compute the matrix hyperbolic sine.
+
+\code
+MatrixFunctionReturnValue<Derived> MatrixBase<Derived>::sinh() const
+\endcode
+
+\param[in] M a square matrix.
+\returns expression representing \f$ \sinh(M) \f$
+
+This function calls \ref matrixbase_matrixfunction "matrixFunction()" with StdStemFunctions::sinh().
+
+Example: \include MatrixSinh.cpp
+Output: \verbinclude MatrixSinh.out
+
+
+\section matrixbase_sqrt MatrixBase::sqrt()
+
+Compute the matrix square root.
+
+\code
+const MatrixSquareRootReturnValue<Derived> MatrixBase<Derived>::sqrt() const
+\endcode
+
+\param[in] M invertible matrix whose square root is to be computed.
+\returns expression representing the matrix square root of \p M.
+
+The matrix square root of \f$ M \f$ is the matrix \f$ M^{1/2} \f$
+whose square is the original matrix; so if \f$ S = M^{1/2} \f$ then
+\f$ S^2 = M \f$.
+
+In the <b>real case</b>, the matrix \f$ M \f$ should be invertible and
+it should have no eigenvalues which are real and negative (pairs of
+complex conjugate eigenvalues are allowed). In that case, the matrix
+has a square root which is also real, and this is the square root
+computed by this function.
+
+The matrix square root is computed by first reducing the matrix to
+quasi-triangular form with the real Schur decomposition. The square
+root of the quasi-triangular matrix can then be computed directly. The
+cost is approximately \f$ 25 n^3 \f$ real flops for the real Schur
+decomposition and \f$ 3\frac13 n^3 \f$ real flops for the remainder
+(though the computation time in practice is likely more than this
+indicates).
+
+Details of the algorithm can be found in: Nicholas J. Highan,
+"Computing real square roots of a real matrix", <em>Linear Algebra
+Appl.</em>, 88/89:405&ndash;430, 1987.
+
+If the matrix is <b>positive-definite symmetric</b>, then the square
+root is also positive-definite symmetric. In this case, it is best to
+use SelfAdjointEigenSolver::operatorSqrt() to compute it.
+
+In the <b>complex case</b>, the matrix \f$ M \f$ should be invertible;
+this is a restriction of the algorithm. The square root computed by
+this algorithm is the one whose eigenvalues have an argument in the
+interval \f$ (-\frac12\pi, \frac12\pi] \f$. This is the usual branch
+cut.
+
+The computation is the same as in the real case, except that the
+complex Schur decomposition is used to reduce the matrix to a
+triangular matrix. The theoretical cost is the same. Details are in:
+&Aring;ke Bj&ouml;rck and Sven Hammarling, "A Schur method for the
+square root of a matrix", <em>Linear Algebra Appl.</em>,
+52/53:127&ndash;140, 1983.
+
+Example: The following program checks that the square root of
+\f[ \left[ \begin{array}{cc}
+ \cos(\frac13\pi) & -\sin(\frac13\pi) \\
+ \sin(\frac13\pi) & \cos(\frac13\pi)
+ \end{array} \right], \f]
+corresponding to a rotation over 60 degrees, is a rotation over 30 degrees:
+\f[ \left[ \begin{array}{cc}
+ \cos(\frac16\pi) & -\sin(\frac16\pi) \\
+ \sin(\frac16\pi) & \cos(\frac16\pi)
+ \end{array} \right]. \f]
+
+\include MatrixSquareRoot.cpp
+Output: \verbinclude MatrixSquareRoot.out
+
+\sa class RealSchur, class ComplexSchur, class MatrixSquareRoot,
+ SelfAdjointEigenSolver::operatorSqrt().
+
+*/
+
+#endif // EIGEN_MATRIX_FUNCTIONS
+
diff --git a/unsupported/Eigen/MoreVectorization b/unsupported/Eigen/MoreVectorization
new file mode 100644
index 000000000..9f0a39f75
--- /dev/null
+++ b/unsupported/Eigen/MoreVectorization
@@ -0,0 +1,16 @@
+#ifndef EIGEN_MOREVECTORIZATION_MODULE_H
+#define EIGEN_MOREVECTORIZATION_MODULE_H
+
+#include <Eigen/Core>
+
+namespace Eigen {
+
+/** \ingroup Unsupported_modules
+ * \defgroup MoreVectorization More vectorization module
+ */
+
+}
+
+#include "src/MoreVectorization/MathFunctions.h"
+
+#endif // EIGEN_MOREVECTORIZATION_MODULE_H
diff --git a/unsupported/Eigen/NonLinearOptimization b/unsupported/Eigen/NonLinearOptimization
new file mode 100644
index 000000000..cf6ca58f8
--- /dev/null
+++ b/unsupported/Eigen/NonLinearOptimization
@@ -0,0 +1,134 @@
+// This file is part of Eugenio, a lightweight C++ template library
+// for linear algebra.
+//
+// Copyright (C) 2009 Thomas Capricelli <orzel@freehackers.org>
+//
+// This Source Code Form is subject to the terms of the Mozilla
+// Public License v. 2.0. If a copy of the MPL was not distributed
+// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+#ifndef EIGEN_NONLINEAROPTIMIZATION_MODULE
+#define EIGEN_NONLINEAROPTIMIZATION_MODULE
+
+#include <vector>
+
+#include <Eigen/Core>
+#include <Eigen/Jacobi>
+#include <Eigen/QR>
+#include <unsupported/Eigen/NumericalDiff>
+
+/** \ingroup Unsupported_modules
+ * \defgroup NonLinearOptimization_Module Non linear optimization module
+ *
+ * \code
+ * #include <unsupported/Eigen/NonLinearOptimization>
+ * \endcode
+ *
+ * This module provides implementation of two important algorithms in non linear
+ * optimization. In both cases, we consider a system of non linear functions. Of
+ * course, this should work, and even work very well if those functions are
+ * actually linear. But if this is so, you should probably better use other
+ * methods more fitted to this special case.
+ *
+ * One algorithm allows to find an extremum of such a system (Levenberg
+ * Marquardt algorithm) and the second one is used to find
+ * a zero for the system (Powell hybrid "dogleg" method).
+ *
+ * This code is a port of minpack (http://en.wikipedia.org/wiki/MINPACK).
+ * Minpack is a very famous, old, robust and well-reknown package, written in
+ * fortran. Those implementations have been carefully tuned, tested, and used
+ * for several decades.
+ *
+ * The original fortran code was automatically translated using f2c (http://en.wikipedia.org/wiki/F2c) in C,
+ * then c++, and then cleaned by several different authors.
+ * The last one of those cleanings being our starting point :
+ * http://devernay.free.fr/hacks/cminpack.html
+ *
+ * Finally, we ported this code to Eigen, creating classes and API
+ * coherent with Eigen. When possible, we switched to Eigen
+ * implementation, such as most linear algebra (vectors, matrices, stable norms).
+ *
+ * Doing so, we were very careful to check the tests we setup at the very
+ * beginning, which ensure that the same results are found.
+ *
+ * \section Tests Tests
+ *
+ * The tests are placed in the file unsupported/test/NonLinear.cpp.
+ *
+ * There are two kinds of tests : those that come from examples bundled with cminpack.
+ * They guaranty we get the same results as the original algorithms (value for 'x',
+ * for the number of evaluations of the function, and for the number of evaluations
+ * of the jacobian if ever).
+ *
+ * Other tests were added by myself at the very beginning of the
+ * process and check the results for levenberg-marquardt using the reference data
+ * on http://www.itl.nist.gov/div898/strd/nls/nls_main.shtml. Since then i've
+ * carefully checked that the same results were obtained when modifiying the
+ * code. Please note that we do not always get the exact same decimals as they do,
+ * but this is ok : they use 128bits float, and we do the tests using the C type 'double',
+ * which is 64 bits on most platforms (x86 and amd64, at least).
+ * I've performed those tests on several other implementations of levenberg-marquardt, and
+ * (c)minpack performs VERY well compared to those, both in accuracy and speed.
+ *
+ * The documentation for running the tests is on the wiki
+ * http://eigen.tuxfamily.org/index.php?title=Tests
+ *
+ * \section API API : overview of methods
+ *
+ * Both algorithms can use either the jacobian (provided by the user) or compute
+ * an approximation by themselves (actually using Eigen \ref NumericalDiff_Module).
+ * The part of API referring to the latter use 'NumericalDiff' in the method names
+ * (exemple: LevenbergMarquardt.minimizeNumericalDiff() )
+ *
+ * The methods LevenbergMarquardt.lmder1()/lmdif1()/lmstr1() and
+ * HybridNonLinearSolver.hybrj1()/hybrd1() are specific methods from the original
+ * minpack package that you probably should NOT use until you are porting a code that
+ * was previously using minpack. They just define a 'simple' API with default values
+ * for some parameters.
+ *
+ * All algorithms are provided using Two APIs :
+ * - one where the user inits the algorithm, and uses '*OneStep()' as much as he wants :
+ * this way the caller have control over the steps
+ * - one where the user just calls a method (optimize() or solve()) which will
+ * handle the loop: init + loop until a stop condition is met. Those are provided for
+ * convenience.
+ *
+ * As an example, the method LevenbergMarquardt::minimize() is
+ * implemented as follow :
+ * \code
+ * Status LevenbergMarquardt<FunctorType,Scalar>::minimize(FVectorType &x, const int mode)
+ * {
+ * Status status = minimizeInit(x, mode);
+ * do {
+ * status = minimizeOneStep(x, mode);
+ * } while (status==Running);
+ * return status;
+ * }
+ * \endcode
+ *
+ * \section examples Examples
+ *
+ * The easiest way to understand how to use this module is by looking at the many examples in the file
+ * unsupported/test/NonLinearOptimization.cpp.
+ */
+
+#ifndef EIGEN_PARSED_BY_DOXYGEN
+
+#include "src/NonLinearOptimization/qrsolv.h"
+#include "src/NonLinearOptimization/r1updt.h"
+#include "src/NonLinearOptimization/r1mpyq.h"
+#include "src/NonLinearOptimization/rwupdt.h"
+#include "src/NonLinearOptimization/fdjac1.h"
+#include "src/NonLinearOptimization/lmpar.h"
+#include "src/NonLinearOptimization/dogleg.h"
+#include "src/NonLinearOptimization/covar.h"
+
+#include "src/NonLinearOptimization/chkder.h"
+
+#endif
+
+#include "src/NonLinearOptimization/HybridNonLinearSolver.h"
+#include "src/NonLinearOptimization/LevenbergMarquardt.h"
+
+
+#endif // EIGEN_NONLINEAROPTIMIZATION_MODULE
diff --git a/unsupported/Eigen/NumericalDiff b/unsupported/Eigen/NumericalDiff
new file mode 100644
index 000000000..b3480312d
--- /dev/null
+++ b/unsupported/Eigen/NumericalDiff
@@ -0,0 +1,56 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra.
+//
+// Copyright (C) 2009 Thomas Capricelli <orzel@freehackers.org>
+//
+// This Source Code Form is subject to the terms of the Mozilla
+// Public License v. 2.0. If a copy of the MPL was not distributed
+// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+#ifndef EIGEN_NUMERICALDIFF_MODULE
+#define EIGEN_NUMERICALDIFF_MODULE
+
+#include <Eigen/Core>
+
+namespace Eigen {
+
+/** \ingroup Unsupported_modules
+ * \defgroup NumericalDiff_Module Numerical differentiation module
+ *
+ * \code
+ * #include <unsupported/Eigen/NumericalDiff>
+ * \endcode
+ *
+ * See http://en.wikipedia.org/wiki/Numerical_differentiation
+ *
+ * Warning : this should NOT be confused with automatic differentiation, which
+ * is a different method and has its own module in Eigen : \ref
+ * AutoDiff_Module.
+ *
+ * Currently only "Forward" and "Central" schemes are implemented. Those
+ * are basic methods, and there exist some more elaborated way of
+ * computing such approximates. They are implemented using both
+ * proprietary and free software, and usually requires linking to an
+ * external library. It is very easy for you to write a functor
+ * using such software, and the purpose is quite orthogonal to what we
+ * want to achieve with Eigen.
+ *
+ * This is why we will not provide wrappers for every great numerical
+ * differentiation software that exist, but should rather stick with those
+ * basic ones, that still are useful for testing.
+ *
+ * Also, the \ref NonLinearOptimization_Module needs this in order to
+ * provide full features compatibility with the original (c)minpack
+ * package.
+ *
+ */
+}
+
+//@{
+
+#include "src/NumericalDiff/NumericalDiff.h"
+
+//@}
+
+
+#endif // EIGEN_NUMERICALDIFF_MODULE
diff --git a/unsupported/Eigen/OpenGLSupport b/unsupported/Eigen/OpenGLSupport
new file mode 100644
index 000000000..e66a425f8
--- /dev/null
+++ b/unsupported/Eigen/OpenGLSupport
@@ -0,0 +1,317 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra.
+//
+// Copyright (C) 2010 Gael Guennebaud <gael.guennebaud@inria.fr>
+//
+// This Source Code Form is subject to the terms of the Mozilla
+// Public License v. 2.0. If a copy of the MPL was not distributed
+// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+#ifndef EIGEN_OPENGL_MODULE
+#define EIGEN_OPENGL_MODULE
+
+#include <Eigen/Geometry>
+#include <GL/gl.h>
+
+namespace Eigen {
+
+/** \ingroup Unsupported_modules
+ * \defgroup OpenGLSUpport_Module OpenGL Support module
+ *
+ * This module provides wrapper functions for a couple of OpenGL functions
+ * which simplify the way to pass Eigen's object to openGL.
+ * Here is an exmaple:
+ *
+ * \code
+ * // You need to add path_to_eigen/unsupported to your include path.
+ * #include <Eigen/OpenGLSupport>
+ * // ...
+ * Vector3f x, y;
+ * Matrix3f rot;
+ *
+ * glVertex(y + x * rot);
+ *
+ * Quaternion q;
+ * glRotate(q);
+ *
+ * // ...
+ * \endcode
+ *
+ */
+//@{
+
+#define EIGEN_GL_FUNC_DECLARATION(FUNC) \
+namespace internal { \
+ template< typename XprType, \
+ typename Scalar = typename XprType::Scalar, \
+ int Rows = XprType::RowsAtCompileTime, \
+ int Cols = XprType::ColsAtCompileTime, \
+ bool IsGLCompatible = bool(XprType::Flags&LinearAccessBit) \
+ && bool(XprType::Flags&DirectAccessBit) \
+ && (XprType::IsVectorAtCompileTime || (XprType::Flags&RowMajorBit)==0)> \
+ struct EIGEN_CAT(EIGEN_CAT(gl_,FUNC),_impl); \
+ \
+ template<typename XprType, typename Scalar, int Rows, int Cols> \
+ struct EIGEN_CAT(EIGEN_CAT(gl_,FUNC),_impl)<XprType,Scalar,Rows,Cols,false> { \
+ inline static void run(const XprType& p) { \
+ EIGEN_CAT(EIGEN_CAT(gl_,FUNC),_impl)<typename plain_matrix_type_column_major<XprType>::type>::run(p); } \
+ }; \
+} \
+ \
+template<typename Derived> inline void FUNC(const Eigen::DenseBase<Derived>& p) { \
+ EIGEN_CAT(EIGEN_CAT(internal::gl_,FUNC),_impl)<Derived>::run(p.derived()); \
+}
+
+
+#define EIGEN_GL_FUNC_SPECIALIZATION_MAT(FUNC,SCALAR,ROWS,COLS,SUFFIX) \
+namespace internal { \
+ template< typename XprType> struct EIGEN_CAT(EIGEN_CAT(gl_,FUNC),_impl)<XprType, SCALAR, ROWS, COLS, true> { \
+ inline static void run(const XprType& p) { FUNC##SUFFIX(p.data()); } \
+ }; \
+}
+
+
+#define EIGEN_GL_FUNC_SPECIALIZATION_VEC(FUNC,SCALAR,SIZE,SUFFIX) \
+namespace internal { \
+ template< typename XprType> struct EIGEN_CAT(EIGEN_CAT(gl_,FUNC),_impl)<XprType, SCALAR, SIZE, 1, true> { \
+ inline static void run(const XprType& p) { FUNC##SUFFIX(p.data()); } \
+ }; \
+ template< typename XprType> struct EIGEN_CAT(EIGEN_CAT(gl_,FUNC),_impl)<XprType, SCALAR, 1, SIZE, true> { \
+ inline static void run(const XprType& p) { FUNC##SUFFIX(p.data()); } \
+ }; \
+}
+
+
+EIGEN_GL_FUNC_DECLARATION (glVertex)
+EIGEN_GL_FUNC_SPECIALIZATION_VEC(glVertex,int, 2,2iv)
+EIGEN_GL_FUNC_SPECIALIZATION_VEC(glVertex,short, 2,2sv)
+EIGEN_GL_FUNC_SPECIALIZATION_VEC(glVertex,float, 2,2fv)
+EIGEN_GL_FUNC_SPECIALIZATION_VEC(glVertex,double, 2,2dv)
+EIGEN_GL_FUNC_SPECIALIZATION_VEC(glVertex,int, 3,3iv)
+EIGEN_GL_FUNC_SPECIALIZATION_VEC(glVertex,short, 3,3sv)
+EIGEN_GL_FUNC_SPECIALIZATION_VEC(glVertex,float, 3,3fv)
+EIGEN_GL_FUNC_SPECIALIZATION_VEC(glVertex,double, 3,3dv)
+EIGEN_GL_FUNC_SPECIALIZATION_VEC(glVertex,int, 4,4iv)
+EIGEN_GL_FUNC_SPECIALIZATION_VEC(glVertex,short, 4,4sv)
+EIGEN_GL_FUNC_SPECIALIZATION_VEC(glVertex,float, 4,4fv)
+EIGEN_GL_FUNC_SPECIALIZATION_VEC(glVertex,double, 4,4dv)
+
+EIGEN_GL_FUNC_DECLARATION (glTexCoord)
+EIGEN_GL_FUNC_SPECIALIZATION_VEC(glTexCoord,int, 2,2iv)
+EIGEN_GL_FUNC_SPECIALIZATION_VEC(glTexCoord,short, 2,2sv)
+EIGEN_GL_FUNC_SPECIALIZATION_VEC(glTexCoord,float, 2,2fv)
+EIGEN_GL_FUNC_SPECIALIZATION_VEC(glTexCoord,double, 2,2dv)
+EIGEN_GL_FUNC_SPECIALIZATION_VEC(glTexCoord,int, 3,3iv)
+EIGEN_GL_FUNC_SPECIALIZATION_VEC(glTexCoord,short, 3,3sv)
+EIGEN_GL_FUNC_SPECIALIZATION_VEC(glTexCoord,float, 3,3fv)
+EIGEN_GL_FUNC_SPECIALIZATION_VEC(glTexCoord,double, 3,3dv)
+EIGEN_GL_FUNC_SPECIALIZATION_VEC(glTexCoord,int, 4,4iv)
+EIGEN_GL_FUNC_SPECIALIZATION_VEC(glTexCoord,short, 4,4sv)
+EIGEN_GL_FUNC_SPECIALIZATION_VEC(glTexCoord,float, 4,4fv)
+EIGEN_GL_FUNC_SPECIALIZATION_VEC(glTexCoord,double, 4,4dv)
+
+EIGEN_GL_FUNC_DECLARATION (glColor)
+EIGEN_GL_FUNC_SPECIALIZATION_VEC(glColor,int, 2,2iv)
+EIGEN_GL_FUNC_SPECIALIZATION_VEC(glColor,short, 2,2sv)
+EIGEN_GL_FUNC_SPECIALIZATION_VEC(glColor,float, 2,2fv)
+EIGEN_GL_FUNC_SPECIALIZATION_VEC(glColor,double, 2,2dv)
+EIGEN_GL_FUNC_SPECIALIZATION_VEC(glColor,int, 3,3iv)
+EIGEN_GL_FUNC_SPECIALIZATION_VEC(glColor,short, 3,3sv)
+EIGEN_GL_FUNC_SPECIALIZATION_VEC(glColor,float, 3,3fv)
+EIGEN_GL_FUNC_SPECIALIZATION_VEC(glColor,double, 3,3dv)
+EIGEN_GL_FUNC_SPECIALIZATION_VEC(glColor,int, 4,4iv)
+EIGEN_GL_FUNC_SPECIALIZATION_VEC(glColor,short, 4,4sv)
+EIGEN_GL_FUNC_SPECIALIZATION_VEC(glColor,float, 4,4fv)
+EIGEN_GL_FUNC_SPECIALIZATION_VEC(glColor,double, 4,4dv)
+
+EIGEN_GL_FUNC_DECLARATION (glNormal)
+EIGEN_GL_FUNC_SPECIALIZATION_VEC(glNormal,int, 3,3iv)
+EIGEN_GL_FUNC_SPECIALIZATION_VEC(glNormal,short, 3,3sv)
+EIGEN_GL_FUNC_SPECIALIZATION_VEC(glNormal,float, 3,3fv)
+EIGEN_GL_FUNC_SPECIALIZATION_VEC(glNormal,double, 3,3dv)
+
+inline void glScale2fv(const float* v) { glScalef(v[0], v[1], 1.f); }
+inline void glScale2dv(const double* v) { glScaled(v[0], v[1], 1.0); }
+inline void glScale3fv(const float* v) { glScalef(v[0], v[1], v[2]); }
+inline void glScale3dv(const double* v) { glScaled(v[0], v[1], v[2]); }
+
+EIGEN_GL_FUNC_DECLARATION (glScale)
+EIGEN_GL_FUNC_SPECIALIZATION_VEC(glScale,float, 2,2fv)
+EIGEN_GL_FUNC_SPECIALIZATION_VEC(glScale,double, 2,2dv)
+EIGEN_GL_FUNC_SPECIALIZATION_VEC(glScale,float, 3,3fv)
+EIGEN_GL_FUNC_SPECIALIZATION_VEC(glScale,double, 3,3dv)
+
+template<typename Scalar> void glScale(const UniformScaling<Scalar>& s) { glScale(Matrix<Scalar,3,1>::Constant(s.factor())); }
+
+inline void glTranslate2fv(const float* v) { glTranslatef(v[0], v[1], 0.f); }
+inline void glTranslate2dv(const double* v) { glTranslated(v[0], v[1], 0.0); }
+inline void glTranslate3fv(const float* v) { glTranslatef(v[0], v[1], v[2]); }
+inline void glTranslate3dv(const double* v) { glTranslated(v[0], v[1], v[2]); }
+
+EIGEN_GL_FUNC_DECLARATION (glTranslate)
+EIGEN_GL_FUNC_SPECIALIZATION_VEC(glTranslate,float, 2,2fv)
+EIGEN_GL_FUNC_SPECIALIZATION_VEC(glTranslate,double, 2,2dv)
+EIGEN_GL_FUNC_SPECIALIZATION_VEC(glTranslate,float, 3,3fv)
+EIGEN_GL_FUNC_SPECIALIZATION_VEC(glTranslate,double, 3,3dv)
+
+template<typename Scalar> void glTranslate(const Translation<Scalar,2>& t) { glTranslate(t.vector()); }
+template<typename Scalar> void glTranslate(const Translation<Scalar,3>& t) { glTranslate(t.vector()); }
+
+EIGEN_GL_FUNC_DECLARATION (glMultMatrix)
+EIGEN_GL_FUNC_SPECIALIZATION_MAT(glMultMatrix,float, 4,4,f)
+EIGEN_GL_FUNC_SPECIALIZATION_MAT(glMultMatrix,double, 4,4,d)
+
+template<typename Scalar> void glMultMatrix(const Transform<Scalar,3,Affine>& t) { glMultMatrix(t.matrix()); }
+template<typename Scalar> void glMultMatrix(const Transform<Scalar,3,Projective>& t) { glMultMatrix(t.matrix()); }
+template<typename Scalar> void glMultMatrix(const Transform<Scalar,3,AffineCompact>& t) { glMultMatrix(Transform<Scalar,3,Affine>(t).matrix()); }
+
+EIGEN_GL_FUNC_DECLARATION (glLoadMatrix)
+EIGEN_GL_FUNC_SPECIALIZATION_MAT(glLoadMatrix,float, 4,4,f)
+EIGEN_GL_FUNC_SPECIALIZATION_MAT(glLoadMatrix,double, 4,4,d)
+
+template<typename Scalar> void glLoadMatrix(const Transform<Scalar,3,Affine>& t) { glLoadMatrix(t.matrix()); }
+template<typename Scalar> void glLoadMatrix(const Transform<Scalar,3,Projective>& t) { glLoadMatrix(t.matrix()); }
+template<typename Scalar> void glLoadMatrix(const Transform<Scalar,3,AffineCompact>& t) { glLoadMatrix(Transform<Scalar,3,Affine>(t).matrix()); }
+
+static void glRotate(const Rotation2D<float>& rot)
+{
+ glRotatef(rot.angle()*180.f/float(M_PI), 0.f, 0.f, 1.f);
+}
+static void glRotate(const Rotation2D<double>& rot)
+{
+ glRotated(rot.angle()*180.0/M_PI, 0.0, 0.0, 1.0);
+}
+
+template<typename Derived> void glRotate(const RotationBase<Derived,3>& rot)
+{
+ Transform<typename Derived::Scalar,3,Projective> tr(rot);
+ glMultMatrix(tr.matrix());
+}
+
+#define EIGEN_GL_MAKE_CONST_const const
+#define EIGEN_GL_MAKE_CONST__
+#define EIGEN_GL_EVAL(X) X
+
+#define EIGEN_GL_FUNC1_DECLARATION(FUNC,ARG1,CONST) \
+namespace internal { \
+ template< typename XprType, \
+ typename Scalar = typename XprType::Scalar, \
+ int Rows = XprType::RowsAtCompileTime, \
+ int Cols = XprType::ColsAtCompileTime, \
+ bool IsGLCompatible = bool(XprType::Flags&LinearAccessBit) \
+ && bool(XprType::Flags&DirectAccessBit) \
+ && (XprType::IsVectorAtCompileTime || (XprType::Flags&RowMajorBit)==0)> \
+ struct EIGEN_CAT(EIGEN_CAT(gl_,FUNC),_impl); \
+ \
+ template<typename XprType, typename Scalar, int Rows, int Cols> \
+ struct EIGEN_CAT(EIGEN_CAT(gl_,FUNC),_impl)<XprType,Scalar,Rows,Cols,false> { \
+ inline static void run(ARG1 a,EIGEN_GL_EVAL(EIGEN_GL_MAKE_CONST_##CONST) XprType& p) { \
+ EIGEN_CAT(EIGEN_CAT(gl_,FUNC),_impl)<typename plain_matrix_type_column_major<XprType>::type>::run(a,p); } \
+ }; \
+} \
+ \
+template<typename Derived> inline void FUNC(ARG1 a,EIGEN_GL_EVAL(EIGEN_GL_MAKE_CONST_##CONST) Eigen::DenseBase<Derived>& p) { \
+ EIGEN_CAT(EIGEN_CAT(internal::gl_,FUNC),_impl)<Derived>::run(a,p.derived()); \
+}
+
+
+#define EIGEN_GL_FUNC1_SPECIALIZATION_MAT(FUNC,ARG1,CONST,SCALAR,ROWS,COLS,SUFFIX) \
+namespace internal { \
+ template< typename XprType> struct EIGEN_CAT(EIGEN_CAT(gl_,FUNC),_impl)<XprType, SCALAR, ROWS, COLS, true> { \
+ inline static void run(ARG1 a, EIGEN_GL_EVAL(EIGEN_GL_MAKE_CONST_##CONST) XprType& p) { FUNC##SUFFIX(a,p.data()); } \
+ }; \
+}
+
+
+#define EIGEN_GL_FUNC1_SPECIALIZATION_VEC(FUNC,ARG1,CONST,SCALAR,SIZE,SUFFIX) \
+namespace internal { \
+ template< typename XprType> struct EIGEN_CAT(EIGEN_CAT(gl_,FUNC),_impl)<XprType, SCALAR, SIZE, 1, true> { \
+ inline static void run(ARG1 a, EIGEN_GL_EVAL(EIGEN_GL_MAKE_CONST_##CONST) XprType& p) { FUNC##SUFFIX(a,p.data()); } \
+ }; \
+ template< typename XprType> struct EIGEN_CAT(EIGEN_CAT(gl_,FUNC),_impl)<XprType, SCALAR, 1, SIZE, true> { \
+ inline static void run(ARG1 a, EIGEN_GL_EVAL(EIGEN_GL_MAKE_CONST_##CONST) XprType& p) { FUNC##SUFFIX(a,p.data()); } \
+ }; \
+}
+
+EIGEN_GL_FUNC1_DECLARATION (glGet,GLenum,_)
+EIGEN_GL_FUNC1_SPECIALIZATION_MAT(glGet,GLenum,_,float, 4,4,Floatv)
+EIGEN_GL_FUNC1_SPECIALIZATION_MAT(glGet,GLenum,_,double, 4,4,Doublev)
+
+// glUniform API
+
+#ifdef GL_VERSION_2_0
+
+static void glUniform2fv_ei (GLint loc, const float* v) { glUniform2fv(loc,1,v); }
+static void glUniform2iv_ei (GLint loc, const int* v) { glUniform2iv(loc,1,v); }
+
+static void glUniform3fv_ei (GLint loc, const float* v) { glUniform3fv(loc,1,v); }
+static void glUniform3iv_ei (GLint loc, const int* v) { glUniform3iv(loc,1,v); }
+
+static void glUniform4fv_ei (GLint loc, const float* v) { glUniform4fv(loc,1,v); }
+static void glUniform4iv_ei (GLint loc, const int* v) { glUniform4iv(loc,1,v); }
+
+static void glUniformMatrix2fv_ei (GLint loc, const float* v) { glUniformMatrix2fv(loc,1,false,v); }
+static void glUniformMatrix3fv_ei (GLint loc, const float* v) { glUniformMatrix3fv(loc,1,false,v); }
+static void glUniformMatrix4fv_ei (GLint loc, const float* v) { glUniformMatrix4fv(loc,1,false,v); }
+
+
+EIGEN_GL_FUNC1_DECLARATION (glUniform,GLint,const)
+EIGEN_GL_FUNC1_SPECIALIZATION_VEC(glUniform,GLint,const,float, 2,2fv_ei)
+EIGEN_GL_FUNC1_SPECIALIZATION_VEC(glUniform,GLint,const,int, 2,2iv_ei)
+EIGEN_GL_FUNC1_SPECIALIZATION_VEC(glUniform,GLint,const,float, 3,3fv_ei)
+EIGEN_GL_FUNC1_SPECIALIZATION_VEC(glUniform,GLint,const,int, 3,3iv_ei)
+EIGEN_GL_FUNC1_SPECIALIZATION_VEC(glUniform,GLint,const,float, 4,4fv_ei)
+EIGEN_GL_FUNC1_SPECIALIZATION_VEC(glUniform,GLint,const,int, 4,4iv_ei)
+
+EIGEN_GL_FUNC1_SPECIALIZATION_MAT(glUniform,GLint,const,float, 2,2,Matrix2fv_ei)
+EIGEN_GL_FUNC1_SPECIALIZATION_MAT(glUniform,GLint,const,float, 3,3,Matrix3fv_ei)
+EIGEN_GL_FUNC1_SPECIALIZATION_MAT(glUniform,GLint,const,float, 4,4,Matrix4fv_ei)
+
+#endif
+
+#ifdef GL_VERSION_2_1
+
+static void glUniformMatrix2x3fv_ei(GLint loc, const float* v) { glUniformMatrix2x3fv(loc,1,false,v); }
+static void glUniformMatrix3x2fv_ei(GLint loc, const float* v) { glUniformMatrix3x2fv(loc,1,false,v); }
+static void glUniformMatrix2x4fv_ei(GLint loc, const float* v) { glUniformMatrix2x4fv(loc,1,false,v); }
+static void glUniformMatrix4x2fv_ei(GLint loc, const float* v) { glUniformMatrix4x2fv(loc,1,false,v); }
+static void glUniformMatrix3x4fv_ei(GLint loc, const float* v) { glUniformMatrix3x4fv(loc,1,false,v); }
+static void glUniformMatrix4x3fv_ei(GLint loc, const float* v) { glUniformMatrix4x3fv(loc,1,false,v); }
+
+EIGEN_GL_FUNC1_SPECIALIZATION_MAT(glUniform,GLint,const,float, 2,3,Matrix2x3fv_ei)
+EIGEN_GL_FUNC1_SPECIALIZATION_MAT(glUniform,GLint,const,float, 3,2,Matrix3x2fv_ei)
+EIGEN_GL_FUNC1_SPECIALIZATION_MAT(glUniform,GLint,const,float, 2,4,Matrix2x4fv_ei)
+EIGEN_GL_FUNC1_SPECIALIZATION_MAT(glUniform,GLint,const,float, 4,2,Matrix4x2fv_ei)
+EIGEN_GL_FUNC1_SPECIALIZATION_MAT(glUniform,GLint,const,float, 3,4,Matrix3x4fv_ei)
+EIGEN_GL_FUNC1_SPECIALIZATION_MAT(glUniform,GLint,const,float, 4,3,Matrix4x3fv_ei)
+
+#endif
+
+#ifdef GL_VERSION_3_0
+
+static void glUniform2uiv_ei (GLint loc, const unsigned int* v) { glUniform2uiv(loc,1,v); }
+static void glUniform3uiv_ei (GLint loc, const unsigned int* v) { glUniform3uiv(loc,1,v); }
+static void glUniform4uiv_ei (GLint loc, const unsigned int* v) { glUniform4uiv(loc,1,v); }
+
+EIGEN_GL_FUNC1_SPECIALIZATION_VEC(glUniform,GLint,const,unsigned int, 2,2uiv_ei)
+EIGEN_GL_FUNC1_SPECIALIZATION_VEC(glUniform,GLint,const,unsigned int, 3,3uiv_ei)
+EIGEN_GL_FUNC1_SPECIALIZATION_VEC(glUniform,GLint,const,unsigned int, 4,4uiv_ei)
+
+#endif
+
+#ifdef GL_ARB_gpu_shader_fp64
+static void glUniform2dv_ei (GLint loc, const double* v) { glUniform2dv(loc,1,v); }
+static void glUniform3dv_ei (GLint loc, const double* v) { glUniform3dv(loc,1,v); }
+static void glUniform4dv_ei (GLint loc, const double* v) { glUniform4dv(loc,1,v); }
+
+EIGEN_GL_FUNC1_SPECIALIZATION_VEC(glUniform,GLint,const,double, 2,2dv_ei)
+EIGEN_GL_FUNC1_SPECIALIZATION_VEC(glUniform,GLint,const,double, 3,3dv_ei)
+EIGEN_GL_FUNC1_SPECIALIZATION_VEC(glUniform,GLint,const,double, 4,4dv_ei)
+#endif
+
+
+//@}
+
+}
+
+#endif // EIGEN_OPENGL_MODULE
diff --git a/unsupported/Eigen/Polynomials b/unsupported/Eigen/Polynomials
new file mode 100644
index 000000000..fa58b006d
--- /dev/null
+++ b/unsupported/Eigen/Polynomials
@@ -0,0 +1,133 @@
+#ifndef EIGEN_POLYNOMIALS_MODULE_H
+#define EIGEN_POLYNOMIALS_MODULE_H
+
+#include <Eigen/Core>
+
+#include <Eigen/src/Core/util/DisableStupidWarnings.h>
+
+#include <Eigen/Eigenvalues>
+
+// Note that EIGEN_HIDE_HEAVY_CODE has to be defined per module
+#if (defined EIGEN_EXTERN_INSTANTIATIONS) && (EIGEN_EXTERN_INSTANTIATIONS>=2)
+ #ifndef EIGEN_HIDE_HEAVY_CODE
+ #define EIGEN_HIDE_HEAVY_CODE
+ #endif
+#elif defined EIGEN_HIDE_HEAVY_CODE
+ #undef EIGEN_HIDE_HEAVY_CODE
+#endif
+
+/** \ingroup Unsupported_modules
+ * \defgroup Polynomials_Module Polynomials module
+ *
+ *
+ *
+ * \brief This module provides a QR based polynomial solver.
+ *
+ * To use this module, add
+ * \code
+ * #include <unsupported/Eigen/Polynomials>
+ * \endcode
+ * at the start of your source file.
+ */
+
+#include "src/Polynomials/PolynomialUtils.h"
+#include "src/Polynomials/Companion.h"
+#include "src/Polynomials/PolynomialSolver.h"
+
+/**
+ \page polynomials Polynomials defines functions for dealing with polynomials
+ and a QR based polynomial solver.
+ \ingroup Polynomials_Module
+
+ The remainder of the page documents first the functions for evaluating, computing
+ polynomials, computing estimates about polynomials and next the QR based polynomial
+ solver.
+
+ \section polynomialUtils convenient functions to deal with polynomials
+ \subsection roots_to_monicPolynomial
+ The function
+ \code
+ void roots_to_monicPolynomial( const RootVector& rv, Polynomial& poly )
+ \endcode
+ computes the coefficients \f$ a_i \f$ of
+
+ \f$ p(x) = a_0 + a_{1}x + ... + a_{n-1}x^{n-1} + x^n \f$
+
+ where \f$ p \f$ is known through its roots i.e. \f$ p(x) = (x-r_1)(x-r_2)...(x-r_n) \f$.
+
+ \subsection poly_eval
+ The function
+ \code
+ T poly_eval( const Polynomials& poly, const T& x )
+ \endcode
+ evaluates a polynomial at a given point using stabilized H&ouml;rner method.
+
+ The following code: first computes the coefficients in the monomial basis of the monic polynomial that has the provided roots;
+ then, it evaluates the computed polynomial, using a stabilized H&ouml;rner method.
+
+ \include PolynomialUtils1.cpp
+ Output: \verbinclude PolynomialUtils1.out
+
+ \subsection Cauchy bounds
+ The function
+ \code
+ Real cauchy_max_bound( const Polynomial& poly )
+ \endcode
+ provides a maximum bound (the Cauchy one: \f$C(p)\f$) for the absolute value of a root of the given polynomial i.e.
+ \f$ \forall r_i \f$ root of \f$ p(x) = \sum_{k=0}^d a_k x^k \f$,
+ \f$ |r_i| \le C(p) = \sum_{k=0}^{d} \left | \frac{a_k}{a_d} \right | \f$
+ The leading coefficient \f$ p \f$: should be non zero \f$a_d \neq 0\f$.
+
+
+ The function
+ \code
+ Real cauchy_min_bound( const Polynomial& poly )
+ \endcode
+ provides a minimum bound (the Cauchy one: \f$c(p)\f$) for the absolute value of a non zero root of the given polynomial i.e.
+ \f$ \forall r_i \neq 0 \f$ root of \f$ p(x) = \sum_{k=0}^d a_k x^k \f$,
+ \f$ |r_i| \ge c(p) = \left( \sum_{k=0}^{d} \left | \frac{a_k}{a_0} \right | \right)^{-1} \f$
+
+
+
+
+ \section QR polynomial solver class
+ Computes the complex roots of a polynomial by computing the eigenvalues of the associated companion matrix with the QR algorithm.
+
+ The roots of \f$ p(x) = a_0 + a_1 x + a_2 x^2 + a_{3} x^3 + x^4 \f$ are the eigenvalues of
+ \f$
+ \left [
+ \begin{array}{cccc}
+ 0 & 0 & 0 & a_0 \\
+ 1 & 0 & 0 & a_1 \\
+ 0 & 1 & 0 & a_2 \\
+ 0 & 0 & 1 & a_3
+ \end{array} \right ]
+ \f$
+
+ However, the QR algorithm is not guaranteed to converge when there are several eigenvalues with same modulus.
+
+ Therefore the current polynomial solver is guaranteed to provide a correct result only when the complex roots \f$r_1,r_2,...,r_d\f$ have distinct moduli i.e.
+
+ \f$ \forall i,j \in [1;d],~ \| r_i \| \neq \| r_j \| \f$.
+
+ With 32bit (float) floating types this problem shows up frequently.
+ However, almost always, correct accuracy is reached even in these cases for 64bit
+ (double) floating types and small polynomial degree (<20).
+
+ \include PolynomialSolver1.cpp
+
+ In the above example:
+
+ -# a simple use of the polynomial solver is shown;
+ -# the accuracy problem with the QR algorithm is presented: a polynomial with almost conjugate roots is provided to the solver.
+ Those roots have almost same module therefore the QR algorithm failed to converge: the accuracy
+ of the last root is bad;
+ -# a simple way to circumvent the problem is shown: use doubles instead of floats.
+
+ Output: \verbinclude PolynomialSolver1.out
+*/
+
+#include <Eigen/src/Core/util/ReenableStupidWarnings.h>
+
+#endif // EIGEN_POLYNOMIALS_MODULE_H
+/* vim: set filetype=cpp et sw=2 ts=2 ai: */
diff --git a/unsupported/Eigen/Skyline b/unsupported/Eigen/Skyline
new file mode 100644
index 000000000..c9823f358
--- /dev/null
+++ b/unsupported/Eigen/Skyline
@@ -0,0 +1,31 @@
+#ifndef EIGEN_SKYLINE_MODULE_H
+#define EIGEN_SKYLINE_MODULE_H
+
+
+#include "Eigen/Core"
+
+#include "Eigen/src/Core/util/DisableStupidWarnings.h"
+
+#include <map>
+#include <cstdlib>
+#include <cstring>
+#include <algorithm>
+
+/** \ingroup Unsupported_modules
+ * \defgroup Skyline_Module Skyline module
+ *
+ *
+ *
+ *
+ */
+
+#include "src/Skyline/SkylineUtil.h"
+#include "src/Skyline/SkylineMatrixBase.h"
+#include "src/Skyline/SkylineStorage.h"
+#include "src/Skyline/SkylineMatrix.h"
+#include "src/Skyline/SkylineInplaceLU.h"
+#include "src/Skyline/SkylineProduct.h"
+
+#include "Eigen/src/Core/util/ReenableStupidWarnings.h"
+
+#endif // EIGEN_SKYLINE_MODULE_H
diff --git a/unsupported/Eigen/SparseExtra b/unsupported/Eigen/SparseExtra
new file mode 100644
index 000000000..340c34736
--- /dev/null
+++ b/unsupported/Eigen/SparseExtra
@@ -0,0 +1,47 @@
+#ifndef EIGEN_SPARSE_EXTRA_MODULE_H
+#define EIGEN_SPARSE_EXTRA_MODULE_H
+
+#include "../../Eigen/Sparse"
+
+#include "../../Eigen/src/Core/util/DisableStupidWarnings.h"
+
+#include <vector>
+#include <map>
+#include <cstdlib>
+#include <cstring>
+#include <algorithm>
+#include <fstream>
+#include <sstream>
+
+#ifdef EIGEN_GOOGLEHASH_SUPPORT
+ #include <google/dense_hash_map>
+#endif
+
+/** \ingroup Unsupported_modules
+ * \defgroup SparseExtra_Module SparseExtra module
+ *
+ * This module contains some experimental features extending the sparse module.
+ *
+ * \code
+ * #include <Eigen/SparseExtra>
+ * \endcode
+ */
+
+
+#include "../../Eigen/src/misc/Solve.h"
+#include "../../Eigen/src/misc/SparseSolve.h"
+
+#include "src/SparseExtra/DynamicSparseMatrix.h"
+#include "src/SparseExtra/BlockOfDynamicSparseMatrix.h"
+#include "src/SparseExtra/RandomSetter.h"
+
+#include "src/SparseExtra/MarketIO.h"
+
+#if !defined(_WIN32)
+#include <dirent.h>
+#include "src/SparseExtra/MatrixMarketIterator.h"
+#endif
+
+#include "../../Eigen/src/Core/util/ReenableStupidWarnings.h"
+
+#endif // EIGEN_SPARSE_EXTRA_MODULE_H
diff --git a/unsupported/Eigen/Splines b/unsupported/Eigen/Splines
new file mode 100644
index 000000000..801cec1a1
--- /dev/null
+++ b/unsupported/Eigen/Splines
@@ -0,0 +1,31 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra.
+//
+// Copyright (C) 20010-2011 Hauke Heibel <hauke.heibel@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 EIGEN_SPLINES_MODULE_H
+#define EIGEN_SPLINES_MODULE_H
+
+namespace Eigen
+{
+/** \ingroup Unsupported_modules
+ * \defgroup Splines_Module Spline and spline fitting module
+ *
+ * This module provides a simple multi-dimensional spline class while
+ * offering most basic functionality to fit a spline to point sets.
+ *
+ * \code
+ * #include <unsupported/Eigen/Splines>
+ * \endcode
+ */
+}
+
+#include "src/Splines/SplineFwd.h"
+#include "src/Splines/Spline.h"
+#include "src/Splines/SplineFitting.h"
+
+#endif // EIGEN_SPLINES_MODULE_H
diff --git a/unsupported/Eigen/src/AutoDiff/AutoDiffJacobian.h b/unsupported/Eigen/src/AutoDiff/AutoDiffJacobian.h
new file mode 100644
index 000000000..1a61e3367
--- /dev/null
+++ b/unsupported/Eigen/src/AutoDiff/AutoDiffJacobian.h
@@ -0,0 +1,83 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra.
+//
+// Copyright (C) 2009 Gael Guennebaud <gael.guennebaud@inria.fr>
+//
+// This Source Code Form is subject to the terms of the Mozilla
+// Public License v. 2.0. If a copy of the MPL was not distributed
+// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+#ifndef EIGEN_AUTODIFF_JACOBIAN_H
+#define EIGEN_AUTODIFF_JACOBIAN_H
+
+namespace Eigen
+{
+
+template<typename Functor> class AutoDiffJacobian : public Functor
+{
+public:
+ AutoDiffJacobian() : Functor() {}
+ AutoDiffJacobian(const Functor& f) : Functor(f) {}
+
+ // forward constructors
+ template<typename T0>
+ AutoDiffJacobian(const T0& a0) : Functor(a0) {}
+ template<typename T0, typename T1>
+ AutoDiffJacobian(const T0& a0, const T1& a1) : Functor(a0, a1) {}
+ template<typename T0, typename T1, typename T2>
+ AutoDiffJacobian(const T0& a0, const T1& a1, const T2& a2) : Functor(a0, a1, a2) {}
+
+ enum {
+ InputsAtCompileTime = Functor::InputsAtCompileTime,
+ ValuesAtCompileTime = Functor::ValuesAtCompileTime
+ };
+
+ typedef typename Functor::InputType InputType;
+ typedef typename Functor::ValueType ValueType;
+ typedef typename Functor::JacobianType JacobianType;
+ typedef typename JacobianType::Scalar Scalar;
+ typedef typename JacobianType::Index Index;
+
+ typedef Matrix<Scalar,InputsAtCompileTime,1> DerivativeType;
+ typedef AutoDiffScalar<DerivativeType> ActiveScalar;
+
+
+ typedef Matrix<ActiveScalar, InputsAtCompileTime, 1> ActiveInput;
+ typedef Matrix<ActiveScalar, ValuesAtCompileTime, 1> ActiveValue;
+
+ void operator() (const InputType& x, ValueType* v, JacobianType* _jac=0) const
+ {
+ eigen_assert(v!=0);
+ if (!_jac)
+ {
+ Functor::operator()(x, v);
+ return;
+ }
+
+ JacobianType& jac = *_jac;
+
+ ActiveInput ax = x.template cast<ActiveScalar>();
+ ActiveValue av(jac.rows());
+
+ if(InputsAtCompileTime==Dynamic)
+ for (Index j=0; j<jac.rows(); j++)
+ av[j].derivatives().resize(this->inputs());
+
+ for (Index i=0; i<jac.cols(); i++)
+ ax[i].derivatives() = DerivativeType::Unit(this->inputs(),i);
+
+ Functor::operator()(ax, &av);
+
+ for (Index i=0; i<jac.rows(); i++)
+ {
+ (*v)[i] = av[i].value();
+ jac.row(i) = av[i].derivatives();
+ }
+ }
+protected:
+
+};
+
+}
+
+#endif // EIGEN_AUTODIFF_JACOBIAN_H
diff --git a/unsupported/Eigen/src/AutoDiff/AutoDiffScalar.h b/unsupported/Eigen/src/AutoDiff/AutoDiffScalar.h
new file mode 100644
index 000000000..b833df3c0
--- /dev/null
+++ b/unsupported/Eigen/src/AutoDiff/AutoDiffScalar.h
@@ -0,0 +1,632 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra.
+//
+// Copyright (C) 2009 Gael Guennebaud <gael.guennebaud@inria.fr>
+//
+// This Source Code Form is subject to the terms of the Mozilla
+// Public License v. 2.0. If a copy of the MPL was not distributed
+// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+#ifndef EIGEN_AUTODIFF_SCALAR_H
+#define EIGEN_AUTODIFF_SCALAR_H
+
+namespace Eigen {
+
+namespace internal {
+
+template<typename A, typename B>
+struct make_coherent_impl {
+ static void run(A&, B&) {}
+};
+
+// resize a to match b is a.size()==0, and conversely.
+template<typename A, typename B>
+void make_coherent(const A& a, const B&b)
+{
+ make_coherent_impl<A,B>::run(a.const_cast_derived(), b.const_cast_derived());
+}
+
+template<typename _DerType, bool Enable> struct auto_diff_special_op;
+
+} // end namespace internal
+
+/** \class AutoDiffScalar
+ * \brief A scalar type replacement with automatic differentation capability
+ *
+ * \param _DerType the vector type used to store/represent the derivatives. The base scalar type
+ * as well as the number of derivatives to compute are determined from this type.
+ * Typical choices include, e.g., \c Vector4f for 4 derivatives, or \c VectorXf
+ * if the number of derivatives is not known at compile time, and/or, the number
+ * of derivatives is large.
+ * Note that _DerType can also be a reference (e.g., \c VectorXf&) to wrap a
+ * existing vector into an AutoDiffScalar.
+ * Finally, _DerType can also be any Eigen compatible expression.
+ *
+ * This class represents a scalar value while tracking its respective derivatives using Eigen's expression
+ * template mechanism.
+ *
+ * It supports the following list of global math function:
+ * - std::abs, std::sqrt, std::pow, std::exp, std::log, std::sin, std::cos,
+ * - internal::abs, internal::sqrt, internal::pow, internal::exp, internal::log, internal::sin, internal::cos,
+ * - internal::conj, internal::real, internal::imag, internal::abs2.
+ *
+ * AutoDiffScalar can be used as the scalar type of an Eigen::Matrix object. However,
+ * in that case, the expression template mechanism only occurs at the top Matrix level,
+ * while derivatives are computed right away.
+ *
+ */
+
+template<typename _DerType>
+class AutoDiffScalar
+ : public internal::auto_diff_special_op
+ <_DerType, !internal::is_same<typename internal::traits<typename internal::remove_all<_DerType>::type>::Scalar,
+ typename NumTraits<typename internal::traits<typename internal::remove_all<_DerType>::type>::Scalar>::Real>::value>
+{
+ public:
+ typedef internal::auto_diff_special_op
+ <_DerType, !internal::is_same<typename internal::traits<typename internal::remove_all<_DerType>::type>::Scalar,
+ typename NumTraits<typename internal::traits<typename internal::remove_all<_DerType>::type>::Scalar>::Real>::value> Base;
+ typedef typename internal::remove_all<_DerType>::type DerType;
+ typedef typename internal::traits<DerType>::Scalar Scalar;
+ typedef typename NumTraits<Scalar>::Real Real;
+
+ using Base::operator+;
+ using Base::operator*;
+
+ /** Default constructor without any initialization. */
+ AutoDiffScalar() {}
+
+ /** Constructs an active scalar from its \a value,
+ and initializes the \a nbDer derivatives such that it corresponds to the \a derNumber -th variable */
+ AutoDiffScalar(const Scalar& value, int nbDer, int derNumber)
+ : m_value(value), m_derivatives(DerType::Zero(nbDer))
+ {
+ m_derivatives.coeffRef(derNumber) = Scalar(1);
+ }
+
+ /** Conversion from a scalar constant to an active scalar.
+ * The derivatives are set to zero. */
+ /*explicit*/ AutoDiffScalar(const Real& value)
+ : m_value(value)
+ {
+ if(m_derivatives.size()>0)
+ m_derivatives.setZero();
+ }
+
+ /** Constructs an active scalar from its \a value and derivatives \a der */
+ AutoDiffScalar(const Scalar& value, const DerType& der)
+ : m_value(value), m_derivatives(der)
+ {}
+
+ template<typename OtherDerType>
+ AutoDiffScalar(const AutoDiffScalar<OtherDerType>& other)
+ : m_value(other.value()), m_derivatives(other.derivatives())
+ {}
+
+ friend std::ostream & operator << (std::ostream & s, const AutoDiffScalar& a)
+ {
+ return s << a.value();
+ }
+
+ AutoDiffScalar(const AutoDiffScalar& other)
+ : m_value(other.value()), m_derivatives(other.derivatives())
+ {}
+
+ template<typename OtherDerType>
+ inline AutoDiffScalar& operator=(const AutoDiffScalar<OtherDerType>& other)
+ {
+ m_value = other.value();
+ m_derivatives = other.derivatives();
+ return *this;
+ }
+
+ inline AutoDiffScalar& operator=(const AutoDiffScalar& other)
+ {
+ m_value = other.value();
+ m_derivatives = other.derivatives();
+ return *this;
+ }
+
+// inline operator const Scalar& () const { return m_value; }
+// inline operator Scalar& () { return m_value; }
+
+ inline const Scalar& value() const { return m_value; }
+ inline Scalar& value() { return m_value; }
+
+ inline const DerType& derivatives() const { return m_derivatives; }
+ inline DerType& derivatives() { return m_derivatives; }
+
+ inline bool operator< (const Scalar& other) const { return m_value < other; }
+ inline bool operator<=(const Scalar& other) const { return m_value <= other; }
+ inline bool operator> (const Scalar& other) const { return m_value > other; }
+ inline bool operator>=(const Scalar& other) const { return m_value >= other; }
+ inline bool operator==(const Scalar& other) const { return m_value == other; }
+ inline bool operator!=(const Scalar& other) const { return m_value != other; }
+
+ friend inline bool operator< (const Scalar& a, const AutoDiffScalar& b) { return a < b.value(); }
+ friend inline bool operator<=(const Scalar& a, const AutoDiffScalar& b) { return a <= b.value(); }
+ friend inline bool operator> (const Scalar& a, const AutoDiffScalar& b) { return a > b.value(); }
+ friend inline bool operator>=(const Scalar& a, const AutoDiffScalar& b) { return a >= b.value(); }
+ friend inline bool operator==(const Scalar& a, const AutoDiffScalar& b) { return a == b.value(); }
+ friend inline bool operator!=(const Scalar& a, const AutoDiffScalar& b) { return a != b.value(); }
+
+ template<typename OtherDerType> inline bool operator< (const AutoDiffScalar<OtherDerType>& b) const { return m_value < b.value(); }
+ template<typename OtherDerType> inline bool operator<=(const AutoDiffScalar<OtherDerType>& b) const { return m_value <= b.value(); }
+ template<typename OtherDerType> inline bool operator> (const AutoDiffScalar<OtherDerType>& b) const { return m_value > b.value(); }
+ template<typename OtherDerType> inline bool operator>=(const AutoDiffScalar<OtherDerType>& b) const { return m_value >= b.value(); }
+ template<typename OtherDerType> inline bool operator==(const AutoDiffScalar<OtherDerType>& b) const { return m_value == b.value(); }
+ template<typename OtherDerType> inline bool operator!=(const AutoDiffScalar<OtherDerType>& b) const { return m_value != b.value(); }
+
+ inline const AutoDiffScalar<DerType&> operator+(const Scalar& other) const
+ {
+ return AutoDiffScalar<DerType&>(m_value + other, m_derivatives);
+ }
+
+ friend inline const AutoDiffScalar<DerType&> operator+(const Scalar& a, const AutoDiffScalar& b)
+ {
+ return AutoDiffScalar<DerType&>(a + b.value(), b.derivatives());
+ }
+
+// inline const AutoDiffScalar<DerType&> operator+(const Real& other) const
+// {
+// return AutoDiffScalar<DerType&>(m_value + other, m_derivatives);
+// }
+
+// friend inline const AutoDiffScalar<DerType&> operator+(const Real& a, const AutoDiffScalar& b)
+// {
+// return AutoDiffScalar<DerType&>(a + b.value(), b.derivatives());
+// }
+
+ inline AutoDiffScalar& operator+=(const Scalar& other)
+ {
+ value() += other;
+ return *this;
+ }
+
+ template<typename OtherDerType>
+ inline const AutoDiffScalar<CwiseBinaryOp<internal::scalar_sum_op<Scalar>,const DerType,const typename internal::remove_all<OtherDerType>::type> >
+ operator+(const AutoDiffScalar<OtherDerType>& other) const
+ {
+ internal::make_coherent(m_derivatives, other.derivatives());
+ return AutoDiffScalar<CwiseBinaryOp<internal::scalar_sum_op<Scalar>,const DerType,const typename internal::remove_all<OtherDerType>::type> >(
+ m_value + other.value(),
+ m_derivatives + other.derivatives());
+ }
+
+ template<typename OtherDerType>
+ inline AutoDiffScalar&
+ operator+=(const AutoDiffScalar<OtherDerType>& other)
+ {
+ (*this) = (*this) + other;
+ return *this;
+ }
+
+ inline const AutoDiffScalar<DerType&> operator-(const Scalar& b) const
+ {
+ return AutoDiffScalar<DerType&>(m_value - b, m_derivatives);
+ }
+
+ friend inline const AutoDiffScalar<CwiseUnaryOp<internal::scalar_opposite_op<Scalar>, const DerType> >
+ operator-(const Scalar& a, const AutoDiffScalar& b)
+ {
+ return AutoDiffScalar<CwiseUnaryOp<internal::scalar_opposite_op<Scalar>, const DerType> >
+ (a - b.value(), -b.derivatives());
+ }
+
+ inline AutoDiffScalar& operator-=(const Scalar& other)
+ {
+ value() -= other;
+ return *this;
+ }
+
+ template<typename OtherDerType>
+ inline const AutoDiffScalar<CwiseBinaryOp<internal::scalar_difference_op<Scalar>, const DerType,const typename internal::remove_all<OtherDerType>::type> >
+ operator-(const AutoDiffScalar<OtherDerType>& other) const
+ {
+ internal::make_coherent(m_derivatives, other.derivatives());
+ return AutoDiffScalar<CwiseBinaryOp<internal::scalar_difference_op<Scalar>, const DerType,const typename internal::remove_all<OtherDerType>::type> >(
+ m_value - other.value(),
+ m_derivatives - other.derivatives());
+ }
+
+ template<typename OtherDerType>
+ inline AutoDiffScalar&
+ operator-=(const AutoDiffScalar<OtherDerType>& other)
+ {
+ *this = *this - other;
+ return *this;
+ }
+
+ inline const AutoDiffScalar<CwiseUnaryOp<internal::scalar_opposite_op<Scalar>, const DerType> >
+ operator-() const
+ {
+ return AutoDiffScalar<CwiseUnaryOp<internal::scalar_opposite_op<Scalar>, const DerType> >(
+ -m_value,
+ -m_derivatives);
+ }
+
+ inline const AutoDiffScalar<CwiseUnaryOp<internal::scalar_multiple_op<Scalar>, const DerType> >
+ operator*(const Scalar& other) const
+ {
+ return AutoDiffScalar<CwiseUnaryOp<internal::scalar_multiple_op<Scalar>, const DerType> >(
+ m_value * other,
+ (m_derivatives * other));
+ }
+
+ friend inline const AutoDiffScalar<CwiseUnaryOp<internal::scalar_multiple_op<Scalar>, const DerType> >
+ operator*(const Scalar& other, const AutoDiffScalar& a)
+ {
+ return AutoDiffScalar<CwiseUnaryOp<internal::scalar_multiple_op<Scalar>, const DerType> >(
+ a.value() * other,
+ a.derivatives() * other);
+ }
+
+// inline const AutoDiffScalar<typename CwiseUnaryOp<internal::scalar_multiple_op<Real>, DerType>::Type >
+// operator*(const Real& other) const
+// {
+// return AutoDiffScalar<typename CwiseUnaryOp<internal::scalar_multiple_op<Real>, DerType>::Type >(
+// m_value * other,
+// (m_derivatives * other));
+// }
+//
+// friend inline const AutoDiffScalar<typename CwiseUnaryOp<internal::scalar_multiple_op<Real>, DerType>::Type >
+// operator*(const Real& other, const AutoDiffScalar& a)
+// {
+// return AutoDiffScalar<typename CwiseUnaryOp<internal::scalar_multiple_op<Real>, DerType>::Type >(
+// a.value() * other,
+// a.derivatives() * other);
+// }
+
+ inline const AutoDiffScalar<CwiseUnaryOp<internal::scalar_multiple_op<Scalar>, const DerType> >
+ operator/(const Scalar& other) const
+ {
+ return AutoDiffScalar<CwiseUnaryOp<internal::scalar_multiple_op<Scalar>, const DerType> >(
+ m_value / other,
+ (m_derivatives * (Scalar(1)/other)));
+ }
+
+ friend inline const AutoDiffScalar<CwiseUnaryOp<internal::scalar_multiple_op<Scalar>, const DerType> >
+ operator/(const Scalar& other, const AutoDiffScalar& a)
+ {
+ return AutoDiffScalar<CwiseUnaryOp<internal::scalar_multiple_op<Scalar>, const DerType> >(
+ other / a.value(),
+ a.derivatives() * (Scalar(-other) / (a.value()*a.value())));
+ }
+
+// inline const AutoDiffScalar<typename CwiseUnaryOp<internal::scalar_multiple_op<Real>, DerType>::Type >
+// operator/(const Real& other) const
+// {
+// return AutoDiffScalar<typename CwiseUnaryOp<internal::scalar_multiple_op<Real>, DerType>::Type >(
+// m_value / other,
+// (m_derivatives * (Real(1)/other)));
+// }
+//
+// friend inline const AutoDiffScalar<typename CwiseUnaryOp<internal::scalar_multiple_op<Real>, DerType>::Type >
+// operator/(const Real& other, const AutoDiffScalar& a)
+// {
+// return AutoDiffScalar<typename CwiseUnaryOp<internal::scalar_multiple_op<Real>, DerType>::Type >(
+// other / a.value(),
+// a.derivatives() * (-Real(1)/other));
+// }
+
+ template<typename OtherDerType>
+ inline const AutoDiffScalar<CwiseUnaryOp<internal::scalar_multiple_op<Scalar>,
+ const CwiseBinaryOp<internal::scalar_difference_op<Scalar>,
+ const CwiseUnaryOp<internal::scalar_multiple_op<Scalar>, const DerType>,
+ const CwiseUnaryOp<internal::scalar_multiple_op<Scalar>, const typename internal::remove_all<OtherDerType>::type > > > >
+ operator/(const AutoDiffScalar<OtherDerType>& other) const
+ {
+ internal::make_coherent(m_derivatives, other.derivatives());
+ return AutoDiffScalar<CwiseUnaryOp<internal::scalar_multiple_op<Scalar>,
+ const CwiseBinaryOp<internal::scalar_difference_op<Scalar>,
+ const CwiseUnaryOp<internal::scalar_multiple_op<Scalar>, const DerType>,
+ const CwiseUnaryOp<internal::scalar_multiple_op<Scalar>, const typename internal::remove_all<OtherDerType>::type > > > >(
+ m_value / other.value(),
+ ((m_derivatives * other.value()) - (m_value * other.derivatives()))
+ * (Scalar(1)/(other.value()*other.value())));
+ }
+
+ template<typename OtherDerType>
+ inline const AutoDiffScalar<CwiseBinaryOp<internal::scalar_sum_op<Scalar>,
+ const CwiseUnaryOp<internal::scalar_multiple_op<Scalar>, const DerType>,
+ const CwiseUnaryOp<internal::scalar_multiple_op<Scalar>, const typename internal::remove_all<OtherDerType>::type> > >
+ operator*(const AutoDiffScalar<OtherDerType>& other) const
+ {
+ internal::make_coherent(m_derivatives, other.derivatives());
+ return AutoDiffScalar<const CwiseBinaryOp<internal::scalar_sum_op<Scalar>,
+ const CwiseUnaryOp<internal::scalar_multiple_op<Scalar>, const DerType>,
+ const CwiseUnaryOp<internal::scalar_multiple_op<Scalar>, const typename internal::remove_all<OtherDerType>::type > > >(
+ m_value * other.value(),
+ (m_derivatives * other.value()) + (m_value * other.derivatives()));
+ }
+
+ inline AutoDiffScalar& operator*=(const Scalar& other)
+ {
+ *this = *this * other;
+ return *this;
+ }
+
+ template<typename OtherDerType>
+ inline AutoDiffScalar& operator*=(const AutoDiffScalar<OtherDerType>& other)
+ {
+ *this = *this * other;
+ return *this;
+ }
+
+ inline AutoDiffScalar& operator/=(const Scalar& other)
+ {
+ *this = *this / other;
+ return *this;
+ }
+
+ template<typename OtherDerType>
+ inline AutoDiffScalar& operator/=(const AutoDiffScalar<OtherDerType>& other)
+ {
+ *this = *this / other;
+ return *this;
+ }
+
+ protected:
+ Scalar m_value;
+ DerType m_derivatives;
+
+};
+
+namespace internal {
+
+template<typename _DerType>
+struct auto_diff_special_op<_DerType, true>
+// : auto_diff_scalar_op<_DerType, typename NumTraits<Scalar>::Real,
+// is_same<Scalar,typename NumTraits<Scalar>::Real>::value>
+{
+ typedef typename remove_all<_DerType>::type DerType;
+ typedef typename traits<DerType>::Scalar Scalar;
+ typedef typename NumTraits<Scalar>::Real Real;
+
+// typedef auto_diff_scalar_op<_DerType, typename NumTraits<Scalar>::Real,
+// is_same<Scalar,typename NumTraits<Scalar>::Real>::value> Base;
+
+// using Base::operator+;
+// using Base::operator+=;
+// using Base::operator-;
+// using Base::operator-=;
+// using Base::operator*;
+// using Base::operator*=;
+
+ const AutoDiffScalar<_DerType>& derived() const { return *static_cast<const AutoDiffScalar<_DerType>*>(this); }
+ AutoDiffScalar<_DerType>& derived() { return *static_cast<AutoDiffScalar<_DerType>*>(this); }
+
+
+ inline const AutoDiffScalar<DerType&> operator+(const Real& other) const
+ {
+ return AutoDiffScalar<DerType&>(derived().value() + other, derived().derivatives());
+ }
+
+ friend inline const AutoDiffScalar<DerType&> operator+(const Real& a, const AutoDiffScalar<_DerType>& b)
+ {
+ return AutoDiffScalar<DerType&>(a + b.value(), b.derivatives());
+ }
+
+ inline AutoDiffScalar<_DerType>& operator+=(const Real& other)
+ {
+ derived().value() += other;
+ return derived();
+ }
+
+
+ inline const AutoDiffScalar<typename CwiseUnaryOp<scalar_multiple2_op<Scalar,Real>, DerType>::Type >
+ operator*(const Real& other) const
+ {
+ return AutoDiffScalar<typename CwiseUnaryOp<scalar_multiple2_op<Scalar,Real>, DerType>::Type >(
+ derived().value() * other,
+ derived().derivatives() * other);
+ }
+
+ friend inline const AutoDiffScalar<typename CwiseUnaryOp<scalar_multiple2_op<Scalar,Real>, DerType>::Type >
+ operator*(const Real& other, const AutoDiffScalar<_DerType>& a)
+ {
+ return AutoDiffScalar<typename CwiseUnaryOp<scalar_multiple2_op<Scalar,Real>, DerType>::Type >(
+ a.value() * other,
+ a.derivatives() * other);
+ }
+
+ inline AutoDiffScalar<_DerType>& operator*=(const Scalar& other)
+ {
+ *this = *this * other;
+ return derived();
+ }
+};
+
+template<typename _DerType>
+struct auto_diff_special_op<_DerType, false>
+{
+ void operator*() const;
+ void operator-() const;
+ void operator+() const;
+};
+
+template<typename A_Scalar, int A_Rows, int A_Cols, int A_Options, int A_MaxRows, int A_MaxCols, typename B>
+struct make_coherent_impl<Matrix<A_Scalar, A_Rows, A_Cols, A_Options, A_MaxRows, A_MaxCols>, B> {
+ typedef Matrix<A_Scalar, A_Rows, A_Cols, A_Options, A_MaxRows, A_MaxCols> A;
+ static void run(A& a, B& b) {
+ if((A_Rows==Dynamic || A_Cols==Dynamic) && (a.size()==0))
+ {
+ a.resize(b.size());
+ a.setZero();
+ }
+ }
+};
+
+template<typename A, typename B_Scalar, int B_Rows, int B_Cols, int B_Options, int B_MaxRows, int B_MaxCols>
+struct make_coherent_impl<A, Matrix<B_Scalar, B_Rows, B_Cols, B_Options, B_MaxRows, B_MaxCols> > {
+ typedef Matrix<B_Scalar, B_Rows, B_Cols, B_Options, B_MaxRows, B_MaxCols> B;
+ static void run(A& a, B& b) {
+ if((B_Rows==Dynamic || B_Cols==Dynamic) && (b.size()==0))
+ {
+ b.resize(a.size());
+ b.setZero();
+ }
+ }
+};
+
+template<typename A_Scalar, int A_Rows, int A_Cols, int A_Options, int A_MaxRows, int A_MaxCols,
+ typename B_Scalar, int B_Rows, int B_Cols, int B_Options, int B_MaxRows, int B_MaxCols>
+struct make_coherent_impl<Matrix<A_Scalar, A_Rows, A_Cols, A_Options, A_MaxRows, A_MaxCols>,
+ Matrix<B_Scalar, B_Rows, B_Cols, B_Options, B_MaxRows, B_MaxCols> > {
+ typedef Matrix<A_Scalar, A_Rows, A_Cols, A_Options, A_MaxRows, A_MaxCols> A;
+ typedef Matrix<B_Scalar, B_Rows, B_Cols, B_Options, B_MaxRows, B_MaxCols> B;
+ static void run(A& a, B& b) {
+ if((A_Rows==Dynamic || A_Cols==Dynamic) && (a.size()==0))
+ {
+ a.resize(b.size());
+ a.setZero();
+ }
+ else if((B_Rows==Dynamic || B_Cols==Dynamic) && (b.size()==0))
+ {
+ b.resize(a.size());
+ b.setZero();
+ }
+ }
+};
+
+template<typename A_Scalar, int A_Rows, int A_Cols, int A_Options, int A_MaxRows, int A_MaxCols> struct scalar_product_traits<Matrix<A_Scalar, A_Rows, A_Cols, A_Options, A_MaxRows, A_MaxCols>,A_Scalar>
+{
+ typedef Matrix<A_Scalar, A_Rows, A_Cols, A_Options, A_MaxRows, A_MaxCols> ReturnType;
+};
+
+template<typename A_Scalar, int A_Rows, int A_Cols, int A_Options, int A_MaxRows, int A_MaxCols> struct scalar_product_traits<A_Scalar, Matrix<A_Scalar, A_Rows, A_Cols, A_Options, A_MaxRows, A_MaxCols> >
+{
+ typedef Matrix<A_Scalar, A_Rows, A_Cols, A_Options, A_MaxRows, A_MaxCols> ReturnType;
+};
+
+template<typename DerType>
+struct scalar_product_traits<AutoDiffScalar<DerType>,typename DerType::Scalar>
+{
+ typedef AutoDiffScalar<DerType> ReturnType;
+};
+
+} // end namespace internal
+
+#define EIGEN_AUTODIFF_DECLARE_GLOBAL_UNARY(FUNC,CODE) \
+ template<typename DerType> \
+ inline const Eigen::AutoDiffScalar<Eigen::CwiseUnaryOp<Eigen::internal::scalar_multiple_op<typename Eigen::internal::traits<typename Eigen::internal::remove_all<DerType>::type>::Scalar>, const typename Eigen::internal::remove_all<DerType>::type> > \
+ FUNC(const Eigen::AutoDiffScalar<DerType>& x) { \
+ using namespace Eigen; \
+ typedef typename Eigen::internal::traits<typename Eigen::internal::remove_all<DerType>::type>::Scalar Scalar; \
+ typedef AutoDiffScalar<CwiseUnaryOp<Eigen::internal::scalar_multiple_op<Scalar>, const typename Eigen::internal::remove_all<DerType>::type> > ReturnType; \
+ CODE; \
+ }
+
+template<typename DerType>
+inline const AutoDiffScalar<DerType>& conj(const AutoDiffScalar<DerType>& x) { return x; }
+template<typename DerType>
+inline const AutoDiffScalar<DerType>& real(const AutoDiffScalar<DerType>& x) { return x; }
+template<typename DerType>
+inline typename DerType::Scalar imag(const AutoDiffScalar<DerType>&) { return 0.; }
+template<typename DerType, typename T>
+inline AutoDiffScalar<DerType> (min)(const AutoDiffScalar<DerType>& x, const T& y) { return (x <= y ? x : y); }
+template<typename DerType, typename T>
+inline AutoDiffScalar<DerType> (max)(const AutoDiffScalar<DerType>& x, const T& y) { return (x >= y ? x : y); }
+template<typename DerType, typename T>
+inline AutoDiffScalar<DerType> (min)(const T& x, const AutoDiffScalar<DerType>& y) { return (x < y ? x : y); }
+template<typename DerType, typename T>
+inline AutoDiffScalar<DerType> (max)(const T& x, const AutoDiffScalar<DerType>& y) { return (x > y ? x : y); }
+
+#define sign(x) x >= 0 ? 1 : -1 // required for abs function below
+
+EIGEN_AUTODIFF_DECLARE_GLOBAL_UNARY(abs,
+ using std::abs;
+ return ReturnType(abs(x.value()), x.derivatives() * (sign(x.value())));)
+
+EIGEN_AUTODIFF_DECLARE_GLOBAL_UNARY(abs2,
+ using internal::abs2;
+ return ReturnType(abs2(x.value()), x.derivatives() * (Scalar(2)*x.value()));)
+
+EIGEN_AUTODIFF_DECLARE_GLOBAL_UNARY(sqrt,
+ using std::sqrt;
+ Scalar sqrtx = sqrt(x.value());
+ return ReturnType(sqrtx,x.derivatives() * (Scalar(0.5) / sqrtx));)
+
+EIGEN_AUTODIFF_DECLARE_GLOBAL_UNARY(cos,
+ using std::cos;
+ using std::sin;
+ return ReturnType(cos(x.value()), x.derivatives() * (-sin(x.value())));)
+
+EIGEN_AUTODIFF_DECLARE_GLOBAL_UNARY(sin,
+ using std::sin;
+ using std::cos;
+ return ReturnType(sin(x.value()),x.derivatives() * cos(x.value()));)
+
+EIGEN_AUTODIFF_DECLARE_GLOBAL_UNARY(exp,
+ using std::exp;
+ Scalar expx = exp(x.value());
+ return ReturnType(expx,x.derivatives() * expx);)
+
+EIGEN_AUTODIFF_DECLARE_GLOBAL_UNARY(log,
+ using std::log;
+ return ReturnType(log(x.value()),x.derivatives() * (Scalar(1)/x.value()));)
+
+template<typename DerType>
+inline const Eigen::AutoDiffScalar<Eigen::CwiseUnaryOp<Eigen::internal::scalar_multiple_op<typename Eigen::internal::traits<DerType>::Scalar>, const DerType> >
+pow(const Eigen::AutoDiffScalar<DerType>& x, typename Eigen::internal::traits<DerType>::Scalar y)
+{
+ using namespace Eigen;
+ typedef typename Eigen::internal::traits<DerType>::Scalar Scalar;
+ return AutoDiffScalar<CwiseUnaryOp<Eigen::internal::scalar_multiple_op<Scalar>, const DerType> >(
+ std::pow(x.value(),y),
+ x.derivatives() * (y * std::pow(x.value(),y-1)));
+}
+
+
+template<typename DerTypeA,typename DerTypeB>
+inline const AutoDiffScalar<Matrix<typename internal::traits<DerTypeA>::Scalar,Dynamic,1> >
+atan2(const AutoDiffScalar<DerTypeA>& a, const AutoDiffScalar<DerTypeB>& b)
+{
+ using std::atan2;
+ using std::max;
+ typedef typename internal::traits<DerTypeA>::Scalar Scalar;
+ typedef AutoDiffScalar<Matrix<Scalar,Dynamic,1> > PlainADS;
+ PlainADS ret;
+ ret.value() = atan2(a.value(), b.value());
+
+ Scalar tmp2 = a.value() * a.value();
+ Scalar tmp3 = b.value() * b.value();
+ Scalar tmp4 = tmp3/(tmp2+tmp3);
+
+ if (tmp4!=0)
+ ret.derivatives() = (a.derivatives() * b.value() - a.value() * b.derivatives()) * (tmp2+tmp3);
+
+ return ret;
+}
+
+EIGEN_AUTODIFF_DECLARE_GLOBAL_UNARY(tan,
+ using std::tan;
+ using std::cos;
+ return ReturnType(tan(x.value()),x.derivatives() * (Scalar(1)/internal::abs2(cos(x.value()))));)
+
+EIGEN_AUTODIFF_DECLARE_GLOBAL_UNARY(asin,
+ using std::sqrt;
+ using std::asin;
+ return ReturnType(asin(x.value()),x.derivatives() * (Scalar(1)/sqrt(1-internal::abs2(x.value()))));)
+
+EIGEN_AUTODIFF_DECLARE_GLOBAL_UNARY(acos,
+ using std::sqrt;
+ using std::acos;
+ return ReturnType(acos(x.value()),x.derivatives() * (Scalar(-1)/sqrt(1-internal::abs2(x.value()))));)
+
+#undef EIGEN_AUTODIFF_DECLARE_GLOBAL_UNARY
+
+template<typename DerType> struct NumTraits<AutoDiffScalar<DerType> >
+ : NumTraits< typename NumTraits<typename DerType::Scalar>::Real >
+{
+ typedef AutoDiffScalar<Matrix<typename NumTraits<typename DerType::Scalar>::Real,DerType::RowsAtCompileTime,DerType::ColsAtCompileTime> > Real;
+ typedef AutoDiffScalar<DerType> NonInteger;
+ typedef AutoDiffScalar<DerType>& Nested;
+ enum{
+ RequireInitialization = 1
+ };
+};
+
+}
+
+#endif // EIGEN_AUTODIFF_SCALAR_H
diff --git a/unsupported/Eigen/src/AutoDiff/AutoDiffVector.h b/unsupported/Eigen/src/AutoDiff/AutoDiffVector.h
new file mode 100644
index 000000000..0540add0a
--- /dev/null
+++ b/unsupported/Eigen/src/AutoDiff/AutoDiffVector.h
@@ -0,0 +1,220 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra.
+//
+// Copyright (C) 2009 Gael Guennebaud <gael.guennebaud@inria.fr>
+//
+// This Source Code Form is subject to the terms of the Mozilla
+// Public License v. 2.0. If a copy of the MPL was not distributed
+// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+#ifndef EIGEN_AUTODIFF_VECTOR_H
+#define EIGEN_AUTODIFF_VECTOR_H
+
+namespace Eigen {
+
+/* \class AutoDiffScalar
+ * \brief A scalar type replacement with automatic differentation capability
+ *
+ * \param DerType the vector type used to store/represent the derivatives (e.g. Vector3f)
+ *
+ * This class represents a scalar value while tracking its respective derivatives.
+ *
+ * It supports the following list of global math function:
+ * - std::abs, std::sqrt, std::pow, std::exp, std::log, std::sin, std::cos,
+ * - internal::abs, internal::sqrt, internal::pow, internal::exp, internal::log, internal::sin, internal::cos,
+ * - internal::conj, internal::real, internal::imag, internal::abs2.
+ *
+ * AutoDiffScalar can be used as the scalar type of an Eigen::Matrix object. However,
+ * in that case, the expression template mechanism only occurs at the top Matrix level,
+ * while derivatives are computed right away.
+ *
+ */
+template<typename ValueType, typename JacobianType>
+class AutoDiffVector
+{
+ public:
+ //typedef typename internal::traits<ValueType>::Scalar Scalar;
+ typedef typename internal::traits<ValueType>::Scalar BaseScalar;
+ typedef AutoDiffScalar<Matrix<BaseScalar,JacobianType::RowsAtCompileTime,1> > ActiveScalar;
+ typedef ActiveScalar Scalar;
+ typedef AutoDiffScalar<typename JacobianType::ColXpr> CoeffType;
+ typedef typename JacobianType::Index Index;
+
+ inline AutoDiffVector() {}
+
+ inline AutoDiffVector(const ValueType& values)
+ : m_values(values)
+ {
+ m_jacobian.setZero();
+ }
+
+
+ CoeffType operator[] (Index i) { return CoeffType(m_values[i], m_jacobian.col(i)); }
+ const CoeffType operator[] (Index i) const { return CoeffType(m_values[i], m_jacobian.col(i)); }
+
+ CoeffType operator() (Index i) { return CoeffType(m_values[i], m_jacobian.col(i)); }
+ const CoeffType operator() (Index i) const { return CoeffType(m_values[i], m_jacobian.col(i)); }
+
+ CoeffType coeffRef(Index i) { return CoeffType(m_values[i], m_jacobian.col(i)); }
+ const CoeffType coeffRef(Index i) const { return CoeffType(m_values[i], m_jacobian.col(i)); }
+
+ Index size() const { return m_values.size(); }
+
+ // FIXME here we could return an expression of the sum
+ Scalar sum() const { /*std::cerr << "sum \n\n";*/ /*std::cerr << m_jacobian.rowwise().sum() << "\n\n";*/ return Scalar(m_values.sum(), m_jacobian.rowwise().sum()); }
+
+
+ inline AutoDiffVector(const ValueType& values, const JacobianType& jac)
+ : m_values(values), m_jacobian(jac)
+ {}
+
+ template<typename OtherValueType, typename OtherJacobianType>
+ inline AutoDiffVector(const AutoDiffVector<OtherValueType, OtherJacobianType>& other)
+ : m_values(other.values()), m_jacobian(other.jacobian())
+ {}
+
+ inline AutoDiffVector(const AutoDiffVector& other)
+ : m_values(other.values()), m_jacobian(other.jacobian())
+ {}
+
+ template<typename OtherValueType, typename OtherJacobianType>
+ inline AutoDiffVector& operator=(const AutoDiffVector<OtherValueType, OtherJacobianType>& other)
+ {
+ m_values = other.values();
+ m_jacobian = other.jacobian();
+ return *this;
+ }
+
+ inline AutoDiffVector& operator=(const AutoDiffVector& other)
+ {
+ m_values = other.values();
+ m_jacobian = other.jacobian();
+ return *this;
+ }
+
+ inline const ValueType& values() const { return m_values; }
+ inline ValueType& values() { return m_values; }
+
+ inline const JacobianType& jacobian() const { return m_jacobian; }
+ inline JacobianType& jacobian() { return m_jacobian; }
+
+ template<typename OtherValueType,typename OtherJacobianType>
+ inline const AutoDiffVector<
+ typename MakeCwiseBinaryOp<internal::scalar_sum_op<BaseScalar>,ValueType,OtherValueType>::Type,
+ typename MakeCwiseBinaryOp<internal::scalar_sum_op<BaseScalar>,JacobianType,OtherJacobianType>::Type >
+ operator+(const AutoDiffVector<OtherValueType,OtherJacobianType>& other) const
+ {
+ return AutoDiffVector<
+ typename MakeCwiseBinaryOp<internal::scalar_sum_op<BaseScalar>,ValueType,OtherValueType>::Type,
+ typename MakeCwiseBinaryOp<internal::scalar_sum_op<BaseScalar>,JacobianType,OtherJacobianType>::Type >(
+ m_values + other.values(),
+ m_jacobian + other.jacobian());
+ }
+
+ template<typename OtherValueType, typename OtherJacobianType>
+ inline AutoDiffVector&
+ operator+=(const AutoDiffVector<OtherValueType,OtherJacobianType>& other)
+ {
+ m_values += other.values();
+ m_jacobian += other.jacobian();
+ return *this;
+ }
+
+ template<typename OtherValueType,typename OtherJacobianType>
+ inline const AutoDiffVector<
+ typename MakeCwiseBinaryOp<internal::scalar_difference_op<Scalar>,ValueType,OtherValueType>::Type,
+ typename MakeCwiseBinaryOp<internal::scalar_difference_op<Scalar>,JacobianType,OtherJacobianType>::Type >
+ operator-(const AutoDiffVector<OtherValueType,OtherJacobianType>& other) const
+ {
+ return AutoDiffVector<
+ typename MakeCwiseBinaryOp<internal::scalar_difference_op<Scalar>,ValueType,OtherValueType>::Type,
+ typename MakeCwiseBinaryOp<internal::scalar_difference_op<Scalar>,JacobianType,OtherJacobianType>::Type >(
+ m_values - other.values(),
+ m_jacobian - other.jacobian());
+ }
+
+ template<typename OtherValueType, typename OtherJacobianType>
+ inline AutoDiffVector&
+ operator-=(const AutoDiffVector<OtherValueType,OtherJacobianType>& other)
+ {
+ m_values -= other.values();
+ m_jacobian -= other.jacobian();
+ return *this;
+ }
+
+ inline const AutoDiffVector<
+ typename MakeCwiseUnaryOp<internal::scalar_opposite_op<Scalar>, ValueType>::Type,
+ typename MakeCwiseUnaryOp<internal::scalar_opposite_op<Scalar>, JacobianType>::Type >
+ operator-() const
+ {
+ return AutoDiffVector<
+ typename MakeCwiseUnaryOp<internal::scalar_opposite_op<Scalar>, ValueType>::Type,
+ typename MakeCwiseUnaryOp<internal::scalar_opposite_op<Scalar>, JacobianType>::Type >(
+ -m_values,
+ -m_jacobian);
+ }
+
+ inline const AutoDiffVector<
+ typename MakeCwiseUnaryOp<internal::scalar_multiple_op<Scalar>, ValueType>::Type,
+ typename MakeCwiseUnaryOp<internal::scalar_multiple_op<Scalar>, JacobianType>::Type>
+ operator*(const BaseScalar& other) const
+ {
+ return AutoDiffVector<
+ typename MakeCwiseUnaryOp<internal::scalar_multiple_op<Scalar>, ValueType>::Type,
+ typename MakeCwiseUnaryOp<internal::scalar_multiple_op<Scalar>, JacobianType>::Type >(
+ m_values * other,
+ m_jacobian * other);
+ }
+
+ friend inline const AutoDiffVector<
+ typename MakeCwiseUnaryOp<internal::scalar_multiple_op<Scalar>, ValueType>::Type,
+ typename MakeCwiseUnaryOp<internal::scalar_multiple_op<Scalar>, JacobianType>::Type >
+ operator*(const Scalar& other, const AutoDiffVector& v)
+ {
+ return AutoDiffVector<
+ typename MakeCwiseUnaryOp<internal::scalar_multiple_op<Scalar>, ValueType>::Type,
+ typename MakeCwiseUnaryOp<internal::scalar_multiple_op<Scalar>, JacobianType>::Type >(
+ v.values() * other,
+ v.jacobian() * other);
+ }
+
+// template<typename OtherValueType,typename OtherJacobianType>
+// inline const AutoDiffVector<
+// CwiseBinaryOp<internal::scalar_multiple_op<Scalar>, ValueType, OtherValueType>
+// CwiseBinaryOp<internal::scalar_sum_op<Scalar>,
+// CwiseUnaryOp<internal::scalar_multiple_op<Scalar>, JacobianType>,
+// CwiseUnaryOp<internal::scalar_multiple_op<Scalar>, OtherJacobianType> > >
+// operator*(const AutoDiffVector<OtherValueType,OtherJacobianType>& other) const
+// {
+// return AutoDiffVector<
+// CwiseBinaryOp<internal::scalar_multiple_op<Scalar>, ValueType, OtherValueType>
+// CwiseBinaryOp<internal::scalar_sum_op<Scalar>,
+// CwiseUnaryOp<internal::scalar_multiple_op<Scalar>, JacobianType>,
+// CwiseUnaryOp<internal::scalar_multiple_op<Scalar>, OtherJacobianType> > >(
+// m_values.cwise() * other.values(),
+// (m_jacobian * other.values()) + (m_values * other.jacobian()));
+// }
+
+ inline AutoDiffVector& operator*=(const Scalar& other)
+ {
+ m_values *= other;
+ m_jacobian *= other;
+ return *this;
+ }
+
+ template<typename OtherValueType,typename OtherJacobianType>
+ inline AutoDiffVector& operator*=(const AutoDiffVector<OtherValueType,OtherJacobianType>& other)
+ {
+ *this = *this * other;
+ return *this;
+ }
+
+ protected:
+ ValueType m_values;
+ JacobianType m_jacobian;
+
+};
+
+}
+
+#endif // EIGEN_AUTODIFF_VECTOR_H
diff --git a/unsupported/Eigen/src/AutoDiff/CMakeLists.txt b/unsupported/Eigen/src/AutoDiff/CMakeLists.txt
new file mode 100644
index 000000000..ad91fd9c4
--- /dev/null
+++ b/unsupported/Eigen/src/AutoDiff/CMakeLists.txt
@@ -0,0 +1,6 @@
+FILE(GLOB Eigen_AutoDiff_SRCS "*.h")
+
+INSTALL(FILES
+ ${Eigen_AutoDiff_SRCS}
+ DESTINATION ${INCLUDE_INSTALL_DIR}/unsupported/Eigen/src/AutoDiff COMPONENT Devel
+ )
diff --git a/unsupported/Eigen/src/BVH/BVAlgorithms.h b/unsupported/Eigen/src/BVH/BVAlgorithms.h
new file mode 100644
index 000000000..e5b51decb
--- /dev/null
+++ b/unsupported/Eigen/src/BVH/BVAlgorithms.h
@@ -0,0 +1,293 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra.
+//
+// Copyright (C) 2009 Ilya Baran <ibaran@mit.edu>
+//
+// This Source Code Form is subject to the terms of the Mozilla
+// Public License v. 2.0. If a copy of the MPL was not distributed
+// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+#ifndef EIGEN_BVALGORITHMS_H
+#define EIGEN_BVALGORITHMS_H
+
+namespace Eigen {
+
+namespace internal {
+
+#ifndef EIGEN_PARSED_BY_DOXYGEN
+template<typename BVH, typename Intersector>
+bool intersect_helper(const BVH &tree, Intersector &intersector, typename BVH::Index root)
+{
+ typedef typename BVH::Index Index;
+ typedef typename BVH::VolumeIterator VolIter;
+ typedef typename BVH::ObjectIterator ObjIter;
+
+ VolIter vBegin = VolIter(), vEnd = VolIter();
+ ObjIter oBegin = ObjIter(), oEnd = ObjIter();
+
+ std::vector<Index> todo(1, root);
+
+ while(!todo.empty()) {
+ tree.getChildren(todo.back(), vBegin, vEnd, oBegin, oEnd);
+ todo.pop_back();
+
+ for(; vBegin != vEnd; ++vBegin) //go through child volumes
+ if(intersector.intersectVolume(tree.getVolume(*vBegin)))
+ todo.push_back(*vBegin);
+
+ for(; oBegin != oEnd; ++oBegin) //go through child objects
+ if(intersector.intersectObject(*oBegin))
+ return true; //intersector said to stop query
+ }
+ return false;
+}
+#endif //not EIGEN_PARSED_BY_DOXYGEN
+
+template<typename Volume1, typename Object1, typename Object2, typename Intersector>
+struct intersector_helper1
+{
+ intersector_helper1(const Object2 &inStored, Intersector &in) : stored(inStored), intersector(in) {}
+ bool intersectVolume(const Volume1 &vol) { return intersector.intersectVolumeObject(vol, stored); }
+ bool intersectObject(const Object1 &obj) { return intersector.intersectObjectObject(obj, stored); }
+ Object2 stored;
+ Intersector &intersector;
+private:
+ intersector_helper1& operator=(const intersector_helper1&);
+};
+
+template<typename Volume2, typename Object2, typename Object1, typename Intersector>
+struct intersector_helper2
+{
+ intersector_helper2(const Object1 &inStored, Intersector &in) : stored(inStored), intersector(in) {}
+ bool intersectVolume(const Volume2 &vol) { return intersector.intersectObjectVolume(stored, vol); }
+ bool intersectObject(const Object2 &obj) { return intersector.intersectObjectObject(stored, obj); }
+ Object1 stored;
+ Intersector &intersector;
+private:
+ intersector_helper2& operator=(const intersector_helper2&);
+};
+
+} // end namespace internal
+
+/** Given a BVH, runs the query encapsulated by \a intersector.
+ * The Intersector type must provide the following members: \code
+ bool intersectVolume(const BVH::Volume &volume) //returns true if volume intersects the query
+ bool intersectObject(const BVH::Object &object) //returns true if the search should terminate immediately
+ \endcode
+ */
+template<typename BVH, typename Intersector>
+void BVIntersect(const BVH &tree, Intersector &intersector)
+{
+ internal::intersect_helper(tree, intersector, tree.getRootIndex());
+}
+
+/** Given two BVH's, runs the query on their Cartesian product encapsulated by \a intersector.
+ * The Intersector type must provide the following members: \code
+ bool intersectVolumeVolume(const BVH1::Volume &v1, const BVH2::Volume &v2) //returns true if product of volumes intersects the query
+ bool intersectVolumeObject(const BVH1::Volume &v1, const BVH2::Object &o2) //returns true if the volume-object product intersects the query
+ bool intersectObjectVolume(const BVH1::Object &o1, const BVH2::Volume &v2) //returns true if the volume-object product intersects the query
+ bool intersectObjectObject(const BVH1::Object &o1, const BVH2::Object &o2) //returns true if the search should terminate immediately
+ \endcode
+ */
+template<typename BVH1, typename BVH2, typename Intersector>
+void BVIntersect(const BVH1 &tree1, const BVH2 &tree2, Intersector &intersector) //TODO: tandem descent when it makes sense
+{
+ typedef typename BVH1::Index Index1;
+ typedef typename BVH2::Index Index2;
+ typedef internal::intersector_helper1<typename BVH1::Volume, typename BVH1::Object, typename BVH2::Object, Intersector> Helper1;
+ typedef internal::intersector_helper2<typename BVH2::Volume, typename BVH2::Object, typename BVH1::Object, Intersector> Helper2;
+ typedef typename BVH1::VolumeIterator VolIter1;
+ typedef typename BVH1::ObjectIterator ObjIter1;
+ typedef typename BVH2::VolumeIterator VolIter2;
+ typedef typename BVH2::ObjectIterator ObjIter2;
+
+ VolIter1 vBegin1 = VolIter1(), vEnd1 = VolIter1();
+ ObjIter1 oBegin1 = ObjIter1(), oEnd1 = ObjIter1();
+ VolIter2 vBegin2 = VolIter2(), vEnd2 = VolIter2(), vCur2 = VolIter2();
+ ObjIter2 oBegin2 = ObjIter2(), oEnd2 = ObjIter2(), oCur2 = ObjIter2();
+
+ std::vector<std::pair<Index1, Index2> > todo(1, std::make_pair(tree1.getRootIndex(), tree2.getRootIndex()));
+
+ while(!todo.empty()) {
+ tree1.getChildren(todo.back().first, vBegin1, vEnd1, oBegin1, oEnd1);
+ tree2.getChildren(todo.back().second, vBegin2, vEnd2, oBegin2, oEnd2);
+ todo.pop_back();
+
+ for(; vBegin1 != vEnd1; ++vBegin1) { //go through child volumes of first tree
+ const typename BVH1::Volume &vol1 = tree1.getVolume(*vBegin1);
+ for(vCur2 = vBegin2; vCur2 != vEnd2; ++vCur2) { //go through child volumes of second tree
+ if(intersector.intersectVolumeVolume(vol1, tree2.getVolume(*vCur2)))
+ todo.push_back(std::make_pair(*vBegin1, *vCur2));
+ }
+
+ for(oCur2 = oBegin2; oCur2 != oEnd2; ++oCur2) {//go through child objects of second tree
+ Helper1 helper(*oCur2, intersector);
+ if(internal::intersect_helper(tree1, helper, *vBegin1))
+ return; //intersector said to stop query
+ }
+ }
+
+ for(; oBegin1 != oEnd1; ++oBegin1) { //go through child objects of first tree
+ for(vCur2 = vBegin2; vCur2 != vEnd2; ++vCur2) { //go through child volumes of second tree
+ Helper2 helper(*oBegin1, intersector);
+ if(internal::intersect_helper(tree2, helper, *vCur2))
+ return; //intersector said to stop query
+ }
+
+ for(oCur2 = oBegin2; oCur2 != oEnd2; ++oCur2) {//go through child objects of second tree
+ if(intersector.intersectObjectObject(*oBegin1, *oCur2))
+ return; //intersector said to stop query
+ }
+ }
+ }
+}
+
+namespace internal {
+
+#ifndef EIGEN_PARSED_BY_DOXYGEN
+template<typename BVH, typename Minimizer>
+typename Minimizer::Scalar minimize_helper(const BVH &tree, Minimizer &minimizer, typename BVH::Index root, typename Minimizer::Scalar minimum)
+{
+ typedef typename Minimizer::Scalar Scalar;
+ typedef typename BVH::Index Index;
+ typedef std::pair<Scalar, Index> QueueElement; //first element is priority
+ typedef typename BVH::VolumeIterator VolIter;
+ typedef typename BVH::ObjectIterator ObjIter;
+
+ VolIter vBegin = VolIter(), vEnd = VolIter();
+ ObjIter oBegin = ObjIter(), oEnd = ObjIter();
+ std::priority_queue<QueueElement, std::vector<QueueElement>, std::greater<QueueElement> > todo; //smallest is at the top
+
+ todo.push(std::make_pair(Scalar(), root));
+
+ while(!todo.empty()) {
+ tree.getChildren(todo.top().second, vBegin, vEnd, oBegin, oEnd);
+ todo.pop();
+
+ for(; oBegin != oEnd; ++oBegin) //go through child objects
+ minimum = (std::min)(minimum, minimizer.minimumOnObject(*oBegin));
+
+ for(; vBegin != vEnd; ++vBegin) { //go through child volumes
+ Scalar val = minimizer.minimumOnVolume(tree.getVolume(*vBegin));
+ if(val < minimum)
+ todo.push(std::make_pair(val, *vBegin));
+ }
+ }
+
+ return minimum;
+}
+#endif //not EIGEN_PARSED_BY_DOXYGEN
+
+
+template<typename Volume1, typename Object1, typename Object2, typename Minimizer>
+struct minimizer_helper1
+{
+ typedef typename Minimizer::Scalar Scalar;
+ minimizer_helper1(const Object2 &inStored, Minimizer &m) : stored(inStored), minimizer(m) {}
+ Scalar minimumOnVolume(const Volume1 &vol) { return minimizer.minimumOnVolumeObject(vol, stored); }
+ Scalar minimumOnObject(const Object1 &obj) { return minimizer.minimumOnObjectObject(obj, stored); }
+ Object2 stored;
+ Minimizer &minimizer;
+private:
+ minimizer_helper1& operator=(const minimizer_helper1&) {}
+};
+
+template<typename Volume2, typename Object2, typename Object1, typename Minimizer>
+struct minimizer_helper2
+{
+ typedef typename Minimizer::Scalar Scalar;
+ minimizer_helper2(const Object1 &inStored, Minimizer &m) : stored(inStored), minimizer(m) {}
+ Scalar minimumOnVolume(const Volume2 &vol) { return minimizer.minimumOnObjectVolume(stored, vol); }
+ Scalar minimumOnObject(const Object2 &obj) { return minimizer.minimumOnObjectObject(stored, obj); }
+ Object1 stored;
+ Minimizer &minimizer;
+private:
+ minimizer_helper2& operator=(const minimizer_helper2&);
+};
+
+} // end namespace internal
+
+/** Given a BVH, runs the query encapsulated by \a minimizer.
+ * \returns the minimum value.
+ * The Minimizer type must provide the following members: \code
+ typedef Scalar //the numeric type of what is being minimized--not necessarily the Scalar type of the BVH (if it has one)
+ Scalar minimumOnVolume(const BVH::Volume &volume)
+ Scalar minimumOnObject(const BVH::Object &object)
+ \endcode
+ */
+template<typename BVH, typename Minimizer>
+typename Minimizer::Scalar BVMinimize(const BVH &tree, Minimizer &minimizer)
+{
+ return internal::minimize_helper(tree, minimizer, tree.getRootIndex(), (std::numeric_limits<typename Minimizer::Scalar>::max)());
+}
+
+/** Given two BVH's, runs the query on their cartesian product encapsulated by \a minimizer.
+ * \returns the minimum value.
+ * The Minimizer type must provide the following members: \code
+ typedef Scalar //the numeric type of what is being minimized--not necessarily the Scalar type of the BVH (if it has one)
+ Scalar minimumOnVolumeVolume(const BVH1::Volume &v1, const BVH2::Volume &v2)
+ Scalar minimumOnVolumeObject(const BVH1::Volume &v1, const BVH2::Object &o2)
+ Scalar minimumOnObjectVolume(const BVH1::Object &o1, const BVH2::Volume &v2)
+ Scalar minimumOnObjectObject(const BVH1::Object &o1, const BVH2::Object &o2)
+ \endcode
+ */
+template<typename BVH1, typename BVH2, typename Minimizer>
+typename Minimizer::Scalar BVMinimize(const BVH1 &tree1, const BVH2 &tree2, Minimizer &minimizer)
+{
+ typedef typename Minimizer::Scalar Scalar;
+ typedef typename BVH1::Index Index1;
+ typedef typename BVH2::Index Index2;
+ typedef internal::minimizer_helper1<typename BVH1::Volume, typename BVH1::Object, typename BVH2::Object, Minimizer> Helper1;
+ typedef internal::minimizer_helper2<typename BVH2::Volume, typename BVH2::Object, typename BVH1::Object, Minimizer> Helper2;
+ typedef std::pair<Scalar, std::pair<Index1, Index2> > QueueElement; //first element is priority
+ typedef typename BVH1::VolumeIterator VolIter1;
+ typedef typename BVH1::ObjectIterator ObjIter1;
+ typedef typename BVH2::VolumeIterator VolIter2;
+ typedef typename BVH2::ObjectIterator ObjIter2;
+
+ VolIter1 vBegin1 = VolIter1(), vEnd1 = VolIter1();
+ ObjIter1 oBegin1 = ObjIter1(), oEnd1 = ObjIter1();
+ VolIter2 vBegin2 = VolIter2(), vEnd2 = VolIter2(), vCur2 = VolIter2();
+ ObjIter2 oBegin2 = ObjIter2(), oEnd2 = ObjIter2(), oCur2 = ObjIter2();
+ std::priority_queue<QueueElement, std::vector<QueueElement>, std::greater<QueueElement> > todo; //smallest is at the top
+
+ Scalar minimum = (std::numeric_limits<Scalar>::max)();
+ todo.push(std::make_pair(Scalar(), std::make_pair(tree1.getRootIndex(), tree2.getRootIndex())));
+
+ while(!todo.empty()) {
+ tree1.getChildren(todo.top().second.first, vBegin1, vEnd1, oBegin1, oEnd1);
+ tree2.getChildren(todo.top().second.second, vBegin2, vEnd2, oBegin2, oEnd2);
+ todo.pop();
+
+ for(; oBegin1 != oEnd1; ++oBegin1) { //go through child objects of first tree
+ for(oCur2 = oBegin2; oCur2 != oEnd2; ++oCur2) {//go through child objects of second tree
+ minimum = (std::min)(minimum, minimizer.minimumOnObjectObject(*oBegin1, *oCur2));
+ }
+
+ for(vCur2 = vBegin2; vCur2 != vEnd2; ++vCur2) { //go through child volumes of second tree
+ Helper2 helper(*oBegin1, minimizer);
+ minimum = (std::min)(minimum, internal::minimize_helper(tree2, helper, *vCur2, minimum));
+ }
+ }
+
+ for(; vBegin1 != vEnd1; ++vBegin1) { //go through child volumes of first tree
+ const typename BVH1::Volume &vol1 = tree1.getVolume(*vBegin1);
+
+ for(oCur2 = oBegin2; oCur2 != oEnd2; ++oCur2) {//go through child objects of second tree
+ Helper1 helper(*oCur2, minimizer);
+ minimum = (std::min)(minimum, internal::minimize_helper(tree1, helper, *vBegin1, minimum));
+ }
+
+ for(vCur2 = vBegin2; vCur2 != vEnd2; ++vCur2) { //go through child volumes of second tree
+ Scalar val = minimizer.minimumOnVolumeVolume(vol1, tree2.getVolume(*vCur2));
+ if(val < minimum)
+ todo.push(std::make_pair(val, std::make_pair(*vBegin1, *vCur2)));
+ }
+ }
+ }
+ return minimum;
+}
+
+} // end namespace Eigen
+
+#endif // EIGEN_BVALGORITHMS_H
diff --git a/unsupported/Eigen/src/BVH/CMakeLists.txt b/unsupported/Eigen/src/BVH/CMakeLists.txt
new file mode 100644
index 000000000..b377d865c
--- /dev/null
+++ b/unsupported/Eigen/src/BVH/CMakeLists.txt
@@ -0,0 +1,6 @@
+FILE(GLOB Eigen_BVH_SRCS "*.h")
+
+INSTALL(FILES
+ ${Eigen_BVH_SRCS}
+ DESTINATION ${INCLUDE_INSTALL_DIR}/unsupported/Eigen/src/BVH COMPONENT Devel
+ )
diff --git a/unsupported/Eigen/src/BVH/KdBVH.h b/unsupported/Eigen/src/BVH/KdBVH.h
new file mode 100644
index 000000000..1b8d75865
--- /dev/null
+++ b/unsupported/Eigen/src/BVH/KdBVH.h
@@ -0,0 +1,222 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra.
+//
+// Copyright (C) 2009 Ilya Baran <ibaran@mit.edu>
+//
+// This Source Code Form is subject to the terms of the Mozilla
+// Public License v. 2.0. If a copy of the MPL was not distributed
+// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+#ifndef KDBVH_H_INCLUDED
+#define KDBVH_H_INCLUDED
+
+namespace Eigen {
+
+namespace internal {
+
+//internal pair class for the BVH--used instead of std::pair because of alignment
+template<typename Scalar, int Dim>
+struct vector_int_pair
+{
+EIGEN_MAKE_ALIGNED_OPERATOR_NEW_IF_VECTORIZABLE_FIXED_SIZE(Scalar, Dim)
+ typedef Matrix<Scalar, Dim, 1> VectorType;
+
+ vector_int_pair(const VectorType &v, int i) : first(v), second(i) {}
+
+ VectorType first;
+ int second;
+};
+
+//these templates help the tree initializer get the bounding boxes either from a provided
+//iterator range or using bounding_box in a unified way
+template<typename ObjectList, typename VolumeList, typename BoxIter>
+struct get_boxes_helper {
+ void operator()(const ObjectList &objects, BoxIter boxBegin, BoxIter boxEnd, VolumeList &outBoxes)
+ {
+ outBoxes.insert(outBoxes.end(), boxBegin, boxEnd);
+ eigen_assert(outBoxes.size() == objects.size());
+ }
+};
+
+template<typename ObjectList, typename VolumeList>
+struct get_boxes_helper<ObjectList, VolumeList, int> {
+ void operator()(const ObjectList &objects, int, int, VolumeList &outBoxes)
+ {
+ outBoxes.reserve(objects.size());
+ for(int i = 0; i < (int)objects.size(); ++i)
+ outBoxes.push_back(bounding_box(objects[i]));
+ }
+};
+
+} // end namespace internal
+
+
+/** \class KdBVH
+ * \brief A simple bounding volume hierarchy based on AlignedBox
+ *
+ * \param _Scalar The underlying scalar type of the bounding boxes
+ * \param _Dim The dimension of the space in which the hierarchy lives
+ * \param _Object The object type that lives in the hierarchy. It must have value semantics. Either bounding_box(_Object) must
+ * be defined and return an AlignedBox<_Scalar, _Dim> or bounding boxes must be provided to the tree initializer.
+ *
+ * This class provides a simple (as opposed to optimized) implementation of a bounding volume hierarchy analogous to a Kd-tree.
+ * Given a sequence of objects, it computes their bounding boxes, constructs a Kd-tree of their centers
+ * and builds a BVH with the structure of that Kd-tree. When the elements of the tree are too expensive to be copied around,
+ * it is useful for _Object to be a pointer.
+ */
+template<typename _Scalar, int _Dim, typename _Object> class KdBVH
+{
+public:
+ enum { Dim = _Dim };
+ typedef _Object Object;
+ typedef std::vector<Object, aligned_allocator<Object> > ObjectList;
+ typedef _Scalar Scalar;
+ typedef AlignedBox<Scalar, Dim> Volume;
+ typedef std::vector<Volume, aligned_allocator<Volume> > VolumeList;
+ typedef int Index;
+ typedef const int *VolumeIterator; //the iterators are just pointers into the tree's vectors
+ typedef const Object *ObjectIterator;
+
+ KdBVH() {}
+
+ /** Given an iterator range over \a Object references, constructs the BVH. Requires that bounding_box(Object) return a Volume. */
+ template<typename Iter> KdBVH(Iter begin, Iter end) { init(begin, end, 0, 0); } //int is recognized by init as not being an iterator type
+
+ /** Given an iterator range over \a Object references and an iterator range over their bounding boxes, constructs the BVH */
+ template<typename OIter, typename BIter> KdBVH(OIter begin, OIter end, BIter boxBegin, BIter boxEnd) { init(begin, end, boxBegin, boxEnd); }
+
+ /** Given an iterator range over \a Object references, constructs the BVH, overwriting whatever is in there currently.
+ * Requires that bounding_box(Object) return a Volume. */
+ template<typename Iter> void init(Iter begin, Iter end) { init(begin, end, 0, 0); }
+
+ /** Given an iterator range over \a Object references and an iterator range over their bounding boxes,
+ * constructs the BVH, overwriting whatever is in there currently. */
+ template<typename OIter, typename BIter> void init(OIter begin, OIter end, BIter boxBegin, BIter boxEnd)
+ {
+ objects.clear();
+ boxes.clear();
+ children.clear();
+
+ objects.insert(objects.end(), begin, end);
+ int n = static_cast<int>(objects.size());
+
+ if(n < 2)
+ return; //if we have at most one object, we don't need any internal nodes
+
+ VolumeList objBoxes;
+ VIPairList objCenters;
+
+ //compute the bounding boxes depending on BIter type
+ internal::get_boxes_helper<ObjectList, VolumeList, BIter>()(objects, boxBegin, boxEnd, objBoxes);
+
+ objCenters.reserve(n);
+ boxes.reserve(n - 1);
+ children.reserve(2 * n - 2);
+
+ for(int i = 0; i < n; ++i)
+ objCenters.push_back(VIPair(objBoxes[i].center(), i));
+
+ build(objCenters, 0, n, objBoxes, 0); //the recursive part of the algorithm
+
+ ObjectList tmp(n);
+ tmp.swap(objects);
+ for(int i = 0; i < n; ++i)
+ objects[i] = tmp[objCenters[i].second];
+ }
+
+ /** \returns the index of the root of the hierarchy */
+ inline Index getRootIndex() const { return (int)boxes.size() - 1; }
+
+ /** Given an \a index of a node, on exit, \a outVBegin and \a outVEnd range over the indices of the volume children of the node
+ * and \a outOBegin and \a outOEnd range over the object children of the node */
+ EIGEN_STRONG_INLINE void getChildren(Index index, VolumeIterator &outVBegin, VolumeIterator &outVEnd,
+ ObjectIterator &outOBegin, ObjectIterator &outOEnd) const
+ { //inlining this function should open lots of optimization opportunities to the compiler
+ if(index < 0) {
+ outVBegin = outVEnd;
+ if(!objects.empty())
+ outOBegin = &(objects[0]);
+ outOEnd = outOBegin + objects.size(); //output all objects--necessary when the tree has only one object
+ return;
+ }
+
+ int numBoxes = static_cast<int>(boxes.size());
+
+ int idx = index * 2;
+ if(children[idx + 1] < numBoxes) { //second index is always bigger
+ outVBegin = &(children[idx]);
+ outVEnd = outVBegin + 2;
+ outOBegin = outOEnd;
+ }
+ else if(children[idx] >= numBoxes) { //if both children are objects
+ outVBegin = outVEnd;
+ outOBegin = &(objects[children[idx] - numBoxes]);
+ outOEnd = outOBegin + 2;
+ } else { //if the first child is a volume and the second is an object
+ outVBegin = &(children[idx]);
+ outVEnd = outVBegin + 1;
+ outOBegin = &(objects[children[idx + 1] - numBoxes]);
+ outOEnd = outOBegin + 1;
+ }
+ }
+
+ /** \returns the bounding box of the node at \a index */
+ inline const Volume &getVolume(Index index) const
+ {
+ return boxes[index];
+ }
+
+private:
+ typedef internal::vector_int_pair<Scalar, Dim> VIPair;
+ typedef std::vector<VIPair, aligned_allocator<VIPair> > VIPairList;
+ typedef Matrix<Scalar, Dim, 1> VectorType;
+ struct VectorComparator //compares vectors, or, more specificall, VIPairs along a particular dimension
+ {
+ VectorComparator(int inDim) : dim(inDim) {}
+ inline bool operator()(const VIPair &v1, const VIPair &v2) const { return v1.first[dim] < v2.first[dim]; }
+ int dim;
+ };
+
+ //Build the part of the tree between objects[from] and objects[to] (not including objects[to]).
+ //This routine partitions the objCenters in [from, to) along the dimension dim, recursively constructs
+ //the two halves, and adds their parent node. TODO: a cache-friendlier layout
+ void build(VIPairList &objCenters, int from, int to, const VolumeList &objBoxes, int dim)
+ {
+ eigen_assert(to - from > 1);
+ if(to - from == 2) {
+ boxes.push_back(objBoxes[objCenters[from].second].merged(objBoxes[objCenters[from + 1].second]));
+ children.push_back(from + (int)objects.size() - 1); //there are objects.size() - 1 tree nodes
+ children.push_back(from + (int)objects.size());
+ }
+ else if(to - from == 3) {
+ int mid = from + 2;
+ std::nth_element(objCenters.begin() + from, objCenters.begin() + mid,
+ objCenters.begin() + to, VectorComparator(dim)); //partition
+ build(objCenters, from, mid, objBoxes, (dim + 1) % Dim);
+ int idx1 = (int)boxes.size() - 1;
+ boxes.push_back(boxes[idx1].merged(objBoxes[objCenters[mid].second]));
+ children.push_back(idx1);
+ children.push_back(mid + (int)objects.size() - 1);
+ }
+ else {
+ int mid = from + (to - from) / 2;
+ nth_element(objCenters.begin() + from, objCenters.begin() + mid,
+ objCenters.begin() + to, VectorComparator(dim)); //partition
+ build(objCenters, from, mid, objBoxes, (dim + 1) % Dim);
+ int idx1 = (int)boxes.size() - 1;
+ build(objCenters, mid, to, objBoxes, (dim + 1) % Dim);
+ int idx2 = (int)boxes.size() - 1;
+ boxes.push_back(boxes[idx1].merged(boxes[idx2]));
+ children.push_back(idx1);
+ children.push_back(idx2);
+ }
+ }
+
+ std::vector<int> children; //children of x are children[2x] and children[2x+1], indices bigger than boxes.size() index into objects.
+ VolumeList boxes;
+ ObjectList objects;
+};
+
+} // end namespace Eigen
+
+#endif //KDBVH_H_INCLUDED
diff --git a/unsupported/Eigen/src/CMakeLists.txt b/unsupported/Eigen/src/CMakeLists.txt
new file mode 100644
index 000000000..f3180b52b
--- /dev/null
+++ b/unsupported/Eigen/src/CMakeLists.txt
@@ -0,0 +1,13 @@
+ADD_SUBDIRECTORY(AutoDiff)
+ADD_SUBDIRECTORY(BVH)
+ADD_SUBDIRECTORY(FFT)
+ADD_SUBDIRECTORY(IterativeSolvers)
+ADD_SUBDIRECTORY(MatrixFunctions)
+ADD_SUBDIRECTORY(MoreVectorization)
+ADD_SUBDIRECTORY(NonLinearOptimization)
+ADD_SUBDIRECTORY(NumericalDiff)
+ADD_SUBDIRECTORY(Polynomials)
+ADD_SUBDIRECTORY(Skyline)
+ADD_SUBDIRECTORY(SparseExtra)
+ADD_SUBDIRECTORY(KroneckerProduct)
+ADD_SUBDIRECTORY(Splines)
diff --git a/unsupported/Eigen/src/FFT/CMakeLists.txt b/unsupported/Eigen/src/FFT/CMakeLists.txt
new file mode 100644
index 000000000..edcffcb18
--- /dev/null
+++ b/unsupported/Eigen/src/FFT/CMakeLists.txt
@@ -0,0 +1,6 @@
+FILE(GLOB Eigen_FFT_SRCS "*.h")
+
+INSTALL(FILES
+ ${Eigen_FFT_SRCS}
+ DESTINATION ${INCLUDE_INSTALL_DIR}/unsupported/Eigen/src/FFT COMPONENT Devel
+ )
diff --git a/unsupported/Eigen/src/FFT/ei_fftw_impl.h b/unsupported/Eigen/src/FFT/ei_fftw_impl.h
new file mode 100644
index 000000000..d49aa17f5
--- /dev/null
+++ b/unsupported/Eigen/src/FFT/ei_fftw_impl.h
@@ -0,0 +1,261 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra.
+//
+// Copyright (C) 2009 Mark Borgerding mark a borgerding net
+//
+// This Source Code Form is subject to the terms of the Mozilla
+// Public License v. 2.0. If a copy of the MPL was not distributed
+// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+namespace Eigen {
+
+namespace internal {
+
+ // FFTW uses non-const arguments
+ // so we must use ugly const_cast calls for all the args it uses
+ //
+ // This should be safe as long as
+ // 1. we use FFTW_ESTIMATE for all our planning
+ // see the FFTW docs section 4.3.2 "Planner Flags"
+ // 2. fftw_complex is compatible with std::complex
+ // This assumes std::complex<T> layout is array of size 2 with real,imag
+ template <typename T>
+ inline
+ T * fftw_cast(const T* p)
+ {
+ return const_cast<T*>( p);
+ }
+
+ inline
+ fftw_complex * fftw_cast( const std::complex<double> * p)
+ {
+ return const_cast<fftw_complex*>( reinterpret_cast<const fftw_complex*>(p) );
+ }
+
+ inline
+ fftwf_complex * fftw_cast( const std::complex<float> * p)
+ {
+ return const_cast<fftwf_complex*>( reinterpret_cast<const fftwf_complex*>(p) );
+ }
+
+ inline
+ fftwl_complex * fftw_cast( const std::complex<long double> * p)
+ {
+ return const_cast<fftwl_complex*>( reinterpret_cast<const fftwl_complex*>(p) );
+ }
+
+ template <typename T>
+ struct fftw_plan {};
+
+ template <>
+ struct fftw_plan<float>
+ {
+ typedef float scalar_type;
+ typedef fftwf_complex complex_type;
+ fftwf_plan m_plan;
+ fftw_plan() :m_plan(NULL) {}
+ ~fftw_plan() {if (m_plan) fftwf_destroy_plan(m_plan);}
+
+ inline
+ void fwd(complex_type * dst,complex_type * src,int nfft) {
+ if (m_plan==NULL) m_plan = fftwf_plan_dft_1d(nfft,src,dst, FFTW_FORWARD, FFTW_ESTIMATE|FFTW_PRESERVE_INPUT);
+ fftwf_execute_dft( m_plan, src,dst);
+ }
+ inline
+ void inv(complex_type * dst,complex_type * src,int nfft) {
+ if (m_plan==NULL) m_plan = fftwf_plan_dft_1d(nfft,src,dst, FFTW_BACKWARD , FFTW_ESTIMATE|FFTW_PRESERVE_INPUT);
+ fftwf_execute_dft( m_plan, src,dst);
+ }
+ inline
+ void fwd(complex_type * dst,scalar_type * src,int nfft) {
+ if (m_plan==NULL) m_plan = fftwf_plan_dft_r2c_1d(nfft,src,dst,FFTW_ESTIMATE|FFTW_PRESERVE_INPUT);
+ fftwf_execute_dft_r2c( m_plan,src,dst);
+ }
+ inline
+ void inv(scalar_type * dst,complex_type * src,int nfft) {
+ if (m_plan==NULL)
+ m_plan = fftwf_plan_dft_c2r_1d(nfft,src,dst,FFTW_ESTIMATE|FFTW_PRESERVE_INPUT);
+ fftwf_execute_dft_c2r( m_plan, src,dst);
+ }
+
+ inline
+ void fwd2( complex_type * dst,complex_type * src,int n0,int n1) {
+ if (m_plan==NULL) m_plan = fftwf_plan_dft_2d(n0,n1,src,dst,FFTW_FORWARD,FFTW_ESTIMATE|FFTW_PRESERVE_INPUT);
+ fftwf_execute_dft( m_plan, src,dst);
+ }
+ inline
+ void inv2( complex_type * dst,complex_type * src,int n0,int n1) {
+ if (m_plan==NULL) m_plan = fftwf_plan_dft_2d(n0,n1,src,dst,FFTW_BACKWARD,FFTW_ESTIMATE|FFTW_PRESERVE_INPUT);
+ fftwf_execute_dft( m_plan, src,dst);
+ }
+
+ };
+ template <>
+ struct fftw_plan<double>
+ {
+ typedef double scalar_type;
+ typedef fftw_complex complex_type;
+ ::fftw_plan m_plan;
+ fftw_plan() :m_plan(NULL) {}
+ ~fftw_plan() {if (m_plan) fftw_destroy_plan(m_plan);}
+
+ inline
+ void fwd(complex_type * dst,complex_type * src,int nfft) {
+ if (m_plan==NULL) m_plan = fftw_plan_dft_1d(nfft,src,dst, FFTW_FORWARD, FFTW_ESTIMATE|FFTW_PRESERVE_INPUT);
+ fftw_execute_dft( m_plan, src,dst);
+ }
+ inline
+ void inv(complex_type * dst,complex_type * src,int nfft) {
+ if (m_plan==NULL) m_plan = fftw_plan_dft_1d(nfft,src,dst, FFTW_BACKWARD , FFTW_ESTIMATE|FFTW_PRESERVE_INPUT);
+ fftw_execute_dft( m_plan, src,dst);
+ }
+ inline
+ void fwd(complex_type * dst,scalar_type * src,int nfft) {
+ if (m_plan==NULL) m_plan = fftw_plan_dft_r2c_1d(nfft,src,dst,FFTW_ESTIMATE|FFTW_PRESERVE_INPUT);
+ fftw_execute_dft_r2c( m_plan,src,dst);
+ }
+ inline
+ void inv(scalar_type * dst,complex_type * src,int nfft) {
+ if (m_plan==NULL)
+ m_plan = fftw_plan_dft_c2r_1d(nfft,src,dst,FFTW_ESTIMATE|FFTW_PRESERVE_INPUT);
+ fftw_execute_dft_c2r( m_plan, src,dst);
+ }
+ inline
+ void fwd2( complex_type * dst,complex_type * src,int n0,int n1) {
+ if (m_plan==NULL) m_plan = fftw_plan_dft_2d(n0,n1,src,dst,FFTW_FORWARD,FFTW_ESTIMATE|FFTW_PRESERVE_INPUT);
+ fftw_execute_dft( m_plan, src,dst);
+ }
+ inline
+ void inv2( complex_type * dst,complex_type * src,int n0,int n1) {
+ if (m_plan==NULL) m_plan = fftw_plan_dft_2d(n0,n1,src,dst,FFTW_BACKWARD,FFTW_ESTIMATE|FFTW_PRESERVE_INPUT);
+ fftw_execute_dft( m_plan, src,dst);
+ }
+ };
+ template <>
+ struct fftw_plan<long double>
+ {
+ typedef long double scalar_type;
+ typedef fftwl_complex complex_type;
+ fftwl_plan m_plan;
+ fftw_plan() :m_plan(NULL) {}
+ ~fftw_plan() {if (m_plan) fftwl_destroy_plan(m_plan);}
+
+ inline
+ void fwd(complex_type * dst,complex_type * src,int nfft) {
+ if (m_plan==NULL) m_plan = fftwl_plan_dft_1d(nfft,src,dst, FFTW_FORWARD, FFTW_ESTIMATE|FFTW_PRESERVE_INPUT);
+ fftwl_execute_dft( m_plan, src,dst);
+ }
+ inline
+ void inv(complex_type * dst,complex_type * src,int nfft) {
+ if (m_plan==NULL) m_plan = fftwl_plan_dft_1d(nfft,src,dst, FFTW_BACKWARD , FFTW_ESTIMATE|FFTW_PRESERVE_INPUT);
+ fftwl_execute_dft( m_plan, src,dst);
+ }
+ inline
+ void fwd(complex_type * dst,scalar_type * src,int nfft) {
+ if (m_plan==NULL) m_plan = fftwl_plan_dft_r2c_1d(nfft,src,dst,FFTW_ESTIMATE|FFTW_PRESERVE_INPUT);
+ fftwl_execute_dft_r2c( m_plan,src,dst);
+ }
+ inline
+ void inv(scalar_type * dst,complex_type * src,int nfft) {
+ if (m_plan==NULL)
+ m_plan = fftwl_plan_dft_c2r_1d(nfft,src,dst,FFTW_ESTIMATE|FFTW_PRESERVE_INPUT);
+ fftwl_execute_dft_c2r( m_plan, src,dst);
+ }
+ inline
+ void fwd2( complex_type * dst,complex_type * src,int n0,int n1) {
+ if (m_plan==NULL) m_plan = fftwl_plan_dft_2d(n0,n1,src,dst,FFTW_FORWARD,FFTW_ESTIMATE|FFTW_PRESERVE_INPUT);
+ fftwl_execute_dft( m_plan, src,dst);
+ }
+ inline
+ void inv2( complex_type * dst,complex_type * src,int n0,int n1) {
+ if (m_plan==NULL) m_plan = fftwl_plan_dft_2d(n0,n1,src,dst,FFTW_BACKWARD,FFTW_ESTIMATE|FFTW_PRESERVE_INPUT);
+ fftwl_execute_dft( m_plan, src,dst);
+ }
+ };
+
+ template <typename _Scalar>
+ struct fftw_impl
+ {
+ typedef _Scalar Scalar;
+ typedef std::complex<Scalar> Complex;
+
+ inline
+ void clear()
+ {
+ m_plans.clear();
+ }
+
+ // complex-to-complex forward FFT
+ inline
+ void fwd( Complex * dst,const Complex *src,int nfft)
+ {
+ get_plan(nfft,false,dst,src).fwd(fftw_cast(dst), fftw_cast(src),nfft );
+ }
+
+ // real-to-complex forward FFT
+ inline
+ void fwd( Complex * dst,const Scalar * src,int nfft)
+ {
+ get_plan(nfft,false,dst,src).fwd(fftw_cast(dst), fftw_cast(src) ,nfft);
+ }
+
+ // 2-d complex-to-complex
+ inline
+ void fwd2(Complex * dst, const Complex * src, int n0,int n1)
+ {
+ get_plan(n0,n1,false,dst,src).fwd2(fftw_cast(dst), fftw_cast(src) ,n0,n1);
+ }
+
+ // inverse complex-to-complex
+ inline
+ void inv(Complex * dst,const Complex *src,int nfft)
+ {
+ get_plan(nfft,true,dst,src).inv(fftw_cast(dst), fftw_cast(src),nfft );
+ }
+
+ // half-complex to scalar
+ inline
+ void inv( Scalar * dst,const Complex * src,int nfft)
+ {
+ get_plan(nfft,true,dst,src).inv(fftw_cast(dst), fftw_cast(src),nfft );
+ }
+
+ // 2-d complex-to-complex
+ inline
+ void inv2(Complex * dst, const Complex * src, int n0,int n1)
+ {
+ get_plan(n0,n1,true,dst,src).inv2(fftw_cast(dst), fftw_cast(src) ,n0,n1);
+ }
+
+
+ protected:
+ typedef fftw_plan<Scalar> PlanData;
+
+ typedef std::map<int64_t,PlanData> PlanMap;
+
+ PlanMap m_plans;
+
+ inline
+ PlanData & get_plan(int nfft,bool inverse,void * dst,const void * src)
+ {
+ bool inplace = (dst==src);
+ bool aligned = ( (reinterpret_cast<size_t>(src)&15) | (reinterpret_cast<size_t>(dst)&15) ) == 0;
+ int64_t key = ( (nfft<<3 ) | (inverse<<2) | (inplace<<1) | aligned ) << 1;
+ return m_plans[key];
+ }
+
+ inline
+ PlanData & get_plan(int n0,int n1,bool inverse,void * dst,const void * src)
+ {
+ bool inplace = (dst==src);
+ bool aligned = ( (reinterpret_cast<size_t>(src)&15) | (reinterpret_cast<size_t>(dst)&15) ) == 0;
+ int64_t key = ( ( (((int64_t)n0) << 30)|(n1<<3 ) | (inverse<<2) | (inplace<<1) | aligned ) << 1 ) + 1;
+ return m_plans[key];
+ }
+ };
+
+} // end namespace internal
+
+} // end namespace Eigen
+
+/* vim: set filetype=cpp et sw=2 ts=2 ai: */
diff --git a/unsupported/Eigen/src/FFT/ei_kissfft_impl.h b/unsupported/Eigen/src/FFT/ei_kissfft_impl.h
new file mode 100644
index 000000000..37f5af4c1
--- /dev/null
+++ b/unsupported/Eigen/src/FFT/ei_kissfft_impl.h
@@ -0,0 +1,418 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra.
+//
+// Copyright (C) 2009 Mark Borgerding mark a borgerding net
+//
+// This Source Code Form is subject to the terms of the Mozilla
+// Public License v. 2.0. If a copy of the MPL was not distributed
+// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+namespace Eigen {
+
+namespace internal {
+
+ // This FFT implementation was derived from kissfft http:sourceforge.net/projects/kissfft
+ // Copyright 2003-2009 Mark Borgerding
+
+template <typename _Scalar>
+struct kiss_cpx_fft
+{
+ typedef _Scalar Scalar;
+ typedef std::complex<Scalar> Complex;
+ std::vector<Complex> m_twiddles;
+ std::vector<int> m_stageRadix;
+ std::vector<int> m_stageRemainder;
+ std::vector<Complex> m_scratchBuf;
+ bool m_inverse;
+
+ inline
+ void make_twiddles(int nfft,bool inverse)
+ {
+ m_inverse = inverse;
+ m_twiddles.resize(nfft);
+ Scalar phinc = (inverse?2:-2)* acos( (Scalar) -1) / nfft;
+ for (int i=0;i<nfft;++i)
+ m_twiddles[i] = exp( Complex(0,i*phinc) );
+ }
+
+ void factorize(int nfft)
+ {
+ //start factoring out 4's, then 2's, then 3,5,7,9,...
+ int n= nfft;
+ int p=4;
+ do {
+ while (n % p) {
+ switch (p) {
+ case 4: p = 2; break;
+ case 2: p = 3; break;
+ default: p += 2; break;
+ }
+ if (p*p>n)
+ p=n;// impossible to have a factor > sqrt(n)
+ }
+ n /= p;
+ m_stageRadix.push_back(p);
+ m_stageRemainder.push_back(n);
+ if ( p > 5 )
+ m_scratchBuf.resize(p); // scratchbuf will be needed in bfly_generic
+ }while(n>1);
+ }
+
+ template <typename _Src>
+ inline
+ void work( int stage,Complex * xout, const _Src * xin, size_t fstride,size_t in_stride)
+ {
+ int p = m_stageRadix[stage];
+ int m = m_stageRemainder[stage];
+ Complex * Fout_beg = xout;
+ Complex * Fout_end = xout + p*m;
+
+ if (m>1) {
+ do{
+ // recursive call:
+ // DFT of size m*p performed by doing
+ // p instances of smaller DFTs of size m,
+ // each one takes a decimated version of the input
+ work(stage+1, xout , xin, fstride*p,in_stride);
+ xin += fstride*in_stride;
+ }while( (xout += m) != Fout_end );
+ }else{
+ do{
+ *xout = *xin;
+ xin += fstride*in_stride;
+ }while(++xout != Fout_end );
+ }
+ xout=Fout_beg;
+
+ // recombine the p smaller DFTs
+ switch (p) {
+ case 2: bfly2(xout,fstride,m); break;
+ case 3: bfly3(xout,fstride,m); break;
+ case 4: bfly4(xout,fstride,m); break;
+ case 5: bfly5(xout,fstride,m); break;
+ default: bfly_generic(xout,fstride,m,p); break;
+ }
+ }
+
+ inline
+ void bfly2( Complex * Fout, const size_t fstride, int m)
+ {
+ for (int k=0;k<m;++k) {
+ Complex t = Fout[m+k] * m_twiddles[k*fstride];
+ Fout[m+k] = Fout[k] - t;
+ Fout[k] += t;
+ }
+ }
+
+ inline
+ void bfly4( Complex * Fout, const size_t fstride, const size_t m)
+ {
+ Complex scratch[6];
+ int negative_if_inverse = m_inverse * -2 +1;
+ for (size_t k=0;k<m;++k) {
+ scratch[0] = Fout[k+m] * m_twiddles[k*fstride];
+ scratch[1] = Fout[k+2*m] * m_twiddles[k*fstride*2];
+ scratch[2] = Fout[k+3*m] * m_twiddles[k*fstride*3];
+ scratch[5] = Fout[k] - scratch[1];
+
+ Fout[k] += scratch[1];
+ scratch[3] = scratch[0] + scratch[2];
+ scratch[4] = scratch[0] - scratch[2];
+ scratch[4] = Complex( scratch[4].imag()*negative_if_inverse , -scratch[4].real()* negative_if_inverse );
+
+ Fout[k+2*m] = Fout[k] - scratch[3];
+ Fout[k] += scratch[3];
+ Fout[k+m] = scratch[5] + scratch[4];
+ Fout[k+3*m] = scratch[5] - scratch[4];
+ }
+ }
+
+ inline
+ void bfly3( Complex * Fout, const size_t fstride, const size_t m)
+ {
+ size_t k=m;
+ const size_t m2 = 2*m;
+ Complex *tw1,*tw2;
+ Complex scratch[5];
+ Complex epi3;
+ epi3 = m_twiddles[fstride*m];
+
+ tw1=tw2=&m_twiddles[0];
+
+ do{
+ scratch[1]=Fout[m] * *tw1;
+ scratch[2]=Fout[m2] * *tw2;
+
+ scratch[3]=scratch[1]+scratch[2];
+ scratch[0]=scratch[1]-scratch[2];
+ tw1 += fstride;
+ tw2 += fstride*2;
+ Fout[m] = Complex( Fout->real() - Scalar(.5)*scratch[3].real() , Fout->imag() - Scalar(.5)*scratch[3].imag() );
+ scratch[0] *= epi3.imag();
+ *Fout += scratch[3];
+ Fout[m2] = Complex( Fout[m].real() + scratch[0].imag() , Fout[m].imag() - scratch[0].real() );
+ Fout[m] += Complex( -scratch[0].imag(),scratch[0].real() );
+ ++Fout;
+ }while(--k);
+ }
+
+ inline
+ void bfly5( Complex * Fout, const size_t fstride, const size_t m)
+ {
+ Complex *Fout0,*Fout1,*Fout2,*Fout3,*Fout4;
+ size_t u;
+ Complex scratch[13];
+ Complex * twiddles = &m_twiddles[0];
+ Complex *tw;
+ Complex ya,yb;
+ ya = twiddles[fstride*m];
+ yb = twiddles[fstride*2*m];
+
+ Fout0=Fout;
+ Fout1=Fout0+m;
+ Fout2=Fout0+2*m;
+ Fout3=Fout0+3*m;
+ Fout4=Fout0+4*m;
+
+ tw=twiddles;
+ for ( u=0; u<m; ++u ) {
+ scratch[0] = *Fout0;
+
+ scratch[1] = *Fout1 * tw[u*fstride];
+ scratch[2] = *Fout2 * tw[2*u*fstride];
+ scratch[3] = *Fout3 * tw[3*u*fstride];
+ scratch[4] = *Fout4 * tw[4*u*fstride];
+
+ scratch[7] = scratch[1] + scratch[4];
+ scratch[10] = scratch[1] - scratch[4];
+ scratch[8] = scratch[2] + scratch[3];
+ scratch[9] = scratch[2] - scratch[3];
+
+ *Fout0 += scratch[7];
+ *Fout0 += scratch[8];
+
+ scratch[5] = scratch[0] + Complex(
+ (scratch[7].real()*ya.real() ) + (scratch[8].real() *yb.real() ),
+ (scratch[7].imag()*ya.real()) + (scratch[8].imag()*yb.real())
+ );
+
+ scratch[6] = Complex(
+ (scratch[10].imag()*ya.imag()) + (scratch[9].imag()*yb.imag()),
+ -(scratch[10].real()*ya.imag()) - (scratch[9].real()*yb.imag())
+ );
+
+ *Fout1 = scratch[5] - scratch[6];
+ *Fout4 = scratch[5] + scratch[6];
+
+ scratch[11] = scratch[0] +
+ Complex(
+ (scratch[7].real()*yb.real()) + (scratch[8].real()*ya.real()),
+ (scratch[7].imag()*yb.real()) + (scratch[8].imag()*ya.real())
+ );
+
+ scratch[12] = Complex(
+ -(scratch[10].imag()*yb.imag()) + (scratch[9].imag()*ya.imag()),
+ (scratch[10].real()*yb.imag()) - (scratch[9].real()*ya.imag())
+ );
+
+ *Fout2=scratch[11]+scratch[12];
+ *Fout3=scratch[11]-scratch[12];
+
+ ++Fout0;++Fout1;++Fout2;++Fout3;++Fout4;
+ }
+ }
+
+ /* perform the butterfly for one stage of a mixed radix FFT */
+ inline
+ void bfly_generic(
+ Complex * Fout,
+ const size_t fstride,
+ int m,
+ int p
+ )
+ {
+ int u,k,q1,q;
+ Complex * twiddles = &m_twiddles[0];
+ Complex t;
+ int Norig = static_cast<int>(m_twiddles.size());
+ Complex * scratchbuf = &m_scratchBuf[0];
+
+ for ( u=0; u<m; ++u ) {
+ k=u;
+ for ( q1=0 ; q1<p ; ++q1 ) {
+ scratchbuf[q1] = Fout[ k ];
+ k += m;
+ }
+
+ k=u;
+ for ( q1=0 ; q1<p ; ++q1 ) {
+ int twidx=0;
+ Fout[ k ] = scratchbuf[0];
+ for (q=1;q<p;++q ) {
+ twidx += static_cast<int>(fstride) * k;
+ if (twidx>=Norig) twidx-=Norig;
+ t=scratchbuf[q] * twiddles[twidx];
+ Fout[ k ] += t;
+ }
+ k += m;
+ }
+ }
+ }
+};
+
+template <typename _Scalar>
+struct kissfft_impl
+{
+ typedef _Scalar Scalar;
+ typedef std::complex<Scalar> Complex;
+
+ void clear()
+ {
+ m_plans.clear();
+ m_realTwiddles.clear();
+ }
+
+ inline
+ void fwd( Complex * dst,const Complex *src,int nfft)
+ {
+ get_plan(nfft,false).work(0, dst, src, 1,1);
+ }
+
+ inline
+ void fwd2( Complex * dst,const Complex *src,int n0,int n1)
+ {
+ EIGEN_UNUSED_VARIABLE(dst);
+ EIGEN_UNUSED_VARIABLE(src);
+ EIGEN_UNUSED_VARIABLE(n0);
+ EIGEN_UNUSED_VARIABLE(n1);
+ }
+
+ inline
+ void inv2( Complex * dst,const Complex *src,int n0,int n1)
+ {
+ EIGEN_UNUSED_VARIABLE(dst);
+ EIGEN_UNUSED_VARIABLE(src);
+ EIGEN_UNUSED_VARIABLE(n0);
+ EIGEN_UNUSED_VARIABLE(n1);
+ }
+
+ // real-to-complex forward FFT
+ // perform two FFTs of src even and src odd
+ // then twiddle to recombine them into the half-spectrum format
+ // then fill in the conjugate symmetric half
+ inline
+ void fwd( Complex * dst,const Scalar * src,int nfft)
+ {
+ if ( nfft&3 ) {
+ // use generic mode for odd
+ m_tmpBuf1.resize(nfft);
+ get_plan(nfft,false).work(0, &m_tmpBuf1[0], src, 1,1);
+ std::copy(m_tmpBuf1.begin(),m_tmpBuf1.begin()+(nfft>>1)+1,dst );
+ }else{
+ int ncfft = nfft>>1;
+ int ncfft2 = nfft>>2;
+ Complex * rtw = real_twiddles(ncfft2);
+
+ // use optimized mode for even real
+ fwd( dst, reinterpret_cast<const Complex*> (src), ncfft);
+ Complex dc = dst[0].real() + dst[0].imag();
+ Complex nyquist = dst[0].real() - dst[0].imag();
+ int k;
+ for ( k=1;k <= ncfft2 ; ++k ) {
+ Complex fpk = dst[k];
+ Complex fpnk = conj(dst[ncfft-k]);
+ Complex f1k = fpk + fpnk;
+ Complex f2k = fpk - fpnk;
+ Complex tw= f2k * rtw[k-1];
+ dst[k] = (f1k + tw) * Scalar(.5);
+ dst[ncfft-k] = conj(f1k -tw)*Scalar(.5);
+ }
+ dst[0] = dc;
+ dst[ncfft] = nyquist;
+ }
+ }
+
+ // inverse complex-to-complex
+ inline
+ void inv(Complex * dst,const Complex *src,int nfft)
+ {
+ get_plan(nfft,true).work(0, dst, src, 1,1);
+ }
+
+ // half-complex to scalar
+ inline
+ void inv( Scalar * dst,const Complex * src,int nfft)
+ {
+ if (nfft&3) {
+ m_tmpBuf1.resize(nfft);
+ m_tmpBuf2.resize(nfft);
+ std::copy(src,src+(nfft>>1)+1,m_tmpBuf1.begin() );
+ for (int k=1;k<(nfft>>1)+1;++k)
+ m_tmpBuf1[nfft-k] = conj(m_tmpBuf1[k]);
+ inv(&m_tmpBuf2[0],&m_tmpBuf1[0],nfft);
+ for (int k=0;k<nfft;++k)
+ dst[k] = m_tmpBuf2[k].real();
+ }else{
+ // optimized version for multiple of 4
+ int ncfft = nfft>>1;
+ int ncfft2 = nfft>>2;
+ Complex * rtw = real_twiddles(ncfft2);
+ m_tmpBuf1.resize(ncfft);
+ m_tmpBuf1[0] = Complex( src[0].real() + src[ncfft].real(), src[0].real() - src[ncfft].real() );
+ for (int k = 1; k <= ncfft / 2; ++k) {
+ Complex fk = src[k];
+ Complex fnkc = conj(src[ncfft-k]);
+ Complex fek = fk + fnkc;
+ Complex tmp = fk - fnkc;
+ Complex fok = tmp * conj(rtw[k-1]);
+ m_tmpBuf1[k] = fek + fok;
+ m_tmpBuf1[ncfft-k] = conj(fek - fok);
+ }
+ get_plan(ncfft,true).work(0, reinterpret_cast<Complex*>(dst), &m_tmpBuf1[0], 1,1);
+ }
+ }
+
+ protected:
+ typedef kiss_cpx_fft<Scalar> PlanData;
+ typedef std::map<int,PlanData> PlanMap;
+
+ PlanMap m_plans;
+ std::map<int, std::vector<Complex> > m_realTwiddles;
+ std::vector<Complex> m_tmpBuf1;
+ std::vector<Complex> m_tmpBuf2;
+
+ inline
+ int PlanKey(int nfft, bool isinverse) const { return (nfft<<1) | int(isinverse); }
+
+ inline
+ PlanData & get_plan(int nfft, bool inverse)
+ {
+ // TODO look for PlanKey(nfft, ! inverse) and conjugate the twiddles
+ PlanData & pd = m_plans[ PlanKey(nfft,inverse) ];
+ if ( pd.m_twiddles.size() == 0 ) {
+ pd.make_twiddles(nfft,inverse);
+ pd.factorize(nfft);
+ }
+ return pd;
+ }
+
+ inline
+ Complex * real_twiddles(int ncfft2)
+ {
+ std::vector<Complex> & twidref = m_realTwiddles[ncfft2];// creates new if not there
+ if ( (int)twidref.size() != ncfft2 ) {
+ twidref.resize(ncfft2);
+ int ncfft= ncfft2<<1;
+ Scalar pi = acos( Scalar(-1) );
+ for (int k=1;k<=ncfft2;++k)
+ twidref[k-1] = exp( Complex(0,-pi * (Scalar(k) / ncfft + Scalar(.5)) ) );
+ }
+ return &twidref[0];
+ }
+};
+
+} // end namespace internal
+
+} // end namespace Eigen
+
+/* vim: set filetype=cpp et sw=2 ts=2 ai: */
diff --git a/unsupported/Eigen/src/IterativeSolvers/CMakeLists.txt b/unsupported/Eigen/src/IterativeSolvers/CMakeLists.txt
new file mode 100644
index 000000000..7986afc5e
--- /dev/null
+++ b/unsupported/Eigen/src/IterativeSolvers/CMakeLists.txt
@@ -0,0 +1,6 @@
+FILE(GLOB Eigen_IterativeSolvers_SRCS "*.h")
+
+INSTALL(FILES
+ ${Eigen_IterativeSolvers_SRCS}
+ DESTINATION ${INCLUDE_INSTALL_DIR}/unsupported/Eigen/src/IterativeSolvers COMPONENT Devel
+ )
diff --git a/unsupported/Eigen/src/IterativeSolvers/ConstrainedConjGrad.h b/unsupported/Eigen/src/IterativeSolvers/ConstrainedConjGrad.h
new file mode 100644
index 000000000..b83bf7aef
--- /dev/null
+++ b/unsupported/Eigen/src/IterativeSolvers/ConstrainedConjGrad.h
@@ -0,0 +1,189 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra.
+//
+// Copyright (C) 2008 Gael Guennebaud <gael.guennebaud@inria.fr>
+//
+// This Source Code Form is subject to the terms of the Mozilla
+// Public License v. 2.0. If a copy of the MPL was not distributed
+// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+/* NOTE The functions of this file have been adapted from the GMM++ library */
+
+//========================================================================
+//
+// Copyright (C) 2002-2007 Yves Renard
+//
+// This file is a part of GETFEM++
+//
+// Getfem++ is free software; you can redistribute it and/or modify
+// it under the terms of the GNU Lesser General Public License as
+// published by the Free Software Foundation; version 2.1 of the License.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU Lesser General Public License for more details.
+// You should have received a copy of the GNU Lesser General Public
+// License along with this program; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301,
+// USA.
+//
+//========================================================================
+
+#include "../../../../Eigen/src/Core/util/NonMPL2.h"
+
+#ifndef EIGEN_CONSTRAINEDCG_H
+#define EIGEN_CONSTRAINEDCG_H
+
+#include <Eigen/Core>
+
+namespace Eigen {
+
+namespace internal {
+
+/** \ingroup IterativeSolvers_Module
+ * Compute the pseudo inverse of the non-square matrix C such that
+ * \f$ CINV = (C * C^T)^{-1} * C \f$ based on a conjugate gradient method.
+ *
+ * This function is internally used by constrained_cg.
+ */
+template <typename CMatrix, typename CINVMatrix>
+void pseudo_inverse(const CMatrix &C, CINVMatrix &CINV)
+{
+ // optimisable : copie de la ligne, precalcul de C * trans(C).
+ typedef typename CMatrix::Scalar Scalar;
+ typedef typename CMatrix::Index Index;
+ // FIXME use sparse vectors ?
+ typedef Matrix<Scalar,Dynamic,1> TmpVec;
+
+ Index rows = C.rows(), cols = C.cols();
+
+ TmpVec d(rows), e(rows), l(cols), p(rows), q(rows), r(rows);
+ Scalar rho, rho_1, alpha;
+ d.setZero();
+
+ CINV.startFill(); // FIXME estimate the number of non-zeros
+ for (Index i = 0; i < rows; ++i)
+ {
+ d[i] = 1.0;
+ rho = 1.0;
+ e.setZero();
+ r = d;
+ p = d;
+
+ while (rho >= 1e-38)
+ { /* conjugate gradient to compute e */
+ /* which is the i-th row of inv(C * trans(C)) */
+ l = C.transpose() * p;
+ q = C * l;
+ alpha = rho / p.dot(q);
+ e += alpha * p;
+ r += -alpha * q;
+ rho_1 = rho;
+ rho = r.dot(r);
+ p = (rho/rho_1) * p + r;
+ }
+
+ l = C.transpose() * e; // l is the i-th row of CINV
+ // FIXME add a generic "prune/filter" expression for both dense and sparse object to sparse
+ for (Index j=0; j<l.size(); ++j)
+ if (l[j]<1e-15)
+ CINV.fill(i,j) = l[j];
+
+ d[i] = 0.0;
+ }
+ CINV.endFill();
+}
+
+
+
+/** \ingroup IterativeSolvers_Module
+ * Constrained conjugate gradient
+ *
+ * Computes the minimum of \f$ 1/2((Ax).x) - bx \f$ under the contraint \f$ Cx \le f \f$
+ */
+template<typename TMatrix, typename CMatrix,
+ typename VectorX, typename VectorB, typename VectorF>
+void constrained_cg(const TMatrix& A, const CMatrix& C, VectorX& x,
+ const VectorB& b, const VectorF& f, IterationController &iter)
+{
+ typedef typename TMatrix::Scalar Scalar;
+ typedef typename TMatrix::Index Index;
+ typedef Matrix<Scalar,Dynamic,1> TmpVec;
+
+ Scalar rho = 1.0, rho_1, lambda, gamma;
+ Index xSize = x.size();
+ TmpVec p(xSize), q(xSize), q2(xSize),
+ r(xSize), old_z(xSize), z(xSize),
+ memox(xSize);
+ std::vector<bool> satured(C.rows());
+ p.setZero();
+ iter.setRhsNorm(sqrt(b.dot(b))); // gael vect_sp(PS, b, b)
+ if (iter.rhsNorm() == 0.0) iter.setRhsNorm(1.0);
+
+ SparseMatrix<Scalar,RowMajor> CINV(C.rows(), C.cols());
+ pseudo_inverse(C, CINV);
+
+ while(true)
+ {
+ // computation of residual
+ old_z = z;
+ memox = x;
+ r = b;
+ r += A * -x;
+ z = r;
+ bool transition = false;
+ for (Index i = 0; i < C.rows(); ++i)
+ {
+ Scalar al = C.row(i).dot(x) - f.coeff(i);
+ if (al >= -1.0E-15)
+ {
+ if (!satured[i])
+ {
+ satured[i] = true;
+ transition = true;
+ }
+ Scalar bb = CINV.row(i).dot(z);
+ if (bb > 0.0)
+ // FIXME: we should allow that: z += -bb * C.row(i);
+ for (typename CMatrix::InnerIterator it(C,i); it; ++it)
+ z.coeffRef(it.index()) -= bb*it.value();
+ }
+ else
+ satured[i] = false;
+ }
+
+ // descent direction
+ rho_1 = rho;
+ rho = r.dot(z);
+
+ if (iter.finished(rho)) break;
+
+ if (iter.noiseLevel() > 0 && transition) std::cerr << "CCG: transition\n";
+ if (transition || iter.first()) gamma = 0.0;
+ else gamma = (std::max)(0.0, (rho - old_z.dot(z)) / rho_1);
+ p = z + gamma*p;
+
+ ++iter;
+ // one dimensionnal optimization
+ q = A * p;
+ lambda = rho / q.dot(p);
+ for (Index i = 0; i < C.rows(); ++i)
+ {
+ if (!satured[i])
+ {
+ Scalar bb = C.row(i).dot(p) - f[i];
+ if (bb > 0.0)
+ lambda = (std::min)(lambda, (f.coeff(i)-C.row(i).dot(x)) / bb);
+ }
+ }
+ x += lambda * p;
+ memox -= x;
+ }
+}
+
+} // end namespace internal
+
+} // end namespace Eigen
+
+#endif // EIGEN_CONSTRAINEDCG_H
diff --git a/unsupported/Eigen/src/IterativeSolvers/GMRES.h b/unsupported/Eigen/src/IterativeSolvers/GMRES.h
new file mode 100644
index 000000000..34e67db82
--- /dev/null
+++ b/unsupported/Eigen/src/IterativeSolvers/GMRES.h
@@ -0,0 +1,379 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra.
+//
+// Copyright (C) 2011 Gael Guennebaud <gael.guennebaud@inria.fr>
+// Copyright (C) 2012 Kolja Brix <brix@igpm.rwth-aaachen.de>
+//
+// This Source Code Form is subject to the terms of the Mozilla
+// Public License v. 2.0. If a copy of the MPL was not distributed
+// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+#ifndef EIGEN_GMRES_H
+#define EIGEN_GMRES_H
+
+namespace Eigen {
+
+namespace internal {
+
+/**
+ * Generalized Minimal Residual Algorithm based on the
+ * Arnoldi algorithm implemented with Householder reflections.
+ *
+ * Parameters:
+ * \param mat matrix of linear system of equations
+ * \param Rhs right hand side vector of linear system of equations
+ * \param x on input: initial guess, on output: solution
+ * \param precond preconditioner used
+ * \param iters on input: maximum number of iterations to perform
+ * on output: number of iterations performed
+ * \param restart number of iterations for a restart
+ * \param tol_error on input: residual tolerance
+ * on output: residuum achieved
+ *
+ * \sa IterativeMethods::bicgstab()
+ *
+ *
+ * For references, please see:
+ *
+ * Saad, Y. and Schultz, M. H.
+ * GMRES: A Generalized Minimal Residual Algorithm for Solving Nonsymmetric Linear Systems.
+ * SIAM J.Sci.Stat.Comp. 7, 1986, pp. 856 - 869.
+ *
+ * Saad, Y.
+ * Iterative Methods for Sparse Linear Systems.
+ * Society for Industrial and Applied Mathematics, Philadelphia, 2003.
+ *
+ * Walker, H. F.
+ * Implementations of the GMRES method.
+ * Comput.Phys.Comm. 53, 1989, pp. 311 - 320.
+ *
+ * Walker, H. F.
+ * Implementation of the GMRES Method using Householder Transformations.
+ * SIAM J.Sci.Stat.Comp. 9, 1988, pp. 152 - 163.
+ *
+ */
+template<typename MatrixType, typename Rhs, typename Dest, typename Preconditioner>
+bool gmres(const MatrixType & mat, const Rhs & rhs, Dest & x, const Preconditioner & precond,
+ int &iters, const int &restart, typename Dest::RealScalar & tol_error) {
+
+ using std::sqrt;
+ using std::abs;
+
+ typedef typename Dest::RealScalar RealScalar;
+ typedef typename Dest::Scalar Scalar;
+ typedef Matrix < RealScalar, Dynamic, 1 > RealVectorType;
+ typedef Matrix < Scalar, Dynamic, 1 > VectorType;
+ typedef Matrix < Scalar, Dynamic, Dynamic > FMatrixType;
+
+ RealScalar tol = tol_error;
+ const int maxIters = iters;
+ iters = 0;
+
+ const int m = mat.rows();
+
+ VectorType p0 = rhs - mat*x;
+ VectorType r0 = precond.solve(p0);
+// RealScalar r0_sqnorm = r0.squaredNorm();
+
+ VectorType w = VectorType::Zero(restart + 1);
+
+ FMatrixType H = FMatrixType::Zero(m, restart + 1);
+ VectorType tau = VectorType::Zero(restart + 1);
+ std::vector < JacobiRotation < Scalar > > G(restart);
+
+ // generate first Householder vector
+ VectorType e;
+ RealScalar beta;
+ r0.makeHouseholder(e, tau.coeffRef(0), beta);
+ w(0)=(Scalar) beta;
+ H.bottomLeftCorner(m - 1, 1) = e;
+
+ for (int k = 1; k <= restart; ++k) {
+
+ ++iters;
+
+ VectorType v = VectorType::Unit(m, k - 1), workspace(m);
+
+ // apply Householder reflections H_{1} ... H_{k-1} to v
+ for (int i = k - 1; i >= 0; --i) {
+ v.tail(m - i).applyHouseholderOnTheLeft(H.col(i).tail(m - i - 1), tau.coeffRef(i), workspace.data());
+ }
+
+ // apply matrix M to v: v = mat * v;
+ VectorType t=mat*v;
+ v=precond.solve(t);
+
+ // apply Householder reflections H_{k-1} ... H_{1} to v
+ for (int i = 0; i < k; ++i) {
+ v.tail(m - i).applyHouseholderOnTheLeft(H.col(i).tail(m - i - 1), tau.coeffRef(i), workspace.data());
+ }
+
+ if (v.tail(m - k).norm() != 0.0) {
+
+ if (k <= restart) {
+
+ // generate new Householder vector
+ VectorType e(m - k - 1);
+ RealScalar beta;
+ v.tail(m - k).makeHouseholder(e, tau.coeffRef(k), beta);
+ H.col(k).tail(m - k - 1) = e;
+
+ // apply Householder reflection H_{k} to v
+ v.tail(m - k).applyHouseholderOnTheLeft(H.col(k).tail(m - k - 1), tau.coeffRef(k), workspace.data());
+
+ }
+ }
+
+ if (k > 1) {
+ for (int i = 0; i < k - 1; ++i) {
+ // apply old Givens rotations to v
+ v.applyOnTheLeft(i, i + 1, G[i].adjoint());
+ }
+ }
+
+ if (k<m && v(k) != (Scalar) 0) {
+ // determine next Givens rotation
+ G[k - 1].makeGivens(v(k - 1), v(k));
+
+ // apply Givens rotation to v and w
+ v.applyOnTheLeft(k - 1, k, G[k - 1].adjoint());
+ w.applyOnTheLeft(k - 1, k, G[k - 1].adjoint());
+
+ }
+
+ // insert coefficients into upper matrix triangle
+ H.col(k - 1).head(k) = v.head(k);
+
+ bool stop=(k==m || abs(w(k)) < tol || iters == maxIters);
+
+ if (stop || k == restart) {
+
+ // solve upper triangular system
+ VectorType y = w.head(k);
+ H.topLeftCorner(k, k).template triangularView < Eigen::Upper > ().solveInPlace(y);
+
+ // use Horner-like scheme to calculate solution vector
+ VectorType x_new = y(k - 1) * VectorType::Unit(m, k - 1);
+
+ // apply Householder reflection H_{k} to x_new
+ x_new.tail(m - k + 1).applyHouseholderOnTheLeft(H.col(k - 1).tail(m - k), tau.coeffRef(k - 1), workspace.data());
+
+ for (int i = k - 2; i >= 0; --i) {
+ x_new += y(i) * VectorType::Unit(m, i);
+ // apply Householder reflection H_{i} to x_new
+ x_new.tail(m - i).applyHouseholderOnTheLeft(H.col(i).tail(m - i - 1), tau.coeffRef(i), workspace.data());
+ }
+
+ x += x_new;
+
+ if (stop) {
+ return true;
+ } else {
+ k=0;
+
+ // reset data for a restart r0 = rhs - mat * x;
+ VectorType p0=mat*x;
+ VectorType p1=precond.solve(p0);
+ r0 = rhs - p1;
+// r0_sqnorm = r0.squaredNorm();
+ w = VectorType::Zero(restart + 1);
+ H = FMatrixType::Zero(m, restart + 1);
+ tau = VectorType::Zero(restart + 1);
+
+ // generate first Householder vector
+ RealScalar beta;
+ r0.makeHouseholder(e, tau.coeffRef(0), beta);
+ w(0)=(Scalar) beta;
+ H.bottomLeftCorner(m - 1, 1) = e;
+
+ }
+
+ }
+
+
+
+ }
+
+ return false;
+
+}
+
+}
+
+template< typename _MatrixType,
+ typename _Preconditioner = DiagonalPreconditioner<typename _MatrixType::Scalar> >
+class GMRES;
+
+namespace internal {
+
+template< typename _MatrixType, typename _Preconditioner>
+struct traits<GMRES<_MatrixType,_Preconditioner> >
+{
+ typedef _MatrixType MatrixType;
+ typedef _Preconditioner Preconditioner;
+};
+
+}
+
+/** \ingroup IterativeLinearSolvers_Module
+ * \brief A GMRES solver for sparse square problems
+ *
+ * This class allows to solve for A.x = b sparse linear problems using a generalized minimal
+ * residual method. The vectors x and b can be either dense or sparse.
+ *
+ * \tparam _MatrixType the type of the sparse matrix A, can be a dense or a sparse matrix.
+ * \tparam _Preconditioner the type of the preconditioner. Default is DiagonalPreconditioner
+ *
+ * The maximal number of iterations and tolerance value can be controlled via the setMaxIterations()
+ * and setTolerance() methods. The defaults are the size of the problem for the maximal number of iterations
+ * and NumTraits<Scalar>::epsilon() for the tolerance.
+ *
+ * This class can be used as the direct solver classes. Here is a typical usage example:
+ * \code
+ * int n = 10000;
+ * VectorXd x(n), b(n);
+ * SparseMatrix<double> A(n,n);
+ * // fill A and b
+ * GMRES<SparseMatrix<double> > solver(A);
+ * x = solver.solve(b);
+ * std::cout << "#iterations: " << solver.iterations() << std::endl;
+ * std::cout << "estimated error: " << solver.error() << std::endl;
+ * // update b, and solve again
+ * x = solver.solve(b);
+ * \endcode
+ *
+ * By default the iterations start with x=0 as an initial guess of the solution.
+ * One can control the start using the solveWithGuess() method. Here is a step by
+ * step execution example starting with a random guess and printing the evolution
+ * of the estimated error:
+ * * \code
+ * x = VectorXd::Random(n);
+ * solver.setMaxIterations(1);
+ * int i = 0;
+ * do {
+ * x = solver.solveWithGuess(b,x);
+ * std::cout << i << " : " << solver.error() << std::endl;
+ * ++i;
+ * } while (solver.info()!=Success && i<100);
+ * \endcode
+ * Note that such a step by step excution is slightly slower.
+ *
+ * \sa class SimplicialCholesky, DiagonalPreconditioner, IdentityPreconditioner
+ */
+template< typename _MatrixType, typename _Preconditioner>
+class GMRES : public IterativeSolverBase<GMRES<_MatrixType,_Preconditioner> >
+{
+ typedef IterativeSolverBase<GMRES> Base;
+ using Base::mp_matrix;
+ using Base::m_error;
+ using Base::m_iterations;
+ using Base::m_info;
+ using Base::m_isInitialized;
+
+private:
+ int m_restart;
+
+public:
+ typedef _MatrixType MatrixType;
+ typedef typename MatrixType::Scalar Scalar;
+ typedef typename MatrixType::Index Index;
+ typedef typename MatrixType::RealScalar RealScalar;
+ typedef _Preconditioner Preconditioner;
+
+public:
+
+ /** Default constructor. */
+ GMRES() : Base(), m_restart(30) {}
+
+ /** 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.
+ */
+ GMRES(const MatrixType& A) : Base(A), m_restart(30) {}
+
+ ~GMRES() {}
+
+ /** Get the number of iterations after that a restart is performed.
+ */
+ int get_restart() { return m_restart; }
+
+ /** Set the number of iterations after that a restart is performed.
+ * \param restart number of iterations for a restarti, default is 30.
+ */
+ void set_restart(const int restart) { m_restart=restart; }
+
+ /** \returns the solution x of \f$ A x = b \f$ using the current decomposition of A
+ * \a x0 as an initial solution.
+ *
+ * \sa compute()
+ */
+ template<typename Rhs,typename Guess>
+ inline const internal::solve_retval_with_guess<GMRES, Rhs, Guess>
+ solveWithGuess(const MatrixBase<Rhs>& b, const Guess& x0) const
+ {
+ eigen_assert(m_isInitialized && "GMRES is not initialized.");
+ eigen_assert(Base::rows()==b.rows()
+ && "GMRES::solve(): invalid number of rows of the right hand side matrix b");
+ return internal::solve_retval_with_guess
+ <GMRES, Rhs, Guess>(*this, b.derived(), x0);
+ }
+
+ /** \internal */
+ template<typename Rhs,typename Dest>
+ void _solveWithGuess(const Rhs& b, Dest& x) const
+ {
+ bool failed = false;
+ for(int j=0; j<b.cols(); ++j)
+ {
+ m_iterations = Base::maxIterations();
+ m_error = Base::m_tolerance;
+
+ typename Dest::ColXpr xj(x,j);
+ if(!internal::gmres(*mp_matrix, b.col(j), xj, Base::m_preconditioner, m_iterations, m_restart, m_error))
+ failed = true;
+ }
+ m_info = failed ? NumericalIssue
+ : m_error <= Base::m_tolerance ? Success
+ : NoConvergence;
+ m_isInitialized = true;
+ }
+
+ /** \internal */
+ template<typename Rhs,typename Dest>
+ void _solve(const Rhs& b, Dest& x) const
+ {
+ x.setZero();
+ _solveWithGuess(b,x);
+ }
+
+protected:
+
+};
+
+
+namespace internal {
+
+ template<typename _MatrixType, typename _Preconditioner, typename Rhs>
+struct solve_retval<GMRES<_MatrixType, _Preconditioner>, Rhs>
+ : solve_retval_base<GMRES<_MatrixType, _Preconditioner>, Rhs>
+{
+ typedef GMRES<_MatrixType, _Preconditioner> Dec;
+ EIGEN_MAKE_SOLVE_HELPERS(Dec,Rhs)
+
+ template<typename Dest> void evalTo(Dest& dst) const
+ {
+ dec()._solve(rhs(),dst);
+ }
+};
+
+} // end namespace internal
+
+} // end namespace Eigen
+
+#endif // EIGEN_GMRES_H
diff --git a/unsupported/Eigen/src/IterativeSolvers/IncompleteLU.h b/unsupported/Eigen/src/IterativeSolvers/IncompleteLU.h
new file mode 100644
index 000000000..67e780181
--- /dev/null
+++ b/unsupported/Eigen/src/IterativeSolvers/IncompleteLU.h
@@ -0,0 +1,113 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra.
+//
+// Copyright (C) 2011 Gael Guennebaud <gael.guennebaud@inria.fr>
+//
+// This Source Code Form is subject to the terms of the Mozilla
+// Public License v. 2.0. If a copy of the MPL was not distributed
+// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+#ifndef EIGEN_INCOMPLETE_LU_H
+#define EIGEN_INCOMPLETE_LU_H
+
+namespace Eigen {
+
+template <typename _Scalar>
+class IncompleteLU
+{
+ typedef _Scalar Scalar;
+ typedef Matrix<Scalar,Dynamic,1> Vector;
+ typedef typename Vector::Index Index;
+ typedef SparseMatrix<Scalar,RowMajor> FactorType;
+
+ public:
+ typedef Matrix<Scalar,Dynamic,Dynamic> MatrixType;
+
+ IncompleteLU() : m_isInitialized(false) {}
+
+ template<typename MatrixType>
+ IncompleteLU(const MatrixType& mat) : m_isInitialized(false)
+ {
+ compute(mat);
+ }
+
+ Index rows() const { return m_lu.rows(); }
+ Index cols() const { return m_lu.cols(); }
+
+ template<typename MatrixType>
+ IncompleteLU& compute(const MatrixType& mat)
+ {
+ m_lu = mat;
+ int size = mat.cols();
+ Vector diag(size);
+ for(int i=0; i<size; ++i)
+ {
+ typename FactorType::InnerIterator k_it(m_lu,i);
+ for(; k_it && k_it.index()<i; ++k_it)
+ {
+ int k = k_it.index();
+ k_it.valueRef() /= diag(k);
+
+ typename FactorType::InnerIterator j_it(k_it);
+ typename FactorType::InnerIterator kj_it(m_lu, k);
+ while(kj_it && kj_it.index()<=k) ++kj_it;
+ for(++j_it; j_it; )
+ {
+ if(kj_it.index()==j_it.index())
+ {
+ j_it.valueRef() -= k_it.value() * kj_it.value();
+ ++j_it;
+ ++kj_it;
+ }
+ else if(kj_it.index()<j_it.index()) ++kj_it;
+ else ++j_it;
+ }
+ }
+ if(k_it && k_it.index()==i) diag(i) = k_it.value();
+ else diag(i) = 1;
+ }
+ m_isInitialized = true;
+ return *this;
+ }
+
+ template<typename Rhs, typename Dest>
+ void _solve(const Rhs& b, Dest& x) const
+ {
+ x = m_lu.template triangularView<UnitLower>().solve(b);
+ x = m_lu.template triangularView<Upper>().solve(x);
+ }
+
+ template<typename Rhs> inline const internal::solve_retval<IncompleteLU, Rhs>
+ solve(const MatrixBase<Rhs>& b) const
+ {
+ eigen_assert(m_isInitialized && "IncompleteLU is not initialized.");
+ eigen_assert(cols()==b.rows()
+ && "IncompleteLU::solve(): invalid number of rows of the right hand side matrix b");
+ return internal::solve_retval<IncompleteLU, Rhs>(*this, b.derived());
+ }
+
+ protected:
+ FactorType m_lu;
+ bool m_isInitialized;
+};
+
+namespace internal {
+
+template<typename _MatrixType, typename Rhs>
+struct solve_retval<IncompleteLU<_MatrixType>, Rhs>
+ : solve_retval_base<IncompleteLU<_MatrixType>, Rhs>
+{
+ typedef IncompleteLU<_MatrixType> Dec;
+ EIGEN_MAKE_SOLVE_HELPERS(Dec,Rhs)
+
+ template<typename Dest> void evalTo(Dest& dst) const
+ {
+ dec()._solve(rhs(),dst);
+ }
+};
+
+} // end namespace internal
+
+} // end namespace Eigen
+
+#endif // EIGEN_INCOMPLETE_LU_H
diff --git a/unsupported/Eigen/src/IterativeSolvers/IterationController.h b/unsupported/Eigen/src/IterativeSolvers/IterationController.h
new file mode 100644
index 000000000..aaf46d544
--- /dev/null
+++ b/unsupported/Eigen/src/IterativeSolvers/IterationController.h
@@ -0,0 +1,157 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra.
+//
+// Copyright (C) 2008-2009 Gael Guennebaud <gael.guennebaud@inria.fr>
+//
+// This Source Code Form is subject to the terms of the Mozilla
+// Public License v. 2.0. If a copy of the MPL was not distributed
+// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+/* NOTE The class IterationController has been adapted from the iteration
+ * class of the GMM++ and ITL libraries.
+ */
+
+//=======================================================================
+// Copyright (C) 1997-2001
+// Authors: Andrew Lumsdaine <lums@osl.iu.edu>
+// Lie-Quan Lee <llee@osl.iu.edu>
+//
+// This file is part of the Iterative Template Library
+//
+// You should have received a copy of the License Agreement for the
+// Iterative Template Library along with the software; see the
+// file LICENSE.
+//
+// Permission to modify the code and to distribute modified code is
+// granted, provided the text of this NOTICE is retained, a notice that
+// the code was modified is included with the above COPYRIGHT NOTICE and
+// with the COPYRIGHT NOTICE in the LICENSE file, and that the LICENSE
+// file is distributed with the modified code.
+//
+// LICENSOR MAKES NO REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED.
+// By way of example, but not limitation, Licensor MAKES NO
+// REPRESENTATIONS OR WARRANTIES OF MERCHANTABILITY OR FITNESS FOR ANY
+// PARTICULAR PURPOSE OR THAT THE USE OF THE LICENSED SOFTWARE COMPONENTS
+// OR DOCUMENTATION WILL NOT INFRINGE ANY PATENTS, COPYRIGHTS, TRADEMARKS
+// OR OTHER RIGHTS.
+//=======================================================================
+
+//========================================================================
+//
+// Copyright (C) 2002-2007 Yves Renard
+//
+// This file is a part of GETFEM++
+//
+// Getfem++ is free software; you can redistribute it and/or modify
+// it under the terms of the GNU Lesser General Public License as
+// published by the Free Software Foundation; version 2.1 of the License.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU Lesser General Public License for more details.
+// You should have received a copy of the GNU Lesser General Public
+// License along with this program; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301,
+// USA.
+//
+//========================================================================
+
+#include "../../../../Eigen/src/Core/util/NonMPL2.h"
+
+#ifndef EIGEN_ITERATION_CONTROLLER_H
+#define EIGEN_ITERATION_CONTROLLER_H
+
+namespace Eigen {
+
+/** \ingroup IterativeSolvers_Module
+ * \class IterationController
+ *
+ * \brief Controls the iterations of the iterative solvers
+ *
+ * This class has been adapted from the iteration class of GMM++ and ITL libraries.
+ *
+ */
+class IterationController
+{
+ protected :
+ double m_rhsn; ///< Right hand side norm
+ size_t m_maxiter; ///< Max. number of iterations
+ int m_noise; ///< if noise > 0 iterations are printed
+ double m_resmax; ///< maximum residual
+ double m_resminreach, m_resadd;
+ size_t m_nit; ///< iteration number
+ double m_res; ///< last computed residual
+ bool m_written;
+ void (*m_callback)(const IterationController&);
+ public :
+
+ void init()
+ {
+ m_nit = 0; m_res = 0.0; m_written = false;
+ m_resminreach = 1E50; m_resadd = 0.0;
+ m_callback = 0;
+ }
+
+ IterationController(double r = 1.0E-8, int noi = 0, size_t mit = size_t(-1))
+ : m_rhsn(1.0), m_maxiter(mit), m_noise(noi), m_resmax(r) { init(); }
+
+ void operator ++(int) { m_nit++; m_written = false; m_resadd += m_res; }
+ void operator ++() { (*this)++; }
+
+ bool first() { return m_nit == 0; }
+
+ /* get/set the "noisyness" (verbosity) of the solvers */
+ int noiseLevel() const { return m_noise; }
+ void setNoiseLevel(int n) { m_noise = n; }
+ void reduceNoiseLevel() { if (m_noise > 0) m_noise--; }
+
+ double maxResidual() const { return m_resmax; }
+ void setMaxResidual(double r) { m_resmax = r; }
+
+ double residual() const { return m_res; }
+
+ /* change the user-definable callback, called after each iteration */
+ void setCallback(void (*t)(const IterationController&))
+ {
+ m_callback = t;
+ }
+
+ size_t iteration() const { return m_nit; }
+ void setIteration(size_t i) { m_nit = i; }
+
+ size_t maxIterarions() const { return m_maxiter; }
+ void setMaxIterations(size_t i) { m_maxiter = i; }
+
+ double rhsNorm() const { return m_rhsn; }
+ void setRhsNorm(double r) { m_rhsn = r; }
+
+ bool converged() const { return m_res <= m_rhsn * m_resmax; }
+ bool converged(double nr)
+ {
+ m_res = internal::abs(nr);
+ m_resminreach = (std::min)(m_resminreach, m_res);
+ return converged();
+ }
+ template<typename VectorType> bool converged(const VectorType &v)
+ { return converged(v.squaredNorm()); }
+
+ bool finished(double nr)
+ {
+ if (m_callback) m_callback(*this);
+ if (m_noise > 0 && !m_written)
+ {
+ converged(nr);
+ m_written = true;
+ }
+ return (m_nit >= m_maxiter || converged(nr));
+ }
+ template <typename VectorType>
+ bool finished(const MatrixBase<VectorType> &v)
+ { return finished(double(v.squaredNorm())); }
+
+};
+
+} // end namespace Eigen
+
+#endif // EIGEN_ITERATION_CONTROLLER_H
diff --git a/unsupported/Eigen/src/IterativeSolvers/Scaling.h b/unsupported/Eigen/src/IterativeSolvers/Scaling.h
new file mode 100644
index 000000000..fdef0aca3
--- /dev/null
+++ b/unsupported/Eigen/src/IterativeSolvers/Scaling.h
@@ -0,0 +1,185 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra.
+//
+// Copyright (C) 2012 Desire NUENTSA WAKAM <desire.nuentsa_wakam@inria.fr
+//
+// This Source Code Form is subject to the terms of the Mozilla
+// Public License v. 2.0. If a copy of the MPL was not distributed
+// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+#ifndef EIGEN_SCALING_H
+#define EIGEN_SCALING_H
+/**
+ * \ingroup IterativeSolvers_Module
+ * \brief iterative scaling algorithm to equilibrate rows and column norms in matrices
+ *
+ * This class can be used as a preprocessing tool to accelerate the convergence of iterative methods
+ *
+ * This feature is useful to limit the pivoting amount during LU/ILU factorization
+ * The scaling strategy as presented here preserves the symmetry of the problem
+ * NOTE It is assumed that the matrix does not have empty row or column,
+ *
+ * Example with key steps
+ * \code
+ * VectorXd x(n), b(n);
+ * SparseMatrix<double> A;
+ * // fill A and b;
+ * Scaling<SparseMatrix<double> > scal;
+ * // Compute the left and right scaling vectors. The matrix is equilibrated at output
+ * scal.computeRef(A);
+ * // Scale the right hand side
+ * b = scal.LeftScaling().cwiseProduct(b);
+ * // Now, solve the equilibrated linear system with any available solver
+ *
+ * // Scale back the computed solution
+ * x = scal.RightScaling().cwiseProduct(x);
+ * \endcode
+ *
+ * \tparam _MatrixType the type of the matrix. It should be a real square sparsematrix
+ *
+ * References : D. Ruiz and B. Ucar, A Symmetry Preserving Algorithm for Matrix Scaling, INRIA Research report RR-7552
+ *
+ * \sa \ref IncompleteLUT
+ */
+using std::abs;
+using namespace Eigen;
+template<typename _MatrixType>
+class Scaling
+{
+ public:
+ typedef _MatrixType MatrixType;
+ typedef typename MatrixType::Scalar Scalar;
+ typedef typename MatrixType::Index Index;
+
+ public:
+ Scaling() { init(); }
+
+ Scaling(const MatrixType& matrix)
+ {
+ init();
+ compute(matrix);
+ }
+
+ ~Scaling() { }
+
+ /**
+ * Compute the left and right diagonal matrices to scale the input matrix @p mat
+ *
+ * FIXME This algorithm will be modified such that the diagonal elements are permuted on the diagonal.
+ *
+ * \sa LeftScaling() RightScaling()
+ */
+ void compute (const MatrixType& mat)
+ {
+ int m = mat.rows();
+ int n = mat.cols();
+ assert((m>0 && m == n) && "Please give a non - empty matrix");
+ m_left.resize(m);
+ m_right.resize(n);
+ m_left.setOnes();
+ m_right.setOnes();
+ m_matrix = mat;
+ VectorXd Dr, Dc, DrRes, DcRes; // Temporary Left and right scaling vectors
+ Dr.resize(m); Dc.resize(n);
+ DrRes.resize(m); DcRes.resize(n);
+ double EpsRow = 1.0, EpsCol = 1.0;
+ int its = 0;
+ do
+ { // Iterate until the infinite norm of each row and column is approximately 1
+ // Get the maximum value in each row and column
+ Dr.setZero(); Dc.setZero();
+ for (int k=0; k<m_matrix.outerSize(); ++k)
+ {
+ for (typename MatrixType::InnerIterator it(m_matrix, k); it; ++it)
+ {
+ if ( Dr(it.row()) < abs(it.value()) )
+ Dr(it.row()) = abs(it.value());
+
+ if ( Dc(it.col()) < abs(it.value()) )
+ Dc(it.col()) = abs(it.value());
+ }
+ }
+ for (int i = 0; i < m; ++i)
+ {
+ Dr(i) = std::sqrt(Dr(i));
+ Dc(i) = std::sqrt(Dc(i));
+ }
+ // Save the scaling factors
+ for (int i = 0; i < m; ++i)
+ {
+ m_left(i) /= Dr(i);
+ m_right(i) /= Dc(i);
+ }
+ // Scale the rows and the columns of the matrix
+ DrRes.setZero(); DcRes.setZero();
+ for (int k=0; k<m_matrix.outerSize(); ++k)
+ {
+ for (typename MatrixType::InnerIterator it(m_matrix, k); it; ++it)
+ {
+ it.valueRef() = it.value()/( Dr(it.row()) * Dc(it.col()) );
+ // Accumulate the norms of the row and column vectors
+ if ( DrRes(it.row()) < abs(it.value()) )
+ DrRes(it.row()) = abs(it.value());
+
+ if ( DcRes(it.col()) < abs(it.value()) )
+ DcRes(it.col()) = abs(it.value());
+ }
+ }
+ DrRes.array() = (1-DrRes.array()).abs();
+ EpsRow = DrRes.maxCoeff();
+ DcRes.array() = (1-DcRes.array()).abs();
+ EpsCol = DcRes.maxCoeff();
+ its++;
+ }while ( (EpsRow >m_tol || EpsCol > m_tol) && (its < m_maxits) );
+ m_isInitialized = true;
+ }
+ /** Compute the left and right vectors to scale the vectors
+ * the input matrix is scaled with the computed vectors at output
+ *
+ * \sa compute()
+ */
+ void computeRef (MatrixType& mat)
+ {
+ compute (mat);
+ mat = m_matrix;
+ }
+ /** Get the vector to scale the rows of the matrix
+ */
+ VectorXd& LeftScaling()
+ {
+ return m_left;
+ }
+
+ /** Get the vector to scale the columns of the matrix
+ */
+ VectorXd& RightScaling()
+ {
+ return m_right;
+ }
+
+ /** Set the tolerance for the convergence of the iterative scaling algorithm
+ */
+ void setTolerance(double tol)
+ {
+ m_tol = tol;
+ }
+
+ protected:
+
+ void init()
+ {
+ m_tol = 1e-10;
+ m_maxits = 5;
+ m_isInitialized = false;
+ }
+
+ MatrixType m_matrix;
+ mutable ComputationInfo m_info;
+ bool m_isInitialized;
+ VectorXd m_left; // Left scaling vector
+ VectorXd m_right; // m_right scaling vector
+ double m_tol;
+ int m_maxits; // Maximum number of iterations allowed
+};
+
+#endif \ No newline at end of file
diff --git a/unsupported/Eigen/src/KroneckerProduct/CMakeLists.txt b/unsupported/Eigen/src/KroneckerProduct/CMakeLists.txt
new file mode 100644
index 000000000..4daefebee
--- /dev/null
+++ b/unsupported/Eigen/src/KroneckerProduct/CMakeLists.txt
@@ -0,0 +1,6 @@
+FILE(GLOB Eigen_KroneckerProduct_SRCS "*.h")
+
+INSTALL(FILES
+ ${Eigen_KroneckerProduct_SRCS}
+ DESTINATION ${INCLUDE_INSTALL_DIR}/unsupported/Eigen/src/KroneckerProduct COMPONENT Devel
+ )
diff --git a/unsupported/Eigen/src/KroneckerProduct/KroneckerTensorProduct.h b/unsupported/Eigen/src/KroneckerProduct/KroneckerTensorProduct.h
new file mode 100644
index 000000000..84fd72fc6
--- /dev/null
+++ b/unsupported/Eigen/src/KroneckerProduct/KroneckerTensorProduct.h
@@ -0,0 +1,157 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra.
+//
+// Copyright (C) 2011 Kolja Brix <brix@igpm.rwth-aachen.de>
+// Copyright (C) 2011 Andreas Platen <andiplaten@gmx.de>
+//
+// This Source Code Form is subject to the terms of the Mozilla
+// Public License v. 2.0. If a copy of the MPL was not distributed
+// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+
+#ifndef KRONECKER_TENSOR_PRODUCT_H
+#define KRONECKER_TENSOR_PRODUCT_H
+
+
+namespace Eigen {
+
+namespace internal {
+
+/*!
+ * Kronecker tensor product helper function for dense matrices
+ *
+ * \param A Dense matrix A
+ * \param B Dense matrix B
+ * \param AB_ Kronecker tensor product of A and B
+ */
+template<typename Derived_A, typename Derived_B, typename Derived_AB>
+void kroneckerProduct_full(const Derived_A& A, const Derived_B& B, Derived_AB & AB)
+{
+ const unsigned int Ar = A.rows(),
+ Ac = A.cols(),
+ Br = B.rows(),
+ Bc = B.cols();
+ for (unsigned int i=0; i<Ar; ++i)
+ for (unsigned int j=0; j<Ac; ++j)
+ AB.block(i*Br,j*Bc,Br,Bc) = A(i,j)*B;
+}
+
+
+/*!
+ * Kronecker tensor product helper function for matrices, where at least one is sparse
+ *
+ * \param A Matrix A
+ * \param B Matrix B
+ * \param AB_ Kronecker tensor product of A and B
+ */
+template<typename Derived_A, typename Derived_B, typename Derived_AB>
+void kroneckerProduct_sparse(const Derived_A &A, const Derived_B &B, Derived_AB &AB)
+{
+ const unsigned int Ar = A.rows(),
+ Ac = A.cols(),
+ Br = B.rows(),
+ Bc = B.cols();
+ AB.resize(Ar*Br,Ac*Bc);
+ AB.resizeNonZeros(0);
+ AB.reserve(A.nonZeros()*B.nonZeros());
+
+ for (int kA=0; kA<A.outerSize(); ++kA)
+ {
+ for (int kB=0; kB<B.outerSize(); ++kB)
+ {
+ for (typename Derived_A::InnerIterator itA(A,kA); itA; ++itA)
+ {
+ for (typename Derived_B::InnerIterator itB(B,kB); itB; ++itB)
+ {
+ const unsigned int iA = itA.row(),
+ jA = itA.col(),
+ iB = itB.row(),
+ jB = itB.col(),
+ i = iA*Br + iB,
+ j = jA*Bc + jB;
+ AB.insert(i,j) = itA.value() * itB.value();
+ }
+ }
+ }
+ }
+}
+
+} // end namespace internal
+
+
+
+/*!
+ * Computes Kronecker tensor product of two dense matrices
+ *
+ * \param a Dense matrix a
+ * \param b Dense matrix b
+ * \param c Kronecker tensor product of a and b
+ */
+template<typename A,typename B,typename CScalar,int CRows,int CCols, int COptions, int CMaxRows, int CMaxCols>
+void kroneckerProduct(const MatrixBase<A>& a, const MatrixBase<B>& b, Matrix<CScalar,CRows,CCols,COptions,CMaxRows,CMaxCols>& c)
+{
+ c.resize(a.rows()*b.rows(),a.cols()*b.cols());
+ internal::kroneckerProduct_full(a.derived(), b.derived(), c);
+}
+
+/*!
+ * Computes Kronecker tensor product of two dense matrices
+ *
+ * Remark: this function uses the const cast hack and has been
+ * implemented to make the function call possible, where the
+ * output matrix is a submatrix, e.g.
+ * kroneckerProduct(A,B,AB.block(2,5,6,6));
+ *
+ * \param a Dense matrix a
+ * \param b Dense matrix b
+ * \param c Kronecker tensor product of a and b
+ */
+template<typename A,typename B,typename C>
+void kroneckerProduct(const MatrixBase<A>& a, const MatrixBase<B>& b, MatrixBase<C> const & c_)
+{
+ MatrixBase<C>& c = const_cast<MatrixBase<C>& >(c_);
+ internal::kroneckerProduct_full(a.derived(), b.derived(), c.derived());
+}
+
+/*!
+ * Computes Kronecker tensor product of a dense and a sparse matrix
+ *
+ * \param a Dense matrix a
+ * \param b Sparse matrix b
+ * \param c Kronecker tensor product of a and b
+ */
+template<typename A,typename B,typename C>
+void kroneckerProduct(const MatrixBase<A>& a, const SparseMatrixBase<B>& b, SparseMatrixBase<C>& c)
+{
+ internal::kroneckerProduct_sparse(a.derived(), b.derived(), c.derived());
+}
+
+/*!
+ * Computes Kronecker tensor product of a sparse and a dense matrix
+ *
+ * \param a Sparse matrix a
+ * \param b Dense matrix b
+ * \param c Kronecker tensor product of a and b
+ */
+template<typename A,typename B,typename C>
+void kroneckerProduct(const SparseMatrixBase<A>& a, const MatrixBase<B>& b, SparseMatrixBase<C>& c)
+{
+ internal::kroneckerProduct_sparse(a.derived(), b.derived(), c.derived());
+}
+
+/*!
+ * Computes Kronecker tensor product of two sparse matrices
+ *
+ * \param a Sparse matrix a
+ * \param b Sparse matrix b
+ * \param c Kronecker tensor product of a and b
+ */
+template<typename A,typename B,typename C>
+void kroneckerProduct(const SparseMatrixBase<A>& a, const SparseMatrixBase<B>& b, SparseMatrixBase<C>& c)
+{
+ internal::kroneckerProduct_sparse(a.derived(), b.derived(), c.derived());
+}
+
+} // end namespace Eigen
+
+#endif // KRONECKER_TENSOR_PRODUCT_H
diff --git a/unsupported/Eigen/src/MatrixFunctions/CMakeLists.txt b/unsupported/Eigen/src/MatrixFunctions/CMakeLists.txt
new file mode 100644
index 000000000..cdde64d2c
--- /dev/null
+++ b/unsupported/Eigen/src/MatrixFunctions/CMakeLists.txt
@@ -0,0 +1,6 @@
+FILE(GLOB Eigen_MatrixFunctions_SRCS "*.h")
+
+INSTALL(FILES
+ ${Eigen_MatrixFunctions_SRCS}
+ DESTINATION ${INCLUDE_INSTALL_DIR}/unsupported/Eigen/src/MatrixFunctions COMPONENT Devel
+ )
diff --git a/unsupported/Eigen/src/MatrixFunctions/MatrixExponential.h b/unsupported/Eigen/src/MatrixFunctions/MatrixExponential.h
new file mode 100644
index 000000000..642916764
--- /dev/null
+++ b/unsupported/Eigen/src/MatrixFunctions/MatrixExponential.h
@@ -0,0 +1,454 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra.
+//
+// Copyright (C) 2009, 2010 Jitse Niesen <jitse@maths.leeds.ac.uk>
+// Copyright (C) 2011 Chen-Pang He <jdh8@ms63.hinet.net>
+//
+// This Source Code Form is subject to the terms of the Mozilla
+// Public License v. 2.0. If a copy of the MPL was not distributed
+// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+#ifndef EIGEN_MATRIX_EXPONENTIAL
+#define EIGEN_MATRIX_EXPONENTIAL
+
+#include "StemFunction.h"
+
+namespace Eigen {
+
+#if defined(_MSC_VER) || defined(__FreeBSD__)
+ template <typename Scalar> Scalar log2(Scalar v) { using std::log; return log(v)/log(Scalar(2)); }
+#endif
+
+
+/** \ingroup MatrixFunctions_Module
+ * \brief Class for computing the matrix exponential.
+ * \tparam MatrixType type of the argument of the exponential,
+ * expected to be an instantiation of the Matrix class template.
+ */
+template <typename MatrixType>
+class MatrixExponential {
+
+ public:
+
+ /** \brief Constructor.
+ *
+ * The class stores a reference to \p M, so it should not be
+ * changed (or destroyed) before compute() is called.
+ *
+ * \param[in] M matrix whose exponential is to be computed.
+ */
+ MatrixExponential(const MatrixType &M);
+
+ /** \brief Computes the matrix exponential.
+ *
+ * \param[out] result the matrix exponential of \p M in the constructor.
+ */
+ template <typename ResultType>
+ void compute(ResultType &result);
+
+ private:
+
+ // Prevent copying
+ MatrixExponential(const MatrixExponential&);
+ MatrixExponential& operator=(const MatrixExponential&);
+
+ /** \brief Compute the (3,3)-Pad&eacute; approximant to the exponential.
+ *
+ * After exit, \f$ (V+U)(V-U)^{-1} \f$ is the Pad&eacute;
+ * approximant of \f$ \exp(A) \f$ around \f$ A = 0 \f$.
+ *
+ * \param[in] A Argument of matrix exponential
+ */
+ void pade3(const MatrixType &A);
+
+ /** \brief Compute the (5,5)-Pad&eacute; approximant to the exponential.
+ *
+ * After exit, \f$ (V+U)(V-U)^{-1} \f$ is the Pad&eacute;
+ * approximant of \f$ \exp(A) \f$ around \f$ A = 0 \f$.
+ *
+ * \param[in] A Argument of matrix exponential
+ */
+ void pade5(const MatrixType &A);
+
+ /** \brief Compute the (7,7)-Pad&eacute; approximant to the exponential.
+ *
+ * After exit, \f$ (V+U)(V-U)^{-1} \f$ is the Pad&eacute;
+ * approximant of \f$ \exp(A) \f$ around \f$ A = 0 \f$.
+ *
+ * \param[in] A Argument of matrix exponential
+ */
+ void pade7(const MatrixType &A);
+
+ /** \brief Compute the (9,9)-Pad&eacute; approximant to the exponential.
+ *
+ * After exit, \f$ (V+U)(V-U)^{-1} \f$ is the Pad&eacute;
+ * approximant of \f$ \exp(A) \f$ around \f$ A = 0 \f$.
+ *
+ * \param[in] A Argument of matrix exponential
+ */
+ void pade9(const MatrixType &A);
+
+ /** \brief Compute the (13,13)-Pad&eacute; approximant to the exponential.
+ *
+ * After exit, \f$ (V+U)(V-U)^{-1} \f$ is the Pad&eacute;
+ * approximant of \f$ \exp(A) \f$ around \f$ A = 0 \f$.
+ *
+ * \param[in] A Argument of matrix exponential
+ */
+ void pade13(const MatrixType &A);
+
+ /** \brief Compute the (17,17)-Pad&eacute; approximant to the exponential.
+ *
+ * After exit, \f$ (V+U)(V-U)^{-1} \f$ is the Pad&eacute;
+ * approximant of \f$ \exp(A) \f$ around \f$ A = 0 \f$.
+ *
+ * This function activates only if your long double is double-double or quadruple.
+ *
+ * \param[in] A Argument of matrix exponential
+ */
+ void pade17(const MatrixType &A);
+
+ /** \brief Compute Pad&eacute; approximant to the exponential.
+ *
+ * Computes \c m_U, \c m_V and \c m_squarings such that
+ * \f$ (V+U)(V-U)^{-1} \f$ is a Pad&eacute; of
+ * \f$ \exp(2^{-\mbox{squarings}}M) \f$ around \f$ M = 0 \f$. The
+ * degree of the Pad&eacute; approximant and the value of
+ * squarings are chosen such that the approximation error is no
+ * more than the round-off error.
+ *
+ * The argument of this function should correspond with the (real
+ * part of) the entries of \c m_M. It is used to select the
+ * correct implementation using overloading.
+ */
+ void computeUV(double);
+
+ /** \brief Compute Pad&eacute; approximant to the exponential.
+ *
+ * \sa computeUV(double);
+ */
+ void computeUV(float);
+
+ /** \brief Compute Pad&eacute; approximant to the exponential.
+ *
+ * \sa computeUV(double);
+ */
+ void computeUV(long double);
+
+ typedef typename internal::traits<MatrixType>::Scalar Scalar;
+ typedef typename NumTraits<Scalar>::Real RealScalar;
+ typedef typename std::complex<RealScalar> ComplexScalar;
+
+ /** \brief Reference to matrix whose exponential is to be computed. */
+ typename internal::nested<MatrixType>::type m_M;
+
+ /** \brief Odd-degree terms in numerator of Pad&eacute; approximant. */
+ MatrixType m_U;
+
+ /** \brief Even-degree terms in numerator of Pad&eacute; approximant. */
+ MatrixType m_V;
+
+ /** \brief Used for temporary storage. */
+ MatrixType m_tmp1;
+
+ /** \brief Used for temporary storage. */
+ MatrixType m_tmp2;
+
+ /** \brief Identity matrix of the same size as \c m_M. */
+ MatrixType m_Id;
+
+ /** \brief Number of squarings required in the last step. */
+ int m_squarings;
+
+ /** \brief L1 norm of m_M. */
+ RealScalar m_l1norm;
+};
+
+template <typename MatrixType>
+MatrixExponential<MatrixType>::MatrixExponential(const MatrixType &M) :
+ m_M(M),
+ m_U(M.rows(),M.cols()),
+ m_V(M.rows(),M.cols()),
+ m_tmp1(M.rows(),M.cols()),
+ m_tmp2(M.rows(),M.cols()),
+ m_Id(MatrixType::Identity(M.rows(), M.cols())),
+ m_squarings(0),
+ m_l1norm(M.cwiseAbs().colwise().sum().maxCoeff())
+{
+ /* empty body */
+}
+
+template <typename MatrixType>
+template <typename ResultType>
+void MatrixExponential<MatrixType>::compute(ResultType &result)
+{
+#if LDBL_MANT_DIG > 112 // rarely happens
+ if(sizeof(RealScalar) > 14) {
+ result = m_M.matrixFunction(StdStemFunctions<ComplexScalar>::exp);
+ return;
+ }
+#endif
+ computeUV(RealScalar());
+ m_tmp1 = m_U + m_V; // numerator of Pade approximant
+ m_tmp2 = -m_U + m_V; // denominator of Pade approximant
+ result = m_tmp2.partialPivLu().solve(m_tmp1);
+ for (int i=0; i<m_squarings; i++)
+ result *= result; // undo scaling by repeated squaring
+}
+
+template <typename MatrixType>
+EIGEN_STRONG_INLINE void MatrixExponential<MatrixType>::pade3(const MatrixType &A)
+{
+ const RealScalar b[] = {120., 60., 12., 1.};
+ m_tmp1.noalias() = A * A;
+ m_tmp2 = b[3]*m_tmp1 + b[1]*m_Id;
+ m_U.noalias() = A * m_tmp2;
+ m_V = b[2]*m_tmp1 + b[0]*m_Id;
+}
+
+template <typename MatrixType>
+EIGEN_STRONG_INLINE void MatrixExponential<MatrixType>::pade5(const MatrixType &A)
+{
+ const RealScalar b[] = {30240., 15120., 3360., 420., 30., 1.};
+ MatrixType A2 = A * A;
+ m_tmp1.noalias() = A2 * A2;
+ m_tmp2 = b[5]*m_tmp1 + b[3]*A2 + b[1]*m_Id;
+ m_U.noalias() = A * m_tmp2;
+ m_V = b[4]*m_tmp1 + b[2]*A2 + b[0]*m_Id;
+}
+
+template <typename MatrixType>
+EIGEN_STRONG_INLINE void MatrixExponential<MatrixType>::pade7(const MatrixType &A)
+{
+ const RealScalar b[] = {17297280., 8648640., 1995840., 277200., 25200., 1512., 56., 1.};
+ MatrixType A2 = A * A;
+ MatrixType A4 = A2 * A2;
+ m_tmp1.noalias() = A4 * A2;
+ m_tmp2 = b[7]*m_tmp1 + b[5]*A4 + b[3]*A2 + b[1]*m_Id;
+ m_U.noalias() = A * m_tmp2;
+ m_V = b[6]*m_tmp1 + b[4]*A4 + b[2]*A2 + b[0]*m_Id;
+}
+
+template <typename MatrixType>
+EIGEN_STRONG_INLINE void MatrixExponential<MatrixType>::pade9(const MatrixType &A)
+{
+ const RealScalar b[] = {17643225600., 8821612800., 2075673600., 302702400., 30270240.,
+ 2162160., 110880., 3960., 90., 1.};
+ MatrixType A2 = A * A;
+ MatrixType A4 = A2 * A2;
+ MatrixType A6 = A4 * A2;
+ m_tmp1.noalias() = A6 * A2;
+ m_tmp2 = b[9]*m_tmp1 + b[7]*A6 + b[5]*A4 + b[3]*A2 + b[1]*m_Id;
+ m_U.noalias() = A * m_tmp2;
+ m_V = b[8]*m_tmp1 + b[6]*A6 + b[4]*A4 + b[2]*A2 + b[0]*m_Id;
+}
+
+template <typename MatrixType>
+EIGEN_STRONG_INLINE void MatrixExponential<MatrixType>::pade13(const MatrixType &A)
+{
+ const RealScalar b[] = {64764752532480000., 32382376266240000., 7771770303897600.,
+ 1187353796428800., 129060195264000., 10559470521600., 670442572800.,
+ 33522128640., 1323241920., 40840800., 960960., 16380., 182., 1.};
+ MatrixType A2 = A * A;
+ MatrixType A4 = A2 * A2;
+ m_tmp1.noalias() = A4 * A2;
+ m_V = b[13]*m_tmp1 + b[11]*A4 + b[9]*A2; // used for temporary storage
+ m_tmp2.noalias() = m_tmp1 * m_V;
+ m_tmp2 += b[7]*m_tmp1 + b[5]*A4 + b[3]*A2 + b[1]*m_Id;
+ m_U.noalias() = A * m_tmp2;
+ m_tmp2 = b[12]*m_tmp1 + b[10]*A4 + b[8]*A2;
+ m_V.noalias() = m_tmp1 * m_tmp2;
+ m_V += b[6]*m_tmp1 + b[4]*A4 + b[2]*A2 + b[0]*m_Id;
+}
+
+#if LDBL_MANT_DIG > 64
+template <typename MatrixType>
+EIGEN_STRONG_INLINE void MatrixExponential<MatrixType>::pade17(const MatrixType &A)
+{
+ const RealScalar b[] = {830034394580628357120000.L, 415017197290314178560000.L,
+ 100610229646136770560000.L, 15720348382208870400000.L,
+ 1774878043152614400000.L, 153822763739893248000.L, 10608466464820224000.L,
+ 595373117923584000.L, 27563570274240000.L, 1060137318240000.L,
+ 33924394183680.L, 899510451840.L, 19554575040.L, 341863200.L, 4651200.L,
+ 46512.L, 306.L, 1.L};
+ MatrixType A2 = A * A;
+ MatrixType A4 = A2 * A2;
+ MatrixType A6 = A4 * A2;
+ m_tmp1.noalias() = A4 * A4;
+ m_V = b[17]*m_tmp1 + b[15]*A6 + b[13]*A4 + b[11]*A2; // used for temporary storage
+ m_tmp2.noalias() = m_tmp1 * m_V;
+ m_tmp2 += b[9]*m_tmp1 + b[7]*A6 + b[5]*A4 + b[3]*A2 + b[1]*m_Id;
+ m_U.noalias() = A * m_tmp2;
+ m_tmp2 = b[16]*m_tmp1 + b[14]*A6 + b[12]*A4 + b[10]*A2;
+ m_V.noalias() = m_tmp1 * m_tmp2;
+ m_V += b[8]*m_tmp1 + b[6]*A6 + b[4]*A4 + b[2]*A2 + b[0]*m_Id;
+}
+#endif
+
+template <typename MatrixType>
+void MatrixExponential<MatrixType>::computeUV(float)
+{
+ using std::max;
+ using std::pow;
+ using std::ceil;
+ if (m_l1norm < 4.258730016922831e-001) {
+ pade3(m_M);
+ } else if (m_l1norm < 1.880152677804762e+000) {
+ pade5(m_M);
+ } else {
+ const float maxnorm = 3.925724783138660f;
+ m_squarings = (max)(0, (int)ceil(log2(m_l1norm / maxnorm)));
+ MatrixType A = m_M / pow(Scalar(2), m_squarings);
+ pade7(A);
+ }
+}
+
+template <typename MatrixType>
+void MatrixExponential<MatrixType>::computeUV(double)
+{
+ using std::max;
+ using std::pow;
+ using std::ceil;
+ if (m_l1norm < 1.495585217958292e-002) {
+ pade3(m_M);
+ } else if (m_l1norm < 2.539398330063230e-001) {
+ pade5(m_M);
+ } else if (m_l1norm < 9.504178996162932e-001) {
+ pade7(m_M);
+ } else if (m_l1norm < 2.097847961257068e+000) {
+ pade9(m_M);
+ } else {
+ const double maxnorm = 5.371920351148152;
+ m_squarings = (max)(0, (int)ceil(log2(m_l1norm / maxnorm)));
+ MatrixType A = m_M / pow(Scalar(2), m_squarings);
+ pade13(A);
+ }
+}
+
+template <typename MatrixType>
+void MatrixExponential<MatrixType>::computeUV(long double)
+{
+ using std::max;
+ using std::pow;
+ using std::ceil;
+#if LDBL_MANT_DIG == 53 // double precision
+ computeUV(double());
+#elif LDBL_MANT_DIG <= 64 // extended precision
+ if (m_l1norm < 4.1968497232266989671e-003L) {
+ pade3(m_M);
+ } else if (m_l1norm < 1.1848116734693823091e-001L) {
+ pade5(m_M);
+ } else if (m_l1norm < 5.5170388480686700274e-001L) {
+ pade7(m_M);
+ } else if (m_l1norm < 1.3759868875587845383e+000L) {
+ pade9(m_M);
+ } else {
+ const long double maxnorm = 4.0246098906697353063L;
+ m_squarings = (max)(0, (int)ceil(log2(m_l1norm / maxnorm)));
+ MatrixType A = m_M / pow(Scalar(2), m_squarings);
+ pade13(A);
+ }
+#elif LDBL_MANT_DIG <= 106 // double-double
+ if (m_l1norm < 3.2787892205607026992947488108213e-005L) {
+ pade3(m_M);
+ } else if (m_l1norm < 6.4467025060072760084130906076332e-003L) {
+ pade5(m_M);
+ } else if (m_l1norm < 6.8988028496595374751374122881143e-002L) {
+ pade7(m_M);
+ } else if (m_l1norm < 2.7339737518502231741495857201670e-001L) {
+ pade9(m_M);
+ } else if (m_l1norm < 1.3203382096514474905666448850278e+000L) {
+ pade13(m_M);
+ } else {
+ const long double maxnorm = 3.2579440895405400856599663723517L;
+ m_squarings = (max)(0, (int)ceil(log2(m_l1norm / maxnorm)));
+ MatrixType A = m_M / pow(Scalar(2), m_squarings);
+ pade17(A);
+ }
+#elif LDBL_MANT_DIG <= 112 // quadruple precison
+ if (m_l1norm < 1.639394610288918690547467954466970e-005L) {
+ pade3(m_M);
+ } else if (m_l1norm < 4.253237712165275566025884344433009e-003L) {
+ pade5(m_M);
+ } else if (m_l1norm < 5.125804063165764409885122032933142e-002L) {
+ pade7(m_M);
+ } else if (m_l1norm < 2.170000765161155195453205651889853e-001L) {
+ pade9(m_M);
+ } else if (m_l1norm < 1.125358383453143065081397882891878e+000L) {
+ pade13(m_M);
+ } else {
+ const long double maxnorm = 2.884233277829519311757165057717815L;
+ m_squarings = (max)(0, (int)ceil(log2(m_l1norm / maxnorm)));
+ MatrixType A = m_M / pow(Scalar(2), m_squarings);
+ pade17(A);
+ }
+#else
+ // this case should be handled in compute()
+ eigen_assert(false && "Bug in MatrixExponential");
+#endif // LDBL_MANT_DIG
+}
+
+/** \ingroup MatrixFunctions_Module
+ *
+ * \brief Proxy for the matrix exponential of some matrix (expression).
+ *
+ * \tparam Derived Type of the argument to the matrix exponential.
+ *
+ * This class holds the argument to the matrix exponential until it
+ * is assigned or evaluated for some other reason (so the argument
+ * should not be changed in the meantime). It is the return type of
+ * MatrixBase::exp() and most of the time this is the only way it is
+ * used.
+ */
+template<typename Derived> struct MatrixExponentialReturnValue
+: public ReturnByValue<MatrixExponentialReturnValue<Derived> >
+{
+ typedef typename Derived::Index Index;
+ public:
+ /** \brief Constructor.
+ *
+ * \param[in] src %Matrix (expression) forming the argument of the
+ * matrix exponential.
+ */
+ MatrixExponentialReturnValue(const Derived& src) : m_src(src) { }
+
+ /** \brief Compute the matrix exponential.
+ *
+ * \param[out] result the matrix exponential of \p src in the
+ * constructor.
+ */
+ template <typename ResultType>
+ inline void evalTo(ResultType& result) const
+ {
+ const typename Derived::PlainObject srcEvaluated = m_src.eval();
+ MatrixExponential<typename Derived::PlainObject> me(srcEvaluated);
+ me.compute(result);
+ }
+
+ Index rows() const { return m_src.rows(); }
+ Index cols() const { return m_src.cols(); }
+
+ protected:
+ const Derived& m_src;
+ private:
+ MatrixExponentialReturnValue& operator=(const MatrixExponentialReturnValue&);
+};
+
+namespace internal {
+template<typename Derived>
+struct traits<MatrixExponentialReturnValue<Derived> >
+{
+ typedef typename Derived::PlainObject ReturnType;
+};
+}
+
+template <typename Derived>
+const MatrixExponentialReturnValue<Derived> MatrixBase<Derived>::exp() const
+{
+ eigen_assert(rows() == cols());
+ return MatrixExponentialReturnValue<Derived>(derived());
+}
+
+} // end namespace Eigen
+
+#endif // EIGEN_MATRIX_EXPONENTIAL
diff --git a/unsupported/Eigen/src/MatrixFunctions/MatrixFunction.h b/unsupported/Eigen/src/MatrixFunctions/MatrixFunction.h
new file mode 100644
index 000000000..c57ca87ed
--- /dev/null
+++ b/unsupported/Eigen/src/MatrixFunctions/MatrixFunction.h
@@ -0,0 +1,590 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra.
+//
+// Copyright (C) 2009-2011 Jitse Niesen <jitse@maths.leeds.ac.uk>
+//
+// This Source Code Form is subject to the terms of the Mozilla
+// Public License v. 2.0. If a copy of the MPL was not distributed
+// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+#ifndef EIGEN_MATRIX_FUNCTION
+#define EIGEN_MATRIX_FUNCTION
+
+#include "StemFunction.h"
+#include "MatrixFunctionAtomic.h"
+
+
+namespace Eigen {
+
+/** \ingroup MatrixFunctions_Module
+ * \brief Class for computing matrix functions.
+ * \tparam MatrixType type of the argument of the matrix function,
+ * expected to be an instantiation of the Matrix class template.
+ * \tparam AtomicType type for computing matrix function of atomic blocks.
+ * \tparam IsComplex used internally to select correct specialization.
+ *
+ * This class implements the Schur-Parlett algorithm for computing matrix functions. The spectrum of the
+ * matrix is divided in clustered of eigenvalues that lies close together. This class delegates the
+ * computation of the matrix function on every block corresponding to these clusters to an object of type
+ * \p AtomicType and uses these results to compute the matrix function of the whole matrix. The class
+ * \p AtomicType should have a \p compute() member function for computing the matrix function of a block.
+ *
+ * \sa class MatrixFunctionAtomic, class MatrixLogarithmAtomic
+ */
+template <typename MatrixType,
+ typename AtomicType,
+ int IsComplex = NumTraits<typename internal::traits<MatrixType>::Scalar>::IsComplex>
+class MatrixFunction
+{
+ public:
+
+ /** \brief Constructor.
+ *
+ * \param[in] A argument of matrix function, should be a square matrix.
+ * \param[in] atomic class for computing matrix function of atomic blocks.
+ *
+ * The class stores references to \p A and \p atomic, so they should not be
+ * changed (or destroyed) before compute() is called.
+ */
+ MatrixFunction(const MatrixType& A, AtomicType& atomic);
+
+ /** \brief Compute the matrix function.
+ *
+ * \param[out] result the function \p f applied to \p A, as
+ * specified in the constructor.
+ *
+ * See MatrixBase::matrixFunction() for details on how this computation
+ * is implemented.
+ */
+ template <typename ResultType>
+ void compute(ResultType &result);
+};
+
+
+/** \internal \ingroup MatrixFunctions_Module
+ * \brief Partial specialization of MatrixFunction for real matrices
+ */
+template <typename MatrixType, typename AtomicType>
+class MatrixFunction<MatrixType, AtomicType, 0>
+{
+ private:
+
+ typedef internal::traits<MatrixType> Traits;
+ typedef typename Traits::Scalar Scalar;
+ static const int Rows = Traits::RowsAtCompileTime;
+ static const int Cols = Traits::ColsAtCompileTime;
+ static const int Options = MatrixType::Options;
+ static const int MaxRows = Traits::MaxRowsAtCompileTime;
+ static const int MaxCols = Traits::MaxColsAtCompileTime;
+
+ typedef std::complex<Scalar> ComplexScalar;
+ typedef Matrix<ComplexScalar, Rows, Cols, Options, MaxRows, MaxCols> ComplexMatrix;
+
+ public:
+
+ /** \brief Constructor.
+ *
+ * \param[in] A argument of matrix function, should be a square matrix.
+ * \param[in] atomic class for computing matrix function of atomic blocks.
+ */
+ MatrixFunction(const MatrixType& A, AtomicType& atomic) : m_A(A), m_atomic(atomic) { }
+
+ /** \brief Compute the matrix function.
+ *
+ * \param[out] result the function \p f applied to \p A, as
+ * specified in the constructor.
+ *
+ * This function converts the real matrix \c A to a complex matrix,
+ * uses MatrixFunction<MatrixType,1> and then converts the result back to
+ * a real matrix.
+ */
+ template <typename ResultType>
+ void compute(ResultType& result)
+ {
+ ComplexMatrix CA = m_A.template cast<ComplexScalar>();
+ ComplexMatrix Cresult;
+ MatrixFunction<ComplexMatrix, AtomicType> mf(CA, m_atomic);
+ mf.compute(Cresult);
+ result = Cresult.real();
+ }
+
+ private:
+ typename internal::nested<MatrixType>::type m_A; /**< \brief Reference to argument of matrix function. */
+ AtomicType& m_atomic; /**< \brief Class for computing matrix function of atomic blocks. */
+
+ MatrixFunction& operator=(const MatrixFunction&);
+};
+
+
+/** \internal \ingroup MatrixFunctions_Module
+ * \brief Partial specialization of MatrixFunction for complex matrices
+ */
+template <typename MatrixType, typename AtomicType>
+class MatrixFunction<MatrixType, AtomicType, 1>
+{
+ private:
+
+ typedef internal::traits<MatrixType> Traits;
+ typedef typename MatrixType::Scalar Scalar;
+ typedef typename MatrixType::Index Index;
+ static const int RowsAtCompileTime = Traits::RowsAtCompileTime;
+ static const int ColsAtCompileTime = Traits::ColsAtCompileTime;
+ static const int Options = MatrixType::Options;
+ typedef typename NumTraits<Scalar>::Real RealScalar;
+ typedef Matrix<Scalar, Traits::RowsAtCompileTime, 1> VectorType;
+ typedef Matrix<Index, Traits::RowsAtCompileTime, 1> IntVectorType;
+ typedef Matrix<Index, Dynamic, 1> DynamicIntVectorType;
+ typedef std::list<Scalar> Cluster;
+ typedef std::list<Cluster> ListOfClusters;
+ typedef Matrix<Scalar, Dynamic, Dynamic, Options, RowsAtCompileTime, ColsAtCompileTime> DynMatrixType;
+
+ public:
+
+ MatrixFunction(const MatrixType& A, AtomicType& atomic);
+ template <typename ResultType> void compute(ResultType& result);
+
+ private:
+
+ void computeSchurDecomposition();
+ void partitionEigenvalues();
+ typename ListOfClusters::iterator findCluster(Scalar key);
+ void computeClusterSize();
+ void computeBlockStart();
+ void constructPermutation();
+ void permuteSchur();
+ void swapEntriesInSchur(Index index);
+ void computeBlockAtomic();
+ Block<MatrixType> block(MatrixType& A, Index i, Index j);
+ void computeOffDiagonal();
+ DynMatrixType solveTriangularSylvester(const DynMatrixType& A, const DynMatrixType& B, const DynMatrixType& C);
+
+ typename internal::nested<MatrixType>::type m_A; /**< \brief Reference to argument of matrix function. */
+ AtomicType& m_atomic; /**< \brief Class for computing matrix function of atomic blocks. */
+ MatrixType m_T; /**< \brief Triangular part of Schur decomposition */
+ MatrixType m_U; /**< \brief Unitary part of Schur decomposition */
+ MatrixType m_fT; /**< \brief %Matrix function applied to #m_T */
+ ListOfClusters m_clusters; /**< \brief Partition of eigenvalues into clusters of ei'vals "close" to each other */
+ DynamicIntVectorType m_eivalToCluster; /**< \brief m_eivalToCluster[i] = j means i-th ei'val is in j-th cluster */
+ DynamicIntVectorType m_clusterSize; /**< \brief Number of eigenvalues in each clusters */
+ DynamicIntVectorType m_blockStart; /**< \brief Row index at which block corresponding to i-th cluster starts */
+ IntVectorType m_permutation; /**< \brief Permutation which groups ei'vals in the same cluster together */
+
+ /** \brief Maximum distance allowed between eigenvalues to be considered "close".
+ *
+ * This is morally a \c static \c const \c Scalar, but only
+ * integers can be static constant class members in C++. The
+ * separation constant is set to 0.1, a value taken from the
+ * paper by Davies and Higham. */
+ static const RealScalar separation() { return static_cast<RealScalar>(0.1); }
+
+ MatrixFunction& operator=(const MatrixFunction&);
+};
+
+/** \brief Constructor.
+ *
+ * \param[in] A argument of matrix function, should be a square matrix.
+ * \param[in] atomic class for computing matrix function of atomic blocks.
+ */
+template <typename MatrixType, typename AtomicType>
+MatrixFunction<MatrixType,AtomicType,1>::MatrixFunction(const MatrixType& A, AtomicType& atomic)
+ : m_A(A), m_atomic(atomic)
+{
+ /* empty body */
+}
+
+/** \brief Compute the matrix function.
+ *
+ * \param[out] result the function \p f applied to \p A, as
+ * specified in the constructor.
+ */
+template <typename MatrixType, typename AtomicType>
+template <typename ResultType>
+void MatrixFunction<MatrixType,AtomicType,1>::compute(ResultType& result)
+{
+ computeSchurDecomposition();
+ partitionEigenvalues();
+ computeClusterSize();
+ computeBlockStart();
+ constructPermutation();
+ permuteSchur();
+ computeBlockAtomic();
+ computeOffDiagonal();
+ result = m_U * m_fT * m_U.adjoint();
+}
+
+/** \brief Store the Schur decomposition of #m_A in #m_T and #m_U */
+template <typename MatrixType, typename AtomicType>
+void MatrixFunction<MatrixType,AtomicType,1>::computeSchurDecomposition()
+{
+ const ComplexSchur<MatrixType> schurOfA(m_A);
+ m_T = schurOfA.matrixT();
+ m_U = schurOfA.matrixU();
+}
+
+/** \brief Partition eigenvalues in clusters of ei'vals close to each other
+ *
+ * This function computes #m_clusters. This is a partition of the
+ * eigenvalues of #m_T in clusters, such that
+ * # Any eigenvalue in a certain cluster is at most separation() away
+ * from another eigenvalue in the same cluster.
+ * # The distance between two eigenvalues in different clusters is
+ * more than separation().
+ * The implementation follows Algorithm 4.1 in the paper of Davies
+ * and Higham.
+ */
+template <typename MatrixType, typename AtomicType>
+void MatrixFunction<MatrixType,AtomicType,1>::partitionEigenvalues()
+{
+ const Index rows = m_T.rows();
+ VectorType diag = m_T.diagonal(); // contains eigenvalues of A
+
+ for (Index i=0; i<rows; ++i) {
+ // Find set containing diag(i), adding a new set if necessary
+ typename ListOfClusters::iterator qi = findCluster(diag(i));
+ if (qi == m_clusters.end()) {
+ Cluster l;
+ l.push_back(diag(i));
+ m_clusters.push_back(l);
+ qi = m_clusters.end();
+ --qi;
+ }
+
+ // Look for other element to add to the set
+ for (Index j=i+1; j<rows; ++j) {
+ if (internal::abs(diag(j) - diag(i)) <= separation() && std::find(qi->begin(), qi->end(), diag(j)) == qi->end()) {
+ typename ListOfClusters::iterator qj = findCluster(diag(j));
+ if (qj == m_clusters.end()) {
+ qi->push_back(diag(j));
+ } else {
+ qi->insert(qi->end(), qj->begin(), qj->end());
+ m_clusters.erase(qj);
+ }
+ }
+ }
+ }
+}
+
+/** \brief Find cluster in #m_clusters containing some value
+ * \param[in] key Value to find
+ * \returns Iterator to cluster containing \c key, or
+ * \c m_clusters.end() if no cluster in m_clusters contains \c key.
+ */
+template <typename MatrixType, typename AtomicType>
+typename MatrixFunction<MatrixType,AtomicType,1>::ListOfClusters::iterator MatrixFunction<MatrixType,AtomicType,1>::findCluster(Scalar key)
+{
+ typename Cluster::iterator j;
+ for (typename ListOfClusters::iterator i = m_clusters.begin(); i != m_clusters.end(); ++i) {
+ j = std::find(i->begin(), i->end(), key);
+ if (j != i->end())
+ return i;
+ }
+ return m_clusters.end();
+}
+
+/** \brief Compute #m_clusterSize and #m_eivalToCluster using #m_clusters */
+template <typename MatrixType, typename AtomicType>
+void MatrixFunction<MatrixType,AtomicType,1>::computeClusterSize()
+{
+ const Index rows = m_T.rows();
+ VectorType diag = m_T.diagonal();
+ const Index numClusters = static_cast<Index>(m_clusters.size());
+
+ m_clusterSize.setZero(numClusters);
+ m_eivalToCluster.resize(rows);
+ Index clusterIndex = 0;
+ for (typename ListOfClusters::const_iterator cluster = m_clusters.begin(); cluster != m_clusters.end(); ++cluster) {
+ for (Index i = 0; i < diag.rows(); ++i) {
+ if (std::find(cluster->begin(), cluster->end(), diag(i)) != cluster->end()) {
+ ++m_clusterSize[clusterIndex];
+ m_eivalToCluster[i] = clusterIndex;
+ }
+ }
+ ++clusterIndex;
+ }
+}
+
+/** \brief Compute #m_blockStart using #m_clusterSize */
+template <typename MatrixType, typename AtomicType>
+void MatrixFunction<MatrixType,AtomicType,1>::computeBlockStart()
+{
+ m_blockStart.resize(m_clusterSize.rows());
+ m_blockStart(0) = 0;
+ for (Index i = 1; i < m_clusterSize.rows(); i++) {
+ m_blockStart(i) = m_blockStart(i-1) + m_clusterSize(i-1);
+ }
+}
+
+/** \brief Compute #m_permutation using #m_eivalToCluster and #m_blockStart */
+template <typename MatrixType, typename AtomicType>
+void MatrixFunction<MatrixType,AtomicType,1>::constructPermutation()
+{
+ DynamicIntVectorType indexNextEntry = m_blockStart;
+ m_permutation.resize(m_T.rows());
+ for (Index i = 0; i < m_T.rows(); i++) {
+ Index cluster = m_eivalToCluster[i];
+ m_permutation[i] = indexNextEntry[cluster];
+ ++indexNextEntry[cluster];
+ }
+}
+
+/** \brief Permute Schur decomposition in #m_U and #m_T according to #m_permutation */
+template <typename MatrixType, typename AtomicType>
+void MatrixFunction<MatrixType,AtomicType,1>::permuteSchur()
+{
+ IntVectorType p = m_permutation;
+ for (Index i = 0; i < p.rows() - 1; i++) {
+ Index j;
+ for (j = i; j < p.rows(); j++) {
+ if (p(j) == i) break;
+ }
+ eigen_assert(p(j) == i);
+ for (Index k = j-1; k >= i; k--) {
+ swapEntriesInSchur(k);
+ std::swap(p.coeffRef(k), p.coeffRef(k+1));
+ }
+ }
+}
+
+/** \brief Swap rows \a index and \a index+1 in Schur decomposition in #m_U and #m_T */
+template <typename MatrixType, typename AtomicType>
+void MatrixFunction<MatrixType,AtomicType,1>::swapEntriesInSchur(Index index)
+{
+ JacobiRotation<Scalar> rotation;
+ rotation.makeGivens(m_T(index, index+1), m_T(index+1, index+1) - m_T(index, index));
+ m_T.applyOnTheLeft(index, index+1, rotation.adjoint());
+ m_T.applyOnTheRight(index, index+1, rotation);
+ m_U.applyOnTheRight(index, index+1, rotation);
+}
+
+/** \brief Compute block diagonal part of #m_fT.
+ *
+ * This routine computes the matrix function applied to the block diagonal part of #m_T, with the blocking
+ * given by #m_blockStart. The matrix function of each diagonal block is computed by #m_atomic. The
+ * off-diagonal parts of #m_fT are set to zero.
+ */
+template <typename MatrixType, typename AtomicType>
+void MatrixFunction<MatrixType,AtomicType,1>::computeBlockAtomic()
+{
+ m_fT.resize(m_T.rows(), m_T.cols());
+ m_fT.setZero();
+ for (Index i = 0; i < m_clusterSize.rows(); ++i) {
+ block(m_fT, i, i) = m_atomic.compute(block(m_T, i, i));
+ }
+}
+
+/** \brief Return block of matrix according to blocking given by #m_blockStart */
+template <typename MatrixType, typename AtomicType>
+Block<MatrixType> MatrixFunction<MatrixType,AtomicType,1>::block(MatrixType& A, Index i, Index j)
+{
+ return A.block(m_blockStart(i), m_blockStart(j), m_clusterSize(i), m_clusterSize(j));
+}
+
+/** \brief Compute part of #m_fT above block diagonal.
+ *
+ * This routine assumes that the block diagonal part of #m_fT (which
+ * equals the matrix function applied to #m_T) has already been computed and computes
+ * the part above the block diagonal. The part below the diagonal is
+ * zero, because #m_T is upper triangular.
+ */
+template <typename MatrixType, typename AtomicType>
+void MatrixFunction<MatrixType,AtomicType,1>::computeOffDiagonal()
+{
+ for (Index diagIndex = 1; diagIndex < m_clusterSize.rows(); diagIndex++) {
+ for (Index blockIndex = 0; blockIndex < m_clusterSize.rows() - diagIndex; blockIndex++) {
+ // compute (blockIndex, blockIndex+diagIndex) block
+ DynMatrixType A = block(m_T, blockIndex, blockIndex);
+ DynMatrixType B = -block(m_T, blockIndex+diagIndex, blockIndex+diagIndex);
+ DynMatrixType C = block(m_fT, blockIndex, blockIndex) * block(m_T, blockIndex, blockIndex+diagIndex);
+ C -= block(m_T, blockIndex, blockIndex+diagIndex) * block(m_fT, blockIndex+diagIndex, blockIndex+diagIndex);
+ for (Index k = blockIndex + 1; k < blockIndex + diagIndex; k++) {
+ C += block(m_fT, blockIndex, k) * block(m_T, k, blockIndex+diagIndex);
+ C -= block(m_T, blockIndex, k) * block(m_fT, k, blockIndex+diagIndex);
+ }
+ block(m_fT, blockIndex, blockIndex+diagIndex) = solveTriangularSylvester(A, B, C);
+ }
+ }
+}
+
+/** \brief Solve a triangular Sylvester equation AX + XB = C
+ *
+ * \param[in] A the matrix A; should be square and upper triangular
+ * \param[in] B the matrix B; should be square and upper triangular
+ * \param[in] C the matrix C; should have correct size.
+ *
+ * \returns the solution X.
+ *
+ * If A is m-by-m and B is n-by-n, then both C and X are m-by-n.
+ * The (i,j)-th component of the Sylvester equation is
+ * \f[
+ * \sum_{k=i}^m A_{ik} X_{kj} + \sum_{k=1}^j X_{ik} B_{kj} = C_{ij}.
+ * \f]
+ * This can be re-arranged to yield:
+ * \f[
+ * X_{ij} = \frac{1}{A_{ii} + B_{jj}} \Bigl( C_{ij}
+ * - \sum_{k=i+1}^m A_{ik} X_{kj} - \sum_{k=1}^{j-1} X_{ik} B_{kj} \Bigr).
+ * \f]
+ * It is assumed that A and B are such that the numerator is never
+ * zero (otherwise the Sylvester equation does not have a unique
+ * solution). In that case, these equations can be evaluated in the
+ * order \f$ i=m,\ldots,1 \f$ and \f$ j=1,\ldots,n \f$.
+ */
+template <typename MatrixType, typename AtomicType>
+typename MatrixFunction<MatrixType,AtomicType,1>::DynMatrixType MatrixFunction<MatrixType,AtomicType,1>::solveTriangularSylvester(
+ const DynMatrixType& A,
+ const DynMatrixType& B,
+ const DynMatrixType& C)
+{
+ eigen_assert(A.rows() == A.cols());
+ eigen_assert(A.isUpperTriangular());
+ eigen_assert(B.rows() == B.cols());
+ eigen_assert(B.isUpperTriangular());
+ eigen_assert(C.rows() == A.rows());
+ eigen_assert(C.cols() == B.rows());
+
+ Index m = A.rows();
+ Index n = B.rows();
+ DynMatrixType X(m, n);
+
+ for (Index i = m - 1; i >= 0; --i) {
+ for (Index j = 0; j < n; ++j) {
+
+ // Compute AX = \sum_{k=i+1}^m A_{ik} X_{kj}
+ Scalar AX;
+ if (i == m - 1) {
+ AX = 0;
+ } else {
+ Matrix<Scalar,1,1> AXmatrix = A.row(i).tail(m-1-i) * X.col(j).tail(m-1-i);
+ AX = AXmatrix(0,0);
+ }
+
+ // Compute XB = \sum_{k=1}^{j-1} X_{ik} B_{kj}
+ Scalar XB;
+ if (j == 0) {
+ XB = 0;
+ } else {
+ Matrix<Scalar,1,1> XBmatrix = X.row(i).head(j) * B.col(j).head(j);
+ XB = XBmatrix(0,0);
+ }
+
+ X(i,j) = (C(i,j) - AX - XB) / (A(i,i) + B(j,j));
+ }
+ }
+ return X;
+}
+
+/** \ingroup MatrixFunctions_Module
+ *
+ * \brief Proxy for the matrix function of some matrix (expression).
+ *
+ * \tparam Derived Type of the argument to the matrix function.
+ *
+ * This class holds the argument to the matrix function until it is
+ * assigned or evaluated for some other reason (so the argument
+ * should not be changed in the meantime). It is the return type of
+ * matrixBase::matrixFunction() and related functions and most of the
+ * time this is the only way it is used.
+ */
+template<typename Derived> class MatrixFunctionReturnValue
+: public ReturnByValue<MatrixFunctionReturnValue<Derived> >
+{
+ public:
+
+ typedef typename Derived::Scalar Scalar;
+ typedef typename Derived::Index Index;
+ typedef typename internal::stem_function<Scalar>::type StemFunction;
+
+ /** \brief Constructor.
+ *
+ * \param[in] A %Matrix (expression) forming the argument of the
+ * matrix function.
+ * \param[in] f Stem function for matrix function under consideration.
+ */
+ MatrixFunctionReturnValue(const Derived& A, StemFunction f) : m_A(A), m_f(f) { }
+
+ /** \brief Compute the matrix function.
+ *
+ * \param[out] result \p f applied to \p A, where \p f and \p A
+ * are as in the constructor.
+ */
+ template <typename ResultType>
+ inline void evalTo(ResultType& result) const
+ {
+ typedef typename Derived::PlainObject PlainObject;
+ typedef internal::traits<PlainObject> Traits;
+ static const int RowsAtCompileTime = Traits::RowsAtCompileTime;
+ static const int ColsAtCompileTime = Traits::ColsAtCompileTime;
+ static const int Options = PlainObject::Options;
+ typedef std::complex<typename NumTraits<Scalar>::Real> ComplexScalar;
+ typedef Matrix<ComplexScalar, Dynamic, Dynamic, Options, RowsAtCompileTime, ColsAtCompileTime> DynMatrixType;
+ typedef MatrixFunctionAtomic<DynMatrixType> AtomicType;
+ AtomicType atomic(m_f);
+
+ const PlainObject Aevaluated = m_A.eval();
+ MatrixFunction<PlainObject, AtomicType> mf(Aevaluated, atomic);
+ mf.compute(result);
+ }
+
+ Index rows() const { return m_A.rows(); }
+ Index cols() const { return m_A.cols(); }
+
+ private:
+ typename internal::nested<Derived>::type m_A;
+ StemFunction *m_f;
+
+ MatrixFunctionReturnValue& operator=(const MatrixFunctionReturnValue&);
+};
+
+namespace internal {
+template<typename Derived>
+struct traits<MatrixFunctionReturnValue<Derived> >
+{
+ typedef typename Derived::PlainObject ReturnType;
+};
+}
+
+
+/********** MatrixBase methods **********/
+
+
+template <typename Derived>
+const MatrixFunctionReturnValue<Derived> MatrixBase<Derived>::matrixFunction(typename internal::stem_function<typename internal::traits<Derived>::Scalar>::type f) const
+{
+ eigen_assert(rows() == cols());
+ return MatrixFunctionReturnValue<Derived>(derived(), f);
+}
+
+template <typename Derived>
+const MatrixFunctionReturnValue<Derived> MatrixBase<Derived>::sin() const
+{
+ eigen_assert(rows() == cols());
+ typedef typename internal::stem_function<Scalar>::ComplexScalar ComplexScalar;
+ return MatrixFunctionReturnValue<Derived>(derived(), StdStemFunctions<ComplexScalar>::sin);
+}
+
+template <typename Derived>
+const MatrixFunctionReturnValue<Derived> MatrixBase<Derived>::cos() const
+{
+ eigen_assert(rows() == cols());
+ typedef typename internal::stem_function<Scalar>::ComplexScalar ComplexScalar;
+ return MatrixFunctionReturnValue<Derived>(derived(), StdStemFunctions<ComplexScalar>::cos);
+}
+
+template <typename Derived>
+const MatrixFunctionReturnValue<Derived> MatrixBase<Derived>::sinh() const
+{
+ eigen_assert(rows() == cols());
+ typedef typename internal::stem_function<Scalar>::ComplexScalar ComplexScalar;
+ return MatrixFunctionReturnValue<Derived>(derived(), StdStemFunctions<ComplexScalar>::sinh);
+}
+
+template <typename Derived>
+const MatrixFunctionReturnValue<Derived> MatrixBase<Derived>::cosh() const
+{
+ eigen_assert(rows() == cols());
+ typedef typename internal::stem_function<Scalar>::ComplexScalar ComplexScalar;
+ return MatrixFunctionReturnValue<Derived>(derived(), StdStemFunctions<ComplexScalar>::cosh);
+}
+
+} // end namespace Eigen
+
+#endif // EIGEN_MATRIX_FUNCTION
diff --git a/unsupported/Eigen/src/MatrixFunctions/MatrixFunctionAtomic.h b/unsupported/Eigen/src/MatrixFunctions/MatrixFunctionAtomic.h
new file mode 100644
index 000000000..efe332c48
--- /dev/null
+++ b/unsupported/Eigen/src/MatrixFunctions/MatrixFunctionAtomic.h
@@ -0,0 +1,131 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra.
+//
+// Copyright (C) 2009 Jitse Niesen <jitse@maths.leeds.ac.uk>
+//
+// This Source Code Form is subject to the terms of the Mozilla
+// Public License v. 2.0. If a copy of the MPL was not distributed
+// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+#ifndef EIGEN_MATRIX_FUNCTION_ATOMIC
+#define EIGEN_MATRIX_FUNCTION_ATOMIC
+
+namespace Eigen {
+
+/** \ingroup MatrixFunctions_Module
+ * \class MatrixFunctionAtomic
+ * \brief Helper class for computing matrix functions of atomic matrices.
+ *
+ * \internal
+ * Here, an atomic matrix is a triangular matrix whose diagonal
+ * entries are close to each other.
+ */
+template <typename MatrixType>
+class MatrixFunctionAtomic
+{
+ public:
+
+ typedef typename MatrixType::Scalar Scalar;
+ typedef typename MatrixType::Index Index;
+ typedef typename NumTraits<Scalar>::Real RealScalar;
+ typedef typename internal::stem_function<Scalar>::type StemFunction;
+ typedef Matrix<Scalar, MatrixType::RowsAtCompileTime, 1> VectorType;
+
+ /** \brief Constructor
+ * \param[in] f matrix function to compute.
+ */
+ MatrixFunctionAtomic(StemFunction f) : m_f(f) { }
+
+ /** \brief Compute matrix function of atomic matrix
+ * \param[in] A argument of matrix function, should be upper triangular and atomic
+ * \returns f(A), the matrix function evaluated at the given matrix
+ */
+ MatrixType compute(const MatrixType& A);
+
+ private:
+
+ // Prevent copying
+ MatrixFunctionAtomic(const MatrixFunctionAtomic&);
+ MatrixFunctionAtomic& operator=(const MatrixFunctionAtomic&);
+
+ void computeMu();
+ bool taylorConverged(Index s, const MatrixType& F, const MatrixType& Fincr, const MatrixType& P);
+
+ /** \brief Pointer to scalar function */
+ StemFunction* m_f;
+
+ /** \brief Size of matrix function */
+ Index m_Arows;
+
+ /** \brief Mean of eigenvalues */
+ Scalar m_avgEival;
+
+ /** \brief Argument shifted by mean of eigenvalues */
+ MatrixType m_Ashifted;
+
+ /** \brief Constant used to determine whether Taylor series has converged */
+ RealScalar m_mu;
+};
+
+template <typename MatrixType>
+MatrixType MatrixFunctionAtomic<MatrixType>::compute(const MatrixType& A)
+{
+ // TODO: Use that A is upper triangular
+ m_Arows = A.rows();
+ m_avgEival = A.trace() / Scalar(RealScalar(m_Arows));
+ m_Ashifted = A - m_avgEival * MatrixType::Identity(m_Arows, m_Arows);
+ computeMu();
+ MatrixType F = m_f(m_avgEival, 0) * MatrixType::Identity(m_Arows, m_Arows);
+ MatrixType P = m_Ashifted;
+ MatrixType Fincr;
+ for (Index s = 1; s < 1.1 * m_Arows + 10; s++) { // upper limit is fairly arbitrary
+ Fincr = m_f(m_avgEival, static_cast<int>(s)) * P;
+ F += Fincr;
+ P = Scalar(RealScalar(1.0/(s + 1))) * P * m_Ashifted;
+ if (taylorConverged(s, F, Fincr, P)) {
+ return F;
+ }
+ }
+ eigen_assert("Taylor series does not converge" && 0);
+ return F;
+}
+
+/** \brief Compute \c m_mu. */
+template <typename MatrixType>
+void MatrixFunctionAtomic<MatrixType>::computeMu()
+{
+ const MatrixType N = MatrixType::Identity(m_Arows, m_Arows) - m_Ashifted;
+ VectorType e = VectorType::Ones(m_Arows);
+ N.template triangularView<Upper>().solveInPlace(e);
+ m_mu = e.cwiseAbs().maxCoeff();
+}
+
+/** \brief Determine whether Taylor series has converged */
+template <typename MatrixType>
+bool MatrixFunctionAtomic<MatrixType>::taylorConverged(Index s, const MatrixType& F,
+ const MatrixType& Fincr, const MatrixType& P)
+{
+ const Index n = F.rows();
+ const RealScalar F_norm = F.cwiseAbs().rowwise().sum().maxCoeff();
+ const RealScalar Fincr_norm = Fincr.cwiseAbs().rowwise().sum().maxCoeff();
+ if (Fincr_norm < NumTraits<Scalar>::epsilon() * F_norm) {
+ RealScalar delta = 0;
+ RealScalar rfactorial = 1;
+ for (Index r = 0; r < n; r++) {
+ RealScalar mx = 0;
+ for (Index i = 0; i < n; i++)
+ mx = (std::max)(mx, std::abs(m_f(m_Ashifted(i, i) + m_avgEival, static_cast<int>(s+r))));
+ if (r != 0)
+ rfactorial *= RealScalar(r);
+ delta = (std::max)(delta, mx / rfactorial);
+ }
+ const RealScalar P_norm = P.cwiseAbs().rowwise().sum().maxCoeff();
+ if (m_mu * delta * P_norm < NumTraits<Scalar>::epsilon() * F_norm)
+ return true;
+ }
+ return false;
+}
+
+} // end namespace Eigen
+
+#endif // EIGEN_MATRIX_FUNCTION_ATOMIC
diff --git a/unsupported/Eigen/src/MatrixFunctions/MatrixLogarithm.h b/unsupported/Eigen/src/MatrixFunctions/MatrixLogarithm.h
new file mode 100644
index 000000000..3a50514b9
--- /dev/null
+++ b/unsupported/Eigen/src/MatrixFunctions/MatrixLogarithm.h
@@ -0,0 +1,495 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra.
+//
+// Copyright (C) 2011 Jitse Niesen <jitse@maths.leeds.ac.uk>
+// Copyright (C) 2011 Chen-Pang He <jdh8@ms63.hinet.net>
+//
+// This Source Code Form is subject to the terms of the Mozilla
+// Public License v. 2.0. If a copy of the MPL was not distributed
+// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+#ifndef EIGEN_MATRIX_LOGARITHM
+#define EIGEN_MATRIX_LOGARITHM
+
+#ifndef M_PI
+#define M_PI 3.141592653589793238462643383279503L
+#endif
+
+namespace Eigen {
+
+/** \ingroup MatrixFunctions_Module
+ * \class MatrixLogarithmAtomic
+ * \brief Helper class for computing matrix logarithm of atomic matrices.
+ *
+ * \internal
+ * Here, an atomic matrix is a triangular matrix whose diagonal
+ * entries are close to each other.
+ *
+ * \sa class MatrixFunctionAtomic, MatrixBase::log()
+ */
+template <typename MatrixType>
+class MatrixLogarithmAtomic
+{
+public:
+
+ typedef typename MatrixType::Scalar Scalar;
+ // typedef typename MatrixType::Index Index;
+ typedef typename NumTraits<Scalar>::Real RealScalar;
+ // typedef typename internal::stem_function<Scalar>::type StemFunction;
+ // typedef Matrix<Scalar, MatrixType::RowsAtCompileTime, 1> VectorType;
+
+ /** \brief Constructor. */
+ MatrixLogarithmAtomic() { }
+
+ /** \brief Compute matrix logarithm of atomic matrix
+ * \param[in] A argument of matrix logarithm, should be upper triangular and atomic
+ * \returns The logarithm of \p A.
+ */
+ MatrixType compute(const MatrixType& A);
+
+private:
+
+ void compute2x2(const MatrixType& A, MatrixType& result);
+ void computeBig(const MatrixType& A, MatrixType& result);
+ static Scalar atanh(Scalar x);
+ int getPadeDegree(float normTminusI);
+ int getPadeDegree(double normTminusI);
+ int getPadeDegree(long double normTminusI);
+ void computePade(MatrixType& result, const MatrixType& T, int degree);
+ void computePade3(MatrixType& result, const MatrixType& T);
+ void computePade4(MatrixType& result, const MatrixType& T);
+ void computePade5(MatrixType& result, const MatrixType& T);
+ void computePade6(MatrixType& result, const MatrixType& T);
+ void computePade7(MatrixType& result, const MatrixType& T);
+ void computePade8(MatrixType& result, const MatrixType& T);
+ void computePade9(MatrixType& result, const MatrixType& T);
+ void computePade10(MatrixType& result, const MatrixType& T);
+ void computePade11(MatrixType& result, const MatrixType& T);
+
+ static const int minPadeDegree = 3;
+ static const int maxPadeDegree = std::numeric_limits<RealScalar>::digits<= 24? 5: // single precision
+ std::numeric_limits<RealScalar>::digits<= 53? 7: // double precision
+ std::numeric_limits<RealScalar>::digits<= 64? 8: // extended precision
+ std::numeric_limits<RealScalar>::digits<=106? 10: 11; // double-double or quadruple precision
+
+ // Prevent copying
+ MatrixLogarithmAtomic(const MatrixLogarithmAtomic&);
+ MatrixLogarithmAtomic& operator=(const MatrixLogarithmAtomic&);
+};
+
+/** \brief Compute logarithm of triangular matrix with clustered eigenvalues. */
+template <typename MatrixType>
+MatrixType MatrixLogarithmAtomic<MatrixType>::compute(const MatrixType& A)
+{
+ using std::log;
+ MatrixType result(A.rows(), A.rows());
+ if (A.rows() == 1)
+ result(0,0) = log(A(0,0));
+ else if (A.rows() == 2)
+ compute2x2(A, result);
+ else
+ computeBig(A, result);
+ return result;
+}
+
+/** \brief Compute atanh (inverse hyperbolic tangent). */
+template <typename MatrixType>
+typename MatrixType::Scalar MatrixLogarithmAtomic<MatrixType>::atanh(typename MatrixType::Scalar x)
+{
+ using std::abs;
+ using std::sqrt;
+ if (abs(x) > sqrt(NumTraits<Scalar>::epsilon()))
+ return Scalar(0.5) * log((Scalar(1) + x) / (Scalar(1) - x));
+ else
+ return x + x*x*x / Scalar(3);
+}
+
+/** \brief Compute logarithm of 2x2 triangular matrix. */
+template <typename MatrixType>
+void MatrixLogarithmAtomic<MatrixType>::compute2x2(const MatrixType& A, MatrixType& result)
+{
+ using std::abs;
+ using std::ceil;
+ using std::imag;
+ using std::log;
+
+ Scalar logA00 = log(A(0,0));
+ Scalar logA11 = log(A(1,1));
+
+ result(0,0) = logA00;
+ result(1,0) = Scalar(0);
+ result(1,1) = logA11;
+
+ if (A(0,0) == A(1,1)) {
+ result(0,1) = A(0,1) / A(0,0);
+ } else if ((abs(A(0,0)) < 0.5*abs(A(1,1))) || (abs(A(0,0)) > 2*abs(A(1,1)))) {
+ result(0,1) = A(0,1) * (logA11 - logA00) / (A(1,1) - A(0,0));
+ } else {
+ // computation in previous branch is inaccurate if A(1,1) \approx A(0,0)
+ int unwindingNumber = static_cast<int>(ceil((imag(logA11 - logA00) - M_PI) / (2*M_PI)));
+ Scalar z = (A(1,1) - A(0,0)) / (A(1,1) + A(0,0));
+ result(0,1) = A(0,1) * (Scalar(2) * atanh(z) + Scalar(0,2*M_PI*unwindingNumber)) / (A(1,1) - A(0,0));
+ }
+}
+
+/** \brief Compute logarithm of triangular matrices with size > 2.
+ * \details This uses a inverse scale-and-square algorithm. */
+template <typename MatrixType>
+void MatrixLogarithmAtomic<MatrixType>::computeBig(const MatrixType& A, MatrixType& result)
+{
+ int numberOfSquareRoots = 0;
+ int numberOfExtraSquareRoots = 0;
+ int degree;
+ MatrixType T = A;
+ const RealScalar maxNormForPade = maxPadeDegree<= 5? 5.3149729967117310e-1: // single precision
+ maxPadeDegree<= 7? 2.6429608311114350e-1: // double precision
+ maxPadeDegree<= 8? 2.32777776523703892094e-1L: // extended precision
+ maxPadeDegree<=10? 1.05026503471351080481093652651105e-1L: // double-double
+ 1.1880960220216759245467951592883642e-1L; // quadruple precision
+
+ while (true) {
+ RealScalar normTminusI = (T - MatrixType::Identity(T.rows(), T.rows())).cwiseAbs().colwise().sum().maxCoeff();
+ if (normTminusI < maxNormForPade) {
+ degree = getPadeDegree(normTminusI);
+ int degree2 = getPadeDegree(normTminusI / RealScalar(2));
+ if ((degree - degree2 <= 1) || (numberOfExtraSquareRoots == 1))
+ break;
+ ++numberOfExtraSquareRoots;
+ }
+ MatrixType sqrtT;
+ MatrixSquareRootTriangular<MatrixType>(T).compute(sqrtT);
+ T = sqrtT;
+ ++numberOfSquareRoots;
+ }
+
+ computePade(result, T, degree);
+ result *= pow(RealScalar(2), numberOfSquareRoots);
+}
+
+/* \brief Get suitable degree for Pade approximation. (specialized for RealScalar = float) */
+template <typename MatrixType>
+int MatrixLogarithmAtomic<MatrixType>::getPadeDegree(float normTminusI)
+{
+ const float maxNormForPade[] = { 2.5111573934555054e-1 /* degree = 3 */ , 4.0535837411880493e-1,
+ 5.3149729967117310e-1 };
+ for (int degree = 3; degree <= maxPadeDegree; ++degree)
+ if (normTminusI <= maxNormForPade[degree - minPadeDegree])
+ return degree;
+ assert(false); // this line should never be reached
+}
+
+/* \brief Get suitable degree for Pade approximation. (specialized for RealScalar = double) */
+template <typename MatrixType>
+int MatrixLogarithmAtomic<MatrixType>::getPadeDegree(double normTminusI)
+{
+ const double maxNormForPade[] = { 1.6206284795015624e-2 /* degree = 3 */ , 5.3873532631381171e-2,
+ 1.1352802267628681e-1, 1.8662860613541288e-1, 2.642960831111435e-1 };
+ for (int degree = 3; degree <= maxPadeDegree; ++degree)
+ if (normTminusI <= maxNormForPade[degree - minPadeDegree])
+ return degree;
+ assert(false); // this line should never be reached
+}
+
+/* \brief Get suitable degree for Pade approximation. (specialized for RealScalar = long double) */
+template <typename MatrixType>
+int MatrixLogarithmAtomic<MatrixType>::getPadeDegree(long double normTminusI)
+{
+#if LDBL_MANT_DIG == 53 // double precision
+ const double maxNormForPade[] = { 1.6206284795015624e-2 /* degree = 3 */ , 5.3873532631381171e-2,
+ 1.1352802267628681e-1, 1.8662860613541288e-1, 2.642960831111435e-1 };
+#elif LDBL_MANT_DIG <= 64 // extended precision
+ const double maxNormForPade[] = { 5.48256690357782863103e-3 /* degree = 3 */, 2.34559162387971167321e-2,
+ 5.84603923897347449857e-2, 1.08486423756725170223e-1, 1.68385767881294446649e-1,
+ 2.32777776523703892094e-1 };
+#elif LDBL_MANT_DIG <= 106 // double-double
+ const double maxNormForPade[] = { 8.58970550342939562202529664318890e-5 /* degree = 3 */,
+ 9.34074328446359654039446552677759e-4, 4.26117194647672175773064114582860e-3,
+ 1.21546224740281848743149666560464e-2, 2.61100544998339436713088248557444e-2,
+ 4.66170074627052749243018566390567e-2, 7.32585144444135027565872014932387e-2,
+ 1.05026503471351080481093652651105e-1 };
+#else // quadruple precision
+ const double maxNormForPade[] = { 4.7419931187193005048501568167858103e-5 /* degree = 3 */,
+ 5.8853168473544560470387769480192666e-4, 2.9216120366601315391789493628113520e-3,
+ 8.8415758124319434347116734705174308e-3, 1.9850836029449446668518049562565291e-2,
+ 3.6688019729653446926585242192447447e-2, 5.9290962294020186998954055264528393e-2,
+ 8.6998436081634343903250580992127677e-2, 1.1880960220216759245467951592883642e-1 };
+#endif
+ for (int degree = 3; degree <= maxPadeDegree; ++degree)
+ if (normTminusI <= maxNormForPade[degree - minPadeDegree])
+ return degree;
+ assert(false); // this line should never be reached
+}
+
+/* \brief Compute Pade approximation to matrix logarithm */
+template <typename MatrixType>
+void MatrixLogarithmAtomic<MatrixType>::computePade(MatrixType& result, const MatrixType& T, int degree)
+{
+ switch (degree) {
+ case 3: computePade3(result, T); break;
+ case 4: computePade4(result, T); break;
+ case 5: computePade5(result, T); break;
+ case 6: computePade6(result, T); break;
+ case 7: computePade7(result, T); break;
+ case 8: computePade8(result, T); break;
+ case 9: computePade9(result, T); break;
+ case 10: computePade10(result, T); break;
+ case 11: computePade11(result, T); break;
+ default: assert(false); // should never happen
+ }
+}
+
+template <typename MatrixType>
+void MatrixLogarithmAtomic<MatrixType>::computePade3(MatrixType& result, const MatrixType& T)
+{
+ const int degree = 3;
+ const RealScalar nodes[] = { 0.1127016653792583114820734600217600L, 0.5000000000000000000000000000000000L,
+ 0.8872983346207416885179265399782400L };
+ const RealScalar weights[] = { 0.2777777777777777777777777777777778L, 0.4444444444444444444444444444444444L,
+ 0.2777777777777777777777777777777778L };
+ assert(degree <= maxPadeDegree);
+ MatrixType TminusI = T - MatrixType::Identity(T.rows(), T.rows());
+ result.setZero(T.rows(), T.rows());
+ for (int k = 0; k < degree; ++k)
+ result += weights[k] * (MatrixType::Identity(T.rows(), T.rows()) + nodes[k] * TminusI)
+ .template triangularView<Upper>().solve(TminusI);
+}
+
+template <typename MatrixType>
+void MatrixLogarithmAtomic<MatrixType>::computePade4(MatrixType& result, const MatrixType& T)
+{
+ const int degree = 4;
+ const RealScalar nodes[] = { 0.0694318442029737123880267555535953L, 0.3300094782075718675986671204483777L,
+ 0.6699905217924281324013328795516223L, 0.9305681557970262876119732444464048L };
+ const RealScalar weights[] = { 0.1739274225687269286865319746109997L, 0.3260725774312730713134680253890003L,
+ 0.3260725774312730713134680253890003L, 0.1739274225687269286865319746109997L };
+ assert(degree <= maxPadeDegree);
+ MatrixType TminusI = T - MatrixType::Identity(T.rows(), T.rows());
+ result.setZero(T.rows(), T.rows());
+ for (int k = 0; k < degree; ++k)
+ result += weights[k] * (MatrixType::Identity(T.rows(), T.rows()) + nodes[k] * TminusI)
+ .template triangularView<Upper>().solve(TminusI);
+}
+
+template <typename MatrixType>
+void MatrixLogarithmAtomic<MatrixType>::computePade5(MatrixType& result, const MatrixType& T)
+{
+ const int degree = 5;
+ const RealScalar nodes[] = { 0.0469100770306680036011865608503035L, 0.2307653449471584544818427896498956L,
+ 0.5000000000000000000000000000000000L, 0.7692346550528415455181572103501044L,
+ 0.9530899229693319963988134391496965L };
+ const RealScalar weights[] = { 0.1184634425280945437571320203599587L, 0.2393143352496832340206457574178191L,
+ 0.2844444444444444444444444444444444L, 0.2393143352496832340206457574178191L,
+ 0.1184634425280945437571320203599587L };
+ assert(degree <= maxPadeDegree);
+ MatrixType TminusI = T - MatrixType::Identity(T.rows(), T.rows());
+ result.setZero(T.rows(), T.rows());
+ for (int k = 0; k < degree; ++k)
+ result += weights[k] * (MatrixType::Identity(T.rows(), T.rows()) + nodes[k] * TminusI)
+ .template triangularView<Upper>().solve(TminusI);
+}
+
+template <typename MatrixType>
+void MatrixLogarithmAtomic<MatrixType>::computePade6(MatrixType& result, const MatrixType& T)
+{
+ const int degree = 6;
+ const RealScalar nodes[] = { 0.0337652428984239860938492227530027L, 0.1693953067668677431693002024900473L,
+ 0.3806904069584015456847491391596440L, 0.6193095930415984543152508608403560L,
+ 0.8306046932331322568306997975099527L, 0.9662347571015760139061507772469973L };
+ const RealScalar weights[] = { 0.0856622461895851725201480710863665L, 0.1803807865240693037849167569188581L,
+ 0.2339569672863455236949351719947755L, 0.2339569672863455236949351719947755L,
+ 0.1803807865240693037849167569188581L, 0.0856622461895851725201480710863665L };
+ assert(degree <= maxPadeDegree);
+ MatrixType TminusI = T - MatrixType::Identity(T.rows(), T.rows());
+ result.setZero(T.rows(), T.rows());
+ for (int k = 0; k < degree; ++k)
+ result += weights[k] * (MatrixType::Identity(T.rows(), T.rows()) + nodes[k] * TminusI)
+ .template triangularView<Upper>().solve(TminusI);
+}
+
+template <typename MatrixType>
+void MatrixLogarithmAtomic<MatrixType>::computePade7(MatrixType& result, const MatrixType& T)
+{
+ const int degree = 7;
+ const RealScalar nodes[] = { 0.0254460438286207377369051579760744L, 0.1292344072003027800680676133596058L,
+ 0.2970774243113014165466967939615193L, 0.5000000000000000000000000000000000L,
+ 0.7029225756886985834533032060384807L, 0.8707655927996972199319323866403942L,
+ 0.9745539561713792622630948420239256L };
+ const RealScalar weights[] = { 0.0647424830844348466353057163395410L, 0.1398526957446383339507338857118898L,
+ 0.1909150252525594724751848877444876L, 0.2089795918367346938775510204081633L,
+ 0.1909150252525594724751848877444876L, 0.1398526957446383339507338857118898L,
+ 0.0647424830844348466353057163395410L };
+ assert(degree <= maxPadeDegree);
+ MatrixType TminusI = T - MatrixType::Identity(T.rows(), T.rows());
+ result.setZero(T.rows(), T.rows());
+ for (int k = 0; k < degree; ++k)
+ result += weights[k] * (MatrixType::Identity(T.rows(), T.rows()) + nodes[k] * TminusI)
+ .template triangularView<Upper>().solve(TminusI);
+}
+
+template <typename MatrixType>
+void MatrixLogarithmAtomic<MatrixType>::computePade8(MatrixType& result, const MatrixType& T)
+{
+ const int degree = 8;
+ const RealScalar nodes[] = { 0.0198550717512318841582195657152635L, 0.1016667612931866302042230317620848L,
+ 0.2372337950418355070911304754053768L, 0.4082826787521750975302619288199080L,
+ 0.5917173212478249024697380711800920L, 0.7627662049581644929088695245946232L,
+ 0.8983332387068133697957769682379152L, 0.9801449282487681158417804342847365L };
+ const RealScalar weights[] = { 0.0506142681451881295762656771549811L, 0.1111905172266872352721779972131204L,
+ 0.1568533229389436436689811009933007L, 0.1813418916891809914825752246385978L,
+ 0.1813418916891809914825752246385978L, 0.1568533229389436436689811009933007L,
+ 0.1111905172266872352721779972131204L, 0.0506142681451881295762656771549811L };
+ assert(degree <= maxPadeDegree);
+ MatrixType TminusI = T - MatrixType::Identity(T.rows(), T.rows());
+ result.setZero(T.rows(), T.rows());
+ for (int k = 0; k < degree; ++k)
+ result += weights[k] * (MatrixType::Identity(T.rows(), T.rows()) + nodes[k] * TminusI)
+ .template triangularView<Upper>().solve(TminusI);
+}
+
+template <typename MatrixType>
+void MatrixLogarithmAtomic<MatrixType>::computePade9(MatrixType& result, const MatrixType& T)
+{
+ const int degree = 9;
+ const RealScalar nodes[] = { 0.0159198802461869550822118985481636L, 0.0819844463366821028502851059651326L,
+ 0.1933142836497048013456489803292629L, 0.3378732882980955354807309926783317L,
+ 0.5000000000000000000000000000000000L, 0.6621267117019044645192690073216683L,
+ 0.8066857163502951986543510196707371L, 0.9180155536633178971497148940348674L,
+ 0.9840801197538130449177881014518364L };
+ const RealScalar weights[] = { 0.0406371941807872059859460790552618L, 0.0903240803474287020292360156214564L,
+ 0.1303053482014677311593714347093164L, 0.1561735385200014200343152032922218L,
+ 0.1651196775006298815822625346434870L, 0.1561735385200014200343152032922218L,
+ 0.1303053482014677311593714347093164L, 0.0903240803474287020292360156214564L,
+ 0.0406371941807872059859460790552618L };
+ assert(degree <= maxPadeDegree);
+ MatrixType TminusI = T - MatrixType::Identity(T.rows(), T.rows());
+ result.setZero(T.rows(), T.rows());
+ for (int k = 0; k < degree; ++k)
+ result += weights[k] * (MatrixType::Identity(T.rows(), T.rows()) + nodes[k] * TminusI)
+ .template triangularView<Upper>().solve(TminusI);
+}
+
+template <typename MatrixType>
+void MatrixLogarithmAtomic<MatrixType>::computePade10(MatrixType& result, const MatrixType& T)
+{
+ const int degree = 10;
+ const RealScalar nodes[] = { 0.0130467357414141399610179939577740L, 0.0674683166555077446339516557882535L,
+ 0.1602952158504877968828363174425632L, 0.2833023029353764046003670284171079L,
+ 0.4255628305091843945575869994351400L, 0.5744371694908156054424130005648600L,
+ 0.7166976970646235953996329715828921L, 0.8397047841495122031171636825574368L,
+ 0.9325316833444922553660483442117465L, 0.9869532642585858600389820060422260L };
+ const RealScalar weights[] = { 0.0333356721543440687967844049466659L, 0.0747256745752902965728881698288487L,
+ 0.1095431812579910219977674671140816L, 0.1346333596549981775456134607847347L,
+ 0.1477621123573764350869464973256692L, 0.1477621123573764350869464973256692L,
+ 0.1346333596549981775456134607847347L, 0.1095431812579910219977674671140816L,
+ 0.0747256745752902965728881698288487L, 0.0333356721543440687967844049466659L };
+ assert(degree <= maxPadeDegree);
+ MatrixType TminusI = T - MatrixType::Identity(T.rows(), T.rows());
+ result.setZero(T.rows(), T.rows());
+ for (int k = 0; k < degree; ++k)
+ result += weights[k] * (MatrixType::Identity(T.rows(), T.rows()) + nodes[k] * TminusI)
+ .template triangularView<Upper>().solve(TminusI);
+}
+
+template <typename MatrixType>
+void MatrixLogarithmAtomic<MatrixType>::computePade11(MatrixType& result, const MatrixType& T)
+{
+ const int degree = 11;
+ const RealScalar nodes[] = { 0.0108856709269715035980309994385713L, 0.0564687001159523504624211153480364L,
+ 0.1349239972129753379532918739844233L, 0.2404519353965940920371371652706952L,
+ 0.3652284220238275138342340072995692L, 0.5000000000000000000000000000000000L,
+ 0.6347715779761724861657659927004308L, 0.7595480646034059079628628347293048L,
+ 0.8650760027870246620467081260155767L, 0.9435312998840476495375788846519636L,
+ 0.9891143290730284964019690005614287L };
+ const RealScalar weights[] = { 0.0278342835580868332413768602212743L, 0.0627901847324523123173471496119701L,
+ 0.0931451054638671257130488207158280L, 0.1165968822959952399592618524215876L,
+ 0.1314022722551233310903444349452546L, 0.1364625433889503153572417641681711L,
+ 0.1314022722551233310903444349452546L, 0.1165968822959952399592618524215876L,
+ 0.0931451054638671257130488207158280L, 0.0627901847324523123173471496119701L,
+ 0.0278342835580868332413768602212743L };
+ assert(degree <= maxPadeDegree);
+ MatrixType TminusI = T - MatrixType::Identity(T.rows(), T.rows());
+ result.setZero(T.rows(), T.rows());
+ for (int k = 0; k < degree; ++k)
+ result += weights[k] * (MatrixType::Identity(T.rows(), T.rows()) + nodes[k] * TminusI)
+ .template triangularView<Upper>().solve(TminusI);
+}
+
+/** \ingroup MatrixFunctions_Module
+ *
+ * \brief Proxy for the matrix logarithm of some matrix (expression).
+ *
+ * \tparam Derived Type of the argument to the matrix function.
+ *
+ * This class holds the argument to the matrix function until it is
+ * assigned or evaluated for some other reason (so the argument
+ * should not be changed in the meantime). It is the return type of
+ * matrixBase::matrixLogarithm() and most of the time this is the
+ * only way it is used.
+ */
+template<typename Derived> class MatrixLogarithmReturnValue
+: public ReturnByValue<MatrixLogarithmReturnValue<Derived> >
+{
+public:
+
+ typedef typename Derived::Scalar Scalar;
+ typedef typename Derived::Index Index;
+
+ /** \brief Constructor.
+ *
+ * \param[in] A %Matrix (expression) forming the argument of the matrix logarithm.
+ */
+ MatrixLogarithmReturnValue(const Derived& A) : m_A(A) { }
+
+ /** \brief Compute the matrix logarithm.
+ *
+ * \param[out] result Logarithm of \p A, where \A is as specified in the constructor.
+ */
+ template <typename ResultType>
+ inline void evalTo(ResultType& result) const
+ {
+ typedef typename Derived::PlainObject PlainObject;
+ typedef internal::traits<PlainObject> Traits;
+ static const int RowsAtCompileTime = Traits::RowsAtCompileTime;
+ static const int ColsAtCompileTime = Traits::ColsAtCompileTime;
+ static const int Options = PlainObject::Options;
+ typedef std::complex<typename NumTraits<Scalar>::Real> ComplexScalar;
+ typedef Matrix<ComplexScalar, Dynamic, Dynamic, Options, RowsAtCompileTime, ColsAtCompileTime> DynMatrixType;
+ typedef MatrixLogarithmAtomic<DynMatrixType> AtomicType;
+ AtomicType atomic;
+
+ const PlainObject Aevaluated = m_A.eval();
+ MatrixFunction<PlainObject, AtomicType> mf(Aevaluated, atomic);
+ mf.compute(result);
+ }
+
+ Index rows() const { return m_A.rows(); }
+ Index cols() const { return m_A.cols(); }
+
+private:
+ typename internal::nested<Derived>::type m_A;
+
+ MatrixLogarithmReturnValue& operator=(const MatrixLogarithmReturnValue&);
+};
+
+namespace internal {
+ template<typename Derived>
+ struct traits<MatrixLogarithmReturnValue<Derived> >
+ {
+ typedef typename Derived::PlainObject ReturnType;
+ };
+}
+
+
+/********** MatrixBase method **********/
+
+
+template <typename Derived>
+const MatrixLogarithmReturnValue<Derived> MatrixBase<Derived>::log() const
+{
+ eigen_assert(rows() == cols());
+ return MatrixLogarithmReturnValue<Derived>(derived());
+}
+
+} // end namespace Eigen
+
+#endif // EIGEN_MATRIX_LOGARITHM
diff --git a/unsupported/Eigen/src/MatrixFunctions/MatrixSquareRoot.h b/unsupported/Eigen/src/MatrixFunctions/MatrixSquareRoot.h
new file mode 100644
index 000000000..10319fa17
--- /dev/null
+++ b/unsupported/Eigen/src/MatrixFunctions/MatrixSquareRoot.h
@@ -0,0 +1,484 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra.
+//
+// Copyright (C) 2011 Jitse Niesen <jitse@maths.leeds.ac.uk>
+//
+// This Source Code Form is subject to the terms of the Mozilla
+// Public License v. 2.0. If a copy of the MPL was not distributed
+// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+#ifndef EIGEN_MATRIX_SQUARE_ROOT
+#define EIGEN_MATRIX_SQUARE_ROOT
+
+namespace Eigen {
+
+/** \ingroup MatrixFunctions_Module
+ * \brief Class for computing matrix square roots of upper quasi-triangular matrices.
+ * \tparam MatrixType type of the argument of the matrix square root,
+ * expected to be an instantiation of the Matrix class template.
+ *
+ * This class computes the square root of the upper quasi-triangular
+ * matrix stored in the upper Hessenberg part of the matrix passed to
+ * the constructor.
+ *
+ * \sa MatrixSquareRoot, MatrixSquareRootTriangular
+ */
+template <typename MatrixType>
+class MatrixSquareRootQuasiTriangular
+{
+ public:
+
+ /** \brief Constructor.
+ *
+ * \param[in] A upper quasi-triangular matrix whose square root
+ * is to be computed.
+ *
+ * The class stores a reference to \p A, so it should not be
+ * changed (or destroyed) before compute() is called.
+ */
+ MatrixSquareRootQuasiTriangular(const MatrixType& A)
+ : m_A(A)
+ {
+ eigen_assert(A.rows() == A.cols());
+ }
+
+ /** \brief Compute the matrix square root
+ *
+ * \param[out] result square root of \p A, as specified in the constructor.
+ *
+ * Only the upper Hessenberg part of \p result is updated, the
+ * rest is not touched. See MatrixBase::sqrt() for details on
+ * how this computation is implemented.
+ */
+ template <typename ResultType> void compute(ResultType &result);
+
+ private:
+ typedef typename MatrixType::Index Index;
+ typedef typename MatrixType::Scalar Scalar;
+
+ void computeDiagonalPartOfSqrt(MatrixType& sqrtT, const MatrixType& T);
+ void computeOffDiagonalPartOfSqrt(MatrixType& sqrtT, const MatrixType& T);
+ void compute2x2diagonalBlock(MatrixType& sqrtT, const MatrixType& T, typename MatrixType::Index i);
+ void compute1x1offDiagonalBlock(MatrixType& sqrtT, const MatrixType& T,
+ typename MatrixType::Index i, typename MatrixType::Index j);
+ void compute1x2offDiagonalBlock(MatrixType& sqrtT, const MatrixType& T,
+ typename MatrixType::Index i, typename MatrixType::Index j);
+ void compute2x1offDiagonalBlock(MatrixType& sqrtT, const MatrixType& T,
+ typename MatrixType::Index i, typename MatrixType::Index j);
+ void compute2x2offDiagonalBlock(MatrixType& sqrtT, const MatrixType& T,
+ typename MatrixType::Index i, typename MatrixType::Index j);
+
+ template <typename SmallMatrixType>
+ static void solveAuxiliaryEquation(SmallMatrixType& X, const SmallMatrixType& A,
+ const SmallMatrixType& B, const SmallMatrixType& C);
+
+ const MatrixType& m_A;
+};
+
+template <typename MatrixType>
+template <typename ResultType>
+void MatrixSquareRootQuasiTriangular<MatrixType>::compute(ResultType &result)
+{
+ // Compute Schur decomposition of m_A
+ const RealSchur<MatrixType> schurOfA(m_A);
+ const MatrixType& T = schurOfA.matrixT();
+ const MatrixType& U = schurOfA.matrixU();
+
+ // Compute square root of T
+ MatrixType sqrtT = MatrixType::Zero(m_A.rows(), m_A.rows());
+ computeDiagonalPartOfSqrt(sqrtT, T);
+ computeOffDiagonalPartOfSqrt(sqrtT, T);
+
+ // Compute square root of m_A
+ result = U * sqrtT * U.adjoint();
+}
+
+// pre: T is quasi-upper-triangular and sqrtT is a zero matrix of the same size
+// post: the diagonal blocks of sqrtT are the square roots of the diagonal blocks of T
+template <typename MatrixType>
+void MatrixSquareRootQuasiTriangular<MatrixType>::computeDiagonalPartOfSqrt(MatrixType& sqrtT,
+ const MatrixType& T)
+{
+ const Index size = m_A.rows();
+ for (Index i = 0; i < size; i++) {
+ if (i == size - 1 || T.coeff(i+1, i) == 0) {
+ eigen_assert(T(i,i) > 0);
+ sqrtT.coeffRef(i,i) = internal::sqrt(T.coeff(i,i));
+ }
+ else {
+ compute2x2diagonalBlock(sqrtT, T, i);
+ ++i;
+ }
+ }
+}
+
+// pre: T is quasi-upper-triangular and diagonal blocks of sqrtT are square root of diagonal blocks of T.
+// post: sqrtT is the square root of T.
+template <typename MatrixType>
+void MatrixSquareRootQuasiTriangular<MatrixType>::computeOffDiagonalPartOfSqrt(MatrixType& sqrtT,
+ const MatrixType& T)
+{
+ const Index size = m_A.rows();
+ for (Index j = 1; j < size; j++) {
+ if (T.coeff(j, j-1) != 0) // if T(j-1:j, j-1:j) is a 2-by-2 block
+ continue;
+ for (Index i = j-1; i >= 0; i--) {
+ if (i > 0 && T.coeff(i, i-1) != 0) // if T(i-1:i, i-1:i) is a 2-by-2 block
+ continue;
+ bool iBlockIs2x2 = (i < size - 1) && (T.coeff(i+1, i) != 0);
+ bool jBlockIs2x2 = (j < size - 1) && (T.coeff(j+1, j) != 0);
+ if (iBlockIs2x2 && jBlockIs2x2)
+ compute2x2offDiagonalBlock(sqrtT, T, i, j);
+ else if (iBlockIs2x2 && !jBlockIs2x2)
+ compute2x1offDiagonalBlock(sqrtT, T, i, j);
+ else if (!iBlockIs2x2 && jBlockIs2x2)
+ compute1x2offDiagonalBlock(sqrtT, T, i, j);
+ else if (!iBlockIs2x2 && !jBlockIs2x2)
+ compute1x1offDiagonalBlock(sqrtT, T, i, j);
+ }
+ }
+}
+
+// pre: T.block(i,i,2,2) has complex conjugate eigenvalues
+// post: sqrtT.block(i,i,2,2) is square root of T.block(i,i,2,2)
+template <typename MatrixType>
+void MatrixSquareRootQuasiTriangular<MatrixType>
+ ::compute2x2diagonalBlock(MatrixType& sqrtT, const MatrixType& T, typename MatrixType::Index i)
+{
+ // TODO: This case (2-by-2 blocks with complex conjugate eigenvalues) is probably hidden somewhere
+ // in EigenSolver. If we expose it, we could call it directly from here.
+ Matrix<Scalar,2,2> block = T.template block<2,2>(i,i);
+ EigenSolver<Matrix<Scalar,2,2> > es(block);
+ sqrtT.template block<2,2>(i,i)
+ = (es.eigenvectors() * es.eigenvalues().cwiseSqrt().asDiagonal() * es.eigenvectors().inverse()).real();
+}
+
+// pre: block structure of T is such that (i,j) is a 1x1 block,
+// all blocks of sqrtT to left of and below (i,j) are correct
+// post: sqrtT(i,j) has the correct value
+template <typename MatrixType>
+void MatrixSquareRootQuasiTriangular<MatrixType>
+ ::compute1x1offDiagonalBlock(MatrixType& sqrtT, const MatrixType& T,
+ typename MatrixType::Index i, typename MatrixType::Index j)
+{
+ Scalar tmp = (sqrtT.row(i).segment(i+1,j-i-1) * sqrtT.col(j).segment(i+1,j-i-1)).value();
+ sqrtT.coeffRef(i,j) = (T.coeff(i,j) - tmp) / (sqrtT.coeff(i,i) + sqrtT.coeff(j,j));
+}
+
+// similar to compute1x1offDiagonalBlock()
+template <typename MatrixType>
+void MatrixSquareRootQuasiTriangular<MatrixType>
+ ::compute1x2offDiagonalBlock(MatrixType& sqrtT, const MatrixType& T,
+ typename MatrixType::Index i, typename MatrixType::Index j)
+{
+ Matrix<Scalar,1,2> rhs = T.template block<1,2>(i,j);
+ if (j-i > 1)
+ rhs -= sqrtT.block(i, i+1, 1, j-i-1) * sqrtT.block(i+1, j, j-i-1, 2);
+ Matrix<Scalar,2,2> A = sqrtT.coeff(i,i) * Matrix<Scalar,2,2>::Identity();
+ A += sqrtT.template block<2,2>(j,j).transpose();
+ sqrtT.template block<1,2>(i,j).transpose() = A.fullPivLu().solve(rhs.transpose());
+}
+
+// similar to compute1x1offDiagonalBlock()
+template <typename MatrixType>
+void MatrixSquareRootQuasiTriangular<MatrixType>
+ ::compute2x1offDiagonalBlock(MatrixType& sqrtT, const MatrixType& T,
+ typename MatrixType::Index i, typename MatrixType::Index j)
+{
+ Matrix<Scalar,2,1> rhs = T.template block<2,1>(i,j);
+ if (j-i > 2)
+ rhs -= sqrtT.block(i, i+2, 2, j-i-2) * sqrtT.block(i+2, j, j-i-2, 1);
+ Matrix<Scalar,2,2> A = sqrtT.coeff(j,j) * Matrix<Scalar,2,2>::Identity();
+ A += sqrtT.template block<2,2>(i,i);
+ sqrtT.template block<2,1>(i,j) = A.fullPivLu().solve(rhs);
+}
+
+// similar to compute1x1offDiagonalBlock()
+template <typename MatrixType>
+void MatrixSquareRootQuasiTriangular<MatrixType>
+ ::compute2x2offDiagonalBlock(MatrixType& sqrtT, const MatrixType& T,
+ typename MatrixType::Index i, typename MatrixType::Index j)
+{
+ Matrix<Scalar,2,2> A = sqrtT.template block<2,2>(i,i);
+ Matrix<Scalar,2,2> B = sqrtT.template block<2,2>(j,j);
+ Matrix<Scalar,2,2> C = T.template block<2,2>(i,j);
+ if (j-i > 2)
+ C -= sqrtT.block(i, i+2, 2, j-i-2) * sqrtT.block(i+2, j, j-i-2, 2);
+ Matrix<Scalar,2,2> X;
+ solveAuxiliaryEquation(X, A, B, C);
+ sqrtT.template block<2,2>(i,j) = X;
+}
+
+// solves the equation A X + X B = C where all matrices are 2-by-2
+template <typename MatrixType>
+template <typename SmallMatrixType>
+void MatrixSquareRootQuasiTriangular<MatrixType>
+ ::solveAuxiliaryEquation(SmallMatrixType& X, const SmallMatrixType& A,
+ const SmallMatrixType& B, const SmallMatrixType& C)
+{
+ EIGEN_STATIC_ASSERT((internal::is_same<SmallMatrixType, Matrix<Scalar,2,2> >::value),
+ EIGEN_INTERNAL_ERROR_PLEASE_FILE_A_BUG_REPORT);
+
+ Matrix<Scalar,4,4> coeffMatrix = Matrix<Scalar,4,4>::Zero();
+ coeffMatrix.coeffRef(0,0) = A.coeff(0,0) + B.coeff(0,0);
+ coeffMatrix.coeffRef(1,1) = A.coeff(0,0) + B.coeff(1,1);
+ coeffMatrix.coeffRef(2,2) = A.coeff(1,1) + B.coeff(0,0);
+ coeffMatrix.coeffRef(3,3) = A.coeff(1,1) + B.coeff(1,1);
+ coeffMatrix.coeffRef(0,1) = B.coeff(1,0);
+ coeffMatrix.coeffRef(0,2) = A.coeff(0,1);
+ coeffMatrix.coeffRef(1,0) = B.coeff(0,1);
+ coeffMatrix.coeffRef(1,3) = A.coeff(0,1);
+ coeffMatrix.coeffRef(2,0) = A.coeff(1,0);
+ coeffMatrix.coeffRef(2,3) = B.coeff(1,0);
+ coeffMatrix.coeffRef(3,1) = A.coeff(1,0);
+ coeffMatrix.coeffRef(3,2) = B.coeff(0,1);
+
+ Matrix<Scalar,4,1> rhs;
+ rhs.coeffRef(0) = C.coeff(0,0);
+ rhs.coeffRef(1) = C.coeff(0,1);
+ rhs.coeffRef(2) = C.coeff(1,0);
+ rhs.coeffRef(3) = C.coeff(1,1);
+
+ Matrix<Scalar,4,1> result;
+ result = coeffMatrix.fullPivLu().solve(rhs);
+
+ X.coeffRef(0,0) = result.coeff(0);
+ X.coeffRef(0,1) = result.coeff(1);
+ X.coeffRef(1,0) = result.coeff(2);
+ X.coeffRef(1,1) = result.coeff(3);
+}
+
+
+/** \ingroup MatrixFunctions_Module
+ * \brief Class for computing matrix square roots of upper triangular matrices.
+ * \tparam MatrixType type of the argument of the matrix square root,
+ * expected to be an instantiation of the Matrix class template.
+ *
+ * This class computes the square root of the upper triangular matrix
+ * stored in the upper triangular part (including the diagonal) of
+ * the matrix passed to the constructor.
+ *
+ * \sa MatrixSquareRoot, MatrixSquareRootQuasiTriangular
+ */
+template <typename MatrixType>
+class MatrixSquareRootTriangular
+{
+ public:
+ MatrixSquareRootTriangular(const MatrixType& A)
+ : m_A(A)
+ {
+ eigen_assert(A.rows() == A.cols());
+ }
+
+ /** \brief Compute the matrix square root
+ *
+ * \param[out] result square root of \p A, as specified in the constructor.
+ *
+ * Only the upper triangular part (including the diagonal) of
+ * \p result is updated, the rest is not touched. See
+ * MatrixBase::sqrt() for details on how this computation is
+ * implemented.
+ */
+ template <typename ResultType> void compute(ResultType &result);
+
+ private:
+ const MatrixType& m_A;
+};
+
+template <typename MatrixType>
+template <typename ResultType>
+void MatrixSquareRootTriangular<MatrixType>::compute(ResultType &result)
+{
+ // Compute Schur decomposition of m_A
+ const ComplexSchur<MatrixType> schurOfA(m_A);
+ const MatrixType& T = schurOfA.matrixT();
+ const MatrixType& U = schurOfA.matrixU();
+
+ // Compute square root of T and store it in upper triangular part of result
+ // This uses that the square root of triangular matrices can be computed directly.
+ result.resize(m_A.rows(), m_A.cols());
+ typedef typename MatrixType::Index Index;
+ for (Index i = 0; i < m_A.rows(); i++) {
+ result.coeffRef(i,i) = internal::sqrt(T.coeff(i,i));
+ }
+ for (Index j = 1; j < m_A.cols(); j++) {
+ for (Index i = j-1; i >= 0; i--) {
+ typedef typename MatrixType::Scalar Scalar;
+ // if i = j-1, then segment has length 0 so tmp = 0
+ Scalar tmp = (result.row(i).segment(i+1,j-i-1) * result.col(j).segment(i+1,j-i-1)).value();
+ // denominator may be zero if original matrix is singular
+ result.coeffRef(i,j) = (T.coeff(i,j) - tmp) / (result.coeff(i,i) + result.coeff(j,j));
+ }
+ }
+
+ // Compute square root of m_A as U * result * U.adjoint()
+ MatrixType tmp;
+ tmp.noalias() = U * result.template triangularView<Upper>();
+ result.noalias() = tmp * U.adjoint();
+}
+
+
+/** \ingroup MatrixFunctions_Module
+ * \brief Class for computing matrix square roots of general matrices.
+ * \tparam MatrixType type of the argument of the matrix square root,
+ * expected to be an instantiation of the Matrix class template.
+ *
+ * \sa MatrixSquareRootTriangular, MatrixSquareRootQuasiTriangular, MatrixBase::sqrt()
+ */
+template <typename MatrixType, int IsComplex = NumTraits<typename internal::traits<MatrixType>::Scalar>::IsComplex>
+class MatrixSquareRoot
+{
+ public:
+
+ /** \brief Constructor.
+ *
+ * \param[in] A matrix whose square root is to be computed.
+ *
+ * The class stores a reference to \p A, so it should not be
+ * changed (or destroyed) before compute() is called.
+ */
+ MatrixSquareRoot(const MatrixType& A);
+
+ /** \brief Compute the matrix square root
+ *
+ * \param[out] result square root of \p A, as specified in the constructor.
+ *
+ * See MatrixBase::sqrt() for details on how this computation is
+ * implemented.
+ */
+ template <typename ResultType> void compute(ResultType &result);
+};
+
+
+// ********** Partial specialization for real matrices **********
+
+template <typename MatrixType>
+class MatrixSquareRoot<MatrixType, 0>
+{
+ public:
+
+ MatrixSquareRoot(const MatrixType& A)
+ : m_A(A)
+ {
+ eigen_assert(A.rows() == A.cols());
+ }
+
+ template <typename ResultType> void compute(ResultType &result)
+ {
+ // Compute Schur decomposition of m_A
+ const RealSchur<MatrixType> schurOfA(m_A);
+ const MatrixType& T = schurOfA.matrixT();
+ const MatrixType& U = schurOfA.matrixU();
+
+ // Compute square root of T
+ MatrixSquareRootQuasiTriangular<MatrixType> tmp(T);
+ MatrixType sqrtT = MatrixType::Zero(m_A.rows(), m_A.rows());
+ tmp.compute(sqrtT);
+
+ // Compute square root of m_A
+ result = U * sqrtT * U.adjoint();
+ }
+
+ private:
+ const MatrixType& m_A;
+};
+
+
+// ********** Partial specialization for complex matrices **********
+
+template <typename MatrixType>
+class MatrixSquareRoot<MatrixType, 1>
+{
+ public:
+
+ MatrixSquareRoot(const MatrixType& A)
+ : m_A(A)
+ {
+ eigen_assert(A.rows() == A.cols());
+ }
+
+ template <typename ResultType> void compute(ResultType &result)
+ {
+ // Compute Schur decomposition of m_A
+ const ComplexSchur<MatrixType> schurOfA(m_A);
+ const MatrixType& T = schurOfA.matrixT();
+ const MatrixType& U = schurOfA.matrixU();
+
+ // Compute square root of T
+ MatrixSquareRootTriangular<MatrixType> tmp(T);
+ MatrixType sqrtT = MatrixType::Zero(m_A.rows(), m_A.rows());
+ tmp.compute(sqrtT);
+
+ // Compute square root of m_A
+ result = U * sqrtT * U.adjoint();
+ }
+
+ private:
+ const MatrixType& m_A;
+};
+
+
+/** \ingroup MatrixFunctions_Module
+ *
+ * \brief Proxy for the matrix square root of some matrix (expression).
+ *
+ * \tparam Derived Type of the argument to the matrix square root.
+ *
+ * This class holds the argument to the matrix square root until it
+ * is assigned or evaluated for some other reason (so the argument
+ * should not be changed in the meantime). It is the return type of
+ * MatrixBase::sqrt() and most of the time this is the only way it is
+ * used.
+ */
+template<typename Derived> class MatrixSquareRootReturnValue
+: public ReturnByValue<MatrixSquareRootReturnValue<Derived> >
+{
+ typedef typename Derived::Index Index;
+ public:
+ /** \brief Constructor.
+ *
+ * \param[in] src %Matrix (expression) forming the argument of the
+ * matrix square root.
+ */
+ MatrixSquareRootReturnValue(const Derived& src) : m_src(src) { }
+
+ /** \brief Compute the matrix square root.
+ *
+ * \param[out] result the matrix square root of \p src in the
+ * constructor.
+ */
+ template <typename ResultType>
+ inline void evalTo(ResultType& result) const
+ {
+ const typename Derived::PlainObject srcEvaluated = m_src.eval();
+ MatrixSquareRoot<typename Derived::PlainObject> me(srcEvaluated);
+ me.compute(result);
+ }
+
+ Index rows() const { return m_src.rows(); }
+ Index cols() const { return m_src.cols(); }
+
+ protected:
+ const Derived& m_src;
+ private:
+ MatrixSquareRootReturnValue& operator=(const MatrixSquareRootReturnValue&);
+};
+
+namespace internal {
+template<typename Derived>
+struct traits<MatrixSquareRootReturnValue<Derived> >
+{
+ typedef typename Derived::PlainObject ReturnType;
+};
+}
+
+template <typename Derived>
+const MatrixSquareRootReturnValue<Derived> MatrixBase<Derived>::sqrt() const
+{
+ eigen_assert(rows() == cols());
+ return MatrixSquareRootReturnValue<Derived>(derived());
+}
+
+} // end namespace Eigen
+
+#endif // EIGEN_MATRIX_FUNCTION
diff --git a/unsupported/Eigen/src/MatrixFunctions/StemFunction.h b/unsupported/Eigen/src/MatrixFunctions/StemFunction.h
new file mode 100644
index 000000000..724e55c1d
--- /dev/null
+++ b/unsupported/Eigen/src/MatrixFunctions/StemFunction.h
@@ -0,0 +1,105 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra.
+//
+// Copyright (C) 2010 Jitse Niesen <jitse@maths.leeds.ac.uk>
+//
+// This Source Code Form is subject to the terms of the Mozilla
+// Public License v. 2.0. If a copy of the MPL was not distributed
+// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+#ifndef EIGEN_STEM_FUNCTION
+#define EIGEN_STEM_FUNCTION
+
+namespace Eigen {
+
+/** \ingroup MatrixFunctions_Module
+ * \brief Stem functions corresponding to standard mathematical functions.
+ */
+template <typename Scalar>
+class StdStemFunctions
+{
+ public:
+
+ /** \brief The exponential function (and its derivatives). */
+ static Scalar exp(Scalar x, int)
+ {
+ return std::exp(x);
+ }
+
+ /** \brief Cosine (and its derivatives). */
+ static Scalar cos(Scalar x, int n)
+ {
+ Scalar res;
+ switch (n % 4) {
+ case 0:
+ res = std::cos(x);
+ break;
+ case 1:
+ res = -std::sin(x);
+ break;
+ case 2:
+ res = -std::cos(x);
+ break;
+ case 3:
+ res = std::sin(x);
+ break;
+ }
+ return res;
+ }
+
+ /** \brief Sine (and its derivatives). */
+ static Scalar sin(Scalar x, int n)
+ {
+ Scalar res;
+ switch (n % 4) {
+ case 0:
+ res = std::sin(x);
+ break;
+ case 1:
+ res = std::cos(x);
+ break;
+ case 2:
+ res = -std::sin(x);
+ break;
+ case 3:
+ res = -std::cos(x);
+ break;
+ }
+ return res;
+ }
+
+ /** \brief Hyperbolic cosine (and its derivatives). */
+ static Scalar cosh(Scalar x, int n)
+ {
+ Scalar res;
+ switch (n % 2) {
+ case 0:
+ res = std::cosh(x);
+ break;
+ case 1:
+ res = std::sinh(x);
+ break;
+ }
+ return res;
+ }
+
+ /** \brief Hyperbolic sine (and its derivatives). */
+ static Scalar sinh(Scalar x, int n)
+ {
+ Scalar res;
+ switch (n % 2) {
+ case 0:
+ res = std::sinh(x);
+ break;
+ case 1:
+ res = std::cosh(x);
+ break;
+ }
+ return res;
+ }
+
+}; // end of class StdStemFunctions
+
+} // end namespace Eigen
+
+#endif // EIGEN_STEM_FUNCTION
diff --git a/unsupported/Eigen/src/MoreVectorization/CMakeLists.txt b/unsupported/Eigen/src/MoreVectorization/CMakeLists.txt
new file mode 100644
index 000000000..1b887cc8e
--- /dev/null
+++ b/unsupported/Eigen/src/MoreVectorization/CMakeLists.txt
@@ -0,0 +1,6 @@
+FILE(GLOB Eigen_MoreVectorization_SRCS "*.h")
+
+INSTALL(FILES
+ ${Eigen_MoreVectorization_SRCS}
+ DESTINATION ${INCLUDE_INSTALL_DIR}/unsupported/Eigen/src/MoreVectorization COMPONENT Devel
+ )
diff --git a/unsupported/Eigen/src/MoreVectorization/MathFunctions.h b/unsupported/Eigen/src/MoreVectorization/MathFunctions.h
new file mode 100644
index 000000000..63cb28dea
--- /dev/null
+++ b/unsupported/Eigen/src/MoreVectorization/MathFunctions.h
@@ -0,0 +1,95 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra.
+//
+// Copyright (C) 2009 Rohit Garg <rpg.314@gmail.com>
+// Copyright (C) 2009 Benoit Jacob <jacob.benoit.1@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 EIGEN_MOREVECTORIZATION_MATHFUNCTIONS_H
+#define EIGEN_MOREVECTORIZATION_MATHFUNCTIONS_H
+
+namespace Eigen {
+
+namespace internal {
+
+/** \internal \returns the arcsin of \a a (coeff-wise) */
+template<typename Packet> inline static Packet pasin(Packet a) { return std::asin(a); }
+
+#ifdef EIGEN_VECTORIZE_SSE
+
+template<> EIGEN_DONT_INLINE Packet4f pasin(Packet4f x)
+{
+ _EIGEN_DECLARE_CONST_Packet4f(half, 0.5);
+ _EIGEN_DECLARE_CONST_Packet4f(minus_half, -0.5);
+ _EIGEN_DECLARE_CONST_Packet4f(3half, 1.5);
+
+ _EIGEN_DECLARE_CONST_Packet4f_FROM_INT(sign_mask, 0x80000000);
+
+ _EIGEN_DECLARE_CONST_Packet4f(pi, 3.141592654);
+ _EIGEN_DECLARE_CONST_Packet4f(pi_over_2, 3.141592654*0.5);
+
+ _EIGEN_DECLARE_CONST_Packet4f(asin1, 4.2163199048E-2);
+ _EIGEN_DECLARE_CONST_Packet4f(asin2, 2.4181311049E-2);
+ _EIGEN_DECLARE_CONST_Packet4f(asin3, 4.5470025998E-2);
+ _EIGEN_DECLARE_CONST_Packet4f(asin4, 7.4953002686E-2);
+ _EIGEN_DECLARE_CONST_Packet4f(asin5, 1.6666752422E-1);
+
+ Packet4f a = pabs(x);//got the absolute value
+
+ Packet4f sign_bit= _mm_and_ps(x, p4f_sign_mask);//extracted the sign bit
+
+ Packet4f z1,z2;//will need them during computation
+
+
+//will compute the two branches for asin
+//so first compare with half
+
+ Packet4f branch_mask= _mm_cmpgt_ps(a, p4f_half);//this is to select which branch to take
+//both will be taken, and finally results will be merged
+//the branch for values >0.5
+
+ {
+//the core series expansion
+ z1=pmadd(p4f_minus_half,a,p4f_half);
+ Packet4f x1=psqrt(z1);
+ Packet4f s1=pmadd(p4f_asin1, z1, p4f_asin2);
+ Packet4f s2=pmadd(s1, z1, p4f_asin3);
+ Packet4f s3=pmadd(s2,z1, p4f_asin4);
+ Packet4f s4=pmadd(s3,z1, p4f_asin5);
+ Packet4f temp=pmul(s4,z1);//not really a madd but a mul by z so that the next term can be a madd
+ z1=pmadd(temp,x1,x1);
+ z1=padd(z1,z1);
+ z1=psub(p4f_pi_over_2,z1);
+ }
+
+ {
+//the core series expansion
+ Packet4f x2=a;
+ z2=pmul(x2,x2);
+ Packet4f s1=pmadd(p4f_asin1, z2, p4f_asin2);
+ Packet4f s2=pmadd(s1, z2, p4f_asin3);
+ Packet4f s3=pmadd(s2,z2, p4f_asin4);
+ Packet4f s4=pmadd(s3,z2, p4f_asin5);
+ Packet4f temp=pmul(s4,z2);//not really a madd but a mul by z so that the next term can be a madd
+ z2=pmadd(temp,x2,x2);
+ }
+
+/* select the correct result from the two branch evaluations */
+ z1 = _mm_and_ps(branch_mask, z1);
+ z2 = _mm_andnot_ps(branch_mask, z2);
+ Packet4f z = _mm_or_ps(z1,z2);
+
+/* update the sign */
+ return _mm_xor_ps(z, sign_bit);
+}
+
+#endif // EIGEN_VECTORIZE_SSE
+
+} // end namespace internal
+
+} // end namespace Eigen
+
+#endif // EIGEN_MOREVECTORIZATION_MATHFUNCTIONS_H
diff --git a/unsupported/Eigen/src/NonLinearOptimization/CMakeLists.txt b/unsupported/Eigen/src/NonLinearOptimization/CMakeLists.txt
new file mode 100644
index 000000000..9322ddadf
--- /dev/null
+++ b/unsupported/Eigen/src/NonLinearOptimization/CMakeLists.txt
@@ -0,0 +1,6 @@
+FILE(GLOB Eigen_NonLinearOptimization_SRCS "*.h")
+
+INSTALL(FILES
+ ${Eigen_NonLinearOptimization_SRCS}
+ DESTINATION ${INCLUDE_INSTALL_DIR}/unsupported/Eigen/src/NonLinearOptimization COMPONENT Devel
+ )
diff --git a/unsupported/Eigen/src/NonLinearOptimization/HybridNonLinearSolver.h b/unsupported/Eigen/src/NonLinearOptimization/HybridNonLinearSolver.h
new file mode 100644
index 000000000..d9ce4eab6
--- /dev/null
+++ b/unsupported/Eigen/src/NonLinearOptimization/HybridNonLinearSolver.h
@@ -0,0 +1,596 @@
+// -*- coding: utf-8
+// vim: set fileencoding=utf-8
+
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra.
+//
+// Copyright (C) 2009 Thomas Capricelli <orzel@freehackers.org>
+//
+// This Source Code Form is subject to the terms of the Mozilla
+// Public License v. 2.0. If a copy of the MPL was not distributed
+// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+#ifndef EIGEN_HYBRIDNONLINEARSOLVER_H
+#define EIGEN_HYBRIDNONLINEARSOLVER_H
+
+namespace Eigen {
+
+namespace HybridNonLinearSolverSpace {
+ enum Status {
+ Running = -1,
+ ImproperInputParameters = 0,
+ RelativeErrorTooSmall = 1,
+ TooManyFunctionEvaluation = 2,
+ TolTooSmall = 3,
+ NotMakingProgressJacobian = 4,
+ NotMakingProgressIterations = 5,
+ UserAsked = 6
+ };
+}
+
+/**
+ * \ingroup NonLinearOptimization_Module
+ * \brief Finds a zero of a system of n
+ * nonlinear functions in n variables by a modification of the Powell
+ * hybrid method ("dogleg").
+ *
+ * The user must provide a subroutine which calculates the
+ * functions. The Jacobian is either provided by the user, or approximated
+ * using a forward-difference method.
+ *
+ */
+template<typename FunctorType, typename Scalar=double>
+class HybridNonLinearSolver
+{
+public:
+ typedef DenseIndex Index;
+
+ HybridNonLinearSolver(FunctorType &_functor)
+ : functor(_functor) { nfev=njev=iter = 0; fnorm= 0.; useExternalScaling=false;}
+
+ struct Parameters {
+ Parameters()
+ : factor(Scalar(100.))
+ , maxfev(1000)
+ , xtol(internal::sqrt(NumTraits<Scalar>::epsilon()))
+ , nb_of_subdiagonals(-1)
+ , nb_of_superdiagonals(-1)
+ , epsfcn(Scalar(0.)) {}
+ Scalar factor;
+ Index maxfev; // maximum number of function evaluation
+ Scalar xtol;
+ Index nb_of_subdiagonals;
+ Index nb_of_superdiagonals;
+ Scalar epsfcn;
+ };
+ typedef Matrix< Scalar, Dynamic, 1 > FVectorType;
+ typedef Matrix< Scalar, Dynamic, Dynamic > JacobianType;
+ /* TODO: if eigen provides a triangular storage, use it here */
+ typedef Matrix< Scalar, Dynamic, Dynamic > UpperTriangularType;
+
+ HybridNonLinearSolverSpace::Status hybrj1(
+ FVectorType &x,
+ const Scalar tol = internal::sqrt(NumTraits<Scalar>::epsilon())
+ );
+
+ HybridNonLinearSolverSpace::Status solveInit(FVectorType &x);
+ HybridNonLinearSolverSpace::Status solveOneStep(FVectorType &x);
+ HybridNonLinearSolverSpace::Status solve(FVectorType &x);
+
+ HybridNonLinearSolverSpace::Status hybrd1(
+ FVectorType &x,
+ const Scalar tol = internal::sqrt(NumTraits<Scalar>::epsilon())
+ );
+
+ HybridNonLinearSolverSpace::Status solveNumericalDiffInit(FVectorType &x);
+ HybridNonLinearSolverSpace::Status solveNumericalDiffOneStep(FVectorType &x);
+ HybridNonLinearSolverSpace::Status solveNumericalDiff(FVectorType &x);
+
+ void resetParameters(void) { parameters = Parameters(); }
+ Parameters parameters;
+ FVectorType fvec, qtf, diag;
+ JacobianType fjac;
+ UpperTriangularType R;
+ Index nfev;
+ Index njev;
+ Index iter;
+ Scalar fnorm;
+ bool useExternalScaling;
+private:
+ FunctorType &functor;
+ Index n;
+ Scalar sum;
+ bool sing;
+ Scalar temp;
+ Scalar delta;
+ bool jeval;
+ Index ncsuc;
+ Scalar ratio;
+ Scalar pnorm, xnorm, fnorm1;
+ Index nslow1, nslow2;
+ Index ncfail;
+ Scalar actred, prered;
+ FVectorType wa1, wa2, wa3, wa4;
+
+ HybridNonLinearSolver& operator=(const HybridNonLinearSolver&);
+};
+
+
+
+template<typename FunctorType, typename Scalar>
+HybridNonLinearSolverSpace::Status
+HybridNonLinearSolver<FunctorType,Scalar>::hybrj1(
+ FVectorType &x,
+ const Scalar tol
+ )
+{
+ n = x.size();
+
+ /* check the input parameters for errors. */
+ if (n <= 0 || tol < 0.)
+ return HybridNonLinearSolverSpace::ImproperInputParameters;
+
+ resetParameters();
+ parameters.maxfev = 100*(n+1);
+ parameters.xtol = tol;
+ diag.setConstant(n, 1.);
+ useExternalScaling = true;
+ return solve(x);
+}
+
+template<typename FunctorType, typename Scalar>
+HybridNonLinearSolverSpace::Status
+HybridNonLinearSolver<FunctorType,Scalar>::solveInit(FVectorType &x)
+{
+ n = x.size();
+
+ wa1.resize(n); wa2.resize(n); wa3.resize(n); wa4.resize(n);
+ fvec.resize(n);
+ qtf.resize(n);
+ fjac.resize(n, n);
+ if (!useExternalScaling)
+ diag.resize(n);
+ assert( (!useExternalScaling || diag.size()==n) || "When useExternalScaling is set, the caller must provide a valid 'diag'");
+
+ /* Function Body */
+ nfev = 0;
+ njev = 0;
+
+ /* check the input parameters for errors. */
+ if (n <= 0 || parameters.xtol < 0. || parameters.maxfev <= 0 || parameters.factor <= 0. )
+ return HybridNonLinearSolverSpace::ImproperInputParameters;
+ if (useExternalScaling)
+ for (Index j = 0; j < n; ++j)
+ if (diag[j] <= 0.)
+ return HybridNonLinearSolverSpace::ImproperInputParameters;
+
+ /* evaluate the function at the starting point */
+ /* and calculate its norm. */
+ nfev = 1;
+ if ( functor(x, fvec) < 0)
+ return HybridNonLinearSolverSpace::UserAsked;
+ fnorm = fvec.stableNorm();
+
+ /* initialize iteration counter and monitors. */
+ iter = 1;
+ ncsuc = 0;
+ ncfail = 0;
+ nslow1 = 0;
+ nslow2 = 0;
+
+ return HybridNonLinearSolverSpace::Running;
+}
+
+template<typename FunctorType, typename Scalar>
+HybridNonLinearSolverSpace::Status
+HybridNonLinearSolver<FunctorType,Scalar>::solveOneStep(FVectorType &x)
+{
+ assert(x.size()==n); // check the caller is not cheating us
+
+ Index j;
+ std::vector<JacobiRotation<Scalar> > v_givens(n), w_givens(n);
+
+ jeval = true;
+
+ /* calculate the jacobian matrix. */
+ if ( functor.df(x, fjac) < 0)
+ return HybridNonLinearSolverSpace::UserAsked;
+ ++njev;
+
+ wa2 = fjac.colwise().blueNorm();
+
+ /* on the first iteration and if external scaling is not used, scale according */
+ /* to the norms of the columns of the initial jacobian. */
+ if (iter == 1) {
+ if (!useExternalScaling)
+ for (j = 0; j < n; ++j)
+ diag[j] = (wa2[j]==0.) ? 1. : wa2[j];
+
+ /* on the first iteration, calculate the norm of the scaled x */
+ /* and initialize the step bound delta. */
+ xnorm = diag.cwiseProduct(x).stableNorm();
+ delta = parameters.factor * xnorm;
+ if (delta == 0.)
+ delta = parameters.factor;
+ }
+
+ /* compute the qr factorization of the jacobian. */
+ HouseholderQR<JacobianType> qrfac(fjac); // no pivoting:
+
+ /* copy the triangular factor of the qr factorization into r. */
+ R = qrfac.matrixQR();
+
+ /* accumulate the orthogonal factor in fjac. */
+ fjac = qrfac.householderQ();
+
+ /* form (q transpose)*fvec and store in qtf. */
+ qtf = fjac.transpose() * fvec;
+
+ /* rescale if necessary. */
+ if (!useExternalScaling)
+ diag = diag.cwiseMax(wa2);
+
+ while (true) {
+ /* determine the direction p. */
+ internal::dogleg<Scalar>(R, diag, qtf, delta, wa1);
+
+ /* store the direction p and x + p. calculate the norm of p. */
+ wa1 = -wa1;
+ wa2 = x + wa1;
+ pnorm = diag.cwiseProduct(wa1).stableNorm();
+
+ /* on the first iteration, adjust the initial step bound. */
+ if (iter == 1)
+ delta = (std::min)(delta,pnorm);
+
+ /* evaluate the function at x + p and calculate its norm. */
+ if ( functor(wa2, wa4) < 0)
+ return HybridNonLinearSolverSpace::UserAsked;
+ ++nfev;
+ fnorm1 = wa4.stableNorm();
+
+ /* compute the scaled actual reduction. */
+ actred = -1.;
+ if (fnorm1 < fnorm) /* Computing 2nd power */
+ actred = 1. - internal::abs2(fnorm1 / fnorm);
+
+ /* compute the scaled predicted reduction. */
+ wa3 = R.template triangularView<Upper>()*wa1 + qtf;
+ temp = wa3.stableNorm();
+ prered = 0.;
+ if (temp < fnorm) /* Computing 2nd power */
+ prered = 1. - internal::abs2(temp / fnorm);
+
+ /* compute the ratio of the actual to the predicted reduction. */
+ ratio = 0.;
+ if (prered > 0.)
+ ratio = actred / prered;
+
+ /* update the step bound. */
+ if (ratio < Scalar(.1)) {
+ ncsuc = 0;
+ ++ncfail;
+ delta = Scalar(.5) * delta;
+ } else {
+ ncfail = 0;
+ ++ncsuc;
+ if (ratio >= Scalar(.5) || ncsuc > 1)
+ delta = (std::max)(delta, pnorm / Scalar(.5));
+ if (internal::abs(ratio - 1.) <= Scalar(.1)) {
+ delta = pnorm / Scalar(.5);
+ }
+ }
+
+ /* test for successful iteration. */
+ if (ratio >= Scalar(1e-4)) {
+ /* successful iteration. update x, fvec, and their norms. */
+ x = wa2;
+ wa2 = diag.cwiseProduct(x);
+ fvec = wa4;
+ xnorm = wa2.stableNorm();
+ fnorm = fnorm1;
+ ++iter;
+ }
+
+ /* determine the progress of the iteration. */
+ ++nslow1;
+ if (actred >= Scalar(.001))
+ nslow1 = 0;
+ if (jeval)
+ ++nslow2;
+ if (actred >= Scalar(.1))
+ nslow2 = 0;
+
+ /* test for convergence. */
+ if (delta <= parameters.xtol * xnorm || fnorm == 0.)
+ return HybridNonLinearSolverSpace::RelativeErrorTooSmall;
+
+ /* tests for termination and stringent tolerances. */
+ if (nfev >= parameters.maxfev)
+ return HybridNonLinearSolverSpace::TooManyFunctionEvaluation;
+ if (Scalar(.1) * (std::max)(Scalar(.1) * delta, pnorm) <= NumTraits<Scalar>::epsilon() * xnorm)
+ return HybridNonLinearSolverSpace::TolTooSmall;
+ if (nslow2 == 5)
+ return HybridNonLinearSolverSpace::NotMakingProgressJacobian;
+ if (nslow1 == 10)
+ return HybridNonLinearSolverSpace::NotMakingProgressIterations;
+
+ /* criterion for recalculating jacobian. */
+ if (ncfail == 2)
+ break; // leave inner loop and go for the next outer loop iteration
+
+ /* calculate the rank one modification to the jacobian */
+ /* and update qtf if necessary. */
+ wa1 = diag.cwiseProduct( diag.cwiseProduct(wa1)/pnorm );
+ wa2 = fjac.transpose() * wa4;
+ if (ratio >= Scalar(1e-4))
+ qtf = wa2;
+ wa2 = (wa2-wa3)/pnorm;
+
+ /* compute the qr factorization of the updated jacobian. */
+ internal::r1updt<Scalar>(R, wa1, v_givens, w_givens, wa2, wa3, &sing);
+ internal::r1mpyq<Scalar>(n, n, fjac.data(), v_givens, w_givens);
+ internal::r1mpyq<Scalar>(1, n, qtf.data(), v_givens, w_givens);
+
+ jeval = false;
+ }
+ return HybridNonLinearSolverSpace::Running;
+}
+
+template<typename FunctorType, typename Scalar>
+HybridNonLinearSolverSpace::Status
+HybridNonLinearSolver<FunctorType,Scalar>::solve(FVectorType &x)
+{
+ HybridNonLinearSolverSpace::Status status = solveInit(x);
+ if (status==HybridNonLinearSolverSpace::ImproperInputParameters)
+ return status;
+ while (status==HybridNonLinearSolverSpace::Running)
+ status = solveOneStep(x);
+ return status;
+}
+
+
+
+template<typename FunctorType, typename Scalar>
+HybridNonLinearSolverSpace::Status
+HybridNonLinearSolver<FunctorType,Scalar>::hybrd1(
+ FVectorType &x,
+ const Scalar tol
+ )
+{
+ n = x.size();
+
+ /* check the input parameters for errors. */
+ if (n <= 0 || tol < 0.)
+ return HybridNonLinearSolverSpace::ImproperInputParameters;
+
+ resetParameters();
+ parameters.maxfev = 200*(n+1);
+ parameters.xtol = tol;
+
+ diag.setConstant(n, 1.);
+ useExternalScaling = true;
+ return solveNumericalDiff(x);
+}
+
+template<typename FunctorType, typename Scalar>
+HybridNonLinearSolverSpace::Status
+HybridNonLinearSolver<FunctorType,Scalar>::solveNumericalDiffInit(FVectorType &x)
+{
+ n = x.size();
+
+ if (parameters.nb_of_subdiagonals<0) parameters.nb_of_subdiagonals= n-1;
+ if (parameters.nb_of_superdiagonals<0) parameters.nb_of_superdiagonals= n-1;
+
+ wa1.resize(n); wa2.resize(n); wa3.resize(n); wa4.resize(n);
+ qtf.resize(n);
+ fjac.resize(n, n);
+ fvec.resize(n);
+ if (!useExternalScaling)
+ diag.resize(n);
+ assert( (!useExternalScaling || diag.size()==n) || "When useExternalScaling is set, the caller must provide a valid 'diag'");
+
+ /* Function Body */
+ nfev = 0;
+ njev = 0;
+
+ /* check the input parameters for errors. */
+ if (n <= 0 || parameters.xtol < 0. || parameters.maxfev <= 0 || parameters.nb_of_subdiagonals< 0 || parameters.nb_of_superdiagonals< 0 || parameters.factor <= 0. )
+ return HybridNonLinearSolverSpace::ImproperInputParameters;
+ if (useExternalScaling)
+ for (Index j = 0; j < n; ++j)
+ if (diag[j] <= 0.)
+ return HybridNonLinearSolverSpace::ImproperInputParameters;
+
+ /* evaluate the function at the starting point */
+ /* and calculate its norm. */
+ nfev = 1;
+ if ( functor(x, fvec) < 0)
+ return HybridNonLinearSolverSpace::UserAsked;
+ fnorm = fvec.stableNorm();
+
+ /* initialize iteration counter and monitors. */
+ iter = 1;
+ ncsuc = 0;
+ ncfail = 0;
+ nslow1 = 0;
+ nslow2 = 0;
+
+ return HybridNonLinearSolverSpace::Running;
+}
+
+template<typename FunctorType, typename Scalar>
+HybridNonLinearSolverSpace::Status
+HybridNonLinearSolver<FunctorType,Scalar>::solveNumericalDiffOneStep(FVectorType &x)
+{
+ assert(x.size()==n); // check the caller is not cheating us
+
+ Index j;
+ std::vector<JacobiRotation<Scalar> > v_givens(n), w_givens(n);
+
+ jeval = true;
+ if (parameters.nb_of_subdiagonals<0) parameters.nb_of_subdiagonals= n-1;
+ if (parameters.nb_of_superdiagonals<0) parameters.nb_of_superdiagonals= n-1;
+
+ /* calculate the jacobian matrix. */
+ if (internal::fdjac1(functor, x, fvec, fjac, parameters.nb_of_subdiagonals, parameters.nb_of_superdiagonals, parameters.epsfcn) <0)
+ return HybridNonLinearSolverSpace::UserAsked;
+ nfev += (std::min)(parameters.nb_of_subdiagonals+parameters.nb_of_superdiagonals+ 1, n);
+
+ wa2 = fjac.colwise().blueNorm();
+
+ /* on the first iteration and if external scaling is not used, scale according */
+ /* to the norms of the columns of the initial jacobian. */
+ if (iter == 1) {
+ if (!useExternalScaling)
+ for (j = 0; j < n; ++j)
+ diag[j] = (wa2[j]==0.) ? 1. : wa2[j];
+
+ /* on the first iteration, calculate the norm of the scaled x */
+ /* and initialize the step bound delta. */
+ xnorm = diag.cwiseProduct(x).stableNorm();
+ delta = parameters.factor * xnorm;
+ if (delta == 0.)
+ delta = parameters.factor;
+ }
+
+ /* compute the qr factorization of the jacobian. */
+ HouseholderQR<JacobianType> qrfac(fjac); // no pivoting:
+
+ /* copy the triangular factor of the qr factorization into r. */
+ R = qrfac.matrixQR();
+
+ /* accumulate the orthogonal factor in fjac. */
+ fjac = qrfac.householderQ();
+
+ /* form (q transpose)*fvec and store in qtf. */
+ qtf = fjac.transpose() * fvec;
+
+ /* rescale if necessary. */
+ if (!useExternalScaling)
+ diag = diag.cwiseMax(wa2);
+
+ while (true) {
+ /* determine the direction p. */
+ internal::dogleg<Scalar>(R, diag, qtf, delta, wa1);
+
+ /* store the direction p and x + p. calculate the norm of p. */
+ wa1 = -wa1;
+ wa2 = x + wa1;
+ pnorm = diag.cwiseProduct(wa1).stableNorm();
+
+ /* on the first iteration, adjust the initial step bound. */
+ if (iter == 1)
+ delta = (std::min)(delta,pnorm);
+
+ /* evaluate the function at x + p and calculate its norm. */
+ if ( functor(wa2, wa4) < 0)
+ return HybridNonLinearSolverSpace::UserAsked;
+ ++nfev;
+ fnorm1 = wa4.stableNorm();
+
+ /* compute the scaled actual reduction. */
+ actred = -1.;
+ if (fnorm1 < fnorm) /* Computing 2nd power */
+ actred = 1. - internal::abs2(fnorm1 / fnorm);
+
+ /* compute the scaled predicted reduction. */
+ wa3 = R.template triangularView<Upper>()*wa1 + qtf;
+ temp = wa3.stableNorm();
+ prered = 0.;
+ if (temp < fnorm) /* Computing 2nd power */
+ prered = 1. - internal::abs2(temp / fnorm);
+
+ /* compute the ratio of the actual to the predicted reduction. */
+ ratio = 0.;
+ if (prered > 0.)
+ ratio = actred / prered;
+
+ /* update the step bound. */
+ if (ratio < Scalar(.1)) {
+ ncsuc = 0;
+ ++ncfail;
+ delta = Scalar(.5) * delta;
+ } else {
+ ncfail = 0;
+ ++ncsuc;
+ if (ratio >= Scalar(.5) || ncsuc > 1)
+ delta = (std::max)(delta, pnorm / Scalar(.5));
+ if (internal::abs(ratio - 1.) <= Scalar(.1)) {
+ delta = pnorm / Scalar(.5);
+ }
+ }
+
+ /* test for successful iteration. */
+ if (ratio >= Scalar(1e-4)) {
+ /* successful iteration. update x, fvec, and their norms. */
+ x = wa2;
+ wa2 = diag.cwiseProduct(x);
+ fvec = wa4;
+ xnorm = wa2.stableNorm();
+ fnorm = fnorm1;
+ ++iter;
+ }
+
+ /* determine the progress of the iteration. */
+ ++nslow1;
+ if (actred >= Scalar(.001))
+ nslow1 = 0;
+ if (jeval)
+ ++nslow2;
+ if (actred >= Scalar(.1))
+ nslow2 = 0;
+
+ /* test for convergence. */
+ if (delta <= parameters.xtol * xnorm || fnorm == 0.)
+ return HybridNonLinearSolverSpace::RelativeErrorTooSmall;
+
+ /* tests for termination and stringent tolerances. */
+ if (nfev >= parameters.maxfev)
+ return HybridNonLinearSolverSpace::TooManyFunctionEvaluation;
+ if (Scalar(.1) * (std::max)(Scalar(.1) * delta, pnorm) <= NumTraits<Scalar>::epsilon() * xnorm)
+ return HybridNonLinearSolverSpace::TolTooSmall;
+ if (nslow2 == 5)
+ return HybridNonLinearSolverSpace::NotMakingProgressJacobian;
+ if (nslow1 == 10)
+ return HybridNonLinearSolverSpace::NotMakingProgressIterations;
+
+ /* criterion for recalculating jacobian. */
+ if (ncfail == 2)
+ break; // leave inner loop and go for the next outer loop iteration
+
+ /* calculate the rank one modification to the jacobian */
+ /* and update qtf if necessary. */
+ wa1 = diag.cwiseProduct( diag.cwiseProduct(wa1)/pnorm );
+ wa2 = fjac.transpose() * wa4;
+ if (ratio >= Scalar(1e-4))
+ qtf = wa2;
+ wa2 = (wa2-wa3)/pnorm;
+
+ /* compute the qr factorization of the updated jacobian. */
+ internal::r1updt<Scalar>(R, wa1, v_givens, w_givens, wa2, wa3, &sing);
+ internal::r1mpyq<Scalar>(n, n, fjac.data(), v_givens, w_givens);
+ internal::r1mpyq<Scalar>(1, n, qtf.data(), v_givens, w_givens);
+
+ jeval = false;
+ }
+ return HybridNonLinearSolverSpace::Running;
+}
+
+template<typename FunctorType, typename Scalar>
+HybridNonLinearSolverSpace::Status
+HybridNonLinearSolver<FunctorType,Scalar>::solveNumericalDiff(FVectorType &x)
+{
+ HybridNonLinearSolverSpace::Status status = solveNumericalDiffInit(x);
+ if (status==HybridNonLinearSolverSpace::ImproperInputParameters)
+ return status;
+ while (status==HybridNonLinearSolverSpace::Running)
+ status = solveNumericalDiffOneStep(x);
+ return status;
+}
+
+} // end namespace Eigen
+
+#endif // EIGEN_HYBRIDNONLINEARSOLVER_H
+
+//vim: ai ts=4 sts=4 et sw=4
diff --git a/unsupported/Eigen/src/NonLinearOptimization/LevenbergMarquardt.h b/unsupported/Eigen/src/NonLinearOptimization/LevenbergMarquardt.h
new file mode 100644
index 000000000..075faeeb0
--- /dev/null
+++ b/unsupported/Eigen/src/NonLinearOptimization/LevenbergMarquardt.h
@@ -0,0 +1,644 @@
+// -*- coding: utf-8
+// vim: set fileencoding=utf-8
+
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra.
+//
+// Copyright (C) 2009 Thomas Capricelli <orzel@freehackers.org>
+//
+// This Source Code Form is subject to the terms of the Mozilla
+// Public License v. 2.0. If a copy of the MPL was not distributed
+// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+#ifndef EIGEN_LEVENBERGMARQUARDT__H
+#define EIGEN_LEVENBERGMARQUARDT__H
+
+namespace Eigen {
+
+namespace LevenbergMarquardtSpace {
+ enum Status {
+ NotStarted = -2,
+ Running = -1,
+ ImproperInputParameters = 0,
+ RelativeReductionTooSmall = 1,
+ RelativeErrorTooSmall = 2,
+ RelativeErrorAndReductionTooSmall = 3,
+ CosinusTooSmall = 4,
+ TooManyFunctionEvaluation = 5,
+ FtolTooSmall = 6,
+ XtolTooSmall = 7,
+ GtolTooSmall = 8,
+ UserAsked = 9
+ };
+}
+
+
+
+/**
+ * \ingroup NonLinearOptimization_Module
+ * \brief Performs non linear optimization over a non-linear function,
+ * using a variant of the Levenberg Marquardt algorithm.
+ *
+ * Check wikipedia for more information.
+ * http://en.wikipedia.org/wiki/Levenberg%E2%80%93Marquardt_algorithm
+ */
+template<typename FunctorType, typename Scalar=double>
+class LevenbergMarquardt
+{
+public:
+ LevenbergMarquardt(FunctorType &_functor)
+ : functor(_functor) { nfev = njev = iter = 0; fnorm = gnorm = 0.; useExternalScaling=false; }
+
+ typedef DenseIndex Index;
+
+ struct Parameters {
+ Parameters()
+ : factor(Scalar(100.))
+ , maxfev(400)
+ , ftol(internal::sqrt(NumTraits<Scalar>::epsilon()))
+ , xtol(internal::sqrt(NumTraits<Scalar>::epsilon()))
+ , gtol(Scalar(0.))
+ , epsfcn(Scalar(0.)) {}
+ Scalar factor;
+ Index maxfev; // maximum number of function evaluation
+ Scalar ftol;
+ Scalar xtol;
+ Scalar gtol;
+ Scalar epsfcn;
+ };
+
+ typedef Matrix< Scalar, Dynamic, 1 > FVectorType;
+ typedef Matrix< Scalar, Dynamic, Dynamic > JacobianType;
+
+ LevenbergMarquardtSpace::Status lmder1(
+ FVectorType &x,
+ const Scalar tol = internal::sqrt(NumTraits<Scalar>::epsilon())
+ );
+
+ LevenbergMarquardtSpace::Status minimize(FVectorType &x);
+ LevenbergMarquardtSpace::Status minimizeInit(FVectorType &x);
+ LevenbergMarquardtSpace::Status minimizeOneStep(FVectorType &x);
+
+ static LevenbergMarquardtSpace::Status lmdif1(
+ FunctorType &functor,
+ FVectorType &x,
+ Index *nfev,
+ const Scalar tol = internal::sqrt(NumTraits<Scalar>::epsilon())
+ );
+
+ LevenbergMarquardtSpace::Status lmstr1(
+ FVectorType &x,
+ const Scalar tol = internal::sqrt(NumTraits<Scalar>::epsilon())
+ );
+
+ LevenbergMarquardtSpace::Status minimizeOptimumStorage(FVectorType &x);
+ LevenbergMarquardtSpace::Status minimizeOptimumStorageInit(FVectorType &x);
+ LevenbergMarquardtSpace::Status minimizeOptimumStorageOneStep(FVectorType &x);
+
+ void resetParameters(void) { parameters = Parameters(); }
+
+ Parameters parameters;
+ FVectorType fvec, qtf, diag;
+ JacobianType fjac;
+ PermutationMatrix<Dynamic,Dynamic> permutation;
+ Index nfev;
+ Index njev;
+ Index iter;
+ Scalar fnorm, gnorm;
+ bool useExternalScaling;
+
+ Scalar lm_param(void) { return par; }
+private:
+ FunctorType &functor;
+ Index n;
+ Index m;
+ FVectorType wa1, wa2, wa3, wa4;
+
+ Scalar par, sum;
+ Scalar temp, temp1, temp2;
+ Scalar delta;
+ Scalar ratio;
+ Scalar pnorm, xnorm, fnorm1, actred, dirder, prered;
+
+ LevenbergMarquardt& operator=(const LevenbergMarquardt&);
+};
+
+template<typename FunctorType, typename Scalar>
+LevenbergMarquardtSpace::Status
+LevenbergMarquardt<FunctorType,Scalar>::lmder1(
+ FVectorType &x,
+ const Scalar tol
+ )
+{
+ n = x.size();
+ m = functor.values();
+
+ /* check the input parameters for errors. */
+ if (n <= 0 || m < n || tol < 0.)
+ return LevenbergMarquardtSpace::ImproperInputParameters;
+
+ resetParameters();
+ parameters.ftol = tol;
+ parameters.xtol = tol;
+ parameters.maxfev = 100*(n+1);
+
+ return minimize(x);
+}
+
+
+template<typename FunctorType, typename Scalar>
+LevenbergMarquardtSpace::Status
+LevenbergMarquardt<FunctorType,Scalar>::minimize(FVectorType &x)
+{
+ LevenbergMarquardtSpace::Status status = minimizeInit(x);
+ if (status==LevenbergMarquardtSpace::ImproperInputParameters)
+ return status;
+ do {
+ status = minimizeOneStep(x);
+ } while (status==LevenbergMarquardtSpace::Running);
+ return status;
+}
+
+template<typename FunctorType, typename Scalar>
+LevenbergMarquardtSpace::Status
+LevenbergMarquardt<FunctorType,Scalar>::minimizeInit(FVectorType &x)
+{
+ n = x.size();
+ m = functor.values();
+
+ wa1.resize(n); wa2.resize(n); wa3.resize(n);
+ wa4.resize(m);
+ fvec.resize(m);
+ fjac.resize(m, n);
+ if (!useExternalScaling)
+ diag.resize(n);
+ assert( (!useExternalScaling || diag.size()==n) || "When useExternalScaling is set, the caller must provide a valid 'diag'");
+ qtf.resize(n);
+
+ /* Function Body */
+ nfev = 0;
+ njev = 0;
+
+ /* check the input parameters for errors. */
+ if (n <= 0 || m < n || parameters.ftol < 0. || parameters.xtol < 0. || parameters.gtol < 0. || parameters.maxfev <= 0 || parameters.factor <= 0.)
+ return LevenbergMarquardtSpace::ImproperInputParameters;
+
+ if (useExternalScaling)
+ for (Index j = 0; j < n; ++j)
+ if (diag[j] <= 0.)
+ return LevenbergMarquardtSpace::ImproperInputParameters;
+
+ /* evaluate the function at the starting point */
+ /* and calculate its norm. */
+ nfev = 1;
+ if ( functor(x, fvec) < 0)
+ return LevenbergMarquardtSpace::UserAsked;
+ fnorm = fvec.stableNorm();
+
+ /* initialize levenberg-marquardt parameter and iteration counter. */
+ par = 0.;
+ iter = 1;
+
+ return LevenbergMarquardtSpace::NotStarted;
+}
+
+template<typename FunctorType, typename Scalar>
+LevenbergMarquardtSpace::Status
+LevenbergMarquardt<FunctorType,Scalar>::minimizeOneStep(FVectorType &x)
+{
+ assert(x.size()==n); // check the caller is not cheating us
+
+ /* calculate the jacobian matrix. */
+ Index df_ret = functor.df(x, fjac);
+ if (df_ret<0)
+ return LevenbergMarquardtSpace::UserAsked;
+ if (df_ret>0)
+ // numerical diff, we evaluated the function df_ret times
+ nfev += df_ret;
+ else njev++;
+
+ /* compute the qr factorization of the jacobian. */
+ wa2 = fjac.colwise().blueNorm();
+ ColPivHouseholderQR<JacobianType> qrfac(fjac);
+ fjac = qrfac.matrixQR();
+ permutation = qrfac.colsPermutation();
+
+ /* on the first iteration and if external scaling is not used, scale according */
+ /* to the norms of the columns of the initial jacobian. */
+ if (iter == 1) {
+ if (!useExternalScaling)
+ for (Index j = 0; j < n; ++j)
+ diag[j] = (wa2[j]==0.)? 1. : wa2[j];
+
+ /* on the first iteration, calculate the norm of the scaled x */
+ /* and initialize the step bound delta. */
+ xnorm = diag.cwiseProduct(x).stableNorm();
+ delta = parameters.factor * xnorm;
+ if (delta == 0.)
+ delta = parameters.factor;
+ }
+
+ /* form (q transpose)*fvec and store the first n components in */
+ /* qtf. */
+ wa4 = fvec;
+ wa4.applyOnTheLeft(qrfac.householderQ().adjoint());
+ qtf = wa4.head(n);
+
+ /* compute the norm of the scaled gradient. */
+ gnorm = 0.;
+ if (fnorm != 0.)
+ for (Index j = 0; j < n; ++j)
+ if (wa2[permutation.indices()[j]] != 0.)
+ gnorm = (std::max)(gnorm, internal::abs( fjac.col(j).head(j+1).dot(qtf.head(j+1)/fnorm) / wa2[permutation.indices()[j]]));
+
+ /* test for convergence of the gradient norm. */
+ if (gnorm <= parameters.gtol)
+ return LevenbergMarquardtSpace::CosinusTooSmall;
+
+ /* rescale if necessary. */
+ if (!useExternalScaling)
+ diag = diag.cwiseMax(wa2);
+
+ do {
+
+ /* determine the levenberg-marquardt parameter. */
+ internal::lmpar2<Scalar>(qrfac, diag, qtf, delta, par, wa1);
+
+ /* store the direction p and x + p. calculate the norm of p. */
+ wa1 = -wa1;
+ wa2 = x + wa1;
+ pnorm = diag.cwiseProduct(wa1).stableNorm();
+
+ /* on the first iteration, adjust the initial step bound. */
+ if (iter == 1)
+ delta = (std::min)(delta,pnorm);
+
+ /* evaluate the function at x + p and calculate its norm. */
+ if ( functor(wa2, wa4) < 0)
+ return LevenbergMarquardtSpace::UserAsked;
+ ++nfev;
+ fnorm1 = wa4.stableNorm();
+
+ /* compute the scaled actual reduction. */
+ actred = -1.;
+ if (Scalar(.1) * fnorm1 < fnorm)
+ actred = 1. - internal::abs2(fnorm1 / fnorm);
+
+ /* compute the scaled predicted reduction and */
+ /* the scaled directional derivative. */
+ wa3 = fjac.template triangularView<Upper>() * (qrfac.colsPermutation().inverse() *wa1);
+ temp1 = internal::abs2(wa3.stableNorm() / fnorm);
+ temp2 = internal::abs2(internal::sqrt(par) * pnorm / fnorm);
+ prered = temp1 + temp2 / Scalar(.5);
+ dirder = -(temp1 + temp2);
+
+ /* compute the ratio of the actual to the predicted */
+ /* reduction. */
+ ratio = 0.;
+ if (prered != 0.)
+ ratio = actred / prered;
+
+ /* update the step bound. */
+ if (ratio <= Scalar(.25)) {
+ if (actred >= 0.)
+ temp = Scalar(.5);
+ if (actred < 0.)
+ temp = Scalar(.5) * dirder / (dirder + Scalar(.5) * actred);
+ if (Scalar(.1) * fnorm1 >= fnorm || temp < Scalar(.1))
+ temp = Scalar(.1);
+ /* Computing MIN */
+ delta = temp * (std::min)(delta, pnorm / Scalar(.1));
+ par /= temp;
+ } else if (!(par != 0. && ratio < Scalar(.75))) {
+ delta = pnorm / Scalar(.5);
+ par = Scalar(.5) * par;
+ }
+
+ /* test for successful iteration. */
+ if (ratio >= Scalar(1e-4)) {
+ /* successful iteration. update x, fvec, and their norms. */
+ x = wa2;
+ wa2 = diag.cwiseProduct(x);
+ fvec = wa4;
+ xnorm = wa2.stableNorm();
+ fnorm = fnorm1;
+ ++iter;
+ }
+
+ /* tests for convergence. */
+ if (internal::abs(actred) <= parameters.ftol && prered <= parameters.ftol && Scalar(.5) * ratio <= 1. && delta <= parameters.xtol * xnorm)
+ return LevenbergMarquardtSpace::RelativeErrorAndReductionTooSmall;
+ if (internal::abs(actred) <= parameters.ftol && prered <= parameters.ftol && Scalar(.5) * ratio <= 1.)
+ return LevenbergMarquardtSpace::RelativeReductionTooSmall;
+ if (delta <= parameters.xtol * xnorm)
+ return LevenbergMarquardtSpace::RelativeErrorTooSmall;
+
+ /* tests for termination and stringent tolerances. */
+ if (nfev >= parameters.maxfev)
+ return LevenbergMarquardtSpace::TooManyFunctionEvaluation;
+ if (internal::abs(actred) <= NumTraits<Scalar>::epsilon() && prered <= NumTraits<Scalar>::epsilon() && Scalar(.5) * ratio <= 1.)
+ return LevenbergMarquardtSpace::FtolTooSmall;
+ if (delta <= NumTraits<Scalar>::epsilon() * xnorm)
+ return LevenbergMarquardtSpace::XtolTooSmall;
+ if (gnorm <= NumTraits<Scalar>::epsilon())
+ return LevenbergMarquardtSpace::GtolTooSmall;
+
+ } while (ratio < Scalar(1e-4));
+
+ return LevenbergMarquardtSpace::Running;
+}
+
+template<typename FunctorType, typename Scalar>
+LevenbergMarquardtSpace::Status
+LevenbergMarquardt<FunctorType,Scalar>::lmstr1(
+ FVectorType &x,
+ const Scalar tol
+ )
+{
+ n = x.size();
+ m = functor.values();
+
+ /* check the input parameters for errors. */
+ if (n <= 0 || m < n || tol < 0.)
+ return LevenbergMarquardtSpace::ImproperInputParameters;
+
+ resetParameters();
+ parameters.ftol = tol;
+ parameters.xtol = tol;
+ parameters.maxfev = 100*(n+1);
+
+ return minimizeOptimumStorage(x);
+}
+
+template<typename FunctorType, typename Scalar>
+LevenbergMarquardtSpace::Status
+LevenbergMarquardt<FunctorType,Scalar>::minimizeOptimumStorageInit(FVectorType &x)
+{
+ n = x.size();
+ m = functor.values();
+
+ wa1.resize(n); wa2.resize(n); wa3.resize(n);
+ wa4.resize(m);
+ fvec.resize(m);
+ // Only R is stored in fjac. Q is only used to compute 'qtf', which is
+ // Q.transpose()*rhs. qtf will be updated using givens rotation,
+ // instead of storing them in Q.
+ // The purpose it to only use a nxn matrix, instead of mxn here, so
+ // that we can handle cases where m>>n :
+ fjac.resize(n, n);
+ if (!useExternalScaling)
+ diag.resize(n);
+ assert( (!useExternalScaling || diag.size()==n) || "When useExternalScaling is set, the caller must provide a valid 'diag'");
+ qtf.resize(n);
+
+ /* Function Body */
+ nfev = 0;
+ njev = 0;
+
+ /* check the input parameters for errors. */
+ if (n <= 0 || m < n || parameters.ftol < 0. || parameters.xtol < 0. || parameters.gtol < 0. || parameters.maxfev <= 0 || parameters.factor <= 0.)
+ return LevenbergMarquardtSpace::ImproperInputParameters;
+
+ if (useExternalScaling)
+ for (Index j = 0; j < n; ++j)
+ if (diag[j] <= 0.)
+ return LevenbergMarquardtSpace::ImproperInputParameters;
+
+ /* evaluate the function at the starting point */
+ /* and calculate its norm. */
+ nfev = 1;
+ if ( functor(x, fvec) < 0)
+ return LevenbergMarquardtSpace::UserAsked;
+ fnorm = fvec.stableNorm();
+
+ /* initialize levenberg-marquardt parameter and iteration counter. */
+ par = 0.;
+ iter = 1;
+
+ return LevenbergMarquardtSpace::NotStarted;
+}
+
+
+template<typename FunctorType, typename Scalar>
+LevenbergMarquardtSpace::Status
+LevenbergMarquardt<FunctorType,Scalar>::minimizeOptimumStorageOneStep(FVectorType &x)
+{
+ assert(x.size()==n); // check the caller is not cheating us
+
+ Index i, j;
+ bool sing;
+
+ /* compute the qr factorization of the jacobian matrix */
+ /* calculated one row at a time, while simultaneously */
+ /* forming (q transpose)*fvec and storing the first */
+ /* n components in qtf. */
+ qtf.fill(0.);
+ fjac.fill(0.);
+ Index rownb = 2;
+ for (i = 0; i < m; ++i) {
+ if (functor.df(x, wa3, rownb) < 0) return LevenbergMarquardtSpace::UserAsked;
+ internal::rwupdt<Scalar>(fjac, wa3, qtf, fvec[i]);
+ ++rownb;
+ }
+ ++njev;
+
+ /* if the jacobian is rank deficient, call qrfac to */
+ /* reorder its columns and update the components of qtf. */
+ sing = false;
+ for (j = 0; j < n; ++j) {
+ if (fjac(j,j) == 0.)
+ sing = true;
+ wa2[j] = fjac.col(j).head(j).stableNorm();
+ }
+ permutation.setIdentity(n);
+ if (sing) {
+ wa2 = fjac.colwise().blueNorm();
+ // TODO We have no unit test covering this code path, do not modify
+ // until it is carefully tested
+ ColPivHouseholderQR<JacobianType> qrfac(fjac);
+ fjac = qrfac.matrixQR();
+ wa1 = fjac.diagonal();
+ fjac.diagonal() = qrfac.hCoeffs();
+ permutation = qrfac.colsPermutation();
+ // TODO : avoid this:
+ for(Index ii=0; ii< fjac.cols(); ii++) fjac.col(ii).segment(ii+1, fjac.rows()-ii-1) *= fjac(ii,ii); // rescale vectors
+
+ for (j = 0; j < n; ++j) {
+ if (fjac(j,j) != 0.) {
+ sum = 0.;
+ for (i = j; i < n; ++i)
+ sum += fjac(i,j) * qtf[i];
+ temp = -sum / fjac(j,j);
+ for (i = j; i < n; ++i)
+ qtf[i] += fjac(i,j) * temp;
+ }
+ fjac(j,j) = wa1[j];
+ }
+ }
+
+ /* on the first iteration and if external scaling is not used, scale according */
+ /* to the norms of the columns of the initial jacobian. */
+ if (iter == 1) {
+ if (!useExternalScaling)
+ for (j = 0; j < n; ++j)
+ diag[j] = (wa2[j]==0.)? 1. : wa2[j];
+
+ /* on the first iteration, calculate the norm of the scaled x */
+ /* and initialize the step bound delta. */
+ xnorm = diag.cwiseProduct(x).stableNorm();
+ delta = parameters.factor * xnorm;
+ if (delta == 0.)
+ delta = parameters.factor;
+ }
+
+ /* compute the norm of the scaled gradient. */
+ gnorm = 0.;
+ if (fnorm != 0.)
+ for (j = 0; j < n; ++j)
+ if (wa2[permutation.indices()[j]] != 0.)
+ gnorm = (std::max)(gnorm, internal::abs( fjac.col(j).head(j+1).dot(qtf.head(j+1)/fnorm) / wa2[permutation.indices()[j]]));
+
+ /* test for convergence of the gradient norm. */
+ if (gnorm <= parameters.gtol)
+ return LevenbergMarquardtSpace::CosinusTooSmall;
+
+ /* rescale if necessary. */
+ if (!useExternalScaling)
+ diag = diag.cwiseMax(wa2);
+
+ do {
+
+ /* determine the levenberg-marquardt parameter. */
+ internal::lmpar<Scalar>(fjac, permutation.indices(), diag, qtf, delta, par, wa1);
+
+ /* store the direction p and x + p. calculate the norm of p. */
+ wa1 = -wa1;
+ wa2 = x + wa1;
+ pnorm = diag.cwiseProduct(wa1).stableNorm();
+
+ /* on the first iteration, adjust the initial step bound. */
+ if (iter == 1)
+ delta = (std::min)(delta,pnorm);
+
+ /* evaluate the function at x + p and calculate its norm. */
+ if ( functor(wa2, wa4) < 0)
+ return LevenbergMarquardtSpace::UserAsked;
+ ++nfev;
+ fnorm1 = wa4.stableNorm();
+
+ /* compute the scaled actual reduction. */
+ actred = -1.;
+ if (Scalar(.1) * fnorm1 < fnorm)
+ actred = 1. - internal::abs2(fnorm1 / fnorm);
+
+ /* compute the scaled predicted reduction and */
+ /* the scaled directional derivative. */
+ wa3 = fjac.topLeftCorner(n,n).template triangularView<Upper>() * (permutation.inverse() * wa1);
+ temp1 = internal::abs2(wa3.stableNorm() / fnorm);
+ temp2 = internal::abs2(internal::sqrt(par) * pnorm / fnorm);
+ prered = temp1 + temp2 / Scalar(.5);
+ dirder = -(temp1 + temp2);
+
+ /* compute the ratio of the actual to the predicted */
+ /* reduction. */
+ ratio = 0.;
+ if (prered != 0.)
+ ratio = actred / prered;
+
+ /* update the step bound. */
+ if (ratio <= Scalar(.25)) {
+ if (actred >= 0.)
+ temp = Scalar(.5);
+ if (actred < 0.)
+ temp = Scalar(.5) * dirder / (dirder + Scalar(.5) * actred);
+ if (Scalar(.1) * fnorm1 >= fnorm || temp < Scalar(.1))
+ temp = Scalar(.1);
+ /* Computing MIN */
+ delta = temp * (std::min)(delta, pnorm / Scalar(.1));
+ par /= temp;
+ } else if (!(par != 0. && ratio < Scalar(.75))) {
+ delta = pnorm / Scalar(.5);
+ par = Scalar(.5) * par;
+ }
+
+ /* test for successful iteration. */
+ if (ratio >= Scalar(1e-4)) {
+ /* successful iteration. update x, fvec, and their norms. */
+ x = wa2;
+ wa2 = diag.cwiseProduct(x);
+ fvec = wa4;
+ xnorm = wa2.stableNorm();
+ fnorm = fnorm1;
+ ++iter;
+ }
+
+ /* tests for convergence. */
+ if (internal::abs(actred) <= parameters.ftol && prered <= parameters.ftol && Scalar(.5) * ratio <= 1. && delta <= parameters.xtol * xnorm)
+ return LevenbergMarquardtSpace::RelativeErrorAndReductionTooSmall;
+ if (internal::abs(actred) <= parameters.ftol && prered <= parameters.ftol && Scalar(.5) * ratio <= 1.)
+ return LevenbergMarquardtSpace::RelativeReductionTooSmall;
+ if (delta <= parameters.xtol * xnorm)
+ return LevenbergMarquardtSpace::RelativeErrorTooSmall;
+
+ /* tests for termination and stringent tolerances. */
+ if (nfev >= parameters.maxfev)
+ return LevenbergMarquardtSpace::TooManyFunctionEvaluation;
+ if (internal::abs(actred) <= NumTraits<Scalar>::epsilon() && prered <= NumTraits<Scalar>::epsilon() && Scalar(.5) * ratio <= 1.)
+ return LevenbergMarquardtSpace::FtolTooSmall;
+ if (delta <= NumTraits<Scalar>::epsilon() * xnorm)
+ return LevenbergMarquardtSpace::XtolTooSmall;
+ if (gnorm <= NumTraits<Scalar>::epsilon())
+ return LevenbergMarquardtSpace::GtolTooSmall;
+
+ } while (ratio < Scalar(1e-4));
+
+ return LevenbergMarquardtSpace::Running;
+}
+
+template<typename FunctorType, typename Scalar>
+LevenbergMarquardtSpace::Status
+LevenbergMarquardt<FunctorType,Scalar>::minimizeOptimumStorage(FVectorType &x)
+{
+ LevenbergMarquardtSpace::Status status = minimizeOptimumStorageInit(x);
+ if (status==LevenbergMarquardtSpace::ImproperInputParameters)
+ return status;
+ do {
+ status = minimizeOptimumStorageOneStep(x);
+ } while (status==LevenbergMarquardtSpace::Running);
+ return status;
+}
+
+template<typename FunctorType, typename Scalar>
+LevenbergMarquardtSpace::Status
+LevenbergMarquardt<FunctorType,Scalar>::lmdif1(
+ FunctorType &functor,
+ FVectorType &x,
+ Index *nfev,
+ const Scalar tol
+ )
+{
+ Index n = x.size();
+ Index m = functor.values();
+
+ /* check the input parameters for errors. */
+ if (n <= 0 || m < n || tol < 0.)
+ return LevenbergMarquardtSpace::ImproperInputParameters;
+
+ NumericalDiff<FunctorType> numDiff(functor);
+ // embedded LevenbergMarquardt
+ LevenbergMarquardt<NumericalDiff<FunctorType>, Scalar > lm(numDiff);
+ lm.parameters.ftol = tol;
+ lm.parameters.xtol = tol;
+ lm.parameters.maxfev = 200*(n+1);
+
+ LevenbergMarquardtSpace::Status info = LevenbergMarquardtSpace::Status(lm.minimize(x));
+ if (nfev)
+ * nfev = lm.nfev;
+ return info;
+}
+
+} // end namespace Eigen
+
+#endif // EIGEN_LEVENBERGMARQUARDT__H
+
+//vim: ai ts=4 sts=4 et sw=4
diff --git a/unsupported/Eigen/src/NonLinearOptimization/chkder.h b/unsupported/Eigen/src/NonLinearOptimization/chkder.h
new file mode 100644
index 000000000..ad37c5029
--- /dev/null
+++ b/unsupported/Eigen/src/NonLinearOptimization/chkder.h
@@ -0,0 +1,62 @@
+#define chkder_log10e 0.43429448190325182765
+#define chkder_factor 100.
+
+namespace Eigen {
+
+namespace internal {
+
+template<typename Scalar>
+void chkder(
+ const Matrix< Scalar, Dynamic, 1 > &x,
+ const Matrix< Scalar, Dynamic, 1 > &fvec,
+ const Matrix< Scalar, Dynamic, Dynamic > &fjac,
+ Matrix< Scalar, Dynamic, 1 > &xp,
+ const Matrix< Scalar, Dynamic, 1 > &fvecp,
+ int mode,
+ Matrix< Scalar, Dynamic, 1 > &err
+ )
+{
+ typedef DenseIndex Index;
+
+ const Scalar eps = sqrt(NumTraits<Scalar>::epsilon());
+ const Scalar epsf = chkder_factor * NumTraits<Scalar>::epsilon();
+ const Scalar epslog = chkder_log10e * log(eps);
+ Scalar temp;
+
+ const Index m = fvec.size(), n = x.size();
+
+ if (mode != 2) {
+ /* mode = 1. */
+ xp.resize(n);
+ for (Index j = 0; j < n; ++j) {
+ temp = eps * abs(x[j]);
+ if (temp == 0.)
+ temp = eps;
+ xp[j] = x[j] + temp;
+ }
+ }
+ else {
+ /* mode = 2. */
+ err.setZero(m);
+ for (Index j = 0; j < n; ++j) {
+ temp = abs(x[j]);
+ if (temp == 0.)
+ temp = 1.;
+ err += temp * fjac.col(j);
+ }
+ for (Index i = 0; i < m; ++i) {
+ temp = 1.;
+ if (fvec[i] != 0. && fvecp[i] != 0. && abs(fvecp[i] - fvec[i]) >= epsf * abs(fvec[i]))
+ temp = eps * abs((fvecp[i] - fvec[i]) / eps - err[i]) / (abs(fvec[i]) + abs(fvecp[i]));
+ err[i] = 1.;
+ if (temp > NumTraits<Scalar>::epsilon() && temp < eps)
+ err[i] = (chkder_log10e * log(temp) - epslog) / epslog;
+ if (temp >= eps)
+ err[i] = 0.;
+ }
+ }
+}
+
+} // end namespace internal
+
+} // end namespace Eigen
diff --git a/unsupported/Eigen/src/NonLinearOptimization/covar.h b/unsupported/Eigen/src/NonLinearOptimization/covar.h
new file mode 100644
index 000000000..c73a09645
--- /dev/null
+++ b/unsupported/Eigen/src/NonLinearOptimization/covar.h
@@ -0,0 +1,69 @@
+namespace Eigen {
+
+namespace internal {
+
+template <typename Scalar>
+void covar(
+ Matrix< Scalar, Dynamic, Dynamic > &r,
+ const VectorXi &ipvt,
+ Scalar tol = sqrt(NumTraits<Scalar>::epsilon()) )
+{
+ typedef DenseIndex Index;
+
+ /* Local variables */
+ Index i, j, k, l, ii, jj;
+ bool sing;
+ Scalar temp;
+
+ /* Function Body */
+ const Index n = r.cols();
+ const Scalar tolr = tol * abs(r(0,0));
+ Matrix< Scalar, Dynamic, 1 > wa(n);
+ assert(ipvt.size()==n);
+
+ /* form the inverse of r in the full upper triangle of r. */
+ l = -1;
+ for (k = 0; k < n; ++k)
+ if (abs(r(k,k)) > tolr) {
+ r(k,k) = 1. / r(k,k);
+ for (j = 0; j <= k-1; ++j) {
+ temp = r(k,k) * r(j,k);
+ r(j,k) = 0.;
+ r.col(k).head(j+1) -= r.col(j).head(j+1) * temp;
+ }
+ l = k;
+ }
+
+ /* form the full upper triangle of the inverse of (r transpose)*r */
+ /* in the full upper triangle of r. */
+ for (k = 0; k <= l; ++k) {
+ for (j = 0; j <= k-1; ++j)
+ r.col(j).head(j+1) += r.col(k).head(j+1) * r(j,k);
+ r.col(k).head(k+1) *= r(k,k);
+ }
+
+ /* form the full lower triangle of the covariance matrix */
+ /* in the strict lower triangle of r and in wa. */
+ for (j = 0; j < n; ++j) {
+ jj = ipvt[j];
+ sing = j > l;
+ for (i = 0; i <= j; ++i) {
+ if (sing)
+ r(i,j) = 0.;
+ ii = ipvt[i];
+ if (ii > jj)
+ r(ii,jj) = r(i,j);
+ if (ii < jj)
+ r(jj,ii) = r(i,j);
+ }
+ wa[jj] = r(j,j);
+ }
+
+ /* symmetrize the covariance matrix in r. */
+ r.topLeftCorner(n,n).template triangularView<StrictlyUpper>() = r.topLeftCorner(n,n).transpose();
+ r.diagonal() = wa;
+}
+
+} // end namespace internal
+
+} // end namespace Eigen
diff --git a/unsupported/Eigen/src/NonLinearOptimization/dogleg.h b/unsupported/Eigen/src/NonLinearOptimization/dogleg.h
new file mode 100644
index 000000000..4fbc98bfc
--- /dev/null
+++ b/unsupported/Eigen/src/NonLinearOptimization/dogleg.h
@@ -0,0 +1,104 @@
+namespace Eigen {
+
+namespace internal {
+
+template <typename Scalar>
+void dogleg(
+ const Matrix< Scalar, Dynamic, Dynamic > &qrfac,
+ const Matrix< Scalar, Dynamic, 1 > &diag,
+ const Matrix< Scalar, Dynamic, 1 > &qtb,
+ Scalar delta,
+ Matrix< Scalar, Dynamic, 1 > &x)
+{
+ typedef DenseIndex Index;
+
+ /* Local variables */
+ Index i, j;
+ Scalar sum, temp, alpha, bnorm;
+ Scalar gnorm, qnorm;
+ Scalar sgnorm;
+
+ /* Function Body */
+ const Scalar epsmch = NumTraits<Scalar>::epsilon();
+ const Index n = qrfac.cols();
+ assert(n==qtb.size());
+ assert(n==x.size());
+ assert(n==diag.size());
+ Matrix< Scalar, Dynamic, 1 > wa1(n), wa2(n);
+
+ /* first, calculate the gauss-newton direction. */
+ for (j = n-1; j >=0; --j) {
+ temp = qrfac(j,j);
+ if (temp == 0.) {
+ temp = epsmch * qrfac.col(j).head(j+1).maxCoeff();
+ if (temp == 0.)
+ temp = epsmch;
+ }
+ if (j==n-1)
+ x[j] = qtb[j] / temp;
+ else
+ x[j] = (qtb[j] - qrfac.row(j).tail(n-j-1).dot(x.tail(n-j-1))) / temp;
+ }
+
+ /* test whether the gauss-newton direction is acceptable. */
+ qnorm = diag.cwiseProduct(x).stableNorm();
+ if (qnorm <= delta)
+ return;
+
+ // TODO : this path is not tested by Eigen unit tests
+
+ /* the gauss-newton direction is not acceptable. */
+ /* next, calculate the scaled gradient direction. */
+
+ wa1.fill(0.);
+ for (j = 0; j < n; ++j) {
+ wa1.tail(n-j) += qrfac.row(j).tail(n-j) * qtb[j];
+ wa1[j] /= diag[j];
+ }
+
+ /* calculate the norm of the scaled gradient and test for */
+ /* the special case in which the scaled gradient is zero. */
+ gnorm = wa1.stableNorm();
+ sgnorm = 0.;
+ alpha = delta / qnorm;
+ if (gnorm == 0.)
+ goto algo_end;
+
+ /* calculate the point along the scaled gradient */
+ /* at which the quadratic is minimized. */
+ wa1.array() /= (diag*gnorm).array();
+ // TODO : once unit tests cover this part,:
+ // wa2 = qrfac.template triangularView<Upper>() * wa1;
+ for (j = 0; j < n; ++j) {
+ sum = 0.;
+ for (i = j; i < n; ++i) {
+ sum += qrfac(j,i) * wa1[i];
+ }
+ wa2[j] = sum;
+ }
+ temp = wa2.stableNorm();
+ sgnorm = gnorm / temp / temp;
+
+ /* test whether the scaled gradient direction is acceptable. */
+ alpha = 0.;
+ if (sgnorm >= delta)
+ goto algo_end;
+
+ /* the scaled gradient direction is not acceptable. */
+ /* finally, calculate the point along the dogleg */
+ /* at which the quadratic is minimized. */
+ bnorm = qtb.stableNorm();
+ temp = bnorm / gnorm * (bnorm / qnorm) * (sgnorm / delta);
+ temp = temp - delta / qnorm * abs2(sgnorm / delta) + sqrt(abs2(temp - delta / qnorm) + (1.-abs2(delta / qnorm)) * (1.-abs2(sgnorm / delta)));
+ alpha = delta / qnorm * (1. - abs2(sgnorm / delta)) / temp;
+algo_end:
+
+ /* form appropriate convex combination of the gauss-newton */
+ /* direction and the scaled gradient direction. */
+ temp = (1.-alpha) * (std::min)(sgnorm,delta);
+ x = temp * wa1 + alpha * x;
+}
+
+} // end namespace internal
+
+} // end namespace Eigen
diff --git a/unsupported/Eigen/src/NonLinearOptimization/fdjac1.h b/unsupported/Eigen/src/NonLinearOptimization/fdjac1.h
new file mode 100644
index 000000000..1cabe69ae
--- /dev/null
+++ b/unsupported/Eigen/src/NonLinearOptimization/fdjac1.h
@@ -0,0 +1,76 @@
+namespace Eigen {
+
+namespace internal {
+
+template<typename FunctorType, typename Scalar>
+DenseIndex fdjac1(
+ const FunctorType &Functor,
+ Matrix< Scalar, Dynamic, 1 > &x,
+ Matrix< Scalar, Dynamic, 1 > &fvec,
+ Matrix< Scalar, Dynamic, Dynamic > &fjac,
+ DenseIndex ml, DenseIndex mu,
+ Scalar epsfcn)
+{
+ typedef DenseIndex Index;
+
+ /* Local variables */
+ Scalar h;
+ Index j, k;
+ Scalar eps, temp;
+ Index msum;
+ int iflag;
+ Index start, length;
+
+ /* Function Body */
+ const Scalar epsmch = NumTraits<Scalar>::epsilon();
+ const Index n = x.size();
+ assert(fvec.size()==n);
+ Matrix< Scalar, Dynamic, 1 > wa1(n);
+ Matrix< Scalar, Dynamic, 1 > wa2(n);
+
+ eps = sqrt((std::max)(epsfcn,epsmch));
+ msum = ml + mu + 1;
+ if (msum >= n) {
+ /* computation of dense approximate jacobian. */
+ for (j = 0; j < n; ++j) {
+ temp = x[j];
+ h = eps * abs(temp);
+ if (h == 0.)
+ h = eps;
+ x[j] = temp + h;
+ iflag = Functor(x, wa1);
+ if (iflag < 0)
+ return iflag;
+ x[j] = temp;
+ fjac.col(j) = (wa1-fvec)/h;
+ }
+
+ }else {
+ /* computation of banded approximate jacobian. */
+ for (k = 0; k < msum; ++k) {
+ for (j = k; (msum<0) ? (j>n): (j<n); j += msum) {
+ wa2[j] = x[j];
+ h = eps * abs(wa2[j]);
+ if (h == 0.) h = eps;
+ x[j] = wa2[j] + h;
+ }
+ iflag = Functor(x, wa1);
+ if (iflag < 0)
+ return iflag;
+ for (j = k; (msum<0) ? (j>n): (j<n); j += msum) {
+ x[j] = wa2[j];
+ h = eps * abs(wa2[j]);
+ if (h == 0.) h = eps;
+ fjac.col(j).setZero();
+ start = std::max<Index>(0,j-mu);
+ length = (std::min)(n-1, j+ml) - start + 1;
+ fjac.col(j).segment(start, length) = ( wa1.segment(start, length)-fvec.segment(start, length))/h;
+ }
+ }
+ }
+ return 0;
+}
+
+} // end namespace internal
+
+} // end namespace Eigen
diff --git a/unsupported/Eigen/src/NonLinearOptimization/lmpar.h b/unsupported/Eigen/src/NonLinearOptimization/lmpar.h
new file mode 100644
index 000000000..cc1ca530f
--- /dev/null
+++ b/unsupported/Eigen/src/NonLinearOptimization/lmpar.h
@@ -0,0 +1,294 @@
+namespace Eigen {
+
+namespace internal {
+
+template <typename Scalar>
+void lmpar(
+ Matrix< Scalar, Dynamic, Dynamic > &r,
+ const VectorXi &ipvt,
+ const Matrix< Scalar, Dynamic, 1 > &diag,
+ const Matrix< Scalar, Dynamic, 1 > &qtb,
+ Scalar delta,
+ Scalar &par,
+ Matrix< Scalar, Dynamic, 1 > &x)
+{
+ typedef DenseIndex Index;
+
+ /* Local variables */
+ Index i, j, l;
+ Scalar fp;
+ Scalar parc, parl;
+ Index iter;
+ Scalar temp, paru;
+ Scalar gnorm;
+ Scalar dxnorm;
+
+
+ /* Function Body */
+ const Scalar dwarf = std::numeric_limits<Scalar>::min();
+ const Index n = r.cols();
+ assert(n==diag.size());
+ assert(n==qtb.size());
+ assert(n==x.size());
+
+ Matrix< Scalar, Dynamic, 1 > wa1, wa2;
+
+ /* compute and store in x the gauss-newton direction. if the */
+ /* jacobian is rank-deficient, obtain a least squares solution. */
+ Index nsing = n-1;
+ wa1 = qtb;
+ for (j = 0; j < n; ++j) {
+ if (r(j,j) == 0. && nsing == n-1)
+ nsing = j - 1;
+ if (nsing < n-1)
+ wa1[j] = 0.;
+ }
+ for (j = nsing; j>=0; --j) {
+ wa1[j] /= r(j,j);
+ temp = wa1[j];
+ for (i = 0; i < j ; ++i)
+ wa1[i] -= r(i,j) * temp;
+ }
+
+ for (j = 0; j < n; ++j)
+ x[ipvt[j]] = wa1[j];
+
+ /* initialize the iteration counter. */
+ /* evaluate the function at the origin, and test */
+ /* for acceptance of the gauss-newton direction. */
+ iter = 0;
+ wa2 = diag.cwiseProduct(x);
+ dxnorm = wa2.blueNorm();
+ fp = dxnorm - delta;
+ if (fp <= Scalar(0.1) * delta) {
+ par = 0;
+ return;
+ }
+
+ /* if the jacobian is not rank deficient, the newton */
+ /* step provides a lower bound, parl, for the zero of */
+ /* the function. otherwise set this bound to zero. */
+ parl = 0.;
+ if (nsing >= n-1) {
+ for (j = 0; j < n; ++j) {
+ l = ipvt[j];
+ wa1[j] = diag[l] * (wa2[l] / dxnorm);
+ }
+ // it's actually a triangularView.solveInplace(), though in a weird
+ // way:
+ for (j = 0; j < n; ++j) {
+ Scalar sum = 0.;
+ for (i = 0; i < j; ++i)
+ sum += r(i,j) * wa1[i];
+ wa1[j] = (wa1[j] - sum) / r(j,j);
+ }
+ temp = wa1.blueNorm();
+ parl = fp / delta / temp / temp;
+ }
+
+ /* calculate an upper bound, paru, for the zero of the function. */
+ for (j = 0; j < n; ++j)
+ wa1[j] = r.col(j).head(j+1).dot(qtb.head(j+1)) / diag[ipvt[j]];
+
+ gnorm = wa1.stableNorm();
+ paru = gnorm / delta;
+ if (paru == 0.)
+ paru = dwarf / (std::min)(delta,Scalar(0.1));
+
+ /* if the input par lies outside of the interval (parl,paru), */
+ /* set par to the closer endpoint. */
+ par = (std::max)(par,parl);
+ par = (std::min)(par,paru);
+ if (par == 0.)
+ par = gnorm / dxnorm;
+
+ /* beginning of an iteration. */
+ while (true) {
+ ++iter;
+
+ /* evaluate the function at the current value of par. */
+ if (par == 0.)
+ par = (std::max)(dwarf,Scalar(.001) * paru); /* Computing MAX */
+ wa1 = sqrt(par)* diag;
+
+ Matrix< Scalar, Dynamic, 1 > sdiag(n);
+ qrsolv<Scalar>(r, ipvt, wa1, qtb, x, sdiag);
+
+ wa2 = diag.cwiseProduct(x);
+ dxnorm = wa2.blueNorm();
+ temp = fp;
+ fp = dxnorm - delta;
+
+ /* if the function is small enough, accept the current value */
+ /* of par. also test for the exceptional cases where parl */
+ /* is zero or the number of iterations has reached 10. */
+ if (abs(fp) <= Scalar(0.1) * delta || (parl == 0. && fp <= temp && temp < 0.) || iter == 10)
+ break;
+
+ /* compute the newton correction. */
+ for (j = 0; j < n; ++j) {
+ l = ipvt[j];
+ wa1[j] = diag[l] * (wa2[l] / dxnorm);
+ }
+ for (j = 0; j < n; ++j) {
+ wa1[j] /= sdiag[j];
+ temp = wa1[j];
+ for (i = j+1; i < n; ++i)
+ wa1[i] -= r(i,j) * temp;
+ }
+ temp = wa1.blueNorm();
+ parc = fp / delta / temp / temp;
+
+ /* depending on the sign of the function, update parl or paru. */
+ if (fp > 0.)
+ parl = (std::max)(parl,par);
+ if (fp < 0.)
+ paru = (std::min)(paru,par);
+
+ /* compute an improved estimate for par. */
+ /* Computing MAX */
+ par = (std::max)(parl,par+parc);
+
+ /* end of an iteration. */
+ }
+
+ /* termination. */
+ if (iter == 0)
+ par = 0.;
+ return;
+}
+
+template <typename Scalar>
+void lmpar2(
+ const ColPivHouseholderQR<Matrix< Scalar, Dynamic, Dynamic> > &qr,
+ const Matrix< Scalar, Dynamic, 1 > &diag,
+ const Matrix< Scalar, Dynamic, 1 > &qtb,
+ Scalar delta,
+ Scalar &par,
+ Matrix< Scalar, Dynamic, 1 > &x)
+
+{
+ typedef DenseIndex Index;
+
+ /* Local variables */
+ Index j;
+ Scalar fp;
+ Scalar parc, parl;
+ Index iter;
+ Scalar temp, paru;
+ Scalar gnorm;
+ Scalar dxnorm;
+
+
+ /* Function Body */
+ const Scalar dwarf = std::numeric_limits<Scalar>::min();
+ const Index n = qr.matrixQR().cols();
+ assert(n==diag.size());
+ assert(n==qtb.size());
+
+ Matrix< Scalar, Dynamic, 1 > wa1, wa2;
+
+ /* compute and store in x the gauss-newton direction. if the */
+ /* jacobian is rank-deficient, obtain a least squares solution. */
+
+// const Index rank = qr.nonzeroPivots(); // exactly double(0.)
+ const Index rank = qr.rank(); // use a threshold
+ wa1 = qtb;
+ wa1.tail(n-rank).setZero();
+ qr.matrixQR().topLeftCorner(rank, rank).template triangularView<Upper>().solveInPlace(wa1.head(rank));
+
+ x = qr.colsPermutation()*wa1;
+
+ /* initialize the iteration counter. */
+ /* evaluate the function at the origin, and test */
+ /* for acceptance of the gauss-newton direction. */
+ iter = 0;
+ wa2 = diag.cwiseProduct(x);
+ dxnorm = wa2.blueNorm();
+ fp = dxnorm - delta;
+ if (fp <= Scalar(0.1) * delta) {
+ par = 0;
+ return;
+ }
+
+ /* if the jacobian is not rank deficient, the newton */
+ /* step provides a lower bound, parl, for the zero of */
+ /* the function. otherwise set this bound to zero. */
+ parl = 0.;
+ if (rank==n) {
+ wa1 = qr.colsPermutation().inverse() * diag.cwiseProduct(wa2)/dxnorm;
+ qr.matrixQR().topLeftCorner(n, n).transpose().template triangularView<Lower>().solveInPlace(wa1);
+ temp = wa1.blueNorm();
+ parl = fp / delta / temp / temp;
+ }
+
+ /* calculate an upper bound, paru, for the zero of the function. */
+ for (j = 0; j < n; ++j)
+ wa1[j] = qr.matrixQR().col(j).head(j+1).dot(qtb.head(j+1)) / diag[qr.colsPermutation().indices()(j)];
+
+ gnorm = wa1.stableNorm();
+ paru = gnorm / delta;
+ if (paru == 0.)
+ paru = dwarf / (std::min)(delta,Scalar(0.1));
+
+ /* if the input par lies outside of the interval (parl,paru), */
+ /* set par to the closer endpoint. */
+ par = (std::max)(par,parl);
+ par = (std::min)(par,paru);
+ if (par == 0.)
+ par = gnorm / dxnorm;
+
+ /* beginning of an iteration. */
+ Matrix< Scalar, Dynamic, Dynamic > s = qr.matrixQR();
+ while (true) {
+ ++iter;
+
+ /* evaluate the function at the current value of par. */
+ if (par == 0.)
+ par = (std::max)(dwarf,Scalar(.001) * paru); /* Computing MAX */
+ wa1 = sqrt(par)* diag;
+
+ Matrix< Scalar, Dynamic, 1 > sdiag(n);
+ qrsolv<Scalar>(s, qr.colsPermutation().indices(), wa1, qtb, x, sdiag);
+
+ wa2 = diag.cwiseProduct(x);
+ dxnorm = wa2.blueNorm();
+ temp = fp;
+ fp = dxnorm - delta;
+
+ /* if the function is small enough, accept the current value */
+ /* of par. also test for the exceptional cases where parl */
+ /* is zero or the number of iterations has reached 10. */
+ if (abs(fp) <= Scalar(0.1) * delta || (parl == 0. && fp <= temp && temp < 0.) || iter == 10)
+ break;
+
+ /* compute the newton correction. */
+ wa1 = qr.colsPermutation().inverse() * diag.cwiseProduct(wa2/dxnorm);
+ // we could almost use this here, but the diagonal is outside qr, in sdiag[]
+ // qr.matrixQR().topLeftCorner(n, n).transpose().template triangularView<Lower>().solveInPlace(wa1);
+ for (j = 0; j < n; ++j) {
+ wa1[j] /= sdiag[j];
+ temp = wa1[j];
+ for (Index i = j+1; i < n; ++i)
+ wa1[i] -= s(i,j) * temp;
+ }
+ temp = wa1.blueNorm();
+ parc = fp / delta / temp / temp;
+
+ /* depending on the sign of the function, update parl or paru. */
+ if (fp > 0.)
+ parl = (std::max)(parl,par);
+ if (fp < 0.)
+ paru = (std::min)(paru,par);
+
+ /* compute an improved estimate for par. */
+ par = (std::max)(parl,par+parc);
+ }
+ if (iter == 0)
+ par = 0.;
+ return;
+}
+
+} // end namespace internal
+
+} // end namespace Eigen
diff --git a/unsupported/Eigen/src/NonLinearOptimization/qrsolv.h b/unsupported/Eigen/src/NonLinearOptimization/qrsolv.h
new file mode 100644
index 000000000..feafd62a8
--- /dev/null
+++ b/unsupported/Eigen/src/NonLinearOptimization/qrsolv.h
@@ -0,0 +1,91 @@
+namespace Eigen {
+
+namespace internal {
+
+// TODO : once qrsolv2 is removed, use ColPivHouseholderQR or PermutationMatrix instead of ipvt
+template <typename Scalar>
+void qrsolv(
+ Matrix< Scalar, Dynamic, Dynamic > &s,
+ // TODO : use a PermutationMatrix once lmpar is no more:
+ const VectorXi &ipvt,
+ const Matrix< Scalar, Dynamic, 1 > &diag,
+ const Matrix< Scalar, Dynamic, 1 > &qtb,
+ Matrix< Scalar, Dynamic, 1 > &x,
+ Matrix< Scalar, Dynamic, 1 > &sdiag)
+
+{
+ typedef DenseIndex Index;
+
+ /* Local variables */
+ Index i, j, k, l;
+ Scalar temp;
+ Index n = s.cols();
+ Matrix< Scalar, Dynamic, 1 > wa(n);
+ JacobiRotation<Scalar> givens;
+
+ /* Function Body */
+ // the following will only change the lower triangular part of s, including
+ // the diagonal, though the diagonal is restored afterward
+
+ /* copy r and (q transpose)*b to preserve input and initialize s. */
+ /* in particular, save the diagonal elements of r in x. */
+ x = s.diagonal();
+ wa = qtb;
+
+ s.topLeftCorner(n,n).template triangularView<StrictlyLower>() = s.topLeftCorner(n,n).transpose();
+
+ /* eliminate the diagonal matrix d using a givens rotation. */
+ for (j = 0; j < n; ++j) {
+
+ /* prepare the row of d to be eliminated, locating the */
+ /* diagonal element using p from the qr factorization. */
+ l = ipvt[j];
+ if (diag[l] == 0.)
+ break;
+ sdiag.tail(n-j).setZero();
+ sdiag[j] = diag[l];
+
+ /* the transformations to eliminate the row of d */
+ /* modify only a single element of (q transpose)*b */
+ /* beyond the first n, which is initially zero. */
+ Scalar qtbpj = 0.;
+ for (k = j; k < n; ++k) {
+ /* determine a givens rotation which eliminates the */
+ /* appropriate element in the current row of d. */
+ givens.makeGivens(-s(k,k), sdiag[k]);
+
+ /* compute the modified diagonal element of r and */
+ /* the modified element of ((q transpose)*b,0). */
+ s(k,k) = givens.c() * s(k,k) + givens.s() * sdiag[k];
+ temp = givens.c() * wa[k] + givens.s() * qtbpj;
+ qtbpj = -givens.s() * wa[k] + givens.c() * qtbpj;
+ wa[k] = temp;
+
+ /* accumulate the tranformation in the row of s. */
+ for (i = k+1; i<n; ++i) {
+ temp = givens.c() * s(i,k) + givens.s() * sdiag[i];
+ sdiag[i] = -givens.s() * s(i,k) + givens.c() * sdiag[i];
+ s(i,k) = temp;
+ }
+ }
+ }
+
+ /* solve the triangular system for z. if the system is */
+ /* singular, then obtain a least squares solution. */
+ Index nsing;
+ for(nsing=0; nsing<n && sdiag[nsing]!=0; nsing++) {}
+
+ wa.tail(n-nsing).setZero();
+ s.topLeftCorner(nsing, nsing).transpose().template triangularView<Upper>().solveInPlace(wa.head(nsing));
+
+ // restore
+ sdiag = s.diagonal();
+ s.diagonal() = x;
+
+ /* permute the components of z back to components of x. */
+ for (j = 0; j < n; ++j) x[ipvt[j]] = wa[j];
+}
+
+} // end namespace internal
+
+} // end namespace Eigen
diff --git a/unsupported/Eigen/src/NonLinearOptimization/r1mpyq.h b/unsupported/Eigen/src/NonLinearOptimization/r1mpyq.h
new file mode 100644
index 000000000..36ff700e9
--- /dev/null
+++ b/unsupported/Eigen/src/NonLinearOptimization/r1mpyq.h
@@ -0,0 +1,30 @@
+namespace Eigen {
+
+namespace internal {
+
+// TODO : move this to GivensQR once there's such a thing in Eigen
+
+template <typename Scalar>
+void r1mpyq(DenseIndex m, DenseIndex n, Scalar *a, const std::vector<JacobiRotation<Scalar> > &v_givens, const std::vector<JacobiRotation<Scalar> > &w_givens)
+{
+ typedef DenseIndex Index;
+
+ /* apply the first set of givens rotations to a. */
+ for (Index j = n-2; j>=0; --j)
+ for (Index i = 0; i<m; ++i) {
+ Scalar temp = v_givens[j].c() * a[i+m*j] - v_givens[j].s() * a[i+m*(n-1)];
+ a[i+m*(n-1)] = v_givens[j].s() * a[i+m*j] + v_givens[j].c() * a[i+m*(n-1)];
+ a[i+m*j] = temp;
+ }
+ /* apply the second set of givens rotations to a. */
+ for (Index j = 0; j<n-1; ++j)
+ for (Index i = 0; i<m; ++i) {
+ Scalar temp = w_givens[j].c() * a[i+m*j] + w_givens[j].s() * a[i+m*(n-1)];
+ a[i+m*(n-1)] = -w_givens[j].s() * a[i+m*j] + w_givens[j].c() * a[i+m*(n-1)];
+ a[i+m*j] = temp;
+ }
+}
+
+} // end namespace internal
+
+} // end namespace Eigen
diff --git a/unsupported/Eigen/src/NonLinearOptimization/r1updt.h b/unsupported/Eigen/src/NonLinearOptimization/r1updt.h
new file mode 100644
index 000000000..55fae5ae8
--- /dev/null
+++ b/unsupported/Eigen/src/NonLinearOptimization/r1updt.h
@@ -0,0 +1,99 @@
+namespace Eigen {
+
+namespace internal {
+
+template <typename Scalar>
+void r1updt(
+ Matrix< Scalar, Dynamic, Dynamic > &s,
+ const Matrix< Scalar, Dynamic, 1> &u,
+ std::vector<JacobiRotation<Scalar> > &v_givens,
+ std::vector<JacobiRotation<Scalar> > &w_givens,
+ Matrix< Scalar, Dynamic, 1> &v,
+ Matrix< Scalar, Dynamic, 1> &w,
+ bool *sing)
+{
+ typedef DenseIndex Index;
+ const JacobiRotation<Scalar> IdentityRotation = JacobiRotation<Scalar>(1,0);
+
+ /* Local variables */
+ const Index m = s.rows();
+ const Index n = s.cols();
+ Index i, j=1;
+ Scalar temp;
+ JacobiRotation<Scalar> givens;
+
+ // r1updt had a broader usecase, but we dont use it here. And, more
+ // importantly, we can not test it.
+ assert(m==n);
+ assert(u.size()==m);
+ assert(v.size()==n);
+ assert(w.size()==n);
+
+ /* move the nontrivial part of the last column of s into w. */
+ w[n-1] = s(n-1,n-1);
+
+ /* rotate the vector v into a multiple of the n-th unit vector */
+ /* in such a way that a spike is introduced into w. */
+ for (j=n-2; j>=0; --j) {
+ w[j] = 0.;
+ if (v[j] != 0.) {
+ /* determine a givens rotation which eliminates the */
+ /* j-th element of v. */
+ givens.makeGivens(-v[n-1], v[j]);
+
+ /* apply the transformation to v and store the information */
+ /* necessary to recover the givens rotation. */
+ v[n-1] = givens.s() * v[j] + givens.c() * v[n-1];
+ v_givens[j] = givens;
+
+ /* apply the transformation to s and extend the spike in w. */
+ for (i = j; i < m; ++i) {
+ temp = givens.c() * s(j,i) - givens.s() * w[i];
+ w[i] = givens.s() * s(j,i) + givens.c() * w[i];
+ s(j,i) = temp;
+ }
+ } else
+ v_givens[j] = IdentityRotation;
+ }
+
+ /* add the spike from the rank 1 update to w. */
+ w += v[n-1] * u;
+
+ /* eliminate the spike. */
+ *sing = false;
+ for (j = 0; j < n-1; ++j) {
+ if (w[j] != 0.) {
+ /* determine a givens rotation which eliminates the */
+ /* j-th element of the spike. */
+ givens.makeGivens(-s(j,j), w[j]);
+
+ /* apply the transformation to s and reduce the spike in w. */
+ for (i = j; i < m; ++i) {
+ temp = givens.c() * s(j,i) + givens.s() * w[i];
+ w[i] = -givens.s() * s(j,i) + givens.c() * w[i];
+ s(j,i) = temp;
+ }
+
+ /* store the information necessary to recover the */
+ /* givens rotation. */
+ w_givens[j] = givens;
+ } else
+ v_givens[j] = IdentityRotation;
+
+ /* test for zero diagonal elements in the output s. */
+ if (s(j,j) == 0.) {
+ *sing = true;
+ }
+ }
+ /* move w back into the last column of the output s. */
+ s(n-1,n-1) = w[n-1];
+
+ if (s(j,j) == 0.) {
+ *sing = true;
+ }
+ return;
+}
+
+} // end namespace internal
+
+} // end namespace Eigen
diff --git a/unsupported/Eigen/src/NonLinearOptimization/rwupdt.h b/unsupported/Eigen/src/NonLinearOptimization/rwupdt.h
new file mode 100644
index 000000000..9ce079e22
--- /dev/null
+++ b/unsupported/Eigen/src/NonLinearOptimization/rwupdt.h
@@ -0,0 +1,49 @@
+namespace Eigen {
+
+namespace internal {
+
+template <typename Scalar>
+void rwupdt(
+ Matrix< Scalar, Dynamic, Dynamic > &r,
+ const Matrix< Scalar, Dynamic, 1> &w,
+ Matrix< Scalar, Dynamic, 1> &b,
+ Scalar alpha)
+{
+ typedef DenseIndex Index;
+
+ const Index n = r.cols();
+ assert(r.rows()>=n);
+ std::vector<JacobiRotation<Scalar> > givens(n);
+
+ /* Local variables */
+ Scalar temp, rowj;
+
+ /* Function Body */
+ for (Index j = 0; j < n; ++j) {
+ rowj = w[j];
+
+ /* apply the previous transformations to */
+ /* r(i,j), i=0,1,...,j-1, and to w(j). */
+ for (Index i = 0; i < j; ++i) {
+ temp = givens[i].c() * r(i,j) + givens[i].s() * rowj;
+ rowj = -givens[i].s() * r(i,j) + givens[i].c() * rowj;
+ r(i,j) = temp;
+ }
+
+ /* determine a givens rotation which eliminates w(j). */
+ givens[j].makeGivens(-r(j,j), rowj);
+
+ if (rowj == 0.)
+ continue; // givens[j] is identity
+
+ /* apply the current transformation to r(j,j), b(j), and alpha. */
+ r(j,j) = givens[j].c() * r(j,j) + givens[j].s() * rowj;
+ temp = givens[j].c() * b[j] + givens[j].s() * alpha;
+ alpha = -givens[j].s() * b[j] + givens[j].c() * alpha;
+ b[j] = temp;
+ }
+}
+
+} // end namespace internal
+
+} // end namespace Eigen
diff --git a/unsupported/Eigen/src/NumericalDiff/CMakeLists.txt b/unsupported/Eigen/src/NumericalDiff/CMakeLists.txt
new file mode 100644
index 000000000..1199aca2f
--- /dev/null
+++ b/unsupported/Eigen/src/NumericalDiff/CMakeLists.txt
@@ -0,0 +1,6 @@
+FILE(GLOB Eigen_NumericalDiff_SRCS "*.h")
+
+INSTALL(FILES
+ ${Eigen_NumericalDiff_SRCS}
+ DESTINATION ${INCLUDE_INSTALL_DIR}/unsupported/Eigen/src/NumericalDiff COMPONENT Devel
+ )
diff --git a/unsupported/Eigen/src/NumericalDiff/NumericalDiff.h b/unsupported/Eigen/src/NumericalDiff/NumericalDiff.h
new file mode 100644
index 000000000..d848cb407
--- /dev/null
+++ b/unsupported/Eigen/src/NumericalDiff/NumericalDiff.h
@@ -0,0 +1,128 @@
+// -*- coding: utf-8
+// vim: set fileencoding=utf-8
+
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra.
+//
+// Copyright (C) 2009 Thomas Capricelli <orzel@freehackers.org>
+//
+// This Source Code Form is subject to the terms of the Mozilla
+// Public License v. 2.0. If a copy of the MPL was not distributed
+// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+#ifndef EIGEN_NUMERICAL_DIFF_H
+#define EIGEN_NUMERICAL_DIFF_H
+
+namespace Eigen {
+
+enum NumericalDiffMode {
+ Forward,
+ Central
+};
+
+
+/**
+ * This class allows you to add a method df() to your functor, which will
+ * use numerical differentiation to compute an approximate of the
+ * derivative for the functor. Of course, if you have an analytical form
+ * for the derivative, you should rather implement df() by yourself.
+ *
+ * More information on
+ * http://en.wikipedia.org/wiki/Numerical_differentiation
+ *
+ * Currently only "Forward" and "Central" scheme are implemented.
+ */
+template<typename _Functor, NumericalDiffMode mode=Forward>
+class NumericalDiff : public _Functor
+{
+public:
+ typedef _Functor Functor;
+ typedef typename Functor::Scalar Scalar;
+ typedef typename Functor::InputType InputType;
+ typedef typename Functor::ValueType ValueType;
+ typedef typename Functor::JacobianType JacobianType;
+
+ NumericalDiff(Scalar _epsfcn=0.) : Functor(), epsfcn(_epsfcn) {}
+ NumericalDiff(const Functor& f, Scalar _epsfcn=0.) : Functor(f), epsfcn(_epsfcn) {}
+
+ // forward constructors
+ template<typename T0>
+ NumericalDiff(const T0& a0) : Functor(a0), epsfcn(0) {}
+ template<typename T0, typename T1>
+ NumericalDiff(const T0& a0, const T1& a1) : Functor(a0, a1), epsfcn(0) {}
+ template<typename T0, typename T1, typename T2>
+ NumericalDiff(const T0& a0, const T1& a1, const T2& a2) : Functor(a0, a1, a2), epsfcn(0) {}
+
+ enum {
+ InputsAtCompileTime = Functor::InputsAtCompileTime,
+ ValuesAtCompileTime = Functor::ValuesAtCompileTime
+ };
+
+ /**
+ * return the number of evaluation of functor
+ */
+ int df(const InputType& _x, JacobianType &jac) const
+ {
+ /* Local variables */
+ Scalar h;
+ int nfev=0;
+ const typename InputType::Index n = _x.size();
+ const Scalar eps = internal::sqrt(((std::max)(epsfcn,NumTraits<Scalar>::epsilon() )));
+ ValueType val1, val2;
+ InputType x = _x;
+ // TODO : we should do this only if the size is not already known
+ val1.resize(Functor::values());
+ val2.resize(Functor::values());
+
+ // initialization
+ switch(mode) {
+ case Forward:
+ // compute f(x)
+ Functor::operator()(x, val1); nfev++;
+ break;
+ case Central:
+ // do nothing
+ break;
+ default:
+ assert(false);
+ };
+
+ // Function Body
+ for (int j = 0; j < n; ++j) {
+ h = eps * internal::abs(x[j]);
+ if (h == 0.) {
+ h = eps;
+ }
+ switch(mode) {
+ case Forward:
+ x[j] += h;
+ Functor::operator()(x, val2);
+ nfev++;
+ x[j] = _x[j];
+ jac.col(j) = (val2-val1)/h;
+ break;
+ case Central:
+ x[j] += h;
+ Functor::operator()(x, val2); nfev++;
+ x[j] -= 2*h;
+ Functor::operator()(x, val1); nfev++;
+ x[j] = _x[j];
+ jac.col(j) = (val2-val1)/(2*h);
+ break;
+ default:
+ assert(false);
+ };
+ }
+ return nfev;
+ }
+private:
+ Scalar epsfcn;
+
+ NumericalDiff& operator=(const NumericalDiff&);
+};
+
+} // end namespace Eigen
+
+//vim: ai ts=4 sts=4 et sw=4
+#endif // EIGEN_NUMERICAL_DIFF_H
+
diff --git a/unsupported/Eigen/src/Polynomials/CMakeLists.txt b/unsupported/Eigen/src/Polynomials/CMakeLists.txt
new file mode 100644
index 000000000..51f13f3cb
--- /dev/null
+++ b/unsupported/Eigen/src/Polynomials/CMakeLists.txt
@@ -0,0 +1,6 @@
+FILE(GLOB Eigen_Polynomials_SRCS "*.h")
+
+INSTALL(FILES
+ ${Eigen_Polynomials_SRCS}
+ DESTINATION ${INCLUDE_INSTALL_DIR}/unsupported/Eigen/src/Polynomials COMPONENT Devel
+ )
diff --git a/unsupported/Eigen/src/Polynomials/Companion.h b/unsupported/Eigen/src/Polynomials/Companion.h
new file mode 100644
index 000000000..4badd9d58
--- /dev/null
+++ b/unsupported/Eigen/src/Polynomials/Companion.h
@@ -0,0 +1,275 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra.
+//
+// Copyright (C) 2010 Manuel Yguel <manuel.yguel@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 EIGEN_COMPANION_H
+#define EIGEN_COMPANION_H
+
+// This file requires the user to include
+// * Eigen/Core
+// * Eigen/src/PolynomialSolver.h
+
+namespace Eigen {
+
+namespace internal {
+
+#ifndef EIGEN_PARSED_BY_DOXYGEN
+
+template <typename T>
+T radix(){ return 2; }
+
+template <typename T>
+T radix2(){ return radix<T>()*radix<T>(); }
+
+template<int Size>
+struct decrement_if_fixed_size
+{
+ enum {
+ ret = (Size == Dynamic) ? Dynamic : Size-1 };
+};
+
+#endif
+
+template< typename _Scalar, int _Deg >
+class companion
+{
+ public:
+ EIGEN_MAKE_ALIGNED_OPERATOR_NEW_IF_VECTORIZABLE_FIXED_SIZE(_Scalar,_Deg==Dynamic ? Dynamic : _Deg)
+
+ enum {
+ Deg = _Deg,
+ Deg_1=decrement_if_fixed_size<Deg>::ret
+ };
+
+ typedef _Scalar Scalar;
+ typedef typename NumTraits<Scalar>::Real RealScalar;
+ typedef Matrix<Scalar, Deg, 1> RightColumn;
+ //typedef DiagonalMatrix< Scalar, Deg_1, Deg_1 > BottomLeftDiagonal;
+ typedef Matrix<Scalar, Deg_1, 1> BottomLeftDiagonal;
+
+ typedef Matrix<Scalar, Deg, Deg> DenseCompanionMatrixType;
+ typedef Matrix< Scalar, _Deg, Deg_1 > LeftBlock;
+ typedef Matrix< Scalar, Deg_1, Deg_1 > BottomLeftBlock;
+ typedef Matrix< Scalar, 1, Deg_1 > LeftBlockFirstRow;
+
+ typedef DenseIndex Index;
+
+ public:
+ EIGEN_STRONG_INLINE const _Scalar operator()(Index row, Index col ) const
+ {
+ if( m_bl_diag.rows() > col )
+ {
+ if( 0 < row ){ return m_bl_diag[col]; }
+ else{ return 0; }
+ }
+ else{ return m_monic[row]; }
+ }
+
+ public:
+ template<typename VectorType>
+ void setPolynomial( const VectorType& poly )
+ {
+ const Index deg = poly.size()-1;
+ m_monic = -1/poly[deg] * poly.head(deg);
+ //m_bl_diag.setIdentity( deg-1 );
+ m_bl_diag.setOnes(deg-1);
+ }
+
+ template<typename VectorType>
+ companion( const VectorType& poly ){
+ setPolynomial( poly ); }
+
+ public:
+ DenseCompanionMatrixType denseMatrix() const
+ {
+ const Index deg = m_monic.size();
+ const Index deg_1 = deg-1;
+ DenseCompanionMatrixType companion(deg,deg);
+ companion <<
+ ( LeftBlock(deg,deg_1)
+ << LeftBlockFirstRow::Zero(1,deg_1),
+ BottomLeftBlock::Identity(deg-1,deg-1)*m_bl_diag.asDiagonal() ).finished()
+ , m_monic;
+ return companion;
+ }
+
+
+
+ protected:
+ /** Helper function for the balancing algorithm.
+ * \returns true if the row and the column, having colNorm and rowNorm
+ * as norms, are balanced, false otherwise.
+ * colB and rowB are repectively the multipliers for
+ * the column and the row in order to balance them.
+ * */
+ bool balanced( Scalar colNorm, Scalar rowNorm,
+ bool& isBalanced, Scalar& colB, Scalar& rowB );
+
+ /** Helper function for the balancing algorithm.
+ * \returns true if the row and the column, having colNorm and rowNorm
+ * as norms, are balanced, false otherwise.
+ * colB and rowB are repectively the multipliers for
+ * the column and the row in order to balance them.
+ * */
+ bool balancedR( Scalar colNorm, Scalar rowNorm,
+ bool& isBalanced, Scalar& colB, Scalar& rowB );
+
+ public:
+ /**
+ * Balancing algorithm from B. N. PARLETT and C. REINSCH (1969)
+ * "Balancing a matrix for calculation of eigenvalues and eigenvectors"
+ * adapted to the case of companion matrices.
+ * A matrix with non zero row and non zero column is balanced
+ * for a certain norm if the i-th row and the i-th column
+ * have same norm for all i.
+ */
+ void balance();
+
+ protected:
+ RightColumn m_monic;
+ BottomLeftDiagonal m_bl_diag;
+};
+
+
+
+template< typename _Scalar, int _Deg >
+inline
+bool companion<_Scalar,_Deg>::balanced( Scalar colNorm, Scalar rowNorm,
+ bool& isBalanced, Scalar& colB, Scalar& rowB )
+{
+ if( Scalar(0) == colNorm || Scalar(0) == rowNorm ){ return true; }
+ else
+ {
+ //To find the balancing coefficients, if the radix is 2,
+ //one finds \f$ \sigma \f$ such that
+ // \f$ 2^{2\sigma-1} < rowNorm / colNorm \le 2^{2\sigma+1} \f$
+ // then the balancing coefficient for the row is \f$ 1/2^{\sigma} \f$
+ // and the balancing coefficient for the column is \f$ 2^{\sigma} \f$
+ rowB = rowNorm / radix<Scalar>();
+ colB = Scalar(1);
+ const Scalar s = colNorm + rowNorm;
+
+ while (colNorm < rowB)
+ {
+ colB *= radix<Scalar>();
+ colNorm *= radix2<Scalar>();
+ }
+
+ rowB = rowNorm * radix<Scalar>();
+
+ while (colNorm >= rowB)
+ {
+ colB /= radix<Scalar>();
+ colNorm /= radix2<Scalar>();
+ }
+
+ //This line is used to avoid insubstantial balancing
+ if ((rowNorm + colNorm) < Scalar(0.95) * s * colB)
+ {
+ isBalanced = false;
+ rowB = Scalar(1) / colB;
+ return false;
+ }
+ else{
+ return true; }
+ }
+}
+
+template< typename _Scalar, int _Deg >
+inline
+bool companion<_Scalar,_Deg>::balancedR( Scalar colNorm, Scalar rowNorm,
+ bool& isBalanced, Scalar& colB, Scalar& rowB )
+{
+ if( Scalar(0) == colNorm || Scalar(0) == rowNorm ){ return true; }
+ else
+ {
+ /**
+ * Set the norm of the column and the row to the geometric mean
+ * of the row and column norm
+ */
+ const _Scalar q = colNorm/rowNorm;
+ if( !isApprox( q, _Scalar(1) ) )
+ {
+ rowB = sqrt( colNorm/rowNorm );
+ colB = Scalar(1)/rowB;
+
+ isBalanced = false;
+ return false;
+ }
+ else{
+ return true; }
+ }
+}
+
+
+template< typename _Scalar, int _Deg >
+void companion<_Scalar,_Deg>::balance()
+{
+ EIGEN_STATIC_ASSERT( Deg == Dynamic || 1 < Deg, YOU_MADE_A_PROGRAMMING_MISTAKE );
+ const Index deg = m_monic.size();
+ const Index deg_1 = deg-1;
+
+ bool hasConverged=false;
+ while( !hasConverged )
+ {
+ hasConverged = true;
+ Scalar colNorm,rowNorm;
+ Scalar colB,rowB;
+
+ //First row, first column excluding the diagonal
+ //==============================================
+ colNorm = abs(m_bl_diag[0]);
+ rowNorm = abs(m_monic[0]);
+
+ //Compute balancing of the row and the column
+ if( !balanced( colNorm, rowNorm, hasConverged, colB, rowB ) )
+ {
+ m_bl_diag[0] *= colB;
+ m_monic[0] *= rowB;
+ }
+
+ //Middle rows and columns excluding the diagonal
+ //==============================================
+ for( Index i=1; i<deg_1; ++i )
+ {
+ // column norm, excluding the diagonal
+ colNorm = abs(m_bl_diag[i]);
+
+ // row norm, excluding the diagonal
+ rowNorm = abs(m_bl_diag[i-1]) + abs(m_monic[i]);
+
+ //Compute balancing of the row and the column
+ if( !balanced( colNorm, rowNorm, hasConverged, colB, rowB ) )
+ {
+ m_bl_diag[i] *= colB;
+ m_bl_diag[i-1] *= rowB;
+ m_monic[i] *= rowB;
+ }
+ }
+
+ //Last row, last column excluding the diagonal
+ //============================================
+ const Index ebl = m_bl_diag.size()-1;
+ VectorBlock<RightColumn,Deg_1> headMonic( m_monic, 0, deg_1 );
+ colNorm = headMonic.array().abs().sum();
+ rowNorm = abs( m_bl_diag[ebl] );
+
+ //Compute balancing of the row and the column
+ if( !balanced( colNorm, rowNorm, hasConverged, colB, rowB ) )
+ {
+ headMonic *= colB;
+ m_bl_diag[ebl] *= rowB;
+ }
+ }
+}
+
+} // end namespace internal
+
+} // end namespace Eigen
+
+#endif // EIGEN_COMPANION_H
diff --git a/unsupported/Eigen/src/Polynomials/PolynomialSolver.h b/unsupported/Eigen/src/Polynomials/PolynomialSolver.h
new file mode 100644
index 000000000..70b873dbc
--- /dev/null
+++ b/unsupported/Eigen/src/Polynomials/PolynomialSolver.h
@@ -0,0 +1,386 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra.
+//
+// Copyright (C) 2010 Manuel Yguel <manuel.yguel@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 EIGEN_POLYNOMIAL_SOLVER_H
+#define EIGEN_POLYNOMIAL_SOLVER_H
+
+namespace Eigen {
+
+/** \ingroup Polynomials_Module
+ * \class PolynomialSolverBase.
+ *
+ * \brief Defined to be inherited by polynomial solvers: it provides
+ * convenient methods such as
+ * - real roots,
+ * - greatest, smallest complex roots,
+ * - real roots with greatest, smallest absolute real value,
+ * - greatest, smallest real roots.
+ *
+ * It stores the set of roots as a vector of complexes.
+ *
+ */
+template< typename _Scalar, int _Deg >
+class PolynomialSolverBase
+{
+ public:
+ EIGEN_MAKE_ALIGNED_OPERATOR_NEW_IF_VECTORIZABLE_FIXED_SIZE(_Scalar,_Deg==Dynamic ? Dynamic : _Deg)
+
+ typedef _Scalar Scalar;
+ typedef typename NumTraits<Scalar>::Real RealScalar;
+ typedef std::complex<RealScalar> RootType;
+ typedef Matrix<RootType,_Deg,1> RootsType;
+
+ typedef DenseIndex Index;
+
+ protected:
+ template< typename OtherPolynomial >
+ inline void setPolynomial( const OtherPolynomial& poly ){
+ m_roots.resize(poly.size()); }
+
+ public:
+ template< typename OtherPolynomial >
+ inline PolynomialSolverBase( const OtherPolynomial& poly ){
+ setPolynomial( poly() ); }
+
+ inline PolynomialSolverBase(){}
+
+ public:
+ /** \returns the complex roots of the polynomial */
+ inline const RootsType& roots() const { return m_roots; }
+
+ public:
+ /** Clear and fills the back insertion sequence with the real roots of the polynomial
+ * i.e. the real part of the complex roots that have an imaginary part which
+ * absolute value is smaller than absImaginaryThreshold.
+ * absImaginaryThreshold takes the dummy_precision associated
+ * with the _Scalar template parameter of the PolynomialSolver class as the default value.
+ *
+ * \param[out] bi_seq : the back insertion sequence (stl concept)
+ * \param[in] absImaginaryThreshold : the maximum bound of the imaginary part of a complex
+ * number that is considered as real.
+ * */
+ template<typename Stl_back_insertion_sequence>
+ inline void realRoots( Stl_back_insertion_sequence& bi_seq,
+ const RealScalar& absImaginaryThreshold = NumTraits<Scalar>::dummy_precision() ) const
+ {
+ bi_seq.clear();
+ for(Index i=0; i<m_roots.size(); ++i )
+ {
+ if( internal::abs( m_roots[i].imag() ) < absImaginaryThreshold ){
+ bi_seq.push_back( m_roots[i].real() ); }
+ }
+ }
+
+ protected:
+ template<typename squaredNormBinaryPredicate>
+ inline const RootType& selectComplexRoot_withRespectToNorm( squaredNormBinaryPredicate& pred ) const
+ {
+ Index res=0;
+ RealScalar norm2 = internal::abs2( m_roots[0] );
+ for( Index i=1; i<m_roots.size(); ++i )
+ {
+ const RealScalar currNorm2 = internal::abs2( m_roots[i] );
+ if( pred( currNorm2, norm2 ) ){
+ res=i; norm2=currNorm2; }
+ }
+ return m_roots[res];
+ }
+
+ public:
+ /**
+ * \returns the complex root with greatest norm.
+ */
+ inline const RootType& greatestRoot() const
+ {
+ std::greater<Scalar> greater;
+ return selectComplexRoot_withRespectToNorm( greater );
+ }
+
+ /**
+ * \returns the complex root with smallest norm.
+ */
+ inline const RootType& smallestRoot() const
+ {
+ std::less<Scalar> less;
+ return selectComplexRoot_withRespectToNorm( less );
+ }
+
+ protected:
+ template<typename squaredRealPartBinaryPredicate>
+ inline const RealScalar& selectRealRoot_withRespectToAbsRealPart(
+ squaredRealPartBinaryPredicate& pred,
+ bool& hasArealRoot,
+ const RealScalar& absImaginaryThreshold = NumTraits<Scalar>::dummy_precision() ) const
+ {
+ hasArealRoot = false;
+ Index res=0;
+ RealScalar abs2(0);
+
+ for( Index i=0; i<m_roots.size(); ++i )
+ {
+ if( internal::abs( m_roots[i].imag() ) < absImaginaryThreshold )
+ {
+ if( !hasArealRoot )
+ {
+ hasArealRoot = true;
+ res = i;
+ abs2 = m_roots[i].real() * m_roots[i].real();
+ }
+ else
+ {
+ const RealScalar currAbs2 = m_roots[i].real() * m_roots[i].real();
+ if( pred( currAbs2, abs2 ) )
+ {
+ abs2 = currAbs2;
+ res = i;
+ }
+ }
+ }
+ else
+ {
+ if( internal::abs( m_roots[i].imag() ) < internal::abs( m_roots[res].imag() ) ){
+ res = i; }
+ }
+ }
+ return internal::real_ref(m_roots[res]);
+ }
+
+
+ template<typename RealPartBinaryPredicate>
+ inline const RealScalar& selectRealRoot_withRespectToRealPart(
+ RealPartBinaryPredicate& pred,
+ bool& hasArealRoot,
+ const RealScalar& absImaginaryThreshold = NumTraits<Scalar>::dummy_precision() ) const
+ {
+ hasArealRoot = false;
+ Index res=0;
+ RealScalar val(0);
+
+ for( Index i=0; i<m_roots.size(); ++i )
+ {
+ if( internal::abs( m_roots[i].imag() ) < absImaginaryThreshold )
+ {
+ if( !hasArealRoot )
+ {
+ hasArealRoot = true;
+ res = i;
+ val = m_roots[i].real();
+ }
+ else
+ {
+ const RealScalar curr = m_roots[i].real();
+ if( pred( curr, val ) )
+ {
+ val = curr;
+ res = i;
+ }
+ }
+ }
+ else
+ {
+ if( internal::abs( m_roots[i].imag() ) < internal::abs( m_roots[res].imag() ) ){
+ res = i; }
+ }
+ }
+ return internal::real_ref(m_roots[res]);
+ }
+
+ public:
+ /**
+ * \returns a real root with greatest absolute magnitude.
+ * A real root is defined as the real part of a complex root with absolute imaginary
+ * part smallest than absImaginaryThreshold.
+ * absImaginaryThreshold takes the dummy_precision associated
+ * with the _Scalar template parameter of the PolynomialSolver class as the default value.
+ * If no real root is found the boolean hasArealRoot is set to false and the real part of
+ * the root with smallest absolute imaginary part is returned instead.
+ *
+ * \param[out] hasArealRoot : boolean true if a real root is found according to the
+ * absImaginaryThreshold criterion, false otherwise.
+ * \param[in] absImaginaryThreshold : threshold on the absolute imaginary part to decide
+ * whether or not a root is real.
+ */
+ inline const RealScalar& absGreatestRealRoot(
+ bool& hasArealRoot,
+ const RealScalar& absImaginaryThreshold = NumTraits<Scalar>::dummy_precision() ) const
+ {
+ std::greater<Scalar> greater;
+ return selectRealRoot_withRespectToAbsRealPart( greater, hasArealRoot, absImaginaryThreshold );
+ }
+
+
+ /**
+ * \returns a real root with smallest absolute magnitude.
+ * A real root is defined as the real part of a complex root with absolute imaginary
+ * part smallest than absImaginaryThreshold.
+ * absImaginaryThreshold takes the dummy_precision associated
+ * with the _Scalar template parameter of the PolynomialSolver class as the default value.
+ * If no real root is found the boolean hasArealRoot is set to false and the real part of
+ * the root with smallest absolute imaginary part is returned instead.
+ *
+ * \param[out] hasArealRoot : boolean true if a real root is found according to the
+ * absImaginaryThreshold criterion, false otherwise.
+ * \param[in] absImaginaryThreshold : threshold on the absolute imaginary part to decide
+ * whether or not a root is real.
+ */
+ inline const RealScalar& absSmallestRealRoot(
+ bool& hasArealRoot,
+ const RealScalar& absImaginaryThreshold = NumTraits<Scalar>::dummy_precision() ) const
+ {
+ std::less<Scalar> less;
+ return selectRealRoot_withRespectToAbsRealPart( less, hasArealRoot, absImaginaryThreshold );
+ }
+
+
+ /**
+ * \returns the real root with greatest value.
+ * A real root is defined as the real part of a complex root with absolute imaginary
+ * part smallest than absImaginaryThreshold.
+ * absImaginaryThreshold takes the dummy_precision associated
+ * with the _Scalar template parameter of the PolynomialSolver class as the default value.
+ * If no real root is found the boolean hasArealRoot is set to false and the real part of
+ * the root with smallest absolute imaginary part is returned instead.
+ *
+ * \param[out] hasArealRoot : boolean true if a real root is found according to the
+ * absImaginaryThreshold criterion, false otherwise.
+ * \param[in] absImaginaryThreshold : threshold on the absolute imaginary part to decide
+ * whether or not a root is real.
+ */
+ inline const RealScalar& greatestRealRoot(
+ bool& hasArealRoot,
+ const RealScalar& absImaginaryThreshold = NumTraits<Scalar>::dummy_precision() ) const
+ {
+ std::greater<Scalar> greater;
+ return selectRealRoot_withRespectToRealPart( greater, hasArealRoot, absImaginaryThreshold );
+ }
+
+
+ /**
+ * \returns the real root with smallest value.
+ * A real root is defined as the real part of a complex root with absolute imaginary
+ * part smallest than absImaginaryThreshold.
+ * absImaginaryThreshold takes the dummy_precision associated
+ * with the _Scalar template parameter of the PolynomialSolver class as the default value.
+ * If no real root is found the boolean hasArealRoot is set to false and the real part of
+ * the root with smallest absolute imaginary part is returned instead.
+ *
+ * \param[out] hasArealRoot : boolean true if a real root is found according to the
+ * absImaginaryThreshold criterion, false otherwise.
+ * \param[in] absImaginaryThreshold : threshold on the absolute imaginary part to decide
+ * whether or not a root is real.
+ */
+ inline const RealScalar& smallestRealRoot(
+ bool& hasArealRoot,
+ const RealScalar& absImaginaryThreshold = NumTraits<Scalar>::dummy_precision() ) const
+ {
+ std::less<Scalar> less;
+ return selectRealRoot_withRespectToRealPart( less, hasArealRoot, absImaginaryThreshold );
+ }
+
+ protected:
+ RootsType m_roots;
+};
+
+#define EIGEN_POLYNOMIAL_SOLVER_BASE_INHERITED_TYPES( BASE ) \
+ typedef typename BASE::Scalar Scalar; \
+ typedef typename BASE::RealScalar RealScalar; \
+ typedef typename BASE::RootType RootType; \
+ typedef typename BASE::RootsType RootsType;
+
+
+
+/** \ingroup Polynomials_Module
+ *
+ * \class PolynomialSolver
+ *
+ * \brief A polynomial solver
+ *
+ * Computes the complex roots of a real polynomial.
+ *
+ * \param _Scalar the scalar type, i.e., the type of the polynomial coefficients
+ * \param _Deg the degree of the polynomial, can be a compile time value or Dynamic.
+ * Notice that the number of polynomial coefficients is _Deg+1.
+ *
+ * This class implements a polynomial solver and provides convenient methods such as
+ * - real roots,
+ * - greatest, smallest complex roots,
+ * - real roots with greatest, smallest absolute real value.
+ * - greatest, smallest real roots.
+ *
+ * WARNING: this polynomial solver is experimental, part of the unsuported Eigen modules.
+ *
+ *
+ * Currently a QR algorithm is used to compute the eigenvalues of the companion matrix of
+ * the polynomial to compute its roots.
+ * This supposes that the complex moduli of the roots are all distinct: e.g. there should
+ * be no multiple roots or conjugate roots for instance.
+ * With 32bit (float) floating types this problem shows up frequently.
+ * However, almost always, correct accuracy is reached even in these cases for 64bit
+ * (double) floating types and small polynomial degree (<20).
+ */
+template< typename _Scalar, int _Deg >
+class PolynomialSolver : public PolynomialSolverBase<_Scalar,_Deg>
+{
+ public:
+ EIGEN_MAKE_ALIGNED_OPERATOR_NEW_IF_VECTORIZABLE_FIXED_SIZE(_Scalar,_Deg==Dynamic ? Dynamic : _Deg)
+
+ typedef PolynomialSolverBase<_Scalar,_Deg> PS_Base;
+ EIGEN_POLYNOMIAL_SOLVER_BASE_INHERITED_TYPES( PS_Base )
+
+ typedef Matrix<Scalar,_Deg,_Deg> CompanionMatrixType;
+ typedef EigenSolver<CompanionMatrixType> EigenSolverType;
+
+ public:
+ /** Computes the complex roots of a new polynomial. */
+ template< typename OtherPolynomial >
+ void compute( const OtherPolynomial& poly )
+ {
+ assert( Scalar(0) != poly[poly.size()-1] );
+ internal::companion<Scalar,_Deg> companion( poly );
+ companion.balance();
+ m_eigenSolver.compute( companion.denseMatrix() );
+ m_roots = m_eigenSolver.eigenvalues();
+ }
+
+ public:
+ template< typename OtherPolynomial >
+ inline PolynomialSolver( const OtherPolynomial& poly ){
+ compute( poly ); }
+
+ inline PolynomialSolver(){}
+
+ protected:
+ using PS_Base::m_roots;
+ EigenSolverType m_eigenSolver;
+};
+
+
+template< typename _Scalar >
+class PolynomialSolver<_Scalar,1> : public PolynomialSolverBase<_Scalar,1>
+{
+ public:
+ typedef PolynomialSolverBase<_Scalar,1> PS_Base;
+ EIGEN_POLYNOMIAL_SOLVER_BASE_INHERITED_TYPES( PS_Base )
+
+ public:
+ /** Computes the complex roots of a new polynomial. */
+ template< typename OtherPolynomial >
+ void compute( const OtherPolynomial& poly )
+ {
+ assert( Scalar(0) != poly[poly.size()-1] );
+ m_roots[0] = -poly[0]/poly[poly.size()-1];
+ }
+
+ protected:
+ using PS_Base::m_roots;
+};
+
+} // end namespace Eigen
+
+#endif // EIGEN_POLYNOMIAL_SOLVER_H
diff --git a/unsupported/Eigen/src/Polynomials/PolynomialUtils.h b/unsupported/Eigen/src/Polynomials/PolynomialUtils.h
new file mode 100644
index 000000000..c23204c65
--- /dev/null
+++ b/unsupported/Eigen/src/Polynomials/PolynomialUtils.h
@@ -0,0 +1,141 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra.
+//
+// Copyright (C) 2010 Manuel Yguel <manuel.yguel@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 EIGEN_POLYNOMIAL_UTILS_H
+#define EIGEN_POLYNOMIAL_UTILS_H
+
+namespace Eigen {
+
+/** \ingroup Polynomials_Module
+ * \returns the evaluation of the polynomial at x using Horner algorithm.
+ *
+ * \param[in] poly : the vector of coefficients of the polynomial ordered
+ * by degrees i.e. poly[i] is the coefficient of degree i of the polynomial
+ * e.g. \f$ 1 + 3x^2 \f$ is stored as a vector \f$ [ 1, 0, 3 ] \f$.
+ * \param[in] x : the value to evaluate the polynomial at.
+ *
+ * <i><b>Note for stability:</b></i>
+ * <dd> \f$ |x| \le 1 \f$ </dd>
+ */
+template <typename Polynomials, typename T>
+inline
+T poly_eval_horner( const Polynomials& poly, const T& x )
+{
+ T val=poly[poly.size()-1];
+ for(DenseIndex i=poly.size()-2; i>=0; --i ){
+ val = val*x + poly[i]; }
+ return val;
+}
+
+/** \ingroup Polynomials_Module
+ * \returns the evaluation of the polynomial at x using stabilized Horner algorithm.
+ *
+ * \param[in] poly : the vector of coefficients of the polynomial ordered
+ * by degrees i.e. poly[i] is the coefficient of degree i of the polynomial
+ * e.g. \f$ 1 + 3x^2 \f$ is stored as a vector \f$ [ 1, 0, 3 ] \f$.
+ * \param[in] x : the value to evaluate the polynomial at.
+ */
+template <typename Polynomials, typename T>
+inline
+T poly_eval( const Polynomials& poly, const T& x )
+{
+ typedef typename NumTraits<T>::Real Real;
+
+ if( internal::abs2( x ) <= Real(1) ){
+ return poly_eval_horner( poly, x ); }
+ else
+ {
+ T val=poly[0];
+ T inv_x = T(1)/x;
+ for( DenseIndex i=1; i<poly.size(); ++i ){
+ val = val*inv_x + poly[i]; }
+
+ return std::pow(x,(T)(poly.size()-1)) * val;
+ }
+}
+
+/** \ingroup Polynomials_Module
+ * \returns a maximum bound for the absolute value of any root of the polynomial.
+ *
+ * \param[in] poly : the vector of coefficients of the polynomial ordered
+ * by degrees i.e. poly[i] is the coefficient of degree i of the polynomial
+ * e.g. \f$ 1 + 3x^2 \f$ is stored as a vector \f$ [ 1, 0, 3 ] \f$.
+ *
+ * <i><b>Precondition:</b></i>
+ * <dd> the leading coefficient of the input polynomial poly must be non zero </dd>
+ */
+template <typename Polynomial>
+inline
+typename NumTraits<typename Polynomial::Scalar>::Real cauchy_max_bound( const Polynomial& poly )
+{
+ typedef typename Polynomial::Scalar Scalar;
+ typedef typename NumTraits<Scalar>::Real Real;
+
+ assert( Scalar(0) != poly[poly.size()-1] );
+ const Scalar inv_leading_coeff = Scalar(1)/poly[poly.size()-1];
+ Real cb(0);
+
+ for( DenseIndex i=0; i<poly.size()-1; ++i ){
+ cb += internal::abs(poly[i]*inv_leading_coeff); }
+ return cb + Real(1);
+}
+
+/** \ingroup Polynomials_Module
+ * \returns a minimum bound for the absolute value of any non zero root of the polynomial.
+ * \param[in] poly : the vector of coefficients of the polynomial ordered
+ * by degrees i.e. poly[i] is the coefficient of degree i of the polynomial
+ * e.g. \f$ 1 + 3x^2 \f$ is stored as a vector \f$ [ 1, 0, 3 ] \f$.
+ */
+template <typename Polynomial>
+inline
+typename NumTraits<typename Polynomial::Scalar>::Real cauchy_min_bound( const Polynomial& poly )
+{
+ typedef typename Polynomial::Scalar Scalar;
+ typedef typename NumTraits<Scalar>::Real Real;
+
+ DenseIndex i=0;
+ while( i<poly.size()-1 && Scalar(0) == poly(i) ){ ++i; }
+ if( poly.size()-1 == i ){
+ return Real(1); }
+
+ const Scalar inv_min_coeff = Scalar(1)/poly[i];
+ Real cb(1);
+ for( DenseIndex j=i+1; j<poly.size(); ++j ){
+ cb += internal::abs(poly[j]*inv_min_coeff); }
+ return Real(1)/cb;
+}
+
+/** \ingroup Polynomials_Module
+ * Given the roots of a polynomial compute the coefficients in the
+ * monomial basis of the monic polynomial with same roots and minimal degree.
+ * If RootVector is a vector of complexes, Polynomial should also be a vector
+ * of complexes.
+ * \param[in] rv : a vector containing the roots of a polynomial.
+ * \param[out] poly : the vector of coefficients of the polynomial ordered
+ * by degrees i.e. poly[i] is the coefficient of degree i of the polynomial
+ * e.g. \f$ 3 + x^2 \f$ is stored as a vector \f$ [ 3, 0, 1 ] \f$.
+ */
+template <typename RootVector, typename Polynomial>
+void roots_to_monicPolynomial( const RootVector& rv, Polynomial& poly )
+{
+
+ typedef typename Polynomial::Scalar Scalar;
+
+ poly.setZero( rv.size()+1 );
+ poly[0] = -rv[0]; poly[1] = Scalar(1);
+ for( DenseIndex i=1; i< rv.size(); ++i )
+ {
+ for( DenseIndex j=i+1; j>0; --j ){ poly[j] = poly[j-1] - rv[i]*poly[j]; }
+ poly[0] = -rv[i]*poly[0];
+ }
+}
+
+} // end namespace Eigen
+
+#endif // EIGEN_POLYNOMIAL_UTILS_H
diff --git a/unsupported/Eigen/src/Skyline/CMakeLists.txt b/unsupported/Eigen/src/Skyline/CMakeLists.txt
new file mode 100644
index 000000000..3bf1b0dd4
--- /dev/null
+++ b/unsupported/Eigen/src/Skyline/CMakeLists.txt
@@ -0,0 +1,6 @@
+FILE(GLOB Eigen_Skyline_SRCS "*.h")
+
+INSTALL(FILES
+ ${Eigen_Skyline_SRCS}
+ DESTINATION ${INCLUDE_INSTALL_DIR}/unsupported/Eigen/src/Skyline COMPONENT Devel
+ )
diff --git a/unsupported/Eigen/src/Skyline/SkylineInplaceLU.h b/unsupported/Eigen/src/Skyline/SkylineInplaceLU.h
new file mode 100644
index 000000000..a1f54ed35
--- /dev/null
+++ b/unsupported/Eigen/src/Skyline/SkylineInplaceLU.h
@@ -0,0 +1,352 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra.
+//
+// Copyright (C) 2008 Guillaume Saupin <guillaume.saupin@cea.fr>
+//
+// This Source Code Form is subject to the terms of the Mozilla
+// Public License v. 2.0. If a copy of the MPL was not distributed
+// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+#ifndef EIGEN_SKYLINEINPLACELU_H
+#define EIGEN_SKYLINEINPLACELU_H
+
+namespace Eigen {
+
+/** \ingroup Skyline_Module
+ *
+ * \class SkylineInplaceLU
+ *
+ * \brief Inplace LU decomposition of a skyline matrix and associated features
+ *
+ * \param MatrixType the type of the matrix of which we are computing the LU factorization
+ *
+ */
+template<typename MatrixType>
+class SkylineInplaceLU {
+protected:
+ typedef typename MatrixType::Scalar Scalar;
+ typedef typename MatrixType::Index Index;
+
+ typedef typename NumTraits<typename MatrixType::Scalar>::Real RealScalar;
+
+public:
+
+ /** Creates a LU object and compute the respective factorization of \a matrix using
+ * flags \a flags. */
+ SkylineInplaceLU(MatrixType& matrix, int flags = 0)
+ : /*m_matrix(matrix.rows(), matrix.cols()),*/ m_flags(flags), m_status(0), m_lu(matrix) {
+ m_precision = RealScalar(0.1) * Eigen::dummy_precision<RealScalar > ();
+ m_lu.IsRowMajor ? computeRowMajor() : compute();
+ }
+
+ /** Sets the relative threshold value used to prune zero coefficients during the decomposition.
+ *
+ * Setting a value greater than zero speeds up computation, and yields to an imcomplete
+ * factorization with fewer non zero coefficients. Such approximate factors are especially
+ * useful to initialize an iterative solver.
+ *
+ * Note that the exact meaning of this parameter might depends on the actual
+ * backend. Moreover, not all backends support this feature.
+ *
+ * \sa precision() */
+ void setPrecision(RealScalar v) {
+ m_precision = v;
+ }
+
+ /** \returns the current precision.
+ *
+ * \sa setPrecision() */
+ RealScalar precision() const {
+ return m_precision;
+ }
+
+ /** Sets the flags. Possible values are:
+ * - CompleteFactorization
+ * - IncompleteFactorization
+ * - MemoryEfficient
+ * - one of the ordering methods
+ * - etc...
+ *
+ * \sa flags() */
+ void setFlags(int f) {
+ m_flags = f;
+ }
+
+ /** \returns the current flags */
+ int flags() const {
+ return m_flags;
+ }
+
+ void setOrderingMethod(int m) {
+ m_flags = m;
+ }
+
+ int orderingMethod() const {
+ return m_flags;
+ }
+
+ /** Computes/re-computes the LU factorization */
+ void compute();
+ void computeRowMajor();
+
+ /** \returns the lower triangular matrix L */
+ //inline const MatrixType& matrixL() const { return m_matrixL; }
+
+ /** \returns the upper triangular matrix U */
+ //inline const MatrixType& matrixU() const { return m_matrixU; }
+
+ template<typename BDerived, typename XDerived>
+ bool solve(const MatrixBase<BDerived> &b, MatrixBase<XDerived>* x,
+ const int transposed = 0) const;
+
+ /** \returns true if the factorization succeeded */
+ inline bool succeeded(void) const {
+ return m_succeeded;
+ }
+
+protected:
+ RealScalar m_precision;
+ int m_flags;
+ mutable int m_status;
+ bool m_succeeded;
+ MatrixType& m_lu;
+};
+
+/** Computes / recomputes the in place LU decomposition of the SkylineInplaceLU.
+ * using the default algorithm.
+ */
+template<typename MatrixType>
+//template<typename _Scalar>
+void SkylineInplaceLU<MatrixType>::compute() {
+ const size_t rows = m_lu.rows();
+ const size_t cols = m_lu.cols();
+
+ eigen_assert(rows == cols && "We do not (yet) support rectangular LU.");
+ eigen_assert(!m_lu.IsRowMajor && "LU decomposition does not work with rowMajor Storage");
+
+ for (Index row = 0; row < rows; row++) {
+ const double pivot = m_lu.coeffDiag(row);
+
+ //Lower matrix Columns update
+ const Index& col = row;
+ for (typename MatrixType::InnerLowerIterator lIt(m_lu, col); lIt; ++lIt) {
+ lIt.valueRef() /= pivot;
+ }
+
+ //Upper matrix update -> contiguous memory access
+ typename MatrixType::InnerLowerIterator lIt(m_lu, col);
+ for (Index rrow = row + 1; rrow < m_lu.rows(); rrow++) {
+ typename MatrixType::InnerUpperIterator uItPivot(m_lu, row);
+ typename MatrixType::InnerUpperIterator uIt(m_lu, rrow);
+ const double coef = lIt.value();
+
+ uItPivot += (rrow - row - 1);
+
+ //update upper part -> contiguous memory access
+ for (++uItPivot; uIt && uItPivot;) {
+ uIt.valueRef() -= uItPivot.value() * coef;
+
+ ++uIt;
+ ++uItPivot;
+ }
+ ++lIt;
+ }
+
+ //Upper matrix update -> non contiguous memory access
+ typename MatrixType::InnerLowerIterator lIt3(m_lu, col);
+ for (Index rrow = row + 1; rrow < m_lu.rows(); rrow++) {
+ typename MatrixType::InnerUpperIterator uItPivot(m_lu, row);
+ const double coef = lIt3.value();
+
+ //update lower part -> non contiguous memory access
+ for (Index i = 0; i < rrow - row - 1; i++) {
+ m_lu.coeffRefLower(rrow, row + i + 1) -= uItPivot.value() * coef;
+ ++uItPivot;
+ }
+ ++lIt3;
+ }
+ //update diag -> contiguous
+ typename MatrixType::InnerLowerIterator lIt2(m_lu, col);
+ for (Index rrow = row + 1; rrow < m_lu.rows(); rrow++) {
+
+ typename MatrixType::InnerUpperIterator uItPivot(m_lu, row);
+ typename MatrixType::InnerUpperIterator uIt(m_lu, rrow);
+ const double coef = lIt2.value();
+
+ uItPivot += (rrow - row - 1);
+ m_lu.coeffRefDiag(rrow) -= uItPivot.value() * coef;
+ ++lIt2;
+ }
+ }
+}
+
+template<typename MatrixType>
+void SkylineInplaceLU<MatrixType>::computeRowMajor() {
+ const size_t rows = m_lu.rows();
+ const size_t cols = m_lu.cols();
+
+ eigen_assert(rows == cols && "We do not (yet) support rectangular LU.");
+ eigen_assert(m_lu.IsRowMajor && "You're trying to apply rowMajor decomposition on a ColMajor matrix !");
+
+ for (Index row = 0; row < rows; row++) {
+ typename MatrixType::InnerLowerIterator llIt(m_lu, row);
+
+
+ for (Index col = llIt.col(); col < row; col++) {
+ if (m_lu.coeffExistLower(row, col)) {
+ const double diag = m_lu.coeffDiag(col);
+
+ typename MatrixType::InnerLowerIterator lIt(m_lu, row);
+ typename MatrixType::InnerUpperIterator uIt(m_lu, col);
+
+
+ const Index offset = lIt.col() - uIt.row();
+
+
+ Index stop = offset > 0 ? col - lIt.col() : col - uIt.row();
+
+ //#define VECTORIZE
+#ifdef VECTORIZE
+ Map<VectorXd > rowVal(lIt.valuePtr() + (offset > 0 ? 0 : -offset), stop);
+ Map<VectorXd > colVal(uIt.valuePtr() + (offset > 0 ? offset : 0), stop);
+
+
+ Scalar newCoeff = m_lu.coeffLower(row, col) - rowVal.dot(colVal);
+#else
+ if (offset > 0) //Skip zero value of lIt
+ uIt += offset;
+ else //Skip zero values of uIt
+ lIt += -offset;
+ Scalar newCoeff = m_lu.coeffLower(row, col);
+
+ for (Index k = 0; k < stop; ++k) {
+ const Scalar tmp = newCoeff;
+ newCoeff = tmp - lIt.value() * uIt.value();
+ ++lIt;
+ ++uIt;
+ }
+#endif
+
+ m_lu.coeffRefLower(row, col) = newCoeff / diag;
+ }
+ }
+
+ //Upper matrix update
+ const Index col = row;
+ typename MatrixType::InnerUpperIterator uuIt(m_lu, col);
+ for (Index rrow = uuIt.row(); rrow < col; rrow++) {
+
+ typename MatrixType::InnerLowerIterator lIt(m_lu, rrow);
+ typename MatrixType::InnerUpperIterator uIt(m_lu, col);
+ const Index offset = lIt.col() - uIt.row();
+
+ Index stop = offset > 0 ? rrow - lIt.col() : rrow - uIt.row();
+
+#ifdef VECTORIZE
+ Map<VectorXd > rowVal(lIt.valuePtr() + (offset > 0 ? 0 : -offset), stop);
+ Map<VectorXd > colVal(uIt.valuePtr() + (offset > 0 ? offset : 0), stop);
+
+ Scalar newCoeff = m_lu.coeffUpper(rrow, col) - rowVal.dot(colVal);
+#else
+ if (offset > 0) //Skip zero value of lIt
+ uIt += offset;
+ else //Skip zero values of uIt
+ lIt += -offset;
+ Scalar newCoeff = m_lu.coeffUpper(rrow, col);
+ for (Index k = 0; k < stop; ++k) {
+ const Scalar tmp = newCoeff;
+ newCoeff = tmp - lIt.value() * uIt.value();
+
+ ++lIt;
+ ++uIt;
+ }
+#endif
+ m_lu.coeffRefUpper(rrow, col) = newCoeff;
+ }
+
+
+ //Diag matrix update
+ typename MatrixType::InnerLowerIterator lIt(m_lu, row);
+ typename MatrixType::InnerUpperIterator uIt(m_lu, row);
+
+ const Index offset = lIt.col() - uIt.row();
+
+
+ Index stop = offset > 0 ? lIt.size() : uIt.size();
+#ifdef VECTORIZE
+ Map<VectorXd > rowVal(lIt.valuePtr() + (offset > 0 ? 0 : -offset), stop);
+ Map<VectorXd > colVal(uIt.valuePtr() + (offset > 0 ? offset : 0), stop);
+ Scalar newCoeff = m_lu.coeffDiag(row) - rowVal.dot(colVal);
+#else
+ if (offset > 0) //Skip zero value of lIt
+ uIt += offset;
+ else //Skip zero values of uIt
+ lIt += -offset;
+ Scalar newCoeff = m_lu.coeffDiag(row);
+ for (Index k = 0; k < stop; ++k) {
+ const Scalar tmp = newCoeff;
+ newCoeff = tmp - lIt.value() * uIt.value();
+ ++lIt;
+ ++uIt;
+ }
+#endif
+ m_lu.coeffRefDiag(row) = newCoeff;
+ }
+}
+
+/** Computes *x = U^-1 L^-1 b
+ *
+ * If \a transpose is set to SvTranspose or SvAdjoint, the solution
+ * of the transposed/adjoint system is computed instead.
+ *
+ * Not all backends implement the solution of the transposed or
+ * adjoint system.
+ */
+template<typename MatrixType>
+template<typename BDerived, typename XDerived>
+bool SkylineInplaceLU<MatrixType>::solve(const MatrixBase<BDerived> &b, MatrixBase<XDerived>* x, const int transposed) const {
+ const size_t rows = m_lu.rows();
+ const size_t cols = m_lu.cols();
+
+
+ for (Index row = 0; row < rows; row++) {
+ x->coeffRef(row) = b.coeff(row);
+ Scalar newVal = x->coeff(row);
+ typename MatrixType::InnerLowerIterator lIt(m_lu, row);
+
+ Index col = lIt.col();
+ while (lIt.col() < row) {
+
+ newVal -= x->coeff(col++) * lIt.value();
+ ++lIt;
+ }
+
+ x->coeffRef(row) = newVal;
+ }
+
+
+ for (Index col = rows - 1; col > 0; col--) {
+ x->coeffRef(col) = x->coeff(col) / m_lu.coeffDiag(col);
+
+ const Scalar x_col = x->coeff(col);
+
+ typename MatrixType::InnerUpperIterator uIt(m_lu, col);
+ uIt += uIt.size()-1;
+
+
+ while (uIt) {
+ x->coeffRef(uIt.row()) -= x_col * uIt.value();
+ //TODO : introduce --operator
+ uIt += -1;
+ }
+
+
+ }
+ x->coeffRef(0) = x->coeff(0) / m_lu.coeffDiag(0);
+
+ return true;
+}
+
+} // end namespace Eigen
+
+#endif // EIGEN_SKYLINELU_H
diff --git a/unsupported/Eigen/src/Skyline/SkylineMatrix.h b/unsupported/Eigen/src/Skyline/SkylineMatrix.h
new file mode 100644
index 000000000..a2a8933ca
--- /dev/null
+++ b/unsupported/Eigen/src/Skyline/SkylineMatrix.h
@@ -0,0 +1,862 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra.
+//
+// Copyright (C) 2008-2009 Guillaume Saupin <guillaume.saupin@cea.fr>
+//
+// This Source Code Form is subject to the terms of the Mozilla
+// Public License v. 2.0. If a copy of the MPL was not distributed
+// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+#ifndef EIGEN_SKYLINEMATRIX_H
+#define EIGEN_SKYLINEMATRIX_H
+
+#include "SkylineStorage.h"
+#include "SkylineMatrixBase.h"
+
+namespace Eigen {
+
+/** \ingroup Skyline_Module
+ *
+ * \class SkylineMatrix
+ *
+ * \brief The main skyline matrix class
+ *
+ * This class implements a skyline matrix using the very uncommon storage
+ * scheme.
+ *
+ * \param _Scalar the scalar type, i.e. the type of the coefficients
+ * \param _Options Union of bit flags controlling the storage scheme. Currently the only possibility
+ * is RowMajor. The default is 0 which means column-major.
+ *
+ *
+ */
+namespace internal {
+template<typename _Scalar, int _Options>
+struct traits<SkylineMatrix<_Scalar, _Options> > {
+ typedef _Scalar Scalar;
+ typedef Sparse StorageKind;
+
+ enum {
+ RowsAtCompileTime = Dynamic,
+ ColsAtCompileTime = Dynamic,
+ MaxRowsAtCompileTime = Dynamic,
+ MaxColsAtCompileTime = Dynamic,
+ Flags = SkylineBit | _Options,
+ CoeffReadCost = NumTraits<Scalar>::ReadCost,
+ };
+};
+}
+
+template<typename _Scalar, int _Options>
+class SkylineMatrix
+: public SkylineMatrixBase<SkylineMatrix<_Scalar, _Options> > {
+public:
+ EIGEN_SKYLINE_GENERIC_PUBLIC_INTERFACE(SkylineMatrix)
+ EIGEN_SKYLINE_INHERIT_ASSIGNMENT_OPERATOR(SkylineMatrix, +=)
+ EIGEN_SKYLINE_INHERIT_ASSIGNMENT_OPERATOR(SkylineMatrix, -=)
+
+ using Base::IsRowMajor;
+
+protected:
+
+ typedef SkylineMatrix<Scalar, (Flags&~RowMajorBit) | (IsRowMajor ? RowMajorBit : 0) > TransposedSkylineMatrix;
+
+ Index m_outerSize;
+ Index m_innerSize;
+
+public:
+ Index* m_colStartIndex;
+ Index* m_rowStartIndex;
+ SkylineStorage<Scalar> m_data;
+
+public:
+
+ inline Index rows() const {
+ return IsRowMajor ? m_outerSize : m_innerSize;
+ }
+
+ inline Index cols() const {
+ return IsRowMajor ? m_innerSize : m_outerSize;
+ }
+
+ inline Index innerSize() const {
+ return m_innerSize;
+ }
+
+ inline Index outerSize() const {
+ return m_outerSize;
+ }
+
+ inline Index upperNonZeros() const {
+ return m_data.upperSize();
+ }
+
+ inline Index lowerNonZeros() const {
+ return m_data.lowerSize();
+ }
+
+ inline Index upperNonZeros(Index j) const {
+ return m_colStartIndex[j + 1] - m_colStartIndex[j];
+ }
+
+ inline Index lowerNonZeros(Index j) const {
+ return m_rowStartIndex[j + 1] - m_rowStartIndex[j];
+ }
+
+ inline const Scalar* _diagPtr() const {
+ return &m_data.diag(0);
+ }
+
+ inline Scalar* _diagPtr() {
+ return &m_data.diag(0);
+ }
+
+ inline const Scalar* _upperPtr() const {
+ return &m_data.upper(0);
+ }
+
+ inline Scalar* _upperPtr() {
+ return &m_data.upper(0);
+ }
+
+ inline const Scalar* _lowerPtr() const {
+ return &m_data.lower(0);
+ }
+
+ inline Scalar* _lowerPtr() {
+ return &m_data.lower(0);
+ }
+
+ inline const Index* _upperProfilePtr() const {
+ return &m_data.upperProfile(0);
+ }
+
+ inline Index* _upperProfilePtr() {
+ return &m_data.upperProfile(0);
+ }
+
+ inline const Index* _lowerProfilePtr() const {
+ return &m_data.lowerProfile(0);
+ }
+
+ inline Index* _lowerProfilePtr() {
+ return &m_data.lowerProfile(0);
+ }
+
+ inline Scalar coeff(Index row, Index col) const {
+ const Index outer = IsRowMajor ? row : col;
+ const Index inner = IsRowMajor ? col : row;
+
+ eigen_assert(outer < outerSize());
+ eigen_assert(inner < innerSize());
+
+ if (outer == inner)
+ return this->m_data.diag(outer);
+
+ if (IsRowMajor) {
+ if (inner > outer) //upper matrix
+ {
+ const Index minOuterIndex = inner - m_data.upperProfile(inner);
+ if (outer >= minOuterIndex)
+ return this->m_data.upper(m_colStartIndex[inner] + outer - (inner - m_data.upperProfile(inner)));
+ else
+ return Scalar(0);
+ }
+ if (inner < outer) //lower matrix
+ {
+ const Index minInnerIndex = outer - m_data.lowerProfile(outer);
+ if (inner >= minInnerIndex)
+ return this->m_data.lower(m_rowStartIndex[outer] + inner - (outer - m_data.lowerProfile(outer)));
+ else
+ return Scalar(0);
+ }
+ return m_data.upper(m_colStartIndex[inner] + outer - inner);
+ } else {
+ if (outer > inner) //upper matrix
+ {
+ const Index maxOuterIndex = inner + m_data.upperProfile(inner);
+ if (outer <= maxOuterIndex)
+ return this->m_data.upper(m_colStartIndex[inner] + (outer - inner));
+ else
+ return Scalar(0);
+ }
+ if (outer < inner) //lower matrix
+ {
+ const Index maxInnerIndex = outer + m_data.lowerProfile(outer);
+
+ if (inner <= maxInnerIndex)
+ return this->m_data.lower(m_rowStartIndex[outer] + (inner - outer));
+ else
+ return Scalar(0);
+ }
+ }
+ }
+
+ inline Scalar& coeffRef(Index row, Index col) {
+ const Index outer = IsRowMajor ? row : col;
+ const Index inner = IsRowMajor ? col : row;
+
+ eigen_assert(outer < outerSize());
+ eigen_assert(inner < innerSize());
+
+ if (outer == inner)
+ return this->m_data.diag(outer);
+
+ if (IsRowMajor) {
+ if (col > row) //upper matrix
+ {
+ const Index minOuterIndex = inner - m_data.upperProfile(inner);
+ eigen_assert(outer >= minOuterIndex && "you try to acces a coeff that do not exist in the storage");
+ return this->m_data.upper(m_colStartIndex[inner] + outer - (inner - m_data.upperProfile(inner)));
+ }
+ if (col < row) //lower matrix
+ {
+ const Index minInnerIndex = outer - m_data.lowerProfile(outer);
+ eigen_assert(inner >= minInnerIndex && "you try to acces a coeff that do not exist in the storage");
+ return this->m_data.lower(m_rowStartIndex[outer] + inner - (outer - m_data.lowerProfile(outer)));
+ }
+ } else {
+ if (outer > inner) //upper matrix
+ {
+ const Index maxOuterIndex = inner + m_data.upperProfile(inner);
+ eigen_assert(outer <= maxOuterIndex && "you try to acces a coeff that do not exist in the storage");
+ return this->m_data.upper(m_colStartIndex[inner] + (outer - inner));
+ }
+ if (outer < inner) //lower matrix
+ {
+ const Index maxInnerIndex = outer + m_data.lowerProfile(outer);
+ eigen_assert(inner <= maxInnerIndex && "you try to acces a coeff that do not exist in the storage");
+ return this->m_data.lower(m_rowStartIndex[outer] + (inner - outer));
+ }
+ }
+ }
+
+ inline Scalar coeffDiag(Index idx) const {
+ eigen_assert(idx < outerSize());
+ eigen_assert(idx < innerSize());
+ return this->m_data.diag(idx);
+ }
+
+ inline Scalar coeffLower(Index row, Index col) const {
+ const Index outer = IsRowMajor ? row : col;
+ const Index inner = IsRowMajor ? col : row;
+
+ eigen_assert(outer < outerSize());
+ eigen_assert(inner < innerSize());
+ eigen_assert(inner != outer);
+
+ if (IsRowMajor) {
+ const Index minInnerIndex = outer - m_data.lowerProfile(outer);
+ if (inner >= minInnerIndex)
+ return this->m_data.lower(m_rowStartIndex[outer] + inner - (outer - m_data.lowerProfile(outer)));
+ else
+ return Scalar(0);
+
+ } else {
+ const Index maxInnerIndex = outer + m_data.lowerProfile(outer);
+ if (inner <= maxInnerIndex)
+ return this->m_data.lower(m_rowStartIndex[outer] + (inner - outer));
+ else
+ return Scalar(0);
+ }
+ }
+
+ inline Scalar coeffUpper(Index row, Index col) const {
+ const Index outer = IsRowMajor ? row : col;
+ const Index inner = IsRowMajor ? col : row;
+
+ eigen_assert(outer < outerSize());
+ eigen_assert(inner < innerSize());
+ eigen_assert(inner != outer);
+
+ if (IsRowMajor) {
+ const Index minOuterIndex = inner - m_data.upperProfile(inner);
+ if (outer >= minOuterIndex)
+ return this->m_data.upper(m_colStartIndex[inner] + outer - (inner - m_data.upperProfile(inner)));
+ else
+ return Scalar(0);
+ } else {
+ const Index maxOuterIndex = inner + m_data.upperProfile(inner);
+ if (outer <= maxOuterIndex)
+ return this->m_data.upper(m_colStartIndex[inner] + (outer - inner));
+ else
+ return Scalar(0);
+ }
+ }
+
+ inline Scalar& coeffRefDiag(Index idx) {
+ eigen_assert(idx < outerSize());
+ eigen_assert(idx < innerSize());
+ return this->m_data.diag(idx);
+ }
+
+ inline Scalar& coeffRefLower(Index row, Index col) {
+ const Index outer = IsRowMajor ? row : col;
+ const Index inner = IsRowMajor ? col : row;
+
+ eigen_assert(outer < outerSize());
+ eigen_assert(inner < innerSize());
+ eigen_assert(inner != outer);
+
+ if (IsRowMajor) {
+ const Index minInnerIndex = outer - m_data.lowerProfile(outer);
+ eigen_assert(inner >= minInnerIndex && "you try to acces a coeff that do not exist in the storage");
+ return this->m_data.lower(m_rowStartIndex[outer] + inner - (outer - m_data.lowerProfile(outer)));
+ } else {
+ const Index maxInnerIndex = outer + m_data.lowerProfile(outer);
+ eigen_assert(inner <= maxInnerIndex && "you try to acces a coeff that do not exist in the storage");
+ return this->m_data.lower(m_rowStartIndex[outer] + (inner - outer));
+ }
+ }
+
+ inline bool coeffExistLower(Index row, Index col) {
+ const Index outer = IsRowMajor ? row : col;
+ const Index inner = IsRowMajor ? col : row;
+
+ eigen_assert(outer < outerSize());
+ eigen_assert(inner < innerSize());
+ eigen_assert(inner != outer);
+
+ if (IsRowMajor) {
+ const Index minInnerIndex = outer - m_data.lowerProfile(outer);
+ return inner >= minInnerIndex;
+ } else {
+ const Index maxInnerIndex = outer + m_data.lowerProfile(outer);
+ return inner <= maxInnerIndex;
+ }
+ }
+
+ inline Scalar& coeffRefUpper(Index row, Index col) {
+ const Index outer = IsRowMajor ? row : col;
+ const Index inner = IsRowMajor ? col : row;
+
+ eigen_assert(outer < outerSize());
+ eigen_assert(inner < innerSize());
+ eigen_assert(inner != outer);
+
+ if (IsRowMajor) {
+ const Index minOuterIndex = inner - m_data.upperProfile(inner);
+ eigen_assert(outer >= minOuterIndex && "you try to acces a coeff that do not exist in the storage");
+ return this->m_data.upper(m_colStartIndex[inner] + outer - (inner - m_data.upperProfile(inner)));
+ } else {
+ const Index maxOuterIndex = inner + m_data.upperProfile(inner);
+ eigen_assert(outer <= maxOuterIndex && "you try to acces a coeff that do not exist in the storage");
+ return this->m_data.upper(m_colStartIndex[inner] + (outer - inner));
+ }
+ }
+
+ inline bool coeffExistUpper(Index row, Index col) {
+ const Index outer = IsRowMajor ? row : col;
+ const Index inner = IsRowMajor ? col : row;
+
+ eigen_assert(outer < outerSize());
+ eigen_assert(inner < innerSize());
+ eigen_assert(inner != outer);
+
+ if (IsRowMajor) {
+ const Index minOuterIndex = inner - m_data.upperProfile(inner);
+ return outer >= minOuterIndex;
+ } else {
+ const Index maxOuterIndex = inner + m_data.upperProfile(inner);
+ return outer <= maxOuterIndex;
+ }
+ }
+
+
+protected:
+
+public:
+ class InnerUpperIterator;
+ class InnerLowerIterator;
+
+ class OuterUpperIterator;
+ class OuterLowerIterator;
+
+ /** Removes all non zeros */
+ inline void setZero() {
+ m_data.clear();
+ memset(m_colStartIndex, 0, (m_outerSize + 1) * sizeof (Index));
+ memset(m_rowStartIndex, 0, (m_outerSize + 1) * sizeof (Index));
+ }
+
+ /** \returns the number of non zero coefficients */
+ inline Index nonZeros() const {
+ return m_data.diagSize() + m_data.upperSize() + m_data.lowerSize();
+ }
+
+ /** Preallocates \a reserveSize non zeros */
+ inline void reserve(Index reserveSize, Index reserveUpperSize, Index reserveLowerSize) {
+ m_data.reserve(reserveSize, reserveUpperSize, reserveLowerSize);
+ }
+
+ /** \returns a reference to a novel non zero coefficient with coordinates \a row x \a col.
+
+ *
+ * \warning This function can be extremely slow if the non zero coefficients
+ * are not inserted in a coherent order.
+ *
+ * After an insertion session, you should call the finalize() function.
+ */
+ EIGEN_DONT_INLINE Scalar & insert(Index row, Index col) {
+ const Index outer = IsRowMajor ? row : col;
+ const Index inner = IsRowMajor ? col : row;
+
+ eigen_assert(outer < outerSize());
+ eigen_assert(inner < innerSize());
+
+ if (outer == inner)
+ return m_data.diag(col);
+
+ if (IsRowMajor) {
+ if (outer < inner) //upper matrix
+ {
+ Index minOuterIndex = 0;
+ minOuterIndex = inner - m_data.upperProfile(inner);
+
+ if (outer < minOuterIndex) //The value does not yet exist
+ {
+ const Index previousProfile = m_data.upperProfile(inner);
+
+ m_data.upperProfile(inner) = inner - outer;
+
+
+ const Index bandIncrement = m_data.upperProfile(inner) - previousProfile;
+ //shift data stored after this new one
+ const Index stop = m_colStartIndex[cols()];
+ const Index start = m_colStartIndex[inner];
+
+
+ for (Index innerIdx = stop; innerIdx >= start; innerIdx--) {
+ m_data.upper(innerIdx + bandIncrement) = m_data.upper(innerIdx);
+ }
+
+ for (Index innerIdx = cols(); innerIdx > inner; innerIdx--) {
+ m_colStartIndex[innerIdx] += bandIncrement;
+ }
+
+ //zeros new data
+ memset(this->_upperPtr() + start, 0, (bandIncrement - 1) * sizeof (Scalar));
+
+ return m_data.upper(m_colStartIndex[inner]);
+ } else {
+ return m_data.upper(m_colStartIndex[inner] + outer - (inner - m_data.upperProfile(inner)));
+ }
+ }
+
+ if (outer > inner) //lower matrix
+ {
+ const Index minInnerIndex = outer - m_data.lowerProfile(outer);
+ if (inner < minInnerIndex) //The value does not yet exist
+ {
+ const Index previousProfile = m_data.lowerProfile(outer);
+ m_data.lowerProfile(outer) = outer - inner;
+
+ const Index bandIncrement = m_data.lowerProfile(outer) - previousProfile;
+ //shift data stored after this new one
+ const Index stop = m_rowStartIndex[rows()];
+ const Index start = m_rowStartIndex[outer];
+
+
+ for (Index innerIdx = stop; innerIdx >= start; innerIdx--) {
+ m_data.lower(innerIdx + bandIncrement) = m_data.lower(innerIdx);
+ }
+
+ for (Index innerIdx = rows(); innerIdx > outer; innerIdx--) {
+ m_rowStartIndex[innerIdx] += bandIncrement;
+ }
+
+ //zeros new data
+ memset(this->_lowerPtr() + start, 0, (bandIncrement - 1) * sizeof (Scalar));
+ return m_data.lower(m_rowStartIndex[outer]);
+ } else {
+ return m_data.lower(m_rowStartIndex[outer] + inner - (outer - m_data.lowerProfile(outer)));
+ }
+ }
+ } else {
+ if (outer > inner) //upper matrix
+ {
+ const Index maxOuterIndex = inner + m_data.upperProfile(inner);
+ if (outer > maxOuterIndex) //The value does not yet exist
+ {
+ const Index previousProfile = m_data.upperProfile(inner);
+ m_data.upperProfile(inner) = outer - inner;
+
+ const Index bandIncrement = m_data.upperProfile(inner) - previousProfile;
+ //shift data stored after this new one
+ const Index stop = m_rowStartIndex[rows()];
+ const Index start = m_rowStartIndex[inner + 1];
+
+ for (Index innerIdx = stop; innerIdx >= start; innerIdx--) {
+ m_data.upper(innerIdx + bandIncrement) = m_data.upper(innerIdx);
+ }
+
+ for (Index innerIdx = inner + 1; innerIdx < outerSize() + 1; innerIdx++) {
+ m_rowStartIndex[innerIdx] += bandIncrement;
+ }
+ memset(this->_upperPtr() + m_rowStartIndex[inner] + previousProfile + 1, 0, (bandIncrement - 1) * sizeof (Scalar));
+ return m_data.upper(m_rowStartIndex[inner] + m_data.upperProfile(inner));
+ } else {
+ return m_data.upper(m_rowStartIndex[inner] + (outer - inner));
+ }
+ }
+
+ if (outer < inner) //lower matrix
+ {
+ const Index maxInnerIndex = outer + m_data.lowerProfile(outer);
+ if (inner > maxInnerIndex) //The value does not yet exist
+ {
+ const Index previousProfile = m_data.lowerProfile(outer);
+ m_data.lowerProfile(outer) = inner - outer;
+
+ const Index bandIncrement = m_data.lowerProfile(outer) - previousProfile;
+ //shift data stored after this new one
+ const Index stop = m_colStartIndex[cols()];
+ const Index start = m_colStartIndex[outer + 1];
+
+ for (Index innerIdx = stop; innerIdx >= start; innerIdx--) {
+ m_data.lower(innerIdx + bandIncrement) = m_data.lower(innerIdx);
+ }
+
+ for (Index innerIdx = outer + 1; innerIdx < outerSize() + 1; innerIdx++) {
+ m_colStartIndex[innerIdx] += bandIncrement;
+ }
+ memset(this->_lowerPtr() + m_colStartIndex[outer] + previousProfile + 1, 0, (bandIncrement - 1) * sizeof (Scalar));
+ return m_data.lower(m_colStartIndex[outer] + m_data.lowerProfile(outer));
+ } else {
+ return m_data.lower(m_colStartIndex[outer] + (inner - outer));
+ }
+ }
+ }
+ }
+
+ /** Must be called after inserting a set of non zero entries.
+ */
+ inline void finalize() {
+ if (IsRowMajor) {
+ if (rows() > cols())
+ m_data.resize(cols(), cols(), rows(), m_colStartIndex[cols()] + 1, m_rowStartIndex[rows()] + 1);
+ else
+ m_data.resize(rows(), cols(), rows(), m_colStartIndex[cols()] + 1, m_rowStartIndex[rows()] + 1);
+
+ // eigen_assert(rows() == cols() && "memory reorganisatrion only works with suare matrix");
+ //
+ // Scalar* newArray = new Scalar[m_colStartIndex[cols()] + 1 + m_rowStartIndex[rows()] + 1];
+ // Index dataIdx = 0;
+ // for (Index row = 0; row < rows(); row++) {
+ //
+ // const Index nbLowerElts = m_rowStartIndex[row + 1] - m_rowStartIndex[row];
+ // // std::cout << "nbLowerElts" << nbLowerElts << std::endl;
+ // memcpy(newArray + dataIdx, m_data.m_lower + m_rowStartIndex[row], nbLowerElts * sizeof (Scalar));
+ // m_rowStartIndex[row] = dataIdx;
+ // dataIdx += nbLowerElts;
+ //
+ // const Index nbUpperElts = m_colStartIndex[row + 1] - m_colStartIndex[row];
+ // memcpy(newArray + dataIdx, m_data.m_upper + m_colStartIndex[row], nbUpperElts * sizeof (Scalar));
+ // m_colStartIndex[row] = dataIdx;
+ // dataIdx += nbUpperElts;
+ //
+ //
+ // }
+ // //todo : don't access m_data profile directly : add an accessor from SkylineMatrix
+ // m_rowStartIndex[rows()] = m_rowStartIndex[rows()-1] + m_data.lowerProfile(rows()-1);
+ // m_colStartIndex[cols()] = m_colStartIndex[cols()-1] + m_data.upperProfile(cols()-1);
+ //
+ // delete[] m_data.m_lower;
+ // delete[] m_data.m_upper;
+ //
+ // m_data.m_lower = newArray;
+ // m_data.m_upper = newArray;
+ } else {
+ if (rows() > cols())
+ m_data.resize(cols(), rows(), cols(), m_rowStartIndex[cols()] + 1, m_colStartIndex[cols()] + 1);
+ else
+ m_data.resize(rows(), rows(), cols(), m_rowStartIndex[rows()] + 1, m_colStartIndex[rows()] + 1);
+ }
+ }
+
+ inline void squeeze() {
+ finalize();
+ m_data.squeeze();
+ }
+
+ void prune(Scalar reference, RealScalar epsilon = dummy_precision<RealScalar > ()) {
+ //TODO
+ }
+
+ /** Resizes the matrix to a \a rows x \a cols matrix and initializes it to zero
+ * \sa resizeNonZeros(Index), reserve(), setZero()
+ */
+ void resize(size_t rows, size_t cols) {
+ const Index diagSize = rows > cols ? cols : rows;
+ m_innerSize = IsRowMajor ? cols : rows;
+
+ eigen_assert(rows == cols && "Skyline matrix must be square matrix");
+
+ if (diagSize % 2) { // diagSize is odd
+ const Index k = (diagSize - 1) / 2;
+
+ m_data.resize(diagSize, IsRowMajor ? cols : rows, IsRowMajor ? rows : cols,
+ 2 * k * k + k + 1,
+ 2 * k * k + k + 1);
+
+ } else // diagSize is even
+ {
+ const Index k = diagSize / 2;
+ m_data.resize(diagSize, IsRowMajor ? cols : rows, IsRowMajor ? rows : cols,
+ 2 * k * k - k + 1,
+ 2 * k * k - k + 1);
+ }
+
+ if (m_colStartIndex && m_rowStartIndex) {
+ delete[] m_colStartIndex;
+ delete[] m_rowStartIndex;
+ }
+ m_colStartIndex = new Index [cols + 1];
+ m_rowStartIndex = new Index [rows + 1];
+ m_outerSize = diagSize;
+
+ m_data.reset();
+ m_data.clear();
+
+ m_outerSize = diagSize;
+ memset(m_colStartIndex, 0, (cols + 1) * sizeof (Index));
+ memset(m_rowStartIndex, 0, (rows + 1) * sizeof (Index));
+ }
+
+ void resizeNonZeros(Index size) {
+ m_data.resize(size);
+ }
+
+ inline SkylineMatrix()
+ : m_outerSize(-1), m_innerSize(0), m_colStartIndex(0), m_rowStartIndex(0) {
+ resize(0, 0);
+ }
+
+ inline SkylineMatrix(size_t rows, size_t cols)
+ : m_outerSize(0), m_innerSize(0), m_colStartIndex(0), m_rowStartIndex(0) {
+ resize(rows, cols);
+ }
+
+ template<typename OtherDerived>
+ inline SkylineMatrix(const SkylineMatrixBase<OtherDerived>& other)
+ : m_outerSize(0), m_innerSize(0), m_colStartIndex(0), m_rowStartIndex(0) {
+ *this = other.derived();
+ }
+
+ inline SkylineMatrix(const SkylineMatrix & other)
+ : Base(), m_outerSize(0), m_innerSize(0), m_colStartIndex(0), m_rowStartIndex(0) {
+ *this = other.derived();
+ }
+
+ inline void swap(SkylineMatrix & other) {
+ //EIGEN_DBG_SKYLINE(std::cout << "SkylineMatrix:: swap\n");
+ std::swap(m_colStartIndex, other.m_colStartIndex);
+ std::swap(m_rowStartIndex, other.m_rowStartIndex);
+ std::swap(m_innerSize, other.m_innerSize);
+ std::swap(m_outerSize, other.m_outerSize);
+ m_data.swap(other.m_data);
+ }
+
+ inline SkylineMatrix & operator=(const SkylineMatrix & other) {
+ std::cout << "SkylineMatrix& operator=(const SkylineMatrix& other)\n";
+ if (other.isRValue()) {
+ swap(other.const_cast_derived());
+ } else {
+ resize(other.rows(), other.cols());
+ memcpy(m_colStartIndex, other.m_colStartIndex, (m_outerSize + 1) * sizeof (Index));
+ memcpy(m_rowStartIndex, other.m_rowStartIndex, (m_outerSize + 1) * sizeof (Index));
+ m_data = other.m_data;
+ }
+ return *this;
+ }
+
+ template<typename OtherDerived>
+ inline SkylineMatrix & operator=(const SkylineMatrixBase<OtherDerived>& other) {
+ const bool needToTranspose = (Flags & RowMajorBit) != (OtherDerived::Flags & RowMajorBit);
+ if (needToTranspose) {
+ // TODO
+ // return *this;
+ } else {
+ // there is no special optimization
+ return SkylineMatrixBase<SkylineMatrix>::operator=(other.derived());
+ }
+ }
+
+ friend std::ostream & operator <<(std::ostream & s, const SkylineMatrix & m) {
+
+ EIGEN_DBG_SKYLINE(
+ std::cout << "upper elements : " << std::endl;
+ for (Index i = 0; i < m.m_data.upperSize(); i++)
+ std::cout << m.m_data.upper(i) << "\t";
+ std::cout << std::endl;
+ std::cout << "upper profile : " << std::endl;
+ for (Index i = 0; i < m.m_data.upperProfileSize(); i++)
+ std::cout << m.m_data.upperProfile(i) << "\t";
+ std::cout << std::endl;
+ std::cout << "lower startIdx : " << std::endl;
+ for (Index i = 0; i < m.m_data.upperProfileSize(); i++)
+ std::cout << (IsRowMajor ? m.m_colStartIndex[i] : m.m_rowStartIndex[i]) << "\t";
+ std::cout << std::endl;
+
+
+ std::cout << "lower elements : " << std::endl;
+ for (Index i = 0; i < m.m_data.lowerSize(); i++)
+ std::cout << m.m_data.lower(i) << "\t";
+ std::cout << std::endl;
+ std::cout << "lower profile : " << std::endl;
+ for (Index i = 0; i < m.m_data.lowerProfileSize(); i++)
+ std::cout << m.m_data.lowerProfile(i) << "\t";
+ std::cout << std::endl;
+ std::cout << "lower startIdx : " << std::endl;
+ for (Index i = 0; i < m.m_data.lowerProfileSize(); i++)
+ std::cout << (IsRowMajor ? m.m_rowStartIndex[i] : m.m_colStartIndex[i]) << "\t";
+ std::cout << std::endl;
+ );
+ for (Index rowIdx = 0; rowIdx < m.rows(); rowIdx++) {
+ for (Index colIdx = 0; colIdx < m.cols(); colIdx++) {
+ s << m.coeff(rowIdx, colIdx) << "\t";
+ }
+ s << std::endl;
+ }
+ return s;
+ }
+
+ /** Destructor */
+ inline ~SkylineMatrix() {
+ delete[] m_colStartIndex;
+ delete[] m_rowStartIndex;
+ }
+
+ /** Overloaded for performance */
+ Scalar sum() const;
+};
+
+template<typename Scalar, int _Options>
+class SkylineMatrix<Scalar, _Options>::InnerUpperIterator {
+public:
+
+ InnerUpperIterator(const SkylineMatrix& mat, Index outer)
+ : m_matrix(mat), m_outer(outer),
+ m_id(_Options == RowMajor ? mat.m_colStartIndex[outer] : mat.m_rowStartIndex[outer] + 1),
+ m_start(m_id),
+ m_end(_Options == RowMajor ? mat.m_colStartIndex[outer + 1] : mat.m_rowStartIndex[outer + 1] + 1) {
+ }
+
+ inline InnerUpperIterator & operator++() {
+ m_id++;
+ return *this;
+ }
+
+ inline InnerUpperIterator & operator+=(Index shift) {
+ m_id += shift;
+ return *this;
+ }
+
+ inline Scalar value() const {
+ return m_matrix.m_data.upper(m_id);
+ }
+
+ inline Scalar* valuePtr() {
+ return const_cast<Scalar*> (&(m_matrix.m_data.upper(m_id)));
+ }
+
+ inline Scalar& valueRef() {
+ return const_cast<Scalar&> (m_matrix.m_data.upper(m_id));
+ }
+
+ inline Index index() const {
+ return IsRowMajor ? m_outer - m_matrix.m_data.upperProfile(m_outer) + (m_id - m_start) :
+ m_outer + (m_id - m_start) + 1;
+ }
+
+ inline Index row() const {
+ return IsRowMajor ? index() : m_outer;
+ }
+
+ inline Index col() const {
+ return IsRowMajor ? m_outer : index();
+ }
+
+ inline size_t size() const {
+ return m_matrix.m_data.upperProfile(m_outer);
+ }
+
+ inline operator bool() const {
+ return (m_id < m_end) && (m_id >= m_start);
+ }
+
+protected:
+ const SkylineMatrix& m_matrix;
+ const Index m_outer;
+ Index m_id;
+ const Index m_start;
+ const Index m_end;
+};
+
+template<typename Scalar, int _Options>
+class SkylineMatrix<Scalar, _Options>::InnerLowerIterator {
+public:
+
+ InnerLowerIterator(const SkylineMatrix& mat, Index outer)
+ : m_matrix(mat),
+ m_outer(outer),
+ m_id(_Options == RowMajor ? mat.m_rowStartIndex[outer] : mat.m_colStartIndex[outer] + 1),
+ m_start(m_id),
+ m_end(_Options == RowMajor ? mat.m_rowStartIndex[outer + 1] : mat.m_colStartIndex[outer + 1] + 1) {
+ }
+
+ inline InnerLowerIterator & operator++() {
+ m_id++;
+ return *this;
+ }
+
+ inline InnerLowerIterator & operator+=(Index shift) {
+ m_id += shift;
+ return *this;
+ }
+
+ inline Scalar value() const {
+ return m_matrix.m_data.lower(m_id);
+ }
+
+ inline Scalar* valuePtr() {
+ return const_cast<Scalar*> (&(m_matrix.m_data.lower(m_id)));
+ }
+
+ inline Scalar& valueRef() {
+ return const_cast<Scalar&> (m_matrix.m_data.lower(m_id));
+ }
+
+ inline Index index() const {
+ return IsRowMajor ? m_outer - m_matrix.m_data.lowerProfile(m_outer) + (m_id - m_start) :
+ m_outer + (m_id - m_start) + 1;
+ ;
+ }
+
+ inline Index row() const {
+ return IsRowMajor ? m_outer : index();
+ }
+
+ inline Index col() const {
+ return IsRowMajor ? index() : m_outer;
+ }
+
+ inline size_t size() const {
+ return m_matrix.m_data.lowerProfile(m_outer);
+ }
+
+ inline operator bool() const {
+ return (m_id < m_end) && (m_id >= m_start);
+ }
+
+protected:
+ const SkylineMatrix& m_matrix;
+ const Index m_outer;
+ Index m_id;
+ const Index m_start;
+ const Index m_end;
+};
+
+} // end namespace Eigen
+
+#endif // EIGEN_SkylineMatrix_H
diff --git a/unsupported/Eigen/src/Skyline/SkylineMatrixBase.h b/unsupported/Eigen/src/Skyline/SkylineMatrixBase.h
new file mode 100644
index 000000000..b3a237230
--- /dev/null
+++ b/unsupported/Eigen/src/Skyline/SkylineMatrixBase.h
@@ -0,0 +1,212 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra.
+//
+// Copyright (C) 2008-2009 Guillaume Saupin <guillaume.saupin@cea.fr>
+//
+// This Source Code Form is subject to the terms of the Mozilla
+// Public License v. 2.0. If a copy of the MPL was not distributed
+// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+#ifndef EIGEN_SKYLINEMATRIXBASE_H
+#define EIGEN_SKYLINEMATRIXBASE_H
+
+#include "SkylineUtil.h"
+
+namespace Eigen {
+
+/** \ingroup Skyline_Module
+ *
+ * \class SkylineMatrixBase
+ *
+ * \brief Base class of any skyline matrices or skyline expressions
+ *
+ * \param Derived
+ *
+ */
+template<typename Derived> class SkylineMatrixBase : public EigenBase<Derived> {
+public:
+
+ typedef typename internal::traits<Derived>::Scalar Scalar;
+ typedef typename internal::traits<Derived>::StorageKind StorageKind;
+ typedef typename internal::index<StorageKind>::type Index;
+
+ enum {
+ RowsAtCompileTime = internal::traits<Derived>::RowsAtCompileTime,
+ /**< The number of rows at compile-time. This is just a copy of the value provided
+ * by the \a Derived type. If a value is not known at compile-time,
+ * it is set to the \a Dynamic constant.
+ * \sa MatrixBase::rows(), MatrixBase::cols(), ColsAtCompileTime, SizeAtCompileTime */
+
+ ColsAtCompileTime = internal::traits<Derived>::ColsAtCompileTime,
+ /**< The number of columns at compile-time. This is just a copy of the value provided
+ * by the \a Derived type. If a value is not known at compile-time,
+ * it is set to the \a Dynamic constant.
+ * \sa MatrixBase::rows(), MatrixBase::cols(), RowsAtCompileTime, SizeAtCompileTime */
+
+
+ SizeAtCompileTime = (internal::size_at_compile_time<internal::traits<Derived>::RowsAtCompileTime,
+ internal::traits<Derived>::ColsAtCompileTime>::ret),
+ /**< This is equal to the number of coefficients, i.e. the number of
+ * rows times the number of columns, or to \a Dynamic if this is not
+ * known at compile-time. \sa RowsAtCompileTime, ColsAtCompileTime */
+
+ MaxRowsAtCompileTime = RowsAtCompileTime,
+ MaxColsAtCompileTime = ColsAtCompileTime,
+
+ MaxSizeAtCompileTime = (internal::size_at_compile_time<MaxRowsAtCompileTime,
+ MaxColsAtCompileTime>::ret),
+
+ IsVectorAtCompileTime = RowsAtCompileTime == 1 || ColsAtCompileTime == 1,
+ /**< This is set to true if either the number of rows or the number of
+ * columns is known at compile-time to be equal to 1. Indeed, in that case,
+ * we are dealing with a column-vector (if there is only one column) or with
+ * a row-vector (if there is only one row). */
+
+ Flags = internal::traits<Derived>::Flags,
+ /**< This stores expression \ref flags flags which may or may not be inherited by new expressions
+ * constructed from this one. See the \ref flags "list of flags".
+ */
+
+ CoeffReadCost = internal::traits<Derived>::CoeffReadCost,
+ /**< This is a rough measure of how expensive it is to read one coefficient from
+ * this expression.
+ */
+
+ IsRowMajor = Flags & RowMajorBit ? 1 : 0
+ };
+
+#ifndef EIGEN_PARSED_BY_DOXYGEN
+ /** This is the "real scalar" type; if the \a Scalar type is already real numbers
+ * (e.g. int, float or double) then \a RealScalar is just the same as \a Scalar. If
+ * \a Scalar is \a std::complex<T> then RealScalar is \a T.
+ *
+ * \sa class NumTraits
+ */
+ typedef typename NumTraits<Scalar>::Real RealScalar;
+
+ /** type of the equivalent square matrix */
+ typedef Matrix<Scalar, EIGEN_SIZE_MAX(RowsAtCompileTime, ColsAtCompileTime),
+ EIGEN_SIZE_MAX(RowsAtCompileTime, ColsAtCompileTime) > SquareMatrixType;
+
+ inline const Derived& derived() const {
+ return *static_cast<const Derived*> (this);
+ }
+
+ inline Derived& derived() {
+ return *static_cast<Derived*> (this);
+ }
+
+ inline Derived& const_cast_derived() const {
+ return *static_cast<Derived*> (const_cast<SkylineMatrixBase*> (this));
+ }
+#endif // not EIGEN_PARSED_BY_DOXYGEN
+
+ /** \returns the number of rows. \sa cols(), RowsAtCompileTime */
+ inline Index rows() const {
+ return derived().rows();
+ }
+
+ /** \returns the number of columns. \sa rows(), ColsAtCompileTime*/
+ inline Index cols() const {
+ return derived().cols();
+ }
+
+ /** \returns the number of coefficients, which is \a rows()*cols().
+ * \sa rows(), cols(), SizeAtCompileTime. */
+ inline Index size() const {
+ return rows() * cols();
+ }
+
+ /** \returns the number of nonzero coefficients which is in practice the number
+ * of stored coefficients. */
+ inline Index nonZeros() const {
+ return derived().nonZeros();
+ }
+
+ /** \returns the size of the storage major dimension,
+ * i.e., the number of columns for a columns major matrix, and the number of rows otherwise */
+ Index outerSize() const {
+ return (int(Flags) & RowMajorBit) ? this->rows() : this->cols();
+ }
+
+ /** \returns the size of the inner dimension according to the storage order,
+ * i.e., the number of rows for a columns major matrix, and the number of cols otherwise */
+ Index innerSize() const {
+ return (int(Flags) & RowMajorBit) ? this->cols() : this->rows();
+ }
+
+ bool isRValue() const {
+ return m_isRValue;
+ }
+
+ Derived& markAsRValue() {
+ m_isRValue = true;
+ return derived();
+ }
+
+ SkylineMatrixBase() : m_isRValue(false) {
+ /* TODO check flags */
+ }
+
+ inline Derived & operator=(const Derived& other) {
+ this->operator=<Derived > (other);
+ return derived();
+ }
+
+ template<typename OtherDerived>
+ inline void assignGeneric(const OtherDerived& other) {
+ derived().resize(other.rows(), other.cols());
+ for (Index row = 0; row < rows(); row++)
+ for (Index col = 0; col < cols(); col++) {
+ if (other.coeff(row, col) != Scalar(0))
+ derived().insert(row, col) = other.coeff(row, col);
+ }
+ derived().finalize();
+ }
+
+ template<typename OtherDerived>
+ inline Derived & operator=(const SkylineMatrixBase<OtherDerived>& other) {
+ //TODO
+ }
+
+ template<typename Lhs, typename Rhs>
+ inline Derived & operator=(const SkylineProduct<Lhs, Rhs, SkylineTimeSkylineProduct>& product);
+
+ friend std::ostream & operator <<(std::ostream & s, const SkylineMatrixBase& m) {
+ s << m.derived();
+ return s;
+ }
+
+ template<typename OtherDerived>
+ const typename SkylineProductReturnType<Derived, OtherDerived>::Type
+ operator*(const MatrixBase<OtherDerived> &other) const;
+
+ /** \internal use operator= */
+ template<typename DenseDerived>
+ void evalTo(MatrixBase<DenseDerived>& dst) const {
+ dst.setZero();
+ for (Index i = 0; i < rows(); i++)
+ for (Index j = 0; j < rows(); j++)
+ dst(i, j) = derived().coeff(i, j);
+ }
+
+ Matrix<Scalar, RowsAtCompileTime, ColsAtCompileTime> toDense() const {
+ return derived();
+ }
+
+ /** \returns the matrix or vector obtained by evaluating this expression.
+ *
+ * Notice that in the case of a plain matrix or vector (not an expression) this function just returns
+ * a const reference, in order to avoid a useless copy.
+ */
+ EIGEN_STRONG_INLINE const typename internal::eval<Derived, IsSkyline>::type eval() const {
+ return typename internal::eval<Derived>::type(derived());
+ }
+
+protected:
+ bool m_isRValue;
+};
+
+} // end namespace Eigen
+
+#endif // EIGEN_SkylineMatrixBase_H
diff --git a/unsupported/Eigen/src/Skyline/SkylineProduct.h b/unsupported/Eigen/src/Skyline/SkylineProduct.h
new file mode 100644
index 000000000..1ddf455e2
--- /dev/null
+++ b/unsupported/Eigen/src/Skyline/SkylineProduct.h
@@ -0,0 +1,295 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra.
+//
+// Copyright (C) 2008-2009 Guillaume Saupin <guillaume.saupin@cea.fr>
+//
+// This Source Code Form is subject to the terms of the Mozilla
+// Public License v. 2.0. If a copy of the MPL was not distributed
+// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+#ifndef EIGEN_SKYLINEPRODUCT_H
+#define EIGEN_SKYLINEPRODUCT_H
+
+namespace Eigen {
+
+template<typename Lhs, typename Rhs, int ProductMode>
+struct SkylineProductReturnType {
+ typedef const typename internal::nested<Lhs, Rhs::RowsAtCompileTime>::type LhsNested;
+ typedef const typename internal::nested<Rhs, Lhs::RowsAtCompileTime>::type RhsNested;
+
+ typedef SkylineProduct<LhsNested, RhsNested, ProductMode> Type;
+};
+
+template<typename LhsNested, typename RhsNested, int ProductMode>
+struct internal::traits<SkylineProduct<LhsNested, RhsNested, ProductMode> > {
+ // clean the nested types:
+ typedef typename internal::remove_all<LhsNested>::type _LhsNested;
+ typedef typename internal::remove_all<RhsNested>::type _RhsNested;
+ typedef typename _LhsNested::Scalar Scalar;
+
+ 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,
+
+ EvalToRowMajor = (RhsFlags & LhsFlags & RowMajorBit),
+ ResultIsSkyline = ProductMode == SkylineTimeSkylineProduct,
+
+ RemovedBits = ~((EvalToRowMajor ? 0 : RowMajorBit) | (ResultIsSkyline ? 0 : SkylineBit)),
+
+ Flags = (int(LhsFlags | RhsFlags) & HereditaryBits & RemovedBits)
+ | EvalBeforeAssigningBit
+ | EvalBeforeNestingBit,
+
+ CoeffReadCost = Dynamic
+ };
+
+ typedef typename internal::conditional<ResultIsSkyline,
+ SkylineMatrixBase<SkylineProduct<LhsNested, RhsNested, ProductMode> >,
+ MatrixBase<SkylineProduct<LhsNested, RhsNested, ProductMode> > >::type Base;
+};
+
+namespace internal {
+template<typename LhsNested, typename RhsNested, int ProductMode>
+class SkylineProduct : no_assignment_operator,
+public traits<SkylineProduct<LhsNested, RhsNested, ProductMode> >::Base {
+public:
+
+ EIGEN_GENERIC_PUBLIC_INTERFACE(SkylineProduct)
+
+private:
+
+ typedef typename traits<SkylineProduct>::_LhsNested _LhsNested;
+ typedef typename traits<SkylineProduct>::_RhsNested _RhsNested;
+
+public:
+
+ template<typename Lhs, typename Rhs>
+ EIGEN_STRONG_INLINE SkylineProduct(const Lhs& lhs, const Rhs& rhs)
+ : m_lhs(lhs), m_rhs(rhs) {
+ eigen_assert(lhs.cols() == rhs.rows());
+
+ enum {
+ ProductIsValid = _LhsNested::ColsAtCompileTime == Dynamic
+ || _RhsNested::RowsAtCompileTime == Dynamic
+ || int(_LhsNested::ColsAtCompileTime) == int(_RhsNested::RowsAtCompileTime),
+ AreVectors = _LhsNested::IsVectorAtCompileTime && _RhsNested::IsVectorAtCompileTime,
+ SameSizes = EIGEN_PREDICATE_SAME_MATRIX_SIZE(_LhsNested, _RhsNested)
+ };
+ // note to the lost user:
+ // * for a dot product use: v1.dot(v2)
+ // * for a coeff-wise product use: v1.cwise()*v2
+ EIGEN_STATIC_ASSERT(ProductIsValid || !(AreVectors && SameSizes),
+ INVALID_VECTOR_VECTOR_PRODUCT__IF_YOU_WANTED_A_DOT_OR_COEFF_WISE_PRODUCT_YOU_MUST_USE_THE_EXPLICIT_FUNCTIONS)
+ EIGEN_STATIC_ASSERT(ProductIsValid || !(SameSizes && !AreVectors),
+ INVALID_MATRIX_PRODUCT__IF_YOU_WANTED_A_COEFF_WISE_PRODUCT_YOU_MUST_USE_THE_EXPLICIT_FUNCTION)
+ EIGEN_STATIC_ASSERT(ProductIsValid || SameSizes, INVALID_MATRIX_PRODUCT)
+ }
+
+ EIGEN_STRONG_INLINE Index rows() const {
+ return m_lhs.rows();
+ }
+
+ EIGEN_STRONG_INLINE Index cols() const {
+ return m_rhs.cols();
+ }
+
+ EIGEN_STRONG_INLINE const _LhsNested& lhs() const {
+ return m_lhs;
+ }
+
+ EIGEN_STRONG_INLINE const _RhsNested& rhs() const {
+ return m_rhs;
+ }
+
+protected:
+ LhsNested m_lhs;
+ RhsNested m_rhs;
+};
+
+// dense = skyline * dense
+// Note that here we force no inlining and separate the setZero() because GCC messes up otherwise
+
+template<typename Lhs, typename Rhs, typename Dest>
+EIGEN_DONT_INLINE void skyline_row_major_time_dense_product(const Lhs& lhs, const Rhs& rhs, Dest& dst) {
+ typedef typename remove_all<Lhs>::type _Lhs;
+ typedef typename remove_all<Rhs>::type _Rhs;
+ typedef typename traits<Lhs>::Scalar Scalar;
+
+ enum {
+ LhsIsRowMajor = (_Lhs::Flags & RowMajorBit) == RowMajorBit,
+ LhsIsSelfAdjoint = (_Lhs::Flags & SelfAdjointBit) == SelfAdjointBit,
+ ProcessFirstHalf = LhsIsSelfAdjoint
+ && (((_Lhs::Flags & (UpperTriangularBit | LowerTriangularBit)) == 0)
+ || ((_Lhs::Flags & UpperTriangularBit) && !LhsIsRowMajor)
+ || ((_Lhs::Flags & LowerTriangularBit) && LhsIsRowMajor)),
+ ProcessSecondHalf = LhsIsSelfAdjoint && (!ProcessFirstHalf)
+ };
+
+ //Use matrix diagonal part <- Improvement : use inner iterator on dense matrix.
+ for (Index col = 0; col < rhs.cols(); col++) {
+ for (Index row = 0; row < lhs.rows(); row++) {
+ dst(row, col) = lhs.coeffDiag(row) * rhs(row, col);
+ }
+ }
+ //Use matrix lower triangular part
+ for (Index row = 0; row < lhs.rows(); row++) {
+ typename _Lhs::InnerLowerIterator lIt(lhs, row);
+ const Index stop = lIt.col() + lIt.size();
+ for (Index col = 0; col < rhs.cols(); col++) {
+
+ Index k = lIt.col();
+ Scalar tmp = 0;
+ while (k < stop) {
+ tmp +=
+ lIt.value() *
+ rhs(k++, col);
+ ++lIt;
+ }
+ dst(row, col) += tmp;
+ lIt += -lIt.size();
+ }
+
+ }
+
+ //Use matrix upper triangular part
+ for (Index lhscol = 0; lhscol < lhs.cols(); lhscol++) {
+ typename _Lhs::InnerUpperIterator uIt(lhs, lhscol);
+ const Index stop = uIt.size() + uIt.row();
+ for (Index rhscol = 0; rhscol < rhs.cols(); rhscol++) {
+
+
+ const Scalar rhsCoeff = rhs.coeff(lhscol, rhscol);
+ Index k = uIt.row();
+ while (k < stop) {
+ dst(k++, rhscol) +=
+ uIt.value() *
+ rhsCoeff;
+ ++uIt;
+ }
+ uIt += -uIt.size();
+ }
+ }
+
+}
+
+template<typename Lhs, typename Rhs, typename Dest>
+EIGEN_DONT_INLINE void skyline_col_major_time_dense_product(const Lhs& lhs, const Rhs& rhs, Dest& dst) {
+ typedef typename remove_all<Lhs>::type _Lhs;
+ typedef typename remove_all<Rhs>::type _Rhs;
+ typedef typename traits<Lhs>::Scalar Scalar;
+
+ enum {
+ LhsIsRowMajor = (_Lhs::Flags & RowMajorBit) == RowMajorBit,
+ LhsIsSelfAdjoint = (_Lhs::Flags & SelfAdjointBit) == SelfAdjointBit,
+ ProcessFirstHalf = LhsIsSelfAdjoint
+ && (((_Lhs::Flags & (UpperTriangularBit | LowerTriangularBit)) == 0)
+ || ((_Lhs::Flags & UpperTriangularBit) && !LhsIsRowMajor)
+ || ((_Lhs::Flags & LowerTriangularBit) && LhsIsRowMajor)),
+ ProcessSecondHalf = LhsIsSelfAdjoint && (!ProcessFirstHalf)
+ };
+
+ //Use matrix diagonal part <- Improvement : use inner iterator on dense matrix.
+ for (Index col = 0; col < rhs.cols(); col++) {
+ for (Index row = 0; row < lhs.rows(); row++) {
+ dst(row, col) = lhs.coeffDiag(row) * rhs(row, col);
+ }
+ }
+
+ //Use matrix upper triangular part
+ for (Index row = 0; row < lhs.rows(); row++) {
+ typename _Lhs::InnerUpperIterator uIt(lhs, row);
+ const Index stop = uIt.col() + uIt.size();
+ for (Index col = 0; col < rhs.cols(); col++) {
+
+ Index k = uIt.col();
+ Scalar tmp = 0;
+ while (k < stop) {
+ tmp +=
+ uIt.value() *
+ rhs(k++, col);
+ ++uIt;
+ }
+
+
+ dst(row, col) += tmp;
+ uIt += -uIt.size();
+ }
+ }
+
+ //Use matrix lower triangular part
+ for (Index lhscol = 0; lhscol < lhs.cols(); lhscol++) {
+ typename _Lhs::InnerLowerIterator lIt(lhs, lhscol);
+ const Index stop = lIt.size() + lIt.row();
+ for (Index rhscol = 0; rhscol < rhs.cols(); rhscol++) {
+
+ const Scalar rhsCoeff = rhs.coeff(lhscol, rhscol);
+ Index k = lIt.row();
+ while (k < stop) {
+ dst(k++, rhscol) +=
+ lIt.value() *
+ rhsCoeff;
+ ++lIt;
+ }
+ lIt += -lIt.size();
+ }
+ }
+
+}
+
+template<typename Lhs, typename Rhs, typename ResultType,
+ int LhsStorageOrder = traits<Lhs>::Flags&RowMajorBit>
+ struct skyline_product_selector;
+
+template<typename Lhs, typename Rhs, typename ResultType>
+struct skyline_product_selector<Lhs, Rhs, ResultType, RowMajor> {
+ typedef typename traits<typename remove_all<Lhs>::type>::Scalar Scalar;
+
+ static void run(const Lhs& lhs, const Rhs& rhs, ResultType & res) {
+ skyline_row_major_time_dense_product<Lhs, Rhs, ResultType > (lhs, rhs, res);
+ }
+};
+
+template<typename Lhs, typename Rhs, typename ResultType>
+struct skyline_product_selector<Lhs, Rhs, ResultType, ColMajor> {
+ typedef typename traits<typename remove_all<Lhs>::type>::Scalar Scalar;
+
+ static void run(const Lhs& lhs, const Rhs& rhs, ResultType & res) {
+ skyline_col_major_time_dense_product<Lhs, Rhs, ResultType > (lhs, rhs, res);
+ }
+};
+
+} // end namespace internal
+
+// template<typename Derived>
+// template<typename Lhs, typename Rhs >
+// Derived & MatrixBase<Derived>::lazyAssign(const SkylineProduct<Lhs, Rhs, SkylineTimeDenseProduct>& product) {
+// typedef typename internal::remove_all<Lhs>::type _Lhs;
+// internal::skyline_product_selector<typename internal::remove_all<Lhs>::type,
+// typename internal::remove_all<Rhs>::type,
+// Derived>::run(product.lhs(), product.rhs(), derived());
+//
+// return derived();
+// }
+
+// skyline * dense
+
+template<typename Derived>
+template<typename OtherDerived >
+EIGEN_STRONG_INLINE const typename SkylineProductReturnType<Derived, OtherDerived>::Type
+SkylineMatrixBase<Derived>::operator*(const MatrixBase<OtherDerived> &other) const {
+
+ return typename SkylineProductReturnType<Derived, OtherDerived>::Type(derived(), other.derived());
+}
+
+} // end namespace Eigen
+
+#endif // EIGEN_SKYLINEPRODUCT_H
diff --git a/unsupported/Eigen/src/Skyline/SkylineStorage.h b/unsupported/Eigen/src/Skyline/SkylineStorage.h
new file mode 100644
index 000000000..378a8deb4
--- /dev/null
+++ b/unsupported/Eigen/src/Skyline/SkylineStorage.h
@@ -0,0 +1,259 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra.
+//
+// Copyright (C) 2008-2009 Guillaume Saupin <guillaume.saupin@cea.fr>
+//
+// This Source Code Form is subject to the terms of the Mozilla
+// Public License v. 2.0. If a copy of the MPL was not distributed
+// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+#ifndef EIGEN_SKYLINE_STORAGE_H
+#define EIGEN_SKYLINE_STORAGE_H
+
+namespace Eigen {
+
+/** Stores a skyline set of values in three structures :
+ * The diagonal elements
+ * The upper elements
+ * The lower elements
+ *
+ */
+template<typename Scalar>
+class SkylineStorage {
+ typedef typename NumTraits<Scalar>::Real RealScalar;
+ typedef SparseIndex Index;
+public:
+
+ SkylineStorage()
+ : m_diag(0),
+ m_lower(0),
+ m_upper(0),
+ m_lowerProfile(0),
+ m_upperProfile(0),
+ m_diagSize(0),
+ m_upperSize(0),
+ m_lowerSize(0),
+ m_upperProfileSize(0),
+ m_lowerProfileSize(0),
+ m_allocatedSize(0) {
+ }
+
+ SkylineStorage(const SkylineStorage& other)
+ : m_diag(0),
+ m_lower(0),
+ m_upper(0),
+ m_lowerProfile(0),
+ m_upperProfile(0),
+ m_diagSize(0),
+ m_upperSize(0),
+ m_lowerSize(0),
+ m_upperProfileSize(0),
+ m_lowerProfileSize(0),
+ m_allocatedSize(0) {
+ *this = other;
+ }
+
+ SkylineStorage & operator=(const SkylineStorage& other) {
+ resize(other.diagSize(), other.m_upperProfileSize, other.m_lowerProfileSize, other.upperSize(), other.lowerSize());
+ memcpy(m_diag, other.m_diag, m_diagSize * sizeof (Scalar));
+ memcpy(m_upper, other.m_upper, other.upperSize() * sizeof (Scalar));
+ memcpy(m_lower, other.m_lower, other.lowerSize() * sizeof (Scalar));
+ memcpy(m_upperProfile, other.m_upperProfile, m_upperProfileSize * sizeof (Index));
+ memcpy(m_lowerProfile, other.m_lowerProfile, m_lowerProfileSize * sizeof (Index));
+ return *this;
+ }
+
+ void swap(SkylineStorage& other) {
+ std::swap(m_diag, other.m_diag);
+ std::swap(m_upper, other.m_upper);
+ std::swap(m_lower, other.m_lower);
+ std::swap(m_upperProfile, other.m_upperProfile);
+ std::swap(m_lowerProfile, other.m_lowerProfile);
+ std::swap(m_diagSize, other.m_diagSize);
+ std::swap(m_upperSize, other.m_upperSize);
+ std::swap(m_lowerSize, other.m_lowerSize);
+ std::swap(m_allocatedSize, other.m_allocatedSize);
+ }
+
+ ~SkylineStorage() {
+ delete[] m_diag;
+ delete[] m_upper;
+ if (m_upper != m_lower)
+ delete[] m_lower;
+ delete[] m_upperProfile;
+ delete[] m_lowerProfile;
+ }
+
+ void reserve(Index size, Index upperProfileSize, Index lowerProfileSize, Index upperSize, Index lowerSize) {
+ Index newAllocatedSize = size + upperSize + lowerSize;
+ if (newAllocatedSize > m_allocatedSize)
+ reallocate(size, upperProfileSize, lowerProfileSize, upperSize, lowerSize);
+ }
+
+ void squeeze() {
+ if (m_allocatedSize > m_diagSize + m_upperSize + m_lowerSize)
+ reallocate(m_diagSize, m_upperProfileSize, m_lowerProfileSize, m_upperSize, m_lowerSize);
+ }
+
+ void resize(Index diagSize, Index upperProfileSize, Index lowerProfileSize, Index upperSize, Index lowerSize, float reserveSizeFactor = 0) {
+ if (m_allocatedSize < diagSize + upperSize + lowerSize)
+ reallocate(diagSize, upperProfileSize, lowerProfileSize, upperSize + Index(reserveSizeFactor * upperSize), lowerSize + Index(reserveSizeFactor * lowerSize));
+ m_diagSize = diagSize;
+ m_upperSize = upperSize;
+ m_lowerSize = lowerSize;
+ m_upperProfileSize = upperProfileSize;
+ m_lowerProfileSize = lowerProfileSize;
+ }
+
+ inline Index diagSize() const {
+ return m_diagSize;
+ }
+
+ inline Index upperSize() const {
+ return m_upperSize;
+ }
+
+ inline Index lowerSize() const {
+ return m_lowerSize;
+ }
+
+ inline Index upperProfileSize() const {
+ return m_upperProfileSize;
+ }
+
+ inline Index lowerProfileSize() const {
+ return m_lowerProfileSize;
+ }
+
+ inline Index allocatedSize() const {
+ return m_allocatedSize;
+ }
+
+ inline void clear() {
+ m_diagSize = 0;
+ }
+
+ inline Scalar& diag(Index i) {
+ return m_diag[i];
+ }
+
+ inline const Scalar& diag(Index i) const {
+ return m_diag[i];
+ }
+
+ inline Scalar& upper(Index i) {
+ return m_upper[i];
+ }
+
+ inline const Scalar& upper(Index i) const {
+ return m_upper[i];
+ }
+
+ inline Scalar& lower(Index i) {
+ return m_lower[i];
+ }
+
+ inline const Scalar& lower(Index i) const {
+ return m_lower[i];
+ }
+
+ inline Index& upperProfile(Index i) {
+ return m_upperProfile[i];
+ }
+
+ inline const Index& upperProfile(Index i) const {
+ return m_upperProfile[i];
+ }
+
+ inline Index& lowerProfile(Index i) {
+ return m_lowerProfile[i];
+ }
+
+ inline const Index& lowerProfile(Index i) const {
+ return m_lowerProfile[i];
+ }
+
+ static SkylineStorage Map(Index* upperProfile, Index* lowerProfile, Scalar* diag, Scalar* upper, Scalar* lower, Index size, Index upperSize, Index lowerSize) {
+ SkylineStorage res;
+ res.m_upperProfile = upperProfile;
+ res.m_lowerProfile = lowerProfile;
+ res.m_diag = diag;
+ res.m_upper = upper;
+ res.m_lower = lower;
+ res.m_allocatedSize = res.m_diagSize = size;
+ res.m_upperSize = upperSize;
+ res.m_lowerSize = lowerSize;
+ return res;
+ }
+
+ inline void reset() {
+ memset(m_diag, 0, m_diagSize * sizeof (Scalar));
+ memset(m_upper, 0, m_upperSize * sizeof (Scalar));
+ memset(m_lower, 0, m_lowerSize * sizeof (Scalar));
+ memset(m_upperProfile, 0, m_diagSize * sizeof (Index));
+ memset(m_lowerProfile, 0, m_diagSize * sizeof (Index));
+ }
+
+ void prune(Scalar reference, RealScalar epsilon = dummy_precision<RealScalar>()) {
+ //TODO
+ }
+
+protected:
+
+ inline void reallocate(Index diagSize, Index upperProfileSize, Index lowerProfileSize, Index upperSize, Index lowerSize) {
+
+ Scalar* diag = new Scalar[diagSize];
+ Scalar* upper = new Scalar[upperSize];
+ Scalar* lower = new Scalar[lowerSize];
+ Index* upperProfile = new Index[upperProfileSize];
+ Index* lowerProfile = new Index[lowerProfileSize];
+
+ Index copyDiagSize = (std::min)(diagSize, m_diagSize);
+ Index copyUpperSize = (std::min)(upperSize, m_upperSize);
+ Index copyLowerSize = (std::min)(lowerSize, m_lowerSize);
+ Index copyUpperProfileSize = (std::min)(upperProfileSize, m_upperProfileSize);
+ Index copyLowerProfileSize = (std::min)(lowerProfileSize, m_lowerProfileSize);
+
+ // copy
+ memcpy(diag, m_diag, copyDiagSize * sizeof (Scalar));
+ memcpy(upper, m_upper, copyUpperSize * sizeof (Scalar));
+ memcpy(lower, m_lower, copyLowerSize * sizeof (Scalar));
+ memcpy(upperProfile, m_upperProfile, copyUpperProfileSize * sizeof (Index));
+ memcpy(lowerProfile, m_lowerProfile, copyLowerProfileSize * sizeof (Index));
+
+
+
+ // delete old stuff
+ delete[] m_diag;
+ delete[] m_upper;
+ delete[] m_lower;
+ delete[] m_upperProfile;
+ delete[] m_lowerProfile;
+ m_diag = diag;
+ m_upper = upper;
+ m_lower = lower;
+ m_upperProfile = upperProfile;
+ m_lowerProfile = lowerProfile;
+ m_allocatedSize = diagSize + upperSize + lowerSize;
+ m_upperSize = upperSize;
+ m_lowerSize = lowerSize;
+ }
+
+public:
+ Scalar* m_diag;
+ Scalar* m_upper;
+ Scalar* m_lower;
+ Index* m_upperProfile;
+ Index* m_lowerProfile;
+ Index m_diagSize;
+ Index m_upperSize;
+ Index m_lowerSize;
+ Index m_upperProfileSize;
+ Index m_lowerProfileSize;
+ Index m_allocatedSize;
+
+};
+
+} // end namespace Eigen
+
+#endif // EIGEN_COMPRESSED_STORAGE_H
diff --git a/unsupported/Eigen/src/Skyline/SkylineUtil.h b/unsupported/Eigen/src/Skyline/SkylineUtil.h
new file mode 100644
index 000000000..75eb612f4
--- /dev/null
+++ b/unsupported/Eigen/src/Skyline/SkylineUtil.h
@@ -0,0 +1,89 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra.
+//
+// Copyright (C) 2009 Guillaume Saupin <guillaume.saupin@cea.fr>
+//
+// This Source Code Form is subject to the terms of the Mozilla
+// Public License v. 2.0. If a copy of the MPL was not distributed
+// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+#ifndef EIGEN_SKYLINEUTIL_H
+#define EIGEN_SKYLINEUTIL_H
+
+namespace Eigen {
+
+#ifdef NDEBUG
+#define EIGEN_DBG_SKYLINE(X)
+#else
+#define EIGEN_DBG_SKYLINE(X) X
+#endif
+
+const unsigned int SkylineBit = 0x1200;
+template<typename Lhs, typename Rhs, int ProductMode> class SkylineProduct;
+enum AdditionalProductEvaluationMode {SkylineTimeDenseProduct, SkylineTimeSkylineProduct, DenseTimeSkylineProduct};
+enum {IsSkyline = SkylineBit};
+
+
+#define EIGEN_SKYLINE_INHERIT_ASSIGNMENT_OPERATOR(Derived, Op) \
+template<typename OtherDerived> \
+EIGEN_STRONG_INLINE Derived& operator Op(const Eigen::SkylineMatrixBase<OtherDerived>& other) \
+{ \
+ return Base::operator Op(other.derived()); \
+} \
+EIGEN_STRONG_INLINE Derived& operator Op(const Derived& other) \
+{ \
+ return Base::operator Op(other); \
+}
+
+#define EIGEN_SKYLINE_INHERIT_SCALAR_ASSIGNMENT_OPERATOR(Derived, Op) \
+template<typename Other> \
+EIGEN_STRONG_INLINE Derived& operator Op(const Other& scalar) \
+{ \
+ return Base::operator Op(scalar); \
+}
+
+#define EIGEN_SKYLINE_INHERIT_ASSIGNMENT_OPERATORS(Derived) \
+ EIGEN_SKYLINE_INHERIT_ASSIGNMENT_OPERATOR(Derived, =) \
+ EIGEN_SKYLINE_INHERIT_ASSIGNMENT_OPERATOR(Derived, +=) \
+ EIGEN_SKYLINE_INHERIT_ASSIGNMENT_OPERATOR(Derived, -=) \
+ EIGEN_SKYLINE_INHERIT_SCALAR_ASSIGNMENT_OPERATOR(Derived, *=) \
+ EIGEN_SKYLINE_INHERIT_SCALAR_ASSIGNMENT_OPERATOR(Derived, /=)
+
+#define _EIGEN_SKYLINE_GENERIC_PUBLIC_INTERFACE(Derived, BaseClass) \
+ typedef BaseClass Base; \
+ typedef typename Eigen::internal::traits<Derived>::Scalar Scalar; \
+ typedef typename Eigen::NumTraits<Scalar>::Real RealScalar; \
+ typedef typename Eigen::internal::traits<Derived>::StorageKind StorageKind; \
+ typedef typename Eigen::internal::index<StorageKind>::type Index; \
+ enum { Flags = Eigen::internal::traits<Derived>::Flags, };
+
+#define EIGEN_SKYLINE_GENERIC_PUBLIC_INTERFACE(Derived) \
+ _EIGEN_SKYLINE_GENERIC_PUBLIC_INTERFACE(Derived, Eigen::SkylineMatrixBase<Derived>)
+
+template<typename Derived> class SkylineMatrixBase;
+template<typename _Scalar, int _Flags = 0> class SkylineMatrix;
+template<typename _Scalar, int _Flags = 0> class DynamicSkylineMatrix;
+template<typename _Scalar, int _Flags = 0> class SkylineVector;
+template<typename _Scalar, int _Flags = 0> class MappedSkylineMatrix;
+
+namespace internal {
+
+template<typename Lhs, typename Rhs> struct skyline_product_mode;
+template<typename Lhs, typename Rhs, int ProductMode = skyline_product_mode<Lhs,Rhs>::value> struct SkylineProductReturnType;
+
+template<typename T> class eval<T,IsSkyline>
+{
+ typedef typename traits<T>::Scalar _Scalar;
+ enum {
+ _Flags = traits<T>::Flags
+ };
+
+ public:
+ typedef SkylineMatrix<_Scalar, _Flags> type;
+};
+
+} // end namespace internal
+
+} // end namespace Eigen
+
+#endif // EIGEN_SKYLINEUTIL_H
diff --git a/unsupported/Eigen/src/SparseExtra/BlockOfDynamicSparseMatrix.h b/unsupported/Eigen/src/SparseExtra/BlockOfDynamicSparseMatrix.h
new file mode 100644
index 000000000..fd24a732d
--- /dev/null
+++ b/unsupported/Eigen/src/SparseExtra/BlockOfDynamicSparseMatrix.h
@@ -0,0 +1,114 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra.
+//
+// Copyright (C) 2008-2009 Gael Guennebaud <gael.guennebaud@inria.fr>
+//
+// This Source Code Form is subject to the terms of the Mozilla
+// Public License v. 2.0. If 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_BLOCKFORDYNAMICMATRIX_H
+#define EIGEN_SPARSE_BLOCKFORDYNAMICMATRIX_H
+
+namespace Eigen {
+
+/***************************************************************************
+* specialisation for DynamicSparseMatrix
+***************************************************************************/
+
+template<typename _Scalar, int _Options, typename _Index, int Size>
+class SparseInnerVectorSet<DynamicSparseMatrix<_Scalar, _Options, _Index>, Size>
+ : public SparseMatrixBase<SparseInnerVectorSet<DynamicSparseMatrix<_Scalar, _Options, _Index>, Size> >
+{
+ typedef DynamicSparseMatrix<_Scalar, _Options, _Index> MatrixType;
+ public:
+
+ enum { IsRowMajor = internal::traits<SparseInnerVectorSet>::IsRowMajor };
+
+ EIGEN_SPARSE_PUBLIC_INTERFACE(SparseInnerVectorSet)
+ class InnerIterator: public MatrixType::InnerIterator
+ {
+ public:
+ inline InnerIterator(const SparseInnerVectorSet& xpr, Index outer)
+ : MatrixType::InnerIterator(xpr.m_matrix, xpr.m_outerStart + outer), m_outer(outer)
+ {}
+ inline Index row() const { return IsRowMajor ? m_outer : this->index(); }
+ inline Index col() const { return IsRowMajor ? this->index() : m_outer; }
+ protected:
+ Index m_outer;
+ };
+
+ inline SparseInnerVectorSet(const MatrixType& matrix, Index outerStart, Index outerSize)
+ : m_matrix(matrix), m_outerStart(outerStart), m_outerSize(outerSize)
+ {
+ eigen_assert( (outerStart>=0) && ((outerStart+outerSize)<=matrix.outerSize()) );
+ }
+
+ inline SparseInnerVectorSet(const MatrixType& matrix, Index outer)
+ : m_matrix(matrix), m_outerStart(outer), m_outerSize(Size)
+ {
+ eigen_assert(Size!=Dynamic);
+ eigen_assert( (outer>=0) && (outer<matrix.outerSize()) );
+ }
+
+ template<typename OtherDerived>
+ inline SparseInnerVectorSet& operator=(const SparseMatrixBase<OtherDerived>& other)
+ {
+ if (IsRowMajor != ((OtherDerived::Flags&RowMajorBit)==RowMajorBit))
+ {
+ // need to transpose => perform a block evaluation followed by a big swap
+ DynamicSparseMatrix<Scalar,IsRowMajor?RowMajorBit:0> aux(other);
+ *this = aux.markAsRValue();
+ }
+ else
+ {
+ // evaluate/copy vector per vector
+ for (Index j=0; j<m_outerSize.value(); ++j)
+ {
+ SparseVector<Scalar,IsRowMajor ? RowMajorBit : 0> aux(other.innerVector(j));
+ m_matrix.const_cast_derived()._data()[m_outerStart+j].swap(aux._data());
+ }
+ }
+ return *this;
+ }
+
+ inline SparseInnerVectorSet& operator=(const SparseInnerVectorSet& other)
+ {
+ return operator=<SparseInnerVectorSet>(other);
+ }
+
+ Index nonZeros() const
+ {
+ Index count = 0;
+ for (Index j=0; j<m_outerSize.value(); ++j)
+ count += m_matrix._data()[m_outerStart+j].size();
+ return count;
+ }
+
+ const Scalar& lastCoeff() const
+ {
+ EIGEN_STATIC_ASSERT_VECTOR_ONLY(SparseInnerVectorSet);
+ eigen_assert(m_matrix.data()[m_outerStart].size()>0);
+ return m_matrix.data()[m_outerStart].vale(m_matrix.data()[m_outerStart].size()-1);
+ }
+
+// template<typename Sparse>
+// inline SparseInnerVectorSet& operator=(const SparseMatrixBase<OtherDerived>& other)
+// {
+// return *this;
+// }
+
+ EIGEN_STRONG_INLINE Index rows() const { return IsRowMajor ? m_outerSize.value() : m_matrix.rows(); }
+ EIGEN_STRONG_INLINE Index cols() const { return IsRowMajor ? m_matrix.cols() : m_outerSize.value(); }
+
+ protected:
+
+ const typename MatrixType::Nested m_matrix;
+ Index m_outerStart;
+ const internal::variable_if_dynamic<Index, Size> m_outerSize;
+
+};
+
+} // end namespace Eigen
+
+#endif // EIGEN_SPARSE_BLOCKFORDYNAMICMATRIX_H
diff --git a/unsupported/Eigen/src/SparseExtra/CMakeLists.txt b/unsupported/Eigen/src/SparseExtra/CMakeLists.txt
new file mode 100644
index 000000000..7ea32ca5e
--- /dev/null
+++ b/unsupported/Eigen/src/SparseExtra/CMakeLists.txt
@@ -0,0 +1,6 @@
+FILE(GLOB Eigen_SparseExtra_SRCS "*.h")
+
+INSTALL(FILES
+ ${Eigen_SparseExtra_SRCS}
+ DESTINATION ${INCLUDE_INSTALL_DIR}/unsupported/Eigen/src/SparseExtra COMPONENT Devel
+ )
diff --git a/unsupported/Eigen/src/SparseExtra/DynamicSparseMatrix.h b/unsupported/Eigen/src/SparseExtra/DynamicSparseMatrix.h
new file mode 100644
index 000000000..dec16df28
--- /dev/null
+++ b/unsupported/Eigen/src/SparseExtra/DynamicSparseMatrix.h
@@ -0,0 +1,357 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra.
+//
+// Copyright (C) 2008-2009 Gael Guennebaud <gael.guennebaud@inria.fr>
+//
+// This Source Code Form is subject to the terms of the Mozilla
+// Public License v. 2.0. If a copy of the MPL was not distributed
+// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+#ifndef EIGEN_DYNAMIC_SPARSEMATRIX_H
+#define EIGEN_DYNAMIC_SPARSEMATRIX_H
+
+namespace Eigen {
+
+/** \deprecated use a SparseMatrix in an uncompressed mode
+ *
+ * \class DynamicSparseMatrix
+ *
+ * \brief A sparse matrix class designed for matrix assembly purpose
+ *
+ * \param _Scalar the scalar type, i.e. the type of the coefficients
+ *
+ * Unlike SparseMatrix, this class provides a much higher degree of flexibility. In particular, it allows
+ * random read/write accesses in log(rho*outer_size) where \c rho is the probability that a coefficient is
+ * nonzero and outer_size is the number of columns if the matrix is column-major and the number of rows
+ * otherwise.
+ *
+ * Internally, the data are stored as a std::vector of compressed vector. The performances of random writes might
+ * decrease as the number of nonzeros per inner-vector increase. In practice, we observed very good performance
+ * till about 100 nonzeros/vector, and the performance remains relatively good till 500 nonzeros/vectors.
+ *
+ * \see SparseMatrix
+ */
+
+namespace internal {
+template<typename _Scalar, int _Options, typename _Index>
+struct traits<DynamicSparseMatrix<_Scalar, _Options, _Index> >
+{
+ typedef _Scalar Scalar;
+ typedef _Index Index;
+ typedef Sparse StorageKind;
+ typedef MatrixXpr XprKind;
+ enum {
+ RowsAtCompileTime = Dynamic,
+ ColsAtCompileTime = Dynamic,
+ MaxRowsAtCompileTime = Dynamic,
+ MaxColsAtCompileTime = Dynamic,
+ Flags = _Options | NestByRefBit | LvalueBit,
+ CoeffReadCost = NumTraits<Scalar>::ReadCost,
+ SupportedAccessPatterns = OuterRandomAccessPattern
+ };
+};
+}
+
+template<typename _Scalar, int _Options, typename _Index>
+ class DynamicSparseMatrix
+ : public SparseMatrixBase<DynamicSparseMatrix<_Scalar, _Options, _Index> >
+{
+ public:
+ EIGEN_SPARSE_PUBLIC_INTERFACE(DynamicSparseMatrix)
+ // FIXME: why are these operator already alvailable ???
+ // EIGEN_SPARSE_INHERIT_ASSIGNMENT_OPERATOR(DynamicSparseMatrix, +=)
+ // EIGEN_SPARSE_INHERIT_ASSIGNMENT_OPERATOR(DynamicSparseMatrix, -=)
+ typedef MappedSparseMatrix<Scalar,Flags> Map;
+ using Base::IsRowMajor;
+ using Base::operator=;
+ enum {
+ Options = _Options
+ };
+
+ protected:
+
+ typedef DynamicSparseMatrix<Scalar,(Flags&~RowMajorBit)|(IsRowMajor?RowMajorBit:0)> TransposedSparseMatrix;
+
+ Index m_innerSize;
+ std::vector<internal::CompressedStorage<Scalar,Index> > m_data;
+
+ public:
+
+ inline Index rows() const { return IsRowMajor ? outerSize() : m_innerSize; }
+ inline Index cols() const { return IsRowMajor ? m_innerSize : outerSize(); }
+ inline Index innerSize() const { return m_innerSize; }
+ inline Index outerSize() const { return static_cast<Index>(m_data.size()); }
+ inline Index innerNonZeros(Index j) const { return m_data[j].size(); }
+
+ std::vector<internal::CompressedStorage<Scalar,Index> >& _data() { return m_data; }
+ const std::vector<internal::CompressedStorage<Scalar,Index> >& _data() const { return m_data; }
+
+ /** \returns the coefficient value at given position \a row, \a col
+ * This operation involes a log(rho*outer_size) binary search.
+ */
+ inline Scalar coeff(Index row, Index col) const
+ {
+ const Index outer = IsRowMajor ? row : col;
+ const Index inner = IsRowMajor ? col : row;
+ return m_data[outer].at(inner);
+ }
+
+ /** \returns a reference to the coefficient value at given position \a row, \a col
+ * This operation involes a log(rho*outer_size) binary search. If the coefficient does not
+ * exist yet, then a sorted insertion into a sequential buffer is performed.
+ */
+ inline Scalar& coeffRef(Index row, Index col)
+ {
+ const Index outer = IsRowMajor ? row : col;
+ const Index inner = IsRowMajor ? col : row;
+ return m_data[outer].atWithInsertion(inner);
+ }
+
+ class InnerIterator;
+ class ReverseInnerIterator;
+
+ void setZero()
+ {
+ for (Index j=0; j<outerSize(); ++j)
+ m_data[j].clear();
+ }
+
+ /** \returns the number of non zero coefficients */
+ Index nonZeros() const
+ {
+ Index res = 0;
+ for (Index j=0; j<outerSize(); ++j)
+ res += static_cast<Index>(m_data[j].size());
+ return res;
+ }
+
+
+
+ void reserve(Index reserveSize = 1000)
+ {
+ if (outerSize()>0)
+ {
+ Index reserveSizePerVector = (std::max)(reserveSize/outerSize(),Index(4));
+ for (Index j=0; j<outerSize(); ++j)
+ {
+ m_data[j].reserve(reserveSizePerVector);
+ }
+ }
+ }
+
+ /** Does nothing: provided for compatibility with SparseMatrix */
+ inline void startVec(Index /*outer*/) {}
+
+ /** \returns a reference to the non zero coefficient at position \a row, \a col assuming that:
+ * - the nonzero does not already exist
+ * - the new coefficient is the last one of the given inner vector.
+ *
+ * \sa insert, insertBackByOuterInner */
+ inline Scalar& insertBack(Index row, Index col)
+ {
+ return insertBackByOuterInner(IsRowMajor?row:col, IsRowMajor?col:row);
+ }
+
+ /** \sa insertBack */
+ inline Scalar& insertBackByOuterInner(Index outer, Index inner)
+ {
+ eigen_assert(outer<Index(m_data.size()) && inner<m_innerSize && "out of range");
+ eigen_assert(((m_data[outer].size()==0) || (m_data[outer].index(m_data[outer].size()-1)<inner))
+ && "wrong sorted insertion");
+ m_data[outer].append(0, inner);
+ return m_data[outer].value(m_data[outer].size()-1);
+ }
+
+ inline Scalar& insert(Index row, Index col)
+ {
+ const Index outer = IsRowMajor ? row : col;
+ const Index inner = IsRowMajor ? col : row;
+
+ Index startId = 0;
+ Index id = static_cast<Index>(m_data[outer].size()) - 1;
+ m_data[outer].resize(id+2,1);
+
+ while ( (id >= startId) && (m_data[outer].index(id) > inner) )
+ {
+ m_data[outer].index(id+1) = m_data[outer].index(id);
+ m_data[outer].value(id+1) = m_data[outer].value(id);
+ --id;
+ }
+ m_data[outer].index(id+1) = inner;
+ m_data[outer].value(id+1) = 0;
+ return m_data[outer].value(id+1);
+ }
+
+ /** Does nothing: provided for compatibility with SparseMatrix */
+ inline void finalize() {}
+
+ /** Suppress all nonzeros which are smaller than \a reference under the tolerence \a epsilon */
+ void prune(Scalar reference, RealScalar epsilon = NumTraits<RealScalar>::dummy_precision())
+ {
+ for (Index j=0; j<outerSize(); ++j)
+ m_data[j].prune(reference,epsilon);
+ }
+
+ /** Resize the matrix without preserving the data (the matrix is set to zero)
+ */
+ void resize(Index rows, Index cols)
+ {
+ const Index outerSize = IsRowMajor ? rows : cols;
+ m_innerSize = IsRowMajor ? cols : rows;
+ setZero();
+ if (Index(m_data.size()) != outerSize)
+ {
+ m_data.resize(outerSize);
+ }
+ }
+
+ void resizeAndKeepData(Index rows, Index cols)
+ {
+ const Index outerSize = IsRowMajor ? rows : cols;
+ const Index innerSize = IsRowMajor ? cols : rows;
+ if (m_innerSize>innerSize)
+ {
+ // remove all coefficients with innerCoord>=innerSize
+ // TODO
+ //std::cerr << "not implemented yet\n";
+ exit(2);
+ }
+ if (m_data.size() != outerSize)
+ {
+ m_data.resize(outerSize);
+ }
+ }
+
+ /** The class DynamicSparseMatrix is deprectaed */
+ EIGEN_DEPRECATED inline DynamicSparseMatrix()
+ : m_innerSize(0), m_data(0)
+ {
+ eigen_assert(innerSize()==0 && outerSize()==0);
+ }
+
+ /** The class DynamicSparseMatrix is deprectaed */
+ EIGEN_DEPRECATED inline DynamicSparseMatrix(Index rows, Index cols)
+ : m_innerSize(0)
+ {
+ resize(rows, cols);
+ }
+
+ /** The class DynamicSparseMatrix is deprectaed */
+ template<typename OtherDerived>
+ EIGEN_DEPRECATED explicit inline DynamicSparseMatrix(const SparseMatrixBase<OtherDerived>& other)
+ : m_innerSize(0)
+ {
+ Base::operator=(other.derived());
+ }
+
+ inline DynamicSparseMatrix(const DynamicSparseMatrix& other)
+ : Base(), m_innerSize(0)
+ {
+ *this = other.derived();
+ }
+
+ inline void swap(DynamicSparseMatrix& other)
+ {
+ //EIGEN_DBG_SPARSE(std::cout << "SparseMatrix:: swap\n");
+ std::swap(m_innerSize, other.m_innerSize);
+ //std::swap(m_outerSize, other.m_outerSize);
+ m_data.swap(other.m_data);
+ }
+
+ inline DynamicSparseMatrix& operator=(const DynamicSparseMatrix& other)
+ {
+ if (other.isRValue())
+ {
+ swap(other.const_cast_derived());
+ }
+ else
+ {
+ resize(other.rows(), other.cols());
+ m_data = other.m_data;
+ }
+ return *this;
+ }
+
+ /** Destructor */
+ inline ~DynamicSparseMatrix() {}
+
+ public:
+
+ /** \deprecated
+ * Set the matrix to zero and reserve the memory for \a reserveSize nonzero coefficients. */
+ EIGEN_DEPRECATED void startFill(Index reserveSize = 1000)
+ {
+ setZero();
+ reserve(reserveSize);
+ }
+
+ /** \deprecated use insert()
+ * inserts a nonzero coefficient at given coordinates \a row, \a col and returns its reference assuming that:
+ * 1 - the coefficient does not exist yet
+ * 2 - this the coefficient with greater inner coordinate for the given outer coordinate.
+ * In other words, assuming \c *this is column-major, then there must not exists any nonzero coefficient of coordinates
+ * \c i \c x \a col such that \c i >= \a row. Otherwise the matrix is invalid.
+ *
+ * \see fillrand(), coeffRef()
+ */
+ EIGEN_DEPRECATED Scalar& fill(Index row, Index col)
+ {
+ const Index outer = IsRowMajor ? row : col;
+ const Index inner = IsRowMajor ? col : row;
+ return insertBack(outer,inner);
+ }
+
+ /** \deprecated use insert()
+ * Like fill() but with random inner coordinates.
+ * Compared to the generic coeffRef(), the unique limitation is that we assume
+ * the coefficient does not exist yet.
+ */
+ EIGEN_DEPRECATED Scalar& fillrand(Index row, Index col)
+ {
+ return insert(row,col);
+ }
+
+ /** \deprecated use finalize()
+ * Does nothing. Provided for compatibility with SparseMatrix. */
+ EIGEN_DEPRECATED void endFill() {}
+
+# ifdef EIGEN_DYNAMICSPARSEMATRIX_PLUGIN
+# include EIGEN_DYNAMICSPARSEMATRIX_PLUGIN
+# endif
+ };
+
+template<typename Scalar, int _Options, typename _Index>
+class DynamicSparseMatrix<Scalar,_Options,_Index>::InnerIterator : public SparseVector<Scalar,_Options,_Index>::InnerIterator
+{
+ typedef typename SparseVector<Scalar,_Options,_Index>::InnerIterator Base;
+ public:
+ InnerIterator(const DynamicSparseMatrix& mat, Index outer)
+ : Base(mat.m_data[outer]), m_outer(outer)
+ {}
+
+ inline Index row() const { return IsRowMajor ? m_outer : Base::index(); }
+ inline Index col() const { return IsRowMajor ? Base::index() : m_outer; }
+
+ protected:
+ const Index m_outer;
+};
+
+template<typename Scalar, int _Options, typename _Index>
+class DynamicSparseMatrix<Scalar,_Options,_Index>::ReverseInnerIterator : public SparseVector<Scalar,_Options,_Index>::ReverseInnerIterator
+{
+ typedef typename SparseVector<Scalar,_Options,_Index>::ReverseInnerIterator Base;
+ public:
+ ReverseInnerIterator(const DynamicSparseMatrix& mat, Index outer)
+ : Base(mat.m_data[outer]), m_outer(outer)
+ {}
+
+ inline Index row() const { return IsRowMajor ? m_outer : Base::index(); }
+ inline Index col() const { return IsRowMajor ? Base::index() : m_outer; }
+
+ protected:
+ const Index m_outer;
+};
+
+} // end namespace Eigen
+
+#endif // EIGEN_DYNAMIC_SPARSEMATRIX_H
diff --git a/unsupported/Eigen/src/SparseExtra/MarketIO.h b/unsupported/Eigen/src/SparseExtra/MarketIO.h
new file mode 100644
index 000000000..de958de9f
--- /dev/null
+++ b/unsupported/Eigen/src/SparseExtra/MarketIO.h
@@ -0,0 +1,273 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra.
+//
+// Copyright (C) 2011 Gael Guennebaud <gael.guennebaud@inria.fr>
+// Copyright (C) 2012 Desire NUENTSA WAKAM <desire.nuentsa_wakam@inria.fr>
+//
+// This Source Code Form is subject to the terms of the Mozilla
+// Public License v. 2.0. If 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_MARKET_IO_H
+#define EIGEN_SPARSE_MARKET_IO_H
+
+#include <iostream>
+
+namespace Eigen {
+
+namespace internal
+{
+ template <typename Scalar>
+ inline bool GetMarketLine (std::stringstream& line, int& M, int& N, int& i, int& j, Scalar& value)
+ {
+ line >> i >> j >> value;
+ i--;
+ j--;
+ if(i>=0 && j>=0 && i<M && j<N)
+ {
+ return true;
+ }
+ else
+ return false;
+ }
+ template <typename Scalar>
+ inline bool GetMarketLine (std::stringstream& line, int& M, int& N, int& i, int& j, std::complex<Scalar>& value)
+ {
+ Scalar valR, valI;
+ line >> i >> j >> valR >> valI;
+ i--;
+ j--;
+ if(i>=0 && j>=0 && i<M && j<N)
+ {
+ value = std::complex<Scalar>(valR, valI);
+ return true;
+ }
+ else
+ return false;
+ }
+
+ template <typename RealScalar>
+ inline void GetVectorElt (const std::string& line, RealScalar& val)
+ {
+ std::istringstream newline(line);
+ newline >> val;
+ }
+
+ template <typename RealScalar>
+ inline void GetVectorElt (const std::string& line, std::complex<RealScalar>& val)
+ {
+ RealScalar valR, valI;
+ std::istringstream newline(line);
+ newline >> valR >> valI;
+ val = std::complex<RealScalar>(valR, valI);
+ }
+
+ template<typename Scalar>
+ inline void putMarketHeader(std::string& header,int sym)
+ {
+ header= "%%MatrixMarket matrix coordinate ";
+ if(internal::is_same<Scalar, std::complex<float> >::value || internal::is_same<Scalar, std::complex<double> >::value)
+ {
+ header += " complex";
+ if(sym == Symmetric) header += " symmetric";
+ else if (sym == SelfAdjoint) header += " Hermitian";
+ else header += " general";
+ }
+ else
+ {
+ header += " real";
+ if(sym == Symmetric) header += " symmetric";
+ else header += " general";
+ }
+ }
+
+ template<typename Scalar>
+ inline void PutMatrixElt(Scalar value, int row, int col, std::ofstream& out)
+ {
+ out << row << " "<< col << " " << value << "\n";
+ }
+ template<typename Scalar>
+ inline void PutMatrixElt(std::complex<Scalar> value, int row, int col, std::ofstream& out)
+ {
+ out << row << " " << col << " " << value.real() << " " << value.imag() << "\n";
+ }
+
+
+ template<typename Scalar>
+ inline void putVectorElt(Scalar value, std::ofstream& out)
+ {
+ out << value << "\n";
+ }
+ template<typename Scalar>
+ inline void putVectorElt(std::complex<Scalar> value, std::ofstream& out)
+ {
+ out << value.real << " " << value.imag()<< "\n";
+ }
+
+} // end namepsace internal
+
+inline bool getMarketHeader(const std::string& filename, int& sym, bool& iscomplex, bool& isvector)
+{
+ sym = 0;
+ isvector = false;
+ std::ifstream in(filename.c_str(),std::ios::in);
+ if(!in)
+ return false;
+
+ std::string line;
+ // The matrix header is always the first line in the file
+ std::getline(in, line); assert(in.good());
+
+ std::stringstream fmtline(line);
+ std::string substr[5];
+ fmtline>> substr[0] >> substr[1] >> substr[2] >> substr[3] >> substr[4];
+ if(substr[2].compare("array") == 0) isvector = true;
+ if(substr[3].compare("complex") == 0) iscomplex = true;
+ if(substr[4].compare("symmetric") == 0) sym = Symmetric;
+ else if (substr[4].compare("Hermitian") == 0) sym = SelfAdjoint;
+
+ return true;
+}
+
+template<typename SparseMatrixType>
+bool loadMarket(SparseMatrixType& mat, const std::string& filename)
+{
+ typedef typename SparseMatrixType::Scalar Scalar;
+ std::ifstream input(filename.c_str(),std::ios::in);
+ if(!input)
+ return false;
+
+ const int maxBuffersize = 2048;
+ char buffer[maxBuffersize];
+
+ bool readsizes = false;
+
+ typedef Triplet<Scalar,int> T;
+ std::vector<T> elements;
+
+ int M(-1), N(-1), NNZ(-1);
+ int count = 0;
+ while(input.getline(buffer, maxBuffersize))
+ {
+ // skip comments
+ //NOTE An appropriate test should be done on the header to get the symmetry
+ if(buffer[0]=='%')
+ continue;
+
+ std::stringstream line(buffer);
+
+ if(!readsizes)
+ {
+ line >> M >> N >> NNZ;
+ if(M > 0 && N > 0 && NNZ > 0)
+ {
+ readsizes = true;
+ std::cout << "sizes: " << M << "," << N << "," << NNZ << "\n";
+ mat.resize(M,N);
+ mat.reserve(NNZ);
+ }
+ }
+ else
+ {
+ int i(-1), j(-1);
+ Scalar value;
+ if( internal::GetMarketLine(line, M, N, i, j, value) )
+ {
+ ++ count;
+ elements.push_back(T(i,j,value));
+ }
+ else
+ std::cerr << "Invalid read: " << i << "," << j << "\n";
+ }
+ }
+ mat.setFromTriplets(elements.begin(), elements.end());
+ if(count!=NNZ)
+ std::cerr << count << "!=" << NNZ << "\n";
+
+ input.close();
+ return true;
+}
+
+template<typename VectorType>
+bool loadMarketVector(VectorType& vec, const std::string& filename)
+{
+ typedef typename VectorType::Scalar Scalar;
+ std::ifstream in(filename.c_str(), std::ios::in);
+ if(!in)
+ return false;
+
+ std::string line;
+ int n(0), col(0);
+ do
+ { // Skip comments
+ std::getline(in, line); assert(in.good());
+ } while (line[0] == '%');
+ std::istringstream newline(line);
+ newline >> n >> col;
+ assert(n>0 && col>0);
+ vec.resize(n);
+ int i = 0;
+ Scalar value;
+ while ( std::getline(in, line) && (i < n) ){
+ internal::GetVectorElt(line, value);
+ vec(i++) = value;
+ }
+ in.close();
+ if (i!=n){
+ std::cerr<< "Unable to read all elements from file " << filename << "\n";
+ return false;
+ }
+ return true;
+}
+
+template<typename SparseMatrixType>
+bool saveMarket(const SparseMatrixType& mat, const std::string& filename, int sym = 0)
+{
+ typedef typename SparseMatrixType::Scalar Scalar;
+ std::ofstream out(filename.c_str(),std::ios::out);
+ if(!out)
+ return false;
+
+ out.flags(std::ios_base::scientific);
+ out.precision(64);
+ std::string header;
+ internal::putMarketHeader<Scalar>(header, sym);
+ out << header << std::endl;
+ out << mat.rows() << " " << mat.cols() << " " << mat.nonZeros() << "\n";
+ int count = 0;
+ for(int j=0; j<mat.outerSize(); ++j)
+ for(typename SparseMatrixType::InnerIterator it(mat,j); it; ++it)
+ {
+ ++ count;
+ internal::PutMatrixElt(it.value(), it.row()+1, it.col()+1, out);
+ // out << it.row()+1 << " " << it.col()+1 << " " << it.value() << "\n";
+ }
+ out.close();
+ return true;
+}
+
+template<typename VectorType>
+bool saveMarketVector (const VectorType& vec, const std::string& filename)
+{
+ typedef typename VectorType::Scalar Scalar;
+ std::ofstream out(filename.c_str(),std::ios::out);
+ if(!out)
+ return false;
+
+ out.flags(std::ios_base::scientific);
+ out.precision(64);
+ if(internal::is_same<Scalar, std::complex<float> >::value || internal::is_same<Scalar, std::complex<double> >::value)
+ out << "%%MatrixMarket matrix array complex general\n";
+ else
+ out << "%%MatrixMarket matrix array real general\n";
+ out << vec.size() << " "<< 1 << "\n";
+ for (int i=0; i < vec.size(); i++){
+ internal::putVectorElt(vec(i), out);
+ }
+ out.close();
+ return true;
+}
+
+} // end namespace Eigen
+
+#endif // EIGEN_SPARSE_MARKET_IO_H
diff --git a/unsupported/Eigen/src/SparseExtra/MatrixMarketIterator.h b/unsupported/Eigen/src/SparseExtra/MatrixMarketIterator.h
new file mode 100644
index 000000000..4716b68e7
--- /dev/null
+++ b/unsupported/Eigen/src/SparseExtra/MatrixMarketIterator.h
@@ -0,0 +1,221 @@
+
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra.
+//
+// Copyright (C) 2012 Desire NUENTSA WAKAM <desire.nuentsa_wakam@inria.fr>
+//
+// This Source Code Form is subject to the terms of the Mozilla
+// Public License v. 2.0. If a copy of the MPL was not distributed
+// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+#ifndef EIGEN_BROWSE_MATRICES_H
+#define EIGEN_BROWSE_MATRICES_H
+
+namespace Eigen {
+
+enum {
+ SPD = 0x100,
+ NonSymmetric = 0x0
+};
+
+/**
+ * @brief Iterator to browse matrices from a specified folder
+ *
+ * This is used to load all the matrices from a folder.
+ * The matrices should be in Matrix Market format
+ * It is assumed that the matrices are named as matname.mtx
+ * and matname_SPD.mtx if the matrix is Symmetric and positive definite (or Hermitian)
+ * The right hand side vectors are loaded as well, if they exist.
+ * They should be named as matname_b.mtx.
+ * Note that the right hand side for a SPD matrix is named as matname_SPD_b.mtx
+ *
+ * Sometimes a reference solution is available. In this case, it should be named as matname_x.mtx
+ *
+ * Sample code
+ * \code
+ *
+ * \endcode
+ *
+ * \tparam Scalar The scalar type
+ */
+template <typename Scalar>
+class MatrixMarketIterator
+{
+ public:
+ typedef Matrix<Scalar,Dynamic,1> VectorType;
+ typedef SparseMatrix<Scalar,ColMajor> MatrixType;
+
+ public:
+ MatrixMarketIterator(const std::string folder):m_sym(0),m_isvalid(false),m_matIsLoaded(false),m_hasRhs(false),m_hasrefX(false),m_folder(folder)
+ {
+ m_folder_id = opendir(folder.c_str());
+ if (!m_folder_id){
+ m_isvalid = false;
+ std::cerr << "The provided Matrix folder could not be opened \n\n";
+ abort();
+ }
+ Getnextvalidmatrix();
+ }
+
+ ~MatrixMarketIterator()
+ {
+ if (m_folder_id) closedir(m_folder_id);
+ }
+
+ inline MatrixMarketIterator& operator++()
+ {
+ m_matIsLoaded = false;
+ m_hasrefX = false;
+ m_hasRhs = false;
+ Getnextvalidmatrix();
+ return *this;
+ }
+ inline operator bool() const { return m_isvalid;}
+
+ /** Return the sparse matrix corresponding to the current file */
+ inline MatrixType& matrix()
+ {
+ // Read the matrix
+ if (m_matIsLoaded) return m_mat;
+
+ std::string matrix_file = m_folder + "/" + m_matname + ".mtx";
+ if ( !loadMarket(m_mat, matrix_file))
+ {
+ m_matIsLoaded = false;
+ return m_mat;
+ }
+ m_matIsLoaded = true;
+
+ if (m_sym != NonSymmetric)
+ { // Store the upper part of the matrix. It is needed by the solvers dealing with nonsymmetric matrices ??
+ MatrixType B;
+ B = m_mat;
+ m_mat = B.template selfadjointView<Lower>();
+ }
+ return m_mat;
+ }
+
+ /** Return the right hand side corresponding to the current matrix.
+ * If the rhs file is not provided, a random rhs is generated
+ */
+ inline VectorType& rhs()
+ {
+ // Get the right hand side
+ if (m_hasRhs) return m_rhs;
+
+ std::string rhs_file;
+ rhs_file = m_folder + "/" + m_matname + "_b.mtx"; // The pattern is matname_b.mtx
+ m_hasRhs = Fileexists(rhs_file);
+ if (m_hasRhs)
+ {
+ m_rhs.resize(m_mat.cols());
+ m_hasRhs = loadMarketVector(m_rhs, rhs_file);
+ }
+ if (!m_hasRhs)
+ {
+ // Generate a random right hand side
+ if (!m_matIsLoaded) this->matrix();
+ m_refX.resize(m_mat.cols());
+ m_refX.setRandom();
+ m_rhs = m_mat * m_refX;
+ m_hasrefX = true;
+ m_hasRhs = true;
+ }
+ return m_rhs;
+ }
+
+ /** Return a reference solution
+ * If it is not provided and if the right hand side is not available
+ * then refX is randomly generated such that A*refX = b
+ * where A and b are the matrix and the rhs.
+ * Note that when a rhs is provided, refX is not available
+ */
+ inline VectorType& refX()
+ {
+ // Check if a reference solution is provided
+ if (m_hasrefX) return m_refX;
+
+ std::string lhs_file;
+ lhs_file = m_folder + "/" + m_matname + "_x.mtx";
+ m_hasrefX = Fileexists(lhs_file);
+ if (m_hasrefX)
+ {
+ m_refX.resize(m_mat.cols());
+ m_hasrefX = loadMarketVector(m_refX, lhs_file);
+ }
+ return m_refX;
+ }
+
+ inline std::string& matname() { return m_matname; }
+
+ inline int sym() { return m_sym; }
+
+ inline bool hasRhs() {return m_hasRhs; }
+ inline bool hasrefX() {return m_hasrefX; }
+
+ protected:
+
+ inline bool Fileexists(std::string file)
+ {
+ std::ifstream file_id(file.c_str());
+ if (!file_id.good() )
+ {
+ return false;
+ }
+ else
+ {
+ file_id.close();
+ return true;
+ }
+ }
+
+ void Getnextvalidmatrix( )
+ {
+ m_isvalid = false;
+ // Here, we return with the next valid matrix in the folder
+ while ( (m_curs_id = readdir(m_folder_id)) != NULL) {
+ m_isvalid = false;
+ std::string curfile;
+ curfile = m_folder + "/" + m_curs_id->d_name;
+ // Discard if it is a folder
+ if (m_curs_id->d_type == DT_DIR) continue; //FIXME This may not be available on non BSD systems
+// struct stat st_buf;
+// stat (curfile.c_str(), &st_buf);
+// if (S_ISDIR(st_buf.st_mode)) continue;
+
+ // Determine from the header if it is a matrix or a right hand side
+ bool isvector,iscomplex;
+ if(!getMarketHeader(curfile,m_sym,iscomplex,isvector)) continue;
+ if(isvector) continue;
+
+ // Get the matrix name
+ std::string filename = m_curs_id->d_name;
+ m_matname = filename.substr(0, filename.length()-4);
+
+ // Find if the matrix is SPD
+ size_t found = m_matname.find("SPD");
+ if( (found!=std::string::npos) && (m_sym != NonSymmetric) )
+ m_sym = SPD;
+
+ m_isvalid = true;
+ break;
+ }
+ }
+ int m_sym; // Symmetry of the matrix
+ MatrixType m_mat; // Current matrix
+ VectorType m_rhs; // Current vector
+ VectorType m_refX; // The reference solution, if exists
+ std::string m_matname; // Matrix Name
+ bool m_isvalid;
+ bool m_matIsLoaded; // Determine if the matrix has already been loaded from the file
+ bool m_hasRhs; // The right hand side exists
+ bool m_hasrefX; // A reference solution is provided
+ std::string m_folder;
+ DIR * m_folder_id;
+ struct dirent *m_curs_id;
+
+};
+
+} // end namespace Eigen
+
+#endif
diff --git a/unsupported/Eigen/src/SparseExtra/RandomSetter.h b/unsupported/Eigen/src/SparseExtra/RandomSetter.h
new file mode 100644
index 000000000..dee1708e7
--- /dev/null
+++ b/unsupported/Eigen/src/SparseExtra/RandomSetter.h
@@ -0,0 +1,327 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra.
+//
+// Copyright (C) 2008 Gael Guennebaud <gael.guennebaud@inria.fr>
+//
+// This Source Code Form is subject to the terms of the Mozilla
+// Public License v. 2.0. If a copy of the MPL was not distributed
+// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+#ifndef EIGEN_RANDOMSETTER_H
+#define EIGEN_RANDOMSETTER_H
+
+namespace Eigen {
+
+/** Represents a std::map
+ *
+ * \see RandomSetter
+ */
+template<typename Scalar> struct StdMapTraits
+{
+ typedef int KeyType;
+ typedef std::map<KeyType,Scalar> Type;
+ enum {
+ IsSorted = 1
+ };
+
+ static void setInvalidKey(Type&, const KeyType&) {}
+};
+
+#ifdef EIGEN_UNORDERED_MAP_SUPPORT
+/** Represents a std::unordered_map
+ *
+ * To use it you need to both define EIGEN_UNORDERED_MAP_SUPPORT and include the unordered_map header file
+ * yourself making sure that unordered_map is defined in the std namespace.
+ *
+ * For instance, with current version of gcc you can either enable C++0x standard (-std=c++0x) or do:
+ * \code
+ * #include <tr1/unordered_map>
+ * #define EIGEN_UNORDERED_MAP_SUPPORT
+ * namespace std {
+ * using std::tr1::unordered_map;
+ * }
+ * \endcode
+ *
+ * \see RandomSetter
+ */
+template<typename Scalar> struct StdUnorderedMapTraits
+{
+ typedef int KeyType;
+ typedef std::unordered_map<KeyType,Scalar> Type;
+ enum {
+ IsSorted = 0
+ };
+
+ static void setInvalidKey(Type&, const KeyType&) {}
+};
+#endif // EIGEN_UNORDERED_MAP_SUPPORT
+
+#ifdef _DENSE_HASH_MAP_H_
+/** Represents a google::dense_hash_map
+ *
+ * \see RandomSetter
+ */
+template<typename Scalar> struct GoogleDenseHashMapTraits
+{
+ typedef int KeyType;
+ typedef google::dense_hash_map<KeyType,Scalar> Type;
+ enum {
+ IsSorted = 0
+ };
+
+ static void setInvalidKey(Type& map, const KeyType& k)
+ { map.set_empty_key(k); }
+};
+#endif
+
+#ifdef _SPARSE_HASH_MAP_H_
+/** Represents a google::sparse_hash_map
+ *
+ * \see RandomSetter
+ */
+template<typename Scalar> struct GoogleSparseHashMapTraits
+{
+ typedef int KeyType;
+ typedef google::sparse_hash_map<KeyType,Scalar> Type;
+ enum {
+ IsSorted = 0
+ };
+
+ static void setInvalidKey(Type&, const KeyType&) {}
+};
+#endif
+
+/** \class RandomSetter
+ *
+ * \brief The RandomSetter is a wrapper object allowing to set/update a sparse matrix with random access
+ *
+ * \param SparseMatrixType the type of the sparse matrix we are updating
+ * \param MapTraits a traits class representing the map implementation used for the temporary sparse storage.
+ * Its default value depends on the system.
+ * \param OuterPacketBits defines the number of rows (or columns) manage by a single map object
+ * as a power of two exponent.
+ *
+ * This class temporarily represents a sparse matrix object using a generic map implementation allowing for
+ * efficient random access. The conversion from the compressed representation to a hash_map object is performed
+ * in the RandomSetter constructor, while the sparse matrix is updated back at destruction time. This strategy
+ * suggest the use of nested blocks as in this example:
+ *
+ * \code
+ * SparseMatrix<double> m(rows,cols);
+ * {
+ * RandomSetter<SparseMatrix<double> > w(m);
+ * // don't use m but w instead with read/write random access to the coefficients:
+ * for(;;)
+ * w(rand(),rand()) = rand;
+ * }
+ * // when w is deleted, the data are copied back to m
+ * // and m is ready to use.
+ * \endcode
+ *
+ * Since hash_map objects are not fully sorted, representing a full matrix as a single hash_map would
+ * involve a big and costly sort to update the compressed matrix back. To overcome this issue, a RandomSetter
+ * use multiple hash_map, each representing 2^OuterPacketBits columns or rows according to the storage order.
+ * To reach optimal performance, this value should be adjusted according to the average number of nonzeros
+ * per rows/columns.
+ *
+ * The possible values for the template parameter MapTraits are:
+ * - \b StdMapTraits: corresponds to std::map. (does not perform very well)
+ * - \b GnuHashMapTraits: corresponds to __gnu_cxx::hash_map (available only with GCC)
+ * - \b GoogleDenseHashMapTraits: corresponds to google::dense_hash_map (best efficiency, reasonable memory consumption)
+ * - \b GoogleSparseHashMapTraits: corresponds to google::sparse_hash_map (best memory consumption, relatively good performance)
+ *
+ * The default map implementation depends on the availability, and the preferred order is:
+ * GoogleSparseHashMapTraits, GnuHashMapTraits, and finally StdMapTraits.
+ *
+ * For performance and memory consumption reasons it is highly recommended to use one of
+ * the Google's hash_map implementation. To enable the support for them, you have two options:
+ * - \#include <google/dense_hash_map> yourself \b before Eigen/Sparse header
+ * - define EIGEN_GOOGLEHASH_SUPPORT
+ * In the later case the inclusion of <google/dense_hash_map> is made for you.
+ *
+ * \see http://code.google.com/p/google-sparsehash/
+ */
+template<typename SparseMatrixType,
+ template <typename T> class MapTraits =
+#if defined _DENSE_HASH_MAP_H_
+ GoogleDenseHashMapTraits
+#elif defined _HASH_MAP
+ GnuHashMapTraits
+#else
+ StdMapTraits
+#endif
+ ,int OuterPacketBits = 6>
+class RandomSetter
+{
+ typedef typename SparseMatrixType::Scalar Scalar;
+ typedef typename SparseMatrixType::Index Index;
+
+ struct ScalarWrapper
+ {
+ ScalarWrapper() : value(0) {}
+ Scalar value;
+ };
+ typedef typename MapTraits<ScalarWrapper>::KeyType KeyType;
+ typedef typename MapTraits<ScalarWrapper>::Type HashMapType;
+ static const int OuterPacketMask = (1 << OuterPacketBits) - 1;
+ enum {
+ SwapStorage = 1 - MapTraits<ScalarWrapper>::IsSorted,
+ TargetRowMajor = (SparseMatrixType::Flags & RowMajorBit) ? 1 : 0,
+ SetterRowMajor = SwapStorage ? 1-TargetRowMajor : TargetRowMajor
+ };
+
+ public:
+
+ /** Constructs a random setter object from the sparse matrix \a target
+ *
+ * Note that the initial value of \a target are imported. If you want to re-set
+ * a sparse matrix from scratch, then you must set it to zero first using the
+ * setZero() function.
+ */
+ inline RandomSetter(SparseMatrixType& target)
+ : mp_target(&target)
+ {
+ const Index outerSize = SwapStorage ? target.innerSize() : target.outerSize();
+ const Index innerSize = SwapStorage ? target.outerSize() : target.innerSize();
+ m_outerPackets = outerSize >> OuterPacketBits;
+ if (outerSize&OuterPacketMask)
+ m_outerPackets += 1;
+ m_hashmaps = new HashMapType[m_outerPackets];
+ // compute number of bits needed to store inner indices
+ Index aux = innerSize - 1;
+ m_keyBitsOffset = 0;
+ while (aux)
+ {
+ ++m_keyBitsOffset;
+ aux = aux >> 1;
+ }
+ KeyType ik = (1<<(OuterPacketBits+m_keyBitsOffset));
+ for (Index k=0; k<m_outerPackets; ++k)
+ MapTraits<ScalarWrapper>::setInvalidKey(m_hashmaps[k],ik);
+
+ // insert current coeffs
+ for (Index j=0; j<mp_target->outerSize(); ++j)
+ for (typename SparseMatrixType::InnerIterator it(*mp_target,j); it; ++it)
+ (*this)(TargetRowMajor?j:it.index(), TargetRowMajor?it.index():j) = it.value();
+ }
+
+ /** Destructor updating back the sparse matrix target */
+ ~RandomSetter()
+ {
+ KeyType keyBitsMask = (1<<m_keyBitsOffset)-1;
+ if (!SwapStorage) // also means the map is sorted
+ {
+ mp_target->setZero();
+ mp_target->makeCompressed();
+ mp_target->reserve(nonZeros());
+ Index prevOuter = -1;
+ for (Index k=0; k<m_outerPackets; ++k)
+ {
+ const Index outerOffset = (1<<OuterPacketBits) * k;
+ typename HashMapType::iterator end = m_hashmaps[k].end();
+ for (typename HashMapType::iterator it = m_hashmaps[k].begin(); it!=end; ++it)
+ {
+ const Index outer = (it->first >> m_keyBitsOffset) + outerOffset;
+ const Index inner = it->first & keyBitsMask;
+ if (prevOuter!=outer)
+ {
+ for (Index j=prevOuter+1;j<=outer;++j)
+ mp_target->startVec(j);
+ prevOuter = outer;
+ }
+ mp_target->insertBackByOuterInner(outer, inner) = it->second.value;
+ }
+ }
+ mp_target->finalize();
+ }
+ else
+ {
+ VectorXi positions(mp_target->outerSize());
+ positions.setZero();
+ // pass 1
+ for (Index k=0; k<m_outerPackets; ++k)
+ {
+ typename HashMapType::iterator end = m_hashmaps[k].end();
+ for (typename HashMapType::iterator it = m_hashmaps[k].begin(); it!=end; ++it)
+ {
+ const Index outer = it->first & keyBitsMask;
+ ++positions[outer];
+ }
+ }
+ // prefix sum
+ Index count = 0;
+ for (Index j=0; j<mp_target->outerSize(); ++j)
+ {
+ Index tmp = positions[j];
+ mp_target->outerIndexPtr()[j] = count;
+ positions[j] = count;
+ count += tmp;
+ }
+ mp_target->makeCompressed();
+ mp_target->outerIndexPtr()[mp_target->outerSize()] = count;
+ mp_target->resizeNonZeros(count);
+ // pass 2
+ for (Index k=0; k<m_outerPackets; ++k)
+ {
+ const Index outerOffset = (1<<OuterPacketBits) * k;
+ typename HashMapType::iterator end = m_hashmaps[k].end();
+ for (typename HashMapType::iterator it = m_hashmaps[k].begin(); it!=end; ++it)
+ {
+ const Index inner = (it->first >> m_keyBitsOffset) + outerOffset;
+ const Index outer = it->first & keyBitsMask;
+ // sorted insertion
+ // Note that we have to deal with at most 2^OuterPacketBits unsorted coefficients,
+ // moreover those 2^OuterPacketBits coeffs are likely to be sparse, an so only a
+ // small fraction of them have to be sorted, whence the following simple procedure:
+ Index posStart = mp_target->outerIndexPtr()[outer];
+ Index i = (positions[outer]++) - 1;
+ while ( (i >= posStart) && (mp_target->innerIndexPtr()[i] > inner) )
+ {
+ mp_target->valuePtr()[i+1] = mp_target->valuePtr()[i];
+ mp_target->innerIndexPtr()[i+1] = mp_target->innerIndexPtr()[i];
+ --i;
+ }
+ mp_target->innerIndexPtr()[i+1] = inner;
+ mp_target->valuePtr()[i+1] = it->second.value;
+ }
+ }
+ }
+ delete[] m_hashmaps;
+ }
+
+ /** \returns a reference to the coefficient at given coordinates \a row, \a col */
+ Scalar& operator() (Index row, Index col)
+ {
+ const Index outer = SetterRowMajor ? row : col;
+ const Index inner = SetterRowMajor ? col : row;
+ const Index outerMajor = outer >> OuterPacketBits; // index of the packet/map
+ const Index outerMinor = outer & OuterPacketMask; // index of the inner vector in the packet
+ const KeyType key = (KeyType(outerMinor)<<m_keyBitsOffset) | inner;
+ return m_hashmaps[outerMajor][key].value;
+ }
+
+ /** \returns the number of non zero coefficients
+ *
+ * \note According to the underlying map/hash_map implementation,
+ * this function might be quite expensive.
+ */
+ Index nonZeros() const
+ {
+ Index nz = 0;
+ for (Index k=0; k<m_outerPackets; ++k)
+ nz += static_cast<Index>(m_hashmaps[k].size());
+ return nz;
+ }
+
+
+ protected:
+
+ HashMapType* m_hashmaps;
+ SparseMatrixType* mp_target;
+ Index m_outerPackets;
+ unsigned char m_keyBitsOffset;
+};
+
+} // end namespace Eigen
+
+#endif // EIGEN_RANDOMSETTER_H
diff --git a/unsupported/Eigen/src/Splines/CMakeLists.txt b/unsupported/Eigen/src/Splines/CMakeLists.txt
new file mode 100644
index 000000000..55c6271e9
--- /dev/null
+++ b/unsupported/Eigen/src/Splines/CMakeLists.txt
@@ -0,0 +1,6 @@
+FILE(GLOB Eigen_Splines_SRCS "*.h")
+
+INSTALL(FILES
+ ${Eigen_Splines_SRCS}
+ DESTINATION ${INCLUDE_INSTALL_DIR}/unsupported/Eigen/src/Splines COMPONENT Devel
+ )
diff --git a/unsupported/Eigen/src/Splines/Spline.h b/unsupported/Eigen/src/Splines/Spline.h
new file mode 100644
index 000000000..3680f013a
--- /dev/null
+++ b/unsupported/Eigen/src/Splines/Spline.h
@@ -0,0 +1,464 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra.
+//
+// Copyright (C) 20010-2011 Hauke Heibel <hauke.heibel@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 EIGEN_SPLINE_H
+#define EIGEN_SPLINE_H
+
+#include "SplineFwd.h"
+
+namespace Eigen
+{
+ /**
+ * \ingroup Splines_Module
+ * \class Spline class
+ * \brief A class representing multi-dimensional spline curves.
+ *
+ * The class represents B-splines with non-uniform knot vectors. Each control
+ * point of the B-spline is associated with a basis function
+ * \f{align*}
+ * C(u) & = \sum_{i=0}^{n}N_{i,p}(u)P_i
+ * \f}
+ *
+ * \tparam _Scalar The underlying data type (typically float or double)
+ * \tparam _Dim The curve dimension (e.g. 2 or 3)
+ * \tparam _Degree Per default set to Dynamic; could be set to the actual desired
+ * degree for optimization purposes (would result in stack allocation
+ * of several temporary variables).
+ **/
+ template <typename _Scalar, int _Dim, int _Degree>
+ class Spline
+ {
+ public:
+ typedef _Scalar Scalar; /*!< The spline curve's scalar type. */
+ enum { Dimension = _Dim /*!< The spline curve's dimension. */ };
+ enum { Degree = _Degree /*!< The spline curve's degree. */ };
+
+ /** \brief The point type the spline is representing. */
+ typedef typename SplineTraits<Spline>::PointType PointType;
+
+ /** \brief The data type used to store knot vectors. */
+ typedef typename SplineTraits<Spline>::KnotVectorType KnotVectorType;
+
+ /** \brief The data type used to store non-zero basis functions. */
+ typedef typename SplineTraits<Spline>::BasisVectorType BasisVectorType;
+
+ /** \brief The data type representing the spline's control points. */
+ typedef typename SplineTraits<Spline>::ControlPointVectorType ControlPointVectorType;
+
+ /**
+ * \brief Creates a spline from a knot vector and control points.
+ * \param knots The spline's knot vector.
+ * \param ctrls The spline's control point vector.
+ **/
+ template <typename OtherVectorType, typename OtherArrayType>
+ Spline(const OtherVectorType& knots, const OtherArrayType& ctrls) : m_knots(knots), m_ctrls(ctrls) {}
+
+ /**
+ * \brief Copy constructor for splines.
+ * \param spline The input spline.
+ **/
+ template <int OtherDegree>
+ Spline(const Spline<Scalar, Dimension, OtherDegree>& spline) :
+ m_knots(spline.knots()), m_ctrls(spline.ctrls()) {}
+
+ /**
+ * \brief Returns the knots of the underlying spline.
+ **/
+ const KnotVectorType& knots() const { return m_knots; }
+
+ /**
+ * \brief Returns the knots of the underlying spline.
+ **/
+ const ControlPointVectorType& ctrls() const { return m_ctrls; }
+
+ /**
+ * \brief Returns the spline value at a given site \f$u\f$.
+ *
+ * The function returns
+ * \f{align*}
+ * C(u) & = \sum_{i=0}^{n}N_{i,p}P_i
+ * \f}
+ *
+ * \param u Parameter \f$u \in [0;1]\f$ at which the spline is evaluated.
+ * \return The spline value at the given location \f$u\f$.
+ **/
+ PointType operator()(Scalar u) const;
+
+ /**
+ * \brief Evaluation of spline derivatives of up-to given order.
+ *
+ * The function returns
+ * \f{align*}
+ * \frac{d^i}{du^i}C(u) & = \sum_{i=0}^{n} \frac{d^i}{du^i} N_{i,p}(u)P_i
+ * \f}
+ * for i ranging between 0 and order.
+ *
+ * \param u Parameter \f$u \in [0;1]\f$ at which the spline derivative is evaluated.
+ * \param order The order up to which the derivatives are computed.
+ **/
+ typename SplineTraits<Spline>::DerivativeType
+ derivatives(Scalar u, DenseIndex order) const;
+
+ /**
+ * \copydoc Spline::derivatives
+ * Using the template version of this function is more efficieent since
+ * temporary objects are allocated on the stack whenever this is possible.
+ **/
+ template <int DerivativeOrder>
+ typename SplineTraits<Spline,DerivativeOrder>::DerivativeType
+ derivatives(Scalar u, DenseIndex order = DerivativeOrder) const;
+
+ /**
+ * \brief Computes the non-zero basis functions at the given site.
+ *
+ * Splines have local support and a point from their image is defined
+ * by exactly \f$p+1\f$ control points \f$P_i\f$ where \f$p\f$ is the
+ * spline degree.
+ *
+ * This function computes the \f$p+1\f$ non-zero basis function values
+ * for a given parameter value \f$u\f$. It returns
+ * \f{align*}{
+ * N_{i,p}(u), \hdots, N_{i+p+1,p}(u)
+ * \f}
+ *
+ * \param u Parameter \f$u \in [0;1]\f$ at which the non-zero basis functions
+ * are computed.
+ **/
+ typename SplineTraits<Spline>::BasisVectorType
+ basisFunctions(Scalar u) const;
+
+ /**
+ * \brief Computes the non-zero spline basis function derivatives up to given order.
+ *
+ * The function computes
+ * \f{align*}{
+ * \frac{d^i}{du^i} N_{i,p}(u), \hdots, \frac{d^i}{du^i} N_{i+p+1,p}(u)
+ * \f}
+ * with i ranging from 0 up to the specified order.
+ *
+ * \param u Parameter \f$u \in [0;1]\f$ at which the non-zero basis function
+ * derivatives are computed.
+ * \param order The order up to which the basis function derivatives are computes.
+ **/
+ typename SplineTraits<Spline>::BasisDerivativeType
+ basisFunctionDerivatives(Scalar u, DenseIndex order) const;
+
+ /**
+ * \copydoc Spline::basisFunctionDerivatives
+ * Using the template version of this function is more efficieent since
+ * temporary objects are allocated on the stack whenever this is possible.
+ **/
+ template <int DerivativeOrder>
+ typename SplineTraits<Spline,DerivativeOrder>::BasisDerivativeType
+ basisFunctionDerivatives(Scalar u, DenseIndex order = DerivativeOrder) const;
+
+ /**
+ * \brief Returns the spline degree.
+ **/
+ DenseIndex degree() const;
+
+ /**
+ * \brief Returns the span within the knot vector in which u is falling.
+ * \param u The site for which the span is determined.
+ **/
+ DenseIndex span(Scalar u) const;
+
+ /**
+ * \brief Computes the spang within the provided knot vector in which u is falling.
+ **/
+ static DenseIndex Span(typename SplineTraits<Spline>::Scalar u, DenseIndex degree, const typename SplineTraits<Spline>::KnotVectorType& knots);
+
+ /**
+ * \brief Returns the spline's non-zero basis functions.
+ *
+ * The function computes and returns
+ * \f{align*}{
+ * N_{i,p}(u), \hdots, N_{i+p+1,p}(u)
+ * \f}
+ *
+ * \param u The site at which the basis functions are computed.
+ * \param degree The degree of the underlying spline.
+ * \param knots The underlying spline's knot vector.
+ **/
+ static BasisVectorType BasisFunctions(Scalar u, DenseIndex degree, const KnotVectorType& knots);
+
+
+ private:
+ KnotVectorType m_knots; /*!< Knot vector. */
+ ControlPointVectorType m_ctrls; /*!< Control points. */
+ };
+
+ template <typename _Scalar, int _Dim, int _Degree>
+ DenseIndex Spline<_Scalar, _Dim, _Degree>::Span(
+ typename SplineTraits< Spline<_Scalar, _Dim, _Degree> >::Scalar u,
+ DenseIndex degree,
+ const typename SplineTraits< Spline<_Scalar, _Dim, _Degree> >::KnotVectorType& knots)
+ {
+ // Piegl & Tiller, "The NURBS Book", A2.1 (p. 68)
+ if (u <= knots(0)) return degree;
+ const Scalar* pos = std::upper_bound(knots.data()+degree-1, knots.data()+knots.size()-degree-1, u);
+ return static_cast<DenseIndex>( std::distance(knots.data(), pos) - 1 );
+ }
+
+ template <typename _Scalar, int _Dim, int _Degree>
+ typename Spline<_Scalar, _Dim, _Degree>::BasisVectorType
+ Spline<_Scalar, _Dim, _Degree>::BasisFunctions(
+ typename Spline<_Scalar, _Dim, _Degree>::Scalar u,
+ DenseIndex degree,
+ const typename Spline<_Scalar, _Dim, _Degree>::KnotVectorType& knots)
+ {
+ typedef typename Spline<_Scalar, _Dim, _Degree>::BasisVectorType BasisVectorType;
+
+ const DenseIndex p = degree;
+ const DenseIndex i = Spline::Span(u, degree, knots);
+
+ const KnotVectorType& U = knots;
+
+ BasisVectorType left(p+1); left(0) = Scalar(0);
+ BasisVectorType right(p+1); right(0) = Scalar(0);
+
+ VectorBlock<BasisVectorType,Degree>(left,1,p) = u - VectorBlock<const KnotVectorType,Degree>(U,i+1-p,p).reverse();
+ VectorBlock<BasisVectorType,Degree>(right,1,p) = VectorBlock<const KnotVectorType,Degree>(U,i+1,p) - u;
+
+ BasisVectorType N(1,p+1);
+ N(0) = Scalar(1);
+ for (DenseIndex j=1; j<=p; ++j)
+ {
+ Scalar saved = Scalar(0);
+ for (DenseIndex r=0; r<j; r++)
+ {
+ const Scalar tmp = N(r)/(right(r+1)+left(j-r));
+ N[r] = saved + right(r+1)*tmp;
+ saved = left(j-r)*tmp;
+ }
+ N(j) = saved;
+ }
+ return N;
+ }
+
+ template <typename _Scalar, int _Dim, int _Degree>
+ DenseIndex Spline<_Scalar, _Dim, _Degree>::degree() const
+ {
+ if (_Degree == Dynamic)
+ return m_knots.size() - m_ctrls.cols() - 1;
+ else
+ return _Degree;
+ }
+
+ template <typename _Scalar, int _Dim, int _Degree>
+ DenseIndex Spline<_Scalar, _Dim, _Degree>::span(Scalar u) const
+ {
+ return Spline::Span(u, degree(), knots());
+ }
+
+ template <typename _Scalar, int _Dim, int _Degree>
+ typename Spline<_Scalar, _Dim, _Degree>::PointType Spline<_Scalar, _Dim, _Degree>::operator()(Scalar u) const
+ {
+ enum { Order = SplineTraits<Spline>::OrderAtCompileTime };
+
+ const DenseIndex span = this->span(u);
+ const DenseIndex p = degree();
+ const BasisVectorType basis_funcs = basisFunctions(u);
+
+ const Replicate<BasisVectorType,Dimension,1> ctrl_weights(basis_funcs);
+ const Block<const ControlPointVectorType,Dimension,Order> ctrl_pts(ctrls(),0,span-p,Dimension,p+1);
+ return (ctrl_weights * ctrl_pts).rowwise().sum();
+ }
+
+ /* --------------------------------------------------------------------------------------------- */
+
+ template <typename SplineType, typename DerivativeType>
+ void derivativesImpl(const SplineType& spline, typename SplineType::Scalar u, DenseIndex order, DerivativeType& der)
+ {
+ enum { Dimension = SplineTraits<SplineType>::Dimension };
+ enum { Order = SplineTraits<SplineType>::OrderAtCompileTime };
+ enum { DerivativeOrder = DerivativeType::ColsAtCompileTime };
+
+ typedef typename SplineTraits<SplineType>::Scalar Scalar;
+
+ typedef typename SplineTraits<SplineType>::BasisVectorType BasisVectorType;
+ typedef typename SplineTraits<SplineType>::ControlPointVectorType ControlPointVectorType;
+
+ typedef typename SplineTraits<SplineType,DerivativeOrder>::BasisDerivativeType BasisDerivativeType;
+ typedef typename BasisDerivativeType::ConstRowXpr BasisDerivativeRowXpr;
+
+ const DenseIndex p = spline.degree();
+ const DenseIndex span = spline.span(u);
+
+ const DenseIndex n = (std::min)(p, order);
+
+ der.resize(Dimension,n+1);
+
+ // Retrieve the basis function derivatives up to the desired order...
+ const BasisDerivativeType basis_func_ders = spline.template basisFunctionDerivatives<DerivativeOrder>(u, n+1);
+
+ // ... and perform the linear combinations of the control points.
+ for (DenseIndex der_order=0; der_order<n+1; ++der_order)
+ {
+ const Replicate<BasisDerivativeRowXpr,Dimension,1> ctrl_weights( basis_func_ders.row(der_order) );
+ const Block<const ControlPointVectorType,Dimension,Order> ctrl_pts(spline.ctrls(),0,span-p,Dimension,p+1);
+ der.col(der_order) = (ctrl_weights * ctrl_pts).rowwise().sum();
+ }
+ }
+
+ template <typename _Scalar, int _Dim, int _Degree>
+ typename SplineTraits< Spline<_Scalar, _Dim, _Degree> >::DerivativeType
+ Spline<_Scalar, _Dim, _Degree>::derivatives(Scalar u, DenseIndex order) const
+ {
+ typename SplineTraits< Spline >::DerivativeType res;
+ derivativesImpl(*this, u, order, res);
+ return res;
+ }
+
+ template <typename _Scalar, int _Dim, int _Degree>
+ template <int DerivativeOrder>
+ typename SplineTraits< Spline<_Scalar, _Dim, _Degree>, DerivativeOrder >::DerivativeType
+ Spline<_Scalar, _Dim, _Degree>::derivatives(Scalar u, DenseIndex order) const
+ {
+ typename SplineTraits< Spline, DerivativeOrder >::DerivativeType res;
+ derivativesImpl(*this, u, order, res);
+ return res;
+ }
+
+ template <typename _Scalar, int _Dim, int _Degree>
+ typename SplineTraits< Spline<_Scalar, _Dim, _Degree> >::BasisVectorType
+ Spline<_Scalar, _Dim, _Degree>::basisFunctions(Scalar u) const
+ {
+ return Spline::BasisFunctions(u, degree(), knots());
+ }
+
+ /* --------------------------------------------------------------------------------------------- */
+
+ template <typename SplineType, typename DerivativeType>
+ void basisFunctionDerivativesImpl(const SplineType& spline, typename SplineType::Scalar u, DenseIndex order, DerivativeType& N_)
+ {
+ enum { Order = SplineTraits<SplineType>::OrderAtCompileTime };
+
+ typedef typename SplineTraits<SplineType>::Scalar Scalar;
+ typedef typename SplineTraits<SplineType>::BasisVectorType BasisVectorType;
+ typedef typename SplineTraits<SplineType>::KnotVectorType KnotVectorType;
+ typedef typename SplineTraits<SplineType>::ControlPointVectorType ControlPointVectorType;
+
+ const KnotVectorType& U = spline.knots();
+
+ const DenseIndex p = spline.degree();
+ const DenseIndex span = spline.span(u);
+
+ const DenseIndex n = (std::min)(p, order);
+
+ N_.resize(n+1, p+1);
+
+ BasisVectorType left = BasisVectorType::Zero(p+1);
+ BasisVectorType right = BasisVectorType::Zero(p+1);
+
+ Matrix<Scalar,Order,Order> ndu(p+1,p+1);
+
+ double saved, temp;
+
+ ndu(0,0) = 1.0;
+
+ DenseIndex j;
+ for (j=1; j<=p; ++j)
+ {
+ left[j] = u-U[span+1-j];
+ right[j] = U[span+j]-u;
+ saved = 0.0;
+
+ for (DenseIndex r=0; r<j; ++r)
+ {
+ /* Lower triangle */
+ ndu(j,r) = right[r+1]+left[j-r];
+ temp = ndu(r,j-1)/ndu(j,r);
+ /* Upper triangle */
+ ndu(r,j) = static_cast<Scalar>(saved+right[r+1] * temp);
+ saved = left[j-r] * temp;
+ }
+
+ ndu(j,j) = static_cast<Scalar>(saved);
+ }
+
+ for (j = p; j>=0; --j)
+ N_(0,j) = ndu(j,p);
+
+ // Compute the derivatives
+ DerivativeType a(n+1,p+1);
+ DenseIndex r=0;
+ for (; r<=p; ++r)
+ {
+ DenseIndex s1,s2;
+ s1 = 0; s2 = 1; // alternate rows in array a
+ a(0,0) = 1.0;
+
+ // Compute the k-th derivative
+ for (DenseIndex k=1; k<=static_cast<DenseIndex>(n); ++k)
+ {
+ double d = 0.0;
+ DenseIndex rk,pk,j1,j2;
+ rk = r-k; pk = p-k;
+
+ if (r>=k)
+ {
+ a(s2,0) = a(s1,0)/ndu(pk+1,rk);
+ d = a(s2,0)*ndu(rk,pk);
+ }
+
+ if (rk>=-1) j1 = 1;
+ else j1 = -rk;
+
+ if (r-1 <= pk) j2 = k-1;
+ else j2 = p-r;
+
+ for (j=j1; j<=j2; ++j)
+ {
+ a(s2,j) = (a(s1,j)-a(s1,j-1))/ndu(pk+1,rk+j);
+ d += a(s2,j)*ndu(rk+j,pk);
+ }
+
+ if (r<=pk)
+ {
+ a(s2,k) = -a(s1,k-1)/ndu(pk+1,r);
+ d += a(s2,k)*ndu(r,pk);
+ }
+
+ N_(k,r) = static_cast<Scalar>(d);
+ j = s1; s1 = s2; s2 = j; // Switch rows
+ }
+ }
+
+ /* Multiply through by the correct factors */
+ /* (Eq. [2.9]) */
+ r = p;
+ for (DenseIndex k=1; k<=static_cast<DenseIndex>(n); ++k)
+ {
+ for (DenseIndex j=p; j>=0; --j) N_(k,j) *= r;
+ r *= p-k;
+ }
+ }
+
+ template <typename _Scalar, int _Dim, int _Degree>
+ typename SplineTraits< Spline<_Scalar, _Dim, _Degree> >::BasisDerivativeType
+ Spline<_Scalar, _Dim, _Degree>::basisFunctionDerivatives(Scalar u, DenseIndex order) const
+ {
+ typename SplineTraits< Spline >::BasisDerivativeType der;
+ basisFunctionDerivativesImpl(*this, u, order, der);
+ return der;
+ }
+
+ template <typename _Scalar, int _Dim, int _Degree>
+ template <int DerivativeOrder>
+ typename SplineTraits< Spline<_Scalar, _Dim, _Degree>, DerivativeOrder >::BasisDerivativeType
+ Spline<_Scalar, _Dim, _Degree>::basisFunctionDerivatives(Scalar u, DenseIndex order) const
+ {
+ typename SplineTraits< Spline, DerivativeOrder >::BasisDerivativeType der;
+ basisFunctionDerivativesImpl(*this, u, order, der);
+ return der;
+ }
+}
+
+#endif // EIGEN_SPLINE_H
diff --git a/unsupported/Eigen/src/Splines/SplineFitting.h b/unsupported/Eigen/src/Splines/SplineFitting.h
new file mode 100644
index 000000000..1b566332f
--- /dev/null
+++ b/unsupported/Eigen/src/Splines/SplineFitting.h
@@ -0,0 +1,159 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra.
+//
+// Copyright (C) 20010-2011 Hauke Heibel <hauke.heibel@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 EIGEN_SPLINE_FITTING_H
+#define EIGEN_SPLINE_FITTING_H
+
+#include <numeric>
+
+#include "SplineFwd.h"
+
+#include <Eigen/QR>
+
+namespace Eigen
+{
+ /**
+ * \brief Computes knot averages.
+ * \ingroup Splines_Module
+ *
+ * The knots are computed as
+ * \f{align*}
+ * u_0 & = \hdots = u_p = 0 \\
+ * u_{m-p} & = \hdots = u_{m} = 1 \\
+ * u_{j+p} & = \frac{1}{p}\sum_{i=j}^{j+p-1}\bar{u}_i \quad\quad j=1,\hdots,n-p
+ * \f}
+ * where \f$p\f$ is the degree and \f$m+1\f$ the number knots
+ * of the desired interpolating spline.
+ *
+ * \param[in] parameters The input parameters. During interpolation one for each data point.
+ * \param[in] degree The spline degree which is used during the interpolation.
+ * \param[out] knots The output knot vector.
+ *
+ * \sa Les Piegl and Wayne Tiller, The NURBS book (2nd ed.), 1997, 9.2.1 Global Curve Interpolation to Point Data
+ **/
+ template <typename KnotVectorType>
+ void KnotAveraging(const KnotVectorType& parameters, DenseIndex degree, KnotVectorType& knots)
+ {
+ typedef typename KnotVectorType::Scalar Scalar;
+
+ knots.resize(parameters.size()+degree+1);
+
+ for (DenseIndex j=1; j<parameters.size()-degree; ++j)
+ knots(j+degree) = parameters.segment(j,degree).mean();
+
+ knots.segment(0,degree+1) = KnotVectorType::Zero(degree+1);
+ knots.segment(knots.size()-degree-1,degree+1) = KnotVectorType::Ones(degree+1);
+ }
+
+ /**
+ * \brief Computes chord length parameters which are required for spline interpolation.
+ * \ingroup Splines_Module
+ *
+ * \param[in] pts The data points to which a spline should be fit.
+ * \param[out] chord_lengths The resulting chord lenggth vector.
+ *
+ * \sa Les Piegl and Wayne Tiller, The NURBS book (2nd ed.), 1997, 9.2.1 Global Curve Interpolation to Point Data
+ **/
+ template <typename PointArrayType, typename KnotVectorType>
+ void ChordLengths(const PointArrayType& pts, KnotVectorType& chord_lengths)
+ {
+ typedef typename KnotVectorType::Scalar Scalar;
+
+ const DenseIndex n = pts.cols();
+
+ // 1. compute the column-wise norms
+ chord_lengths.resize(pts.cols());
+ chord_lengths[0] = 0;
+ chord_lengths.rightCols(n-1) = (pts.array().leftCols(n-1) - pts.array().rightCols(n-1)).matrix().colwise().norm();
+
+ // 2. compute the partial sums
+ std::partial_sum(chord_lengths.data(), chord_lengths.data()+n, chord_lengths.data());
+
+ // 3. normalize the data
+ chord_lengths /= chord_lengths(n-1);
+ chord_lengths(n-1) = Scalar(1);
+ }
+
+ /**
+ * \brief Spline fitting methods.
+ * \ingroup Splines_Module
+ **/
+ template <typename SplineType>
+ struct SplineFitting
+ {
+ typedef typename SplineType::KnotVectorType KnotVectorType;
+
+ /**
+ * \brief Fits an interpolating Spline to the given data points.
+ *
+ * \param pts The points for which an interpolating spline will be computed.
+ * \param degree The degree of the interpolating spline.
+ *
+ * \returns A spline interpolating the initially provided points.
+ **/
+ template <typename PointArrayType>
+ static SplineType Interpolate(const PointArrayType& pts, DenseIndex degree);
+
+ /**
+ * \brief Fits an interpolating Spline to the given data points.
+ *
+ * \param pts The points for which an interpolating spline will be computed.
+ * \param degree The degree of the interpolating spline.
+ * \param knot_parameters The knot parameters for the interpolation.
+ *
+ * \returns A spline interpolating the initially provided points.
+ **/
+ template <typename PointArrayType>
+ static SplineType Interpolate(const PointArrayType& pts, DenseIndex degree, const KnotVectorType& knot_parameters);
+ };
+
+ template <typename SplineType>
+ template <typename PointArrayType>
+ SplineType SplineFitting<SplineType>::Interpolate(const PointArrayType& pts, DenseIndex degree, const KnotVectorType& knot_parameters)
+ {
+ typedef typename SplineType::KnotVectorType::Scalar Scalar;
+ typedef typename SplineType::BasisVectorType BasisVectorType;
+ typedef typename SplineType::ControlPointVectorType ControlPointVectorType;
+
+ typedef Matrix<Scalar,Dynamic,Dynamic> MatrixType;
+
+ KnotVectorType knots;
+ KnotAveraging(knot_parameters, degree, knots);
+
+ DenseIndex n = pts.cols();
+ MatrixType A = MatrixType::Zero(n,n);
+ for (DenseIndex i=1; i<n-1; ++i)
+ {
+ const DenseIndex span = SplineType::Span(knot_parameters[i], degree, knots);
+
+ // The segment call should somehow be told the spline order at compile time.
+ A.row(i).segment(span-degree, degree+1) = SplineType::BasisFunctions(knot_parameters[i], degree, knots);
+ }
+ A(0,0) = 1.0;
+ A(n-1,n-1) = 1.0;
+
+ HouseholderQR<MatrixType> qr(A);
+
+ // Here, we are creating a temporary due to an Eigen issue.
+ ControlPointVectorType ctrls = qr.solve(MatrixType(pts.transpose())).transpose();
+
+ return SplineType(knots, ctrls);
+ }
+
+ template <typename SplineType>
+ template <typename PointArrayType>
+ SplineType SplineFitting<SplineType>::Interpolate(const PointArrayType& pts, DenseIndex degree)
+ {
+ KnotVectorType chord_lengths; // knot parameters
+ ChordLengths(pts, chord_lengths);
+ return Interpolate(pts, degree, chord_lengths);
+ }
+}
+
+#endif // EIGEN_SPLINE_FITTING_H
diff --git a/unsupported/Eigen/src/Splines/SplineFwd.h b/unsupported/Eigen/src/Splines/SplineFwd.h
new file mode 100644
index 000000000..49db8d35d
--- /dev/null
+++ b/unsupported/Eigen/src/Splines/SplineFwd.h
@@ -0,0 +1,86 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra.
+//
+// Copyright (C) 20010-2011 Hauke Heibel <hauke.heibel@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 EIGEN_SPLINES_FWD_H
+#define EIGEN_SPLINES_FWD_H
+
+#include <Eigen/Core>
+
+namespace Eigen
+{
+ template <typename Scalar, int Dim, int Degree = Dynamic> class Spline;
+
+ template < typename SplineType, int DerivativeOrder = Dynamic > struct SplineTraits {};
+
+ /**
+ * \ingroup Splines_Module
+ * \brief Compile-time attributes of the Spline class for Dynamic degree.
+ **/
+ template <typename _Scalar, int _Dim, int _Degree>
+ struct SplineTraits< Spline<_Scalar, _Dim, _Degree>, Dynamic >
+ {
+ typedef _Scalar Scalar; /*!< The spline curve's scalar type. */
+ enum { Dimension = _Dim /*!< The spline curve's dimension. */ };
+ enum { Degree = _Degree /*!< The spline curve's degree. */ };
+
+ enum { OrderAtCompileTime = _Degree==Dynamic ? Dynamic : _Degree+1 /*!< The spline curve's order at compile-time. */ };
+ enum { NumOfDerivativesAtCompileTime = OrderAtCompileTime /*!< The number of derivatives defined for the current spline. */ };
+
+ /** \brief The data type used to store non-zero basis functions. */
+ typedef Array<Scalar,1,OrderAtCompileTime> BasisVectorType;
+
+ /** \brief The data type used to store the values of the basis function derivatives. */
+ typedef Array<Scalar,Dynamic,Dynamic,RowMajor,NumOfDerivativesAtCompileTime,OrderAtCompileTime> BasisDerivativeType;
+
+ /** \brief The data type used to store the spline's derivative values. */
+ typedef Array<Scalar,Dimension,Dynamic,ColMajor,Dimension,NumOfDerivativesAtCompileTime> DerivativeType;
+
+ /** \brief The point type the spline is representing. */
+ typedef Array<Scalar,Dimension,1> PointType;
+
+ /** \brief The data type used to store knot vectors. */
+ typedef Array<Scalar,1,Dynamic> KnotVectorType;
+
+ /** \brief The data type representing the spline's control points. */
+ typedef Array<Scalar,Dimension,Dynamic> ControlPointVectorType;
+ };
+
+ /**
+ * \ingroup Splines_Module
+ * \brief Compile-time attributes of the Spline class for fixed degree.
+ *
+ * The traits class inherits all attributes from the SplineTraits of Dynamic degree.
+ **/
+ template < typename _Scalar, int _Dim, int _Degree, int _DerivativeOrder >
+ struct SplineTraits< Spline<_Scalar, _Dim, _Degree>, _DerivativeOrder > : public SplineTraits< Spline<_Scalar, _Dim, _Degree> >
+ {
+ enum { OrderAtCompileTime = _Degree==Dynamic ? Dynamic : _Degree+1 /*!< The spline curve's order at compile-time. */ };
+ enum { NumOfDerivativesAtCompileTime = _DerivativeOrder==Dynamic ? Dynamic : _DerivativeOrder+1 /*!< The number of derivatives defined for the current spline. */ };
+
+ /** \brief The data type used to store the values of the basis function derivatives. */
+ typedef Array<_Scalar,Dynamic,Dynamic,RowMajor,NumOfDerivativesAtCompileTime,OrderAtCompileTime> BasisDerivativeType;
+
+ /** \brief The data type used to store the spline's derivative values. */
+ typedef Array<_Scalar,_Dim,Dynamic,ColMajor,_Dim,NumOfDerivativesAtCompileTime> DerivativeType;
+ };
+
+ /** \brief 2D float B-spline with dynamic degree. */
+ typedef Spline<float,2> Spline2f;
+
+ /** \brief 3D float B-spline with dynamic degree. */
+ typedef Spline<float,3> Spline3f;
+
+ /** \brief 2D double B-spline with dynamic degree. */
+ typedef Spline<double,2> Spline2d;
+
+ /** \brief 3D double B-spline with dynamic degree. */
+ typedef Spline<double,3> Spline3d;
+}
+
+#endif // EIGEN_SPLINES_FWD_H
diff --git a/unsupported/README.txt b/unsupported/README.txt
new file mode 100644
index 000000000..83479ff0b
--- /dev/null
+++ b/unsupported/README.txt
@@ -0,0 +1,50 @@
+This directory contains contributions from various users.
+They are provided "as is", without any support. Nevertheless,
+most of them are subject to be included in Eigen in the future.
+
+In order to use an unsupported module you have to do either:
+
+ - add the path_to_eigen/unsupported directory to your include path and do:
+ #include <Eigen/ModuleHeader>
+
+ - or directly do:
+ #include <unsupported/Eigen/ModuleHeader>
+
+
+If you are interested in contributing to one of them, or have other stuff
+you would like to share, feel free to contact us:
+http://eigen.tuxfamily.org/index.php?title=Main_Page#Mailing_list
+
+Any kind of contributions are much appreciated, even very preliminary ones.
+However, it:
+ - must rely on Eigen,
+ - must be highly related to math,
+ - should have some general purpose in the sense that it could
+ potentially become an offical Eigen module (or be merged into another one).
+
+In doubt feel free to contact us. For instance, if your addons is very too specific
+but it shows an interesting way of using Eigen, then it could be a nice demo.
+
+
+This directory is organized as follow:
+
+unsupported/Eigen/ModuleHeader1
+unsupported/Eigen/ModuleHeader2
+unsupported/Eigen/...
+unsupported/Eigen/src/Module1/SourceFile1.h
+unsupported/Eigen/src/Module1/SourceFile2.h
+unsupported/Eigen/src/Module1/...
+unsupported/Eigen/src/Module2/SourceFile1.h
+unsupported/Eigen/src/Module2/SourceFile2.h
+unsupported/Eigen/src/Module2/...
+unsupported/Eigen/src/...
+unsupported/doc/snippets/.cpp <- code snippets for the doc
+unsupported/doc/examples/.cpp <- examples for the doc
+unsupported/doc/TutorialModule1.dox
+unsupported/doc/TutorialModule2.dox
+unsupported/doc/...
+unsupported/test/.cpp <- unit test files
+
+The documentation is generated at the same time than the main Eigen documentation.
+The .html files are generated in: build_dir/doc/html/unsupported/
+
diff --git a/unsupported/doc/CMakeLists.txt b/unsupported/doc/CMakeLists.txt
new file mode 100644
index 000000000..9e9ab9800
--- /dev/null
+++ b/unsupported/doc/CMakeLists.txt
@@ -0,0 +1,4 @@
+set_directory_properties(PROPERTIES EXCLUDE_FROM_ALL TRUE)
+
+add_subdirectory(examples)
+add_subdirectory(snippets)
diff --git a/unsupported/doc/Doxyfile.in b/unsupported/doc/Doxyfile.in
new file mode 100644
index 000000000..1facf2985
--- /dev/null
+++ b/unsupported/doc/Doxyfile.in
@@ -0,0 +1,1460 @@
+# This file describes the settings to be used by the documentation system
+# doxygen (www.doxygen.org) for a project
+#
+# All text after a hash (#) is considered a comment and will be ignored
+# The format is:
+# TAG = value [value, ...]
+# For lists items can also be appended using:
+# TAG += value [value, ...]
+# Values that contain spaces should be placed between quotes (" ")
+
+#---------------------------------------------------------------------------
+# Project related configuration options
+#---------------------------------------------------------------------------
+
+# This tag specifies the encoding used for all characters in the config file
+# that follow. The default is UTF-8 which is also the encoding used for all
+# text before the first occurrence of this tag. Doxygen uses libiconv (or the
+# iconv built into libc) for the transcoding. See
+# http://www.gnu.org/software/libiconv for the list of possible encodings.
+
+DOXYFILE_ENCODING = UTF-8
+
+# The PROJECT_NAME tag is a single word (or a sequence of words surrounded
+# by quotes) that should identify the project.
+
+PROJECT_NAME = Eigen - unsupported modules
+
+# The PROJECT_NUMBER tag can be used to enter a project or revision number.
+# This could be handy for archiving the generated documentation or
+# if some version control system is used.
+
+#EIGEN_VERSION is set in the root CMakeLists.txt
+PROJECT_NUMBER = "${EIGEN_VERSION}"
+
+# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute)
+# base path where the generated documentation will be put.
+# If a relative path is entered, it will be relative to the location
+# where doxygen was started. If left blank the current directory will be used.
+
+OUTPUT_DIRECTORY = "${Eigen_BINARY_DIR}/doc/unsupported"
+
+# If the CREATE_SUBDIRS tag is set to YES, then doxygen will create
+# 4096 sub-directories (in 2 levels) under the output directory of each output
+# format and will distribute the generated files over these directories.
+# Enabling this option can be useful when feeding doxygen a huge amount of
+# source files, where putting all generated files in the same directory would
+# otherwise cause performance problems for the file system.
+
+CREATE_SUBDIRS = NO
+
+# The OUTPUT_LANGUAGE tag is used to specify the language in which all
+# documentation generated by doxygen is written. Doxygen will use this
+# information to generate all constant output in the proper language.
+# The default language is English, other supported languages are:
+# Afrikaans, Arabic, Brazilian, Catalan, Chinese, Chinese-Traditional,
+# Croatian, Czech, Danish, Dutch, Farsi, Finnish, French, German, Greek,
+# Hungarian, Italian, Japanese, Japanese-en (Japanese with English messages),
+# Korean, Korean-en, Lithuanian, Norwegian, Macedonian, Persian, Polish,
+# Portuguese, Romanian, Russian, Serbian, Slovak, Slovene, Spanish, Swedish,
+# and Ukrainian.
+
+OUTPUT_LANGUAGE = English
+
+# If the BRIEF_MEMBER_DESC tag is set to YES (the default) Doxygen will
+# include brief member descriptions after the members that are listed in
+# the file and class documentation (similar to JavaDoc).
+# Set to NO to disable this.
+
+BRIEF_MEMBER_DESC = YES
+
+# If the REPEAT_BRIEF tag is set to YES (the default) Doxygen will prepend
+# the brief description of a member or function before the detailed description.
+# Note: if both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the
+# brief descriptions will be completely suppressed.
+
+REPEAT_BRIEF = YES
+
+# This tag implements a quasi-intelligent brief description abbreviator
+# that is used to form the text in various listings. Each string
+# in this list, if found as the leading text of the brief description, will be
+# stripped from the text and the result after processing the whole list, is
+# used as the annotated text. Otherwise, the brief description is used as-is.
+# If left blank, the following values are used ("$name" is automatically
+# replaced with the name of the entity): "The $name class" "The $name widget"
+# "The $name file" "is" "provides" "specifies" "contains"
+# "represents" "a" "an" "the"
+
+ABBREVIATE_BRIEF = "The $name class" \
+ "The $name widget" \
+ "The $name file" \
+ is \
+ provides \
+ specifies \
+ contains \
+ represents \
+ a \
+ an \
+ the
+
+# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then
+# Doxygen will generate a detailed section even if there is only a brief
+# description.
+
+ALWAYS_DETAILED_SEC = NO
+
+# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all
+# inherited members of a class in the documentation of that class as if those
+# members were ordinary class members. Constructors, destructors and assignment
+# operators of the base classes will not be shown.
+
+INLINE_INHERITED_MEMB = NO
+
+# If the FULL_PATH_NAMES tag is set to YES then Doxygen will prepend the full
+# path before files name in the file list and in the header files. If set
+# to NO the shortest path that makes the file name unique will be used.
+
+FULL_PATH_NAMES = NO
+
+# If the FULL_PATH_NAMES tag is set to YES then the STRIP_FROM_PATH tag
+# can be used to strip a user-defined part of the path. Stripping is
+# only done if one of the specified strings matches the left-hand part of
+# the path. The tag can be used to show relative paths in the file list.
+# If left blank the directory from which doxygen is run is used as the
+# path to strip.
+
+STRIP_FROM_PATH =
+
+# The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of
+# the path mentioned in the documentation of a class, which tells
+# the reader which header file to include in order to use a class.
+# If left blank only the name of the header file containing the class
+# definition is used. Otherwise one should specify the include paths that
+# are normally passed to the compiler using the -I flag.
+
+STRIP_FROM_INC_PATH =
+
+# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter
+# (but less readable) file names. This can be useful is your file systems
+# doesn't support long names like on DOS, Mac, or CD-ROM.
+
+SHORT_NAMES = NO
+
+# If the JAVADOC_AUTOBRIEF tag is set to YES then Doxygen
+# will interpret the first line (until the first dot) of a JavaDoc-style
+# comment as the brief description. If set to NO, the JavaDoc
+# comments will behave just like regular Qt-style comments
+# (thus requiring an explicit @brief command for a brief description.)
+
+JAVADOC_AUTOBRIEF = NO
+
+# If the QT_AUTOBRIEF tag is set to YES then Doxygen will
+# interpret the first line (until the first dot) of a Qt-style
+# comment as the brief description. If set to NO, the comments
+# will behave just like regular Qt-style comments (thus requiring
+# an explicit \brief command for a brief description.)
+
+QT_AUTOBRIEF = NO
+
+# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make Doxygen
+# treat a multi-line C++ special comment block (i.e. a block of //! or ///
+# comments) as a brief description. This used to be the default behaviour.
+# The new default is to treat a multi-line C++ comment block as a detailed
+# description. Set this tag to YES if you prefer the old behaviour instead.
+
+MULTILINE_CPP_IS_BRIEF = NO
+
+# If the DETAILS_AT_TOP tag is set to YES then Doxygen
+# will output the detailed description near the top, like JavaDoc.
+# If set to NO, the detailed description appears after the member
+# documentation.
+
+DETAILS_AT_TOP = YES
+
+# If the INHERIT_DOCS tag is set to YES (the default) then an undocumented
+# member inherits the documentation from any documented member that it
+# re-implements.
+
+INHERIT_DOCS = YES
+
+# If the SEPARATE_MEMBER_PAGES tag is set to YES, then doxygen will produce
+# a new page for each member. If set to NO, the documentation of a member will
+# be part of the file/class/namespace that contains it.
+
+SEPARATE_MEMBER_PAGES = NO
+
+# The TAB_SIZE tag can be used to set the number of spaces in a tab.
+# Doxygen uses this value to replace tabs by spaces in code fragments.
+
+TAB_SIZE = 8
+
+# This tag can be used to specify a number of aliases that acts
+# as commands in the documentation. An alias has the form "name=value".
+# For example adding "sideeffect=\par Side Effects:\n" will allow you to
+# put the command \sideeffect (or @sideeffect) in the documentation, which
+# will result in a user-defined paragraph with heading "Side Effects:".
+# You can put \n's in the value part of an alias to insert newlines.
+
+ALIASES = "only_for_vectors=This is only for vectors (either row-vectors or column-vectors), i.e. matrices which are known at compile-time to have either one row or one column." \
+ "array_module=This is defined in the %Array module. \code #include <Eigen/Array> \endcode" \
+ "lu_module=This is defined in the %LU module. \code #include <Eigen/LU> \endcode" \
+ "cholesky_module=This is defined in the %Cholesky module. \code #include <Eigen/Cholesky> \endcode" \
+ "qr_module=This is defined in the %QR module. \code #include <Eigen/QR> \endcode" \
+ "svd_module=This is defined in the %SVD module. \code #include <Eigen/SVD> \endcode" \
+ "geometry_module=This is defined in the %Geometry module. \code #include <Eigen/Geometry> \endcode" \
+ "label=\bug" \
+ "nonstableyet=\warning This is not considered to be part of the stable public API yet. Changes may happen in future releases. See \ref Experimental \"Experimental parts of Eigen\""
+
+# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C
+# sources only. Doxygen will then generate output that is more tailored for C.
+# For instance, some of the names that are used will be different. The list
+# of all members will be omitted, etc.
+
+OPTIMIZE_OUTPUT_FOR_C = NO
+
+# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java
+# sources only. Doxygen will then generate output that is more tailored for
+# Java. For instance, namespaces will be presented as packages, qualified
+# scopes will look different, etc.
+
+OPTIMIZE_OUTPUT_JAVA = NO
+
+# Set the OPTIMIZE_FOR_FORTRAN tag to YES if your project consists of Fortran
+# sources only. Doxygen will then generate output that is more tailored for
+# Fortran.
+
+OPTIMIZE_FOR_FORTRAN = NO
+
+# Set the OPTIMIZE_OUTPUT_VHDL tag to YES if your project consists of VHDL
+# sources. Doxygen will then generate output that is tailored for
+# VHDL.
+
+OPTIMIZE_OUTPUT_VHDL = NO
+
+# If you use STL classes (i.e. std::string, std::vector, etc.) but do not want
+# to include (a tag file for) the STL sources as input, then you should
+# set this tag to YES in order to let doxygen match functions declarations and
+# definitions whose arguments contain STL classes (e.g. func(std::string); v.s.
+# func(std::string) {}). This also make the inheritance and collaboration
+# diagrams that involve STL classes more complete and accurate.
+
+BUILTIN_STL_SUPPORT = NO
+
+# If you use Microsoft's C++/CLI language, you should set this option to YES to
+# enable parsing support.
+
+CPP_CLI_SUPPORT = NO
+
+# Set the SIP_SUPPORT tag to YES if your project consists of sip sources only.
+# Doxygen will parse them like normal C++ but will assume all classes use public
+# instead of private inheritance when no explicit protection keyword is present.
+
+SIP_SUPPORT = NO
+
+# For Microsoft's IDL there are propget and propput attributes to indicate getter
+# and setter methods for a property. Setting this option to YES (the default)
+# will make doxygen to replace the get and set methods by a property in the
+# documentation. This will only work if the methods are indeed getting or
+# setting a simple type. If this is not the case, or you want to show the
+# methods anyway, you should set this option to NO.
+
+IDL_PROPERTY_SUPPORT = YES
+
+# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC
+# tag is set to YES, then doxygen will reuse the documentation of the first
+# member in the group (if any) for the other members of the group. By default
+# all members of a group must be documented explicitly.
+
+DISTRIBUTE_GROUP_DOC = NO
+
+# Set the SUBGROUPING tag to YES (the default) to allow class member groups of
+# the same type (for instance a group of public functions) to be put as a
+# subgroup of that type (e.g. under the Public Functions section). Set it to
+# NO to prevent subgrouping. Alternatively, this can be done per class using
+# the \nosubgrouping command.
+
+SUBGROUPING = YES
+
+# When TYPEDEF_HIDES_STRUCT is enabled, a typedef of a struct, union, or enum
+# is documented as struct, union, or enum with the name of the typedef. So
+# typedef struct TypeS {} TypeT, will appear in the documentation as a struct
+# with name TypeT. When disabled the typedef will appear as a member of a file,
+# namespace, or class. And the struct will be named TypeS. This can typically
+# be useful for C code in case the coding convention dictates that all compound
+# types are typedef'ed and only the typedef is referenced, never the tag name.
+
+TYPEDEF_HIDES_STRUCT = NO
+
+#---------------------------------------------------------------------------
+# Build related configuration options
+#---------------------------------------------------------------------------
+
+# If the EXTRACT_ALL tag is set to YES doxygen will assume all entities in
+# documentation are documented, even if no documentation was available.
+# Private class members and static file members will be hidden unless
+# the EXTRACT_PRIVATE and EXTRACT_STATIC tags are set to YES
+
+EXTRACT_ALL = NO
+
+# If the EXTRACT_PRIVATE tag is set to YES all private members of a class
+# will be included in the documentation.
+
+EXTRACT_PRIVATE = NO
+
+# If the EXTRACT_STATIC tag is set to YES all static members of a file
+# will be included in the documentation.
+
+EXTRACT_STATIC = NO
+
+# If the EXTRACT_LOCAL_CLASSES tag is set to YES classes (and structs)
+# defined locally in source files will be included in the documentation.
+# If set to NO only classes defined in header files are included.
+
+EXTRACT_LOCAL_CLASSES = NO
+
+# This flag is only useful for Objective-C code. When set to YES local
+# methods, which are defined in the implementation section but not in
+# the interface are included in the documentation.
+# If set to NO (the default) only methods in the interface are included.
+
+EXTRACT_LOCAL_METHODS = NO
+
+# If this flag is set to YES, the members of anonymous namespaces will be
+# extracted and appear in the documentation as a namespace called
+# 'anonymous_namespace{file}', where file will be replaced with the base
+# name of the file that contains the anonymous namespace. By default
+# anonymous namespace are hidden.
+
+EXTRACT_ANON_NSPACES = NO
+
+# If the HIDE_UNDOC_MEMBERS tag is set to YES, Doxygen will hide all
+# undocumented members of documented classes, files or namespaces.
+# If set to NO (the default) these members will be included in the
+# various overviews, but no documentation section is generated.
+# This option has no effect if EXTRACT_ALL is enabled.
+
+HIDE_UNDOC_MEMBERS = NO
+
+# If the HIDE_UNDOC_CLASSES tag is set to YES, Doxygen will hide all
+# undocumented classes that are normally visible in the class hierarchy.
+# If set to NO (the default) these classes will be included in the various
+# overviews. This option has no effect if EXTRACT_ALL is enabled.
+
+HIDE_UNDOC_CLASSES = YES
+
+# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, Doxygen will hide all
+# friend (class|struct|union) declarations.
+# If set to NO (the default) these declarations will be included in the
+# documentation.
+
+HIDE_FRIEND_COMPOUNDS = YES
+
+# If the HIDE_IN_BODY_DOCS tag is set to YES, Doxygen will hide any
+# documentation blocks found inside the body of a function.
+# If set to NO (the default) these blocks will be appended to the
+# function's detailed documentation block.
+
+HIDE_IN_BODY_DOCS = NO
+
+# The INTERNAL_DOCS tag determines if documentation
+# that is typed after a \internal command is included. If the tag is set
+# to NO (the default) then the documentation will be excluded.
+# Set it to YES to include the internal documentation.
+
+INTERNAL_DOCS = NO
+
+# If the CASE_SENSE_NAMES tag is set to NO then Doxygen will only generate
+# file names in lower-case letters. If set to YES upper-case letters are also
+# allowed. This is useful if you have classes or files whose names only differ
+# in case and if your file system supports case sensitive file names. Windows
+# and Mac users are advised to set this option to NO.
+
+CASE_SENSE_NAMES = YES
+
+# If the HIDE_SCOPE_NAMES tag is set to NO (the default) then Doxygen
+# will show members with their full class and namespace scopes in the
+# documentation. If set to YES the scope will be hidden.
+
+HIDE_SCOPE_NAMES = YES
+
+# If the SHOW_INCLUDE_FILES tag is set to YES (the default) then Doxygen
+# will put a list of the files that are included by a file in the documentation
+# of that file.
+
+SHOW_INCLUDE_FILES = YES
+
+# If the INLINE_INFO tag is set to YES (the default) then a tag [inline]
+# is inserted in the documentation for inline members.
+
+INLINE_INFO = YES
+
+# If the SORT_MEMBER_DOCS tag is set to YES (the default) then doxygen
+# will sort the (detailed) documentation of file and class members
+# alphabetically by member name. If set to NO the members will appear in
+# declaration order.
+
+SORT_MEMBER_DOCS = YES
+
+# If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the
+# brief documentation of file, namespace and class members alphabetically
+# by member name. If set to NO (the default) the members will appear in
+# declaration order.
+
+SORT_BRIEF_DOCS = YES
+
+# If the SORT_GROUP_NAMES tag is set to YES then doxygen will sort the
+# hierarchy of group names into alphabetical order. If set to NO (the default)
+# the group names will appear in their defined order.
+
+SORT_GROUP_NAMES = NO
+
+# If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be
+# sorted by fully-qualified names, including namespaces. If set to
+# NO (the default), the class list will be sorted only by class name,
+# not including the namespace part.
+# Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES.
+# Note: This option applies only to the class list, not to the
+# alphabetical list.
+
+SORT_BY_SCOPE_NAME = NO
+
+# The GENERATE_TODOLIST tag can be used to enable (YES) or
+# disable (NO) the todo list. This list is created by putting \todo
+# commands in the documentation.
+
+GENERATE_TODOLIST = NO
+
+# The GENERATE_TESTLIST tag can be used to enable (YES) or
+# disable (NO) the test list. This list is created by putting \test
+# commands in the documentation.
+
+GENERATE_TESTLIST = NO
+
+# The GENERATE_BUGLIST tag can be used to enable (YES) or
+# disable (NO) the bug list. This list is created by putting \bug
+# commands in the documentation.
+
+GENERATE_BUGLIST = NO
+
+# The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or
+# disable (NO) the deprecated list. This list is created by putting
+# \deprecated commands in the documentation.
+
+GENERATE_DEPRECATEDLIST= NO
+
+# The ENABLED_SECTIONS tag can be used to enable conditional
+# documentation sections, marked by \if sectionname ... \endif.
+
+ENABLED_SECTIONS =
+
+# The MAX_INITIALIZER_LINES tag determines the maximum number of lines
+# the initial value of a variable or define consists of for it to appear in
+# the documentation. If the initializer consists of more lines than specified
+# here it will be hidden. Use a value of 0 to hide initializers completely.
+# The appearance of the initializer of individual variables and defines in the
+# documentation can be controlled using \showinitializer or \hideinitializer
+# command in the documentation regardless of this setting.
+
+MAX_INITIALIZER_LINES = 0
+
+# Set the SHOW_USED_FILES tag to NO to disable the list of files generated
+# at the bottom of the documentation of classes and structs. If set to YES the
+# list will mention the files that were used to generate the documentation.
+
+SHOW_USED_FILES = YES
+
+# If the sources in your project are distributed over multiple directories
+# then setting the SHOW_DIRECTORIES tag to YES will show the directory hierarchy
+# in the documentation. The default is NO.
+
+SHOW_DIRECTORIES = NO
+
+# Set the SHOW_FILES tag to NO to disable the generation of the Files page.
+# This will remove the Files entry from the Quick Index and from the
+# Folder Tree View (if specified). The default is YES.
+
+SHOW_FILES = YES
+
+# Set the SHOW_NAMESPACES tag to NO to disable the generation of the
+# Namespaces page. This will remove the Namespaces entry from the Quick Index
+# and from the Folder Tree View (if specified). The default is YES.
+
+SHOW_NAMESPACES = NO
+
+# The FILE_VERSION_FILTER tag can be used to specify a program or script that
+# doxygen should invoke to get the current version for each file (typically from
+# the version control system). Doxygen will invoke the program by executing (via
+# popen()) the command <command> <input-file>, where <command> is the value of
+# the FILE_VERSION_FILTER tag, and <input-file> is the name of an input file
+# provided by doxygen. Whatever the program writes to standard output
+# is used as the file version. See the manual for examples.
+
+FILE_VERSION_FILTER =
+
+#---------------------------------------------------------------------------
+# configuration options related to warning and progress messages
+#---------------------------------------------------------------------------
+
+# The QUIET tag can be used to turn on/off the messages that are generated
+# by doxygen. Possible values are YES and NO. If left blank NO is used.
+
+QUIET = NO
+
+# The WARNINGS tag can be used to turn on/off the warning messages that are
+# generated by doxygen. Possible values are YES and NO. If left blank
+# NO is used.
+
+WARNINGS = YES
+
+# If WARN_IF_UNDOCUMENTED is set to YES, then doxygen will generate warnings
+# for undocumented members. If EXTRACT_ALL is set to YES then this flag will
+# automatically be disabled.
+
+WARN_IF_UNDOCUMENTED = NO
+
+# If WARN_IF_DOC_ERROR is set to YES, doxygen will generate warnings for
+# potential errors in the documentation, such as not documenting some
+# parameters in a documented function, or documenting parameters that
+# don't exist or using markup commands wrongly.
+
+WARN_IF_DOC_ERROR = YES
+
+# This WARN_NO_PARAMDOC option can be abled to get warnings for
+# functions that are documented, but have no documentation for their parameters
+# or return value. If set to NO (the default) doxygen will only warn about
+# wrong or incomplete parameter documentation, but not about the absence of
+# documentation.
+
+WARN_NO_PARAMDOC = NO
+
+# The WARN_FORMAT tag determines the format of the warning messages that
+# doxygen can produce. The string should contain the $file, $line, and $text
+# tags, which will be replaced by the file and line number from which the
+# warning originated and the warning text. Optionally the format may contain
+# $version, which will be replaced by the version of the file (if it could
+# be obtained via FILE_VERSION_FILTER)
+
+WARN_FORMAT = "$file:$line: $text"
+
+# The WARN_LOGFILE tag can be used to specify a file to which warning
+# and error messages should be written. If left blank the output is written
+# to stderr.
+
+WARN_LOGFILE =
+
+#---------------------------------------------------------------------------
+# configuration options related to the input files
+#---------------------------------------------------------------------------
+
+# The INPUT tag can be used to specify the files and/or directories that contain
+# documented source files. You may enter file names like "myfile.cpp" or
+# directories like "/usr/src/myproject". Separate the files or directories
+# with spaces.
+
+INPUT = "${Eigen_SOURCE_DIR}/unsupported/Eigen" \
+ "${Eigen_SOURCE_DIR}/unsupported/doc"
+
+# This tag can be used to specify the character encoding of the source files
+# that doxygen parses. Internally doxygen uses the UTF-8 encoding, which is
+# also the default input encoding. Doxygen uses libiconv (or the iconv built
+# into libc) for the transcoding. See http://www.gnu.org/software/libiconv for
+# the list of possible encodings.
+
+INPUT_ENCODING = UTF-8
+
+# If the value of the INPUT tag contains directories, you can use the
+# FILE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp
+# and *.h) to filter out the source-files in the directories. If left
+# blank the following patterns are tested:
+# *.c *.cc *.cxx *.cpp *.c++ *.java *.ii *.ixx *.ipp *.i++ *.inl *.h *.hh *.hxx
+# *.hpp *.h++ *.idl *.odl *.cs *.php *.php3 *.inc *.m *.mm *.py *.f90
+
+FILE_PATTERNS = *
+
+# The RECURSIVE tag can be used to turn specify whether or not subdirectories
+# should be searched for input files as well. Possible values are YES and NO.
+# If left blank NO is used.
+
+RECURSIVE = YES
+
+# The EXCLUDE tag can be used to specify files and/or directories that should
+# excluded from the INPUT source files. This way you can easily exclude a
+# subdirectory from a directory tree whose root is specified with the INPUT tag.
+
+EXCLUDE = "${Eigen_SOURCE_DIR}/unsupported/doc/examples" \
+ "${Eigen_SOURCE_DIR}/unsupported/doc/snippets"
+
+# The EXCLUDE_SYMLINKS tag can be used select whether or not files or
+# directories that are symbolic links (a Unix filesystem feature) are excluded
+# from the input.
+
+EXCLUDE_SYMLINKS = NO
+
+# If the value of the INPUT tag contains directories, you can use the
+# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude
+# certain files from those directories. Note that the wildcards are matched
+# against the file with absolute path, so to exclude all test directories
+# for example use the pattern */test/*
+
+EXCLUDE_PATTERNS = CMake* \
+ *.txt \
+ *.sh \
+ *.diff \
+ *.orig \
+ diff \
+ *~
+
+# The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names
+# (namespaces, classes, functions, etc.) that should be excluded from the
+# output. The symbol name can be a fully qualified name, a word, or if the
+# wildcard * is used, a substring. Examples: ANamespace, AClass,
+# AClass::ANamespace, ANamespace::*Test
+
+EXCLUDE_SYMBOLS = MatrixBase<* MapBase<* RotationBase<* Matrix<*
+
+# The EXAMPLE_PATH tag can be used to specify one or more files or
+# directories that contain example code fragments that are included (see
+# the \include command).
+
+EXAMPLE_PATH = "${Eigen_SOURCE_DIR}/doc/snippets" \
+ "${Eigen_BINARY_DIR}/doc/snippets" \
+ "${Eigen_SOURCE_DIR}/doc/examples" \
+ "${Eigen_BINARY_DIR}/doc/examples" \
+ "${Eigen_SOURCE_DIR}/unsupported/doc/snippets" \
+ "${Eigen_BINARY_DIR}/unsupported/doc/snippets" \
+ "${Eigen_SOURCE_DIR}/unsupported/doc/examples" \
+ "${Eigen_BINARY_DIR}/unsupported/doc/examples"
+
+# If the value of the EXAMPLE_PATH tag contains directories, you can use the
+# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp
+# and *.h) to filter out the source-files in the directories. If left
+# blank all files are included.
+
+EXAMPLE_PATTERNS = *
+
+# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be
+# searched for input files to be used with the \include or \dontinclude
+# commands irrespective of the value of the RECURSIVE tag.
+# Possible values are YES and NO. If left blank NO is used.
+
+EXAMPLE_RECURSIVE = NO
+
+# The IMAGE_PATH tag can be used to specify one or more files or
+# directories that contain image that are included in the documentation (see
+# the \image command).
+
+IMAGE_PATH =
+
+# The INPUT_FILTER tag can be used to specify a program that doxygen should
+# invoke to filter for each input file. Doxygen will invoke the filter program
+# by executing (via popen()) the command <filter> <input-file>, where <filter>
+# is the value of the INPUT_FILTER tag, and <input-file> is the name of an
+# input file. Doxygen will then use the output that the filter program writes
+# to standard output. If FILTER_PATTERNS is specified, this tag will be
+# ignored.
+
+INPUT_FILTER =
+
+# The FILTER_PATTERNS tag can be used to specify filters on a per file pattern
+# basis. Doxygen will compare the file name with each pattern and apply the
+# filter if there is a match. The filters are a list of the form:
+# pattern=filter (like *.cpp=my_cpp_filter). See INPUT_FILTER for further
+# info on how filters are used. If FILTER_PATTERNS is empty, INPUT_FILTER
+# is applied to all files.
+
+FILTER_PATTERNS =
+
+# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using
+# INPUT_FILTER) will be used to filter the input files when producing source
+# files to browse (i.e. when SOURCE_BROWSER is set to YES).
+
+FILTER_SOURCE_FILES = NO
+
+#---------------------------------------------------------------------------
+# configuration options related to source browsing
+#---------------------------------------------------------------------------
+
+# If the SOURCE_BROWSER tag is set to YES then a list of source files will
+# be generated. Documented entities will be cross-referenced with these sources.
+# Note: To get rid of all source code in the generated output, make sure also
+# VERBATIM_HEADERS is set to NO.
+
+SOURCE_BROWSER = NO
+
+# Setting the INLINE_SOURCES tag to YES will include the body
+# of functions and classes directly in the documentation.
+
+INLINE_SOURCES = NO
+
+# Setting the STRIP_CODE_COMMENTS tag to YES (the default) will instruct
+# doxygen to hide any special comment blocks from generated source code
+# fragments. Normal C and C++ comments will always remain visible.
+
+STRIP_CODE_COMMENTS = YES
+
+# If the REFERENCED_BY_RELATION tag is set to YES
+# then for each documented function all documented
+# functions referencing it will be listed.
+
+REFERENCED_BY_RELATION = YES
+
+# If the REFERENCES_RELATION tag is set to YES
+# then for each documented function all documented entities
+# called/used by that function will be listed.
+
+REFERENCES_RELATION = YES
+
+# If the REFERENCES_LINK_SOURCE tag is set to YES (the default)
+# and SOURCE_BROWSER tag is set to YES, then the hyperlinks from
+# functions in REFERENCES_RELATION and REFERENCED_BY_RELATION lists will
+# link to the source code. Otherwise they will link to the documentstion.
+
+REFERENCES_LINK_SOURCE = YES
+
+# If the USE_HTAGS tag is set to YES then the references to source code
+# will point to the HTML generated by the htags(1) tool instead of doxygen
+# built-in source browser. The htags tool is part of GNU's global source
+# tagging system (see http://www.gnu.org/software/global/global.html). You
+# will need version 4.8.6 or higher.
+
+USE_HTAGS = NO
+
+# If the VERBATIM_HEADERS tag is set to YES (the default) then Doxygen
+# will generate a verbatim copy of the header file for each class for
+# which an include is specified. Set to NO to disable this.
+
+VERBATIM_HEADERS = YES
+
+#---------------------------------------------------------------------------
+# configuration options related to the alphabetical class index
+#---------------------------------------------------------------------------
+
+# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index
+# of all compounds will be generated. Enable this if the project
+# contains a lot of classes, structs, unions or interfaces.
+
+ALPHABETICAL_INDEX = NO
+
+# If the alphabetical index is enabled (see ALPHABETICAL_INDEX) then
+# the COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns
+# in which this list will be split (can be a number in the range [1..20])
+
+COLS_IN_ALPHA_INDEX = 5
+
+# In case all classes in a project start with a common prefix, all
+# classes will be put under the same header in the alphabetical index.
+# The IGNORE_PREFIX tag can be used to specify one or more prefixes that
+# should be ignored while generating the index headers.
+
+IGNORE_PREFIX =
+
+#---------------------------------------------------------------------------
+# configuration options related to the HTML output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_HTML tag is set to YES (the default) Doxygen will
+# generate HTML output.
+
+GENERATE_HTML = YES
+
+# The HTML_OUTPUT tag is used to specify where the HTML docs will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be
+# put in front of it. If left blank `html' will be used as the default path.
+
+HTML_OUTPUT = "${Eigen_BINARY_DIR}/doc/html/unsupported"
+
+# The HTML_FILE_EXTENSION tag can be used to specify the file extension for
+# each generated HTML page (for example: .htm,.php,.asp). If it is left blank
+# doxygen will generate files with .html extension.
+
+HTML_FILE_EXTENSION = .html
+
+# The HTML_HEADER tag can be used to specify a personal HTML header for
+# each generated HTML page. If it is left blank doxygen will generate a
+# standard header.
+
+HTML_HEADER = "${Eigen_BINARY_DIR}/doc/eigendoxy_header.html"
+
+# The HTML_FOOTER tag can be used to specify a personal HTML footer for
+# each generated HTML page. If it is left blank doxygen will generate a
+# standard footer.
+
+# the footer has not been customized yet, so let's use the default one
+# ${Eigen_BINARY_DIR}/doc/eigendoxy_footer.html
+HTML_FOOTER =
+
+# The HTML_STYLESHEET tag can be used to specify a user-defined cascading
+# style sheet that is used by each HTML page. It can be used to
+# fine-tune the look of the HTML output. If the tag is left blank doxygen
+# will generate a default style sheet. Note that doxygen will try to copy
+# the style sheet file to the HTML output directory, so don't put your own
+# stylesheet in the HTML output directory as well, or it will be erased!
+
+HTML_STYLESHEET = "${Eigen_SOURCE_DIR}/doc/eigendoxy.css"
+
+# If the HTML_ALIGN_MEMBERS tag is set to YES, the members of classes,
+# files or namespaces will be aligned in HTML using tables. If set to
+# NO a bullet list will be used.
+
+HTML_ALIGN_MEMBERS = YES
+
+# If the GENERATE_HTMLHELP tag is set to YES, additional index files
+# will be generated that can be used as input for tools like the
+# Microsoft HTML help workshop to generate a compiled HTML help file (.chm)
+# of the generated HTML documentation.
+
+GENERATE_HTMLHELP = NO
+
+# If the GENERATE_DOCSET tag is set to YES, additional index files
+# will be generated that can be used as input for Apple's Xcode 3
+# integrated development environment, introduced with OSX 10.5 (Leopard).
+# To create a documentation set, doxygen will generate a Makefile in the
+# HTML output directory. Running make will produce the docset in that
+# directory and running "make install" will install the docset in
+# ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find
+# it at startup.
+
+GENERATE_DOCSET = NO
+
+# When GENERATE_DOCSET tag is set to YES, this tag determines the name of the
+# feed. A documentation feed provides an umbrella under which multiple
+# documentation sets from a single provider (such as a company or product suite)
+# can be grouped.
+
+DOCSET_FEEDNAME = "Doxygen generated docs"
+
+# When GENERATE_DOCSET tag is set to YES, this tag specifies a string that
+# should uniquely identify the documentation set bundle. This should be a
+# reverse domain-name style string, e.g. com.mycompany.MyDocSet. Doxygen
+# will append .docset to the name.
+
+DOCSET_BUNDLE_ID = org.doxygen.Project
+
+# If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML
+# documentation will contain sections that can be hidden and shown after the
+# page has loaded. For this to work a browser that supports
+# JavaScript and DHTML is required (for instance Mozilla 1.0+, Firefox
+# Netscape 6.0+, Internet explorer 5.0+, Konqueror, or Safari).
+
+HTML_DYNAMIC_SECTIONS = NO
+
+# If the GENERATE_HTMLHELP tag is set to YES, the CHM_FILE tag can
+# be used to specify the file name of the resulting .chm file. You
+# can add a path in front of the file if the result should not be
+# written to the html output directory.
+
+CHM_FILE =
+
+# If the GENERATE_HTMLHELP tag is set to YES, the HHC_LOCATION tag can
+# be used to specify the location (absolute path including file name) of
+# the HTML help compiler (hhc.exe). If non-empty doxygen will try to run
+# the HTML help compiler on the generated index.hhp.
+
+HHC_LOCATION =
+
+# If the GENERATE_HTMLHELP tag is set to YES, the GENERATE_CHI flag
+# controls if a separate .chi index file is generated (YES) or that
+# it should be included in the master .chm file (NO).
+
+GENERATE_CHI = NO
+
+# If the GENERATE_HTMLHELP tag is set to YES, the CHM_INDEX_ENCODING
+# is used to encode HtmlHelp index (hhk), content (hhc) and project file
+# content.
+
+CHM_INDEX_ENCODING =
+
+# If the GENERATE_HTMLHELP tag is set to YES, the BINARY_TOC flag
+# controls whether a binary table of contents is generated (YES) or a
+# normal table of contents (NO) in the .chm file.
+
+BINARY_TOC = NO
+
+# The TOC_EXPAND flag can be set to YES to add extra items for group members
+# to the contents of the HTML help documentation and to the tree view.
+
+TOC_EXPAND = NO
+
+# The DISABLE_INDEX tag can be used to turn on/off the condensed index at
+# top of each HTML page. The value NO (the default) enables the index and
+# the value YES disables it.
+
+DISABLE_INDEX = NO
+
+# This tag can be used to set the number of enum values (range [1..20])
+# that doxygen will group on one line in the generated HTML documentation.
+
+ENUM_VALUES_PER_LINE = 1
+
+# The GENERATE_TREEVIEW tag is used to specify whether a tree-like index
+# structure should be generated to display hierarchical information.
+# If the tag value is set to FRAME, a side panel will be generated
+# containing a tree-like index structure (just like the one that
+# is generated for HTML Help). For this to work a browser that supports
+# JavaScript, DHTML, CSS and frames is required (for instance Mozilla 1.0+,
+# Netscape 6.0+, Internet explorer 5.0+, or Konqueror). Windows users are
+# probably better off using the HTML help feature. Other possible values
+# for this tag are: HIERARCHIES, which will generate the Groups, Directories,
+# and Class Hiererachy pages using a tree view instead of an ordered list;
+# ALL, which combines the behavior of FRAME and HIERARCHIES; and NONE, which
+# disables this behavior completely. For backwards compatibility with previous
+# releases of Doxygen, the values YES and NO are equivalent to FRAME and NONE
+# respectively.
+
+GENERATE_TREEVIEW = NO
+
+# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be
+# used to set the initial width (in pixels) of the frame in which the tree
+# is shown.
+
+TREEVIEW_WIDTH = 250
+
+# Use this tag to change the font size of Latex formulas included
+# as images in the HTML documentation. The default is 10. Note that
+# when you change the font size after a successful doxygen run you need
+# to manually remove any form_*.png images from the HTML output directory
+# to force them to be regenerated.
+
+FORMULA_FONTSIZE = 12
+
+#---------------------------------------------------------------------------
+# configuration options related to the LaTeX output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_LATEX tag is set to YES (the default) Doxygen will
+# generate Latex output.
+
+GENERATE_LATEX = NO
+
+# The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be
+# put in front of it. If left blank `latex' will be used as the default path.
+
+LATEX_OUTPUT = latex
+
+# The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be
+# invoked. If left blank `latex' will be used as the default command name.
+
+LATEX_CMD_NAME = latex
+
+# The MAKEINDEX_CMD_NAME tag can be used to specify the command name to
+# generate index for LaTeX. If left blank `makeindex' will be used as the
+# default command name.
+
+MAKEINDEX_CMD_NAME = makeindex
+
+# If the COMPACT_LATEX tag is set to YES Doxygen generates more compact
+# LaTeX documents. This may be useful for small projects and may help to
+# save some trees in general.
+
+COMPACT_LATEX = NO
+
+# The PAPER_TYPE tag can be used to set the paper type that is used
+# by the printer. Possible values are: a4, a4wide, letter, legal and
+# executive. If left blank a4wide will be used.
+
+PAPER_TYPE = a4wide
+
+# The EXTRA_PACKAGES tag can be to specify one or more names of LaTeX
+# packages that should be included in the LaTeX output.
+
+EXTRA_PACKAGES = amssymb \
+ amsmath
+
+# The LATEX_HEADER tag can be used to specify a personal LaTeX header for
+# the generated latex document. The header should contain everything until
+# the first chapter. If it is left blank doxygen will generate a
+# standard header. Notice: only use this tag if you know what you are doing!
+
+LATEX_HEADER =
+
+# If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated
+# is prepared for conversion to pdf (using ps2pdf). The pdf file will
+# contain links (just like the HTML output) instead of page references
+# This makes the output suitable for online browsing using a pdf viewer.
+
+PDF_HYPERLINKS = NO
+
+# If the USE_PDFLATEX tag is set to YES, pdflatex will be used instead of
+# plain latex in the generated Makefile. Set this option to YES to get a
+# higher quality PDF documentation.
+
+USE_PDFLATEX = NO
+
+# If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \\batchmode.
+# command to the generated LaTeX files. This will instruct LaTeX to keep
+# running if errors occur, instead of asking the user for help.
+# This option is also used when generating formulas in HTML.
+
+LATEX_BATCHMODE = NO
+
+# If LATEX_HIDE_INDICES is set to YES then doxygen will not
+# include the index chapters (such as File Index, Compound Index, etc.)
+# in the output.
+
+LATEX_HIDE_INDICES = NO
+
+#---------------------------------------------------------------------------
+# configuration options related to the RTF output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_RTF tag is set to YES Doxygen will generate RTF output
+# The RTF output is optimized for Word 97 and may not look very pretty with
+# other RTF readers or editors.
+
+GENERATE_RTF = NO
+
+# The RTF_OUTPUT tag is used to specify where the RTF docs will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be
+# put in front of it. If left blank `rtf' will be used as the default path.
+
+RTF_OUTPUT = rtf
+
+# If the COMPACT_RTF tag is set to YES Doxygen generates more compact
+# RTF documents. This may be useful for small projects and may help to
+# save some trees in general.
+
+COMPACT_RTF = NO
+
+# If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated
+# will contain hyperlink fields. The RTF file will
+# contain links (just like the HTML output) instead of page references.
+# This makes the output suitable for online browsing using WORD or other
+# programs which support those fields.
+# Note: wordpad (write) and others do not support links.
+
+RTF_HYPERLINKS = NO
+
+# Load stylesheet definitions from file. Syntax is similar to doxygen's
+# config file, i.e. a series of assignments. You only have to provide
+# replacements, missing definitions are set to their default value.
+
+RTF_STYLESHEET_FILE =
+
+# Set optional variables used in the generation of an rtf document.
+# Syntax is similar to doxygen's config file.
+
+RTF_EXTENSIONS_FILE =
+
+#---------------------------------------------------------------------------
+# configuration options related to the man page output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_MAN tag is set to YES (the default) Doxygen will
+# generate man pages
+
+GENERATE_MAN = NO
+
+# The MAN_OUTPUT tag is used to specify where the man pages will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be
+# put in front of it. If left blank `man' will be used as the default path.
+
+MAN_OUTPUT = man
+
+# The MAN_EXTENSION tag determines the extension that is added to
+# the generated man pages (default is the subroutine's section .3)
+
+MAN_EXTENSION = .3
+
+# If the MAN_LINKS tag is set to YES and Doxygen generates man output,
+# then it will generate one additional man file for each entity
+# documented in the real man page(s). These additional files
+# only source the real man page, but without them the man command
+# would be unable to find the correct page. The default is NO.
+
+MAN_LINKS = NO
+
+#---------------------------------------------------------------------------
+# configuration options related to the XML output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_XML tag is set to YES Doxygen will
+# generate an XML file that captures the structure of
+# the code including all documentation.
+
+GENERATE_XML = NO
+
+# The XML_OUTPUT tag is used to specify where the XML pages will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be
+# put in front of it. If left blank `xml' will be used as the default path.
+
+XML_OUTPUT = xml
+
+# The XML_SCHEMA tag can be used to specify an XML schema,
+# which can be used by a validating XML parser to check the
+# syntax of the XML files.
+
+XML_SCHEMA =
+
+# The XML_DTD tag can be used to specify an XML DTD,
+# which can be used by a validating XML parser to check the
+# syntax of the XML files.
+
+XML_DTD =
+
+# If the XML_PROGRAMLISTING tag is set to YES Doxygen will
+# dump the program listings (including syntax highlighting
+# and cross-referencing information) to the XML output. Note that
+# enabling this will significantly increase the size of the XML output.
+
+XML_PROGRAMLISTING = YES
+
+#---------------------------------------------------------------------------
+# configuration options for the AutoGen Definitions output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_AUTOGEN_DEF tag is set to YES Doxygen will
+# generate an AutoGen Definitions (see autogen.sf.net) file
+# that captures the structure of the code including all
+# documentation. Note that this feature is still experimental
+# and incomplete at the moment.
+
+GENERATE_AUTOGEN_DEF = NO
+
+#---------------------------------------------------------------------------
+# configuration options related to the Perl module output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_PERLMOD tag is set to YES Doxygen will
+# generate a Perl module file that captures the structure of
+# the code including all documentation. Note that this
+# feature is still experimental and incomplete at the
+# moment.
+
+GENERATE_PERLMOD = NO
+
+# If the PERLMOD_LATEX tag is set to YES Doxygen will generate
+# the necessary Makefile rules, Perl scripts and LaTeX code to be able
+# to generate PDF and DVI output from the Perl module output.
+
+PERLMOD_LATEX = NO
+
+# If the PERLMOD_PRETTY tag is set to YES the Perl module output will be
+# nicely formatted so it can be parsed by a human reader. This is useful
+# if you want to understand what is going on. On the other hand, if this
+# tag is set to NO the size of the Perl module output will be much smaller
+# and Perl will parse it just the same.
+
+PERLMOD_PRETTY = YES
+
+# The names of the make variables in the generated doxyrules.make file
+# are prefixed with the string contained in PERLMOD_MAKEVAR_PREFIX.
+# This is useful so different doxyrules.make files included by the same
+# Makefile don't overwrite each other's variables.
+
+PERLMOD_MAKEVAR_PREFIX =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the preprocessor
+#---------------------------------------------------------------------------
+
+# If the ENABLE_PREPROCESSING tag is set to YES (the default) Doxygen will
+# evaluate all C-preprocessor directives found in the sources and include
+# files.
+
+ENABLE_PREPROCESSING = YES
+
+# If the MACRO_EXPANSION tag is set to YES Doxygen will expand all macro
+# names in the source code. If set to NO (the default) only conditional
+# compilation will be performed. Macro expansion can be done in a controlled
+# way by setting EXPAND_ONLY_PREDEF to YES.
+
+MACRO_EXPANSION = YES
+
+# If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES
+# then the macro expansion is limited to the macros specified with the
+# PREDEFINED and EXPAND_AS_DEFINED tags.
+
+EXPAND_ONLY_PREDEF = YES
+
+# If the SEARCH_INCLUDES tag is set to YES (the default) the includes files
+# in the INCLUDE_PATH (see below) will be search if a #include is found.
+
+SEARCH_INCLUDES = YES
+
+# The INCLUDE_PATH tag can be used to specify one or more directories that
+# contain include files that are not input files but should be processed by
+# the preprocessor.
+
+INCLUDE_PATH =
+
+# You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard
+# patterns (like *.h and *.hpp) to filter out the header-files in the
+# directories. If left blank, the patterns specified with FILE_PATTERNS will
+# be used.
+
+INCLUDE_FILE_PATTERNS =
+
+# The PREDEFINED tag can be used to specify one or more macro names that
+# are defined before the preprocessor is started (similar to the -D option of
+# gcc). The argument of the tag is a list of macros of the form: name
+# or name=definition (no spaces). If the definition and the = are
+# omitted =1 is assumed. To prevent a macro definition from being
+# undefined via #undef or recursively expanded use the := operator
+# instead of the = operator.
+
+PREDEFINED = EIGEN_EMPTY_STRUCT \
+ EIGEN_PARSED_BY_DOXYGEN \
+ EIGEN_VECTORIZE \
+ EIGEN_QT_SUPPORT \
+ EIGEN_STRONG_INLINE=inline
+
+# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then
+# this tag can be used to specify a list of macro names that should be expanded.
+# The macro definition that is found in the sources will be used.
+# Use the PREDEFINED tag if you want to use a different macro definition.
+
+EXPAND_AS_DEFINED = EIGEN_MAKE_SCALAR_OPS \
+ EIGEN_MAKE_TYPEDEFS \
+ EIGEN_MAKE_TYPEDEFS_ALL_SIZES \
+ EIGEN_CWISE_UNOP_RETURN_TYPE \
+ EIGEN_CWISE_BINOP_RETURN_TYPE
+
+# If the SKIP_FUNCTION_MACROS tag is set to YES (the default) then
+# doxygen's preprocessor will remove all function-like macros that are alone
+# on a line, have an all uppercase name, and do not end with a semicolon. Such
+# function macros are typically used for boiler-plate code, and will confuse
+# the parser if not removed.
+
+SKIP_FUNCTION_MACROS = YES
+
+#---------------------------------------------------------------------------
+# Configuration::additions related to external references
+#---------------------------------------------------------------------------
+
+# The TAGFILES option can be used to specify one or more tagfiles.
+# Optionally an initial location of the external documentation
+# can be added for each tagfile. The format of a tag file without
+# this location is as follows:
+# TAGFILES = file1 file2 ...
+# Adding location for the tag files is done as follows:
+# TAGFILES = file1=loc1 "file2 = loc2" ...
+# where "loc1" and "loc2" can be relative or absolute paths or
+# URLs. If a location is present for each tag, the installdox tool
+# does not have to be run to correct the links.
+# Note that each tag file must have a unique name
+# (where the name does NOT include the path)
+# If a tag file is not located in the directory in which doxygen
+# is run, you must also specify the path to the tagfile here.
+
+TAGFILES = "${Eigen_BINARY_DIR}/doc/eigen.doxytags"=../
+
+# When a file name is specified after GENERATE_TAGFILE, doxygen will create
+# a tag file that is based on the input files it reads.
+
+GENERATE_TAGFILE = "${Eigen_BINARY_DIR}/doc/eigen-unsupported.doxytags"
+
+# If the ALLEXTERNALS tag is set to YES all external classes will be listed
+# in the class index. If set to NO only the inherited external classes
+# will be listed.
+
+ALLEXTERNALS = NO
+
+# If the EXTERNAL_GROUPS tag is set to YES all external groups will be listed
+# in the modules index. If set to NO, only the current project's groups will
+# be listed.
+
+EXTERNAL_GROUPS = YES
+
+# The PERL_PATH should be the absolute path and name of the perl script
+# interpreter (i.e. the result of `which perl').
+
+PERL_PATH = /usr/bin/perl
+
+#---------------------------------------------------------------------------
+# Configuration options related to the dot tool
+#---------------------------------------------------------------------------
+
+# If the CLASS_DIAGRAMS tag is set to YES (the default) Doxygen will
+# generate a inheritance diagram (in HTML, RTF and LaTeX) for classes with base
+# or super classes. Setting the tag to NO turns the diagrams off. Note that
+# this option is superseded by the HAVE_DOT option below. This is only a
+# fallback. It is recommended to install and use dot, since it yields more
+# powerful graphs.
+
+CLASS_DIAGRAMS = NO
+
+# You can define message sequence charts within doxygen comments using the \msc
+# command. Doxygen will then run the mscgen tool (see
+# http://www.mcternan.me.uk/mscgen/) to produce the chart and insert it in the
+# documentation. The MSCGEN_PATH tag allows you to specify the directory where
+# the mscgen tool resides. If left empty the tool is assumed to be found in the
+# default search path.
+
+MSCGEN_PATH = NO
+
+# If set to YES, the inheritance and collaboration graphs will hide
+# inheritance and usage relations if the target is undocumented
+# or is not a class.
+
+HIDE_UNDOC_RELATIONS = NO
+
+# If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is
+# available from the path. This tool is part of Graphviz, a graph visualization
+# toolkit from AT&T and Lucent Bell Labs. The other options in this section
+# have no effect if this option is set to NO (the default)
+
+HAVE_DOT = NO
+
+# By default doxygen will write a font called FreeSans.ttf to the output
+# directory and reference it in all dot files that doxygen generates. This
+# font does not include all possible unicode characters however, so when you need
+# these (or just want a differently looking font) you can specify the font name
+# using DOT_FONTNAME. You need need to make sure dot is able to find the font,
+# which can be done by putting it in a standard location or by setting the
+# DOTFONTPATH environment variable or by setting DOT_FONTPATH to the directory
+# containing the font.
+
+DOT_FONTNAME = FreeSans
+
+# By default doxygen will tell dot to use the output directory to look for the
+# FreeSans.ttf font (which doxygen will put there itself). If you specify a
+# different font using DOT_FONTNAME you can set the path where dot
+# can find it using this tag.
+
+DOT_FONTPATH =
+
+# If the CLASS_GRAPH and HAVE_DOT tags are set to YES then doxygen
+# will generate a graph for each documented class showing the direct and
+# indirect inheritance relations. Setting this tag to YES will force the
+# the CLASS_DIAGRAMS tag to NO.
+
+CLASS_GRAPH = NO
+
+# If the COLLABORATION_GRAPH and HAVE_DOT tags are set to YES then doxygen
+# will generate a graph for each documented class showing the direct and
+# indirect implementation dependencies (inheritance, containment, and
+# class references variables) of the class with other documented classes.
+
+COLLABORATION_GRAPH = NO
+
+# If the GROUP_GRAPHS and HAVE_DOT tags are set to YES then doxygen
+# will generate a graph for groups, showing the direct groups dependencies
+
+GROUP_GRAPHS = NO
+
+# If the UML_LOOK tag is set to YES doxygen will generate inheritance and
+# collaboration diagrams in a style similar to the OMG's Unified Modeling
+# Language.
+
+UML_LOOK = NO
+
+# If set to YES, the inheritance and collaboration graphs will show the
+# relations between templates and their instances.
+
+TEMPLATE_RELATIONS = NO
+
+# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDE_GRAPH, and HAVE_DOT
+# tags are set to YES then doxygen will generate a graph for each documented
+# file showing the direct and indirect include dependencies of the file with
+# other documented files.
+
+INCLUDE_GRAPH = NO
+
+# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDED_BY_GRAPH, and
+# HAVE_DOT tags are set to YES then doxygen will generate a graph for each
+# documented header file showing the documented files that directly or
+# indirectly include this file.
+
+INCLUDED_BY_GRAPH = NO
+
+# If the CALL_GRAPH and HAVE_DOT options are set to YES then
+# doxygen will generate a call dependency graph for every global function
+# or class method. Note that enabling this option will significantly increase
+# the time of a run. So in most cases it will be better to enable call graphs
+# for selected functions only using the \callgraph command.
+
+CALL_GRAPH = NO
+
+# If the CALLER_GRAPH and HAVE_DOT tags are set to YES then
+# doxygen will generate a caller dependency graph for every global function
+# or class method. Note that enabling this option will significantly increase
+# the time of a run. So in most cases it will be better to enable caller
+# graphs for selected functions only using the \callergraph command.
+
+CALLER_GRAPH = NO
+
+# If the GRAPHICAL_HIERARCHY and HAVE_DOT tags are set to YES then doxygen
+# will graphical hierarchy of all classes instead of a textual one.
+
+GRAPHICAL_HIERARCHY = NO
+
+# If the DIRECTORY_GRAPH, SHOW_DIRECTORIES and HAVE_DOT tags are set to YES
+# then doxygen will show the dependencies a directory has on other directories
+# in a graphical way. The dependency relations are determined by the #include
+# relations between the files in the directories.
+
+DIRECTORY_GRAPH = NO
+
+# The DOT_IMAGE_FORMAT tag can be used to set the image format of the images
+# generated by dot. Possible values are png, jpg, or gif
+# If left blank png will be used.
+
+DOT_IMAGE_FORMAT = png
+
+# The tag DOT_PATH can be used to specify the path where the dot tool can be
+# found. If left blank, it is assumed the dot tool can be found in the path.
+
+DOT_PATH =
+
+# The DOTFILE_DIRS tag can be used to specify one or more directories that
+# contain dot files that are included in the documentation (see the
+# \dotfile command).
+
+DOTFILE_DIRS =
+
+# The DOT_GRAPH_MAX_NODES tag can be used to set the maximum number of
+# nodes that will be shown in the graph. If the number of nodes in a graph
+# becomes larger than this value, doxygen will truncate the graph, which is
+# visualized by representing a node as a red box. Note that doxygen if the
+# number of direct children of the root node in a graph is already larger than
+# DOT_GRAPH_MAX_NODES then the graph will not be shown at all. Also note
+# that the size of a graph can be further restricted by MAX_DOT_GRAPH_DEPTH.
+
+DOT_GRAPH_MAX_NODES = 50
+
+# The MAX_DOT_GRAPH_DEPTH tag can be used to set the maximum depth of the
+# graphs generated by dot. A depth value of 3 means that only nodes reachable
+# from the root by following a path via at most 3 edges will be shown. Nodes
+# that lay further from the root node will be omitted. Note that setting this
+# option to 1 or 2 may greatly reduce the computation time needed for large
+# code bases. Also note that the size of a graph can be further restricted by
+# DOT_GRAPH_MAX_NODES. Using a depth of 0 means no depth restriction.
+
+MAX_DOT_GRAPH_DEPTH = 1000
+
+# Set the DOT_TRANSPARENT tag to YES to generate images with a transparent
+# background. This is enabled by default, which results in a transparent
+# background. Warning: Depending on the platform used, enabling this option
+# may lead to badly anti-aliased labels on the edges of a graph (i.e. they
+# become hard to read).
+
+DOT_TRANSPARENT = NO
+
+# Set the DOT_MULTI_TARGETS tag to YES allow dot to generate multiple output
+# files in one run (i.e. multiple -o and -T options on the command line). This
+# makes dot run faster, but since only newer versions of dot (>1.8.10)
+# support this, this feature is disabled by default.
+
+DOT_MULTI_TARGETS = NO
+
+# If the GENERATE_LEGEND tag is set to YES (the default) Doxygen will
+# generate a legend page explaining the meaning of the various boxes and
+# arrows in the dot generated graphs.
+
+GENERATE_LEGEND = NO
+
+# If the DOT_CLEANUP tag is set to YES (the default) Doxygen will
+# remove the intermediate dot files that are used to generate
+# the various graphs.
+
+DOT_CLEANUP = NO
+
+#---------------------------------------------------------------------------
+# Configuration::additions related to the search engine
+#---------------------------------------------------------------------------
+
+# The SEARCHENGINE tag specifies whether or not a search engine should be
+# used. If set to NO the values of all tags below this one will be ignored.
+
+SEARCHENGINE = NO
diff --git a/unsupported/doc/Overview.dox b/unsupported/doc/Overview.dox
new file mode 100644
index 000000000..458b507b5
--- /dev/null
+++ b/unsupported/doc/Overview.dox
@@ -0,0 +1,22 @@
+namespace Eigen {
+
+/** \mainpage Eigen's unsupported modules
+
+This is the API documentation for Eigen's unsupported modules.
+
+These modules are contributions from various users. They are provided "as is", without any support.
+
+Click on the \e Modules tab at the top of this page to get a list of all unsupported modules.
+
+Don't miss the <a href="..//index.html">official Eigen documentation</a>.
+
+
+\defgroup Unsupported_modules Unsupported modules
+
+The unsupported modules are contributions from various users. They are
+provided "as is", without any support. Nevertheless, some of them are
+subject to be included in Eigen in the future.
+
+*/
+
+}
diff --git a/unsupported/doc/examples/BVH_Example.cpp b/unsupported/doc/examples/BVH_Example.cpp
new file mode 100644
index 000000000..6b6fac075
--- /dev/null
+++ b/unsupported/doc/examples/BVH_Example.cpp
@@ -0,0 +1,52 @@
+#include <Eigen/StdVector>
+#include <unsupported/Eigen/BVH>
+#include <iostream>
+
+using namespace Eigen;
+typedef AlignedBox<double, 2> Box2d;
+
+namespace Eigen {
+ namespace internal {
+ Box2d bounding_box(const Vector2d &v) { return Box2d(v, v); } //compute the bounding box of a single point
+ }
+}
+
+struct PointPointMinimizer //how to compute squared distances between points and rectangles
+{
+ PointPointMinimizer() : calls(0) {}
+ typedef double Scalar;
+
+ double minimumOnVolumeVolume(const Box2d &r1, const Box2d &r2) { ++calls; return r1.squaredExteriorDistance(r2); }
+ double minimumOnVolumeObject(const Box2d &r, const Vector2d &v) { ++calls; return r.squaredExteriorDistance(v); }
+ double minimumOnObjectVolume(const Vector2d &v, const Box2d &r) { ++calls; return r.squaredExteriorDistance(v); }
+ double minimumOnObjectObject(const Vector2d &v1, const Vector2d &v2) { ++calls; return (v1 - v2).squaredNorm(); }
+
+ int calls;
+};
+
+int main()
+{
+ typedef std::vector<Vector2d, aligned_allocator<Vector2d> > StdVectorOfVector2d;
+ StdVectorOfVector2d redPoints, bluePoints;
+ for(int i = 0; i < 100; ++i) { //initialize random set of red points and blue points
+ redPoints.push_back(Vector2d::Random());
+ bluePoints.push_back(Vector2d::Random());
+ }
+
+ PointPointMinimizer minimizer;
+ double minDistSq = std::numeric_limits<double>::max();
+
+ //brute force to find closest red-blue pair
+ for(int i = 0; i < (int)redPoints.size(); ++i)
+ for(int j = 0; j < (int)bluePoints.size(); ++j)
+ minDistSq = std::min(minDistSq, minimizer.minimumOnObjectObject(redPoints[i], bluePoints[j]));
+ std::cout << "Brute force distance = " << sqrt(minDistSq) << ", calls = " << minimizer.calls << std::endl;
+
+ //using BVH to find closest red-blue pair
+ minimizer.calls = 0;
+ KdBVH<double, 2, Vector2d> redTree(redPoints.begin(), redPoints.end()), blueTree(bluePoints.begin(), bluePoints.end()); //construct the trees
+ minDistSq = BVMinimize(redTree, blueTree, minimizer); //actual BVH minimization call
+ std::cout << "BVH distance = " << sqrt(minDistSq) << ", calls = " << minimizer.calls << std::endl;
+
+ return 0;
+}
diff --git a/unsupported/doc/examples/CMakeLists.txt b/unsupported/doc/examples/CMakeLists.txt
new file mode 100644
index 000000000..978f9afd8
--- /dev/null
+++ b/unsupported/doc/examples/CMakeLists.txt
@@ -0,0 +1,22 @@
+FILE(GLOB examples_SRCS "*.cpp")
+
+ADD_CUSTOM_TARGET(unsupported_examples)
+
+INCLUDE_DIRECTORIES(../../../unsupported ../../../unsupported/test)
+
+FOREACH(example_src ${examples_SRCS})
+ GET_FILENAME_COMPONENT(example ${example_src} NAME_WE)
+ ADD_EXECUTABLE(example_${example} ${example_src})
+ if(EIGEN_STANDARD_LIBRARIES_TO_LINK_TO)
+ target_link_libraries(example_${example} ${EIGEN_STANDARD_LIBRARIES_TO_LINK_TO})
+ endif()
+ GET_TARGET_PROPERTY(example_executable
+ example_${example} LOCATION)
+ ADD_CUSTOM_COMMAND(
+ TARGET example_${example}
+ POST_BUILD
+ COMMAND ${example_executable}
+ ARGS >${CMAKE_CURRENT_BINARY_DIR}/${example}.out
+ )
+ ADD_DEPENDENCIES(unsupported_examples example_${example})
+ENDFOREACH(example_src)
diff --git a/unsupported/doc/examples/FFT.cpp b/unsupported/doc/examples/FFT.cpp
new file mode 100644
index 000000000..fcbf81276
--- /dev/null
+++ b/unsupported/doc/examples/FFT.cpp
@@ -0,0 +1,118 @@
+// To use the simple FFT implementation
+// g++ -o demofft -I.. -Wall -O3 FFT.cpp
+
+// To use the FFTW implementation
+// g++ -o demofft -I.. -DUSE_FFTW -Wall -O3 FFT.cpp -lfftw3 -lfftw3f -lfftw3l
+
+#ifdef USE_FFTW
+#include <fftw3.h>
+#endif
+
+#include <vector>
+#include <complex>
+#include <algorithm>
+#include <iterator>
+#include <iostream>
+#include <Eigen/Core>
+#include <unsupported/Eigen/FFT>
+
+using namespace std;
+using namespace Eigen;
+
+template <typename T>
+T mag2(T a)
+{
+ return a*a;
+}
+template <typename T>
+T mag2(std::complex<T> a)
+{
+ return norm(a);
+}
+
+template <typename T>
+T mag2(const std::vector<T> & vec)
+{
+ T out=0;
+ for (size_t k=0;k<vec.size();++k)
+ out += mag2(vec[k]);
+ return out;
+}
+
+template <typename T>
+T mag2(const std::vector<std::complex<T> > & vec)
+{
+ T out=0;
+ for (size_t k=0;k<vec.size();++k)
+ out += mag2(vec[k]);
+ return out;
+}
+
+template <typename T>
+vector<T> operator-(const vector<T> & a,const vector<T> & b )
+{
+ vector<T> c(a);
+ for (size_t k=0;k<b.size();++k)
+ c[k] -= b[k];
+ return c;
+}
+
+template <typename T>
+void RandomFill(std::vector<T> & vec)
+{
+ for (size_t k=0;k<vec.size();++k)
+ vec[k] = T( rand() )/T(RAND_MAX) - .5;
+}
+
+template <typename T>
+void RandomFill(std::vector<std::complex<T> > & vec)
+{
+ for (size_t k=0;k<vec.size();++k)
+ vec[k] = std::complex<T> ( T( rand() )/T(RAND_MAX) - .5, T( rand() )/T(RAND_MAX) - .5);
+}
+
+template <typename T_time,typename T_freq>
+void fwd_inv(size_t nfft)
+{
+ typedef typename NumTraits<T_freq>::Real Scalar;
+ vector<T_time> timebuf(nfft);
+ RandomFill(timebuf);
+
+ vector<T_freq> freqbuf;
+ static FFT<Scalar> fft;
+ fft.fwd(freqbuf,timebuf);
+
+ vector<T_time> timebuf2;
+ fft.inv(timebuf2,freqbuf);
+
+ long double rmse = mag2(timebuf - timebuf2) / mag2(timebuf);
+ cout << "roundtrip rmse: " << rmse << endl;
+}
+
+template <typename T_scalar>
+void two_demos(int nfft)
+{
+ cout << " scalar ";
+ fwd_inv<T_scalar,std::complex<T_scalar> >(nfft);
+ cout << " complex ";
+ fwd_inv<std::complex<T_scalar>,std::complex<T_scalar> >(nfft);
+}
+
+void demo_all_types(int nfft)
+{
+ cout << "nfft=" << nfft << endl;
+ cout << " float" << endl;
+ two_demos<float>(nfft);
+ cout << " double" << endl;
+ two_demos<double>(nfft);
+ cout << " long double" << endl;
+ two_demos<long double>(nfft);
+}
+
+int main()
+{
+ demo_all_types( 2*3*4*5*7 );
+ demo_all_types( 2*9*16*25 );
+ demo_all_types( 1024 );
+ return 0;
+}
diff --git a/unsupported/doc/examples/MatrixExponential.cpp b/unsupported/doc/examples/MatrixExponential.cpp
new file mode 100644
index 000000000..ebd3b9675
--- /dev/null
+++ b/unsupported/doc/examples/MatrixExponential.cpp
@@ -0,0 +1,16 @@
+#include <unsupported/Eigen/MatrixFunctions>
+#include <iostream>
+
+using namespace Eigen;
+
+int main()
+{
+ const double pi = std::acos(-1.0);
+
+ MatrixXd A(3,3);
+ A << 0, -pi/4, 0,
+ pi/4, 0, 0,
+ 0, 0, 0;
+ std::cout << "The matrix A is:\n" << A << "\n\n";
+ std::cout << "The matrix exponential of A is:\n" << A.exp() << "\n\n";
+}
diff --git a/unsupported/doc/examples/MatrixFunction.cpp b/unsupported/doc/examples/MatrixFunction.cpp
new file mode 100644
index 000000000..a4172e4ae
--- /dev/null
+++ b/unsupported/doc/examples/MatrixFunction.cpp
@@ -0,0 +1,23 @@
+#include <unsupported/Eigen/MatrixFunctions>
+#include <iostream>
+
+using namespace Eigen;
+
+std::complex<double> expfn(std::complex<double> x, int)
+{
+ return std::exp(x);
+}
+
+int main()
+{
+ const double pi = std::acos(-1.0);
+
+ MatrixXd A(3,3);
+ A << 0, -pi/4, 0,
+ pi/4, 0, 0,
+ 0, 0, 0;
+
+ std::cout << "The matrix A is:\n" << A << "\n\n";
+ std::cout << "The matrix exponential of A is:\n"
+ << A.matrixFunction(expfn) << "\n\n";
+}
diff --git a/unsupported/doc/examples/MatrixLogarithm.cpp b/unsupported/doc/examples/MatrixLogarithm.cpp
new file mode 100644
index 000000000..8c5d97054
--- /dev/null
+++ b/unsupported/doc/examples/MatrixLogarithm.cpp
@@ -0,0 +1,15 @@
+#include <unsupported/Eigen/MatrixFunctions>
+#include <iostream>
+
+using namespace Eigen;
+
+int main()
+{
+ using std::sqrt;
+ MatrixXd A(3,3);
+ A << 0.5*sqrt(2), -0.5*sqrt(2), 0,
+ 0.5*sqrt(2), 0.5*sqrt(2), 0,
+ 0, 0, 1;
+ std::cout << "The matrix A is:\n" << A << "\n\n";
+ std::cout << "The matrix logarithm of A is:\n" << A.log() << "\n";
+}
diff --git a/unsupported/doc/examples/MatrixSine.cpp b/unsupported/doc/examples/MatrixSine.cpp
new file mode 100644
index 000000000..9eea9a081
--- /dev/null
+++ b/unsupported/doc/examples/MatrixSine.cpp
@@ -0,0 +1,20 @@
+#include <unsupported/Eigen/MatrixFunctions>
+#include <iostream>
+
+using namespace Eigen;
+
+int main()
+{
+ MatrixXd A = MatrixXd::Random(3,3);
+ std::cout << "A = \n" << A << "\n\n";
+
+ MatrixXd sinA = A.sin();
+ std::cout << "sin(A) = \n" << sinA << "\n\n";
+
+ MatrixXd cosA = A.cos();
+ std::cout << "cos(A) = \n" << cosA << "\n\n";
+
+ // The matrix functions satisfy sin^2(A) + cos^2(A) = I,
+ // like the scalar functions.
+ std::cout << "sin^2(A) + cos^2(A) = \n" << sinA*sinA + cosA*cosA << "\n\n";
+}
diff --git a/unsupported/doc/examples/MatrixSinh.cpp b/unsupported/doc/examples/MatrixSinh.cpp
new file mode 100644
index 000000000..f77186724
--- /dev/null
+++ b/unsupported/doc/examples/MatrixSinh.cpp
@@ -0,0 +1,20 @@
+#include <unsupported/Eigen/MatrixFunctions>
+#include <iostream>
+
+using namespace Eigen;
+
+int main()
+{
+ MatrixXf A = MatrixXf::Random(3,3);
+ std::cout << "A = \n" << A << "\n\n";
+
+ MatrixXf sinhA = A.sinh();
+ std::cout << "sinh(A) = \n" << sinhA << "\n\n";
+
+ MatrixXf coshA = A.cosh();
+ std::cout << "cosh(A) = \n" << coshA << "\n\n";
+
+ // The matrix functions satisfy cosh^2(A) - sinh^2(A) = I,
+ // like the scalar functions.
+ std::cout << "cosh^2(A) - sinh^2(A) = \n" << coshA*coshA - sinhA*sinhA << "\n\n";
+}
diff --git a/unsupported/doc/examples/MatrixSquareRoot.cpp b/unsupported/doc/examples/MatrixSquareRoot.cpp
new file mode 100644
index 000000000..88e7557d7
--- /dev/null
+++ b/unsupported/doc/examples/MatrixSquareRoot.cpp
@@ -0,0 +1,16 @@
+#include <unsupported/Eigen/MatrixFunctions>
+#include <iostream>
+
+using namespace Eigen;
+
+int main()
+{
+ const double pi = std::acos(-1.0);
+
+ MatrixXd A(2,2);
+ A << cos(pi/3), -sin(pi/3),
+ sin(pi/3), cos(pi/3);
+ std::cout << "The matrix A is:\n" << A << "\n\n";
+ std::cout << "The matrix square root of A is:\n" << A.sqrt() << "\n\n";
+ std::cout << "The square of the last matrix is:\n" << A.sqrt() * A.sqrt() << "\n";
+}
diff --git a/unsupported/doc/examples/PolynomialSolver1.cpp b/unsupported/doc/examples/PolynomialSolver1.cpp
new file mode 100644
index 000000000..71e6b825f
--- /dev/null
+++ b/unsupported/doc/examples/PolynomialSolver1.cpp
@@ -0,0 +1,53 @@
+#include <unsupported/Eigen/Polynomials>
+#include <vector>
+#include <iostream>
+
+using namespace Eigen;
+using namespace std;
+
+int main()
+{
+ typedef Matrix<double,5,1> Vector5d;
+
+ Vector5d roots = Vector5d::Random();
+ cout << "Roots: " << roots.transpose() << endl;
+ Eigen::Matrix<double,6,1> polynomial;
+ roots_to_monicPolynomial( roots, polynomial );
+
+ PolynomialSolver<double,5> psolve( polynomial );
+ cout << "Complex roots: " << psolve.roots().transpose() << endl;
+
+ std::vector<double> realRoots;
+ psolve.realRoots( realRoots );
+ Map<Vector5d> mapRR( &realRoots[0] );
+ cout << "Real roots: " << mapRR.transpose() << endl;
+
+ cout << endl;
+ cout << "Illustration of the convergence problem with the QR algorithm: " << endl;
+ cout << "---------------------------------------------------------------" << endl;
+ Eigen::Matrix<float,7,1> hardCase_polynomial;
+ hardCase_polynomial <<
+ -0.957, 0.9219, 0.3516, 0.9453, -0.4023, -0.5508, -0.03125;
+ cout << "Hard case polynomial defined by floats: " << hardCase_polynomial.transpose() << endl;
+ PolynomialSolver<float,6> psolvef( hardCase_polynomial );
+ cout << "Complex roots: " << psolvef.roots().transpose() << endl;
+ Eigen::Matrix<float,6,1> evals;
+ for( int i=0; i<6; ++i ){ evals[i] = std::abs( poly_eval( hardCase_polynomial, psolvef.roots()[i] ) ); }
+ cout << "Norms of the evaluations of the polynomial at the roots: " << evals.transpose() << endl << endl;
+
+ cout << "Using double's almost always solves the problem for small degrees: " << endl;
+ cout << "-------------------------------------------------------------------" << endl;
+ PolynomialSolver<double,6> psolve6d( hardCase_polynomial.cast<double>() );
+ cout << "Complex roots: " << psolve6d.roots().transpose() << endl;
+ for( int i=0; i<6; ++i )
+ {
+ std::complex<float> castedRoot( psolve6d.roots()[i].real(), psolve6d.roots()[i].imag() );
+ evals[i] = std::abs( poly_eval( hardCase_polynomial, castedRoot ) );
+ }
+ cout << "Norms of the evaluations of the polynomial at the roots: " << evals.transpose() << endl << endl;
+
+ cout.precision(10);
+ cout << "The last root in float then in double: " << psolvef.roots()[5] << "\t" << psolve6d.roots()[5] << endl;
+ std::complex<float> castedRoot( psolve6d.roots()[5].real(), psolve6d.roots()[5].imag() );
+ cout << "Norm of the difference: " << internal::abs( psolvef.roots()[5] - castedRoot ) << endl;
+}
diff --git a/unsupported/doc/examples/PolynomialUtils1.cpp b/unsupported/doc/examples/PolynomialUtils1.cpp
new file mode 100644
index 000000000..dbfe520b5
--- /dev/null
+++ b/unsupported/doc/examples/PolynomialUtils1.cpp
@@ -0,0 +1,20 @@
+#include <unsupported/Eigen/Polynomials>
+#include <iostream>
+
+using namespace Eigen;
+using namespace std;
+
+int main()
+{
+ Vector4d roots = Vector4d::Random();
+ cout << "Roots: " << roots.transpose() << endl;
+ Eigen::Matrix<double,5,1> polynomial;
+ roots_to_monicPolynomial( roots, polynomial );
+ cout << "Polynomial: ";
+ for( int i=0; i<4; ++i ){ cout << polynomial[i] << ".x^" << i << "+ "; }
+ cout << polynomial[4] << ".x^4" << endl;
+ Vector4d evaluation;
+ for( int i=0; i<4; ++i ){
+ evaluation[i] = poly_eval( polynomial, roots[i] ); }
+ cout << "Evaluation of the polynomial at the roots: " << evaluation.transpose();
+}
diff --git a/unsupported/doc/snippets/CMakeLists.txt b/unsupported/doc/snippets/CMakeLists.txt
new file mode 100644
index 000000000..4a4157933
--- /dev/null
+++ b/unsupported/doc/snippets/CMakeLists.txt
@@ -0,0 +1,28 @@
+FILE(GLOB snippets_SRCS "*.cpp")
+
+ADD_CUSTOM_TARGET(unsupported_snippets)
+
+FOREACH(snippet_src ${snippets_SRCS})
+ GET_FILENAME_COMPONENT(snippet ${snippet_src} NAME_WE)
+ SET(compile_snippet_target compile_${snippet})
+ SET(compile_snippet_src ${compile_snippet_target}.cpp)
+ FILE(READ ${snippet_src} snippet_source_code)
+ CONFIGURE_FILE(${PROJECT_SOURCE_DIR}/doc/snippets/compile_snippet.cpp.in
+ ${CMAKE_CURRENT_BINARY_DIR}/${compile_snippet_src})
+ ADD_EXECUTABLE(${compile_snippet_target}
+ ${CMAKE_CURRENT_BINARY_DIR}/${compile_snippet_src})
+ if(EIGEN_STANDARD_LIBRARIES_TO_LINK_TO)
+ target_link_libraries(${compile_snippet_target} ${EIGEN_STANDARD_LIBRARIES_TO_LINK_TO})
+ endif()
+ GET_TARGET_PROPERTY(compile_snippet_executable
+ ${compile_snippet_target} LOCATION)
+ ADD_CUSTOM_COMMAND(
+ TARGET ${compile_snippet_target}
+ POST_BUILD
+ COMMAND ${compile_snippet_executable}
+ ARGS >${CMAKE_CURRENT_BINARY_DIR}/${snippet}.out
+ )
+ ADD_DEPENDENCIES(unsupported_snippets ${compile_snippet_target})
+ set_source_files_properties(${CMAKE_CURRENT_BINARY_DIR}/${compile_snippet_src}
+ PROPERTIES OBJECT_DEPENDS ${snippet_src})
+ENDFOREACH(snippet_src)
diff --git a/unsupported/test/BVH.cpp b/unsupported/test/BVH.cpp
new file mode 100644
index 000000000..ff5b3299d
--- /dev/null
+++ b/unsupported/test/BVH.cpp
@@ -0,0 +1,222 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra.
+//
+// Copyright (C) 2009 Ilya Baran <ibaran@mit.edu>
+//
+// This Source Code Form is subject to the terms of the Mozilla
+// Public License v. 2.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 "main.h"
+#include <Eigen/StdVector>
+#include <Eigen/Geometry>
+#include <unsupported/Eigen/BVH>
+
+namespace Eigen {
+
+template<typename Scalar, int Dim> AlignedBox<Scalar, Dim> bounding_box(const Matrix<Scalar, Dim, 1> &v) { return AlignedBox<Scalar, Dim>(v); }
+
+}
+
+
+template<int Dim>
+struct Ball
+{
+EIGEN_MAKE_ALIGNED_OPERATOR_NEW_IF_VECTORIZABLE_FIXED_SIZE(double, Dim)
+
+ typedef Matrix<double, Dim, 1> VectorType;
+
+ Ball() {}
+ Ball(const VectorType &c, double r) : center(c), radius(r) {}
+
+ VectorType center;
+ double radius;
+};
+template<int Dim> AlignedBox<double, Dim> bounding_box(const Ball<Dim> &b)
+{ return AlignedBox<double, Dim>(b.center.array() - b.radius, b.center.array() + b.radius); }
+
+inline double SQR(double x) { return x * x; }
+
+template<int Dim>
+struct BallPointStuff //this class provides functions to be both an intersector and a minimizer, both for a ball and a point and for two trees
+{
+ typedef double Scalar;
+ typedef Matrix<double, Dim, 1> VectorType;
+ typedef Ball<Dim> BallType;
+ typedef AlignedBox<double, Dim> BoxType;
+
+ BallPointStuff() : calls(0), count(0) {}
+ BallPointStuff(const VectorType &inP) : p(inP), calls(0), count(0) {}
+
+
+ bool intersectVolume(const BoxType &r) { ++calls; return r.contains(p); }
+ bool intersectObject(const BallType &b) {
+ ++calls;
+ if((b.center - p).squaredNorm() < SQR(b.radius))
+ ++count;
+ return false; //continue
+ }
+
+ bool intersectVolumeVolume(const BoxType &r1, const BoxType &r2) { ++calls; return !(r1.intersection(r2)).isNull(); }
+ bool intersectVolumeObject(const BoxType &r, const BallType &b) { ++calls; return r.squaredExteriorDistance(b.center) < SQR(b.radius); }
+ bool intersectObjectVolume(const BallType &b, const BoxType &r) { ++calls; return r.squaredExteriorDistance(b.center) < SQR(b.radius); }
+ bool intersectObjectObject(const BallType &b1, const BallType &b2){
+ ++calls;
+ if((b1.center - b2.center).norm() < b1.radius + b2.radius)
+ ++count;
+ return false;
+ }
+ bool intersectVolumeObject(const BoxType &r, const VectorType &v) { ++calls; return r.contains(v); }
+ bool intersectObjectObject(const BallType &b, const VectorType &v){
+ ++calls;
+ if((b.center - v).squaredNorm() < SQR(b.radius))
+ ++count;
+ return false;
+ }
+
+ double minimumOnVolume(const BoxType &r) { ++calls; return r.squaredExteriorDistance(p); }
+ double minimumOnObject(const BallType &b) { ++calls; return (std::max)(0., (b.center - p).squaredNorm() - SQR(b.radius)); }
+ double minimumOnVolumeVolume(const BoxType &r1, const BoxType &r2) { ++calls; return r1.squaredExteriorDistance(r2); }
+ double minimumOnVolumeObject(const BoxType &r, const BallType &b) { ++calls; return SQR((std::max)(0., r.exteriorDistance(b.center) - b.radius)); }
+ double minimumOnObjectVolume(const BallType &b, const BoxType &r) { ++calls; return SQR((std::max)(0., r.exteriorDistance(b.center) - b.radius)); }
+ double minimumOnObjectObject(const BallType &b1, const BallType &b2){ ++calls; return SQR((std::max)(0., (b1.center - b2.center).norm() - b1.radius - b2.radius)); }
+ double minimumOnVolumeObject(const BoxType &r, const VectorType &v) { ++calls; return r.squaredExteriorDistance(v); }
+ double minimumOnObjectObject(const BallType &b, const VectorType &v){ ++calls; return SQR((std::max)(0., (b.center - v).norm() - b.radius)); }
+
+ VectorType p;
+ int calls;
+ int count;
+};
+
+
+template<int Dim>
+struct TreeTest
+{
+ typedef Matrix<double, Dim, 1> VectorType;
+ typedef std::vector<VectorType, aligned_allocator<VectorType> > VectorTypeList;
+ typedef Ball<Dim> BallType;
+ typedef std::vector<BallType, aligned_allocator<BallType> > BallTypeList;
+ typedef AlignedBox<double, Dim> BoxType;
+
+ void testIntersect1()
+ {
+ BallTypeList b;
+ for(int i = 0; i < 500; ++i) {
+ b.push_back(BallType(VectorType::Random(), 0.5 * internal::random(0., 1.)));
+ }
+ KdBVH<double, Dim, BallType> tree(b.begin(), b.end());
+
+ VectorType pt = VectorType::Random();
+ BallPointStuff<Dim> i1(pt), i2(pt);
+
+ for(int i = 0; i < (int)b.size(); ++i)
+ i1.intersectObject(b[i]);
+
+ BVIntersect(tree, i2);
+
+ VERIFY(i1.count == i2.count);
+ }
+
+ void testMinimize1()
+ {
+ BallTypeList b;
+ for(int i = 0; i < 500; ++i) {
+ b.push_back(BallType(VectorType::Random(), 0.01 * internal::random(0., 1.)));
+ }
+ KdBVH<double, Dim, BallType> tree(b.begin(), b.end());
+
+ VectorType pt = VectorType::Random();
+ BallPointStuff<Dim> i1(pt), i2(pt);
+
+ double m1 = (std::numeric_limits<double>::max)(), m2 = m1;
+
+ for(int i = 0; i < (int)b.size(); ++i)
+ m1 = (std::min)(m1, i1.minimumOnObject(b[i]));
+
+ m2 = BVMinimize(tree, i2);
+
+ VERIFY_IS_APPROX(m1, m2);
+ }
+
+ void testIntersect2()
+ {
+ BallTypeList b;
+ VectorTypeList v;
+
+ for(int i = 0; i < 50; ++i) {
+ b.push_back(BallType(VectorType::Random(), 0.5 * internal::random(0., 1.)));
+ for(int j = 0; j < 3; ++j)
+ v.push_back(VectorType::Random());
+ }
+
+ KdBVH<double, Dim, BallType> tree(b.begin(), b.end());
+ KdBVH<double, Dim, VectorType> vTree(v.begin(), v.end());
+
+ BallPointStuff<Dim> i1, i2;
+
+ for(int i = 0; i < (int)b.size(); ++i)
+ for(int j = 0; j < (int)v.size(); ++j)
+ i1.intersectObjectObject(b[i], v[j]);
+
+ BVIntersect(tree, vTree, i2);
+
+ VERIFY(i1.count == i2.count);
+ }
+
+ void testMinimize2()
+ {
+ BallTypeList b;
+ VectorTypeList v;
+
+ for(int i = 0; i < 50; ++i) {
+ b.push_back(BallType(VectorType::Random(), 1e-7 + 1e-6 * internal::random(0., 1.)));
+ for(int j = 0; j < 3; ++j)
+ v.push_back(VectorType::Random());
+ }
+
+ KdBVH<double, Dim, BallType> tree(b.begin(), b.end());
+ KdBVH<double, Dim, VectorType> vTree(v.begin(), v.end());
+
+ BallPointStuff<Dim> i1, i2;
+
+ double m1 = (std::numeric_limits<double>::max)(), m2 = m1;
+
+ for(int i = 0; i < (int)b.size(); ++i)
+ for(int j = 0; j < (int)v.size(); ++j)
+ m1 = (std::min)(m1, i1.minimumOnObjectObject(b[i], v[j]));
+
+ m2 = BVMinimize(tree, vTree, i2);
+
+ VERIFY_IS_APPROX(m1, m2);
+ }
+};
+
+
+void test_BVH()
+{
+ for(int i = 0; i < g_repeat; i++) {
+#ifdef EIGEN_TEST_PART_1
+ TreeTest<2> test2;
+ CALL_SUBTEST(test2.testIntersect1());
+ CALL_SUBTEST(test2.testMinimize1());
+ CALL_SUBTEST(test2.testIntersect2());
+ CALL_SUBTEST(test2.testMinimize2());
+#endif
+
+#ifdef EIGEN_TEST_PART_2
+ TreeTest<3> test3;
+ CALL_SUBTEST(test3.testIntersect1());
+ CALL_SUBTEST(test3.testMinimize1());
+ CALL_SUBTEST(test3.testIntersect2());
+ CALL_SUBTEST(test3.testMinimize2());
+#endif
+
+#ifdef EIGEN_TEST_PART_3
+ TreeTest<4> test4;
+ CALL_SUBTEST(test4.testIntersect1());
+ CALL_SUBTEST(test4.testMinimize1());
+ CALL_SUBTEST(test4.testIntersect2());
+ CALL_SUBTEST(test4.testMinimize2());
+#endif
+ }
+}
diff --git a/unsupported/test/CMakeLists.txt b/unsupported/test/CMakeLists.txt
new file mode 100644
index 000000000..b34b151b1
--- /dev/null
+++ b/unsupported/test/CMakeLists.txt
@@ -0,0 +1,87 @@
+
+include_directories(../../test ../../unsupported ../../Eigen
+ ${CMAKE_CURRENT_BINARY_DIR}/../../test)
+
+find_package(GoogleHash)
+if(GOOGLEHASH_FOUND)
+ add_definitions("-DEIGEN_GOOGLEHASH_SUPPORT")
+ include_directories(${GOOGLEHASH_INCLUDES})
+ ei_add_property(EIGEN_TESTED_BACKENDS "GoogleHash, ")
+else(GOOGLEHASH_FOUND)
+ ei_add_property(EIGEN_MISSING_BACKENDS "GoogleHash, ")
+endif(GOOGLEHASH_FOUND)
+
+find_package(Adolc)
+if(ADOLC_FOUND)
+ include_directories(${ADOLC_INCLUDES})
+ ei_add_property(EIGEN_TESTED_BACKENDS "Adolc, ")
+ ei_add_test(forward_adolc "" ${ADOLC_LIBRARIES})
+else(ADOLC_FOUND)
+ ei_add_property(EIGEN_MISSING_BACKENDS "Adolc, ")
+endif(ADOLC_FOUND)
+
+# this test seems to never have been successful on x87, so is considered to contain a FP-related bug.
+# see thread: "non-linear optimization test summary"
+#ei_add_test(NonLinearOptimization)
+
+ei_add_test(NumericalDiff)
+ei_add_test(autodiff)
+
+if (NOT CMAKE_CXX_COMPILER MATCHES "clang\\+\\+$")
+ei_add_test(BVH)
+endif()
+
+ei_add_test(matrix_exponential)
+ei_add_test(matrix_function)
+ei_add_test(matrix_square_root)
+ei_add_test(alignedvector3)
+ei_add_test(FFT)
+
+find_package(MPFR 2.3.0)
+find_package(GMP)
+if(MPFR_FOUND)
+ include_directories(${MPFR_INCLUDES} ./mpreal)
+ ei_add_property(EIGEN_TESTED_BACKENDS "MPFR C++, ")
+ set(EIGEN_MPFR_TEST_LIBRARIES ${MPFR_LIBRARIES} ${GMP_LIBRARIES})
+ ei_add_test(mpreal_support "" "${EIGEN_MPFR_TEST_LIBRARIES}" )
+else()
+ ei_add_property(EIGEN_MISSING_BACKENDS "MPFR C++, ")
+endif()
+
+ei_add_test(sparse_extra "" "")
+
+find_package(FFTW)
+if(FFTW_FOUND)
+ ei_add_property(EIGEN_TESTED_BACKENDS "fftw, ")
+ include_directories( ${FFTW_INCLUDES} )
+ if(FFTWL_LIB)
+ ei_add_test(FFTW "-DEIGEN_FFTW_DEFAULT -DEIGEN_HAS_FFTWL" "${FFTW_LIBRARIES}" )
+ else()
+ ei_add_test(FFTW "-DEIGEN_FFTW_DEFAULT" "${FFTW_LIBRARIES}" )
+ endif()
+else()
+ ei_add_property(EIGEN_MISSING_BACKENDS "fftw, ")
+endif()
+
+option(EIGEN_TEST_NO_OPENGL "Disable OpenGL support in unit tests" OFF)
+if(NOT EIGEN_TEST_NO_OPENGL)
+ find_package(OpenGL)
+ find_package(GLUT)
+ find_package(GLEW)
+ if(OPENGL_FOUND AND GLUT_FOUND AND GLEW_FOUND)
+ ei_add_property(EIGEN_TESTED_BACKENDS "OpenGL, ")
+ set(EIGEN_GL_LIB ${GLUT_LIBRARIES} ${GLEW_LIBRARIES})
+ ei_add_test(openglsupport "" "${EIGEN_GL_LIB}" )
+ else()
+ ei_add_property(EIGEN_MISSING_BACKENDS "OpenGL, ")
+ endif()
+else()
+ ei_add_property(EIGEN_MISSING_BACKENDS "OpenGL, ")
+endif()
+
+ei_add_test(polynomialsolver)
+ei_add_test(polynomialutils)
+ei_add_test(kronecker_product)
+ei_add_test(splines)
+ei_add_test(gmres)
+
diff --git a/unsupported/test/FFT.cpp b/unsupported/test/FFT.cpp
new file mode 100644
index 000000000..45c87f5a7
--- /dev/null
+++ b/unsupported/test/FFT.cpp
@@ -0,0 +1,2 @@
+#define test_FFTW test_FFT
+#include "FFTW.cpp"
diff --git a/unsupported/test/FFTW.cpp b/unsupported/test/FFTW.cpp
new file mode 100644
index 000000000..a07bf274b
--- /dev/null
+++ b/unsupported/test/FFTW.cpp
@@ -0,0 +1,265 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra.
+//
+// Copyright (C) 2009 Mark Borgerding mark a borgerding net
+//
+// This Source Code Form is subject to the terms of the Mozilla
+// Public License v. 2.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 "main.h"
+#include <unsupported/Eigen/FFT>
+
+template <typename T>
+std::complex<T> RandomCpx() { return std::complex<T>( (T)(rand()/(T)RAND_MAX - .5), (T)(rand()/(T)RAND_MAX - .5) ); }
+
+using namespace std;
+using namespace Eigen;
+
+float norm(float x) {return x*x;}
+double norm(double x) {return x*x;}
+long double norm(long double x) {return x*x;}
+
+template < typename T>
+complex<long double> promote(complex<T> x) { return complex<long double>(x.real(),x.imag()); }
+
+complex<long double> promote(float x) { return complex<long double>( x); }
+complex<long double> promote(double x) { return complex<long double>( x); }
+complex<long double> promote(long double x) { return complex<long double>( x); }
+
+
+ template <typename VT1,typename VT2>
+ long double fft_rmse( const VT1 & fftbuf,const VT2 & timebuf)
+ {
+ long double totalpower=0;
+ long double difpower=0;
+ long double pi = acos((long double)-1 );
+ for (size_t k0=0;k0<(size_t)fftbuf.size();++k0) {
+ complex<long double> acc = 0;
+ long double phinc = -2.*k0* pi / timebuf.size();
+ for (size_t k1=0;k1<(size_t)timebuf.size();++k1) {
+ acc += promote( timebuf[k1] ) * exp( complex<long double>(0,k1*phinc) );
+ }
+ totalpower += norm(acc);
+ complex<long double> x = promote(fftbuf[k0]);
+ complex<long double> dif = acc - x;
+ difpower += norm(dif);
+ //cerr << k0 << "\t" << acc << "\t" << x << "\t" << sqrt(norm(dif)) << endl;
+ }
+ cerr << "rmse:" << sqrt(difpower/totalpower) << endl;
+ return sqrt(difpower/totalpower);
+ }
+
+ template <typename VT1,typename VT2>
+ long double dif_rmse( const VT1 buf1,const VT2 buf2)
+ {
+ long double totalpower=0;
+ long double difpower=0;
+ size_t n = (min)( buf1.size(),buf2.size() );
+ for (size_t k=0;k<n;++k) {
+ totalpower += (norm( buf1[k] ) + norm(buf2[k]) )/2.;
+ difpower += norm(buf1[k] - buf2[k]);
+ }
+ return sqrt(difpower/totalpower);
+ }
+
+enum { StdVectorContainer, EigenVectorContainer };
+
+template<int Container, typename Scalar> struct VectorType;
+
+template<typename Scalar> struct VectorType<StdVectorContainer,Scalar>
+{
+ typedef vector<Scalar> type;
+};
+
+template<typename Scalar> struct VectorType<EigenVectorContainer,Scalar>
+{
+ typedef Matrix<Scalar,Dynamic,1> type;
+};
+
+template <int Container, typename T>
+void test_scalar_generic(int nfft)
+{
+ typedef typename FFT<T>::Complex Complex;
+ typedef typename FFT<T>::Scalar Scalar;
+ typedef typename VectorType<Container,Scalar>::type ScalarVector;
+ typedef typename VectorType<Container,Complex>::type ComplexVector;
+
+ FFT<T> fft;
+ ScalarVector tbuf(nfft);
+ ComplexVector freqBuf;
+ for (int k=0;k<nfft;++k)
+ tbuf[k]= (T)( rand()/(double)RAND_MAX - .5);
+
+ // make sure it DOESN'T give the right full spectrum answer
+ // if we've asked for half-spectrum
+ fft.SetFlag(fft.HalfSpectrum );
+ fft.fwd( freqBuf,tbuf);
+ VERIFY((size_t)freqBuf.size() == (size_t)( (nfft>>1)+1) );
+ VERIFY( fft_rmse(freqBuf,tbuf) < test_precision<T>() );// gross check
+
+ fft.ClearFlag(fft.HalfSpectrum );
+ fft.fwd( freqBuf,tbuf);
+ VERIFY( (size_t)freqBuf.size() == (size_t)nfft);
+ VERIFY( fft_rmse(freqBuf,tbuf) < test_precision<T>() );// gross check
+
+ if (nfft&1)
+ return; // odd FFTs get the wrong size inverse FFT
+
+ ScalarVector tbuf2;
+ fft.inv( tbuf2 , freqBuf);
+ VERIFY( dif_rmse(tbuf,tbuf2) < test_precision<T>() );// gross check
+
+
+ // verify that the Unscaled flag takes effect
+ ScalarVector tbuf3;
+ fft.SetFlag(fft.Unscaled);
+
+ fft.inv( tbuf3 , freqBuf);
+
+ for (int k=0;k<nfft;++k)
+ tbuf3[k] *= T(1./nfft);
+
+
+ //for (size_t i=0;i<(size_t) tbuf.size();++i)
+ // cout << "freqBuf=" << freqBuf[i] << " in2=" << tbuf3[i] << " - in=" << tbuf[i] << " => " << (tbuf3[i] - tbuf[i] ) << endl;
+
+ VERIFY( dif_rmse(tbuf,tbuf3) < test_precision<T>() );// gross check
+
+ // verify that ClearFlag works
+ fft.ClearFlag(fft.Unscaled);
+ fft.inv( tbuf2 , freqBuf);
+ VERIFY( dif_rmse(tbuf,tbuf2) < test_precision<T>() );// gross check
+}
+
+template <typename T>
+void test_scalar(int nfft)
+{
+ test_scalar_generic<StdVectorContainer,T>(nfft);
+ //test_scalar_generic<EigenVectorContainer,T>(nfft);
+}
+
+
+template <int Container, typename T>
+void test_complex_generic(int nfft)
+{
+ typedef typename FFT<T>::Complex Complex;
+ typedef typename VectorType<Container,Complex>::type ComplexVector;
+
+ FFT<T> fft;
+
+ ComplexVector inbuf(nfft);
+ ComplexVector outbuf;
+ ComplexVector buf3;
+ for (int k=0;k<nfft;++k)
+ inbuf[k]= Complex( (T)(rand()/(double)RAND_MAX - .5), (T)(rand()/(double)RAND_MAX - .5) );
+ fft.fwd( outbuf , inbuf);
+
+ VERIFY( fft_rmse(outbuf,inbuf) < test_precision<T>() );// gross check
+ fft.inv( buf3 , outbuf);
+
+ VERIFY( dif_rmse(inbuf,buf3) < test_precision<T>() );// gross check
+
+ // verify that the Unscaled flag takes effect
+ ComplexVector buf4;
+ fft.SetFlag(fft.Unscaled);
+ fft.inv( buf4 , outbuf);
+ for (int k=0;k<nfft;++k)
+ buf4[k] *= T(1./nfft);
+ VERIFY( dif_rmse(inbuf,buf4) < test_precision<T>() );// gross check
+
+ // verify that ClearFlag works
+ fft.ClearFlag(fft.Unscaled);
+ fft.inv( buf3 , outbuf);
+ VERIFY( dif_rmse(inbuf,buf3) < test_precision<T>() );// gross check
+}
+
+template <typename T>
+void test_complex(int nfft)
+{
+ test_complex_generic<StdVectorContainer,T>(nfft);
+ test_complex_generic<EigenVectorContainer,T>(nfft);
+}
+/*
+template <typename T,int nrows,int ncols>
+void test_complex2d()
+{
+ typedef typename Eigen::FFT<T>::Complex Complex;
+ FFT<T> fft;
+ Eigen::Matrix<Complex,nrows,ncols> src,src2,dst,dst2;
+
+ src = Eigen::Matrix<Complex,nrows,ncols>::Random();
+ //src = Eigen::Matrix<Complex,nrows,ncols>::Identity();
+
+ for (int k=0;k<ncols;k++) {
+ Eigen::Matrix<Complex,nrows,1> tmpOut;
+ fft.fwd( tmpOut,src.col(k) );
+ dst2.col(k) = tmpOut;
+ }
+
+ for (int k=0;k<nrows;k++) {
+ Eigen::Matrix<Complex,1,ncols> tmpOut;
+ fft.fwd( tmpOut, dst2.row(k) );
+ dst2.row(k) = tmpOut;
+ }
+
+ fft.fwd2(dst.data(),src.data(),ncols,nrows);
+ fft.inv2(src2.data(),dst.data(),ncols,nrows);
+ VERIFY( (src-src2).norm() < test_precision<T>() );
+ VERIFY( (dst-dst2).norm() < test_precision<T>() );
+}
+*/
+
+
+void test_return_by_value(int len)
+{
+ VectorXf in;
+ VectorXf in1;
+ in.setRandom( len );
+ VectorXcf out1,out2;
+ FFT<float> fft;
+
+ fft.SetFlag(fft.HalfSpectrum );
+
+ fft.fwd(out1,in);
+ out2 = fft.fwd(in);
+ VERIFY( (out1-out2).norm() < test_precision<float>() );
+ in1 = fft.inv(out1);
+ VERIFY( (in1-in).norm() < test_precision<float>() );
+}
+
+void test_FFTW()
+{
+ CALL_SUBTEST( test_return_by_value(32) );
+ //CALL_SUBTEST( ( test_complex2d<float,4,8> () ) ); CALL_SUBTEST( ( test_complex2d<double,4,8> () ) );
+ //CALL_SUBTEST( ( test_complex2d<long double,4,8> () ) );
+ CALL_SUBTEST( test_complex<float>(32) ); CALL_SUBTEST( test_complex<double>(32) );
+ CALL_SUBTEST( test_complex<float>(256) ); CALL_SUBTEST( test_complex<double>(256) );
+ CALL_SUBTEST( test_complex<float>(3*8) ); CALL_SUBTEST( test_complex<double>(3*8) );
+ CALL_SUBTEST( test_complex<float>(5*32) ); CALL_SUBTEST( test_complex<double>(5*32) );
+ CALL_SUBTEST( test_complex<float>(2*3*4) ); CALL_SUBTEST( test_complex<double>(2*3*4) );
+ CALL_SUBTEST( test_complex<float>(2*3*4*5) ); CALL_SUBTEST( test_complex<double>(2*3*4*5) );
+ CALL_SUBTEST( test_complex<float>(2*3*4*5*7) ); CALL_SUBTEST( test_complex<double>(2*3*4*5*7) );
+
+ CALL_SUBTEST( test_scalar<float>(32) ); CALL_SUBTEST( test_scalar<double>(32) );
+ CALL_SUBTEST( test_scalar<float>(45) ); CALL_SUBTEST( test_scalar<double>(45) );
+ CALL_SUBTEST( test_scalar<float>(50) ); CALL_SUBTEST( test_scalar<double>(50) );
+ CALL_SUBTEST( test_scalar<float>(256) ); CALL_SUBTEST( test_scalar<double>(256) );
+ CALL_SUBTEST( test_scalar<float>(2*3*4*5*7) ); CALL_SUBTEST( test_scalar<double>(2*3*4*5*7) );
+
+ #ifdef EIGEN_HAS_FFTWL
+ CALL_SUBTEST( test_complex<long double>(32) );
+ CALL_SUBTEST( test_complex<long double>(256) );
+ CALL_SUBTEST( test_complex<long double>(3*8) );
+ CALL_SUBTEST( test_complex<long double>(5*32) );
+ CALL_SUBTEST( test_complex<long double>(2*3*4) );
+ CALL_SUBTEST( test_complex<long double>(2*3*4*5) );
+ CALL_SUBTEST( test_complex<long double>(2*3*4*5*7) );
+
+ CALL_SUBTEST( test_scalar<long double>(32) );
+ CALL_SUBTEST( test_scalar<long double>(45) );
+ CALL_SUBTEST( test_scalar<long double>(50) );
+ CALL_SUBTEST( test_scalar<long double>(256) );
+ CALL_SUBTEST( test_scalar<long double>(2*3*4*5*7) );
+ #endif
+}
diff --git a/unsupported/test/NonLinearOptimization.cpp b/unsupported/test/NonLinearOptimization.cpp
new file mode 100644
index 000000000..81b066897
--- /dev/null
+++ b/unsupported/test/NonLinearOptimization.cpp
@@ -0,0 +1,1861 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra.
+//
+// Copyright (C) 2009 Thomas Capricelli <orzel@freehackers.org>
+
+#include <stdio.h>
+
+#include "main.h"
+#include <unsupported/Eigen/NonLinearOptimization>
+
+// This disables some useless Warnings on MSVC.
+// It is intended to be done for this test only.
+#include <Eigen/src/Core/util/DisableStupidWarnings.h>
+
+int fcn_chkder(const VectorXd &x, VectorXd &fvec, MatrixXd &fjac, int iflag)
+{
+ /* subroutine fcn for chkder example. */
+
+ int i;
+ assert(15 == fvec.size());
+ assert(3 == x.size());
+ double tmp1, tmp2, tmp3, tmp4;
+ static const double y[15]={1.4e-1, 1.8e-1, 2.2e-1, 2.5e-1, 2.9e-1, 3.2e-1, 3.5e-1,
+ 3.9e-1, 3.7e-1, 5.8e-1, 7.3e-1, 9.6e-1, 1.34, 2.1, 4.39};
+
+
+ if (iflag == 0)
+ return 0;
+
+ if (iflag != 2)
+ for (i=0; i<15; i++) {
+ tmp1 = i+1;
+ tmp2 = 16-i-1;
+ tmp3 = tmp1;
+ if (i >= 8) tmp3 = tmp2;
+ fvec[i] = y[i] - (x[0] + tmp1/(x[1]*tmp2 + x[2]*tmp3));
+ }
+ else {
+ for (i = 0; i < 15; i++) {
+ tmp1 = i+1;
+ tmp2 = 16-i-1;
+
+ /* error introduced into next statement for illustration. */
+ /* corrected statement should read tmp3 = tmp1 . */
+
+ tmp3 = tmp2;
+ if (i >= 8) tmp3 = tmp2;
+ tmp4 = (x[1]*tmp2 + x[2]*tmp3); tmp4=tmp4*tmp4;
+ fjac(i,0) = -1.;
+ fjac(i,1) = tmp1*tmp2/tmp4;
+ fjac(i,2) = tmp1*tmp3/tmp4;
+ }
+ }
+ return 0;
+}
+
+
+void testChkder()
+{
+ const int m=15, n=3;
+ VectorXd x(n), fvec(m), xp, fvecp(m), err;
+ MatrixXd fjac(m,n);
+ VectorXi ipvt;
+
+ /* the following values should be suitable for */
+ /* checking the jacobian matrix. */
+ x << 9.2e-1, 1.3e-1, 5.4e-1;
+
+ internal::chkder(x, fvec, fjac, xp, fvecp, 1, err);
+ fcn_chkder(x, fvec, fjac, 1);
+ fcn_chkder(x, fvec, fjac, 2);
+ fcn_chkder(xp, fvecp, fjac, 1);
+ internal::chkder(x, fvec, fjac, xp, fvecp, 2, err);
+
+ fvecp -= fvec;
+
+ // check those
+ VectorXd fvec_ref(m), fvecp_ref(m), err_ref(m);
+ fvec_ref <<
+ -1.181606, -1.429655, -1.606344,
+ -1.745269, -1.840654, -1.921586,
+ -1.984141, -2.022537, -2.468977,
+ -2.827562, -3.473582, -4.437612,
+ -6.047662, -9.267761, -18.91806;
+ fvecp_ref <<
+ -7.724666e-09, -3.432406e-09, -2.034843e-10,
+ 2.313685e-09, 4.331078e-09, 5.984096e-09,
+ 7.363281e-09, 8.53147e-09, 1.488591e-08,
+ 2.33585e-08, 3.522012e-08, 5.301255e-08,
+ 8.26666e-08, 1.419747e-07, 3.19899e-07;
+ err_ref <<
+ 0.1141397, 0.09943516, 0.09674474,
+ 0.09980447, 0.1073116, 0.1220445,
+ 0.1526814, 1, 1,
+ 1, 1, 1,
+ 1, 1, 1;
+
+ VERIFY_IS_APPROX(fvec, fvec_ref);
+ VERIFY_IS_APPROX(fvecp, fvecp_ref);
+ VERIFY_IS_APPROX(err, err_ref);
+}
+
+// Generic functor
+template<typename _Scalar, int NX=Dynamic, int NY=Dynamic>
+struct Functor
+{
+ typedef _Scalar Scalar;
+ enum {
+ InputsAtCompileTime = NX,
+ ValuesAtCompileTime = NY
+ };
+ typedef Matrix<Scalar,InputsAtCompileTime,1> InputType;
+ typedef Matrix<Scalar,ValuesAtCompileTime,1> ValueType;
+ typedef Matrix<Scalar,ValuesAtCompileTime,InputsAtCompileTime> JacobianType;
+
+ const int m_inputs, m_values;
+
+ Functor() : m_inputs(InputsAtCompileTime), m_values(ValuesAtCompileTime) {}
+ Functor(int inputs, int values) : m_inputs(inputs), m_values(values) {}
+
+ int inputs() const { return m_inputs; }
+ int values() const { return m_values; }
+
+ // you should define that in the subclass :
+// void operator() (const InputType& x, ValueType* v, JacobianType* _j=0) const;
+};
+
+struct lmder_functor : Functor<double>
+{
+ lmder_functor(void): Functor<double>(3,15) {}
+ int operator()(const VectorXd &x, VectorXd &fvec) const
+ {
+ double tmp1, tmp2, tmp3;
+ static const double y[15] = {1.4e-1, 1.8e-1, 2.2e-1, 2.5e-1, 2.9e-1, 3.2e-1, 3.5e-1,
+ 3.9e-1, 3.7e-1, 5.8e-1, 7.3e-1, 9.6e-1, 1.34, 2.1, 4.39};
+
+ for (int i = 0; i < values(); i++)
+ {
+ tmp1 = i+1;
+ tmp2 = 16 - i - 1;
+ tmp3 = (i>=8)? tmp2 : tmp1;
+ fvec[i] = y[i] - (x[0] + tmp1/(x[1]*tmp2 + x[2]*tmp3));
+ }
+ return 0;
+ }
+
+ int df(const VectorXd &x, MatrixXd &fjac) const
+ {
+ double tmp1, tmp2, tmp3, tmp4;
+ for (int i = 0; i < values(); i++)
+ {
+ tmp1 = i+1;
+ tmp2 = 16 - i - 1;
+ tmp3 = (i>=8)? tmp2 : tmp1;
+ tmp4 = (x[1]*tmp2 + x[2]*tmp3); tmp4 = tmp4*tmp4;
+ fjac(i,0) = -1;
+ fjac(i,1) = tmp1*tmp2/tmp4;
+ fjac(i,2) = tmp1*tmp3/tmp4;
+ }
+ return 0;
+ }
+};
+
+void testLmder1()
+{
+ int n=3, info;
+
+ VectorXd x;
+
+ /* the following starting values provide a rough fit. */
+ x.setConstant(n, 1.);
+
+ // do the computation
+ lmder_functor functor;
+ LevenbergMarquardt<lmder_functor> lm(functor);
+ info = lm.lmder1(x);
+
+ // check return value
+ VERIFY_IS_EQUAL(info, 1);
+ VERIFY_IS_EQUAL(lm.nfev, 6);
+ VERIFY_IS_EQUAL(lm.njev, 5);
+
+ // check norm
+ VERIFY_IS_APPROX(lm.fvec.blueNorm(), 0.09063596);
+
+ // check x
+ VectorXd x_ref(n);
+ x_ref << 0.08241058, 1.133037, 2.343695;
+ VERIFY_IS_APPROX(x, x_ref);
+}
+
+void testLmder()
+{
+ const int m=15, n=3;
+ int info;
+ double fnorm, covfac;
+ VectorXd x;
+
+ /* the following starting values provide a rough fit. */
+ x.setConstant(n, 1.);
+
+ // do the computation
+ lmder_functor functor;
+ LevenbergMarquardt<lmder_functor> lm(functor);
+ info = lm.minimize(x);
+
+ // check return values
+ VERIFY_IS_EQUAL(info, 1);
+ VERIFY_IS_EQUAL(lm.nfev, 6);
+ VERIFY_IS_EQUAL(lm.njev, 5);
+
+ // check norm
+ fnorm = lm.fvec.blueNorm();
+ VERIFY_IS_APPROX(fnorm, 0.09063596);
+
+ // check x
+ VectorXd x_ref(n);
+ x_ref << 0.08241058, 1.133037, 2.343695;
+ VERIFY_IS_APPROX(x, x_ref);
+
+ // check covariance
+ covfac = fnorm*fnorm/(m-n);
+ internal::covar(lm.fjac, lm.permutation.indices()); // TODO : move this as a function of lm
+
+ MatrixXd cov_ref(n,n);
+ cov_ref <<
+ 0.0001531202, 0.002869941, -0.002656662,
+ 0.002869941, 0.09480935, -0.09098995,
+ -0.002656662, -0.09098995, 0.08778727;
+
+// std::cout << fjac*covfac << std::endl;
+
+ MatrixXd cov;
+ cov = covfac*lm.fjac.topLeftCorner<n,n>();
+ VERIFY_IS_APPROX( cov, cov_ref);
+ // TODO: why isn't this allowed ? :
+ // VERIFY_IS_APPROX( covfac*fjac.topLeftCorner<n,n>() , cov_ref);
+}
+
+struct hybrj_functor : Functor<double>
+{
+ hybrj_functor(void) : Functor<double>(9,9) {}
+
+ int operator()(const VectorXd &x, VectorXd &fvec)
+ {
+ double temp, temp1, temp2;
+ const int n = x.size();
+ assert(fvec.size()==n);
+ for (int k = 0; k < n; k++)
+ {
+ temp = (3. - 2.*x[k])*x[k];
+ temp1 = 0.;
+ if (k) temp1 = x[k-1];
+ temp2 = 0.;
+ if (k != n-1) temp2 = x[k+1];
+ fvec[k] = temp - temp1 - 2.*temp2 + 1.;
+ }
+ return 0;
+ }
+ int df(const VectorXd &x, MatrixXd &fjac)
+ {
+ const int n = x.size();
+ assert(fjac.rows()==n);
+ assert(fjac.cols()==n);
+ for (int k = 0; k < n; k++)
+ {
+ for (int j = 0; j < n; j++)
+ fjac(k,j) = 0.;
+ fjac(k,k) = 3.- 4.*x[k];
+ if (k) fjac(k,k-1) = -1.;
+ if (k != n-1) fjac(k,k+1) = -2.;
+ }
+ return 0;
+ }
+};
+
+
+void testHybrj1()
+{
+ const int n=9;
+ int info;
+ VectorXd x(n);
+
+ /* the following starting values provide a rough fit. */
+ x.setConstant(n, -1.);
+
+ // do the computation
+ hybrj_functor functor;
+ HybridNonLinearSolver<hybrj_functor> solver(functor);
+ info = solver.hybrj1(x);
+
+ // check return value
+ VERIFY_IS_EQUAL(info, 1);
+ VERIFY_IS_EQUAL(solver.nfev, 11);
+ VERIFY_IS_EQUAL(solver.njev, 1);
+
+ // check norm
+ VERIFY_IS_APPROX(solver.fvec.blueNorm(), 1.192636e-08);
+
+
+// check x
+ VectorXd x_ref(n);
+ x_ref <<
+ -0.5706545, -0.6816283, -0.7017325,
+ -0.7042129, -0.701369, -0.6918656,
+ -0.665792, -0.5960342, -0.4164121;
+ VERIFY_IS_APPROX(x, x_ref);
+}
+
+void testHybrj()
+{
+ const int n=9;
+ int info;
+ VectorXd x(n);
+
+ /* the following starting values provide a rough fit. */
+ x.setConstant(n, -1.);
+
+
+ // do the computation
+ hybrj_functor functor;
+ HybridNonLinearSolver<hybrj_functor> solver(functor);
+ solver.diag.setConstant(n, 1.);
+ solver.useExternalScaling = true;
+ info = solver.solve(x);
+
+ // check return value
+ VERIFY_IS_EQUAL(info, 1);
+ VERIFY_IS_EQUAL(solver.nfev, 11);
+ VERIFY_IS_EQUAL(solver.njev, 1);
+
+ // check norm
+ VERIFY_IS_APPROX(solver.fvec.blueNorm(), 1.192636e-08);
+
+
+// check x
+ VectorXd x_ref(n);
+ x_ref <<
+ -0.5706545, -0.6816283, -0.7017325,
+ -0.7042129, -0.701369, -0.6918656,
+ -0.665792, -0.5960342, -0.4164121;
+ VERIFY_IS_APPROX(x, x_ref);
+
+}
+
+struct hybrd_functor : Functor<double>
+{
+ hybrd_functor(void) : Functor<double>(9,9) {}
+ int operator()(const VectorXd &x, VectorXd &fvec) const
+ {
+ double temp, temp1, temp2;
+ const int n = x.size();
+
+ assert(fvec.size()==n);
+ for (int k=0; k < n; k++)
+ {
+ temp = (3. - 2.*x[k])*x[k];
+ temp1 = 0.;
+ if (k) temp1 = x[k-1];
+ temp2 = 0.;
+ if (k != n-1) temp2 = x[k+1];
+ fvec[k] = temp - temp1 - 2.*temp2 + 1.;
+ }
+ return 0;
+ }
+};
+
+void testHybrd1()
+{
+ int n=9, info;
+ VectorXd x(n);
+
+ /* the following starting values provide a rough solution. */
+ x.setConstant(n, -1.);
+
+ // do the computation
+ hybrd_functor functor;
+ HybridNonLinearSolver<hybrd_functor> solver(functor);
+ info = solver.hybrd1(x);
+
+ // check return value
+ VERIFY_IS_EQUAL(info, 1);
+ VERIFY_IS_EQUAL(solver.nfev, 20);
+
+ // check norm
+ VERIFY_IS_APPROX(solver.fvec.blueNorm(), 1.192636e-08);
+
+ // check x
+ VectorXd x_ref(n);
+ x_ref << -0.5706545, -0.6816283, -0.7017325, -0.7042129, -0.701369, -0.6918656, -0.665792, -0.5960342, -0.4164121;
+ VERIFY_IS_APPROX(x, x_ref);
+}
+
+void testHybrd()
+{
+ const int n=9;
+ int info;
+ VectorXd x;
+
+ /* the following starting values provide a rough fit. */
+ x.setConstant(n, -1.);
+
+ // do the computation
+ hybrd_functor functor;
+ HybridNonLinearSolver<hybrd_functor> solver(functor);
+ solver.parameters.nb_of_subdiagonals = 1;
+ solver.parameters.nb_of_superdiagonals = 1;
+ solver.diag.setConstant(n, 1.);
+ solver.useExternalScaling = true;
+ info = solver.solveNumericalDiff(x);
+
+ // check return value
+ VERIFY_IS_EQUAL(info, 1);
+ VERIFY_IS_EQUAL(solver.nfev, 14);
+
+ // check norm
+ VERIFY_IS_APPROX(solver.fvec.blueNorm(), 1.192636e-08);
+
+ // check x
+ VectorXd x_ref(n);
+ x_ref <<
+ -0.5706545, -0.6816283, -0.7017325,
+ -0.7042129, -0.701369, -0.6918656,
+ -0.665792, -0.5960342, -0.4164121;
+ VERIFY_IS_APPROX(x, x_ref);
+}
+
+struct lmstr_functor : Functor<double>
+{
+ lmstr_functor(void) : Functor<double>(3,15) {}
+ int operator()(const VectorXd &x, VectorXd &fvec)
+ {
+ /* subroutine fcn for lmstr1 example. */
+ double tmp1, tmp2, tmp3;
+ static const double y[15]={1.4e-1, 1.8e-1, 2.2e-1, 2.5e-1, 2.9e-1, 3.2e-1, 3.5e-1,
+ 3.9e-1, 3.7e-1, 5.8e-1, 7.3e-1, 9.6e-1, 1.34, 2.1, 4.39};
+
+ assert(15==fvec.size());
+ assert(3==x.size());
+
+ for (int i=0; i<15; i++)
+ {
+ tmp1 = i+1;
+ tmp2 = 16 - i - 1;
+ tmp3 = (i>=8)? tmp2 : tmp1;
+ fvec[i] = y[i] - (x[0] + tmp1/(x[1]*tmp2 + x[2]*tmp3));
+ }
+ return 0;
+ }
+ int df(const VectorXd &x, VectorXd &jac_row, VectorXd::Index rownb)
+ {
+ assert(x.size()==3);
+ assert(jac_row.size()==x.size());
+ double tmp1, tmp2, tmp3, tmp4;
+
+ int i = rownb-2;
+ tmp1 = i+1;
+ tmp2 = 16 - i - 1;
+ tmp3 = (i>=8)? tmp2 : tmp1;
+ tmp4 = (x[1]*tmp2 + x[2]*tmp3); tmp4 = tmp4*tmp4;
+ jac_row[0] = -1;
+ jac_row[1] = tmp1*tmp2/tmp4;
+ jac_row[2] = tmp1*tmp3/tmp4;
+ return 0;
+ }
+};
+
+void testLmstr1()
+{
+ const int n=3;
+ int info;
+
+ VectorXd x(n);
+
+ /* the following starting values provide a rough fit. */
+ x.setConstant(n, 1.);
+
+ // do the computation
+ lmstr_functor functor;
+ LevenbergMarquardt<lmstr_functor> lm(functor);
+ info = lm.lmstr1(x);
+
+ // check return value
+ VERIFY_IS_EQUAL(info, 1);
+ VERIFY_IS_EQUAL(lm.nfev, 6);
+ VERIFY_IS_EQUAL(lm.njev, 5);
+
+ // check norm
+ VERIFY_IS_APPROX(lm.fvec.blueNorm(), 0.09063596);
+
+ // check x
+ VectorXd x_ref(n);
+ x_ref << 0.08241058, 1.133037, 2.343695 ;
+ VERIFY_IS_APPROX(x, x_ref);
+}
+
+void testLmstr()
+{
+ const int n=3;
+ int info;
+ double fnorm;
+ VectorXd x(n);
+
+ /* the following starting values provide a rough fit. */
+ x.setConstant(n, 1.);
+
+ // do the computation
+ lmstr_functor functor;
+ LevenbergMarquardt<lmstr_functor> lm(functor);
+ info = lm.minimizeOptimumStorage(x);
+
+ // check return values
+ VERIFY_IS_EQUAL(info, 1);
+ VERIFY_IS_EQUAL(lm.nfev, 6);
+ VERIFY_IS_EQUAL(lm.njev, 5);
+
+ // check norm
+ fnorm = lm.fvec.blueNorm();
+ VERIFY_IS_APPROX(fnorm, 0.09063596);
+
+ // check x
+ VectorXd x_ref(n);
+ x_ref << 0.08241058, 1.133037, 2.343695;
+ VERIFY_IS_APPROX(x, x_ref);
+
+}
+
+struct lmdif_functor : Functor<double>
+{
+ lmdif_functor(void) : Functor<double>(3,15) {}
+ int operator()(const VectorXd &x, VectorXd &fvec) const
+ {
+ int i;
+ double tmp1,tmp2,tmp3;
+ static const double y[15]={1.4e-1,1.8e-1,2.2e-1,2.5e-1,2.9e-1,3.2e-1,3.5e-1,3.9e-1,
+ 3.7e-1,5.8e-1,7.3e-1,9.6e-1,1.34e0,2.1e0,4.39e0};
+
+ assert(x.size()==3);
+ assert(fvec.size()==15);
+ for (i=0; i<15; i++)
+ {
+ tmp1 = i+1;
+ tmp2 = 15 - i;
+ tmp3 = tmp1;
+
+ if (i >= 8) tmp3 = tmp2;
+ fvec[i] = y[i] - (x[0] + tmp1/(x[1]*tmp2 + x[2]*tmp3));
+ }
+ return 0;
+ }
+};
+
+void testLmdif1()
+{
+ const int n=3;
+ int info;
+
+ VectorXd x(n), fvec(15);
+
+ /* the following starting values provide a rough fit. */
+ x.setConstant(n, 1.);
+
+ // do the computation
+ lmdif_functor functor;
+ DenseIndex nfev;
+ info = LevenbergMarquardt<lmdif_functor>::lmdif1(functor, x, &nfev);
+
+ // check return value
+ VERIFY_IS_EQUAL(info, 1);
+ VERIFY_IS_EQUAL(nfev, 26);
+
+ // check norm
+ functor(x, fvec);
+ VERIFY_IS_APPROX(fvec.blueNorm(), 0.09063596);
+
+ // check x
+ VectorXd x_ref(n);
+ x_ref << 0.0824106, 1.1330366, 2.3436947;
+ VERIFY_IS_APPROX(x, x_ref);
+
+}
+
+void testLmdif()
+{
+ const int m=15, n=3;
+ int info;
+ double fnorm, covfac;
+ VectorXd x(n);
+
+ /* the following starting values provide a rough fit. */
+ x.setConstant(n, 1.);
+
+ // do the computation
+ lmdif_functor functor;
+ NumericalDiff<lmdif_functor> numDiff(functor);
+ LevenbergMarquardt<NumericalDiff<lmdif_functor> > lm(numDiff);
+ info = lm.minimize(x);
+
+ // check return values
+ VERIFY_IS_EQUAL(info, 1);
+ VERIFY_IS_EQUAL(lm.nfev, 26);
+
+ // check norm
+ fnorm = lm.fvec.blueNorm();
+ VERIFY_IS_APPROX(fnorm, 0.09063596);
+
+ // check x
+ VectorXd x_ref(n);
+ x_ref << 0.08241058, 1.133037, 2.343695;
+ VERIFY_IS_APPROX(x, x_ref);
+
+ // check covariance
+ covfac = fnorm*fnorm/(m-n);
+ internal::covar(lm.fjac, lm.permutation.indices()); // TODO : move this as a function of lm
+
+ MatrixXd cov_ref(n,n);
+ cov_ref <<
+ 0.0001531202, 0.002869942, -0.002656662,
+ 0.002869942, 0.09480937, -0.09098997,
+ -0.002656662, -0.09098997, 0.08778729;
+
+// std::cout << fjac*covfac << std::endl;
+
+ MatrixXd cov;
+ cov = covfac*lm.fjac.topLeftCorner<n,n>();
+ VERIFY_IS_APPROX( cov, cov_ref);
+ // TODO: why isn't this allowed ? :
+ // VERIFY_IS_APPROX( covfac*fjac.topLeftCorner<n,n>() , cov_ref);
+}
+
+struct chwirut2_functor : Functor<double>
+{
+ chwirut2_functor(void) : Functor<double>(3,54) {}
+ static const double m_x[54];
+ static const double m_y[54];
+ int operator()(const VectorXd &b, VectorXd &fvec)
+ {
+ int i;
+
+ assert(b.size()==3);
+ assert(fvec.size()==54);
+ for(i=0; i<54; i++) {
+ double x = m_x[i];
+ fvec[i] = exp(-b[0]*x)/(b[1]+b[2]*x) - m_y[i];
+ }
+ return 0;
+ }
+ int df(const VectorXd &b, MatrixXd &fjac)
+ {
+ assert(b.size()==3);
+ assert(fjac.rows()==54);
+ assert(fjac.cols()==3);
+ for(int i=0; i<54; i++) {
+ double x = m_x[i];
+ double factor = 1./(b[1]+b[2]*x);
+ double e = exp(-b[0]*x);
+ fjac(i,0) = -x*e*factor;
+ fjac(i,1) = -e*factor*factor;
+ fjac(i,2) = -x*e*factor*factor;
+ }
+ return 0;
+ }
+};
+const double chwirut2_functor::m_x[54] = { 0.500E0, 1.000E0, 1.750E0, 3.750E0, 5.750E0, 0.875E0, 2.250E0, 3.250E0, 5.250E0, 0.750E0, 1.750E0, 2.750E0, 4.750E0, 0.625E0, 1.250E0, 2.250E0, 4.250E0, .500E0, 3.000E0, .750E0, 3.000E0, 1.500E0, 6.000E0, 3.000E0, 6.000E0, 1.500E0, 3.000E0, .500E0, 2.000E0, 4.000E0, .750E0, 2.000E0, 5.000E0, .750E0, 2.250E0, 3.750E0, 5.750E0, 3.000E0, .750E0, 2.500E0, 4.000E0, .750E0, 2.500E0, 4.000E0, .750E0, 2.500E0, 4.000E0, .500E0, 6.000E0, 3.000E0, .500E0, 2.750E0, .500E0, 1.750E0};
+const double chwirut2_functor::m_y[54] = { 92.9000E0 ,57.1000E0 ,31.0500E0 ,11.5875E0 ,8.0250E0 ,63.6000E0 ,21.4000E0 ,14.2500E0 ,8.4750E0 ,63.8000E0 ,26.8000E0 ,16.4625E0 ,7.1250E0 ,67.3000E0 ,41.0000E0 ,21.1500E0 ,8.1750E0 ,81.5000E0 ,13.1200E0 ,59.9000E0 ,14.6200E0 ,32.9000E0 ,5.4400E0 ,12.5600E0 ,5.4400E0 ,32.0000E0 ,13.9500E0 ,75.8000E0 ,20.0000E0 ,10.4200E0 ,59.5000E0 ,21.6700E0 ,8.5500E0 ,62.0000E0 ,20.2000E0 ,7.7600E0 ,3.7500E0 ,11.8100E0 ,54.7000E0 ,23.7000E0 ,11.5500E0 ,61.3000E0 ,17.7000E0 ,8.7400E0 ,59.2000E0 ,16.3000E0 ,8.6200E0 ,81.0000E0 ,4.8700E0 ,14.6200E0 ,81.7000E0 ,17.1700E0 ,81.3000E0 ,28.9000E0 };
+
+// http://www.itl.nist.gov/div898/strd/nls/data/chwirut2.shtml
+void testNistChwirut2(void)
+{
+ const int n=3;
+ int info;
+
+ VectorXd x(n);
+
+ /*
+ * First try
+ */
+ x<< 0.1, 0.01, 0.02;
+ // do the computation
+ chwirut2_functor functor;
+ LevenbergMarquardt<chwirut2_functor> lm(functor);
+ info = lm.minimize(x);
+
+ // check return value
+ VERIFY_IS_EQUAL(info, 1);
+ VERIFY_IS_EQUAL(lm.nfev, 10);
+ VERIFY_IS_EQUAL(lm.njev, 8);
+ // check norm^2
+ VERIFY_IS_APPROX(lm.fvec.squaredNorm(), 5.1304802941E+02);
+ // check x
+ VERIFY_IS_APPROX(x[0], 1.6657666537E-01);
+ VERIFY_IS_APPROX(x[1], 5.1653291286E-03);
+ VERIFY_IS_APPROX(x[2], 1.2150007096E-02);
+
+ /*
+ * Second try
+ */
+ x<< 0.15, 0.008, 0.010;
+ // do the computation
+ lm.resetParameters();
+ lm.parameters.ftol = 1.E6*NumTraits<double>::epsilon();
+ lm.parameters.xtol = 1.E6*NumTraits<double>::epsilon();
+ info = lm.minimize(x);
+
+ // check return value
+ VERIFY_IS_EQUAL(info, 1);
+ VERIFY_IS_EQUAL(lm.nfev, 7);
+ VERIFY_IS_EQUAL(lm.njev, 6);
+ // check norm^2
+ VERIFY_IS_APPROX(lm.fvec.squaredNorm(), 5.1304802941E+02);
+ // check x
+ VERIFY_IS_APPROX(x[0], 1.6657666537E-01);
+ VERIFY_IS_APPROX(x[1], 5.1653291286E-03);
+ VERIFY_IS_APPROX(x[2], 1.2150007096E-02);
+}
+
+
+struct misra1a_functor : Functor<double>
+{
+ misra1a_functor(void) : Functor<double>(2,14) {}
+ static const double m_x[14];
+ static const double m_y[14];
+ int operator()(const VectorXd &b, VectorXd &fvec)
+ {
+ assert(b.size()==2);
+ assert(fvec.size()==14);
+ for(int i=0; i<14; i++) {
+ fvec[i] = b[0]*(1.-exp(-b[1]*m_x[i])) - m_y[i] ;
+ }
+ return 0;
+ }
+ int df(const VectorXd &b, MatrixXd &fjac)
+ {
+ assert(b.size()==2);
+ assert(fjac.rows()==14);
+ assert(fjac.cols()==2);
+ for(int i=0; i<14; i++) {
+ fjac(i,0) = (1.-exp(-b[1]*m_x[i]));
+ fjac(i,1) = (b[0]*m_x[i]*exp(-b[1]*m_x[i]));
+ }
+ return 0;
+ }
+};
+const double misra1a_functor::m_x[14] = { 77.6E0, 114.9E0, 141.1E0, 190.8E0, 239.9E0, 289.0E0, 332.8E0, 378.4E0, 434.8E0, 477.3E0, 536.8E0, 593.1E0, 689.1E0, 760.0E0};
+const double misra1a_functor::m_y[14] = { 10.07E0, 14.73E0, 17.94E0, 23.93E0, 29.61E0, 35.18E0, 40.02E0, 44.82E0, 50.76E0, 55.05E0, 61.01E0, 66.40E0, 75.47E0, 81.78E0};
+
+// http://www.itl.nist.gov/div898/strd/nls/data/misra1a.shtml
+void testNistMisra1a(void)
+{
+ const int n=2;
+ int info;
+
+ VectorXd x(n);
+
+ /*
+ * First try
+ */
+ x<< 500., 0.0001;
+ // do the computation
+ misra1a_functor functor;
+ LevenbergMarquardt<misra1a_functor> lm(functor);
+ info = lm.minimize(x);
+
+ // check return value
+ VERIFY_IS_EQUAL(info, 1);
+ VERIFY_IS_EQUAL(lm.nfev, 19);
+ VERIFY_IS_EQUAL(lm.njev, 15);
+ // check norm^2
+ VERIFY_IS_APPROX(lm.fvec.squaredNorm(), 1.2455138894E-01);
+ // check x
+ VERIFY_IS_APPROX(x[0], 2.3894212918E+02);
+ VERIFY_IS_APPROX(x[1], 5.5015643181E-04);
+
+ /*
+ * Second try
+ */
+ x<< 250., 0.0005;
+ // do the computation
+ info = lm.minimize(x);
+
+ // check return value
+ VERIFY_IS_EQUAL(info, 1);
+ VERIFY_IS_EQUAL(lm.nfev, 5);
+ VERIFY_IS_EQUAL(lm.njev, 4);
+ // check norm^2
+ VERIFY_IS_APPROX(lm.fvec.squaredNorm(), 1.2455138894E-01);
+ // check x
+ VERIFY_IS_APPROX(x[0], 2.3894212918E+02);
+ VERIFY_IS_APPROX(x[1], 5.5015643181E-04);
+}
+
+struct hahn1_functor : Functor<double>
+{
+ hahn1_functor(void) : Functor<double>(7,236) {}
+ static const double m_x[236];
+ int operator()(const VectorXd &b, VectorXd &fvec)
+ {
+ static const double m_y[236] = { .591E0 , 1.547E0 , 2.902E0 , 2.894E0 , 4.703E0 , 6.307E0 , 7.03E0 , 7.898E0 , 9.470E0 , 9.484E0 , 10.072E0 , 10.163E0 , 11.615E0 , 12.005E0 , 12.478E0 , 12.982E0 , 12.970E0 , 13.926E0 , 14.452E0 , 14.404E0 , 15.190E0 , 15.550E0 , 15.528E0 , 15.499E0 , 16.131E0 , 16.438E0 , 16.387E0 , 16.549E0 , 16.872E0 , 16.830E0 , 16.926E0 , 16.907E0 , 16.966E0 , 17.060E0 , 17.122E0 , 17.311E0 , 17.355E0 , 17.668E0 , 17.767E0 , 17.803E0 , 17.765E0 , 17.768E0 , 17.736E0 , 17.858E0 , 17.877E0 , 17.912E0 , 18.046E0 , 18.085E0 , 18.291E0 , 18.357E0 , 18.426E0 , 18.584E0 , 18.610E0 , 18.870E0 , 18.795E0 , 19.111E0 , .367E0 , .796E0 , 0.892E0 , 1.903E0 , 2.150E0 , 3.697E0 , 5.870E0 , 6.421E0 , 7.422E0 , 9.944E0 , 11.023E0 , 11.87E0 , 12.786E0 , 14.067E0 , 13.974E0 , 14.462E0 , 14.464E0 , 15.381E0 , 15.483E0 , 15.59E0 , 16.075E0 , 16.347E0 , 16.181E0 , 16.915E0 , 17.003E0 , 16.978E0 , 17.756E0 , 17.808E0 , 17.868E0 , 18.481E0 , 18.486E0 , 19.090E0 , 16.062E0 , 16.337E0 , 16.345E0 , 16.388E0 , 17.159E0 , 17.116E0 , 17.164E0 , 17.123E0 , 17.979E0 , 17.974E0 , 18.007E0 , 17.993E0 , 18.523E0 , 18.669E0 , 18.617E0 , 19.371E0 , 19.330E0 , 0.080E0 , 0.248E0 , 1.089E0 , 1.418E0 , 2.278E0 , 3.624E0 , 4.574E0 , 5.556E0 , 7.267E0 , 7.695E0 , 9.136E0 , 9.959E0 , 9.957E0 , 11.600E0 , 13.138E0 , 13.564E0 , 13.871E0 , 13.994E0 , 14.947E0 , 15.473E0 , 15.379E0 , 15.455E0 , 15.908E0 , 16.114E0 , 17.071E0 , 17.135E0 , 17.282E0 , 17.368E0 , 17.483E0 , 17.764E0 , 18.185E0 , 18.271E0 , 18.236E0 , 18.237E0 , 18.523E0 , 18.627E0 , 18.665E0 , 19.086E0 , 0.214E0 , 0.943E0 , 1.429E0 , 2.241E0 , 2.951E0 , 3.782E0 , 4.757E0 , 5.602E0 , 7.169E0 , 8.920E0 , 10.055E0 , 12.035E0 , 12.861E0 , 13.436E0 , 14.167E0 , 14.755E0 , 15.168E0 , 15.651E0 , 15.746E0 , 16.216E0 , 16.445E0 , 16.965E0 , 17.121E0 , 17.206E0 , 17.250E0 , 17.339E0 , 17.793E0 , 18.123E0 , 18.49E0 , 18.566E0 , 18.645E0 , 18.706E0 , 18.924E0 , 19.1E0 , 0.375E0 , 0.471E0 , 1.504E0 , 2.204E0 , 2.813E0 , 4.765E0 , 9.835E0 , 10.040E0 , 11.946E0 , 12.596E0 , 13.303E0 , 13.922E0 , 14.440E0 , 14.951E0 , 15.627E0 , 15.639E0 , 15.814E0 , 16.315E0 , 16.334E0 , 16.430E0 , 16.423E0 , 17.024E0 , 17.009E0 , 17.165E0 , 17.134E0 , 17.349E0 , 17.576E0 , 17.848E0 , 18.090E0 , 18.276E0 , 18.404E0 , 18.519E0 , 19.133E0 , 19.074E0 , 19.239E0 , 19.280E0 , 19.101E0 , 19.398E0 , 19.252E0 , 19.89E0 , 20.007E0 , 19.929E0 , 19.268E0 , 19.324E0 , 20.049E0 , 20.107E0 , 20.062E0 , 20.065E0 , 19.286E0 , 19.972E0 , 20.088E0 , 20.743E0 , 20.83E0 , 20.935E0 , 21.035E0 , 20.93E0 , 21.074E0 , 21.085E0 , 20.935E0 };
+
+ // int called=0; printf("call hahn1_functor with iflag=%d, called=%d\n", iflag, called); if (iflag==1) called++;
+
+ assert(b.size()==7);
+ assert(fvec.size()==236);
+ for(int i=0; i<236; i++) {
+ double x=m_x[i], xx=x*x, xxx=xx*x;
+ fvec[i] = (b[0]+b[1]*x+b[2]*xx+b[3]*xxx) / (1.+b[4]*x+b[5]*xx+b[6]*xxx) - m_y[i];
+ }
+ return 0;
+ }
+
+ int df(const VectorXd &b, MatrixXd &fjac)
+ {
+ assert(b.size()==7);
+ assert(fjac.rows()==236);
+ assert(fjac.cols()==7);
+ for(int i=0; i<236; i++) {
+ double x=m_x[i], xx=x*x, xxx=xx*x;
+ double fact = 1./(1.+b[4]*x+b[5]*xx+b[6]*xxx);
+ fjac(i,0) = 1.*fact;
+ fjac(i,1) = x*fact;
+ fjac(i,2) = xx*fact;
+ fjac(i,3) = xxx*fact;
+ fact = - (b[0]+b[1]*x+b[2]*xx+b[3]*xxx) * fact * fact;
+ fjac(i,4) = x*fact;
+ fjac(i,5) = xx*fact;
+ fjac(i,6) = xxx*fact;
+ }
+ return 0;
+ }
+};
+const double hahn1_functor::m_x[236] = { 24.41E0 , 34.82E0 , 44.09E0 , 45.07E0 , 54.98E0 , 65.51E0 , 70.53E0 , 75.70E0 , 89.57E0 , 91.14E0 , 96.40E0 , 97.19E0 , 114.26E0 , 120.25E0 , 127.08E0 , 133.55E0 , 133.61E0 , 158.67E0 , 172.74E0 , 171.31E0 , 202.14E0 , 220.55E0 , 221.05E0 , 221.39E0 , 250.99E0 , 268.99E0 , 271.80E0 , 271.97E0 , 321.31E0 , 321.69E0 , 330.14E0 , 333.03E0 , 333.47E0 , 340.77E0 , 345.65E0 , 373.11E0 , 373.79E0 , 411.82E0 , 419.51E0 , 421.59E0 , 422.02E0 , 422.47E0 , 422.61E0 , 441.75E0 , 447.41E0 , 448.7E0 , 472.89E0 , 476.69E0 , 522.47E0 , 522.62E0 , 524.43E0 , 546.75E0 , 549.53E0 , 575.29E0 , 576.00E0 , 625.55E0 , 20.15E0 , 28.78E0 , 29.57E0 , 37.41E0 , 39.12E0 , 50.24E0 , 61.38E0 , 66.25E0 , 73.42E0 , 95.52E0 , 107.32E0 , 122.04E0 , 134.03E0 , 163.19E0 , 163.48E0 , 175.70E0 , 179.86E0 , 211.27E0 , 217.78E0 , 219.14E0 , 262.52E0 , 268.01E0 , 268.62E0 , 336.25E0 , 337.23E0 , 339.33E0 , 427.38E0 , 428.58E0 , 432.68E0 , 528.99E0 , 531.08E0 , 628.34E0 , 253.24E0 , 273.13E0 , 273.66E0 , 282.10E0 , 346.62E0 , 347.19E0 , 348.78E0 , 351.18E0 , 450.10E0 , 450.35E0 , 451.92E0 , 455.56E0 , 552.22E0 , 553.56E0 , 555.74E0 , 652.59E0 , 656.20E0 , 14.13E0 , 20.41E0 , 31.30E0 , 33.84E0 , 39.70E0 , 48.83E0 , 54.50E0 , 60.41E0 , 72.77E0 , 75.25E0 , 86.84E0 , 94.88E0 , 96.40E0 , 117.37E0 , 139.08E0 , 147.73E0 , 158.63E0 , 161.84E0 , 192.11E0 , 206.76E0 , 209.07E0 , 213.32E0 , 226.44E0 , 237.12E0 , 330.90E0 , 358.72E0 , 370.77E0 , 372.72E0 , 396.24E0 , 416.59E0 , 484.02E0 , 495.47E0 , 514.78E0 , 515.65E0 , 519.47E0 , 544.47E0 , 560.11E0 , 620.77E0 , 18.97E0 , 28.93E0 , 33.91E0 , 40.03E0 , 44.66E0 , 49.87E0 , 55.16E0 , 60.90E0 , 72.08E0 , 85.15E0 , 97.06E0 , 119.63E0 , 133.27E0 , 143.84E0 , 161.91E0 , 180.67E0 , 198.44E0 , 226.86E0 , 229.65E0 , 258.27E0 , 273.77E0 , 339.15E0 , 350.13E0 , 362.75E0 , 371.03E0 , 393.32E0 , 448.53E0 , 473.78E0 , 511.12E0 , 524.70E0 , 548.75E0 , 551.64E0 , 574.02E0 , 623.86E0 , 21.46E0 , 24.33E0 , 33.43E0 , 39.22E0 , 44.18E0 , 55.02E0 , 94.33E0 , 96.44E0 , 118.82E0 , 128.48E0 , 141.94E0 , 156.92E0 , 171.65E0 , 190.00E0 , 223.26E0 , 223.88E0 , 231.50E0 , 265.05E0 , 269.44E0 , 271.78E0 , 273.46E0 , 334.61E0 , 339.79E0 , 349.52E0 , 358.18E0 , 377.98E0 , 394.77E0 , 429.66E0 , 468.22E0 , 487.27E0 , 519.54E0 , 523.03E0 , 612.99E0 , 638.59E0 , 641.36E0 , 622.05E0 , 631.50E0 , 663.97E0 , 646.9E0 , 748.29E0 , 749.21E0 , 750.14E0 , 647.04E0 , 646.89E0 , 746.9E0 , 748.43E0 , 747.35E0 , 749.27E0 , 647.61E0 , 747.78E0 , 750.51E0 , 851.37E0 , 845.97E0 , 847.54E0 , 849.93E0 , 851.61E0 , 849.75E0 , 850.98E0 , 848.23E0};
+
+// http://www.itl.nist.gov/div898/strd/nls/data/hahn1.shtml
+void testNistHahn1(void)
+{
+ const int n=7;
+ int info;
+
+ VectorXd x(n);
+
+ /*
+ * First try
+ */
+ x<< 10., -1., .05, -.00001, -.05, .001, -.000001;
+ // do the computation
+ hahn1_functor functor;
+ LevenbergMarquardt<hahn1_functor> lm(functor);
+ info = lm.minimize(x);
+
+ // check return value
+ VERIFY_IS_EQUAL(info, 1);
+ VERIFY_IS_EQUAL(lm.nfev, 11);
+ VERIFY_IS_EQUAL(lm.njev, 10);
+ // check norm^2
+ VERIFY_IS_APPROX(lm.fvec.squaredNorm(), 1.5324382854E+00);
+ // check x
+ VERIFY_IS_APPROX(x[0], 1.0776351733E+00);
+ VERIFY_IS_APPROX(x[1],-1.2269296921E-01);
+ VERIFY_IS_APPROX(x[2], 4.0863750610E-03);
+ VERIFY_IS_APPROX(x[3],-1.426264e-06); // shoulde be : -1.4262662514E-06
+ VERIFY_IS_APPROX(x[4],-5.7609940901E-03);
+ VERIFY_IS_APPROX(x[5], 2.4053735503E-04);
+ VERIFY_IS_APPROX(x[6],-1.2314450199E-07);
+
+ /*
+ * Second try
+ */
+ x<< .1, -.1, .005, -.000001, -.005, .0001, -.0000001;
+ // do the computation
+ info = lm.minimize(x);
+
+ // check return value
+ VERIFY_IS_EQUAL(info, 1);
+ VERIFY_IS_EQUAL(lm.nfev, 11);
+ VERIFY_IS_EQUAL(lm.njev, 10);
+ // check norm^2
+ VERIFY_IS_APPROX(lm.fvec.squaredNorm(), 1.5324382854E+00);
+ // check x
+ VERIFY_IS_APPROX(x[0], 1.077640); // should be : 1.0776351733E+00
+ VERIFY_IS_APPROX(x[1], -0.1226933); // should be : -1.2269296921E-01
+ VERIFY_IS_APPROX(x[2], 0.004086383); // should be : 4.0863750610E-03
+ VERIFY_IS_APPROX(x[3], -1.426277e-06); // shoulde be : -1.4262662514E-06
+ VERIFY_IS_APPROX(x[4],-5.7609940901E-03);
+ VERIFY_IS_APPROX(x[5], 0.00024053772); // should be : 2.4053735503E-04
+ VERIFY_IS_APPROX(x[6], -1.231450e-07); // should be : -1.2314450199E-07
+
+}
+
+struct misra1d_functor : Functor<double>
+{
+ misra1d_functor(void) : Functor<double>(2,14) {}
+ static const double x[14];
+ static const double y[14];
+ int operator()(const VectorXd &b, VectorXd &fvec)
+ {
+ assert(b.size()==2);
+ assert(fvec.size()==14);
+ for(int i=0; i<14; i++) {
+ fvec[i] = b[0]*b[1]*x[i]/(1.+b[1]*x[i]) - y[i];
+ }
+ return 0;
+ }
+ int df(const VectorXd &b, MatrixXd &fjac)
+ {
+ assert(b.size()==2);
+ assert(fjac.rows()==14);
+ assert(fjac.cols()==2);
+ for(int i=0; i<14; i++) {
+ double den = 1.+b[1]*x[i];
+ fjac(i,0) = b[1]*x[i] / den;
+ fjac(i,1) = b[0]*x[i]*(den-b[1]*x[i])/den/den;
+ }
+ return 0;
+ }
+};
+const double misra1d_functor::x[14] = { 77.6E0, 114.9E0, 141.1E0, 190.8E0, 239.9E0, 289.0E0, 332.8E0, 378.4E0, 434.8E0, 477.3E0, 536.8E0, 593.1E0, 689.1E0, 760.0E0};
+const double misra1d_functor::y[14] = { 10.07E0, 14.73E0, 17.94E0, 23.93E0, 29.61E0, 35.18E0, 40.02E0, 44.82E0, 50.76E0, 55.05E0, 61.01E0, 66.40E0, 75.47E0, 81.78E0};
+
+// http://www.itl.nist.gov/div898/strd/nls/data/misra1d.shtml
+void testNistMisra1d(void)
+{
+ const int n=2;
+ int info;
+
+ VectorXd x(n);
+
+ /*
+ * First try
+ */
+ x<< 500., 0.0001;
+ // do the computation
+ misra1d_functor functor;
+ LevenbergMarquardt<misra1d_functor> lm(functor);
+ info = lm.minimize(x);
+
+ // check return value
+ VERIFY_IS_EQUAL(info, 3);
+ VERIFY_IS_EQUAL(lm.nfev, 9);
+ VERIFY_IS_EQUAL(lm.njev, 7);
+ // check norm^2
+ VERIFY_IS_APPROX(lm.fvec.squaredNorm(), 5.6419295283E-02);
+ // check x
+ VERIFY_IS_APPROX(x[0], 4.3736970754E+02);
+ VERIFY_IS_APPROX(x[1], 3.0227324449E-04);
+
+ /*
+ * Second try
+ */
+ x<< 450., 0.0003;
+ // do the computation
+ info = lm.minimize(x);
+
+ // check return value
+ VERIFY_IS_EQUAL(info, 1);
+ VERIFY_IS_EQUAL(lm.nfev, 4);
+ VERIFY_IS_EQUAL(lm.njev, 3);
+ // check norm^2
+ VERIFY_IS_APPROX(lm.fvec.squaredNorm(), 5.6419295283E-02);
+ // check x
+ VERIFY_IS_APPROX(x[0], 4.3736970754E+02);
+ VERIFY_IS_APPROX(x[1], 3.0227324449E-04);
+}
+
+
+struct lanczos1_functor : Functor<double>
+{
+ lanczos1_functor(void) : Functor<double>(6,24) {}
+ static const double x[24];
+ static const double y[24];
+ int operator()(const VectorXd &b, VectorXd &fvec)
+ {
+ assert(b.size()==6);
+ assert(fvec.size()==24);
+ for(int i=0; i<24; i++)
+ fvec[i] = b[0]*exp(-b[1]*x[i]) + b[2]*exp(-b[3]*x[i]) + b[4]*exp(-b[5]*x[i]) - y[i];
+ return 0;
+ }
+ int df(const VectorXd &b, MatrixXd &fjac)
+ {
+ assert(b.size()==6);
+ assert(fjac.rows()==24);
+ assert(fjac.cols()==6);
+ for(int i=0; i<24; i++) {
+ fjac(i,0) = exp(-b[1]*x[i]);
+ fjac(i,1) = -b[0]*x[i]*exp(-b[1]*x[i]);
+ fjac(i,2) = exp(-b[3]*x[i]);
+ fjac(i,3) = -b[2]*x[i]*exp(-b[3]*x[i]);
+ fjac(i,4) = exp(-b[5]*x[i]);
+ fjac(i,5) = -b[4]*x[i]*exp(-b[5]*x[i]);
+ }
+ return 0;
+ }
+};
+const double lanczos1_functor::x[24] = { 0.000000000000E+00, 5.000000000000E-02, 1.000000000000E-01, 1.500000000000E-01, 2.000000000000E-01, 2.500000000000E-01, 3.000000000000E-01, 3.500000000000E-01, 4.000000000000E-01, 4.500000000000E-01, 5.000000000000E-01, 5.500000000000E-01, 6.000000000000E-01, 6.500000000000E-01, 7.000000000000E-01, 7.500000000000E-01, 8.000000000000E-01, 8.500000000000E-01, 9.000000000000E-01, 9.500000000000E-01, 1.000000000000E+00, 1.050000000000E+00, 1.100000000000E+00, 1.150000000000E+00 };
+const double lanczos1_functor::y[24] = { 2.513400000000E+00 ,2.044333373291E+00 ,1.668404436564E+00 ,1.366418021208E+00 ,1.123232487372E+00 ,9.268897180037E-01 ,7.679338563728E-01 ,6.388775523106E-01 ,5.337835317402E-01 ,4.479363617347E-01 ,3.775847884350E-01 ,3.197393199326E-01 ,2.720130773746E-01 ,2.324965529032E-01 ,1.996589546065E-01 ,1.722704126914E-01 ,1.493405660168E-01 ,1.300700206922E-01 ,1.138119324644E-01 ,1.000415587559E-01 ,8.833209084540E-02 ,7.833544019350E-02 ,6.976693743449E-02 ,6.239312536719E-02 };
+
+// http://www.itl.nist.gov/div898/strd/nls/data/lanczos1.shtml
+void testNistLanczos1(void)
+{
+ const int n=6;
+ int info;
+
+ VectorXd x(n);
+
+ /*
+ * First try
+ */
+ x<< 1.2, 0.3, 5.6, 5.5, 6.5, 7.6;
+ // do the computation
+ lanczos1_functor functor;
+ LevenbergMarquardt<lanczos1_functor> lm(functor);
+ info = lm.minimize(x);
+
+ // check return value
+ VERIFY_IS_EQUAL(info, 2);
+ VERIFY_IS_EQUAL(lm.nfev, 79);
+ VERIFY_IS_EQUAL(lm.njev, 72);
+ // check norm^2
+ VERIFY_IS_APPROX(lm.fvec.squaredNorm(), 1.430899764097e-25); // should be 1.4307867721E-25, but nist results are on 128-bit floats
+ // check x
+ VERIFY_IS_APPROX(x[0], 9.5100000027E-02);
+ VERIFY_IS_APPROX(x[1], 1.0000000001E+00);
+ VERIFY_IS_APPROX(x[2], 8.6070000013E-01);
+ VERIFY_IS_APPROX(x[3], 3.0000000002E+00);
+ VERIFY_IS_APPROX(x[4], 1.5575999998E+00);
+ VERIFY_IS_APPROX(x[5], 5.0000000001E+00);
+
+ /*
+ * Second try
+ */
+ x<< 0.5, 0.7, 3.6, 4.2, 4., 6.3;
+ // do the computation
+ info = lm.minimize(x);
+
+ // check return value
+ VERIFY_IS_EQUAL(info, 2);
+ VERIFY_IS_EQUAL(lm.nfev, 9);
+ VERIFY_IS_EQUAL(lm.njev, 8);
+ // check norm^2
+ VERIFY_IS_APPROX(lm.fvec.squaredNorm(), 1.428595533845e-25); // should be 1.4307867721E-25, but nist results are on 128-bit floats
+ // check x
+ VERIFY_IS_APPROX(x[0], 9.5100000027E-02);
+ VERIFY_IS_APPROX(x[1], 1.0000000001E+00);
+ VERIFY_IS_APPROX(x[2], 8.6070000013E-01);
+ VERIFY_IS_APPROX(x[3], 3.0000000002E+00);
+ VERIFY_IS_APPROX(x[4], 1.5575999998E+00);
+ VERIFY_IS_APPROX(x[5], 5.0000000001E+00);
+
+}
+
+struct rat42_functor : Functor<double>
+{
+ rat42_functor(void) : Functor<double>(3,9) {}
+ static const double x[9];
+ static const double y[9];
+ int operator()(const VectorXd &b, VectorXd &fvec)
+ {
+ assert(b.size()==3);
+ assert(fvec.size()==9);
+ for(int i=0; i<9; i++) {
+ fvec[i] = b[0] / (1.+exp(b[1]-b[2]*x[i])) - y[i];
+ }
+ return 0;
+ }
+
+ int df(const VectorXd &b, MatrixXd &fjac)
+ {
+ assert(b.size()==3);
+ assert(fjac.rows()==9);
+ assert(fjac.cols()==3);
+ for(int i=0; i<9; i++) {
+ double e = exp(b[1]-b[2]*x[i]);
+ fjac(i,0) = 1./(1.+e);
+ fjac(i,1) = -b[0]*e/(1.+e)/(1.+e);
+ fjac(i,2) = +b[0]*e*x[i]/(1.+e)/(1.+e);
+ }
+ return 0;
+ }
+};
+const double rat42_functor::x[9] = { 9.000E0, 14.000E0, 21.000E0, 28.000E0, 42.000E0, 57.000E0, 63.000E0, 70.000E0, 79.000E0 };
+const double rat42_functor::y[9] = { 8.930E0 ,10.800E0 ,18.590E0 ,22.330E0 ,39.350E0 ,56.110E0 ,61.730E0 ,64.620E0 ,67.080E0 };
+
+// http://www.itl.nist.gov/div898/strd/nls/data/ratkowsky2.shtml
+void testNistRat42(void)
+{
+ const int n=3;
+ int info;
+
+ VectorXd x(n);
+
+ /*
+ * First try
+ */
+ x<< 100., 1., 0.1;
+ // do the computation
+ rat42_functor functor;
+ LevenbergMarquardt<rat42_functor> lm(functor);
+ info = lm.minimize(x);
+
+ // check return value
+ VERIFY_IS_EQUAL(info, 1);
+ VERIFY_IS_EQUAL(lm.nfev, 10);
+ VERIFY_IS_EQUAL(lm.njev, 8);
+ // check norm^2
+ VERIFY_IS_APPROX(lm.fvec.squaredNorm(), 8.0565229338E+00);
+ // check x
+ VERIFY_IS_APPROX(x[0], 7.2462237576E+01);
+ VERIFY_IS_APPROX(x[1], 2.6180768402E+00);
+ VERIFY_IS_APPROX(x[2], 6.7359200066E-02);
+
+ /*
+ * Second try
+ */
+ x<< 75., 2.5, 0.07;
+ // do the computation
+ info = lm.minimize(x);
+
+ // check return value
+ VERIFY_IS_EQUAL(info, 1);
+ VERIFY_IS_EQUAL(lm.nfev, 6);
+ VERIFY_IS_EQUAL(lm.njev, 5);
+ // check norm^2
+ VERIFY_IS_APPROX(lm.fvec.squaredNorm(), 8.0565229338E+00);
+ // check x
+ VERIFY_IS_APPROX(x[0], 7.2462237576E+01);
+ VERIFY_IS_APPROX(x[1], 2.6180768402E+00);
+ VERIFY_IS_APPROX(x[2], 6.7359200066E-02);
+}
+
+struct MGH10_functor : Functor<double>
+{
+ MGH10_functor(void) : Functor<double>(3,16) {}
+ static const double x[16];
+ static const double y[16];
+ int operator()(const VectorXd &b, VectorXd &fvec)
+ {
+ assert(b.size()==3);
+ assert(fvec.size()==16);
+ for(int i=0; i<16; i++)
+ fvec[i] = b[0] * exp(b[1]/(x[i]+b[2])) - y[i];
+ return 0;
+ }
+ int df(const VectorXd &b, MatrixXd &fjac)
+ {
+ assert(b.size()==3);
+ assert(fjac.rows()==16);
+ assert(fjac.cols()==3);
+ for(int i=0; i<16; i++) {
+ double factor = 1./(x[i]+b[2]);
+ double e = exp(b[1]*factor);
+ fjac(i,0) = e;
+ fjac(i,1) = b[0]*factor*e;
+ fjac(i,2) = -b[1]*b[0]*factor*factor*e;
+ }
+ return 0;
+ }
+};
+const double MGH10_functor::x[16] = { 5.000000E+01, 5.500000E+01, 6.000000E+01, 6.500000E+01, 7.000000E+01, 7.500000E+01, 8.000000E+01, 8.500000E+01, 9.000000E+01, 9.500000E+01, 1.000000E+02, 1.050000E+02, 1.100000E+02, 1.150000E+02, 1.200000E+02, 1.250000E+02 };
+const double MGH10_functor::y[16] = { 3.478000E+04, 2.861000E+04, 2.365000E+04, 1.963000E+04, 1.637000E+04, 1.372000E+04, 1.154000E+04, 9.744000E+03, 8.261000E+03, 7.030000E+03, 6.005000E+03, 5.147000E+03, 4.427000E+03, 3.820000E+03, 3.307000E+03, 2.872000E+03 };
+
+// http://www.itl.nist.gov/div898/strd/nls/data/mgh10.shtml
+void testNistMGH10(void)
+{
+ const int n=3;
+ int info;
+
+ VectorXd x(n);
+
+ /*
+ * First try
+ */
+ x<< 2., 400000., 25000.;
+ // do the computation
+ MGH10_functor functor;
+ LevenbergMarquardt<MGH10_functor> lm(functor);
+ info = lm.minimize(x);
+
+ // check return value
+ VERIFY_IS_EQUAL(info, 2);
+ VERIFY_IS_EQUAL(lm.nfev, 284 );
+ VERIFY_IS_EQUAL(lm.njev, 249 );
+ // check norm^2
+ VERIFY_IS_APPROX(lm.fvec.squaredNorm(), 8.7945855171E+01);
+ // check x
+ VERIFY_IS_APPROX(x[0], 5.6096364710E-03);
+ VERIFY_IS_APPROX(x[1], 6.1813463463E+03);
+ VERIFY_IS_APPROX(x[2], 3.4522363462E+02);
+
+ /*
+ * Second try
+ */
+ x<< 0.02, 4000., 250.;
+ // do the computation
+ info = lm.minimize(x);
+
+ // check return value
+ VERIFY_IS_EQUAL(info, 3);
+ VERIFY_IS_EQUAL(lm.nfev, 126);
+ VERIFY_IS_EQUAL(lm.njev, 116);
+ // check norm^2
+ VERIFY_IS_APPROX(lm.fvec.squaredNorm(), 8.7945855171E+01);
+ // check x
+ VERIFY_IS_APPROX(x[0], 5.6096364710E-03);
+ VERIFY_IS_APPROX(x[1], 6.1813463463E+03);
+ VERIFY_IS_APPROX(x[2], 3.4522363462E+02);
+}
+
+
+struct BoxBOD_functor : Functor<double>
+{
+ BoxBOD_functor(void) : Functor<double>(2,6) {}
+ static const double x[6];
+ int operator()(const VectorXd &b, VectorXd &fvec)
+ {
+ static const double y[6] = { 109., 149., 149., 191., 213., 224. };
+ assert(b.size()==2);
+ assert(fvec.size()==6);
+ for(int i=0; i<6; i++)
+ fvec[i] = b[0]*(1.-exp(-b[1]*x[i])) - y[i];
+ return 0;
+ }
+ int df(const VectorXd &b, MatrixXd &fjac)
+ {
+ assert(b.size()==2);
+ assert(fjac.rows()==6);
+ assert(fjac.cols()==2);
+ for(int i=0; i<6; i++) {
+ double e = exp(-b[1]*x[i]);
+ fjac(i,0) = 1.-e;
+ fjac(i,1) = b[0]*x[i]*e;
+ }
+ return 0;
+ }
+};
+const double BoxBOD_functor::x[6] = { 1., 2., 3., 5., 7., 10. };
+
+// http://www.itl.nist.gov/div898/strd/nls/data/boxbod.shtml
+void testNistBoxBOD(void)
+{
+ const int n=2;
+ int info;
+
+ VectorXd x(n);
+
+ /*
+ * First try
+ */
+ x<< 1., 1.;
+ // do the computation
+ BoxBOD_functor functor;
+ LevenbergMarquardt<BoxBOD_functor> lm(functor);
+ lm.parameters.ftol = 1.E6*NumTraits<double>::epsilon();
+ lm.parameters.xtol = 1.E6*NumTraits<double>::epsilon();
+ lm.parameters.factor = 10.;
+ info = lm.minimize(x);
+
+ // check return value
+ VERIFY_IS_EQUAL(info, 1);
+ VERIFY_IS_EQUAL(lm.nfev, 31);
+ VERIFY_IS_EQUAL(lm.njev, 25);
+ // check norm^2
+ VERIFY_IS_APPROX(lm.fvec.squaredNorm(), 1.1680088766E+03);
+ // check x
+ VERIFY_IS_APPROX(x[0], 2.1380940889E+02);
+ VERIFY_IS_APPROX(x[1], 5.4723748542E-01);
+
+ /*
+ * Second try
+ */
+ x<< 100., 0.75;
+ // do the computation
+ lm.resetParameters();
+ lm.parameters.ftol = NumTraits<double>::epsilon();
+ lm.parameters.xtol = NumTraits<double>::epsilon();
+ info = lm.minimize(x);
+
+ // check return value
+ VERIFY_IS_EQUAL(info, 1);
+ VERIFY_IS_EQUAL(lm.nfev, 15 );
+ VERIFY_IS_EQUAL(lm.njev, 14 );
+ // check norm^2
+ VERIFY_IS_APPROX(lm.fvec.squaredNorm(), 1.1680088766E+03);
+ // check x
+ VERIFY_IS_APPROX(x[0], 2.1380940889E+02);
+ VERIFY_IS_APPROX(x[1], 5.4723748542E-01);
+}
+
+struct MGH17_functor : Functor<double>
+{
+ MGH17_functor(void) : Functor<double>(5,33) {}
+ static const double x[33];
+ static const double y[33];
+ int operator()(const VectorXd &b, VectorXd &fvec)
+ {
+ assert(b.size()==5);
+ assert(fvec.size()==33);
+ for(int i=0; i<33; i++)
+ fvec[i] = b[0] + b[1]*exp(-b[3]*x[i]) + b[2]*exp(-b[4]*x[i]) - y[i];
+ return 0;
+ }
+ int df(const VectorXd &b, MatrixXd &fjac)
+ {
+ assert(b.size()==5);
+ assert(fjac.rows()==33);
+ assert(fjac.cols()==5);
+ for(int i=0; i<33; i++) {
+ fjac(i,0) = 1.;
+ fjac(i,1) = exp(-b[3]*x[i]);
+ fjac(i,2) = exp(-b[4]*x[i]);
+ fjac(i,3) = -x[i]*b[1]*exp(-b[3]*x[i]);
+ fjac(i,4) = -x[i]*b[2]*exp(-b[4]*x[i]);
+ }
+ return 0;
+ }
+};
+const double MGH17_functor::x[33] = { 0.000000E+00, 1.000000E+01, 2.000000E+01, 3.000000E+01, 4.000000E+01, 5.000000E+01, 6.000000E+01, 7.000000E+01, 8.000000E+01, 9.000000E+01, 1.000000E+02, 1.100000E+02, 1.200000E+02, 1.300000E+02, 1.400000E+02, 1.500000E+02, 1.600000E+02, 1.700000E+02, 1.800000E+02, 1.900000E+02, 2.000000E+02, 2.100000E+02, 2.200000E+02, 2.300000E+02, 2.400000E+02, 2.500000E+02, 2.600000E+02, 2.700000E+02, 2.800000E+02, 2.900000E+02, 3.000000E+02, 3.100000E+02, 3.200000E+02 };
+const double MGH17_functor::y[33] = { 8.440000E-01, 9.080000E-01, 9.320000E-01, 9.360000E-01, 9.250000E-01, 9.080000E-01, 8.810000E-01, 8.500000E-01, 8.180000E-01, 7.840000E-01, 7.510000E-01, 7.180000E-01, 6.850000E-01, 6.580000E-01, 6.280000E-01, 6.030000E-01, 5.800000E-01, 5.580000E-01, 5.380000E-01, 5.220000E-01, 5.060000E-01, 4.900000E-01, 4.780000E-01, 4.670000E-01, 4.570000E-01, 4.480000E-01, 4.380000E-01, 4.310000E-01, 4.240000E-01, 4.200000E-01, 4.140000E-01, 4.110000E-01, 4.060000E-01 };
+
+// http://www.itl.nist.gov/div898/strd/nls/data/mgh17.shtml
+void testNistMGH17(void)
+{
+ const int n=5;
+ int info;
+
+ VectorXd x(n);
+
+ /*
+ * First try
+ */
+ x<< 50., 150., -100., 1., 2.;
+ // do the computation
+ MGH17_functor functor;
+ LevenbergMarquardt<MGH17_functor> lm(functor);
+ lm.parameters.ftol = NumTraits<double>::epsilon();
+ lm.parameters.xtol = NumTraits<double>::epsilon();
+ lm.parameters.maxfev = 1000;
+ info = lm.minimize(x);
+
+ // check return value
+ VERIFY_IS_EQUAL(info, 2);
+ VERIFY_IS_EQUAL(lm.nfev, 602 );
+ VERIFY_IS_EQUAL(lm.njev, 545 );
+ // check norm^2
+ VERIFY_IS_APPROX(lm.fvec.squaredNorm(), 5.4648946975E-05);
+ // check x
+ VERIFY_IS_APPROX(x[0], 3.7541005211E-01);
+ VERIFY_IS_APPROX(x[1], 1.9358469127E+00);
+ VERIFY_IS_APPROX(x[2], -1.4646871366E+00);
+ VERIFY_IS_APPROX(x[3], 1.2867534640E-02);
+ VERIFY_IS_APPROX(x[4], 2.2122699662E-02);
+
+ /*
+ * Second try
+ */
+ x<< 0.5 ,1.5 ,-1 ,0.01 ,0.02;
+ // do the computation
+ lm.resetParameters();
+ info = lm.minimize(x);
+
+ // check return value
+ VERIFY_IS_EQUAL(info, 1);
+ VERIFY_IS_EQUAL(lm.nfev, 18);
+ VERIFY_IS_EQUAL(lm.njev, 15);
+ // check norm^2
+ VERIFY_IS_APPROX(lm.fvec.squaredNorm(), 5.4648946975E-05);
+ // check x
+ VERIFY_IS_APPROX(x[0], 3.7541005211E-01);
+ VERIFY_IS_APPROX(x[1], 1.9358469127E+00);
+ VERIFY_IS_APPROX(x[2], -1.4646871366E+00);
+ VERIFY_IS_APPROX(x[3], 1.2867534640E-02);
+ VERIFY_IS_APPROX(x[4], 2.2122699662E-02);
+}
+
+struct MGH09_functor : Functor<double>
+{
+ MGH09_functor(void) : Functor<double>(4,11) {}
+ static const double _x[11];
+ static const double y[11];
+ int operator()(const VectorXd &b, VectorXd &fvec)
+ {
+ assert(b.size()==4);
+ assert(fvec.size()==11);
+ for(int i=0; i<11; i++) {
+ double x = _x[i], xx=x*x;
+ fvec[i] = b[0]*(xx+x*b[1])/(xx+x*b[2]+b[3]) - y[i];
+ }
+ return 0;
+ }
+ int df(const VectorXd &b, MatrixXd &fjac)
+ {
+ assert(b.size()==4);
+ assert(fjac.rows()==11);
+ assert(fjac.cols()==4);
+ for(int i=0; i<11; i++) {
+ double x = _x[i], xx=x*x;
+ double factor = 1./(xx+x*b[2]+b[3]);
+ fjac(i,0) = (xx+x*b[1]) * factor;
+ fjac(i,1) = b[0]*x* factor;
+ fjac(i,2) = - b[0]*(xx+x*b[1]) * x * factor * factor;
+ fjac(i,3) = - b[0]*(xx+x*b[1]) * factor * factor;
+ }
+ return 0;
+ }
+};
+const double MGH09_functor::_x[11] = { 4., 2., 1., 5.E-1 , 2.5E-01, 1.670000E-01, 1.250000E-01, 1.E-01, 8.330000E-02, 7.140000E-02, 6.250000E-02 };
+const double MGH09_functor::y[11] = { 1.957000E-01, 1.947000E-01, 1.735000E-01, 1.600000E-01, 8.440000E-02, 6.270000E-02, 4.560000E-02, 3.420000E-02, 3.230000E-02, 2.350000E-02, 2.460000E-02 };
+
+// http://www.itl.nist.gov/div898/strd/nls/data/mgh09.shtml
+void testNistMGH09(void)
+{
+ const int n=4;
+ int info;
+
+ VectorXd x(n);
+
+ /*
+ * First try
+ */
+ x<< 25., 39, 41.5, 39.;
+ // do the computation
+ MGH09_functor functor;
+ LevenbergMarquardt<MGH09_functor> lm(functor);
+ lm.parameters.maxfev = 1000;
+ info = lm.minimize(x);
+
+ // check return value
+ VERIFY_IS_EQUAL(info, 1);
+ VERIFY_IS_EQUAL(lm.nfev, 490 );
+ VERIFY_IS_EQUAL(lm.njev, 376 );
+ // check norm^2
+ VERIFY_IS_APPROX(lm.fvec.squaredNorm(), 3.0750560385E-04);
+ // check x
+ VERIFY_IS_APPROX(x[0], 0.1928077089); // should be 1.9280693458E-01
+ VERIFY_IS_APPROX(x[1], 0.19126423573); // should be 1.9128232873E-01
+ VERIFY_IS_APPROX(x[2], 0.12305309914); // should be 1.2305650693E-01
+ VERIFY_IS_APPROX(x[3], 0.13605395375); // should be 1.3606233068E-01
+
+ /*
+ * Second try
+ */
+ x<< 0.25, 0.39, 0.415, 0.39;
+ // do the computation
+ lm.resetParameters();
+ info = lm.minimize(x);
+
+ // check return value
+ VERIFY_IS_EQUAL(info, 1);
+ VERIFY_IS_EQUAL(lm.nfev, 18);
+ VERIFY_IS_EQUAL(lm.njev, 16);
+ // check norm^2
+ VERIFY_IS_APPROX(lm.fvec.squaredNorm(), 3.0750560385E-04);
+ // check x
+ VERIFY_IS_APPROX(x[0], 0.19280781); // should be 1.9280693458E-01
+ VERIFY_IS_APPROX(x[1], 0.19126265); // should be 1.9128232873E-01
+ VERIFY_IS_APPROX(x[2], 0.12305280); // should be 1.2305650693E-01
+ VERIFY_IS_APPROX(x[3], 0.13605322); // should be 1.3606233068E-01
+}
+
+
+
+struct Bennett5_functor : Functor<double>
+{
+ Bennett5_functor(void) : Functor<double>(3,154) {}
+ static const double x[154];
+ static const double y[154];
+ int operator()(const VectorXd &b, VectorXd &fvec)
+ {
+ assert(b.size()==3);
+ assert(fvec.size()==154);
+ for(int i=0; i<154; i++)
+ fvec[i] = b[0]* pow(b[1]+x[i],-1./b[2]) - y[i];
+ return 0;
+ }
+ int df(const VectorXd &b, MatrixXd &fjac)
+ {
+ assert(b.size()==3);
+ assert(fjac.rows()==154);
+ assert(fjac.cols()==3);
+ for(int i=0; i<154; i++) {
+ double e = pow(b[1]+x[i],-1./b[2]);
+ fjac(i,0) = e;
+ fjac(i,1) = - b[0]*e/b[2]/(b[1]+x[i]);
+ fjac(i,2) = b[0]*e*log(b[1]+x[i])/b[2]/b[2];
+ }
+ return 0;
+ }
+};
+const double Bennett5_functor::x[154] = { 7.447168E0, 8.102586E0, 8.452547E0, 8.711278E0, 8.916774E0, 9.087155E0, 9.232590E0, 9.359535E0, 9.472166E0, 9.573384E0, 9.665293E0, 9.749461E0, 9.827092E0, 9.899128E0, 9.966321E0, 10.029280E0, 10.088510E0, 10.144430E0, 10.197380E0, 10.247670E0, 10.295560E0, 10.341250E0, 10.384950E0, 10.426820E0, 10.467000E0, 10.505640E0, 10.542830E0, 10.578690E0, 10.613310E0, 10.646780E0, 10.679150E0, 10.710520E0, 10.740920E0, 10.770440E0, 10.799100E0, 10.826970E0, 10.854080E0, 10.880470E0, 10.906190E0, 10.931260E0, 10.955720E0, 10.979590E0, 11.002910E0, 11.025700E0, 11.047980E0, 11.069770E0, 11.091100E0, 11.111980E0, 11.132440E0, 11.152480E0, 11.172130E0, 11.191410E0, 11.210310E0, 11.228870E0, 11.247090E0, 11.264980E0, 11.282560E0, 11.299840E0, 11.316820E0, 11.333520E0, 11.349940E0, 11.366100E0, 11.382000E0, 11.397660E0, 11.413070E0, 11.428240E0, 11.443200E0, 11.457930E0, 11.472440E0, 11.486750E0, 11.500860E0, 11.514770E0, 11.528490E0, 11.542020E0, 11.555380E0, 11.568550E0, 11.581560E0, 11.594420E0, 11.607121E0, 11.619640E0, 11.632000E0, 11.644210E0, 11.656280E0, 11.668200E0, 11.679980E0, 11.691620E0, 11.703130E0, 11.714510E0, 11.725760E0, 11.736880E0, 11.747890E0, 11.758780E0, 11.769550E0, 11.780200E0, 11.790730E0, 11.801160E0, 11.811480E0, 11.821700E0, 11.831810E0, 11.841820E0, 11.851730E0, 11.861550E0, 11.871270E0, 11.880890E0, 11.890420E0, 11.899870E0, 11.909220E0, 11.918490E0, 11.927680E0, 11.936780E0, 11.945790E0, 11.954730E0, 11.963590E0, 11.972370E0, 11.981070E0, 11.989700E0, 11.998260E0, 12.006740E0, 12.015150E0, 12.023490E0, 12.031760E0, 12.039970E0, 12.048100E0, 12.056170E0, 12.064180E0, 12.072120E0, 12.080010E0, 12.087820E0, 12.095580E0, 12.103280E0, 12.110920E0, 12.118500E0, 12.126030E0, 12.133500E0, 12.140910E0, 12.148270E0, 12.155570E0, 12.162830E0, 12.170030E0, 12.177170E0, 12.184270E0, 12.191320E0, 12.198320E0, 12.205270E0, 12.212170E0, 12.219030E0, 12.225840E0, 12.232600E0, 12.239320E0, 12.245990E0, 12.252620E0, 12.259200E0, 12.265750E0, 12.272240E0 };
+const double Bennett5_functor::y[154] = { -34.834702E0 ,-34.393200E0 ,-34.152901E0 ,-33.979099E0 ,-33.845901E0 ,-33.732899E0 ,-33.640301E0 ,-33.559200E0 ,-33.486801E0 ,-33.423100E0 ,-33.365101E0 ,-33.313000E0 ,-33.260899E0 ,-33.217400E0 ,-33.176899E0 ,-33.139198E0 ,-33.101601E0 ,-33.066799E0 ,-33.035000E0 ,-33.003101E0 ,-32.971298E0 ,-32.942299E0 ,-32.916302E0 ,-32.890202E0 ,-32.864101E0 ,-32.841000E0 ,-32.817799E0 ,-32.797501E0 ,-32.774300E0 ,-32.757000E0 ,-32.733799E0 ,-32.716400E0 ,-32.699100E0 ,-32.678799E0 ,-32.661400E0 ,-32.644001E0 ,-32.626701E0 ,-32.612202E0 ,-32.597698E0 ,-32.583199E0 ,-32.568699E0 ,-32.554298E0 ,-32.539799E0 ,-32.525299E0 ,-32.510799E0 ,-32.499199E0 ,-32.487598E0 ,-32.473202E0 ,-32.461601E0 ,-32.435501E0 ,-32.435501E0 ,-32.426800E0 ,-32.412300E0 ,-32.400799E0 ,-32.392101E0 ,-32.380501E0 ,-32.366001E0 ,-32.357300E0 ,-32.348598E0 ,-32.339901E0 ,-32.328400E0 ,-32.319698E0 ,-32.311001E0 ,-32.299400E0 ,-32.290699E0 ,-32.282001E0 ,-32.273300E0 ,-32.264599E0 ,-32.256001E0 ,-32.247299E0 ,-32.238602E0 ,-32.229900E0 ,-32.224098E0 ,-32.215401E0 ,-32.203800E0 ,-32.198002E0 ,-32.189400E0 ,-32.183601E0 ,-32.174900E0 ,-32.169102E0 ,-32.163300E0 ,-32.154598E0 ,-32.145901E0 ,-32.140099E0 ,-32.131401E0 ,-32.125599E0 ,-32.119801E0 ,-32.111198E0 ,-32.105400E0 ,-32.096699E0 ,-32.090900E0 ,-32.088001E0 ,-32.079300E0 ,-32.073502E0 ,-32.067699E0 ,-32.061901E0 ,-32.056099E0 ,-32.050301E0 ,-32.044498E0 ,-32.038799E0 ,-32.033001E0 ,-32.027199E0 ,-32.024300E0 ,-32.018501E0 ,-32.012699E0 ,-32.004002E0 ,-32.001099E0 ,-31.995300E0 ,-31.989500E0 ,-31.983700E0 ,-31.977900E0 ,-31.972099E0 ,-31.969299E0 ,-31.963501E0 ,-31.957701E0 ,-31.951900E0 ,-31.946100E0 ,-31.940300E0 ,-31.937401E0 ,-31.931601E0 ,-31.925800E0 ,-31.922899E0 ,-31.917101E0 ,-31.911301E0 ,-31.908400E0 ,-31.902599E0 ,-31.896900E0 ,-31.893999E0 ,-31.888201E0 ,-31.885300E0 ,-31.882401E0 ,-31.876600E0 ,-31.873699E0 ,-31.867901E0 ,-31.862101E0 ,-31.859200E0 ,-31.856300E0 ,-31.850500E0 ,-31.844700E0 ,-31.841801E0 ,-31.838900E0 ,-31.833099E0 ,-31.830200E0 ,-31.827299E0 ,-31.821600E0 ,-31.818701E0 ,-31.812901E0 ,-31.809999E0 ,-31.807100E0 ,-31.801300E0 ,-31.798401E0 ,-31.795500E0 ,-31.789700E0 ,-31.786800E0 };
+
+// http://www.itl.nist.gov/div898/strd/nls/data/bennett5.shtml
+void testNistBennett5(void)
+{
+ const int n=3;
+ int info;
+
+ VectorXd x(n);
+
+ /*
+ * First try
+ */
+ x<< -2000., 50., 0.8;
+ // do the computation
+ Bennett5_functor functor;
+ LevenbergMarquardt<Bennett5_functor> lm(functor);
+ lm.parameters.maxfev = 1000;
+ info = lm.minimize(x);
+
+ // check return value
+ VERIFY_IS_EQUAL(info, 1);
+ VERIFY_IS_EQUAL(lm.nfev, 758);
+ VERIFY_IS_EQUAL(lm.njev, 744);
+ // check norm^2
+ VERIFY_IS_APPROX(lm.fvec.squaredNorm(), 5.2404744073E-04);
+ // check x
+ VERIFY_IS_APPROX(x[0], -2.5235058043E+03);
+ VERIFY_IS_APPROX(x[1], 4.6736564644E+01);
+ VERIFY_IS_APPROX(x[2], 9.3218483193E-01);
+ /*
+ * Second try
+ */
+ x<< -1500., 45., 0.85;
+ // do the computation
+ lm.resetParameters();
+ info = lm.minimize(x);
+
+ // check return value
+ VERIFY_IS_EQUAL(info, 1);
+ VERIFY_IS_EQUAL(lm.nfev, 203);
+ VERIFY_IS_EQUAL(lm.njev, 192);
+ // check norm^2
+ VERIFY_IS_APPROX(lm.fvec.squaredNorm(), 5.2404744073E-04);
+ // check x
+ VERIFY_IS_APPROX(x[0], -2523.3007865); // should be -2.5235058043E+03
+ VERIFY_IS_APPROX(x[1], 46.735705771); // should be 4.6736564644E+01);
+ VERIFY_IS_APPROX(x[2], 0.93219881891); // should be 9.3218483193E-01);
+}
+
+struct thurber_functor : Functor<double>
+{
+ thurber_functor(void) : Functor<double>(7,37) {}
+ static const double _x[37];
+ static const double _y[37];
+ int operator()(const VectorXd &b, VectorXd &fvec)
+ {
+ // int called=0; printf("call hahn1_functor with iflag=%d, called=%d\n", iflag, called); if (iflag==1) called++;
+ assert(b.size()==7);
+ assert(fvec.size()==37);
+ for(int i=0; i<37; i++) {
+ double x=_x[i], xx=x*x, xxx=xx*x;
+ fvec[i] = (b[0]+b[1]*x+b[2]*xx+b[3]*xxx) / (1.+b[4]*x+b[5]*xx+b[6]*xxx) - _y[i];
+ }
+ return 0;
+ }
+ int df(const VectorXd &b, MatrixXd &fjac)
+ {
+ assert(b.size()==7);
+ assert(fjac.rows()==37);
+ assert(fjac.cols()==7);
+ for(int i=0; i<37; i++) {
+ double x=_x[i], xx=x*x, xxx=xx*x;
+ double fact = 1./(1.+b[4]*x+b[5]*xx+b[6]*xxx);
+ fjac(i,0) = 1.*fact;
+ fjac(i,1) = x*fact;
+ fjac(i,2) = xx*fact;
+ fjac(i,3) = xxx*fact;
+ fact = - (b[0]+b[1]*x+b[2]*xx+b[3]*xxx) * fact * fact;
+ fjac(i,4) = x*fact;
+ fjac(i,5) = xx*fact;
+ fjac(i,6) = xxx*fact;
+ }
+ return 0;
+ }
+};
+const double thurber_functor::_x[37] = { -3.067E0, -2.981E0, -2.921E0, -2.912E0, -2.840E0, -2.797E0, -2.702E0, -2.699E0, -2.633E0, -2.481E0, -2.363E0, -2.322E0, -1.501E0, -1.460E0, -1.274E0, -1.212E0, -1.100E0, -1.046E0, -0.915E0, -0.714E0, -0.566E0, -0.545E0, -0.400E0, -0.309E0, -0.109E0, -0.103E0, 0.010E0, 0.119E0, 0.377E0, 0.790E0, 0.963E0, 1.006E0, 1.115E0, 1.572E0, 1.841E0, 2.047E0, 2.200E0 };
+const double thurber_functor::_y[37] = { 80.574E0, 84.248E0, 87.264E0, 87.195E0, 89.076E0, 89.608E0, 89.868E0, 90.101E0, 92.405E0, 95.854E0, 100.696E0, 101.060E0, 401.672E0, 390.724E0, 567.534E0, 635.316E0, 733.054E0, 759.087E0, 894.206E0, 990.785E0, 1090.109E0, 1080.914E0, 1122.643E0, 1178.351E0, 1260.531E0, 1273.514E0, 1288.339E0, 1327.543E0, 1353.863E0, 1414.509E0, 1425.208E0, 1421.384E0, 1442.962E0, 1464.350E0, 1468.705E0, 1447.894E0, 1457.628E0};
+
+// http://www.itl.nist.gov/div898/strd/nls/data/thurber.shtml
+void testNistThurber(void)
+{
+ const int n=7;
+ int info;
+
+ VectorXd x(n);
+
+ /*
+ * First try
+ */
+ x<< 1000 ,1000 ,400 ,40 ,0.7,0.3,0.0 ;
+ // do the computation
+ thurber_functor functor;
+ LevenbergMarquardt<thurber_functor> lm(functor);
+ lm.parameters.ftol = 1.E4*NumTraits<double>::epsilon();
+ lm.parameters.xtol = 1.E4*NumTraits<double>::epsilon();
+ info = lm.minimize(x);
+
+ // check return value
+ VERIFY_IS_EQUAL(info, 1);
+ VERIFY_IS_EQUAL(lm.nfev, 39);
+ VERIFY_IS_EQUAL(lm.njev, 36);
+ // check norm^2
+ VERIFY_IS_APPROX(lm.fvec.squaredNorm(), 5.6427082397E+03);
+ // check x
+ VERIFY_IS_APPROX(x[0], 1.2881396800E+03);
+ VERIFY_IS_APPROX(x[1], 1.4910792535E+03);
+ VERIFY_IS_APPROX(x[2], 5.8323836877E+02);
+ VERIFY_IS_APPROX(x[3], 7.5416644291E+01);
+ VERIFY_IS_APPROX(x[4], 9.6629502864E-01);
+ VERIFY_IS_APPROX(x[5], 3.9797285797E-01);
+ VERIFY_IS_APPROX(x[6], 4.9727297349E-02);
+
+ /*
+ * Second try
+ */
+ x<< 1300 ,1500 ,500 ,75 ,1 ,0.4 ,0.05 ;
+ // do the computation
+ lm.resetParameters();
+ lm.parameters.ftol = 1.E4*NumTraits<double>::epsilon();
+ lm.parameters.xtol = 1.E4*NumTraits<double>::epsilon();
+ info = lm.minimize(x);
+
+ // check return value
+ VERIFY_IS_EQUAL(info, 1);
+ VERIFY_IS_EQUAL(lm.nfev, 29);
+ VERIFY_IS_EQUAL(lm.njev, 28);
+ // check norm^2
+ VERIFY_IS_APPROX(lm.fvec.squaredNorm(), 5.6427082397E+03);
+ // check x
+ VERIFY_IS_APPROX(x[0], 1.2881396800E+03);
+ VERIFY_IS_APPROX(x[1], 1.4910792535E+03);
+ VERIFY_IS_APPROX(x[2], 5.8323836877E+02);
+ VERIFY_IS_APPROX(x[3], 7.5416644291E+01);
+ VERIFY_IS_APPROX(x[4], 9.6629502864E-01);
+ VERIFY_IS_APPROX(x[5], 3.9797285797E-01);
+ VERIFY_IS_APPROX(x[6], 4.9727297349E-02);
+}
+
+struct rat43_functor : Functor<double>
+{
+ rat43_functor(void) : Functor<double>(4,15) {}
+ static const double x[15];
+ static const double y[15];
+ int operator()(const VectorXd &b, VectorXd &fvec)
+ {
+ assert(b.size()==4);
+ assert(fvec.size()==15);
+ for(int i=0; i<15; i++)
+ fvec[i] = b[0] * pow(1.+exp(b[1]-b[2]*x[i]),-1./b[3]) - y[i];
+ return 0;
+ }
+ int df(const VectorXd &b, MatrixXd &fjac)
+ {
+ assert(b.size()==4);
+ assert(fjac.rows()==15);
+ assert(fjac.cols()==4);
+ for(int i=0; i<15; i++) {
+ double e = exp(b[1]-b[2]*x[i]);
+ double power = -1./b[3];
+ fjac(i,0) = pow(1.+e, power);
+ fjac(i,1) = power*b[0]*e*pow(1.+e, power-1.);
+ fjac(i,2) = -power*b[0]*e*x[i]*pow(1.+e, power-1.);
+ fjac(i,3) = b[0]*power*power*log(1.+e)*pow(1.+e, power);
+ }
+ return 0;
+ }
+};
+const double rat43_functor::x[15] = { 1., 2., 3., 4., 5., 6., 7., 8., 9., 10., 11., 12., 13., 14., 15. };
+const double rat43_functor::y[15] = { 16.08, 33.83, 65.80, 97.20, 191.55, 326.20, 386.87, 520.53, 590.03, 651.92, 724.93, 699.56, 689.96, 637.56, 717.41 };
+
+// http://www.itl.nist.gov/div898/strd/nls/data/ratkowsky3.shtml
+void testNistRat43(void)
+{
+ const int n=4;
+ int info;
+
+ VectorXd x(n);
+
+ /*
+ * First try
+ */
+ x<< 100., 10., 1., 1.;
+ // do the computation
+ rat43_functor functor;
+ LevenbergMarquardt<rat43_functor> lm(functor);
+ lm.parameters.ftol = 1.E6*NumTraits<double>::epsilon();
+ lm.parameters.xtol = 1.E6*NumTraits<double>::epsilon();
+ info = lm.minimize(x);
+
+ // check return value
+ VERIFY_IS_EQUAL(info, 1);
+ VERIFY_IS_EQUAL(lm.nfev, 27);
+ VERIFY_IS_EQUAL(lm.njev, 20);
+ // check norm^2
+ VERIFY_IS_APPROX(lm.fvec.squaredNorm(), 8.7864049080E+03);
+ // check x
+ VERIFY_IS_APPROX(x[0], 6.9964151270E+02);
+ VERIFY_IS_APPROX(x[1], 5.2771253025E+00);
+ VERIFY_IS_APPROX(x[2], 7.5962938329E-01);
+ VERIFY_IS_APPROX(x[3], 1.2792483859E+00);
+
+ /*
+ * Second try
+ */
+ x<< 700., 5., 0.75, 1.3;
+ // do the computation
+ lm.resetParameters();
+ lm.parameters.ftol = 1.E5*NumTraits<double>::epsilon();
+ lm.parameters.xtol = 1.E5*NumTraits<double>::epsilon();
+ info = lm.minimize(x);
+
+ // check return value
+ VERIFY_IS_EQUAL(info, 1);
+ VERIFY_IS_EQUAL(lm.nfev, 9);
+ VERIFY_IS_EQUAL(lm.njev, 8);
+ // check norm^2
+ VERIFY_IS_APPROX(lm.fvec.squaredNorm(), 8.7864049080E+03);
+ // check x
+ VERIFY_IS_APPROX(x[0], 6.9964151270E+02);
+ VERIFY_IS_APPROX(x[1], 5.2771253025E+00);
+ VERIFY_IS_APPROX(x[2], 7.5962938329E-01);
+ VERIFY_IS_APPROX(x[3], 1.2792483859E+00);
+}
+
+
+
+struct eckerle4_functor : Functor<double>
+{
+ eckerle4_functor(void) : Functor<double>(3,35) {}
+ static const double x[35];
+ static const double y[35];
+ int operator()(const VectorXd &b, VectorXd &fvec)
+ {
+ assert(b.size()==3);
+ assert(fvec.size()==35);
+ for(int i=0; i<35; i++)
+ fvec[i] = b[0]/b[1] * exp(-0.5*(x[i]-b[2])*(x[i]-b[2])/(b[1]*b[1])) - y[i];
+ return 0;
+ }
+ int df(const VectorXd &b, MatrixXd &fjac)
+ {
+ assert(b.size()==3);
+ assert(fjac.rows()==35);
+ assert(fjac.cols()==3);
+ for(int i=0; i<35; i++) {
+ double b12 = b[1]*b[1];
+ double e = exp(-0.5*(x[i]-b[2])*(x[i]-b[2])/b12);
+ fjac(i,0) = e / b[1];
+ fjac(i,1) = ((x[i]-b[2])*(x[i]-b[2])/b12-1.) * b[0]*e/b12;
+ fjac(i,2) = (x[i]-b[2])*e*b[0]/b[1]/b12;
+ }
+ return 0;
+ }
+};
+const double eckerle4_functor::x[35] = { 400.0, 405.0, 410.0, 415.0, 420.0, 425.0, 430.0, 435.0, 436.5, 438.0, 439.5, 441.0, 442.5, 444.0, 445.5, 447.0, 448.5, 450.0, 451.5, 453.0, 454.5, 456.0, 457.5, 459.0, 460.5, 462.0, 463.5, 465.0, 470.0, 475.0, 480.0, 485.0, 490.0, 495.0, 500.0};
+const double eckerle4_functor::y[35] = { 0.0001575, 0.0001699, 0.0002350, 0.0003102, 0.0004917, 0.0008710, 0.0017418, 0.0046400, 0.0065895, 0.0097302, 0.0149002, 0.0237310, 0.0401683, 0.0712559, 0.1264458, 0.2073413, 0.2902366, 0.3445623, 0.3698049, 0.3668534, 0.3106727, 0.2078154, 0.1164354, 0.0616764, 0.0337200, 0.0194023, 0.0117831, 0.0074357, 0.0022732, 0.0008800, 0.0004579, 0.0002345, 0.0001586, 0.0001143, 0.0000710 };
+
+// http://www.itl.nist.gov/div898/strd/nls/data/eckerle4.shtml
+void testNistEckerle4(void)
+{
+ const int n=3;
+ int info;
+
+ VectorXd x(n);
+
+ /*
+ * First try
+ */
+ x<< 1., 10., 500.;
+ // do the computation
+ eckerle4_functor functor;
+ LevenbergMarquardt<eckerle4_functor> lm(functor);
+ info = lm.minimize(x);
+
+ // check return value
+ VERIFY_IS_EQUAL(info, 1);
+ VERIFY_IS_EQUAL(lm.nfev, 18);
+ VERIFY_IS_EQUAL(lm.njev, 15);
+ // check norm^2
+ VERIFY_IS_APPROX(lm.fvec.squaredNorm(), 1.4635887487E-03);
+ // check x
+ VERIFY_IS_APPROX(x[0], 1.5543827178);
+ VERIFY_IS_APPROX(x[1], 4.0888321754);
+ VERIFY_IS_APPROX(x[2], 4.5154121844E+02);
+
+ /*
+ * Second try
+ */
+ x<< 1.5, 5., 450.;
+ // do the computation
+ info = lm.minimize(x);
+
+ // check return value
+ VERIFY_IS_EQUAL(info, 1);
+ VERIFY_IS_EQUAL(lm.nfev, 7);
+ VERIFY_IS_EQUAL(lm.njev, 6);
+ // check norm^2
+ VERIFY_IS_APPROX(lm.fvec.squaredNorm(), 1.4635887487E-03);
+ // check x
+ VERIFY_IS_APPROX(x[0], 1.5543827178);
+ VERIFY_IS_APPROX(x[1], 4.0888321754);
+ VERIFY_IS_APPROX(x[2], 4.5154121844E+02);
+}
+
+void test_NonLinearOptimization()
+{
+ // Tests using the examples provided by (c)minpack
+ CALL_SUBTEST/*_1*/(testChkder());
+ CALL_SUBTEST/*_1*/(testLmder1());
+ CALL_SUBTEST/*_1*/(testLmder());
+ CALL_SUBTEST/*_2*/(testHybrj1());
+ CALL_SUBTEST/*_2*/(testHybrj());
+ CALL_SUBTEST/*_2*/(testHybrd1());
+ CALL_SUBTEST/*_2*/(testHybrd());
+ CALL_SUBTEST/*_3*/(testLmstr1());
+ CALL_SUBTEST/*_3*/(testLmstr());
+ CALL_SUBTEST/*_3*/(testLmdif1());
+ CALL_SUBTEST/*_3*/(testLmdif());
+
+ // NIST tests, level of difficulty = "Lower"
+ CALL_SUBTEST/*_4*/(testNistMisra1a());
+ CALL_SUBTEST/*_4*/(testNistChwirut2());
+
+ // NIST tests, level of difficulty = "Average"
+ CALL_SUBTEST/*_5*/(testNistHahn1());
+ CALL_SUBTEST/*_6*/(testNistMisra1d());
+ CALL_SUBTEST/*_7*/(testNistMGH17());
+ CALL_SUBTEST/*_8*/(testNistLanczos1());
+
+ // NIST tests, level of difficulty = "Higher"
+ CALL_SUBTEST/*_9*/(testNistRat42());
+ CALL_SUBTEST/*_10*/(testNistMGH10());
+ CALL_SUBTEST/*_11*/(testNistBoxBOD());
+ CALL_SUBTEST/*_12*/(testNistMGH09());
+ CALL_SUBTEST/*_13*/(testNistBennett5());
+ CALL_SUBTEST/*_14*/(testNistThurber());
+ CALL_SUBTEST/*_15*/(testNistRat43());
+ CALL_SUBTEST/*_16*/(testNistEckerle4());
+}
+
+/*
+ * Can be useful for debugging...
+ printf("info, nfev : %d, %d\n", info, lm.nfev);
+ printf("info, nfev, njev : %d, %d, %d\n", info, solver.nfev, solver.njev);
+ printf("info, nfev : %d, %d\n", info, solver.nfev);
+ printf("x[0] : %.32g\n", x[0]);
+ printf("x[1] : %.32g\n", x[1]);
+ printf("x[2] : %.32g\n", x[2]);
+ printf("x[3] : %.32g\n", x[3]);
+ printf("fvec.blueNorm() : %.32g\n", solver.fvec.blueNorm());
+ printf("fvec.blueNorm() : %.32g\n", lm.fvec.blueNorm());
+
+ printf("info, nfev, njev : %d, %d, %d\n", info, lm.nfev, lm.njev);
+ printf("fvec.squaredNorm() : %.13g\n", lm.fvec.squaredNorm());
+ std::cout << x << std::endl;
+ std::cout.precision(9);
+ std::cout << x[0] << std::endl;
+ std::cout << x[1] << std::endl;
+ std::cout << x[2] << std::endl;
+ std::cout << x[3] << std::endl;
+*/
+
diff --git a/unsupported/test/NumericalDiff.cpp b/unsupported/test/NumericalDiff.cpp
new file mode 100644
index 000000000..27d888056
--- /dev/null
+++ b/unsupported/test/NumericalDiff.cpp
@@ -0,0 +1,114 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra.
+//
+// Copyright (C) 2009 Thomas Capricelli <orzel@freehackers.org>
+
+#include <stdio.h>
+
+#include "main.h"
+#include <unsupported/Eigen/NumericalDiff>
+
+// Generic functor
+template<typename _Scalar, int NX=Dynamic, int NY=Dynamic>
+struct Functor
+{
+ typedef _Scalar Scalar;
+ enum {
+ InputsAtCompileTime = NX,
+ ValuesAtCompileTime = NY
+ };
+ typedef Matrix<Scalar,InputsAtCompileTime,1> InputType;
+ typedef Matrix<Scalar,ValuesAtCompileTime,1> ValueType;
+ typedef Matrix<Scalar,ValuesAtCompileTime,InputsAtCompileTime> JacobianType;
+
+ int m_inputs, m_values;
+
+ Functor() : m_inputs(InputsAtCompileTime), m_values(ValuesAtCompileTime) {}
+ Functor(int inputs, int values) : m_inputs(inputs), m_values(values) {}
+
+ int inputs() const { return m_inputs; }
+ int values() const { return m_values; }
+
+};
+
+struct my_functor : Functor<double>
+{
+ my_functor(void): Functor<double>(3,15) {}
+ int operator()(const VectorXd &x, VectorXd &fvec) const
+ {
+ double tmp1, tmp2, tmp3;
+ double y[15] = {1.4e-1, 1.8e-1, 2.2e-1, 2.5e-1, 2.9e-1, 3.2e-1, 3.5e-1,
+ 3.9e-1, 3.7e-1, 5.8e-1, 7.3e-1, 9.6e-1, 1.34, 2.1, 4.39};
+
+ for (int i = 0; i < values(); i++)
+ {
+ tmp1 = i+1;
+ tmp2 = 16 - i - 1;
+ tmp3 = (i>=8)? tmp2 : tmp1;
+ fvec[i] = y[i] - (x[0] + tmp1/(x[1]*tmp2 + x[2]*tmp3));
+ }
+ return 0;
+ }
+
+ int actual_df(const VectorXd &x, MatrixXd &fjac) const
+ {
+ double tmp1, tmp2, tmp3, tmp4;
+ for (int i = 0; i < values(); i++)
+ {
+ tmp1 = i+1;
+ tmp2 = 16 - i - 1;
+ tmp3 = (i>=8)? tmp2 : tmp1;
+ tmp4 = (x[1]*tmp2 + x[2]*tmp3); tmp4 = tmp4*tmp4;
+ fjac(i,0) = -1;
+ fjac(i,1) = tmp1*tmp2/tmp4;
+ fjac(i,2) = tmp1*tmp3/tmp4;
+ }
+ return 0;
+ }
+};
+
+void test_forward()
+{
+ VectorXd x(3);
+ MatrixXd jac(15,3);
+ MatrixXd actual_jac(15,3);
+ my_functor functor;
+
+ x << 0.082, 1.13, 2.35;
+
+ // real one
+ functor.actual_df(x, actual_jac);
+// std::cout << actual_jac << std::endl << std::endl;
+
+ // using NumericalDiff
+ NumericalDiff<my_functor> numDiff(functor);
+ numDiff.df(x, jac);
+// std::cout << jac << std::endl;
+
+ VERIFY_IS_APPROX(jac, actual_jac);
+}
+
+void test_central()
+{
+ VectorXd x(3);
+ MatrixXd jac(15,3);
+ MatrixXd actual_jac(15,3);
+ my_functor functor;
+
+ x << 0.082, 1.13, 2.35;
+
+ // real one
+ functor.actual_df(x, actual_jac);
+
+ // using NumericalDiff
+ NumericalDiff<my_functor,Central> numDiff(functor);
+ numDiff.df(x, jac);
+
+ VERIFY_IS_APPROX(jac, actual_jac);
+}
+
+void test_NumericalDiff()
+{
+ CALL_SUBTEST(test_forward());
+ CALL_SUBTEST(test_central());
+}
diff --git a/unsupported/test/alignedvector3.cpp b/unsupported/test/alignedvector3.cpp
new file mode 100644
index 000000000..fc2bc2135
--- /dev/null
+++ b/unsupported/test/alignedvector3.cpp
@@ -0,0 +1,59 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra.
+//
+// Copyright (C) 2009 Gael Guennebaud <g.gael@free.fr>
+//
+// This Source Code Form is subject to the terms of the Mozilla
+// Public License v. 2.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 "main.h"
+#include <unsupported/Eigen/AlignedVector3>
+
+template<typename Scalar>
+void alignedvector3()
+{
+ Scalar s1 = internal::random<Scalar>();
+ Scalar s2 = internal::random<Scalar>();
+ typedef Matrix<Scalar,3,1> RefType;
+ typedef Matrix<Scalar,3,3> Mat33;
+ typedef AlignedVector3<Scalar> FastType;
+ RefType r1(RefType::Random()), r2(RefType::Random()), r3(RefType::Random()),
+ r4(RefType::Random()), r5(RefType::Random()), r6(RefType::Random());
+ FastType f1(r1), f2(r2), f3(r3), f4(r4), f5(r5), f6(r6);
+ Mat33 m1(Mat33::Random());
+
+ VERIFY_IS_APPROX(f1,r1);
+ VERIFY_IS_APPROX(f4,r4);
+
+ VERIFY_IS_APPROX(f4+f1,r4+r1);
+ VERIFY_IS_APPROX(f4-f1,r4-r1);
+ VERIFY_IS_APPROX(f4+f1-f2,r4+r1-r2);
+ VERIFY_IS_APPROX(f4+=f3,r4+=r3);
+ VERIFY_IS_APPROX(f4-=f5,r4-=r5);
+ VERIFY_IS_APPROX(f4-=f5+f1,r4-=r5+r1);
+ VERIFY_IS_APPROX(f5+f1-s1*f2,r5+r1-s1*r2);
+ VERIFY_IS_APPROX(f5+f1/s2-s1*f2,r5+r1/s2-s1*r2);
+
+ VERIFY_IS_APPROX(m1*f4,m1*r4);
+ VERIFY_IS_APPROX(f4.transpose()*m1,r4.transpose()*m1);
+
+ VERIFY_IS_APPROX(f2.dot(f3),r2.dot(r3));
+ VERIFY_IS_APPROX(f2.cross(f3),r2.cross(r3));
+ VERIFY_IS_APPROX(f2.norm(),r2.norm());
+
+ VERIFY_IS_APPROX(f2.normalized(),r2.normalized());
+
+ VERIFY_IS_APPROX((f2+f1).normalized(),(r2+r1).normalized());
+
+ f2.normalize();
+ r2.normalize();
+ VERIFY_IS_APPROX(f2,r2);
+}
+
+void test_alignedvector3()
+{
+ for(int i = 0; i < g_repeat; i++) {
+ CALL_SUBTEST( alignedvector3<float>() );
+ }
+}
diff --git a/unsupported/test/autodiff.cpp b/unsupported/test/autodiff.cpp
new file mode 100644
index 000000000..6eb417e8d
--- /dev/null
+++ b/unsupported/test/autodiff.cpp
@@ -0,0 +1,172 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra.
+//
+// Copyright (C) 2009 Gael Guennebaud <g.gael@free.fr>
+//
+// This Source Code Form is subject to the terms of the Mozilla
+// Public License v. 2.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 "main.h"
+#include <unsupported/Eigen/AutoDiff>
+
+template<typename Scalar>
+EIGEN_DONT_INLINE Scalar foo(const Scalar& x, const Scalar& y)
+{
+ using namespace std;
+// return x+std::sin(y);
+ EIGEN_ASM_COMMENT("mybegin");
+ return static_cast<Scalar>(x*2 - pow(x,2) + 2*sqrt(y*y) - 4 * sin(x) + 2 * cos(y) - exp(-0.5*x*x));
+ //return x+2*y*x;//x*2 -std::pow(x,2);//(2*y/x);// - y*2;
+ EIGEN_ASM_COMMENT("myend");
+}
+
+template<typename Vector>
+EIGEN_DONT_INLINE typename Vector::Scalar foo(const Vector& p)
+{
+ typedef typename Vector::Scalar Scalar;
+ return (p-Vector(Scalar(-1),Scalar(1.))).norm() + (p.array() * p.array()).sum() + p.dot(p);
+}
+
+template<typename _Scalar, int NX=Dynamic, int NY=Dynamic>
+struct TestFunc1
+{
+ typedef _Scalar Scalar;
+ enum {
+ InputsAtCompileTime = NX,
+ ValuesAtCompileTime = NY
+ };
+ typedef Matrix<Scalar,InputsAtCompileTime,1> InputType;
+ typedef Matrix<Scalar,ValuesAtCompileTime,1> ValueType;
+ typedef Matrix<Scalar,ValuesAtCompileTime,InputsAtCompileTime> JacobianType;
+
+ int m_inputs, m_values;
+
+ TestFunc1() : m_inputs(InputsAtCompileTime), m_values(ValuesAtCompileTime) {}
+ TestFunc1(int inputs, int values) : m_inputs(inputs), m_values(values) {}
+
+ int inputs() const { return m_inputs; }
+ int values() const { return m_values; }
+
+ template<typename T>
+ void operator() (const Matrix<T,InputsAtCompileTime,1>& x, Matrix<T,ValuesAtCompileTime,1>* _v) const
+ {
+ Matrix<T,ValuesAtCompileTime,1>& v = *_v;
+
+ v[0] = 2 * x[0] * x[0] + x[0] * x[1];
+ v[1] = 3 * x[1] * x[0] + 0.5 * x[1] * x[1];
+ if(inputs()>2)
+ {
+ v[0] += 0.5 * x[2];
+ v[1] += x[2];
+ }
+ if(values()>2)
+ {
+ v[2] = 3 * x[1] * x[0] * x[0];
+ }
+ if (inputs()>2 && values()>2)
+ v[2] *= x[2];
+ }
+
+ void operator() (const InputType& x, ValueType* v, JacobianType* _j) const
+ {
+ (*this)(x, v);
+
+ if(_j)
+ {
+ JacobianType& j = *_j;
+
+ j(0,0) = 4 * x[0] + x[1];
+ j(1,0) = 3 * x[1];
+
+ j(0,1) = x[0];
+ j(1,1) = 3 * x[0] + 2 * 0.5 * x[1];
+
+ if (inputs()>2)
+ {
+ j(0,2) = 0.5;
+ j(1,2) = 1;
+ }
+ if(values()>2)
+ {
+ j(2,0) = 3 * x[1] * 2 * x[0];
+ j(2,1) = 3 * x[0] * x[0];
+ }
+ if (inputs()>2 && values()>2)
+ {
+ j(2,0) *= x[2];
+ j(2,1) *= x[2];
+
+ j(2,2) = 3 * x[1] * x[0] * x[0];
+ j(2,2) = 3 * x[1] * x[0] * x[0];
+ }
+ }
+ }
+};
+
+template<typename Func> void forward_jacobian(const Func& f)
+{
+ typename Func::InputType x = Func::InputType::Random(f.inputs());
+ typename Func::ValueType y(f.values()), yref(f.values());
+ typename Func::JacobianType j(f.values(),f.inputs()), jref(f.values(),f.inputs());
+
+ jref.setZero();
+ yref.setZero();
+ f(x,&yref,&jref);
+// std::cerr << y.transpose() << "\n\n";;
+// std::cerr << j << "\n\n";;
+
+ j.setZero();
+ y.setZero();
+ AutoDiffJacobian<Func> autoj(f);
+ autoj(x, &y, &j);
+// std::cerr << y.transpose() << "\n\n";;
+// std::cerr << j << "\n\n";;
+
+ VERIFY_IS_APPROX(y, yref);
+ VERIFY_IS_APPROX(j, jref);
+}
+
+void test_autodiff_scalar()
+{
+ std::cerr << foo<float>(1,2) << "\n";
+ typedef AutoDiffScalar<Vector2f> AD;
+ AD ax(1,Vector2f::UnitX());
+ AD ay(2,Vector2f::UnitY());
+ AD res = foo<AD>(ax,ay);
+ std::cerr << res.value() << " <> "
+ << res.derivatives().transpose() << "\n\n";
+}
+
+void test_autodiff_vector()
+{
+ std::cerr << foo<Vector2f>(Vector2f(1,2)) << "\n";
+ typedef AutoDiffScalar<Vector2f> AD;
+ typedef Matrix<AD,2,1> VectorAD;
+ VectorAD p(AD(1),AD(-1));
+ p.x().derivatives() = Vector2f::UnitX();
+ p.y().derivatives() = Vector2f::UnitY();
+
+ AD res = foo<VectorAD>(p);
+ std::cerr << res.value() << " <> "
+ << res.derivatives().transpose() << "\n\n";
+}
+
+void test_autodiff_jacobian()
+{
+ for(int i = 0; i < g_repeat; i++) {
+ CALL_SUBTEST(( forward_jacobian(TestFunc1<double,2,2>()) ));
+ CALL_SUBTEST(( forward_jacobian(TestFunc1<double,2,3>()) ));
+ CALL_SUBTEST(( forward_jacobian(TestFunc1<double,3,2>()) ));
+ CALL_SUBTEST(( forward_jacobian(TestFunc1<double,3,3>()) ));
+ CALL_SUBTEST(( forward_jacobian(TestFunc1<double>(3,3)) ));
+ }
+}
+
+void test_autodiff()
+{
+ test_autodiff_scalar();
+ test_autodiff_vector();
+// test_autodiff_jacobian();
+}
+
diff --git a/unsupported/test/forward_adolc.cpp b/unsupported/test/forward_adolc.cpp
new file mode 100644
index 000000000..d4baafe62
--- /dev/null
+++ b/unsupported/test/forward_adolc.cpp
@@ -0,0 +1,143 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra.
+//
+// Copyright (C) 2008 Gael Guennebaud <g.gael@free.fr>
+//
+// This Source Code Form is subject to the terms of the Mozilla
+// Public License v. 2.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 "main.h"
+#include <Eigen/Dense>
+
+#define NUMBER_DIRECTIONS 16
+#include <unsupported/Eigen/AdolcForward>
+
+int adtl::ADOLC_numDir;
+
+template<typename Vector>
+EIGEN_DONT_INLINE typename Vector::Scalar foo(const Vector& p)
+{
+ typedef typename Vector::Scalar Scalar;
+ return (p-Vector(Scalar(-1),Scalar(1.))).norm() + (p.array().sqrt().abs() * p.array().sin()).sum() + p.dot(p);
+}
+
+template<typename _Scalar, int NX=Dynamic, int NY=Dynamic>
+struct TestFunc1
+{
+ typedef _Scalar Scalar;
+ enum {
+ InputsAtCompileTime = NX,
+ ValuesAtCompileTime = NY
+ };
+ typedef Matrix<Scalar,InputsAtCompileTime,1> InputType;
+ typedef Matrix<Scalar,ValuesAtCompileTime,1> ValueType;
+ typedef Matrix<Scalar,ValuesAtCompileTime,InputsAtCompileTime> JacobianType;
+
+ int m_inputs, m_values;
+
+ TestFunc1() : m_inputs(InputsAtCompileTime), m_values(ValuesAtCompileTime) {}
+ TestFunc1(int inputs, int values) : m_inputs(inputs), m_values(values) {}
+
+ int inputs() const { return m_inputs; }
+ int values() const { return m_values; }
+
+ template<typename T>
+ void operator() (const Matrix<T,InputsAtCompileTime,1>& x, Matrix<T,ValuesAtCompileTime,1>* _v) const
+ {
+ Matrix<T,ValuesAtCompileTime,1>& v = *_v;
+
+ v[0] = 2 * x[0] * x[0] + x[0] * x[1];
+ v[1] = 3 * x[1] * x[0] + 0.5 * x[1] * x[1];
+ if(inputs()>2)
+ {
+ v[0] += 0.5 * x[2];
+ v[1] += x[2];
+ }
+ if(values()>2)
+ {
+ v[2] = 3 * x[1] * x[0] * x[0];
+ }
+ if (inputs()>2 && values()>2)
+ v[2] *= x[2];
+ }
+
+ void operator() (const InputType& x, ValueType* v, JacobianType* _j) const
+ {
+ (*this)(x, v);
+
+ if(_j)
+ {
+ JacobianType& j = *_j;
+
+ j(0,0) = 4 * x[0] + x[1];
+ j(1,0) = 3 * x[1];
+
+ j(0,1) = x[0];
+ j(1,1) = 3 * x[0] + 2 * 0.5 * x[1];
+
+ if (inputs()>2)
+ {
+ j(0,2) = 0.5;
+ j(1,2) = 1;
+ }
+ if(values()>2)
+ {
+ j(2,0) = 3 * x[1] * 2 * x[0];
+ j(2,1) = 3 * x[0] * x[0];
+ }
+ if (inputs()>2 && values()>2)
+ {
+ j(2,0) *= x[2];
+ j(2,1) *= x[2];
+
+ j(2,2) = 3 * x[1] * x[0] * x[0];
+ j(2,2) = 3 * x[1] * x[0] * x[0];
+ }
+ }
+ }
+};
+
+template<typename Func> void adolc_forward_jacobian(const Func& f)
+{
+ typename Func::InputType x = Func::InputType::Random(f.inputs());
+ typename Func::ValueType y(f.values()), yref(f.values());
+ typename Func::JacobianType j(f.values(),f.inputs()), jref(f.values(),f.inputs());
+
+ jref.setZero();
+ yref.setZero();
+ f(x,&yref,&jref);
+// std::cerr << y.transpose() << "\n\n";;
+// std::cerr << j << "\n\n";;
+
+ j.setZero();
+ y.setZero();
+ AdolcForwardJacobian<Func> autoj(f);
+ autoj(x, &y, &j);
+// std::cerr << y.transpose() << "\n\n";;
+// std::cerr << j << "\n\n";;
+
+ VERIFY_IS_APPROX(y, yref);
+ VERIFY_IS_APPROX(j, jref);
+}
+
+void test_forward_adolc()
+{
+ adtl::ADOLC_numDir = NUMBER_DIRECTIONS;
+
+ for(int i = 0; i < g_repeat; i++) {
+ CALL_SUBTEST(( adolc_forward_jacobian(TestFunc1<double,2,2>()) ));
+ CALL_SUBTEST(( adolc_forward_jacobian(TestFunc1<double,2,3>()) ));
+ CALL_SUBTEST(( adolc_forward_jacobian(TestFunc1<double,3,2>()) ));
+ CALL_SUBTEST(( adolc_forward_jacobian(TestFunc1<double,3,3>()) ));
+ CALL_SUBTEST(( adolc_forward_jacobian(TestFunc1<double>(3,3)) ));
+ }
+
+ {
+ // simple instanciation tests
+ Matrix<adtl::adouble,2,1> x;
+ foo(x);
+ Matrix<adtl::adouble,Dynamic,Dynamic> A(4,4);;
+ A.selfadjointView<Lower>().eigenvalues();
+ }
+}
diff --git a/unsupported/test/gmres.cpp b/unsupported/test/gmres.cpp
new file mode 100644
index 000000000..647c16927
--- /dev/null
+++ b/unsupported/test/gmres.cpp
@@ -0,0 +1,33 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra.
+//
+// Copyright (C) 2011 Gael Guennebaud <g.gael@free.fr>
+// Copyright (C) 2012 Kolja Brix <brix@igpm.rwth-aaachen.de>
+//
+// This Source Code Form is subject to the terms of the Mozilla
+// Public License v. 2.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 "../../test/sparse_solver.h"
+#include <Eigen/IterativeSolvers>
+
+template<typename T> void test_gmres_T()
+{
+ GMRES<SparseMatrix<T>, DiagonalPreconditioner<T> > gmres_colmajor_diag;
+ GMRES<SparseMatrix<T>, IdentityPreconditioner > gmres_colmajor_I;
+ GMRES<SparseMatrix<T>, IncompleteLUT<T> > gmres_colmajor_ilut;
+ //GMRES<SparseMatrix<T>, SSORPreconditioner<T> > gmres_colmajor_ssor;
+
+ CALL_SUBTEST( check_sparse_square_solving(gmres_colmajor_diag) );
+// CALL_SUBTEST( check_sparse_square_solving(gmres_colmajor_I) );
+ CALL_SUBTEST( check_sparse_square_solving(gmres_colmajor_ilut) );
+ //CALL_SUBTEST( check_sparse_square_solving(gmres_colmajor_ssor) );
+}
+
+void test_gmres()
+{
+ for(int i = 0; i < g_repeat; i++) {
+ CALL_SUBTEST_1(test_gmres_T<double>());
+ CALL_SUBTEST_2(test_gmres_T<std::complex<double> >());
+ }
+}
diff --git a/unsupported/test/kronecker_product.cpp b/unsupported/test/kronecker_product.cpp
new file mode 100644
index 000000000..a60bd3022
--- /dev/null
+++ b/unsupported/test/kronecker_product.cpp
@@ -0,0 +1,179 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra.
+//
+// Copyright (C) 2011 Kolja Brix <brix@igpm.rwth-aachen.de>
+// Copyright (C) 2011 Andreas Platen <andiplaten@gmx.de>
+//
+// This Source Code Form is subject to the terms of the Mozilla
+// Public License v. 2.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 "sparse.h"
+#include <Eigen/SparseExtra>
+#include <Eigen/KroneckerProduct>
+
+
+template<typename MatrixType>
+void check_dimension(const MatrixType& ab, const unsigned int rows, const unsigned int cols)
+{
+ VERIFY_IS_EQUAL(ab.rows(), rows);
+ VERIFY_IS_EQUAL(ab.cols(), cols);
+}
+
+
+template<typename MatrixType>
+void check_kronecker_product(const MatrixType& ab)
+{
+ VERIFY_IS_EQUAL(ab.rows(), 6);
+ VERIFY_IS_EQUAL(ab.cols(), 6);
+ VERIFY_IS_EQUAL(ab.nonZeros(), 36);
+ VERIFY_IS_APPROX(ab.coeff(0,0), -0.4017367630386106);
+ VERIFY_IS_APPROX(ab.coeff(0,1), 0.1056863433932735);
+ VERIFY_IS_APPROX(ab.coeff(0,2), -0.7255206194554212);
+ VERIFY_IS_APPROX(ab.coeff(0,3), 0.1908653336744706);
+ VERIFY_IS_APPROX(ab.coeff(0,4), 0.350864567234111);
+ VERIFY_IS_APPROX(ab.coeff(0,5), -0.0923032108308013);
+ VERIFY_IS_APPROX(ab.coeff(1,0), 0.415417514804677);
+ VERIFY_IS_APPROX(ab.coeff(1,1), -0.2369227701722048);
+ VERIFY_IS_APPROX(ab.coeff(1,2), 0.7502275131458511);
+ VERIFY_IS_APPROX(ab.coeff(1,3), -0.4278731019742696);
+ VERIFY_IS_APPROX(ab.coeff(1,4), -0.3628129162264507);
+ VERIFY_IS_APPROX(ab.coeff(1,5), 0.2069210808481275);
+ VERIFY_IS_APPROX(ab.coeff(2,0), 0.05465890160863986);
+ VERIFY_IS_APPROX(ab.coeff(2,1), -0.2634092511419858);
+ VERIFY_IS_APPROX(ab.coeff(2,2), 0.09871180285793758);
+ VERIFY_IS_APPROX(ab.coeff(2,3), -0.4757066334017702);
+ VERIFY_IS_APPROX(ab.coeff(2,4), -0.04773740823058334);
+ VERIFY_IS_APPROX(ab.coeff(2,5), 0.2300535609645254);
+ VERIFY_IS_APPROX(ab.coeff(3,0), -0.8172945853260133);
+ VERIFY_IS_APPROX(ab.coeff(3,1), 0.2150086428359221);
+ VERIFY_IS_APPROX(ab.coeff(3,2), 0.5825113847292743);
+ VERIFY_IS_APPROX(ab.coeff(3,3), -0.1532433770097174);
+ VERIFY_IS_APPROX(ab.coeff(3,4), -0.329383387282399);
+ VERIFY_IS_APPROX(ab.coeff(3,5), 0.08665207912033064);
+ VERIFY_IS_APPROX(ab.coeff(4,0), 0.8451267514863225);
+ VERIFY_IS_APPROX(ab.coeff(4,1), -0.481996458918977);
+ VERIFY_IS_APPROX(ab.coeff(4,2), -0.6023482390791535);
+ VERIFY_IS_APPROX(ab.coeff(4,3), 0.3435339347164565);
+ VERIFY_IS_APPROX(ab.coeff(4,4), 0.3406002157428891);
+ VERIFY_IS_APPROX(ab.coeff(4,5), -0.1942526344200915);
+ VERIFY_IS_APPROX(ab.coeff(5,0), 0.1111982482925399);
+ VERIFY_IS_APPROX(ab.coeff(5,1), -0.5358806424754169);
+ VERIFY_IS_APPROX(ab.coeff(5,2), -0.07925446559335647);
+ VERIFY_IS_APPROX(ab.coeff(5,3), 0.3819388757769038);
+ VERIFY_IS_APPROX(ab.coeff(5,4), 0.04481475387219876);
+ VERIFY_IS_APPROX(ab.coeff(5,5), -0.2159688616158057);
+}
+
+
+template<typename MatrixType>
+void check_sparse_kronecker_product(const MatrixType& ab)
+{
+ VERIFY_IS_EQUAL(ab.rows(), 12);
+ VERIFY_IS_EQUAL(ab.cols(), 10);
+ VERIFY_IS_EQUAL(ab.nonZeros(), 3*2);
+ VERIFY_IS_APPROX(ab.coeff(3,0), -0.04);
+ VERIFY_IS_APPROX(ab.coeff(5,1), 0.05);
+ VERIFY_IS_APPROX(ab.coeff(0,6), -0.08);
+ VERIFY_IS_APPROX(ab.coeff(2,7), 0.10);
+ VERIFY_IS_APPROX(ab.coeff(6,8), 0.12);
+ VERIFY_IS_APPROX(ab.coeff(8,9), -0.15);
+}
+
+
+void test_kronecker_product()
+{
+ // DM = dense matrix; SM = sparse matrix
+ Matrix<double, 2, 3> DM_a;
+ MatrixXd DM_b(3,2);
+ SparseMatrix<double> SM_a(2,3);
+ SparseMatrix<double> SM_b(3,2);
+ SM_a.insert(0,0) = DM_a(0,0) = -0.4461540300782201;
+ SM_a.insert(0,1) = DM_a(0,1) = -0.8057364375283049;
+ SM_a.insert(0,2) = DM_a(0,2) = 0.3896572459516341;
+ SM_a.insert(1,0) = DM_a(1,0) = -0.9076572187376921;
+ SM_a.insert(1,1) = DM_a(1,1) = 0.6469156566545853;
+ SM_a.insert(1,2) = DM_a(1,2) = -0.3658010398782789;
+ SM_b.insert(0,0) = DM_b(0,0) = 0.9004440976767099;
+ SM_b.insert(0,1) = DM_b(0,1) = -0.2368830858139832;
+ SM_b.insert(1,0) = DM_b(1,0) = -0.9311078389941825;
+ SM_b.insert(1,1) = DM_b(1,1) = 0.5310335762980047;
+ SM_b.insert(2,0) = DM_b(2,0) = -0.1225112806872035;
+ SM_b.insert(2,1) = DM_b(2,1) = 0.5903998022741264;
+ SparseMatrix<double,RowMajor> SM_row_a(SM_a), SM_row_b(SM_b);
+
+ // test kroneckerProduct(DM_block,DM,DM_fixedSize)
+ Matrix<double, 6, 6> DM_fix_ab;
+ DM_fix_ab(0,0)=37.0;
+ kroneckerProduct(DM_a.block(0,0,2,3),DM_b,DM_fix_ab);
+ CALL_SUBTEST(check_kronecker_product(DM_fix_ab));
+
+ // test kroneckerProduct(DM,DM,DM_block)
+ MatrixXd DM_block_ab(10,15);
+ DM_block_ab(0,0)=37.0;
+ kroneckerProduct(DM_a,DM_b,DM_block_ab.block(2,5,6,6));
+ CALL_SUBTEST(check_kronecker_product(DM_block_ab.block(2,5,6,6)));
+
+ // test kroneckerProduct(DM,DM,DM)
+ MatrixXd DM_ab(1,5);
+ DM_ab(0,0)=37.0;
+ kroneckerProduct(DM_a,DM_b,DM_ab);
+ CALL_SUBTEST(check_kronecker_product(DM_ab));
+
+ // test kroneckerProduct(SM,DM,SM)
+ SparseMatrix<double> SM_ab(1,20);
+ SM_ab.insert(0,0)=37.0;
+ kroneckerProduct(SM_a,DM_b,SM_ab);
+ CALL_SUBTEST(check_kronecker_product(SM_ab));
+ SparseMatrix<double,RowMajor> SM_ab2(10,3);
+ SM_ab2.insert(0,0)=37.0;
+ kroneckerProduct(SM_a,DM_b,SM_ab2);
+ CALL_SUBTEST(check_kronecker_product(SM_ab2));
+
+ // test kroneckerProduct(DM,SM,SM)
+ SM_ab.insert(0,0)=37.0;
+ kroneckerProduct(DM_a,SM_b,SM_ab);
+ CALL_SUBTEST(check_kronecker_product(SM_ab));
+ SM_ab2.insert(0,0)=37.0;
+ kroneckerProduct(DM_a,SM_b,SM_ab2);
+ CALL_SUBTEST(check_kronecker_product(SM_ab2));
+
+ // test kroneckerProduct(SM,SM,SM)
+ SM_ab.resize(2,33);
+ SM_ab.insert(0,0)=37.0;
+ kroneckerProduct(SM_a,SM_b,SM_ab);
+ CALL_SUBTEST(check_kronecker_product(SM_ab));
+ SM_ab2.resize(5,11);
+ SM_ab2.insert(0,0)=37.0;
+ kroneckerProduct(SM_a,SM_b,SM_ab2);
+ CALL_SUBTEST(check_kronecker_product(SM_ab2));
+
+ // test kroneckerProduct(SM,SM,SM) with sparse pattern
+ SM_a.resize(4,5);
+ SM_b.resize(3,2);
+ SM_a.resizeNonZeros(0);
+ SM_b.resizeNonZeros(0);
+ SM_a.insert(1,0) = -0.1;
+ SM_a.insert(0,3) = -0.2;
+ SM_a.insert(2,4) = 0.3;
+ SM_a.finalize();
+ SM_b.insert(0,0) = 0.4;
+ SM_b.insert(2,1) = -0.5;
+ SM_b.finalize();
+ SM_ab.resize(1,1);
+ SM_ab.insert(0,0)=37.0;
+ kroneckerProduct(SM_a,SM_b,SM_ab);
+ CALL_SUBTEST(check_sparse_kronecker_product(SM_ab));
+
+ // test dimension of result of kroneckerProduct(DM,DM,DM)
+ MatrixXd DM_a2(2,1);
+ MatrixXd DM_b2(5,4);
+ MatrixXd DM_ab2;
+ kroneckerProduct(DM_a2,DM_b2,DM_ab2);
+ CALL_SUBTEST(check_dimension(DM_ab2,2*5,1*4));
+ DM_a2.resize(10,9);
+ DM_b2.resize(4,8);
+ kroneckerProduct(DM_a2,DM_b2,DM_ab2);
+ CALL_SUBTEST(check_dimension(DM_ab2,10*4,9*8));
+}
diff --git a/unsupported/test/matrix_exponential.cpp b/unsupported/test/matrix_exponential.cpp
new file mode 100644
index 000000000..695472f91
--- /dev/null
+++ b/unsupported/test/matrix_exponential.cpp
@@ -0,0 +1,149 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra.
+//
+// Copyright (C) 2009 Jitse Niesen <jitse@maths.leeds.ac.uk>
+//
+// This Source Code Form is subject to the terms of the Mozilla
+// Public License v. 2.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 "main.h"
+#include <unsupported/Eigen/MatrixFunctions>
+
+double binom(int n, int k)
+{
+ double res = 1;
+ for (int i=0; i<k; i++)
+ res = res * (n-k+i+1) / (i+1);
+ return res;
+}
+
+template <typename Derived, typename OtherDerived>
+double relerr(const MatrixBase<Derived>& A, const MatrixBase<OtherDerived>& B)
+{
+ return std::sqrt((A - B).cwiseAbs2().sum() / (std::min)(A.cwiseAbs2().sum(), B.cwiseAbs2().sum()));
+}
+
+template <typename T>
+T expfn(T x, int)
+{
+ return std::exp(x);
+}
+
+template <typename T>
+void test2dRotation(double tol)
+{
+ Matrix<T,2,2> A, B, C;
+ T angle;
+
+ A << 0, 1, -1, 0;
+ for (int i=0; i<=20; i++)
+ {
+ angle = static_cast<T>(pow(10, i / 5. - 2));
+ B << std::cos(angle), std::sin(angle), -std::sin(angle), std::cos(angle);
+
+ C = (angle*A).matrixFunction(expfn);
+ std::cout << "test2dRotation: i = " << i << " error funm = " << relerr(C, B);
+ VERIFY(C.isApprox(B, static_cast<T>(tol)));
+
+ C = (angle*A).exp();
+ std::cout << " error expm = " << relerr(C, B) << "\n";
+ VERIFY(C.isApprox(B, static_cast<T>(tol)));
+ }
+}
+
+template <typename T>
+void test2dHyperbolicRotation(double tol)
+{
+ Matrix<std::complex<T>,2,2> A, B, C;
+ std::complex<T> imagUnit(0,1);
+ T angle, ch, sh;
+
+ for (int i=0; i<=20; i++)
+ {
+ angle = static_cast<T>((i-10) / 2.0);
+ ch = std::cosh(angle);
+ sh = std::sinh(angle);
+ A << 0, angle*imagUnit, -angle*imagUnit, 0;
+ B << ch, sh*imagUnit, -sh*imagUnit, ch;
+
+ C = A.matrixFunction(expfn);
+ std::cout << "test2dHyperbolicRotation: i = " << i << " error funm = " << relerr(C, B);
+ VERIFY(C.isApprox(B, static_cast<T>(tol)));
+
+ C = A.exp();
+ std::cout << " error expm = " << relerr(C, B) << "\n";
+ VERIFY(C.isApprox(B, static_cast<T>(tol)));
+ }
+}
+
+template <typename T>
+void testPascal(double tol)
+{
+ for (int size=1; size<20; size++)
+ {
+ Matrix<T,Dynamic,Dynamic> A(size,size), B(size,size), C(size,size);
+ A.setZero();
+ for (int i=0; i<size-1; i++)
+ A(i+1,i) = static_cast<T>(i+1);
+ B.setZero();
+ for (int i=0; i<size; i++)
+ for (int j=0; j<=i; j++)
+ B(i,j) = static_cast<T>(binom(i,j));
+
+ C = A.matrixFunction(expfn);
+ std::cout << "testPascal: size = " << size << " error funm = " << relerr(C, B);
+ VERIFY(C.isApprox(B, static_cast<T>(tol)));
+
+ C = A.exp();
+ std::cout << " error expm = " << relerr(C, B) << "\n";
+ VERIFY(C.isApprox(B, static_cast<T>(tol)));
+ }
+}
+
+template<typename MatrixType>
+void randomTest(const MatrixType& m, double tol)
+{
+ /* this test covers the following files:
+ Inverse.h
+ */
+ typename MatrixType::Index rows = m.rows();
+ typename MatrixType::Index cols = m.cols();
+ MatrixType m1(rows, cols), m2(rows, cols), m3(rows, cols),
+ identity = MatrixType::Identity(rows, rows);
+
+ typedef typename NumTraits<typename internal::traits<MatrixType>::Scalar>::Real RealScalar;
+
+ for(int i = 0; i < g_repeat; i++) {
+ m1 = MatrixType::Random(rows, cols);
+
+ m2 = m1.matrixFunction(expfn) * (-m1).matrixFunction(expfn);
+ std::cout << "randomTest: error funm = " << relerr(identity, m2);
+ VERIFY(identity.isApprox(m2, static_cast<RealScalar>(tol)));
+
+ m2 = m1.exp() * (-m1).exp();
+ std::cout << " error expm = " << relerr(identity, m2) << "\n";
+ VERIFY(identity.isApprox(m2, static_cast<RealScalar>(tol)));
+ }
+}
+
+void test_matrix_exponential()
+{
+ CALL_SUBTEST_2(test2dRotation<double>(1e-13));
+ CALL_SUBTEST_1(test2dRotation<float>(2e-5)); // was 1e-5, relaxed for clang 2.8 / linux / x86-64
+ CALL_SUBTEST_8(test2dRotation<long double>(1e-13));
+ CALL_SUBTEST_2(test2dHyperbolicRotation<double>(1e-14));
+ CALL_SUBTEST_1(test2dHyperbolicRotation<float>(1e-5));
+ CALL_SUBTEST_8(test2dHyperbolicRotation<long double>(1e-14));
+ CALL_SUBTEST_6(testPascal<float>(1e-6));
+ CALL_SUBTEST_5(testPascal<double>(1e-15));
+ CALL_SUBTEST_2(randomTest(Matrix2d(), 1e-13));
+ CALL_SUBTEST_7(randomTest(Matrix<double,3,3,RowMajor>(), 1e-13));
+ CALL_SUBTEST_3(randomTest(Matrix4cd(), 1e-13));
+ CALL_SUBTEST_4(randomTest(MatrixXd(8,8), 1e-13));
+ CALL_SUBTEST_1(randomTest(Matrix2f(), 1e-4));
+ CALL_SUBTEST_5(randomTest(Matrix3cf(), 1e-4));
+ CALL_SUBTEST_1(randomTest(Matrix4f(), 1e-4));
+ CALL_SUBTEST_6(randomTest(MatrixXf(8,8), 1e-4));
+ CALL_SUBTEST_9(randomTest(Matrix<long double,Dynamic,Dynamic>(7,7), 1e-13));
+}
diff --git a/unsupported/test/matrix_function.cpp b/unsupported/test/matrix_function.cpp
new file mode 100644
index 000000000..0439c5a7d
--- /dev/null
+++ b/unsupported/test/matrix_function.cpp
@@ -0,0 +1,194 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra.
+//
+// Copyright (C) 2010 Jitse Niesen <jitse@maths.leeds.ac.uk>
+//
+// This Source Code Form is subject to the terms of the Mozilla
+// Public License v. 2.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 "main.h"
+#include <unsupported/Eigen/MatrixFunctions>
+
+// Variant of VERIFY_IS_APPROX which uses absolute error instead of
+// relative error.
+#define VERIFY_IS_APPROX_ABS(a, b) VERIFY(test_isApprox_abs(a, b))
+
+template<typename Type1, typename Type2>
+inline bool test_isApprox_abs(const Type1& a, const Type2& b)
+{
+ return ((a-b).array().abs() < test_precision<typename Type1::RealScalar>()).all();
+}
+
+
+// Returns a matrix with eigenvalues clustered around 0, 1 and 2.
+template<typename MatrixType>
+MatrixType randomMatrixWithRealEivals(const typename MatrixType::Index size)
+{
+ typedef typename MatrixType::Index Index;
+ typedef typename MatrixType::Scalar Scalar;
+ typedef typename MatrixType::RealScalar RealScalar;
+ MatrixType diag = MatrixType::Zero(size, size);
+ for (Index i = 0; i < size; ++i) {
+ diag(i, i) = Scalar(RealScalar(internal::random<int>(0,2)))
+ + internal::random<Scalar>() * Scalar(RealScalar(0.01));
+ }
+ MatrixType A = MatrixType::Random(size, size);
+ HouseholderQR<MatrixType> QRofA(A);
+ return QRofA.householderQ().inverse() * diag * QRofA.householderQ();
+}
+
+template <typename MatrixType, int IsComplex = NumTraits<typename internal::traits<MatrixType>::Scalar>::IsComplex>
+struct randomMatrixWithImagEivals
+{
+ // Returns a matrix with eigenvalues clustered around 0 and +/- i.
+ static MatrixType run(const typename MatrixType::Index size);
+};
+
+// Partial specialization for real matrices
+template<typename MatrixType>
+struct randomMatrixWithImagEivals<MatrixType, 0>
+{
+ static MatrixType run(const typename MatrixType::Index size)
+ {
+ typedef typename MatrixType::Index Index;
+ typedef typename MatrixType::Scalar Scalar;
+ MatrixType diag = MatrixType::Zero(size, size);
+ Index i = 0;
+ while (i < size) {
+ Index randomInt = internal::random<Index>(-1, 1);
+ if (randomInt == 0 || i == size-1) {
+ diag(i, i) = internal::random<Scalar>() * Scalar(0.01);
+ ++i;
+ } else {
+ Scalar alpha = Scalar(randomInt) + internal::random<Scalar>() * Scalar(0.01);
+ diag(i, i+1) = alpha;
+ diag(i+1, i) = -alpha;
+ i += 2;
+ }
+ }
+ MatrixType A = MatrixType::Random(size, size);
+ HouseholderQR<MatrixType> QRofA(A);
+ return QRofA.householderQ().inverse() * diag * QRofA.householderQ();
+ }
+};
+
+// Partial specialization for complex matrices
+template<typename MatrixType>
+struct randomMatrixWithImagEivals<MatrixType, 1>
+{
+ static MatrixType run(const typename MatrixType::Index size)
+ {
+ typedef typename MatrixType::Index Index;
+ typedef typename MatrixType::Scalar Scalar;
+ typedef typename MatrixType::RealScalar RealScalar;
+ const Scalar imagUnit(0, 1);
+ MatrixType diag = MatrixType::Zero(size, size);
+ for (Index i = 0; i < size; ++i) {
+ diag(i, i) = Scalar(RealScalar(internal::random<Index>(-1, 1))) * imagUnit
+ + internal::random<Scalar>() * Scalar(RealScalar(0.01));
+ }
+ MatrixType A = MatrixType::Random(size, size);
+ HouseholderQR<MatrixType> QRofA(A);
+ return QRofA.householderQ().inverse() * diag * QRofA.householderQ();
+ }
+};
+
+
+template<typename MatrixType>
+void testMatrixExponential(const MatrixType& A)
+{
+ typedef typename internal::traits<MatrixType>::Scalar Scalar;
+ typedef typename NumTraits<Scalar>::Real RealScalar;
+ typedef std::complex<RealScalar> ComplexScalar;
+
+ VERIFY_IS_APPROX(A.exp(), A.matrixFunction(StdStemFunctions<ComplexScalar>::exp));
+}
+
+template<typename MatrixType>
+void testMatrixLogarithm(const MatrixType& A)
+{
+ typedef typename internal::traits<MatrixType>::Scalar Scalar;
+ typedef typename NumTraits<Scalar>::Real RealScalar;
+ typedef std::complex<RealScalar> ComplexScalar;
+
+ MatrixType scaledA;
+ RealScalar maxImagPartOfSpectrum = A.eigenvalues().imag().cwiseAbs().maxCoeff();
+ if (maxImagPartOfSpectrum >= 0.9 * M_PI)
+ scaledA = A * 0.9 * M_PI / maxImagPartOfSpectrum;
+ else
+ scaledA = A;
+
+ // identity X.exp().log() = X only holds if Im(lambda) < pi for all eigenvalues of X
+ MatrixType expA = scaledA.exp();
+ MatrixType logExpA = expA.log();
+ VERIFY_IS_APPROX(logExpA, scaledA);
+}
+
+template<typename MatrixType>
+void testHyperbolicFunctions(const MatrixType& A)
+{
+ // Need to use absolute error because of possible cancellation when
+ // adding/subtracting expA and expmA.
+ VERIFY_IS_APPROX_ABS(A.sinh(), (A.exp() - (-A).exp()) / 2);
+ VERIFY_IS_APPROX_ABS(A.cosh(), (A.exp() + (-A).exp()) / 2);
+}
+
+template<typename MatrixType>
+void testGonioFunctions(const MatrixType& A)
+{
+ typedef typename MatrixType::Scalar Scalar;
+ typedef typename NumTraits<Scalar>::Real RealScalar;
+ typedef std::complex<RealScalar> ComplexScalar;
+ typedef Matrix<ComplexScalar, MatrixType::RowsAtCompileTime,
+ MatrixType::ColsAtCompileTime, MatrixType::Options> ComplexMatrix;
+
+ ComplexScalar imagUnit(0,1);
+ ComplexScalar two(2,0);
+
+ ComplexMatrix Ac = A.template cast<ComplexScalar>();
+
+ ComplexMatrix exp_iA = (imagUnit * Ac).exp();
+ ComplexMatrix exp_miA = (-imagUnit * Ac).exp();
+
+ ComplexMatrix sinAc = A.sin().template cast<ComplexScalar>();
+ VERIFY_IS_APPROX_ABS(sinAc, (exp_iA - exp_miA) / (two*imagUnit));
+
+ ComplexMatrix cosAc = A.cos().template cast<ComplexScalar>();
+ VERIFY_IS_APPROX_ABS(cosAc, (exp_iA + exp_miA) / 2);
+}
+
+template<typename MatrixType>
+void testMatrix(const MatrixType& A)
+{
+ testMatrixExponential(A);
+ testMatrixLogarithm(A);
+ testHyperbolicFunctions(A);
+ testGonioFunctions(A);
+}
+
+template<typename MatrixType>
+void testMatrixType(const MatrixType& m)
+{
+ // Matrices with clustered eigenvalue lead to different code paths
+ // in MatrixFunction.h and are thus useful for testing.
+ typedef typename MatrixType::Index Index;
+
+ const Index size = m.rows();
+ for (int i = 0; i < g_repeat; i++) {
+ testMatrix(MatrixType::Random(size, size).eval());
+ testMatrix(randomMatrixWithRealEivals<MatrixType>(size));
+ testMatrix(randomMatrixWithImagEivals<MatrixType>::run(size));
+ }
+}
+
+void test_matrix_function()
+{
+ CALL_SUBTEST_1(testMatrixType(Matrix<float,1,1>()));
+ CALL_SUBTEST_2(testMatrixType(Matrix3cf()));
+ CALL_SUBTEST_3(testMatrixType(MatrixXf(8,8)));
+ CALL_SUBTEST_4(testMatrixType(Matrix2d()));
+ CALL_SUBTEST_5(testMatrixType(Matrix<double,5,5,RowMajor>()));
+ CALL_SUBTEST_6(testMatrixType(Matrix4cd()));
+ CALL_SUBTEST_7(testMatrixType(MatrixXd(13,13)));
+}
diff --git a/unsupported/test/matrix_square_root.cpp b/unsupported/test/matrix_square_root.cpp
new file mode 100644
index 000000000..508619a7a
--- /dev/null
+++ b/unsupported/test/matrix_square_root.cpp
@@ -0,0 +1,62 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra.
+//
+// Copyright (C) 2011 Jitse Niesen <jitse@maths.leeds.ac.uk>
+//
+// This Source Code Form is subject to the terms of the Mozilla
+// Public License v. 2.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 "main.h"
+#include <unsupported/Eigen/MatrixFunctions>
+
+template <typename MatrixType, int IsComplex = NumTraits<typename internal::traits<MatrixType>::Scalar>::IsComplex>
+struct generateTestMatrix;
+
+// for real matrices, make sure none of the eigenvalues are negative
+template <typename MatrixType>
+struct generateTestMatrix<MatrixType,0>
+{
+ static void run(MatrixType& result, typename MatrixType::Index size)
+ {
+ MatrixType mat = MatrixType::Random(size, size);
+ EigenSolver<MatrixType> es(mat);
+ typename EigenSolver<MatrixType>::EigenvalueType eivals = es.eigenvalues();
+ for (typename MatrixType::Index i = 0; i < size; ++i) {
+ if (eivals(i).imag() == 0 && eivals(i).real() < 0)
+ eivals(i) = -eivals(i);
+ }
+ result = (es.eigenvectors() * eivals.asDiagonal() * es.eigenvectors().inverse()).real();
+ }
+};
+
+// for complex matrices, any matrix is fine
+template <typename MatrixType>
+struct generateTestMatrix<MatrixType,1>
+{
+ static void run(MatrixType& result, typename MatrixType::Index size)
+ {
+ result = MatrixType::Random(size, size);
+ }
+};
+
+template<typename MatrixType>
+void testMatrixSqrt(const MatrixType& m)
+{
+ MatrixType A;
+ generateTestMatrix<MatrixType>::run(A, m.rows());
+ MatrixType sqrtA = A.sqrt();
+ VERIFY_IS_APPROX(sqrtA * sqrtA, A);
+}
+
+void test_matrix_square_root()
+{
+ for (int i = 0; i < g_repeat; i++) {
+ CALL_SUBTEST_1(testMatrixSqrt(Matrix3cf()));
+ CALL_SUBTEST_2(testMatrixSqrt(MatrixXcd(12,12)));
+ CALL_SUBTEST_3(testMatrixSqrt(Matrix4f()));
+ CALL_SUBTEST_4(testMatrixSqrt(Matrix<double,Dynamic,Dynamic,RowMajor>(9, 9)));
+ CALL_SUBTEST_5(testMatrixSqrt(Matrix<float,1,1>()));
+ CALL_SUBTEST_5(testMatrixSqrt(Matrix<std::complex<float>,1,1>()));
+ }
+}
diff --git a/unsupported/test/mpreal/dlmalloc.c b/unsupported/test/mpreal/dlmalloc.c
new file mode 100755
index 000000000..7ce8feb07
--- /dev/null
+++ b/unsupported/test/mpreal/dlmalloc.c
@@ -0,0 +1,5703 @@
+/*
+ This is a version (aka dlmalloc) of malloc/free/realloc written by
+ Doug Lea and released to the public domain, as explained at
+ http://creativecommons.org/licenses/publicdomain. Send questions,
+ comments, complaints, performance data, etc to dl@cs.oswego.edu
+
+* Version 2.8.4 Wed May 27 09:56:23 2009 Doug Lea (dl at gee)
+
+ Note: There may be an updated version of this malloc obtainable at
+ ftp://gee.cs.oswego.edu/pub/misc/malloc.c
+ Check before installing!
+
+* Quickstart
+
+ This library is all in one file to simplify the most common usage:
+ ftp it, compile it (-O3), and link it into another program. All of
+ the compile-time options default to reasonable values for use on
+ most platforms. You might later want to step through various
+ compile-time and dynamic tuning options.
+
+ For convenience, an include file for code using this malloc is at:
+ ftp://gee.cs.oswego.edu/pub/misc/malloc-2.8.4.h
+ You don't really need this .h file unless you call functions not
+ defined in your system include files. The .h file contains only the
+ excerpts from this file needed for using this malloc on ANSI C/C++
+ systems, so long as you haven't changed compile-time options about
+ naming and tuning parameters. If you do, then you can create your
+ own malloc.h that does include all settings by cutting at the point
+ indicated below. Note that you may already by default be using a C
+ library containing a malloc that is based on some version of this
+ malloc (for example in linux). You might still want to use the one
+ in this file to customize settings or to avoid overheads associated
+ with library versions.
+
+* Vital statistics:
+
+ Supported pointer/size_t representation: 4 or 8 bytes
+ size_t MUST be an unsigned type of the same width as
+ pointers. (If you are using an ancient system that declares
+ size_t as a signed type, or need it to be a different width
+ than pointers, you can use a previous release of this malloc
+ (e.g. 2.7.2) supporting these.)
+
+ Alignment: 8 bytes (default)
+ This suffices for nearly all current machines and C compilers.
+ However, you can define MALLOC_ALIGNMENT to be wider than this
+ if necessary (up to 128bytes), at the expense of using more space.
+
+ Minimum overhead per allocated chunk: 4 or 8 bytes (if 4byte sizes)
+ 8 or 16 bytes (if 8byte sizes)
+ Each malloced chunk has a hidden word of overhead holding size
+ and status information, and additional cross-check word
+ if FOOTERS is defined.
+
+ Minimum allocated size: 4-byte ptrs: 16 bytes (including overhead)
+ 8-byte ptrs: 32 bytes (including overhead)
+
+ Even a request for zero bytes (i.e., malloc(0)) returns a
+ pointer to something of the minimum allocatable size.
+ The maximum overhead wastage (i.e., number of extra bytes
+ allocated than were requested in malloc) is less than or equal
+ to the minimum size, except for requests >= mmap_threshold that
+ are serviced via mmap(), where the worst case wastage is about
+ 32 bytes plus the remainder from a system page (the minimal
+ mmap unit); typically 4096 or 8192 bytes.
+
+ Security: static-safe; optionally more or less
+ The "security" of malloc refers to the ability of malicious
+ code to accentuate the effects of errors (for example, freeing
+ space that is not currently malloc'ed or overwriting past the
+ ends of chunks) in code that calls malloc. This malloc
+ guarantees not to modify any memory locations below the base of
+ heap, i.e., static variables, even in the presence of usage
+ errors. The routines additionally detect most improper frees
+ and reallocs. All this holds as long as the static bookkeeping
+ for malloc itself is not corrupted by some other means. This
+ is only one aspect of security -- these checks do not, and
+ cannot, detect all possible programming errors.
+
+ If FOOTERS is defined nonzero, then each allocated chunk
+ carries an additional check word to verify that it was malloced
+ from its space. These check words are the same within each
+ execution of a program using malloc, but differ across
+ executions, so externally crafted fake chunks cannot be
+ freed. This improves security by rejecting frees/reallocs that
+ could corrupt heap memory, in addition to the checks preventing
+ writes to statics that are always on. This may further improve
+ security at the expense of time and space overhead. (Note that
+ FOOTERS may also be worth using with MSPACES.)
+
+ By default detected errors cause the program to abort (calling
+ "abort()"). You can override this to instead proceed past
+ errors by defining PROCEED_ON_ERROR. In this case, a bad free
+ has no effect, and a malloc that encounters a bad address
+ caused by user overwrites will ignore the bad address by
+ dropping pointers and indices to all known memory. This may
+ be appropriate for programs that should continue if at all
+ possible in the face of programming errors, although they may
+ run out of memory because dropped memory is never reclaimed.
+
+ If you don't like either of these options, you can define
+ CORRUPTION_ERROR_ACTION and USAGE_ERROR_ACTION to do anything
+ else. And if if you are sure that your program using malloc has
+ no errors or vulnerabilities, you can define INSECURE to 1,
+ which might (or might not) provide a small performance improvement.
+
+ Thread-safety: NOT thread-safe unless USE_LOCKS defined
+ When USE_LOCKS is defined, each public call to malloc, free,
+ etc is surrounded with either a pthread mutex or a win32
+ spinlock (depending on WIN32). This is not especially fast, and
+ can be a major bottleneck. It is designed only to provide
+ minimal protection in concurrent environments, and to provide a
+ basis for extensions. If you are using malloc in a concurrent
+ program, consider instead using nedmalloc
+ (http://www.nedprod.com/programs/portable/nedmalloc/) or
+ ptmalloc (See http://www.malloc.de), which are derived
+ from versions of this malloc.
+
+ System requirements: Any combination of MORECORE and/or MMAP/MUNMAP
+ This malloc can use unix sbrk or any emulation (invoked using
+ the CALL_MORECORE macro) and/or mmap/munmap or any emulation
+ (invoked using CALL_MMAP/CALL_MUNMAP) to get and release system
+ memory. On most unix systems, it tends to work best if both
+ MORECORE and MMAP are enabled. On Win32, it uses emulations
+ based on VirtualAlloc. It also uses common C library functions
+ like memset.
+
+ Compliance: I believe it is compliant with the Single Unix Specification
+ (See http://www.unix.org). Also SVID/XPG, ANSI C, and probably
+ others as well.
+
+* Overview of algorithms
+
+ This is not the fastest, most space-conserving, most portable, or
+ most tunable malloc ever written. However it is among the fastest
+ while also being among the most space-conserving, portable and
+ tunable. Consistent balance across these factors results in a good
+ general-purpose allocator for malloc-intensive programs.
+
+ In most ways, this malloc is a best-fit allocator. Generally, it
+ chooses the best-fitting existing chunk for a request, with ties
+ broken in approximately least-recently-used order. (This strategy
+ normally maintains low fragmentation.) However, for requests less
+ than 256bytes, it deviates from best-fit when there is not an
+ exactly fitting available chunk by preferring to use space adjacent
+ to that used for the previous small request, as well as by breaking
+ ties in approximately most-recently-used order. (These enhance
+ locality of series of small allocations.) And for very large requests
+ (>= 256Kb by default), it relies on system memory mapping
+ facilities, if supported. (This helps avoid carrying around and
+ possibly fragmenting memory used only for large chunks.)
+
+ All operations (except malloc_stats and mallinfo) have execution
+ times that are bounded by a constant factor of the number of bits in
+ a size_t, not counting any clearing in calloc or copying in realloc,
+ or actions surrounding MORECORE and MMAP that have times
+ proportional to the number of non-contiguous regions returned by
+ system allocation routines, which is often just 1. In real-time
+ applications, you can optionally suppress segment traversals using
+ NO_SEGMENT_TRAVERSAL, which assures bounded execution even when
+ system allocators return non-contiguous spaces, at the typical
+ expense of carrying around more memory and increased fragmentation.
+
+ The implementation is not very modular and seriously overuses
+ macros. Perhaps someday all C compilers will do as good a job
+ inlining modular code as can now be done by brute-force expansion,
+ but now, enough of them seem not to.
+
+ Some compilers issue a lot of warnings about code that is
+ dead/unreachable only on some platforms, and also about intentional
+ uses of negation on unsigned types. All known cases of each can be
+ ignored.
+
+ For a longer but out of date high-level description, see
+ http://gee.cs.oswego.edu/dl/html/malloc.html
+
+* MSPACES
+ If MSPACES is defined, then in addition to malloc, free, etc.,
+ this file also defines mspace_malloc, mspace_free, etc. These
+ are versions of malloc routines that take an "mspace" argument
+ obtained using create_mspace, to control all internal bookkeeping.
+ If ONLY_MSPACES is defined, only these versions are compiled.
+ So if you would like to use this allocator for only some allocations,
+ and your system malloc for others, you can compile with
+ ONLY_MSPACES and then do something like...
+ static mspace mymspace = create_mspace(0,0); // for example
+ #define mymalloc(bytes) mspace_malloc(mymspace, bytes)
+
+ (Note: If you only need one instance of an mspace, you can instead
+ use "USE_DL_PREFIX" to relabel the global malloc.)
+
+ You can similarly create thread-local allocators by storing
+ mspaces as thread-locals. For example:
+ static __thread mspace tlms = 0;
+ void* tlmalloc(size_t bytes) {
+ if (tlms == 0) tlms = create_mspace(0, 0);
+ return mspace_malloc(tlms, bytes);
+ }
+ void tlfree(void* mem) { mspace_free(tlms, mem); }
+
+ Unless FOOTERS is defined, each mspace is completely independent.
+ You cannot allocate from one and free to another (although
+ conformance is only weakly checked, so usage errors are not always
+ caught). If FOOTERS is defined, then each chunk carries around a tag
+ indicating its originating mspace, and frees are directed to their
+ originating spaces.
+
+ ------------------------- Compile-time options ---------------------------
+
+Be careful in setting #define values for numerical constants of type
+size_t. On some systems, literal values are not automatically extended
+to size_t precision unless they are explicitly casted. You can also
+use the symbolic values MAX_SIZE_T, SIZE_T_ONE, etc below.
+
+WIN32 default: defined if _WIN32 defined
+ Defining WIN32 sets up defaults for MS environment and compilers.
+ Otherwise defaults are for unix. Beware that there seem to be some
+ cases where this malloc might not be a pure drop-in replacement for
+ Win32 malloc: Random-looking failures from Win32 GDI API's (eg;
+ SetDIBits()) may be due to bugs in some video driver implementations
+ when pixel buffers are malloc()ed, and the region spans more than
+ one VirtualAlloc()ed region. Because dlmalloc uses a small (64Kb)
+ default granularity, pixel buffers may straddle virtual allocation
+ regions more often than when using the Microsoft allocator. You can
+ avoid this by using VirtualAlloc() and VirtualFree() for all pixel
+ buffers rather than using malloc(). If this is not possible,
+ recompile this malloc with a larger DEFAULT_GRANULARITY.
+
+MALLOC_ALIGNMENT default: (size_t)8
+ Controls the minimum alignment for malloc'ed chunks. It must be a
+ power of two and at least 8, even on machines for which smaller
+ alignments would suffice. It may be defined as larger than this
+ though. Note however that code and data structures are optimized for
+ the case of 8-byte alignment.
+
+MSPACES default: 0 (false)
+ If true, compile in support for independent allocation spaces.
+ This is only supported if HAVE_MMAP is true.
+
+ONLY_MSPACES default: 0 (false)
+ If true, only compile in mspace versions, not regular versions.
+
+USE_LOCKS default: 0 (false)
+ Causes each call to each public routine to be surrounded with
+ pthread or WIN32 mutex lock/unlock. (If set true, this can be
+ overridden on a per-mspace basis for mspace versions.) If set to a
+ non-zero value other than 1, locks are used, but their
+ implementation is left out, so lock functions must be supplied manually,
+ as described below.
+
+USE_SPIN_LOCKS default: 1 iff USE_LOCKS and on x86 using gcc or MSC
+ If true, uses custom spin locks for locking. This is currently
+ supported only for x86 platforms using gcc or recent MS compilers.
+ Otherwise, posix locks or win32 critical sections are used.
+
+FOOTERS default: 0
+ If true, provide extra checking and dispatching by placing
+ information in the footers of allocated chunks. This adds
+ space and time overhead.
+
+INSECURE default: 0
+ If true, omit checks for usage errors and heap space overwrites.
+
+USE_DL_PREFIX default: NOT defined
+ Causes compiler to prefix all public routines with the string 'dl'.
+ This can be useful when you only want to use this malloc in one part
+ of a program, using your regular system malloc elsewhere.
+
+ABORT default: defined as abort()
+ Defines how to abort on failed checks. On most systems, a failed
+ check cannot die with an "assert" or even print an informative
+ message, because the underlying print routines in turn call malloc,
+ which will fail again. Generally, the best policy is to simply call
+ abort(). It's not very useful to do more than this because many
+ errors due to overwriting will show up as address faults (null, odd
+ addresses etc) rather than malloc-triggered checks, so will also
+ abort. Also, most compilers know that abort() does not return, so
+ can better optimize code conditionally calling it.
+
+PROCEED_ON_ERROR default: defined as 0 (false)
+ Controls whether detected bad addresses cause them to bypassed
+ rather than aborting. If set, detected bad arguments to free and
+ realloc are ignored. And all bookkeeping information is zeroed out
+ upon a detected overwrite of freed heap space, thus losing the
+ ability to ever return it from malloc again, but enabling the
+ application to proceed. If PROCEED_ON_ERROR is defined, the
+ static variable malloc_corruption_error_count is compiled in
+ and can be examined to see if errors have occurred. This option
+ generates slower code than the default abort policy.
+
+DEBUG default: NOT defined
+ The DEBUG setting is mainly intended for people trying to modify
+ this code or diagnose problems when porting to new platforms.
+ However, it may also be able to better isolate user errors than just
+ using runtime checks. The assertions in the check routines spell
+ out in more detail the assumptions and invariants underlying the
+ algorithms. The checking is fairly extensive, and will slow down
+ execution noticeably. Calling malloc_stats or mallinfo with DEBUG
+ set will attempt to check every non-mmapped allocated and free chunk
+ in the course of computing the summaries.
+
+ABORT_ON_ASSERT_FAILURE default: defined as 1 (true)
+ Debugging assertion failures can be nearly impossible if your
+ version of the assert macro causes malloc to be called, which will
+ lead to a cascade of further failures, blowing the runtime stack.
+ ABORT_ON_ASSERT_FAILURE cause assertions failures to call abort(),
+ which will usually make debugging easier.
+
+MALLOC_FAILURE_ACTION default: sets errno to ENOMEM, or no-op on win32
+ The action to take before "return 0" when malloc fails to be able to
+ return memory because there is none available.
+
+HAVE_MORECORE default: 1 (true) unless win32 or ONLY_MSPACES
+ True if this system supports sbrk or an emulation of it.
+
+MORECORE default: sbrk
+ The name of the sbrk-style system routine to call to obtain more
+ memory. See below for guidance on writing custom MORECORE
+ functions. The type of the argument to sbrk/MORECORE varies across
+ systems. It cannot be size_t, because it supports negative
+ arguments, so it is normally the signed type of the same width as
+ size_t (sometimes declared as "intptr_t"). It doesn't much matter
+ though. Internally, we only call it with arguments less than half
+ the max value of a size_t, which should work across all reasonable
+ possibilities, although sometimes generating compiler warnings.
+
+MORECORE_CONTIGUOUS default: 1 (true) if HAVE_MORECORE
+ If true, take advantage of fact that consecutive calls to MORECORE
+ with positive arguments always return contiguous increasing
+ addresses. This is true of unix sbrk. It does not hurt too much to
+ set it true anyway, since malloc copes with non-contiguities.
+ Setting it false when definitely non-contiguous saves time
+ and possibly wasted space it would take to discover this though.
+
+MORECORE_CANNOT_TRIM default: NOT defined
+ True if MORECORE cannot release space back to the system when given
+ negative arguments. This is generally necessary only if you are
+ using a hand-crafted MORECORE function that cannot handle negative
+ arguments.
+
+NO_SEGMENT_TRAVERSAL default: 0
+ If non-zero, suppresses traversals of memory segments
+ returned by either MORECORE or CALL_MMAP. This disables
+ merging of segments that are contiguous, and selectively
+ releasing them to the OS if unused, but bounds execution times.
+
+HAVE_MMAP default: 1 (true)
+ True if this system supports mmap or an emulation of it. If so, and
+ HAVE_MORECORE is not true, MMAP is used for all system
+ allocation. If set and HAVE_MORECORE is true as well, MMAP is
+ primarily used to directly allocate very large blocks. It is also
+ used as a backup strategy in cases where MORECORE fails to provide
+ space from system. Note: A single call to MUNMAP is assumed to be
+ able to unmap memory that may have be allocated using multiple calls
+ to MMAP, so long as they are adjacent.
+
+HAVE_MREMAP default: 1 on linux, else 0
+ If true realloc() uses mremap() to re-allocate large blocks and
+ extend or shrink allocation spaces.
+
+MMAP_CLEARS default: 1 except on WINCE.
+ True if mmap clears memory so calloc doesn't need to. This is true
+ for standard unix mmap using /dev/zero and on WIN32 except for WINCE.
+
+USE_BUILTIN_FFS default: 0 (i.e., not used)
+ Causes malloc to use the builtin ffs() function to compute indices.
+ Some compilers may recognize and intrinsify ffs to be faster than the
+ supplied C version. Also, the case of x86 using gcc is special-cased
+ to an asm instruction, so is already as fast as it can be, and so
+ this setting has no effect. Similarly for Win32 under recent MS compilers.
+ (On most x86s, the asm version is only slightly faster than the C version.)
+
+malloc_getpagesize default: derive from system includes, or 4096.
+ The system page size. To the extent possible, this malloc manages
+ memory from the system in page-size units. This may be (and
+ usually is) a function rather than a constant. This is ignored
+ if WIN32, where page size is determined using getSystemInfo during
+ initialization.
+
+USE_DEV_RANDOM default: 0 (i.e., not used)
+ Causes malloc to use /dev/random to initialize secure magic seed for
+ stamping footers. Otherwise, the current time is used.
+
+NO_MALLINFO default: 0
+ If defined, don't compile "mallinfo". This can be a simple way
+ of dealing with mismatches between system declarations and
+ those in this file.
+
+MALLINFO_FIELD_TYPE default: size_t
+ The type of the fields in the mallinfo struct. This was originally
+ defined as "int" in SVID etc, but is more usefully defined as
+ size_t. The value is used only if HAVE_USR_INCLUDE_MALLOC_H is not set
+
+REALLOC_ZERO_BYTES_FREES default: not defined
+ This should be set if a call to realloc with zero bytes should
+ be the same as a call to free. Some people think it should. Otherwise,
+ since this malloc returns a unique pointer for malloc(0), so does
+ realloc(p, 0).
+
+LACKS_UNISTD_H, LACKS_FCNTL_H, LACKS_SYS_PARAM_H, LACKS_SYS_MMAN_H
+LACKS_STRINGS_H, LACKS_STRING_H, LACKS_SYS_TYPES_H, LACKS_ERRNO_H
+LACKS_STDLIB_H default: NOT defined unless on WIN32
+ Define these if your system does not have these header files.
+ You might need to manually insert some of the declarations they provide.
+
+DEFAULT_GRANULARITY default: page size if MORECORE_CONTIGUOUS,
+ system_info.dwAllocationGranularity in WIN32,
+ otherwise 64K.
+ Also settable using mallopt(M_GRANULARITY, x)
+ The unit for allocating and deallocating memory from the system. On
+ most systems with contiguous MORECORE, there is no reason to
+ make this more than a page. However, systems with MMAP tend to
+ either require or encourage larger granularities. You can increase
+ this value to prevent system allocation functions to be called so
+ often, especially if they are slow. The value must be at least one
+ page and must be a power of two. Setting to 0 causes initialization
+ to either page size or win32 region size. (Note: In previous
+ versions of malloc, the equivalent of this option was called
+ "TOP_PAD")
+
+DEFAULT_TRIM_THRESHOLD default: 2MB
+ Also settable using mallopt(M_TRIM_THRESHOLD, x)
+ The maximum amount of unused top-most memory to keep before
+ releasing via malloc_trim in free(). Automatic trimming is mainly
+ useful in long-lived programs using contiguous MORECORE. Because
+ trimming via sbrk can be slow on some systems, and can sometimes be
+ wasteful (in cases where programs immediately afterward allocate
+ more large chunks) the value should be high enough so that your
+ overall system performance would improve by releasing this much
+ memory. As a rough guide, you might set to a value close to the
+ average size of a process (program) running on your system.
+ Releasing this much memory would allow such a process to run in
+ memory. Generally, it is worth tuning trim thresholds when a
+ program undergoes phases where several large chunks are allocated
+ and released in ways that can reuse each other's storage, perhaps
+ mixed with phases where there are no such chunks at all. The trim
+ value must be greater than page size to have any useful effect. To
+ disable trimming completely, you can set to MAX_SIZE_T. Note that the trick
+ some people use of mallocing a huge space and then freeing it at
+ program startup, in an attempt to reserve system memory, doesn't
+ have the intended effect under automatic trimming, since that memory
+ will immediately be returned to the system.
+
+DEFAULT_MMAP_THRESHOLD default: 256K
+ Also settable using mallopt(M_MMAP_THRESHOLD, x)
+ The request size threshold for using MMAP to directly service a
+ request. Requests of at least this size that cannot be allocated
+ using already-existing space will be serviced via mmap. (If enough
+ normal freed space already exists it is used instead.) Using mmap
+ segregates relatively large chunks of memory so that they can be
+ individually obtained and released from the host system. A request
+ serviced through mmap is never reused by any other request (at least
+ not directly; the system may just so happen to remap successive
+ requests to the same locations). Segregating space in this way has
+ the benefits that: Mmapped space can always be individually released
+ back to the system, which helps keep the system level memory demands
+ of a long-lived program low. Also, mapped memory doesn't become
+ `locked' between other chunks, as can happen with normally allocated
+ chunks, which means that even trimming via malloc_trim would not
+ release them. However, it has the disadvantage that the space
+ cannot be reclaimed, consolidated, and then used to service later
+ requests, as happens with normal chunks. The advantages of mmap
+ nearly always outweigh disadvantages for "large" chunks, but the
+ value of "large" may vary across systems. The default is an
+ empirically derived value that works well in most systems. You can
+ disable mmap by setting to MAX_SIZE_T.
+
+MAX_RELEASE_CHECK_RATE default: 4095 unless not HAVE_MMAP
+ The number of consolidated frees between checks to release
+ unused segments when freeing. When using non-contiguous segments,
+ especially with multiple mspaces, checking only for topmost space
+ doesn't always suffice to trigger trimming. To compensate for this,
+ free() will, with a period of MAX_RELEASE_CHECK_RATE (or the
+ current number of segments, if greater) try to release unused
+ segments to the OS when freeing chunks that result in
+ consolidation. The best value for this parameter is a compromise
+ between slowing down frees with relatively costly checks that
+ rarely trigger versus holding on to unused memory. To effectively
+ disable, set to MAX_SIZE_T. This may lead to a very slight speed
+ improvement at the expense of carrying around more memory.
+*/
+
+#define USE_DL_PREFIX
+//#define HAVE_USR_INCLUDE_MALLOC_H
+//#define MSPACES 1
+#define NO_SEGMENT_TRAVERSAL 1
+
+/* Version identifier to allow people to support multiple versions */
+#ifndef DLMALLOC_VERSION
+#define DLMALLOC_VERSION 20804
+#endif /* DLMALLOC_VERSION */
+
+#ifndef WIN32
+#ifdef _WIN32
+#define WIN32 1
+#endif /* _WIN32 */
+#ifdef _WIN32_WCE
+#define LACKS_FCNTL_H
+#define WIN32 1
+#endif /* _WIN32_WCE */
+#endif /* WIN32 */
+#ifdef WIN32
+#define WIN32_LEAN_AND_MEAN
+#include <windows.h>
+#define HAVE_MMAP 1
+#define HAVE_MORECORE 0
+#define LACKS_UNISTD_H
+#define LACKS_SYS_PARAM_H
+#define LACKS_SYS_MMAN_H
+#define LACKS_STRING_H
+#define LACKS_STRINGS_H
+#define LACKS_SYS_TYPES_H
+#define LACKS_ERRNO_H
+#ifndef MALLOC_FAILURE_ACTION
+#define MALLOC_FAILURE_ACTION
+#endif /* MALLOC_FAILURE_ACTION */
+#ifdef _WIN32_WCE /* WINCE reportedly does not clear */
+#define MMAP_CLEARS 0
+#else
+#define MMAP_CLEARS 1
+#endif /* _WIN32_WCE */
+#endif /* WIN32 */
+
+#if defined(DARWIN) || defined(_DARWIN)
+/* Mac OSX docs advise not to use sbrk; it seems better to use mmap */
+#ifndef HAVE_MORECORE
+#define HAVE_MORECORE 0
+#define HAVE_MMAP 1
+/* OSX allocators provide 16 byte alignment */
+#ifndef MALLOC_ALIGNMENT
+#define MALLOC_ALIGNMENT ((size_t)16U)
+#endif
+#endif /* HAVE_MORECORE */
+#endif /* DARWIN */
+
+#ifndef LACKS_SYS_TYPES_H
+#include <sys/types.h> /* For size_t */
+#endif /* LACKS_SYS_TYPES_H */
+
+#if (defined(__GNUC__) && ((defined(__i386__) || defined(__x86_64__)))) || (defined(_MSC_VER) && _MSC_VER>=1310)
+#define SPIN_LOCKS_AVAILABLE 1
+#else
+#define SPIN_LOCKS_AVAILABLE 0
+#endif
+
+/* The maximum possible size_t value has all bits set */
+#define MAX_SIZE_T (~(size_t)0)
+
+#ifndef ONLY_MSPACES
+#define ONLY_MSPACES 0 /* define to a value */
+#else
+#define ONLY_MSPACES 1
+#endif /* ONLY_MSPACES */
+#ifndef MSPACES
+#if ONLY_MSPACES
+#define MSPACES 1
+#else /* ONLY_MSPACES */
+#define MSPACES 0
+#endif /* ONLY_MSPACES */
+#endif /* MSPACES */
+#ifndef MALLOC_ALIGNMENT
+#define MALLOC_ALIGNMENT ((size_t)8U)
+#endif /* MALLOC_ALIGNMENT */
+#ifndef FOOTERS
+#define FOOTERS 0
+#endif /* FOOTERS */
+#ifndef ABORT
+#define ABORT abort()
+#endif /* ABORT */
+#ifndef ABORT_ON_ASSERT_FAILURE
+#define ABORT_ON_ASSERT_FAILURE 1
+#endif /* ABORT_ON_ASSERT_FAILURE */
+#ifndef PROCEED_ON_ERROR
+#define PROCEED_ON_ERROR 0
+#endif /* PROCEED_ON_ERROR */
+#ifndef USE_LOCKS
+#define USE_LOCKS 0
+#endif /* USE_LOCKS */
+#ifndef USE_SPIN_LOCKS
+#if USE_LOCKS && SPIN_LOCKS_AVAILABLE
+#define USE_SPIN_LOCKS 1
+#else
+#define USE_SPIN_LOCKS 0
+#endif /* USE_LOCKS && SPIN_LOCKS_AVAILABLE. */
+#endif /* USE_SPIN_LOCKS */
+#ifndef INSECURE
+#define INSECURE 0
+#endif /* INSECURE */
+#ifndef HAVE_MMAP
+#define HAVE_MMAP 1
+#endif /* HAVE_MMAP */
+#ifndef MMAP_CLEARS
+#define MMAP_CLEARS 1
+#endif /* MMAP_CLEARS */
+#ifndef HAVE_MREMAP
+#ifdef linux
+#define HAVE_MREMAP 1
+#else /* linux */
+#define HAVE_MREMAP 0
+#endif /* linux */
+#endif /* HAVE_MREMAP */
+#ifndef MALLOC_FAILURE_ACTION
+#define MALLOC_FAILURE_ACTION errno = ENOMEM;
+#endif /* MALLOC_FAILURE_ACTION */
+#ifndef HAVE_MORECORE
+#if ONLY_MSPACES
+#define HAVE_MORECORE 0
+#else /* ONLY_MSPACES */
+#define HAVE_MORECORE 1
+#endif /* ONLY_MSPACES */
+#endif /* HAVE_MORECORE */
+#if !HAVE_MORECORE
+#define MORECORE_CONTIGUOUS 0
+#else /* !HAVE_MORECORE */
+#define MORECORE_DEFAULT sbrk
+#ifndef MORECORE_CONTIGUOUS
+#define MORECORE_CONTIGUOUS 1
+#endif /* MORECORE_CONTIGUOUS */
+#endif /* HAVE_MORECORE */
+#ifndef DEFAULT_GRANULARITY
+#if (MORECORE_CONTIGUOUS || defined(WIN32))
+#define DEFAULT_GRANULARITY (0) /* 0 means to compute in init_mparams */
+#else /* MORECORE_CONTIGUOUS */
+#define DEFAULT_GRANULARITY ((size_t)64U * (size_t)1024U)
+#endif /* MORECORE_CONTIGUOUS */
+#endif /* DEFAULT_GRANULARITY */
+#ifndef DEFAULT_TRIM_THRESHOLD
+#ifndef MORECORE_CANNOT_TRIM
+#define DEFAULT_TRIM_THRESHOLD ((size_t)2U * (size_t)1024U * (size_t)1024U)
+#else /* MORECORE_CANNOT_TRIM */
+#define DEFAULT_TRIM_THRESHOLD MAX_SIZE_T
+#endif /* MORECORE_CANNOT_TRIM */
+#endif /* DEFAULT_TRIM_THRESHOLD */
+#ifndef DEFAULT_MMAP_THRESHOLD
+#if HAVE_MMAP
+#define DEFAULT_MMAP_THRESHOLD ((size_t)256U * (size_t)1024U)
+#else /* HAVE_MMAP */
+#define DEFAULT_MMAP_THRESHOLD MAX_SIZE_T
+#endif /* HAVE_MMAP */
+#endif /* DEFAULT_MMAP_THRESHOLD */
+#ifndef MAX_RELEASE_CHECK_RATE
+#if HAVE_MMAP
+#define MAX_RELEASE_CHECK_RATE 4095
+#else
+#define MAX_RELEASE_CHECK_RATE MAX_SIZE_T
+#endif /* HAVE_MMAP */
+#endif /* MAX_RELEASE_CHECK_RATE */
+#ifndef USE_BUILTIN_FFS
+#define USE_BUILTIN_FFS 0
+#endif /* USE_BUILTIN_FFS */
+#ifndef USE_DEV_RANDOM
+#define USE_DEV_RANDOM 0
+#endif /* USE_DEV_RANDOM */
+#ifndef NO_MALLINFO
+#define NO_MALLINFO 0
+#endif /* NO_MALLINFO */
+#ifndef MALLINFO_FIELD_TYPE
+#define MALLINFO_FIELD_TYPE size_t
+#endif /* MALLINFO_FIELD_TYPE */
+#ifndef NO_SEGMENT_TRAVERSAL
+#define NO_SEGMENT_TRAVERSAL 0
+#endif /* NO_SEGMENT_TRAVERSAL */
+
+/*
+ mallopt tuning options. SVID/XPG defines four standard parameter
+ numbers for mallopt, normally defined in malloc.h. None of these
+ are used in this malloc, so setting them has no effect. But this
+ malloc does support the following options.
+*/
+
+#define M_TRIM_THRESHOLD (-1)
+#define M_GRANULARITY (-2)
+#define M_MMAP_THRESHOLD (-3)
+
+/* ------------------------ Mallinfo declarations ------------------------ */
+
+#if !NO_MALLINFO
+/*
+ This version of malloc supports the standard SVID/XPG mallinfo
+ routine that returns a struct containing usage properties and
+ statistics. It should work on any system that has a
+ /usr/include/malloc.h defining struct mallinfo. The main
+ declaration needed is the mallinfo struct that is returned (by-copy)
+ by mallinfo(). The malloinfo struct contains a bunch of fields that
+ are not even meaningful in this version of malloc. These fields are
+ are instead filled by mallinfo() with other numbers that might be of
+ interest.
+
+ HAVE_USR_INCLUDE_MALLOC_H should be set if you have a
+ /usr/include/malloc.h file that includes a declaration of struct
+ mallinfo. If so, it is included; else a compliant version is
+ declared below. These must be precisely the same for mallinfo() to
+ work. The original SVID version of this struct, defined on most
+ systems with mallinfo, declares all fields as ints. But some others
+ define as unsigned long. If your system defines the fields using a
+ type of different width than listed here, you MUST #include your
+ system version and #define HAVE_USR_INCLUDE_MALLOC_H.
+*/
+
+/* #define HAVE_USR_INCLUDE_MALLOC_H */
+
+#ifdef HAVE_USR_INCLUDE_MALLOC_H
+#include "/usr/include/malloc.h"
+#else /* HAVE_USR_INCLUDE_MALLOC_H */
+#ifndef STRUCT_MALLINFO_DECLARED
+#define STRUCT_MALLINFO_DECLARED 1
+struct mallinfo {
+ MALLINFO_FIELD_TYPE arena; /* non-mmapped space allocated from system */
+ MALLINFO_FIELD_TYPE ordblks; /* number of free chunks */
+ MALLINFO_FIELD_TYPE smblks; /* always 0 */
+ MALLINFO_FIELD_TYPE hblks; /* always 0 */
+ MALLINFO_FIELD_TYPE hblkhd; /* space in mmapped regions */
+ MALLINFO_FIELD_TYPE usmblks; /* maximum total allocated space */
+ MALLINFO_FIELD_TYPE fsmblks; /* always 0 */
+ MALLINFO_FIELD_TYPE uordblks; /* total allocated space */
+ MALLINFO_FIELD_TYPE fordblks; /* total free space */
+ MALLINFO_FIELD_TYPE keepcost; /* releasable (via malloc_trim) space */
+};
+#endif /* STRUCT_MALLINFO_DECLARED */
+#endif /* HAVE_USR_INCLUDE_MALLOC_H */
+#endif /* NO_MALLINFO */
+
+/*
+ Try to persuade compilers to inline. The most critical functions for
+ inlining are defined as macros, so these aren't used for them.
+*/
+
+#ifndef FORCEINLINE
+ #if defined(__GNUC__)
+#define FORCEINLINE __inline __attribute__ ((always_inline))
+ #elif defined(_MSC_VER)
+ #define FORCEINLINE __forceinline
+ #endif
+#endif
+#ifndef NOINLINE
+ #if defined(__GNUC__)
+ #define NOINLINE __attribute__ ((noinline))
+ #elif defined(_MSC_VER)
+ #define NOINLINE __declspec(noinline)
+ #else
+ #define NOINLINE
+ #endif
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#ifndef FORCEINLINE
+ #define FORCEINLINE inline
+#endif
+#endif /* __cplusplus */
+#ifndef FORCEINLINE
+ #define FORCEINLINE
+#endif
+
+#if !ONLY_MSPACES
+
+/* ------------------- Declarations of public routines ------------------- */
+
+#ifndef USE_DL_PREFIX
+#define dlcalloc calloc
+#define dlfree free
+#define dlmalloc malloc
+#define dlmemalign memalign
+#define dlrealloc realloc
+#define dlvalloc valloc
+#define dlpvalloc pvalloc
+#define dlmallinfo mallinfo
+#define dlmallopt mallopt
+#define dlmalloc_trim malloc_trim
+#define dlmalloc_stats malloc_stats
+#define dlmalloc_usable_size malloc_usable_size
+#define dlmalloc_footprint malloc_footprint
+#define dlmalloc_max_footprint malloc_max_footprint
+#define dlindependent_calloc independent_calloc
+#define dlindependent_comalloc independent_comalloc
+#endif /* USE_DL_PREFIX */
+
+
+/*
+ malloc(size_t n)
+ Returns a pointer to a newly allocated chunk of at least n bytes, or
+ null if no space is available, in which case errno is set to ENOMEM
+ on ANSI C systems.
+
+ If n is zero, malloc returns a minimum-sized chunk. (The minimum
+ size is 16 bytes on most 32bit systems, and 32 bytes on 64bit
+ systems.) Note that size_t is an unsigned type, so calls with
+ arguments that would be negative if signed are interpreted as
+ requests for huge amounts of space, which will often fail. The
+ maximum supported value of n differs across systems, but is in all
+ cases less than the maximum representable value of a size_t.
+*/
+void* dlmalloc(size_t);
+
+/*
+ free(void* p)
+ Releases the chunk of memory pointed to by p, that had been previously
+ allocated using malloc or a related routine such as realloc.
+ It has no effect if p is null. If p was not malloced or already
+ freed, free(p) will by default cause the current program to abort.
+*/
+void dlfree(void*);
+
+/*
+ calloc(size_t n_elements, size_t element_size);
+ Returns a pointer to n_elements * element_size bytes, with all locations
+ set to zero.
+*/
+void* dlcalloc(size_t, size_t);
+
+/*
+ realloc(void* p, size_t n)
+ Returns a pointer to a chunk of size n that contains the same data
+ as does chunk p up to the minimum of (n, p's size) bytes, or null
+ if no space is available.
+
+ The returned pointer may or may not be the same as p. The algorithm
+ prefers extending p in most cases when possible, otherwise it
+ employs the equivalent of a malloc-copy-free sequence.
+
+ If p is null, realloc is equivalent to malloc.
+
+ If space is not available, realloc returns null, errno is set (if on
+ ANSI) and p is NOT freed.
+
+ if n is for fewer bytes than already held by p, the newly unused
+ space is lopped off and freed if possible. realloc with a size
+ argument of zero (re)allocates a minimum-sized chunk.
+
+ The old unix realloc convention of allowing the last-free'd chunk
+ to be used as an argument to realloc is not supported.
+*/
+
+void* dlrealloc(void*, size_t);
+
+/*
+ memalign(size_t alignment, size_t n);
+ Returns a pointer to a newly allocated chunk of n bytes, aligned
+ in accord with the alignment argument.
+
+ The alignment argument should be a power of two. If the argument is
+ not a power of two, the nearest greater power is used.
+ 8-byte alignment is guaranteed by normal malloc calls, so don't
+ bother calling memalign with an argument of 8 or less.
+
+ Overreliance on memalign is a sure way to fragment space.
+*/
+void* dlmemalign(size_t, size_t);
+
+/*
+ valloc(size_t n);
+ Equivalent to memalign(pagesize, n), where pagesize is the page
+ size of the system. If the pagesize is unknown, 4096 is used.
+*/
+void* dlvalloc(size_t);
+
+/*
+ mallopt(int parameter_number, int parameter_value)
+ Sets tunable parameters The format is to provide a
+ (parameter-number, parameter-value) pair. mallopt then sets the
+ corresponding parameter to the argument value if it can (i.e., so
+ long as the value is meaningful), and returns 1 if successful else
+ 0. To workaround the fact that mallopt is specified to use int,
+ not size_t parameters, the value -1 is specially treated as the
+ maximum unsigned size_t value.
+
+ SVID/XPG/ANSI defines four standard param numbers for mallopt,
+ normally defined in malloc.h. None of these are use in this malloc,
+ so setting them has no effect. But this malloc also supports other
+ options in mallopt. See below for details. Briefly, supported
+ parameters are as follows (listed defaults are for "typical"
+ configurations).
+
+ Symbol param # default allowed param values
+ M_TRIM_THRESHOLD -1 2*1024*1024 any (-1 disables)
+ M_GRANULARITY -2 page size any power of 2 >= page size
+ M_MMAP_THRESHOLD -3 256*1024 any (or 0 if no MMAP support)
+*/
+int dlmallopt(int, int);
+
+/*
+ malloc_footprint();
+ Returns the number of bytes obtained from the system. The total
+ number of bytes allocated by malloc, realloc etc., is less than this
+ value. Unlike mallinfo, this function returns only a precomputed
+ result, so can be called frequently to monitor memory consumption.
+ Even if locks are otherwise defined, this function does not use them,
+ so results might not be up to date.
+*/
+size_t dlmalloc_footprint(void);
+
+/*
+ malloc_max_footprint();
+ Returns the maximum number of bytes obtained from the system. This
+ value will be greater than current footprint if deallocated space
+ has been reclaimed by the system. The peak number of bytes allocated
+ by malloc, realloc etc., is less than this value. Unlike mallinfo,
+ this function returns only a precomputed result, so can be called
+ frequently to monitor memory consumption. Even if locks are
+ otherwise defined, this function does not use them, so results might
+ not be up to date.
+*/
+size_t dlmalloc_max_footprint(void);
+
+#if !NO_MALLINFO
+/*
+ mallinfo()
+ Returns (by copy) a struct containing various summary statistics:
+
+ arena: current total non-mmapped bytes allocated from system
+ ordblks: the number of free chunks
+ smblks: always zero.
+ hblks: current number of mmapped regions
+ hblkhd: total bytes held in mmapped regions
+ usmblks: the maximum total allocated space. This will be greater
+ than current total if trimming has occurred.
+ fsmblks: always zero
+ uordblks: current total allocated space (normal or mmapped)
+ fordblks: total free space
+ keepcost: the maximum number of bytes that could ideally be released
+ back to system via malloc_trim. ("ideally" means that
+ it ignores page restrictions etc.)
+
+ Because these fields are ints, but internal bookkeeping may
+ be kept as longs, the reported values may wrap around zero and
+ thus be inaccurate.
+*/
+struct mallinfo dlmallinfo(void);
+#endif /* NO_MALLINFO */
+
+/*
+ independent_calloc(size_t n_elements, size_t element_size, void* chunks[]);
+
+ independent_calloc is similar to calloc, but instead of returning a
+ single cleared space, it returns an array of pointers to n_elements
+ independent elements that can hold contents of size elem_size, each
+ of which starts out cleared, and can be independently freed,
+ realloc'ed etc. The elements are guaranteed to be adjacently
+ allocated (this is not guaranteed to occur with multiple callocs or
+ mallocs), which may also improve cache locality in some
+ applications.
+
+ The "chunks" argument is optional (i.e., may be null, which is
+ probably the most typical usage). If it is null, the returned array
+ is itself dynamically allocated and should also be freed when it is
+ no longer needed. Otherwise, the chunks array must be of at least
+ n_elements in length. It is filled in with the pointers to the
+ chunks.
+
+ In either case, independent_calloc returns this pointer array, or
+ null if the allocation failed. If n_elements is zero and "chunks"
+ is null, it returns a chunk representing an array with zero elements
+ (which should be freed if not wanted).
+
+ Each element must be individually freed when it is no longer
+ needed. If you'd like to instead be able to free all at once, you
+ should instead use regular calloc and assign pointers into this
+ space to represent elements. (In this case though, you cannot
+ independently free elements.)
+
+ independent_calloc simplifies and speeds up implementations of many
+ kinds of pools. It may also be useful when constructing large data
+ structures that initially have a fixed number of fixed-sized nodes,
+ but the number is not known at compile time, and some of the nodes
+ may later need to be freed. For example:
+
+ struct Node { int item; struct Node* next; };
+
+ struct Node* build_list() {
+ struct Node** pool;
+ int n = read_number_of_nodes_needed();
+ if (n <= 0) return 0;
+ pool = (struct Node**)(independent_calloc(n, sizeof(struct Node), 0);
+ if (pool == 0) die();
+ // organize into a linked list...
+ struct Node* first = pool[0];
+ for (i = 0; i < n-1; ++i)
+ pool[i]->next = pool[i+1];
+ free(pool); // Can now free the array (or not, if it is needed later)
+ return first;
+ }
+*/
+void** dlindependent_calloc(size_t, size_t, void**);
+
+/*
+ independent_comalloc(size_t n_elements, size_t sizes[], void* chunks[]);
+
+ independent_comalloc allocates, all at once, a set of n_elements
+ chunks with sizes indicated in the "sizes" array. It returns
+ an array of pointers to these elements, each of which can be
+ independently freed, realloc'ed etc. The elements are guaranteed to
+ be adjacently allocated (this is not guaranteed to occur with
+ multiple callocs or mallocs), which may also improve cache locality
+ in some applications.
+
+ The "chunks" argument is optional (i.e., may be null). If it is null
+ the returned array is itself dynamically allocated and should also
+ be freed when it is no longer needed. Otherwise, the chunks array
+ must be of at least n_elements in length. It is filled in with the
+ pointers to the chunks.
+
+ In either case, independent_comalloc returns this pointer array, or
+ null if the allocation failed. If n_elements is zero and chunks is
+ null, it returns a chunk representing an array with zero elements
+ (which should be freed if not wanted).
+
+ Each element must be individually freed when it is no longer
+ needed. If you'd like to instead be able to free all at once, you
+ should instead use a single regular malloc, and assign pointers at
+ particular offsets in the aggregate space. (In this case though, you
+ cannot independently free elements.)
+
+ independent_comallac differs from independent_calloc in that each
+ element may have a different size, and also that it does not
+ automatically clear elements.
+
+ independent_comalloc can be used to speed up allocation in cases
+ where several structs or objects must always be allocated at the
+ same time. For example:
+
+ struct Head { ... }
+ struct Foot { ... }
+
+ void send_message(char* msg) {
+ int msglen = strlen(msg);
+ size_t sizes[3] = { sizeof(struct Head), msglen, sizeof(struct Foot) };
+ void* chunks[3];
+ if (independent_comalloc(3, sizes, chunks) == 0)
+ die();
+ struct Head* head = (struct Head*)(chunks[0]);
+ char* body = (char*)(chunks[1]);
+ struct Foot* foot = (struct Foot*)(chunks[2]);
+ // ...
+ }
+
+ In general though, independent_comalloc is worth using only for
+ larger values of n_elements. For small values, you probably won't
+ detect enough difference from series of malloc calls to bother.
+
+ Overuse of independent_comalloc can increase overall memory usage,
+ since it cannot reuse existing noncontiguous small chunks that
+ might be available for some of the elements.
+*/
+void** dlindependent_comalloc(size_t, size_t*, void**);
+
+
+/*
+ pvalloc(size_t n);
+ Equivalent to valloc(minimum-page-that-holds(n)), that is,
+ round up n to nearest pagesize.
+ */
+void* dlpvalloc(size_t);
+
+/*
+ malloc_trim(size_t pad);
+
+ If possible, gives memory back to the system (via negative arguments
+ to sbrk) if there is unused memory at the `high' end of the malloc
+ pool or in unused MMAP segments. You can call this after freeing
+ large blocks of memory to potentially reduce the system-level memory
+ requirements of a program. However, it cannot guarantee to reduce
+ memory. Under some allocation patterns, some large free blocks of
+ memory will be locked between two used chunks, so they cannot be
+ given back to the system.
+
+ The `pad' argument to malloc_trim represents the amount of free
+ trailing space to leave untrimmed. If this argument is zero, only
+ the minimum amount of memory to maintain internal data structures
+ will be left. Non-zero arguments can be supplied to maintain enough
+ trailing space to service future expected allocations without having
+ to re-obtain memory from the system.
+
+ Malloc_trim returns 1 if it actually released any memory, else 0.
+*/
+int dlmalloc_trim(size_t);
+
+/*
+ malloc_stats();
+ Prints on stderr the amount of space obtained from the system (both
+ via sbrk and mmap), the maximum amount (which may be more than
+ current if malloc_trim and/or munmap got called), and the current
+ number of bytes allocated via malloc (or realloc, etc) but not yet
+ freed. Note that this is the number of bytes allocated, not the
+ number requested. It will be larger than the number requested
+ because of alignment and bookkeeping overhead. Because it includes
+ alignment wastage as being in use, this figure may be greater than
+ zero even when no user-level chunks are allocated.
+
+ The reported current and maximum system memory can be inaccurate if
+ a program makes other calls to system memory allocation functions
+ (normally sbrk) outside of malloc.
+
+ malloc_stats prints only the most commonly interesting statistics.
+ More information can be obtained by calling mallinfo.
+*/
+void dlmalloc_stats(void);
+
+#endif /* ONLY_MSPACES */
+
+/*
+ malloc_usable_size(void* p);
+
+ Returns the number of bytes you can actually use in
+ an allocated chunk, which may be more than you requested (although
+ often not) due to alignment and minimum size constraints.
+ You can use this many bytes without worrying about
+ overwriting other allocated objects. This is not a particularly great
+ programming practice. malloc_usable_size can be more useful in
+ debugging and assertions, for example:
+
+ p = malloc(n);
+ assert(malloc_usable_size(p) >= 256);
+*/
+size_t dlmalloc_usable_size(void*);
+
+
+#if MSPACES
+
+/*
+ mspace is an opaque type representing an independent
+ region of space that supports mspace_malloc, etc.
+*/
+typedef void* mspace;
+
+/*
+ create_mspace creates and returns a new independent space with the
+ given initial capacity, or, if 0, the default granularity size. It
+ returns null if there is no system memory available to create the
+ space. If argument locked is non-zero, the space uses a separate
+ lock to control access. The capacity of the space will grow
+ dynamically as needed to service mspace_malloc requests. You can
+ control the sizes of incremental increases of this space by
+ compiling with a different DEFAULT_GRANULARITY or dynamically
+ setting with mallopt(M_GRANULARITY, value).
+*/
+mspace create_mspace(size_t capacity, int locked);
+
+/*
+ destroy_mspace destroys the given space, and attempts to return all
+ of its memory back to the system, returning the total number of
+ bytes freed. After destruction, the results of access to all memory
+ used by the space become undefined.
+*/
+size_t destroy_mspace(mspace msp);
+
+/*
+ create_mspace_with_base uses the memory supplied as the initial base
+ of a new mspace. Part (less than 128*sizeof(size_t) bytes) of this
+ space is used for bookkeeping, so the capacity must be at least this
+ large. (Otherwise 0 is returned.) When this initial space is
+ exhausted, additional memory will be obtained from the system.
+ Destroying this space will deallocate all additionally allocated
+ space (if possible) but not the initial base.
+*/
+mspace create_mspace_with_base(void* base, size_t capacity, int locked);
+
+/*
+ mspace_track_large_chunks controls whether requests for large chunks
+ are allocated in their own untracked mmapped regions, separate from
+ others in this mspace. By default large chunks are not tracked,
+ which reduces fragmentation. However, such chunks are not
+ necessarily released to the system upon destroy_mspace. Enabling
+ tracking by setting to true may increase fragmentation, but avoids
+ leakage when relying on destroy_mspace to release all memory
+ allocated using this space. The function returns the previous
+ setting.
+*/
+int mspace_track_large_chunks(mspace msp, int enable);
+
+
+/*
+ mspace_malloc behaves as malloc, but operates within
+ the given space.
+*/
+void* mspace_malloc(mspace msp, size_t bytes);
+
+/*
+ mspace_free behaves as free, but operates within
+ the given space.
+
+ If compiled with FOOTERS==1, mspace_free is not actually needed.
+ free may be called instead of mspace_free because freed chunks from
+ any space are handled by their originating spaces.
+*/
+void mspace_free(mspace msp, void* mem);
+
+/*
+ mspace_realloc behaves as realloc, but operates within
+ the given space.
+
+ If compiled with FOOTERS==1, mspace_realloc is not actually
+ needed. realloc may be called instead of mspace_realloc because
+ realloced chunks from any space are handled by their originating
+ spaces.
+*/
+void* mspace_realloc(mspace msp, void* mem, size_t newsize);
+
+/*
+ mspace_calloc behaves as calloc, but operates within
+ the given space.
+*/
+void* mspace_calloc(mspace msp, size_t n_elements, size_t elem_size);
+
+/*
+ mspace_memalign behaves as memalign, but operates within
+ the given space.
+*/
+void* mspace_memalign(mspace msp, size_t alignment, size_t bytes);
+
+/*
+ mspace_independent_calloc behaves as independent_calloc, but
+ operates within the given space.
+*/
+void** mspace_independent_calloc(mspace msp, size_t n_elements,
+ size_t elem_size, void* chunks[]);
+
+/*
+ mspace_independent_comalloc behaves as independent_comalloc, but
+ operates within the given space.
+*/
+void** mspace_independent_comalloc(mspace msp, size_t n_elements,
+ size_t sizes[], void* chunks[]);
+
+/*
+ mspace_footprint() returns the number of bytes obtained from the
+ system for this space.
+*/
+size_t mspace_footprint(mspace msp);
+
+/*
+ mspace_max_footprint() returns the peak number of bytes obtained from the
+ system for this space.
+*/
+size_t mspace_max_footprint(mspace msp);
+
+
+#if !NO_MALLINFO
+/*
+ mspace_mallinfo behaves as mallinfo, but reports properties of
+ the given space.
+*/
+struct mallinfo mspace_mallinfo(mspace msp);
+#endif /* NO_MALLINFO */
+
+/*
+ malloc_usable_size(void* p) behaves the same as malloc_usable_size;
+*/
+ size_t mspace_usable_size(void* mem);
+
+/*
+ mspace_malloc_stats behaves as malloc_stats, but reports
+ properties of the given space.
+*/
+void mspace_malloc_stats(mspace msp);
+
+/*
+ mspace_trim behaves as malloc_trim, but
+ operates within the given space.
+*/
+int mspace_trim(mspace msp, size_t pad);
+
+/*
+ An alias for mallopt.
+*/
+int mspace_mallopt(int, int);
+
+#endif /* MSPACES */
+
+#ifdef __cplusplus
+} /* end of extern "C" */
+#endif /* __cplusplus */
+
+/*
+ ========================================================================
+ To make a fully customizable malloc.h header file, cut everything
+ above this line, put into file malloc.h, edit to suit, and #include it
+ on the next line, as well as in programs that use this malloc.
+ ========================================================================
+*/
+
+/* #include "malloc.h" */
+
+/*------------------------------ internal #includes ---------------------- */
+
+#ifdef WIN32
+#pragma warning( disable : 4146 ) /* no "unsigned" warnings */
+#endif /* WIN32 */
+
+#include <stdio.h> /* for printing in malloc_stats */
+
+#ifndef LACKS_ERRNO_H
+#include <errno.h> /* for MALLOC_FAILURE_ACTION */
+#endif /* LACKS_ERRNO_H */
+/*#if FOOTERS || DEBUG
+*/
+#include <time.h> /* for magic initialization */
+/*#endif*/ /* FOOTERS */
+#ifndef LACKS_STDLIB_H
+#include <stdlib.h> /* for abort() */
+#endif /* LACKS_STDLIB_H */
+#ifdef DEBUG
+#if ABORT_ON_ASSERT_FAILURE
+#undef assert
+#define assert(x) if(!(x)) ABORT
+#else /* ABORT_ON_ASSERT_FAILURE */
+#include <assert.h>
+#endif /* ABORT_ON_ASSERT_FAILURE */
+#else /* DEBUG */
+#ifndef assert
+#define assert(x)
+#endif
+#define DEBUG 0
+#endif /* DEBUG */
+#ifndef LACKS_STRING_H
+#include <string.h> /* for memset etc */
+#endif /* LACKS_STRING_H */
+#if USE_BUILTIN_FFS
+#ifndef LACKS_STRINGS_H
+#include <strings.h> /* for ffs */
+#endif /* LACKS_STRINGS_H */
+#endif /* USE_BUILTIN_FFS */
+#if HAVE_MMAP
+#ifndef LACKS_SYS_MMAN_H
+/* On some versions of linux, mremap decl in mman.h needs __USE_GNU set */
+#if (defined(linux) && !defined(__USE_GNU))
+#define __USE_GNU 1
+#include <sys/mman.h> /* for mmap */
+#undef __USE_GNU
+#else
+#include <sys/mman.h> /* for mmap */
+#endif /* linux */
+#endif /* LACKS_SYS_MMAN_H */
+#ifndef LACKS_FCNTL_H
+#include <fcntl.h>
+#endif /* LACKS_FCNTL_H */
+#endif /* HAVE_MMAP */
+#ifndef LACKS_UNISTD_H
+#include <unistd.h> /* for sbrk, sysconf */
+#else /* LACKS_UNISTD_H */
+#if !defined(__FreeBSD__) && !defined(__OpenBSD__) && !defined(__NetBSD__)
+extern void* sbrk(ptrdiff_t);
+#endif /* FreeBSD etc */
+#endif /* LACKS_UNISTD_H */
+
+/* Declarations for locking */
+#if USE_LOCKS
+#ifndef WIN32
+#include <pthread.h>
+#if defined (__SVR4) && defined (__sun) /* solaris */
+#include <thread.h>
+#endif /* solaris */
+#else
+#ifndef _M_AMD64
+/* These are already defined on AMD64 builds */
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+LONG __cdecl _InterlockedCompareExchange(LONG volatile *Dest, LONG Exchange, LONG Comp);
+LONG __cdecl _InterlockedExchange(LONG volatile *Target, LONG Value);
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+#endif /* _M_AMD64 */
+#pragma intrinsic (_InterlockedCompareExchange)
+#pragma intrinsic (_InterlockedExchange)
+#define interlockedcompareexchange _InterlockedCompareExchange
+#define interlockedexchange _InterlockedExchange
+#endif /* Win32 */
+#endif /* USE_LOCKS */
+
+/* Declarations for bit scanning on win32 */
+#if defined(_MSC_VER) && _MSC_VER>=1300
+#ifndef BitScanForward /* Try to avoid pulling in WinNT.h */
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+unsigned char _BitScanForward(unsigned long *index, unsigned long mask);
+unsigned char _BitScanReverse(unsigned long *index, unsigned long mask);
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+#define BitScanForward _BitScanForward
+#define BitScanReverse _BitScanReverse
+#pragma intrinsic(_BitScanForward)
+#pragma intrinsic(_BitScanReverse)
+#endif /* BitScanForward */
+#endif /* defined(_MSC_VER) && _MSC_VER>=1300 */
+
+#ifndef WIN32
+#ifndef malloc_getpagesize
+# ifdef _SC_PAGESIZE /* some SVR4 systems omit an underscore */
+# ifndef _SC_PAGE_SIZE
+# define _SC_PAGE_SIZE _SC_PAGESIZE
+# endif
+# endif
+# ifdef _SC_PAGE_SIZE
+# define malloc_getpagesize sysconf(_SC_PAGE_SIZE)
+# else
+# if defined(BSD) || defined(DGUX) || defined(HAVE_GETPAGESIZE)
+ extern size_t getpagesize();
+# define malloc_getpagesize getpagesize()
+# else
+# ifdef WIN32 /* use supplied emulation of getpagesize */
+# define malloc_getpagesize getpagesize()
+# else
+# ifndef LACKS_SYS_PARAM_H
+# include <sys/param.h>
+# endif
+# ifdef EXEC_PAGESIZE
+# define malloc_getpagesize EXEC_PAGESIZE
+# else
+# ifdef NBPG
+# ifndef CLSIZE
+# define malloc_getpagesize NBPG
+# else
+# define malloc_getpagesize (NBPG * CLSIZE)
+# endif
+# else
+# ifdef NBPC
+# define malloc_getpagesize NBPC
+# else
+# ifdef PAGESIZE
+# define malloc_getpagesize PAGESIZE
+# else /* just guess */
+# define malloc_getpagesize ((size_t)4096U)
+# endif
+# endif
+# endif
+# endif
+# endif
+# endif
+# endif
+#endif
+#endif
+
+
+
+/* ------------------- size_t and alignment properties -------------------- */
+
+/* The byte and bit size of a size_t */
+#define SIZE_T_SIZE (sizeof(size_t))
+#define SIZE_T_BITSIZE (sizeof(size_t) << 3)
+
+/* Some constants coerced to size_t */
+/* Annoying but necessary to avoid errors on some platforms */
+#define SIZE_T_ZERO ((size_t)0)
+#define SIZE_T_ONE ((size_t)1)
+#define SIZE_T_TWO ((size_t)2)
+#define SIZE_T_FOUR ((size_t)4)
+#define TWO_SIZE_T_SIZES (SIZE_T_SIZE<<1)
+#define FOUR_SIZE_T_SIZES (SIZE_T_SIZE<<2)
+#define SIX_SIZE_T_SIZES (FOUR_SIZE_T_SIZES+TWO_SIZE_T_SIZES)
+#define HALF_MAX_SIZE_T (MAX_SIZE_T / 2U)
+
+/* The bit mask value corresponding to MALLOC_ALIGNMENT */
+#define CHUNK_ALIGN_MASK (MALLOC_ALIGNMENT - SIZE_T_ONE)
+
+/* True if address a has acceptable alignment */
+#define is_aligned(A) (((size_t)((A)) & (CHUNK_ALIGN_MASK)) == 0)
+
+/* the number of bytes to offset an address to align it */
+#define align_offset(A)\
+ ((((size_t)(A) & CHUNK_ALIGN_MASK) == 0)? 0 :\
+ ((MALLOC_ALIGNMENT - ((size_t)(A) & CHUNK_ALIGN_MASK)) & CHUNK_ALIGN_MASK))
+
+/* -------------------------- MMAP preliminaries ------------------------- */
+
+/*
+ If HAVE_MORECORE or HAVE_MMAP are false, we just define calls and
+ checks to fail so compiler optimizer can delete code rather than
+ using so many "#if"s.
+*/
+
+
+/* MORECORE and MMAP must return MFAIL on failure */
+#define MFAIL ((void*)(MAX_SIZE_T))
+#define CMFAIL ((char*)(MFAIL)) /* defined for convenience */
+
+#if HAVE_MMAP
+
+#ifndef WIN32
+#define MUNMAP_DEFAULT(a, s) munmap((a), (s))
+#define MMAP_PROT (PROT_READ|PROT_WRITE)
+#if !defined(MAP_ANONYMOUS) && defined(MAP_ANON)
+#define MAP_ANONYMOUS MAP_ANON
+#endif /* MAP_ANON */
+#ifdef MAP_ANONYMOUS
+#define MMAP_FLAGS (MAP_PRIVATE|MAP_ANONYMOUS)
+#define MMAP_DEFAULT(s) mmap(0, (s), MMAP_PROT, MMAP_FLAGS, -1, 0)
+#else /* MAP_ANONYMOUS */
+/*
+ Nearly all versions of mmap support MAP_ANONYMOUS, so the following
+ is unlikely to be needed, but is supplied just in case.
+*/
+#define MMAP_FLAGS (MAP_PRIVATE)
+static int dev_zero_fd = -1; /* Cached file descriptor for /dev/zero. */
+#define MMAP_DEFAULT(s) ((dev_zero_fd < 0) ? \
+ (dev_zero_fd = open("/dev/zero", O_RDWR), \
+ mmap(0, (s), MMAP_PROT, MMAP_FLAGS, dev_zero_fd, 0)) : \
+ mmap(0, (s), MMAP_PROT, MMAP_FLAGS, dev_zero_fd, 0))
+#endif /* MAP_ANONYMOUS */
+
+#define DIRECT_MMAP_DEFAULT(s) MMAP_DEFAULT(s)
+
+#else /* WIN32 */
+
+/* Win32 MMAP via VirtualAlloc */
+static FORCEINLINE void* win32mmap(size_t size) {
+ void* ptr = VirtualAlloc(0, size, MEM_RESERVE|MEM_COMMIT, PAGE_READWRITE);
+ return (ptr != 0)? ptr: MFAIL;
+}
+
+/* For direct MMAP, use MEM_TOP_DOWN to minimize interference */
+static FORCEINLINE void* win32direct_mmap(size_t size) {
+ void* ptr = VirtualAlloc(0, size, MEM_RESERVE|MEM_COMMIT|MEM_TOP_DOWN,
+ PAGE_READWRITE);
+ return (ptr != 0)? ptr: MFAIL;
+}
+
+/* This function supports releasing coalesed segments */
+static FORCEINLINE int win32munmap(void* ptr, size_t size) {
+ MEMORY_BASIC_INFORMATION minfo;
+ char* cptr = (char*)ptr;
+ while (size) {
+ if (VirtualQuery(cptr, &minfo, sizeof(minfo)) == 0)
+ return -1;
+ if (minfo.BaseAddress != cptr || minfo.AllocationBase != cptr ||
+ minfo.State != MEM_COMMIT || minfo.RegionSize > size)
+ return -1;
+ if (VirtualFree(cptr, 0, MEM_RELEASE) == 0)
+ return -1;
+ cptr += minfo.RegionSize;
+ size -= minfo.RegionSize;
+ }
+ return 0;
+}
+
+#define MMAP_DEFAULT(s) win32mmap(s)
+#define MUNMAP_DEFAULT(a, s) win32munmap((a), (s))
+#define DIRECT_MMAP_DEFAULT(s) win32direct_mmap(s)
+#endif /* WIN32 */
+#endif /* HAVE_MMAP */
+
+#if HAVE_MREMAP
+#ifndef WIN32
+#define MREMAP_DEFAULT(addr, osz, nsz, mv) mremap((addr), (osz), (nsz), (mv))
+#endif /* WIN32 */
+#endif /* HAVE_MREMAP */
+
+
+/**
+ * Define CALL_MORECORE
+ */
+#if HAVE_MORECORE
+ #ifdef MORECORE
+ #define CALL_MORECORE(S) MORECORE(S)
+ #else /* MORECORE */
+ #define CALL_MORECORE(S) MORECORE_DEFAULT(S)
+ #endif /* MORECORE */
+#else /* HAVE_MORECORE */
+ #define CALL_MORECORE(S) MFAIL
+#endif /* HAVE_MORECORE */
+
+/**
+ * Define CALL_MMAP/CALL_MUNMAP/CALL_DIRECT_MMAP
+ */
+#if HAVE_MMAP
+ #define USE_MMAP_BIT (SIZE_T_ONE)
+
+ #ifdef MMAP
+ #define CALL_MMAP(s) MMAP(s)
+ #else /* MMAP */
+ #define CALL_MMAP(s) MMAP_DEFAULT(s)
+ #endif /* MMAP */
+ #ifdef MUNMAP
+ #define CALL_MUNMAP(a, s) MUNMAP((a), (s))
+ #else /* MUNMAP */
+ #define CALL_MUNMAP(a, s) MUNMAP_DEFAULT((a), (s))
+ #endif /* MUNMAP */
+ #ifdef DIRECT_MMAP
+ #define CALL_DIRECT_MMAP(s) DIRECT_MMAP(s)
+ #else /* DIRECT_MMAP */
+ #define CALL_DIRECT_MMAP(s) DIRECT_MMAP_DEFAULT(s)
+ #endif /* DIRECT_MMAP */
+#else /* HAVE_MMAP */
+ #define USE_MMAP_BIT (SIZE_T_ZERO)
+
+ #define MMAP(s) MFAIL
+ #define MUNMAP(a, s) (-1)
+ #define DIRECT_MMAP(s) MFAIL
+ #define CALL_DIRECT_MMAP(s) DIRECT_MMAP(s)
+ #define CALL_MMAP(s) MMAP(s)
+ #define CALL_MUNMAP(a, s) MUNMAP((a), (s))
+#endif /* HAVE_MMAP */
+
+/**
+ * Define CALL_MREMAP
+ */
+#if HAVE_MMAP && HAVE_MREMAP
+ #ifdef MREMAP
+ #define CALL_MREMAP(addr, osz, nsz, mv) MREMAP((addr), (osz), (nsz), (mv))
+ #else /* MREMAP */
+ #define CALL_MREMAP(addr, osz, nsz, mv) MREMAP_DEFAULT((addr), (osz), (nsz), (mv))
+ #endif /* MREMAP */
+#else /* HAVE_MMAP && HAVE_MREMAP */
+ #define CALL_MREMAP(addr, osz, nsz, mv) MFAIL
+#endif /* HAVE_MMAP && HAVE_MREMAP */
+
+/* mstate bit set if continguous morecore disabled or failed */
+#define USE_NONCONTIGUOUS_BIT (4U)
+
+/* segment bit set in create_mspace_with_base */
+#define EXTERN_BIT (8U)
+
+
+/* --------------------------- Lock preliminaries ------------------------ */
+
+/*
+ When locks are defined, there is one global lock, plus
+ one per-mspace lock.
+
+ The global lock_ensures that mparams.magic and other unique
+ mparams values are initialized only once. It also protects
+ sequences of calls to MORECORE. In many cases sys_alloc requires
+ two calls, that should not be interleaved with calls by other
+ threads. This does not protect against direct calls to MORECORE
+ by other threads not using this lock, so there is still code to
+ cope the best we can on interference.
+
+ Per-mspace locks surround calls to malloc, free, etc. To enable use
+ in layered extensions, per-mspace locks are reentrant.
+
+ Because lock-protected regions generally have bounded times, it is
+ OK to use the supplied simple spinlocks in the custom versions for
+ x86. Spinlocks are likely to improve performance for lightly
+ contended applications, but worsen performance under heavy
+ contention.
+
+ If USE_LOCKS is > 1, the definitions of lock routines here are
+ bypassed, in which case you will need to define the type MLOCK_T,
+ and at least INITIAL_LOCK, ACQUIRE_LOCK, RELEASE_LOCK and possibly
+ TRY_LOCK (which is not used in this malloc, but commonly needed in
+ extensions.) You must also declare a
+ static MLOCK_T malloc_global_mutex = { initialization values };.
+
+*/
+
+#if USE_LOCKS == 1
+
+#if USE_SPIN_LOCKS && SPIN_LOCKS_AVAILABLE
+#ifndef WIN32
+
+/* Custom pthread-style spin locks on x86 and x64 for gcc */
+struct pthread_mlock_t {
+ volatile unsigned int l;
+ unsigned int c;
+ pthread_t threadid;
+};
+#define MLOCK_T struct pthread_mlock_t
+#define CURRENT_THREAD pthread_self()
+#define INITIAL_LOCK(sl) ((sl)->threadid = 0, (sl)->l = (sl)->c = 0, 0)
+#define ACQUIRE_LOCK(sl) pthread_acquire_lock(sl)
+#define RELEASE_LOCK(sl) pthread_release_lock(sl)
+#define TRY_LOCK(sl) pthread_try_lock(sl)
+#define SPINS_PER_YIELD 63
+
+static MLOCK_T malloc_global_mutex = { 0, 0, 0};
+
+static FORCEINLINE int pthread_acquire_lock (MLOCK_T *sl) {
+ int spins = 0;
+ volatile unsigned int* lp = &sl->l;
+ for (;;) {
+ if (*lp != 0) {
+ if (sl->threadid == CURRENT_THREAD) {
+ ++sl->c;
+ return 0;
+ }
+ }
+ else {
+ /* place args to cmpxchgl in locals to evade oddities in some gccs */
+ int cmp = 0;
+ int val = 1;
+ int ret;
+ __asm__ __volatile__ ("lock; cmpxchgl %1, %2"
+ : "=a" (ret)
+ : "r" (val), "m" (*(lp)), "0"(cmp)
+ : "memory", "cc");
+ if (!ret) {
+ assert(!sl->threadid);
+ sl->threadid = CURRENT_THREAD;
+ sl->c = 1;
+ return 0;
+ }
+ }
+ if ((++spins & SPINS_PER_YIELD) == 0) {
+#if defined (__SVR4) && defined (__sun) /* solaris */
+ thr_yield();
+#else
+#if defined(__linux__) || defined(__FreeBSD__) || defined(__APPLE__)
+ sched_yield();
+#else /* no-op yield on unknown systems */
+ ;
+#endif /* __linux__ || __FreeBSD__ || __APPLE__ */
+#endif /* solaris */
+ }
+ }
+}
+
+static FORCEINLINE void pthread_release_lock (MLOCK_T *sl) {
+ volatile unsigned int* lp = &sl->l;
+ assert(*lp != 0);
+ assert(sl->threadid == CURRENT_THREAD);
+ if (--sl->c == 0) {
+ sl->threadid = 0;
+ int prev = 0;
+ int ret;
+ __asm__ __volatile__ ("lock; xchgl %0, %1"
+ : "=r" (ret)
+ : "m" (*(lp)), "0"(prev)
+ : "memory");
+ }
+}
+
+static FORCEINLINE int pthread_try_lock (MLOCK_T *sl) {
+ volatile unsigned int* lp = &sl->l;
+ if (*lp != 0) {
+ if (sl->threadid == CURRENT_THREAD) {
+ ++sl->c;
+ return 1;
+ }
+ }
+ else {
+ int cmp = 0;
+ int val = 1;
+ int ret;
+ __asm__ __volatile__ ("lock; cmpxchgl %1, %2"
+ : "=a" (ret)
+ : "r" (val), "m" (*(lp)), "0"(cmp)
+ : "memory", "cc");
+ if (!ret) {
+ assert(!sl->threadid);
+ sl->threadid = CURRENT_THREAD;
+ sl->c = 1;
+ return 1;
+ }
+ }
+ return 0;
+}
+
+
+#else /* WIN32 */
+/* Custom win32-style spin locks on x86 and x64 for MSC */
+struct win32_mlock_t {
+ volatile long l;
+ unsigned int c;
+ long threadid;
+};
+
+#define MLOCK_T struct win32_mlock_t
+#define CURRENT_THREAD GetCurrentThreadId()
+#define INITIAL_LOCK(sl) ((sl)->threadid = 0, (sl)->l = (sl)->c = 0, 0)
+#define ACQUIRE_LOCK(sl) win32_acquire_lock(sl)
+#define RELEASE_LOCK(sl) win32_release_lock(sl)
+#define TRY_LOCK(sl) win32_try_lock(sl)
+#define SPINS_PER_YIELD 63
+
+static MLOCK_T malloc_global_mutex = { 0, 0, 0};
+
+static FORCEINLINE int win32_acquire_lock (MLOCK_T *sl) {
+ int spins = 0;
+ for (;;) {
+ if (sl->l != 0) {
+ if (sl->threadid == CURRENT_THREAD) {
+ ++sl->c;
+ return 0;
+ }
+ }
+ else {
+ if (!interlockedexchange(&sl->l, 1)) {
+ assert(!sl->threadid);
+ sl->threadid = CURRENT_THREAD;
+ sl->c = 1;
+ return 0;
+ }
+ }
+ if ((++spins & SPINS_PER_YIELD) == 0)
+ SleepEx(0, FALSE);
+ }
+}
+
+static FORCEINLINE void win32_release_lock (MLOCK_T *sl) {
+ assert(sl->threadid == CURRENT_THREAD);
+ assert(sl->l != 0);
+ if (--sl->c == 0) {
+ sl->threadid = 0;
+ interlockedexchange (&sl->l, 0);
+ }
+}
+
+static FORCEINLINE int win32_try_lock (MLOCK_T *sl) {
+ if (sl->l != 0) {
+ if (sl->threadid == CURRENT_THREAD) {
+ ++sl->c;
+ return 1;
+ }
+ }
+ else {
+ if (!interlockedexchange(&sl->l, 1)){
+ assert(!sl->threadid);
+ sl->threadid = CURRENT_THREAD;
+ sl->c = 1;
+ return 1;
+ }
+ }
+ return 0;
+}
+
+#endif /* WIN32 */
+#else /* USE_SPIN_LOCKS */
+
+#ifndef WIN32
+/* pthreads-based locks */
+
+#define MLOCK_T pthread_mutex_t
+#define CURRENT_THREAD pthread_self()
+#define INITIAL_LOCK(sl) pthread_init_lock(sl)
+#define ACQUIRE_LOCK(sl) pthread_mutex_lock(sl)
+#define RELEASE_LOCK(sl) pthread_mutex_unlock(sl)
+#define TRY_LOCK(sl) (!pthread_mutex_trylock(sl))
+
+static MLOCK_T malloc_global_mutex = PTHREAD_MUTEX_INITIALIZER;
+
+/* Cope with old-style linux recursive lock initialization by adding */
+/* skipped internal declaration from pthread.h */
+#ifdef linux
+#ifndef PTHREAD_MUTEX_RECURSIVE
+extern int pthread_mutexattr_setkind_np __P ((pthread_mutexattr_t *__attr,
+ int __kind));
+#define PTHREAD_MUTEX_RECURSIVE PTHREAD_MUTEX_RECURSIVE_NP
+#define pthread_mutexattr_settype(x,y) pthread_mutexattr_setkind_np(x,y)
+#endif
+#endif
+
+static int pthread_init_lock (MLOCK_T *sl) {
+ pthread_mutexattr_t attr;
+ if (pthread_mutexattr_init(&attr)) return 1;
+ if (pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE)) return 1;
+ if (pthread_mutex_init(sl, &attr)) return 1;
+ if (pthread_mutexattr_destroy(&attr)) return 1;
+ return 0;
+}
+
+#else /* WIN32 */
+/* Win32 critical sections */
+#define MLOCK_T CRITICAL_SECTION
+#define CURRENT_THREAD GetCurrentThreadId()
+#define INITIAL_LOCK(s) (!InitializeCriticalSectionAndSpinCount((s), 0x80000000|4000))
+#define ACQUIRE_LOCK(s) (EnterCriticalSection(sl), 0)
+#define RELEASE_LOCK(s) LeaveCriticalSection(sl)
+#define TRY_LOCK(s) TryEnterCriticalSection(sl)
+#define NEED_GLOBAL_LOCK_INIT
+
+static MLOCK_T malloc_global_mutex;
+static volatile long malloc_global_mutex_status;
+
+/* Use spin loop to initialize global lock */
+static void init_malloc_global_mutex() {
+ for (;;) {
+ long stat = malloc_global_mutex_status;
+ if (stat > 0)
+ return;
+ /* transition to < 0 while initializing, then to > 0) */
+ if (stat == 0 &&
+ interlockedcompareexchange(&malloc_global_mutex_status, -1, 0) == 0) {
+ InitializeCriticalSection(&malloc_global_mutex);
+ interlockedexchange(&malloc_global_mutex_status,1);
+ return;
+ }
+ SleepEx(0, FALSE);
+ }
+}
+
+#endif /* WIN32 */
+#endif /* USE_SPIN_LOCKS */
+#endif /* USE_LOCKS == 1 */
+
+/* ----------------------- User-defined locks ------------------------ */
+
+#if USE_LOCKS > 1
+/* Define your own lock implementation here */
+/* #define INITIAL_LOCK(sl) ... */
+/* #define ACQUIRE_LOCK(sl) ... */
+/* #define RELEASE_LOCK(sl) ... */
+/* #define TRY_LOCK(sl) ... */
+/* static MLOCK_T malloc_global_mutex = ... */
+#endif /* USE_LOCKS > 1 */
+
+/* ----------------------- Lock-based state ------------------------ */
+
+#if USE_LOCKS
+#define USE_LOCK_BIT (2U)
+#else /* USE_LOCKS */
+#define USE_LOCK_BIT (0U)
+#define INITIAL_LOCK(l)
+#endif /* USE_LOCKS */
+
+#if USE_LOCKS
+#ifndef ACQUIRE_MALLOC_GLOBAL_LOCK
+#define ACQUIRE_MALLOC_GLOBAL_LOCK() ACQUIRE_LOCK(&malloc_global_mutex);
+#endif
+#ifndef RELEASE_MALLOC_GLOBAL_LOCK
+#define RELEASE_MALLOC_GLOBAL_LOCK() RELEASE_LOCK(&malloc_global_mutex);
+#endif
+#else /* USE_LOCKS */
+#define ACQUIRE_MALLOC_GLOBAL_LOCK()
+#define RELEASE_MALLOC_GLOBAL_LOCK()
+#endif /* USE_LOCKS */
+
+
+/* ----------------------- Chunk representations ------------------------ */
+
+/*
+ (The following includes lightly edited explanations by Colin Plumb.)
+
+ The malloc_chunk declaration below is misleading (but accurate and
+ necessary). It declares a "view" into memory allowing access to
+ necessary fields at known offsets from a given base.
+
+ Chunks of memory are maintained using a `boundary tag' method as
+ originally described by Knuth. (See the paper by Paul Wilson
+ ftp://ftp.cs.utexas.edu/pub/garbage/allocsrv.ps for a survey of such
+ techniques.) Sizes of free chunks are stored both in the front of
+ each chunk and at the end. This makes consolidating fragmented
+ chunks into bigger chunks fast. The head fields also hold bits
+ representing whether chunks are free or in use.
+
+ Here are some pictures to make it clearer. They are "exploded" to
+ show that the state of a chunk can be thought of as extending from
+ the high 31 bits of the head field of its header through the
+ prev_foot and PINUSE_BIT bit of the following chunk header.
+
+ A chunk that's in use looks like:
+
+ chunk-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | Size of previous chunk (if P = 0) |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |P|
+ | Size of this chunk 1| +-+
+ mem-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | |
+ +- -+
+ | |
+ +- -+
+ | :
+ +- size - sizeof(size_t) available payload bytes -+
+ : |
+ chunk-> +- -+
+ | |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |1|
+ | Size of next chunk (may or may not be in use) | +-+
+ mem-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+
+ And if it's free, it looks like this:
+
+ chunk-> +- -+
+ | User payload (must be in use, or we would have merged!) |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |P|
+ | Size of this chunk 0| +-+
+ mem-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | Next pointer |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | Prev pointer |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | :
+ +- size - sizeof(struct chunk) unused bytes -+
+ : |
+ chunk-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | Size of this chunk |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |0|
+ | Size of next chunk (must be in use, or we would have merged)| +-+
+ mem-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | :
+ +- User payload -+
+ : |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ |0|
+ +-+
+ Note that since we always merge adjacent free chunks, the chunks
+ adjacent to a free chunk must be in use.
+
+ Given a pointer to a chunk (which can be derived trivially from the
+ payload pointer) we can, in O(1) time, find out whether the adjacent
+ chunks are free, and if so, unlink them from the lists that they
+ are on and merge them with the current chunk.
+
+ Chunks always begin on even word boundaries, so the mem portion
+ (which is returned to the user) is also on an even word boundary, and
+ thus at least double-word aligned.
+
+ The P (PINUSE_BIT) bit, stored in the unused low-order bit of the
+ chunk size (which is always a multiple of two words), is an in-use
+ bit for the *previous* chunk. If that bit is *clear*, then the
+ word before the current chunk size contains the previous chunk
+ size, and can be used to find the front of the previous chunk.
+ The very first chunk allocated always has this bit set, preventing
+ access to non-existent (or non-owned) memory. If pinuse is set for
+ any given chunk, then you CANNOT determine the size of the
+ previous chunk, and might even get a memory addressing fault when
+ trying to do so.
+
+ The C (CINUSE_BIT) bit, stored in the unused second-lowest bit of
+ the chunk size redundantly records whether the current chunk is
+ inuse (unless the chunk is mmapped). This redundancy enables usage
+ checks within free and realloc, and reduces indirection when freeing
+ and consolidating chunks.
+
+ Each freshly allocated chunk must have both cinuse and pinuse set.
+ That is, each allocated chunk borders either a previously allocated
+ and still in-use chunk, or the base of its memory arena. This is
+ ensured by making all allocations from the the `lowest' part of any
+ found chunk. Further, no free chunk physically borders another one,
+ so each free chunk is known to be preceded and followed by either
+ inuse chunks or the ends of memory.
+
+ Note that the `foot' of the current chunk is actually represented
+ as the prev_foot of the NEXT chunk. This makes it easier to
+ deal with alignments etc but can be very confusing when trying
+ to extend or adapt this code.
+
+ The exceptions to all this are
+
+ 1. The special chunk `top' is the top-most available chunk (i.e.,
+ the one bordering the end of available memory). It is treated
+ specially. Top is never included in any bin, is used only if
+ no other chunk is available, and is released back to the
+ system if it is very large (see M_TRIM_THRESHOLD). In effect,
+ the top chunk is treated as larger (and thus less well
+ fitting) than any other available chunk. The top chunk
+ doesn't update its trailing size field since there is no next
+ contiguous chunk that would have to index off it. However,
+ space is still allocated for it (TOP_FOOT_SIZE) to enable
+ separation or merging when space is extended.
+
+ 3. Chunks allocated via mmap, have both cinuse and pinuse bits
+ cleared in their head fields. Because they are allocated
+ one-by-one, each must carry its own prev_foot field, which is
+ also used to hold the offset this chunk has within its mmapped
+ region, which is needed to preserve alignment. Each mmapped
+ chunk is trailed by the first two fields of a fake next-chunk
+ for sake of usage checks.
+
+*/
+
+struct malloc_chunk {
+ size_t prev_foot; /* Size of previous chunk (if free). */
+ size_t head; /* Size and inuse bits. */
+ struct malloc_chunk* fd; /* double links -- used only if free. */
+ struct malloc_chunk* bk;
+};
+
+typedef struct malloc_chunk mchunk;
+typedef struct malloc_chunk* mchunkptr;
+typedef struct malloc_chunk* sbinptr; /* The type of bins of chunks */
+typedef unsigned int bindex_t; /* Described below */
+typedef unsigned int binmap_t; /* Described below */
+typedef unsigned int flag_t; /* The type of various bit flag sets */
+
+/* ------------------- Chunks sizes and alignments ----------------------- */
+
+#define MCHUNK_SIZE (sizeof(mchunk))
+
+#if FOOTERS
+#define CHUNK_OVERHEAD (TWO_SIZE_T_SIZES)
+#else /* FOOTERS */
+#define CHUNK_OVERHEAD (SIZE_T_SIZE)
+#endif /* FOOTERS */
+
+/* MMapped chunks need a second word of overhead ... */
+#define MMAP_CHUNK_OVERHEAD (TWO_SIZE_T_SIZES)
+/* ... and additional padding for fake next-chunk at foot */
+#define MMAP_FOOT_PAD (FOUR_SIZE_T_SIZES)
+
+/* The smallest size we can malloc is an aligned minimal chunk */
+#define MIN_CHUNK_SIZE\
+ ((MCHUNK_SIZE + CHUNK_ALIGN_MASK) & ~CHUNK_ALIGN_MASK)
+
+/* conversion from malloc headers to user pointers, and back */
+#define chunk2mem(p) ((void*)((char*)(p) + TWO_SIZE_T_SIZES))
+#define mem2chunk(mem) ((mchunkptr)((char*)(mem) - TWO_SIZE_T_SIZES))
+/* chunk associated with aligned address A */
+#define align_as_chunk(A) (mchunkptr)((A) + align_offset(chunk2mem(A)))
+
+/* Bounds on request (not chunk) sizes. */
+#define MAX_REQUEST ((-MIN_CHUNK_SIZE) << 2)
+#define MIN_REQUEST (MIN_CHUNK_SIZE - CHUNK_OVERHEAD - SIZE_T_ONE)
+
+/* pad request bytes into a usable size */
+#define pad_request(req) \
+ (((req) + CHUNK_OVERHEAD + CHUNK_ALIGN_MASK) & ~CHUNK_ALIGN_MASK)
+
+/* pad request, checking for minimum (but not maximum) */
+#define request2size(req) \
+ (((req) < MIN_REQUEST)? MIN_CHUNK_SIZE : pad_request(req))
+
+
+/* ------------------ Operations on head and foot fields ----------------- */
+
+/*
+ The head field of a chunk is or'ed with PINUSE_BIT when previous
+ adjacent chunk in use, and or'ed with CINUSE_BIT if this chunk is in
+ use, unless mmapped, in which case both bits are cleared.
+
+ FLAG4_BIT is not used by this malloc, but might be useful in extensions.
+*/
+
+#define PINUSE_BIT (SIZE_T_ONE)
+#define CINUSE_BIT (SIZE_T_TWO)
+#define FLAG4_BIT (SIZE_T_FOUR)
+#define INUSE_BITS (PINUSE_BIT|CINUSE_BIT)
+#define FLAG_BITS (PINUSE_BIT|CINUSE_BIT|FLAG4_BIT)
+
+/* Head value for fenceposts */
+#define FENCEPOST_HEAD (INUSE_BITS|SIZE_T_SIZE)
+
+/* extraction of fields from head words */
+#define cinuse(p) ((p)->head & CINUSE_BIT)
+#define pinuse(p) ((p)->head & PINUSE_BIT)
+#define is_inuse(p) (((p)->head & INUSE_BITS) != PINUSE_BIT)
+#define is_mmapped(p) (((p)->head & INUSE_BITS) == 0)
+
+#define chunksize(p) ((p)->head & ~(FLAG_BITS))
+
+#define clear_pinuse(p) ((p)->head &= ~PINUSE_BIT)
+
+/* Treat space at ptr +/- offset as a chunk */
+#define chunk_plus_offset(p, s) ((mchunkptr)(((char*)(p)) + (s)))
+#define chunk_minus_offset(p, s) ((mchunkptr)(((char*)(p)) - (s)))
+
+/* Ptr to next or previous physical malloc_chunk. */
+#define next_chunk(p) ((mchunkptr)( ((char*)(p)) + ((p)->head & ~FLAG_BITS)))
+#define prev_chunk(p) ((mchunkptr)( ((char*)(p)) - ((p)->prev_foot) ))
+
+/* extract next chunk's pinuse bit */
+#define next_pinuse(p) ((next_chunk(p)->head) & PINUSE_BIT)
+
+/* Get/set size at footer */
+#define get_foot(p, s) (((mchunkptr)((char*)(p) + (s)))->prev_foot)
+#define set_foot(p, s) (((mchunkptr)((char*)(p) + (s)))->prev_foot = (s))
+
+/* Set size, pinuse bit, and foot */
+#define set_size_and_pinuse_of_free_chunk(p, s)\
+ ((p)->head = (s|PINUSE_BIT), set_foot(p, s))
+
+/* Set size, pinuse bit, foot, and clear next pinuse */
+#define set_free_with_pinuse(p, s, n)\
+ (clear_pinuse(n), set_size_and_pinuse_of_free_chunk(p, s))
+
+/* Get the internal overhead associated with chunk p */
+#define overhead_for(p)\
+ (is_mmapped(p)? MMAP_CHUNK_OVERHEAD : CHUNK_OVERHEAD)
+
+/* Return true if malloced space is not necessarily cleared */
+#if MMAP_CLEARS
+#define calloc_must_clear(p) (!is_mmapped(p))
+#else /* MMAP_CLEARS */
+#define calloc_must_clear(p) (1)
+#endif /* MMAP_CLEARS */
+
+/* ---------------------- Overlaid data structures ----------------------- */
+
+/*
+ When chunks are not in use, they are treated as nodes of either
+ lists or trees.
+
+ "Small" chunks are stored in circular doubly-linked lists, and look
+ like this:
+
+ chunk-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | Size of previous chunk |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ `head:' | Size of chunk, in bytes |P|
+ mem-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | Forward pointer to next chunk in list |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | Back pointer to previous chunk in list |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | Unused space (may be 0 bytes long) .
+ . .
+ . |
+nextchunk-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ `foot:' | Size of chunk, in bytes |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+
+ Larger chunks are kept in a form of bitwise digital trees (aka
+ tries) keyed on chunksizes. Because malloc_tree_chunks are only for
+ free chunks greater than 256 bytes, their size doesn't impose any
+ constraints on user chunk sizes. Each node looks like:
+
+ chunk-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | Size of previous chunk |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ `head:' | Size of chunk, in bytes |P|
+ mem-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | Forward pointer to next chunk of same size |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | Back pointer to previous chunk of same size |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | Pointer to left child (child[0]) |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | Pointer to right child (child[1]) |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | Pointer to parent |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | bin index of this chunk |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | Unused space .
+ . |
+nextchunk-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ `foot:' | Size of chunk, in bytes |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+
+ Each tree holding treenodes is a tree of unique chunk sizes. Chunks
+ of the same size are arranged in a circularly-linked list, with only
+ the oldest chunk (the next to be used, in our FIFO ordering)
+ actually in the tree. (Tree members are distinguished by a non-null
+ parent pointer.) If a chunk with the same size an an existing node
+ is inserted, it is linked off the existing node using pointers that
+ work in the same way as fd/bk pointers of small chunks.
+
+ Each tree contains a power of 2 sized range of chunk sizes (the
+ smallest is 0x100 <= x < 0x180), which is is divided in half at each
+ tree level, with the chunks in the smaller half of the range (0x100
+ <= x < 0x140 for the top nose) in the left subtree and the larger
+ half (0x140 <= x < 0x180) in the right subtree. This is, of course,
+ done by inspecting individual bits.
+
+ Using these rules, each node's left subtree contains all smaller
+ sizes than its right subtree. However, the node at the root of each
+ subtree has no particular ordering relationship to either. (The
+ dividing line between the subtree sizes is based on trie relation.)
+ If we remove the last chunk of a given size from the interior of the
+ tree, we need to replace it with a leaf node. The tree ordering
+ rules permit a node to be replaced by any leaf below it.
+
+ The smallest chunk in a tree (a common operation in a best-fit
+ allocator) can be found by walking a path to the leftmost leaf in
+ the tree. Unlike a usual binary tree, where we follow left child
+ pointers until we reach a null, here we follow the right child
+ pointer any time the left one is null, until we reach a leaf with
+ both child pointers null. The smallest chunk in the tree will be
+ somewhere along that path.
+
+ The worst case number of steps to add, find, or remove a node is
+ bounded by the number of bits differentiating chunks within
+ bins. Under current bin calculations, this ranges from 6 up to 21
+ (for 32 bit sizes) or up to 53 (for 64 bit sizes). The typical case
+ is of course much better.
+*/
+
+struct malloc_tree_chunk {
+ /* The first four fields must be compatible with malloc_chunk */
+ size_t prev_foot;
+ size_t head;
+ struct malloc_tree_chunk* fd;
+ struct malloc_tree_chunk* bk;
+
+ struct malloc_tree_chunk* child[2];
+ struct malloc_tree_chunk* parent;
+ bindex_t index;
+};
+
+typedef struct malloc_tree_chunk tchunk;
+typedef struct malloc_tree_chunk* tchunkptr;
+typedef struct malloc_tree_chunk* tbinptr; /* The type of bins of trees */
+
+/* A little helper macro for trees */
+#define leftmost_child(t) ((t)->child[0] != 0? (t)->child[0] : (t)->child[1])
+
+/* ----------------------------- Segments -------------------------------- */
+
+/*
+ Each malloc space may include non-contiguous segments, held in a
+ list headed by an embedded malloc_segment record representing the
+ top-most space. Segments also include flags holding properties of
+ the space. Large chunks that are directly allocated by mmap are not
+ included in this list. They are instead independently created and
+ destroyed without otherwise keeping track of them.
+
+ Segment management mainly comes into play for spaces allocated by
+ MMAP. Any call to MMAP might or might not return memory that is
+ adjacent to an existing segment. MORECORE normally contiguously
+ extends the current space, so this space is almost always adjacent,
+ which is simpler and faster to deal with. (This is why MORECORE is
+ used preferentially to MMAP when both are available -- see
+ sys_alloc.) When allocating using MMAP, we don't use any of the
+ hinting mechanisms (inconsistently) supported in various
+ implementations of unix mmap, or distinguish reserving from
+ committing memory. Instead, we just ask for space, and exploit
+ contiguity when we get it. It is probably possible to do
+ better than this on some systems, but no general scheme seems
+ to be significantly better.
+
+ Management entails a simpler variant of the consolidation scheme
+ used for chunks to reduce fragmentation -- new adjacent memory is
+ normally prepended or appended to an existing segment. However,
+ there are limitations compared to chunk consolidation that mostly
+ reflect the fact that segment processing is relatively infrequent
+ (occurring only when getting memory from system) and that we
+ don't expect to have huge numbers of segments:
+
+ * Segments are not indexed, so traversal requires linear scans. (It
+ would be possible to index these, but is not worth the extra
+ overhead and complexity for most programs on most platforms.)
+ * New segments are only appended to old ones when holding top-most
+ memory; if they cannot be prepended to others, they are held in
+ different segments.
+
+ Except for the top-most segment of an mstate, each segment record
+ is kept at the tail of its segment. Segments are added by pushing
+ segment records onto the list headed by &mstate.seg for the
+ containing mstate.
+
+ Segment flags control allocation/merge/deallocation policies:
+ * If EXTERN_BIT set, then we did not allocate this segment,
+ and so should not try to deallocate or merge with others.
+ (This currently holds only for the initial segment passed
+ into create_mspace_with_base.)
+ * If USE_MMAP_BIT set, the segment may be merged with
+ other surrounding mmapped segments and trimmed/de-allocated
+ using munmap.
+ * If neither bit is set, then the segment was obtained using
+ MORECORE so can be merged with surrounding MORECORE'd segments
+ and deallocated/trimmed using MORECORE with negative arguments.
+*/
+
+struct malloc_segment {
+ char* base; /* base address */
+ size_t size; /* allocated size */
+ struct malloc_segment* next; /* ptr to next segment */
+ flag_t sflags; /* mmap and extern flag */
+};
+
+#define is_mmapped_segment(S) ((S)->sflags & USE_MMAP_BIT)
+#define is_extern_segment(S) ((S)->sflags & EXTERN_BIT)
+
+typedef struct malloc_segment msegment;
+typedef struct malloc_segment* msegmentptr;
+
+/* ---------------------------- malloc_state ----------------------------- */
+
+/*
+ A malloc_state holds all of the bookkeeping for a space.
+ The main fields are:
+
+ Top
+ The topmost chunk of the currently active segment. Its size is
+ cached in topsize. The actual size of topmost space is
+ topsize+TOP_FOOT_SIZE, which includes space reserved for adding
+ fenceposts and segment records if necessary when getting more
+ space from the system. The size at which to autotrim top is
+ cached from mparams in trim_check, except that it is disabled if
+ an autotrim fails.
+
+ Designated victim (dv)
+ This is the preferred chunk for servicing small requests that
+ don't have exact fits. It is normally the chunk split off most
+ recently to service another small request. Its size is cached in
+ dvsize. The link fields of this chunk are not maintained since it
+ is not kept in a bin.
+
+ SmallBins
+ An array of bin headers for free chunks. These bins hold chunks
+ with sizes less than MIN_LARGE_SIZE bytes. Each bin contains
+ chunks of all the same size, spaced 8 bytes apart. To simplify
+ use in double-linked lists, each bin header acts as a malloc_chunk
+ pointing to the real first node, if it exists (else pointing to
+ itself). This avoids special-casing for headers. But to avoid
+ waste, we allocate only the fd/bk pointers of bins, and then use
+ repositioning tricks to treat these as the fields of a chunk.
+
+ TreeBins
+ Treebins are pointers to the roots of trees holding a range of
+ sizes. There are 2 equally spaced treebins for each power of two
+ from TREE_SHIFT to TREE_SHIFT+16. The last bin holds anything
+ larger.
+
+ Bin maps
+ There is one bit map for small bins ("smallmap") and one for
+ treebins ("treemap). Each bin sets its bit when non-empty, and
+ clears the bit when empty. Bit operations are then used to avoid
+ bin-by-bin searching -- nearly all "search" is done without ever
+ looking at bins that won't be selected. The bit maps
+ conservatively use 32 bits per map word, even if on 64bit system.
+ For a good description of some of the bit-based techniques used
+ here, see Henry S. Warren Jr's book "Hacker's Delight" (and
+ supplement at http://hackersdelight.org/). Many of these are
+ intended to reduce the branchiness of paths through malloc etc, as
+ well as to reduce the number of memory locations read or written.
+
+ Segments
+ A list of segments headed by an embedded malloc_segment record
+ representing the initial space.
+
+ Address check support
+ The least_addr field is the least address ever obtained from
+ MORECORE or MMAP. Attempted frees and reallocs of any address less
+ than this are trapped (unless INSECURE is defined).
+
+ Magic tag
+ A cross-check field that should always hold same value as mparams.magic.
+
+ Flags
+ Bits recording whether to use MMAP, locks, or contiguous MORECORE
+
+ Statistics
+ Each space keeps track of current and maximum system memory
+ obtained via MORECORE or MMAP.
+
+ Trim support
+ Fields holding the amount of unused topmost memory that should trigger
+ timming, and a counter to force periodic scanning to release unused
+ non-topmost segments.
+
+ Locking
+ If USE_LOCKS is defined, the "mutex" lock is acquired and released
+ around every public call using this mspace.
+
+ Extension support
+ A void* pointer and a size_t field that can be used to help implement
+ extensions to this malloc.
+*/
+
+/* Bin types, widths and sizes */
+#define NSMALLBINS (32U)
+#define NTREEBINS (32U)
+#define SMALLBIN_SHIFT (3U)
+#define SMALLBIN_WIDTH (SIZE_T_ONE << SMALLBIN_SHIFT)
+#define TREEBIN_SHIFT (8U)
+#define MIN_LARGE_SIZE (SIZE_T_ONE << TREEBIN_SHIFT)
+#define MAX_SMALL_SIZE (MIN_LARGE_SIZE - SIZE_T_ONE)
+#define MAX_SMALL_REQUEST (MAX_SMALL_SIZE - CHUNK_ALIGN_MASK - CHUNK_OVERHEAD)
+
+struct malloc_state {
+ binmap_t smallmap;
+ binmap_t treemap;
+ size_t dvsize;
+ size_t topsize;
+ char* least_addr;
+ mchunkptr dv;
+ mchunkptr top;
+ size_t trim_check;
+ size_t release_checks;
+ size_t magic;
+ mchunkptr smallbins[(NSMALLBINS+1)*2];
+ tbinptr treebins[NTREEBINS];
+ size_t footprint;
+ size_t max_footprint;
+ flag_t mflags;
+#if USE_LOCKS
+ MLOCK_T mutex; /* locate lock among fields that rarely change */
+#endif /* USE_LOCKS */
+ msegment seg;
+ void* extp; /* Unused but available for extensions */
+ size_t exts;
+};
+
+typedef struct malloc_state* mstate;
+
+/* ------------- Global malloc_state and malloc_params ------------------- */
+
+/*
+ malloc_params holds global properties, including those that can be
+ dynamically set using mallopt. There is a single instance, mparams,
+ initialized in init_mparams. Note that the non-zeroness of "magic"
+ also serves as an initialization flag.
+*/
+
+struct malloc_params {
+ volatile size_t magic;
+ size_t page_size;
+ size_t granularity;
+ size_t mmap_threshold;
+ size_t trim_threshold;
+ flag_t default_mflags;
+};
+
+static struct malloc_params mparams;
+
+/* Ensure mparams initialized */
+#define ensure_initialization() (void)(mparams.magic != 0 || init_mparams())
+
+#if !ONLY_MSPACES
+
+/* The global malloc_state used for all non-"mspace" calls */
+static struct malloc_state _gm_;
+#define gm (&_gm_)
+#define is_global(M) ((M) == &_gm_)
+
+#endif /* !ONLY_MSPACES */
+
+#define is_initialized(M) ((M)->top != 0)
+
+/* -------------------------- system alloc setup ------------------------- */
+
+/* Operations on mflags */
+
+#define use_lock(M) ((M)->mflags & USE_LOCK_BIT)
+#define enable_lock(M) ((M)->mflags |= USE_LOCK_BIT)
+#define disable_lock(M) ((M)->mflags &= ~USE_LOCK_BIT)
+
+#define use_mmap(M) ((M)->mflags & USE_MMAP_BIT)
+#define enable_mmap(M) ((M)->mflags |= USE_MMAP_BIT)
+#define disable_mmap(M) ((M)->mflags &= ~USE_MMAP_BIT)
+
+#define use_noncontiguous(M) ((M)->mflags & USE_NONCONTIGUOUS_BIT)
+#define disable_contiguous(M) ((M)->mflags |= USE_NONCONTIGUOUS_BIT)
+
+#define set_lock(M,L)\
+ ((M)->mflags = (L)?\
+ ((M)->mflags | USE_LOCK_BIT) :\
+ ((M)->mflags & ~USE_LOCK_BIT))
+
+/* page-align a size */
+#define page_align(S)\
+ (((S) + (mparams.page_size - SIZE_T_ONE)) & ~(mparams.page_size - SIZE_T_ONE))
+
+/* granularity-align a size */
+#define granularity_align(S)\
+ (((S) + (mparams.granularity - SIZE_T_ONE))\
+ & ~(mparams.granularity - SIZE_T_ONE))
+
+
+/* For mmap, use granularity alignment on windows, else page-align */
+#ifdef WIN32
+#define mmap_align(S) granularity_align(S)
+#else
+#define mmap_align(S) page_align(S)
+#endif
+
+/* For sys_alloc, enough padding to ensure can malloc request on success */
+#define SYS_ALLOC_PADDING (TOP_FOOT_SIZE + MALLOC_ALIGNMENT)
+
+#define is_page_aligned(S)\
+ (((size_t)(S) & (mparams.page_size - SIZE_T_ONE)) == 0)
+#define is_granularity_aligned(S)\
+ (((size_t)(S) & (mparams.granularity - SIZE_T_ONE)) == 0)
+
+/* True if segment S holds address A */
+#define segment_holds(S, A)\
+ ((char*)(A) >= S->base && (char*)(A) < S->base + S->size)
+
+/* Return segment holding given address */
+static msegmentptr segment_holding(mstate m, char* addr) {
+ msegmentptr sp = &m->seg;
+ for (;;) {
+ if (addr >= sp->base && addr < sp->base + sp->size)
+ return sp;
+ if ((sp = sp->next) == 0)
+ return 0;
+ }
+}
+
+/* Return true if segment contains a segment link */
+static int has_segment_link(mstate m, msegmentptr ss) {
+ msegmentptr sp = &m->seg;
+ for (;;) {
+ if ((char*)sp >= ss->base && (char*)sp < ss->base + ss->size)
+ return 1;
+ if ((sp = sp->next) == 0)
+ return 0;
+ }
+}
+
+#ifndef MORECORE_CANNOT_TRIM
+#define should_trim(M,s) ((s) > (M)->trim_check)
+#else /* MORECORE_CANNOT_TRIM */
+#define should_trim(M,s) (0)
+#endif /* MORECORE_CANNOT_TRIM */
+
+/*
+ TOP_FOOT_SIZE is padding at the end of a segment, including space
+ that may be needed to place segment records and fenceposts when new
+ noncontiguous segments are added.
+*/
+#define TOP_FOOT_SIZE\
+ (align_offset(chunk2mem(0))+pad_request(sizeof(struct malloc_segment))+MIN_CHUNK_SIZE)
+
+
+/* ------------------------------- Hooks -------------------------------- */
+
+/*
+ PREACTION should be defined to return 0 on success, and nonzero on
+ failure. If you are not using locking, you can redefine these to do
+ anything you like.
+*/
+
+#if USE_LOCKS
+
+#define PREACTION(M) ((use_lock(M))? ACQUIRE_LOCK(&(M)->mutex) : 0)
+#define POSTACTION(M) { if (use_lock(M)) RELEASE_LOCK(&(M)->mutex); }
+#else /* USE_LOCKS */
+
+#ifndef PREACTION
+#define PREACTION(M) (0)
+#endif /* PREACTION */
+
+#ifndef POSTACTION
+#define POSTACTION(M)
+#endif /* POSTACTION */
+
+#endif /* USE_LOCKS */
+
+/*
+ CORRUPTION_ERROR_ACTION is triggered upon detected bad addresses.
+ USAGE_ERROR_ACTION is triggered on detected bad frees and
+ reallocs. The argument p is an address that might have triggered the
+ fault. It is ignored by the two predefined actions, but might be
+ useful in custom actions that try to help diagnose errors.
+*/
+
+#if PROCEED_ON_ERROR
+
+/* A count of the number of corruption errors causing resets */
+int malloc_corruption_error_count;
+
+/* default corruption action */
+static void reset_on_error(mstate m);
+
+#define CORRUPTION_ERROR_ACTION(m) reset_on_error(m)
+#define USAGE_ERROR_ACTION(m, p)
+
+#else /* PROCEED_ON_ERROR */
+
+#ifndef CORRUPTION_ERROR_ACTION
+#define CORRUPTION_ERROR_ACTION(m) ABORT
+#endif /* CORRUPTION_ERROR_ACTION */
+
+#ifndef USAGE_ERROR_ACTION
+#define USAGE_ERROR_ACTION(m,p) ABORT
+#endif /* USAGE_ERROR_ACTION */
+
+#endif /* PROCEED_ON_ERROR */
+
+/* -------------------------- Debugging setup ---------------------------- */
+
+#if ! DEBUG
+
+#define check_free_chunk(M,P)
+#define check_inuse_chunk(M,P)
+#define check_malloced_chunk(M,P,N)
+#define check_mmapped_chunk(M,P)
+#define check_malloc_state(M)
+#define check_top_chunk(M,P)
+
+#else /* DEBUG */
+#define check_free_chunk(M,P) do_check_free_chunk(M,P)
+#define check_inuse_chunk(M,P) do_check_inuse_chunk(M,P)
+#define check_top_chunk(M,P) do_check_top_chunk(M,P)
+#define check_malloced_chunk(M,P,N) do_check_malloced_chunk(M,P,N)
+#define check_mmapped_chunk(M,P) do_check_mmapped_chunk(M,P)
+#define check_malloc_state(M) do_check_malloc_state(M)
+
+static void do_check_any_chunk(mstate m, mchunkptr p);
+static void do_check_top_chunk(mstate m, mchunkptr p);
+static void do_check_mmapped_chunk(mstate m, mchunkptr p);
+static void do_check_inuse_chunk(mstate m, mchunkptr p);
+static void do_check_free_chunk(mstate m, mchunkptr p);
+static void do_check_malloced_chunk(mstate m, void* mem, size_t s);
+static void do_check_tree(mstate m, tchunkptr t);
+static void do_check_treebin(mstate m, bindex_t i);
+static void do_check_smallbin(mstate m, bindex_t i);
+static void do_check_malloc_state(mstate m);
+static int bin_find(mstate m, mchunkptr x);
+static size_t traverse_and_check(mstate m);
+#endif /* DEBUG */
+
+/* ---------------------------- Indexing Bins ---------------------------- */
+
+#define is_small(s) (((s) >> SMALLBIN_SHIFT) < NSMALLBINS)
+#define small_index(s) ((s) >> SMALLBIN_SHIFT)
+#define small_index2size(i) ((i) << SMALLBIN_SHIFT)
+#define MIN_SMALL_INDEX (small_index(MIN_CHUNK_SIZE))
+
+/* addressing by index. See above about smallbin repositioning */
+#define smallbin_at(M, i) ((sbinptr)((char*)&((M)->smallbins[(i)<<1])))
+#define treebin_at(M,i) (&((M)->treebins[i]))
+
+/* assign tree index for size S to variable I. Use x86 asm if possible */
+#if defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__))
+#define compute_tree_index(S, I)\
+{\
+ unsigned int X = S >> TREEBIN_SHIFT;\
+ if (X == 0)\
+ I = 0;\
+ else if (X > 0xFFFF)\
+ I = NTREEBINS-1;\
+ else {\
+ unsigned int K;\
+ __asm__("bsrl\t%1, %0\n\t" : "=r" (K) : "g" (X));\
+ I = (bindex_t)((K << 1) + ((S >> (K + (TREEBIN_SHIFT-1)) & 1)));\
+ }\
+}
+
+#elif defined (__INTEL_COMPILER)
+#define compute_tree_index(S, I)\
+{\
+ size_t X = S >> TREEBIN_SHIFT;\
+ if (X == 0)\
+ I = 0;\
+ else if (X > 0xFFFF)\
+ I = NTREEBINS-1;\
+ else {\
+ unsigned int K = _bit_scan_reverse (X); \
+ I = (bindex_t)((K << 1) + ((S >> (K + (TREEBIN_SHIFT-1)) & 1)));\
+ }\
+}
+
+#elif defined(_MSC_VER) && _MSC_VER>=1300
+#define compute_tree_index(S, I)\
+{\
+ size_t X = S >> TREEBIN_SHIFT;\
+ if (X == 0)\
+ I = 0;\
+ else if (X > 0xFFFF)\
+ I = NTREEBINS-1;\
+ else {\
+ unsigned int K;\
+ _BitScanReverse((DWORD *) &K, X);\
+ I = (bindex_t)((K << 1) + ((S >> (K + (TREEBIN_SHIFT-1)) & 1)));\
+ }\
+}
+
+#else /* GNUC */
+#define compute_tree_index(S, I)\
+{\
+ size_t X = S >> TREEBIN_SHIFT;\
+ if (X == 0)\
+ I = 0;\
+ else if (X > 0xFFFF)\
+ I = NTREEBINS-1;\
+ else {\
+ unsigned int Y = (unsigned int)X;\
+ unsigned int N = ((Y - 0x100) >> 16) & 8;\
+ unsigned int K = (((Y <<= N) - 0x1000) >> 16) & 4;\
+ N += K;\
+ N += K = (((Y <<= K) - 0x4000) >> 16) & 2;\
+ K = 14 - N + ((Y <<= K) >> 15);\
+ I = (K << 1) + ((S >> (K + (TREEBIN_SHIFT-1)) & 1));\
+ }\
+}
+#endif /* GNUC */
+
+/* Bit representing maximum resolved size in a treebin at i */
+#define bit_for_tree_index(i) \
+ (i == NTREEBINS-1)? (SIZE_T_BITSIZE-1) : (((i) >> 1) + TREEBIN_SHIFT - 2)
+
+/* Shift placing maximum resolved bit in a treebin at i as sign bit */
+#define leftshift_for_tree_index(i) \
+ ((i == NTREEBINS-1)? 0 : \
+ ((SIZE_T_BITSIZE-SIZE_T_ONE) - (((i) >> 1) + TREEBIN_SHIFT - 2)))
+
+/* The size of the smallest chunk held in bin with index i */
+#define minsize_for_tree_index(i) \
+ ((SIZE_T_ONE << (((i) >> 1) + TREEBIN_SHIFT)) | \
+ (((size_t)((i) & SIZE_T_ONE)) << (((i) >> 1) + TREEBIN_SHIFT - 1)))
+
+
+/* ------------------------ Operations on bin maps ----------------------- */
+
+/* bit corresponding to given index */
+#define idx2bit(i) ((binmap_t)(1) << (i))
+
+/* Mark/Clear bits with given index */
+#define mark_smallmap(M,i) ((M)->smallmap |= idx2bit(i))
+#define clear_smallmap(M,i) ((M)->smallmap &= ~idx2bit(i))
+#define smallmap_is_marked(M,i) ((M)->smallmap & idx2bit(i))
+
+#define mark_treemap(M,i) ((M)->treemap |= idx2bit(i))
+#define clear_treemap(M,i) ((M)->treemap &= ~idx2bit(i))
+#define treemap_is_marked(M,i) ((M)->treemap & idx2bit(i))
+
+/* isolate the least set bit of a bitmap */
+#define least_bit(x) ((x) & -(x))
+
+/* mask with all bits to left of least bit of x on */
+#define left_bits(x) ((x<<1) | -(x<<1))
+
+/* mask with all bits to left of or equal to least bit of x on */
+#define same_or_left_bits(x) ((x) | -(x))
+
+/* index corresponding to given bit. Use x86 asm if possible */
+
+#if defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__))
+#define compute_bit2idx(X, I)\
+{\
+ unsigned int J;\
+ __asm__("bsfl\t%1, %0\n\t" : "=r" (J) : "g" (X));\
+ I = (bindex_t)J;\
+}
+
+#elif defined (__INTEL_COMPILER)
+#define compute_bit2idx(X, I)\
+{\
+ unsigned int J;\
+ J = _bit_scan_forward (X); \
+ I = (bindex_t)J;\
+}
+
+#elif defined(_MSC_VER) && _MSC_VER>=1300
+#define compute_bit2idx(X, I)\
+{\
+ unsigned int J;\
+ _BitScanForward((DWORD *) &J, X);\
+ I = (bindex_t)J;\
+}
+
+#elif USE_BUILTIN_FFS
+#define compute_bit2idx(X, I) I = ffs(X)-1
+
+#else
+#define compute_bit2idx(X, I)\
+{\
+ unsigned int Y = X - 1;\
+ unsigned int K = Y >> (16-4) & 16;\
+ unsigned int N = K; Y >>= K;\
+ N += K = Y >> (8-3) & 8; Y >>= K;\
+ N += K = Y >> (4-2) & 4; Y >>= K;\
+ N += K = Y >> (2-1) & 2; Y >>= K;\
+ N += K = Y >> (1-0) & 1; Y >>= K;\
+ I = (bindex_t)(N + Y);\
+}
+#endif /* GNUC */
+
+
+/* ----------------------- Runtime Check Support ------------------------- */
+
+/*
+ For security, the main invariant is that malloc/free/etc never
+ writes to a static address other than malloc_state, unless static
+ malloc_state itself has been corrupted, which cannot occur via
+ malloc (because of these checks). In essence this means that we
+ believe all pointers, sizes, maps etc held in malloc_state, but
+ check all of those linked or offsetted from other embedded data
+ structures. These checks are interspersed with main code in a way
+ that tends to minimize their run-time cost.
+
+ When FOOTERS is defined, in addition to range checking, we also
+ verify footer fields of inuse chunks, which can be used guarantee
+ that the mstate controlling malloc/free is intact. This is a
+ streamlined version of the approach described by William Robertson
+ et al in "Run-time Detection of Heap-based Overflows" LISA'03
+ http://www.usenix.org/events/lisa03/tech/robertson.html The footer
+ of an inuse chunk holds the xor of its mstate and a random seed,
+ that is checked upon calls to free() and realloc(). This is
+ (probablistically) unguessable from outside the program, but can be
+ computed by any code successfully malloc'ing any chunk, so does not
+ itself provide protection against code that has already broken
+ security through some other means. Unlike Robertson et al, we
+ always dynamically check addresses of all offset chunks (previous,
+ next, etc). This turns out to be cheaper than relying on hashes.
+*/
+
+#if !INSECURE
+/* Check if address a is at least as high as any from MORECORE or MMAP */
+#define ok_address(M, a) ((char*)(a) >= (M)->least_addr)
+/* Check if address of next chunk n is higher than base chunk p */
+#define ok_next(p, n) ((char*)(p) < (char*)(n))
+/* Check if p has inuse status */
+#define ok_inuse(p) is_inuse(p)
+/* Check if p has its pinuse bit on */
+#define ok_pinuse(p) pinuse(p)
+
+#else /* !INSECURE */
+#define ok_address(M, a) (1)
+#define ok_next(b, n) (1)
+#define ok_inuse(p) (1)
+#define ok_pinuse(p) (1)
+#endif /* !INSECURE */
+
+#if (FOOTERS && !INSECURE)
+/* Check if (alleged) mstate m has expected magic field */
+#define ok_magic(M) ((M)->magic == mparams.magic)
+#else /* (FOOTERS && !INSECURE) */
+#define ok_magic(M) (1)
+#endif /* (FOOTERS && !INSECURE) */
+
+
+/* In gcc, use __builtin_expect to minimize impact of checks */
+#if !INSECURE
+#if defined(__GNUC__) && __GNUC__ >= 3
+#define RTCHECK(e) __builtin_expect(e, 1)
+#else /* GNUC */
+#define RTCHECK(e) (e)
+#endif /* GNUC */
+#else /* !INSECURE */
+#define RTCHECK(e) (1)
+#endif /* !INSECURE */
+
+/* macros to set up inuse chunks with or without footers */
+
+#if !FOOTERS
+
+#define mark_inuse_foot(M,p,s)
+
+/* Macros for setting head/foot of non-mmapped chunks */
+
+/* Set cinuse bit and pinuse bit of next chunk */
+#define set_inuse(M,p,s)\
+ ((p)->head = (((p)->head & PINUSE_BIT)|s|CINUSE_BIT),\
+ ((mchunkptr)(((char*)(p)) + (s)))->head |= PINUSE_BIT)
+
+/* Set cinuse and pinuse of this chunk and pinuse of next chunk */
+#define set_inuse_and_pinuse(M,p,s)\
+ ((p)->head = (s|PINUSE_BIT|CINUSE_BIT),\
+ ((mchunkptr)(((char*)(p)) + (s)))->head |= PINUSE_BIT)
+
+/* Set size, cinuse and pinuse bit of this chunk */
+#define set_size_and_pinuse_of_inuse_chunk(M, p, s)\
+ ((p)->head = (s|PINUSE_BIT|CINUSE_BIT))
+
+#else /* FOOTERS */
+
+/* Set foot of inuse chunk to be xor of mstate and seed */
+#define mark_inuse_foot(M,p,s)\
+ (((mchunkptr)((char*)(p) + (s)))->prev_foot = ((size_t)(M) ^ mparams.magic))
+
+#define get_mstate_for(p)\
+ ((mstate)(((mchunkptr)((char*)(p) +\
+ (chunksize(p))))->prev_foot ^ mparams.magic))
+
+#define set_inuse(M,p,s)\
+ ((p)->head = (((p)->head & PINUSE_BIT)|s|CINUSE_BIT),\
+ (((mchunkptr)(((char*)(p)) + (s)))->head |= PINUSE_BIT), \
+ mark_inuse_foot(M,p,s))
+
+#define set_inuse_and_pinuse(M,p,s)\
+ ((p)->head = (s|PINUSE_BIT|CINUSE_BIT),\
+ (((mchunkptr)(((char*)(p)) + (s)))->head |= PINUSE_BIT),\
+ mark_inuse_foot(M,p,s))
+
+#define set_size_and_pinuse_of_inuse_chunk(M, p, s)\
+ ((p)->head = (s|PINUSE_BIT|CINUSE_BIT),\
+ mark_inuse_foot(M, p, s))
+
+#endif /* !FOOTERS */
+
+/* ---------------------------- setting mparams -------------------------- */
+
+/* Initialize mparams */
+static int init_mparams(void) {
+#ifdef NEED_GLOBAL_LOCK_INIT
+ if (malloc_global_mutex_status <= 0)
+ init_malloc_global_mutex();
+#endif
+
+ ACQUIRE_MALLOC_GLOBAL_LOCK();
+ if (mparams.magic == 0) {
+ size_t magic;
+ size_t psize;
+ size_t gsize;
+
+#ifndef WIN32
+ psize = malloc_getpagesize;
+ gsize = ((DEFAULT_GRANULARITY != 0)? DEFAULT_GRANULARITY : psize);
+#else /* WIN32 */
+ {
+ SYSTEM_INFO system_info;
+ GetSystemInfo(&system_info);
+ psize = system_info.dwPageSize;
+ gsize = ((DEFAULT_GRANULARITY != 0)?
+ DEFAULT_GRANULARITY : system_info.dwAllocationGranularity);
+ }
+#endif /* WIN32 */
+
+ /* Sanity-check configuration:
+ size_t must be unsigned and as wide as pointer type.
+ ints must be at least 4 bytes.
+ alignment must be at least 8.
+ Alignment, min chunk size, and page size must all be powers of 2.
+ */
+ if ((sizeof(size_t) != sizeof(char*)) ||
+ (MAX_SIZE_T < MIN_CHUNK_SIZE) ||
+ (sizeof(int) < 4) ||
+ (MALLOC_ALIGNMENT < (size_t)8U) ||
+ ((MALLOC_ALIGNMENT & (MALLOC_ALIGNMENT-SIZE_T_ONE)) != 0) ||
+ ((MCHUNK_SIZE & (MCHUNK_SIZE-SIZE_T_ONE)) != 0) ||
+ ((gsize & (gsize-SIZE_T_ONE)) != 0) ||
+ ((psize & (psize-SIZE_T_ONE)) != 0))
+ ABORT;
+
+ mparams.granularity = gsize;
+ mparams.page_size = psize;
+ mparams.mmap_threshold = DEFAULT_MMAP_THRESHOLD;
+ mparams.trim_threshold = DEFAULT_TRIM_THRESHOLD;
+#if MORECORE_CONTIGUOUS
+ mparams.default_mflags = USE_LOCK_BIT|USE_MMAP_BIT;
+#else /* MORECORE_CONTIGUOUS */
+ mparams.default_mflags = USE_LOCK_BIT|USE_MMAP_BIT|USE_NONCONTIGUOUS_BIT;
+#endif /* MORECORE_CONTIGUOUS */
+
+#if !ONLY_MSPACES
+ /* Set up lock for main malloc area */
+ gm->mflags = mparams.default_mflags;
+ INITIAL_LOCK(&gm->mutex);
+#endif
+
+ {
+#if USE_DEV_RANDOM
+ int fd;
+ unsigned char buf[sizeof(size_t)];
+ /* Try to use /dev/urandom, else fall back on using time */
+ if ((fd = open("/dev/urandom", O_RDONLY)) >= 0 &&
+ read(fd, buf, sizeof(buf)) == sizeof(buf)) {
+ magic = *((size_t *) buf);
+ close(fd);
+ }
+ else
+#endif /* USE_DEV_RANDOM */
+#ifdef WIN32
+ magic = (size_t)(GetTickCount() ^ (size_t)0x55555555U);
+#else
+ magic = (size_t)(time(0) ^ (size_t)0x55555555U);
+#endif
+ magic |= (size_t)8U; /* ensure nonzero */
+ magic &= ~(size_t)7U; /* improve chances of fault for bad values */
+ mparams.magic = magic;
+ }
+ }
+
+ RELEASE_MALLOC_GLOBAL_LOCK();
+ return 1;
+}
+
+/* support for mallopt */
+static int change_mparam(int param_number, int value) {
+ size_t val;
+ ensure_initialization();
+ val = (value == -1)? MAX_SIZE_T : (size_t)value;
+ switch(param_number) {
+ case M_TRIM_THRESHOLD:
+ mparams.trim_threshold = val;
+ return 1;
+ case M_GRANULARITY:
+ if (val >= mparams.page_size && ((val & (val-1)) == 0)) {
+ mparams.granularity = val;
+ return 1;
+ }
+ else
+ return 0;
+ case M_MMAP_THRESHOLD:
+ mparams.mmap_threshold = val;
+ return 1;
+ default:
+ return 0;
+ }
+}
+
+#if DEBUG
+/* ------------------------- Debugging Support --------------------------- */
+
+/* Check properties of any chunk, whether free, inuse, mmapped etc */
+static void do_check_any_chunk(mstate m, mchunkptr p) {
+ assert((is_aligned(chunk2mem(p))) || (p->head == FENCEPOST_HEAD));
+ assert(ok_address(m, p));
+}
+
+/* Check properties of top chunk */
+static void do_check_top_chunk(mstate m, mchunkptr p) {
+ msegmentptr sp = segment_holding(m, (char*)p);
+ size_t sz = p->head & ~INUSE_BITS; /* third-lowest bit can be set! */
+ assert(sp != 0);
+ assert((is_aligned(chunk2mem(p))) || (p->head == FENCEPOST_HEAD));
+ assert(ok_address(m, p));
+ assert(sz == m->topsize);
+ assert(sz > 0);
+ assert(sz == ((sp->base + sp->size) - (char*)p) - TOP_FOOT_SIZE);
+ assert(pinuse(p));
+ assert(!pinuse(chunk_plus_offset(p, sz)));
+}
+
+/* Check properties of (inuse) mmapped chunks */
+static void do_check_mmapped_chunk(mstate m, mchunkptr p) {
+ size_t sz = chunksize(p);
+ size_t len = (sz + (p->prev_foot) + MMAP_FOOT_PAD);
+ assert(is_mmapped(p));
+ assert(use_mmap(m));
+ assert((is_aligned(chunk2mem(p))) || (p->head == FENCEPOST_HEAD));
+ assert(ok_address(m, p));
+ assert(!is_small(sz));
+ assert((len & (mparams.page_size-SIZE_T_ONE)) == 0);
+ assert(chunk_plus_offset(p, sz)->head == FENCEPOST_HEAD);
+ assert(chunk_plus_offset(p, sz+SIZE_T_SIZE)->head == 0);
+}
+
+/* Check properties of inuse chunks */
+static void do_check_inuse_chunk(mstate m, mchunkptr p) {
+ do_check_any_chunk(m, p);
+ assert(is_inuse(p));
+ assert(next_pinuse(p));
+ /* If not pinuse and not mmapped, previous chunk has OK offset */
+ assert(is_mmapped(p) || pinuse(p) || next_chunk(prev_chunk(p)) == p);
+ if (is_mmapped(p))
+ do_check_mmapped_chunk(m, p);
+}
+
+/* Check properties of free chunks */
+static void do_check_free_chunk(mstate m, mchunkptr p) {
+ size_t sz = chunksize(p);
+ mchunkptr next = chunk_plus_offset(p, sz);
+ do_check_any_chunk(m, p);
+ assert(!is_inuse(p));
+ assert(!next_pinuse(p));
+ assert (!is_mmapped(p));
+ if (p != m->dv && p != m->top) {
+ if (sz >= MIN_CHUNK_SIZE) {
+ assert((sz & CHUNK_ALIGN_MASK) == 0);
+ assert(is_aligned(chunk2mem(p)));
+ assert(next->prev_foot == sz);
+ assert(pinuse(p));
+ assert (next == m->top || is_inuse(next));
+ assert(p->fd->bk == p);
+ assert(p->bk->fd == p);
+ }
+ else /* markers are always of size SIZE_T_SIZE */
+ assert(sz == SIZE_T_SIZE);
+ }
+}
+
+/* Check properties of malloced chunks at the point they are malloced */
+static void do_check_malloced_chunk(mstate m, void* mem, size_t s) {
+ if (mem != 0) {
+ mchunkptr p = mem2chunk(mem);
+ size_t sz = p->head & ~INUSE_BITS;
+ do_check_inuse_chunk(m, p);
+ assert((sz & CHUNK_ALIGN_MASK) == 0);
+ assert(sz >= MIN_CHUNK_SIZE);
+ assert(sz >= s);
+ /* unless mmapped, size is less than MIN_CHUNK_SIZE more than request */
+ assert(is_mmapped(p) || sz < (s + MIN_CHUNK_SIZE));
+ }
+}
+
+/* Check a tree and its subtrees. */
+static void do_check_tree(mstate m, tchunkptr t) {
+ tchunkptr head = 0;
+ tchunkptr u = t;
+ bindex_t tindex = t->index;
+ size_t tsize = chunksize(t);
+ bindex_t idx;
+ compute_tree_index(tsize, idx);
+ assert(tindex == idx);
+ assert(tsize >= MIN_LARGE_SIZE);
+ assert(tsize >= minsize_for_tree_index(idx));
+ assert((idx == NTREEBINS-1) || (tsize < minsize_for_tree_index((idx+1))));
+
+ do { /* traverse through chain of same-sized nodes */
+ do_check_any_chunk(m, ((mchunkptr)u));
+ assert(u->index == tindex);
+ assert(chunksize(u) == tsize);
+ assert(!is_inuse(u));
+ assert(!next_pinuse(u));
+ assert(u->fd->bk == u);
+ assert(u->bk->fd == u);
+ if (u->parent == 0) {
+ assert(u->child[0] == 0);
+ assert(u->child[1] == 0);
+ }
+ else {
+ assert(head == 0); /* only one node on chain has parent */
+ head = u;
+ assert(u->parent != u);
+ assert (u->parent->child[0] == u ||
+ u->parent->child[1] == u ||
+ *((tbinptr*)(u->parent)) == u);
+ if (u->child[0] != 0) {
+ assert(u->child[0]->parent == u);
+ assert(u->child[0] != u);
+ do_check_tree(m, u->child[0]);
+ }
+ if (u->child[1] != 0) {
+ assert(u->child[1]->parent == u);
+ assert(u->child[1] != u);
+ do_check_tree(m, u->child[1]);
+ }
+ if (u->child[0] != 0 && u->child[1] != 0) {
+ assert(chunksize(u->child[0]) < chunksize(u->child[1]));
+ }
+ }
+ u = u->fd;
+ } while (u != t);
+ assert(head != 0);
+}
+
+/* Check all the chunks in a treebin. */
+static void do_check_treebin(mstate m, bindex_t i) {
+ tbinptr* tb = treebin_at(m, i);
+ tchunkptr t = *tb;
+ int empty = (m->treemap & (1U << i)) == 0;
+ if (t == 0)
+ assert(empty);
+ if (!empty)
+ do_check_tree(m, t);
+}
+
+/* Check all the chunks in a smallbin. */
+static void do_check_smallbin(mstate m, bindex_t i) {
+ sbinptr b = smallbin_at(m, i);
+ mchunkptr p = b->bk;
+ unsigned int empty = (m->smallmap & (1U << i)) == 0;
+ if (p == b)
+ assert(empty);
+ if (!empty) {
+ for (; p != b; p = p->bk) {
+ size_t size = chunksize(p);
+ mchunkptr q;
+ /* each chunk claims to be free */
+ do_check_free_chunk(m, p);
+ /* chunk belongs in bin */
+ assert(small_index(size) == i);
+ assert(p->bk == b || chunksize(p->bk) == chunksize(p));
+ /* chunk is followed by an inuse chunk */
+ q = next_chunk(p);
+ if (q->head != FENCEPOST_HEAD)
+ do_check_inuse_chunk(m, q);
+ }
+ }
+}
+
+/* Find x in a bin. Used in other check functions. */
+static int bin_find(mstate m, mchunkptr x) {
+ size_t size = chunksize(x);
+ if (is_small(size)) {
+ bindex_t sidx = small_index(size);
+ sbinptr b = smallbin_at(m, sidx);
+ if (smallmap_is_marked(m, sidx)) {
+ mchunkptr p = b;
+ do {
+ if (p == x)
+ return 1;
+ } while ((p = p->fd) != b);
+ }
+ }
+ else {
+ bindex_t tidx;
+ compute_tree_index(size, tidx);
+ if (treemap_is_marked(m, tidx)) {
+ tchunkptr t = *treebin_at(m, tidx);
+ size_t sizebits = size << leftshift_for_tree_index(tidx);
+ while (t != 0 && chunksize(t) != size) {
+ t = t->child[(sizebits >> (SIZE_T_BITSIZE-SIZE_T_ONE)) & 1];
+ sizebits <<= 1;
+ }
+ if (t != 0) {
+ tchunkptr u = t;
+ do {
+ if (u == (tchunkptr)x)
+ return 1;
+ } while ((u = u->fd) != t);
+ }
+ }
+ }
+ return 0;
+}
+
+/* Traverse each chunk and check it; return total */
+static size_t traverse_and_check(mstate m) {
+ size_t sum = 0;
+ if (is_initialized(m)) {
+ msegmentptr s = &m->seg;
+ sum += m->topsize + TOP_FOOT_SIZE;
+ while (s != 0) {
+ mchunkptr q = align_as_chunk(s->base);
+ mchunkptr lastq = 0;
+ assert(pinuse(q));
+ while (segment_holds(s, q) &&
+ q != m->top && q->head != FENCEPOST_HEAD) {
+ sum += chunksize(q);
+ if (is_inuse(q)) {
+ assert(!bin_find(m, q));
+ do_check_inuse_chunk(m, q);
+ }
+ else {
+ assert(q == m->dv || bin_find(m, q));
+ assert(lastq == 0 || is_inuse(lastq)); /* Not 2 consecutive free */
+ do_check_free_chunk(m, q);
+ }
+ lastq = q;
+ q = next_chunk(q);
+ }
+ s = s->next;
+ }
+ }
+ return sum;
+}
+
+/* Check all properties of malloc_state. */
+static void do_check_malloc_state(mstate m) {
+ bindex_t i;
+ size_t total;
+ /* check bins */
+ for (i = 0; i < NSMALLBINS; ++i)
+ do_check_smallbin(m, i);
+ for (i = 0; i < NTREEBINS; ++i)
+ do_check_treebin(m, i);
+
+ if (m->dvsize != 0) { /* check dv chunk */
+ do_check_any_chunk(m, m->dv);
+ assert(m->dvsize == chunksize(m->dv));
+ assert(m->dvsize >= MIN_CHUNK_SIZE);
+ assert(bin_find(m, m->dv) == 0);
+ }
+
+ if (m->top != 0) { /* check top chunk */
+ do_check_top_chunk(m, m->top);
+ /*assert(m->topsize == chunksize(m->top)); redundant */
+ assert(m->topsize > 0);
+ assert(bin_find(m, m->top) == 0);
+ }
+
+ total = traverse_and_check(m);
+ assert(total <= m->footprint);
+ assert(m->footprint <= m->max_footprint);
+}
+#endif /* DEBUG */
+
+/* ----------------------------- statistics ------------------------------ */
+
+#if !NO_MALLINFO
+static struct mallinfo internal_mallinfo(mstate m) {
+ struct mallinfo nm = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
+ ensure_initialization();
+ if (!PREACTION(m)) {
+ check_malloc_state(m);
+ if (is_initialized(m)) {
+ size_t nfree = SIZE_T_ONE; /* top always free */
+ size_t mfree = m->topsize + TOP_FOOT_SIZE;
+ size_t sum = mfree;
+ msegmentptr s = &m->seg;
+ while (s != 0) {
+ mchunkptr q = align_as_chunk(s->base);
+ while (segment_holds(s, q) &&
+ q != m->top && q->head != FENCEPOST_HEAD) {
+ size_t sz = chunksize(q);
+ sum += sz;
+ if (!is_inuse(q)) {
+ mfree += sz;
+ ++nfree;
+ }
+ q = next_chunk(q);
+ }
+ s = s->next;
+ }
+
+ nm.arena = sum;
+ nm.ordblks = nfree;
+ nm.hblkhd = m->footprint - sum;
+ nm.usmblks = m->max_footprint;
+ nm.uordblks = m->footprint - mfree;
+ nm.fordblks = mfree;
+ nm.keepcost = m->topsize;
+ }
+
+ POSTACTION(m);
+ }
+ return nm;
+}
+#endif /* !NO_MALLINFO */
+
+static void internal_malloc_stats(mstate m) {
+ ensure_initialization();
+ if (!PREACTION(m)) {
+ size_t maxfp = 0;
+ size_t fp = 0;
+ size_t used = 0;
+ check_malloc_state(m);
+ if (is_initialized(m)) {
+ msegmentptr s = &m->seg;
+ maxfp = m->max_footprint;
+ fp = m->footprint;
+ used = fp - (m->topsize + TOP_FOOT_SIZE);
+
+ while (s != 0) {
+ mchunkptr q = align_as_chunk(s->base);
+ while (segment_holds(s, q) &&
+ q != m->top && q->head != FENCEPOST_HEAD) {
+ if (!is_inuse(q))
+ used -= chunksize(q);
+ q = next_chunk(q);
+ }
+ s = s->next;
+ }
+ }
+
+ fprintf(stderr, "max system bytes = %10lu\n", (unsigned long)(maxfp));
+ fprintf(stderr, "system bytes = %10lu\n", (unsigned long)(fp));
+ fprintf(stderr, "in use bytes = %10lu\n", (unsigned long)(used));
+
+ POSTACTION(m);
+ }
+}
+
+/* ----------------------- Operations on smallbins ----------------------- */
+
+/*
+ Various forms of linking and unlinking are defined as macros. Even
+ the ones for trees, which are very long but have very short typical
+ paths. This is ugly but reduces reliance on inlining support of
+ compilers.
+*/
+
+/* Link a free chunk into a smallbin */
+#define insert_small_chunk(M, P, S) {\
+ bindex_t I = small_index(S);\
+ mchunkptr B = smallbin_at(M, I);\
+ mchunkptr F = B;\
+ assert(S >= MIN_CHUNK_SIZE);\
+ if (!smallmap_is_marked(M, I))\
+ mark_smallmap(M, I);\
+ else if (RTCHECK(ok_address(M, B->fd)))\
+ F = B->fd;\
+ else {\
+ CORRUPTION_ERROR_ACTION(M);\
+ }\
+ B->fd = P;\
+ F->bk = P;\
+ P->fd = F;\
+ P->bk = B;\
+}
+
+/* Unlink a chunk from a smallbin */
+#define unlink_small_chunk(M, P, S) {\
+ mchunkptr F = P->fd;\
+ mchunkptr B = P->bk;\
+ bindex_t I = small_index(S);\
+ assert(P != B);\
+ assert(P != F);\
+ assert(chunksize(P) == small_index2size(I));\
+ if (F == B)\
+ clear_smallmap(M, I);\
+ else if (RTCHECK((F == smallbin_at(M,I) || ok_address(M, F)) &&\
+ (B == smallbin_at(M,I) || ok_address(M, B)))) {\
+ F->bk = B;\
+ B->fd = F;\
+ }\
+ else {\
+ CORRUPTION_ERROR_ACTION(M);\
+ }\
+}
+
+/* Unlink the first chunk from a smallbin */
+#define unlink_first_small_chunk(M, B, P, I) {\
+ mchunkptr F = P->fd;\
+ assert(P != B);\
+ assert(P != F);\
+ assert(chunksize(P) == small_index2size(I));\
+ if (B == F)\
+ clear_smallmap(M, I);\
+ else if (RTCHECK(ok_address(M, F))) {\
+ B->fd = F;\
+ F->bk = B;\
+ }\
+ else {\
+ CORRUPTION_ERROR_ACTION(M);\
+ }\
+}
+
+
+
+/* Replace dv node, binning the old one */
+/* Used only when dvsize known to be small */
+#define replace_dv(M, P, S) {\
+ size_t DVS = M->dvsize;\
+ if (DVS != 0) {\
+ mchunkptr DV = M->dv;\
+ assert(is_small(DVS));\
+ insert_small_chunk(M, DV, DVS);\
+ }\
+ M->dvsize = S;\
+ M->dv = P;\
+}
+
+/* ------------------------- Operations on trees ------------------------- */
+
+/* Insert chunk into tree */
+#define insert_large_chunk(M, X, S) {\
+ tbinptr* H;\
+ bindex_t I;\
+ compute_tree_index(S, I);\
+ H = treebin_at(M, I);\
+ X->index = I;\
+ X->child[0] = X->child[1] = 0;\
+ if (!treemap_is_marked(M, I)) {\
+ mark_treemap(M, I);\
+ *H = X;\
+ X->parent = (tchunkptr)H;\
+ X->fd = X->bk = X;\
+ }\
+ else {\
+ tchunkptr T = *H;\
+ size_t K = S << leftshift_for_tree_index(I);\
+ for (;;) {\
+ if (chunksize(T) != S) {\
+ tchunkptr* C = &(T->child[(K >> (SIZE_T_BITSIZE-SIZE_T_ONE)) & 1]);\
+ K <<= 1;\
+ if (*C != 0)\
+ T = *C;\
+ else if (RTCHECK(ok_address(M, C))) {\
+ *C = X;\
+ X->parent = T;\
+ X->fd = X->bk = X;\
+ break;\
+ }\
+ else {\
+ CORRUPTION_ERROR_ACTION(M);\
+ break;\
+ }\
+ }\
+ else {\
+ tchunkptr F = T->fd;\
+ if (RTCHECK(ok_address(M, T) && ok_address(M, F))) {\
+ T->fd = F->bk = X;\
+ X->fd = F;\
+ X->bk = T;\
+ X->parent = 0;\
+ break;\
+ }\
+ else {\
+ CORRUPTION_ERROR_ACTION(M);\
+ break;\
+ }\
+ }\
+ }\
+ }\
+}
+
+/*
+ Unlink steps:
+
+ 1. If x is a chained node, unlink it from its same-sized fd/bk links
+ and choose its bk node as its replacement.
+ 2. If x was the last node of its size, but not a leaf node, it must
+ be replaced with a leaf node (not merely one with an open left or
+ right), to make sure that lefts and rights of descendents
+ correspond properly to bit masks. We use the rightmost descendent
+ of x. We could use any other leaf, but this is easy to locate and
+ tends to counteract removal of leftmosts elsewhere, and so keeps
+ paths shorter than minimally guaranteed. This doesn't loop much
+ because on average a node in a tree is near the bottom.
+ 3. If x is the base of a chain (i.e., has parent links) relink
+ x's parent and children to x's replacement (or null if none).
+*/
+
+#define unlink_large_chunk(M, X) {\
+ tchunkptr XP = X->parent;\
+ tchunkptr R;\
+ if (X->bk != X) {\
+ tchunkptr F = X->fd;\
+ R = X->bk;\
+ if (RTCHECK(ok_address(M, F))) {\
+ F->bk = R;\
+ R->fd = F;\
+ }\
+ else {\
+ CORRUPTION_ERROR_ACTION(M);\
+ }\
+ }\
+ else {\
+ tchunkptr* RP;\
+ if (((R = *(RP = &(X->child[1]))) != 0) ||\
+ ((R = *(RP = &(X->child[0]))) != 0)) {\
+ tchunkptr* CP;\
+ while ((*(CP = &(R->child[1])) != 0) ||\
+ (*(CP = &(R->child[0])) != 0)) {\
+ R = *(RP = CP);\
+ }\
+ if (RTCHECK(ok_address(M, RP)))\
+ *RP = 0;\
+ else {\
+ CORRUPTION_ERROR_ACTION(M);\
+ }\
+ }\
+ }\
+ if (XP != 0) {\
+ tbinptr* H = treebin_at(M, X->index);\
+ if (X == *H) {\
+ if ((*H = R) == 0) \
+ clear_treemap(M, X->index);\
+ }\
+ else if (RTCHECK(ok_address(M, XP))) {\
+ if (XP->child[0] == X) \
+ XP->child[0] = R;\
+ else \
+ XP->child[1] = R;\
+ }\
+ else\
+ CORRUPTION_ERROR_ACTION(M);\
+ if (R != 0) {\
+ if (RTCHECK(ok_address(M, R))) {\
+ tchunkptr C0, C1;\
+ R->parent = XP;\
+ if ((C0 = X->child[0]) != 0) {\
+ if (RTCHECK(ok_address(M, C0))) {\
+ R->child[0] = C0;\
+ C0->parent = R;\
+ }\
+ else\
+ CORRUPTION_ERROR_ACTION(M);\
+ }\
+ if ((C1 = X->child[1]) != 0) {\
+ if (RTCHECK(ok_address(M, C1))) {\
+ R->child[1] = C1;\
+ C1->parent = R;\
+ }\
+ else\
+ CORRUPTION_ERROR_ACTION(M);\
+ }\
+ }\
+ else\
+ CORRUPTION_ERROR_ACTION(M);\
+ }\
+ }\
+}
+
+/* Relays to large vs small bin operations */
+
+#define insert_chunk(M, P, S)\
+ if (is_small(S)) insert_small_chunk(M, P, S)\
+ else { tchunkptr TP = (tchunkptr)(P); insert_large_chunk(M, TP, S); }
+
+#define unlink_chunk(M, P, S)\
+ if (is_small(S)) unlink_small_chunk(M, P, S)\
+ else { tchunkptr TP = (tchunkptr)(P); unlink_large_chunk(M, TP); }
+
+
+/* Relays to internal calls to malloc/free from realloc, memalign etc */
+
+#if ONLY_MSPACES
+#define internal_malloc(m, b) mspace_malloc(m, b)
+#define internal_free(m, mem) mspace_free(m,mem);
+#else /* ONLY_MSPACES */
+#if MSPACES
+#define internal_malloc(m, b)\
+ (m == gm)? dlmalloc(b) : mspace_malloc(m, b)
+#define internal_free(m, mem)\
+ if (m == gm) dlfree(mem); else mspace_free(m,mem);
+#else /* MSPACES */
+#define internal_malloc(m, b) dlmalloc(b)
+#define internal_free(m, mem) dlfree(mem)
+#endif /* MSPACES */
+#endif /* ONLY_MSPACES */
+
+/* ----------------------- Direct-mmapping chunks ----------------------- */
+
+/*
+ Directly mmapped chunks are set up with an offset to the start of
+ the mmapped region stored in the prev_foot field of the chunk. This
+ allows reconstruction of the required argument to MUNMAP when freed,
+ and also allows adjustment of the returned chunk to meet alignment
+ requirements (especially in memalign).
+*/
+
+/* Malloc using mmap */
+static void* mmap_alloc(mstate m, size_t nb) {
+ size_t mmsize = mmap_align(nb + SIX_SIZE_T_SIZES + CHUNK_ALIGN_MASK);
+ if (mmsize > nb) { /* Check for wrap around 0 */
+ char* mm = (char*)(CALL_DIRECT_MMAP(mmsize));
+ if (mm != CMFAIL) {
+ size_t offset = align_offset(chunk2mem(mm));
+ size_t psize = mmsize - offset - MMAP_FOOT_PAD;
+ mchunkptr p = (mchunkptr)(mm + offset);
+ p->prev_foot = offset;
+ p->head = psize;
+ mark_inuse_foot(m, p, psize);
+ chunk_plus_offset(p, psize)->head = FENCEPOST_HEAD;
+ chunk_plus_offset(p, psize+SIZE_T_SIZE)->head = 0;
+
+ if (m->least_addr == 0 || mm < m->least_addr)
+ m->least_addr = mm;
+ if ((m->footprint += mmsize) > m->max_footprint)
+ m->max_footprint = m->footprint;
+ assert(is_aligned(chunk2mem(p)));
+ check_mmapped_chunk(m, p);
+ return chunk2mem(p);
+ }
+ }
+ return 0;
+}
+
+/* Realloc using mmap */
+static mchunkptr mmap_resize(mstate m, mchunkptr oldp, size_t nb) {
+ size_t oldsize = chunksize(oldp);
+ if (is_small(nb)) /* Can't shrink mmap regions below small size */
+ return 0;
+ /* Keep old chunk if big enough but not too big */
+ if (oldsize >= nb + SIZE_T_SIZE &&
+ (oldsize - nb) <= (mparams.granularity << 1))
+ return oldp;
+ else {
+ size_t offset = oldp->prev_foot;
+ size_t oldmmsize = oldsize + offset + MMAP_FOOT_PAD;
+ size_t newmmsize = mmap_align(nb + SIX_SIZE_T_SIZES + CHUNK_ALIGN_MASK);
+ char* cp = (char*)CALL_MREMAP((char*)oldp - offset,
+ oldmmsize, newmmsize, 1);
+ if (cp != CMFAIL) {
+ mchunkptr newp = (mchunkptr)(cp + offset);
+ size_t psize = newmmsize - offset - MMAP_FOOT_PAD;
+ newp->head = psize;
+ mark_inuse_foot(m, newp, psize);
+ chunk_plus_offset(newp, psize)->head = FENCEPOST_HEAD;
+ chunk_plus_offset(newp, psize+SIZE_T_SIZE)->head = 0;
+
+ if (cp < m->least_addr)
+ m->least_addr = cp;
+ if ((m->footprint += newmmsize - oldmmsize) > m->max_footprint)
+ m->max_footprint = m->footprint;
+ check_mmapped_chunk(m, newp);
+ return newp;
+ }
+ }
+ return 0;
+}
+
+/* -------------------------- mspace management -------------------------- */
+
+/* Initialize top chunk and its size */
+static void init_top(mstate m, mchunkptr p, size_t psize) {
+ /* Ensure alignment */
+ size_t offset = align_offset(chunk2mem(p));
+ p = (mchunkptr)((char*)p + offset);
+ psize -= offset;
+
+ m->top = p;
+ m->topsize = psize;
+ p->head = psize | PINUSE_BIT;
+ /* set size of fake trailing chunk holding overhead space only once */
+ chunk_plus_offset(p, psize)->head = TOP_FOOT_SIZE;
+ m->trim_check = mparams.trim_threshold; /* reset on each update */
+}
+
+/* Initialize bins for a new mstate that is otherwise zeroed out */
+static void init_bins(mstate m) {
+ /* Establish circular links for smallbins */
+ bindex_t i;
+ for (i = 0; i < NSMALLBINS; ++i) {
+ sbinptr bin = smallbin_at(m,i);
+ bin->fd = bin->bk = bin;
+ }
+}
+
+#if PROCEED_ON_ERROR
+
+/* default corruption action */
+static void reset_on_error(mstate m) {
+ int i;
+ ++malloc_corruption_error_count;
+ /* Reinitialize fields to forget about all memory */
+ m->smallbins = m->treebins = 0;
+ m->dvsize = m->topsize = 0;
+ m->seg.base = 0;
+ m->seg.size = 0;
+ m->seg.next = 0;
+ m->top = m->dv = 0;
+ for (i = 0; i < NTREEBINS; ++i)
+ *treebin_at(m, i) = 0;
+ init_bins(m);
+}
+#endif /* PROCEED_ON_ERROR */
+
+/* Allocate chunk and prepend remainder with chunk in successor base. */
+static void* prepend_alloc(mstate m, char* newbase, char* oldbase,
+ size_t nb) {
+ mchunkptr p = align_as_chunk(newbase);
+ mchunkptr oldfirst = align_as_chunk(oldbase);
+ size_t psize = (char*)oldfirst - (char*)p;
+ mchunkptr q = chunk_plus_offset(p, nb);
+ size_t qsize = psize - nb;
+ set_size_and_pinuse_of_inuse_chunk(m, p, nb);
+
+ assert((char*)oldfirst > (char*)q);
+ assert(pinuse(oldfirst));
+ assert(qsize >= MIN_CHUNK_SIZE);
+
+ /* consolidate remainder with first chunk of old base */
+ if (oldfirst == m->top) {
+ size_t tsize = m->topsize += qsize;
+ m->top = q;
+ q->head = tsize | PINUSE_BIT;
+ check_top_chunk(m, q);
+ }
+ else if (oldfirst == m->dv) {
+ size_t dsize = m->dvsize += qsize;
+ m->dv = q;
+ set_size_and_pinuse_of_free_chunk(q, dsize);
+ }
+ else {
+ if (!is_inuse(oldfirst)) {
+ size_t nsize = chunksize(oldfirst);
+ unlink_chunk(m, oldfirst, nsize);
+ oldfirst = chunk_plus_offset(oldfirst, nsize);
+ qsize += nsize;
+ }
+ set_free_with_pinuse(q, qsize, oldfirst);
+ insert_chunk(m, q, qsize);
+ check_free_chunk(m, q);
+ }
+
+ check_malloced_chunk(m, chunk2mem(p), nb);
+ return chunk2mem(p);
+}
+
+/* Add a segment to hold a new noncontiguous region */
+static void add_segment(mstate m, char* tbase, size_t tsize, flag_t mmapped) {
+ /* Determine locations and sizes of segment, fenceposts, old top */
+ char* old_top = (char*)m->top;
+ msegmentptr oldsp = segment_holding(m, old_top);
+ char* old_end = oldsp->base + oldsp->size;
+ size_t ssize = pad_request(sizeof(struct malloc_segment));
+ char* rawsp = old_end - (ssize + FOUR_SIZE_T_SIZES + CHUNK_ALIGN_MASK);
+ size_t offset = align_offset(chunk2mem(rawsp));
+ char* asp = rawsp + offset;
+ char* csp = (asp < (old_top + MIN_CHUNK_SIZE))? old_top : asp;
+ mchunkptr sp = (mchunkptr)csp;
+ msegmentptr ss = (msegmentptr)(chunk2mem(sp));
+ mchunkptr tnext = chunk_plus_offset(sp, ssize);
+ mchunkptr p = tnext;
+ int nfences = 0;
+
+ /* reset top to new space */
+ init_top(m, (mchunkptr)tbase, tsize - TOP_FOOT_SIZE);
+
+ /* Set up segment record */
+ assert(is_aligned(ss));
+ set_size_and_pinuse_of_inuse_chunk(m, sp, ssize);
+ *ss = m->seg; /* Push current record */
+ m->seg.base = tbase;
+ m->seg.size = tsize;
+ m->seg.sflags = mmapped;
+ m->seg.next = ss;
+
+ /* Insert trailing fenceposts */
+ for (;;) {
+ mchunkptr nextp = chunk_plus_offset(p, SIZE_T_SIZE);
+ p->head = FENCEPOST_HEAD;
+ ++nfences;
+ if ((char*)(&(nextp->head)) < old_end)
+ p = nextp;
+ else
+ break;
+ }
+ assert(nfences >= 2);
+
+ /* Insert the rest of old top into a bin as an ordinary free chunk */
+ if (csp != old_top) {
+ mchunkptr q = (mchunkptr)old_top;
+ size_t psize = csp - old_top;
+ mchunkptr tn = chunk_plus_offset(q, psize);
+ set_free_with_pinuse(q, psize, tn);
+ insert_chunk(m, q, psize);
+ }
+
+ check_top_chunk(m, m->top);
+}
+
+/* -------------------------- System allocation -------------------------- */
+
+/* Get memory from system using MORECORE or MMAP */
+static void* sys_alloc(mstate m, size_t nb) {
+ char* tbase = CMFAIL;
+ size_t tsize = 0;
+ flag_t mmap_flag = 0;
+
+ ensure_initialization();
+
+ /* Directly map large chunks, but only if already initialized */
+ if (use_mmap(m) && nb >= mparams.mmap_threshold && m->topsize != 0) {
+ void* mem = mmap_alloc(m, nb);
+ if (mem != 0)
+ return mem;
+ }
+
+ /*
+ Try getting memory in any of three ways (in most-preferred to
+ least-preferred order):
+ 1. A call to MORECORE that can normally contiguously extend memory.
+ (disabled if not MORECORE_CONTIGUOUS or not HAVE_MORECORE or
+ or main space is mmapped or a previous contiguous call failed)
+ 2. A call to MMAP new space (disabled if not HAVE_MMAP).
+ Note that under the default settings, if MORECORE is unable to
+ fulfill a request, and HAVE_MMAP is true, then mmap is
+ used as a noncontiguous system allocator. This is a useful backup
+ strategy for systems with holes in address spaces -- in this case
+ sbrk cannot contiguously expand the heap, but mmap may be able to
+ find space.
+ 3. A call to MORECORE that cannot usually contiguously extend memory.
+ (disabled if not HAVE_MORECORE)
+
+ In all cases, we need to request enough bytes from system to ensure
+ we can malloc nb bytes upon success, so pad with enough space for
+ top_foot, plus alignment-pad to make sure we don't lose bytes if
+ not on boundary, and round this up to a granularity unit.
+ */
+
+ if (MORECORE_CONTIGUOUS && !use_noncontiguous(m)) {
+ char* br = CMFAIL;
+ msegmentptr ss = (m->top == 0)? 0 : segment_holding(m, (char*)m->top);
+ size_t asize = 0;
+ ACQUIRE_MALLOC_GLOBAL_LOCK();
+
+ if (ss == 0) { /* First time through or recovery */
+ char* base = (char*)CALL_MORECORE(0);
+ if (base != CMFAIL) {
+ asize = granularity_align(nb + SYS_ALLOC_PADDING);
+ /* Adjust to end on a page boundary */
+ if (!is_page_aligned(base))
+ asize += (page_align((size_t)base) - (size_t)base);
+ /* Can't call MORECORE if size is negative when treated as signed */
+ if (asize < HALF_MAX_SIZE_T &&
+ (br = (char*)(CALL_MORECORE(asize))) == base) {
+ tbase = base;
+ tsize = asize;
+ }
+ }
+ }
+ else {
+ /* Subtract out existing available top space from MORECORE request. */
+ asize = granularity_align(nb - m->topsize + SYS_ALLOC_PADDING);
+ /* Use mem here only if it did continuously extend old space */
+ if (asize < HALF_MAX_SIZE_T &&
+ (br = (char*)(CALL_MORECORE(asize))) == ss->base+ss->size) {
+ tbase = br;
+ tsize = asize;
+ }
+ }
+
+ if (tbase == CMFAIL) { /* Cope with partial failure */
+ if (br != CMFAIL) { /* Try to use/extend the space we did get */
+ if (asize < HALF_MAX_SIZE_T &&
+ asize < nb + SYS_ALLOC_PADDING) {
+ size_t esize = granularity_align(nb + SYS_ALLOC_PADDING - asize);
+ if (esize < HALF_MAX_SIZE_T) {
+ char* end = (char*)CALL_MORECORE(esize);
+ if (end != CMFAIL)
+ asize += esize;
+ else { /* Can't use; try to release */
+ (void) CALL_MORECORE(-asize);
+ br = CMFAIL;
+ }
+ }
+ }
+ }
+ if (br != CMFAIL) { /* Use the space we did get */
+ tbase = br;
+ tsize = asize;
+ }
+ else
+ disable_contiguous(m); /* Don't try contiguous path in the future */
+ }
+
+ RELEASE_MALLOC_GLOBAL_LOCK();
+ }
+
+ if (HAVE_MMAP && tbase == CMFAIL) { /* Try MMAP */
+ size_t rsize = granularity_align(nb + SYS_ALLOC_PADDING);
+ if (rsize > nb) { /* Fail if wraps around zero */
+ char* mp = (char*)(CALL_MMAP(rsize));
+ if (mp != CMFAIL) {
+ tbase = mp;
+ tsize = rsize;
+ mmap_flag = USE_MMAP_BIT;
+ }
+ }
+ }
+
+ if (HAVE_MORECORE && tbase == CMFAIL) { /* Try noncontiguous MORECORE */
+ size_t asize = granularity_align(nb + SYS_ALLOC_PADDING);
+ if (asize < HALF_MAX_SIZE_T) {
+ char* br = CMFAIL;
+ char* end = CMFAIL;
+ ACQUIRE_MALLOC_GLOBAL_LOCK();
+ br = (char*)(CALL_MORECORE(asize));
+ end = (char*)(CALL_MORECORE(0));
+ RELEASE_MALLOC_GLOBAL_LOCK();
+ if (br != CMFAIL && end != CMFAIL && br < end) {
+ size_t ssize = end - br;
+ if (ssize > nb + TOP_FOOT_SIZE) {
+ tbase = br;
+ tsize = ssize;
+ }
+ }
+ }
+ }
+
+ if (tbase != CMFAIL) {
+
+ if ((m->footprint += tsize) > m->max_footprint)
+ m->max_footprint = m->footprint;
+
+ if (!is_initialized(m)) { /* first-time initialization */
+ if (m->least_addr == 0 || tbase < m->least_addr)
+ m->least_addr = tbase;
+ m->seg.base = tbase;
+ m->seg.size = tsize;
+ m->seg.sflags = mmap_flag;
+ m->magic = mparams.magic;
+ m->release_checks = MAX_RELEASE_CHECK_RATE;
+ init_bins(m);
+#if !ONLY_MSPACES
+ if (is_global(m))
+ init_top(m, (mchunkptr)tbase, tsize - TOP_FOOT_SIZE);
+ else
+#endif
+ {
+ /* Offset top by embedded malloc_state */
+ mchunkptr mn = next_chunk(mem2chunk(m));
+ init_top(m, mn, (size_t)((tbase + tsize) - (char*)mn) -TOP_FOOT_SIZE);
+ }
+ }
+
+ else {
+ /* Try to merge with an existing segment */
+ msegmentptr sp = &m->seg;
+ /* Only consider most recent segment if traversal suppressed */
+ while (sp != 0 && tbase != sp->base + sp->size)
+ sp = (NO_SEGMENT_TRAVERSAL) ? 0 : sp->next;
+ if (sp != 0 &&
+ !is_extern_segment(sp) &&
+ (sp->sflags & USE_MMAP_BIT) == mmap_flag &&
+ segment_holds(sp, m->top)) { /* append */
+ sp->size += tsize;
+ init_top(m, m->top, m->topsize + tsize);
+ }
+ else {
+ if (tbase < m->least_addr)
+ m->least_addr = tbase;
+ sp = &m->seg;
+ while (sp != 0 && sp->base != tbase + tsize)
+ sp = (NO_SEGMENT_TRAVERSAL) ? 0 : sp->next;
+ if (sp != 0 &&
+ !is_extern_segment(sp) &&
+ (sp->sflags & USE_MMAP_BIT) == mmap_flag) {
+ char* oldbase = sp->base;
+ sp->base = tbase;
+ sp->size += tsize;
+ return prepend_alloc(m, tbase, oldbase, nb);
+ }
+ else
+ add_segment(m, tbase, tsize, mmap_flag);
+ }
+ }
+
+ if (nb < m->topsize) { /* Allocate from new or extended top space */
+ size_t rsize = m->topsize -= nb;
+ mchunkptr p = m->top;
+ mchunkptr r = m->top = chunk_plus_offset(p, nb);
+ r->head = rsize | PINUSE_BIT;
+ set_size_and_pinuse_of_inuse_chunk(m, p, nb);
+ check_top_chunk(m, m->top);
+ check_malloced_chunk(m, chunk2mem(p), nb);
+ return chunk2mem(p);
+ }
+ }
+
+ MALLOC_FAILURE_ACTION;
+ return 0;
+}
+
+/* ----------------------- system deallocation -------------------------- */
+
+/* Unmap and unlink any mmapped segments that don't contain used chunks */
+static size_t release_unused_segments(mstate m) {
+ size_t released = 0;
+ int nsegs = 0;
+ msegmentptr pred = &m->seg;
+ msegmentptr sp = pred->next;
+ while (sp != 0) {
+ char* base = sp->base;
+ size_t size = sp->size;
+ msegmentptr next = sp->next;
+ ++nsegs;
+ if (is_mmapped_segment(sp) && !is_extern_segment(sp)) {
+ mchunkptr p = align_as_chunk(base);
+ size_t psize = chunksize(p);
+ /* Can unmap if first chunk holds entire segment and not pinned */
+ if (!is_inuse(p) && (char*)p + psize >= base + size - TOP_FOOT_SIZE) {
+ tchunkptr tp = (tchunkptr)p;
+ assert(segment_holds(sp, (char*)sp));
+ if (p == m->dv) {
+ m->dv = 0;
+ m->dvsize = 0;
+ }
+ else {
+ unlink_large_chunk(m, tp);
+ }
+ if (CALL_MUNMAP(base, size) == 0) {
+ released += size;
+ m->footprint -= size;
+ /* unlink obsoleted record */
+ sp = pred;
+ sp->next = next;
+ }
+ else { /* back out if cannot unmap */
+ insert_large_chunk(m, tp, psize);
+ }
+ }
+ }
+ if (NO_SEGMENT_TRAVERSAL) /* scan only first segment */
+ break;
+ pred = sp;
+ sp = next;
+ }
+ /* Reset check counter */
+ m->release_checks = ((nsegs > MAX_RELEASE_CHECK_RATE)?
+ nsegs : MAX_RELEASE_CHECK_RATE);
+ return released;
+}
+
+static int sys_trim(mstate m, size_t pad) {
+ size_t released = 0;
+ ensure_initialization();
+ if (pad < MAX_REQUEST && is_initialized(m)) {
+ pad += TOP_FOOT_SIZE; /* ensure enough room for segment overhead */
+
+ if (m->topsize > pad) {
+ /* Shrink top space in granularity-size units, keeping at least one */
+ size_t unit = mparams.granularity;
+ size_t extra = ((m->topsize - pad + (unit - SIZE_T_ONE)) / unit -
+ SIZE_T_ONE) * unit;
+ msegmentptr sp = segment_holding(m, (char*)m->top);
+
+ if (!is_extern_segment(sp)) {
+ if (is_mmapped_segment(sp)) {
+ if (HAVE_MMAP &&
+ sp->size >= extra &&
+ !has_segment_link(m, sp)) { /* can't shrink if pinned */
+ size_t newsize = sp->size - extra;
+ /* Prefer mremap, fall back to munmap */
+ if ((CALL_MREMAP(sp->base, sp->size, newsize, 0) != MFAIL) ||
+ (CALL_MUNMAP(sp->base + newsize, extra) == 0)) {
+ released = extra;
+ }
+ }
+ }
+ else if (HAVE_MORECORE) {
+ if (extra >= HALF_MAX_SIZE_T) /* Avoid wrapping negative */
+ extra = (HALF_MAX_SIZE_T) + SIZE_T_ONE - unit;
+ ACQUIRE_MALLOC_GLOBAL_LOCK();
+ {
+ /* Make sure end of memory is where we last set it. */
+ char* old_br = (char*)(CALL_MORECORE(0));
+ if (old_br == sp->base + sp->size) {
+ char* rel_br = (char*)(CALL_MORECORE(-extra));
+ char* new_br = (char*)(CALL_MORECORE(0));
+ if (rel_br != CMFAIL && new_br < old_br)
+ released = old_br - new_br;
+ }
+ }
+ RELEASE_MALLOC_GLOBAL_LOCK();
+ }
+ }
+
+ if (released != 0) {
+ sp->size -= released;
+ m->footprint -= released;
+ init_top(m, m->top, m->topsize - released);
+ check_top_chunk(m, m->top);
+ }
+ }
+
+ /* Unmap any unused mmapped segments */
+ if (HAVE_MMAP)
+ released += release_unused_segments(m);
+
+ /* On failure, disable autotrim to avoid repeated failed future calls */
+ if (released == 0 && m->topsize > m->trim_check)
+ m->trim_check = MAX_SIZE_T;
+ }
+
+ return (released != 0)? 1 : 0;
+}
+
+
+/* ---------------------------- malloc support --------------------------- */
+
+/* allocate a large request from the best fitting chunk in a treebin */
+static void* tmalloc_large(mstate m, size_t nb) {
+ tchunkptr v = 0;
+ size_t rsize = -nb; /* Unsigned negation */
+ tchunkptr t;
+ bindex_t idx;
+ compute_tree_index(nb, idx);
+ if ((t = *treebin_at(m, idx)) != 0) {
+ /* Traverse tree for this bin looking for node with size == nb */
+ size_t sizebits = nb << leftshift_for_tree_index(idx);
+ tchunkptr rst = 0; /* The deepest untaken right subtree */
+ for (;;) {
+ tchunkptr rt;
+ size_t trem = chunksize(t) - nb;
+ if (trem < rsize) {
+ v = t;
+ if ((rsize = trem) == 0)
+ break;
+ }
+ rt = t->child[1];
+ t = t->child[(sizebits >> (SIZE_T_BITSIZE-SIZE_T_ONE)) & 1];
+ if (rt != 0 && rt != t)
+ rst = rt;
+ if (t == 0) {
+ t = rst; /* set t to least subtree holding sizes > nb */
+ break;
+ }
+ sizebits <<= 1;
+ }
+ }
+ if (t == 0 && v == 0) { /* set t to root of next non-empty treebin */
+ binmap_t leftbits = left_bits(idx2bit(idx)) & m->treemap;
+ if (leftbits != 0) {
+ bindex_t i;
+ binmap_t leastbit = least_bit(leftbits);
+ compute_bit2idx(leastbit, i);
+ t = *treebin_at(m, i);
+ }
+ }
+
+ while (t != 0) { /* find smallest of tree or subtree */
+ size_t trem = chunksize(t) - nb;
+ if (trem < rsize) {
+ rsize = trem;
+ v = t;
+ }
+ t = leftmost_child(t);
+ }
+
+ /* If dv is a better fit, return 0 so malloc will use it */
+ if (v != 0 && rsize < (size_t)(m->dvsize - nb)) {
+ if (RTCHECK(ok_address(m, v))) { /* split */
+ mchunkptr r = chunk_plus_offset(v, nb);
+ assert(chunksize(v) == rsize + nb);
+ if (RTCHECK(ok_next(v, r))) {
+ unlink_large_chunk(m, v);
+ if (rsize < MIN_CHUNK_SIZE)
+ set_inuse_and_pinuse(m, v, (rsize + nb));
+ else {
+ set_size_and_pinuse_of_inuse_chunk(m, v, nb);
+ set_size_and_pinuse_of_free_chunk(r, rsize);
+ insert_chunk(m, r, rsize);
+ }
+ return chunk2mem(v);
+ }
+ }
+ CORRUPTION_ERROR_ACTION(m);
+ }
+ return 0;
+}
+
+/* allocate a small request from the best fitting chunk in a treebin */
+static void* tmalloc_small(mstate m, size_t nb) {
+ tchunkptr t, v;
+ size_t rsize;
+ bindex_t i;
+ binmap_t leastbit = least_bit(m->treemap);
+ compute_bit2idx(leastbit, i);
+ v = t = *treebin_at(m, i);
+ rsize = chunksize(t) - nb;
+
+ while ((t = leftmost_child(t)) != 0) {
+ size_t trem = chunksize(t) - nb;
+ if (trem < rsize) {
+ rsize = trem;
+ v = t;
+ }
+ }
+
+ if (RTCHECK(ok_address(m, v))) {
+ mchunkptr r = chunk_plus_offset(v, nb);
+ assert(chunksize(v) == rsize + nb);
+ if (RTCHECK(ok_next(v, r))) {
+ unlink_large_chunk(m, v);
+ if (rsize < MIN_CHUNK_SIZE)
+ set_inuse_and_pinuse(m, v, (rsize + nb));
+ else {
+ set_size_and_pinuse_of_inuse_chunk(m, v, nb);
+ set_size_and_pinuse_of_free_chunk(r, rsize);
+ replace_dv(m, r, rsize);
+ }
+ return chunk2mem(v);
+ }
+ }
+
+ CORRUPTION_ERROR_ACTION(m);
+ return 0;
+}
+
+/* --------------------------- realloc support --------------------------- */
+
+static void* internal_realloc(mstate m, void* oldmem, size_t bytes) {
+ if (bytes >= MAX_REQUEST) {
+ MALLOC_FAILURE_ACTION;
+ return 0;
+ }
+ if (!PREACTION(m)) {
+ mchunkptr oldp = mem2chunk(oldmem);
+ size_t oldsize = chunksize(oldp);
+ mchunkptr next = chunk_plus_offset(oldp, oldsize);
+ mchunkptr newp = 0;
+ void* extra = 0;
+
+ /* Try to either shrink or extend into top. Else malloc-copy-free */
+
+ if (RTCHECK(ok_address(m, oldp) && ok_inuse(oldp) &&
+ ok_next(oldp, next) && ok_pinuse(next))) {
+ size_t nb = request2size(bytes);
+ if (is_mmapped(oldp))
+ newp = mmap_resize(m, oldp, nb);
+ else if (oldsize >= nb) { /* already big enough */
+ size_t rsize = oldsize - nb;
+ newp = oldp;
+ if (rsize >= MIN_CHUNK_SIZE) {
+ mchunkptr remainder = chunk_plus_offset(newp, nb);
+ set_inuse(m, newp, nb);
+ set_inuse_and_pinuse(m, remainder, rsize);
+ extra = chunk2mem(remainder);
+ }
+ }
+ else if (next == m->top && oldsize + m->topsize > nb) {
+ /* Expand into top */
+ size_t newsize = oldsize + m->topsize;
+ size_t newtopsize = newsize - nb;
+ mchunkptr newtop = chunk_plus_offset(oldp, nb);
+ set_inuse(m, oldp, nb);
+ newtop->head = newtopsize |PINUSE_BIT;
+ m->top = newtop;
+ m->topsize = newtopsize;
+ newp = oldp;
+ }
+ }
+ else {
+ USAGE_ERROR_ACTION(m, oldmem);
+ POSTACTION(m);
+ return 0;
+ }
+#if DEBUG
+ if (newp != 0) {
+ check_inuse_chunk(m, newp); /* Check requires lock */
+ }
+#endif
+
+ POSTACTION(m);
+
+ if (newp != 0) {
+ if (extra != 0) {
+ internal_free(m, extra);
+ }
+ return chunk2mem(newp);
+ }
+ else {
+ void* newmem = internal_malloc(m, bytes);
+ if (newmem != 0) {
+ size_t oc = oldsize - overhead_for(oldp);
+ memcpy(newmem, oldmem, (oc < bytes)? oc : bytes);
+ internal_free(m, oldmem);
+ }
+ return newmem;
+ }
+ }
+ return 0;
+}
+
+/* --------------------------- memalign support -------------------------- */
+
+static void* internal_memalign(mstate m, size_t alignment, size_t bytes) {
+ if (alignment <= MALLOC_ALIGNMENT) /* Can just use malloc */
+ return internal_malloc(m, bytes);
+ if (alignment < MIN_CHUNK_SIZE) /* must be at least a minimum chunk size */
+ alignment = MIN_CHUNK_SIZE;
+ if ((alignment & (alignment-SIZE_T_ONE)) != 0) {/* Ensure a power of 2 */
+ size_t a = MALLOC_ALIGNMENT << 1;
+ while (a < alignment) a <<= 1;
+ alignment = a;
+ }
+
+ if (bytes >= MAX_REQUEST - alignment) {
+ if (m != 0) { /* Test isn't needed but avoids compiler warning */
+ MALLOC_FAILURE_ACTION;
+ }
+ }
+ else {
+ size_t nb = request2size(bytes);
+ size_t req = nb + alignment + MIN_CHUNK_SIZE - CHUNK_OVERHEAD;
+ char* mem = (char*)internal_malloc(m, req);
+ if (mem != 0) {
+ void* leader = 0;
+ void* trailer = 0;
+ mchunkptr p = mem2chunk(mem);
+
+ if (PREACTION(m)) return 0;
+ if ((((size_t)(mem)) % alignment) != 0) { /* misaligned */
+ /*
+ Find an aligned spot inside chunk. Since we need to give
+ back leading space in a chunk of at least MIN_CHUNK_SIZE, if
+ the first calculation places us at a spot with less than
+ MIN_CHUNK_SIZE leader, we can move to the next aligned spot.
+ We've allocated enough total room so that this is always
+ possible.
+ */
+ char* br = (char*)mem2chunk((size_t)(((size_t)(mem +
+ alignment -
+ SIZE_T_ONE)) &
+ -alignment));
+ char* pos = ((size_t)(br - (char*)(p)) >= MIN_CHUNK_SIZE)?
+ br : br+alignment;
+ mchunkptr newp = (mchunkptr)pos;
+ size_t leadsize = pos - (char*)(p);
+ size_t newsize = chunksize(p) - leadsize;
+
+ if (is_mmapped(p)) { /* For mmapped chunks, just adjust offset */
+ newp->prev_foot = p->prev_foot + leadsize;
+ newp->head = newsize;
+ }
+ else { /* Otherwise, give back leader, use the rest */
+ set_inuse(m, newp, newsize);
+ set_inuse(m, p, leadsize);
+ leader = chunk2mem(p);
+ }
+ p = newp;
+ }
+
+ /* Give back spare room at the end */
+ if (!is_mmapped(p)) {
+ size_t size = chunksize(p);
+ if (size > nb + MIN_CHUNK_SIZE) {
+ size_t remainder_size = size - nb;
+ mchunkptr remainder = chunk_plus_offset(p, nb);
+ set_inuse(m, p, nb);
+ set_inuse(m, remainder, remainder_size);
+ trailer = chunk2mem(remainder);
+ }
+ }
+
+ assert (chunksize(p) >= nb);
+ assert((((size_t)(chunk2mem(p))) % alignment) == 0);
+ check_inuse_chunk(m, p);
+ POSTACTION(m);
+ if (leader != 0) {
+ internal_free(m, leader);
+ }
+ if (trailer != 0) {
+ internal_free(m, trailer);
+ }
+ return chunk2mem(p);
+ }
+ }
+ return 0;
+}
+
+/* ------------------------ comalloc/coalloc support --------------------- */
+
+static void** ialloc(mstate m,
+ size_t n_elements,
+ size_t* sizes,
+ int opts,
+ void* chunks[]) {
+ /*
+ This provides common support for independent_X routines, handling
+ all of the combinations that can result.
+
+ The opts arg has:
+ bit 0 set if all elements are same size (using sizes[0])
+ bit 1 set if elements should be zeroed
+ */
+
+ size_t element_size; /* chunksize of each element, if all same */
+ size_t contents_size; /* total size of elements */
+ size_t array_size; /* request size of pointer array */
+ void* mem; /* malloced aggregate space */
+ mchunkptr p; /* corresponding chunk */
+ size_t remainder_size; /* remaining bytes while splitting */
+ void** marray; /* either "chunks" or malloced ptr array */
+ mchunkptr array_chunk; /* chunk for malloced ptr array */
+ flag_t was_enabled; /* to disable mmap */
+ size_t size;
+ size_t i;
+
+ ensure_initialization();
+ /* compute array length, if needed */
+ if (chunks != 0) {
+ if (n_elements == 0)
+ return chunks; /* nothing to do */
+ marray = chunks;
+ array_size = 0;
+ }
+ else {
+ /* if empty req, must still return chunk representing empty array */
+ if (n_elements == 0)
+ return (void**)internal_malloc(m, 0);
+ marray = 0;
+ array_size = request2size(n_elements * (sizeof(void*)));
+ }
+
+ /* compute total element size */
+ if (opts & 0x1) { /* all-same-size */
+ element_size = request2size(*sizes);
+ contents_size = n_elements * element_size;
+ }
+ else { /* add up all the sizes */
+ element_size = 0;
+ contents_size = 0;
+ for (i = 0; i != n_elements; ++i)
+ contents_size += request2size(sizes[i]);
+ }
+
+ size = contents_size + array_size;
+
+ /*
+ Allocate the aggregate chunk. First disable direct-mmapping so
+ malloc won't use it, since we would not be able to later
+ free/realloc space internal to a segregated mmap region.
+ */
+ was_enabled = use_mmap(m);
+ disable_mmap(m);
+ mem = internal_malloc(m, size - CHUNK_OVERHEAD);
+ if (was_enabled)
+ enable_mmap(m);
+ if (mem == 0)
+ return 0;
+
+ if (PREACTION(m)) return 0;
+ p = mem2chunk(mem);
+ remainder_size = chunksize(p);
+
+ assert(!is_mmapped(p));
+
+ if (opts & 0x2) { /* optionally clear the elements */
+ memset((size_t*)mem, 0, remainder_size - SIZE_T_SIZE - array_size);
+ }
+
+ /* If not provided, allocate the pointer array as final part of chunk */
+ if (marray == 0) {
+ size_t array_chunk_size;
+ array_chunk = chunk_plus_offset(p, contents_size);
+ array_chunk_size = remainder_size - contents_size;
+ marray = (void**) (chunk2mem(array_chunk));
+ set_size_and_pinuse_of_inuse_chunk(m, array_chunk, array_chunk_size);
+ remainder_size = contents_size;
+ }
+
+ /* split out elements */
+ for (i = 0; ; ++i) {
+ marray[i] = chunk2mem(p);
+ if (i != n_elements-1) {
+ if (element_size != 0)
+ size = element_size;
+ else
+ size = request2size(sizes[i]);
+ remainder_size -= size;
+ set_size_and_pinuse_of_inuse_chunk(m, p, size);
+ p = chunk_plus_offset(p, size);
+ }
+ else { /* the final element absorbs any overallocation slop */
+ set_size_and_pinuse_of_inuse_chunk(m, p, remainder_size);
+ break;
+ }
+ }
+
+#if DEBUG
+ if (marray != chunks) {
+ /* final element must have exactly exhausted chunk */
+ if (element_size != 0) {
+ assert(remainder_size == element_size);
+ }
+ else {
+ assert(remainder_size == request2size(sizes[i]));
+ }
+ check_inuse_chunk(m, mem2chunk(marray));
+ }
+ for (i = 0; i != n_elements; ++i)
+ check_inuse_chunk(m, mem2chunk(marray[i]));
+
+#endif /* DEBUG */
+
+ POSTACTION(m);
+ return marray;
+}
+
+
+/* -------------------------- public routines ---------------------------- */
+
+#if !ONLY_MSPACES
+
+void* dlmalloc(size_t bytes) {
+ /*
+ Basic algorithm:
+ If a small request (< 256 bytes minus per-chunk overhead):
+ 1. If one exists, use a remainderless chunk in associated smallbin.
+ (Remainderless means that there are too few excess bytes to
+ represent as a chunk.)
+ 2. If it is big enough, use the dv chunk, which is normally the
+ chunk adjacent to the one used for the most recent small request.
+ 3. If one exists, split the smallest available chunk in a bin,
+ saving remainder in dv.
+ 4. If it is big enough, use the top chunk.
+ 5. If available, get memory from system and use it
+ Otherwise, for a large request:
+ 1. Find the smallest available binned chunk that fits, and use it
+ if it is better fitting than dv chunk, splitting if necessary.
+ 2. If better fitting than any binned chunk, use the dv chunk.
+ 3. If it is big enough, use the top chunk.
+ 4. If request size >= mmap threshold, try to directly mmap this chunk.
+ 5. If available, get memory from system and use it
+
+ The ugly goto's here ensure that postaction occurs along all paths.
+ */
+
+#if USE_LOCKS
+ ensure_initialization(); /* initialize in sys_alloc if not using locks */
+#endif
+
+ if (!PREACTION(gm)) {
+ void* mem;
+ size_t nb;
+ if (bytes <= MAX_SMALL_REQUEST) {
+ bindex_t idx;
+ binmap_t smallbits;
+ nb = (bytes < MIN_REQUEST)? MIN_CHUNK_SIZE : pad_request(bytes);
+ idx = small_index(nb);
+ smallbits = gm->smallmap >> idx;
+
+ if ((smallbits & 0x3U) != 0) { /* Remainderless fit to a smallbin. */
+ mchunkptr b, p;
+ idx += ~smallbits & 1; /* Uses next bin if idx empty */
+ b = smallbin_at(gm, idx);
+ p = b->fd;
+ assert(chunksize(p) == small_index2size(idx));
+ unlink_first_small_chunk(gm, b, p, idx);
+ set_inuse_and_pinuse(gm, p, small_index2size(idx));
+ mem = chunk2mem(p);
+ check_malloced_chunk(gm, mem, nb);
+ goto postaction;
+ }
+
+ else if (nb > gm->dvsize) {
+ if (smallbits != 0) { /* Use chunk in next nonempty smallbin */
+ mchunkptr b, p, r;
+ size_t rsize;
+ bindex_t i;
+ binmap_t leftbits = (smallbits << idx) & left_bits(idx2bit(idx));
+ binmap_t leastbit = least_bit(leftbits);
+ compute_bit2idx(leastbit, i);
+ b = smallbin_at(gm, i);
+ p = b->fd;
+ assert(chunksize(p) == small_index2size(i));
+ unlink_first_small_chunk(gm, b, p, i);
+ rsize = small_index2size(i) - nb;
+ /* Fit here cannot be remainderless if 4byte sizes */
+ if (SIZE_T_SIZE != 4 && rsize < MIN_CHUNK_SIZE)
+ set_inuse_and_pinuse(gm, p, small_index2size(i));
+ else {
+ set_size_and_pinuse_of_inuse_chunk(gm, p, nb);
+ r = chunk_plus_offset(p, nb);
+ set_size_and_pinuse_of_free_chunk(r, rsize);
+ replace_dv(gm, r, rsize);
+ }
+ mem = chunk2mem(p);
+ check_malloced_chunk(gm, mem, nb);
+ goto postaction;
+ }
+
+ else if (gm->treemap != 0 && (mem = tmalloc_small(gm, nb)) != 0) {
+ check_malloced_chunk(gm, mem, nb);
+ goto postaction;
+ }
+ }
+ }
+ else if (bytes >= MAX_REQUEST)
+ nb = MAX_SIZE_T; /* Too big to allocate. Force failure (in sys alloc) */
+ else {
+ nb = pad_request(bytes);
+ if (gm->treemap != 0 && (mem = tmalloc_large(gm, nb)) != 0) {
+ check_malloced_chunk(gm, mem, nb);
+ goto postaction;
+ }
+ }
+
+ if (nb <= gm->dvsize) {
+ size_t rsize = gm->dvsize - nb;
+ mchunkptr p = gm->dv;
+ if (rsize >= MIN_CHUNK_SIZE) { /* split dv */
+ mchunkptr r = gm->dv = chunk_plus_offset(p, nb);
+ gm->dvsize = rsize;
+ set_size_and_pinuse_of_free_chunk(r, rsize);
+ set_size_and_pinuse_of_inuse_chunk(gm, p, nb);
+ }
+ else { /* exhaust dv */
+ size_t dvs = gm->dvsize;
+ gm->dvsize = 0;
+ gm->dv = 0;
+ set_inuse_and_pinuse(gm, p, dvs);
+ }
+ mem = chunk2mem(p);
+ check_malloced_chunk(gm, mem, nb);
+ goto postaction;
+ }
+
+ else if (nb < gm->topsize) { /* Split top */
+ size_t rsize = gm->topsize -= nb;
+ mchunkptr p = gm->top;
+ mchunkptr r = gm->top = chunk_plus_offset(p, nb);
+ r->head = rsize | PINUSE_BIT;
+ set_size_and_pinuse_of_inuse_chunk(gm, p, nb);
+ mem = chunk2mem(p);
+ check_top_chunk(gm, gm->top);
+ check_malloced_chunk(gm, mem, nb);
+ goto postaction;
+ }
+
+ mem = sys_alloc(gm, nb);
+
+ postaction:
+ POSTACTION(gm);
+ return mem;
+ }
+
+ return 0;
+}
+
+void dlfree(void* mem) {
+ /*
+ Consolidate freed chunks with preceeding or succeeding bordering
+ free chunks, if they exist, and then place in a bin. Intermixed
+ with special cases for top, dv, mmapped chunks, and usage errors.
+ */
+
+ if (mem != 0) {
+ mchunkptr p = mem2chunk(mem);
+#if FOOTERS
+ mstate fm = get_mstate_for(p);
+ if (!ok_magic(fm)) {
+ USAGE_ERROR_ACTION(fm, p);
+ return;
+ }
+#else /* FOOTERS */
+#define fm gm
+#endif /* FOOTERS */
+ if (!PREACTION(fm)) {
+ check_inuse_chunk(fm, p);
+ if (RTCHECK(ok_address(fm, p) && ok_inuse(p))) {
+ size_t psize = chunksize(p);
+ mchunkptr next = chunk_plus_offset(p, psize);
+ if (!pinuse(p)) {
+ size_t prevsize = p->prev_foot;
+ if (is_mmapped(p)) {
+ psize += prevsize + MMAP_FOOT_PAD;
+ if (CALL_MUNMAP((char*)p - prevsize, psize) == 0)
+ fm->footprint -= psize;
+ goto postaction;
+ }
+ else {
+ mchunkptr prev = chunk_minus_offset(p, prevsize);
+ psize += prevsize;
+ p = prev;
+ if (RTCHECK(ok_address(fm, prev))) { /* consolidate backward */
+ if (p != fm->dv) {
+ unlink_chunk(fm, p, prevsize);
+ }
+ else if ((next->head & INUSE_BITS) == INUSE_BITS) {
+ fm->dvsize = psize;
+ set_free_with_pinuse(p, psize, next);
+ goto postaction;
+ }
+ }
+ else
+ goto erroraction;
+ }
+ }
+
+ if (RTCHECK(ok_next(p, next) && ok_pinuse(next))) {
+ if (!cinuse(next)) { /* consolidate forward */
+ if (next == fm->top) {
+ size_t tsize = fm->topsize += psize;
+ fm->top = p;
+ p->head = tsize | PINUSE_BIT;
+ if (p == fm->dv) {
+ fm->dv = 0;
+ fm->dvsize = 0;
+ }
+ if (should_trim(fm, tsize))
+ sys_trim(fm, 0);
+ goto postaction;
+ }
+ else if (next == fm->dv) {
+ size_t dsize = fm->dvsize += psize;
+ fm->dv = p;
+ set_size_and_pinuse_of_free_chunk(p, dsize);
+ goto postaction;
+ }
+ else {
+ size_t nsize = chunksize(next);
+ psize += nsize;
+ unlink_chunk(fm, next, nsize);
+ set_size_and_pinuse_of_free_chunk(p, psize);
+ if (p == fm->dv) {
+ fm->dvsize = psize;
+ goto postaction;
+ }
+ }
+ }
+ else
+ set_free_with_pinuse(p, psize, next);
+
+ if (is_small(psize)) {
+ insert_small_chunk(fm, p, psize);
+ check_free_chunk(fm, p);
+ }
+ else {
+ tchunkptr tp = (tchunkptr)p;
+ insert_large_chunk(fm, tp, psize);
+ check_free_chunk(fm, p);
+ if (--fm->release_checks == 0)
+ release_unused_segments(fm);
+ }
+ goto postaction;
+ }
+ }
+ erroraction:
+ USAGE_ERROR_ACTION(fm, p);
+ postaction:
+ POSTACTION(fm);
+ }
+ }
+#if !FOOTERS
+#undef fm
+#endif /* FOOTERS */
+}
+
+void* dlcalloc(size_t n_elements, size_t elem_size) {
+ void* mem;
+ size_t req = 0;
+ if (n_elements != 0) {
+ req = n_elements * elem_size;
+ if (((n_elements | elem_size) & ~(size_t)0xffff) &&
+ (req / n_elements != elem_size))
+ req = MAX_SIZE_T; /* force downstream failure on overflow */
+ }
+ mem = dlmalloc(req);
+ if (mem != 0 && calloc_must_clear(mem2chunk(mem)))
+ memset(mem, 0, req);
+ return mem;
+}
+
+void* dlrealloc(void* oldmem, size_t bytes) {
+ if (oldmem == 0)
+ return dlmalloc(bytes);
+#ifdef REALLOC_ZERO_BYTES_FREES
+ if (bytes == 0) {
+ dlfree(oldmem);
+ return 0;
+ }
+#endif /* REALLOC_ZERO_BYTES_FREES */
+ else {
+#if ! FOOTERS
+ mstate m = gm;
+#else /* FOOTERS */
+ mstate m = get_mstate_for(mem2chunk(oldmem));
+ if (!ok_magic(m)) {
+ USAGE_ERROR_ACTION(m, oldmem);
+ return 0;
+ }
+#endif /* FOOTERS */
+ return internal_realloc(m, oldmem, bytes);
+ }
+}
+
+void* dlmemalign(size_t alignment, size_t bytes) {
+ return internal_memalign(gm, alignment, bytes);
+}
+
+void** dlindependent_calloc(size_t n_elements, size_t elem_size,
+ void* chunks[]) {
+ size_t sz = elem_size; /* serves as 1-element array */
+ return ialloc(gm, n_elements, &sz, 3, chunks);
+}
+
+void** dlindependent_comalloc(size_t n_elements, size_t sizes[],
+ void* chunks[]) {
+ return ialloc(gm, n_elements, sizes, 0, chunks);
+}
+
+void* dlvalloc(size_t bytes) {
+ size_t pagesz;
+ ensure_initialization();
+ pagesz = mparams.page_size;
+ return dlmemalign(pagesz, bytes);
+}
+
+void* dlpvalloc(size_t bytes) {
+ size_t pagesz;
+ ensure_initialization();
+ pagesz = mparams.page_size;
+ return dlmemalign(pagesz, (bytes + pagesz - SIZE_T_ONE) & ~(pagesz - SIZE_T_ONE));
+}
+
+int dlmalloc_trim(size_t pad) {
+ int result = 0;
+ ensure_initialization();
+ if (!PREACTION(gm)) {
+ result = sys_trim(gm, pad);
+ POSTACTION(gm);
+ }
+ return result;
+}
+
+size_t dlmalloc_footprint(void) {
+ return gm->footprint;
+}
+
+size_t dlmalloc_max_footprint(void) {
+ return gm->max_footprint;
+}
+
+#if !NO_MALLINFO
+struct mallinfo dlmallinfo(void) {
+ return internal_mallinfo(gm);
+}
+#endif /* NO_MALLINFO */
+
+void dlmalloc_stats() {
+ internal_malloc_stats(gm);
+}
+
+int dlmallopt(int param_number, int value) {
+ return change_mparam(param_number, value);
+}
+
+#endif /* !ONLY_MSPACES */
+
+size_t dlmalloc_usable_size(void* mem) {
+ if (mem != 0) {
+ mchunkptr p = mem2chunk(mem);
+ if (is_inuse(p))
+ return chunksize(p) - overhead_for(p);
+ }
+ return 0;
+}
+
+/* ----------------------------- user mspaces ---------------------------- */
+
+#if MSPACES
+
+static mstate init_user_mstate(char* tbase, size_t tsize) {
+ size_t msize = pad_request(sizeof(struct malloc_state));
+ mchunkptr mn;
+ mchunkptr msp = align_as_chunk(tbase);
+ mstate m = (mstate)(chunk2mem(msp));
+ memset(m, 0, msize);
+ INITIAL_LOCK(&m->mutex);
+ msp->head = (msize|INUSE_BITS);
+ m->seg.base = m->least_addr = tbase;
+ m->seg.size = m->footprint = m->max_footprint = tsize;
+ m->magic = mparams.magic;
+ m->release_checks = MAX_RELEASE_CHECK_RATE;
+ m->mflags = mparams.default_mflags;
+ m->extp = 0;
+ m->exts = 0;
+ disable_contiguous(m);
+ init_bins(m);
+ mn = next_chunk(mem2chunk(m));
+ init_top(m, mn, (size_t)((tbase + tsize) - (char*)mn) - TOP_FOOT_SIZE);
+ check_top_chunk(m, m->top);
+ return m;
+}
+
+mspace create_mspace(size_t capacity, int locked) {
+ mstate m = 0;
+ size_t msize;
+ ensure_initialization();
+ msize = pad_request(sizeof(struct malloc_state));
+ if (capacity < (size_t) -(msize + TOP_FOOT_SIZE + mparams.page_size)) {
+ size_t rs = ((capacity == 0)? mparams.granularity :
+ (capacity + TOP_FOOT_SIZE + msize));
+ size_t tsize = granularity_align(rs);
+ char* tbase = (char*)(CALL_MMAP(tsize));
+ if (tbase != CMFAIL) {
+ m = init_user_mstate(tbase, tsize);
+ m->seg.sflags = USE_MMAP_BIT;
+ set_lock(m, locked);
+ }
+ }
+ return (mspace)m;
+}
+
+mspace create_mspace_with_base(void* base, size_t capacity, int locked) {
+ mstate m = 0;
+ size_t msize;
+ ensure_initialization();
+ msize = pad_request(sizeof(struct malloc_state));
+ if (capacity > msize + TOP_FOOT_SIZE &&
+ capacity < (size_t) -(msize + TOP_FOOT_SIZE + mparams.page_size)) {
+ m = init_user_mstate((char*)base, capacity);
+ m->seg.sflags = EXTERN_BIT;
+ set_lock(m, locked);
+ }
+ return (mspace)m;
+}
+
+int mspace_track_large_chunks(mspace msp, int enable) {
+ int ret = 0;
+ mstate ms = (mstate)msp;
+ if (!PREACTION(ms)) {
+ if (!use_mmap(ms))
+ ret = 1;
+ if (!enable)
+ enable_mmap(ms);
+ else
+ disable_mmap(ms);
+ POSTACTION(ms);
+ }
+ return ret;
+}
+
+size_t destroy_mspace(mspace msp) {
+ size_t freed = 0;
+ mstate ms = (mstate)msp;
+ if (ok_magic(ms)) {
+ msegmentptr sp = &ms->seg;
+ while (sp != 0) {
+ char* base = sp->base;
+ size_t size = sp->size;
+ flag_t flag = sp->sflags;
+ sp = sp->next;
+ if ((flag & USE_MMAP_BIT) && !(flag & EXTERN_BIT) &&
+ CALL_MUNMAP(base, size) == 0)
+ freed += size;
+ }
+ }
+ else {
+ USAGE_ERROR_ACTION(ms,ms);
+ }
+ return freed;
+}
+
+/*
+ mspace versions of routines are near-clones of the global
+ versions. This is not so nice but better than the alternatives.
+*/
+
+
+void* mspace_malloc(mspace msp, size_t bytes) {
+ mstate ms = (mstate)msp;
+ if (!ok_magic(ms)) {
+ USAGE_ERROR_ACTION(ms,ms);
+ return 0;
+ }
+ if (!PREACTION(ms)) {
+ void* mem;
+ size_t nb;
+ if (bytes <= MAX_SMALL_REQUEST) {
+ bindex_t idx;
+ binmap_t smallbits;
+ nb = (bytes < MIN_REQUEST)? MIN_CHUNK_SIZE : pad_request(bytes);
+ idx = small_index(nb);
+ smallbits = ms->smallmap >> idx;
+
+ if ((smallbits & 0x3U) != 0) { /* Remainderless fit to a smallbin. */
+ mchunkptr b, p;
+ idx += ~smallbits & 1; /* Uses next bin if idx empty */
+ b = smallbin_at(ms, idx);
+ p = b->fd;
+ assert(chunksize(p) == small_index2size(idx));
+ unlink_first_small_chunk(ms, b, p, idx);
+ set_inuse_and_pinuse(ms, p, small_index2size(idx));
+ mem = chunk2mem(p);
+ check_malloced_chunk(ms, mem, nb);
+ goto postaction;
+ }
+
+ else if (nb > ms->dvsize) {
+ if (smallbits != 0) { /* Use chunk in next nonempty smallbin */
+ mchunkptr b, p, r;
+ size_t rsize;
+ bindex_t i;
+ binmap_t leftbits = (smallbits << idx) & left_bits(idx2bit(idx));
+ binmap_t leastbit = least_bit(leftbits);
+ compute_bit2idx(leastbit, i);
+ b = smallbin_at(ms, i);
+ p = b->fd;
+ assert(chunksize(p) == small_index2size(i));
+ unlink_first_small_chunk(ms, b, p, i);
+ rsize = small_index2size(i) - nb;
+ /* Fit here cannot be remainderless if 4byte sizes */
+ if (SIZE_T_SIZE != 4 && rsize < MIN_CHUNK_SIZE)
+ set_inuse_and_pinuse(ms, p, small_index2size(i));
+ else {
+ set_size_and_pinuse_of_inuse_chunk(ms, p, nb);
+ r = chunk_plus_offset(p, nb);
+ set_size_and_pinuse_of_free_chunk(r, rsize);
+ replace_dv(ms, r, rsize);
+ }
+ mem = chunk2mem(p);
+ check_malloced_chunk(ms, mem, nb);
+ goto postaction;
+ }
+
+ else if (ms->treemap != 0 && (mem = tmalloc_small(ms, nb)) != 0) {
+ check_malloced_chunk(ms, mem, nb);
+ goto postaction;
+ }
+ }
+ }
+ else if (bytes >= MAX_REQUEST)
+ nb = MAX_SIZE_T; /* Too big to allocate. Force failure (in sys alloc) */
+ else {
+ nb = pad_request(bytes);
+ if (ms->treemap != 0 && (mem = tmalloc_large(ms, nb)) != 0) {
+ check_malloced_chunk(ms, mem, nb);
+ goto postaction;
+ }
+ }
+
+ if (nb <= ms->dvsize) {
+ size_t rsize = ms->dvsize - nb;
+ mchunkptr p = ms->dv;
+ if (rsize >= MIN_CHUNK_SIZE) { /* split dv */
+ mchunkptr r = ms->dv = chunk_plus_offset(p, nb);
+ ms->dvsize = rsize;
+ set_size_and_pinuse_of_free_chunk(r, rsize);
+ set_size_and_pinuse_of_inuse_chunk(ms, p, nb);
+ }
+ else { /* exhaust dv */
+ size_t dvs = ms->dvsize;
+ ms->dvsize = 0;
+ ms->dv = 0;
+ set_inuse_and_pinuse(ms, p, dvs);
+ }
+ mem = chunk2mem(p);
+ check_malloced_chunk(ms, mem, nb);
+ goto postaction;
+ }
+
+ else if (nb < ms->topsize) { /* Split top */
+ size_t rsize = ms->topsize -= nb;
+ mchunkptr p = ms->top;
+ mchunkptr r = ms->top = chunk_plus_offset(p, nb);
+ r->head = rsize | PINUSE_BIT;
+ set_size_and_pinuse_of_inuse_chunk(ms, p, nb);
+ mem = chunk2mem(p);
+ check_top_chunk(ms, ms->top);
+ check_malloced_chunk(ms, mem, nb);
+ goto postaction;
+ }
+
+ mem = sys_alloc(ms, nb);
+
+ postaction:
+ POSTACTION(ms);
+ return mem;
+ }
+
+ return 0;
+}
+
+void mspace_free(mspace msp, void* mem) {
+ if (mem != 0) {
+ mchunkptr p = mem2chunk(mem);
+#if FOOTERS
+ mstate fm = get_mstate_for(p);
+ msp = msp; /* placate people compiling -Wunused */
+#else /* FOOTERS */
+ mstate fm = (mstate)msp;
+#endif /* FOOTERS */
+ if (!ok_magic(fm)) {
+ USAGE_ERROR_ACTION(fm, p);
+ return;
+ }
+ if (!PREACTION(fm)) {
+ check_inuse_chunk(fm, p);
+ if (RTCHECK(ok_address(fm, p) && ok_inuse(p))) {
+ size_t psize = chunksize(p);
+ mchunkptr next = chunk_plus_offset(p, psize);
+ if (!pinuse(p)) {
+ size_t prevsize = p->prev_foot;
+ if (is_mmapped(p)) {
+ psize += prevsize + MMAP_FOOT_PAD;
+ if (CALL_MUNMAP((char*)p - prevsize, psize) == 0)
+ fm->footprint -= psize;
+ goto postaction;
+ }
+ else {
+ mchunkptr prev = chunk_minus_offset(p, prevsize);
+ psize += prevsize;
+ p = prev;
+ if (RTCHECK(ok_address(fm, prev))) { /* consolidate backward */
+ if (p != fm->dv) {
+ unlink_chunk(fm, p, prevsize);
+ }
+ else if ((next->head & INUSE_BITS) == INUSE_BITS) {
+ fm->dvsize = psize;
+ set_free_with_pinuse(p, psize, next);
+ goto postaction;
+ }
+ }
+ else
+ goto erroraction;
+ }
+ }
+
+ if (RTCHECK(ok_next(p, next) && ok_pinuse(next))) {
+ if (!cinuse(next)) { /* consolidate forward */
+ if (next == fm->top) {
+ size_t tsize = fm->topsize += psize;
+ fm->top = p;
+ p->head = tsize | PINUSE_BIT;
+ if (p == fm->dv) {
+ fm->dv = 0;
+ fm->dvsize = 0;
+ }
+ if (should_trim(fm, tsize))
+ sys_trim(fm, 0);
+ goto postaction;
+ }
+ else if (next == fm->dv) {
+ size_t dsize = fm->dvsize += psize;
+ fm->dv = p;
+ set_size_and_pinuse_of_free_chunk(p, dsize);
+ goto postaction;
+ }
+ else {
+ size_t nsize = chunksize(next);
+ psize += nsize;
+ unlink_chunk(fm, next, nsize);
+ set_size_and_pinuse_of_free_chunk(p, psize);
+ if (p == fm->dv) {
+ fm->dvsize = psize;
+ goto postaction;
+ }
+ }
+ }
+ else
+ set_free_with_pinuse(p, psize, next);
+
+ if (is_small(psize)) {
+ insert_small_chunk(fm, p, psize);
+ check_free_chunk(fm, p);
+ }
+ else {
+ tchunkptr tp = (tchunkptr)p;
+ insert_large_chunk(fm, tp, psize);
+ check_free_chunk(fm, p);
+ if (--fm->release_checks == 0)
+ release_unused_segments(fm);
+ }
+ goto postaction;
+ }
+ }
+ erroraction:
+ USAGE_ERROR_ACTION(fm, p);
+ postaction:
+ POSTACTION(fm);
+ }
+ }
+}
+
+void* mspace_calloc(mspace msp, size_t n_elements, size_t elem_size) {
+ void* mem;
+ size_t req = 0;
+ mstate ms = (mstate)msp;
+ if (!ok_magic(ms)) {
+ USAGE_ERROR_ACTION(ms,ms);
+ return 0;
+ }
+ if (n_elements != 0) {
+ req = n_elements * elem_size;
+ if (((n_elements | elem_size) & ~(size_t)0xffff) &&
+ (req / n_elements != elem_size))
+ req = MAX_SIZE_T; /* force downstream failure on overflow */
+ }
+ mem = internal_malloc(ms, req);
+ if (mem != 0 && calloc_must_clear(mem2chunk(mem)))
+ memset(mem, 0, req);
+ return mem;
+}
+
+void* mspace_realloc(mspace msp, void* oldmem, size_t bytes) {
+ if (oldmem == 0)
+ return mspace_malloc(msp, bytes);
+#ifdef REALLOC_ZERO_BYTES_FREES
+ if (bytes == 0) {
+ mspace_free(msp, oldmem);
+ return 0;
+ }
+#endif /* REALLOC_ZERO_BYTES_FREES */
+ else {
+#if FOOTERS
+ mchunkptr p = mem2chunk(oldmem);
+ mstate ms = get_mstate_for(p);
+#else /* FOOTERS */
+ mstate ms = (mstate)msp;
+#endif /* FOOTERS */
+ if (!ok_magic(ms)) {
+ USAGE_ERROR_ACTION(ms,ms);
+ return 0;
+ }
+ return internal_realloc(ms, oldmem, bytes);
+ }
+}
+
+void* mspace_memalign(mspace msp, size_t alignment, size_t bytes) {
+ mstate ms = (mstate)msp;
+ if (!ok_magic(ms)) {
+ USAGE_ERROR_ACTION(ms,ms);
+ return 0;
+ }
+ return internal_memalign(ms, alignment, bytes);
+}
+
+void** mspace_independent_calloc(mspace msp, size_t n_elements,
+ size_t elem_size, void* chunks[]) {
+ size_t sz = elem_size; /* serves as 1-element array */
+ mstate ms = (mstate)msp;
+ if (!ok_magic(ms)) {
+ USAGE_ERROR_ACTION(ms,ms);
+ return 0;
+ }
+ return ialloc(ms, n_elements, &sz, 3, chunks);
+}
+
+void** mspace_independent_comalloc(mspace msp, size_t n_elements,
+ size_t sizes[], void* chunks[]) {
+ mstate ms = (mstate)msp;
+ if (!ok_magic(ms)) {
+ USAGE_ERROR_ACTION(ms,ms);
+ return 0;
+ }
+ return ialloc(ms, n_elements, sizes, 0, chunks);
+}
+
+int mspace_trim(mspace msp, size_t pad) {
+ int result = 0;
+ mstate ms = (mstate)msp;
+ if (ok_magic(ms)) {
+ if (!PREACTION(ms)) {
+ result = sys_trim(ms, pad);
+ POSTACTION(ms);
+ }
+ }
+ else {
+ USAGE_ERROR_ACTION(ms,ms);
+ }
+ return result;
+}
+
+void mspace_malloc_stats(mspace msp) {
+ mstate ms = (mstate)msp;
+ if (ok_magic(ms)) {
+ internal_malloc_stats(ms);
+ }
+ else {
+ USAGE_ERROR_ACTION(ms,ms);
+ }
+}
+
+size_t mspace_footprint(mspace msp) {
+ size_t result = 0;
+ mstate ms = (mstate)msp;
+ if (ok_magic(ms)) {
+ result = ms->footprint;
+ }
+ else {
+ USAGE_ERROR_ACTION(ms,ms);
+ }
+ return result;
+}
+
+
+size_t mspace_max_footprint(mspace msp) {
+ size_t result = 0;
+ mstate ms = (mstate)msp;
+ if (ok_magic(ms)) {
+ result = ms->max_footprint;
+ }
+ else {
+ USAGE_ERROR_ACTION(ms,ms);
+ }
+ return result;
+}
+
+
+#if !NO_MALLINFO
+struct mallinfo mspace_mallinfo(mspace msp) {
+ mstate ms = (mstate)msp;
+ if (!ok_magic(ms)) {
+ USAGE_ERROR_ACTION(ms,ms);
+ }
+ return internal_mallinfo(ms);
+}
+#endif /* NO_MALLINFO */
+
+size_t mspace_usable_size(void* mem) {
+ if (mem != 0) {
+ mchunkptr p = mem2chunk(mem);
+ if (is_inuse(p))
+ return chunksize(p) - overhead_for(p);
+ }
+ return 0;
+}
+
+int mspace_mallopt(int param_number, int value) {
+ return change_mparam(param_number, value);
+}
+
+#endif /* MSPACES */
+
+
+/* -------------------- Alternative MORECORE functions ------------------- */
+
+/*
+ Guidelines for creating a custom version of MORECORE:
+
+ * For best performance, MORECORE should allocate in multiples of pagesize.
+ * MORECORE may allocate more memory than requested. (Or even less,
+ but this will usually result in a malloc failure.)
+ * MORECORE must not allocate memory when given argument zero, but
+ instead return one past the end address of memory from previous
+ nonzero call.
+ * For best performance, consecutive calls to MORECORE with positive
+ arguments should return increasing addresses, indicating that
+ space has been contiguously extended.
+ * Even though consecutive calls to MORECORE need not return contiguous
+ addresses, it must be OK for malloc'ed chunks to span multiple
+ regions in those cases where they do happen to be contiguous.
+ * MORECORE need not handle negative arguments -- it may instead
+ just return MFAIL when given negative arguments.
+ Negative arguments are always multiples of pagesize. MORECORE
+ must not misinterpret negative args as large positive unsigned
+ args. You can suppress all such calls from even occurring by defining
+ MORECORE_CANNOT_TRIM,
+
+ As an example alternative MORECORE, here is a custom allocator
+ kindly contributed for pre-OSX macOS. It uses virtually but not
+ necessarily physically contiguous non-paged memory (locked in,
+ present and won't get swapped out). You can use it by uncommenting
+ this section, adding some #includes, and setting up the appropriate
+ defines above:
+
+ #define MORECORE osMoreCore
+
+ There is also a shutdown routine that should somehow be called for
+ cleanup upon program exit.
+
+ #define MAX_POOL_ENTRIES 100
+ #define MINIMUM_MORECORE_SIZE (64 * 1024U)
+ static int next_os_pool;
+ void *our_os_pools[MAX_POOL_ENTRIES];
+
+ void *osMoreCore(int size)
+ {
+ void *ptr = 0;
+ static void *sbrk_top = 0;
+
+ if (size > 0)
+ {
+ if (size < MINIMUM_MORECORE_SIZE)
+ size = MINIMUM_MORECORE_SIZE;
+ if (CurrentExecutionLevel() == kTaskLevel)
+ ptr = PoolAllocateResident(size + RM_PAGE_SIZE, 0);
+ if (ptr == 0)
+ {
+ return (void *) MFAIL;
+ }
+ // save ptrs so they can be freed during cleanup
+ our_os_pools[next_os_pool] = ptr;
+ next_os_pool++;
+ ptr = (void *) ((((size_t) ptr) + RM_PAGE_MASK) & ~RM_PAGE_MASK);
+ sbrk_top = (char *) ptr + size;
+ return ptr;
+ }
+ else if (size < 0)
+ {
+ // we don't currently support shrink behavior
+ return (void *) MFAIL;
+ }
+ else
+ {
+ return sbrk_top;
+ }
+ }
+
+ // cleanup any allocated memory pools
+ // called as last thing before shutting down driver
+
+ void osCleanupMem(void)
+ {
+ void **ptr;
+
+ for (ptr = our_os_pools; ptr < &our_os_pools[MAX_POOL_ENTRIES]; ptr++)
+ if (*ptr)
+ {
+ PoolDeallocate(*ptr);
+ *ptr = 0;
+ }
+ }
+
+*/
+
+
+/* -----------------------------------------------------------------------
+History:
+ V2.8.4 Wed May 27 09:56:23 2009 Doug Lea (dl at gee)
+ * Use zeros instead of prev foot for is_mmapped
+ * Add mspace_track_large_chunks; thanks to Jean Brouwers
+ * Fix set_inuse in internal_realloc; thanks to Jean Brouwers
+ * Fix insufficient sys_alloc padding when using 16byte alignment
+ * Fix bad error check in mspace_footprint
+ * Adaptations for ptmalloc; thanks to Wolfram Gloger.
+ * Reentrant spin locks; thanks to Earl Chew and others
+ * Win32 improvements; thanks to Niall Douglas and Earl Chew
+ * Add NO_SEGMENT_TRAVERSAL and MAX_RELEASE_CHECK_RATE options
+ * Extension hook in malloc_state
+ * Various small adjustments to reduce warnings on some compilers
+ * Various configuration extensions/changes for more platforms. Thanks
+ to all who contributed these.
+
+ V2.8.3 Thu Sep 22 11:16:32 2005 Doug Lea (dl at gee)
+ * Add max_footprint functions
+ * Ensure all appropriate literals are size_t
+ * Fix conditional compilation problem for some #define settings
+ * Avoid concatenating segments with the one provided
+ in create_mspace_with_base
+ * Rename some variables to avoid compiler shadowing warnings
+ * Use explicit lock initialization.
+ * Better handling of sbrk interference.
+ * Simplify and fix segment insertion, trimming and mspace_destroy
+ * Reinstate REALLOC_ZERO_BYTES_FREES option from 2.7.x
+ * Thanks especially to Dennis Flanagan for help on these.
+
+ V2.8.2 Sun Jun 12 16:01:10 2005 Doug Lea (dl at gee)
+ * Fix memalign brace error.
+
+ V2.8.1 Wed Jun 8 16:11:46 2005 Doug Lea (dl at gee)
+ * Fix improper #endif nesting in C++
+ * Add explicit casts needed for C++
+
+ V2.8.0 Mon May 30 14:09:02 2005 Doug Lea (dl at gee)
+ * Use trees for large bins
+ * Support mspaces
+ * Use segments to unify sbrk-based and mmap-based system allocation,
+ removing need for emulation on most platforms without sbrk.
+ * Default safety checks
+ * Optional footer checks. Thanks to William Robertson for the idea.
+ * Internal code refactoring
+ * Incorporate suggestions and platform-specific changes.
+ Thanks to Dennis Flanagan, Colin Plumb, Niall Douglas,
+ Aaron Bachmann, Emery Berger, and others.
+ * Speed up non-fastbin processing enough to remove fastbins.
+ * Remove useless cfree() to avoid conflicts with other apps.
+ * Remove internal memcpy, memset. Compilers handle builtins better.
+ * Remove some options that no one ever used and rename others.
+
+ V2.7.2 Sat Aug 17 09:07:30 2002 Doug Lea (dl at gee)
+ * Fix malloc_state bitmap array misdeclaration
+
+ V2.7.1 Thu Jul 25 10:58:03 2002 Doug Lea (dl at gee)
+ * Allow tuning of FIRST_SORTED_BIN_SIZE
+ * Use PTR_UINT as type for all ptr->int casts. Thanks to John Belmonte.
+ * Better detection and support for non-contiguousness of MORECORE.
+ Thanks to Andreas Mueller, Conal Walsh, and Wolfram Gloger
+ * Bypass most of malloc if no frees. Thanks To Emery Berger.
+ * Fix freeing of old top non-contiguous chunk im sysmalloc.
+ * Raised default trim and map thresholds to 256K.
+ * Fix mmap-related #defines. Thanks to Lubos Lunak.
+ * Fix copy macros; added LACKS_FCNTL_H. Thanks to Neal Walfield.
+ * Branch-free bin calculation
+ * Default trim and mmap thresholds now 256K.
+
+ V2.7.0 Sun Mar 11 14:14:06 2001 Doug Lea (dl at gee)
+ * Introduce independent_comalloc and independent_calloc.
+ Thanks to Michael Pachos for motivation and help.
+ * Make optional .h file available
+ * Allow > 2GB requests on 32bit systems.
+ * new WIN32 sbrk, mmap, munmap, lock code from <Walter@GeNeSys-e.de>.
+ Thanks also to Andreas Mueller <a.mueller at paradatec.de>,
+ and Anonymous.
+ * Allow override of MALLOC_ALIGNMENT (Thanks to Ruud Waij for
+ helping test this.)
+ * memalign: check alignment arg
+ * realloc: don't try to shift chunks backwards, since this
+ leads to more fragmentation in some programs and doesn't
+ seem to help in any others.
+ * Collect all cases in malloc requiring system memory into sysmalloc
+ * Use mmap as backup to sbrk
+ * Place all internal state in malloc_state
+ * Introduce fastbins (although similar to 2.5.1)
+ * Many minor tunings and cosmetic improvements
+ * Introduce USE_PUBLIC_MALLOC_WRAPPERS, USE_MALLOC_LOCK
+ * Introduce MALLOC_FAILURE_ACTION, MORECORE_CONTIGUOUS
+ Thanks to Tony E. Bennett <tbennett@nvidia.com> and others.
+ * Include errno.h to support default failure action.
+
+ V2.6.6 Sun Dec 5 07:42:19 1999 Doug Lea (dl at gee)
+ * return null for negative arguments
+ * Added Several WIN32 cleanups from Martin C. Fong <mcfong at yahoo.com>
+ * Add 'LACKS_SYS_PARAM_H' for those systems without 'sys/param.h'
+ (e.g. WIN32 platforms)
+ * Cleanup header file inclusion for WIN32 platforms
+ * Cleanup code to avoid Microsoft Visual C++ compiler complaints
+ * Add 'USE_DL_PREFIX' to quickly allow co-existence with existing
+ memory allocation routines
+ * Set 'malloc_getpagesize' for WIN32 platforms (needs more work)
+ * Use 'assert' rather than 'ASSERT' in WIN32 code to conform to
+ usage of 'assert' in non-WIN32 code
+ * Improve WIN32 'sbrk()' emulation's 'findRegion()' routine to
+ avoid infinite loop
+ * Always call 'fREe()' rather than 'free()'
+
+ V2.6.5 Wed Jun 17 15:57:31 1998 Doug Lea (dl at gee)
+ * Fixed ordering problem with boundary-stamping
+
+ V2.6.3 Sun May 19 08:17:58 1996 Doug Lea (dl at gee)
+ * Added pvalloc, as recommended by H.J. Liu
+ * Added 64bit pointer support mainly from Wolfram Gloger
+ * Added anonymously donated WIN32 sbrk emulation
+ * Malloc, calloc, getpagesize: add optimizations from Raymond Nijssen
+ * malloc_extend_top: fix mask error that caused wastage after
+ foreign sbrks
+ * Add linux mremap support code from HJ Liu
+
+ V2.6.2 Tue Dec 5 06:52:55 1995 Doug Lea (dl at gee)
+ * Integrated most documentation with the code.
+ * Add support for mmap, with help from
+ Wolfram Gloger (Gloger@lrz.uni-muenchen.de).
+ * Use last_remainder in more cases.
+ * Pack bins using idea from colin@nyx10.cs.du.edu
+ * Use ordered bins instead of best-fit threshhold
+ * Eliminate block-local decls to simplify tracing and debugging.
+ * Support another case of realloc via move into top
+ * Fix error occuring when initial sbrk_base not word-aligned.
+ * Rely on page size for units instead of SBRK_UNIT to
+ avoid surprises about sbrk alignment conventions.
+ * Add mallinfo, mallopt. Thanks to Raymond Nijssen
+ (raymond@es.ele.tue.nl) for the suggestion.
+ * Add `pad' argument to malloc_trim and top_pad mallopt parameter.
+ * More precautions for cases where other routines call sbrk,
+ courtesy of Wolfram Gloger (Gloger@lrz.uni-muenchen.de).
+ * Added macros etc., allowing use in linux libc from
+ H.J. Lu (hjl@gnu.ai.mit.edu)
+ * Inverted this history list
+
+ V2.6.1 Sat Dec 2 14:10:57 1995 Doug Lea (dl at gee)
+ * Re-tuned and fixed to behave more nicely with V2.6.0 changes.
+ * Removed all preallocation code since under current scheme
+ the work required to undo bad preallocations exceeds
+ the work saved in good cases for most test programs.
+ * No longer use return list or unconsolidated bins since
+ no scheme using them consistently outperforms those that don't
+ given above changes.
+ * Use best fit for very large chunks to prevent some worst-cases.
+ * Added some support for debugging
+
+ V2.6.0 Sat Nov 4 07:05:23 1995 Doug Lea (dl at gee)
+ * Removed footers when chunks are in use. Thanks to
+ Paul Wilson (wilson@cs.texas.edu) for the suggestion.
+
+ V2.5.4 Wed Nov 1 07:54:51 1995 Doug Lea (dl at gee)
+ * Added malloc_trim, with help from Wolfram Gloger
+ (wmglo@Dent.MED.Uni-Muenchen.DE).
+
+ V2.5.3 Tue Apr 26 10:16:01 1994 Doug Lea (dl at g)
+
+ V2.5.2 Tue Apr 5 16:20:40 1994 Doug Lea (dl at g)
+ * realloc: try to expand in both directions
+ * malloc: swap order of clean-bin strategy;
+ * realloc: only conditionally expand backwards
+ * Try not to scavenge used bins
+ * Use bin counts as a guide to preallocation
+ * Occasionally bin return list chunks in first scan
+ * Add a few optimizations from colin@nyx10.cs.du.edu
+
+ V2.5.1 Sat Aug 14 15:40:43 1993 Doug Lea (dl at g)
+ * faster bin computation & slightly different binning
+ * merged all consolidations to one part of malloc proper
+ (eliminating old malloc_find_space & malloc_clean_bin)
+ * Scan 2 returns chunks (not just 1)
+ * Propagate failure in realloc if malloc returns 0
+ * Add stuff to allow compilation on non-ANSI compilers
+ from kpv@research.att.com
+
+ V2.5 Sat Aug 7 07:41:59 1993 Doug Lea (dl at g.oswego.edu)
+ * removed potential for odd address access in prev_chunk
+ * removed dependency on getpagesize.h
+ * misc cosmetics and a bit more internal documentation
+ * anticosmetics: mangled names in macros to evade debugger strangeness
+ * tested on sparc, hp-700, dec-mips, rs6000
+ with gcc & native cc (hp, dec only) allowing
+ Detlefs & Zorn comparison study (in SIGPLAN Notices.)
+
+ Trial version Fri Aug 28 13:14:29 1992 Doug Lea (dl at g.oswego.edu)
+ * Based loosely on libg++-1.2X malloc. (It retains some of the overall
+ structure of old version, but most details differ.)
+
+*/
+
diff --git a/unsupported/test/mpreal/dlmalloc.h b/unsupported/test/mpreal/dlmalloc.h
new file mode 100755
index 000000000..a90dcb6f5
--- /dev/null
+++ b/unsupported/test/mpreal/dlmalloc.h
@@ -0,0 +1,562 @@
+/*
+ Default header file for malloc-2.8.x, written by Doug Lea
+ and released to the public domain, as explained at
+ http://creativecommons.org/licenses/publicdomain.
+
+ last update: Wed May 27 14:25:17 2009 Doug Lea (dl at gee)
+
+ This header is for ANSI C/C++ only. You can set any of
+ the following #defines before including:
+
+ * If USE_DL_PREFIX is defined, it is assumed that malloc.c
+ was also compiled with this option, so all routines
+ have names starting with "dl".
+
+ * If HAVE_USR_INCLUDE_MALLOC_H is defined, it is assumed that this
+ file will be #included AFTER <malloc.h>. This is needed only if
+ your system defines a struct mallinfo that is incompatible with the
+ standard one declared here. Otherwise, you can include this file
+ INSTEAD of your system system <malloc.h>. At least on ANSI, all
+ declarations should be compatible with system versions
+
+ * If MSPACES is defined, declarations for mspace versions are included.
+*/
+
+#ifndef MALLOC_280_H
+#define MALLOC_280_H
+
+#define USE_DL_PREFIX
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <stddef.h> /* for size_t */
+
+#ifndef ONLY_MSPACES
+#define ONLY_MSPACES 0 /* define to a value */
+#endif /* ONLY_MSPACES */
+#ifndef NO_MALLINFO
+#define NO_MALLINFO 0
+#endif /* NO_MALLINFO */
+
+
+#if !ONLY_MSPACES
+
+#ifndef USE_DL_PREFIX
+#define dlcalloc calloc
+#define dlfree free
+#define dlmalloc malloc
+#define dlmemalign memalign
+#define dlrealloc realloc
+#define dlvalloc valloc
+#define dlpvalloc pvalloc
+#define dlmallinfo mallinfo
+#define dlmallopt mallopt
+#define dlmalloc_trim malloc_trim
+#define dlmalloc_stats malloc_stats
+#define dlmalloc_usable_size malloc_usable_size
+#define dlmalloc_footprint malloc_footprint
+#define dlindependent_calloc independent_calloc
+#define dlindependent_comalloc independent_comalloc
+#endif /* USE_DL_PREFIX */
+#if !NO_MALLINFO
+#ifndef HAVE_USR_INCLUDE_MALLOC_H
+#ifndef _MALLOC_H
+#ifndef MALLINFO_FIELD_TYPE
+#define MALLINFO_FIELD_TYPE size_t
+#endif /* MALLINFO_FIELD_TYPE */
+#ifndef STRUCT_MALLINFO_DECLARED
+#define STRUCT_MALLINFO_DECLARED 1
+struct mallinfo {
+ MALLINFO_FIELD_TYPE arena; /* non-mmapped space allocated from system */
+ MALLINFO_FIELD_TYPE ordblks; /* number of free chunks */
+ MALLINFO_FIELD_TYPE smblks; /* always 0 */
+ MALLINFO_FIELD_TYPE hblks; /* always 0 */
+ MALLINFO_FIELD_TYPE hblkhd; /* space in mmapped regions */
+ MALLINFO_FIELD_TYPE usmblks; /* maximum total allocated space */
+ MALLINFO_FIELD_TYPE fsmblks; /* always 0 */
+ MALLINFO_FIELD_TYPE uordblks; /* total allocated space */
+ MALLINFO_FIELD_TYPE fordblks; /* total free space */
+ MALLINFO_FIELD_TYPE keepcost; /* releasable (via malloc_trim) space */
+};
+#endif /* STRUCT_MALLINFO_DECLARED */
+#endif /* _MALLOC_H */
+#endif /* HAVE_USR_INCLUDE_MALLOC_H */
+#endif /* !NO_MALLINFO */
+
+/*
+ malloc(size_t n)
+ Returns a pointer to a newly allocated chunk of at least n bytes, or
+ null if no space is available, in which case errno is set to ENOMEM
+ on ANSI C systems.
+
+ If n is zero, malloc returns a minimum-sized chunk. (The minimum
+ size is 16 bytes on most 32bit systems, and 32 bytes on 64bit
+ systems.) Note that size_t is an unsigned type, so calls with
+ arguments that would be negative if signed are interpreted as
+ requests for huge amounts of space, which will often fail. The
+ maximum supported value of n differs across systems, but is in all
+ cases less than the maximum representable value of a size_t.
+*/
+void* dlmalloc(size_t);
+
+/*
+ free(void* p)
+ Releases the chunk of memory pointed to by p, that had been previously
+ allocated using malloc or a related routine such as realloc.
+ It has no effect if p is null. If p was not malloced or already
+ freed, free(p) will by default cuase the current program to abort.
+*/
+void dlfree(void*);
+
+/*
+ calloc(size_t n_elements, size_t element_size);
+ Returns a pointer to n_elements * element_size bytes, with all locations
+ set to zero.
+*/
+void* dlcalloc(size_t, size_t);
+
+/*
+ realloc(void* p, size_t n)
+ Returns a pointer to a chunk of size n that contains the same data
+ as does chunk p up to the minimum of (n, p's size) bytes, or null
+ if no space is available.
+
+ The returned pointer may or may not be the same as p. The algorithm
+ prefers extending p in most cases when possible, otherwise it
+ employs the equivalent of a malloc-copy-free sequence.
+
+ If p is null, realloc is equivalent to malloc.
+
+ If space is not available, realloc returns null, errno is set (if on
+ ANSI) and p is NOT freed.
+
+ if n is for fewer bytes than already held by p, the newly unused
+ space is lopped off and freed if possible. realloc with a size
+ argument of zero (re)allocates a minimum-sized chunk.
+
+ The old unix realloc convention of allowing the last-free'd chunk
+ to be used as an argument to realloc is not supported.
+*/
+
+void* dlrealloc(void*, size_t);
+
+/*
+ memalign(size_t alignment, size_t n);
+ Returns a pointer to a newly allocated chunk of n bytes, aligned
+ in accord with the alignment argument.
+
+ The alignment argument should be a power of two. If the argument is
+ not a power of two, the nearest greater power is used.
+ 8-byte alignment is guaranteed by normal malloc calls, so don't
+ bother calling memalign with an argument of 8 or less.
+
+ Overreliance on memalign is a sure way to fragment space.
+*/
+void* dlmemalign(size_t, size_t);
+
+/*
+ valloc(size_t n);
+ Equivalent to memalign(pagesize, n), where pagesize is the page
+ size of the system. If the pagesize is unknown, 4096 is used.
+*/
+void* dlvalloc(size_t);
+
+/*
+ mallopt(int parameter_number, int parameter_value)
+ Sets tunable parameters The format is to provide a
+ (parameter-number, parameter-value) pair. mallopt then sets the
+ corresponding parameter to the argument value if it can (i.e., so
+ long as the value is meaningful), and returns 1 if successful else
+ 0. SVID/XPG/ANSI defines four standard param numbers for mallopt,
+ normally defined in malloc.h. None of these are use in this malloc,
+ so setting them has no effect. But this malloc also supports other
+ options in mallopt:
+
+ Symbol param # default allowed param values
+ M_TRIM_THRESHOLD -1 2*1024*1024 any (-1U disables trimming)
+ M_GRANULARITY -2 page size any power of 2 >= page size
+ M_MMAP_THRESHOLD -3 256*1024 any (or 0 if no MMAP support)
+*/
+int dlmallopt(int, int);
+
+#define M_TRIM_THRESHOLD (-1)
+#define M_GRANULARITY (-2)
+#define M_MMAP_THRESHOLD (-3)
+
+
+/*
+ malloc_footprint();
+ Returns the number of bytes obtained from the system. The total
+ number of bytes allocated by malloc, realloc etc., is less than this
+ value. Unlike mallinfo, this function returns only a precomputed
+ result, so can be called frequently to monitor memory consumption.
+ Even if locks are otherwise defined, this function does not use them,
+ so results might not be up to date.
+*/
+size_t dlmalloc_footprint();
+
+#if !NO_MALLINFO
+/*
+ mallinfo()
+ Returns (by copy) a struct containing various summary statistics:
+
+ arena: current total non-mmapped bytes allocated from system
+ ordblks: the number of free chunks
+ smblks: always zero.
+ hblks: current number of mmapped regions
+ hblkhd: total bytes held in mmapped regions
+ usmblks: the maximum total allocated space. This will be greater
+ than current total if trimming has occurred.
+ fsmblks: always zero
+ uordblks: current total allocated space (normal or mmapped)
+ fordblks: total free space
+ keepcost: the maximum number of bytes that could ideally be released
+ back to system via malloc_trim. ("ideally" means that
+ it ignores page restrictions etc.)
+
+ Because these fields are ints, but internal bookkeeping may
+ be kept as longs, the reported values may wrap around zero and
+ thus be inaccurate.
+*/
+
+struct mallinfo dlmallinfo(void);
+#endif /* NO_MALLINFO */
+
+/*
+ independent_calloc(size_t n_elements, size_t element_size, void* chunks[]);
+
+ independent_calloc is similar to calloc, but instead of returning a
+ single cleared space, it returns an array of pointers to n_elements
+ independent elements that can hold contents of size elem_size, each
+ of which starts out cleared, and can be independently freed,
+ realloc'ed etc. The elements are guaranteed to be adjacently
+ allocated (this is not guaranteed to occur with multiple callocs or
+ mallocs), which may also improve cache locality in some
+ applications.
+
+ The "chunks" argument is optional (i.e., may be null, which is
+ probably the most typical usage). If it is null, the returned array
+ is itself dynamically allocated and should also be freed when it is
+ no longer needed. Otherwise, the chunks array must be of at least
+ n_elements in length. It is filled in with the pointers to the
+ chunks.
+
+ In either case, independent_calloc returns this pointer array, or
+ null if the allocation failed. If n_elements is zero and "chunks"
+ is null, it returns a chunk representing an array with zero elements
+ (which should be freed if not wanted).
+
+ Each element must be individually freed when it is no longer
+ needed. If you'd like to instead be able to free all at once, you
+ should instead use regular calloc and assign pointers into this
+ space to represent elements. (In this case though, you cannot
+ independently free elements.)
+
+ independent_calloc simplifies and speeds up implementations of many
+ kinds of pools. It may also be useful when constructing large data
+ structures that initially have a fixed number of fixed-sized nodes,
+ but the number is not known at compile time, and some of the nodes
+ may later need to be freed. For example:
+
+ struct Node { int item; struct Node* next; };
+
+ struct Node* build_list() {
+ struct Node** pool;
+ int n = read_number_of_nodes_needed();
+ if (n <= 0) return 0;
+ pool = (struct Node**)(independent_calloc(n, sizeof(struct Node), 0);
+ if (pool == 0) die();
+ // organize into a linked list...
+ struct Node* first = pool[0];
+ for (i = 0; i < n-1; ++i)
+ pool[i]->next = pool[i+1];
+ free(pool); // Can now free the array (or not, if it is needed later)
+ return first;
+ }
+*/
+void** dlindependent_calloc(size_t, size_t, void**);
+
+/*
+ independent_comalloc(size_t n_elements, size_t sizes[], void* chunks[]);
+
+ independent_comalloc allocates, all at once, a set of n_elements
+ chunks with sizes indicated in the "sizes" array. It returns
+ an array of pointers to these elements, each of which can be
+ independently freed, realloc'ed etc. The elements are guaranteed to
+ be adjacently allocated (this is not guaranteed to occur with
+ multiple callocs or mallocs), which may also improve cache locality
+ in some applications.
+
+ The "chunks" argument is optional (i.e., may be null). If it is null
+ the returned array is itself dynamically allocated and should also
+ be freed when it is no longer needed. Otherwise, the chunks array
+ must be of at least n_elements in length. It is filled in with the
+ pointers to the chunks.
+
+ In either case, independent_comalloc returns this pointer array, or
+ null if the allocation failed. If n_elements is zero and chunks is
+ null, it returns a chunk representing an array with zero elements
+ (which should be freed if not wanted).
+
+ Each element must be individually freed when it is no longer
+ needed. If you'd like to instead be able to free all at once, you
+ should instead use a single regular malloc, and assign pointers at
+ particular offsets in the aggregate space. (In this case though, you
+ cannot independently free elements.)
+
+ independent_comallac differs from independent_calloc in that each
+ element may have a different size, and also that it does not
+ automatically clear elements.
+
+ independent_comalloc can be used to speed up allocation in cases
+ where several structs or objects must always be allocated at the
+ same time. For example:
+
+ struct Head { ... }
+ struct Foot { ... }
+
+ void send_message(char* msg) {
+ int msglen = strlen(msg);
+ size_t sizes[3] = { sizeof(struct Head), msglen, sizeof(struct Foot) };
+ void* chunks[3];
+ if (independent_comalloc(3, sizes, chunks) == 0)
+ die();
+ struct Head* head = (struct Head*)(chunks[0]);
+ char* body = (char*)(chunks[1]);
+ struct Foot* foot = (struct Foot*)(chunks[2]);
+ // ...
+ }
+
+ In general though, independent_comalloc is worth using only for
+ larger values of n_elements. For small values, you probably won't
+ detect enough difference from series of malloc calls to bother.
+
+ Overuse of independent_comalloc can increase overall memory usage,
+ since it cannot reuse existing noncontiguous small chunks that
+ might be available for some of the elements.
+*/
+void** dlindependent_comalloc(size_t, size_t*, void**);
+
+
+/*
+ pvalloc(size_t n);
+ Equivalent to valloc(minimum-page-that-holds(n)), that is,
+ round up n to nearest pagesize.
+ */
+void* dlpvalloc(size_t);
+
+/*
+ malloc_trim(size_t pad);
+
+ If possible, gives memory back to the system (via negative arguments
+ to sbrk) if there is unused memory at the `high' end of the malloc
+ pool or in unused MMAP segments. You can call this after freeing
+ large blocks of memory to potentially reduce the system-level memory
+ requirements of a program. However, it cannot guarantee to reduce
+ memory. Under some allocation patterns, some large free blocks of
+ memory will be locked between two used chunks, so they cannot be
+ given back to the system.
+
+ The `pad' argument to malloc_trim represents the amount of free
+ trailing space to leave untrimmed. If this argument is zero, only
+ the minimum amount of memory to maintain internal data structures
+ will be left. Non-zero arguments can be supplied to maintain enough
+ trailing space to service future expected allocations without having
+ to re-obtain memory from the system.
+
+ Malloc_trim returns 1 if it actually released any memory, else 0.
+*/
+int dlmalloc_trim(size_t);
+
+/*
+ malloc_stats();
+ Prints on stderr the amount of space obtained from the system (both
+ via sbrk and mmap), the maximum amount (which may be more than
+ current if malloc_trim and/or munmap got called), and the current
+ number of bytes allocated via malloc (or realloc, etc) but not yet
+ freed. Note that this is the number of bytes allocated, not the
+ number requested. It will be larger than the number requested
+ because of alignment and bookkeeping overhead. Because it includes
+ alignment wastage as being in use, this figure may be greater than
+ zero even when no user-level chunks are allocated.
+
+ The reported current and maximum system memory can be inaccurate if
+ a program makes other calls to system memory allocation functions
+ (normally sbrk) outside of malloc.
+
+ malloc_stats prints only the most commonly interesting statistics.
+ More information can be obtained by calling mallinfo.
+*/
+void dlmalloc_stats();
+
+#endif /* !ONLY_MSPACES */
+
+/*
+ malloc_usable_size(void* p);
+
+ Returns the number of bytes you can actually use in
+ an allocated chunk, which may be more than you requested (although
+ often not) due to alignment and minimum size constraints.
+ You can use this many bytes without worrying about
+ overwriting other allocated objects. This is not a particularly great
+ programming practice. malloc_usable_size can be more useful in
+ debugging and assertions, for example:
+
+ p = malloc(n);
+ assert(malloc_usable_size(p) >= 256);
+*/
+size_t dlmalloc_usable_size(void*);
+
+
+#if MSPACES
+
+/*
+ mspace is an opaque type representing an independent
+ region of space that supports mspace_malloc, etc.
+*/
+typedef void* mspace;
+
+/*
+ create_mspace creates and returns a new independent space with the
+ given initial capacity, or, if 0, the default granularity size. It
+ returns null if there is no system memory available to create the
+ space. If argument locked is non-zero, the space uses a separate
+ lock to control access. The capacity of the space will grow
+ dynamically as needed to service mspace_malloc requests. You can
+ control the sizes of incremental increases of this space by
+ compiling with a different DEFAULT_GRANULARITY or dynamically
+ setting with mallopt(M_GRANULARITY, value).
+*/
+mspace create_mspace(size_t capacity, int locked);
+
+/*
+ destroy_mspace destroys the given space, and attempts to return all
+ of its memory back to the system, returning the total number of
+ bytes freed. After destruction, the results of access to all memory
+ used by the space become undefined.
+*/
+size_t destroy_mspace(mspace msp);
+
+/*
+ create_mspace_with_base uses the memory supplied as the initial base
+ of a new mspace. Part (less than 128*sizeof(size_t) bytes) of this
+ space is used for bookkeeping, so the capacity must be at least this
+ large. (Otherwise 0 is returned.) When this initial space is
+ exhausted, additional memory will be obtained from the system.
+ Destroying this space will deallocate all additionally allocated
+ space (if possible) but not the initial base.
+*/
+mspace create_mspace_with_base(void* base, size_t capacity, int locked);
+
+/*
+ mspace_track_large_chunks controls whether requests for large chunks
+ are allocated in their own untracked mmapped regions, separate from
+ others in this mspace. By default large chunks are not tracked,
+ which reduces fragmentation. However, such chunks are not
+ necessarily released to the system upon destroy_mspace. Enabling
+ tracking by setting to true may increase fragmentation, but avoids
+ leakage when relying on destroy_mspace to release all memory
+ allocated using this space. The function returns the previous
+ setting.
+*/
+int mspace_track_large_chunks(mspace msp, int enable);
+
+/*
+ mspace_malloc behaves as malloc, but operates within
+ the given space.
+*/
+void* mspace_malloc(mspace msp, size_t bytes);
+
+/*
+ mspace_free behaves as free, but operates within
+ the given space.
+
+ If compiled with FOOTERS==1, mspace_free is not actually needed.
+ free may be called instead of mspace_free because freed chunks from
+ any space are handled by their originating spaces.
+*/
+void mspace_free(mspace msp, void* mem);
+
+/*
+ mspace_realloc behaves as realloc, but operates within
+ the given space.
+
+ If compiled with FOOTERS==1, mspace_realloc is not actually
+ needed. realloc may be called instead of mspace_realloc because
+ realloced chunks from any space are handled by their originating
+ spaces.
+*/
+void* mspace_realloc(mspace msp, void* mem, size_t newsize);
+
+/*
+ mspace_calloc behaves as calloc, but operates within
+ the given space.
+*/
+void* mspace_calloc(mspace msp, size_t n_elements, size_t elem_size);
+
+/*
+ mspace_memalign behaves as memalign, but operates within
+ the given space.
+*/
+void* mspace_memalign(mspace msp, size_t alignment, size_t bytes);
+
+/*
+ mspace_independent_calloc behaves as independent_calloc, but
+ operates within the given space.
+*/
+void** mspace_independent_calloc(mspace msp, size_t n_elements,
+ size_t elem_size, void* chunks[]);
+
+/*
+ mspace_independent_comalloc behaves as independent_comalloc, but
+ operates within the given space.
+*/
+void** mspace_independent_comalloc(mspace msp, size_t n_elements,
+ size_t sizes[], void* chunks[]);
+
+/*
+ mspace_footprint() returns the number of bytes obtained from the
+ system for this space.
+*/
+size_t mspace_footprint(mspace msp);
+
+
+#if !NO_MALLINFO
+/*
+ mspace_mallinfo behaves as mallinfo, but reports properties of
+ the given space.
+*/
+struct mallinfo mspace_mallinfo(mspace msp);
+#endif /* NO_MALLINFO */
+
+/*
+ malloc_usable_size(void* p) behaves the same as malloc_usable_size;
+*/
+ size_t mspace_usable_size(void* mem);
+
+/*
+ mspace_malloc_stats behaves as malloc_stats, but reports
+ properties of the given space.
+*/
+void mspace_malloc_stats(mspace msp);
+
+/*
+ mspace_trim behaves as malloc_trim, but
+ operates within the given space.
+*/
+int mspace_trim(mspace msp, size_t pad);
+
+/*
+ An alias for mallopt.
+*/
+int mspace_mallopt(int, int);
+
+#endif /* MSPACES */
+
+#ifdef __cplusplus
+}; /* end of extern "C" */
+#endif
+
+#endif /* MALLOC_280_H */
diff --git a/unsupported/test/mpreal/mpreal.cpp b/unsupported/test/mpreal/mpreal.cpp
new file mode 100644
index 000000000..5c23544ef
--- /dev/null
+++ b/unsupported/test/mpreal/mpreal.cpp
@@ -0,0 +1,597 @@
+/*
+ Multi-precision real number class. C++ interface fo MPFR library.
+ Project homepage: http://www.holoborodko.com/pavel/
+ Contact e-mail: pavel@holoborodko.com
+
+ Copyright (c) 2008-2011 Pavel Holoborodko
+
+ Core Developers:
+ Pavel Holoborodko, Dmitriy Gubanov, Konstantin Holoborodko.
+
+ Contributors:
+ Brian Gladman, Helmut Jarausch, Fokko Beekhof, Ulrich Mutze,
+ Heinz van Saanen, Pere Constans, Peter van Hoof, Gael Guennebaud,
+ Tsai Chia Cheng, Alexei Zubanov.
+
+ ****************************************************************************
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+ ****************************************************************************
+ ****************************************************************************
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ 1. Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+
+ 2. 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.
+
+ 3. The name of the author may be used to endorse or promote products
+ derived from this software without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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.
+*/
+#include <cstring>
+#include "mpreal.h"
+
+#if defined (MPREAL_HAVE_CUSTOM_MPFR_MALLOC)
+#include "dlmalloc.h"
+#endif
+
+using std::ws;
+using std::cerr;
+using std::endl;
+using std::string;
+using std::ostream;
+using std::istream;
+
+namespace mpfr{
+
+mp_rnd_t mpreal::default_rnd = MPFR_RNDN; //(mpfr_get_default_rounding_mode)();
+mp_prec_t mpreal::default_prec = 64; //(mpfr_get_default_prec)();
+int mpreal::default_base = 10;
+int mpreal::double_bits = -1;
+
+#if defined (MPREAL_HAVE_CUSTOM_MPFR_MALLOC)
+bool mpreal::is_custom_malloc = false;
+#endif
+
+// Default constructor: creates mp number and initializes it to 0.
+mpreal::mpreal()
+{
+
+#if defined (MPREAL_HAVE_CUSTOM_MPFR_MALLOC)
+ set_custom_malloc();
+#endif
+
+ mpfr_init2(mp,default_prec);
+ mpfr_set_ui(mp,0,default_rnd);
+
+ MPREAL_MSVC_DEBUGVIEW_CODE;
+}
+
+mpreal::mpreal(const mpreal& u)
+{
+
+#if defined (MPREAL_HAVE_CUSTOM_MPFR_MALLOC)
+ set_custom_malloc();
+#endif
+
+ mpfr_init2(mp,mpfr_get_prec(u.mp));
+ mpfr_set(mp,u.mp,default_rnd);
+
+ MPREAL_MSVC_DEBUGVIEW_CODE;
+}
+
+mpreal::mpreal(const mpfr_t u)
+{
+
+#if defined (MPREAL_HAVE_CUSTOM_MPFR_MALLOC)
+ set_custom_malloc();
+#endif
+
+ mpfr_init2(mp,mpfr_get_prec(u));
+ mpfr_set(mp,u,default_rnd);
+
+ MPREAL_MSVC_DEBUGVIEW_CODE;
+}
+
+mpreal::mpreal(const mpf_t u)
+{
+
+#if defined (MPREAL_HAVE_CUSTOM_MPFR_MALLOC)
+ set_custom_malloc();
+#endif
+
+ mpfr_init2(mp,(mp_prec_t) mpf_get_prec(u)); // (gmp: mp_bitcnt_t) unsigned long -> long (mpfr: mp_prec_t)
+ mpfr_set_f(mp,u,default_rnd);
+
+ MPREAL_MSVC_DEBUGVIEW_CODE;
+}
+
+mpreal::mpreal(const mpz_t u, mp_prec_t prec, mp_rnd_t mode)
+{
+
+#if defined (MPREAL_HAVE_CUSTOM_MPFR_MALLOC)
+ set_custom_malloc();
+#endif
+
+ mpfr_init2(mp,prec);
+ mpfr_set_z(mp,u,mode);
+
+ MPREAL_MSVC_DEBUGVIEW_CODE;
+}
+
+mpreal::mpreal(const mpq_t u, mp_prec_t prec, mp_rnd_t mode)
+{
+
+#if defined (MPREAL_HAVE_CUSTOM_MPFR_MALLOC)
+ set_custom_malloc();
+#endif
+
+ mpfr_init2(mp,prec);
+ mpfr_set_q(mp,u,mode);
+
+ MPREAL_MSVC_DEBUGVIEW_CODE;
+}
+
+mpreal::mpreal(const double u, mp_prec_t prec, mp_rnd_t mode)
+{
+
+#if defined (MPREAL_HAVE_CUSTOM_MPFR_MALLOC)
+ set_custom_malloc();
+#endif
+
+ if(double_bits == -1 || fits_in_bits(u, double_bits))
+ {
+ mpfr_init2(mp,prec);
+ mpfr_set_d(mp,u,mode);
+
+ MPREAL_MSVC_DEBUGVIEW_CODE;
+ }
+ else
+ throw conversion_overflow();
+}
+
+mpreal::mpreal(const long double u, mp_prec_t prec, mp_rnd_t mode)
+{
+
+#if defined (MPREAL_HAVE_CUSTOM_MPFR_MALLOC)
+ set_custom_malloc();
+#endif
+
+ mpfr_init2(mp,prec);
+ mpfr_set_ld(mp,u,mode);
+
+ MPREAL_MSVC_DEBUGVIEW_CODE;
+}
+
+mpreal::mpreal(const unsigned long int u, mp_prec_t prec, mp_rnd_t mode)
+{
+
+#if defined (MPREAL_HAVE_CUSTOM_MPFR_MALLOC)
+ set_custom_malloc();
+#endif
+
+ mpfr_init2(mp,prec);
+ mpfr_set_ui(mp,u,mode);
+
+ MPREAL_MSVC_DEBUGVIEW_CODE;
+}
+
+mpreal::mpreal(const unsigned int u, mp_prec_t prec, mp_rnd_t mode)
+{
+
+#if defined (MPREAL_HAVE_CUSTOM_MPFR_MALLOC)
+ set_custom_malloc();
+#endif
+
+ mpfr_init2(mp,prec);
+ mpfr_set_ui(mp,u,mode);
+
+ MPREAL_MSVC_DEBUGVIEW_CODE;
+}
+
+mpreal::mpreal(const long int u, mp_prec_t prec, mp_rnd_t mode)
+{
+
+#if defined (MPREAL_HAVE_CUSTOM_MPFR_MALLOC)
+ set_custom_malloc();
+#endif
+
+ mpfr_init2(mp,prec);
+ mpfr_set_si(mp,u,mode);
+
+ MPREAL_MSVC_DEBUGVIEW_CODE;
+}
+
+mpreal::mpreal(const int u, mp_prec_t prec, mp_rnd_t mode)
+{
+
+#if defined (MPREAL_HAVE_CUSTOM_MPFR_MALLOC)
+ set_custom_malloc();
+#endif
+
+ mpfr_init2(mp,prec);
+ mpfr_set_si(mp,u,mode);
+
+ MPREAL_MSVC_DEBUGVIEW_CODE;
+}
+
+#if defined (MPREAL_HAVE_INT64_SUPPORT)
+mpreal::mpreal(const uint64_t u, mp_prec_t prec, mp_rnd_t mode)
+{
+
+#if defined (MPREAL_HAVE_CUSTOM_MPFR_MALLOC)
+ set_custom_malloc();
+#endif
+
+ mpfr_init2(mp,prec);
+ mpfr_set_uj(mp, u, mode);
+
+ MPREAL_MSVC_DEBUGVIEW_CODE;
+}
+
+mpreal::mpreal(const int64_t u, mp_prec_t prec, mp_rnd_t mode)
+{
+
+#if defined (MPREAL_HAVE_CUSTOM_MPFR_MALLOC)
+ set_custom_malloc();
+#endif
+
+ mpfr_init2(mp,prec);
+ mpfr_set_sj(mp, u, mode);
+
+ MPREAL_MSVC_DEBUGVIEW_CODE;
+}
+#endif
+
+mpreal::mpreal(const char* s, mp_prec_t prec, int base, mp_rnd_t mode)
+{
+
+#if defined (MPREAL_HAVE_CUSTOM_MPFR_MALLOC)
+ set_custom_malloc();
+#endif
+
+ mpfr_init2(mp,prec);
+ mpfr_set_str(mp, s, base, mode);
+
+ MPREAL_MSVC_DEBUGVIEW_CODE;
+}
+
+mpreal::mpreal(const std::string& s, mp_prec_t prec, int base, mp_rnd_t mode)
+{
+
+#if defined (MPREAL_HAVE_CUSTOM_MPFR_MALLOC)
+ set_custom_malloc();
+#endif
+
+ mpfr_init2(mp,prec);
+ mpfr_set_str(mp, s.c_str(), base, mode);
+
+ MPREAL_MSVC_DEBUGVIEW_CODE;
+}
+
+mpreal::~mpreal()
+{
+ mpfr_clear(mp);
+}
+
+// Operators - Assignment
+mpreal& mpreal::operator=(const char* s)
+{
+ mpfr_t t;
+
+#if defined (MPREAL_HAVE_CUSTOM_MPFR_MALLOC)
+ set_custom_malloc();
+#endif
+
+ if(0==mpfr_init_set_str(t,s,default_base,default_rnd))
+ {
+ // We will rewrite mp anyway, so flash it and resize
+ mpfr_set_prec(mp,mpfr_get_prec(t));
+ mpfr_set(mp,t,mpreal::default_rnd);
+ mpfr_clear(t);
+
+ MPREAL_MSVC_DEBUGVIEW_CODE;
+
+ }else{
+ mpfr_clear(t);
+ }
+
+ return *this;
+}
+
+const mpreal fma (const mpreal& v1, const mpreal& v2, const mpreal& v3, mp_rnd_t rnd_mode)
+{
+ mpreal a;
+ mp_prec_t p1, p2, p3;
+
+ p1 = v1.get_prec();
+ p2 = v2.get_prec();
+ p3 = v3.get_prec();
+
+ a.set_prec(p3>p2?(p3>p1?p3:p1):(p2>p1?p2:p1));
+
+ mpfr_fma(a.mp,v1.mp,v2.mp,v3.mp,rnd_mode);
+ return a;
+}
+
+const mpreal fms (const mpreal& v1, const mpreal& v2, const mpreal& v3, mp_rnd_t rnd_mode)
+{
+ mpreal a;
+ mp_prec_t p1, p2, p3;
+
+ p1 = v1.get_prec();
+ p2 = v2.get_prec();
+ p3 = v3.get_prec();
+
+ a.set_prec(p3>p2?(p3>p1?p3:p1):(p2>p1?p2:p1));
+
+ mpfr_fms(a.mp,v1.mp,v2.mp,v3.mp,rnd_mode);
+ return a;
+}
+
+const mpreal agm (const mpreal& v1, const mpreal& v2, mp_rnd_t rnd_mode)
+{
+ mpreal a;
+ mp_prec_t p1, p2;
+
+ p1 = v1.get_prec();
+ p2 = v2.get_prec();
+
+ a.set_prec(p1>p2?p1:p2);
+
+ mpfr_agm(a.mp, v1.mp, v2.mp, rnd_mode);
+
+ return a;
+}
+
+const mpreal sum (const mpreal tab[], unsigned long int n, mp_rnd_t rnd_mode)
+{
+ mpreal x;
+ mpfr_ptr* t;
+ unsigned long int i;
+
+ t = new mpfr_ptr[n];
+ for (i=0;i<n;i++) t[i] = (mpfr_ptr)tab[i].mp;
+ mpfr_sum(x.mp,t,n,rnd_mode);
+ delete[] t;
+ return x;
+}
+
+const mpreal remquo (long* q, const mpreal& x, const mpreal& y, mp_rnd_t rnd_mode)
+{
+ mpreal a;
+ mp_prec_t yp, xp;
+
+ yp = y.get_prec();
+ xp = x.get_prec();
+
+ a.set_prec(yp>xp?yp:xp);
+
+ mpfr_remquo(a.mp,q, x.mp, y.mp, rnd_mode);
+
+ return a;
+}
+
+template <class T>
+std::string toString(T t, std::ios_base & (*f)(std::ios_base&))
+{
+ std::ostringstream oss;
+ oss << f << t;
+ return oss.str();
+}
+
+#if (MPFR_VERSION >= MPFR_VERSION_NUM(2,4,0))
+
+std::string mpreal::toString(const std::string& format) const
+{
+ char *s = NULL;
+ string out;
+
+ if( !format.empty() )
+ {
+ if(!(mpfr_asprintf(&s,format.c_str(),mp) < 0))
+ {
+ out = std::string(s);
+
+ mpfr_free_str(s);
+ }
+ }
+
+ return out;
+}
+
+#endif
+
+std::string mpreal::toString(int n, int b, mp_rnd_t mode) const
+{
+ (void)b;
+ (void)mode;
+#if (MPFR_VERSION >= MPFR_VERSION_NUM(2,4,0))
+
+ // Use MPFR native function for output
+ char format[128];
+ int digits;
+
+ digits = n > 0 ? n : bits2digits(mpfr_get_prec(mp));
+
+ sprintf(format,"%%.%dRNg",digits); // Default format
+
+ return toString(std::string(format));
+
+#else
+
+ char *s, *ns = NULL;
+ size_t slen, nslen;
+ mp_exp_t exp;
+ string out;
+
+#if defined (MPREAL_HAVE_CUSTOM_MPFR_MALLOC)
+ set_custom_malloc();
+#endif
+
+ if(mpfr_inf_p(mp))
+ {
+ if(mpfr_sgn(mp)>0) return "+Inf";
+ else return "-Inf";
+ }
+
+ if(mpfr_zero_p(mp)) return "0";
+ if(mpfr_nan_p(mp)) return "NaN";
+
+ s = mpfr_get_str(NULL,&exp,b,0,mp,mode);
+ ns = mpfr_get_str(NULL,&exp,b,n,mp,mode);
+
+ if(s!=NULL && ns!=NULL)
+ {
+ slen = strlen(s);
+ nslen = strlen(ns);
+ if(nslen<=slen)
+ {
+ mpfr_free_str(s);
+ s = ns;
+ slen = nslen;
+ }
+ else {
+ mpfr_free_str(ns);
+ }
+
+ // Make human eye-friendly formatting if possible
+ if (exp>0 && static_cast<size_t>(exp)<slen)
+ {
+ if(s[0]=='-')
+ {
+ // Remove zeros starting from right end
+ char* ptr = s+slen-1;
+ while (*ptr=='0' && ptr>s+exp) ptr--;
+
+ if(ptr==s+exp) out = string(s,exp+1);
+ else out = string(s,exp+1)+'.'+string(s+exp+1,ptr-(s+exp+1)+1);
+
+ //out = string(s,exp+1)+'.'+string(s+exp+1);
+ }
+ else
+ {
+ // Remove zeros starting from right end
+ char* ptr = s+slen-1;
+ while (*ptr=='0' && ptr>s+exp-1) ptr--;
+
+ if(ptr==s+exp-1) out = string(s,exp);
+ else out = string(s,exp)+'.'+string(s+exp,ptr-(s+exp)+1);
+
+ //out = string(s,exp)+'.'+string(s+exp);
+ }
+
+ }else{ // exp<0 || exp>slen
+ if(s[0]=='-')
+ {
+ // Remove zeros starting from right end
+ char* ptr = s+slen-1;
+ while (*ptr=='0' && ptr>s+1) ptr--;
+
+ if(ptr==s+1) out = string(s,2);
+ else out = string(s,2)+'.'+string(s+2,ptr-(s+2)+1);
+
+ //out = string(s,2)+'.'+string(s+2);
+ }
+ else
+ {
+ // Remove zeros starting from right end
+ char* ptr = s+slen-1;
+ while (*ptr=='0' && ptr>s) ptr--;
+
+ if(ptr==s) out = string(s,1);
+ else out = string(s,1)+'.'+string(s+1,ptr-(s+1)+1);
+
+ //out = string(s,1)+'.'+string(s+1);
+ }
+
+ // Make final string
+ if(--exp)
+ {
+ if(exp>0) out += "e+"+mpfr::toString<mp_exp_t>(exp,std::dec);
+ else out += "e"+mpfr::toString<mp_exp_t>(exp,std::dec);
+ }
+ }
+
+ mpfr_free_str(s);
+ return out;
+ }else{
+ return "conversion error!";
+ }
+#endif
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+// I/O
+ostream& operator<<(ostream& os, const mpreal& v)
+{
+ return os<<v.toString(static_cast<int>(os.precision()));
+}
+
+istream& operator>>(istream &is, mpreal& v)
+{
+ string tmp;
+ is >> tmp;
+ mpfr_set_str(v.mp, tmp.c_str(),mpreal::default_base,mpreal::default_rnd);
+ return is;
+}
+
+
+#if defined (MPREAL_HAVE_CUSTOM_MPFR_MALLOC)
+ // Optimized dynamic memory allocation/(re-)deallocation.
+ void * mpreal::mpreal_allocate(size_t alloc_size)
+ {
+ return(dlmalloc(alloc_size));
+ }
+
+ void * mpreal::mpreal_reallocate(void *ptr, size_t old_size, size_t new_size)
+ {
+ return(dlrealloc(ptr,new_size));
+ }
+
+ void mpreal::mpreal_free(void *ptr, size_t size)
+ {
+ dlfree(ptr);
+ }
+
+ inline void mpreal::set_custom_malloc(void)
+ {
+ if(!is_custom_malloc)
+ {
+ mp_set_memory_functions(mpreal_allocate,mpreal_reallocate,mpreal_free);
+ is_custom_malloc = true;
+ }
+ }
+#endif
+
+}
+
diff --git a/unsupported/test/mpreal/mpreal.h b/unsupported/test/mpreal/mpreal.h
new file mode 100644
index 000000000..c640af947
--- /dev/null
+++ b/unsupported/test/mpreal/mpreal.h
@@ -0,0 +1,2735 @@
+/*
+ Multi-precision real number class. C++ interface for MPFR library.
+ Project homepage: http://www.holoborodko.com/pavel/
+ Contact e-mail: pavel@holoborodko.com
+
+ Copyright (c) 2008-2012 Pavel Holoborodko
+
+ Core Developers:
+ Pavel Holoborodko, Dmitriy Gubanov, Konstantin Holoborodko.
+
+ Contributors:
+ Brian Gladman, Helmut Jarausch, Fokko Beekhof, Ulrich Mutze,
+ Heinz van Saanen, Pere Constans, Peter van Hoof, Gael Guennebaud,
+ Tsai Chia Cheng, Alexei Zubanov.
+
+ ****************************************************************************
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+ ****************************************************************************
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ 1. Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+
+ 2. 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.
+
+ 3. The name of the author may be used to endorse or promote products
+ derived from this software without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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.
+*/
+
+#ifndef __MPREAL_H__
+#define __MPREAL_H__
+
+#include <string>
+#include <iostream>
+#include <sstream>
+#include <stdexcept>
+#include <cfloat>
+#include <cmath>
+
+// Options
+#define MPREAL_HAVE_INT64_SUPPORT // int64_t support: available only for MSVC 2010 & GCC
+#define MPREAL_HAVE_MSVC_DEBUGVIEW // Enable Debugger Visualizer (valid only for MSVC in "Debug" builds)
+
+// Detect compiler using signatures from http://predef.sourceforge.net/
+#if defined(__GNUC__) && defined(__INTEL_COMPILER)
+ #define IsInf(x) isinf(x) // Intel ICC compiler on Linux
+
+#elif defined(_MSC_VER) // Microsoft Visual C++
+ #define IsInf(x) (!_finite(x))
+
+#elif defined(__GNUC__)
+ #define IsInf(x) std::isinf(x) // GNU C/C++
+
+#else
+ #define IsInf(x) std::isinf(x) // Unknown compiler, just hope for C99 conformance
+#endif
+
+#if defined(MPREAL_HAVE_INT64_SUPPORT)
+
+ #define MPFR_USE_INTMAX_T // should be defined before mpfr.h
+
+ #if defined(_MSC_VER) // <stdint.h> is available only in msvc2010!
+ #if (_MSC_VER >= 1600)
+ #include <stdint.h>
+ #else // MPFR relies on intmax_t which is available only in msvc2010
+ #undef MPREAL_HAVE_INT64_SUPPORT // Besides, MPFR - MPIR have to be compiled with msvc2010
+ #undef MPFR_USE_INTMAX_T // Since we cannot detect this, disable x64 by default
+ // Someone should change this manually if needed.
+ #endif
+ #endif
+
+ #if defined (__MINGW32__) || defined(__MINGW64__)
+ #include <stdint.h> // equivalent to msvc2010
+ #elif defined (__GNUC__)
+ #if defined(__amd64__) || defined(__amd64) || defined(__x86_64__) || defined(__x86_64)
+ #undef MPREAL_HAVE_INT64_SUPPORT // remove all shaman dances for x64 builds since
+ #undef MPFR_USE_INTMAX_T // GCC already support x64 as of "long int" is 64-bit integer, nothing left to do
+ #else
+ #include <stdint.h> // use int64_t, uint64_t otherwise.
+ #endif
+ #endif
+
+#endif
+
+#if defined(MPREAL_HAVE_MSVC_DEBUGVIEW) && defined(_MSC_VER) && defined(_DEBUG)
+#define MPREAL_MSVC_DEBUGVIEW_CODE DebugView = toString()
+ #define MPREAL_MSVC_DEBUGVIEW_DATA std::string DebugView
+#else
+ #define MPREAL_MSVC_DEBUGVIEW_CODE
+ #define MPREAL_MSVC_DEBUGVIEW_DATA
+#endif
+
+#include <mpfr.h>
+
+#if (MPFR_VERSION < MPFR_VERSION_NUM(3,0,0))
+ #include <cstdlib> // needed for random()
+#endif
+
+namespace mpfr {
+
+class mpreal {
+private:
+ mpfr_t mp;
+
+public:
+ static mp_rnd_t default_rnd;
+ static mp_prec_t default_prec;
+ static int default_base;
+ static int double_bits;
+
+public:
+ // Constructors && type conversion
+ mpreal();
+ mpreal(const mpreal& u);
+ mpreal(const mpfr_t u);
+ mpreal(const mpf_t u);
+ mpreal(const mpz_t u, mp_prec_t prec = default_prec, mp_rnd_t mode = default_rnd);
+ mpreal(const mpq_t u, mp_prec_t prec = default_prec, mp_rnd_t mode = default_rnd);
+ mpreal(const double u, mp_prec_t prec = default_prec, mp_rnd_t mode = default_rnd);
+ mpreal(const long double u, mp_prec_t prec = default_prec, mp_rnd_t mode = default_rnd);
+ mpreal(const unsigned long int u, mp_prec_t prec = default_prec, mp_rnd_t mode = default_rnd);
+ mpreal(const unsigned int u, mp_prec_t prec = default_prec, mp_rnd_t mode = default_rnd);
+ mpreal(const long int u, mp_prec_t prec = default_prec, mp_rnd_t mode = default_rnd);
+ mpreal(const int u, mp_prec_t prec = default_prec, mp_rnd_t mode = default_rnd);
+
+#if defined (MPREAL_HAVE_INT64_SUPPORT)
+ mpreal(const uint64_t u, mp_prec_t prec = default_prec, mp_rnd_t mode = default_rnd);
+ mpreal(const int64_t u, mp_prec_t prec = default_prec, mp_rnd_t mode = default_rnd);
+#endif
+
+ mpreal(const char* s, mp_prec_t prec = default_prec, int base = default_base, mp_rnd_t mode = default_rnd);
+ mpreal(const std::string& s, mp_prec_t prec = default_prec, int base = default_base, mp_rnd_t mode = default_rnd);
+
+ ~mpreal();
+
+ // Operations
+ // =
+ // +, -, *, /, ++, --, <<, >>
+ // *=, +=, -=, /=,
+ // <, >, ==, <=, >=
+
+ // =
+ mpreal& operator=(const mpreal& v);
+ mpreal& operator=(const mpf_t v);
+ mpreal& operator=(const mpz_t v);
+ mpreal& operator=(const mpq_t v);
+ mpreal& operator=(const long double v);
+ mpreal& operator=(const double v);
+ mpreal& operator=(const unsigned long int v);
+ mpreal& operator=(const unsigned int v);
+ mpreal& operator=(const long int v);
+ mpreal& operator=(const int v);
+ mpreal& operator=(const char* s);
+
+ // +
+ mpreal& operator+=(const mpreal& v);
+ mpreal& operator+=(const mpf_t v);
+ mpreal& operator+=(const mpz_t v);
+ mpreal& operator+=(const mpq_t v);
+ mpreal& operator+=(const long double u);
+ mpreal& operator+=(const double u);
+ mpreal& operator+=(const unsigned long int u);
+ mpreal& operator+=(const unsigned int u);
+ mpreal& operator+=(const long int u);
+ mpreal& operator+=(const int u);
+
+#if defined (MPREAL_HAVE_INT64_SUPPORT)
+ mpreal& operator+=(const int64_t u);
+ mpreal& operator+=(const uint64_t u);
+ mpreal& operator-=(const int64_t u);
+ mpreal& operator-=(const uint64_t u);
+ mpreal& operator*=(const int64_t u);
+ mpreal& operator*=(const uint64_t u);
+ mpreal& operator/=(const int64_t u);
+ mpreal& operator/=(const uint64_t u);
+#endif
+
+ const mpreal operator+() const;
+ mpreal& operator++ ();
+ const mpreal operator++ (int);
+
+ // -
+ mpreal& operator-=(const mpreal& v);
+ mpreal& operator-=(const mpz_t v);
+ mpreal& operator-=(const mpq_t v);
+ mpreal& operator-=(const long double u);
+ mpreal& operator-=(const double u);
+ mpreal& operator-=(const unsigned long int u);
+ mpreal& operator-=(const unsigned int u);
+ mpreal& operator-=(const long int u);
+ mpreal& operator-=(const int u);
+ const mpreal operator-() const;
+ friend const mpreal operator-(const unsigned long int b, const mpreal& a);
+ friend const mpreal operator-(const unsigned int b, const mpreal& a);
+ friend const mpreal operator-(const long int b, const mpreal& a);
+ friend const mpreal operator-(const int b, const mpreal& a);
+ friend const mpreal operator-(const double b, const mpreal& a);
+ mpreal& operator-- ();
+ const mpreal operator-- (int);
+
+ // *
+ mpreal& operator*=(const mpreal& v);
+ mpreal& operator*=(const mpz_t v);
+ mpreal& operator*=(const mpq_t v);
+ mpreal& operator*=(const long double v);
+ mpreal& operator*=(const double v);
+ mpreal& operator*=(const unsigned long int v);
+ mpreal& operator*=(const unsigned int v);
+ mpreal& operator*=(const long int v);
+ mpreal& operator*=(const int v);
+
+ // /
+ mpreal& operator/=(const mpreal& v);
+ mpreal& operator/=(const mpz_t v);
+ mpreal& operator/=(const mpq_t v);
+ mpreal& operator/=(const long double v);
+ mpreal& operator/=(const double v);
+ mpreal& operator/=(const unsigned long int v);
+ mpreal& operator/=(const unsigned int v);
+ mpreal& operator/=(const long int v);
+ mpreal& operator/=(const int v);
+ friend const mpreal operator/(const unsigned long int b, const mpreal& a);
+ friend const mpreal operator/(const unsigned int b, const mpreal& a);
+ friend const mpreal operator/(const long int b, const mpreal& a);
+ friend const mpreal operator/(const int b, const mpreal& a);
+ friend const mpreal operator/(const double b, const mpreal& a);
+
+ //<<= Fast Multiplication by 2^u
+ mpreal& operator<<=(const unsigned long int u);
+ mpreal& operator<<=(const unsigned int u);
+ mpreal& operator<<=(const long int u);
+ mpreal& operator<<=(const int u);
+
+ //>>= Fast Division by 2^u
+ mpreal& operator>>=(const unsigned long int u);
+ mpreal& operator>>=(const unsigned int u);
+ mpreal& operator>>=(const long int u);
+ mpreal& operator>>=(const int u);
+
+ // Boolean Operators
+ friend bool operator > (const mpreal& a, const mpreal& b);
+ friend bool operator >= (const mpreal& a, const mpreal& b);
+ friend bool operator < (const mpreal& a, const mpreal& b);
+ friend bool operator <= (const mpreal& a, const mpreal& b);
+ friend bool operator == (const mpreal& a, const mpreal& b);
+ friend bool operator != (const mpreal& a, const mpreal& b);
+
+ // Optimized specializations for boolean operators
+ friend bool operator == (const mpreal& a, const unsigned long int b);
+ friend bool operator == (const mpreal& a, const unsigned int b);
+ friend bool operator == (const mpreal& a, const long int b);
+ friend bool operator == (const mpreal& a, const int b);
+ friend bool operator == (const mpreal& a, const long double b);
+ friend bool operator == (const mpreal& a, const double b);
+
+ // Type Conversion operators
+ long toLong() const;
+ unsigned long toULong() const;
+ double toDouble() const;
+ long double toLDouble() const;
+
+#if defined (MPREAL_HAVE_INT64_SUPPORT)
+ int64_t toInt64() const;
+ uint64_t toUInt64() const;
+#endif
+
+ // Get raw pointers
+ ::mpfr_ptr mpfr_ptr();
+ ::mpfr_srcptr mpfr_srcptr() const;
+
+ // Convert mpreal to string with n significant digits in base b
+ // n = 0 -> convert with the maximum available digits
+ std::string toString(int n = 0, int b = default_base, mp_rnd_t mode = default_rnd) const;
+
+#if (MPFR_VERSION >= MPFR_VERSION_NUM(2,4,0))
+ std::string toString(const std::string& format) const;
+#endif
+
+ // Math Functions
+ friend const mpreal sqr (const mpreal& v, mp_rnd_t rnd_mode = mpreal::default_rnd);
+ friend const mpreal sqrt(const mpreal& v, mp_rnd_t rnd_mode = mpreal::default_rnd);
+ friend const mpreal sqrt(const unsigned long int v, mp_rnd_t rnd_mode = mpreal::default_rnd);
+ friend const mpreal cbrt(const mpreal& v, mp_rnd_t rnd_mode = mpreal::default_rnd);
+ friend const mpreal root(const mpreal& v, unsigned long int k, mp_rnd_t rnd_mode = mpreal::default_rnd);
+ friend const mpreal pow (const mpreal& a, const mpreal& b, mp_rnd_t rnd_mode = mpreal::default_rnd);
+ friend const mpreal pow (const mpreal& a, const mpz_t b, mp_rnd_t rnd_mode = mpreal::default_rnd);
+ friend const mpreal pow (const mpreal& a, const unsigned long int b, mp_rnd_t rnd_mode = mpreal::default_rnd);
+ friend const mpreal pow (const mpreal& a, const long int b, mp_rnd_t rnd_mode = mpreal::default_rnd);
+ friend const mpreal pow (const unsigned long int a, const mpreal& b, mp_rnd_t rnd_mode = mpreal::default_rnd);
+ friend const mpreal pow (const unsigned long int a, const unsigned long int b, mp_rnd_t rnd_mode = mpreal::default_rnd);
+ friend const mpreal fabs(const mpreal& v, mp_rnd_t rnd_mode = mpreal::default_rnd);
+
+ friend const mpreal abs(const mpreal& v, mp_rnd_t rnd_mode = mpreal::default_rnd);
+ friend const mpreal dim(const mpreal& a, const mpreal& b, mp_rnd_t rnd_mode = mpreal::default_rnd);
+ friend inline const mpreal mul_2ui(const mpreal& v, unsigned long int k, mp_rnd_t rnd_mode = mpreal::default_rnd);
+ friend inline const mpreal mul_2si(const mpreal& v, long int k, mp_rnd_t rnd_mode = mpreal::default_rnd);
+ friend inline const mpreal div_2ui(const mpreal& v, unsigned long int k, mp_rnd_t rnd_mode = mpreal::default_rnd);
+ friend inline const mpreal div_2si(const mpreal& v, long int k, mp_rnd_t rnd_mode = mpreal::default_rnd);
+ friend int cmpabs(const mpreal& a,const mpreal& b);
+
+ friend const mpreal log (const mpreal& v, mp_rnd_t rnd_mode = mpreal::default_rnd);
+ friend const mpreal log2 (const mpreal& v, mp_rnd_t rnd_mode = mpreal::default_rnd);
+ friend const mpreal log10(const mpreal& v, mp_rnd_t rnd_mode = mpreal::default_rnd);
+ friend const mpreal exp (const mpreal& v, mp_rnd_t rnd_mode = mpreal::default_rnd);
+ friend const mpreal exp2 (const mpreal& v, mp_rnd_t rnd_mode = mpreal::default_rnd);
+ friend const mpreal exp10(const mpreal& v, mp_rnd_t rnd_mode = mpreal::default_rnd);
+ friend const mpreal log1p(const mpreal& v, mp_rnd_t rnd_mode = mpreal::default_rnd);
+ friend const mpreal expm1(const mpreal& v, mp_rnd_t rnd_mode = mpreal::default_rnd);
+
+ friend const mpreal cos(const mpreal& v, mp_rnd_t rnd_mode = mpreal::default_rnd);
+ friend const mpreal sin(const mpreal& v, mp_rnd_t rnd_mode = mpreal::default_rnd);
+ friend const mpreal tan(const mpreal& v, mp_rnd_t rnd_mode = mpreal::default_rnd);
+ friend const mpreal sec(const mpreal& v, mp_rnd_t rnd_mode = mpreal::default_rnd);
+ friend const mpreal csc(const mpreal& v, mp_rnd_t rnd_mode = mpreal::default_rnd);
+ friend const mpreal cot(const mpreal& v, mp_rnd_t rnd_mode = mpreal::default_rnd);
+ friend int sin_cos(mpreal& s, mpreal& c, const mpreal& v, mp_rnd_t rnd_mode = mpreal::default_rnd);
+
+ friend const mpreal acos (const mpreal& v, mp_rnd_t rnd_mode = mpreal::default_rnd);
+ friend const mpreal asin (const mpreal& v, mp_rnd_t rnd_mode = mpreal::default_rnd);
+ friend const mpreal atan (const mpreal& v, mp_rnd_t rnd_mode = mpreal::default_rnd);
+ friend const mpreal atan2 (const mpreal& y, const mpreal& x, mp_rnd_t rnd_mode = mpreal::default_rnd);
+ friend const mpreal acot (const mpreal& v, mp_rnd_t rnd_mode = mpreal::default_rnd);
+ friend const mpreal asec (const mpreal& v, mp_rnd_t rnd_mode = mpreal::default_rnd);
+ friend const mpreal acsc (const mpreal& v, mp_rnd_t rnd_mode = mpreal::default_rnd);
+
+ friend const mpreal cosh (const mpreal& v, mp_rnd_t rnd_mode = mpreal::default_rnd);
+ friend const mpreal sinh (const mpreal& v, mp_rnd_t rnd_mode = mpreal::default_rnd);
+ friend const mpreal tanh (const mpreal& v, mp_rnd_t rnd_mode = mpreal::default_rnd);
+ friend const mpreal sech (const mpreal& v, mp_rnd_t rnd_mode = mpreal::default_rnd);
+ friend const mpreal csch (const mpreal& v, mp_rnd_t rnd_mode = mpreal::default_rnd);
+ friend const mpreal coth (const mpreal& v, mp_rnd_t rnd_mode = mpreal::default_rnd);
+ friend const mpreal acosh (const mpreal& v, mp_rnd_t rnd_mode = mpreal::default_rnd);
+ friend const mpreal asinh (const mpreal& v, mp_rnd_t rnd_mode = mpreal::default_rnd);
+ friend const mpreal atanh (const mpreal& v, mp_rnd_t rnd_mode = mpreal::default_rnd);
+ friend const mpreal acoth (const mpreal& v, mp_rnd_t rnd_mode = mpreal::default_rnd);
+ friend const mpreal asech (const mpreal& v, mp_rnd_t rnd_mode = mpreal::default_rnd);
+ friend const mpreal acsch (const mpreal& v, mp_rnd_t rnd_mode = mpreal::default_rnd);
+
+ friend const mpreal hypot (const mpreal& x, const mpreal& y, mp_rnd_t rnd_mode = mpreal::default_rnd);
+
+ friend const mpreal fac_ui (unsigned long int v, mp_prec_t prec = mpreal::default_prec, mp_rnd_t rnd_mode = mpreal::default_rnd);
+ friend const mpreal eint (const mpreal& v, mp_rnd_t rnd_mode = mpreal::default_rnd);
+
+ friend const mpreal gamma (const mpreal& v, mp_rnd_t rnd_mode = mpreal::default_rnd);
+ friend const mpreal lngamma (const mpreal& v, mp_rnd_t rnd_mode = mpreal::default_rnd);
+ friend const mpreal lgamma (const mpreal& v, int *signp = 0, mp_rnd_t rnd_mode = mpreal::default_rnd);
+ friend const mpreal zeta (const mpreal& v, mp_rnd_t rnd_mode = mpreal::default_rnd);
+ friend const mpreal erf (const mpreal& v, mp_rnd_t rnd_mode = mpreal::default_rnd);
+ friend const mpreal erfc (const mpreal& v, mp_rnd_t rnd_mode = mpreal::default_rnd);
+ friend const mpreal besselj0 (const mpreal& v, mp_rnd_t rnd_mode = mpreal::default_rnd);
+ friend const mpreal besselj1 (const mpreal& v, mp_rnd_t rnd_mode = mpreal::default_rnd);
+ friend const mpreal besseljn (long n, const mpreal& v, mp_rnd_t rnd_mode = mpreal::default_rnd);
+ friend const mpreal bessely0 (const mpreal& v, mp_rnd_t rnd_mode = mpreal::default_rnd);
+ friend const mpreal bessely1 (const mpreal& v, mp_rnd_t rnd_mode = mpreal::default_rnd);
+ friend const mpreal besselyn (long n, const mpreal& v, mp_rnd_t rnd_mode = mpreal::default_rnd);
+ friend const mpreal fma (const mpreal& v1, const mpreal& v2, const mpreal& v3, mp_rnd_t rnd_mode = mpreal::default_rnd);
+ friend const mpreal fms (const mpreal& v1, const mpreal& v2, const mpreal& v3, mp_rnd_t rnd_mode = mpreal::default_rnd);
+ friend const mpreal agm (const mpreal& v1, const mpreal& v2, mp_rnd_t rnd_mode = mpreal::default_rnd);
+ friend const mpreal sum (const mpreal tab[], unsigned long int n, mp_rnd_t rnd_mode = mpreal::default_rnd);
+ friend int sgn(const mpreal& v); // -1 or +1
+
+// MPFR 2.4.0 Specifics
+#if (MPFR_VERSION >= MPFR_VERSION_NUM(2,4,0))
+ friend int sinh_cosh(mpreal& s, mpreal& c, const mpreal& v, mp_rnd_t rnd_mode = mpreal::default_rnd);
+ friend const mpreal li2(const mpreal& v, mp_rnd_t rnd_mode = mpreal::default_rnd);
+ friend const mpreal fmod (const mpreal& x, const mpreal& y, mp_rnd_t rnd_mode = mpreal::default_rnd);
+ friend const mpreal rec_sqrt(const mpreal& v, mp_rnd_t rnd_mode = mpreal::default_rnd);
+#endif
+
+// MPFR 3.0.0 Specifics
+#if (MPFR_VERSION >= MPFR_VERSION_NUM(3,0,0))
+ friend const mpreal digamma(const mpreal& v, mp_rnd_t rnd_mode = mpreal::default_rnd);
+ friend const mpreal ai(const mpreal& v, mp_rnd_t rnd_mode = mpreal::default_rnd);
+ friend const mpreal urandom (gmp_randstate_t& state,mp_rnd_t rnd_mode = mpreal::default_rnd); // use gmp_randinit_default() to init state, gmp_randclear() to clear
+ friend bool isregular(const mpreal& v);
+#endif
+
+ // Uniformly distributed random number generation in [0,1] using
+ // Mersenne-Twister algorithm by default.
+ // Use parameter to setup seed, e.g.: random((unsigned)time(NULL))
+ // Check urandom() for more precise control.
+ friend const mpreal random(unsigned int seed = 0);
+
+ // Exponent and mantissa manipulation
+ friend const mpreal frexp(const mpreal& v, mp_exp_t* exp);
+ friend const mpreal ldexp(const mpreal& v, mp_exp_t exp);
+
+ // Splits mpreal value into fractional and integer parts.
+ // Returns fractional part and stores integer part in n.
+ friend const mpreal modf(const mpreal& v, mpreal& n);
+
+ // Constants
+ // don't forget to call mpfr_free_cache() for every thread where you are using const-functions
+ friend const mpreal const_log2 (mp_prec_t prec = mpreal::default_prec, mp_rnd_t rnd_mode = mpreal::default_rnd);
+ friend const mpreal const_pi (mp_prec_t prec = mpreal::default_prec, mp_rnd_t rnd_mode = mpreal::default_rnd);
+ friend const mpreal const_euler (mp_prec_t prec = mpreal::default_prec, mp_rnd_t rnd_mode = mpreal::default_rnd);
+ friend const mpreal const_catalan (mp_prec_t prec = mpreal::default_prec, mp_rnd_t rnd_mode = mpreal::default_rnd);
+ // returns +inf iff sign>=0 otherwise -inf
+ friend const mpreal const_infinity(int sign = 1, mp_prec_t prec = mpreal::default_prec, mp_rnd_t rnd_mode = mpreal::default_rnd);
+
+ // Output/ Input
+ friend std::ostream& operator<<(std::ostream& os, const mpreal& v);
+ friend std::istream& operator>>(std::istream& is, mpreal& v);
+
+ // Integer Related Functions
+ friend const mpreal rint (const mpreal& v, mp_rnd_t rnd_mode = mpreal::default_rnd);
+ friend const mpreal ceil (const mpreal& v);
+ friend const mpreal floor(const mpreal& v);
+ friend const mpreal round(const mpreal& v);
+ friend const mpreal trunc(const mpreal& v);
+ friend const mpreal rint_ceil (const mpreal& v, mp_rnd_t rnd_mode = mpreal::default_rnd);
+ friend const mpreal rint_floor(const mpreal& v, mp_rnd_t rnd_mode = mpreal::default_rnd);
+ friend const mpreal rint_round(const mpreal& v, mp_rnd_t rnd_mode = mpreal::default_rnd);
+ friend const mpreal rint_trunc(const mpreal& v, mp_rnd_t rnd_mode = mpreal::default_rnd);
+ friend const mpreal frac (const mpreal& v, mp_rnd_t rnd_mode = mpreal::default_rnd);
+ friend const mpreal remainder (const mpreal& x, const mpreal& y, mp_rnd_t rnd_mode = mpreal::default_rnd);
+ friend const mpreal remquo (long* q, const mpreal& x, const mpreal& y, mp_rnd_t rnd_mode = mpreal::default_rnd);
+
+ // Miscellaneous Functions
+ friend const mpreal nexttoward (const mpreal& x, const mpreal& y);
+ friend const mpreal nextabove (const mpreal& x);
+ friend const mpreal nextbelow (const mpreal& x);
+
+ // use gmp_randinit_default() to init state, gmp_randclear() to clear
+ friend const mpreal urandomb (gmp_randstate_t& state);
+
+// MPFR < 2.4.2 Specifics
+#if (MPFR_VERSION <= MPFR_VERSION_NUM(2,4,2))
+ friend const mpreal random2 (mp_size_t size, mp_exp_t exp);
+#endif
+
+ // Instance Checkers
+ friend bool isnan (const mpreal& v);
+ friend bool isinf (const mpreal& v);
+ friend bool isfinite(const mpreal& v);
+
+ friend bool isnum(const mpreal& v);
+ friend bool iszero(const mpreal& v);
+ friend bool isint(const mpreal& v);
+
+ // Set/Get instance properties
+ inline mp_prec_t get_prec() const;
+ inline void set_prec(mp_prec_t prec, mp_rnd_t rnd_mode = default_rnd); // Change precision with rounding mode
+
+ // Aliases for get_prec(), set_prec() - needed for compatibility with std::complex<mpreal> interface
+ inline mpreal& setPrecision(int Precision, mp_rnd_t RoundingMode = (mpfr_get_default_rounding_mode)());
+ inline int getPrecision() const;
+
+ // Set mpreal to +/- inf, NaN, +/-0
+ mpreal& setInf (int Sign = +1);
+ mpreal& setNan ();
+ mpreal& setZero (int Sign = +1);
+ mpreal& setSign (int Sign, mp_rnd_t RoundingMode = (mpfr_get_default_rounding_mode)());
+
+ //Exponent
+ mp_exp_t get_exp();
+ int set_exp(mp_exp_t e);
+ int check_range (int t, mp_rnd_t rnd_mode = default_rnd);
+ int subnormalize (int t,mp_rnd_t rnd_mode = default_rnd);
+
+ // Inexact conversion from float
+ inline bool fits_in_bits(double x, int n);
+
+ // Set/Get global properties
+ static void set_default_prec(mp_prec_t prec);
+ static mp_prec_t get_default_prec();
+ static void set_default_base(int base);
+ static int get_default_base();
+ static void set_double_bits(int dbits);
+ static int get_double_bits();
+ static void set_default_rnd(mp_rnd_t rnd_mode);
+ static mp_rnd_t get_default_rnd();
+ static mp_exp_t get_emin (void);
+ static mp_exp_t get_emax (void);
+ static mp_exp_t get_emin_min (void);
+ static mp_exp_t get_emin_max (void);
+ static mp_exp_t get_emax_min (void);
+ static mp_exp_t get_emax_max (void);
+ static int set_emin (mp_exp_t exp);
+ static int set_emax (mp_exp_t exp);
+
+ // Efficient swapping of two mpreal values
+ friend void swap(mpreal& x, mpreal& y);
+
+ //Min Max - macros is evil. Needed for systems which defines max and min globally as macros (e.g. Windows)
+ //Hope that globally defined macros use > < operations only
+ friend const mpreal fmax(const mpreal& x, const mpreal& y, mp_rnd_t rnd_mode = default_rnd);
+ friend const mpreal fmin(const mpreal& x, const mpreal& y, mp_rnd_t rnd_mode = default_rnd);
+
+#if defined (MPREAL_HAVE_CUSTOM_MPFR_MALLOC)
+
+private:
+ // Optimized dynamic memory allocation/(re-)deallocation.
+ static bool is_custom_malloc;
+ static void *mpreal_allocate (size_t alloc_size);
+ static void *mpreal_reallocate (void *ptr, size_t old_size, size_t new_size);
+ static void mpreal_free (void *ptr, size_t size);
+ inline static void set_custom_malloc (void);
+
+#endif
+
+
+private:
+ // Human friendly Debug Preview in Visual Studio.
+ // Put one of these lines:
+ //
+ // mpfr::mpreal=<DebugView> ; Show value only
+ // mpfr::mpreal=<DebugView>, <mp[0]._mpfr_prec,u>bits ; Show value & precision
+ //
+ // at the beginning of
+ // [Visual Studio Installation Folder]\Common7\Packages\Debugger\autoexp.dat
+ MPREAL_MSVC_DEBUGVIEW_DATA
+};
+
+//////////////////////////////////////////////////////////////////////////
+// Exceptions
+class conversion_overflow : public std::exception {
+public:
+ std::string why() { return "inexact conversion from floating point"; }
+};
+
+namespace internal{
+
+ // Use SFINAE to restrict arithmetic operations instantiation only for numeric types
+ // This is needed for smooth integration with libraries based on expression templates
+ template <typename ArgumentType> struct result_type {};
+
+ template <> struct result_type<mpreal> {typedef mpreal type;};
+ template <> struct result_type<mpz_t> {typedef mpreal type;};
+ template <> struct result_type<mpq_t> {typedef mpreal type;};
+ template <> struct result_type<long double> {typedef mpreal type;};
+ template <> struct result_type<double> {typedef mpreal type;};
+ template <> struct result_type<unsigned long int> {typedef mpreal type;};
+ template <> struct result_type<unsigned int> {typedef mpreal type;};
+ template <> struct result_type<long int> {typedef mpreal type;};
+ template <> struct result_type<int> {typedef mpreal type;};
+
+#if defined (MPREAL_HAVE_INT64_SUPPORT)
+ template <> struct result_type<int64_t > {typedef mpreal type;};
+ template <> struct result_type<uint64_t > {typedef mpreal type;};
+#endif
+}
+
+// + Addition
+template <typename Rhs>
+inline const typename internal::result_type<Rhs>::type
+ operator+(const mpreal& lhs, const Rhs& rhs){ return mpreal(lhs) += rhs; }
+
+template <typename Lhs>
+inline const typename internal::result_type<Lhs>::type
+ operator+(const Lhs& lhs, const mpreal& rhs){ return mpreal(rhs) += lhs; }
+
+// - Subtraction
+template <typename Rhs>
+inline const typename internal::result_type<Rhs>::type
+ operator-(const mpreal& lhs, const Rhs& rhs){ return mpreal(lhs) -= rhs; }
+
+template <typename Lhs>
+inline const typename internal::result_type<Lhs>::type
+ operator-(const Lhs& lhs, const mpreal& rhs){ return mpreal(lhs) -= rhs; }
+
+// * Multiplication
+template <typename Rhs>
+inline const typename internal::result_type<Rhs>::type
+ operator*(const mpreal& lhs, const Rhs& rhs){ return mpreal(lhs) *= rhs; }
+
+template <typename Lhs>
+inline const typename internal::result_type<Lhs>::type
+ operator*(const Lhs& lhs, const mpreal& rhs){ return mpreal(rhs) *= lhs; }
+
+// / Division
+template <typename Rhs>
+inline const typename internal::result_type<Rhs>::type
+ operator/(const mpreal& lhs, const Rhs& rhs){ return mpreal(lhs) /= rhs; }
+
+template <typename Lhs>
+inline const typename internal::result_type<Lhs>::type
+ operator/(const Lhs& lhs, const mpreal& rhs){ return mpreal(lhs) /= rhs; }
+
+//////////////////////////////////////////////////////////////////////////
+// sqrt
+const mpreal sqrt(const unsigned int v, mp_rnd_t rnd_mode = mpreal::default_rnd);
+const mpreal sqrt(const long int v, mp_rnd_t rnd_mode = mpreal::default_rnd);
+const mpreal sqrt(const int v, mp_rnd_t rnd_mode = mpreal::default_rnd);
+const mpreal sqrt(const long double v, mp_rnd_t rnd_mode = mpreal::default_rnd);
+const mpreal sqrt(const double v, mp_rnd_t rnd_mode = mpreal::default_rnd);
+
+//////////////////////////////////////////////////////////////////////////
+// pow
+const mpreal pow(const mpreal& a, const unsigned int b, mp_rnd_t rnd_mode = mpreal::default_rnd);
+const mpreal pow(const mpreal& a, const int b, mp_rnd_t rnd_mode = mpreal::default_rnd);
+const mpreal pow(const mpreal& a, const long double b, mp_rnd_t rnd_mode = mpreal::default_rnd);
+const mpreal pow(const mpreal& a, const double b, mp_rnd_t rnd_mode = mpreal::default_rnd);
+
+const mpreal pow(const unsigned int a, const mpreal& b, mp_rnd_t rnd_mode = mpreal::default_rnd);
+const mpreal pow(const long int a, const mpreal& b, mp_rnd_t rnd_mode = mpreal::default_rnd);
+const mpreal pow(const int a, const mpreal& b, mp_rnd_t rnd_mode = mpreal::default_rnd);
+const mpreal pow(const long double a, const mpreal& b, mp_rnd_t rnd_mode = mpreal::default_rnd);
+const mpreal pow(const double a, const mpreal& b, mp_rnd_t rnd_mode = mpreal::default_rnd);
+
+const mpreal pow(const unsigned long int a, const unsigned int b, mp_rnd_t rnd_mode = mpreal::default_rnd);
+const mpreal pow(const unsigned long int a, const long int b, mp_rnd_t rnd_mode = mpreal::default_rnd);
+const mpreal pow(const unsigned long int a, const int b, mp_rnd_t rnd_mode = mpreal::default_rnd);
+const mpreal pow(const unsigned long int a, const long double b, mp_rnd_t rnd_mode = mpreal::default_rnd);
+const mpreal pow(const unsigned long int a, const double b, mp_rnd_t rnd_mode = mpreal::default_rnd);
+
+const mpreal pow(const unsigned int a, const unsigned long int b, mp_rnd_t rnd_mode = mpreal::default_rnd);
+const mpreal pow(const unsigned int a, const unsigned int b, mp_rnd_t rnd_mode = mpreal::default_rnd);
+const mpreal pow(const unsigned int a, const long int b, mp_rnd_t rnd_mode = mpreal::default_rnd);
+const mpreal pow(const unsigned int a, const int b, mp_rnd_t rnd_mode = mpreal::default_rnd);
+const mpreal pow(const unsigned int a, const long double b, mp_rnd_t rnd_mode = mpreal::default_rnd);
+const mpreal pow(const unsigned int a, const double b, mp_rnd_t rnd_mode = mpreal::default_rnd);
+
+const mpreal pow(const long int a, const unsigned long int b, mp_rnd_t rnd_mode = mpreal::default_rnd);
+const mpreal pow(const long int a, const unsigned int b, mp_rnd_t rnd_mode = mpreal::default_rnd);
+const mpreal pow(const long int a, const long int b, mp_rnd_t rnd_mode = mpreal::default_rnd);
+const mpreal pow(const long int a, const int b, mp_rnd_t rnd_mode = mpreal::default_rnd);
+const mpreal pow(const long int a, const long double b, mp_rnd_t rnd_mode = mpreal::default_rnd);
+const mpreal pow(const long int a, const double b, mp_rnd_t rnd_mode = mpreal::default_rnd);
+
+const mpreal pow(const int a, const unsigned long int b, mp_rnd_t rnd_mode = mpreal::default_rnd);
+const mpreal pow(const int a, const unsigned int b, mp_rnd_t rnd_mode = mpreal::default_rnd);
+const mpreal pow(const int a, const long int b, mp_rnd_t rnd_mode = mpreal::default_rnd);
+const mpreal pow(const int a, const int b, mp_rnd_t rnd_mode = mpreal::default_rnd);
+const mpreal pow(const int a, const long double b, mp_rnd_t rnd_mode = mpreal::default_rnd);
+const mpreal pow(const int a, const double b, mp_rnd_t rnd_mode = mpreal::default_rnd);
+
+const mpreal pow(const long double a, const long double b, mp_rnd_t rnd_mode = mpreal::default_rnd);
+const mpreal pow(const long double a, const unsigned long int b, mp_rnd_t rnd_mode = mpreal::default_rnd);
+const mpreal pow(const long double a, const unsigned int b, mp_rnd_t rnd_mode = mpreal::default_rnd);
+const mpreal pow(const long double a, const long int b, mp_rnd_t rnd_mode = mpreal::default_rnd);
+const mpreal pow(const long double a, const int b, mp_rnd_t rnd_mode = mpreal::default_rnd);
+
+const mpreal pow(const double a, const double b, mp_rnd_t rnd_mode = mpreal::default_rnd);
+const mpreal pow(const double a, const unsigned long int b, mp_rnd_t rnd_mode = mpreal::default_rnd);
+const mpreal pow(const double a, const unsigned int b, mp_rnd_t rnd_mode = mpreal::default_rnd);
+const mpreal pow(const double a, const long int b, mp_rnd_t rnd_mode = mpreal::default_rnd);
+const mpreal pow(const double a, const int b, mp_rnd_t rnd_mode = mpreal::default_rnd);
+
+//////////////////////////////////////////////////////////////////////////
+// Estimate machine epsilon for the given precision
+// Returns smallest eps such that 1.0 + eps != 1.0
+inline const mpreal machine_epsilon(mp_prec_t prec = mpreal::get_default_prec());
+
+// Returns the positive distance from abs(x) to the next larger in magnitude floating point number of the same precision as x
+inline const mpreal machine_epsilon(const mpreal& x);
+
+inline const mpreal mpreal_min(mp_prec_t prec = mpreal::get_default_prec());
+inline const mpreal mpreal_max(mp_prec_t prec = mpreal::get_default_prec());
+inline bool isEqualFuzzy(const mpreal& a, const mpreal& b, const mpreal& eps);
+inline bool isEqualUlps(const mpreal& a, const mpreal& b, int maxUlps);
+
+//////////////////////////////////////////////////////////////////////////
+// Bits - decimal digits relation
+// bits = ceil(digits*log[2](10))
+// digits = floor(bits*log[10](2))
+
+inline mp_prec_t digits2bits(int d);
+inline int bits2digits(mp_prec_t b);
+
+//////////////////////////////////////////////////////////////////////////
+// min, max
+const mpreal (max)(const mpreal& x, const mpreal& y);
+const mpreal (min)(const mpreal& x, const mpreal& y);
+
+//////////////////////////////////////////////////////////////////////////
+// Implementation
+//////////////////////////////////////////////////////////////////////////
+
+//////////////////////////////////////////////////////////////////////////
+// Operators - Assignment
+inline mpreal& mpreal::operator=(const mpreal& v)
+{
+ if (this != &v)
+ {
+ mpfr_clear(mp);
+ mpfr_init2(mp,mpfr_get_prec(v.mp));
+ mpfr_set(mp,v.mp,default_rnd);
+
+ MPREAL_MSVC_DEBUGVIEW_CODE;
+ }
+ return *this;
+}
+
+inline mpreal& mpreal::operator=(const mpf_t v)
+{
+ mpfr_set_f(mp,v,default_rnd);
+
+ MPREAL_MSVC_DEBUGVIEW_CODE;
+ return *this;
+}
+
+inline mpreal& mpreal::operator=(const mpz_t v)
+{
+ mpfr_set_z(mp,v,default_rnd);
+
+ MPREAL_MSVC_DEBUGVIEW_CODE;
+ return *this;
+}
+
+inline mpreal& mpreal::operator=(const mpq_t v)
+{
+ mpfr_set_q(mp,v,default_rnd);
+
+ MPREAL_MSVC_DEBUGVIEW_CODE;
+ return *this;
+}
+
+inline mpreal& mpreal::operator=(const long double v)
+{
+ mpfr_set_ld(mp,v,default_rnd);
+
+ MPREAL_MSVC_DEBUGVIEW_CODE;
+ return *this;
+}
+
+inline mpreal& mpreal::operator=(const double v)
+{
+ if(double_bits == -1 || fits_in_bits(v, double_bits))
+ {
+ mpfr_set_d(mp,v,default_rnd);
+
+ MPREAL_MSVC_DEBUGVIEW_CODE;
+ }
+ else
+ throw conversion_overflow();
+
+ return *this;
+}
+
+inline mpreal& mpreal::operator=(const unsigned long int v)
+{
+ mpfr_set_ui(mp,v,default_rnd);
+
+ MPREAL_MSVC_DEBUGVIEW_CODE;
+ return *this;
+}
+
+inline mpreal& mpreal::operator=(const unsigned int v)
+{
+ mpfr_set_ui(mp,v,default_rnd);
+
+ MPREAL_MSVC_DEBUGVIEW_CODE;
+ return *this;
+}
+
+inline mpreal& mpreal::operator=(const long int v)
+{
+ mpfr_set_si(mp,v,default_rnd);
+
+ MPREAL_MSVC_DEBUGVIEW_CODE;
+ return *this;
+}
+
+inline mpreal& mpreal::operator=(const int v)
+{
+ mpfr_set_si(mp,v,default_rnd);
+
+ MPREAL_MSVC_DEBUGVIEW_CODE;
+ return *this;
+}
+
+//////////////////////////////////////////////////////////////////////////
+// + Addition
+inline mpreal& mpreal::operator+=(const mpreal& v)
+{
+ mpfr_add(mp,mp,v.mp,default_rnd);
+ MPREAL_MSVC_DEBUGVIEW_CODE;
+ return *this;
+}
+
+inline mpreal& mpreal::operator+=(const mpf_t u)
+{
+ *this += mpreal(u);
+ MPREAL_MSVC_DEBUGVIEW_CODE;
+ return *this;
+}
+
+inline mpreal& mpreal::operator+=(const mpz_t u)
+{
+ mpfr_add_z(mp,mp,u,default_rnd);
+ MPREAL_MSVC_DEBUGVIEW_CODE;
+ return *this;
+}
+
+inline mpreal& mpreal::operator+=(const mpq_t u)
+{
+ mpfr_add_q(mp,mp,u,default_rnd);
+ MPREAL_MSVC_DEBUGVIEW_CODE;
+ return *this;
+}
+
+inline mpreal& mpreal::operator+= (const long double u)
+{
+ *this += mpreal(u);
+ MPREAL_MSVC_DEBUGVIEW_CODE;
+ return *this;
+}
+
+inline mpreal& mpreal::operator+= (const double u)
+{
+#if (MPFR_VERSION >= MPFR_VERSION_NUM(2,4,0))
+ mpfr_add_d(mp,mp,u,default_rnd);
+#else
+ *this += mpreal(u);
+#endif
+
+ MPREAL_MSVC_DEBUGVIEW_CODE;
+ return *this;
+}
+
+inline mpreal& mpreal::operator+=(const unsigned long int u)
+{
+ mpfr_add_ui(mp,mp,u,default_rnd);
+ MPREAL_MSVC_DEBUGVIEW_CODE;
+ return *this;
+}
+
+inline mpreal& mpreal::operator+=(const unsigned int u)
+{
+ mpfr_add_ui(mp,mp,u,default_rnd);
+ MPREAL_MSVC_DEBUGVIEW_CODE;
+ return *this;
+}
+
+inline mpreal& mpreal::operator+=(const long int u)
+{
+ mpfr_add_si(mp,mp,u,default_rnd);
+ MPREAL_MSVC_DEBUGVIEW_CODE;
+ return *this;
+}
+
+inline mpreal& mpreal::operator+=(const int u)
+{
+ mpfr_add_si(mp,mp,u,default_rnd);
+ MPREAL_MSVC_DEBUGVIEW_CODE;
+ return *this;
+}
+
+#if defined (MPREAL_HAVE_INT64_SUPPORT)
+inline mpreal& mpreal::operator+=(const int64_t u){ *this += mpreal(u); MPREAL_MSVC_DEBUGVIEW_CODE; return *this; }
+inline mpreal& mpreal::operator+=(const uint64_t u){ *this += mpreal(u); MPREAL_MSVC_DEBUGVIEW_CODE; return *this; }
+inline mpreal& mpreal::operator-=(const int64_t u){ *this -= mpreal(u); MPREAL_MSVC_DEBUGVIEW_CODE; return *this; }
+inline mpreal& mpreal::operator-=(const uint64_t u){ *this -= mpreal(u); MPREAL_MSVC_DEBUGVIEW_CODE; return *this; }
+inline mpreal& mpreal::operator*=(const int64_t u){ *this *= mpreal(u); MPREAL_MSVC_DEBUGVIEW_CODE; return *this; }
+inline mpreal& mpreal::operator*=(const uint64_t u){ *this *= mpreal(u); MPREAL_MSVC_DEBUGVIEW_CODE; return *this; }
+inline mpreal& mpreal::operator/=(const int64_t u){ *this /= mpreal(u); MPREAL_MSVC_DEBUGVIEW_CODE; return *this; }
+inline mpreal& mpreal::operator/=(const uint64_t u){ *this /= mpreal(u); MPREAL_MSVC_DEBUGVIEW_CODE; return *this; }
+#endif
+
+inline const mpreal mpreal::operator+()const { return mpreal(*this); }
+
+inline const mpreal operator+(const mpreal& a, const mpreal& b)
+{
+ // prec(a+b) = max(prec(a),prec(b))
+ if(a.get_prec()>b.get_prec()) return mpreal(a) += b;
+ else return mpreal(b) += a;
+}
+
+inline mpreal& mpreal::operator++()
+{
+ return *this += 1;
+}
+
+inline const mpreal mpreal::operator++ (int)
+{
+ mpreal x(*this);
+ *this += 1;
+ return x;
+}
+
+inline mpreal& mpreal::operator--()
+{
+ return *this -= 1;
+}
+
+inline const mpreal mpreal::operator-- (int)
+{
+ mpreal x(*this);
+ *this -= 1;
+ return x;
+}
+
+//////////////////////////////////////////////////////////////////////////
+// - Subtraction
+inline mpreal& mpreal::operator-= (const mpreal& v)
+{
+ mpfr_sub(mp,mp,v.mp,default_rnd);
+ MPREAL_MSVC_DEBUGVIEW_CODE;
+ return *this;
+}
+
+inline mpreal& mpreal::operator-=(const mpz_t v)
+{
+ mpfr_sub_z(mp,mp,v,default_rnd);
+ MPREAL_MSVC_DEBUGVIEW_CODE;
+ return *this;
+}
+
+inline mpreal& mpreal::operator-=(const mpq_t v)
+{
+ mpfr_sub_q(mp,mp,v,default_rnd);
+ MPREAL_MSVC_DEBUGVIEW_CODE;
+ return *this;
+}
+
+inline mpreal& mpreal::operator-=(const long double v)
+{
+ *this -= mpreal(v);
+ MPREAL_MSVC_DEBUGVIEW_CODE;
+ return *this;
+}
+
+inline mpreal& mpreal::operator-=(const double v)
+{
+#if (MPFR_VERSION >= MPFR_VERSION_NUM(2,4,0))
+ mpfr_sub_d(mp,mp,v,default_rnd);
+#else
+ *this -= mpreal(v);
+#endif
+
+ MPREAL_MSVC_DEBUGVIEW_CODE;
+ return *this;
+}
+
+inline mpreal& mpreal::operator-=(const unsigned long int v)
+{
+ mpfr_sub_ui(mp,mp,v,default_rnd);
+ MPREAL_MSVC_DEBUGVIEW_CODE;
+ return *this;
+}
+
+inline mpreal& mpreal::operator-=(const unsigned int v)
+{
+ mpfr_sub_ui(mp,mp,v,default_rnd);
+ MPREAL_MSVC_DEBUGVIEW_CODE;
+ return *this;
+}
+
+inline mpreal& mpreal::operator-=(const long int v)
+{
+ mpfr_sub_si(mp,mp,v,default_rnd);
+ MPREAL_MSVC_DEBUGVIEW_CODE;
+ return *this;
+}
+
+inline mpreal& mpreal::operator-=(const int v)
+{
+ mpfr_sub_si(mp,mp,v,default_rnd);
+ MPREAL_MSVC_DEBUGVIEW_CODE;
+ return *this;
+}
+
+inline const mpreal mpreal::operator-()const
+{
+ mpreal u(*this);
+ mpfr_neg(u.mp,u.mp,default_rnd);
+ return u;
+}
+
+inline const mpreal operator-(const mpreal& a, const mpreal& b)
+{
+ // prec(a-b) = max(prec(a),prec(b))
+ if(a.getPrecision() >= b.getPrecision())
+ {
+ return mpreal(a) -= b;
+ }else{
+ mpreal x(a);
+ x.setPrecision(b.getPrecision());
+ return x -= b;
+ }
+}
+
+inline const mpreal operator-(const double b, const mpreal& a)
+{
+#if (MPFR_VERSION >= MPFR_VERSION_NUM(2,4,0))
+ mpreal x(a);
+ mpfr_d_sub(x.mp,b,a.mp,mpreal::default_rnd);
+ return x;
+#else
+ return mpreal(b) -= a;
+#endif
+}
+
+inline const mpreal operator-(const unsigned long int b, const mpreal& a)
+{
+ mpreal x(a);
+ mpfr_ui_sub(x.mp,b,a.mp,mpreal::default_rnd);
+ return x;
+}
+
+inline const mpreal operator-(const unsigned int b, const mpreal& a)
+{
+ mpreal x(a);
+ mpfr_ui_sub(x.mp,b,a.mp,mpreal::default_rnd);
+ return x;
+}
+
+inline const mpreal operator-(const long int b, const mpreal& a)
+{
+ mpreal x(a);
+ mpfr_si_sub(x.mp,b,a.mp,mpreal::default_rnd);
+ return x;
+}
+
+inline const mpreal operator-(const int b, const mpreal& a)
+{
+ mpreal x(a);
+ mpfr_si_sub(x.mp,b,a.mp,mpreal::default_rnd);
+ return x;
+}
+
+//////////////////////////////////////////////////////////////////////////
+// * Multiplication
+inline mpreal& mpreal::operator*= (const mpreal& v)
+{
+ mpfr_mul(mp,mp,v.mp,default_rnd);
+ MPREAL_MSVC_DEBUGVIEW_CODE;
+ return *this;
+}
+
+inline mpreal& mpreal::operator*=(const mpz_t v)
+{
+ mpfr_mul_z(mp,mp,v,default_rnd);
+ MPREAL_MSVC_DEBUGVIEW_CODE;
+ return *this;
+}
+
+inline mpreal& mpreal::operator*=(const mpq_t v)
+{
+ mpfr_mul_q(mp,mp,v,default_rnd);
+ MPREAL_MSVC_DEBUGVIEW_CODE;
+ return *this;
+}
+
+inline mpreal& mpreal::operator*=(const long double v)
+{
+ *this *= mpreal(v);
+ MPREAL_MSVC_DEBUGVIEW_CODE;
+ return *this;
+}
+
+inline mpreal& mpreal::operator*=(const double v)
+{
+#if (MPFR_VERSION >= MPFR_VERSION_NUM(2,4,0))
+ mpfr_mul_d(mp,mp,v,default_rnd);
+#else
+ *this *= mpreal(v);
+#endif
+
+ MPREAL_MSVC_DEBUGVIEW_CODE;
+ return *this;
+}
+
+inline mpreal& mpreal::operator*=(const unsigned long int v)
+{
+ mpfr_mul_ui(mp,mp,v,default_rnd);
+ MPREAL_MSVC_DEBUGVIEW_CODE;
+ return *this;
+}
+
+inline mpreal& mpreal::operator*=(const unsigned int v)
+{
+ mpfr_mul_ui(mp,mp,v,default_rnd);
+ MPREAL_MSVC_DEBUGVIEW_CODE;
+ return *this;
+}
+
+inline mpreal& mpreal::operator*=(const long int v)
+{
+ mpfr_mul_si(mp,mp,v,default_rnd);
+ MPREAL_MSVC_DEBUGVIEW_CODE;
+ return *this;
+}
+
+inline mpreal& mpreal::operator*=(const int v)
+{
+ mpfr_mul_si(mp,mp,v,default_rnd);
+ MPREAL_MSVC_DEBUGVIEW_CODE;
+ return *this;
+}
+
+inline const mpreal operator*(const mpreal& a, const mpreal& b)
+{
+ // prec(a*b) = max(prec(a),prec(b))
+ if(a.getPrecision() >= b.getPrecision()) return mpreal(a) *= b;
+ else return mpreal(b) *= a;
+}
+
+//////////////////////////////////////////////////////////////////////////
+// / Division
+inline mpreal& mpreal::operator/=(const mpreal& v)
+{
+ mpfr_div(mp,mp,v.mp,default_rnd);
+ MPREAL_MSVC_DEBUGVIEW_CODE;
+ return *this;
+}
+
+inline mpreal& mpreal::operator/=(const mpz_t v)
+{
+ mpfr_div_z(mp,mp,v,default_rnd);
+ MPREAL_MSVC_DEBUGVIEW_CODE;
+ return *this;
+}
+
+inline mpreal& mpreal::operator/=(const mpq_t v)
+{
+ mpfr_div_q(mp,mp,v,default_rnd);
+ MPREAL_MSVC_DEBUGVIEW_CODE;
+ return *this;
+}
+
+inline mpreal& mpreal::operator/=(const long double v)
+{
+ *this /= mpreal(v);
+ MPREAL_MSVC_DEBUGVIEW_CODE;
+ return *this;
+}
+
+inline mpreal& mpreal::operator/=(const double v)
+{
+#if (MPFR_VERSION >= MPFR_VERSION_NUM(2,4,0))
+ mpfr_div_d(mp,mp,v,default_rnd);
+#else
+ *this /= mpreal(v);
+#endif
+ MPREAL_MSVC_DEBUGVIEW_CODE;
+ return *this;
+}
+
+inline mpreal& mpreal::operator/=(const unsigned long int v)
+{
+ mpfr_div_ui(mp,mp,v,default_rnd);
+ MPREAL_MSVC_DEBUGVIEW_CODE;
+ return *this;
+}
+
+inline mpreal& mpreal::operator/=(const unsigned int v)
+{
+ mpfr_div_ui(mp,mp,v,default_rnd);
+ MPREAL_MSVC_DEBUGVIEW_CODE;
+ return *this;
+}
+
+inline mpreal& mpreal::operator/=(const long int v)
+{
+ mpfr_div_si(mp,mp,v,default_rnd);
+ MPREAL_MSVC_DEBUGVIEW_CODE;
+ return *this;
+}
+
+inline mpreal& mpreal::operator/=(const int v)
+{
+ mpfr_div_si(mp,mp,v,default_rnd);
+ MPREAL_MSVC_DEBUGVIEW_CODE;
+ return *this;
+}
+
+inline const mpreal operator/(const mpreal& a, const mpreal& b)
+{
+ // prec(a/b) = max(prec(a),prec(b))
+ if(a.getPrecision() >= b.getPrecision())
+ {
+ return mpreal(a) /= b;
+ }else{
+
+ mpreal x(a);
+ x.setPrecision(b.getPrecision());
+ return x /= b;
+ }
+}
+
+inline const mpreal operator/(const unsigned long int b, const mpreal& a)
+{
+ mpreal x(a);
+ mpfr_ui_div(x.mp,b,a.mp,mpreal::default_rnd);
+ return x;
+}
+
+inline const mpreal operator/(const unsigned int b, const mpreal& a)
+{
+ mpreal x(a);
+ mpfr_ui_div(x.mp,b,a.mp,mpreal::default_rnd);
+ return x;
+}
+
+inline const mpreal operator/(const long int b, const mpreal& a)
+{
+ mpreal x(a);
+ mpfr_si_div(x.mp,b,a.mp,mpreal::default_rnd);
+ return x;
+}
+
+inline const mpreal operator/(const int b, const mpreal& a)
+{
+ mpreal x(a);
+ mpfr_si_div(x.mp,b,a.mp,mpreal::default_rnd);
+ return x;
+}
+
+inline const mpreal operator/(const double b, const mpreal& a)
+{
+#if (MPFR_VERSION >= MPFR_VERSION_NUM(2,4,0))
+ mpreal x(a);
+ mpfr_d_div(x.mp,b,a.mp,mpreal::default_rnd);
+ return x;
+#else
+ return mpreal(b) /= a;
+#endif
+}
+
+//////////////////////////////////////////////////////////////////////////
+// Shifts operators - Multiplication/Division by power of 2
+inline mpreal& mpreal::operator<<=(const unsigned long int u)
+{
+ mpfr_mul_2ui(mp,mp,u,default_rnd);
+ MPREAL_MSVC_DEBUGVIEW_CODE;
+ return *this;
+}
+
+inline mpreal& mpreal::operator<<=(const unsigned int u)
+{
+ mpfr_mul_2ui(mp,mp,static_cast<unsigned long int>(u),default_rnd);
+ MPREAL_MSVC_DEBUGVIEW_CODE;
+ return *this;
+}
+
+inline mpreal& mpreal::operator<<=(const long int u)
+{
+ mpfr_mul_2si(mp,mp,u,default_rnd);
+ MPREAL_MSVC_DEBUGVIEW_CODE;
+ return *this;
+}
+
+inline mpreal& mpreal::operator<<=(const int u)
+{
+ mpfr_mul_2si(mp,mp,static_cast<long int>(u),default_rnd);
+ MPREAL_MSVC_DEBUGVIEW_CODE;
+ return *this;
+}
+
+inline mpreal& mpreal::operator>>=(const unsigned long int u)
+{
+ mpfr_div_2ui(mp,mp,u,default_rnd);
+ MPREAL_MSVC_DEBUGVIEW_CODE;
+ return *this;
+}
+
+inline mpreal& mpreal::operator>>=(const unsigned int u)
+{
+ mpfr_div_2ui(mp,mp,static_cast<unsigned long int>(u),default_rnd);
+ MPREAL_MSVC_DEBUGVIEW_CODE;
+ return *this;
+}
+
+inline mpreal& mpreal::operator>>=(const long int u)
+{
+ mpfr_div_2si(mp,mp,u,default_rnd);
+ MPREAL_MSVC_DEBUGVIEW_CODE;
+ return *this;
+}
+
+inline mpreal& mpreal::operator>>=(const int u)
+{
+ mpfr_div_2si(mp,mp,static_cast<long int>(u),default_rnd);
+ MPREAL_MSVC_DEBUGVIEW_CODE;
+ return *this;
+}
+
+inline const mpreal operator<<(const mpreal& v, const unsigned long int k)
+{
+ return mul_2ui(v,k);
+}
+
+inline const mpreal operator<<(const mpreal& v, const unsigned int k)
+{
+ return mul_2ui(v,static_cast<unsigned long int>(k));
+}
+
+inline const mpreal operator<<(const mpreal& v, const long int k)
+{
+ return mul_2si(v,k);
+}
+
+inline const mpreal operator<<(const mpreal& v, const int k)
+{
+ return mul_2si(v,static_cast<long int>(k));
+}
+
+inline const mpreal operator>>(const mpreal& v, const unsigned long int k)
+{
+ return div_2ui(v,k);
+}
+
+inline const mpreal operator>>(const mpreal& v, const long int k)
+{
+ return div_2si(v,k);
+}
+
+inline const mpreal operator>>(const mpreal& v, const unsigned int k)
+{
+ return div_2ui(v,static_cast<unsigned long int>(k));
+}
+
+inline const mpreal operator>>(const mpreal& v, const int k)
+{
+ return div_2si(v,static_cast<long int>(k));
+}
+
+// mul_2ui
+inline const mpreal mul_2ui(const mpreal& v, unsigned long int k, mp_rnd_t rnd_mode)
+{
+ mpreal x(v);
+ mpfr_mul_2ui(x.mp,v.mp,k,rnd_mode);
+ return x;
+}
+
+// mul_2si
+inline const mpreal mul_2si(const mpreal& v, long int k, mp_rnd_t rnd_mode)
+{
+ mpreal x(v);
+ mpfr_mul_2si(x.mp,v.mp,k,rnd_mode);
+ return x;
+}
+
+inline const mpreal div_2ui(const mpreal& v, unsigned long int k, mp_rnd_t rnd_mode)
+{
+ mpreal x(v);
+ mpfr_div_2ui(x.mp,v.mp,k,rnd_mode);
+ return x;
+}
+
+inline const mpreal div_2si(const mpreal& v, long int k, mp_rnd_t rnd_mode)
+{
+ mpreal x(v);
+ mpfr_div_2si(x.mp,v.mp,k,rnd_mode);
+ return x;
+}
+
+//////////////////////////////////////////////////////////////////////////
+//Boolean operators
+inline bool operator > (const mpreal& a, const mpreal& b){ return (mpfr_greater_p(a.mp,b.mp) !=0); }
+inline bool operator >= (const mpreal& a, const mpreal& b){ return (mpfr_greaterequal_p(a.mp,b.mp) !=0); }
+inline bool operator < (const mpreal& a, const mpreal& b){ return (mpfr_less_p(a.mp,b.mp) !=0); }
+inline bool operator <= (const mpreal& a, const mpreal& b){ return (mpfr_lessequal_p(a.mp,b.mp) !=0); }
+inline bool operator == (const mpreal& a, const mpreal& b){ return (mpfr_equal_p(a.mp,b.mp) !=0); }
+inline bool operator != (const mpreal& a, const mpreal& b){ return (mpfr_lessgreater_p(a.mp,b.mp) !=0); }
+
+inline bool operator == (const mpreal& a, const unsigned long int b ){ return (mpfr_cmp_ui(a.mp,b) == 0); }
+inline bool operator == (const mpreal& a, const unsigned int b ){ return (mpfr_cmp_ui(a.mp,b) == 0); }
+inline bool operator == (const mpreal& a, const long int b ){ return (mpfr_cmp_si(a.mp,b) == 0); }
+inline bool operator == (const mpreal& a, const int b ){ return (mpfr_cmp_si(a.mp,b) == 0); }
+inline bool operator == (const mpreal& a, const long double b ){ return (mpfr_cmp_ld(a.mp,b) == 0); }
+inline bool operator == (const mpreal& a, const double b ){ return (mpfr_cmp_d(a.mp,b) == 0); }
+
+
+inline bool isnan (const mpreal& v){ return (mpfr_nan_p(v.mp) != 0); }
+inline bool isinf (const mpreal& v){ return (mpfr_inf_p(v.mp) != 0); }
+inline bool isfinite(const mpreal& v){ return (mpfr_number_p(v.mp) != 0); }
+inline bool iszero (const mpreal& v){ return (mpfr_zero_p(v.mp) != 0); }
+inline bool isint (const mpreal& v){ return (mpfr_integer_p(v.mp) != 0); }
+
+#if (MPFR_VERSION >= MPFR_VERSION_NUM(3,0,0))
+inline bool isregular(const mpreal& v){ return (mpfr_regular_p(v.mp));}
+#endif
+
+//////////////////////////////////////////////////////////////////////////
+// Type Converters
+inline long mpreal::toLong() const { return mpfr_get_si(mp,GMP_RNDZ); }
+inline unsigned long mpreal::toULong() const { return mpfr_get_ui(mp,GMP_RNDZ); }
+inline double mpreal::toDouble() const { return mpfr_get_d(mp,default_rnd); }
+inline long double mpreal::toLDouble() const { return mpfr_get_ld(mp,default_rnd); }
+
+#if defined (MPREAL_HAVE_INT64_SUPPORT)
+inline int64_t mpreal::toInt64() const{ return mpfr_get_sj(mp,GMP_RNDZ); }
+inline uint64_t mpreal::toUInt64() const{ return mpfr_get_uj(mp,GMP_RNDZ); }
+#endif
+
+inline ::mpfr_ptr mpreal::mpfr_ptr() { return mp; }
+inline ::mpfr_srcptr mpreal::mpfr_srcptr() const { return const_cast< ::mpfr_srcptr >(mp); }
+
+//////////////////////////////////////////////////////////////////////////
+// Bits - decimal digits relation
+// bits = ceil(digits*log[2](10))
+// digits = floor(bits*log[10](2))
+
+inline mp_prec_t digits2bits(int d)
+{
+ const double LOG2_10 = 3.3219280948873624;
+
+ d = 10>d?10:d;
+
+ return (mp_prec_t)std::ceil((d)*LOG2_10);
+}
+
+inline int bits2digits(mp_prec_t b)
+{
+ const double LOG10_2 = 0.30102999566398119;
+
+ b = 34>b?34:b;
+
+ return (int)std::floor((b)*LOG10_2);
+}
+
+//////////////////////////////////////////////////////////////////////////
+// Set/Get number properties
+inline int sgn(const mpreal& v)
+{
+ int r = mpfr_signbit(v.mp);
+ return (r>0?-1:1);
+}
+
+inline mpreal& mpreal::setSign(int sign, mp_rnd_t RoundingMode)
+{
+ mpfr_setsign(mp,mp,(sign<0?1:0),RoundingMode);
+ MPREAL_MSVC_DEBUGVIEW_CODE;
+ return *this;
+}
+
+inline int mpreal::getPrecision() const
+{
+ return mpfr_get_prec(mp);
+}
+
+inline mpreal& mpreal::setPrecision(int Precision, mp_rnd_t RoundingMode)
+{
+ mpfr_prec_round(mp,Precision, RoundingMode);
+ MPREAL_MSVC_DEBUGVIEW_CODE;
+ return *this;
+}
+
+inline mpreal& mpreal::setInf(int sign)
+{
+ mpfr_set_inf(mp,sign);
+ MPREAL_MSVC_DEBUGVIEW_CODE;
+ return *this;
+}
+
+inline mpreal& mpreal::setNan()
+{
+ mpfr_set_nan(mp);
+ MPREAL_MSVC_DEBUGVIEW_CODE;
+ return *this;
+}
+
+inline mpreal& mpreal::setZero(int sign)
+{
+ mpfr_set_zero(mp,sign);
+ MPREAL_MSVC_DEBUGVIEW_CODE;
+ return *this;
+}
+
+inline mp_prec_t mpreal::get_prec() const
+{
+ return mpfr_get_prec(mp);
+}
+
+inline void mpreal::set_prec(mp_prec_t prec, mp_rnd_t rnd_mode)
+{
+ mpfr_prec_round(mp,prec,rnd_mode);
+ MPREAL_MSVC_DEBUGVIEW_CODE;
+}
+
+inline mp_exp_t mpreal::get_exp ()
+{
+ return mpfr_get_exp(mp);
+}
+
+inline int mpreal::set_exp (mp_exp_t e)
+{
+ int x = mpfr_set_exp(mp, e);
+ MPREAL_MSVC_DEBUGVIEW_CODE;
+ return x;
+}
+
+inline const mpreal frexp(const mpreal& v, mp_exp_t* exp)
+{
+ mpreal x(v);
+ *exp = x.get_exp();
+ x.set_exp(0);
+ return x;
+}
+
+inline const mpreal ldexp(const mpreal& v, mp_exp_t exp)
+{
+ mpreal x(v);
+
+ // rounding is not important since we just increasing the exponent
+ mpfr_mul_2si(x.mp,x.mp,exp,mpreal::default_rnd);
+ return x;
+}
+
+inline const mpreal machine_epsilon(mp_prec_t prec)
+{
+ // the smallest eps such that 1.0+eps != 1.0
+ // depends (of cause) on the precision
+ return machine_epsilon(mpreal(1,prec));
+}
+
+inline const mpreal machine_epsilon(const mpreal& x)
+{
+ if( x < 0)
+ {
+ return nextabove(-x)+x;
+ }else{
+ return nextabove(x)-x;
+ }
+}
+
+inline const mpreal mpreal_min(mp_prec_t prec)
+{
+ // min = 1/2*2^emin = 2^(emin-1)
+
+ return mpreal(1,prec) << mpreal::get_emin()-1;
+}
+
+inline const mpreal mpreal_max(mp_prec_t prec)
+{
+ // max = (1-eps)*2^emax, assume eps = 0?,
+ // and use emax-1 to prevent value to be +inf
+ // max = 2^(emax-1)
+
+ return mpreal(1,prec) << mpreal::get_emax()-1;
+}
+
+inline bool isEqualUlps(const mpreal& a, const mpreal& b, int maxUlps)
+{
+ /*
+ maxUlps - a and b can be apart by maxUlps binary numbers.
+ */
+ return abs(a - b) <= machine_epsilon((max)(abs(a), abs(b))) * maxUlps;
+}
+
+inline bool isEqualFuzzy(const mpreal& a, const mpreal& b, const mpreal& eps)
+{
+ return abs(a - b) <= (min)(abs(a), abs(b)) * eps;
+}
+
+inline bool isEqualFuzzy(const mpreal& a, const mpreal& b)
+{
+ return isEqualFuzzy(a,b,machine_epsilon((std::min)(abs(a), abs(b))));
+}
+
+inline const mpreal modf(const mpreal& v, mpreal& n)
+{
+ mpreal frac(v);
+
+ // rounding is not important since we are using the same number
+ mpfr_frac(frac.mp,frac.mp,mpreal::default_rnd);
+ mpfr_trunc(n.mp,v.mp);
+ return frac;
+}
+
+inline int mpreal::check_range (int t, mp_rnd_t rnd_mode)
+{
+ return mpfr_check_range(mp,t,rnd_mode);
+}
+
+inline int mpreal::subnormalize (int t,mp_rnd_t rnd_mode)
+{
+ int r = mpfr_subnormalize(mp,t,rnd_mode);
+ MPREAL_MSVC_DEBUGVIEW_CODE;
+ return r;
+}
+
+inline mp_exp_t mpreal::get_emin (void)
+{
+ return mpfr_get_emin();
+}
+
+inline int mpreal::set_emin (mp_exp_t exp)
+{
+ return mpfr_set_emin(exp);
+}
+
+inline mp_exp_t mpreal::get_emax (void)
+{
+ return mpfr_get_emax();
+}
+
+inline int mpreal::set_emax (mp_exp_t exp)
+{
+ return mpfr_set_emax(exp);
+}
+
+inline mp_exp_t mpreal::get_emin_min (void)
+{
+ return mpfr_get_emin_min();
+}
+
+inline mp_exp_t mpreal::get_emin_max (void)
+{
+ return mpfr_get_emin_max();
+}
+
+inline mp_exp_t mpreal::get_emax_min (void)
+{
+ return mpfr_get_emax_min();
+}
+
+inline mp_exp_t mpreal::get_emax_max (void)
+{
+ return mpfr_get_emax_max();
+}
+
+//////////////////////////////////////////////////////////////////////////
+// Mathematical Functions
+//////////////////////////////////////////////////////////////////////////
+inline const mpreal sqr(const mpreal& v, mp_rnd_t rnd_mode)
+{
+ mpreal x(v);
+ mpfr_sqr(x.mp,x.mp,rnd_mode);
+ return x;
+}
+
+inline const mpreal sqrt(const mpreal& v, mp_rnd_t rnd_mode)
+{
+ mpreal x(v);
+ mpfr_sqrt(x.mp,x.mp,rnd_mode);
+ return x;
+}
+
+inline const mpreal sqrt(const unsigned long int v, mp_rnd_t rnd_mode)
+{
+ mpreal x;
+ mpfr_sqrt_ui(x.mp,v,rnd_mode);
+ return x;
+}
+
+inline const mpreal sqrt(const unsigned int v, mp_rnd_t rnd_mode)
+{
+ return sqrt(static_cast<unsigned long int>(v),rnd_mode);
+}
+
+inline const mpreal sqrt(const long int v, mp_rnd_t rnd_mode)
+{
+ if (v>=0) return sqrt(static_cast<unsigned long int>(v),rnd_mode);
+ else return mpreal().setNan(); // NaN
+}
+
+inline const mpreal sqrt(const int v, mp_rnd_t rnd_mode)
+{
+ if (v>=0) return sqrt(static_cast<unsigned long int>(v),rnd_mode);
+ else return mpreal().setNan(); // NaN
+}
+
+inline const mpreal sqrt(const long double v, mp_rnd_t rnd_mode)
+{
+ return sqrt(mpreal(v),rnd_mode);
+}
+
+inline const mpreal sqrt(const double v, mp_rnd_t rnd_mode)
+{
+ return sqrt(mpreal(v),rnd_mode);
+}
+
+inline const mpreal cbrt(const mpreal& v, mp_rnd_t rnd_mode)
+{
+ mpreal x(v);
+ mpfr_cbrt(x.mp,x.mp,rnd_mode);
+ return x;
+}
+
+inline const mpreal root(const mpreal& v, unsigned long int k, mp_rnd_t rnd_mode)
+{
+ mpreal x(v);
+ mpfr_root(x.mp,x.mp,k,rnd_mode);
+ return x;
+}
+
+inline const mpreal fabs(const mpreal& v, mp_rnd_t rnd_mode)
+{
+ mpreal x(v);
+ mpfr_abs(x.mp,x.mp,rnd_mode);
+ return x;
+}
+
+inline const mpreal abs(const mpreal& v, mp_rnd_t rnd_mode)
+{
+ mpreal x(v);
+ mpfr_abs(x.mp,x.mp,rnd_mode);
+ return x;
+}
+
+inline const mpreal dim(const mpreal& a, const mpreal& b, mp_rnd_t rnd_mode)
+{
+ mpreal x(a);
+ mpfr_dim(x.mp,a.mp,b.mp,rnd_mode);
+ return x;
+}
+
+inline int cmpabs(const mpreal& a,const mpreal& b)
+{
+ return mpfr_cmpabs(a.mp,b.mp);
+}
+
+inline const mpreal log (const mpreal& v, mp_rnd_t rnd_mode)
+{
+ mpreal x(v);
+ mpfr_log(x.mp,v.mp,rnd_mode);
+ return x;
+}
+
+inline const mpreal log2(const mpreal& v, mp_rnd_t rnd_mode)
+{
+ mpreal x(v);
+ mpfr_log2(x.mp,v.mp,rnd_mode);
+ return x;
+}
+
+inline const mpreal log10(const mpreal& v, mp_rnd_t rnd_mode)
+{
+ mpreal x(v);
+ mpfr_log10(x.mp,v.mp,rnd_mode);
+ return x;
+}
+
+inline const mpreal exp(const mpreal& v, mp_rnd_t rnd_mode)
+{
+ mpreal x(v);
+ mpfr_exp(x.mp,v.mp,rnd_mode);
+ return x;
+}
+
+inline const mpreal exp2(const mpreal& v, mp_rnd_t rnd_mode)
+{
+ mpreal x(v);
+ mpfr_exp2(x.mp,v.mp,rnd_mode);
+ return x;
+}
+
+inline const mpreal exp10(const mpreal& v, mp_rnd_t rnd_mode)
+{
+ mpreal x(v);
+ mpfr_exp10(x.mp,v.mp,rnd_mode);
+ return x;
+}
+
+inline const mpreal cos(const mpreal& v, mp_rnd_t rnd_mode)
+{
+ mpreal x(v);
+ mpfr_cos(x.mp,v.mp,rnd_mode);
+ return x;
+}
+
+inline const mpreal sin(const mpreal& v, mp_rnd_t rnd_mode)
+{
+ mpreal x(v);
+ mpfr_sin(x.mp,v.mp,rnd_mode);
+ return x;
+}
+
+inline const mpreal tan(const mpreal& v, mp_rnd_t rnd_mode)
+{
+ mpreal x(v);
+ mpfr_tan(x.mp,v.mp,rnd_mode);
+ return x;
+}
+
+inline const mpreal sec(const mpreal& v, mp_rnd_t rnd_mode)
+{
+ mpreal x(v);
+ mpfr_sec(x.mp,v.mp,rnd_mode);
+ return x;
+}
+
+inline const mpreal csc(const mpreal& v, mp_rnd_t rnd_mode)
+{
+ mpreal x(v);
+ mpfr_csc(x.mp,v.mp,rnd_mode);
+ return x;
+}
+
+inline const mpreal cot(const mpreal& v, mp_rnd_t rnd_mode)
+{
+ mpreal x(v);
+ mpfr_cot(x.mp,v.mp,rnd_mode);
+ return x;
+}
+
+inline int sin_cos(mpreal& s, mpreal& c, const mpreal& v, mp_rnd_t rnd_mode)
+{
+ return mpfr_sin_cos(s.mp,c.mp,v.mp,rnd_mode);
+}
+
+inline const mpreal acos (const mpreal& v, mp_rnd_t rnd_mode)
+{
+ mpreal x(v);
+ mpfr_acos(x.mp,v.mp,rnd_mode);
+ return x;
+}
+
+inline const mpreal asin (const mpreal& v, mp_rnd_t rnd_mode)
+{
+ mpreal x(v);
+ mpfr_asin(x.mp,v.mp,rnd_mode);
+ return x;
+}
+
+inline const mpreal atan (const mpreal& v, mp_rnd_t rnd_mode)
+{
+ mpreal x(v);
+ mpfr_atan(x.mp,v.mp,rnd_mode);
+ return x;
+}
+
+inline const mpreal acot (const mpreal& v, mp_rnd_t rnd_mode)
+{
+ return atan(1/v, rnd_mode);
+}
+
+inline const mpreal asec (const mpreal& v, mp_rnd_t rnd_mode)
+{
+ return acos(1/v, rnd_mode);
+}
+
+inline const mpreal acsc (const mpreal& v, mp_rnd_t rnd_mode)
+{
+ return asin(1/v, rnd_mode);
+}
+
+inline const mpreal acoth (const mpreal& v, mp_rnd_t rnd_mode)
+{
+ return atanh(1/v, rnd_mode);
+}
+
+inline const mpreal asech (const mpreal& v, mp_rnd_t rnd_mode)
+{
+ return acosh(1/v, rnd_mode);
+}
+
+inline const mpreal acsch (const mpreal& v, mp_rnd_t rnd_mode)
+{
+ return asinh(1/v, rnd_mode);
+}
+
+inline const mpreal atan2 (const mpreal& y, const mpreal& x, mp_rnd_t rnd_mode)
+{
+ mpreal a;
+ mp_prec_t yp, xp;
+
+ yp = y.get_prec();
+ xp = x.get_prec();
+
+ a.set_prec(yp>xp?yp:xp);
+
+ mpfr_atan2(a.mp, y.mp, x.mp, rnd_mode);
+
+ return a;
+}
+
+inline const mpreal cosh (const mpreal& v, mp_rnd_t rnd_mode)
+{
+ mpreal x(v);
+ mpfr_cosh(x.mp,v.mp,rnd_mode);
+ return x;
+}
+
+inline const mpreal sinh (const mpreal& v, mp_rnd_t rnd_mode)
+{
+ mpreal x(v);
+ mpfr_sinh(x.mp,v.mp,rnd_mode);
+ return x;
+}
+
+inline const mpreal tanh (const mpreal& v, mp_rnd_t rnd_mode)
+{
+ mpreal x(v);
+ mpfr_tanh(x.mp,v.mp,rnd_mode);
+ return x;
+}
+
+inline const mpreal sech (const mpreal& v, mp_rnd_t rnd_mode)
+{
+ mpreal x(v);
+ mpfr_sech(x.mp,v.mp,rnd_mode);
+ return x;
+}
+
+inline const mpreal csch (const mpreal& v, mp_rnd_t rnd_mode)
+{
+ mpreal x(v);
+ mpfr_csch(x.mp,v.mp,rnd_mode);
+ return x;
+}
+
+inline const mpreal coth (const mpreal& v, mp_rnd_t rnd_mode)
+{
+ mpreal x(v);
+ mpfr_coth(x.mp,v.mp,rnd_mode);
+ return x;
+}
+
+inline const mpreal acosh (const mpreal& v, mp_rnd_t rnd_mode)
+{
+ mpreal x(v);
+ mpfr_acosh(x.mp,v.mp,rnd_mode);
+ return x;
+}
+
+inline const mpreal asinh (const mpreal& v, mp_rnd_t rnd_mode)
+{
+ mpreal x(v);
+ mpfr_asinh(x.mp,v.mp,rnd_mode);
+ return x;
+}
+
+inline const mpreal atanh (const mpreal& v, mp_rnd_t rnd_mode)
+{
+ mpreal x(v);
+ mpfr_atanh(x.mp,v.mp,rnd_mode);
+ return x;
+}
+
+inline const mpreal hypot (const mpreal& x, const mpreal& y, mp_rnd_t rnd_mode)
+{
+ mpreal a;
+ mp_prec_t yp, xp;
+
+ yp = y.get_prec();
+ xp = x.get_prec();
+
+ a.set_prec(yp>xp?yp:xp);
+
+ mpfr_hypot(a.mp, x.mp, y.mp, rnd_mode);
+
+ return a;
+}
+
+inline const mpreal remainder (const mpreal& x, const mpreal& y, mp_rnd_t rnd_mode)
+{
+ mpreal a;
+ mp_prec_t yp, xp;
+
+ yp = y.get_prec();
+ xp = x.get_prec();
+
+ a.set_prec(yp>xp?yp:xp);
+
+ mpfr_remainder(a.mp, x.mp, y.mp, rnd_mode);
+
+ return a;
+}
+
+inline const mpreal fac_ui (unsigned long int v, mp_prec_t prec, mp_rnd_t rnd_mode)
+{
+ mpreal x(0,prec);
+ mpfr_fac_ui(x.mp,v,rnd_mode);
+ return x;
+}
+
+inline const mpreal log1p (const mpreal& v, mp_rnd_t rnd_mode)
+{
+ mpreal x(v);
+ mpfr_log1p(x.mp,v.mp,rnd_mode);
+ return x;
+}
+
+inline const mpreal expm1 (const mpreal& v, mp_rnd_t rnd_mode)
+{
+ mpreal x(v);
+ mpfr_expm1(x.mp,v.mp,rnd_mode);
+ return x;
+}
+
+inline const mpreal eint (const mpreal& v, mp_rnd_t rnd_mode)
+{
+ mpreal x(v);
+ mpfr_eint(x.mp,v.mp,rnd_mode);
+ return x;
+}
+
+inline const mpreal gamma (const mpreal& x, mp_rnd_t rnd_mode)
+{
+ mpreal FunctionValue(x);
+
+ // x < 0: gamma(-x) = -pi/(x * gamma(x) * sin(pi*x))
+
+ mpfr_gamma(FunctionValue.mp, x.mp, rnd_mode);
+
+ return FunctionValue;
+}
+
+inline const mpreal lngamma (const mpreal& v, mp_rnd_t rnd_mode)
+{
+ mpreal x(v);
+ mpfr_lngamma(x.mp,v.mp,rnd_mode);
+ return x;
+}
+
+inline const mpreal lgamma (const mpreal& v, int *signp, mp_rnd_t rnd_mode)
+{
+ mpreal x(v);
+ int tsignp;
+
+ if(signp)
+ mpfr_lgamma(x.mp,signp,v.mp,rnd_mode);
+ else
+ mpfr_lgamma(x.mp,&tsignp,v.mp,rnd_mode);
+
+ return x;
+}
+
+inline const mpreal zeta (const mpreal& v, mp_rnd_t rnd_mode)
+{
+ mpreal x(v);
+ mpfr_zeta(x.mp,v.mp,rnd_mode);
+ return x;
+}
+
+inline const mpreal erf (const mpreal& v, mp_rnd_t rnd_mode)
+{
+ mpreal x(v);
+ mpfr_erf(x.mp,v.mp,rnd_mode);
+ return x;
+}
+
+inline const mpreal erfc (const mpreal& v, mp_rnd_t rnd_mode)
+{
+ mpreal x(v);
+ mpfr_erfc(x.mp,v.mp,rnd_mode);
+ return x;
+}
+
+inline const mpreal besselj0 (const mpreal& v, mp_rnd_t rnd_mode)
+{
+ mpreal x(v);
+ mpfr_j0(x.mp,v.mp,rnd_mode);
+ return x;
+}
+
+inline const mpreal besselj1 (const mpreal& v, mp_rnd_t rnd_mode)
+{
+ mpreal x(v);
+ mpfr_j1(x.mp,v.mp,rnd_mode);
+ return x;
+}
+
+inline const mpreal besseljn (long n, const mpreal& v, mp_rnd_t rnd_mode)
+{
+ mpreal x(v);
+ mpfr_jn(x.mp,n,v.mp,rnd_mode);
+ return x;
+}
+
+inline const mpreal bessely0 (const mpreal& v, mp_rnd_t rnd_mode)
+{
+ mpreal x(v);
+ mpfr_y0(x.mp,v.mp,rnd_mode);
+ return x;
+}
+
+inline const mpreal bessely1 (const mpreal& v, mp_rnd_t rnd_mode)
+{
+ mpreal x(v);
+ mpfr_y1(x.mp,v.mp,rnd_mode);
+ return x;
+}
+
+inline const mpreal besselyn (long n, const mpreal& v, mp_rnd_t rnd_mode)
+{
+ mpreal x(v);
+ mpfr_yn(x.mp,n,v.mp,rnd_mode);
+ return x;
+}
+
+//////////////////////////////////////////////////////////////////////////
+// MPFR 2.4.0 Specifics
+#if (MPFR_VERSION >= MPFR_VERSION_NUM(2,4,0))
+
+inline int sinh_cosh(mpreal& s, mpreal& c, const mpreal& v, mp_rnd_t rnd_mode)
+{
+ return mpfr_sinh_cosh(s.mp,c.mp,v.mp,rnd_mode);
+}
+
+inline const mpreal li2(const mpreal& v, mp_rnd_t rnd_mode)
+{
+ mpreal x(v);
+ mpfr_li2(x.mp,v.mp,rnd_mode);
+ return x;
+}
+
+inline const mpreal fmod (const mpreal& x, const mpreal& y, mp_rnd_t rnd_mode)
+{
+ mpreal a;
+ mp_prec_t yp, xp;
+
+ yp = y.get_prec();
+ xp = x.get_prec();
+
+ a.set_prec(yp>xp?yp:xp);
+
+ mpfr_fmod(a.mp, x.mp, y.mp, rnd_mode);
+
+ return a;
+}
+
+inline const mpreal rec_sqrt(const mpreal& v, mp_rnd_t rnd_mode)
+{
+ mpreal x(v);
+ mpfr_rec_sqrt(x.mp,v.mp,rnd_mode);
+ return x;
+}
+#endif // MPFR 2.4.0 Specifics
+
+//////////////////////////////////////////////////////////////////////////
+// MPFR 3.0.0 Specifics
+#if (MPFR_VERSION >= MPFR_VERSION_NUM(3,0,0))
+
+inline const mpreal digamma(const mpreal& v, mp_rnd_t rnd_mode)
+{
+ mpreal x(v);
+ mpfr_digamma(x.mp,v.mp,rnd_mode);
+ return x;
+}
+
+inline const mpreal ai(const mpreal& v, mp_rnd_t rnd_mode)
+{
+ mpreal x(v);
+ mpfr_ai(x.mp,v.mp,rnd_mode);
+ return x;
+}
+
+#endif // MPFR 3.0.0 Specifics
+
+//////////////////////////////////////////////////////////////////////////
+// Constants
+inline const mpreal const_log2 (mp_prec_t prec, mp_rnd_t rnd_mode)
+{
+ mpreal x;
+ x.set_prec(prec);
+ mpfr_const_log2(x.mp,rnd_mode);
+ return x;
+}
+
+inline const mpreal const_pi (mp_prec_t prec, mp_rnd_t rnd_mode)
+{
+ mpreal x;
+ x.set_prec(prec);
+ mpfr_const_pi(x.mp,rnd_mode);
+ return x;
+}
+
+inline const mpreal const_euler (mp_prec_t prec, mp_rnd_t rnd_mode)
+{
+ mpreal x;
+ x.set_prec(prec);
+ mpfr_const_euler(x.mp,rnd_mode);
+ return x;
+}
+
+inline const mpreal const_catalan (mp_prec_t prec, mp_rnd_t rnd_mode)
+{
+ mpreal x;
+ x.set_prec(prec);
+ mpfr_const_catalan(x.mp,rnd_mode);
+ return x;
+}
+
+inline const mpreal const_infinity (int sign, mp_prec_t prec, mp_rnd_t rnd_mode)
+{
+ mpreal x;
+ x.set_prec(prec,rnd_mode);
+ mpfr_set_inf(x.mp, sign);
+ return x;
+}
+
+//////////////////////////////////////////////////////////////////////////
+// Integer Related Functions
+inline const mpreal rint(const mpreal& v, mp_rnd_t rnd_mode)
+{
+ mpreal x(v);
+ mpfr_rint(x.mp,v.mp,rnd_mode);
+ return x;
+}
+
+inline const mpreal ceil(const mpreal& v)
+{
+ mpreal x(v);
+ mpfr_ceil(x.mp,v.mp);
+ return x;
+
+}
+
+inline const mpreal floor(const mpreal& v)
+{
+ mpreal x(v);
+ mpfr_floor(x.mp,v.mp);
+ return x;
+}
+
+inline const mpreal round(const mpreal& v)
+{
+ mpreal x(v);
+ mpfr_round(x.mp,v.mp);
+ return x;
+}
+
+inline const mpreal trunc(const mpreal& v)
+{
+ mpreal x(v);
+ mpfr_trunc(x.mp,v.mp);
+ return x;
+}
+
+inline const mpreal rint_ceil (const mpreal& v, mp_rnd_t rnd_mode)
+{
+ mpreal x(v);
+ mpfr_rint_ceil(x.mp,v.mp,rnd_mode);
+ return x;
+}
+
+inline const mpreal rint_floor(const mpreal& v, mp_rnd_t rnd_mode)
+{
+ mpreal x(v);
+ mpfr_rint_floor(x.mp,v.mp,rnd_mode);
+ return x;
+}
+
+inline const mpreal rint_round(const mpreal& v, mp_rnd_t rnd_mode)
+{
+ mpreal x(v);
+ mpfr_rint_round(x.mp,v.mp,rnd_mode);
+ return x;
+}
+
+inline const mpreal rint_trunc(const mpreal& v, mp_rnd_t rnd_mode)
+{
+ mpreal x(v);
+ mpfr_rint_trunc(x.mp,v.mp,rnd_mode);
+ return x;
+}
+
+inline const mpreal frac (const mpreal& v, mp_rnd_t rnd_mode)
+{
+ mpreal x(v);
+ mpfr_frac(x.mp,v.mp,rnd_mode);
+ return x;
+}
+
+//////////////////////////////////////////////////////////////////////////
+// Miscellaneous Functions
+inline void swap(mpreal& a, mpreal& b)
+{
+ mpfr_swap(a.mp,b.mp);
+}
+
+inline const mpreal (max)(const mpreal& x, const mpreal& y)
+{
+ return (x>y?x:y);
+}
+
+inline const mpreal (min)(const mpreal& x, const mpreal& y)
+{
+ return (x<y?x:y);
+}
+
+inline const mpreal fmax(const mpreal& x, const mpreal& y, mp_rnd_t rnd_mode)
+{
+ mpreal a;
+ mpfr_max(a.mp,x.mp,y.mp,rnd_mode);
+ return a;
+}
+
+inline const mpreal fmin(const mpreal& x, const mpreal& y, mp_rnd_t rnd_mode)
+{
+ mpreal a;
+ mpfr_min(a.mp,x.mp,y.mp,rnd_mode);
+ return a;
+}
+
+inline const mpreal nexttoward (const mpreal& x, const mpreal& y)
+{
+ mpreal a(x);
+ mpfr_nexttoward(a.mp,y.mp);
+ return a;
+}
+
+inline const mpreal nextabove (const mpreal& x)
+{
+ mpreal a(x);
+ mpfr_nextabove(a.mp);
+ return a;
+}
+
+inline const mpreal nextbelow (const mpreal& x)
+{
+ mpreal a(x);
+ mpfr_nextbelow(a.mp);
+ return a;
+}
+
+inline const mpreal urandomb (gmp_randstate_t& state)
+{
+ mpreal x;
+ mpfr_urandomb(x.mp,state);
+ return x;
+}
+
+#if (MPFR_VERSION >= MPFR_VERSION_NUM(3,0,0))
+// use gmp_randinit_default() to init state, gmp_randclear() to clear
+inline const mpreal urandom (gmp_randstate_t& state, mp_rnd_t rnd_mode)
+{
+ mpreal x;
+ mpfr_urandom(x.mp,state,rnd_mode);
+ return x;
+}
+#endif
+
+#if (MPFR_VERSION <= MPFR_VERSION_NUM(2,4,2))
+inline const mpreal random2 (mp_size_t size, mp_exp_t exp)
+{
+ mpreal x;
+ mpfr_random2(x.mp,size,exp);
+ return x;
+}
+#endif
+
+// Uniformly distributed random number generation
+// a = random(seed); <- initialization & first random number generation
+// a = random(); <- next random numbers generation
+// seed != 0
+inline const mpreal random(unsigned int seed)
+{
+
+#if (MPFR_VERSION >= MPFR_VERSION_NUM(3,0,0))
+ static gmp_randstate_t state;
+ static bool isFirstTime = true;
+
+ if(isFirstTime)
+ {
+ gmp_randinit_default(state);
+ gmp_randseed_ui(state,0);
+ isFirstTime = false;
+ }
+
+ if(seed != 0) gmp_randseed_ui(state,seed);
+
+ return mpfr::urandom(state);
+#else
+ if(seed != 0) std::srand(seed);
+ return mpfr::mpreal(std::rand()/(double)RAND_MAX);
+#endif
+
+}
+
+//////////////////////////////////////////////////////////////////////////
+// Set/Get global properties
+inline void mpreal::set_default_prec(mp_prec_t prec)
+{
+ default_prec = prec;
+ mpfr_set_default_prec(prec);
+}
+
+inline mp_prec_t mpreal::get_default_prec()
+{
+ return (mpfr_get_default_prec)();
+}
+
+inline void mpreal::set_default_base(int base)
+{
+ default_base = base;
+}
+
+inline int mpreal::get_default_base()
+{
+ return default_base;
+}
+
+inline void mpreal::set_default_rnd(mp_rnd_t rnd_mode)
+{
+ default_rnd = rnd_mode;
+ mpfr_set_default_rounding_mode(rnd_mode);
+}
+
+inline mp_rnd_t mpreal::get_default_rnd()
+{
+ return static_cast<mp_rnd_t>((mpfr_get_default_rounding_mode)());
+}
+
+inline void mpreal::set_double_bits(int dbits)
+{
+ double_bits = dbits;
+}
+
+inline int mpreal::get_double_bits()
+{
+ return double_bits;
+}
+
+inline bool mpreal::fits_in_bits(double x, int n)
+{
+ int i;
+ double t;
+ return IsInf(x) || (std::modf ( std::ldexp ( std::frexp ( x, &i ), n ), &t ) == 0.0);
+}
+
+inline const mpreal pow(const mpreal& a, const mpreal& b, mp_rnd_t rnd_mode)
+{
+ mpreal x(a);
+ mpfr_pow(x.mp,x.mp,b.mp,rnd_mode);
+ return x;
+}
+
+inline const mpreal pow(const mpreal& a, const mpz_t b, mp_rnd_t rnd_mode)
+{
+ mpreal x(a);
+ mpfr_pow_z(x.mp,x.mp,b,rnd_mode);
+ return x;
+}
+
+inline const mpreal pow(const mpreal& a, const unsigned long int b, mp_rnd_t rnd_mode)
+{
+ mpreal x(a);
+ mpfr_pow_ui(x.mp,x.mp,b,rnd_mode);
+ return x;
+}
+
+inline const mpreal pow(const mpreal& a, const unsigned int b, mp_rnd_t rnd_mode)
+{
+ return pow(a,static_cast<unsigned long int>(b),rnd_mode);
+}
+
+inline const mpreal pow(const mpreal& a, const long int b, mp_rnd_t rnd_mode)
+{
+ mpreal x(a);
+ mpfr_pow_si(x.mp,x.mp,b,rnd_mode);
+ return x;
+}
+
+inline const mpreal pow(const mpreal& a, const int b, mp_rnd_t rnd_mode)
+{
+ return pow(a,static_cast<long int>(b),rnd_mode);
+}
+
+inline const mpreal pow(const mpreal& a, const long double b, mp_rnd_t rnd_mode)
+{
+ return pow(a,mpreal(b),rnd_mode);
+}
+
+inline const mpreal pow(const mpreal& a, const double b, mp_rnd_t rnd_mode)
+{
+ return pow(a,mpreal(b),rnd_mode);
+}
+
+inline const mpreal pow(const unsigned long int a, const mpreal& b, mp_rnd_t rnd_mode)
+{
+ mpreal x(a);
+ mpfr_ui_pow(x.mp,a,b.mp,rnd_mode);
+ return x;
+}
+
+inline const mpreal pow(const unsigned int a, const mpreal& b, mp_rnd_t rnd_mode)
+{
+ return pow(static_cast<unsigned long int>(a),b,rnd_mode);
+}
+
+inline const mpreal pow(const long int a, const mpreal& b, mp_rnd_t rnd_mode)
+{
+ if (a>=0) return pow(static_cast<unsigned long int>(a),b,rnd_mode);
+ else return pow(mpreal(a),b,rnd_mode);
+}
+
+inline const mpreal pow(const int a, const mpreal& b, mp_rnd_t rnd_mode)
+{
+ if (a>=0) return pow(static_cast<unsigned long int>(a),b,rnd_mode);
+ else return pow(mpreal(a),b,rnd_mode);
+}
+
+inline const mpreal pow(const long double a, const mpreal& b, mp_rnd_t rnd_mode)
+{
+ return pow(mpreal(a),b,rnd_mode);
+}
+
+inline const mpreal pow(const double a, const mpreal& b, mp_rnd_t rnd_mode)
+{
+ return pow(mpreal(a),b,rnd_mode);
+}
+
+// pow unsigned long int
+inline const mpreal pow(const unsigned long int a, const unsigned long int b, mp_rnd_t rnd_mode)
+{
+ mpreal x(a);
+ mpfr_ui_pow_ui(x.mp,a,b,rnd_mode);
+ return x;
+}
+
+inline const mpreal pow(const unsigned long int a, const unsigned int b, mp_rnd_t rnd_mode)
+{
+ return pow(a,static_cast<unsigned long int>(b),rnd_mode); //mpfr_ui_pow_ui
+}
+
+inline const mpreal pow(const unsigned long int a, const long int b, mp_rnd_t rnd_mode)
+{
+ if(b>0) return pow(a,static_cast<unsigned long int>(b),rnd_mode); //mpfr_ui_pow_ui
+ else return pow(a,mpreal(b),rnd_mode); //mpfr_ui_pow
+}
+
+inline const mpreal pow(const unsigned long int a, const int b, mp_rnd_t rnd_mode)
+{
+ if(b>0) return pow(a,static_cast<unsigned long int>(b),rnd_mode); //mpfr_ui_pow_ui
+ else return pow(a,mpreal(b),rnd_mode); //mpfr_ui_pow
+}
+
+inline const mpreal pow(const unsigned long int a, const long double b, mp_rnd_t rnd_mode)
+{
+ return pow(a,mpreal(b),rnd_mode); //mpfr_ui_pow
+}
+
+inline const mpreal pow(const unsigned long int a, const double b, mp_rnd_t rnd_mode)
+{
+ return pow(a,mpreal(b),rnd_mode); //mpfr_ui_pow
+}
+
+// pow unsigned int
+inline const mpreal pow(const unsigned int a, const unsigned long int b, mp_rnd_t rnd_mode)
+{
+ return pow(static_cast<unsigned long int>(a),b,rnd_mode); //mpfr_ui_pow_ui
+}
+
+inline const mpreal pow(const unsigned int a, const unsigned int b, mp_rnd_t rnd_mode)
+{
+ return pow(static_cast<unsigned long int>(a),static_cast<unsigned long int>(b),rnd_mode); //mpfr_ui_pow_ui
+}
+
+inline const mpreal pow(const unsigned int a, const long int b, mp_rnd_t rnd_mode)
+{
+ if(b>0) return pow(static_cast<unsigned long int>(a),static_cast<unsigned long int>(b),rnd_mode); //mpfr_ui_pow_ui
+ else return pow(static_cast<unsigned long int>(a),mpreal(b),rnd_mode); //mpfr_ui_pow
+}
+
+inline const mpreal pow(const unsigned int a, const int b, mp_rnd_t rnd_mode)
+{
+ if(b>0) return pow(static_cast<unsigned long int>(a),static_cast<unsigned long int>(b),rnd_mode); //mpfr_ui_pow_ui
+ else return pow(static_cast<unsigned long int>(a),mpreal(b),rnd_mode); //mpfr_ui_pow
+}
+
+inline const mpreal pow(const unsigned int a, const long double b, mp_rnd_t rnd_mode)
+{
+ return pow(static_cast<unsigned long int>(a),mpreal(b),rnd_mode); //mpfr_ui_pow
+}
+
+inline const mpreal pow(const unsigned int a, const double b, mp_rnd_t rnd_mode)
+{
+ return pow(static_cast<unsigned long int>(a),mpreal(b),rnd_mode); //mpfr_ui_pow
+}
+
+// pow long int
+inline const mpreal pow(const long int a, const unsigned long int b, mp_rnd_t rnd_mode)
+{
+ if (a>0) return pow(static_cast<unsigned long int>(a),b,rnd_mode); //mpfr_ui_pow_ui
+ else return pow(mpreal(a),b,rnd_mode); //mpfr_pow_ui
+}
+
+inline const mpreal pow(const long int a, const unsigned int b, mp_rnd_t rnd_mode)
+{
+ if (a>0) return pow(static_cast<unsigned long int>(a),static_cast<unsigned long int>(b),rnd_mode); //mpfr_ui_pow_ui
+ else return pow(mpreal(a),static_cast<unsigned long int>(b),rnd_mode); //mpfr_pow_ui
+}
+
+inline const mpreal pow(const long int a, const long int b, mp_rnd_t rnd_mode)
+{
+ if (a>0)
+ {
+ if(b>0) return pow(static_cast<unsigned long int>(a),static_cast<unsigned long int>(b),rnd_mode); //mpfr_ui_pow_ui
+ else return pow(static_cast<unsigned long int>(a),mpreal(b),rnd_mode); //mpfr_ui_pow
+ }else{
+ return pow(mpreal(a),b,rnd_mode); // mpfr_pow_si
+ }
+}
+
+inline const mpreal pow(const long int a, const int b, mp_rnd_t rnd_mode)
+{
+ if (a>0)
+ {
+ if(b>0) return pow(static_cast<unsigned long int>(a),static_cast<unsigned long int>(b),rnd_mode); //mpfr_ui_pow_ui
+ else return pow(static_cast<unsigned long int>(a),mpreal(b),rnd_mode); //mpfr_ui_pow
+ }else{
+ return pow(mpreal(a),static_cast<long int>(b),rnd_mode); // mpfr_pow_si
+ }
+}
+
+inline const mpreal pow(const long int a, const long double b, mp_rnd_t rnd_mode)
+{
+ if (a>=0) return pow(static_cast<unsigned long int>(a),mpreal(b),rnd_mode); //mpfr_ui_pow
+ else return pow(mpreal(a),mpreal(b),rnd_mode); //mpfr_pow
+}
+
+inline const mpreal pow(const long int a, const double b, mp_rnd_t rnd_mode)
+{
+ if (a>=0) return pow(static_cast<unsigned long int>(a),mpreal(b),rnd_mode); //mpfr_ui_pow
+ else return pow(mpreal(a),mpreal(b),rnd_mode); //mpfr_pow
+}
+
+// pow int
+inline const mpreal pow(const int a, const unsigned long int b, mp_rnd_t rnd_mode)
+{
+ if (a>0) return pow(static_cast<unsigned long int>(a),b,rnd_mode); //mpfr_ui_pow_ui
+ else return pow(mpreal(a),b,rnd_mode); //mpfr_pow_ui
+}
+
+inline const mpreal pow(const int a, const unsigned int b, mp_rnd_t rnd_mode)
+{
+ if (a>0) return pow(static_cast<unsigned long int>(a),static_cast<unsigned long int>(b),rnd_mode); //mpfr_ui_pow_ui
+ else return pow(mpreal(a),static_cast<unsigned long int>(b),rnd_mode); //mpfr_pow_ui
+}
+
+inline const mpreal pow(const int a, const long int b, mp_rnd_t rnd_mode)
+{
+ if (a>0)
+ {
+ if(b>0) return pow(static_cast<unsigned long int>(a),static_cast<unsigned long int>(b),rnd_mode); //mpfr_ui_pow_ui
+ else return pow(static_cast<unsigned long int>(a),mpreal(b),rnd_mode); //mpfr_ui_pow
+ }else{
+ return pow(mpreal(a),b,rnd_mode); // mpfr_pow_si
+ }
+}
+
+inline const mpreal pow(const int a, const int b, mp_rnd_t rnd_mode)
+{
+ if (a>0)
+ {
+ if(b>0) return pow(static_cast<unsigned long int>(a),static_cast<unsigned long int>(b),rnd_mode); //mpfr_ui_pow_ui
+ else return pow(static_cast<unsigned long int>(a),mpreal(b),rnd_mode); //mpfr_ui_pow
+ }else{
+ return pow(mpreal(a),static_cast<long int>(b),rnd_mode); // mpfr_pow_si
+ }
+}
+
+inline const mpreal pow(const int a, const long double b, mp_rnd_t rnd_mode)
+{
+ if (a>=0) return pow(static_cast<unsigned long int>(a),mpreal(b),rnd_mode); //mpfr_ui_pow
+ else return pow(mpreal(a),mpreal(b),rnd_mode); //mpfr_pow
+}
+
+inline const mpreal pow(const int a, const double b, mp_rnd_t rnd_mode)
+{
+ if (a>=0) return pow(static_cast<unsigned long int>(a),mpreal(b),rnd_mode); //mpfr_ui_pow
+ else return pow(mpreal(a),mpreal(b),rnd_mode); //mpfr_pow
+}
+
+// pow long double
+inline const mpreal pow(const long double a, const long double b, mp_rnd_t rnd_mode)
+{
+ return pow(mpreal(a),mpreal(b),rnd_mode);
+}
+
+inline const mpreal pow(const long double a, const unsigned long int b, mp_rnd_t rnd_mode)
+{
+ return pow(mpreal(a),b,rnd_mode); //mpfr_pow_ui
+}
+
+inline const mpreal pow(const long double a, const unsigned int b, mp_rnd_t rnd_mode)
+{
+ return pow(mpreal(a),static_cast<unsigned long int>(b),rnd_mode); //mpfr_pow_ui
+}
+
+inline const mpreal pow(const long double a, const long int b, mp_rnd_t rnd_mode)
+{
+ return pow(mpreal(a),b,rnd_mode); // mpfr_pow_si
+}
+
+inline const mpreal pow(const long double a, const int b, mp_rnd_t rnd_mode)
+{
+ return pow(mpreal(a),static_cast<long int>(b),rnd_mode); // mpfr_pow_si
+}
+
+inline const mpreal pow(const double a, const double b, mp_rnd_t rnd_mode)
+{
+ return pow(mpreal(a),mpreal(b),rnd_mode);
+}
+
+inline const mpreal pow(const double a, const unsigned long int b, mp_rnd_t rnd_mode)
+{
+ return pow(mpreal(a),b,rnd_mode); // mpfr_pow_ui
+}
+
+inline const mpreal pow(const double a, const unsigned int b, mp_rnd_t rnd_mode)
+{
+ return pow(mpreal(a),static_cast<unsigned long int>(b),rnd_mode); // mpfr_pow_ui
+}
+
+inline const mpreal pow(const double a, const long int b, mp_rnd_t rnd_mode)
+{
+ return pow(mpreal(a),b,rnd_mode); // mpfr_pow_si
+}
+
+inline const mpreal pow(const double a, const int b, mp_rnd_t rnd_mode)
+{
+ return pow(mpreal(a),static_cast<long int>(b),rnd_mode); // mpfr_pow_si
+}
+} // End of mpfr namespace
+
+// Explicit specialization of std::swap for mpreal numbers
+// Thus standard algorithms will use efficient version of swap (due to Koenig lookup)
+// Non-throwing swap C++ idiom: http://en.wikibooks.org/wiki/More_C%2B%2B_Idioms/Non-throwing_swap
+namespace std
+{
+ template <>
+ inline void swap(mpfr::mpreal& x, mpfr::mpreal& y)
+ {
+ return mpfr::swap(x, y);
+ }
+}
+
+#endif /* __MPREAL_H__ */
diff --git a/unsupported/test/mpreal_support.cpp b/unsupported/test/mpreal_support.cpp
new file mode 100644
index 000000000..551af9db8
--- /dev/null
+++ b/unsupported/test/mpreal_support.cpp
@@ -0,0 +1,64 @@
+#include "main.h"
+#include <Eigen/MPRealSupport>
+#include <Eigen/LU>
+#include <Eigen/Eigenvalues>
+#include <sstream>
+
+using namespace mpfr;
+using namespace std;
+using namespace Eigen;
+
+void test_mpreal_support()
+{
+ // set precision to 256 bits (double has only 53 bits)
+ mpreal::set_default_prec(256);
+ typedef Matrix<mpreal,Eigen::Dynamic,Eigen::Dynamic> MatrixXmp;
+
+ std::cerr << "epsilon = " << NumTraits<mpreal>::epsilon() << "\n";
+ std::cerr << "dummy_precision = " << NumTraits<mpreal>::dummy_precision() << "\n";
+ std::cerr << "highest = " << NumTraits<mpreal>::highest() << "\n";
+ std::cerr << "lowest = " << NumTraits<mpreal>::lowest() << "\n";
+
+ for(int i = 0; i < g_repeat; i++) {
+ int s = Eigen::internal::random<int>(1,100);
+ MatrixXmp A = MatrixXmp::Random(s,s);
+ MatrixXmp B = MatrixXmp::Random(s,s);
+ MatrixXmp S = A.adjoint() * A;
+ MatrixXmp X;
+
+ // Basic stuffs
+ VERIFY_IS_APPROX(A.real(), A);
+ VERIFY(Eigen::internal::isApprox(A.array().abs2().sum(), A.squaredNorm()));
+ VERIFY_IS_APPROX(A.array().exp(), exp(A.array()));
+ VERIFY_IS_APPROX(A.array().abs2().sqrt(), A.array().abs());
+ VERIFY_IS_APPROX(A.array().sin(), sin(A.array()));
+ VERIFY_IS_APPROX(A.array().cos(), cos(A.array()));
+
+
+ // Cholesky
+ X = S.selfadjointView<Lower>().llt().solve(B);
+ VERIFY_IS_APPROX((S.selfadjointView<Lower>()*X).eval(),B);
+
+ // partial LU
+ X = A.lu().solve(B);
+ VERIFY_IS_APPROX((A*X).eval(),B);
+
+ // symmetric eigenvalues
+ SelfAdjointEigenSolver<MatrixXmp> eig(S);
+ VERIFY_IS_EQUAL(eig.info(), Success);
+ VERIFY_IS_APPROX((S.selfadjointView<Lower>() * eig.eigenvectors()),
+ eig.eigenvectors() * eig.eigenvalues().asDiagonal());
+ }
+
+ {
+ MatrixXmp A(8,3); A.setRandom();
+ // test output (interesting things happen in this code)
+ std::stringstream stream;
+ stream << A;
+ }
+}
+
+extern "C" {
+#include "mpreal/dlmalloc.c"
+}
+#include "mpreal/mpreal.cpp"
diff --git a/unsupported/test/openglsupport.cpp b/unsupported/test/openglsupport.cpp
new file mode 100644
index 000000000..706a816f7
--- /dev/null
+++ b/unsupported/test/openglsupport.cpp
@@ -0,0 +1,337 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra.
+//
+// Copyright (C) 2010 Gael Guennebaud <gael.guennebaud@inria.fr>
+//
+// This Source Code Form is subject to the terms of the Mozilla
+// Public License v. 2.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 <main.h>
+#include <iostream>
+#include <GL/glew.h>
+#include <Eigen/OpenGLSupport>
+#include <GL/glut.h>
+using namespace Eigen;
+
+
+
+
+#define VERIFY_MATRIX(CODE,REF) { \
+ glLoadIdentity(); \
+ CODE; \
+ Matrix<float,4,4,ColMajor> m; m.setZero(); \
+ glGet(GL_MODELVIEW_MATRIX, m); \
+ if(!(REF).cast<float>().isApprox(m)) { \
+ std::cerr << "Expected:\n" << ((REF).cast<float>()) << "\n" << "got\n" << m << "\n\n"; \
+ } \
+ VERIFY_IS_APPROX((REF).cast<float>(), m); \
+ }
+
+#define VERIFY_UNIFORM(SUFFIX,NAME,TYPE) { \
+ TYPE value; value.setRandom(); \
+ TYPE data; \
+ int loc = glGetUniformLocation(prg_id, #NAME); \
+ VERIFY((loc!=-1) && "uniform not found"); \
+ glUniform(loc,value); \
+ EIGEN_CAT(glGetUniform,SUFFIX)(prg_id,loc,data.data()); \
+ if(!value.isApprox(data)) { \
+ std::cerr << "Expected:\n" << value << "\n" << "got\n" << data << "\n\n"; \
+ } \
+ VERIFY_IS_APPROX(value, data); \
+ }
+
+#define VERIFY_UNIFORMi(NAME,TYPE) { \
+ TYPE value = TYPE::Random().eval().cast<float>().cast<TYPE::Scalar>(); \
+ TYPE data; \
+ int loc = glGetUniformLocation(prg_id, #NAME); \
+ VERIFY((loc!=-1) && "uniform not found"); \
+ glUniform(loc,value); \
+ glGetUniformiv(prg_id,loc,(GLint*)data.data()); \
+ if(!value.isApprox(data)) { \
+ std::cerr << "Expected:\n" << value << "\n" << "got\n" << data << "\n\n"; \
+ } \
+ VERIFY_IS_APPROX(value, data); \
+ }
+
+void printInfoLog(GLuint objectID)
+{
+ int infologLength, charsWritten;
+ GLchar *infoLog;
+ glGetProgramiv(objectID,GL_INFO_LOG_LENGTH, &infologLength);
+ if(infologLength > 0)
+ {
+ infoLog = new GLchar[infologLength];
+ glGetProgramInfoLog(objectID, infologLength, &charsWritten, infoLog);
+ if (charsWritten>0)
+ std::cerr << "Shader info : \n" << infoLog << std::endl;
+ delete[] infoLog;
+ }
+}
+
+GLint createShader(const char* vtx, const char* frg)
+{
+ GLint prg_id = glCreateProgram();
+ GLint vtx_id = glCreateShader(GL_VERTEX_SHADER);
+ GLint frg_id = glCreateShader(GL_FRAGMENT_SHADER);
+ GLint ok;
+
+ glShaderSource(vtx_id, 1, &vtx, 0);
+ glCompileShader(vtx_id);
+ glGetShaderiv(vtx_id,GL_COMPILE_STATUS,&ok);
+ if(!ok)
+ {
+ std::cerr << "vtx compilation failed\n";
+ }
+
+ glShaderSource(frg_id, 1, &frg, 0);
+ glCompileShader(frg_id);
+ glGetShaderiv(frg_id,GL_COMPILE_STATUS,&ok);
+ if(!ok)
+ {
+ std::cerr << "frg compilation failed\n";
+ }
+
+ glAttachShader(prg_id, vtx_id);
+ glAttachShader(prg_id, frg_id);
+ glLinkProgram(prg_id);
+ glGetProgramiv(prg_id,GL_LINK_STATUS,&ok);
+ if(!ok)
+ {
+ std::cerr << "linking failed\n";
+ }
+ printInfoLog(prg_id);
+
+ glUseProgram(prg_id);
+ return prg_id;
+}
+
+void test_openglsupport()
+{
+ int argc = 0;
+ glutInit(&argc, 0);
+ glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH);
+ glutInitWindowPosition (0,0);
+ glutInitWindowSize(10, 10);
+
+ if(glutCreateWindow("Eigen") <= 0)
+ {
+ std::cerr << "Error: Unable to create GLUT Window.\n";
+ exit(1);
+ }
+
+ glewExperimental = GL_TRUE;
+ if(glewInit() != GLEW_OK)
+ {
+ std::cerr << "Warning: Failed to initialize GLEW\n";
+ }
+
+ Vector3f v3f;
+ Matrix3f rot;
+ glBegin(GL_POINTS);
+
+ glVertex(v3f);
+ glVertex(2*v3f+v3f);
+ glVertex(rot*v3f);
+
+ glEnd();
+
+ // 4x4 matrices
+ Matrix4f mf44; mf44.setRandom();
+ VERIFY_MATRIX(glLoadMatrix(mf44), mf44);
+ VERIFY_MATRIX(glMultMatrix(mf44), mf44);
+ Matrix4d md44; md44.setRandom();
+ VERIFY_MATRIX(glLoadMatrix(md44), md44);
+ VERIFY_MATRIX(glMultMatrix(md44), md44);
+
+ // Quaternion
+ Quaterniond qd(AngleAxisd(internal::random<double>(), Vector3d::Random()));
+ VERIFY_MATRIX(glRotate(qd), Projective3d(qd).matrix());
+
+ Quaternionf qf(AngleAxisf(internal::random<double>(), Vector3f::Random()));
+ VERIFY_MATRIX(glRotate(qf), Projective3f(qf).matrix());
+
+ // 3D Transform
+ Transform<float,3,AffineCompact> acf3; acf3.matrix().setRandom();
+ VERIFY_MATRIX(glLoadMatrix(acf3), Projective3f(acf3).matrix());
+ VERIFY_MATRIX(glMultMatrix(acf3), Projective3f(acf3).matrix());
+
+ Transform<float,3,Affine> af3(acf3);
+ VERIFY_MATRIX(glLoadMatrix(af3), Projective3f(af3).matrix());
+ VERIFY_MATRIX(glMultMatrix(af3), Projective3f(af3).matrix());
+
+ Transform<float,3,Projective> pf3; pf3.matrix().setRandom();
+ VERIFY_MATRIX(glLoadMatrix(pf3), Projective3f(pf3).matrix());
+ VERIFY_MATRIX(glMultMatrix(pf3), Projective3f(pf3).matrix());
+
+ Transform<double,3,AffineCompact> acd3; acd3.matrix().setRandom();
+ VERIFY_MATRIX(glLoadMatrix(acd3), Projective3d(acd3).matrix());
+ VERIFY_MATRIX(glMultMatrix(acd3), Projective3d(acd3).matrix());
+
+ Transform<double,3,Affine> ad3(acd3);
+ VERIFY_MATRIX(glLoadMatrix(ad3), Projective3d(ad3).matrix());
+ VERIFY_MATRIX(glMultMatrix(ad3), Projective3d(ad3).matrix());
+
+ Transform<double,3,Projective> pd3; pd3.matrix().setRandom();
+ VERIFY_MATRIX(glLoadMatrix(pd3), Projective3d(pd3).matrix());
+ VERIFY_MATRIX(glMultMatrix(pd3), Projective3d(pd3).matrix());
+
+ // translations (2D and 3D)
+ {
+ Vector2f vf2; vf2.setRandom(); Vector3f vf23; vf23 << vf2, 0;
+ VERIFY_MATRIX(glTranslate(vf2), Projective3f(Translation3f(vf23)).matrix());
+ Vector2d vd2; vd2.setRandom(); Vector3d vd23; vd23 << vd2, 0;
+ VERIFY_MATRIX(glTranslate(vd2), Projective3d(Translation3d(vd23)).matrix());
+
+ Vector3f vf3; vf3.setRandom();
+ VERIFY_MATRIX(glTranslate(vf3), Projective3f(Translation3f(vf3)).matrix());
+ Vector3d vd3; vd3.setRandom();
+ VERIFY_MATRIX(glTranslate(vd3), Projective3d(Translation3d(vd3)).matrix());
+
+ Translation<float,3> tf3; tf3.vector().setRandom();
+ VERIFY_MATRIX(glTranslate(tf3), Projective3f(tf3).matrix());
+
+ Translation<double,3> td3; td3.vector().setRandom();
+ VERIFY_MATRIX(glTranslate(td3), Projective3d(td3).matrix());
+ }
+
+ // scaling (2D and 3D)
+ {
+ Vector2f vf2; vf2.setRandom(); Vector3f vf23; vf23 << vf2, 1;
+ VERIFY_MATRIX(glScale(vf2), Projective3f(Scaling(vf23)).matrix());
+ Vector2d vd2; vd2.setRandom(); Vector3d vd23; vd23 << vd2, 1;
+ VERIFY_MATRIX(glScale(vd2), Projective3d(Scaling(vd23)).matrix());
+
+ Vector3f vf3; vf3.setRandom();
+ VERIFY_MATRIX(glScale(vf3), Projective3f(Scaling(vf3)).matrix());
+ Vector3d vd3; vd3.setRandom();
+ VERIFY_MATRIX(glScale(vd3), Projective3d(Scaling(vd3)).matrix());
+
+ UniformScaling<float> usf(internal::random<float>());
+ VERIFY_MATRIX(glScale(usf), Projective3f(usf).matrix());
+
+ UniformScaling<double> usd(internal::random<double>());
+ VERIFY_MATRIX(glScale(usd), Projective3d(usd).matrix());
+ }
+
+ // uniform
+ {
+ const char* vtx = "void main(void) { gl_Position = gl_Vertex; }\n";
+
+ if(GLEW_VERSION_2_0)
+ {
+ #ifdef GL_VERSION_2_0
+ const char* frg = ""
+ "uniform vec2 v2f;\n"
+ "uniform vec3 v3f;\n"
+ "uniform vec4 v4f;\n"
+ "uniform ivec2 v2i;\n"
+ "uniform ivec3 v3i;\n"
+ "uniform ivec4 v4i;\n"
+ "uniform mat2 m2f;\n"
+ "uniform mat3 m3f;\n"
+ "uniform mat4 m4f;\n"
+ "void main(void) { gl_FragColor = vec4(v2f[0]+v3f[0]+v4f[0])+vec4(v2i[0]+v3i[0]+v4i[0])+vec4(m2f[0][0]+m3f[0][0]+m4f[0][0]); }\n";
+
+ GLint prg_id = createShader(vtx,frg);
+
+ VERIFY_UNIFORM(fv,v2f, Vector2f);
+ VERIFY_UNIFORM(fv,v3f, Vector3f);
+ VERIFY_UNIFORM(fv,v4f, Vector4f);
+ VERIFY_UNIFORMi(v2i, Vector2i);
+ VERIFY_UNIFORMi(v3i, Vector3i);
+ VERIFY_UNIFORMi(v4i, Vector4i);
+ VERIFY_UNIFORM(fv,m2f, Matrix2f);
+ VERIFY_UNIFORM(fv,m3f, Matrix3f);
+ VERIFY_UNIFORM(fv,m4f, Matrix4f);
+ #endif
+ }
+ else
+ std::cerr << "Warning: opengl 2.0 was not tested\n";
+
+ if(GLEW_VERSION_2_1)
+ {
+ #ifdef GL_VERSION_2_1
+ const char* frg = "#version 120\n"
+ "uniform mat2x3 m23f;\n"
+ "uniform mat3x2 m32f;\n"
+ "uniform mat2x4 m24f;\n"
+ "uniform mat4x2 m42f;\n"
+ "uniform mat3x4 m34f;\n"
+ "uniform mat4x3 m43f;\n"
+ "void main(void) { gl_FragColor = vec4(m23f[0][0]+m32f[0][0]+m24f[0][0]+m42f[0][0]+m34f[0][0]+m43f[0][0]); }\n";
+
+ GLint prg_id = createShader(vtx,frg);
+
+ typedef Matrix<float,2,3> Matrix23f;
+ typedef Matrix<float,3,2> Matrix32f;
+ typedef Matrix<float,2,4> Matrix24f;
+ typedef Matrix<float,4,2> Matrix42f;
+ typedef Matrix<float,3,4> Matrix34f;
+ typedef Matrix<float,4,3> Matrix43f;
+
+ VERIFY_UNIFORM(fv,m23f, Matrix23f);
+ VERIFY_UNIFORM(fv,m32f, Matrix32f);
+ VERIFY_UNIFORM(fv,m24f, Matrix24f);
+ VERIFY_UNIFORM(fv,m42f, Matrix42f);
+ VERIFY_UNIFORM(fv,m34f, Matrix34f);
+ VERIFY_UNIFORM(fv,m43f, Matrix43f);
+ #endif
+ }
+ else
+ std::cerr << "Warning: opengl 2.1 was not tested\n";
+
+ if(GLEW_VERSION_3_0)
+ {
+ #ifdef GL_VERSION_3_0
+ const char* frg = "#version 150\n"
+ "uniform uvec2 v2ui;\n"
+ "uniform uvec3 v3ui;\n"
+ "uniform uvec4 v4ui;\n"
+ "out vec4 data;\n"
+ "void main(void) { data = vec4(v2ui[0]+v3ui[0]+v4ui[0]); }\n";
+
+ GLint prg_id = createShader(vtx,frg);
+
+ typedef Matrix<unsigned int,2,1> Vector2ui;
+ typedef Matrix<unsigned int,3,1> Vector3ui;
+ typedef Matrix<unsigned int,4,1> Vector4ui;
+
+ VERIFY_UNIFORMi(v2ui, Vector2ui);
+ VERIFY_UNIFORMi(v3ui, Vector3ui);
+ VERIFY_UNIFORMi(v4ui, Vector4ui);
+ #endif
+ }
+ else
+ std::cerr << "Warning: opengl 3.0 was not tested\n";
+
+ #ifdef GLEW_ARB_gpu_shader_fp64
+ if(GLEW_ARB_gpu_shader_fp64)
+ {
+ #ifdef GL_ARB_gpu_shader_fp64
+ const char* frg = "#version 150\n"
+ "uniform dvec2 v2d;\n"
+ "uniform dvec3 v3d;\n"
+ "uniform dvec4 v4d;\n"
+ "out vec4 data;\n"
+ "void main(void) { data = vec4(v2d[0]+v3d[0]+v4d[0]); }\n";
+
+ GLint prg_id = createShader(vtx,frg);
+
+ typedef Vector2d Vector2d;
+ typedef Vector3d Vector3d;
+ typedef Vector4d Vector4d;
+
+ VERIFY_UNIFORM(dv,v2d, Vector2d);
+ VERIFY_UNIFORM(dv,v3d, Vector3d);
+ VERIFY_UNIFORM(dv,v4d, Vector4d);
+ #endif
+ }
+ else
+ std::cerr << "Warning: GLEW_ARB_gpu_shader_fp64 was not tested\n";
+ #else
+ std::cerr << "Warning: GLEW_ARB_gpu_shader_fp64 was not tested\n";
+ #endif
+ }
+
+}
diff --git a/unsupported/test/polynomialsolver.cpp b/unsupported/test/polynomialsolver.cpp
new file mode 100644
index 000000000..fefeaff01
--- /dev/null
+++ b/unsupported/test/polynomialsolver.cpp
@@ -0,0 +1,217 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra.
+//
+// Copyright (C) 2010 Manuel Yguel <manuel.yguel@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 "main.h"
+#include <unsupported/Eigen/Polynomials>
+#include <iostream>
+#include <algorithm>
+
+using namespace std;
+
+namespace Eigen {
+namespace internal {
+template<int Size>
+struct increment_if_fixed_size
+{
+ enum {
+ ret = (Size == Dynamic) ? Dynamic : Size+1
+ };
+};
+}
+}
+
+
+template<int Deg, typename POLYNOMIAL, typename SOLVER>
+bool aux_evalSolver( const POLYNOMIAL& pols, SOLVER& psolve )
+{
+ typedef typename POLYNOMIAL::Index Index;
+ typedef typename POLYNOMIAL::Scalar Scalar;
+
+ typedef typename SOLVER::RootsType RootsType;
+ typedef Matrix<Scalar,Deg,1> EvalRootsType;
+
+ const Index deg = pols.size()-1;
+
+ psolve.compute( pols );
+ const RootsType& roots( psolve.roots() );
+ EvalRootsType evr( deg );
+ for( int i=0; i<roots.size(); ++i ){
+ evr[i] = std::abs( poly_eval( pols, roots[i] ) ); }
+
+ bool evalToZero = evr.isZero( test_precision<Scalar>() );
+ if( !evalToZero )
+ {
+ cerr << "WRONG root: " << endl;
+ cerr << "Polynomial: " << pols.transpose() << endl;
+ cerr << "Roots found: " << roots.transpose() << endl;
+ cerr << "Abs value of the polynomial at the roots: " << evr.transpose() << endl;
+ cerr << endl;
+ }
+
+ std::vector<Scalar> rootModuli( roots.size() );
+ Map< EvalRootsType > aux( &rootModuli[0], roots.size() );
+ aux = roots.array().abs();
+ std::sort( rootModuli.begin(), rootModuli.end() );
+ bool distinctModuli=true;
+ for( size_t i=1; i<rootModuli.size() && distinctModuli; ++i )
+ {
+ if( internal::isApprox( rootModuli[i], rootModuli[i-1] ) ){
+ distinctModuli = false; }
+ }
+ VERIFY( evalToZero || !distinctModuli );
+
+ return distinctModuli;
+}
+
+
+
+
+
+
+
+template<int Deg, typename POLYNOMIAL>
+void evalSolver( const POLYNOMIAL& pols )
+{
+ typedef typename POLYNOMIAL::Scalar Scalar;
+
+ typedef PolynomialSolver<Scalar, Deg > PolynomialSolverType;
+
+ PolynomialSolverType psolve;
+ aux_evalSolver<Deg, POLYNOMIAL, PolynomialSolverType>( pols, psolve );
+}
+
+
+
+
+template< int Deg, typename POLYNOMIAL, typename ROOTS, typename REAL_ROOTS >
+void evalSolverSugarFunction( const POLYNOMIAL& pols, const ROOTS& roots, const REAL_ROOTS& real_roots )
+{
+ typedef typename POLYNOMIAL::Scalar Scalar;
+
+ typedef PolynomialSolver<Scalar, Deg > PolynomialSolverType;
+
+ PolynomialSolverType psolve;
+ if( aux_evalSolver<Deg, POLYNOMIAL, PolynomialSolverType>( pols, psolve ) )
+ {
+ //It is supposed that
+ // 1) the roots found are correct
+ // 2) the roots have distinct moduli
+
+ typedef typename POLYNOMIAL::Scalar Scalar;
+ typedef typename REAL_ROOTS::Scalar Real;
+
+ typedef PolynomialSolver<Scalar, Deg > PolynomialSolverType;
+ typedef typename PolynomialSolverType::RootsType RootsType;
+ typedef Matrix<Scalar,Deg,1> EvalRootsType;
+
+ //Test realRoots
+ std::vector< Real > calc_realRoots;
+ psolve.realRoots( calc_realRoots );
+ VERIFY( calc_realRoots.size() == (size_t)real_roots.size() );
+
+ const Scalar psPrec = internal::sqrt( test_precision<Scalar>() );
+
+ for( size_t i=0; i<calc_realRoots.size(); ++i )
+ {
+ bool found = false;
+ for( size_t j=0; j<calc_realRoots.size()&& !found; ++j )
+ {
+ if( internal::isApprox( calc_realRoots[i], real_roots[j] ), psPrec ){
+ found = true; }
+ }
+ VERIFY( found );
+ }
+
+ //Test greatestRoot
+ VERIFY( internal::isApprox( roots.array().abs().maxCoeff(),
+ internal::abs( psolve.greatestRoot() ), psPrec ) );
+
+ //Test smallestRoot
+ VERIFY( internal::isApprox( roots.array().abs().minCoeff(),
+ internal::abs( psolve.smallestRoot() ), psPrec ) );
+
+ bool hasRealRoot;
+ //Test absGreatestRealRoot
+ Real r = psolve.absGreatestRealRoot( hasRealRoot );
+ VERIFY( hasRealRoot == (real_roots.size() > 0 ) );
+ if( hasRealRoot ){
+ VERIFY( internal::isApprox( real_roots.array().abs().maxCoeff(), internal::abs(r), psPrec ) ); }
+
+ //Test absSmallestRealRoot
+ r = psolve.absSmallestRealRoot( hasRealRoot );
+ VERIFY( hasRealRoot == (real_roots.size() > 0 ) );
+ if( hasRealRoot ){
+ VERIFY( internal::isApprox( real_roots.array().abs().minCoeff(), internal::abs( r ), psPrec ) ); }
+
+ //Test greatestRealRoot
+ r = psolve.greatestRealRoot( hasRealRoot );
+ VERIFY( hasRealRoot == (real_roots.size() > 0 ) );
+ if( hasRealRoot ){
+ VERIFY( internal::isApprox( real_roots.array().maxCoeff(), r, psPrec ) ); }
+
+ //Test smallestRealRoot
+ r = psolve.smallestRealRoot( hasRealRoot );
+ VERIFY( hasRealRoot == (real_roots.size() > 0 ) );
+ if( hasRealRoot ){
+ VERIFY( internal::isApprox( real_roots.array().minCoeff(), r, psPrec ) ); }
+ }
+}
+
+
+template<typename _Scalar, int _Deg>
+void polynomialsolver(int deg)
+{
+ typedef internal::increment_if_fixed_size<_Deg> Dim;
+ typedef Matrix<_Scalar,Dim::ret,1> PolynomialType;
+ typedef Matrix<_Scalar,_Deg,1> EvalRootsType;
+
+ cout << "Standard cases" << endl;
+ PolynomialType pols = PolynomialType::Random(deg+1);
+ evalSolver<_Deg,PolynomialType>( pols );
+
+ cout << "Hard cases" << endl;
+ _Scalar multipleRoot = internal::random<_Scalar>();
+ EvalRootsType allRoots = EvalRootsType::Constant(deg,multipleRoot);
+ roots_to_monicPolynomial( allRoots, pols );
+ evalSolver<_Deg,PolynomialType>( pols );
+
+ cout << "Test sugar" << endl;
+ EvalRootsType realRoots = EvalRootsType::Random(deg);
+ roots_to_monicPolynomial( realRoots, pols );
+ evalSolverSugarFunction<_Deg>(
+ pols,
+ realRoots.template cast <
+ std::complex<
+ typename NumTraits<_Scalar>::Real
+ >
+ >(),
+ realRoots );
+}
+
+void test_polynomialsolver()
+{
+ for(int i = 0; i < g_repeat; i++)
+ {
+ CALL_SUBTEST_1( (polynomialsolver<float,1>(1)) );
+ CALL_SUBTEST_2( (polynomialsolver<double,2>(2)) );
+ CALL_SUBTEST_3( (polynomialsolver<double,3>(3)) );
+ CALL_SUBTEST_4( (polynomialsolver<float,4>(4)) );
+ CALL_SUBTEST_5( (polynomialsolver<double,5>(5)) );
+ CALL_SUBTEST_6( (polynomialsolver<float,6>(6)) );
+ CALL_SUBTEST_7( (polynomialsolver<float,7>(7)) );
+ CALL_SUBTEST_8( (polynomialsolver<double,8>(8)) );
+
+ CALL_SUBTEST_9( (polynomialsolver<float,Dynamic>(
+ internal::random<int>(9,13)
+ )) );
+ CALL_SUBTEST_10((polynomialsolver<double,Dynamic>(
+ internal::random<int>(9,13)
+ )) );
+ }
+}
diff --git a/unsupported/test/polynomialutils.cpp b/unsupported/test/polynomialutils.cpp
new file mode 100644
index 000000000..5fc968402
--- /dev/null
+++ b/unsupported/test/polynomialutils.cpp
@@ -0,0 +1,113 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra.
+//
+// Copyright (C) 2010 Manuel Yguel <manuel.yguel@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 "main.h"
+#include <unsupported/Eigen/Polynomials>
+#include <iostream>
+
+using namespace std;
+
+namespace Eigen {
+namespace internal {
+template<int Size>
+struct increment_if_fixed_size
+{
+ enum {
+ ret = (Size == Dynamic) ? Dynamic : Size+1
+ };
+};
+}
+}
+
+template<typename _Scalar, int _Deg>
+void realRoots_to_monicPolynomial_test(int deg)
+{
+ typedef internal::increment_if_fixed_size<_Deg> Dim;
+ typedef Matrix<_Scalar,Dim::ret,1> PolynomialType;
+ typedef Matrix<_Scalar,_Deg,1> EvalRootsType;
+
+ PolynomialType pols(deg+1);
+ EvalRootsType roots = EvalRootsType::Random(deg);
+ roots_to_monicPolynomial( roots, pols );
+
+ EvalRootsType evr( deg );
+ for( int i=0; i<roots.size(); ++i ){
+ evr[i] = std::abs( poly_eval( pols, roots[i] ) ); }
+
+ bool evalToZero = evr.isZero( test_precision<_Scalar>() );
+ if( !evalToZero ){
+ cerr << evr.transpose() << endl; }
+ VERIFY( evalToZero );
+}
+
+template<typename _Scalar> void realRoots_to_monicPolynomial_scalar()
+{
+ CALL_SUBTEST_2( (realRoots_to_monicPolynomial_test<_Scalar,2>(2)) );
+ CALL_SUBTEST_3( (realRoots_to_monicPolynomial_test<_Scalar,3>(3)) );
+ CALL_SUBTEST_4( (realRoots_to_monicPolynomial_test<_Scalar,4>(4)) );
+ CALL_SUBTEST_5( (realRoots_to_monicPolynomial_test<_Scalar,5>(5)) );
+ CALL_SUBTEST_6( (realRoots_to_monicPolynomial_test<_Scalar,6>(6)) );
+ CALL_SUBTEST_7( (realRoots_to_monicPolynomial_test<_Scalar,7>(7)) );
+ CALL_SUBTEST_8( (realRoots_to_monicPolynomial_test<_Scalar,17>(17)) );
+
+ CALL_SUBTEST_9( (realRoots_to_monicPolynomial_test<_Scalar,Dynamic>(
+ internal::random<int>(18,26) )) );
+}
+
+
+
+
+template<typename _Scalar, int _Deg>
+void CauchyBounds(int deg)
+{
+ typedef internal::increment_if_fixed_size<_Deg> Dim;
+ typedef Matrix<_Scalar,Dim::ret,1> PolynomialType;
+ typedef Matrix<_Scalar,_Deg,1> EvalRootsType;
+
+ PolynomialType pols(deg+1);
+ EvalRootsType roots = EvalRootsType::Random(deg);
+ roots_to_monicPolynomial( roots, pols );
+ _Scalar M = cauchy_max_bound( pols );
+ _Scalar m = cauchy_min_bound( pols );
+ _Scalar Max = roots.array().abs().maxCoeff();
+ _Scalar min = roots.array().abs().minCoeff();
+ bool eval = (M >= Max) && (m <= min);
+ if( !eval )
+ {
+ cerr << "Roots: " << roots << endl;
+ cerr << "Bounds: (" << m << ", " << M << ")" << endl;
+ cerr << "Min,Max: (" << min << ", " << Max << ")" << endl;
+ }
+ VERIFY( eval );
+}
+
+template<typename _Scalar> void CauchyBounds_scalar()
+{
+ CALL_SUBTEST_2( (CauchyBounds<_Scalar,2>(2)) );
+ CALL_SUBTEST_3( (CauchyBounds<_Scalar,3>(3)) );
+ CALL_SUBTEST_4( (CauchyBounds<_Scalar,4>(4)) );
+ CALL_SUBTEST_5( (CauchyBounds<_Scalar,5>(5)) );
+ CALL_SUBTEST_6( (CauchyBounds<_Scalar,6>(6)) );
+ CALL_SUBTEST_7( (CauchyBounds<_Scalar,7>(7)) );
+ CALL_SUBTEST_8( (CauchyBounds<_Scalar,17>(17)) );
+
+ CALL_SUBTEST_9( (CauchyBounds<_Scalar,Dynamic>(
+ internal::random<int>(18,26) )) );
+}
+
+void test_polynomialutils()
+{
+ for(int i = 0; i < g_repeat; i++)
+ {
+ realRoots_to_monicPolynomial_scalar<double>();
+ realRoots_to_monicPolynomial_scalar<float>();
+ CauchyBounds_scalar<double>();
+ CauchyBounds_scalar<float>();
+ }
+}
diff --git a/unsupported/test/sparse_extra.cpp b/unsupported/test/sparse_extra.cpp
new file mode 100644
index 000000000..5dc333424
--- /dev/null
+++ b/unsupported/test/sparse_extra.cpp
@@ -0,0 +1,149 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra.
+//
+// Copyright (C) 2008-2010 Gael Guennebaud <g.gael@free.fr>
+//
+// This Source Code Form is subject to the terms of the Mozilla
+// Public License v. 2.0. If a copy of the MPL was not distributed
+// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+
+// import basic and product tests for deprectaed DynamicSparseMatrix
+#define EIGEN_NO_DEPRECATED_WARNING
+#include "sparse_basic.cpp"
+#include "sparse_product.cpp"
+#include <Eigen/SparseExtra>
+
+template<typename SetterType,typename DenseType, typename Scalar, int Options>
+bool test_random_setter(SparseMatrix<Scalar,Options>& sm, const DenseType& ref, const std::vector<Vector2i>& nonzeroCoords)
+{
+ typedef SparseMatrix<Scalar,Options> SparseType;
+ {
+ sm.setZero();
+ SetterType w(sm);
+ std::vector<Vector2i> remaining = nonzeroCoords;
+ while(!remaining.empty())
+ {
+ int i = internal::random<int>(0,static_cast<int>(remaining.size())-1);
+ w(remaining[i].x(),remaining[i].y()) = ref.coeff(remaining[i].x(),remaining[i].y());
+ remaining[i] = remaining.back();
+ remaining.pop_back();
+ }
+ }
+ return sm.isApprox(ref);
+}
+
+template<typename SetterType,typename DenseType, typename T>
+bool test_random_setter(DynamicSparseMatrix<T>& sm, const DenseType& ref, const std::vector<Vector2i>& nonzeroCoords)
+{
+ sm.setZero();
+ std::vector<Vector2i> remaining = nonzeroCoords;
+ while(!remaining.empty())
+ {
+ int i = internal::random<int>(0,static_cast<int>(remaining.size())-1);
+ sm.coeffRef(remaining[i].x(),remaining[i].y()) = ref.coeff(remaining[i].x(),remaining[i].y());
+ remaining[i] = remaining.back();
+ remaining.pop_back();
+ }
+ return sm.isApprox(ref);
+}
+
+template<typename SparseMatrixType> void sparse_extra(const SparseMatrixType& ref)
+{
+ typedef typename SparseMatrixType::Index Index;
+ const Index rows = ref.rows();
+ const Index cols = ref.cols();
+ typedef typename SparseMatrixType::Scalar Scalar;
+ enum { Flags = SparseMatrixType::Flags };
+
+ double density = (std::max)(8./(rows*cols), 0.01);
+ typedef Matrix<Scalar,Dynamic,Dynamic> DenseMatrix;
+ typedef Matrix<Scalar,Dynamic,1> DenseVector;
+ Scalar eps = 1e-6;
+
+ SparseMatrixType m(rows, cols);
+ DenseMatrix refMat = DenseMatrix::Zero(rows, cols);
+ DenseVector vec1 = DenseVector::Random(rows);
+
+ std::vector<Vector2i> zeroCoords;
+ std::vector<Vector2i> nonzeroCoords;
+ initSparse<Scalar>(density, refMat, m, 0, &zeroCoords, &nonzeroCoords);
+
+ if (zeroCoords.size()==0 || nonzeroCoords.size()==0)
+ return;
+
+ // test coeff and coeffRef
+ for (int i=0; i<(int)zeroCoords.size(); ++i)
+ {
+ VERIFY_IS_MUCH_SMALLER_THAN( m.coeff(zeroCoords[i].x(),zeroCoords[i].y()), eps );
+ if(internal::is_same<SparseMatrixType,SparseMatrix<Scalar,Flags> >::value)
+ VERIFY_RAISES_ASSERT( m.coeffRef(zeroCoords[0].x(),zeroCoords[0].y()) = 5 );
+ }
+ VERIFY_IS_APPROX(m, refMat);
+
+ m.coeffRef(nonzeroCoords[0].x(), nonzeroCoords[0].y()) = Scalar(5);
+ refMat.coeffRef(nonzeroCoords[0].x(), nonzeroCoords[0].y()) = Scalar(5);
+
+ VERIFY_IS_APPROX(m, refMat);
+
+ // random setter
+// {
+// m.setZero();
+// VERIFY_IS_NOT_APPROX(m, refMat);
+// SparseSetter<SparseMatrixType, RandomAccessPattern> w(m);
+// std::vector<Vector2i> remaining = nonzeroCoords;
+// while(!remaining.empty())
+// {
+// int i = internal::random<int>(0,remaining.size()-1);
+// w->coeffRef(remaining[i].x(),remaining[i].y()) = refMat.coeff(remaining[i].x(),remaining[i].y());
+// remaining[i] = remaining.back();
+// remaining.pop_back();
+// }
+// }
+// VERIFY_IS_APPROX(m, refMat);
+
+ VERIFY(( test_random_setter<RandomSetter<SparseMatrixType, StdMapTraits> >(m,refMat,nonzeroCoords) ));
+ #ifdef EIGEN_UNORDERED_MAP_SUPPORT
+ VERIFY(( test_random_setter<RandomSetter<SparseMatrixType, StdUnorderedMapTraits> >(m,refMat,nonzeroCoords) ));
+ #endif
+ #ifdef _DENSE_HASH_MAP_H_
+ VERIFY(( test_random_setter<RandomSetter<SparseMatrixType, GoogleDenseHashMapTraits> >(m,refMat,nonzeroCoords) ));
+ #endif
+ #ifdef _SPARSE_HASH_MAP_H_
+ VERIFY(( test_random_setter<RandomSetter<SparseMatrixType, GoogleSparseHashMapTraits> >(m,refMat,nonzeroCoords) ));
+ #endif
+
+
+ // test RandomSetter
+ /*{
+ SparseMatrixType m1(rows,cols), m2(rows,cols);
+ DenseMatrix refM1 = DenseMatrix::Zero(rows, rows);
+ initSparse<Scalar>(density, refM1, m1);
+ {
+ Eigen::RandomSetter<SparseMatrixType > setter(m2);
+ for (int j=0; j<m1.outerSize(); ++j)
+ for (typename SparseMatrixType::InnerIterator i(m1,j); i; ++i)
+ setter(i.index(), j) = i.value();
+ }
+ VERIFY_IS_APPROX(m1, m2);
+ }*/
+
+
+}
+
+void test_sparse_extra()
+{
+ for(int i = 0; i < g_repeat; i++) {
+ int s = Eigen::internal::random<int>(1,50);
+ CALL_SUBTEST_1( sparse_extra(SparseMatrix<double>(8, 8)) );
+ CALL_SUBTEST_2( sparse_extra(SparseMatrix<std::complex<double> >(s, s)) );
+ CALL_SUBTEST_1( sparse_extra(SparseMatrix<double>(s, s)) );
+
+ CALL_SUBTEST_3( sparse_extra(DynamicSparseMatrix<double>(s, s)) );
+// CALL_SUBTEST_3(( sparse_basic(DynamicSparseMatrix<double>(s, s)) ));
+// CALL_SUBTEST_3(( sparse_basic(DynamicSparseMatrix<double,ColMajor,long int>(s, s)) ));
+
+ CALL_SUBTEST_3( (sparse_product<DynamicSparseMatrix<float, ColMajor> >()) );
+ CALL_SUBTEST_3( (sparse_product<DynamicSparseMatrix<float, RowMajor> >()) );
+ }
+}
diff --git a/unsupported/test/splines.cpp b/unsupported/test/splines.cpp
new file mode 100644
index 000000000..1043453dc
--- /dev/null
+++ b/unsupported/test/splines.cpp
@@ -0,0 +1,240 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra.
+//
+// Copyright (C) 2010-2011 Hauke Heibel <heibel@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 "main.h"
+
+#include <unsupported/Eigen/Splines>
+
+// lets do some explicit instantiations and thus
+// force the compilation of all spline functions...
+template class Spline<double, 2, Dynamic>;
+template class Spline<double, 3, Dynamic>;
+
+template class Spline<double, 2, 2>;
+template class Spline<double, 2, 3>;
+template class Spline<double, 2, 4>;
+template class Spline<double, 2, 5>;
+
+template class Spline<float, 2, Dynamic>;
+template class Spline<float, 3, Dynamic>;
+
+template class Spline<float, 3, 2>;
+template class Spline<float, 3, 3>;
+template class Spline<float, 3, 4>;
+template class Spline<float, 3, 5>;
+
+Spline<double, 2, Dynamic> closed_spline2d()
+{
+ RowVectorXd knots(12);
+ knots << 0,
+ 0,
+ 0,
+ 0,
+ 0.867193179093898,
+ 1.660330955342408,
+ 2.605084834823134,
+ 3.484154586374428,
+ 4.252699478956276,
+ 4.252699478956276,
+ 4.252699478956276,
+ 4.252699478956276;
+
+ MatrixXd ctrls(8,2);
+ ctrls << -0.370967741935484, 0.236842105263158,
+ -0.231401860693277, 0.442245185027632,
+ 0.344361228532831, 0.773369994120753,
+ 0.828990216203802, 0.106550882647595,
+ 0.407270163678382, -1.043452922172848,
+ -0.488467813584053, -0.390098582530090,
+ -0.494657189446427, 0.054804824897884,
+ -0.370967741935484, 0.236842105263158;
+ ctrls.transposeInPlace();
+
+ return Spline<double, 2, Dynamic>(knots, ctrls);
+}
+
+/* create a reference spline */
+Spline<double, 3, Dynamic> spline3d()
+{
+ RowVectorXd knots(11);
+ knots << 0,
+ 0,
+ 0,
+ 0.118997681558377,
+ 0.162611735194631,
+ 0.498364051982143,
+ 0.655098003973841,
+ 0.679702676853675,
+ 1.000000000000000,
+ 1.000000000000000,
+ 1.000000000000000;
+
+ MatrixXd ctrls(8,3);
+ ctrls << 0.959743958516081, 0.340385726666133, 0.585267750979777,
+ 0.223811939491137, 0.751267059305653, 0.255095115459269,
+ 0.505957051665142, 0.699076722656686, 0.890903252535799,
+ 0.959291425205444, 0.547215529963803, 0.138624442828679,
+ 0.149294005559057, 0.257508254123736, 0.840717255983663,
+ 0.254282178971531, 0.814284826068816, 0.243524968724989,
+ 0.929263623187228, 0.349983765984809, 0.196595250431208,
+ 0.251083857976031, 0.616044676146639, 0.473288848902729;
+ ctrls.transposeInPlace();
+
+ return Spline<double, 3, Dynamic>(knots, ctrls);
+}
+
+/* compares evaluations against known results */
+void eval_spline3d()
+{
+ Spline3d spline = spline3d();
+
+ RowVectorXd u(10);
+ u << 0.351659507062997,
+ 0.830828627896291,
+ 0.585264091152724,
+ 0.549723608291140,
+ 0.917193663829810,
+ 0.285839018820374,
+ 0.757200229110721,
+ 0.753729094278495,
+ 0.380445846975357,
+ 0.567821640725221;
+
+ MatrixXd pts(10,3);
+ pts << 0.707620811535916, 0.510258911240815, 0.417485437023409,
+ 0.603422256426978, 0.529498282727551, 0.270351549348981,
+ 0.228364197569334, 0.423745615677815, 0.637687289287490,
+ 0.275556796335168, 0.350856706427970, 0.684295784598905,
+ 0.514519311047655, 0.525077224890754, 0.351628308305896,
+ 0.724152914315666, 0.574461155457304, 0.469860285484058,
+ 0.529365063753288, 0.613328702656816, 0.237837040141739,
+ 0.522469395136878, 0.619099658652895, 0.237139665242069,
+ 0.677357023849552, 0.480655768435853, 0.422227610314397,
+ 0.247046593173758, 0.380604672404750, 0.670065791405019;
+ pts.transposeInPlace();
+
+ for (int i=0; i<u.size(); ++i)
+ {
+ Vector3d pt = spline(u(i));
+ VERIFY( (pt - pts.col(i)).norm() < 1e-14 );
+ }
+}
+
+/* compares evaluations on corner cases */
+void eval_spline3d_onbrks()
+{
+ Spline3d spline = spline3d();
+
+ RowVectorXd u = spline.knots();
+
+ MatrixXd pts(11,3);
+ pts << 0.959743958516081, 0.340385726666133, 0.585267750979777,
+ 0.959743958516081, 0.340385726666133, 0.585267750979777,
+ 0.959743958516081, 0.340385726666133, 0.585267750979777,
+ 0.430282980289940, 0.713074680056118, 0.720373307943349,
+ 0.558074875553060, 0.681617921034459, 0.804417124839942,
+ 0.407076008291750, 0.349707710518163, 0.617275937419545,
+ 0.240037008286602, 0.738739390398014, 0.324554153129411,
+ 0.302434111480572, 0.781162443963899, 0.240177089094644,
+ 0.251083857976031, 0.616044676146639, 0.473288848902729,
+ 0.251083857976031, 0.616044676146639, 0.473288848902729,
+ 0.251083857976031, 0.616044676146639, 0.473288848902729;
+ pts.transposeInPlace();
+
+ for (int i=0; i<u.size(); ++i)
+ {
+ Vector3d pt = spline(u(i));
+ VERIFY( (pt - pts.col(i)).norm() < 1e-14 );
+ }
+}
+
+void eval_closed_spline2d()
+{
+ Spline2d spline = closed_spline2d();
+
+ RowVectorXd u(12);
+ u << 0,
+ 0.332457030395796,
+ 0.356467130532952,
+ 0.453562180176215,
+ 0.648017921874804,
+ 0.973770235555003,
+ 1.882577647219307,
+ 2.289408593930498,
+ 3.511951429883045,
+ 3.884149321369450,
+ 4.236261590369414,
+ 4.252699478956276;
+
+ MatrixXd pts(12,2);
+ pts << -0.370967741935484, 0.236842105263158,
+ -0.152576775123250, 0.448975001279334,
+ -0.133417538277668, 0.461615613865667,
+ -0.053199060826740, 0.507630360006299,
+ 0.114249591147281, 0.570414135097409,
+ 0.377810316891987, 0.560497102875315,
+ 0.665052120135908, -0.157557441109611,
+ 0.516006487053228, -0.559763292174825,
+ -0.379486035348887, -0.331959640488223,
+ -0.462034726249078, -0.039105670080824,
+ -0.378730600917982, 0.225127015099919,
+ -0.370967741935484, 0.236842105263158;
+ pts.transposeInPlace();
+
+ for (int i=0; i<u.size(); ++i)
+ {
+ Vector2d pt = spline(u(i));
+ VERIFY( (pt - pts.col(i)).norm() < 1e-14 );
+ }
+}
+
+void check_global_interpolation2d()
+{
+ typedef Spline2d::PointType PointType;
+ typedef Spline2d::KnotVectorType KnotVectorType;
+ typedef Spline2d::ControlPointVectorType ControlPointVectorType;
+
+ ControlPointVectorType points = ControlPointVectorType::Random(2,100);
+
+ KnotVectorType chord_lengths; // knot parameters
+ Eigen::ChordLengths(points, chord_lengths);
+
+ // interpolation without knot parameters
+ {
+ const Spline2d spline = SplineFitting<Spline2d>::Interpolate(points,3);
+
+ for (Eigen::DenseIndex i=0; i<points.cols(); ++i)
+ {
+ PointType pt = spline( chord_lengths(i) );
+ PointType ref = points.col(i);
+ VERIFY( (pt - ref).matrix().norm() < 1e-14 );
+ }
+ }
+
+ // interpolation with given knot parameters
+ {
+ const Spline2d spline = SplineFitting<Spline2d>::Interpolate(points,3,chord_lengths);
+
+ for (Eigen::DenseIndex i=0; i<points.cols(); ++i)
+ {
+ PointType pt = spline( chord_lengths(i) );
+ PointType ref = points.col(i);
+ VERIFY( (pt - ref).matrix().norm() < 1e-14 );
+ }
+ }
+}
+
+
+void test_splines()
+{
+ CALL_SUBTEST( eval_spline3d() );
+ CALL_SUBTEST( eval_spline3d_onbrks() );
+ CALL_SUBTEST( eval_closed_spline2d() );
+ CALL_SUBTEST( check_global_interpolation2d() );
+}