mirror of
https://gitlab.com/libeigen/eigen.git
synced 2026-04-10 11:34:33 +08:00
Compare commits
89 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
cb409914e0 | ||
|
|
069ecbb4ab | ||
|
|
09fd69d734 | ||
|
|
6700f07fb0 | ||
|
|
08e6b7ad80 | ||
|
|
7e8ee5b527 | ||
|
|
93c1f62979 | ||
|
|
2b20da624a | ||
|
|
bb33ec4ef3 | ||
|
|
9c0deb55ca | ||
|
|
faf942a947 | ||
|
|
6d1439a52f | ||
|
|
2ff7961c10 | ||
|
|
c1e2156d8a | ||
|
|
84cc69f0f3 | ||
|
|
20c11bc52c | ||
|
|
eb9dadf3b2 | ||
|
|
6b3d0e68e2 | ||
|
|
aba378eb1a | ||
|
|
00f89a8f37 | ||
|
|
582c1f92c8 | ||
|
|
a040b7f15d | ||
|
|
cc6121b98d | ||
|
|
a3b89e0ee6 | ||
|
|
3614321401 | ||
|
|
139529e97b | ||
|
|
86ccd99d8d | ||
|
|
9aba671cfc | ||
|
|
2a4fdf31c8 | ||
|
|
033ac82c9d | ||
|
|
12f84acda6 | ||
|
|
e80099932a | ||
|
|
a0ec0fca5a | ||
|
|
3d90c13970 | ||
|
|
3f580e240e | ||
|
|
ebe14aae7d | ||
|
|
48137e28d8 | ||
|
|
3e502abfda | ||
|
|
b26e04f40b | ||
|
|
9f873a855f | ||
|
|
ca048aaf77 | ||
|
|
94f6f2a7de | ||
|
|
ec0a423862 | ||
|
|
505ce85814 | ||
|
|
e5b8a59cfa | ||
|
|
568a7e8eba | ||
|
|
72f2c7eed5 | ||
|
|
0c5a09d93f | ||
|
|
8ea8b481de | ||
|
|
65abb4c52e | ||
|
|
cf0f82ecbe | ||
|
|
9e02e42ff6 | ||
|
|
3645d6c138 | ||
|
|
96538b976d | ||
|
|
5066fe8bbe | ||
|
|
e1c50a3cb1 | ||
|
|
fa27cd1ed0 | ||
|
|
f44316e5f8 | ||
|
|
3a231c2349 | ||
|
|
64f7fbe3f2 | ||
|
|
76fe2e1b34 | ||
|
|
ecc6c43dba | ||
|
|
6be0131774 | ||
|
|
cfca7f71fe | ||
|
|
727dfa1c43 | ||
|
|
e747b338ee | ||
|
|
28d32f9bd8 | ||
|
|
765219aa51 | ||
|
|
e2bd8623f8 | ||
|
|
537a0e0a52 | ||
|
|
e80d6a95d9 | ||
|
|
8466244faa | ||
|
|
b46c327133 | ||
|
|
4e502dd6b0 | ||
|
|
22507fa645 | ||
|
|
b8fc1edb2c | ||
|
|
3c155ab073 | ||
|
|
b730c6f57d | ||
|
|
a930dfb229 | ||
|
|
98d3c0a413 | ||
|
|
068ff3370d | ||
|
|
1fc503e3ce | ||
|
|
d907cd4410 | ||
|
|
618de17bf7 | ||
|
|
373331e3bf | ||
|
|
42e88b1724 | ||
|
|
fb5b62fbac | ||
|
|
af991a6bdb | ||
|
|
247f2b0ffa |
110
CMakeLists.txt
110
CMakeLists.txt
@@ -1,67 +1,73 @@
|
||||
PROJECT(Eigen)
|
||||
SET(EIGEN_VERSION_NUMBER "2.0-beta1")
|
||||
project(Eigen)
|
||||
set(EIGEN_VERSION_NUMBER "2.0-beta2")
|
||||
|
||||
#if the svnversion program is absent, this will leave the SVN_REVISION string empty,
|
||||
#but won't stop CMake.
|
||||
EXECUTE_PROCESS(COMMAND svnversion -n ${CMAKE_SOURCE_DIR}
|
||||
execute_process(COMMAND svnversion -n ${CMAKE_SOURCE_DIR}
|
||||
OUTPUT_VARIABLE EIGEN_SVN_REVISION)
|
||||
|
||||
IF(EIGEN_SVN_REVISION)
|
||||
SET(EIGEN_VERSION "${EIGEN_VERSION_NUMBER} (SVN revision ${EIGEN_SVN_REVISION})")
|
||||
ELSE(EIGEN_SVN_REVISION)
|
||||
SET(EIGEN_VERSION "${EIGEN_VERSION_NUMBER}")
|
||||
ENDIF(EIGEN_SVN_REVISION)
|
||||
if(EIGEN_SVN_REVISION)
|
||||
set(EIGEN_VERSION "${EIGEN_VERSION_NUMBER} (SVN revision ${EIGEN_SVN_REVISION})")
|
||||
else(EIGEN_SVN_REVISION)
|
||||
set(EIGEN_VERSION "${EIGEN_VERSION_NUMBER}")
|
||||
endif(EIGEN_SVN_REVISION)
|
||||
|
||||
SET(EIGEN_SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR})
|
||||
SET(EIGEN_BINARY_DIR ${CMAKE_CURRENT_BINARY_DIR})
|
||||
|
||||
CMAKE_MINIMUM_REQUIRED(VERSION 2.4)
|
||||
cmake_minimum_required(VERSION 2.4)
|
||||
|
||||
set(CMAKE_MODULE_PATH ${PROJECT_SOURCE_DIR}/cmake)
|
||||
|
||||
OPTION(BUILD_TESTS "Build tests" OFF)
|
||||
OPTION(BUILD_DEMOS "Build demos" OFF)
|
||||
OPTION(BUILD_LIB "Build the binary shared library" OFF)
|
||||
OPTION(BUILD_BTL "Build benchmark suite" OFF)
|
||||
option(EIGEN_BUILD_TESTS "Build tests" OFF)
|
||||
option(EIGEN_BUILD_DEMOS "Build demos" OFF)
|
||||
if(NOT WIN32)
|
||||
option(EIGEN_BUILD_LIB "Build the binary shared library" OFF)
|
||||
endif(NOT WIN32)
|
||||
option(EIGEN_BUILD_BTL "Build benchmark suite" OFF)
|
||||
|
||||
IF(BUILD_LIB)
|
||||
OPTION(TEST_LIB "Build the unit tests using the library (disable -pedantic)" OFF)
|
||||
ENDIF(BUILD_LIB)
|
||||
if(EIGEN_BUILD_LIB)
|
||||
option(EIGEN_TEST_LIB "Build the unit tests using the library (disable -pedantic)" OFF)
|
||||
endif(EIGEN_BUILD_LIB)
|
||||
|
||||
SET(CMAKE_INCLUDE_CURRENT_DIR ON)
|
||||
set(CMAKE_INCLUDE_CURRENT_DIR ON)
|
||||
|
||||
IF(CMAKE_COMPILER_IS_GNUCXX)
|
||||
IF(CMAKE_SYSTEM_NAME MATCHES Linux)
|
||||
SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wnon-virtual-dtor -Wno-long-long -ansi -Wundef -Wcast-align -Wchar-subscripts -Wall -W -Wpointer-arith -Wwrite-strings -Wformat-security -fno-exceptions -fno-check-new -fno-common -fstrict-aliasing")
|
||||
IF(NOT TEST_LIB)
|
||||
SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -pedantic")
|
||||
ENDIF(NOT TEST_LIB)
|
||||
IF(TEST_SSE2)
|
||||
SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -msse2")
|
||||
MESSAGE("Enabling SSE2 in tests/examples")
|
||||
ENDIF(TEST_SSE2)
|
||||
IF(TEST_SSE3)
|
||||
SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -msse3")
|
||||
MESSAGE("Enabling SSE3 in tests/examples")
|
||||
ENDIF(TEST_SSE3)
|
||||
IF(TEST_SSSE3)
|
||||
SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -mssse3")
|
||||
MESSAGE("Enabling SSSE3 in tests/examples")
|
||||
ENDIF(TEST_SSSE3)
|
||||
IF(TEST_ALTIVEC)
|
||||
SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -maltivec -mabi=altivec")
|
||||
MESSAGE("Enabling AltiVec in tests/examples")
|
||||
ENDIF(TEST_ALTIVEC)
|
||||
ENDIF(CMAKE_SYSTEM_NAME MATCHES Linux)
|
||||
ENDIF(CMAKE_COMPILER_IS_GNUCXX)
|
||||
if(CMAKE_COMPILER_IS_GNUCXX)
|
||||
if(CMAKE_SYSTEM_NAME MATCHES Linux)
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wnon-virtual-dtor -Wno-long-long -ansi -Wundef -Wcast-align -Wchar-subscripts -Wall -W -Wpointer-arith -Wwrite-strings -Wformat-security -fno-exceptions -fno-check-new -fno-common -fstrict-aliasing")
|
||||
if(NOT EIGEN_TEST_LIB)
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -pedantic")
|
||||
endif(NOT EIGEN_TEST_LIB)
|
||||
if(EIGEN_TEST_SSE2)
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -msse2")
|
||||
message("Enabling SSE2 in tests/examples")
|
||||
endif(EIGEN_TEST_SSE2)
|
||||
if(EIGEN_TEST_SSE3)
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -msse3")
|
||||
message("Enabling SSE3 in tests/examples")
|
||||
endif(EIGEN_TEST_SSE3)
|
||||
if(EIGEN_TEST_SSSE3)
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -mssse3")
|
||||
message("Enabling SSSE3 in tests/examples")
|
||||
endif(EIGEN_TEST_SSSE3)
|
||||
if(EIGEN_TEST_ALTIVEC)
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -maltivec -mabi=altivec")
|
||||
message("Enabling AltiVec in tests/examples")
|
||||
endif(EIGEN_TEST_ALTIVEC)
|
||||
endif(CMAKE_SYSTEM_NAME MATCHES Linux)
|
||||
endif(CMAKE_COMPILER_IS_GNUCXX)
|
||||
|
||||
INCLUDE_DIRECTORIES(${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_BINARY_DIR})
|
||||
include_directories(${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_BINARY_DIR})
|
||||
|
||||
ADD_SUBDIRECTORY(Eigen)
|
||||
ADD_SUBDIRECTORY(test)
|
||||
ADD_SUBDIRECTORY(doc)
|
||||
ADD_SUBDIRECTORY(demos)
|
||||
add_subdirectory(Eigen)
|
||||
|
||||
IF(BUILD_BTL)
|
||||
ADD_SUBDIRECTORY(bench/btl)
|
||||
ENDIF(BUILD_BTL)
|
||||
if(EIGEN_BUILD_TESTS)
|
||||
add_subdirectory(test)
|
||||
endif(EIGEN_BUILD_TESTS)
|
||||
|
||||
add_subdirectory(doc)
|
||||
|
||||
if(EIGEN_BUILD_DEMOS)
|
||||
add_subdirectory(demos)
|
||||
endif(EIGEN_BUILD_DEMOS)
|
||||
|
||||
if(EIGEN_BUILD_BTL)
|
||||
add_subdirectory(bench/btl)
|
||||
endif(EIGEN_BUILD_BTL)
|
||||
|
||||
2
Doxyfile
2
Doxyfile
@@ -5,7 +5,7 @@
|
||||
#---------------------------------------------------------------------------
|
||||
DOXYFILE_ENCODING = UTF-8
|
||||
PROJECT_NAME = Eigen
|
||||
PROJECT_NUMBER = 2.0-alpha7
|
||||
PROJECT_NUMBER = 2.0
|
||||
OUTPUT_DIRECTORY = ./
|
||||
CREATE_SUBDIRS = NO
|
||||
OUTPUT_LANGUAGE = English
|
||||
|
||||
@@ -28,6 +28,7 @@ namespace Eigen {
|
||||
#include "src/Array/Select.h"
|
||||
#include "src/Array/PartialRedux.h"
|
||||
#include "src/Array/Random.h"
|
||||
#include "src/Array/Norms.h"
|
||||
|
||||
} // namespace Eigen
|
||||
|
||||
|
||||
@@ -1,34 +1,34 @@
|
||||
SET(Eigen_HEADERS Core LU Cholesky QR Geometry Sparse Array SVD Regression)
|
||||
set(Eigen_HEADERS Core LU Cholesky QR Geometry Sparse Array SVD Regression)
|
||||
|
||||
IF(BUILD_LIB)
|
||||
SET(Eigen_SRCS
|
||||
if(EIGEN_BUILD_LIB)
|
||||
set(Eigen_SRCS
|
||||
src/Core/CoreInstantiations.cpp
|
||||
src/Cholesky/CholeskyInstantiations.cpp
|
||||
src/QR/QrInstantiations.cpp
|
||||
)
|
||||
|
||||
ADD_LIBRARY(Eigen2 SHARED ${Eigen_SRCS})
|
||||
add_library(Eigen2 SHARED ${Eigen_SRCS})
|
||||
|
||||
INSTALL(TARGETS Eigen2
|
||||
install(TARGETS Eigen2
|
||||
RUNTIME DESTINATION bin
|
||||
LIBRARY DESTINATION lib
|
||||
ARCHIVE DESTINATION lib)
|
||||
ENDIF(BUILD_LIB)
|
||||
endif(EIGEN_BUILD_LIB)
|
||||
|
||||
IF(CMAKE_COMPILER_IS_GNUCXX)
|
||||
SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -g1 -O2")
|
||||
SET(CMAKE_CXX_FLAGS_RELWITHDEBINFO "${CMAKE_CXX_FLAGS_RELWITHDEBINFO} -g1 -O2")
|
||||
ENDIF(CMAKE_COMPILER_IS_GNUCXX)
|
||||
if(CMAKE_COMPILER_IS_GNUCXX)
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -g1 -O2")
|
||||
set(CMAKE_CXX_FLAGS_RELWITHDEBINFO "${CMAKE_CXX_FLAGS_RELWITHDEBINFO} -g1 -O2")
|
||||
endif(CMAKE_COMPILER_IS_GNUCXX)
|
||||
|
||||
SET(INCLUDE_INSTALL_DIR
|
||||
set(INCLUDE_INSTALL_DIR
|
||||
"${CMAKE_INSTALL_PREFIX}/include/eigen2"
|
||||
CACHE PATH
|
||||
"The directory where we install the header files"
|
||||
FORCE)
|
||||
|
||||
INSTALL(FILES
|
||||
install(FILES
|
||||
${Eigen_HEADERS}
|
||||
DESTINATION ${INCLUDE_INSTALL_DIR}/Eigen
|
||||
)
|
||||
|
||||
ADD_SUBDIRECTORY(src)
|
||||
add_subdirectory(src)
|
||||
|
||||
@@ -17,8 +17,8 @@ namespace Eigen {
|
||||
/** \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::cholesky(),
|
||||
* - MatrixBase::choleskyNoSqrt()
|
||||
* - MatrixBase::llt(),
|
||||
* - MatrixBase::ldlt()
|
||||
*
|
||||
* \code
|
||||
* #include <Eigen/Cholesky>
|
||||
@@ -27,6 +27,8 @@ namespace Eigen {
|
||||
|
||||
#include "src/Array/CwiseOperators.h"
|
||||
#include "src/Array/Functors.h"
|
||||
#include "src/Cholesky/LLT.h"
|
||||
#include "src/Cholesky/LDLT.h"
|
||||
#include "src/Cholesky/Cholesky.h"
|
||||
#include "src/Cholesky/CholeskyWithoutSquareRoot.h"
|
||||
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
#define EIGEN_GEOMETRY_MODULE_H
|
||||
|
||||
#include "Array"
|
||||
#include <limits>
|
||||
|
||||
#ifndef M_PI
|
||||
#define M_PI 3.14159265358979323846
|
||||
@@ -28,11 +29,13 @@ namespace Eigen {
|
||||
#include "src/Geometry/Rotation2D.h"
|
||||
#include "src/Geometry/Quaternion.h"
|
||||
#include "src/Geometry/AngleAxis.h"
|
||||
#include "src/Geometry/EulerAngles.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"
|
||||
|
||||
} // namespace Eigen
|
||||
|
||||
|
||||
84
Eigen/Sparse
84
Eigen/Sparse
@@ -8,19 +8,97 @@
|
||||
#include <cstring>
|
||||
#include <algorithm>
|
||||
|
||||
#ifdef EIGEN_GOOGLEHASH_SUPPORT
|
||||
#include <google/dense_hash_map>
|
||||
#endif
|
||||
|
||||
#ifdef EIGEN_CHOLMOD_SUPPORT
|
||||
extern "C" {
|
||||
#include "cholmod.h"
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef EIGEN_TAUCS_SUPPORT
|
||||
|
||||
// taucs.h declares a lot of mess
|
||||
#define isnan
|
||||
#define finite
|
||||
#define isinf
|
||||
extern "C" {
|
||||
#include "taucs.h"
|
||||
}
|
||||
#undef isnan
|
||||
#undef finite
|
||||
#undef isinf
|
||||
|
||||
#ifdef min
|
||||
#undef min
|
||||
#endif
|
||||
#ifdef max
|
||||
#undef max
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef EIGEN_SUPERLU_SUPPORT
|
||||
typedef int int_t;
|
||||
#include "superlu/slu_Cnames.h"
|
||||
#include "superlu/supermatrix.h"
|
||||
#include "superlu/slu_util.h"
|
||||
|
||||
namespace SuperLU_S {
|
||||
#include "superlu/slu_sdefs.h"
|
||||
}
|
||||
namespace SuperLU_D {
|
||||
#include "superlu/slu_ddefs.h"
|
||||
}
|
||||
namespace SuperLU_C {
|
||||
#include "superlu/slu_cdefs.h"
|
||||
}
|
||||
namespace SuperLU_Z {
|
||||
#include "superlu/slu_zdefs.h"
|
||||
}
|
||||
namespace Eigen { struct SluMatrix; }
|
||||
#endif
|
||||
|
||||
#ifdef EIGEN_UMFPACK_SUPPORT
|
||||
#include "umfpack.h"
|
||||
#endif
|
||||
|
||||
namespace Eigen {
|
||||
|
||||
#include "src/Sparse/SparseUtil.h"
|
||||
#include "src/Sparse/SparseMatrixBase.h"
|
||||
#include "src/Sparse/SparseArray.h"
|
||||
#include "src/Sparse/AmbiVector.h"
|
||||
#include "src/Sparse/RandomSetter.h"
|
||||
#include "src/Sparse/SparseBlock.h"
|
||||
#include "src/Sparse/SparseMatrix.h"
|
||||
#include "src/Sparse/HashMatrix.h"
|
||||
#include "src/Sparse/LinkedVectorMatrix.h"
|
||||
//#include "src/Sparse/HashMatrix.h"
|
||||
//#include "src/Sparse/LinkedVectorMatrix.h"
|
||||
#include "src/Sparse/CoreIterators.h"
|
||||
#include "src/Sparse/SparseSetter.h"
|
||||
//#include "src/Sparse/SparseSetter.h"
|
||||
#include "src/Sparse/SparseProduct.h"
|
||||
#include "src/Sparse/TriangularSolver.h"
|
||||
#include "src/Sparse/SparseLLT.h"
|
||||
#include "src/Sparse/SparseLDLT.h"
|
||||
#include "src/Sparse/SparseLU.h"
|
||||
|
||||
#ifdef EIGEN_CHOLMOD_SUPPORT
|
||||
# include "src/Sparse/CholmodSupport.h"
|
||||
#endif
|
||||
|
||||
#ifdef EIGEN_TAUCS_SUPPORT
|
||||
# include "src/Sparse/TaucsSupport.h"
|
||||
#endif
|
||||
|
||||
#ifdef EIGEN_SUPERLU_SUPPORT
|
||||
# include "src/Sparse/SuperLUSupport.h"
|
||||
#endif
|
||||
|
||||
#ifdef EIGEN_UMFPACK_SUPPORT
|
||||
# include "src/Sparse/UmfPackSupport.h"
|
||||
#endif
|
||||
|
||||
} // namespace Eigen
|
||||
|
||||
|
||||
80
Eigen/src/Array/Norms.h
Normal file
80
Eigen/src/Array/Norms.h
Normal file
@@ -0,0 +1,80 @@
|
||||
// This file is part of Eigen, a lightweight C++ template library
|
||||
// for linear algebra. Eigen itself is part of the KDE project.
|
||||
//
|
||||
// Copyright (C) 2008 Benoit Jacob <jacob.benoit.1@gmail.com>
|
||||
//
|
||||
// Eigen is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU Lesser General Public
|
||||
// License as published by the Free Software Foundation; either
|
||||
// version 3 of the License, or (at your option) any later version.
|
||||
//
|
||||
// Alternatively, you can redistribute it and/or
|
||||
// modify it under the terms of the GNU General Public License as
|
||||
// published by the Free Software Foundation; either version 2 of
|
||||
// the License, or (at your option) any later version.
|
||||
//
|
||||
// Eigen is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||
// FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License or the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public
|
||||
// License and a copy of the GNU General Public License along with
|
||||
// Eigen. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
#ifndef EIGEN_ARRAY_NORMS_H
|
||||
#define EIGEN_ARRAY_NORMS_H
|
||||
|
||||
template<typename Derived, int p>
|
||||
struct ei_lpNorm_selector
|
||||
{
|
||||
typedef typename NumTraits<typename ei_traits<Derived>::Scalar>::Real RealScalar;
|
||||
inline static RealScalar run(const MatrixBase<Derived>& m)
|
||||
{
|
||||
return ei_pow(m.cwise().abs().cwise().pow(p).sum(), RealScalar(1)/p);
|
||||
}
|
||||
};
|
||||
|
||||
template<typename Derived>
|
||||
struct ei_lpNorm_selector<Derived, 1>
|
||||
{
|
||||
inline static typename NumTraits<typename ei_traits<Derived>::Scalar>::Real run(const MatrixBase<Derived>& m)
|
||||
{
|
||||
return m.cwise().abs().sum();
|
||||
}
|
||||
};
|
||||
|
||||
template<typename Derived>
|
||||
struct ei_lpNorm_selector<Derived, 2>
|
||||
{
|
||||
inline static typename NumTraits<typename ei_traits<Derived>::Scalar>::Real run(const MatrixBase<Derived>& m)
|
||||
{
|
||||
return m.norm();
|
||||
}
|
||||
};
|
||||
|
||||
template<typename Derived>
|
||||
struct ei_lpNorm_selector<Derived, Infinity>
|
||||
{
|
||||
inline static typename NumTraits<typename ei_traits<Derived>::Scalar>::Real run(const MatrixBase<Derived>& m)
|
||||
{
|
||||
return m.cwise().abs().maxCoeff();
|
||||
}
|
||||
};
|
||||
|
||||
/** \array_module
|
||||
*
|
||||
* \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^p\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 ei_traits<Derived>::Scalar>::Real MatrixBase<Derived>::lpNorm() const
|
||||
{
|
||||
return ei_lpNorm_selector<Derived, p>::run(*this);
|
||||
}
|
||||
|
||||
#endif // EIGEN_ARRAY_NORMS_H
|
||||
@@ -2,7 +2,7 @@
|
||||
// for linear algebra. Eigen itself is part of the KDE project.
|
||||
//
|
||||
// Copyright (C) 2008 Gael Guennebaud <g.gael@free.fr>
|
||||
// Copyright (C) 2006-2008 Benoit Jacob <jacob@math.jussieu.fr>
|
||||
// Copyright (C) 2006-2008 Benoit Jacob <jacob.benoit.1@gmail.com>
|
||||
//
|
||||
// Eigen is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU Lesser General Public
|
||||
@@ -107,7 +107,7 @@ class PartialReduxExpr : ei_no_assignment_operator,
|
||||
{ return mat.MEMBER(); } \
|
||||
}
|
||||
|
||||
EIGEN_MEMBER_FUNCTOR(norm2, Size * NumTraits<Scalar>::MulCost + (Size-1)*NumTraits<Scalar>::AddCost);
|
||||
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(sum, (Size-1)*NumTraits<Scalar>::AddCost);
|
||||
EIGEN_MEMBER_FUNCTOR(minCoeff, (Size-1)*NumTraits<Scalar>::AddCost);
|
||||
@@ -204,11 +204,11 @@ template<typename ExpressionType, int Direction> class PartialRedux
|
||||
/** \returns a row (or column) vector expression of the squared norm
|
||||
* of each column (or row) of the referenced expression.
|
||||
*
|
||||
* Example: \include PartialRedux_norm2.cpp
|
||||
* Output: \verbinclude PartialRedux_norm2.out
|
||||
* Example: \include PartialRedux_squaredNorm.cpp
|
||||
* Output: \verbinclude PartialRedux_squaredNorm.out
|
||||
*
|
||||
* \sa MatrixBase::norm2() */
|
||||
const typename ReturnType<ei_member_norm2>::Type norm2() const
|
||||
* \sa MatrixBase::squaredNorm() */
|
||||
const typename ReturnType<ei_member_squaredNorm>::Type squaredNorm() const
|
||||
{ return _expression(); }
|
||||
|
||||
/** \returns a row (or column) vector expression of the norm
|
||||
|
||||
@@ -29,22 +29,7 @@
|
||||
*
|
||||
* \class Cholesky
|
||||
*
|
||||
* \brief Standard Cholesky decomposition of a matrix and associated features
|
||||
*
|
||||
* \param MatrixType the type of the matrix of which we are computing the Cholesky decomposition
|
||||
*
|
||||
* This class performs a standard 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.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* \sa MatrixBase::cholesky(), class CholeskyWithoutSquareRoot
|
||||
* \deprecated this class has been renamed LLT
|
||||
*/
|
||||
template<typename MatrixType> class Cholesky
|
||||
{
|
||||
@@ -59,20 +44,27 @@ template<typename MatrixType> class Cholesky
|
||||
};
|
||||
|
||||
public:
|
||||
|
||||
|
||||
Cholesky(const MatrixType& matrix)
|
||||
: m_matrix(matrix.rows(), matrix.cols())
|
||||
{
|
||||
compute(matrix);
|
||||
}
|
||||
|
||||
/** \deprecated */
|
||||
inline Part<MatrixType, Lower> matrixL(void) const { return m_matrix; }
|
||||
|
||||
/** \returns true if the matrix is positive definite */
|
||||
/** \deprecated */
|
||||
inline bool isPositiveDefinite(void) const { return m_isPositiveDefinite; }
|
||||
|
||||
template<typename Derived>
|
||||
typename Derived::Eval solve(const MatrixBase<Derived> &b) const;
|
||||
typename Derived::Eval solve(const MatrixBase<Derived> &b) const EIGEN_DEPRECATED;
|
||||
|
||||
template<typename RhsDerived, typename ResDerived>
|
||||
bool solve(const MatrixBase<RhsDerived> &b, MatrixBase<ResDerived> *result) const;
|
||||
|
||||
template<typename Derived>
|
||||
bool solveInPlace(MatrixBase<Derived> &bAndX) const;
|
||||
|
||||
void compute(const MatrixType& matrix);
|
||||
|
||||
@@ -85,8 +77,7 @@ template<typename MatrixType> class Cholesky
|
||||
bool m_isPositiveDefinite;
|
||||
};
|
||||
|
||||
/** Computes / recomputes the Cholesky decomposition A = LL^* = U^*U of \a matrix
|
||||
*/
|
||||
/** \deprecated */
|
||||
template<typename MatrixType>
|
||||
void Cholesky<MatrixType>::compute(const MatrixType& a)
|
||||
{
|
||||
@@ -102,7 +93,7 @@ void Cholesky<MatrixType>::compute(const MatrixType& a)
|
||||
m_matrix.col(0).end(size-1) = a.row(0).end(size-1).adjoint() / ei_real(m_matrix.coeff(0,0));
|
||||
for (int j = 1; j < size; ++j)
|
||||
{
|
||||
Scalar tmp = ei_real(a.coeff(j,j)) - m_matrix.row(j).start(j).norm2();
|
||||
Scalar tmp = ei_real(a.coeff(j,j)) - m_matrix.row(j).start(j).squaredNorm();
|
||||
x = ei_real(tmp);
|
||||
if (x < eps || (!ei_isMuchSmallerThan(ei_imag(tmp), RealScalar(1))))
|
||||
{
|
||||
@@ -125,28 +116,44 @@ void Cholesky<MatrixType>::compute(const MatrixType& a)
|
||||
}
|
||||
}
|
||||
|
||||
/** \returns the solution of \f$ A x = b \f$ using the current decomposition of A.
|
||||
* In other words, it returns \f$ A^{-1} b \f$ computing
|
||||
* \f$ {L^{*}}^{-1} L^{-1} b \f$ from right to left.
|
||||
* \param b the column vector \f$ b \f$, which can also be a matrix.
|
||||
*
|
||||
* Example: \include Cholesky_solve.cpp
|
||||
* Output: \verbinclude Cholesky_solve.out
|
||||
*
|
||||
* \sa MatrixBase::cholesky(), CholeskyWithoutSquareRoot::solve()
|
||||
*/
|
||||
/** \deprecated */
|
||||
template<typename MatrixType>
|
||||
template<typename Derived>
|
||||
typename Derived::Eval Cholesky<MatrixType>::solve(const MatrixBase<Derived> &b) const
|
||||
{
|
||||
const int size = m_matrix.rows();
|
||||
ei_assert(size==b.rows());
|
||||
typename ei_eval_to_column_major<Derived>::type x(b);
|
||||
solveInPlace(x);
|
||||
return x;
|
||||
}
|
||||
|
||||
return m_matrix.adjoint().template part<Upper>().solveTriangular(matrixL().solveTriangular(b));
|
||||
/** \deprecated */
|
||||
template<typename MatrixType>
|
||||
template<typename RhsDerived, typename ResDerived>
|
||||
bool Cholesky<MatrixType>::solve(const MatrixBase<RhsDerived> &b, MatrixBase<ResDerived> *result) const
|
||||
{
|
||||
const int size = m_matrix.rows();
|
||||
ei_assert(size==b.rows() && "Cholesky::solve(): invalid number of rows of the right hand side matrix b");
|
||||
return solveInPlace((*result) = b);
|
||||
}
|
||||
|
||||
/** \deprecated */
|
||||
template<typename MatrixType>
|
||||
template<typename Derived>
|
||||
bool Cholesky<MatrixType>::solveInPlace(MatrixBase<Derived> &bAndX) const
|
||||
{
|
||||
const int size = m_matrix.rows();
|
||||
ei_assert(size==bAndX.rows());
|
||||
if (!m_isPositiveDefinite)
|
||||
return false;
|
||||
matrixL().solveTriangularInPlace(bAndX);
|
||||
m_matrix.adjoint().template part<Upper>().solveTriangularInPlace(bAndX);
|
||||
return true;
|
||||
}
|
||||
|
||||
/** \cholesky_module
|
||||
* \returns the Cholesky decomposition of \c *this
|
||||
* \deprecated has been renamed llt()
|
||||
*/
|
||||
template<typename Derived>
|
||||
inline const Cholesky<typename MatrixBase<Derived>::EvalType>
|
||||
|
||||
@@ -25,25 +25,11 @@
|
||||
#ifndef EIGEN_CHOLESKY_WITHOUT_SQUARE_ROOT_H
|
||||
#define EIGEN_CHOLESKY_WITHOUT_SQUARE_ROOT_H
|
||||
|
||||
/** \ingroup Cholesky_Module
|
||||
/** \deprecated \ingroup Cholesky_Module
|
||||
*
|
||||
* \class CholeskyWithoutSquareRoot
|
||||
*
|
||||
* \brief Robust Cholesky decomposition of a matrix and associated features
|
||||
*
|
||||
* \param MatrixType the type of the matrix of which we are computing the Cholesky decomposition
|
||||
*
|
||||
* This class performs a Cholesky decomposition without square root of a symmetric, positive definite
|
||||
* matrix A such that A = L D L^* = U^* D U, where L is lower triangular with a unit diagonal
|
||||
* and D is a diagonal matrix.
|
||||
*
|
||||
* Compared to a standard Cholesky decomposition, avoiding the square roots allows for faster and more
|
||||
* stable computation.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* \sa MatrixBase::choleskyNoSqrt(), class Cholesky
|
||||
* \deprecated this class has been renamed LDLT
|
||||
*/
|
||||
template<typename MatrixType> class CholeskyWithoutSquareRoot
|
||||
{
|
||||
@@ -69,7 +55,13 @@ template<typename MatrixType> class CholeskyWithoutSquareRoot
|
||||
inline bool isPositiveDefinite(void) const { return m_isPositiveDefinite; }
|
||||
|
||||
template<typename Derived>
|
||||
typename Derived::Eval solve(const MatrixBase<Derived> &b) const;
|
||||
typename Derived::Eval solve(const MatrixBase<Derived> &b) const EIGEN_DEPRECATED;
|
||||
|
||||
template<typename RhsDerived, typename ResDerived>
|
||||
bool solve(const MatrixBase<RhsDerived> &b, MatrixBase<ResDerived> *result) const;
|
||||
|
||||
template<typename Derived>
|
||||
bool solveInPlace(MatrixBase<Derived> &bAndX) const;
|
||||
|
||||
void compute(const MatrixType& matrix);
|
||||
|
||||
@@ -85,8 +77,7 @@ template<typename MatrixType> class CholeskyWithoutSquareRoot
|
||||
bool m_isPositiveDefinite;
|
||||
};
|
||||
|
||||
/** Compute / recompute the Cholesky decomposition A = L D L^* = U^* D U of \a matrix
|
||||
*/
|
||||
/** \deprecated */
|
||||
template<typename MatrixType>
|
||||
void CholeskyWithoutSquareRoot<MatrixType>::compute(const MatrixType& a)
|
||||
{
|
||||
@@ -101,7 +92,7 @@ void CholeskyWithoutSquareRoot<MatrixType>::compute(const MatrixType& a)
|
||||
m_matrix = a;
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
// Let's preallocate a temporay vector to evaluate the matrix-vector product into it.
|
||||
// Unlike the standard Cholesky decomposition, here we cannot evaluate it to the destination
|
||||
// matrix because it a sub-row which is not compatible suitable for efficient packet evaluation.
|
||||
@@ -138,15 +129,7 @@ void CholeskyWithoutSquareRoot<MatrixType>::compute(const MatrixType& a)
|
||||
}
|
||||
}
|
||||
|
||||
/** \returns the solution of \f$ A x = b \f$ using the current decomposition of A.
|
||||
* In other words, it returns \f$ A^{-1} b \f$ computing
|
||||
* \f$ {L^{*}}^{-1} D^{-1} L^{-1} b \f$ from right to left.
|
||||
* \param b the column vector \f$ b \f$, which can also be a matrix.
|
||||
*
|
||||
* See Cholesky::solve() for a example.
|
||||
*
|
||||
* \sa MatrixBase::choleskyNoSqrt()
|
||||
*/
|
||||
/** \deprecated */
|
||||
template<typename MatrixType>
|
||||
template<typename Derived>
|
||||
typename Derived::Eval CholeskyWithoutSquareRoot<MatrixType>::solve(const MatrixBase<Derived> &b) const
|
||||
@@ -161,8 +144,35 @@ typename Derived::Eval CholeskyWithoutSquareRoot<MatrixType>::solve(const Matrix
|
||||
);
|
||||
}
|
||||
|
||||
/** \deprecated */
|
||||
template<typename MatrixType>
|
||||
template<typename RhsDerived, typename ResDerived>
|
||||
bool CholeskyWithoutSquareRoot<MatrixType>
|
||||
::solve(const MatrixBase<RhsDerived> &b, MatrixBase<ResDerived> *result) const
|
||||
{
|
||||
const int size = m_matrix.rows();
|
||||
ei_assert(size==b.rows() && "Cholesky::solve(): invalid number of rows of the right hand side matrix b");
|
||||
*result = b;
|
||||
return solveInPlace(*result);
|
||||
}
|
||||
|
||||
/** \deprecated */
|
||||
template<typename MatrixType>
|
||||
template<typename Derived>
|
||||
bool CholeskyWithoutSquareRoot<MatrixType>::solveInPlace(MatrixBase<Derived> &bAndX) const
|
||||
{
|
||||
const int size = m_matrix.rows();
|
||||
ei_assert(size==bAndX.rows());
|
||||
if (!m_isPositiveDefinite)
|
||||
return false;
|
||||
matrixL().solveTriangularInPlace(bAndX);
|
||||
bAndX = (m_matrix.cwise().inverse().template part<Diagonal>() * bAndX).lazy();
|
||||
m_matrix.adjoint().template part<UnitUpper>().solveTriangularInPlace(bAndX);
|
||||
return true;
|
||||
}
|
||||
|
||||
/** \cholesky_module
|
||||
* \returns the Cholesky decomposition without square root of \c *this
|
||||
* \deprecated has been renamed ldlt()
|
||||
*/
|
||||
template<typename Derived>
|
||||
inline const CholeskyWithoutSquareRoot<typename MatrixBase<Derived>::EvalType>
|
||||
|
||||
198
Eigen/src/Cholesky/LDLT.h
Normal file
198
Eigen/src/Cholesky/LDLT.h
Normal file
@@ -0,0 +1,198 @@
|
||||
// This file is part of Eigen, a lightweight C++ template library
|
||||
// for linear algebra. Eigen itself is part of the KDE project.
|
||||
//
|
||||
// Copyright (C) 2008 Gael Guennebaud <g.gael@free.fr>
|
||||
//
|
||||
// Eigen is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU Lesser General Public
|
||||
// License as published by the Free Software Foundation; either
|
||||
// version 3 of the License, or (at your option) any later version.
|
||||
//
|
||||
// Alternatively, you can redistribute it and/or
|
||||
// modify it under the terms of the GNU General Public License as
|
||||
// published by the Free Software Foundation; either version 2 of
|
||||
// the License, or (at your option) any later version.
|
||||
//
|
||||
// Eigen is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||
// FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License or the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public
|
||||
// License and a copy of the GNU General Public License along with
|
||||
// Eigen. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
#ifndef EIGEN_LDLT_H
|
||||
#define EIGEN_LDLT_H
|
||||
|
||||
/** \ingroup cholesky_Module
|
||||
*
|
||||
* \class LDLT
|
||||
*
|
||||
* \brief Robust Cholesky decomposition of a matrix and associated features
|
||||
*
|
||||
* \param MatrixType the type of the matrix of which we are computing the LDL^T Cholesky decomposition
|
||||
*
|
||||
* This class performs a Cholesky decomposition without square root of a symmetric, positive definite
|
||||
* matrix A such that A = L D L^* = U^* D U, where L is lower triangular with a unit diagonal
|
||||
* and D is a diagonal matrix.
|
||||
*
|
||||
* Compared to a standard Cholesky decomposition, avoiding the square roots allows for faster and more
|
||||
* stable computation.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* \sa MatrixBase::ldlt(), class LLT
|
||||
*/
|
||||
template<typename MatrixType> class LDLT
|
||||
{
|
||||
public:
|
||||
|
||||
typedef typename MatrixType::Scalar Scalar;
|
||||
typedef typename NumTraits<typename MatrixType::Scalar>::Real RealScalar;
|
||||
typedef Matrix<Scalar, MatrixType::ColsAtCompileTime, 1> VectorType;
|
||||
|
||||
LDLT(const MatrixType& matrix)
|
||||
: m_matrix(matrix.rows(), matrix.cols())
|
||||
{
|
||||
compute(matrix);
|
||||
}
|
||||
|
||||
/** \returns the lower triangular matrix L */
|
||||
inline Part<MatrixType, UnitLower> matrixL(void) const { return m_matrix; }
|
||||
|
||||
/** \returns the coefficients of the diagonal matrix D */
|
||||
inline DiagonalCoeffs<MatrixType> vectorD(void) const { return m_matrix.diagonal(); }
|
||||
|
||||
/** \returns true if the matrix is positive definite */
|
||||
inline bool isPositiveDefinite(void) const { return m_isPositiveDefinite; }
|
||||
|
||||
template<typename RhsDerived, typename ResDerived>
|
||||
bool solve(const MatrixBase<RhsDerived> &b, MatrixBase<ResDerived> *result) const;
|
||||
|
||||
template<typename Derived>
|
||||
bool solveInPlace(MatrixBase<Derived> &bAndX) const;
|
||||
|
||||
void compute(const MatrixType& matrix);
|
||||
|
||||
protected:
|
||||
/** \internal
|
||||
* Used to compute and store the cholesky decomposition A = L D L^* = U^* D U.
|
||||
* The strict upper part is used during the decomposition, the strict lower
|
||||
* part correspond to the coefficients of L (its diagonal is equal to 1 and
|
||||
* is not stored), and the diagonal entries correspond to D.
|
||||
*/
|
||||
MatrixType m_matrix;
|
||||
|
||||
bool m_isPositiveDefinite;
|
||||
};
|
||||
|
||||
/** Compute / recompute the LLT decomposition A = L D L^* = U^* D U of \a matrix
|
||||
*/
|
||||
template<typename MatrixType>
|
||||
void LDLT<MatrixType>::compute(const MatrixType& a)
|
||||
{
|
||||
assert(a.rows()==a.cols());
|
||||
const int size = a.rows();
|
||||
m_matrix.resize(size, size);
|
||||
m_isPositiveDefinite = true;
|
||||
const RealScalar eps = ei_sqrt(precision<Scalar>());
|
||||
|
||||
if (size<=1)
|
||||
{
|
||||
m_matrix = a;
|
||||
return;
|
||||
}
|
||||
|
||||
// Let's preallocate a temporay vector to evaluate the matrix-vector product into it.
|
||||
// Unlike the standard LLT decomposition, here we cannot evaluate it to the destination
|
||||
// matrix because it a sub-row which is not compatible suitable for efficient packet evaluation.
|
||||
// (at least if we assume the matrix is col-major)
|
||||
Matrix<Scalar,MatrixType::RowsAtCompileTime,1> _temporary(size);
|
||||
|
||||
// Note that, in this algorithm the rows of the strict upper part of m_matrix is used to store
|
||||
// column vector, thus the strange .conjugate() and .transpose()...
|
||||
|
||||
m_matrix.row(0) = a.row(0).conjugate();
|
||||
m_matrix.col(0).end(size-1) = m_matrix.row(0).end(size-1) / m_matrix.coeff(0,0);
|
||||
for (int j = 1; j < size; ++j)
|
||||
{
|
||||
RealScalar tmp = ei_real(a.coeff(j,j) - (m_matrix.row(j).start(j) * m_matrix.col(j).start(j).conjugate()).coeff(0,0));
|
||||
m_matrix.coeffRef(j,j) = tmp;
|
||||
|
||||
if (tmp < eps)
|
||||
{
|
||||
m_isPositiveDefinite = false;
|
||||
return;
|
||||
}
|
||||
|
||||
int endSize = size-j-1;
|
||||
if (endSize>0)
|
||||
{
|
||||
_temporary.end(endSize) = ( m_matrix.block(j+1,0, endSize, j)
|
||||
* m_matrix.col(j).start(j).conjugate() ).lazy();
|
||||
|
||||
m_matrix.row(j).end(endSize) = a.row(j).end(endSize).conjugate()
|
||||
- _temporary.end(endSize).transpose();
|
||||
|
||||
m_matrix.col(j).end(endSize) = m_matrix.row(j).end(endSize) / tmp;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** Computes the solution x of \f$ A x = b \f$ using the current decomposition of A.
|
||||
* The result is stored in \a result
|
||||
*
|
||||
* \returns true in case of success, false otherwise.
|
||||
*
|
||||
* In other words, it computes \f$ b = A^{-1} b \f$ with
|
||||
* \f$ {L^{*}}^{-1} D^{-1} L^{-1} b \f$ from right to left.
|
||||
*
|
||||
* \sa LDLT::solveInPlace(), MatrixBase::ldlt()
|
||||
*/
|
||||
template<typename MatrixType>
|
||||
template<typename RhsDerived, typename ResDerived>
|
||||
bool LDLT<MatrixType>
|
||||
::solve(const MatrixBase<RhsDerived> &b, MatrixBase<ResDerived> *result) const
|
||||
{
|
||||
const int size = m_matrix.rows();
|
||||
ei_assert(size==b.rows() && "LLT::solve(): invalid number of rows of the right hand side matrix b");
|
||||
*result = b;
|
||||
return solveInPlace(*result);
|
||||
}
|
||||
|
||||
/** This is the \em in-place version of solve().
|
||||
*
|
||||
* \param bAndX represents both the right-hand side matrix b and result x.
|
||||
*
|
||||
* This version avoids a copy when the right hand side matrix b is not
|
||||
* needed anymore.
|
||||
*
|
||||
* \sa LDLT::solve(), MatrixBase::ldlt()
|
||||
*/
|
||||
template<typename MatrixType>
|
||||
template<typename Derived>
|
||||
bool LDLT<MatrixType>::solveInPlace(MatrixBase<Derived> &bAndX) const
|
||||
{
|
||||
const int size = m_matrix.rows();
|
||||
ei_assert(size==bAndX.rows());
|
||||
if (!m_isPositiveDefinite)
|
||||
return false;
|
||||
matrixL().solveTriangularInPlace(bAndX);
|
||||
bAndX = (m_matrix.cwise().inverse().template part<Diagonal>() * bAndX).lazy();
|
||||
m_matrix.adjoint().template part<UnitUpper>().solveTriangularInPlace(bAndX);
|
||||
return true;
|
||||
}
|
||||
|
||||
/** \cholesky_module
|
||||
* \returns the Cholesky decomposition without square root of \c *this
|
||||
*/
|
||||
template<typename Derived>
|
||||
inline const LDLT<typename MatrixBase<Derived>::EvalType>
|
||||
MatrixBase<Derived>::ldlt() const
|
||||
{
|
||||
return derived();
|
||||
}
|
||||
|
||||
#endif // EIGEN_LDLT_H
|
||||
186
Eigen/src/Cholesky/LLT.h
Normal file
186
Eigen/src/Cholesky/LLT.h
Normal file
@@ -0,0 +1,186 @@
|
||||
// This file is part of Eigen, a lightweight C++ template library
|
||||
// for linear algebra. Eigen itself is part of the KDE project.
|
||||
//
|
||||
// Copyright (C) 2008 Gael Guennebaud <g.gael@free.fr>
|
||||
//
|
||||
// Eigen is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU Lesser General Public
|
||||
// License as published by the Free Software Foundation; either
|
||||
// version 3 of the License, or (at your option) any later version.
|
||||
//
|
||||
// Alternatively, you can redistribute it and/or
|
||||
// modify it under the terms of the GNU General Public License as
|
||||
// published by the Free Software Foundation; either version 2 of
|
||||
// the License, or (at your option) any later version.
|
||||
//
|
||||
// Eigen is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||
// FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License or the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public
|
||||
// License and a copy of the GNU General Public License along with
|
||||
// Eigen. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
#ifndef EIGEN_LLT_H
|
||||
#define EIGEN_LLT_H
|
||||
|
||||
/** \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
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* \sa MatrixBase::llt(), class LDLT
|
||||
*/
|
||||
template<typename MatrixType> class LLT
|
||||
{
|
||||
private:
|
||||
typedef typename MatrixType::Scalar Scalar;
|
||||
typedef typename NumTraits<typename MatrixType::Scalar>::Real RealScalar;
|
||||
typedef Matrix<Scalar, MatrixType::ColsAtCompileTime, 1> VectorType;
|
||||
|
||||
enum {
|
||||
PacketSize = ei_packet_traits<Scalar>::size,
|
||||
AlignmentMask = int(PacketSize)-1
|
||||
};
|
||||
|
||||
public:
|
||||
|
||||
LLT(const MatrixType& matrix)
|
||||
: m_matrix(matrix.rows(), matrix.cols())
|
||||
{
|
||||
compute(matrix);
|
||||
}
|
||||
|
||||
/** \returns the lower triangular matrix L */
|
||||
inline Part<MatrixType, Lower> matrixL(void) const { return m_matrix; }
|
||||
|
||||
/** \returns true if the matrix is positive definite */
|
||||
inline bool isPositiveDefinite(void) const { return m_isPositiveDefinite; }
|
||||
|
||||
template<typename RhsDerived, typename ResDerived>
|
||||
bool solve(const MatrixBase<RhsDerived> &b, MatrixBase<ResDerived> *result) const;
|
||||
|
||||
template<typename Derived>
|
||||
bool solveInPlace(MatrixBase<Derived> &bAndX) const;
|
||||
|
||||
void compute(const MatrixType& matrix);
|
||||
|
||||
protected:
|
||||
/** \internal
|
||||
* Used to compute and store L
|
||||
* The strict upper part is not used and even not initialized.
|
||||
*/
|
||||
MatrixType m_matrix;
|
||||
bool m_isPositiveDefinite;
|
||||
};
|
||||
|
||||
/** Computes / recomputes the Cholesky decomposition A = LL^* = U^*U of \a matrix
|
||||
*/
|
||||
template<typename MatrixType>
|
||||
void LLT<MatrixType>::compute(const MatrixType& a)
|
||||
{
|
||||
assert(a.rows()==a.cols());
|
||||
const int size = a.rows();
|
||||
m_matrix.resize(size, size);
|
||||
const RealScalar eps = ei_sqrt(precision<Scalar>());
|
||||
|
||||
RealScalar x;
|
||||
x = ei_real(a.coeff(0,0));
|
||||
m_isPositiveDefinite = x > eps && ei_isMuchSmallerThan(ei_imag(a.coeff(0,0)), RealScalar(1));
|
||||
m_matrix.coeffRef(0,0) = ei_sqrt(x);
|
||||
m_matrix.col(0).end(size-1) = a.row(0).end(size-1).adjoint() / ei_real(m_matrix.coeff(0,0));
|
||||
for (int j = 1; j < size; ++j)
|
||||
{
|
||||
Scalar tmp = ei_real(a.coeff(j,j)) - m_matrix.row(j).start(j).squaredNorm();
|
||||
x = ei_real(tmp);
|
||||
if (x < eps || (!ei_isMuchSmallerThan(ei_imag(tmp), RealScalar(1))))
|
||||
{
|
||||
m_isPositiveDefinite = false;
|
||||
return;
|
||||
}
|
||||
m_matrix.coeffRef(j,j) = x = ei_sqrt(x);
|
||||
|
||||
int endSize = size-j-1;
|
||||
if (endSize>0) {
|
||||
// Note that when all matrix columns have good alignment, then the following
|
||||
// product is guaranteed to be optimal with respect to alignment.
|
||||
m_matrix.col(j).end(endSize) =
|
||||
(m_matrix.block(j+1, 0, endSize, j) * m_matrix.row(j).start(j).adjoint()).lazy();
|
||||
|
||||
// FIXME could use a.col instead of a.row
|
||||
m_matrix.col(j).end(endSize) = (a.row(j).end(endSize).adjoint()
|
||||
- m_matrix.col(j).end(endSize) ) / x;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** Computes the solution x of \f$ A x = b \f$ using the current decomposition of A.
|
||||
* The result is stored in \a result
|
||||
*
|
||||
* \returns true in case of success, false otherwise.
|
||||
*
|
||||
* In other words, it computes \f$ b = A^{-1} b \f$ with
|
||||
* \f$ {L^{*}}^{-1} L^{-1} b \f$ from right to left.
|
||||
*
|
||||
* Example: \include LLT_solve.cpp
|
||||
* Output: \verbinclude LLT_solve.out
|
||||
*
|
||||
* \sa LLT::solveInPlace(), MatrixBase::llt()
|
||||
*/
|
||||
template<typename MatrixType>
|
||||
template<typename RhsDerived, typename ResDerived>
|
||||
bool LLT<MatrixType>::solve(const MatrixBase<RhsDerived> &b, MatrixBase<ResDerived> *result) const
|
||||
{
|
||||
const int size = m_matrix.rows();
|
||||
ei_assert(size==b.rows() && "LLT::solve(): invalid number of rows of the right hand side matrix b");
|
||||
return solveInPlace((*result) = b);
|
||||
}
|
||||
|
||||
/** This is the \em in-place version of solve().
|
||||
*
|
||||
* \param bAndX represents both the right-hand side matrix b and result x.
|
||||
*
|
||||
* This version avoids a copy when the right hand side matrix b is not
|
||||
* needed anymore.
|
||||
*
|
||||
* \sa LLT::solve(), MatrixBase::llt()
|
||||
*/
|
||||
template<typename MatrixType>
|
||||
template<typename Derived>
|
||||
bool LLT<MatrixType>::solveInPlace(MatrixBase<Derived> &bAndX) const
|
||||
{
|
||||
const int size = m_matrix.rows();
|
||||
ei_assert(size==bAndX.rows());
|
||||
if (!m_isPositiveDefinite)
|
||||
return false;
|
||||
matrixL().solveTriangularInPlace(bAndX);
|
||||
m_matrix.adjoint().template part<Upper>().solveTriangularInPlace(bAndX);
|
||||
return true;
|
||||
}
|
||||
|
||||
/** \cholesky_module
|
||||
* \returns the LLT decomposition of \c *this
|
||||
*/
|
||||
template<typename Derived>
|
||||
inline const LLT<typename MatrixBase<Derived>::EvalType>
|
||||
MatrixBase<Derived>::llt() const
|
||||
{
|
||||
return LLT<typename ei_eval<Derived>::type>(derived());
|
||||
}
|
||||
|
||||
#endif // EIGEN_LLT_H
|
||||
@@ -2,7 +2,7 @@
|
||||
// for linear algebra. Eigen itself is part of the KDE project.
|
||||
//
|
||||
// Copyright (C) 2007 Michael Olbrich <michael.olbrich@gmx.net>
|
||||
// Copyright (C) 2006-2008 Benoit Jacob <jacob@math.jussieu.fr>
|
||||
// Copyright (C) 2006-2008 Benoit Jacob <jacob.benoit.1@gmail.com>
|
||||
// Copyright (C) 2008 Gael Guennebaud <g.gael@free.fr>
|
||||
//
|
||||
// Eigen is free software; you can redistribute it and/or
|
||||
@@ -400,7 +400,7 @@ template<typename OtherDerived>
|
||||
inline Derived& MatrixBase<Derived>
|
||||
::lazyAssign(const MatrixBase<OtherDerived>& other)
|
||||
{
|
||||
EIGEN_STATIC_ASSERT_SAME_MATRIX_SIZE(Derived,OtherDerived);
|
||||
EIGEN_STATIC_ASSERT_SAME_MATRIX_SIZE(Derived,OtherDerived)
|
||||
ei_assert(rows() == other.rows() && cols() == other.cols());
|
||||
ei_assign_impl<Derived, OtherDerived>::run(derived(),other.derived());
|
||||
return derived();
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
// for linear algebra. Eigen itself is part of the KDE project.
|
||||
//
|
||||
// Copyright (C) 2008 Gael Guennebaud <g.gael@free.fr>
|
||||
// Copyright (C) 2006-2008 Benoit Jacob <jacob@math.jussieu.fr>
|
||||
// Copyright (C) 2006-2008 Benoit Jacob <jacob.benoit.1@gmail.com>
|
||||
//
|
||||
// Eigen is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU Lesser General Public
|
||||
@@ -122,7 +122,7 @@ template<typename MatrixType, int BlockRows, int BlockCols, int PacketAccess, in
|
||||
: m_matrix(matrix), m_startRow(startRow), m_startCol(startCol),
|
||||
m_blockRows(matrix.rows()), m_blockCols(matrix.cols())
|
||||
{
|
||||
EIGEN_STATIC_ASSERT(RowsAtCompileTime!=Dynamic && RowsAtCompileTime!=Dynamic,this_method_is_only_for_fixed_size);
|
||||
EIGEN_STATIC_ASSERT(RowsAtCompileTime!=Dynamic && RowsAtCompileTime!=Dynamic,this_method_is_only_for_fixed_size)
|
||||
ei_assert(startRow >= 0 && BlockRows >= 1 && startRow + BlockRows <= matrix.rows()
|
||||
&& startCol >= 0 && BlockCols >= 1 && startCol + BlockCols <= matrix.cols());
|
||||
}
|
||||
@@ -318,41 +318,41 @@ inline const typename BlockReturnType<Derived>::Type MatrixBase<Derived>
|
||||
return typename BlockReturnType<Derived>::Type(derived(), startRow, startCol, blockRows, blockCols);
|
||||
}
|
||||
|
||||
/** \returns a dynamic-size expression of a block in *this.
|
||||
/** \returns a dynamic-size expression of a segment (i.e. a vector block) in *this.
|
||||
*
|
||||
* \only_for_vectors
|
||||
*
|
||||
* \addexample BlockIntInt \label How to reference a sub-vector (dynamic size)
|
||||
* \addexample SegmentIntInt \label How to reference a sub-vector (dynamic size)
|
||||
*
|
||||
* \param start the first coefficient in the block
|
||||
* \param size the number of coefficients in the block
|
||||
* \param start the first coefficient in the segment
|
||||
* \param size the number of coefficients in the segment
|
||||
*
|
||||
* Example: \include MatrixBase_block_int_int.cpp
|
||||
* Output: \verbinclude MatrixBase_block_int_int.out
|
||||
* 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, block(int)
|
||||
* \sa class Block, segment(int)
|
||||
*/
|
||||
template<typename Derived>
|
||||
inline typename BlockReturnType<Derived>::SubVectorType MatrixBase<Derived>
|
||||
::block(int start, int size)
|
||||
::segment(int start, int size)
|
||||
{
|
||||
EIGEN_STATIC_ASSERT_VECTOR_ONLY(Derived);
|
||||
EIGEN_STATIC_ASSERT_VECTOR_ONLY(Derived)
|
||||
return typename BlockReturnType<Derived>::SubVectorType(derived(), RowsAtCompileTime == 1 ? 0 : start,
|
||||
ColsAtCompileTime == 1 ? 0 : start,
|
||||
RowsAtCompileTime == 1 ? 1 : size,
|
||||
ColsAtCompileTime == 1 ? 1 : size);
|
||||
}
|
||||
|
||||
/** This is the const version of block(int,int).*/
|
||||
/** This is the const version of segment(int,int).*/
|
||||
template<typename Derived>
|
||||
inline const typename BlockReturnType<Derived>::SubVectorType
|
||||
MatrixBase<Derived>::block(int start, int size) const
|
||||
MatrixBase<Derived>::segment(int start, int size) const
|
||||
{
|
||||
EIGEN_STATIC_ASSERT_VECTOR_ONLY(Derived);
|
||||
EIGEN_STATIC_ASSERT_VECTOR_ONLY(Derived)
|
||||
return typename BlockReturnType<Derived>::SubVectorType(derived(), RowsAtCompileTime == 1 ? 0 : start,
|
||||
ColsAtCompileTime == 1 ? 0 : start,
|
||||
RowsAtCompileTime == 1 ? 1 : size,
|
||||
@@ -380,7 +380,7 @@ template<typename Derived>
|
||||
inline typename BlockReturnType<Derived,Dynamic>::SubVectorType
|
||||
MatrixBase<Derived>::start(int size)
|
||||
{
|
||||
EIGEN_STATIC_ASSERT_VECTOR_ONLY(Derived);
|
||||
EIGEN_STATIC_ASSERT_VECTOR_ONLY(Derived)
|
||||
return Block<Derived,
|
||||
RowsAtCompileTime == 1 ? 1 : Dynamic,
|
||||
ColsAtCompileTime == 1 ? 1 : Dynamic>
|
||||
@@ -394,7 +394,7 @@ template<typename Derived>
|
||||
inline const typename BlockReturnType<Derived,Dynamic>::SubVectorType
|
||||
MatrixBase<Derived>::start(int size) const
|
||||
{
|
||||
EIGEN_STATIC_ASSERT_VECTOR_ONLY(Derived);
|
||||
EIGEN_STATIC_ASSERT_VECTOR_ONLY(Derived)
|
||||
return Block<Derived,
|
||||
RowsAtCompileTime == 1 ? 1 : Dynamic,
|
||||
ColsAtCompileTime == 1 ? 1 : Dynamic>
|
||||
@@ -424,7 +424,7 @@ template<typename Derived>
|
||||
inline typename BlockReturnType<Derived,Dynamic>::SubVectorType
|
||||
MatrixBase<Derived>::end(int size)
|
||||
{
|
||||
EIGEN_STATIC_ASSERT_VECTOR_ONLY(Derived);
|
||||
EIGEN_STATIC_ASSERT_VECTOR_ONLY(Derived)
|
||||
return Block<Derived,
|
||||
RowsAtCompileTime == 1 ? 1 : Dynamic,
|
||||
ColsAtCompileTime == 1 ? 1 : Dynamic>
|
||||
@@ -440,7 +440,7 @@ template<typename Derived>
|
||||
inline const typename BlockReturnType<Derived,Dynamic>::SubVectorType
|
||||
MatrixBase<Derived>::end(int size) const
|
||||
{
|
||||
EIGEN_STATIC_ASSERT_VECTOR_ONLY(Derived);
|
||||
EIGEN_STATIC_ASSERT_VECTOR_ONLY(Derived)
|
||||
return Block<Derived,
|
||||
RowsAtCompileTime == 1 ? 1 : Dynamic,
|
||||
ColsAtCompileTime == 1 ? 1 : Dynamic>
|
||||
@@ -451,7 +451,7 @@ MatrixBase<Derived>::end(int size) const
|
||||
ColsAtCompileTime == 1 ? 1 : size);
|
||||
}
|
||||
|
||||
/** \returns a fixed-size expression of a sub-vector of \c *this
|
||||
/** \returns a fixed-size expression of a segment (i.e. a vector block) in \c *this
|
||||
*
|
||||
* \only_for_vectors
|
||||
*
|
||||
@@ -459,30 +459,30 @@ MatrixBase<Derived>::end(int size) const
|
||||
*
|
||||
* \param start the index of the first element of the sub-vector
|
||||
*
|
||||
* Example: \include MatrixBase_template_int.cpp
|
||||
* Output: \verbinclude MatrixBase_template_int.out
|
||||
* Example: \include MatrixBase_template_int_segment.cpp
|
||||
* Output: \verbinclude MatrixBase_template_int_segment.out
|
||||
*
|
||||
* \sa class Block
|
||||
*/
|
||||
template<typename Derived>
|
||||
template<int Size>
|
||||
inline typename BlockReturnType<Derived,Size>::SubVectorType
|
||||
MatrixBase<Derived>::block(int start)
|
||||
MatrixBase<Derived>::segment(int start)
|
||||
{
|
||||
EIGEN_STATIC_ASSERT_VECTOR_ONLY(Derived);
|
||||
EIGEN_STATIC_ASSERT_VECTOR_ONLY(Derived)
|
||||
return Block<Derived, (RowsAtCompileTime == 1 ? 1 : Size),
|
||||
(ColsAtCompileTime == 1 ? 1 : Size)>
|
||||
(derived(), RowsAtCompileTime == 1 ? 0 : start,
|
||||
ColsAtCompileTime == 1 ? 0 : start);
|
||||
}
|
||||
|
||||
/** This is the const version of block<int>(int).*/
|
||||
/** This is the const version of segment<int>(int).*/
|
||||
template<typename Derived>
|
||||
template<int Size>
|
||||
inline const typename BlockReturnType<Derived,Size>::SubVectorType
|
||||
MatrixBase<Derived>::block(int start) const
|
||||
MatrixBase<Derived>::segment(int start) const
|
||||
{
|
||||
EIGEN_STATIC_ASSERT_VECTOR_ONLY(Derived);
|
||||
EIGEN_STATIC_ASSERT_VECTOR_ONLY(Derived)
|
||||
return Block<Derived, (RowsAtCompileTime == 1 ? 1 : Size),
|
||||
(ColsAtCompileTime == 1 ? 1 : Size)>
|
||||
(derived(), RowsAtCompileTime == 1 ? 0 : start,
|
||||
@@ -507,7 +507,7 @@ template<int Size>
|
||||
inline typename BlockReturnType<Derived,Size>::SubVectorType
|
||||
MatrixBase<Derived>::start()
|
||||
{
|
||||
EIGEN_STATIC_ASSERT_VECTOR_ONLY(Derived);
|
||||
EIGEN_STATIC_ASSERT_VECTOR_ONLY(Derived)
|
||||
return Block<Derived, (RowsAtCompileTime == 1 ? 1 : Size),
|
||||
(ColsAtCompileTime == 1 ? 1 : Size)>(derived(), 0, 0);
|
||||
}
|
||||
@@ -518,7 +518,7 @@ template<int Size>
|
||||
inline const typename BlockReturnType<Derived,Size>::SubVectorType
|
||||
MatrixBase<Derived>::start() const
|
||||
{
|
||||
EIGEN_STATIC_ASSERT_VECTOR_ONLY(Derived);
|
||||
EIGEN_STATIC_ASSERT_VECTOR_ONLY(Derived)
|
||||
return Block<Derived, (RowsAtCompileTime == 1 ? 1 : Size),
|
||||
(ColsAtCompileTime == 1 ? 1 : Size)>(derived(), 0, 0);
|
||||
}
|
||||
@@ -539,7 +539,7 @@ template<int Size>
|
||||
inline typename BlockReturnType<Derived,Size>::SubVectorType
|
||||
MatrixBase<Derived>::end()
|
||||
{
|
||||
EIGEN_STATIC_ASSERT_VECTOR_ONLY(Derived);
|
||||
EIGEN_STATIC_ASSERT_VECTOR_ONLY(Derived)
|
||||
return Block<Derived, RowsAtCompileTime == 1 ? 1 : Size,
|
||||
ColsAtCompileTime == 1 ? 1 : Size>
|
||||
(derived(),
|
||||
@@ -553,7 +553,7 @@ template<int Size>
|
||||
inline const typename BlockReturnType<Derived,Size>::SubVectorType
|
||||
MatrixBase<Derived>::end() const
|
||||
{
|
||||
EIGEN_STATIC_ASSERT_VECTOR_ONLY(Derived);
|
||||
EIGEN_STATIC_ASSERT_VECTOR_ONLY(Derived)
|
||||
return Block<Derived, RowsAtCompileTime == 1 ? 1 : Size,
|
||||
ColsAtCompileTime == 1 ? 1 : Size>
|
||||
(derived(),
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
// This file is part of Eigen, a lightweight C++ template library
|
||||
// for linear algebra. Eigen itself is part of the KDE project.
|
||||
//
|
||||
// Copyright (C) 2006-2008 Benoit Jacob <jacob@math.jussieu.fr>
|
||||
// Copyright (C) 2006-2008 Benoit Jacob <jacob.benoit.1@gmail.com>
|
||||
//
|
||||
// Eigen is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU Lesser General Public
|
||||
@@ -313,6 +313,13 @@ inline void MatrixBase<Derived>::writePacket
|
||||
derived().template writePacket<StoreMode>(index,x);
|
||||
}
|
||||
|
||||
/** \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 Derived>
|
||||
template<typename OtherDerived>
|
||||
inline void MatrixBase<Derived>::copyCoeff(int row, int col, const MatrixBase<OtherDerived>& other)
|
||||
@@ -322,6 +329,13 @@ inline void MatrixBase<Derived>::copyCoeff(int row, int col, const MatrixBase<Ot
|
||||
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 Derived>
|
||||
template<typename OtherDerived>
|
||||
inline void MatrixBase<Derived>::copyCoeff(int index, const MatrixBase<OtherDerived>& other)
|
||||
@@ -330,6 +344,13 @@ inline void MatrixBase<Derived>::copyCoeff(int index, const MatrixBase<OtherDeri
|
||||
derived().coeffRef(index) = other.derived().coeff(index);
|
||||
}
|
||||
|
||||
/** \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 Derived>
|
||||
template<typename OtherDerived, int StoreMode, int LoadMode>
|
||||
inline void MatrixBase<Derived>::copyPacket(int row, int col, const MatrixBase<OtherDerived>& other)
|
||||
@@ -340,6 +361,13 @@ inline void MatrixBase<Derived>::copyPacket(int row, int col, const MatrixBase<O
|
||||
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 Derived>
|
||||
template<typename OtherDerived, int StoreMode, int LoadMode>
|
||||
inline void MatrixBase<Derived>::copyPacket(int index, const MatrixBase<OtherDerived>& other)
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
// for linear algebra. Eigen itself is part of the KDE project.
|
||||
//
|
||||
// Copyright (C) 2008 Gael Guennebaud <g.gael@free.fr>
|
||||
// Copyright (C) 2006-2008 Benoit Jacob <jacob@math.jussieu.fr>
|
||||
// Copyright (C) 2006-2008 Benoit Jacob <jacob.benoit.1@gmail.com>
|
||||
//
|
||||
// Eigen is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU Lesser General Public
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
// for linear algebra. Eigen itself is part of the KDE project.
|
||||
//
|
||||
// Copyright (C) 2008 Gael Guennebaud <g.gael@free.fr>
|
||||
// Copyright (C) 2008 Benoit Jacob <jacob@math.jussieu.fr>
|
||||
// Copyright (C) 2008 Benoit Jacob <jacob.benoit.1@gmail.com>
|
||||
//
|
||||
// Eigen is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU Lesser General Public
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
// for linear algebra. Eigen itself is part of the KDE project.
|
||||
//
|
||||
// Copyright (C) 2008 Gael Guennebaud <g.gael@free.fr>
|
||||
// Copyright (C) 2006-2008 Benoit Jacob <jacob@math.jussieu.fr>
|
||||
// Copyright (C) 2006-2008 Benoit Jacob <jacob.benoit.1@gmail.com>
|
||||
//
|
||||
// Eigen is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU Lesser General Public
|
||||
@@ -46,12 +46,15 @@
|
||||
template<typename BinaryOp, typename Lhs, typename Rhs>
|
||||
struct ei_traits<CwiseBinaryOp<BinaryOp, Lhs, Rhs> >
|
||||
{
|
||||
// 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 ei_result_of<
|
||||
BinaryOp(
|
||||
typename Lhs::Scalar,
|
||||
typename Rhs::Scalar
|
||||
)
|
||||
>::type Scalar;
|
||||
|
||||
typedef typename Lhs::Nested LhsNested;
|
||||
typedef typename Rhs::Nested RhsNested;
|
||||
typedef typename ei_unref<LhsNested>::type _LhsNested;
|
||||
@@ -89,6 +92,16 @@ class CwiseBinaryOp : ei_no_assignment_operator,
|
||||
inline CwiseBinaryOp(const Lhs& lhs, const Rhs& rhs, const BinaryOp& func = BinaryOp())
|
||||
: m_lhs(lhs), m_rhs(rhs), m_functor(func)
|
||||
{
|
||||
// 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.
|
||||
EIGEN_STATIC_ASSERT((ei_is_same_type<typename Lhs::Scalar, typename Rhs::Scalar>::ret),
|
||||
you_mixed_different_numeric_types__you_need_to_use_the_cast_method_of_MatrixBase_to_cast_numeric_types_explicitly)
|
||||
// require the sizes to match
|
||||
ei_assert(lhs.rows() == rhs.rows() && lhs.cols() == rhs.cols());
|
||||
}
|
||||
|
||||
|
||||
@@ -561,7 +561,7 @@ inline Derived& MatrixBase<Derived>::setIdentity()
|
||||
template<typename Derived>
|
||||
const typename MatrixBase<Derived>::BasisReturnType MatrixBase<Derived>::Unit(int size, int i)
|
||||
{
|
||||
EIGEN_STATIC_ASSERT_VECTOR_ONLY(Derived);
|
||||
EIGEN_STATIC_ASSERT_VECTOR_ONLY(Derived)
|
||||
return BasisReturnType(SquareMatrixType::Identity(size,size), i);
|
||||
}
|
||||
|
||||
@@ -576,7 +576,7 @@ const typename MatrixBase<Derived>::BasisReturnType MatrixBase<Derived>::Unit(in
|
||||
template<typename Derived>
|
||||
const typename MatrixBase<Derived>::BasisReturnType MatrixBase<Derived>::Unit(int i)
|
||||
{
|
||||
EIGEN_STATIC_ASSERT_VECTOR_ONLY(Derived);
|
||||
EIGEN_STATIC_ASSERT_VECTOR_ONLY(Derived)
|
||||
return BasisReturnType(SquareMatrixType::Identity(),i);
|
||||
}
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
// for linear algebra. Eigen itself is part of the KDE project.
|
||||
//
|
||||
// Copyright (C) 2008 Gael Guennebaud <g.gael@free.fr>
|
||||
// Copyright (C) 2006-2008 Benoit Jacob <jacob@math.jussieu.fr>
|
||||
// Copyright (C) 2006-2008 Benoit Jacob <jacob.benoit.1@gmail.com>
|
||||
//
|
||||
// Eigen is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU Lesser General Public
|
||||
@@ -174,13 +174,17 @@ MatrixBase<Derived>::conjugate() const
|
||||
|
||||
/** \returns an expression of the real part of \c *this.
|
||||
*
|
||||
* \sa adjoint() */
|
||||
* \sa imag() */
|
||||
template<typename Derived>
|
||||
inline const typename MatrixBase<Derived>::RealReturnType
|
||||
MatrixBase<Derived>::real() const
|
||||
{
|
||||
return derived();
|
||||
}
|
||||
MatrixBase<Derived>::real() const { return derived(); }
|
||||
|
||||
/** \returns an expression of the imaginary part of \c *this.
|
||||
*
|
||||
* \sa real() */
|
||||
template<typename Derived>
|
||||
inline const typename MatrixBase<Derived>::ImagReturnType
|
||||
MatrixBase<Derived>::imag() const { return derived(); }
|
||||
|
||||
/** \returns an expression of *this with the \a Scalar type casted to
|
||||
* \a NewScalar.
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
// This file is part of Eigen, a lightweight C++ template library
|
||||
// for linear algebra. Eigen itself is part of the KDE project.
|
||||
//
|
||||
// Copyright (C) 2006-2008 Benoit Jacob <jacob@math.jussieu.fr>
|
||||
// Copyright (C) 2006-2008 Benoit Jacob <jacob.benoit.1@gmail.com>
|
||||
//
|
||||
// Eigen is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU Lesser General Public
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
// This file is part of Eigen, a lightweight C++ template library
|
||||
// for linear algebra. Eigen itself is part of the KDE project.
|
||||
//
|
||||
// Copyright (C) 2006-2008 Benoit Jacob <jacob@math.jussieu.fr>
|
||||
// Copyright (C) 2006-2008 Benoit Jacob <jacob.benoit.1@gmail.com>
|
||||
//
|
||||
// Eigen is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU Lesser General Public
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
// for linear algebra. Eigen itself is part of the KDE project.
|
||||
//
|
||||
// Copyright (C) 2008 Gael Guennebaud <g.gael@free.fr>
|
||||
// Copyright (C) 2006-2008 Benoit Jacob <jacob@math.jussieu.fr>
|
||||
// Copyright (C) 2006-2008 Benoit Jacob <jacob.benoit.1@gmail.com>
|
||||
//
|
||||
// Eigen is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU Lesser General Public
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
// This file is part of Eigen, a lightweight C++ template library
|
||||
// for linear algebra. Eigen itself is part of the KDE project.
|
||||
//
|
||||
// Copyright (C) 2006-2008 Benoit Jacob <jacob@math.jussieu.fr>
|
||||
// Copyright (C) 2006-2008 Benoit Jacob <jacob.benoit.1@gmail.com>
|
||||
//
|
||||
// Eigen is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU Lesser General Public
|
||||
@@ -153,6 +153,7 @@ struct ei_dot_impl<Derived1, Derived2, NoVectorization, NoUnrolling>
|
||||
typedef typename Derived1::Scalar Scalar;
|
||||
static Scalar run(const Derived1& v1, const Derived2& v2)
|
||||
{
|
||||
ei_assert(v1.size()>0 && "you are using a non initialized vector");
|
||||
Scalar res;
|
||||
res = v1.coeff(0) * ei_conj(v2.coeff(0));
|
||||
for(int i = 1; i < v1.size(); i++)
|
||||
@@ -247,10 +248,10 @@ struct ei_dot_impl<Derived1, Derived2, LinearVectorization, CompleteUnrolling>
|
||||
* \only_for_vectors
|
||||
*
|
||||
* \note If the scalar type is complex numbers, then this function returns the hermitian
|
||||
* (sesquilinear) dot product, linear in the first variable and anti-linear in the
|
||||
* (sesquilinear) dot product, linear in the first variable and conjugate-linear in the
|
||||
* second variable.
|
||||
*
|
||||
* \sa norm2(), norm()
|
||||
* \sa squaredNorm(), norm()
|
||||
*/
|
||||
template<typename Derived>
|
||||
template<typename OtherDerived>
|
||||
@@ -262,14 +263,30 @@ MatrixBase<Derived>::dot(const MatrixBase<OtherDerived>& other) const
|
||||
typedef typename ei_unref<Nested>::type _Nested;
|
||||
typedef typename ei_unref<OtherNested>::type _OtherNested;
|
||||
|
||||
EIGEN_STATIC_ASSERT_VECTOR_ONLY(_Nested);
|
||||
EIGEN_STATIC_ASSERT_VECTOR_ONLY(_OtherNested);
|
||||
EIGEN_STATIC_ASSERT_SAME_VECTOR_SIZE(_Nested,_OtherNested);
|
||||
EIGEN_STATIC_ASSERT_VECTOR_ONLY(_Nested)
|
||||
EIGEN_STATIC_ASSERT_VECTOR_ONLY(_OtherNested)
|
||||
EIGEN_STATIC_ASSERT_SAME_VECTOR_SIZE(_Nested,_OtherNested)
|
||||
ei_assert(size() == other.size());
|
||||
|
||||
return ei_dot_impl<_Nested, _OtherNested>::run(derived(), other.derived());
|
||||
}
|
||||
|
||||
/** \returns the squared norm of *this, i.e. the dot product of *this with itself.
|
||||
*
|
||||
* \note This is \em not the \em l2 norm, but its square.
|
||||
*
|
||||
* \deprecated Use squaredNorm() instead. This norm2() function is kept only for compatibility and will be removed in Eigen 2.0.
|
||||
*
|
||||
* \only_for_vectors
|
||||
*
|
||||
* \sa dot(), norm()
|
||||
*/
|
||||
template<typename Derived>
|
||||
EIGEN_DEPRECATED inline typename NumTraits<typename ei_traits<Derived>::Scalar>::Real MatrixBase<Derived>::norm2() const
|
||||
{
|
||||
return ei_real(dot(*this));
|
||||
}
|
||||
|
||||
/** \returns the squared norm of *this, i.e. the dot product of *this with itself.
|
||||
*
|
||||
* \only_for_vectors
|
||||
@@ -277,21 +294,21 @@ MatrixBase<Derived>::dot(const MatrixBase<OtherDerived>& other) const
|
||||
* \sa dot(), norm()
|
||||
*/
|
||||
template<typename Derived>
|
||||
inline typename NumTraits<typename ei_traits<Derived>::Scalar>::Real MatrixBase<Derived>::norm2() const
|
||||
inline typename NumTraits<typename ei_traits<Derived>::Scalar>::Real MatrixBase<Derived>::squaredNorm() const
|
||||
{
|
||||
return ei_real(dot(*this));
|
||||
}
|
||||
|
||||
/** \returns the norm of *this, i.e. the square root of the dot product of *this with itself.
|
||||
/** \returns the \em l2 norm of *this, i.e. the square root of the dot product of *this with itself.
|
||||
*
|
||||
* \only_for_vectors
|
||||
*
|
||||
* \sa dot(), norm2()
|
||||
* \sa dot(), normSquared()
|
||||
*/
|
||||
template<typename Derived>
|
||||
inline typename NumTraits<typename ei_traits<Derived>::Scalar>::Real MatrixBase<Derived>::norm() const
|
||||
{
|
||||
return ei_sqrt(norm2());
|
||||
return ei_sqrt(squaredNorm());
|
||||
}
|
||||
|
||||
/** \returns an expression of the quotient of *this by its own norm.
|
||||
@@ -335,7 +352,7 @@ bool MatrixBase<Derived>::isOrthogonal
|
||||
{
|
||||
typename ei_nested<Derived,2>::type nested(derived());
|
||||
typename ei_nested<OtherDerived,2>::type otherNested(other.derived());
|
||||
return ei_abs2(nested.dot(otherNested)) <= prec * prec * nested.norm2() * otherNested.norm2();
|
||||
return ei_abs2(nested.dot(otherNested)) <= prec * prec * nested.squaredNorm() * otherNested.squaredNorm();
|
||||
}
|
||||
|
||||
/** \returns true if *this is approximately an unitary matrix,
|
||||
@@ -355,7 +372,7 @@ bool MatrixBase<Derived>::isUnitary(RealScalar prec) const
|
||||
typename Derived::Nested nested(derived());
|
||||
for(int i = 0; i < cols(); i++)
|
||||
{
|
||||
if(!ei_isApprox(nested.col(i).norm2(), static_cast<Scalar>(1), prec))
|
||||
if(!ei_isApprox(nested.col(i).squaredNorm(), static_cast<Scalar>(1), prec))
|
||||
return false;
|
||||
for(int j = 0; j < i; j++)
|
||||
if(!ei_isMuchSmallerThan(nested.col(i).dot(nested.col(j)), static_cast<Scalar>(1), prec))
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
// This file is part of Eigen, a lightweight C++ template library
|
||||
// for linear algebra. Eigen itself is part of the KDE project.
|
||||
//
|
||||
// Copyright (C) 2008 Benoit Jacob <jacob@math.jussieu.fr>
|
||||
// Copyright (C) 2008 Benoit Jacob <jacob.benoit.1@gmail.com>
|
||||
//
|
||||
// Eigen is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU Lesser General Public
|
||||
|
||||
@@ -240,7 +240,21 @@ struct ei_scalar_real_op EIGEN_EMPTY_STRUCT {
|
||||
};
|
||||
template<typename Scalar>
|
||||
struct ei_functor_traits<ei_scalar_real_op<Scalar> >
|
||||
{ enum { Cost = 0, PacketAccess = false }; };
|
||||
{ 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 ei_scalar_imag_op EIGEN_EMPTY_STRUCT {
|
||||
typedef typename NumTraits<Scalar>::Real result_type;
|
||||
inline result_type operator() (const Scalar& a) const { return ei_imag(a); }
|
||||
};
|
||||
template<typename Scalar>
|
||||
struct ei_functor_traits<ei_scalar_imag_op<Scalar> >
|
||||
{ enum { Cost = 0, PacketAccess = false }; };
|
||||
|
||||
/** \internal
|
||||
* \brief Template functor to multiply a scalar by a fixed other one
|
||||
@@ -334,7 +348,7 @@ template<typename Scalar>
|
||||
struct ei_functor_traits<ei_scalar_identity_op<Scalar> >
|
||||
{ enum { Cost = NumTraits<Scalar>::AddCost, PacketAccess = false, IsRepeatable = true }; };
|
||||
|
||||
// NOTE quick hack:
|
||||
// FIXME quick hack:
|
||||
// all functors allow linear access, except ei_scalar_identity_op. So we fix here a quick meta
|
||||
// to indicate whether a functor allows linear access, just always answering 'yes' except for
|
||||
// ei_scalar_identity_op.
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
// This file is part of Eigen, a lightweight C++ template library
|
||||
// for linear algebra. Eigen itself is part of the KDE project.
|
||||
//
|
||||
// Copyright (C) 2006-2008 Benoit Jacob <jacob@math.jussieu.fr>
|
||||
// Copyright (C) 2006-2008 Benoit Jacob <jacob.benoit.1@gmail.com>
|
||||
// Copyright (C) 2008 Gael Guennebaud <g.gael@free.fr>
|
||||
//
|
||||
// Eigen is free software; you can redistribute it and/or
|
||||
@@ -176,19 +176,19 @@ struct ei_fuzzy_selector<Derived,OtherDerived,true>
|
||||
typedef typename Derived::RealScalar RealScalar;
|
||||
static bool isApprox(const Derived& self, const OtherDerived& other, RealScalar prec)
|
||||
{
|
||||
EIGEN_STATIC_ASSERT_SAME_VECTOR_SIZE(Derived,OtherDerived);
|
||||
EIGEN_STATIC_ASSERT_SAME_VECTOR_SIZE(Derived,OtherDerived)
|
||||
ei_assert(self.size() == other.size());
|
||||
return((self - other).norm2() <= std::min(self.norm2(), other.norm2()) * prec * prec);
|
||||
return((self - other).squaredNorm() <= std::min(self.squaredNorm(), other.squaredNorm()) * prec * prec);
|
||||
}
|
||||
static bool isMuchSmallerThan(const Derived& self, const RealScalar& other, RealScalar prec)
|
||||
{
|
||||
return(self.norm2() <= ei_abs2(other * prec));
|
||||
return(self.squaredNorm() <= ei_abs2(other * prec));
|
||||
}
|
||||
static bool isMuchSmallerThan(const Derived& self, const OtherDerived& other, RealScalar prec)
|
||||
{
|
||||
EIGEN_STATIC_ASSERT_SAME_VECTOR_SIZE(Derived,OtherDerived);
|
||||
EIGEN_STATIC_ASSERT_SAME_VECTOR_SIZE(Derived,OtherDerived)
|
||||
ei_assert(self.size() == other.size());
|
||||
return(self.norm2() <= other.norm2() * prec * prec);
|
||||
return(self.squaredNorm() <= other.squaredNorm() * prec * prec);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -198,13 +198,13 @@ struct ei_fuzzy_selector<Derived,OtherDerived,false>
|
||||
typedef typename Derived::RealScalar RealScalar;
|
||||
static bool isApprox(const Derived& self, const OtherDerived& other, RealScalar prec)
|
||||
{
|
||||
EIGEN_STATIC_ASSERT_SAME_MATRIX_SIZE(Derived,OtherDerived);
|
||||
EIGEN_STATIC_ASSERT_SAME_MATRIX_SIZE(Derived,OtherDerived)
|
||||
ei_assert(self.rows() == other.rows() && self.cols() == other.cols());
|
||||
typename Derived::Nested nested(self);
|
||||
typename OtherDerived::Nested otherNested(other);
|
||||
for(int i = 0; i < self.cols(); i++)
|
||||
if((nested.col(i) - otherNested.col(i)).norm2()
|
||||
> std::min(nested.col(i).norm2(), otherNested.col(i).norm2()) * prec * prec)
|
||||
if((nested.col(i) - otherNested.col(i)).squaredNorm()
|
||||
> std::min(nested.col(i).squaredNorm(), otherNested.col(i).squaredNorm()) * prec * prec)
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
@@ -212,18 +212,18 @@ struct ei_fuzzy_selector<Derived,OtherDerived,false>
|
||||
{
|
||||
typename Derived::Nested nested(self);
|
||||
for(int i = 0; i < self.cols(); i++)
|
||||
if(nested.col(i).norm2() > ei_abs2(other * prec))
|
||||
if(nested.col(i).squaredNorm() > ei_abs2(other * prec))
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
static bool isMuchSmallerThan(const Derived& self, const OtherDerived& other, RealScalar prec)
|
||||
{
|
||||
EIGEN_STATIC_ASSERT_SAME_MATRIX_SIZE(Derived,OtherDerived);
|
||||
EIGEN_STATIC_ASSERT_SAME_MATRIX_SIZE(Derived,OtherDerived)
|
||||
ei_assert(self.rows() == other.rows() && self.cols() == other.cols());
|
||||
typename Derived::Nested nested(self);
|
||||
typename OtherDerived::Nested otherNested(other);
|
||||
for(int i = 0; i < self.cols(); i++)
|
||||
if(nested.col(i).norm2() > otherNested.col(i).norm2() * prec * prec)
|
||||
if(nested.col(i).squaredNorm() > otherNested.col(i).squaredNorm() * prec * prec)
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
// for linear algebra. Eigen itself is part of the KDE project.
|
||||
//
|
||||
// Copyright (C) 2008 Gael Guennebaud <g.gael@free.fr>
|
||||
// Copyright (C) 2006-2008 Benoit Jacob <jacob@math.jussieu.fr>
|
||||
// Copyright (C) 2006-2008 Benoit Jacob <jacob.benoit.1@gmail.com>
|
||||
//
|
||||
// Eigen is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU Lesser General Public
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
// This file is part of Eigen, a lightweight C++ template library
|
||||
// for linear algebra. Eigen itself is part of the KDE project.
|
||||
//
|
||||
// Copyright (C) 2006-2008 Benoit Jacob <jacob@math.jussieu.fr>
|
||||
// Copyright (C) 2006-2008 Benoit Jacob <jacob.benoit.1@gmail.com>
|
||||
// Copyright (C) 2008 Gael Guennebaud <g.gael@free.fr>
|
||||
//
|
||||
// Eigen is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU Lesser General Public
|
||||
@@ -121,8 +122,7 @@ MatrixBase<Derived>::format(const IOFormat& fmt) const
|
||||
/** \internal
|
||||
* print the matrix \a _m to the output stream \a s using the output format \a fmt */
|
||||
template<typename Derived>
|
||||
std::ostream & ei_print_matrix(std::ostream & s, const MatrixBase<Derived> & _m,
|
||||
const IOFormat& fmt = IOFormat())
|
||||
std::ostream & ei_print_matrix(std::ostream & s, const MatrixBase<Derived> & _m, const IOFormat& fmt)
|
||||
{
|
||||
const typename Derived::Nested m = _m;
|
||||
int width = 0;
|
||||
@@ -163,8 +163,12 @@ std::ostream & ei_print_matrix(std::ostream & s, const MatrixBase<Derived> & _m,
|
||||
|
||||
/** \relates MatrixBase
|
||||
*
|
||||
* Outputs the matrix, laid out as an array as usual, to the given stream.
|
||||
* You can control the way the matrix is printed using MatrixBase::format().
|
||||
* Outputs the matrix, to the given stream.
|
||||
*
|
||||
* If you wish to print the matrix with a format different than the default, use MatrixBase::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 MatrixBase::format()
|
||||
*/
|
||||
@@ -173,7 +177,7 @@ std::ostream & operator <<
|
||||
(std::ostream & s,
|
||||
const MatrixBase<Derived> & m)
|
||||
{
|
||||
return ei_print_matrix(s, m.eval());
|
||||
return ei_print_matrix(s, m.eval(), EIGEN_DEFAULT_IO_FORMAT);
|
||||
}
|
||||
|
||||
#endif // EIGEN_IO_H
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
// This file is part of Eigen, a lightweight C++ template library
|
||||
// for linear algebra. Eigen itself is part of the KDE project.
|
||||
//
|
||||
// Copyright (C) 2006-2008 Benoit Jacob <jacob@math.jussieu.fr>
|
||||
// Copyright (C) 2006-2008 Benoit Jacob <jacob.benoit.1@gmail.com>
|
||||
// Copyright (C) 2008 Gael Guennebaud <g.gael@free.fr>
|
||||
//
|
||||
// Eigen is free software; you can redistribute it and/or
|
||||
@@ -40,9 +40,9 @@
|
||||
* 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.
|
||||
*
|
||||
* This class is the return type of Matrix::map() but can also be used directly.
|
||||
* This class is the return type of Matrix::Map() but can also be used directly.
|
||||
*
|
||||
* \sa Matrix::map()
|
||||
* \sa Matrix::Map()
|
||||
*/
|
||||
template<typename MatrixType, int _PacketAccess>
|
||||
struct ei_traits<Map<MatrixType, _PacketAccess> > : public ei_traits<MatrixType>
|
||||
@@ -90,7 +90,7 @@ template<typename MatrixType, int PacketAccess> class Map
|
||||
|
||||
inline void resize(int size)
|
||||
{
|
||||
EIGEN_STATIC_ASSERT_VECTOR_ONLY(MatrixType);
|
||||
EIGEN_STATIC_ASSERT_VECTOR_ONLY(MatrixType)
|
||||
EIGEN_ONLY_USED_FOR_DEBUG(size);
|
||||
ei_assert(size == this->size());
|
||||
}
|
||||
@@ -106,13 +106,13 @@ template<typename MatrixType, int PacketAccess> class Map
|
||||
* for the dimensions.
|
||||
*
|
||||
* \sa Matrix(const Scalar *, int), Matrix(const Scalar *, int, int),
|
||||
* Matrix::map(const Scalar *)
|
||||
* Matrix::Map(const Scalar *)
|
||||
*/
|
||||
template<typename _Scalar, int _Rows, int _Cols, int _StorageOrder, int _MaxRows, int _MaxCols>
|
||||
inline Matrix<_Scalar, _Rows, _Cols, _StorageOrder, _MaxRows, _MaxCols>
|
||||
::Matrix(const Scalar *data)
|
||||
{
|
||||
*this = Map<Matrix>(data);
|
||||
*this = Eigen::Map<Matrix>(data);
|
||||
}
|
||||
|
||||
#endif // EIGEN_MAP_H
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
// This file is part of Eigen, a lightweight C++ template library
|
||||
// for linear algebra. Eigen itself is part of the KDE project.
|
||||
//
|
||||
// Copyright (C) 2006-2008 Benoit Jacob <jacob@math.jussieu.fr>
|
||||
// Copyright (C) 2006-2008 Benoit Jacob <jacob.benoit.1@gmail.com>
|
||||
// Copyright (C) 2008 Gael Guennebaud <g.gael@free.fr>
|
||||
//
|
||||
// Eigen is free software; you can redistribute it and/or
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
// This file is part of Eigen, a lightweight C++ template library
|
||||
// for linear algebra. Eigen itself is part of the KDE project.
|
||||
//
|
||||
// Copyright (C) 2006-2008 Benoit Jacob <jacob@math.jussieu.fr>
|
||||
// Copyright (C) 2006-2008 Benoit Jacob <jacob.benoit.1@gmail.com>
|
||||
//
|
||||
// Eigen is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU Lesser General Public
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
// This file is part of Eigen, a lightweight C++ template library
|
||||
// for linear algebra. Eigen itself is part of the KDE project.
|
||||
//
|
||||
// Copyright (C) 2006-2008 Benoit Jacob <jacob@math.jussieu.fr>
|
||||
// Copyright (C) 2006-2008 Benoit Jacob <jacob.benoit.1@gmail.com>
|
||||
//
|
||||
// Eigen is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU Lesser General Public
|
||||
@@ -25,60 +25,84 @@
|
||||
#ifndef EIGEN_MATRIX_H
|
||||
#define EIGEN_MATRIX_H
|
||||
|
||||
|
||||
/** \class Matrix
|
||||
*
|
||||
* \brief The matrix class, also used for vectors and row-vectors
|
||||
*
|
||||
* \param _Scalar the scalar type, i.e. the type of the coefficients
|
||||
* \param _Rows the number of rows at compile-time. Use the special value \a Dynamic to
|
||||
* specify that the number of rows is dynamic, i.e. is not fixed at compile-time.
|
||||
* \param _Cols the number of columns at compile-time. Use the special value \a Dynamic to
|
||||
* specify that the number of columns is dynamic, i.e. is not fixed at compile-time.
|
||||
* \param _StorageOrder can be either RowMajor or ColMajor. The default is ColMajor.
|
||||
* \param _MaxRows the maximum number of rows at compile-time. By default this is equal to \a _Rows.
|
||||
* The most common exception is when you don't know the exact number of rows, but know that
|
||||
* it is smaller than some given value. Then you can set \a _MaxRows to that value, and set
|
||||
* _Rows to \a Dynamic.
|
||||
* \param _MaxCols the maximum number of cols at compile-time. By default this is equal to \a _Cols.
|
||||
* The most common exception is when you don't know the exact number of cols, but know that
|
||||
* it is smaller than some given value. Then you can set \a _MaxCols to that value, and set
|
||||
* _Cols to \a Dynamic.
|
||||
* 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.
|
||||
*
|
||||
* This single class template covers all kinds of matrix and vectors that Eigen can handle.
|
||||
* All matrix and vector types are just typedefs to specializations of this class template.
|
||||
* The %Matrix class encompasses \em both fixed-size and dynamic-size objects (\ref fixedsize "note").
|
||||
*
|
||||
* These typedefs are as follows:
|
||||
* \li \c %Matrix\#\#Size\#\#Type for square matrices
|
||||
* \li \c Vector\#\#Size\#\#Type for vectors (matrices with one column)
|
||||
* \li \c RowVector\#\#Size\#\#Type for row-vectors (matrices with one row)
|
||||
* The first three template parameters are required:
|
||||
* \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
|
||||
*
|
||||
* where \c Size can be
|
||||
* \li \c 2 for fixed size 2
|
||||
* \li \c 3 for fixed size 3
|
||||
* \li \c 4 for fixed size 4
|
||||
* \li \c X for dynamic size
|
||||
* The remaining template parameters are optional -- in most cases you don't have to worry about them.
|
||||
* \param _StorageOrder Either \b RowMajor or \b ColMajor. The default is \b ColMajor.
|
||||
* \param _MaxRows Maximum number of rows. Defaults to \a _Rows (\ref maxrows "note").
|
||||
* \param _MaxCols Maximum number of columns. Defaults to \a _Cols (\ref maxrows "note").
|
||||
*
|
||||
* and \c Type can be
|
||||
* \li \c i for type \c int
|
||||
* \li \c f for type \c float
|
||||
* \li \c d for type \c double
|
||||
* \li \c cf for type \c std::complex<float>
|
||||
* \li \c cd for type \c std::complex<double>
|
||||
* Eigen provides a number of typedefs covering the usual cases. Here are some examples:
|
||||
*
|
||||
* Examples:
|
||||
* \li \c Matrix2d is a typedef for \c Matrix<double,2,2>
|
||||
* \li \c VectorXf is a typedef for \c Matrix<float,Dynamic,1>
|
||||
* \li \c RowVector3i is a typedef for \c Matrix<int,1,3>
|
||||
* \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>)
|
||||
*
|
||||
* See \ref matrixtypedefs for an explicit list of all matrix typedefs.
|
||||
* \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>)
|
||||
*
|
||||
* Of course these typedefs do not exhaust all the possibilities offered by the Matrix class
|
||||
* template, they only address some of the most common cases. For instance, if you want a
|
||||
* fixed-size matrix with 3 rows and 5 columns, there is no typedef for that, so you should use
|
||||
* \c Matrix<double,3,5>.
|
||||
* See \link matrixtypedefs this page \endlink for a complete list of predefined \em %Matrix and \em Vector typedefs.
|
||||
*
|
||||
* Note that most of the API is in the base class MatrixBase.
|
||||
* 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
|
||||
*
|
||||
* <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, typically on the heap (\ref alloca "note").
|
||||
*
|
||||
* 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>
|
||||
*
|
||||
* <dt><b>\anchor alloca Usage of alloca():</b></dt>
|
||||
* <dd>On the Linux platform, for small enough arrays, Eigen will avoid heap allocation and instead will use alloca() to perform a dynamic
|
||||
* allocation on the stack.</dd>
|
||||
* </dl>
|
||||
*
|
||||
* \see MatrixBase for the majority of the API methods for matrices
|
||||
*/
|
||||
template<typename _Scalar, int _Rows, int _Cols, int _StorageOrder, int _MaxRows, int _MaxCols>
|
||||
struct ei_traits<Matrix<_Scalar, _Rows, _Cols, _StorageOrder, _MaxRows, _MaxCols> >
|
||||
@@ -105,7 +129,9 @@ class Matrix
|
||||
public:
|
||||
EIGEN_GENERIC_PUBLIC_INTERFACE(Matrix)
|
||||
friend class Eigen::Map<Matrix, Unaligned>;
|
||||
typedef class Eigen::Map<Matrix, Unaligned> UnalignedMapType;
|
||||
friend class Eigen::Map<Matrix, Aligned>;
|
||||
typedef class Eigen::Map<Matrix, Aligned> AlignedMapType;
|
||||
|
||||
protected:
|
||||
ei_matrix_storage<Scalar, MaxSizeAtCompileTime, RowsAtCompileTime, ColsAtCompileTime> m_storage;
|
||||
@@ -187,6 +213,17 @@ class Matrix
|
||||
inline Scalar *data()
|
||||
{ return m_storage.data(); }
|
||||
|
||||
/** Resizes \c *this to a \a rows x \a cols matrix.
|
||||
*
|
||||
* Makes sense for dynamic-size matrices only.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* \sa resize(int) for vectors.
|
||||
*/
|
||||
inline void resize(int rows, int cols)
|
||||
{
|
||||
ei_assert(rows > 0
|
||||
@@ -198,8 +235,13 @@ class Matrix
|
||||
m_storage.resize(rows * cols, rows, cols);
|
||||
}
|
||||
|
||||
/** Resizes \c *this to a vector of length \a size
|
||||
*
|
||||
* \sa resize(int,int) for the details.
|
||||
*/
|
||||
inline void resize(int size)
|
||||
{
|
||||
ei_assert(size>0 && "a vector cannot be resized to 0 length");
|
||||
EIGEN_STATIC_ASSERT_VECTOR_ONLY(Matrix)
|
||||
if(RowsAtCompileTime == 1)
|
||||
m_storage.resize(size, 1, size);
|
||||
@@ -207,16 +249,36 @@ class Matrix
|
||||
m_storage.resize(size, size, 1);
|
||||
}
|
||||
|
||||
/** Copies the value of the expression \a other into *this.
|
||||
/** Copies the value of the expression \a other into \c *this.
|
||||
*
|
||||
* *this is resized (if possible) to match the dimensions of \a other.
|
||||
* \warning Note that the sizes of \c *this and \a other must match.
|
||||
* If you want automatic resizing, then you must use the function set().
|
||||
*
|
||||
* As a special exception, 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.
|
||||
* is allowed.
|
||||
*
|
||||
* \sa set()
|
||||
*/
|
||||
template<typename OtherDerived>
|
||||
inline Matrix& operator=(const MatrixBase<OtherDerived>& other)
|
||||
{
|
||||
ei_assert(m_storage.data()!=0 && "you cannot use operator= with a non initialized matrix (instead use set()");
|
||||
return Base::operator=(other.derived());
|
||||
}
|
||||
|
||||
/** Copies the value of the expression \a other into \c *this with automatic resizing.
|
||||
*
|
||||
* This function is the same than the assignment operator = excepted that \c *this might
|
||||
* be resized to match the dimensions of \a other.
|
||||
*
|
||||
* 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=()
|
||||
*/
|
||||
template<typename OtherDerived>
|
||||
inline Matrix& set(const MatrixBase<OtherDerived>& other)
|
||||
{
|
||||
if(RowsAtCompileTime == 1)
|
||||
{
|
||||
@@ -249,10 +311,28 @@ class Matrix
|
||||
*
|
||||
* For fixed-size matrices, does nothing.
|
||||
*
|
||||
* For dynamic-size matrices, initializes with initial size 1x1, which is inefficient, hence
|
||||
* when performance matters one should avoid using this constructor on dynamic-size matrices.
|
||||
* For dynamic-size matrices, creates an empty matrix of size null.
|
||||
* \warning while creating such an \em null matrix is allowed, it \b cannot
|
||||
* \b be \b used before having being resized or initialized with the function set().
|
||||
* In particular, initializing a null matrix with operator = is not supported.
|
||||
* Finally, this constructor is the unique way to create null matrices: resizing
|
||||
* a matrix to 0 is not supported.
|
||||
* Here are some examples:
|
||||
* \code
|
||||
* MatrixXf r = MatrixXf::Random(3,4); // create a random matrix of floats
|
||||
* MatrixXf m1, m2; // creates two null matrices of float
|
||||
*
|
||||
* m1 = r; // illegal (raise an assertion)
|
||||
* r = m1; // illegal (raise an assertion)
|
||||
* m1 = m2; // illegal (raise an assertion)
|
||||
* m1.set(r); // OK
|
||||
* m2.resize(3,4);
|
||||
* m2 = r; // OK
|
||||
* \endcode
|
||||
*
|
||||
* \sa resize(int,int), set()
|
||||
*/
|
||||
inline explicit Matrix() : m_storage(1, 1, 1)
|
||||
inline explicit Matrix() : m_storage()
|
||||
{
|
||||
ei_assert(RowsAtCompileTime > 0 && ColsAtCompileTime > 0);
|
||||
}
|
||||
@@ -298,21 +378,21 @@ class Matrix
|
||||
/** constructs an initialized 2D vector with given coefficients */
|
||||
inline Matrix(const float& x, const float& y)
|
||||
{
|
||||
EIGEN_STATIC_ASSERT_VECTOR_SPECIFIC_SIZE(Matrix, 2);
|
||||
EIGEN_STATIC_ASSERT_VECTOR_SPECIFIC_SIZE(Matrix, 2)
|
||||
m_storage.data()[0] = x;
|
||||
m_storage.data()[1] = y;
|
||||
}
|
||||
/** constructs an initialized 2D vector with given coefficients */
|
||||
inline Matrix(const double& x, const double& y)
|
||||
{
|
||||
EIGEN_STATIC_ASSERT_VECTOR_SPECIFIC_SIZE(Matrix, 2);
|
||||
EIGEN_STATIC_ASSERT_VECTOR_SPECIFIC_SIZE(Matrix, 2)
|
||||
m_storage.data()[0] = x;
|
||||
m_storage.data()[1] = y;
|
||||
}
|
||||
/** constructs an initialized 3D vector with given coefficients */
|
||||
inline Matrix(const Scalar& x, const Scalar& y, const Scalar& z)
|
||||
{
|
||||
EIGEN_STATIC_ASSERT_VECTOR_SPECIFIC_SIZE(Matrix, 3);
|
||||
EIGEN_STATIC_ASSERT_VECTOR_SPECIFIC_SIZE(Matrix, 3)
|
||||
m_storage.data()[0] = x;
|
||||
m_storage.data()[1] = y;
|
||||
m_storage.data()[2] = z;
|
||||
@@ -320,7 +400,7 @@ class Matrix
|
||||
/** constructs an initialized 4D vector with given coefficients */
|
||||
inline Matrix(const Scalar& x, const Scalar& y, const Scalar& z, const Scalar& w)
|
||||
{
|
||||
EIGEN_STATIC_ASSERT_VECTOR_SPECIFIC_SIZE(Matrix, 4);
|
||||
EIGEN_STATIC_ASSERT_VECTOR_SPECIFIC_SIZE(Matrix, 4)
|
||||
m_storage.data()[0] = x;
|
||||
m_storage.data()[1] = y;
|
||||
m_storage.data()[2] = z;
|
||||
@@ -349,7 +429,7 @@ class Matrix
|
||||
/** Override MatrixBase::eval() since matrices don't need to be evaluated, it is enough to just read them.
|
||||
* This prevents a useless copy when doing e.g. "m1 = m2.eval()"
|
||||
*/
|
||||
const Matrix& eval() const
|
||||
inline const Matrix& eval() const
|
||||
{
|
||||
return *this;
|
||||
}
|
||||
@@ -357,7 +437,7 @@ class Matrix
|
||||
/** Override MatrixBase::swap() since for dynamic-sized matrices of same type it is enough to swap the
|
||||
* data pointers.
|
||||
*/
|
||||
void swap(Matrix& other)
|
||||
inline void swap(Matrix& other)
|
||||
{
|
||||
if (Base::SizeAtCompileTime==Dynamic)
|
||||
m_storage.swap(other.m_storage);
|
||||
@@ -365,12 +445,52 @@ class Matrix
|
||||
this->Base::swap(other);
|
||||
}
|
||||
|
||||
/** \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
|
||||
*/
|
||||
//@{
|
||||
inline static const UnalignedMapType Map(const Scalar* data)
|
||||
{ return UnalignedMapType(data); }
|
||||
inline static UnalignedMapType Map(Scalar* data)
|
||||
{ return UnalignedMapType(data); }
|
||||
inline static const UnalignedMapType Map(const Scalar* data, int size)
|
||||
{ return UnalignedMapType(data, size); }
|
||||
inline static UnalignedMapType Map(Scalar* data, int size)
|
||||
{ return UnalignedMapType(data, size); }
|
||||
inline static const UnalignedMapType Map(const Scalar* data, int rows, int cols)
|
||||
{ return UnalignedMapType(data, rows, cols); }
|
||||
inline static UnalignedMapType Map(Scalar* data, int rows, int cols)
|
||||
{ return UnalignedMapType(data, rows, cols); }
|
||||
|
||||
inline static const AlignedMapType MapAligned(const Scalar* data)
|
||||
{ return AlignedMapType(data); }
|
||||
inline static AlignedMapType MapAligned(Scalar* data)
|
||||
{ return AlignedMapType(data); }
|
||||
inline static const AlignedMapType MapAligned(const Scalar* data, int size)
|
||||
{ return AlignedMapType(data, size); }
|
||||
inline static AlignedMapType MapAligned(Scalar* data, int size)
|
||||
{ return AlignedMapType(data, size); }
|
||||
inline static const AlignedMapType MapAligned(const Scalar* data, int rows, int cols)
|
||||
{ return AlignedMapType(data, rows, cols); }
|
||||
inline static AlignedMapType MapAligned(Scalar* data, int rows, int cols)
|
||||
{ return AlignedMapType(data, rows, cols); }
|
||||
//@}
|
||||
|
||||
/////////// Geometry module ///////////
|
||||
|
||||
template<typename OtherDerived>
|
||||
explicit Matrix(const RotationBase<OtherDerived,ColsAtCompileTime>& r);
|
||||
template<typename OtherDerived>
|
||||
Matrix& operator=(const RotationBase<OtherDerived,ColsAtCompileTime>& r);
|
||||
|
||||
// allow to extend Matrix outside Eigen
|
||||
#ifdef EIGEN_MATRIX_PLUGIN
|
||||
#include EIGEN_MATRIX_PLUGIN
|
||||
#endif
|
||||
};
|
||||
|
||||
/** \defgroup matrixtypedefs Global matrix typedefs
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
// This file is part of Eigen, a lightweight C++ template library
|
||||
// for linear algebra. Eigen itself is part of the KDE project.
|
||||
//
|
||||
// Copyright (C) 2006-2008 Benoit Jacob <jacob@math.jussieu.fr>
|
||||
// Copyright (C) 2006-2008 Benoit Jacob <jacob.benoit.1@gmail.com>
|
||||
// Copyright (C) 2008 Gael Guennebaud <g.gael@free.fr>
|
||||
//
|
||||
// Eigen is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU Lesser General Public
|
||||
@@ -55,10 +56,12 @@ template<typename Derived> class MatrixBase
|
||||
{
|
||||
public:
|
||||
|
||||
#ifndef EIGEN_PARSED_BY_DOXYGEN
|
||||
class InnerIterator;
|
||||
|
||||
typedef typename ei_traits<Derived>::Scalar Scalar;
|
||||
typedef typename ei_packet_traits<Scalar>::type PacketScalar;
|
||||
#endif // not EIGEN_PARSED_BY_DOXYGEN
|
||||
|
||||
enum {
|
||||
|
||||
@@ -139,6 +142,7 @@ template<typename Derived> class MatrixBase
|
||||
ei_assert(ei_are_flags_consistent<Flags>::ret);
|
||||
}
|
||||
|
||||
#ifndef EIGEN_PARSED_BY_DOXYGEN
|
||||
/** This is the "real scalar" type; if the \a Scalar type is already real numbers
|
||||
* (e.g. int, float or double) then \a RealScalar is just the same as \a Scalar. If
|
||||
* \a Scalar is \a std::complex<T> then RealScalar is \a T.
|
||||
@@ -150,6 +154,7 @@ template<typename Derived> class MatrixBase
|
||||
/** type of the equivalent square matrix */
|
||||
typedef Matrix<Scalar,EIGEN_ENUM_MAX(RowsAtCompileTime,ColsAtCompileTime),
|
||||
EIGEN_ENUM_MAX(RowsAtCompileTime,ColsAtCompileTime)> SquareMatrixType;
|
||||
#endif // not EIGEN_PARSED_BY_DOXYGEN
|
||||
|
||||
/** \returns the number of rows. \sa cols(), RowsAtCompileTime */
|
||||
inline int rows() const { return derived().rows(); }
|
||||
@@ -173,6 +178,7 @@ template<typename Derived> class MatrixBase
|
||||
* i.e., the number of rows for a columns major matrix, and the number of cols otherwise */
|
||||
int innerSize() const { return (int(Flags)&RowMajorBit) ? this->cols() : this->rows(); }
|
||||
|
||||
#ifndef EIGEN_PARSED_BY_DOXYGEN
|
||||
/** \internal the type to which the expression gets evaluated (needed by MSVC) */
|
||||
typedef typename ei_eval<Derived>::type EvalType;
|
||||
/** \internal Represents a constant matrix */
|
||||
@@ -188,8 +194,10 @@ template<typename Derived> class MatrixBase
|
||||
>::ret ConjugateReturnType;
|
||||
/** \internal the return type of MatrixBase::real() */
|
||||
typedef CwiseUnaryOp<ei_scalar_real_op<Scalar>, Derived> RealReturnType;
|
||||
/** \internal the return type of MatrixBase::imag() */
|
||||
typedef CwiseUnaryOp<ei_scalar_imag_op<Scalar>, Derived> ImagReturnType;
|
||||
/** \internal the return type of MatrixBase::adjoint() */
|
||||
typedef Transpose<NestByValue<typename ei_cleantype<ConjugateReturnType>::type> >
|
||||
typedef Eigen::Transpose<NestByValue<typename ei_cleantype<ConjugateReturnType>::type> >
|
||||
AdjointReturnType;
|
||||
/** \internal the return type of MatrixBase::eigenvalues() */
|
||||
typedef Matrix<typename NumTraits<typename ei_traits<Derived>::Scalar>::Real, ei_traits<Derived>::ColsAtCompileTime, 1> EigenvaluesReturnType;
|
||||
@@ -203,6 +211,7 @@ template<typename Derived> class MatrixBase
|
||||
typedef Block<CwiseNullaryOp<ei_scalar_identity_op<Scalar>, SquareMatrixType>,
|
||||
ei_traits<Derived>::RowsAtCompileTime,
|
||||
ei_traits<Derived>::ColsAtCompileTime> BasisReturnType;
|
||||
#endif // not EIGEN_PARSED_BY_DOXYGEN
|
||||
|
||||
|
||||
/** Copies \a other into *this. \returns a reference to *this. */
|
||||
@@ -253,6 +262,7 @@ template<typename Derived> class MatrixBase
|
||||
Scalar& operator[](int index);
|
||||
Scalar& operator()(int index);
|
||||
|
||||
#ifndef EIGEN_PARSED_BY_DOXYGEN
|
||||
template<typename OtherDerived>
|
||||
void copyCoeff(int row, int col, const MatrixBase<OtherDerived>& other);
|
||||
template<typename OtherDerived>
|
||||
@@ -261,6 +271,7 @@ template<typename Derived> class MatrixBase
|
||||
void copyPacket(int row, int col, const MatrixBase<OtherDerived>& other);
|
||||
template<typename OtherDerived, int StoreMode, int LoadMode>
|
||||
void copyPacket(int index, const MatrixBase<OtherDerived>& other);
|
||||
#endif // not EIGEN_PARSED_BY_DOXYGEN
|
||||
|
||||
template<int LoadMode>
|
||||
PacketScalar packet(int row, int col) const;
|
||||
@@ -320,7 +331,8 @@ template<typename Derived> class MatrixBase
|
||||
Derived& operator*=(const MatrixBase<OtherDerived>& other);
|
||||
|
||||
template<typename OtherDerived>
|
||||
typename OtherDerived::Eval solveTriangular(const MatrixBase<OtherDerived>& other) const;
|
||||
typename ei_eval_to_column_major<OtherDerived>::type
|
||||
solveTriangular(const MatrixBase<OtherDerived>& other) const;
|
||||
|
||||
template<typename OtherDerived>
|
||||
void solveTriangularInPlace(MatrixBase<OtherDerived>& other) const;
|
||||
@@ -328,13 +340,15 @@ template<typename Derived> class MatrixBase
|
||||
|
||||
template<typename OtherDerived>
|
||||
Scalar dot(const MatrixBase<OtherDerived>& other) const;
|
||||
RealScalar squaredNorm() const;
|
||||
RealScalar norm2() const;
|
||||
RealScalar norm() const;
|
||||
const EvalType normalized() const;
|
||||
void normalize();
|
||||
|
||||
Transpose<Derived> transpose();
|
||||
const Transpose<Derived> transpose() const;
|
||||
Eigen::Transpose<Derived> transpose();
|
||||
const Eigen::Transpose<Derived> transpose() const;
|
||||
void transposeInPlace();
|
||||
const AdjointReturnType adjoint() const;
|
||||
|
||||
|
||||
@@ -351,8 +365,8 @@ template<typename Derived> class MatrixBase
|
||||
const typename BlockReturnType<Derived>::Type
|
||||
block(int startRow, int startCol, int blockRows, int blockCols) const;
|
||||
|
||||
typename BlockReturnType<Derived>::SubVectorType block(int start, int size);
|
||||
const typename BlockReturnType<Derived>::SubVectorType block(int start, int size) const;
|
||||
typename BlockReturnType<Derived>::SubVectorType segment(int start, int size);
|
||||
const typename BlockReturnType<Derived>::SubVectorType segment(int start, int size) const;
|
||||
|
||||
typename BlockReturnType<Derived,Dynamic>::SubVectorType start(int size);
|
||||
const typename BlockReturnType<Derived,Dynamic>::SubVectorType start(int size) const;
|
||||
@@ -379,8 +393,8 @@ template<typename Derived> class MatrixBase
|
||||
template<int Size> typename BlockReturnType<Derived,Size>::SubVectorType end();
|
||||
template<int Size> const typename BlockReturnType<Derived,Size>::SubVectorType end() const;
|
||||
|
||||
template<int Size> typename BlockReturnType<Derived,Size>::SubVectorType block(int start);
|
||||
template<int Size> const typename BlockReturnType<Derived,Size>::SubVectorType block(int start) const;
|
||||
template<int Size> typename BlockReturnType<Derived,Size>::SubVectorType segment(int start);
|
||||
template<int Size> const typename BlockReturnType<Derived,Size>::SubVectorType segment(int start) const;
|
||||
|
||||
DiagonalCoeffs<Derived> diagonal();
|
||||
const DiagonalCoeffs<Derived> diagonal() const;
|
||||
@@ -492,6 +506,7 @@ template<typename Derived> class MatrixBase
|
||||
|
||||
ConjugateReturnType conjugate() const;
|
||||
const RealReturnType real() const;
|
||||
const ImagReturnType imag() const;
|
||||
|
||||
template<typename CustomUnaryOp>
|
||||
const CwiseUnaryOp<CustomUnaryOp, Derived> unaryExpr(const CustomUnaryOp& func = CustomUnaryOp()) const;
|
||||
@@ -517,11 +532,12 @@ template<typename Derived> class MatrixBase
|
||||
template<typename Visitor>
|
||||
void visit(Visitor& func) const;
|
||||
|
||||
|
||||
#ifndef EIGEN_PARSED_BY_DOXYGEN
|
||||
inline const Derived& derived() const { return *static_cast<const Derived*>(this); }
|
||||
inline Derived& derived() { return *static_cast<Derived*>(this); }
|
||||
inline Derived& const_cast_derived() const
|
||||
{ return *static_cast<Derived*>(const_cast<MatrixBase*>(this)); }
|
||||
#endif // not EIGEN_PARSED_BY_DOXYGEN
|
||||
|
||||
const Cwise<Derived> cwise() const;
|
||||
Cwise<Derived> cwise();
|
||||
@@ -544,15 +560,17 @@ template<typename Derived> class MatrixBase
|
||||
const Select<Derived,ThenDerived,ElseDerived>
|
||||
select(const MatrixBase<ThenDerived>& thenMatrix,
|
||||
const MatrixBase<ElseDerived>& elseMatrix) const;
|
||||
|
||||
|
||||
template<typename ThenDerived>
|
||||
inline const Select<Derived,ThenDerived, NestByValue<typename ThenDerived::ConstantReturnType> >
|
||||
select(const MatrixBase<ThenDerived>& thenMatrix, typename ThenDerived::Scalar elseScalar) const;
|
||||
|
||||
|
||||
template<typename ElseDerived>
|
||||
inline const Select<Derived, NestByValue<typename ElseDerived::ConstantReturnType>, ElseDerived >
|
||||
select(typename ElseDerived::Scalar thenScalar, const MatrixBase<ElseDerived>& elseMatrix) const;
|
||||
|
||||
template<int p> RealScalar lpNorm() const;
|
||||
|
||||
/////////// LU module ///////////
|
||||
|
||||
const LU<EvalType> lu() const;
|
||||
@@ -562,6 +580,9 @@ template<typename Derived> class MatrixBase
|
||||
|
||||
/////////// Cholesky module ///////////
|
||||
|
||||
const LLT<EvalType> llt() const;
|
||||
const LDLT<EvalType> ldlt() const;
|
||||
// deprecated:
|
||||
const Cholesky<EvalType> cholesky() const;
|
||||
const CholeskyWithoutSquareRoot<EvalType> choleskyNoSqrt() const;
|
||||
|
||||
@@ -581,7 +602,8 @@ template<typename Derived> class MatrixBase
|
||||
template<typename OtherDerived>
|
||||
EvalType cross(const MatrixBase<OtherDerived>& other) const;
|
||||
EvalType unitOrthogonal(void) const;
|
||||
|
||||
Matrix<Scalar,3,1> eulerAngles(int a0, int a1, int a2) const;
|
||||
|
||||
#ifdef EIGEN_MATRIXBASE_PLUGIN
|
||||
#include EIGEN_MATRIXBASE_PLUGIN
|
||||
#endif
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
// for linear algebra. Eigen itself is part of the KDE project.
|
||||
//
|
||||
// Copyright (C) 2008 Gael Guennebaud <g.gael@free.fr>
|
||||
// Copyright (C) 2006-2008 Benoit Jacob <jacob@math.jussieu.fr>
|
||||
// Copyright (C) 2006-2008 Benoit Jacob <jacob.benoit.1@gmail.com>
|
||||
//
|
||||
// Eigen is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU Lesser General Public
|
||||
@@ -44,7 +44,7 @@ template<typename T, int Size, int _Rows, int _Cols> class ei_matrix_storage
|
||||
{
|
||||
ei_aligned_array<T,Size,((Size*sizeof(T))%16)==0> m_data;
|
||||
public:
|
||||
inline ei_matrix_storage() {}
|
||||
inline explicit ei_matrix_storage() {}
|
||||
inline ei_matrix_storage(int,int,int) {}
|
||||
inline void swap(ei_matrix_storage& other) { std::swap(m_data,other.m_data); }
|
||||
inline static int rows(void) {return _Rows;}
|
||||
@@ -61,6 +61,7 @@ template<typename T, int Size> class ei_matrix_storage<T, Size, Dynamic, Dynamic
|
||||
int m_rows;
|
||||
int m_cols;
|
||||
public:
|
||||
inline explicit ei_matrix_storage() : m_rows(0), m_cols(0) {}
|
||||
inline ei_matrix_storage(int, int rows, int cols) : m_rows(rows), m_cols(cols) {}
|
||||
inline ~ei_matrix_storage() {}
|
||||
inline void swap(ei_matrix_storage& other)
|
||||
@@ -82,6 +83,7 @@ template<typename T, int Size, int _Cols> class ei_matrix_storage<T, Size, Dynam
|
||||
ei_aligned_array<T,Size,((Size*sizeof(T))%16)==0> m_data;
|
||||
int m_rows;
|
||||
public:
|
||||
inline explicit ei_matrix_storage() : m_rows(0) {}
|
||||
inline ei_matrix_storage(int, int rows, int) : m_rows(rows) {}
|
||||
inline ~ei_matrix_storage() {}
|
||||
inline void swap(ei_matrix_storage& other) { std::swap(m_data,other.m_data); std::swap(m_rows,other.m_rows); }
|
||||
@@ -101,6 +103,7 @@ template<typename T, int Size, int _Rows> class ei_matrix_storage<T, Size, _Rows
|
||||
ei_aligned_array<T,Size,((Size*sizeof(T))%16)==0> m_data;
|
||||
int m_cols;
|
||||
public:
|
||||
inline explicit ei_matrix_storage() : m_cols(0) {}
|
||||
inline ei_matrix_storage(int, int, int cols) : m_cols(cols) {}
|
||||
inline ~ei_matrix_storage() {}
|
||||
inline void swap(ei_matrix_storage& other) { std::swap(m_data,other.m_data); std::swap(m_cols,other.m_cols); }
|
||||
@@ -121,6 +124,7 @@ template<typename T> class ei_matrix_storage<T, Dynamic, Dynamic, Dynamic>
|
||||
int m_rows;
|
||||
int m_cols;
|
||||
public:
|
||||
inline explicit ei_matrix_storage() : m_data(0), m_rows(0), m_cols(0) {}
|
||||
inline ei_matrix_storage(int size, int rows, int cols)
|
||||
: m_data(ei_aligned_malloc<T>(size)), m_rows(rows), m_cols(cols) {}
|
||||
inline ~ei_matrix_storage() { ei_aligned_free(m_data); }
|
||||
@@ -148,6 +152,7 @@ template<typename T, int _Rows> class ei_matrix_storage<T, Dynamic, _Rows, Dynam
|
||||
T *m_data;
|
||||
int m_cols;
|
||||
public:
|
||||
inline explicit ei_matrix_storage() : m_data(0), m_cols(0) {}
|
||||
inline ei_matrix_storage(int size, int, int cols) : m_data(ei_aligned_malloc<T>(size)), m_cols(cols) {}
|
||||
inline ~ei_matrix_storage() { ei_aligned_free(m_data); }
|
||||
inline void swap(ei_matrix_storage& other) { std::swap(m_data,other.m_data); std::swap(m_cols,other.m_cols); }
|
||||
@@ -172,6 +177,7 @@ template<typename T, int _Cols> class ei_matrix_storage<T, Dynamic, Dynamic, _Co
|
||||
T *m_data;
|
||||
int m_rows;
|
||||
public:
|
||||
inline explicit ei_matrix_storage() : m_data(0), m_rows(0) {}
|
||||
inline ei_matrix_storage(int size, int rows, int) : m_data(ei_aligned_malloc<T>(size)), m_rows(rows) {}
|
||||
inline ~ei_matrix_storage() { ei_aligned_free(m_data); }
|
||||
inline void swap(ei_matrix_storage& other) { std::swap(m_data,other.m_data); std::swap(m_rows,other.m_rows); }
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
// This file is part of Eigen, a lightweight C++ template library
|
||||
// for linear algebra. Eigen itself is part of the KDE project.
|
||||
//
|
||||
// Copyright (C) 2006-2008 Benoit Jacob <jacob@math.jussieu.fr>
|
||||
// Copyright (C) 2006-2008 Benoit Jacob <jacob.benoit.1@gmail.com>
|
||||
//
|
||||
// Eigen is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU Lesser General Public
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
// for linear algebra. Eigen itself is part of the KDE project.
|
||||
//
|
||||
// Copyright (C) 2008 Gael Guennebaud <g.gael@free.fr>
|
||||
// Copyright (C) 2006-2008 Benoit Jacob <jacob@math.jussieu.fr>
|
||||
// Copyright (C) 2006-2008 Benoit Jacob <jacob.benoit.1@gmail.com>
|
||||
//
|
||||
// Eigen is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU Lesser General Public
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
// This file is part of Eigen, a lightweight C++ template library
|
||||
// for linear algebra. Eigen itself is part of the KDE project.
|
||||
//
|
||||
// Copyright (C) 2006-2008 Benoit Jacob <jacob@math.jussieu.fr>
|
||||
// Copyright (C) 2006-2008 Benoit Jacob <jacob.benoit.1@gmail.com>
|
||||
//
|
||||
// Eigen is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU Lesser General Public
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
// This file is part of Eigen, a lightweight C++ template library
|
||||
// for linear algebra. Eigen itself is part of the KDE project.
|
||||
//
|
||||
// Copyright (C) 2008 Benoit Jacob <jacob@math.jussieu.fr>
|
||||
// Copyright (C) 2008 Benoit Jacob <jacob.benoit.1@gmail.com>
|
||||
// Copyright (C) 2008 Gael Guennebaud <g.gael@free.fr>
|
||||
//
|
||||
// Eigen is free software; you can redistribute it and/or
|
||||
@@ -88,8 +88,10 @@ template<typename MatrixType, unsigned int Mode> class Part
|
||||
|
||||
inline Scalar coeff(int row, int col) const
|
||||
{
|
||||
// SelfAdjointBit doesn't play any role here: just because a matrix is selfadjoint doesn't say anything about
|
||||
// each individual coefficient, except for the not-very-useful-here fact that diagonal coefficients are real.
|
||||
if( ((Flags & LowerTriangularBit) && (col>row)) || ((Flags & UpperTriangularBit) && (row>col)) )
|
||||
return (Flags & SelfAdjointBit) ? ei_conj(m_matrix.coeff(col, row)) : (Scalar)0;
|
||||
return (Scalar)0;
|
||||
if(Flags & UnitDiagBit)
|
||||
return col==row ? (Scalar)1 : m_matrix.coeff(row, col);
|
||||
else if(Flags & ZeroDiagBit)
|
||||
@@ -100,8 +102,8 @@ template<typename MatrixType, unsigned int Mode> class Part
|
||||
|
||||
inline Scalar& coeffRef(int row, int col)
|
||||
{
|
||||
EIGEN_STATIC_ASSERT(!(Flags & UnitDiagBit), writting_to_triangular_part_with_unit_diag_is_not_supported);
|
||||
EIGEN_STATIC_ASSERT(!(Flags & SelfAdjointBit), default_writting_to_selfadjoint_not_supported);
|
||||
EIGEN_STATIC_ASSERT(!(Flags & UnitDiagBit), writing_to_triangular_part_with_unit_diagonal_is_not_supported)
|
||||
EIGEN_STATIC_ASSERT(!(Flags & SelfAdjointBit), coefficient_write_access_to_selfadjoint_not_supported)
|
||||
ei_assert( (Mode==Upper && col>=row)
|
||||
|| (Mode==Lower && col<=row)
|
||||
|| (Mode==StrictlyUpper && col>row)
|
||||
@@ -119,6 +121,12 @@ template<typename MatrixType, unsigned int Mode> class Part
|
||||
const Block<Part, RowsAtCompileTime, 1> col(int i) { return Base::col(i); }
|
||||
const Block<Part, RowsAtCompileTime, 1> col(int i) const { return Base::col(i); }
|
||||
|
||||
template<typename OtherDerived/*, int OtherMode*/>
|
||||
void swap(const MatrixBase<OtherDerived>& other)
|
||||
{
|
||||
Part<SwapWrapper<MatrixType>,Mode>(SwapWrapper<MatrixType>(const_cast<MatrixType&>(m_matrix))).lazyAssign(other.derived());
|
||||
}
|
||||
|
||||
protected:
|
||||
|
||||
const typename MatrixType::Nested m_matrix;
|
||||
@@ -184,7 +192,7 @@ struct ei_part_assignment_impl
|
||||
|| (Mode == Lower && row >= col)
|
||||
|| (Mode == StrictlyUpper && row < col)
|
||||
|| (Mode == StrictlyLower && row > col))
|
||||
dst.coeffRef(row, col) = src.coeff(row, col);
|
||||
dst.copyCoeff(row, col, src);
|
||||
}
|
||||
}
|
||||
};
|
||||
@@ -195,7 +203,7 @@ struct ei_part_assignment_impl<Derived1, Derived2, Mode, 1>
|
||||
inline static void run(Derived1 &dst, const Derived2 &src)
|
||||
{
|
||||
if(!(Mode & ZeroDiagBit))
|
||||
dst.coeffRef(0, 0) = src.coeff(0, 0);
|
||||
dst.copyCoeff(0, 0, src);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -213,7 +221,7 @@ struct ei_part_assignment_impl<Derived1, Derived2, Upper, Dynamic>
|
||||
{
|
||||
for(int j = 0; j < dst.cols(); j++)
|
||||
for(int i = 0; i <= j; i++)
|
||||
dst.coeffRef(i, j) = src.coeff(i, j);
|
||||
dst.copyCoeff(i, j, src);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -224,7 +232,7 @@ struct ei_part_assignment_impl<Derived1, Derived2, Lower, Dynamic>
|
||||
{
|
||||
for(int j = 0; j < dst.cols(); j++)
|
||||
for(int i = j; i < dst.rows(); i++)
|
||||
dst.coeffRef(i, j) = src.coeff(i, j);
|
||||
dst.copyCoeff(i, j, src);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -235,7 +243,7 @@ struct ei_part_assignment_impl<Derived1, Derived2, StrictlyUpper, Dynamic>
|
||||
{
|
||||
for(int j = 0; j < dst.cols(); j++)
|
||||
for(int i = 0; i < j; i++)
|
||||
dst.coeffRef(i, j) = src.coeff(i, j);
|
||||
dst.copyCoeff(i, j, src);
|
||||
}
|
||||
};
|
||||
template<typename Derived1, typename Derived2>
|
||||
@@ -245,7 +253,7 @@ struct ei_part_assignment_impl<Derived1, Derived2, StrictlyLower, Dynamic>
|
||||
{
|
||||
for(int j = 0; j < dst.cols(); j++)
|
||||
for(int i = j+1; i < dst.rows(); i++)
|
||||
dst.coeffRef(i, j) = src.coeff(i, j);
|
||||
dst.copyCoeff(i, j, src);
|
||||
}
|
||||
};
|
||||
template<typename Derived1, typename Derived2>
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
// This file is part of Eigen, a lightweight C++ template library
|
||||
// for linear algebra. Eigen itself is part of the KDE project.
|
||||
//
|
||||
// Copyright (C) 2006-2008 Benoit Jacob <jacob@math.jussieu.fr>
|
||||
// Copyright (C) 2006-2008 Benoit Jacob <jacob.benoit.1@gmail.com>
|
||||
// Copyright (C) 2008 Gael Guennebaud <g.gael@free.fr>
|
||||
//
|
||||
// Eigen is free software; you can redistribute it and/or
|
||||
@@ -36,8 +36,6 @@ struct ei_product_coeff_impl;
|
||||
template<int StorageOrder, int Index, typename Lhs, typename Rhs, typename PacketScalar, int LoadMode>
|
||||
struct ei_product_packet_impl;
|
||||
|
||||
template<typename T> struct ei_product_eval_to_column_major;
|
||||
|
||||
/** \class ProductReturnType
|
||||
*
|
||||
* \brief Helper class to get the correct and optimized returned type of operator*
|
||||
@@ -70,7 +68,7 @@ struct ProductReturnType<Lhs,Rhs,CacheFriendlyProduct>
|
||||
typedef typename ei_nested<Lhs,Rhs::ColsAtCompileTime>::type LhsNested;
|
||||
|
||||
typedef typename ei_nested<Rhs,Lhs::RowsAtCompileTime,
|
||||
typename ei_product_eval_to_column_major<Rhs>::type
|
||||
typename ei_eval_to_column_major<Rhs>::type
|
||||
>::type RhsNested;
|
||||
|
||||
typedef Product<LhsNested, RhsNested, CacheFriendlyProduct> Type;
|
||||
@@ -118,8 +116,8 @@ template<typename LhsNested, typename RhsNested, int ProductMode>
|
||||
struct ei_traits<Product<LhsNested, RhsNested, ProductMode> >
|
||||
{
|
||||
// clean the nested types:
|
||||
typedef typename ei_unconst<typename ei_unref<LhsNested>::type>::type _LhsNested;
|
||||
typedef typename ei_unconst<typename ei_unref<RhsNested>::type>::type _RhsNested;
|
||||
typedef typename ei_cleantype<LhsNested>::type _LhsNested;
|
||||
typedef typename ei_cleantype<RhsNested>::type _RhsNested;
|
||||
typedef typename _LhsNested::Scalar Scalar;
|
||||
|
||||
enum {
|
||||
@@ -196,7 +194,13 @@ template<typename LhsNested, typename RhsNested, int ProductMode> class Product
|
||||
inline Product(const Lhs& lhs, const Rhs& rhs)
|
||||
: m_lhs(lhs), m_rhs(rhs)
|
||||
{
|
||||
ei_assert(lhs.cols() == rhs.rows());
|
||||
// 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((ei_is_same_type<typename Lhs::RealScalar, typename Rhs::RealScalar>::ret),
|
||||
you_mixed_different_numeric_types__you_need_to_use_the_cast_method_of_MatrixBase_to_cast_numeric_types_explicitly)
|
||||
ei_assert(lhs.cols() == rhs.rows()
|
||||
&& "invalid matrix product"
|
||||
&& "if you wanted a coeff-wise or a dot product use the respective explicit functions");
|
||||
}
|
||||
|
||||
/** \internal
|
||||
@@ -267,6 +271,21 @@ template<typename OtherDerived>
|
||||
inline const typename ProductReturnType<Derived,OtherDerived>::Type
|
||||
MatrixBase<Derived>::operator*(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.cwise()*v2
|
||||
EIGEN_STATIC_ASSERT(ProductIsValid || !(AreVectors && SameSizes),
|
||||
invalid_vector_vector_product__if_you_wanted_a_dot_or_coeff_wise_product_you_must_use_the_explicit_functions)
|
||||
EIGEN_STATIC_ASSERT(ProductIsValid || !(SameSizes && !AreVectors),
|
||||
invalid_matrix_product__if_you_wanted_a_coeff_wise_product_you_must_use_the_explicit_function)
|
||||
EIGEN_STATIC_ASSERT(ProductIsValid || SameSizes, invalid_matrix_product)
|
||||
return typename ProductReturnType<Derived,OtherDerived>::Type(derived(), other.derived());
|
||||
}
|
||||
|
||||
@@ -314,6 +333,7 @@ struct ei_product_coeff_impl<NoVectorization, Dynamic, Lhs, Rhs>
|
||||
{
|
||||
inline static void run(int row, int col, const Lhs& lhs, const Rhs& rhs, typename Lhs::Scalar& res)
|
||||
{
|
||||
ei_assert(lhs.cols()>0 && "you are using a non initialized matrix");
|
||||
res = lhs.coeff(row, 0) * rhs.coeff(0, col);
|
||||
for(int i = 1; i < lhs.cols(); i++)
|
||||
res += lhs.coeff(row, i) * rhs.coeff(i, col);
|
||||
@@ -471,6 +491,7 @@ struct ei_product_packet_impl<RowMajor, Dynamic, Lhs, Rhs, PacketScalar, LoadMod
|
||||
{
|
||||
inline static void run(int row, int col, const Lhs& lhs, const Rhs& rhs, PacketScalar& res)
|
||||
{
|
||||
ei_assert(lhs.cols()>0 && "you are using a non initialized matrix");
|
||||
res = ei_pmul(ei_pset1(lhs.coeff(row, 0)),rhs.template packet<LoadMode>(0, col));
|
||||
for(int i = 1; i < lhs.cols(); i++)
|
||||
res = ei_pmadd(ei_pset1(lhs.coeff(row, i)), rhs.template packet<LoadMode>(i, col), res);
|
||||
@@ -482,6 +503,7 @@ struct ei_product_packet_impl<ColMajor, Dynamic, Lhs, Rhs, PacketScalar, LoadMod
|
||||
{
|
||||
inline static void run(int row, int col, const Lhs& lhs, const Rhs& rhs, PacketScalar& res)
|
||||
{
|
||||
ei_assert(lhs.cols()>0 && "you are using a non initialized matrix");
|
||||
res = ei_pmul(lhs.template packet<LoadMode>(row, 0), ei_pset1(rhs.coeff(0, col)));
|
||||
for(int i = 1; i < lhs.cols(); i++)
|
||||
res = ei_pmadd(lhs.template packet<LoadMode>(row, i), ei_pset1(rhs.coeff(i, col)), res);
|
||||
@@ -706,23 +728,12 @@ inline Derived& MatrixBase<Derived>::lazyAssign(const Product<Lhs,Rhs,CacheFrien
|
||||
return derived();
|
||||
}
|
||||
|
||||
template<typename T> struct ei_product_eval_to_column_major
|
||||
{
|
||||
typedef Matrix<typename ei_traits<T>::Scalar,
|
||||
ei_traits<T>::RowsAtCompileTime,
|
||||
ei_traits<T>::ColsAtCompileTime,
|
||||
ColMajor,
|
||||
ei_traits<T>::MaxRowsAtCompileTime,
|
||||
ei_traits<T>::MaxColsAtCompileTime
|
||||
> type;
|
||||
};
|
||||
|
||||
template<typename T> struct ei_product_copy_rhs
|
||||
{
|
||||
typedef typename ei_meta_if<
|
||||
(ei_traits<T>::Flags & RowMajorBit)
|
||||
|| (!(ei_traits<T>::Flags & DirectAccessBit)),
|
||||
typename ei_product_eval_to_column_major<T>::type,
|
||||
typename ei_eval_to_column_major<T>::type,
|
||||
const T&
|
||||
>::ret type;
|
||||
};
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
// for linear algebra. Eigen itself is part of the KDE project.
|
||||
//
|
||||
// Copyright (C) 2008 Gael Guennebaud <g.gael@free.fr>
|
||||
// Copyright (C) 2006-2008 Benoit Jacob <jacob@math.jussieu.fr>
|
||||
// Copyright (C) 2006-2008 Benoit Jacob <jacob.benoit.1@gmail.com>
|
||||
//
|
||||
// Eigen is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU Lesser General Public
|
||||
@@ -65,6 +65,7 @@ struct ei_redux_impl<BinaryOp, Derived, Start, Dynamic>
|
||||
typedef typename ei_result_of<BinaryOp(typename Derived::Scalar)>::type Scalar;
|
||||
static Scalar run(const Derived& mat, const BinaryOp& func)
|
||||
{
|
||||
ei_assert(mat.rows()>0 && mat.cols()>0 && "you are using a non initialized matrix");
|
||||
Scalar res;
|
||||
res = mat.coeff(0,0);
|
||||
for(int i = 1; i < mat.rows(); i++)
|
||||
|
||||
44
Eigen/src/Core/SolveTriangular.h
Executable file → Normal file
44
Eigen/src/Core/SolveTriangular.h
Executable file → Normal file
@@ -88,12 +88,12 @@ struct ei_solve_triangular_selector<Lhs,Rhs,UpLo,RowMajor|IsDense>
|
||||
other.coeffRef(i,c) = tmp/lhs.coeff(i,i);
|
||||
}
|
||||
|
||||
// now let process the remaining rows 4 at once
|
||||
// now let's process the remaining rows 4 at once
|
||||
for(int i=blockyStart; IsLower ? i<size : i>0; )
|
||||
{
|
||||
int startBlock = i;
|
||||
int endBlock = startBlock + (IsLower ? 4 : -4);
|
||||
|
||||
|
||||
/* Process the i cols times 4 rows block, and keep the result in a temporary vector */
|
||||
// FIXME use fixed size block but take care to small fixed size matrices...
|
||||
Matrix<Scalar,Dynamic,1> btmp(4);
|
||||
@@ -101,7 +101,7 @@ struct ei_solve_triangular_selector<Lhs,Rhs,UpLo,RowMajor|IsDense>
|
||||
btmp = lhs.block(startBlock,0,4,i) * other.col(c).start(i);
|
||||
else
|
||||
btmp = lhs.block(i-3,i+1,4,size-1-i) * other.col(c).end(size-1-i);
|
||||
|
||||
|
||||
/* Let's process the 4x4 sub-matrix as usual.
|
||||
* btmp stores the diagonal coefficients used to update the remaining part of the result.
|
||||
*/
|
||||
@@ -119,8 +119,8 @@ struct ei_solve_triangular_selector<Lhs,Rhs,UpLo,RowMajor|IsDense>
|
||||
int remainingSize = IsLower ? i-startBlock : startBlock-i;
|
||||
Scalar tmp = other.coeff(i,c)
|
||||
- btmp.coeff(IsLower ? remainingSize : 3-remainingSize)
|
||||
- ( lhs.row(i).block(IsLower ? startBlock : i+1, remainingSize)
|
||||
* other.col(c).block(IsLower ? startBlock : i+1, remainingSize)).coeff(0,0);
|
||||
- ( lhs.row(i).segment(IsLower ? startBlock : i+1, remainingSize)
|
||||
* other.col(c).segment(IsLower ? startBlock : i+1, remainingSize)).coeff(0,0);
|
||||
|
||||
if (Lhs::Flags & UnitDiagBit)
|
||||
other.coeffRef(i,c) = tmp;
|
||||
@@ -172,7 +172,7 @@ struct ei_solve_triangular_selector<Lhs,Rhs,UpLo,ColMajor|IsDense>
|
||||
other.coeffRef(i,c) /= lhs.coeff(i,i);
|
||||
int remainingSize = IsLower ? endBlock-i-1 : i-endBlock-1;
|
||||
if (remainingSize>0)
|
||||
other.col(c).block((IsLower ? i : endBlock) + 1, remainingSize) -=
|
||||
other.col(c).segment((IsLower ? i : endBlock) + 1, remainingSize) -=
|
||||
other.coeffRef(i,c)
|
||||
* Block<Lhs,Dynamic,1>(lhs, (IsLower ? i : endBlock) + 1, i, remainingSize, 1);
|
||||
btmp.coeffRef(IsLower ? i-startBlock : remainingSize) = -other.coeffRef(i,c);
|
||||
@@ -191,6 +191,12 @@ struct ei_solve_triangular_selector<Lhs,Rhs,UpLo,ColMajor|IsDense>
|
||||
&(lhs.const_cast_derived().coeffRef(IsLower ? endBlock : 0, IsLower ? startBlock : endBlock+1)),
|
||||
lhs.stride(),
|
||||
btmp, &(other.coeffRef(IsLower ? endBlock : 0, c)));
|
||||
// if (IsLower)
|
||||
// other.col(c).end(size-endBlock) += (lhs.block(endBlock, startBlock, size-endBlock, endBlock-startBlock)
|
||||
// * other.col(c).block(startBlock,endBlock-startBlock)).lazy();
|
||||
// else
|
||||
// other.col(c).end(size-endBlock) += (lhs.block(endBlock, startBlock, size-endBlock, endBlock-startBlock)
|
||||
// * other.col(c).block(startBlock,endBlock-startBlock)).lazy();
|
||||
}
|
||||
|
||||
/* Now we have to process the remaining part as usual */
|
||||
@@ -227,7 +233,16 @@ void MatrixBase<Derived>::solveTriangularInPlace(MatrixBase<OtherDerived>& other
|
||||
ei_assert(!(Flags & ZeroDiagBit));
|
||||
ei_assert(Flags & (UpperTriangularBit|LowerTriangularBit));
|
||||
|
||||
ei_solve_triangular_selector<Derived, OtherDerived>::run(derived(), other.derived());
|
||||
enum { copy = ei_traits<OtherDerived>::Flags & RowMajorBit };
|
||||
|
||||
typedef typename ei_meta_if<copy,
|
||||
typename ei_eval_to_column_major<OtherDerived>::type, OtherDerived&>::ret OtherCopy;
|
||||
OtherCopy otherCopy(other.derived());
|
||||
|
||||
ei_solve_triangular_selector<Derived, typename ei_unref<OtherCopy>::type>::run(derived(), otherCopy);
|
||||
|
||||
if (copy)
|
||||
other = otherCopy;
|
||||
}
|
||||
|
||||
/** \returns the product of the inverse of \c *this with \a other, \a *this being triangular.
|
||||
@@ -240,17 +255,17 @@ void MatrixBase<Derived>::solveTriangularInPlace(MatrixBase<OtherDerived>& other
|
||||
* It is required that \c *this be marked as either an upper or a lower triangular matrix, which
|
||||
* can be done by marked(), and that is automatically the case with expressions such as those returned
|
||||
* by extract().
|
||||
*
|
||||
*
|
||||
* \addexample SolveTriangular \label How to solve a triangular system (aka. how to multiply the inverse of a triangular matrix by another one)
|
||||
*
|
||||
*
|
||||
* Example: \include MatrixBase_marked.cpp
|
||||
* Output: \verbinclude MatrixBase_marked.out
|
||||
*
|
||||
*
|
||||
* This function is essentially a wrapper to the faster solveTriangularInPlace() function creating
|
||||
* a temporary copy of \a other, calling solveTriangularInPlace() on the copy and returning it.
|
||||
* Therefore, if \a other is not needed anymore, it is quite faster to call solveTriangularInPlace()
|
||||
* instead of solveTriangular().
|
||||
*
|
||||
*
|
||||
* For users coming from BLAS, this function (and more specifically solveTriangularInPlace()) offer
|
||||
* all the operations supported by the \c *TRSV and \c *TRSM BLAS routines.
|
||||
*
|
||||
@@ -258,14 +273,15 @@ void MatrixBase<Derived>::solveTriangularInPlace(MatrixBase<OtherDerived>& other
|
||||
* \code
|
||||
* M * T^1 <=> T.transpose().solveTriangularInPlace(M.transpose());
|
||||
* \endcode
|
||||
*
|
||||
*
|
||||
* \sa solveTriangularInPlace(), marked(), extract()
|
||||
*/
|
||||
template<typename Derived>
|
||||
template<typename OtherDerived>
|
||||
typename OtherDerived::Eval MatrixBase<Derived>::solveTriangular(const MatrixBase<OtherDerived>& other) const
|
||||
typename ei_eval_to_column_major<OtherDerived>::type
|
||||
MatrixBase<Derived>::solveTriangular(const MatrixBase<OtherDerived>& other) const
|
||||
{
|
||||
typename OtherDerived::Eval res(other);
|
||||
typename ei_eval_to_column_major<OtherDerived>::type res(other);
|
||||
solveTriangularInPlace(res);
|
||||
return res;
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
// for linear algebra. Eigen itself is part of the KDE project.
|
||||
//
|
||||
// Copyright (C) 2008 Gael Guennebaud <g.gael@free.fr>
|
||||
// Copyright (C) 2008 Benoit Jacob <jacob@math.jussieu.fr>
|
||||
// Copyright (C) 2008 Benoit Jacob <jacob.benoit.1@gmail.com>
|
||||
//
|
||||
// Eigen is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU Lesser General Public
|
||||
@@ -165,6 +165,7 @@ struct ei_sum_impl<Derived, NoVectorization, NoUnrolling>
|
||||
typedef typename Derived::Scalar Scalar;
|
||||
static Scalar run(const Derived& mat)
|
||||
{
|
||||
ei_assert(mat.rows()>0 && mat.cols()>0 && "you are using a non initialized matrix");
|
||||
Scalar res;
|
||||
res = mat.coeff(0, 0);
|
||||
for(int i = 1; i < mat.rows(); i++)
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
// This file is part of Eigen, a lightweight C++ template library
|
||||
// for linear algebra. Eigen itself is part of the KDE project.
|
||||
//
|
||||
// Copyright (C) 2006-2008 Benoit Jacob <jacob@math.jussieu.fr>
|
||||
// Copyright (C) 2006-2008 Benoit Jacob <jacob.benoit.1@gmail.com>
|
||||
//
|
||||
// Eigen is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU Lesser General Public
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
// This file is part of Eigen, a lightweight C++ template library
|
||||
// for linear algebra. Eigen itself is part of the KDE project.
|
||||
//
|
||||
// Copyright (C) 2006-2008 Benoit Jacob <jacob@math.jussieu.fr>
|
||||
// Copyright (C) 2006-2008 Benoit Jacob <jacob.benoit.1@gmail.com>
|
||||
//
|
||||
// Eigen is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU Lesser General Public
|
||||
@@ -156,4 +156,49 @@ MatrixBase<Derived>::adjoint() const
|
||||
return conjugate().nestByValue();
|
||||
}
|
||||
|
||||
/***************************************************************************
|
||||
* "in place" transpose implementation
|
||||
***************************************************************************/
|
||||
|
||||
template<typename MatrixType,
|
||||
bool IsSquare = (MatrixType::RowsAtCompileTime == MatrixType::ColsAtCompileTime) && MatrixType::RowsAtCompileTime!=Dynamic>
|
||||
struct ei_inplace_transpose_selector;
|
||||
|
||||
template<typename MatrixType>
|
||||
struct ei_inplace_transpose_selector<MatrixType,true> { // square matrix
|
||||
static void run(MatrixType& m) {
|
||||
m.template part<StrictlyUpper>().swap(m.transpose());
|
||||
}
|
||||
};
|
||||
|
||||
template<typename MatrixType>
|
||||
struct ei_inplace_transpose_selector<MatrixType,false> { // non square matrix
|
||||
static void run(MatrixType& m) {
|
||||
if (m.rows()==m.cols())
|
||||
m.template part<StrictlyUpper>().swap(m.transpose());
|
||||
else
|
||||
m.set(m.transpose().eval());
|
||||
}
|
||||
};
|
||||
|
||||
/** This is the "in place" version of transpose: it transposes \c *this.
|
||||
*
|
||||
* In most cases it is probably better to simply use the transposed expression
|
||||
* of a matrix. However, when transposing 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 .transpose() requires special care:
|
||||
* \code m.set(m.transpose().eval()); \endcode
|
||||
* - no temporary object is created (currently only for squared matrices)
|
||||
* - it allows future optimizations (cache friendliness, etc.)
|
||||
*
|
||||
* \note if the matrix is not square, then \c *this must be a resizable matrix.
|
||||
*
|
||||
* \sa transpose(), adjoint() */
|
||||
template<typename Derived>
|
||||
inline void MatrixBase<Derived>::transposeInPlace()
|
||||
{
|
||||
ei_inplace_transpose_selector<Derived>::run(derived());
|
||||
}
|
||||
|
||||
#endif // EIGEN_TRANSPOSE_H
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
// for linear algebra. Eigen itself is part of the KDE project.
|
||||
//
|
||||
// Copyright (C) 2008 Gael Guennebaud <g.gael@free.fr>
|
||||
// Copyright (C) 2006-2008 Benoit Jacob <jacob@math.jussieu.fr>
|
||||
// Copyright (C) 2006-2008 Benoit Jacob <jacob.benoit.1@gmail.com>
|
||||
//
|
||||
// Eigen is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU Lesser General Public
|
||||
@@ -26,14 +26,37 @@
|
||||
#ifndef EIGEN_CONSTANTS_H
|
||||
#define EIGEN_CONSTANTS_H
|
||||
|
||||
/** This value means that a quantity is not known at compile-time, and that instead the value is
|
||||
* stored in some runtime variable.
|
||||
*
|
||||
* Explanation for the choice of this value:
|
||||
* - It should be positive and larger than any reasonable compile-time-fixed number of rows or columns.
|
||||
* This allows to simplify many compile-time conditions throughout Eigen.
|
||||
* - It should be smaller than the sqrt of INT_MAX. Indeed, we often multiply a number of rows with a number
|
||||
* of columns in order to compute a number of coefficients. Even if we guard that with an "if" checking whether
|
||||
* the values are Dynamic, we still get a compiler warning "integer overflow". So the only way to get around
|
||||
* it would be a meta-selector. Doing this everywhere would reduce code readability and lenghten compilation times.
|
||||
* Also, disabling compiler warnings for integer overflow, sounds like a bad idea.
|
||||
*
|
||||
* If you wish to port Eigen to a platform where sizeof(int)==2, it is perfectly possible to set Dynamic to, say, 100.
|
||||
*/
|
||||
const int Dynamic = 10000;
|
||||
|
||||
/** 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
|
||||
*/
|
||||
|
||||
@@ -194,9 +217,9 @@ enum {
|
||||
};
|
||||
|
||||
enum {
|
||||
CompleteUnrolling,
|
||||
NoUnrolling,
|
||||
InnerUnrolling,
|
||||
NoUnrolling
|
||||
CompleteUnrolling
|
||||
};
|
||||
|
||||
enum {
|
||||
@@ -206,9 +229,9 @@ enum {
|
||||
|
||||
enum {
|
||||
IsDense = 0,
|
||||
IsSparse = SparseBit,
|
||||
NoDirectAccess = 0,
|
||||
HasDirectAccess = DirectAccessBit,
|
||||
IsSparse = SparseBit
|
||||
HasDirectAccess = DirectAccessBit
|
||||
};
|
||||
|
||||
const int FullyCoherentAccessPattern = 0x1;
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
// This file is part of Eigen, a lightweight C++ template library
|
||||
// for linear algebra. Eigen itself is part of the KDE project.
|
||||
//
|
||||
// Copyright (C) 2006-2008 Benoit Jacob <jacob@math.jussieu.fr>
|
||||
// Copyright (C) 2006-2008 Benoit Jacob <jacob.benoit.1@gmail.com>
|
||||
//
|
||||
// Eigen is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU Lesser General Public
|
||||
@@ -64,6 +64,7 @@ template<typename Scalar> struct ei_scalar_quotient_op;
|
||||
template<typename Scalar> struct ei_scalar_opposite_op;
|
||||
template<typename Scalar> struct ei_scalar_conjugate_op;
|
||||
template<typename Scalar> struct ei_scalar_real_op;
|
||||
template<typename Scalar> struct ei_scalar_imag_op;
|
||||
template<typename Scalar> struct ei_scalar_abs_op;
|
||||
template<typename Scalar> struct ei_scalar_abs2_op;
|
||||
template<typename Scalar> struct ei_scalar_sqrt_op;
|
||||
@@ -102,6 +103,9 @@ template<typename ExpressionType, int Direction> class PartialRedux;
|
||||
template<typename MatrixType> class LU;
|
||||
template<typename MatrixType> class QR;
|
||||
template<typename MatrixType> class SVD;
|
||||
template<typename MatrixType> class LLT;
|
||||
template<typename MatrixType> class LDLT;
|
||||
// deprecated:
|
||||
template<typename MatrixType> class Cholesky;
|
||||
template<typename MatrixType> class CholeskyWithoutSquareRoot;
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
// for linear algebra. Eigen itself is part of the KDE project.
|
||||
//
|
||||
// Copyright (C) 2008 Gael Guennebaud <g.gael@free.fr>
|
||||
// Copyright (C) 2006-2008 Benoit Jacob <jacob@math.jussieu.fr>
|
||||
// Copyright (C) 2006-2008 Benoit Jacob <jacob.benoit.1@gmail.com>
|
||||
//
|
||||
// Eigen is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU Lesser General Public
|
||||
@@ -28,7 +28,10 @@
|
||||
|
||||
#undef minor
|
||||
|
||||
/** \internal Defines the maximal loop size to enable meta unrolling of loops */
|
||||
/** \internal 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
|
||||
@@ -36,7 +39,7 @@
|
||||
/** \internal Define the maximal size in Bytes of L2 blocks.
|
||||
* The current value is set to generate blocks of 256x256 for float */
|
||||
#ifndef EIGEN_TUNE_FOR_L2_CACHE_SIZE
|
||||
#define EIGEN_TUNE_FOR_L2_CACHE_SIZE (1024*256)
|
||||
#define EIGEN_TUNE_FOR_L2_CACHE_SIZE (sizeof(float)*256*256)
|
||||
#endif
|
||||
|
||||
#define USING_PART_OF_NAMESPACE_EIGEN \
|
||||
@@ -70,7 +73,7 @@ using Eigen::ei_cos;
|
||||
#endif
|
||||
|
||||
#ifdef EIGEN_INTERNAL_DEBUGGING
|
||||
#define ei_internal_assert(x) ei_assert(x);
|
||||
#define ei_internal_assert(x) ei_assert(x)
|
||||
#else
|
||||
#define ei_internal_assert(x)
|
||||
#endif
|
||||
@@ -97,6 +100,12 @@ using Eigen::ei_cos;
|
||||
#define EIGEN_DONT_INLINE
|
||||
#endif
|
||||
|
||||
#if (defined __GNUC__)
|
||||
#define EIGEN_DEPRECATED __attribute__((deprecated))
|
||||
#else
|
||||
#define EIGEN_DEPRECATED
|
||||
#endif
|
||||
|
||||
#if (defined __GNUC__)
|
||||
#define EIGEN_ALIGN_128 __attribute__ ((aligned(16)))
|
||||
#else
|
||||
@@ -105,9 +114,17 @@ using Eigen::ei_cos;
|
||||
|
||||
#define EIGEN_RESTRICT __restrict
|
||||
|
||||
#ifndef EIGEN_DEFAULT_IO_FORMAT
|
||||
#define EIGEN_DEFAULT_IO_FORMAT Eigen::IOFormat()
|
||||
#endif
|
||||
|
||||
// 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_DOCS_IO_FORMAT IOFormat(3, AlignCols, " ", "\n", "", "")
|
||||
|
||||
#define EIGEN_INHERIT_ASSIGNMENT_OPERATOR(Derived, Op) \
|
||||
template<typename OtherDerived> \
|
||||
Derived& operator Op(const MatrixBase<OtherDerived>& other) \
|
||||
Derived& operator Op(const Eigen::MatrixBase<OtherDerived>& other) \
|
||||
{ \
|
||||
return Eigen::MatrixBase<Derived>::operator Op(other.derived()); \
|
||||
} \
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
// for linear algebra. Eigen itself is part of the KDE project.
|
||||
//
|
||||
// Copyright (C) 2008 Gael Guennebaud <g.gael@free.fr>
|
||||
// Copyright (C) 2006-2008 Benoit Jacob <jacob@math.jussieu.fr>
|
||||
// Copyright (C) 2006-2008 Benoit Jacob <jacob.benoit.1@gmail.com>
|
||||
//
|
||||
// Eigen is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU Lesser General Public
|
||||
@@ -37,6 +37,12 @@ extern "C" int posix_memalign (void **, size_t, size_t) throw ();
|
||||
template <typename T, int Size, bool Align> struct ei_aligned_array
|
||||
{
|
||||
EIGEN_ALIGN_128 T array[Size];
|
||||
|
||||
ei_aligned_array()
|
||||
{
|
||||
ei_assert((reinterpret_cast<unsigned int>(array) & 0xf) == 0
|
||||
&& "this assertion is explained here: http://eigen.tuxfamily.org/api/UnalignedArrayAssert.html **** READ THIS WEB PAGE !!! ****");
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T, int Size> struct ei_aligned_array<T,Size,false>
|
||||
@@ -44,7 +50,7 @@ template <typename T, int Size> struct ei_aligned_array<T,Size,false>
|
||||
T array[Size];
|
||||
};
|
||||
|
||||
/** \internal allocates \a size * sizeof(\a T) bytes with a 16 bytes based alignment */
|
||||
/** \internal allocates \a size * sizeof(\a T) bytes with 16 bytes alignment */
|
||||
template<typename T>
|
||||
inline T* ei_aligned_malloc(size_t size)
|
||||
{
|
||||
@@ -91,7 +97,7 @@ inline static int ei_alignmentOffset(const Scalar* ptr, int maxOffset)
|
||||
/** \internal
|
||||
* ei_alloc_stack(TYPE,SIZE) allocates sizeof(TYPE)*SIZE bytes on the stack if sizeof(TYPE)*SIZE is
|
||||
* smaller than EIGEN_STACK_ALLOCATION_LIMIT. Otherwise the memory is allocated using the operator new.
|
||||
* Data allocated with ei_alloc_stack \b must be freed calling ei_free_stack(PTR,TYPE,SIZE).
|
||||
* Data allocated with ei_alloc_stack \b must be freed by calling ei_free_stack(PTR,TYPE,SIZE).
|
||||
* \code
|
||||
* float * data = ei_alloc_stack(float,array.size());
|
||||
* // ...
|
||||
@@ -108,15 +114,15 @@ inline static int ei_alignmentOffset(const Scalar* ptr, int maxOffset)
|
||||
|
||||
/** \class WithAlignedOperatorNew
|
||||
*
|
||||
* \brief Enforces inherited classes to be 16 bytes aligned when dynamicalled allocated with operator new
|
||||
* \brief Enforces instances of inherited classes to be 16 bytes aligned when allocated with operator new
|
||||
*
|
||||
* When Eigen's explicit vectorization is enabled, Eigen assumes that some fixed sizes types are aligned
|
||||
* on a 16 bytes boundary. Such types include:
|
||||
* on a 16 bytes boundary. Those include all Matrix types having a sizeof multiple of 16 bytes, e.g.:
|
||||
* - Vector2d, Vector4f, Vector4i, Vector4d,
|
||||
* - Matrix2d, Matrix4f, Matrix4i, Matrix4d,
|
||||
* - etc.
|
||||
* When objects are statically allocated, the compiler will automatically and always enforces 16 bytes
|
||||
* alignment of the data. However some troubles might appear when data are dynamically allocated.
|
||||
* When an object is statically allocated, the compiler will automatically and always enforces 16 bytes
|
||||
* alignment of the data when needed. However some troubles might appear when data are dynamically allocated.
|
||||
* Let's pick an example:
|
||||
* \code
|
||||
* struct Foo {
|
||||
@@ -130,8 +136,8 @@ inline static int ei_alignmentOffset(const Scalar* ptr, int maxOffset)
|
||||
* pObj2->some_vector = Vector4f(..); // => !! might segfault !!
|
||||
* \endcode
|
||||
* Here, the problem is that operator new is not aware of the compile time alignment requirement of the
|
||||
* type Vector4f (and hence of the type Foo). Therefore "new Foo" does not necessarily returned a 16 bytes
|
||||
* aligned pointer. The purpose of the class WithAlignedOperatorNew is exactly to overcome this issue, by
|
||||
* type Vector4f (and hence of the type Foo). Therefore "new Foo" does not necessarily returns a 16 bytes
|
||||
* aligned pointer. The purpose of the class WithAlignedOperatorNew is exactly to overcome this issue by
|
||||
* overloading the operator new to return aligned data when the vectorization is enabled.
|
||||
* Here is a similar safe example:
|
||||
* \code
|
||||
@@ -139,12 +145,9 @@ inline static int ei_alignmentOffset(const Scalar* ptr, int maxOffset)
|
||||
* char dummy;
|
||||
* Vector4f some_vector;
|
||||
* };
|
||||
* Foo obj1; // static allocation
|
||||
* obj1.some_vector = Vector4f(..); // => OK
|
||||
*
|
||||
* Foo *pObj2 = new Foo; // dynamic allocation
|
||||
* pObj2->some_vector = Vector4f(..); // => SAFE !
|
||||
* \endcode
|
||||
* \endcode
|
||||
*
|
||||
* \sa class ei_new_allocator
|
||||
*/
|
||||
@@ -172,7 +175,7 @@ struct WithAlignedOperatorNew
|
||||
|
||||
void operator delete(void * ptr) { free(ptr); }
|
||||
void operator delete[](void * ptr) { free(ptr); }
|
||||
|
||||
|
||||
#endif
|
||||
};
|
||||
|
||||
@@ -190,14 +193,14 @@ struct ei_with_aligned_operator_new<T,SizeAtCompileTime,false> {};
|
||||
* STL allocator simply wrapping operators new[] and delete[]. Unlike GCC's default new_allocator,
|
||||
* ei_new_allocator call operator new on the type \a T and not the general new operator ignoring
|
||||
* overloaded version of operator new.
|
||||
*
|
||||
*
|
||||
* Example:
|
||||
* \code
|
||||
* // Vector4f requires 16 bytes alignment:
|
||||
* std::vector<Vector4f,ei_new_allocator<Vector4f> > dataVec4;
|
||||
* // Vector3f does not require 16 bytes alignment, no need to use Eigen's allocator:
|
||||
* std::vector<Vector3f> dataVec3;
|
||||
*
|
||||
*
|
||||
* struct Foo : WithAlignedOperatorNew {
|
||||
* char dummy;
|
||||
* Vector4f some_vector;
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
// for linear algebra. Eigen itself is part of the KDE project.
|
||||
//
|
||||
// Copyright (C) 2008 Gael Guennebaud <g.gael@free.fr>
|
||||
// Copyright (C) 2006-2008 Benoit Jacob <jacob@math.jussieu.fr>
|
||||
// Copyright (C) 2006-2008 Benoit Jacob <jacob.benoit.1@gmail.com>
|
||||
//
|
||||
// Eigen is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU Lesser General Public
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
// for linear algebra. Eigen itself is part of the KDE project.
|
||||
//
|
||||
// Copyright (C) 2008 Gael Guennebaud <g.gael@free.fr>
|
||||
// Copyright (C) 2006-2008 Benoit Jacob <jacob@math.jussieu.fr>
|
||||
// Copyright (C) 2006-2008 Benoit Jacob <jacob.benoit.1@gmail.com>
|
||||
//
|
||||
// Eigen is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU Lesser General Public
|
||||
@@ -44,7 +44,7 @@
|
||||
#ifdef __GXX_EXPERIMENTAL_CXX0X__
|
||||
|
||||
// if native static_assert is enabled, let's use it
|
||||
#define EIGEN_STATIC_ASSERT(X,MSG) static_assert(X,#MSG)
|
||||
#define EIGEN_STATIC_ASSERT(X,MSG) static_assert(X,#MSG);
|
||||
|
||||
#else // CXX0X
|
||||
|
||||
@@ -60,24 +60,28 @@
|
||||
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,
|
||||
you_did_a_programming_error,
|
||||
you_made_a_programming_mistake,
|
||||
you_called_a_fixed_size_method_on_a_dynamic_size_matrix_or_vector,
|
||||
unaligned_load_and_store_operations_unimplemented_on_AltiVec,
|
||||
scalar_type_must_be_floating_point,
|
||||
default_writting_to_selfadjoint_not_supported,
|
||||
writting_to_triangular_part_with_unit_diag_is_not_supported,
|
||||
this_method_is_only_for_fixed_size
|
||||
numeric_type_must_be_floating_point,
|
||||
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
|
||||
};
|
||||
};
|
||||
|
||||
#define EIGEN_STATIC_ASSERT(CONDITION,MSG) \
|
||||
if (ei_static_assert<CONDITION ? true : false>::MSG) {}
|
||||
if (Eigen::ei_static_assert<CONDITION ? true : false>::MSG) {}
|
||||
|
||||
#endif // CXX0X
|
||||
#endif // not CXX0X
|
||||
|
||||
#else // EIGEN_NO_STATIC_ASSERT
|
||||
|
||||
#define EIGEN_STATIC_ASSERT(CONDITION,MSG) ei_assert((CONDITION) && #MSG)
|
||||
#define EIGEN_STATIC_ASSERT(CONDITION,MSG) ei_assert((CONDITION) && #MSG);
|
||||
|
||||
#endif // EIGEN_NO_STATIC_ASSERT
|
||||
|
||||
@@ -110,15 +114,18 @@
|
||||
|| int(TYPE0::SizeAtCompileTime)==int(TYPE1::SizeAtCompileTime)),\
|
||||
you_mixed_vectors_of_different_sizes)
|
||||
|
||||
// static assertion failing if the two matrix expression types are not compatible (same fixed-size or dynamic size)
|
||||
#define EIGEN_STATIC_ASSERT_SAME_MATRIX_SIZE(TYPE0,TYPE1) \
|
||||
EIGEN_STATIC_ASSERT( \
|
||||
((int(TYPE0::RowsAtCompileTime)==Eigen::Dynamic \
|
||||
#define EIGEN_PREDICATE_SAME_MATRIX_SIZE(TYPE0,TYPE1) \
|
||||
((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))),\
|
||||
|| int(TYPE0::ColsAtCompileTime)==int(TYPE1::ColsAtCompileTime)))
|
||||
|
||||
// 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)
|
||||
|
||||
#endif // EIGEN_STATIC_ASSERT_H
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
// for linear algebra. Eigen itself is part of the KDE project.
|
||||
//
|
||||
// Copyright (C) 2008 Gael Guennebaud <g.gael@free.fr>
|
||||
// Copyright (C) 2006-2008 Benoit Jacob <jacob@math.jussieu.fr>
|
||||
// Copyright (C) 2006-2008 Benoit Jacob <jacob.benoit.1@gmail.com>
|
||||
//
|
||||
// Eigen is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU Lesser General Public
|
||||
@@ -41,6 +41,10 @@ class ei_no_assignment_operator
|
||||
ei_no_assignment_operator& operator=(const ei_no_assignment_operator&);
|
||||
};
|
||||
|
||||
/** \internal If the template parameter Value is Dynamic, this class is just a wrapper around an int 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<int Value> class ei_int_if_dynamic EIGEN_EMPTY_STRUCT
|
||||
{
|
||||
public:
|
||||
@@ -121,9 +125,39 @@ template<typename T> struct ei_eval<T,IsDense>
|
||||
> type;
|
||||
};
|
||||
|
||||
|
||||
template<typename T> struct ei_eval_to_column_major
|
||||
{
|
||||
typedef Matrix<typename ei_traits<T>::Scalar,
|
||||
ei_traits<T>::RowsAtCompileTime,
|
||||
ei_traits<T>::ColsAtCompileTime,
|
||||
ColMajor,
|
||||
ei_traits<T>::MaxRowsAtCompileTime,
|
||||
ei_traits<T>::MaxColsAtCompileTime
|
||||
> type;
|
||||
};
|
||||
|
||||
template<typename T> struct ei_must_nest_by_value { enum { ret = false }; };
|
||||
template<typename T> struct ei_must_nest_by_value<NestByValue<T> > { enum { ret = true }; };
|
||||
|
||||
/** \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.
|
||||
*
|
||||
* 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: ei_nested<S, 3>::ret, which turns out to be Matrix3d because the internal logic of
|
||||
* ei_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 ei_nested<Matrix3d, 3>::ret, which turns out to be
|
||||
* const Matrix3d&, because the internal logic of ei_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 EvalType = typename ei_eval<T>::type> struct ei_nested
|
||||
{
|
||||
enum {
|
||||
@@ -157,4 +191,9 @@ template<typename ExpressionType, int RowsOrSize=Dynamic, int Cols=Dynamic> stru
|
||||
typedef Block<ExpressionType, RowsOrSize, Cols> Type;
|
||||
};
|
||||
|
||||
template<typename CurrentType, typename NewType> struct ei_cast_return_type
|
||||
{
|
||||
typedef typename ei_meta_if<ei_is_same_type<CurrentType,NewType>::ret,const CurrentType&,NewType>::ret type;
|
||||
};
|
||||
|
||||
#endif // EIGEN_XPRHELPER_H
|
||||
|
||||
176
Eigen/src/Geometry/AlignedBox.h
Normal file
176
Eigen/src/Geometry/AlignedBox.h
Normal file
@@ -0,0 +1,176 @@
|
||||
// This file is part of Eigen, a lightweight C++ template library
|
||||
// for linear algebra. Eigen itself is part of the KDE project.
|
||||
//
|
||||
// Copyright (C) 2008 Gael Guennebaud <g.gael@free.fr>
|
||||
//
|
||||
// Eigen is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU Lesser General Public
|
||||
// License as published by the Free Software Foundation; either
|
||||
// version 3 of the License, or (at your option) any later version.
|
||||
//
|
||||
// Alternatively, you can redistribute it and/or
|
||||
// modify it under the terms of the GNU General Public License as
|
||||
// published by the Free Software Foundation; either version 2 of
|
||||
// the License, or (at your option) any later version.
|
||||
//
|
||||
// Eigen is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||
// FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License or the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public
|
||||
// License and a copy of the GNU General Public License along with
|
||||
// Eigen. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
#ifndef EIGEN_ALIGNEDBOX_H
|
||||
#define EIGEN_ALIGNEDBOX_H
|
||||
|
||||
/** \geometry_module \ingroup GeometryModule
|
||||
* \nonstableyet
|
||||
*
|
||||
* \class AlignedBox
|
||||
*
|
||||
* \brief An axis aligned box
|
||||
*
|
||||
* \param _Scalar the type of the scalar coefficients
|
||||
* \param _AmbientDim the dimension of the ambient space, can be a compile time value or Dynamic.
|
||||
*
|
||||
* This class represents an axis aligned box as a pair of the minimal and maximal corners.
|
||||
*/
|
||||
template <typename _Scalar, int _AmbientDim>
|
||||
class AlignedBox
|
||||
#ifdef EIGEN_VECTORIZE
|
||||
: public ei_with_aligned_operator_new<_Scalar,_AmbientDim==Dynamic ? Dynamic : _AmbientDim+1>
|
||||
#endif
|
||||
{
|
||||
public:
|
||||
|
||||
enum { AmbientDimAtCompileTime = _AmbientDim };
|
||||
typedef _Scalar Scalar;
|
||||
typedef typename NumTraits<Scalar>::Real RealScalar;
|
||||
typedef Matrix<Scalar,AmbientDimAtCompileTime,1> VectorType;
|
||||
|
||||
/** Default constructor initializing a null box. */
|
||||
inline explicit AlignedBox()
|
||||
{ if (AmbientDimAtCompileTime!=Dynamic) setNull(); }
|
||||
|
||||
/** Constructs a null box with \a _dim the dimension of the ambient space. */
|
||||
inline explicit AlignedBox(int _dim) : m_min(_dim), m_max(_dim)
|
||||
{ setNull(); }
|
||||
|
||||
/** Constructs a box with extremities \a _min and \a _max. */
|
||||
inline AlignedBox(const VectorType& _min, const VectorType _max) : m_min(_min), m_max(_max) {}
|
||||
|
||||
/** Constructs a box containing a single point \a p. */
|
||||
inline explicit AlignedBox(const VectorType& p) : m_min(p), m_max(p) {}
|
||||
|
||||
~AlignedBox() {}
|
||||
|
||||
/** \returns the dimension in which the box holds */
|
||||
inline int dim() const { return AmbientDimAtCompileTime==Dynamic ? m_min.size()-1 : AmbientDimAtCompileTime; }
|
||||
|
||||
/** \returns true if the box is null, i.e, empty. */
|
||||
inline bool isNull() const { return (m_min.cwise() > m_max).any(); }
|
||||
|
||||
/** Makes \c *this a null/empty box. */
|
||||
inline void setNull()
|
||||
{
|
||||
m_min.setConstant( std::numeric_limits<Scalar>::max());
|
||||
m_max.setConstant(-std::numeric_limits<Scalar>::max());
|
||||
}
|
||||
|
||||
/** \returns the minimal corner */
|
||||
inline const VectorType& min() const { return m_min; }
|
||||
/** \returns a non const reference to the minimal corner */
|
||||
inline VectorType& min() { return m_min; }
|
||||
/** \returns the maximal corner */
|
||||
inline const VectorType& max() const { return m_max; }
|
||||
/** \returns a non const reference to the maximal corner */
|
||||
inline VectorType& max() { return m_max; }
|
||||
|
||||
/** \returns true if the point \a p is inside the box \c *this. */
|
||||
inline bool contains(const VectorType& p) const
|
||||
{ return (m_min.cwise()<=p).all() && (p.cwise()<=m_max).all(); }
|
||||
|
||||
/** \returns true if the box \a b is entirely inside the box \c *this. */
|
||||
inline bool contains(const AlignedBox& b) const
|
||||
{ return (m_min.cwise()<=b.min()).all() && (b.max().cwise()<=m_max).all(); }
|
||||
|
||||
/** Extends \c *this such that it contains the point \a p and returns a reference to \c *this. */
|
||||
inline AlignedBox& extend(const VectorType& p)
|
||||
{ m_min = m_min.cwise().min(p); m_max = m_max.cwise().max(p); return *this; }
|
||||
|
||||
/** Extends \c *this such that it contains the box \a b and returns a reference to \c *this. */
|
||||
inline AlignedBox& extend(const AlignedBox& b)
|
||||
{ m_min = m_min.cwise().min(b.m_min); m_max = m_max.cwise().max(b.m_max); return *this; }
|
||||
|
||||
/** Clamps \c *this by the box \a b and returns a reference to \c *this. */
|
||||
inline AlignedBox& clamp(const AlignedBox& b)
|
||||
{ m_min = m_min.cwise().max(b.m_min); m_max = m_max.cwise().min(b.m_max); return *this; }
|
||||
|
||||
/** Translate \c *this by the vector \a t and returns a reference to \c *this. */
|
||||
inline AlignedBox& translate(const VectorType& t)
|
||||
{ m_min += t; m_max += t; return *this; }
|
||||
|
||||
/** \returns the squared distance between the point \a p and the box \c *this,
|
||||
* and zero if \a p is inside the box.
|
||||
* \sa exteriorDistance()
|
||||
*/
|
||||
inline Scalar squaredExteriorDistance(const VectorType& p) const;
|
||||
|
||||
/** \returns the distance between the point \a p and the box \c *this,
|
||||
* and zero if \a p is inside the box.
|
||||
* \sa squaredExteriorDistance()
|
||||
*/
|
||||
inline Scalar exteriorDistance(const VectorType& p) const
|
||||
{ return ei_sqrt(squaredExteriorDistance(p)); }
|
||||
|
||||
/** \returns \c *this with scalar type casted to \a NewScalarType
|
||||
*
|
||||
* Note that if \a NewScalarType is equal to the current scalar type of \c *this
|
||||
* then this function smartly returns a const reference to \c *this.
|
||||
*/
|
||||
template<typename NewScalarType>
|
||||
inline typename ei_cast_return_type<AlignedBox,
|
||||
AlignedBox<NewScalarType,AmbientDimAtCompileTime> >::type cast() const
|
||||
{
|
||||
return typename ei_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<OtherScalarType>();
|
||||
m_max = other.max().template cast<OtherScalarType>();
|
||||
}
|
||||
|
||||
/** \returns \c true if \c *this is approximately equal to \a other, within the precision
|
||||
* determined by \a prec.
|
||||
*
|
||||
* \sa MatrixBase::isApprox() */
|
||||
bool isApprox(const AlignedBox& other, typename NumTraits<Scalar>::Real prec = precision<Scalar>()) const
|
||||
{ return m_min.isApprox(other.m_min, prec) && m_max.isApprox(other.m_max, prec); }
|
||||
|
||||
protected:
|
||||
|
||||
VectorType m_min, m_max;
|
||||
};
|
||||
|
||||
template<typename Scalar,int AmbiantDim>
|
||||
inline Scalar AlignedBox<Scalar,AmbiantDim>::squaredExteriorDistance(const VectorType& p) const
|
||||
{
|
||||
Scalar dist2 = 0.;
|
||||
Scalar aux;
|
||||
for (int k=0; k<dim(); ++k)
|
||||
{
|
||||
if ((aux = (p[k]-m_min[k]))<0.)
|
||||
dist2 += aux*aux;
|
||||
else if ( (aux = (m_max[k]-p[k]))<0. )
|
||||
dist2 += aux*aux;
|
||||
}
|
||||
return dist2;
|
||||
}
|
||||
|
||||
#endif // EIGEN_ALIGNEDBOX_H
|
||||
@@ -47,7 +47,7 @@
|
||||
* \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()
|
||||
*/
|
||||
|
||||
@@ -64,7 +64,7 @@ class AngleAxis : public RotationBase<AngleAxis<_Scalar>,3>
|
||||
public:
|
||||
|
||||
using Base::operator*;
|
||||
|
||||
|
||||
enum { Dim = 3 };
|
||||
/** the scalar type of the coefficients */
|
||||
typedef _Scalar Scalar;
|
||||
@@ -132,6 +132,30 @@ public:
|
||||
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 ei_cast_return_type<AngleAxis,AngleAxis<NewScalarType> >::type cast() const
|
||||
{ return typename ei_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<OtherScalarType>();
|
||||
m_angle = other.angle();
|
||||
}
|
||||
|
||||
/** \returns \c true if \c *this is approximately equal to \a other, within the precision
|
||||
* determined by \a prec.
|
||||
*
|
||||
* \sa MatrixBase::isApprox() */
|
||||
bool isApprox(const AngleAxis& other, typename NumTraits<Scalar>::Real prec = precision<Scalar>()) const
|
||||
{ return m_axis.isApprox(other.m_axis, prec) && ei_isApprox(m_angle,other.m_angle, prec); }
|
||||
};
|
||||
|
||||
/** \ingroup GeometryModule
|
||||
@@ -147,7 +171,7 @@ typedef AngleAxis<double> AngleAxisd;
|
||||
template<typename Scalar>
|
||||
AngleAxis<Scalar>& AngleAxis<Scalar>::operator=(const QuaternionType& q)
|
||||
{
|
||||
Scalar n2 = q.vec().norm2();
|
||||
Scalar n2 = q.vec().squaredNorm();
|
||||
if (n2 < precision<Scalar>()*precision<Scalar>())
|
||||
{
|
||||
m_angle = 0;
|
||||
|
||||
96
Eigen/src/Geometry/EulerAngles.h
Normal file
96
Eigen/src/Geometry/EulerAngles.h
Normal file
@@ -0,0 +1,96 @@
|
||||
// This file is part of Eigen, a lightweight C++ template library
|
||||
// for linear algebra. Eigen itself is part of the KDE project.
|
||||
//
|
||||
// Copyright (C) 2008 Gael Guennebaud <g.gael@free.fr>
|
||||
//
|
||||
// Eigen is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU Lesser General Public
|
||||
// License as published by the Free Software Foundation; either
|
||||
// version 3 of the License, or (at your option) any later version.
|
||||
//
|
||||
// Alternatively, you can redistribute it and/or
|
||||
// modify it under the terms of the GNU General Public License as
|
||||
// published by the Free Software Foundation; either version 2 of
|
||||
// the License, or (at your option) any later version.
|
||||
//
|
||||
// Eigen is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||
// FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License or the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public
|
||||
// License and a copy of the GNU General Public License along with
|
||||
// Eigen. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
#ifndef EIGEN_EULERANGLES_H
|
||||
#define EIGEN_EULERANGLES_H
|
||||
|
||||
/** \geometry_module \ingroup GeometryModule
|
||||
* \nonstableyet
|
||||
*
|
||||
* \returns the Euler-angles of the rotation matrix \c *this using the convention defined by the triplet (\a a0,\a a1,\a a2)
|
||||
*
|
||||
* Each of the three parameters \a a0,\a a1,\a a2 represents the respective rotation axis as an integer in {0,1,2}.
|
||||
* For instance, in:
|
||||
* \code Vector3f ea = mat.eulerAngles(2, 0, 2); \endcode
|
||||
* "2" represents the z axis and "0" the x axis, etc. The returned angles are such that
|
||||
* we have the following equality:
|
||||
* \code
|
||||
* mat == AngleAxisf(ea[0], Vector3f::UnitZ())
|
||||
* * AngleAxisf(ea[1], Vector3f::UnitX())
|
||||
* * AngleAxisf(ea[2], Vector3f::UnitZ()); \endcode
|
||||
* This corresponds to the right-multiply conventions (with right hand side frames).
|
||||
*/
|
||||
template<typename Derived>
|
||||
inline Matrix<typename MatrixBase<Derived>::Scalar,3,1>
|
||||
MatrixBase<Derived>::eulerAngles(int a0, int a1, int a2) const
|
||||
{
|
||||
/* Implemented from Graphics Gems IV */
|
||||
EIGEN_STATIC_ASSERT_MATRIX_SPECIFIC_SIZE(Derived,3,3)
|
||||
|
||||
Matrix<Scalar,3,1> res;
|
||||
typedef Matrix<typename Derived::Scalar,2,1> Vector2;
|
||||
const Scalar epsilon = precision<Scalar>();
|
||||
|
||||
const int odd = ((a0+1)%3 == a1) ? 0 : 1;
|
||||
const int i = a0;
|
||||
const int j = (a0 + 1 + odd)%3;
|
||||
const int k = (a0 + 2 - odd)%3;
|
||||
|
||||
if (a0==a2)
|
||||
{
|
||||
Scalar s = Vector2(coeff(j,i) , coeff(k,i)).norm();
|
||||
res[1] = std::atan2(s, coeff(i,i));
|
||||
if (s > epsilon)
|
||||
{
|
||||
res[0] = std::atan2(coeff(j,i), coeff(k,i));
|
||||
res[2] = std::atan2(coeff(i,j),-coeff(i,k));
|
||||
}
|
||||
else
|
||||
{
|
||||
res[0] = Scalar(0);
|
||||
res[2] = (coeff(i,i)>0?1:-1)*std::atan2(-coeff(k,j), coeff(j,j));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Scalar c = Vector2(coeff(i,i) , coeff(i,j)).norm();
|
||||
res[1] = std::atan2(-coeff(i,k), c);
|
||||
if (c > epsilon)
|
||||
{
|
||||
res[0] = std::atan2(coeff(j,k), coeff(k,k));
|
||||
res[2] = std::atan2(coeff(i,j), coeff(i,i));
|
||||
}
|
||||
else
|
||||
{
|
||||
res[0] = Scalar(0);
|
||||
res[2] = (coeff(i,k)>0?1:-1)*std::atan2(-coeff(k,j), coeff(j,j));
|
||||
}
|
||||
}
|
||||
if (!odd)
|
||||
res = -res;
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
#endif // EIGEN_EULERANGLES_H
|
||||
@@ -2,7 +2,7 @@
|
||||
// for linear algebra. Eigen itself is part of the KDE project.
|
||||
//
|
||||
// Copyright (C) 2008 Gael Guennebaud <g.gael@free.fr>
|
||||
// Copyright (C) 2008 Benoit Jacob <jacob@math.jussieu.fr>
|
||||
// Copyright (C) 2008 Benoit Jacob <jacob.benoit.1@gmail.com>
|
||||
//
|
||||
// Eigen is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU Lesser General Public
|
||||
@@ -49,173 +49,223 @@ class Hyperplane
|
||||
: public ei_with_aligned_operator_new<_Scalar,_AmbientDim==Dynamic ? Dynamic : _AmbientDim+1>
|
||||
#endif
|
||||
{
|
||||
public:
|
||||
public:
|
||||
|
||||
enum { AmbientDimAtCompileTime = _AmbientDim };
|
||||
typedef _Scalar Scalar;
|
||||
typedef typename NumTraits<Scalar>::Real RealScalar;
|
||||
typedef Matrix<Scalar,AmbientDimAtCompileTime,1> VectorType;
|
||||
typedef Matrix<Scalar,AmbientDimAtCompileTime==Dynamic
|
||||
? Dynamic
|
||||
: AmbientDimAtCompileTime+1,1> Coefficients;
|
||||
typedef Block<Coefficients,AmbientDimAtCompileTime,1> NormalReturnType;
|
||||
enum { AmbientDimAtCompileTime = _AmbientDim };
|
||||
typedef _Scalar Scalar;
|
||||
typedef typename NumTraits<Scalar>::Real RealScalar;
|
||||
typedef Matrix<Scalar,AmbientDimAtCompileTime,1> VectorType;
|
||||
typedef Matrix<Scalar,AmbientDimAtCompileTime==Dynamic
|
||||
? Dynamic
|
||||
: AmbientDimAtCompileTime+1,1> Coefficients;
|
||||
typedef Block<Coefficients,AmbientDimAtCompileTime,1> NormalReturnType;
|
||||
|
||||
/** Default constructor without initialization */
|
||||
inline explicit Hyperplane(int _dim = AmbientDimAtCompileTime) : m_coeffs(_dim+1) {}
|
||||
|
||||
/** Construct a plane from its normal \a n and a point \a e onto the plane.
|
||||
* \warning the vector normal is assumed to be normalized.
|
||||
*/
|
||||
inline Hyperplane(const VectorType& n, const VectorType e)
|
||||
: m_coeffs(n.size()+1)
|
||||
{
|
||||
normal() = n;
|
||||
offset() = -e.dot(n);
|
||||
/** Default constructor without initialization */
|
||||
inline explicit Hyperplane() {}
|
||||
|
||||
/** Constructs a dynamic-size hyperplane with \a _dim the dimension
|
||||
* of the ambient space */
|
||||
inline explicit Hyperplane(int _dim) : m_coeffs(_dim+1) {}
|
||||
|
||||
/** Construct a plane from its normal \a n and a point \a e onto the plane.
|
||||
* \warning the vector normal is assumed to be normalized.
|
||||
*/
|
||||
inline Hyperplane(const VectorType& n, const VectorType e)
|
||||
: m_coeffs(n.size()+1)
|
||||
{
|
||||
normal() = n;
|
||||
offset() = -e.dot(n);
|
||||
}
|
||||
|
||||
/** Constructs a plane from its normal \a n and distance to the origin \a d
|
||||
* such that the algebraic equation of the plane is \f$ n \cdot x + d = 0 \f$.
|
||||
* \warning the vector normal is assumed to be normalized.
|
||||
*/
|
||||
inline Hyperplane(const VectorType& n, Scalar d)
|
||||
: m_coeffs(n.size()+1)
|
||||
{
|
||||
normal() = n;
|
||||
offset() = d;
|
||||
}
|
||||
|
||||
/** Constructs a hyperplane passing through the two points. If the dimension of the ambient space
|
||||
* is greater than 2, then there isn't uniqueness, so an arbitrary choice is made.
|
||||
*/
|
||||
static inline Hyperplane Through(const VectorType& p0, const VectorType& p1)
|
||||
{
|
||||
Hyperplane result(p0.size());
|
||||
result.normal() = (p1 - p0).unitOrthogonal();
|
||||
result.offset() = -result.normal().dot(p0);
|
||||
return result;
|
||||
}
|
||||
|
||||
/** Constructs a hyperplane passing through the three points. The dimension of the ambient space
|
||||
* is required to be exactly 3.
|
||||
*/
|
||||
static inline Hyperplane Through(const VectorType& p0, const VectorType& p1, const VectorType& p2)
|
||||
{
|
||||
EIGEN_STATIC_ASSERT_VECTOR_SPECIFIC_SIZE(VectorType, 3)
|
||||
Hyperplane result(p0.size());
|
||||
result.normal() = (p2 - p0).cross(p1 - p0).normalized();
|
||||
result.offset() = -result.normal().dot(p0);
|
||||
return result;
|
||||
}
|
||||
|
||||
/** Constructs a hyperplane passing through the parametrized line \a parametrized.
|
||||
* If the dimension of the ambient space is greater than 2, then there isn't uniqueness,
|
||||
* so an arbitrary choice is made.
|
||||
*/
|
||||
// FIXME to be consitent with the rest this could be implemented as a static Through function ??
|
||||
explicit Hyperplane(const ParametrizedLine<Scalar, AmbientDimAtCompileTime>& parametrized)
|
||||
{
|
||||
normal() = parametrized.direction().unitOrthogonal();
|
||||
offset() = -normal().dot(parametrized.origin());
|
||||
}
|
||||
|
||||
~Hyperplane() {}
|
||||
|
||||
/** \returns the dimension in which the plane holds */
|
||||
inline int dim() const { return AmbientDimAtCompileTime==Dynamic ? m_coeffs.size()-1 : AmbientDimAtCompileTime; }
|
||||
|
||||
/** normalizes \c *this */
|
||||
void normalize(void)
|
||||
{
|
||||
m_coeffs /= normal().norm();
|
||||
}
|
||||
|
||||
/** \returns the signed distance between the plane \c *this and a point \a p.
|
||||
* \sa absDistance()
|
||||
*/
|
||||
inline Scalar signedDistance(const VectorType& p) const { return p.dot(normal()) + offset(); }
|
||||
|
||||
/** \returns the absolute distance between the plane \c *this and a point \a p.
|
||||
* \sa signedDistance()
|
||||
*/
|
||||
inline Scalar absDistance(const VectorType& p) const { return ei_abs(signedDistance(p)); }
|
||||
|
||||
/** \returns the projection of a point \a p onto the plane \c *this.
|
||||
*/
|
||||
inline VectorType projection(const VectorType& p) const { return p - signedDistance(p) * normal(); }
|
||||
|
||||
/** \returns a constant reference to the unit normal vector of the plane, which corresponds
|
||||
* to the linear part of the implicit equation.
|
||||
*/
|
||||
inline const NormalReturnType normal() const { return NormalReturnType(m_coeffs,0,0,dim(),1); }
|
||||
|
||||
/** \returns a non-constant reference to the unit normal vector of the plane, which corresponds
|
||||
* to the linear part of the implicit equation.
|
||||
*/
|
||||
inline NormalReturnType normal() { return NormalReturnType(m_coeffs,0,0,dim(),1); }
|
||||
|
||||
/** \returns the distance to the origin, which is also the "constant term" of the implicit equation
|
||||
* \warning the vector normal is assumed to be normalized.
|
||||
*/
|
||||
inline const Scalar& offset() const { return m_coeffs.coeff(dim()); }
|
||||
|
||||
/** \returns a non-constant reference to the distance to the origin, which is also the constant part
|
||||
* of the implicit equation */
|
||||
inline Scalar& offset() { return m_coeffs(dim()); }
|
||||
|
||||
/** \returns a constant reference to the coefficients c_i of the plane equation:
|
||||
* \f$ c_0*x_0 + ... + c_{d-1}*x_{d-1} + c_d = 0 \f$
|
||||
*/
|
||||
inline const Coefficients& coeffs() const { return m_coeffs; }
|
||||
|
||||
/** \returns a non-constant reference to the coefficients c_i of the plane equation:
|
||||
* \f$ c_0*x_0 + ... + c_{d-1}*x_{d-1} + c_d = 0 \f$
|
||||
*/
|
||||
inline Coefficients& coeffs() { return m_coeffs; }
|
||||
|
||||
/** \returns the intersection of *this with \a other.
|
||||
*
|
||||
* \warning The ambient space must be a plane, i.e. have dimension 2, so that \c *this and \a other are lines.
|
||||
*
|
||||
* \note If \a other is approximately parallel to *this, this method will return any point on *this.
|
||||
*/
|
||||
VectorType intersection(const Hyperplane& other)
|
||||
{
|
||||
EIGEN_STATIC_ASSERT_VECTOR_SPECIFIC_SIZE(VectorType, 2)
|
||||
Scalar det = coeffs().coeff(0) * other.coeffs().coeff(1) - coeffs().coeff(1) * other.coeffs().coeff(0);
|
||||
// since the line equations ax+by=c are normalized with a^2+b^2=1, the following tests
|
||||
// whether the two lines are approximately parallel.
|
||||
if(ei_isMuchSmallerThan(det, Scalar(1)))
|
||||
{ // special case where the two lines are approximately parallel. Pick any point on the first line.
|
||||
if(ei_abs(coeffs().coeff(1))>ei_abs(coeffs().coeff(0)))
|
||||
return VectorType(coeffs().coeff(1), -coeffs().coeff(2)/coeffs().coeff(1)-coeffs().coeff(0));
|
||||
else
|
||||
return VectorType(-coeffs().coeff(2)/coeffs().coeff(0)-coeffs().coeff(1), coeffs().coeff(0));
|
||||
}
|
||||
|
||||
/** Constructs a plane from its normal \a n and distance to the origin \a d.
|
||||
* \warning the vector normal is assumed to be normalized.
|
||||
*/
|
||||
inline Hyperplane(const VectorType& n, Scalar d)
|
||||
: m_coeffs(n.size()+1)
|
||||
{
|
||||
normal() = n;
|
||||
offset() = d;
|
||||
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)));
|
||||
}
|
||||
}
|
||||
|
||||
/** 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)
|
||||
/** 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
|
||||
{
|
||||
Hyperplane result(p0.size());
|
||||
result.normal() = (p1 - p0).unitOrthogonal();
|
||||
result.offset() = -result.normal().dot(p0);
|
||||
return result;
|
||||
ei_assert("invalid traits value in Hyperplane::transform()");
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
/** Constructs a hyperplane passing through the three points. The dimension of the ambient space
|
||||
* is required to be exactly 3.
|
||||
*/
|
||||
static inline Hyperplane Through(const VectorType& p0, const VectorType& p1, const VectorType& p2)
|
||||
{
|
||||
EIGEN_STATIC_ASSERT_VECTOR_SPECIFIC_SIZE(VectorType, 3);
|
||||
Hyperplane result(p0.size());
|
||||
result.normal() = (p2 - p0).cross(p1 - p0).normalized();
|
||||
result.offset() = -result.normal().dot(p0);
|
||||
return result;
|
||||
}
|
||||
/** Applies the transformation \a t to \c *this and returns a reference to \c *this.
|
||||
*
|
||||
* \param t the transformation of dimension Dim
|
||||
* \param traits specifies whether the transformation \a t represents an Isometry
|
||||
* or a more generic Affine transformation. The default is Affine.
|
||||
* Other kind of transformations are not supported.
|
||||
*/
|
||||
inline Hyperplane& transform(const Transform<Scalar,AmbientDimAtCompileTime>& t,
|
||||
TransformTraits traits = Affine)
|
||||
{
|
||||
transform(t.linear(), traits);
|
||||
offset() -= t.translation().dot(normal());
|
||||
return *this;
|
||||
}
|
||||
|
||||
Hyperplane(const ParametrizedLine<Scalar, AmbientDimAtCompileTime>& parametrized)
|
||||
{
|
||||
normal() = parametrized.direction().unitOrthogonal();
|
||||
offset() = -normal().dot(parametrized.origin());
|
||||
}
|
||||
|
||||
~Hyperplane() {}
|
||||
/** \returns \c *this with scalar type casted to \a NewScalarType
|
||||
*
|
||||
* Note that if \a NewScalarType is equal to the current scalar type of \c *this
|
||||
* then this function smartly returns a const reference to \c *this.
|
||||
*/
|
||||
template<typename NewScalarType>
|
||||
inline typename ei_cast_return_type<Hyperplane,
|
||||
Hyperplane<NewScalarType,AmbientDimAtCompileTime> >::type cast() const
|
||||
{
|
||||
return typename ei_cast_return_type<Hyperplane,
|
||||
Hyperplane<NewScalarType,AmbientDimAtCompileTime> >::type(*this);
|
||||
}
|
||||
|
||||
/** \returns the dimension in which the plane holds */
|
||||
inline int dim() const { return AmbientDimAtCompileTime==Dynamic ? m_coeffs.size()-1 : 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.
|
||||
*/
|
||||
inline Scalar signedDistance(const VectorType& p) const { return p.dot(normal()) + offset(); }
|
||||
/** Copy constructor with scalar type conversion */
|
||||
template<typename OtherScalarType>
|
||||
inline explicit Hyperplane(const Hyperplane<OtherScalarType,AmbientDimAtCompileTime>& other)
|
||||
{ m_coeffs = other.coeffs().template cast<OtherScalarType>(); }
|
||||
|
||||
/** \returns the absolute distance between the plane \c *this and a point \a p.
|
||||
*/
|
||||
inline Scalar absDistance(const VectorType& p) const { return ei_abs(signedDistance(p)); }
|
||||
|
||||
/** \returns the projection of a point \a p onto the plane \c *this.
|
||||
*/
|
||||
inline VectorType projection(const VectorType& p) const { return p - signedDistance(p) * normal(); }
|
||||
|
||||
/** \returns a constant reference to the unit normal vector of the plane, which corresponds
|
||||
* to the linear part of the implicit equation.
|
||||
*/
|
||||
inline const NormalReturnType normal() const { return NormalReturnType(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 *this and \a other are lines.
|
||||
*
|
||||
* \note If \a other is approximately parallel to *this, this method will return any point on *this.
|
||||
*/
|
||||
VectorType intersection(const Hyperplane& other)
|
||||
{
|
||||
EIGEN_STATIC_ASSERT_VECTOR_SPECIFIC_SIZE(VectorType, 2);
|
||||
Scalar det = coeffs().coeff(0) * other.coeffs().coeff(1) - coeffs().coeff(1) * other.coeffs().coeff(0);
|
||||
// since the line equations ax+by=c are normalized with a^2+b^2=1, the following tests
|
||||
// whether the two lines are approximately parallel.
|
||||
if(ei_isMuchSmallerThan(det, Scalar(1)))
|
||||
{ // special case where the two lines are approximately parallel. Pick any point on the first line.
|
||||
if(ei_abs(coeffs().coeff(1))>ei_abs(coeffs().coeff(0)))
|
||||
return VectorType(coeffs().coeff(1), -coeffs().coeff(2)/coeffs().coeff(1)-coeffs().coeff(0));
|
||||
else
|
||||
return VectorType(-coeffs().coeff(2)/coeffs().coeff(0)-coeffs().coeff(1), coeffs().coeff(0));
|
||||
}
|
||||
else
|
||||
{ // general case
|
||||
Scalar invdet = Scalar(1) / det;
|
||||
return VectorType(invdet*(coeffs().coeff(1)*other.coeffs().coeff(2)-other.coeffs().coeff(1)*coeffs().coeff(2)),
|
||||
invdet*(other.coeffs().coeff(0)*coeffs().coeff(2)-coeffs().coeff(0)*other.coeffs().coeff(2)));
|
||||
}
|
||||
}
|
||||
|
||||
template<typename XprType>
|
||||
inline Hyperplane& transform(const MatrixBase<XprType>& mat, TransformTraits traits = Affine)
|
||||
{
|
||||
if (traits==Affine)
|
||||
normal() = mat.inverse().transpose() * normal();
|
||||
else if (traits==Isometry)
|
||||
normal() = mat * normal();
|
||||
else
|
||||
{
|
||||
ei_assert("invalid traits value in Hyperplane::transform()");
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline Hyperplane& transform(const Transform<Scalar,AmbientDimAtCompileTime>& t,
|
||||
TransformTraits traits = Affine)
|
||||
{
|
||||
transform(t.linear(), traits);
|
||||
offset() -= t.translation().dot(normal());
|
||||
return *this;
|
||||
}
|
||||
/** \returns \c true if \c *this is approximately equal to \a other, within the precision
|
||||
* determined by \a prec.
|
||||
*
|
||||
* \sa MatrixBase::isApprox() */
|
||||
bool isApprox(const Hyperplane& other, typename NumTraits<Scalar>::Real prec = precision<Scalar>()) const
|
||||
{ return m_coeffs.isApprox(other.m_coeffs, prec); }
|
||||
|
||||
protected:
|
||||
|
||||
Coefficients m_coeffs;
|
||||
Coefficients m_coeffs;
|
||||
};
|
||||
|
||||
#endif // EIGEN_HYPERPLANE_H
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
// for linear algebra. Eigen itself is part of the KDE project.
|
||||
//
|
||||
// Copyright (C) 2008 Gael Guennebaud <g.gael@free.fr>
|
||||
// Copyright (C) 2006-2008 Benoit Jacob <jacob@math.jussieu.fr>
|
||||
// Copyright (C) 2006-2008 Benoit Jacob <jacob.benoit.1@gmail.com>
|
||||
//
|
||||
// Eigen is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU Lesser General Public
|
||||
@@ -27,13 +27,17 @@
|
||||
#define EIGEN_ORTHOMETHODS_H
|
||||
|
||||
/** \geometry_module
|
||||
* \returns the cross product of \c *this and \a other */
|
||||
*
|
||||
* \returns the cross product of \c *this and \a other
|
||||
*
|
||||
* Here is a very good explanation of cross-product: http://xkcd.com/199/
|
||||
*/
|
||||
template<typename Derived>
|
||||
template<typename OtherDerived>
|
||||
inline typename MatrixBase<Derived>::EvalType
|
||||
MatrixBase<Derived>::cross(const MatrixBase<OtherDerived>& other) const
|
||||
{
|
||||
EIGEN_STATIC_ASSERT_VECTOR_SPECIFIC_SIZE(Derived,3);
|
||||
EIGEN_STATIC_ASSERT_VECTOR_SPECIFIC_SIZE(Derived,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)
|
||||
@@ -108,7 +112,7 @@ template<typename Derived>
|
||||
typename MatrixBase<Derived>::EvalType
|
||||
MatrixBase<Derived>::unitOrthogonal() const
|
||||
{
|
||||
EIGEN_STATIC_ASSERT_VECTOR_ONLY(Derived);
|
||||
EIGEN_STATIC_ASSERT_VECTOR_ONLY(Derived)
|
||||
return ei_unitOrthogonal_selector<Derived>::run(derived());
|
||||
}
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
// for linear algebra. Eigen itself is part of the KDE project.
|
||||
//
|
||||
// Copyright (C) 2008 Gael Guennebaud <g.gael@free.fr>
|
||||
// Copyright (C) 2008 Benoit Jacob <jacob@math.jussieu.fr>
|
||||
// Copyright (C) 2008 Benoit Jacob <jacob.benoit.1@gmail.com>
|
||||
//
|
||||
// Eigen is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU Lesser General Public
|
||||
@@ -32,9 +32,12 @@
|
||||
*
|
||||
* \brief A parametrized line
|
||||
*
|
||||
* A parametrized line is defined by an origin point \f$ \mathbf{o} \f$ and a unit
|
||||
* direction vector \f$ \mathbf{d} \f$ such that the line corresponds to
|
||||
* the set \f$ l(t) = \mathbf{o} + t \mathbf{d} \f$, \f$ l \in \mathbf{R} \f$.
|
||||
*
|
||||
* \param _Scalar the scalar type, i.e., the type of the coefficients
|
||||
* \param _AmbientDim the dimension of the ambient space, can be a compile time value or Dynamic.
|
||||
* Notice that the dimension of the hyperplane is _AmbientDim-1.
|
||||
*/
|
||||
template <typename _Scalar, int _AmbientDim>
|
||||
class ParametrizedLine
|
||||
@@ -42,71 +45,108 @@ class ParametrizedLine
|
||||
: public ei_with_aligned_operator_new<_Scalar,_AmbientDim>
|
||||
#endif
|
||||
{
|
||||
public:
|
||||
public:
|
||||
|
||||
enum { AmbientDimAtCompileTime = _AmbientDim };
|
||||
typedef _Scalar Scalar;
|
||||
typedef typename NumTraits<Scalar>::Real RealScalar;
|
||||
typedef Matrix<Scalar,AmbientDimAtCompileTime,1> VectorType;
|
||||
enum { AmbientDimAtCompileTime = _AmbientDim };
|
||||
typedef _Scalar Scalar;
|
||||
typedef typename NumTraits<Scalar>::Real RealScalar;
|
||||
typedef Matrix<Scalar,AmbientDimAtCompileTime,1> VectorType;
|
||||
|
||||
/** Default constructor without initialization */
|
||||
inline explicit ParametrizedLine(int _dim = AmbientDimAtCompileTime)
|
||||
: m_origin(_dim), m_direction(_dim)
|
||||
{}
|
||||
|
||||
ParametrizedLine(const VectorType& origin, const VectorType& direction)
|
||||
: m_origin(origin), m_direction(direction) {}
|
||||
explicit ParametrizedLine(const Hyperplane<_Scalar, _AmbientDim>& hyperplane);
|
||||
/** Default constructor without initialization */
|
||||
inline explicit ParametrizedLine() {}
|
||||
|
||||
~ParametrizedLine() {}
|
||||
/** Constructs a dynamic-size line with \a _dim the dimension
|
||||
* of the ambient space */
|
||||
inline explicit ParametrizedLine(int _dim) : m_origin(_dim), m_direction(_dim) {}
|
||||
|
||||
/** \returns the dimension in which the line holds */
|
||||
inline int dim() const { return m_direction.size(); }
|
||||
/** 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) {}
|
||||
|
||||
const VectorType& origin() const { return m_origin; }
|
||||
VectorType& origin() { return m_origin; }
|
||||
explicit ParametrizedLine(const Hyperplane<_Scalar, _AmbientDim>& hyperplane);
|
||||
|
||||
const VectorType& direction() const { return m_direction; }
|
||||
VectorType& direction() { return m_direction; }
|
||||
/** 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()); }
|
||||
|
||||
/** \returns the squared distance of a point \a p to its projection onto the line \c *this.
|
||||
* \sa distance()
|
||||
*/
|
||||
RealScalar squaredDistance(const VectorType& p) const
|
||||
{
|
||||
VectorType diff = p-origin();
|
||||
return (diff - diff.dot(direction())* direction()).norm2();
|
||||
}
|
||||
/** \returns the distance of a point \a p to its projection onto the line \c *this.
|
||||
* \sa squaredDistance()
|
||||
*/
|
||||
RealScalar distance(const VectorType& p) const { return ei_sqrt(squaredDistance(p)); }
|
||||
~ParametrizedLine() {}
|
||||
|
||||
/** \returns the projection of a point \a p onto the line \c *this.
|
||||
*/
|
||||
VectorType projection(const VectorType& p) const
|
||||
{ return origin() + (p-origin()).dot(direction()) * direction(); }
|
||||
/** \returns the dimension in which the line holds */
|
||||
inline int dim() const { return m_direction.size(); }
|
||||
|
||||
Scalar intersection(const Hyperplane<_Scalar, _AmbientDim>& hyperplane);
|
||||
const VectorType& origin() const { return m_origin; }
|
||||
VectorType& origin() { return m_origin; }
|
||||
|
||||
protected:
|
||||
const VectorType& direction() const { return m_direction; }
|
||||
VectorType& direction() { return m_direction; }
|
||||
|
||||
VectorType m_origin, m_direction;
|
||||
/** \returns the squared distance of a point \a p to its projection onto the line \c *this.
|
||||
* \sa distance()
|
||||
*/
|
||||
RealScalar squaredDistance(const VectorType& p) const
|
||||
{
|
||||
VectorType diff = p-origin();
|
||||
return (diff - diff.dot(direction())* direction()).squaredNorm();
|
||||
}
|
||||
/** \returns the distance of a point \a p to its projection onto the line \c *this.
|
||||
* \sa squaredDistance()
|
||||
*/
|
||||
RealScalar distance(const VectorType& p) const { return ei_sqrt(squaredDistance(p)); }
|
||||
|
||||
/** \returns the projection of a point \a p onto the line \c *this. */
|
||||
VectorType projection(const VectorType& p) const
|
||||
{ return origin() + (p-origin()).dot(direction()) * direction(); }
|
||||
|
||||
Scalar intersection(const Hyperplane<_Scalar, _AmbientDim>& hyperplane);
|
||||
|
||||
/** \returns \c *this with scalar type casted to \a NewScalarType
|
||||
*
|
||||
* Note that if \a NewScalarType is equal to the current scalar type of \c *this
|
||||
* then this function smartly returns a const reference to \c *this.
|
||||
*/
|
||||
template<typename NewScalarType>
|
||||
inline typename ei_cast_return_type<ParametrizedLine,
|
||||
ParametrizedLine<NewScalarType,AmbientDimAtCompileTime> >::type cast() const
|
||||
{
|
||||
return typename ei_cast_return_type<ParametrizedLine,
|
||||
ParametrizedLine<NewScalarType,AmbientDimAtCompileTime> >::type(*this);
|
||||
}
|
||||
|
||||
/** Copy constructor with scalar type conversion */
|
||||
template<typename OtherScalarType>
|
||||
inline explicit ParametrizedLine(const ParametrizedLine<OtherScalarType,AmbientDimAtCompileTime>& other)
|
||||
{
|
||||
m_origin = other.origin().template cast<OtherScalarType>();
|
||||
m_direction = other.direction().template cast<OtherScalarType>();
|
||||
}
|
||||
|
||||
/** \returns \c true if \c *this is approximately equal to \a other, within the precision
|
||||
* determined by \a prec.
|
||||
*
|
||||
* \sa MatrixBase::isApprox() */
|
||||
bool isApprox(const ParametrizedLine& other, typename NumTraits<Scalar>::Real prec = precision<Scalar>()) const
|
||||
{ return m_origin.isApprox(other.m_origin, prec) && m_direction.isApprox(other.m_direction, prec); }
|
||||
|
||||
protected:
|
||||
|
||||
VectorType m_origin, m_direction;
|
||||
};
|
||||
|
||||
/** Construct a parametrized line from a 2D hyperplane
|
||||
/** Constructs a parametrized line from a 2D hyperplane
|
||||
*
|
||||
* \warning the ambient space must have dimension 2 such that the hyperplane actually describes a line
|
||||
*/
|
||||
template <typename _Scalar, int _AmbientDim>
|
||||
inline ParametrizedLine<_Scalar, _AmbientDim>::ParametrizedLine(const Hyperplane<_Scalar, _AmbientDim>& hyperplane)
|
||||
{
|
||||
EIGEN_STATIC_ASSERT_VECTOR_SPECIFIC_SIZE(VectorType, 2);
|
||||
EIGEN_STATIC_ASSERT_VECTOR_SPECIFIC_SIZE(VectorType, 2)
|
||||
direction() = hyperplane.normal().unitOrthogonal();
|
||||
origin() = -hyperplane.normal()*hyperplane.offset();
|
||||
}
|
||||
|
||||
/** \returns the parameter value of the intersection between *this and the given hyperplane
|
||||
/** \returns the parameter value of the intersection between \c *this and the given hyperplane
|
||||
*/
|
||||
template <typename _Scalar, int _AmbientDim>
|
||||
inline _Scalar ParametrizedLine<_Scalar, _AmbientDim>::intersection(const Hyperplane<_Scalar, _AmbientDim>& hyperplane)
|
||||
|
||||
@@ -117,7 +117,7 @@ public:
|
||||
|
||||
/** 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]
|
||||
@@ -154,21 +154,21 @@ public:
|
||||
inline Quaternion& setIdentity() { m_coeffs << 1, 0, 0, 0; return *this; }
|
||||
|
||||
/** \returns the squared norm of the quaternion's coefficients
|
||||
* \sa Quaternion::norm(), MatrixBase::norm2()
|
||||
* \sa Quaternion::norm(), MatrixBase::squaredNorm()
|
||||
*/
|
||||
inline Scalar norm2() const { return m_coeffs.norm2(); }
|
||||
inline Scalar squaredNorm() const { return m_coeffs.squaredNorm(); }
|
||||
|
||||
/** \returns the norm of the quaternion's coefficients
|
||||
* \sa Quaternion::norm2(), MatrixBase::norm()
|
||||
* \sa Quaternion::squaredNorm(), MatrixBase::norm()
|
||||
*/
|
||||
inline Scalar norm() const { return m_coeffs.norm(); }
|
||||
|
||||
/** Normalizes the quaternion \c *this
|
||||
|
||||
/** Normalizes the quaternion \c *this
|
||||
* \sa normalized(), MatrixBase::normalize() */
|
||||
inline void normalize() { m_coeffs.normalize(); }
|
||||
inline void normalize() { m_coeffs.normalize(); }
|
||||
/** \returns a normalized version of \c *this
|
||||
* \sa normalize(), MatrixBase::normalized() */
|
||||
inline Quaternion normalized() const { Quaternion(m_coeffs.normalized()); }
|
||||
inline Quaternion normalized() const { return Quaternion(m_coeffs.normalized()); }
|
||||
|
||||
/** \returns the dot product of \c *this and \a other
|
||||
* Geometrically speaking, the dot product of two unit quaternions
|
||||
@@ -195,6 +195,27 @@ public:
|
||||
template<typename Derived>
|
||||
Vector3 operator* (const MatrixBase<Derived>& vec) const;
|
||||
|
||||
/** \returns \c *this with scalar type casted to \a NewScalarType
|
||||
*
|
||||
* Note that if \a NewScalarType is equal to the current scalar type of \c *this
|
||||
* then this function smartly returns a const reference to \c *this.
|
||||
*/
|
||||
template<typename NewScalarType>
|
||||
inline typename ei_cast_return_type<Quaternion,Quaternion<NewScalarType> >::type cast() const
|
||||
{ return typename ei_cast_return_type<Quaternion,Quaternion<NewScalarType> >::type(*this); }
|
||||
|
||||
/** Copy constructor with scalar type conversion */
|
||||
template<typename OtherScalarType>
|
||||
inline explicit Quaternion(const Quaternion<OtherScalarType>& other)
|
||||
{ m_coeffs = other.coeffs().template cast<OtherScalarType>(); }
|
||||
|
||||
/** \returns \c true if \c *this is approximately equal to \a other, within the precision
|
||||
* determined by \a prec.
|
||||
*
|
||||
* \sa MatrixBase::isApprox() */
|
||||
bool isApprox(const Quaternion& other, typename NumTraits<Scalar>::Real prec = precision<Scalar>()) const
|
||||
{ return m_coeffs.isApprox(other.m_coeffs, prec); }
|
||||
|
||||
};
|
||||
|
||||
/** \ingroup GeometryModule
|
||||
@@ -288,18 +309,18 @@ Quaternion<Scalar>::toRotationMatrix(void) const
|
||||
// it has to be inlined, and so the return by value is not an issue
|
||||
Matrix3 res;
|
||||
|
||||
Scalar tx = 2*this->x();
|
||||
Scalar ty = 2*this->y();
|
||||
Scalar tz = 2*this->z();
|
||||
Scalar twx = tx*this->w();
|
||||
Scalar twy = ty*this->w();
|
||||
Scalar twz = tz*this->w();
|
||||
Scalar txx = tx*this->x();
|
||||
Scalar txy = ty*this->x();
|
||||
Scalar txz = tz*this->x();
|
||||
Scalar tyy = ty*this->y();
|
||||
Scalar tyz = tz*this->y();
|
||||
Scalar tzz = tz*this->z();
|
||||
const Scalar tx = 2*this->x();
|
||||
const Scalar ty = 2*this->y();
|
||||
const Scalar tz = 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) = 1-(tyy+tzz);
|
||||
res.coeffRef(0,1) = txy-twz;
|
||||
@@ -314,9 +335,11 @@ Quaternion<Scalar>::toRotationMatrix(void) const
|
||||
return res;
|
||||
}
|
||||
|
||||
/** Makes a quaternion representing the rotation between two vectors \a a and \a b.
|
||||
* \returns a reference to the actual quaternion
|
||||
* Note that the two input vectors have \b not to be normalized.
|
||||
/** Sets *this to be a quaternion representing a rotation sending the vector \a a to the vector \a b.
|
||||
*
|
||||
* \returns a reference to *this.
|
||||
*
|
||||
* Note that the two input vectors do \b not have to be normalized.
|
||||
*/
|
||||
template<typename Scalar>
|
||||
template<typename Derived1, typename Derived2>
|
||||
@@ -334,9 +357,9 @@ inline Quaternion<Scalar>& Quaternion<Scalar>::setFromTwoVectors(const MatrixBas
|
||||
this->w() = 1; this->vec().setZero();
|
||||
}
|
||||
Scalar s = ei_sqrt((1+c)*2);
|
||||
Scalar invs = 1./s;
|
||||
Scalar invs = Scalar(1)/s;
|
||||
this->vec() = axis * invs;
|
||||
this->w() = s * 0.5;
|
||||
this->w() = s * Scalar(0.5);
|
||||
|
||||
return *this;
|
||||
}
|
||||
@@ -351,7 +374,7 @@ template <typename Scalar>
|
||||
inline Quaternion<Scalar> Quaternion<Scalar>::inverse() const
|
||||
{
|
||||
// FIXME should this function be called multiplicativeInverse and conjugate() be called inverse() or opposite() ??
|
||||
Scalar n2 = this->norm2();
|
||||
Scalar n2 = this->squaredNorm();
|
||||
if (n2 > 0)
|
||||
return Quaternion(conjugate().coeffs() / n2);
|
||||
else
|
||||
@@ -382,7 +405,7 @@ inline Scalar Quaternion<Scalar>::angularDistance(const Quaternion& other) const
|
||||
double d = ei_abs(this->dot(other));
|
||||
if (d>=1.0)
|
||||
return 0;
|
||||
return 2.0 * std::acos(d);
|
||||
return Scalar(2) * std::acos(d);
|
||||
}
|
||||
|
||||
/** \returns the spherical linear interpolation between the two quaternions
|
||||
@@ -439,8 +462,8 @@ struct ei_quaternion_assign_impl<Other,3,3>
|
||||
int k = (j+1)%3;
|
||||
|
||||
t = ei_sqrt(mat.coeff(i,i)-mat.coeff(j,j)-mat.coeff(k,k) + 1.0);
|
||||
q.coeffs().coeffRef(i) = 0.5 * t;
|
||||
t = 0.5/t;
|
||||
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;
|
||||
|
||||
@@ -100,6 +100,29 @@ public:
|
||||
*/
|
||||
inline Rotation2D slerp(Scalar t, const Rotation2D& other) const
|
||||
{ return m_angle * (1-t) + other.angle() * t; }
|
||||
|
||||
/** \returns \c *this with scalar type casted to \a NewScalarType
|
||||
*
|
||||
* Note that if \a NewScalarType is equal to the current scalar type of \c *this
|
||||
* then this function smartly returns a const reference to \c *this.
|
||||
*/
|
||||
template<typename NewScalarType>
|
||||
inline typename ei_cast_return_type<Rotation2D,Rotation2D<NewScalarType> >::type cast() const
|
||||
{ return typename ei_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 = other.angle();
|
||||
}
|
||||
|
||||
/** \returns \c true if \c *this is approximately equal to \a other, within the precision
|
||||
* determined by \a prec.
|
||||
*
|
||||
* \sa MatrixBase::isApprox() */
|
||||
bool isApprox(const Rotation2D& other, typename NumTraits<Scalar>::Real prec = precision<Scalar>()) const
|
||||
{ return ei_isApprox(m_angle,other.m_angle, prec); }
|
||||
};
|
||||
|
||||
/** \ingroup GeometryModule
|
||||
@@ -117,7 +140,7 @@ template<typename Scalar>
|
||||
template<typename Derived>
|
||||
Rotation2D<Scalar>& Rotation2D<Scalar>::fromRotationMatrix(const MatrixBase<Derived>& mat)
|
||||
{
|
||||
EIGEN_STATIC_ASSERT(Derived::RowsAtCompileTime==2 && Derived::ColsAtCompileTime==2,you_did_a_programming_error);
|
||||
EIGEN_STATIC_ASSERT(Derived::RowsAtCompileTime==2 && Derived::ColsAtCompileTime==2,you_made_a_programming_mistake)
|
||||
m_angle = ei_atan2(mat.coeff(1,0), mat.coeff(0,0));
|
||||
return *this;
|
||||
}
|
||||
|
||||
@@ -77,7 +77,7 @@ 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));
|
||||
EIGEN_STATIC_ASSERT_MATRIX_SPECIFIC_SIZE(Matrix,int(OtherDerived::Dim),int(OtherDerived::Dim))
|
||||
*this = r.toRotationMatrix();
|
||||
}
|
||||
|
||||
@@ -91,7 +91,7 @@ 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));
|
||||
EIGEN_STATIC_ASSERT_MATRIX_SPECIFIC_SIZE(Matrix,int(OtherDerived::Dim),int(OtherDerived::Dim))
|
||||
return *this = r.toRotationMatrix();
|
||||
}
|
||||
|
||||
@@ -116,7 +116,7 @@ Matrix<_Scalar, _Rows, _Cols, _Storage, _MaxRows, _MaxCols>
|
||||
template<typename Scalar, int Dim>
|
||||
inline static Matrix<Scalar,2,2> ei_toRotationMatrix(const Scalar& s)
|
||||
{
|
||||
EIGEN_STATIC_ASSERT(Dim==2,you_did_a_programming_error);
|
||||
EIGEN_STATIC_ASSERT(Dim==2,you_made_a_programming_mistake)
|
||||
return Rotation2D<Scalar>(s).toRotationMatrix();
|
||||
}
|
||||
|
||||
@@ -130,7 +130,7 @@ template<typename Scalar, int Dim, typename OtherDerived>
|
||||
inline static const MatrixBase<OtherDerived>& ei_toRotationMatrix(const MatrixBase<OtherDerived>& mat)
|
||||
{
|
||||
EIGEN_STATIC_ASSERT(OtherDerived::RowsAtCompileTime==Dim && OtherDerived::ColsAtCompileTime==Dim,
|
||||
you_did_a_programming_error);
|
||||
you_made_a_programming_mistake)
|
||||
return mat;
|
||||
}
|
||||
|
||||
|
||||
@@ -35,7 +35,7 @@
|
||||
* \param _Dim the dimension of the space, can be a compile time value or Dynamic
|
||||
*
|
||||
* \note This class is not aimed to be used to store a scaling transformation,
|
||||
* but rather to make easier the constructions and updates of Transformation object.
|
||||
* but rather to make easier the constructions and updates of Transform objects.
|
||||
*
|
||||
* \sa class Translation, class Transform
|
||||
*/
|
||||
@@ -128,6 +128,27 @@ public:
|
||||
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 ei_cast_return_type<Scaling,Scaling<NewScalarType,Dim> >::type cast() const
|
||||
{ return typename ei_cast_return_type<Scaling,Scaling<NewScalarType,Dim> >::type(*this); }
|
||||
|
||||
/** Copy constructor with scalar type conversion */
|
||||
template<typename OtherScalarType>
|
||||
inline explicit Scaling(const Scaling<OtherScalarType,Dim>& other)
|
||||
{ m_coeffs = other.coeffs().template cast<OtherScalarType>(); }
|
||||
|
||||
/** \returns \c true if \c *this is approximately equal to \a other, within the precision
|
||||
* determined by \a prec.
|
||||
*
|
||||
* \sa MatrixBase::isApprox() */
|
||||
bool isApprox(const Scaling& other, typename NumTraits<Scalar>::Real prec = precision<Scalar>()) const
|
||||
{ return m_coeffs.isApprox(other.m_coeffs, prec); }
|
||||
|
||||
};
|
||||
|
||||
/** \addtogroup GeometryModule */
|
||||
|
||||
@@ -100,6 +100,11 @@ public:
|
||||
inline Transform(const Transform& other)
|
||||
{ m_matrix = other.m_matrix; }
|
||||
|
||||
inline explicit Transform(const TranslationType& t) { *this = t; }
|
||||
inline explicit Transform(const ScalingType& s) { *this = s; }
|
||||
template<typename Derived>
|
||||
inline explicit Transform(const RotationBase<Derived, Dim>& r) { *this = r; }
|
||||
|
||||
inline Transform& operator=(const Transform& other)
|
||||
{ m_matrix = other.m_matrix; return *this; }
|
||||
|
||||
@@ -226,8 +231,8 @@ public:
|
||||
return res;
|
||||
}
|
||||
|
||||
// template<typename Derived>
|
||||
// inline Transform& operator=(const Rotation<Derived,Dim>& t);
|
||||
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>
|
||||
@@ -241,9 +246,32 @@ public:
|
||||
|
||||
inline const MatrixType inverse(TransformTraits traits = Affine) const;
|
||||
|
||||
/** \returns a const pointer to the column major internal matrix */
|
||||
const Scalar* data() const { return m_matrix.data(); }
|
||||
/** \returns a non-const pointer to the column major internal matrix */
|
||||
Scalar* data() { return m_matrix.data(); }
|
||||
|
||||
/** \returns \c *this with scalar type casted to \a NewScalarType
|
||||
*
|
||||
* Note that if \a NewScalarType is equal to the current scalar type of \c *this
|
||||
* then this function smartly returns a const reference to \c *this.
|
||||
*/
|
||||
template<typename NewScalarType>
|
||||
inline typename ei_cast_return_type<Transform,Transform<NewScalarType,Dim> >::type cast() const
|
||||
{ return typename ei_cast_return_type<Transform,Transform<NewScalarType,Dim> >::type(*this); }
|
||||
|
||||
/** Copy constructor with scalar type conversion */
|
||||
template<typename OtherScalarType>
|
||||
inline explicit Transform(const Transform<OtherScalarType,Dim>& other)
|
||||
{ m_matrix = other.matrix().template cast<OtherScalarType>(); }
|
||||
|
||||
/** \returns \c true if \c *this is approximately equal to \a other, within the precision
|
||||
* determined by \a prec.
|
||||
*
|
||||
* \sa MatrixBase::isApprox() */
|
||||
bool isApprox(const Transform& other, typename NumTraits<Scalar>::Real prec = precision<Scalar>()) const
|
||||
{ return m_matrix.isApprox(other.m_matrix, prec); }
|
||||
|
||||
protected:
|
||||
|
||||
};
|
||||
@@ -279,7 +307,7 @@ Transform<Scalar,Dim>::Transform(const QMatrix& other)
|
||||
template<typename Scalar, int Dim>
|
||||
Transform<Scalar,Dim>& Transform<Scalar,Dim>::operator=(const QMatrix& other)
|
||||
{
|
||||
EIGEN_STATIC_ASSERT(Dim==2, you_did_a_programming_error);
|
||||
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;
|
||||
@@ -295,7 +323,7 @@ Transform<Scalar,Dim>& Transform<Scalar,Dim>::operator=(const QMatrix& other)
|
||||
template<typename Scalar, int Dim>
|
||||
QMatrix Transform<Scalar,Dim>::toQMatrix(void) const
|
||||
{
|
||||
EIGEN_STATIC_ASSERT(Dim==2, you_did_a_programming_error);
|
||||
EIGEN_STATIC_ASSERT(Dim==2, you_made_a_programming_mistake)
|
||||
return QMatrix(other.coeffRef(0,0), other.coeffRef(1,0),
|
||||
other.coeffRef(0,1), other.coeffRef(1,1),
|
||||
other.coeffRef(0,2), other.coeffRef(1,2));
|
||||
@@ -318,7 +346,7 @@ Transform<Scalar,Dim>::Transform(const QTransform& other)
|
||||
template<typename Scalar, int Dim>
|
||||
Transform<Scalar,Dim>& Transform<Scalar,Dim>::operator=(const QTransform& other)
|
||||
{
|
||||
EIGEN_STATIC_ASSERT(Dim==2, you_did_a_programming_error);
|
||||
EIGEN_STATIC_ASSERT(Dim==2, you_made_a_programming_mistake)
|
||||
m_matrix << other.m11(), other.m21(), other.dx(),
|
||||
other.m12(), other.m22(), other.dy(),
|
||||
other.m13(), other.m23(), other.m33();
|
||||
@@ -332,7 +360,7 @@ Transform<Scalar,Dim>& Transform<Scalar,Dim>::operator=(const QTransform& other)
|
||||
template<typename Scalar, int Dim>
|
||||
QMatrix Transform<Scalar,Dim>::toQTransform(void) const
|
||||
{
|
||||
EIGEN_STATIC_ASSERT(Dim==2, you_did_a_programming_error);
|
||||
EIGEN_STATIC_ASSERT(Dim==2, you_made_a_programming_mistake)
|
||||
return QTransform(other.coeffRef(0,0), other.coeffRef(1,0), other.coeffRef(2,0)
|
||||
other.coeffRef(0,1), other.coeffRef(1,1), other.coeffRef(2,1)
|
||||
other.coeffRef(0,2), other.coeffRef(1,2), other.coeffRef(2,2);
|
||||
@@ -352,7 +380,7 @@ template<typename OtherDerived>
|
||||
Transform<Scalar,Dim>&
|
||||
Transform<Scalar,Dim>::scale(const MatrixBase<OtherDerived> &other)
|
||||
{
|
||||
EIGEN_STATIC_ASSERT_VECTOR_SPECIFIC_SIZE(OtherDerived,int(Dim));
|
||||
EIGEN_STATIC_ASSERT_VECTOR_SPECIFIC_SIZE(OtherDerived,int(Dim))
|
||||
linear() = (linear() * other.asDiagonal()).lazy();
|
||||
return *this;
|
||||
}
|
||||
@@ -377,7 +405,7 @@ template<typename OtherDerived>
|
||||
Transform<Scalar,Dim>&
|
||||
Transform<Scalar,Dim>::prescale(const MatrixBase<OtherDerived> &other)
|
||||
{
|
||||
EIGEN_STATIC_ASSERT_VECTOR_SPECIFIC_SIZE(OtherDerived,int(Dim));
|
||||
EIGEN_STATIC_ASSERT_VECTOR_SPECIFIC_SIZE(OtherDerived,int(Dim))
|
||||
m_matrix.template block<Dim,HDim>(0,0) = (other.asDiagonal() * m_matrix.template block<Dim,HDim>(0,0)).lazy();
|
||||
return *this;
|
||||
}
|
||||
@@ -402,7 +430,7 @@ template<typename OtherDerived>
|
||||
Transform<Scalar,Dim>&
|
||||
Transform<Scalar,Dim>::translate(const MatrixBase<OtherDerived> &other)
|
||||
{
|
||||
EIGEN_STATIC_ASSERT_VECTOR_SPECIFIC_SIZE(OtherDerived,int(Dim));
|
||||
EIGEN_STATIC_ASSERT_VECTOR_SPECIFIC_SIZE(OtherDerived,int(Dim))
|
||||
translation() += linear() * other;
|
||||
return *this;
|
||||
}
|
||||
@@ -416,7 +444,7 @@ template<typename OtherDerived>
|
||||
Transform<Scalar,Dim>&
|
||||
Transform<Scalar,Dim>::pretranslate(const MatrixBase<OtherDerived> &other)
|
||||
{
|
||||
EIGEN_STATIC_ASSERT_VECTOR_SPECIFIC_SIZE(OtherDerived,int(Dim));
|
||||
EIGEN_STATIC_ASSERT_VECTOR_SPECIFIC_SIZE(OtherDerived,int(Dim))
|
||||
translation() += other;
|
||||
return *this;
|
||||
}
|
||||
@@ -473,7 +501,7 @@ template<typename Scalar, int Dim>
|
||||
Transform<Scalar,Dim>&
|
||||
Transform<Scalar,Dim>::shear(Scalar sx, Scalar sy)
|
||||
{
|
||||
EIGEN_STATIC_ASSERT(int(Dim)==2, you_did_a_programming_error);
|
||||
EIGEN_STATIC_ASSERT(int(Dim)==2, you_made_a_programming_mistake)
|
||||
VectorType tmp = linear().col(0)*sy + linear().col(1);
|
||||
linear() << linear().col(0) + linear().col(1)*sx, tmp;
|
||||
return *this;
|
||||
@@ -488,7 +516,7 @@ template<typename Scalar, int Dim>
|
||||
Transform<Scalar,Dim>&
|
||||
Transform<Scalar,Dim>::preshear(Scalar sx, Scalar sy)
|
||||
{
|
||||
EIGEN_STATIC_ASSERT(int(Dim)==2, you_did_a_programming_error);
|
||||
EIGEN_STATIC_ASSERT(int(Dim)==2, you_made_a_programming_mistake)
|
||||
m_matrix.template block<Dim,HDim>(0,0) = LinearMatrixType(1, sx, sy, 1) * m_matrix.template block<Dim,HDim>(0,0);
|
||||
return *this;
|
||||
}
|
||||
@@ -500,8 +528,10 @@ Transform<Scalar,Dim>::preshear(Scalar sx, Scalar sy)
|
||||
template<typename Scalar, int Dim>
|
||||
inline Transform<Scalar,Dim>& Transform<Scalar,Dim>::operator=(const TranslationType& t)
|
||||
{
|
||||
setIdentity();
|
||||
linear().setIdentity;
|
||||
translation() = t.vector();
|
||||
m_matrix.template block<1,Dim>(Dim,0).setZero();
|
||||
m_matrix(Dim,Dim) = Scalar(1);
|
||||
return *this;
|
||||
}
|
||||
|
||||
@@ -530,6 +560,17 @@ inline Transform<Scalar,Dim> Transform<Scalar,Dim>::operator*(const ScalingType&
|
||||
return res;
|
||||
}
|
||||
|
||||
template<typename Scalar, int Dim>
|
||||
template<typename Derived>
|
||||
inline Transform<Scalar,Dim>& Transform<Scalar,Dim>::operator=(const RotationBase<Derived,Dim>& r)
|
||||
{
|
||||
linear() = ei_toRotationMatrix<Scalar,Dim>(r);
|
||||
translation().setZero();
|
||||
m_matrix.template block<1,Dim>(Dim,0).setZero();
|
||||
m_matrix(Dim,Dim) = Scalar(1);
|
||||
return *this;
|
||||
}
|
||||
|
||||
template<typename Scalar, int Dim>
|
||||
template<typename Derived>
|
||||
inline Transform<Scalar,Dim> Transform<Scalar,Dim>::operator*(const RotationBase<Derived,Dim>& r) const
|
||||
@@ -594,8 +635,8 @@ Transform<Scalar,Dim>::fromPositionOrientationScale(const MatrixBase<PositionDer
|
||||
linear() = ei_toRotationMatrix<Scalar,Dim>(orientation);
|
||||
linear() *= scale.asDiagonal();
|
||||
translation() = position;
|
||||
m_matrix(Dim,Dim) = 1.;
|
||||
m_matrix.template block<1,Dim>(Dim,0).setZero();
|
||||
m_matrix(Dim,Dim) = Scalar(1);
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
@@ -35,7 +35,7 @@
|
||||
* \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 Transformation object.
|
||||
* but rather to make easier the constructions and updates of Transform objects.
|
||||
*
|
||||
* \sa class Scaling, class Transform
|
||||
*/
|
||||
@@ -91,7 +91,7 @@ public:
|
||||
/** Concatenates two translation */
|
||||
inline Translation operator* (const Translation& other) const
|
||||
{ return Translation(m_coeffs + other.m_coeffs); }
|
||||
|
||||
|
||||
/** Concatenates a translation and a scaling */
|
||||
inline TransformType operator* (const ScalingType& other) const;
|
||||
|
||||
@@ -131,6 +131,27 @@ public:
|
||||
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 ei_cast_return_type<Translation,Translation<NewScalarType,Dim> >::type cast() const
|
||||
{ return typename ei_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<OtherScalarType>(); }
|
||||
|
||||
/** \returns \c true if \c *this is approximately equal to \a other, within the precision
|
||||
* determined by \a prec.
|
||||
*
|
||||
* \sa MatrixBase::isApprox() */
|
||||
bool isApprox(const Translation& other, typename NumTraits<Scalar>::Real prec = precision<Scalar>()) const
|
||||
{ return m_coeffs.isApprox(other.m_coeffs, prec); }
|
||||
|
||||
};
|
||||
|
||||
/** \addtogroup GeometryModule */
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
// This file is part of Eigen, a lightweight C++ template library
|
||||
// for linear algebra. Eigen itself is part of the KDE project.
|
||||
//
|
||||
// Copyright (C) 2008 Benoit Jacob <jacob@math.jussieu.fr>
|
||||
// Copyright (C) 2008 Benoit Jacob <jacob.benoit.1@gmail.com>
|
||||
//
|
||||
// Eigen is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU Lesser General Public
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
// This file is part of Eigen, a lightweight C++ template library
|
||||
// for linear algebra. Eigen itself is part of the KDE project.
|
||||
//
|
||||
// Copyright (C) 2008 Benoit Jacob <jacob@math.jussieu.fr>
|
||||
// Copyright (C) 2008 Benoit Jacob <jacob.benoit.1@gmail.com>
|
||||
//
|
||||
// Eigen is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU Lesser General Public
|
||||
@@ -220,7 +220,7 @@ inline void MatrixBase<Derived>::computeInverse(EvalType *result) const
|
||||
{
|
||||
typedef typename ei_eval<Derived>::type MatrixType;
|
||||
ei_assert(rows() == cols());
|
||||
EIGEN_STATIC_ASSERT(NumTraits<Scalar>::HasFloatingPoint,scalar_type_must_be_floating_point);
|
||||
EIGEN_STATIC_ASSERT(NumTraits<Scalar>::HasFloatingPoint,numeric_type_must_be_floating_point)
|
||||
ei_compute_inverse<MatrixType>::run(eval(), result);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
// This file is part of Eigen, a lightweight C++ template library
|
||||
// for linear algebra. Eigen itself is part of the KDE project.
|
||||
//
|
||||
// Copyright (C) 2006-2008 Benoit Jacob <jacob@math.jussieu.fr>
|
||||
// Copyright (C) 2006-2008 Benoit Jacob <jacob.benoit.1@gmail.com>
|
||||
//
|
||||
// Eigen is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU Lesser General Public
|
||||
@@ -181,7 +181,8 @@ template<typename MatrixType> class LU
|
||||
* \returns true if any solution exists, false if no solution exists.
|
||||
*
|
||||
* \note If there exist more than one solution, this method will arbitrarily choose one.
|
||||
* If you need a complete analysis of the space of solutions, take the one solution obtained * by this method and add to it elements of the kernel, as determined by kernel().
|
||||
* If you need a complete analysis of the space of solutions, take the one solution obtained
|
||||
* by this method and add to it elements of the kernel, as determined by kernel().
|
||||
*
|
||||
* Example: \include LU_solve.cpp
|
||||
* Output: \verbinclude LU_solve.out
|
||||
@@ -189,10 +190,7 @@ template<typename MatrixType> class LU
|
||||
* \sa MatrixBase::solveTriangular(), kernel(), computeKernel(), inverse(), computeInverse()
|
||||
*/
|
||||
template<typename OtherDerived, typename ResultType>
|
||||
bool solve(
|
||||
const MatrixBase<OtherDerived>& b,
|
||||
ResultType *result
|
||||
) const;
|
||||
bool solve(const MatrixBase<OtherDerived>& b, ResultType *result) const;
|
||||
|
||||
/** \returns the determinant of the matrix of which
|
||||
* *this is the LU decomposition. It has only linear complexity
|
||||
|
||||
@@ -26,6 +26,7 @@
|
||||
#define EIGEN_EIGENSOLVER_H
|
||||
|
||||
/** \ingroup QR_Module
|
||||
* \nonstableyet
|
||||
*
|
||||
* \class EigenSolver
|
||||
*
|
||||
@@ -48,6 +49,7 @@ template<typename _MatrixType> class EigenSolver
|
||||
typedef typename NumTraits<Scalar>::Real RealScalar;
|
||||
typedef std::complex<RealScalar> Complex;
|
||||
typedef Matrix<Complex, MatrixType::ColsAtCompileTime, 1> EigenvalueType;
|
||||
typedef Matrix<Complex, MatrixType::RowsAtCompileTime, MatrixType::ColsAtCompileTime> EigenvectorType;
|
||||
typedef Matrix<RealScalar, MatrixType::ColsAtCompileTime, 1> RealVectorType;
|
||||
typedef Matrix<RealScalar, Dynamic, 1> RealVectorTypeX;
|
||||
|
||||
@@ -58,9 +60,46 @@ template<typename _MatrixType> class EigenSolver
|
||||
compute(matrix);
|
||||
}
|
||||
|
||||
MatrixType eigenvectors(void) const { return m_eivec; }
|
||||
|
||||
EigenvalueType eigenvalues(void) const { return m_eivalues; }
|
||||
EigenvectorType eigenvectors(void) const;
|
||||
|
||||
/** \returns a real matrix V of pseudo eigenvectors.
|
||||
*
|
||||
* Let D be the block diagonal matrix with the real eigenvalues in 1x1 blocks,
|
||||
* and any complex values u+iv in 2x2 blocks [u v ; -v u]. Then, the matrices D
|
||||
* and V satisfy A*V = V*D.
|
||||
*
|
||||
* More precisely, if the diagonal matrix of the eigen values is:\n
|
||||
* \f$
|
||||
* \left[ \begin{array}{cccccc}
|
||||
* u+iv & & & & & \\
|
||||
* & u-iv & & & & \\
|
||||
* & & a+ib & & & \\
|
||||
* & & & a-ib & & \\
|
||||
* & & & & x & \\
|
||||
* & & & & & y \\
|
||||
* \end{array} \right]
|
||||
* \f$ \n
|
||||
* then, we have:\n
|
||||
* \f$
|
||||
* D =\left[ \begin{array}{cccccc}
|
||||
* u & v & & & & \\
|
||||
* -v & u & & & & \\
|
||||
* & & a & b & & \\
|
||||
* & & -b & a & & \\
|
||||
* & & & & x & \\
|
||||
* & & & & & y \\
|
||||
* \end{array} \right]
|
||||
* \f$
|
||||
*
|
||||
* \sa pseudoEigenvalueMatrix()
|
||||
*/
|
||||
const MatrixType& pseudoEigenvectors() const { return m_eivec; }
|
||||
|
||||
MatrixType pseudoEigenvalueMatrix() const;
|
||||
|
||||
/** \returns the eigenvalues as a column vector */
|
||||
EigenvalueType eigenvalues() const { return m_eivalues; }
|
||||
|
||||
void compute(const MatrixType& matrix);
|
||||
|
||||
@@ -74,6 +113,61 @@ template<typename _MatrixType> class EigenSolver
|
||||
EigenvalueType m_eivalues;
|
||||
};
|
||||
|
||||
/** \returns the real block diagonal matrix D of the eigenvalues.
|
||||
*
|
||||
* See pseudoEigenvectors() for the details.
|
||||
*/
|
||||
template<typename MatrixType>
|
||||
MatrixType EigenSolver<MatrixType>::pseudoEigenvalueMatrix() const
|
||||
{
|
||||
int n = m_eivec.cols();
|
||||
MatrixType matD = MatrixType::Zero(n,n);
|
||||
for (int i=0; i<n; i++)
|
||||
{
|
||||
if (ei_isMuchSmallerThan(ei_imag(m_eivalues.coeff(i)), ei_real(m_eivalues.coeff(i))))
|
||||
matD.coeffRef(i,i) = ei_real(m_eivalues.coeff(i));
|
||||
else
|
||||
{
|
||||
matD.template block<2,2>(i,i) << ei_real(m_eivalues.coeff(i)), ei_imag(m_eivalues.coeff(i)),
|
||||
-ei_imag(m_eivalues.coeff(i)), ei_real(m_eivalues.coeff(i));
|
||||
i++;
|
||||
}
|
||||
}
|
||||
return matD;
|
||||
}
|
||||
|
||||
/** \returns the normalized complex eigenvectors as a matrix of column vectors.
|
||||
*
|
||||
* \sa eigenvalues(), pseudoEigenvectors()
|
||||
*/
|
||||
template<typename MatrixType>
|
||||
typename EigenSolver<MatrixType>::EigenvectorType EigenSolver<MatrixType>::eigenvectors(void) const
|
||||
{
|
||||
int n = m_eivec.cols();
|
||||
EigenvectorType matV(n,n);
|
||||
for (int j=0; j<n; j++)
|
||||
{
|
||||
if (ei_isMuchSmallerThan(ei_abs(ei_imag(m_eivalues.coeff(j))), ei_abs(ei_real(m_eivalues.coeff(j)))))
|
||||
{
|
||||
// we have a real eigen value
|
||||
matV.col(j) = m_eivec.col(j);
|
||||
}
|
||||
else
|
||||
{
|
||||
// we have a pair of complex eigen values
|
||||
for (int i=0; i<n; i++)
|
||||
{
|
||||
matV.coeffRef(i,j) = Complex(m_eivec.coeff(i,j), m_eivec.coeff(i,j+1));
|
||||
matV.coeffRef(i,j+1) = Complex(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>
|
||||
void EigenSolver<MatrixType>::compute(const MatrixType& matrix)
|
||||
{
|
||||
@@ -107,18 +201,18 @@ void EigenSolver<MatrixType>::orthes(MatrixType& matH, RealVectorType& ort)
|
||||
for (int m = low+1; m <= high-1; m++)
|
||||
{
|
||||
// Scale column.
|
||||
Scalar scale = matH.block(m, m-1, high-m+1, 1).cwise().abs().sum();
|
||||
RealScalar scale = matH.block(m, m-1, high-m+1, 1).cwise().abs().sum();
|
||||
if (scale != 0.0)
|
||||
{
|
||||
// Compute Householder transformation.
|
||||
Scalar h = 0.0;
|
||||
RealScalar h = 0.0;
|
||||
// FIXME could be rewritten, but this one looks better wrt cache
|
||||
for (int i = high; i >= m; i--)
|
||||
{
|
||||
ort.coeffRef(i) = matH.coeff(i,m-1)/scale;
|
||||
h += ort.coeff(i) * ort.coeff(i);
|
||||
}
|
||||
Scalar g = ei_sqrt(h);
|
||||
RealScalar g = ei_sqrt(h);
|
||||
if (ort.coeff(m) > 0)
|
||||
g = -g;
|
||||
h = h - ort.coeff(m) * g;
|
||||
@@ -127,11 +221,11 @@ void EigenSolver<MatrixType>::orthes(MatrixType& matH, RealVectorType& ort)
|
||||
// Apply Householder similarity transformation
|
||||
// H = (I-u*u'/h)*H*(I-u*u')/h)
|
||||
int bSize = high-m+1;
|
||||
matH.block(m, m, bSize, n-m) -= ((ort.block(m, bSize)/h)
|
||||
* (ort.block(m, bSize).transpose() * matH.block(m, m, bSize, n-m)).lazy()).lazy();
|
||||
matH.block(m, m, bSize, n-m) -= ((ort.segment(m, bSize)/h)
|
||||
* (ort.segment(m, bSize).transpose() * matH.block(m, m, bSize, n-m)).lazy()).lazy();
|
||||
|
||||
matH.block(0, m, high+1, bSize) -= ((matH.block(0, m, high+1, bSize) * ort.block(m, bSize)).lazy()
|
||||
* (ort.block(m, bSize)/h).transpose()).lazy();
|
||||
matH.block(0, m, high+1, bSize) -= ((matH.block(0, m, high+1, bSize) * ort.segment(m, bSize)).lazy()
|
||||
* (ort.segment(m, bSize)/h).transpose()).lazy();
|
||||
|
||||
ort.coeffRef(m) = scale*ort.coeff(m);
|
||||
matH.coeffRef(m,m-1) = scale*g;
|
||||
@@ -145,16 +239,15 @@ void EigenSolver<MatrixType>::orthes(MatrixType& matH, RealVectorType& ort)
|
||||
{
|
||||
if (matH.coeff(m,m-1) != 0.0)
|
||||
{
|
||||
ort.block(m+1, high-m) = matH.col(m-1).block(m+1, high-m);
|
||||
ort.segment(m+1, high-m) = matH.col(m-1).segment(m+1, high-m);
|
||||
|
||||
int bSize = high-m+1;
|
||||
m_eivec.block(m, m, bSize, bSize) += ( (ort.block(m, bSize) / (matH.coeff(m,m-1) * ort.coeff(m) ) )
|
||||
* (ort.block(m, bSize).transpose() * m_eivec.block(m, m, bSize, bSize)).lazy());
|
||||
m_eivec.block(m, m, bSize, bSize) += ( (ort.segment(m, bSize) / (matH.coeff(m,m-1) * ort.coeff(m) ) )
|
||||
* (ort.segment(m, bSize).transpose() * m_eivec.block(m, m, bSize, bSize)).lazy());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Complex scalar division.
|
||||
template<typename Scalar>
|
||||
std::complex<Scalar> cdiv(Scalar xr, Scalar xi, Scalar yr, Scalar yi)
|
||||
@@ -205,7 +298,7 @@ void EigenSolver<MatrixType>::hqr2(MatrixType& matH)
|
||||
m_eivalues.coeffRef(j).real() = matH.coeff(j,j);
|
||||
m_eivalues.coeffRef(j).imag() = 0.0;
|
||||
}
|
||||
norm += matH.col(j).start(std::min(j+1,nn)).cwise().abs().sum();
|
||||
norm += matH.row(j).segment(std::max(j-1,0), nn-std::max(j-1,0)).cwise().abs().sum();
|
||||
}
|
||||
|
||||
// Outer loop over eigenvalue index
|
||||
@@ -478,7 +571,7 @@ void EigenSolver<MatrixType>::hqr2(MatrixType& matH)
|
||||
for (int i = n-1; i >= 0; i--)
|
||||
{
|
||||
w = matH.coeff(i,i) - p;
|
||||
r = (matH.row(i).end(nn-l) * matH.col(n).end(nn-l))(0,0);
|
||||
r = (matH.row(i).segment(l,n-l+1) * matH.col(n).segment(l, n-l+1))(0,0);
|
||||
|
||||
if (m_eivalues.coeff(i).imag() < 0.0)
|
||||
{
|
||||
@@ -537,8 +630,8 @@ void EigenSolver<MatrixType>::hqr2(MatrixType& matH)
|
||||
for (int i = n-2; i >= 0; i--)
|
||||
{
|
||||
Scalar ra,sa,vr,vi;
|
||||
ra = (matH.row(i).end(nn-l) * matH.col(n-1).end(nn-l)).lazy()(0,0);
|
||||
sa = (matH.row(i).end(nn-l) * matH.col(n).end(nn-l)).lazy()(0,0);
|
||||
ra = (matH.block(i,l, 1, n-l+1) * matH.block(l,n-1, n-l+1, 1)).lazy()(0,0);
|
||||
sa = (matH.block(i,l, 1, n-l+1) * matH.block(l,n, n-l+1, 1)).lazy()(0,0);
|
||||
w = matH.coeff(i,i) - p;
|
||||
|
||||
if (m_eivalues.coeff(i).imag() < 0.0)
|
||||
@@ -608,7 +701,7 @@ void EigenSolver<MatrixType>::hqr2(MatrixType& matH)
|
||||
for (int j = nn-1; j >= low; j--)
|
||||
{
|
||||
int bSize = std::min(j,high)-low+1;
|
||||
m_eivec.col(j).block(low, bRows) = (m_eivec.block(low, low, bRows, bSize) * matH.col(j).block(low, bSize));
|
||||
m_eivec.col(j).segment(low, bRows) = (m_eivec.block(low, low, bRows, bSize) * matH.col(j).segment(low, bSize));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
3
Eigen/src/QR/HessenbergDecomposition.h
Executable file → Normal file
3
Eigen/src/QR/HessenbergDecomposition.h
Executable file → Normal file
@@ -26,6 +26,7 @@
|
||||
#define EIGEN_HESSENBERGDECOMPOSITION_H
|
||||
|
||||
/** \ingroup QR_Module
|
||||
* \nonstableyet
|
||||
*
|
||||
* \class HessenbergDecomposition
|
||||
*
|
||||
@@ -148,7 +149,7 @@ void HessenbergDecomposition<MatrixType>::_compute(MatrixType& matA, CoeffVector
|
||||
|
||||
// start of the householder transformation
|
||||
// squared norm of the vector v skipping the first element
|
||||
RealScalar v1norm2 = matA.col(i).end(n-(i+2)).norm2();
|
||||
RealScalar v1norm2 = matA.col(i).end(n-(i+2)).squaredNorm();
|
||||
|
||||
if (ei_isMuchSmallerThan(v1norm2,static_cast<Scalar>(1)))
|
||||
{
|
||||
|
||||
@@ -26,6 +26,7 @@
|
||||
#define EIGEN_QR_H
|
||||
|
||||
/** \ingroup QR_Module
|
||||
* \nonstableyet
|
||||
*
|
||||
* \class QR
|
||||
*
|
||||
@@ -109,7 +110,7 @@ void QR<MatrixType>::_compute(const MatrixType& matrix)
|
||||
m_hCoeffs.coeffRef(k) = 0;
|
||||
}
|
||||
}
|
||||
else if ( (!ei_isMuchSmallerThan(beta=m_qr.col(k).end(remainingSize-1).norm2(),static_cast<Scalar>(1))) || ei_imag(v0)==0 )
|
||||
else if ( (!ei_isMuchSmallerThan(beta=m_qr.col(k).end(remainingSize-1).squaredNorm(),static_cast<Scalar>(1))) || ei_imag(v0)==0 )
|
||||
{
|
||||
// form k-th Householder vector
|
||||
beta = ei_sqrt(ei_abs2(v0)+beta);
|
||||
|
||||
@@ -26,8 +26,6 @@
|
||||
#define EIGEN_EXTERN_INSTANTIATIONS
|
||||
#endif
|
||||
#include "../../Core"
|
||||
// commented because of -pedantic
|
||||
// #include "../../Cholesky"
|
||||
#undef EIGEN_EXTERN_INSTANTIATIONS
|
||||
|
||||
#include "../../QR"
|
||||
|
||||
@@ -26,6 +26,7 @@
|
||||
#define EIGEN_SELFADJOINTEIGENSOLVER_H
|
||||
|
||||
/** \qr_module \ingroup QR_Module
|
||||
* \nonstableyet
|
||||
*
|
||||
* \class SelfAdjointEigenSolver
|
||||
*
|
||||
@@ -204,7 +205,7 @@ void SelfAdjointEigenSolver<MatrixType>::compute(const MatrixType& matrix, bool
|
||||
for (int i = 0; i < n-1; i++)
|
||||
{
|
||||
int k;
|
||||
m_eivalues.block(i,n-i).minCoeff(&k);
|
||||
m_eivalues.segment(i,n-i).minCoeff(&k);
|
||||
if (k > 0)
|
||||
{
|
||||
std::swap(m_eivalues[i], m_eivalues[k+i]);
|
||||
@@ -225,9 +226,9 @@ void SelfAdjointEigenSolver<MatrixType>::
|
||||
compute(const MatrixType& matA, const MatrixType& matB, bool computeEigenvectors)
|
||||
{
|
||||
ei_assert(matA.cols()==matA.rows() && matB.rows()==matA.rows() && matB.cols()==matB.rows());
|
||||
|
||||
|
||||
// Compute the cholesky decomposition of matB = L L'
|
||||
Cholesky<MatrixType> cholB(matB);
|
||||
LLT<MatrixType> cholB(matB);
|
||||
|
||||
// compute C = inv(L) A inv(L')
|
||||
MatrixType matC = matA;
|
||||
|
||||
11
Eigen/src/QR/Tridiagonalization.h
Executable file → Normal file
11
Eigen/src/QR/Tridiagonalization.h
Executable file → Normal file
@@ -26,6 +26,7 @@
|
||||
#define EIGEN_TRIDIAGONALIZATION_H
|
||||
|
||||
/** \ingroup QR_Module
|
||||
* \nonstableyet
|
||||
*
|
||||
* \class Tridiagonalization
|
||||
*
|
||||
@@ -198,7 +199,7 @@ void Tridiagonalization<MatrixType>::_compute(MatrixType& matA, CoeffVectorType&
|
||||
|
||||
// start of the householder transformation
|
||||
// squared norm of the vector v skipping the first element
|
||||
RealScalar v1norm2 = matA.col(i).end(n-(i+2)).norm2();
|
||||
RealScalar v1norm2 = matA.col(i).end(n-(i+2)).squaredNorm();
|
||||
|
||||
if (ei_isMuchSmallerThan(v1norm2,static_cast<Scalar>(1)))
|
||||
{
|
||||
@@ -219,7 +220,7 @@ void Tridiagonalization<MatrixType>::_compute(MatrixType& matA, CoeffVectorType&
|
||||
// i.e., A = H' A H where H = I - h v v' and v = matA.col(i).end(n-i-1)
|
||||
|
||||
matA.col(i).coeffRef(i+1) = 1;
|
||||
|
||||
|
||||
/* This is the initial algorithm which minimize operation counts and maximize
|
||||
* the use of Eigen's expression. Unfortunately, the first matrix-vector product
|
||||
* using Part<Lower|Selfadjoint> is very very slow */
|
||||
@@ -284,7 +285,7 @@ void Tridiagonalization<MatrixType>::_compute(MatrixType& matA, CoeffVectorType&
|
||||
|
||||
hCoeffs.end(n-i-1) += (h * Scalar(-0.5) * matA.col(i).end(n-i-1).dot(hCoeffs.end(n-i-1)))
|
||||
* matA.col(i).end(n-i-1);
|
||||
|
||||
|
||||
const Scalar* EIGEN_RESTRICT pb = &matA.coeffRef(0,i);
|
||||
const Scalar* EIGEN_RESTRICT pa = (&hCoeffs.coeffRef(0)) - 1;
|
||||
for (int j1=i+1; j1<n; ++j1)
|
||||
@@ -295,11 +296,11 @@ void Tridiagonalization<MatrixType>::_compute(MatrixType& matA, CoeffVectorType&
|
||||
{
|
||||
int alignedStart = (starti) + ei_alignmentOffset(&matA.coeffRef(starti,j1), n-starti);
|
||||
alignedEnd = alignedStart + ((n-alignedStart)/PacketSize)*PacketSize;
|
||||
|
||||
|
||||
for (int i1=starti; i1<alignedStart; ++i1)
|
||||
matA.coeffRef(i1,j1) -= matA.coeff(i1,i)*ei_conj(hCoeffs.coeff(j1-1))
|
||||
+ hCoeffs.coeff(i1-1)*ei_conj(matA.coeff(j1,i));
|
||||
|
||||
|
||||
Packet tmp0 = ei_pset1(hCoeffs.coeff(j1-1));
|
||||
Packet tmp1 = ei_pset1(matA.coeff(j1,i));
|
||||
Scalar* pc = &matA.coeffRef(0,j1);
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
// This file is part of Eigen, a lightweight C++ template library
|
||||
// for linear algebra. Eigen itself is part of the KDE project.
|
||||
//
|
||||
// Copyright (C) 2006-2008 Benoit Jacob <jacob@math.jussieu.fr>
|
||||
// Copyright (C) 2006-2008 Benoit Jacob <jacob.benoit.1@gmail.com>
|
||||
//
|
||||
// Eigen is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU Lesser General Public
|
||||
|
||||
@@ -26,6 +26,7 @@
|
||||
#define EIGEN_SVD_H
|
||||
|
||||
/** \ingroup SVD_Module
|
||||
* \nonstableyet
|
||||
*
|
||||
* \class SVD
|
||||
*
|
||||
@@ -50,16 +51,16 @@ template<typename MatrixType> class SVD
|
||||
AlignmentMask = int(PacketSize)-1,
|
||||
MinSize = EIGEN_ENUM_MIN(MatrixType::RowsAtCompileTime, MatrixType::ColsAtCompileTime)
|
||||
};
|
||||
|
||||
|
||||
typedef Matrix<Scalar, MatrixType::RowsAtCompileTime, 1> ColVector;
|
||||
typedef Matrix<Scalar, MatrixType::ColsAtCompileTime, 1> RowVector;
|
||||
|
||||
|
||||
typedef Matrix<Scalar, MatrixType::RowsAtCompileTime, MinSize> MatrixUType;
|
||||
typedef Matrix<Scalar, MatrixType::ColsAtCompileTime, MatrixType::ColsAtCompileTime> MatrixVType;
|
||||
typedef Matrix<Scalar, MinSize, 1> SingularValuesType;
|
||||
|
||||
public:
|
||||
|
||||
|
||||
SVD(const MatrixType& matrix)
|
||||
: m_matU(matrix.rows(), std::min(matrix.rows(), matrix.cols())),
|
||||
m_matV(matrix.cols(),matrix.cols()),
|
||||
@@ -69,7 +70,7 @@ template<typename MatrixType> class SVD
|
||||
}
|
||||
|
||||
template<typename OtherDerived, typename ResultType>
|
||||
void solve(const MatrixBase<OtherDerived> &b, ResultType* result) const;
|
||||
bool solve(const MatrixBase<OtherDerived> &b, ResultType* result) const;
|
||||
|
||||
const MatrixUType& matrixU() const { return m_matU; }
|
||||
const SingularValuesType& singularValues() const { return m_sigma; }
|
||||
@@ -97,7 +98,7 @@ void SVD<MatrixType>::compute(const MatrixType& matrix)
|
||||
const int m = matrix.rows();
|
||||
const int n = matrix.cols();
|
||||
const int nu = std::min(m,n);
|
||||
|
||||
|
||||
m_matU.resize(m, nu);
|
||||
m_matU.setZero();
|
||||
m_sigma.resize(std::min(m,n));
|
||||
@@ -130,7 +131,7 @@ void SVD<MatrixType>::compute(const MatrixType& matrix)
|
||||
}
|
||||
m_sigma[k] = -m_sigma[k];
|
||||
}
|
||||
|
||||
|
||||
for (j = k+1; j < n; j++)
|
||||
{
|
||||
if ((k < nct) && (m_sigma[k] != 0.0))
|
||||
@@ -468,18 +469,18 @@ void SVD<MatrixType>::compute(const MatrixType& matrix)
|
||||
template<typename MatrixType>
|
||||
SVD<MatrixType>& SVD<MatrixType>::sort()
|
||||
{
|
||||
int mu = m_matU.rows();
|
||||
int mv = m_matV.rows();
|
||||
int mu = m_matU.rows();
|
||||
int mv = m_matV.rows();
|
||||
int n = m_matU.cols();
|
||||
|
||||
for (int i=0; i<n; i++)
|
||||
{
|
||||
int k = i;
|
||||
int k = i;
|
||||
Scalar p = m_sigma.coeff(i);
|
||||
|
||||
for (int j=i+1; j<n; j++)
|
||||
{
|
||||
if (m_sigma.coeff(j) > p)
|
||||
if (m_sigma.coeff(j) > p)
|
||||
{
|
||||
k = j;
|
||||
p = m_sigma.coeff(j);
|
||||
@@ -505,11 +506,11 @@ SVD<MatrixType>& SVD<MatrixType>::sort()
|
||||
/** \returns the solution of \f$ A x = b \f$ using the current SVD decomposition of A.
|
||||
* The parts of the solution corresponding to zero singular values are ignored.
|
||||
*
|
||||
* \sa MatrixBase::svd(), LU::solve(), Cholesky::solve()
|
||||
* \sa MatrixBase::svd(), LU::solve(), LLT::solve()
|
||||
*/
|
||||
template<typename MatrixType>
|
||||
template<typename OtherDerived, typename ResultType>
|
||||
void SVD<MatrixType>::solve(const MatrixBase<OtherDerived> &b, ResultType* result) const
|
||||
bool SVD<MatrixType>::solve(const MatrixBase<OtherDerived> &b, ResultType* result) const
|
||||
{
|
||||
const int rows = m_matU.rows();
|
||||
ei_assert(b.rows() == rows);
|
||||
@@ -530,6 +531,7 @@ void SVD<MatrixType>::solve(const MatrixBase<OtherDerived> &b, ResultType* resul
|
||||
|
||||
result->col(j) = m_matV * aux;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/** \svd_module
|
||||
|
||||
371
Eigen/src/Sparse/AmbiVector.h
Normal file
371
Eigen/src/Sparse/AmbiVector.h
Normal file
@@ -0,0 +1,371 @@
|
||||
// This file is part of Eigen, a lightweight C++ template library
|
||||
// for linear algebra. Eigen itself is part of the KDE project.
|
||||
//
|
||||
// Copyright (C) 2008 Gael Guennebaud <g.gael@free.fr>
|
||||
//
|
||||
// Eigen is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU Lesser General Public
|
||||
// License as published by the Free Software Foundation; either
|
||||
// version 3 of the License, or (at your option) any later version.
|
||||
//
|
||||
// Alternatively, you can redistribute it and/or
|
||||
// modify it under the terms of the GNU General Public License as
|
||||
// published by the Free Software Foundation; either version 2 of
|
||||
// the License, or (at your option) any later version.
|
||||
//
|
||||
// Eigen is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||
// FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License or the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public
|
||||
// License and a copy of the GNU General Public License along with
|
||||
// Eigen. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
#ifndef EIGEN_AMBIVECTOR_H
|
||||
#define EIGEN_AMBIVECTOR_H
|
||||
|
||||
/** \internal
|
||||
* Hybrid sparse/dense vector class designed for intensive read-write operations.
|
||||
*
|
||||
* See BasicSparseLLT and SparseProduct for usage examples.
|
||||
*/
|
||||
template<typename _Scalar> class AmbiVector
|
||||
{
|
||||
public:
|
||||
typedef _Scalar Scalar;
|
||||
typedef typename NumTraits<Scalar>::Real RealScalar;
|
||||
AmbiVector(int size)
|
||||
: m_buffer(0), m_size(0), m_allocatedSize(0), m_allocatedElements(0), m_mode(-1)
|
||||
{
|
||||
resize(size);
|
||||
}
|
||||
|
||||
void init(RealScalar estimatedDensity);
|
||||
void init(int mode);
|
||||
|
||||
void nonZeros() const;
|
||||
|
||||
/** Specifies a sub-vector to work on */
|
||||
void setBounds(int start, int end) { m_start = start; m_end = end; }
|
||||
|
||||
void setZero();
|
||||
|
||||
void restart();
|
||||
Scalar& coeffRef(int i);
|
||||
Scalar coeff(int i);
|
||||
|
||||
class Iterator;
|
||||
|
||||
~AmbiVector() { delete[] m_buffer; }
|
||||
|
||||
void resize(int size)
|
||||
{
|
||||
if (m_allocatedSize < size)
|
||||
reallocate(size);
|
||||
m_size = size;
|
||||
}
|
||||
|
||||
int size() const { return m_size; }
|
||||
|
||||
protected:
|
||||
|
||||
void reallocate(int size)
|
||||
{
|
||||
// if the size of the matrix is not too large, let's allocate a bit more than needed such
|
||||
// that we can handle dense vector even in sparse mode.
|
||||
delete[] m_buffer;
|
||||
if (size<1000)
|
||||
{
|
||||
int allocSize = (size * sizeof(ListEl))/sizeof(Scalar);
|
||||
m_allocatedElements = (allocSize*sizeof(Scalar))/sizeof(ListEl);
|
||||
m_buffer = new Scalar[allocSize];
|
||||
}
|
||||
else
|
||||
{
|
||||
m_allocatedElements = (size*sizeof(Scalar))/sizeof(ListEl);
|
||||
m_buffer = new Scalar[size];
|
||||
}
|
||||
m_size = size;
|
||||
m_start = 0;
|
||||
m_end = m_size;
|
||||
}
|
||||
|
||||
void reallocateSparse()
|
||||
{
|
||||
int copyElements = m_allocatedElements;
|
||||
m_allocatedElements = std::min(int(m_allocatedElements*1.5),m_size);
|
||||
int allocSize = m_allocatedElements * sizeof(ListEl);
|
||||
allocSize = allocSize/sizeof(Scalar) + (allocSize%sizeof(Scalar)>0?1:0);
|
||||
Scalar* newBuffer = new Scalar[allocSize];
|
||||
memcpy(newBuffer, m_buffer, copyElements * sizeof(ListEl));
|
||||
}
|
||||
|
||||
protected:
|
||||
// element type of the linked list
|
||||
struct ListEl
|
||||
{
|
||||
int next;
|
||||
int index;
|
||||
Scalar value;
|
||||
};
|
||||
|
||||
// used to store data in both mode
|
||||
Scalar* m_buffer;
|
||||
int m_size;
|
||||
int m_start;
|
||||
int m_end;
|
||||
int m_allocatedSize;
|
||||
int m_allocatedElements;
|
||||
int m_mode;
|
||||
|
||||
// linked list mode
|
||||
int m_llStart;
|
||||
int m_llCurrent;
|
||||
int m_llSize;
|
||||
|
||||
private:
|
||||
AmbiVector(const AmbiVector&);
|
||||
|
||||
};
|
||||
|
||||
/** \returns the number of non zeros in the current sub vector */
|
||||
template<typename Scalar>
|
||||
void AmbiVector<Scalar>::nonZeros() const
|
||||
{
|
||||
if (m_mode==IsSparse)
|
||||
return m_llSize;
|
||||
else
|
||||
return m_end - m_start;
|
||||
}
|
||||
|
||||
template<typename Scalar>
|
||||
void AmbiVector<Scalar>::init(RealScalar estimatedDensity)
|
||||
{
|
||||
if (estimatedDensity>0.1)
|
||||
init(IsDense);
|
||||
else
|
||||
init(IsSparse);
|
||||
}
|
||||
|
||||
template<typename Scalar>
|
||||
void AmbiVector<Scalar>::init(int mode)
|
||||
{
|
||||
m_mode = mode;
|
||||
if (m_mode==IsSparse)
|
||||
{
|
||||
m_llSize = 0;
|
||||
m_llStart = -1;
|
||||
}
|
||||
}
|
||||
|
||||
/** Must be called whenever we might perform a write access
|
||||
* with an index smaller than the previous one.
|
||||
*
|
||||
* Don't worry, this function is extremely cheap.
|
||||
*/
|
||||
template<typename Scalar>
|
||||
void AmbiVector<Scalar>::restart()
|
||||
{
|
||||
m_llCurrent = m_llStart;
|
||||
}
|
||||
|
||||
/** Set all coefficients of current subvector to zero */
|
||||
template<typename Scalar>
|
||||
void AmbiVector<Scalar>::setZero()
|
||||
{
|
||||
if (m_mode==IsDense)
|
||||
{
|
||||
for (int i=m_start; i<m_end; ++i)
|
||||
m_buffer[i] = Scalar(0);
|
||||
}
|
||||
else
|
||||
{
|
||||
ei_assert(m_mode==IsSparse);
|
||||
m_llSize = 0;
|
||||
m_llStart = -1;
|
||||
}
|
||||
}
|
||||
|
||||
template<typename Scalar>
|
||||
Scalar& AmbiVector<Scalar>::coeffRef(int i)
|
||||
{
|
||||
if (m_mode==IsDense)
|
||||
return m_buffer[i];
|
||||
else
|
||||
{
|
||||
ListEl* EIGEN_RESTRICT llElements = reinterpret_cast<ListEl*>(m_buffer);
|
||||
// TODO factorize the following code to reduce code generation
|
||||
ei_assert(m_mode==IsSparse);
|
||||
if (m_llSize==0)
|
||||
{
|
||||
// this is the first element
|
||||
m_llStart = 0;
|
||||
m_llCurrent = 0;
|
||||
m_llSize++;
|
||||
llElements[0].value = Scalar(0);
|
||||
llElements[0].index = i;
|
||||
llElements[0].next = -1;
|
||||
return llElements[0].value;
|
||||
}
|
||||
else if (i<llElements[m_llStart].index)
|
||||
{
|
||||
// this is going to be the new first element of the list
|
||||
ListEl& el = llElements[m_llSize];
|
||||
el.value = Scalar(0);
|
||||
el.index = i;
|
||||
el.next = m_llStart;
|
||||
m_llStart = m_llSize;
|
||||
m_llSize++;
|
||||
m_llCurrent = m_llStart;
|
||||
return el.value;
|
||||
}
|
||||
else
|
||||
{
|
||||
int nextel = llElements[m_llCurrent].next;
|
||||
ei_assert(i>=llElements[m_llCurrent].index && "you must call restart() before inserting an element with lower or equal index");
|
||||
while (nextel >= 0 && llElements[nextel].index<=i)
|
||||
{
|
||||
m_llCurrent = nextel;
|
||||
nextel = llElements[nextel].next;
|
||||
}
|
||||
|
||||
if (llElements[m_llCurrent].index==i)
|
||||
{
|
||||
// the coefficient already exists and we found it !
|
||||
return llElements[m_llCurrent].value;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (m_llSize>=m_allocatedElements)
|
||||
reallocateSparse();
|
||||
ei_internal_assert(m_llSize<m_size && "internal error: overflow in sparse mode");
|
||||
// let's insert a new coefficient
|
||||
ListEl& el = llElements[m_llSize];
|
||||
el.value = Scalar(0);
|
||||
el.index = i;
|
||||
el.next = llElements[m_llCurrent].next;
|
||||
llElements[m_llCurrent].next = m_llSize;
|
||||
m_llSize++;
|
||||
return el.value;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template<typename Scalar>
|
||||
Scalar AmbiVector<Scalar>::coeff(int i)
|
||||
{
|
||||
if (m_mode==IsDense)
|
||||
return m_buffer[i];
|
||||
else
|
||||
{
|
||||
ListEl* EIGEN_RESTRICT llElements = reinterpret_cast<ListEl*>(m_buffer);
|
||||
ei_assert(m_mode==IsSparse);
|
||||
if ((m_llSize==0) || (i<llElements[m_llStart].index))
|
||||
{
|
||||
return Scalar(0);
|
||||
}
|
||||
else
|
||||
{
|
||||
int elid = m_llStart;
|
||||
while (elid >= 0 && llElements[elid].index<i)
|
||||
elid = llElements[elid].next;
|
||||
|
||||
if (llElements[elid].index==i)
|
||||
return llElements[m_llCurrent].value;
|
||||
else
|
||||
return Scalar(0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** Iterator over the nonzero coefficients */
|
||||
template<typename _Scalar>
|
||||
class AmbiVector<_Scalar>::Iterator
|
||||
{
|
||||
public:
|
||||
typedef _Scalar Scalar;
|
||||
typedef typename NumTraits<Scalar>::Real RealScalar;
|
||||
|
||||
/** Default constructor
|
||||
* \param vec the vector on which we iterate
|
||||
* \param epsilon the minimal value used to prune zero coefficients.
|
||||
* In practice, all coefficients having a magnitude smaller than \a epsilon
|
||||
* are skipped.
|
||||
*/
|
||||
Iterator(const AmbiVector& vec, RealScalar epsilon = RealScalar(0.1)*precision<RealScalar>())
|
||||
: m_vector(vec)
|
||||
{
|
||||
m_epsilon = epsilon;
|
||||
m_isDense = m_vector.m_mode==IsDense;
|
||||
if (m_isDense)
|
||||
{
|
||||
m_cachedIndex = m_vector.m_start-1;
|
||||
++(*this);
|
||||
}
|
||||
else
|
||||
{
|
||||
ListEl* EIGEN_RESTRICT llElements = reinterpret_cast<ListEl*>(m_vector.m_buffer);
|
||||
m_currentEl = m_vector.m_llStart;
|
||||
while (m_currentEl>=0 && ei_abs(llElements[m_currentEl].value)<m_epsilon)
|
||||
m_currentEl = llElements[m_currentEl].next;
|
||||
if (m_currentEl<0)
|
||||
{
|
||||
m_cachedIndex = -1;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_cachedIndex = llElements[m_currentEl].index;
|
||||
m_cachedValue = llElements[m_currentEl].value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int index() const { return m_cachedIndex; }
|
||||
Scalar value() const { return m_cachedValue; }
|
||||
|
||||
operator bool() const { return m_cachedIndex>=0; }
|
||||
|
||||
Iterator& operator++()
|
||||
{
|
||||
if (m_isDense)
|
||||
{
|
||||
do {
|
||||
m_cachedIndex++;
|
||||
} while (m_cachedIndex<m_vector.m_end && ei_abs(m_vector.m_buffer[m_cachedIndex])<m_epsilon);
|
||||
if (m_cachedIndex<m_vector.m_end)
|
||||
m_cachedValue = m_vector.m_buffer[m_cachedIndex];
|
||||
else
|
||||
m_cachedIndex=-1;
|
||||
}
|
||||
else
|
||||
{
|
||||
ListEl* EIGEN_RESTRICT llElements = reinterpret_cast<ListEl*>(m_vector.m_buffer);
|
||||
do {
|
||||
m_currentEl = llElements[m_currentEl].next;
|
||||
} while (m_currentEl>=0 && ei_abs(llElements[m_currentEl].value)<m_epsilon);
|
||||
if (m_currentEl<0)
|
||||
{
|
||||
m_cachedIndex = -1;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_cachedIndex = llElements[m_currentEl].index;
|
||||
m_cachedValue = llElements[m_currentEl].value;
|
||||
}
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
protected:
|
||||
const AmbiVector& m_vector; // the target vector
|
||||
int m_currentEl; // the current element in sparse/linked-list mode
|
||||
RealScalar m_epsilon; // epsilon used to prune zero coefficients
|
||||
int m_cachedIndex; // current coordinate
|
||||
Scalar m_cachedValue; // current value
|
||||
bool m_isDense; // mode of the vector
|
||||
};
|
||||
|
||||
|
||||
#endif // EIGEN_AMBIVECTOR_H
|
||||
208
Eigen/src/Sparse/CholmodSupport.h
Normal file
208
Eigen/src/Sparse/CholmodSupport.h
Normal file
@@ -0,0 +1,208 @@
|
||||
// This file is part of Eigen, a lightweight C++ template library
|
||||
// for linear algebra. Eigen itself is part of the KDE project.
|
||||
//
|
||||
// Copyright (C) 2008 Gael Guennebaud <g.gael@free.fr>
|
||||
//
|
||||
// Eigen is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU Lesser General Public
|
||||
// License as published by the Free Software Foundation; either
|
||||
// version 3 of the License, or (at your option) any later version.
|
||||
//
|
||||
// Alternatively, you can redistribute it and/or
|
||||
// modify it under the terms of the GNU General Public License as
|
||||
// published by the Free Software Foundation; either version 2 of
|
||||
// the License, or (at your option) any later version.
|
||||
//
|
||||
// Eigen is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||
// FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License or the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public
|
||||
// License and a copy of the GNU General Public License along with
|
||||
// Eigen. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
#ifndef EIGEN_CHOLMODSUPPORT_H
|
||||
#define EIGEN_CHOLMODSUPPORT_H
|
||||
|
||||
template<typename Scalar, int Flags>
|
||||
cholmod_sparse SparseMatrix<Scalar,Flags>::asCholmodMatrix()
|
||||
{
|
||||
cholmod_sparse res;
|
||||
res.nzmax = nonZeros();
|
||||
res.nrow = rows();;
|
||||
res.ncol = cols();
|
||||
res.p = _outerIndexPtr();
|
||||
res.i = _innerIndexPtr();
|
||||
res.x = _valuePtr();
|
||||
res.xtype = CHOLMOD_REAL;
|
||||
res.itype = CHOLMOD_INT;
|
||||
res.sorted = 1;
|
||||
res.packed = 1;
|
||||
res.dtype = 0;
|
||||
res.stype = -1;
|
||||
|
||||
if (ei_is_same_type<Scalar,float>::ret)
|
||||
{
|
||||
res.xtype = CHOLMOD_REAL;
|
||||
res.dtype = 1;
|
||||
}
|
||||
else if (ei_is_same_type<Scalar,double>::ret)
|
||||
{
|
||||
res.xtype = CHOLMOD_REAL;
|
||||
res.dtype = 0;
|
||||
}
|
||||
else if (ei_is_same_type<Scalar,std::complex<float> >::ret)
|
||||
{
|
||||
res.xtype = CHOLMOD_COMPLEX;
|
||||
res.dtype = 1;
|
||||
}
|
||||
else if (ei_is_same_type<Scalar,std::complex<double> >::ret)
|
||||
{
|
||||
res.xtype = CHOLMOD_COMPLEX;
|
||||
res.dtype = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
ei_assert(false && "Scalar type not supported by CHOLMOD");
|
||||
}
|
||||
|
||||
if (Flags & SelfAdjoint)
|
||||
{
|
||||
if (Flags & Upper)
|
||||
res.stype = 1;
|
||||
else if (Flags & Lower)
|
||||
res.stype = -1;
|
||||
else
|
||||
res.stype = 0;
|
||||
}
|
||||
else
|
||||
res.stype = 0;
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
template<typename Scalar, int Flags>
|
||||
SparseMatrix<Scalar,Flags> SparseMatrix<Scalar,Flags>::Map(cholmod_sparse& cm)
|
||||
{
|
||||
SparseMatrix res;
|
||||
res.m_innerSize = cm.nrow;
|
||||
res.m_outerSize = cm.ncol;
|
||||
res.m_outerIndex = reinterpret_cast<int*>(cm.p);
|
||||
SparseArray<Scalar> data = SparseArray<Scalar>::Map(
|
||||
reinterpret_cast<int*>(cm.i),
|
||||
reinterpret_cast<Scalar*>(cm.x),
|
||||
res.m_outerIndex[cm.ncol]);
|
||||
res.m_data.swap(data);
|
||||
res.markAsRValue();
|
||||
return res;
|
||||
}
|
||||
|
||||
template<typename MatrixType>
|
||||
class SparseLLT<MatrixType,Cholmod> : public SparseLLT<MatrixType>
|
||||
{
|
||||
protected:
|
||||
typedef SparseLLT<MatrixType> Base;
|
||||
using Base::Scalar;
|
||||
using Base::RealScalar;
|
||||
using Base::MatrixLIsDirty;
|
||||
using Base::SupernodalFactorIsDirty;
|
||||
using Base::m_flags;
|
||||
using Base::m_matrix;
|
||||
using Base::m_status;
|
||||
|
||||
public:
|
||||
|
||||
SparseLLT(int flags = 0)
|
||||
: Base(flags), m_cholmodFactor(0)
|
||||
{
|
||||
cholmod_start(&m_cholmod);
|
||||
}
|
||||
|
||||
SparseLLT(const MatrixType& matrix, int flags = 0)
|
||||
: Base(flags), m_cholmodFactor(0)
|
||||
{
|
||||
cholmod_start(&m_cholmod);
|
||||
compute(matrix);
|
||||
}
|
||||
|
||||
~SparseLLT()
|
||||
{
|
||||
if (m_cholmodFactor)
|
||||
cholmod_free_factor(&m_cholmodFactor, &m_cholmod);
|
||||
cholmod_finish(&m_cholmod);
|
||||
}
|
||||
|
||||
inline const typename Base::CholMatrixType& matrixL(void) const;
|
||||
|
||||
template<typename Derived>
|
||||
void solveInPlace(MatrixBase<Derived> &b) const;
|
||||
|
||||
void compute(const MatrixType& matrix);
|
||||
|
||||
protected:
|
||||
mutable cholmod_common m_cholmod;
|
||||
cholmod_factor* m_cholmodFactor;
|
||||
};
|
||||
|
||||
template<typename MatrixType>
|
||||
void SparseLLT<MatrixType,Cholmod>::compute(const MatrixType& a)
|
||||
{
|
||||
if (m_cholmodFactor)
|
||||
{
|
||||
cholmod_free_factor(&m_cholmodFactor, &m_cholmod);
|
||||
m_cholmodFactor = 0;
|
||||
}
|
||||
|
||||
cholmod_sparse A = const_cast<MatrixType&>(a).asCholmodMatrix();
|
||||
// TODO
|
||||
if (m_flags&IncompleteFactorization)
|
||||
{
|
||||
m_cholmod.nmethods = 1;
|
||||
m_cholmod.method [0].ordering = CHOLMOD_NATURAL;
|
||||
m_cholmod.postorder = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_cholmod.nmethods = 1;
|
||||
m_cholmod.method[0].ordering = CHOLMOD_NATURAL;
|
||||
m_cholmod.postorder = 0;
|
||||
}
|
||||
m_cholmod.final_ll = 1;
|
||||
m_cholmodFactor = cholmod_analyze(&A, &m_cholmod);
|
||||
cholmod_factorize(&A, m_cholmodFactor, &m_cholmod);
|
||||
|
||||
m_status = (m_status & ~SupernodalFactorIsDirty) | MatrixLIsDirty;
|
||||
}
|
||||
|
||||
template<typename MatrixType>
|
||||
inline const typename SparseLLT<MatrixType>::CholMatrixType&
|
||||
SparseLLT<MatrixType,Cholmod>::matrixL() const
|
||||
{
|
||||
if (m_status & MatrixLIsDirty)
|
||||
{
|
||||
ei_assert(!(m_status & SupernodalFactorIsDirty));
|
||||
|
||||
cholmod_sparse* cmRes = cholmod_factor_to_sparse(m_cholmodFactor, &m_cholmod);
|
||||
const_cast<typename Base::CholMatrixType&>(m_matrix) = Base::CholMatrixType::Map(*cmRes);
|
||||
free(cmRes);
|
||||
|
||||
m_status = (m_status & ~MatrixLIsDirty);
|
||||
}
|
||||
return m_matrix;
|
||||
}
|
||||
|
||||
template<typename MatrixType>
|
||||
template<typename Derived>
|
||||
void SparseLLT<MatrixType,Cholmod>::solveInPlace(MatrixBase<Derived> &b) const
|
||||
{
|
||||
if (m_status & MatrixLIsDirty)
|
||||
matrixL();
|
||||
|
||||
const int size = m_matrix.rows();
|
||||
ei_assert(size==b.rows());
|
||||
|
||||
Base::solveInPlace(b);
|
||||
}
|
||||
|
||||
#endif // EIGEN_CHOLMODSUPPORT_H
|
||||
257
Eigen/src/Sparse/RandomSetter.h
Normal file
257
Eigen/src/Sparse/RandomSetter.h
Normal file
@@ -0,0 +1,257 @@
|
||||
// This file is part of Eigen, a lightweight C++ template library
|
||||
// for linear algebra. Eigen itself is part of the KDE project.
|
||||
//
|
||||
// Copyright (C) 2008 Gael Guennebaud <g.gael@free.fr>
|
||||
//
|
||||
// Eigen is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU Lesser General Public
|
||||
// License as published by the Free Software Foundation; either
|
||||
// version 3 of the License, or (at your option) any later version.
|
||||
//
|
||||
// Alternatively, you can redistribute it and/or
|
||||
// modify it under the terms of the GNU General Public License as
|
||||
// published by the Free Software Foundation; either version 2 of
|
||||
// the License, or (at your option) any later version.
|
||||
//
|
||||
// Eigen is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||
// FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License or the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public
|
||||
// License and a copy of the GNU General Public License along with
|
||||
// Eigen. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
#ifndef EIGEN_RANDOMSETTER_H
|
||||
#define EIGEN_RANDOMSETTER_H
|
||||
|
||||
template<typename Scalar> struct StdMapTraits
|
||||
{
|
||||
typedef int KeyType;
|
||||
typedef std::map<KeyType,Scalar> Type;
|
||||
enum {
|
||||
IsSorted = 1
|
||||
};
|
||||
|
||||
static void setInvalidKey(Type&, const KeyType&) {}
|
||||
};
|
||||
|
||||
#ifdef _HASH_MAP
|
||||
template<typename Scalar> struct GnuHashMapTraits
|
||||
{
|
||||
typedef int KeyType;
|
||||
typedef __gnu_cxx::hash_map<KeyType,Scalar> Type;
|
||||
enum {
|
||||
IsSorted = 0
|
||||
};
|
||||
|
||||
static void setInvalidKey(Type&, const KeyType&) {}
|
||||
};
|
||||
#endif
|
||||
|
||||
#ifdef _DENSE_HASH_MAP_H_
|
||||
template<typename Scalar> struct GoogleDenseHashMapTraits
|
||||
{
|
||||
typedef int KeyType;
|
||||
typedef google::dense_hash_map<KeyType,Scalar> Type;
|
||||
enum {
|
||||
IsSorted = 0
|
||||
};
|
||||
|
||||
static void setInvalidKey(Type& map, const KeyType& k)
|
||||
{ map.set_empty_key(k); }
|
||||
};
|
||||
#endif
|
||||
|
||||
#ifdef _SPARSE_HASH_MAP_H_
|
||||
template<typename Scalar> struct GoogleSparseHashMapTraits
|
||||
{
|
||||
typedef int KeyType;
|
||||
typedef google::sparse_hash_map<KeyType,Scalar> Type;
|
||||
enum {
|
||||
IsSorted = 0
|
||||
};
|
||||
|
||||
static void setInvalidKey(Type&, const KeyType&) {}
|
||||
};
|
||||
#endif
|
||||
|
||||
/** \class RandomSetter
|
||||
*
|
||||
* Typical usage:
|
||||
* \code
|
||||
* SparseMatrix<double> m(rows,cols);
|
||||
* {
|
||||
* RandomSetter<SparseMatrix<double> > w(m);
|
||||
* // don't use m but w instead with read/write random access to the coefficients:
|
||||
* for(;;)
|
||||
* w(rand(),rand()) = rand;
|
||||
* }
|
||||
* // when w is deleted, the data are copied back to m
|
||||
* // and m is ready to use.
|
||||
* \endcode
|
||||
*
|
||||
* \note for performance and memory consumption reasons it is highly recommended to use
|
||||
* Google's hash library. To do so you have two options:
|
||||
* - include <google/dense_hash_map> yourself \b before Eigen/Sparse header
|
||||
* - define EIGEN_GOOGLEHASH_SUPPORT
|
||||
* In the later case the inclusion of <google/dense_hash_map> is made for you.
|
||||
*/
|
||||
template<typename SparseMatrixType,
|
||||
template <typename T> class MapTraits =
|
||||
#if defined _DENSE_HASH_MAP_H_
|
||||
GoogleDenseHashMapTraits
|
||||
#elif defined _HASH_MAP
|
||||
GnuHashMapTraits
|
||||
#else
|
||||
StdMapTraits
|
||||
#endif
|
||||
,int OuterPacketBits = 6>
|
||||
class RandomSetter
|
||||
{
|
||||
typedef typename ei_traits<SparseMatrixType>::Scalar Scalar;
|
||||
struct ScalarWrapper
|
||||
{
|
||||
ScalarWrapper() : value(0) {}
|
||||
Scalar value;
|
||||
};
|
||||
typedef typename MapTraits<ScalarWrapper>::KeyType KeyType;
|
||||
typedef typename MapTraits<ScalarWrapper>::Type HashMapType;
|
||||
static const int OuterPacketMask = (1 << OuterPacketBits) - 1;
|
||||
enum {
|
||||
SwapStorage = 1 - MapTraits<ScalarWrapper>::IsSorted,
|
||||
TargetRowMajor = (SparseMatrixType::Flags & RowMajorBit) ? 1 : 0,
|
||||
SetterRowMajor = SwapStorage ? 1-TargetRowMajor : TargetRowMajor
|
||||
};
|
||||
|
||||
public:
|
||||
|
||||
inline RandomSetter(SparseMatrixType& target)
|
||||
: mp_target(&target)
|
||||
{
|
||||
const int outerSize = SwapStorage ? target.innerSize() : target.outerSize();
|
||||
const int innerSize = SwapStorage ? target.outerSize() : target.innerSize();
|
||||
m_outerPackets = outerSize >> OuterPacketBits;
|
||||
if (outerSize&OuterPacketMask)
|
||||
m_outerPackets += 1;
|
||||
m_hashmaps = new HashMapType[m_outerPackets];
|
||||
// compute number of bits needed to store inner indices
|
||||
int aux = innerSize - 1;
|
||||
m_keyBitsOffset = 0;
|
||||
while (aux)
|
||||
{
|
||||
m_keyBitsOffset++;
|
||||
aux = aux >> 1;
|
||||
}
|
||||
KeyType ik = (1<<(OuterPacketBits+m_keyBitsOffset));
|
||||
for (int k=0; k<m_outerPackets; ++k)
|
||||
MapTraits<ScalarWrapper>::setInvalidKey(m_hashmaps[k],ik);
|
||||
|
||||
// insert current coeffs
|
||||
for (int j=0; j<mp_target->outerSize(); ++j)
|
||||
for (typename SparseMatrixType::InnerIterator it(*mp_target,j); it; ++it)
|
||||
(*this)(TargetRowMajor?j:it.index(), TargetRowMajor?it.index():j) = it.value();
|
||||
}
|
||||
|
||||
~RandomSetter()
|
||||
{
|
||||
KeyType keyBitsMask = (1<<m_keyBitsOffset)-1;
|
||||
if (!SwapStorage) // also means the map is sorted
|
||||
{
|
||||
mp_target->startFill(nonZeros());
|
||||
for (int k=0; k<m_outerPackets; ++k)
|
||||
{
|
||||
const int outerOffset = (1<<OuterPacketBits) * k;
|
||||
typename HashMapType::iterator end = m_hashmaps[k].end();
|
||||
for (typename HashMapType::iterator it = m_hashmaps[k].begin(); it!=end; ++it)
|
||||
{
|
||||
const int outer = (it->first >> m_keyBitsOffset) + outerOffset;
|
||||
const int inner = it->first & keyBitsMask;
|
||||
mp_target->fill(TargetRowMajor ? outer : inner, TargetRowMajor ? inner : outer) = it->second.value;
|
||||
}
|
||||
}
|
||||
mp_target->endFill();
|
||||
}
|
||||
else
|
||||
{
|
||||
VectorXi positions(mp_target->outerSize());
|
||||
positions.setZero();
|
||||
// pass 1
|
||||
for (int k=0; k<m_outerPackets; ++k)
|
||||
{
|
||||
typename HashMapType::iterator end = m_hashmaps[k].end();
|
||||
for (typename HashMapType::iterator it = m_hashmaps[k].begin(); it!=end; ++it)
|
||||
{
|
||||
const int outer = it->first & keyBitsMask;
|
||||
positions[outer]++;
|
||||
}
|
||||
}
|
||||
// prefix sum
|
||||
int count = 0;
|
||||
for (int j=0; j<mp_target->outerSize(); ++j)
|
||||
{
|
||||
int tmp = positions[j];
|
||||
mp_target->_outerIndexPtr()[j] = count;
|
||||
positions[j] = count;
|
||||
count += tmp;
|
||||
}
|
||||
mp_target->_outerIndexPtr()[mp_target->outerSize()] = count;
|
||||
mp_target->resizeNonZeros(count);
|
||||
// pass 2
|
||||
for (int k=0; k<m_outerPackets; ++k)
|
||||
{
|
||||
const int outerOffset = (1<<OuterPacketBits) * k;
|
||||
typename HashMapType::iterator end = m_hashmaps[k].end();
|
||||
for (typename HashMapType::iterator it = m_hashmaps[k].begin(); it!=end; ++it)
|
||||
{
|
||||
const int inner = (it->first >> m_keyBitsOffset) + outerOffset;
|
||||
const int outer = it->first & keyBitsMask;
|
||||
// sorted insertion
|
||||
// Note that we have to deal with at most 2^OuterPacketBits unsorted coefficients,
|
||||
// moreover those 2^OuterPacketBits coeffs are likely to be sparse, an so only a
|
||||
// small fraction of them have to be sorted, whence the following simple procedure:
|
||||
int posStart = mp_target->_outerIndexPtr()[outer];
|
||||
int i = (positions[outer]++) - 1;
|
||||
while ( (i >= posStart) && (mp_target->_innerIndexPtr()[i] > inner) )
|
||||
{
|
||||
mp_target->_valuePtr()[i+1] = mp_target->_valuePtr()[i];
|
||||
mp_target->_innerIndexPtr()[i+1] = mp_target->_innerIndexPtr()[i];
|
||||
--i;
|
||||
}
|
||||
mp_target->_innerIndexPtr()[i+1] = inner;
|
||||
mp_target->_valuePtr()[i+1] = it->second.value;
|
||||
}
|
||||
}
|
||||
}
|
||||
delete[] m_hashmaps;
|
||||
}
|
||||
|
||||
Scalar& operator() (int row, int col)
|
||||
{
|
||||
const int outer = SetterRowMajor ? row : col;
|
||||
const int inner = SetterRowMajor ? col : row;
|
||||
const int outerMajor = outer >> OuterPacketBits; // index of the packet/map
|
||||
const int outerMinor = outer & OuterPacketMask; // index of the inner vector in the packet
|
||||
const KeyType key = (KeyType(outerMinor)<<m_keyBitsOffset) | inner;
|
||||
return m_hashmaps[outerMajor][key].value;
|
||||
}
|
||||
|
||||
// might be slow
|
||||
int nonZeros() const
|
||||
{
|
||||
int nz = 0;
|
||||
for (int k=0; k<m_outerPackets; ++k)
|
||||
nz += m_hashmaps[k].size();
|
||||
return nz;
|
||||
}
|
||||
|
||||
|
||||
protected:
|
||||
|
||||
HashMapType* m_hashmaps;
|
||||
SparseMatrixType* mp_target;
|
||||
int m_outerPackets;
|
||||
unsigned char m_keyBitsOffset;
|
||||
};
|
||||
|
||||
#endif // EIGEN_RANDOMSETTER_H
|
||||
@@ -28,7 +28,8 @@
|
||||
/** Stores a sparse set of values as a list of values and a list of indices.
|
||||
*
|
||||
*/
|
||||
template<typename Scalar> class SparseArray
|
||||
template<typename Scalar>
|
||||
class SparseArray
|
||||
{
|
||||
public:
|
||||
SparseArray()
|
||||
@@ -105,6 +106,15 @@ template<typename Scalar> class SparseArray
|
||||
int& index(int i) { return m_indices[i]; }
|
||||
const int& index(int i) const { return m_indices[i]; }
|
||||
|
||||
static SparseArray Map(int* indices, Scalar* values, int size)
|
||||
{
|
||||
SparseArray res;
|
||||
res.m_indices = indices;
|
||||
res.m_values = values;
|
||||
res.m_allocatedSize = res.m_size = size;
|
||||
return res;
|
||||
}
|
||||
|
||||
protected:
|
||||
|
||||
void reallocate(int size)
|
||||
|
||||
@@ -59,7 +59,7 @@ public:
|
||||
: m_matrix(matrix), m_startRow(startRow), m_startCol(startCol),
|
||||
m_blockRows(matrix.rows()), m_blockCols(matrix.cols())
|
||||
{
|
||||
EIGEN_STATIC_ASSERT(RowsAtCompileTime!=Dynamic && RowsAtCompileTime!=Dynamic,this_method_is_only_for_fixed_size);
|
||||
EIGEN_STATIC_ASSERT(RowsAtCompileTime!=Dynamic && RowsAtCompileTime!=Dynamic,this_method_is_only_for_fixed_size)
|
||||
ei_assert(startRow >= 0 && BlockRows >= 1 && startRow + BlockRows <= matrix.rows()
|
||||
&& startCol >= 0 && BlockCols >= 1 && startCol + BlockCols <= matrix.cols());
|
||||
}
|
||||
|
||||
346
Eigen/src/Sparse/SparseLDLT.h
Normal file
346
Eigen/src/Sparse/SparseLDLT.h
Normal file
@@ -0,0 +1,346 @@
|
||||
// This file is part of Eigen, a lightweight C++ template library
|
||||
// for linear algebra. Eigen itself is part of the KDE project.
|
||||
//
|
||||
// Copyright (C) 2008 Gael Guennebaud <g.gael@free.fr>
|
||||
//
|
||||
// Eigen is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU Lesser General Public
|
||||
// License as published by the Free Software Foundation; either
|
||||
// version 3 of the License, or (at your option) any later version.
|
||||
//
|
||||
// Alternatively, you can redistribute it and/or
|
||||
// modify it under the terms of the GNU General Public License as
|
||||
// published by the Free Software Foundation; either version 2 of
|
||||
// the License, or (at your option) any later version.
|
||||
//
|
||||
// Eigen is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||
// FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License or the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public
|
||||
// License and a copy of the GNU General Public License along with
|
||||
// Eigen. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
/*
|
||||
|
||||
NOTE: the _symbolic, and _numeric functions has been adapted from
|
||||
the LDL library:
|
||||
|
||||
LDL Copyright (c) 2005 by Timothy A. Davis. All Rights Reserved.
|
||||
|
||||
LDL License:
|
||||
|
||||
Your use or distribution of LDL or any modified version of
|
||||
LDL implies that you agree to this License.
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
|
||||
USA
|
||||
|
||||
Permission is hereby granted to use or copy this program under the
|
||||
terms of the GNU LGPL, provided that the Copyright, this License,
|
||||
and the Availability of the original version is retained on all copies.
|
||||
User documentation of any code that uses this code or any modified
|
||||
version of this code must cite the Copyright, this License, the
|
||||
Availability note, and "Used by permission." Permission to modify
|
||||
the code and to distribute modified code is granted, provided the
|
||||
Copyright, this License, and the Availability note are retained,
|
||||
and a notice that the code was modified is included.
|
||||
*/
|
||||
|
||||
#ifndef EIGEN_SPARSELDLT_H
|
||||
#define EIGEN_SPARSELDLT_H
|
||||
|
||||
/** \ingroup Sparse_Module
|
||||
*
|
||||
* \class SparseLDLT
|
||||
*
|
||||
* \brief LDLT Cholesky decomposition of a sparse matrix and associated features
|
||||
*
|
||||
* \param MatrixType the type of the matrix of which we are computing the LDLT Cholesky decomposition
|
||||
*
|
||||
* \sa class LDLT, class LDLT
|
||||
*/
|
||||
template<typename MatrixType, int Backend = DefaultBackend>
|
||||
class SparseLDLT
|
||||
{
|
||||
protected:
|
||||
typedef typename MatrixType::Scalar Scalar;
|
||||
typedef typename NumTraits<typename MatrixType::Scalar>::Real RealScalar;
|
||||
typedef SparseMatrix<Scalar,Lower|UnitDiagBit> CholMatrixType;
|
||||
typedef Matrix<Scalar,MatrixType::ColsAtCompileTime,1> VectorType;
|
||||
|
||||
enum {
|
||||
SupernodalFactorIsDirty = 0x10000,
|
||||
MatrixLIsDirty = 0x20000
|
||||
};
|
||||
|
||||
public:
|
||||
|
||||
/** Creates a dummy LDLT factorization object with flags \a flags. */
|
||||
SparseLDLT(int flags = 0)
|
||||
: m_flags(flags), m_status(0)
|
||||
{
|
||||
ei_assert((MatrixType::Flags&RowMajorBit)==0);
|
||||
m_precision = RealScalar(0.1) * Eigen::precision<RealScalar>();
|
||||
}
|
||||
|
||||
/** Creates a LDLT object and compute the respective factorization of \a matrix using
|
||||
* flags \a flags. */
|
||||
SparseLDLT(const MatrixType& matrix, int flags = 0)
|
||||
: m_matrix(matrix.rows(), matrix.cols()), m_flags(flags), m_status(0)
|
||||
{
|
||||
ei_assert((MatrixType::Flags&RowMajorBit)==0);
|
||||
m_precision = RealScalar(0.1) * Eigen::precision<RealScalar>();
|
||||
compute(matrix);
|
||||
}
|
||||
|
||||
/** Sets the relative threshold value used to prune zero coefficients during the decomposition.
|
||||
*
|
||||
* Setting a value greater than zero speeds up computation, and yields to an imcomplete
|
||||
* factorization with fewer non zero coefficients. Such approximate factors are especially
|
||||
* useful to initialize an iterative solver.
|
||||
*
|
||||
* \warning if precision is greater that zero, the LDLT factorization is not guaranteed to succeed
|
||||
* even if the matrix is positive definite.
|
||||
*
|
||||
* Note that the exact meaning of this parameter might depends on the actual
|
||||
* backend. Moreover, not all backends support this feature.
|
||||
*
|
||||
* \sa precision() */
|
||||
void setPrecision(RealScalar v) { m_precision = v; }
|
||||
|
||||
/** \returns the current precision.
|
||||
*
|
||||
* \sa setPrecision() */
|
||||
RealScalar precision() const { return m_precision; }
|
||||
|
||||
/** Sets the flags. Possible values are:
|
||||
* - CompleteFactorization
|
||||
* - IncompleteFactorization
|
||||
* - MemoryEfficient (hint to use the memory most efficient method offered by the backend)
|
||||
* - SupernodalMultifrontal (implies a complete factorization if supported by the backend,
|
||||
* overloads the MemoryEfficient flags)
|
||||
* - SupernodalLeftLooking (implies a complete factorization if supported by the backend,
|
||||
* overloads the MemoryEfficient flags)
|
||||
*
|
||||
* \sa flags() */
|
||||
void settagss(int f) { m_flags = f; }
|
||||
/** \returns the current flags */
|
||||
int flags() const { return m_flags; }
|
||||
|
||||
/** Computes/re-computes the LDLT factorization */
|
||||
void compute(const MatrixType& matrix);
|
||||
|
||||
/** Perform a symbolic factorization */
|
||||
void _symbolic(const MatrixType& matrix);
|
||||
/** Perform the actual factorization using the previously
|
||||
* computed symbolic factorization */
|
||||
bool _numeric(const MatrixType& matrix);
|
||||
|
||||
/** \returns the lower triangular matrix L */
|
||||
inline const CholMatrixType& matrixL(void) const { return m_matrix; }
|
||||
|
||||
/** \returns the coefficients of the diagonal matrix D */
|
||||
inline VectorType vectorD(void) const { return m_diag; }
|
||||
|
||||
template<typename Derived>
|
||||
bool solveInPlace(MatrixBase<Derived> &b) const;
|
||||
|
||||
/** \returns true if the factorization succeeded */
|
||||
inline bool succeeded(void) const { return m_succeeded; }
|
||||
|
||||
protected:
|
||||
CholMatrixType m_matrix;
|
||||
VectorType m_diag;
|
||||
VectorXi m_parent; // elimination tree
|
||||
VectorXi m_nonZerosPerCol;
|
||||
// VectorXi m_w; // workspace
|
||||
RealScalar m_precision;
|
||||
int m_flags;
|
||||
mutable int m_status;
|
||||
bool m_succeeded;
|
||||
};
|
||||
|
||||
/** Computes / recomputes the LDLT decomposition of matrix \a a
|
||||
* using the default algorithm.
|
||||
*/
|
||||
template<typename MatrixType, int Backend>
|
||||
void SparseLDLT<MatrixType,Backend>::compute(const MatrixType& a)
|
||||
{
|
||||
_symbolic(a);
|
||||
m_succeeded = _numeric(a);
|
||||
}
|
||||
|
||||
template<typename MatrixType, int Backend>
|
||||
void SparseLDLT<MatrixType,Backend>::_symbolic(const MatrixType& a)
|
||||
{
|
||||
assert(a.rows()==a.cols());
|
||||
const int size = a.rows();
|
||||
m_matrix.resize(size, size);
|
||||
m_parent.resize(size);
|
||||
m_nonZerosPerCol.resize(size);
|
||||
int * tags = ei_alloc_stack(int, size);
|
||||
|
||||
const int* Ap = a._outerIndexPtr();
|
||||
const int* Ai = a._innerIndexPtr();
|
||||
int* Lp = m_matrix._outerIndexPtr();
|
||||
const int* P = 0;
|
||||
int* Pinv = 0;
|
||||
|
||||
if (P)
|
||||
{
|
||||
/* If P is present then compute Pinv, the inverse of P */
|
||||
for (int k = 0; k < size; k++)
|
||||
Pinv[P[k]] = k;
|
||||
}
|
||||
for (int k = 0; k < size; k++)
|
||||
{
|
||||
/* L(k,:) pattern: all nodes reachable in etree from nz in A(0:k-1,k) */
|
||||
m_parent[k] = -1; /* parent of k is not yet known */
|
||||
tags[k] = k; /* mark node k as visited */
|
||||
m_nonZerosPerCol[k] = 0; /* count of nonzeros in column k of L */
|
||||
int kk = P ? P[k] : k; /* kth original, or permuted, column */
|
||||
int p2 = Ap[kk+1];
|
||||
for (int p = Ap[kk]; p < p2; p++)
|
||||
{
|
||||
/* A (i,k) is nonzero (original or permuted A) */
|
||||
int i = Pinv ? Pinv[Ai[p]] : Ai[p];
|
||||
if (i < k)
|
||||
{
|
||||
/* follow path from i to root of etree, stop at flagged node */
|
||||
for (; tags[i] != k; i = m_parent[i])
|
||||
{
|
||||
/* find parent of i if not yet determined */
|
||||
if (m_parent[i] == -1)
|
||||
m_parent[i] = k;
|
||||
m_nonZerosPerCol[i]++; /* L (k,i) is nonzero */
|
||||
tags[i] = k; /* mark i as visited */
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
/* construct Lp index array from m_nonZerosPerCol column counts */
|
||||
Lp[0] = 0;
|
||||
for (int k = 0; k < size; k++)
|
||||
Lp[k+1] = Lp[k] + m_nonZerosPerCol[k];
|
||||
|
||||
m_matrix.resizeNonZeros(Lp[size]);
|
||||
ei_free_stack(tags, int, size);
|
||||
}
|
||||
|
||||
template<typename MatrixType, int Backend>
|
||||
bool SparseLDLT<MatrixType,Backend>::_numeric(const MatrixType& a)
|
||||
{
|
||||
assert(a.rows()==a.cols());
|
||||
const int size = a.rows();
|
||||
assert(m_parent.size()==size);
|
||||
assert(m_nonZerosPerCol.size()==size);
|
||||
|
||||
const int* Ap = a._outerIndexPtr();
|
||||
const int* Ai = a._innerIndexPtr();
|
||||
const Scalar* Ax = a._valuePtr();
|
||||
const int* Lp = m_matrix._outerIndexPtr();
|
||||
int* Li = m_matrix._innerIndexPtr();
|
||||
Scalar* Lx = m_matrix._valuePtr();
|
||||
m_diag.resize(size);
|
||||
|
||||
Scalar * y = ei_alloc_stack(Scalar, size);
|
||||
int * pattern = ei_alloc_stack(int, size);
|
||||
int * tags = ei_alloc_stack(int, size);
|
||||
|
||||
const int* P = 0;
|
||||
const int* Pinv = 0;
|
||||
bool ok = true;
|
||||
|
||||
for (int k = 0; k < size; k++)
|
||||
{
|
||||
/* compute nonzero pattern of kth row of L, in topological order */
|
||||
y[k] = 0.0; /* Y(0:k) is now all zero */
|
||||
int top = size; /* stack for pattern is empty */
|
||||
tags[k] = k; /* mark node k as visited */
|
||||
m_nonZerosPerCol[k] = 0; /* count of nonzeros in column k of L */
|
||||
int kk = (P) ? (P[k]) : (k); /* kth original, or permuted, column */
|
||||
int p2 = Ap[kk+1];
|
||||
for (int p = Ap[kk]; p < p2; p++)
|
||||
{
|
||||
int i = Pinv ? Pinv[Ai[p]] : Ai[p]; /* get A(i,k) */
|
||||
if (i <= k)
|
||||
{
|
||||
y[i] += Ax[p]; /* scatter A(i,k) into Y (sum duplicates) */
|
||||
int len;
|
||||
for (len = 0; tags[i] != k; i = m_parent[i])
|
||||
{
|
||||
pattern[len++] = i; /* L(k,i) is nonzero */
|
||||
tags[i] = k; /* mark i as visited */
|
||||
}
|
||||
while (len > 0)
|
||||
pattern[--top] = pattern[--len];
|
||||
}
|
||||
}
|
||||
/* compute numerical values kth row of L (a sparse triangular solve) */
|
||||
m_diag[k] = y[k]; /* get D(k,k) and clear Y(k) */
|
||||
y[k] = 0.0;
|
||||
for (; top < size; top++)
|
||||
{
|
||||
int i = pattern[top]; /* pattern[top:n-1] is pattern of L(:,k) */
|
||||
Scalar yi = y[i]; /* get and clear Y(i) */
|
||||
y[i] = 0.0;
|
||||
int p2 = Lp[i] + m_nonZerosPerCol[i];
|
||||
int p;
|
||||
for (p = Lp[i]; p < p2; p++)
|
||||
y[Li[p]] -= Lx[p] * yi;
|
||||
Scalar l_ki = yi / m_diag[i]; /* the nonzero entry L(k,i) */
|
||||
m_diag[k] -= l_ki * yi;
|
||||
Li[p] = k; /* store L(k,i) in column form of L */
|
||||
Lx[p] = l_ki;
|
||||
m_nonZerosPerCol[i]++; /* increment count of nonzeros in col i */
|
||||
}
|
||||
if (m_diag[k] == 0.0)
|
||||
{
|
||||
ok = false; /* failure, D(k,k) is zero */
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
ei_free_stack(y, Scalar, size);
|
||||
ei_free_stack(pattern, int, size);
|
||||
ei_free_stack(tags, int, size);
|
||||
|
||||
return ok; /* success, diagonal of D is all nonzero */
|
||||
}
|
||||
|
||||
/** Computes b = L^-T L^-1 b */
|
||||
template<typename MatrixType, int Backend>
|
||||
template<typename Derived>
|
||||
bool SparseLDLT<MatrixType, Backend>::solveInPlace(MatrixBase<Derived> &b) const
|
||||
{
|
||||
const int size = m_matrix.rows();
|
||||
ei_assert(size==b.rows());
|
||||
if (!m_succeeded)
|
||||
return false;
|
||||
|
||||
if (m_matrix.nonZeros()>0) // otherwise L==I
|
||||
m_matrix.solveTriangularInPlace(b);
|
||||
b = b.cwise() / m_diag;
|
||||
// FIXME should be .adjoint() but it fails to compile...
|
||||
|
||||
if (m_matrix.nonZeros()>0) // otherwise L==I
|
||||
m_matrix.transpose().solveTriangularInPlace(b);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
#endif // EIGEN_SPARSELDLT_H
|
||||
199
Eigen/src/Sparse/SparseLLT.h
Normal file
199
Eigen/src/Sparse/SparseLLT.h
Normal file
@@ -0,0 +1,199 @@
|
||||
// This file is part of Eigen, a lightweight C++ template library
|
||||
// for linear algebra. Eigen itself is part of the KDE project.
|
||||
//
|
||||
// Copyright (C) 2008 Gael Guennebaud <g.gael@free.fr>
|
||||
//
|
||||
// Eigen is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU Lesser General Public
|
||||
// License as published by the Free Software Foundation; either
|
||||
// version 3 of the License, or (at your option) any later version.
|
||||
//
|
||||
// Alternatively, you can redistribute it and/or
|
||||
// modify it under the terms of the GNU General Public License as
|
||||
// published by the Free Software Foundation; either version 2 of
|
||||
// the License, or (at your option) any later version.
|
||||
//
|
||||
// Eigen is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||
// FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License or the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public
|
||||
// License and a copy of the GNU General Public License along with
|
||||
// Eigen. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
#ifndef EIGEN_SPARSELLT_H
|
||||
#define EIGEN_SPARSELLT_H
|
||||
|
||||
/** \ingroup Sparse_Module
|
||||
*
|
||||
* \class SparseLLT
|
||||
*
|
||||
* \brief LLT Cholesky decomposition of a sparse matrix and associated features
|
||||
*
|
||||
* \param MatrixType the type of the matrix of which we are computing the LLT Cholesky decomposition
|
||||
*
|
||||
* \sa class LLT, class LDLT
|
||||
*/
|
||||
template<typename MatrixType, int Backend = DefaultBackend>
|
||||
class SparseLLT
|
||||
{
|
||||
protected:
|
||||
typedef typename MatrixType::Scalar Scalar;
|
||||
typedef typename NumTraits<typename MatrixType::Scalar>::Real RealScalar;
|
||||
typedef SparseMatrix<Scalar,Lower> CholMatrixType;
|
||||
|
||||
enum {
|
||||
SupernodalFactorIsDirty = 0x10000,
|
||||
MatrixLIsDirty = 0x20000
|
||||
};
|
||||
|
||||
public:
|
||||
|
||||
/** Creates a dummy LLT factorization object with flags \a flags. */
|
||||
SparseLLT(int flags = 0)
|
||||
: m_flags(flags), m_status(0)
|
||||
{
|
||||
m_precision = RealScalar(0.1) * Eigen::precision<RealScalar>();
|
||||
}
|
||||
|
||||
/** Creates a LLT object and compute the respective factorization of \a matrix using
|
||||
* flags \a flags. */
|
||||
SparseLLT(const MatrixType& matrix, int flags = 0)
|
||||
: m_matrix(matrix.rows(), matrix.cols()), m_flags(flags), m_status(0)
|
||||
{
|
||||
m_precision = RealScalar(0.1) * Eigen::precision<RealScalar>();
|
||||
compute(matrix);
|
||||
}
|
||||
|
||||
/** Sets the relative threshold value used to prune zero coefficients during the decomposition.
|
||||
*
|
||||
* Setting a value greater than zero speeds up computation, and yields to an imcomplete
|
||||
* factorization with fewer non zero coefficients. Such approximate factors are especially
|
||||
* useful to initialize an iterative solver.
|
||||
*
|
||||
* \warning if precision is greater that zero, the LLT factorization is not guaranteed to succeed
|
||||
* even if the matrix is positive definite.
|
||||
*
|
||||
* Note that the exact meaning of this parameter might depends on the actual
|
||||
* backend. Moreover, not all backends support this feature.
|
||||
*
|
||||
* \sa precision() */
|
||||
void setPrecision(RealScalar v) { m_precision = v; }
|
||||
|
||||
/** \returns the current precision.
|
||||
*
|
||||
* \sa setPrecision() */
|
||||
RealScalar precision() const { return m_precision; }
|
||||
|
||||
/** Sets the flags. Possible values are:
|
||||
* - CompleteFactorization
|
||||
* - IncompleteFactorization
|
||||
* - MemoryEfficient (hint to use the memory most efficient method offered by the backend)
|
||||
* - SupernodalMultifrontal (implies a complete factorization if supported by the backend,
|
||||
* overloads the MemoryEfficient flags)
|
||||
* - SupernodalLeftLooking (implies a complete factorization if supported by the backend,
|
||||
* overloads the MemoryEfficient flags)
|
||||
*
|
||||
* \sa flags() */
|
||||
void setFlags(int f) { m_flags = f; }
|
||||
/** \returns the current flags */
|
||||
int flags() const { return m_flags; }
|
||||
|
||||
/** Computes/re-computes the LLT factorization */
|
||||
void compute(const MatrixType& matrix);
|
||||
|
||||
/** \returns the lower triangular matrix L */
|
||||
inline const CholMatrixType& matrixL(void) const { return m_matrix; }
|
||||
|
||||
template<typename Derived>
|
||||
bool solveInPlace(MatrixBase<Derived> &b) const;
|
||||
|
||||
/** \returns true if the factorization succeeded */
|
||||
inline bool succeeded(void) const { return m_succeeded; }
|
||||
|
||||
protected:
|
||||
CholMatrixType m_matrix;
|
||||
RealScalar m_precision;
|
||||
int m_flags;
|
||||
mutable int m_status;
|
||||
bool m_succeeded;
|
||||
};
|
||||
|
||||
/** Computes / recomputes the LLT decomposition of matrix \a a
|
||||
* using the default algorithm.
|
||||
*/
|
||||
template<typename MatrixType, int Backend>
|
||||
void SparseLLT<MatrixType,Backend>::compute(const MatrixType& a)
|
||||
{
|
||||
assert(a.rows()==a.cols());
|
||||
const int size = a.rows();
|
||||
m_matrix.resize(size, size);
|
||||
|
||||
// allocate a temporary vector for accumulations
|
||||
AmbiVector<Scalar> tempVector(size);
|
||||
RealScalar density = a.nonZeros()/RealScalar(size*size);
|
||||
|
||||
// TODO estimate the number of non zeros
|
||||
m_matrix.startFill(a.nonZeros()*2);
|
||||
for (int j = 0; j < size; ++j)
|
||||
{
|
||||
Scalar x = ei_real(a.coeff(j,j));
|
||||
|
||||
// TODO better estimate of the density !
|
||||
tempVector.init(density>0.001? IsDense : IsSparse);
|
||||
tempVector.setBounds(j+1,size);
|
||||
tempVector.setZero();
|
||||
// init with current matrix a
|
||||
{
|
||||
typename MatrixType::InnerIterator it(a,j);
|
||||
++it; // skip diagonal element
|
||||
for (; it; ++it)
|
||||
tempVector.coeffRef(it.index()) = it.value();
|
||||
}
|
||||
for (int k=0; k<j+1; ++k)
|
||||
{
|
||||
typename CholMatrixType::InnerIterator it(m_matrix, k);
|
||||
while (it && it.index()<j)
|
||||
++it;
|
||||
if (it && it.index()==j)
|
||||
{
|
||||
Scalar y = it.value();
|
||||
x -= ei_abs2(y);
|
||||
++it; // skip j-th element, and process remaining column coefficients
|
||||
tempVector.restart();
|
||||
for (; it; ++it)
|
||||
{
|
||||
tempVector.coeffRef(it.index()) -= it.value() * y;
|
||||
}
|
||||
}
|
||||
}
|
||||
// copy the temporary vector to the respective m_matrix.col()
|
||||
// while scaling the result by 1/real(x)
|
||||
RealScalar rx = ei_sqrt(ei_real(x));
|
||||
m_matrix.fill(j,j) = rx;
|
||||
Scalar y = Scalar(1)/rx;
|
||||
for (typename AmbiVector<Scalar>::Iterator it(tempVector, m_precision*rx); it; ++it)
|
||||
{
|
||||
m_matrix.fill(it.index(), j) = it.value() * y;
|
||||
}
|
||||
}
|
||||
m_matrix.endFill();
|
||||
}
|
||||
|
||||
/** Computes b = L^-T L^-1 b */
|
||||
template<typename MatrixType, int Backend>
|
||||
template<typename Derived>
|
||||
bool SparseLLT<MatrixType, Backend>::solveInPlace(MatrixBase<Derived> &b) const
|
||||
{
|
||||
const int size = m_matrix.rows();
|
||||
ei_assert(size==b.rows());
|
||||
|
||||
m_matrix.solveTriangularInPlace(b);
|
||||
// FIXME should be .adjoint() but it fails to compile...
|
||||
m_matrix.transpose().solveTriangularInPlace(b);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
#endif // EIGEN_SPARSELLT_H
|
||||
148
Eigen/src/Sparse/SparseLU.h
Normal file
148
Eigen/src/Sparse/SparseLU.h
Normal file
@@ -0,0 +1,148 @@
|
||||
// This file is part of Eigen, a lightweight C++ template library
|
||||
// for linear algebra. Eigen itself is part of the KDE project.
|
||||
//
|
||||
// Copyright (C) 2008 Gael Guennebaud <g.gael@free.fr>
|
||||
//
|
||||
// Eigen is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU Lesser General Public
|
||||
// License as published by the Free Software Foundation; either
|
||||
// version 3 of the License, or (at your option) any later version.
|
||||
//
|
||||
// Alternatively, you can redistribute it and/or
|
||||
// modify it under the terms of the GNU General Public License as
|
||||
// published by the Free Software Foundation; either version 2 of
|
||||
// the License, or (at your option) any later version.
|
||||
//
|
||||
// Eigen is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||
// FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License or the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public
|
||||
// License and a copy of the GNU General Public License along with
|
||||
// Eigen. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
#ifndef EIGEN_SPARSELU_H
|
||||
#define EIGEN_SPARSELU_H
|
||||
|
||||
/** \ingroup Sparse_Module
|
||||
*
|
||||
* \class SparseLU
|
||||
*
|
||||
* \brief LU decomposition of a sparse matrix and associated features
|
||||
*
|
||||
* \param MatrixType the type of the matrix of which we are computing the LU factorization
|
||||
*
|
||||
* \sa class LU, class SparseLLT
|
||||
*/
|
||||
template<typename MatrixType, int Backend = DefaultBackend>
|
||||
class SparseLU
|
||||
{
|
||||
protected:
|
||||
typedef typename MatrixType::Scalar Scalar;
|
||||
typedef typename NumTraits<typename MatrixType::Scalar>::Real RealScalar;
|
||||
typedef SparseMatrix<Scalar,Lower> LUMatrixType;
|
||||
|
||||
enum {
|
||||
MatrixLUIsDirty = 0x10000
|
||||
};
|
||||
|
||||
public:
|
||||
|
||||
/** Creates a dummy LU factorization object with flags \a flags. */
|
||||
SparseLU(int flags = 0)
|
||||
: m_flags(flags), m_status(0)
|
||||
{
|
||||
m_precision = RealScalar(0.1) * Eigen::precision<RealScalar>();
|
||||
}
|
||||
|
||||
/** Creates a LU object and compute the respective factorization of \a matrix using
|
||||
* flags \a flags. */
|
||||
SparseLU(const MatrixType& matrix, int flags = 0)
|
||||
: /*m_matrix(matrix.rows(), matrix.cols()),*/ m_flags(flags), m_status(0)
|
||||
{
|
||||
m_precision = RealScalar(0.1) * Eigen::precision<RealScalar>();
|
||||
compute(matrix);
|
||||
}
|
||||
|
||||
/** Sets the relative threshold value used to prune zero coefficients during the decomposition.
|
||||
*
|
||||
* Setting a value greater than zero speeds up computation, and yields to an imcomplete
|
||||
* factorization with fewer non zero coefficients. Such approximate factors are especially
|
||||
* useful to initialize an iterative solver.
|
||||
*
|
||||
* Note that the exact meaning of this parameter might depends on the actual
|
||||
* backend. Moreover, not all backends support this feature.
|
||||
*
|
||||
* \sa precision() */
|
||||
void setPrecision(RealScalar v) { m_precision = v; }
|
||||
|
||||
/** \returns the current precision.
|
||||
*
|
||||
* \sa setPrecision() */
|
||||
RealScalar precision() const { return m_precision; }
|
||||
|
||||
/** Sets the flags. Possible values are:
|
||||
* - CompleteFactorization
|
||||
* - IncompleteFactorization
|
||||
* - MemoryEfficient
|
||||
* - one of the ordering methods
|
||||
* - etc...
|
||||
*
|
||||
* \sa flags() */
|
||||
void setFlags(int f) { m_flags = f; }
|
||||
/** \returns the current flags */
|
||||
int flags() const { return m_flags; }
|
||||
|
||||
void setOrderingMethod(int m)
|
||||
{
|
||||
ei_assert(m&~OrderingMask == 0 && m!=0 && "invalid ordering method");
|
||||
m_flags = m_flags&~OrderingMask | m&OrderingMask;
|
||||
}
|
||||
|
||||
int orderingMethod() const
|
||||
{
|
||||
return m_flags&OrderingMask;
|
||||
}
|
||||
|
||||
/** Computes/re-computes the LU factorization */
|
||||
void compute(const MatrixType& matrix);
|
||||
|
||||
/** \returns the lower triangular matrix L */
|
||||
//inline const MatrixType& matrixL() const { return m_matrixL; }
|
||||
|
||||
/** \returns the upper triangular matrix U */
|
||||
//inline const MatrixType& matrixU() const { return m_matrixU; }
|
||||
|
||||
template<typename BDerived, typename XDerived>
|
||||
bool solve(const MatrixBase<BDerived> &b, MatrixBase<XDerived>* x) const;
|
||||
|
||||
/** \returns true if the factorization succeeded */
|
||||
inline bool succeeded(void) const { return m_succeeded; }
|
||||
|
||||
protected:
|
||||
RealScalar m_precision;
|
||||
int m_flags;
|
||||
mutable int m_status;
|
||||
bool m_succeeded;
|
||||
};
|
||||
|
||||
/** Computes / recomputes the LU decomposition of matrix \a a
|
||||
* using the default algorithm.
|
||||
*/
|
||||
template<typename MatrixType, int Backend>
|
||||
void SparseLU<MatrixType,Backend>::compute(const MatrixType& a)
|
||||
{
|
||||
ei_assert(false && "not implemented yet");
|
||||
}
|
||||
|
||||
/** Computes *x = U^-1 L^-1 b */
|
||||
template<typename MatrixType, int Backend>
|
||||
template<typename BDerived, typename XDerived>
|
||||
bool SparseLU<MatrixType,Backend>::solve(const MatrixBase<BDerived> &b, MatrixBase<XDerived>* x) const
|
||||
{
|
||||
ei_assert(false && "not implemented yet");
|
||||
return false;
|
||||
}
|
||||
|
||||
#endif // EIGEN_SPARSELU_H
|
||||
@@ -65,6 +65,7 @@ class SparseMatrix
|
||||
enum {
|
||||
RowMajor = SparseBase::RowMajor
|
||||
};
|
||||
typedef SparseMatrix<Scalar,(Flags&~RowMajorBit)|(RowMajor?RowMajorBit:0)> TransposedSparseMatrix;
|
||||
|
||||
int m_outerSize;
|
||||
int m_innerSize;
|
||||
@@ -80,6 +81,15 @@ class SparseMatrix
|
||||
inline int outerSize() const { return m_outerSize; }
|
||||
inline int innerNonZeros(int j) const { return m_outerIndex[j+1]-m_outerIndex[j]; }
|
||||
|
||||
inline const Scalar* _valuePtr() const { return &m_data.value(0); }
|
||||
inline Scalar* _valuePtr() { return &m_data.value(0); }
|
||||
|
||||
inline const int* _innerIndexPtr() const { return &m_data.index(0); }
|
||||
inline int* _innerIndexPtr() { return &m_data.index(0); }
|
||||
|
||||
inline const int* _outerIndexPtr() const { return m_outerIndex; }
|
||||
inline int* _outerIndexPtr() { return m_outerIndex; }
|
||||
|
||||
inline Scalar coeff(int row, int col) const
|
||||
{
|
||||
const int outer = RowMajor ? row : col;
|
||||
@@ -133,10 +143,10 @@ class SparseMatrix
|
||||
{
|
||||
const int outer = RowMajor ? row : col;
|
||||
const int inner = RowMajor ? col : row;
|
||||
|
||||
// std::cout << " fill " << outer << "," << inner << "\n";
|
||||
if (m_outerIndex[outer+1]==0)
|
||||
{
|
||||
int i=col;
|
||||
int i = outer;
|
||||
while (i>=0 && m_outerIndex[i]==0)
|
||||
{
|
||||
m_outerIndex[i] = m_data.size();
|
||||
@@ -179,6 +189,14 @@ class SparseMatrix
|
||||
m_outerSize = outerSize;
|
||||
}
|
||||
}
|
||||
void resizeNonZeros(int size)
|
||||
{
|
||||
m_data.resize(size);
|
||||
}
|
||||
|
||||
inline SparseMatrix()
|
||||
: m_outerSize(0), m_innerSize(0), m_outerIndex(0)
|
||||
{}
|
||||
|
||||
inline SparseMatrix(int rows, int cols)
|
||||
: m_outerSize(0), m_innerSize(0), m_outerIndex(0)
|
||||
@@ -195,7 +213,7 @@ class SparseMatrix
|
||||
|
||||
inline void swap(SparseMatrix& other)
|
||||
{
|
||||
EIGEN_DBG_SPARSE(std::cout << "SparseMatrix:: swap\n");
|
||||
//EIGEN_DBG_SPARSE(std::cout << "SparseMatrix:: swap\n");
|
||||
std::swap(m_outerIndex, other.m_outerIndex);
|
||||
std::swap(m_innerSize, other.m_innerSize);
|
||||
std::swap(m_outerSize, other.m_outerSize);
|
||||
@@ -204,6 +222,7 @@ class SparseMatrix
|
||||
|
||||
inline SparseMatrix& operator=(const SparseMatrix& other)
|
||||
{
|
||||
// std::cout << "SparseMatrix& operator=(const SparseMatrix& other)\n";
|
||||
if (other.isRValue())
|
||||
{
|
||||
swap(other.const_cast_derived());
|
||||
@@ -211,8 +230,7 @@ class SparseMatrix
|
||||
else
|
||||
{
|
||||
resize(other.rows(), other.cols());
|
||||
for (int j=0; j<=m_outerSize; ++j)
|
||||
m_outerIndex[j] = other.m_outerIndex[j];
|
||||
memcpy(m_outerIndex, other.m_outerIndex, (m_outerSize+1)*sizeof(int));
|
||||
m_data = other.m_data;
|
||||
}
|
||||
return *this;
|
||||
@@ -221,7 +239,54 @@ class SparseMatrix
|
||||
template<typename OtherDerived>
|
||||
inline SparseMatrix& operator=(const MatrixBase<OtherDerived>& other)
|
||||
{
|
||||
return SparseMatrixBase<SparseMatrix>::operator=(other.derived());
|
||||
const bool needToTranspose = (Flags & RowMajorBit) != (OtherDerived::Flags & RowMajorBit);
|
||||
if (needToTranspose)
|
||||
{
|
||||
// two passes algorithm:
|
||||
// 1 - compute the number of coeffs per dest inner vector
|
||||
// 2 - do the actual copy/eval
|
||||
// Since each coeff of the rhs has to be evaluated twice, let's evauluate it if needed
|
||||
typedef typename ei_nested<OtherDerived,2>::type OtherCopy;
|
||||
OtherCopy otherCopy(other.derived());
|
||||
typedef typename ei_cleantype<OtherCopy>::type _OtherCopy;
|
||||
|
||||
resize(other.rows(), other.cols());
|
||||
Eigen::Map<VectorXi>(m_outerIndex,outerSize()).setZero();
|
||||
// pass 1
|
||||
// FIXME the above copy could be merged with that pass
|
||||
for (int j=0; j<otherCopy.outerSize(); ++j)
|
||||
for (typename _OtherCopy::InnerIterator it(otherCopy, j); it; ++it)
|
||||
m_outerIndex[it.index()]++;
|
||||
|
||||
// prefix sum
|
||||
int count = 0;
|
||||
VectorXi positions(outerSize());
|
||||
for (int j=0; j<outerSize(); ++j)
|
||||
{
|
||||
int tmp = m_outerIndex[j];
|
||||
m_outerIndex[j] = count;
|
||||
positions[j] = count;
|
||||
count += tmp;
|
||||
}
|
||||
m_outerIndex[outerSize()] = count;
|
||||
// alloc
|
||||
m_data.resize(count);
|
||||
// pass 2
|
||||
for (int j=0; j<otherCopy.outerSize(); ++j)
|
||||
for (typename _OtherCopy::InnerIterator it(otherCopy, j); it; ++it)
|
||||
{
|
||||
int pos = positions[it.index()]++;
|
||||
m_data.index(pos) = j;
|
||||
m_data.value(pos) = it.value();
|
||||
}
|
||||
|
||||
return *this;
|
||||
}
|
||||
else
|
||||
{
|
||||
// there is no special optimization
|
||||
return SparseMatrixBase<SparseMatrix>::operator=(other.derived());
|
||||
}
|
||||
}
|
||||
|
||||
friend std::ostream & operator << (std::ostream & s, const SparseMatrix& m)
|
||||
@@ -246,6 +311,21 @@ class SparseMatrix
|
||||
return s;
|
||||
}
|
||||
|
||||
#ifdef EIGEN_TAUCS_SUPPORT
|
||||
static SparseMatrix Map(taucs_ccs_matrix& taucsMatrix);
|
||||
taucs_ccs_matrix asTaucsMatrix();
|
||||
#endif
|
||||
|
||||
#ifdef EIGEN_CHOLMOD_SUPPORT
|
||||
static SparseMatrix Map(cholmod_sparse& cholmodMatrix);
|
||||
cholmod_sparse asCholmodMatrix();
|
||||
#endif
|
||||
|
||||
#ifdef EIGEN_SUPERLU_SUPPORT
|
||||
static SparseMatrix Map(SluMatrix& sluMatrix);
|
||||
SluMatrix asSluMatrix();
|
||||
#endif
|
||||
|
||||
/** Destructor */
|
||||
inline ~SparseMatrix()
|
||||
{
|
||||
|
||||
@@ -51,6 +51,7 @@ class SparseMatrixBase : public MatrixBase<Derived>
|
||||
|
||||
inline Derived& operator=(const Derived& other)
|
||||
{
|
||||
// std::cout << "Derived& operator=(const Derived& other)\n";
|
||||
if (other.isRValue())
|
||||
derived().swap(other.const_cast_derived());
|
||||
else
|
||||
@@ -61,10 +62,13 @@ class SparseMatrixBase : public MatrixBase<Derived>
|
||||
template<typename OtherDerived>
|
||||
inline Derived& operator=(const MatrixBase<OtherDerived>& other)
|
||||
{
|
||||
// std::cout << "Derived& operator=(const MatrixBase<OtherDerived>& other)\n";
|
||||
const bool transpose = (Flags & RowMajorBit) != (OtherDerived::Flags & RowMajorBit);
|
||||
ei_assert((!transpose) && "the transpose operation is supposed to be handled in SparseMatrix::operator=");
|
||||
const int outerSize = other.outerSize();
|
||||
typedef typename ei_meta_if<transpose, LinkedVectorMatrix<Scalar,Flags&RowMajorBit>, Derived>::ret TempType;
|
||||
TempType temp(other.rows(), other.cols());
|
||||
//typedef typename ei_meta_if<transpose, LinkedVectorMatrix<Scalar,Flags&RowMajorBit>, Derived>::ret TempType;
|
||||
// thanks to shallow copies, we always eval to a tempary
|
||||
Derived temp(other.rows(), other.cols());
|
||||
|
||||
temp.startFill(std::max(this->rows(),this->cols())*2);
|
||||
for (int j=0; j<outerSize; ++j)
|
||||
@@ -88,6 +92,8 @@ class SparseMatrixBase : public MatrixBase<Derived>
|
||||
template<typename OtherDerived>
|
||||
inline Derived& operator=(const SparseMatrixBase<OtherDerived>& other)
|
||||
{
|
||||
// std::cout << typeid(OtherDerived).name() << "\n";
|
||||
// std::cout << Flags << " " << OtherDerived::Flags << "\n";
|
||||
const bool transpose = (Flags & RowMajorBit) != (OtherDerived::Flags & RowMajorBit);
|
||||
// std::cout << "eval transpose = " << transpose << "\n";
|
||||
const int outerSize = (int(OtherDerived::Flags) & RowMajorBit) ? other.rows() : other.cols();
|
||||
@@ -153,7 +159,7 @@ class SparseMatrixBase : public MatrixBase<Derived>
|
||||
}
|
||||
else
|
||||
{
|
||||
LinkedVectorMatrix<Scalar, RowMajorBit> trans = m.derived();
|
||||
SparseMatrix<Scalar, RowMajorBit> trans = m.derived();
|
||||
s << trans;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -41,22 +41,22 @@ struct ProductReturnType<Lhs,Rhs,SparseProduct>
|
||||
// type of the temporary to perform the transpose op
|
||||
typedef typename ei_meta_if<TransposeLhs,
|
||||
SparseMatrix<Scalar,0>,
|
||||
typename ei_nested<Lhs,Rhs::RowsAtCompileTime>::type>::ret LhsNested;
|
||||
const typename ei_nested<Lhs,Rhs::RowsAtCompileTime>::type>::ret LhsNested;
|
||||
|
||||
typedef typename ei_meta_if<TransposeRhs,
|
||||
SparseMatrix<Scalar,0>,
|
||||
typename ei_nested<Rhs,Lhs::RowsAtCompileTime>::type>::ret RhsNested;
|
||||
const typename ei_nested<Rhs,Lhs::RowsAtCompileTime>::type>::ret RhsNested;
|
||||
|
||||
typedef Product<typename ei_unconst<LhsNested>::type,
|
||||
typename ei_unconst<RhsNested>::type, SparseProduct> Type;
|
||||
typedef Product<LhsNested,
|
||||
RhsNested, SparseProduct> Type;
|
||||
};
|
||||
|
||||
template<typename LhsNested, typename RhsNested>
|
||||
struct ei_traits<Product<LhsNested, RhsNested, SparseProduct> >
|
||||
{
|
||||
// clean the nested types:
|
||||
typedef typename ei_unconst<typename ei_unref<LhsNested>::type>::type _LhsNested;
|
||||
typedef typename ei_unconst<typename ei_unref<RhsNested>::type>::type _RhsNested;
|
||||
typedef typename ei_cleantype<LhsNested>::type _LhsNested;
|
||||
typedef typename ei_cleantype<RhsNested>::type _RhsNested;
|
||||
typedef typename _LhsNested::Scalar Scalar;
|
||||
|
||||
enum {
|
||||
@@ -118,8 +118,8 @@ template<typename LhsNested, typename RhsNested> class Product<LhsNested,RhsNest
|
||||
const _LhsNested& rhs() const { return m_rhs; }
|
||||
|
||||
protected:
|
||||
const LhsNested m_lhs;
|
||||
const RhsNested m_rhs;
|
||||
LhsNested m_lhs;
|
||||
RhsNested m_rhs;
|
||||
};
|
||||
|
||||
template<typename Lhs, typename Rhs, typename ResultType,
|
||||
@@ -133,23 +133,16 @@ struct ei_sparse_product_selector<Lhs,Rhs,ResultType,ColMajor,ColMajor,ColMajor>
|
||||
{
|
||||
typedef typename ei_traits<typename ei_cleantype<Lhs>::type>::Scalar Scalar;
|
||||
|
||||
struct ListEl
|
||||
{
|
||||
int next;
|
||||
int index;
|
||||
Scalar value;
|
||||
};
|
||||
|
||||
static void run(const Lhs& lhs, const Rhs& rhs, ResultType& res)
|
||||
{
|
||||
// make sure to call innerSize/outerSize since we fake the storage order.
|
||||
int rows = lhs.innerSize();
|
||||
int cols = rhs.outerSize();
|
||||
int size = lhs.outerSize();
|
||||
ei_assert(size == rhs.rows());
|
||||
ei_assert(size == rhs.innerSize());
|
||||
|
||||
// allocate a temporary buffer
|
||||
Scalar* buffer = new Scalar[rows];
|
||||
AmbiVector<Scalar> tempVector(rows);
|
||||
|
||||
// estimate the number of non zero entries
|
||||
float ratioLhs = float(lhs.nonZeros())/float(lhs.rows()*lhs.cols());
|
||||
@@ -164,89 +157,23 @@ struct ei_sparse_product_selector<Lhs,Rhs,ResultType,ColMajor,ColMajor,ColMajor>
|
||||
//float ratioColRes = std::min(ratioLhs * rhs.innerNonZeros(j), 1.f);
|
||||
// FIXME find a nice way to get the number of nonzeros of a sub matrix (here an inner vector)
|
||||
float ratioColRes = ratioRes;
|
||||
if (ratioColRes>0.1)
|
||||
tempVector.init(ratioColRes);
|
||||
tempVector.setZero();
|
||||
for (typename Rhs::InnerIterator rhsIt(rhs, j); rhsIt; ++rhsIt)
|
||||
{
|
||||
// dense path, the scalar * columns products are accumulated into a dense column
|
||||
Scalar* __restrict__ tmp = buffer;
|
||||
// set to zero
|
||||
for (int k=0; k<rows; ++k)
|
||||
tmp[k] = 0;
|
||||
for (typename Rhs::InnerIterator rhsIt(rhs, j); rhsIt; ++rhsIt)
|
||||
// FIXME should be written like this: tmp += rhsIt.value() * lhs.col(rhsIt.index())
|
||||
tempVector.restart();
|
||||
Scalar x = rhsIt.value();
|
||||
for (typename Lhs::InnerIterator lhsIt(lhs, rhsIt.index()); lhsIt; ++lhsIt)
|
||||
{
|
||||
// FIXME should be written like this: tmp += rhsIt.value() * lhs.col(rhsIt.index())
|
||||
Scalar x = rhsIt.value();
|
||||
for (typename Lhs::InnerIterator lhsIt(lhs, rhsIt.index()); lhsIt; ++lhsIt)
|
||||
{
|
||||
tmp[lhsIt.index()] += lhsIt.value() * x;
|
||||
}
|
||||
}
|
||||
// copy the temporary to the respective res.col()
|
||||
for (int k=0; k<rows; ++k)
|
||||
if (tmp[k]!=0)
|
||||
res.fill(k, j) = tmp[k];
|
||||
}
|
||||
else
|
||||
{
|
||||
ListEl* __restrict__ tmp = reinterpret_cast<ListEl*>(buffer);
|
||||
// sparse path, the scalar * columns products are accumulated into a linked list
|
||||
int tmp_size = 0;
|
||||
int tmp_start = -1;
|
||||
for (typename Rhs::InnerIterator rhsIt(rhs, j); rhsIt; ++rhsIt)
|
||||
{
|
||||
int tmp_el = tmp_start;
|
||||
for (typename Lhs::InnerIterator lhsIt(lhs, rhsIt.index()); lhsIt; ++lhsIt)
|
||||
{
|
||||
Scalar v = lhsIt.value() * rhsIt.value();
|
||||
int id = lhsIt.index();
|
||||
if (tmp_size==0)
|
||||
{
|
||||
tmp_start = 0;
|
||||
tmp_el = 0;
|
||||
tmp_size++;
|
||||
tmp[0].value = v;
|
||||
tmp[0].index = id;
|
||||
tmp[0].next = -1;
|
||||
}
|
||||
else if (id<tmp[tmp_start].index)
|
||||
{
|
||||
tmp[tmp_size].value = v;
|
||||
tmp[tmp_size].index = id;
|
||||
tmp[tmp_size].next = tmp_start;
|
||||
tmp_start = tmp_size;
|
||||
tmp_size++;
|
||||
}
|
||||
else
|
||||
{
|
||||
int nextel = tmp[tmp_el].next;
|
||||
while (nextel >= 0 && tmp[nextel].index<=id)
|
||||
{
|
||||
tmp_el = nextel;
|
||||
nextel = tmp[nextel].next;
|
||||
}
|
||||
|
||||
if (tmp[tmp_el].index==id)
|
||||
{
|
||||
tmp[tmp_el].value += v;
|
||||
}
|
||||
else
|
||||
{
|
||||
tmp[tmp_size].value = v;
|
||||
tmp[tmp_size].index = id;
|
||||
tmp[tmp_size].next = tmp[tmp_el].next;
|
||||
tmp[tmp_el].next = tmp_size;
|
||||
tmp_size++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
int k = tmp_start;
|
||||
while (k>=0)
|
||||
{
|
||||
if (tmp[k].value!=0)
|
||||
res.fill(tmp[k].index, j) = tmp[k].value;
|
||||
k = tmp[k].next;
|
||||
tempVector.coeffRef(lhsIt.index()) += lhsIt.value() * x;
|
||||
}
|
||||
}
|
||||
for (typename AmbiVector<Scalar>::Iterator it(tempVector); it; ++it)
|
||||
if (ResultType::Flags&RowMajorBit)
|
||||
res.fill(j,it.index()) = it.value();
|
||||
else
|
||||
res.fill(it.index(), j) = it.value();
|
||||
}
|
||||
res.endFill();
|
||||
}
|
||||
@@ -269,7 +196,7 @@ struct ei_sparse_product_selector<Lhs,Rhs,ResultType,RowMajor,RowMajor,RowMajor>
|
||||
{
|
||||
static void run(const Lhs& lhs, const Rhs& rhs, ResultType& res)
|
||||
{
|
||||
// let's transpose the product and fake the matrices are column major
|
||||
// let's transpose the product to get a column x column product
|
||||
ei_sparse_product_selector<Rhs,Lhs,ResultType,ColMajor,ColMajor,ColMajor>::run(rhs, lhs, res);
|
||||
}
|
||||
};
|
||||
@@ -280,8 +207,11 @@ struct ei_sparse_product_selector<Lhs,Rhs,ResultType,RowMajor,RowMajor,ColMajor>
|
||||
typedef SparseMatrix<typename ResultType::Scalar> SparseTemporaryType;
|
||||
static void run(const Lhs& lhs, const Rhs& rhs, ResultType& res)
|
||||
{
|
||||
// let's transpose the product and fake the matrices are column major
|
||||
ei_sparse_product_selector<Rhs,Lhs,ResultType,ColMajor,ColMajor,RowMajor>::run(rhs, lhs, res);
|
||||
// let's transpose the product to get a column x column product
|
||||
SparseTemporaryType _res(res.cols(), res.rows());
|
||||
ei_sparse_product_selector<Rhs,Lhs,ResultType,ColMajor,ColMajor,ColMajor>
|
||||
::run(rhs, lhs, _res);
|
||||
res = _res.transpose();
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -31,6 +31,35 @@
|
||||
#define EIGEN_DBG_SPARSE(X) X
|
||||
#endif
|
||||
|
||||
enum SparseBackend {
|
||||
DefaultBackend,
|
||||
Taucs,
|
||||
Cholmod,
|
||||
SuperLU,
|
||||
UmfPack
|
||||
};
|
||||
|
||||
// solver flags
|
||||
enum {
|
||||
CompleteFactorization = 0x0000, // the default
|
||||
IncompleteFactorization = 0x0001,
|
||||
MemoryEfficient = 0x0002,
|
||||
|
||||
// For LLT Cholesky:
|
||||
SupernodalMultifrontal = 0x0010,
|
||||
SupernodalLeftLooking = 0x0020,
|
||||
|
||||
// Ordering methods:
|
||||
NaturalOrdering = 0x0100, // the default
|
||||
MinimumDegree_AT_PLUS_A = 0x0200,
|
||||
MinimumDegree_ATA = 0x0300,
|
||||
ColApproxMinimumDegree = 0x0400,
|
||||
Metis = 0x0500,
|
||||
Scotch = 0x0600,
|
||||
Chaco = 0x0700,
|
||||
OrderingMask = 0x0f00
|
||||
};
|
||||
|
||||
template<typename Derived> class SparseMatrixBase;
|
||||
template<typename _Scalar, int _Flags = 0> class SparseMatrix;
|
||||
template<typename _Scalar, int _Flags = 0> class HashMatrix;
|
||||
|
||||
511
Eigen/src/Sparse/SuperLUSupport.h
Normal file
511
Eigen/src/Sparse/SuperLUSupport.h
Normal file
@@ -0,0 +1,511 @@
|
||||
// This file is part of Eigen, a lightweight C++ template library
|
||||
// for linear algebra. Eigen itself is part of the KDE project.
|
||||
//
|
||||
// Copyright (C) 2008 Gael Guennebaud <g.gael@free.fr>
|
||||
//
|
||||
// Eigen is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU Lesser General Public
|
||||
// License as published by the Free Software Foundation; either
|
||||
// version 3 of the License, or (at your option) any later version.
|
||||
//
|
||||
// Alternatively, you can redistribute it and/or
|
||||
// modify it under the terms of the GNU General Public License as
|
||||
// published by the Free Software Foundation; either version 2 of
|
||||
// the License, or (at your option) any later version.
|
||||
//
|
||||
// Eigen is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||
// FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License or the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public
|
||||
// License and a copy of the GNU General Public License along with
|
||||
// Eigen. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
#ifndef EIGEN_SUPERLUSUPPORT_H
|
||||
#define EIGEN_SUPERLUSUPPORT_H
|
||||
|
||||
// declaration of gssvx taken from GMM++
|
||||
#define DECL_GSSVX(NAMESPACE,FNAME,FLOATTYPE,KEYTYPE) \
|
||||
inline float SuperLU_gssvx(superlu_options_t *options, SuperMatrix *A, \
|
||||
int *perm_c, int *perm_r, int *etree, char *equed, \
|
||||
FLOATTYPE *R, FLOATTYPE *C, SuperMatrix *L, \
|
||||
SuperMatrix *U, void *work, int lwork, \
|
||||
SuperMatrix *B, SuperMatrix *X, \
|
||||
FLOATTYPE *recip_pivot_growth, \
|
||||
FLOATTYPE *rcond, FLOATTYPE *ferr, FLOATTYPE *berr, \
|
||||
SuperLUStat_t *stats, int *info, KEYTYPE) { \
|
||||
NAMESPACE::mem_usage_t mem_usage; \
|
||||
NAMESPACE::FNAME(options, A, perm_c, perm_r, etree, equed, R, C, L, \
|
||||
U, work, lwork, B, X, recip_pivot_growth, rcond, \
|
||||
ferr, berr, &mem_usage, stats, info); \
|
||||
return mem_usage.for_lu; /* bytes used by the factor storage */ \
|
||||
}
|
||||
|
||||
DECL_GSSVX(SuperLU_S,sgssvx,float,float)
|
||||
DECL_GSSVX(SuperLU_C,cgssvx,float,std::complex<float>)
|
||||
DECL_GSSVX(SuperLU_D,dgssvx,double,double)
|
||||
DECL_GSSVX(SuperLU_Z,zgssvx,double,std::complex<double>)
|
||||
|
||||
template<typename MatrixType>
|
||||
struct SluMatrixMapHelper;
|
||||
|
||||
/** \internal
|
||||
*
|
||||
* A wrapper class for SuperLU matrices. It supports only compressed sparse matrices
|
||||
* and dense matrices. Supernodal and other fancy format are not supported by this wrapper.
|
||||
*
|
||||
* This wrapper class mainly aims to avoids the need of dynamic allocation of the storage structure.
|
||||
*/
|
||||
struct SluMatrix : SuperMatrix
|
||||
{
|
||||
SluMatrix() {}
|
||||
|
||||
SluMatrix(const SluMatrix& other)
|
||||
: SuperMatrix(other)
|
||||
{
|
||||
Store = &storage;
|
||||
storage = other.storage;
|
||||
}
|
||||
|
||||
struct
|
||||
{
|
||||
union {int nnz;int lda;};
|
||||
void *values;
|
||||
int *innerInd;
|
||||
int *outerInd;
|
||||
} storage;
|
||||
|
||||
void setStorageType(Stype_t t)
|
||||
{
|
||||
Stype = t;
|
||||
if (t==SLU_NC || t==SLU_NR || t==SLU_DN)
|
||||
Store = &storage;
|
||||
else
|
||||
{
|
||||
ei_assert(false && "storage type not supported");
|
||||
Store = 0;
|
||||
}
|
||||
}
|
||||
|
||||
template<typename Scalar>
|
||||
void setScalarType()
|
||||
{
|
||||
if (ei_is_same_type<Scalar,float>::ret)
|
||||
Dtype = SLU_S;
|
||||
else if (ei_is_same_type<Scalar,double>::ret)
|
||||
Dtype = SLU_D;
|
||||
else if (ei_is_same_type<Scalar,std::complex<float> >::ret)
|
||||
Dtype = SLU_C;
|
||||
else if (ei_is_same_type<Scalar,std::complex<double> >::ret)
|
||||
Dtype = SLU_Z;
|
||||
else
|
||||
{
|
||||
ei_assert(false && "Scalar type not supported by SuperLU");
|
||||
}
|
||||
}
|
||||
|
||||
template<typename MatrixType>
|
||||
static SluMatrix Map(MatrixType& mat)
|
||||
{
|
||||
SluMatrix res;
|
||||
SluMatrixMapHelper<MatrixType>::run(mat, res);
|
||||
return res;
|
||||
}
|
||||
};
|
||||
|
||||
template<typename Scalar, int Rows, int Cols, int StorageOrder, int MRows, int MCols>
|
||||
struct SluMatrixMapHelper<Matrix<Scalar,Rows,Cols,StorageOrder,MRows,MCols> >
|
||||
{
|
||||
typedef Matrix<Scalar,Rows,Cols,StorageOrder,MRows,MCols> MatrixType;
|
||||
static void run(MatrixType& mat, SluMatrix& res)
|
||||
{
|
||||
assert(StorageOrder==0 && "row-major dense matrices is not supported by SuperLU");
|
||||
res.setStorageType(SLU_DN);
|
||||
res.setScalarType<Scalar>();
|
||||
res.Mtype = SLU_GE;
|
||||
|
||||
res.nrow = mat.rows();
|
||||
res.ncol = mat.cols();
|
||||
|
||||
res.storage.lda = mat.stride();
|
||||
res.storage.values = mat.data();
|
||||
}
|
||||
};
|
||||
|
||||
template<typename Scalar, int Flags>
|
||||
struct SluMatrixMapHelper<SparseMatrix<Scalar,Flags> >
|
||||
{
|
||||
typedef SparseMatrix<Scalar,Flags> MatrixType;
|
||||
static void run(MatrixType& mat, SluMatrix& res)
|
||||
{
|
||||
if (Flags&RowMajorBit)
|
||||
{
|
||||
res.setStorageType(SLU_NR);
|
||||
res.nrow = mat.cols();
|
||||
res.ncol = mat.rows();
|
||||
}
|
||||
else
|
||||
{
|
||||
res.setStorageType(SLU_NC);
|
||||
res.nrow = mat.rows();
|
||||
res.ncol = mat.cols();
|
||||
}
|
||||
|
||||
res.Mtype = SLU_GE;
|
||||
|
||||
res.storage.nnz = mat.nonZeros();
|
||||
res.storage.values = mat._valuePtr();
|
||||
res.storage.innerInd = mat._innerIndexPtr();
|
||||
res.storage.outerInd = mat._outerIndexPtr();
|
||||
|
||||
res.setScalarType<Scalar>();
|
||||
|
||||
// FIXME the following is not very accurate
|
||||
if (Flags & Upper)
|
||||
res.Mtype = SLU_TRU;
|
||||
if (Flags & Lower)
|
||||
res.Mtype = SLU_TRL;
|
||||
if (Flags & SelfAdjoint)
|
||||
ei_assert(false && "SelfAdjoint matrix shape not supported by SuperLU");
|
||||
}
|
||||
};
|
||||
|
||||
template<typename Scalar, int Flags>
|
||||
SluMatrix SparseMatrix<Scalar,Flags>::asSluMatrix()
|
||||
{
|
||||
return SluMatrix::Map(*this);
|
||||
}
|
||||
|
||||
template<typename Scalar, int Flags>
|
||||
SparseMatrix<Scalar,Flags> SparseMatrix<Scalar,Flags>::Map(SluMatrix& sluMat)
|
||||
{
|
||||
SparseMatrix res;
|
||||
if (Flags&RowMajorBit)
|
||||
{
|
||||
assert(sluMat.Stype == SLU_NR);
|
||||
res.m_innerSize = sluMat.ncol;
|
||||
res.m_outerSize = sluMat.nrow;
|
||||
}
|
||||
else
|
||||
{
|
||||
assert(sluMat.Stype == SLU_NC);
|
||||
res.m_innerSize = sluMat.nrow;
|
||||
res.m_outerSize = sluMat.ncol;
|
||||
}
|
||||
res.m_outerIndex = sluMat.storage.outerInd;
|
||||
SparseArray<Scalar> data = SparseArray<Scalar>::Map(
|
||||
sluMat.storage.innerInd,
|
||||
reinterpret_cast<Scalar*>(sluMat.storage.values),
|
||||
sluMat.storage.outerInd[res.m_outerSize]);
|
||||
res.m_data.swap(data);
|
||||
res.markAsRValue();
|
||||
return res;
|
||||
}
|
||||
|
||||
template<typename MatrixType>
|
||||
class SparseLU<MatrixType,SuperLU> : public SparseLU<MatrixType>
|
||||
{
|
||||
protected:
|
||||
typedef SparseLU<MatrixType> Base;
|
||||
typedef typename Base::Scalar Scalar;
|
||||
typedef typename Base::RealScalar RealScalar;
|
||||
typedef Matrix<Scalar,Dynamic,1> Vector;
|
||||
typedef Matrix<int, 1, MatrixType::ColsAtCompileTime> IntRowVectorType;
|
||||
typedef Matrix<int, MatrixType::RowsAtCompileTime, 1> IntColVectorType;
|
||||
typedef SparseMatrix<Scalar,Lower|UnitDiagBit> LMatrixType;
|
||||
typedef SparseMatrix<Scalar,Upper> UMatrixType;
|
||||
using Base::m_flags;
|
||||
using Base::m_status;
|
||||
|
||||
public:
|
||||
|
||||
SparseLU(int flags = NaturalOrdering)
|
||||
: Base(flags)
|
||||
{
|
||||
}
|
||||
|
||||
SparseLU(const MatrixType& matrix, int flags = NaturalOrdering)
|
||||
: Base(flags)
|
||||
{
|
||||
compute(matrix);
|
||||
}
|
||||
|
||||
~SparseLU()
|
||||
{
|
||||
}
|
||||
|
||||
inline const LMatrixType& matrixL() const
|
||||
{
|
||||
if (m_extractedDataAreDirty) extractData();
|
||||
return m_l;
|
||||
}
|
||||
|
||||
inline const UMatrixType& matrixU() const
|
||||
{
|
||||
if (m_extractedDataAreDirty) extractData();
|
||||
return m_u;
|
||||
}
|
||||
|
||||
inline const IntColVectorType& permutationP() const
|
||||
{
|
||||
if (m_extractedDataAreDirty) extractData();
|
||||
return m_p;
|
||||
}
|
||||
|
||||
inline const IntRowVectorType& permutationQ() const
|
||||
{
|
||||
if (m_extractedDataAreDirty) extractData();
|
||||
return m_q;
|
||||
}
|
||||
|
||||
Scalar determinant() const;
|
||||
|
||||
template<typename BDerived, typename XDerived>
|
||||
bool solve(const MatrixBase<BDerived> &b, MatrixBase<XDerived>* x) const;
|
||||
|
||||
void compute(const MatrixType& matrix);
|
||||
|
||||
protected:
|
||||
|
||||
void extractData() const;
|
||||
|
||||
protected:
|
||||
// cached data to reduce reallocation, etc.
|
||||
mutable LMatrixType m_l;
|
||||
mutable UMatrixType m_u;
|
||||
mutable IntColVectorType m_p;
|
||||
mutable IntRowVectorType m_q;
|
||||
|
||||
mutable SparseMatrix<Scalar> m_matrix;
|
||||
mutable SluMatrix m_sluA;
|
||||
mutable SuperMatrix m_sluL, m_sluU;
|
||||
mutable SluMatrix m_sluB, m_sluX;
|
||||
mutable SuperLUStat_t m_sluStat;
|
||||
mutable superlu_options_t m_sluOptions;
|
||||
mutable std::vector<int> m_sluEtree;
|
||||
mutable std::vector<RealScalar> m_sluRscale, m_sluCscale;
|
||||
mutable std::vector<RealScalar> m_sluFerr, m_sluBerr;
|
||||
mutable char m_sluEqued;
|
||||
mutable bool m_extractedDataAreDirty;
|
||||
};
|
||||
|
||||
template<typename MatrixType>
|
||||
void SparseLU<MatrixType,SuperLU>::compute(const MatrixType& a)
|
||||
{
|
||||
const int size = a.rows();
|
||||
m_matrix = a;
|
||||
|
||||
set_default_options(&m_sluOptions);
|
||||
m_sluOptions.ColPerm = NATURAL;
|
||||
m_sluOptions.PrintStat = NO;
|
||||
m_sluOptions.ConditionNumber = NO;
|
||||
m_sluOptions.Trans = NOTRANS;
|
||||
// m_sluOptions.Equil = NO;
|
||||
|
||||
switch (Base::orderingMethod())
|
||||
{
|
||||
case NaturalOrdering : m_sluOptions.ColPerm = NATURAL; break;
|
||||
case MinimumDegree_AT_PLUS_A : m_sluOptions.ColPerm = MMD_AT_PLUS_A; break;
|
||||
case MinimumDegree_ATA : m_sluOptions.ColPerm = MMD_ATA; break;
|
||||
case ColApproxMinimumDegree : m_sluOptions.ColPerm = COLAMD; break;
|
||||
default:
|
||||
std::cerr << "Eigen: ordering method \"" << Base::orderingMethod() << "\" not supported by the SuperLU backend\n";
|
||||
m_sluOptions.ColPerm = NATURAL;
|
||||
};
|
||||
|
||||
m_sluA = m_matrix.asSluMatrix();
|
||||
memset(&m_sluL,0,sizeof m_sluL);
|
||||
memset(&m_sluU,0,sizeof m_sluU);
|
||||
m_sluEqued = 'B';
|
||||
int info = 0;
|
||||
|
||||
m_p.resize(size);
|
||||
m_q.resize(size);
|
||||
m_sluRscale.resize(size);
|
||||
m_sluCscale.resize(size);
|
||||
m_sluEtree.resize(size);
|
||||
|
||||
RealScalar recip_pivot_gross, rcond;
|
||||
RealScalar ferr, berr;
|
||||
|
||||
// set empty B and X
|
||||
m_sluB.setStorageType(SLU_DN);
|
||||
m_sluB.setScalarType<Scalar>();
|
||||
m_sluB.Mtype = SLU_GE;
|
||||
m_sluB.storage.values = 0;
|
||||
m_sluB.nrow = m_sluB.ncol = 0;
|
||||
m_sluB.storage.lda = size;
|
||||
m_sluX = m_sluB;
|
||||
|
||||
StatInit(&m_sluStat);
|
||||
SuperLU_gssvx(&m_sluOptions, &m_sluA, m_q.data(), m_p.data(), &m_sluEtree[0],
|
||||
&m_sluEqued, &m_sluRscale[0], &m_sluCscale[0],
|
||||
&m_sluL, &m_sluU,
|
||||
NULL, 0,
|
||||
&m_sluB, &m_sluX,
|
||||
&recip_pivot_gross, &rcond,
|
||||
&ferr, &berr,
|
||||
&m_sluStat, &info, Scalar());
|
||||
StatFree(&m_sluStat);
|
||||
|
||||
m_extractedDataAreDirty = true;
|
||||
|
||||
// FIXME how to better check for errors ???
|
||||
Base::m_succeeded = (info == 0);
|
||||
}
|
||||
|
||||
template<typename MatrixType>
|
||||
template<typename BDerived,typename XDerived>
|
||||
bool SparseLU<MatrixType,SuperLU>::solve(const MatrixBase<BDerived> &b, MatrixBase<XDerived> *x) const
|
||||
{
|
||||
const int size = m_matrix.rows();
|
||||
const int rhsCols = b.cols();
|
||||
ei_assert(size==b.rows());
|
||||
|
||||
m_sluOptions.Fact = FACTORED;
|
||||
m_sluOptions.IterRefine = NOREFINE;
|
||||
|
||||
m_sluFerr.resize(rhsCols);
|
||||
m_sluBerr.resize(rhsCols);
|
||||
m_sluB = SluMatrix::Map(b.const_cast_derived());
|
||||
m_sluX = SluMatrix::Map(x->derived());
|
||||
|
||||
StatInit(&m_sluStat);
|
||||
int info = 0;
|
||||
RealScalar recip_pivot_gross, rcond;
|
||||
SuperLU_gssvx(
|
||||
&m_sluOptions, &m_sluA,
|
||||
m_q.data(), m_p.data(),
|
||||
&m_sluEtree[0], &m_sluEqued,
|
||||
&m_sluRscale[0], &m_sluCscale[0],
|
||||
&m_sluL, &m_sluU,
|
||||
NULL, 0,
|
||||
&m_sluB, &m_sluX,
|
||||
&recip_pivot_gross, &rcond,
|
||||
&m_sluFerr[0], &m_sluBerr[0],
|
||||
&m_sluStat, &info, Scalar());
|
||||
StatFree(&m_sluStat);
|
||||
|
||||
return info==0;
|
||||
}
|
||||
|
||||
//
|
||||
// the code of this extractData() function has been adapted from the SuperLU's Matlab support code,
|
||||
//
|
||||
// Copyright (c) 1994 by Xerox Corporation. All rights reserved.
|
||||
//
|
||||
// THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY
|
||||
// EXPRESSED OR IMPLIED. ANY USE IS AT YOUR OWN RISK.
|
||||
//
|
||||
template<typename MatrixType>
|
||||
void SparseLU<MatrixType,SuperLU>::extractData() const
|
||||
{
|
||||
if (m_extractedDataAreDirty)
|
||||
{
|
||||
int upper;
|
||||
int fsupc, istart, nsupr;
|
||||
int lastl = 0, lastu = 0;
|
||||
SCformat *Lstore = static_cast<SCformat*>(m_sluL.Store);
|
||||
NCformat *Ustore = static_cast<NCformat*>(m_sluU.Store);
|
||||
Scalar *SNptr;
|
||||
|
||||
const int size = m_matrix.rows();
|
||||
m_l.resize(size,size);
|
||||
m_l.resizeNonZeros(Lstore->nnz);
|
||||
m_u.resize(size,size);
|
||||
m_u.resizeNonZeros(Ustore->nnz);
|
||||
|
||||
int* Lcol = m_l._outerIndexPtr();
|
||||
int* Lrow = m_l._innerIndexPtr();
|
||||
Scalar* Lval = m_l._valuePtr();
|
||||
|
||||
int* Ucol = m_u._outerIndexPtr();
|
||||
int* Urow = m_u._innerIndexPtr();
|
||||
Scalar* Uval = m_u._valuePtr();
|
||||
|
||||
Ucol[0] = 0;
|
||||
Ucol[0] = 0;
|
||||
|
||||
/* for each supernode */
|
||||
for (int k = 0; k <= Lstore->nsuper; ++k)
|
||||
{
|
||||
fsupc = L_FST_SUPC(k);
|
||||
istart = L_SUB_START(fsupc);
|
||||
nsupr = L_SUB_START(fsupc+1) - istart;
|
||||
upper = 1;
|
||||
|
||||
/* for each column in the supernode */
|
||||
for (int j = fsupc; j < L_FST_SUPC(k+1); ++j)
|
||||
{
|
||||
SNptr = &((Scalar*)Lstore->nzval)[L_NZ_START(j)];
|
||||
|
||||
/* Extract U */
|
||||
for (int i = U_NZ_START(j); i < U_NZ_START(j+1); ++i)
|
||||
{
|
||||
Uval[lastu] = ((Scalar*)Ustore->nzval)[i];
|
||||
/* Matlab doesn't like explicit zero. */
|
||||
if (Uval[lastu] != 0.0)
|
||||
Urow[lastu++] = U_SUB(i);
|
||||
}
|
||||
for (int i = 0; i < upper; ++i)
|
||||
{
|
||||
/* upper triangle in the supernode */
|
||||
Uval[lastu] = SNptr[i];
|
||||
/* Matlab doesn't like explicit zero. */
|
||||
if (Uval[lastu] != 0.0)
|
||||
Urow[lastu++] = L_SUB(istart+i);
|
||||
}
|
||||
Ucol[j+1] = lastu;
|
||||
|
||||
/* Extract L */
|
||||
Lval[lastl] = 1.0; /* unit diagonal */
|
||||
Lrow[lastl++] = L_SUB(istart + upper - 1);
|
||||
for (int i = upper; i < nsupr; ++i)
|
||||
{
|
||||
Lval[lastl] = SNptr[i];
|
||||
/* Matlab doesn't like explicit zero. */
|
||||
if (Lval[lastl] != 0.0)
|
||||
Lrow[lastl++] = L_SUB(istart+i);
|
||||
}
|
||||
Lcol[j+1] = lastl;
|
||||
|
||||
++upper;
|
||||
} /* for j ... */
|
||||
|
||||
} /* for k ... */
|
||||
|
||||
// squeeze the matrices :
|
||||
m_l.resizeNonZeros(lastl);
|
||||
m_u.resizeNonZeros(lastu);
|
||||
|
||||
m_extractedDataAreDirty = false;
|
||||
}
|
||||
}
|
||||
|
||||
template<typename MatrixType>
|
||||
typename SparseLU<MatrixType,SuperLU>::Scalar SparseLU<MatrixType,SuperLU>::determinant() const
|
||||
{
|
||||
if (m_extractedDataAreDirty)
|
||||
extractData();
|
||||
|
||||
// TODO this code coule be moved to the default/base backend
|
||||
// FIXME perhaps we have to take into account the scale factors m_sluRscale and m_sluCscale ???
|
||||
Scalar det = Scalar(1);
|
||||
for (int j=0; j<m_u.cols(); ++j)
|
||||
{
|
||||
if (m_u._outerIndexPtr()[j+1]-m_u._outerIndexPtr()[j] > 0)
|
||||
{
|
||||
int lastId = m_u._outerIndexPtr()[j+1]-1;
|
||||
ei_assert(m_u._innerIndexPtr()[lastId]<=j);
|
||||
if (m_u._innerIndexPtr()[lastId]==j)
|
||||
{
|
||||
det *= m_u._valuePtr()[lastId];
|
||||
}
|
||||
}
|
||||
// std::cout << m_sluRscale[j] << " " << m_sluCscale[j] << " ";
|
||||
}
|
||||
return det;
|
||||
}
|
||||
|
||||
#endif // EIGEN_SUPERLUSUPPORT_H
|
||||
198
Eigen/src/Sparse/TaucsSupport.h
Normal file
198
Eigen/src/Sparse/TaucsSupport.h
Normal file
@@ -0,0 +1,198 @@
|
||||
// This file is part of Eigen, a lightweight C++ template library
|
||||
// for linear algebra. Eigen itself is part of the KDE project.
|
||||
//
|
||||
// Copyright (C) 2008 Gael Guennebaud <g.gael@free.fr>
|
||||
//
|
||||
// Eigen is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU Lesser General Public
|
||||
// License as published by the Free Software Foundation; either
|
||||
// version 3 of the License, or (at your option) any later version.
|
||||
//
|
||||
// Alternatively, you can redistribute it and/or
|
||||
// modify it under the terms of the GNU General Public License as
|
||||
// published by the Free Software Foundation; either version 2 of
|
||||
// the License, or (at your option) any later version.
|
||||
//
|
||||
// Eigen is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||
// FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License or the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public
|
||||
// License and a copy of the GNU General Public License along with
|
||||
// Eigen. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
#ifndef EIGEN_TAUCSSUPPORT_H
|
||||
#define EIGEN_TAUCSSUPPORT_H
|
||||
|
||||
template<typename Scalar, int Flags>
|
||||
taucs_ccs_matrix SparseMatrix<Scalar,Flags>::asTaucsMatrix()
|
||||
{
|
||||
taucs_ccs_matrix res;
|
||||
res.n = cols();
|
||||
res.m = rows();
|
||||
res.flags = 0;
|
||||
res.colptr = _outerIndexPtr();
|
||||
res.rowind = _innerIndexPtr();
|
||||
res.values.v = _valuePtr();
|
||||
if (ei_is_same_type<Scalar,int>::ret)
|
||||
res.flags |= TAUCS_INT;
|
||||
else if (ei_is_same_type<Scalar,float>::ret)
|
||||
res.flags |= TAUCS_SINGLE;
|
||||
else if (ei_is_same_type<Scalar,double>::ret)
|
||||
res.flags |= TAUCS_DOUBLE;
|
||||
else if (ei_is_same_type<Scalar,std::complex<float> >::ret)
|
||||
res.flags |= TAUCS_SCOMPLEX;
|
||||
else if (ei_is_same_type<Scalar,std::complex<double> >::ret)
|
||||
res.flags |= TAUCS_DCOMPLEX;
|
||||
else
|
||||
{
|
||||
ei_assert(false && "Scalar type not supported by TAUCS");
|
||||
}
|
||||
|
||||
if (Flags & Upper)
|
||||
res.flags |= TAUCS_UPPER;
|
||||
if (Flags & Lower)
|
||||
res.flags |= TAUCS_LOWER;
|
||||
if (Flags & SelfAdjoint)
|
||||
res.flags |= (NumTraits<Scalar>::IsComplex ? TAUCS_HERMITIAN : TAUCS_SYMMETRIC);
|
||||
else if ((Flags & Upper) || (Flags & Lower))
|
||||
res.flags |= TAUCS_TRIANGULAR;
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
template<typename Scalar, int Flags>
|
||||
SparseMatrix<Scalar,Flags> SparseMatrix<Scalar,Flags>::Map(taucs_ccs_matrix& taucsMat)
|
||||
{
|
||||
SparseMatrix res;
|
||||
res.m_innerSize = taucsMat.m;
|
||||
res.m_outerSize = taucsMat.n;
|
||||
res.m_outerIndex = taucsMat.colptr;
|
||||
SparseArray<Scalar> data = SparseArray<Scalar>::Map(
|
||||
taucsMat.rowind,
|
||||
reinterpret_cast<Scalar*>(taucsMat.values.v),
|
||||
taucsMat.colptr[taucsMat.n]);
|
||||
res.m_data.swap(data);
|
||||
res.markAsRValue();
|
||||
return res;
|
||||
}
|
||||
|
||||
template<typename MatrixType>
|
||||
class SparseLLT<MatrixType,Taucs> : public SparseLLT<MatrixType>
|
||||
{
|
||||
protected:
|
||||
typedef SparseLLT<MatrixType> Base;
|
||||
using Base::Scalar;
|
||||
using Base::RealScalar;
|
||||
using Base::MatrixLIsDirty;
|
||||
using Base::SupernodalFactorIsDirty;
|
||||
using Base::m_flags;
|
||||
using Base::m_matrix;
|
||||
using Base::m_status;
|
||||
|
||||
public:
|
||||
|
||||
SparseLLT(int flags = 0)
|
||||
: Base(flags), m_taucsSupernodalFactor(0)
|
||||
{
|
||||
}
|
||||
|
||||
SparseLLT(const MatrixType& matrix, int flags = 0)
|
||||
: Base(flags), m_taucsSupernodalFactor(0)
|
||||
{
|
||||
compute(matrix);
|
||||
}
|
||||
|
||||
~SparseLLT()
|
||||
{
|
||||
if (m_taucsSupernodalFactor)
|
||||
taucs_supernodal_factor_free(m_taucsSupernodalFactor);
|
||||
}
|
||||
|
||||
inline const typename Base::CholMatrixType& matrixL(void) const;
|
||||
|
||||
template<typename Derived>
|
||||
void solveInPlace(MatrixBase<Derived> &b) const;
|
||||
|
||||
void compute(const MatrixType& matrix);
|
||||
|
||||
protected:
|
||||
void* m_taucsSupernodalFactor;
|
||||
};
|
||||
|
||||
template<typename MatrixType>
|
||||
void SparseLLT<MatrixType,Taucs>::compute(const MatrixType& a)
|
||||
{
|
||||
if (m_taucsSupernodalFactor)
|
||||
{
|
||||
taucs_supernodal_factor_free(m_taucsSupernodalFactor);
|
||||
m_taucsSupernodalFactor = 0;
|
||||
}
|
||||
|
||||
if (m_flags & IncompleteFactorization)
|
||||
{
|
||||
taucs_ccs_matrix taucsMatA = const_cast<MatrixType&>(a).asTaucsMatrix();
|
||||
taucs_ccs_matrix* taucsRes = taucs_ccs_factor_llt(&taucsMatA, Base::m_precision, 0);
|
||||
m_matrix = Base::CholMatrixType::Map(*taucsRes);
|
||||
free(taucsRes);
|
||||
m_status = (m_status & ~(CompleteFactorization|MatrixLIsDirty))
|
||||
| IncompleteFactorization
|
||||
| SupernodalFactorIsDirty;
|
||||
}
|
||||
else
|
||||
{
|
||||
taucs_ccs_matrix taucsMatA = const_cast<MatrixType&>(a).asTaucsMatrix();
|
||||
if ( (m_flags & SupernodalLeftLooking)
|
||||
|| ((!(m_flags & SupernodalMultifrontal)) && (m_flags & MemoryEfficient)) )
|
||||
{
|
||||
m_taucsSupernodalFactor = taucs_ccs_factor_llt_ll(&taucsMatA);
|
||||
}
|
||||
else
|
||||
{
|
||||
// use the faster Multifrontal routine
|
||||
m_taucsSupernodalFactor = taucs_ccs_factor_llt_mf(&taucsMatA);
|
||||
}
|
||||
m_status = (m_status & ~IncompleteFactorization) | CompleteFactorization | MatrixLIsDirty;
|
||||
}
|
||||
}
|
||||
|
||||
template<typename MatrixType>
|
||||
inline const typename SparseLLT<MatrixType>::CholMatrixType&
|
||||
SparseLLT<MatrixType,Taucs>::matrixL() const
|
||||
{
|
||||
if (m_status & MatrixLIsDirty)
|
||||
{
|
||||
ei_assert(!(m_status & SupernodalFactorIsDirty));
|
||||
|
||||
taucs_ccs_matrix* taucsL = taucs_supernodal_factor_to_ccs(m_taucsSupernodalFactor);
|
||||
const_cast<typename Base::CholMatrixType&>(m_matrix) = Base::CholMatrixType::Map(*taucsL);
|
||||
free(taucsL);
|
||||
m_status = (m_status & ~MatrixLIsDirty);
|
||||
}
|
||||
return m_matrix;
|
||||
}
|
||||
|
||||
template<typename MatrixType>
|
||||
template<typename Derived>
|
||||
void SparseLLT<MatrixType,Taucs>::solveInPlace(MatrixBase<Derived> &b) const
|
||||
{
|
||||
if (m_status & MatrixLIsDirty)
|
||||
{
|
||||
// TODO use taucs's supernodal solver, in particular check types, storage order, etc.
|
||||
// VectorXb x(b.rows());
|
||||
// for (int j=0; j<b.cols(); ++j)
|
||||
// {
|
||||
// taucs_supernodal_solve_llt(m_taucsSupernodalFactor,x.data(),&b.col(j).coeffRef(0));
|
||||
// b.col(j) = x;
|
||||
// }
|
||||
matrixL();
|
||||
}
|
||||
|
||||
|
||||
{
|
||||
Base::solveInPlace(b);
|
||||
}
|
||||
}
|
||||
|
||||
#endif // EIGEN_TAUCSSUPPORT_H
|
||||
@@ -25,16 +25,6 @@
|
||||
#ifndef EIGEN_SPARSETRIANGULARSOLVER_H
|
||||
#define EIGEN_SPARSETRIANGULARSOLVER_H
|
||||
|
||||
// template<typename Lhs, typename Rhs,
|
||||
// int TriangularPart = (int(Lhs::Flags) & LowerTriangularBit)
|
||||
// ? Lower
|
||||
// : (int(Lhs::Flags) & UpperTriangularBit)
|
||||
// ? Upper
|
||||
// : -1,
|
||||
// int StorageOrder = int(Lhs::Flags) & RowMajorBit ? RowMajor : ColMajor
|
||||
// >
|
||||
// struct ei_sparse_trisolve_selector;
|
||||
|
||||
// forward substitution, row-major
|
||||
template<typename Lhs, typename Rhs>
|
||||
struct ei_solve_triangular_selector<Lhs,Rhs,Lower,RowMajor|IsSparse>
|
||||
@@ -80,7 +70,9 @@ struct ei_solve_triangular_selector<Lhs,Rhs,Upper,RowMajor|IsSparse>
|
||||
{
|
||||
Scalar tmp = other.coeff(i,col);
|
||||
typename Lhs::InnerIterator it(lhs, i);
|
||||
for(++it; it; ++it)
|
||||
if (it.index() == i)
|
||||
++it;
|
||||
for(; it; ++it)
|
||||
{
|
||||
tmp -= it.value() * other.coeff(it.index(),col);
|
||||
}
|
||||
@@ -112,12 +104,14 @@ struct ei_solve_triangular_selector<Lhs,Rhs,Lower,ColMajor|IsSparse>
|
||||
typename Lhs::InnerIterator it(lhs, i);
|
||||
if(!(Lhs::Flags & UnitDiagBit))
|
||||
{
|
||||
std::cerr << it.value() << " ; " << it.index() << " == " << i << "\n";
|
||||
// std::cerr << it.value() << " ; " << it.index() << " == " << i << "\n";
|
||||
ei_assert(it.index()==i);
|
||||
other.coeffRef(i,col) /= it.value();
|
||||
}
|
||||
Scalar tmp = other.coeffRef(i,col);
|
||||
for(++it; it; ++it)
|
||||
if (it.index()==i)
|
||||
++it;
|
||||
for(; it; ++it)
|
||||
other.coeffRef(it.index(), col) -= tmp * it.value();
|
||||
}
|
||||
}
|
||||
|
||||
289
Eigen/src/Sparse/UmfPackSupport.h
Normal file
289
Eigen/src/Sparse/UmfPackSupport.h
Normal file
@@ -0,0 +1,289 @@
|
||||
// This file is part of Eigen, a lightweight C++ template library
|
||||
// for linear algebra. Eigen itself is part of the KDE project.
|
||||
//
|
||||
// Copyright (C) 2008 Gael Guennebaud <g.gael@free.fr>
|
||||
//
|
||||
// Eigen is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU Lesser General Public
|
||||
// License as published by the Free Software Foundation; either
|
||||
// version 3 of the License, or (at your option) any later version.
|
||||
//
|
||||
// Alternatively, you can redistribute it and/or
|
||||
// modify it under the terms of the GNU General Public License as
|
||||
// published by the Free Software Foundation; either version 2 of
|
||||
// the License, or (at your option) any later version.
|
||||
//
|
||||
// Eigen is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||
// FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License or the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public
|
||||
// License and a copy of the GNU General Public License along with
|
||||
// Eigen. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
#ifndef EIGEN_UMFPACKSUPPORT_H
|
||||
#define EIGEN_UMFPACKSUPPORT_H
|
||||
|
||||
/* TODO extract L, extract U, compute det, etc... */
|
||||
|
||||
// generic double/complex<double> wrapper functions:
|
||||
|
||||
inline void umfpack_free_numeric(void **Numeric, double)
|
||||
{ umfpack_di_free_numeric(Numeric); }
|
||||
|
||||
inline void umfpack_free_numeric(void **Numeric, std::complex<double>)
|
||||
{ umfpack_zi_free_numeric(Numeric); }
|
||||
|
||||
inline void umfpack_free_symbolic(void **Symbolic, double)
|
||||
{ umfpack_di_free_symbolic(Symbolic); }
|
||||
|
||||
inline void umfpack_free_symbolic(void **Symbolic, std::complex<double>)
|
||||
{ umfpack_zi_free_symbolic(Symbolic); }
|
||||
|
||||
inline int umfpack_symbolic(int n_row,int n_col,
|
||||
const int Ap[], const int Ai[], const double Ax[], void **Symbolic,
|
||||
const double Control [UMFPACK_CONTROL], double Info [UMFPACK_INFO])
|
||||
{
|
||||
return umfpack_di_symbolic(n_row,n_col,Ap,Ai,Ax,Symbolic,Control,Info);
|
||||
}
|
||||
|
||||
inline int umfpack_symbolic(int n_row,int n_col,
|
||||
const int Ap[], const int Ai[], const std::complex<double> Ax[], void **Symbolic,
|
||||
const double Control [UMFPACK_CONTROL], double Info [UMFPACK_INFO])
|
||||
{
|
||||
return umfpack_zi_symbolic(n_row,n_col,Ap,Ai,&Ax[0].real(),0,Symbolic,Control,Info);
|
||||
}
|
||||
|
||||
inline int umfpack_numeric( const int Ap[], const int Ai[], const double Ax[],
|
||||
void *Symbolic, void **Numeric,
|
||||
const double Control[UMFPACK_CONTROL],double Info [UMFPACK_INFO])
|
||||
{
|
||||
return umfpack_di_numeric(Ap,Ai,Ax,Symbolic,Numeric,Control,Info);
|
||||
}
|
||||
|
||||
inline int umfpack_numeric( const int Ap[], const int Ai[], const std::complex<double> Ax[],
|
||||
void *Symbolic, void **Numeric,
|
||||
const double Control[UMFPACK_CONTROL],double Info [UMFPACK_INFO])
|
||||
{
|
||||
return umfpack_zi_numeric(Ap,Ai,&Ax[0].real(),0,Symbolic,Numeric,Control,Info);
|
||||
}
|
||||
|
||||
inline int umfpack_solve( int sys, const int Ap[], const int Ai[], const double Ax[],
|
||||
double X[], const double B[], void *Numeric,
|
||||
const double Control[UMFPACK_CONTROL], double Info[UMFPACK_INFO])
|
||||
{
|
||||
return umfpack_di_solve(sys,Ap,Ai,Ax,X,B,Numeric,Control,Info);
|
||||
}
|
||||
|
||||
inline int umfpack_solve( int sys, const int Ap[], const int Ai[], const std::complex<double> Ax[],
|
||||
std::complex<double> X[], const std::complex<double> B[], void *Numeric,
|
||||
const double Control[UMFPACK_CONTROL], double Info[UMFPACK_INFO])
|
||||
{
|
||||
return umfpack_zi_solve(sys,Ap,Ai,&Ax[0].real(),0,&X[0].real(),0,&B[0].real(),0,Numeric,Control,Info);
|
||||
}
|
||||
|
||||
inline int umfpack_get_lunz(int *lnz, int *unz, int *n_row, int *n_col, int *nz_udiag, void *Numeric, double)
|
||||
{
|
||||
return umfpack_di_get_lunz(lnz,unz,n_row,n_col,nz_udiag,Numeric);
|
||||
}
|
||||
|
||||
inline int umfpack_get_lunz(int *lnz, int *unz, int *n_row, int *n_col, int *nz_udiag, void *Numeric, std::complex<double>)
|
||||
{
|
||||
return umfpack_zi_get_lunz(lnz,unz,n_row,n_col,nz_udiag,Numeric);
|
||||
}
|
||||
|
||||
inline int umfpack_get_numeric(int Lp[], int Lj[], double Lx[], int Up[], int Ui[], double Ux[],
|
||||
int P[], int Q[], double Dx[], int *do_recip, double Rs[], void *Numeric)
|
||||
{
|
||||
return umfpack_di_get_numeric(Lp,Lj,Lx,Up,Ui,Ux,P,Q,Dx,do_recip,Rs,Numeric);
|
||||
}
|
||||
|
||||
inline int umfpack_get_numeric(int Lp[], int Lj[], std::complex<double> Lx[], int Up[], int Ui[], std::complex<double> Ux[],
|
||||
int P[], int Q[], std::complex<double> Dx[], int *do_recip, double Rs[], void *Numeric)
|
||||
{
|
||||
return umfpack_zi_get_numeric(Lp,Lj,Lx?&Lx[0].real():0,0,Up,Ui,Ux?&Ux[0].real():0,0,P,Q,
|
||||
Dx?&Dx[0].real():0,0,do_recip,Rs,Numeric);
|
||||
}
|
||||
|
||||
inline int umfpack_get_determinant(double *Mx, double *Ex, void *NumericHandle, double User_Info [UMFPACK_INFO])
|
||||
{
|
||||
return umfpack_di_get_determinant(Mx,Ex,NumericHandle,User_Info);
|
||||
}
|
||||
|
||||
inline int umfpack_get_determinant(std::complex<double> *Mx, double *Ex, void *NumericHandle, double User_Info [UMFPACK_INFO])
|
||||
{
|
||||
return umfpack_zi_get_determinant(&Mx->real(),0,Ex,NumericHandle,User_Info);
|
||||
}
|
||||
|
||||
|
||||
template<typename MatrixType>
|
||||
class SparseLU<MatrixType,UmfPack> : public SparseLU<MatrixType>
|
||||
{
|
||||
protected:
|
||||
typedef SparseLU<MatrixType> Base;
|
||||
typedef typename Base::Scalar Scalar;
|
||||
typedef typename Base::RealScalar RealScalar;
|
||||
typedef Matrix<Scalar,Dynamic,1> Vector;
|
||||
typedef Matrix<int, 1, MatrixType::ColsAtCompileTime> IntRowVectorType;
|
||||
typedef Matrix<int, MatrixType::RowsAtCompileTime, 1> IntColVectorType;
|
||||
typedef SparseMatrix<Scalar,Lower|UnitDiagBit> LMatrixType;
|
||||
typedef SparseMatrix<Scalar,Upper> UMatrixType;
|
||||
using Base::m_flags;
|
||||
using Base::m_status;
|
||||
|
||||
public:
|
||||
|
||||
SparseLU(int flags = NaturalOrdering)
|
||||
: Base(flags), m_numeric(0)
|
||||
{
|
||||
}
|
||||
|
||||
SparseLU(const MatrixType& matrix, int flags = NaturalOrdering)
|
||||
: Base(flags), m_numeric(0)
|
||||
{
|
||||
compute(matrix);
|
||||
}
|
||||
|
||||
~SparseLU()
|
||||
{
|
||||
if (m_numeric)
|
||||
umfpack_free_numeric(&m_numeric,Scalar());
|
||||
}
|
||||
|
||||
inline const LMatrixType& matrixL() const
|
||||
{
|
||||
if (m_extractedDataAreDirty) extractData();
|
||||
return m_l;
|
||||
}
|
||||
|
||||
inline const UMatrixType& matrixU() const
|
||||
{
|
||||
if (m_extractedDataAreDirty) extractData();
|
||||
return m_u;
|
||||
}
|
||||
|
||||
inline const IntColVectorType& permutationP() const
|
||||
{
|
||||
if (m_extractedDataAreDirty) extractData();
|
||||
return m_p;
|
||||
}
|
||||
|
||||
inline const IntRowVectorType& permutationQ() const
|
||||
{
|
||||
if (m_extractedDataAreDirty) extractData();
|
||||
return m_q;
|
||||
}
|
||||
|
||||
Scalar determinant() const;
|
||||
|
||||
template<typename BDerived, typename XDerived>
|
||||
bool solve(const MatrixBase<BDerived> &b, MatrixBase<XDerived>* x) const;
|
||||
|
||||
void compute(const MatrixType& matrix);
|
||||
|
||||
protected:
|
||||
|
||||
void extractData() const;
|
||||
|
||||
protected:
|
||||
// cached data:
|
||||
void* m_numeric;
|
||||
const MatrixType* m_matrixRef;
|
||||
mutable LMatrixType m_l;
|
||||
mutable UMatrixType m_u;
|
||||
mutable IntColVectorType m_p;
|
||||
mutable IntRowVectorType m_q;
|
||||
mutable bool m_extractedDataAreDirty;
|
||||
};
|
||||
|
||||
template<typename MatrixType>
|
||||
void SparseLU<MatrixType,UmfPack>::compute(const MatrixType& a)
|
||||
{
|
||||
const int rows = a.rows();
|
||||
const int cols = a.cols();
|
||||
ei_assert((MatrixType::Flags&RowMajorBit)==0 && "Row major matrices are not supported yet");
|
||||
|
||||
m_matrixRef = &a;
|
||||
|
||||
if (m_numeric)
|
||||
umfpack_free_numeric(&m_numeric,Scalar());
|
||||
|
||||
void* symbolic;
|
||||
int errorCode = 0;
|
||||
errorCode = umfpack_symbolic(rows, cols, a._outerIndexPtr(), a._innerIndexPtr(), a._valuePtr(),
|
||||
&symbolic, 0, 0);
|
||||
if (errorCode==0)
|
||||
errorCode = umfpack_numeric(a._outerIndexPtr(), a._innerIndexPtr(), a._valuePtr(),
|
||||
symbolic, &m_numeric, 0, 0);
|
||||
|
||||
umfpack_free_symbolic(&symbolic,Scalar());
|
||||
|
||||
m_extractedDataAreDirty = true;
|
||||
|
||||
Base::m_succeeded = (errorCode==0);
|
||||
}
|
||||
|
||||
template<typename MatrixType>
|
||||
void SparseLU<MatrixType,UmfPack>::extractData() const
|
||||
{
|
||||
if (m_extractedDataAreDirty)
|
||||
{
|
||||
// get size of the data
|
||||
int lnz, unz, rows, cols, nz_udiag;
|
||||
umfpack_get_lunz(&lnz, &unz, &rows, &cols, &nz_udiag, m_numeric, Scalar());
|
||||
|
||||
// allocate data
|
||||
m_l.resize(rows,std::min(rows,cols));
|
||||
m_l.resizeNonZeros(lnz);
|
||||
|
||||
m_u.resize(std::min(rows,cols),cols);
|
||||
m_u.resizeNonZeros(unz);
|
||||
|
||||
m_p.resize(rows);
|
||||
m_q.resize(cols);
|
||||
|
||||
// extract
|
||||
umfpack_get_numeric(m_l._outerIndexPtr(), m_l._innerIndexPtr(), m_l._valuePtr(),
|
||||
m_u._outerIndexPtr(), m_u._innerIndexPtr(), m_u._valuePtr(),
|
||||
m_p.data(), m_q.data(), 0, 0, 0, m_numeric);
|
||||
|
||||
m_extractedDataAreDirty = false;
|
||||
}
|
||||
}
|
||||
|
||||
template<typename MatrixType>
|
||||
typename SparseLU<MatrixType,UmfPack>::Scalar SparseLU<MatrixType,UmfPack>::determinant() const
|
||||
{
|
||||
Scalar det;
|
||||
umfpack_get_determinant(&det, 0, m_numeric, 0);
|
||||
return det;
|
||||
}
|
||||
|
||||
template<typename MatrixType>
|
||||
template<typename BDerived,typename XDerived>
|
||||
bool SparseLU<MatrixType,UmfPack>::solve(const MatrixBase<BDerived> &b, MatrixBase<XDerived> *x) const
|
||||
{
|
||||
//const int size = m_matrix.rows();
|
||||
const int rhsCols = b.cols();
|
||||
// ei_assert(size==b.rows());
|
||||
ei_assert((BDerived::Flags&RowMajorBit)==0 && "UmfPack backend does not support non col-major rhs yet");
|
||||
ei_assert((XDerived::Flags&RowMajorBit)==0 && "UmfPack backend does not support non col-major result yet");
|
||||
|
||||
int errorCode;
|
||||
for (int j=0; j<rhsCols; ++j)
|
||||
{
|
||||
errorCode = umfpack_solve(UMFPACK_A,
|
||||
m_matrixRef->_outerIndexPtr(), m_matrixRef->_innerIndexPtr(), m_matrixRef->_valuePtr(),
|
||||
&x->col(j).coeffRef(0), &b.const_cast_derived().col(j).coeffRef(0), m_numeric, 0, 0);
|
||||
if (errorCode!=0)
|
||||
return false;
|
||||
}
|
||||
// errorCode = umfpack_di_solve(UMFPACK_A,
|
||||
// m_matrixRef._outerIndexPtr(), m_matrixRef._innerIndexPtr(), m_matrixRef._valuePtr(),
|
||||
// x->derived().data(), b.derived().data(), m_numeric, 0, 0);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
#endif // EIGEN_UMFPACKSUPPORT_H
|
||||
@@ -1,4 +1,7 @@
|
||||
|
||||
// Please don't remove the following lines:
|
||||
// this is the only way to specify doxygen options
|
||||
// to api.kde.org's scripts
|
||||
|
||||
// DOXYGEN_SET_PROJECT_NAME = Eigen2
|
||||
// DOXYGEN_SET_PROJECT_NUMBER = "2.0-beta1"
|
||||
@@ -15,7 +18,7 @@
|
||||
// DOXYGEN_SET_MULTILINE_CPP_IS_BRIEF = NO
|
||||
// DOXYGEN_SET_DETAILS_AT_TOP = YES
|
||||
// DOXYGEN_SET_INHERIT_DOCS = YES
|
||||
// DOXYGEN_SET_ALIASES = "only_for_vectors=This is only for vectors (either row-vectors or column-vectors), i.e. matrices which are known at compile-time to have either one row or one column." "array_module=This is defined in the %Array module. \code #include <Eigen/Array> \endcode" "lu_module=This is defined in the %LU module. \code #include <Eigen/LU> \endcode" "cholesky_module=This is defined in the %Cholesky module. \code #include <Eigen/Cholesky> \endcode" "qr_module=This is defined in the %QR module. \code #include <Eigen/QR> \endcode" "svd_module=This is defined in the %SVD module. \code #include <Eigen/SVD> \endcode" "geometry_module=This is defined in the %Geometry module. \code #include <Eigen/Geometry> \endcode" "regression_module=This is defined in the %Regression module. \code #include <Eigen/Regression> \endcode" "addexample=\anchor" "label=\bug"
|
||||
// DOXYGEN_SET_ALIASES = "only_for_vectors=This is only for vectors (either row-vectors or column-vectors), i.e. matrices which are known at compile-time to have either one row or one column." "array_module=This is defined in the %Array module. \code #include <Eigen/Array> \endcode" "lu_module=This is defined in the %LU module. \code #include <Eigen/LU> \endcode" "cholesky_module=This is defined in the %Cholesky module. \code #include <Eigen/Cholesky> \endcode" "qr_module=This is defined in the %QR module. \code #include <Eigen/QR> \endcode" "svd_module=This is defined in the %SVD module. \code #include <Eigen/SVD> \endcode" "geometry_module=This is defined in the %Geometry module. \code #include <Eigen/Geometry> \endcode" "regression_module=This is defined in the %Regression module. \code #include <Eigen/Regression> \endcode" "addexample=\anchor" "label=\bug" "redstar=<a href='#warningarraymodule' style='color:red;text-decoration: none;'><span style='color:red'>*</span></a>"
|
||||
// DOXYGEN_SET_DISTRIBUTE_GROUP_DOC = NO
|
||||
// DOXYGEN_SET_SUBGROUPING = YES
|
||||
// DOXYGEN_SET_TYPEDEF_HIDES_STRUCT = NO
|
||||
@@ -58,7 +61,6 @@
|
||||
|
||||
// DOXYGEN_SET_FILE_PATTERNS = *
|
||||
// DOXYGEN_SET_RECURSIVE = NO
|
||||
DISABLED/FILTER_PATTERNS = *.cpp=@topdir@/eigen2/doc/apidox_preprocessing.sh
|
||||
// DOXYGEN_SET_FILTER_SOURCE_FILES = YES
|
||||
|
||||
// DOXYGEN_SET_SOURCE_BROWSER = NO
|
||||
|
||||
@@ -16,7 +16,7 @@ USING_PART_OF_NAMESPACE_EIGEN
|
||||
#endif
|
||||
|
||||
#ifndef SCALAR
|
||||
#define SCALAR float
|
||||
#define SCALAR double
|
||||
#endif
|
||||
|
||||
typedef SCALAR Scalar;
|
||||
@@ -72,3 +72,23 @@ void eiToMtl(const EigenSparseMatrix& src, MtlSparse& dst)
|
||||
ins[it.index()][j] = it.value();
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef CSPARSE
|
||||
extern "C" {
|
||||
#include "cs.h"
|
||||
}
|
||||
void eiToCSparse(const EigenSparseMatrix& src, cs* &dst)
|
||||
{
|
||||
cs* aux = cs_spalloc (0, 0, 1, 1, 1);
|
||||
for (int j=0; j<src.cols(); ++j)
|
||||
for (EigenSparseMatrix::InnerIterator it(src.derived(), j); it; ++it)
|
||||
if (!cs_entry(aux, it.index(), j, it.value()))
|
||||
{
|
||||
std::cout << "cs_entry error\n";
|
||||
exit(2);
|
||||
}
|
||||
dst = cs_compress(aux);
|
||||
// cs_spfree(aux);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
// for linear algebra. Eigen itself is part of the KDE project.
|
||||
//
|
||||
// Copyright (C) 2008 Gael Guennebaud <g.gael@free.fr>
|
||||
// Copyright (C) 2006-2008 Benoit Jacob <jacob@math.jussieu.fr>
|
||||
// Copyright (C) 2006-2008 Benoit Jacob <jacob.benoit.1@gmail.com>
|
||||
//
|
||||
// Eigen is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU Lesser General Public
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
|
||||
// g++ -DNDEBUG -O3 -I.. benchCholesky.cpp -o benchCholesky && ./benchCholesky
|
||||
// g++ -DNDEBUG -O3 -I.. benchLLT.cpp -o benchLLT && ./benchLLT
|
||||
// options:
|
||||
// -DBENCH_GSL -lgsl /usr/lib/libcblas.so.3
|
||||
// -DEIGEN_DONT_VECTORIZE
|
||||
@@ -9,7 +9,7 @@
|
||||
// -DSCALAR=double
|
||||
|
||||
#include <Eigen/Array>
|
||||
#include <Eigen/Cholesky>
|
||||
#include <Eigen/LLT>
|
||||
#include <bench/BenchUtil.h>
|
||||
using namespace Eigen;
|
||||
|
||||
@@ -24,7 +24,7 @@ using namespace Eigen;
|
||||
typedef float Scalar;
|
||||
|
||||
template <typename MatrixType>
|
||||
__attribute__ ((noinline)) void benchCholesky(const MatrixType& m)
|
||||
__attribute__ ((noinline)) void benchLLT(const MatrixType& m)
|
||||
{
|
||||
int rows = m.rows();
|
||||
int cols = m.cols();
|
||||
@@ -54,7 +54,7 @@ __attribute__ ((noinline)) void benchCholesky(const MatrixType& m)
|
||||
timerNoSqrt.start();
|
||||
for (int k=0; k<repeats; ++k)
|
||||
{
|
||||
CholeskyWithoutSquareRoot<SquareMatrixType> cholnosqrt(covMat);
|
||||
LDLT<SquareMatrixType> cholnosqrt(covMat);
|
||||
acc += cholnosqrt.matrixL().coeff(r,c);
|
||||
}
|
||||
timerNoSqrt.stop();
|
||||
@@ -65,7 +65,7 @@ __attribute__ ((noinline)) void benchCholesky(const MatrixType& m)
|
||||
timerSqrt.start();
|
||||
for (int k=0; k<repeats; ++k)
|
||||
{
|
||||
Cholesky<SquareMatrixType> chol(covMat);
|
||||
LLT<SquareMatrixType> chol(covMat);
|
||||
acc += chol.matrixL().coeff(r,c);
|
||||
}
|
||||
timerSqrt.stop();
|
||||
@@ -124,17 +124,17 @@ int main(int argc, char* argv[])
|
||||
std::cout << "\n";
|
||||
|
||||
for (uint i=0; dynsizes[i]>0; ++i)
|
||||
benchCholesky(Matrix<Scalar,Dynamic,Dynamic>(dynsizes[i],dynsizes[i]));
|
||||
benchLLT(Matrix<Scalar,Dynamic,Dynamic>(dynsizes[i],dynsizes[i]));
|
||||
|
||||
// benchCholesky(Matrix<Scalar,2,2>());
|
||||
// benchCholesky(Matrix<Scalar,3,3>());
|
||||
// benchCholesky(Matrix<Scalar,4,4>());
|
||||
// benchCholesky(Matrix<Scalar,5,5>());
|
||||
// benchCholesky(Matrix<Scalar,6,6>());
|
||||
// benchCholesky(Matrix<Scalar,7,7>());
|
||||
// benchCholesky(Matrix<Scalar,8,8>());
|
||||
// benchCholesky(Matrix<Scalar,12,12>());
|
||||
// benchCholesky(Matrix<Scalar,16,16>());
|
||||
// benchLLT(Matrix<Scalar,2,2>());
|
||||
// benchLLT(Matrix<Scalar,3,3>());
|
||||
// benchLLT(Matrix<Scalar,4,4>());
|
||||
// benchLLT(Matrix<Scalar,5,5>());
|
||||
// benchLLT(Matrix<Scalar,6,6>());
|
||||
// benchLLT(Matrix<Scalar,7,7>());
|
||||
// benchLLT(Matrix<Scalar,8,8>());
|
||||
// benchLLT(Matrix<Scalar,12,12>());
|
||||
// benchLLT(Matrix<Scalar,16,16>());
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
215
bench/sparse_cholesky.cpp
Normal file
215
bench/sparse_cholesky.cpp
Normal file
@@ -0,0 +1,215 @@
|
||||
// #define EIGEN_TAUCS_SUPPORT
|
||||
// #define EIGEN_CHOLMOD_SUPPORT
|
||||
#include <Eigen/Sparse>
|
||||
|
||||
// g++ -DSIZE=10000 -DDENSITY=0.001 sparse_cholesky.cpp -I.. -DDENSEMATRI -O3 -g0 -DNDEBUG -DNBTRIES=1 -I /home/gael/Coding/LinearAlgebra/taucs_full/src/ -I/home/gael/Coding/LinearAlgebra/taucs_full/build/linux/ -L/home/gael/Coding/LinearAlgebra/taucs_full/lib/linux/ -ltaucs /home/gael/Coding/LinearAlgebra/GotoBLAS/libgoto.a -lpthread -I /home/gael/Coding/LinearAlgebra/SuiteSparse/CHOLMOD/Include/ $CHOLLIB -I /home/gael/Coding/LinearAlgebra/SuiteSparse/UFconfig/ /home/gael/Coding/LinearAlgebra/SuiteSparse/CCOLAMD/Lib/libccolamd.a /home/gael/Coding/LinearAlgebra/SuiteSparse/CHOLMOD/Lib/libcholmod.a -lmetis /home/gael/Coding/LinearAlgebra/SuiteSparse/AMD/Lib/libamd.a /home/gael/Coding/LinearAlgebra/SuiteSparse/CAMD/Lib/libcamd.a /home/gael/Coding/LinearAlgebra/SuiteSparse/CCOLAMD/Lib/libccolamd.a /home/gael/Coding/LinearAlgebra/SuiteSparse/COLAMD/Lib/libcolamd.a -llapack && ./a.out
|
||||
|
||||
#define NOGMM
|
||||
#define NOMTL
|
||||
|
||||
#ifndef SIZE
|
||||
#define SIZE 10
|
||||
#endif
|
||||
|
||||
#ifndef DENSITY
|
||||
#define DENSITY 0.01
|
||||
#endif
|
||||
|
||||
#ifndef REPEAT
|
||||
#define REPEAT 1
|
||||
#endif
|
||||
|
||||
#include "BenchSparseUtil.h"
|
||||
|
||||
#ifndef MINDENSITY
|
||||
#define MINDENSITY 0.0004
|
||||
#endif
|
||||
|
||||
#ifndef NBTRIES
|
||||
#define NBTRIES 10
|
||||
#endif
|
||||
|
||||
#define BENCH(X) \
|
||||
timer.reset(); \
|
||||
for (int _j=0; _j<NBTRIES; ++_j) { \
|
||||
timer.start(); \
|
||||
for (int _k=0; _k<REPEAT; ++_k) { \
|
||||
X \
|
||||
} timer.stop(); }
|
||||
|
||||
// typedef SparseMatrix<Scalar,Upper> EigenSparseTriMatrix;
|
||||
typedef SparseMatrix<Scalar,SelfAdjoint|Lower> EigenSparseSelfAdjointMatrix;
|
||||
|
||||
void fillSpdMatrix(float density, int rows, int cols, EigenSparseSelfAdjointMatrix& dst)
|
||||
{
|
||||
dst.startFill(rows*cols*density);
|
||||
for(int j = 0; j < cols; j++)
|
||||
{
|
||||
dst.fill(j,j) = ei_random<Scalar>(10,20);
|
||||
for(int i = j+1; i < rows; i++)
|
||||
{
|
||||
Scalar v = (ei_random<float>(0,1) < density) ? ei_random<Scalar>() : 0;
|
||||
if (v!=0)
|
||||
dst.fill(i,j) = v;
|
||||
}
|
||||
|
||||
}
|
||||
dst.endFill();
|
||||
}
|
||||
|
||||
#include <Eigen/Cholesky>
|
||||
|
||||
template<int Backend>
|
||||
void doEigen(const char* name, const EigenSparseSelfAdjointMatrix& sm1, int flags = 0)
|
||||
{
|
||||
std::cout << name << "..." << std::flush;
|
||||
BenchTimer timer;
|
||||
timer.start();
|
||||
SparseLLT<EigenSparseSelfAdjointMatrix,Backend> chol(sm1, flags);
|
||||
timer.stop();
|
||||
std::cout << ":\t" << timer.value() << endl;
|
||||
|
||||
std::cout << " nnz: " << sm1.nonZeros() << " => " << chol.matrixL().nonZeros() << "\n";
|
||||
// std::cout << "sparse\n" << chol.matrixL() << "%\n";
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
int rows = SIZE;
|
||||
int cols = SIZE;
|
||||
float density = DENSITY;
|
||||
BenchTimer timer;
|
||||
|
||||
VectorXf b = VectorXf::Random(cols);
|
||||
VectorXf x = VectorXf::Random(cols);
|
||||
|
||||
bool densedone = false;
|
||||
|
||||
//for (float density = DENSITY; density>=MINDENSITY; density*=0.5)
|
||||
// float density = 0.5;
|
||||
{
|
||||
EigenSparseSelfAdjointMatrix sm1(rows, cols);
|
||||
std::cout << "Generate sparse matrix (might take a while)...\n";
|
||||
fillSpdMatrix(density, rows, cols, sm1);
|
||||
std::cout << "DONE\n\n";
|
||||
|
||||
// dense matrices
|
||||
#ifdef DENSEMATRIX
|
||||
if (!densedone)
|
||||
{
|
||||
densedone = true;
|
||||
std::cout << "Eigen Dense\t" << density*100 << "%\n";
|
||||
DenseMatrix m1(rows,cols);
|
||||
eiToDense(sm1, m1);
|
||||
m1 = (m1 + m1.transpose()).eval();
|
||||
m1.diagonal() *= 0.5;
|
||||
|
||||
// BENCH(LLT<DenseMatrix> chol(m1);)
|
||||
// std::cout << "dense:\t" << timer.value() << endl;
|
||||
|
||||
BenchTimer timer;
|
||||
timer.start();
|
||||
LLT<DenseMatrix> chol(m1);
|
||||
timer.stop();
|
||||
std::cout << "dense:\t" << timer.value() << endl;
|
||||
int count = 0;
|
||||
for (int j=0; j<cols; ++j)
|
||||
for (int i=j; i<rows; ++i)
|
||||
if (!ei_isMuchSmallerThan(ei_abs(chol.matrixL()(i,j)), 0.1))
|
||||
count++;
|
||||
std::cout << "dense: " << "nnz = " << count << "\n";
|
||||
// std::cout << "dense:\n" << m1 << "\n\n" << chol.matrixL() << endl;
|
||||
}
|
||||
#endif
|
||||
|
||||
// eigen sparse matrices
|
||||
doEigen<Eigen::DefaultBackend>("Eigen/Sparse", sm1, Eigen::IncompleteFactorization);
|
||||
|
||||
#ifdef EIGEN_CHOLMOD_SUPPORT
|
||||
doEigen<Eigen::Cholmod>("Eigen/Cholmod", sm1, Eigen::IncompleteFactorization);
|
||||
#endif
|
||||
|
||||
#ifdef EIGEN_TAUCS_SUPPORT
|
||||
doEigen<Eigen::Taucs>("Eigen/Taucs", sm1, Eigen::IncompleteFactorization);
|
||||
#endif
|
||||
|
||||
#if 0
|
||||
// TAUCS
|
||||
{
|
||||
taucs_ccs_matrix A = sm1.asTaucsMatrix();
|
||||
|
||||
//BENCH(taucs_ccs_matrix* chol = taucs_ccs_factor_llt(&A, 0, 0);)
|
||||
// BENCH(taucs_supernodal_factor_to_ccs(taucs_ccs_factor_llt_ll(&A));)
|
||||
// std::cout << "taucs:\t" << timer.value() << endl;
|
||||
|
||||
taucs_ccs_matrix* chol = taucs_ccs_factor_llt(&A, 0, 0);
|
||||
|
||||
for (int j=0; j<cols; ++j)
|
||||
{
|
||||
for (int i=chol->colptr[j]; i<chol->colptr[j+1]; ++i)
|
||||
std::cout << chol->values.d[i] << " ";
|
||||
}
|
||||
}
|
||||
|
||||
// CHOLMOD
|
||||
#ifdef EIGEN_CHOLMOD_SUPPORT
|
||||
{
|
||||
cholmod_common c;
|
||||
cholmod_start (&c);
|
||||
cholmod_sparse A;
|
||||
cholmod_factor *L;
|
||||
|
||||
A = sm1.asCholmodMatrix();
|
||||
BenchTimer timer;
|
||||
// timer.reset();
|
||||
timer.start();
|
||||
std::vector<int> perm(cols);
|
||||
// std::vector<int> set(ncols);
|
||||
for (int i=0; i<cols; ++i)
|
||||
perm[i] = i;
|
||||
// c.nmethods = 1;
|
||||
// c.method[0] = 1;
|
||||
|
||||
c.nmethods = 1;
|
||||
c.method [0].ordering = CHOLMOD_NATURAL;
|
||||
c.postorder = 0;
|
||||
c.final_ll = 1;
|
||||
|
||||
L = cholmod_analyze_p(&A, &perm[0], &perm[0], cols, &c);
|
||||
timer.stop();
|
||||
std::cout << "cholmod/analyze:\t" << timer.value() << endl;
|
||||
timer.reset();
|
||||
timer.start();
|
||||
cholmod_factorize(&A, L, &c);
|
||||
timer.stop();
|
||||
std::cout << "cholmod/factorize:\t" << timer.value() << endl;
|
||||
|
||||
cholmod_sparse* cholmat = cholmod_factor_to_sparse(L, &c);
|
||||
|
||||
cholmod_print_factor(L, "Factors", &c);
|
||||
|
||||
cholmod_print_sparse(cholmat, "Chol", &c);
|
||||
cholmod_write_sparse(stdout, cholmat, 0, 0, &c);
|
||||
//
|
||||
// cholmod_print_sparse(&A, "A", &c);
|
||||
// cholmod_write_sparse(stdout, &A, 0, 0, &c);
|
||||
|
||||
|
||||
// for (int j=0; j<cols; ++j)
|
||||
// {
|
||||
// for (int i=chol->colptr[j]; i<chol->colptr[j+1]; ++i)
|
||||
// std::cout << chol->values.s[i] << " ";
|
||||
// }
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
132
bench/sparse_lu.cpp
Normal file
132
bench/sparse_lu.cpp
Normal file
@@ -0,0 +1,132 @@
|
||||
|
||||
// g++ -I.. sparse_lu.cpp -O3 -g0 -I /usr/include/superlu/ -lsuperlu -lgfortran -DSIZE=1000 -DDENSITY=.05 && ./a.out
|
||||
|
||||
#define EIGEN_SUPERLU_SUPPORT
|
||||
#define EIGEN_UMFPACK_SUPPORT
|
||||
#include <Eigen/Sparse>
|
||||
|
||||
#define NOGMM
|
||||
#define NOMTL
|
||||
|
||||
#ifndef SIZE
|
||||
#define SIZE 10
|
||||
#endif
|
||||
|
||||
#ifndef DENSITY
|
||||
#define DENSITY 0.01
|
||||
#endif
|
||||
|
||||
#ifndef REPEAT
|
||||
#define REPEAT 1
|
||||
#endif
|
||||
|
||||
#include "BenchSparseUtil.h"
|
||||
|
||||
#ifndef MINDENSITY
|
||||
#define MINDENSITY 0.0004
|
||||
#endif
|
||||
|
||||
#ifndef NBTRIES
|
||||
#define NBTRIES 10
|
||||
#endif
|
||||
|
||||
#define BENCH(X) \
|
||||
timer.reset(); \
|
||||
for (int _j=0; _j<NBTRIES; ++_j) { \
|
||||
timer.start(); \
|
||||
for (int _k=0; _k<REPEAT; ++_k) { \
|
||||
X \
|
||||
} timer.stop(); }
|
||||
|
||||
typedef Matrix<Scalar,Dynamic,1> VectorX;
|
||||
|
||||
#include <Eigen/LU>
|
||||
|
||||
template<int Backend>
|
||||
void doEigen(const char* name, const EigenSparseMatrix& sm1, const VectorX& b, VectorX& x, int flags = 0)
|
||||
{
|
||||
std::cout << name << "..." << std::flush;
|
||||
BenchTimer timer; timer.start();
|
||||
SparseLU<EigenSparseMatrix,Backend> lu(sm1, flags);
|
||||
timer.stop();
|
||||
if (lu.succeeded())
|
||||
std::cout << ":\t" << timer.value() << endl;
|
||||
else
|
||||
{
|
||||
std::cout << ":\t FAILED" << endl;
|
||||
return;
|
||||
}
|
||||
|
||||
bool ok;
|
||||
timer.reset(); timer.start();
|
||||
ok = lu.solve(b,&x);
|
||||
timer.stop();
|
||||
if (ok)
|
||||
std::cout << " solve:\t" << timer.value() << endl;
|
||||
else
|
||||
std::cout << " solve:\t" << " FAILED" << endl;
|
||||
|
||||
//std::cout << x.transpose() << "\n";
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
int rows = SIZE;
|
||||
int cols = SIZE;
|
||||
float density = DENSITY;
|
||||
BenchTimer timer;
|
||||
|
||||
VectorX b = VectorX::Random(cols);
|
||||
VectorX x = VectorX::Random(cols);
|
||||
|
||||
bool densedone = false;
|
||||
|
||||
//for (float density = DENSITY; density>=MINDENSITY; density*=0.5)
|
||||
// float density = 0.5;
|
||||
{
|
||||
EigenSparseMatrix sm1(rows, cols);
|
||||
fillMatrix(density, rows, cols, sm1);
|
||||
|
||||
// dense matrices
|
||||
#ifdef DENSEMATRIX
|
||||
if (!densedone)
|
||||
{
|
||||
densedone = true;
|
||||
std::cout << "Eigen Dense\t" << density*100 << "%\n";
|
||||
DenseMatrix m1(rows,cols);
|
||||
eiToDense(sm1, m1);
|
||||
|
||||
BenchTimer timer;
|
||||
timer.start();
|
||||
LU<DenseMatrix> lu(m1);
|
||||
timer.stop();
|
||||
std::cout << "Eigen/dense:\t" << timer.value() << endl;
|
||||
|
||||
timer.reset();
|
||||
timer.start();
|
||||
lu.solve(b,&x);
|
||||
timer.stop();
|
||||
std::cout << " solve:\t" << timer.value() << endl;
|
||||
// std::cout << b.transpose() << "\n";
|
||||
// std::cout << x.transpose() << "\n";
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef EIGEN_UMFPACK_SUPPORT
|
||||
x.setZero();
|
||||
doEigen<Eigen::UmfPack>("Eigen/UmfPack (auto)", sm1, b, x, 0);
|
||||
#endif
|
||||
|
||||
#ifdef EIGEN_SUPERLU_SUPPORT
|
||||
x.setZero();
|
||||
doEigen<Eigen::SuperLU>("Eigen/SuperLU (nat)", sm1, b, x, Eigen::NaturalOrdering);
|
||||
// doEigen<Eigen::SuperLU>("Eigen/SuperLU (MD AT+A)", sm1, b, x, Eigen::MinimumDegree_AT_PLUS_A);
|
||||
// doEigen<Eigen::SuperLU>("Eigen/SuperLU (MD ATA)", sm1, b, x, Eigen::MinimumDegree_ATA);
|
||||
doEigen<Eigen::SuperLU>("Eigen/SuperLU (COLAMD)", sm1, b, x, Eigen::ColApproxMinimumDegree);
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
|
||||
//g++ -O3 -g0 -DNDEBUG sparse_product.cpp -I.. -I/home/gael/Coding/LinearAlgebra/mtl4/ -DDENSITY=0.005 -DSIZE=10000 && ./a.out
|
||||
//g++ -O3 -g0 -DNDEBUG sparse_product.cpp -I.. -I/home/gael/Coding/LinearAlgebra/mtl4/ -DDENSITY=0.05 -DSIZE=2000 && ./a.out
|
||||
// -DNOGMM -DNOMTL
|
||||
|
||||
// -DNOGMM -DNOMTL -DCSPARSE
|
||||
// -I /home/gael/Coding/LinearAlgebra/CSparse/Include/ /home/gael/Coding/LinearAlgebra/CSparse/Lib/libcsparse.a
|
||||
#ifndef SIZE
|
||||
#define SIZE 10000
|
||||
#endif
|
||||
@@ -21,6 +21,34 @@
|
||||
#define MINDENSITY 0.0004
|
||||
#endif
|
||||
|
||||
#ifndef NBTRIES
|
||||
#define NBTRIES 10
|
||||
#endif
|
||||
|
||||
#define BENCH(X) \
|
||||
timer.reset(); \
|
||||
for (int _j=0; _j<NBTRIES; ++_j) { \
|
||||
timer.start(); \
|
||||
for (int _k=0; _k<REPEAT; ++_k) { \
|
||||
X \
|
||||
} timer.stop(); }
|
||||
|
||||
|
||||
#ifdef CSPARSE
|
||||
cs* cs_sorted_multiply(const cs* a, const cs* b)
|
||||
{
|
||||
cs* A = cs_transpose (a, 1) ;
|
||||
cs* B = cs_transpose (b, 1) ;
|
||||
cs* D = cs_multiply (B,A) ; /* D = B'*A' */
|
||||
cs_spfree (A) ;
|
||||
cs_spfree (B) ;
|
||||
cs_dropzeros (D) ; /* drop zeros from D */
|
||||
cs* C = cs_transpose (D, 1) ; /* C = D', so that C is sorted */
|
||||
cs_spfree (D) ;
|
||||
return C;
|
||||
}
|
||||
#endif
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
int rows = SIZE;
|
||||
@@ -75,36 +103,66 @@ int main(int argc, char *argv[])
|
||||
|
||||
// eigen sparse matrices
|
||||
{
|
||||
std::cout << "Eigen sparse\t" << density*100 << "%\n";
|
||||
std::cout << "Eigen sparse\t" << sm1.nonZeros()/float(sm1.rows()*sm1.cols())*100 << "% * "
|
||||
<< sm2.nonZeros()/float(sm2.rows()*sm2.cols())*100 << "%\n";
|
||||
|
||||
timer.reset();
|
||||
timer.start();
|
||||
for (int k=0; k<REPEAT; ++k)
|
||||
sm3 = sm1 * sm2;
|
||||
timer.stop();
|
||||
// timer.reset();
|
||||
// timer.start();
|
||||
BENCH(for (int k=0; k<REPEAT; ++k) sm3 = sm1 * sm2;)
|
||||
// timer.stop();
|
||||
std::cout << " a * b:\t" << timer.value() << endl;
|
||||
// std::cout << sm3 << "\n";
|
||||
|
||||
timer.reset();
|
||||
timer.start();
|
||||
for (int k=0; k<REPEAT; ++k)
|
||||
sm3 = sm1.transpose() * sm2;
|
||||
timer.stop();
|
||||
// std::cerr << "transpose...\n";
|
||||
// EigenSparseMatrix sm4 = sm1.transpose();
|
||||
// std::cout << sm4.nonZeros() << " == " << sm1.nonZeros() << "\n";
|
||||
// exit(1);
|
||||
// std::cerr << "transpose OK\n";
|
||||
// std::cout << sm1 << "\n\n" << sm1.transpose() << "\n\n" << sm4.transpose() << "\n\n";
|
||||
BENCH(for (int k=0; k<REPEAT; ++k) sm3 = sm1.transpose() * sm2;)
|
||||
// timer.stop();
|
||||
std::cout << " a' * b:\t" << timer.value() << endl;
|
||||
|
||||
timer.reset();
|
||||
timer.start();
|
||||
for (int k=0; k<REPEAT; ++k)
|
||||
sm3 = sm1.transpose() * sm2.transpose();
|
||||
timer.stop();
|
||||
// timer.reset();
|
||||
// timer.start();
|
||||
BENCH( for (int k=0; k<REPEAT; ++k) sm3 = sm1.transpose() * sm2.transpose(); )
|
||||
// timer.stop();
|
||||
std::cout << " a' * b':\t" << timer.value() << endl;
|
||||
|
||||
// timer.reset();
|
||||
// timer.start();
|
||||
BENCH( for (int k=0; k<REPEAT; ++k) sm3 = sm1 * sm2.transpose(); )
|
||||
// timer.stop();
|
||||
std::cout << " a * b' :\t" << timer.value() << endl;
|
||||
}
|
||||
|
||||
// CSparse
|
||||
#ifdef CSPARSE
|
||||
{
|
||||
std::cout << "CSparse \t" << density*100 << "%\n";
|
||||
cs *m1, *m2, *m3;
|
||||
eiToCSparse(sm1, m1);
|
||||
eiToCSparse(sm2, m2);
|
||||
|
||||
timer.reset();
|
||||
timer.start();
|
||||
for (int k=0; k<REPEAT; ++k)
|
||||
sm3 = sm1 * sm2.transpose();
|
||||
{
|
||||
m3 = cs_sorted_multiply(m1, m2);
|
||||
if (!m3)
|
||||
{
|
||||
std::cerr << "cs_multiply failed\n";
|
||||
// break;
|
||||
}
|
||||
// cs_print(m3, 0);
|
||||
cs_spfree(m3);
|
||||
}
|
||||
timer.stop();
|
||||
std::cout << " a * b' :\t" << timer.value() << endl;
|
||||
std::cout << " a * b:\t" << timer.value() << endl;
|
||||
}
|
||||
#endif
|
||||
|
||||
// GMM++
|
||||
#ifndef NOGMM
|
||||
|
||||
125
bench/sparse_randomsetter.cpp
Normal file
125
bench/sparse_randomsetter.cpp
Normal file
@@ -0,0 +1,125 @@
|
||||
|
||||
#define NOGMM
|
||||
#define NOMTL
|
||||
|
||||
#include <map>
|
||||
#include <ext/hash_map>
|
||||
#include <google/dense_hash_map>
|
||||
#include <google/sparse_hash_map>
|
||||
|
||||
#ifndef SIZE
|
||||
#define SIZE 10000
|
||||
#endif
|
||||
|
||||
#ifndef DENSITY
|
||||
#define DENSITY 0.01
|
||||
#endif
|
||||
|
||||
#ifndef REPEAT
|
||||
#define REPEAT 1
|
||||
#endif
|
||||
|
||||
#include "BenchSparseUtil.h"
|
||||
|
||||
#ifndef MINDENSITY
|
||||
#define MINDENSITY 0.0004
|
||||
#endif
|
||||
|
||||
#ifndef NBTRIES
|
||||
#define NBTRIES 10
|
||||
#endif
|
||||
|
||||
#define BENCH(X) \
|
||||
timer.reset(); \
|
||||
for (int _j=0; _j<NBTRIES; ++_j) { \
|
||||
timer.start(); \
|
||||
for (int _k=0; _k<REPEAT; ++_k) { \
|
||||
X \
|
||||
} timer.stop(); }
|
||||
|
||||
|
||||
static double rtime;
|
||||
static double nentries;
|
||||
|
||||
template<typename SetterType>
|
||||
void dostuff(const char* name, EigenSparseMatrix& sm1)
|
||||
{
|
||||
int rows = sm1.rows();
|
||||
int cols = sm1.cols();
|
||||
sm1.setZero();
|
||||
BenchTimer t;
|
||||
SetterType* set1 = new SetterType(sm1);
|
||||
t.reset(); t.start();
|
||||
for (int k=0; k<nentries; ++k)
|
||||
(*set1)(ei_random<int>(0,rows-1),ei_random<int>(0,cols-1)) += 1;
|
||||
t.stop();
|
||||
std::cout << "std::map => \t" << t.value()-rtime
|
||||
<< " nnz=" << set1->nonZeros() << std::flush;
|
||||
|
||||
// getchar();
|
||||
|
||||
t.reset(); t.start(); delete set1; t.stop();
|
||||
std::cout << " back: \t" << t.value() << "\n";
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
int rows = SIZE;
|
||||
int cols = SIZE;
|
||||
float density = DENSITY;
|
||||
|
||||
EigenSparseMatrix sm1(rows,cols), sm2(rows,cols);
|
||||
|
||||
|
||||
nentries = rows*cols*density;
|
||||
std::cout << "n = " << nentries << "\n";
|
||||
int dummy;
|
||||
BenchTimer t;
|
||||
|
||||
t.reset(); t.start();
|
||||
for (int k=0; k<nentries; ++k)
|
||||
dummy = ei_random<int>(0,rows-1) + ei_random<int>(0,cols-1);
|
||||
t.stop();
|
||||
rtime = t.value();
|
||||
std::cout << "rtime = " << rtime << " (" << dummy << ")\n\n";
|
||||
const int Bits = 6;
|
||||
for (;;)
|
||||
{
|
||||
dostuff<RandomSetter<EigenSparseMatrix,StdMapTraits,Bits> >("std::map ", sm1);
|
||||
dostuff<RandomSetter<EigenSparseMatrix,GnuHashMapTraits,Bits> >("gnu::hash_map", sm1);
|
||||
dostuff<RandomSetter<EigenSparseMatrix,GoogleDenseHashMapTraits,Bits> >("google::dense", sm1);
|
||||
dostuff<RandomSetter<EigenSparseMatrix,GoogleSparseHashMapTraits,Bits> >("google::sparse", sm1);
|
||||
|
||||
// {
|
||||
// RandomSetter<EigenSparseMatrix,GnuHashMapTraits,Bits> set1(sm1);
|
||||
// t.reset(); t.start();
|
||||
// for (int k=0; k<n; ++k)
|
||||
// set1(ei_random<int>(0,rows-1),ei_random<int>(0,cols-1)) += 1;
|
||||
// t.stop();
|
||||
// std::cout << "gnu::hash_map => \t" << t.value()-rtime
|
||||
// << " nnz=" << set1.nonZeros() << "\n";getchar();
|
||||
// }
|
||||
// {
|
||||
// RandomSetter<EigenSparseMatrix,GoogleDenseHashMapTraits,Bits> set1(sm1);
|
||||
// t.reset(); t.start();
|
||||
// for (int k=0; k<n; ++k)
|
||||
// set1(ei_random<int>(0,rows-1),ei_random<int>(0,cols-1)) += 1;
|
||||
// t.stop();
|
||||
// std::cout << "google::dense => \t" << t.value()-rtime
|
||||
// << " nnz=" << set1.nonZeros() << "\n";getchar();
|
||||
// }
|
||||
// {
|
||||
// RandomSetter<EigenSparseMatrix,GoogleSparseHashMapTraits,Bits> set1(sm1);
|
||||
// t.reset(); t.start();
|
||||
// for (int k=0; k<n; ++k)
|
||||
// set1(ei_random<int>(0,rows-1),ei_random<int>(0,cols-1)) += 1;
|
||||
// t.stop();
|
||||
// std::cout << "google::sparse => \t" << t.value()-rtime
|
||||
// << " nnz=" << set1.nonZeros() << "\n";getchar();
|
||||
// }
|
||||
std::cout << "\n\n";
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user