mirror of
https://gitlab.com/libeigen/eigen.git
synced 2025-06-04 18:54:00 +08:00
Merge latest changes from upstream
This commit is contained in:
commit
fbc39fd02c
@ -28,7 +28,7 @@ endif()
|
||||
|
||||
|
||||
#############################################################################
|
||||
# retrieve version infomation #
|
||||
# retrieve version information #
|
||||
#############################################################################
|
||||
|
||||
# automatically parse the version number
|
||||
@ -416,16 +416,15 @@ add_subdirectory(Eigen)
|
||||
|
||||
add_subdirectory(doc EXCLUDE_FROM_ALL)
|
||||
|
||||
include(EigenConfigureTesting)
|
||||
option(BUILD_TESTING "Enable creation of Eigen tests." ON)
|
||||
if(BUILD_TESTING)
|
||||
include(EigenConfigureTesting)
|
||||
|
||||
# fixme, not sure this line is still needed:
|
||||
enable_testing() # must be called from the root CMakeLists, see man page
|
||||
|
||||
|
||||
if(EIGEN_LEAVE_TEST_IN_ALL_TARGET)
|
||||
if(EIGEN_LEAVE_TEST_IN_ALL_TARGET)
|
||||
add_subdirectory(test) # can't do EXCLUDE_FROM_ALL here, breaks CTest
|
||||
else()
|
||||
else()
|
||||
add_subdirectory(test EXCLUDE_FROM_ALL)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if(EIGEN_LEAVE_TEST_IN_ALL_TARGET)
|
||||
@ -461,7 +460,9 @@ endif(NOT WIN32)
|
||||
|
||||
configure_file(scripts/cdashtesting.cmake.in cdashtesting.cmake @ONLY)
|
||||
|
||||
ei_testing_print_summary()
|
||||
if(BUILD_TESTING)
|
||||
ei_testing_print_summary()
|
||||
endif()
|
||||
|
||||
message(STATUS "")
|
||||
message(STATUS "Configured Eigen ${EIGEN_VERSION_NUMBER}")
|
||||
@ -541,7 +542,8 @@ if (NOT CMAKE_VERSION VERSION_LESS 3.0)
|
||||
set (_Eigen3_CMAKE_SIZEOF_VOID_P ${CMAKE_SIZEOF_VOID_P})
|
||||
unset (CMAKE_SIZEOF_VOID_P)
|
||||
write_basic_package_version_file (Eigen3ConfigVersion.cmake
|
||||
VERSION ${EIGEN_VERSION_NUMBER} COMPATIBILITY SameMajorVersion)
|
||||
VERSION ${EIGEN_VERSION_NUMBER}
|
||||
COMPATIBILITY SameMajorVersion)
|
||||
set (CMAKE_SIZEOF_VOID_P ${_Eigen3_CMAKE_SIZEOF_VOID_P})
|
||||
|
||||
# The Eigen target will be located in the Eigen3 namespace. Other CMake
|
||||
@ -551,13 +553,8 @@ if (NOT CMAKE_VERSION VERSION_LESS 3.0)
|
||||
# CMake even if it has not been installed to a standard directory.
|
||||
export (PACKAGE Eigen3)
|
||||
|
||||
install (EXPORT Eigen3Targets NAMESPACE Eigen3:: DESTINATION
|
||||
${CMAKEPACKAGE_INSTALL_DIR})
|
||||
install (FILES
|
||||
${CMAKE_CURRENT_BINARY_DIR}/Eigen3Config.cmake
|
||||
${CMAKE_CURRENT_BINARY_DIR}/Eigen3ConfigVersion.cmake
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/cmake/UseEigen3.cmake
|
||||
DESTINATION ${CMAKEPACKAGE_INSTALL_DIR})
|
||||
install (EXPORT Eigen3Targets NAMESPACE Eigen3:: DESTINATION ${CMAKEPACKAGE_INSTALL_DIR})
|
||||
|
||||
else (NOT CMAKE_VERSION VERSION_LESS 3.0)
|
||||
# Fallback to legacy Eigen3Config.cmake without the imported target
|
||||
|
||||
@ -581,16 +578,20 @@ else (NOT CMAKE_VERSION VERSION_LESS 3.0)
|
||||
set(PACKAGE_EIGEN_ROOT_DIR ${EIGEN_ROOT_DIR})
|
||||
configure_file ( ${CMAKE_CURRENT_SOURCE_DIR}/cmake/Eigen3ConfigLegacy.cmake.in
|
||||
${CMAKE_CURRENT_BINARY_DIR}/Eigen3Config.cmake
|
||||
@ONLY ESCAPE_QUOTES
|
||||
)
|
||||
@ONLY ESCAPE_QUOTES )
|
||||
endif()
|
||||
|
||||
install ( FILES ${CMAKE_CURRENT_SOURCE_DIR}/cmake/UseEigen3.cmake
|
||||
${CMAKE_CURRENT_BINARY_DIR}/Eigen3Config.cmake
|
||||
DESTINATION ${CMAKEPACKAGE_INSTALL_DIR}
|
||||
)
|
||||
write_basic_package_version_file( Eigen3ConfigVersion.cmake
|
||||
VERSION ${EIGEN_VERSION_NUMBER}
|
||||
COMPATIBILITY SameMajorVersion )
|
||||
|
||||
endif (NOT CMAKE_VERSION VERSION_LESS 3.0)
|
||||
|
||||
install ( FILES ${CMAKE_CURRENT_SOURCE_DIR}/cmake/UseEigen3.cmake
|
||||
${CMAKE_CURRENT_BINARY_DIR}/Eigen3Config.cmake
|
||||
${CMAKE_CURRENT_BINARY_DIR}/Eigen3ConfigVersion.cmake
|
||||
DESTINATION ${CMAKEPACKAGE_INSTALL_DIR} )
|
||||
|
||||
# Add uninstall target
|
||||
add_custom_target ( uninstall
|
||||
COMMAND ${CMAKE_COMMAND} -P ${CMAKE_CURRENT_SOURCE_DIR}/cmake/EigenUninstall.cmake)
|
||||
|
15
Eigen/Core
15
Eigen/Core
@ -141,6 +141,11 @@
|
||||
#endif
|
||||
#ifdef __AVX2__
|
||||
#define EIGEN_VECTORIZE_AVX2
|
||||
#define EIGEN_VECTORIZE_AVX
|
||||
#define EIGEN_VECTORIZE_SSE3
|
||||
#define EIGEN_VECTORIZE_SSSE3
|
||||
#define EIGEN_VECTORIZE_SSE4_1
|
||||
#define EIGEN_VECTORIZE_SSE4_2
|
||||
#endif
|
||||
#ifdef __FMA__
|
||||
#define EIGEN_VECTORIZE_FMA
|
||||
@ -332,12 +337,16 @@ inline static const char *SimdInstructionSetsInUse(void) {
|
||||
#error Eigen2-support is only available up to version 3.2. Please go to "http://eigen.tuxfamily.org/index.php?title=Eigen2" for further information
|
||||
#endif
|
||||
|
||||
namespace Eigen {
|
||||
|
||||
// we use size_t frequently and we'll never remember to prepend it with std:: everytime just to
|
||||
// ensure QNX/QCC support
|
||||
using std::size_t;
|
||||
// gcc 4.6.0 wants std:: for ptrdiff_t
|
||||
using std::ptrdiff_t;
|
||||
|
||||
}
|
||||
|
||||
/** \defgroup Core_Module Core module
|
||||
* This is the main module of Eigen providing dense matrix and vector support
|
||||
* (both fixed and dynamic size) with all the features corresponding to a BLAS library
|
||||
@ -354,6 +363,9 @@ using std::ptrdiff_t;
|
||||
#include "src/Core/util/StaticAssert.h"
|
||||
#include "src/Core/util/XprHelper.h"
|
||||
#include "src/Core/util/Memory.h"
|
||||
#include "src/Core/util/IntegralConstant.h"
|
||||
#include "src/Core/util/SymbolicIndex.h"
|
||||
|
||||
|
||||
#include "src/Core/NumTraits.h"
|
||||
#include "src/Core/MathFunctions.h"
|
||||
@ -418,6 +430,8 @@ using std::ptrdiff_t;
|
||||
// on CUDA devices
|
||||
#include "src/Core/arch/CUDA/Complex.h"
|
||||
|
||||
#include "src/Core/util/IndexedViewHelper.h"
|
||||
#include "src/Core/ArithmeticSequence.h"
|
||||
#include "src/Core/DenseCoeffsBase.h"
|
||||
#include "src/Core/DenseBase.h"
|
||||
#include "src/Core/MatrixBase.h"
|
||||
@ -458,6 +472,7 @@ using std::ptrdiff_t;
|
||||
#include "src/Core/Ref.h"
|
||||
#include "src/Core/Block.h"
|
||||
#include "src/Core/VectorBlock.h"
|
||||
#include "src/Core/IndexedView.h"
|
||||
#include "src/Core/Transpose.h"
|
||||
#include "src/Core/DiagonalMatrix.h"
|
||||
#include "src/Core/Diagonal.h"
|
||||
|
@ -14,7 +14,7 @@
|
||||
|
||||
#include "src/Core/util/DisableStupidWarnings.h"
|
||||
|
||||
void *qMalloc(size_t size)
|
||||
void *qMalloc(std::size_t size)
|
||||
{
|
||||
return Eigen::internal::aligned_malloc(size);
|
||||
}
|
||||
@ -24,7 +24,7 @@ void qFree(void *ptr)
|
||||
Eigen::internal::aligned_free(ptr);
|
||||
}
|
||||
|
||||
void *qRealloc(void *ptr, size_t size)
|
||||
void *qRealloc(void *ptr, std::size_t size)
|
||||
{
|
||||
void* newPtr = Eigen::internal::aligned_malloc(size);
|
||||
memcpy(newPtr, ptr, size);
|
||||
|
@ -190,9 +190,9 @@ template<typename _StorageIndex> cholmod_sparse* cm_spsolve (int sys, chol
|
||||
template<> cholmod_sparse* cm_spsolve<long> (int sys, cholmod_factor& L, cholmod_sparse& B, cholmod_common &Common) { return cholmod_l_spsolve (sys, &L, &B, &Common); }
|
||||
|
||||
template<typename _StorageIndex>
|
||||
int cm_factorize_p (cholmod_sparse* A, double beta[2], _StorageIndex* fset, size_t fsize, cholmod_factor* L, cholmod_common &Common) { return cholmod_factorize_p (A, beta, fset, fsize, L, &Common); }
|
||||
int cm_factorize_p (cholmod_sparse* A, double beta[2], _StorageIndex* fset, std::size_t fsize, cholmod_factor* L, cholmod_common &Common) { return cholmod_factorize_p (A, beta, fset, fsize, L, &Common); }
|
||||
template<>
|
||||
int cm_factorize_p<long> (cholmod_sparse* A, double beta[2], long* fset, size_t fsize, cholmod_factor* L, cholmod_common &Common) { return cholmod_l_factorize_p (A, beta, fset, fsize, L, &Common); }
|
||||
int cm_factorize_p<long> (cholmod_sparse* A, double beta[2], long* fset, std::size_t fsize, cholmod_factor* L, cholmod_common &Common) { return cholmod_l_factorize_p (A, beta, fset, fsize, L, &Common); }
|
||||
|
||||
#undef EIGEN_CHOLMOD_SPECIALIZE0
|
||||
#undef EIGEN_CHOLMOD_SPECIALIZE1
|
||||
|
350
Eigen/src/Core/ArithmeticSequence.h
Normal file
350
Eigen/src/Core/ArithmeticSequence.h
Normal file
@ -0,0 +1,350 @@
|
||||
// This file is part of Eigen, a lightweight C++ template library
|
||||
// for linear algebra.
|
||||
//
|
||||
// Copyright (C) 2017 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_ARITHMETIC_SEQUENCE_H
|
||||
#define EIGEN_ARITHMETIC_SEQUENCE_H
|
||||
|
||||
namespace Eigen {
|
||||
|
||||
namespace internal {
|
||||
|
||||
#if !EIGEN_HAS_CXX11
|
||||
template<typename T> struct aseq_negate {};
|
||||
|
||||
template<> struct aseq_negate<Index> {
|
||||
typedef Index type;
|
||||
};
|
||||
|
||||
template<int N> struct aseq_negate<FixedInt<N> > {
|
||||
typedef FixedInt<-N> type;
|
||||
};
|
||||
|
||||
// Compilation error in the following case:
|
||||
template<> struct aseq_negate<FixedInt<DynamicIndex> > {};
|
||||
|
||||
template<typename FirstType,typename SizeType,typename IncrType,
|
||||
bool FirstIsSymbolic=Symbolic::is_symbolic<FirstType>::value,
|
||||
bool SizeIsSymbolic =Symbolic::is_symbolic<SizeType>::value>
|
||||
struct aseq_reverse_first_type {
|
||||
typedef Index type;
|
||||
};
|
||||
|
||||
template<typename FirstType,typename SizeType,typename IncrType>
|
||||
struct aseq_reverse_first_type<FirstType,SizeType,IncrType,true,true> {
|
||||
typedef Symbolic::AddExpr<FirstType,
|
||||
Symbolic::ProductExpr<Symbolic::AddExpr<SizeType,Symbolic::ValueExpr<FixedInt<-1> > >,
|
||||
Symbolic::ValueExpr<IncrType> >
|
||||
> type;
|
||||
};
|
||||
|
||||
template<typename SizeType,typename IncrType,typename EnableIf = void>
|
||||
struct aseq_reverse_first_type_aux {
|
||||
typedef Index type;
|
||||
};
|
||||
|
||||
template<typename SizeType,typename IncrType>
|
||||
struct aseq_reverse_first_type_aux<SizeType,IncrType,typename internal::enable_if<bool((SizeType::value+IncrType::value)|0x1)>::type> {
|
||||
typedef FixedInt<(SizeType::value-1)*IncrType::value> type;
|
||||
};
|
||||
|
||||
template<typename FirstType,typename SizeType,typename IncrType>
|
||||
struct aseq_reverse_first_type<FirstType,SizeType,IncrType,true,false> {
|
||||
typedef typename aseq_reverse_first_type_aux<SizeType,IncrType>::type Aux;
|
||||
typedef Symbolic::AddExpr<FirstType,Symbolic::ValueExpr<Aux> > type;
|
||||
};
|
||||
|
||||
template<typename FirstType,typename SizeType,typename IncrType>
|
||||
struct aseq_reverse_first_type<FirstType,SizeType,IncrType,false,true> {
|
||||
typedef Symbolic::AddExpr<Symbolic::ProductExpr<Symbolic::AddExpr<SizeType,Symbolic::ValueExpr<FixedInt<-1> > >,
|
||||
Symbolic::ValueExpr<IncrType> >,
|
||||
Symbolic::ValueExpr<> > type;
|
||||
};
|
||||
#endif
|
||||
|
||||
// Helper to cleanup the type of the increment:
|
||||
template<typename T> struct cleanup_seq_incr {
|
||||
typedef typename cleanup_index_type<T,DynamicIndex>::type type;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------
|
||||
// seq(first,last,incr) and seqN(first,size,incr)
|
||||
//--------------------------------------------------------------------------------
|
||||
|
||||
template<typename FirstType=Index,typename SizeType=Index,typename IncrType=internal::FixedInt<1> >
|
||||
class ArithmeticSequence;
|
||||
|
||||
template<typename FirstType,typename SizeType,typename IncrType>
|
||||
ArithmeticSequence<typename internal::cleanup_index_type<FirstType>::type,
|
||||
typename internal::cleanup_index_type<SizeType>::type,
|
||||
typename internal::cleanup_seq_incr<IncrType>::type >
|
||||
seqN(FirstType first, SizeType size, IncrType incr);
|
||||
|
||||
/** \class ArithmeticSequence
|
||||
* \ingroup Core_Module
|
||||
*
|
||||
* This class represents an arithmetic progression \f$ a_0, a_1, a_2, ..., a_{n-1}\f$ defined by
|
||||
* its \em first value \f$ a_0 \f$, its \em size (aka length) \em n, and the \em increment (aka stride)
|
||||
* that is equal to \f$ a_{i+1}-a_{i}\f$ for any \em i.
|
||||
*
|
||||
* It is internally used as the return type of the Eigen::seq and Eigen::seqN functions, and as the input arguments
|
||||
* of DenseBase::operator()(const RowIndices&, const ColIndices&), and most of the time this is the
|
||||
* only way it is used.
|
||||
*
|
||||
* \tparam FirstType type of the first element, usually an Index,
|
||||
* but internally it can be a symbolic expression
|
||||
* \tparam SizeType type representing the size of the sequence, usually an Index
|
||||
* or a compile time integral constant. Internally, it can also be a symbolic expression
|
||||
* \tparam IncrType type of the increment, can be a runtime Index, or a compile time integral constant (default is compile-time 1)
|
||||
*
|
||||
* \sa Eigen::seq, Eigen::seqN, DenseBase::operator()(const RowIndices&, const ColIndices&), class IndexedView
|
||||
*/
|
||||
template<typename FirstType,typename SizeType,typename IncrType>
|
||||
class ArithmeticSequence
|
||||
{
|
||||
public:
|
||||
ArithmeticSequence(FirstType first, SizeType size) : m_first(first), m_size(size) {}
|
||||
ArithmeticSequence(FirstType first, SizeType size, IncrType incr) : m_first(first), m_size(size), m_incr(incr) {}
|
||||
|
||||
enum {
|
||||
SizeAtCompileTime = internal::get_fixed_value<SizeType>::value,
|
||||
IncrAtCompileTime = internal::get_fixed_value<IncrType,DynamicIndex>::value
|
||||
};
|
||||
|
||||
/** \returns the size, i.e., number of elements, of the sequence */
|
||||
Index size() const { return m_size; }
|
||||
|
||||
/** \returns the first element \f$ a_0 \f$ in the sequence */
|
||||
Index first() const { return m_first; }
|
||||
|
||||
/** \returns the value \f$ a_i \f$ at index \a i in the sequence. */
|
||||
Index operator[](Index i) const { return m_first + i * m_incr; }
|
||||
|
||||
const FirstType& firstObject() const { return m_first; }
|
||||
const SizeType& sizeObject() const { return m_size; }
|
||||
const IncrType& incrObject() const { return m_incr; }
|
||||
|
||||
protected:
|
||||
FirstType m_first;
|
||||
SizeType m_size;
|
||||
IncrType m_incr;
|
||||
|
||||
public:
|
||||
|
||||
#if EIGEN_HAS_CXX11
|
||||
auto reverse() const -> decltype(Eigen::seqN(m_first+(m_size+fix<-1>())*m_incr,m_size,-m_incr)) {
|
||||
return seqN(m_first+(m_size+fix<-1>())*m_incr,m_size,-m_incr);
|
||||
}
|
||||
#else
|
||||
protected:
|
||||
typedef typename internal::aseq_negate<IncrType>::type ReverseIncrType;
|
||||
typedef typename internal::aseq_reverse_first_type<FirstType,SizeType,IncrType>::type ReverseFirstType;
|
||||
public:
|
||||
ArithmeticSequence<ReverseFirstType,SizeType,ReverseIncrType>
|
||||
reverse() const {
|
||||
return seqN(m_first+(m_size+fix<-1>())*m_incr,m_size,-m_incr);
|
||||
}
|
||||
#endif
|
||||
};
|
||||
|
||||
/** \returns an ArithmeticSequence starting at \a first, of length \a size, and increment \a incr
|
||||
*
|
||||
* \sa seqN(FirstType,SizeType), seq(FirstType,LastType,IncrType) */
|
||||
template<typename FirstType,typename SizeType,typename IncrType>
|
||||
ArithmeticSequence<typename internal::cleanup_index_type<FirstType>::type,typename internal::cleanup_index_type<SizeType>::type,typename internal::cleanup_seq_incr<IncrType>::type >
|
||||
seqN(FirstType first, SizeType size, IncrType incr) {
|
||||
return ArithmeticSequence<typename internal::cleanup_index_type<FirstType>::type,typename internal::cleanup_index_type<SizeType>::type,typename internal::cleanup_seq_incr<IncrType>::type>(first,size,incr);
|
||||
}
|
||||
|
||||
/** \returns an ArithmeticSequence starting at \a first, of length \a size, and unit increment
|
||||
*
|
||||
* \sa seqN(FirstType,SizeType,IncrType), seq(FirstType,LastType) */
|
||||
template<typename FirstType,typename SizeType>
|
||||
ArithmeticSequence<typename internal::cleanup_index_type<FirstType>::type,typename internal::cleanup_index_type<SizeType>::type >
|
||||
seqN(FirstType first, SizeType size) {
|
||||
return ArithmeticSequence<typename internal::cleanup_index_type<FirstType>::type,typename internal::cleanup_index_type<SizeType>::type>(first,size);
|
||||
}
|
||||
|
||||
#ifdef EIGEN_PARSED_BY_DOXYGEN
|
||||
|
||||
/** \returns an ArithmeticSequence starting at \a f, up (or down) to \a l, and with positive (or negative) increment \a incr
|
||||
*
|
||||
* It is essentially an alias to:
|
||||
* \code
|
||||
* seqN(f, (l-f+incr)/incr, incr);
|
||||
* \endcode
|
||||
*
|
||||
* \sa seqN(FirstType,SizeType,IncrType), seq(FirstType,LastType)
|
||||
*/
|
||||
template<typename FirstType,typename LastType, typename IncrType>
|
||||
auto seq(FirstType f, LastType l, IncrType incr);
|
||||
|
||||
/** \returns an ArithmeticSequence starting at \a f, up (or down) to \a l, and unit increment
|
||||
*
|
||||
* It is essentially an alias to:
|
||||
* \code
|
||||
* seqN(f,l-f+1);
|
||||
* \endcode
|
||||
*
|
||||
* \sa seqN(FirstType,SizeType), seq(FirstType,LastType,IncrType)
|
||||
*/
|
||||
template<typename FirstType,typename LastType>
|
||||
auto seq(FirstType f, LastType l);
|
||||
|
||||
#else // EIGEN_PARSED_BY_DOXYGEN
|
||||
|
||||
#if EIGEN_HAS_CXX11
|
||||
template<typename FirstType,typename LastType>
|
||||
auto seq(FirstType f, LastType l) -> decltype(seqN(typename internal::cleanup_index_type<FirstType>::type(f),
|
||||
( typename internal::cleanup_index_type<LastType>::type(l)
|
||||
- typename internal::cleanup_index_type<FirstType>::type(f)+fix<1>())))
|
||||
{
|
||||
return seqN(typename internal::cleanup_index_type<FirstType>::type(f),
|
||||
(typename internal::cleanup_index_type<LastType>::type(l)
|
||||
-typename internal::cleanup_index_type<FirstType>::type(f)+fix<1>()));
|
||||
}
|
||||
|
||||
template<typename FirstType,typename LastType, typename IncrType>
|
||||
auto seq(FirstType f, LastType l, IncrType incr)
|
||||
-> decltype(seqN(typename internal::cleanup_index_type<FirstType>::type(f),
|
||||
( typename internal::cleanup_index_type<LastType>::type(l)
|
||||
- typename internal::cleanup_index_type<FirstType>::type(f)+typename internal::cleanup_seq_incr<IncrType>::type(incr)
|
||||
) / typename internal::cleanup_seq_incr<IncrType>::type(incr),
|
||||
typename internal::cleanup_seq_incr<IncrType>::type(incr)))
|
||||
{
|
||||
typedef typename internal::cleanup_seq_incr<IncrType>::type CleanedIncrType;
|
||||
return seqN(typename internal::cleanup_index_type<FirstType>::type(f),
|
||||
( typename internal::cleanup_index_type<LastType>::type(l)
|
||||
-typename internal::cleanup_index_type<FirstType>::type(f)+CleanedIncrType(incr)) / CleanedIncrType(incr),
|
||||
CleanedIncrType(incr));
|
||||
}
|
||||
#else
|
||||
|
||||
template<typename FirstType,typename LastType>
|
||||
typename internal::enable_if<!(Symbolic::is_symbolic<FirstType>::value || Symbolic::is_symbolic<LastType>::value),
|
||||
ArithmeticSequence<typename internal::cleanup_index_type<FirstType>::type,Index> >::type
|
||||
seq(FirstType f, LastType l)
|
||||
{
|
||||
return seqN(typename internal::cleanup_index_type<FirstType>::type(f),
|
||||
Index((typename internal::cleanup_index_type<LastType>::type(l)-typename internal::cleanup_index_type<FirstType>::type(f)+fix<1>())));
|
||||
}
|
||||
|
||||
template<typename FirstTypeDerived,typename LastType>
|
||||
typename internal::enable_if<!Symbolic::is_symbolic<LastType>::value,
|
||||
ArithmeticSequence<FirstTypeDerived, Symbolic::AddExpr<Symbolic::AddExpr<Symbolic::NegateExpr<FirstTypeDerived>,Symbolic::ValueExpr<> >,
|
||||
Symbolic::ValueExpr<internal::FixedInt<1> > > > >::type
|
||||
seq(const Symbolic::BaseExpr<FirstTypeDerived> &f, LastType l)
|
||||
{
|
||||
return seqN(f.derived(),(typename internal::cleanup_index_type<LastType>::type(l)-f.derived()+fix<1>()));
|
||||
}
|
||||
|
||||
template<typename FirstType,typename LastTypeDerived>
|
||||
typename internal::enable_if<!Symbolic::is_symbolic<FirstType>::value,
|
||||
ArithmeticSequence<typename internal::cleanup_index_type<FirstType>::type,
|
||||
Symbolic::AddExpr<Symbolic::AddExpr<LastTypeDerived,Symbolic::ValueExpr<> >,
|
||||
Symbolic::ValueExpr<internal::FixedInt<1> > > > >::type
|
||||
seq(FirstType f, const Symbolic::BaseExpr<LastTypeDerived> &l)
|
||||
{
|
||||
return seqN(typename internal::cleanup_index_type<FirstType>::type(f),(l.derived()-typename internal::cleanup_index_type<FirstType>::type(f)+fix<1>()));
|
||||
}
|
||||
|
||||
template<typename FirstTypeDerived,typename LastTypeDerived>
|
||||
ArithmeticSequence<FirstTypeDerived,
|
||||
Symbolic::AddExpr<Symbolic::AddExpr<LastTypeDerived,Symbolic::NegateExpr<FirstTypeDerived> >,Symbolic::ValueExpr<internal::FixedInt<1> > > >
|
||||
seq(const Symbolic::BaseExpr<FirstTypeDerived> &f, const Symbolic::BaseExpr<LastTypeDerived> &l)
|
||||
{
|
||||
return seqN(f.derived(),(l.derived()-f.derived()+fix<1>()));
|
||||
}
|
||||
|
||||
|
||||
template<typename FirstType,typename LastType, typename IncrType>
|
||||
typename internal::enable_if<!(Symbolic::is_symbolic<FirstType>::value || Symbolic::is_symbolic<LastType>::value),
|
||||
ArithmeticSequence<typename internal::cleanup_index_type<FirstType>::type,Index,typename internal::cleanup_seq_incr<IncrType>::type> >::type
|
||||
seq(FirstType f, LastType l, IncrType incr)
|
||||
{
|
||||
typedef typename internal::cleanup_seq_incr<IncrType>::type CleanedIncrType;
|
||||
return seqN(typename internal::cleanup_index_type<FirstType>::type(f),
|
||||
Index((typename internal::cleanup_index_type<LastType>::type(l)-typename internal::cleanup_index_type<FirstType>::type(f)+CleanedIncrType(incr))/CleanedIncrType(incr)), incr);
|
||||
}
|
||||
|
||||
template<typename FirstTypeDerived,typename LastType, typename IncrType>
|
||||
typename internal::enable_if<!Symbolic::is_symbolic<LastType>::value,
|
||||
ArithmeticSequence<FirstTypeDerived,
|
||||
Symbolic::QuotientExpr<Symbolic::AddExpr<Symbolic::AddExpr<Symbolic::NegateExpr<FirstTypeDerived>,
|
||||
Symbolic::ValueExpr<> >,
|
||||
Symbolic::ValueExpr<typename internal::cleanup_seq_incr<IncrType>::type> >,
|
||||
Symbolic::ValueExpr<typename internal::cleanup_seq_incr<IncrType>::type> >,
|
||||
typename internal::cleanup_seq_incr<IncrType>::type> >::type
|
||||
seq(const Symbolic::BaseExpr<FirstTypeDerived> &f, LastType l, IncrType incr)
|
||||
{
|
||||
typedef typename internal::cleanup_seq_incr<IncrType>::type CleanedIncrType;
|
||||
return seqN(f.derived(),(typename internal::cleanup_index_type<LastType>::type(l)-f.derived()+CleanedIncrType(incr))/CleanedIncrType(incr), incr);
|
||||
}
|
||||
|
||||
template<typename FirstType,typename LastTypeDerived, typename IncrType>
|
||||
typename internal::enable_if<!Symbolic::is_symbolic<FirstType>::value,
|
||||
ArithmeticSequence<typename internal::cleanup_index_type<FirstType>::type,
|
||||
Symbolic::QuotientExpr<Symbolic::AddExpr<Symbolic::AddExpr<LastTypeDerived,Symbolic::ValueExpr<> >,
|
||||
Symbolic::ValueExpr<typename internal::cleanup_seq_incr<IncrType>::type> >,
|
||||
Symbolic::ValueExpr<typename internal::cleanup_seq_incr<IncrType>::type> >,
|
||||
typename internal::cleanup_seq_incr<IncrType>::type> >::type
|
||||
seq(FirstType f, const Symbolic::BaseExpr<LastTypeDerived> &l, IncrType incr)
|
||||
{
|
||||
typedef typename internal::cleanup_seq_incr<IncrType>::type CleanedIncrType;
|
||||
return seqN(typename internal::cleanup_index_type<FirstType>::type(f),
|
||||
(l.derived()-typename internal::cleanup_index_type<FirstType>::type(f)+CleanedIncrType(incr))/CleanedIncrType(incr), incr);
|
||||
}
|
||||
|
||||
template<typename FirstTypeDerived,typename LastTypeDerived, typename IncrType>
|
||||
ArithmeticSequence<FirstTypeDerived,
|
||||
Symbolic::QuotientExpr<Symbolic::AddExpr<Symbolic::AddExpr<LastTypeDerived,
|
||||
Symbolic::NegateExpr<FirstTypeDerived> >,
|
||||
Symbolic::ValueExpr<typename internal::cleanup_seq_incr<IncrType>::type> >,
|
||||
Symbolic::ValueExpr<typename internal::cleanup_seq_incr<IncrType>::type> >,
|
||||
typename internal::cleanup_seq_incr<IncrType>::type>
|
||||
seq(const Symbolic::BaseExpr<FirstTypeDerived> &f, const Symbolic::BaseExpr<LastTypeDerived> &l, IncrType incr)
|
||||
{
|
||||
typedef typename internal::cleanup_seq_incr<IncrType>::type CleanedIncrType;
|
||||
return seqN(f.derived(),(l.derived()-f.derived()+CleanedIncrType(incr))/CleanedIncrType(incr), incr);
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif // EIGEN_PARSED_BY_DOXYGEN
|
||||
|
||||
namespace internal {
|
||||
|
||||
// Convert a symbolic span into a usable one (i.e., remove last/end "keywords")
|
||||
template<typename T>
|
||||
struct make_size_type {
|
||||
typedef typename internal::conditional<Symbolic::is_symbolic<T>::value, Index, T>::type type;
|
||||
};
|
||||
|
||||
template<typename FirstType,typename SizeType,typename IncrType,int XprSize>
|
||||
struct IndexedViewCompatibleType<ArithmeticSequence<FirstType,SizeType,IncrType>, XprSize> {
|
||||
typedef ArithmeticSequence<Index,typename make_size_type<SizeType>::type,IncrType> type;
|
||||
};
|
||||
|
||||
template<typename FirstType,typename SizeType,typename IncrType>
|
||||
ArithmeticSequence<Index,typename make_size_type<SizeType>::type,IncrType>
|
||||
makeIndexedViewCompatible(const ArithmeticSequence<FirstType,SizeType,IncrType>& ids, Index size,SpecializedType) {
|
||||
return ArithmeticSequence<Index,typename make_size_type<SizeType>::type,IncrType>(
|
||||
eval_expr_given_size(ids.firstObject(),size),eval_expr_given_size(ids.sizeObject(),size),ids.incrObject());
|
||||
}
|
||||
|
||||
template<typename FirstType,typename SizeType,typename IncrType>
|
||||
struct get_compile_time_incr<ArithmeticSequence<FirstType,SizeType,IncrType> > {
|
||||
enum { value = get_fixed_value<IncrType,DynamicIndex>::value };
|
||||
};
|
||||
|
||||
} // end namespace internal
|
||||
|
||||
} // end namespace Eigen
|
||||
|
||||
#endif // EIGEN_ARITHMETIC_SEQUENCE_H
|
@ -69,6 +69,7 @@ template<typename Derived> class ArrayBase
|
||||
using Base::coeff;
|
||||
using Base::coeffRef;
|
||||
using Base::lazyAssign;
|
||||
using Base::operator-;
|
||||
using Base::operator=;
|
||||
using Base::operator+=;
|
||||
using Base::operator-=;
|
||||
@ -88,7 +89,6 @@ template<typename Derived> class ArrayBase
|
||||
|
||||
#define EIGEN_CURRENT_STORAGE_BASE_CLASS Eigen::ArrayBase
|
||||
#define EIGEN_DOC_UNARY_ADDONS(X,Y)
|
||||
# include "../plugins/CommonCwiseUnaryOps.h"
|
||||
# include "../plugins/MatrixCwiseUnaryOps.h"
|
||||
# include "../plugins/ArrayCwiseUnaryOps.h"
|
||||
# include "../plugins/CommonCwiseBinaryOps.h"
|
||||
|
@ -701,6 +701,26 @@ protected:
|
||||
* Part 5 : Entry point for dense rectangular assignment
|
||||
***************************************************************************/
|
||||
|
||||
template<typename DstXprType,typename SrcXprType, typename Functor>
|
||||
EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE
|
||||
void resize_if_allowed(DstXprType &dst, const SrcXprType& src, const Functor &/*func*/)
|
||||
{
|
||||
EIGEN_ONLY_USED_FOR_DEBUG(dst);
|
||||
EIGEN_ONLY_USED_FOR_DEBUG(src);
|
||||
eigen_assert(dst.rows() == src.rows() && dst.cols() == src.cols());
|
||||
}
|
||||
|
||||
template<typename DstXprType,typename SrcXprType, typename T1, typename T2>
|
||||
EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE
|
||||
void resize_if_allowed(DstXprType &dst, const SrcXprType& src, const internal::assign_op<T1,T2> &/*func*/)
|
||||
{
|
||||
Index dstRows = src.rows();
|
||||
Index dstCols = src.cols();
|
||||
if(((dst.rows()!=dstRows) || (dst.cols()!=dstCols)))
|
||||
dst.resize(dstRows, dstCols);
|
||||
eigen_assert(dst.rows() == dstRows && dst.cols() == dstCols);
|
||||
}
|
||||
|
||||
template<typename DstXprType, typename SrcXprType, typename Functor>
|
||||
EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void call_dense_assignment_loop(DstXprType& dst, const SrcXprType& src, const Functor &func)
|
||||
{
|
||||
@ -711,10 +731,7 @@ EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void call_dense_assignment_loop(DstXprType
|
||||
|
||||
// NOTE To properly handle A = (A*A.transpose())/s with A rectangular,
|
||||
// we need to resize the destination after the source evaluator has been created.
|
||||
Index dstRows = src.rows();
|
||||
Index dstCols = src.cols();
|
||||
if((dst.rows()!=dstRows) || (dst.cols()!=dstCols))
|
||||
dst.resize(dstRows, dstCols);
|
||||
resize_if_allowed(dst, src, func);
|
||||
|
||||
DstEvaluatorType dstEvaluator(dst);
|
||||
|
||||
|
@ -1613,9 +1613,7 @@ struct evaluator<Diagonal<ArgType, DiagIndex> >
|
||||
{ }
|
||||
|
||||
typedef typename XprType::Scalar Scalar;
|
||||
// FIXME having to check whether ArgType is sparse here i not very nice.
|
||||
typedef typename internal::conditional<!internal::is_same<typename ArgType::StorageKind,Sparse>::value,
|
||||
typename XprType::CoeffReturnType,Scalar>::type CoeffReturnType;
|
||||
typedef typename XprType::CoeffReturnType CoeffReturnType;
|
||||
|
||||
EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE
|
||||
CoeffReturnType coeff(Index row, Index) const
|
||||
|
@ -48,6 +48,11 @@ public:
|
||||
* Explicit zeros are not skipped over. To skip explicit zeros, see class SparseView
|
||||
*/
|
||||
EIGEN_STRONG_INLINE InnerIterator& operator++() { m_iter.operator++(); return *this; }
|
||||
EIGEN_STRONG_INLINE InnerIterator& operator+=(Index i) { m_iter.operator+=(i); return *this; }
|
||||
EIGEN_STRONG_INLINE InnerIterator operator+(Index i)
|
||||
{ InnerIterator result(*this); result+=i; return result; }
|
||||
|
||||
|
||||
/// \returns the column or row index of the current coefficient.
|
||||
EIGEN_STRONG_INLINE Index index() const { return m_iter.index(); }
|
||||
/// \returns the row index of the current coefficient.
|
||||
|
@ -46,7 +46,7 @@ struct traits<CwiseBinaryOp<BinaryOp, Lhs, Rhs> >
|
||||
typedef typename remove_reference<LhsNested>::type _LhsNested;
|
||||
typedef typename remove_reference<RhsNested>::type _RhsNested;
|
||||
enum {
|
||||
Flags = _LhsNested::Flags & RowMajorBit
|
||||
Flags = cwise_promote_storage_order<typename traits<Lhs>::StorageKind,typename traits<Rhs>::StorageKind,_LhsNested::Flags & RowMajorBit,_RhsNested::Flags & RowMajorBit>::value
|
||||
};
|
||||
};
|
||||
} // end namespace internal
|
||||
|
@ -560,13 +560,17 @@ template<typename Derived> class DenseBase
|
||||
#define EIGEN_CURRENT_STORAGE_BASE_CLASS Eigen::DenseBase
|
||||
#define EIGEN_DOC_BLOCK_ADDONS_NOT_INNER_PANEL
|
||||
#define EIGEN_DOC_BLOCK_ADDONS_INNER_PANEL_IF(COND)
|
||||
#define EIGEN_DOC_UNARY_ADDONS(X,Y)
|
||||
# include "../plugins/CommonCwiseUnaryOps.h"
|
||||
# include "../plugins/BlockMethods.h"
|
||||
# include "../plugins/IndexedViewMethods.h"
|
||||
# ifdef EIGEN_DENSEBASE_PLUGIN
|
||||
# include EIGEN_DENSEBASE_PLUGIN
|
||||
# endif
|
||||
#undef EIGEN_CURRENT_STORAGE_BASE_CLASS
|
||||
#undef EIGEN_DOC_BLOCK_ADDONS_NOT_INNER_PANEL
|
||||
#undef EIGEN_DOC_BLOCK_ADDONS_INNER_PANEL_IF
|
||||
#undef EIGEN_DOC_UNARY_ADDONS
|
||||
|
||||
// disable the use of evalTo for dense objects with a nice compilation error
|
||||
template<typename Dest>
|
||||
|
@ -21,7 +21,7 @@ namespace Eigen {
|
||||
* \param MatrixType the type of the object in which we are taking a sub/main/super diagonal
|
||||
* \param DiagIndex the index of the sub/super diagonal. The default is 0 and it means the main diagonal.
|
||||
* A positive value means a superdiagonal, a negative value means a subdiagonal.
|
||||
* You can also use Dynamic so the index can be set at runtime.
|
||||
* You can also use DynamicIndex so the index can be set at runtime.
|
||||
*
|
||||
* The matrix is not required to be square.
|
||||
*
|
||||
|
@ -51,7 +51,8 @@ struct dot_nocheck<T, U, true>
|
||||
|
||||
} // end namespace internal
|
||||
|
||||
/** \returns the dot product of *this with other.
|
||||
/** \fn MatrixBase::dot
|
||||
* \returns the dot product of *this with other.
|
||||
*
|
||||
* \only_for_vectors
|
||||
*
|
||||
|
@ -105,7 +105,7 @@ class WithFormat
|
||||
}
|
||||
|
||||
protected:
|
||||
const typename ExpressionType::Nested m_matrix;
|
||||
typename ExpressionType::Nested m_matrix;
|
||||
IOFormat m_format;
|
||||
};
|
||||
|
||||
|
207
Eigen/src/Core/IndexedView.h
Normal file
207
Eigen/src/Core/IndexedView.h
Normal file
@ -0,0 +1,207 @@
|
||||
// This file is part of Eigen, a lightweight C++ template library
|
||||
// for linear algebra.
|
||||
//
|
||||
// Copyright (C) 2017 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_INDEXED_VIEW_H
|
||||
#define EIGEN_INDEXED_VIEW_H
|
||||
|
||||
namespace Eigen {
|
||||
|
||||
namespace internal {
|
||||
|
||||
template<typename XprType, typename RowIndices, typename ColIndices>
|
||||
struct traits<IndexedView<XprType, RowIndices, ColIndices> >
|
||||
: traits<XprType>
|
||||
{
|
||||
enum {
|
||||
RowsAtCompileTime = array_size<RowIndices>::value,
|
||||
ColsAtCompileTime = array_size<ColIndices>::value,
|
||||
MaxRowsAtCompileTime = RowsAtCompileTime != Dynamic ? int(RowsAtCompileTime) : int(traits<XprType>::MaxRowsAtCompileTime),
|
||||
MaxColsAtCompileTime = ColsAtCompileTime != Dynamic ? int(ColsAtCompileTime) : int(traits<XprType>::MaxColsAtCompileTime),
|
||||
|
||||
XprTypeIsRowMajor = (int(traits<XprType>::Flags)&RowMajorBit) != 0,
|
||||
IsRowMajor = (MaxRowsAtCompileTime==1&&MaxColsAtCompileTime!=1) ? 1
|
||||
: (MaxColsAtCompileTime==1&&MaxRowsAtCompileTime!=1) ? 0
|
||||
: XprTypeIsRowMajor,
|
||||
|
||||
RowIncr = get_compile_time_incr<RowIndices>::value,
|
||||
ColIncr = get_compile_time_incr<ColIndices>::value,
|
||||
InnerIncr = IsRowMajor ? ColIncr : RowIncr,
|
||||
OuterIncr = IsRowMajor ? RowIncr : ColIncr,
|
||||
|
||||
HasSameStorageOrderAsXprType = (IsRowMajor == XprTypeIsRowMajor),
|
||||
XprInnerStride = HasSameStorageOrderAsXprType ? int(inner_stride_at_compile_time<XprType>::ret) : int(outer_stride_at_compile_time<XprType>::ret),
|
||||
XprOuterstride = HasSameStorageOrderAsXprType ? int(outer_stride_at_compile_time<XprType>::ret) : int(inner_stride_at_compile_time<XprType>::ret),
|
||||
|
||||
InnerSize = XprTypeIsRowMajor ? ColsAtCompileTime : RowsAtCompileTime,
|
||||
IsBlockAlike = InnerIncr==1 && OuterIncr==1,
|
||||
IsInnerPannel = HasSameStorageOrderAsXprType && is_same<AllRange<InnerSize>,typename conditional<XprTypeIsRowMajor,ColIndices,RowIndices>::type>::value,
|
||||
|
||||
InnerStrideAtCompileTime = InnerIncr<0 || InnerIncr==DynamicIndex || XprInnerStride==Dynamic ? Dynamic : XprInnerStride * InnerIncr,
|
||||
OuterStrideAtCompileTime = OuterIncr<0 || OuterIncr==DynamicIndex || XprOuterstride==Dynamic ? Dynamic : XprOuterstride * OuterIncr,
|
||||
|
||||
ReturnAsScalar = is_same<RowIndices,SingleRange>::value && is_same<ColIndices,SingleRange>::value,
|
||||
ReturnAsBlock = (!ReturnAsScalar) && IsBlockAlike,
|
||||
ReturnAsIndexedView = (!ReturnAsScalar) && (!ReturnAsBlock),
|
||||
|
||||
// FIXME we deal with compile-time strides if and only if we have DirectAccessBit flag,
|
||||
// but this is too strict regarding negative strides...
|
||||
DirectAccessMask = (InnerIncr!=UndefinedIncr && OuterIncr!=UndefinedIncr && InnerIncr>=0 && OuterIncr>=0) ? DirectAccessBit : 0,
|
||||
FlagsRowMajorBit = IsRowMajor ? RowMajorBit : 0,
|
||||
FlagsLvalueBit = is_lvalue<XprType>::value ? LvalueBit : 0,
|
||||
Flags = (traits<XprType>::Flags & (HereditaryBits | DirectAccessMask)) | FlagsLvalueBit | FlagsRowMajorBit
|
||||
};
|
||||
|
||||
typedef Block<XprType,RowsAtCompileTime,ColsAtCompileTime,IsInnerPannel> BlockType;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
template<typename XprType, typename RowIndices, typename ColIndices, typename StorageKind>
|
||||
class IndexedViewImpl;
|
||||
|
||||
|
||||
/** \class IndexedView
|
||||
* \ingroup Core_Module
|
||||
*
|
||||
* \brief Expression of a non-sequential sub-matrix defined by arbitrary sequences of row and column indices
|
||||
*
|
||||
* \tparam XprType the type of the expression in which we are taking the intersections of sub-rows and sub-columns
|
||||
* \tparam RowIndices the type of the object defining the sequence of row indices
|
||||
* \tparam ColIndices the type of the object defining the sequence of column indices
|
||||
*
|
||||
* This class represents an expression of a sub-matrix (or sub-vector) defined as the intersection
|
||||
* of sub-sets of rows and columns, that are themself defined by generic sequences of row indices \f$ \{r_0,r_1,..r_{m-1}\} \f$
|
||||
* and column indices \f$ \{c_0,c_1,..c_{n-1} \}\f$. Let \f$ A \f$ be the nested matrix, then the resulting matrix \f$ B \f$ has \c m
|
||||
* rows and \c n columns, and its entries are given by: \f$ B(i,j) = A(r_i,c_j) \f$.
|
||||
*
|
||||
* The \c RowIndices and \c ColIndices types must be compatible with the following API:
|
||||
* \code
|
||||
* <integral type> operator[](Index) const;
|
||||
* Index size() const;
|
||||
* \endcode
|
||||
*
|
||||
* Typical supported types thus include:
|
||||
* - std::vector<int>
|
||||
* - std::valarray<int>
|
||||
* - std::array<int>
|
||||
* - Plain C arrays: int[N]
|
||||
* - Eigen::ArrayXi
|
||||
* - decltype(ArrayXi::LinSpaced(...))
|
||||
* - Any view/expressions of the previous types
|
||||
* - Eigen::ArithmeticSequence
|
||||
* - Eigen::internal::AllRange (helper for Eigen::all)
|
||||
* - Eigen::internal::SingleRange (helper for single index)
|
||||
* - etc.
|
||||
*
|
||||
* In typical usages of %Eigen, this class should never be used directly. It is the return type of
|
||||
* DenseBase::operator()(const RowIndices&, const ColIndices&).
|
||||
*
|
||||
* \sa class Block
|
||||
*/
|
||||
template<typename XprType, typename RowIndices, typename ColIndices>
|
||||
class IndexedView : public IndexedViewImpl<XprType, RowIndices, ColIndices, typename internal::traits<XprType>::StorageKind>
|
||||
{
|
||||
public:
|
||||
typedef typename IndexedViewImpl<XprType, RowIndices, ColIndices, typename internal::traits<XprType>::StorageKind>::Base Base;
|
||||
EIGEN_GENERIC_PUBLIC_INTERFACE(IndexedView)
|
||||
EIGEN_INHERIT_ASSIGNMENT_OPERATORS(IndexedView)
|
||||
|
||||
typedef typename internal::ref_selector<XprType>::non_const_type MatrixTypeNested;
|
||||
typedef typename internal::remove_all<XprType>::type NestedExpression;
|
||||
|
||||
template<typename T0, typename T1>
|
||||
IndexedView(XprType& xpr, const T0& rowIndices, const T1& colIndices)
|
||||
: m_xpr(xpr), m_rowIndices(rowIndices), m_colIndices(colIndices)
|
||||
{}
|
||||
|
||||
/** \returns number of rows */
|
||||
Index rows() const { return internal::size(m_rowIndices); }
|
||||
|
||||
/** \returns number of columns */
|
||||
Index cols() const { return internal::size(m_colIndices); }
|
||||
|
||||
/** \returns the nested expression */
|
||||
const typename internal::remove_all<XprType>::type&
|
||||
nestedExpression() const { return m_xpr; }
|
||||
|
||||
/** \returns the nested expression */
|
||||
typename internal::remove_reference<XprType>::type&
|
||||
nestedExpression() { return m_xpr.const_cast_derived(); }
|
||||
|
||||
/** \returns a const reference to the object storing/generating the row indices */
|
||||
const RowIndices& rowIndices() const { return m_rowIndices; }
|
||||
|
||||
/** \returns a const reference to the object storing/generating the column indices */
|
||||
const ColIndices& colIndices() const { return m_colIndices; }
|
||||
|
||||
protected:
|
||||
MatrixTypeNested m_xpr;
|
||||
RowIndices m_rowIndices;
|
||||
ColIndices m_colIndices;
|
||||
};
|
||||
|
||||
|
||||
// Generic API dispatcher
|
||||
template<typename XprType, typename RowIndices, typename ColIndices, typename StorageKind>
|
||||
class IndexedViewImpl
|
||||
: public internal::generic_xpr_base<IndexedView<XprType, RowIndices, ColIndices> >::type
|
||||
{
|
||||
public:
|
||||
typedef typename internal::generic_xpr_base<IndexedView<XprType, RowIndices, ColIndices> >::type Base;
|
||||
};
|
||||
|
||||
namespace internal {
|
||||
|
||||
|
||||
template<typename ArgType, typename RowIndices, typename ColIndices>
|
||||
struct unary_evaluator<IndexedView<ArgType, RowIndices, ColIndices>, IndexBased>
|
||||
: evaluator_base<IndexedView<ArgType, RowIndices, ColIndices> >
|
||||
{
|
||||
typedef IndexedView<ArgType, RowIndices, ColIndices> XprType;
|
||||
|
||||
enum {
|
||||
CoeffReadCost = evaluator<ArgType>::CoeffReadCost /* TODO + cost of row/col index */,
|
||||
|
||||
Flags = (evaluator<ArgType>::Flags & (HereditaryBits /*| LinearAccessBit | DirectAccessBit*/)),
|
||||
|
||||
Alignment = 0
|
||||
};
|
||||
|
||||
EIGEN_DEVICE_FUNC explicit unary_evaluator(const XprType& xpr) : m_argImpl(xpr.nestedExpression()), m_xpr(xpr)
|
||||
{
|
||||
EIGEN_INTERNAL_CHECK_COST_VALUE(CoeffReadCost);
|
||||
}
|
||||
|
||||
typedef typename XprType::Scalar Scalar;
|
||||
typedef typename XprType::CoeffReturnType CoeffReturnType;
|
||||
|
||||
EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE
|
||||
CoeffReturnType coeff(Index row, Index col) const
|
||||
{
|
||||
return m_argImpl.coeff(m_xpr.rowIndices()[row], m_xpr.colIndices()[col]);
|
||||
}
|
||||
|
||||
EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE
|
||||
Scalar& coeffRef(Index row, Index col)
|
||||
{
|
||||
return m_argImpl.coeffRef(m_xpr.rowIndices()[row], m_xpr.colIndices()[col]);
|
||||
}
|
||||
|
||||
protected:
|
||||
|
||||
evaluator<ArgType> m_argImpl;
|
||||
const XprType& m_xpr;
|
||||
|
||||
};
|
||||
|
||||
} // end namespace internal
|
||||
|
||||
} // end namespace Eigen
|
||||
|
||||
#endif // EIGEN_INDEXED_VIEW_H
|
@ -29,12 +29,7 @@ T generic_fast_tanh_float(const T& a_x)
|
||||
// this range is +/-1.0f in single-precision.
|
||||
const T plus_9 = pset1<T>(9.f);
|
||||
const T minus_9 = pset1<T>(-9.f);
|
||||
// NOTE GCC prior to 6.3 might improperly optimize this max/min
|
||||
// step such that if a_x is nan, x will be either 9 or -9,
|
||||
// and tanh will return 1 or -1 instead of nan.
|
||||
// This is supposed to be fixed in gcc6.3,
|
||||
// see: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=72867
|
||||
const T x = pmax(minus_9,pmin(plus_9,a_x));
|
||||
const T x = pmax(pmin(a_x, plus_9), minus_9);
|
||||
// The monomial coefficients of the numerator polynomial (odd).
|
||||
const T alpha_1 = pset1<T>(4.89352455891786e-03f);
|
||||
const T alpha_3 = pset1<T>(6.37261928875436e-04f);
|
||||
|
@ -76,6 +76,7 @@ template<typename Derived> class MatrixBase
|
||||
using Base::coeffRef;
|
||||
using Base::lazyAssign;
|
||||
using Base::eval;
|
||||
using Base::operator-;
|
||||
using Base::operator+=;
|
||||
using Base::operator-=;
|
||||
using Base::operator*=;
|
||||
@ -122,7 +123,6 @@ template<typename Derived> class MatrixBase
|
||||
|
||||
#define EIGEN_CURRENT_STORAGE_BASE_CLASS Eigen::MatrixBase
|
||||
#define EIGEN_DOC_UNARY_ADDONS(X,Y)
|
||||
# include "../plugins/CommonCwiseUnaryOps.h"
|
||||
# include "../plugins/CommonCwiseBinaryOps.h"
|
||||
# include "../plugins/MatrixCwiseUnaryOps.h"
|
||||
# include "../plugins/MatrixCwiseBinaryOps.h"
|
||||
|
@ -41,7 +41,7 @@ template<> struct check_rows_cols_for_overflow<Dynamic> {
|
||||
{
|
||||
// http://hg.mozilla.org/mozilla-central/file/6c8a909977d3/xpcom/ds/CheckedInt.h#l242
|
||||
// we assume Index is signed
|
||||
Index max_index = (size_t(1) << (8 * sizeof(Index) - 1)) - 1; // assume Index is signed
|
||||
Index max_index = (std::size_t(1) << (8 * sizeof(Index) - 1)) - 1; // assume Index is signed
|
||||
bool error = (rows == 0 || cols == 0) ? false
|
||||
: (rows > max_index / cols);
|
||||
if (error)
|
||||
@ -58,6 +58,28 @@ template<typename MatrixTypeA, typename MatrixTypeB, bool SwapPointers> struct m
|
||||
|
||||
} // end namespace internal
|
||||
|
||||
#ifdef EIGEN_PARSED_BY_DOXYGEN
|
||||
namespace doxygen {
|
||||
|
||||
// This is a workaround to doxygen not being able to understand the inheritance logic
|
||||
// when it is hidden by the dense_xpr_base helper struct.
|
||||
// Moreover, doxygen fails to include members that are not documented in the declaration body of
|
||||
// MatrixBase if we inherits MatrixBase<Matrix<_Scalar, _Rows, _Cols, _Options, _MaxRows, _MaxCols> >,
|
||||
// this is why we simply inherits MatrixBase, though this does not make sense.
|
||||
|
||||
/** This class is just a workaround for Doxygen and it does not not actually exist. */
|
||||
template<typename Derived> struct dense_xpr_base_dispatcher;
|
||||
/** This class is just a workaround for Doxygen and it does not not actually exist. */
|
||||
template<typename _Scalar, int _Rows, int _Cols, int _Options, int _MaxRows, int _MaxCols>
|
||||
struct dense_xpr_base_dispatcher<Matrix<_Scalar, _Rows, _Cols, _Options, _MaxRows, _MaxCols> >
|
||||
: public MatrixBase {};
|
||||
/** This class is just a workaround for Doxygen and it does not not actually exist. */
|
||||
template<typename _Scalar, int _Rows, int _Cols, int _Options, int _MaxRows, int _MaxCols>
|
||||
struct dense_xpr_base_dispatcher<Array<_Scalar, _Rows, _Cols, _Options, _MaxRows, _MaxCols> >
|
||||
: public ArrayBase {};
|
||||
|
||||
} // namespace doxygen
|
||||
|
||||
/** \class PlainObjectBase
|
||||
* \ingroup Core_Module
|
||||
* \brief %Dense storage base class for matrices and arrays.
|
||||
@ -65,26 +87,10 @@ template<typename MatrixTypeA, typename MatrixTypeB, bool SwapPointers> struct m
|
||||
* This class can be extended with the help of the plugin mechanism described on the page
|
||||
* \ref TopicCustomizing_Plugins by defining the preprocessor symbol \c EIGEN_PLAINOBJECTBASE_PLUGIN.
|
||||
*
|
||||
* \tparam Derived is the derived type, e.g., a Matrix or Array
|
||||
*
|
||||
* \sa \ref TopicClassHierarchy
|
||||
*/
|
||||
#ifdef EIGEN_PARSED_BY_DOXYGEN
|
||||
namespace doxygen {
|
||||
|
||||
// this is a workaround to doxygen not being able to understand the inheritance logic
|
||||
// when it is hidden by the dense_xpr_base helper struct.
|
||||
/** This class is just a workaround for Doxygen and it does not not actually exist. */
|
||||
template<typename Derived> struct dense_xpr_base_dispatcher;
|
||||
/** This class is just a workaround for Doxygen and it does not not actually exist. */
|
||||
template<typename _Scalar, int _Rows, int _Cols, int _Options, int _MaxRows, int _MaxCols>
|
||||
struct dense_xpr_base_dispatcher<Matrix<_Scalar, _Rows, _Cols, _Options, _MaxRows, _MaxCols> >
|
||||
: public MatrixBase<Matrix<_Scalar, _Rows, _Cols, _Options, _MaxRows, _MaxCols> > {};
|
||||
/** This class is just a workaround for Doxygen and it does not not actually exist. */
|
||||
template<typename _Scalar, int _Rows, int _Cols, int _Options, int _MaxRows, int _MaxCols>
|
||||
struct dense_xpr_base_dispatcher<Array<_Scalar, _Rows, _Cols, _Options, _MaxRows, _MaxCols> >
|
||||
: public ArrayBase<Array<_Scalar, _Rows, _Cols, _Options, _MaxRows, _MaxCols> > {};
|
||||
|
||||
} // namespace doxygen
|
||||
|
||||
template<typename Derived>
|
||||
class PlainObjectBase : public doxygen::dense_xpr_base_dispatcher<Derived>
|
||||
#else
|
||||
@ -554,7 +560,8 @@ class PlainObjectBase : public internal::dense_xpr_base<Derived>::type
|
||||
|
||||
public:
|
||||
|
||||
/** \copydoc DenseBase::operator=(const EigenBase<OtherDerived>&)
|
||||
/** \brief Copies the generic expression \a other into *this.
|
||||
* \copydetails DenseBase::operator=(const EigenBase<OtherDerived> &other)
|
||||
*/
|
||||
template<typename OtherDerived>
|
||||
EIGEN_DEVICE_FUNC
|
||||
|
@ -184,6 +184,8 @@ protected:
|
||||
* void foo(const Ref<MatrixXf,0,Stride<> >& A) { foo_impl(A); }
|
||||
* \endcode
|
||||
*
|
||||
* See also the following stackoverflow questions for further references:
|
||||
* - <a href="http://stackoverflow.com/questions/21132538/correct-usage-of-the-eigenref-class">Correct usage of the Eigen::Ref<> class</a>
|
||||
*
|
||||
* \sa PlainObjectBase::Map(), \ref TopicStorageOrders
|
||||
*/
|
||||
|
@ -319,6 +319,7 @@ public:
|
||||
* Implementation of MatrixBase methods
|
||||
***************************************************************************/
|
||||
|
||||
/** This is the const version of MatrixBase::selfadjointView() */
|
||||
template<typename Derived>
|
||||
template<unsigned int UpLo>
|
||||
typename MatrixBase<Derived>::template ConstSelfAdjointViewReturnType<UpLo>::Type
|
||||
@ -327,6 +328,15 @@ MatrixBase<Derived>::selfadjointView() const
|
||||
return typename ConstSelfAdjointViewReturnType<UpLo>::Type(derived());
|
||||
}
|
||||
|
||||
/** \returns an expression of a symmetric/self-adjoint view extracted from the upper or lower triangular part of the current matrix
|
||||
*
|
||||
* The parameter \a UpLo can be either \c #Upper or \c #Lower
|
||||
*
|
||||
* Example: \include MatrixBase_selfadjointView.cpp
|
||||
* Output: \verbinclude MatrixBase_selfadjointView.out
|
||||
*
|
||||
* \sa class SelfAdjointView
|
||||
*/
|
||||
template<typename Derived>
|
||||
template<unsigned int UpLo>
|
||||
typename MatrixBase<Derived>::template SelfAdjointViewReturnType<UpLo>::Type
|
||||
|
@ -161,6 +161,7 @@ struct triangular_solver_selector<Lhs,Rhs,OnTheRight,Mode,CompleteUnrolling,1> {
|
||||
* TriangularView methods
|
||||
***************************************************************************/
|
||||
|
||||
#ifndef EIGEN_PARSED_BY_DOXYGEN
|
||||
template<typename MatrixType, unsigned int Mode>
|
||||
template<int Side, typename OtherDerived>
|
||||
void TriangularViewImpl<MatrixType,Mode,Dense>::solveInPlace(const MatrixBase<OtherDerived>& _other) const
|
||||
@ -188,6 +189,7 @@ TriangularViewImpl<Derived,Mode,Dense>::solve(const MatrixBase<Other>& other) co
|
||||
{
|
||||
return internal::triangular_solve_retval<Side,TriangularViewType,Other>(derived(), other.derived());
|
||||
}
|
||||
#endif
|
||||
|
||||
namespace internal {
|
||||
|
||||
|
@ -470,6 +470,8 @@ template<typename _MatrixType, unsigned int _Mode> class TriangularViewImpl<_Mat
|
||||
* \a Side==OnTheLeft (the default), or the right-inverse-multiply \a other * inverse(\c *this) if
|
||||
* \a Side==OnTheRight.
|
||||
*
|
||||
* Note that the template parameter \c Side can be ommitted, in which case \c Side==OnTheLeft
|
||||
*
|
||||
* The matrix \c *this must be triangular and invertible (i.e., all the coefficients of the
|
||||
* diagonal must be non zero). It works as a forward (resp. backward) substitution if \c *this
|
||||
* is an upper (resp. lower) triangular matrix.
|
||||
@ -495,6 +497,8 @@ template<typename _MatrixType, unsigned int _Mode> class TriangularViewImpl<_Mat
|
||||
* \warning The parameter is only marked 'const' to make the C++ compiler accept a temporary expression here.
|
||||
* This function will const_cast it, so constness isn't honored here.
|
||||
*
|
||||
* Note that the template parameter \c Side can be ommitted, in which case \c Side==OnTheLeft
|
||||
*
|
||||
* See TriangularView:solve() for the details.
|
||||
*/
|
||||
template<int Side, typename OtherDerived>
|
||||
@ -539,13 +543,14 @@ template<typename _MatrixType, unsigned int _Mode> class TriangularViewImpl<_Mat
|
||||
|
||||
template<typename ProductType>
|
||||
EIGEN_DEVICE_FUNC
|
||||
EIGEN_STRONG_INLINE TriangularViewType& _assignProduct(const ProductType& prod, const Scalar& alpha);
|
||||
EIGEN_STRONG_INLINE TriangularViewType& _assignProduct(const ProductType& prod, const Scalar& alpha, bool beta);
|
||||
};
|
||||
|
||||
/***************************************************************************
|
||||
* Implementation of triangular evaluation/assignment
|
||||
***************************************************************************/
|
||||
|
||||
#ifndef EIGEN_PARSED_BY_DOXYGEN
|
||||
// FIXME should we keep that possibility
|
||||
template<typename MatrixType, unsigned int Mode>
|
||||
template<typename OtherDerived>
|
||||
@ -583,6 +588,7 @@ void TriangularViewImpl<MatrixType, Mode, Dense>::lazyAssign(const TriangularBas
|
||||
eigen_assert(Mode == int(OtherDerived::Mode));
|
||||
internal::call_assignment_no_alias(derived(), other.derived());
|
||||
}
|
||||
#endif
|
||||
|
||||
/***************************************************************************
|
||||
* Implementation of TriangularBase methods
|
||||
@ -944,8 +950,7 @@ struct Assignment<DstXprType, Product<Lhs,Rhs,DefaultProduct>, internal::assign_
|
||||
if((dst.rows()!=dstRows) || (dst.cols()!=dstCols))
|
||||
dst.resize(dstRows, dstCols);
|
||||
|
||||
dst.setZero();
|
||||
dst._assignProduct(src, 1);
|
||||
dst._assignProduct(src, 1, 0);
|
||||
}
|
||||
};
|
||||
|
||||
@ -956,7 +961,7 @@ struct Assignment<DstXprType, Product<Lhs,Rhs,DefaultProduct>, internal::add_ass
|
||||
typedef Product<Lhs,Rhs,DefaultProduct> SrcXprType;
|
||||
static void run(DstXprType &dst, const SrcXprType &src, const internal::add_assign_op<Scalar,typename SrcXprType::Scalar> &)
|
||||
{
|
||||
dst._assignProduct(src, 1);
|
||||
dst._assignProduct(src, 1, 1);
|
||||
}
|
||||
};
|
||||
|
||||
@ -967,7 +972,7 @@ struct Assignment<DstXprType, Product<Lhs,Rhs,DefaultProduct>, internal::sub_ass
|
||||
typedef Product<Lhs,Rhs,DefaultProduct> SrcXprType;
|
||||
static void run(DstXprType &dst, const SrcXprType &src, const internal::sub_assign_op<Scalar,typename SrcXprType::Scalar> &)
|
||||
{
|
||||
dst._assignProduct(src, -1);
|
||||
dst._assignProduct(src, -1, 1);
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -194,7 +194,8 @@ struct functor_traits<max_coeff_visitor<Scalar> > {
|
||||
|
||||
} // end namespace internal
|
||||
|
||||
/** \returns the minimum of all coefficients of *this and puts in *row and *col its location.
|
||||
/** \fn DenseBase<Derived>::minCoeff(IndexType* rowId, IndexType* colId) const
|
||||
* \returns the minimum of all coefficients of *this and puts in *row and *col its location.
|
||||
* \warning the result is undefined if \c *this contains NaN.
|
||||
*
|
||||
* \sa DenseBase::minCoeff(Index*), DenseBase::maxCoeff(Index*,Index*), DenseBase::visit(), DenseBase::minCoeff()
|
||||
@ -230,7 +231,8 @@ DenseBase<Derived>::minCoeff(IndexType* index) const
|
||||
return minVisitor.res;
|
||||
}
|
||||
|
||||
/** \returns the maximum of all coefficients of *this and puts in *row and *col its location.
|
||||
/** \fn DenseBase<Derived>::maxCoeff(IndexType* rowId, IndexType* colId) const
|
||||
* \returns the maximum of all coefficients of *this and puts in *row and *col its location.
|
||||
* \warning the result is undefined if \c *this contains NaN.
|
||||
*
|
||||
* \sa DenseBase::minCoeff(IndexType*,IndexType*), DenseBase::visit(), DenseBase::maxCoeff()
|
||||
|
@ -183,12 +183,22 @@ template<> EIGEN_STRONG_INLINE Packet4d pmadd(const Packet4d& a, const Packet4d&
|
||||
}
|
||||
#endif
|
||||
|
||||
template<> EIGEN_STRONG_INLINE Packet8f pmin<Packet8f>(const Packet8f& a, const Packet8f& b) { return _mm256_min_ps(a,b); }
|
||||
template<> EIGEN_STRONG_INLINE Packet4d pmin<Packet4d>(const Packet4d& a, const Packet4d& b) { return _mm256_min_pd(a,b); }
|
||||
|
||||
template<> EIGEN_STRONG_INLINE Packet8f pmax<Packet8f>(const Packet8f& a, const Packet8f& b) { return _mm256_max_ps(a,b); }
|
||||
template<> EIGEN_STRONG_INLINE Packet4d pmax<Packet4d>(const Packet4d& a, const Packet4d& b) { return _mm256_max_pd(a,b); }
|
||||
|
||||
template<> EIGEN_STRONG_INLINE Packet8f pmin<Packet8f>(const Packet8f& a, const Packet8f& b) {
|
||||
// Arguments are swapped to match NaN propagation behavior of std::min.
|
||||
return _mm256_min_ps(b,a);
|
||||
}
|
||||
template<> EIGEN_STRONG_INLINE Packet4d pmin<Packet4d>(const Packet4d& a, const Packet4d& b) {
|
||||
// Arguments are swapped to match NaN propagation behavior of std::min.
|
||||
return _mm256_min_pd(b,a);
|
||||
}
|
||||
template<> EIGEN_STRONG_INLINE Packet8f pmax<Packet8f>(const Packet8f& a, const Packet8f& b) {
|
||||
// Arguments are swapped to match NaN propagation behavior of std::max.
|
||||
return _mm256_max_ps(b,a);
|
||||
}
|
||||
template<> EIGEN_STRONG_INLINE Packet4d pmax<Packet4d>(const Packet4d& a, const Packet4d& b) {
|
||||
// Arguments are swapped to match NaN propagation behavior of std::max.
|
||||
return _mm256_max_pd(b,a);
|
||||
}
|
||||
template<> EIGEN_STRONG_INLINE Packet8f pround<Packet8f>(const Packet8f& a) { return _mm256_round_ps(a, _MM_FROUND_CUR_DIRECTION); }
|
||||
template<> EIGEN_STRONG_INLINE Packet4d pround<Packet4d>(const Packet4d& a) { return _mm256_round_pd(a, _MM_FROUND_CUR_DIRECTION); }
|
||||
|
||||
|
@ -59,8 +59,8 @@ template<> struct packet_traits<float> : default_packet_traits
|
||||
HasLog = 1,
|
||||
#endif
|
||||
HasExp = 1,
|
||||
HasSqrt = 1,
|
||||
HasRsqrt = 1,
|
||||
HasSqrt = EIGEN_FAST_MATH,
|
||||
HasRsqrt = EIGEN_FAST_MATH,
|
||||
#endif
|
||||
HasDiv = 1
|
||||
};
|
||||
@ -75,7 +75,7 @@ template<> struct packet_traits<double> : default_packet_traits
|
||||
size = 8,
|
||||
HasHalfPacket = 1,
|
||||
#if EIGEN_GNUC_AT_LEAST(5, 3)
|
||||
HasSqrt = 1,
|
||||
HasSqrt = EIGEN_FAST_MATH,
|
||||
HasRsqrt = EIGEN_FAST_MATH,
|
||||
#endif
|
||||
HasDiv = 1
|
||||
@ -230,23 +230,27 @@ EIGEN_STRONG_INLINE Packet8d pmadd(const Packet8d& a, const Packet8d& b,
|
||||
template <>
|
||||
EIGEN_STRONG_INLINE Packet16f pmin<Packet16f>(const Packet16f& a,
|
||||
const Packet16f& b) {
|
||||
return _mm512_min_ps(a, b);
|
||||
// Arguments are reversed to match NaN propagation behavior of std::min.
|
||||
return _mm512_min_ps(b, a);
|
||||
}
|
||||
template <>
|
||||
EIGEN_STRONG_INLINE Packet8d pmin<Packet8d>(const Packet8d& a,
|
||||
const Packet8d& b) {
|
||||
return _mm512_min_pd(a, b);
|
||||
// Arguments are reversed to match NaN propagation behavior of std::min.
|
||||
return _mm512_min_pd(b, a);
|
||||
}
|
||||
|
||||
template <>
|
||||
EIGEN_STRONG_INLINE Packet16f pmax<Packet16f>(const Packet16f& a,
|
||||
const Packet16f& b) {
|
||||
return _mm512_max_ps(a, b);
|
||||
// Arguments are reversed to match NaN propagation behavior of std::max.
|
||||
return _mm512_max_ps(b, a);
|
||||
}
|
||||
template <>
|
||||
EIGEN_STRONG_INLINE Packet8d pmax<Packet8d>(const Packet8d& a,
|
||||
const Packet8d& b) {
|
||||
return _mm512_max_pd(a, b);
|
||||
// Arguments are reversed to match NaN propagation behavior of std::max.
|
||||
return _mm512_max_pd(b, a);
|
||||
}
|
||||
|
||||
template <>
|
||||
@ -628,8 +632,8 @@ EIGEN_STRONG_INLINE Packet8d pabs(const Packet8d& a) {
|
||||
#ifdef EIGEN_VECTORIZE_AVX512DQ
|
||||
// AVX512F does not define _mm512_extractf32x8_ps to extract _m256 from _m512
|
||||
#define EIGEN_EXTRACT_8f_FROM_16f(INPUT, OUTPUT) \
|
||||
__m256 OUTPUT##_0 = _mm512_extractf32x8_ps(INPUT, 0) __m256 OUTPUT##_1 = \
|
||||
_mm512_extractf32x8_ps(INPUT, 1)
|
||||
__m256 OUTPUT##_0 = _mm512_extractf32x8_ps(INPUT, 0); \
|
||||
__m256 OUTPUT##_1 = _mm512_extractf32x8_ps(INPUT, 1)
|
||||
#else
|
||||
#define EIGEN_EXTRACT_8f_FROM_16f(INPUT, OUTPUT) \
|
||||
__m256 OUTPUT##_0 = _mm256_insertf128_ps( \
|
||||
@ -719,7 +723,7 @@ vecs)
|
||||
blend1 = _mm256_blend_ps(sum1, sum2, 0xcc);
|
||||
blend2 = _mm256_blend_ps(sum3, sum4, 0xcc);
|
||||
|
||||
final = padd(final, _mm256_blend_ps(blend1, blend2, 0xf0));
|
||||
final = _mm256_add_ps(final, _mm256_blend_ps(blend1, blend2, 0xf0));
|
||||
|
||||
hsum1 = _mm256_hadd_ps(vecs8_0, vecs9_0);
|
||||
hsum2 = _mm256_hadd_ps(vecs10_0, vecs11_0);
|
||||
@ -769,7 +773,7 @@ vecs)
|
||||
blend1 = _mm256_blend_ps(sum1, sum2, 0xcc);
|
||||
blend2 = _mm256_blend_ps(sum3, sum4, 0xcc);
|
||||
|
||||
final_1 = padd(final_1, _mm256_blend_ps(blend1, blend2, 0xf0));
|
||||
final_1 = _mm256_add_ps(final_1, _mm256_blend_ps(blend1, blend2, 0xf0));
|
||||
|
||||
__m512 final_output;
|
||||
|
||||
@ -819,7 +823,7 @@ template<> EIGEN_STRONG_INLINE Packet8d preduxp<Packet8d>(const Packet8d* vecs)
|
||||
tmp1 = _mm256_hadd_pd(vecs2_1, vecs3_1);
|
||||
tmp1 = _mm256_add_pd(tmp1, _mm256_permute2f128_pd(tmp1, tmp1, 1));
|
||||
|
||||
final_0 = padd(final_0, _mm256_blend_pd(tmp0, tmp1, 0xC));
|
||||
final_0 = _mm256_add_pd(final_0, _mm256_blend_pd(tmp0, tmp1, 0xC));
|
||||
|
||||
tmp0 = _mm256_hadd_pd(vecs4_0, vecs5_0);
|
||||
tmp0 = _mm256_add_pd(tmp0, _mm256_permute2f128_pd(tmp0, tmp0, 1));
|
||||
@ -835,7 +839,7 @@ template<> EIGEN_STRONG_INLINE Packet8d preduxp<Packet8d>(const Packet8d* vecs)
|
||||
tmp1 = _mm256_hadd_pd(vecs6_1, vecs7_1);
|
||||
tmp1 = _mm256_add_pd(tmp1, _mm256_permute2f128_pd(tmp1, tmp1, 1));
|
||||
|
||||
final_1 = padd(final_1, _mm256_blend_pd(tmp0, tmp1, 0xC));
|
||||
final_1 = _mm256_add_pd(final_1, _mm256_blend_pd(tmp0, tmp1, 0xC));
|
||||
|
||||
__m512d final_output = _mm512_insertf64x4(final_output, final_0, 0);
|
||||
|
||||
@ -844,55 +848,52 @@ template<> EIGEN_STRONG_INLINE Packet8d preduxp<Packet8d>(const Packet8d* vecs)
|
||||
|
||||
template <>
|
||||
EIGEN_STRONG_INLINE float predux<Packet16f>(const Packet16f& a) {
|
||||
//#ifdef EIGEN_VECTORIZE_AVX512DQ
|
||||
#if 0
|
||||
Packet8f lane0 = _mm512_extractf32x8_ps(a, 0);
|
||||
Packet8f lane1 = _mm512_extractf32x8_ps(a, 1);
|
||||
Packet8f sum = padd(lane0, lane1);
|
||||
Packet8f tmp0 = _mm256_hadd_ps(sum, _mm256_permute2f128_ps(a, a, 1));
|
||||
tmp0 = _mm256_hadd_ps(tmp0, tmp0);
|
||||
return pfirst(_mm256_hadd_ps(tmp0, tmp0));
|
||||
#ifdef EIGEN_VECTORIZE_AVX512DQ
|
||||
__m256 lane0 = _mm512_extractf32x8_ps(a, 0);
|
||||
__m256 lane1 = _mm512_extractf32x8_ps(a, 1);
|
||||
Packet8f x = _mm256_add_ps(lane0, lane1);
|
||||
return predux<Packet8f>(x);
|
||||
#else
|
||||
Packet4f lane0 = _mm512_extractf32x4_ps(a, 0);
|
||||
Packet4f lane1 = _mm512_extractf32x4_ps(a, 1);
|
||||
Packet4f lane2 = _mm512_extractf32x4_ps(a, 2);
|
||||
Packet4f lane3 = _mm512_extractf32x4_ps(a, 3);
|
||||
Packet4f sum = padd(padd(lane0, lane1), padd(lane2, lane3));
|
||||
__m128 lane0 = _mm512_extractf32x4_ps(a, 0);
|
||||
__m128 lane1 = _mm512_extractf32x4_ps(a, 1);
|
||||
__m128 lane2 = _mm512_extractf32x4_ps(a, 2);
|
||||
__m128 lane3 = _mm512_extractf32x4_ps(a, 3);
|
||||
__m128 sum = _mm_add_ps(_mm_add_ps(lane0, lane1), _mm_add_ps(lane2, lane3));
|
||||
sum = _mm_hadd_ps(sum, sum);
|
||||
sum = _mm_hadd_ps(sum, _mm_permute_ps(sum, 1));
|
||||
return pfirst(sum);
|
||||
return _mm_cvtss_f32(sum);
|
||||
#endif
|
||||
}
|
||||
template <>
|
||||
EIGEN_STRONG_INLINE double predux<Packet8d>(const Packet8d& a) {
|
||||
Packet4d lane0 = _mm512_extractf64x4_pd(a, 0);
|
||||
Packet4d lane1 = _mm512_extractf64x4_pd(a, 1);
|
||||
Packet4d sum = padd(lane0, lane1);
|
||||
Packet4d tmp0 = _mm256_hadd_pd(sum, _mm256_permute2f128_pd(sum, sum, 1));
|
||||
return pfirst(_mm256_hadd_pd(tmp0, tmp0));
|
||||
__m256d lane0 = _mm512_extractf64x4_pd(a, 0);
|
||||
__m256d lane1 = _mm512_extractf64x4_pd(a, 1);
|
||||
__m256d sum = _mm256_add_pd(lane0, lane1);
|
||||
__m256d tmp0 = _mm256_hadd_pd(sum, _mm256_permute2f128_pd(sum, sum, 1));
|
||||
return _mm_cvtsd_f64(_mm256_castpd256_pd128(_mm256_hadd_pd(tmp0, tmp0)));
|
||||
}
|
||||
|
||||
template <>
|
||||
EIGEN_STRONG_INLINE Packet8f predux_downto4<Packet16f>(const Packet16f& a) {
|
||||
#ifdef EIGEN_VECTORIZE_AVX512DQ
|
||||
Packet8f lane0 = _mm512_extractf32x8_ps(a, 0);
|
||||
Packet8f lane1 = _mm512_extractf32x8_ps(a, 1);
|
||||
return padd(lane0, lane1);
|
||||
__m256 lane0 = _mm512_extractf32x8_ps(a, 0);
|
||||
__m256 lane1 = _mm512_extractf32x8_ps(a, 1);
|
||||
return _mm256_add_ps(lane0, lane1);
|
||||
#else
|
||||
Packet4f lane0 = _mm512_extractf32x4_ps(a, 0);
|
||||
Packet4f lane1 = _mm512_extractf32x4_ps(a, 1);
|
||||
Packet4f lane2 = _mm512_extractf32x4_ps(a, 2);
|
||||
Packet4f lane3 = _mm512_extractf32x4_ps(a, 3);
|
||||
Packet4f sum0 = padd(lane0, lane2);
|
||||
Packet4f sum1 = padd(lane1, lane3);
|
||||
__m128 lane0 = _mm512_extractf32x4_ps(a, 0);
|
||||
__m128 lane1 = _mm512_extractf32x4_ps(a, 1);
|
||||
__m128 lane2 = _mm512_extractf32x4_ps(a, 2);
|
||||
__m128 lane3 = _mm512_extractf32x4_ps(a, 3);
|
||||
__m128 sum0 = _mm_add_ps(lane0, lane2);
|
||||
__m128 sum1 = _mm_add_ps(lane1, lane3);
|
||||
return _mm256_insertf128_ps(_mm256_castps128_ps256(sum0), sum1, 1);
|
||||
#endif
|
||||
}
|
||||
template <>
|
||||
EIGEN_STRONG_INLINE Packet4d predux_downto4<Packet8d>(const Packet8d& a) {
|
||||
Packet4d lane0 = _mm512_extractf64x4_pd(a, 0);
|
||||
Packet4d lane1 = _mm512_extractf64x4_pd(a, 1);
|
||||
Packet4d res = padd(lane0, lane1);
|
||||
__m256d lane0 = _mm512_extractf64x4_pd(a, 0);
|
||||
__m256d lane1 = _mm512_extractf64x4_pd(a, 1);
|
||||
__m256d res = _mm256_add_pd(lane0, lane1);
|
||||
return res;
|
||||
}
|
||||
|
||||
@ -907,58 +908,59 @@ EIGEN_STRONG_INLINE float predux_mul<Packet16f>(const Packet16f& a) {
|
||||
res = pmul(res, _mm_permute_ps(res, _MM_SHUFFLE(0, 0, 3, 2)));
|
||||
return pfirst(pmul(res, _mm_permute_ps(res, _MM_SHUFFLE(0, 0, 0, 1))));
|
||||
#else
|
||||
Packet4f lane0 = _mm512_extractf32x4_ps(a, 0);
|
||||
Packet4f lane1 = _mm512_extractf32x4_ps(a, 1);
|
||||
Packet4f lane2 = _mm512_extractf32x4_ps(a, 2);
|
||||
Packet4f lane3 = _mm512_extractf32x4_ps(a, 3);
|
||||
Packet4f res = pmul(pmul(lane0, lane1), pmul(lane2, lane3));
|
||||
__m128 lane0 = _mm512_extractf32x4_ps(a, 0);
|
||||
__m128 lane1 = _mm512_extractf32x4_ps(a, 1);
|
||||
__m128 lane2 = _mm512_extractf32x4_ps(a, 2);
|
||||
__m128 lane3 = _mm512_extractf32x4_ps(a, 3);
|
||||
__m128 res = pmul(pmul(lane0, lane1), pmul(lane2, lane3));
|
||||
res = pmul(res, _mm_permute_ps(res, _MM_SHUFFLE(0, 0, 3, 2)));
|
||||
return pfirst(pmul(res, _mm_permute_ps(res, _MM_SHUFFLE(0, 0, 0, 1))));
|
||||
#endif
|
||||
}
|
||||
template <>
|
||||
EIGEN_STRONG_INLINE double predux_mul<Packet8d>(const Packet8d& a) {
|
||||
Packet4d lane0 = _mm512_extractf64x4_pd(a, 0);
|
||||
Packet4d lane1 = _mm512_extractf64x4_pd(a, 1);
|
||||
Packet4d res = pmul(lane0, lane1);
|
||||
__m256d lane0 = _mm512_extractf64x4_pd(a, 0);
|
||||
__m256d lane1 = _mm512_extractf64x4_pd(a, 1);
|
||||
__m256d res = pmul(lane0, lane1);
|
||||
res = pmul(res, _mm256_permute2f128_pd(res, res, 1));
|
||||
return pfirst(pmul(res, _mm256_shuffle_pd(res, res, 1)));
|
||||
}
|
||||
|
||||
template <>
|
||||
EIGEN_STRONG_INLINE float predux_min<Packet16f>(const Packet16f& a) {
|
||||
Packet4f lane0 = _mm512_extractf32x4_ps(a, 0);
|
||||
Packet4f lane1 = _mm512_extractf32x4_ps(a, 1);
|
||||
Packet4f lane2 = _mm512_extractf32x4_ps(a, 2);
|
||||
Packet4f lane3 = _mm512_extractf32x4_ps(a, 3);
|
||||
Packet4f res = _mm_min_ps(_mm_min_ps(lane0, lane1), _mm_min_ps(lane2, lane3));
|
||||
__m128 lane0 = _mm512_extractf32x4_ps(a, 0);
|
||||
__m128 lane1 = _mm512_extractf32x4_ps(a, 1);
|
||||
__m128 lane2 = _mm512_extractf32x4_ps(a, 2);
|
||||
__m128 lane3 = _mm512_extractf32x4_ps(a, 3);
|
||||
__m128 res = _mm_min_ps(_mm_min_ps(lane0, lane1), _mm_min_ps(lane2, lane3));
|
||||
res = _mm_min_ps(res, _mm_permute_ps(res, _MM_SHUFFLE(0, 0, 3, 2)));
|
||||
return pfirst(_mm_min_ps(res, _mm_permute_ps(res, _MM_SHUFFLE(0, 0, 0, 1))));
|
||||
}
|
||||
template <>
|
||||
EIGEN_STRONG_INLINE double predux_min<Packet8d>(const Packet8d& a) {
|
||||
Packet4d lane0 = _mm512_extractf64x4_pd(a, 0);
|
||||
Packet4d lane1 = _mm512_extractf64x4_pd(a, 1);
|
||||
Packet4d res = _mm256_min_pd(lane0, lane1);
|
||||
__m256d lane0 = _mm512_extractf64x4_pd(a, 0);
|
||||
__m256d lane1 = _mm512_extractf64x4_pd(a, 1);
|
||||
__m256d res = _mm256_min_pd(lane0, lane1);
|
||||
res = _mm256_min_pd(res, _mm256_permute2f128_pd(res, res, 1));
|
||||
return pfirst(_mm256_min_pd(res, _mm256_shuffle_pd(res, res, 1)));
|
||||
}
|
||||
|
||||
template <>
|
||||
EIGEN_STRONG_INLINE float predux_max<Packet16f>(const Packet16f& a) {
|
||||
Packet4f lane0 = _mm512_extractf32x4_ps(a, 0);
|
||||
Packet4f lane1 = _mm512_extractf32x4_ps(a, 1);
|
||||
Packet4f lane2 = _mm512_extractf32x4_ps(a, 2);
|
||||
Packet4f lane3 = _mm512_extractf32x4_ps(a, 3);
|
||||
Packet4f res = _mm_max_ps(_mm_max_ps(lane0, lane1), _mm_max_ps(lane2, lane3));
|
||||
__m128 lane0 = _mm512_extractf32x4_ps(a, 0);
|
||||
__m128 lane1 = _mm512_extractf32x4_ps(a, 1);
|
||||
__m128 lane2 = _mm512_extractf32x4_ps(a, 2);
|
||||
__m128 lane3 = _mm512_extractf32x4_ps(a, 3);
|
||||
__m128 res = _mm_max_ps(_mm_max_ps(lane0, lane1), _mm_max_ps(lane2, lane3));
|
||||
res = _mm_max_ps(res, _mm_permute_ps(res, _MM_SHUFFLE(0, 0, 3, 2)));
|
||||
return pfirst(_mm_max_ps(res, _mm_permute_ps(res, _MM_SHUFFLE(0, 0, 0, 1))));
|
||||
}
|
||||
|
||||
template <>
|
||||
EIGEN_STRONG_INLINE double predux_max<Packet8d>(const Packet8d& a) {
|
||||
Packet4d lane0 = _mm512_extractf64x4_pd(a, 0);
|
||||
Packet4d lane1 = _mm512_extractf64x4_pd(a, 1);
|
||||
Packet4d res = _mm256_max_pd(lane0, lane1);
|
||||
__m256d lane0 = _mm512_extractf64x4_pd(a, 0);
|
||||
__m256d lane1 = _mm512_extractf64x4_pd(a, 1);
|
||||
__m256d res = _mm256_max_pd(lane0, lane1);
|
||||
res = _mm256_max_pd(res, _mm256_permute2f128_pd(res, res, 1));
|
||||
return pfirst(_mm256_max_pd(res, _mm256_shuffle_pd(res, res, 1)));
|
||||
}
|
||||
|
@ -65,7 +65,7 @@ template<> struct unpacket_traits<Packet2cf> { typedef std::complex<float> type;
|
||||
template<> EIGEN_STRONG_INLINE Packet2cf pset1<Packet2cf>(const std::complex<float>& from)
|
||||
{
|
||||
Packet2cf res;
|
||||
if((ptrdiff_t(&from) % 16) == 0)
|
||||
if((std::ptrdiff_t(&from) % 16) == 0)
|
||||
res.v = pload<Packet4f>((const float *)&from);
|
||||
else
|
||||
res.v = ploadu<Packet4f>((const float *)&from);
|
||||
|
@ -90,7 +90,7 @@ static Packet16uc p16uc_DUPLICATE32_HI = { 0,1,2,3, 0,1,2,3, 4,5,6,7, 4,5,6,7 };
|
||||
#define _EIGEN_MASK_ALIGNMENT 0xfffffff0
|
||||
#endif
|
||||
|
||||
#define _EIGEN_ALIGNED_PTR(x) ((ptrdiff_t)(x) & _EIGEN_MASK_ALIGNMENT)
|
||||
#define _EIGEN_ALIGNED_PTR(x) ((std::ptrdiff_t)(x) & _EIGEN_MASK_ALIGNMENT)
|
||||
|
||||
// Handle endianness properly while loading constants
|
||||
// Define global static constants:
|
||||
@ -450,14 +450,14 @@ template<> EIGEN_STRONG_INLINE Packet4f ploadu<Packet4f>(const float* from)
|
||||
template<> EIGEN_STRONG_INLINE Packet4f ploaddup<Packet4f>(const float* from)
|
||||
{
|
||||
Packet4f p;
|
||||
if((ptrdiff_t(from) % 16) == 0) p = pload<Packet4f>(from);
|
||||
if((std::ptrdiff_t(from) % 16) == 0) p = pload<Packet4f>(from);
|
||||
else p = ploadu<Packet4f>(from);
|
||||
return vec_perm(p, p, p16uc_DUPLICATE32_HI);
|
||||
}
|
||||
template<> EIGEN_STRONG_INLINE Packet4i ploaddup<Packet4i>(const int* from)
|
||||
{
|
||||
Packet4i p;
|
||||
if((ptrdiff_t(from) % 16) == 0) p = pload<Packet4i>(from);
|
||||
if((std::ptrdiff_t(from) % 16) == 0) p = pload<Packet4i>(from);
|
||||
else p = ploadu<Packet4i>(from);
|
||||
return vec_perm(p, p, p16uc_DUPLICATE32_HI);
|
||||
}
|
||||
@ -935,7 +935,7 @@ template<> EIGEN_STRONG_INLINE Packet2d ploadu<Packet2d>(const double* from)
|
||||
template<> EIGEN_STRONG_INLINE Packet2d ploaddup<Packet2d>(const double* from)
|
||||
{
|
||||
Packet2d p;
|
||||
if((ptrdiff_t(from) % 16) == 0) p = pload<Packet2d>(from);
|
||||
if((std::ptrdiff_t(from) % 16) == 0) p = pload<Packet2d>(from);
|
||||
else p = ploadu<Packet2d>(from);
|
||||
return vec_splat_dbl<0>(p);
|
||||
}
|
||||
|
@ -250,8 +250,34 @@ template<> EIGEN_STRONG_INLINE Packet4f pmadd(const Packet4f& a, const Packet4f&
|
||||
template<> EIGEN_STRONG_INLINE Packet2d pmadd(const Packet2d& a, const Packet2d& b, const Packet2d& c) { return _mm_fmadd_pd(a,b,c); }
|
||||
#endif
|
||||
|
||||
template<> EIGEN_STRONG_INLINE Packet4f pmin<Packet4f>(const Packet4f& a, const Packet4f& b) { return _mm_min_ps(a,b); }
|
||||
template<> EIGEN_STRONG_INLINE Packet2d pmin<Packet2d>(const Packet2d& a, const Packet2d& b) { return _mm_min_pd(a,b); }
|
||||
template<> EIGEN_STRONG_INLINE Packet4f pmin<Packet4f>(const Packet4f& a, const Packet4f& b) {
|
||||
#if EIGEN_COMP_GNUC
|
||||
// There appears to be a bug in GCC, by which the optimizer may
|
||||
// flip the argument order in calls to _mm_min_ps, so we have to
|
||||
// resort to inline ASM here. This is supposed to be fixed in gcc6.3,
|
||||
// see also: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=72867
|
||||
Packet4f res = b;
|
||||
asm("minps %[a], %[res]" : [res] "+x" (res) : [a] "x" (a));
|
||||
return res;
|
||||
#else
|
||||
// Arguments are reversed to match NaN propagation behavior of std::min.
|
||||
return _mm_min_ps(b, a);
|
||||
#endif
|
||||
}
|
||||
template<> EIGEN_STRONG_INLINE Packet2d pmin<Packet2d>(const Packet2d& a, const Packet2d& b) {
|
||||
#if EIGEN_COMP_GNUC
|
||||
// There appears to be a bug in GCC, by which the optimizer may
|
||||
// flip the argument order in calls to _mm_min_pd, so we have to
|
||||
// resort to inline ASM here. This is supposed to be fixed in gcc6.3,
|
||||
// see also: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=72867
|
||||
Packet2d res = b;
|
||||
asm("minpd %[a], %[res]" : [res] "+x" (res) : [a] "x" (a));
|
||||
return res;
|
||||
#else
|
||||
// Arguments are reversed to match NaN propagation behavior of std::min.
|
||||
return _mm_min_pd(b, a);
|
||||
#endif
|
||||
}
|
||||
template<> EIGEN_STRONG_INLINE Packet4i pmin<Packet4i>(const Packet4i& a, const Packet4i& b)
|
||||
{
|
||||
#ifdef EIGEN_VECTORIZE_SSE4_1
|
||||
@ -263,8 +289,34 @@ template<> EIGEN_STRONG_INLINE Packet4i pmin<Packet4i>(const Packet4i& a, const
|
||||
#endif
|
||||
}
|
||||
|
||||
template<> EIGEN_STRONG_INLINE Packet4f pmax<Packet4f>(const Packet4f& a, const Packet4f& b) { return _mm_max_ps(a,b); }
|
||||
template<> EIGEN_STRONG_INLINE Packet2d pmax<Packet2d>(const Packet2d& a, const Packet2d& b) { return _mm_max_pd(a,b); }
|
||||
template<> EIGEN_STRONG_INLINE Packet4f pmax<Packet4f>(const Packet4f& a, const Packet4f& b) {
|
||||
#if EIGEN_COMP_GNUC
|
||||
// There appears to be a bug in GCC, by which the optimizer may
|
||||
// flip the argument order in calls to _mm_max_ps, so we have to
|
||||
// resort to inline ASM here. This is supposed to be fixed in gcc6.3,
|
||||
// see also: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=72867
|
||||
Packet4f res = b;
|
||||
asm("maxps %[a], %[res]" : [res] "+x" (res) : [a] "x" (a));
|
||||
return res;
|
||||
#else
|
||||
// Arguments are reversed to match NaN propagation behavior of std::max.
|
||||
return _mm_max_ps(b, a);
|
||||
#endif
|
||||
}
|
||||
template<> EIGEN_STRONG_INLINE Packet2d pmax<Packet2d>(const Packet2d& a, const Packet2d& b) {
|
||||
#if EIGEN_COMP_GNUC
|
||||
// There appears to be a bug in GCC, by which the optimizer may
|
||||
// flip the argument order in calls to _mm_max_pd, so we have to
|
||||
// resort to inline ASM here. This is supposed to be fixed in gcc6.3,
|
||||
// see also: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=72867
|
||||
Packet2d res = b;
|
||||
asm("maxpd %[a], %[res]" : [res] "+x" (res) : [a] "x" (a));
|
||||
return res;
|
||||
#else
|
||||
// Arguments are reversed to match NaN propagation behavior of std::max.
|
||||
return _mm_max_pd(b, a);
|
||||
#endif
|
||||
}
|
||||
template<> EIGEN_STRONG_INLINE Packet4i pmax<Packet4i>(const Packet4i& a, const Packet4i& b)
|
||||
{
|
||||
#ifdef EIGEN_VECTORIZE_SSE4_1
|
||||
|
@ -100,7 +100,7 @@ static Packet16uc p16uc_DUPLICATE32_HI = { 0,1,2,3, 0,1,2,3, 4,5,6,7, 4,5,6,7 };
|
||||
// Mask alignment
|
||||
#define _EIGEN_MASK_ALIGNMENT 0xfffffffffffffff0
|
||||
|
||||
#define _EIGEN_ALIGNED_PTR(x) ((ptrdiff_t)(x) & _EIGEN_MASK_ALIGNMENT)
|
||||
#define _EIGEN_ALIGNED_PTR(x) ((std::ptrdiff_t)(x) & _EIGEN_MASK_ALIGNMENT)
|
||||
|
||||
// Handle endianness properly while loading constants
|
||||
// Define global static constants:
|
||||
|
@ -28,7 +28,7 @@ template<typename DstScalar,typename SrcScalar> struct assign_op {
|
||||
{ internal::pstoret<DstScalar,Packet,Alignment>(a,b); }
|
||||
};
|
||||
|
||||
// Empty overload for void type (used by PermutationMatrix
|
||||
// Empty overload for void type (used by PermutationMatrix)
|
||||
template<typename DstScalar> struct assign_op<DstScalar,void> {};
|
||||
|
||||
template<typename DstScalar,typename SrcScalar>
|
||||
|
@ -93,8 +93,8 @@ struct linspaced_op_impl<Scalar,Packet,/*IsInteger*/true>
|
||||
linspaced_op_impl(const Scalar& low, const Scalar& high, Index num_steps) :
|
||||
m_low(low),
|
||||
m_multiplier((high-low)/convert_index<Scalar>(num_steps<=1 ? 1 : num_steps-1)),
|
||||
m_divisor(convert_index<Scalar>(num_steps+high-low)/(high-low+1)),
|
||||
m_use_divisor((high+1)<(low+num_steps))
|
||||
m_divisor(convert_index<Scalar>((high>=low?num_steps:-num_steps)+(high-low))/((numext::abs(high-low)+1)==0?1:(numext::abs(high-low)+1))),
|
||||
m_use_divisor(num_steps>1 && (numext::abs(high-low)+1)<num_steps)
|
||||
{}
|
||||
|
||||
template<typename IndexType>
|
||||
|
@ -72,7 +72,7 @@ template<typename T>
|
||||
struct functor_traits<std::not_equal_to<T> >
|
||||
{ enum { Cost = 1, PacketAccess = false }; };
|
||||
|
||||
#if(__cplusplus < 201103L)
|
||||
#if (__cplusplus < 201103L) && (EIGEN_COMP_MSVC <= 1900)
|
||||
// std::binder* are deprecated since c++11 and will be removed in c++17
|
||||
template<typename T>
|
||||
struct functor_traits<std::binder2nd<T> >
|
||||
|
@ -83,8 +83,8 @@ static void run(Index rows, Index cols, Index depth,
|
||||
if(info)
|
||||
{
|
||||
// this is the parallel version!
|
||||
Index tid = omp_get_thread_num();
|
||||
Index threads = omp_get_num_threads();
|
||||
int tid = omp_get_thread_num();
|
||||
int threads = omp_get_num_threads();
|
||||
|
||||
LhsScalar* blockA = blocking.blockA();
|
||||
eigen_internal_assert(blockA!=0);
|
||||
@ -116,9 +116,9 @@ static void run(Index rows, Index cols, Index depth,
|
||||
info[tid].sync = k;
|
||||
|
||||
// Computes C_i += A' * B' per A'_i
|
||||
for(Index shift=0; shift<threads; ++shift)
|
||||
for(int shift=0; shift<threads; ++shift)
|
||||
{
|
||||
Index i = (tid+shift)%threads;
|
||||
int i = (tid+shift)%threads;
|
||||
|
||||
// At this point we have to make sure that A'_i has been updated by the thread i,
|
||||
// we use testAndSetOrdered to mimic a volatile access.
|
||||
|
@ -199,7 +199,7 @@ struct general_product_to_triangular_selector;
|
||||
template<typename MatrixType, typename ProductType, int UpLo>
|
||||
struct general_product_to_triangular_selector<MatrixType,ProductType,UpLo,true>
|
||||
{
|
||||
static void run(MatrixType& mat, const ProductType& prod, const typename MatrixType::Scalar& alpha)
|
||||
static void run(MatrixType& mat, const ProductType& prod, const typename MatrixType::Scalar& alpha, bool beta)
|
||||
{
|
||||
typedef typename MatrixType::Scalar Scalar;
|
||||
|
||||
@ -217,6 +217,9 @@ struct general_product_to_triangular_selector<MatrixType,ProductType,UpLo,true>
|
||||
|
||||
Scalar actualAlpha = alpha * LhsBlasTraits::extractScalarFactor(prod.lhs().derived()) * RhsBlasTraits::extractScalarFactor(prod.rhs().derived());
|
||||
|
||||
if(!beta)
|
||||
mat.template triangularView<UpLo>().setZero();
|
||||
|
||||
enum {
|
||||
StorageOrder = (internal::traits<MatrixType>::Flags&RowMajorBit) ? RowMajor : ColMajor,
|
||||
UseLhsDirectly = _ActualLhs::InnerStrideAtCompileTime==1,
|
||||
@ -244,7 +247,7 @@ struct general_product_to_triangular_selector<MatrixType,ProductType,UpLo,true>
|
||||
template<typename MatrixType, typename ProductType, int UpLo>
|
||||
struct general_product_to_triangular_selector<MatrixType,ProductType,UpLo,false>
|
||||
{
|
||||
static void run(MatrixType& mat, const ProductType& prod, const typename MatrixType::Scalar& alpha)
|
||||
static void run(MatrixType& mat, const ProductType& prod, const typename MatrixType::Scalar& alpha, bool beta)
|
||||
{
|
||||
typedef typename internal::remove_all<typename ProductType::LhsNested>::type Lhs;
|
||||
typedef internal::blas_traits<Lhs> LhsBlasTraits;
|
||||
@ -260,6 +263,9 @@ struct general_product_to_triangular_selector<MatrixType,ProductType,UpLo,false>
|
||||
|
||||
typename ProductType::Scalar actualAlpha = alpha * LhsBlasTraits::extractScalarFactor(prod.lhs().derived()) * RhsBlasTraits::extractScalarFactor(prod.rhs().derived());
|
||||
|
||||
if(!beta)
|
||||
mat.template triangularView<UpLo>().setZero();
|
||||
|
||||
enum {
|
||||
IsRowMajor = (internal::traits<MatrixType>::Flags&RowMajorBit) ? 1 : 0,
|
||||
LhsIsRowMajor = _ActualLhs::Flags&RowMajorBit ? 1 : 0,
|
||||
@ -286,11 +292,11 @@ struct general_product_to_triangular_selector<MatrixType,ProductType,UpLo,false>
|
||||
|
||||
template<typename MatrixType, unsigned int UpLo>
|
||||
template<typename ProductType>
|
||||
TriangularView<MatrixType,UpLo>& TriangularViewImpl<MatrixType,UpLo,Dense>::_assignProduct(const ProductType& prod, const Scalar& alpha)
|
||||
TriangularView<MatrixType,UpLo>& TriangularViewImpl<MatrixType,UpLo,Dense>::_assignProduct(const ProductType& prod, const Scalar& alpha, bool beta)
|
||||
{
|
||||
eigen_assert(derived().nestedExpression().rows() == prod.rows() && derived().cols() == prod.cols());
|
||||
|
||||
general_product_to_triangular_selector<MatrixType, ProductType, UpLo, internal::traits<ProductType>::InnerSize==1>::run(derived().nestedExpression().const_cast_derived(), prod, alpha);
|
||||
general_product_to_triangular_selector<MatrixType, ProductType, UpLo, internal::traits<ProductType>::InnerSize==1>::run(derived().nestedExpression().const_cast_derived(), prod, alpha, beta);
|
||||
|
||||
return derived();
|
||||
}
|
||||
|
@ -75,7 +75,7 @@ template<typename Index> struct GemmParallelInfo
|
||||
{
|
||||
GemmParallelInfo() : sync(-1), users(0), lhs_start(0), lhs_length(0) {}
|
||||
|
||||
int volatile sync;
|
||||
Index volatile sync;
|
||||
int volatile users;
|
||||
|
||||
Index lhs_start;
|
||||
|
@ -83,10 +83,10 @@ EIGEN_DONT_INLINE void selfadjoint_matrix_vector_product<Scalar,Index,StorageOrd
|
||||
Scalar t3(0);
|
||||
Packet ptmp3 = pset1<Packet>(t3);
|
||||
|
||||
size_t starti = FirstTriangular ? 0 : j+2;
|
||||
size_t endi = FirstTriangular ? j : size;
|
||||
size_t alignedStart = (starti) + internal::first_default_aligned(&res[starti], endi-starti);
|
||||
size_t alignedEnd = alignedStart + ((endi-alignedStart)/(PacketSize))*(PacketSize);
|
||||
Index starti = FirstTriangular ? 0 : j+2;
|
||||
Index endi = FirstTriangular ? j : size;
|
||||
Index alignedStart = (starti) + internal::first_default_aligned(&res[starti], endi-starti);
|
||||
Index alignedEnd = alignedStart + ((endi-alignedStart)/(PacketSize))*(PacketSize);
|
||||
|
||||
res[j] += cjd.pmul(numext::real(A0[j]), t0);
|
||||
res[j+1] += cjd.pmul(numext::real(A1[j+1]), t1);
|
||||
@ -101,7 +101,7 @@ EIGEN_DONT_INLINE void selfadjoint_matrix_vector_product<Scalar,Index,StorageOrd
|
||||
t2 += cj1.pmul(A0[j+1], rhs[j+1]);
|
||||
}
|
||||
|
||||
for (size_t i=starti; i<alignedStart; ++i)
|
||||
for (Index i=starti; i<alignedStart; ++i)
|
||||
{
|
||||
res[i] += cj0.pmul(A0[i], t0) + cj0.pmul(A1[i],t1);
|
||||
t2 += cj1.pmul(A0[i], rhs[i]);
|
||||
@ -113,7 +113,7 @@ EIGEN_DONT_INLINE void selfadjoint_matrix_vector_product<Scalar,Index,StorageOrd
|
||||
const Scalar* EIGEN_RESTRICT a1It = A1 + alignedStart;
|
||||
const Scalar* EIGEN_RESTRICT rhsIt = rhs + alignedStart;
|
||||
Scalar* EIGEN_RESTRICT resIt = res + alignedStart;
|
||||
for (size_t i=alignedStart; i<alignedEnd; i+=PacketSize)
|
||||
for (Index i=alignedStart; i<alignedEnd; i+=PacketSize)
|
||||
{
|
||||
Packet A0i = ploadu<Packet>(a0It); a0It += PacketSize;
|
||||
Packet A1i = ploadu<Packet>(a1It); a1It += PacketSize;
|
||||
@ -125,7 +125,7 @@ EIGEN_DONT_INLINE void selfadjoint_matrix_vector_product<Scalar,Index,StorageOrd
|
||||
ptmp3 = pcj1.pmadd(A1i, Bi, ptmp3);
|
||||
pstore(resIt,Xi); resIt += PacketSize;
|
||||
}
|
||||
for (size_t i=alignedEnd; i<endi; i++)
|
||||
for (Index i=alignedEnd; i<endi; i++)
|
||||
{
|
||||
res[i] += cj0.pmul(A0[i], t0) + cj0.pmul(A1[i],t1);
|
||||
t2 += cj1.pmul(A0[i], rhs[i]);
|
||||
|
@ -25,6 +25,10 @@ const int Dynamic = -1;
|
||||
*/
|
||||
const int DynamicIndex = 0xffffff;
|
||||
|
||||
/** This value means that the increment to go from one value to another in a sequence is not constant for each step.
|
||||
*/
|
||||
const int UndefinedIncr = 0xfffffe;
|
||||
|
||||
/** This value means +Infinity; it is currently used only as the p parameter to MatrixBase::lpNorm<int>().
|
||||
* The value Infinity there means the L-infinity norm.
|
||||
*/
|
||||
|
@ -83,6 +83,7 @@ template<typename ExpressionType> class ForceAlignedAccess;
|
||||
template<typename ExpressionType> class SwapWrapper;
|
||||
|
||||
template<typename XprType, int BlockRows=Dynamic, int BlockCols=Dynamic, bool InnerPanel = false> class Block;
|
||||
template<typename XprType, typename RowIndices, typename ColIndices> class IndexedView;
|
||||
|
||||
template<typename MatrixType, int Size=Dynamic> class VectorBlock;
|
||||
template<typename MatrixType> class Transpose;
|
||||
|
187
Eigen/src/Core/util/IndexedViewHelper.h
Normal file
187
Eigen/src/Core/util/IndexedViewHelper.h
Normal file
@ -0,0 +1,187 @@
|
||||
// This file is part of Eigen, a lightweight C++ template library
|
||||
// for linear algebra.
|
||||
//
|
||||
// Copyright (C) 2017 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_INDEXED_VIEW_HELPER_H
|
||||
#define EIGEN_INDEXED_VIEW_HELPER_H
|
||||
|
||||
namespace Eigen {
|
||||
|
||||
/** \namespace Eigen::placeholders
|
||||
* \ingroup Core_Module
|
||||
*
|
||||
* Namespace containing symbolic placeholder and identifiers
|
||||
*/
|
||||
namespace placeholders {
|
||||
|
||||
namespace internal {
|
||||
struct symbolic_last_tag {};
|
||||
}
|
||||
|
||||
/** \var last
|
||||
* \ingroup Core_Module
|
||||
*
|
||||
* Can be used as a parameter to Eigen::seq and Eigen::seqN functions to symbolically reference the last element/row/columns
|
||||
* of the underlying vector or matrix once passed to DenseBase::operator()(const RowIndices&, const ColIndices&).
|
||||
*
|
||||
* This symbolic placeholder support standard arithmetic operation.
|
||||
*
|
||||
* A typical usage example would be:
|
||||
* \code
|
||||
* using namespace Eigen;
|
||||
* using Eigen::placeholders::last;
|
||||
* VectorXd v(n);
|
||||
* v(seq(2,last-2)).setOnes();
|
||||
* \endcode
|
||||
*
|
||||
* \sa end
|
||||
*/
|
||||
static const Symbolic::SymbolExpr<internal::symbolic_last_tag> last;
|
||||
|
||||
/** \var end
|
||||
* \ingroup Core_Module
|
||||
*
|
||||
* Can be used as a parameter to Eigen::seq and Eigen::seqN functions to symbolically reference the last+1 element/row/columns
|
||||
* of the underlying vector or matrix once passed to DenseBase::operator()(const RowIndices&, const ColIndices&).
|
||||
*
|
||||
* This symbolic placeholder support standard arithmetic operation.
|
||||
* It is essentially an alias to last+1
|
||||
*
|
||||
* \sa last
|
||||
*/
|
||||
#ifdef EIGEN_PARSED_BY_DOXYGEN
|
||||
static const auto end = last+1;
|
||||
#else
|
||||
// Using a FixedExpr<1> expression is important here to make sure the compiler
|
||||
// can fully optimize the computation starting indices with zero overhead.
|
||||
static const Symbolic::AddExpr<Symbolic::SymbolExpr<internal::symbolic_last_tag>,Symbolic::ValueExpr<Eigen::internal::FixedInt<1> > > end(last+fix<1>());
|
||||
#endif
|
||||
|
||||
} // end namespace placeholders
|
||||
|
||||
namespace internal {
|
||||
|
||||
// Replace symbolic last/end "keywords" by their true runtime value
|
||||
inline Index eval_expr_given_size(Index x, Index /* size */) { return x; }
|
||||
|
||||
template<int N>
|
||||
FixedInt<N> eval_expr_given_size(FixedInt<N> x, Index /*size*/) { return x; }
|
||||
|
||||
template<typename Derived>
|
||||
Index eval_expr_given_size(const Symbolic::BaseExpr<Derived> &x, Index size)
|
||||
{
|
||||
return x.derived().eval(placeholders::last=size-1);
|
||||
}
|
||||
|
||||
// Extract increment/step at compile time
|
||||
template<typename T, typename EnableIf = void> struct get_compile_time_incr {
|
||||
enum { value = UndefinedIncr };
|
||||
};
|
||||
|
||||
// Analogue of std::get<0>(x), but tailored for our needs.
|
||||
template<typename T>
|
||||
Index first(const T& x) { return x.first(); }
|
||||
|
||||
// IndexedViewCompatibleType/makeIndexedViewCompatible turn an arbitrary object of type T into something usable by MatrixSlice
|
||||
// The generic implementation is a no-op
|
||||
template<typename T,int XprSize,typename EnableIf=void>
|
||||
struct IndexedViewCompatibleType {
|
||||
typedef T type;
|
||||
};
|
||||
|
||||
template<typename T,typename Q>
|
||||
const T& makeIndexedViewCompatible(const T& x, Index /*size*/, Q) { return x; }
|
||||
|
||||
//--------------------------------------------------------------------------------
|
||||
// Handling of a single Index
|
||||
//--------------------------------------------------------------------------------
|
||||
|
||||
struct SingleRange {
|
||||
enum {
|
||||
SizeAtCompileTime = 1
|
||||
};
|
||||
SingleRange(Index val) : m_value(val) {}
|
||||
Index operator[](Index) const { return m_value; }
|
||||
Index size() const { return 1; }
|
||||
Index first() const { return m_value; }
|
||||
Index m_value;
|
||||
};
|
||||
|
||||
template<> struct get_compile_time_incr<SingleRange> {
|
||||
enum { value = 1 }; // 1 or 0 ??
|
||||
};
|
||||
|
||||
// Turn a single index into something that looks like an array (i.e., that exposes a .size(), and operatro[](int) methods)
|
||||
template<typename T, int XprSize>
|
||||
struct IndexedViewCompatibleType<T,XprSize,typename internal::enable_if<internal::is_integral<T>::value>::type> {
|
||||
// Here we could simply use Array, but maybe it's less work for the compiler to use
|
||||
// a simpler wrapper as SingleRange
|
||||
//typedef Eigen::Array<Index,1,1> type;
|
||||
typedef SingleRange type;
|
||||
};
|
||||
|
||||
template<typename T, int XprSize>
|
||||
struct IndexedViewCompatibleType<T, XprSize, typename enable_if<Symbolic::is_symbolic<T>::value>::type> {
|
||||
typedef SingleRange type;
|
||||
};
|
||||
|
||||
|
||||
template<typename T>
|
||||
typename enable_if<Symbolic::is_symbolic<T>::value,SingleRange>::type
|
||||
makeIndexedViewCompatible(const T& id, Index size, SpecializedType) {
|
||||
return eval_expr_given_size(id,size);
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------
|
||||
// Handling of all
|
||||
//--------------------------------------------------------------------------------
|
||||
|
||||
struct all_t { all_t() {} };
|
||||
|
||||
// Convert a symbolic 'all' into a usable range type
|
||||
template<int XprSize>
|
||||
struct AllRange {
|
||||
enum { SizeAtCompileTime = XprSize };
|
||||
AllRange(Index size = XprSize) : m_size(size) {}
|
||||
Index operator[](Index i) const { return i; }
|
||||
Index size() const { return m_size.value(); }
|
||||
Index first() const { return 0; }
|
||||
variable_if_dynamic<Index,XprSize> m_size;
|
||||
};
|
||||
|
||||
template<int XprSize>
|
||||
struct IndexedViewCompatibleType<all_t,XprSize> {
|
||||
typedef AllRange<XprSize> type;
|
||||
};
|
||||
|
||||
template<typename XprSizeType>
|
||||
inline AllRange<get_fixed_value<XprSizeType>::value> makeIndexedViewCompatible(all_t , XprSizeType size, SpecializedType) {
|
||||
return AllRange<get_fixed_value<XprSizeType>::value>(size);
|
||||
}
|
||||
|
||||
template<int Size> struct get_compile_time_incr<AllRange<Size> > {
|
||||
enum { value = 1 };
|
||||
};
|
||||
|
||||
} // end namespace internal
|
||||
|
||||
|
||||
namespace placeholders {
|
||||
|
||||
/** \var all
|
||||
* \ingroup Core_Module
|
||||
* Can be used as a parameter to DenseBase::operator()(const RowIndices&, const ColIndices&) to index all rows or columns
|
||||
*/
|
||||
static const Eigen::internal::all_t all;
|
||||
|
||||
}
|
||||
|
||||
} // end namespace Eigen
|
||||
|
||||
#endif // EIGEN_INDEXED_VIEW_HELPER_H
|
270
Eigen/src/Core/util/IntegralConstant.h
Normal file
270
Eigen/src/Core/util/IntegralConstant.h
Normal file
@ -0,0 +1,270 @@
|
||||
// This file is part of Eigen, a lightweight C++ template library
|
||||
// for linear algebra.
|
||||
//
|
||||
// Copyright (C) 2017 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_INTEGRAL_CONSTANT_H
|
||||
#define EIGEN_INTEGRAL_CONSTANT_H
|
||||
|
||||
namespace Eigen {
|
||||
|
||||
namespace internal {
|
||||
|
||||
template<int N> class FixedInt;
|
||||
template<int N> class VariableAndFixedInt;
|
||||
|
||||
/** \internal
|
||||
* \class FixedInt
|
||||
*
|
||||
* This class embeds a compile-time integer \c N.
|
||||
*
|
||||
* It is similar to c++11 std::integral_constant<int,N> but with some additional features
|
||||
* such as:
|
||||
* - implicit conversion to int
|
||||
* - arithmetic and some bitwise operators: -, +, *, /, %, &, |
|
||||
* - c++98/14 compatibility with fix<N> and fix<N>() syntax to define integral constants.
|
||||
*
|
||||
* It is strongly discouraged to directly deal with this class FixedInt. Instances are expcected to
|
||||
* be created by the user using Eigen::fix<N> or Eigen::fix<N>(). In C++98-11, the former syntax does
|
||||
* not create a FixedInt<N> instance but rather a point to function that needs to be \em cleaned-up
|
||||
* using the generic helper:
|
||||
* \code
|
||||
* internal::cleanup_index_type<T>::type
|
||||
* internal::cleanup_index_type<T,DynamicKey>::type
|
||||
* \endcode
|
||||
* where T can a FixedInt<N>, a pointer to function FixedInt<N> (*)(), or numerous other integer-like representations.
|
||||
* \c DynamicKey is either Dynamic (default) or DynamicIndex and used to identify true compile-time values.
|
||||
*
|
||||
* For convenience, you can extract the compile-time value \c N in a generic way using the following helper:
|
||||
* \code
|
||||
* internal::get_fixed_value<T,DefaultVal>::value
|
||||
* \endcode
|
||||
* that will give you \c N if T equals FixedInt<N> or FixedInt<N> (*)(), and \c DefaultVal if T does not embed any compile-time value (e.g., T==int).
|
||||
*
|
||||
* \sa fix<N>, class VariableAndFixedInt
|
||||
*/
|
||||
template<int N> class FixedInt
|
||||
{
|
||||
public:
|
||||
static const int value = N;
|
||||
operator int() const { return value; }
|
||||
FixedInt() {}
|
||||
FixedInt( VariableAndFixedInt<N> other) {
|
||||
EIGEN_ONLY_USED_FOR_DEBUG(other);
|
||||
eigen_internal_assert(int(other)==N);
|
||||
}
|
||||
|
||||
FixedInt<-N> operator-() const { return FixedInt<-N>(); }
|
||||
template<int M>
|
||||
FixedInt<N+M> operator+( FixedInt<M>) const { return FixedInt<N+M>(); }
|
||||
template<int M>
|
||||
FixedInt<N-M> operator-( FixedInt<M>) const { return FixedInt<N-M>(); }
|
||||
template<int M>
|
||||
FixedInt<N*M> operator*( FixedInt<M>) const { return FixedInt<N*M>(); }
|
||||
template<int M>
|
||||
FixedInt<N/M> operator/( FixedInt<M>) const { return FixedInt<N/M>(); }
|
||||
template<int M>
|
||||
FixedInt<N%M> operator%( FixedInt<M>) const { return FixedInt<N%M>(); }
|
||||
template<int M>
|
||||
FixedInt<N|M> operator|( FixedInt<M>) const { return FixedInt<N|M>(); }
|
||||
template<int M>
|
||||
FixedInt<N&M> operator&( FixedInt<M>) const { return FixedInt<N&M>(); }
|
||||
|
||||
#if EIGEN_HAS_CXX14
|
||||
// Needed in C++14 to allow fix<N>():
|
||||
FixedInt operator() () const { return *this; }
|
||||
|
||||
VariableAndFixedInt<N> operator() (int val) const { return VariableAndFixedInt<N>(val); }
|
||||
#else
|
||||
FixedInt ( FixedInt<N> (*)() ) {}
|
||||
#endif
|
||||
|
||||
#if EIGEN_HAS_CXX11
|
||||
FixedInt(std::integral_constant<int,N>) {}
|
||||
#endif
|
||||
};
|
||||
|
||||
/** \internal
|
||||
* \class VariableAndFixedInt
|
||||
*
|
||||
* This class embeds both a compile-time integer \c N and a runtime integer.
|
||||
* Both values are supposed to be equal unless the compile-time value \c N has a special
|
||||
* value meaning that the runtime-value should be used. Depending on the context, this special
|
||||
* value can be either Eigen::Dynamic (for positive quantities) or Eigen::DynamicIndex (for
|
||||
* quantities that can be negative).
|
||||
*
|
||||
* It is the return-type of the function Eigen::fix<N>(int), and most of the time this is the only
|
||||
* way it is used. It is strongly discouraged to directly deal with instances of VariableAndFixedInt.
|
||||
* Indeed, in order to write generic code, it is the responsibility of the callee to properly convert
|
||||
* it to either a true compile-time quantity (i.e. a FixedInt<N>), or to a runtime quantity (e.g., an Index)
|
||||
* using the following generic helper:
|
||||
* \code
|
||||
* internal::cleanup_index_type<T>::type
|
||||
* internal::cleanup_index_type<T,DynamicKey>::type
|
||||
* \endcode
|
||||
* where T can be a template instantiation of VariableAndFixedInt or numerous other integer-like representations.
|
||||
* \c DynamicKey is either Dynamic (default) or DynamicIndex and used to identify true compile-time values.
|
||||
*
|
||||
* For convenience, you can also extract the compile-time value \c N using the following helper:
|
||||
* \code
|
||||
* internal::get_fixed_value<T,DefaultVal>::value
|
||||
* \endcode
|
||||
* that will give you \c N if T equals VariableAndFixedInt<N>, and \c DefaultVal if T does not embed any compile-time value (e.g., T==int).
|
||||
*
|
||||
* \sa fix<N>(int), class FixedInt
|
||||
*/
|
||||
template<int N> class VariableAndFixedInt
|
||||
{
|
||||
public:
|
||||
static const int value = N;
|
||||
operator int() const { return m_value; }
|
||||
VariableAndFixedInt(int val) { m_value = val; }
|
||||
protected:
|
||||
int m_value;
|
||||
};
|
||||
|
||||
template<typename T, int Default=Dynamic> struct get_fixed_value {
|
||||
static const int value = Default;
|
||||
};
|
||||
|
||||
template<int N,int Default> struct get_fixed_value<FixedInt<N>,Default> {
|
||||
static const int value = N;
|
||||
};
|
||||
|
||||
#if !EIGEN_HAS_CXX14
|
||||
template<int N,int Default> struct get_fixed_value<FixedInt<N> (*)(),Default> {
|
||||
static const int value = N;
|
||||
};
|
||||
#endif
|
||||
|
||||
template<int N,int Default> struct get_fixed_value<VariableAndFixedInt<N>,Default> {
|
||||
static const int value = N ;
|
||||
};
|
||||
|
||||
template<typename T, int N, int Default>
|
||||
struct get_fixed_value<variable_if_dynamic<T,N>,Default> {
|
||||
static const int value = N;
|
||||
};
|
||||
|
||||
template<typename T> Index get_runtime_value(const T &x) { return x; }
|
||||
#if !EIGEN_HAS_CXX14
|
||||
template<int N> Index get_runtime_value(FixedInt<N> (*)()) { return N; }
|
||||
#endif
|
||||
|
||||
// Cleanup integer/FixedInt/VariableAndFixedInt/etc types:
|
||||
|
||||
// By default, no cleanup:
|
||||
template<typename T, int DynamicKey=Dynamic, typename EnableIf=void> struct cleanup_index_type { typedef T type; };
|
||||
|
||||
// Convert any integral type (e.g., short, int, unsigned int, etc.) to Eigen::Index
|
||||
template<typename T, int DynamicKey> struct cleanup_index_type<T,DynamicKey,typename internal::enable_if<internal::is_integral<T>::value>::type> { typedef Index type; };
|
||||
|
||||
#if !EIGEN_HAS_CXX14
|
||||
// In c++98/c++11, fix<N> is a pointer to function that we better cleanup to a true FixedInt<N>:
|
||||
template<int N, int DynamicKey> struct cleanup_index_type<FixedInt<N> (*)(), DynamicKey> { typedef FixedInt<N> type; };
|
||||
#endif
|
||||
|
||||
// If VariableAndFixedInt does not match DynamicKey, then we turn it to a pure compile-time value:
|
||||
template<int N, int DynamicKey> struct cleanup_index_type<VariableAndFixedInt<N>, DynamicKey> { typedef FixedInt<N> type; };
|
||||
// If VariableAndFixedInt matches DynamicKey, then we turn it to a pure runtime-value (aka Index):
|
||||
template<int DynamicKey> struct cleanup_index_type<VariableAndFixedInt<DynamicKey>, DynamicKey> { typedef Index type; };
|
||||
|
||||
#if EIGEN_HAS_CXX11
|
||||
template<int N, int DynamicKey> struct cleanup_index_type<std::integral_constant<int,N>, DynamicKey> { typedef FixedInt<N> type; };
|
||||
#endif
|
||||
|
||||
} // end namespace internal
|
||||
|
||||
#ifndef EIGEN_PARSED_BY_DOXYGEN
|
||||
|
||||
#if EIGEN_HAS_CXX14
|
||||
template<int N>
|
||||
static const internal::FixedInt<N> fix{};
|
||||
#else
|
||||
template<int N>
|
||||
inline internal::FixedInt<N> fix() { return internal::FixedInt<N>(); }
|
||||
|
||||
// The generic typename T is mandatory. Otherwise, a code like fix<N> could refer to either the function above or this next overload.
|
||||
// This way a code like fix<N> can only refer to the previous function.
|
||||
template<int N,typename T>
|
||||
inline internal::VariableAndFixedInt<N> fix(T val) { return internal::VariableAndFixedInt<N>(val); }
|
||||
#endif
|
||||
|
||||
#else // EIGEN_PARSED_BY_DOXYGEN
|
||||
|
||||
/** \var fix<N>()
|
||||
* \ingroup Core_Module
|
||||
*
|
||||
* This \em identifier permits to construct an object embedding a compile-time integer \c N.
|
||||
*
|
||||
* \tparam N the compile-time integer value
|
||||
*
|
||||
* It is typically used in conjunction with the Eigen::seq and Eigen::seqN functions to pass compile-time values to them:
|
||||
* \code
|
||||
* seqN(10,fix<4>,fix<-3>) // <=> [10 7 4 1]
|
||||
* \endcode
|
||||
*
|
||||
* See also the function fix(int) to pass both a compile-time and runtime value.
|
||||
*
|
||||
* In c++14, it is implemented as:
|
||||
* \code
|
||||
* template<int N> static const internal::FixedInt<N> fix{};
|
||||
* \endcode
|
||||
* where internal::FixedInt<N> is an internal template class similar to
|
||||
* <a href="http://en.cppreference.com/w/cpp/types/integral_constant">\c std::integral_constant </a><tt> <int,N> </tt>
|
||||
* Here, \c fix<N> is thus an object of type \c internal::FixedInt<N>.
|
||||
*
|
||||
* In c++98/11, it is implemented as a function:
|
||||
* \code
|
||||
* template<int N> inline internal::FixedInt<N> fix();
|
||||
* \endcode
|
||||
* Here internal::FixedInt<N> is thus a pointer to function.
|
||||
*
|
||||
* If for some reason you want a true object in c++98 then you can write: \code fix<N>() \endcode which is also valid in c++14.
|
||||
*
|
||||
* \sa fix<N>(int), seq, seqN
|
||||
*/
|
||||
template<int N>
|
||||
static const auto fix();
|
||||
|
||||
/** \fn fix<N>(int)
|
||||
* \ingroup Core_Module
|
||||
*
|
||||
* This function returns an object embedding both a compile-time integer \c N, and a fallback runtime value \a val.
|
||||
*
|
||||
* \tparam N the compile-time integer value
|
||||
* \param val the fallback runtime integer value
|
||||
*
|
||||
* This function is a more general version of the \ref fix identifier/function that can be used in template code
|
||||
* where the compile-time value could turn out to actually mean "undefined at compile-time". For positive integers
|
||||
* such as a size or a dimension, this case is identified by Eigen::Dynamic, whereas runtime signed integers
|
||||
* (e.g., an increment/stride) are identified as Eigen::DynamicIndex. In such a case, the runtime value \a val
|
||||
* will be used as a fallback.
|
||||
*
|
||||
* A typical use case would be:
|
||||
* \code
|
||||
* template<typename Derived> void foo(const MatrixBase<Derived> &mat) {
|
||||
* const int N = Derived::RowsAtCompileTime==Dynamic ? Dynamic : Derived::RowsAtCompileTime/2;
|
||||
* const int n = mat.rows()/2;
|
||||
* ... mat( seqN(0,fix<N>(n) ) ...;
|
||||
* }
|
||||
* \endcode
|
||||
* In this example, the function Eigen::seqN knows that the second argument is expected to be a size.
|
||||
* If the passed compile-time value N equals Eigen::Dynamic, then the proxy object returned by fix will be dissmissed, and converted to an Eigen::Index of value \c n.
|
||||
* Otherwise, the runtime-value \c n will be dissmissed, and the returned ArithmeticSequence will be of the exact same type as <tt> seqN(0,fix<N>) </tt>.
|
||||
*
|
||||
* \sa fix, seqN, class ArithmeticSequence
|
||||
*/
|
||||
template<int N>
|
||||
static const auto fix(int val);
|
||||
|
||||
#endif // EIGEN_PARSED_BY_DOXYGEN
|
||||
|
||||
} // end namespace Eigen
|
||||
|
||||
#endif // EIGEN_INTEGRAL_CONSTANT_H
|
@ -356,12 +356,17 @@
|
||||
#define EIGEN_MAX_CPP_VER 99
|
||||
#endif
|
||||
|
||||
#if EIGEN_MAX_CPP_VER>=11 && defined(__cplusplus) && (__cplusplus >= 201103L)
|
||||
#if EIGEN_MAX_CPP_VER>=11 && (defined(__cplusplus) && (__cplusplus >= 201103L) || EIGEN_COMP_MSVC >= 1900)
|
||||
#define EIGEN_HAS_CXX11 1
|
||||
#else
|
||||
#define EIGEN_HAS_CXX11 0
|
||||
#endif
|
||||
|
||||
#if EIGEN_MAX_CPP_VER>=14 && (defined(__cplusplus) && (__cplusplus > 201103L) || EIGEN_COMP_MSVC >= 1910)
|
||||
#define EIGEN_HAS_CXX14 1
|
||||
#else
|
||||
#define EIGEN_HAS_CXX14 0
|
||||
#endif
|
||||
|
||||
// Do we support r-value references?
|
||||
#ifndef EIGEN_HAS_RVALUE_REFERENCES
|
||||
@ -865,7 +870,8 @@ namespace Eigen {
|
||||
typedef typename Eigen::internal::ref_selector<Derived>::type Nested; \
|
||||
typedef typename Eigen::internal::traits<Derived>::StorageKind StorageKind; \
|
||||
typedef typename Eigen::internal::traits<Derived>::StorageIndex StorageIndex; \
|
||||
enum { RowsAtCompileTime = Eigen::internal::traits<Derived>::RowsAtCompileTime, \
|
||||
enum CompileTimeTraits \
|
||||
{ RowsAtCompileTime = Eigen::internal::traits<Derived>::RowsAtCompileTime, \
|
||||
ColsAtCompileTime = Eigen::internal::traits<Derived>::ColsAtCompileTime, \
|
||||
Flags = Eigen::internal::traits<Derived>::Flags, \
|
||||
SizeAtCompileTime = Base::SizeAtCompileTime, \
|
||||
|
@ -150,7 +150,7 @@ EIGEN_DEVICE_FUNC inline void check_that_malloc_is_allowed()
|
||||
/** \internal Allocates \a size bytes. The returned pointer is guaranteed to have 16 or 32 bytes alignment depending on the requirements.
|
||||
* On allocation error, the returned pointer is null, and std::bad_alloc is thrown.
|
||||
*/
|
||||
EIGEN_DEVICE_FUNC inline void* aligned_malloc(size_t size)
|
||||
EIGEN_DEVICE_FUNC inline void* aligned_malloc(std::size_t size)
|
||||
{
|
||||
check_that_malloc_is_allowed();
|
||||
|
||||
@ -185,7 +185,7 @@ EIGEN_DEVICE_FUNC inline void aligned_free(void *ptr)
|
||||
* \brief Reallocates an aligned block of memory.
|
||||
* \throws std::bad_alloc on allocation failure
|
||||
*/
|
||||
inline void* aligned_realloc(void *ptr, size_t new_size, size_t old_size)
|
||||
inline void* aligned_realloc(void *ptr, std::size_t new_size, std::size_t old_size)
|
||||
{
|
||||
EIGEN_UNUSED_VARIABLE(old_size);
|
||||
|
||||
@ -209,12 +209,12 @@ inline void* aligned_realloc(void *ptr, size_t new_size, size_t old_size)
|
||||
/** \internal Allocates \a size bytes. If Align is true, then the returned ptr is 16-byte-aligned.
|
||||
* On allocation error, the returned pointer is null, and a std::bad_alloc is thrown.
|
||||
*/
|
||||
template<bool Align> EIGEN_DEVICE_FUNC inline void* conditional_aligned_malloc(size_t size)
|
||||
template<bool Align> EIGEN_DEVICE_FUNC inline void* conditional_aligned_malloc(std::size_t size)
|
||||
{
|
||||
return aligned_malloc(size);
|
||||
}
|
||||
|
||||
template<> EIGEN_DEVICE_FUNC inline void* conditional_aligned_malloc<false>(size_t size)
|
||||
template<> EIGEN_DEVICE_FUNC inline void* conditional_aligned_malloc<false>(std::size_t size)
|
||||
{
|
||||
check_that_malloc_is_allowed();
|
||||
|
||||
@ -235,12 +235,12 @@ template<> EIGEN_DEVICE_FUNC inline void conditional_aligned_free<false>(void *p
|
||||
std::free(ptr);
|
||||
}
|
||||
|
||||
template<bool Align> inline void* conditional_aligned_realloc(void* ptr, size_t new_size, size_t old_size)
|
||||
template<bool Align> inline void* conditional_aligned_realloc(void* ptr, std::size_t new_size, std::size_t old_size)
|
||||
{
|
||||
return aligned_realloc(ptr, new_size, old_size);
|
||||
}
|
||||
|
||||
template<> inline void* conditional_aligned_realloc<false>(void* ptr, size_t new_size, size_t)
|
||||
template<> inline void* conditional_aligned_realloc<false>(void* ptr, std::size_t new_size, std::size_t)
|
||||
{
|
||||
return std::realloc(ptr, new_size);
|
||||
}
|
||||
@ -252,7 +252,7 @@ template<> inline void* conditional_aligned_realloc<false>(void* ptr, size_t new
|
||||
/** \internal Destructs the elements of an array.
|
||||
* The \a size parameters tells on how many objects to call the destructor of T.
|
||||
*/
|
||||
template<typename T> EIGEN_DEVICE_FUNC inline void destruct_elements_of_array(T *ptr, size_t size)
|
||||
template<typename T> EIGEN_DEVICE_FUNC inline void destruct_elements_of_array(T *ptr, std::size_t size)
|
||||
{
|
||||
// always destruct an array starting from the end.
|
||||
if(ptr)
|
||||
@ -262,9 +262,9 @@ template<typename T> EIGEN_DEVICE_FUNC inline void destruct_elements_of_array(T
|
||||
/** \internal Constructs the elements of an array.
|
||||
* The \a size parameter tells on how many objects to call the constructor of T.
|
||||
*/
|
||||
template<typename T> EIGEN_DEVICE_FUNC inline T* construct_elements_of_array(T *ptr, size_t size)
|
||||
template<typename T> EIGEN_DEVICE_FUNC inline T* construct_elements_of_array(T *ptr, std::size_t size)
|
||||
{
|
||||
size_t i;
|
||||
std::size_t i;
|
||||
EIGEN_TRY
|
||||
{
|
||||
for (i = 0; i < size; ++i) ::new (ptr + i) T;
|
||||
@ -283,9 +283,9 @@ template<typename T> EIGEN_DEVICE_FUNC inline T* construct_elements_of_array(T *
|
||||
*****************************************************************************/
|
||||
|
||||
template<typename T>
|
||||
EIGEN_DEVICE_FUNC EIGEN_ALWAYS_INLINE void check_size_for_overflow(size_t size)
|
||||
EIGEN_DEVICE_FUNC EIGEN_ALWAYS_INLINE void check_size_for_overflow(std::size_t size)
|
||||
{
|
||||
if(size > size_t(-1) / sizeof(T))
|
||||
if(size > std::size_t(-1) / sizeof(T))
|
||||
throw_std_bad_alloc();
|
||||
}
|
||||
|
||||
@ -293,7 +293,7 @@ EIGEN_DEVICE_FUNC EIGEN_ALWAYS_INLINE void check_size_for_overflow(size_t size)
|
||||
* On allocation error, the returned pointer is undefined, but a std::bad_alloc is thrown.
|
||||
* The default constructor of T is called.
|
||||
*/
|
||||
template<typename T> EIGEN_DEVICE_FUNC inline T* aligned_new(size_t size)
|
||||
template<typename T> EIGEN_DEVICE_FUNC inline T* aligned_new(std::size_t size)
|
||||
{
|
||||
check_size_for_overflow<T>(size);
|
||||
T *result = reinterpret_cast<T*>(aligned_malloc(sizeof(T)*size));
|
||||
@ -309,7 +309,7 @@ template<typename T> EIGEN_DEVICE_FUNC inline T* aligned_new(size_t size)
|
||||
return result;
|
||||
}
|
||||
|
||||
template<typename T, bool Align> EIGEN_DEVICE_FUNC inline T* conditional_aligned_new(size_t size)
|
||||
template<typename T, bool Align> EIGEN_DEVICE_FUNC inline T* conditional_aligned_new(std::size_t size)
|
||||
{
|
||||
check_size_for_overflow<T>(size);
|
||||
T *result = reinterpret_cast<T*>(conditional_aligned_malloc<Align>(sizeof(T)*size));
|
||||
@ -328,7 +328,7 @@ template<typename T, bool Align> EIGEN_DEVICE_FUNC inline T* conditional_aligned
|
||||
/** \internal Deletes objects constructed with aligned_new
|
||||
* The \a size parameters tells on how many objects to call the destructor of T.
|
||||
*/
|
||||
template<typename T> EIGEN_DEVICE_FUNC inline void aligned_delete(T *ptr, size_t size)
|
||||
template<typename T> EIGEN_DEVICE_FUNC inline void aligned_delete(T *ptr, std::size_t size)
|
||||
{
|
||||
destruct_elements_of_array<T>(ptr, size);
|
||||
aligned_free(ptr);
|
||||
@ -337,13 +337,13 @@ template<typename T> EIGEN_DEVICE_FUNC inline void aligned_delete(T *ptr, size_t
|
||||
/** \internal Deletes objects constructed with conditional_aligned_new
|
||||
* The \a size parameters tells on how many objects to call the destructor of T.
|
||||
*/
|
||||
template<typename T, bool Align> EIGEN_DEVICE_FUNC inline void conditional_aligned_delete(T *ptr, size_t size)
|
||||
template<typename T, bool Align> EIGEN_DEVICE_FUNC inline void conditional_aligned_delete(T *ptr, std::size_t size)
|
||||
{
|
||||
destruct_elements_of_array<T>(ptr, size);
|
||||
conditional_aligned_free<Align>(ptr);
|
||||
}
|
||||
|
||||
template<typename T, bool Align> EIGEN_DEVICE_FUNC inline T* conditional_aligned_realloc_new(T* pts, size_t new_size, size_t old_size)
|
||||
template<typename T, bool Align> EIGEN_DEVICE_FUNC inline T* conditional_aligned_realloc_new(T* pts, std::size_t new_size, std::size_t old_size)
|
||||
{
|
||||
check_size_for_overflow<T>(new_size);
|
||||
check_size_for_overflow<T>(old_size);
|
||||
@ -366,7 +366,7 @@ template<typename T, bool Align> EIGEN_DEVICE_FUNC inline T* conditional_aligned
|
||||
}
|
||||
|
||||
|
||||
template<typename T, bool Align> EIGEN_DEVICE_FUNC inline T* conditional_aligned_new_auto(size_t size)
|
||||
template<typename T, bool Align> EIGEN_DEVICE_FUNC inline T* conditional_aligned_new_auto(std::size_t size)
|
||||
{
|
||||
if(size==0)
|
||||
return 0; // short-cut. Also fixes Bug 884
|
||||
@ -387,7 +387,7 @@ template<typename T, bool Align> EIGEN_DEVICE_FUNC inline T* conditional_aligned
|
||||
return result;
|
||||
}
|
||||
|
||||
template<typename T, bool Align> inline T* conditional_aligned_realloc_new_auto(T* pts, size_t new_size, size_t old_size)
|
||||
template<typename T, bool Align> inline T* conditional_aligned_realloc_new_auto(T* pts, std::size_t new_size, std::size_t old_size)
|
||||
{
|
||||
check_size_for_overflow<T>(new_size);
|
||||
check_size_for_overflow<T>(old_size);
|
||||
@ -409,7 +409,7 @@ template<typename T, bool Align> inline T* conditional_aligned_realloc_new_auto(
|
||||
return result;
|
||||
}
|
||||
|
||||
template<typename T, bool Align> EIGEN_DEVICE_FUNC inline void conditional_aligned_delete_auto(T *ptr, size_t size)
|
||||
template<typename T, bool Align> EIGEN_DEVICE_FUNC inline void conditional_aligned_delete_auto(T *ptr, std::size_t size)
|
||||
{
|
||||
if(NumTraits<T>::RequireInitialization)
|
||||
destruct_elements_of_array<T>(ptr, size);
|
||||
@ -561,7 +561,7 @@ template<typename T> class aligned_stack_memory_handler : noncopyable
|
||||
* In this case, the buffer elements will also be destructed when this handler will be destructed.
|
||||
* Finally, if \a dealloc is true, then the pointer \a ptr is freed.
|
||||
**/
|
||||
aligned_stack_memory_handler(T* ptr, size_t size, bool dealloc)
|
||||
aligned_stack_memory_handler(T* ptr, std::size_t size, bool dealloc)
|
||||
: m_ptr(ptr), m_size(size), m_deallocate(dealloc)
|
||||
{
|
||||
if(NumTraits<T>::RequireInitialization && m_ptr)
|
||||
@ -576,7 +576,7 @@ template<typename T> class aligned_stack_memory_handler : noncopyable
|
||||
}
|
||||
protected:
|
||||
T* m_ptr;
|
||||
size_t m_size;
|
||||
std::size_t m_size;
|
||||
bool m_deallocate;
|
||||
};
|
||||
|
||||
@ -655,15 +655,15 @@ template<typename T> void swap(scoped_array<T> &a,scoped_array<T> &b)
|
||||
|
||||
#if EIGEN_MAX_ALIGN_BYTES!=0
|
||||
#define EIGEN_MAKE_ALIGNED_OPERATOR_NEW_NOTHROW(NeedsToAlign) \
|
||||
void* operator new(size_t size, const std::nothrow_t&) EIGEN_NO_THROW { \
|
||||
void* operator new(std::size_t size, const std::nothrow_t&) EIGEN_NO_THROW { \
|
||||
EIGEN_TRY { return Eigen::internal::conditional_aligned_malloc<NeedsToAlign>(size); } \
|
||||
EIGEN_CATCH (...) { return 0; } \
|
||||
}
|
||||
#define EIGEN_MAKE_ALIGNED_OPERATOR_NEW_IF(NeedsToAlign) \
|
||||
void *operator new(size_t size) { \
|
||||
void *operator new(std::size_t size) { \
|
||||
return Eigen::internal::conditional_aligned_malloc<NeedsToAlign>(size); \
|
||||
} \
|
||||
void *operator new[](size_t size) { \
|
||||
void *operator new[](std::size_t size) { \
|
||||
return Eigen::internal::conditional_aligned_malloc<NeedsToAlign>(size); \
|
||||
} \
|
||||
void operator delete(void * ptr) EIGEN_NO_THROW { Eigen::internal::conditional_aligned_free<NeedsToAlign>(ptr); } \
|
||||
@ -673,8 +673,8 @@ template<typename T> void swap(scoped_array<T> &a,scoped_array<T> &b)
|
||||
/* in-place new and delete. since (at least afaik) there is no actual */ \
|
||||
/* memory allocated we can safely let the default implementation handle */ \
|
||||
/* this particular case. */ \
|
||||
static void *operator new(size_t size, void *ptr) { return ::operator new(size,ptr); } \
|
||||
static void *operator new[](size_t size, void* ptr) { return ::operator new[](size,ptr); } \
|
||||
static void *operator new(std::size_t size, void *ptr) { return ::operator new(size,ptr); } \
|
||||
static void *operator new[](std::size_t size, void* ptr) { return ::operator new[](size,ptr); } \
|
||||
void operator delete(void * memory, void *ptr) EIGEN_NO_THROW { return ::operator delete(memory,ptr); } \
|
||||
void operator delete[](void * memory, void *ptr) EIGEN_NO_THROW { return ::operator delete[](memory,ptr); } \
|
||||
/* nothrow-new (returns zero instead of std::bad_alloc) */ \
|
||||
@ -713,7 +713,7 @@ template<class T>
|
||||
class aligned_allocator : public std::allocator<T>
|
||||
{
|
||||
public:
|
||||
typedef size_t size_type;
|
||||
typedef std::size_t size_type;
|
||||
typedef std::ptrdiff_t difference_type;
|
||||
typedef T* pointer;
|
||||
typedef const T* const_pointer;
|
||||
|
@ -278,6 +278,59 @@ protected:
|
||||
EIGEN_DEVICE_FUNC ~noncopyable() {}
|
||||
};
|
||||
|
||||
/** \internal
|
||||
* Provides access to the number of elements in the object of as a compile-time constant expression.
|
||||
* It "returns" Eigen::Dynamic if the size cannot be resolved at compile-time (default).
|
||||
*
|
||||
* Similar to std::tuple_size, but more general.
|
||||
*
|
||||
* It currently supports:
|
||||
* - any types T defining T::SizeAtCompileTime
|
||||
* - plain C arrays as T[N]
|
||||
* - std::array (c++11)
|
||||
* - some internal types such as SingleRange and AllRange
|
||||
*
|
||||
* The second template parameter eases SFINAE-based specializations.
|
||||
*/
|
||||
template<typename T, typename EnableIf = void> struct array_size {
|
||||
enum { value = Dynamic };
|
||||
};
|
||||
|
||||
template<typename T> struct array_size<T,typename internal::enable_if<((T::SizeAtCompileTime&0)==0)>::type> {
|
||||
enum { value = T::SizeAtCompileTime };
|
||||
};
|
||||
|
||||
template<typename T, int N> struct array_size<const T (&)[N]> {
|
||||
enum { value = N };
|
||||
};
|
||||
template<typename T, int N> struct array_size<T (&)[N]> {
|
||||
enum { value = N };
|
||||
};
|
||||
|
||||
#if EIGEN_HAS_CXX11
|
||||
template<typename T, std::size_t N> struct array_size<const std::array<T,N> > {
|
||||
enum { value = N };
|
||||
};
|
||||
template<typename T, std::size_t N> struct array_size<std::array<T,N> > {
|
||||
enum { value = N };
|
||||
};
|
||||
#endif
|
||||
|
||||
/** \internal
|
||||
* Analogue of the std::size free function.
|
||||
* It returns the size of the container or view \a x of type \c T
|
||||
*
|
||||
* It currently supports:
|
||||
* - any types T defining a member T::size() const
|
||||
* - plain C arrays as T[N]
|
||||
*
|
||||
*/
|
||||
template<typename T>
|
||||
Index size(const T& x) { return x.size(); }
|
||||
|
||||
template<typename T,std::size_t N>
|
||||
Index size(const T (&) [N]) { return N; }
|
||||
|
||||
/** \internal
|
||||
* Convenient struct to get the result type of a unary or binary functor.
|
||||
*
|
||||
|
300
Eigen/src/Core/util/SymbolicIndex.h
Normal file
300
Eigen/src/Core/util/SymbolicIndex.h
Normal file
@ -0,0 +1,300 @@
|
||||
// This file is part of Eigen, a lightweight C++ template library
|
||||
// for linear algebra.
|
||||
//
|
||||
// Copyright (C) 2017 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_SYMBOLIC_INDEX_H
|
||||
#define EIGEN_SYMBOLIC_INDEX_H
|
||||
|
||||
namespace Eigen {
|
||||
|
||||
/** \namespace Eigen::Symbolic
|
||||
* \ingroup Core_Module
|
||||
*
|
||||
* This namespace defines a set of classes and functions to build and evaluate symbolic expressions of scalar type Index.
|
||||
* Here is a simple example:
|
||||
*
|
||||
* \code
|
||||
* // First step, defines symbols:
|
||||
* struct x_tag {}; static const Symbolic::SymbolExpr<x_tag> x;
|
||||
* struct y_tag {}; static const Symbolic::SymbolExpr<y_tag> y;
|
||||
* struct z_tag {}; static const Symbolic::SymbolExpr<z_tag> z;
|
||||
*
|
||||
* // Defines an expression:
|
||||
* auto expr = (x+3)/y+z;
|
||||
*
|
||||
* // And evaluate it: (c++14)
|
||||
* std::cout << expr.eval(x=6,y=3,z=-13) << "\n";
|
||||
*
|
||||
* // In c++98/11, only one symbol per expression is supported for now:
|
||||
* auto expr98 = (3-x)/2;
|
||||
* std::cout << expr98.eval(x=6) << "\n";
|
||||
* \endcode
|
||||
*
|
||||
* It is currently only used internally to define and minipulate the placeholders::last and placeholders::end symbols in Eigen::seq and Eigen::seqN.
|
||||
*
|
||||
*/
|
||||
namespace Symbolic {
|
||||
|
||||
template<typename Tag> class Symbol;
|
||||
template<typename Arg0> class NegateExpr;
|
||||
template<typename Arg1,typename Arg2> class AddExpr;
|
||||
template<typename Arg1,typename Arg2> class ProductExpr;
|
||||
template<typename Arg1,typename Arg2> class QuotientExpr;
|
||||
|
||||
// A simple wrapper around an integral value to provide the eval method.
|
||||
// We could also use a free-function symbolic_eval...
|
||||
template<typename IndexType=Index>
|
||||
class ValueExpr {
|
||||
public:
|
||||
ValueExpr(IndexType val) : m_value(val) {}
|
||||
template<typename T>
|
||||
IndexType eval_impl(const T&) const { return m_value; }
|
||||
protected:
|
||||
IndexType m_value;
|
||||
};
|
||||
|
||||
// Specialization for compile-time value,
|
||||
// It is similar to ValueExpr(N) but this version helps the compiler to generate better code.
|
||||
template<int N>
|
||||
class ValueExpr<internal::FixedInt<N> > {
|
||||
public:
|
||||
ValueExpr() {}
|
||||
template<typename T>
|
||||
Index eval_impl(const T&) const { return N; }
|
||||
};
|
||||
|
||||
|
||||
/** \class BaseExpr
|
||||
* \ingroup Core_Module
|
||||
* Common base class of any symbolic expressions
|
||||
*/
|
||||
template<typename Derived>
|
||||
class BaseExpr
|
||||
{
|
||||
public:
|
||||
const Derived& derived() const { return *static_cast<const Derived*>(this); }
|
||||
|
||||
/** Evaluate the expression given the \a values of the symbols.
|
||||
*
|
||||
* \param values defines the values of the symbols, it can either be a SymbolValue or a std::tuple of SymbolValue
|
||||
* as constructed by SymbolExpr::operator= operator.
|
||||
*
|
||||
*/
|
||||
template<typename T>
|
||||
Index eval(const T& values) const { return derived().eval_impl(values); }
|
||||
|
||||
#if EIGEN_HAS_CXX14
|
||||
template<typename... Types>
|
||||
Index eval(Types&&... values) const { return derived().eval_impl(std::make_tuple(values...)); }
|
||||
#endif
|
||||
|
||||
NegateExpr<Derived> operator-() const { return NegateExpr<Derived>(derived()); }
|
||||
|
||||
AddExpr<Derived,ValueExpr<> > operator+(Index b) const
|
||||
{ return AddExpr<Derived,ValueExpr<> >(derived(), b); }
|
||||
AddExpr<Derived,ValueExpr<> > operator-(Index a) const
|
||||
{ return AddExpr<Derived,ValueExpr<> >(derived(), -a); }
|
||||
ProductExpr<Derived,ValueExpr<> > operator*(Index a) const
|
||||
{ return ProductExpr<Derived,ValueExpr<> >(derived(),a); }
|
||||
QuotientExpr<Derived,ValueExpr<> > operator/(Index a) const
|
||||
{ return QuotientExpr<Derived,ValueExpr<> >(derived(),a); }
|
||||
|
||||
friend AddExpr<Derived,ValueExpr<> > operator+(Index a, const BaseExpr& b)
|
||||
{ return AddExpr<Derived,ValueExpr<> >(b.derived(), a); }
|
||||
friend AddExpr<NegateExpr<Derived>,ValueExpr<> > operator-(Index a, const BaseExpr& b)
|
||||
{ return AddExpr<NegateExpr<Derived>,ValueExpr<> >(-b.derived(), a); }
|
||||
friend ProductExpr<ValueExpr<>,Derived> operator*(Index a, const BaseExpr& b)
|
||||
{ return ProductExpr<ValueExpr<>,Derived>(a,b.derived()); }
|
||||
friend QuotientExpr<ValueExpr<>,Derived> operator/(Index a, const BaseExpr& b)
|
||||
{ return QuotientExpr<ValueExpr<>,Derived>(a,b.derived()); }
|
||||
|
||||
template<int N>
|
||||
AddExpr<Derived,ValueExpr<internal::FixedInt<N> > > operator+(internal::FixedInt<N>) const
|
||||
{ return AddExpr<Derived,ValueExpr<internal::FixedInt<N> > >(derived(), ValueExpr<internal::FixedInt<N> >()); }
|
||||
template<int N>
|
||||
AddExpr<Derived,ValueExpr<internal::FixedInt<-N> > > operator-(internal::FixedInt<N>) const
|
||||
{ return AddExpr<Derived,ValueExpr<internal::FixedInt<-N> > >(derived(), ValueExpr<internal::FixedInt<-N> >()); }
|
||||
template<int N>
|
||||
ProductExpr<Derived,ValueExpr<internal::FixedInt<N> > > operator*(internal::FixedInt<N>) const
|
||||
{ return ProductExpr<Derived,ValueExpr<internal::FixedInt<N> > >(derived(),ValueExpr<internal::FixedInt<N> >()); }
|
||||
template<int N>
|
||||
QuotientExpr<Derived,ValueExpr<internal::FixedInt<N> > > operator/(internal::FixedInt<N>) const
|
||||
{ return QuotientExpr<Derived,ValueExpr<internal::FixedInt<N> > >(derived(),ValueExpr<internal::FixedInt<N> >()); }
|
||||
|
||||
template<int N>
|
||||
friend AddExpr<Derived,ValueExpr<internal::FixedInt<N> > > operator+(internal::FixedInt<N>, const BaseExpr& b)
|
||||
{ return AddExpr<Derived,ValueExpr<internal::FixedInt<N> > >(b.derived(), ValueExpr<internal::FixedInt<N> >()); }
|
||||
template<int N>
|
||||
friend AddExpr<NegateExpr<Derived>,ValueExpr<internal::FixedInt<N> > > operator-(internal::FixedInt<N>, const BaseExpr& b)
|
||||
{ return AddExpr<NegateExpr<Derived>,ValueExpr<internal::FixedInt<N> > >(-b.derived(), ValueExpr<internal::FixedInt<N> >()); }
|
||||
template<int N>
|
||||
friend ProductExpr<ValueExpr<internal::FixedInt<N> >,Derived> operator*(internal::FixedInt<N>, const BaseExpr& b)
|
||||
{ return ProductExpr<ValueExpr<internal::FixedInt<N> >,Derived>(ValueExpr<internal::FixedInt<N> >(),b.derived()); }
|
||||
template<int N>
|
||||
friend QuotientExpr<ValueExpr<internal::FixedInt<N> >,Derived> operator/(internal::FixedInt<N>, const BaseExpr& b)
|
||||
{ return QuotientExpr<ValueExpr<internal::FixedInt<N> > ,Derived>(ValueExpr<internal::FixedInt<N> >(),b.derived()); }
|
||||
|
||||
#if (!EIGEN_HAS_CXX14)
|
||||
template<int N>
|
||||
AddExpr<Derived,ValueExpr<internal::FixedInt<N> > > operator+(internal::FixedInt<N> (*)()) const
|
||||
{ return AddExpr<Derived,ValueExpr<internal::FixedInt<N> > >(derived(), ValueExpr<internal::FixedInt<N> >()); }
|
||||
template<int N>
|
||||
AddExpr<Derived,ValueExpr<internal::FixedInt<-N> > > operator-(internal::FixedInt<N> (*)()) const
|
||||
{ return AddExpr<Derived,ValueExpr<internal::FixedInt<-N> > >(derived(), ValueExpr<internal::FixedInt<-N> >()); }
|
||||
template<int N>
|
||||
ProductExpr<Derived,ValueExpr<internal::FixedInt<N> > > operator*(internal::FixedInt<N> (*)()) const
|
||||
{ return ProductExpr<Derived,ValueExpr<internal::FixedInt<N> > >(derived(),ValueExpr<internal::FixedInt<N> >()); }
|
||||
template<int N>
|
||||
QuotientExpr<Derived,ValueExpr<internal::FixedInt<N> > > operator/(internal::FixedInt<N> (*)()) const
|
||||
{ return QuotientExpr<Derived,ValueExpr<internal::FixedInt<N> > >(derived(),ValueExpr<internal::FixedInt<N> >()); }
|
||||
|
||||
template<int N>
|
||||
friend AddExpr<Derived,ValueExpr<internal::FixedInt<N> > > operator+(internal::FixedInt<N> (*)(), const BaseExpr& b)
|
||||
{ return AddExpr<Derived,ValueExpr<internal::FixedInt<N> > >(b.derived(), ValueExpr<internal::FixedInt<N> >()); }
|
||||
template<int N>
|
||||
friend AddExpr<NegateExpr<Derived>,ValueExpr<internal::FixedInt<N> > > operator-(internal::FixedInt<N> (*)(), const BaseExpr& b)
|
||||
{ return AddExpr<NegateExpr<Derived>,ValueExpr<internal::FixedInt<N> > >(-b.derived(), ValueExpr<internal::FixedInt<N> >()); }
|
||||
template<int N>
|
||||
friend ProductExpr<ValueExpr<internal::FixedInt<N> >,Derived> operator*(internal::FixedInt<N> (*)(), const BaseExpr& b)
|
||||
{ return ProductExpr<ValueExpr<internal::FixedInt<N> >,Derived>(ValueExpr<internal::FixedInt<N> >(),b.derived()); }
|
||||
template<int N>
|
||||
friend QuotientExpr<ValueExpr<internal::FixedInt<N> >,Derived> operator/(internal::FixedInt<N> (*)(), const BaseExpr& b)
|
||||
{ return QuotientExpr<ValueExpr<internal::FixedInt<N> > ,Derived>(ValueExpr<internal::FixedInt<N> >(),b.derived()); }
|
||||
#endif
|
||||
|
||||
|
||||
template<typename OtherDerived>
|
||||
AddExpr<Derived,OtherDerived> operator+(const BaseExpr<OtherDerived> &b) const
|
||||
{ return AddExpr<Derived,OtherDerived>(derived(), b.derived()); }
|
||||
|
||||
template<typename OtherDerived>
|
||||
AddExpr<Derived,NegateExpr<OtherDerived> > operator-(const BaseExpr<OtherDerived> &b) const
|
||||
{ return AddExpr<Derived,NegateExpr<OtherDerived> >(derived(), -b.derived()); }
|
||||
|
||||
template<typename OtherDerived>
|
||||
ProductExpr<Derived,OtherDerived> operator*(const BaseExpr<OtherDerived> &b) const
|
||||
{ return ProductExpr<Derived,OtherDerived>(derived(), b.derived()); }
|
||||
|
||||
template<typename OtherDerived>
|
||||
QuotientExpr<Derived,OtherDerived> operator/(const BaseExpr<OtherDerived> &b) const
|
||||
{ return QuotientExpr<Derived,OtherDerived>(derived(), b.derived()); }
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
struct is_symbolic {
|
||||
// BaseExpr has no conversion ctor, so we only have to check whether T can be staticaly cast to its base class BaseExpr<T>.
|
||||
enum { value = internal::is_convertible<T,BaseExpr<T> >::value };
|
||||
};
|
||||
|
||||
// Specialization for functions, because is_convertible fails in this case.
|
||||
// Useful in c++98/11 mode when testing is_symbolic<decltype(fix<N>)>
|
||||
template<typename T>
|
||||
struct is_symbolic<T (*)()> {
|
||||
enum { value = false };
|
||||
};
|
||||
|
||||
/** Represents the actual value of a symbol identified by its tag
|
||||
*
|
||||
* It is the return type of SymbolValue::operator=, and most of the time this is only way it is used.
|
||||
*/
|
||||
template<typename Tag>
|
||||
class SymbolValue
|
||||
{
|
||||
public:
|
||||
/** Default constructor from the value \a val */
|
||||
SymbolValue(Index val) : m_value(val) {}
|
||||
|
||||
/** \returns the stored value of the symbol */
|
||||
Index value() const { return m_value; }
|
||||
protected:
|
||||
Index m_value;
|
||||
};
|
||||
|
||||
/** Expression of a symbol uniquely identified by the template parameter type \c tag */
|
||||
template<typename tag>
|
||||
class SymbolExpr : public BaseExpr<SymbolExpr<tag> >
|
||||
{
|
||||
public:
|
||||
/** Alias to the template parameter \c tag */
|
||||
typedef tag Tag;
|
||||
|
||||
SymbolExpr() {}
|
||||
|
||||
/** Associate the value \a val to the given symbol \c *this, uniquely identified by its \c Tag.
|
||||
*
|
||||
* The returned object should be passed to ExprBase::eval() to evaluate a given expression with this specified runtime-time value.
|
||||
*/
|
||||
SymbolValue<Tag> operator=(Index val) const {
|
||||
return SymbolValue<Tag>(val);
|
||||
}
|
||||
|
||||
Index eval_impl(const SymbolValue<Tag> &values) const { return values.value(); }
|
||||
|
||||
#if EIGEN_HAS_CXX14
|
||||
// C++14 versions suitable for multiple symbols
|
||||
template<typename... Types>
|
||||
Index eval_impl(const std::tuple<Types...>& values) const { return std::get<SymbolValue<Tag> >(values).value(); }
|
||||
#endif
|
||||
};
|
||||
|
||||
template<typename Arg0>
|
||||
class NegateExpr : public BaseExpr<NegateExpr<Arg0> >
|
||||
{
|
||||
public:
|
||||
NegateExpr(const Arg0& arg0) : m_arg0(arg0) {}
|
||||
|
||||
template<typename T>
|
||||
Index eval_impl(const T& values) const { return -m_arg0.eval_impl(values); }
|
||||
protected:
|
||||
Arg0 m_arg0;
|
||||
};
|
||||
|
||||
template<typename Arg0, typename Arg1>
|
||||
class AddExpr : public BaseExpr<AddExpr<Arg0,Arg1> >
|
||||
{
|
||||
public:
|
||||
AddExpr(const Arg0& arg0, const Arg1& arg1) : m_arg0(arg0), m_arg1(arg1) {}
|
||||
|
||||
template<typename T>
|
||||
Index eval_impl(const T& values) const { return m_arg0.eval_impl(values) + m_arg1.eval_impl(values); }
|
||||
protected:
|
||||
Arg0 m_arg0;
|
||||
Arg1 m_arg1;
|
||||
};
|
||||
|
||||
template<typename Arg0, typename Arg1>
|
||||
class ProductExpr : public BaseExpr<ProductExpr<Arg0,Arg1> >
|
||||
{
|
||||
public:
|
||||
ProductExpr(const Arg0& arg0, const Arg1& arg1) : m_arg0(arg0), m_arg1(arg1) {}
|
||||
|
||||
template<typename T>
|
||||
Index eval_impl(const T& values) const { return m_arg0.eval_impl(values) * m_arg1.eval_impl(values); }
|
||||
protected:
|
||||
Arg0 m_arg0;
|
||||
Arg1 m_arg1;
|
||||
};
|
||||
|
||||
template<typename Arg0, typename Arg1>
|
||||
class QuotientExpr : public BaseExpr<QuotientExpr<Arg0,Arg1> >
|
||||
{
|
||||
public:
|
||||
QuotientExpr(const Arg0& arg0, const Arg1& arg1) : m_arg0(arg0), m_arg1(arg1) {}
|
||||
|
||||
template<typename T>
|
||||
Index eval_impl(const T& values) const { return m_arg0.eval_impl(values) / m_arg1.eval_impl(values); }
|
||||
protected:
|
||||
Arg0 m_arg0;
|
||||
Arg1 m_arg1;
|
||||
};
|
||||
|
||||
} // end namespace Symbolic
|
||||
|
||||
} // end namespace Eigen
|
||||
|
||||
#endif // EIGEN_SYMBOLIC_INDEX_H
|
@ -109,6 +109,7 @@ template<typename T, int Value> class variable_if_dynamic
|
||||
EIGEN_EMPTY_STRUCT_CTOR(variable_if_dynamic)
|
||||
EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE explicit variable_if_dynamic(T v) { EIGEN_ONLY_USED_FOR_DEBUG(v); eigen_assert(v == T(Value)); }
|
||||
EIGEN_DEVICE_FUNC static EIGEN_STRONG_INLINE T value() { return T(Value); }
|
||||
EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE operator T() const { return T(Value); }
|
||||
EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void setValue(T) {}
|
||||
};
|
||||
|
||||
@ -119,6 +120,7 @@ template<typename T> class variable_if_dynamic<T, Dynamic>
|
||||
public:
|
||||
EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE explicit variable_if_dynamic(T value) : m_value(value) {}
|
||||
EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE T value() const { return m_value; }
|
||||
EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE operator T() const { return m_value; }
|
||||
EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void setValue(T value) { m_value = value; }
|
||||
};
|
||||
|
||||
@ -532,6 +534,15 @@ template <typename B, typename Functor> struct cwise_promote_s
|
||||
template <typename Functor> struct cwise_promote_storage_type<Sparse,Dense,Functor> { typedef Sparse ret; };
|
||||
template <typename Functor> struct cwise_promote_storage_type<Dense,Sparse,Functor> { typedef Sparse ret; };
|
||||
|
||||
template <typename LhsKind, typename RhsKind, int LhsOrder, int RhsOrder> struct cwise_promote_storage_order {
|
||||
enum { value = LhsOrder };
|
||||
};
|
||||
|
||||
template <typename LhsKind, int LhsOrder, int RhsOrder> struct cwise_promote_storage_order<LhsKind,Sparse,LhsOrder,RhsOrder> { enum { value = RhsOrder }; };
|
||||
template <typename RhsKind, int LhsOrder, int RhsOrder> struct cwise_promote_storage_order<Sparse,RhsKind,LhsOrder,RhsOrder> { enum { value = LhsOrder }; };
|
||||
template <int Order> struct cwise_promote_storage_order<Sparse,Sparse,Order,Order> { enum { value = Order }; };
|
||||
|
||||
|
||||
/** \internal Specify the "storage kind" of multiplying an expression of kind A with kind B.
|
||||
* The template parameter ProductTag permits to specialize the resulting storage kind wrt to
|
||||
* some compile-time properties of the product: GemmProduct, GemvProduct, OuterProduct, InnerProduct.
|
||||
@ -629,7 +640,7 @@ struct plain_constant_type
|
||||
template<typename ExpressionType>
|
||||
struct is_lvalue
|
||||
{
|
||||
enum { value = !bool(is_const<ExpressionType>::value) &&
|
||||
enum { value = (!bool(is_const<ExpressionType>::value)) &&
|
||||
bool(traits<ExpressionType>::Flags & LvalueBit) };
|
||||
};
|
||||
|
||||
@ -662,7 +673,7 @@ bool is_same_dense(const T1 &, const T2 &, typename enable_if<!(has_direct_acces
|
||||
|
||||
// Internal helper defining the cost of a scalar division for the type T.
|
||||
// The default heuristic can be specialized for each scalar type and architecture.
|
||||
template<typename T,bool Vectorized=false,typename EnaleIf = void>
|
||||
template<typename T,bool Vectorized=false,typename EnableIf = void>
|
||||
struct scalar_div_cost {
|
||||
enum { value = 8*NumTraits<T>::MulCost };
|
||||
};
|
||||
|
@ -138,7 +138,7 @@ class CompleteOrthogonalDecomposition {
|
||||
* problem \f[\mathrm{minimize} \|A X - B\|, \f] where \b A is the matrix of
|
||||
* which \c *this is the complete orthogonal decomposition.
|
||||
*
|
||||
* \param B the right-hand sides of the problem to solve.
|
||||
* \param b the right-hand sides of the problem to solve.
|
||||
*
|
||||
* \returns a solution.
|
||||
*
|
||||
|
@ -143,10 +143,7 @@ struct Assignment<DstXprType, SrcXprType, Functor, Sparse2Dense>
|
||||
dst.setZero();
|
||||
|
||||
internal::evaluator<SrcXprType> srcEval(src);
|
||||
Index dstRows = src.rows();
|
||||
Index dstCols = src.cols();
|
||||
if((dst.rows()!=dstRows) || (dst.cols()!=dstCols))
|
||||
dst.resize(dstRows, dstCols);
|
||||
resize_if_allowed(dst, src, func);
|
||||
internal::evaluator<DstXprType> dstEval(dst);
|
||||
|
||||
const Index outerEvaluationSize = (internal::evaluator<SrcXprType>::Flags&RowMajorBit) ? src.rows() : src.cols();
|
||||
|
@ -185,6 +185,14 @@ class SparseCompressedBase<Derived>::InnerIterator
|
||||
}
|
||||
|
||||
inline InnerIterator& operator++() { m_id++; return *this; }
|
||||
inline InnerIterator& operator+=(Index i) { m_id += i ; return *this; }
|
||||
|
||||
inline InnerIterator operator+(Index i)
|
||||
{
|
||||
InnerIterator result = *this;
|
||||
result += i;
|
||||
return result;
|
||||
}
|
||||
|
||||
inline const Scalar& value() const { return m_values[m_id]; }
|
||||
inline Scalar& valueRef() { return const_cast<Scalar&>(m_values[m_id]); }
|
||||
@ -245,6 +253,14 @@ class SparseCompressedBase<Derived>::ReverseInnerIterator
|
||||
}
|
||||
|
||||
inline ReverseInnerIterator& operator--() { --m_id; return *this; }
|
||||
inline ReverseInnerIterator& operator-=(Index i) { m_id -= i; return *this; }
|
||||
|
||||
inline ReverseInnerIterator operator-(Index i)
|
||||
{
|
||||
ReverseInnerIterator result = *this;
|
||||
result -= i;
|
||||
return result;
|
||||
}
|
||||
|
||||
inline const Scalar& value() const { return m_values[m_id-1]; }
|
||||
inline Scalar& valueRef() { return const_cast<Scalar&>(m_values[m_id-1]); }
|
||||
@ -279,11 +295,11 @@ struct evaluator<SparseCompressedBase<Derived> >
|
||||
Flags = Derived::Flags
|
||||
};
|
||||
|
||||
evaluator() : m_matrix(0)
|
||||
evaluator() : m_matrix(0), m_zero(0)
|
||||
{
|
||||
EIGEN_INTERNAL_CHECK_COST_VALUE(CoeffReadCost);
|
||||
}
|
||||
explicit evaluator(const Derived &mat) : m_matrix(&mat)
|
||||
explicit evaluator(const Derived &mat) : m_matrix(&mat), m_zero(0)
|
||||
{
|
||||
EIGEN_INTERNAL_CHECK_COST_VALUE(CoeffReadCost);
|
||||
}
|
||||
@ -296,10 +312,26 @@ struct evaluator<SparseCompressedBase<Derived> >
|
||||
operator const Derived&() const { return *m_matrix; }
|
||||
|
||||
typedef typename DenseCoeffsBase<Derived,ReadOnlyAccessors>::CoeffReturnType CoeffReturnType;
|
||||
Scalar coeff(Index row, Index col) const
|
||||
{ return m_matrix->coeff(row,col); }
|
||||
const Scalar& coeff(Index row, Index col) const
|
||||
{
|
||||
Index p = find(row,col);
|
||||
|
||||
if(p==Dynamic)
|
||||
return m_zero;
|
||||
else
|
||||
return m_matrix->const_cast_derived().valuePtr()[p];
|
||||
}
|
||||
|
||||
Scalar& coeffRef(Index row, Index col)
|
||||
{
|
||||
Index p = find(row,col);
|
||||
eigen_assert(p!=Dynamic && "written coefficient does not exist");
|
||||
return m_matrix->const_cast_derived().valuePtr()[p];
|
||||
}
|
||||
|
||||
protected:
|
||||
|
||||
Index find(Index row, Index col) const
|
||||
{
|
||||
eigen_internal_assert(row>=0 && row<m_matrix->rows() && col>=0 && col<m_matrix->cols());
|
||||
|
||||
@ -308,14 +340,14 @@ struct evaluator<SparseCompressedBase<Derived> >
|
||||
|
||||
Index start = m_matrix->outerIndexPtr()[outer];
|
||||
Index end = m_matrix->isCompressed() ? m_matrix->outerIndexPtr()[outer+1] : m_matrix->outerIndexPtr()[outer] + m_matrix->innerNonZeroPtr()[outer];
|
||||
eigen_assert(end>start && "you are using a non finalized sparse matrix or written coefficient does not exist");
|
||||
const Index p = std::lower_bound(m_matrix->innerIndexPtr()+start, m_matrix->innerIndexPtr()+end,inner)
|
||||
- m_matrix->innerIndexPtr();
|
||||
eigen_assert((p<end) && (m_matrix->innerIndexPtr()[p]==inner) && "written coefficient does not exist");
|
||||
return m_matrix->const_cast_derived().valuePtr()[p];
|
||||
eigen_assert(end>=start && "you are using a non finalized sparse matrix or written coefficient does not exist");
|
||||
const Index p = std::lower_bound(m_matrix->innerIndexPtr()+start, m_matrix->innerIndexPtr()+end,inner) - m_matrix->innerIndexPtr();
|
||||
|
||||
return ((p<end) && (m_matrix->innerIndexPtr()[p]==inner)) ? p : Dynamic;
|
||||
}
|
||||
|
||||
const Derived *m_matrix;
|
||||
const Scalar m_zero;
|
||||
};
|
||||
|
||||
}
|
||||
|
@ -45,7 +45,7 @@ class CwiseBinaryOpImpl<BinaryOp, Lhs, Rhs, Sparse>
|
||||
EIGEN_STATIC_ASSERT((
|
||||
(!internal::is_same<typename internal::traits<Lhs>::StorageKind,
|
||||
typename internal::traits<Rhs>::StorageKind>::value)
|
||||
|| ((Lhs::Flags&RowMajorBit) == (Rhs::Flags&RowMajorBit))),
|
||||
|| ((internal::evaluator<Lhs>::Flags&RowMajorBit) == (internal::evaluator<Rhs>::Flags&RowMajorBit))),
|
||||
THE_STORAGE_ORDER_OF_BOTH_SIDES_MUST_MATCH);
|
||||
}
|
||||
};
|
||||
@ -110,6 +110,7 @@ public:
|
||||
EIGEN_STRONG_INLINE Scalar value() const { return m_value; }
|
||||
|
||||
EIGEN_STRONG_INLINE StorageIndex index() const { return m_id; }
|
||||
EIGEN_STRONG_INLINE Index outer() const { return m_lhsIter.outer(); }
|
||||
EIGEN_STRONG_INLINE Index row() const { return Lhs::IsRowMajor ? m_lhsIter.row() : index(); }
|
||||
EIGEN_STRONG_INLINE Index col() const { return Lhs::IsRowMajor ? index() : m_lhsIter.col(); }
|
||||
|
||||
@ -193,6 +194,7 @@ public:
|
||||
EIGEN_STRONG_INLINE Scalar value() const { eigen_internal_assert(m_id<m_innerSize); return m_value; }
|
||||
|
||||
EIGEN_STRONG_INLINE StorageIndex index() const { return m_id; }
|
||||
EIGEN_STRONG_INLINE Index outer() const { return m_rhsIter.outer(); }
|
||||
EIGEN_STRONG_INLINE Index row() const { return IsRowMajor ? m_rhsIter.outer() : m_id; }
|
||||
EIGEN_STRONG_INLINE Index col() const { return IsRowMajor ? m_id : m_rhsIter.outer(); }
|
||||
|
||||
@ -210,8 +212,7 @@ public:
|
||||
|
||||
enum {
|
||||
CoeffReadCost = evaluator<Lhs>::CoeffReadCost + evaluator<Rhs>::CoeffReadCost + functor_traits<BinaryOp>::Cost,
|
||||
// Expose storage order of the sparse expression
|
||||
Flags = (XprType::Flags & ~RowMajorBit) | (int(Rhs::Flags)&RowMajorBit)
|
||||
Flags = XprType::Flags
|
||||
};
|
||||
|
||||
explicit binary_evaluator(const XprType& xpr)
|
||||
@ -280,6 +281,7 @@ public:
|
||||
EIGEN_STRONG_INLINE Scalar value() const { eigen_internal_assert(m_id<m_innerSize); return m_value; }
|
||||
|
||||
EIGEN_STRONG_INLINE StorageIndex index() const { return m_id; }
|
||||
EIGEN_STRONG_INLINE Index outer() const { return m_lhsIter.outer(); }
|
||||
EIGEN_STRONG_INLINE Index row() const { return IsRowMajor ? m_lhsIter.outer() : m_id; }
|
||||
EIGEN_STRONG_INLINE Index col() const { return IsRowMajor ? m_id : m_lhsIter.outer(); }
|
||||
|
||||
@ -297,8 +299,7 @@ public:
|
||||
|
||||
enum {
|
||||
CoeffReadCost = evaluator<Lhs>::CoeffReadCost + evaluator<Rhs>::CoeffReadCost + functor_traits<BinaryOp>::Cost,
|
||||
// Expose storage order of the sparse expression
|
||||
Flags = (XprType::Flags & ~RowMajorBit) | (int(Lhs::Flags)&RowMajorBit)
|
||||
Flags = XprType::Flags
|
||||
};
|
||||
|
||||
explicit binary_evaluator(const XprType& xpr)
|
||||
@ -356,6 +357,16 @@ struct binary_evaluator<CwiseBinaryOp<scalar_product_op<T1,T2>, Lhs, Rhs>, Itera
|
||||
explicit binary_evaluator(const XprType& xpr) : Base(xpr) {}
|
||||
};
|
||||
|
||||
// "sparse ./ dense"
|
||||
template<typename T1, typename T2, typename Lhs, typename Rhs>
|
||||
struct binary_evaluator<CwiseBinaryOp<scalar_quotient_op<T1,T2>, Lhs, Rhs>, IteratorBased, IndexBased>
|
||||
: sparse_conjunction_evaluator<CwiseBinaryOp<scalar_quotient_op<T1,T2>, Lhs, Rhs> >
|
||||
{
|
||||
typedef CwiseBinaryOp<scalar_quotient_op<T1,T2>, Lhs, Rhs> XprType;
|
||||
typedef sparse_conjunction_evaluator<XprType> Base;
|
||||
explicit binary_evaluator(const XprType& xpr) : Base(xpr) {}
|
||||
};
|
||||
|
||||
// "sparse && sparse"
|
||||
template<typename Lhs, typename Rhs>
|
||||
struct binary_evaluator<CwiseBinaryOp<scalar_boolean_and_op, Lhs, Rhs>, IteratorBased, IteratorBased>
|
||||
@ -432,6 +443,7 @@ public:
|
||||
EIGEN_STRONG_INLINE Scalar value() const { return m_functor(m_lhsIter.value(), m_rhsIter.value()); }
|
||||
|
||||
EIGEN_STRONG_INLINE StorageIndex index() const { return m_lhsIter.index(); }
|
||||
EIGEN_STRONG_INLINE Index outer() const { return m_lhsIter.outer(); }
|
||||
EIGEN_STRONG_INLINE Index row() const { return m_lhsIter.row(); }
|
||||
EIGEN_STRONG_INLINE Index col() const { return m_lhsIter.col(); }
|
||||
|
||||
@ -503,6 +515,7 @@ public:
|
||||
{ return m_functor(m_lhsEval.coeff(IsRowMajor?m_outer:m_rhsIter.index(),IsRowMajor?m_rhsIter.index():m_outer), m_rhsIter.value()); }
|
||||
|
||||
EIGEN_STRONG_INLINE StorageIndex index() const { return m_rhsIter.index(); }
|
||||
EIGEN_STRONG_INLINE Index outer() const { return m_rhsIter.outer(); }
|
||||
EIGEN_STRONG_INLINE Index row() const { return m_rhsIter.row(); }
|
||||
EIGEN_STRONG_INLINE Index col() const { return m_rhsIter.col(); }
|
||||
|
||||
@ -518,8 +531,7 @@ public:
|
||||
|
||||
enum {
|
||||
CoeffReadCost = evaluator<LhsArg>::CoeffReadCost + evaluator<RhsArg>::CoeffReadCost + functor_traits<BinaryOp>::Cost,
|
||||
// Expose storage order of the sparse expression
|
||||
Flags = (XprType::Flags & ~RowMajorBit) | (int(RhsArg::Flags)&RowMajorBit)
|
||||
Flags = XprType::Flags
|
||||
};
|
||||
|
||||
explicit sparse_conjunction_evaluator(const XprType& xpr)
|
||||
@ -577,6 +589,7 @@ public:
|
||||
m_rhsEval.coeff(IsRowMajor?m_outer:m_lhsIter.index(),IsRowMajor?m_lhsIter.index():m_outer)); }
|
||||
|
||||
EIGEN_STRONG_INLINE StorageIndex index() const { return m_lhsIter.index(); }
|
||||
EIGEN_STRONG_INLINE Index outer() const { return m_lhsIter.outer(); }
|
||||
EIGEN_STRONG_INLINE Index row() const { return m_lhsIter.row(); }
|
||||
EIGEN_STRONG_INLINE Index col() const { return m_lhsIter.col(); }
|
||||
|
||||
@ -592,8 +605,7 @@ public:
|
||||
|
||||
enum {
|
||||
CoeffReadCost = evaluator<LhsArg>::CoeffReadCost + evaluator<RhsArg>::CoeffReadCost + functor_traits<BinaryOp>::Cost,
|
||||
// Expose storage order of the sparse expression
|
||||
Flags = (XprType::Flags & ~RowMajorBit) | (int(LhsArg::Flags)&RowMajorBit)
|
||||
Flags = XprType::Flags
|
||||
};
|
||||
|
||||
explicit sparse_conjunction_evaluator(const XprType& xpr)
|
||||
|
@ -81,6 +81,8 @@ public:
|
||||
: m_sparseXprImpl(sparseXpr), m_diagCoeffImpl(diagCoeff)
|
||||
{}
|
||||
|
||||
Index nonZerosEstimate() const { return m_sparseXprImpl.nonZerosEstimate(); }
|
||||
|
||||
protected:
|
||||
evaluator<SparseXprType> m_sparseXprImpl;
|
||||
evaluator<DiagonalCoeffType> m_diagCoeffImpl;
|
||||
@ -122,6 +124,8 @@ struct sparse_diagonal_product_evaluator<SparseXprType, DiagCoeffType, SDP_AsCwi
|
||||
: m_sparseXprEval(sparseXpr), m_diagCoeffNested(diagCoeff)
|
||||
{}
|
||||
|
||||
Index nonZerosEstimate() const { return m_sparseXprEval.nonZerosEstimate(); }
|
||||
|
||||
protected:
|
||||
evaluator<SparseXprType> m_sparseXprEval;
|
||||
DiagCoeffNested m_diagCoeffNested;
|
||||
|
@ -32,18 +32,22 @@ namespace Eigen {
|
||||
* \tparam _Scalar the scalar type, i.e. the type of the coefficients
|
||||
* \tparam _Options Union of bit flags controlling the storage scheme. Currently the only possibility
|
||||
* is ColMajor or RowMajor. The default is 0 which means column-major.
|
||||
* \tparam _Index the type of the indices. It has to be a \b signed type (e.g., short, int, std::ptrdiff_t). Default is \c int.
|
||||
* \tparam _StorageIndex the type of the indices. It has to be a \b signed type (e.g., short, int, std::ptrdiff_t). Default is \c int.
|
||||
*
|
||||
* \warning In %Eigen 3.2, the undocumented type \c SparseMatrix::Index was improperly defined as the storage index type (e.g., int),
|
||||
* whereas it is now (starting from %Eigen 3.3) deprecated and always defined as Eigen::Index.
|
||||
* Codes making use of \c SparseMatrix::Index, might thus likely have to be changed to use \c SparseMatrix::StorageIndex instead.
|
||||
*
|
||||
* This class can be extended with the help of the plugin mechanism described on the page
|
||||
* \ref TopicCustomizing_Plugins by defining the preprocessor symbol \c EIGEN_SPARSEMATRIX_PLUGIN.
|
||||
*/
|
||||
|
||||
namespace internal {
|
||||
template<typename _Scalar, int _Options, typename _Index>
|
||||
struct traits<SparseMatrix<_Scalar, _Options, _Index> >
|
||||
template<typename _Scalar, int _Options, typename _StorageIndex>
|
||||
struct traits<SparseMatrix<_Scalar, _Options, _StorageIndex> >
|
||||
{
|
||||
typedef _Scalar Scalar;
|
||||
typedef _Index StorageIndex;
|
||||
typedef _StorageIndex StorageIndex;
|
||||
typedef Sparse StorageKind;
|
||||
typedef MatrixXpr XprKind;
|
||||
enum {
|
||||
@ -56,16 +60,16 @@ struct traits<SparseMatrix<_Scalar, _Options, _Index> >
|
||||
};
|
||||
};
|
||||
|
||||
template<typename _Scalar, int _Options, typename _Index, int DiagIndex>
|
||||
struct traits<Diagonal<SparseMatrix<_Scalar, _Options, _Index>, DiagIndex> >
|
||||
template<typename _Scalar, int _Options, typename _StorageIndex, int DiagIndex>
|
||||
struct traits<Diagonal<SparseMatrix<_Scalar, _Options, _StorageIndex>, DiagIndex> >
|
||||
{
|
||||
typedef SparseMatrix<_Scalar, _Options, _Index> MatrixType;
|
||||
typedef SparseMatrix<_Scalar, _Options, _StorageIndex> MatrixType;
|
||||
typedef typename ref_selector<MatrixType>::type MatrixTypeNested;
|
||||
typedef typename remove_reference<MatrixTypeNested>::type _MatrixTypeNested;
|
||||
|
||||
typedef _Scalar Scalar;
|
||||
typedef Dense StorageKind;
|
||||
typedef _Index StorageIndex;
|
||||
typedef _StorageIndex StorageIndex;
|
||||
typedef MatrixXpr XprKind;
|
||||
|
||||
enum {
|
||||
@ -77,9 +81,9 @@ struct traits<Diagonal<SparseMatrix<_Scalar, _Options, _Index>, DiagIndex> >
|
||||
};
|
||||
};
|
||||
|
||||
template<typename _Scalar, int _Options, typename _Index, int DiagIndex>
|
||||
struct traits<Diagonal<const SparseMatrix<_Scalar, _Options, _Index>, DiagIndex> >
|
||||
: public traits<Diagonal<SparseMatrix<_Scalar, _Options, _Index>, DiagIndex> >
|
||||
template<typename _Scalar, int _Options, typename _StorageIndex, int DiagIndex>
|
||||
struct traits<Diagonal<const SparseMatrix<_Scalar, _Options, _StorageIndex>, DiagIndex> >
|
||||
: public traits<Diagonal<SparseMatrix<_Scalar, _Options, _StorageIndex>, DiagIndex> >
|
||||
{
|
||||
enum {
|
||||
Flags = 0
|
||||
@ -88,13 +92,13 @@ struct traits<Diagonal<const SparseMatrix<_Scalar, _Options, _Index>, DiagIndex>
|
||||
|
||||
} // end namespace internal
|
||||
|
||||
template<typename _Scalar, int _Options, typename _Index>
|
||||
template<typename _Scalar, int _Options, typename _StorageIndex>
|
||||
class SparseMatrix
|
||||
: public SparseCompressedBase<SparseMatrix<_Scalar, _Options, _Index> >
|
||||
: public SparseCompressedBase<SparseMatrix<_Scalar, _Options, _StorageIndex> >
|
||||
{
|
||||
typedef SparseCompressedBase<SparseMatrix> Base;
|
||||
using Base::convert_index;
|
||||
friend class SparseVector<_Scalar,0,_Index>;
|
||||
friend class SparseVector<_Scalar,0,_StorageIndex>;
|
||||
public:
|
||||
using Base::isCompressed;
|
||||
using Base::nonZeros;
|
||||
@ -984,11 +988,11 @@ void set_from_triplets(const InputIterator& begin, const InputIterator& end, Spa
|
||||
* an abstract iterator over a complex data-structure that would be expensive to evaluate. The triplets should rather
|
||||
* be explicitely stored into a std::vector for instance.
|
||||
*/
|
||||
template<typename Scalar, int _Options, typename _Index>
|
||||
template<typename Scalar, int _Options, typename _StorageIndex>
|
||||
template<typename InputIterators>
|
||||
void SparseMatrix<Scalar,_Options,_Index>::setFromTriplets(const InputIterators& begin, const InputIterators& end)
|
||||
void SparseMatrix<Scalar,_Options,_StorageIndex>::setFromTriplets(const InputIterators& begin, const InputIterators& end)
|
||||
{
|
||||
internal::set_from_triplets<InputIterators, SparseMatrix<Scalar,_Options,_Index> >(begin, end, *this, internal::scalar_sum_op<Scalar,Scalar>());
|
||||
internal::set_from_triplets<InputIterators, SparseMatrix<Scalar,_Options,_StorageIndex> >(begin, end, *this, internal::scalar_sum_op<Scalar,Scalar>());
|
||||
}
|
||||
|
||||
/** The same as setFromTriplets but when duplicates are met the functor \a dup_func is applied:
|
||||
@ -1000,17 +1004,17 @@ void SparseMatrix<Scalar,_Options,_Index>::setFromTriplets(const InputIterators&
|
||||
* mat.setFromTriplets(triplets.begin(), triplets.end(), [] (const Scalar&,const Scalar &b) { return b; });
|
||||
* \endcode
|
||||
*/
|
||||
template<typename Scalar, int _Options, typename _Index>
|
||||
template<typename Scalar, int _Options, typename _StorageIndex>
|
||||
template<typename InputIterators,typename DupFunctor>
|
||||
void SparseMatrix<Scalar,_Options,_Index>::setFromTriplets(const InputIterators& begin, const InputIterators& end, DupFunctor dup_func)
|
||||
void SparseMatrix<Scalar,_Options,_StorageIndex>::setFromTriplets(const InputIterators& begin, const InputIterators& end, DupFunctor dup_func)
|
||||
{
|
||||
internal::set_from_triplets<InputIterators, SparseMatrix<Scalar,_Options,_Index>, DupFunctor>(begin, end, *this, dup_func);
|
||||
internal::set_from_triplets<InputIterators, SparseMatrix<Scalar,_Options,_StorageIndex>, DupFunctor>(begin, end, *this, dup_func);
|
||||
}
|
||||
|
||||
/** \internal */
|
||||
template<typename Scalar, int _Options, typename _Index>
|
||||
template<typename Scalar, int _Options, typename _StorageIndex>
|
||||
template<typename DupFunctor>
|
||||
void SparseMatrix<Scalar,_Options,_Index>::collapseDuplicates(DupFunctor dup_func)
|
||||
void SparseMatrix<Scalar,_Options,_StorageIndex>::collapseDuplicates(DupFunctor dup_func)
|
||||
{
|
||||
eigen_assert(!isCompressed());
|
||||
// TODO, in practice we should be able to use m_innerNonZeros for that task
|
||||
@ -1048,9 +1052,9 @@ void SparseMatrix<Scalar,_Options,_Index>::collapseDuplicates(DupFunctor dup_fun
|
||||
m_data.resize(m_outerIndex[m_outerSize]);
|
||||
}
|
||||
|
||||
template<typename Scalar, int _Options, typename _Index>
|
||||
template<typename Scalar, int _Options, typename _StorageIndex>
|
||||
template<typename OtherDerived>
|
||||
EIGEN_DONT_INLINE SparseMatrix<Scalar,_Options,_Index>& SparseMatrix<Scalar,_Options,_Index>::operator=(const SparseMatrixBase<OtherDerived>& other)
|
||||
EIGEN_DONT_INLINE SparseMatrix<Scalar,_Options,_StorageIndex>& SparseMatrix<Scalar,_Options,_StorageIndex>::operator=(const SparseMatrixBase<OtherDerived>& other)
|
||||
{
|
||||
EIGEN_STATIC_ASSERT((internal::is_same<Scalar, typename OtherDerived::Scalar>::value),
|
||||
YOU_MIXED_DIFFERENT_NUMERIC_TYPES__YOU_NEED_TO_USE_THE_CAST_METHOD_OF_MATRIXBASE_TO_CAST_NUMERIC_TYPES_EXPLICITLY)
|
||||
@ -1121,8 +1125,8 @@ 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)
|
||||
template<typename _Scalar, int _Options, typename _StorageIndex>
|
||||
typename SparseMatrix<_Scalar,_Options,_StorageIndex>::Scalar& SparseMatrix<_Scalar,_Options,_StorageIndex>::insert(Index row, Index col)
|
||||
{
|
||||
eigen_assert(row>=0 && row<rows() && col>=0 && col<cols());
|
||||
|
||||
@ -1241,8 +1245,8 @@ typename SparseMatrix<_Scalar,_Options,_Index>::Scalar& SparseMatrix<_Scalar,_Op
|
||||
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)
|
||||
template<typename _Scalar, int _Options, typename _StorageIndex>
|
||||
EIGEN_DONT_INLINE typename SparseMatrix<_Scalar,_Options,_StorageIndex>::Scalar& SparseMatrix<_Scalar,_Options,_StorageIndex>::insertUncompressed(Index row, Index col)
|
||||
{
|
||||
eigen_assert(!isCompressed());
|
||||
|
||||
@ -1273,8 +1277,8 @@ EIGEN_DONT_INLINE typename SparseMatrix<_Scalar,_Options,_Index>::Scalar& Sparse
|
||||
return (m_data.value(p) = 0);
|
||||
}
|
||||
|
||||
template<typename _Scalar, int _Options, typename _Index>
|
||||
EIGEN_DONT_INLINE typename SparseMatrix<_Scalar,_Options,_Index>::Scalar& SparseMatrix<_Scalar,_Options,_Index>::insertCompressed(Index row, Index col)
|
||||
template<typename _Scalar, int _Options, typename _StorageIndex>
|
||||
EIGEN_DONT_INLINE typename SparseMatrix<_Scalar,_Options,_StorageIndex>::Scalar& SparseMatrix<_Scalar,_Options,_StorageIndex>::insertCompressed(Index row, Index col)
|
||||
{
|
||||
eigen_assert(isCompressed());
|
||||
|
||||
@ -1297,11 +1301,11 @@ EIGEN_DONT_INLINE typename SparseMatrix<_Scalar,_Options,_Index>::Scalar& Sparse
|
||||
// starts with: [ 0 0 0 0 0 1 ...] and we are inserted in, e.g.,
|
||||
// the 2nd inner vector...
|
||||
bool isLastVec = (!(previousOuter==-1 && m_data.size()!=0))
|
||||
&& (size_t(m_outerIndex[outer+1]) == m_data.size());
|
||||
&& (std::size_t(m_outerIndex[outer+1]) == m_data.size());
|
||||
|
||||
size_t startId = m_outerIndex[outer];
|
||||
// FIXME let's make sure sizeof(long int) == sizeof(size_t)
|
||||
size_t p = m_outerIndex[outer+1];
|
||||
std::size_t startId = m_outerIndex[outer];
|
||||
// FIXME let's make sure sizeof(long int) == sizeof(std::size_t)
|
||||
std::size_t p = m_outerIndex[outer+1];
|
||||
++m_outerIndex[outer+1];
|
||||
|
||||
double reallocRatio = 1;
|
||||
@ -1382,12 +1386,12 @@ EIGEN_DONT_INLINE typename SparseMatrix<_Scalar,_Options,_Index>::Scalar& Sparse
|
||||
|
||||
namespace internal {
|
||||
|
||||
template<typename _Scalar, int _Options, typename _Index>
|
||||
struct evaluator<SparseMatrix<_Scalar,_Options,_Index> >
|
||||
: evaluator<SparseCompressedBase<SparseMatrix<_Scalar,_Options,_Index> > >
|
||||
template<typename _Scalar, int _Options, typename _StorageIndex>
|
||||
struct evaluator<SparseMatrix<_Scalar,_Options,_StorageIndex> >
|
||||
: evaluator<SparseCompressedBase<SparseMatrix<_Scalar,_Options,_StorageIndex> > >
|
||||
{
|
||||
typedef evaluator<SparseCompressedBase<SparseMatrix<_Scalar,_Options,_Index> > > Base;
|
||||
typedef SparseMatrix<_Scalar,_Options,_Index> SparseMatrixType;
|
||||
typedef evaluator<SparseCompressedBase<SparseMatrix<_Scalar,_Options,_StorageIndex> > > Base;
|
||||
typedef SparseMatrix<_Scalar,_Options,_StorageIndex> SparseMatrixType;
|
||||
evaluator() : Base() {}
|
||||
explicit evaluator(const SparseMatrixType &mat) : Base(mat) {}
|
||||
};
|
||||
|
@ -37,7 +37,11 @@ template<typename Derived> class SparseMatrixBase
|
||||
|
||||
typedef typename internal::packet_traits<Scalar>::type PacketScalar;
|
||||
typedef typename internal::traits<Derived>::StorageKind StorageKind;
|
||||
|
||||
/** The integer type used to \b store indices within a SparseMatrix.
|
||||
* For a \c SparseMatrix<Scalar,Options,IndexType> it an alias of the third template parameter \c IndexType. */
|
||||
typedef typename internal::traits<Derived>::StorageIndex StorageIndex;
|
||||
|
||||
typedef typename internal::add_const_on_value_type_if_arithmetic<
|
||||
typename internal::packet_traits<Scalar>::type
|
||||
>::type PacketReturnType;
|
||||
@ -213,7 +217,7 @@ template<typename Derived> class SparseMatrixBase
|
||||
|
||||
if (Flags&RowMajorBit)
|
||||
{
|
||||
const Nested nm(m.derived());
|
||||
Nested nm(m.derived());
|
||||
internal::evaluator<NestedCleaned> thisEval(nm);
|
||||
for (Index row=0; row<nm.outerSize(); ++row)
|
||||
{
|
||||
@ -232,7 +236,7 @@ template<typename Derived> class SparseMatrixBase
|
||||
}
|
||||
else
|
||||
{
|
||||
const Nested nm(m.derived());
|
||||
Nested nm(m.derived());
|
||||
internal::evaluator<NestedCleaned> thisEval(nm);
|
||||
if (m.cols() == 1) {
|
||||
Index row = 0;
|
||||
|
@ -55,7 +55,10 @@ template<typename MatrixType, unsigned int Mode> class TriangularViewImpl<Matrix
|
||||
this->solveInPlace(dst);
|
||||
}
|
||||
|
||||
/** Applies the inverse of \c *this to the dense vector or matrix \a other, "in-place" */
|
||||
template<typename OtherDerived> void solveInPlace(MatrixBase<OtherDerived>& other) const;
|
||||
|
||||
/** Applies the inverse of \c *this to the sparse vector or matrix \a other, "in-place" */
|
||||
template<typename OtherDerived> void solveInPlace(SparseMatrixBase<OtherDerived>& other) const;
|
||||
|
||||
};
|
||||
|
@ -27,6 +27,20 @@ struct traits<SparseView<MatrixType> > : traits<MatrixType>
|
||||
|
||||
} // end namespace internal
|
||||
|
||||
/** \ingroup SparseCore_Module
|
||||
* \class SparseView
|
||||
*
|
||||
* \brief Expression of a dense or sparse matrix with zero or too small values removed
|
||||
*
|
||||
* \tparam MatrixType the type of the object of which we are removing the small entries
|
||||
*
|
||||
* This class represents an expression of a given dense or sparse matrix with
|
||||
* entries smaller than \c reference * \c epsilon are removed.
|
||||
* It is the return type of MatrixBase::sparseView() and SparseMatrixBase::pruned()
|
||||
* and most of the time this is the only way it is used.
|
||||
*
|
||||
* \sa MatrixBase::sparseView(), SparseMatrixBase::pruned()
|
||||
*/
|
||||
template<typename MatrixType>
|
||||
class SparseView : public SparseMatrixBase<SparseView<MatrixType> >
|
||||
{
|
||||
@ -190,6 +204,23 @@ struct unary_evaluator<SparseView<ArgType>, IndexBased>
|
||||
|
||||
} // end namespace internal
|
||||
|
||||
/** \ingroup SparseCore_Module
|
||||
*
|
||||
* \returns a sparse expression of the dense expression \c *this with values smaller than
|
||||
* \a reference * \a epsilon removed.
|
||||
*
|
||||
* This method is typically used when prototyping to convert a quickly assembled dense Matrix \c D to a SparseMatrix \c S:
|
||||
* \code
|
||||
* MatrixXd D(n,m);
|
||||
* SparseMatrix<double> S;
|
||||
* S = D.sparseView(); // suppress numerical zeros (exact)
|
||||
* S = D.sparseView(reference);
|
||||
* S = D.sparseView(reference,epsilon);
|
||||
* \endcode
|
||||
* where \a reference is a meaningful non zero reference value,
|
||||
* and \a epsilon is a tolerance factor defaulting to NumTraits<Scalar>::dummy_precision().
|
||||
*
|
||||
* \sa SparseMatrixBase::pruned(), class SparseView */
|
||||
template<typename Derived>
|
||||
const SparseView<Derived> MatrixBase<Derived>::sparseView(const Scalar& reference,
|
||||
const typename NumTraits<Scalar>::Real& epsilon) const
|
||||
@ -198,7 +229,7 @@ const SparseView<Derived> MatrixBase<Derived>::sparseView(const Scalar& referenc
|
||||
}
|
||||
|
||||
/** \returns an expression of \c *this with values smaller than
|
||||
* \a reference * \a epsilon are removed.
|
||||
* \a reference * \a epsilon removed.
|
||||
*
|
||||
* This method is typically used in conjunction with the product of two sparse matrices
|
||||
* to automatically prune the smallest values as follows:
|
||||
|
@ -171,6 +171,8 @@ struct sparse_solve_triangular_selector<Lhs,Rhs,Mode,Upper,ColMajor>
|
||||
|
||||
} // end namespace internal
|
||||
|
||||
#ifndef EIGEN_PARSED_BY_DOXYGEN
|
||||
|
||||
template<typename ExpressionType,unsigned int Mode>
|
||||
template<typename OtherDerived>
|
||||
void TriangularViewImpl<ExpressionType,Mode,Sparse>::solveInPlace(MatrixBase<OtherDerived>& other) const
|
||||
@ -189,6 +191,7 @@ void TriangularViewImpl<ExpressionType,Mode,Sparse>::solveInPlace(MatrixBase<Oth
|
||||
if (copy)
|
||||
other = otherCopy;
|
||||
}
|
||||
#endif
|
||||
|
||||
// pure sparse path
|
||||
|
||||
@ -286,6 +289,7 @@ struct sparse_solve_triangular_sparse_selector<Lhs,Rhs,Mode,UpLo,ColMajor>
|
||||
|
||||
} // end namespace internal
|
||||
|
||||
#ifndef EIGEN_PARSED_BY_DOXYGEN
|
||||
template<typename ExpressionType,unsigned int Mode>
|
||||
template<typename OtherDerived>
|
||||
void TriangularViewImpl<ExpressionType,Mode,Sparse>::solveInPlace(SparseMatrixBase<OtherDerived>& other) const
|
||||
@ -304,6 +308,7 @@ void TriangularViewImpl<ExpressionType,Mode,Sparse>::solveInPlace(SparseMatrixBa
|
||||
// if (copy)
|
||||
// other = otherCopy;
|
||||
}
|
||||
#endif
|
||||
|
||||
} // end namespace Eigen
|
||||
|
||||
|
@ -22,8 +22,8 @@ namespace Eigen {
|
||||
class aligned_allocator_indirection : public EIGEN_ALIGNED_ALLOCATOR<T>
|
||||
{
|
||||
public:
|
||||
typedef size_t size_type;
|
||||
typedef ptrdiff_t difference_type;
|
||||
typedef std::size_t size_type;
|
||||
typedef std::ptrdiff_t difference_type;
|
||||
typedef T* pointer;
|
||||
typedef const T* const_pointer;
|
||||
typedef T& reference;
|
||||
|
@ -967,6 +967,7 @@ void SuperILU<MatrixType>::factorize(const MatrixType& a)
|
||||
m_factorizationIsOk = true;
|
||||
}
|
||||
|
||||
#ifndef EIGEN_PARSED_BY_DOXYGEN
|
||||
template<typename MatrixType>
|
||||
template<typename Rhs,typename Dest>
|
||||
void SuperILU<MatrixType>::_solve_impl(const MatrixBase<Rhs> &b, MatrixBase<Dest>& x) const
|
||||
@ -1019,6 +1020,8 @@ void SuperILU<MatrixType>::_solve_impl(const MatrixBase<Rhs> &b, MatrixBase<Dest
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
} // end namespace Eigen
|
||||
|
||||
#endif // EIGEN_SUPERLUSUPPORT_H
|
||||
|
@ -23,6 +23,24 @@ inline void umfpack_defaults(double control[UMFPACK_CONTROL], double)
|
||||
inline void umfpack_defaults(double control[UMFPACK_CONTROL], std::complex<double>)
|
||||
{ umfpack_zi_defaults(control); }
|
||||
|
||||
inline void umfpack_report_info(double control[UMFPACK_CONTROL], double info[UMFPACK_INFO], double)
|
||||
{ umfpack_di_report_info(control, info);}
|
||||
|
||||
inline void umfpack_report_info(double control[UMFPACK_CONTROL], double info[UMFPACK_INFO], std::complex<double>)
|
||||
{ umfpack_zi_report_info(control, info);}
|
||||
|
||||
inline void umfpack_report_status(double control[UMFPACK_CONTROL], int status, double)
|
||||
{ umfpack_di_report_status(control, status);}
|
||||
|
||||
inline void umfpack_report_status(double control[UMFPACK_CONTROL], int status, std::complex<double>)
|
||||
{ umfpack_zi_report_status(control, status);}
|
||||
|
||||
inline void umfpack_report_control(double control[UMFPACK_CONTROL], double)
|
||||
{ umfpack_di_report_control(control);}
|
||||
|
||||
inline void umfpack_report_control(double control[UMFPACK_CONTROL], std::complex<double>)
|
||||
{ umfpack_zi_report_control(control);}
|
||||
|
||||
inline void umfpack_free_numeric(void **Numeric, double)
|
||||
{ umfpack_di_free_numeric(Numeric); *Numeric = 0; }
|
||||
|
||||
@ -156,6 +174,7 @@ class UmfPackLU : public SparseSolverBase<UmfPackLU<_MatrixType> >
|
||||
public:
|
||||
|
||||
typedef Array<double, UMFPACK_CONTROL, 1> UmfpackControl;
|
||||
typedef Array<double, UMFPACK_INFO, 1> UmfpackInfo;
|
||||
|
||||
UmfPackLU()
|
||||
: m_dummy(0,0), mp_matrix(m_dummy)
|
||||
@ -297,6 +316,34 @@ class UmfPackLU : public SparseSolverBase<UmfPackLU<_MatrixType> >
|
||||
factorize_impl();
|
||||
}
|
||||
|
||||
/** Prints the current UmfPack control settings.
|
||||
*
|
||||
* \sa umfpackControl()
|
||||
*/
|
||||
void printUmfpackControl()
|
||||
{
|
||||
umfpack_report_control(m_control.data(), Scalar());
|
||||
}
|
||||
|
||||
/** Prints statistics collected by UmfPack.
|
||||
*
|
||||
* \sa analyzePattern(), compute()
|
||||
*/
|
||||
void printUmfpackInfo()
|
||||
{
|
||||
eigen_assert(m_analysisIsOk && "UmfPackLU: you must first call analyzePattern()");
|
||||
umfpack_report_info(m_control.data(), m_umfpackInfo.data(), Scalar());
|
||||
}
|
||||
|
||||
/** Prints the status of the previous factorization operation performed by UmfPack (symbolic or numerical factorization).
|
||||
*
|
||||
* \sa analyzePattern(), compute()
|
||||
*/
|
||||
void printUmfpackStatus() {
|
||||
eigen_assert(m_analysisIsOk && "UmfPackLU: you must first call analyzePattern()");
|
||||
umfpack_report_status(m_control.data(), m_fact_errorCode, Scalar());
|
||||
}
|
||||
|
||||
/** \internal */
|
||||
template<typename BDerived,typename XDerived>
|
||||
bool _solve_impl(const MatrixBase<BDerived> &b, MatrixBase<XDerived> &x) const;
|
||||
@ -314,19 +361,19 @@ class UmfPackLU : public SparseSolverBase<UmfPackLU<_MatrixType> >
|
||||
m_numeric = 0;
|
||||
m_symbolic = 0;
|
||||
m_extractedDataAreDirty = true;
|
||||
|
||||
umfpack_defaults(m_control.data(), Scalar());
|
||||
}
|
||||
|
||||
void analyzePattern_impl()
|
||||
{
|
||||
umfpack_defaults(m_control.data(), Scalar());
|
||||
int errorCode = 0;
|
||||
errorCode = umfpack_symbolic(internal::convert_index<int>(mp_matrix.rows()),
|
||||
m_fact_errorCode = umfpack_symbolic(internal::convert_index<int>(mp_matrix.rows()),
|
||||
internal::convert_index<int>(mp_matrix.cols()),
|
||||
mp_matrix.outerIndexPtr(), mp_matrix.innerIndexPtr(), mp_matrix.valuePtr(),
|
||||
&m_symbolic, m_control.data(), 0);
|
||||
&m_symbolic, m_control.data(), m_umfpackInfo.data());
|
||||
|
||||
m_isInitialized = true;
|
||||
m_info = errorCode ? InvalidInput : Success;
|
||||
m_info = m_fact_errorCode ? InvalidInput : Success;
|
||||
m_analysisIsOk = true;
|
||||
m_factorizationIsOk = false;
|
||||
m_extractedDataAreDirty = true;
|
||||
@ -334,8 +381,9 @@ class UmfPackLU : public SparseSolverBase<UmfPackLU<_MatrixType> >
|
||||
|
||||
void factorize_impl()
|
||||
{
|
||||
|
||||
m_fact_errorCode = umfpack_numeric(mp_matrix.outerIndexPtr(), mp_matrix.innerIndexPtr(), mp_matrix.valuePtr(),
|
||||
m_symbolic, &m_numeric, m_control.data(), 0);
|
||||
m_symbolic, &m_numeric, m_control.data(), m_umfpackInfo.data());
|
||||
|
||||
m_info = m_fact_errorCode == UMFPACK_OK ? Success : NumericalIssue;
|
||||
m_factorizationIsOk = true;
|
||||
@ -362,6 +410,7 @@ class UmfPackLU : public SparseSolverBase<UmfPackLU<_MatrixType> >
|
||||
mutable LUMatrixType m_l;
|
||||
int m_fact_errorCode;
|
||||
UmfpackControl m_control;
|
||||
mutable UmfpackInfo m_umfpackInfo;
|
||||
|
||||
mutable LUMatrixType m_u;
|
||||
mutable IntColVectorType m_p;
|
||||
@ -442,7 +491,7 @@ bool UmfPackLU<MatrixType>::_solve_impl(const MatrixBase<BDerived> &b, MatrixBas
|
||||
x_ptr = &x.col(j).coeffRef(0);
|
||||
errorCode = umfpack_solve(UMFPACK_A,
|
||||
mp_matrix.outerIndexPtr(), mp_matrix.innerIndexPtr(), mp_matrix.valuePtr(),
|
||||
x_ptr, &b.const_cast_derived().col(j).coeffRef(0), m_numeric, m_control.data(), 0);
|
||||
x_ptr, &b.const_cast_derived().col(j).coeffRef(0), m_numeric, m_control.data(), m_umfpackInfo.data());
|
||||
if(x.innerStride()!=1)
|
||||
x.col(j) = x_tmp;
|
||||
if (errorCode!=0)
|
||||
|
File diff suppressed because it is too large
Load Diff
260
Eigen/src/plugins/IndexedViewMethods.h
Normal file
260
Eigen/src/plugins/IndexedViewMethods.h
Normal file
@ -0,0 +1,260 @@
|
||||
// This file is part of Eigen, a lightweight C++ template library
|
||||
// for linear algebra.
|
||||
//
|
||||
// Copyright (C) 2017 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_PARSED_BY_DOXYGEN
|
||||
|
||||
// This file is automatically included twice to generate const and non-const versions
|
||||
|
||||
#ifndef EIGEN_INDEXED_VIEW_METHOD_2ND_PASS
|
||||
#define EIGEN_INDEXED_VIEW_METHOD_CONST const
|
||||
#define EIGEN_INDEXED_VIEW_METHOD_TYPE ConstIndexedViewType
|
||||
#else
|
||||
#define EIGEN_INDEXED_VIEW_METHOD_CONST
|
||||
#define EIGEN_INDEXED_VIEW_METHOD_TYPE IndexedViewType
|
||||
#endif
|
||||
|
||||
#ifndef EIGEN_INDEXED_VIEW_METHOD_2ND_PASS
|
||||
protected:
|
||||
|
||||
// define some aliases to ease readability
|
||||
|
||||
template<typename Indices>
|
||||
struct IvcRowType : public internal::IndexedViewCompatibleType<Indices,RowsAtCompileTime> {};
|
||||
|
||||
template<typename Indices>
|
||||
struct IvcColType : public internal::IndexedViewCompatibleType<Indices,ColsAtCompileTime> {};
|
||||
|
||||
template<typename Indices>
|
||||
struct IvcType : public internal::IndexedViewCompatibleType<Indices,SizeAtCompileTime> {};
|
||||
|
||||
typedef typename internal::IndexedViewCompatibleType<Index,1>::type IvcIndex;
|
||||
|
||||
template<typename Indices>
|
||||
typename IvcRowType<Indices>::type
|
||||
ivcRow(const Indices& indices) const {
|
||||
return internal::makeIndexedViewCompatible(indices, internal::variable_if_dynamic<Index,RowsAtCompileTime>(derived().rows()),Specialized);
|
||||
}
|
||||
|
||||
template<typename Indices>
|
||||
typename IvcColType<Indices>::type
|
||||
ivcCol(const Indices& indices) const {
|
||||
return internal::makeIndexedViewCompatible(indices, internal::variable_if_dynamic<Index,ColsAtCompileTime>(derived().cols()),Specialized);
|
||||
}
|
||||
|
||||
template<typename Indices>
|
||||
typename IvcColType<Indices>::type
|
||||
ivcSize(const Indices& indices) const {
|
||||
return internal::makeIndexedViewCompatible(indices, internal::variable_if_dynamic<Index,SizeAtCompileTime>(derived().size()),Specialized);
|
||||
}
|
||||
|
||||
template<typename RowIndices, typename ColIndices>
|
||||
struct valid_indexed_view_overload {
|
||||
// Here we use is_convertible to Index instead of is_integral in order to treat enums as Index.
|
||||
// In c++11 we could use is_integral<T> && is_enum<T> if is_convertible appears to be too permissive.
|
||||
enum { value = !(internal::is_convertible<RowIndices,Index>::value && internal::is_convertible<ColIndices,Index>::value) };
|
||||
};
|
||||
|
||||
public:
|
||||
|
||||
#endif
|
||||
|
||||
template<typename RowIndices, typename ColIndices>
|
||||
struct EIGEN_INDEXED_VIEW_METHOD_TYPE {
|
||||
typedef IndexedView<EIGEN_INDEXED_VIEW_METHOD_CONST Derived,
|
||||
typename IvcRowType<RowIndices>::type,
|
||||
typename IvcColType<ColIndices>::type> type;
|
||||
};
|
||||
|
||||
// This is the generic version
|
||||
|
||||
template<typename RowIndices, typename ColIndices>
|
||||
typename internal::enable_if<valid_indexed_view_overload<RowIndices,ColIndices>::value
|
||||
&& internal::traits<typename EIGEN_INDEXED_VIEW_METHOD_TYPE<RowIndices,ColIndices>::type>::ReturnAsIndexedView,
|
||||
typename EIGEN_INDEXED_VIEW_METHOD_TYPE<RowIndices,ColIndices>::type >::type
|
||||
operator()(const RowIndices& rowIndices, const ColIndices& colIndices) EIGEN_INDEXED_VIEW_METHOD_CONST
|
||||
{
|
||||
return typename EIGEN_INDEXED_VIEW_METHOD_TYPE<RowIndices,ColIndices>::type
|
||||
(derived(), ivcRow(rowIndices), ivcCol(colIndices));
|
||||
}
|
||||
|
||||
// The following overload returns a Block<> object
|
||||
|
||||
template<typename RowIndices, typename ColIndices>
|
||||
typename internal::enable_if<valid_indexed_view_overload<RowIndices,ColIndices>::value
|
||||
&& internal::traits<typename EIGEN_INDEXED_VIEW_METHOD_TYPE<RowIndices,ColIndices>::type>::ReturnAsBlock,
|
||||
typename internal::traits<typename EIGEN_INDEXED_VIEW_METHOD_TYPE<RowIndices,ColIndices>::type>::BlockType>::type
|
||||
operator()(const RowIndices& rowIndices, const ColIndices& colIndices) EIGEN_INDEXED_VIEW_METHOD_CONST
|
||||
{
|
||||
typedef typename internal::traits<typename EIGEN_INDEXED_VIEW_METHOD_TYPE<RowIndices,ColIndices>::type>::BlockType BlockType;
|
||||
typename IvcRowType<RowIndices>::type actualRowIndices = ivcRow(rowIndices);
|
||||
typename IvcColType<ColIndices>::type actualColIndices = ivcCol(colIndices);
|
||||
return BlockType(derived(),
|
||||
internal::first(actualRowIndices),
|
||||
internal::first(actualColIndices),
|
||||
internal::size(actualRowIndices),
|
||||
internal::size(actualColIndices));
|
||||
}
|
||||
|
||||
// The following overload returns a Scalar
|
||||
|
||||
template<typename RowIndices, typename ColIndices>
|
||||
typename internal::enable_if<valid_indexed_view_overload<RowIndices,ColIndices>::value
|
||||
&& internal::traits<typename EIGEN_INDEXED_VIEW_METHOD_TYPE<RowIndices,ColIndices>::type>::ReturnAsScalar,
|
||||
CoeffReturnType >::type
|
||||
operator()(const RowIndices& rowIndices, const ColIndices& colIndices) EIGEN_INDEXED_VIEW_METHOD_CONST
|
||||
{
|
||||
return Base::operator()(internal::eval_expr_given_size(rowIndices,rows()),internal::eval_expr_given_size(colIndices,cols()));
|
||||
}
|
||||
|
||||
// The folowing three overloads are needed to handle raw Index[N] arrays.
|
||||
|
||||
template<typename RowIndicesT, std::size_t RowIndicesN, typename ColIndices>
|
||||
IndexedView<EIGEN_INDEXED_VIEW_METHOD_CONST Derived,const RowIndicesT (&)[RowIndicesN],typename IvcColType<ColIndices>::type>
|
||||
operator()(const RowIndicesT (&rowIndices)[RowIndicesN], const ColIndices& colIndices) EIGEN_INDEXED_VIEW_METHOD_CONST
|
||||
{
|
||||
return IndexedView<EIGEN_INDEXED_VIEW_METHOD_CONST Derived,const RowIndicesT (&)[RowIndicesN],typename IvcColType<ColIndices>::type>
|
||||
(derived(), rowIndices, ivcCol(colIndices));
|
||||
}
|
||||
|
||||
template<typename RowIndices, typename ColIndicesT, std::size_t ColIndicesN>
|
||||
IndexedView<EIGEN_INDEXED_VIEW_METHOD_CONST Derived,typename IvcRowType<RowIndices>::type, const ColIndicesT (&)[ColIndicesN]>
|
||||
operator()(const RowIndices& rowIndices, const ColIndicesT (&colIndices)[ColIndicesN]) EIGEN_INDEXED_VIEW_METHOD_CONST
|
||||
{
|
||||
return IndexedView<EIGEN_INDEXED_VIEW_METHOD_CONST Derived,typename IvcRowType<RowIndices>::type,const ColIndicesT (&)[ColIndicesN]>
|
||||
(derived(), ivcRow(rowIndices), colIndices);
|
||||
}
|
||||
|
||||
template<typename RowIndicesT, std::size_t RowIndicesN, typename ColIndicesT, std::size_t ColIndicesN>
|
||||
IndexedView<EIGEN_INDEXED_VIEW_METHOD_CONST Derived,const RowIndicesT (&)[RowIndicesN], const ColIndicesT (&)[ColIndicesN]>
|
||||
operator()(const RowIndicesT (&rowIndices)[RowIndicesN], const ColIndicesT (&colIndices)[ColIndicesN]) EIGEN_INDEXED_VIEW_METHOD_CONST
|
||||
{
|
||||
return IndexedView<EIGEN_INDEXED_VIEW_METHOD_CONST Derived,const RowIndicesT (&)[RowIndicesN],const ColIndicesT (&)[ColIndicesN]>
|
||||
(derived(), rowIndices, colIndices);
|
||||
}
|
||||
|
||||
// Overloads for 1D vectors/arrays
|
||||
|
||||
template<typename Indices>
|
||||
typename internal::enable_if<
|
||||
IsRowMajor && (!(internal::get_compile_time_incr<typename IvcType<Indices>::type>::value==1 || internal::is_integral<Indices>::value)),
|
||||
IndexedView<EIGEN_INDEXED_VIEW_METHOD_CONST Derived,IvcIndex,typename IvcType<Indices>::type> >::type
|
||||
operator()(const Indices& indices) EIGEN_INDEXED_VIEW_METHOD_CONST
|
||||
{
|
||||
EIGEN_STATIC_ASSERT_VECTOR_ONLY(Derived)
|
||||
return IndexedView<EIGEN_INDEXED_VIEW_METHOD_CONST Derived,IvcIndex,typename IvcType<Indices>::type>
|
||||
(derived(), IvcIndex(0), ivcCol(indices));
|
||||
}
|
||||
|
||||
template<typename Indices>
|
||||
typename internal::enable_if<
|
||||
(!IsRowMajor) && (!(internal::get_compile_time_incr<typename IvcType<Indices>::type>::value==1 || internal::is_integral<Indices>::value)),
|
||||
IndexedView<EIGEN_INDEXED_VIEW_METHOD_CONST Derived,typename IvcType<Indices>::type,IvcIndex> >::type
|
||||
operator()(const Indices& indices) EIGEN_INDEXED_VIEW_METHOD_CONST
|
||||
{
|
||||
EIGEN_STATIC_ASSERT_VECTOR_ONLY(Derived)
|
||||
return IndexedView<EIGEN_INDEXED_VIEW_METHOD_CONST Derived,typename IvcType<Indices>::type,IvcIndex>
|
||||
(derived(), ivcRow(indices), IvcIndex(0));
|
||||
}
|
||||
|
||||
template<typename Indices>
|
||||
typename internal::enable_if<
|
||||
(internal::get_compile_time_incr<typename IvcType<Indices>::type>::value==1) && (!internal::is_integral<Indices>::value) && (!Symbolic::is_symbolic<Indices>::value),
|
||||
VectorBlock<EIGEN_INDEXED_VIEW_METHOD_CONST Derived,internal::array_size<Indices>::value> >::type
|
||||
operator()(const Indices& indices) EIGEN_INDEXED_VIEW_METHOD_CONST
|
||||
{
|
||||
EIGEN_STATIC_ASSERT_VECTOR_ONLY(Derived)
|
||||
typename IvcType<Indices>::type actualIndices = ivcSize(indices);
|
||||
return VectorBlock<EIGEN_INDEXED_VIEW_METHOD_CONST Derived,internal::array_size<Indices>::value>
|
||||
(derived(), internal::first(actualIndices), internal::size(actualIndices));
|
||||
}
|
||||
|
||||
template<typename IndexType>
|
||||
typename internal::enable_if<Symbolic::is_symbolic<IndexType>::value, CoeffReturnType >::type
|
||||
operator()(const IndexType& id) EIGEN_INDEXED_VIEW_METHOD_CONST
|
||||
{
|
||||
return Base::operator()(internal::eval_expr_given_size(id,size()));
|
||||
}
|
||||
|
||||
template<typename IndicesT, std::size_t IndicesN>
|
||||
typename internal::enable_if<IsRowMajor,
|
||||
IndexedView<EIGEN_INDEXED_VIEW_METHOD_CONST Derived,IvcIndex,const IndicesT (&)[IndicesN]> >::type
|
||||
operator()(const IndicesT (&indices)[IndicesN]) EIGEN_INDEXED_VIEW_METHOD_CONST
|
||||
{
|
||||
EIGEN_STATIC_ASSERT_VECTOR_ONLY(Derived)
|
||||
return IndexedView<EIGEN_INDEXED_VIEW_METHOD_CONST Derived,IvcIndex,const IndicesT (&)[IndicesN]>
|
||||
(derived(), IvcIndex(0), indices);
|
||||
}
|
||||
|
||||
template<typename IndicesT, std::size_t IndicesN>
|
||||
typename internal::enable_if<!IsRowMajor,
|
||||
IndexedView<EIGEN_INDEXED_VIEW_METHOD_CONST Derived,const IndicesT (&)[IndicesN],IvcIndex> >::type
|
||||
operator()(const IndicesT (&indices)[IndicesN]) EIGEN_INDEXED_VIEW_METHOD_CONST
|
||||
{
|
||||
EIGEN_STATIC_ASSERT_VECTOR_ONLY(Derived)
|
||||
return IndexedView<EIGEN_INDEXED_VIEW_METHOD_CONST Derived,const IndicesT (&)[IndicesN],IvcIndex>
|
||||
(derived(), indices, IvcIndex(0));
|
||||
}
|
||||
|
||||
#undef EIGEN_INDEXED_VIEW_METHOD_CONST
|
||||
#undef EIGEN_INDEXED_VIEW_METHOD_TYPE
|
||||
|
||||
#ifndef EIGEN_INDEXED_VIEW_METHOD_2ND_PASS
|
||||
#define EIGEN_INDEXED_VIEW_METHOD_2ND_PASS
|
||||
#include "IndexedViewMethods.h"
|
||||
#undef EIGEN_INDEXED_VIEW_METHOD_2ND_PASS
|
||||
#endif
|
||||
|
||||
#else // EIGEN_PARSED_BY_DOXYGEN
|
||||
|
||||
/**
|
||||
* \returns a generic submatrix view defined by the rows and columns indexed \a rowIndices and \a colIndices respectively.
|
||||
*
|
||||
* Each parameter must either be:
|
||||
* - An integer indexing a single row or column
|
||||
* - Eigen::all indexing the full set of respective rows or columns in increasing order
|
||||
* - An ArithmeticSequence as returned by the Eigen::seq and Eigen::seqN functions
|
||||
* - Any %Eigen's vector/array of integers or expressions
|
||||
* - Plain C arrays: \c int[N]
|
||||
* - And more generally any type exposing the following two member functions:
|
||||
* \code
|
||||
* <integral type> operator[](<integral type>) const;
|
||||
* <integral type> size() const;
|
||||
* \endcode
|
||||
* where \c <integral \c type> stands for any integer type compatible with Eigen::Index (i.e. \c std::ptrdiff_t).
|
||||
*
|
||||
* The last statement implies compatibility with \c std::vector, \c std::valarray, \c std::array, many of the Range-v3's ranges, etc.
|
||||
*
|
||||
* If the submatrix can be represented using a starting position \c (i,j) and positive sizes \c (rows,columns), then this
|
||||
* method will returns a Block object after extraction of the relevant information from the passed arguments. This is the case
|
||||
* when all arguments are either:
|
||||
* - An integer
|
||||
* - Eigen::all
|
||||
* - An ArithmeticSequence with compile-time increment strictly equal to 1, as returned by Eigen::seq(a,b), and Eigen::seqN(a,N).
|
||||
*
|
||||
* Otherwise a more general IndexedView<Derived,RowIndices',ColIndices'> object will be returned, after conversion of the inputs
|
||||
* to more suitable types \c RowIndices' and \c ColIndices'.
|
||||
*
|
||||
* For 1D vectors and arrays, you better use the operator()(const Indices&) overload, which behave the same way but taking a single parameter.
|
||||
*
|
||||
* \sa operator()(const Indices&), class Block, class IndexedView, DenseBase::block(Index,Index,Index,Index)
|
||||
*/
|
||||
template<typename RowIndices, typename ColIndices>
|
||||
IndexedView_or_Block
|
||||
operator()(const RowIndices& rowIndices, const ColIndices& colIndices);
|
||||
|
||||
/** This is an overload of operator()(const RowIndices&, const ColIndices&) for 1D vectors or arrays
|
||||
*
|
||||
* \only_for_vectors
|
||||
*/
|
||||
template<typename Indices>
|
||||
IndexedView_or_VectorBlock
|
||||
operator()(const Indices& indices);
|
||||
|
||||
#endif // EIGEN_PARSED_BY_DOXYGEN
|
||||
|
@ -3,7 +3,7 @@
|
||||
#include <vector>
|
||||
#include <string>
|
||||
#include "eigen_src/Eigen/Core"
|
||||
#include "../../BenchTimer.h"
|
||||
#include "../BenchTimer.h"
|
||||
using namespace Eigen;
|
||||
|
||||
#ifndef SCALAR
|
||||
|
@ -4,7 +4,7 @@
|
||||
#include <string>
|
||||
#include <functional>
|
||||
#include "eigen_src/Eigen/Core"
|
||||
#include "../../BenchTimer.h"
|
||||
#include "../BenchTimer.h"
|
||||
using namespace Eigen;
|
||||
|
||||
#ifndef SCALAR
|
||||
|
@ -112,6 +112,7 @@ function test_current
|
||||
# echo $update et $selected et $rev_found because $rev et "$global_args"
|
||||
# echo $count_rev et $count_ref
|
||||
if [ $update == true ] || [ $count_rev != $count_ref ] || ([ $selected == true ] && [ $rev_found == true ]); then
|
||||
echo "RUN: $CXX -O3 -DNDEBUG -march=native $CXX_FLAGS -I eigen_src $bench.cpp -DSCALAR=$scalar -o $name"
|
||||
if $CXX -O3 -DNDEBUG -march=native $CXX_FLAGS -I eigen_src $bench.cpp -DSCALAR=$scalar -o $name; then
|
||||
curr=`./$name $settings_file`
|
||||
if [ $count_rev == $count_ref ]; then
|
||||
|
@ -45,10 +45,12 @@ install(TARGETS eigen_blas eigen_blas_static
|
||||
|
||||
if(EIGEN_Fortran_COMPILER_WORKS)
|
||||
|
||||
if(EIGEN_LEAVE_TEST_IN_ALL_TARGET)
|
||||
if(BUILD_TESTING)
|
||||
if(EIGEN_LEAVE_TEST_IN_ALL_TARGET)
|
||||
add_subdirectory(testing) # can't do EXCLUDE_FROM_ALL here, breaks CTest
|
||||
else()
|
||||
else()
|
||||
add_subdirectory(testing EXCLUDE_FROM_ALL)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
endif()
|
||||
|
25
cmake/FindXsmm.cmake
Normal file
25
cmake/FindXsmm.cmake
Normal file
@ -0,0 +1,25 @@
|
||||
# libxsmm support.
|
||||
# libxsmm provides matrix multiplication kernels optimized for
|
||||
# the latest Intel architectures.
|
||||
# Download the library from https://github.com/hfp/libxsmm
|
||||
# Compile with make BLAS=0
|
||||
|
||||
if (LIBXSMM)
|
||||
set(XSMM_FIND_QUIETLY TRUE)
|
||||
set(XSMM_INCLUDES ${LIBXSMM}/include)
|
||||
set(XSMM_LIBRARIES ${LIBXSMM}/lib)
|
||||
endif (LIBXSMM)
|
||||
|
||||
find_path(LIBXSMM
|
||||
NAMES
|
||||
libxsmm.h
|
||||
PATHS
|
||||
$ENV{XSMMDIR}/include
|
||||
${INCLUDE_INSTALL_DIR}
|
||||
)
|
||||
|
||||
include(FindPackageHandleStandardArgs)
|
||||
find_package_handle_standard_args(XSMM DEFAULT_MSG
|
||||
LIBXSMM)
|
||||
|
||||
mark_as_advanced(LIBXSMM)
|
@ -36,7 +36,7 @@ A.fill(10); // Fill A with all 10's.
|
||||
MatrixXd::Identity(rows,cols) // eye(rows,cols)
|
||||
C.setIdentity(rows,cols) // C = eye(rows,cols)
|
||||
MatrixXd::Zero(rows,cols) // zeros(rows,cols)
|
||||
C.setZero(rows,cols) // C = ones(rows,cols)
|
||||
C.setZero(rows,cols) // C = zeros(rows,cols)
|
||||
MatrixXd::Ones(rows,cols) // ones(rows,cols)
|
||||
C.setOnes(rows,cols) // C = ones(rows,cols)
|
||||
MatrixXd::Random(rows,cols) // rand(rows,cols)*2-1 // MatrixXd::Random returns uniform random numbers in (-1, 1).
|
||||
@ -84,7 +84,7 @@ P.bottomRightCorner<rows,cols>() // P(end-rows+1:end, end-cols+1:end)
|
||||
|
||||
// Of particular note is Eigen's swap function which is highly optimized.
|
||||
// Eigen // Matlab
|
||||
R.row(i) = P.col(j); // R(i, :) = P(:, i)
|
||||
R.row(i) = P.col(j); // R(i, :) = P(:, j)
|
||||
R.col(j1).swap(mat1.col(j2)); // R(:, [j1 j2]) = R(:, [j2, j1])
|
||||
|
||||
// Views, transpose, etc;
|
||||
|
@ -366,7 +366,7 @@ This also means that, unless specified, if the function \c std::foo is available
|
||||
<tr>
|
||||
<td class="code">
|
||||
\anchor cwisetable_isfinite
|
||||
a.\link ArrayBase::isfinite isfinite\endlink(); \n
|
||||
a.\link ArrayBase::isFinite isFinite\endlink(); \n
|
||||
\link Eigen::isfinite isfinite\endlink(a);
|
||||
</td>
|
||||
<td>checks if the given number has finite value</td>
|
||||
@ -377,7 +377,7 @@ This also means that, unless specified, if the function \c std::foo is available
|
||||
<tr>
|
||||
<td class="code">
|
||||
\anchor cwisetable_isinf
|
||||
a.\link ArrayBase::isinf isinf\endlink(); \n
|
||||
a.\link ArrayBase::isInf isInf\endlink(); \n
|
||||
\link Eigen::isinf isinf\endlink(a);
|
||||
</td>
|
||||
<td>checks if the given number is infinite</td>
|
||||
@ -388,7 +388,7 @@ This also means that, unless specified, if the function \c std::foo is available
|
||||
<tr>
|
||||
<td class="code">
|
||||
\anchor cwisetable_isnan
|
||||
a.\link ArrayBase::isnan isnan\endlink(); \n
|
||||
a.\link ArrayBase::isNaN isNaN\endlink(); \n
|
||||
\link Eigen::isnan isnan\endlink(a);
|
||||
</td>
|
||||
<td>checks if the given number is not a number</td>
|
||||
@ -399,7 +399,7 @@ This also means that, unless specified, if the function \c std::foo is available
|
||||
<tr>
|
||||
<th colspan="4">Error and gamma functions</th>
|
||||
</tr>
|
||||
<tr> <td colspan="4"> Require \c #include \c <unsupported/Eigen/SpecialFunctions> </td></tr>
|
||||
<tr> <td colspan="4"> Require \c \#include \c <unsupported/Eigen/SpecialFunctions> </td></tr>
|
||||
<tr>
|
||||
<td class="code">
|
||||
\anchor cwisetable_erf
|
||||
@ -478,7 +478,7 @@ This also means that, unless specified, if the function \c std::foo is available
|
||||
<tr>
|
||||
<th colspan="4">Special functions</th>
|
||||
</tr>
|
||||
<tr> <td colspan="4"> Require \c #include \c <unsupported/Eigen/SpecialFunctions> </td></tr>
|
||||
<tr> <td colspan="4"> Require \c \#include \c <unsupported/Eigen/SpecialFunctions> </td></tr>
|
||||
<tr>
|
||||
<td class="code">
|
||||
\anchor cwisetable_polygamma
|
||||
|
@ -229,7 +229,8 @@ ALIASES = "only_for_vectors=This is only for vectors (either row-
|
||||
"blank= " \
|
||||
"cpp11=<span class='cpp11'>[c++11]</span>" \
|
||||
"cpp14=<span class='cpp14'>[c++14]</span>" \
|
||||
"cpp17=<span class='cpp17'>[c++17]</span>"
|
||||
"cpp17=<span class='cpp17'>[c++17]</span>" \
|
||||
"newin{1}=<span class='newin3x'>New in %Eigen \1.</span>"
|
||||
|
||||
|
||||
ALIASES += "eigenAutoToc= "
|
||||
@ -409,7 +410,7 @@ EXTRACT_PACKAGE = NO
|
||||
# If the EXTRACT_STATIC tag is set to YES all static members of a file
|
||||
# will be included in the documentation.
|
||||
|
||||
EXTRACT_STATIC = NO
|
||||
EXTRACT_STATIC = YES
|
||||
|
||||
# If the EXTRACT_LOCAL_CLASSES tag is set to YES classes (and structs)
|
||||
# defined locally in source files will be included in the documentation.
|
||||
@ -727,7 +728,8 @@ RECURSIVE = YES
|
||||
# Note that relative paths are relative to the directory from which doxygen is
|
||||
# run.
|
||||
|
||||
EXCLUDE = "${Eigen_SOURCE_DIR}/Eigen/Eigen2Support" \
|
||||
EXCLUDE = "${Eigen_SOURCE_DIR}/Eigen/src/Core/products" \
|
||||
"${Eigen_SOURCE_DIR}/Eigen/Eigen2Support" \
|
||||
"${Eigen_SOURCE_DIR}/Eigen/src/Eigen2Support" \
|
||||
"${Eigen_SOURCE_DIR}/doc/examples" \
|
||||
"${Eigen_SOURCE_DIR}/doc/special_examples" \
|
||||
@ -1591,9 +1593,13 @@ PREDEFINED = EIGEN_EMPTY_STRUCT \
|
||||
EIGEN_STRONG_INLINE=inline \
|
||||
EIGEN_DEVICE_FUNC= \
|
||||
"EIGEN_MAKE_CWISE_BINARY_OP(METHOD,FUNCTOR)=template<typename OtherDerived> const CwiseBinaryOp<FUNCTOR<Scalar>, const Derived, const OtherDerived> METHOD(const EIGEN_CURRENT_STORAGE_BASE_CLASS<OtherDerived> &other) const;" \
|
||||
"EIGEN_CWISE_PRODUCT_RETURN_TYPE(LHS,RHS)=CwiseBinaryOp<internal::scalar_product_op<typename LHS::Scalar, typename RHS::Scalar >, const LHS, const RHS>"\
|
||||
"EIGEN_CWISE_PRODUCT_RETURN_TYPE(LHS,RHS)=CwiseBinaryOp<internal::scalar_product_op<LHS::Scalar,RHS::Scalar>, const LHS, const RHS>"\
|
||||
"EIGEN_CAT2(a,b)= a ## b"\
|
||||
"EIGEN_CAT(a,b)=EIGEN_CAT2(a,b)"\
|
||||
"EIGEN_CWISE_BINARY_RETURN_TYPE(LHS,RHS,OPNAME)=CwiseBinaryOp<EIGEN_CAT(EIGEN_CAT(internal::scalar_,OPNAME),_op)<LHS::Scalar, RHS::Scalar>, const LHS, const RHS>"\
|
||||
DOXCOMMA=,
|
||||
|
||||
|
||||
# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then
|
||||
# this tag can be used to specify a list of macro names that should be expanded.
|
||||
# The macro definition that is found in the sources will be used.
|
||||
@ -1617,6 +1623,7 @@ EXPAND_AS_DEFINED = EIGEN_MAKE_TYPEDEFS \
|
||||
EIGEN_DOC_BLOCK_ADDONS_NOT_INNER_PANEL \
|
||||
EIGEN_DOC_BLOCK_ADDONS_INNER_PANEL_IF
|
||||
|
||||
|
||||
# If the SKIP_FUNCTION_MACROS tag is set to YES (the default) then
|
||||
# doxygen's preprocessor will remove all references to function-like macros
|
||||
# that are alone on a line, have an all uppercase name, and do not end with a
|
||||
|
@ -129,7 +129,7 @@ run time. However, these assertions do cost time and can thus be turned off.
|
||||
\section TopicPreprocessorDirectivesPlugins Plugins
|
||||
|
||||
It is possible to add new methods to many fundamental classes in %Eigen by writing a plugin. As explained in
|
||||
the section \ref ExtendingMatrixBase, the plugin is specified by defining a \c EIGEN_xxx_PLUGIN macro. The
|
||||
the section \ref TopicCustomizing_Plugins, the plugin is specified by defining a \c EIGEN_xxx_PLUGIN macro. The
|
||||
following macros are supported; none of them are defined by default.
|
||||
|
||||
- \b EIGEN_ARRAY_PLUGIN - filename of plugin for extending the Array class.
|
||||
|
@ -340,7 +340,7 @@ mat1 = mat2.adjoint(); mat1.adjointInPlace();
|
||||
\endcode
|
||||
</td></tr>
|
||||
<tr><td>
|
||||
\link MatrixBase::dot() dot \endlink product \n inner product \matrixworld</td><td>\code
|
||||
\link MatrixBase::dot dot \endlink product \n inner product \matrixworld</td><td>\code
|
||||
scalar = vec1.dot(vec2);
|
||||
scalar = col1.adjoint() * col2;
|
||||
scalar = (col1.adjoint() * col2).value();\endcode
|
||||
|
@ -181,6 +181,11 @@ span.cpp11,span.cpp14,span.cpp17 {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.newin3x {
|
||||
color: #a37c1a;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
/**** old Eigen's styles ****/
|
||||
|
||||
|
||||
|
2
doc/snippets/Cwise_boolean_xor.cpp
Normal file
2
doc/snippets/Cwise_boolean_xor.cpp
Normal file
@ -0,0 +1,2 @@
|
||||
Array3d v(-1,2,1), w(-3,2,3);
|
||||
cout << ((v<w) ^ (v<0)) << endl;
|
6
doc/snippets/MatrixBase_selfadjointView.cpp
Normal file
6
doc/snippets/MatrixBase_selfadjointView.cpp
Normal file
@ -0,0 +1,6 @@
|
||||
Matrix3i m = Matrix3i::Random();
|
||||
cout << "Here is the matrix m:" << endl << m << endl;
|
||||
cout << "Here is the symmetric matrix extracted from the upper part of m:" << endl
|
||||
<< Matrix3i(m.selfadjointView<Upper>()) << endl;
|
||||
cout << "Here is the symmetric matrix extracted from the lower part of m:" << endl
|
||||
<< Matrix3i(m.selfadjointView<Lower>()) << endl;
|
@ -161,6 +161,8 @@ ei_add_test(redux)
|
||||
ei_add_test(visitor)
|
||||
ei_add_test(block)
|
||||
ei_add_test(corners)
|
||||
ei_add_test(symbolic_index)
|
||||
ei_add_test(indexed_view)
|
||||
ei_add_test(swap)
|
||||
ei_add_test(resize)
|
||||
ei_add_test(conservative_resize)
|
||||
|
@ -29,6 +29,13 @@ block_real_only(const MatrixType &, Index, Index, Index, Index, const Scalar&) {
|
||||
return Scalar(0);
|
||||
}
|
||||
|
||||
// Check at compile-time that T1==T2, and at runtime-time that a==b
|
||||
template<typename T1,typename T2>
|
||||
typename internal::enable_if<internal::is_same<T1,T2>::value,bool>::type
|
||||
is_same_block(const T1& a, const T2& b)
|
||||
{
|
||||
return a.isApprox(b);
|
||||
}
|
||||
|
||||
template<typename MatrixType> void block(const MatrixType& m)
|
||||
{
|
||||
@ -87,10 +94,9 @@ template<typename MatrixType> void block(const MatrixType& m)
|
||||
m1.block(r1,c1,r2-r1+1,c2-c1+1) = s1 * m2.block(0, 0, r2-r1+1,c2-c1+1);
|
||||
m1.block(r1,c1,r2-r1+1,c2-c1+1)(r2-r1,c2-c1) = m2.block(0, 0, r2-r1+1,c2-c1+1)(0,0);
|
||||
|
||||
enum {
|
||||
BlockRows = 2,
|
||||
BlockCols = 5
|
||||
};
|
||||
const Index BlockRows = 2;
|
||||
const Index BlockCols = 5;
|
||||
|
||||
if (rows>=5 && cols>=8)
|
||||
{
|
||||
// test fixed block() as lvalue
|
||||
@ -106,6 +112,11 @@ template<typename MatrixType> void block(const MatrixType& m)
|
||||
m1.template block<BlockRows,Dynamic>(1,1,BlockRows,BlockCols)(0,3) = m1.template block<2,5>(1,1)(1,2);
|
||||
Matrix<Scalar,Dynamic,Dynamic> b2 = m1.template block<Dynamic,BlockCols>(3,3,2,5);
|
||||
VERIFY_IS_EQUAL(b2, m1.block(3,3,BlockRows,BlockCols));
|
||||
|
||||
VERIFY(is_same_block(m1.block(3,3,BlockRows,BlockCols), m1.block(3,3,fix<Dynamic>(BlockRows),fix<Dynamic>(BlockCols))));
|
||||
VERIFY(is_same_block(m1.template block<BlockRows,Dynamic>(1,1,BlockRows,BlockCols), m1.block(1,1,fix<BlockRows>,BlockCols)));
|
||||
VERIFY(is_same_block(m1.template block<BlockRows,BlockCols>(1,1,BlockRows,BlockCols), m1.block(1,1,fix<BlockRows>(),fix<BlockCols>)));
|
||||
VERIFY(is_same_block(m1.template block<BlockRows,BlockCols>(1,1,BlockRows,BlockCols), m1.block(1,1,fix<BlockRows>,fix<BlockCols>(BlockCols))));
|
||||
}
|
||||
|
||||
if (rows>2)
|
||||
@ -186,6 +197,14 @@ template<typename MatrixType> void block(const MatrixType& m)
|
||||
VERIFY_IS_EQUAL( (m1.template block<1,Dynamic>(0,1,1,0)), m1.block(0,1,1,0));
|
||||
VERIFY_IS_EQUAL( ((m1*1).template block<Dynamic,1>(1,0,0,1)), m1.block(1,0,0,1));
|
||||
VERIFY_IS_EQUAL( ((m1*1).template block<1,Dynamic>(0,1,1,0)), m1.block(0,1,1,0));
|
||||
|
||||
if (rows>=2 && cols>=2)
|
||||
{
|
||||
VERIFY_RAISES_ASSERT( m1 += m1.col(0) );
|
||||
VERIFY_RAISES_ASSERT( m1 -= m1.col(0) );
|
||||
VERIFY_RAISES_ASSERT( m1.array() *= m1.col(0).array() );
|
||||
VERIFY_RAISES_ASSERT( m1.array() /= m1.col(0).array() );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
@ -68,6 +68,21 @@ template<typename MatrixType> void diagonal(const MatrixType& m)
|
||||
}
|
||||
}
|
||||
|
||||
template<typename MatrixType> void diagonal_assert(const MatrixType& m) {
|
||||
Index rows = m.rows();
|
||||
Index cols = m.cols();
|
||||
|
||||
MatrixType m1 = MatrixType::Random(rows, cols);
|
||||
|
||||
if (rows>=2 && cols>=2)
|
||||
{
|
||||
VERIFY_RAISES_ASSERT( m1 += m1.diagonal() );
|
||||
VERIFY_RAISES_ASSERT( m1 -= m1.diagonal() );
|
||||
VERIFY_RAISES_ASSERT( m1.array() *= m1.diagonal().array() );
|
||||
VERIFY_RAISES_ASSERT( m1.array() /= m1.diagonal().array() );
|
||||
}
|
||||
}
|
||||
|
||||
void test_diagonal()
|
||||
{
|
||||
for(int i = 0; i < g_repeat; i++) {
|
||||
@ -81,4 +96,6 @@ void test_diagonal()
|
||||
CALL_SUBTEST_1( diagonal(MatrixXf(internal::random<int>(1,EIGEN_TEST_MAX_SIZE), internal::random<int>(1,EIGEN_TEST_MAX_SIZE))) );
|
||||
CALL_SUBTEST_1( diagonal(Matrix<float,Dynamic,4>(3, 4)) );
|
||||
}
|
||||
|
||||
CALL_SUBTEST_1( diagonal_assert(MatrixXf(internal::random<int>(1,EIGEN_TEST_MAX_SIZE), internal::random<int>(1,EIGEN_TEST_MAX_SIZE))) );
|
||||
}
|
||||
|
378
test/indexed_view.cpp
Normal file
378
test/indexed_view.cpp
Normal file
@ -0,0 +1,378 @@
|
||||
// This file is part of Eigen, a lightweight C++ template library
|
||||
// for linear algebra.
|
||||
//
|
||||
// Copyright (C) 2017 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/.
|
||||
|
||||
#ifdef EIGEN_TEST_PART_2
|
||||
// Make sure we also check c++11 max implementation
|
||||
#define EIGEN_MAX_CPP_VER 11
|
||||
#endif
|
||||
|
||||
#ifdef EIGEN_TEST_PART_3
|
||||
// Make sure we also check c++98 max implementation
|
||||
#define EIGEN_MAX_CPP_VER 03
|
||||
#endif
|
||||
|
||||
#include <valarray>
|
||||
#include <vector>
|
||||
#include "main.h"
|
||||
|
||||
#if EIGEN_HAS_CXX11
|
||||
#include <array>
|
||||
#endif
|
||||
|
||||
typedef std::pair<Index,Index> IndexPair;
|
||||
|
||||
int encode(Index i, Index j) {
|
||||
return int(i*100 + j);
|
||||
}
|
||||
|
||||
IndexPair decode(Index ij) {
|
||||
return IndexPair(ij / 100, ij % 100);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
bool match(const T& xpr, std::string ref, std::string str_xpr = "") {
|
||||
EIGEN_UNUSED_VARIABLE(str_xpr);
|
||||
std::stringstream str;
|
||||
str << xpr;
|
||||
if(!(str.str() == ref))
|
||||
std::cout << str_xpr << "\n" << xpr << "\n\n";
|
||||
return str.str() == ref;
|
||||
}
|
||||
|
||||
#define MATCH(X,R) match(X, R, #X)
|
||||
|
||||
template<typename T1,typename T2>
|
||||
typename internal::enable_if<internal::is_same<T1,T2>::value,bool>::type
|
||||
is_same_eq(const T1& a, const T2& b)
|
||||
{
|
||||
return (a == b).all();
|
||||
}
|
||||
|
||||
template<typename T1,typename T2>
|
||||
bool is_same_seq(const T1& a, const T2& b)
|
||||
{
|
||||
bool ok = a.first()==b.first() && a.size() == b.size() && Index(a.incrObject())==Index(b.incrObject());;
|
||||
if(!ok)
|
||||
{
|
||||
std::cerr << "seqN(" << a.first() << ", " << a.size() << ", " << Index(a.incrObject()) << ") != ";
|
||||
std::cerr << "seqN(" << b.first() << ", " << b.size() << ", " << Index(b.incrObject()) << ")\n";
|
||||
}
|
||||
return ok;
|
||||
}
|
||||
|
||||
template<typename T1,typename T2>
|
||||
typename internal::enable_if<internal::is_same<T1,T2>::value,bool>::type
|
||||
is_same_seq_type(const T1& a, const T2& b)
|
||||
{
|
||||
return is_same_seq(a,b);
|
||||
}
|
||||
|
||||
|
||||
|
||||
#define VERIFY_EQ_INT(A,B) VERIFY_IS_APPROX(int(A),int(B))
|
||||
|
||||
void check_indexed_view()
|
||||
{
|
||||
using Eigen::placeholders::all;
|
||||
using Eigen::placeholders::last;
|
||||
using Eigen::placeholders::end;
|
||||
|
||||
Index n = 10;
|
||||
|
||||
ArrayXd a = ArrayXd::LinSpaced(n,0,n-1);
|
||||
Array<double,1,Dynamic> b = a.transpose();
|
||||
|
||||
ArrayXXi A = ArrayXXi::NullaryExpr(n,n, std::ptr_fun(encode));
|
||||
|
||||
for(Index i=0; i<n; ++i)
|
||||
for(Index j=0; j<n; ++j)
|
||||
VERIFY( decode(A(i,j)) == IndexPair(i,j) );
|
||||
|
||||
Array4i eii(4); eii << 3, 1, 6, 5;
|
||||
std::valarray<int> vali(4); Map<ArrayXi>(&vali[0],4) = eii;
|
||||
std::vector<int> veci(4); Map<ArrayXi>(veci.data(),4) = eii;
|
||||
|
||||
VERIFY( MATCH( A(3, seq(9,3,-1)),
|
||||
"309 308 307 306 305 304 303")
|
||||
);
|
||||
|
||||
VERIFY( MATCH( A(seqN(2,5), seq(9,3,-1)),
|
||||
"209 208 207 206 205 204 203\n"
|
||||
"309 308 307 306 305 304 303\n"
|
||||
"409 408 407 406 405 404 403\n"
|
||||
"509 508 507 506 505 504 503\n"
|
||||
"609 608 607 606 605 604 603")
|
||||
);
|
||||
|
||||
VERIFY( MATCH( A(seqN(2,5), 5),
|
||||
"205\n"
|
||||
"305\n"
|
||||
"405\n"
|
||||
"505\n"
|
||||
"605")
|
||||
);
|
||||
|
||||
VERIFY( MATCH( A(seqN(last,5,-1), seq(2,last)),
|
||||
"902 903 904 905 906 907 908 909\n"
|
||||
"802 803 804 805 806 807 808 809\n"
|
||||
"702 703 704 705 706 707 708 709\n"
|
||||
"602 603 604 605 606 607 608 609\n"
|
||||
"502 503 504 505 506 507 508 509")
|
||||
);
|
||||
|
||||
VERIFY( MATCH( A(eii, veci),
|
||||
"303 301 306 305\n"
|
||||
"103 101 106 105\n"
|
||||
"603 601 606 605\n"
|
||||
"503 501 506 505")
|
||||
);
|
||||
|
||||
VERIFY( MATCH( A(eii, all),
|
||||
"300 301 302 303 304 305 306 307 308 309\n"
|
||||
"100 101 102 103 104 105 106 107 108 109\n"
|
||||
"600 601 602 603 604 605 606 607 608 609\n"
|
||||
"500 501 502 503 504 505 506 507 508 509")
|
||||
);
|
||||
|
||||
// takes the row numer 3, and repeat it 5 times
|
||||
VERIFY( MATCH( A(seqN(3,5,0), all),
|
||||
"300 301 302 303 304 305 306 307 308 309\n"
|
||||
"300 301 302 303 304 305 306 307 308 309\n"
|
||||
"300 301 302 303 304 305 306 307 308 309\n"
|
||||
"300 301 302 303 304 305 306 307 308 309\n"
|
||||
"300 301 302 303 304 305 306 307 308 309")
|
||||
);
|
||||
|
||||
VERIFY( MATCH( a(seqN(3,3),0), "3\n4\n5" ) );
|
||||
VERIFY( MATCH( a(seq(3,5)), "3\n4\n5" ) );
|
||||
VERIFY( MATCH( a(seqN(3,3,1)), "3\n4\n5" ) );
|
||||
VERIFY( MATCH( a(seqN(5,3,-1)), "5\n4\n3" ) );
|
||||
|
||||
VERIFY( MATCH( b(0,seqN(3,3)), "3 4 5" ) );
|
||||
VERIFY( MATCH( b(seq(3,5)), "3 4 5" ) );
|
||||
VERIFY( MATCH( b(seqN(3,3,1)), "3 4 5" ) );
|
||||
VERIFY( MATCH( b(seqN(5,3,-1)), "5 4 3" ) );
|
||||
|
||||
VERIFY( MATCH( b(all), "0 1 2 3 4 5 6 7 8 9" ) );
|
||||
VERIFY( MATCH( b(eii), "3 1 6 5" ) );
|
||||
|
||||
Array44i B;
|
||||
B.setRandom();
|
||||
VERIFY( (A(seqN(2,5), 5)).ColsAtCompileTime == 1);
|
||||
VERIFY( (A(seqN(2,5), 5)).RowsAtCompileTime == Dynamic);
|
||||
VERIFY_EQ_INT( (A(seqN(2,5), 5)).InnerStrideAtCompileTime , A.InnerStrideAtCompileTime);
|
||||
VERIFY_EQ_INT( (A(seqN(2,5), 5)).OuterStrideAtCompileTime , A.col(5).OuterStrideAtCompileTime);
|
||||
|
||||
VERIFY_EQ_INT( (A(5,seqN(2,5))).InnerStrideAtCompileTime , A.row(5).InnerStrideAtCompileTime);
|
||||
VERIFY_EQ_INT( (A(5,seqN(2,5))).OuterStrideAtCompileTime , A.row(5).OuterStrideAtCompileTime);
|
||||
VERIFY_EQ_INT( (B(1,seqN(1,2))).InnerStrideAtCompileTime , B.row(1).InnerStrideAtCompileTime);
|
||||
VERIFY_EQ_INT( (B(1,seqN(1,2))).OuterStrideAtCompileTime , B.row(1).OuterStrideAtCompileTime);
|
||||
|
||||
VERIFY_EQ_INT( (A(seqN(2,5), seq(1,3))).InnerStrideAtCompileTime , A.InnerStrideAtCompileTime);
|
||||
VERIFY_EQ_INT( (A(seqN(2,5), seq(1,3))).OuterStrideAtCompileTime , A.OuterStrideAtCompileTime);
|
||||
VERIFY_EQ_INT( (B(seqN(1,2), seq(1,3))).InnerStrideAtCompileTime , B.InnerStrideAtCompileTime);
|
||||
VERIFY_EQ_INT( (B(seqN(1,2), seq(1,3))).OuterStrideAtCompileTime , B.OuterStrideAtCompileTime);
|
||||
VERIFY_EQ_INT( (A(seqN(2,5,2), seq(1,3,2))).InnerStrideAtCompileTime , Dynamic);
|
||||
VERIFY_EQ_INT( (A(seqN(2,5,2), seq(1,3,2))).OuterStrideAtCompileTime , Dynamic);
|
||||
VERIFY_EQ_INT( (A(seqN(2,5,fix<2>), seq(1,3,fix<3>))).InnerStrideAtCompileTime , 2);
|
||||
VERIFY_EQ_INT( (A(seqN(2,5,fix<2>), seq(1,3,fix<3>))).OuterStrideAtCompileTime , Dynamic);
|
||||
VERIFY_EQ_INT( (B(seqN(1,2,fix<2>), seq(1,3,fix<3>))).InnerStrideAtCompileTime , 2);
|
||||
VERIFY_EQ_INT( (B(seqN(1,2,fix<2>), seq(1,3,fix<3>))).OuterStrideAtCompileTime , 3*4);
|
||||
|
||||
VERIFY_EQ_INT( (A(seqN(2,fix<5>), seqN(1,fix<3>))).RowsAtCompileTime, 5);
|
||||
VERIFY_EQ_INT( (A(seqN(2,fix<5>), seqN(1,fix<3>))).ColsAtCompileTime, 3);
|
||||
VERIFY_EQ_INT( (A(seqN(2,fix<5>(5)), seqN(1,fix<3>(3)))).RowsAtCompileTime, 5);
|
||||
VERIFY_EQ_INT( (A(seqN(2,fix<5>(5)), seqN(1,fix<3>(3)))).ColsAtCompileTime, 3);
|
||||
VERIFY_EQ_INT( (A(seqN(2,fix<Dynamic>(5)), seqN(1,fix<Dynamic>(3)))).RowsAtCompileTime, Dynamic);
|
||||
VERIFY_EQ_INT( (A(seqN(2,fix<Dynamic>(5)), seqN(1,fix<Dynamic>(3)))).ColsAtCompileTime, Dynamic);
|
||||
VERIFY_EQ_INT( (A(seqN(2,fix<Dynamic>(5)), seqN(1,fix<Dynamic>(3)))).rows(), 5);
|
||||
VERIFY_EQ_INT( (A(seqN(2,fix<Dynamic>(5)), seqN(1,fix<Dynamic>(3)))).cols(), 3);
|
||||
|
||||
VERIFY( is_same_seq_type( seqN(2,5,fix<-1>), seqN(2,5,fix<-1>(-1)) ) );
|
||||
VERIFY( is_same_seq_type( seqN(2,5), seqN(2,5,fix<1>(1)) ) );
|
||||
VERIFY( is_same_seq_type( seqN(2,5,3), seqN(2,5,fix<DynamicIndex>(3)) ) );
|
||||
VERIFY( is_same_seq_type( seq(2,7,fix<3>), seqN(2,2,fix<3>) ) );
|
||||
VERIFY( is_same_seq_type( seqN(2,fix<Dynamic>(5),3), seqN(2,5,fix<DynamicIndex>(3)) ) );
|
||||
VERIFY( is_same_seq_type( seqN(2,fix<5>(5),fix<-2>), seqN(2,fix<5>,fix<-2>()) ) );
|
||||
|
||||
VERIFY( is_same_seq_type( seq(2,fix<5>), seqN(2,4) ) );
|
||||
#if EIGEN_HAS_CXX11
|
||||
VERIFY( is_same_seq_type( seq(fix<2>,fix<5>), seqN(fix<2>,fix<4>) ) );
|
||||
VERIFY( is_same_seq( seqN(2,std::integral_constant<int,5>(),std::integral_constant<int,-2>()), seqN(2,fix<5>,fix<-2>()) ) );
|
||||
VERIFY( is_same_seq( seq(std::integral_constant<int,1>(),std::integral_constant<int,5>(),std::integral_constant<int,2>()),
|
||||
seq(fix<1>,fix<5>,fix<2>()) ) );
|
||||
VERIFY( is_same_seq_type( seqN(2,std::integral_constant<int,5>(),std::integral_constant<int,-2>()), seqN(2,fix<5>,fix<-2>()) ) );
|
||||
VERIFY( is_same_seq_type( seq(std::integral_constant<int,1>(),std::integral_constant<int,5>(),std::integral_constant<int,2>()),
|
||||
seq(fix<1>,fix<5>,fix<2>()) ) );
|
||||
|
||||
VERIFY( is_same_seq_type( seqN(2,std::integral_constant<int,5>()), seqN(2,fix<5>) ) );
|
||||
VERIFY( is_same_seq_type( seq(std::integral_constant<int,1>(),std::integral_constant<int,5>()), seq(fix<1>,fix<5>) ) );
|
||||
#else
|
||||
// sorry, no compile-time size recovery in c++98/03
|
||||
VERIFY( is_same_seq( seq(fix<2>,fix<5>), seqN(fix<2>,fix<4>) ) );
|
||||
#endif
|
||||
|
||||
VERIFY( (A(seqN(2,fix<5>), 5)).RowsAtCompileTime == 5);
|
||||
VERIFY( (A(4, all)).ColsAtCompileTime == Dynamic);
|
||||
VERIFY( (A(4, all)).RowsAtCompileTime == 1);
|
||||
VERIFY( (B(1, all)).ColsAtCompileTime == 4);
|
||||
VERIFY( (B(1, all)).RowsAtCompileTime == 1);
|
||||
VERIFY( (B(all,1)).ColsAtCompileTime == 1);
|
||||
VERIFY( (B(all,1)).RowsAtCompileTime == 4);
|
||||
|
||||
VERIFY(int( (A(all, eii)).ColsAtCompileTime) == int(eii.SizeAtCompileTime));
|
||||
VERIFY_EQ_INT( (A(eii, eii)).Flags&DirectAccessBit, (unsigned int)(0));
|
||||
VERIFY_EQ_INT( (A(eii, eii)).InnerStrideAtCompileTime, 0);
|
||||
VERIFY_EQ_INT( (A(eii, eii)).OuterStrideAtCompileTime, 0);
|
||||
|
||||
VERIFY_IS_APPROX( A(seq(n-1,2,-2), seqN(n-1-6,3,-1)), A(seq(last,2,fix<-2>), seqN(last-6,3,fix<-1>)) );
|
||||
|
||||
VERIFY_IS_APPROX( A(seq(n-1,2,-2), seqN(n-1-6,4)), A(seq(last,2,-2), seqN(last-6,4)) );
|
||||
VERIFY_IS_APPROX( A(seq(n-1-6,n-1-2), seqN(n-1-6,4)), A(seq(last-6,last-2), seqN(6+last-6-6,4)) );
|
||||
VERIFY_IS_APPROX( A(seq((n-1)/2,(n)/2+3), seqN(2,4)), A(seq(last/2,(last+1)/2+3), seqN(last+2-last,4)) );
|
||||
VERIFY_IS_APPROX( A(seq(n-2,2,-2), seqN(n-8,4)), A(seq(end-2,2,-2), seqN(end-8,4)) );
|
||||
|
||||
// Check all combinations of seq:
|
||||
VERIFY_IS_APPROX( A(seq(1,n-1-2,2), seq(1,n-1-2,2)), A(seq(1,last-2,2), seq(1,last-2,fix<2>)) );
|
||||
VERIFY_IS_APPROX( A(seq(n-1-5,n-1-2,2), seq(n-1-5,n-1-2,2)), A(seq(last-5,last-2,2), seq(last-5,last-2,fix<2>)) );
|
||||
VERIFY_IS_APPROX( A(seq(n-1-5,7,2), seq(n-1-5,7,2)), A(seq(last-5,7,2), seq(last-5,7,fix<2>)) );
|
||||
VERIFY_IS_APPROX( A(seq(1,n-1-2), seq(n-1-5,7)), A(seq(1,last-2), seq(last-5,7)) );
|
||||
VERIFY_IS_APPROX( A(seq(n-1-5,n-1-2), seq(n-1-5,n-1-2)), A(seq(last-5,last-2), seq(last-5,last-2)) );
|
||||
|
||||
VERIFY_IS_APPROX( A.col(A.cols()-1), A(all,last) );
|
||||
VERIFY_IS_APPROX( A(A.rows()-2, A.cols()/2), A(last-1, end/2) );
|
||||
VERIFY_IS_APPROX( a(a.size()-2), a(last-1) );
|
||||
VERIFY_IS_APPROX( a(a.size()/2), a((last+1)/2) );
|
||||
|
||||
// Check fall-back to Block
|
||||
{
|
||||
VERIFY( is_same_eq(A.col(0), A(all,0)) );
|
||||
VERIFY( is_same_eq(A.row(0), A(0,all)) );
|
||||
VERIFY( is_same_eq(A.block(0,0,2,2), A(seqN(0,2),seq(0,1))) );
|
||||
VERIFY( is_same_eq(A.middleRows(2,4), A(seqN(2,4),all)) );
|
||||
VERIFY( is_same_eq(A.middleCols(2,4), A(all,seqN(2,4))) );
|
||||
|
||||
VERIFY( is_same_eq(A.col(A.cols()-1), A(all,last)) );
|
||||
|
||||
const ArrayXXi& cA(A);
|
||||
VERIFY( is_same_eq(cA.col(0), cA(all,0)) );
|
||||
VERIFY( is_same_eq(cA.row(0), cA(0,all)) );
|
||||
VERIFY( is_same_eq(cA.block(0,0,2,2), cA(seqN(0,2),seq(0,1))) );
|
||||
VERIFY( is_same_eq(cA.middleRows(2,4), cA(seqN(2,4),all)) );
|
||||
VERIFY( is_same_eq(cA.middleCols(2,4), cA(all,seqN(2,4))) );
|
||||
|
||||
VERIFY( is_same_eq(a.head(4), a(seq(0,3))) );
|
||||
VERIFY( is_same_eq(a.tail(4), a(seqN(last-3,4))) );
|
||||
VERIFY( is_same_eq(a.tail(4), a(seq(end-4,last))) );
|
||||
VERIFY( is_same_eq(a.segment<4>(3), a(seqN(3,fix<4>))) );
|
||||
}
|
||||
|
||||
ArrayXXi A1=A, A2 = ArrayXXi::Random(4,4);
|
||||
ArrayXi range25(4); range25 << 3,2,4,5;
|
||||
A1(seqN(3,4),seq(2,5)) = A2;
|
||||
VERIFY_IS_APPROX( A1.block(3,2,4,4), A2 );
|
||||
A1 = A;
|
||||
A2.setOnes();
|
||||
A1(seq(6,3,-1),range25) = A2;
|
||||
VERIFY_IS_APPROX( A1.block(3,2,4,4), A2 );
|
||||
|
||||
// check reverse
|
||||
{
|
||||
VERIFY( is_same_seq_type( seq(3,7).reverse(), seqN(7,5,fix<-1>) ) );
|
||||
VERIFY( is_same_seq_type( seq(7,3,fix<-2>).reverse(), seqN(3,3,fix<2>) ) );
|
||||
VERIFY_IS_APPROX( a(seqN(2,last/2).reverse()), a(seqN(2+(last/2-1)*1,last/2,fix<-1>)) );
|
||||
VERIFY_IS_APPROX( a(seqN(last/2,fix<4>).reverse()),a(seqN(last/2,fix<4>)).reverse() );
|
||||
VERIFY_IS_APPROX( A(seq(last-5,last-1,2).reverse(), seqN(last-3,3,fix<-2>).reverse()),
|
||||
A(seq(last-5,last-1,2), seqN(last-3,3,fix<-2>)).reverse() );
|
||||
}
|
||||
|
||||
#if EIGEN_HAS_CXX11
|
||||
VERIFY( (A(all, std::array<int,4>{{1,3,2,4}})).ColsAtCompileTime == 4);
|
||||
|
||||
VERIFY_IS_APPROX( (A(std::array<int,3>{{1,3,5}}, std::array<int,4>{{9,6,3,0}})), A(seqN(1,3,2), seqN(9,4,-3)) );
|
||||
|
||||
#if (!EIGEN_COMP_CLANG) || (EIGEN_COMP_CLANG>=308 && !defined(__apple_build_version__))
|
||||
VERIFY_IS_APPROX( A({3, 1, 6, 5}, all), A(std::array<int,4>{{3, 1, 6, 5}}, all) );
|
||||
VERIFY_IS_APPROX( A(all,{3, 1, 6, 5}), A(all,std::array<int,4>{{3, 1, 6, 5}}) );
|
||||
VERIFY_IS_APPROX( A({1,3,5},{3, 1, 6, 5}), A(std::array<int,3>{{1,3,5}},std::array<int,4>{{3, 1, 6, 5}}) );
|
||||
|
||||
VERIFY_IS_EQUAL( A({1,3,5},{3, 1, 6, 5}).RowsAtCompileTime, 3 );
|
||||
VERIFY_IS_EQUAL( A({1,3,5},{3, 1, 6, 5}).ColsAtCompileTime, 4 );
|
||||
|
||||
VERIFY_IS_APPROX( a({3, 1, 6, 5}), a(std::array<int,4>{{3, 1, 6, 5}}) );
|
||||
VERIFY_IS_EQUAL( a({1,3,5}).SizeAtCompileTime, 3 );
|
||||
|
||||
VERIFY_IS_APPROX( b({3, 1, 6, 5}), b(std::array<int,4>{{3, 1, 6, 5}}) );
|
||||
VERIFY_IS_EQUAL( b({1,3,5}).SizeAtCompileTime, 3 );
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
// check mat(i,j) with weird types for i and j
|
||||
{
|
||||
VERIFY_IS_APPROX( A(B.RowsAtCompileTime-1, 1), A(3,1) );
|
||||
VERIFY_IS_APPROX( A(B.RowsAtCompileTime, 1), A(4,1) );
|
||||
VERIFY_IS_APPROX( A(B.RowsAtCompileTime-1, B.ColsAtCompileTime-1), A(3,3) );
|
||||
VERIFY_IS_APPROX( A(B.RowsAtCompileTime, B.ColsAtCompileTime), A(4,4) );
|
||||
const Index I = 3, J = 4;
|
||||
VERIFY_IS_APPROX( A(I,J), A(3,4) );
|
||||
}
|
||||
|
||||
// check extended block API
|
||||
{
|
||||
VERIFY( is_same_eq( A.block<3,4>(1,1), A.block(1,1,fix<3>,fix<4>)) );
|
||||
VERIFY( is_same_eq( A.block<3,4>(1,1,3,4), A.block(1,1,fix<3>(),fix<4>(4))) );
|
||||
VERIFY( is_same_eq( A.block<3,Dynamic>(1,1,3,4), A.block(1,1,fix<3>,4)) );
|
||||
VERIFY( is_same_eq( A.block<Dynamic,4>(1,1,3,4), A.block(1,1,fix<Dynamic>(3),fix<4>)) );
|
||||
VERIFY( is_same_eq( A.block(1,1,3,4), A.block(1,1,fix<Dynamic>(3),fix<Dynamic>(4))) );
|
||||
|
||||
VERIFY( is_same_eq( A.topLeftCorner<3,4>(), A.topLeftCorner(fix<3>,fix<4>)) );
|
||||
VERIFY( is_same_eq( A.bottomLeftCorner<3,4>(), A.bottomLeftCorner(fix<3>,fix<4>)) );
|
||||
VERIFY( is_same_eq( A.bottomRightCorner<3,4>(), A.bottomRightCorner(fix<3>,fix<4>)) );
|
||||
VERIFY( is_same_eq( A.topRightCorner<3,4>(), A.topRightCorner(fix<3>,fix<4>)) );
|
||||
|
||||
VERIFY( is_same_eq( A.leftCols<3>(), A.leftCols(fix<3>)) );
|
||||
VERIFY( is_same_eq( A.rightCols<3>(), A.rightCols(fix<3>)) );
|
||||
VERIFY( is_same_eq( A.middleCols<3>(1), A.middleCols(1,fix<3>)) );
|
||||
|
||||
VERIFY( is_same_eq( A.topRows<3>(), A.topRows(fix<3>)) );
|
||||
VERIFY( is_same_eq( A.bottomRows<3>(), A.bottomRows(fix<3>)) );
|
||||
VERIFY( is_same_eq( A.middleRows<3>(1), A.middleRows(1,fix<3>)) );
|
||||
|
||||
VERIFY( is_same_eq( a.segment<3>(1), a.segment(1,fix<3>)) );
|
||||
VERIFY( is_same_eq( a.head<3>(), a.head(fix<3>)) );
|
||||
VERIFY( is_same_eq( a.tail<3>(), a.tail(fix<3>)) );
|
||||
|
||||
const ArrayXXi& cA(A);
|
||||
VERIFY( is_same_eq( cA.block<Dynamic,4>(1,1,3,4), cA.block(1,1,fix<Dynamic>(3),fix<4>)) );
|
||||
|
||||
VERIFY( is_same_eq( cA.topLeftCorner<3,4>(), cA.topLeftCorner(fix<3>,fix<4>)) );
|
||||
VERIFY( is_same_eq( cA.bottomLeftCorner<3,4>(), cA.bottomLeftCorner(fix<3>,fix<4>)) );
|
||||
VERIFY( is_same_eq( cA.bottomRightCorner<3,4>(), cA.bottomRightCorner(fix<3>,fix<4>)) );
|
||||
VERIFY( is_same_eq( cA.topRightCorner<3,4>(), cA.topRightCorner(fix<3>,fix<4>)) );
|
||||
|
||||
VERIFY( is_same_eq( cA.leftCols<3>(), cA.leftCols(fix<3>)) );
|
||||
VERIFY( is_same_eq( cA.rightCols<3>(), cA.rightCols(fix<3>)) );
|
||||
VERIFY( is_same_eq( cA.middleCols<3>(1), cA.middleCols(1,fix<3>)) );
|
||||
|
||||
VERIFY( is_same_eq( cA.topRows<3>(), cA.topRows(fix<3>)) );
|
||||
VERIFY( is_same_eq( cA.bottomRows<3>(), cA.bottomRows(fix<3>)) );
|
||||
VERIFY( is_same_eq( cA.middleRows<3>(1), cA.middleRows(1,fix<3>)) );
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void test_indexed_view()
|
||||
{
|
||||
// for(int i = 0; i < g_repeat; i++) {
|
||||
CALL_SUBTEST_1( check_indexed_view() );
|
||||
CALL_SUBTEST_2( check_indexed_view() );
|
||||
CALL_SUBTEST_3( check_indexed_view() );
|
||||
// }
|
||||
}
|
@ -372,10 +372,10 @@ inline bool test_isApproxOrLessThan(const half& a, const half& b)
|
||||
|
||||
// test_relative_error returns the relative difference between a and b as a real scalar as used in isApprox.
|
||||
template<typename T1,typename T2>
|
||||
typename T1::RealScalar test_relative_error(const EigenBase<T1> &a, const EigenBase<T2> &b)
|
||||
typename NumTraits<typename T1::RealScalar>::NonInteger test_relative_error(const EigenBase<T1> &a, const EigenBase<T2> &b)
|
||||
{
|
||||
using std::sqrt;
|
||||
typedef typename T1::RealScalar RealScalar;
|
||||
typedef typename NumTraits<typename T1::RealScalar>::NonInteger RealScalar;
|
||||
typename internal::nested_eval<T1,2>::type ea(a.derived());
|
||||
typename internal::nested_eval<T2,2>::type eb(b.derived());
|
||||
return sqrt(RealScalar((ea-eb).cwiseAbs2().sum()) / RealScalar((std::min)(eb.cwiseAbs2().sum(),ea.cwiseAbs2().sum())));
|
||||
@ -433,9 +433,9 @@ typename T1::RealScalar test_relative_error(const SparseMatrixBase<T1> &a, const
|
||||
}
|
||||
|
||||
template<typename T1,typename T2>
|
||||
typename NumTraits<T1>::Real test_relative_error(const T1 &a, const T2 &b, typename internal::enable_if<internal::is_arithmetic<typename NumTraits<T1>::Real>::value, T1>::type* = 0)
|
||||
typename NumTraits<typename NumTraits<T1>::Real>::NonInteger test_relative_error(const T1 &a, const T2 &b, typename internal::enable_if<internal::is_arithmetic<typename NumTraits<T1>::Real>::value, T1>::type* = 0)
|
||||
{
|
||||
typedef typename NumTraits<T1>::Real RealScalar;
|
||||
typedef typename NumTraits<typename NumTraits<T1>::Real>::NonInteger RealScalar;
|
||||
return numext::sqrt(RealScalar(numext::abs2(a-b))/RealScalar((numext::mini)(numext::abs2(a),numext::abs2(b))));
|
||||
}
|
||||
|
||||
|
@ -152,6 +152,45 @@ void testVectorType(const VectorType& base)
|
||||
m.tail(size-1).setLinSpaced(low, high);
|
||||
VERIFY_IS_APPROX(m(size-1), high);
|
||||
}
|
||||
|
||||
// regression test for bug 1383 (LinSpaced with empty size/range)
|
||||
{
|
||||
Index n0 = VectorType::SizeAtCompileTime==Dynamic ? 0 : VectorType::SizeAtCompileTime;
|
||||
low = internal::random<Scalar>();
|
||||
m = VectorType::LinSpaced(n0,low,low-1);
|
||||
VERIFY(m.size()==n0);
|
||||
|
||||
if(VectorType::SizeAtCompileTime==Dynamic)
|
||||
{
|
||||
VERIFY_IS_EQUAL(VectorType::LinSpaced(n0,0,Scalar(n0-1)).sum(),Scalar(0));
|
||||
VERIFY_IS_EQUAL(VectorType::LinSpaced(n0,low,low-1).sum(),Scalar(0));
|
||||
}
|
||||
|
||||
m.setLinSpaced(n0,0,Scalar(n0-1));
|
||||
VERIFY(m.size()==n0);
|
||||
m.setLinSpaced(n0,low,low-1);
|
||||
VERIFY(m.size()==n0);
|
||||
|
||||
// empty range only:
|
||||
VERIFY_IS_APPROX(VectorType::LinSpaced(size,low,low),VectorType::Constant(size,low));
|
||||
m.setLinSpaced(size,low,low);
|
||||
VERIFY_IS_APPROX(m,VectorType::Constant(size,low));
|
||||
|
||||
if(NumTraits<Scalar>::IsInteger)
|
||||
{
|
||||
VERIFY_IS_APPROX( VectorType::LinSpaced(size,low,Scalar(low+size-1)), VectorType::LinSpaced(size,Scalar(low+size-1),low).reverse() );
|
||||
|
||||
if(VectorType::SizeAtCompileTime==Dynamic)
|
||||
{
|
||||
// Check negative multiplicator path:
|
||||
for(Index k=1; k<5; ++k)
|
||||
VERIFY_IS_APPROX( VectorType::LinSpaced(size,low,Scalar(low+(size-1)*k)), VectorType::LinSpaced(size,Scalar(low+(size-1)*k),low).reverse() );
|
||||
// Check negative divisor path:
|
||||
for(Index k=1; k<5; ++k)
|
||||
VERIFY_IS_APPROX( VectorType::LinSpaced(size*k,low,Scalar(low+size-1)), VectorType::LinSpaced(size*k,Scalar(low+size-1),low).reverse() );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template<typename MatrixType>
|
||||
@ -198,7 +237,8 @@ void test_nullary()
|
||||
CALL_SUBTEST_8( testVectorType(Matrix<float,8,1>()) );
|
||||
CALL_SUBTEST_8( testVectorType(Matrix<float,1,1>()) );
|
||||
|
||||
CALL_SUBTEST_9( testVectorType(VectorXi(internal::random<int>(1,300))) );
|
||||
CALL_SUBTEST_9( testVectorType(VectorXi(internal::random<int>(1,10))) );
|
||||
CALL_SUBTEST_9( testVectorType(VectorXi(internal::random<int>(9,300))) );
|
||||
CALL_SUBTEST_9( testVectorType(Matrix<int,1,1>()) );
|
||||
}
|
||||
|
||||
|
@ -62,6 +62,19 @@ template<typename Scalar> void mmtr(int size)
|
||||
CHECK_MMTR(matc, Upper, -= (s*sqc).template triangularView<Upper>()*sqc);
|
||||
CHECK_MMTR(matc, Lower, = (s*sqr).template triangularView<Lower>()*sqc);
|
||||
CHECK_MMTR(matc, Upper, += (s*sqc).template triangularView<Lower>()*sqc);
|
||||
|
||||
// check aliasing
|
||||
ref2 = ref1 = matc;
|
||||
ref1 = sqc.adjoint() * matc * sqc;
|
||||
ref2.template triangularView<Upper>() = ref1.template triangularView<Upper>();
|
||||
matc.template triangularView<Upper>() = sqc.adjoint() * matc * sqc;
|
||||
VERIFY_IS_APPROX(matc, ref2);
|
||||
|
||||
ref2 = ref1 = matc;
|
||||
ref1 = sqc * matc * sqc.adjoint();
|
||||
ref2.template triangularView<Lower>() = ref1.template triangularView<Lower>();
|
||||
matc.template triangularView<Lower>() = sqc * matc * sqc.adjoint();
|
||||
VERIFY_IS_APPROX(matc, ref2);
|
||||
}
|
||||
|
||||
void test_product_mmtr()
|
||||
|
@ -25,6 +25,7 @@ template<typename SparseMatrixType> void sparse_basic(const SparseMatrixType& re
|
||||
//const Index outer = ref.outerSize();
|
||||
|
||||
typedef typename SparseMatrixType::Scalar Scalar;
|
||||
typedef typename SparseMatrixType::RealScalar RealScalar;
|
||||
enum { Flags = SparseMatrixType::Flags };
|
||||
|
||||
double density = (std::max)(8./(rows*cols), 0.01);
|
||||
@ -160,11 +161,15 @@ template<typename SparseMatrixType> void sparse_basic(const SparseMatrixType& re
|
||||
if(internal::random<bool>())
|
||||
m1.makeCompressed();
|
||||
|
||||
Index m1_nnz = m1.nonZeros();
|
||||
|
||||
VERIFY_IS_APPROX(m1*s1, refM1*s1);
|
||||
VERIFY_IS_APPROX(m1+m2, refM1+refM2);
|
||||
VERIFY_IS_APPROX(m1+m2+m3, refM1+refM2+refM3);
|
||||
VERIFY_IS_APPROX(m3.cwiseProduct(m1+m2), refM3.cwiseProduct(refM1+refM2));
|
||||
VERIFY_IS_APPROX(m1*s1-m2, refM1*s1-refM2);
|
||||
VERIFY_IS_APPROX(m4=m1/s1, refM1/s1);
|
||||
VERIFY_IS_EQUAL(m4.nonZeros(), m1_nnz);
|
||||
|
||||
if(SparseMatrixType::IsRowMajor)
|
||||
VERIFY_IS_APPROX(m1.innerVector(0).dot(refM2.row(0)), refM1.row(0).dot(refM2.row(0)));
|
||||
@ -193,20 +198,52 @@ template<typename SparseMatrixType> void sparse_basic(const SparseMatrixType& re
|
||||
VERIFY_IS_APPROX(m3 + refM4, refM3 + refM4);
|
||||
VERIFY_IS_APPROX(refM4 - m3, refM4 - refM3);
|
||||
VERIFY_IS_APPROX(m3 - refM4, refM3 - refM4);
|
||||
VERIFY_IS_APPROX((RealScalar(0.5)*refM4 + RealScalar(0.5)*m3).eval(), RealScalar(0.5)*refM4 + RealScalar(0.5)*refM3);
|
||||
VERIFY_IS_APPROX((RealScalar(0.5)*refM4 + m3*RealScalar(0.5)).eval(), RealScalar(0.5)*refM4 + RealScalar(0.5)*refM3);
|
||||
VERIFY_IS_APPROX((RealScalar(0.5)*refM4 + m3.cwiseProduct(m3)).eval(), RealScalar(0.5)*refM4 + refM3.cwiseProduct(refM3));
|
||||
|
||||
VERIFY_IS_APPROX((RealScalar(0.5)*refM4 + RealScalar(0.5)*m3).eval(), RealScalar(0.5)*refM4 + RealScalar(0.5)*refM3);
|
||||
VERIFY_IS_APPROX((RealScalar(0.5)*refM4 + m3*RealScalar(0.5)).eval(), RealScalar(0.5)*refM4 + RealScalar(0.5)*refM3);
|
||||
VERIFY_IS_APPROX((RealScalar(0.5)*refM4 + (m3+m3)).eval(), RealScalar(0.5)*refM4 + (refM3+refM3));
|
||||
VERIFY_IS_APPROX(((refM3+m3)+RealScalar(0.5)*m3).eval(), RealScalar(0.5)*refM3 + (refM3+refM3));
|
||||
VERIFY_IS_APPROX((RealScalar(0.5)*refM4 + (refM3+m3)).eval(), RealScalar(0.5)*refM4 + (refM3+refM3));
|
||||
VERIFY_IS_APPROX((RealScalar(0.5)*refM4 + (m3+refM3)).eval(), RealScalar(0.5)*refM4 + (refM3+refM3));
|
||||
|
||||
|
||||
VERIFY_IS_APPROX(m1.sum(), refM1.sum());
|
||||
|
||||
m4 = m1; refM4 = m4;
|
||||
|
||||
VERIFY_IS_APPROX(m1*=s1, refM1*=s1);
|
||||
VERIFY_IS_EQUAL(m1.nonZeros(), m1_nnz);
|
||||
VERIFY_IS_APPROX(m1/=s1, refM1/=s1);
|
||||
VERIFY_IS_EQUAL(m1.nonZeros(), m1_nnz);
|
||||
|
||||
VERIFY_IS_APPROX(m1+=m2, refM1+=refM2);
|
||||
VERIFY_IS_APPROX(m1-=m2, refM1-=refM2);
|
||||
|
||||
if (rows>=2 && cols>=2)
|
||||
{
|
||||
VERIFY_RAISES_ASSERT( m1 += m1.innerVector(0) );
|
||||
VERIFY_RAISES_ASSERT( m1 -= m1.innerVector(0) );
|
||||
VERIFY_RAISES_ASSERT( refM1 -= m1.innerVector(0) );
|
||||
VERIFY_RAISES_ASSERT( refM1 += m1.innerVector(0) );
|
||||
m1 = m4; refM1 = refM4;
|
||||
}
|
||||
|
||||
// test aliasing
|
||||
VERIFY_IS_APPROX((m1 = -m1), (refM1 = -refM1));
|
||||
VERIFY_IS_EQUAL(m1.nonZeros(), m1_nnz);
|
||||
m1 = m4; refM1 = refM4;
|
||||
VERIFY_IS_APPROX((m1 = m1.transpose()), (refM1 = refM1.transpose().eval()));
|
||||
VERIFY_IS_EQUAL(m1.nonZeros(), m1_nnz);
|
||||
m1 = m4; refM1 = refM4;
|
||||
VERIFY_IS_APPROX((m1 = -m1.transpose()), (refM1 = -refM1.transpose().eval()));
|
||||
VERIFY_IS_EQUAL(m1.nonZeros(), m1_nnz);
|
||||
m1 = m4; refM1 = refM4;
|
||||
VERIFY_IS_APPROX((m1 += -m1), (refM1 += -refM1));
|
||||
VERIFY_IS_EQUAL(m1.nonZeros(), m1_nnz);
|
||||
m1 = m4; refM1 = refM4;
|
||||
|
||||
if(m1.isCompressed())
|
||||
{
|
||||
@ -416,7 +453,7 @@ template<typename SparseMatrixType> void sparse_basic(const SparseMatrixType& re
|
||||
m3 = m2.template triangularView<StrictlyLower>();
|
||||
VERIFY_IS_APPROX(m3, refMat3);
|
||||
|
||||
// check sparse-traingular to dense
|
||||
// check sparse-triangular to dense
|
||||
refMat3 = m2.template triangularView<StrictlyUpper>();
|
||||
VERIFY_IS_APPROX(refMat3, DenseMatrix(refMat2.template triangularView<StrictlyUpper>()));
|
||||
}
|
||||
@ -465,6 +502,10 @@ template<typename SparseMatrixType> void sparse_basic(const SparseMatrixType& re
|
||||
SparseMatrixType m2(rows, cols);
|
||||
initSparse<Scalar>(density, refMat2, m2);
|
||||
VERIFY_IS_APPROX(m2.diagonal(), refMat2.diagonal().eval());
|
||||
DenseVector d = m2.diagonal();
|
||||
VERIFY_IS_APPROX(d, refMat2.diagonal().eval());
|
||||
d = m2.diagonal().array();
|
||||
VERIFY_IS_APPROX(d, refMat2.diagonal().eval());
|
||||
VERIFY_IS_APPROX(const_cast<const SparseMatrixType&>(m2).diagonal(), refMat2.diagonal().eval());
|
||||
|
||||
initSparse<Scalar>(density, refMat2, m2, ForceNonZeroDiag);
|
||||
|
@ -241,6 +241,7 @@ template<typename SparseMatrixType> void sparse_product()
|
||||
// also check with a SparseWrapper:
|
||||
DenseVector v1 = DenseVector::Random(cols);
|
||||
DenseVector v2 = DenseVector::Random(rows);
|
||||
DenseVector v3 = DenseVector::Random(rows);
|
||||
VERIFY_IS_APPROX(m3=m2*v1.asDiagonal(), refM3=refM2*v1.asDiagonal());
|
||||
VERIFY_IS_APPROX(m3=m2.transpose()*v2.asDiagonal(), refM3=refM2.transpose()*v2.asDiagonal());
|
||||
VERIFY_IS_APPROX(m3=v2.asDiagonal()*m2, refM3=v2.asDiagonal()*refM2);
|
||||
@ -248,6 +249,9 @@ template<typename SparseMatrixType> void sparse_product()
|
||||
|
||||
VERIFY_IS_APPROX(m3=v2.asDiagonal()*m2*v1.asDiagonal(), refM3=v2.asDiagonal()*refM2*v1.asDiagonal());
|
||||
|
||||
VERIFY_IS_APPROX(v2=m2*v1.asDiagonal()*v1, refM2*v1.asDiagonal()*v1);
|
||||
VERIFY_IS_APPROX(v3=v2.asDiagonal()*m2*v1, v2.asDiagonal()*refM2*v1);
|
||||
|
||||
// evaluate to a dense matrix to check the .row() and .col() iterator functions
|
||||
VERIFY_IS_APPROX(d3=m2*d1, refM3=refM2*d1);
|
||||
VERIFY_IS_APPROX(d3=m2.transpose()*d2, refM3=refM2.transpose()*d2);
|
||||
|
104
test/symbolic_index.cpp
Normal file
104
test/symbolic_index.cpp
Normal file
@ -0,0 +1,104 @@
|
||||
// This file is part of Eigen, a lightweight C++ template library
|
||||
// for linear algebra.
|
||||
//
|
||||
// Copyright (C) 2017 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/.
|
||||
|
||||
#ifdef EIGEN_TEST_PART_2
|
||||
#define EIGEN_MAX_CPP_VER 03
|
||||
#endif
|
||||
|
||||
#include "main.h"
|
||||
|
||||
template<typename T>
|
||||
bool match(const T& xpr, std::string ref, std::string str_xpr = "") {
|
||||
EIGEN_UNUSED_VARIABLE(str_xpr);
|
||||
std::stringstream str;
|
||||
str << xpr;
|
||||
if(!(str.str() == ref))
|
||||
std::cout << str_xpr << "\n" << xpr << "\n\n";
|
||||
return str.str() == ref;
|
||||
}
|
||||
|
||||
#define MATCH(X,R) match(X, R, #X)
|
||||
|
||||
template<typename T1,typename T2>
|
||||
typename internal::enable_if<internal::is_same<T1,T2>::value,bool>::type
|
||||
is_same_fixed(const T1& a, const T2& b)
|
||||
{
|
||||
return (Index(a) == Index(b));
|
||||
}
|
||||
|
||||
template<typename T1,typename T2>
|
||||
bool is_same_seq(const T1& a, const T2& b)
|
||||
{
|
||||
bool ok = a.first()==b.first() && a.size() == b.size() && Index(a.incrObject())==Index(b.incrObject());;
|
||||
if(!ok)
|
||||
{
|
||||
std::cerr << "seqN(" << a.first() << ", " << a.size() << ", " << Index(a.incrObject()) << ") != ";
|
||||
std::cerr << "seqN(" << b.first() << ", " << b.size() << ", " << Index(b.incrObject()) << ")\n";
|
||||
}
|
||||
return ok;
|
||||
}
|
||||
|
||||
template<typename T1,typename T2>
|
||||
typename internal::enable_if<internal::is_same<T1,T2>::value,bool>::type
|
||||
is_same_type(const T1&, const T2&)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
template<typename T1,typename T2>
|
||||
bool is_same_symb(const T1& a, const T2& b, Index size)
|
||||
{
|
||||
using Eigen::placeholders::last;
|
||||
return a.eval(last=size-1) == b.eval(last=size-1);
|
||||
}
|
||||
|
||||
|
||||
#define VERIFY_EQ_INT(A,B) VERIFY_IS_APPROX(int(A),int(B))
|
||||
|
||||
void check_symbolic_index()
|
||||
{
|
||||
using Eigen::placeholders::last;
|
||||
using Eigen::placeholders::end;
|
||||
|
||||
Index size=100;
|
||||
|
||||
// First, let's check FixedInt arithmetic:
|
||||
VERIFY( is_same_type( (fix<5>()-fix<3>())*fix<9>()/(-fix<3>()), fix<-(5-3)*9/3>() ) );
|
||||
VERIFY( is_same_type( (fix<5>()-fix<3>())*fix<9>()/fix<2>(), fix<(5-3)*9/2>() ) );
|
||||
VERIFY( is_same_type( fix<9>()/fix<2>(), fix<9/2>() ) );
|
||||
VERIFY( is_same_type( fix<9>()%fix<2>(), fix<9%2>() ) );
|
||||
VERIFY( is_same_type( fix<9>()&fix<2>(), fix<9&2>() ) );
|
||||
VERIFY( is_same_type( fix<9>()|fix<2>(), fix<9|2>() ) );
|
||||
VERIFY( is_same_type( fix<9>()/2, int(9/2) ) );
|
||||
|
||||
VERIFY( is_same_symb( end-1, last, size) );
|
||||
VERIFY( is_same_symb( end-fix<1>, last, size) );
|
||||
|
||||
VERIFY_IS_EQUAL( ( (last*5-2)/3 ).eval(last=size-1), ((size-1)*5-2)/3 );
|
||||
VERIFY_IS_EQUAL( ( (last*fix<5>-fix<2>)/fix<3> ).eval(last=size-1), ((size-1)*5-2)/3 );
|
||||
VERIFY_IS_EQUAL( ( -last*end ).eval(last=size-1), -(size-1)*size );
|
||||
VERIFY_IS_EQUAL( ( end-3*last ).eval(last=size-1), size- 3*(size-1) );
|
||||
VERIFY_IS_EQUAL( ( (end-3*last)/end ).eval(last=size-1), (size- 3*(size-1))/size );
|
||||
|
||||
#if EIGEN_HAS_CXX14
|
||||
{
|
||||
struct x_tag {}; static const Symbolic::SymbolExpr<x_tag> x;
|
||||
struct y_tag {}; static const Symbolic::SymbolExpr<y_tag> y;
|
||||
struct z_tag {}; static const Symbolic::SymbolExpr<z_tag> z;
|
||||
|
||||
VERIFY_IS_APPROX( int(((x+3)/y+z).eval(x=6,y=3,z=-13)), (6+3)/3+(-13) );
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void test_symbolic_index()
|
||||
{
|
||||
CALL_SUBTEST_1( check_symbolic_index() );
|
||||
CALL_SUBTEST_2( check_symbolic_index() );
|
||||
}
|
@ -1,7 +1,9 @@
|
||||
add_subdirectory(Eigen)
|
||||
add_subdirectory(doc EXCLUDE_FROM_ALL)
|
||||
if(EIGEN_LEAVE_TEST_IN_ALL_TARGET)
|
||||
if(BUILD_TESTING)
|
||||
if(EIGEN_LEAVE_TEST_IN_ALL_TARGET)
|
||||
add_subdirectory(test) # can't do EXCLUDE_FROM_ALL here, breaks CTest
|
||||
else()
|
||||
else()
|
||||
add_subdirectory(test EXCLUDE_FROM_ALL)
|
||||
endif()
|
||||
endif()
|
||||
|
@ -71,6 +71,10 @@ typedef unsigned __int64 uint64_t;
|
||||
#include <time.h>
|
||||
#endif
|
||||
|
||||
#if defined(EIGEN_USE_LIBXSMM)
|
||||
#include "libxsmm.h"
|
||||
#endif
|
||||
|
||||
#ifdef EIGEN_USE_THREADS
|
||||
#include "ThreadPool"
|
||||
#endif
|
||||
|
@ -20,6 +20,70 @@ namespace Eigen {
|
||||
*
|
||||
*/
|
||||
namespace internal {
|
||||
#if defined(EIGEN_VECTORIZE_AVX) && defined(EIGEN_USE_LIBXSMM)
|
||||
template<typename Scalar, typename Index>
|
||||
void pack_simple(Scalar * dst, const Scalar * src, Index cols, Index rows, Index lddst, Index ldsrc) {
|
||||
size_t psize = packet_traits<Scalar>::size; // Packet size
|
||||
typedef typename packet_traits<Scalar>::type Packet; // Packet type
|
||||
size_t alignment = psize*sizeof(Scalar); // Needed alignment
|
||||
if (rows % psize == 0 && (lddst*sizeof(Scalar)) % alignment == 0 &&
|
||||
(ldsrc*sizeof(Scalar)) % alignment == 0 &&
|
||||
reinterpret_cast<uintptr_t>(src) % alignment == 0 &&
|
||||
reinterpret_cast<uintptr_t>(dst) % alignment == 0) {
|
||||
// Optimized version using packets
|
||||
size_t num_packets = rows / psize;
|
||||
for (Index col = 0; col < cols; ++col) {
|
||||
EIGEN_ASM_COMMENT("begin pack_simple inner copy");
|
||||
// Unrolled manually 4 times.
|
||||
for (size_t i=0; i < num_packets/4; ++i) {
|
||||
internal::pstore(dst, internal::pload<Packet>(src));
|
||||
dst += psize; src += psize;
|
||||
internal::pstore(dst, internal::pload<Packet>(src));
|
||||
dst += psize; src += psize;
|
||||
internal::pstore(dst, internal::pload<Packet>(src));
|
||||
dst += psize; src += psize;
|
||||
internal::pstore(dst, internal::pload<Packet>(src));
|
||||
dst += psize; src += psize;
|
||||
}
|
||||
for (size_t i=0; i < num_packets%4; ++i) {
|
||||
internal::pstore(dst, internal::pload<Packet>(src));
|
||||
dst += psize; src += psize;
|
||||
}
|
||||
dst += lddst - num_packets*psize;
|
||||
src += ldsrc - num_packets*psize;
|
||||
EIGEN_ASM_COMMENT("end pack_simple inner copy");
|
||||
}
|
||||
} else {
|
||||
// Naive memcpy calls
|
||||
for (Index col = 0; col < cols; ++col) {
|
||||
memcpy(dst + col*lddst, src + col*ldsrc, rows*sizeof(Scalar));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template<typename LhsScalar, typename RhsScalar, typename Scalar>
|
||||
struct libxsmm_wrapper {
|
||||
libxsmm_wrapper() {}
|
||||
libxsmm_wrapper(int flags, int m, int n, int k, int lda, int ldb, int ldc, float alpha, float beta, int prefetch) {}
|
||||
void operator()(const LhsScalar* a, const RhsScalar* b, Scalar* c) {}
|
||||
void operator()(const LhsScalar* a, const RhsScalar* b, Scalar* c, const LhsScalar* ap, const RhsScalar* bp, const Scalar* cp) {}
|
||||
};
|
||||
|
||||
template<>
|
||||
struct libxsmm_wrapper<float, float, float>: public libxsmm_mmfunction<float> {
|
||||
libxsmm_wrapper(): libxsmm_mmfunction() {}
|
||||
libxsmm_wrapper(int flags, int m, int n, int k, int lda, int ldb, int ldc, float alpha, float beta, int prefetch) :
|
||||
libxsmm_mmfunction(flags, m, n, k, lda, ldb, ldc, alpha, beta, prefetch) {}
|
||||
};
|
||||
|
||||
template<>
|
||||
struct libxsmm_wrapper<double, double, double>: public libxsmm_mmfunction<double> {
|
||||
libxsmm_wrapper(): libxsmm_mmfunction() {}
|
||||
libxsmm_wrapper(int flags, int m, int n, int k, int lda, int ldb, int ldc, float alpha, float beta, int prefetch) :
|
||||
libxsmm_mmfunction(flags, m, n, k, lda, ldb, ldc, alpha, beta, prefetch) {}
|
||||
};
|
||||
#endif
|
||||
|
||||
|
||||
template<typename Dimensions, typename LhsXprType, typename RhsXprType>
|
||||
struct traits<TensorContractionOp<Dimensions, LhsXprType, RhsXprType> >
|
||||
@ -317,6 +381,8 @@ struct TensorContractionEvaluatorBase
|
||||
}
|
||||
}
|
||||
|
||||
EnableXSMMIfPossible(eval_op_indices);
|
||||
|
||||
// If the layout is RowMajor, we need to reverse the m_dimensions
|
||||
if (static_cast<int>(Layout) == static_cast<int>(RowMajor)) {
|
||||
for (int i = 0, j = NumDims - 1; i < j; i++, j--) {
|
||||
@ -422,6 +488,13 @@ struct TensorContractionEvaluatorBase
|
||||
|
||||
template <bool lhs_inner_dim_contiguous, bool rhs_inner_dim_contiguous, bool rhs_inner_dim_reordered, int Alignment>
|
||||
EIGEN_DEVICE_FUNC void evalGemm(Scalar* buffer) const {
|
||||
#if defined(EIGEN_VECTORIZE_AVX) && defined(EIGEN_USE_LIBXSMM)
|
||||
if (m_can_use_xsmm) {
|
||||
evalGemmXSMM(buffer);
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
// columns in left side, rows in right side
|
||||
const Index k = this->m_k_size;
|
||||
|
||||
@ -538,7 +611,212 @@ struct TensorContractionEvaluatorBase
|
||||
|
||||
EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Scalar* data() const { return m_result; }
|
||||
|
||||
protected:
|
||||
protected:
|
||||
EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void EnableXSMMIfPossible(const array<IndexPair<Index>, ContractDims>& eval_op_indices) {
|
||||
m_can_use_xsmm = false;
|
||||
|
||||
#if defined(EIGEN_VECTORIZE_AVX) && defined(EIGEN_USE_LIBXSMM)
|
||||
typedef typename internal::remove_const<typename EvalLeftArgType::Scalar>::type LhsScalar;
|
||||
typedef typename internal::remove_const<typename EvalRightArgType::Scalar>::type RhsScalar;
|
||||
if (!std::is_same<Scalar, LhsScalar>::value ||
|
||||
!std::is_same<Scalar, RhsScalar>::value ||
|
||||
!(std::is_same<Scalar, float>::value ||
|
||||
std::is_same<Scalar, double>::value) ||
|
||||
m_leftImpl.data() == NULL ||
|
||||
m_rightImpl.data() == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Check if we can use faster matmul algorithms. For contraction to be
|
||||
// equivalent to matmul, we need both lhs and rhs contracting dims sequences
|
||||
// to be either a prefix or suffix of all dims. Also, the order of both
|
||||
// must be the same, so we don't have to do reordering.
|
||||
// For example:
|
||||
// * OK: lhs 4D, rhs 4D, contraction: [(0, 2), (1, 3)]
|
||||
// * BAD: lhs 3D, rhs 3D, contraction: [(1,1)]
|
||||
// * BAD: lhs 3D, rhs 3D, contraction: [(0, 0), (2, 2)]
|
||||
// * BAD: lhs 3D, rhs 3D, contraction: [(0, 2), (1, 1)]
|
||||
// Depending if contraction dims are prefix or suffix of all dims we need to
|
||||
// pre-transpose matrices in matmul algorithm:
|
||||
// lhs: prefix -> transpose, suffix -> no transpose
|
||||
// rhs: prefix -> no transpose, suffix -> transpose
|
||||
// For example, for lhs 2D, rhs 2D, contraction [(1, 0)] is regular,
|
||||
// non-transposed matmul.
|
||||
if (ContractDims == 0) {
|
||||
// This case is totally uninteresting, filter it out to avoid problems
|
||||
// with iterations in further tests.
|
||||
return;
|
||||
}
|
||||
|
||||
// Check if RHS dims list is increasing. LHS already is, so if not, the
|
||||
// order is different and we cannot do matmul.
|
||||
for (int i = 1; i < ContractDims; i++) {
|
||||
if (eval_op_indices[i].second < eval_op_indices[i-1].second) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Check if no holes.
|
||||
int diff;
|
||||
for (int i = 1; i < ContractDims; i++) {
|
||||
// LHS contract dims are sorted to form an increasing seq.
|
||||
diff = eval_op_indices[i].first - eval_op_indices[i-1].first;
|
||||
if (diff != 1) {
|
||||
return;
|
||||
}
|
||||
// Now we may already assume RHS contract dims seq is increasing too.
|
||||
diff = eval_op_indices[i].second - eval_op_indices[i-1].second;
|
||||
if (diff != 1) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Check if suffix or prefix.
|
||||
if (eval_op_indices[0].first != 0 &&
|
||||
eval_op_indices[ContractDims-1].first != LDims-1) {
|
||||
return;
|
||||
}
|
||||
if (eval_op_indices[0].second != 0 &&
|
||||
eval_op_indices[ContractDims-1].second != RDims-1) {
|
||||
return;
|
||||
}
|
||||
|
||||
m_can_use_xsmm = true;
|
||||
#endif
|
||||
}
|
||||
|
||||
#if defined(EIGEN_VECTORIZE_AVX) && defined(EIGEN_USE_LIBXSMM)
|
||||
EIGEN_DEVICE_FUNC void evalGemmXSMM(Scalar* buffer) const {
|
||||
// columns in left side, rows in right side
|
||||
const Index k = this->m_k_size;
|
||||
|
||||
// rows in left side
|
||||
const Index m = this->m_i_size;
|
||||
|
||||
// columns in right side
|
||||
const Index n = this->m_j_size;
|
||||
|
||||
const bool transposeA = !m_lhs_inner_dim_contiguous;
|
||||
const bool transposeB = !m_rhs_inner_dim_contiguous;
|
||||
|
||||
typedef typename internal::remove_const<typename EvalLeftArgType::Scalar>::type LhsScalar;
|
||||
typedef typename internal::remove_const<typename EvalRightArgType::Scalar>::type RhsScalar;
|
||||
|
||||
internal::TensorXsmmContractionBlocking<LhsScalar, RhsScalar, Index> blocking(
|
||||
k, m, n, 1, transposeA, transposeB);
|
||||
|
||||
// Outer blocks sizes
|
||||
const Index mc_outer = blocking.outer_m();
|
||||
const Index nc_outer = blocking.outer_n();
|
||||
const Index kc_outer = blocking.outer_k();
|
||||
// Inner blocks sizes
|
||||
const Index mc = blocking.mc();
|
||||
const Index nc = blocking.nc();
|
||||
const Index kc = blocking.kc();
|
||||
// Decisions whether we should copy parts of matrices
|
||||
const bool copyA = blocking.copyA();
|
||||
const bool copyB = blocking.copyB();
|
||||
|
||||
const LhsScalar* leftData = m_leftImpl.data();
|
||||
const RhsScalar* rightData = m_rightImpl.data();
|
||||
|
||||
const libxsmm_blasint stride_A = static_cast<libxsmm_blasint>(transposeA ? k : m);
|
||||
const libxsmm_blasint stride_B = static_cast<libxsmm_blasint>(transposeB ? n : k);
|
||||
const libxsmm_blasint stride_C = static_cast<libxsmm_blasint>(m);
|
||||
|
||||
const libxsmm_blasint stride_blockA = static_cast<libxsmm_blasint>(mc);
|
||||
// Use bigger stride to avoid hitting same cache line too often.
|
||||
// This consistently gives +~0.5 Gflops.
|
||||
const libxsmm_blasint stride_panelB = static_cast<libxsmm_blasint>(
|
||||
kc % 32 == 0 ? kc + 16 : kc
|
||||
);
|
||||
|
||||
// Kernel for the general case (not edges)
|
||||
internal::libxsmm_wrapper<LhsScalar, RhsScalar, Scalar> kernel;
|
||||
|
||||
LhsScalar* blockA = NULL;
|
||||
RhsScalar* panelB = NULL;
|
||||
|
||||
if (copyA) {
|
||||
blockA = static_cast<LhsScalar*>(this->m_device.allocate(mc * kc * sizeof(LhsScalar)));
|
||||
}
|
||||
if (copyB) {
|
||||
panelB = static_cast<RhsScalar*>(this->m_device.allocate(nc_outer * stride_panelB * sizeof(RhsScalar)));
|
||||
}
|
||||
|
||||
const Index kernel_stride_A = copyA ? stride_blockA : stride_A;
|
||||
const Index kernel_stride_B = copyB ? stride_panelB : stride_B;
|
||||
kernel = internal::libxsmm_wrapper<LhsScalar, RhsScalar, Scalar>(0, mc, nc, kc, kernel_stride_A, kernel_stride_B, stride_C, 1, 1, blocking.prefetch());
|
||||
|
||||
// Outer blocking
|
||||
for (Index ki_outer = 0; ki_outer < k; ki_outer += kc_outer) {
|
||||
for (Index mi_outer = 0; mi_outer < m; mi_outer += mc_outer) {
|
||||
for (Index ni_outer = 0; ni_outer < n; ni_outer += nc_outer) {
|
||||
using numext::mini;
|
||||
|
||||
Index actual_nc_outer = mini(ni_outer+nc_outer, n) - ni_outer;
|
||||
|
||||
// Inner blocking
|
||||
for (Index ki = ki_outer; ki < mini(ki_outer+kc_outer, k); ki += kc) {
|
||||
const Index actual_kc = mini(ki_outer+kc_outer, mini(ki+kc, k)) - ki;
|
||||
const float beta = ki == 0 ? 0 : 1;
|
||||
|
||||
if (copyB) {
|
||||
if (transposeB) {
|
||||
libxsmm_otrans(panelB, rightData + ki*stride_B + ni_outer, sizeof(RhsScalar), actual_nc_outer, actual_kc, stride_B, stride_panelB);
|
||||
} else {
|
||||
internal::pack_simple<RhsScalar, Index>(panelB, rightData + ni_outer*stride_B + ki, actual_nc_outer, actual_kc, stride_panelB, stride_B);
|
||||
}
|
||||
}
|
||||
|
||||
for (Index mi = mi_outer; mi < mini(mi_outer+mc_outer, m); mi += mc) {
|
||||
const Index actual_mc = mini(mi_outer+mc_outer, mini(mi+mc, m)) - mi;
|
||||
|
||||
const LhsScalar* a = transposeA ? leftData + mi*stride_A + ki :
|
||||
leftData + ki*stride_A + mi;
|
||||
|
||||
if (copyA) {
|
||||
if (transposeA) {
|
||||
libxsmm_otrans(blockA, a, sizeof(LhsScalar), actual_kc, actual_mc, stride_A, stride_blockA);
|
||||
} else {
|
||||
internal::pack_simple<LhsScalar, Index>(blockA, a, actual_kc, actual_mc, stride_blockA, stride_A);
|
||||
}
|
||||
}
|
||||
const LhsScalar* actual_a = copyA ? blockA : a;
|
||||
|
||||
for (Index ni = ni_outer; ni < mini(ni_outer+nc_outer, n); ni += nc) {
|
||||
const Index actual_nc = mini(ni_outer+nc_outer, mini(ni+nc, n)) - ni;
|
||||
|
||||
const RhsScalar* b = rightData + ni*stride_B + ki;
|
||||
Scalar* c = buffer + ni*stride_C + mi;
|
||||
const Scalar* cp = c + nc*stride_C;
|
||||
|
||||
const RhsScalar* actual_b = copyB ? panelB + (ni-ni_outer)*stride_panelB : b;
|
||||
const RhsScalar* bp = copyB ? panelB + nc*stride_panelB : b + nc*stride_B;
|
||||
|
||||
if (actual_mc == mc && actual_kc == kc && actual_nc == nc && beta == 1) {
|
||||
// Most used, cached kernel.
|
||||
kernel(actual_a, actual_b, c, actual_a, bp, cp);
|
||||
} else {
|
||||
// Edges - use libxsmm kernel cache.
|
||||
internal::libxsmm_wrapper<LhsScalar, RhsScalar, Scalar>(0, actual_mc, actual_nc, actual_kc, kernel_stride_A, kernel_stride_B, stride_C, 1, beta, blocking.prefetch())(actual_a, actual_b, c, actual_a, bp, cp);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (copyA) {
|
||||
this->m_device.deallocate(blockA);
|
||||
}
|
||||
if (copyB) {
|
||||
this->m_device.deallocate(panelB);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
// Prevent assignment
|
||||
TensorContractionEvaluatorBase& operator = (const TensorContractionEvaluatorBase&);
|
||||
Dimensions m_dimensions;
|
||||
@ -564,6 +842,11 @@ struct TensorContractionEvaluatorBase
|
||||
TensorEvaluator<EvalRightArgType, Device> m_rightImpl;
|
||||
const Device& m_device;
|
||||
Scalar* m_result;
|
||||
|
||||
/// required for sycl
|
||||
const Indices m_expr_indices;
|
||||
|
||||
bool m_can_use_xsmm;
|
||||
};
|
||||
|
||||
|
||||
@ -621,7 +904,6 @@ struct TensorEvaluator<const TensorContractionOp<Indices, LeftArgType, RightArgT
|
||||
|
||||
this->template evalGemm<lhs_inner_dim_contiguous, rhs_inner_dim_contiguous, rhs_inner_dim_reordered, Alignment>(buffer);
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
} // end namespace Eigen
|
||||
|
@ -50,6 +50,140 @@ class TensorContractionBlocking {
|
||||
};
|
||||
|
||||
|
||||
|
||||
#if defined(EIGEN_USE_LIBXSMM)
|
||||
template <typename LhsScalar, typename RhsScalar, typename Index>
|
||||
class TensorXsmmContractionBlocking {
|
||||
public:
|
||||
TensorXsmmContractionBlocking(Index k, Index m, Index n,
|
||||
size_t max_num_threads = 1, bool transposeA = false,
|
||||
bool transposeB = false):
|
||||
k_(k), m_(m), n_(n), transposeA_(transposeA),
|
||||
transposeB_(transposeB), num_threads_(max_num_threads) {
|
||||
#ifdef EIGEN_TEST_SPECIFIC_BLOCKING_SIZES
|
||||
if (EIGEN_TEST_SPECIFIC_BLOCKING_SIZES) {
|
||||
mc_ = EIGEN_TEST_SPECIFIC_BLOCKING_SIZE_M;
|
||||
kc_ = EIGEN_TEST_SPECIFIC_BLOCKING_SIZE_K;
|
||||
nc_ = EIGEN_TEST_SPECIFIC_BLOCKING_SIZE_N;
|
||||
outer_m_ = EIGEN_TEST_SPECIFIC_OUTER_BLOCKING_SIZE_M;
|
||||
outer_k_ = EIGEN_TEST_SPECIFIC_OUTER_BLOCKING_SIZE_K;
|
||||
outer_n_ = EIGEN_TEST_SPECIFIC_OUTER_BLOCKING_SIZE_N;
|
||||
copyA_ = EIGEN_TEST_SPECIFIC_BLOCKING_COPY_A;
|
||||
copyB_ = EIGEN_TEST_SPECIFIC_BLOCKING_COPY_B;
|
||||
outer_m_ = outer_m_ != 0 ? outer_m_ : m;
|
||||
outer_k_ = outer_k_ != 0 ? outer_k_ : k;
|
||||
outer_n_ = outer_n_ != 0 ? outer_n_ : n;
|
||||
}
|
||||
#else
|
||||
// Defaults, possibly overriden per-platform.
|
||||
copyA_ = true;
|
||||
copyB_ = false;
|
||||
|
||||
// If the matrix is small enough, don't do blocking, just call single xsmm
|
||||
// kernel.
|
||||
if (static_cast<double>(m)*k*n <= LIBXSMM_THRESHOLD) {
|
||||
mc_ = m; kc_ = k; nc_ = n;
|
||||
outer_m_ = m; outer_k_ = k; outer_n_ = n;
|
||||
copyA_ = false; copyB_ = false;
|
||||
} else {
|
||||
int arch = libxsmm_cpuid_x86();
|
||||
|
||||
if (arch == LIBXSMM_X86_AVX512_CORE) {
|
||||
// skylake
|
||||
mc_ = 64; kc_ = 64; nc_ = 24;
|
||||
outer_m_ = 512; outer_k_ = 512; outer_n_ = 24*22;
|
||||
// Hack to use this kernel architecture as the other one has performance
|
||||
// issues (no hardware prefetching).
|
||||
// TODO(nishantpatil): This should be removed if the issues are fixed,
|
||||
// or this one becomes the default.
|
||||
setenv("LIBXSMM_AVX512_CLASSIC_GEMM", "1", 1);
|
||||
} else if (arch == LIBXSMM_X86_AVX2) {
|
||||
// haswell
|
||||
mc_ = 32; kc_ = 192; nc_ = 33;
|
||||
outer_m_ = 512; outer_k_ = 3*192; outer_n_ = 33*16;
|
||||
} else if (arch == LIBXSMM_X86_AVX) {
|
||||
// ivybridge
|
||||
mc_ = 32; kc_ = 192; nc_ = 48;
|
||||
outer_m_ = 512; outer_k_ = 3*192; outer_n_ = 48*11;
|
||||
} else {
|
||||
// generic kernel size, usually performing well
|
||||
mc_ = 32; kc_ = 128; nc_ = 32;
|
||||
outer_m_ = 512; outer_k_ = 512; outer_n_ = 512;
|
||||
}
|
||||
|
||||
// Only copy if it makes the stride smaller.
|
||||
copyA_ = copyA_ && (m > mc_);
|
||||
copyB_ = copyB_ && (k > kc_);
|
||||
}
|
||||
|
||||
// We need to copy anyway if transposing
|
||||
copyA_ = copyA_ || transposeA;
|
||||
copyB_ = copyB_ || transposeB;
|
||||
|
||||
// See libxsmm_gemm_prefetch_type definition in libxsmm_typedefs.h
|
||||
prefetch_ = LIBXSMM_PREFETCH_AL2CL2BL2_VIA_C;
|
||||
|
||||
#endif
|
||||
|
||||
mc_ = mc_ > m ? m : mc_;
|
||||
nc_ = nc_ > n ? n : nc_;
|
||||
kc_ = kc_ > k ? k : kc_;
|
||||
|
||||
size_t compute_parallelism = (m / mc_) * (n / nc_);
|
||||
size_t pack_parallelism = 0;
|
||||
if (copyA_) {
|
||||
pack_parallelism += (m / mc_) * (k / kc_);
|
||||
}
|
||||
if (copyB_) {
|
||||
pack_parallelism += (n / nc_) * (k / kc_);
|
||||
}
|
||||
size_t parallelism = numext::maxi(compute_parallelism, pack_parallelism);
|
||||
|
||||
num_threads_ = numext::mini<size_t>(num_threads_,
|
||||
parallelism / MIN_JOBS_PER_THREAD);
|
||||
num_threads_ = numext::maxi<size_t>(num_threads_, 1);
|
||||
|
||||
// For optimal performance outer block sizes should be multiplies of kernel
|
||||
// sizes, or bigger than matrix size (=no outer blocking).
|
||||
eigen_assert(outer_m_ % mc_ == 0 || outer_m_ >= m);
|
||||
eigen_assert(outer_k_ % kc_ == 0 || outer_k_ >= k);
|
||||
eigen_assert(outer_n_ % nc_ == 0 || outer_n_ >= n);
|
||||
}
|
||||
|
||||
EIGEN_ALWAYS_INLINE Index kc() const { return kc_; }
|
||||
EIGEN_ALWAYS_INLINE Index mc() const { return mc_; }
|
||||
EIGEN_ALWAYS_INLINE Index nc() const { return nc_; }
|
||||
EIGEN_ALWAYS_INLINE Index outer_k() const { return outer_k_; }
|
||||
EIGEN_ALWAYS_INLINE Index outer_m() const { return outer_m_; }
|
||||
EIGEN_ALWAYS_INLINE Index outer_n() const { return outer_n_; }
|
||||
EIGEN_ALWAYS_INLINE bool copyA() const { return copyA_; }
|
||||
EIGEN_ALWAYS_INLINE bool copyB() const { return copyB_; }
|
||||
EIGEN_ALWAYS_INLINE bool transposeA() const { return transposeA_; }
|
||||
EIGEN_ALWAYS_INLINE bool transposeB() const { return transposeB_; }
|
||||
EIGEN_ALWAYS_INLINE int num_threads() const { return num_threads_; }
|
||||
EIGEN_ALWAYS_INLINE Index blocks_m() const { return divup(m_, mc_); }
|
||||
EIGEN_ALWAYS_INLINE Index blocks_k() const { return divup(k_, kc_); }
|
||||
EIGEN_ALWAYS_INLINE Index blocks_n() const { return divup(n_, nc_); }
|
||||
EIGEN_ALWAYS_INLINE libxsmm_gemm_prefetch_type prefetch() const {
|
||||
return prefetch_;
|
||||
}
|
||||
|
||||
private:
|
||||
Index k_, m_, n_;
|
||||
Index kc_, mc_, nc_;
|
||||
Index outer_k_, outer_m_, outer_n_;
|
||||
bool copyA_, copyB_, transposeA_, transposeB_;
|
||||
size_t num_threads_;
|
||||
|
||||
// Threshold for m*k*n to skip blocking and just call libxsmm
|
||||
const double LIBXSMM_THRESHOLD = 80*80*80;
|
||||
// For computing optimal number of threads - so that each thread gets at least
|
||||
// that many jobs.
|
||||
const double MIN_JOBS_PER_THREAD = 3;
|
||||
libxsmm_gemm_prefetch_type prefetch_;
|
||||
};
|
||||
#endif // EIGEN_USE_LIBXSMM
|
||||
|
||||
} // end namespace internal
|
||||
} // end namespace Eigen
|
||||
|
||||
|
@ -116,6 +116,28 @@ struct TensorEvaluator<const TensorContractionOp<Indices, LeftArgType, RightArgT
|
||||
template <bool lhs_inner_dim_contiguous, bool rhs_inner_dim_contiguous,
|
||||
bool rhs_inner_dim_reordered, int Alignment>
|
||||
void evalProduct(Scalar* buffer) const {
|
||||
const Index m = this->m_i_size;
|
||||
const Index n = this->m_j_size;
|
||||
const Index k = this->m_k_size;
|
||||
if (m == 0 || n == 0 || k == 0) return;
|
||||
|
||||
#if defined(EIGEN_VECTORIZE_AVX) && defined(EIGEN_USE_LIBXSMM)
|
||||
if (this->m_can_use_xsmm) {
|
||||
bool transposeA = !this->m_lhs_inner_dim_contiguous;
|
||||
bool transposeB = !this->m_rhs_inner_dim_contiguous;
|
||||
internal::TensorXsmmContractionBlocking<LhsScalar, RhsScalar, Index>
|
||||
blocking(k, m, n, this->m_device.numThreads(), transposeA,
|
||||
transposeB);
|
||||
|
||||
if (blocking.num_threads() == 1) {
|
||||
this->evalGemmXSMM(buffer);
|
||||
} else {
|
||||
ContextXsmm<Alignment>(this, buffer, m, n, k, blocking).run();
|
||||
}
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
typedef
|
||||
typename internal::remove_const<typename EvalLeftArgType::Scalar>::type
|
||||
LhsScalar;
|
||||
@ -147,10 +169,7 @@ struct TensorEvaluator<const TensorContractionOp<Indices, LeftArgType, RightArgT
|
||||
Traits::mr, Traits::nr, false, false>
|
||||
GebpKernel;
|
||||
|
||||
const Index m = this->m_i_size;
|
||||
const Index n = this->m_j_size;
|
||||
const Index k = this->m_k_size;
|
||||
if (m == 0 || n == 0 || k == 0) return;
|
||||
|
||||
|
||||
// Compute a set of algorithm parameters:
|
||||
// - kernel block sizes (bm, bn, bk)
|
||||
@ -1044,6 +1063,187 @@ struct TensorEvaluator<const TensorContractionOp<Indices, LeftArgType, RightArgT
|
||||
rhsCost.dropMemoryCost();
|
||||
return cost + lhsCost + rhsCost;
|
||||
}
|
||||
|
||||
#if defined(EIGEN_VECTORIZE_AVX) && defined(EIGEN_USE_LIBXSMM)
|
||||
template<int Alignment>
|
||||
class ContextXsmm {
|
||||
public:
|
||||
ContextXsmm(const Self* self, Scalar* buffer, Index m, Index n, Index k,
|
||||
const internal::TensorXsmmContractionBlocking<LhsScalar,
|
||||
RhsScalar, Index>& blocking):
|
||||
device(self->m_device),
|
||||
m(m), k(k), n(n),
|
||||
stride_a(blocking.transposeA() ? k : m),
|
||||
stride_b(blocking.transposeB() ? n : k),
|
||||
stride_c(m),
|
||||
bm(blocking.mc()), bk(blocking.kc()), bn(blocking.nc()),
|
||||
blocks_m(blocking.blocks_m()), blocks_k(blocking.blocks_k()),
|
||||
blocks_n(blocking.blocks_n()),
|
||||
copyA(blocking.copyA()), copyB(blocking.copyB()),
|
||||
transposeA(blocking.transposeA()), transposeB(blocking.transposeB()),
|
||||
num_threads(blocking.num_threads()),
|
||||
buffer(buffer),
|
||||
leftData(self->m_leftImpl.data()), rightData(self->m_rightImpl.data()),
|
||||
workers_done(blocking.num_threads()),
|
||||
|
||||
packingA_jobs(0), packingB_jobs(0), compute_jobs(0),
|
||||
packingA_done(blocking.blocks_m()), packingB_done(blocking.blocks_n()) {}
|
||||
|
||||
void worker() {
|
||||
// Pack
|
||||
|
||||
if (copyA) {
|
||||
while (true) {
|
||||
uint32_t mk = packingA_jobs++;
|
||||
Index mi = mk / blocks_k;
|
||||
Index ki = mk % blocks_k;
|
||||
if (mi >= blocks_m) break;
|
||||
|
||||
LhsScalar * blockA = blocksA + (bk*bm) * (mi*blocks_k+ki);
|
||||
if (transposeA) {
|
||||
const LhsScalar * current_a = leftData + (bm*mi)*stride_a + (bk*ki);
|
||||
libxsmm_otrans(blockA, current_a, sizeof(LhsScalar), actual_bk(ki),
|
||||
actual_bm(mi), stride_a, bm);
|
||||
} else {
|
||||
const LhsScalar * current_a = leftData + (bk*ki)*stride_a + (bm*mi);
|
||||
internal::pack_simple<LhsScalar, Index>(blockA, current_a,
|
||||
actual_bk(ki), actual_bm(mi), bm, stride_a);
|
||||
}
|
||||
packingA_done.at(mi)++;
|
||||
}
|
||||
}
|
||||
|
||||
if (copyB) {
|
||||
while (true) {
|
||||
uint32_t nk = packingB_jobs++;
|
||||
Index ni = nk / blocks_k;
|
||||
Index ki = nk % blocks_k;
|
||||
if (ni >= blocks_n) break;
|
||||
|
||||
RhsScalar * blockB = blocksB + (bk*bn) * (ni*blocks_k+ki);
|
||||
if (transposeB) {
|
||||
const RhsScalar * current_b = rightData + (ki*bk)*stride_b +
|
||||
(ni*bn);
|
||||
libxsmm_otrans(blockB, current_b, sizeof(RhsScalar), actual_bn(ni),
|
||||
actual_bk(ki), stride_b, bk);
|
||||
} else {
|
||||
const RhsScalar * current_b = rightData + (ni*bn)*stride_b +
|
||||
(ki*bk);
|
||||
internal::pack_simple<RhsScalar, Index>(blockB, current_b,
|
||||
actual_bn(ni), actual_bk(ki), bk, stride_b);
|
||||
}
|
||||
packingB_done.at(ni)++;
|
||||
}
|
||||
}
|
||||
|
||||
// Compute
|
||||
|
||||
while (true) {
|
||||
uint32_t mn = compute_jobs++;
|
||||
Index mi = mn / blocks_n;
|
||||
Index ni = mn % blocks_n;
|
||||
if (mi >= blocks_m) break;
|
||||
|
||||
// Wait for mi, ni packings to be done. This is more fine-grained than
|
||||
// waiting for all workers to finish packing.
|
||||
while ((copyA && (packingA_done.at(mi) < blocks_k)) ||
|
||||
(copyB && (packingB_done.at(ni) < blocks_k)))
|
||||
{}
|
||||
|
||||
for (Index ki=0; ki < blocks_k; ++ki) {
|
||||
const LhsScalar * current_a = copyA ?
|
||||
blocksA + (bk*bm) * (mi*blocks_k+ki) :
|
||||
leftData + (bk*ki)*stride_a + (bm*mi);
|
||||
const RhsScalar * current_b = copyB ?
|
||||
blocksB + (bk*bn) * (ni*blocks_k+ki) :
|
||||
rightData + (ni*bn)*stride_b + (bk*ki);
|
||||
|
||||
Index current_stride_a = copyA ? bm : stride_a;
|
||||
Index current_stride_b = copyB ? bk : stride_b;
|
||||
|
||||
// Memory may not be zeroed, overwrite instead of adding in first
|
||||
// iteration.
|
||||
float beta = ki == 0 ? 0 : 1;
|
||||
|
||||
Scalar * current_c = buffer + (mi*bm) + (ni*bn)*stride_c;
|
||||
internal::libxsmm_wrapper<LhsScalar, RhsScalar, Scalar>(
|
||||
0, actual_bm(mi), actual_bn(ni), actual_bk(ki),
|
||||
current_stride_a, current_stride_b, stride_c, 1, beta, 0)
|
||||
(current_a, current_b, current_c);
|
||||
}
|
||||
}
|
||||
|
||||
workers_done.Notify();
|
||||
}
|
||||
|
||||
void run() {
|
||||
// Parallelization strategy.
|
||||
//
|
||||
// First pack A into blocks (sharding by m, k) and B (sharding by n,k),
|
||||
// then shard by m, n.
|
||||
//
|
||||
// Do not use advanced ThreadPool queuing, just run a single long-standing
|
||||
// function in each thread.
|
||||
if (copyA) {
|
||||
blocksA = static_cast<LhsScalar*>(device.allocate(
|
||||
(blocks_m*bm)*(blocks_k*bk)*sizeof(LhsScalar)));
|
||||
}
|
||||
if (copyB) {
|
||||
blocksB = static_cast<RhsScalar*>(device.allocate(
|
||||
(blocks_n*bn)*(blocks_k*bk)*sizeof(RhsScalar)));
|
||||
}
|
||||
|
||||
for (Index i = 0; i < num_threads; ++i) {
|
||||
device.enqueueNoNotification([=]() { worker(); });
|
||||
}
|
||||
|
||||
workers_done.Wait();
|
||||
|
||||
if (copyA) {
|
||||
device.deallocate(blocksA);
|
||||
}
|
||||
if (copyB) {
|
||||
device.deallocate(blocksB);
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
// real block size for block index in [0, ..., blocks - 1].
|
||||
Index actual_bm(Index mi) const {
|
||||
return mi != blocks_m - 1 ? bm : m + bm - bm * blocks_m;
|
||||
}
|
||||
Index actual_bk(Index ki) const {
|
||||
return ki != blocks_k - 1 ? bk : k + bk - bk * blocks_k;
|
||||
}
|
||||
Index actual_bn(Index ni) const {
|
||||
return ni != blocks_n - 1 ? bn : n + bn - bn * blocks_n;
|
||||
}
|
||||
|
||||
const Device& device;
|
||||
Index m, k, n;
|
||||
Index stride_a, stride_b, stride_c;
|
||||
Index bm, bk, bn; // Block sizes.
|
||||
Index blocks_m, blocks_k, blocks_n; // Number of blocks in each dimension.
|
||||
bool copyA, copyB, transposeA, transposeB;
|
||||
Index num_threads;
|
||||
Scalar *buffer;
|
||||
const LhsScalar *leftData;
|
||||
const RhsScalar *rightData;
|
||||
|
||||
LhsScalar *blocksA;
|
||||
RhsScalar *blocksB;
|
||||
// barrier for joining all threads after all done.
|
||||
Barrier workers_done;
|
||||
// "queues" of (mi,ki), (ki,ni), (mi,ni) jobs packed [0,p)x[0,q) -> [0, p*q)
|
||||
std::atomic<uint32_t> packingA_jobs;
|
||||
std::atomic<uint32_t> packingB_jobs;
|
||||
std::atomic<uint32_t> compute_jobs;
|
||||
// already packed blocks for each mi-panel in A and ni-panel in B.
|
||||
std::vector<std::atomic<uint8_t>> packingA_done;
|
||||
std::vector<std::atomic<uint8_t>> packingB_done;
|
||||
};
|
||||
#endif
|
||||
|
||||
};
|
||||
|
||||
} // end namespace Eigen
|
||||
|
@ -253,7 +253,7 @@ struct TensorEvaluator<const TensorFFTOp<FFT, ArgType, FFTResultType, FFTDir>, D
|
||||
// get data into line_buf
|
||||
const Index stride = m_strides[dim];
|
||||
if (stride == 1) {
|
||||
memcpy(line_buf, &buf[base_offset], line_len*sizeof(ComplexScalar));
|
||||
m_device.memcpy(line_buf, &buf[base_offset], line_len*sizeof(ComplexScalar));
|
||||
} else {
|
||||
Index offset = base_offset;
|
||||
for (int j = 0; j < line_len; ++j, offset += stride) {
|
||||
@ -271,7 +271,7 @@ struct TensorEvaluator<const TensorFFTOp<FFT, ArgType, FFTResultType, FFTDir>, D
|
||||
|
||||
// write back
|
||||
if (FFTDir == FFT_FORWARD && stride == 1) {
|
||||
memcpy(&buf[base_offset], line_buf, line_len*sizeof(ComplexScalar));
|
||||
m_device.memcpy(&buf[base_offset], line_buf, line_len*sizeof(ComplexScalar));
|
||||
} else {
|
||||
Index offset = base_offset;
|
||||
const ComplexScalar div_factor = ComplexScalar(1.0 / line_len, 0);
|
||||
|
@ -200,19 +200,15 @@ EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const T& array_get(const array<T,N>& a) {
|
||||
return a[I];
|
||||
}
|
||||
|
||||
template <typename T> struct array_size;
|
||||
template<class T, std::size_t N> struct array_size<array<T,N> > {
|
||||
static const size_t value = N;
|
||||
};
|
||||
template <typename T> struct array_size;
|
||||
template<class T, std::size_t N> struct array_size<array<T,N>& > {
|
||||
static const size_t value = N;
|
||||
};
|
||||
template <typename T> struct array_size;
|
||||
template<class T, std::size_t N> struct array_size<const array<T,N> > {
|
||||
static const size_t value = N;
|
||||
};
|
||||
template <typename T> struct array_size;
|
||||
template<class T, std::size_t N> struct array_size<const array<T,N>& > {
|
||||
static const size_t value = N;
|
||||
};
|
||||
@ -251,14 +247,6 @@ template<std::size_t I, class T, std::size_t N> constexpr inline T const& array_
|
||||
|
||||
#undef STD_GET_ARR_HACK
|
||||
|
||||
template <typename T> struct array_size;
|
||||
template<class T, std::size_t N> struct array_size<const std::array<T,N> > {
|
||||
static const size_t value = N;
|
||||
};
|
||||
template <typename T> struct array_size;
|
||||
template<class T, std::size_t N> struct array_size<std::array<T,N> > {
|
||||
static const size_t value = N;
|
||||
};
|
||||
} // end namespace internal
|
||||
} // end namespace Eigen
|
||||
|
||||
|
@ -204,7 +204,8 @@ struct matrix_exp_computeUV
|
||||
template <typename MatrixType>
|
||||
struct matrix_exp_computeUV<MatrixType, float>
|
||||
{
|
||||
static void run(const MatrixType& arg, MatrixType& U, MatrixType& V, int& squarings)
|
||||
template <typename ArgType>
|
||||
static void run(const ArgType& arg, MatrixType& U, MatrixType& V, int& squarings)
|
||||
{
|
||||
using std::frexp;
|
||||
using std::pow;
|
||||
@ -227,7 +228,8 @@ struct matrix_exp_computeUV<MatrixType, float>
|
||||
template <typename MatrixType>
|
||||
struct matrix_exp_computeUV<MatrixType, double>
|
||||
{
|
||||
static void run(const MatrixType& arg, MatrixType& U, MatrixType& V, int& squarings)
|
||||
template <typename ArgType>
|
||||
static void run(const ArgType& arg, MatrixType& U, MatrixType& V, int& squarings)
|
||||
{
|
||||
using std::frexp;
|
||||
using std::pow;
|
||||
@ -254,7 +256,8 @@ struct matrix_exp_computeUV<MatrixType, double>
|
||||
template <typename MatrixType>
|
||||
struct matrix_exp_computeUV<MatrixType, long double>
|
||||
{
|
||||
static void run(const MatrixType& arg, MatrixType& U, MatrixType& V, int& squarings)
|
||||
template <typename ArgType>
|
||||
static void run(const ArgType& arg, MatrixType& U, MatrixType& V, int& squarings)
|
||||
{
|
||||
#if LDBL_MANT_DIG == 53 // double precision
|
||||
matrix_exp_computeUV<MatrixType, double>::run(arg, U, V, squarings);
|
||||
@ -351,11 +354,11 @@ void matrix_exp_compute(const MatrixType& arg, ResultType &result)
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
MatrixType U, V;
|
||||
typename MatrixType::PlainObject U, V;
|
||||
int squarings;
|
||||
matrix_exp_computeUV<MatrixType>::run(arg, U, V, squarings); // Pade approximant is (U+V) / (-U+V)
|
||||
MatrixType numer = U + V;
|
||||
MatrixType denom = -U + V;
|
||||
typename MatrixType::PlainObject numer = U + V;
|
||||
typename MatrixType::PlainObject denom = -U + V;
|
||||
result = denom.partialPivLu().solve(numer);
|
||||
for (int i=0; i<squarings; i++)
|
||||
result *= result; // undo scaling by repeated squaring
|
||||
|
@ -21,6 +21,17 @@ include_directories(../../test ../../unsupported ../../Eigen
|
||||
|
||||
find_package (Threads)
|
||||
|
||||
find_package(Xsmm)
|
||||
if(XSMM_FOUND)
|
||||
add_definitions("-DEIGEN_USE_LIBXSMM")
|
||||
include_directories(${XSMM_INCLUDES})
|
||||
link_directories(${XSMM_LIBRARIES})
|
||||
set(EXTERNAL_LIBS ${EXTERNAL_LIBS} xsmm)
|
||||
ei_add_property(EIGEN_TESTED_BACKENDS "Xsmm, ")
|
||||
else(XSMM_FOUND)
|
||||
ei_add_property(EIGEN_MISSING_BACKENDS "Xsmm, ")
|
||||
endif(XSMM_FOUND)
|
||||
|
||||
find_package(GoogleHash)
|
||||
if(GOOGLEHASH_FOUND)
|
||||
add_definitions("-DEIGEN_GOOGLEHASH_SUPPORT")
|
||||
|
@ -300,6 +300,51 @@ static void test_select()
|
||||
}
|
||||
}
|
||||
|
||||
template <typename Scalar>
|
||||
void test_minmax_nan_propagation_templ() {
|
||||
for (int size = 1; size < 17; ++size) {
|
||||
const Scalar kNan = std::numeric_limits<Scalar>::quiet_NaN();
|
||||
Tensor<Scalar, 1> vec_nan(size);
|
||||
Tensor<Scalar, 1> vec_zero(size);
|
||||
Tensor<Scalar, 1> vec_res(size);
|
||||
vec_nan.setConstant(kNan);
|
||||
vec_zero.setZero();
|
||||
vec_res.setZero();
|
||||
|
||||
// Test that we propagate NaNs in the tensor when applying the
|
||||
// cwiseMax(scalar) operator, which is used for the Relu operator.
|
||||
vec_res = vec_nan.cwiseMax(Scalar(0));
|
||||
for (int i = 0; i < size; ++i) {
|
||||
VERIFY((numext::isnan)(vec_res(i)));
|
||||
}
|
||||
|
||||
// Test that NaNs do not propagate if we reverse the arguments.
|
||||
vec_res = vec_zero.cwiseMax(kNan);
|
||||
for (int i = 0; i < size; ++i) {
|
||||
VERIFY_IS_EQUAL(vec_res(i), Scalar(0));
|
||||
}
|
||||
|
||||
// Test that we propagate NaNs in the tensor when applying the
|
||||
// cwiseMin(scalar) operator.
|
||||
vec_res.setZero();
|
||||
vec_res = vec_nan.cwiseMin(Scalar(0));
|
||||
for (int i = 0; i < size; ++i) {
|
||||
VERIFY((numext::isnan)(vec_res(i)));
|
||||
}
|
||||
|
||||
// Test that NaNs do not propagate if we reverse the arguments.
|
||||
vec_res = vec_zero.cwiseMin(kNan);
|
||||
for (int i = 0; i < size; ++i) {
|
||||
VERIFY_IS_EQUAL(vec_res(i), Scalar(0));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void test_minmax_nan_propagation()
|
||||
{
|
||||
test_minmax_nan_propagation_templ<float>();
|
||||
test_minmax_nan_propagation_templ<double>();
|
||||
}
|
||||
|
||||
void test_cxx11_tensor_expr()
|
||||
{
|
||||
@ -311,4 +356,5 @@ void test_cxx11_tensor_expr()
|
||||
CALL_SUBTEST(test_functors());
|
||||
CALL_SUBTEST(test_type_casting());
|
||||
CALL_SUBTEST(test_select());
|
||||
CALL_SUBTEST(test_minmax_nan_propagation());
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user