mirror of
https://gitlab.com/libeigen/eigen.git
synced 2026-04-10 11:34:33 +08:00
Pulled latest update from the eigen main codebase
This commit is contained in:
@@ -310,6 +310,7 @@ using std::ptrdiff_t;
|
||||
#include "src/Core/arch/NEON/PacketMath.h"
|
||||
#include "src/Core/arch/NEON/MathFunctions.h"
|
||||
#include "src/Core/arch/NEON/Complex.h"
|
||||
#include "src/Core/arch/NEON/BlockingSizesLookupTables.h"
|
||||
#endif
|
||||
|
||||
#if defined EIGEN_VECTORIZE_CUDA
|
||||
@@ -383,6 +384,7 @@ using std::ptrdiff_t;
|
||||
#include "src/Core/Inverse.h"
|
||||
#include "src/Core/TriangularMatrix.h"
|
||||
#include "src/Core/SelfAdjointView.h"
|
||||
#include "src/Core/products/LookupBlockingSizesTable.h"
|
||||
#include "src/Core/products/GeneralBlockPanelKernel.h"
|
||||
#include "src/Core/products/Parallelizer.h"
|
||||
#include "src/Core/ProductEvaluators.h"
|
||||
|
||||
@@ -12,24 +12,26 @@
|
||||
* This module currently provides iterative methods to solve problems of the form \c A \c x = \c b, where \c A is a squared matrix, usually very large and sparse.
|
||||
* Those solvers are accessible via the following classes:
|
||||
* - ConjugateGradient for selfadjoint (hermitian) matrices,
|
||||
* - LeastSquaresConjugateGradient for rectangular least-square problems,
|
||||
* - BiCGSTAB for general square matrices.
|
||||
*
|
||||
* These iterative solvers are associated with some preconditioners:
|
||||
* - IdentityPreconditioner - not really useful
|
||||
* - DiagonalPreconditioner - also called JAcobi preconditioner, work very well on diagonal dominant matrices.
|
||||
* - IncompleteILUT - incomplete LU factorization with dual thresholding
|
||||
* - IncompleteLUT - incomplete LU factorization with dual thresholding
|
||||
*
|
||||
* Such problems can also be solved using the direct sparse decomposition modules: SparseCholesky, CholmodSupport, UmfPackSupport, SuperLUSupport.
|
||||
*
|
||||
* \code
|
||||
* #include <Eigen/IterativeLinearSolvers>
|
||||
* \endcode
|
||||
\code
|
||||
#include <Eigen/IterativeLinearSolvers>
|
||||
\endcode
|
||||
*/
|
||||
|
||||
#include "src/IterativeLinearSolvers/SolveWithGuess.h"
|
||||
#include "src/IterativeLinearSolvers/IterativeSolverBase.h"
|
||||
#include "src/IterativeLinearSolvers/BasicPreconditioners.h"
|
||||
#include "src/IterativeLinearSolvers/ConjugateGradient.h"
|
||||
#include "src/IterativeLinearSolvers/LeastSquareConjugateGradient.h"
|
||||
#include "src/IterativeLinearSolvers/BiCGSTAB.h"
|
||||
#include "src/IterativeLinearSolvers/IncompleteLUT.h"
|
||||
|
||||
|
||||
@@ -11,9 +11,9 @@
|
||||
* - \ref SparseQR_Module
|
||||
* - \ref IterativeLinearSolvers_Module
|
||||
*
|
||||
* \code
|
||||
* #include <Eigen/Sparse>
|
||||
* \endcode
|
||||
\code
|
||||
#include <Eigen/Sparse>
|
||||
\endcode
|
||||
*/
|
||||
|
||||
#include "SparseCore"
|
||||
|
||||
@@ -226,6 +226,11 @@ template<typename _MatrixType, int _UpLo> class LDLT
|
||||
#endif
|
||||
|
||||
protected:
|
||||
|
||||
static void check_template_parameters()
|
||||
{
|
||||
EIGEN_STATIC_ASSERT_NON_INTEGER(Scalar);
|
||||
}
|
||||
|
||||
/** \internal
|
||||
* Used to compute and store the Cholesky decomposition A = L D L^* = U^* D U.
|
||||
@@ -424,6 +429,8 @@ template<typename MatrixType> struct LDLT_Traits<MatrixType,Upper>
|
||||
template<typename MatrixType, int _UpLo>
|
||||
LDLT<MatrixType,_UpLo>& LDLT<MatrixType,_UpLo>::compute(const MatrixType& a)
|
||||
{
|
||||
check_template_parameters();
|
||||
|
||||
eigen_assert(a.rows()==a.cols());
|
||||
const Index size = a.rows();
|
||||
|
||||
|
||||
@@ -170,6 +170,12 @@ template<typename _MatrixType, int _UpLo> class LLT
|
||||
#endif
|
||||
|
||||
protected:
|
||||
|
||||
static void check_template_parameters()
|
||||
{
|
||||
EIGEN_STATIC_ASSERT_NON_INTEGER(Scalar);
|
||||
}
|
||||
|
||||
/** \internal
|
||||
* Used to compute and store L
|
||||
* The strict upper part is not used and even not initialized.
|
||||
@@ -377,6 +383,8 @@ template<typename MatrixType> struct LLT_Traits<MatrixType,Upper>
|
||||
template<typename MatrixType, int _UpLo>
|
||||
LLT<MatrixType,_UpLo>& LLT<MatrixType,_UpLo>::compute(const MatrixType& a)
|
||||
{
|
||||
check_template_parameters();
|
||||
|
||||
eigen_assert(a.rows()==a.cols());
|
||||
const Index size = a.rows();
|
||||
m_matrix.resize(size, size);
|
||||
|
||||
@@ -647,11 +647,15 @@ struct evaluator<Map<PlainObjectType, MapOptions, StrideType> >
|
||||
HasNoStride = HasNoInnerStride && HasNoOuterStride,
|
||||
IsAligned = bool(EIGEN_ALIGN) && ((int(MapOptions)&Aligned)==Aligned),
|
||||
IsDynamicSize = PlainObjectType::SizeAtCompileTime==Dynamic,
|
||||
|
||||
// TODO: should check for smaller packet types once we can handle multi-sized packet types
|
||||
AlignBytes = int(packet_traits<Scalar>::size) * sizeof(Scalar),
|
||||
|
||||
KeepsPacketAccess = bool(HasNoInnerStride)
|
||||
&& ( bool(IsDynamicSize)
|
||||
|| HasNoOuterStride
|
||||
|| ( OuterStrideAtCompileTime!=Dynamic
|
||||
&& ((static_cast<int>(sizeof(Scalar))*OuterStrideAtCompileTime)%EIGEN_ALIGN_BYTES)==0 ) ),
|
||||
&& ((static_cast<int>(sizeof(Scalar))*OuterStrideAtCompileTime) % AlignBytes)==0 ) ),
|
||||
Flags0 = evaluator<PlainObjectType>::Flags,
|
||||
Flags1 = IsAligned ? (int(Flags0) | AlignedBit) : (int(Flags0) & ~AlignedBit),
|
||||
Flags2 = (bool(HasNoStride) || bool(PlainObjectType::IsVectorAtCompileTime))
|
||||
@@ -717,7 +721,10 @@ struct evaluator<Block<ArgType, BlockRows, BlockCols, InnerPanel> >
|
||||
&& (InnerStrideAtCompileTime == 1)
|
||||
? PacketAccessBit : 0,
|
||||
|
||||
MaskAlignedBit = (InnerPanel && (OuterStrideAtCompileTime!=Dynamic) && (((OuterStrideAtCompileTime * int(sizeof(Scalar))) % EIGEN_ALIGN_BYTES) == 0)) ? AlignedBit : 0,
|
||||
// TODO: should check for smaller packet types once we can handle multi-sized packet types
|
||||
AlignBytes = int(packet_traits<Scalar>::size) * sizeof(Scalar),
|
||||
|
||||
MaskAlignedBit = (InnerPanel && (OuterStrideAtCompileTime!=Dynamic) && (((OuterStrideAtCompileTime * int(sizeof(Scalar))) % AlignBytes) == 0)) ? AlignedBit : 0,
|
||||
FlagsLinearAccessBit = (RowsAtCompileTime == 1 || ColsAtCompileTime == 1 || (InnerPanel && (evaluator<ArgType>::Flags&LinearAccessBit))) ? LinearAccessBit : 0,
|
||||
FlagsRowMajorBit = XprType::Flags&RowMajorBit,
|
||||
Flags0 = evaluator<ArgType>::Flags & ( (HereditaryBits & ~RowMajorBit) |
|
||||
@@ -825,12 +832,16 @@ struct block_evaluator<ArgType, BlockRows, BlockCols, InnerPanel, /* HasDirectAc
|
||||
typename Block<ArgType, BlockRows, BlockCols, InnerPanel>::PlainObject>
|
||||
{
|
||||
typedef Block<ArgType, BlockRows, BlockCols, InnerPanel> XprType;
|
||||
typedef typename XprType::Scalar Scalar;
|
||||
|
||||
EIGEN_DEVICE_FUNC explicit block_evaluator(const XprType& block)
|
||||
: mapbase_evaluator<XprType, typename XprType::PlainObject>(block)
|
||||
{
|
||||
// TODO: should check for smaller packet types once we can handle multi-sized packet types
|
||||
const int AlignBytes = int(packet_traits<Scalar>::size) * sizeof(Scalar);
|
||||
EIGEN_ONLY_USED_FOR_DEBUG(AlignBytes)
|
||||
// FIXME this should be an internal assertion
|
||||
eigen_assert(EIGEN_IMPLIES(evaluator<XprType>::Flags&AlignedBit, (size_t(block.data()) % EIGEN_ALIGN_BYTES) == 0) && "data is not aligned");
|
||||
eigen_assert(EIGEN_IMPLIES(evaluator<XprType>::Flags&AlignedBit, (size_t(block.data()) % AlignBytes) == 0) && "data is not aligned");
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -34,14 +34,35 @@ void check_static_allocation_size()
|
||||
#endif
|
||||
}
|
||||
|
||||
template<typename T, int Size, typename Packet = typename packet_traits<T>::type,
|
||||
bool Match = bool((Size%unpacket_traits<Packet>::size)==0),
|
||||
bool TryHalf = bool(int(unpacket_traits<Packet>::size) > Size)
|
||||
&& bool(int(unpacket_traits<Packet>::size) > int(unpacket_traits<typename unpacket_traits<Packet>::half>::size)) >
|
||||
struct compute_default_alignment
|
||||
{
|
||||
enum { value = 0 };
|
||||
};
|
||||
|
||||
template<typename T, int Size, typename Packet>
|
||||
struct compute_default_alignment<T, Size, Packet, true, false> // Match
|
||||
{
|
||||
enum { value = sizeof(T) * unpacket_traits<Packet>::size };
|
||||
};
|
||||
|
||||
template<typename T, int Size, typename Packet>
|
||||
struct compute_default_alignment<T, Size, Packet, false, true>
|
||||
{
|
||||
// current packet too large, try with an half-packet
|
||||
enum { value = compute_default_alignment<T, Size, typename unpacket_traits<Packet>::half>::value };
|
||||
};
|
||||
|
||||
/** \internal
|
||||
* Static array. If the MatrixOrArrayOptions require auto-alignment, the array will be automatically aligned:
|
||||
* to 16 bytes boundary if the total size is a multiple of 16 bytes.
|
||||
*/
|
||||
template <typename T, int Size, int MatrixOrArrayOptions,
|
||||
int Alignment = (MatrixOrArrayOptions&DontAlign) ? 0
|
||||
: (((Size*sizeof(T))%EIGEN_ALIGN_BYTES)==0) ? EIGEN_ALIGN_BYTES
|
||||
: 0 >
|
||||
: compute_default_alignment<T,Size>::value >
|
||||
struct plain_array
|
||||
{
|
||||
T array[Size];
|
||||
@@ -81,14 +102,71 @@ struct plain_array
|
||||
#endif
|
||||
|
||||
template <typename T, int Size, int MatrixOrArrayOptions>
|
||||
struct plain_array<T, Size, MatrixOrArrayOptions, EIGEN_ALIGN_BYTES>
|
||||
struct plain_array<T, Size, MatrixOrArrayOptions, 8>
|
||||
{
|
||||
EIGEN_USER_ALIGN_DEFAULT T array[Size];
|
||||
EIGEN_ALIGN_TO_BOUNDARY(8) T array[Size];
|
||||
|
||||
EIGEN_DEVICE_FUNC
|
||||
plain_array()
|
||||
{
|
||||
EIGEN_MAKE_UNALIGNED_ARRAY_ASSERT(EIGEN_ALIGN_BYTES-1);
|
||||
EIGEN_MAKE_UNALIGNED_ARRAY_ASSERT(7);
|
||||
check_static_allocation_size<T,Size>();
|
||||
}
|
||||
|
||||
EIGEN_DEVICE_FUNC
|
||||
plain_array(constructor_without_unaligned_array_assert)
|
||||
{
|
||||
check_static_allocation_size<T,Size>();
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T, int Size, int MatrixOrArrayOptions>
|
||||
struct plain_array<T, Size, MatrixOrArrayOptions, 16>
|
||||
{
|
||||
EIGEN_ALIGN_TO_BOUNDARY(16) T array[Size];
|
||||
|
||||
EIGEN_DEVICE_FUNC
|
||||
plain_array()
|
||||
{
|
||||
EIGEN_MAKE_UNALIGNED_ARRAY_ASSERT(15);
|
||||
check_static_allocation_size<T,Size>();
|
||||
}
|
||||
|
||||
EIGEN_DEVICE_FUNC
|
||||
plain_array(constructor_without_unaligned_array_assert)
|
||||
{
|
||||
check_static_allocation_size<T,Size>();
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T, int Size, int MatrixOrArrayOptions>
|
||||
struct plain_array<T, Size, MatrixOrArrayOptions, 32>
|
||||
{
|
||||
EIGEN_ALIGN_TO_BOUNDARY(32) T array[Size];
|
||||
|
||||
EIGEN_DEVICE_FUNC
|
||||
plain_array()
|
||||
{
|
||||
EIGEN_MAKE_UNALIGNED_ARRAY_ASSERT(31);
|
||||
check_static_allocation_size<T,Size>();
|
||||
}
|
||||
|
||||
EIGEN_DEVICE_FUNC
|
||||
plain_array(constructor_without_unaligned_array_assert)
|
||||
{
|
||||
check_static_allocation_size<T,Size>();
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T, int Size, int MatrixOrArrayOptions>
|
||||
struct plain_array<T, Size, MatrixOrArrayOptions, 64>
|
||||
{
|
||||
EIGEN_ALIGN_TO_BOUNDARY(64) T array[Size];
|
||||
|
||||
EIGEN_DEVICE_FUNC
|
||||
plain_array()
|
||||
{
|
||||
EIGEN_MAKE_UNALIGNED_ARRAY_ASSERT(63);
|
||||
check_static_allocation_size<T,Size>();
|
||||
}
|
||||
|
||||
|
||||
@@ -473,48 +473,48 @@ struct random_default_impl<Scalar, false, false>
|
||||
};
|
||||
|
||||
enum {
|
||||
floor_log2_terminate,
|
||||
floor_log2_move_up,
|
||||
floor_log2_move_down,
|
||||
floor_log2_bogus
|
||||
meta_floor_log2_terminate,
|
||||
meta_floor_log2_move_up,
|
||||
meta_floor_log2_move_down,
|
||||
meta_floor_log2_bogus
|
||||
};
|
||||
|
||||
template<unsigned int n, int lower, int upper> struct floor_log2_selector
|
||||
template<unsigned int n, int lower, int upper> struct meta_floor_log2_selector
|
||||
{
|
||||
enum { middle = (lower + upper) / 2,
|
||||
value = (upper <= lower + 1) ? int(floor_log2_terminate)
|
||||
: (n < (1 << middle)) ? int(floor_log2_move_down)
|
||||
: (n==0) ? int(floor_log2_bogus)
|
||||
: int(floor_log2_move_up)
|
||||
value = (upper <= lower + 1) ? int(meta_floor_log2_terminate)
|
||||
: (n < (1 << middle)) ? int(meta_floor_log2_move_down)
|
||||
: (n==0) ? int(meta_floor_log2_bogus)
|
||||
: int(meta_floor_log2_move_up)
|
||||
};
|
||||
};
|
||||
|
||||
template<unsigned int n,
|
||||
int lower = 0,
|
||||
int upper = sizeof(unsigned int) * CHAR_BIT - 1,
|
||||
int selector = floor_log2_selector<n, lower, upper>::value>
|
||||
struct floor_log2 {};
|
||||
int selector = meta_floor_log2_selector<n, lower, upper>::value>
|
||||
struct meta_floor_log2 {};
|
||||
|
||||
template<unsigned int n, int lower, int upper>
|
||||
struct floor_log2<n, lower, upper, floor_log2_move_down>
|
||||
struct meta_floor_log2<n, lower, upper, meta_floor_log2_move_down>
|
||||
{
|
||||
enum { value = floor_log2<n, lower, floor_log2_selector<n, lower, upper>::middle>::value };
|
||||
enum { value = meta_floor_log2<n, lower, meta_floor_log2_selector<n, lower, upper>::middle>::value };
|
||||
};
|
||||
|
||||
template<unsigned int n, int lower, int upper>
|
||||
struct floor_log2<n, lower, upper, floor_log2_move_up>
|
||||
struct meta_floor_log2<n, lower, upper, meta_floor_log2_move_up>
|
||||
{
|
||||
enum { value = floor_log2<n, floor_log2_selector<n, lower, upper>::middle, upper>::value };
|
||||
enum { value = meta_floor_log2<n, meta_floor_log2_selector<n, lower, upper>::middle, upper>::value };
|
||||
};
|
||||
|
||||
template<unsigned int n, int lower, int upper>
|
||||
struct floor_log2<n, lower, upper, floor_log2_terminate>
|
||||
struct meta_floor_log2<n, lower, upper, meta_floor_log2_terminate>
|
||||
{
|
||||
enum { value = (n >= ((unsigned int)(1) << (lower+1))) ? lower+1 : lower };
|
||||
};
|
||||
|
||||
template<unsigned int n, int lower, int upper>
|
||||
struct floor_log2<n, lower, upper, floor_log2_bogus>
|
||||
struct meta_floor_log2<n, lower, upper, meta_floor_log2_bogus>
|
||||
{
|
||||
// no value, error at compile time
|
||||
};
|
||||
@@ -522,11 +522,24 @@ struct floor_log2<n, lower, upper, floor_log2_bogus>
|
||||
template<typename Scalar>
|
||||
struct random_default_impl<Scalar, false, true>
|
||||
{
|
||||
typedef typename NumTraits<Scalar>::NonInteger NonInteger;
|
||||
|
||||
static inline Scalar run(const Scalar& x, const Scalar& y)
|
||||
{
|
||||
return x + Scalar((NonInteger(y)-x+1) * std::rand() / (RAND_MAX + NonInteger(1)));
|
||||
{
|
||||
using std::max;
|
||||
using std::min;
|
||||
typedef typename conditional<NumTraits<Scalar>::IsSigned,std::ptrdiff_t,std::size_t>::type ScalarX;
|
||||
if(y<x)
|
||||
return x;
|
||||
std::size_t range = ScalarX(y)-ScalarX(x);
|
||||
std::size_t offset = 0;
|
||||
// rejection sampling
|
||||
std::size_t divisor = (range+RAND_MAX-1)/(range+1);
|
||||
std::size_t multiplier = (range+RAND_MAX-1)/std::size_t(RAND_MAX);
|
||||
|
||||
do {
|
||||
offset = ( (std::size_t(std::rand()) * multiplier) / divisor );
|
||||
} while (offset > range);
|
||||
|
||||
return Scalar(ScalarX(x) + offset);
|
||||
}
|
||||
|
||||
static inline Scalar run()
|
||||
@@ -534,7 +547,7 @@ struct random_default_impl<Scalar, false, true>
|
||||
#ifdef EIGEN_MAKING_DOCS
|
||||
return run(Scalar(NumTraits<Scalar>::IsSigned ? -10 : 0), Scalar(10));
|
||||
#else
|
||||
enum { rand_bits = floor_log2<(unsigned int)(RAND_MAX)+1>::value,
|
||||
enum { rand_bits = meta_floor_log2<(unsigned int)(RAND_MAX)+1>::value,
|
||||
scalar_bits = sizeof(Scalar) * CHAR_BIT,
|
||||
shift = EIGEN_PLAIN_ENUM_MAX(0, int(rand_bits) - int(scalar_bits)),
|
||||
offset = NumTraits<Scalar>::IsSigned ? (1 << (EIGEN_PLAIN_ENUM_MIN(rand_bits,scalar_bits)-1)) : 0
|
||||
|
||||
@@ -105,7 +105,8 @@ struct traits<Ref<_PlainObjectType, _Options, _StrideType> >
|
||||
OuterStrideMatch = Derived::IsVectorAtCompileTime
|
||||
|| int(StrideType::OuterStrideAtCompileTime)==int(Dynamic) || int(StrideType::OuterStrideAtCompileTime)==int(Derived::OuterStrideAtCompileTime),
|
||||
AlignmentMatch = (_Options!=Aligned) || ((PlainObjectType::Flags&AlignedBit)==0) || ((traits<Derived>::Flags&AlignedBit)==AlignedBit),
|
||||
MatchAtCompileTime = HasDirectAccess && StorageOrderMatch && InnerStrideMatch && OuterStrideMatch && AlignmentMatch
|
||||
ScalarTypeMatch = internal::is_same<typename PlainObjectType::Scalar, typename Derived::Scalar>::value,
|
||||
MatchAtCompileTime = HasDirectAccess && StorageOrderMatch && InnerStrideMatch && OuterStrideMatch && AlignmentMatch && ScalarTypeMatch
|
||||
};
|
||||
typedef typename internal::conditional<MatchAtCompileTime,internal::true_type,internal::false_type>::type type;
|
||||
};
|
||||
@@ -184,9 +185,11 @@ protected:
|
||||
template<typename PlainObjectType, int Options, typename StrideType> class Ref
|
||||
: public RefBase<Ref<PlainObjectType, Options, StrideType> >
|
||||
{
|
||||
private:
|
||||
typedef internal::traits<Ref> Traits;
|
||||
template<typename Derived>
|
||||
EIGEN_DEVICE_FUNC inline Ref(const PlainObjectBase<Derived>& expr);
|
||||
EIGEN_DEVICE_FUNC inline Ref(const PlainObjectBase<Derived>& expr,
|
||||
typename internal::enable_if<bool(Traits::template match<Derived>::MatchAtCompileTime),Derived>::type* = 0);
|
||||
public:
|
||||
|
||||
typedef RefBase<Ref> Base;
|
||||
@@ -195,13 +198,15 @@ template<typename PlainObjectType, int Options, typename StrideType> class Ref
|
||||
|
||||
#ifndef EIGEN_PARSED_BY_DOXYGEN
|
||||
template<typename Derived>
|
||||
EIGEN_DEVICE_FUNC inline Ref(PlainObjectBase<Derived>& expr)
|
||||
EIGEN_DEVICE_FUNC inline Ref(PlainObjectBase<Derived>& expr,
|
||||
typename internal::enable_if<bool(Traits::template match<Derived>::MatchAtCompileTime),Derived>::type* = 0)
|
||||
{
|
||||
EIGEN_STATIC_ASSERT(bool(Traits::template match<Derived>::MatchAtCompileTime), STORAGE_LAYOUT_DOES_NOT_MATCH);
|
||||
Base::construct(expr.derived());
|
||||
}
|
||||
template<typename Derived>
|
||||
EIGEN_DEVICE_FUNC inline Ref(const DenseBase<Derived>& expr)
|
||||
EIGEN_DEVICE_FUNC inline Ref(const DenseBase<Derived>& expr,
|
||||
typename internal::enable_if<bool(Traits::template match<Derived>::MatchAtCompileTime),Derived>::type* = 0)
|
||||
#else
|
||||
template<typename Derived>
|
||||
inline Ref(DenseBase<Derived>& expr)
|
||||
@@ -228,7 +233,8 @@ template<typename TPlainObjectType, int Options, typename StrideType> class Ref<
|
||||
EIGEN_DENSE_PUBLIC_INTERFACE(Ref)
|
||||
|
||||
template<typename Derived>
|
||||
EIGEN_DEVICE_FUNC inline Ref(const DenseBase<Derived>& expr)
|
||||
EIGEN_DEVICE_FUNC inline Ref(const DenseBase<Derived>& expr,
|
||||
typename internal::enable_if<bool(Traits::template match<Derived>::ScalarTypeMatch),Derived>::type* = 0)
|
||||
{
|
||||
// std::cout << match_helper<Derived>::HasDirectAccess << "," << match_helper<Derived>::OuterStrideMatch << "," << match_helper<Derived>::InnerStrideMatch << "\n";
|
||||
// std::cout << int(StrideType::OuterStrideAtCompileTime) << " - " << int(Derived::OuterStrideAtCompileTime) << "\n";
|
||||
|
||||
@@ -197,21 +197,21 @@ EIGEN_DEVICE_FUNC EIGEN_ALWAYS_INLINE double2 ploadt_ro<double2, Unaligned>(cons
|
||||
}
|
||||
#endif
|
||||
|
||||
template<> EIGEN_DEVICE_FUNC inline float4 pgather<float, float4>(const float* from, int stride) {
|
||||
template<> EIGEN_DEVICE_FUNC inline float4 pgather<float, float4>(const float* from, Index stride) {
|
||||
return make_float4(from[0*stride], from[1*stride], from[2*stride], from[3*stride]);
|
||||
}
|
||||
|
||||
template<> EIGEN_DEVICE_FUNC inline double2 pgather<double, double2>(const double* from, int stride) {
|
||||
template<> EIGEN_DEVICE_FUNC inline double2 pgather<double, double2>(const double* from, Index stride) {
|
||||
return make_double2(from[0*stride], from[1*stride]);
|
||||
}
|
||||
|
||||
template<> EIGEN_DEVICE_FUNC inline void pscatter<float, float4>(float* to, const float4& from, int stride) {
|
||||
template<> EIGEN_DEVICE_FUNC inline void pscatter<float, float4>(float* to, const float4& from, Index stride) {
|
||||
to[stride*0] = from.x;
|
||||
to[stride*1] = from.y;
|
||||
to[stride*2] = from.z;
|
||||
to[stride*3] = from.w;
|
||||
}
|
||||
template<> EIGEN_DEVICE_FUNC inline void pscatter<double, double2>(double* to, const double2& from, int stride) {
|
||||
template<> EIGEN_DEVICE_FUNC inline void pscatter<double, double2>(double* to, const double2& from, Index stride) {
|
||||
to[stride*0] = from.x;
|
||||
to[stride*1] = from.y;
|
||||
}
|
||||
@@ -245,14 +245,14 @@ template<> EIGEN_DEVICE_FUNC inline double predux_min<double2>(const double2& a)
|
||||
}
|
||||
|
||||
template<> EIGEN_DEVICE_FUNC inline float4 pabs<float4>(const float4& a) {
|
||||
return make_float4(fabs(a.x), fabs(a.y), fabs(a.z), fabs(a.w));
|
||||
return make_float4(fabsf(a.x), fabsf(a.y), fabsf(a.z), fabsf(a.w));
|
||||
}
|
||||
template<> EIGEN_DEVICE_FUNC inline double2 pabs<double2>(const double2& a) {
|
||||
return make_double2(abs(a.x), abs(a.y));
|
||||
return make_double2(fabs(a.x), fabs(a.y));
|
||||
}
|
||||
|
||||
|
||||
template<> EIGEN_DEVICE_FUNC inline void
|
||||
EIGEN_DEVICE_FUNC inline void
|
||||
ptranspose(PacketBlock<float4,4>& kernel) {
|
||||
double tmp = kernel.packet[0].y;
|
||||
kernel.packet[0].y = kernel.packet[1].x;
|
||||
@@ -279,7 +279,7 @@ ptranspose(PacketBlock<float4,4>& kernel) {
|
||||
kernel.packet[3].z = tmp;
|
||||
}
|
||||
|
||||
template<> EIGEN_DEVICE_FUNC inline void
|
||||
EIGEN_DEVICE_FUNC inline void
|
||||
ptranspose(PacketBlock<double2,2>& kernel) {
|
||||
double tmp = kernel.packet[0].y;
|
||||
kernel.packet[0].y = kernel.packet[1].x;
|
||||
|
||||
110
Eigen/src/Core/arch/NEON/BlockingSizesLookupTables.h
Normal file
110
Eigen/src/Core/arch/NEON/BlockingSizesLookupTables.h
Normal file
@@ -0,0 +1,110 @@
|
||||
// This file is part of Eigen, a lightweight C++ template library
|
||||
// for linear algebra.
|
||||
//
|
||||
// Copyright (C) 2015 Benoit Jacob <benoitjacob@google.com>
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the Mozilla
|
||||
// Public License v. 2.0. If a copy of the MPL was not distributed
|
||||
// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
#ifndef EIGEN_NEON_BLOCKING_SIZES_LOOKUP_TABLES_H
|
||||
#define EIGEN_NEON_BLOCKING_SIZES_LOOKUP_TABLES_H
|
||||
|
||||
namespace Eigen {
|
||||
namespace internal {
|
||||
|
||||
/* The following lookup table was generated from measurements on a Nexus 5,
|
||||
* which has a Qualcomm Krait 400 CPU. This is very representative of current
|
||||
* 32bit (ARMv7) Android devices. On the other hand, I don't know how
|
||||
* representative that is outside of these conditions. Accordingly,
|
||||
* let's only use this lookup table on ARM 32bit on Android for now.
|
||||
*
|
||||
* Measurements were single-threaded, with Scalar=float, compiled with
|
||||
* -mfpu=neon-vfpv4, so the pmadd instruction used was VFMA.F32.
|
||||
*
|
||||
* The device was cooled, allowing it to run a the max clock speed throughout.
|
||||
* This may not be representative of real-world thermal conditions.
|
||||
*
|
||||
* The benchmark attempted to flush caches to test cold-cache performance.
|
||||
*/
|
||||
#if EIGEN_ARCH_ARM && EIGEN_OS_ANDROID
|
||||
template<>
|
||||
struct BlockingSizesLookupTable<float, float> {
|
||||
static const size_t BaseSize = 16;
|
||||
static const size_t NumSizes = 8;
|
||||
static const unsigned short* Data() {
|
||||
static const unsigned short data[512] = {
|
||||
0x444, 0x445, 0x446, 0x447, 0x448, 0x449, 0x447, 0x447,
|
||||
0x454, 0x455, 0x456, 0x457, 0x458, 0x459, 0x45a, 0x456,
|
||||
0x464, 0x465, 0x466, 0x467, 0x468, 0x469, 0x46a, 0x467,
|
||||
0x474, 0x475, 0x476, 0x467, 0x478, 0x479, 0x476, 0x478,
|
||||
0x474, 0x475, 0x476, 0x477, 0x478, 0x479, 0x476, 0x476,
|
||||
0x474, 0x475, 0x476, 0x477, 0x478, 0x479, 0x496, 0x488,
|
||||
0x474, 0x475, 0x476, 0x4a6, 0x496, 0x496, 0x495, 0x4a6,
|
||||
0x474, 0x475, 0x466, 0x4a6, 0x497, 0x4a5, 0x496, 0x4a5,
|
||||
0x544, 0x545, 0x546, 0x547, 0x548, 0x549, 0x54a, 0x54b,
|
||||
0x554, 0x555, 0x556, 0x557, 0x558, 0x559, 0x55a, 0x55b,
|
||||
0x564, 0x565, 0x566, 0x567, 0x568, 0x569, 0x56a, 0x56b,
|
||||
0x564, 0x565, 0x566, 0x567, 0x568, 0x569, 0x56a, 0x576,
|
||||
0x564, 0x565, 0x566, 0x567, 0x568, 0x569, 0x56a, 0x587,
|
||||
0x564, 0x565, 0x566, 0x567, 0x596, 0x596, 0x596, 0x597,
|
||||
0x574, 0x565, 0x566, 0x596, 0x596, 0x5a6, 0x5a6, 0x5a6,
|
||||
0x564, 0x565, 0x5a6, 0x596, 0x5a6, 0x5a6, 0x5a6, 0x5a6,
|
||||
0x644, 0x645, 0x646, 0x647, 0x648, 0x649, 0x64a, 0x64b,
|
||||
0x644, 0x655, 0x656, 0x657, 0x658, 0x659, 0x65a, 0x65b,
|
||||
0x664, 0x665, 0x666, 0x667, 0x668, 0x669, 0x65a, 0x667,
|
||||
0x654, 0x665, 0x676, 0x677, 0x678, 0x679, 0x67a, 0x675,
|
||||
0x684, 0x675, 0x686, 0x687, 0x688, 0x688, 0x687, 0x686,
|
||||
0x664, 0x685, 0x666, 0x677, 0x697, 0x696, 0x697, 0x697,
|
||||
0x664, 0x665, 0x696, 0x696, 0x685, 0x6a6, 0x696, 0x696,
|
||||
0x664, 0x675, 0x686, 0x696, 0x6a6, 0x696, 0x696, 0x696,
|
||||
0x744, 0x745, 0x746, 0x747, 0x748, 0x749, 0x74a, 0x747,
|
||||
0x754, 0x755, 0x756, 0x757, 0x758, 0x759, 0x75a, 0x757,
|
||||
0x764, 0x765, 0x756, 0x767, 0x768, 0x759, 0x75a, 0x766,
|
||||
0x744, 0x755, 0x766, 0x777, 0x768, 0x759, 0x778, 0x777,
|
||||
0x744, 0x745, 0x766, 0x777, 0x788, 0x786, 0x786, 0x788,
|
||||
0x754, 0x755, 0x766, 0x787, 0x796, 0x796, 0x787, 0x796,
|
||||
0x684, 0x695, 0x696, 0x6a6, 0x795, 0x786, 0x795, 0x796,
|
||||
0x684, 0x695, 0x696, 0x795, 0x786, 0x796, 0x795, 0x796,
|
||||
0x844, 0x845, 0x846, 0x847, 0x848, 0x849, 0x848, 0x848,
|
||||
0x844, 0x855, 0x846, 0x847, 0x848, 0x849, 0x855, 0x857,
|
||||
0x844, 0x845, 0x846, 0x857, 0x848, 0x859, 0x866, 0x865,
|
||||
0x844, 0x855, 0x846, 0x847, 0x878, 0x859, 0x877, 0x877,
|
||||
0x844, 0x855, 0x846, 0x867, 0x886, 0x887, 0x885, 0x886,
|
||||
0x784, 0x785, 0x786, 0x877, 0x897, 0x885, 0x896, 0x896,
|
||||
0x684, 0x695, 0x686, 0x886, 0x885, 0x885, 0x886, 0x896,
|
||||
0x694, 0x6a5, 0x6a6, 0x885, 0x885, 0x886, 0x896, 0x896,
|
||||
0x944, 0x945, 0x946, 0x947, 0x948, 0x847, 0x847, 0x848,
|
||||
0x954, 0x855, 0x856, 0x947, 0x858, 0x857, 0x858, 0x858,
|
||||
0x944, 0x945, 0x946, 0x867, 0x948, 0x866, 0x867, 0x867,
|
||||
0x944, 0x975, 0x976, 0x877, 0x877, 0x877, 0x877, 0x877,
|
||||
0x784, 0x785, 0x886, 0x887, 0x886, 0x887, 0x887, 0x887,
|
||||
0x784, 0x785, 0x786, 0x796, 0x887, 0x897, 0x896, 0x896,
|
||||
0x684, 0x695, 0x6a6, 0x886, 0x886, 0x896, 0x896, 0x896,
|
||||
0x6a4, 0x6a5, 0x696, 0x896, 0x886, 0x896, 0x896, 0x896,
|
||||
0xa44, 0xa45, 0xa46, 0xa47, 0x847, 0x848, 0x847, 0x848,
|
||||
0xa44, 0xa45, 0x856, 0x857, 0x857, 0x857, 0x857, 0x857,
|
||||
0xa44, 0xa65, 0x866, 0x867, 0x867, 0x867, 0x867, 0x867,
|
||||
0x774, 0x875, 0x876, 0x877, 0x877, 0x877, 0x877, 0x877,
|
||||
0x784, 0x785, 0x886, 0x887, 0x887, 0x887, 0x887, 0x887,
|
||||
0x784, 0x785, 0x786, 0x787, 0x887, 0x896, 0x897, 0x897,
|
||||
0x684, 0x6a5, 0x696, 0x886, 0x886, 0x896, 0x896, 0x896,
|
||||
0x684, 0x6a5, 0x6a5, 0x886, 0x886, 0x896, 0x896, 0x896,
|
||||
0xb44, 0x845, 0x846, 0x847, 0x847, 0x945, 0x846, 0x946,
|
||||
0xb54, 0x855, 0x856, 0x857, 0x857, 0x856, 0x857, 0x856,
|
||||
0x864, 0x865, 0x866, 0x867, 0x867, 0x866, 0x866, 0x867,
|
||||
0x864, 0x875, 0x876, 0x877, 0x877, 0x877, 0x877, 0x877,
|
||||
0x784, 0x885, 0x886, 0x787, 0x887, 0x887, 0x887, 0x887,
|
||||
0x784, 0x785, 0x786, 0x796, 0x886, 0x897, 0x897, 0x897,
|
||||
0x684, 0x695, 0x696, 0x886, 0x896, 0x896, 0x896, 0x896,
|
||||
0x684, 0x685, 0x696, 0xb57, 0x896, 0x896, 0x896, 0x896
|
||||
};
|
||||
return data;
|
||||
}
|
||||
};
|
||||
#endif
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#endif // EIGEN_NEON_BLOCKING_SIZES_LOOKUP_TABLES_H
|
||||
@@ -272,7 +272,7 @@ ptranspose(PacketBlock<Packet2cf,2>& kernel) {
|
||||
}
|
||||
|
||||
//---------- double ----------
|
||||
#if EIGEN_ARCH_ARM64
|
||||
#if EIGEN_ARCH_ARM64 && !EIGEN_APPLE_DOUBLE_NEON_BUG
|
||||
|
||||
static uint64x2_t p2ul_CONJ_XOR = EIGEN_INIT_NEON_PACKET2(0x0, 0x8000000000000000);
|
||||
|
||||
|
||||
@@ -518,7 +518,19 @@ ptranspose(PacketBlock<Packet4i,4>& kernel) {
|
||||
}
|
||||
|
||||
//---------- double ----------
|
||||
#if EIGEN_ARCH_ARM64
|
||||
|
||||
// Clang 3.5 in the iOS toolchain has an ICE triggered by NEON intrisics for double.
|
||||
// Confirmed at least with __apple_build_version__ = 6000054.
|
||||
#ifdef __apple_build_version__
|
||||
// Let's hope that by the time __apple_build_version__ hits the 601* range, the bug will be fixed.
|
||||
// https://gist.github.com/yamaya/2924292 suggests that the 3 first digits are only updated with
|
||||
// major toolchain updates.
|
||||
#define EIGEN_APPLE_DOUBLE_NEON_BUG (__apple_build_version__ < 6010000)
|
||||
#else
|
||||
#define EIGEN_APPLE_DOUBLE_NEON_BUG 0
|
||||
#endif
|
||||
|
||||
#if EIGEN_ARCH_ARM64 && !EIGEN_APPLE_DOUBLE_NEON_BUG
|
||||
|
||||
#if (EIGEN_COMP_GNUC_STRICT && defined(__ANDROID__)) || defined(__apple_build_version__)
|
||||
// Bug 907: workaround missing declarations of the following two functions in the ADK
|
||||
@@ -541,12 +553,12 @@ typedef float64x1_t Packet1d;
|
||||
template<> struct packet_traits<double> : default_packet_traits
|
||||
{
|
||||
typedef Packet2d type;
|
||||
typedef Packet1d half;
|
||||
typedef Packet2d half;
|
||||
enum {
|
||||
Vectorizable = 1,
|
||||
AlignedOnScalar = 1,
|
||||
size = 2,
|
||||
HasHalfPacket=1,
|
||||
HasHalfPacket=0,
|
||||
|
||||
HasDiv = 1,
|
||||
// FIXME check the Has*
|
||||
|
||||
@@ -55,6 +55,34 @@ struct functor_traits<scalar_abs_op<Scalar> >
|
||||
};
|
||||
};
|
||||
|
||||
/** \internal
|
||||
* \brief Template functor to compute the score of a scalar, to chose a pivot
|
||||
*
|
||||
* \sa class CwiseUnaryOp
|
||||
*/
|
||||
template<typename Scalar> struct scalar_score_coeff_op : scalar_abs_op<Scalar>
|
||||
{
|
||||
typedef void Score_is_abs;
|
||||
};
|
||||
template<typename Scalar>
|
||||
struct functor_traits<scalar_score_coeff_op<Scalar> > : functor_traits<scalar_abs_op<Scalar> > {};
|
||||
|
||||
/* Avoid recomputing abs when we know the score and they are the same. Not a true Eigen functor. */
|
||||
template<typename Scalar, typename=void> struct abs_knowing_score
|
||||
{
|
||||
EIGEN_EMPTY_STRUCT_CTOR(abs_knowing_score)
|
||||
typedef typename NumTraits<Scalar>::Real result_type;
|
||||
template<typename Score>
|
||||
EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const result_type operator() (const Scalar& a, const Score&) const { using std::abs; return abs(a); }
|
||||
};
|
||||
template<typename Scalar> struct abs_knowing_score<Scalar, typename scalar_score_coeff_op<Scalar>::Score_is_abs>
|
||||
{
|
||||
EIGEN_EMPTY_STRUCT_CTOR(abs_knowing_score)
|
||||
typedef typename NumTraits<Scalar>::Real result_type;
|
||||
template<typename Scal>
|
||||
EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const result_type operator() (const Scal&, const result_type& a) const { return a; }
|
||||
};
|
||||
|
||||
/** \internal
|
||||
* \brief Template functor to compute the squared absolute value of a scalar
|
||||
*
|
||||
|
||||
@@ -25,21 +25,31 @@ inline std::ptrdiff_t manage_caching_sizes_helper(std::ptrdiff_t a, std::ptrdiff
|
||||
return a<=0 ? b : a;
|
||||
}
|
||||
|
||||
#if EIGEN_ARCH_i386_OR_x86_64
|
||||
const std::ptrdiff_t defaultL1CacheSize = 32*1024;
|
||||
const std::ptrdiff_t defaultL2CacheSize = 256*1024;
|
||||
const std::ptrdiff_t defaultL3CacheSize = 2*1024*1024;
|
||||
#else
|
||||
const std::ptrdiff_t defaultL1CacheSize = 16*1024;
|
||||
const std::ptrdiff_t defaultL2CacheSize = 512*1024;
|
||||
const std::ptrdiff_t defaultL3CacheSize = 512*1024;
|
||||
#endif
|
||||
|
||||
/** \internal */
|
||||
inline void manage_caching_sizes(Action action, std::ptrdiff_t* l1, std::ptrdiff_t* l2, std::ptrdiff_t* l3)
|
||||
{
|
||||
static bool m_cache_sizes_initialized = false;
|
||||
static std::ptrdiff_t m_l1CacheSize = 32*1024;
|
||||
static std::ptrdiff_t m_l2CacheSize = 256*1024;
|
||||
static std::ptrdiff_t m_l3CacheSize = 2*1024*1024;
|
||||
static std::ptrdiff_t m_l1CacheSize = 0;
|
||||
static std::ptrdiff_t m_l2CacheSize = 0;
|
||||
static std::ptrdiff_t m_l3CacheSize = 0;
|
||||
|
||||
if(!m_cache_sizes_initialized)
|
||||
{
|
||||
int l1CacheSize, l2CacheSize, l3CacheSize;
|
||||
queryCacheSizes(l1CacheSize, l2CacheSize, l3CacheSize);
|
||||
m_l1CacheSize = manage_caching_sizes_helper(l1CacheSize, 8*1024);
|
||||
m_l2CacheSize = manage_caching_sizes_helper(l2CacheSize, 256*1024);
|
||||
m_l3CacheSize = manage_caching_sizes_helper(l3CacheSize, 8*1024*1024);
|
||||
m_l1CacheSize = manage_caching_sizes_helper(l1CacheSize, defaultL1CacheSize);
|
||||
m_l2CacheSize = manage_caching_sizes_helper(l2CacheSize, defaultL2CacheSize);
|
||||
m_l3CacheSize = manage_caching_sizes_helper(l3CacheSize, defaultL3CacheSize);
|
||||
m_cache_sizes_initialized = true;
|
||||
}
|
||||
|
||||
@@ -64,43 +74,23 @@ inline void manage_caching_sizes(Action action, std::ptrdiff_t* l1, std::ptrdiff
|
||||
}
|
||||
}
|
||||
|
||||
/** \brief Computes the blocking parameters for a m x k times k x n matrix product
|
||||
*
|
||||
* \param[in,out] k Input: the third dimension of the product. Output: the blocking size along the same dimension.
|
||||
* \param[in,out] m Input: the number of rows of the left hand side. Output: the blocking size along the same dimension.
|
||||
* \param[in,out] n Input: the number of columns of the right hand side. Output: the blocking size along the same dimension.
|
||||
*
|
||||
* Given a m x k times k x n matrix product of scalar types \c LhsScalar and \c RhsScalar,
|
||||
* this function computes the blocking size parameters along the respective dimensions
|
||||
* for matrix products and related algorithms. The blocking sizes depends on various
|
||||
* parameters:
|
||||
* - the L1 and L2 cache sizes,
|
||||
* - the register level blocking sizes defined by gebp_traits,
|
||||
* - the number of scalars that fit into a packet (when vectorization is enabled).
|
||||
*
|
||||
* \sa setCpuCacheSizes */
|
||||
/* Helper for computeProductBlockingSizes.
|
||||
*
|
||||
* Given a m x k times k x n matrix product of scalar types \c LhsScalar and \c RhsScalar,
|
||||
* this function computes the blocking size parameters along the respective dimensions
|
||||
* for matrix products and related algorithms. The blocking sizes depends on various
|
||||
* parameters:
|
||||
* - the L1 and L2 cache sizes,
|
||||
* - the register level blocking sizes defined by gebp_traits,
|
||||
* - the number of scalars that fit into a packet (when vectorization is enabled).
|
||||
*
|
||||
* \sa setCpuCacheSizes */
|
||||
|
||||
template<typename LhsScalar, typename RhsScalar, int KcFactor>
|
||||
void computeProductBlockingSizes(Index& k, Index& m, Index& n, Index num_threads = 1)
|
||||
void evaluateProductBlockingSizesHeuristic(Index& k, Index& m, Index& n, Index num_threads = 1)
|
||||
{
|
||||
typedef gebp_traits<LhsScalar,RhsScalar> Traits;
|
||||
|
||||
#ifdef EIGEN_TEST_SPECIFIC_BLOCKING_SIZES
|
||||
EIGEN_UNUSED_VARIABLE(num_threads);
|
||||
enum {
|
||||
kr = 8,
|
||||
mr = Traits::mr,
|
||||
nr = Traits::nr
|
||||
};
|
||||
k = std::min<Index>(k, EIGEN_TEST_SPECIFIC_BLOCKING_SIZE_K);
|
||||
if (k > kr) k -= k % kr;
|
||||
m = std::min<Index>(m, EIGEN_TEST_SPECIFIC_BLOCKING_SIZE_M);
|
||||
if (m > mr) m -= m % mr;
|
||||
n = std::min<Index>(n, EIGEN_TEST_SPECIFIC_BLOCKING_SIZE_N);
|
||||
if (n > nr) n -= n % nr;
|
||||
return;
|
||||
#endif
|
||||
|
||||
// Explanations:
|
||||
// Let's recall that the product algorithms form mc x kc vertical panels A' on the lhs and
|
||||
// kc x nc blocks B' on the rhs. B' has to fit into L2/L3 cache. Moreover, A' is processed
|
||||
@@ -155,7 +145,7 @@ void computeProductBlockingSizes(Index& k, Index& m, Index& n, Index num_threads
|
||||
// In unit tests we do not want to use extra large matrices,
|
||||
// so we reduce the cache size to check the blocking strategy is not flawed
|
||||
#ifdef EIGEN_DEBUG_SMALL_PRODUCT_BLOCKS
|
||||
l1 = 4*1024;
|
||||
l1 = 9*1024;
|
||||
l2 = 32*1024;
|
||||
l3 = 512*1024;
|
||||
#endif
|
||||
@@ -164,7 +154,7 @@ void computeProductBlockingSizes(Index& k, Index& m, Index& n, Index num_threads
|
||||
// Perhaps it would make more sense to consider k*n*m??
|
||||
// Note that for very tiny problem, this function should be bypassed anyway
|
||||
// because we use the coefficient-based implementation for them.
|
||||
if(std::max(k,std::max(m,n))<48)
|
||||
if((std::max)(k,(std::max)(m,n))<48)
|
||||
return;
|
||||
|
||||
typedef typename Traits::ResScalar ResScalar;
|
||||
@@ -211,8 +201,22 @@ void computeProductBlockingSizes(Index& k, Index& m, Index& n, Index num_threads
|
||||
// Here, nc is chosen such that a block of kc x nc of the rhs fit within half of L2.
|
||||
// The second half is implicitly reserved to access the result and lhs coefficients.
|
||||
// When k<max_kc, then nc can arbitrarily growth. In practice, it seems to be fruitful
|
||||
// to limit this growth: we bound nc to growth by a factor x1.5, leading to:
|
||||
const Index max_nc = (3*actual_l2)/(2*2*max_kc*sizeof(RhsScalar));
|
||||
// to limit this growth: we bound nc to growth by a factor x1.5.
|
||||
// However, if the entire lhs block fit within L1, then we are not going to block on the rows at all,
|
||||
// and it becomes fruitful to keep the packed rhs blocks in L1 if there is enough remaining space.
|
||||
Index max_nc;
|
||||
const Index lhs_bytes = m * k * sizeof(LhsScalar);
|
||||
const Index remaining_l1 = l1- k_sub - lhs_bytes;
|
||||
if(remaining_l1 >= Index(Traits::nr*sizeof(RhsScalar))*k)
|
||||
{
|
||||
// L1 blocking
|
||||
max_nc = remaining_l1 / (k*sizeof(RhsScalar));
|
||||
}
|
||||
else
|
||||
{
|
||||
// L2 blocking
|
||||
max_nc = (3*actual_l2)/(2*2*max_kc*sizeof(RhsScalar));
|
||||
}
|
||||
// WARNING Below, we assume that Traits::nr is a power of two.
|
||||
Index nc = std::min<Index>(actual_l2/(2*k*sizeof(RhsScalar)), max_nc) & (~(Traits::nr-1));
|
||||
if(n>nc)
|
||||
@@ -228,6 +232,7 @@ void computeProductBlockingSizes(Index& k, Index& m, Index& n, Index num_threads
|
||||
{
|
||||
// So far, no blocking at all, i.e., kc==k, and nc==n.
|
||||
// In this case, let's perform a blocking over the rows such that the packed lhs data is kept in cache L1/L2
|
||||
// TODO: part of this blocking strategy is now implemented within the kernel itself, so the L1-based heuristic here should be obsolete.
|
||||
Index problem_size = k*n*sizeof(LhsScalar);
|
||||
Index actual_lm = actual_l2;
|
||||
Index max_mc = m;
|
||||
@@ -254,6 +259,60 @@ void computeProductBlockingSizes(Index& k, Index& m, Index& n, Index num_threads
|
||||
}
|
||||
}
|
||||
|
||||
inline bool useSpecificBlockingSizes(Index& k, Index& m, Index& n)
|
||||
{
|
||||
#ifdef EIGEN_TEST_SPECIFIC_BLOCKING_SIZES
|
||||
if (EIGEN_TEST_SPECIFIC_BLOCKING_SIZES) {
|
||||
k = std::min<Index>(k, EIGEN_TEST_SPECIFIC_BLOCKING_SIZE_K);
|
||||
m = std::min<Index>(m, EIGEN_TEST_SPECIFIC_BLOCKING_SIZE_M);
|
||||
n = std::min<Index>(n, EIGEN_TEST_SPECIFIC_BLOCKING_SIZE_N);
|
||||
return true;
|
||||
}
|
||||
#else
|
||||
EIGEN_UNUSED_VARIABLE(k)
|
||||
EIGEN_UNUSED_VARIABLE(m)
|
||||
EIGEN_UNUSED_VARIABLE(n)
|
||||
#endif
|
||||
return false;
|
||||
}
|
||||
|
||||
/** \brief Computes the blocking parameters for a m x k times k x n matrix product
|
||||
*
|
||||
* \param[in,out] k Input: the third dimension of the product. Output: the blocking size along the same dimension.
|
||||
* \param[in,out] m Input: the number of rows of the left hand side. Output: the blocking size along the same dimension.
|
||||
* \param[in,out] n Input: the number of columns of the right hand side. Output: the blocking size along the same dimension.
|
||||
*
|
||||
* Given a m x k times k x n matrix product of scalar types \c LhsScalar and \c RhsScalar,
|
||||
* this function computes the blocking size parameters along the respective dimensions
|
||||
* for matrix products and related algorithms.
|
||||
*
|
||||
* The blocking size parameters may be evaluated:
|
||||
* - either by a heuristic based on cache sizes;
|
||||
* - or using a precomputed lookup table;
|
||||
* - or using fixed prescribed values (for testing purposes).
|
||||
*
|
||||
* \sa setCpuCacheSizes */
|
||||
|
||||
template<typename LhsScalar, typename RhsScalar, int KcFactor>
|
||||
void computeProductBlockingSizes(Index& k, Index& m, Index& n, Index num_threads = 1)
|
||||
{
|
||||
if (!useSpecificBlockingSizes(k, m, n)) {
|
||||
if (!lookupBlockingSizesFromTable<LhsScalar, RhsScalar>(k, m, n, num_threads)) {
|
||||
evaluateProductBlockingSizesHeuristic<LhsScalar, RhsScalar, KcFactor>(k, m, n, num_threads);
|
||||
}
|
||||
}
|
||||
|
||||
typedef gebp_traits<LhsScalar,RhsScalar> Traits;
|
||||
enum {
|
||||
kr = 8,
|
||||
mr = Traits::mr,
|
||||
nr = Traits::nr
|
||||
};
|
||||
if (k > kr) k -= k % kr;
|
||||
if (m > mr) m -= m % mr;
|
||||
if (n > nr) n -= n % nr;
|
||||
}
|
||||
|
||||
template<typename LhsScalar, typename RhsScalar>
|
||||
inline void computeProductBlockingSizes(Index& k, Index& m, Index& n, Index num_threads = 1)
|
||||
{
|
||||
@@ -949,19 +1008,31 @@ void gebp_kernel<LhsScalar,RhsScalar,Index,DataMapper,mr,nr,ConjugateLhs,Conjuga
|
||||
// This corresponds to 3*LhsProgress x nr register blocks.
|
||||
// Usually, make sense only with FMA
|
||||
if(mr>=3*Traits::LhsProgress)
|
||||
{
|
||||
{
|
||||
PossiblyRotatingKernelHelper<gebp_kernel> possiblyRotatingKernelHelper(traits);
|
||||
|
||||
// loops on each largest micro horizontal panel of lhs (3*Traits::LhsProgress x depth)
|
||||
for(Index i=0; i<peeled_mc3; i+=3*Traits::LhsProgress)
|
||||
|
||||
// Here, the general idea is to loop on each largest micro horizontal panel of the lhs (3*Traits::LhsProgress x depth)
|
||||
// and on each largest micro vertical panel of the rhs (depth * nr).
|
||||
// Blocking sizes, i.e., 'depth' has been computed so that the micro horizontal panel of the lhs fit in L1.
|
||||
// However, if depth is too small, we can extend the number of rows of these horizontal panels.
|
||||
// This actual number of rows is computed as follow:
|
||||
const Index l1 = defaultL1CacheSize; // in Bytes, TODO, l1 should be passed to this function.
|
||||
// The max(1, ...) here is needed because we may be using blocking params larger than what our known l1 cache size
|
||||
// suggests we should be using: either because our known l1 cache size is inaccurate (e.g. on Android, we can only guess),
|
||||
// or because we are testing specific blocking sizes.
|
||||
const Index actual_panel_rows = (3*LhsProgress) * std::max<Index>(1,( (l1 - sizeof(ResScalar)*mr*nr - depth*nr*sizeof(RhsScalar)) / (depth * sizeof(LhsScalar) * 3*LhsProgress) ));
|
||||
for(Index i1=0; i1<peeled_mc3; i1+=actual_panel_rows)
|
||||
{
|
||||
// loops on each largest micro vertical panel of rhs (depth * nr)
|
||||
const Index actual_panel_end = (std::min)(i1+actual_panel_rows, peeled_mc3);
|
||||
for(Index j2=0; j2<packet_cols4; j2+=nr)
|
||||
{
|
||||
// We select a 3*Traits::LhsProgress x nr micro block of res which is entirely
|
||||
for(Index i=i1; i<actual_panel_end; i+=3*LhsProgress)
|
||||
{
|
||||
|
||||
// We selected a 3*Traits::LhsProgress x nr micro block of res which is entirely
|
||||
// stored into 3 x nr registers.
|
||||
|
||||
const LhsScalar* blA = &blockA[i*strideA+offsetA*(3*Traits::LhsProgress)];
|
||||
const LhsScalar* blA = &blockA[i*strideA+offsetA*(3*LhsProgress)];
|
||||
prefetch(&blA[0]);
|
||||
|
||||
// gets res block as register
|
||||
@@ -1093,12 +1164,15 @@ void gebp_kernel<LhsScalar,RhsScalar,Index,DataMapper,mr,nr,ConjugateLhs,Conjuga
|
||||
traits.acc(C11, alphav, R2);
|
||||
r3.storePacket(0 * Traits::ResPacketSize, R0);
|
||||
r3.storePacket(1 * Traits::ResPacketSize, R1);
|
||||
r3.storePacket(2 * Traits::ResPacketSize, R2);
|
||||
r3.storePacket(2 * Traits::ResPacketSize, R2);
|
||||
}
|
||||
}
|
||||
|
||||
// Deal with remaining columns of the rhs
|
||||
for(Index j2=packet_cols4; j2<cols; j2++)
|
||||
{
|
||||
for(Index i=i1; i<actual_panel_end; i+=3*LhsProgress)
|
||||
{
|
||||
// One column at a time
|
||||
const LhsScalar* blA = &blockA[i*strideA+offsetA*(3*Traits::LhsProgress)];
|
||||
prefetch(&blA[0]);
|
||||
@@ -1169,7 +1243,8 @@ void gebp_kernel<LhsScalar,RhsScalar,Index,DataMapper,mr,nr,ConjugateLhs,Conjuga
|
||||
traits.acc(C8, alphav, R2);
|
||||
r0.storePacket(0 * Traits::ResPacketSize, R0);
|
||||
r0.storePacket(1 * Traits::ResPacketSize, R1);
|
||||
r0.storePacket(2 * Traits::ResPacketSize, R2);
|
||||
r0.storePacket(2 * Traits::ResPacketSize, R2);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1177,13 +1252,21 @@ void gebp_kernel<LhsScalar,RhsScalar,Index,DataMapper,mr,nr,ConjugateLhs,Conjuga
|
||||
//---------- Process 2 * LhsProgress rows at once ----------
|
||||
if(mr>=2*Traits::LhsProgress)
|
||||
{
|
||||
// loops on each largest micro horizontal panel of lhs (2*LhsProgress x depth)
|
||||
for(Index i=peeled_mc3; i<peeled_mc2; i+=2*LhsProgress)
|
||||
const Index l1 = defaultL1CacheSize; // in Bytes, TODO, l1 should be passed to this function.
|
||||
// The max(1, ...) here is needed because we may be using blocking params larger than what our known l1 cache size
|
||||
// suggests we should be using: either because our known l1 cache size is inaccurate (e.g. on Android, we can only guess),
|
||||
// or because we are testing specific blocking sizes.
|
||||
Index actual_panel_rows = (2*LhsProgress) * std::max<Index>(1,( (l1 - sizeof(ResScalar)*mr*nr - depth*nr*sizeof(RhsScalar)) / (depth * sizeof(LhsScalar) * 2*LhsProgress) ));
|
||||
|
||||
for(Index i1=peeled_mc3; i1<peeled_mc2; i1+=actual_panel_rows)
|
||||
{
|
||||
// loops on each largest micro vertical panel of rhs (depth * nr)
|
||||
Index actual_panel_end = (std::min)(i1+actual_panel_rows, peeled_mc2);
|
||||
for(Index j2=0; j2<packet_cols4; j2+=nr)
|
||||
{
|
||||
// We select a 2*Traits::LhsProgress x nr micro block of res which is entirely
|
||||
for(Index i=i1; i<actual_panel_end; i+=2*LhsProgress)
|
||||
{
|
||||
|
||||
// We selected a 2*Traits::LhsProgress x nr micro block of res which is entirely
|
||||
// stored into 2 x nr registers.
|
||||
|
||||
const LhsScalar* blA = &blockA[i*strideA+offsetA*(2*Traits::LhsProgress)];
|
||||
@@ -1287,11 +1370,14 @@ void gebp_kernel<LhsScalar,RhsScalar,Index,DataMapper,mr,nr,ConjugateLhs,Conjuga
|
||||
r2.storePacket(1 * Traits::ResPacketSize, R1);
|
||||
r3.storePacket(0 * Traits::ResPacketSize, R2);
|
||||
r3.storePacket(1 * Traits::ResPacketSize, R3);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Deal with remaining columns of the rhs
|
||||
for(Index j2=packet_cols4; j2<cols; j2++)
|
||||
{
|
||||
for(Index i=i1; i<actual_panel_end; i+=2*LhsProgress)
|
||||
{
|
||||
// One column at a time
|
||||
const LhsScalar* blA = &blockA[i*strideA+offsetA*(2*Traits::LhsProgress)];
|
||||
prefetch(&blA[0]);
|
||||
@@ -1358,6 +1444,7 @@ void gebp_kernel<LhsScalar,RhsScalar,Index,DataMapper,mr,nr,ConjugateLhs,Conjuga
|
||||
traits.acc(C4, alphav, R1);
|
||||
r0.storePacket(0 * Traits::ResPacketSize, R0);
|
||||
r0.storePacket(1 * Traits::ResPacketSize, R1);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1479,17 +1566,17 @@ void gebp_kernel<LhsScalar,RhsScalar,Index,DataMapper,mr,nr,ConjugateLhs,Conjuga
|
||||
|
||||
for(Index k=0; k<peeled_kc; k+=pk)
|
||||
{
|
||||
EIGEN_ASM_COMMENT("begin gebp micro kernel 2pX1");
|
||||
EIGEN_ASM_COMMENT("begin gebp micro kernel 1pX1");
|
||||
RhsPacket B_0;
|
||||
|
||||
#define EIGEN_GEBGP_ONESTEP(K) \
|
||||
do { \
|
||||
EIGEN_ASM_COMMENT("begin step of gebp micro kernel 2pX1"); \
|
||||
EIGEN_ASM_COMMENT("begin step of gebp micro kernel 1pX1"); \
|
||||
EIGEN_ASM_COMMENT("Note: these asm comments work around bug 935!"); \
|
||||
traits.loadLhs(&blA[(0+1*K)*LhsProgress], A0); \
|
||||
traits.loadRhs(&blB[(0+K)*RhsProgress], B_0); \
|
||||
traits.madd(A0, B_0, C0, B_0); \
|
||||
EIGEN_ASM_COMMENT("end step of gebp micro kernel 2pX1"); \
|
||||
EIGEN_ASM_COMMENT("end step of gebp micro kernel 1pX1"); \
|
||||
} while(false);
|
||||
|
||||
EIGEN_GEBGP_ONESTEP(0);
|
||||
@@ -1504,7 +1591,7 @@ void gebp_kernel<LhsScalar,RhsScalar,Index,DataMapper,mr,nr,ConjugateLhs,Conjuga
|
||||
blB += pk*RhsProgress;
|
||||
blA += pk*1*Traits::LhsProgress;
|
||||
|
||||
EIGEN_ASM_COMMENT("end gebp micro kernel 2pX1");
|
||||
EIGEN_ASM_COMMENT("end gebp micro kernel 1pX1");
|
||||
}
|
||||
|
||||
// process remaining peeled loop
|
||||
|
||||
@@ -457,6 +457,8 @@ struct generic_product_impl<Lhs,Rhs,DenseShape,DenseShape,GemmProduct>
|
||||
static void scaleAndAddTo(Dest& dst, const Lhs& a_lhs, const Rhs& a_rhs, const Scalar& alpha)
|
||||
{
|
||||
eigen_assert(dst.rows()==a_lhs.rows() && dst.cols()==a_rhs.cols());
|
||||
if(a_lhs.cols()==0 || a_lhs.rows()==0 || a_rhs.cols()==0)
|
||||
return;
|
||||
|
||||
typename internal::add_const_on_value_type<ActualLhsType>::type lhs = LhsBlasTraits::extract(a_lhs);
|
||||
typename internal::add_const_on_value_type<ActualRhsType>::type rhs = RhsBlasTraits::extract(a_rhs);
|
||||
|
||||
89
Eigen/src/Core/products/LookupBlockingSizesTable.h
Normal file
89
Eigen/src/Core/products/LookupBlockingSizesTable.h
Normal file
@@ -0,0 +1,89 @@
|
||||
// This file is part of Eigen, a lightweight C++ template library
|
||||
// for linear algebra.
|
||||
//
|
||||
// Copyright (C) 2015 Benoit Jacob <benoitjacob@google.com>
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the Mozilla
|
||||
// Public License v. 2.0. If a copy of the MPL was not distributed
|
||||
// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
#ifndef EIGEN_LOOKUP_BLOCKING_SIZES_TABLE_H
|
||||
#define EIGEN_LOOKUP_BLOCKING_SIZES_TABLE_H
|
||||
|
||||
namespace Eigen {
|
||||
|
||||
namespace internal {
|
||||
|
||||
template <typename LhsScalar,
|
||||
typename RhsScalar,
|
||||
bool HasLookupTable = BlockingSizesLookupTable<LhsScalar, RhsScalar>::NumSizes != 0 >
|
||||
struct LookupBlockingSizesFromTableImpl
|
||||
{
|
||||
static bool run(Index&, Index&, Index&, Index)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
inline size_t floor_log2_helper(unsigned short& x, size_t offset)
|
||||
{
|
||||
unsigned short y = x >> offset;
|
||||
if (y) {
|
||||
x = y;
|
||||
return offset;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
inline size_t floor_log2(unsigned short x)
|
||||
{
|
||||
return floor_log2_helper(x, 8)
|
||||
+ floor_log2_helper(x, 4)
|
||||
+ floor_log2_helper(x, 2)
|
||||
+ floor_log2_helper(x, 1);
|
||||
}
|
||||
|
||||
inline size_t ceil_log2(unsigned short x)
|
||||
{
|
||||
return x > 1 ? floor_log2(x - 1) + 1 : 0;
|
||||
}
|
||||
|
||||
template <typename LhsScalar,
|
||||
typename RhsScalar>
|
||||
struct LookupBlockingSizesFromTableImpl<LhsScalar, RhsScalar, true>
|
||||
{
|
||||
static bool run(Index& k, Index& m, Index& n, Index)
|
||||
{
|
||||
using std::min;
|
||||
using std::max;
|
||||
typedef BlockingSizesLookupTable<LhsScalar, RhsScalar> Table;
|
||||
const unsigned short minsize = Table::BaseSize;
|
||||
const unsigned short maxsize = minsize << (Table::NumSizes - 1);
|
||||
const unsigned short k_clamped = max<unsigned short>(minsize, min<Index>(k, maxsize));
|
||||
const unsigned short m_clamped = max<unsigned short>(minsize, min<Index>(m, maxsize));
|
||||
const unsigned short n_clamped = max<unsigned short>(minsize, min<Index>(n, maxsize));
|
||||
const size_t k_index = ceil_log2(k_clamped / minsize);
|
||||
const size_t m_index = ceil_log2(m_clamped / minsize);
|
||||
const size_t n_index = ceil_log2(n_clamped / minsize);
|
||||
const size_t index = n_index + Table::NumSizes * (m_index + Table::NumSizes * k_index);
|
||||
const unsigned short table_entry = Table::Data()[index];
|
||||
k = min<Index>(k, 1 << ((table_entry & 0xf00) >> 8));
|
||||
m = min<Index>(m, 1 << ((table_entry & 0x0f0) >> 4));
|
||||
n = min<Index>(n, 1 << ((table_entry & 0x00f) >> 0));
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
template <typename LhsScalar,
|
||||
typename RhsScalar>
|
||||
bool lookupBlockingSizesFromTable(Index& k, Index& m, Index& n, Index num_threads)
|
||||
{
|
||||
return LookupBlockingSizesFromTableImpl<LhsScalar, RhsScalar>::run(k, m, n, num_threads);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif // EIGEN_LOOKUP_BLOCKING_SIZES_TABLE_H
|
||||
@@ -214,7 +214,7 @@ class blas_data_mapper {
|
||||
}
|
||||
|
||||
template<typename SubPacket>
|
||||
EIGEN_ALWAYS_INLINE void scatterPacket(Index i, Index j, SubPacket p) const {
|
||||
EIGEN_ALWAYS_INLINE void scatterPacket(Index i, Index j, const SubPacket &p) const {
|
||||
pscatter<Scalar, SubPacket>(&operator()(i, j), p, m_stride);
|
||||
}
|
||||
|
||||
|
||||
@@ -288,6 +288,14 @@ struct stem_function
|
||||
typedef std::complex<typename NumTraits<Scalar>::Real> ComplexScalar;
|
||||
typedef ComplexScalar type(ComplexScalar, int);
|
||||
};
|
||||
|
||||
template <typename LhsScalar,
|
||||
typename RhsScalar>
|
||||
struct BlockingSizesLookupTable
|
||||
{
|
||||
static const size_t NumSizes = 0;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
} // end namespace Eigen
|
||||
|
||||
@@ -318,6 +318,9 @@
|
||||
// Defined the boundary (in bytes) on which the data needs to be aligned. Note
|
||||
// that unless EIGEN_ALIGN is defined and not equal to 0, the data may not be
|
||||
// aligned at all regardless of the value of this #define.
|
||||
// TODO should be renamed EIGEN_MAXIMAL_ALIGN_BYTES,
|
||||
// for instance with AVX 1 EIGEN_MAXIMAL_ALIGN_BYTES=32 while for 'int' 16 bytes alignment is always enough,
|
||||
// and 16 bytes alignment is also enough for Vector4f.
|
||||
#define EIGEN_ALIGN_BYTES 16
|
||||
|
||||
#ifdef EIGEN_DONT_ALIGN
|
||||
|
||||
@@ -159,13 +159,16 @@ class compute_matrix_evaluator_flags
|
||||
enum {
|
||||
row_major_bit = Options&RowMajor ? RowMajorBit : 0,
|
||||
is_dynamic_size_storage = MaxRows==Dynamic || MaxCols==Dynamic,
|
||||
|
||||
// TODO: should check for smaller packet types once we can handle multi-sized packet types
|
||||
align_bytes = int(packet_traits<Scalar>::size) * sizeof(Scalar),
|
||||
|
||||
aligned_bit =
|
||||
(
|
||||
((Options&DontAlign)==0)
|
||||
&& (
|
||||
#if EIGEN_ALIGN_STATICALLY
|
||||
((!is_dynamic_size_storage) && (((MaxCols*MaxRows*int(sizeof(Scalar))) % EIGEN_ALIGN_BYTES) == 0))
|
||||
((!is_dynamic_size_storage) && (((MaxCols*MaxRows*int(sizeof(Scalar))) % align_bytes) == 0))
|
||||
#else
|
||||
0
|
||||
#endif
|
||||
|
||||
@@ -234,6 +234,12 @@ template<typename _MatrixType> class ComplexEigenSolver
|
||||
}
|
||||
|
||||
protected:
|
||||
|
||||
static void check_template_parameters()
|
||||
{
|
||||
EIGEN_STATIC_ASSERT_NON_INTEGER(Scalar);
|
||||
}
|
||||
|
||||
EigenvectorType m_eivec;
|
||||
EigenvalueType m_eivalues;
|
||||
ComplexSchur<MatrixType> m_schur;
|
||||
@@ -251,6 +257,8 @@ template<typename MatrixType>
|
||||
ComplexEigenSolver<MatrixType>&
|
||||
ComplexEigenSolver<MatrixType>::compute(const MatrixType& matrix, bool computeEigenvectors)
|
||||
{
|
||||
check_template_parameters();
|
||||
|
||||
// this code is inspired from Jampack
|
||||
eigen_assert(matrix.cols() == matrix.rows());
|
||||
|
||||
|
||||
@@ -299,6 +299,13 @@ template<typename _MatrixType> class EigenSolver
|
||||
void doComputeEigenvectors();
|
||||
|
||||
protected:
|
||||
|
||||
static void check_template_parameters()
|
||||
{
|
||||
EIGEN_STATIC_ASSERT_NON_INTEGER(Scalar);
|
||||
EIGEN_STATIC_ASSERT(!NumTraits<Scalar>::IsComplex, NUMERIC_TYPE_MUST_BE_REAL);
|
||||
}
|
||||
|
||||
MatrixType m_eivec;
|
||||
EigenvalueType m_eivalues;
|
||||
bool m_isInitialized;
|
||||
@@ -366,6 +373,8 @@ template<typename MatrixType>
|
||||
EigenSolver<MatrixType>&
|
||||
EigenSolver<MatrixType>::compute(const MatrixType& matrix, bool computeEigenvectors)
|
||||
{
|
||||
check_template_parameters();
|
||||
|
||||
using std::sqrt;
|
||||
using std::abs;
|
||||
using numext::isfinite;
|
||||
|
||||
@@ -263,6 +263,13 @@ template<typename _MatrixType> class GeneralizedEigenSolver
|
||||
}
|
||||
|
||||
protected:
|
||||
|
||||
static void check_template_parameters()
|
||||
{
|
||||
EIGEN_STATIC_ASSERT_NON_INTEGER(Scalar);
|
||||
EIGEN_STATIC_ASSERT(!NumTraits<Scalar>::IsComplex, NUMERIC_TYPE_MUST_BE_REAL);
|
||||
}
|
||||
|
||||
MatrixType m_eivec;
|
||||
ComplexVectorType m_alphas;
|
||||
VectorType m_betas;
|
||||
@@ -290,6 +297,8 @@ template<typename MatrixType>
|
||||
GeneralizedEigenSolver<MatrixType>&
|
||||
GeneralizedEigenSolver<MatrixType>::compute(const MatrixType& A, const MatrixType& B, bool computeEigenvectors)
|
||||
{
|
||||
check_template_parameters();
|
||||
|
||||
using std::sqrt;
|
||||
using std::abs;
|
||||
eigen_assert(A.cols() == A.rows() && B.cols() == A.rows() && B.cols() == B.rows());
|
||||
|
||||
@@ -347,6 +347,11 @@ template<typename _MatrixType> class SelfAdjointEigenSolver
|
||||
static const int m_maxIterations = 30;
|
||||
|
||||
protected:
|
||||
static void check_template_parameters()
|
||||
{
|
||||
EIGEN_STATIC_ASSERT_NON_INTEGER(Scalar);
|
||||
}
|
||||
|
||||
MatrixType m_eivec;
|
||||
RealVectorType m_eivalues;
|
||||
typename TridiagonalizationType::SubDiagonalType m_subdiag;
|
||||
@@ -382,6 +387,8 @@ EIGEN_DEVICE_FUNC
|
||||
SelfAdjointEigenSolver<MatrixType>& SelfAdjointEigenSolver<MatrixType>
|
||||
::compute(const MatrixType& matrix, int options)
|
||||
{
|
||||
check_template_parameters();
|
||||
|
||||
using std::abs;
|
||||
eigen_assert(matrix.cols() == matrix.rows());
|
||||
eigen_assert((options&~(EigVecMask|GenEigMask))==0
|
||||
|
||||
@@ -441,7 +441,7 @@ QuaternionBase<Derived>::operator* (const QuaternionBase<OtherDerived>& other) c
|
||||
YOU_MIXED_DIFFERENT_NUMERIC_TYPES__YOU_NEED_TO_USE_THE_CAST_METHOD_OF_MATRIXBASE_TO_CAST_NUMERIC_TYPES_EXPLICITLY)
|
||||
return internal::quat_product<Architecture::Target, Derived, OtherDerived,
|
||||
typename internal::traits<Derived>::Scalar,
|
||||
internal::traits<Derived>::IsAligned && internal::traits<OtherDerived>::IsAligned>::run(*this, other);
|
||||
(internal::traits<Derived>::IsAligned && internal::traits<OtherDerived>::IsAligned)?Aligned:Unaligned>::run(*this, other);
|
||||
}
|
||||
|
||||
/** \sa operator*(Quaternion) */
|
||||
@@ -646,6 +646,16 @@ inline Quaternion<typename internal::traits<Derived>::Scalar> QuaternionBase<Der
|
||||
}
|
||||
}
|
||||
|
||||
// Generic conjugate of a Quaternion
|
||||
namespace internal {
|
||||
template<int Arch, class Derived, typename Scalar, int _Options> struct quat_conj
|
||||
{
|
||||
static EIGEN_STRONG_INLINE Quaternion<Scalar> run(const QuaternionBase<Derived>& q){
|
||||
return Quaternion<Scalar>(q.w(),-q.x(),-q.y(),-q.z());
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/** \returns the conjugate of the \c *this which is equal to the multiplicative inverse
|
||||
* if the quaternion is normalized.
|
||||
* The conjugate of a quaternion represents the opposite rotation.
|
||||
@@ -656,7 +666,10 @@ template <class Derived>
|
||||
inline Quaternion<typename internal::traits<Derived>::Scalar>
|
||||
QuaternionBase<Derived>::conjugate() const
|
||||
{
|
||||
return Quaternion<Scalar>(this->w(),-this->x(),-this->y(),-this->z());
|
||||
return internal::quat_conj<Architecture::Target, Derived,
|
||||
typename internal::traits<Derived>::Scalar,
|
||||
internal::traits<Derived>::IsAligned?Aligned:Unaligned>::run(*this);
|
||||
|
||||
}
|
||||
|
||||
/** \returns the angle (in radian) between two rotations
|
||||
@@ -667,12 +680,10 @@ template <class OtherDerived>
|
||||
inline typename internal::traits<Derived>::Scalar
|
||||
QuaternionBase<Derived>::angularDistance(const QuaternionBase<OtherDerived>& other) const
|
||||
{
|
||||
using std::acos;
|
||||
using std::atan2;
|
||||
using std::abs;
|
||||
Scalar d = abs(this->dot(other));
|
||||
if (d>=Scalar(1))
|
||||
return Scalar(0);
|
||||
return Scalar(2) * acos(d);
|
||||
Quaternion<Scalar> d = (*this) * other.conjugate();
|
||||
return Scalar(2) * atan2( d.vec().norm(), abs(d.w()) );
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -20,23 +20,35 @@ struct quat_product<Architecture::SSE, Derived, OtherDerived, float, Aligned>
|
||||
{
|
||||
static inline Quaternion<float> run(const QuaternionBase<Derived>& _a, const QuaternionBase<OtherDerived>& _b)
|
||||
{
|
||||
const __m128 mask = _mm_castsi128_ps(_mm_setr_epi32(0,0,0,0x80000000));
|
||||
Quaternion<float> res;
|
||||
const __m128 mask = _mm_setr_ps(0.f,0.f,0.f,-0.f);
|
||||
__m128 a = _a.coeffs().template packet<Aligned>(0);
|
||||
__m128 b = _b.coeffs().template packet<Aligned>(0);
|
||||
__m128 flip1 = _mm_xor_ps(_mm_mul_ps(vec4f_swizzle1(a,1,2,0,2),
|
||||
vec4f_swizzle1(b,2,0,1,2)),mask);
|
||||
__m128 flip2 = _mm_xor_ps(_mm_mul_ps(vec4f_swizzle1(a,3,3,3,1),
|
||||
vec4f_swizzle1(b,0,1,2,1)),mask);
|
||||
__m128 s1 = _mm_mul_ps(vec4f_swizzle1(a,1,2,0,2),vec4f_swizzle1(b,2,0,1,2));
|
||||
__m128 s2 = _mm_mul_ps(vec4f_swizzle1(a,3,3,3,1),vec4f_swizzle1(b,0,1,2,1));
|
||||
pstore(&res.x(),
|
||||
_mm_add_ps(_mm_sub_ps(_mm_mul_ps(a,vec4f_swizzle1(b,3,3,3,3)),
|
||||
_mm_mul_ps(vec4f_swizzle1(a,2,0,1,0),
|
||||
vec4f_swizzle1(b,1,2,0,0))),
|
||||
_mm_add_ps(flip1,flip2)));
|
||||
_mm_xor_ps(mask,_mm_add_ps(s1,s2))));
|
||||
|
||||
return res;
|
||||
}
|
||||
};
|
||||
|
||||
template<class Derived, int Alignment>
|
||||
struct quat_conj<Architecture::SSE, Derived, float, Alignment>
|
||||
{
|
||||
static inline Quaternion<float> run(const QuaternionBase<Derived>& q)
|
||||
{
|
||||
Quaternion<float> res;
|
||||
const __m128 mask = _mm_setr_ps(-0.f,-0.f,-0.f,0.f);
|
||||
pstore(&res.x(), _mm_xor_ps(mask, q.coeffs().template packet<Alignment>(0)));
|
||||
return res;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
template<typename VectorLhs,typename VectorRhs>
|
||||
struct cross3_impl<Architecture::SSE,VectorLhs,VectorRhs,float,true>
|
||||
{
|
||||
@@ -56,8 +68,8 @@ struct cross3_impl<Architecture::SSE,VectorLhs,VectorRhs,float,true>
|
||||
|
||||
|
||||
|
||||
template<class Derived, class OtherDerived>
|
||||
struct quat_product<Architecture::SSE, Derived, OtherDerived, double, Aligned>
|
||||
template<class Derived, class OtherDerived, int Alignment>
|
||||
struct quat_product<Architecture::SSE, Derived, OtherDerived, double, Alignment>
|
||||
{
|
||||
static inline Quaternion<double> run(const QuaternionBase<Derived>& _a, const QuaternionBase<OtherDerived>& _b)
|
||||
{
|
||||
@@ -66,8 +78,8 @@ struct quat_product<Architecture::SSE, Derived, OtherDerived, double, Aligned>
|
||||
Quaternion<double> res;
|
||||
|
||||
const double* a = _a.coeffs().data();
|
||||
Packet2d b_xy = _b.coeffs().template packet<Aligned>(0);
|
||||
Packet2d b_zw = _b.coeffs().template packet<Aligned>(2);
|
||||
Packet2d b_xy = _b.coeffs().template packet<Alignment>(0);
|
||||
Packet2d b_zw = _b.coeffs().template packet<Alignment>(2);
|
||||
Packet2d a_xx = pset1<Packet2d>(a[0]);
|
||||
Packet2d a_yy = pset1<Packet2d>(a[1]);
|
||||
Packet2d a_zz = pset1<Packet2d>(a[2]);
|
||||
@@ -108,6 +120,20 @@ struct quat_product<Architecture::SSE, Derived, OtherDerived, double, Aligned>
|
||||
}
|
||||
};
|
||||
|
||||
template<class Derived, int Alignment>
|
||||
struct quat_conj<Architecture::SSE, Derived, double, Alignment>
|
||||
{
|
||||
static inline Quaternion<double> run(const QuaternionBase<Derived>& q)
|
||||
{
|
||||
Quaternion<double> res;
|
||||
const __m128d mask0 = _mm_setr_pd(-0.,-0.);
|
||||
const __m128d mask2 = _mm_setr_pd(-0.,0.);
|
||||
pstore(&res.x(), _mm_xor_pd(mask0, q.coeffs().template packet<Alignment>(0)));
|
||||
pstore(&res.z(), _mm_xor_pd(mask2, q.coeffs().template packet<Alignment>(2)));
|
||||
return res;
|
||||
}
|
||||
};
|
||||
|
||||
} // end namespace internal
|
||||
|
||||
} // end namespace Eigen
|
||||
|
||||
@@ -17,9 +17,9 @@ namespace Eigen {
|
||||
*
|
||||
* This class allows to approximately solve for A.x = b problems assuming A is a diagonal matrix.
|
||||
* In other words, this preconditioner neglects all off diagonal entries and, in Eigen's language, solves for:
|
||||
* \code
|
||||
* A.diagonal().asDiagonal() . x = b
|
||||
* \endcode
|
||||
\code
|
||||
A.diagonal().asDiagonal() . x = b
|
||||
\endcode
|
||||
*
|
||||
* \tparam _Scalar the type of the scalar.
|
||||
*
|
||||
@@ -28,6 +28,7 @@ namespace Eigen {
|
||||
*
|
||||
* \note A variant that has yet to be implemented would attempt to preserve the norm of each column.
|
||||
*
|
||||
* \sa class LeastSquareDiagonalPreconditioner, class ConjugateGradient
|
||||
*/
|
||||
template <typename _Scalar>
|
||||
class DiagonalPreconditioner
|
||||
@@ -100,6 +101,69 @@ class DiagonalPreconditioner
|
||||
bool m_isInitialized;
|
||||
};
|
||||
|
||||
/** \ingroup IterativeLinearSolvers_Module
|
||||
* \brief Jacobi preconditioner for LeastSquaresConjugateGradient
|
||||
*
|
||||
* This class allows to approximately solve for A' A x = A' b problems assuming A' A is a diagonal matrix.
|
||||
* In other words, this preconditioner neglects all off diagonal entries and, in Eigen's language, solves for:
|
||||
\code
|
||||
(A.adjoint() * A).diagonal().asDiagonal() * x = b
|
||||
\endcode
|
||||
*
|
||||
* \tparam _Scalar the type of the scalar.
|
||||
*
|
||||
* The diagonal entries are pre-inverted and stored into a dense vector.
|
||||
*
|
||||
* \sa class LeastSquaresConjugateGradient, class DiagonalPreconditioner
|
||||
*/
|
||||
template <typename _Scalar>
|
||||
class LeastSquareDiagonalPreconditioner : public DiagonalPreconditioner<_Scalar>
|
||||
{
|
||||
typedef _Scalar Scalar;
|
||||
typedef typename NumTraits<Scalar>::Real RealScalar;
|
||||
typedef DiagonalPreconditioner<_Scalar> Base;
|
||||
using Base::m_invdiag;
|
||||
public:
|
||||
|
||||
LeastSquareDiagonalPreconditioner() : Base() {}
|
||||
|
||||
template<typename MatType>
|
||||
explicit LeastSquareDiagonalPreconditioner(const MatType& mat) : Base()
|
||||
{
|
||||
compute(mat);
|
||||
}
|
||||
|
||||
template<typename MatType>
|
||||
LeastSquareDiagonalPreconditioner& analyzePattern(const MatType& )
|
||||
{
|
||||
return *this;
|
||||
}
|
||||
|
||||
template<typename MatType>
|
||||
LeastSquareDiagonalPreconditioner& factorize(const MatType& mat)
|
||||
{
|
||||
// Compute the inverse squared-norm of each column of mat
|
||||
m_invdiag.resize(mat.cols());
|
||||
for(Index j=0; j<mat.outerSize(); ++j)
|
||||
{
|
||||
RealScalar sum = mat.innerVector(j).squaredNorm();
|
||||
if(sum>0)
|
||||
m_invdiag(j) = RealScalar(1)/sum;
|
||||
else
|
||||
m_invdiag(j) = RealScalar(1);
|
||||
}
|
||||
Base::m_isInitialized = true;
|
||||
return *this;
|
||||
}
|
||||
|
||||
template<typename MatType>
|
||||
LeastSquareDiagonalPreconditioner& compute(const MatType& mat)
|
||||
{
|
||||
return factorize(mat);
|
||||
}
|
||||
|
||||
protected:
|
||||
};
|
||||
|
||||
/** \ingroup IterativeLinearSolvers_Module
|
||||
* \brief A naive preconditioner which approximates any matrix as the identity matrix
|
||||
|
||||
@@ -60,29 +60,29 @@ void conjugate_gradient(const MatrixType& mat, const Rhs& rhs, Dest& x,
|
||||
}
|
||||
|
||||
VectorType p(n);
|
||||
p = precond.solve(residual); //initial search direction
|
||||
p = precond.solve(residual); // initial search direction
|
||||
|
||||
VectorType z(n), tmp(n);
|
||||
RealScalar absNew = numext::real(residual.dot(p)); // the square of the absolute value of r scaled by invM
|
||||
Index i = 0;
|
||||
while(i < maxIters)
|
||||
{
|
||||
tmp.noalias() = mat * p; // the bottleneck of the algorithm
|
||||
tmp.noalias() = mat * p; // the bottleneck of the algorithm
|
||||
|
||||
Scalar alpha = absNew / p.dot(tmp); // the amount we travel on dir
|
||||
x += alpha * p; // update solution
|
||||
residual -= alpha * tmp; // update residue
|
||||
Scalar alpha = absNew / p.dot(tmp); // the amount we travel on dir
|
||||
x += alpha * p; // update solution
|
||||
residual -= alpha * tmp; // update residual
|
||||
|
||||
residualNorm2 = residual.squaredNorm();
|
||||
if(residualNorm2 < threshold)
|
||||
break;
|
||||
|
||||
z = precond.solve(residual); // approximately solve for "A z = residual"
|
||||
z = precond.solve(residual); // approximately solve for "A z = residual"
|
||||
|
||||
RealScalar absOld = absNew;
|
||||
absNew = numext::real(residual.dot(z)); // update the absolute value of r
|
||||
RealScalar beta = absNew / absOld; // calculate the Gram-Schmidt value used to create the new search direction
|
||||
p = z + beta * p; // update search direction
|
||||
RealScalar beta = absNew / absOld; // calculate the Gram-Schmidt value used to create the new search direction
|
||||
p = z + beta * p; // update search direction
|
||||
i++;
|
||||
}
|
||||
tol_error = sqrt(residualNorm2 / rhsNorm2);
|
||||
@@ -122,24 +122,24 @@ struct traits<ConjugateGradient<_MatrixType,_UpLo,_Preconditioner> >
|
||||
* and NumTraits<Scalar>::epsilon() for the tolerance.
|
||||
*
|
||||
* This class can be used as the direct solver classes. Here is a typical usage example:
|
||||
* \code
|
||||
* int n = 10000;
|
||||
* VectorXd x(n), b(n);
|
||||
* SparseMatrix<double> A(n,n);
|
||||
* // fill A and b
|
||||
* ConjugateGradient<SparseMatrix<double> > cg;
|
||||
* cg.compute(A);
|
||||
* x = cg.solve(b);
|
||||
* std::cout << "#iterations: " << cg.iterations() << std::endl;
|
||||
* std::cout << "estimated error: " << cg.error() << std::endl;
|
||||
* // update b, and solve again
|
||||
* x = cg.solve(b);
|
||||
* \endcode
|
||||
\code
|
||||
int n = 10000;
|
||||
VectorXd x(n), b(n);
|
||||
SparseMatrix<double> A(n,n);
|
||||
// fill A and b
|
||||
ConjugateGradient<SparseMatrix<double> > cg;
|
||||
cg.compute(A);
|
||||
x = cg.solve(b);
|
||||
std::cout << "#iterations: " << cg.iterations() << std::endl;
|
||||
std::cout << "estimated error: " << cg.error() << std::endl;
|
||||
// update b, and solve again
|
||||
x = cg.solve(b);
|
||||
\endcode
|
||||
*
|
||||
* By default the iterations start with x=0 as an initial guess of the solution.
|
||||
* One can control the start using the solveWithGuess() method.
|
||||
*
|
||||
* \sa class SimplicialCholesky, DiagonalPreconditioner, IdentityPreconditioner
|
||||
* \sa class LeastSquaresConjugateGradient, class SimplicialCholesky, DiagonalPreconditioner, IdentityPreconditioner
|
||||
*/
|
||||
template< typename _MatrixType, int _UpLo, typename _Preconditioner>
|
||||
class ConjugateGradient : public IterativeSolverBase<ConjugateGradient<_MatrixType,_UpLo,_Preconditioner> >
|
||||
@@ -185,7 +185,7 @@ public:
|
||||
{
|
||||
typedef typename internal::conditional<UpLo==(Lower|Upper),
|
||||
Ref<const MatrixType>&,
|
||||
SparseSelfAdjointView<const Ref<const MatrixType>, UpLo>
|
||||
typename Ref<const MatrixType>::template ConstSelfAdjointViewReturnType<UpLo>::Type
|
||||
>::type MatrixWrapperType;
|
||||
m_iterations = Base::maxIterations();
|
||||
m_error = Base::m_tolerance;
|
||||
@@ -208,7 +208,7 @@ public:
|
||||
template<typename Rhs,typename Dest>
|
||||
void _solve_impl(const MatrixBase<Rhs>& b, Dest& x) const
|
||||
{
|
||||
x.setOnes();
|
||||
x.setZero();
|
||||
_solve_with_guess_impl(b.derived(),x);
|
||||
}
|
||||
|
||||
|
||||
@@ -93,21 +93,23 @@ Index QuickSplit(VectorV &row, VectorI &ind, Index ncut)
|
||||
* alternatively, on GMANE:
|
||||
* http://comments.gmane.org/gmane.comp.lib.eigen/3302
|
||||
*/
|
||||
template <typename _Scalar>
|
||||
class IncompleteLUT : public SparseSolverBase<IncompleteLUT<_Scalar> >
|
||||
template <typename _Scalar, typename _StorageIndex = int>
|
||||
class IncompleteLUT : public SparseSolverBase<IncompleteLUT<_Scalar, _StorageIndex> >
|
||||
{
|
||||
protected:
|
||||
typedef SparseSolverBase<IncompleteLUT<_Scalar> > Base;
|
||||
typedef SparseSolverBase<IncompleteLUT> Base;
|
||||
using Base::m_isInitialized;
|
||||
public:
|
||||
typedef _Scalar Scalar;
|
||||
typedef _StorageIndex StorageIndex;
|
||||
typedef typename NumTraits<Scalar>::Real RealScalar;
|
||||
typedef Matrix<Scalar,Dynamic,1> Vector;
|
||||
typedef SparseMatrix<Scalar,RowMajor> FactorType;
|
||||
typedef SparseMatrix<Scalar,ColMajor> PermutType;
|
||||
typedef typename FactorType::StorageIndex StorageIndex;
|
||||
typedef Matrix<StorageIndex,Dynamic,1> VectorI;
|
||||
typedef SparseMatrix<Scalar,RowMajor,StorageIndex> FactorType;
|
||||
|
||||
public:
|
||||
|
||||
// this typedef is only to export the scalar type and compile-time dimensions to solve_retval
|
||||
typedef Matrix<Scalar,Dynamic,Dynamic> MatrixType;
|
||||
|
||||
IncompleteLUT()
|
||||
@@ -151,7 +153,7 @@ class IncompleteLUT : public SparseSolverBase<IncompleteLUT<_Scalar> >
|
||||
*
|
||||
**/
|
||||
template<typename MatrixType>
|
||||
IncompleteLUT<Scalar>& compute(const MatrixType& amat)
|
||||
IncompleteLUT& compute(const MatrixType& amat)
|
||||
{
|
||||
analyzePattern(amat);
|
||||
factorize(amat);
|
||||
@@ -197,8 +199,8 @@ protected:
|
||||
* Set control parameter droptol
|
||||
* \param droptol Drop any element whose magnitude is less than this tolerance
|
||||
**/
|
||||
template<typename Scalar>
|
||||
void IncompleteLUT<Scalar>::setDroptol(const RealScalar& droptol)
|
||||
template<typename Scalar, typename StorageIndex>
|
||||
void IncompleteLUT<Scalar,StorageIndex>::setDroptol(const RealScalar& droptol)
|
||||
{
|
||||
this->m_droptol = droptol;
|
||||
}
|
||||
@@ -207,15 +209,15 @@ void IncompleteLUT<Scalar>::setDroptol(const RealScalar& droptol)
|
||||
* Set control parameter fillfactor
|
||||
* \param fillfactor This is used to compute the number @p fill_in of largest elements to keep on each row.
|
||||
**/
|
||||
template<typename Scalar>
|
||||
void IncompleteLUT<Scalar>::setFillfactor(int fillfactor)
|
||||
template<typename Scalar, typename StorageIndex>
|
||||
void IncompleteLUT<Scalar,StorageIndex>::setFillfactor(int fillfactor)
|
||||
{
|
||||
this->m_fillfactor = fillfactor;
|
||||
}
|
||||
|
||||
template <typename Scalar>
|
||||
template <typename Scalar, typename StorageIndex>
|
||||
template<typename _MatrixType>
|
||||
void IncompleteLUT<Scalar>::analyzePattern(const _MatrixType& amat)
|
||||
void IncompleteLUT<Scalar,StorageIndex>::analyzePattern(const _MatrixType& amat)
|
||||
{
|
||||
// Compute the Fill-reducing permutation
|
||||
SparseMatrix<Scalar,ColMajor, StorageIndex> mat1 = amat;
|
||||
@@ -232,9 +234,9 @@ void IncompleteLUT<Scalar>::analyzePattern(const _MatrixType& amat)
|
||||
m_analysisIsOk = true;
|
||||
}
|
||||
|
||||
template <typename Scalar>
|
||||
template <typename Scalar, typename StorageIndex>
|
||||
template<typename _MatrixType>
|
||||
void IncompleteLUT<Scalar>::factorize(const _MatrixType& amat)
|
||||
void IncompleteLUT<Scalar,StorageIndex>::factorize(const _MatrixType& amat)
|
||||
{
|
||||
using std::sqrt;
|
||||
using std::swap;
|
||||
@@ -246,8 +248,8 @@ void IncompleteLUT<Scalar>::factorize(const _MatrixType& amat)
|
||||
m_lu.resize(n,n);
|
||||
// Declare Working vectors and variables
|
||||
Vector u(n) ; // real values of the row -- maximum size is n --
|
||||
VectorXi ju(n); // column position of the values in u -- maximum size is n
|
||||
VectorXi jr(n); // Indicate the position of the nonzero elements in the vector u -- A zero location is indicated by -1
|
||||
VectorI ju(n); // column position of the values in u -- maximum size is n
|
||||
VectorI jr(n); // Indicate the position of the nonzero elements in the vector u -- A zero location is indicated by -1
|
||||
|
||||
// Apply the fill-reducing permutation
|
||||
eigen_assert(m_analysisIsOk && "You must first call analyzePattern()");
|
||||
@@ -398,7 +400,7 @@ void IncompleteLUT<Scalar>::factorize(const _MatrixType& amat)
|
||||
sizel = len;
|
||||
len = (std::min)(sizel, nnzL);
|
||||
typename Vector::SegmentReturnType ul(u.segment(0, sizel));
|
||||
typename VectorXi::SegmentReturnType jul(ju.segment(0, sizel));
|
||||
typename VectorI::SegmentReturnType jul(ju.segment(0, sizel));
|
||||
internal::QuickSplit(ul, jul, len);
|
||||
|
||||
// store the largest m_fill elements of the L part
|
||||
@@ -427,14 +429,13 @@ void IncompleteLUT<Scalar>::factorize(const _MatrixType& amat)
|
||||
sizeu = len + 1; // +1 to take into account the diagonal element
|
||||
len = (std::min)(sizeu, nnzU);
|
||||
typename Vector::SegmentReturnType uu(u.segment(ii+1, sizeu-1));
|
||||
typename VectorXi::SegmentReturnType juu(ju.segment(ii+1, sizeu-1));
|
||||
typename VectorI::SegmentReturnType juu(ju.segment(ii+1, sizeu-1));
|
||||
internal::QuickSplit(uu, juu, len);
|
||||
|
||||
// store the largest elements of the U part
|
||||
for(Index k = ii + 1; k < ii + len; k++)
|
||||
m_lu.insertBackByOuterInnerUnordered(ii,ju(k)) = u(k);
|
||||
}
|
||||
|
||||
m_lu.finalize();
|
||||
m_lu.makeCompressed();
|
||||
|
||||
|
||||
@@ -52,9 +52,9 @@ public:
|
||||
* this class becomes invalid. Call compute() to update it with the new
|
||||
* matrix A, or modify a copy of A.
|
||||
*/
|
||||
template<typename SparseMatrixDerived>
|
||||
explicit IterativeSolverBase(const SparseMatrixBase<SparseMatrixDerived>& A)
|
||||
: mp_matrix(A)
|
||||
template<typename MatrixDerived>
|
||||
explicit IterativeSolverBase(const EigenBase<MatrixDerived>& A)
|
||||
: mp_matrix(A.derived())
|
||||
{
|
||||
init();
|
||||
compute(mp_matrix);
|
||||
@@ -67,8 +67,8 @@ public:
|
||||
* Currently, this function mostly calls analyzePattern on the preconditioner. In the future
|
||||
* we might, for instance, implement column reordering for faster matrix vector products.
|
||||
*/
|
||||
template<typename SparseMatrixDerived>
|
||||
Derived& analyzePattern(const SparseMatrixBase<SparseMatrixDerived>& A)
|
||||
template<typename MatrixDerived>
|
||||
Derived& analyzePattern(const EigenBase<MatrixDerived>& A)
|
||||
{
|
||||
grab(A.derived());
|
||||
m_preconditioner.analyzePattern(mp_matrix);
|
||||
@@ -87,8 +87,8 @@ public:
|
||||
* this class becomes invalid. Call compute() to update it with the new
|
||||
* matrix A, or modify a copy of A.
|
||||
*/
|
||||
template<typename SparseMatrixDerived>
|
||||
Derived& factorize(const SparseMatrixBase<SparseMatrixDerived>& A)
|
||||
template<typename MatrixDerived>
|
||||
Derived& factorize(const EigenBase<MatrixDerived>& A)
|
||||
{
|
||||
eigen_assert(m_analysisIsOk && "You must first call analyzePattern()");
|
||||
grab(A.derived());
|
||||
@@ -108,8 +108,8 @@ public:
|
||||
* this class becomes invalid. Call compute() to update it with the new
|
||||
* matrix A, or modify a copy of A.
|
||||
*/
|
||||
template<typename SparseMatrixDerived>
|
||||
Derived& compute(const SparseMatrixBase<SparseMatrixDerived>& A)
|
||||
template<typename MatrixDerived>
|
||||
Derived& compute(const EigenBase<MatrixDerived>& A)
|
||||
{
|
||||
grab(A.derived());
|
||||
m_preconditioner.compute(mp_matrix);
|
||||
@@ -223,11 +223,11 @@ protected:
|
||||
m_tolerance = NumTraits<Scalar>::epsilon();
|
||||
}
|
||||
|
||||
template<typename SparseMatrixDerived>
|
||||
void grab(const SparseMatrixBase<SparseMatrixDerived> &A)
|
||||
template<typename MatrixDerived>
|
||||
void grab(const EigenBase<MatrixDerived> &A)
|
||||
{
|
||||
mp_matrix.~Ref<const MatrixType>();
|
||||
::new (&mp_matrix) Ref<const MatrixType>(A);
|
||||
::new (&mp_matrix) Ref<const MatrixType>(A.derived());
|
||||
}
|
||||
|
||||
void grab(const Ref<const MatrixType> &A)
|
||||
|
||||
213
Eigen/src/IterativeLinearSolvers/LeastSquareConjugateGradient.h
Normal file
213
Eigen/src/IterativeLinearSolvers/LeastSquareConjugateGradient.h
Normal file
@@ -0,0 +1,213 @@
|
||||
// This file is part of Eigen, a lightweight C++ template library
|
||||
// for linear algebra.
|
||||
//
|
||||
// Copyright (C) 2015 Gael Guennebaud <gael.guennebaud@inria.fr>
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the Mozilla
|
||||
// Public License v. 2.0. If a copy of the MPL was not distributed
|
||||
// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
#ifndef EIGEN_LEAST_SQUARE_CONJUGATE_GRADIENT_H
|
||||
#define EIGEN_LEAST_SQUARE_CONJUGATE_GRADIENT_H
|
||||
|
||||
namespace Eigen {
|
||||
|
||||
namespace internal {
|
||||
|
||||
/** \internal Low-level conjugate gradient algorithm for least-square problems
|
||||
* \param mat The matrix A
|
||||
* \param rhs The right hand side vector b
|
||||
* \param x On input and initial solution, on output the computed solution.
|
||||
* \param precond A preconditioner being able to efficiently solve for an
|
||||
* approximation of A'Ax=b (regardless of b)
|
||||
* \param iters On input the max number of iteration, on output the number of performed iterations.
|
||||
* \param tol_error On input the tolerance error, on output an estimation of the relative error.
|
||||
*/
|
||||
template<typename MatrixType, typename Rhs, typename Dest, typename Preconditioner>
|
||||
EIGEN_DONT_INLINE
|
||||
void least_square_conjugate_gradient(const MatrixType& mat, const Rhs& rhs, Dest& x,
|
||||
const Preconditioner& precond, Index& iters,
|
||||
typename Dest::RealScalar& tol_error)
|
||||
{
|
||||
using std::sqrt;
|
||||
using std::abs;
|
||||
typedef typename Dest::RealScalar RealScalar;
|
||||
typedef typename Dest::Scalar Scalar;
|
||||
typedef Matrix<Scalar,Dynamic,1> VectorType;
|
||||
|
||||
RealScalar tol = tol_error;
|
||||
Index maxIters = iters;
|
||||
|
||||
Index m = mat.rows(), n = mat.cols();
|
||||
|
||||
VectorType residual = rhs - mat * x;
|
||||
VectorType normal_residual = mat.adjoint() * residual;
|
||||
|
||||
RealScalar rhsNorm2 = (mat.adjoint()*rhs).squaredNorm();
|
||||
if(rhsNorm2 == 0)
|
||||
{
|
||||
x.setZero();
|
||||
iters = 0;
|
||||
tol_error = 0;
|
||||
return;
|
||||
}
|
||||
RealScalar threshold = tol*tol*rhsNorm2;
|
||||
RealScalar residualNorm2 = normal_residual.squaredNorm();
|
||||
if (residualNorm2 < threshold)
|
||||
{
|
||||
iters = 0;
|
||||
tol_error = sqrt(residualNorm2 / rhsNorm2);
|
||||
return;
|
||||
}
|
||||
|
||||
VectorType p(n);
|
||||
p = precond.solve(normal_residual); // initial search direction
|
||||
|
||||
VectorType z(n), tmp(m);
|
||||
RealScalar absNew = numext::real(normal_residual.dot(p)); // the square of the absolute value of r scaled by invM
|
||||
Index i = 0;
|
||||
while(i < maxIters)
|
||||
{
|
||||
tmp.noalias() = mat * p;
|
||||
|
||||
Scalar alpha = absNew / tmp.squaredNorm(); // the amount we travel on dir
|
||||
x += alpha * p; // update solution
|
||||
residual -= alpha * tmp; // update residual
|
||||
normal_residual = mat.adjoint() * residual; // update residual of the normal equation
|
||||
|
||||
residualNorm2 = normal_residual.squaredNorm();
|
||||
if(residualNorm2 < threshold)
|
||||
break;
|
||||
|
||||
z = precond.solve(normal_residual); // approximately solve for "A'A z = normal_residual"
|
||||
|
||||
RealScalar absOld = absNew;
|
||||
absNew = numext::real(normal_residual.dot(z)); // update the absolute value of r
|
||||
RealScalar beta = absNew / absOld; // calculate the Gram-Schmidt value used to create the new search direction
|
||||
p = z + beta * p; // update search direction
|
||||
i++;
|
||||
}
|
||||
tol_error = sqrt(residualNorm2 / rhsNorm2);
|
||||
iters = i;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
template< typename _MatrixType,
|
||||
typename _Preconditioner = LeastSquareDiagonalPreconditioner<typename _MatrixType::Scalar> >
|
||||
class LeastSquaresConjugateGradient;
|
||||
|
||||
namespace internal {
|
||||
|
||||
template< typename _MatrixType, typename _Preconditioner>
|
||||
struct traits<LeastSquaresConjugateGradient<_MatrixType,_Preconditioner> >
|
||||
{
|
||||
typedef _MatrixType MatrixType;
|
||||
typedef _Preconditioner Preconditioner;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
/** \ingroup IterativeLinearSolvers_Module
|
||||
* \brief A conjugate gradient solver for sparse (or dense) least-square problems
|
||||
*
|
||||
* This class allows to solve for A x = b linear problems using an iterative conjugate gradient algorithm.
|
||||
* The matrix A can be non symmetric and rectangular, but the matrix A' A should be positive-definite to guaranty stability.
|
||||
* Otherwise, the SparseLU or SparseQR classes might be preferable.
|
||||
* The matrix A and the vectors x and b can be either dense or sparse.
|
||||
*
|
||||
* \tparam _MatrixType the type of the matrix A, can be a dense or a sparse matrix.
|
||||
* \tparam _Preconditioner the type of the preconditioner. Default is LeastSquareDiagonalPreconditioner
|
||||
*
|
||||
* The maximal number of iterations and tolerance value can be controlled via the setMaxIterations()
|
||||
* and setTolerance() methods. The defaults are the size of the problem for the maximal number of iterations
|
||||
* and NumTraits<Scalar>::epsilon() for the tolerance.
|
||||
*
|
||||
* This class can be used as the direct solver classes. Here is a typical usage example:
|
||||
\code
|
||||
int m=1000000, n = 10000;
|
||||
VectorXd x(n), b(m);
|
||||
SparseMatrix<double> A(m,n);
|
||||
// fill A and b
|
||||
LeastSquaresConjugateGradient<SparseMatrix<double> > lscg;
|
||||
lscg.compute(A);
|
||||
x = lscg.solve(b);
|
||||
std::cout << "#iterations: " << lscg.iterations() << std::endl;
|
||||
std::cout << "estimated error: " << lscg.error() << std::endl;
|
||||
// update b, and solve again
|
||||
x = lscg.solve(b);
|
||||
\endcode
|
||||
*
|
||||
* By default the iterations start with x=0 as an initial guess of the solution.
|
||||
* One can control the start using the solveWithGuess() method.
|
||||
*
|
||||
* \sa class ConjugateGradient, SparseLU, SparseQR
|
||||
*/
|
||||
template< typename _MatrixType, typename _Preconditioner>
|
||||
class LeastSquaresConjugateGradient : public IterativeSolverBase<LeastSquaresConjugateGradient<_MatrixType,_Preconditioner> >
|
||||
{
|
||||
typedef IterativeSolverBase<LeastSquaresConjugateGradient> Base;
|
||||
using Base::mp_matrix;
|
||||
using Base::m_error;
|
||||
using Base::m_iterations;
|
||||
using Base::m_info;
|
||||
using Base::m_isInitialized;
|
||||
public:
|
||||
typedef _MatrixType MatrixType;
|
||||
typedef typename MatrixType::Scalar Scalar;
|
||||
typedef typename MatrixType::RealScalar RealScalar;
|
||||
typedef _Preconditioner Preconditioner;
|
||||
|
||||
public:
|
||||
|
||||
/** Default constructor. */
|
||||
LeastSquaresConjugateGradient() : Base() {}
|
||||
|
||||
/** Initialize the solver with matrix \a A for further \c Ax=b solving.
|
||||
*
|
||||
* This constructor is a shortcut for the default constructor followed
|
||||
* by a call to compute().
|
||||
*
|
||||
* \warning this class stores a reference to the matrix A as well as some
|
||||
* precomputed values that depend on it. Therefore, if \a A is changed
|
||||
* this class becomes invalid. Call compute() to update it with the new
|
||||
* matrix A, or modify a copy of A.
|
||||
*/
|
||||
explicit LeastSquaresConjugateGradient(const MatrixType& A) : Base(A) {}
|
||||
|
||||
~LeastSquaresConjugateGradient() {}
|
||||
|
||||
/** \internal */
|
||||
template<typename Rhs,typename Dest>
|
||||
void _solve_with_guess_impl(const Rhs& b, Dest& x) const
|
||||
{
|
||||
m_iterations = Base::maxIterations();
|
||||
m_error = Base::m_tolerance;
|
||||
|
||||
for(Index j=0; j<b.cols(); ++j)
|
||||
{
|
||||
m_iterations = Base::maxIterations();
|
||||
m_error = Base::m_tolerance;
|
||||
|
||||
typename Dest::ColXpr xj(x,j);
|
||||
internal::least_square_conjugate_gradient(mp_matrix, b.col(j), xj, Base::m_preconditioner, m_iterations, m_error);
|
||||
}
|
||||
|
||||
m_isInitialized = true;
|
||||
m_info = m_error <= Base::m_tolerance ? Success : NoConvergence;
|
||||
}
|
||||
|
||||
/** \internal */
|
||||
using Base::_solve_impl;
|
||||
template<typename Rhs,typename Dest>
|
||||
void _solve_impl(const MatrixBase<Rhs>& b, Dest& x) const
|
||||
{
|
||||
x.setZero();
|
||||
_solve_with_guess_impl(b.derived(),x);
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
} // end namespace Eigen
|
||||
|
||||
#endif // EIGEN_LEAST_SQUARE_CONJUGATE_GRADIENT_H
|
||||
@@ -390,6 +390,12 @@ template<typename _MatrixType> class FullPivLU
|
||||
#endif
|
||||
|
||||
protected:
|
||||
|
||||
static void check_template_parameters()
|
||||
{
|
||||
EIGEN_STATIC_ASSERT_NON_INTEGER(Scalar);
|
||||
}
|
||||
|
||||
MatrixType m_lu;
|
||||
PermutationPType m_p;
|
||||
PermutationQType m_q;
|
||||
@@ -434,6 +440,8 @@ FullPivLU<MatrixType>::FullPivLU(const MatrixType& matrix)
|
||||
template<typename MatrixType>
|
||||
FullPivLU<MatrixType>& FullPivLU<MatrixType>::compute(const MatrixType& matrix)
|
||||
{
|
||||
check_template_parameters();
|
||||
|
||||
// the permutations are stored as int indices, so just to be sure:
|
||||
eigen_assert(matrix.rows()<=NumTraits<int>::highest() && matrix.cols()<=NumTraits<int>::highest());
|
||||
|
||||
@@ -459,14 +467,16 @@ FullPivLU<MatrixType>& FullPivLU<MatrixType>::compute(const MatrixType& matrix)
|
||||
|
||||
// biggest coefficient in the remaining bottom-right corner (starting at row k, col k)
|
||||
Index row_of_biggest_in_corner, col_of_biggest_in_corner;
|
||||
RealScalar biggest_in_corner;
|
||||
typedef internal::scalar_score_coeff_op<Scalar> Scoring;
|
||||
typedef typename Scoring::result_type Score;
|
||||
Score biggest_in_corner;
|
||||
biggest_in_corner = m_lu.bottomRightCorner(rows-k, cols-k)
|
||||
.cwiseAbs()
|
||||
.unaryExpr(Scoring())
|
||||
.maxCoeff(&row_of_biggest_in_corner, &col_of_biggest_in_corner);
|
||||
row_of_biggest_in_corner += k; // correct the values! since they were computed in the corner,
|
||||
col_of_biggest_in_corner += k; // need to add k to them.
|
||||
|
||||
if(biggest_in_corner==RealScalar(0))
|
||||
if(biggest_in_corner==Score(0))
|
||||
{
|
||||
// before exiting, make sure to initialize the still uninitialized transpositions
|
||||
// in a sane state without destroying what we already have.
|
||||
@@ -479,7 +489,8 @@ FullPivLU<MatrixType>& FullPivLU<MatrixType>::compute(const MatrixType& matrix)
|
||||
break;
|
||||
}
|
||||
|
||||
if(biggest_in_corner > m_maxpivot) m_maxpivot = biggest_in_corner;
|
||||
RealScalar abs_pivot = internal::abs_knowing_score<Scalar>()(m_lu(row_of_biggest_in_corner, col_of_biggest_in_corner), biggest_in_corner);
|
||||
if(abs_pivot > m_maxpivot) m_maxpivot = abs_pivot;
|
||||
|
||||
// Now that we've found the pivot, we need to apply the row/col swaps to
|
||||
// bring it to the location (k,k).
|
||||
|
||||
@@ -209,6 +209,12 @@ template<typename _MatrixType> class PartialPivLU
|
||||
#endif
|
||||
|
||||
protected:
|
||||
|
||||
static void check_template_parameters()
|
||||
{
|
||||
EIGEN_STATIC_ASSERT_NON_INTEGER(Scalar);
|
||||
}
|
||||
|
||||
MatrixType m_lu;
|
||||
PermutationType m_p;
|
||||
TranspositionType m_rowsTranspositions;
|
||||
@@ -275,6 +281,8 @@ struct partial_lu_impl
|
||||
*/
|
||||
static Index unblocked_lu(MatrixType& lu, PivIndex* row_transpositions, PivIndex& nb_transpositions)
|
||||
{
|
||||
typedef scalar_score_coeff_op<Scalar> Scoring;
|
||||
typedef typename Scoring::result_type Score;
|
||||
const Index rows = lu.rows();
|
||||
const Index cols = lu.cols();
|
||||
const Index size = (std::min)(rows,cols);
|
||||
@@ -286,13 +294,13 @@ struct partial_lu_impl
|
||||
Index rcols = cols-k-1;
|
||||
|
||||
Index row_of_biggest_in_col;
|
||||
RealScalar biggest_in_corner
|
||||
= lu.col(k).tail(rows-k).cwiseAbs().maxCoeff(&row_of_biggest_in_col);
|
||||
Score biggest_in_corner
|
||||
= lu.col(k).tail(rows-k).unaryExpr(Scoring()).maxCoeff(&row_of_biggest_in_col);
|
||||
row_of_biggest_in_col += k;
|
||||
|
||||
row_transpositions[k] = PivIndex(row_of_biggest_in_col);
|
||||
|
||||
if(biggest_in_corner != RealScalar(0))
|
||||
if(biggest_in_corner != Score(0))
|
||||
{
|
||||
if(k != row_of_biggest_in_col)
|
||||
{
|
||||
@@ -423,6 +431,8 @@ void partial_lu_inplace(MatrixType& lu, TranspositionType& row_transpositions, t
|
||||
template<typename MatrixType>
|
||||
PartialPivLU<MatrixType>& PartialPivLU<MatrixType>::compute(const MatrixType& matrix)
|
||||
{
|
||||
check_template_parameters();
|
||||
|
||||
// the row permutation is stored as int indices, so just to be sure:
|
||||
eigen_assert(matrix.rows()<NumTraits<int>::highest());
|
||||
|
||||
|
||||
@@ -137,22 +137,27 @@ void minimum_degree_ordering(SparseMatrix<Scalar,ColMajor,StorageIndex>& C, Perm
|
||||
degree[i] = len[i]; // degree of node i
|
||||
}
|
||||
mark = internal::cs_wclear<StorageIndex>(0, 0, w, n); /* clear w */
|
||||
elen[n] = -2; /* n is a dead element */
|
||||
Cp[n] = -1; /* n is a root of assembly tree */
|
||||
w[n] = 0; /* n is a dead element */
|
||||
|
||||
/* --- Initialize degree lists ------------------------------------------ */
|
||||
for(i = 0; i < n; i++)
|
||||
{
|
||||
bool has_diag = false;
|
||||
for(p = Cp[i]; p<Cp[i+1]; ++p)
|
||||
if(Ci[p]==i)
|
||||
{
|
||||
has_diag = true;
|
||||
break;
|
||||
}
|
||||
|
||||
d = degree[i];
|
||||
if(d == 0) /* node i is empty */
|
||||
if(d == 1) /* node i is empty */
|
||||
{
|
||||
elen[i] = -2; /* element i is dead */
|
||||
nel++;
|
||||
Cp[i] = -1; /* i is a root of assembly tree */
|
||||
w[i] = 0;
|
||||
}
|
||||
else if(d > dense) /* node i is dense */
|
||||
else if(d > dense || !has_diag) /* node i is dense or has no structural diagonal element */
|
||||
{
|
||||
nv[i] = 0; /* absorb i into element n */
|
||||
elen[i] = -1; /* node i is dead */
|
||||
@@ -168,6 +173,10 @@ void minimum_degree_ordering(SparseMatrix<Scalar,ColMajor,StorageIndex>& C, Perm
|
||||
}
|
||||
}
|
||||
|
||||
elen[n] = -2; /* n is a dead element */
|
||||
Cp[n] = -1; /* n is a root of assembly tree */
|
||||
w[n] = 0; /* n is a dead element */
|
||||
|
||||
while (nel < n) /* while (selecting pivots) do */
|
||||
{
|
||||
/* --- Select node of minimum approximate degree -------------------- */
|
||||
|
||||
@@ -90,11 +90,11 @@ class AMDOrdering
|
||||
* \note Returns an empty permutation matrix
|
||||
* \tparam Index The type of indices of the matrix
|
||||
*/
|
||||
template <typename Index>
|
||||
template <typename StorageIndex>
|
||||
class NaturalOrdering
|
||||
{
|
||||
public:
|
||||
typedef PermutationMatrix<Dynamic, Dynamic, Index> PermutationType;
|
||||
typedef PermutationMatrix<Dynamic, Dynamic, StorageIndex> PermutationType;
|
||||
|
||||
/** Compute the permutation vector from a column-major sparse matrix */
|
||||
template <typename MatrixType>
|
||||
|
||||
@@ -398,6 +398,12 @@ template<typename _MatrixType> class ColPivHouseholderQR
|
||||
#endif
|
||||
|
||||
protected:
|
||||
|
||||
static void check_template_parameters()
|
||||
{
|
||||
EIGEN_STATIC_ASSERT_NON_INTEGER(Scalar);
|
||||
}
|
||||
|
||||
MatrixType m_qr;
|
||||
HCoeffsType m_hCoeffs;
|
||||
PermutationType m_colsPermutation;
|
||||
@@ -436,6 +442,8 @@ typename MatrixType::RealScalar ColPivHouseholderQR<MatrixType>::logAbsDetermina
|
||||
template<typename MatrixType>
|
||||
ColPivHouseholderQR<MatrixType>& ColPivHouseholderQR<MatrixType>::compute(const MatrixType& matrix)
|
||||
{
|
||||
check_template_parameters();
|
||||
|
||||
using std::abs;
|
||||
Index rows = matrix.rows();
|
||||
Index cols = matrix.cols();
|
||||
|
||||
@@ -380,6 +380,12 @@ template<typename _MatrixType> class FullPivHouseholderQR
|
||||
#endif
|
||||
|
||||
protected:
|
||||
|
||||
static void check_template_parameters()
|
||||
{
|
||||
EIGEN_STATIC_ASSERT_NON_INTEGER(Scalar);
|
||||
}
|
||||
|
||||
MatrixType m_qr;
|
||||
HCoeffsType m_hCoeffs;
|
||||
IntDiagSizeVectorType m_rows_transpositions;
|
||||
@@ -419,6 +425,8 @@ typename MatrixType::RealScalar FullPivHouseholderQR<MatrixType>::logAbsDetermin
|
||||
template<typename MatrixType>
|
||||
FullPivHouseholderQR<MatrixType>& FullPivHouseholderQR<MatrixType>::compute(const MatrixType& matrix)
|
||||
{
|
||||
check_template_parameters();
|
||||
|
||||
using std::abs;
|
||||
Index rows = matrix.rows();
|
||||
Index cols = matrix.cols();
|
||||
@@ -443,13 +451,15 @@ FullPivHouseholderQR<MatrixType>& FullPivHouseholderQR<MatrixType>::compute(cons
|
||||
for (Index k = 0; k < size; ++k)
|
||||
{
|
||||
Index row_of_biggest_in_corner, col_of_biggest_in_corner;
|
||||
RealScalar biggest_in_corner;
|
||||
typedef internal::scalar_score_coeff_op<Scalar> Scoring;
|
||||
typedef typename Scoring::result_type Score;
|
||||
|
||||
biggest_in_corner = m_qr.bottomRightCorner(rows-k, cols-k)
|
||||
.cwiseAbs()
|
||||
.maxCoeff(&row_of_biggest_in_corner, &col_of_biggest_in_corner);
|
||||
Score score = m_qr.bottomRightCorner(rows-k, cols-k)
|
||||
.unaryExpr(Scoring())
|
||||
.maxCoeff(&row_of_biggest_in_corner, &col_of_biggest_in_corner);
|
||||
row_of_biggest_in_corner += k;
|
||||
col_of_biggest_in_corner += k;
|
||||
RealScalar biggest_in_corner = internal::abs_knowing_score<Scalar>()(m_qr(row_of_biggest_in_corner, col_of_biggest_in_corner), score);
|
||||
if(k==0) biggest = biggest_in_corner;
|
||||
|
||||
// if the corner is negligible, then we have less than full rank, and we can finish early
|
||||
|
||||
@@ -196,6 +196,12 @@ template<typename _MatrixType> class HouseholderQR
|
||||
#endif
|
||||
|
||||
protected:
|
||||
|
||||
static void check_template_parameters()
|
||||
{
|
||||
EIGEN_STATIC_ASSERT_NON_INTEGER(Scalar);
|
||||
}
|
||||
|
||||
MatrixType m_qr;
|
||||
HCoeffsType m_hCoeffs;
|
||||
RowVectorType m_temp;
|
||||
@@ -348,6 +354,8 @@ void HouseholderQR<_MatrixType>::_solve_impl(const RhsType &rhs, DstType &dst) c
|
||||
template<typename MatrixType>
|
||||
HouseholderQR<MatrixType>& HouseholderQR<MatrixType>::compute(const MatrixType& matrix)
|
||||
{
|
||||
check_template_parameters();
|
||||
|
||||
Index rows = matrix.rows();
|
||||
Index cols = matrix.cols();
|
||||
Index size = (std::min)(rows,cols);
|
||||
|
||||
@@ -130,9 +130,10 @@ public:
|
||||
inline Index rank() const
|
||||
{
|
||||
using std::abs;
|
||||
using std::max;
|
||||
eigen_assert(m_isInitialized && "JacobiSVD is not initialized.");
|
||||
if(m_singularValues.size()==0) return 0;
|
||||
RealScalar premultiplied_threshold = m_singularValues.coeff(0) * threshold();
|
||||
RealScalar premultiplied_threshold = (max)(m_singularValues.coeff(0) * threshold(), (std::numeric_limits<RealScalar>::min)());
|
||||
Index i = m_nonzeroSingularValues-1;
|
||||
while(i>=0 && m_singularValues.coeff(i) < premultiplied_threshold) --i;
|
||||
return i+1;
|
||||
@@ -217,6 +218,12 @@ public:
|
||||
#endif
|
||||
|
||||
protected:
|
||||
|
||||
static void check_template_parameters()
|
||||
{
|
||||
EIGEN_STATIC_ASSERT_NON_INTEGER(Scalar);
|
||||
}
|
||||
|
||||
// return true if already allocated
|
||||
bool allocate(Index rows, Index cols, unsigned int computationOptions) ;
|
||||
|
||||
@@ -240,7 +247,9 @@ protected:
|
||||
m_usePrescribedThreshold(false),
|
||||
m_computationOptions(0),
|
||||
m_rows(-1), m_cols(-1), m_diagSize(0)
|
||||
{}
|
||||
{
|
||||
check_template_parameters();
|
||||
}
|
||||
|
||||
|
||||
};
|
||||
|
||||
@@ -69,6 +69,7 @@ class SimplicialCholeskyBase : public SparseSolverBase<Derived>
|
||||
typedef SparseMatrix<Scalar,ColMajor,StorageIndex> CholMatrixType;
|
||||
typedef CholMatrixType const * ConstCholMatrixPtr;
|
||||
typedef Matrix<Scalar,Dynamic,1> VectorType;
|
||||
typedef Matrix<StorageIndex,Dynamic,1> VectorI;
|
||||
|
||||
public:
|
||||
|
||||
@@ -250,8 +251,8 @@ class SimplicialCholeskyBase : public SparseSolverBase<Derived>
|
||||
|
||||
CholMatrixType m_matrix;
|
||||
VectorType m_diag; // the diagonal coefficients (LDLT mode)
|
||||
VectorXi m_parent; // elimination tree
|
||||
VectorXi m_nonZerosPerCol;
|
||||
VectorI m_parent; // elimination tree
|
||||
VectorI m_nonZerosPerCol;
|
||||
PermutationMatrix<Dynamic,Dynamic,StorageIndex> m_P; // the permutation
|
||||
PermutationMatrix<Dynamic,Dynamic,StorageIndex> m_Pinv; // the inverse permutation
|
||||
|
||||
|
||||
@@ -86,7 +86,12 @@ class CompressedStorage
|
||||
void resize(Index size, double reserveSizeFactor = 0)
|
||||
{
|
||||
if (m_allocatedSize<size)
|
||||
reallocate(size + Index(reserveSizeFactor*double(size)));
|
||||
{
|
||||
Index realloc_size = (std::min<Index>)(NumTraits<StorageIndex>::highest(), size + Index(reserveSizeFactor*double(size)));
|
||||
if(realloc_size<size)
|
||||
internal::throw_std_bad_alloc();
|
||||
reallocate(realloc_size);
|
||||
}
|
||||
m_size = size;
|
||||
}
|
||||
|
||||
@@ -214,6 +219,9 @@ class CompressedStorage
|
||||
|
||||
inline void reallocate(Index size)
|
||||
{
|
||||
#ifdef EIGEN_SPARSE_COMPRESSED_STORAGE_REALLOCATE_PLUGIN
|
||||
EIGEN_SPARSE_COMPRESSED_STORAGE_REALLOCATE_PLUGIN
|
||||
#endif
|
||||
eigen_internal_assert(size!=m_allocatedSize);
|
||||
internal::scoped_array<Scalar> newValues(size);
|
||||
internal::scoped_array<StorageIndex> newIndices(size);
|
||||
|
||||
@@ -49,6 +49,16 @@ public:
|
||||
return nnz;
|
||||
}
|
||||
|
||||
inline const Scalar coeff(Index row, Index col) const
|
||||
{
|
||||
return m_matrix.coeff(row + (IsRowMajor ? m_outerStart : 0), col + (IsRowMajor ? 0 : m_outerStart));
|
||||
}
|
||||
|
||||
inline const Scalar coeff(Index index) const
|
||||
{
|
||||
return m_matrix.coeff(IsRowMajor ? m_outerStart : index, IsRowMajor ? index : m_outerStart);
|
||||
}
|
||||
|
||||
inline const _MatrixTypeNested& nestedExpression() const { return m_matrix; }
|
||||
Index startRow() const { return IsRowMajor ? m_outerStart : 0; }
|
||||
Index startCol() const { return IsRowMajor ? 0 : m_outerStart; }
|
||||
@@ -204,6 +214,21 @@ public:
|
||||
}
|
||||
|
||||
bool isCompressed() const { return m_matrix.innerNonZeroPtr()==0; }
|
||||
|
||||
inline Scalar& coeffRef(Index row, Index col)
|
||||
{
|
||||
return m_matrix.const_cast_derived().coeffRef(row + (IsRowMajor ? m_outerStart : 0), col + (IsRowMajor ? 0 : m_outerStart));
|
||||
}
|
||||
|
||||
inline const Scalar coeff(Index row, Index col) const
|
||||
{
|
||||
return m_matrix.coeff(row + (IsRowMajor ? m_outerStart : 0), col + (IsRowMajor ? 0 : m_outerStart));
|
||||
}
|
||||
|
||||
inline const Scalar coeff(Index index) const
|
||||
{
|
||||
return m_matrix.coeff(IsRowMajor ? m_outerStart : index, IsRowMajor ? index : m_outerStart);
|
||||
}
|
||||
|
||||
const Scalar& lastCoeff() const
|
||||
{
|
||||
|
||||
@@ -222,24 +222,18 @@ class SparseMatrix
|
||||
* The non zero coefficient must \b not already exist.
|
||||
*
|
||||
* If the matrix \c *this is in compressed mode, then \c *this is turned into uncompressed
|
||||
* mode while reserving room for 2 non zeros per inner vector. It is strongly recommended to first
|
||||
* call reserve(const SizesType &) to reserve a more appropriate number of elements per
|
||||
* inner vector that better match your scenario.
|
||||
* mode while reserving room for 2 x this->innerSize() non zeros if reserve(Index) has not been called earlier.
|
||||
* In this case, the insertion procedure is optimized for a \e sequential insertion mode where elements are assumed to be
|
||||
* inserted by increasing outer-indices.
|
||||
*
|
||||
* If that's not the case, then it is strongly recommended to either use a triplet-list to assemble the matrix, or to first
|
||||
* call reserve(const SizesType &) to reserve the appropriate number of non-zero elements per inner vector.
|
||||
*
|
||||
* This function performs a sorted insertion in O(1) if the elements of each inner vector are
|
||||
* inserted in increasing inner index order, and in O(nnz_j) for a random insertion.
|
||||
* Assuming memory has been appropriately reserved, this function performs a sorted insertion in O(1)
|
||||
* if the elements of each inner vector are inserted in increasing inner index order, and in O(nnz_j) for a random insertion.
|
||||
*
|
||||
*/
|
||||
Scalar& insert(Index row, Index col)
|
||||
{
|
||||
eigen_assert(row>=0 && row<rows() && col>=0 && col<cols());
|
||||
|
||||
if(isCompressed())
|
||||
{
|
||||
reserve(IndexVector::Constant(outerSize(), 2));
|
||||
}
|
||||
return insertUncompressed(row,col);
|
||||
}
|
||||
Scalar& insert(Index row, Index col);
|
||||
|
||||
public:
|
||||
|
||||
@@ -1076,6 +1070,118 @@ EIGEN_DONT_INLINE SparseMatrix<Scalar,_Options,_Index>& SparseMatrix<Scalar,_Opt
|
||||
}
|
||||
}
|
||||
|
||||
template<typename _Scalar, int _Options, typename _Index>
|
||||
typename SparseMatrix<_Scalar,_Options,_Index>::Scalar& SparseMatrix<_Scalar,_Options,_Index>::insert(Index row, Index col)
|
||||
{
|
||||
eigen_assert(row>=0 && row<rows() && col>=0 && col<cols());
|
||||
|
||||
const Index outer = IsRowMajor ? row : col;
|
||||
const Index inner = IsRowMajor ? col : row;
|
||||
|
||||
if(isCompressed())
|
||||
{
|
||||
if(nonZeros()==0)
|
||||
{
|
||||
// reserve space if not already done
|
||||
if(m_data.allocatedSize()==0)
|
||||
m_data.reserve(2*m_innerSize);
|
||||
|
||||
// turn the matrix into non-compressed mode
|
||||
m_innerNonZeros = static_cast<StorageIndex*>(std::malloc(m_outerSize * sizeof(StorageIndex)));
|
||||
if(!m_innerNonZeros) internal::throw_std_bad_alloc();
|
||||
|
||||
memset(m_innerNonZeros, 0, (m_outerSize)*sizeof(StorageIndex));
|
||||
|
||||
// pack all inner-vectors to the end of the pre-allocated space
|
||||
// and allocate the entire free-space to the first inner-vector
|
||||
StorageIndex end = convert_index(m_data.allocatedSize());
|
||||
for(Index j=1; j<=m_outerSize; ++j)
|
||||
m_outerIndex[j] = end;
|
||||
}
|
||||
}
|
||||
|
||||
// check whether we can do a fast "push back" insertion
|
||||
Index data_end = m_data.allocatedSize();
|
||||
|
||||
// First case: we are filling a new inner vector which is packed at the end.
|
||||
// We assume that all remaining inner-vectors are also empty and packed to the end.
|
||||
if(m_outerIndex[outer]==data_end)
|
||||
{
|
||||
eigen_internal_assert(m_innerNonZeros[outer]==0);
|
||||
|
||||
// pack previous empty inner-vectors to end of the used-space
|
||||
// and allocate the entire free-space to the current inner-vector.
|
||||
StorageIndex p = convert_index(m_data.size());
|
||||
Index j = outer;
|
||||
while(j>=0 && m_innerNonZeros[j]==0)
|
||||
m_outerIndex[j--] = p;
|
||||
|
||||
// push back the new element
|
||||
++m_innerNonZeros[outer];
|
||||
m_data.append(Scalar(0), inner);
|
||||
|
||||
// check for reallocation
|
||||
if(data_end != m_data.allocatedSize())
|
||||
{
|
||||
// m_data has been reallocated
|
||||
// -> move remaining inner-vectors back to the end of the free-space
|
||||
// so that the entire free-space is allocated to the current inner-vector.
|
||||
eigen_internal_assert(data_end < m_data.allocatedSize());
|
||||
StorageIndex new_end = convert_index(m_data.allocatedSize());
|
||||
for(Index j=outer+1; j<=m_outerSize; ++j)
|
||||
if(m_outerIndex[j]==data_end)
|
||||
m_outerIndex[j] = new_end;
|
||||
}
|
||||
return m_data.value(p);
|
||||
}
|
||||
|
||||
// Second case: the next inner-vector is packed to the end
|
||||
// and the current inner-vector end match the used-space.
|
||||
if(m_outerIndex[outer+1]==data_end && m_outerIndex[outer]+m_innerNonZeros[outer]==m_data.size())
|
||||
{
|
||||
eigen_internal_assert(outer+1==m_outerSize || m_innerNonZeros[outer+1]==0);
|
||||
|
||||
// add space for the new element
|
||||
++m_innerNonZeros[outer];
|
||||
m_data.resize(m_data.size()+1);
|
||||
|
||||
// check for reallocation
|
||||
if(data_end != m_data.allocatedSize())
|
||||
{
|
||||
// m_data has been reallocated
|
||||
// -> move remaining inner-vectors back to the end of the free-space
|
||||
// so that the entire free-space is allocated to the current inner-vector.
|
||||
eigen_internal_assert(data_end < m_data.allocatedSize());
|
||||
StorageIndex new_end = convert_index(m_data.allocatedSize());
|
||||
for(Index j=outer+1; j<=m_outerSize; ++j)
|
||||
if(m_outerIndex[j]==data_end)
|
||||
m_outerIndex[j] = new_end;
|
||||
}
|
||||
|
||||
// and insert it at the right position (sorted insertion)
|
||||
Index startId = m_outerIndex[outer];
|
||||
Index p = m_outerIndex[outer]+m_innerNonZeros[outer]-1;
|
||||
while ( (p > startId) && (m_data.index(p-1) > inner) )
|
||||
{
|
||||
m_data.index(p) = m_data.index(p-1);
|
||||
m_data.value(p) = m_data.value(p-1);
|
||||
--p;
|
||||
}
|
||||
|
||||
m_data.index(p) = convert_index(inner);
|
||||
return (m_data.value(p) = 0);
|
||||
}
|
||||
|
||||
if(m_data.size() != m_data.allocatedSize())
|
||||
{
|
||||
// make sure the matrix is compatible to random un-compressed insertion:
|
||||
m_data.resize(m_data.allocatedSize());
|
||||
this->reserveInnerVectors(Array<StorageIndex,Dynamic,1>::Constant(2*m_outerSize, convert_index(m_outerSize)));
|
||||
}
|
||||
|
||||
return insertUncompressed(row,col);
|
||||
}
|
||||
|
||||
template<typename _Scalar, int _Options, typename _Index>
|
||||
EIGEN_DONT_INLINE typename SparseMatrix<_Scalar,_Options,_Index>::Scalar& SparseMatrix<_Scalar,_Options,_Index>::insertUncompressed(Index row, Index col)
|
||||
{
|
||||
|
||||
@@ -97,7 +97,6 @@ template<typename Derived> class SparseMatrixBase : public EigenBase<Derived>
|
||||
Transpose<const Derived>
|
||||
>::type AdjointReturnType;
|
||||
typedef Transpose<Derived> TransposeReturnType;
|
||||
template<unsigned int UpLo> struct SelfAdjointViewReturnType { typedef SelfAdjointView<Derived, UpLo> Type; };
|
||||
typedef typename internal::add_const<Transpose<const Derived> >::type ConstTransposeReturnType;
|
||||
|
||||
// FIXME storage order do not match evaluator storage order
|
||||
@@ -300,9 +299,14 @@ template<typename Derived> class SparseMatrixBase : public EigenBase<Derived>
|
||||
|
||||
template<int Mode>
|
||||
inline const TriangularView<const Derived, Mode> triangularView() const;
|
||||
|
||||
template<unsigned int UpLo> struct SelfAdjointViewReturnType { typedef SparseSelfAdjointView<Derived, UpLo> Type; };
|
||||
template<unsigned int UpLo> struct ConstSelfAdjointViewReturnType { typedef const SparseSelfAdjointView<const Derived, UpLo> Type; };
|
||||
|
||||
template<unsigned int UpLo> inline const SparseSelfAdjointView<const Derived, UpLo> selfadjointView() const;
|
||||
template<unsigned int UpLo> inline SparseSelfAdjointView<Derived, UpLo> selfadjointView();
|
||||
template<unsigned int UpLo> inline
|
||||
typename ConstSelfAdjointViewReturnType<UpLo>::Type selfadjointView() const;
|
||||
template<unsigned int UpLo> inline
|
||||
typename SelfAdjointViewReturnType<UpLo>::Type selfadjointView();
|
||||
|
||||
template<typename OtherDerived> Scalar dot(const MatrixBase<OtherDerived>& other) const;
|
||||
template<typename OtherDerived> Scalar dot(const SparseMatrixBase<OtherDerived>& other) const;
|
||||
|
||||
@@ -169,17 +169,17 @@ template<typename MatrixType, unsigned int _Mode> class SparseSelfAdjointView
|
||||
***************************************************************************/
|
||||
|
||||
template<typename Derived>
|
||||
template<unsigned int Mode>
|
||||
const SparseSelfAdjointView<const Derived, Mode> SparseMatrixBase<Derived>::selfadjointView() const
|
||||
template<unsigned int UpLo>
|
||||
typename SparseMatrixBase<Derived>::template ConstSelfAdjointViewReturnType<UpLo>::Type SparseMatrixBase<Derived>::selfadjointView() const
|
||||
{
|
||||
return SparseSelfAdjointView<const Derived, Mode>(derived());
|
||||
return SparseSelfAdjointView<const Derived, UpLo>(derived());
|
||||
}
|
||||
|
||||
template<typename Derived>
|
||||
template<unsigned int Mode>
|
||||
SparseSelfAdjointView<Derived, Mode> SparseMatrixBase<Derived>::selfadjointView()
|
||||
template<unsigned int UpLo>
|
||||
typename SparseMatrixBase<Derived>::template SelfAdjointViewReturnType<UpLo>::Type SparseMatrixBase<Derived>::selfadjointView()
|
||||
{
|
||||
return SparseSelfAdjointView<Derived, Mode>(derived());
|
||||
return SparseSelfAdjointView<Derived, UpLo>(derived());
|
||||
}
|
||||
|
||||
/***************************************************************************
|
||||
|
||||
Reference in New Issue
Block a user