Eigne Matrix Class Library
Dependents: Eigen_test Odometry_test AttitudeEstimation_usingTicker MPU9250_Quaternion_Binary_Serial ... more
Eigen Matrix Class Library for mbed.
Finally, you can use Eigen on your mbed!!!
Revision 0:13a5d365ba16, committed 2016-10-13
- Comitter:
- ykuroda
- Date:
- Thu Oct 13 04:07:23 2016 +0000
- Commit message:
- First commint, Eigne Matrix Class Library
Changed in this revision
diff -r 000000000000 -r 13a5d365ba16 Array.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Array.h Thu Oct 13 04:07:23 2016 +0000 @@ -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 \ No newline at end of file
diff -r 000000000000 -r 13a5d365ba16 Cholesky.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Cholesky.h Thu Oct 13 04:07:23 2016 +0000 @@ -0,0 +1,32 @@ +#ifndef EIGEN_CHOLESKY_MODULE_H +#define EIGEN_CHOLESKY_MODULE_H + +#include "Core.h" + +#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: */ \ No newline at end of file
diff -r 000000000000 -r 13a5d365ba16 Core.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Core.h Thu Oct 13 04:07:23 2016 +0000 @@ -0,0 +1,376 @@ +// 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" + +// Disable the ipa-cp-clone optimization flag with MinGW 6.x or newer (enabled by default with -O3) +// See http://eigen.tuxfamily.org/bz/show_bug.cgi?id=556 for details. +#if defined(__MINGW32__) && EIGEN_GNUC_AT_LEAST(4,6) + #pragma GCC optimize ("-fno-ipa-cp-clone") +#endif + +#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__) || (defined __INTEL_COMPILER) || 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" { + // In theory we should only include immintrin.h and not the other *mmintrin.h header files directly. + // Doing so triggers some issues with ICC. However old gcc versions seems to not have this file, thus: + #if defined(__INTEL_COMPILER) && __INTEL_COMPILER >= 1110 + #include <immintrin.h> + #else + #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 + #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)) && (!defined(_WIN32_WCE)) + #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 + */ + +#include "src/Core/util/Constants.h" +#include "src/Core/util/ForwardDeclarations.h" +#include "src/Core/util/Meta.h" +#include "src/Core/util/StaticAssert.h" +#include "src/Core/util/XprHelper.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/Ref.h" +#include "src/Core/Transpose.h" +#include "src/Core/DiagonalMatrix.h" +#include "src/Core/Diagonal.h" +#include "src/Core/DiagonalProduct.h" +#include "src/Core/PermutationMatrix.h" +#include "src/Core/Transpositions.h" +#include "src/Core/Redux.h" +#include "src/Core/Visitor.h" +#include "src/Core/Fuzzy.h" +#include "src/Core/IO.h" +#include "src/Core/Swap.h" +#include "src/Core/CommaInitializer.h" +#include "src/Core/Flagged.h" +#include "src/Core/ProductBase.h" +#include "src/Core/GeneralProduct.h" +#include "src/Core/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/CoreIterators.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 \ No newline at end of file
diff -r 000000000000 -r 13a5d365ba16 Dense.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Dense.h Thu Oct 13 04:07:23 2016 +0000 @@ -0,0 +1,7 @@ +#include "Core.h" +#include "LU.h" +#include "Cholesky.h" +#include "QR.h" +#include "SVD.h" +#include "Geometry.h" +#include "Eigenvalues.h" \ No newline at end of file
diff -r 000000000000 -r 13a5d365ba16 Eigenvalues.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Eigenvalues.h Thu Oct 13 04:07:23 2016 +0000 @@ -0,0 +1,48 @@ +#ifndef EIGEN_EIGENVALUES_MODULE_H +#define EIGEN_EIGENVALUES_MODULE_H + +#include "Core.h" + +#include "src/Core/util/DisableStupidWarnings.h" + +#include "Cholesky.h" +#include "Jacobi.h" +#include "Householder.h" +#include "LU.h" +#include "Geometry.h" + +/** \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/RealQZ.h" +#include "src/Eigenvalues/GeneralizedEigenSolver.h" +#include "src/Eigenvalues/MatrixBaseEigenvalues.h" +#ifdef EIGEN_USE_LAPACKE +#include "src/Eigenvalues/RealSchur_MKL.h" +#include "src/Eigenvalues/ComplexSchur_MKL.h" +#include "src/Eigenvalues/SelfAdjointEigenSolver_MKL.h" +#endif + +#include "src/Core/util/ReenableStupidWarnings.h" + +#endif // EIGEN_EIGENVALUES_MODULE_H +/* vim: set filetype=cpp et sw=2 ts=2 ai: */ \ No newline at end of file
diff -r 000000000000 -r 13a5d365ba16 Geometry.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Geometry.h Thu Oct 13 04:07:23 2016 +0000 @@ -0,0 +1,62 @@ +#ifndef EIGEN_GEOMETRY_MODULE_H +#define EIGEN_GEOMETRY_MODULE_H + +#include "Core.h" + +#include "src/Core/util/DisableStupidWarnings.h" + +#include "SVD.h" +#include "LU.h" +#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 -r 000000000000 -r 13a5d365ba16 Householder.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Householder.h Thu Oct 13 04:07:23 2016 +0000 @@ -0,0 +1,23 @@ +#ifndef EIGEN_HOUSEHOLDER_MODULE_H +#define EIGEN_HOUSEHOLDER_MODULE_H + +#include "Core.h" + +#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: */ \ No newline at end of file
diff -r 000000000000 -r 13a5d365ba16 Jacobi.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Jacobi.h Thu Oct 13 04:07:23 2016 +0000 @@ -0,0 +1,25 @@ +#ifndef EIGEN_JACOBI_MODULE_H +#define EIGEN_JACOBI_MODULE_H + +#include "Core.h" + +#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 -r 000000000000 -r 13a5d365ba16 LU.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/LU.h Thu Oct 13 04:07:23 2016 +0000 @@ -0,0 +1,41 @@ +#ifndef EIGEN_LU_MODULE_H +#define EIGEN_LU_MODULE_H + +#include "Core.h" + +#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: */ \ No newline at end of file
diff -r 000000000000 -r 13a5d365ba16 QR.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/QR.h Thu Oct 13 04:07:23 2016 +0000 @@ -0,0 +1,45 @@ +#ifndef EIGEN_QR_MODULE_H +#define EIGEN_QR_MODULE_H + +#include "Core.h" + +#include "src/Core/util/DisableStupidWarnings.h" + +#include "Cholesky.h" +#include "Jacobi.h" +#include "Householder.h" + +/** \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: */ \ No newline at end of file
diff -r 000000000000 -r 13a5d365ba16 SVD.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/SVD.h Thu Oct 13 04:07:23 2016 +0000 @@ -0,0 +1,37 @@ +#ifndef EIGEN_SVD_MODULE_H +#define EIGEN_SVD_MODULE_H + +#include "QR.h" +#include "Householder.h" +#include "Jacobi.h" + +#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: */ \ No newline at end of file
diff -r 000000000000 -r 13a5d365ba16 src/Cholesky/LDLT.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/Cholesky/LDLT.h Thu Oct 13 04:07:23 2016 +0000 @@ -0,0 +1,611 @@ +// 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; + + // PositiveSemiDef means positive semi-definite and non-zero; same for NegativeSemiDef + enum SignMatrix { PositiveSemiDef, NegativeSemiDef, ZeroSign, Indefinite }; +} + +/** \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_sign(internal::ZeroSign), + 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_sign(internal::ZeroSign), + 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_sign(internal::ZeroSign), + 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 == internal::PositiveSemiDef || m_sign == internal::ZeroSign; + } + + #ifdef EIGEN2_SUPPORT + inline bool isPositiveDefinite() const + { + return isPositive(); + } + #endif + + /** \returns true if the matrix is negative (semidefinite) */ + inline bool isNegative(void) const + { + eigen_assert(m_isInitialized && "LDLT is not initialized."); + return m_sign == internal::NegativeSemiDef || m_sign == internal::ZeroSign; + } + + /** \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, const 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: + + static void check_template_parameters() + { + EIGEN_STATIC_ASSERT_NON_INTEGER(Scalar); + } + + /** \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; + internal::SignMatrix 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, SignMatrix& sign) + { + using std::abs; + 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 (numext::real(mat.coeff(0,0)) > 0) sign = PositiveSemiDef; + else if (numext::real(mat.coeff(0,0)) < 0) sign = NegativeSemiDef; + else sign = ZeroSign; + return true; + } + + for (Index k = 0; k < size; ++k) + { + // Find largest diagonal element + Index index_of_biggest_in_corner; + mat.diagonal().tail(size-k).cwiseAbs().maxCoeff(&index_of_biggest_in_corner); + index_of_biggest_in_corner += k; + + transpositions.coeffRef(k) = index_of_biggest_in_corner; + 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) = numext::conj(mat.coeffRef(index_of_biggest_in_corner,i)); + mat.coeffRef(index_of_biggest_in_corner,i) = numext::conj(tmp); + } + if(NumTraits<Scalar>::IsComplex) + mat.coeffRef(index_of_biggest_in_corner,k) = numext::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().real().head(k).asDiagonal() * A10.adjoint(); + mat.coeffRef(k,k) -= (A10 * temp.head(k)).value(); + if(rs>0) + A21.noalias() -= A20 * temp.head(k); + } + + // In some previous versions of Eigen (e.g., 3.2.1), the scaling was omitted if the pivot + // was smaller than the cutoff value. However, soince LDLT is not rank-revealing + // we should only make sure we do not introduce INF or NaN values. + // LAPACK also uses 0 as the cutoff value. + RealScalar realAkk = numext::real(mat.coeffRef(k,k)); + if((rs>0) && (abs(realAkk) > RealScalar(0))) + A21 /= realAkk; + + if (sign == PositiveSemiDef) { + if (realAkk < 0) sign = Indefinite; + } else if (sign == NegativeSemiDef) { + if (realAkk > 0) sign = Indefinite; + } else if (sign == ZeroSign) { + if (realAkk > 0) sign = PositiveSemiDef; + else if (realAkk < 0) sign = NegativeSemiDef; + } + } + + 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, const typename MatrixType::RealScalar& sigma=1) + { + using numext::isfinite; + typedef typename MatrixType::Scalar Scalar; + typedef typename MatrixType::RealScalar RealScalar; + typedef typename MatrixType::Index Index; + + const Index size = mat.rows(); + eigen_assert(mat.cols() == size && w.size()==size); + + 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 = numext::real(mat.coeff(j,j)); + Scalar wj = w.coeff(j); + RealScalar swj2 = sigma*numext::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*numext::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, const 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, SignMatrix& sign) + { + 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, const 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) +{ + check_template_parameters(); + + 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); + m_sign = internal::ZeroSign; + + 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, const typename LDLT<MatrixType,_UpLo>::RealScalar& 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 ? internal::PositiveSemiDef : internal::NegativeSemiDef; + 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::RealScalar RealScalar; + const typename Diagonal<const MatrixType>::RealReturnType vectorD(dec().vectorD()); + // In some previous versions, tolerance was set to the max of 1/highest and the maximal diagonal entry * epsilon + // as motivated by LAPACK's xGELSS: + // RealScalar tolerance = (max)(vectorD.array().abs().maxCoeff() *NumTraits<RealScalar>::epsilon(),RealScalar(1) / NumTraits<RealScalar>::highest()); + // However, LDLT is not rank revealing, and so adjusting the tolerance wrt to the highest + // diagonal element is not well justified and to numerical issues in some cases. + // Moreover, Lapack's xSYTRS routines use 0 for the tolerance. + RealScalar tolerance = RealScalar(1) / NumTraits<RealScalar>::highest(); + + 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."); + eigen_assert(m_matrix.rows() == 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().real().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 \ No newline at end of file
diff -r 000000000000 -r 13a5d365ba16 src/Cholesky/LLT.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/Cholesky/LLT.h Thu Oct 13 04:07:23 2016 +0000 @@ -0,0 +1,498 @@ +// 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: + + static void check_template_parameters() + { + EIGEN_STATIC_ASSERT_NON_INTEGER(Scalar); + } + + /** \internal + * Used to compute and store L + * The strict upper part is not used and even not initialized. + */ + MatrixType m_matrix; + 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) +{ + using std::sqrt; + typedef typename MatrixType::Scalar Scalar; + typedef typename MatrixType::RealScalar RealScalar; + typedef typename MatrixType::Index Index; + typedef typename MatrixType::ColXpr ColXpr; + typedef typename internal::remove_all<ColXpr>::type ColXprCleaned; + typedef typename ColXprCleaned::SegmentReturnType ColXprSegment; + typedef Matrix<Scalar,Dynamic,1> TempVectorType; + typedef typename TempVectorType::SegmentReturnType TempVecSegment; + + Index 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(Index i=0; i<n; ++i) + { + JacobiRotation<Scalar> g; + g.makeGivens(mat(i,i), -temp(i), &mat(i,i)); + + Index 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(Index j=0; j<n; ++j) + { + RealScalar Ljj = numext::real(mat.coeff(j,j)); + RealScalar dj = numext::abs2(Ljj); + Scalar wj = temp.coeff(j); + RealScalar swj2 = sigma*numext::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*numext::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) + { + using std::sqrt; + typedef typename MatrixType::Index Index; + + eigen_assert(mat.rows()==mat.cols()); + const Index size = mat.rows(); + for(Index k = 0; k < size; ++k) + { + 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 = numext::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 /= 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) +{ + check_template_parameters(); + + 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 \ No newline at end of file
diff -r 000000000000 -r 13a5d365ba16 src/Cholesky/LLT_MKL.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/Cholesky/LLT_MKL.h Thu Oct 13 04:07:23 2016 +0000 @@ -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) ? -1 : info>0 ? info-1 : size; \ + 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 \ No newline at end of file
diff -r 000000000000 -r 13a5d365ba16 src/Core/Array.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/Core/Array.h Thu Oct 13 04:07:23 2016 +0000 @@ -0,0 +1,323 @@ +// 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 Array() : Base() + { + Base::_check_template_params(); + EIGEN_INITIALIZE_COEFFS_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_COEFFS_IF_THAT_OPTION_IS_ENABLED + } +#endif + +#ifdef EIGEN_HAVE_RVALUE_REFERENCES + Array(Array&& other) + : Base(std::move(other)) + { + Base::_check_template_params(); + if (RowsAtCompileTime!=Dynamic && ColsAtCompileTime!=Dynamic) + Base::_set_noalias(other); + } + Array& operator=(Array&& other) + { + other.swap(*this); + return *this; + } +#endif + + /** Constructs a vector or row-vector with given dimension. \only_for_vectors + * + * Note that this is only useful for dynamic-size vectors. For fixed-size vectors, + * it is redundant to pass the dimension here, so it makes more sense to use the default + * constructor Matrix() instead. + */ + EIGEN_STRONG_INLINE explicit Array(Index dim) + : Base(dim, RowsAtCompileTime == 1 ? 1 : dim, ColsAtCompileTime == 1 ? 1 : dim) + { + Base::_check_template_params(); + EIGEN_STATIC_ASSERT_VECTOR_ONLY(Array) + eigen_assert(dim >= 0); + eigen_assert(SizeAtCompileTime == Dynamic || SizeAtCompileTime == dim); + EIGEN_INITIALIZE_COEFFS_IF_THAT_OPTION_IS_ENABLED + } + + #ifndef EIGEN_PARSED_BY_DOXYGEN + template<typename T0, typename T1> + EIGEN_STRONG_INLINE Array(const T0& val0, const T1& val1) + { + Base::_check_template_params(); + this->template _init2<T0,T1>(val0, val1); + } + #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& val0, const Scalar& val1); + #endif + + /** constructs an initialized 3D vector with given coefficients */ + EIGEN_STRONG_INLINE Array(const Scalar& val0, const Scalar& val1, const Scalar& val2) + { + Base::_check_template_params(); + EIGEN_STATIC_ASSERT_VECTOR_SPECIFIC_SIZE(Array, 3) + m_storage.data()[0] = val0; + m_storage.data()[1] = val1; + m_storage.data()[2] = val2; + } + /** constructs an initialized 4D vector with given coefficients */ + EIGEN_STRONG_INLINE Array(const Scalar& val0, const Scalar& val1, const Scalar& val2, const Scalar& val3) + { + Base::_check_template_params(); + EIGEN_STATIC_ASSERT_VECTOR_SPECIFIC_SIZE(Array, 4) + m_storage.data()[0] = val0; + m_storage.data()[1] = val1; + m_storage.data()[2] = val2; + m_storage.data()[3] = val3; + } + + 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_to_match(other); + *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 \ No newline at end of file
diff -r 000000000000 -r 13a5d365ba16 src/Core/ArrayBase.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/Core/ArrayBase.h Thu Oct 13 04:07:23 2016 +0000 @@ -0,0 +1,226 @@ +// 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; + + 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::operator*; + 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 Eigen::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 \ No newline at end of file
diff -r 000000000000 -r 13a5d365ba16 src/Core/ArrayWrapper.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/Core/ArrayWrapper.h Thu Oct 13 04:07:23 2016 +0000 @@ -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_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; + // Let's remove NestByRefBit + enum { + Flags0 = traits<typename remove_all<typename ExpressionType::Nested>::type >::Flags, + Flags = Flags0 & ~NestByRefBit + }; +}; +} + +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.const_cast_derived().data(); } + inline const Scalar* data() const { return m_expression.data(); } + + inline CoeffReturnType coeff(Index rowId, Index colId) const + { + return m_expression.coeff(rowId, colId); + } + + inline Scalar& coeffRef(Index rowId, Index colId) + { + return m_expression.const_cast_derived().coeffRef(rowId, colId); + } + + inline const Scalar& coeffRef(Index rowId, Index colId) const + { + return m_expression.const_cast_derived().coeffRef(rowId, colId); + } + + inline CoeffReturnType coeff(Index index) const + { + return m_expression.coeff(index); + } + + inline Scalar& coeffRef(Index index) + { + return m_expression.const_cast_derived().coeffRef(index); + } + + inline const Scalar& coeffRef(Index index) const + { + return m_expression.const_cast_derived().coeffRef(index); + } + + template<int LoadMode> + inline const PacketScalar packet(Index rowId, Index colId) const + { + return m_expression.template packet<LoadMode>(rowId, colId); + } + + template<int LoadMode> + inline void writePacket(Index rowId, Index colId, const PacketScalar& val) + { + m_expression.const_cast_derived().template writePacket<LoadMode>(rowId, colId, val); + } + + 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& val) + { + m_expression.const_cast_derived().template writePacket<LoadMode>(index, val); + } + + template<typename Dest> + inline void evalTo(Dest& dst) const { dst = m_expression; } + + const typename internal::remove_all<NestedExpressionType>::type& + nestedExpression() const + { + return m_expression; + } + + /** Forwards the resizing request to the nested expression + * \sa DenseBase::resize(Index) */ + void resize(Index newSize) { m_expression.const_cast_derived().resize(newSize); } + /** Forwards the resizing request to the nested expression + * \sa DenseBase::resize(Index,Index)*/ + void resize(Index nbRows, Index nbCols) { m_expression.const_cast_derived().resize(nbRows,nbCols); } + + 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; + // Let's remove NestByRefBit + enum { + Flags0 = traits<typename remove_all<typename ExpressionType::Nested>::type >::Flags, + Flags = Flags0 & ~NestByRefBit + }; +}; +} + +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& a_matrix) : m_expression(a_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.const_cast_derived().data(); } + inline const Scalar* data() const { return m_expression.data(); } + + inline CoeffReturnType coeff(Index rowId, Index colId) const + { + return m_expression.coeff(rowId, colId); + } + + inline Scalar& coeffRef(Index rowId, Index colId) + { + return m_expression.const_cast_derived().coeffRef(rowId, colId); + } + + inline const Scalar& coeffRef(Index rowId, Index colId) const + { + return m_expression.derived().coeffRef(rowId, colId); + } + + inline CoeffReturnType coeff(Index index) const + { + return m_expression.coeff(index); + } + + inline Scalar& coeffRef(Index index) + { + return m_expression.const_cast_derived().coeffRef(index); + } + + inline const Scalar& coeffRef(Index index) const + { + return m_expression.const_cast_derived().coeffRef(index); + } + + template<int LoadMode> + inline const PacketScalar packet(Index rowId, Index colId) const + { + return m_expression.template packet<LoadMode>(rowId, colId); + } + + template<int LoadMode> + inline void writePacket(Index rowId, Index colId, const PacketScalar& val) + { + m_expression.const_cast_derived().template writePacket<LoadMode>(rowId, colId, val); + } + + 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& val) + { + m_expression.const_cast_derived().template writePacket<LoadMode>(index, val); + } + + const typename internal::remove_all<NestedExpressionType>::type& + nestedExpression() const + { + return m_expression; + } + + /** Forwards the resizing request to the nested expression + * \sa DenseBase::resize(Index) */ + void resize(Index newSize) { m_expression.const_cast_derived().resize(newSize); } + /** Forwards the resizing request to the nested expression + * \sa DenseBase::resize(Index,Index)*/ + void resize(Index nbRows, Index nbCols) { m_expression.const_cast_derived().resize(nbRows,nbCols); } + + protected: + NestedExpressionType m_expression; +}; + +} // end namespace Eigen + +#endif // EIGEN_ARRAYWRAPPER_H \ No newline at end of file
diff -r 000000000000 -r 13a5d365ba16 src/Core/Assign.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/Core/Assign.h Thu Oct 13 04:07:23 2016 +0000 @@ -0,0 +1,590 @@ +// 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, typename Derived1::Index 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 &, typename Derived1::Index) {} +}; + +/*********************** +*** 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, typename Derived1::Index 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 &, typename Derived1::Index) {} +}; + +/*************************************************************************** +* 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 typename Derived1::Scalar Scalar; + typedef packet_traits<Scalar> PacketTraits; + enum { + packetSize = PacketTraits::size, + alignable = PacketTraits::AlignedOnScalar, + dstIsAligned = assign_traits<Derived1,Derived2>::DstIsAligned, + dstAlignment = alignable ? Aligned : int(dstIsAligned), + srcAlignment = assign_traits<Derived1,Derived2>::JointAlignment + }; + const Scalar *dst_ptr = &dst.coeffRef(0,0); + if((!bool(dstIsAligned)) && (size_t(dst_ptr) % sizeof(Scalar))>0) + { + // the pointer is not aligend-on scalar, so alignment is not possible + return assign_impl<Derived1,Derived2,DefaultTraversal,NoUnrolling>::run(dst, src); + } + const Index packetAlignedMask = packetSize - 1; + const Index innerSize = dst.innerSize(); + const Index outerSize = dst.outerSize(); + const Index alignedStep = alignable ? (packetSize - dst.outerStride() % packetSize) & packetAlignedMask : 0; + Index alignedStart = ((!alignable) || bool(dstIsAligned)) ? 0 : internal::first_aligned(dst_ptr, innerSize); + + for(Index outer = 0; outer < outerSize; ++outer) + { + const Index alignedEnd = alignedStart + ((innerSize-alignedStart) & ~packetAlignedMask); + // do the non-vectorizable part of the assignment + for(Index inner = 0; inner<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(internal::traits<OtherDerived>::Flags) & EvalBeforeAssigningBit) != 0, + bool NeedToTranspose = ((int(Derived::RowsAtCompileTime) == 1 && int(OtherDerived::ColsAtCompileTime) == 1) + | // FIXME | instead of || to please GCC 4.4.0 stupid warning "suggest parentheses around &&". + // revert to || as soon as not needed anymore. + (int(Derived::ColsAtCompileTime) == 1 && int(OtherDerived::RowsAtCompileTime) == 1)) + && int(Derived::SizeAtCompileTime) != 1> +struct assign_selector; + +template<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 ActualDerived, typename ActualOtherDerived> + static EIGEN_STRONG_INLINE Derived& evalTo(ActualDerived& dst, const ActualOtherDerived& other) { other.evalTo(dst); return dst; } +}; +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 ActualDerived, typename ActualOtherDerived> + static EIGEN_STRONG_INLINE Derived& evalTo(ActualDerived& dst, const ActualOtherDerived& other) { Transpose<ActualDerived> dstTrans(dst); other.evalTo(dstTrans); return dst; } +}; +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) +{ + return internal::assign_selector<Derived,OtherDerived,false>::evalTo(derived(), other.derived()); +} + +template<typename Derived> +template<typename OtherDerived> +EIGEN_STRONG_INLINE Derived& MatrixBase<Derived>::operator=(const ReturnByValue<OtherDerived>& other) +{ + return internal::assign_selector<Derived,OtherDerived,false>::evalTo(derived(), other.derived()); +} + +} // end namespace Eigen + +#endif // EIGEN_ASSIGN_H \ No newline at end of file
diff -r 000000000000 -r 13a5d365ba16 src/Core/Assign_MKL.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/Core/Assign_MKL.h Thu Oct 13 04:07:23 2016 +0000 @@ -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. +#ifndef _WIN32 +EIGEN_MKL_VML_DECLARE_POW_CALL(pow, vmspowx_, float, float) +EIGEN_MKL_VML_DECLARE_POW_CALL(pow, vmdpowx_, double, double) +EIGEN_MKL_VML_DECLARE_POW_CALL(pow, vmcpowx_, scomplex, MKL_Complex8) +EIGEN_MKL_VML_DECLARE_POW_CALL(pow, vmzpowx_, dcomplex, MKL_Complex16) +#endif + +} // end namespace internal + +} // end namespace Eigen + +#endif // EIGEN_ASSIGN_VML_H \ No newline at end of file
diff -r 000000000000 -r 13a5d365ba16 src/Core/BandMatrix.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/Core/BandMatrix.h Thu Oct 13 04:07:23 2016 +0000 @@ -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 \ No newline at end of file
diff -r 000000000000 -r 13a5d365ba16 src/Core/Block.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/Core/Block.h Thu Oct 13 04:07:23 2016 +0000 @@ -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-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) + * + * 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> +struct traits<Block<XprType, BlockRows, BlockCols, InnerPanel> > : 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, + IsDense = is_same<StorageKind,Dense>::value, + IsRowMajor = (IsDense&&MaxRowsAtCompileTime==1&&MaxColsAtCompileTime!=1) ? 1 + : (IsDense&&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 || (InnerPanel && (traits<XprType>::Flags&LinearAccessBit))) ? 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=Dynamic, int BlockCols=Dynamic, bool InnerPanel = false, + bool HasDirectAccess = internal::has_direct_access<XprType>::ret> class BlockImpl_dense; + +} // end namespace internal + +template<typename XprType, int BlockRows, int BlockCols, bool InnerPanel, typename StorageKind> class BlockImpl; + +template<typename XprType, int BlockRows, int BlockCols, bool InnerPanel> class Block + : public BlockImpl<XprType, BlockRows, BlockCols, InnerPanel, typename internal::traits<XprType>::StorageKind> +{ + typedef BlockImpl<XprType, BlockRows, BlockCols, InnerPanel, typename internal::traits<XprType>::StorageKind> Impl; + public: + //typedef typename Impl::Base Base; + typedef Impl Base; + EIGEN_GENERIC_PUBLIC_INTERFACE(Block) + EIGEN_INHERIT_ASSIGNMENT_OPERATORS(Block) + + /** Column or Row constructor + */ + inline Block(XprType& xpr, Index i) : Impl(xpr,i) + { + 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 a_startRow, Index a_startCol) + : Impl(xpr, a_startRow, a_startCol) + { + EIGEN_STATIC_ASSERT(RowsAtCompileTime!=Dynamic && ColsAtCompileTime!=Dynamic,THIS_METHOD_IS_ONLY_FOR_FIXED_SIZE) + eigen_assert(a_startRow >= 0 && BlockRows >= 1 && a_startRow + BlockRows <= xpr.rows() + && a_startCol >= 0 && BlockCols >= 1 && a_startCol + BlockCols <= xpr.cols()); + } + + /** Dynamic-size constructor + */ + inline Block(XprType& xpr, + Index a_startRow, Index a_startCol, + Index blockRows, Index blockCols) + : Impl(xpr, a_startRow, a_startCol, blockRows, blockCols) + { + eigen_assert((RowsAtCompileTime==Dynamic || RowsAtCompileTime==blockRows) + && (ColsAtCompileTime==Dynamic || ColsAtCompileTime==blockCols)); + eigen_assert(a_startRow >= 0 && blockRows >= 0 && a_startRow <= xpr.rows() - blockRows + && a_startCol >= 0 && blockCols >= 0 && a_startCol <= xpr.cols() - blockCols); + } +}; + +// The generic default implementation for dense block simplu forward to the internal::BlockImpl_dense +// that must be specialized for direct and non-direct access... +template<typename XprType, int BlockRows, int BlockCols, bool InnerPanel> +class BlockImpl<XprType, BlockRows, BlockCols, InnerPanel, Dense> + : public internal::BlockImpl_dense<XprType, BlockRows, BlockCols, InnerPanel> +{ + typedef internal::BlockImpl_dense<XprType, BlockRows, BlockCols, InnerPanel> Impl; + typedef typename XprType::Index Index; + public: + typedef Impl Base; + EIGEN_INHERIT_ASSIGNMENT_OPERATORS(BlockImpl) + inline BlockImpl(XprType& xpr, Index i) : Impl(xpr,i) {} + inline BlockImpl(XprType& xpr, Index a_startRow, Index a_startCol) : Impl(xpr, a_startRow, a_startCol) {} + inline BlockImpl(XprType& xpr, Index a_startRow, Index a_startCol, Index blockRows, Index blockCols) + : Impl(xpr, a_startRow, a_startCol, blockRows, blockCols) {} +}; + +namespace internal { + +/** \internal Internal implementation of dense Blocks in the general case. */ +template<typename XprType, int BlockRows, int BlockCols, bool InnerPanel, bool HasDirectAccess> class BlockImpl_dense + : public internal::dense_xpr_base<Block<XprType, BlockRows, BlockCols, InnerPanel> >::type +{ + typedef Block<XprType, BlockRows, BlockCols, InnerPanel> BlockType; + public: + + typedef typename internal::dense_xpr_base<BlockType>::type Base; + EIGEN_DENSE_PUBLIC_INTERFACE(BlockType) + EIGEN_INHERIT_ASSIGNMENT_OPERATORS(BlockImpl_dense) + + class InnerIterator; + + /** Column or Row constructor + */ + inline BlockImpl_dense(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()) + {} + + /** Fixed-size constructor + */ + inline BlockImpl_dense(XprType& xpr, Index a_startRow, Index a_startCol) + : m_xpr(xpr), m_startRow(a_startRow), m_startCol(a_startCol), + m_blockRows(BlockRows), m_blockCols(BlockCols) + {} + + /** Dynamic-size constructor + */ + inline BlockImpl_dense(XprType& xpr, + Index a_startRow, Index a_startCol, + Index blockRows, Index blockCols) + : m_xpr(xpr), m_startRow(a_startRow), m_startCol(a_startCol), + m_blockRows(blockRows), m_blockCols(blockCols) + {} + + inline Index rows() const { return m_blockRows.value(); } + inline Index cols() const { return m_blockCols.value(); } + + inline Scalar& coeffRef(Index rowId, Index colId) + { + EIGEN_STATIC_ASSERT_LVALUE(XprType) + return m_xpr.const_cast_derived() + .coeffRef(rowId + m_startRow.value(), colId + m_startCol.value()); + } + + inline const Scalar& coeffRef(Index rowId, Index colId) const + { + return m_xpr.derived() + .coeffRef(rowId + m_startRow.value(), colId + m_startCol.value()); + } + + EIGEN_STRONG_INLINE const CoeffReturnType coeff(Index rowId, Index colId) const + { + return m_xpr.coeff(rowId + m_startRow.value(), colId + 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 rowId, Index colId) const + { + return m_xpr.template packet<Unaligned> + (rowId + m_startRow.value(), colId + m_startCol.value()); + } + + template<int LoadMode> + inline void writePacket(Index rowId, Index colId, const PacketScalar& val) + { + m_xpr.const_cast_derived().template writePacket<Unaligned> + (rowId + m_startRow.value(), colId + m_startCol.value(), val); + } + + 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& val) + { + m_xpr.const_cast_derived().template writePacket<Unaligned> + (m_startRow.value() + (RowsAtCompileTime == 1 ? 0 : index), + m_startCol.value() + (RowsAtCompileTime == 1 ? index : 0), val); + } + + #ifdef EIGEN_PARSED_BY_DOXYGEN + /** \sa MapBase::data() */ + inline const Scalar* data() const; + inline Index innerStride() const; + inline Index outerStride() const; + #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 Internal implementation of dense Blocks in the direct access case.*/ +template<typename XprType, int BlockRows, int BlockCols, bool InnerPanel> +class BlockImpl_dense<XprType,BlockRows,BlockCols, InnerPanel,true> + : public MapBase<Block<XprType, BlockRows, BlockCols, InnerPanel> > +{ + typedef Block<XprType, BlockRows, BlockCols, InnerPanel> BlockType; + public: + + typedef MapBase<BlockType> Base; + EIGEN_DENSE_PUBLIC_INTERFACE(BlockType) + EIGEN_INHERIT_ASSIGNMENT_OPERATORS(BlockImpl_dense) + + /** Column or Row constructor + */ + inline BlockImpl_dense(XprType& xpr, Index i) + : Base(internal::const_cast_ptr(&xpr.coeffRef( + (BlockRows==1) && (BlockCols==XprType::ColsAtCompileTime) ? i : 0, + (BlockRows==XprType::RowsAtCompileTime) && (BlockCols==1) ? i : 0)), + BlockRows==1 ? 1 : xpr.rows(), + BlockCols==1 ? 1 : xpr.cols()), + m_xpr(xpr) + { + init(); + } + + /** Fixed-size constructor + */ + inline BlockImpl_dense(XprType& xpr, Index startRow, Index startCol) + : Base(internal::const_cast_ptr(&xpr.coeffRef(startRow,startCol))), m_xpr(xpr) + { + init(); + } + + /** Dynamic-size constructor + */ + inline BlockImpl_dense(XprType& xpr, + Index startRow, Index startCol, + Index blockRows, Index blockCols) + : Base(internal::const_cast_ptr(&xpr.coeffRef(startRow,startCol)), blockRows, blockCols), + m_xpr(xpr) + { + 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<BlockType>::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 BlockImpl_dense(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<BlockType>::HasSameStorageOrderAsXprType + ? m_xpr.outerStride() + : m_xpr.innerStride(); + } + + typename XprType::Nested m_xpr; + Index m_outerStride; +}; + +} // end namespace internal + +} // end namespace Eigen + +#endif // EIGEN_BLOCK_H \ No newline at end of file
diff -r 000000000000 -r 13a5d365ba16 src/Core/BooleanRedux.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/Core/BooleanRedux.h Thu Oct 13 04:07:23 2016 +0000 @@ -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_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, 0> +{ + static inline bool run(const Derived &/*mat*/) { return true; } +}; + +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, 0> +{ + static inline bool run(const Derived & /*mat*/) { return false; } +}; + +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(); +} + +/** \returns true is \c *this contains at least one Not A Number (NaN). + * + * \sa allFinite() + */ +template<typename Derived> +inline bool DenseBase<Derived>::hasNaN() const +{ + return !((derived().array()==derived().array()).all()); +} + +/** \returns true if \c *this contains only finite numbers, i.e., no NaN and no +/-INF values. + * + * \sa hasNaN() + */ +template<typename Derived> +inline bool DenseBase<Derived>::allFinite() const +{ + return !((derived()-derived()).hasNaN()); +} + +} // end namespace Eigen + +#endif // EIGEN_ALLANDANY_H \ No newline at end of file
diff -r 000000000000 -r 13a5d365ba16 src/Core/CommaInitializer.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/Core/CommaInitializer.h Thu Oct 13 04:07:23 2016 +0000 @@ -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> +// 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; + } + + /* Copy/Move constructor which transfers ownership. This is crucial in + * absence of return value optimization to avoid assertions during destruction. */ + // FIXME in C++11 mode this could be replaced by a proper RValue constructor + inline CommaInitializer(const CommaInitializer& o) + : m_xpr(o.m_xpr), m_row(o.m_row), m_col(o.m_col), m_currentBlockRows(o.m_currentBlockRows) { + // Mark original object as finished. In absence of R-value references we need to const_cast: + const_cast<CommaInitializer&>(o).m_row = m_xpr.rows(); + const_cast<CommaInitializer&>(o).m_col = m_xpr.cols(); + const_cast<CommaInitializer&>(o).m_currentBlockRows = 0; + } + + /* 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(other.cols()==0 || other.rows()==0) + return *this; + 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 + * + * \note According the c++ standard, the argument expressions of this comma initializer are evaluated in arbitrary order. + * + * \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 \ No newline at end of file
diff -r 000000000000 -r 13a5d365ba16 src/Core/CoreIterators.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/Core/CoreIterators.h Thu Oct 13 04:07:23 2016 +0000 @@ -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 \ No newline at end of file
diff -r 000000000000 -r 13a5d365ba16 src/Core/CwiseBinaryOp.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/Core/CwiseBinaryOp.h Thu Oct 13 04:07:23 2016 +0000 @@ -0,0 +1,230 @@ +// 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), + Cost0 = EIGEN_ADD_COST(LhsCoeffReadCost,RhsCoeffReadCost), + CoeffReadCost = EIGEN_ADD_COST(Cost0,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_is_product_like<BINOP>::ret \ + ? int(internal::scalar_product_traits<LHS, RHS>::Defined) \ + : 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& aLhs, const Rhs& aRhs, const BinaryOp& func = BinaryOp()) + : m_lhs(aLhs), m_rhs(aRhs), 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(aLhs.rows() == aRhs.rows() && aLhs.cols() == aRhs.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 rowId, Index colId) const + { + return derived().functor()(derived().lhs().coeff(rowId, colId), + derived().rhs().coeff(rowId, colId)); + } + + template<int LoadMode> + EIGEN_STRONG_INLINE PacketScalar packet(Index rowId, Index colId) const + { + return derived().functor().packetOp(derived().lhs().template packet<LoadMode>(rowId, colId), + derived().rhs().template packet<LoadMode>(rowId, colId)); + } + + 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 \ No newline at end of file
diff -r 000000000000 -r 13a5d365ba16 src/Core/CwiseNullaryOp.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/Core/CwiseNullaryOp.h Thu Oct 13 04:07:23 2016 +0000 @@ -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 nbRows, Index nbCols, const NullaryOp& func = NullaryOp()) + : m_rows(nbRows), m_cols(nbCols), m_functor(func) + { + eigen_assert(nbRows >= 0 + && (RowsAtCompileTime == Dynamic || RowsAtCompileTime == nbRows) + && nbCols >= 0 + && (ColsAtCompileTime == Dynamic || ColsAtCompileTime == nbCols)); + } + + 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 rowId, Index colId) const + { + return m_functor(rowId, colId); + } + + template<int LoadMode> + EIGEN_STRONG_INLINE PacketScalar packet(Index rowId, Index colId) const + { + return m_functor.packetOp(rowId, colId); + } + + EIGEN_STRONG_INLINE const Scalar coeff(Index index) const + { + return m_functor(index); + } + + template<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 nbRows and \a nbCols are the number of rows and of columns of + * the returned matrix. Must be compatible with this DenseBase type. + * + * This variant is meant to be used for dynamic-size matrix types. For fixed-size types, + * it is redundant to pass \a nbRows and \a nbCols as arguments, so Zero() should be used + * 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 nbRows, Index nbCols, const Scalar& value) +{ + return DenseBase<Derived>::NullaryExpr(nbRows, nbCols, 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 val, to within precision \a prec */ +template<typename Derived> +bool DenseBase<Derived>::isApproxToConstant +(const Scalar& val, const RealScalar& prec) const +{ + for(Index j = 0; j < cols(); ++j) + for(Index i = 0; i < rows(); ++i) + if(!internal::isApprox(this->coeff(i, j), val, 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& val, const RealScalar& prec) const +{ + return isApproxToConstant(val, prec); +} + +/** Alias for setConstant(): sets all coefficients in this expression to \a val. + * + * \sa setConstant(), Constant(), class CwiseNullaryOp + */ +template<typename Derived> +EIGEN_STRONG_INLINE void DenseBase<Derived>::fill(const Scalar& val) +{ + setConstant(val); +} + +/** 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& val) +{ + return derived() = Constant(rows(), cols(), val); +} + +/** Resizes to the given \a size, and sets all coefficients in this expression to the given \a value. + * + * \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& val) +{ + resize(size); + return setConstant(val); +} + +/** Resizes to the given size, and sets all coefficients in this expression to the given \a value. + * + * \param nbRows the new number of rows + * \param nbCols the new number of columns + * \param val 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 nbRows, Index nbCols, const Scalar& val) +{ + resize(nbRows, nbCols); + return setConstant(val); +} + +/** + * \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 newSize, const Scalar& low, const Scalar& high) +{ + EIGEN_STATIC_ASSERT_VECTOR_ONLY(Derived) + return derived() = Derived::NullaryExpr(newSize, internal::linspaced_op<Scalar,false>(low,high,newSize)); +} + +/** + * \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 nbRows, Index nbCols) +{ + return Constant(nbRows, nbCols, 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(const 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 newSize) +{ + resize(newSize); + return setConstant(Scalar(0)); +} + +/** Resizes to the given size, and sets all coefficients in this expression to zero. + * + * \param nbRows the new number of rows + * \param nbCols the new number of columns + * + * 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 nbRows, Index nbCols) +{ + resize(nbRows, nbCols); + return setConstant(Scalar(0)); +} + +// ones: + +/** \returns an expression of a matrix where all coefficients equal one. + * + * The parameters \a nbRows and \a nbCols are the number of rows and of columns of + * the 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 nbRows, Index nbCols) +{ + return Constant(nbRows, nbCols, Scalar(1)); +} + +/** \returns an expression of a vector where all coefficients equal one. + * + * The parameter \a newSize 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 newSize) +{ + return Constant(newSize, 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 +(const 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 newSize, 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 newSize) +{ + resize(newSize); + return setConstant(Scalar(1)); +} + +/** Resizes to the given size, and sets all coefficients in this expression to one. + * + * \param nbRows the new number of rows + * \param nbCols the new number of columns + * + * 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 nbRows, Index nbCols) +{ + resize(nbRows, nbCols); + return setConstant(Scalar(1)); +} + +// Identity: + +/** \returns an expression of the identity matrix (not necessarily square). + * + * The parameters \a nbRows and \a nbCols are the number of rows and of columns of + * the 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 nbRows, Index nbCols) +{ + return DenseBase<Derived>::NullaryExpr(nbRows, nbCols, 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 +(const 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 nbRows the new number of rows + * \param nbCols 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 nbRows, Index nbCols) +{ + derived().resize(nbRows, nbCols); + 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 newSize, Index i) +{ + EIGEN_STATIC_ASSERT_VECTOR_ONLY(Derived) + return BasisReturnType(SquareMatrixType::Identity(newSize,newSize), 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 \ No newline at end of file
diff -r 000000000000 -r 13a5d365ba16 src/Core/CwiseUnaryOp.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/Core/CwiseUnaryOp.h Thu Oct 13 04:07:23 2016 +0000 @@ -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 = EIGEN_ADD_COST(_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 rowId, Index colId) const + { + return derived().functor()(derived().nestedExpression().coeff(rowId, colId)); + } + + template<int LoadMode> + EIGEN_STRONG_INLINE PacketScalar packet(Index rowId, Index colId) const + { + return derived().functor().packetOp(derived().nestedExpression().template packet<LoadMode>(rowId, colId)); + } + + 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 \ No newline at end of file
diff -r 000000000000 -r 13a5d365ba16 src/Core/CwiseUnaryView.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/Core/CwiseUnaryView.h Thu Oct 13 04:07:23 2016 +0000 @@ -0,0 +1,139 @@ +// 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 = EIGEN_ADD_COST(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 == Dynamic + ? int(Dynamic) + : outer_stride_at_compile_time<MatrixType>::ret * int(sizeof(typename traits<MatrixType>::Scalar) / sizeof(Scalar)) + }; +}; +} + +template<typename ViewOp, typename MatrixType, typename StorageKind> +class CwiseUnaryViewImpl; + +template<typename ViewOp, typename MatrixType> +class CwiseUnaryView : 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) + EIGEN_INHERIT_ASSIGNMENT_OPERATORS(CwiseUnaryViewImpl) + + inline Scalar* data() { return &coeffRef(0); } + inline const Scalar* data() const { return &coeff(0); } + + inline Index innerStride() const + { + return derived().nestedExpression().innerStride() * sizeof(typename internal::traits<MatrixType>::Scalar) / sizeof(Scalar); + } + + inline Index outerStride() const + { + return derived().nestedExpression().outerStride() * sizeof(typename internal::traits<MatrixType>::Scalar) / sizeof(Scalar); + } + + EIGEN_STRONG_INLINE CoeffReturnType coeff(Index row, Index col) const + { + return derived().functor()(derived().nestedExpression().coeff(row, col)); + } + + EIGEN_STRONG_INLINE CoeffReturnType coeff(Index index) const + { + return derived().functor()(derived().nestedExpression().coeff(index)); + } + + EIGEN_STRONG_INLINE Scalar& coeffRef(Index row, Index col) + { + return derived().functor()(const_cast_derived().nestedExpression().coeffRef(row, col)); + } + + EIGEN_STRONG_INLINE Scalar& coeffRef(Index index) + { + return derived().functor()(const_cast_derived().nestedExpression().coeffRef(index)); + } +}; + +} // end namespace Eigen + +#endif // EIGEN_CWISE_UNARY_VIEW_H \ No newline at end of file
diff -r 000000000000 -r 13a5d365ba16 src/Core/DenseBase.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/Core/DenseBase.h Thu Oct 13 04:07:23 2016 +0000 @@ -0,0 +1,521 @@ +// 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 { + +namespace internal { + +// The index type defined by EIGEN_DEFAULT_DENSE_INDEX_TYPE must be a signed type. +// This dummy function simply aims at checking that at compile time. +static inline void check_DenseIndex_is_signed() { + EIGEN_STATIC_ASSERT(NumTraits<DenseIndex>::IsSigned,THE_INDEX_TYPE_MUST_BE_A_SIGNED_TYPE); +} + +} // end namespace internal + +/** \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, + DenseCoeffsBase<Derived> > +#else + : public DenseCoeffsBase<Derived> +#endif // not EIGEN_PARSED_BY_DOXYGEN +{ + public: + + 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 internal::special_scalar_op_base<Derived,Scalar,RealScalar, DenseCoeffsBase<Derived> > Base; + + using Base::operator*; + 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 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 newSize) + { + EIGEN_ONLY_USED_FOR_DEBUG(newSize); + eigen_assert(newSize == 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 nbRows, Index nbCols) + { + EIGEN_ONLY_USED_FOR_DEBUG(nbRows); + EIGEN_ONLY_USED_FOR_DEBUG(nbCols); + eigen_assert(nbRows == this->rows() && nbCols == 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); + + /** \internal Copies \a other into *this without evaluating other. \returns a reference to *this. */ + template<typename OtherDerived> + Derived& lazyAssign(const DenseBase<OtherDerived>& other); + + /** \internal Evaluates \a other into *this. \returns a reference to *this. */ + template<typename OtherDerived> + Derived& lazyAssign(const ReturnByValue<OtherDerived>& other); + + 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 typename internal::add_const<Transpose<const Derived> >::type ConstTransposeReturnType; + ConstTransposeReturnType transpose() const; + void transposeInPlace(); +#ifndef EIGEN_NO_DEBUG + protected: + template<typename OtherDerived> + void checkTransposeAliasing(const OtherDerived& other) const; + public: +#endif + + + 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, + const RealScalar& prec = NumTraits<Scalar>::dummy_precision()) const; + bool isMuchSmallerThan(const RealScalar& other, + const RealScalar& prec = NumTraits<Scalar>::dummy_precision()) const; + template<typename OtherDerived> + bool isMuchSmallerThan(const DenseBase<OtherDerived>& other, + const RealScalar& prec = NumTraits<Scalar>::dummy_precision()) const; + + bool isApproxToConstant(const Scalar& value, const RealScalar& prec = NumTraits<Scalar>::dummy_precision()) const; + bool isConstant(const Scalar& value, const RealScalar& prec = NumTraits<Scalar>::dummy_precision()) const; + bool isZero(const RealScalar& prec = NumTraits<Scalar>::dummy_precision()) const; + bool isOnes(const RealScalar& prec = NumTraits<Scalar>::dummy_precision()) const; + + inline bool hasNaN() const; + inline bool allFinite() 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); + } + + 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, const typename ThenDerived::Scalar& elseScalar) const; + + template<typename ElseDerived> + inline const Select<Derived, typename ElseDerived::ConstantReturnType, ElseDerived > + select(const typename ElseDerived::Scalar& thenScalar, const DenseBase<ElseDerived>& elseMatrix) const; + + template<int p> RealScalar lpNorm() const; + + template<int RowFactor, int ColFactor> + inline const Replicate<Derived,RowFactor,ColFactor> replicate() const; + + typedef Replicate<Derived,Dynamic,Dynamic> ReplicateReturnType; + inline const ReplicateReturnType 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 \ No newline at end of file
diff -r 000000000000 -r 13a5d365ba16 src/Core/DenseCoeffsBase.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/Core/DenseCoeffsBase.h Thu Oct 13 04:07:23 2016 +0000 @@ -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& val) + { + eigen_internal_assert(row >= 0 && row < rows() + && col >= 0 && col < cols()); + derived().template writePacket<StoreMode>(row,col,val); + } + + + /** \internal */ + template<int StoreMode> + EIGEN_STRONG_INLINE void writePacketByOuterInner + (Index outer, Index inner, const typename internal::packet_traits<Scalar>::type& val) + { + writePacket<StoreMode>(rowIndexByOuterInner(outer, inner), + colIndexByOuterInner(outer, inner), + val); + } + + /** \internal + * Stores the given packet of coefficients, at the given index in this expression. It is your responsibility + * to ensure that a packet really starts there. This method is only available on expressions having the + * PacketAccessBit and the LinearAccessBit. + * + * The \a LoadMode parameter may have the value \a Aligned or \a Unaligned. Its effect is to select + * the appropriate vectorization instruction. Aligned access is faster, but is only possible for packets + * starting at an address which is a multiple of the packet size. + */ + template<int StoreMode> + EIGEN_STRONG_INLINE void writePacket + (Index index, const typename internal::packet_traits<Scalar>::type& val) + { + eigen_internal_assert(index >= 0 && index < size()); + derived().template writePacket<StoreMode>(index,val); + } + +#ifndef EIGEN_PARSED_BY_DOXYGEN + + /** \internal Copies the coefficient at position (row,col) of other into *this. + * + * This method is overridden in SwapWrapper, allowing swap() assignments to share 99% of their code + * with usual assignments. + * + * Outside of this internal usage, this method has probably no usefulness. It is hidden in the public API dox. + */ + + template<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 \ No newline at end of file
diff -r 000000000000 -r 13a5d365ba16 src/Core/DenseStorage.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/Core/DenseStorage.h Thu Oct 13 04:07:23 2016 +0000 @@ -0,0 +1,434 @@ +// 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 {}; + +template<typename T, int Size> void check_static_allocation_size() +{ + // if EIGEN_STACK_ALLOCATION_LIMIT is defined to 0, then no limit + #if EIGEN_STACK_ALLOCATION_LIMIT + EIGEN_STATIC_ASSERT(Size * sizeof(T) <= EIGEN_STACK_ALLOCATION_LIMIT, OBJECT_ALLOCATED_ON_STACK_IS_TOO_BIG); + #endif +} + +/** \internal + * Static array. If the MatrixOrArrayOptions require auto-alignment, the array will be automatically aligned: + * to 16 bytes boundary if the total size is a multiple of 16 bytes. + */ +template <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() + { + check_static_allocation_size<T,Size>(); + } + + plain_array(constructor_without_unaligned_array_assert) + { + check_static_allocation_size<T,Size>(); + } +}; + +#if defined(EIGEN_DISABLE_UNALIGNED_ARRAY_ASSERT) + #define EIGEN_MAKE_UNALIGNED_ARRAY_ASSERT(sizemask) +#elif EIGEN_GNUC_AT_LEAST(4,7) + // GCC 4.7 is too aggressive in its optimizations and remove the alignement test based on the fact the array is declared to be aligned. + // See this bug report: http://gcc.gnu.org/bugzilla/show_bug.cgi?id=53900 + // Hiding the origin of the array pointer behind a function argument seems to do the trick even if the function is inlined: + template<typename PtrType> + EIGEN_ALWAYS_INLINE PtrType eigen_unaligned_array_assert_workaround_gcc47(PtrType array) { return array; } + #define EIGEN_MAKE_UNALIGNED_ARRAY_ASSERT(sizemask) \ + eigen_assert((reinterpret_cast<size_t>(eigen_unaligned_array_assert_workaround_gcc47(array)) & sizemask) == 0 \ + && "this assertion is explained here: " \ + "http://eigen.tuxfamily.org/dox-devel/group__TopicUnalignedArrayAssert.html" \ + " **** READ THIS WEB PAGE !!! ****"); +#else + #define EIGEN_MAKE_UNALIGNED_ARRAY_ASSERT(sizemask) \ + eigen_assert((reinterpret_cast<size_t>(array) & sizemask) == 0 \ + && "this assertion is explained here: " \ + "http://eigen.tuxfamily.org/dox-devel/group__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); + check_static_allocation_size<T,Size>(); + } + + plain_array(constructor_without_unaligned_array_assert) + { + check_static_allocation_size<T,Size>(); + } +}; + +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: + DenseStorage() {} + DenseStorage(internal::constructor_without_unaligned_array_assert) + : m_data(internal::constructor_without_unaligned_array_assert()) {} + DenseStorage(const DenseStorage& other) : m_data(other.m_data) {} + DenseStorage& operator=(const DenseStorage& other) + { + if (this != &other) m_data = other.m_data; + return *this; + } + DenseStorage(DenseIndex,DenseIndex,DenseIndex) {} + void swap(DenseStorage& other) { std::swap(m_data,other.m_data); } + static DenseIndex rows(void) {return _Rows;} + static DenseIndex cols(void) {return _Cols;} + void conservativeResize(DenseIndex,DenseIndex,DenseIndex) {} + void resize(DenseIndex,DenseIndex,DenseIndex) {} + const T *data() const { return m_data.array; } + T *data() { return m_data.array; } +}; + +// null matrix +template<typename T, int _Rows, int _Cols, int _Options> class DenseStorage<T, 0, _Rows, _Cols, _Options> +{ + public: + DenseStorage() {} + DenseStorage(internal::constructor_without_unaligned_array_assert) {} + DenseStorage(const DenseStorage&) {} + DenseStorage& operator=(const DenseStorage&) { return *this; } + DenseStorage(DenseIndex,DenseIndex,DenseIndex) {} + void swap(DenseStorage& ) {} + static DenseIndex rows(void) {return _Rows;} + static DenseIndex cols(void) {return _Cols;} + void conservativeResize(DenseIndex,DenseIndex,DenseIndex) {} + void resize(DenseIndex,DenseIndex,DenseIndex) {} + const T *data() const { return 0; } + T *data() { return 0; } +}; + +// more specializations for null matrices; these are necessary to resolve ambiguities +template<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: + DenseStorage() : m_rows(0), m_cols(0) {} + DenseStorage(internal::constructor_without_unaligned_array_assert) + : m_data(internal::constructor_without_unaligned_array_assert()), m_rows(0), m_cols(0) {} + DenseStorage(const DenseStorage& other) : m_data(other.m_data), m_rows(other.m_rows), m_cols(other.m_cols) {} + DenseStorage& operator=(const DenseStorage& other) + { + if (this != &other) + { + m_data = other.m_data; + m_rows = other.m_rows; + m_cols = other.m_cols; + } + return *this; + } + DenseStorage(DenseIndex, DenseIndex nbRows, DenseIndex nbCols) : m_rows(nbRows), m_cols(nbCols) {} + void swap(DenseStorage& other) + { std::swap(m_data,other.m_data); std::swap(m_rows,other.m_rows); std::swap(m_cols,other.m_cols); } + DenseIndex rows() const {return m_rows;} + DenseIndex cols() const {return m_cols;} + void conservativeResize(DenseIndex, DenseIndex nbRows, DenseIndex nbCols) { m_rows = nbRows; m_cols = nbCols; } + void resize(DenseIndex, DenseIndex nbRows, DenseIndex nbCols) { m_rows = nbRows; m_cols = nbCols; } + const T *data() const { return m_data.array; } + T *data() { return m_data.array; } +}; + +// dynamic-size matrix with fixed-size storage and fixed width +template<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: + DenseStorage() : m_rows(0) {} + DenseStorage(internal::constructor_without_unaligned_array_assert) + : m_data(internal::constructor_without_unaligned_array_assert()), m_rows(0) {} + DenseStorage(const DenseStorage& other) : m_data(other.m_data), m_rows(other.m_rows) {} + DenseStorage& operator=(const DenseStorage& other) + { + if (this != &other) + { + m_data = other.m_data; + m_rows = other.m_rows; + } + return *this; + } + DenseStorage(DenseIndex, DenseIndex nbRows, DenseIndex) : m_rows(nbRows) {} + void swap(DenseStorage& other) { std::swap(m_data,other.m_data); std::swap(m_rows,other.m_rows); } + DenseIndex rows(void) const {return m_rows;} + DenseIndex cols(void) const {return _Cols;} + void conservativeResize(DenseIndex, DenseIndex nbRows, DenseIndex) { m_rows = nbRows; } + void resize(DenseIndex, DenseIndex nbRows, DenseIndex) { m_rows = nbRows; } + const T *data() const { return m_data.array; } + T *data() { return m_data.array; } +}; + +// dynamic-size matrix with fixed-size storage and fixed height +template<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: + DenseStorage() : m_cols(0) {} + DenseStorage(internal::constructor_without_unaligned_array_assert) + : m_data(internal::constructor_without_unaligned_array_assert()), m_cols(0) {} + DenseStorage(const DenseStorage& other) : m_data(other.m_data), m_cols(other.m_cols) {} + DenseStorage& operator=(const DenseStorage& other) + { + if (this != &other) + { + m_data = other.m_data; + m_cols = other.m_cols; + } + return *this; + } + DenseStorage(DenseIndex, DenseIndex, DenseIndex nbCols) : m_cols(nbCols) {} + void swap(DenseStorage& other) { std::swap(m_data,other.m_data); std::swap(m_cols,other.m_cols); } + DenseIndex rows(void) const {return _Rows;} + DenseIndex cols(void) const {return m_cols;} + void conservativeResize(DenseIndex, DenseIndex, DenseIndex nbCols) { m_cols = nbCols; } + void resize(DenseIndex, DenseIndex, DenseIndex nbCols) { m_cols = nbCols; } + const T *data() const { return m_data.array; } + T *data() { return m_data.array; } +}; + +// purely dynamic matrix. +template<typename T, int _Options> class DenseStorage<T, Dynamic, Dynamic, Dynamic, _Options> +{ + T *m_data; + DenseIndex m_rows; + DenseIndex m_cols; + public: + DenseStorage() : m_data(0), m_rows(0), m_cols(0) {} + DenseStorage(internal::constructor_without_unaligned_array_assert) + : m_data(0), m_rows(0), m_cols(0) {} + DenseStorage(DenseIndex size, DenseIndex nbRows, DenseIndex nbCols) + : m_data(internal::conditional_aligned_new_auto<T,(_Options&DontAlign)==0>(size)), m_rows(nbRows), m_cols(nbCols) + { EIGEN_INTERNAL_DENSE_STORAGE_CTOR_PLUGIN } +#ifdef EIGEN_HAVE_RVALUE_REFERENCES + DenseStorage(DenseStorage&& other) + : m_data(std::move(other.m_data)) + , m_rows(std::move(other.m_rows)) + , m_cols(std::move(other.m_cols)) + { + other.m_data = nullptr; + } + DenseStorage& operator=(DenseStorage&& other) + { + using std::swap; + swap(m_data, other.m_data); + swap(m_rows, other.m_rows); + swap(m_cols, other.m_cols); + return *this; + } +#endif + ~DenseStorage() { internal::conditional_aligned_delete_auto<T,(_Options&DontAlign)==0>(m_data, m_rows*m_cols); } + void swap(DenseStorage& other) + { std::swap(m_data,other.m_data); std::swap(m_rows,other.m_rows); std::swap(m_cols,other.m_cols); } + DenseIndex rows(void) const {return m_rows;} + DenseIndex cols(void) const {return m_cols;} + void conservativeResize(DenseIndex size, DenseIndex nbRows, DenseIndex nbCols) + { + m_data = internal::conditional_aligned_realloc_new_auto<T,(_Options&DontAlign)==0>(m_data, size, m_rows*m_cols); + m_rows = nbRows; + m_cols = nbCols; + } + void resize(DenseIndex size, DenseIndex nbRows, DenseIndex nbCols) + { + if(size != m_rows*m_cols) + { + internal::conditional_aligned_delete_auto<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 = nbRows; + m_cols = nbCols; + } + const T *data() const { return m_data; } + T *data() { return m_data; } + private: + DenseStorage(const DenseStorage&); + DenseStorage& operator=(const DenseStorage&); +}; + +// matrix with dynamic width and fixed height (so that matrix has dynamic size). +template<typename T, int _Rows, int _Options> class DenseStorage<T, Dynamic, _Rows, Dynamic, _Options> +{ + T *m_data; + DenseIndex m_cols; + public: + DenseStorage() : m_data(0), m_cols(0) {} + DenseStorage(internal::constructor_without_unaligned_array_assert) : m_data(0), m_cols(0) {} + DenseStorage(DenseIndex size, DenseIndex, DenseIndex nbCols) : m_data(internal::conditional_aligned_new_auto<T,(_Options&DontAlign)==0>(size)), m_cols(nbCols) + { EIGEN_INTERNAL_DENSE_STORAGE_CTOR_PLUGIN } +#ifdef EIGEN_HAVE_RVALUE_REFERENCES + DenseStorage(DenseStorage&& other) + : m_data(std::move(other.m_data)) + , m_cols(std::move(other.m_cols)) + { + other.m_data = nullptr; + } + DenseStorage& operator=(DenseStorage&& other) + { + using std::swap; + swap(m_data, other.m_data); + swap(m_cols, other.m_cols); + return *this; + } +#endif + ~DenseStorage() { internal::conditional_aligned_delete_auto<T,(_Options&DontAlign)==0>(m_data, _Rows*m_cols); } + void swap(DenseStorage& other) { std::swap(m_data,other.m_data); std::swap(m_cols,other.m_cols); } + static DenseIndex rows(void) {return _Rows;} + DenseIndex cols(void) const {return m_cols;} + void conservativeResize(DenseIndex size, DenseIndex, DenseIndex nbCols) + { + m_data = internal::conditional_aligned_realloc_new_auto<T,(_Options&DontAlign)==0>(m_data, size, _Rows*m_cols); + m_cols = nbCols; + } + EIGEN_STRONG_INLINE void resize(DenseIndex size, DenseIndex, DenseIndex nbCols) + { + if(size != _Rows*m_cols) + { + internal::conditional_aligned_delete_auto<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 = nbCols; + } + const T *data() const { return m_data; } + T *data() { return m_data; } + private: + DenseStorage(const DenseStorage&); + DenseStorage& operator=(const DenseStorage&); +}; + +// matrix with dynamic height and fixed width (so that matrix has dynamic size). +template<typename T, int _Cols, int _Options> class DenseStorage<T, Dynamic, Dynamic, _Cols, _Options> +{ + T *m_data; + DenseIndex m_rows; + public: + DenseStorage() : m_data(0), m_rows(0) {} + DenseStorage(internal::constructor_without_unaligned_array_assert) : m_data(0), m_rows(0) {} + DenseStorage(DenseIndex size, DenseIndex nbRows, DenseIndex) : m_data(internal::conditional_aligned_new_auto<T,(_Options&DontAlign)==0>(size)), m_rows(nbRows) + { EIGEN_INTERNAL_DENSE_STORAGE_CTOR_PLUGIN } +#ifdef EIGEN_HAVE_RVALUE_REFERENCES + DenseStorage(DenseStorage&& other) + : m_data(std::move(other.m_data)) + , m_rows(std::move(other.m_rows)) + { + other.m_data = nullptr; + } + DenseStorage& operator=(DenseStorage&& other) + { + using std::swap; + swap(m_data, other.m_data); + swap(m_rows, other.m_rows); + return *this; + } +#endif + ~DenseStorage() { internal::conditional_aligned_delete_auto<T,(_Options&DontAlign)==0>(m_data, _Cols*m_rows); } + void swap(DenseStorage& other) { std::swap(m_data,other.m_data); std::swap(m_rows,other.m_rows); } + DenseIndex rows(void) const {return m_rows;} + static DenseIndex cols(void) {return _Cols;} + void conservativeResize(DenseIndex size, DenseIndex nbRows, DenseIndex) + { + m_data = internal::conditional_aligned_realloc_new_auto<T,(_Options&DontAlign)==0>(m_data, size, m_rows*_Cols); + m_rows = nbRows; + } + EIGEN_STRONG_INLINE void resize(DenseIndex size, DenseIndex nbRows, DenseIndex) + { + if(size != m_rows*_Cols) + { + internal::conditional_aligned_delete_auto<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 = nbRows; + } + const T *data() const { return m_data; } + T *data() { return m_data; } + private: + DenseStorage(const DenseStorage&); + DenseStorage& operator=(const DenseStorage&); +}; + +} // end namespace Eigen + +#endif // EIGEN_MATRIX_H \ No newline at end of file
diff -r 000000000000 -r 13a5d365ba16 src/Core/Diagonal.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/Core/Diagonal.h Thu Oct 13 04:07:23 2016 +0000 @@ -0,0 +1,237 @@ +// 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) == DynamicIndex || 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 == DynamicIndex ? 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: + + enum { DiagIndex = _DiagIndex }; + typedef typename internal::dense_xpr_base<Diagonal>::type Base; + EIGEN_DENSE_PUBLIC_INTERFACE(Diagonal) + + inline Diagonal(MatrixType& matrix, Index a_index = DiagIndex) : m_matrix(matrix), m_index(a_index) {} + + EIGEN_INHERIT_ASSIGNMENT_OPERATORS(Diagonal) + + inline Index rows() const + { return m_index.value()<0 ? (std::min<Index>)(m_matrix.cols(),m_matrix.rows()+m_index.value()) : (std::min<Index>)(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 idx) + { + EIGEN_STATIC_ASSERT_LVALUE(MatrixType) + return m_matrix.const_cast_derived().coeffRef(idx+rowOffset(), idx+colOffset()); + } + + inline const Scalar& coeffRef(Index idx) const + { + return m_matrix.const_cast_derived().coeffRef(idx+rowOffset(), idx+colOffset()); + } + + inline CoeffReturnType coeff(Index idx) const + { + return m_matrix.coeff(idx+rowOffset(), idx+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_dynamicindex<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 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>::DiagonalDynamicIndexReturnType +MatrixBase<Derived>::diagonal(Index index) +{ + return DiagonalDynamicIndexReturnType(derived(), index); +} + +/** This is the const version of diagonal(Index). */ +template<typename Derived> +inline typename MatrixBase<Derived>::ConstDiagonalDynamicIndexReturnType +MatrixBase<Derived>::diagonal(Index index) const +{ + return ConstDiagonalDynamicIndexReturnType(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 \ No newline at end of file
diff -r 000000000000 -r 13a5d365ba16 src/Core/DiagonalMatrix.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/Core/DiagonalMatrix.h Thu Oct 13 04:07:23 2016 +0000 @@ -0,0 +1,313 @@ +// 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 DiagonalVectorType::RealScalar RealScalar; + 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(); } + + /** \returns the diagonal matrix product of \c *this by the matrix \a matrix. + */ + template<typename MatrixDerived> + const DiagonalProduct<MatrixDerived, Derived, OnTheLeft> + operator*(const MatrixBase<MatrixDerived> &matrix) const + { + return DiagonalProduct<MatrixDerived, Derived, OnTheLeft>(matrix.derived(), derived()); + } + + inline const DiagonalWrapper<const CwiseUnaryOp<internal::scalar_inverse_op<Scalar>, const DiagonalVectorType> > + inverse() const + { + return diagonal().cwiseInverse(); + } + + inline const DiagonalWrapper<const CwiseUnaryOp<internal::scalar_multiple_op<Scalar>, const DiagonalVectorType> > + operator*(const Scalar& scalar) const + { + return diagonal() * scalar; + } + friend inline const DiagonalWrapper<const CwiseUnaryOp<internal::scalar_multiple_op<Scalar>, const DiagonalVectorType> > + operator*(const Scalar& scalar, const DiagonalBase& other) + { + return other.diagonal() * scalar; + } + + #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& a_diagonal) : m_diagonal(a_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(const RealScalar& prec) const +{ + using std::abs; + if(cols() != rows()) return false; + RealScalar maxAbsOnDiagonal = static_cast<RealScalar>(-1); + for(Index j = 0; j < cols(); ++j) + { + RealScalar absOnDiagonal = 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 \ No newline at end of file
diff -r 000000000000 -r 13a5d365ba16 src/Core/DiagonalProduct.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/Core/DiagonalProduct.h Thu Oct 13 04:07:23 2016 +0000 @@ -0,0 +1,131 @@ +// 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, + _ScalarAccessOnDiag = !((int(_StorageOrder) == ColMajor && int(ProductOrder) == OnTheLeft) + ||(int(_StorageOrder) == RowMajor && 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::DiagonalVectorType::Flags)&PacketAccessBit))), + _Vectorizable = bool(int(MatrixType::Flags)&PacketAccessBit) && _SameTypes && (_ScalarAccessOnDiag || (bool(int(DiagonalType::DiagonalVectorType::Flags)&PacketAccessBit))), + _LinearAccessMask = (RowsAtCompileTime==1 || ColsAtCompileTime==1) ? LinearAccessBit : 0, + + Flags = ((HereditaryBits|_LinearAccessMask|AlignedBit) & (unsigned int)(MatrixType::Flags)) | (_Vectorizable ? PacketAccessBit : 0),//(int(MatrixType::Flags)&int(DiagonalType::DiagonalVectorType::Flags)&AlignedBit), + Cost0 = EIGEN_ADD_COST(NumTraits<Scalar>::MulCost, MatrixType::CoeffReadCost), + CoeffReadCost = EIGEN_ADD_COST(Cost0,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())); + } + + EIGEN_STRONG_INLINE Index rows() const { return m_matrix.rows(); } + EIGEN_STRONG_INLINE Index cols() const { return m_matrix.cols(); } + + EIGEN_STRONG_INLINE const Scalar coeff(Index row, Index col) const + { + return m_diagonal.diagonal().coeff(ProductOrder == OnTheLeft ? row : col) * m_matrix.coeff(row, col); + } + + EIGEN_STRONG_INLINE const Scalar coeff(Index idx) const + { + enum { + StorageOrder = int(MatrixType::Flags) & RowMajorBit ? RowMajor : ColMajor + }; + return coeff(int(StorageOrder)==ColMajor?idx:0,int(StorageOrder)==ColMajor?0:idx); + } + + template<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()); + } + + template<int LoadMode> + EIGEN_STRONG_INLINE PacketScalar packet(Index idx) const + { + enum { + StorageOrder = int(MatrixType::Flags) & RowMajorBit ? RowMajor : ColMajor + }; + return packet<LoadMode>(int(StorageOrder)==ColMajor?idx:0,int(StorageOrder)==ColMajor?0:idx); + } + + 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) || (int(DiagonalType::DiagonalVectorType::Flags)&AlignedBit)==AlignedBit) ? 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> &a_diagonal) const +{ + return DiagonalProduct<Derived, DiagonalDerived, OnTheRight>(derived(), a_diagonal.derived()); +} + +} // end namespace Eigen + +#endif // EIGEN_DIAGONALPRODUCT_H \ No newline at end of file
diff -r 000000000000 -r 13a5d365ba16 src/Core/Dot.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/Core/Dot.h Thu Oct 13 04:07:23 2016 +0000 @@ -0,0 +1,263 @@ +// 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 numext::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 +{ + using std::sqrt; + return 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) + { + using std::pow; + 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, const RealScalar& prec) const +{ + typename internal::nested<Derived,2>::type nested(derived()); + typename internal::nested<OtherDerived,2>::type otherNested(other.derived()); + return numext::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(const 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 \ No newline at end of file
diff -r 000000000000 -r 13a5d365ba16 src/Core/EigenBase.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/Core/EigenBase.h Thu Oct 13 04:07:23 2016 +0000 @@ -0,0 +1,131 @@ +// 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(); +} + +} // end namespace Eigen + +#endif // EIGEN_EIGENBASE_H \ No newline at end of file
diff -r 000000000000 -r 13a5d365ba16 src/Core/Flagged.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/Core/Flagged.h Thu Oct 13 04:07:23 2016 +0000 @@ -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 \ No newline at end of file
diff -r 000000000000 -r 13a5d365ba16 src/Core/ForceAlignedAccess.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/Core/ForceAlignedAccess.h Thu Oct 13 04:07:23 2016 +0000 @@ -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 \ No newline at end of file
diff -r 000000000000 -r 13a5d365ba16 src/Core/Functors.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/Core/Functors.h Thu Oct 13 04:07:23 2016 +0000 @@ -0,0 +1,1026 @@ +// 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; + using std::sqrt; + Scalar p = (max)(_x, _y); + Scalar q = (min)(_x, _y); + Scalar qp = q/p; + return p * sqrt(Scalar(1) + qp*qp); + } +}; +template<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 numext::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 LhsScalar,typename RhsScalar> struct scalar_quotient_op { + enum { + // TODO vectorize mixed product + Vectorizable = is_same<LhsScalar,RhsScalar>::value && packet_traits<LhsScalar>::HasDiv && packet_traits<RhsScalar>::HasDiv + }; + typedef typename scalar_product_traits<LhsScalar,RhsScalar>::ReturnType result_type; + EIGEN_EMPTY_STRUCT_CTOR(scalar_quotient_op) + EIGEN_STRONG_INLINE const result_type operator() (const LhsScalar& a, const RhsScalar& b) const { return a / b; } + template<typename Packet> + EIGEN_STRONG_INLINE const Packet packetOp(const Packet& a, const Packet& b) const + { return internal::pdiv(a,b); } +}; +template<typename LhsScalar,typename RhsScalar> +struct functor_traits<scalar_quotient_op<LhsScalar,RhsScalar> > { + enum { + Cost = (NumTraits<LhsScalar>::MulCost + NumTraits<RhsScalar>::MulCost), // rough estimate! + PacketAccess = scalar_quotient_op<LhsScalar,RhsScalar>::Vectorizable + }; +}; + + + +/** \internal + * \brief Template functor to compute the and of two booleans + * + * \sa class CwiseBinaryOp, ArrayBase::operator&& + */ +struct scalar_boolean_and_op { + EIGEN_EMPTY_STRUCT_CTOR(scalar_boolean_and_op) + EIGEN_STRONG_INLINE bool operator() (const bool& a, const bool& b) const { return a && b; } +}; +template<> struct functor_traits<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 + }; +}; + +/** \internal + * \brief Template functors for comparison of two scalars + * \todo Implement packet-comparisons + */ +template<typename Scalar, ComparisonName cmp> struct scalar_cmp_op; + +template<typename Scalar, ComparisonName cmp> +struct functor_traits<scalar_cmp_op<Scalar, cmp> > { + enum { + Cost = NumTraits<Scalar>::AddCost, + PacketAccess = false + }; +}; + +template<ComparisonName Cmp, typename Scalar> +struct result_of<scalar_cmp_op<Scalar, Cmp>(Scalar,Scalar)> { + typedef bool type; +}; + + +template<typename Scalar> struct scalar_cmp_op<Scalar, cmp_EQ> { + EIGEN_EMPTY_STRUCT_CTOR(scalar_cmp_op) + EIGEN_STRONG_INLINE bool operator()(const Scalar& a, const Scalar& b) const {return a==b;} +}; +template<typename Scalar> struct scalar_cmp_op<Scalar, cmp_LT> { + EIGEN_EMPTY_STRUCT_CTOR(scalar_cmp_op) + EIGEN_STRONG_INLINE bool operator()(const Scalar& a, const Scalar& b) const {return a<b;} +}; +template<typename Scalar> struct scalar_cmp_op<Scalar, cmp_LE> { + EIGEN_EMPTY_STRUCT_CTOR(scalar_cmp_op) + EIGEN_STRONG_INLINE bool operator()(const Scalar& a, const Scalar& b) const {return a<=b;} +}; +template<typename Scalar> struct scalar_cmp_op<Scalar, cmp_UNORD> { + EIGEN_EMPTY_STRUCT_CTOR(scalar_cmp_op) + EIGEN_STRONG_INLINE bool operator()(const Scalar& a, const Scalar& b) const {return !(a<=b || b<=a);} +}; +template<typename Scalar> struct scalar_cmp_op<Scalar, cmp_NEQ> { + EIGEN_EMPTY_STRUCT_CTOR(scalar_cmp_op) + EIGEN_STRONG_INLINE bool operator()(const Scalar& a, const Scalar& b) const {return a!=b;} +}; + +// unary functors: + +/** \internal + * \brief Template functor to compute the opposite of a scalar + * + * \sa class CwiseUnaryOp, MatrixBase::operator- + */ +template<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 { using std::abs; return 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 numext::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 { using numext::conj; return 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 numext::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 numext::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 numext::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 numext::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 { using std::exp; return 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 { using std::log; return 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() outside the loop :) + * - simpler code ;) + * (ICC and gcc 4.4 seems to perform well in both cases, the issue is visible with y = a*x + b*y) + */ +template<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 }; }; + +/** \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 { + typedef typename packet_traits<Scalar>::type Packet; + // FIXME default copy constructors seems bugged with std::complex<> + EIGEN_STRONG_INLINE scalar_quotient1_op(const scalar_quotient1_op& other) : m_other(other.m_other) { } + EIGEN_STRONG_INLINE scalar_quotient1_op(const Scalar& other) : m_other(other) {} + EIGEN_STRONG_INLINE Scalar operator() (const Scalar& a) const { return a / m_other; } + EIGEN_STRONG_INLINE const Packet packetOp(const Packet& a) const + { return internal::pdiv(a, pset1<Packet>(m_other)); } + typename add_const_on_value_type<typename NumTraits<Scalar>::Nested>::type m_other; +}; +template<typename Scalar> +struct functor_traits<scalar_quotient1_op<Scalar> > +{ enum { Cost = 2 * NumTraits<Scalar>::MulCost, PacketAccess = packet_traits<Scalar>::HasDiv }; }; + +// 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 (where size is 1 for coeff access or PacketSize for packet access) +// base += [size*step, ..., size*step] +// +// TODO: Perhaps it's better to initialize lazily (so not in the constructor but in packetOp) +// in order to avoid the padd() in operator() ? +template <typename Scalar> +struct linspaced_op_impl<Scalar,false> +{ + typedef typename packet_traits<Scalar>::type Packet; + + linspaced_op_impl(const Scalar& low, const 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 + { + m_base = padd(m_base, pset1<Packet>(m_step)); + return m_low+Scalar(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(const Scalar& low, const 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>(Scalar(i)),m_interPacket))); } + + const Scalar m_low; + const Scalar m_step; + const Packet m_lowPacket; + const Packet m_stepPacket; + const Packet m_interPacket; +}; + +// ----- Linspace functor ---------------------------------------------------------------- + +// Forward declaration (we default to random access which does not really give +// us a speed gain when using packet access but it allows to use the functor in +// nested expressions). +template <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(const Scalar& low, const Scalar& high, DenseIndex num_steps) : impl((num_steps==1 ? high : low), (num_steps==1 ? Scalar() : (high-low)/Scalar(num_steps-1))) {} + + template<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 Eigen, any binary op (Product, CwiseBinaryOp) require the Lhs and Rhs to have the same scalar type, except for multiplication +// where the mixing of different types is handled by scalar_product_traits +// In particular, real * complex<real> is allowed. +// FIXME move this to functor_traits adding a functor_default +template<typename Functor> struct functor_is_product_like { enum { ret = 0 }; }; +template<typename LhsScalar,typename RhsScalar> struct functor_is_product_like<scalar_product_op<LhsScalar,RhsScalar> > { enum { ret = 1 }; }; +template<typename LhsScalar,typename RhsScalar> struct functor_is_product_like<scalar_conj_product_op<LhsScalar,RhsScalar> > { enum { ret = 1 }; }; +template<typename LhsScalar,typename RhsScalar> struct functor_is_product_like<scalar_quotient_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 { using std::sqrt; return 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 { using std::cos; return 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 { using std::sin; return 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 { using std::tan; return 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 { using std::acos; return 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 { using std::asin; return 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 numext::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 \ No newline at end of file
diff -r 000000000000 -r 13a5d365ba16 src/Core/Fuzzy.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/Core/Fuzzy.h Thu Oct 13 04:07:23 2016 +0000 @@ -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, const 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, const 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, const typename Derived::RealScalar& prec) + { + return x.cwiseAbs2().sum() <= numext::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&, const 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, const typename Derived::RealScalar& prec) + { + return x.cwiseAbs2().sum() <= numext::abs2(prec * y); + } +}; + +template<typename Derived> +struct isMuchSmallerThan_scalar_selector<Derived, true> +{ + static bool run(const Derived& x, const typename Derived::RealScalar&, const 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, + const 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, + const 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, + const RealScalar& prec +) const +{ + return internal::isMuchSmallerThan_object_selector<Derived, OtherDerived>::run(derived(), other.derived(), prec); +} + +} // end namespace Eigen + +#endif // EIGEN_FUZZY_H \ No newline at end of file
diff -r 000000000000 -r 13a5d365ba16 src/Core/GeneralProduct.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/Core/GeneralProduct.h Thu Oct 13 04:07:23 2016 +0000 @@ -0,0 +1,638 @@ +// 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 { + +// Column major +template<typename ProductType, typename Dest, typename Func> +EIGEN_DONT_INLINE void outer_product_selector_run(const ProductType& prod, Dest& dest, const Func& func, const false_type&) +{ + typedef typename Dest::Index Index; + // FIXME make sure lhs is sequentially stored + // FIXME not very good if rhs is real and lhs complex while alpha is real too + const Index cols = dest.cols(); + for (Index j=0; j<cols; ++j) + func(dest.col(j), prod.rhs().coeff(0,j) * prod.lhs()); +} + +// Row major +template<typename ProductType, typename Dest, typename Func> +EIGEN_DONT_INLINE void outer_product_selector_run(const ProductType& prod, Dest& dest, const Func& func, const true_type&) { + typedef typename Dest::Index Index; + // FIXME make sure rhs is sequentially stored + // FIXME not very good if lhs is real and rhs complex while alpha is real too + const Index rows = dest.rows(); + for (Index i=0; i<rows; ++i) + func(dest.row(i), prod.lhs().coeff(i,0) * prod.rhs()); +} + +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> +{ + template<typename T> struct is_row_major : internal::conditional<(int(T::Flags)&RowMajorBit), internal::true_type, internal::false_type>::type {}; + + public: + EIGEN_PRODUCT_PUBLIC_INTERFACE(GeneralProduct) + + GeneralProduct(const Lhs& lhs, const Rhs& rhs) : Base(lhs,rhs) + { + EIGEN_STATIC_ASSERT((internal::is_same<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) + } + + struct set { template<typename Dst, typename Src> void operator()(const Dst& dst, const Src& src) const { dst.const_cast_derived() = src; } }; + struct add { template<typename Dst, typename Src> void operator()(const Dst& dst, const Src& src) const { dst.const_cast_derived() += src; } }; + struct sub { template<typename Dst, typename Src> void operator()(const Dst& dst, const Src& src) const { dst.const_cast_derived() -= src; } }; + struct adds { + Scalar m_scale; + adds(const Scalar& s) : m_scale(s) {} + template<typename Dst, typename Src> void operator()(const Dst& dst, const Src& src) const { + dst.const_cast_derived() += m_scale * src; + } + }; + + template<typename Dest> + inline void evalTo(Dest& dest) const { + internal::outer_product_selector_run(*this, dest, set(), is_row_major<Dest>()); + } + + template<typename Dest> + inline void addTo(Dest& dest) const { + internal::outer_product_selector_run(*this, dest, add(), is_row_major<Dest>()); + } + + template<typename Dest> + inline void subTo(Dest& dest) const { + internal::outer_product_selector_run(*this, dest, sub(), is_row_major<Dest>()); + } + + template<typename Dest> void scaleAndAddTo(Dest& dest, const Scalar& alpha) const + { + internal::outer_product_selector_run(*this, dest, adds(alpha), is_row_major<Dest>()); + } +}; + +/*********************************************************************** +* 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& a_lhs, const Rhs& a_rhs) : Base(a_lhs,a_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, const 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, const 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, const typename ProductType::Scalar& alpha) + { + typedef typename ProductType::Index Index; + typedef typename ProductType::LhsScalar LhsScalar; + typedef typename ProductType::RhsScalar RhsScalar; + typedef typename ProductType::Scalar ResScalar; + typedef typename ProductType::RealScalar RealScalar; + typedef typename ProductType::ActualLhsType ActualLhsType; + typedef typename ProductType::ActualRhsType ActualRhsType; + typedef typename ProductType::LhsBlasTraits LhsBlasTraits; + typedef typename ProductType::RhsBlasTraits RhsBlasTraits; + typedef Map<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()); + + // make sure Dest is a compile-time vector type (bug 1166) + typedef typename conditional<Dest::IsVectorAtCompileTime, Dest, typename Dest::ColXpr>::type ActualDest; + + 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 = (ActualDest::InnerStrideAtCompileTime==1), + ComplexByReal = (NumTraits<LhsScalar>::IsComplex) && (!NumTraits<RhsScalar>::IsComplex), + MightCannotUseDest = (ActualDest::InnerStrideAtCompileTime!=1) || ComplexByReal + }; + + gemv_static_vector_if<ResScalar,ActualDest::SizeAtCompileTime,ActualDest::MaxSizeAtCompileTime,MightCannotUseDest> static_dest; + + bool alphaIsCompatible = (!ComplexByReal) || (numext::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, const typename ProductType::Scalar& alpha) + { + typedef typename ProductType::LhsScalar LhsScalar; + typedef typename ProductType::RhsScalar RhsScalar; + typedef typename ProductType::Scalar ResScalar; + typedef typename ProductType::Index Index; + typedef typename ProductType::ActualLhsType ActualLhsType; + typedef typename ProductType::ActualRhsType ActualRhsType; + typedef typename ProductType::_ActualRhsType _ActualRhsType; + typedef typename ProductType::LhsBlasTraits LhsBlasTraits; + typedef typename ProductType::RhsBlasTraits RhsBlasTraits; + + typename add_const<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.col(0).innerStride(), //NOTE if dest is not a vector at compile-time, then dest.innerStride() might be wrong. (bug 1166) + actualAlpha); + } +}; + +template<> struct gemv_selector<OnTheRight,ColMajor,false> +{ + template<typename ProductType, typename Dest> + static void run(const ProductType& prod, Dest& dest, const typename ProductType::Scalar& alpha) + { + typedef typename Dest::Index Index; + // TODO makes sure dest is sequentially stored in memory, otherwise use a temp + const Index size = prod.rhs().rows(); + for(Index k=0; k<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, const typename ProductType::Scalar& alpha) + { + typedef typename Dest::Index Index; + // TODO makes sure rhs is sequentially stored in memory, otherwise use a temp + const Index rows = prod.rows(); + for(Index i=0; i<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 \ No newline at end of file
diff -r 000000000000 -r 13a5d365ba16 src/Core/GenericPacketMath.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/Core/GenericPacketMath.h Thu Oct 13 04:07:23 2016 +0000 @@ -0,0 +1,349 @@ +// 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 numext::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) { using std::abs; 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. + * For instance, for a packet of 8 elements, 4 scalar will be read from \a *from and + * duplicated to form: {from[0],from[0],from[1],from[1],,from[2],from[2],,from[3],from[3]} + * Currently, this function is only used for scalar * complex products. + */ +template<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) +{ + // FIXME: uncomment the following in case we drop the internal imag and real functions. +// using std::imag; +// using std::real; + return Packet(imag(a),real(a)); +} + +/************************** +* Special math functions +***************************/ + +/** \internal \returns the sine of \a a (coeff-wise) */ +template<typename Packet> EIGEN_DECLARE_FUNCTION_ALLOWING_MULTIPLE_DEFINITIONS +Packet psin(const Packet& a) { using std::sin; return sin(a); } + +/** \internal \returns the cosine of \a a (coeff-wise) */ +template<typename Packet> EIGEN_DECLARE_FUNCTION_ALLOWING_MULTIPLE_DEFINITIONS +Packet pcos(const Packet& a) { using std::cos; return cos(a); } + +/** \internal \returns the tan of \a a (coeff-wise) */ +template<typename Packet> EIGEN_DECLARE_FUNCTION_ALLOWING_MULTIPLE_DEFINITIONS +Packet ptan(const Packet& a) { using std::tan; return tan(a); } + +/** \internal \returns the arc sine of \a a (coeff-wise) */ +template<typename Packet> EIGEN_DECLARE_FUNCTION_ALLOWING_MULTIPLE_DEFINITIONS +Packet pasin(const Packet& a) { using std::asin; return asin(a); } + +/** \internal \returns the arc cosine of \a a (coeff-wise) */ +template<typename Packet> EIGEN_DECLARE_FUNCTION_ALLOWING_MULTIPLE_DEFINITIONS +Packet pacos(const Packet& a) { using std::acos; return acos(a); } + +/** \internal \returns the exp of \a a (coeff-wise) */ +template<typename Packet> EIGEN_DECLARE_FUNCTION_ALLOWING_MULTIPLE_DEFINITIONS +Packet pexp(const Packet& a) { using std::exp; return exp(a); } + +/** \internal \returns the log of \a a (coeff-wise) */ +template<typename Packet> EIGEN_DECLARE_FUNCTION_ALLOWING_MULTIPLE_DEFINITIONS +Packet plog(const Packet& a) { using std::log; return log(a); } + +/** \internal \returns the square-root of \a a (coeff-wise) */ +template<typename Packet> EIGEN_DECLARE_FUNCTION_ALLOWING_MULTIPLE_DEFINITIONS +Packet psqrt(const Packet& a) { using std::sqrt; return sqrt(a); } + +/*************************************************************************** +* The following functions might not have to be overwritten for vectorized types +***************************************************************************/ + +/** \internal copy a packet with constant coeficient \a a (e.g., [a,a,a,a]) to \a *to. \a to must be 16 bytes aligned */ +// NOTE: this function must really be templated on the packet type (think about different packet types for the same scalar type) +template<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 packet_size minus \a Offset last elements + * of \a first and \a Offset first elements of \a second. + * + * This function is currently only used to optimize matrix-vector products on unligned matrices. + * It takes 2 packets that represent a contiguous memory array, and returns a packet starting + * at the position \a Offset. For instance, for packets of 4 elements, we have: + * Input: + * - first = {f0,f1,f2,f3} + * - second = {s0,s1,s2,s3} + * Output: + * - if Offset==0 then {f0,f1,f2,f3} + * - if Offset==1 then {f1,f2,f3,s0} + * - if Offset==2 then {f2,f3,s0,s1} + * - if Offset==3 then {f3,s0,s1,s3} + */ +template<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 -r 000000000000 -r 13a5d365ba16 src/Core/GlobalFunctions.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/Core/GlobalFunctions.h Thu Oct 13 04:07:23 2016 +0000 @@ -0,0 +1,92 @@ +// This file is part of Eigen, a lightweight C++ template library +// for linear algebra. +// +// Copyright (C) 2010-2012 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_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 Eigen +{ + EIGEN_ARRAY_DECLARE_GLOBAL_UNARY(real,scalar_real_op) + EIGEN_ARRAY_DECLARE_GLOBAL_UNARY(imag,scalar_imag_op) + EIGEN_ARRAY_DECLARE_GLOBAL_UNARY(conj,scalar_conjugate_op) + EIGEN_ARRAY_DECLARE_GLOBAL_UNARY(sin,scalar_sin_op) + EIGEN_ARRAY_DECLARE_GLOBAL_UNARY(cos,scalar_cos_op) + EIGEN_ARRAY_DECLARE_GLOBAL_UNARY(asin,scalar_asin_op) + EIGEN_ARRAY_DECLARE_GLOBAL_UNARY(acos,scalar_acos_op) + EIGEN_ARRAY_DECLARE_GLOBAL_UNARY(tan,scalar_tan_op) + EIGEN_ARRAY_DECLARE_GLOBAL_UNARY(exp,scalar_exp_op) + EIGEN_ARRAY_DECLARE_GLOBAL_UNARY(log,scalar_log_op) + EIGEN_ARRAY_DECLARE_GLOBAL_UNARY(abs,scalar_abs_op) + EIGEN_ARRAY_DECLARE_GLOBAL_UNARY(sqrt,scalar_sqrt_op) + + template<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() + ); + } + + /** + * \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/(const 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(abs2,scalar_abs2_op) + } +} + +// TODO: cleanly disable those functions that are not supported on Array (numext::real_ref, internal::random, internal::isApprox...) + +#endif // EIGEN_GLOBAL_FUNCTIONS_H \ No newline at end of file
diff -r 000000000000 -r 13a5d365ba16 src/Core/IO.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/Core/IO.h Thu Oct 13 04:07:23 2016 +0000 @@ -0,0 +1,250 @@ +// 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), + rowSpacer(""), coeffSeparator(_coeffSeparator), precision(_precision), flags(_flags) + { + 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; + using std::log; + 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; + } + + std::streamsize old_precision = 0; + if(explicit_precision) old_precision = s.precision(explicit_precision); + + bool align_cols = !(fmt.flags & DontAlignCols); + if(align_cols) + { + // compute the largest width + for(Index j = 0; j < m.cols(); ++j) + for(Index i = 0; i < m.rows(); ++i) + { + std::stringstream sstr; + sstr.copyfmt(s); + sstr << m.coeff(i,j); + width = std::max<Index>(width, Index(sstr.str().length())); + } + } + 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 \ No newline at end of file
diff -r 000000000000 -r 13a5d365ba16 src/Core/Map.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/Core/Map.h Thu Oct 13 04:07:23 2016 +0000 @@ -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 dataPtr pointer to the array to map + * \param a_stride optional Stride object, passing the strides. + */ + inline Map(PointerArgType dataPtr, const StrideType& a_stride = StrideType()) + : Base(cast_to_pointer_type(dataPtr)), m_stride(a_stride) + { + PlainObjectType::Base::_check_template_params(); + } + + /** Constructor in the dynamic-size vector case. + * + * \param dataPtr pointer to the array to map + * \param a_size the size of the vector expression + * \param a_stride optional Stride object, passing the strides. + */ + inline Map(PointerArgType dataPtr, Index a_size, const StrideType& a_stride = StrideType()) + : Base(cast_to_pointer_type(dataPtr), a_size), m_stride(a_stride) + { + PlainObjectType::Base::_check_template_params(); + } + + /** Constructor in the dynamic-size matrix case. + * + * \param dataPtr pointer to the array to map + * \param nbRows the number of rows of the matrix expression + * \param nbCols the number of columns of the matrix expression + * \param a_stride optional Stride object, passing the strides. + */ + inline Map(PointerArgType dataPtr, Index nbRows, Index nbCols, const StrideType& a_stride = StrideType()) + : Base(cast_to_pointer_type(dataPtr), nbRows, nbCols), m_stride(a_stride) + { + 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 \ No newline at end of file
diff -r 000000000000 -r 13a5d365ba16 src/Core/MapBase.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/Core/MapBase.h Thu Oct 13 04:07:23 2016 +0000 @@ -0,0 +1,251 @@ +// 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 rowId, Index colId) const + { + return m_data[colId * colStride() + rowId * 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 rowId, Index colId) const + { + return this->m_data[colId * colStride() + rowId * 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 rowId, Index colId) const + { + return internal::ploadt<PacketScalar, LoadMode> + (m_data + (colId * colStride() + rowId * 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()); + } + + explicit inline MapBase(PointerType dataPtr) : m_data(dataPtr), m_rows(RowsAtCompileTime), m_cols(ColsAtCompileTime) + { + EIGEN_STATIC_ASSERT_FIXED_SIZE(Derived) + checkSanity(); + } + + inline MapBase(PointerType dataPtr, Index vecSize) + : m_data(dataPtr), + m_rows(RowsAtCompileTime == Dynamic ? vecSize : Index(RowsAtCompileTime)), + m_cols(ColsAtCompileTime == Dynamic ? vecSize : Index(ColsAtCompileTime)) + { + EIGEN_STATIC_ASSERT_VECTOR_ONLY(Derived) + eigen_assert(vecSize >= 0); + eigen_assert(dataPtr == 0 || SizeAtCompileTime == Dynamic || SizeAtCompileTime == vecSize); + checkSanity(); + } + + inline MapBase(PointerType dataPtr, Index nbRows, Index nbCols) + : m_data(dataPtr), m_rows(nbRows), m_cols(nbCols) + { + eigen_assert( (dataPtr == 0) + || ( nbRows >= 0 && (RowsAtCompileTime == Dynamic || RowsAtCompileTime == nbRows) + && nbCols >= 0 && (ColsAtCompileTime == Dynamic || ColsAtCompileTime == nbCols))); + checkSanity(); + } + + #ifdef EIGEN_MAPBASE_PLUGIN + #include EIGEN_MAPBASE_PLUGIN + #endif + + 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) + && "input pointer is not aligned on a 16 byte boundary"); + } + + 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> +{ + typedef MapBase<Derived, ReadOnlyAccessors> ReadOnlyMapBase; + 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& val) + { + internal::pstoret<Scalar, PacketScalar, StoreMode> + (this->m_data + (col * colStride() + row * rowStride()), val); + } + + template<int StoreMode> + inline void writePacket(Index index, const PacketScalar& val) + { + EIGEN_STATIC_ASSERT_INDEX_BASED_ACCESS(Derived) + internal::pstoret<Scalar, PacketScalar, StoreMode> + (this->m_data + index * innerStride(), val); + } + + explicit inline MapBase(PointerType dataPtr) : Base(dataPtr) {} + inline MapBase(PointerType dataPtr, Index vecSize) : Base(dataPtr, vecSize) {} + inline MapBase(PointerType dataPtr, Index nbRows, Index nbCols) : Base(dataPtr, nbRows, nbCols) {} + + Derived& operator=(const MapBase& other) + { + ReadOnlyMapBase::Base::operator=(other); + return derived(); + } + + // In theory we could simply refer to Base:Base::operator=, but MSVC does not like Base::Base, + // see bugs 821 and 920. + using ReadOnlyMapBase::Base::operator=; +}; + +#undef EIGEN_STATIC_ASSERT_INDEX_BASED_ACCESS + +} // end namespace Eigen + +#endif // EIGEN_MAPBASE_H \ No newline at end of file
diff -r 000000000000 -r 13a5d365ba16 src/Core/MathFunctions.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/Core/MathFunctions.h Thu Oct 13 04:07:23 2016 +0000 @@ -0,0 +1,768 @@ +// 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) Eigen::internal::func##_impl<typename Eigen::internal::global_math_functions_filtering_base<scalar>::type> +#define EIGEN_MATHFUNC_RETVAL(func, scalar) typename Eigen::internal::func##_retval<typename Eigen::internal::global_math_functions_filtering_base<scalar>::type>::type + +/**************************************************************************** +* Implementation of real * +****************************************************************************/ + +template<typename Scalar, bool IsComplex = NumTraits<Scalar>::IsComplex> +struct real_default_impl +{ + typedef typename NumTraits<Scalar>::Real RealScalar; + static inline RealScalar run(const Scalar& x) + { + return x; + } +}; + +template<typename Scalar> +struct real_default_impl<Scalar,true> +{ + typedef typename NumTraits<Scalar>::Real RealScalar; + static inline RealScalar run(const Scalar& x) + { + using std::real; + return real(x); + } +}; + +template<typename Scalar> struct real_impl : real_default_impl<Scalar> {}; + +template<typename Scalar> +struct real_retval +{ + typedef typename NumTraits<Scalar>::Real type; +}; + + +/**************************************************************************** +* Implementation of imag * +****************************************************************************/ + +template<typename Scalar, bool IsComplex = NumTraits<Scalar>::IsComplex> +struct imag_default_impl +{ + typedef typename NumTraits<Scalar>::Real RealScalar; + static inline RealScalar run(const Scalar&) + { + return RealScalar(0); + } +}; + +template<typename Scalar> +struct imag_default_impl<Scalar,true> +{ + typedef typename NumTraits<Scalar>::Real RealScalar; + static inline RealScalar run(const Scalar& x) + { + using std::imag; + return imag(x); + } +}; + +template<typename Scalar> struct imag_impl : imag_default_impl<Scalar> {}; + +template<typename Scalar> +struct imag_retval +{ + typedef typename NumTraits<Scalar>::Real type; +}; + +/**************************************************************************** +* 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; +}; + +/**************************************************************************** +* 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; +}; + +/**************************************************************************** +* Implementation of conj * +****************************************************************************/ + +template<typename Scalar, bool IsComplex = NumTraits<Scalar>::IsComplex> +struct conj_impl +{ + static inline Scalar run(const Scalar& x) + { + return x; + } +}; + +template<typename Scalar> +struct conj_impl<Scalar,true> +{ + static inline Scalar run(const Scalar& x) + { + using std::conj; + return conj(x); + } +}; + +template<typename Scalar> +struct conj_retval +{ + typedef Scalar type; +}; + +/**************************************************************************** +* 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; +}; + +/**************************************************************************** +* 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) + { + using std::abs; + return abs(real(x)) + abs(imag(x)); + } +}; + +template<typename Scalar> +struct norm1_default_impl<Scalar, false> +{ + static inline Scalar run(const Scalar& x) + { + using std::abs; + 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; +}; + +/**************************************************************************** +* 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; + using std::abs; + using std::sqrt; + RealScalar _x = abs(x); + RealScalar _y = abs(y); + RealScalar p = (max)(_x, _y); + if(p==RealScalar(0)) return RealScalar(0); + RealScalar q = (min)(_x, _y); + RealScalar qp = q/p; + return p * sqrt(RealScalar(1) + qp*qp); + } +}; + +template<typename Scalar> +struct hypot_retval +{ + typedef typename NumTraits<Scalar>::Real type; +}; + +/**************************************************************************** +* 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 atanh2 * +****************************************************************************/ + +template<typename Scalar, bool IsInteger> +struct atanh2_default_impl +{ + typedef Scalar retval; + typedef typename NumTraits<Scalar>::Real RealScalar; + static inline Scalar run(const Scalar& x, const Scalar& y) + { + using std::abs; + using std::log; + using std::sqrt; + Scalar z = x / y; + if (y == Scalar(0) || abs(z) > sqrt(NumTraits<RealScalar>::epsilon())) + return RealScalar(0.5) * log((y + x) / (y - x)); + else + return z + z*z*z / RealScalar(3); + } +}; + +template<typename Scalar> +struct atanh2_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 atanh2_impl : atanh2_default_impl<Scalar, NumTraits<Scalar>::IsInteger> {}; + +template<typename Scalar> +struct atanh2_retval +{ + typedef Scalar type; +}; + +/**************************************************************************** +* 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; +}; + +/**************************************************************************** +* 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)), + offset = NumTraits<Scalar>::IsSigned ? (1 << (EIGEN_PLAIN_ENUM_MIN(rand_bits,scalar_bits)-1)) : 0 + }; + return Scalar((std::rand() >> shift) - 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(); +} + +} // end namespace internal + +/**************************************************************************** +* Generic math function * +****************************************************************************/ + +namespace numext { + +template<typename Scalar> +inline EIGEN_MATHFUNC_RETVAL(real, Scalar) real(const Scalar& x) +{ + return EIGEN_MATHFUNC_IMPL(real, Scalar)::run(x); +} + +template<typename Scalar> +inline typename internal::add_const_on_value_type< EIGEN_MATHFUNC_RETVAL(real_ref, Scalar) >::type real_ref(const Scalar& x) +{ + return internal::real_ref_impl<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); +} + +template<typename Scalar> +inline EIGEN_MATHFUNC_RETVAL(imag, Scalar) imag(const Scalar& x) +{ + return EIGEN_MATHFUNC_IMPL(imag, Scalar)::run(x); +} + +template<typename Scalar> +inline typename internal::add_const_on_value_type< EIGEN_MATHFUNC_RETVAL(imag_ref, Scalar) >::type imag_ref(const Scalar& x) +{ + return internal::imag_ref_impl<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); +} + +template<typename Scalar> +inline EIGEN_MATHFUNC_RETVAL(conj, Scalar) conj(const Scalar& x) +{ + return EIGEN_MATHFUNC_IMPL(conj, Scalar)::run(x); +} + +template<typename Scalar> +inline EIGEN_MATHFUNC_RETVAL(abs2, Scalar) abs2(const Scalar& x) +{ + return EIGEN_MATHFUNC_IMPL(abs2, Scalar)::run(x); +} + +template<typename Scalar> +inline EIGEN_MATHFUNC_RETVAL(norm1, Scalar) norm1(const Scalar& x) +{ + return EIGEN_MATHFUNC_IMPL(norm1, Scalar)::run(x); +} + +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); +} + +template<typename Scalar> +inline EIGEN_MATHFUNC_RETVAL(atanh2, Scalar) atanh2(const Scalar& x, const Scalar& y) +{ + return EIGEN_MATHFUNC_IMPL(atanh2, Scalar)::run(x, y); +} + +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); +} + +// 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 numext + +namespace internal { + +/**************************************************************************** +* 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) + { + using std::abs; + return abs(x) <= abs(y) * prec; + } + static inline bool isApprox(const Scalar& x, const Scalar& y, const RealScalar& prec) + { + using std::min; + using std::abs; + return abs(x - y) <= (min)(abs(x), abs(y)) * prec; + } + static inline bool isApproxOrLessThan(const Scalar& x, const Scalar& y, const RealScalar& prec) + { + return x <= y || isApprox(x, y, prec); + } +}; + +template<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 numext::abs2(x) <= numext::abs2(y) * prec * prec; + } + static inline bool isApprox(const Scalar& x, const Scalar& y, const RealScalar& prec) + { + using std::min; + return numext::abs2(x - y) <= (min)(numext::abs2(x), numext::abs2(y)) * prec * prec; + } +}; + +template<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, + const 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, + const 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, + const 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; + } + +}; + + +} // end namespace internal + +} // end namespace Eigen + +#endif // EIGEN_MATHFUNCTIONS_H \ No newline at end of file
diff -r 000000000000 -r 13a5d365ba16 src/Core/Matrix.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/Core/Matrix.h Thu Oct 13 04:07:23 2016 +0000 @@ -0,0 +1,420 @@ +// 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 Matrix() : Base() + { + Base::_check_template_params(); + EIGEN_INITIALIZE_COEFFS_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_COEFFS_IF_THAT_OPTION_IS_ENABLED } + +#ifdef EIGEN_HAVE_RVALUE_REFERENCES + Matrix(Matrix&& other) + : Base(std::move(other)) + { + Base::_check_template_params(); + if (RowsAtCompileTime!=Dynamic && ColsAtCompileTime!=Dynamic) + Base::_set_noalias(other); + } + Matrix& operator=(Matrix&& other) + { + other.swap(*this); + return *this; + } +#endif + + /** \brief Constructs a vector or row-vector with given dimension. \only_for_vectors + * + * Note that this is only useful for dynamic-size vectors. For fixed-size vectors, + * it is redundant to pass the dimension here, so it makes more sense to use the default + * constructor Matrix() instead. + */ + EIGEN_STRONG_INLINE explicit Matrix(Index dim) + : Base(dim, RowsAtCompileTime == 1 ? 1 : dim, ColsAtCompileTime == 1 ? 1 : dim) + { + Base::_check_template_params(); + EIGEN_STATIC_ASSERT_VECTOR_ONLY(Matrix) + eigen_assert(dim >= 0); + eigen_assert(SizeAtCompileTime == Dynamic || SizeAtCompileTime == dim); + EIGEN_INITIALIZE_COEFFS_IF_THAT_OPTION_IS_ENABLED + } + + #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_to_match(other); + // FIXME/CHECK: isn't *this = other.derived() more efficient. it allows to + // go for pure _set() implementations, right? + *this = other; + } + + /** \internal + * \brief Override MatrixBase::swap() since for dynamic-sized matrices + * of same type it is enough to swap the data pointers. + */ + template<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 \ No newline at end of file
diff -r 000000000000 -r 13a5d365ba16 src/Core/MatrixBase.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/Core/MatrixBase.h Thu Oct 13 04:07:23 2016 +0000 @@ -0,0 +1,563 @@ +// 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); + + template<typename ProductDerived, typename Lhs, typename Rhs> + Derived& lazyAssign(const ProductBase<ProductDerived, Lhs,Rhs>& other); + + template<typename MatrixPower, typename Lhs, typename Rhs> + Derived& lazyAssign(const MatrixPowerProduct<MatrixPower, Lhs,Rhs>& other); + + 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 typename internal::add_const<Diagonal<const Derived> >::type ConstDiagonalReturnType; + 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; + + typedef Diagonal<Derived,DynamicIndex> DiagonalDynamicIndexReturnType; + typedef typename internal::add_const<Diagonal<const Derived,DynamicIndex> >::type ConstDiagonalDynamicIndexReturnType; + + DiagonalDynamicIndexReturnType diagonal(Index index); + ConstDiagonalDynamicIndexReturnType diagonal(Index index) const; + + #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), + const 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(const RealScalar& prec = NumTraits<Scalar>::dummy_precision()) const; + bool isDiagonal(const RealScalar& prec = NumTraits<Scalar>::dummy_precision()) const; + + bool isUpperTriangular(const RealScalar& prec = NumTraits<Scalar>::dummy_precision()) const; + bool isLowerTriangular(const RealScalar& prec = NumTraits<Scalar>::dummy_precision()) const; + + template<typename OtherDerived> + bool isOrthogonal(const MatrixBase<OtherDerived>& other, + const RealScalar& prec = NumTraits<Scalar>::dummy_precision()) const; + bool isUnitary(const 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 Eigen::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); + +///////// SparseCore module ///////// + + template<typename OtherDerived> + EIGEN_STRONG_INLINE const typename SparseMatrixBase<OtherDerived>::template CwiseProductDenseReturnType<Derived>::Type + cwiseProduct(const SparseMatrixBase<OtherDerived> &other) const + { + return other.cwiseProduct(derived()); + } + +///////// 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; + const MatrixPowerReturnValue<Derived> pow(const RealScalar& p) 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;} +}; + + +/*************************************************************************** +* Implementation of matrix base methods +***************************************************************************/ + +/** replaces \c *this by \c *this * \a other. + * + * \returns a reference to \c *this + * + * Example: \include MatrixBase_applyOnTheRight.cpp + * Output: \verbinclude MatrixBase_applyOnTheRight.out + */ +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*=(). + * + * Example: \include MatrixBase_applyOnTheRight.cpp + * Output: \verbinclude MatrixBase_applyOnTheRight.out + */ +template<typename Derived> +template<typename OtherDerived> +inline void MatrixBase<Derived>::applyOnTheRight(const EigenBase<OtherDerived> &other) +{ + other.derived().applyThisOnTheRight(derived()); +} + +/** replaces \c *this by \a other * \c *this. + * + * Example: \include MatrixBase_applyOnTheLeft.cpp + * Output: \verbinclude MatrixBase_applyOnTheLeft.out + */ +template<typename Derived> +template<typename OtherDerived> +inline void MatrixBase<Derived>::applyOnTheLeft(const EigenBase<OtherDerived> &other) +{ + other.derived().applyThisOnTheLeft(derived()); +} + +} // end namespace Eigen + +#endif // EIGEN_MATRIXBASE_H \ No newline at end of file
diff -r 000000000000 -r 13a5d365ba16 src/Core/NestByValue.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/Core/NestByValue.h Thu Oct 13 04:07:23 2016 +0000 @@ -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 \ No newline at end of file
diff -r 000000000000 -r 13a5d365ba16 src/Core/NoAlias.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/Core/NoAlias.h Thu Oct 13 04:07:23 2016 +0000 @@ -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> +// +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If 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()); } + + template<typename OtherDerived> + ExpressionType& operator=(const ReturnByValue<OtherDerived>& func) + { return m_expression = func; } +#endif + + ExpressionType& expression() const + { + return m_expression; + } + + 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 \ No newline at end of file
diff -r 000000000000 -r 13a5d365ba16 src/Core/NumTraits.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/Core/NumTraits.h Thu Oct 13 04:07:23 2016 +0000 @@ -0,0 +1,150 @@ +// 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 + }; + + static inline RealScalar epsilon() { return NumTraits<RealScalar>::epsilon(); } + static inline RealScalar dummy_precision() { return NumTraits<RealScalar>::dummy_precision(); } +}; + +} // end namespace Eigen + +#endif // EIGEN_NUMTRAITS_H \ No newline at end of file
diff -r 000000000000 -r 13a5d365ba16 src/Core/PermutationMatrix.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/Core/PermutationMatrix.h Thu Oct 13 04:07:23 2016 +0000 @@ -0,0 +1,721 @@ +// 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 Index(indices().size()); } + + /** \returns the number of columns */ + inline Index cols() const { return Index(indices().size()); } + + /** \returns the size of a side of the respective square matrix, i.e., the number of indices */ + inline Index size() const { return Index(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 newSize) + { + indices().resize(newSize); + } + + /** 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 newSize) + { + resize(newSize); + 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); } + + /** \returns the determinant of the permutation matrix, which is either 1 or -1 depending on the parity of the permutation. + * + * This function is O(\c n) procedure allocating a buffer of \c n booleans. + */ + Index determinant() const + { + Index res = 1; + Index n = size(); + Matrix<bool,RowsAtCompileTime,1,0,MaxRowsAtCompileTime> mask(n); + mask.fill(false); + Index r = 0; + while(r < n) + { + // search for the next seed + while(r<n && mask[r]) r++; + if(r>=n) + break; + // we got one, let's follow it until we are back to the seed + Index k0 = r++; + mask.coeffRef(k0) = true; + for(Index k=indices().coeff(k0); k!=k0; k=indices().coeff(k)) + { + mask.coeffRef(k) = true; + res = -res; + } + } + return res; + } + + 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>& a_indices) : m_indices(a_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* indicesPtr) + : m_indices(indicesPtr) + {} + + inline Map(const Index* indicesPtr, Index size) + : m_indices(indicesPtr,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& a_indices) + : m_indices(a_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; + typedef typename MatrixType::Index Index; + + permut_matrix_product_retval(const PermutationType& perm, const MatrixType& matrix) + : m_permutation(perm), m_matrix(matrix) + {} + + inline Index rows() const { return m_matrix.rows(); } + inline Index cols() const { return m_matrix.cols(); } + + template<typename Dest> inline void evalTo(Dest& dst) const + { + const Index n = Side==OnTheLeft ? rows() : cols(); + // FIXME we need an is_same for expression that is not sensitive to constness. For instance + // is_same_xpr<Block<const Matrix>, Block<Matrix> >::value should be true. + if( is_same<MatrixTypeNestedCleaned,Dest>::value + && blas_traits<MatrixTypeNestedCleaned>::HasUsableDirectAccess + && blas_traits<Dest>::HasUsableDirectAccess + && 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); + Index 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 + Index k0 = r++; + Index kPrev = k0; + mask.coeffRef(k0) = true; + for(Index k=m_permutation.indices().coeff(k0); k!=k0; k=m_permutation.indices().coeff(k)) + { + Block<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 \ No newline at end of file
diff -r 000000000000 -r 13a5d365ba16 src/Core/PlainObjectBase.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/Core/PlainObjectBase.h Thu Oct 13 04:07:23 2016 +0000 @@ -0,0 +1,822 @@ +// 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 + +#if defined(EIGEN_INITIALIZE_MATRICES_BY_ZERO) +# define EIGEN_INITIALIZE_COEFFS +# define EIGEN_INITIALIZE_COEFFS_IF_THAT_OPTION_IS_ENABLED for(int i=0;i<base().size();++i) coeffRef(i)=Scalar(0); +#elif defined(EIGEN_INITIALIZE_MATRICES_BY_NAN) +# define EIGEN_INITIALIZE_COEFFS +# define EIGEN_INITIALIZE_COEFFS_IF_THAT_OPTION_IS_ENABLED for(int i=0;i<base().size();++i) coeffRef(i)=std::numeric_limits<Scalar>::quiet_NaN(); +#else +# undef EIGEN_INITIALIZE_COEFFS +# define EIGEN_INITIALIZE_COEFFS_IF_THAT_OPTION_IS_ENABLED +#endif + +namespace Eigen { + +namespace internal { + +template<int MaxSizeAtCompileTime> struct check_rows_cols_for_overflow { + template<typename Index> + static EIGEN_ALWAYS_INLINE void run(Index, Index) + { + } +}; + +template<> struct check_rows_cols_for_overflow<Dynamic> { + template<typename Index> + static EIGEN_ALWAYS_INLINE void run(Index rows, Index cols) + { + // http://hg.mozilla.org/mozilla-central/file/6c8a909977d3/xpcom/ds/CheckedInt.h#l242 + // we assume Index is signed + Index max_index = (size_t(1) << (8 * sizeof(Index) - 1)) - 1; // assume Index is signed + bool error = (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) && bool(OtherDerived::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 rowId, Index colId) const + { + if(Flags & RowMajorBit) + return m_storage.data()[colId + rowId * m_storage.cols()]; + else // column-major + return m_storage.data()[rowId + colId * m_storage.rows()]; + } + + EIGEN_STRONG_INLINE const Scalar& coeff(Index index) const + { + return m_storage.data()[index]; + } + + EIGEN_STRONG_INLINE Scalar& coeffRef(Index rowId, Index colId) + { + if(Flags & RowMajorBit) + return m_storage.data()[colId + rowId * m_storage.cols()]; + else // column-major + return m_storage.data()[rowId + colId * m_storage.rows()]; + } + + EIGEN_STRONG_INLINE Scalar& coeffRef(Index index) + { + return m_storage.data()[index]; + } + + EIGEN_STRONG_INLINE const Scalar& coeffRef(Index rowId, Index colId) const + { + if(Flags & RowMajorBit) + return m_storage.data()[colId + rowId * m_storage.cols()]; + else // column-major + return m_storage.data()[rowId + colId * 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 rowId, Index colId) const + { + return internal::ploadt<PacketScalar, LoadMode> + (m_storage.data() + (Flags & RowMajorBit + ? colId + rowId * m_storage.cols() + : rowId + colId * 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 rowId, Index colId, const PacketScalar& val) + { + internal::pstoret<Scalar, PacketScalar, StoreMode> + (m_storage.data() + (Flags & RowMajorBit + ? colId + rowId * m_storage.cols() + : rowId + colId * m_storage.rows()), val); + } + + /** \internal */ + template<int StoreMode> + EIGEN_STRONG_INLINE void writePacket(Index index, const PacketScalar& val) + { + internal::pstoret<Scalar, PacketScalar, StoreMode>(m_storage.data() + index, val); + } + + /** \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 nbRows, Index nbCols) + { + eigen_assert( EIGEN_IMPLIES(RowsAtCompileTime!=Dynamic,nbRows==RowsAtCompileTime) + && EIGEN_IMPLIES(ColsAtCompileTime!=Dynamic,nbCols==ColsAtCompileTime) + && EIGEN_IMPLIES(RowsAtCompileTime==Dynamic && MaxRowsAtCompileTime!=Dynamic,nbRows<=MaxRowsAtCompileTime) + && EIGEN_IMPLIES(ColsAtCompileTime==Dynamic && MaxColsAtCompileTime!=Dynamic,nbCols<=MaxColsAtCompileTime) + && nbRows>=0 && nbCols>=0 && "Invalid sizes when resizing a matrix or array."); + internal::check_rows_cols_for_overflow<MaxSizeAtCompileTime>::run(nbRows, nbCols); + #ifdef EIGEN_INITIALIZE_COEFFS + Index size = nbRows*nbCols; + bool size_changed = size != this->size(); + m_storage.resize(size, nbRows, nbCols); + if(size_changed) EIGEN_INITIALIZE_COEFFS_IF_THAT_OPTION_IS_ENABLED + #else + internal::check_rows_cols_for_overflow<MaxSizeAtCompileTime>::run(nbRows, nbCols); + m_storage.resize(nbRows*nbCols, nbRows, nbCols); + #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 && (MaxSizeAtCompileTime==Dynamic || size<=MaxSizeAtCompileTime)) || SizeAtCompileTime == size) && size>=0); + #ifdef EIGEN_INITIALIZE_COEFFS + 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_COEFFS + if(size_changed) EIGEN_INITIALIZE_COEFFS_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 nbCols) + { + resize(rows(), nbCols); + } + + /** 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 nbRows, NoChange_t) + { + resize(nbRows, 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<MaxSizeAtCompileTime>::run(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 nbRows, Index nbCols) + { + internal::conservative_resize_like_impl<Derived>::run(*this, nbRows, nbCols); + } + + /** 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 nbRows, NoChange_t) + { + // Note: see the comment in conservativeResize(Index,Index) + conservativeResize(nbRows, 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 nbCols) + { + // Note: see the comment in conservativeResize(Index,Index) + conservativeResize(rows(), nbCols); + } + + /** 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 PlainObjectBase() : m_storage() + { +// _check_template_params(); +// EIGEN_INITIALIZE_COEFFS_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_COEFFS_IF_THAT_OPTION_IS_ENABLED + } +#endif + +#ifdef EIGEN_HAVE_RVALUE_REFERENCES + PlainObjectBase(PlainObjectBase&& other) + : m_storage( std::move(other.m_storage) ) + { + } + + PlainObjectBase& operator=(PlainObjectBase&& other) + { + using std::swap; + swap(m_storage, other.m_storage); + return *this; + } +#endif + + /** Copy constructor */ + EIGEN_STRONG_INLINE PlainObjectBase(const PlainObjectBase& other) + : m_storage() + { + _check_template_params(); + lazyAssign(other); + } + + template<typename OtherDerived> + EIGEN_STRONG_INLINE PlainObjectBase(const DenseBase<OtherDerived> &other) + : m_storage() + { + _check_template_params(); + lazyAssign(other); + } + + EIGEN_STRONG_INLINE PlainObjectBase(Index a_size, Index nbRows, Index nbCols) + : m_storage(a_size, nbRows, nbCols) + { +// _check_template_params(); +// EIGEN_INITIALIZE_COEFFS_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<MaxSizeAtCompileTime>::run(other.derived().rows(), other.derived().cols()); + Base::operator=(other.derived()); + } + + /** \name Map + * These are convenience functions returning Map objects. The Map() static functions return unaligned Map objects, + * while the AlignedMap() functions return aligned Map objects and thus should be called only with 16-byte-aligned + * \a data pointers. + * + * \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"); + EIGEN_ONLY_USED_FOR_DEBUG(other); + if(this->size()==0) + resizeLike(other); + #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 nbRows, Index nbCols, 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) + resize(nbRows,nbCols); + } + template<typename T0, typename T1> + EIGEN_STRONG_INLINE void _init2(const Scalar& val0, const Scalar& val1, typename internal::enable_if<Base::SizeAtCompileTime==2,T0>::type* = 0) + { + EIGEN_STATIC_ASSERT_VECTOR_SPECIFIC_SIZE(PlainObjectBase, 2) + m_storage.data()[0] = val0; + m_storage.data()[1] = val1; + } + + 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 }; +}; + +namespace internal { + +template <typename Derived, typename OtherDerived, bool IsVector> +struct 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<Derived::MaxSizeAtCompileTime>::run(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); + } + } +}; + +// Here, the specialization for vectors inherits from the general matrix case +// to allow calling .conservativeResize(rows,cols) on vectors. +template <typename Derived, typename OtherDerived> +struct conservative_resize_like_impl<Derived,OtherDerived,true> + : conservative_resize_like_impl<Derived,OtherDerived,false> +{ + using conservative_resize_like_impl<Derived,OtherDerived,false>::run; + + 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 \ No newline at end of file
diff -r 000000000000 -r 13a5d365ba16 src/Core/ProductBase.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/Core/ProductBase.h Thu Oct 13 04:07:23 2016 +0000 @@ -0,0 +1,290 @@ +// 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: + +#ifndef EIGEN_NO_MALLOC + typedef typename Base::PlainObject BasePlainObject; + typedef Matrix<Scalar,RowsAtCompileTime==1?1:Dynamic,ColsAtCompileTime==1?1:Dynamic,BasePlainObject::Options> DynPlainObject; + typedef typename internal::conditional<(BasePlainObject::SizeAtCompileTime==Dynamic) || (BasePlainObject::SizeAtCompileTime*int(sizeof(Scalar)) < int(EIGEN_STACK_ALLOCATION_LIMIT)), + BasePlainObject, DynPlainObject>::type PlainObject; +#else + typedef typename Base::PlainObject PlainObject; +#endif + + ProductBase(const Lhs& a_lhs, const Rhs& a_rhs) + : m_lhs(a_lhs), m_rhs(a_rhs) + { + eigen_assert(a_lhs.cols() == a_rhs.rows() + && "invalid matrix product" + && "if you wanted a coeff-wise or a dot product use the respective explicit functions"); + } + + inline Index rows() const { return m_lhs.rows(); } + inline Index cols() const { return m_rhs.cols(); } + + template<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, const Scalar& alpha) const { derived().scaleAndAddTo(dst,alpha); } + + const _LhsNested& lhs() const { return m_lhs; } + const _RhsNested& rhs() const { return m_rhs; } + + // Implicit conversion to the nested type (trigger the evaluation of the product) + operator const PlainObject& () const + { + m_result.resize(m_lhs.rows(), m_rhs.cols()); + derived().evalTo(m_result); + return m_result; + } + + const Diagonal<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 typename GeneralProduct<Lhs,Rhs,Mode>::PlainObject const& type; +}; +template<typename Lhs, typename Rhs, int Mode, int N, typename PlainObject> +struct nested<const GeneralProduct<Lhs,Rhs,Mode>, N, PlainObject> +{ + typedef typename GeneralProduct<Lhs,Rhs,Mode>::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, const 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, const typename Derived::RealScalar& x) +{ return ScaledProduct<Derived>(prod.derived(), x); } + + +template<typename Derived,typename Lhs,typename Rhs> +const ScaledProduct<Derived> +operator*(const 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*(const 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, const 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, const Scalar& a_alpha) const { m_prod.derived().scaleAndAddTo(dst,a_alpha * m_alpha); } + + const Scalar& alpha() const { return m_alpha; } + + protected: + const NestedProduct& m_prod; + Scalar m_alpha; +}; + +/** \internal + * Overloaded to perform an efficient C = (A*B).lazy() */ +template<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 \ No newline at end of file
diff -r 000000000000 -r 13a5d365ba16 src/Core/Random.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/Core/Random.h Thu Oct 13 04:07:23 2016 +0000 @@ -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 newSize, 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 newSize) +{ + resize(newSize); + return setRandom(); +} + +/** Resizes to the given size, and sets all coefficients in this expression to random values. + * + * \param nbRows the new number of rows + * \param nbCols the new number of columns + * + * 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 nbRows, Index nbCols) +{ + resize(nbRows, nbCols); + return setRandom(); +} + +} // end namespace Eigen + +#endif // EIGEN_RANDOM_H \ No newline at end of file
diff -r 000000000000 -r 13a5d365ba16 src/Core/Redux.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/Core/Redux.h Thu Oct 13 04:07:23 2016 +0000 @@ -0,0 +1,409 @@ +// 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; + } +}; + +// NOTE: for SliceVectorizedTraversal we simply bypass unrolling +template<typename Func, typename Derived, int Unrolling> +struct redux_impl<Func, Derived, SliceVectorizedTraversal, Unrolling> +{ + 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 \c *this. + * \warning the result is undefined if \c *this contains NaN. + */ +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 \c *this. + * \warning the result is undefined if \c *this contains NaN. + */ +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 \ No newline at end of file
diff -r 000000000000 -r 13a5d365ba16 src/Core/Ref.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/Core/Ref.h Thu Oct 13 04:07:23 2016 +0000 @@ -0,0 +1,278 @@ +// 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_REF_H +#define EIGEN_REF_H + +namespace Eigen { + +template<typename Derived> class RefBase; +template<typename PlainObjectType, int Options = 0, + typename StrideType = typename internal::conditional<PlainObjectType::IsVectorAtCompileTime,InnerStride<1>,OuterStride<> >::type > class Ref; + +/** \class Ref + * \ingroup Core_Module + * + * \brief A matrix or vector expression mapping an existing expressions + * + * \tparam PlainObjectType the equivalent matrix type of the mapped data + * \tparam Options specifies whether the pointer is \c #Aligned, or \c #Unaligned. + * The default is \c #Unaligned. + * \tparam StrideType optionally specifies strides. By default, Ref implies a contiguous storage along the inner dimension (inner stride==1), + * but accept a variable outer stride (leading dimension). + * This can be overridden by specifying strides. + * The type passed here must be a specialization of the Stride template, see examples below. + * + * This class permits to write non template functions taking Eigen's object as parameters while limiting the number of copies. + * A Ref<> object can represent either a const expression or a l-value: + * \code + * // in-out argument: + * void foo1(Ref<VectorXf> x); + * + * // read-only const argument: + * void foo2(const Ref<const VectorXf>& x); + * \endcode + * + * In the in-out case, the input argument must satisfies the constraints of the actual Ref<> type, otherwise a compilation issue will be triggered. + * By default, a Ref<VectorXf> can reference any dense vector expression of float having a contiguous memory layout. + * Likewise, a Ref<MatrixXf> can reference any column major dense matrix expression of float whose column's elements are contiguously stored with + * the possibility to have a constant space inbetween each column, i.e.: the inner stride mmust be equal to 1, but the outer-stride (or leading dimension), + * can be greater than the number of rows. + * + * In the const case, if the input expression does not match the above requirement, then it is evaluated into a temporary before being passed to the function. + * Here are some examples: + * \code + * MatrixXf A; + * VectorXf a; + * foo1(a.head()); // OK + * foo1(A.col()); // OK + * foo1(A.row()); // compilation error because here innerstride!=1 + * foo2(A.row()); // The row is copied into a contiguous temporary + * foo2(2*a); // The expression is evaluated into a temporary + * foo2(A.col().segment(2,4)); // No temporary + * \endcode + * + * The range of inputs that can be referenced without temporary can be enlarged using the last two template parameter. + * Here is an example accepting an innerstride!=1: + * \code + * // in-out argument: + * void foo3(Ref<VectorXf,0,InnerStride<> > x); + * foo3(A.row()); // OK + * \endcode + * The downside here is that the function foo3 might be significantly slower than foo1 because it won't be able to exploit vectorization, and will involved more + * expensive address computations even if the input is contiguously stored in memory. To overcome this issue, one might propose to overloads internally calling a + * template function, e.g.: + * \code + * // in the .h: + * void foo(const Ref<MatrixXf>& A); + * void foo(const Ref<MatrixXf,0,Stride<> >& A); + * + * // in the .cpp: + * template<typename TypeOfA> void foo_impl(const TypeOfA& A) { + * ... // crazy code goes here + * } + * void foo(const Ref<MatrixXf>& A) { foo_impl(A); } + * void foo(const Ref<MatrixXf,0,Stride<> >& A) { foo_impl(A); } + * \endcode + * + * + * \sa PlainObjectBase::Map(), \ref TopicStorageOrders + */ + +namespace internal { + +template<typename _PlainObjectType, int _Options, typename _StrideType> +struct traits<Ref<_PlainObjectType, _Options, _StrideType> > + : public traits<Map<_PlainObjectType, _Options, _StrideType> > +{ + typedef _PlainObjectType PlainObjectType; + typedef _StrideType StrideType; + enum { + Options = _Options, + Flags = traits<Map<_PlainObjectType, _Options, _StrideType> >::Flags | NestByRefBit + }; + + template<typename Derived> struct match { + enum { + HasDirectAccess = internal::has_direct_access<Derived>::ret, + StorageOrderMatch = PlainObjectType::IsVectorAtCompileTime || Derived::IsVectorAtCompileTime || ((PlainObjectType::Flags&RowMajorBit)==(Derived::Flags&RowMajorBit)), + InnerStrideMatch = int(StrideType::InnerStrideAtCompileTime)==int(Dynamic) + || int(StrideType::InnerStrideAtCompileTime)==int(Derived::InnerStrideAtCompileTime) + || (int(StrideType::InnerStrideAtCompileTime)==0 && int(Derived::InnerStrideAtCompileTime)==1), + OuterStrideMatch = Derived::IsVectorAtCompileTime + || int(StrideType::OuterStrideAtCompileTime)==int(Dynamic) || int(StrideType::OuterStrideAtCompileTime)==int(Derived::OuterStrideAtCompileTime), + AlignmentMatch = (_Options!=Aligned) || ((PlainObjectType::Flags&AlignedBit)==0) || ((traits<Derived>::Flags&AlignedBit)==AlignedBit), + ScalarTypeMatch = internal::is_same<typename PlainObjectType::Scalar, typename Derived::Scalar>::value, + MatchAtCompileTime = HasDirectAccess && StorageOrderMatch && InnerStrideMatch && OuterStrideMatch && AlignmentMatch && ScalarTypeMatch + }; + typedef typename internal::conditional<MatchAtCompileTime,internal::true_type,internal::false_type>::type type; + }; + +}; + +template<typename Derived> +struct traits<RefBase<Derived> > : public traits<Derived> {}; + +} + +template<typename Derived> class RefBase + : public MapBase<Derived> +{ + typedef typename internal::traits<Derived>::PlainObjectType PlainObjectType; + typedef typename internal::traits<Derived>::StrideType StrideType; + +public: + + typedef MapBase<Derived> Base; + EIGEN_DENSE_PUBLIC_INTERFACE(RefBase) + + 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(); + } + + RefBase() + : Base(0,RowsAtCompileTime==Dynamic?0:RowsAtCompileTime,ColsAtCompileTime==Dynamic?0:ColsAtCompileTime), + // Stride<> does not allow default ctor for Dynamic strides, so let' initialize it with dummy values: + m_stride(StrideType::OuterStrideAtCompileTime==Dynamic?0:StrideType::OuterStrideAtCompileTime, + StrideType::InnerStrideAtCompileTime==Dynamic?0:StrideType::InnerStrideAtCompileTime) + {} + + EIGEN_INHERIT_ASSIGNMENT_OPERATORS(RefBase) + +protected: + + typedef Stride<StrideType::OuterStrideAtCompileTime,StrideType::InnerStrideAtCompileTime> StrideBase; + + template<typename Expression> + void construct(Expression& expr) + { + if(PlainObjectType::RowsAtCompileTime==1) + { + eigen_assert(expr.rows()==1 || expr.cols()==1); + ::new (static_cast<Base*>(this)) Base(expr.data(), 1, expr.size()); + } + else if(PlainObjectType::ColsAtCompileTime==1) + { + eigen_assert(expr.rows()==1 || expr.cols()==1); + ::new (static_cast<Base*>(this)) Base(expr.data(), expr.size(), 1); + } + else + ::new (static_cast<Base*>(this)) Base(expr.data(), expr.rows(), expr.cols()); + + if(Expression::IsVectorAtCompileTime && (!PlainObjectType::IsVectorAtCompileTime) && ((Expression::Flags&RowMajorBit)!=(PlainObjectType::Flags&RowMajorBit))) + ::new (&m_stride) StrideBase(expr.innerStride(), StrideType::InnerStrideAtCompileTime==0?0:1); + else + ::new (&m_stride) StrideBase(StrideType::OuterStrideAtCompileTime==0?0:expr.outerStride(), + StrideType::InnerStrideAtCompileTime==0?0:expr.innerStride()); + } + + StrideBase m_stride; +}; + + +template<typename PlainObjectType, int Options, typename StrideType> class Ref + : public RefBase<Ref<PlainObjectType, Options, StrideType> > +{ + private: + typedef internal::traits<Ref> Traits; + template<typename Derived> + inline Ref(const PlainObjectBase<Derived>& expr, + typename internal::enable_if<bool(Traits::template match<Derived>::MatchAtCompileTime),Derived>::type* = 0); + public: + + typedef RefBase<Ref> Base; + EIGEN_DENSE_PUBLIC_INTERFACE(Ref) + + + #ifndef EIGEN_PARSED_BY_DOXYGEN + template<typename Derived> + inline Ref(PlainObjectBase<Derived>& expr, + typename internal::enable_if<bool(Traits::template match<Derived>::MatchAtCompileTime),Derived>::type* = 0) + { + EIGEN_STATIC_ASSERT(static_cast<bool>(Traits::template match<Derived>::MatchAtCompileTime), STORAGE_LAYOUT_DOES_NOT_MATCH); + Base::construct(expr.derived()); + } + template<typename Derived> + inline Ref(const DenseBase<Derived>& expr, + typename internal::enable_if<bool(Traits::template match<Derived>::MatchAtCompileTime),Derived>::type* = 0) + #else + template<typename Derived> + inline Ref(DenseBase<Derived>& expr) + #endif + { + EIGEN_STATIC_ASSERT(static_cast<bool>(internal::is_lvalue<Derived>::value), THIS_EXPRESSION_IS_NOT_A_LVALUE__IT_IS_READ_ONLY); + EIGEN_STATIC_ASSERT(static_cast<bool>(Traits::template match<Derived>::MatchAtCompileTime), STORAGE_LAYOUT_DOES_NOT_MATCH); + enum { THIS_EXPRESSION_IS_NOT_A_LVALUE__IT_IS_READ_ONLY = Derived::ThisConstantIsPrivateInPlainObjectBase}; + Base::construct(expr.const_cast_derived()); + } + + EIGEN_INHERIT_ASSIGNMENT_OPERATORS(Ref) + +}; + +// this is the const ref version +template<typename TPlainObjectType, int Options, typename StrideType> class Ref<const TPlainObjectType, Options, StrideType> + : public RefBase<Ref<const TPlainObjectType, Options, StrideType> > +{ + typedef internal::traits<Ref> Traits; + public: + + typedef RefBase<Ref> Base; + EIGEN_DENSE_PUBLIC_INTERFACE(Ref) + + template<typename Derived> + inline Ref(const DenseBase<Derived>& expr, + typename internal::enable_if<bool(Traits::template match<Derived>::ScalarTypeMatch),Derived>::type* = 0) + { +// std::cout << match_helper<Derived>::HasDirectAccess << "," << match_helper<Derived>::OuterStrideMatch << "," << match_helper<Derived>::InnerStrideMatch << "\n"; +// std::cout << int(StrideType::OuterStrideAtCompileTime) << " - " << int(Derived::OuterStrideAtCompileTime) << "\n"; +// std::cout << int(StrideType::InnerStrideAtCompileTime) << " - " << int(Derived::InnerStrideAtCompileTime) << "\n"; + construct(expr.derived(), typename Traits::template match<Derived>::type()); + } + + inline Ref(const Ref& other) : Base(other) { + // copy constructor shall not copy the m_object, to avoid unnecessary malloc and copy + } + + template<typename OtherRef> + inline Ref(const RefBase<OtherRef>& other) { + construct(other.derived(), typename Traits::template match<OtherRef>::type()); + } + + protected: + + template<typename Expression> + void construct(const Expression& expr,internal::true_type) + { + Base::construct(expr); + } + + template<typename Expression> + void construct(const Expression& expr, internal::false_type) + { + m_object.lazyAssign(expr); + Base::construct(m_object); + } + + protected: + TPlainObjectType m_object; +}; + +} // end namespace Eigen + +#endif // EIGEN_REF_H \ No newline at end of file
diff -r 000000000000 -r 13a5d365ba16 src/Core/Replicate.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/Core/Replicate.h Thu Oct 13 04:07:23 2016 +0000 @@ -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& a_matrix) + : m_matrix(a_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& a_matrix, Index rowFactor, Index colFactor) + : m_matrix(a_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 rowId, Index colId) const + { + // try to avoid using modulo; this is a pure optimization strategy + const Index actual_row = internal::traits<MatrixType>::RowsAtCompileTime==1 ? 0 + : RowFactor==1 ? rowId + : rowId%m_matrix.rows(); + const Index actual_col = internal::traits<MatrixType>::ColsAtCompileTime==1 ? 0 + : ColFactor==1 ? colId + : colId%m_matrix.cols(); + + return m_matrix.coeff(actual_row, actual_col); + } + template<int LoadMode> + inline PacketScalar packet(Index rowId, Index colId) const + { + const Index actual_row = internal::traits<MatrixType>::RowsAtCompileTime==1 ? 0 + : RowFactor==1 ? rowId + : rowId%m_matrix.rows(); + const Index actual_col = internal::traits<MatrixType>::ColsAtCompileTime==1 ? 0 + : ColFactor==1 ? colId + : colId%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> +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> +const typename DenseBase<Derived>::ReplicateReturnType +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 \ No newline at end of file
diff -r 000000000000 -r 13a5d365ba16 src/Core/ReturnByValue.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/Core/ReturnByValue.h Thu Oct 13 04:07:23 2016 +0000 @@ -0,0 +1,99 @@ +// 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 + : internal::no_assignment_operator, 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); } + template<int LoadMode> Unusable& packet(Index) const; + template<int LoadMode> Unusable& packet(Index, Index) const; +#endif +}; + +template<typename Derived> +template<typename OtherDerived> +Derived& DenseBase<Derived>::operator=(const ReturnByValue<OtherDerived>& other) +{ + other.evalTo(derived()); + return derived(); +} + +template<typename Derived> +template<typename OtherDerived> +Derived& DenseBase<Derived>::lazyAssign(const ReturnByValue<OtherDerived>& other) +{ + other.evalTo(derived()); + return derived(); +} + + +} // end namespace Eigen + +#endif // EIGEN_RETURNBYVALUE_H \ No newline at end of file
diff -r 000000000000 -r 13a5d365ba16 src/Core/Reverse.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/Core/Reverse.h Thu Oct 13 04:07:23 2016 +0000 @@ -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 \ No newline at end of file
diff -r 000000000000 -r 13a5d365ba16 src/Core/Select.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/Core/Select.h Thu Oct 13 04:07:23 2016 +0000 @@ -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& a_conditionMatrix, + const ThenMatrixType& a_thenMatrix, + const ElseMatrixType& a_elseMatrix) + : m_condition(a_conditionMatrix), m_then(a_thenMatrix), m_else(a_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, + const 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(const 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 \ No newline at end of file
diff -r 000000000000 -r 13a5d365ba16 src/Core/SelfAdjointView.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/Core/SelfAdjointView.h Thu Oct 13 04:07:23 2016 +0000 @@ -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, const Scalar& alpha = Scalar(1)); + + /** Perform a symmetric rank K update of the selfadjoint matrix \c *this: + * \f$ this = this + \alpha ( u u^* ) \f$ where \a u is a vector or matrix. + * + * \returns a reference to \c *this + * + * Note that to perform \f$ this = this + \alpha ( u^* u ) \f$ you can simply + * call this function with u.adjoint(). + * + * \sa rankUpdate(const MatrixBase<DerivedU>&, const MatrixBase<DerivedV>&, Scalar) + */ + template<typename DerivedU> + SelfAdjointView& rankUpdate(const MatrixBase<DerivedU>& u, const 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) = numext::real(src.coeff(row, col)); + else if(row < col) + dst.coeffRef(col, row) = numext::conj(dst.coeffRef(row, col) = src.coeff(row, col)); + } +}; + +template<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) = numext::real(src.coeff(row, col)); + else if(row > col) + dst.coeffRef(col, row) = numext::conj(dst.coeffRef(row, col) = src.coeff(row, col)); + } +}; + +template<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) = numext::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) = numext::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 \ No newline at end of file
diff -r 000000000000 -r 13a5d365ba16 src/Core/SelfCwiseBinaryOp.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/Core/SelfCwiseBinaryOp.h Thu Oct 13 04:07:23 2016 +0000 @@ -0,0 +1,191 @@ +// 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 Derived::PlainObject PlainObject; + SelfCwiseBinaryOp<internal::scalar_quotient_op<Scalar>, Derived, typename PlainObject::ConstantReturnType> tmp(derived()); + tmp = PlainObject::Constant(rows(),cols(), other); + return derived(); +} + +} // end namespace Eigen + +#endif // EIGEN_SELFCWISEBINARYOP_H \ No newline at end of file
diff -r 000000000000 -r 13a5d365ba16 src/Core/SolveTriangular.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/Core/SolveTriangular.h Thu Oct 13 04:07:23 2016 +0000 @@ -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), + RowIndex = IsLower ? Index : Size - Index - 1, + S = IsLower ? 0 : RowIndex+1 + }; + static void run(const Lhs& lhs, Rhs& rhs) + { + if (Index>0) + rhs.coeffRef(RowIndex) -= lhs.row(RowIndex).template segment<Index>(S).transpose() + .cwiseProduct(rhs.template segment<Index>(S)).sum(); + + if(!(Mode & UnitDiag)) + rhs.coeffRef(RowIndex) /= lhs.coeff(RowIndex,RowIndex); + + 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 \ No newline at end of file
diff -r 000000000000 -r 13a5d365ba16 src/Core/StableNorm.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/Core/StableNorm.h Thu Oct 13 04:07:23 2016 +0000 @@ -0,0 +1,203 @@ +// 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) +{ + using std::max; + Scalar maxCoeff = bl.cwiseAbs().maxCoeff(); + + if (maxCoeff>scale) + { + ssq = ssq * numext::abs2(scale/maxCoeff); + Scalar tmp = Scalar(1)/maxCoeff; + if(tmp > NumTraits<Scalar>::highest()) + { + invScale = NumTraits<Scalar>::highest(); + scale = Scalar(1)/invScale; + } + else + { + scale = maxCoeff; + invScale = tmp; + } + } + + // TODO if the maxCoeff is much much smaller than the current scale, + // then we can neglect this sub vector + if(scale>Scalar(0)) // if scale==0, then bl is 0 + ssq += (bl*invScale).squaredNorm(); +} + +template<typename Derived> +inline typename NumTraits<typename traits<Derived>::Scalar>::Real +blueNorm_impl(const EigenBase<Derived>& _vec) +{ + typedef typename Derived::RealScalar RealScalar; + typedef typename Derived::Index Index; + using std::pow; + using std::min; + using std::max; + using std::sqrt; + using std::abs; + const Derived& vec(_vec.derived()); + static bool initialized = false; + static RealScalar b1, b2, s1m, s2m, overfl, rbig, relerr; + if(!initialized) + { + int ibeta, it, iemin, iemax, iexp; + RealScalar eps; + // This program calculates the machine-dependent constants + // bl, b2, slm, s2m, relerr overfl + // 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 + 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 = sqrt(eps); // tolerance for neglecting asml + initialized = true; + } + Index n = vec.size(); + RealScalar ab2 = b2 / RealScalar(n); + RealScalar asml = RealScalar(0); + RealScalar amed = RealScalar(0); + RealScalar abig = RealScalar(0); + for(typename Derived::InnerIterator it(vec, 0); it; ++it) + { + RealScalar ax = abs(it.value()); + if(ax > ab2) abig += numext::abs2(ax*s2m); + else if(ax < b1) asml += numext::abs2(ax*s1m); + else amed += numext::abs2(ax); + } + if(abig > RealScalar(0)) + { + abig = sqrt(abig); + if(abig > overfl) + { + return rbig; + } + if(amed > RealScalar(0)) + { + abig = abig/s2m; + amed = sqrt(amed); + } + else + return abig/s2m; + } + else if(asml > RealScalar(0)) + { + if (amed > RealScalar(0)) + { + abig = sqrt(amed); + amed = sqrt(asml) / s1m; + } + else + return sqrt(asml)/s1m; + } + else + return sqrt(amed); + asml = (min)(abig, amed); + abig = (max)(abig, amed); + if(asml <= abig*relerr) + return abig; + else + return abig * sqrt(RealScalar(1) + numext::abs2(asml/abig)); +} + +} // end namespace internal + +/** \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; + using std::sqrt; + 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 * 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 +{ + return internal::blueNorm_impl(*this); +} + +/** \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 \ No newline at end of file
diff -r 000000000000 -r 13a5d365ba16 src/Core/Stride.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/Core/Stride.h Thu Oct 13 04:07:23 2016 +0000 @@ -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 \ No newline at end of file
diff -r 000000000000 -r 13a5d365ba16 src/Core/Swap.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/Core/Swap.h Thu Oct 13 04:07:23 2016 +0000 @@ -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 rowId, Index colId) + { + return m_expression.const_cast_derived().coeffRef(rowId, colId); + } + + inline Scalar& coeffRef(Index index) + { + return m_expression.const_cast_derived().coeffRef(index); + } + + inline Scalar& coeffRef(Index rowId, Index colId) const + { + return m_expression.coeffRef(rowId, colId); + } + + inline Scalar& coeffRef(Index index) const + { + return m_expression.coeffRef(index); + } + + template<typename OtherDerived> + void copyCoeff(Index rowId, Index colId, const DenseBase<OtherDerived>& other) + { + OtherDerived& _other = other.const_cast_derived(); + eigen_internal_assert(rowId >= 0 && rowId < rows() + && colId >= 0 && colId < cols()); + Scalar tmp = m_expression.coeff(rowId, colId); + m_expression.coeffRef(rowId, colId) = _other.coeff(rowId, colId); + _other.coeffRef(rowId, colId) = tmp; + } + + template<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 rowId, Index colId, const DenseBase<OtherDerived>& other) + { + OtherDerived& _other = other.const_cast_derived(); + eigen_internal_assert(rowId >= 0 && rowId < rows() + && colId >= 0 && colId < cols()); + Packet tmp = m_expression.template packet<StoreMode>(rowId, colId); + m_expression.template writePacket<StoreMode>(rowId, colId, + _other.template packet<LoadMode>(rowId, colId) + ); + _other.template writePacket<LoadMode>(rowId, colId, 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 \ No newline at end of file
diff -r 000000000000 -r 13a5d365ba16 src/Core/Transpose.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/Core/Transpose.h Thu Oct 13 04:07:23 2016 +0000 @@ -0,0 +1,419 @@ +// 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& a_matrix) : m_matrix(a_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>) + EIGEN_INHERIT_ASSIGNMENT_OPERATORS(TransposeImpl) + + 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 rowId, Index colId) + { + EIGEN_STATIC_ASSERT_LVALUE(MatrixType) + return derived().nestedExpression().const_cast_derived().coeffRef(colId, rowId); + } + + inline ScalarWithConstIfNotLvalue& coeffRef(Index index) + { + EIGEN_STATIC_ASSERT_LVALUE(MatrixType) + return derived().nestedExpression().const_cast_derived().coeffRef(index); + } + + inline const Scalar& coeffRef(Index rowId, Index colId) const + { + return derived().nestedExpression().coeffRef(colId, rowId); + } + + inline const Scalar& coeffRef(Index index) const + { + return derived().nestedExpression().coeffRef(index); + } + + inline CoeffReturnType coeff(Index rowId, Index colId) const + { + return derived().nestedExpression().coeff(colId, rowId); + } + + inline CoeffReturnType coeff(Index index) const + { + return derived().nestedExpression().coeff(index); + } + + template<int LoadMode> + inline const PacketScalar packet(Index rowId, Index colId) const + { + return derived().nestedExpression().template packet<LoadMode>(colId, rowId); + } + + template<int LoadMode> + inline void writePacket(Index rowId, Index colId, const PacketScalar& x) + { + derived().nestedExpression().const_cast_derived().template writePacket<LoadMode>(colId, rowId, 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 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.matrix().template triangularView<StrictlyUpper>().swap(m.matrix().transpose()); + } +}; + +template<typename MatrixType> +struct inplace_transpose_selector<MatrixType,false> { // non square matrix + static void run(MatrixType& m) { + if (m.rows()==m.cols()) + m.matrix().template triangularView<StrictlyUpper>().swap(m.matrix().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 \ref TopicAliasing "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. + * This excludes (non-square) fixed-size matrices, block-expressions and maps. + * + * \sa transpose(), adjoint(), adjointInPlace() */ +template<typename Derived> +inline void DenseBase<Derived>::transposeInPlace() +{ + eigen_assert((rows() == cols() || (RowsAtCompileTime == Dynamic && ColsAtCompileTime == Dynamic)) + && "transposeInPlace() called on a non-square non-resizable matrix"); + 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. + * This excludes (non-square) fixed-size matrices, block-expressions and maps. + * + * \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==(const 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==(const Scalar*)extract_data(src.lhs()))) + || ((blas_traits<DerivedB>::IsTransposed != DestIsTransposed) && (dest!=0 && dest==(const 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 transposition, 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 \ No newline at end of file
diff -r 000000000000 -r 13a5d365ba16 src/Core/Transpositions.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/Core/Transpositions.h Thu Oct 13 04:07:23 2016 +0000 @@ -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 newSize) + { + indices().resize(newSize); + } + + /** 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>& a_indices) : m_indices(a_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* indicesPtr) + : m_indices(indicesPtr) + {} + + inline Map(const Index* indicesPtr, Index size) + : m_indices(indicesPtr,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& a_indices) + : m_indices(a_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 \ No newline at end of file
diff -r 000000000000 -r 13a5d365ba16 src/Core/TriangularMatrix.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/Core/TriangularMatrix.h Thu Oct 13 04:07:23 2016 +0000 @@ -0,0 +1,839 @@ +// 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::ColsAtCompileTime==1> + operator*(const MatrixBase<OtherDerived>& rhs) const + { + return TriangularProduct + <Mode, true, MatrixType, false, OtherDerived, OtherDerived::ColsAtCompileTime==1> + (m_matrix, rhs.derived()); + } + + /** Efficient vector/matrix times triangular matrix product */ + template<typename OtherDerived> friend + TriangularProduct<Mode, false, OtherDerived, OtherDerived::RowsAtCompileTime==1, MatrixType, false> + operator*(const MatrixBase<OtherDerived>& lhs, const TriangularView& rhs) + { + return TriangularProduct + <Mode, false, OtherDerived, OtherDerived::RowsAtCompileTime==1, 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.derived(),1); + } + + template<typename ProductDerived, typename Lhs, typename Rhs> + EIGEN_STRONG_INLINE TriangularView& operator+=(const ProductBase<ProductDerived, Lhs,Rhs>& other) + { + return assignProduct(other.derived(),1); + } + + template<typename ProductDerived, typename Lhs, typename Rhs> + EIGEN_STRONG_INLINE TriangularView& operator-=(const ProductBase<ProductDerived, Lhs,Rhs>& other) + { + return assignProduct(other.derived(),-1); + } + + + template<typename ProductDerived> + EIGEN_STRONG_INLINE TriangularView& operator=(const ScaledProduct<ProductDerived>& other) + { + setZero(); + return assignProduct(other.derived(),other.alpha()); + } + + template<typename ProductDerived> + EIGEN_STRONG_INLINE TriangularView& operator+=(const ScaledProduct<ProductDerived>& other) + { + return assignProduct(other.derived(),other.alpha()); + } + + template<typename ProductDerived> + EIGEN_STRONG_INLINE TriangularView& operator-=(const ScaledProduct<ProductDerived>& other) + { + return assignProduct(other.derived(),-other.alpha()); + } + + protected: + + template<typename ProductDerived, typename Lhs, typename Rhs> + EIGEN_STRONG_INLINE TriangularView& assignProduct(const ProductBase<ProductDerived, Lhs,Rhs>& prod, const Scalar& alpha); + + template<int Mode, bool LhsIsTriangular, + typename Lhs, bool LhsIsVector, + typename Rhs, bool RhsIsVector> + EIGEN_STRONG_INLINE TriangularView& assignProduct(const TriangularProduct<Mode, LhsIsTriangular, Lhs, LhsIsVector, Rhs, RhsIsVector>& prod, const Scalar& alpha) + { + lazyAssign(alpha*prod.eval()); + return *this; + } + + 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; + typedef typename Derived1::Scalar Scalar; + static inline void run(Derived1 &dst, const Derived2 &src) + { + for(Index j = 0; j < dst.cols(); ++j) + { + Index maxi = (std::min)(j, dst.rows()); + for(Index i = 0; i < maxi; ++i) + dst.copyCoeff(i, j, src); + if (ClearOpposite) + for(Index i = maxi; i < dst.rows(); ++i) + dst.coeffRef(i, j) = Scalar(0); + } + } +}; + +template<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(const RealScalar& prec) const +{ + using std::abs; + 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 = abs(coeff(i,j)); + if(absValue > maxAbsOnUpperPart) maxAbsOnUpperPart = absValue; + } + } + RealScalar threshold = maxAbsOnUpperPart * prec; + for(Index j = 0; j < cols(); ++j) + for(Index i = j+1; i < rows(); ++i) + if(abs(coeff(i, j)) > threshold) return false; + return true; +} + +/** \returns true if *this is approximately equal to a lower triangular matrix, + * within the precision given by \a prec. + * + * \sa isUpperTriangular() + */ +template<typename Derived> +bool MatrixBase<Derived>::isLowerTriangular(const RealScalar& prec) const +{ + using std::abs; + RealScalar maxAbsOnLowerPart = static_cast<RealScalar>(-1); + for(Index j = 0; j < cols(); ++j) + for(Index i = j; i < rows(); ++i) + { + RealScalar absValue = abs(coeff(i,j)); + if(absValue > maxAbsOnLowerPart) maxAbsOnLowerPart = absValue; + } + RealScalar threshold = maxAbsOnLowerPart * prec; + for(Index j = 1; j < cols(); ++j) + { + Index maxi = (std::min)(j, rows()-1); + for(Index i = 0; i < maxi; ++i) + if(abs(coeff(i, j)) > threshold) return false; + } + return true; +} + +} // end namespace Eigen + +#endif // EIGEN_TRIANGULARMATRIX_H \ No newline at end of file
diff -r 000000000000 -r 13a5d365ba16 src/Core/VectorBlock.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/Core/VectorBlock.h Thu Oct 13 04:07:23 2016 +0000 @@ -0,0 +1,95 @@ +// 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); + } +}; + + +} // end namespace Eigen + +#endif // EIGEN_VECTORBLOCK_H \ No newline at end of file
diff -r 000000000000 -r 13a5d365ba16 src/Core/VectorwiseOp.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/Core/VectorwiseOp.h Thu Oct 13 04:07:23 2016 +0000 @@ -0,0 +1,642 @@ +// 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 ? MatrixType::RowsAtCompileTime : MatrixType::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==Dynamic ? Dynamic + : 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()); + } + + template<typename OtherDerived> struct OppositeExtendedType { + typedef Replicate<OtherDerived, + Direction==Horizontal ? 1 : ExpressionType::RowsAtCompileTime, + Direction==Vertical ? 1 : ExpressionType::ColsAtCompileTime> Type; + }; + + /** \internal + * Replicates a vector in the opposite direction to match the size of \c *this */ + template<typename OtherDerived> + typename OppositeExtendedType<OtherDerived>::Type + extendedToOpposite(const DenseBase<OtherDerived>& other) const + { + EIGEN_STATIC_ASSERT(EIGEN_IMPLIES(Direction==Horizontal, OtherDerived::MaxColsAtCompileTime==1), + YOU_PASSED_A_ROW_VECTOR_BUT_A_COLUMN_VECTOR_WAS_EXPECTED) + EIGEN_STATIC_ASSERT(EIGEN_IMPLIES(Direction==Vertical, OtherDerived::MaxRowsAtCompileTime==1), + YOU_PASSED_A_COLUMN_VECTOR_BUT_A_ROW_VECTOR_WAS_EXPECTED) + return typename OppositeExtendedType<OtherDerived>::Type + (other.derived(), + Direction==Horizontal ? 1 : m_matrix.rows(), + Direction==Vertical ? 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. + * + * \warning the result is undefined if \c *this contains NaN. + * + * 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. + * + * \warning the result is undefined if \c *this contains NaN. + * + * 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()); + } + + /** \returns an expression where each column of row of the referenced matrix are normalized. + * The referenced matrix is \b not modified. + * \sa MatrixBase::normalized(), normalize() + */ + CwiseBinaryOp<internal::scalar_quotient_op<Scalar>, + const ExpressionTypeNestedCleaned, + const typename OppositeExtendedType<typename ReturnType<internal::member_norm,RealScalar>::Type>::Type> + normalized() const { return m_matrix.cwiseQuotient(extendedToOpposite(this->norm())); } + + + /** Normalize in-place each row or columns of the referenced matrix. + * \sa MatrixBase::normalize(), normalized() + */ + void normalize() { + m_matrix = this->normalized(); + } + +/////////// 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 \ No newline at end of file
diff -r 000000000000 -r 13a5d365ba16 src/Core/Visitor.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/Core/Visitor.h Thu Oct 13 04:07:23 2016 +0000 @@ -0,0 +1,240 @@ +// 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 +{ + typedef typename internal::remove_all<typename Derived::Nested>::type ThisNested; + typename Derived::Nested thisNested(derived()); + + 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, ThisNested, + unroll ? int(SizeAtCompileTime) : Dynamic + >::run(thisNested, 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. + * \warning the result is undefined if \c *this contains NaN. + * + * \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* rowId, IndexType* colId) const +{ + internal::min_coeff_visitor<Derived> minVisitor; + this->visit(minVisitor); + *rowId = minVisitor.row; + if (colId) *colId = minVisitor.col; + return minVisitor.res; +} + +/** \returns the minimum of all coefficients of *this and puts in *index its location. + * \warning the result is undefined if \c *this contains NaN. + * + * \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. + * \warning the result is undefined if \c *this contains NaN. + * + * \sa DenseBase::minCoeff(IndexType*,IndexType*), DenseBase::visitor(), DenseBase::maxCoeff() + */ +template<typename Derived> +template<typename IndexType> +typename internal::traits<Derived>::Scalar +DenseBase<Derived>::maxCoeff(IndexType* rowPtr, IndexType* colPtr) const +{ + internal::max_coeff_visitor<Derived> maxVisitor; + this->visit(maxVisitor); + *rowPtr = maxVisitor.row; + if (colPtr) *colPtr = maxVisitor.col; + return maxVisitor.res; +} + +/** \returns the maximum of all coefficients of *this and puts in *index its location. + * \warning the result is undefined if \c *this contains NaN. + * + * \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 \ No newline at end of file
diff -r 000000000000 -r 13a5d365ba16 src/Core/arch/Default/Settings.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/Core/arch/Default/Settings.h Thu Oct 13 04:07:23 2016 +0000 @@ -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 \ No newline at end of file
diff -r 000000000000 -r 13a5d365ba16 src/Core/products/CoeffBasedProduct.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/Core/products/CoeffBasedProduct.h Thu Oct 13 04:07:23 2016 +0000 @@ -0,0 +1,476 @@ +// 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 == 0 ? 0 + : 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 : 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::scalar_product_traits<typename Lhs::RealScalar, typename Rhs::RealScalar>::Defined), + YOU_MIXED_DIFFERENT_NUMERIC_TYPES__YOU_NEED_TO_USE_THE_CAST_METHOD_OF_MATRIXBASE_TO_CAST_NUMERIC_TYPES_EXPLICITLY) + eigen_assert(lhs.cols() == rhs.rows() + && "invalid matrix product" + && "if you wanted a coeff-wise or a dot product use the respective explicit functions"); + } + + EIGEN_STRONG_INLINE Index rows() const { return m_lhs.rows(); } + EIGEN_STRONG_INLINE Index cols() const { return m_rhs.cols(); } + + EIGEN_STRONG_INLINE const Scalar coeff(Index row, Index col) const + { + Scalar res; + ScalarCoeffImpl::run(row, col, m_lhs, m_rhs, res); + return res; + } + + /* Allow index-based non-packet access. It is impossible though to allow index-based packed access, + * which is why we don't set the LinearAccessBit. + */ + EIGEN_STRONG_INLINE const Scalar coeff(Index index) const + { + Scalar res; + const Index row = RowsAtCompileTime == 1 ? 0 : index; + const Index col = RowsAtCompileTime == 1 ? index : 0; + ScalarCoeffImpl::run(row, col, m_lhs, m_rhs, res); + return res; + } + + template<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 : 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-1) * rhs.coeff(UnrollingIndex-1, col); + } +}; + +template<typename Lhs, typename Rhs, typename RetScalar> +struct product_coeff_impl<DefaultTraversal, 1, 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, 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 = RetScalar(0); + } +}; + +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) + { + res = (lhs.row(row).transpose().cwiseProduct( rhs.col(col) )).sum(); + } +}; + +/******************************************* +*** 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<typename Lhs, typename Rhs, typename RetScalar> +struct product_coeff_impl<InnerVectorizedTraversal, 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 = 0; + } +}; + +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-PacketSize, Lhs, Rhs, Packet>::run(row, col, lhs, rhs, pres); + 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-1)), rhs.template packet<LoadMode>(UnrollingIndex-1, 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-1), pset1<Packet>(rhs.coeff(UnrollingIndex-1, col)), res); + } +}; + +template<typename Lhs, typename Rhs, typename Packet, int LoadMode> +struct product_packet_impl<RowMajor, 1, 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, 1, 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, 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 = pset1<Packet>(0); + } +}; + +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 = pset1<Packet>(0); + } +}; + +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) + { + res = pset1<Packet>(0); + for(Index i = 0; 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) + { + res = pset1<Packet>(0); + for(Index i = 0; 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 \ No newline at end of file
diff -r 000000000000 -r 13a5d365ba16 src/Core/products/GeneralBlockPanelKernel.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/Core/products/GeneralBlockPanelKernel.h Thu Oct 13 04:07:23 2016 +0000 @@ -0,0 +1,1341 @@ +// 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, typename SizeType> +void computeProductBlockingSizes(SizeType& k, SizeType& m, SizeType& n) +{ + EIGEN_UNUSED_VARIABLE(n); + // Explanations: + // Let's recall the product algorithms form kc x nc horizontal panels B' on the rhs and + // mc x kc blocks A' on the lhs. A' has to fit into L2 cache. Moreover, B' is processed + // per kc x nr vertical small panels where nr is the blocking size along the n dimension + // at the register level. For vectorization purpose, these small vertical panels are unpacked, + // e.g., each coefficient is replicated to fit a packet. This small vertical panel has to + // stay in L1 cache. + std::ptrdiff_t l1, l2; + + typedef gebp_traits<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<SizeType>(k, l1/kdiv); + SizeType _m = k>0 ? l2/(4 * sizeof(LhsScalar) * k) : 0; + if(_m<m) m = _m & mr_mask; +} + +template<typename LhsScalar, typename RhsScalar, typename SizeType> +inline void computeProductBlockingSizes(SizeType& k, SizeType& m, SizeType& 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 + void operator()(ResScalar* res, Index resStride, const LhsScalar* blockA, const RhsScalar* blockB, Index rows, Index depth, Index cols, ResScalar alpha, + Index strideA=-1, Index strideB=-1, Index offsetA=0, Index offsetB=0, RhsScalar* unpackedB=0); +}; + +template<typename LhsScalar, typename RhsScalar, typename Index, int mr, int nr, bool ConjugateLhs, bool ConjugateRhs> +EIGEN_DONT_INLINE +void gebp_kernel<LhsScalar,RhsScalar,Index,mr,nr,ConjugateLhs,ConjugateRhs> + ::operator()(ResScalar* res, Index resStride, const LhsScalar* blockA, const RhsScalar* blockB, Index rows, Index depth, Index cols, ResScalar alpha, + Index strideA, Index strideB, Index offsetA, Index offsetB, RhsScalar* unpackedB) + { + Traits traits; + + if(strideA==-1) strideA = depth; + if(strideB==-1) strideB = depth; + conj_helper<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); +}; + +template<typename Scalar, typename Index, int Pack1, int Pack2, int StorageOrder, bool Conjugate, bool PanelMode> +EIGEN_DONT_INLINE void gemm_pack_lhs<Scalar, Index, Pack1, Pack2, StorageOrder, Conjugate, PanelMode> + ::operator()(Scalar* blockA, const Scalar* EIGEN_RESTRICT _lhs, Index lhsStride, Index depth, Index rows, Index stride, Index offset) +{ + typedef typename packet_traits<Scalar>::type Packet; + enum { PacketSize = packet_traits<Scalar>::size }; + + EIGEN_ASM_COMMENT("EIGEN PRODUCT PACK LHS"); + EIGEN_UNUSED_VARIABLE(stride) + EIGEN_UNUSED_VARIABLE(offset) + eigen_assert(((!PanelMode) && stride==0 && offset==0) || (PanelMode && stride>=depth && offset<=stride)); + eigen_assert( (StorageOrder==RowMajor) || ((Pack1%PacketSize)==0 && Pack1<=4*PacketSize) ); + conj_if<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); +}; + +template<typename Scalar, typename Index, int nr, bool Conjugate, bool PanelMode> +EIGEN_DONT_INLINE void gemm_pack_rhs<Scalar, Index, nr, ColMajor, Conjugate, PanelMode> + ::operator()(Scalar* blockB, const Scalar* rhs, Index rhsStride, Index depth, Index cols, Index stride, Index offset) +{ + EIGEN_ASM_COMMENT("EIGEN PRODUCT PACK RHS COLMAJOR"); + EIGEN_UNUSED_VARIABLE(stride) + EIGEN_UNUSED_VARIABLE(offset) + eigen_assert(((!PanelMode) && stride==0 && offset==0) || (PanelMode && stride>=depth && offset<=stride)); + conj_if<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); +}; + +template<typename Scalar, typename Index, int nr, bool Conjugate, bool PanelMode> +EIGEN_DONT_INLINE void gemm_pack_rhs<Scalar, Index, nr, RowMajor, Conjugate, PanelMode> + ::operator()(Scalar* blockB, const Scalar* rhs, Index rhsStride, Index depth, Index cols, Index stride, Index offset) +{ + EIGEN_ASM_COMMENT("EIGEN PRODUCT PACK RHS ROWMAJOR"); + EIGEN_UNUSED_VARIABLE(stride) + EIGEN_UNUSED_VARIABLE(offset) + eigen_assert(((!PanelMode) && stride==0 && offset==0) || (PanelMode && stride>=depth && offset<=stride)); + conj_if<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 \ No newline at end of file
diff -r 000000000000 -r 13a5d365ba16 src/Core/products/GeneralMatrixMatrix.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/Core/products/GeneralMatrixMatrix.h Thu Oct 13 04:07:23 2016 +0000 @@ -0,0 +1,433 @@ +// 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 -= 1; + } + } + } + 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, const Scalar& actualAlpha, + BlockingType& blocking) + : m_lhs(lhs), m_rhs(rhs), m_dest(dest), m_actualAlpha(actualAlpha), m_blocking(blocking) + {} + + void initParallelSession() const + { + m_blocking.allocateB(); + } + + void operator() (Index row, Index rows, Index col=0, Index cols=-1, GemmParallelInfo<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) + { +#if !(defined(EIGEN_NO_STATIC_ASSERT) && defined(EIGEN_NO_DEBUG)) + typedef internal::scalar_product_op<LhsScalar,RhsScalar> BinOp; + EIGEN_CHECK_BINARY_COMPATIBILIY(BinOp,LhsScalar,RhsScalar); +#endif + } + + template<typename Dest> void scaleAndAddTo(Dest& dst, const Scalar& alpha) const + { + eigen_assert(dst.rows()==m_lhs.rows() && dst.cols()==m_rhs.cols()); + if(m_lhs.cols()==0 || m_lhs.rows()==0 || m_rhs.cols()==0) + return; + + typename internal::add_const_on_value_type<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 \ No newline at end of file
diff -r 000000000000 -r 13a5d365ba16 src/Core/products/GeneralMatrixMatrixTriangular.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/Core/products/GeneralMatrixMatrixTriangular.h Thu Oct 13 04:07:23 2016 +0000 @@ -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_GENERAL_MATRIX_MATRIX_TRIANGULAR_H +#define EIGEN_GENERAL_MATRIX_MATRIX_TRIANGULAR_H + +namespace Eigen { + +template<typename Scalar, typename Index, int StorageOrder, int UpLo, bool ConjLhs, bool ConjRhs> +struct selfadjoint_rank1_update; + +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, const 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, const 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, const 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, typename ProductType, int UpLo, bool IsOuterProduct> +struct general_product_to_triangular_selector; + + +template<typename MatrixType, typename ProductType, int UpLo> +struct general_product_to_triangular_selector<MatrixType,ProductType,UpLo,true> +{ + static void run(MatrixType& mat, const ProductType& prod, const typename MatrixType::Scalar& alpha) + { + typedef typename MatrixType::Scalar Scalar; + typedef typename MatrixType::Index Index; + + typedef typename internal::remove_all<typename ProductType::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 ProductType::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()); + + Scalar actualAlpha = alpha * LhsBlasTraits::extractScalarFactor(prod.lhs().derived()) * RhsBlasTraits::extractScalarFactor(prod.rhs().derived()); + + enum { + StorageOrder = (internal::traits<MatrixType>::Flags&RowMajorBit) ? RowMajor : ColMajor, + UseLhsDirectly = _ActualLhs::InnerStrideAtCompileTime==1, + UseRhsDirectly = _ActualRhs::InnerStrideAtCompileTime==1 + }; + + internal::gemv_static_vector_if<Scalar,Lhs::SizeAtCompileTime,Lhs::MaxSizeAtCompileTime,!UseLhsDirectly> static_lhs; + ei_declare_aligned_stack_constructed_variable(Scalar, actualLhsPtr, actualLhs.size(), + (UseLhsDirectly ? const_cast<Scalar*>(actualLhs.data()) : static_lhs.data())); + if(!UseLhsDirectly) Map<typename _ActualLhs::PlainObject>(actualLhsPtr, actualLhs.size()) = actualLhs; + + internal::gemv_static_vector_if<Scalar,Rhs::SizeAtCompileTime,Rhs::MaxSizeAtCompileTime,!UseRhsDirectly> static_rhs; + ei_declare_aligned_stack_constructed_variable(Scalar, actualRhsPtr, actualRhs.size(), + (UseRhsDirectly ? const_cast<Scalar*>(actualRhs.data()) : static_rhs.data())); + if(!UseRhsDirectly) Map<typename _ActualRhs::PlainObject>(actualRhsPtr, actualRhs.size()) = actualRhs; + + + selfadjoint_rank1_update<Scalar,Index,StorageOrder,UpLo, + LhsBlasTraits::NeedToConjugate && NumTraits<Scalar>::IsComplex, + RhsBlasTraits::NeedToConjugate && NumTraits<Scalar>::IsComplex> + ::run(actualLhs.size(), mat.data(), mat.outerStride(), actualLhsPtr, actualRhsPtr, actualAlpha); + } +}; + +template<typename MatrixType, typename ProductType, int UpLo> +struct general_product_to_triangular_selector<MatrixType,ProductType,UpLo,false> +{ + static void run(MatrixType& mat, const ProductType& prod, const typename MatrixType::Scalar& alpha) + { + typedef typename MatrixType::Index Index; + + typedef typename internal::remove_all<typename ProductType::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 ProductType::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 ProductType::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(mat.cols(), actualLhs.cols(), + &actualLhs.coeffRef(0,0), actualLhs.outerStride(), &actualRhs.coeffRef(0,0), actualRhs.outerStride(), + mat.data(), mat.outerStride(), actualAlpha); + } +}; + +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) +{ + general_product_to_triangular_selector<MatrixType, ProductDerived, UpLo, (_Lhs::ColsAtCompileTime==1) || (_Rhs::RowsAtCompileTime==1)>::run(m_matrix.const_cast_derived(), prod.derived(), alpha); + + return *this; +} + +} // end namespace Eigen + +#endif // EIGEN_GENERAL_MATRIX_MATRIX_TRIANGULAR_H \ No newline at end of file
diff -r 000000000000 -r 13a5d365ba16 src/Core/products/GeneralMatrixMatrixTriangular_MKL.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/Core/products/GeneralMatrixMatrixTriangular_MKL.h Thu Oct 13 04:07:23 2016 +0000 @@ -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 \ No newline at end of file
diff -r 000000000000 -r 13a5d365ba16 src/Core/products/GeneralMatrixMatrix_MKL.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/Core/products/GeneralMatrixMatrix_MKL.h Thu Oct 13 04:07:23 2016 +0000 @@ -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 \ No newline at end of file
diff -r 000000000000 -r 13a5d365ba16 src/Core/products/GeneralMatrixVector.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/Core/products/GeneralMatrixVector.h Thu Oct 13 04:07:23 2016 +0000 @@ -0,0 +1,566 @@ +// 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 resIncr, RhsScalar alpha); +}; + +template<typename Index, typename LhsScalar, bool ConjugateLhs, typename RhsScalar, bool ConjugateRhs, int Version> +EIGEN_DONT_INLINE void general_matrix_vector_product<Index,LhsScalar,ColMajor,ConjugateLhs,RhsScalar,ConjugateRhs,Version>::run( + Index rows, Index cols, + const LhsScalar* lhs, Index lhsStride, + const RhsScalar* rhs, Index rhsIncr, + ResScalar* res, Index resIncr, RhsScalar alpha) +{ + EIGEN_UNUSED_VARIABLE(resIncr) + 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 = numext::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 = alignedSize - RhsPacketSize*peels - RhsPacketSize + 1; + + 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: + { + Index j = alignedStart; + 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 (; 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 (; 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(pload<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); +}; + +template<typename Index, typename LhsScalar, bool ConjugateLhs, typename RhsScalar, bool ConjugateRhs, int Version> +EIGEN_DONT_INLINE void general_matrix_vector_product<Index,LhsScalar,RowMajor,ConjugateLhs,RhsScalar,ConjugateRhs,Version>::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 = alignedSize - RhsPacketSize*peels - RhsPacketSize + 1; + + 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: + { + Index j = alignedStart; + if (peels>1) + { + /* Here we proccess 4 rows with with two peeled iterations to hide + * the 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 (; 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 (; 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 \ No newline at end of file
diff -r 000000000000 -r 13a5d365ba16 src/Core/products/GeneralMatrixVector_MKL.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/Core/products/GeneralMatrixVector_MKL.h Thu Oct 13 04:07:23 2016 +0000 @@ -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 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 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 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 \ No newline at end of file
diff -r 000000000000 -r 13a5d365ba16 src/Core/products/Parallelizer.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/Core/products/Parallelizer.h Thu Oct 13 04:07:23 2016 +0000 @@ -0,0 +1,162 @@ +// 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); + + GemmParallelInfo<Index>* info = new GemmParallelInfo<Index>[threads]; + + #pragma omp parallel num_threads(threads) + { + Index i = omp_get_thread_num(); + // Note that the actual number of threads might be lower than the number of request ones. + Index actual_threads = omp_get_num_threads(); + + Index blockCols = (cols / actual_threads) & ~Index(0x3); + Index blockRows = (rows / actual_threads) & ~Index(0x7); + + Index r0 = i*blockRows; + Index actualBlockRows = (i+1==actual_threads) ? rows-r0 : blockRows; + + Index c0 = i*blockCols; + Index actualBlockCols = (i+1==actual_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 \ No newline at end of file
diff -r 000000000000 -r 13a5d365ba16 src/Core/products/SelfadjointMatrixMatrix.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/Core/products/SelfadjointMatrixMatrix.h Thu Oct 13 04:07:23 2016 +0000 @@ -0,0 +1,436 @@ +// 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++] = numext::conj(lhs(k, i+w)); // transposed + + blockA[count++] = numext::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++] = numext::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++] = numext::real(lhs(i, i)); // real (diagonal) + + for(Index k=i+1; k<cols; k++) + blockA[count++] = numext::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] = numext::conj(rhs(j2+0,k)); + blockB[count+1] = numext::conj(rhs(j2+1,k)); + if (nr==4) + { + blockB[count+2] = numext::conj(rhs(j2+2,k)); + blockB[count+3] = numext::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] = numext::real(rhs(k,k)); + + // transpose + for (Index w=h+1 ; w<nr; ++w) + blockB[count+w] = numext::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] = numext::conj(rhs(j2+0,k)); + blockB[count+1] = numext::conj(rhs(j2+1,k)); + if (nr==4) + { + blockB[count+2] = numext::conj(rhs(j2+2,k)); + blockB[count+3] = numext::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] = numext::conj(rhs(j2,k)); + count += 1; + } + + if(half==j2 && half<k2+rows) + { + blockB[count] = numext::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, + const 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, + const Scalar& alpha); +}; + +template <typename Scalar, typename Index, + int LhsStorageOrder, bool ConjugateLhs, + int RhsStorageOrder, bool ConjugateRhs> +EIGEN_DONT_INLINE void product_selfadjoint_matrix<Scalar,Index,LhsStorageOrder,true,ConjugateLhs, RhsStorageOrder,false,ConjugateRhs,ColMajor>::run( + Index rows, Index cols, + const Scalar* _lhs, Index lhsStride, + const Scalar* _rhs, Index rhsStride, + Scalar* res, Index resStride, + const 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, + const Scalar& alpha); +}; + +template <typename Scalar, typename Index, + int LhsStorageOrder, bool ConjugateLhs, + int RhsStorageOrder, bool ConjugateRhs> +EIGEN_DONT_INLINE void product_selfadjoint_matrix<Scalar,Index,LhsStorageOrder,false,ConjugateLhs, RhsStorageOrder,true,ConjugateRhs,ColMajor>::run( + Index rows, Index cols, + const Scalar* _lhs, Index lhsStride, + const Scalar* _rhs, Index rhsStride, + Scalar* res, Index resStride, + const 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, const 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 \ No newline at end of file
diff -r 000000000000 -r 13a5d365ba16 src/Core/products/SelfadjointMatrixMatrix_MKL.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/Core/products/SelfadjointMatrixMatrix_MKL.h Thu Oct 13 04:07:23 2016 +0000 @@ -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 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 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 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 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 \ No newline at end of file
diff -r 000000000000 -r 13a5d365ba16 src/Core/products/SelfadjointMatrixVector.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/Core/products/SelfadjointMatrixVector.h Thu Oct 13 04:07:23 2016 +0000 @@ -0,0 +1,281 @@ +// 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); +}; + +template<typename Scalar, typename Index, int StorageOrder, int UpLo, bool ConjugateLhs, bool ConjugateRhs, int Version> +EIGEN_DONT_INLINE void selfadjoint_matrix_vector_product<Scalar,Index,StorageOrder,UpLo,ConjugateLhs,ConjugateRhs,Version>::run( + Index size, + const Scalar* lhs, Index lhsStride, + const Scalar* _rhs, Index rhsIncr, + Scalar* res, + Scalar alpha) +{ + typedef typename packet_traits<Scalar>::type Packet; + 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 ? numext::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) + { + const Scalar* EIGEN_RESTRICT A0 = lhs + j*lhsStride; + 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(numext::real(A0[j]), t0); + res[j+1] += cjd.pmul(numext::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 += numext::conj(A0[i]) * rhs[i]; + t3 += numext::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++) + { + 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(numext::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, const 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, const 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 \ No newline at end of file
diff -r 000000000000 -r 13a5d365ba16 src/Core/products/SelfadjointMatrixVector_MKL.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/Core/products/SelfadjointMatrixVector_MKL.h Thu Oct 13 04:07:23 2016 +0000 @@ -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 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 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 \ No newline at end of file
diff -r 000000000000 -r 13a5d365ba16 src/Core/products/SelfadjointProduct.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/Core/products/SelfadjointProduct.h Thu Oct 13 04:07:23 2016 +0000 @@ -0,0 +1,123 @@ +// 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 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* vecX, const Scalar* vecY, const 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 ConjLhsType; + 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(vecY[i])) * ConjLhsType(OtherMap(vecX+(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* vecX, const Scalar* vecY, const Scalar& alpha) + { + selfadjoint_rank1_update<Scalar,Index,ColMajor,UpLo==Lower?Upper:Lower,ConjRhs,ConjLhs>::run(size,mat,stride,vecY,vecX,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, const 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, 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, const 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, const 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 \ No newline at end of file
diff -r 000000000000 -r 13a5d365ba16 src/Core/products/SelfadjointRank2Update.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/Core/products/SelfadjointRank2Update.h Thu Oct 13 04:07:23 2016 +0000 @@ -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, const 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) += + (numext::conj(alpha) * numext::conj(u.coeff(i))) * v.tail(size-i) + + (alpha * numext::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, const Scalar& alpha) + { + const Index size = u.size(); + for (Index i=0; i<size; ++i) + Map<Matrix<Scalar,Dynamic,1> >(mat+stride*i, i+1) += + (numext::conj(alpha) * numext::conj(u.coeff(i))) * v.head(i+1) + + (alpha * numext::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, const 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()) + * numext::conj(VBlasTraits::extractScalarFactor(v.derived())); + if (IsRowMajor) + actualAlpha = numext::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 \ No newline at end of file
diff -r 000000000000 -r 13a5d365ba16 src/Core/products/TriangularMatrixMatrix.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/Core/products/TriangularMatrixMatrix.h Thu Oct 13 04:07:23 2016 +0000 @@ -0,0 +1,427 @@ +// 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, + const 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, + const Scalar& alpha, level3_blocking<Scalar,Scalar>& blocking); +}; + +template <typename Scalar, typename Index, int Mode, + int LhsStorageOrder, bool ConjugateLhs, + int RhsStorageOrder, bool ConjugateRhs, int Version> +EIGEN_DONT_INLINE void product_triangular_matrix_matrix<Scalar,Index,Mode,true, + LhsStorageOrder,ConjugateLhs, + RhsStorageOrder,ConjugateRhs,ColMajor,Version>::run( + Index _rows, Index _cols, Index _depth, + const Scalar* _lhs, Index lhsStride, + const Scalar* _rhs, Index rhsStride, + Scalar* res, Index resStride, + const 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, + const Scalar& alpha, level3_blocking<Scalar,Scalar>& blocking); +}; + +template <typename Scalar, typename Index, int Mode, + int LhsStorageOrder, bool ConjugateLhs, + int RhsStorageOrder, bool ConjugateRhs, int Version> +EIGEN_DONT_INLINE void product_triangular_matrix_matrix<Scalar,Index,Mode,false, + LhsStorageOrder,ConjugateLhs, + RhsStorageOrder,ConjugateRhs,ColMajor,Version>::run( + Index _rows, Index _cols, Index _depth, + const Scalar* _lhs, Index lhsStride, + const Scalar* _rhs, Index rhsStride, + Scalar* res, Index resStride, + const 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, const 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 \ No newline at end of file
diff -r 000000000000 -r 13a5d365ba16 src/Core/products/TriangularMatrixMatrix_MKL.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/Core/products/TriangularMatrixMatrix_MKL.h Thu Oct 13 04:07:23 2016 +0000 @@ -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, level3_blocking<Scalar,Scalar>& blocking) { \ + 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, blocking); \ + } \ +}; + +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 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) \ + { \ + 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(EIGEN_MKL_DOMAIN_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, blocking); \ + /*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> gemm_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, gemm_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 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) \ + { \ + 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(EIGEN_MKL_DOMAIN_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, blocking); \ + /*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> gemm_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, gemm_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 \ No newline at end of file
diff -r 000000000000 -r 13a5d365ba16 src/Core/products/TriangularMatrixVector.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/Core/products/TriangularMatrixVector.h Thu Oct 13 04:07:23 2016 +0000 @@ -0,0 +1,348 @@ +// 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, const ResScalar& alpha); +}; + +template<typename Index, int Mode, typename LhsScalar, bool ConjLhs, typename RhsScalar, bool ConjRhs, int Version> +EIGEN_DONT_INLINE void triangular_matrix_vector_product<Index,Mode,LhsScalar,ConjLhs,RhsScalar,ConjRhs,ColMajor,Version> + ::run(Index _rows, Index _cols, const LhsScalar* _lhs, Index lhsStride, + const RhsScalar* _rhs, Index rhsIncr, ResScalar* _res, Index resIncr, const 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 EIGEN_DONT_INLINE void run(Index _rows, Index _cols, const LhsScalar* _lhs, Index lhsStride, + const RhsScalar* _rhs, Index rhsIncr, ResScalar* _res, Index resIncr, const ResScalar& alpha); +}; + +template<typename Index, int Mode, typename LhsScalar, bool ConjLhs, typename RhsScalar, bool ConjRhs,int Version> +EIGEN_DONT_INLINE void triangular_matrix_vector_product<Index,Mode,LhsScalar,ConjLhs,RhsScalar,ConjRhs,RowMajor,Version> + ::run(Index _rows, Index _cols, const LhsScalar* _lhs, Index lhsStride, + const RhsScalar* _rhs, Index rhsIncr, ResScalar* _res, Index resIncr, const 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, const 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, const 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, const 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) || (numext::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 + Index size = dest.size(); + EIGEN_DENSE_STORAGE_CTOR_PLUGIN + #endif + if(!alphaIsCompatible) + { + MappedDest(actualDestPtr, dest.size()).setZero(); + compatibleAlpha = RhsScalar(1); + } + else + MappedDest(actualDestPtr, dest.size()) = dest; + } + + 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, const 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 \ No newline at end of file
diff -r 000000000000 -r 13a5d365ba16 src/Core/products/TriangularMatrixVector_MKL.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/Core/products/TriangularMatrixVector_MKL.h Thu Oct 13 04:07:23 2016 +0000 @@ -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 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 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 void run(Index _rows, Index _cols, const EIGTYPE* _lhs, Index lhsStride, \ + const EIGTYPE* _rhs, Index rhsIncr, EIGTYPE* _res, Index resIncr, EIGTYPE alpha) \ + { \ + 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); \ + 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 void run(Index _rows, Index _cols, const EIGTYPE* _lhs, Index lhsStride, \ + const EIGTYPE* _rhs, Index rhsIncr, EIGTYPE* _res, Index resIncr, EIGTYPE alpha) \ + { \ + if (IsZeroDiag) { \ + triangular_matrix_vector_product<Index,Mode,EIGTYPE,ConjLhs,EIGTYPE,ConjRhs,RowMajor,BuiltIn>::run( \ + _rows, _cols, _lhs, lhsStride, _rhs, rhsIncr, _res, resIncr, alpha); \ + 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 \ No newline at end of file
diff -r 000000000000 -r 13a5d365ba16 src/Core/products/TriangularSolverMatrix.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/Core/products/TriangularSolverMatrix.h Thu Oct 13 04:07:23 2016 +0000 @@ -0,0 +1,332 @@ +// 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 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); +}; +template <typename Scalar, typename Index, int Mode, bool Conjugate, int TriStorageOrder> +EIGEN_DONT_INLINE void triangular_solve_matrix<Scalar,Index,OnTheLeft,Mode,Conjugate,TriStorageOrder,ColMajor>::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 rs = actualPanelWidth - k - 1; // remaining size + Index s = TriStorageOrder==RowMajor ? (IsLower ? k2+k1 : i+1) + : IsLower ? i+1 : i-rs; + + 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 + { + 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); +}; +template <typename Scalar, typename Index, int Mode, bool Conjugate, int TriStorageOrder> +EIGEN_DONT_INLINE void triangular_solve_matrix<Scalar,Index,OnTheRight,Mode,Conjugate,TriStorageOrder,ColMajor>::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; + } + if((Mode & UnitDiag)==0) + { + Scalar b = 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 \ No newline at end of file
diff -r 000000000000 -r 13a5d365ba16 src/Core/products/TriangularSolverMatrix_MKL.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/Core/products/TriangularSolverMatrix_MKL.h Thu Oct 13 04:07:23 2016 +0000 @@ -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 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 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 \ No newline at end of file
diff -r 000000000000 -r 13a5d365ba16 src/Core/products/TriangularSolverVector.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/Core/products/TriangularSolverVector.h Thu Oct 13 04:07:23 2016 +0000 @@ -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 \ No newline at end of file
diff -r 000000000000 -r 13a5d365ba16 src/Core/util/BlasUtil.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/Core/util/BlasUtil.h Thu Oct 13 04:07:23 2016 +0000 @@ -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 numext::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(numext::real(x)*numext::real(y) + numext::imag(x)*numext::imag(y), numext::imag(x)*numext::real(y) - numext::real(x)*numext::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(numext::real(x)*numext::real(y) + numext::imag(x)*numext::imag(y), numext::real(x)*numext::imag(y) - numext::imag(x)*numext::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(numext::real(x)*numext::real(y) - numext::imag(x)*numext::imag(y), - numext::real(x)*numext::imag(y) - numext::imag(x)*numext::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 numext::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 \ No newline at end of file
diff -r 000000000000 -r 13a5d365ba16 src/Core/util/Constants.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/Core/util/Constants.h Thu Oct 13 04:07:23 2016 +0000 @@ -0,0 +1,451 @@ +// 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 positive quantity (e.g., a size) 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 that a signed quantity (e.g., a signed index) is not known at compile-time, and that instead its value + * has to be specified at runtime. + */ +const int DynamicIndex = 0xffffff; + +/** 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 Evaluate all entries at once */ + AllAtOnceTraversal +}; + +/** \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 + /** Align the matrix itself if it is vectorizable fixed-size */ + AutoAlign = 0, + /** 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 {}; + +namespace internal { + /** \internal + * Constants for comparison functors + */ + enum ComparisonName { + cmp_EQ = 0, + cmp_LT = 1, + cmp_LE = 2, + cmp_UNORD = 3, + cmp_NEQ = 4 + }; +} + +} // end namespace Eigen + +#endif // EIGEN_CONSTANTS_H \ No newline at end of file
diff -r 000000000000 -r 13a5d365ba16 src/Core/util/DisableStupidWarnings.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/Core/util/DisableStupidWarnings.h Thu Oct 13 04:07:23 2016 +0000 @@ -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 \ No newline at end of file
diff -r 000000000000 -r 13a5d365ba16 src/Core/util/ForwardDeclarations.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/Core/util/ForwardDeclarations.h Thu Oct 13 04:07:23 2016 +0000 @@ -0,0 +1,302 @@ +// 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> 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_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; +template<typename LhsScalar,typename RhsScalar=LhsScalar> struct scalar_quotient_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; + +// Sparse module: +template<typename Derived> class SparseMatrixBase; + +#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; +template<typename Derived> class MatrixPowerReturnValue; +template<typename Derived, typename Lhs, typename Rhs> class MatrixPowerProduct; + +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 \ No newline at end of file
diff -r 000000000000 -r 13a5d365ba16 src/Core/util/MKL_support.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/Core/util/MKL_support.h Thu Oct 13 04:07:23 2016 +0000 @@ -0,0 +1,158 @@ +/* + 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> +/*Check IMKL version for compatibility: < 10.3 is not usable with Eigen*/ +# ifndef INTEL_MKL_VERSION +# undef EIGEN_USE_MKL /* INTEL_MKL_VERSION is not even defined on older versions */ +# elif INTEL_MKL_VERSION < 100305 /* the intel-mkl-103-release-notes say this was when the lapacke.h interface was added*/ +# undef EIGEN_USE_MKL +# endif +# ifndef EIGEN_USE_MKL + /*If the MKL version is too old, undef everything*/ +# undef EIGEN_USE_MKL_ALL +# undef EIGEN_USE_BLAS +# undef EIGEN_USE_LAPACKE +# undef EIGEN_USE_MKL_VML +# undef EIGEN_USE_LAPACKE_STRICT +# undef EIGEN_USE_LAPACKE +# endif +#endif + +#if defined EIGEN_USE_MKL +#include <mkl_lapacke.h> +#define EIGEN_MKL_VML_THRESHOLD 128 + +/* MKL_DOMAIN_BLAS, etc are defined only in 10.3 update 7 */ +/* MKL_BLAS, etc are not defined in 11.2 */ +#ifdef MKL_DOMAIN_ALL +#define EIGEN_MKL_DOMAIN_ALL MKL_DOMAIN_ALL +#else +#define EIGEN_MKL_DOMAIN_ALL MKL_ALL +#endif + +#ifdef MKL_DOMAIN_BLAS +#define EIGEN_MKL_DOMAIN_BLAS MKL_DOMAIN_BLAS +#else +#define EIGEN_MKL_DOMAIN_BLAS MKL_BLAS +#endif + +#ifdef MKL_DOMAIN_FFT +#define EIGEN_MKL_DOMAIN_FFT MKL_DOMAIN_FFT +#else +#define EIGEN_MKL_DOMAIN_FFT MKL_FFT +#endif + +#ifdef MKL_DOMAIN_VML +#define EIGEN_MKL_DOMAIN_VML MKL_DOMAIN_VML +#else +#define EIGEN_MKL_DOMAIN_VML MKL_VML +#endif + +#ifdef MKL_DOMAIN_PARDISO +#define EIGEN_MKL_DOMAIN_PARDISO MKL_DOMAIN_PARDISO +#else +#define EIGEN_MKL_DOMAIN_PARDISO MKL_PARDISO +#endif + +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 \ No newline at end of file
diff -r 000000000000 -r 13a5d365ba16 src/Core/util/Macros.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/Core/util/Macros.h Thu Oct 13 04:07:23 2016 +0000 @@ -0,0 +1,714 @@ +// 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 2 +#define EIGEN_MINOR_VERSION 8 + +#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)))) + + +// Compiler identification, EIGEN_COMP_* + +/// \internal EIGEN_COMP_GNUC set to 1 for all compilers compatible with GCC +#ifdef __GNUC__ + #define EIGEN_COMP_GNUC 1 +#else + #define EIGEN_COMP_GNUC 0 +#endif + +/// \internal EIGEN_COMP_CLANG set to 1 if the compiler is clang (alias for __clang__) +#if defined(__clang__) + #define EIGEN_COMP_CLANG 1 +#else + #define EIGEN_COMP_CLANG 0 +#endif + + +/// \internal EIGEN_COMP_LLVM set to 1 if the compiler backend is llvm +#if defined(__llvm__) + #define EIGEN_COMP_LLVM 1 +#else + #define EIGEN_COMP_LLVM 0 +#endif + +/// \internal EIGEN_COMP_ICC set to __INTEL_COMPILER if the compiler is Intel compiler, 0 otherwise +#if defined(__INTEL_COMPILER) + #define EIGEN_COMP_ICC __INTEL_COMPILER +#else + #define EIGEN_COMP_ICC 0 +#endif + +/// \internal EIGEN_COMP_MINGW set to 1 if the compiler is mingw +#if defined(__MINGW32__) + #define EIGEN_COMP_MINGW 1 +#else + #define EIGEN_COMP_MINGW 0 +#endif + +/// \internal EIGEN_COMP_SUNCC set to 1 if the compiler is Solaris Studio +#if defined(__SUNPRO_CC) + #define EIGEN_COMP_SUNCC 1 +#else + #define EIGEN_COMP_SUNCC 0 +#endif + +/// \internal EIGEN_COMP_MSVC set to _MSC_VER if the compiler is Microsoft Visual C++, 0 otherwise. +#if defined(_MSC_VER) + #define EIGEN_COMP_MSVC _MSC_VER +#else + #define EIGEN_COMP_MSVC 0 +#endif + +/// \internal EIGEN_COMP_MSVC_STRICT set to 1 if the compiler is really Microsoft Visual C++ and not ,e.g., ICC +#if EIGEN_COMP_MSVC && !(EIGEN_COMP_ICC) + #define EIGEN_COMP_MSVC_STRICT _MSC_VER +#else + #define EIGEN_COMP_MSVC_STRICT 0 +#endif + +/// \internal EIGEN_COMP_IBM set to 1 if the compiler is IBM XL C++ +#if defined(__IBMCPP__) || defined(__xlc__) + #define EIGEN_COMP_IBM 1 +#else + #define EIGEN_COMP_IBM 0 +#endif + +/// \internal EIGEN_COMP_PGI set to 1 if the compiler is Portland Group Compiler +#if defined(__PGI) + #define EIGEN_COMP_PGI 1 +#else + #define EIGEN_COMP_PGI 0 +#endif + +/// \internal EIGEN_COMP_ARM set to 1 if the compiler is ARM Compiler +#if defined(__CC_ARM) || defined(__ARMCC_VERSION) + #define EIGEN_COMP_ARM 1 +#else + #define EIGEN_COMP_ARM 0 +#endif + + +/// \internal EIGEN_GNUC_STRICT set to 1 if the compiler is really GCC and not a compatible compiler (e.g., ICC, clang, mingw, etc.) +#if EIGEN_COMP_GNUC && !(EIGEN_COMP_CLANG || EIGEN_COMP_ICC || EIGEN_COMP_MINGW || EIGEN_COMP_PGI || EIGEN_COMP_IBM || EIGEN_COMP_ARM ) + #define EIGEN_COMP_GNUC_STRICT 1 +#else + #define EIGEN_COMP_GNUC_STRICT 0 +#endif + + +#if EIGEN_COMP_GNUC + #define EIGEN_GNUC_AT_LEAST(x,y) ((__GNUC__==x && __GNUC_MINOR__>=y) || __GNUC__>x) + #define EIGEN_GNUC_AT_MOST(x,y) ((__GNUC__==x && __GNUC_MINOR__<=y) || __GNUC__<x) + #define EIGEN_GNUC_AT(x,y) ( __GNUC__==x && __GNUC_MINOR__==y ) +#else + #define EIGEN_GNUC_AT_LEAST(x,y) 0 + #define EIGEN_GNUC_AT_MOST(x,y) 0 + #define EIGEN_GNUC_AT(x,y) 0 +#endif + +// FIXME: could probably be removed as we do not support gcc 3.x anymore +#if EIGEN_COMP_GNUC && (__GNUC__ <= 3) +#define EIGEN_GCC3_OR_OLDER 1 +#else +#define EIGEN_GCC3_OR_OLDER 0 +#endif + + +// Architecture identification, EIGEN_ARCH_* + +#if defined(__x86_64__) || defined(_M_X64) || defined(__amd64) + #define EIGEN_ARCH_x86_64 1 +#else + #define EIGEN_ARCH_x86_64 0 +#endif + +#if defined(__i386__) || defined(_M_IX86) || defined(_X86_) || defined(__i386) + #define EIGEN_ARCH_i386 1 +#else + #define EIGEN_ARCH_i386 0 +#endif + +#if EIGEN_ARCH_x86_64 || EIGEN_ARCH_i386 + #define EIGEN_ARCH_i386_OR_x86_64 1 +#else + #define EIGEN_ARCH_i386_OR_x86_64 0 +#endif + +/// \internal EIGEN_ARCH_ARM set to 1 if the architecture is ARM +#if defined(__arm__) + #define EIGEN_ARCH_ARM 1 +#else + #define EIGEN_ARCH_ARM 0 +#endif + +/// \internal EIGEN_ARCH_ARM64 set to 1 if the architecture is ARM64 +#if defined(__aarch64__) + #define EIGEN_ARCH_ARM64 1 +#else + #define EIGEN_ARCH_ARM64 0 +#endif + +#if EIGEN_ARCH_ARM || EIGEN_ARCH_ARM64 + #define EIGEN_ARCH_ARM_OR_ARM64 1 +#else + #define EIGEN_ARCH_ARM_OR_ARM64 0 +#endif + +/// \internal EIGEN_ARCH_MIPS set to 1 if the architecture is MIPS +#if defined(__mips__) || defined(__mips) + #define EIGEN_ARCH_MIPS 1 +#else + #define EIGEN_ARCH_MIPS 0 +#endif + +/// \internal EIGEN_ARCH_SPARC set to 1 if the architecture is SPARC +#if defined(__sparc__) || defined(__sparc) + #define EIGEN_ARCH_SPARC 1 +#else + #define EIGEN_ARCH_SPARC 0 +#endif + +/// \internal EIGEN_ARCH_IA64 set to 1 if the architecture is Intel Itanium +#if defined(__ia64__) + #define EIGEN_ARCH_IA64 1 +#else + #define EIGEN_ARCH_IA64 0 +#endif + +/// \internal EIGEN_ARCH_PPC set to 1 if the architecture is PowerPC +#if defined(__powerpc__) || defined(__ppc__) || defined(_M_PPC) + #define EIGEN_ARCH_PPC 1 +#else + #define EIGEN_ARCH_PPC 0 +#endif + + + +// Operating system identification, EIGEN_OS_* + +/// \internal EIGEN_OS_UNIX set to 1 if the OS is a unix variant +#if defined(__unix__) || defined(__unix) + #define EIGEN_OS_UNIX 1 +#else + #define EIGEN_OS_UNIX 0 +#endif + +/// \internal EIGEN_OS_LINUX set to 1 if the OS is based on Linux kernel +#if defined(__linux__) + #define EIGEN_OS_LINUX 1 +#else + #define EIGEN_OS_LINUX 0 +#endif + +/// \internal EIGEN_OS_ANDROID set to 1 if the OS is Android +// note: ANDROID is defined when using ndk_build, __ANDROID__ is defined when using a standalone toolchain. +#if defined(__ANDROID__) || defined(ANDROID) + #define EIGEN_OS_ANDROID 1 +#else + #define EIGEN_OS_ANDROID 0 +#endif + +/// \internal EIGEN_OS_GNULINUX set to 1 if the OS is GNU Linux and not Linux-based OS (e.g., not android) +#if defined(__gnu_linux__) && !(EIGEN_OS_ANDROID) + #define EIGEN_OS_GNULINUX 1 +#else + #define EIGEN_OS_GNULINUX 0 +#endif + +/// \internal EIGEN_OS_BSD set to 1 if the OS is a BSD variant +#if defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) || defined(__bsdi__) || defined(__DragonFly__) + #define EIGEN_OS_BSD 1 +#else + #define EIGEN_OS_BSD 0 +#endif + +/// \internal EIGEN_OS_MAC set to 1 if the OS is MacOS +#if defined(__APPLE__) + #define EIGEN_OS_MAC 1 +#else + #define EIGEN_OS_MAC 0 +#endif + +/// \internal EIGEN_OS_QNX set to 1 if the OS is QNX +#if defined(__QNX__) + #define EIGEN_OS_QNX 1 +#else + #define EIGEN_OS_QNX 0 +#endif + +/// \internal EIGEN_OS_WIN set to 1 if the OS is Windows based +#if defined(_WIN32) + #define EIGEN_OS_WIN 1 +#else + #define EIGEN_OS_WIN 0 +#endif + +/// \internal EIGEN_OS_WIN64 set to 1 if the OS is Windows 64bits +#if defined(_WIN64) + #define EIGEN_OS_WIN64 1 +#else + #define EIGEN_OS_WIN64 0 +#endif + +/// \internal EIGEN_OS_WINCE set to 1 if the OS is Windows CE +#if defined(_WIN32_WCE) + #define EIGEN_OS_WINCE 1 +#else + #define EIGEN_OS_WINCE 0 +#endif + +/// \internal EIGEN_OS_CYGWIN set to 1 if the OS is Windows/Cygwin +#if defined(__CYGWIN__) + #define EIGEN_OS_CYGWIN 1 +#else + #define EIGEN_OS_CYGWIN 0 +#endif + +/// \internal EIGEN_OS_WIN_STRICT set to 1 if the OS is really Windows and not some variants +#if EIGEN_OS_WIN && !( EIGEN_OS_WINCE || EIGEN_OS_CYGWIN ) + #define EIGEN_OS_WIN_STRICT 1 +#else + #define EIGEN_OS_WIN_STRICT 0 +#endif + +/// \internal EIGEN_OS_SUN set to 1 if the OS is SUN +#if (defined(sun) || defined(__sun)) && !(defined(__SVR4) || defined(__svr4__)) + #define EIGEN_OS_SUN 1 +#else + #define EIGEN_OS_SUN 0 +#endif + +/// \internal EIGEN_OS_SOLARIS set to 1 if the OS is Solaris +#if (defined(sun) || defined(__sun)) && (defined(__SVR4) || defined(__svr4__)) + #define EIGEN_OS_SOLARIS 1 +#else + #define EIGEN_OS_SOLARIS 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 + +// 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 + +// A Clang feature extension to determine compiler features. +// We use it to determine 'cxx_rvalue_references' +#ifndef __has_feature +# define __has_feature(x) 0 +#endif + +// Do we support r-value references? +#if (__has_feature(cxx_rvalue_references) || \ + (defined(__cplusplus) && __cplusplus >= 201103L) || \ + (defined(_MSC_VER) && _MSC_VER >= 1600)) + #define EIGEN_HAVE_RVALUE_REFERENCES +#endif + + +// Cross compiler wrapper around LLVM's __has_builtin +#ifdef __has_builtin +# define EIGEN_HAS_BUILTIN(x) __has_builtin(x) +#else +# define EIGEN_HAS_BUILTIN(x) 0 +#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) + +// 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 + +#if (defined __GNUC__) +#define EIGEN_PERMISSIVE_EXPR __extension__ +#else +#define EIGEN_PERMISSIVE_EXPR +#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. +namespace Eigen { + namespace internal { + template<typename T> void ignore_unused_variable(const T&) {} + } +} +#define EIGEN_UNUSED_VARIABLE(var) Eigen::internal::ignore_unused_variable(var); + +#if !defined(EIGEN_ASM_COMMENT) + #if (defined __GNUC__) && ( defined(__i386__) || defined(__x86_64__) ) + #define EIGEN_ASM_COMMENT(X) __asm__("#" X) + #else + #define EIGEN_ASM_COMMENT(X) + #endif +#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_ALIGN8 EIGEN_ALIGN_TO_BOUNDARY(8) +#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 +// 131072 == 128 KB +#define EIGEN_STACK_ALLOCATION_LIMIT 131072 +#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) && (_MSC_VER < 1900) && (!defined(__INTEL_COMPILER)) +#define EIGEN_INHERIT_ASSIGNMENT_EQUAL_OPERATOR(Derived) \ + using Base::operator =; +#elif defined(__clang__) // workaround clang bug (see http://forum.kde.org/viewtopic.php?f=74&t=102653) +#define EIGEN_INHERIT_ASSIGNMENT_EQUAL_OPERATOR(Derived) \ + using Base::operator =; \ + EIGEN_STRONG_INLINE Derived& operator=(const Derived& other) { Base::operator=(other); return *this; } \ + template <typename OtherDerived> \ + EIGEN_STRONG_INLINE Derived& operator=(const DenseBase<OtherDerived>& other) { Base::operator=(other.derived()); return *this; } +#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 + +/** \internal + * \brief Macro to manually inherit assignment operators. + * This is necessary, because the implicitly defined assignment operator gets deleted when a custom operator= is defined. + */ +#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_ADD_COST(a,b) int(a)==Dynamic || int(b)==Dynamic ? Dynamic : 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 \ No newline at end of file
diff -r 000000000000 -r 13a5d365ba16 src/Core/util/Memory.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/Core/util/Memory.h Thu Oct 13 04:07:23 2016 +0000 @@ -0,0 +1,979 @@ +// 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 + +#ifndef EIGEN_MALLOC_ALREADY_ALIGNED + +// Try to determine automatically if malloc is already aligned. + +// 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__) && ! defined( __SANITIZE_ADDRESS__ ) + #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 + +#endif + +// See bug 554 (http://eigen.tuxfamily.org/bz/show_bug.cgi?id=554) +// It seems to be unsafe to check _POSIX_ADVISORY_INFO without including unistd.h first. +// Currently, let's include it only on unix systems: +#if defined(__unix__) || defined(__unix) + #include <unistd.h> + #if ((defined __QNXNTO__) || (defined _GNU_SOURCE) || (defined __PGI) || ((defined _XOPEN_SOURCE) && (_XOPEN_SOURCE >= 600))) && (defined _POSIX_ADVISORY_INFO) && (_POSIX_ADVISORY_INFO > 0) + #define EIGEN_HAS_POSIX_MEMALIGN 1 + #endif +#endif + +#ifndef EIGEN_HAS_POSIX_MEMALIGN + #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(std::size_t size) +{ + void *original = std::malloc(size+16); + if (original == 0) return 0; + void *aligned = reinterpret_cast<void*>((reinterpret_cast<std::size_t>(original) & ~(std::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, std::size_t size, std::size_t = 0) +{ + if (ptr == 0) return handmade_aligned_malloc(size); + void *original = *(reinterpret_cast<void**>(ptr) - 1); + std::ptrdiff_t previous_offset = static_cast<char *>(ptr)-static_cast<char *>(original); + original = std::realloc(original,size+16); + if (original == 0) return 0; + void *aligned = reinterpret_cast<void*>((reinterpret_cast<std::size_t>(original) & ~(std::size_t(15))) + 16); + void *previous_aligned = static_cast<char *>(original)+previous_offset; + if(aligned!=previous_aligned) + std::memmove(aligned, previous_aligned, size); + + *(reinterpret_cast<void**>(aligned) - 1) = original; + return aligned; +} + +/***************************************************************************** +*** Implementation of generic aligned realloc (when no realloc can be used)*** +*****************************************************************************/ + +void* aligned_malloc(std::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) && (!defined(_WIN32_WCE)) + 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) && (!defined(_WIN32_WCE)) + _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(_WIN32_WCE)) && 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) && (!defined(_WIN32_WCE)) + 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) +{ + if(size==0) + return 0; // short-cut. Also fixes Bug 884 + 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) +{ + static const Index PacketSize = packet_traits<Scalar>::size; + static const Index 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); + } +} + +/** \internal Returns the smallest integer multiple of \a base and greater or equal to \a size + */ +template<typename Index> +inline static Index first_multiple(Index size, Index base) +{ + return ((size+base-1)/base)*base; +} + +// 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__) || (defined __APPLE__) || (defined alloca) + #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 + + #if defined(__arm__) || defined(_WIN32) + #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; } \ + } + #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); } \ + void operator delete(void * ptr, std::size_t /* sz */) throw() { Eigen::internal::conditional_aligned_free<NeedsToAlign>(ptr); } \ + void operator delete[](void * ptr, std::size_t /* sz */) 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); } \ + 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); } \ + 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 ); + } + + 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, %k1;cpuid; xchgl %%ebx,%k1": "=a" (abcd[0]), "=&r" (abcd[1]), "=c" (abcd[2]), "=d" (abcd[3]) : "a" (func), "c" (id)); +# elif defined(__PIC__) && defined(__x86_64__) + // Case for x64 with PIC. In theory this is only a problem with recent gcc and with medium or large code model, not with the default small code model. + // However, we cannot detect which code model is used, and the xchg overhead is negligible anyway. +# define EIGEN_CPUID(abcd,func,id) \ + __asm__ __volatile__ ("xchg{q}\t{%%}rbx, %q1; cpuid; xchg{q}\t{%%}rbx, %q1": "=a" (abcd[0]), "=&r" (abcd[1]), "=c" (abcd[2]), "=d" (abcd[3]) : "0" (func), "2" (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]) : "0" (func), "2" (id) ); +# endif +# elif defined(_MSC_VER) +# if (_MSC_VER > 1500) && ( defined(_M_IX86) || defined(_M_X64) ) +# 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 int vendor[3]) +{ + return abcd[1]==vendor[0] && abcd[3]==vendor[1] && abcd[2]==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]; + const int GenuineIntel[] = {0x756e6547, 0x49656e69, 0x6c65746e}; + const int AuthenticAMD[] = {0x68747541, 0x69746e65, 0x444d4163}; + const int AMDisbetter_[] = {0x69444d41, 0x74656273, 0x21726574}; // "AMDisbetter!" + + // 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 \ No newline at end of file
diff -r 000000000000 -r 13a5d365ba16 src/Core/util/Meta.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/Core/util/Meta.h Thu Oct 13 04:07:23 2016 +0000 @@ -0,0 +1,243 @@ +// 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 +{ + enum { Defined = 0 }; +}; + +template<typename T> struct scalar_product_traits<T,T> +{ + enum { + // Cost = NumTraits<T>::MulCost, + Defined = 1 + }; + typedef T ReturnType; +}; + +template<typename T> struct scalar_product_traits<T,std::complex<T> > +{ + enum { + // Cost = 2*NumTraits<T>::MulCost, + Defined = 1 + }; + typedef std::complex<T> ReturnType; +}; + +template<typename T> struct scalar_product_traits<std::complex<T>, T> +{ + enum { + // Cost = 2*NumTraits<T>::MulCost, + Defined = 1 + }; + 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 \ No newline at end of file
diff -r 000000000000 -r 13a5d365ba16 src/Core/util/NonMPL2.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/Core/util/NonMPL2.h Thu Oct 13 04:07:23 2016 +0000 @@ -0,0 +1,3 @@ +#ifdef EIGEN_MPL2_ONLY +#error Including non-MPL2 code in EIGEN_MPL2_ONLY mode +#endif \ No newline at end of file
diff -r 000000000000 -r 13a5d365ba16 src/Core/util/ReenableStupidWarnings.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/Core/util/ReenableStupidWarnings.h Thu Oct 13 04:07:23 2016 +0000 @@ -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 \ No newline at end of file
diff -r 000000000000 -r 13a5d365ba16 src/Core/util/StaticAssert.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/Core/util/StaticAssert.h Thu Oct 13 04:07:23 2016 +0000 @@ -0,0 +1,208 @@ +// 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 __has_feature(cxx_static_assert) || (defined(__cplusplus) && __cplusplus >= 201103L) || (EIGEN_COMP_MSVC >= 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, + OBJECT_ALLOCATED_ON_STACK_IS_TOO_BIG, + IMPLICIT_CONVERSION_TO_SCALAR_IS_FOR_INNER_PRODUCT_ONLY, + STORAGE_LAYOUT_DOES_NOT_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 \ No newline at end of file
diff -r 000000000000 -r 13a5d365ba16 src/Core/util/XprHelper.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/Core/util/XprHelper.h Thu Oct 13 04:07:23 2016 +0000 @@ -0,0 +1,469 @@ +// 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; } +}; + +/** \internal like variable_if_dynamic but for DynamicIndex + */ +template<typename T, int Value> class variable_if_dynamicindex +{ + public: + EIGEN_EMPTY_STRUCT_CTOR(variable_if_dynamicindex) + explicit variable_if_dynamicindex(T v) { EIGEN_ONLY_USED_FOR_DEBUG(v); assert(v == T(Value)); } + static T value() { return T(Value); } + void setValue(T) {} +}; + +template<typename T> class variable_if_dynamicindex<T, DynamicIndex> +{ + T m_value; + variable_if_dynamicindex() { assert(false); } + public: + explicit variable_if_dynamicindex(T value) : m_value(value) {} + T value() const { return m_value; } + void setValue(T value) { m_value = value; } +}; + +template<typename T> struct functor_traits +{ + enum + { + Cost = 10, + PacketAccess = false, + IsRepeatable = 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 ? int(DynamicAsInteger) : int(ScalarReadCost), + CoeffReadCost = traits<T>::CoeffReadCost, + CoeffReadCostAsInteger = CoeffReadCost == Dynamic ? int(DynamicAsInteger) : int(CoeffReadCost), + NAsInteger = n == Dynamic ? int(DynamicAsInteger) : n, + CostEvalAsInteger = (NAsInteger+1) * ScalarReadCostAsInteger + CoeffReadCostAsInteger, + CostNoEvalAsInteger = NAsInteger * CoeffReadCostAsInteger + }; + + typedef typename conditional< + ( (int(traits<T>::Flags) & EvalBeforeNestingBit) || + int(CostEvalAsInteger) < int(CostNoEvalAsInteger) + ), + PlainObject, + typename ref_selector<T>::type + >::type type; +}; + +template<typename T> +inline 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, typename BaseType, + bool EnableIt = !is_same<Scalar,OtherScalar>::value > +struct special_scalar_op_base : public BaseType +{ + // dummy operator* so that the + // "using special_scalar_op_base::operator*" compiles + void operator*() const; +}; + +template<typename Derived,typename Scalar,typename OtherScalar, typename BaseType> +struct special_scalar_op_base<Derived,Scalar,OtherScalar,BaseType,true> : public BaseType +{ + 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 \ No newline at end of file
diff -r 000000000000 -r 13a5d365ba16 src/Eigenvalues/ComplexEigenSolver.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/Eigenvalues/ComplexEigenSolver.h Thu Oct 13 04:07:23 2016 +0000 @@ -0,0 +1,341 @@ +// 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,2012 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(); + } + + /** \brief Sets the maximum number of iterations allowed. */ + ComplexEigenSolver& setMaxIterations(Index maxIters) + { + m_schur.setMaxIterations(maxIters); + return *this; + } + + /** \brief Returns the maximum number of iterations. */ + Index getMaxIterations() + { + return m_schur.getMaxIterations(); + } + + protected: + + static void check_template_parameters() + { + EIGEN_STATIC_ASSERT_NON_INTEGER(Scalar); + } + + EigenvectorType m_eivec; + EigenvalueType m_eivalues; + ComplexSchur<MatrixType> m_schur; + bool m_isInitialized; + bool m_eigenvectorsOk; + EigenvectorType m_matX; + + private: + void doComputeEigenvectors(const RealScalar& matrixnorm); + void sortEigenvalues(bool computeEigenvectors); +}; + + +template<typename MatrixType> +ComplexEigenSolver<MatrixType>& +ComplexEigenSolver<MatrixType>::compute(const MatrixType& matrix, bool computeEigenvectors) +{ + check_template_parameters(); + + // this code is inspired from Jampack + eigen_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(const 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. + numext::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 \ No newline at end of file
diff -r 000000000000 -r 13a5d365ba16 src/Eigenvalues/ComplexSchur.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/Eigenvalues/ComplexSchur.h Thu Oct 13 04:07:23 2016 +0000 @@ -0,0 +1,456 @@ +// 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,2012 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), + m_maxIters(-1) + {} + + /** \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), + m_maxIters(-1) + { + 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 + * + * \sa compute(const MatrixType&, bool, Index) + */ + ComplexSchur& compute(const MatrixType& matrix, bool computeU = true); + + /** \brief Compute Schur decomposition from a given Hessenberg matrix + * \param[in] matrixH Matrix in Hessenberg form H + * \param[in] matrixQ orthogonal matrix Q that transform a matrix A to H : A = Q H Q^T + * \param computeU Computes the matriX U of the Schur vectors + * \return Reference to \c *this + * + * This routine assumes that the matrix is already reduced in Hessenberg form matrixH + * using either the class HessenbergDecomposition or another mean. + * It computes the upper quasi-triangular matrix T of the Schur decomposition of H + * When computeU is true, this routine computes the matrix U such that + * A = U T U^T = (QZ) T (QZ)^T = Q H Q^T where A is the initial matrix + * + * NOTE Q is referenced if computeU is true; so, if the initial orthogonal matrix + * is not available, the user should give an identity matrix (Q.setIdentity()) + * + * \sa compute(const MatrixType&, bool) + */ + template<typename HessMatrixType, typename OrthMatrixType> + ComplexSchur& computeFromHessenberg(const HessMatrixType& matrixH, const OrthMatrixType& matrixQ, 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 && "ComplexSchur is not initialized."); + return m_info; + } + + /** \brief Sets the maximum number of iterations allowed. + * + * If not specified by the user, the maximum number of iterations is m_maxIterationsPerRow times the size + * of the matrix. + */ + ComplexSchur& setMaxIterations(Index maxIters) + { + m_maxIters = maxIters; + return *this; + } + + /** \brief Returns the maximum number of iterations. */ + Index getMaxIterations() + { + return m_maxIters; + } + + /** \brief Maximum number of iterations per row. + * + * If not otherwise specified, the maximum number of iterations is this number times the size of the + * matrix. It is currently set to 30. + */ + static const int m_maxIterationsPerRow = 30; + + protected: + ComplexMatrixType m_matT, m_matU; + HessenbergDecomposition<MatrixType> m_hess; + ComputationInfo m_info; + bool m_isInitialized; + bool m_matUisUptodate; + Index m_maxIters; + + 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 = numext::norm1(m_matT.coeff(i,i)) + numext::norm1(m_matT.coeff(i+1,i+1)); + RealScalar sd = numext::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) +{ + using std::abs; + if (iter == 10 || iter == 20) + { + // exceptional shift, taken from http://www.netlib.org/eispack/comqr.f + return abs(numext::real(m_matT.coeff(iu,iu-1))) + abs(numext::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(numext::norm1(eival1) > numext::norm1(eival2)) + eival2 = det / eival1; + else + eival1 = det / eival2; + + // choose the eigenvalue closest to the bottom entry of the diagonal + if(numext::norm1(eival1-t.coeff(1,1)) < numext::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); + computeFromHessenberg(m_matT, m_matU, computeU); + return *this; +} + +template<typename MatrixType> +template<typename HessMatrixType, typename OrthMatrixType> +ComplexSchur<MatrixType>& ComplexSchur<MatrixType>::computeFromHessenberg(const HessMatrixType& matrixH, const OrthMatrixType& matrixQ, bool computeU) +{ + m_matT = matrixH; + if(computeU) + m_matU = matrixQ; + 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; + + // 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) +{ + Index maxIters = m_maxIters; + if (maxIters == -1) + maxIters = m_maxIterationsPerRow * m_matT.rows(); + + // 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 + Index totalIter = 0; // number of iterations for whole matrix + + 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, we give up + iter++; + totalIter++; + if(totalIter > maxIters) 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(totalIter <= maxIters) + m_info = Success; + else + m_info = NoConvergence; + + m_isInitialized = true; + m_matUisUptodate = computeU; +} + +} // end namespace Eigen + +#endif // EIGEN_COMPLEX_SCHUR_H \ No newline at end of file
diff -r 000000000000 -r 13a5d365ba16 src/Eigenvalues/ComplexSchur_MKL.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/Eigenvalues/ComplexSchur_MKL.h Thu Oct 13 04:07:23 2016 +0000 @@ -0,0 +1,93 @@ +/* + 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::RealScalar RealScalar; \ + typedef std::complex<RealScalar> ComplexScalar; \ +\ + eigen_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 \ No newline at end of file
diff -r 000000000000 -r 13a5d365ba16 src/Eigenvalues/EigenSolver.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/Eigenvalues/EigenSolver.h Thu Oct 13 04:07:23 2016 +0000 @@ -0,0 +1,607 @@ +// 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,2012 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(); + } + + /** \brief Sets the maximum number of iterations allowed. */ + EigenSolver& setMaxIterations(Index maxIters) + { + m_realSchur.setMaxIterations(maxIters); + return *this; + } + + /** \brief Returns the maximum number of iterations. */ + Index getMaxIterations() + { + return m_realSchur.getMaxIterations(); + } + + private: + void doComputeEigenvectors(); + + protected: + + static void check_template_parameters() + { + EIGEN_STATIC_ASSERT_NON_INTEGER(Scalar); + EIGEN_STATIC_ASSERT(!NumTraits<Scalar>::IsComplex, NUMERIC_TYPE_MUST_BE_REAL); + } + + 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(numext::imag(m_eivalues.coeff(i)), numext::real(m_eivalues.coeff(i)))) + matD.coeffRef(i,i) = numext::real(m_eivalues.coeff(i)); + else + { + matD.template block<2,2>(i,i) << numext::real(m_eivalues.coeff(i)), numext::imag(m_eivalues.coeff(i)), + -numext::imag(m_eivalues.coeff(i)), numext::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(numext::imag(m_eivalues.coeff(j)), numext::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) +{ + check_template_parameters(); + + using std::sqrt; + using std::abs; + eigen_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 = sqrt(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(const Scalar& xr, const Scalar& xi, const Scalar& yr, const Scalar& yi) +{ + using std::abs; + Scalar r,d; + if (abs(yr) > 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() +{ + using std::abs; + 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 (abs(x) > 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 = 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 (abs(m_matT.coeff(n,n-1)) > 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) = numext::real(cc); + m_matT.coeffRef(n-1,n) = numext::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) = numext::real(cc); + m_matT.coeffRef(i,n) = numext::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 * (abs(w) + abs(q) + abs(x) + abs(y) + 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) = numext::real(cc); + m_matT.coeffRef(i,n) = numext::imag(cc); + if (abs(x) > (abs(lastw) + 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) = numext::real(cc); + m_matT.coeffRef(i+1,n) = numext::imag(cc); + } + } + + // Overflow control + using std::max; + Scalar t = (max)(abs(m_matT.coeff(i,n-1)),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 \ No newline at end of file
diff -r 000000000000 -r 13a5d365ba16 src/Eigenvalues/GeneralizedEigenSolver.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/Eigenvalues/GeneralizedEigenSolver.h Thu Oct 13 04:07:23 2016 +0000 @@ -0,0 +1,350 @@ +// This file is part of Eigen, a lightweight C++ template library +// for linear algebra. +// +// Copyright (C) 2012 Gael Guennebaud <gael.guennebaud@inria.fr> +// Copyright (C) 2010,2012 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_GENERALIZEDEIGENSOLVER_H +#define EIGEN_GENERALIZEDEIGENSOLVER_H + +#include "./RealQZ.h" + +namespace Eigen { + +/** \eigenvalues_module \ingroup Eigenvalues_Module + * + * + * \class GeneralizedEigenSolver + * + * \brief Computes the generalized eigenvalues and eigenvectors of a pair of general matrices + * + * \tparam _MatrixType the type of the matrices of which we are computing the + * eigen-decomposition; this is expected to be an instantiation of the Matrix + * class template. Currently, only real matrices are supported. + * + * The generalized eigenvalues and eigenvectors of a matrix pair \f$ A \f$ and \f$ B \f$ are scalars + * \f$ \lambda \f$ and vectors \f$ v \f$ such that \f$ Av = \lambda Bv \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 = + * B V D \f$. The matrix \f$ V \f$ is almost always invertible, in which case we + * have \f$ A = B V D V^{-1} \f$. This is called the generalized eigen-decomposition. + * + * The generalized eigenvalues and eigenvectors of a matrix pair may be complex, even when the + * matrices are real. Moreover, the generalized eigenvalue might be infinite if the matrix B is + * singular. To workaround this difficulty, the eigenvalues are provided as a pair of complex \f$ \alpha \f$ + * and real \f$ \beta \f$ such that: \f$ \lambda_i = \alpha_i / \beta_i \f$. If \f$ \beta_i \f$ is (nearly) zero, + * then one can consider the well defined left eigenvalue \f$ \mu = \beta_i / \alpha_i\f$ such that: + * \f$ \mu_i A v_i = B v_i \f$, or even \f$ \mu_i u_i^T A = u_i^T B \f$ where \f$ u_i \f$ is + * called the left eigenvector. + * + * Call the function compute() to compute the generalized eigenvalues and eigenvectors of + * a given matrix pair. Alternatively, you can use the + * GeneralizedEigenSolver(const MatrixType&, 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. + * + * Here is an usage example of this class: + * Example: \include GeneralizedEigenSolver.cpp + * Output: \verbinclude GeneralizedEigenSolver.out + * + * \sa MatrixBase::eigenvalues(), class ComplexEigenSolver, class SelfAdjointEigenSolver + */ +template<typename _MatrixType> class GeneralizedEigenSolver +{ + 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 real scalar values eigenvalues as returned by betas(). + * + * This is a column vector with entries of type #Scalar. + * The length of the vector is the size of #MatrixType. + */ + typedef Matrix<Scalar, ColsAtCompileTime, 1, Options & ~RowMajor, MaxColsAtCompileTime, 1> VectorType; + + /** \brief Type for vector of complex scalar values eigenvalues as returned by betas(). + * + * 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> ComplexVectorType; + + /** \brief Expression type for the eigenvalues as returned by eigenvalues(). + */ + typedef CwiseBinaryOp<internal::scalar_quotient_op<ComplexScalar,Scalar>,ComplexVectorType,VectorType> 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. + */ + GeneralizedEigenSolver() : m_eivec(), m_alphas(), m_betas(), m_isInitialized(false), m_realQZ(), m_matS(), 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 GeneralizedEigenSolver() + */ + GeneralizedEigenSolver(Index size) + : m_eivec(size, size), + m_alphas(size), + m_betas(size), + m_isInitialized(false), + m_eigenvectorsOk(false), + m_realQZ(size), + m_matS(size, size), + m_tmp(size) + {} + + /** \brief Constructor; computes the generalized eigendecomposition of given matrix pair. + * + * \param[in] A Square matrix whose eigendecomposition is to be computed. + * \param[in] B 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 generalized eigenvalues + * and eigenvectors. + * + * \sa compute() + */ + GeneralizedEigenSolver(const MatrixType& A, const MatrixType& B, bool computeEigenvectors = true) + : m_eivec(A.rows(), A.cols()), + m_alphas(A.cols()), + m_betas(A.cols()), + m_isInitialized(false), + m_eigenvectorsOk(false), + m_realQZ(A.cols()), + m_matS(A.rows(), A.cols()), + m_tmp(A.cols()) + { + compute(A, B, computeEigenvectors); + } + + /* \brief Returns the computed generalized eigenvectors. + * + * \returns %Matrix whose columns are the (possibly complex) eigenvectors. + * + * \pre Either the constructor + * GeneralizedEigenSolver(const MatrixType&,const MatrixType&, bool) or the member function + * compute(const MatrixType&, 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 + * generalized eigendecomposition \f$ A = B V D V^{-1} \f$, if it exists. + * + * \sa eigenvalues() + */ +// EigenvectorsType eigenvectors() const; + + /** \brief Returns an expression of the computed generalized eigenvalues. + * + * \returns An expression of the column vector containing the eigenvalues. + * + * It is a shortcut for \code this->alphas().cwiseQuotient(this->betas()); \endcode + * Not that betas might contain zeros. It is therefore not recommended to use this function, + * but rather directly deal with the alphas and betas vectors. + * + * \pre Either the constructor + * GeneralizedEigenSolver(const MatrixType&,const MatrixType&,bool) or the member function + * compute(const MatrixType&,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. + * + * \sa alphas(), betas(), eigenvectors() + */ + EigenvalueType eigenvalues() const + { + eigen_assert(m_isInitialized && "GeneralizedEigenSolver is not initialized."); + return EigenvalueType(m_alphas,m_betas); + } + + /** \returns A const reference to the vectors containing the alpha values + * + * This vector permits to reconstruct the j-th eigenvalues as alphas(i)/betas(j). + * + * \sa betas(), eigenvalues() */ + ComplexVectorType alphas() const + { + eigen_assert(m_isInitialized && "GeneralizedEigenSolver is not initialized."); + return m_alphas; + } + + /** \returns A const reference to the vectors containing the beta values + * + * This vector permits to reconstruct the j-th eigenvalues as alphas(i)/betas(j). + * + * \sa alphas(), eigenvalues() */ + VectorType betas() const + { + eigen_assert(m_isInitialized && "GeneralizedEigenSolver is not initialized."); + return m_betas; + } + + /** \brief Computes generalized eigendecomposition of given matrix. + * + * \param[in] A Square matrix whose eigendecomposition is to be computed. + * \param[in] B 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 generalized Schur form using the RealQZ + * class. The generalized Schur decomposition is then used to compute the eigenvalues + * and eigenvectors. + * + * The cost of the computation is dominated by the cost of the + * generalized Schur decomposition. + * + * This method reuses of the allocated data in the GeneralizedEigenSolver object. + */ + GeneralizedEigenSolver& compute(const MatrixType& A, const MatrixType& B, bool computeEigenvectors = true); + + ComputationInfo info() const + { + eigen_assert(m_isInitialized && "EigenSolver is not initialized."); + return m_realQZ.info(); + } + + /** Sets the maximal number of iterations allowed. + */ + GeneralizedEigenSolver& setMaxIterations(Index maxIters) + { + m_realQZ.setMaxIterations(maxIters); + return *this; + } + + protected: + + static void check_template_parameters() + { + EIGEN_STATIC_ASSERT_NON_INTEGER(Scalar); + EIGEN_STATIC_ASSERT(!NumTraits<Scalar>::IsComplex, NUMERIC_TYPE_MUST_BE_REAL); + } + + MatrixType m_eivec; + ComplexVectorType m_alphas; + VectorType m_betas; + bool m_isInitialized; + bool m_eigenvectorsOk; + RealQZ<MatrixType> m_realQZ; + MatrixType m_matS; + + typedef Matrix<Scalar, ColsAtCompileTime, 1, Options & ~RowMajor, MaxColsAtCompileTime, 1> ColumnVectorType; + ColumnVectorType m_tmp; +}; + +//template<typename MatrixType> +//typename GeneralizedEigenSolver<MatrixType>::EigenvectorsType GeneralizedEigenSolver<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); +// // TODO +// return matV; +//} + +template<typename MatrixType> +GeneralizedEigenSolver<MatrixType>& +GeneralizedEigenSolver<MatrixType>::compute(const MatrixType& A, const MatrixType& B, bool computeEigenvectors) +{ + check_template_parameters(); + + using std::sqrt; + using std::abs; + eigen_assert(A.cols() == A.rows() && B.cols() == A.rows() && B.cols() == B.rows()); + + // Reduce to generalized real Schur form: + // A = Q S Z and B = Q T Z + m_realQZ.compute(A, B, computeEigenvectors); + + if (m_realQZ.info() == Success) + { + m_matS = m_realQZ.matrixS(); + if (computeEigenvectors) + m_eivec = m_realQZ.matrixZ().transpose(); + + // Compute eigenvalues from matS + m_alphas.resize(A.cols()); + m_betas.resize(A.cols()); + Index i = 0; + while (i < A.cols()) + { + if (i == A.cols() - 1 || m_matS.coeff(i+1, i) == Scalar(0)) + { + m_alphas.coeffRef(i) = m_matS.coeff(i, i); + m_betas.coeffRef(i) = m_realQZ.matrixT().coeff(i,i); + ++i; + } + else + { + Scalar p = Scalar(0.5) * (m_matS.coeff(i, i) - m_matS.coeff(i+1, i+1)); + Scalar z = sqrt(abs(p * p + m_matS.coeff(i+1, i) * m_matS.coeff(i, i+1))); + m_alphas.coeffRef(i) = ComplexScalar(m_matS.coeff(i+1, i+1) + p, z); + m_alphas.coeffRef(i+1) = ComplexScalar(m_matS.coeff(i+1, i+1) + p, -z); + + m_betas.coeffRef(i) = m_realQZ.matrixT().coeff(i,i); + m_betas.coeffRef(i+1) = m_realQZ.matrixT().coeff(i,i); + i += 2; + } + } + } + + m_isInitialized = true; + m_eigenvectorsOk = false;//computeEigenvectors; + + return *this; +} + +} // end namespace Eigen + +#endif // EIGEN_GENERALIZEDEIGENSOLVER_H \ No newline at end of file
diff -r 000000000000 -r 13a5d365ba16 src/Eigenvalues/GeneralizedSelfAdjointEigenSolver.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/Eigenvalues/GeneralizedSelfAdjointEigenSolver.h Thu Oct 13 04:07:23 2016 +0000 @@ -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 \ No newline at end of file
diff -r 000000000000 -r 13a5d365ba16 src/Eigenvalues/HessenbergDecomposition.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/Eigenvalues/HessenbergDecomposition.h Thu Oct 13 04:07:23 2016 +0000 @@ -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 HouseholderSequence<MatrixType,typename internal::remove_all<typename CoeffVectorType::ConjugateReturnType>::type> 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) +{ + eigen_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(), numext::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 \ No newline at end of file
diff -r 000000000000 -r 13a5d365ba16 src/Eigenvalues/MatrixBaseEigenvalues.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/Eigenvalues/MatrixBaseEigenvalues.h Thu Oct 13 04:07:23 2016 +0000 @@ -0,0 +1,160 @@ +// 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 +{ + using std::sqrt; + 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 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 \ No newline at end of file
diff -r 000000000000 -r 13a5d365ba16 src/Eigenvalues/RealQZ.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/Eigenvalues/RealQZ.h Thu Oct 13 04:07:23 2016 +0000 @@ -0,0 +1,624 @@ +// This file is part of Eigen, a lightweight C++ template library +// for linear algebra. +// +// Copyright (C) 2012 Alexey Korepanov <kaikaikai@yandex.ru> +// +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If 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_QZ_H +#define EIGEN_REAL_QZ_H + +namespace Eigen { + + /** \eigenvalues_module \ingroup Eigenvalues_Module + * + * + * \class RealQZ + * + * \brief Performs a real QZ decomposition of a pair of square matrices + * + * \tparam _MatrixType the type of the matrix of which we are computing the + * real QZ decomposition; this is expected to be an instantiation of the + * Matrix class template. + * + * Given a real square matrices A and B, this class computes the real QZ + * decomposition: \f$ A = Q S Z \f$, \f$ B = Q T Z \f$ where Q and Z are + * real orthogonal matrixes, T is upper-triangular matrix, and S is upper + * 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 where further reduction is impossible due to + * complex eigenvalues. + * + * The eigenvalues of the pencil \f$ A - z B \f$ can be obtained from + * 1x1 and 2x2 blocks on the diagonals of S and T. + * + * Call the function compute() to compute the real QZ decomposition of a + * given pair of matrices. Alternatively, you can use the + * RealQZ(const MatrixType& B, const MatrixType& B, bool computeQZ) + * constructor which computes the real QZ decomposition at construction + * time. Once the decomposition is computed, you can use the matrixS(), + * matrixT(), matrixQ() and matrixZ() functions to retrieve the matrices + * S, T, Q and Z in the decomposition. If computeQZ==false, some time + * is saved by not computing matrices Q and Z. + * + * Example: \include RealQZ_compute.cpp + * Output: \include RealQZ_compute.out + * + * \note The implementation is based on the algorithm in "Matrix Computations" + * by Gene H. Golub and Charles F. Van Loan, and a paper "An algorithm for + * generalized eigenvalue problems" by C.B.Moler and G.W.Stewart. + * + * \sa class RealSchur, class ComplexSchur, class EigenSolver, class ComplexEigenSolver + */ + + template<typename _MatrixType> class RealQZ + { + 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 QZ 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. + */ + RealQZ(Index size = RowsAtCompileTime==Dynamic ? 1 : RowsAtCompileTime) : + m_S(size, size), + m_T(size, size), + m_Q(size, size), + m_Z(size, size), + m_workspace(size*2), + m_maxIters(400), + m_isInitialized(false) + { } + + /** \brief Constructor; computes real QZ decomposition of given matrices + * + * \param[in] A Matrix A. + * \param[in] B Matrix B. + * \param[in] computeQZ If false, A and Z are not computed. + * + * This constructor calls compute() to compute the QZ decomposition. + */ + RealQZ(const MatrixType& A, const MatrixType& B, bool computeQZ = true) : + m_S(A.rows(),A.cols()), + m_T(A.rows(),A.cols()), + m_Q(A.rows(),A.cols()), + m_Z(A.rows(),A.cols()), + m_workspace(A.rows()*2), + m_maxIters(400), + m_isInitialized(false) { + compute(A, B, computeQZ); + } + + /** \brief Returns matrix Q in the QZ decomposition. + * + * \returns A const reference to the matrix Q. + */ + const MatrixType& matrixQ() const { + eigen_assert(m_isInitialized && "RealQZ is not initialized."); + eigen_assert(m_computeQZ && "The matrices Q and Z have not been computed during the QZ decomposition."); + return m_Q; + } + + /** \brief Returns matrix Z in the QZ decomposition. + * + * \returns A const reference to the matrix Z. + */ + const MatrixType& matrixZ() const { + eigen_assert(m_isInitialized && "RealQZ is not initialized."); + eigen_assert(m_computeQZ && "The matrices Q and Z have not been computed during the QZ decomposition."); + return m_Z; + } + + /** \brief Returns matrix S in the QZ decomposition. + * + * \returns A const reference to the matrix S. + */ + const MatrixType& matrixS() const { + eigen_assert(m_isInitialized && "RealQZ is not initialized."); + return m_S; + } + + /** \brief Returns matrix S in the QZ decomposition. + * + * \returns A const reference to the matrix S. + */ + const MatrixType& matrixT() const { + eigen_assert(m_isInitialized && "RealQZ is not initialized."); + return m_T; + } + + /** \brief Computes QZ decomposition of given matrix. + * + * \param[in] A Matrix A. + * \param[in] B Matrix B. + * \param[in] computeQZ If false, A and Z are not computed. + * \returns Reference to \c *this + */ + RealQZ& compute(const MatrixType& A, const MatrixType& B, bool computeQZ = 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 && "RealQZ is not initialized."); + return m_info; + } + + /** \brief Returns number of performed QR-like iterations. + */ + Index iterations() const + { + eigen_assert(m_isInitialized && "RealQZ is not initialized."); + return m_global_iter; + } + + /** Sets the maximal number of iterations allowed to converge to one eigenvalue + * or decouple the problem. + */ + RealQZ& setMaxIterations(Index maxIters) + { + m_maxIters = maxIters; + return *this; + } + + private: + + MatrixType m_S, m_T, m_Q, m_Z; + Matrix<Scalar,Dynamic,1> m_workspace; + ComputationInfo m_info; + Index m_maxIters; + bool m_isInitialized; + bool m_computeQZ; + Scalar m_normOfT, m_normOfS; + Index m_global_iter; + + typedef Matrix<Scalar,3,1> Vector3s; + typedef Matrix<Scalar,2,1> Vector2s; + typedef Matrix<Scalar,2,2> Matrix2s; + typedef JacobiRotation<Scalar> JRs; + + void hessenbergTriangular(); + void computeNorms(); + Index findSmallSubdiagEntry(Index iu); + Index findSmallDiagEntry(Index f, Index l); + void splitOffTwoRows(Index i); + void pushDownZero(Index z, Index f, Index l); + void step(Index f, Index l, Index iter); + + }; // RealQZ + + /** \internal Reduces S and T to upper Hessenberg - triangular form */ + template<typename MatrixType> + void RealQZ<MatrixType>::hessenbergTriangular() + { + + const Index dim = m_S.cols(); + + // perform QR decomposition of T, overwrite T with R, save Q + HouseholderQR<MatrixType> qrT(m_T); + m_T = qrT.matrixQR(); + m_T.template triangularView<StrictlyLower>().setZero(); + m_Q = qrT.householderQ(); + // overwrite S with Q* S + m_S.applyOnTheLeft(m_Q.adjoint()); + // init Z as Identity + if (m_computeQZ) + m_Z = MatrixType::Identity(dim,dim); + // reduce S to upper Hessenberg with Givens rotations + for (Index j=0; j<=dim-3; j++) { + for (Index i=dim-1; i>=j+2; i--) { + JRs G; + // kill S(i,j) + if(m_S.coeff(i,j) != 0) + { + G.makeGivens(m_S.coeff(i-1,j), m_S.coeff(i,j), &m_S.coeffRef(i-1, j)); + m_S.coeffRef(i,j) = Scalar(0.0); + m_S.rightCols(dim-j-1).applyOnTheLeft(i-1,i,G.adjoint()); + m_T.rightCols(dim-i+1).applyOnTheLeft(i-1,i,G.adjoint()); + // update Q + if (m_computeQZ) + m_Q.applyOnTheRight(i-1,i,G); + } + // kill T(i,i-1) + if(m_T.coeff(i,i-1)!=Scalar(0)) + { + G.makeGivens(m_T.coeff(i,i), m_T.coeff(i,i-1), &m_T.coeffRef(i,i)); + m_T.coeffRef(i,i-1) = Scalar(0.0); + m_S.applyOnTheRight(i,i-1,G); + m_T.topRows(i).applyOnTheRight(i,i-1,G); + // update Z + if (m_computeQZ) + m_Z.applyOnTheLeft(i,i-1,G.adjoint()); + } + } + } + } + + /** \internal Computes vector L1 norms of S and T when in Hessenberg-Triangular form already */ + template<typename MatrixType> + inline void RealQZ<MatrixType>::computeNorms() + { + const Index size = m_S.cols(); + m_normOfS = Scalar(0.0); + m_normOfT = Scalar(0.0); + for (Index j = 0; j < size; ++j) + { + m_normOfS += m_S.col(j).segment(0, (std::min)(size,j+2)).cwiseAbs().sum(); + m_normOfT += m_T.row(j).segment(j, size - j).cwiseAbs().sum(); + } + } + + + /** \internal Look for single small sub-diagonal element S(res, res-1) and return res (or 0) */ + template<typename MatrixType> + inline typename MatrixType::Index RealQZ<MatrixType>::findSmallSubdiagEntry(Index iu) + { + using std::abs; + Index res = iu; + while (res > 0) + { + Scalar s = abs(m_S.coeff(res-1,res-1)) + abs(m_S.coeff(res,res)); + if (s == Scalar(0.0)) + s = m_normOfS; + if (abs(m_S.coeff(res,res-1)) < NumTraits<Scalar>::epsilon() * s) + break; + res--; + } + return res; + } + + /** \internal Look for single small diagonal element T(res, res) for res between f and l, and return res (or f-1) */ + template<typename MatrixType> + inline typename MatrixType::Index RealQZ<MatrixType>::findSmallDiagEntry(Index f, Index l) + { + using std::abs; + Index res = l; + while (res >= f) { + if (abs(m_T.coeff(res,res)) <= NumTraits<Scalar>::epsilon() * m_normOfT) + break; + res--; + } + return res; + } + + /** \internal decouple 2x2 diagonal block in rows i, i+1 if eigenvalues are real */ + template<typename MatrixType> + inline void RealQZ<MatrixType>::splitOffTwoRows(Index i) + { + using std::abs; + using std::sqrt; + const Index dim=m_S.cols(); + if (abs(m_S.coeff(i+1,i))==Scalar(0)) + return; + Index z = findSmallDiagEntry(i,i+1); + if (z==i-1) + { + // block of (S T^{-1}) + Matrix2s STi = m_T.template block<2,2>(i,i).template triangularView<Upper>(). + template solve<OnTheRight>(m_S.template block<2,2>(i,i)); + Scalar p = Scalar(0.5)*(STi(0,0)-STi(1,1)); + Scalar q = p*p + STi(1,0)*STi(0,1); + if (q>=0) { + Scalar z = sqrt(q); + // one QR-like iteration for ABi - lambda I + // is enough - when we know exact eigenvalue in advance, + // convergence is immediate + JRs G; + if (p>=0) + G.makeGivens(p + z, STi(1,0)); + else + G.makeGivens(p - z, STi(1,0)); + m_S.rightCols(dim-i).applyOnTheLeft(i,i+1,G.adjoint()); + m_T.rightCols(dim-i).applyOnTheLeft(i,i+1,G.adjoint()); + // update Q + if (m_computeQZ) + m_Q.applyOnTheRight(i,i+1,G); + + G.makeGivens(m_T.coeff(i+1,i+1), m_T.coeff(i+1,i)); + m_S.topRows(i+2).applyOnTheRight(i+1,i,G); + m_T.topRows(i+2).applyOnTheRight(i+1,i,G); + // update Z + if (m_computeQZ) + m_Z.applyOnTheLeft(i+1,i,G.adjoint()); + + m_S.coeffRef(i+1,i) = Scalar(0.0); + m_T.coeffRef(i+1,i) = Scalar(0.0); + } + } + else + { + pushDownZero(z,i,i+1); + } + } + + /** \internal use zero in T(z,z) to zero S(l,l-1), working in block f..l */ + template<typename MatrixType> + inline void RealQZ<MatrixType>::pushDownZero(Index z, Index f, Index l) + { + JRs G; + const Index dim = m_S.cols(); + for (Index zz=z; zz<l; zz++) + { + // push 0 down + Index firstColS = zz>f ? (zz-1) : zz; + G.makeGivens(m_T.coeff(zz, zz+1), m_T.coeff(zz+1, zz+1)); + m_S.rightCols(dim-firstColS).applyOnTheLeft(zz,zz+1,G.adjoint()); + m_T.rightCols(dim-zz).applyOnTheLeft(zz,zz+1,G.adjoint()); + m_T.coeffRef(zz+1,zz+1) = Scalar(0.0); + // update Q + if (m_computeQZ) + m_Q.applyOnTheRight(zz,zz+1,G); + // kill S(zz+1, zz-1) + if (zz>f) + { + G.makeGivens(m_S.coeff(zz+1, zz), m_S.coeff(zz+1,zz-1)); + m_S.topRows(zz+2).applyOnTheRight(zz, zz-1,G); + m_T.topRows(zz+1).applyOnTheRight(zz, zz-1,G); + m_S.coeffRef(zz+1,zz-1) = Scalar(0.0); + // update Z + if (m_computeQZ) + m_Z.applyOnTheLeft(zz,zz-1,G.adjoint()); + } + } + // finally kill S(l,l-1) + G.makeGivens(m_S.coeff(l,l), m_S.coeff(l,l-1)); + m_S.applyOnTheRight(l,l-1,G); + m_T.applyOnTheRight(l,l-1,G); + m_S.coeffRef(l,l-1)=Scalar(0.0); + // update Z + if (m_computeQZ) + m_Z.applyOnTheLeft(l,l-1,G.adjoint()); + } + + /** \internal QR-like iterative step for block f..l */ + template<typename MatrixType> + inline void RealQZ<MatrixType>::step(Index f, Index l, Index iter) + { + using std::abs; + const Index dim = m_S.cols(); + + // x, y, z + Scalar x, y, z; + if (iter==10) + { + // Wilkinson ad hoc shift + const Scalar + a11=m_S.coeff(f+0,f+0), a12=m_S.coeff(f+0,f+1), + a21=m_S.coeff(f+1,f+0), a22=m_S.coeff(f+1,f+1), a32=m_S.coeff(f+2,f+1), + b12=m_T.coeff(f+0,f+1), + b11i=Scalar(1.0)/m_T.coeff(f+0,f+0), + b22i=Scalar(1.0)/m_T.coeff(f+1,f+1), + a87=m_S.coeff(l-1,l-2), + a98=m_S.coeff(l-0,l-1), + b77i=Scalar(1.0)/m_T.coeff(l-2,l-2), + b88i=Scalar(1.0)/m_T.coeff(l-1,l-1); + Scalar ss = abs(a87*b77i) + abs(a98*b88i), + lpl = Scalar(1.5)*ss, + ll = ss*ss; + x = ll + a11*a11*b11i*b11i - lpl*a11*b11i + a12*a21*b11i*b22i + - a11*a21*b12*b11i*b11i*b22i; + y = a11*a21*b11i*b11i - lpl*a21*b11i + a21*a22*b11i*b22i + - a21*a21*b12*b11i*b11i*b22i; + z = a21*a32*b11i*b22i; + } + else if (iter==16) + { + // another exceptional shift + x = m_S.coeff(f,f)/m_T.coeff(f,f)-m_S.coeff(l,l)/m_T.coeff(l,l) + m_S.coeff(l,l-1)*m_T.coeff(l-1,l) / + (m_T.coeff(l-1,l-1)*m_T.coeff(l,l)); + y = m_S.coeff(f+1,f)/m_T.coeff(f,f); + z = 0; + } + else if (iter>23 && !(iter%8)) + { + // extremely exceptional shift + x = internal::random<Scalar>(-1.0,1.0); + y = internal::random<Scalar>(-1.0,1.0); + z = internal::random<Scalar>(-1.0,1.0); + } + else + { + // Compute the shifts: (x,y,z,0...) = (AB^-1 - l1 I) (AB^-1 - l2 I) e1 + // where l1 and l2 are the eigenvalues of the 2x2 matrix C = U V^-1 where + // U and V are 2x2 bottom right sub matrices of A and B. Thus: + // = AB^-1AB^-1 + l1 l2 I - (l1+l2)(AB^-1) + // = AB^-1AB^-1 + det(M) - tr(M)(AB^-1) + // Since we are only interested in having x, y, z with a correct ratio, we have: + const Scalar + a11 = m_S.coeff(f,f), a12 = m_S.coeff(f,f+1), + a21 = m_S.coeff(f+1,f), a22 = m_S.coeff(f+1,f+1), + a32 = m_S.coeff(f+2,f+1), + + a88 = m_S.coeff(l-1,l-1), a89 = m_S.coeff(l-1,l), + a98 = m_S.coeff(l,l-1), a99 = m_S.coeff(l,l), + + b11 = m_T.coeff(f,f), b12 = m_T.coeff(f,f+1), + b22 = m_T.coeff(f+1,f+1), + + b88 = m_T.coeff(l-1,l-1), b89 = m_T.coeff(l-1,l), + b99 = m_T.coeff(l,l); + + x = ( (a88/b88 - a11/b11)*(a99/b99 - a11/b11) - (a89/b99)*(a98/b88) + (a98/b88)*(b89/b99)*(a11/b11) ) * (b11/a21) + + a12/b22 - (a11/b11)*(b12/b22); + y = (a22/b22-a11/b11) - (a21/b11)*(b12/b22) - (a88/b88-a11/b11) - (a99/b99-a11/b11) + (a98/b88)*(b89/b99); + z = a32/b22; + } + + JRs G; + + for (Index k=f; k<=l-2; k++) + { + // variables for Householder reflections + Vector2s essential2; + Scalar tau, beta; + + Vector3s hr(x,y,z); + + // Q_k to annihilate S(k+1,k-1) and S(k+2,k-1) + hr.makeHouseholderInPlace(tau, beta); + essential2 = hr.template bottomRows<2>(); + Index fc=(std::max)(k-1,Index(0)); // first col to update + m_S.template middleRows<3>(k).rightCols(dim-fc).applyHouseholderOnTheLeft(essential2, tau, m_workspace.data()); + m_T.template middleRows<3>(k).rightCols(dim-fc).applyHouseholderOnTheLeft(essential2, tau, m_workspace.data()); + if (m_computeQZ) + m_Q.template middleCols<3>(k).applyHouseholderOnTheRight(essential2, tau, m_workspace.data()); + if (k>f) + m_S.coeffRef(k+2,k-1) = m_S.coeffRef(k+1,k-1) = Scalar(0.0); + + // Z_{k1} to annihilate T(k+2,k+1) and T(k+2,k) + hr << m_T.coeff(k+2,k+2),m_T.coeff(k+2,k),m_T.coeff(k+2,k+1); + hr.makeHouseholderInPlace(tau, beta); + essential2 = hr.template bottomRows<2>(); + { + Index lr = (std::min)(k+4,dim); // last row to update + Map<Matrix<Scalar,Dynamic,1> > tmp(m_workspace.data(),lr); + // S + tmp = m_S.template middleCols<2>(k).topRows(lr) * essential2; + tmp += m_S.col(k+2).head(lr); + m_S.col(k+2).head(lr) -= tau*tmp; + m_S.template middleCols<2>(k).topRows(lr) -= (tau*tmp) * essential2.adjoint(); + // T + tmp = m_T.template middleCols<2>(k).topRows(lr) * essential2; + tmp += m_T.col(k+2).head(lr); + m_T.col(k+2).head(lr) -= tau*tmp; + m_T.template middleCols<2>(k).topRows(lr) -= (tau*tmp) * essential2.adjoint(); + } + if (m_computeQZ) + { + // Z + Map<Matrix<Scalar,1,Dynamic> > tmp(m_workspace.data(),dim); + tmp = essential2.adjoint()*(m_Z.template middleRows<2>(k)); + tmp += m_Z.row(k+2); + m_Z.row(k+2) -= tau*tmp; + m_Z.template middleRows<2>(k) -= essential2 * (tau*tmp); + } + m_T.coeffRef(k+2,k) = m_T.coeffRef(k+2,k+1) = Scalar(0.0); + + // Z_{k2} to annihilate T(k+1,k) + G.makeGivens(m_T.coeff(k+1,k+1), m_T.coeff(k+1,k)); + m_S.applyOnTheRight(k+1,k,G); + m_T.applyOnTheRight(k+1,k,G); + // update Z + if (m_computeQZ) + m_Z.applyOnTheLeft(k+1,k,G.adjoint()); + m_T.coeffRef(k+1,k) = Scalar(0.0); + + // update x,y,z + x = m_S.coeff(k+1,k); + y = m_S.coeff(k+2,k); + if (k < l-2) + z = m_S.coeff(k+3,k); + } // loop over k + + // Q_{n-1} to annihilate y = S(l,l-2) + G.makeGivens(x,y); + m_S.applyOnTheLeft(l-1,l,G.adjoint()); + m_T.applyOnTheLeft(l-1,l,G.adjoint()); + if (m_computeQZ) + m_Q.applyOnTheRight(l-1,l,G); + m_S.coeffRef(l,l-2) = Scalar(0.0); + + // Z_{n-1} to annihilate T(l,l-1) + G.makeGivens(m_T.coeff(l,l),m_T.coeff(l,l-1)); + m_S.applyOnTheRight(l,l-1,G); + m_T.applyOnTheRight(l,l-1,G); + if (m_computeQZ) + m_Z.applyOnTheLeft(l,l-1,G.adjoint()); + m_T.coeffRef(l,l-1) = Scalar(0.0); + } + + + template<typename MatrixType> + RealQZ<MatrixType>& RealQZ<MatrixType>::compute(const MatrixType& A_in, const MatrixType& B_in, bool computeQZ) + { + + const Index dim = A_in.cols(); + + eigen_assert (A_in.rows()==dim && A_in.cols()==dim + && B_in.rows()==dim && B_in.cols()==dim + && "Need square matrices of the same dimension"); + + m_isInitialized = true; + m_computeQZ = computeQZ; + m_S = A_in; m_T = B_in; + m_workspace.resize(dim*2); + m_global_iter = 0; + + // entrance point: hessenberg triangular decomposition + hessenbergTriangular(); + // compute L1 vector norms of T, S into m_normOfS, m_normOfT + computeNorms(); + + Index l = dim-1, + f, + local_iter = 0; + + while (l>0 && local_iter<m_maxIters) + { + f = findSmallSubdiagEntry(l); + // now rows and columns f..l (including) decouple from the rest of the problem + if (f>0) m_S.coeffRef(f,f-1) = Scalar(0.0); + if (f == l) // One root found + { + l--; + local_iter = 0; + } + else if (f == l-1) // Two roots found + { + splitOffTwoRows(f); + l -= 2; + local_iter = 0; + } + else // No convergence yet + { + // if there's zero on diagonal of T, we can isolate an eigenvalue with Givens rotations + Index z = findSmallDiagEntry(f,l); + if (z>=f) + { + // zero found + pushDownZero(z,f,l); + } + else + { + // We are sure now that S.block(f,f, l-f+1,l-f+1) is underuced upper-Hessenberg + // and T.block(f,f, l-f+1,l-f+1) is invertible uper-triangular, which allows to + // apply a QR-like iteration to rows and columns f..l. + step(f,l, local_iter); + local_iter++; + m_global_iter++; + } + } + } + // check if we converged before reaching iterations limit + m_info = (local_iter<m_maxIters) ? Success : NoConvergence; + return *this; + } // end compute + +} // end namespace Eigen + +#endif //EIGEN_REAL_QZ \ No newline at end of file
diff -r 000000000000 -r 13a5d365ba16 src/Eigenvalues/RealSchur.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/Eigenvalues/RealSchur.h Thu Oct 13 04:07:23 2016 +0000 @@ -0,0 +1,525 @@ +// 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,2012 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), + m_maxIters(-1) + { } + + /** \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), + m_maxIters(-1) + { + 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 + * + * \sa compute(const MatrixType&, bool, Index) + */ + RealSchur& compute(const MatrixType& matrix, bool computeU = true); + + /** \brief Computes Schur decomposition of a Hessenberg matrix H = Z T Z^T + * \param[in] matrixH Matrix in Hessenberg form H + * \param[in] matrixQ orthogonal matrix Q that transform a matrix A to H : A = Q H Q^T + * \param computeU Computes the matriX U of the Schur vectors + * \return Reference to \c *this + * + * This routine assumes that the matrix is already reduced in Hessenberg form matrixH + * using either the class HessenbergDecomposition or another mean. + * It computes the upper quasi-triangular matrix T of the Schur decomposition of H + * When computeU is true, this routine computes the matrix U such that + * A = U T U^T = (QZ) T (QZ)^T = Q H Q^T where A is the initial matrix + * + * NOTE Q is referenced if computeU is true; so, if the initial orthogonal matrix + * is not available, the user should give an identity matrix (Q.setIdentity()) + * + * \sa compute(const MatrixType&, bool) + */ + template<typename HessMatrixType, typename OrthMatrixType> + RealSchur& computeFromHessenberg(const HessMatrixType& matrixH, const OrthMatrixType& matrixQ, bool computeU); + /** \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 Sets the maximum number of iterations allowed. + * + * If not specified by the user, the maximum number of iterations is m_maxIterationsPerRow times the size + * of the matrix. + */ + RealSchur& setMaxIterations(Index maxIters) + { + m_maxIters = maxIters; + return *this; + } + + /** \brief Returns the maximum number of iterations. */ + Index getMaxIterations() + { + return m_maxIters; + } + + /** \brief Maximum number of iterations per row. + * + * If not otherwise specified, the maximum number of iterations is this number times the size of the + * matrix. It is currently set to 40. + */ + static const int m_maxIterationsPerRow = 40; + + private: + + MatrixType m_matT; + MatrixType m_matU; + ColumnVectorType m_workspaceVector; + HessenbergDecomposition<MatrixType> m_hess; + ComputationInfo m_info; + bool m_isInitialized; + bool m_matUisUptodate; + Index m_maxIters; + + typedef Matrix<Scalar,3,1> Vector3s; + + Scalar computeNormOfT(); + Index findSmallSubdiagEntry(Index iu); + void splitOffTwoRows(Index iu, bool computeU, const 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) +{ + eigen_assert(matrix.cols() == matrix.rows()); + Index maxIters = m_maxIters; + if (maxIters == -1) + maxIters = m_maxIterationsPerRow * matrix.rows(); + + // Step 1. Reduce to Hessenberg form + m_hess.compute(matrix); + + // Step 2. Reduce to real Schur form + computeFromHessenberg(m_hess.matrixH(), m_hess.matrixQ(), computeU); + + return *this; +} +template<typename MatrixType> +template<typename HessMatrixType, typename OrthMatrixType> +RealSchur<MatrixType>& RealSchur<MatrixType>::computeFromHessenberg(const HessMatrixType& matrixH, const OrthMatrixType& matrixQ, bool computeU) +{ + m_matT = matrixH; + if(computeU) + m_matU = matrixQ; + + Index maxIters = m_maxIters; + if (maxIters == -1) + maxIters = m_maxIterationsPerRow * matrixH.rows(); + 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 for current eigenvalue + Index totalIter = 0; // iteration count for whole matrix + Scalar exshift(0); // sum of exceptional shifts + Scalar norm = computeNormOfT(); + + if(norm!=0) + { + while (iu >= 0) + { + Index il = findSmallSubdiagEntry(iu); + + // 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; + totalIter = totalIter + 1; + if (totalIter > maxIters) break; + Index im; + initFrancisQRStep(il, iu, shiftInfo, im, firstHouseholderVector); + performFrancisQRStep(il, im, iu, computeU, firstHouseholderVector, workspace); + } + } + } + if(totalIter <= maxIters) + 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.col(j).segment(0, (std::min)(size,j+2)).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) +{ + using std::abs; + Index res = iu; + while (res > 0) + { + Scalar s = abs(m_matT.coeff(res-1,res-1)) + abs(m_matT.coeff(res,res)); + if (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, const Scalar& exshift) +{ + using std::sqrt; + using std::abs; + 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 = sqrt(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) +{ + using std::sqrt; + using std::abs; + 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 = abs(m_matT.coeff(iu,iu-1)) + 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 = 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) +{ + using std::abs; + 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) * (abs(v.coeff(1)) + abs(v.coeff(2))); + const Scalar rhs = v.coeff(0) * (abs(m_matT.coeff(im-1,im-1)) + abs(Tmm) + abs(m_matT.coeff(im+1,im+1))); + if (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) +{ + eigen_assert(im >= il); + eigen_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 \ No newline at end of file
diff -r 000000000000 -r 13a5d365ba16 src/Eigenvalues/RealSchur_MKL.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/Eigenvalues/RealSchur_MKL.h Thu Oct 13 04:07:23 2016 +0000 @@ -0,0 +1,79 @@ +/* + 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) \ +{ \ + eigen_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 \ No newline at end of file
diff -r 000000000000 -r 13a5d365ba16 src/Eigenvalues/SelfAdjointEigenSolver.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/Eigenvalues/SelfAdjointEigenSolver.h Thu Oct 13 04:07:23 2016 +0000 @@ -0,0 +1,801 @@ +// 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; + + typedef Matrix<Scalar,Size,Size,ColMajor,MaxColsAtCompileTime,MaxColsAtCompileTime> EigenvectorsType; + + /** \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 EigenvectorsType& 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: + static void check_template_parameters() + { + EIGEN_STATIC_ASSERT_NON_INTEGER(Scalar); + } + + EigenvectorsType 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<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) +{ + check_template_parameters(); + + using std::abs; + 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) = numext::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; + EigenvectorsType& mat = m_eivec; + + // map the matrix coefficients to [-1:1] to avoid over- and underflow. + mat = matrix.template triangularView<Lower>(); + RealScalar scale = mat.cwiseAbs().maxCoeff(); + if(scale==RealScalar(0)) scale = RealScalar(1); + mat.template triangularView<Lower>() /= 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(abs(m_subdiag[i]),(abs(diag[i])+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(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; + typedef typename MatrixType::Index Index; + typedef typename SolverType::EigenvectorsType EigenvectorsType; + + /** \internal + * Computes the roots of the characteristic polynomial of \a m. + * For numerical stability m.trace() should be near zero and to avoid over- or underflow m should be normalized. + */ + 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 = (c2*c2_over_3 - c1)*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 = a_over_3*a_over_3*a_over_3 - half_b*half_b; + 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; // since sqrt(q) > 0, atan2 is in [0, pi] and theta is in [0, pi/3] + Scalar cos_theta = cos(theta); + Scalar sin_theta = sin(theta); + // roots are already sorted, since cos is monotonically decreasing on [0, pi] + roots(0) = c2_over_3 - rho*(cos_theta + s_sqrt3*sin_theta); // == 2*rho*cos(theta+2pi/3) + roots(1) = c2_over_3 - rho*(cos_theta - s_sqrt3*sin_theta); // == 2*rho*cos(theta+ pi/3) + roots(2) = c2_over_3 + Scalar(2)*rho*cos_theta; + } + + static inline bool extract_kernel(MatrixType& mat, Ref<VectorType> res, Ref<VectorType> representative) + { + using std::abs; + Index i0; + // Find non-zero column i0 (by construction, there must exist a non zero coefficient on the diagonal): + mat.diagonal().cwiseAbs().maxCoeff(&i0); + // mat.col(i0) is a good candidate for an orthogonal vector to the current eigenvector, + // so let's save it: + representative = mat.col(i0); + Scalar n0, n1; + VectorType c0, c1; + n0 = (c0 = representative.cross(mat.col((i0+1)%3))).squaredNorm(); + n1 = (c1 = representative.cross(mat.col((i0+2)%3))).squaredNorm(); + if(n0>n1) res = c0/std::sqrt(n0); + else res = c1/std::sqrt(n1); + + return true; + } + + static inline void run(SolverType& solver, const MatrixType& mat, int options) + { + 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; + + EigenvectorsType& eivecs = solver.m_eivec; + VectorType& eivals = solver.m_eivalues; + + // Shift the matrix to the mean eigenvalue and map the matrix coefficients to [-1:1] to avoid over- and underflow. + Scalar shift = mat.trace() / Scalar(3); + // TODO Avoid this copy. Currently it is necessary to suppress bogus values when determining maxCoeff and for computing the eigenvectors later + MatrixType scaledMat = mat.template selfadjointView<Lower>(); + scaledMat.diagonal().array() -= shift; + Scalar scale = scaledMat.cwiseAbs().maxCoeff(); + if(scale > 0) scaledMat /= scale; // TODO for scale==0 we could save the remaining operations + + // compute the eigenvalues + computeRoots(scaledMat,eivals); + + // compute the eigenvectors + if(computeEigenvectors) + { + if((eivals(2)-eivals(0))<=Eigen::NumTraits<Scalar>::epsilon()) + { + // All three eigenvalues are numerically the same + eivecs.setIdentity(); + } + else + { + MatrixType tmp; + tmp = scaledMat; + + // Compute the eigenvector of the most distinct eigenvalue + Scalar d0 = eivals(2) - eivals(1); + Scalar d1 = eivals(1) - eivals(0); + Index k(0), l(2); + if(d0 > d1) + { + std::swap(k,l); + d0 = d1; + } + + // Compute the eigenvector of index k + { + tmp.diagonal().array () -= eivals(k); + // By construction, 'tmp' is of rank 2, and its kernel corresponds to the respective eigenvector. + extract_kernel(tmp, eivecs.col(k), eivecs.col(l)); + } + + // Compute eigenvector of index l + if(d0<=2*Eigen::NumTraits<Scalar>::epsilon()*d1) + { + // If d0 is too small, then the two other eigenvalues are numerically the same, + // and thus we only have to ortho-normalize the near orthogonal vector we saved above. + eivecs.col(l) -= eivecs.col(k).dot(eivecs.col(l))*eivecs.col(l); + eivecs.col(l).normalize(); + } + else + { + tmp = scaledMat; + tmp.diagonal().array () -= eivals(l); + + VectorType dummy; + extract_kernel(tmp, eivecs.col(l), dummy); + } + + // Compute last eigenvector from the other two + eivecs.col(1) = eivecs.col(2).cross(eivecs.col(0)).normalized(); + } + } + + // Rescale back to the original size. + eivals *= scale; + eivals.array() += shift; + + 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; + typedef typename SolverType::EigenvectorsType EigenvectorsType; + + static inline void computeRoots(const MatrixType& m, VectorType& roots) + { + using std::sqrt; + const Scalar t0 = Scalar(0.5) * sqrt( numext::abs2(m(0,0)-m(1,1)) + Scalar(4)*numext::abs2(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) + { + using std::sqrt; + using std::abs; + + 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; + + EigenvectorsType& 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) + { + if((eivals(1)-eivals(0))<=abs(eivals(1))*Eigen::NumTraits<Scalar>::epsilon()) + { + eivecs.setIdentity(); + } + else + { + scaledMat.diagonal().array () -= eivals(1); + Scalar a2 = numext::abs2(scaledMat(0,0)); + Scalar c2 = numext::abs2(scaledMat(1,1)); + Scalar b2 = numext::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<typename RealScalar, typename Scalar, typename Index> +static void tridiagonal_qr_step(RealScalar* diag, RealScalar* subdiag, Index start, Index end, Scalar* matrixQ, Index n) +{ + using std::abs; + 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 = numext::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]; + if(td==0) + mu -= abs(e); + else + { + RealScalar e2 = numext::abs2(subdiag[end-1]); + RealScalar h = numext::hypot(td,e); + if(e2==0) mu -= (e / (td + (td>0 ? 1 : -1))) * (e / h); + else mu -= e2 / (td + (td>0 ? h : -h)); + } + + 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) + { + Map<Matrix<Scalar,Dynamic,Dynamic,ColMajor> > q(matrixQ,n,n); + q.applyOnTheRight(k,k+1,rot); + } + } +} + +} // end namespace internal + +} // end namespace Eigen + +#endif // EIGEN_SELFADJOINTEIGENSOLVER_H \ No newline at end of file
diff -r 000000000000 -r 13a5d365ba16 src/Eigenvalues/SelfAdjointEigenSolver_MKL.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/Eigenvalues/SelfAdjointEigenSolver_MKL.h Thu Oct 13 04:07:23 2016 +0000 @@ -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) = numext::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 \ No newline at end of file
diff -r 000000000000 -r 13a5d365ba16 src/Eigenvalues/Tridiagonalization.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/Eigenvalues/Tridiagonalization.h Thu Oct 13 04:07:23 2016 +0000 @@ -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 HouseholderSequence<MatrixType,typename internal::remove_all<typename CoeffVectorType::ConjugateReturnType>::type> 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) +{ + using numext::conj; + 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) +{ + 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) + { + using std::sqrt; + diag[0] = mat(0,0); + RealScalar v1norm2 = numext::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(numext::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) = numext::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 \ No newline at end of file
diff -r 000000000000 -r 13a5d365ba16 src/Geometry/AlignedBox.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/Geometry/AlignedBox.h Thu Oct 13 04:07:23 2016 +0000 @@ -0,0 +1,392 @@ +// 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 + * + * \tparam _Scalar the type of the scalar coefficients + * \tparam _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. + * \warning The result of most methods is undefined when applied to an empty box. You can check for empty boxes using isEmpty(). + * \sa alignedboxtypedefs + */ +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, + /** @} */ + + /** Identifier for 2D corner @{ */ + BottomLeft=0, BottomRight=1, + TopLeft=2, TopRight=3, + /** @} */ + + /** Identifier for 3D corner @{ */ + BottomLeftFloor=0, BottomRightFloor=1, + TopLeftFloor=2, TopRightFloor=3, + BottomLeftCeil=4, BottomRightCeil=5, + TopLeftCeil=6, TopRightCeil=7 + /** @} */ + }; + + + /** Default constructor initializing a null box. */ + inline 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. + * \warning If either component of \a _min is larger than the same component of \a _max, the constructed box is empty. */ + 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>& p) : m_min(p), m_max(m_min) + { } + + ~AlignedBox() {} + + /** \returns the dimension in which the box holds */ + inline Index dim() const { return AmbientDimAtCompileTime==Dynamic ? m_min.size() : 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. + * \sa setEmpty */ + inline bool isEmpty() const { return (m_min.array() > m_max.array()).any(); } + + /** Makes \c *this an empty box. + * \sa isEmpty */ + 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(dim()); + 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>& p) const + { + typename internal::nested<Derived,2>::type p_n(p.derived()); + return (m_min.array()<=p_n.array()).all() && (p_n.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(); } + + /** \returns true if the box \a b is intersecting the box \c *this. + * \sa intersection, clamp */ + inline bool intersects(const AlignedBox& b) const + { return (m_min.array()<=(b.max)().array()).all() && ((b.min)().array()<=m_max.array()).all(); } + + /** Extends \c *this such that it contains the point \a p and returns a reference to \c *this. + * \sa extend(const AlignedBox&) */ + template<typename Derived> + inline AlignedBox& extend(const MatrixBase<Derived>& p) + { + typename internal::nested<Derived,2>::type p_n(p.derived()); + m_min = m_min.cwiseMin(p_n); + m_max = m_max.cwiseMax(p_n); + return *this; + } + + /** Extends \c *this such that it contains the box \a b and returns a reference to \c *this. + * \sa merged, extend(const MatrixBase&) */ + 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. + * \note If the boxes don't intersect, the resulting box is empty. + * \sa intersection(), intersects() */ + 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 + * \note If the boxes don't intersect, the resulting box is empty. + * \sa intersects(), clamp, contains() */ + 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. + * \note Merging with an empty box may result in a box bigger than \c *this. + * \sa extend(const AlignedBox&) */ + 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(const MatrixBase&), squaredExteriorDistance(const AlignedBox&) + */ + template<typename Derived> + inline Scalar squaredExteriorDistance(const MatrixBase<Derived>& p) const; + + /** \returns the squared distance between the boxes \a b and \c *this, + * and zero if the boxes intersect. + * \sa exteriorDistance(const AlignedBox&), squaredExteriorDistance(const MatrixBase&) + */ + 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(const MatrixBase&), exteriorDistance(const AlignedBox&) + */ + template<typename Derived> + inline NonInteger exteriorDistance(const MatrixBase<Derived>& p) const + { using std::sqrt; return sqrt(NonInteger(squaredExteriorDistance(p))); } + + /** \returns the distance between the boxes \a b and \c *this, + * and zero if the boxes intersect. + * \sa squaredExteriorDistance(const AlignedBox&), exteriorDistance(const MatrixBase&) + */ + inline NonInteger exteriorDistance(const AlignedBox& b) const + { using std::sqrt; return 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, const 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 +{ + 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 \ No newline at end of file
diff -r 000000000000 -r 13a5d365ba16 src/Geometry/AngleAxis.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/Geometry/AngleAxis.h Thu Oct 13 04:07:23 2016 +0000 @@ -0,0 +1,240 @@ +// 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(const 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; } + + /** \returns the value of the rotation angle in radian */ + Scalar angle() const { return m_angle; } + /** \returns a read-write reference to the stored angle in radian */ + Scalar& angle() { return m_angle; } + + /** \returns the rotation axis */ + const Vector3& axis() const { return m_axis; } + /** \returns a read-write reference to the stored rotation axis. + * + * \warning The rotation axis must remain a \b unit vector. + */ + 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(Scalar(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, const 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; + using std::sqrt; + Scalar n2 = q.vec().squaredNorm(); + if (n2 < NumTraits<Scalar>::dummy_precision()*NumTraits<Scalar>::dummy_precision()) + { + m_angle = Scalar(0); + m_axis << Scalar(1), Scalar(0), Scalar(0); + } + else + { + m_angle = Scalar(2)*acos((min)((max)(Scalar(-1),q.w()),Scalar(1))); + m_axis = q.vec() / 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 +{ + using std::sin; + using std::cos; + Matrix3 res; + Vector3 sin_axis = sin(m_angle) * m_axis; + Scalar c = 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 \ No newline at end of file
diff -r 000000000000 -r 13a5d365ba16 src/Geometry/EulerAngles.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/Geometry/EulerAngles.h Thu Oct 13 04:07:23 2016 +0000 @@ -0,0 +1,104 @@ +// 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). + * + * The returned angles are in the ranges [0:pi]x[-pi:pi]x[-pi:pi]. + * + * \sa class AngleAxis + */ +template<typename Derived> +inline Matrix<typename MatrixBase<Derived>::Scalar,3,1> +MatrixBase<Derived>::eulerAngles(Index a0, Index a1, Index a2) const +{ + using std::atan2; + using std::sin; + using std::cos; + /* 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 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) + { + res[0] = atan2(coeff(j,i), coeff(k,i)); + if((odd && res[0]<Scalar(0)) || ((!odd) && res[0]>Scalar(0))) + { + res[0] = (res[0] > Scalar(0)) ? res[0] - Scalar(M_PI) : res[0] + Scalar(M_PI); + Scalar s2 = Vector2(coeff(j,i), coeff(k,i)).norm(); + res[1] = -atan2(s2, coeff(i,i)); + } + else + { + Scalar s2 = Vector2(coeff(j,i), coeff(k,i)).norm(); + res[1] = atan2(s2, coeff(i,i)); + } + + // With a=(0,1,0), we have i=0; j=1; k=2, and after computing the first two angles, + // we can compute their respective rotation, and apply its inverse to M. Since the result must + // be a rotation around x, we have: + // + // c2 s1.s2 c1.s2 1 0 0 + // 0 c1 -s1 * M = 0 c3 s3 + // -s2 s1.c2 c1.c2 0 -s3 c3 + // + // Thus: m11.c1 - m21.s1 = c3 & m12.c1 - m22.s1 = s3 + + Scalar s1 = sin(res[0]); + Scalar c1 = cos(res[0]); + res[2] = atan2(c1*coeff(j,k)-s1*coeff(k,k), c1*coeff(j,j) - s1 * coeff(k,j)); + } + else + { + res[0] = atan2(coeff(j,k), coeff(k,k)); + Scalar c2 = Vector2(coeff(i,i), coeff(i,j)).norm(); + if((odd && res[0]<Scalar(0)) || ((!odd) && res[0]>Scalar(0))) { + res[0] = (res[0] > Scalar(0)) ? res[0] - Scalar(M_PI) : res[0] + Scalar(M_PI); + res[1] = atan2(-coeff(i,k), -c2); + } + else + res[1] = atan2(-coeff(i,k), c2); + Scalar s1 = sin(res[0]); + Scalar c1 = cos(res[0]); + res[2] = atan2(s1*coeff(k,i)-c1*coeff(j,i), c1*coeff(j,j) - s1 * coeff(k,j)); + } + if (!odd) + res = -res; + + return res; +} + +} // end namespace Eigen + +#endif // EIGEN_EULERANGLES_H \ No newline at end of file
diff -r 000000000000 -r 13a5d365ba16 src/Geometry/Homogeneous.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/Geometry/Homogeneous.h Thu Oct 13 04:07:23 2016 +0000 @@ -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 + : internal::no_assignment_operator, 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 Scalar(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 \ No newline at end of file
diff -r 000000000000 -r 13a5d365ba16 src/Geometry/Hyperplane.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/Geometry/Hyperplane.h Thu Oct 13 04:07:23 2016 +0000 @@ -0,0 +1,280 @@ +// 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 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, const 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()); + VectorType v0(p2 - p0), v1(p1 - p0); + result.normal() = v0.cross(v1); + RealScalar norm = result.normal().norm(); + if(norm <= v0.norm() * v1.norm() * NumTraits<RealScalar>::epsilon()) + { + Matrix<Scalar,2,3> m; m << v0.transpose(), v1.transpose(); + JacobiSVD<Matrix<Scalar,2,3> > svd(m, ComputeFullV); + result.normal() = svd.matrixV().col(2); + } + else + result.normal() /= norm; + 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 { using std::abs; return 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 + { + using std::abs; + 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(abs(coeffs().coeff(1))>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, const 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 \ No newline at end of file
diff -r 000000000000 -r 13a5d365ba16 src/Geometry/OrthoMethods.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/Geometry/OrthoMethods.h Thu Oct 13 04:07:23 2016 +0000 @@ -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( + numext::conj(lhs.coeff(1) * rhs.coeff(2) - lhs.coeff(2) * rhs.coeff(1)), + numext::conj(lhs.coeff(2) * rhs.coeff(0) - lhs.coeff(0) * rhs.coeff(2)), + numext::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( + numext::conj(lhs.coeff(1) * rhs.coeff(2) - lhs.coeff(2) * rhs.coeff(1)), + numext::conj(lhs.coeff(2) * rhs.coeff(0) - lhs.coeff(0) * rhs.coeff(2)), + numext::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; + DerivedNested lhs(derived()); + 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) = -numext::conj(src.coeff(sndi)) * invnm; + perp.coeffRef(sndi) = numext::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) = -numext::conj(src.y())*invnm; + perp.coeffRef(1) = numext::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) = -numext::conj(src.z())*invnm; + perp.coeffRef(2) = numext::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(-numext::conj(src.y()), numext::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 \ No newline at end of file
diff -r 000000000000 -r 13a5d365ba16 src/Geometry/ParametrizedLine.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/Geometry/ParametrizedLine.h Thu Oct 13 04:07:23 2016 +0000 @@ -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 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 { using std::sqrt; return 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(const 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, const 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(const _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 \ No newline at end of file
diff -r 000000000000 -r 13a5d365ba16 src/Geometry/Quaternion.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/Geometry/Quaternion.h Thu Oct 13 04:07:23 2016 +0000 @@ -0,0 +1,776 @@ +// 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>(Scalar(1), Scalar(0), Scalar(0), Scalar(0)); } + + /** \sa QuaternionBase::Identity(), MatrixBase::setIdentity() + */ + inline QuaternionBase& setIdentity() { coeffs() << Scalar(0), Scalar(0), Scalar(0), Scalar(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; + + template<class OtherDerived> Quaternion<Scalar> slerp(const 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, const 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(const 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 + * + * \tparam _Scalar the scalar type, i.e., the type of the coefficients + * \tparam _Options controls the memory alignment of the coefficients. Can be \# AutoAlign or \# DontAlign. Default is AutoAlign. + * + * 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, quaternions 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 + * + * \warning Operations interpreting the quaternion as rotation have undefined behavior if the quaternion is not normalized. + * + * \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_OPERATORS(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(const Scalar& w, const Scalar& x, const Scalar& y, const 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, (int(_Options)&Aligned)==Aligned ? AutoAlign : DontAlign> > + { + typedef Map<Matrix<_Scalar,4,1>, _Options> Coefficients; + }; +} + +namespace internal { + template<typename _Scalar, int _Options> + struct traits<Map<const Quaternion<_Scalar>, _Options> > : traits<Quaternion<_Scalar, (int(_Options)&Aligned)==Aligned ? AutoAlign : DontAlign> > + { + typedef Map<const Matrix<_Scalar,4,1>, _Options> Coefficients; + typedef traits<Quaternion<_Scalar, (int(_Options)&Aligned)==Aligned ? AutoAlign : DontAlign> > TraitsBase; + enum { + Flags = TraitsBase::Flags & ~LvalueBit + }; + }; +} + +/** \ingroup Geometry_Module + * \brief Quaternion expression mapping a constant memory buffer + * + * \tparam _Scalar the type of the Quaternion coefficients + * \tparam _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_OPERATORS(Map) + using Base::operator*=; + + /** Constructs a Mapped Quaternion object from the pointer \a coeffs + * + * The pointer \a coeffs must reference the four coefficients 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; +}; + +/** \ingroup Geometry_Module + * \brief Expression of a quaternion from a memory buffer + * + * \tparam _Scalar the type of the Quaternion coefficients + * \tparam _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_OPERATORS(Map) + using Base::operator*=; + + /** Constructs a Mapped Quaternion object from the pointer \a coeffs + * + * The pointer \a coeffs must reference the four coefficients 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 scalars as a quaternion */ +typedef Map<Quaternion<float>, 0> QuaternionMapf; +/** \ingroup Geometry_Module + * Map an unaligned array of double precision scalars as a quaternion */ +typedef Map<Quaternion<double>, 0> QuaternionMapd; +/** \ingroup Geometry_Module + * Map a 16-byte aligned array of single precision scalars as a quaternion */ +typedef Map<Quaternion<float>, Aligned> QuaternionMapAlignedf; +/** \ingroup Geometry_Module + * Map a 16-byte 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(const 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 literature (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) +{ + using std::cos; + using std::sin; + Scalar ha = Scalar(0.5)*aa.angle(); // Scalar(0.5) to suppress precision loss warnings + this->w() = cos(ha); + this->vec() = 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; + using std::sqrt; + Vector3 v0 = a.normalized(); + Vector3 v1 = b.normalized(); + Scalar c = v1.dot(v0); + + // if dot == -1, vectors are nearly opposites + // => accurately 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)(c,Scalar(-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() = sqrt(w2); + this->vec() = axis * sqrt(Scalar(1) - w2); + return derived(); + } + Vector3 axis = v0.cross(v1); + Scalar s = 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 > Scalar(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::atan2; + using std::abs; + Quaternion<Scalar> d = (*this) * other.conjugate(); + return Scalar(2) * atan2( d.vec().norm(), abs(d.w()) ); +} + + + +/** \returns the spherical linear interpolation between the two quaternions + * \c *this and \a other at the parameter \a t in [0;1]. + * + * This represents an interpolation for a constant motion between \c *this and \a other, + * see also http://en.wikipedia.org/wiki/Slerp. + */ +template <class Derived> +template <class OtherDerived> +Quaternion<typename internal::traits<Derived>::Scalar> +QuaternionBase<Derived>::slerp(const Scalar& t, const QuaternionBase<OtherDerived>& other) const +{ + using std::acos; + using std::sin; + using std::abs; + static const Scalar one = Scalar(1) - NumTraits<Scalar>::epsilon(); + Scalar d = this->dot(other); + Scalar absD = 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 = sin(theta); + + scale0 = sin( ( Scalar(1) - t ) * theta) / sinTheta; + scale1 = sin( ( t * theta) ) / sinTheta; + } + if(d<Scalar(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) + { + using std::sqrt; + // 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 \ No newline at end of file
diff -r 000000000000 -r 13a5d365ba16 src/Geometry/Rotation2D.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/Geometry/Rotation2D.h Thu Oct 13 04:07:23 2016 +0000 @@ -0,0 +1,160 @@ +// 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(const Scalar& a) : m_angle(a) {} + + /** Default constructor wihtout initialization. The represented rotation is undefined. */ + Rotation2D() {} + + /** \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() 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(const 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, const 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) +{ + using std::atan2; + EIGEN_STATIC_ASSERT(Derived::RowsAtCompileTime==2 && Derived::ColsAtCompileTime==2,YOU_MADE_A_PROGRAMMING_MISTAKE) + m_angle = 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 +{ + using std::sin; + using std::cos; + Scalar sinA = sin(m_angle); + Scalar cosA = cos(m_angle); + return (Matrix2() << cosA, -sinA, sinA, cosA).finished(); +} + +} // end namespace Eigen + +#endif // EIGEN_ROTATION2D_H \ No newline at end of file
diff -r 000000000000 -r 13a5d365ba16 src/Geometry/RotationBase.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/Geometry/RotationBase.h Thu Oct 13 04:07:23 2016 +0000 @@ -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 \ No newline at end of file
diff -r 000000000000 -r 13a5d365ba16 src/Geometry/Scaling.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/Geometry/Scaling.h Thu Oct 13 04:07:23 2016 +0000 @@ -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, const 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(const Scalar& sx, const Scalar& sy) +{ return DiagonalMatrix<Scalar,2>(sx, sy); } +/** Constructs a 3D axis aligned scaling */ +template<typename Scalar> +static inline DiagonalMatrix<Scalar,3> Scaling(const Scalar& sx, const Scalar& sy, const 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 \ No newline at end of file
diff -r 000000000000 -r 13a5d365ba16 src/Geometry/Transform.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/Geometry/Transform.h Thu Oct 13 04:07:23 2016 +0000 @@ -0,0 +1,1474 @@ +// 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; + +template<int Mode> struct transform_make_affine; + +} // 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,DiagonalMatrix) + * 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 points, the latters are automatically promoted to homogeneous vectors + * before doing the matrix product. The conventions 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 Scaling \b DiagonalMatrix S (Dim)x(Dim): + * \f$ \left( \begin{array}{cc} + * S & 0\\ + * 0\,...\,0 & 1 + * \end{array} \right) \f$ + * + * \b Column \b point v (Dim)x(1): + * \f$ \left( \begin{array}{c} + * v\\ + * 1 + * \end{array} \right) \f$ + * + * \b Set \b of \b column \b points 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) && (Options&RowMajor)==0> LinearPart; + /** type of read reference to the linear part of the transformation */ + typedef const Block<ConstMatrixType,Dim,Dim,int(Mode)==(AffineCompact) && (Options&RowMajor)==0> 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(); + internal::transform_make_affine<(int(Mode)==Affine) ? Affine : AffineCompact>::run(m_matrix); + } + + 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 can be either: + * \li an homogeneous vector of size Dim+1, + * \li a set of homogeneous vectors of size Dim+1 x N, + * \li a transformation matrix of size Dim+1 x Dim+1. + * + * Moreover, if \c *this represents an affine transformation (i.e., Mode!=Projective), then \a other can also be: + * \li a point of size Dim (computes: \code this->linear() * other + this->translation()\endcode), + * \li a set of N points as a Dim x N matrix (computes: \code (this->linear() * other).colwise() + this->translation()\endcode), + * + * In all cases, the return type is a matrix or vector of same sizes as the right-hand-side \a other. + * + * If you want to interpret \a other as a linear or affine transformation, then first convert it to a Transform<> type, + * or do your own cooking. + * + * Finally, if you want to apply Affine transformations to vectors, then explicitly apply the linear part only: + * \code + * Affine3f A; + * Vector3f v1, v2; + * v2 = A.linear() * v1; + * \endcode + * + */ + // note: this function is defined here because some compilers cannot find the respective declaration + template<typename OtherDerived> + EIGEN_STRONG_INLINE const typename OtherDerived::PlainObject + 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 can 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(const Scalar& s); + inline Transform& prescale(const 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(const Scalar& sx, const Scalar& sy); + Transform& preshear(const Scalar& sx, const 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)?int(Affine):int(Mode))> operator*(const UniformScaling<Scalar>& s) const + { + Transform<Scalar,Dim,(int(Mode)==int(Isometry)?int(Affine):int(Mode)),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, const 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() + { + internal::transform_make_affine<int(Mode)>::run(m_matrix); + } + + /** \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(const 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(const 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(const Scalar& sx, const 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(const Scalar& sx, const 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 { + +template<int Mode> +struct transform_make_affine +{ + template<typename MatrixType> + static void run(MatrixType &mat) + { + static const int Dim = MatrixType::ColsAtCompileTime-1; + mat.template block<1,Dim>(Dim,0).setZero(); + mat.coeffRef(Dim,Dim) = typename MatrixType::Scalar(1); + } +}; + +template<> +struct transform_make_affine<AffineCompact> +{ + template<typename MatrixType> static void run(MatrixType &) { } +}; + +// 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 \ No newline at end of file
diff -r 000000000000 -r 13a5d365ba16 src/Geometry/Translation.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/Geometry/Translation.h Thu Oct 13 04:07:23 2016 +0000 @@ -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, const 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 \ No newline at end of file
diff -r 000000000000 -r 13a5d365ba16 src/Geometry/Umeyama.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/Geometry/Umeyama.h Thu Oct 13 04:07:23 2016 +0000 @@ -0,0 +1,177 @@ +// 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 = RealScalar(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()<Scalar(0)) S(m-1) = Scalar(-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() > Scalar(0) ) { + Rt.block(0,0,m,m).noalias() = svd.matrixU()*svd.matrixV().transpose(); + } else { + const Scalar s = S(m-1); S(m-1) = Scalar(-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(); + } + + if (with_scaling) + { + // Eq. (42) + const Scalar c = Scalar(1)/src_var * svd.singularValues().dot(S); + + // Eq. (41) + Rt.col(m).head(m) = dst_mean; + Rt.col(m).head(m).noalias() -= c*Rt.topLeftCorner(m,m)*src_mean; + Rt.block(0,0,m,m) *= c; + } + else + { + Rt.col(m).head(m) = dst_mean; + Rt.col(m).head(m).noalias() -= Rt.topLeftCorner(m,m)*src_mean; + } + + return Rt; +} + +} // end namespace Eigen + +#endif // EIGEN_UMEYAMA_H \ No newline at end of file
diff -r 000000000000 -r 13a5d365ba16 src/Householder/BlockHouseholder.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/Householder/BlockHouseholder.h Thu Oct 13 04:07:23 2016 +0000 @@ -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, ColMajor> 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 \ No newline at end of file
diff -r 000000000000 -r 13a5d365ba16 src/Householder/Householder.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/Householder/Householder.h Thu Oct 13 04:07:23 2016 +0000 @@ -0,0 +1,171 @@ +// 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 +{ + using std::sqrt; + using numext::conj; + + 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) && numext::imag(c0)==RealScalar(0)) + { + tau = RealScalar(0); + beta = numext::real(c0); + essential.setZero(); + } + else + { + beta = sqrt(numext::abs2(c0) + tailSqNorm); + if (numext::real(c0)>=RealScalar(0)) + beta = -beta; + essential = tail / (c0 - beta); + tau = 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 \ No newline at end of file
diff -r 000000000000 -r 13a5d365ba16 src/Householder/HouseholderSequence.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/Householder/HouseholderSequence.h Thu Oct 13 04:07:23 2016 +0000 @@ -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> > +{ + typedef typename internal::hseq_side_dependent_impl<VectorsType,CoeffsType,Side>::EssentialVectorType EssentialVectorType; + + public: + 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 HouseholderSequence< + typename internal::conditional<NumTraits<Scalar>::IsComplex, + typename internal::remove_all<typename VectorsType::ConjugateReturnType>::type, + VectorsType>::type, + 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.conjugate(), 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 \ No newline at end of file
diff -r 000000000000 -r 13a5d365ba16 src/Jacobi/Jacobi.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/Jacobi/Jacobi.h Thu Oct 13 04:07:23 2016 +0000 @@ -0,0 +1,433 @@ +// 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) + { + using numext::conj; + return JacobiRotation(m_c * other.m_c - conj(m_s) * other.m_s, + conj(m_c * conj(other.m_s) + conj(m_s) * conj(other.m_c))); + } + + /** Returns the transposed transformation */ + JacobiRotation transpose() const { using numext::conj; return JacobiRotation(m_c, -conj(m_s)); } + + /** Returns the adjoint transformation */ + JacobiRotation adjoint() const { using numext::conj; return JacobiRotation(conj(m_c), -m_s); } + + template<typename Derived> + bool makeJacobi(const MatrixBase<Derived>&, typename Derived::Index p, typename Derived::Index q); + bool makeJacobi(const RealScalar& x, const Scalar& y, const 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(const RealScalar& x, const Scalar& y, const RealScalar& z) +{ + using std::sqrt; + using std::abs; + 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)*abs(y)); + RealScalar w = sqrt(numext::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) / sqrt(numext::abs2(t)+RealScalar(1)); + m_s = - sign_t * (numext::conj(y) / abs(y)) * 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(numext::real(m.coeff(p,p)), m.coeff(p,q), numext::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) +{ + using std::sqrt; + using std::abs; + using numext::conj; + + if(q==Scalar(0)) + { + m_c = numext::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/abs(q); + if(r) *r = abs(q); + } + else + { + RealScalar p1 = numext::norm1(p); + RealScalar q1 = numext::norm1(q); + if(p1>=q1) + { + Scalar ps = p / p1; + RealScalar p2 = numext::abs2(ps); + Scalar qs = q / p1; + RealScalar q2 = numext::abs2(qs); + + RealScalar u = sqrt(RealScalar(1) + q2/p2); + if(numext::real(p)<RealScalar(0)) + u = -u; + + m_c = Scalar(1)/u; + m_s = -qs*conj(ps)*(m_c/p2); + if(r) *r = p * u; + } + else + { + Scalar ps = p / q1; + RealScalar p2 = numext::abs2(ps); + Scalar qs = q / q1; + RealScalar q2 = numext::abs2(qs); + + RealScalar u = q1 * sqrt(p2 + q2); + if(numext::real(p)<RealScalar(0)) + u = -u; + + p1 = abs(p); + ps = p/p1; + m_c = p1/u; + m_s = -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) +{ + using std::sqrt; + using std::abs; + if(q==Scalar(0)) + { + m_c = p<Scalar(0) ? Scalar(-1) : Scalar(1); + m_s = Scalar(0); + if(r) *r = abs(p); + } + else if(p==Scalar(0)) + { + m_c = Scalar(0); + m_s = q<Scalar(0) ? Scalar(1) : Scalar(-1); + if(r) *r = abs(q); + } + else if(abs(p) > abs(q)) + { + Scalar t = q/p; + Scalar u = sqrt(Scalar(1) + numext::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 = sqrt(Scalar(1) + numext::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); + + OtherScalar c = j.c(); + OtherScalar s = j.s(); + if (c==OtherScalar(1) && s==OtherScalar(0)) + return; + + /*** 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>(c); + const Packet ps = pset1<Packet>(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] = c * xi + numext::conj(s) * yi; + y[i] = -s * xi + numext::conj(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] = c * xi + numext::conj(s) * yi; + y[i] = -s * xi + numext::conj(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>(c); + const Packet ps = pset1<Packet>(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 = c * xi + numext::conj(s) * yi; + *y = -s * xi + numext::conj(c) * yi; + x += incrx; + y += incry; + } + } +} + +} // end namespace internal + +} // end namespace Eigen + +#endif // EIGEN_JACOBI_H \ No newline at end of file
diff -r 000000000000 -r 13a5d365ba16 src/LU/Determinant.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/LU/Determinant.h Thu Oct 13 04:07:23 2016 +0000 @@ -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 +{ + eigen_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 \ No newline at end of file
diff -r 000000000000 -r 13a5d365ba16 src/LU/FullPivLU.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/LU/FullPivLU.h Thu Oct 13 04:07:23 2016 +0000 @@ -0,0 +1,751 @@ +// 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 \f$ A = P^{-1} L U Q^{-1} \f$ 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 + { + using std::abs; + eigen_assert(m_isInitialized && "LU is not initialized."); + RealScalar premultiplied_threshold = abs(m_maxpivot) * threshold(); + Index result = 0; + for(Index i = 0; i < m_nonzero_pivots; ++i) + result += (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: + + static void check_template_parameters() + { + EIGEN_STATIC_ASSERT_NON_INTEGER(Scalar); + } + + 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) +{ + check_template_parameters(); + + // the permutations are stored as int indices, so just to be sure: + eigen_assert(matrix.rows()<=NumTraits<int>::highest() && matrix.cols()<=NumTraits<int>::highest()); + + 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: \f$ P^{-1} L U Q^{-1} \f$. + * This function is provided for debug purposes. */ +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 + { + using std::abs; + 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 + { + using std::abs; + 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().rank(); + 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 \ No newline at end of file
diff -r 000000000000 -r 13a5d365ba16 src/LU/Inverse.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/LU/Inverse.h Thu Oct 13 04:07:23 2016 +0000 @@ -0,0 +1,400 @@ +// 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 + ) + { + using std::abs; + 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 + ) + { + using std::abs; + 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 + ) + { + using std::abs; + 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 + ) + { + using std::abs; + 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 determinant. + * \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 \ No newline at end of file
diff -r 000000000000 -r 13a5d365ba16 src/LU/PartialPivLU.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/LU/PartialPivLU.h Thu Oct 13 04:07:23 2016 +0000 @@ -0,0 +1,509 @@ +// 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: + + static void check_template_parameters() + { + EIGEN_STATIC_ASSERT_NON_INTEGER(Scalar); + } + + 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; + Index 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] = PivIndex(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; + Index 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) +{ + check_template_parameters(); + + // the row permutation is stored as int indices, so just to be sure: + eigen_assert(matrix.rows()<NumTraits<int>::highest()); + + 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 \ No newline at end of file
diff -r 000000000000 -r 13a5d365ba16 src/LU/PartialPivLU_MKL.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/LU/PartialPivLU_MKL.h Thu Oct 13 04:07:23 2016 +0000 @@ -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 \ No newline at end of file
diff -r 000000000000 -r 13a5d365ba16 src/QR/ColPivHouseholderQR.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/QR/ColPivHouseholderQR.h Thu Oct 13 04:07:23 2016 +0000 @@ -0,0 +1,580 @@ +// 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 HouseholderSequence<MatrixType,typename internal::remove_all<typename HCoeffsType::ConjugateReturnType>::type> HouseholderSequenceType; + + private: + + typedef typename PermutationType::Index PermIndexType; + + public: + + /** + * \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), + 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 ColPivHouseholderQR() + */ + ColPivHouseholderQR(Index rows, Index cols) + : m_qr(rows, cols), + m_hCoeffs((std::min)(rows,cols)), + m_colsPermutation(PermIndexType(cols)), + m_colsTranspositions(cols), + m_temp(cols), + m_colSqNorms(cols), + m_isInitialized(false), + m_usePrescribedThreshold(false) {} + + /** \brief Constructs a QR factorization from a given matrix + * + * This constructor computes the QR factorization of the matrix \a matrix by calling + * the method compute(). It is a short cut for: + * + * \code + * ColPivHouseholderQR<MatrixType> qr(matrix.rows(), matrix.cols()); + * qr.compute(matrix); + * \endcode + * + * \sa compute() + */ + ColPivHouseholderQR(const MatrixType& matrix) + : m_qr(matrix.rows(), matrix.cols()), + m_hCoeffs((std::min)(matrix.rows(),matrix.cols())), + m_colsPermutation(PermIndexType(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; + HouseholderSequenceType matrixQ(void) const + { + return householderQ(); + } + + /** \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; + } + + /** \returns a reference to the matrix where the result Householder QR is stored + * \warning The strict lower part of this matrix contains internal values. + * Only the upper triangular part should be referenced. To get it, use + * \code matrixR().template triangularView<Upper>() \endcode + * For rank-deficient matrices, use + * \code + * matrixR().topLeftCorner(rank(), rank()).template triangularView<Upper>() + * \endcode + */ + const MatrixType& matrixR() const + { + eigen_assert(m_isInitialized && "ColPivHouseholderQR is not initialized."); + return m_qr; + } + + ColPivHouseholderQR& compute(const MatrixType& matrix); + + /** \returns a const reference to the column permutation 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 + { + using std::abs; + eigen_assert(m_isInitialized && "ColPivHouseholderQR is not initialized."); + RealScalar premultiplied_threshold = abs(m_maxpivot) * threshold(); + Index result = 0; + for(Index i = 0; i < m_nonzero_pivots; ++i) + result += (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(); } + + /** \returns a const reference to the vector of Householder coefficients used to represent the factor \c Q. + * + * For advanced uses only. + */ + 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() * RealScalar(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; } + + /** \brief Reports whether the QR factorization was succesful. + * + * \note This function always returns \c Success. It is provided for compatibility + * with other factorization routines. + * \returns \c Success + */ + ComputationInfo info() const + { + eigen_assert(m_isInitialized && "Decomposition is not initialized."); + return Success; + } + + protected: + + static void check_template_parameters() + { + EIGEN_STATIC_ASSERT_NON_INTEGER(Scalar); + } + + 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 +{ + using std::abs; + 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 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(); +} + +/** Performs the QR factorization of the given matrix \a matrix. The result of + * the factorization is stored into \c *this, and a reference to \c *this + * is returned. + * + * \sa class ColPivHouseholderQR, ColPivHouseholderQR(const MatrixType&) + */ +template<typename MatrixType> +ColPivHouseholderQR<MatrixType>& ColPivHouseholderQR<MatrixType>::compute(const MatrixType& matrix) +{ + check_template_parameters(); + + using std::abs; + Index rows = matrix.rows(); + Index cols = matrix.cols(); + Index size = matrix.diagonalSize(); + + // the column permutation is stored as int indices, so just to be sure: + eigen_assert(cols<=NumTraits<int>::highest()); + + 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() * numext::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; + + // Track the number of meaningful pivots but do not stop the decomposition to make + // sure that the initial matrix is properly reproduced. See bug 941. + if(m_nonzero_pivots==size && biggest_col_sq_norm < threshold_helper * RealScalar(rows-k)) + m_nonzero_pivots = k; + + // 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(abs(beta) > m_maxpivot) m_maxpivot = 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(PermIndexType(cols)); + for(PermIndexType k = 0; k < size/*m_nonzero_pivots*/; ++k) + m_colsPermutation.applyTranspositionOnTheRight(k, PermIndexType(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 Index 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().matrixR() + .topLeftCorner(nonzero_pivots, nonzero_pivots) + .template triangularView<Upper>() + .solveInPlace(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. + * You can extract the meaningful part only by using: + * \code qr.householderQ().setLength(qr.nonzeroPivots()) \endcode*/ +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()); +} + +/** \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 \ No newline at end of file
diff -r 000000000000 -r 13a5d365ba16 src/QR/ColPivHouseholderQR_MKL.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/QR/ColPivHouseholderQR_MKL.h Thu Oct 13 04:07:23 2016 +0000 @@ -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) \ +\ +{ \ + using std::abs; \ + typedef Matrix<EIGTYPE, Dynamic, Dynamic, EIGCOLROW, Dynamic, Dynamic> MatrixType; \ + 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 = abs(m_maxpivot) * threshold(); \ + lapack_int *perm = m_colsPermutation.indices().data(); \ + for(i=0;i<size;i++) { \ + m_nonzero_pivots += (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 \ No newline at end of file
diff -r 000000000000 -r 13a5d365ba16 src/QR/FullPivHouseholderQR.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/QR/FullPivHouseholderQR.h Thu Oct 13 04:07:23 2016 +0000 @@ -0,0 +1,622 @@ +// 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, + EIGEN_SIZE_MIN_PREFER_DYNAMIC(ColsAtCompileTime,RowsAtCompileTime), RowMajor, 1, + EIGEN_SIZE_MIN_PREFER_FIXED(MaxColsAtCompileTime,MaxRowsAtCompileTime)> IntDiagSizeVectorType; + typedef PermutationMatrix<ColsAtCompileTime, MaxColsAtCompileTime> PermutationType; + 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((std::min)(rows,cols)), + m_cols_transpositions((std::min)(rows,cols)), + m_cols_permutation(cols), + m_temp(cols), + m_isInitialized(false), + m_usePrescribedThreshold(false) {} + + /** \brief Constructs a QR factorization from a given matrix + * + * This constructor computes the QR factorization of the matrix \a matrix by calling + * the method compute(). It is a short cut for: + * + * \code + * FullPivHouseholderQR<MatrixType> qr(matrix.rows(), matrix.cols()); + * qr.compute(matrix); + * \endcode + * + * \sa compute() + */ + FullPivHouseholderQR(const MatrixType& matrix) + : m_qr(matrix.rows(), matrix.cols()), + m_hCoeffs((std::min)(matrix.rows(), matrix.cols())), + m_rows_transpositions((std::min)(matrix.rows(), matrix.cols())), + m_cols_transpositions((std::min)(matrix.rows(), matrix.cols())), + m_cols_permutation(matrix.cols()), + m_temp(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 + * \c *this is the QR decomposition. + * + * \param b the right-hand-side of the equation to solve. + * + * \returns the exact or least-square solution if the rank is greater or equal to the number of columns of A, + * and an arbitrary solution otherwise. + * + * \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); + + /** \returns a const reference to the column permutation matrix */ + const PermutationType& colsPermutation() const + { + eigen_assert(m_isInitialized && "FullPivHouseholderQR is not initialized."); + return m_cols_permutation; + } + + /** \returns a const reference to the vector of indices representing the rows transpositions */ + const IntDiagSizeVectorType& 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 + { + using std::abs; + eigen_assert(m_isInitialized && "FullPivHouseholderQR is not initialized."); + RealScalar premultiplied_threshold = abs(m_maxpivot) * threshold(); + Index result = 0; + for(Index i = 0; i < m_nonzero_pivots; ++i) + result += (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(); } + + /** \returns a const reference to the vector of Householder coefficients used to represent the factor \c Q. + * + * For advanced uses only. + */ + 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() * RealScalar(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: + + static void check_template_parameters() + { + EIGEN_STATIC_ASSERT_NON_INTEGER(Scalar); + } + + MatrixType m_qr; + HCoeffsType m_hCoeffs; + IntDiagSizeVectorType m_rows_transpositions; + IntDiagSizeVectorType 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 +{ + using std::abs; + 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 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(); +} + +/** Performs the QR factorization of the given matrix \a matrix. The result of + * the factorization is stored into \c *this, and a reference to \c *this + * is returned. + * + * \sa class FullPivHouseholderQR, FullPivHouseholderQR(const MatrixType&) + */ +template<typename MatrixType> +FullPivHouseholderQR<MatrixType>& FullPivHouseholderQR<MatrixType>::compute(const MatrixType& matrix) +{ + check_template_parameters(); + + using std::abs; + 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() * RealScalar(size); + + m_rows_transpositions.resize(size); + m_cols_transpositions.resize(size); + 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(abs(beta) > m_maxpivot) m_maxpivot = 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)); + } + + 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 FullPivHouseholderQR<MatrixType>::IntDiagSizeVectorType IntDiagSizeVectorType; + 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 IntDiagSizeVectorType& 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 + { + using numext::conj; + // 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), 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 IntDiagSizeVectorType::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 \ No newline at end of file
diff -r 000000000000 -r 13a5d365ba16 src/QR/HouseholderQR.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/QR/HouseholderQR.h Thu Oct 13 04:07:23 2016 +0000 @@ -0,0 +1,388 @@ +// 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 HouseholderSequence<MatrixType,typename internal::remove_all<typename HCoeffsType::ConjugateReturnType>::type> 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) {} + + /** \brief Constructs a QR factorization from a given matrix + * + * This constructor computes the QR factorization of the matrix \a matrix by calling + * the method compute(). It is a short cut for: + * + * \code + * HouseholderQR<MatrixType> qr(matrix.rows(), matrix.cols()); + * qr.compute(matrix); + * \endcode + * + * \sa compute() + */ + 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()); + } + + /** This method returns an expression of the unitary matrix Q as a sequence of Householder transformations. + * + * The returned expression can directly be used to perform matrix products. It can also be assigned to a dense Matrix object. + * Here is an example showing how to recover the full or thin matrix Q, as well as how to perform matrix products using operator*: + * + * Example: \include HouseholderQR_householderQ.cpp + * Output: \verbinclude HouseholderQR_householderQ.out + */ + 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(); } + + /** \returns a const reference to the vector of Householder coefficients used to represent the factor \c Q. + * + * For advanced uses only. + */ + const HCoeffsType& hCoeffs() const { return m_hCoeffs; } + + protected: + + static void check_template_parameters() + { + EIGEN_STATIC_ASSERT_NON_INTEGER(Scalar); + } + + MatrixType m_qr; + HCoeffsType m_hCoeffs; + RowVectorType m_temp; + bool m_isInitialized; +}; + +template<typename MatrixType> +typename MatrixType::RealScalar HouseholderQR<MatrixType>::absDeterminant() const +{ + using std::abs; + 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 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, + typename MatrixQRScalar = typename MatrixQR::Scalar, + bool InnerStrideIsOne = (MatrixQR::InnerStrideAtCompileTime == 1 && HCoeffs::InnerStrideAtCompileTime == 1)> +struct householder_qr_inplace_blocked +{ + // This is specialized for MKL-supported Scalar types in HouseholderQR_MKL.h + static void run(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 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 + +/** Performs the QR factorization of the given matrix \a matrix. The result of + * the factorization is stored into \c *this, and a reference to \c *this + * is returned. + * + * \sa class HouseholderQR, HouseholderQR(const MatrixType&) + */ +template<typename MatrixType> +HouseholderQR<MatrixType>& HouseholderQR<MatrixType>::compute(const MatrixType& matrix) +{ + check_template_parameters(); + + 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<MatrixType, HCoeffsType>::run(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 \ No newline at end of file
diff -r 000000000000 -r 13a5d365ba16 src/QR/HouseholderQR_MKL.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/QR/HouseholderQR_MKL.h Thu Oct 13 04:07:23 2016 +0000 @@ -0,0 +1,71 @@ +/* + 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 "../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> \ +struct householder_qr_inplace_blocked<MatrixQR, HCoeffs, EIGTYPE, true> \ +{ \ + static void run(MatrixQR& mat, HCoeffs& hCoeffs, \ + typename MatrixQR::Index = 32, \ + typename MatrixQR::Scalar* = 0) \ + { \ + lapack_int m = (lapack_int) mat.rows(); \ + lapack_int n = (lapack_int) mat.cols(); \ + lapack_int lda = (lapack_int) 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 \ No newline at end of file
diff -r 000000000000 -r 13a5d365ba16 src/SVD/JacobiSVD.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/SVD/JacobiSVD.h Thu Oct 13 04:07:23 2016 +0000 @@ -0,0 +1,976 @@ +// 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.~QRType(); + ::new (&m_qr) QRType(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: + typedef FullPivHouseholderQR<MatrixType> QRType; + QRType 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.~QRType(); + ::new (&m_qr) QRType(svd.cols(), svd.rows()); + } + m_adjoint.resize(svd.cols(), svd.rows()); + if (svd.m_computeFullV) m_workspace.resize(svd.cols()); + } + + bool run(JacobiSVD<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: + typedef FullPivHouseholderQR<TransposeTypeWithSameStorageOrder> QRType; + QRType 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.~QRType(); + ::new (&m_qr) QRType(svd.rows(), svd.cols()); + } + if (svd.m_computeFullU) m_workspace.resize(svd.rows()); + else if (svd.m_computeThinU) m_workspace.resize(svd.cols()); + } + + bool run(JacobiSVD<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: + typedef ColPivHouseholderQR<MatrixType> QRType; + QRType 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.~QRType(); + ::new (&m_qr) QRType(svd.cols(), svd.rows()); + } + if (svd.m_computeFullV) m_workspace.resize(svd.cols()); + else if (svd.m_computeThinV) m_workspace.resize(svd.rows()); + m_adjoint.resize(svd.cols(), svd.rows()); + } + + bool run(JacobiSVD<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: + typedef ColPivHouseholderQR<TransposeTypeWithSameStorageOrder> QRType; + QRType 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.~QRType(); + ::new (&m_qr) QRType(svd.rows(), svd.cols()); + } + if (svd.m_computeFullU) m_workspace.resize(svd.rows()); + else if (svd.m_computeThinU) m_workspace.resize(svd.cols()); + } + + bool run(JacobiSVD<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: + typedef HouseholderQR<MatrixType> QRType; + QRType 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.~QRType(); + ::new (&m_qr) QRType(svd.cols(), svd.rows()); + } + if (svd.m_computeFullV) m_workspace.resize(svd.cols()); + else if (svd.m_computeThinV) m_workspace.resize(svd.rows()); + m_adjoint.resize(svd.cols(), svd.rows()); + } + + bool run(JacobiSVD<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: + typedef HouseholderQR<TransposeTypeWithSameStorageOrder> QRType; + QRType 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) + { + using std::sqrt; + Scalar z; + JacobiRotation<Scalar> rot; + RealScalar n = sqrt(numext::abs2(work_matrix.coeff(p,p)) + numext::abs2(work_matrix.coeff(q,p))); + + if(n==0) + { + z = abs(work_matrix.coeff(p,q)) / work_matrix.coeff(p,q); + work_matrix.row(p) *= z; + if(svd.computeU()) svd.m_matrixU.col(p) *= conj(z); + if(work_matrix.coeff(q,q)!=Scalar(0)) + { + z = abs(work_matrix.coeff(q,q)) / work_matrix.coeff(q,q); + work_matrix.row(q) *= z; + if(svd.computeU()) svd.m_matrixU.col(q) *= conj(z); + } + // otherwise the second row is already zero, so we have nothing to do. + } + else + { + rot.c() = conj(work_matrix.coeff(p,p)) / n; + rot.s() = work_matrix.coeff(q,p) / n; + work_matrix.applyOnTheLeft(p,q,rot); + if(svd.computeU()) svd.m_matrixU.applyOnTheRight(p,q,rot.adjoint()); + if(work_matrix.coeff(p,q) != Scalar(0)) + { + Scalar z = abs(work_matrix.coeff(p,q)) / work_matrix.coeff(p,q); + work_matrix.col(q) *= z; + if(svd.computeV()) svd.m_matrixV.col(q) *= z; + } + if(work_matrix.coeff(q,q) != Scalar(0)) + { + z = abs(work_matrix.coeff(q,q)) / work_matrix.coeff(q,q); + work_matrix.row(q) *= z; + if(svd.computeU()) svd.m_matrixU.col(q) *= conj(z); + } + } + } +}; + +template<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) +{ + using std::sqrt; + using std::abs; + Matrix<RealScalar,2,2> m; + m << numext::real(matrix.coeff(p,p)), numext::real(matrix.coeff(p,q)), + numext::real(matrix.coeff(q,p)), numext::real(matrix.coeff(q,q)); + JacobiRotation<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 t2d2 = numext::hypot(t,d); + rot1.c() = abs(t)/t2d2; + rot1.s() = d/t2d2; + if(t<RealScalar(0)) + rot1.s() = -rot1.s(); + } + 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_usePrescribedThreshold(false), + m_computationOptions(0), + m_rows(-1), m_cols(-1), m_diagSize(0) + {} + + + /** \brief Default Constructor with memory preallocation + * + * Like the default constructor but with preallocation of the internal data + * according to the specified problem size. + * \sa JacobiSVD() + */ + JacobiSVD(Index rows, Index cols, unsigned int computationOptions = 0) + : m_isInitialized(false), + m_isAllocated(false), + m_usePrescribedThreshold(false), + m_computationOptions(0), + m_rows(-1), m_cols(-1) + { + allocate(rows, cols, computationOptions); + } + + /** \brief Constructor performing the decomposition of given matrix. + * + * \param matrix the matrix to decompose + * \param computationOptions optional parameter allowing to specify if you want full or thin U or V unitaries to be computed. + * By default, none is computed. This is a bit-field, the possible bits are #ComputeFullU, #ComputeThinU, + * #ComputeFullV, #ComputeThinV. + * + * Thin unitaries are only available if your matrix type has a Dynamic number of columns (for example MatrixXf). They also are not + * available with the (non-default) FullPivHouseholderQR preconditioner. + */ + JacobiSVD(const MatrixType& matrix, unsigned int computationOptions = 0) + : m_isInitialized(false), + m_isAllocated(false), + m_usePrescribedThreshold(false), + m_computationOptions(0), + m_rows(-1), m_cols(-1) + { + compute(matrix, computationOptions); + } + + /** \brief Method performing the decomposition of given matrix using custom options. + * + * \param matrix the matrix to decompose + * \param computationOptions optional parameter allowing to specify if you want full or thin U or V unitaries to be computed. + * By default, none is computed. This is a bit-field, the possible bits are #ComputeFullU, #ComputeThinU, + * #ComputeFullV, #ComputeThinV. + * + * Thin unitaries are only available if your matrix type has a Dynamic number of columns (for example MatrixXf). They also are not + * available with the (non-default) FullPivHouseholderQR preconditioner. + */ + JacobiSVD& compute(const MatrixType& matrix, unsigned int computationOptions); + + /** \brief Method performing the decomposition of given matrix using current options. + * + * \param matrix the matrix to decompose + * + * This method uses the current \a computationOptions, as already passed to the constructor or to compute(const MatrixType&, unsigned int). + */ + JacobiSVD& compute(const MatrixType& matrix) + { + return compute(matrix, m_computationOptions); + } + + /** \returns the \a U matrix. + * + * For the SVD decomposition of a n-by-p matrix, letting \a m be the minimum of \a n and \a p, + * the U matrix is n-by-n if you asked for #ComputeFullU, and is n-by-m if you asked for #ComputeThinU. + * + * The \a m first columns of \a U are the left singular vectors of the matrix being decomposed. + * + * This method asserts that you asked for \a U to be computed. + */ + const MatrixUType& matrixU() const + { + eigen_assert(m_isInitialized && "JacobiSVD is not initialized."); + eigen_assert(computeU() && "This JacobiSVD decomposition didn't compute U. Did you ask for it?"); + return m_matrixU; + } + + /** \returns the \a V matrix. + * + * For the SVD decomposition of a n-by-p matrix, letting \a m be the minimum of \a n and \a p, + * the V matrix is p-by-p if you asked for #ComputeFullV, and is p-by-m if you asked for ComputeThinV. + * + * The \a m first columns of \a V are the right singular vectors of the matrix being decomposed. + * + * This method asserts that you asked for \a V to be computed. + */ + const MatrixVType& matrixV() const + { + eigen_assert(m_isInitialized && "JacobiSVD is not initialized."); + eigen_assert(computeV() && "This JacobiSVD decomposition didn't compute V. Did you ask for it?"); + return m_matrixV; + } + + /** \returns the vector of singular values. + * + * For the SVD decomposition of a n-by-p matrix, letting \a m be the minimum of \a n and \a p, the + * returned vector has size \a m. Singular values are always sorted in decreasing order. + */ + const SingularValuesType& singularValues() const + { + eigen_assert(m_isInitialized && "JacobiSVD is not initialized."); + return m_singularValues; + } + + /** \returns true if \a U (full or thin) is asked for in this SVD decomposition */ + inline bool computeU() const { return m_computeFullU || m_computeThinU; } + /** \returns true if \a V (full or thin) is asked for in this SVD decomposition */ + inline bool computeV() const { return m_computeFullV || m_computeThinV; } + + /** \returns a (least squares) solution of \f$ A x = b \f$ using the current SVD decomposition of A. + * + * \param b the right-hand-side of the equation to solve. + * + * \note Solving requires both U and V to be computed. Thin U and V are enough, there is no need for full U or V. + * + * \note SVD solving is implicitly least-squares. Thus, this method serves both purposes of exact solving and least-squares solving. + * In other words, the returned solution is guaranteed to minimize the Euclidean norm \f$ \Vert A x - b \Vert \f$. + */ + template<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; + } + + /** \returns the rank of the matrix of which \c *this is the SVD. + * + * \note This method has to determine which singular values should be considered nonzero. + * For that, it uses the threshold value that you can control by calling + * setThreshold(const RealScalar&). + */ + inline Index rank() const + { + using std::abs; + eigen_assert(m_isInitialized && "JacobiSVD is not initialized."); + if(m_singularValues.size()==0) return 0; + RealScalar premultiplied_threshold = m_singularValues.coeff(0) * threshold(); + Index i = m_nonzeroSingularValues-1; + while(i>=0 && m_singularValues.coeff(i) < premultiplied_threshold) --i; + return i+1; + } + + /** Allows to prescribe a threshold to be used by certain methods, such as rank() and solve(), + * which need to determine when singular values are to be considered nonzero. + * This is not used for the SVD decomposition itself. + * + * When it needs to get the threshold value, Eigen calls threshold(). + * The default is \c NumTraits<Scalar>::epsilon() + * + * \param threshold The new value to use as the threshold. + * + * A singular value will be considered nonzero if its value is strictly greater than + * \f$ \vert singular value \vert \leqslant threshold \times \vert max singular value \vert \f$. + * + * If you want to come back to the default behavior, call setThreshold(Default_t) + */ + JacobiSVD& setThreshold(const RealScalar& threshold) + { + m_usePrescribedThreshold = true; + m_prescribedThreshold = threshold; + return *this; + } + + /** Allows to come back to the default behavior, letting Eigen use its default formula for + * determining the threshold. + * + * You should pass the special object Eigen::Default as parameter here. + * \code svd.setThreshold(Eigen::Default); \endcode + * + * See the documentation of setThreshold(const RealScalar&). + */ + JacobiSVD& setThreshold(Default_t) + { + m_usePrescribedThreshold = false; + return *this; + } + + /** Returns the threshold that will be used by certain methods such as rank(). + * + * See the documentation of setThreshold(const RealScalar&). + */ + RealScalar threshold() const + { + eigen_assert(m_isInitialized || m_usePrescribedThreshold); + return m_usePrescribedThreshold ? m_prescribedThreshold + : (std::max<Index>)(1,m_diagSize)*NumTraits<Scalar>::epsilon(); + } + + inline Index rows() const { return m_rows; } + inline Index cols() const { return m_cols; } + + private: + void allocate(Index rows, Index cols, unsigned int computationOptions); + + static void check_template_parameters() + { + EIGEN_STATIC_ASSERT_NON_INTEGER(Scalar); + } + + protected: + MatrixUType m_matrixU; + MatrixVType m_matrixV; + SingularValuesType m_singularValues; + WorkMatrixType m_workMatrix; + bool m_isInitialized, m_isAllocated, m_usePrescribedThreshold; + bool m_computeFullU, m_computeThinU; + bool m_computeFullV, m_computeThinV; + unsigned int m_computationOptions; + Index m_nonzeroSingularValues, m_rows, m_cols, m_diagSize; + RealScalar m_prescribedThreshold; + + template<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; + MatrixType m_scaledMatrix; +}; + +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); + if(RowsAtCompileTime==Dynamic) + m_matrixU.resize(m_rows, m_computeFullU ? m_rows + : m_computeThinU ? m_diagSize + : 0); + if(ColsAtCompileTime==Dynamic) + m_matrixV.resize(m_cols, m_computeFullV ? m_cols + : m_computeThinV ? m_diagSize + : 0); + m_workMatrix.resize(m_diagSize, m_diagSize); + + if(m_cols>m_rows) m_qr_precond_morecols.allocate(*this); + if(m_rows>m_cols) m_qr_precond_morerows.allocate(*this); + if(m_rows!=m_cols) m_scaledMatrix.resize(rows,cols); +} + +template<typename MatrixType, int QRPreconditioner> +JacobiSVD<MatrixType, QRPreconditioner>& +JacobiSVD<MatrixType, QRPreconditioner>::compute(const MatrixType& matrix, unsigned int computationOptions) +{ + check_template_parameters(); + + using std::abs; + allocate(matrix.rows(), matrix.cols(), computationOptions); + + // currently we stop when we reach precision 2*epsilon as the last bit of precision can require an unreasonable number of iterations, + // only worsening the precision of U and V as we accumulate more rotations + const RealScalar precision = RealScalar(2) * NumTraits<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(); + + // Scaling factor to reduce over/under-flows + RealScalar scale = matrix.cwiseAbs().maxCoeff(); + if(scale==RealScalar(0)) scale = RealScalar(1); + + /*** step 1. The R-SVD step: we use a QR decomposition to reduce to the case of a square matrix */ + + if(m_rows!=m_cols) + { + m_scaledMatrix = matrix / scale; + m_qr_precond_morecols.run(*this, m_scaledMatrix); + m_qr_precond_morerows.run(*this, m_scaledMatrix); + } + else + { + m_workMatrix = matrix.block(0,0,m_diagSize,m_diagSize) / scale; + if(m_computeFullU) m_matrixU.setIdentity(m_rows,m_rows); + if(m_computeThinU) m_matrixU.setIdentity(m_rows,m_diagSize); + if(m_computeFullV) m_matrixV.setIdentity(m_cols,m_cols); + if(m_computeThinV) m_matrixV.setIdentity(m_cols, m_diagSize); + } + + /*** step 2. The main Jacobi SVD iteration. ***/ + + bool finished = false; + while(!finished) + { + finished = true; + + // do a sweep: for all index pairs (p,q), perform SVD of the corresponding 2x2 sub-matrix + + for(Index p = 1; p < m_diagSize; ++p) + { + for(Index q = 0; q < p; ++q) + { + // if this 2x2 sub-matrix is not diagonal already... + // notice that this comparison will evaluate to false if any NaN is involved, ensuring that NaN's don't + // keep us iterating forever. Similarly, small denormal numbers are considered zero. + using std::max; + RealScalar threshold = (max)(considerAsZero, precision * (max)(abs(m_workMatrix.coeff(p,p)), + abs(m_workMatrix.coeff(q,q)))); + // We compare both values to threshold instead of calling max to be robust to NaN (See bug 791) + if(abs(m_workMatrix.coeff(p,q))>threshold || abs(m_workMatrix.coeff(q,p)) > threshold) + { + finished = false; + + // perform SVD decomposition of 2x2 sub-matrix corresponding to indices p,q to make it diagonal + internal::svd_precondition_2x2_block_to_be_real<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 = abs(m_workMatrix.coeff(i,i)); + m_singularValues.coeffRef(i) = a; + if(computeU() && (a!=RealScalar(0))) m_matrixU.col(i) *= m_workMatrix.coeff(i,i)/a; + } + + /*** step 4. Sort singular values in descending order and compute the number of nonzero singular values ***/ + + m_nonzeroSingularValues = m_diagSize; + for(Index i = 0; i < m_diagSize; i++) + { + Index pos; + RealScalar maxRemainingSingularValue = m_singularValues.tail(m_diagSize-i).maxCoeff(&pos); + if(maxRemainingSingularValue == RealScalar(0)) + { + m_nonzeroSingularValues = i; + break; + } + if(pos) + { + pos += i; + std::swap(m_singularValues.coeffRef(i), m_singularValues.coeffRef(pos)); + if(computeU()) m_matrixU.col(pos).swap(m_matrixU.col(i)); + if(computeV()) m_matrixV.col(pos).swap(m_matrixV.col(i)); + } + } + + m_singularValues *= scale; + + m_isInitialized = true; + return *this; +} + +namespace internal { +template<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^* + + Matrix<Scalar, Dynamic, Rhs::ColsAtCompileTime, 0, _MatrixType::MaxRowsAtCompileTime, Rhs::MaxColsAtCompileTime> tmp; + Index rank = dec().rank(); + + tmp.noalias() = dec().matrixU().leftCols(rank).adjoint() * rhs(); + tmp = dec().singularValues().head(rank).asDiagonal().inverse() * tmp; + dst = dec().matrixV().leftCols(rank) * tmp; + } +}; +} // end namespace internal + +/** \svd_module + * + * \return the singular value decomposition of \c *this computed by two-sided + * Jacobi transformations. + * + * \sa class JacobiSVD + */ +template<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 \ No newline at end of file
diff -r 000000000000 -r 13a5d365ba16 src/SVD/JacobiSVD_MKL.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/SVD/JacobiSVD_MKL.h Thu Oct 13 04:07:23 2016 +0000 @@ -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 \ No newline at end of file
diff -r 000000000000 -r 13a5d365ba16 src/SVD/UpperBidiagonalization.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/SVD/UpperBidiagonalization.h Thu Oct 13 04:07:23 2016 +0000 @@ -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 typename internal::remove_all<typename MatrixType::ConjugateReturnType>::type, + 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.conjugate(), m_householder.const_derived().template diagonal<1>()) + .setLength(m_householder.cols()-1) + .setShift(1); + } + + protected: + MatrixType m_householder; + BidiagonalType m_bidiagonal; + bool m_isInitialized; +}; + +template<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 \ No newline at end of file
diff -r 000000000000 -r 13a5d365ba16 src/misc/Image.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/misc/Image.h Thu Oct 13 04:07:23 2016 +0000 @@ -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 \ No newline at end of file
diff -r 000000000000 -r 13a5d365ba16 src/misc/Kernel.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/misc/Kernel.h Thu Oct 13 04:07:23 2016 +0000 @@ -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 \ No newline at end of file
diff -r 000000000000 -r 13a5d365ba16 src/misc/Solve.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/misc/Solve.h Thu Oct 13 04:07:23 2016 +0000 @@ -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 \ No newline at end of file
diff -r 000000000000 -r 13a5d365ba16 src/misc/SparseSolve.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/misc/SparseSolve.h Thu Oct 13 04:07:23 2016 +0000 @@ -0,0 +1,128 @@ +// 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: + template<typename DestScalar, int DestOptions, typename DestIndex> + inline void defaultEvalTo(SparseMatrix<DestScalar,DestOptions,DestIndex>& dst) const + { + // we process the sparse rhs per block of NbColsAtOnce columns temporarily stored into a dense matrix. + static const int NbColsAtOnce = 4; + int rhsCols = m_rhs.cols(); + int size = m_rhs.rows(); + Eigen::Matrix<DestScalar,Dynamic,Dynamic> tmp(size,rhsCols); + Eigen::Matrix<DestScalar,Dynamic,Dynamic> tmpX(size,rhsCols); + for(int k=0; k<rhsCols; k+=NbColsAtOnce) + { + int actualCols = std::min<int>(rhsCols-k, NbColsAtOnce); + tmp.leftCols(actualCols) = m_rhs.middleCols(k,actualCols); + tmpX.leftCols(actualCols) = m_dec.solve(tmp.leftCols(actualCols)); + dst.middleCols(k,actualCols) = tmpX.leftCols(actualCols).sparseView(); + } + } + const DecompositionType& m_dec; + typename Rhs::Nested m_rhs; +}; + +#define EIGEN_MAKE_SPARSE_SOLVE_HELPERS(DecompositionType,Rhs) \ + typedef typename DecompositionType::MatrixType MatrixType; \ + typedef typename MatrixType::Scalar Scalar; \ + typedef typename MatrixType::RealScalar RealScalar; \ + typedef typename MatrixType::Index Index; \ + typedef Eigen::internal::sparse_solve_retval_base<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 \ No newline at end of file
diff -r 000000000000 -r 13a5d365ba16 src/misc/blas.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/misc/blas.h Thu Oct 13 04:07:23 2016 +0000 @@ -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 \ No newline at end of file
diff -r 000000000000 -r 13a5d365ba16 src/plugins/ArrayCwiseBinaryOps.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/plugins/ArrayCwiseBinaryOps.h Thu Oct 13 04:07:23 2016 +0000 @@ -0,0 +1,252 @@ +/** \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 CwiseNullaryOp<internal::scalar_constant_op<Scalar>, PlainObject> > +#ifdef EIGEN_PARSED_BY_DOXYGEN +min +#else +(min) +#endif +(const Scalar &other) const +{ + return (min)(Derived::PlainObject::Constant(rows(), cols(), other)); +} + +/** \returns an expression of the coefficient-wise max of \c *this and \a other + * + * Example: \include Cwise_max.cpp + * Output: \verbinclude Cwise_max.out + * + * \sa min() + */ +EIGEN_MAKE_CWISE_BINARY_OP(max,internal::scalar_max_op) + +/** \returns an expression of the coefficient-wise max of \c *this and scalar \a other + * + * \sa min() + */ +EIGEN_STRONG_INLINE const CwiseBinaryOp<internal::scalar_max_op<Scalar>, const Derived, + const CwiseNullaryOp<internal::scalar_constant_op<Scalar>, PlainObject> > +#ifdef EIGEN_PARSED_BY_DOXYGEN +max +#else +(max) +#endif +(const Scalar &other) const +{ + return (max)(Derived::PlainObject::Constant(rows(), cols(), other)); +} + + +#define EIGEN_MAKE_CWISE_COMP_OP(OP, COMPARATOR) \ +template<typename OtherDerived> \ +EIGEN_STRONG_INLINE const CwiseBinaryOp<internal::scalar_cmp_op<Scalar, internal::cmp_ ## COMPARATOR>, const Derived, const OtherDerived> \ +OP(const EIGEN_CURRENT_STORAGE_BASE_CLASS<OtherDerived> &other) const \ +{ \ + return CwiseBinaryOp<internal::scalar_cmp_op<Scalar, internal::cmp_ ## COMPARATOR>, const Derived, const OtherDerived>(derived(), other.derived()); \ +}\ +typedef CwiseBinaryOp<internal::scalar_cmp_op<Scalar, internal::cmp_ ## COMPARATOR>, const Derived, const CwiseNullaryOp<internal::scalar_constant_op<Scalar>, PlainObject> > Cmp ## COMPARATOR ## ReturnType; \ +typedef CwiseBinaryOp<internal::scalar_cmp_op<Scalar, internal::cmp_ ## COMPARATOR>, const CwiseNullaryOp<internal::scalar_constant_op<Scalar>, PlainObject>, const Derived > RCmp ## COMPARATOR ## ReturnType; \ +EIGEN_STRONG_INLINE const Cmp ## COMPARATOR ## ReturnType \ +OP(const Scalar& s) const { \ + return this->OP(Derived::PlainObject::Constant(rows(), cols(), s)); \ +} \ +friend EIGEN_STRONG_INLINE const RCmp ## COMPARATOR ## ReturnType \ +OP(const Scalar& s, const Derived& d) { \ + return Derived::PlainObject::Constant(d.rows(), d.cols(), s).OP(d); \ +} + +#define EIGEN_MAKE_CWISE_COMP_R_OP(OP, R_OP, RCOMPARATOR) \ +template<typename OtherDerived> \ +EIGEN_STRONG_INLINE const CwiseBinaryOp<internal::scalar_cmp_op<Scalar, internal::cmp_##RCOMPARATOR>, const OtherDerived, const Derived> \ +OP(const EIGEN_CURRENT_STORAGE_BASE_CLASS<OtherDerived> &other) const \ +{ \ + return CwiseBinaryOp<internal::scalar_cmp_op<Scalar, internal::cmp_##RCOMPARATOR>, const OtherDerived, const Derived>(other.derived(), derived()); \ +} \ +\ +inline const RCmp ## RCOMPARATOR ## ReturnType \ +OP(const Scalar& s) const { \ + return Derived::PlainObject::Constant(rows(), cols(), s).R_OP(*this); \ +} \ +friend inline const Cmp ## RCOMPARATOR ## ReturnType \ +OP(const Scalar& s, const Derived& d) { \ + return d.R_OP(Derived::PlainObject::Constant(d.rows(), d.cols(), s)); \ +} + + +/** \returns an expression of the coefficient-wise \< operator of *this and \a other + * + * Example: \include Cwise_less.cpp + * Output: \verbinclude Cwise_less.out + * + * \sa all(), any(), operator>(), operator<=() + */ +EIGEN_MAKE_CWISE_COMP_OP(operator<, LT) + +/** \returns an expression of the coefficient-wise \<= operator of *this and \a other + * + * Example: \include Cwise_less_equal.cpp + * Output: \verbinclude Cwise_less_equal.out + * + * \sa all(), any(), operator>=(), operator<() + */ +EIGEN_MAKE_CWISE_COMP_OP(operator<=, LE) + +/** \returns an expression of the coefficient-wise \> operator of *this and \a other + * + * Example: \include Cwise_greater.cpp + * Output: \verbinclude Cwise_greater.out + * + * \sa all(), any(), operator>=(), operator<() + */ +EIGEN_MAKE_CWISE_COMP_R_OP(operator>, operator<, LT) + +/** \returns an expression of the coefficient-wise \>= operator of *this and \a other + * + * Example: \include Cwise_greater_equal.cpp + * Output: \verbinclude Cwise_greater_equal.out + * + * \sa all(), any(), operator>(), operator<=() + */ +EIGEN_MAKE_CWISE_COMP_R_OP(operator>=, operator<=, LE) + +/** \returns an expression of the coefficient-wise == operator of *this and \a other + * + * \warning this performs an exact comparison, which is generally a bad idea with floating-point types. + * In order to check for equality between two vectors or matrices with floating-point coefficients, it is + * generally a far better idea to use a fuzzy comparison as provided by isApprox() and + * isMuchSmallerThan(). + * + * Example: \include Cwise_equal_equal.cpp + * Output: \verbinclude Cwise_equal_equal.out + * + * \sa all(), any(), isApprox(), isMuchSmallerThan() + */ +EIGEN_MAKE_CWISE_COMP_OP(operator==, EQ) + +/** \returns an expression of the coefficient-wise != operator of *this and \a other + * + * \warning this performs an exact comparison, which is generally a bad idea with floating-point types. + * In order to check for equality between two vectors or matrices with floating-point coefficients, it is + * generally a far better idea to use a fuzzy comparison as provided by isApprox() and + * isMuchSmallerThan(). + * + * Example: \include Cwise_not_equal.cpp + * Output: \verbinclude Cwise_not_equal.out + * + * \sa all(), any(), isApprox(), isMuchSmallerThan() + */ +EIGEN_MAKE_CWISE_COMP_OP(operator!=, NEQ) + +#undef EIGEN_MAKE_CWISE_COMP_OP +#undef EIGEN_MAKE_CWISE_COMP_R_OP + +// scalar addition + +/** \returns an expression of \c *this with each coeff incremented by the constant \a scalar + * + * Example: \include Cwise_plus.cpp + * Output: \verbinclude Cwise_plus.out + * + * \sa operator+=(), operator-() + */ +inline const CwiseUnaryOp<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 -r 000000000000 -r 13a5d365ba16 src/plugins/ArrayCwiseUnaryOps.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/plugins/ArrayCwiseUnaryOps.h Thu Oct 13 04:07:23 2016 +0000 @@ -0,0 +1,187 @@ + + +/** \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(); +} \ No newline at end of file
diff -r 000000000000 -r 13a5d365ba16 src/plugins/BlockMethods.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/plugins/BlockMethods.h Thu Oct 13 04:07:23 2016 +0000 @@ -0,0 +1,935 @@ +// 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_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; }; + +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; }; + +#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. + * + * \tparam CRows the number of rows in the corner + * \tparam CCols the number of columns in the corner + * + * Example: \include MatrixBase_template_int_int_topRightCorner.cpp + * Output: \verbinclude MatrixBase_template_int_int_topRightCorner.out + * + * \sa class Block, block<int,int>(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 an expression of a top-right corner of *this. + * + * \tparam CRows number of rows in corner as specified at compile-time + * \tparam CCols number of columns in corner as specified at compile-time + * \param cRows number of rows in corner as specified at run-time + * \param cCols number of columns in corner as specified at run-time + * + * This function is mainly useful for corners where the number of rows is specified at compile-time + * and the number of columns is specified at run-time, or vice versa. The compile-time and run-time + * information should not contradict. In other words, \a cRows should equal \a CRows unless + * \a CRows is \a Dynamic, and the same for the number of columns. + * + * Example: \include MatrixBase_template_int_int_topRightCorner_int_int.cpp + * Output: \verbinclude MatrixBase_template_int_int_topRightCorner_int_int.out + * + * \sa class Block + */ +template<int CRows, int CCols> +inline Block<Derived, CRows, CCols> topRightCorner(Index cRows, Index cCols) +{ + return Block<Derived, CRows, CCols>(derived(), 0, cols() - cCols, cRows, cCols); +} + +/** This is the const version of topRightCorner<int, int>(Index, Index).*/ +template<int CRows, int CCols> +inline const Block<const Derived, CRows, CCols> topRightCorner(Index cRows, Index cCols) const +{ + return Block<const Derived, CRows, CCols>(derived(), 0, cols() - cCols, cRows, cCols); +} + + + +/** \returns a dynamic-size expression of a top-left corner of *this. + * + * \param cRows the number of rows in the corner + * \param cCols the number of columns in the corner + * + * Example: \include MatrixBase_topLeftCorner_int_int.cpp + * Output: \verbinclude MatrixBase_topLeftCorner_int_int.out + * + * \sa class Block, block(Index,Index,Index,Index) + */ +inline Block<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 an expression of a top-left corner of *this. + * + * \tparam CRows number of rows in corner as specified at compile-time + * \tparam CCols number of columns in corner as specified at compile-time + * \param cRows number of rows in corner as specified at run-time + * \param cCols number of columns in corner as specified at run-time + * + * This function is mainly useful for corners where the number of rows is specified at compile-time + * and the number of columns is specified at run-time, or vice versa. The compile-time and run-time + * information should not contradict. In other words, \a cRows should equal \a CRows unless + * \a CRows is \a Dynamic, and the same for the number of columns. + * + * Example: \include MatrixBase_template_int_int_topLeftCorner_int_int.cpp + * Output: \verbinclude MatrixBase_template_int_int_topLeftCorner_int_int.out + * + * \sa class Block + */ +template<int CRows, int CCols> +inline Block<Derived, CRows, CCols> topLeftCorner(Index cRows, Index cCols) +{ + return Block<Derived, CRows, CCols>(derived(), 0, 0, cRows, cCols); +} + +/** This is the const version of topLeftCorner<int, int>(Index, Index).*/ +template<int CRows, int CCols> +inline const Block<const Derived, CRows, CCols> topLeftCorner(Index cRows, Index cCols) const +{ + return Block<const Derived, CRows, CCols>(derived(), 0, 0, cRows, cCols); +} + + + +/** \returns a dynamic-size expression of a bottom-right corner of *this. + * + * \param cRows the number of rows in the corner + * \param cCols the number of columns in the corner + * + * Example: \include MatrixBase_bottomRightCorner_int_int.cpp + * Output: \verbinclude MatrixBase_bottomRightCorner_int_int.out + * + * \sa class Block, block(Index,Index,Index,Index) + */ +inline Block<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 an expression of a bottom-right corner of *this. + * + * \tparam CRows number of rows in corner as specified at compile-time + * \tparam CCols number of columns in corner as specified at compile-time + * \param cRows number of rows in corner as specified at run-time + * \param cCols number of columns in corner as specified at run-time + * + * This function is mainly useful for corners where the number of rows is specified at compile-time + * and the number of columns is specified at run-time, or vice versa. The compile-time and run-time + * information should not contradict. In other words, \a cRows should equal \a CRows unless + * \a CRows is \a Dynamic, and the same for the number of columns. + * + * Example: \include MatrixBase_template_int_int_bottomRightCorner_int_int.cpp + * Output: \verbinclude MatrixBase_template_int_int_bottomRightCorner_int_int.out + * + * \sa class Block + */ +template<int CRows, int CCols> +inline Block<Derived, CRows, CCols> bottomRightCorner(Index cRows, Index cCols) +{ + return Block<Derived, CRows, CCols>(derived(), rows() - cRows, cols() - cCols, cRows, cCols); +} + +/** This is the const version of bottomRightCorner<int, int>(Index, Index).*/ +template<int CRows, int CCols> +inline const Block<const Derived, CRows, CCols> bottomRightCorner(Index cRows, Index cCols) const +{ + return Block<const Derived, CRows, CCols>(derived(), rows() - cRows, cols() - cCols, cRows, cCols); +} + + + +/** \returns a dynamic-size expression of a bottom-left corner of *this. + * + * \param cRows the number of rows in the corner + * \param cCols the number of columns in the corner + * + * Example: \include MatrixBase_bottomLeftCorner_int_int.cpp + * Output: \verbinclude MatrixBase_bottomLeftCorner_int_int.out + * + * \sa class Block, block(Index,Index,Index,Index) + */ +inline Block<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 an expression of a bottom-left corner of *this. + * + * \tparam CRows number of rows in corner as specified at compile-time + * \tparam CCols number of columns in corner as specified at compile-time + * \param cRows number of rows in corner as specified at run-time + * \param cCols number of columns in corner as specified at run-time + * + * This function is mainly useful for corners where the number of rows is specified at compile-time + * and the number of columns is specified at run-time, or vice versa. The compile-time and run-time + * information should not contradict. In other words, \a cRows should equal \a CRows unless + * \a CRows is \a Dynamic, and the same for the number of columns. + * + * Example: \include MatrixBase_template_int_int_bottomLeftCorner_int_int.cpp + * Output: \verbinclude MatrixBase_template_int_int_bottomLeftCorner_int_int.out + * + * \sa class Block + */ +template<int CRows, int CCols> +inline Block<Derived, CRows, CCols> bottomLeftCorner(Index cRows, Index cCols) +{ + return Block<Derived, CRows, CCols>(derived(), rows() - cRows, 0, cRows, cCols); +} + +/** This is the const version of bottomLeftCorner<int, int>(Index, Index).*/ +template<int CRows, int CCols> +inline const Block<const Derived, CRows, CCols> bottomLeftCorner(Index cRows, Index cCols) const +{ + return Block<const Derived, CRows, CCols>(derived(), rows() - cRows, 0, cRows, cCols); +} + + + +/** \returns a block consisting of the top rows of *this. + * + * \param n the number of rows in the block + * + * Example: \include MatrixBase_topRows_int.cpp + * Output: \verbinclude MatrixBase_topRows_int.out + * + * \sa class Block, block(Index,Index,Index,Index) + */ +inline RowsBlockXpr topRows(Index n) +{ + return RowsBlockXpr(derived(), 0, 0, n, cols()); +} + +/** This is the const version of topRows(Index).*/ +inline ConstRowsBlockXpr topRows(Index n) const +{ + return ConstRowsBlockXpr(derived(), 0, 0, n, cols()); +} + +/** \returns a block consisting of the top rows of *this. + * + * \tparam N the number of rows in the block as specified at compile-time + * \param n the number of rows in the block as specified at run-time + * + * The compile-time and run-time information should not contradict. In other words, + * \a n should equal \a N unless \a N is \a Dynamic. + * + * Example: \include MatrixBase_template_int_topRows.cpp + * Output: \verbinclude MatrixBase_template_int_topRows.out + * + * \sa class Block, block(Index,Index,Index,Index) + */ +template<int N> +inline typename NRowsBlockXpr<N>::Type topRows(Index n = N) +{ + 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(Index n = N) 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 as specified at compile-time + * \param n the number of rows in the block as specified at run-time + * + * The compile-time and run-time information should not contradict. In other words, + * \a n should equal \a N unless \a N is \a Dynamic. + * + * Example: \include MatrixBase_template_int_bottomRows.cpp + * Output: \verbinclude MatrixBase_template_int_bottomRows.out + * + * \sa class Block, block(Index,Index,Index,Index) + */ +template<int N> +inline typename NRowsBlockXpr<N>::Type bottomRows(Index n = N) +{ + 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(Index n = N) 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 n the number of rows in the block + * + * Example: \include DenseBase_middleRows_int.cpp + * Output: \verbinclude DenseBase_middleRows_int.out + * + * \sa class Block, block(Index,Index,Index,Index) + */ +inline RowsBlockXpr middleRows(Index startRow, Index n) +{ + return RowsBlockXpr(derived(), startRow, 0, n, cols()); +} + +/** This is the const version of middleRows(Index,Index).*/ +inline ConstRowsBlockXpr middleRows(Index startRow, Index n) const +{ + return ConstRowsBlockXpr(derived(), startRow, 0, n, cols()); +} + +/** \returns a block consisting of a range of rows of *this. + * + * \tparam N the number of rows in the block as specified at compile-time + * \param startRow the index of the first row in the block + * \param n the number of rows in the block as specified at run-time + * + * The compile-time and run-time information should not contradict. In other words, + * \a n should equal \a N unless \a N is \a Dynamic. + * + * Example: \include DenseBase_template_int_middleRows.cpp + * Output: \verbinclude DenseBase_template_int_middleRows.out + * + * \sa class Block, block(Index,Index,Index,Index) + */ +template<int N> +inline typename NRowsBlockXpr<N>::Type middleRows(Index startRow, Index n = N) +{ + 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, Index n = N) 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 as specified at compile-time + * \param n the number of columns in the block as specified at run-time + * + * The compile-time and run-time information should not contradict. In other words, + * \a n should equal \a N unless \a N is \a Dynamic. + * + * Example: \include MatrixBase_template_int_leftCols.cpp + * Output: \verbinclude MatrixBase_template_int_leftCols.out + * + * \sa class Block, block(Index,Index,Index,Index) + */ +template<int N> +inline typename NColsBlockXpr<N>::Type leftCols(Index n = N) +{ + 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(Index n = N) 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 as specified at compile-time + * \param n the number of columns in the block as specified at run-time + * + * The compile-time and run-time information should not contradict. In other words, + * \a n should equal \a N unless \a N is \a Dynamic. + * + * Example: \include MatrixBase_template_int_rightCols.cpp + * Output: \verbinclude MatrixBase_template_int_rightCols.out + * + * \sa class Block, block(Index,Index,Index,Index) + */ +template<int N> +inline typename NColsBlockXpr<N>::Type rightCols(Index n = N) +{ + 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(Index n = N) 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 as specified at compile-time + * \param startCol the index of the first column in the block + * \param n the number of columns in the block as specified at run-time + * + * The compile-time and run-time information should not contradict. In other words, + * \a n should equal \a N unless \a N is \a Dynamic. + * + * Example: \include DenseBase_template_int_middleCols.cpp + * Output: \verbinclude DenseBase_template_int_middleCols.out + * + * \sa class Block, block(Index,Index,Index,Index) + */ +template<int N> +inline typename NColsBlockXpr<N>::Type middleCols(Index startCol, Index n = N) +{ + 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, Index n = N) 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 a block in *this. + * + * \tparam BlockRows number of rows in block as specified at compile-time + * \tparam BlockCols number of columns in block as specified at compile-time + * \param startRow the first row in the block + * \param startCol the first column in the block + * \param blockRows number of rows in block as specified at run-time + * \param blockCols number of columns in block as specified at run-time + * + * This function is mainly useful for blocks where the number of rows is specified at compile-time + * and the number of columns is specified at run-time, or vice versa. The compile-time and run-time + * information should not contradict. In other words, \a blockRows should equal \a BlockRows unless + * \a BlockRows is \a Dynamic, and the same for the number of columns. + * + * Example: \include MatrixBase_template_int_int_block_int_int_int_int.cpp + * Output: \verbinclude MatrixBase_template_int_int_block_int_int_int_int.cpp + * + * \sa class Block, block(Index,Index,Index,Index) + */ +template<int BlockRows, int BlockCols> +inline Block<Derived, BlockRows, BlockCols> block(Index startRow, Index startCol, + Index blockRows, Index blockCols) +{ + return Block<Derived, BlockRows, BlockCols>(derived(), startRow, startCol, blockRows, blockCols); +} + +/** This is the const version of block<>(Index, Index, Index, Index). */ +template<int BlockRows, int BlockCols> +inline const Block<const Derived, BlockRows, BlockCols> block(Index startRow, Index startCol, + Index blockRows, Index blockCols) const +{ + return Block<const Derived, BlockRows, BlockCols>(derived(), startRow, startCol, blockRows, blockCols); +} + +/** \returns an expression of the \a i-th column of *this. Note that the numbering starts at 0. + * + * Example: \include MatrixBase_col.cpp + * Output: \verbinclude MatrixBase_col.out + * + * \sa row(), class Block */ +inline ColXpr col(Index i) +{ + return ColXpr(derived(), i); +} + +/** This is the const version of col(). */ +inline ConstColXpr col(Index i) const +{ + return ConstColXpr(derived(), i); +} + +/** \returns an expression of the \a i-th row of *this. Note that the numbering starts at 0. + * + * Example: \include MatrixBase_row.cpp + * Output: \verbinclude MatrixBase_row.out + * + * \sa col(), class Block */ +inline RowXpr row(Index i) +{ + return RowXpr(derived(), i); +} + +/** This is the const version of row(). */ +inline ConstRowXpr row(Index i) const +{ + return ConstRowXpr(derived(), i); +} + +/** \returns a dynamic-size expression of a segment (i.e. a vector block) in *this. + * + * \only_for_vectors + * + * \param start the first coefficient in the segment + * \param n the number of coefficients in the segment + * + * Example: \include MatrixBase_segment_int_int.cpp + * Output: \verbinclude MatrixBase_segment_int_int.out + * + * \note Even though the returned expression has dynamic size, in the case + * when it is applied to a fixed-size vector, it inherits a fixed maximal size, + * which means that evaluating it does not cause a dynamic memory allocation. + * + * \sa class Block, segment(Index) + */ +inline SegmentReturnType segment(Index start, Index n) +{ + EIGEN_STATIC_ASSERT_VECTOR_ONLY(Derived) + return SegmentReturnType(derived(), start, n); +} + + +/** This is the const version of segment(Index,Index).*/ +inline ConstSegmentReturnType segment(Index start, Index n) const +{ + EIGEN_STATIC_ASSERT_VECTOR_ONLY(Derived) + return ConstSegmentReturnType(derived(), start, n); +} + +/** \returns a dynamic-size expression of the first coefficients of *this. + * + * \only_for_vectors + * + * \param n the number of coefficients in the segment + * + * Example: \include MatrixBase_start_int.cpp + * Output: \verbinclude MatrixBase_start_int.out + * + * \note Even though the returned expression has dynamic size, in the case + * when it is applied to a fixed-size vector, it inherits a fixed maximal size, + * which means that evaluating it does not cause a dynamic memory allocation. + * + * \sa class Block, block(Index,Index) + */ +inline SegmentReturnType head(Index n) +{ + EIGEN_STATIC_ASSERT_VECTOR_ONLY(Derived) + return SegmentReturnType(derived(), 0, n); +} + +/** This is the const version of head(Index).*/ +inline ConstSegmentReturnType head(Index n) const +{ + EIGEN_STATIC_ASSERT_VECTOR_ONLY(Derived) + return ConstSegmentReturnType(derived(), 0, n); +} + +/** \returns a dynamic-size expression of the last coefficients of *this. + * + * \only_for_vectors + * + * \param n the number of coefficients in the segment + * + * Example: \include MatrixBase_end_int.cpp + * Output: \verbinclude MatrixBase_end_int.out + * + * \note Even though the returned expression has dynamic size, in the case + * when it is applied to a fixed-size vector, it inherits a fixed maximal size, + * which means that evaluating it does not cause a dynamic memory allocation. + * + * \sa class Block, block(Index,Index) + */ +inline SegmentReturnType tail(Index n) +{ + EIGEN_STATIC_ASSERT_VECTOR_ONLY(Derived) + return SegmentReturnType(derived(), this->size() - n, n); +} + +/** This is the const version of tail(Index).*/ +inline ConstSegmentReturnType tail(Index n) const +{ + EIGEN_STATIC_ASSERT_VECTOR_ONLY(Derived) + return ConstSegmentReturnType(derived(), this->size() - n, n); +} + +/** \returns a fixed-size expression of a segment (i.e. a vector block) in \c *this + * + * \only_for_vectors + * + * \tparam N the number of coefficients in the segment as specified at compile-time + * \param start the index of the first element in the segment + * \param n the number of coefficients in the segment as specified at compile-time + * + * The compile-time and run-time information should not contradict. In other words, + * \a n should equal \a N unless \a N is \a Dynamic. + * + * Example: \include MatrixBase_template_int_segment.cpp + * Output: \verbinclude MatrixBase_template_int_segment.out + * + * \sa class Block + */ +template<int N> +inline typename FixedSegmentReturnType<N>::Type segment(Index start, Index n = N) +{ + EIGEN_STATIC_ASSERT_VECTOR_ONLY(Derived) + return typename FixedSegmentReturnType<N>::Type(derived(), start, n); +} + +/** This is the const version of segment<int>(Index).*/ +template<int N> +inline typename ConstFixedSegmentReturnType<N>::Type segment(Index start, Index n = N) const +{ + EIGEN_STATIC_ASSERT_VECTOR_ONLY(Derived) + return typename ConstFixedSegmentReturnType<N>::Type(derived(), start, n); +} + +/** \returns a fixed-size expression of the first coefficients of *this. + * + * \only_for_vectors + * + * \tparam N the number of coefficients in the segment as specified at compile-time + * \param n the number of coefficients in the segment as specified at run-time + * + * The compile-time and run-time information should not contradict. In other words, + * \a n should equal \a N unless \a N is \a Dynamic. + * + * Example: \include MatrixBase_template_int_start.cpp + * Output: \verbinclude MatrixBase_template_int_start.out + * + * \sa class Block + */ +template<int N> +inline typename FixedSegmentReturnType<N>::Type head(Index n = N) +{ + EIGEN_STATIC_ASSERT_VECTOR_ONLY(Derived) + return typename FixedSegmentReturnType<N>::Type(derived(), 0, n); +} + +/** This is the const version of head<int>().*/ +template<int N> +inline typename ConstFixedSegmentReturnType<N>::Type head(Index n = N) const +{ + EIGEN_STATIC_ASSERT_VECTOR_ONLY(Derived) + return typename ConstFixedSegmentReturnType<N>::Type(derived(), 0, n); +} + +/** \returns a fixed-size expression of the last coefficients of *this. + * + * \only_for_vectors + * + * \tparam N the number of coefficients in the segment as specified at compile-time + * \param n the number of coefficients in the segment as specified at run-time + * + * The compile-time and run-time information should not contradict. In other words, + * \a n should equal \a N unless \a N is \a Dynamic. + * + * Example: \include MatrixBase_template_int_end.cpp + * Output: \verbinclude MatrixBase_template_int_end.out + * + * \sa class Block + */ +template<int N> +inline typename FixedSegmentReturnType<N>::Type tail(Index n = N) +{ + EIGEN_STATIC_ASSERT_VECTOR_ONLY(Derived) + return typename FixedSegmentReturnType<N>::Type(derived(), size() - n); +} + +/** This is the const version of tail<int>.*/ +template<int N> +inline typename ConstFixedSegmentReturnType<N>::Type tail(Index n = N) const +{ + EIGEN_STATIC_ASSERT_VECTOR_ONLY(Derived) + return typename ConstFixedSegmentReturnType<N>::Type(derived(), size() - n); +} \ No newline at end of file
diff -r 000000000000 -r 13a5d365ba16 src/plugins/CommonCwiseBinaryOps.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/plugins/CommonCwiseBinaryOps.h Thu Oct 13 04:07:23 2016 +0000 @@ -0,0 +1,45 @@ +// 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 -r 000000000000 -r 13a5d365ba16 src/plugins/CommonCwiseUnaryOps.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/plugins/CommonCwiseUnaryOps.h Thu Oct 13 04:07:23 2016 +0000 @@ -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(); } \ No newline at end of file
diff -r 000000000000 -r 13a5d365ba16 src/plugins/MatrixCwiseBinaryOps.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/plugins/MatrixCwiseBinaryOps.h Thu Oct 13 04:07:23 2016 +0000 @@ -0,0 +1,143 @@ +// 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::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::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()); +} + +typedef CwiseBinaryOp<internal::scalar_cmp_op<Scalar,internal::cmp_EQ>, const Derived, const ConstantReturnType> CwiseScalarEqualReturnType; + +/** \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 CwiseScalarEqualReturnType +cwiseEqual(const Scalar& s) const +{ + return CwiseScalarEqualReturnType(derived(), Derived::Constant(rows(), cols(), s), internal::scalar_cmp_op<Scalar,internal::cmp_EQ>()); +} \ No newline at end of file
diff -r 000000000000 -r 13a5d365ba16 src/plugins/MatrixCwiseUnaryOps.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/plugins/MatrixCwiseUnaryOps.h Thu Oct 13 04:07:23 2016 +0000 @@ -0,0 +1,51 @@ +// 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(); }