From 76946849922a50bc288da2ec9806c6b9c11ff9e0 Mon Sep 17 00:00:00 2001 From: Angelos Mantzaflaris Date: Wed, 7 Dec 2016 00:37:48 +0100 Subject: Remove superfluous const's (can cause warnings on some Intel compilers) (grafted from e236d3443c79f38aa721d95e64c275abbb5df10f ) --- Eigen/src/Core/IO.h | 2 +- Eigen/src/SparseCore/SparseMatrixBase.h | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Eigen/src/Core/IO.h b/Eigen/src/Core/IO.h index 94e00f58b..644228c3f 100644 --- a/Eigen/src/Core/IO.h +++ b/Eigen/src/Core/IO.h @@ -105,7 +105,7 @@ class WithFormat } protected: - const typename ExpressionType::Nested m_matrix; + typename ExpressionType::Nested m_matrix; IOFormat m_format; }; diff --git a/Eigen/src/SparseCore/SparseMatrixBase.h b/Eigen/src/SparseCore/SparseMatrixBase.h index 6087da5c4..0da4c2a36 100644 --- a/Eigen/src/SparseCore/SparseMatrixBase.h +++ b/Eigen/src/SparseCore/SparseMatrixBase.h @@ -213,7 +213,7 @@ template class SparseMatrixBase if (Flags&RowMajorBit) { - const Nested nm(m.derived()); + Nested nm(m.derived()); internal::evaluator thisEval(nm); for (Index row=0; row class SparseMatrixBase } else { - const Nested nm(m.derived()); + Nested nm(m.derived()); internal::evaluator thisEval(nm); if (m.cols() == 1) { Index row = 0; -- cgit v1.2.3 From 95b804c0feb9b96467fb3d34ca3a56173f2bd815 Mon Sep 17 00:00:00 2001 From: Joao Rui Leal Date: Mon, 19 Dec 2016 10:45:59 +0000 Subject: it is now possible to change Umfpack control settings before factorizations; added access to the report functions of Umfpack --- Eigen/src/UmfPackSupport/UmfPackSupport.h | 101 ++++++++++++++++++++++-------- 1 file changed, 75 insertions(+), 26 deletions(-) diff --git a/Eigen/src/UmfPackSupport/UmfPackSupport.h b/Eigen/src/UmfPackSupport/UmfPackSupport.h index dc74de935..9d410393d 100644 --- a/Eigen/src/UmfPackSupport/UmfPackSupport.h +++ b/Eigen/src/UmfPackSupport/UmfPackSupport.h @@ -10,19 +10,37 @@ #ifndef EIGEN_UMFPACKSUPPORT_H #define EIGEN_UMFPACKSUPPORT_H -namespace Eigen { +namespace Eigen { /* TODO extract L, extract U, compute det, etc... */ // generic double/complex wrapper functions: -inline void umfpack_defaults(double control[UMFPACK_CONTROL], double) +inline void umfpack_defaults(double control[UMFPACK_CONTROL], double) { umfpack_di_defaults(control); } -inline void umfpack_defaults(double control[UMFPACK_CONTROL], std::complex) +inline void umfpack_defaults(double control[UMFPACK_CONTROL], std::complex) { 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) +{ 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) +{ 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) +{ 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 > public: typedef Array UmfpackControl; + typedef Array UmfpackInfo; UmfPackLU() : m_dummy(0,0), mp_matrix(m_dummy) @@ -215,7 +234,7 @@ class UmfPackLU : public SparseSolverBase > return m_q; } - /** Computes the sparse Cholesky decomposition of \a matrix + /** Computes the sparse Cholesky decomposition of \a matrix * Note that the matrix should be column-major, and in compressed format for best performance. * \sa SparseMatrix::makeCompressed(). */ @@ -240,7 +259,7 @@ class UmfPackLU : public SparseSolverBase > { if(m_symbolic) umfpack_free_symbolic(&m_symbolic,Scalar()); if(m_numeric) umfpack_free_numeric(&m_numeric,Scalar()); - + grab(matrix.derived()); analyzePattern_impl(); @@ -267,7 +286,7 @@ class UmfPackLU : public SparseSolverBase > { return m_control; } - + /** Provides access to the control settings array used by UmfPack. * * If this array contains NaN's, the default values are used. @@ -278,7 +297,7 @@ class UmfPackLU : public SparseSolverBase > { return m_control; } - + /** Performs a numeric decomposition of \a matrix * * The given matrix must has the same sparcity than the matrix on which the pattern anylysis has been performed. @@ -293,10 +312,38 @@ class UmfPackLU : public SparseSolverBase > umfpack_free_numeric(&m_numeric,Scalar()); grab(matrix.derived()); - + factorize_impl(); } + /** Prints the current UmfPack control settings. + * + * \sa umfpackControl() + */ + void umfpackReportControl() + { + umfpack_report_control(m_control.data(), Scalar()); + } + + /** Prints statistics collected by UmfPack. + * + * \sa analyzePattern(), compute() + */ + void umfpackReportInfo() + { + 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 umfpackReportStatus() { + eigen_assert(m_analysisIsOk && "UmfPackLU: you must first call analyzePattern()"); + umfpack_report_status(m_control.data(), m_fact_errorCode, Scalar()); + } + /** \internal */ template bool _solve_impl(const MatrixBase &b, MatrixBase &x) const; @@ -314,41 +361,42 @@ class UmfPackLU : public SparseSolverBase > 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(mp_matrix.rows()), - internal::convert_index(mp_matrix.cols()), - mp_matrix.outerIndexPtr(), mp_matrix.innerIndexPtr(), mp_matrix.valuePtr(), - &m_symbolic, m_control.data(), 0); + m_fact_errorCode = umfpack_symbolic(internal::convert_index(mp_matrix.rows()), + internal::convert_index(mp_matrix.cols()), + mp_matrix.outerIndexPtr(), mp_matrix.innerIndexPtr(), mp_matrix.valuePtr(), + &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; } - + 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; m_extractedDataAreDirty = true; } - + template void grab(const EigenBase &A) { mp_matrix.~UmfpackMatrixRef(); ::new (&mp_matrix) UmfpackMatrixRef(A.derived()); } - + void grab(const UmfpackMatrixRef &A) { if(&(A.derived()) != &mp_matrix) @@ -357,19 +405,20 @@ class UmfPackLU : public SparseSolverBase > ::new (&mp_matrix) UmfpackMatrixRef(A); } } - + // cached data to reduce reallocation, etc. mutable LUMatrixType m_l; int m_fact_errorCode; UmfpackControl m_control; - + UmfpackInfo m_umfpackInfo; + mutable LUMatrixType m_u; mutable IntColVectorType m_p; mutable IntRowVectorType m_q; UmfpackMatrixType m_dummy; UmfpackMatrixRef mp_matrix; - + void* m_numeric; void* m_symbolic; @@ -377,7 +426,7 @@ class UmfPackLU : public SparseSolverBase > int m_factorizationIsOk; int m_analysisIsOk; mutable bool m_extractedDataAreDirty; - + private: UmfPackLU(const UmfPackLU& ) { } }; @@ -427,7 +476,7 @@ bool UmfPackLU::_solve_impl(const MatrixBase &b, MatrixBas eigen_assert((BDerived::Flags&RowMajorBit)==0 && "UmfPackLU backend does not support non col-major rhs yet"); eigen_assert((XDerived::Flags&RowMajorBit)==0 && "UmfPackLU backend does not support non col-major result yet"); eigen_assert(b.derived().data() != x.derived().data() && " Umfpack does not support inplace solve"); - + int errorCode; Scalar* x_ptr = 0; Matrix x_tmp; @@ -442,7 +491,7 @@ bool UmfPackLU::_solve_impl(const MatrixBase &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) -- cgit v1.2.3 From c8c89b5e1973607c74298daa82a15e45b89e24d1 Mon Sep 17 00:00:00 2001 From: Joao Rui Leal Date: Wed, 21 Dec 2016 09:16:28 +0000 Subject: renamed methods umfpackReportControl(), umfpackReportInfo(), and umfpackReportStatus() from UmfPackLU to printUmfpackControl(), printUmfpackInfo(), and printUmfpackStatus() --- Eigen/src/UmfPackSupport/UmfPackSupport.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Eigen/src/UmfPackSupport/UmfPackSupport.h b/Eigen/src/UmfPackSupport/UmfPackSupport.h index 9d410393d..3f6333a78 100644 --- a/Eigen/src/UmfPackSupport/UmfPackSupport.h +++ b/Eigen/src/UmfPackSupport/UmfPackSupport.h @@ -320,7 +320,7 @@ class UmfPackLU : public SparseSolverBase > * * \sa umfpackControl() */ - void umfpackReportControl() + void printUmfpackControl() { umfpack_report_control(m_control.data(), Scalar()); } @@ -329,7 +329,7 @@ class UmfPackLU : public SparseSolverBase > * * \sa analyzePattern(), compute() */ - void umfpackReportInfo() + void printUmfpackInfo() { eigen_assert(m_analysisIsOk && "UmfPackLU: you must first call analyzePattern()"); umfpack_report_info(m_control.data(), m_umfpackInfo.data(), Scalar()); @@ -339,7 +339,7 @@ class UmfPackLU : public SparseSolverBase > * * \sa analyzePattern(), compute() */ - void umfpackReportStatus() { + void printUmfpackStatus() { eigen_assert(m_analysisIsOk && "UmfPackLU: you must first call analyzePattern()"); umfpack_report_status(m_control.data(), m_fact_errorCode, Scalar()); } -- cgit v1.2.3 From c19fe5e9ed24923b5c80867b38c9823da13ff76e Mon Sep 17 00:00:00 2001 From: Benoit Steiner Date: Wed, 21 Dec 2016 10:43:40 -0800 Subject: Added support for libxsmm in the eigen makefiles --- cmake/FindXsmm.cmake | 24 ++++++++++++++++++++++++ unsupported/test/CMakeLists.txt | 9 +++++++++ 2 files changed, 33 insertions(+) create mode 100644 cmake/FindXsmm.cmake diff --git a/cmake/FindXsmm.cmake b/cmake/FindXsmm.cmake new file mode 100644 index 000000000..745414c72 --- /dev/null +++ b/cmake/FindXsmm.cmake @@ -0,0 +1,24 @@ +# libxsmm + +if (XSMM_INCLUDES AND XSMM_LIBRARIES) + set(XSMM_FIND_QUIETLY TRUE) +endif (XSMM_INCLUDES AND XSMM_LIBRARIES) + +find_path(XSMM_INCLUDES + NAMES + scotch.h + PATHS + $ENV{XSMMDIR} + ${INCLUDE_INSTALL_DIR} + PATH_SUFFIXES + scotch +) + + +find_library(XSMM_LIBRARIES xsmm PATHS $ENV{XSMMDIR} ${LIB_INSTALL_DIR}) + +include(FindPackageHandleStandardArgs) +find_package_handle_standard_args(XSMM DEFAULT_MSG + XSMM_INCLUDES XSMM_LIBRARIES) + +mark_as_advanced(XSMM_INCLUDES XSMM_LIBRARIES) diff --git a/unsupported/test/CMakeLists.txt b/unsupported/test/CMakeLists.txt index daedb671c..c8511b345 100644 --- a/unsupported/test/CMakeLists.txt +++ b/unsupported/test/CMakeLists.txt @@ -21,6 +21,15 @@ include_directories(../../test ../../unsupported ../../Eigen find_package (Threads) +find_package(Xsmm) +if(XSMM_FOUND) + add_definitions("-DEIGEN_USE_LIBXSMM") + include_directories(${XSMM_INCLUDES}) + 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") -- cgit v1.2.3 From f9eff17e915e270e654287723cea67be495f5c5f Mon Sep 17 00:00:00 2001 From: Benoit Steiner Date: Wed, 21 Dec 2016 12:32:06 -0800 Subject: Leverage libxsmm kernels within signle threaded contractions --- unsupported/Eigen/CXX11/Tensor | 4 + .../Eigen/CXX11/src/Tensor/TensorContraction.h | 291 ++++++++++++++++++++- .../CXX11/src/Tensor/TensorContractionBlocking.h | 134 ++++++++++ 3 files changed, 427 insertions(+), 2 deletions(-) diff --git a/unsupported/Eigen/CXX11/Tensor b/unsupported/Eigen/CXX11/Tensor index f98eb03bd..39916092b 100644 --- a/unsupported/Eigen/CXX11/Tensor +++ b/unsupported/Eigen/CXX11/Tensor @@ -71,6 +71,10 @@ typedef unsigned __int64 uint64_t; #include #endif +#if defined(EIGEN_USE_LIBXSMM) +#include "libxsmm.h" +#endif + #ifdef EIGEN_USE_THREADS #include "ThreadPool" #endif diff --git a/unsupported/Eigen/CXX11/src/Tensor/TensorContraction.h b/unsupported/Eigen/CXX11/src/Tensor/TensorContraction.h index 2ac6abf69..c446ba1af 100644 --- a/unsupported/Eigen/CXX11/src/Tensor/TensorContraction.h +++ b/unsupported/Eigen/CXX11/src/Tensor/TensorContraction.h @@ -20,6 +20,70 @@ namespace Eigen { * */ namespace internal { +#if defined(EIGEN_VECTORIZE_AVX) && defined(EIGEN_USE_LIBXSMM) +template +void pack_simple(Scalar * dst, const Scalar * src, Index cols, Index rows, Index lddst, Index ldsrc) { + size_t psize = packet_traits::size; // Packet size + typedef typename packet_traits::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(src) % alignment == 0 && + reinterpret_cast(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(src)); + dst += psize; src += psize; + internal::pstore(dst, internal::pload(src)); + dst += psize; src += psize; + internal::pstore(dst, internal::pload(src)); + dst += psize; src += psize; + internal::pstore(dst, internal::pload(src)); + dst += psize; src += psize; + } + for (size_t i=0; i < num_packets%4; ++i) { + internal::pstore(dst, internal::pload(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 + 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: public libxsmm_mmfunction { + 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: public libxsmm_mmfunction { + 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 struct traits > @@ -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(Layout) == static_cast(RowMajor)) { for (int i = 0, j = NumDims - 1; i < j; i++, j--) { @@ -422,6 +488,13 @@ struct TensorContractionEvaluatorBase template 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,221 @@ 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, ContractDims>& eval_op_indices) { + m_can_use_xsmm = false; + +#if defined(EIGEN_VECTORIZE_AVX) && defined(EIGEN_USE_LIBXSMM) + typedef typename internal::remove_const::type LhsScalar; + typedef typename internal::remove_const::type RhsScalar; + if (!std::is_same::value || + !std::is_same::value || + !(std::is_same::value || + std::is_same::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::type LhsScalar; + typedef typename internal::remove_const::type RhsScalar; + + internal::TensorXsmmContractionBlocking 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(); + + libxsmm_blasint stride_A = static_cast(transposeA ? k : m); + libxsmm_blasint stride_B = static_cast(transposeB ? n : k); + libxsmm_blasint stride_C = static_cast(m); + + libxsmm_blasint stride_blockA = static_cast(mc); + // Use bigger stride to avoid hitting same cache line too often. + // This consistently gives +~0.5 Gflops. + libxsmm_blasint stride_panelB = static_cast( + kc % 32 == 0 ? kc + 16 : kc + ); + + // Kernel for the general case (not edges) + internal::libxsmm_wrapper kernel; + + const LhsScalar *ap; + const RhsScalar *bp; + const Scalar *cp; + + LhsScalar* blockA = NULL; + RhsScalar* panelB = NULL; + + if (copyA) { + blockA = static_cast(this->m_device.allocate(mc * kc * sizeof(LhsScalar))); + } + if (copyB) { + panelB = static_cast(this->m_device.allocate(nc_outer * stride_panelB * sizeof(RhsScalar))); + } + + Index kernel_stride_A = copyA ? stride_blockA : stride_A; + Index kernel_stride_B = copyB ? stride_panelB : stride_B; + kernel = internal::libxsmm_wrapper(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; + + 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(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(blockA, a, actual_kc, actual_mc, stride_blockA, stride_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; + cp = c + nc*stride_C; + + const LhsScalar * actual_a = copyA ? blockA : a; + const Index actual_lda = copyA ? stride_blockA : stride_A; + ap = copyA ? blockA : a; + + const RhsScalar * actual_b = copyB ? panelB + (ni-ni_outer)*stride_panelB : b; + const Index actual_ldb = copyB ? stride_panelB : stride_B; + bp = copyB ? panelB + nc*stride_panelB : b + nc*stride_B; + + float beta = ki == 0 ? 0 : 1; + + if (actual_mc == mc && actual_kc == kc && actual_nc == nc && beta == 1) { + // Most used, cached kernel. + kernel(actual_a, actual_b, c, ap, bp, cp); + } else { + // Edges - use libxsmm kernel cache. + internal::libxsmm_wrapper(0, actual_mc, actual_nc, actual_kc, actual_lda, actual_ldb, stride_C, 1, beta, blocking.prefetch())(actual_a, actual_b, c, ap, 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; @@ -567,6 +854,7 @@ struct TensorContractionEvaluatorBase /// required for sycl const Indices m_expr_indices; + bool m_can_use_xsmm; }; @@ -624,7 +912,6 @@ struct TensorEvaluatortemplate evalGemm(buffer); } - }; } // end namespace Eigen diff --git a/unsupported/Eigen/CXX11/src/Tensor/TensorContractionBlocking.h b/unsupported/Eigen/CXX11/src/Tensor/TensorContractionBlocking.h index 5cf7b4f71..d34f9caee 100644 --- a/unsupported/Eigen/CXX11/src/Tensor/TensorContractionBlocking.h +++ b/unsupported/Eigen/CXX11/src/Tensor/TensorContractionBlocking.h @@ -50,6 +50,140 @@ class TensorContractionBlocking { }; + +#if defined(EIGEN_USE_LIBXSMM) +template +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(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(num_threads_, + parallelism / MIN_JOBS_PER_THREAD); + num_threads_ = numext::maxi(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 -- cgit v1.2.3 From b91be60220d26335d3c7e205d09a34798e7a4c0c Mon Sep 17 00:00:00 2001 From: Benoit Steiner Date: Wed, 21 Dec 2016 13:44:59 -0800 Subject: Automatically include and link libxsmm when present. --- cmake/EigenTesting.cmake | 6 ++++++ cmake/FindXsmm.cmake | 27 ++++++++++++++------------- 2 files changed, 20 insertions(+), 13 deletions(-) diff --git a/cmake/EigenTesting.cmake b/cmake/EigenTesting.cmake index a92a2978b..a83b9435e 100644 --- a/cmake/EigenTesting.cmake +++ b/cmake/EigenTesting.cmake @@ -84,6 +84,12 @@ macro(ei_add_test_internal testname testname_with_suffix) target_link_libraries(${targetname} ${EIGEN_TEST_CUSTOM_LINKER_FLAGS}) endif() + if(XSMM_FOUND) + include_directories(${XSMM_INCLUDES}) + link_directories(${XSMM_LIBRARIES}) + target_link_libraries(${targetname} xsmm) + endif() + if(${ARGC} GREATER 3) set(libs_to_link ${ARGV3}) # it could be that some cmake module provides a bad library string " " (just spaces), diff --git a/cmake/FindXsmm.cmake b/cmake/FindXsmm.cmake index 745414c72..809d6f414 100644 --- a/cmake/FindXsmm.cmake +++ b/cmake/FindXsmm.cmake @@ -1,24 +1,25 @@ -# libxsmm +# 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 (XSMM_INCLUDES AND XSMM_LIBRARIES) +if (LIBXSMM) set(XSMM_FIND_QUIETLY TRUE) -endif (XSMM_INCLUDES AND XSMM_LIBRARIES) + set(XSMM_INCLUDES ${LIBXSMM}/include) + set(XSMM_LIBRARIES ${LIBXSMM}/lib) +endif (LIBXSMM) -find_path(XSMM_INCLUDES +find_path(LIBXSMM NAMES - scotch.h + libxsmm.h PATHS - $ENV{XSMMDIR} + $ENV{XSMMDIR}/include ${INCLUDE_INSTALL_DIR} - PATH_SUFFIXES - scotch ) - -find_library(XSMM_LIBRARIES xsmm PATHS $ENV{XSMMDIR} ${LIB_INSTALL_DIR}) - include(FindPackageHandleStandardArgs) find_package_handle_standard_args(XSMM DEFAULT_MSG - XSMM_INCLUDES XSMM_LIBRARIES) + LIBXSMM) -mark_as_advanced(XSMM_INCLUDES XSMM_LIBRARIES) +mark_as_advanced(LIBXSMM) -- cgit v1.2.3 From 0657228569b26c132bbe9a0016912e7cb0fdc2b0 Mon Sep 17 00:00:00 2001 From: Benoit Steiner Date: Wed, 21 Dec 2016 14:40:08 -0800 Subject: Simplified the way we link libxsmm --- cmake/EigenTesting.cmake | 6 ------ unsupported/test/CMakeLists.txt | 2 ++ 2 files changed, 2 insertions(+), 6 deletions(-) diff --git a/cmake/EigenTesting.cmake b/cmake/EigenTesting.cmake index a83b9435e..a92a2978b 100644 --- a/cmake/EigenTesting.cmake +++ b/cmake/EigenTesting.cmake @@ -84,12 +84,6 @@ macro(ei_add_test_internal testname testname_with_suffix) target_link_libraries(${targetname} ${EIGEN_TEST_CUSTOM_LINKER_FLAGS}) endif() - if(XSMM_FOUND) - include_directories(${XSMM_INCLUDES}) - link_directories(${XSMM_LIBRARIES}) - target_link_libraries(${targetname} xsmm) - endif() - if(${ARGC} GREATER 3) set(libs_to_link ${ARGV3}) # it could be that some cmake module provides a bad library string " " (just spaces), diff --git a/unsupported/test/CMakeLists.txt b/unsupported/test/CMakeLists.txt index c8511b345..a087f4759 100644 --- a/unsupported/test/CMakeLists.txt +++ b/unsupported/test/CMakeLists.txt @@ -25,6 +25,8 @@ 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, ") -- cgit v1.2.3 From 519d63d350222ddbed5db1883a8fb2c7aab4b4e9 Mon Sep 17 00:00:00 2001 From: Benoit Steiner Date: Wed, 21 Dec 2016 15:06:06 -0800 Subject: Added support for libxsmm kernel in multithreaded contractions --- .../CXX11/src/Tensor/TensorContractionThreadPool.h | 208 ++++++++++++++++++++- 1 file changed, 204 insertions(+), 4 deletions(-) diff --git a/unsupported/Eigen/CXX11/src/Tensor/TensorContractionThreadPool.h b/unsupported/Eigen/CXX11/src/Tensor/TensorContractionThreadPool.h index ee16cde9b..d30cc96ab 100644 --- a/unsupported/Eigen/CXX11/src/Tensor/TensorContractionThreadPool.h +++ b/unsupported/Eigen/CXX11/src/Tensor/TensorContractionThreadPool.h @@ -116,6 +116,28 @@ struct TensorEvaluator 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 + blocking(k, m, n, this->m_device.numThreads(), transposeA, + transposeB); + + if (blocking.num_threads() == 1) { + this->evalGemmXSMM(buffer); + } else { + ContextXsmm(this, buffer, m, n, k, blocking).run(); + } + return; + } +#endif + typedef typename internal::remove_const::type LhsScalar; @@ -147,10 +169,7 @@ struct TensorEvaluator 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 + class ContextXsmm { + public: + ContextXsmm(const Self* self, Scalar* buffer, Index m, Index n, Index k, + const internal::TensorXsmmContractionBlocking& 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(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(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( + 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(device.allocate( + (blocks_m*bm)*(blocks_k*bk)*sizeof(LhsScalar))); + } + if (copyB) { + blocksB = static_cast(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 packingA_jobs; + std::atomic packingB_jobs; + std::atomic compute_jobs; + // already packed blocks for each mi-panel in A and ni-panel in B. + std::vector> packingA_done; + std::vector> packingB_done; + }; +#endif + }; } // end namespace Eigen -- cgit v1.2.3 From 4236aebe103b0fa54f3b9e7e3c0c12094fa6e200 Mon Sep 17 00:00:00 2001 From: Benoit Steiner Date: Wed, 21 Dec 2016 16:42:56 -0800 Subject: Simplified the contraction code` --- .../Eigen/CXX11/src/Tensor/TensorContraction.h | 45 +++++++++------------- 1 file changed, 18 insertions(+), 27 deletions(-) diff --git a/unsupported/Eigen/CXX11/src/Tensor/TensorContraction.h b/unsupported/Eigen/CXX11/src/Tensor/TensorContraction.h index c446ba1af..442c14fac 100644 --- a/unsupported/Eigen/CXX11/src/Tensor/TensorContraction.h +++ b/unsupported/Eigen/CXX11/src/Tensor/TensorContraction.h @@ -720,24 +720,20 @@ protected: const LhsScalar* leftData = m_leftImpl.data(); const RhsScalar* rightData = m_rightImpl.data(); - libxsmm_blasint stride_A = static_cast(transposeA ? k : m); - libxsmm_blasint stride_B = static_cast(transposeB ? n : k); - libxsmm_blasint stride_C = static_cast(m); + const libxsmm_blasint stride_A = static_cast(transposeA ? k : m); + const libxsmm_blasint stride_B = static_cast(transposeB ? n : k); + const libxsmm_blasint stride_C = static_cast(m); - libxsmm_blasint stride_blockA = static_cast(mc); + const libxsmm_blasint stride_blockA = static_cast(mc); // Use bigger stride to avoid hitting same cache line too often. // This consistently gives +~0.5 Gflops. - libxsmm_blasint stride_panelB = static_cast( + const libxsmm_blasint stride_panelB = static_cast( kc % 32 == 0 ? kc + 16 : kc ); // Kernel for the general case (not edges) internal::libxsmm_wrapper kernel; - const LhsScalar *ap; - const RhsScalar *bp; - const Scalar *cp; - LhsScalar* blockA = NULL; RhsScalar* panelB = NULL; @@ -748,8 +744,8 @@ protected: panelB = static_cast(this->m_device.allocate(nc_outer * stride_panelB * sizeof(RhsScalar))); } - Index kernel_stride_A = copyA ? stride_blockA : stride_A; - Index kernel_stride_B = copyB ? stride_panelB : stride_B; + const Index kernel_stride_A = copyA ? stride_blockA : stride_A; + const Index kernel_stride_B = copyB ? stride_panelB : stride_B; kernel = internal::libxsmm_wrapper(0, mc, nc, kc, kernel_stride_A, kernel_stride_B, stride_C, 1, 1, blocking.prefetch()); // Outer blocking @@ -763,6 +759,7 @@ protected: // 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) { @@ -775,8 +772,8 @@ protected: 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; + const LhsScalar* a = transposeA ? leftData + mi*stride_A + ki : + leftData + ki*stride_A + mi; if (copyA) { if (transposeA) { @@ -785,30 +782,24 @@ protected: internal::pack_simple(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; - cp = c + nc*stride_C; - - const LhsScalar * actual_a = copyA ? blockA : a; - const Index actual_lda = copyA ? stride_blockA : stride_A; - ap = copyA ? blockA : a; - - const RhsScalar * actual_b = copyB ? panelB + (ni-ni_outer)*stride_panelB : b; - const Index actual_ldb = copyB ? stride_panelB : stride_B; - bp = copyB ? panelB + nc*stride_panelB : b + nc*stride_B; + const RhsScalar* b = rightData + ni*stride_B + ki; + Scalar* c = buffer + ni*stride_C + mi; + const Scalar* cp = c + nc*stride_C; - float beta = ki == 0 ? 0 : 1; + 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, ap, bp, cp); + kernel(actual_a, actual_b, c, actual_a, bp, cp); } else { // Edges - use libxsmm kernel cache. - internal::libxsmm_wrapper(0, actual_mc, actual_nc, actual_kc, actual_lda, actual_ldb, stride_C, 1, beta, blocking.prefetch())(actual_a, actual_b, c, ap, bp, cp); + internal::libxsmm_wrapper(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); } } } -- cgit v1.2.3 From d7825b6707367c92f5d2cba742373059779c4e0f Mon Sep 17 00:00:00 2001 From: Benoit Steiner Date: Wed, 21 Dec 2016 20:06:18 -0800 Subject: Use native AVX512 types instead of Eigen Packets whenever possible. --- Eigen/src/Core/arch/AVX512/PacketMath.h | 122 ++++++++++++++++---------------- 1 file changed, 61 insertions(+), 61 deletions(-) diff --git a/Eigen/src/Core/arch/AVX512/PacketMath.h b/Eigen/src/Core/arch/AVX512/PacketMath.h index 0580b80f8..14ef93c55 100644 --- a/Eigen/src/Core/arch/AVX512/PacketMath.h +++ b/Eigen/src/Core/arch/AVX512/PacketMath.h @@ -59,8 +59,8 @@ template<> struct packet_traits : 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 : 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 @@ -719,7 +719,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 +769,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 +819,7 @@ template<> EIGEN_STRONG_INLINE Packet8d preduxp(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 +835,7 @@ template<> EIGEN_STRONG_INLINE Packet8d preduxp(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 +844,54 @@ template<> EIGEN_STRONG_INLINE Packet8d preduxp(const Packet8d* vecs) template <> EIGEN_STRONG_INLINE float predux(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)); +#ifdef EIGEN_VECTORIZE_AVX512DQ + __m256 lane0 = _mm512_extractf32x8_ps(a, 0); + __m256 lane1 = _mm512_extractf32x8_ps(a, 1); + __m256 sum = _mm256_add_ps(lane0, lane1); + __m256 tmp0 = _mm256_hadd_ps(sum, _mm256_permute2f128_ps(a, a, 1)); tmp0 = _mm256_hadd_ps(tmp0, tmp0); - return pfirst(_mm256_hadd_ps(tmp0, tmp0)); + return _mm_cvtss_f32(_mm256_castps256_ps128(_mm256_hadd_ps(tmp0, tmp0))); #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(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(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(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 +906,59 @@ EIGEN_STRONG_INLINE float predux_mul(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(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(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(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(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(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))); } -- cgit v1.2.3 From 354baa0fb1bb6c2d137288a61339e8cf0e702ad7 Mon Sep 17 00:00:00 2001 From: Benoit Steiner Date: Wed, 21 Dec 2016 20:55:07 -0800 Subject: Avoid using horizontal adds since they're not very efficient. --- Eigen/src/Core/arch/AVX512/PacketMath.h | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/Eigen/src/Core/arch/AVX512/PacketMath.h b/Eigen/src/Core/arch/AVX512/PacketMath.h index 14ef93c55..e46a60472 100644 --- a/Eigen/src/Core/arch/AVX512/PacketMath.h +++ b/Eigen/src/Core/arch/AVX512/PacketMath.h @@ -628,8 +628,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( \ @@ -847,10 +847,8 @@ EIGEN_STRONG_INLINE float predux(const Packet16f& a) { #ifdef EIGEN_VECTORIZE_AVX512DQ __m256 lane0 = _mm512_extractf32x8_ps(a, 0); __m256 lane1 = _mm512_extractf32x8_ps(a, 1); - __m256 sum = _mm256_add_ps(lane0, lane1); - __m256 tmp0 = _mm256_hadd_ps(sum, _mm256_permute2f128_ps(a, a, 1)); - tmp0 = _mm256_hadd_ps(tmp0, tmp0); - return _mm_cvtss_f32(_mm256_castps256_ps128(_mm256_hadd_ps(tmp0, tmp0))); + Packet8f x = _mm256_add_ps(lane0, lane1); + return predux(x); #else __m128 lane0 = _mm512_extractf32x4_ps(a, 0); __m128 lane1 = _mm512_extractf32x4_ps(a, 1); -- cgit v1.2.3 From 6b8f637ab16ae34eb78d572efd347bad68f9331a Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Tue, 27 Dec 2016 16:31:17 +0100 Subject: Harmless typo --- Eigen/src/Core/util/XprHelper.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Eigen/src/Core/util/XprHelper.h b/Eigen/src/Core/util/XprHelper.h index efd179b35..b0cc41d6f 100644 --- a/Eigen/src/Core/util/XprHelper.h +++ b/Eigen/src/Core/util/XprHelper.h @@ -662,7 +662,7 @@ bool is_same_dense(const T1 &, const T2 &, typename enable_if +template struct scalar_div_cost { enum { value = 8*NumTraits::MulCost }; }; -- cgit v1.2.3 From fe0ee72390b8a494301bb467c9ab02a0ea2022a5 Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Tue, 27 Dec 2016 16:33:19 +0100 Subject: Fix check of storage order mismatch for "sparse cwiseop sparse". --- Eigen/src/SparseCore/SparseCwiseBinaryOp.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Eigen/src/SparseCore/SparseCwiseBinaryOp.h b/Eigen/src/SparseCore/SparseCwiseBinaryOp.h index c1ddd1ac1..f65b009d7 100644 --- a/Eigen/src/SparseCore/SparseCwiseBinaryOp.h +++ b/Eigen/src/SparseCore/SparseCwiseBinaryOp.h @@ -45,7 +45,7 @@ class CwiseBinaryOpImpl EIGEN_STATIC_ASSERT(( (!internal::is_same::StorageKind, typename internal::traits::StorageKind>::value) - || ((Lhs::Flags&RowMajorBit) == (Rhs::Flags&RowMajorBit))), + || ((internal::evaluator::Flags&RowMajorBit) == (internal::evaluator::Flags&RowMajorBit))), THE_STORAGE_ORDER_OF_BOTH_SIDES_MUST_MATCH); } }; -- cgit v1.2.3 From 71362674613a552fd157e175aabfc0e85877bebd Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Tue, 27 Dec 2016 16:34:30 +0100 Subject: Add missing .outer() member to iterators of evaluators of cwise sparse binary expression --- Eigen/src/SparseCore/SparseCwiseBinaryOp.h | 6 ++++++ test/sparse_basic.cpp | 12 ++++++++++++ 2 files changed, 18 insertions(+) diff --git a/Eigen/src/SparseCore/SparseCwiseBinaryOp.h b/Eigen/src/SparseCore/SparseCwiseBinaryOp.h index f65b009d7..526c7121b 100644 --- a/Eigen/src/SparseCore/SparseCwiseBinaryOp.h +++ b/Eigen/src/SparseCore/SparseCwiseBinaryOp.h @@ -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 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); @@ -193,6 +194,17 @@ template 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()); -- cgit v1.2.3 From d32a43e33a01631745aa4c0e450153f2f3ac6b9e Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Tue, 27 Dec 2016 16:35:45 +0100 Subject: Make sure that traits::Flags reports the correct storage order so that methods like .outerSize()/.innerSize() work properly. --- Eigen/src/Core/CwiseBinaryOp.h | 2 +- Eigen/src/Core/util/XprHelper.h | 9 +++++++++ 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/Eigen/src/Core/CwiseBinaryOp.h b/Eigen/src/Core/CwiseBinaryOp.h index 9ddbfe286..a36765e39 100644 --- a/Eigen/src/Core/CwiseBinaryOp.h +++ b/Eigen/src/Core/CwiseBinaryOp.h @@ -46,7 +46,7 @@ struct traits > typedef typename remove_reference::type _LhsNested; typedef typename remove_reference::type _RhsNested; enum { - Flags = _LhsNested::Flags & RowMajorBit + Flags = cwise_promote_storage_order::StorageKind,typename traits::StorageKind,_LhsNested::Flags & RowMajorBit,_RhsNested::Flags & RowMajorBit>::value }; }; } // end namespace internal diff --git a/Eigen/src/Core/util/XprHelper.h b/Eigen/src/Core/util/XprHelper.h index b0cc41d6f..b94dd61ff 100644 --- a/Eigen/src/Core/util/XprHelper.h +++ b/Eigen/src/Core/util/XprHelper.h @@ -532,6 +532,15 @@ template struct cwise_promote_s template struct cwise_promote_storage_type { typedef Sparse ret; }; template struct cwise_promote_storage_type { typedef Sparse ret; }; +template struct cwise_promote_storage_order { + enum { value = LhsOrder }; +}; + +template struct cwise_promote_storage_order { enum { value = RhsOrder }; }; +template struct cwise_promote_storage_order { enum { value = LhsOrder }; }; +template struct cwise_promote_storage_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. -- cgit v1.2.3 From ab69a7f6d19b22a98bbb3bef2f0567d20204b0a0 Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Tue, 27 Dec 2016 16:55:47 +0100 Subject: Cleanup because trait::Flags now expose the correct storage order --- Eigen/src/SparseCore/SparseCwiseBinaryOp.h | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/Eigen/src/SparseCore/SparseCwiseBinaryOp.h b/Eigen/src/SparseCore/SparseCwiseBinaryOp.h index 526c7121b..145a7389e 100644 --- a/Eigen/src/SparseCore/SparseCwiseBinaryOp.h +++ b/Eigen/src/SparseCore/SparseCwiseBinaryOp.h @@ -212,8 +212,7 @@ public: enum { CoeffReadCost = evaluator::CoeffReadCost + evaluator::CoeffReadCost + functor_traits::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) @@ -300,8 +299,7 @@ public: enum { CoeffReadCost = evaluator::CoeffReadCost + evaluator::CoeffReadCost + functor_traits::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) @@ -523,8 +521,7 @@ public: enum { CoeffReadCost = evaluator::CoeffReadCost + evaluator::CoeffReadCost + functor_traits::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) @@ -598,8 +595,7 @@ public: enum { CoeffReadCost = evaluator::CoeffReadCost + evaluator::CoeffReadCost + functor_traits::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) -- cgit v1.2.3 From 7713e20fd2f673091807dd7f5b3864ac8aef17f2 Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Tue, 27 Dec 2016 22:04:58 +0100 Subject: Fix compilation --- Eigen/src/UmfPackSupport/UmfPackSupport.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Eigen/src/UmfPackSupport/UmfPackSupport.h b/Eigen/src/UmfPackSupport/UmfPackSupport.h index 3f6333a78..9568cc1d5 100644 --- a/Eigen/src/UmfPackSupport/UmfPackSupport.h +++ b/Eigen/src/UmfPackSupport/UmfPackSupport.h @@ -410,7 +410,7 @@ class UmfPackLU : public SparseSolverBase > mutable LUMatrixType m_l; int m_fact_errorCode; UmfpackControl m_control; - UmfpackInfo m_umfpackInfo; + mutable UmfpackInfo m_umfpackInfo; mutable LUMatrixType m_u; mutable IntColVectorType m_p; -- cgit v1.2.3 From 97812ff0d30c2fd5c93791a63a941d0960a64b69 Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Wed, 28 Dec 2016 23:29:35 +0100 Subject: bug #1369: fix type mismatch warning. Returned values of omp thread id and numbers are int, o let's use int instead of Index here. --- Eigen/src/Core/products/GeneralMatrixMatrix.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Eigen/src/Core/products/GeneralMatrixMatrix.h b/Eigen/src/Core/products/GeneralMatrixMatrix.h index 61df3be57..6440e1d09 100644 --- a/Eigen/src/Core/products/GeneralMatrixMatrix.h +++ b/Eigen/src/Core/products/GeneralMatrixMatrix.h @@ -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 Date: Wed, 28 Dec 2016 23:35:43 +0100 Subject: bug #1365: fix another type mismatch warning (sync is set from and compared to an Index) --- Eigen/src/Core/products/Parallelizer.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Eigen/src/Core/products/Parallelizer.h b/Eigen/src/Core/products/Parallelizer.h index 2a31e4cbe..3477d7182 100644 --- a/Eigen/src/Core/products/Parallelizer.h +++ b/Eigen/src/Core/products/Parallelizer.h @@ -75,7 +75,7 @@ template 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; -- cgit v1.2.3 From 4ebf69394d46cf5113b27fb11923cffeb54c28d2 Mon Sep 17 00:00:00 2001 From: Marco Falke Date: Sun, 1 Jan 2017 13:25:48 +0000 Subject: doc: Fix trivial typo in AsciiQuickReference.txt * * * fixup! --- doc/AsciiQuickReference.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/doc/AsciiQuickReference.txt b/doc/AsciiQuickReference.txt index 9599df60b..8409f8850 100644 --- a/doc/AsciiQuickReference.txt +++ b/doc/AsciiQuickReference.txt @@ -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() // 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; -- cgit v1.2.3 From 5c279624538d484940c34673245ea2a9a48ca964 Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Mon, 2 Jan 2017 22:27:07 +0100 Subject: Move common cwise-unary method from MatrixBase/ArrayBase to the common DenseBase class. --- Eigen/src/Core/ArrayBase.h | 2 +- Eigen/src/Core/DenseBase.h | 3 +++ Eigen/src/Core/MatrixBase.h | 2 +- 3 files changed, 5 insertions(+), 2 deletions(-) diff --git a/Eigen/src/Core/ArrayBase.h b/Eigen/src/Core/ArrayBase.h index f0232f65e..af5fb2566 100644 --- a/Eigen/src/Core/ArrayBase.h +++ b/Eigen/src/Core/ArrayBase.h @@ -69,6 +69,7 @@ template 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 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" diff --git a/Eigen/src/Core/DenseBase.h b/Eigen/src/Core/DenseBase.h index bd74e8a13..9f3c7c8a9 100644 --- a/Eigen/src/Core/DenseBase.h +++ b/Eigen/src/Core/DenseBase.h @@ -560,6 +560,8 @@ template 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" # ifdef EIGEN_DENSEBASE_PLUGIN # include EIGEN_DENSEBASE_PLUGIN @@ -567,6 +569,7 @@ template class DenseBase #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 diff --git a/Eigen/src/Core/MatrixBase.h b/Eigen/src/Core/MatrixBase.h index f7cf04cde..675c94e12 100644 --- a/Eigen/src/Core/MatrixBase.h +++ b/Eigen/src/Core/MatrixBase.h @@ -76,6 +76,7 @@ template 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 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" -- cgit v1.2.3 From d3c5525c23cd354c535eeacdc21d2c600ab55c6c Mon Sep 17 00:00:00 2001 From: Valentin Roussellet Date: Wed, 28 Dec 2016 18:29:30 +0100 Subject: Added += and + operators to inner iterators Fix #1340 #1340 --- Eigen/src/Core/CoreIterators.h | 5 +++++ Eigen/src/SparseCore/SparseCompressedBase.h | 16 ++++++++++++++++ 2 files changed, 21 insertions(+) diff --git a/Eigen/src/Core/CoreIterators.h b/Eigen/src/Core/CoreIterators.h index 4eb42b93a..b96719681 100644 --- a/Eigen/src/Core/CoreIterators.h +++ b/Eigen/src/Core/CoreIterators.h @@ -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. diff --git a/Eigen/src/SparseCore/SparseCompressedBase.h b/Eigen/src/SparseCore/SparseCompressedBase.h index e0850795c..d32a8df40 100644 --- a/Eigen/src/SparseCore/SparseCompressedBase.h +++ b/Eigen/src/SparseCore/SparseCompressedBase.h @@ -185,6 +185,14 @@ class SparseCompressedBase::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(m_values[m_id]); } @@ -245,6 +253,14 @@ class SparseCompressedBase::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(m_values[m_id-1]); } -- cgit v1.2.3 From c4fc2611ba34652f98b5e0ac9f817879bef8eed1 Mon Sep 17 00:00:00 2001 From: NeroBurner Date: Mon, 2 Jan 2017 09:09:21 +0100 Subject: add cmake-option to enable/disable creation of tests * * * disable unsupportet/test when test are disabled * * * rename EIGEN_ENABLE_TESTS to BUILD_TESTING * * * consider BUILD_TESTING in blas --- CMakeLists.txt | 21 +++++++++++---------- blas/CMakeLists.txt | 10 ++++++---- unsupported/CMakeLists.txt | 10 ++++++---- 3 files changed, 23 insertions(+), 18 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 7237b54df..aab9c0e2c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -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) - add_subdirectory(test) # can't do EXCLUDE_FROM_ALL here, breaks CTest -else() - add_subdirectory(test EXCLUDE_FROM_ALL) + if(EIGEN_LEAVE_TEST_IN_ALL_TARGET) + add_subdirectory(test) # can't do EXCLUDE_FROM_ALL here, breaks CTest + else() + add_subdirectory(test EXCLUDE_FROM_ALL) + endif() 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}") diff --git a/blas/CMakeLists.txt b/blas/CMakeLists.txt index d0efb4188..9887d5804 100644 --- a/blas/CMakeLists.txt +++ b/blas/CMakeLists.txt @@ -45,10 +45,12 @@ install(TARGETS eigen_blas eigen_blas_static if(EIGEN_Fortran_COMPILER_WORKS) -if(EIGEN_LEAVE_TEST_IN_ALL_TARGET) - add_subdirectory(testing) # can't do EXCLUDE_FROM_ALL here, breaks CTest -else() - add_subdirectory(testing EXCLUDE_FROM_ALL) +if(BUILD_TESTING) + if(EIGEN_LEAVE_TEST_IN_ALL_TARGET) + add_subdirectory(testing) # can't do EXCLUDE_FROM_ALL here, breaks CTest + else() + add_subdirectory(testing EXCLUDE_FROM_ALL) + endif() endif() endif() diff --git a/unsupported/CMakeLists.txt b/unsupported/CMakeLists.txt index 4fef40a86..9a5666105 100644 --- a/unsupported/CMakeLists.txt +++ b/unsupported/CMakeLists.txt @@ -1,7 +1,9 @@ add_subdirectory(Eigen) add_subdirectory(doc EXCLUDE_FROM_ALL) -if(EIGEN_LEAVE_TEST_IN_ALL_TARGET) - add_subdirectory(test) # can't do EXCLUDE_FROM_ALL here, breaks CTest -else() - add_subdirectory(test EXCLUDE_FROM_ALL) +if(BUILD_TESTING) + if(EIGEN_LEAVE_TEST_IN_ALL_TARGET) + add_subdirectory(test) # can't do EXCLUDE_FROM_ALL here, breaks CTest + else() + add_subdirectory(test EXCLUDE_FROM_ALL) + endif() endif() -- cgit v1.2.3 From 575c078759e718f9afc8353c5222dafc72d053b0 Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Tue, 3 Jan 2017 11:19:14 +0100 Subject: bug #1370: rename _Index to _StorageIndex in SparseMatrix, and add a warning in the doc regarding the 3.2 to 3.3 change of SparseMatrix::Index --- Eigen/src/SparseCore/SparseMatrix.h | 74 +++++++++++++++++++------------------ 1 file changed, 39 insertions(+), 35 deletions(-) diff --git a/Eigen/src/SparseCore/SparseMatrix.h b/Eigen/src/SparseCore/SparseMatrix.h index fcf6dbbad..529c7a0ac 100644 --- a/Eigen/src/SparseCore/SparseMatrix.h +++ b/Eigen/src/SparseCore/SparseMatrix.h @@ -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 -struct traits > +template +struct traits > { typedef _Scalar Scalar; - typedef _Index StorageIndex; + typedef _StorageIndex StorageIndex; typedef Sparse StorageKind; typedef MatrixXpr XprKind; enum { @@ -56,16 +60,16 @@ struct traits > }; }; -template -struct traits, DiagIndex> > +template +struct traits, DiagIndex> > { - typedef SparseMatrix<_Scalar, _Options, _Index> MatrixType; + typedef SparseMatrix<_Scalar, _Options, _StorageIndex> MatrixType; typedef typename ref_selector::type MatrixTypeNested; typedef typename remove_reference::type _MatrixTypeNested; typedef _Scalar Scalar; typedef Dense StorageKind; - typedef _Index StorageIndex; + typedef _StorageIndex StorageIndex; typedef MatrixXpr XprKind; enum { @@ -77,9 +81,9 @@ struct traits, DiagIndex> > }; }; -template -struct traits, DiagIndex> > - : public traits, DiagIndex> > +template +struct traits, DiagIndex> > + : public traits, DiagIndex> > { enum { Flags = 0 @@ -88,13 +92,13 @@ struct traits, DiagIndex> } // end namespace internal -template +template class SparseMatrix - : public SparseCompressedBase > + : public SparseCompressedBase > { typedef SparseCompressedBase 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 +template template -void SparseMatrix::setFromTriplets(const InputIterators& begin, const InputIterators& end) +void SparseMatrix::setFromTriplets(const InputIterators& begin, const InputIterators& end) { - internal::set_from_triplets >(begin, end, *this, internal::scalar_sum_op()); + internal::set_from_triplets >(begin, end, *this, internal::scalar_sum_op()); } /** The same as setFromTriplets but when duplicates are met the functor \a dup_func is applied: @@ -1000,17 +1004,17 @@ void SparseMatrix::setFromTriplets(const InputIterators& * mat.setFromTriplets(triplets.begin(), triplets.end(), [] (const Scalar&,const Scalar &b) { return b; }); * \endcode */ -template +template template -void SparseMatrix::setFromTriplets(const InputIterators& begin, const InputIterators& end, DupFunctor dup_func) +void SparseMatrix::setFromTriplets(const InputIterators& begin, const InputIterators& end, DupFunctor dup_func) { - internal::set_from_triplets, DupFunctor>(begin, end, *this, dup_func); + internal::set_from_triplets, DupFunctor>(begin, end, *this, dup_func); } /** \internal */ -template +template template -void SparseMatrix::collapseDuplicates(DupFunctor dup_func) +void SparseMatrix::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::collapseDuplicates(DupFunctor dup_fun m_data.resize(m_outerIndex[m_outerSize]); } -template +template template -EIGEN_DONT_INLINE SparseMatrix& SparseMatrix::operator=(const SparseMatrixBase& other) +EIGEN_DONT_INLINE SparseMatrix& SparseMatrix::operator=(const SparseMatrixBase& other) { EIGEN_STATIC_ASSERT((internal::is_same::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& SparseMatrix -typename SparseMatrix<_Scalar,_Options,_Index>::Scalar& SparseMatrix<_Scalar,_Options,_Index>::insert(Index row, Index col) +template +typename SparseMatrix<_Scalar,_Options,_StorageIndex>::Scalar& SparseMatrix<_Scalar,_Options,_StorageIndex>::insert(Index row, Index col) { eigen_assert(row>=0 && row=0 && col::Scalar& SparseMatrix<_Scalar,_Op return insertUncompressed(row,col); } -template -EIGEN_DONT_INLINE typename SparseMatrix<_Scalar,_Options,_Index>::Scalar& SparseMatrix<_Scalar,_Options,_Index>::insertUncompressed(Index row, Index col) +template +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 -EIGEN_DONT_INLINE typename SparseMatrix<_Scalar,_Options,_Index>::Scalar& SparseMatrix<_Scalar,_Options,_Index>::insertCompressed(Index row, Index col) +template +EIGEN_DONT_INLINE typename SparseMatrix<_Scalar,_Options,_StorageIndex>::Scalar& SparseMatrix<_Scalar,_Options,_StorageIndex>::insertCompressed(Index row, Index col) { eigen_assert(isCompressed()); @@ -1382,12 +1386,12 @@ EIGEN_DONT_INLINE typename SparseMatrix<_Scalar,_Options,_Index>::Scalar& Sparse namespace internal { -template -struct evaluator > - : evaluator > > +template +struct evaluator > + : evaluator > > { - typedef evaluator > > Base; - typedef SparseMatrix<_Scalar,_Options,_Index> SparseMatrixType; + typedef evaluator > > Base; + typedef SparseMatrix<_Scalar,_Options,_StorageIndex> SparseMatrixType; evaluator() : Base() {} explicit evaluator(const SparseMatrixType &mat) : Base(mat) {} }; -- cgit v1.2.3 From 870256217719e5d5a55ce0791ee4c8ff6f4592c4 Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Tue, 3 Jan 2017 11:25:41 +0100 Subject: bug #1370: add doc for StorageIndex --- Eigen/src/SparseCore/SparseMatrixBase.h | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Eigen/src/SparseCore/SparseMatrixBase.h b/Eigen/src/SparseCore/SparseMatrixBase.h index 0da4c2a36..c6b548f11 100644 --- a/Eigen/src/SparseCore/SparseMatrixBase.h +++ b/Eigen/src/SparseCore/SparseMatrixBase.h @@ -37,7 +37,11 @@ template class SparseMatrixBase typedef typename internal::packet_traits::type PacketScalar; typedef typename internal::traits::StorageKind StorageKind; + + /** The integer type used to \b store indices within a SparseMatrix. + * For a \c SparseMatrix it an alias of the third template parameter \c IndexType. */ typedef typename internal::traits::StorageIndex StorageIndex; + typedef typename internal::add_const_on_value_type_if_arithmetic< typename internal::packet_traits::type >::type PacketReturnType; -- cgit v1.2.3 From 5838f078a70f24ad4b60498abca531e42caae8fb Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Tue, 3 Jan 2017 11:30:27 +0100 Subject: Fix inclusion --- bench/perf_monitoring/gemm_common.h | 2 +- bench/perf_monitoring/gemv_common.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/bench/perf_monitoring/gemm_common.h b/bench/perf_monitoring/gemm_common.h index 4d4a5c0f9..30dbc0df6 100644 --- a/bench/perf_monitoring/gemm_common.h +++ b/bench/perf_monitoring/gemm_common.h @@ -3,7 +3,7 @@ #include #include #include "eigen_src/Eigen/Core" -#include "../../BenchTimer.h" +#include "../BenchTimer.h" using namespace Eigen; #ifndef SCALAR diff --git a/bench/perf_monitoring/gemv_common.h b/bench/perf_monitoring/gemv_common.h index 25a5280a0..cc3257729 100644 --- a/bench/perf_monitoring/gemv_common.h +++ b/bench/perf_monitoring/gemv_common.h @@ -4,7 +4,7 @@ #include #include #include "eigen_src/Eigen/Core" -#include "../../BenchTimer.h" +#include "../BenchTimer.h" using namespace Eigen; #ifndef SCALAR -- cgit v1.2.3 From 45b289505c46f05d2a2ba8658a11259bd20eff5b Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Tue, 3 Jan 2017 11:31:02 +0100 Subject: Add debug output --- bench/perf_monitoring/run.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/bench/perf_monitoring/run.sh b/bench/perf_monitoring/run.sh index 14a26907f..20871668e 100755 --- a/bench/perf_monitoring/run.sh +++ b/bench/perf_monitoring/run.sh @@ -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 -- cgit v1.2.3 From a5ebc92f8d6ec99c866626789de263e4b0d4c62b Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Wed, 4 Jan 2017 18:21:44 +0100 Subject: bug #1336: fix doxygen issue regarding EIGEN_CWISE_BINARY_RETURN_TYPE --- doc/Doxyfile.in | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/doc/Doxyfile.in b/doc/Doxyfile.in index e9b116d28..cac2d1948 100644 --- a/doc/Doxyfile.in +++ b/doc/Doxyfile.in @@ -1591,9 +1591,13 @@ PREDEFINED = EIGEN_EMPTY_STRUCT \ EIGEN_STRONG_INLINE=inline \ EIGEN_DEVICE_FUNC= \ "EIGEN_MAKE_CWISE_BINARY_OP(METHOD,FUNCTOR)=template const CwiseBinaryOp, const Derived, const OtherDerived> METHOD(const EIGEN_CURRENT_STORAGE_BASE_CLASS &other) const;" \ - "EIGEN_CWISE_PRODUCT_RETURN_TYPE(LHS,RHS)=CwiseBinaryOp, const LHS, const RHS>"\ + "EIGEN_CWISE_PRODUCT_RETURN_TYPE(LHS,RHS)=CwiseBinaryOp, 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, 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 +1621,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 -- cgit v1.2.3 From 29a1a58113e3978ce12b8592b7f2f2184e20ec81 Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Wed, 4 Jan 2017 22:01:50 +0100 Subject: Document selfadjointView --- Eigen/src/Core/SelfAdjointView.h | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/Eigen/src/Core/SelfAdjointView.h b/Eigen/src/Core/SelfAdjointView.h index 06484ab30..504c98f0e 100644 --- a/Eigen/src/Core/SelfAdjointView.h +++ b/Eigen/src/Core/SelfAdjointView.h @@ -319,6 +319,7 @@ public: * Implementation of MatrixBase methods ***************************************************************************/ +/** This is the const version of MatrixBase::selfadjointView() */ template template typename MatrixBase::template ConstSelfAdjointViewReturnType::Type @@ -327,6 +328,15 @@ MatrixBase::selfadjointView() const return typename ConstSelfAdjointViewReturnType::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 template typename MatrixBase::template SelfAdjointViewReturnType::Type -- cgit v1.2.3 From a0a36ad0efd3f36545a16e78faf5ce2efa2dd7d3 Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Wed, 4 Jan 2017 22:02:39 +0100 Subject: bug #1336: workaround doxygen failing to include numerous members of MatriBase in Matrix --- Eigen/src/Core/PlainObjectBase.h | 30 ++++++++++++++++++------------ 1 file changed, 18 insertions(+), 12 deletions(-) diff --git a/Eigen/src/Core/PlainObjectBase.h b/Eigen/src/Core/PlainObjectBase.h index 0c04f8250..d06c16225 100644 --- a/Eigen/src/Core/PlainObjectBase.h +++ b/Eigen/src/Core/PlainObjectBase.h @@ -58,33 +58,39 @@ template struct m } // end namespace internal -/** \class PlainObjectBase - * \ingroup Core_Module - * \brief %Dense storage base class for matrices and arrays. - * - * This class can be extended with the help of the plugin mechanism described on the page - * \ref TopicCustomizing_Plugins by defining the preprocessor symbol \c EIGEN_PLAINOBJECTBASE_PLUGIN. - * - * \sa \ref TopicClassHierarchy - */ #ifdef EIGEN_PARSED_BY_DOXYGEN namespace doxygen { -// this is a workaround to doxygen not being able to understand the inheritance logic +// 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 >, +// 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 struct dense_xpr_base_dispatcher; /** This class is just a workaround for Doxygen and it does not not actually exist. */ template struct dense_xpr_base_dispatcher > - : public MatrixBase > {}; + : public MatrixBase {}; /** This class is just a workaround for Doxygen and it does not not actually exist. */ template struct dense_xpr_base_dispatcher > - : public ArrayBase > {}; + : public ArrayBase {}; } // namespace doxygen +/** \class PlainObjectBase + * \ingroup Core_Module + * \brief %Dense storage base class for matrices and arrays. + * + * This class can be extended with the help of the plugin mechanism described on the page + * \ref 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 + */ template class PlainObjectBase : public doxygen::dense_xpr_base_dispatcher #else -- cgit v1.2.3 From 5165de97a44869188b19e62b669b6bc78d8e96e0 Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Wed, 4 Jan 2017 23:08:27 +0100 Subject: Add missing snippet files. --- doc/snippets/Cwise_boolean_xor.cpp | 2 ++ doc/snippets/MatrixBase_selfadjointView.cpp | 6 ++++++ 2 files changed, 8 insertions(+) create mode 100644 doc/snippets/Cwise_boolean_xor.cpp create mode 100644 doc/snippets/MatrixBase_selfadjointView.cpp diff --git a/doc/snippets/Cwise_boolean_xor.cpp b/doc/snippets/Cwise_boolean_xor.cpp new file mode 100644 index 000000000..99bcc5e09 --- /dev/null +++ b/doc/snippets/Cwise_boolean_xor.cpp @@ -0,0 +1,2 @@ +.Array3d v(-1,2,1), w(-3,2,3); +cout << ((v()) << endl; +cout << "Here is the symmetric matrix extracted from the lower part of m:" << endl + << Matrix3i(m.selfadjointView()) << endl; -- cgit v1.2.3 From ee6f7f6c0ca28e984a4e84aeb7209d520ead54c1 Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Wed, 4 Jan 2017 23:10:36 +0100 Subject: Add doc for sparse triangular solve functions --- Eigen/src/SparseCore/SparseTriangularView.h | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Eigen/src/SparseCore/SparseTriangularView.h b/Eigen/src/SparseCore/SparseTriangularView.h index 0c27855d5..9ac120266 100644 --- a/Eigen/src/SparseCore/SparseTriangularView.h +++ b/Eigen/src/SparseCore/SparseTriangularView.h @@ -55,7 +55,10 @@ template class TriangularViewImplsolveInPlace(dst); } + /** Applies the inverse of \c *this to the dense vector or matrix \a other, "in-place" */ template void solveInPlace(MatrixBase& other) const; + + /** Applies the inverse of \c *this to the sparse vector or matrix \a other, "in-place" */ template void solveInPlace(SparseMatrixBase& other) const; }; -- cgit v1.2.3 From 2299717fd5a25ce645c4add41ab4e04a59ca590b Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Wed, 4 Jan 2017 23:27:33 +0100 Subject: Fix and workaround several doxygen issues/warnings --- Eigen/src/Core/Dot.h | 3 ++- Eigen/src/Core/PlainObjectBase.h | 3 ++- Eigen/src/Core/SolveTriangular.h | 2 ++ Eigen/src/Core/TriangularMatrix.h | 6 ++++++ Eigen/src/Core/Visitor.h | 6 ++++-- Eigen/src/QR/CompleteOrthogonalDecomposition.h | 2 +- Eigen/src/SparseCore/TriangularSolver.h | 5 +++++ Eigen/src/SuperLUSupport/SuperLUSupport.h | 3 +++ Eigen/src/plugins/BlockMethods.h | 12 ++++++------ doc/CoeffwiseMathFunctionsTable.dox | 12 ++++++------ doc/Doxyfile.in | 3 ++- doc/PreprocessorDirectives.dox | 2 +- doc/QuickReference.dox | 2 +- 13 files changed, 41 insertions(+), 20 deletions(-) diff --git a/Eigen/src/Core/Dot.h b/Eigen/src/Core/Dot.h index f4fb4db7e..06ef18b8b 100644 --- a/Eigen/src/Core/Dot.h +++ b/Eigen/src/Core/Dot.h @@ -51,7 +51,8 @@ struct dot_nocheck } // 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 * diff --git a/Eigen/src/Core/PlainObjectBase.h b/Eigen/src/Core/PlainObjectBase.h index d06c16225..359135628 100644 --- a/Eigen/src/Core/PlainObjectBase.h +++ b/Eigen/src/Core/PlainObjectBase.h @@ -560,7 +560,8 @@ class PlainObjectBase : public internal::dense_xpr_base::type public: - /** \copydoc DenseBase::operator=(const EigenBase&) + /** \brief Copies the generic expression \a other into *this. + * \copydetails DenseBase::operator=(const EigenBase &other) */ template EIGEN_DEVICE_FUNC diff --git a/Eigen/src/Core/SolveTriangular.h b/Eigen/src/Core/SolveTriangular.h index 96d3dde50..049890b25 100644 --- a/Eigen/src/Core/SolveTriangular.h +++ b/Eigen/src/Core/SolveTriangular.h @@ -161,6 +161,7 @@ struct triangular_solver_selector { * TriangularView methods ***************************************************************************/ +#ifndef EIGEN_PARSED_BY_DOXYGEN template template void TriangularViewImpl::solveInPlace(const MatrixBase& _other) const @@ -188,6 +189,7 @@ TriangularViewImpl::solve(const MatrixBase& other) co { return internal::triangular_solve_retval(derived(), other.derived()); } +#endif namespace internal { diff --git a/Eigen/src/Core/TriangularMatrix.h b/Eigen/src/Core/TriangularMatrix.h index 641c20417..c35fb8083 100644 --- a/Eigen/src/Core/TriangularMatrix.h +++ b/Eigen/src/Core/TriangularMatrix.h @@ -470,6 +470,8 @@ template 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 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 @@ -546,6 +550,7 @@ template class TriangularViewImpl<_Mat * Implementation of triangular evaluation/assignment ***************************************************************************/ +#ifndef EIGEN_PARSED_BY_DOXYGEN // FIXME should we keep that possibility template template @@ -583,6 +588,7 @@ void TriangularViewImpl::lazyAssign(const TriangularBas eigen_assert(Mode == int(OtherDerived::Mode)); internal::call_assignment_no_alias(derived(), other.derived()); } +#endif /*************************************************************************** * Implementation of TriangularBase methods diff --git a/Eigen/src/Core/Visitor.h b/Eigen/src/Core/Visitor.h index d71dfc968..54c1883d9 100644 --- a/Eigen/src/Core/Visitor.h +++ b/Eigen/src/Core/Visitor.h @@ -194,7 +194,8 @@ struct functor_traits > { } // end namespace internal -/** \returns the minimum of all coefficients of *this and puts in *row and *col its location. +/** \fn DenseBase::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::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::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() diff --git a/Eigen/src/QR/CompleteOrthogonalDecomposition.h b/Eigen/src/QR/CompleteOrthogonalDecomposition.h index 41e4ecdfd..34c637b70 100644 --- a/Eigen/src/QR/CompleteOrthogonalDecomposition.h +++ b/Eigen/src/QR/CompleteOrthogonalDecomposition.h @@ -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. * diff --git a/Eigen/src/SparseCore/TriangularSolver.h b/Eigen/src/SparseCore/TriangularSolver.h index 19f8f6704..f9c56ba79 100644 --- a/Eigen/src/SparseCore/TriangularSolver.h +++ b/Eigen/src/SparseCore/TriangularSolver.h @@ -171,6 +171,8 @@ struct sparse_solve_triangular_selector } // end namespace internal +#ifndef EIGEN_PARSED_BY_DOXYGEN + template template void TriangularViewImpl::solveInPlace(MatrixBase& other) const @@ -189,6 +191,7 @@ void TriangularViewImpl::solveInPlace(MatrixBase } // end namespace internal +#ifndef EIGEN_PARSED_BY_DOXYGEN template template void TriangularViewImpl::solveInPlace(SparseMatrixBase& other) const @@ -304,6 +308,7 @@ void TriangularViewImpl::solveInPlace(SparseMatrixBa // if (copy) // other = otherCopy; } +#endif } // end namespace Eigen diff --git a/Eigen/src/SuperLUSupport/SuperLUSupport.h b/Eigen/src/SuperLUSupport/SuperLUSupport.h index 88c44bcd0..50a69f306 100644 --- a/Eigen/src/SuperLUSupport/SuperLUSupport.h +++ b/Eigen/src/SuperLUSupport/SuperLUSupport.h @@ -967,6 +967,7 @@ void SuperILU::factorize(const MatrixType& a) m_factorizationIsOk = true; } +#ifndef EIGEN_PARSED_BY_DOXYGEN template template void SuperILU::_solve_impl(const MatrixBase &b, MatrixBase& x) const @@ -1019,6 +1020,8 @@ void SuperILU::_solve_impl(const MatrixBase &b, MatrixBase::Type block(Index startRow, Index sta return typename FixedBlockXpr::Type(derived(), startRow, startCol, blockRows, blockCols); } -/// This is the const version of block<>(Index, Index, Index, Index). */ +/// This is the const version of block<>(Index, Index, Index, Index). template inline const typename ConstFixedBlockXpr::Type block(Index startRow, Index startCol, Index blockRows, Index blockCols) const @@ -832,15 +832,15 @@ inline const typename ConstFixedBlockXpr::Type block(Index startRow /// Output: \verbinclude MatrixBase_col.out /// EIGEN_DOC_BLOCK_ADDONS_INNER_PANEL_IF(column-major) -/// -/// \sa row(), class Block */ +/** + * \sa row(), class Block */ EIGEN_DEVICE_FUNC inline ColXpr col(Index i) { return ColXpr(derived(), i); } -/// This is the const version of col(). */ +/// This is the const version of col(). EIGEN_DEVICE_FUNC inline ConstColXpr col(Index i) const { @@ -853,8 +853,8 @@ inline ConstColXpr col(Index i) const /// Output: \verbinclude MatrixBase_row.out /// EIGEN_DOC_BLOCK_ADDONS_INNER_PANEL_IF(row-major) -/// -/// \sa col(), class Block */ +/** + * \sa col(), class Block */ EIGEN_DEVICE_FUNC inline RowXpr row(Index i) { diff --git a/doc/CoeffwiseMathFunctionsTable.dox b/doc/CoeffwiseMathFunctionsTable.dox index ac6e0bd31..3ae9420dc 100644 --- a/doc/CoeffwiseMathFunctionsTable.dox +++ b/doc/CoeffwiseMathFunctionsTable.dox @@ -366,7 +366,7 @@ This also means that, unless specified, if the function \c std::foo is available \anchor cwisetable_isfinite - a.\link ArrayBase::isfinite isfinite\endlink(); \n + a.\link ArrayBase::isFinite isFinite\endlink(); \n \link Eigen::isfinite isfinite\endlink(a); checks if the given number has finite value @@ -377,7 +377,7 @@ This also means that, unless specified, if the function \c std::foo is available \anchor cwisetable_isinf - a.\link ArrayBase::isinf isinf\endlink(); \n + a.\link ArrayBase::isInf isInf\endlink(); \n \link Eigen::isinf isinf\endlink(a); checks if the given number is infinite @@ -388,7 +388,7 @@ This also means that, unless specified, if the function \c std::foo is available \anchor cwisetable_isnan - a.\link ArrayBase::isnan isnan\endlink(); \n + a.\link ArrayBase::isNaN isNaN\endlink(); \n \link Eigen::isnan isnan\endlink(a); checks if the given number is not a number @@ -399,7 +399,7 @@ This also means that, unless specified, if the function \c std::foo is available Error and gamma functions - Require \c #include \c + Require \c \#include \c \anchor cwisetable_erf @@ -478,7 +478,7 @@ This also means that, unless specified, if the function \c std::foo is available Special functions - Require \c #include \c + Require \c \#include \c \anchor cwisetable_polygamma @@ -522,4 +522,4 @@ This also means that, unless specified, if the function \c std::foo is available */ -} \ No newline at end of file +} diff --git a/doc/Doxyfile.in b/doc/Doxyfile.in index cac2d1948..48bb0a8ec 100644 --- a/doc/Doxyfile.in +++ b/doc/Doxyfile.in @@ -727,7 +727,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" \ diff --git a/doc/PreprocessorDirectives.dox b/doc/PreprocessorDirectives.dox index c4b9903c1..f01b39aec 100644 --- a/doc/PreprocessorDirectives.dox +++ b/doc/PreprocessorDirectives.dox @@ -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. diff --git a/doc/QuickReference.dox b/doc/QuickReference.dox index e19c7e3a4..44f5410db 100644 --- a/doc/QuickReference.dox +++ b/doc/QuickReference.dox @@ -340,7 +340,7 @@ mat1 = mat2.adjoint(); mat1.adjointInPlace(); \endcode -\link MatrixBase::dot() dot \endlink product \n inner product \matrixworld\code +\link MatrixBase::dot dot \endlink product \n inner product \matrixworld\code scalar = vec1.dot(vec2); scalar = col1.adjoint() * col2; scalar = (col1.adjoint() * col2).value();\endcode -- cgit v1.2.3 From f3f026c9aacfc3ad28c54b4f5287b7b58e62d8ac Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Thu, 5 Jan 2017 13:36:08 +0100 Subject: Convert integers to real numbers when computing relative L2 error --- test/main.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/test/main.h b/test/main.h index ea27b9715..1d5bdc1c4 100644 --- a/test/main.h +++ b/test/main.h @@ -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::RealScalar test_relative_error(const EigenBase &a, const EigenBase &b) +typename NumTraits::NonInteger test_relative_error(const EigenBase &a, const EigenBase &b) { using std::sqrt; - typedef typename T1::RealScalar RealScalar; + typedef typename NumTraits::NonInteger RealScalar; typename internal::nested_eval::type ea(a.derived()); typename internal::nested_eval::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 &a, const } template -typename NumTraits::Real test_relative_error(const T1 &a, const T2 &b, typename internal::enable_if::Real>::value, T1>::type* = 0) +typename NumTraits::Real>::NonInteger test_relative_error(const T1 &a, const T2 &b, typename internal::enable_if::Real>::value, T1>::type* = 0) { - typedef typename NumTraits::Real RealScalar; + typedef typename NumTraits::Real>::NonInteger RealScalar; return numext::sqrt(RealScalar(numext::abs2(a-b))/RealScalar((numext::mini)(numext::abs2(a),numext::abs2(b)))); } -- cgit v1.2.3 From ac7e4ac9c071ee879e9da278a9a2cf6cef82f053 Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Fri, 6 Jan 2017 00:01:44 +0100 Subject: Initial commit to add a generic indexed-based view of matrices. This version already works as a read-only expression. Numerous refactoring, renaming, extension, tuning passes are expected... --- Eigen/Core | 2 + Eigen/src/Core/ArithmeticSequence.h | 229 ++++++++++++++++++++++++++++++ Eigen/src/Core/DenseBase.h | 9 ++ Eigen/src/Core/IndexedView.h | 137 ++++++++++++++++++ Eigen/src/Core/util/ForwardDeclarations.h | 1 + 5 files changed, 378 insertions(+) create mode 100644 Eigen/src/Core/ArithmeticSequence.h create mode 100644 Eigen/src/Core/IndexedView.h diff --git a/Eigen/Core b/Eigen/Core index 16be82ac2..a93e3ce65 100644 --- a/Eigen/Core +++ b/Eigen/Core @@ -418,6 +418,7 @@ using std::ptrdiff_t; // on CUDA devices #include "src/Core/arch/CUDA/Complex.h" +#include "src/Core/ArithmeticSequence.h" #include "src/Core/DenseCoeffsBase.h" #include "src/Core/DenseBase.h" #include "src/Core/MatrixBase.h" @@ -458,6 +459,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" diff --git a/Eigen/src/Core/ArithmeticSequence.h b/Eigen/src/Core/ArithmeticSequence.h new file mode 100644 index 000000000..3439a2586 --- /dev/null +++ b/Eigen/src/Core/ArithmeticSequence.h @@ -0,0 +1,229 @@ +// This file is part of Eigen, a lightweight C++ template library +// for linear algebra. +// +// Copyright (C) 2017 Gael Guennebaud +// +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If 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 { + + +struct all_t { all_t() {} }; +static const all_t all; + +struct shifted_last { + explicit shifted_last(int o) : offset(o) {} + int offset; + shifted_last operator+ (int x) const { return shifted_last(offset+x); } + shifted_last operator- (int x) const { return shifted_last(offset-x); } + int operator- (shifted_last x) const { return offset-x.offset; } +}; + +struct last_t { + last_t() {} + shifted_last operator- (int offset) const { return shifted_last(-offset); } + shifted_last operator+ (int offset) const { return shifted_last(+offset); } + int operator- (last_t) const { return 0; } + int operator- (shifted_last x) const { return -x.offset; } +}; +static const last_t last; + + +struct shifted_end { + explicit shifted_end(int o) : offset(o) {} + int offset; + shifted_end operator+ (int x) const { return shifted_end(offset+x); } + shifted_end operator- (int x) const { return shifted_end(offset-x); } + int operator- (shifted_end x) const { return offset-x.offset; } +}; + +struct end_t { + end_t() {} + shifted_end operator- (int offset) const { return shifted_end (-offset); } + shifted_end operator+ (int offset) const { return shifted_end ( offset); } + int operator- (end_t) const { return 0; } + int operator- (shifted_end x) const { return -x.offset; } +}; +static const end_t end; + +template struct Index_c { + static const int value = N; + operator int() const { return value; } + Index_c (Index_c (*)() ) {} + Index_c() {} + // Needed in C++14 to allow c(): + Index_c operator() () const { return *this; } +}; + +//-------------------------------------------------------------------------------- +// Range(first,last) and Slice(first,step,last) +//-------------------------------------------------------------------------------- + +template > +struct Range_t { + Range_t(FirstType f, LastType l) : m_first(f), m_last(l) {} + Range_t(FirstType f, LastType l, StepType s) : m_first(f), m_last(l), m_step(s) {} + + FirstType m_first; + LastType m_last; + StepType m_step; + + enum { SizeAtCompileTime = -1 }; + + Index size() const { return (m_last-m_first+m_step)/m_step; } + Index operator[] (Index k) const { return m_first + k*m_step; } +}; + +template struct cleanup_slice_type { typedef Index type; }; +template<> struct cleanup_slice_type { typedef last_t type; }; +template<> struct cleanup_slice_type { typedef shifted_last type; }; +template<> struct cleanup_slice_type { typedef end_t type; }; +template<> struct cleanup_slice_type { typedef shifted_end type; }; +template struct cleanup_slice_type > { typedef Index_c type; }; +template struct cleanup_slice_type (*)() > { typedef Index_c type; }; + +template +Range_t::type,typename cleanup_slice_type::type > +range(FirstType f, LastType l) { + return Range_t::type,typename cleanup_slice_type::type>(f,l); +} + +template +Range_t::type,typename cleanup_slice_type::type,typename cleanup_slice_type::type > +range(FirstType f, LastType l, StepType s) { + return Range_t::type,typename cleanup_slice_type::type,typename cleanup_slice_type::type>(f,l,typename cleanup_slice_type::type(s)); +} + + +template struct get_compile_time { + enum { value = Default }; +}; + +template struct get_compile_time,Default> { + enum { value = N }; +}; + +template struct is_compile_time { enum { value = false }; }; +template struct is_compile_time > { enum { value = true }; }; + +template > +struct Span_t { + Span_t(FirstType first, SizeType size) : m_first(first), m_size(size) {} + Span_t(FirstType first, SizeType size, StepType step) : m_first(first), m_size(size), m_step(step) {} + + FirstType m_first; + SizeType m_size; + StepType m_step; + + enum { SizeAtCompileTime = get_compile_time::value }; + + Index size() const { return m_size; } + Index operator[] (Index k) const { return m_first + k*m_step; } +}; + +template +Span_t::type,typename cleanup_slice_type::type,typename cleanup_slice_type::type > +span(FirstType first, SizeType size, StepType step) { + return Span_t::type,typename cleanup_slice_type::type,typename cleanup_slice_type::type>(first,size,step); +} + +template +Span_t::type,typename cleanup_slice_type::type > +span(FirstType first, SizeType size) { + return Span_t::type,typename cleanup_slice_type::type>(first,size); +} + +#if __cplusplus > 201103L +template +static const Index_c c{}; +#else +template +inline Index_c c() { return Index_c(); } +#endif + +namespace internal { + +// MakeIndexing/make_indexing turn an arbitrary object of type T into something usable by MatrixSlice +template +struct MakeIndexing { + typedef T type; +}; + +template +const T& make_indexing(const T& x, Index size) { return x; } + +struct IntAsArray { + IntAsArray(Index val) : m_value(val) {} + Index operator[](Index) const { return m_value; } + Index size() const { return 1; } + Index m_value; +}; + +// Turn a single index into something that looks like an array (i.e., that exposes a .size(), and operatro[](int) methods) +template +struct MakeIndexing::value>::type> { + // Here we could simply use Array, but maybe it's less work for the compiler to use + // a simpler wrapper as IntAsArray + //typedef Eigen::Array type; + typedef IntAsArray type; +}; + +// Replace symbolic last/end "keywords" by their true runtime value +Index symbolic2value(Index x, Index /* size */) { return x; } +Index symbolic2value(last_t, Index size) { return size-1; } +Index symbolic2value(shifted_last x, Index size) { return size+x.offset-1; } +Index symbolic2value(end_t, Index size) { return size; } +Index symbolic2value(shifted_end x, Index size) { return size+x.offset; } + +// Convert a symbolic range into a usable one (i.e., remove last/end "keywords") +template +struct MakeIndexing > { + typedef Range_t type; +}; + +template +Range_t make_indexing(const Range_t& ids, Index size) { + return Range_t(symbolic2value(ids.m_first,size),symbolic2value(ids.m_last,size),ids.m_step); +} + +// Convert a symbolic span into a usable one (i.e., remove last/end "keywords") +template +struct MakeIndexing > { + typedef Span_t type; +}; + +template +Span_t make_indexing(const Span_t& ids, Index size) { + return Span_t(symbolic2value(ids.m_first,size),ids.m_size,ids.m_step); +} + +// Convert a symbolic 'all' into a usable range +// Implementation-wise, it would be more efficient to not having to store m_size since +// this information is already in the nested expression. To this end, we would need a +// get_size(indices, underlying_size); function returning indices.size() by default. +struct AllRange { + AllRange(Index size) : m_size(size) {} + Index operator[](Index i) const { return i; } + Index size() const { return m_size; } + Index m_size; +}; + +template<> +struct MakeIndexing { + typedef AllRange type; +}; + +AllRange make_indexing(all_t , Index size) { + return AllRange(size); +} + +} // end namespace internal + +} // end namespace Eigen + +#endif // EIGEN_ARITHMETIC_SEQUENCE_H diff --git a/Eigen/src/Core/DenseBase.h b/Eigen/src/Core/DenseBase.h index 9f3c7c8a9..f8a6b2625 100644 --- a/Eigen/src/Core/DenseBase.h +++ b/Eigen/src/Core/DenseBase.h @@ -557,6 +557,15 @@ template class DenseBase } EIGEN_DEVICE_FUNC void reverseInPlace(); + template + typename internal::enable_if< + !(internal::is_integral::value && internal::is_integral::value), + IndexedView::type,typename internal::MakeIndexing::type> >::type + operator()(const RowIndices& rowIndices, const ColIndices& colIndices) const { + return IndexedView::type,typename internal::MakeIndexing::type>( + derived(), internal::make_indexing(rowIndices,derived().rows()), internal::make_indexing(colIndices,derived().cols())); + } + #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) diff --git a/Eigen/src/Core/IndexedView.h b/Eigen/src/Core/IndexedView.h new file mode 100644 index 000000000..e11739a99 --- /dev/null +++ b/Eigen/src/Core/IndexedView.h @@ -0,0 +1,137 @@ +// This file is part of Eigen, a lightweight C++ template library +// for linear algebra. +// +// Copyright (C) 2017 Gael Guennebaud +// +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If 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 +struct traits > + : traits +{ + enum { + FlagsLvalueBit = is_lvalue::value ? LvalueBit : 0, + Flags = traits::Flags & (RowMajorBit | FlagsLvalueBit /*| DirectAccessBit*/), + //MatrixTypeInnerStride = inner_stride_at_compile_time::ret, + InnerStrideAtCompileTime = int(Dynamic), + OuterStrideAtCompileTime = int(Dynamic) + }; +}; + +} + +template +class IndexedViewImpl; + +// Expression of a generic slice +template +class IndexedView : public IndexedViewImpl::StorageKind> +{ +public: + typedef typename IndexedViewImpl::StorageKind>::Base Base; + EIGEN_GENERIC_PUBLIC_INTERFACE(IndexedView) + + typedef typename internal::ref_selector::non_const_type MatrixTypeNested; + typedef typename internal::remove_all::type NestedExpression; + + template + IndexedView(XprType& xpr, const T0& rowIndices, const T1& colIndices) + : m_xpr(xpr), m_rowIndices(rowIndices), m_colIndices(colIndices) + {} + Index rows() const { return m_rowIndices.size(); } + Index cols() const { return m_colIndices.size(); } + + /** \returns the nested expression */ + const typename internal::remove_all::type& + nestedExpression() const { return m_xpr; } + + /** \returns the nested expression */ + typename internal::remove_reference::type& + nestedExpression() { return m_xpr.const_cast_derived(); } + + const RowIndices& rowIndices() const { return m_rowIndices; } + const ColIndices& colIndices() const { return m_colIndices; } + +// std::pair index(Index i, Index j) const { +// return std::pair(m_rowIndices[i], m_colIndices[j]); +// } +// +// void print() const { +// for(Index i=0; i k = index(i,j); +// std::cout << '(' << k.first << ',' << k.second << ") "; +// } +// std::cout << '\n'; +// } +// } +protected: + MatrixTypeNested m_xpr; + RowIndices m_rowIndices; + ColIndices m_colIndices; +}; + + +// Generic API dispatcher +template +class IndexedViewImpl + : public internal::generic_xpr_base >::type +{ +public: + typedef typename internal::generic_xpr_base >::type Base; +}; + +namespace internal { + + +template +struct unary_evaluator, IndexBased> + : evaluator_base > +{ + typedef IndexedView XprType; + + enum { + CoeffReadCost = evaluator::CoeffReadCost /* + cost of row/col index */, + + Flags = (evaluator::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]); + } + +protected: + + evaluator m_argImpl; + const XprType& m_xpr; + +}; + +} // end namespace internal + +} // end namespace Eigen + +#endif // EIGEN_INDEXED_VIEW_H diff --git a/Eigen/src/Core/util/ForwardDeclarations.h b/Eigen/src/Core/util/ForwardDeclarations.h index ea107393a..1a48cff04 100644 --- a/Eigen/src/Core/util/ForwardDeclarations.h +++ b/Eigen/src/Core/util/ForwardDeclarations.h @@ -83,6 +83,7 @@ template class ForceAlignedAccess; template class SwapWrapper; template class Block; +template class IndexedView; template class VectorBlock; template class Transpose; -- cgit v1.2.3 From 60e99ad8d76c167a48dab82d2fc16a87956fd7a4 Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Fri, 6 Jan 2017 11:59:08 +0100 Subject: Add unit test for indexed views --- test/CMakeLists.txt | 1 + test/indexed_view.cpp | 107 ++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 108 insertions(+) create mode 100644 test/indexed_view.cpp diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index e17985107..921d9688c 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -161,6 +161,7 @@ ei_add_test(redux) ei_add_test(visitor) ei_add_test(block) ei_add_test(corners) +ei_add_test(indexed_view) ei_add_test(swap) ei_add_test(resize) ei_add_test(conservative_resize) diff --git a/test/indexed_view.cpp b/test/indexed_view.cpp new file mode 100644 index 000000000..1bb2b4256 --- /dev/null +++ b/test/indexed_view.cpp @@ -0,0 +1,107 @@ +// This file is part of Eigen, a lightweight C++ template library +// for linear algebra. +// +// Copyright (C) 2017 Gael Guennebaud +// +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#include +#include +#include "main.h" + +typedef std::pair IndexPair; + +Index encode(Index i, Index j) { + return i*100 + j; +} + +IndexPair decode(Index ij) { + return IndexPair(ij / 100, ij % 100); +} + +template +bool match(const T& xpr, std::string ref, std::string str_xpr = "") { + std::cout << str_xpr << "\n" << xpr << "\n\n"; + std::stringstream str; + str << xpr; + return str.str() == ref; +} + +#define MATCH(X,R) match(X, R, #X) + +void check_indexed_view() +{ + Index n = 10; + + ArrayXXi A = ArrayXXi::NullaryExpr(n,n, std::ptr_fun(encode)); + + for(Index i=0; i vala(10); Map(&vala[0],10) = eia; + std::valarray vali(4); Map(&vali[0],4) = eii; + std::vector veci(4); Map(veci.data(),4) = eii; + + VERIFY( MATCH( A(3, range(9,3,-1)), + "309 308 307 306 305 304 303") + ); + + VERIFY( MATCH( A(span(2,5), range(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(span(2,5), 5), + "205\n" + "305\n" + "405\n" + "505\n" + "605") + ); + + VERIFY( MATCH( A(span(last,5,-1), range(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(span(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") + ); + +} + +void test_indexed_view() +{ +// for(int i = 0; i < g_repeat; i++) { + CALL_SUBTEST_1( check_indexed_view() ); +// } +} -- cgit v1.2.3 From 3730e3ca9ec8e256b76c08fb4b1e928c62f37b40 Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Fri, 6 Jan 2017 13:10:10 +0100 Subject: Use "fix" for compile-time values, propagate compile-time sizes for span, clean some cleanup. --- Eigen/src/Core/ArithmeticSequence.h | 134 ++++++++++++++++++++++-------------- Eigen/src/Core/IndexedView.h | 13 +++- test/indexed_view.cpp | 15 +++- 3 files changed, 106 insertions(+), 56 deletions(-) diff --git a/Eigen/src/Core/ArithmeticSequence.h b/Eigen/src/Core/ArithmeticSequence.h index 3439a2586..1e7812c8c 100644 --- a/Eigen/src/Core/ArithmeticSequence.h +++ b/Eigen/src/Core/ArithmeticSequence.h @@ -12,6 +12,9 @@ namespace Eigen { +//-------------------------------------------------------------------------------- +// Pseudo keywords: all, last, end +//-------------------------------------------------------------------------------- struct all_t { all_t() {} }; static const all_t all; @@ -51,32 +54,55 @@ struct end_t { }; static const end_t end; -template struct Index_c { +//-------------------------------------------------------------------------------- +// integral constant +//-------------------------------------------------------------------------------- + +template struct fix_t { static const int value = N; operator int() const { return value; } - Index_c (Index_c (*)() ) {} - Index_c() {} - // Needed in C++14 to allow c(): - Index_c operator() () const { return *this; } + fix_t (fix_t (*)() ) {} + fix_t() {} + // Needed in C++14 to allow fix(): + fix_t operator() () const { return *this; } }; +template struct get_compile_time { + enum { value = Default }; +}; + +template struct get_compile_time,Default> { + enum { value = N }; +}; + +template struct is_compile_time { enum { value = false }; }; +template struct is_compile_time > { enum { value = true }; }; + +#if __cplusplus > 201103L +template +static const fix_t fix{}; +#else +template +inline fix_t fix() { return fix_t(); } +#endif + //-------------------------------------------------------------------------------- -// Range(first,last) and Slice(first,step,last) +// range(first,last,incr) and span(first,size,incr) //-------------------------------------------------------------------------------- -template > +template > struct Range_t { Range_t(FirstType f, LastType l) : m_first(f), m_last(l) {} - Range_t(FirstType f, LastType l, StepType s) : m_first(f), m_last(l), m_step(s) {} + Range_t(FirstType f, LastType l, IncrType s) : m_first(f), m_last(l), m_incr(s) {} FirstType m_first; LastType m_last; - StepType m_step; + IncrType m_incr; enum { SizeAtCompileTime = -1 }; - Index size() const { return (m_last-m_first+m_step)/m_step; } - Index operator[] (Index k) const { return m_first + k*m_step; } + Index size() const { return (m_last-m_first+m_incr)/m_incr; } + Index operator[] (Index k) const { return m_first + k*m_incr; } }; template struct cleanup_slice_type { typedef Index type; }; @@ -84,8 +110,8 @@ template<> struct cleanup_slice_type { typedef last_t type; }; template<> struct cleanup_slice_type { typedef shifted_last type; }; template<> struct cleanup_slice_type { typedef end_t type; }; template<> struct cleanup_slice_type { typedef shifted_end type; }; -template struct cleanup_slice_type > { typedef Index_c type; }; -template struct cleanup_slice_type (*)() > { typedef Index_c type; }; +template struct cleanup_slice_type > { typedef fix_t type; }; +template struct cleanup_slice_type (*)() > { typedef fix_t type; }; template Range_t::type,typename cleanup_slice_type::type > @@ -93,43 +119,34 @@ range(FirstType f, LastType l) { return Range_t::type,typename cleanup_slice_type::type>(f,l); } -template -Range_t::type,typename cleanup_slice_type::type,typename cleanup_slice_type::type > -range(FirstType f, LastType l, StepType s) { - return Range_t::type,typename cleanup_slice_type::type,typename cleanup_slice_type::type>(f,l,typename cleanup_slice_type::type(s)); +template +Range_t::type,typename cleanup_slice_type::type,typename cleanup_slice_type::type > +range(FirstType f, LastType l, IncrType s) { + return Range_t::type,typename cleanup_slice_type::type,typename cleanup_slice_type::type>(f,l,typename cleanup_slice_type::type(s)); } -template struct get_compile_time { - enum { value = Default }; -}; -template struct get_compile_time,Default> { - enum { value = N }; -}; -template struct is_compile_time { enum { value = false }; }; -template struct is_compile_time > { enum { value = true }; }; - -template > +template > struct Span_t { Span_t(FirstType first, SizeType size) : m_first(first), m_size(size) {} - Span_t(FirstType first, SizeType size, StepType step) : m_first(first), m_size(size), m_step(step) {} + Span_t(FirstType first, SizeType size, IncrType incr) : m_first(first), m_size(size), m_incr(incr) {} FirstType m_first; SizeType m_size; - StepType m_step; + IncrType m_incr; enum { SizeAtCompileTime = get_compile_time::value }; Index size() const { return m_size; } - Index operator[] (Index k) const { return m_first + k*m_step; } + Index operator[] (Index k) const { return m_first + k*m_incr; } }; -template -Span_t::type,typename cleanup_slice_type::type,typename cleanup_slice_type::type > -span(FirstType first, SizeType size, StepType step) { - return Span_t::type,typename cleanup_slice_type::type,typename cleanup_slice_type::type>(first,size,step); +template +Span_t::type,typename cleanup_slice_type::type,typename cleanup_slice_type::type > +span(FirstType first, SizeType size, IncrType incr) { + return Span_t::type,typename cleanup_slice_type::type,typename cleanup_slice_type::type>(first,size,incr); } template @@ -138,16 +155,24 @@ span(FirstType first, SizeType size) { return Span_t::type,typename cleanup_slice_type::type>(first,size); } -#if __cplusplus > 201103L -template -static const Index_c c{}; -#else -template -inline Index_c c() { return Index_c(); } -#endif + namespace internal { +template struct get_compile_time_size { + enum { value = -1 }; +}; + +template struct get_compile_time_size::type> { + enum { value = T::SizeAtCompileTime }; +}; + +#ifdef EIGEN_HAS_CXX11 +template struct get_compile_time_size > { + enum { value = N }; +}; +#endif + // MakeIndexing/make_indexing turn an arbitrary object of type T into something usable by MatrixSlice template struct MakeIndexing { @@ -158,6 +183,9 @@ template const T& make_indexing(const T& x, Index size) { return x; } struct IntAsArray { + enum { + SizeAtCompileTime = 1 + }; IntAsArray(Index val) : m_value(val) {} Index operator[](Index) const { return m_value; } Index size() const { return 1; } @@ -181,25 +209,25 @@ Index symbolic2value(end_t, Index size) { return size; } Index symbolic2value(shifted_end x, Index size) { return size+x.offset; } // Convert a symbolic range into a usable one (i.e., remove last/end "keywords") -template -struct MakeIndexing > { - typedef Range_t type; +template +struct MakeIndexing > { + typedef Range_t type; }; -template -Range_t make_indexing(const Range_t& ids, Index size) { - return Range_t(symbolic2value(ids.m_first,size),symbolic2value(ids.m_last,size),ids.m_step); +template +Range_t make_indexing(const Range_t& ids, Index size) { + return Range_t(symbolic2value(ids.m_first,size),symbolic2value(ids.m_last,size),ids.m_incr); } // Convert a symbolic span into a usable one (i.e., remove last/end "keywords") -template -struct MakeIndexing > { - typedef Span_t type; +template +struct MakeIndexing > { + typedef Span_t type; }; -template -Span_t make_indexing(const Span_t& ids, Index size) { - return Span_t(symbolic2value(ids.m_first,size),ids.m_size,ids.m_step); +template +Span_t make_indexing(const Span_t& ids, Index size) { + return Span_t(symbolic2value(ids.m_first,size),ids.m_size,ids.m_incr); } // Convert a symbolic 'all' into a usable range diff --git a/Eigen/src/Core/IndexedView.h b/Eigen/src/Core/IndexedView.h index e11739a99..7fc856feb 100644 --- a/Eigen/src/Core/IndexedView.h +++ b/Eigen/src/Core/IndexedView.h @@ -19,8 +19,19 @@ struct traits > : traits { enum { + RowsAtCompileTime = get_compile_time_size::value, + ColsAtCompileTime = get_compile_time_size::value, + MaxRowsAtCompileTime = RowsAtCompileTime != Dynamic ? int(RowsAtCompileTime) : int(traits::MaxRowsAtCompileTime), + MaxColsAtCompileTime = ColsAtCompileTime != Dynamic ? int(ColsAtCompileTime) : int(traits::MaxColsAtCompileTime), + + XprTypeIsRowMajor = (int(traits::Flags)&RowMajorBit) != 0, + IsRowMajor = (MaxRowsAtCompileTime==1&&MaxColsAtCompileTime!=1) ? 1 + : (MaxColsAtCompileTime==1&&MaxRowsAtCompileTime!=1) ? 0 + : XprTypeIsRowMajor, + + FlagsRowMajorBit = IsRowMajor ? RowMajorBit : 0, FlagsLvalueBit = is_lvalue::value ? LvalueBit : 0, - Flags = traits::Flags & (RowMajorBit | FlagsLvalueBit /*| DirectAccessBit*/), + Flags = (traits::Flags & HereditaryBits) | FlagsLvalueBit | FlagsRowMajorBit, //MatrixTypeInnerStride = inner_stride_at_compile_time::ret, InnerStrideAtCompileTime = int(Dynamic), OuterStrideAtCompileTime = int(Dynamic) diff --git a/test/indexed_view.cpp b/test/indexed_view.cpp index 1bb2b4256..0be5e434c 100644 --- a/test/indexed_view.cpp +++ b/test/indexed_view.cpp @@ -13,8 +13,8 @@ typedef std::pair IndexPair; -Index encode(Index i, Index j) { - return i*100 + j; +int encode(Index i, Index j) { + return int(i*100 + j); } IndexPair decode(Index ij) { @@ -97,6 +97,17 @@ void check_indexed_view() "300 301 302 303 304 305 306 307 308 309") ); + Array44i B; + VERIFY( (A(span(2,5), 5)).ColsAtCompileTime == 1); + VERIFY( (A(span(2,5), 5)).RowsAtCompileTime == Dynamic); + VERIFY( (A(span(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); + } void test_indexed_view() -- cgit v1.2.3 From fad1fa75b32ccd3a19fc783a0c660ca512283224 Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Fri, 6 Jan 2017 13:29:33 +0100 Subject: Propagate compile-time size with "all" and add c++11 array unit test --- Eigen/src/Core/ArithmeticSequence.h | 10 +++++++--- Eigen/src/Core/IndexedView.h | 4 ++-- test/indexed_view.cpp | 11 +++++++++++ 3 files changed, 20 insertions(+), 5 deletions(-) diff --git a/Eigen/src/Core/ArithmeticSequence.h b/Eigen/src/Core/ArithmeticSequence.h index 1e7812c8c..06b6b53eb 100644 --- a/Eigen/src/Core/ArithmeticSequence.h +++ b/Eigen/src/Core/ArithmeticSequence.h @@ -159,16 +159,16 @@ span(FirstType first, SizeType size) { namespace internal { -template struct get_compile_time_size { +template struct get_compile_time_size { enum { value = -1 }; }; -template struct get_compile_time_size::type> { +template struct get_compile_time_size::type> { enum { value = T::SizeAtCompileTime }; }; #ifdef EIGEN_HAS_CXX11 -template struct get_compile_time_size > { +template struct get_compile_time_size,XprSize> { enum { value = N }; }; #endif @@ -250,6 +250,10 @@ AllRange make_indexing(all_t , Index size) { return AllRange(size); } +template struct get_compile_time_size { + enum { value = XprSize }; +}; + } // end namespace internal } // end namespace Eigen diff --git a/Eigen/src/Core/IndexedView.h b/Eigen/src/Core/IndexedView.h index 7fc856feb..bc1eff8f9 100644 --- a/Eigen/src/Core/IndexedView.h +++ b/Eigen/src/Core/IndexedView.h @@ -19,8 +19,8 @@ struct traits > : traits { enum { - RowsAtCompileTime = get_compile_time_size::value, - ColsAtCompileTime = get_compile_time_size::value, + RowsAtCompileTime = get_compile_time_size::RowsAtCompileTime>::value, + ColsAtCompileTime = get_compile_time_size::ColsAtCompileTime>::value, MaxRowsAtCompileTime = RowsAtCompileTime != Dynamic ? int(RowsAtCompileTime) : int(traits::MaxRowsAtCompileTime), MaxColsAtCompileTime = ColsAtCompileTime != Dynamic ? int(ColsAtCompileTime) : int(traits::MaxColsAtCompileTime), diff --git a/test/indexed_view.cpp b/test/indexed_view.cpp index 0be5e434c..5d8ce16ee 100644 --- a/test/indexed_view.cpp +++ b/test/indexed_view.cpp @@ -11,6 +11,10 @@ #include #include "main.h" +#if EIGEN_HAS_CXX11 +#include +#endif + typedef std::pair IndexPair; int encode(Index i, Index j) { @@ -108,6 +112,13 @@ void check_indexed_view() VERIFY( (B(all,1)).ColsAtCompileTime == 1); VERIFY( (B(all,1)).RowsAtCompileTime == 4); + VERIFY( (A(all, eii)).ColsAtCompileTime == eii.SizeAtCompileTime); +#if EIGEN_HAS_CXX11 + VERIFY( (A(all, std::array{{1,3,2,4}})).ColsAtCompileTime == 4); + + VERIFY_IS_APPROX( (A(std::array{{1,3,5}}, std::array{{9,6,3,0}})), A(span(1,3,2), span(9,4,-3)) ); +#endif + } void test_indexed_view() -- cgit v1.2.3 From e383d6159af1b726ebcd1bed3f082fe9e52275af Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Fri, 6 Jan 2017 15:44:13 +0100 Subject: MSVC 2015 has all we want about c++11 and MSVC 2017 fails on binder1st/binder2nd --- Eigen/src/Core/functors/StlFunctors.h | 2 +- Eigen/src/Core/util/Macros.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Eigen/src/Core/functors/StlFunctors.h b/Eigen/src/Core/functors/StlFunctors.h index 0b4e5a29d..6df3fa501 100644 --- a/Eigen/src/Core/functors/StlFunctors.h +++ b/Eigen/src/Core/functors/StlFunctors.h @@ -72,7 +72,7 @@ template struct functor_traits > { 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 struct functor_traits > diff --git a/Eigen/src/Core/util/Macros.h b/Eigen/src/Core/util/Macros.h index 95960b448..14addd8fb 100644 --- a/Eigen/src/Core/util/Macros.h +++ b/Eigen/src/Core/util/Macros.h @@ -356,7 +356,7 @@ #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 -- cgit v1.2.3 From a875167d99cffa76a662de5475627d60238f0f36 Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Fri, 6 Jan 2017 15:54:55 +0100 Subject: Propagate compile-time increment and strides. Had to introduce a UndefinedIncr constant for non structured list of indices. --- Eigen/src/Core/ArithmeticSequence.h | 27 +++++++++++++++++++++++++-- Eigen/src/Core/IndexedView.h | 35 ++++++++++++++++------------------- Eigen/src/Core/util/Constants.h | 4 ++++ test/indexed_view.cpp | 27 ++++++++++++++++++++++++++- 4 files changed, 71 insertions(+), 22 deletions(-) diff --git a/Eigen/src/Core/ArithmeticSequence.h b/Eigen/src/Core/ArithmeticSequence.h index 06b6b53eb..1585c1dbf 100644 --- a/Eigen/src/Core/ArithmeticSequence.h +++ b/Eigen/src/Core/ArithmeticSequence.h @@ -160,7 +160,7 @@ span(FirstType first, SizeType size) { namespace internal { template struct get_compile_time_size { - enum { value = -1 }; + enum { value = Dynamic }; }; template struct get_compile_time_size::type> { @@ -173,6 +173,21 @@ template struct get_compile_time_size struct get_compile_time_incr { + enum { value = UndefinedIncr }; +}; + +template +struct get_compile_time_incr > { + enum { value = get_compile_time::value }; +}; + +template +struct get_compile_time_incr > { + enum { value = get_compile_time::value }; +}; + + // MakeIndexing/make_indexing turn an arbitrary object of type T into something usable by MatrixSlice template struct MakeIndexing { @@ -180,7 +195,7 @@ struct MakeIndexing { }; template -const T& make_indexing(const T& x, Index size) { return x; } +const T& make_indexing(const T& x, Index /*size*/) { return x; } struct IntAsArray { enum { @@ -192,6 +207,10 @@ struct IntAsArray { Index m_value; }; +template<> struct get_compile_time_incr { + 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 struct MakeIndexing::value>::type> { @@ -254,6 +273,10 @@ template struct get_compile_time_size { enum { value = XprSize }; }; +template<> struct get_compile_time_incr { + enum { value = 1 }; +}; + } // end namespace internal } // end namespace Eigen diff --git a/Eigen/src/Core/IndexedView.h b/Eigen/src/Core/IndexedView.h index bc1eff8f9..26c048584 100644 --- a/Eigen/src/Core/IndexedView.h +++ b/Eigen/src/Core/IndexedView.h @@ -29,12 +29,24 @@ struct traits > : (MaxColsAtCompileTime==1&&MaxRowsAtCompileTime!=1) ? 0 : XprTypeIsRowMajor, + RowIncr = get_compile_time_incr::value, + ColIncr = get_compile_time_incr::value, + InnerIncr = IsRowMajor ? ColIncr : RowIncr, + OuterIncr = IsRowMajor ? RowIncr : ColIncr, + + HasSameStorageOrderAsXprType = (IsRowMajor == XprTypeIsRowMajor), + XprInnerStride = HasSameStorageOrderAsXprType ? int(inner_stride_at_compile_time::ret) : int(outer_stride_at_compile_time::ret), + XprOuterstride = HasSameStorageOrderAsXprType ? int(outer_stride_at_compile_time::ret) : int(inner_stride_at_compile_time::ret), + + InnerStrideAtCompileTime = InnerIncr<0 || InnerIncr==DynamicIndex || XprInnerStride==Dynamic ? Dynamic : XprInnerStride * InnerIncr, + OuterStrideAtCompileTime = OuterIncr<0 || OuterIncr==DynamicIndex || XprOuterstride==Dynamic ? Dynamic : XprOuterstride * OuterIncr, + + // 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::value ? LvalueBit : 0, - Flags = (traits::Flags & HereditaryBits) | FlagsLvalueBit | FlagsRowMajorBit, - //MatrixTypeInnerStride = inner_stride_at_compile_time::ret, - InnerStrideAtCompileTime = int(Dynamic), - OuterStrideAtCompileTime = int(Dynamic) + Flags = (traits::Flags & (HereditaryBits | DirectAccessMask)) | FlagsLvalueBit | FlagsRowMajorBit }; }; @@ -72,21 +84,6 @@ public: const RowIndices& rowIndices() const { return m_rowIndices; } const ColIndices& colIndices() const { return m_colIndices; } -// std::pair index(Index i, Index j) const { -// return std::pair(m_rowIndices[i], m_colIndices[j]); -// } -// -// void print() const { -// for(Index i=0; i k = index(i,j); -// std::cout << '(' << k.first << ',' << k.second << ") "; -// } -// std::cout << '\n'; -// } -// } protected: MatrixTypeNested m_xpr; RowIndices m_rowIndices; diff --git a/Eigen/src/Core/util/Constants.h b/Eigen/src/Core/util/Constants.h index 7587d6842..5d37e5d04 100644 --- a/Eigen/src/Core/util/Constants.h +++ b/Eigen/src/Core/util/Constants.h @@ -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(). * The value Infinity there means the L-infinity norm. */ diff --git a/test/indexed_view.cpp b/test/indexed_view.cpp index 5d8ce16ee..bc69adf13 100644 --- a/test/indexed_view.cpp +++ b/test/indexed_view.cpp @@ -27,7 +27,8 @@ IndexPair decode(Index ij) { template bool match(const T& xpr, std::string ref, std::string str_xpr = "") { - std::cout << str_xpr << "\n" << xpr << "\n\n"; + EIGEN_UNUSED_VARIABLE(str_xpr); + //std::cout << str_xpr << "\n" << xpr << "\n\n"; std::stringstream str; str << xpr; return str.str() == ref; @@ -102,8 +103,28 @@ void check_indexed_view() ); Array44i B; + B.setRandom(); VERIFY( (A(span(2,5), 5)).ColsAtCompileTime == 1); VERIFY( (A(span(2,5), 5)).RowsAtCompileTime == Dynamic); + VERIFY_IS_EQUAL( (A(span(2,5), 5)).InnerStrideAtCompileTime , A.InnerStrideAtCompileTime); + VERIFY_IS_EQUAL( (A(span(2,5), 5)).OuterStrideAtCompileTime , A.col(5).OuterStrideAtCompileTime); + + VERIFY_IS_EQUAL( (A(5,span(2,5))).InnerStrideAtCompileTime , A.row(5).InnerStrideAtCompileTime); + VERIFY_IS_EQUAL( (A(5,span(2,5))).OuterStrideAtCompileTime , A.row(5).OuterStrideAtCompileTime); + VERIFY_IS_EQUAL( (B(1,span(1,2))).InnerStrideAtCompileTime , B.row(1).InnerStrideAtCompileTime); + VERIFY_IS_EQUAL( (B(1,span(1,2))).OuterStrideAtCompileTime , B.row(1).OuterStrideAtCompileTime); + + VERIFY_IS_EQUAL( (A(span(2,5), range(1,3))).InnerStrideAtCompileTime , A.InnerStrideAtCompileTime); + VERIFY_IS_EQUAL( (A(span(2,5), range(1,3))).OuterStrideAtCompileTime , A.OuterStrideAtCompileTime); + VERIFY_IS_EQUAL( (B(span(1,2), range(1,3))).InnerStrideAtCompileTime , B.InnerStrideAtCompileTime); + VERIFY_IS_EQUAL( (B(span(1,2), range(1,3))).OuterStrideAtCompileTime , B.OuterStrideAtCompileTime); + VERIFY_IS_EQUAL( (A(span(2,5,2), range(1,3,2))).InnerStrideAtCompileTime , Dynamic); + VERIFY_IS_EQUAL( (A(span(2,5,2), range(1,3,2))).OuterStrideAtCompileTime , Dynamic); + VERIFY_IS_EQUAL( (A(span(2,5,fix<2>), range(1,3,fix<3>))).InnerStrideAtCompileTime , 2); + VERIFY_IS_EQUAL( (A(span(2,5,fix<2>), range(1,3,fix<3>))).OuterStrideAtCompileTime , Dynamic); + VERIFY_IS_EQUAL( (B(span(1,2,fix<2>), range(1,3,fix<3>))).InnerStrideAtCompileTime , 2); + VERIFY_IS_EQUAL( (B(span(1,2,fix<2>), range(1,3,fix<3>))).OuterStrideAtCompileTime , 3*4); + VERIFY( (A(span(2,fix<5>), 5)).RowsAtCompileTime == 5); VERIFY( (A(4, all)).ColsAtCompileTime == Dynamic); VERIFY( (A(4, all)).RowsAtCompileTime == 1); @@ -113,6 +134,10 @@ void check_indexed_view() VERIFY( (B(all,1)).RowsAtCompileTime == 4); VERIFY( (A(all, eii)).ColsAtCompileTime == eii.SizeAtCompileTime); + VERIFY_IS_EQUAL( (A(eii, eii)).Flags&DirectAccessBit, (unsigned int)(0)); + VERIFY_IS_EQUAL( (A(eii, eii)).InnerStrideAtCompileTime, 0); + VERIFY_IS_EQUAL( (A(eii, eii)).OuterStrideAtCompileTime, 0); + #if EIGEN_HAS_CXX11 VERIFY( (A(all, std::array{{1,3,2,4}})).ColsAtCompileTime == 4); -- cgit v1.2.3 From 831fffe874d791448ff2040654411383ae260a75 Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Fri, 6 Jan 2017 18:01:29 +0100 Subject: Add missing doc of SparseView --- Eigen/src/SparseCore/SparseView.h | 33 ++++++++++++++++++++++++++++++++- 1 file changed, 32 insertions(+), 1 deletion(-) diff --git a/Eigen/src/SparseCore/SparseView.h b/Eigen/src/SparseCore/SparseView.h index b867877d8..7c4aea743 100644 --- a/Eigen/src/SparseCore/SparseView.h +++ b/Eigen/src/SparseCore/SparseView.h @@ -27,6 +27,20 @@ struct traits > : traits } // 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 class SparseView : public SparseMatrixBase > { @@ -190,6 +204,23 @@ struct unary_evaluator, 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 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::dummy_precision(). + * + * \sa SparseMatrixBase::pruned(), class SparseView */ template const SparseView MatrixBase::sparseView(const Scalar& reference, const typename NumTraits::Real& epsilon) const @@ -198,7 +229,7 @@ const SparseView MatrixBase::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: -- cgit v1.2.3 From 3264d3c761e6b08101e7577b4278119dea42ec09 Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Fri, 6 Jan 2017 21:53:32 +0100 Subject: Add support for plain-array as indices, e.g., mat({1,2,3,4}) --- Eigen/src/Core/ArithmeticSequence.h | 6 ++++++ Eigen/src/Core/DenseBase.h | 7 +++++++ Eigen/src/Core/IndexedView.h | 4 ++-- test/indexed_view.cpp | 8 ++++++++ 4 files changed, 23 insertions(+), 2 deletions(-) diff --git a/Eigen/src/Core/ArithmeticSequence.h b/Eigen/src/Core/ArithmeticSequence.h index 1585c1dbf..bfc586a61 100644 --- a/Eigen/src/Core/ArithmeticSequence.h +++ b/Eigen/src/Core/ArithmeticSequence.h @@ -159,6 +159,12 @@ span(FirstType first, SizeType size) { namespace internal { +template +Index size(const T& x) { return x.size(); } + +template +Index size(const T (&x) [N]) { return N; } + template struct get_compile_time_size { enum { value = Dynamic }; }; diff --git a/Eigen/src/Core/DenseBase.h b/Eigen/src/Core/DenseBase.h index f8a6b2625..13aa3854a 100644 --- a/Eigen/src/Core/DenseBase.h +++ b/Eigen/src/Core/DenseBase.h @@ -566,6 +566,13 @@ template class DenseBase derived(), internal::make_indexing(rowIndices,derived().rows()), internal::make_indexing(colIndices,derived().cols())); } + template + IndexedView::type> + operator()(const RowIndicesT (&rowIndices)[RowIndicesN], const ColIndices& colIndices) const { + return IndexedView::type>( + derived(), rowIndices, internal::make_indexing(colIndices,derived().cols())); + } + #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) diff --git a/Eigen/src/Core/IndexedView.h b/Eigen/src/Core/IndexedView.h index 26c048584..5ff1c1837 100644 --- a/Eigen/src/Core/IndexedView.h +++ b/Eigen/src/Core/IndexedView.h @@ -70,8 +70,8 @@ public: IndexedView(XprType& xpr, const T0& rowIndices, const T1& colIndices) : m_xpr(xpr), m_rowIndices(rowIndices), m_colIndices(colIndices) {} - Index rows() const { return m_rowIndices.size(); } - Index cols() const { return m_colIndices.size(); } + Index rows() const { return internal::size(m_rowIndices); } + Index cols() const { return internal::size(m_colIndices); } /** \returns the nested expression */ const typename internal::remove_all::type& diff --git a/test/indexed_view.cpp b/test/indexed_view.cpp index bc69adf13..4ab1a5251 100644 --- a/test/indexed_view.cpp +++ b/test/indexed_view.cpp @@ -93,6 +93,7 @@ void check_indexed_view() "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(span(3,5,0), all), "300 301 302 303 304 305 306 307 308 309\n" @@ -138,10 +139,17 @@ void check_indexed_view() VERIFY_IS_EQUAL( (A(eii, eii)).InnerStrideAtCompileTime, 0); VERIFY_IS_EQUAL( (A(eii, eii)).OuterStrideAtCompileTime, 0); + + #if EIGEN_HAS_CXX11 VERIFY( (A(all, std::array{{1,3,2,4}})).ColsAtCompileTime == 4); VERIFY_IS_APPROX( (A(std::array{{1,3,5}}, std::array{{9,6,3,0}})), A(span(1,3,2), span(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{{3, 1, 6, 5}}, all) ); +#endif + #endif } -- cgit v1.2.3 From 76e183bd52b5b008c32c2e07428f9672ab8e1c6f Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Fri, 6 Jan 2017 22:01:23 +0100 Subject: Propagate compile-time size for plain arrays --- Eigen/src/Core/ArithmeticSequence.h | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Eigen/src/Core/ArithmeticSequence.h b/Eigen/src/Core/ArithmeticSequence.h index bfc586a61..efab2d631 100644 --- a/Eigen/src/Core/ArithmeticSequence.h +++ b/Eigen/src/Core/ArithmeticSequence.h @@ -173,6 +173,10 @@ template struct get_compile_time_size struct get_compile_time_size { + enum { value = N }; +}; + #ifdef EIGEN_HAS_CXX11 template struct get_compile_time_size,XprSize> { enum { value = N }; -- cgit v1.2.3 From 233dff1b3505dcf0592f11a82ac442b28c577f87 Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Fri, 6 Jan 2017 22:01:53 +0100 Subject: Add support for plain arrays for columns and both rows/columns --- Eigen/src/Core/DenseBase.h | 16 +++++++++++++++- test/indexed_view.cpp | 5 +++++ 2 files changed, 20 insertions(+), 1 deletion(-) diff --git a/Eigen/src/Core/DenseBase.h b/Eigen/src/Core/DenseBase.h index 13aa3854a..07057ce69 100644 --- a/Eigen/src/Core/DenseBase.h +++ b/Eigen/src/Core/DenseBase.h @@ -569,10 +569,24 @@ template class DenseBase template IndexedView::type> operator()(const RowIndicesT (&rowIndices)[RowIndicesN], const ColIndices& colIndices) const { - return IndexedView::type>( + return IndexedView::type>( derived(), rowIndices, internal::make_indexing(colIndices,derived().cols())); } + template + IndexedView::type, const ColIndicesT (&)[ColIndicesN]> + operator()(const RowIndices& rowIndices, const ColIndicesT (&colIndices)[ColIndicesN]) const { + return IndexedView::type,const ColIndicesT (&)[ColIndicesN]>( + derived(), internal::make_indexing(rowIndices,derived().rows()), colIndices); + } + + template + IndexedView + operator()(const RowIndicesT (&rowIndices)[RowIndicesN], const ColIndicesT (&colIndices)[ColIndicesN]) const { + return IndexedView( + derived(), rowIndices, colIndices); + } + #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) diff --git a/test/indexed_view.cpp b/test/indexed_view.cpp index 4ab1a5251..5372a3a90 100644 --- a/test/indexed_view.cpp +++ b/test/indexed_view.cpp @@ -148,6 +148,11 @@ void check_indexed_view() #if (!EIGEN_COMP_CLANG) || (EIGEN_COMP_CLANG>=308 && !defined(__apple_build_version__)) VERIFY_IS_APPROX( A({3, 1, 6, 5}, all), A(std::array{{3, 1, 6, 5}}, all) ); + VERIFY_IS_APPROX( A(all,{3, 1, 6, 5}), A(all,std::array{{3, 1, 6, 5}}) ); + VERIFY_IS_APPROX( A({1,3,5},{3, 1, 6, 5}), A(std::array{{1,3,5}},std::array{{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 ); #endif #endif -- cgit v1.2.3 From 75aef5b37f17f780fdd42ccadd7e13a27a380771 Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Fri, 6 Jan 2017 22:04:49 +0100 Subject: Fix extraction of compile-time size of std::array with gcc --- Eigen/src/Core/ArithmeticSequence.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Eigen/src/Core/ArithmeticSequence.h b/Eigen/src/Core/ArithmeticSequence.h index efab2d631..3b469ba6e 100644 --- a/Eigen/src/Core/ArithmeticSequence.h +++ b/Eigen/src/Core/ArithmeticSequence.h @@ -178,7 +178,7 @@ template struct get_compile_time_size struct get_compile_time_size,XprSize> { +template struct get_compile_time_size,XprSize> { enum { value = N }; }; #endif -- cgit v1.2.3 From ad3eef76082a8d25d27ca6894d128dd47652a4cf Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Mon, 9 Jan 2017 13:01:39 +0100 Subject: Add link to SO --- Eigen/src/Core/Ref.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Eigen/src/Core/Ref.h b/Eigen/src/Core/Ref.h index bdf24f52a..abb1e5121 100644 --- a/Eigen/src/Core/Ref.h +++ b/Eigen/src/Core/Ref.h @@ -184,6 +184,8 @@ protected: * void foo(const Ref >& A) { foo_impl(A); } * \endcode * + * See also the following stackoverflow questions for further references: + * - Correct usage of the Eigen::Ref<> class * * \sa PlainObjectBase::Map(), \ref TopicStorageOrders */ -- cgit v1.2.3 From 68064e14fac8c72c05faaeff98c1b70e2dae6ee7 Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Mon, 9 Jan 2017 17:35:21 +0100 Subject: Rename span/range to seqN/seq --- Eigen/src/Core/ArithmeticSequence.h | 101 ++++++++++++++++++++++-------------- test/indexed_view.cpp | 58 ++++++++++----------- 2 files changed, 89 insertions(+), 70 deletions(-) diff --git a/Eigen/src/Core/ArithmeticSequence.h b/Eigen/src/Core/ArithmeticSequence.h index 3b469ba6e..71301797a 100644 --- a/Eigen/src/Core/ArithmeticSequence.h +++ b/Eigen/src/Core/ArithmeticSequence.h @@ -87,22 +87,33 @@ inline fix_t fix() { return fix_t(); } #endif //-------------------------------------------------------------------------------- -// range(first,last,incr) and span(first,size,incr) +// seq(first,last,incr) and seqN(first,size,incr) //-------------------------------------------------------------------------------- + template > -struct Range_t { - Range_t(FirstType f, LastType l) : m_first(f), m_last(l) {} - Range_t(FirstType f, LastType l, IncrType s) : m_first(f), m_last(l), m_incr(s) {} +class ArithemeticSequenceProxyWithBounds +{ +public: + ArithemeticSequenceProxyWithBounds(FirstType f, LastType l) : m_first(f), m_last(l) {} + ArithemeticSequenceProxyWithBounds(FirstType f, LastType l, IncrType s) : m_first(f), m_last(l), m_incr(s) {} + + enum { + SizeAtCompileTime = -1, + IncrAtCompileTime = get_compile_time::value + }; + + Index size() const { return (m_last-m_first+m_incr)/m_incr; } + Index operator[](Index i) const { return m_first + i * m_incr; } + + const FirstType& firstObject() const { return m_first; } + const LastType& lastObject() const { return m_last; } + const IncrType& incrObject() const { return m_incr; } +protected: FirstType m_first; LastType m_last; IncrType m_incr; - - enum { SizeAtCompileTime = -1 }; - - Index size() const { return (m_last-m_first+m_incr)/m_incr; } - Index operator[] (Index k) const { return m_first + k*m_incr; } }; template struct cleanup_slice_type { typedef Index type; }; @@ -114,45 +125,55 @@ template struct cleanup_slice_type > { typedef fix_t type; }; template struct cleanup_slice_type (*)() > { typedef fix_t type; }; template -Range_t::type,typename cleanup_slice_type::type > -range(FirstType f, LastType l) { - return Range_t::type,typename cleanup_slice_type::type>(f,l); +ArithemeticSequenceProxyWithBounds::type,typename cleanup_slice_type::type > +seq(FirstType f, LastType l) { + return ArithemeticSequenceProxyWithBounds::type,typename cleanup_slice_type::type>(f,l); } template -Range_t::type,typename cleanup_slice_type::type,typename cleanup_slice_type::type > -range(FirstType f, LastType l, IncrType s) { - return Range_t::type,typename cleanup_slice_type::type,typename cleanup_slice_type::type>(f,l,typename cleanup_slice_type::type(s)); +ArithemeticSequenceProxyWithBounds::type,typename cleanup_slice_type::type,typename cleanup_slice_type::type > +seq(FirstType f, LastType l, IncrType s) { + return ArithemeticSequenceProxyWithBounds::type,typename cleanup_slice_type::type,typename cleanup_slice_type::type>(f,l,typename cleanup_slice_type::type(s)); } +template > +class ArithemeticSequenceProxyWithSize +{ +public: + ArithemeticSequenceProxyWithSize(FirstType first, SizeType size) : m_first(first), m_size(size) {} + ArithemeticSequenceProxyWithSize(FirstType first, SizeType size, IncrType incr) : m_first(first), m_size(size), m_incr(incr) {} -template > -struct Span_t { - Span_t(FirstType first, SizeType size) : m_first(first), m_size(size) {} - Span_t(FirstType first, SizeType size, IncrType incr) : m_first(first), m_size(size), m_incr(incr) {} + enum { + SizeAtCompileTime = get_compile_time::value, + IncrAtCompileTime = get_compile_time::value + }; + + Index size() const { return m_size; } + 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; - - enum { SizeAtCompileTime = get_compile_time::value }; - - Index size() const { return m_size; } - Index operator[] (Index k) const { return m_first + k*m_incr; } }; + template -Span_t::type,typename cleanup_slice_type::type,typename cleanup_slice_type::type > -span(FirstType first, SizeType size, IncrType incr) { - return Span_t::type,typename cleanup_slice_type::type,typename cleanup_slice_type::type>(first,size,incr); +ArithemeticSequenceProxyWithSize::type,typename cleanup_slice_type::type,typename cleanup_slice_type::type > +seqN(FirstType first, SizeType size, IncrType incr) { + return ArithemeticSequenceProxyWithSize::type,typename cleanup_slice_type::type,typename cleanup_slice_type::type>(first,size,incr); } template -Span_t::type,typename cleanup_slice_type::type > -span(FirstType first, SizeType size) { - return Span_t::type,typename cleanup_slice_type::type>(first,size); +ArithemeticSequenceProxyWithSize::type,typename cleanup_slice_type::type > +seqN(FirstType first, SizeType size) { + return ArithemeticSequenceProxyWithSize::type,typename cleanup_slice_type::type>(first,size); } @@ -188,12 +209,12 @@ template struct get_compile_time_incr { }; template -struct get_compile_time_incr > { +struct get_compile_time_incr > { enum { value = get_compile_time::value }; }; template -struct get_compile_time_incr > { +struct get_compile_time_incr > { enum { value = get_compile_time::value }; }; @@ -239,24 +260,24 @@ Index symbolic2value(shifted_end x, Index size) { return size+x.offset; } // Convert a symbolic range into a usable one (i.e., remove last/end "keywords") template -struct MakeIndexing > { - typedef Range_t type; +struct MakeIndexing > { + typedef ArithemeticSequenceProxyWithBounds type; }; template -Range_t make_indexing(const Range_t& ids, Index size) { - return Range_t(symbolic2value(ids.m_first,size),symbolic2value(ids.m_last,size),ids.m_incr); +ArithemeticSequenceProxyWithBounds make_indexing(const ArithemeticSequenceProxyWithBounds& ids, Index size) { + return ArithemeticSequenceProxyWithBounds(symbolic2value(ids.firstObject(),size),symbolic2value(ids.lastObject(),size),ids.incrObject()); } // Convert a symbolic span into a usable one (i.e., remove last/end "keywords") template -struct MakeIndexing > { - typedef Span_t type; +struct MakeIndexing > { + typedef ArithemeticSequenceProxyWithSize type; }; template -Span_t make_indexing(const Span_t& ids, Index size) { - return Span_t(symbolic2value(ids.m_first,size),ids.m_size,ids.m_incr); +ArithemeticSequenceProxyWithSize make_indexing(const ArithemeticSequenceProxyWithSize& ids, Index size) { + return ArithemeticSequenceProxyWithSize(symbolic2value(ids.firstObject(),size),ids.sizeObject(),ids.incrObject()); } // Convert a symbolic 'all' into a usable range diff --git a/test/indexed_view.cpp b/test/indexed_view.cpp index 5372a3a90..23ad2d743 100644 --- a/test/indexed_view.cpp +++ b/test/indexed_view.cpp @@ -52,11 +52,11 @@ void check_indexed_view() std::valarray vali(4); Map(&vali[0],4) = eii; std::vector veci(4); Map(veci.data(),4) = eii; - VERIFY( MATCH( A(3, range(9,3,-1)), + VERIFY( MATCH( A(3, seq(9,3,-1)), "309 308 307 306 305 304 303") ); - VERIFY( MATCH( A(span(2,5), range(9,3,-1)), + 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" @@ -64,7 +64,7 @@ void check_indexed_view() "609 608 607 606 605 604 603") ); - VERIFY( MATCH( A(span(2,5), 5), + VERIFY( MATCH( A(seqN(2,5), 5), "205\n" "305\n" "405\n" @@ -72,7 +72,7 @@ void check_indexed_view() "605") ); - VERIFY( MATCH( A(span(last,5,-1), range(2,last)), + 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" @@ -95,7 +95,7 @@ void check_indexed_view() ); // takes the row numer 3, and repeat it 5 times - VERIFY( MATCH( A(span(3,5,0), all), + 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" @@ -105,28 +105,28 @@ void check_indexed_view() Array44i B; B.setRandom(); - VERIFY( (A(span(2,5), 5)).ColsAtCompileTime == 1); - VERIFY( (A(span(2,5), 5)).RowsAtCompileTime == Dynamic); - VERIFY_IS_EQUAL( (A(span(2,5), 5)).InnerStrideAtCompileTime , A.InnerStrideAtCompileTime); - VERIFY_IS_EQUAL( (A(span(2,5), 5)).OuterStrideAtCompileTime , A.col(5).OuterStrideAtCompileTime); - - VERIFY_IS_EQUAL( (A(5,span(2,5))).InnerStrideAtCompileTime , A.row(5).InnerStrideAtCompileTime); - VERIFY_IS_EQUAL( (A(5,span(2,5))).OuterStrideAtCompileTime , A.row(5).OuterStrideAtCompileTime); - VERIFY_IS_EQUAL( (B(1,span(1,2))).InnerStrideAtCompileTime , B.row(1).InnerStrideAtCompileTime); - VERIFY_IS_EQUAL( (B(1,span(1,2))).OuterStrideAtCompileTime , B.row(1).OuterStrideAtCompileTime); - - VERIFY_IS_EQUAL( (A(span(2,5), range(1,3))).InnerStrideAtCompileTime , A.InnerStrideAtCompileTime); - VERIFY_IS_EQUAL( (A(span(2,5), range(1,3))).OuterStrideAtCompileTime , A.OuterStrideAtCompileTime); - VERIFY_IS_EQUAL( (B(span(1,2), range(1,3))).InnerStrideAtCompileTime , B.InnerStrideAtCompileTime); - VERIFY_IS_EQUAL( (B(span(1,2), range(1,3))).OuterStrideAtCompileTime , B.OuterStrideAtCompileTime); - VERIFY_IS_EQUAL( (A(span(2,5,2), range(1,3,2))).InnerStrideAtCompileTime , Dynamic); - VERIFY_IS_EQUAL( (A(span(2,5,2), range(1,3,2))).OuterStrideAtCompileTime , Dynamic); - VERIFY_IS_EQUAL( (A(span(2,5,fix<2>), range(1,3,fix<3>))).InnerStrideAtCompileTime , 2); - VERIFY_IS_EQUAL( (A(span(2,5,fix<2>), range(1,3,fix<3>))).OuterStrideAtCompileTime , Dynamic); - VERIFY_IS_EQUAL( (B(span(1,2,fix<2>), range(1,3,fix<3>))).InnerStrideAtCompileTime , 2); - VERIFY_IS_EQUAL( (B(span(1,2,fix<2>), range(1,3,fix<3>))).OuterStrideAtCompileTime , 3*4); - - VERIFY( (A(span(2,fix<5>), 5)).RowsAtCompileTime == 5); + VERIFY( (A(seqN(2,5), 5)).ColsAtCompileTime == 1); + VERIFY( (A(seqN(2,5), 5)).RowsAtCompileTime == Dynamic); + VERIFY_IS_EQUAL( (A(seqN(2,5), 5)).InnerStrideAtCompileTime , A.InnerStrideAtCompileTime); + VERIFY_IS_EQUAL( (A(seqN(2,5), 5)).OuterStrideAtCompileTime , A.col(5).OuterStrideAtCompileTime); + + VERIFY_IS_EQUAL( (A(5,seqN(2,5))).InnerStrideAtCompileTime , A.row(5).InnerStrideAtCompileTime); + VERIFY_IS_EQUAL( (A(5,seqN(2,5))).OuterStrideAtCompileTime , A.row(5).OuterStrideAtCompileTime); + VERIFY_IS_EQUAL( (B(1,seqN(1,2))).InnerStrideAtCompileTime , B.row(1).InnerStrideAtCompileTime); + VERIFY_IS_EQUAL( (B(1,seqN(1,2))).OuterStrideAtCompileTime , B.row(1).OuterStrideAtCompileTime); + + VERIFY_IS_EQUAL( (A(seqN(2,5), seq(1,3))).InnerStrideAtCompileTime , A.InnerStrideAtCompileTime); + VERIFY_IS_EQUAL( (A(seqN(2,5), seq(1,3))).OuterStrideAtCompileTime , A.OuterStrideAtCompileTime); + VERIFY_IS_EQUAL( (B(seqN(1,2), seq(1,3))).InnerStrideAtCompileTime , B.InnerStrideAtCompileTime); + VERIFY_IS_EQUAL( (B(seqN(1,2), seq(1,3))).OuterStrideAtCompileTime , B.OuterStrideAtCompileTime); + VERIFY_IS_EQUAL( (A(seqN(2,5,2), seq(1,3,2))).InnerStrideAtCompileTime , Dynamic); + VERIFY_IS_EQUAL( (A(seqN(2,5,2), seq(1,3,2))).OuterStrideAtCompileTime , Dynamic); + VERIFY_IS_EQUAL( (A(seqN(2,5,fix<2>), seq(1,3,fix<3>))).InnerStrideAtCompileTime , 2); + VERIFY_IS_EQUAL( (A(seqN(2,5,fix<2>), seq(1,3,fix<3>))).OuterStrideAtCompileTime , Dynamic); + VERIFY_IS_EQUAL( (B(seqN(1,2,fix<2>), seq(1,3,fix<3>))).InnerStrideAtCompileTime , 2); + VERIFY_IS_EQUAL( (B(seqN(1,2,fix<2>), seq(1,3,fix<3>))).OuterStrideAtCompileTime , 3*4); + + 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); @@ -139,12 +139,10 @@ void check_indexed_view() VERIFY_IS_EQUAL( (A(eii, eii)).InnerStrideAtCompileTime, 0); VERIFY_IS_EQUAL( (A(eii, eii)).OuterStrideAtCompileTime, 0); - - #if EIGEN_HAS_CXX11 VERIFY( (A(all, std::array{{1,3,2,4}})).ColsAtCompileTime == 4); - VERIFY_IS_APPROX( (A(std::array{{1,3,5}}, std::array{{9,6,3,0}})), A(span(1,3,2), span(9,4,-3)) ); + VERIFY_IS_APPROX( (A(std::array{{1,3,5}}, std::array{{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{{3, 1, 6, 5}}, all) ); -- cgit v1.2.3 From b50c3e967e1676f248c93c1a79e6574ae746e2fd Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Mon, 9 Jan 2017 23:42:16 +0100 Subject: Add a minimalistic symbolic scalar type with expression template and make use of it to define the last placeholder and to unify the return type of seq and seqN. --- Eigen/src/Core/ArithmeticSequence.h | 218 +++++++++++++++++++++++++++++++----- test/indexed_view.cpp | 5 + 2 files changed, 196 insertions(+), 27 deletions(-) diff --git a/Eigen/src/Core/ArithmeticSequence.h b/Eigen/src/Core/ArithmeticSequence.h index 71301797a..9f4fe327b 100644 --- a/Eigen/src/Core/ArithmeticSequence.h +++ b/Eigen/src/Core/ArithmeticSequence.h @@ -34,7 +34,7 @@ struct last_t { int operator- (last_t) const { return 0; } int operator- (shifted_last x) const { return -x.offset; } }; -static const last_t last; +static const last_t last_legacy; struct shifted_end { @@ -52,7 +52,145 @@ struct end_t { int operator- (end_t) const { return 0; } int operator- (shifted_end x) const { return -x.offset; } }; -static const end_t end; +static const end_t end_legacy; + +// A simple wrapper around an Index to provide the eval method. +// We could also use a free-function symbolic_eval... +class symbolic_value_wrapper { +public: + symbolic_value_wrapper(Index val) : m_value(val) {} + template + Index eval(const T&) const { return m_value; } +protected: + Index m_value; +}; + +//-------------------------------------------------------------------------------- +// minimalistic symbolic scalar type +//-------------------------------------------------------------------------------- + +template class symbolic_symbol; +template class symbolic_negate; +template class symbolic_add; +template class symbolic_product; +template class symbolic_quotient; + +template +class symbolic_index_base +{ +public: + const Derived& derived() const { return *static_cast(this); } + + symbolic_negate operator-() const { return symbolic_negate(derived()); } + + symbolic_add operator+(Index b) const + { return symbolic_add(derived(), b); } + symbolic_add operator-(Index a) const + { return symbolic_add(derived(), -a); } + symbolic_quotient operator/(Index a) const + { return symbolic_quotient(derived(),a); } + + friend symbolic_add operator+(Index a, const symbolic_index_base& b) + { return symbolic_add(b.derived(), a); } + friend symbolic_add,symbolic_value_wrapper> operator-(Index a, const symbolic_index_base& b) + { return symbolic_add,symbolic_value_wrapper>(-b.derived(), a); } + friend symbolic_add operator/(Index a, const symbolic_index_base& b) + { return symbolic_add(a,b.derived()); } + + template + symbolic_add operator+(const symbolic_index_base &b) const + { return symbolic_add(derived(), b.derived()); } + + template + symbolic_add > operator-(const symbolic_index_base &b) const + { return symbolic_add >(derived(), -b.derived()); } + + template + symbolic_add operator/(const symbolic_index_base &b) const + { return symbolic_quotient(derived(), b.derived()); } +}; + +template +struct is_symbolic { + enum { value = internal::is_convertible >::value }; +}; + +template +class symbolic_value_pair +{ +public: + symbolic_value_pair(Index val) : m_value(val) {} + Index value() const { return m_value; } +protected: + Index m_value; +}; + +template +class symbolic_value : public symbolic_index_base > +{ +public: + symbolic_value() {} + + Index eval(const symbolic_value_pair &values) const { return values.value(); } + + // TODO add a c++14 eval taking a tuple of symbolic_value_pair and getting the value with std::get >... +}; + +template +class symbolic_negate : public symbolic_index_base > +{ +public: + symbolic_negate(const Arg0& arg0) : m_arg0(arg0) {} + + template + Index eval(const T& values) const { return -m_arg0.eval(values); } +protected: + Arg0 m_arg0; +}; + +template +class symbolic_add : public symbolic_index_base > +{ +public: + symbolic_add(const Arg0& arg0, const Arg1& arg1) : m_arg0(arg0), m_arg1(arg1) {} + + template + Index eval(const T& values) const { return m_arg0.eval(values) + m_arg1.eval(values); } +protected: + Arg0 m_arg0; + Arg1 m_arg1; +}; + +template +class symbolic_product : public symbolic_index_base > +{ +public: + symbolic_product(const Arg0& arg0, const Arg1& arg1) : m_arg0(arg0), m_arg1(arg1) {} + + template + Index eval(const T& values) const { return m_arg0.eval(values) * m_arg1.eval(values); } +protected: + Arg0 m_arg0; + Arg1 m_arg1; +}; + +template +class symbolic_quotient : public symbolic_index_base > +{ +public: + symbolic_quotient(const Arg0& arg0, const Arg1& arg1) : m_arg0(arg0), m_arg1(arg1) {} + + template + Index eval(const T& values) const { return m_arg0.eval(values) / m_arg1.eval(values); } +protected: + Arg0 m_arg0; + Arg1 m_arg1; +}; + +struct symb_last_tag {}; + +static const symbolic_value last; +static const symbolic_add,symbolic_value_wrapper> end(last+1); //-------------------------------------------------------------------------------- // integral constant @@ -116,34 +254,30 @@ protected: IncrType m_incr; }; -template struct cleanup_slice_type { typedef Index type; }; -template<> struct cleanup_slice_type { typedef last_t type; }; -template<> struct cleanup_slice_type { typedef shifted_last type; }; -template<> struct cleanup_slice_type { typedef end_t type; }; -template<> struct cleanup_slice_type { typedef shifted_end type; }; -template struct cleanup_slice_type > { typedef fix_t type; }; -template struct cleanup_slice_type (*)() > { typedef fix_t type; }; +template struct cleanup_seq_type { typedef T type; }; +template struct cleanup_seq_type > { typedef fix_t type; }; +template struct cleanup_seq_type (*)() > { typedef fix_t type; }; template -ArithemeticSequenceProxyWithBounds::type,typename cleanup_slice_type::type > -seq(FirstType f, LastType l) { - return ArithemeticSequenceProxyWithBounds::type,typename cleanup_slice_type::type>(f,l); +ArithemeticSequenceProxyWithBounds::type,typename cleanup_seq_type::type > +seq_legacy(FirstType f, LastType l) { + return ArithemeticSequenceProxyWithBounds::type,typename cleanup_seq_type::type>(f,l); } template -ArithemeticSequenceProxyWithBounds::type,typename cleanup_slice_type::type,typename cleanup_slice_type::type > -seq(FirstType f, LastType l, IncrType s) { - return ArithemeticSequenceProxyWithBounds::type,typename cleanup_slice_type::type,typename cleanup_slice_type::type>(f,l,typename cleanup_slice_type::type(s)); +ArithemeticSequenceProxyWithBounds::type,typename cleanup_seq_type::type,typename cleanup_seq_type::type > +seq_legacy(FirstType f, LastType l, IncrType s) { + return ArithemeticSequenceProxyWithBounds::type,typename cleanup_seq_type::type,typename cleanup_seq_type::type>(f,l,typename cleanup_seq_type::type(s)); } template > -class ArithemeticSequenceProxyWithSize +class ArithemeticSequence { public: - ArithemeticSequenceProxyWithSize(FirstType first, SizeType size) : m_first(first), m_size(size) {} - ArithemeticSequenceProxyWithSize(FirstType first, SizeType size, IncrType incr) : m_first(first), m_size(size), m_incr(incr) {} + ArithemeticSequence(FirstType first, SizeType size) : m_first(first), m_size(size) {} + ArithemeticSequence(FirstType first, SizeType size, IncrType incr) : m_first(first), m_size(size), m_incr(incr) {} enum { SizeAtCompileTime = get_compile_time::value, @@ -165,18 +299,30 @@ protected: template -ArithemeticSequenceProxyWithSize::type,typename cleanup_slice_type::type,typename cleanup_slice_type::type > +ArithemeticSequence::type,typename cleanup_seq_type::type,typename cleanup_seq_type::type > seqN(FirstType first, SizeType size, IncrType incr) { - return ArithemeticSequenceProxyWithSize::type,typename cleanup_slice_type::type,typename cleanup_slice_type::type>(first,size,incr); + return ArithemeticSequence::type,typename cleanup_seq_type::type,typename cleanup_seq_type::type>(first,size,incr); } template -ArithemeticSequenceProxyWithSize::type,typename cleanup_slice_type::type > +ArithemeticSequence::type,typename cleanup_seq_type::type > seqN(FirstType first, SizeType size) { - return ArithemeticSequenceProxyWithSize::type,typename cleanup_slice_type::type>(first,size); + return ArithemeticSequence::type,typename cleanup_seq_type::type>(first,size); } +template +auto seq(FirstType f, LastType l) -> decltype(seqN(f,(l-f+1))) +{ + return seqN(f,(l-f+1)); +} +template +auto seq(FirstType f, LastType l, IncrType incr) + -> decltype(seqN(f,(l-f+typename cleanup_seq_type::type(incr))/typename cleanup_seq_type::type(incr),typename cleanup_seq_type::type(incr))) +{ + typedef typename cleanup_seq_type::type CleanedIncrType; + return seqN(f,(l-f+CleanedIncrType(incr))/CleanedIncrType(incr),CleanedIncrType(incr)); +} namespace internal { @@ -214,7 +360,7 @@ struct get_compile_time_incr -struct get_compile_time_incr > { +struct get_compile_time_incr > { enum { value = get_compile_time::value }; }; @@ -258,6 +404,17 @@ Index symbolic2value(shifted_last x, Index size) { return size+x.offset-1; } Index symbolic2value(end_t, Index size) { return size; } Index symbolic2value(shifted_end x, Index size) { return size+x.offset; } +template +fix_t symbolic2value(fix_t x, Index /*size*/) { return x; } + +template +Index symbolic2value(const symbolic_index_base &x, Index size) +{ + Index h=x.derived().eval(symbolic_value_pair(size-1)); + return x.derived().eval(symbolic_value_pair(size-1)); +} + + // Convert a symbolic range into a usable one (i.e., remove last/end "keywords") template struct MakeIndexing > { @@ -270,14 +427,21 @@ ArithemeticSequenceProxyWithBounds make_indexing(const Ari } // Convert a symbolic span into a usable one (i.e., remove last/end "keywords") +template +struct make_size_type { + typedef typename internal::conditional::value, Index, T>::type type; +}; + template -struct MakeIndexing > { - typedef ArithemeticSequenceProxyWithSize type; +struct MakeIndexing > { + typedef ArithemeticSequence::type,IncrType> type; }; template -ArithemeticSequenceProxyWithSize make_indexing(const ArithemeticSequenceProxyWithSize& ids, Index size) { - return ArithemeticSequenceProxyWithSize(symbolic2value(ids.firstObject(),size),ids.sizeObject(),ids.incrObject()); +ArithemeticSequence::type,IncrType> +make_indexing(const ArithemeticSequence& ids, Index size) { + return ArithemeticSequence::type,IncrType>( + symbolic2value(ids.firstObject(),size),symbolic2value(ids.sizeObject(),size),ids.incrObject()); } // Convert a symbolic 'all' into a usable range diff --git a/test/indexed_view.cpp b/test/indexed_view.cpp index 23ad2d743..25a25499c 100644 --- a/test/indexed_view.cpp +++ b/test/indexed_view.cpp @@ -139,6 +139,11 @@ void check_indexed_view() VERIFY_IS_EQUAL( (A(eii, eii)).InnerStrideAtCompileTime, 0); VERIFY_IS_EQUAL( (A(eii, eii)).OuterStrideAtCompileTime, 0); + 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)) ); + #if EIGEN_HAS_CXX11 VERIFY( (A(all, std::array{{1,3,2,4}})).ColsAtCompileTime == 4); -- cgit v1.2.3 From ecd9cc54126c6d01859fbf26276cc1d03e370aec Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Tue, 10 Jan 2017 09:34:25 +0100 Subject: Isolate legacy code (we keep it for performance comparison purpose) --- Eigen/src/Core/ArithmeticSequence.h | 208 +++++++++++++++++++----------------- test/indexed_view.cpp | 4 + 2 files changed, 113 insertions(+), 99 deletions(-) diff --git a/Eigen/src/Core/ArithmeticSequence.h b/Eigen/src/Core/ArithmeticSequence.h index 9f4fe327b..7c104ad91 100644 --- a/Eigen/src/Core/ArithmeticSequence.h +++ b/Eigen/src/Core/ArithmeticSequence.h @@ -19,41 +19,6 @@ namespace Eigen { struct all_t { all_t() {} }; static const all_t all; -struct shifted_last { - explicit shifted_last(int o) : offset(o) {} - int offset; - shifted_last operator+ (int x) const { return shifted_last(offset+x); } - shifted_last operator- (int x) const { return shifted_last(offset-x); } - int operator- (shifted_last x) const { return offset-x.offset; } -}; - -struct last_t { - last_t() {} - shifted_last operator- (int offset) const { return shifted_last(-offset); } - shifted_last operator+ (int offset) const { return shifted_last(+offset); } - int operator- (last_t) const { return 0; } - int operator- (shifted_last x) const { return -x.offset; } -}; -static const last_t last_legacy; - - -struct shifted_end { - explicit shifted_end(int o) : offset(o) {} - int offset; - shifted_end operator+ (int x) const { return shifted_end(offset+x); } - shifted_end operator- (int x) const { return shifted_end(offset-x); } - int operator- (shifted_end x) const { return offset-x.offset; } -}; - -struct end_t { - end_t() {} - shifted_end operator- (int offset) const { return shifted_end (-offset); } - shifted_end operator+ (int offset) const { return shifted_end ( offset); } - int operator- (end_t) const { return 0; } - int operator- (shifted_end x) const { return -x.offset; } -}; -static const end_t end_legacy; - // A simple wrapper around an Index to provide the eval method. // We could also use a free-function symbolic_eval... class symbolic_value_wrapper { @@ -228,49 +193,6 @@ inline fix_t fix() { return fix_t(); } // seq(first,last,incr) and seqN(first,size,incr) //-------------------------------------------------------------------------------- - -template > -class ArithemeticSequenceProxyWithBounds -{ -public: - ArithemeticSequenceProxyWithBounds(FirstType f, LastType l) : m_first(f), m_last(l) {} - ArithemeticSequenceProxyWithBounds(FirstType f, LastType l, IncrType s) : m_first(f), m_last(l), m_incr(s) {} - - enum { - SizeAtCompileTime = -1, - IncrAtCompileTime = get_compile_time::value - }; - - Index size() const { return (m_last-m_first+m_incr)/m_incr; } - Index operator[](Index i) const { return m_first + i * m_incr; } - - const FirstType& firstObject() const { return m_first; } - const LastType& lastObject() const { return m_last; } - const IncrType& incrObject() const { return m_incr; } - -protected: - FirstType m_first; - LastType m_last; - IncrType m_incr; -}; - -template struct cleanup_seq_type { typedef T type; }; -template struct cleanup_seq_type > { typedef fix_t type; }; -template struct cleanup_seq_type (*)() > { typedef fix_t type; }; - -template -ArithemeticSequenceProxyWithBounds::type,typename cleanup_seq_type::type > -seq_legacy(FirstType f, LastType l) { - return ArithemeticSequenceProxyWithBounds::type,typename cleanup_seq_type::type>(f,l); -} - -template -ArithemeticSequenceProxyWithBounds::type,typename cleanup_seq_type::type,typename cleanup_seq_type::type > -seq_legacy(FirstType f, LastType l, IncrType s) { - return ArithemeticSequenceProxyWithBounds::type,typename cleanup_seq_type::type,typename cleanup_seq_type::type>(f,l,typename cleanup_seq_type::type(s)); -} - - template > class ArithemeticSequence { @@ -297,6 +219,9 @@ protected: IncrType m_incr; }; +template struct cleanup_seq_type { typedef T type; }; +template struct cleanup_seq_type > { typedef fix_t type; }; +template struct cleanup_seq_type (*)() > { typedef fix_t type; }; template ArithemeticSequence::type,typename cleanup_seq_type::type,typename cleanup_seq_type::type > @@ -354,11 +279,6 @@ template struct get_compile_time_incr { enum { value = UndefinedIncr }; }; -template -struct get_compile_time_incr > { - enum { value = get_compile_time::value }; -}; - template struct get_compile_time_incr > { enum { value = get_compile_time::value }; @@ -399,10 +319,6 @@ struct MakeIndexing::val // Replace symbolic last/end "keywords" by their true runtime value Index symbolic2value(Index x, Index /* size */) { return x; } -Index symbolic2value(last_t, Index size) { return size-1; } -Index symbolic2value(shifted_last x, Index size) { return size+x.offset-1; } -Index symbolic2value(end_t, Index size) { return size; } -Index symbolic2value(shifted_end x, Index size) { return size+x.offset; } template fix_t symbolic2value(fix_t x, Index /*size*/) { return x; } @@ -414,18 +330,6 @@ Index symbolic2value(const symbolic_index_base &x, Index size) return x.derived().eval(symbolic_value_pair(size-1)); } - -// Convert a symbolic range into a usable one (i.e., remove last/end "keywords") -template -struct MakeIndexing > { - typedef ArithemeticSequenceProxyWithBounds type; -}; - -template -ArithemeticSequenceProxyWithBounds make_indexing(const ArithemeticSequenceProxyWithBounds& ids, Index size) { - return ArithemeticSequenceProxyWithBounds(symbolic2value(ids.firstObject(),size),symbolic2value(ids.lastObject(),size),ids.incrObject()); -} - // Convert a symbolic span into a usable one (i.e., remove last/end "keywords") template struct make_size_type { @@ -474,6 +378,112 @@ template<> struct get_compile_time_incr { } // end namespace internal +//-------------------------------------------------------------------------------- + +namespace legacy { +// Here are some initial code that I keep here for now to compare the quality of the code generated by the compilers + +struct shifted_last { + explicit shifted_last(int o) : offset(o) {} + int offset; + shifted_last operator+ (int x) const { return shifted_last(offset+x); } + shifted_last operator- (int x) const { return shifted_last(offset-x); } + int operator- (shifted_last x) const { return offset-x.offset; } +}; + +struct last_t { + last_t() {} + shifted_last operator- (int offset) const { return shifted_last(-offset); } + shifted_last operator+ (int offset) const { return shifted_last(+offset); } + int operator- (last_t) const { return 0; } + int operator- (shifted_last x) const { return -x.offset; } +}; +static const last_t last; + + +struct shifted_end { + explicit shifted_end(int o) : offset(o) {} + int offset; + shifted_end operator+ (int x) const { return shifted_end(offset+x); } + shifted_end operator- (int x) const { return shifted_end(offset-x); } + int operator- (shifted_end x) const { return offset-x.offset; } +}; + +struct end_t { + end_t() {} + shifted_end operator- (int offset) const { return shifted_end (-offset); } + shifted_end operator+ (int offset) const { return shifted_end ( offset); } + int operator- (end_t) const { return 0; } + int operator- (shifted_end x) const { return -x.offset; } +}; +static const end_t end; + +Index symbolic2value(last_t, Index size) { return size-1; } +Index symbolic2value(shifted_last x, Index size) { return size+x.offset-1; } +Index symbolic2value(end_t, Index size) { return size; } +Index symbolic2value(shifted_end x, Index size) { return size+x.offset; } + +template > +class ArithemeticSequenceProxyWithBounds +{ +public: + ArithemeticSequenceProxyWithBounds(FirstType f, LastType l) : m_first(f), m_last(l) {} + ArithemeticSequenceProxyWithBounds(FirstType f, LastType l, IncrType s) : m_first(f), m_last(l), m_incr(s) {} + + enum { + SizeAtCompileTime = -1, + IncrAtCompileTime = get_compile_time::value + }; + + Index size() const { return (m_last-m_first+m_incr)/m_incr; } + Index operator[](Index i) const { return m_first + i * m_incr; } + + const FirstType& firstObject() const { return m_first; } + const LastType& lastObject() const { return m_last; } + const IncrType& incrObject() const { return m_incr; } + +protected: + FirstType m_first; + LastType m_last; + IncrType m_incr; +}; + +template +ArithemeticSequenceProxyWithBounds::type,typename cleanup_seq_type::type > +seq(FirstType f, LastType l) { + return ArithemeticSequenceProxyWithBounds::type,typename cleanup_seq_type::type>(f,l); +} + +template +ArithemeticSequenceProxyWithBounds::type,typename cleanup_seq_type::type,typename cleanup_seq_type::type > +seq(FirstType f, LastType l, IncrType s) { + return ArithemeticSequenceProxyWithBounds::type,typename cleanup_seq_type::type,typename cleanup_seq_type::type>(f,l,typename cleanup_seq_type::type(s)); +} + +} + +namespace internal { + +template +struct get_compile_time_incr > { + enum { value = get_compile_time::value }; +}; + +// Convert a symbolic range into a usable one (i.e., remove last/end "keywords") +template +struct MakeIndexing > { + typedef legacy::ArithemeticSequenceProxyWithBounds type; +}; + +template +legacy::ArithemeticSequenceProxyWithBounds +make_indexing(const legacy::ArithemeticSequenceProxyWithBounds& ids, Index size) { + return legacy::ArithemeticSequenceProxyWithBounds( + symbolic2value(ids.firstObject(),size),symbolic2value(ids.lastObject(),size),ids.incrObject()); +} + +} + } // end namespace Eigen #endif // EIGEN_ARITHMETIC_SEQUENCE_H diff --git a/test/indexed_view.cpp b/test/indexed_view.cpp index 25a25499c..5c5cb5cde 100644 --- a/test/indexed_view.cpp +++ b/test/indexed_view.cpp @@ -160,6 +160,10 @@ void check_indexed_view() #endif + // check legacy code + VERIFY_IS_APPROX( A(legacy::seq(legacy::last,2,-2), legacy::seq(legacy::last-6,7)), A(seq(last,2,-2), seq(last-6,7)) ); + VERIFY_IS_APPROX( A(seqN(legacy::last,2,-2), seqN(legacy::last-6,3)), A(seqN(last,2,-2), seqN(last-6,3)) ); + } void test_indexed_view() -- cgit v1.2.3 From 1df2377d78c30b87099fd38b2b78021dc28f6181 Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Tue, 10 Jan 2017 10:28:45 +0100 Subject: Implement c++98 version of seq() --- Eigen/src/Core/ArithmeticSequence.h | 85 ++++++++++++++++++++++++++++++++++--- test/indexed_view.cpp | 13 ++++++ 2 files changed, 93 insertions(+), 5 deletions(-) diff --git a/Eigen/src/Core/ArithmeticSequence.h b/Eigen/src/Core/ArithmeticSequence.h index 7c104ad91..6c9cb9ef3 100644 --- a/Eigen/src/Core/ArithmeticSequence.h +++ b/Eigen/src/Core/ArithmeticSequence.h @@ -219,7 +219,8 @@ protected: IncrType m_incr; }; -template struct cleanup_seq_type { typedef T type; }; +template struct cleanup_seq_type { typedef T type; }; +template struct cleanup_seq_type::value>::type> { typedef Index type; }; template struct cleanup_seq_type > { typedef fix_t type; }; template struct cleanup_seq_type (*)() > { typedef fix_t type; }; @@ -235,10 +236,11 @@ seqN(FirstType first, SizeType size) { return ArithemeticSequence::type,typename cleanup_seq_type::type>(first,size); } +#if EIGEN_HAS_CXX11 template -auto seq(FirstType f, LastType l) -> decltype(seqN(f,(l-f+1))) +auto seq(FirstType f, LastType l) -> decltype(seqN(f,(l-f+fix<1>()))) { - return seqN(f,(l-f+1)); + return seqN(f,(l-f+fix<1>())); } template @@ -248,6 +250,80 @@ auto seq(FirstType f, LastType l, IncrType incr) typedef typename cleanup_seq_type::type CleanedIncrType; return seqN(f,(l-f+CleanedIncrType(incr))/CleanedIncrType(incr),CleanedIncrType(incr)); } +#else +template +typename internal::enable_if::value || is_symbolic::value), + ArithemeticSequence::type,Index> >::type +seq(FirstType f, LastType l) +{ + return seqN(f,(l-f+1)); +} + +template +typename internal::enable_if::value, + ArithemeticSequence,symbolic_value_wrapper>,symbolic_value_wrapper> > >::type +seq(const symbolic_index_base &f, LastType l) +{ + return seqN(f.derived(),(l-f.derived()+1)); +} + +template +typename internal::enable_if::value, + ArithemeticSequence::type,symbolic_add,symbolic_value_wrapper> > >::type +seq(FirstType f, const symbolic_index_base &l) +{ + return seqN(f,(l.derived()-f+1)); +} + +template +ArithemeticSequence >,symbolic_value_wrapper> > +seq(const symbolic_index_base &f, const symbolic_index_base &l) +{ + return seqN(f.derived(),(l.derived()-f.derived()+1)); +} + + +template +typename internal::enable_if::value || is_symbolic::value), + ArithemeticSequence::type,Index,typename cleanup_seq_type::type> >::type +seq(FirstType f, LastType l, IncrType incr) +{ + typedef typename cleanup_seq_type::type CleanedIncrType; + return seqN(f,(l-f+CleanedIncrType(incr))/CleanedIncrType(incr), incr); +} + +template +typename internal::enable_if::value, + ArithemeticSequence,symbolic_value_wrapper>,symbolic_value_wrapper>,symbolic_value_wrapper>, + typename cleanup_seq_type::type> >::type +seq(const symbolic_index_base &f, LastType l, IncrType incr) +{ + typedef typename cleanup_seq_type::type CleanedIncrType; + return seqN(f.derived(),(l-f.derived()+CleanedIncrType(incr))/CleanedIncrType(incr), incr); +} + +template +typename internal::enable_if::value, + ArithemeticSequence::type, + symbolic_quotient,symbolic_value_wrapper>,symbolic_value_wrapper>, + typename cleanup_seq_type::type> >::type +seq(FirstType f, const symbolic_index_base &l, IncrType incr) +{ + typedef typename cleanup_seq_type::type CleanedIncrType; + return seqN(f,(l.derived()-f+CleanedIncrType(incr))/CleanedIncrType(incr), incr); +} + +template +ArithemeticSequence >,symbolic_value_wrapper>,symbolic_value_wrapper>, + typename cleanup_seq_type::type> +seq(const symbolic_index_base &f, const symbolic_index_base &l, IncrType incr) +{ + typedef typename cleanup_seq_type::type CleanedIncrType; + return seqN(f.derived(),(l.derived()-f.derived()+CleanedIncrType(incr))/CleanedIncrType(incr), incr); +} +#endif namespace internal { @@ -255,7 +331,7 @@ template Index size(const T& x) { return x.size(); } template -Index size(const T (&x) [N]) { return N; } +Index size(const T (&) [N]) { return N; } template struct get_compile_time_size { enum { value = Dynamic }; @@ -326,7 +402,6 @@ fix_t symbolic2value(fix_t x, Index /*size*/) { return x; } template Index symbolic2value(const symbolic_index_base &x, Index size) { - Index h=x.derived().eval(symbolic_value_pair(size-1)); return x.derived().eval(symbolic_value_pair(size-1)); } diff --git a/test/indexed_view.cpp b/test/indexed_view.cpp index 5c5cb5cde..13eb1ef35 100644 --- a/test/indexed_view.cpp +++ b/test/indexed_view.cpp @@ -7,6 +7,11 @@ // Public License v. 2.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++98 implementation +#define EIGEN_MAX_CPP_VER 03 +#endif + #include #include #include "main.h" @@ -144,6 +149,13 @@ void check_indexed_view() 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)) ); + #if EIGEN_HAS_CXX11 VERIFY( (A(all, std::array{{1,3,2,4}})).ColsAtCompileTime == 4); @@ -170,5 +182,6 @@ void test_indexed_view() { // for(int i = 0; i < g_repeat; i++) { CALL_SUBTEST_1( check_indexed_view() ); + CALL_SUBTEST_2( check_indexed_view() ); // } } -- cgit v1.2.3 From acd08900c9992de386c7ded14a593b2ba0a0f20e Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Tue, 10 Jan 2017 10:31:07 +0100 Subject: Move 'last' and 'end' to their own namespace --- Eigen/src/Core/ArithmeticSequence.h | 4 ++++ test/indexed_view.cpp | 3 +++ 2 files changed, 7 insertions(+) diff --git a/Eigen/src/Core/ArithmeticSequence.h b/Eigen/src/Core/ArithmeticSequence.h index 6c9cb9ef3..88954b4a6 100644 --- a/Eigen/src/Core/ArithmeticSequence.h +++ b/Eigen/src/Core/ArithmeticSequence.h @@ -154,9 +154,13 @@ protected: struct symb_last_tag {}; +namespace placeholders { + static const symbolic_value last; static const symbolic_add,symbolic_value_wrapper> end(last+1); +} // end namespace placeholders + //-------------------------------------------------------------------------------- // integral constant //-------------------------------------------------------------------------------- diff --git a/test/indexed_view.cpp b/test/indexed_view.cpp index 13eb1ef35..e04fe0cd4 100644 --- a/test/indexed_view.cpp +++ b/test/indexed_view.cpp @@ -43,6 +43,9 @@ bool match(const T& xpr, std::string ref, std::string str_xpr = "") { void check_indexed_view() { + using Eigen::placeholders::last; + using Eigen::placeholders::end; + Index n = 10; ArrayXXi A = ArrayXXi::NullaryExpr(n,n, std::ptr_fun(encode)); -- cgit v1.2.3 From 9eaab4f9e0c50bf8bfa8d8b79b809d3d564ccbf3 Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Tue, 10 Jan 2017 10:57:08 +0100 Subject: Refactoring: move all symbolic stuff into its own namespace --- Eigen/src/Core/ArithmeticSequence.h | 171 +++++++++++++++++++++--------------- 1 file changed, 98 insertions(+), 73 deletions(-) diff --git a/Eigen/src/Core/ArithmeticSequence.h b/Eigen/src/Core/ArithmeticSequence.h index 88954b4a6..72ca639db 100644 --- a/Eigen/src/Core/ArithmeticSequence.h +++ b/Eigen/src/Core/ArithmeticSequence.h @@ -19,93 +19,103 @@ namespace Eigen { struct all_t { all_t() {} }; static const all_t all; +//-------------------------------------------------------------------------------- +// minimalistic symbolic scalar type +//-------------------------------------------------------------------------------- + +namespace Symbolic { + +template class Symbol; +template class NegateExpr; +template class AddExpr; +template class ProductExpr; +template class QuotientExpr; + // A simple wrapper around an Index to provide the eval method. // We could also use a free-function symbolic_eval... -class symbolic_value_wrapper { +class ValueExpr { public: - symbolic_value_wrapper(Index val) : m_value(val) {} + ValueExpr(Index val) : m_value(val) {} template Index eval(const T&) const { return m_value; } protected: Index m_value; }; -//-------------------------------------------------------------------------------- -// minimalistic symbolic scalar type -//-------------------------------------------------------------------------------- - -template class symbolic_symbol; -template class symbolic_negate; -template class symbolic_add; -template class symbolic_product; -template class symbolic_quotient; - template -class symbolic_index_base +class BaseExpr { public: const Derived& derived() const { return *static_cast(this); } - symbolic_negate operator-() const { return symbolic_negate(derived()); } + NegateExpr operator-() const { return NegateExpr(derived()); } - symbolic_add operator+(Index b) const - { return symbolic_add(derived(), b); } - symbolic_add operator-(Index a) const - { return symbolic_add(derived(), -a); } - symbolic_quotient operator/(Index a) const - { return symbolic_quotient(derived(),a); } + AddExpr operator+(Index b) const + { return AddExpr(derived(), b); } + AddExpr operator-(Index a) const + { return AddExpr(derived(), -a); } + QuotientExpr operator/(Index a) const + { return QuotientExpr(derived(),a); } - friend symbolic_add operator+(Index a, const symbolic_index_base& b) - { return symbolic_add(b.derived(), a); } - friend symbolic_add,symbolic_value_wrapper> operator-(Index a, const symbolic_index_base& b) - { return symbolic_add,symbolic_value_wrapper>(-b.derived(), a); } - friend symbolic_add operator/(Index a, const symbolic_index_base& b) - { return symbolic_add(a,b.derived()); } + friend AddExpr operator+(Index a, const BaseExpr& b) + { return AddExpr(b.derived(), a); } + friend AddExpr,ValueExpr> operator-(Index a, const BaseExpr& b) + { return AddExpr,ValueExpr>(-b.derived(), a); } + friend AddExpr operator/(Index a, const BaseExpr& b) + { return AddExpr(a,b.derived()); } template - symbolic_add operator+(const symbolic_index_base &b) const - { return symbolic_add(derived(), b.derived()); } + AddExpr operator+(const BaseExpr &b) const + { return AddExpr(derived(), b.derived()); } template - symbolic_add > operator-(const symbolic_index_base &b) const - { return symbolic_add >(derived(), -b.derived()); } + AddExpr > operator-(const BaseExpr &b) const + { return AddExpr >(derived(), -b.derived()); } template - symbolic_add operator/(const symbolic_index_base &b) const - { return symbolic_quotient(derived(), b.derived()); } + AddExpr operator/(const BaseExpr &b) const + { return QuotientExpr(derived(), b.derived()); } }; template struct is_symbolic { - enum { value = internal::is_convertible >::value }; + // BaseExpr has no conversion ctor, so we only to check whether T can be staticaly cast to its base class BaseExpr. + enum { value = internal::is_convertible >::value }; }; template -class symbolic_value_pair +class SymbolValue { public: - symbolic_value_pair(Index val) : m_value(val) {} + SymbolValue(Index val) : m_value(val) {} Index value() const { return m_value; } protected: Index m_value; }; -template -class symbolic_value : public symbolic_index_base > +template +class SymbolExpr : public BaseExpr > { public: - symbolic_value() {} + typedef TagT Tag; + SymbolExpr() {} + + Index eval(const SymbolValue &values) const { return values.value(); } - Index eval(const symbolic_value_pair &values) const { return values.value(); } - // TODO add a c++14 eval taking a tuple of symbolic_value_pair and getting the value with std::get >... + // TODO add a c++14 eval taking a tuple of SymbolValue and getting the value with std::get >... }; +template +SymbolValue defineValue(SymbolExpr,Index val) { + return SymbolValue(val); +} + template -class symbolic_negate : public symbolic_index_base > +class NegateExpr : public BaseExpr > { public: - symbolic_negate(const Arg0& arg0) : m_arg0(arg0) {} + NegateExpr(const Arg0& arg0) : m_arg0(arg0) {} template Index eval(const T& values) const { return -m_arg0.eval(values); } @@ -114,10 +124,10 @@ protected: }; template -class symbolic_add : public symbolic_index_base > +class AddExpr : public BaseExpr > { public: - symbolic_add(const Arg0& arg0, const Arg1& arg1) : m_arg0(arg0), m_arg1(arg1) {} + AddExpr(const Arg0& arg0, const Arg1& arg1) : m_arg0(arg0), m_arg1(arg1) {} template Index eval(const T& values) const { return m_arg0.eval(values) + m_arg1.eval(values); } @@ -127,10 +137,10 @@ protected: }; template -class symbolic_product : public symbolic_index_base > +class ProductExpr : public BaseExpr > { public: - symbolic_product(const Arg0& arg0, const Arg1& arg1) : m_arg0(arg0), m_arg1(arg1) {} + ProductExpr(const Arg0& arg0, const Arg1& arg1) : m_arg0(arg0), m_arg1(arg1) {} template Index eval(const T& values) const { return m_arg0.eval(values) * m_arg1.eval(values); } @@ -140,10 +150,10 @@ protected: }; template -class symbolic_quotient : public symbolic_index_base > +class QuotientExpr : public BaseExpr > { public: - symbolic_quotient(const Arg0& arg0, const Arg1& arg1) : m_arg0(arg0), m_arg1(arg1) {} + QuotientExpr(const Arg0& arg0, const Arg1& arg1) : m_arg0(arg0), m_arg1(arg1) {} template Index eval(const T& values) const { return m_arg0.eval(values) / m_arg1.eval(values); } @@ -152,12 +162,16 @@ protected: Arg1 m_arg1; }; -struct symb_last_tag {}; +} // end namespace Symbolic namespace placeholders { -static const symbolic_value last; -static const symbolic_add,symbolic_value_wrapper> end(last+1); +namespace internal { +struct symbolic_last_tag {}; +} + +static const Symbolic::SymbolExpr last; +static const Symbolic::AddExpr,Symbolic::ValueExpr> end(last+1); } // end namespace placeholders @@ -256,7 +270,7 @@ auto seq(FirstType f, LastType l, IncrType incr) } #else template -typename internal::enable_if::value || is_symbolic::value), +typename internal::enable_if::value || Symbolic::is_symbolic::value), ArithemeticSequence::type,Index> >::type seq(FirstType f, LastType l) { @@ -264,31 +278,34 @@ seq(FirstType f, LastType l) } template -typename internal::enable_if::value, - ArithemeticSequence,symbolic_value_wrapper>,symbolic_value_wrapper> > >::type -seq(const symbolic_index_base &f, LastType l) +typename internal::enable_if::value, + ArithemeticSequence,Symbolic::ValueExpr>, + Symbolic::ValueExpr> > >::type +seq(const Symbolic::BaseExpr &f, LastType l) { return seqN(f.derived(),(l-f.derived()+1)); } template -typename internal::enable_if::value, - ArithemeticSequence::type,symbolic_add,symbolic_value_wrapper> > >::type -seq(FirstType f, const symbolic_index_base &l) +typename internal::enable_if::value, + ArithemeticSequence::type, + Symbolic::AddExpr,Symbolic::ValueExpr> > >::type +seq(FirstType f, const Symbolic::BaseExpr &l) { return seqN(f,(l.derived()-f+1)); } template -ArithemeticSequence >,symbolic_value_wrapper> > -seq(const symbolic_index_base &f, const symbolic_index_base &l) +ArithemeticSequence >,Symbolic::ValueExpr> > +seq(const Symbolic::BaseExpr &f, const Symbolic::BaseExpr &l) { return seqN(f.derived(),(l.derived()-f.derived()+1)); } template -typename internal::enable_if::value || is_symbolic::value), +typename internal::enable_if::value || Symbolic::is_symbolic::value), ArithemeticSequence::type,Index,typename cleanup_seq_type::type> >::type seq(FirstType f, LastType l, IncrType incr) { @@ -297,22 +314,27 @@ seq(FirstType f, LastType l, IncrType incr) } template -typename internal::enable_if::value, +typename internal::enable_if::value, ArithemeticSequence,symbolic_value_wrapper>,symbolic_value_wrapper>,symbolic_value_wrapper>, - typename cleanup_seq_type::type> >::type -seq(const symbolic_index_base &f, LastType l, IncrType incr) + Symbolic::QuotientExpr, + Symbolic::ValueExpr>, + Symbolic::ValueExpr>, + Symbolic::ValueExpr>, + typename cleanup_seq_type::type> >::type +seq(const Symbolic::BaseExpr &f, LastType l, IncrType incr) { typedef typename cleanup_seq_type::type CleanedIncrType; return seqN(f.derived(),(l-f.derived()+CleanedIncrType(incr))/CleanedIncrType(incr), incr); } template -typename internal::enable_if::value, +typename internal::enable_if::value, ArithemeticSequence::type, - symbolic_quotient,symbolic_value_wrapper>,symbolic_value_wrapper>, + Symbolic::QuotientExpr, + Symbolic::ValueExpr>, + Symbolic::ValueExpr>, typename cleanup_seq_type::type> >::type -seq(FirstType f, const symbolic_index_base &l, IncrType incr) +seq(FirstType f, const Symbolic::BaseExpr &l, IncrType incr) { typedef typename cleanup_seq_type::type CleanedIncrType; return seqN(f,(l.derived()-f+CleanedIncrType(incr))/CleanedIncrType(incr), incr); @@ -320,9 +342,12 @@ seq(FirstType f, const symbolic_index_base &l, IncrType incr) template ArithemeticSequence >,symbolic_value_wrapper>,symbolic_value_wrapper>, + Symbolic::QuotientExpr >, + Symbolic::ValueExpr>, + Symbolic::ValueExpr>, typename cleanup_seq_type::type> -seq(const symbolic_index_base &f, const symbolic_index_base &l, IncrType incr) +seq(const Symbolic::BaseExpr &f, const Symbolic::BaseExpr &l, IncrType incr) { typedef typename cleanup_seq_type::type CleanedIncrType; return seqN(f.derived(),(l.derived()-f.derived()+CleanedIncrType(incr))/CleanedIncrType(incr), incr); @@ -404,15 +429,15 @@ template fix_t symbolic2value(fix_t x, Index /*size*/) { return x; } template -Index symbolic2value(const symbolic_index_base &x, Index size) +Index symbolic2value(const Symbolic::BaseExpr &x, Index size) { - return x.derived().eval(symbolic_value_pair(size-1)); + return x.derived().eval(Symbolic::defineValue(placeholders::last,size-1)); } // Convert a symbolic span into a usable one (i.e., remove last/end "keywords") template struct make_size_type { - typedef typename internal::conditional::value, Index, T>::type type; + typedef typename internal::conditional::value, Index, T>::type type; }; template -- cgit v1.2.3 From 13d954f2702a10bd192c46b01137df9193a7d214 Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Tue, 10 Jan 2017 11:06:02 +0100 Subject: Cleanup Eigen's namespace --- Eigen/src/Core/ArithmeticSequence.h | 73 +++++++++++++++++++++---------------- 1 file changed, 42 insertions(+), 31 deletions(-) diff --git a/Eigen/src/Core/ArithmeticSequence.h b/Eigen/src/Core/ArithmeticSequence.h index 72ca639db..38cc32aa3 100644 --- a/Eigen/src/Core/ArithmeticSequence.h +++ b/Eigen/src/Core/ArithmeticSequence.h @@ -237,21 +237,25 @@ protected: IncrType m_incr; }; +namespace internal { + template struct cleanup_seq_type { typedef T type; }; template struct cleanup_seq_type::value>::type> { typedef Index type; }; template struct cleanup_seq_type > { typedef fix_t type; }; template struct cleanup_seq_type (*)() > { typedef fix_t type; }; +} + template -ArithemeticSequence::type,typename cleanup_seq_type::type,typename cleanup_seq_type::type > +ArithemeticSequence::type,typename internal::cleanup_seq_type::type,typename internal::cleanup_seq_type::type > seqN(FirstType first, SizeType size, IncrType incr) { - return ArithemeticSequence::type,typename cleanup_seq_type::type,typename cleanup_seq_type::type>(first,size,incr); + return ArithemeticSequence::type,typename internal::cleanup_seq_type::type,typename internal::cleanup_seq_type::type>(first,size,incr); } template -ArithemeticSequence::type,typename cleanup_seq_type::type > +ArithemeticSequence::type,typename internal::cleanup_seq_type::type > seqN(FirstType first, SizeType size) { - return ArithemeticSequence::type,typename cleanup_seq_type::type>(first,size); + return ArithemeticSequence::type,typename internal::cleanup_seq_type::type>(first,size); } #if EIGEN_HAS_CXX11 @@ -263,15 +267,16 @@ auto seq(FirstType f, LastType l) -> decltype(seqN(f,(l-f+fix<1>()))) template auto seq(FirstType f, LastType l, IncrType incr) - -> decltype(seqN(f,(l-f+typename cleanup_seq_type::type(incr))/typename cleanup_seq_type::type(incr),typename cleanup_seq_type::type(incr))) + -> decltype(seqN(f, (l-f+typename internal::cleanup_seq_type::type(incr)) + / typename internal::cleanup_seq_type::type(incr),typename internal::cleanup_seq_type::type(incr))) { - typedef typename cleanup_seq_type::type CleanedIncrType; + typedef typename internal::cleanup_seq_type::type CleanedIncrType; return seqN(f,(l-f+CleanedIncrType(incr))/CleanedIncrType(incr),CleanedIncrType(incr)); } #else template typename internal::enable_if::value || Symbolic::is_symbolic::value), - ArithemeticSequence::type,Index> >::type + ArithemeticSequence::type,Index> >::type seq(FirstType f, LastType l) { return seqN(f,(l-f+1)); @@ -288,7 +293,7 @@ seq(const Symbolic::BaseExpr &f, LastType l) template typename internal::enable_if::value, - ArithemeticSequence::type, + ArithemeticSequence::type, Symbolic::AddExpr,Symbolic::ValueExpr> > >::type seq(FirstType f, const Symbolic::BaseExpr &l) { @@ -306,10 +311,10 @@ seq(const Symbolic::BaseExpr &f, const Symbolic::BaseExpr typename internal::enable_if::value || Symbolic::is_symbolic::value), - ArithemeticSequence::type,Index,typename cleanup_seq_type::type> >::type + ArithemeticSequence::type,Index,typename internal::cleanup_seq_type::type> >::type seq(FirstType f, LastType l, IncrType incr) { - typedef typename cleanup_seq_type::type CleanedIncrType; + typedef typename internal::cleanup_seq_type::type CleanedIncrType; return seqN(f,(l-f+CleanedIncrType(incr))/CleanedIncrType(incr), incr); } @@ -320,23 +325,23 @@ typename internal::enable_if::value, Symbolic::ValueExpr>, Symbolic::ValueExpr>, Symbolic::ValueExpr>, - typename cleanup_seq_type::type> >::type + typename internal::cleanup_seq_type::type> >::type seq(const Symbolic::BaseExpr &f, LastType l, IncrType incr) { - typedef typename cleanup_seq_type::type CleanedIncrType; + typedef typename internal::cleanup_seq_type::type CleanedIncrType; return seqN(f.derived(),(l-f.derived()+CleanedIncrType(incr))/CleanedIncrType(incr), incr); } template typename internal::enable_if::value, - ArithemeticSequence::type, + ArithemeticSequence::type, Symbolic::QuotientExpr, Symbolic::ValueExpr>, Symbolic::ValueExpr>, - typename cleanup_seq_type::type> >::type + typename internal::cleanup_seq_type::type> >::type seq(FirstType f, const Symbolic::BaseExpr &l, IncrType incr) { - typedef typename cleanup_seq_type::type CleanedIncrType; + typedef typename internal::cleanup_seq_type::type CleanedIncrType; return seqN(f,(l.derived()-f+CleanedIncrType(incr))/CleanedIncrType(incr), incr); } @@ -346,10 +351,10 @@ ArithemeticSequence >, Symbolic::ValueExpr>, Symbolic::ValueExpr>, - typename cleanup_seq_type::type> + typename internal::cleanup_seq_type::type> seq(const Symbolic::BaseExpr &f, const Symbolic::BaseExpr &l, IncrType incr) { - typedef typename cleanup_seq_type::type CleanedIncrType; + typedef typename internal::cleanup_seq_type::type CleanedIncrType; return seqN(f.derived(),(l.derived()-f.derived()+CleanedIncrType(incr))/CleanedIncrType(incr), incr); } #endif @@ -423,13 +428,13 @@ struct MakeIndexing::val }; // Replace symbolic last/end "keywords" by their true runtime value -Index symbolic2value(Index x, Index /* size */) { return x; } +Index eval_expr_given_size(Index x, Index /* size */) { return x; } template -fix_t symbolic2value(fix_t x, Index /*size*/) { return x; } +fix_t eval_expr_given_size(fix_t x, Index /*size*/) { return x; } template -Index symbolic2value(const Symbolic::BaseExpr &x, Index size) +Index eval_expr_given_size(const Symbolic::BaseExpr &x, Index size) { return x.derived().eval(Symbolic::defineValue(placeholders::last,size-1)); } @@ -449,7 +454,7 @@ template ArithemeticSequence::type,IncrType> make_indexing(const ArithemeticSequence& ids, Index size) { return ArithemeticSequence::type,IncrType>( - symbolic2value(ids.firstObject(),size),symbolic2value(ids.sizeObject(),size),ids.incrObject()); + eval_expr_given_size(ids.firstObject(),size),eval_expr_given_size(ids.sizeObject(),size),ids.incrObject()); } // Convert a symbolic 'all' into a usable range @@ -522,10 +527,10 @@ struct end_t { }; static const end_t end; -Index symbolic2value(last_t, Index size) { return size-1; } -Index symbolic2value(shifted_last x, Index size) { return size+x.offset-1; } -Index symbolic2value(end_t, Index size) { return size; } -Index symbolic2value(shifted_end x, Index size) { return size+x.offset; } +Index eval_expr_given_size(last_t, Index size) { return size-1; } +Index eval_expr_given_size(shifted_last x, Index size) { return size+x.offset-1; } +Index eval_expr_given_size(end_t, Index size) { return size; } +Index eval_expr_given_size(shifted_end x, Index size) { return size+x.offset; } template > class ArithemeticSequenceProxyWithBounds @@ -553,15 +558,21 @@ protected: }; template -ArithemeticSequenceProxyWithBounds::type,typename cleanup_seq_type::type > +ArithemeticSequenceProxyWithBounds::type,typename internal::cleanup_seq_type::type > seq(FirstType f, LastType l) { - return ArithemeticSequenceProxyWithBounds::type,typename cleanup_seq_type::type>(f,l); + return ArithemeticSequenceProxyWithBounds::type,typename internal::cleanup_seq_type::type>(f,l); } template -ArithemeticSequenceProxyWithBounds::type,typename cleanup_seq_type::type,typename cleanup_seq_type::type > -seq(FirstType f, LastType l, IncrType s) { - return ArithemeticSequenceProxyWithBounds::type,typename cleanup_seq_type::type,typename cleanup_seq_type::type>(f,l,typename cleanup_seq_type::type(s)); +ArithemeticSequenceProxyWithBounds< typename internal::cleanup_seq_type::type, + typename internal::cleanup_seq_type::type, + typename internal::cleanup_seq_type::type > +seq(FirstType f, LastType l, IncrType s) +{ + return ArithemeticSequenceProxyWithBounds::type, + typename internal::cleanup_seq_type::type, + typename internal::cleanup_seq_type::type> + (f,l,typename internal::cleanup_seq_type::type(s)); } } @@ -583,7 +594,7 @@ template legacy::ArithemeticSequenceProxyWithBounds make_indexing(const legacy::ArithemeticSequenceProxyWithBounds& ids, Index size) { return legacy::ArithemeticSequenceProxyWithBounds( - symbolic2value(ids.firstObject(),size),symbolic2value(ids.lastObject(),size),ids.incrObject()); + eval_expr_given_size(ids.firstObject(),size),eval_expr_given_size(ids.lastObject(),size),ids.incrObject()); } } -- cgit v1.2.3 From a98c7efb163a1183d61ae56cacc7d903057285f0 Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Tue, 10 Jan 2017 11:46:29 +0100 Subject: Add a more generic evaluation mechanism and minimalistic doc. --- Eigen/src/Core/ArithmeticSequence.h | 55 ++++++++++++++++++++++++++++++++++--- 1 file changed, 51 insertions(+), 4 deletions(-) diff --git a/Eigen/src/Core/ArithmeticSequence.h b/Eigen/src/Core/ArithmeticSequence.h index 38cc32aa3..dc346bac6 100644 --- a/Eigen/src/Core/ArithmeticSequence.h +++ b/Eigen/src/Core/ArithmeticSequence.h @@ -23,6 +23,29 @@ static const all_t all; // minimalistic symbolic scalar type //-------------------------------------------------------------------------------- + +/** 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; + * struct y_tag {}; static const Symbolic::SymbolExpr y; + * struct z_tag {}; static const Symbolic::SymbolExpr z; + * + * // Defines an expression: + * auto expr = (x+3)/y+z; + * + * // And evaluate it: (c++14) + * std::cout << expr.eval(std::make_tuple(Symbolic::defineValue(x,6),Symbolic::defineValue(y,3),Symbolic::defineValue(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(Symbolic::defineValue(x,6)) << "\n"; + * + * 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 class Symbol; @@ -42,12 +65,24 @@ protected: Index m_value; }; +/** \class BaseExpr + * Common base class of any symbolic expressions + */ template class BaseExpr { public: const Derived& derived() const { return *static_cast(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 the defineValue function. + * + */ + template + Index eval(const T& values) const { return derived().eval(values); } + NegateExpr operator-() const { return NegateExpr(derived()); } AddExpr operator+(Index b) const @@ -73,7 +108,7 @@ public: { return AddExpr >(derived(), -b.derived()); } template - AddExpr operator/(const BaseExpr &b) const + QuotientExpr operator/(const BaseExpr &b) const { return QuotientExpr(derived(), b.derived()); } }; @@ -83,11 +118,18 @@ struct is_symbolic { enum { value = internal::is_convertible >::value }; }; +/** Represents the actual value of a symbol identified by its tag + * + * It is the return type of defineValue(), and most of the time this is only way it is used. + */ template 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; @@ -102,12 +144,17 @@ public: Index eval(const SymbolValue &values) const { return values.value(); } - - // TODO add a c++14 eval taking a tuple of SymbolValue and getting the value with std::get >... +#if __cplusplus > 201103L + // C++14 versions suitable for multiple symbols + template + Index eval(const std::tuple& values) const { return std::get >(values).value(); } +#endif }; +/** Associate the value \a val to the symbol \a symb + */ template -SymbolValue defineValue(SymbolExpr,Index val) { +SymbolValue defineValue(SymbolExpr /*symb*/,Index val) { return SymbolValue(val); } -- cgit v1.2.3 From 87963f441c9abd8514b94b6b2c712652d646ed64 Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Tue, 10 Jan 2017 14:25:30 +0100 Subject: Fallback to Block<> when possible (Index, all, seq with > increment). This is important to take advantage of the optimized implementations (evaluator, products, etc.), and to support sparse matrices. --- Eigen/src/Core/ArithmeticSequence.h | 6 ++++++ Eigen/src/Core/DenseBase.h | 27 ++++++++++++++++++++++++--- Eigen/src/Core/IndexedView.h | 6 ++++++ test/indexed_view.cpp | 17 +++++++++++++++++ 4 files changed, 53 insertions(+), 3 deletions(-) diff --git a/Eigen/src/Core/ArithmeticSequence.h b/Eigen/src/Core/ArithmeticSequence.h index dc346bac6..dd24d0b05 100644 --- a/Eigen/src/Core/ArithmeticSequence.h +++ b/Eigen/src/Core/ArithmeticSequence.h @@ -272,6 +272,7 @@ public: }; Index size() const { return m_size; } + Index first() const { return m_first; } Index operator[](Index i) const { return m_first + i * m_incr; } const FirstType& firstObject() const { return m_first; } @@ -414,6 +415,9 @@ Index size(const T& x) { return x.size(); } template Index size(const T (&) [N]) { return N; } +template +Index first(const T& x) { return x.first(); } + template struct get_compile_time_size { enum { value = Dynamic }; }; @@ -458,6 +462,7 @@ struct IntAsArray { IntAsArray(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; }; @@ -512,6 +517,7 @@ struct AllRange { AllRange(Index size) : m_size(size) {} Index operator[](Index i) const { return i; } Index size() const { return m_size; } + Index first() const { return 0; } Index m_size; }; diff --git a/Eigen/src/Core/DenseBase.h b/Eigen/src/Core/DenseBase.h index 07057ce69..7c01e9328 100644 --- a/Eigen/src/Core/DenseBase.h +++ b/Eigen/src/Core/DenseBase.h @@ -557,15 +557,36 @@ template class DenseBase } EIGEN_DEVICE_FUNC void reverseInPlace(); + template + struct IndexedViewType { + typedef IndexedView::type,typename internal::MakeIndexing::type> type; + }; + template typename internal::enable_if< - !(internal::is_integral::value && internal::is_integral::value), - IndexedView::type,typename internal::MakeIndexing::type> >::type + ! (internal::traits::type>::IsBlockAlike + || (internal::is_integral::value && internal::is_integral::value)), + typename IndexedViewType::type >::type operator()(const RowIndices& rowIndices, const ColIndices& colIndices) const { - return IndexedView::type,typename internal::MakeIndexing::type>( + return typename IndexedViewType::type( derived(), internal::make_indexing(rowIndices,derived().rows()), internal::make_indexing(colIndices,derived().cols())); } + template + typename internal::enable_if< + internal::traits::type>::IsBlockAlike, + typename internal::traits::type>::BlockType>::type + operator()(const RowIndices& rowIndices, const ColIndices& colIndices) const { + typedef typename internal::traits::type>::BlockType BlockType; + typename internal::MakeIndexing::type actualRowIndices = internal::make_indexing(rowIndices,derived().rows()); + typename internal::MakeIndexing::type actualColIndices = internal::make_indexing(colIndices,derived().cols()); + return BlockType(derived(), + internal::first(actualRowIndices), + internal::first(actualColIndices), + internal::size(actualRowIndices), + internal::size(actualColIndices)); + } + template IndexedView::type> operator()(const RowIndicesT (&rowIndices)[RowIndicesN], const ColIndices& colIndices) const { diff --git a/Eigen/src/Core/IndexedView.h b/Eigen/src/Core/IndexedView.h index 5ff1c1837..ab9f6b453 100644 --- a/Eigen/src/Core/IndexedView.h +++ b/Eigen/src/Core/IndexedView.h @@ -38,6 +38,9 @@ struct traits > XprInnerStride = HasSameStorageOrderAsXprType ? int(inner_stride_at_compile_time::ret) : int(outer_stride_at_compile_time::ret), XprOuterstride = HasSameStorageOrderAsXprType ? int(outer_stride_at_compile_time::ret) : int(inner_stride_at_compile_time::ret), + IsBlockAlike = InnerIncr==1 && OuterIncr==1, + IsInnerPannel = HasSameStorageOrderAsXprType && is_same::type>::value, + InnerStrideAtCompileTime = InnerIncr<0 || InnerIncr==DynamicIndex || XprInnerStride==Dynamic ? Dynamic : XprInnerStride * InnerIncr, OuterStrideAtCompileTime = OuterIncr<0 || OuterIncr==DynamicIndex || XprOuterstride==Dynamic ? Dynamic : XprOuterstride * OuterIncr, @@ -48,8 +51,11 @@ struct traits > FlagsLvalueBit = is_lvalue::value ? LvalueBit : 0, Flags = (traits::Flags & (HereditaryBits | DirectAccessMask)) | FlagsLvalueBit | FlagsRowMajorBit }; + + typedef Block BlockType; }; + } template diff --git a/test/indexed_view.cpp b/test/indexed_view.cpp index e04fe0cd4..fde3ee8f9 100644 --- a/test/indexed_view.cpp +++ b/test/indexed_view.cpp @@ -41,6 +41,13 @@ bool match(const T& xpr, std::string ref, std::string str_xpr = "") { #define MATCH(X,R) match(X, R, #X) +template +typename internal::enable_if::value,bool>::type +is_same_type(const T1& a, const T2& b) +{ + return (a == b).all(); +} + void check_indexed_view() { using Eigen::placeholders::last; @@ -159,6 +166,16 @@ void check_indexed_view() 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)) ); + // Check fall-back to Block + { + const ArrayXXi& cA(A); + VERIFY( is_same_type(cA.col(0), cA(all,0)) ); + VERIFY( is_same_type(cA.row(0), cA(0,all)) ); + VERIFY( is_same_type(cA.block(0,0,2,2), cA(seqN(0,2),seq(0,1))) ); + VERIFY( is_same_type(cA.middleRows(2,4), cA(seqN(2,4),all)) ); + VERIFY( is_same_type(cA.middleCols(2,4), cA(all,seqN(2,4))) ); + } + #if EIGEN_HAS_CXX11 VERIFY( (A(all, std::array{{1,3,2,4}})).ColsAtCompileTime == 4); -- cgit v1.2.3 From b47a7e5c3a01018951a30fe51043b702dc7048be Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Tue, 10 Jan 2017 16:28:57 +0100 Subject: Add doc for IndexedView --- Eigen/src/Core/IndexedView.h | 47 ++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 45 insertions(+), 2 deletions(-) diff --git a/Eigen/src/Core/IndexedView.h b/Eigen/src/Core/IndexedView.h index ab9f6b453..12e122030 100644 --- a/Eigen/src/Core/IndexedView.h +++ b/Eigen/src/Core/IndexedView.h @@ -55,13 +55,49 @@ struct traits > typedef Block BlockType; }; - } template class IndexedViewImpl; -// Expression of a generic slice + +/** \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 + * operator[](Index) const; + * Index size() const; + * \endcode + * + * Typical supported types thus include: + * - std::vector + * - std::valarray + * - std::array + * - c++ arrays: int[N] + * - Eigen::ArrayXi + * - decltype(ArrayXi::LinSpaced(...)) + * - Any view/expressions of the previous types + * - Eigen::ArithmeticSequence + * - Eigen::AllRange (helper for Eigen::all) + * - Eigen::IntAsArray (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(). + * + * \sa class Block + */ template class IndexedView : public IndexedViewImpl::StorageKind> { @@ -76,7 +112,11 @@ public: 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 */ @@ -87,7 +127,10 @@ public: typename internal::remove_reference::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: -- cgit v1.2.3 From 8e247744a41dab895fec206020b58a6e6f28b0f7 Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Tue, 10 Jan 2017 16:32:06 +0100 Subject: Fix linking issue --- Eigen/src/Core/ArithmeticSequence.h | 10 +++++----- Eigen/src/Core/IndexedView.h | 2 +- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/Eigen/src/Core/ArithmeticSequence.h b/Eigen/src/Core/ArithmeticSequence.h index dd24d0b05..238601818 100644 --- a/Eigen/src/Core/ArithmeticSequence.h +++ b/Eigen/src/Core/ArithmeticSequence.h @@ -480,7 +480,7 @@ struct MakeIndexing::val }; // Replace symbolic last/end "keywords" by their true runtime value -Index eval_expr_given_size(Index x, Index /* size */) { return x; } +inline Index eval_expr_given_size(Index x, Index /* size */) { return x; } template fix_t eval_expr_given_size(fix_t x, Index /*size*/) { return x; } @@ -580,10 +580,10 @@ struct end_t { }; static const end_t end; -Index eval_expr_given_size(last_t, Index size) { return size-1; } -Index eval_expr_given_size(shifted_last x, Index size) { return size+x.offset-1; } -Index eval_expr_given_size(end_t, Index size) { return size; } -Index eval_expr_given_size(shifted_end x, Index size) { return size+x.offset; } +inline Index eval_expr_given_size(last_t, Index size) { return size-1; } +inline Index eval_expr_given_size(shifted_last x, Index size) { return size+x.offset-1; } +inline Index eval_expr_given_size(end_t, Index size) { return size; } +inline Index eval_expr_given_size(shifted_end x, Index size) { return size+x.offset; } template > class ArithemeticSequenceProxyWithBounds diff --git a/Eigen/src/Core/IndexedView.h b/Eigen/src/Core/IndexedView.h index 12e122030..5aaf5b4e0 100644 --- a/Eigen/src/Core/IndexedView.h +++ b/Eigen/src/Core/IndexedView.h @@ -159,7 +159,7 @@ struct unary_evaluator, IndexBased> typedef IndexedView XprType; enum { - CoeffReadCost = evaluator::CoeffReadCost /* + cost of row/col index */, + CoeffReadCost = evaluator::CoeffReadCost /* TODO + cost of row/col index */, Flags = (evaluator::Flags & (HereditaryBits /*| LinearAccessBit | DirectAccessBit*/)), -- cgit v1.2.3 From e63678bc8969e76f0a767f0abf9a42f2a89c2d2a Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Tue, 10 Jan 2017 16:33:40 +0100 Subject: Fix ambiguous call --- Eigen/src/Core/DenseBase.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Eigen/src/Core/DenseBase.h b/Eigen/src/Core/DenseBase.h index 7c01e9328..779cb4549 100644 --- a/Eigen/src/Core/DenseBase.h +++ b/Eigen/src/Core/DenseBase.h @@ -574,7 +574,8 @@ template class DenseBase template typename internal::enable_if< - internal::traits::type>::IsBlockAlike, + internal::traits::type>::IsBlockAlike + && !(internal::is_integral::value && internal::is_integral::value), typename internal::traits::type>::BlockType>::type operator()(const RowIndices& rowIndices, const ColIndices& colIndices) const { typedef typename internal::traits::type>::BlockType BlockType; -- cgit v1.2.3 From 96e6cf9aa20a136068e4e7e2efcb4ecab8655ff0 Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Tue, 10 Jan 2017 16:35:46 +0100 Subject: Fix linking issue. --- Eigen/src/Core/ArithmeticSequence.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Eigen/src/Core/ArithmeticSequence.h b/Eigen/src/Core/ArithmeticSequence.h index 238601818..b425b7804 100644 --- a/Eigen/src/Core/ArithmeticSequence.h +++ b/Eigen/src/Core/ArithmeticSequence.h @@ -526,7 +526,7 @@ struct MakeIndexing { typedef AllRange type; }; -AllRange make_indexing(all_t , Index size) { +inline AllRange make_indexing(all_t , Index size) { return AllRange(size); } -- cgit v1.2.3 From 407e7b7a9376dd3f722f0fc08fb806b3970e594d Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Tue, 10 Jan 2017 16:45:32 +0100 Subject: Simplify symbolic API by using "symbol=value" to associate a runtime value to a symbol. --- Eigen/src/Core/ArithmeticSequence.h | 26 ++++++++++++++------------ 1 file changed, 14 insertions(+), 12 deletions(-) diff --git a/Eigen/src/Core/ArithmeticSequence.h b/Eigen/src/Core/ArithmeticSequence.h index b425b7804..01cc5e15b 100644 --- a/Eigen/src/Core/ArithmeticSequence.h +++ b/Eigen/src/Core/ArithmeticSequence.h @@ -37,11 +37,11 @@ static const all_t all; * auto expr = (x+3)/y+z; * * // And evaluate it: (c++14) - * std::cout << expr.eval(std::make_tuple(Symbolic::defineValue(x,6),Symbolic::defineValue(y,3),Symbolic::defineValue(z,-13))) << "\n"; + * std::cout << expr.eval(std::make_tuple(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(Symbolic::defineValue(x,6)) << "\n"; + * std::cout << expr98.eval(x=6) << "\n"; * * It is currently only used internally to define and minipulate the placeholders::last and placeholders::end symbols in Eigen::seq and Eigen::seqN. * @@ -77,7 +77,7 @@ public: /** 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 the defineValue function. + * as constructed by SymbolExpr::operator= operator. * */ template @@ -120,7 +120,7 @@ struct is_symbolic { /** Represents the actual value of a symbol identified by its tag * - * It is the return type of defineValue(), and most of the time this is only way it is used. + * It is the return type of SymbolValue::operator=, and most of the time this is only way it is used. */ template class SymbolValue @@ -135,6 +135,7 @@ protected: Index m_value; }; +/** Expression of a symbol uniquely identified by the tag \tparam TagT */ template class SymbolExpr : public BaseExpr > { @@ -142,6 +143,14 @@ public: typedef TagT 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 operator=(Index val) const { + return SymbolValue(val); + } + Index eval(const SymbolValue &values) const { return values.value(); } #if __cplusplus > 201103L @@ -151,13 +160,6 @@ public: #endif }; -/** Associate the value \a val to the symbol \a symb - */ -template -SymbolValue defineValue(SymbolExpr /*symb*/,Index val) { - return SymbolValue(val); -} - template class NegateExpr : public BaseExpr > { @@ -488,7 +490,7 @@ fix_t eval_expr_given_size(fix_t x, Index /*size*/) { return x; } template Index eval_expr_given_size(const Symbolic::BaseExpr &x, Index size) { - return x.derived().eval(Symbolic::defineValue(placeholders::last,size-1)); + return x.derived().eval(placeholders::last=size-1); } // Convert a symbolic span into a usable one (i.e., remove last/end "keywords") -- cgit v1.2.3 From c9d5e5c6dac14fac1a4bc16b6e1570479daeacb8 Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Tue, 10 Jan 2017 16:55:07 +0100 Subject: Simplify Symbolic API: std::tuple is now used internally and automatically built. --- Eigen/src/Core/ArithmeticSequence.h | 23 ++++++++++++++--------- 1 file changed, 14 insertions(+), 9 deletions(-) diff --git a/Eigen/src/Core/ArithmeticSequence.h b/Eigen/src/Core/ArithmeticSequence.h index 01cc5e15b..bbedd99c2 100644 --- a/Eigen/src/Core/ArithmeticSequence.h +++ b/Eigen/src/Core/ArithmeticSequence.h @@ -37,7 +37,7 @@ static const all_t all; * auto expr = (x+3)/y+z; * * // And evaluate it: (c++14) - * std::cout << expr.eval(std::make_tuple(x=6,y=3,z=-13)) << "\n"; + * 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; @@ -60,7 +60,7 @@ class ValueExpr { public: ValueExpr(Index val) : m_value(val) {} template - Index eval(const T&) const { return m_value; } + Index eval_impl(const T&) const { return m_value; } protected: Index m_value; }; @@ -81,7 +81,12 @@ public: * */ template - Index eval(const T& values) const { return derived().eval(values); } + Index eval(const T& values) const { return derived().eval_impl(values); } + +#if __cplusplus > 201103L + template + Index eval(Types&&... values) const { return derived().eval_impl(std::make_tuple(values...)); } +#endif NegateExpr operator-() const { return NegateExpr(derived()); } @@ -151,12 +156,12 @@ public: return SymbolValue(val); } - Index eval(const SymbolValue &values) const { return values.value(); } + Index eval_impl(const SymbolValue &values) const { return values.value(); } #if __cplusplus > 201103L // C++14 versions suitable for multiple symbols template - Index eval(const std::tuple& values) const { return std::get >(values).value(); } + Index eval_impl(const std::tuple& values) const { return std::get >(values).value(); } #endif }; @@ -167,7 +172,7 @@ public: NegateExpr(const Arg0& arg0) : m_arg0(arg0) {} template - Index eval(const T& values) const { return -m_arg0.eval(values); } + Index eval_impl(const T& values) const { return -m_arg0.eval_impl(values); } protected: Arg0 m_arg0; }; @@ -179,7 +184,7 @@ public: AddExpr(const Arg0& arg0, const Arg1& arg1) : m_arg0(arg0), m_arg1(arg1) {} template - Index eval(const T& values) const { return m_arg0.eval(values) + m_arg1.eval(values); } + 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; @@ -192,7 +197,7 @@ public: ProductExpr(const Arg0& arg0, const Arg1& arg1) : m_arg0(arg0), m_arg1(arg1) {} template - Index eval(const T& values) const { return m_arg0.eval(values) * m_arg1.eval(values); } + 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; @@ -205,7 +210,7 @@ public: QuotientExpr(const Arg0& arg0, const Arg1& arg1) : m_arg0(arg0), m_arg1(arg1) {} template - Index eval(const T& values) const { return m_arg0.eval(values) / m_arg1.eval(values); } + 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; -- cgit v1.2.3 From d072fc4b1432b193d24e44d70885b636d4132405 Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Tue, 10 Jan 2017 17:10:35 +0100 Subject: add writeable IndexedView --- Eigen/src/Core/DenseBase.h | 66 +++++++++++++++++++++++++++++++++++++++----- Eigen/src/Core/IndexedView.h | 7 +++++ test/indexed_view.cpp | 15 ++++++++++ 3 files changed, 81 insertions(+), 7 deletions(-) diff --git a/Eigen/src/Core/DenseBase.h b/Eigen/src/Core/DenseBase.h index 779cb4549..909fa0f12 100644 --- a/Eigen/src/Core/DenseBase.h +++ b/Eigen/src/Core/DenseBase.h @@ -558,27 +558,27 @@ template class DenseBase EIGEN_DEVICE_FUNC void reverseInPlace(); template - struct IndexedViewType { + struct ConstIndexedViewType { typedef IndexedView::type,typename internal::MakeIndexing::type> type; }; template typename internal::enable_if< - ! (internal::traits::type>::IsBlockAlike + ! (internal::traits::type>::IsBlockAlike || (internal::is_integral::value && internal::is_integral::value)), - typename IndexedViewType::type >::type + typename ConstIndexedViewType::type >::type operator()(const RowIndices& rowIndices, const ColIndices& colIndices) const { - return typename IndexedViewType::type( + return typename ConstIndexedViewType::type( derived(), internal::make_indexing(rowIndices,derived().rows()), internal::make_indexing(colIndices,derived().cols())); } template typename internal::enable_if< - internal::traits::type>::IsBlockAlike + internal::traits::type>::IsBlockAlike && !(internal::is_integral::value && internal::is_integral::value), - typename internal::traits::type>::BlockType>::type + typename internal::traits::type>::BlockType>::type operator()(const RowIndices& rowIndices, const ColIndices& colIndices) const { - typedef typename internal::traits::type>::BlockType BlockType; + typedef typename internal::traits::type>::BlockType BlockType; typename internal::MakeIndexing::type actualRowIndices = internal::make_indexing(rowIndices,derived().rows()); typename internal::MakeIndexing::type actualColIndices = internal::make_indexing(colIndices,derived().cols()); return BlockType(derived(), @@ -609,6 +609,58 @@ template class DenseBase derived(), rowIndices, colIndices); } + template + struct IndexedViewType { + typedef IndexedView::type,typename internal::MakeIndexing::type> type; + }; + + template + typename internal::enable_if< + ! (internal::traits::type>::IsBlockAlike + || (internal::is_integral::value && internal::is_integral::value)), + typename IndexedViewType::type >::type + operator()(const RowIndices& rowIndices, const ColIndices& colIndices) { + return typename IndexedViewType::type( + derived(), internal::make_indexing(rowIndices,derived().rows()), internal::make_indexing(colIndices,derived().cols())); + } + + template + typename internal::enable_if< + internal::traits::type>::IsBlockAlike + && !(internal::is_integral::value && internal::is_integral::value), + typename internal::traits::type>::BlockType>::type + operator()(const RowIndices& rowIndices, const ColIndices& colIndices) { + typedef typename internal::traits::type>::BlockType BlockType; + typename internal::MakeIndexing::type actualRowIndices = internal::make_indexing(rowIndices,derived().rows()); + typename internal::MakeIndexing::type actualColIndices = internal::make_indexing(colIndices,derived().cols()); + return BlockType(derived(), + internal::first(actualRowIndices), + internal::first(actualColIndices), + internal::size(actualRowIndices), + internal::size(actualColIndices)); + } + + template + IndexedView::type> + operator()(const RowIndicesT (&rowIndices)[RowIndicesN], const ColIndices& colIndices) { + return IndexedView::type>( + derived(), rowIndices, internal::make_indexing(colIndices,derived().cols())); + } + + template + IndexedView::type, const ColIndicesT (&)[ColIndicesN]> + operator()(const RowIndices& rowIndices, const ColIndicesT (&colIndices)[ColIndicesN]) { + return IndexedView::type,const ColIndicesT (&)[ColIndicesN]>( + derived(), internal::make_indexing(rowIndices,derived().rows()), colIndices); + } + + template + IndexedView + operator()(const RowIndicesT (&rowIndices)[RowIndicesN], const ColIndicesT (&colIndices)[ColIndicesN]) { + return IndexedView( + derived(), rowIndices, colIndices); + } + #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) diff --git a/Eigen/src/Core/IndexedView.h b/Eigen/src/Core/IndexedView.h index 5aaf5b4e0..81ff53758 100644 --- a/Eigen/src/Core/IndexedView.h +++ b/Eigen/src/Core/IndexedView.h @@ -104,6 +104,7 @@ class IndexedView : public IndexedViewImpl::StorageKind>::Base Base; EIGEN_GENERIC_PUBLIC_INTERFACE(IndexedView) + EIGEN_INHERIT_ASSIGNMENT_OPERATORS(IndexedView) typedef typename internal::ref_selector::non_const_type MatrixTypeNested; typedef typename internal::remove_all::type NestedExpression; @@ -180,6 +181,12 @@ struct unary_evaluator, IndexBased> 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 m_argImpl; diff --git a/test/indexed_view.cpp b/test/indexed_view.cpp index fde3ee8f9..42d136847 100644 --- a/test/indexed_view.cpp +++ b/test/indexed_view.cpp @@ -168,6 +168,12 @@ void check_indexed_view() // Check fall-back to Block { + VERIFY( is_same_type(A.col(0), A(all,0)) ); + VERIFY( is_same_type(A.row(0), A(0,all)) ); + VERIFY( is_same_type(A.block(0,0,2,2), A(seqN(0,2),seq(0,1))) ); + VERIFY( is_same_type(A.middleRows(2,4), A(seqN(2,4),all)) ); + VERIFY( is_same_type(A.middleCols(2,4), A(all,seqN(2,4))) ); + const ArrayXXi& cA(A); VERIFY( is_same_type(cA.col(0), cA(all,0)) ); VERIFY( is_same_type(cA.row(0), cA(0,all)) ); @@ -176,6 +182,15 @@ void check_indexed_view() VERIFY( is_same_type(cA.middleCols(2,4), cA(all,seqN(2,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 ); + #if EIGEN_HAS_CXX11 VERIFY( (A(all, std::array{{1,3,2,4}})).ColsAtCompileTime == 4); -- cgit v1.2.3 From 17eac60446650dc31bde7156a4febe504ab347b7 Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Tue, 10 Jan 2017 21:45:55 +0100 Subject: Factorize const and non-const version of the generic operator() method. --- Eigen/src/Core/DenseBase.h | 105 +-------------------------------- Eigen/src/Core/IndexedView.h | 4 +- Eigen/src/plugins/IndexedViewMethods.h | 81 +++++++++++++++++++++++++ 3 files changed, 84 insertions(+), 106 deletions(-) create mode 100644 Eigen/src/plugins/IndexedViewMethods.h diff --git a/Eigen/src/Core/DenseBase.h b/Eigen/src/Core/DenseBase.h index 909fa0f12..a8229cf03 100644 --- a/Eigen/src/Core/DenseBase.h +++ b/Eigen/src/Core/DenseBase.h @@ -557,116 +557,13 @@ template class DenseBase } EIGEN_DEVICE_FUNC void reverseInPlace(); - template - struct ConstIndexedViewType { - typedef IndexedView::type,typename internal::MakeIndexing::type> type; - }; - - template - typename internal::enable_if< - ! (internal::traits::type>::IsBlockAlike - || (internal::is_integral::value && internal::is_integral::value)), - typename ConstIndexedViewType::type >::type - operator()(const RowIndices& rowIndices, const ColIndices& colIndices) const { - return typename ConstIndexedViewType::type( - derived(), internal::make_indexing(rowIndices,derived().rows()), internal::make_indexing(colIndices,derived().cols())); - } - - template - typename internal::enable_if< - internal::traits::type>::IsBlockAlike - && !(internal::is_integral::value && internal::is_integral::value), - typename internal::traits::type>::BlockType>::type - operator()(const RowIndices& rowIndices, const ColIndices& colIndices) const { - typedef typename internal::traits::type>::BlockType BlockType; - typename internal::MakeIndexing::type actualRowIndices = internal::make_indexing(rowIndices,derived().rows()); - typename internal::MakeIndexing::type actualColIndices = internal::make_indexing(colIndices,derived().cols()); - return BlockType(derived(), - internal::first(actualRowIndices), - internal::first(actualColIndices), - internal::size(actualRowIndices), - internal::size(actualColIndices)); - } - - template - IndexedView::type> - operator()(const RowIndicesT (&rowIndices)[RowIndicesN], const ColIndices& colIndices) const { - return IndexedView::type>( - derived(), rowIndices, internal::make_indexing(colIndices,derived().cols())); - } - - template - IndexedView::type, const ColIndicesT (&)[ColIndicesN]> - operator()(const RowIndices& rowIndices, const ColIndicesT (&colIndices)[ColIndicesN]) const { - return IndexedView::type,const ColIndicesT (&)[ColIndicesN]>( - derived(), internal::make_indexing(rowIndices,derived().rows()), colIndices); - } - - template - IndexedView - operator()(const RowIndicesT (&rowIndices)[RowIndicesN], const ColIndicesT (&colIndices)[ColIndicesN]) const { - return IndexedView( - derived(), rowIndices, colIndices); - } - - template - struct IndexedViewType { - typedef IndexedView::type,typename internal::MakeIndexing::type> type; - }; - - template - typename internal::enable_if< - ! (internal::traits::type>::IsBlockAlike - || (internal::is_integral::value && internal::is_integral::value)), - typename IndexedViewType::type >::type - operator()(const RowIndices& rowIndices, const ColIndices& colIndices) { - return typename IndexedViewType::type( - derived(), internal::make_indexing(rowIndices,derived().rows()), internal::make_indexing(colIndices,derived().cols())); - } - - template - typename internal::enable_if< - internal::traits::type>::IsBlockAlike - && !(internal::is_integral::value && internal::is_integral::value), - typename internal::traits::type>::BlockType>::type - operator()(const RowIndices& rowIndices, const ColIndices& colIndices) { - typedef typename internal::traits::type>::BlockType BlockType; - typename internal::MakeIndexing::type actualRowIndices = internal::make_indexing(rowIndices,derived().rows()); - typename internal::MakeIndexing::type actualColIndices = internal::make_indexing(colIndices,derived().cols()); - return BlockType(derived(), - internal::first(actualRowIndices), - internal::first(actualColIndices), - internal::size(actualRowIndices), - internal::size(actualColIndices)); - } - - template - IndexedView::type> - operator()(const RowIndicesT (&rowIndices)[RowIndicesN], const ColIndices& colIndices) { - return IndexedView::type>( - derived(), rowIndices, internal::make_indexing(colIndices,derived().cols())); - } - - template - IndexedView::type, const ColIndicesT (&)[ColIndicesN]> - operator()(const RowIndices& rowIndices, const ColIndicesT (&colIndices)[ColIndicesN]) { - return IndexedView::type,const ColIndicesT (&)[ColIndicesN]>( - derived(), internal::make_indexing(rowIndices,derived().rows()), colIndices); - } - - template - IndexedView - operator()(const RowIndicesT (&rowIndices)[RowIndicesN], const ColIndicesT (&colIndices)[ColIndicesN]) { - return IndexedView( - derived(), rowIndices, colIndices); - } - #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 diff --git a/Eigen/src/Core/IndexedView.h b/Eigen/src/Core/IndexedView.h index 81ff53758..269882e78 100644 --- a/Eigen/src/Core/IndexedView.h +++ b/Eigen/src/Core/IndexedView.h @@ -71,8 +71,8 @@ class IndexedViewImpl; * \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 + * 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: diff --git a/Eigen/src/plugins/IndexedViewMethods.h b/Eigen/src/plugins/IndexedViewMethods.h new file mode 100644 index 000000000..53eff093c --- /dev/null +++ b/Eigen/src/plugins/IndexedViewMethods.h @@ -0,0 +1,81 @@ +// This file is part of Eigen, a lightweight C++ template library +// for linear algebra. +// +// Copyright (C) 2017 Gael Guennebaud +// +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. + + +// This file is 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 + +template +struct EIGEN_INDEXED_VIEW_METHOD_TYPE { + typedef IndexedView::type,typename internal::MakeIndexing::type> type; +}; + +template +typename internal::enable_if< + ! (internal::traits::type>::IsBlockAlike + || (internal::is_integral::value && internal::is_integral::value)), + typename EIGEN_INDEXED_VIEW_METHOD_TYPE::type >::type +operator()(const RowIndices& rowIndices, const ColIndices& colIndices) EIGEN_INDEXED_VIEW_METHOD_CONST { + return typename EIGEN_INDEXED_VIEW_METHOD_TYPE::type( + derived(), internal::make_indexing(rowIndices,derived().rows()), internal::make_indexing(colIndices,derived().cols())); +} + +template +typename internal::enable_if< + internal::traits::type>::IsBlockAlike + && !(internal::is_integral::value && internal::is_integral::value), + typename internal::traits::type>::BlockType>::type +operator()(const RowIndices& rowIndices, const ColIndices& colIndices) EIGEN_INDEXED_VIEW_METHOD_CONST { + typedef typename internal::traits::type>::BlockType BlockType; + typename internal::MakeIndexing::type actualRowIndices = internal::make_indexing(rowIndices,derived().rows()); + typename internal::MakeIndexing::type actualColIndices = internal::make_indexing(colIndices,derived().cols()); + return BlockType(derived(), + internal::first(actualRowIndices), + internal::first(actualColIndices), + internal::size(actualRowIndices), + internal::size(actualColIndices)); +} + +template +IndexedView::type> +operator()(const RowIndicesT (&rowIndices)[RowIndicesN], const ColIndices& colIndices) EIGEN_INDEXED_VIEW_METHOD_CONST { + return IndexedView::type>( + derived(), rowIndices, internal::make_indexing(colIndices,derived().cols())); +} + +template +IndexedView::type, const ColIndicesT (&)[ColIndicesN]> +operator()(const RowIndices& rowIndices, const ColIndicesT (&colIndices)[ColIndicesN]) EIGEN_INDEXED_VIEW_METHOD_CONST { + return IndexedView::type,const ColIndicesT (&)[ColIndicesN]>( + derived(), internal::make_indexing(rowIndices,derived().rows()), colIndices); +} + +template +IndexedView +operator()(const RowIndicesT (&rowIndices)[RowIndicesN], const ColIndicesT (&colIndices)[ColIndicesN]) EIGEN_INDEXED_VIEW_METHOD_CONST { + return IndexedView( + derived(), rowIndices, colIndices); +} + +#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 + -- cgit v1.2.3 From 1b5570988bd2d6f783874e2d4fd6b7be45c8ac3c Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Tue, 10 Jan 2017 22:58:58 +0100 Subject: Add doc to seq, seqN, ArithmeticSequence, operator(), etc. --- Eigen/src/Core/ArithmeticSequence.h | 91 +++++++++++++++++++++++++++++++++- Eigen/src/Core/IndexedView.h | 4 +- Eigen/src/plugins/IndexedViewMethods.h | 88 +++++++++++++++++++++++++------- 3 files changed, 162 insertions(+), 21 deletions(-) diff --git a/Eigen/src/Core/ArithmeticSequence.h b/Eigen/src/Core/ArithmeticSequence.h index bbedd99c2..0fadfb86c 100644 --- a/Eigen/src/Core/ArithmeticSequence.h +++ b/Eigen/src/Core/ArithmeticSequence.h @@ -17,6 +17,8 @@ namespace Eigen { //-------------------------------------------------------------------------------- struct all_t { all_t() {} }; + +/** Can be used as a parameter to DenseBase::operator()(const RowIndices&, const ColIndices&) to index all rows or columns */ static const all_t all; //-------------------------------------------------------------------------------- @@ -24,7 +26,10 @@ static const all_t all; //-------------------------------------------------------------------------------- -/** This namespace defines a set of classes and functions to build and evaluate symbolic expressions of scalar type Index. +/** \namespace 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 @@ -42,6 +47,7 @@ static const all_t all; * // 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. * @@ -218,13 +224,39 @@ protected: } // end namespace Symbolic +/** \namespace placeholders + */ namespace placeholders { namespace internal { struct symbolic_last_tag {}; } +/** Can be used as a parameter to seq and 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 last; + +/** Can be used as a parameter to seq and 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 + */ static const Symbolic::AddExpr,Symbolic::ValueExpr> end(last+1); } // end namespace placeholders @@ -265,6 +297,24 @@ inline fix_t fix() { return fix_t(); } // seq(first,last,incr) and seqN(first,size,incr) //-------------------------------------------------------------------------------- +/** \class ArithemeticSequence + * + * 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 seq and 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 seq, seqN, DenseBase::operator()(const RowIndices&, const ColIndices&), class IndexedView + */ template > class ArithemeticSequence { @@ -278,8 +328,13 @@ public: IncrAtCompileTime = get_compile_time::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; } @@ -301,18 +356,50 @@ template struct cleanup_seq_type (*)() > { typedef fix_t type } +/** \returns an ArithemeticSequence starting at \a first, of length \a size, and increment \a incr + * \sa seqN(FirstType,SizeType), seq(FirstType,LastType,IncrType) */ template ArithemeticSequence::type,typename internal::cleanup_seq_type::type,typename internal::cleanup_seq_type::type > seqN(FirstType first, SizeType size, IncrType incr) { return ArithemeticSequence::type,typename internal::cleanup_seq_type::type,typename internal::cleanup_seq_type::type>(first,size,incr); } +/** \returns an ArithemeticSequence starting at \a first, of length \a size, and unit increment + * \sa seqN(FirstType,SizeType,IncrType), seq(FirstType,LastType) */ template ArithemeticSequence::type,typename internal::cleanup_seq_type::type > seqN(FirstType first, SizeType size) { return ArithemeticSequence::type,typename internal::cleanup_seq_type::type>(first,size); } +#ifdef EIGEN_PARSED_BY_DOXYGEN + +/** \returns an ArithemeticSequence 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 +auto seq(FirstType f, LastType l); + +/** \returns an ArithemeticSequence 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 +auto seq(FirstType f, LastType l, IncrType incr); + +#else // EIGEN_PARSED_BY_DOXYGEN + #if EIGEN_HAS_CXX11 template auto seq(FirstType f, LastType l) -> decltype(seqN(f,(l-f+fix<1>()))) @@ -414,6 +501,8 @@ seq(const Symbolic::BaseExpr &f, const Symbolic::BaseExpr diff --git a/Eigen/src/Core/IndexedView.h b/Eigen/src/Core/IndexedView.h index 269882e78..781cebd4e 100644 --- a/Eigen/src/Core/IndexedView.h +++ b/Eigen/src/Core/IndexedView.h @@ -85,7 +85,7 @@ class IndexedViewImpl; * - std::vector * - std::valarray * - std::array - * - c++ arrays: int[N] + * - Plain C arrays: int[N] * - Eigen::ArrayXi * - decltype(ArrayXi::LinSpaced(...)) * - Any view/expressions of the previous types @@ -94,7 +94,7 @@ class IndexedViewImpl; * - Eigen::IntAsArray (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(). + * 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 */ diff --git a/Eigen/src/plugins/IndexedViewMethods.h b/Eigen/src/plugins/IndexedViewMethods.h index 53eff093c..ea1aa6e2e 100644 --- a/Eigen/src/plugins/IndexedViewMethods.h +++ b/Eigen/src/plugins/IndexedViewMethods.h @@ -7,6 +7,7 @@ // Public License v. 2.0. If 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 @@ -20,54 +21,67 @@ template struct EIGEN_INDEXED_VIEW_METHOD_TYPE { - typedef IndexedView::type,typename internal::MakeIndexing::type> type; + typedef IndexedView::type, + typename internal::MakeIndexing::type> type; }; +// This is the generic version + template typename internal::enable_if< ! (internal::traits::type>::IsBlockAlike || (internal::is_integral::value && internal::is_integral::value)), typename EIGEN_INDEXED_VIEW_METHOD_TYPE::type >::type -operator()(const RowIndices& rowIndices, const ColIndices& colIndices) EIGEN_INDEXED_VIEW_METHOD_CONST { - return typename EIGEN_INDEXED_VIEW_METHOD_TYPE::type( - derived(), internal::make_indexing(rowIndices,derived().rows()), internal::make_indexing(colIndices,derived().cols())); +operator()(const RowIndices& rowIndices, const ColIndices& colIndices) EIGEN_INDEXED_VIEW_METHOD_CONST +{ + return typename EIGEN_INDEXED_VIEW_METHOD_TYPE::type + (derived(), internal::make_indexing(rowIndices,derived().rows()), internal::make_indexing(colIndices,derived().cols())); } +// The folowing overload returns a Block<> object + template typename internal::enable_if< internal::traits::type>::IsBlockAlike && !(internal::is_integral::value && internal::is_integral::value), typename internal::traits::type>::BlockType>::type -operator()(const RowIndices& rowIndices, const ColIndices& colIndices) EIGEN_INDEXED_VIEW_METHOD_CONST { +operator()(const RowIndices& rowIndices, const ColIndices& colIndices) EIGEN_INDEXED_VIEW_METHOD_CONST +{ typedef typename internal::traits::type>::BlockType BlockType; typename internal::MakeIndexing::type actualRowIndices = internal::make_indexing(rowIndices,derived().rows()); typename internal::MakeIndexing::type actualColIndices = internal::make_indexing(colIndices,derived().cols()); return BlockType(derived(), - internal::first(actualRowIndices), - internal::first(actualColIndices), - internal::size(actualRowIndices), - internal::size(actualColIndices)); + internal::first(actualRowIndices), + internal::first(actualColIndices), + internal::size(actualRowIndices), + internal::size(actualColIndices)); } +// The folowing three overloads are needed to handle raw Index[N] arrays. + template IndexedView::type> -operator()(const RowIndicesT (&rowIndices)[RowIndicesN], const ColIndices& colIndices) EIGEN_INDEXED_VIEW_METHOD_CONST { - return IndexedView::type>( - derived(), rowIndices, internal::make_indexing(colIndices,derived().cols())); +operator()(const RowIndicesT (&rowIndices)[RowIndicesN], const ColIndices& colIndices) EIGEN_INDEXED_VIEW_METHOD_CONST +{ + return IndexedView::type> + (derived(), rowIndices, internal::make_indexing(colIndices,derived().cols())); } template IndexedView::type, const ColIndicesT (&)[ColIndicesN]> -operator()(const RowIndices& rowIndices, const ColIndicesT (&colIndices)[ColIndicesN]) EIGEN_INDEXED_VIEW_METHOD_CONST { - return IndexedView::type,const ColIndicesT (&)[ColIndicesN]>( - derived(), internal::make_indexing(rowIndices,derived().rows()), colIndices); +operator()(const RowIndices& rowIndices, const ColIndicesT (&colIndices)[ColIndicesN]) EIGEN_INDEXED_VIEW_METHOD_CONST +{ + return IndexedView::type,const ColIndicesT (&)[ColIndicesN]> + (derived(), internal::make_indexing(rowIndices,derived().rows()), colIndices); } template IndexedView -operator()(const RowIndicesT (&rowIndices)[RowIndicesN], const ColIndicesT (&colIndices)[ColIndicesN]) EIGEN_INDEXED_VIEW_METHOD_CONST { - return IndexedView( - derived(), rowIndices, colIndices); +operator()(const RowIndicesT (&rowIndices)[RowIndicesN], const ColIndicesT (&colIndices)[ColIndicesN]) EIGEN_INDEXED_VIEW_METHOD_CONST +{ + return IndexedView + (derived(), rowIndices, colIndices); } #undef EIGEN_INDEXED_VIEW_METHOD_CONST @@ -79,3 +93,41 @@ operator()(const RowIndicesT (&rowIndices)[RowIndicesN], const ColIndicesT (&col #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 ArithemeticSequence as returned by the seq and 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 + * operator[]() const; + * size() const; + * \endcode + * where \c 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 ArithemeticSequence with compile-time increment strictly equal to 1, as returned by seq(a,b), and seqN(a,N). + * + * Otherwise a more general IndexedView object will be returned, after conversion of the inputs + * to more suitable types \c RowIndices' and \c ColIndices'. + * + * \sa class Block, class IndexedView, DenseBase::block(Index,Index,Index,Index) + */ +template +IndexedView_or_Block +operator()(const RowIndices& rowIndices, const ColIndices& colIndices); + +#endif // EIGEN_PARSED_BY_DOXYGEN + -- cgit v1.2.3 From 45199b97730cc8f4773d7133478e3296b25c18ba Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Wed, 11 Jan 2017 09:34:08 +0100 Subject: Fix typo --- doc/snippets/Cwise_boolean_xor.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/snippets/Cwise_boolean_xor.cpp b/doc/snippets/Cwise_boolean_xor.cpp index 99bcc5e09..fafbec806 100644 --- a/doc/snippets/Cwise_boolean_xor.cpp +++ b/doc/snippets/Cwise_boolean_xor.cpp @@ -1,2 +1,2 @@ -.Array3d v(-1,2,1), w(-3,2,3); +Array3d v(-1,2,1), w(-3,2,3); cout << ((v Date: Wed, 11 Jan 2017 13:17:09 +0100 Subject: Add 1D overloads of operator() --- Eigen/src/plugins/IndexedViewMethods.h | 70 +++++++++++++++++++++++++++++++++- test/indexed_view.cpp | 32 ++++++++++++++-- 2 files changed, 97 insertions(+), 5 deletions(-) diff --git a/Eigen/src/plugins/IndexedViewMethods.h b/Eigen/src/plugins/IndexedViewMethods.h index ea1aa6e2e..7d63f8d62 100644 --- a/Eigen/src/plugins/IndexedViewMethods.h +++ b/Eigen/src/plugins/IndexedViewMethods.h @@ -13,7 +13,7 @@ #ifndef EIGEN_INDEXED_VIEW_METHOD_2ND_PASS #define EIGEN_INDEXED_VIEW_METHOD_CONST const -#define EIGEN_INDEXED_VIEW_METHOD_TYPE ConstIndexedViewType +#define EIGEN_INDEXED_VIEW_METHOD_TYPE ConstIndexedViewType #else #define EIGEN_INDEXED_VIEW_METHOD_CONST #define EIGEN_INDEXED_VIEW_METHOD_TYPE IndexedViewType @@ -84,6 +84,62 @@ operator()(const RowIndicesT (&rowIndices)[RowIndicesN], const ColIndicesT (&col (derived(), rowIndices, colIndices); } +// Overloads for 1D vectors/arrays + +template +typename internal::enable_if< + IsRowMajor && (!(internal::get_compile_time_incr::type>::value==1 || internal::is_integral::value)), + IndexedView::type,typename internal::MakeIndexing::type> >::type +operator()(const Indices& indices) EIGEN_INDEXED_VIEW_METHOD_CONST +{ + EIGEN_STATIC_ASSERT_VECTOR_ONLY(Derived) + return IndexedView::type,typename internal::MakeIndexing::type> + (derived(), internal::make_indexing(0,derived().rows()), internal::make_indexing(indices,derived().cols())); +} + +template +typename internal::enable_if< + (!IsRowMajor) && (!(internal::get_compile_time_incr::type>::value==1 || internal::is_integral::value)), + IndexedView::type,typename internal::MakeIndexing::type> >::type +operator()(const Indices& indices) EIGEN_INDEXED_VIEW_METHOD_CONST +{ + EIGEN_STATIC_ASSERT_VECTOR_ONLY(Derived) + return IndexedView::type,typename internal::MakeIndexing::type> + (derived(), internal::make_indexing(indices,derived().rows()), internal::make_indexing(Index(0),derived().cols())); +} + +template +typename internal::enable_if< + (internal::get_compile_time_incr::type>::value==1) && (!internal::is_integral::value), + VectorBlock::value> >::type +operator()(const Indices& indices) EIGEN_INDEXED_VIEW_METHOD_CONST +{ + EIGEN_STATIC_ASSERT_VECTOR_ONLY(Derived) + typename internal::MakeIndexing::type actualIndices = internal::make_indexing(indices,derived().size()); + return VectorBlock::value> + (derived(), internal::first(actualIndices), internal::size(actualIndices)); +} + +template +typename internal::enable_if::type,const IndicesT (&)[IndicesN]> >::type +operator()(const IndicesT (&indices)[IndicesN]) EIGEN_INDEXED_VIEW_METHOD_CONST +{ + EIGEN_STATIC_ASSERT_VECTOR_ONLY(Derived) + return IndexedView::type,const IndicesT (&)[IndicesN]> + (derived(), internal::make_indexing(0,derived().rows()), indices); +} + +template +typename internal::enable_if::type> >::type +operator()(const IndicesT (&indices)[IndicesN]) EIGEN_INDEXED_VIEW_METHOD_CONST +{ + EIGEN_STATIC_ASSERT_VECTOR_ONLY(Derived) + return IndexedView::type> + (derived(), indices, internal::make_indexing(0,derived().rows())); +} + #undef EIGEN_INDEXED_VIEW_METHOD_CONST #undef EIGEN_INDEXED_VIEW_METHOD_TYPE @@ -123,11 +179,21 @@ operator()(const RowIndicesT (&rowIndices)[RowIndicesN], const ColIndicesT (&col * Otherwise a more general IndexedView object will be returned, after conversion of the inputs * to more suitable types \c RowIndices' and \c ColIndices'. * - * \sa class Block, class IndexedView, DenseBase::block(Index,Index,Index,Index) + * 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 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 +IndexedView_or_VectorBlock +operator()(const Indices& indices); + #endif // EIGEN_PARSED_BY_DOXYGEN diff --git a/test/indexed_view.cpp b/test/indexed_view.cpp index 42d136847..c15a8306a 100644 --- a/test/indexed_view.cpp +++ b/test/indexed_view.cpp @@ -33,9 +33,10 @@ IndexPair decode(Index ij) { template bool match(const T& xpr, std::string ref, std::string str_xpr = "") { EIGEN_UNUSED_VARIABLE(str_xpr); - //std::cout << str_xpr << "\n" << xpr << "\n\n"; std::stringstream str; str << xpr; + if(!(str.str() == ref)) + std::cout << str_xpr << "\n" << xpr << "\n\n"; return str.str() == ref; } @@ -55,15 +56,16 @@ void check_indexed_view() Index n = 10; + ArrayXd a = ArrayXd::LinSpaced(n,0,n-1); + Array b = a.transpose(); + ArrayXXi A = ArrayXXi::NullaryExpr(n,n, std::ptr_fun(encode)); for(Index i=0; i vala(10); Map(&vala[0],10) = eia; std::valarray vali(4); Map(&vali[0],4) = eii; std::vector veci(4); Map(veci.data(),4) = eii; @@ -118,6 +120,19 @@ void check_indexed_view() "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); @@ -180,6 +195,11 @@ void check_indexed_view() VERIFY( is_same_type(cA.block(0,0,2,2), cA(seqN(0,2),seq(0,1))) ); VERIFY( is_same_type(cA.middleRows(2,4), cA(seqN(2,4),all)) ); VERIFY( is_same_type(cA.middleCols(2,4), cA(all,seqN(2,4))) ); + + VERIFY( is_same_type(a.head(4), a(seq(0,3))) ); + VERIFY( is_same_type(a.tail(4), a(seqN(last-3,4))) ); + VERIFY( is_same_type(a.tail(4), a(seq(end-4,last))) ); + VERIFY( is_same_type(a.segment<4>(3), a(seqN(3,fix<4>))) ); } ArrayXXi A1=A, A2 = ArrayXXi::Random(4,4); @@ -203,6 +223,12 @@ void check_indexed_view() 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{{3, 1, 6, 5}}) ); + VERIFY_IS_EQUAL( a({1,3,5}).SizeAtCompileTime, 3 ); + + VERIFY_IS_APPROX( b({3, 1, 6, 5}), b(std::array{{3, 1, 6, 5}}) ); + VERIFY_IS_EQUAL( b({1,3,5}).SizeAtCompileTime, 3 ); #endif #endif -- cgit v1.2.3 From b1dc0fa81321b5c46c3d1d654d29969b7a337c85 Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Wed, 11 Jan 2017 14:28:28 +0100 Subject: Move fix and symbolic to their own file, and improve doxygen compatibility --- Eigen/Core | 2 + Eigen/src/Core/ArithmeticSequence.h | 296 +++++---------------------------- Eigen/src/Core/IndexedView.h | 3 +- Eigen/src/Core/util/IntegralConstant.h | 87 ++++++++++ Eigen/src/Core/util/SymbolicIndex.h | 218 ++++++++++++++++++++++++ Eigen/src/plugins/IndexedViewMethods.h | 4 +- 6 files changed, 353 insertions(+), 257 deletions(-) create mode 100644 Eigen/src/Core/util/IntegralConstant.h create mode 100644 Eigen/src/Core/util/SymbolicIndex.h diff --git a/Eigen/Core b/Eigen/Core index a93e3ce65..563a71ff8 100644 --- a/Eigen/Core +++ b/Eigen/Core @@ -354,6 +354,8 @@ 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" diff --git a/Eigen/src/Core/ArithmeticSequence.h b/Eigen/src/Core/ArithmeticSequence.h index 0fadfb86c..c221afcfd 100644 --- a/Eigen/src/Core/ArithmeticSequence.h +++ b/Eigen/src/Core/ArithmeticSequence.h @@ -16,215 +16,22 @@ namespace Eigen { // Pseudo keywords: all, last, end //-------------------------------------------------------------------------------- -struct all_t { all_t() {} }; - -/** Can be used as a parameter to DenseBase::operator()(const RowIndices&, const ColIndices&) to index all rows or columns */ -static const all_t all; +namespace internal { -//-------------------------------------------------------------------------------- -// minimalistic symbolic scalar type -//-------------------------------------------------------------------------------- +struct all_t { all_t() {} }; +} -/** \namespace Symbolic +/** \var all * \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; - * struct y_tag {}; static const Symbolic::SymbolExpr y; - * struct z_tag {}; static const Symbolic::SymbolExpr 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. - * + * Can be used as a parameter to DenseBase::operator()(const RowIndices&, const ColIndices&) to index all rows or columns */ -namespace Symbolic { - -template class Symbol; -template class NegateExpr; -template class AddExpr; -template class ProductExpr; -template class QuotientExpr; - -// A simple wrapper around an Index to provide the eval method. -// We could also use a free-function symbolic_eval... -class ValueExpr { -public: - ValueExpr(Index val) : m_value(val) {} - template - Index eval_impl(const T&) const { return m_value; } -protected: - Index m_value; -}; - -/** \class BaseExpr - * Common base class of any symbolic expressions - */ -template -class BaseExpr -{ -public: - const Derived& derived() const { return *static_cast(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 - Index eval(const T& values) const { return derived().eval_impl(values); } - -#if __cplusplus > 201103L - template - Index eval(Types&&... values) const { return derived().eval_impl(std::make_tuple(values...)); } -#endif - - NegateExpr operator-() const { return NegateExpr(derived()); } - - AddExpr operator+(Index b) const - { return AddExpr(derived(), b); } - AddExpr operator-(Index a) const - { return AddExpr(derived(), -a); } - QuotientExpr operator/(Index a) const - { return QuotientExpr(derived(),a); } - - friend AddExpr operator+(Index a, const BaseExpr& b) - { return AddExpr(b.derived(), a); } - friend AddExpr,ValueExpr> operator-(Index a, const BaseExpr& b) - { return AddExpr,ValueExpr>(-b.derived(), a); } - friend AddExpr operator/(Index a, const BaseExpr& b) - { return AddExpr(a,b.derived()); } - - template - AddExpr operator+(const BaseExpr &b) const - { return AddExpr(derived(), b.derived()); } - - template - AddExpr > operator-(const BaseExpr &b) const - { return AddExpr >(derived(), -b.derived()); } - - template - QuotientExpr operator/(const BaseExpr &b) const - { return QuotientExpr(derived(), b.derived()); } -}; +static const internal::all_t all; -template -struct is_symbolic { - // BaseExpr has no conversion ctor, so we only to check whether T can be staticaly cast to its base class BaseExpr. - enum { value = internal::is_convertible >::value }; -}; - -/** Represents the actual value of a symbol identified by its tag +/** \namespace Eigen::placeholders + * \ingroup Core_Module * - * It is the return type of SymbolValue::operator=, and most of the time this is only way it is used. - */ -template -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 tag \tparam TagT */ -template -class SymbolExpr : public BaseExpr > -{ -public: - typedef TagT 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 operator=(Index val) const { - return SymbolValue(val); - } - - Index eval_impl(const SymbolValue &values) const { return values.value(); } - -#if __cplusplus > 201103L - // C++14 versions suitable for multiple symbols - template - Index eval_impl(const std::tuple& values) const { return std::get >(values).value(); } -#endif -}; - -template -class NegateExpr : public BaseExpr > -{ -public: - NegateExpr(const Arg0& arg0) : m_arg0(arg0) {} - - template - Index eval_impl(const T& values) const { return -m_arg0.eval_impl(values); } -protected: - Arg0 m_arg0; -}; - -template -class AddExpr : public BaseExpr > -{ -public: - AddExpr(const Arg0& arg0, const Arg1& arg1) : m_arg0(arg0), m_arg1(arg1) {} - - template - 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 -class ProductExpr : public BaseExpr > -{ -public: - ProductExpr(const Arg0& arg0, const Arg1& arg1) : m_arg0(arg0), m_arg1(arg1) {} - - template - 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 -class QuotientExpr : public BaseExpr > -{ -public: - QuotientExpr(const Arg0& arg0, const Arg1& arg1) : m_arg0(arg0), m_arg1(arg1) {} - - template - 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 - -/** \namespace placeholders + * Namespace containing symbolic placeholders */ namespace placeholders { @@ -232,7 +39,10 @@ namespace internal { struct symbolic_last_tag {}; } -/** Can be used as a parameter to seq and seqN functions to symbolically reference the last element/row/columns +/** \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. @@ -249,7 +59,10 @@ struct symbolic_last_tag {}; */ static const Symbolic::SymbolExpr last; -/** Can be used as a parameter to seq and seqN functions to symbolically reference the last+1 element/row/columns +/** \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. @@ -257,53 +70,26 @@ static const Symbolic::SymbolExpr last; * * \sa last */ +#ifdef EIGEN_PARSED_BY_DOXYGEN +static const auto end = last+1; +#else static const Symbolic::AddExpr,Symbolic::ValueExpr> end(last+1); +#endif } // end namespace placeholders -//-------------------------------------------------------------------------------- -// integral constant -//-------------------------------------------------------------------------------- - -template struct fix_t { - static const int value = N; - operator int() const { return value; } - fix_t (fix_t (*)() ) {} - fix_t() {} - // Needed in C++14 to allow fix(): - fix_t operator() () const { return *this; } -}; - -template struct get_compile_time { - enum { value = Default }; -}; - -template struct get_compile_time,Default> { - enum { value = N }; -}; - -template struct is_compile_time { enum { value = false }; }; -template struct is_compile_time > { enum { value = true }; }; - -#if __cplusplus > 201103L -template -static const fix_t fix{}; -#else -template -inline fix_t fix() { return fix_t(); } -#endif - //-------------------------------------------------------------------------------- // seq(first,last,incr) and seqN(first,size,incr) //-------------------------------------------------------------------------------- /** \class ArithemeticSequence + * \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 seq and seqN functions, and as the input arguments + * 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. * @@ -313,9 +99,9 @@ inline fix_t fix() { return fix_t(); } * 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 seq, seqN, DenseBase::operator()(const RowIndices&, const ColIndices&), class IndexedView + * \sa Eigen::seq, Eigen::seqN, DenseBase::operator()(const RowIndices&, const ColIndices&), class IndexedView */ -template > +template > class ArithemeticSequence { @@ -324,8 +110,8 @@ public: ArithemeticSequence(FirstType first, SizeType size, IncrType incr) : m_first(first), m_size(size), m_incr(incr) {} enum { - SizeAtCompileTime = get_compile_time::value, - IncrAtCompileTime = get_compile_time::value + SizeAtCompileTime = internal::get_compile_time::value, + IncrAtCompileTime = internal::get_compile_time::value }; /** \returns the size, i.e., number of elements, of the sequence */ @@ -357,7 +143,8 @@ template struct cleanup_seq_type (*)() > { typedef fix_t type } /** \returns an ArithemeticSequence starting at \a first, of length \a size, and increment \a incr - * \sa seqN(FirstType,SizeType), seq(FirstType,LastType,IncrType) */ + * + * \sa seqN(FirstType,SizeType), seq(FirstType,LastType,IncrType) */ template ArithemeticSequence::type,typename internal::cleanup_seq_type::type,typename internal::cleanup_seq_type::type > seqN(FirstType first, SizeType size, IncrType incr) { @@ -365,6 +152,7 @@ seqN(FirstType first, SizeType size, IncrType incr) { } /** \returns an ArithemeticSequence starting at \a first, of length \a size, and unit increment + * * \sa seqN(FirstType,SizeType,IncrType), seq(FirstType,LastType) */ template ArithemeticSequence::type,typename internal::cleanup_seq_type::type > @@ -374,29 +162,29 @@ seqN(FirstType first, SizeType size) { #ifdef EIGEN_PARSED_BY_DOXYGEN -/** \returns an ArithemeticSequence starting at \a f, up (or down) to \a l, and unit increment +/** \returns an ArithemeticSequence 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+1); + * seqN(f, (l-f+incr)/incr, incr); * \endcode * - * \sa seqN(FirstType,SizeType), seq(FirstType,LastType,IncrType) + * \sa seqN(FirstType,SizeType,IncrType), seq(FirstType,LastType) */ -template -auto seq(FirstType f, LastType l); +template +auto seq(FirstType f, LastType l, IncrType incr); -/** \returns an ArithemeticSequence starting at \a f, up (or down) to \a l, and with positive (or negative) increment \a incr +/** \returns an ArithemeticSequence starting at \a f, up (or down) to \a l, and unit increment * * It is essentially an alias to: * \code - * seqN(f, (l-f+incr)/incr, incr); + * seqN(f,l-f+1); * \endcode * - * \sa seqN(FirstType,SizeType,IncrType), seq(FirstType,LastType) + * \sa seqN(FirstType,SizeType), seq(FirstType,LastType,IncrType) */ -template -auto seq(FirstType f, LastType l, IncrType incr); +template +auto seq(FirstType f, LastType l); #else // EIGEN_PARSED_BY_DOXYGEN @@ -681,7 +469,7 @@ inline Index eval_expr_given_size(shifted_last x, Index size) { return size+x.o inline Index eval_expr_given_size(end_t, Index size) { return size; } inline Index eval_expr_given_size(shifted_end x, Index size) { return size+x.offset; } -template > +template > class ArithemeticSequenceProxyWithBounds { public: @@ -690,7 +478,7 @@ public: enum { SizeAtCompileTime = -1, - IncrAtCompileTime = get_compile_time::value + IncrAtCompileTime = internal::get_compile_time::value }; Index size() const { return (m_last-m_first+m_incr)/m_incr; } diff --git a/Eigen/src/Core/IndexedView.h b/Eigen/src/Core/IndexedView.h index 781cebd4e..d975c6e80 100644 --- a/Eigen/src/Core/IndexedView.h +++ b/Eigen/src/Core/IndexedView.h @@ -94,7 +94,8 @@ class IndexedViewImpl; * - Eigen::IntAsArray (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&). + * 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 */ diff --git a/Eigen/src/Core/util/IntegralConstant.h b/Eigen/src/Core/util/IntegralConstant.h new file mode 100644 index 000000000..f6b206275 --- /dev/null +++ b/Eigen/src/Core/util/IntegralConstant.h @@ -0,0 +1,87 @@ +// This file is part of Eigen, a lightweight C++ template library +// for linear algebra. +// +// Copyright (C) 2017 Gael Guennebaud +// +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If 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 struct fix_t { + static const int value = N; + operator int() const { return value; } + fix_t (fix_t (*)() ) {} + fix_t() {} + // Needed in C++14 to allow fix(): + fix_t operator() () const { return *this; } +}; + +template struct get_compile_time { + enum { value = Default }; +}; + +template struct get_compile_time,Default> { + enum { value = N }; +}; + +template struct is_compile_time { enum { value = false }; }; +template struct is_compile_time > { enum { value = true }; }; + +} // end namespace internal + +#ifndef EIGEN_PARSED_BY_DOXYGEN + +#if __cplusplus > 201103L +template +static const internal::fix_t fix{}; +#else +template +inline internal::fix_t fix() { return internal::fix_t(); } +#endif + +#else // EIGEN_PARSED_BY_DOXYGEN + +/** \var fix + * \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 + * + * In c++14, it is implemented as: + * \code + * template static const internal::fix_t fix{}; + * \endcode + * where internal::fix_t is an internal template class similar to + * \c std::integral_constant + * Here, \c fix is thus an object of type \c internal::fix_t. + * + * In c++98/11, it is implemented as a function: + * \code + * template inline internal::fix_t fix(); + * \endcode + * Here internal::fix_t is thus a pointer to function. + * + * If for some reason you want a true object in c++98 then you can write: \code fix() \endcode which is also valid in c++14. + */ +template +static const auto fix; + +#endif // EIGEN_PARSED_BY_DOXYGEN + +} // end namespace Eigen + +#endif // EIGEN_INTEGRAL_CONSTANT_H diff --git a/Eigen/src/Core/util/SymbolicIndex.h b/Eigen/src/Core/util/SymbolicIndex.h new file mode 100644 index 000000000..03086d6fa --- /dev/null +++ b/Eigen/src/Core/util/SymbolicIndex.h @@ -0,0 +1,218 @@ +// This file is part of Eigen, a lightweight C++ template library +// for linear algebra. +// +// Copyright (C) 2017 Gael Guennebaud +// +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If 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; + * struct y_tag {}; static const Symbolic::SymbolExpr y; + * struct z_tag {}; static const Symbolic::SymbolExpr 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 class Symbol; +template class NegateExpr; +template class AddExpr; +template class ProductExpr; +template class QuotientExpr; + +// A simple wrapper around an Index to provide the eval method. +// We could also use a free-function symbolic_eval... +class ValueExpr { +public: + ValueExpr(Index val) : m_value(val) {} + template + Index eval_impl(const T&) const { return m_value; } +protected: + Index m_value; +}; + +/** \class BaseExpr + * \ingroup Core_Module + * Common base class of any symbolic expressions + */ +template +class BaseExpr +{ +public: + const Derived& derived() const { return *static_cast(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 + Index eval(const T& values) const { return derived().eval_impl(values); } + +#if __cplusplus > 201103L + template + Index eval(Types&&... values) const { return derived().eval_impl(std::make_tuple(values...)); } +#endif + + NegateExpr operator-() const { return NegateExpr(derived()); } + + AddExpr operator+(Index b) const + { return AddExpr(derived(), b); } + AddExpr operator-(Index a) const + { return AddExpr(derived(), -a); } + QuotientExpr operator/(Index a) const + { return QuotientExpr(derived(),a); } + + friend AddExpr operator+(Index a, const BaseExpr& b) + { return AddExpr(b.derived(), a); } + friend AddExpr,ValueExpr> operator-(Index a, const BaseExpr& b) + { return AddExpr,ValueExpr>(-b.derived(), a); } + friend AddExpr operator/(Index a, const BaseExpr& b) + { return AddExpr(a,b.derived()); } + + template + AddExpr operator+(const BaseExpr &b) const + { return AddExpr(derived(), b.derived()); } + + template + AddExpr > operator-(const BaseExpr &b) const + { return AddExpr >(derived(), -b.derived()); } + + template + QuotientExpr operator/(const BaseExpr &b) const + { return QuotientExpr(derived(), b.derived()); } +}; + +template +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. + enum { value = internal::is_convertible >::value }; +}; + +/** 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 +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 +class SymbolExpr : public BaseExpr > +{ +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 operator=(Index val) const { + return SymbolValue(val); + } + + Index eval_impl(const SymbolValue &values) const { return values.value(); } + +#if __cplusplus > 201103L + // C++14 versions suitable for multiple symbols + template + Index eval_impl(const std::tuple& values) const { return std::get >(values).value(); } +#endif +}; + +template +class NegateExpr : public BaseExpr > +{ +public: + NegateExpr(const Arg0& arg0) : m_arg0(arg0) {} + + template + Index eval_impl(const T& values) const { return -m_arg0.eval_impl(values); } +protected: + Arg0 m_arg0; +}; + +template +class AddExpr : public BaseExpr > +{ +public: + AddExpr(const Arg0& arg0, const Arg1& arg1) : m_arg0(arg0), m_arg1(arg1) {} + + template + 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 +class ProductExpr : public BaseExpr > +{ +public: + ProductExpr(const Arg0& arg0, const Arg1& arg1) : m_arg0(arg0), m_arg1(arg1) {} + + template + 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 +class QuotientExpr : public BaseExpr > +{ +public: + QuotientExpr(const Arg0& arg0, const Arg1& arg1) : m_arg0(arg0), m_arg1(arg1) {} + + template + 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 diff --git a/Eigen/src/plugins/IndexedViewMethods.h b/Eigen/src/plugins/IndexedViewMethods.h index 7d63f8d62..ae817e90b 100644 --- a/Eigen/src/plugins/IndexedViewMethods.h +++ b/Eigen/src/plugins/IndexedViewMethods.h @@ -157,7 +157,7 @@ operator()(const IndicesT (&indices)[IndicesN]) EIGEN_INDEXED_VIEW_METHOD_CONST * 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 ArithemeticSequence as returned by the seq and seqN functions + * - An ArithemeticSequence 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: @@ -174,7 +174,7 @@ operator()(const IndicesT (&indices)[IndicesN]) EIGEN_INDEXED_VIEW_METHOD_CONST * when all arguments are either: * - An integer * - Eigen::all - * - An ArithemeticSequence with compile-time increment strictly equal to 1, as returned by seq(a,b), and seqN(a,N). + * - An ArithemeticSequence 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 object will be returned, after conversion of the inputs * to more suitable types \c RowIndices' and \c ColIndices'. -- cgit v1.2.3 From 152cd57bb7d38d3805c3845757ef72563e53a510 Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Wed, 11 Jan 2017 14:29:20 +0100 Subject: Enable generation of doc for static variables in Eigen's namespace. --- doc/Doxyfile.in | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/Doxyfile.in b/doc/Doxyfile.in index 48bb0a8ec..b42de1bdb 100644 --- a/doc/Doxyfile.in +++ b/doc/Doxyfile.in @@ -409,7 +409,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. -- cgit v1.2.3 From c020d307a657a3783c593c4ce2b6a8325a04cd70 Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Wed, 11 Jan 2017 17:08:05 +0100 Subject: Make variable_if_dynamic implicitely convertible to T --- Eigen/src/Core/util/XprHelper.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Eigen/src/Core/util/XprHelper.h b/Eigen/src/Core/util/XprHelper.h index b94dd61ff..640753047 100644 --- a/Eigen/src/Core/util/XprHelper.h +++ b/Eigen/src/Core/util/XprHelper.h @@ -109,6 +109,7 @@ template 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 class variable_if_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; } }; -- cgit v1.2.3 From f93d1c58e09b8435191a55f123873d8f496620b6 Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Wed, 11 Jan 2017 17:08:59 +0100 Subject: Make get_compile_time compatible with variable_if_dynamic --- Eigen/src/Core/util/IntegralConstant.h | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/Eigen/src/Core/util/IntegralConstant.h b/Eigen/src/Core/util/IntegralConstant.h index f6b206275..a4394c464 100644 --- a/Eigen/src/Core/util/IntegralConstant.h +++ b/Eigen/src/Core/util/IntegralConstant.h @@ -32,6 +32,12 @@ template struct get_compile_time,Default> { enum { value = N }; }; +template +struct get_compile_time,Default> { + enum { value = N }; +}; + + template struct is_compile_time { enum { value = false }; }; template struct is_compile_time > { enum { value = true }; }; -- cgit v1.2.3 From 752bd92ba53de344eba66b8cec4480f9d3207025 Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Wed, 11 Jan 2017 17:24:02 +0100 Subject: Large code refactoring: - generalize some utilities and move them to Meta (size(), array_size()) - move handling of all and single indices to IndexedViewHelper.h - several cleanup changes --- Eigen/Core | 1 + Eigen/src/Core/ArithmeticSequence.h | 135 +++----------------------------- Eigen/src/Core/IndexedView.h | 7 +- Eigen/src/Core/util/IndexedViewHelper.h | 111 ++++++++++++++++++++++++++ Eigen/src/Core/util/Meta.h | 47 +++++++++++ Eigen/src/plugins/IndexedViewMethods.h | 96 ++++++++++++++++------- test/indexed_view.cpp | 1 + 7 files changed, 244 insertions(+), 154 deletions(-) create mode 100644 Eigen/src/Core/util/IndexedViewHelper.h diff --git a/Eigen/Core b/Eigen/Core index 563a71ff8..38306e11d 100644 --- a/Eigen/Core +++ b/Eigen/Core @@ -420,6 +420,7 @@ 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" diff --git a/Eigen/src/Core/ArithmeticSequence.h b/Eigen/src/Core/ArithmeticSequence.h index c221afcfd..afb014ac5 100644 --- a/Eigen/src/Core/ArithmeticSequence.h +++ b/Eigen/src/Core/ArithmeticSequence.h @@ -12,26 +12,10 @@ namespace Eigen { -//-------------------------------------------------------------------------------- -// Pseudo keywords: all, last, end -//-------------------------------------------------------------------------------- - -namespace internal { - -struct all_t { all_t() {} }; - -} - -/** \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 internal::all_t all; - /** \namespace Eigen::placeholders * \ingroup Core_Module * - * Namespace containing symbolic placeholders + * Namespace containing symbolic placeholder and identifiers */ namespace placeholders { @@ -268,7 +252,7 @@ typename internal::enable_if::value, Symbolic::QuotientExpr, Symbolic::ValueExpr>, Symbolic::ValueExpr>, - typename internal::cleanup_seq_type::type> >::type + typename internal::cleanup_seq_type::type> >::type seq(FirstType f, const Symbolic::BaseExpr &l, IncrType incr) { typedef typename internal::cleanup_seq_type::type CleanedIncrType; @@ -281,7 +265,7 @@ ArithemeticSequence >, Symbolic::ValueExpr>, Symbolic::ValueExpr>, - typename internal::cleanup_seq_type::type> + typename internal::cleanup_seq_type::type> seq(const Symbolic::BaseExpr &f, const Symbolic::BaseExpr &l, IncrType incr) { typedef typename internal::cleanup_seq_type::type CleanedIncrType; @@ -293,76 +277,6 @@ seq(const Symbolic::BaseExpr &f, const Symbolic::BaseExpr -Index size(const T& x) { return x.size(); } - -template -Index size(const T (&) [N]) { return N; } - -template -Index first(const T& x) { return x.first(); } - -template struct get_compile_time_size { - enum { value = Dynamic }; -}; - -template struct get_compile_time_size::type> { - enum { value = T::SizeAtCompileTime }; -}; - -template struct get_compile_time_size { - enum { value = N }; -}; - -#ifdef EIGEN_HAS_CXX11 -template struct get_compile_time_size,XprSize> { - enum { value = N }; -}; -#endif - -template struct get_compile_time_incr { - enum { value = UndefinedIncr }; -}; - -template -struct get_compile_time_incr > { - enum { value = get_compile_time::value }; -}; - - -// MakeIndexing/make_indexing turn an arbitrary object of type T into something usable by MatrixSlice -template -struct MakeIndexing { - typedef T type; -}; - -template -const T& make_indexing(const T& x, Index /*size*/) { return x; } - -struct IntAsArray { - enum { - SizeAtCompileTime = 1 - }; - IntAsArray(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 { - 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 -struct MakeIndexing::value>::type> { - // Here we could simply use Array, but maybe it's less work for the compiler to use - // a simpler wrapper as IntAsArray - //typedef Eigen::Array type; - typedef IntAsArray type; -}; - // Replace symbolic last/end "keywords" by their true runtime value inline Index eval_expr_given_size(Index x, Index /* size */) { return x; } @@ -381,45 +295,21 @@ struct make_size_type { typedef typename internal::conditional::value, Index, T>::type type; }; -template -struct MakeIndexing > { +template +struct IndexedViewCompatibleType, XprSize> { typedef ArithemeticSequence::type,IncrType> type; }; template ArithemeticSequence::type,IncrType> -make_indexing(const ArithemeticSequence& ids, Index size) { +makeIndexedViewCompatible(const ArithemeticSequence& ids, Index size) { return ArithemeticSequence::type,IncrType>( eval_expr_given_size(ids.firstObject(),size),eval_expr_given_size(ids.sizeObject(),size),ids.incrObject()); } -// Convert a symbolic 'all' into a usable range -// Implementation-wise, it would be more efficient to not having to store m_size since -// this information is already in the nested expression. To this end, we would need a -// get_size(indices, underlying_size); function returning indices.size() by default. -struct AllRange { - AllRange(Index size) : m_size(size) {} - Index operator[](Index i) const { return i; } - Index size() const { return m_size; } - Index first() const { return 0; } - Index m_size; -}; - -template<> -struct MakeIndexing { - typedef AllRange type; -}; - -inline AllRange make_indexing(all_t , Index size) { - return AllRange(size); -} - -template struct get_compile_time_size { - enum { value = XprSize }; -}; - -template<> struct get_compile_time_incr { - enum { value = 1 }; +template +struct get_compile_time_incr > { + enum { value = get_compile_time::value }; }; } // end namespace internal @@ -428,6 +318,7 @@ template<> struct get_compile_time_incr { namespace legacy { // Here are some initial code that I keep here for now to compare the quality of the code generated by the compilers +// This part will be removed once we have checked everything is right. struct shifted_last { explicit shifted_last(int o) : offset(o) {} @@ -522,14 +413,14 @@ struct get_compile_time_incr -struct MakeIndexing > { +template +struct IndexedViewCompatibleType,XprSize> { typedef legacy::ArithemeticSequenceProxyWithBounds type; }; template legacy::ArithemeticSequenceProxyWithBounds -make_indexing(const legacy::ArithemeticSequenceProxyWithBounds& ids, Index size) { +makeIndexedViewCompatible(const legacy::ArithemeticSequenceProxyWithBounds& ids, Index size) { return legacy::ArithemeticSequenceProxyWithBounds( eval_expr_given_size(ids.firstObject(),size),eval_expr_given_size(ids.lastObject(),size),ids.incrObject()); } diff --git a/Eigen/src/Core/IndexedView.h b/Eigen/src/Core/IndexedView.h index d975c6e80..38ee69638 100644 --- a/Eigen/src/Core/IndexedView.h +++ b/Eigen/src/Core/IndexedView.h @@ -19,8 +19,8 @@ struct traits > : traits { enum { - RowsAtCompileTime = get_compile_time_size::RowsAtCompileTime>::value, - ColsAtCompileTime = get_compile_time_size::ColsAtCompileTime>::value, + RowsAtCompileTime = array_size::value, + ColsAtCompileTime = array_size::value, MaxRowsAtCompileTime = RowsAtCompileTime != Dynamic ? int(RowsAtCompileTime) : int(traits::MaxRowsAtCompileTime), MaxColsAtCompileTime = ColsAtCompileTime != Dynamic ? int(ColsAtCompileTime) : int(traits::MaxColsAtCompileTime), @@ -38,8 +38,9 @@ struct traits > XprInnerStride = HasSameStorageOrderAsXprType ? int(inner_stride_at_compile_time::ret) : int(outer_stride_at_compile_time::ret), XprOuterstride = HasSameStorageOrderAsXprType ? int(outer_stride_at_compile_time::ret) : int(inner_stride_at_compile_time::ret), + InnerSize = XprTypeIsRowMajor ? ColsAtCompileTime : RowsAtCompileTime, IsBlockAlike = InnerIncr==1 && OuterIncr==1, - IsInnerPannel = HasSameStorageOrderAsXprType && is_same::type>::value, + IsInnerPannel = HasSameStorageOrderAsXprType && is_same,typename conditional::type>::value, InnerStrideAtCompileTime = InnerIncr<0 || InnerIncr==DynamicIndex || XprInnerStride==Dynamic ? Dynamic : XprInnerStride * InnerIncr, OuterStrideAtCompileTime = OuterIncr<0 || OuterIncr==DynamicIndex || XprOuterstride==Dynamic ? Dynamic : XprOuterstride * OuterIncr, diff --git a/Eigen/src/Core/util/IndexedViewHelper.h b/Eigen/src/Core/util/IndexedViewHelper.h new file mode 100644 index 000000000..4f6dd065e --- /dev/null +++ b/Eigen/src/Core/util/IndexedViewHelper.h @@ -0,0 +1,111 @@ +// This file is part of Eigen, a lightweight C++ template library +// for linear algebra. +// +// Copyright (C) 2017 Gael Guennebaud +// +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If 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 internal { + +// Extract increment/step at compile time +template struct get_compile_time_incr { + enum { value = UndefinedIncr }; +}; + +// Analogue of std::get<0>(x), but tailored for our needs. +template +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 +struct IndexedViewCompatibleType { + typedef T type; +}; + +template +const T& makeIndexedViewCompatible(const T& x, Index /*size*/) { 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 { + 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 +struct IndexedViewCompatibleType::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 type; + typedef SingleRange type; +}; + +//-------------------------------------------------------------------------------- +// Handling of all +//-------------------------------------------------------------------------------- + +struct all_t { all_t() {} }; + +// Convert a symbolic 'all' into a usable range type +template +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 m_size; +}; + +template +struct IndexedViewCompatibleType { + typedef AllRange type; +}; + +template +inline AllRange::value> makeIndexedViewCompatible(all_t , XprSizeType size) { + return AllRange::value>(size); +} + +template struct get_compile_time_incr > { + 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 diff --git a/Eigen/src/Core/util/Meta.h b/Eigen/src/Core/util/Meta.h index 7f6370755..804657f7b 100755 --- a/Eigen/src/Core/util/Meta.h +++ b/Eigen/src/Core/util/Meta.h @@ -278,6 +278,53 @@ 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 ease SFINAE-based specializations. + */ +template struct array_size { + enum { value = Dynamic }; +}; + +template struct array_size::type> { + enum { value = T::SizeAtCompileTime }; +}; + +template struct array_size { + enum { value = N }; +}; + +#ifdef EIGEN_HAS_CXX11 +template struct array_size > { + 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 +Index size(const T& x) { return x.size(); } + +template +Index size(const T (&) [N]) { return N; } + /** \internal * Convenient struct to get the result type of a unary or binary functor. * diff --git a/Eigen/src/plugins/IndexedViewMethods.h b/Eigen/src/plugins/IndexedViewMethods.h index ae817e90b..774a5cbe5 100644 --- a/Eigen/src/plugins/IndexedViewMethods.h +++ b/Eigen/src/plugins/IndexedViewMethods.h @@ -19,11 +19,49 @@ #define EIGEN_INDEXED_VIEW_METHOD_TYPE IndexedViewType #endif +#ifndef EIGEN_INDEXED_VIEW_METHOD_2ND_PASS +protected: + +// define some aliases to ease readability + +template +struct IvcRowType : public internal::IndexedViewCompatibleType {}; + +template +struct IvcColType : public internal::IndexedViewCompatibleType {}; + +template +struct IvcType : public internal::IndexedViewCompatibleType {}; + +typedef typename internal::IndexedViewCompatibleType::type IvcIndex; + +template +typename IvcRowType::type +ivcRow(const Indices& indices) const { + return internal::makeIndexedViewCompatible(indices, internal::variable_if_dynamic(derived().rows())); +}; + +template +typename IvcColType::type +ivcCol(const Indices& indices) const { + return internal::makeIndexedViewCompatible(indices, internal::variable_if_dynamic(derived().cols())); +}; + +template +typename IvcColType::type +ivcSize(const Indices& indices) const { + return internal::makeIndexedViewCompatible(indices, internal::variable_if_dynamic(derived().size())); +}; + +public: + +#endif + template struct EIGEN_INDEXED_VIEW_METHOD_TYPE { typedef IndexedView::type, - typename internal::MakeIndexing::type> type; + typename IvcRowType::type, + typename IvcColType::type> type; }; // This is the generic version @@ -36,7 +74,7 @@ typename internal::enable_if< operator()(const RowIndices& rowIndices, const ColIndices& colIndices) EIGEN_INDEXED_VIEW_METHOD_CONST { return typename EIGEN_INDEXED_VIEW_METHOD_TYPE::type - (derived(), internal::make_indexing(rowIndices,derived().rows()), internal::make_indexing(colIndices,derived().cols())); + (derived(), ivcRow(rowIndices), ivcCol(colIndices)); } // The folowing overload returns a Block<> object @@ -49,8 +87,8 @@ typename internal::enable_if< operator()(const RowIndices& rowIndices, const ColIndices& colIndices) EIGEN_INDEXED_VIEW_METHOD_CONST { typedef typename internal::traits::type>::BlockType BlockType; - typename internal::MakeIndexing::type actualRowIndices = internal::make_indexing(rowIndices,derived().rows()); - typename internal::MakeIndexing::type actualColIndices = internal::make_indexing(colIndices,derived().cols()); + typename IvcRowType::type actualRowIndices = ivcRow(rowIndices); + typename IvcColType::type actualColIndices = ivcCol(colIndices); return BlockType(derived(), internal::first(actualRowIndices), internal::first(actualColIndices), @@ -61,19 +99,19 @@ operator()(const RowIndices& rowIndices, const ColIndices& colIndices) EIGEN_IND // The folowing three overloads are needed to handle raw Index[N] arrays. template -IndexedView::type> +IndexedView::type> operator()(const RowIndicesT (&rowIndices)[RowIndicesN], const ColIndices& colIndices) EIGEN_INDEXED_VIEW_METHOD_CONST { - return IndexedView::type> - (derived(), rowIndices, internal::make_indexing(colIndices,derived().cols())); + return IndexedView::type> + (derived(), rowIndices, ivcCol(colIndices)); } template -IndexedView::type, const ColIndicesT (&)[ColIndicesN]> +IndexedView::type, const ColIndicesT (&)[ColIndicesN]> operator()(const RowIndices& rowIndices, const ColIndicesT (&colIndices)[ColIndicesN]) EIGEN_INDEXED_VIEW_METHOD_CONST { - return IndexedView::type,const ColIndicesT (&)[ColIndicesN]> - (derived(), internal::make_indexing(rowIndices,derived().rows()), colIndices); + return IndexedView::type,const ColIndicesT (&)[ColIndicesN]> + (derived(), ivcRow(rowIndices), colIndices); } template @@ -88,56 +126,56 @@ operator()(const RowIndicesT (&rowIndices)[RowIndicesN], const ColIndicesT (&col template typename internal::enable_if< - IsRowMajor && (!(internal::get_compile_time_incr::type>::value==1 || internal::is_integral::value)), - IndexedView::type,typename internal::MakeIndexing::type> >::type + IsRowMajor && (!(internal::get_compile_time_incr::type>::value==1 || internal::is_integral::value)), + IndexedView::type> >::type operator()(const Indices& indices) EIGEN_INDEXED_VIEW_METHOD_CONST { EIGEN_STATIC_ASSERT_VECTOR_ONLY(Derived) - return IndexedView::type,typename internal::MakeIndexing::type> - (derived(), internal::make_indexing(0,derived().rows()), internal::make_indexing(indices,derived().cols())); + return IndexedView::type> + (derived(), IvcIndex(0), ivcCol(indices)); } template typename internal::enable_if< - (!IsRowMajor) && (!(internal::get_compile_time_incr::type>::value==1 || internal::is_integral::value)), - IndexedView::type,typename internal::MakeIndexing::type> >::type + (!IsRowMajor) && (!(internal::get_compile_time_incr::type>::value==1 || internal::is_integral::value)), + IndexedView::type,IvcIndex> >::type operator()(const Indices& indices) EIGEN_INDEXED_VIEW_METHOD_CONST { EIGEN_STATIC_ASSERT_VECTOR_ONLY(Derived) - return IndexedView::type,typename internal::MakeIndexing::type> - (derived(), internal::make_indexing(indices,derived().rows()), internal::make_indexing(Index(0),derived().cols())); + return IndexedView::type,IvcIndex> + (derived(), ivcRow(indices), IvcIndex(0)); } template typename internal::enable_if< - (internal::get_compile_time_incr::type>::value==1) && (!internal::is_integral::value), - VectorBlock::value> >::type + (internal::get_compile_time_incr::type>::value==1) && (!internal::is_integral::value), + VectorBlock::value> >::type operator()(const Indices& indices) EIGEN_INDEXED_VIEW_METHOD_CONST { EIGEN_STATIC_ASSERT_VECTOR_ONLY(Derived) - typename internal::MakeIndexing::type actualIndices = internal::make_indexing(indices,derived().size()); - return VectorBlock::value> + typename IvcType::type actualIndices = ivcSize(indices); + return VectorBlock::value> (derived(), internal::first(actualIndices), internal::size(actualIndices)); } template typename internal::enable_if::type,const IndicesT (&)[IndicesN]> >::type + IndexedView >::type operator()(const IndicesT (&indices)[IndicesN]) EIGEN_INDEXED_VIEW_METHOD_CONST { EIGEN_STATIC_ASSERT_VECTOR_ONLY(Derived) - return IndexedView::type,const IndicesT (&)[IndicesN]> - (derived(), internal::make_indexing(0,derived().rows()), indices); + return IndexedView + (derived(), IvcIndex(0), indices); } template typename internal::enable_if::type> >::type + IndexedView >::type operator()(const IndicesT (&indices)[IndicesN]) EIGEN_INDEXED_VIEW_METHOD_CONST { EIGEN_STATIC_ASSERT_VECTOR_ONLY(Derived) - return IndexedView::type> - (derived(), indices, internal::make_indexing(0,derived().rows())); + return IndexedView + (derived(), indices, IvcIndex(0)); } #undef EIGEN_INDEXED_VIEW_METHOD_CONST diff --git a/test/indexed_view.cpp b/test/indexed_view.cpp index c15a8306a..e2c0e886d 100644 --- a/test/indexed_view.cpp +++ b/test/indexed_view.cpp @@ -51,6 +51,7 @@ is_same_type(const T1& a, const T2& b) void check_indexed_view() { + using Eigen::placeholders::all; using Eigen::placeholders::last; using Eigen::placeholders::end; -- cgit v1.2.3 From 1b19b80c06c06f9e1de72caf53107115d3ed5176 Mon Sep 17 00:00:00 2001 From: LaFeuille Date: Fri, 13 Jan 2017 07:24:55 +0000 Subject: Fix a typo --- CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index aab9c0e2c..b4555647c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -28,7 +28,7 @@ endif() ############################################################################# -# retrieve version infomation # +# retrieve version information # ############################################################################# # automatically parse the version number -- cgit v1.2.3 From 6e97698161275db750868afb99f405cdb849f412 Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Mon, 16 Jan 2017 16:13:37 +0100 Subject: Introduce a EIGEN_HAS_CXX14 macro --- Eigen/src/Core/util/Macros.h | 5 +++++ Eigen/src/Core/util/SymbolicIndex.h | 2 +- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/Eigen/src/Core/util/Macros.h b/Eigen/src/Core/util/Macros.h index 14addd8fb..7462dc5cf 100644 --- a/Eigen/src/Core/util/Macros.h +++ b/Eigen/src/Core/util/Macros.h @@ -362,6 +362,11 @@ #define EIGEN_HAS_CXX11 0 #endif +#if EIGEN_MAX_CPP_VER>=14 && (defined(__cplusplus) && (__cplusplus > 201103L) || EIGEN_COMP_MSVC >= 1900) +#define EIGEN_HAS_CXX14 1 +#else +#define EIGEN_HAS_CXX14 0 +#endif // Do we support r-value references? #ifndef EIGEN_HAS_RVALUE_REFERENCES diff --git a/Eigen/src/Core/util/SymbolicIndex.h b/Eigen/src/Core/util/SymbolicIndex.h index 03086d6fa..6f603f301 100644 --- a/Eigen/src/Core/util/SymbolicIndex.h +++ b/Eigen/src/Core/util/SymbolicIndex.h @@ -76,7 +76,7 @@ public: template Index eval(const T& values) const { return derived().eval_impl(values); } -#if __cplusplus > 201103L +#if EIGEN_HAS_CXX14 template Index eval(Types&&... values) const { return derived().eval_impl(std::make_tuple(values...)); } #endif -- cgit v1.2.3 From a9232af845702d62d81c49b4d92b39f29410cea0 Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Mon, 16 Jan 2017 16:17:01 +0100 Subject: Introduce a variable_or_fixed proxy returned by fix(val) to pass both a compile-time and runtime fallback value in case N means "runtime". This mechanism is used by the seq/seqN functions. The proxy object is immediately converted to pure compile-time (as fix) or pure runtime (i.e., an Index) to avoid redundant template instantiations. --- Eigen/src/Core/ArithmeticSequence.h | 56 +++++++++++++++++---------- Eigen/src/Core/util/IntegralConstant.h | 69 +++++++++++++++++++++++++++++++++- test/indexed_view.cpp | 31 ++++++++++++++- 3 files changed, 133 insertions(+), 23 deletions(-) diff --git a/Eigen/src/Core/ArithmeticSequence.h b/Eigen/src/Core/ArithmeticSequence.h index afb014ac5..bafc00f14 100644 --- a/Eigen/src/Core/ArithmeticSequence.h +++ b/Eigen/src/Core/ArithmeticSequence.h @@ -119,10 +119,26 @@ protected: namespace internal { -template struct cleanup_seq_type { typedef T type; }; -template struct cleanup_seq_type::value>::type> { typedef Index type; }; -template struct cleanup_seq_type > { typedef fix_t type; }; -template struct cleanup_seq_type (*)() > { typedef fix_t type; }; +// Cleanup return types: + +// By default, no change: +template struct cleanup_seq_type { typedef T type; }; + +// Convert short, int, unsigned int, etc. to Eigen::Index +template struct cleanup_seq_type::value>::type> { typedef Index type; }; + +// In c++98/c++11, fix is a pointer to function that we better cleanup to a true fix_t: +template struct cleanup_seq_type (*)(), DynamicKey> { typedef fix_t type; }; + +// If variable_or_fixed does not match DynamicKey, then we turn it to a pure compile-time value: +template struct cleanup_seq_type, DynamicKey> { typedef fix_t type; }; +// If variable_or_fixed matches DynamicKey, then we turn it to a pure runtime-value (aka Index): +template struct cleanup_seq_type, DynamicKey> { typedef Index type; }; + +// Helper to cleanup the type of the increment: +template struct cleanup_seq_incr { + typedef typename cleanup_seq_type::type type; +}; } @@ -130,9 +146,9 @@ template struct cleanup_seq_type (*)() > { typedef fix_t type * * \sa seqN(FirstType,SizeType), seq(FirstType,LastType,IncrType) */ template -ArithemeticSequence::type,typename internal::cleanup_seq_type::type,typename internal::cleanup_seq_type::type > +ArithemeticSequence::type,typename internal::cleanup_seq_type::type,typename internal::cleanup_seq_incr::type > seqN(FirstType first, SizeType size, IncrType incr) { - return ArithemeticSequence::type,typename internal::cleanup_seq_type::type,typename internal::cleanup_seq_type::type>(first,size,incr); + return ArithemeticSequence::type,typename internal::cleanup_seq_type::type,typename internal::cleanup_seq_incr::type>(first,size,incr); } /** \returns an ArithemeticSequence starting at \a first, of length \a size, and unit increment @@ -181,10 +197,10 @@ auto seq(FirstType f, LastType l) -> decltype(seqN(f,(l-f+fix<1>()))) template auto seq(FirstType f, LastType l, IncrType incr) - -> decltype(seqN(f, (l-f+typename internal::cleanup_seq_type::type(incr)) - / typename internal::cleanup_seq_type::type(incr),typename internal::cleanup_seq_type::type(incr))) + -> decltype(seqN(f, (l-f+typename internal::cleanup_seq_incr::type(incr)) + / typename internal::cleanup_seq_incr::type(incr),typename internal::cleanup_seq_incr::type(incr))) { - typedef typename internal::cleanup_seq_type::type CleanedIncrType; + typedef typename internal::cleanup_seq_incr::type CleanedIncrType; return seqN(f,(l-f+CleanedIncrType(incr))/CleanedIncrType(incr),CleanedIncrType(incr)); } #else @@ -225,10 +241,10 @@ seq(const Symbolic::BaseExpr &f, const Symbolic::BaseExpr typename internal::enable_if::value || Symbolic::is_symbolic::value), - ArithemeticSequence::type,Index,typename internal::cleanup_seq_type::type> >::type + ArithemeticSequence::type,Index,typename internal::cleanup_seq_incr::type> >::type seq(FirstType f, LastType l, IncrType incr) { - typedef typename internal::cleanup_seq_type::type CleanedIncrType; + typedef typename internal::cleanup_seq_incr::type CleanedIncrType; return seqN(f,(l-f+CleanedIncrType(incr))/CleanedIncrType(incr), incr); } @@ -239,10 +255,10 @@ typename internal::enable_if::value, Symbolic::ValueExpr>, Symbolic::ValueExpr>, Symbolic::ValueExpr>, - typename internal::cleanup_seq_type::type> >::type + typename internal::cleanup_seq_incr::type> >::type seq(const Symbolic::BaseExpr &f, LastType l, IncrType incr) { - typedef typename internal::cleanup_seq_type::type CleanedIncrType; + typedef typename internal::cleanup_seq_incr::type CleanedIncrType; return seqN(f.derived(),(l-f.derived()+CleanedIncrType(incr))/CleanedIncrType(incr), incr); } @@ -252,10 +268,10 @@ typename internal::enable_if::value, Symbolic::QuotientExpr, Symbolic::ValueExpr>, Symbolic::ValueExpr>, - typename internal::cleanup_seq_type::type> >::type + typename internal::cleanup_seq_incr::type> >::type seq(FirstType f, const Symbolic::BaseExpr &l, IncrType incr) { - typedef typename internal::cleanup_seq_type::type CleanedIncrType; + typedef typename internal::cleanup_seq_incr::type CleanedIncrType; return seqN(f,(l.derived()-f+CleanedIncrType(incr))/CleanedIncrType(incr), incr); } @@ -265,10 +281,10 @@ ArithemeticSequence >, Symbolic::ValueExpr>, Symbolic::ValueExpr>, - typename internal::cleanup_seq_type::type> + typename internal::cleanup_seq_incr::type> seq(const Symbolic::BaseExpr &f, const Symbolic::BaseExpr &l, IncrType incr) { - typedef typename internal::cleanup_seq_type::type CleanedIncrType; + typedef typename internal::cleanup_seq_incr::type CleanedIncrType; return seqN(f.derived(),(l.derived()-f.derived()+CleanedIncrType(incr))/CleanedIncrType(incr), incr); } #endif @@ -394,13 +410,13 @@ seq(FirstType f, LastType l) { template ArithemeticSequenceProxyWithBounds< typename internal::cleanup_seq_type::type, typename internal::cleanup_seq_type::type, - typename internal::cleanup_seq_type::type > + typename internal::cleanup_seq_incr::type > seq(FirstType f, LastType l, IncrType s) { return ArithemeticSequenceProxyWithBounds::type, typename internal::cleanup_seq_type::type, - typename internal::cleanup_seq_type::type> - (f,l,typename internal::cleanup_seq_type::type(s)); + typename internal::cleanup_seq_incr::type> + (f,l,typename internal::cleanup_seq_incr::type(s)); } } diff --git a/Eigen/src/Core/util/IntegralConstant.h b/Eigen/src/Core/util/IntegralConstant.h index a4394c464..dc8c8413d 100644 --- a/Eigen/src/Core/util/IntegralConstant.h +++ b/Eigen/src/Core/util/IntegralConstant.h @@ -15,13 +15,35 @@ namespace Eigen { namespace internal { +template struct fix_t; +template class variable_or_fixed; + template struct fix_t { static const int value = N; operator int() const { return value; } - fix_t (fix_t (*)() ) {} fix_t() {} + fix_t(variable_or_fixed other) { + EIGEN_ONLY_USED_FOR_DEBUG(other); + eigen_internal_assert(int(other)==N); + } + +#if EIGEN_HAS_CXX14 // Needed in C++14 to allow fix(): fix_t operator() () const { return *this; } + + variable_or_fixed operator() (int val) const { return variable_or_fixed(val); } +#else + fix_t (fix_t (*)() ) {} +#endif +}; + +template class variable_or_fixed { +public: + static const int value = N; + operator int() const { return m_value; } + variable_or_fixed(int val) { m_value = val; } +protected: + int m_value; }; template struct get_compile_time { @@ -32,6 +54,10 @@ template struct get_compile_time,Default> { enum { value = N }; }; +template struct get_compile_time,Default> { + enum { value = N }; +}; + template struct get_compile_time,Default> { enum { value = N }; @@ -45,12 +71,17 @@ template struct is_compile_time > { enum { value = true }; }; #ifndef EIGEN_PARSED_BY_DOXYGEN -#if __cplusplus > 201103L +#if EIGEN_HAS_CXX14 template static const internal::fix_t fix{}; #else template inline internal::fix_t fix() { return internal::fix_t(); } + +// The generic typename T is mandatory. Otherwise, a code like fix could refer to either the function above or this next overload. +// This way a code like fix can only refer to the previous function. +template +inline internal::variable_or_fixed fix(T val) { return internal::variable_or_fixed(val); } #endif #else // EIGEN_PARSED_BY_DOXYGEN @@ -67,6 +98,8 @@ inline internal::fix_t fix() { return internal::fix_t(); } * 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 static const internal::fix_t fix{}; @@ -82,10 +115,42 @@ inline internal::fix_t fix() { return internal::fix_t(); } * Here internal::fix_t is thus a pointer to function. * * If for some reason you want a true object in c++98 then you can write: \code fix() \endcode which is also valid in c++14. + * + * \sa fix(int), seq, seqN */ template static const auto fix; +/** \fn fix(int) + * \ingroup Core_Module + * + * This function returns an object embedding both a compile-time integer \c N, and a runtime value \a val. + * + * \tparam N the compile-time integer value + * \param val the 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 coudl turned out to actually mean "undefined at compile-time". For positive integers + * such as a size of a dimension, this case is identified by Eigen::Dynamic, whereas runtime signed integers (e.g., an increment/stride) are identified + * as Eigen::DynamicIndex. + * + * A typical use case would be: + * \code + * template void foo(const MatrixBase &mat) { + * const int N = Derived::RowsAtCompileTime==Dynamic ? Dynamic : Derived::RowsAtCompileTime/2; + * const int n = mat.rows()/2; + * ... mat( seqN(0,fix(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 seqN(0,fix) . + * + * \sa fix, seqN, class ArithmeticSequence + */ +template +static const auto fix(int val); + #endif // EIGEN_PARSED_BY_DOXYGEN } // end namespace Eigen diff --git a/test/indexed_view.cpp b/test/indexed_view.cpp index e2c0e886d..472268010 100644 --- a/test/indexed_view.cpp +++ b/test/indexed_view.cpp @@ -8,7 +8,12 @@ // 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++98 implementation +// 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 @@ -49,6 +54,13 @@ is_same_type(const T1& a, const T2& b) return (a == b).all(); } +template +typename internal::enable_if::value,bool>::type +is_same_seq_type(const T1& a, const T2& b) +{ + return a.size() == b.size() && a.first()==b.first() && Index(a.incrObject())==Index(b.incrObject()); +} + void check_indexed_view() { using Eigen::placeholders::all; @@ -157,6 +169,23 @@ void check_indexed_view() VERIFY_IS_EQUAL( (B(seqN(1,2,fix<2>), seq(1,3,fix<3>))).InnerStrideAtCompileTime , 2); VERIFY_IS_EQUAL( (B(seqN(1,2,fix<2>), seq(1,3,fix<3>))).OuterStrideAtCompileTime , 3*4); + VERIFY_IS_EQUAL( (A(seqN(2,fix<5>), seqN(1,fix<3>))).RowsAtCompileTime, 5); + VERIFY_IS_EQUAL( (A(seqN(2,fix<5>), seqN(1,fix<3>))).ColsAtCompileTime, 3); + VERIFY_IS_EQUAL( (A(seqN(2,fix<5>(5)), seqN(1,fix<3>(3)))).RowsAtCompileTime, 5); + VERIFY_IS_EQUAL( (A(seqN(2,fix<5>(5)), seqN(1,fix<3>(3)))).ColsAtCompileTime, 3); + VERIFY_IS_EQUAL( (A(seqN(2,fix(5)), seqN(1,fix(3)))).RowsAtCompileTime, Dynamic); + VERIFY_IS_EQUAL( (A(seqN(2,fix(5)), seqN(1,fix(3)))).ColsAtCompileTime, Dynamic); + VERIFY_IS_EQUAL( (A(seqN(2,fix(5)), seqN(1,fix(3)))).rows(), 5); + VERIFY_IS_EQUAL( (A(seqN(2,fix(5)), seqN(1,fix(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(3)) ) ); + VERIFY( is_same_seq_type( seq(2,7,fix<3>), seqN(2,2,fix<3>) ) ); + VERIFY( is_same_seq_type( seqN(2,fix(5),3), seqN(2,5,fix(3)) ) ); + VERIFY( is_same_seq_type( seqN(2,fix<5>(5),fix<-2>), seqN(2,fix<5>,fix<-2>()) ) ); + + VERIFY( (A(seqN(2,fix<5>), 5)).RowsAtCompileTime == 5); VERIFY( (A(4, all)).ColsAtCompileTime == Dynamic); VERIFY( (A(4, all)).RowsAtCompileTime == 1); -- cgit v1.2.3 From e70c4c97faf89b844dc9986e664257c9423c7ff6 Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Mon, 16 Jan 2017 16:20:16 +0100 Subject: Typo --- Eigen/src/Core/ArithmeticSequence.h | 78 +++++++++++++++++----------------- Eigen/src/plugins/IndexedViewMethods.h | 4 +- 2 files changed, 41 insertions(+), 41 deletions(-) diff --git a/Eigen/src/Core/ArithmeticSequence.h b/Eigen/src/Core/ArithmeticSequence.h index bafc00f14..79e6bb74e 100644 --- a/Eigen/src/Core/ArithmeticSequence.h +++ b/Eigen/src/Core/ArithmeticSequence.h @@ -66,7 +66,7 @@ static const Symbolic::AddExpr // seq(first,last,incr) and seqN(first,size,incr) //-------------------------------------------------------------------------------- -/** \class ArithemeticSequence +/** \class ArithmeticSequence * \ingroup Core_Module * * This class represents an arithmetic progression \f$ a_0, a_1, a_2, ..., a_{n-1}\f$ defined by @@ -86,12 +86,12 @@ static const Symbolic::AddExpr * \sa Eigen::seq, Eigen::seqN, DenseBase::operator()(const RowIndices&, const ColIndices&), class IndexedView */ template > -class ArithemeticSequence +class ArithmeticSequence { public: - ArithemeticSequence(FirstType first, SizeType size) : m_first(first), m_size(size) {} - ArithemeticSequence(FirstType first, SizeType size, IncrType incr) : m_first(first), m_size(size), m_incr(incr) {} + 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_compile_time::value, @@ -142,27 +142,27 @@ template struct cleanup_seq_incr { } -/** \returns an ArithemeticSequence starting at \a first, of length \a size, and increment \a incr +/** \returns an ArithmeticSequence starting at \a first, of length \a size, and increment \a incr * * \sa seqN(FirstType,SizeType), seq(FirstType,LastType,IncrType) */ template -ArithemeticSequence::type,typename internal::cleanup_seq_type::type,typename internal::cleanup_seq_incr::type > +ArithmeticSequence::type,typename internal::cleanup_seq_type::type,typename internal::cleanup_seq_incr::type > seqN(FirstType first, SizeType size, IncrType incr) { - return ArithemeticSequence::type,typename internal::cleanup_seq_type::type,typename internal::cleanup_seq_incr::type>(first,size,incr); + return ArithmeticSequence::type,typename internal::cleanup_seq_type::type,typename internal::cleanup_seq_incr::type>(first,size,incr); } -/** \returns an ArithemeticSequence starting at \a first, of length \a size, and unit increment +/** \returns an ArithmeticSequence starting at \a first, of length \a size, and unit increment * * \sa seqN(FirstType,SizeType,IncrType), seq(FirstType,LastType) */ template -ArithemeticSequence::type,typename internal::cleanup_seq_type::type > +ArithmeticSequence::type,typename internal::cleanup_seq_type::type > seqN(FirstType first, SizeType size) { - return ArithemeticSequence::type,typename internal::cleanup_seq_type::type>(first,size); + return ArithmeticSequence::type,typename internal::cleanup_seq_type::type>(first,size); } #ifdef EIGEN_PARSED_BY_DOXYGEN -/** \returns an ArithemeticSequence starting at \a f, up (or down) to \a l, and with positive (or negative) increment \a incr +/** \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 @@ -174,7 +174,7 @@ seqN(FirstType first, SizeType size) { template auto seq(FirstType f, LastType l, IncrType incr); -/** \returns an ArithemeticSequence starting at \a f, up (or down) to \a l, and unit increment +/** \returns an ArithmeticSequence starting at \a f, up (or down) to \a l, and unit increment * * It is essentially an alias to: * \code @@ -206,7 +206,7 @@ auto seq(FirstType f, LastType l, IncrType incr) #else template typename internal::enable_if::value || Symbolic::is_symbolic::value), - ArithemeticSequence::type,Index> >::type + ArithmeticSequence::type,Index> >::type seq(FirstType f, LastType l) { return seqN(f,(l-f+1)); @@ -214,7 +214,7 @@ seq(FirstType f, LastType l) template typename internal::enable_if::value, - ArithemeticSequence,Symbolic::ValueExpr>, + ArithmeticSequence,Symbolic::ValueExpr>, Symbolic::ValueExpr> > >::type seq(const Symbolic::BaseExpr &f, LastType l) { @@ -223,7 +223,7 @@ seq(const Symbolic::BaseExpr &f, LastType l) template typename internal::enable_if::value, - ArithemeticSequence::type, + ArithmeticSequence::type, Symbolic::AddExpr,Symbolic::ValueExpr> > >::type seq(FirstType f, const Symbolic::BaseExpr &l) { @@ -231,7 +231,7 @@ seq(FirstType f, const Symbolic::BaseExpr &l) } template -ArithemeticSequence >,Symbolic::ValueExpr> > seq(const Symbolic::BaseExpr &f, const Symbolic::BaseExpr &l) { @@ -241,7 +241,7 @@ seq(const Symbolic::BaseExpr &f, const Symbolic::BaseExpr typename internal::enable_if::value || Symbolic::is_symbolic::value), - ArithemeticSequence::type,Index,typename internal::cleanup_seq_incr::type> >::type + ArithmeticSequence::type,Index,typename internal::cleanup_seq_incr::type> >::type seq(FirstType f, LastType l, IncrType incr) { typedef typename internal::cleanup_seq_incr::type CleanedIncrType; @@ -250,7 +250,7 @@ seq(FirstType f, LastType l, IncrType incr) template typename internal::enable_if::value, - ArithemeticSequence, Symbolic::ValueExpr>, Symbolic::ValueExpr>, @@ -264,7 +264,7 @@ seq(const Symbolic::BaseExpr &f, LastType l, IncrType incr) template typename internal::enable_if::value, - ArithemeticSequence::type, + ArithmeticSequence::type, Symbolic::QuotientExpr, Symbolic::ValueExpr>, Symbolic::ValueExpr>, @@ -276,7 +276,7 @@ seq(FirstType f, const Symbolic::BaseExpr &l, IncrType incr) } template -ArithemeticSequence >, Symbolic::ValueExpr>, @@ -312,19 +312,19 @@ struct make_size_type { }; template -struct IndexedViewCompatibleType, XprSize> { - typedef ArithemeticSequence::type,IncrType> type; +struct IndexedViewCompatibleType, XprSize> { + typedef ArithmeticSequence::type,IncrType> type; }; template -ArithemeticSequence::type,IncrType> -makeIndexedViewCompatible(const ArithemeticSequence& ids, Index size) { - return ArithemeticSequence::type,IncrType>( +ArithmeticSequence::type,IncrType> +makeIndexedViewCompatible(const ArithmeticSequence& ids, Index size) { + return ArithmeticSequence::type,IncrType>( eval_expr_given_size(ids.firstObject(),size),eval_expr_given_size(ids.sizeObject(),size),ids.incrObject()); } template -struct get_compile_time_incr > { +struct get_compile_time_incr > { enum { value = get_compile_time::value }; }; @@ -377,11 +377,11 @@ inline Index eval_expr_given_size(end_t, Index size) { return size; } inline Index eval_expr_given_size(shifted_end x, Index size) { return size+x.offset; } template > -class ArithemeticSequenceProxyWithBounds +class ArithmeticSequenceProxyWithBounds { public: - ArithemeticSequenceProxyWithBounds(FirstType f, LastType l) : m_first(f), m_last(l) {} - ArithemeticSequenceProxyWithBounds(FirstType f, LastType l, IncrType s) : m_first(f), m_last(l), m_incr(s) {} + ArithmeticSequenceProxyWithBounds(FirstType f, LastType l) : m_first(f), m_last(l) {} + ArithmeticSequenceProxyWithBounds(FirstType f, LastType l, IncrType s) : m_first(f), m_last(l), m_incr(s) {} enum { SizeAtCompileTime = -1, @@ -402,18 +402,18 @@ protected: }; template -ArithemeticSequenceProxyWithBounds::type,typename internal::cleanup_seq_type::type > +ArithmeticSequenceProxyWithBounds::type,typename internal::cleanup_seq_type::type > seq(FirstType f, LastType l) { - return ArithemeticSequenceProxyWithBounds::type,typename internal::cleanup_seq_type::type>(f,l); + return ArithmeticSequenceProxyWithBounds::type,typename internal::cleanup_seq_type::type>(f,l); } template -ArithemeticSequenceProxyWithBounds< typename internal::cleanup_seq_type::type, +ArithmeticSequenceProxyWithBounds< typename internal::cleanup_seq_type::type, typename internal::cleanup_seq_type::type, typename internal::cleanup_seq_incr::type > seq(FirstType f, LastType l, IncrType s) { - return ArithemeticSequenceProxyWithBounds::type, + return ArithmeticSequenceProxyWithBounds::type, typename internal::cleanup_seq_type::type, typename internal::cleanup_seq_incr::type> (f,l,typename internal::cleanup_seq_incr::type(s)); @@ -424,20 +424,20 @@ seq(FirstType f, LastType l, IncrType s) namespace internal { template -struct get_compile_time_incr > { +struct get_compile_time_incr > { enum { value = get_compile_time::value }; }; // Convert a symbolic range into a usable one (i.e., remove last/end "keywords") template -struct IndexedViewCompatibleType,XprSize> { - typedef legacy::ArithemeticSequenceProxyWithBounds type; +struct IndexedViewCompatibleType,XprSize> { + typedef legacy::ArithmeticSequenceProxyWithBounds type; }; template -legacy::ArithemeticSequenceProxyWithBounds -makeIndexedViewCompatible(const legacy::ArithemeticSequenceProxyWithBounds& ids, Index size) { - return legacy::ArithemeticSequenceProxyWithBounds( +legacy::ArithmeticSequenceProxyWithBounds +makeIndexedViewCompatible(const legacy::ArithmeticSequenceProxyWithBounds& ids, Index size) { + return legacy::ArithmeticSequenceProxyWithBounds( eval_expr_given_size(ids.firstObject(),size),eval_expr_given_size(ids.lastObject(),size),ids.incrObject()); } diff --git a/Eigen/src/plugins/IndexedViewMethods.h b/Eigen/src/plugins/IndexedViewMethods.h index 774a5cbe5..0584a5926 100644 --- a/Eigen/src/plugins/IndexedViewMethods.h +++ b/Eigen/src/plugins/IndexedViewMethods.h @@ -195,7 +195,7 @@ operator()(const IndicesT (&indices)[IndicesN]) EIGEN_INDEXED_VIEW_METHOD_CONST * 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 ArithemeticSequence as returned by the Eigen::seq and Eigen::seqN functions + * - 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: @@ -212,7 +212,7 @@ operator()(const IndicesT (&indices)[IndicesN]) EIGEN_INDEXED_VIEW_METHOD_CONST * when all arguments are either: * - An integer * - Eigen::all - * - An ArithemeticSequence with compile-time increment strictly equal to 1, as returned by Eigen::seq(a,b), and Eigen::seqN(a,N). + * - 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 object will be returned, after conversion of the inputs * to more suitable types \c RowIndices' and \c ColIndices'. -- cgit v1.2.3 From 12e22a2844d060cfbeab7a48512046ee59709e53 Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Mon, 16 Jan 2017 16:31:19 +0100 Subject: typos in doc --- Eigen/src/Core/util/IntegralConstant.h | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/Eigen/src/Core/util/IntegralConstant.h b/Eigen/src/Core/util/IntegralConstant.h index dc8c8413d..57538060c 100644 --- a/Eigen/src/Core/util/IntegralConstant.h +++ b/Eigen/src/Core/util/IntegralConstant.h @@ -124,15 +124,16 @@ static const auto fix; /** \fn fix(int) * \ingroup Core_Module * - * This function returns an object embedding both a compile-time integer \c N, and a runtime value \a val. + * 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 runtime 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 coudl turned out to actually mean "undefined at compile-time". For positive integers - * such as a size of a dimension, this case is identified by Eigen::Dynamic, whereas runtime signed integers (e.g., an increment/stride) are identified - * as Eigen::DynamicIndex. + * 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 -- cgit v1.2.3 From 4989922be2708378b2438db5a843640ec468ce4c Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Mon, 16 Jan 2017 22:21:23 +0100 Subject: Add support for symbolic expressions as arguments of operator() --- Eigen/Core | 3 +- Eigen/src/Core/ArithmeticSequence.h | 66 +-------------------------- Eigen/src/Core/IndexedView.h | 8 +++- Eigen/src/Core/util/IndexedViewHelper.h | 80 +++++++++++++++++++++++++++++++-- Eigen/src/plugins/IndexedViewMethods.h | 41 ++++++++++++----- test/indexed_view.cpp | 8 ++++ 6 files changed, 126 insertions(+), 80 deletions(-) diff --git a/Eigen/Core b/Eigen/Core index 38306e11d..2ce2dd6b2 100644 --- a/Eigen/Core +++ b/Eigen/Core @@ -354,8 +354,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/util/IntegralConstant.h" + #include "src/Core/NumTraits.h" #include "src/Core/MathFunctions.h" diff --git a/Eigen/src/Core/ArithmeticSequence.h b/Eigen/src/Core/ArithmeticSequence.h index 79e6bb74e..056ace1f2 100644 --- a/Eigen/src/Core/ArithmeticSequence.h +++ b/Eigen/src/Core/ArithmeticSequence.h @@ -12,56 +12,6 @@ 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 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 -static const Symbolic::AddExpr,Symbolic::ValueExpr> end(last+1); -#endif - -} // end namespace placeholders - //-------------------------------------------------------------------------------- // seq(first,last,incr) and seqN(first,size,incr) //-------------------------------------------------------------------------------- @@ -293,18 +243,6 @@ seq(const Symbolic::BaseExpr &f, const Symbolic::BaseExpr -fix_t eval_expr_given_size(fix_t x, Index /*size*/) { return x; } - -template -Index eval_expr_given_size(const Symbolic::BaseExpr &x, Index size) -{ - return x.derived().eval(placeholders::last=size-1); -} - // Convert a symbolic span into a usable one (i.e., remove last/end "keywords") template struct make_size_type { @@ -318,7 +256,7 @@ struct IndexedViewCompatibleType template ArithmeticSequence::type,IncrType> -makeIndexedViewCompatible(const ArithmeticSequence& ids, Index size) { +makeIndexedViewCompatible(const ArithmeticSequence& ids, Index size,SpecializedType) { return ArithmeticSequence::type,IncrType>( eval_expr_given_size(ids.firstObject(),size),eval_expr_given_size(ids.sizeObject(),size),ids.incrObject()); } @@ -436,7 +374,7 @@ struct IndexedViewCompatibleType legacy::ArithmeticSequenceProxyWithBounds -makeIndexedViewCompatible(const legacy::ArithmeticSequenceProxyWithBounds& ids, Index size) { +makeIndexedViewCompatible(const legacy::ArithmeticSequenceProxyWithBounds& ids, Index size,SpecializedType) { return legacy::ArithmeticSequenceProxyWithBounds( eval_expr_given_size(ids.firstObject(),size),eval_expr_given_size(ids.lastObject(),size),ids.incrObject()); } diff --git a/Eigen/src/Core/IndexedView.h b/Eigen/src/Core/IndexedView.h index 38ee69638..63878428e 100644 --- a/Eigen/src/Core/IndexedView.h +++ b/Eigen/src/Core/IndexedView.h @@ -45,6 +45,10 @@ struct traits > InnerStrideAtCompileTime = InnerIncr<0 || InnerIncr==DynamicIndex || XprInnerStride==Dynamic ? Dynamic : XprInnerStride * InnerIncr, OuterStrideAtCompileTime = OuterIncr<0 || OuterIncr==DynamicIndex || XprOuterstride==Dynamic ? Dynamic : XprOuterstride * OuterIncr, + ReturnAsScalar = is_same::value && is_same::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, @@ -91,8 +95,8 @@ class IndexedViewImpl; * - decltype(ArrayXi::LinSpaced(...)) * - Any view/expressions of the previous types * - Eigen::ArithmeticSequence - * - Eigen::AllRange (helper for Eigen::all) - * - Eigen::IntAsArray (helper for single index) + * - 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 diff --git a/Eigen/src/Core/util/IndexedViewHelper.h b/Eigen/src/Core/util/IndexedViewHelper.h index 4f6dd065e..09637a157 100644 --- a/Eigen/src/Core/util/IndexedViewHelper.h +++ b/Eigen/src/Core/util/IndexedViewHelper.h @@ -13,8 +13,70 @@ 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 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 +static const Symbolic::AddExpr,Symbolic::ValueExpr> end(last+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 +fix_t eval_expr_given_size(fix_t x, Index /*size*/) { return x; } + +template +Index eval_expr_given_size(const Symbolic::BaseExpr &x, Index size) +{ + return x.derived().eval(placeholders::last=size-1); +} + // Extract increment/step at compile time template struct get_compile_time_incr { enum { value = UndefinedIncr }; @@ -31,8 +93,8 @@ struct IndexedViewCompatibleType { typedef T type; }; -template -const T& makeIndexedViewCompatible(const T& x, Index /*size*/) { return x; } +template +const T& makeIndexedViewCompatible(const T& x, Index /*size*/, Q) { return x; } //-------------------------------------------------------------------------------- // Handling of a single Index @@ -62,6 +124,18 @@ struct IndexedViewCompatibleType +struct IndexedViewCompatibleType::value>::type> { + typedef SingleRange type; +}; + + +template +typename enable_if::value,SingleRange>::type +makeIndexedViewCompatible(const T& id, Index size, SpecializedType) { + return eval_expr_given_size(id,size); +} + //-------------------------------------------------------------------------------- // Handling of all //-------------------------------------------------------------------------------- @@ -85,7 +159,7 @@ struct IndexedViewCompatibleType { }; template -inline AllRange::value> makeIndexedViewCompatible(all_t , XprSizeType size) { +inline AllRange::value> makeIndexedViewCompatible(all_t , XprSizeType size, SpecializedType) { return AllRange::value>(size); } diff --git a/Eigen/src/plugins/IndexedViewMethods.h b/Eigen/src/plugins/IndexedViewMethods.h index 0584a5926..90ade05ed 100644 --- a/Eigen/src/plugins/IndexedViewMethods.h +++ b/Eigen/src/plugins/IndexedViewMethods.h @@ -38,19 +38,24 @@ typedef typename internal::IndexedViewCompatibleType::type IvcIndex; template typename IvcRowType::type ivcRow(const Indices& indices) const { - return internal::makeIndexedViewCompatible(indices, internal::variable_if_dynamic(derived().rows())); + return internal::makeIndexedViewCompatible(indices, internal::variable_if_dynamic(derived().rows()),Specialized); }; template typename IvcColType::type ivcCol(const Indices& indices) const { - return internal::makeIndexedViewCompatible(indices, internal::variable_if_dynamic(derived().cols())); + return internal::makeIndexedViewCompatible(indices, internal::variable_if_dynamic(derived().cols()),Specialized); }; template typename IvcColType::type ivcSize(const Indices& indices) const { - return internal::makeIndexedViewCompatible(indices, internal::variable_if_dynamic(derived().size())); + return internal::makeIndexedViewCompatible(indices, internal::variable_if_dynamic(derived().size()),Specialized); +}; + +template +struct valid_indexed_view_overload { + enum { value = !(internal::is_integral::value && internal::is_integral::value) }; }; public: @@ -67,9 +72,8 @@ struct EIGEN_INDEXED_VIEW_METHOD_TYPE { // This is the generic version template -typename internal::enable_if< - ! (internal::traits::type>::IsBlockAlike - || (internal::is_integral::value && internal::is_integral::value)), +typename internal::enable_if::value + && internal::traits::type>::ReturnAsIndexedView, typename EIGEN_INDEXED_VIEW_METHOD_TYPE::type >::type operator()(const RowIndices& rowIndices, const ColIndices& colIndices) EIGEN_INDEXED_VIEW_METHOD_CONST { @@ -80,9 +84,8 @@ operator()(const RowIndices& rowIndices, const ColIndices& colIndices) EIGEN_IND // The folowing overload returns a Block<> object template -typename internal::enable_if< - internal::traits::type>::IsBlockAlike - && !(internal::is_integral::value && internal::is_integral::value), +typename internal::enable_if::value + && internal::traits::type>::ReturnAsBlock, typename internal::traits::type>::BlockType>::type operator()(const RowIndices& rowIndices, const ColIndices& colIndices) EIGEN_INDEXED_VIEW_METHOD_CONST { @@ -96,6 +99,17 @@ operator()(const RowIndices& rowIndices, const ColIndices& colIndices) EIGEN_IND internal::size(actualColIndices)); } +// The following overload returns a Scalar + +template +typename internal::enable_if::value + && internal::traits::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 @@ -148,7 +162,7 @@ operator()(const Indices& indices) EIGEN_INDEXED_VIEW_METHOD_CONST template typename internal::enable_if< - (internal::get_compile_time_incr::type>::value==1) && (!internal::is_integral::value), + (internal::get_compile_time_incr::type>::value==1) && (!internal::is_integral::value) && (!Symbolic::is_symbolic::value), VectorBlock::value> >::type operator()(const Indices& indices) EIGEN_INDEXED_VIEW_METHOD_CONST { @@ -158,6 +172,13 @@ operator()(const Indices& indices) EIGEN_INDEXED_VIEW_METHOD_CONST (derived(), internal::first(actualIndices), internal::size(actualIndices)); } +template +typename internal::enable_if::value, CoeffReturnType >::type +operator()(const IndexType& id) EIGEN_INDEXED_VIEW_METHOD_CONST +{ + return Base::operator()(internal::eval_expr_given_size(id,size())); +} + template typename internal::enable_if >::type diff --git a/test/indexed_view.cpp b/test/indexed_view.cpp index 472268010..88211f05e 100644 --- a/test/indexed_view.cpp +++ b/test/indexed_view.cpp @@ -211,6 +211,12 @@ void check_indexed_view() 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_type(A.col(0), A(all,0)) ); @@ -219,6 +225,8 @@ void check_indexed_view() VERIFY( is_same_type(A.middleRows(2,4), A(seqN(2,4),all)) ); VERIFY( is_same_type(A.middleCols(2,4), A(all,seqN(2,4))) ); + VERIFY( is_same_type(A.col(A.cols()-1), A(all,last)) ); + const ArrayXXi& cA(A); VERIFY( is_same_type(cA.col(0), cA(all,0)) ); VERIFY( is_same_type(cA.row(0), cA(0,all)) ); -- cgit v1.2.3 From edff32c2c2377ed02ec7af299fccc8ef09070d62 Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Tue, 17 Jan 2017 10:29:33 +0100 Subject: Disambiguate the two versions of fix for doxygen --- Eigen/src/Core/util/IntegralConstant.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Eigen/src/Core/util/IntegralConstant.h b/Eigen/src/Core/util/IntegralConstant.h index 57538060c..7f99863a1 100644 --- a/Eigen/src/Core/util/IntegralConstant.h +++ b/Eigen/src/Core/util/IntegralConstant.h @@ -86,7 +86,7 @@ inline internal::variable_or_fixed fix(T val) { return internal::variable_or_ #else // EIGEN_PARSED_BY_DOXYGEN -/** \var fix +/** \var fix() * \ingroup Core_Module * * This \em identifier permits to construct an object embedding a compile-time integer \c N. @@ -116,12 +116,12 @@ inline internal::variable_or_fixed fix(T val) { return internal::variable_or_ * * If for some reason you want a true object in c++98 then you can write: \code fix() \endcode which is also valid in c++14. * - * \sa fix(int), seq, seqN + * \sa fix(int), seq, seqN */ template -static const auto fix; +static const auto fix(); -/** \fn fix(int) +/** \fn fix(int) * \ingroup Core_Module * * This function returns an object embedding both a compile-time integer \c N, and a fallback runtime value \a val. -- cgit v1.2.3 From 23bfcfc15ffca75a0a90440c50781d384ce3fe0c Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Tue, 17 Jan 2017 10:30:21 +0100 Subject: Add missing overload of get_compile_time for c++98/11 --- Eigen/src/Core/util/IntegralConstant.h | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/Eigen/src/Core/util/IntegralConstant.h b/Eigen/src/Core/util/IntegralConstant.h index 7f99863a1..003856b20 100644 --- a/Eigen/src/Core/util/IntegralConstant.h +++ b/Eigen/src/Core/util/IntegralConstant.h @@ -47,20 +47,24 @@ protected: }; template struct get_compile_time { - enum { value = Default }; + static const int value = Default; }; template struct get_compile_time,Default> { - enum { value = N }; + static const int value = N; +}; + +template struct get_compile_time (*)(),Default> { + static const int value = N; }; template struct get_compile_time,Default> { - enum { value = N }; + static const int value = N ; }; template struct get_compile_time,Default> { - enum { value = N }; + static const int value = N; }; -- cgit v1.2.3 From 59801a32509635b753c9f025d95d2efb9a9fb1d4 Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Tue, 17 Jan 2017 10:31:28 +0100 Subject: Add \newin{3.x} doxygen command --- doc/Doxyfile.in | 3 ++- doc/eigendoxy.css | 5 +++++ 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/doc/Doxyfile.in b/doc/Doxyfile.in index b42de1bdb..2109978fe 100644 --- a/doc/Doxyfile.in +++ b/doc/Doxyfile.in @@ -229,7 +229,8 @@ ALIASES = "only_for_vectors=This is only for vectors (either row- "blank= " \ "cpp11=[c++11]" \ "cpp14=[c++14]" \ - "cpp17=[c++17]" + "cpp17=[c++17]" \ + "newin{1}=New in %Eigen \1." ALIASES += "eigenAutoToc= " diff --git a/doc/eigendoxy.css b/doc/eigendoxy.css index 6274e6c70..6ce2b839b 100644 --- a/doc/eigendoxy.css +++ b/doc/eigendoxy.css @@ -181,6 +181,11 @@ span.cpp11,span.cpp14,span.cpp17 { font-weight: bold; } +.newin3x { + color: #a37c1a; + font-weight: bold; +} + /**** old Eigen's styles ****/ -- cgit v1.2.3 From 71e5b713563ba9a61ab58901f3034d7248a879d7 Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Tue, 17 Jan 2017 11:33:57 +0100 Subject: Add a get_runtime_value helper to deal with pointer-to-function hack, plus some refactoring to make the internals more consistent. --- Eigen/src/Core/ArithmeticSequence.h | 56 ++++++++++++--------------------- Eigen/src/Core/util/IndexedViewHelper.h | 4 +-- Eigen/src/Core/util/IntegralConstant.h | 35 ++++++++++++++++----- 3 files changed, 50 insertions(+), 45 deletions(-) diff --git a/Eigen/src/Core/ArithmeticSequence.h b/Eigen/src/Core/ArithmeticSequence.h index 056ace1f2..2ad4c0906 100644 --- a/Eigen/src/Core/ArithmeticSequence.h +++ b/Eigen/src/Core/ArithmeticSequence.h @@ -44,8 +44,8 @@ public: ArithmeticSequence(FirstType first, SizeType size, IncrType incr) : m_first(first), m_size(size), m_incr(incr) {} enum { - SizeAtCompileTime = internal::get_compile_time::value, - IncrAtCompileTime = internal::get_compile_time::value + SizeAtCompileTime = internal::get_fixed_value::value, + IncrAtCompileTime = internal::get_fixed_value::value }; /** \returns the size, i.e., number of elements, of the sequence */ @@ -69,25 +69,9 @@ protected: namespace internal { -// Cleanup return types: - -// By default, no change: -template struct cleanup_seq_type { typedef T type; }; - -// Convert short, int, unsigned int, etc. to Eigen::Index -template struct cleanup_seq_type::value>::type> { typedef Index type; }; - -// In c++98/c++11, fix is a pointer to function that we better cleanup to a true fix_t: -template struct cleanup_seq_type (*)(), DynamicKey> { typedef fix_t type; }; - -// If variable_or_fixed does not match DynamicKey, then we turn it to a pure compile-time value: -template struct cleanup_seq_type, DynamicKey> { typedef fix_t type; }; -// If variable_or_fixed matches DynamicKey, then we turn it to a pure runtime-value (aka Index): -template struct cleanup_seq_type, DynamicKey> { typedef Index type; }; - // Helper to cleanup the type of the increment: template struct cleanup_seq_incr { - typedef typename cleanup_seq_type::type type; + typedef typename cleanup_index_type::type type; }; } @@ -96,18 +80,18 @@ template struct cleanup_seq_incr { * * \sa seqN(FirstType,SizeType), seq(FirstType,LastType,IncrType) */ template -ArithmeticSequence::type,typename internal::cleanup_seq_type::type,typename internal::cleanup_seq_incr::type > +ArithmeticSequence::type,typename internal::cleanup_index_type::type,typename internal::cleanup_seq_incr::type > seqN(FirstType first, SizeType size, IncrType incr) { - return ArithmeticSequence::type,typename internal::cleanup_seq_type::type,typename internal::cleanup_seq_incr::type>(first,size,incr); + return ArithmeticSequence::type,typename internal::cleanup_index_type::type,typename internal::cleanup_seq_incr::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 -ArithmeticSequence::type,typename internal::cleanup_seq_type::type > +ArithmeticSequence::type,typename internal::cleanup_index_type::type > seqN(FirstType first, SizeType size) { - return ArithmeticSequence::type,typename internal::cleanup_seq_type::type>(first,size); + return ArithmeticSequence::type,typename internal::cleanup_index_type::type>(first,size); } #ifdef EIGEN_PARSED_BY_DOXYGEN @@ -156,7 +140,7 @@ auto seq(FirstType f, LastType l, IncrType incr) #else template typename internal::enable_if::value || Symbolic::is_symbolic::value), - ArithmeticSequence::type,Index> >::type + ArithmeticSequence::type,Index> >::type seq(FirstType f, LastType l) { return seqN(f,(l-f+1)); @@ -173,7 +157,7 @@ seq(const Symbolic::BaseExpr &f, LastType l) template typename internal::enable_if::value, - ArithmeticSequence::type, + ArithmeticSequence::type, Symbolic::AddExpr,Symbolic::ValueExpr> > >::type seq(FirstType f, const Symbolic::BaseExpr &l) { @@ -191,7 +175,7 @@ seq(const Symbolic::BaseExpr &f, const Symbolic::BaseExpr typename internal::enable_if::value || Symbolic::is_symbolic::value), - ArithmeticSequence::type,Index,typename internal::cleanup_seq_incr::type> >::type + ArithmeticSequence::type,Index,typename internal::cleanup_seq_incr::type> >::type seq(FirstType f, LastType l, IncrType incr) { typedef typename internal::cleanup_seq_incr::type CleanedIncrType; @@ -214,7 +198,7 @@ seq(const Symbolic::BaseExpr &f, LastType l, IncrType incr) template typename internal::enable_if::value, - ArithmeticSequence::type, + ArithmeticSequence::type, Symbolic::QuotientExpr, Symbolic::ValueExpr>, Symbolic::ValueExpr>, @@ -263,7 +247,7 @@ makeIndexedViewCompatible(const ArithmeticSequence& template struct get_compile_time_incr > { - enum { value = get_compile_time::value }; + enum { value = get_fixed_value::value }; }; } // end namespace internal @@ -323,7 +307,7 @@ public: enum { SizeAtCompileTime = -1, - IncrAtCompileTime = internal::get_compile_time::value + IncrAtCompileTime = internal::get_fixed_value::value }; Index size() const { return (m_last-m_first+m_incr)/m_incr; } @@ -340,19 +324,19 @@ protected: }; template -ArithmeticSequenceProxyWithBounds::type,typename internal::cleanup_seq_type::type > +ArithmeticSequenceProxyWithBounds::type,typename internal::cleanup_index_type::type > seq(FirstType f, LastType l) { - return ArithmeticSequenceProxyWithBounds::type,typename internal::cleanup_seq_type::type>(f,l); + return ArithmeticSequenceProxyWithBounds::type,typename internal::cleanup_index_type::type>(f,l); } template -ArithmeticSequenceProxyWithBounds< typename internal::cleanup_seq_type::type, - typename internal::cleanup_seq_type::type, +ArithmeticSequenceProxyWithBounds< typename internal::cleanup_index_type::type, + typename internal::cleanup_index_type::type, typename internal::cleanup_seq_incr::type > seq(FirstType f, LastType l, IncrType s) { - return ArithmeticSequenceProxyWithBounds::type, - typename internal::cleanup_seq_type::type, + return ArithmeticSequenceProxyWithBounds::type, + typename internal::cleanup_index_type::type, typename internal::cleanup_seq_incr::type> (f,l,typename internal::cleanup_seq_incr::type(s)); } @@ -363,7 +347,7 @@ namespace internal { template struct get_compile_time_incr > { - enum { value = get_compile_time::value }; + enum { value = get_fixed_value::value }; }; // Convert a symbolic range into a usable one (i.e., remove last/end "keywords") diff --git a/Eigen/src/Core/util/IndexedViewHelper.h b/Eigen/src/Core/util/IndexedViewHelper.h index 09637a157..b4f7c0dd7 100644 --- a/Eigen/src/Core/util/IndexedViewHelper.h +++ b/Eigen/src/Core/util/IndexedViewHelper.h @@ -159,8 +159,8 @@ struct IndexedViewCompatibleType { }; template -inline AllRange::value> makeIndexedViewCompatible(all_t , XprSizeType size, SpecializedType) { - return AllRange::value>(size); +inline AllRange::value> makeIndexedViewCompatible(all_t , XprSizeType size, SpecializedType) { + return AllRange::value>(size); } template struct get_compile_time_incr > { diff --git a/Eigen/src/Core/util/IntegralConstant.h b/Eigen/src/Core/util/IntegralConstant.h index 003856b20..2402baeec 100644 --- a/Eigen/src/Core/util/IntegralConstant.h +++ b/Eigen/src/Core/util/IntegralConstant.h @@ -46,30 +46,51 @@ protected: int m_value; }; -template struct get_compile_time { +template struct get_fixed_value { static const int value = Default; }; -template struct get_compile_time,Default> { +template struct get_fixed_value,Default> { static const int value = N; }; -template struct get_compile_time (*)(),Default> { +#if !EIGEN_HAS_CXX14 +template struct get_fixed_value (*)(),Default> { static const int value = N; }; +#endif -template struct get_compile_time,Default> { +template struct get_fixed_value,Default> { static const int value = N ; }; template -struct get_compile_time,Default> { +struct get_fixed_value,Default> { static const int value = N; }; +template Index get_runtime_value(const T &x) { return x; } +#if !EIGEN_HAS_CXX14 +template Index get_runtime_value(fix_t (*)()) { return N; } +#endif + +// Cleanup integer/fix_t/variable_or_fixed/etc types: + +// By default, no cleanup: +template struct cleanup_index_type { typedef T type; }; + +// Convert any integral type (e.g., short, int, unsigned int, etc.) to Eigen::Index +template struct cleanup_index_type::value>::type> { typedef Index type; }; + +#if !EIGEN_HAS_CXX14 +// In c++98/c++11, fix is a pointer to function that we better cleanup to a true fix_t: +template struct cleanup_index_type (*)(), DynamicKey> { typedef fix_t type; }; +#endif -template struct is_compile_time { enum { value = false }; }; -template struct is_compile_time > { enum { value = true }; }; +// If variable_or_fixed does not match DynamicKey, then we turn it to a pure compile-time value: +template struct cleanup_index_type, DynamicKey> { typedef fix_t type; }; +// If variable_or_fixed matches DynamicKey, then we turn it to a pure runtime-value (aka Index): +template struct cleanup_index_type, DynamicKey> { typedef Index type; }; } // end namespace internal -- cgit v1.2.3 From 4f36dcfda88be7737fbbe5145c52fca6d164ca91 Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Tue, 17 Jan 2017 11:34:28 +0100 Subject: Add a generic block() method compatible with Eigen::fix --- Eigen/src/plugins/BlockMethods.h | 60 ++++++++++++++++++++++++++++++++++++++-- test/block.cpp | 12 ++++++++ test/indexed_view.cpp | 47 +++++++++++++++++++------------ 3 files changed, 100 insertions(+), 19 deletions(-) diff --git a/Eigen/src/plugins/BlockMethods.h b/Eigen/src/plugins/BlockMethods.h index ac35a0086..38020730c 100644 --- a/Eigen/src/plugins/BlockMethods.h +++ b/Eigen/src/plugins/BlockMethods.h @@ -773,7 +773,7 @@ inline typename ConstNColsBlockXpr::Type middleCols(Index startCol, Index n = /// EIGEN_DOC_BLOCK_ADDONS_NOT_INNER_PANEL /// -/// \sa class Block, block(Index,Index,Index,Index) +/// \sa block(Index,Index,NRowsType,NColsType), class Block, block(Index,Index,Index,Index) /// template EIGEN_DEVICE_FUNC @@ -809,7 +809,7 @@ inline const typename ConstFixedBlockXpr::Type block(Index startRow /// EIGEN_DOC_BLOCK_ADDONS_NOT_INNER_PANEL /// -/// \sa class Block, block(Index,Index,Index,Index) +/// \sa block(Index,Index,NRowsType,NColsType), block(Index,Index,Index,Index), class Block /// template inline typename FixedBlockXpr::Type block(Index startRow, Index startCol, @@ -826,6 +826,62 @@ inline const typename ConstFixedBlockXpr::Type block(Index startRow return typename ConstFixedBlockXpr::Type(derived(), startRow, startCol, blockRows, blockCols); } +/// \returns an expression of a block in \c *this. +/// +/// \tparam NRowsType the type of the object handling the number of rows in the block, can be any integral type (e.g., int, Index) or any returned by Eigen::fix or Eigen::fix(n). +/// \tparam NColsType analogue of NRowsType but for the number of columns. +/// \param startRow the first row in the block +/// \param startCol the first column in the block +/// \param blockRows number of rows in the block as specified at either run-time or compile-time +/// \param blockCols number of columns in the block as specified at either run-time or compile-time +/// +/// \newin{3.4} +/// +/// This function covers the same versatility as block(Index, Index), and block(Index, Index, Index, Index) +/// but with less redundancy and more consistency as it does not modify the argument order +/// and seamlessly enable hybrid fixed/dynamic sizes. +/// The one-to-one full equivalences are as follows: +/// +/// \code +/// mat.template block(i,j) <--> mat.block(i,j,fix,fix) +/// mat.template block(i,j,rows,cols) <--> mat.block(i,j,fix(rows),fix(cols)) +/// \endcode +/// +/// but of course, with this version one of the compile-time parameter can be completely +/// omitted if it turns out to be a pure runtime one: +/// \code +/// mat.template block(i,j,rows,cols) <--> mat.block(i,j,fix,cols) +/// \endcode +/// +EIGEN_DOC_BLOCK_ADDONS_NOT_INNER_PANEL +/// +/// \sa class Block, block(Index,Index,Index,Index), fix +/// +template +#ifndef EIGEN_PARSED_BY_DOXYGEN +inline typename FixedBlockXpr::value,internal::get_fixed_value::value>::Type +#else +inline typename FixedBlockXpr<...,...>::Type +#endif +block(Index startRow, Index startCol, NRowsType blockRows, NColsType blockCols) +{ + return typename FixedBlockXpr::value,internal::get_fixed_value::value>::Type( + derived(), startRow, startCol, internal::get_runtime_value(blockRows), internal::get_runtime_value(blockCols)); +} + +/// This is the const version of block(Index,Index,NRowsType,NColsType) +template +#ifndef EIGEN_PARSED_BY_DOXYGEN +inline typename ConstFixedBlockXpr::value,internal::get_fixed_value::value>::Type +#else +inline typename ConstFixedBlockXpr<...,...>::Type +#endif +block(Index startRow, Index startCol, NRowsType blockRows, NColsType blockCols) const +{ + return typename ConstFixedBlockXpr::value,internal::get_fixed_value::value>::Type( + derived(), startRow, startCol, internal::get_runtime_value(blockRows), internal::get_runtime_value(blockCols)); +} + /// \returns an expression of the \a i-th column of *this. Note that the numbering starts at 0. /// /// Example: \include MatrixBase_col.cpp diff --git a/test/block.cpp b/test/block.cpp index 1eeb2da27..80e24fd5b 100644 --- a/test/block.cpp +++ b/test/block.cpp @@ -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 internal::enable_if::value,bool>::type +is_same_block(const T1& a, const T2& b) +{ + return a.isApprox(b); +} template void block(const MatrixType& m) { @@ -106,6 +113,11 @@ template void block(const MatrixType& m) m1.template block(1,1,BlockRows,BlockCols)(0,3) = m1.template block<2,5>(1,1)(1,2); Matrix b2 = m1.template block(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(BlockRows),fix(BlockCols)))); + VERIFY(is_same_block(m1.template block(1,1,BlockRows,BlockCols), m1.block(1,1,fix,BlockCols))); + VERIFY(is_same_block(m1.template block(1,1,BlockRows,BlockCols), m1.block(1,1,fix(),fix))); + VERIFY(is_same_block(m1.template block(1,1,BlockRows,BlockCols), m1.block(1,1,fix,fix(BlockCols)))); } if (rows>2) diff --git a/test/indexed_view.cpp b/test/indexed_view.cpp index 88211f05e..5a055376d 100644 --- a/test/indexed_view.cpp +++ b/test/indexed_view.cpp @@ -49,7 +49,7 @@ bool match(const T& xpr, std::string ref, std::string str_xpr = "") { template typename internal::enable_if::value,bool>::type -is_same_type(const T1& a, const T2& b) +is_same_eq(const T1& a, const T2& b) { return (a == b).all(); } @@ -219,25 +219,25 @@ void check_indexed_view() // Check fall-back to Block { - VERIFY( is_same_type(A.col(0), A(all,0)) ); - VERIFY( is_same_type(A.row(0), A(0,all)) ); - VERIFY( is_same_type(A.block(0,0,2,2), A(seqN(0,2),seq(0,1))) ); - VERIFY( is_same_type(A.middleRows(2,4), A(seqN(2,4),all)) ); - VERIFY( is_same_type(A.middleCols(2,4), A(all,seqN(2,4))) ); + 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_type(A.col(A.cols()-1), A(all,last)) ); + VERIFY( is_same_eq(A.col(A.cols()-1), A(all,last)) ); const ArrayXXi& cA(A); - VERIFY( is_same_type(cA.col(0), cA(all,0)) ); - VERIFY( is_same_type(cA.row(0), cA(0,all)) ); - VERIFY( is_same_type(cA.block(0,0,2,2), cA(seqN(0,2),seq(0,1))) ); - VERIFY( is_same_type(cA.middleRows(2,4), cA(seqN(2,4),all)) ); - VERIFY( is_same_type(cA.middleCols(2,4), cA(all,seqN(2,4))) ); - - VERIFY( is_same_type(a.head(4), a(seq(0,3))) ); - VERIFY( is_same_type(a.tail(4), a(seqN(last-3,4))) ); - VERIFY( is_same_type(a.tail(4), a(seq(end-4,last))) ); - VERIFY( is_same_type(a.segment<4>(3), a(seqN(3,fix<4>))) ); + 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); @@ -275,6 +275,18 @@ void check_indexed_view() VERIFY_IS_APPROX( A(legacy::seq(legacy::last,2,-2), legacy::seq(legacy::last-6,7)), A(seq(last,2,-2), seq(last-6,7)) ); VERIFY_IS_APPROX( A(seqN(legacy::last,2,-2), seqN(legacy::last-6,3)), A(seqN(last,2,-2), seqN(last-6,3)) ); + // 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(1,1,3,4), A.block(1,1,fix(3),fix<4>)) ); + VERIFY( is_same_eq( A.block(1,1,3,4), A.block(1,1,fix(3),fix(4))) ); + + const ArrayXXi& cA(A); + VERIFY( is_same_eq( cA.block(1,1,3,4), cA.block(1,1,fix(3),fix<4>)) ); + } + } void test_indexed_view() @@ -282,5 +294,6 @@ 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() ); // } } -- cgit v1.2.3 From f7852c3d16b7a5636dd8e0603b30034a06c80ac8 Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Tue, 17 Jan 2017 16:05:58 +0100 Subject: Fix -Wunnamed-type-template-args --- test/indexed_view.cpp | 62 ++++++++++++++++++++++++++------------------------- 1 file changed, 32 insertions(+), 30 deletions(-) diff --git a/test/indexed_view.cpp b/test/indexed_view.cpp index 5a055376d..d4d82c54d 100644 --- a/test/indexed_view.cpp +++ b/test/indexed_view.cpp @@ -61,6 +61,8 @@ is_same_seq_type(const T1& a, const T2& b) return a.size() == b.size() && a.first()==b.first() && Index(a.incrObject())==Index(b.incrObject()); } +#define VERIFY_EQ_INT(A,B) VERIFY_IS_APPROX(int(A),int(B)) + void check_indexed_view() { using Eigen::placeholders::all; @@ -150,33 +152,33 @@ void check_indexed_view() B.setRandom(); VERIFY( (A(seqN(2,5), 5)).ColsAtCompileTime == 1); VERIFY( (A(seqN(2,5), 5)).RowsAtCompileTime == Dynamic); - VERIFY_IS_EQUAL( (A(seqN(2,5), 5)).InnerStrideAtCompileTime , A.InnerStrideAtCompileTime); - VERIFY_IS_EQUAL( (A(seqN(2,5), 5)).OuterStrideAtCompileTime , A.col(5).OuterStrideAtCompileTime); - - VERIFY_IS_EQUAL( (A(5,seqN(2,5))).InnerStrideAtCompileTime , A.row(5).InnerStrideAtCompileTime); - VERIFY_IS_EQUAL( (A(5,seqN(2,5))).OuterStrideAtCompileTime , A.row(5).OuterStrideAtCompileTime); - VERIFY_IS_EQUAL( (B(1,seqN(1,2))).InnerStrideAtCompileTime , B.row(1).InnerStrideAtCompileTime); - VERIFY_IS_EQUAL( (B(1,seqN(1,2))).OuterStrideAtCompileTime , B.row(1).OuterStrideAtCompileTime); - - VERIFY_IS_EQUAL( (A(seqN(2,5), seq(1,3))).InnerStrideAtCompileTime , A.InnerStrideAtCompileTime); - VERIFY_IS_EQUAL( (A(seqN(2,5), seq(1,3))).OuterStrideAtCompileTime , A.OuterStrideAtCompileTime); - VERIFY_IS_EQUAL( (B(seqN(1,2), seq(1,3))).InnerStrideAtCompileTime , B.InnerStrideAtCompileTime); - VERIFY_IS_EQUAL( (B(seqN(1,2), seq(1,3))).OuterStrideAtCompileTime , B.OuterStrideAtCompileTime); - VERIFY_IS_EQUAL( (A(seqN(2,5,2), seq(1,3,2))).InnerStrideAtCompileTime , Dynamic); - VERIFY_IS_EQUAL( (A(seqN(2,5,2), seq(1,3,2))).OuterStrideAtCompileTime , Dynamic); - VERIFY_IS_EQUAL( (A(seqN(2,5,fix<2>), seq(1,3,fix<3>))).InnerStrideAtCompileTime , 2); - VERIFY_IS_EQUAL( (A(seqN(2,5,fix<2>), seq(1,3,fix<3>))).OuterStrideAtCompileTime , Dynamic); - VERIFY_IS_EQUAL( (B(seqN(1,2,fix<2>), seq(1,3,fix<3>))).InnerStrideAtCompileTime , 2); - VERIFY_IS_EQUAL( (B(seqN(1,2,fix<2>), seq(1,3,fix<3>))).OuterStrideAtCompileTime , 3*4); - - VERIFY_IS_EQUAL( (A(seqN(2,fix<5>), seqN(1,fix<3>))).RowsAtCompileTime, 5); - VERIFY_IS_EQUAL( (A(seqN(2,fix<5>), seqN(1,fix<3>))).ColsAtCompileTime, 3); - VERIFY_IS_EQUAL( (A(seqN(2,fix<5>(5)), seqN(1,fix<3>(3)))).RowsAtCompileTime, 5); - VERIFY_IS_EQUAL( (A(seqN(2,fix<5>(5)), seqN(1,fix<3>(3)))).ColsAtCompileTime, 3); - VERIFY_IS_EQUAL( (A(seqN(2,fix(5)), seqN(1,fix(3)))).RowsAtCompileTime, Dynamic); - VERIFY_IS_EQUAL( (A(seqN(2,fix(5)), seqN(1,fix(3)))).ColsAtCompileTime, Dynamic); - VERIFY_IS_EQUAL( (A(seqN(2,fix(5)), seqN(1,fix(3)))).rows(), 5); - VERIFY_IS_EQUAL( (A(seqN(2,fix(5)), seqN(1,fix(3)))).cols(), 3); + 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(5)), seqN(1,fix(3)))).RowsAtCompileTime, Dynamic); + VERIFY_EQ_INT( (A(seqN(2,fix(5)), seqN(1,fix(3)))).ColsAtCompileTime, Dynamic); + VERIFY_EQ_INT( (A(seqN(2,fix(5)), seqN(1,fix(3)))).rows(), 5); + VERIFY_EQ_INT( (A(seqN(2,fix(5)), seqN(1,fix(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)) ) ); @@ -195,9 +197,9 @@ void check_indexed_view() VERIFY( (B(all,1)).RowsAtCompileTime == 4); VERIFY( (A(all, eii)).ColsAtCompileTime == eii.SizeAtCompileTime); - VERIFY_IS_EQUAL( (A(eii, eii)).Flags&DirectAccessBit, (unsigned int)(0)); - VERIFY_IS_EQUAL( (A(eii, eii)).InnerStrideAtCompileTime, 0); - VERIFY_IS_EQUAL( (A(eii, eii)).OuterStrideAtCompileTime, 0); + 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,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)) ); -- cgit v1.2.3 From 5e36ec3b6f3cf5513357e8520230083ff9ecb938 Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Tue, 17 Jan 2017 17:10:16 +0100 Subject: Fix regression when passing enums to operator() --- Eigen/src/plugins/IndexedViewMethods.h | 6 ++++-- test/indexed_view.cpp | 10 ++++++++++ 2 files changed, 14 insertions(+), 2 deletions(-) diff --git a/Eigen/src/plugins/IndexedViewMethods.h b/Eigen/src/plugins/IndexedViewMethods.h index 90ade05ed..e6098bfc7 100644 --- a/Eigen/src/plugins/IndexedViewMethods.h +++ b/Eigen/src/plugins/IndexedViewMethods.h @@ -55,7 +55,9 @@ ivcSize(const Indices& indices) const { template struct valid_indexed_view_overload { - enum { value = !(internal::is_integral::value && internal::is_integral::value) }; + // 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 && is_enum if is_convertible appears to be too permissive. + enum { value = !(internal::is_convertible::value && internal::is_convertible::value) }; }; public: @@ -81,7 +83,7 @@ operator()(const RowIndices& rowIndices, const ColIndices& colIndices) EIGEN_IND (derived(), ivcRow(rowIndices), ivcCol(colIndices)); } -// The folowing overload returns a Block<> object +// The following overload returns a Block<> object template typename internal::enable_if::value diff --git a/test/indexed_view.cpp b/test/indexed_view.cpp index d4d82c54d..3ea8e7c00 100644 --- a/test/indexed_view.cpp +++ b/test/indexed_view.cpp @@ -277,6 +277,16 @@ void check_indexed_view() VERIFY_IS_APPROX( A(legacy::seq(legacy::last,2,-2), legacy::seq(legacy::last-6,7)), A(seq(last,2,-2), seq(last-6,7)) ); VERIFY_IS_APPROX( A(seqN(legacy::last,2,-2), seqN(legacy::last-6,3)), A(seqN(last,2,-2), seqN(last-6,3)) ); + // 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(3,1) ); + VERIFY_IS_APPROX( A(B.RowsAtCompileTime-1, B.ColsAtCompileTime-1), A(3,3) ); + VERIFY_IS_APPROX( A(B.RowsAtCompileTime, B.ColsAtCompileTime), A(3,3) ); + enum { 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>)) ); -- cgit v1.2.3 From 655ba783f8b2c9a8c3f4edb45e6db468aca22188 Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Tue, 17 Jan 2017 18:03:35 +0100 Subject: Defer set-to-zero in triangular = product so that no aliasing issue occur in the common: A.triangularView() = B*A.sefladjointView()*B.adjoint() case that used to work in 3.2. --- Eigen/src/Core/TriangularMatrix.h | 9 ++++----- Eigen/src/Core/products/GeneralMatrixMatrixTriangular.h | 14 ++++++++++---- test/product_mmtr.cpp | 13 +++++++++++++ 3 files changed, 27 insertions(+), 9 deletions(-) diff --git a/Eigen/src/Core/TriangularMatrix.h b/Eigen/src/Core/TriangularMatrix.h index c35fb8083..667ef09dc 100644 --- a/Eigen/src/Core/TriangularMatrix.h +++ b/Eigen/src/Core/TriangularMatrix.h @@ -543,7 +543,7 @@ template class TriangularViewImpl<_Mat template 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); }; /*************************************************************************** @@ -950,8 +950,7 @@ struct Assignment, internal::assign_ if((dst.rows()!=dstRows) || (dst.cols()!=dstCols)) dst.resize(dstRows, dstCols); - dst.setZero(); - dst._assignProduct(src, 1); + dst._assignProduct(src, 1, 0); } }; @@ -962,7 +961,7 @@ struct Assignment, internal::add_ass typedef Product SrcXprType; static void run(DstXprType &dst, const SrcXprType &src, const internal::add_assign_op &) { - dst._assignProduct(src, 1); + dst._assignProduct(src, 1, 1); } }; @@ -973,7 +972,7 @@ struct Assignment, internal::sub_ass typedef Product SrcXprType; static void run(DstXprType &dst, const SrcXprType &src, const internal::sub_assign_op &) { - dst._assignProduct(src, -1); + dst._assignProduct(src, -1, 1); } }; diff --git a/Eigen/src/Core/products/GeneralMatrixMatrixTriangular.h b/Eigen/src/Core/products/GeneralMatrixMatrixTriangular.h index 29d6dc721..5cd2794a4 100644 --- a/Eigen/src/Core/products/GeneralMatrixMatrixTriangular.h +++ b/Eigen/src/Core/products/GeneralMatrixMatrixTriangular.h @@ -199,7 +199,7 @@ struct general_product_to_triangular_selector; template struct general_product_to_triangular_selector { - 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 Scalar actualAlpha = alpha * LhsBlasTraits::extractScalarFactor(prod.lhs().derived()) * RhsBlasTraits::extractScalarFactor(prod.rhs().derived()); + if(!beta) + mat.template triangularView().setZero(); + enum { StorageOrder = (internal::traits::Flags&RowMajorBit) ? RowMajor : ColMajor, UseLhsDirectly = _ActualLhs::InnerStrideAtCompileTime==1, @@ -244,7 +247,7 @@ struct general_product_to_triangular_selector template struct general_product_to_triangular_selector { - 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::type Lhs; typedef internal::blas_traits LhsBlasTraits; @@ -260,6 +263,9 @@ struct general_product_to_triangular_selector typename ProductType::Scalar actualAlpha = alpha * LhsBlasTraits::extractScalarFactor(prod.lhs().derived()) * RhsBlasTraits::extractScalarFactor(prod.rhs().derived()); + if(!beta) + mat.template triangularView().setZero(); + enum { IsRowMajor = (internal::traits::Flags&RowMajorBit) ? 1 : 0, LhsIsRowMajor = _ActualLhs::Flags&RowMajorBit ? 1 : 0, @@ -286,11 +292,11 @@ struct general_product_to_triangular_selector template template -TriangularView& TriangularViewImpl::_assignProduct(const ProductType& prod, const Scalar& alpha) +TriangularView& TriangularViewImpl::_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::InnerSize==1>::run(derived().nestedExpression().const_cast_derived(), prod, alpha); + general_product_to_triangular_selector::InnerSize==1>::run(derived().nestedExpression().const_cast_derived(), prod, alpha, beta); return derived(); } diff --git a/test/product_mmtr.cpp b/test/product_mmtr.cpp index b66529acd..f6e4bb1ae 100644 --- a/test/product_mmtr.cpp +++ b/test/product_mmtr.cpp @@ -62,6 +62,19 @@ template void mmtr(int size) CHECK_MMTR(matc, Upper, -= (s*sqc).template triangularView()*sqc); CHECK_MMTR(matc, Lower, = (s*sqr).template triangularView()*sqc); CHECK_MMTR(matc, Upper, += (s*sqc).template triangularView()*sqc); + + // check aliasing + ref2 = ref1 = matc; + ref1 = sqc.adjoint() * matc * sqc; + ref2.template triangularView() = ref1.template triangularView(); + matc.template triangularView() = sqc.adjoint() * matc * sqc; + VERIFY_IS_APPROX(matc, ref2); + + ref2 = ref1 = matc; + ref1 = sqc * matc * sqc.adjoint(); + ref2.template triangularView() = ref1.template triangularView(); + matc.template triangularView() = sqc * matc * sqc.adjoint(); + VERIFY_IS_APPROX(matc, ref2); } void test_product_mmtr() -- cgit v1.2.3 From 5484ddd353168c5b989be0e3ce6568b93b94093c Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Tue, 17 Jan 2017 22:11:46 +0100 Subject: Merge the generic and dynamic overloads of block() --- Eigen/src/plugins/BlockMethods.h | 175 ++++++++++++++++++--------------------- 1 file changed, 82 insertions(+), 93 deletions(-) diff --git a/Eigen/src/plugins/BlockMethods.h b/Eigen/src/plugins/BlockMethods.h index 38020730c..060d79db4 100644 --- a/Eigen/src/plugins/BlockMethods.h +++ b/Eigen/src/plugins/BlockMethods.h @@ -42,40 +42,69 @@ template struct ConstFixedSegmentReturnType { typedef const VectorBloc #endif // not EIGEN_PARSED_BY_DOXYGEN -/// \returns a dynamic-size expression of a block in *this. +/// \returns an expression of a block in \c *this with either dynamic or fixed sizes. /// -/// \param startRow the first row in the block -/// \param startCol the first column in the block -/// \param blockRows the number of rows in the block -/// \param blockCols the number of columns in the block +/// \param startRow the first row in the block +/// \param startCol the first column in the block +/// \param blockRows number of rows in the block, specified at either run-time or compile-time +/// \param blockCols number of columns in the block, specified at either run-time or compile-time +/// \tparam NRowsType the type of the value handling the number of rows in the block, typically Index. +/// \tparam NColsType the type of the value handling the number of columns in the block, typically Index. /// -/// Example: \include MatrixBase_block_int_int_int_int.cpp +/// Example using runtime (aka dynamic) sizes: \include MatrixBase_block_int_int_int_int.cpp /// Output: \verbinclude MatrixBase_block_int_int_int_int.out /// -/// \note Even though the returned expression has dynamic size, in the case +/// \newin{3.4}: +/// +/// The number of rows \a blockRows and columns \a blockCols can also be specified at compile-time by passing Eigen::fix, +/// or Eigen::fix(n) as arguments. In the later case, \c n plays the role of a runtime fallback value in case \c N equals Eigen::Dynamic. +/// Here is an example with a fixed number of rows \c NRows and dynamic number of columns \c cols: +/// \code +/// mat.block(i,j,fix,cols) +/// \endcode +/// +/// This function thus fully covers the features offered by the following overloads block(Index, Index), +/// and block(Index, Index, Index, Index) that are thus obsolete. Indeed, this generic version avoids +/// redundancy, it preserves the argument order, and prevents the need to rely on the template keyword in templated code. +/// +/// but with less redundancy and more consistency as it does not modify the argument order +/// and seamlessly enable hybrid fixed/dynamic sizes. +/// +/// \note Even in the case that the returned expression has dynamic size, in the case /// when it is applied to a fixed-size matrix, it inherits a fixed maximal size, /// which means that evaluating it does not cause a dynamic memory allocation. /// EIGEN_DOC_BLOCK_ADDONS_NOT_INNER_PANEL /// -/// \sa class Block, block(Index,Index) +/// \sa class Block, fix, fix(int) /// -EIGEN_DEVICE_FUNC -inline BlockXpr block(Index startRow, Index startCol, Index blockRows, Index blockCols) +template +#ifndef EIGEN_PARSED_BY_DOXYGEN +inline typename FixedBlockXpr::value,internal::get_fixed_value::value>::Type +#else +inline typename FixedBlockXpr<...,...>::Type +#endif +block(Index startRow, Index startCol, NRowsType blockRows, NColsType blockCols) { - return BlockXpr(derived(), startRow, startCol, blockRows, blockCols); + return typename FixedBlockXpr::value,internal::get_fixed_value::value>::Type( + derived(), startRow, startCol, internal::get_runtime_value(blockRows), internal::get_runtime_value(blockCols)); } -/// This is the const version of block(Index,Index,Index,Index). */ -EIGEN_DEVICE_FUNC -inline const ConstBlockXpr block(Index startRow, Index startCol, Index blockRows, Index blockCols) const +/// This is the const version of block(Index,Index,NRowsType,NColsType) +template +#ifndef EIGEN_PARSED_BY_DOXYGEN +inline typename ConstFixedBlockXpr::value,internal::get_fixed_value::value>::Type +#else +inline typename ConstFixedBlockXpr<...,...>::Type +#endif +block(Index startRow, Index startCol, NRowsType blockRows, NColsType blockCols) const { - return ConstBlockXpr(derived(), startRow, startCol, blockRows, blockCols); + return typename ConstFixedBlockXpr::value,internal::get_fixed_value::value>::Type( + derived(), startRow, startCol, internal::get_runtime_value(blockRows), internal::get_runtime_value(blockCols)); } - /// \returns a dynamic-size expression of a top-right corner of *this. /// /// \param cRows the number of rows in the corner @@ -86,7 +115,7 @@ inline const ConstBlockXpr block(Index startRow, Index startCol, Index blockRows /// EIGEN_DOC_BLOCK_ADDONS_NOT_INNER_PANEL /// -/// \sa class Block, block(Index,Index,Index,Index) +/// \sa class Block, block(Index,Index,NRowsType,NColsType) /// EIGEN_DEVICE_FUNC inline BlockXpr topRightCorner(Index cRows, Index cCols) @@ -172,7 +201,7 @@ inline const typename ConstFixedBlockXpr::Type topRightCorner(Index /// EIGEN_DOC_BLOCK_ADDONS_NOT_INNER_PANEL /// -/// \sa class Block, block(Index,Index,Index,Index) +/// \sa class Block, block(Index,Index,NRowsType,NColsType) /// EIGEN_DEVICE_FUNC inline BlockXpr topLeftCorner(Index cRows, Index cCols) @@ -196,7 +225,7 @@ inline const ConstBlockXpr topLeftCorner(Index cRows, Index cCols) const /// EIGEN_DOC_BLOCK_ADDONS_NOT_INNER_PANEL /// -/// \sa class Block, block(Index,Index,Index,Index) +/// \sa class Block, block(Index,Index,NRowsType,NColsType) /// template EIGEN_DEVICE_FUNC @@ -257,7 +286,7 @@ inline const typename ConstFixedBlockXpr::Type topLeftCorner(Index /// EIGEN_DOC_BLOCK_ADDONS_NOT_INNER_PANEL /// -/// \sa class Block, block(Index,Index,Index,Index) +/// \sa class Block, block(Index,Index,NRowsType,NColsType) /// EIGEN_DEVICE_FUNC inline BlockXpr bottomRightCorner(Index cRows, Index cCols) @@ -281,7 +310,7 @@ inline const ConstBlockXpr bottomRightCorner(Index cRows, Index cCols) const /// EIGEN_DOC_BLOCK_ADDONS_NOT_INNER_PANEL /// -/// \sa class Block, block(Index,Index,Index,Index) +/// \sa class Block, block(Index,Index,NRowsType,NColsType) /// template EIGEN_DEVICE_FUNC @@ -342,7 +371,7 @@ inline const typename ConstFixedBlockXpr::Type bottomRightCorner(In /// EIGEN_DOC_BLOCK_ADDONS_NOT_INNER_PANEL /// -/// \sa class Block, block(Index,Index,Index,Index) +/// \sa class Block, block(Index,Index,NRowsType,NColsType) /// EIGEN_DEVICE_FUNC inline BlockXpr bottomLeftCorner(Index cRows, Index cCols) @@ -366,7 +395,7 @@ inline const ConstBlockXpr bottomLeftCorner(Index cRows, Index cCols) const /// EIGEN_DOC_BLOCK_ADDONS_NOT_INNER_PANEL /// -/// \sa class Block, block(Index,Index,Index,Index) +/// \sa class Block, block(Index,Index,NRowsType,NColsType) /// template EIGEN_DEVICE_FUNC @@ -426,7 +455,7 @@ inline const typename ConstFixedBlockXpr::Type bottomLeftCorner(Ind /// EIGEN_DOC_BLOCK_ADDONS_INNER_PANEL_IF(row-major) /// -/// \sa class Block, block(Index,Index,Index,Index) +/// \sa class Block, block(Index,Index,NRowsType,NColsType) /// EIGEN_DEVICE_FUNC inline RowsBlockXpr topRows(Index n) @@ -454,7 +483,7 @@ inline ConstRowsBlockXpr topRows(Index n) const /// EIGEN_DOC_BLOCK_ADDONS_INNER_PANEL_IF(row-major) /// -/// \sa class Block, block(Index,Index,Index,Index) +/// \sa class Block, block(Index,Index,NRowsType,NColsType) /// template EIGEN_DEVICE_FUNC @@ -482,7 +511,7 @@ inline typename ConstNRowsBlockXpr::Type topRows(Index n = N) const /// EIGEN_DOC_BLOCK_ADDONS_INNER_PANEL_IF(row-major) /// -/// \sa class Block, block(Index,Index,Index,Index) +/// \sa class Block, block(Index,Index,NRowsType,NColsType) /// EIGEN_DEVICE_FUNC inline RowsBlockXpr bottomRows(Index n) @@ -510,7 +539,7 @@ inline ConstRowsBlockXpr bottomRows(Index n) const /// EIGEN_DOC_BLOCK_ADDONS_INNER_PANEL_IF(row-major) /// -/// \sa class Block, block(Index,Index,Index,Index) +/// \sa class Block, block(Index,Index,NRowsType,NColsType) /// template EIGEN_DEVICE_FUNC @@ -539,7 +568,7 @@ inline typename ConstNRowsBlockXpr::Type bottomRows(Index n = N) const /// EIGEN_DOC_BLOCK_ADDONS_INNER_PANEL_IF(row-major) /// -/// \sa class Block, block(Index,Index,Index,Index) +/// \sa class Block, block(Index,Index,NRowsType,NColsType) /// EIGEN_DEVICE_FUNC inline RowsBlockXpr middleRows(Index startRow, Index n) @@ -568,7 +597,7 @@ inline ConstRowsBlockXpr middleRows(Index startRow, Index n) const /// EIGEN_DOC_BLOCK_ADDONS_INNER_PANEL_IF(row-major) /// -/// \sa class Block, block(Index,Index,Index,Index) +/// \sa class Block, block(Index,Index,NRowsType,NColsType) /// template EIGEN_DEVICE_FUNC @@ -596,7 +625,7 @@ inline typename ConstNRowsBlockXpr::Type middleRows(Index startRow, Index n = /// EIGEN_DOC_BLOCK_ADDONS_INNER_PANEL_IF(column-major) /// -/// \sa class Block, block(Index,Index,Index,Index) +/// \sa class Block, block(Index,Index,NRowsType,NColsType) /// EIGEN_DEVICE_FUNC inline ColsBlockXpr leftCols(Index n) @@ -624,7 +653,7 @@ inline ConstColsBlockXpr leftCols(Index n) const /// EIGEN_DOC_BLOCK_ADDONS_INNER_PANEL_IF(column-major) /// -/// \sa class Block, block(Index,Index,Index,Index) +/// \sa class Block, block(Index,Index,NRowsType,NColsType) /// template EIGEN_DEVICE_FUNC @@ -652,7 +681,7 @@ inline typename ConstNColsBlockXpr::Type leftCols(Index n = N) const /// EIGEN_DOC_BLOCK_ADDONS_INNER_PANEL_IF(column-major) /// -/// \sa class Block, block(Index,Index,Index,Index) +/// \sa class Block, block(Index,Index,NRowsType,NColsType) /// EIGEN_DEVICE_FUNC inline ColsBlockXpr rightCols(Index n) @@ -680,7 +709,7 @@ inline ConstColsBlockXpr rightCols(Index n) const /// EIGEN_DOC_BLOCK_ADDONS_INNER_PANEL_IF(column-major) /// -/// \sa class Block, block(Index,Index,Index,Index) +/// \sa class Block, block(Index,Index,NRowsType,NColsType) /// template EIGEN_DEVICE_FUNC @@ -709,7 +738,7 @@ inline typename ConstNColsBlockXpr::Type rightCols(Index n = N) const /// EIGEN_DOC_BLOCK_ADDONS_INNER_PANEL_IF(column-major) /// -/// \sa class Block, block(Index,Index,Index,Index) +/// \sa class Block, block(Index,Index,NRowsType,NColsType) /// EIGEN_DEVICE_FUNC inline ColsBlockXpr middleCols(Index startCol, Index numCols) @@ -738,7 +767,7 @@ inline ConstColsBlockXpr middleCols(Index startCol, Index numCols) const /// EIGEN_DOC_BLOCK_ADDONS_INNER_PANEL_IF(column-major) /// -/// \sa class Block, block(Index,Index,Index,Index) +/// \sa class Block, block(Index,Index,NRowsType,NColsType) /// template EIGEN_DEVICE_FUNC @@ -768,12 +797,18 @@ inline typename ConstNColsBlockXpr::Type middleCols(Index startCol, Index n = /// Example: \include MatrixBase_block_int_int.cpp /// Output: \verbinclude MatrixBase_block_int_int.out /// +/// \note The usage of of this overload is discouraged from %Eigen 3.4, better used the generic +/// block(Index,Index,NRowsType,NColsType), here is the one-to-one equivalence: +/// \code +/// mat.template block(i,j) <--> mat.block(i,j,fix,fix) +/// \endcode +/// /// \note since block is a templated member, the keyword template has to be used /// if the matrix type is also a template parameter: \code m.template block<3,3>(1,1); \endcode /// EIGEN_DOC_BLOCK_ADDONS_NOT_INNER_PANEL /// -/// \sa block(Index,Index,NRowsType,NColsType), class Block, block(Index,Index,Index,Index) +/// \sa block(Index,Index,NRowsType,NColsType), class Block /// template EIGEN_DEVICE_FUNC @@ -807,9 +842,19 @@ inline const typename ConstFixedBlockXpr::Type block(Index startRow /// Example: \include MatrixBase_template_int_int_block_int_int_int_int.cpp /// Output: \verbinclude MatrixBase_template_int_int_block_int_int_int_int.cpp /// +/// \note The usage of of this overload is discouraged from %Eigen 3.4, better used the generic +/// block(Index,Index,NRowsType,NColsType), here is the one-to-one complete equivalence: +/// \code +/// mat.template block(i,j,rows,cols) <--> mat.block(i,j,fix(rows),fix(cols)) +/// \endcode +/// If we known that, e.g., NRows==Dynamic and NCols!=Dynamic, then the equivalence becomes: +/// \code +/// mat.template block(i,j,rows,NCols) <--> mat.block(i,j,rows,fix) +/// \endcode +/// EIGEN_DOC_BLOCK_ADDONS_NOT_INNER_PANEL /// -/// \sa block(Index,Index,NRowsType,NColsType), block(Index,Index,Index,Index), class Block +/// \sa block(Index,Index,NRowsType,NColsType), block(Index,Index,NRowsType,NColsType), class Block /// template inline typename FixedBlockXpr::Type block(Index startRow, Index startCol, @@ -826,62 +871,6 @@ inline const typename ConstFixedBlockXpr::Type block(Index startRow return typename ConstFixedBlockXpr::Type(derived(), startRow, startCol, blockRows, blockCols); } -/// \returns an expression of a block in \c *this. -/// -/// \tparam NRowsType the type of the object handling the number of rows in the block, can be any integral type (e.g., int, Index) or any returned by Eigen::fix or Eigen::fix(n). -/// \tparam NColsType analogue of NRowsType but for the number of columns. -/// \param startRow the first row in the block -/// \param startCol the first column in the block -/// \param blockRows number of rows in the block as specified at either run-time or compile-time -/// \param blockCols number of columns in the block as specified at either run-time or compile-time -/// -/// \newin{3.4} -/// -/// This function covers the same versatility as block(Index, Index), and block(Index, Index, Index, Index) -/// but with less redundancy and more consistency as it does not modify the argument order -/// and seamlessly enable hybrid fixed/dynamic sizes. -/// The one-to-one full equivalences are as follows: -/// -/// \code -/// mat.template block(i,j) <--> mat.block(i,j,fix,fix) -/// mat.template block(i,j,rows,cols) <--> mat.block(i,j,fix(rows),fix(cols)) -/// \endcode -/// -/// but of course, with this version one of the compile-time parameter can be completely -/// omitted if it turns out to be a pure runtime one: -/// \code -/// mat.template block(i,j,rows,cols) <--> mat.block(i,j,fix,cols) -/// \endcode -/// -EIGEN_DOC_BLOCK_ADDONS_NOT_INNER_PANEL -/// -/// \sa class Block, block(Index,Index,Index,Index), fix -/// -template -#ifndef EIGEN_PARSED_BY_DOXYGEN -inline typename FixedBlockXpr::value,internal::get_fixed_value::value>::Type -#else -inline typename FixedBlockXpr<...,...>::Type -#endif -block(Index startRow, Index startCol, NRowsType blockRows, NColsType blockCols) -{ - return typename FixedBlockXpr::value,internal::get_fixed_value::value>::Type( - derived(), startRow, startCol, internal::get_runtime_value(blockRows), internal::get_runtime_value(blockCols)); -} - -/// This is the const version of block(Index,Index,NRowsType,NColsType) -template -#ifndef EIGEN_PARSED_BY_DOXYGEN -inline typename ConstFixedBlockXpr::value,internal::get_fixed_value::value>::Type -#else -inline typename ConstFixedBlockXpr<...,...>::Type -#endif -block(Index startRow, Index startCol, NRowsType blockRows, NColsType blockCols) const -{ - return typename ConstFixedBlockXpr::value,internal::get_fixed_value::value>::Type( - derived(), startRow, startCol, internal::get_runtime_value(blockRows), internal::get_runtime_value(blockCols)); -} - /// \returns an expression of the \a i-th column of *this. Note that the numbering starts at 0. /// /// Example: \include MatrixBase_col.cpp -- cgit v1.2.3 From 198507141b35aee322a95110dd9aab182db58f29 Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Wed, 18 Jan 2017 09:43:58 +0100 Subject: Update all block expressions to accept compile-time sizes passed by fix or fix(n) --- Eigen/src/plugins/BlockMethods.h | 505 +++++++++++++++++++++++++++++---------- test/indexed_view.cpp | 34 ++- 2 files changed, 411 insertions(+), 128 deletions(-) diff --git a/Eigen/src/plugins/BlockMethods.h b/Eigen/src/plugins/BlockMethods.h index 060d79db4..2d5a4e507 100644 --- a/Eigen/src/plugins/BlockMethods.h +++ b/Eigen/src/plugins/BlockMethods.h @@ -78,6 +78,7 @@ EIGEN_DOC_BLOCK_ADDONS_NOT_INNER_PANEL /// /// \sa class Block, fix, fix(int) /// +EIGEN_DEVICE_FUNC template #ifndef EIGEN_PARSED_BY_DOXYGEN inline typename FixedBlockXpr::value,internal::get_fixed_value::value>::Type @@ -91,11 +92,12 @@ block(Index startRow, Index startCol, NRowsType blockRows, NColsType blockCols) } /// This is the const version of block(Index,Index,NRowsType,NColsType) +EIGEN_DEVICE_FUNC template #ifndef EIGEN_PARSED_BY_DOXYGEN -inline typename ConstFixedBlockXpr::value,internal::get_fixed_value::value>::Type +inline const typename ConstFixedBlockXpr::value,internal::get_fixed_value::value>::Type #else -inline typename ConstFixedBlockXpr<...,...>::Type +inline const typename ConstFixedBlockXpr<...,...>::Type #endif block(Index startRow, Index startCol, NRowsType blockRows, NColsType blockCols) const { @@ -105,32 +107,51 @@ block(Index startRow, Index startCol, NRowsType blockRows, NColsType blockCols) -/// \returns a dynamic-size expression of a top-right corner of *this. +/// \returns a expression of a top-right corner of \c *this with either dynamic or fixed sizes. /// /// \param cRows the number of rows in the corner /// \param cCols the number of columns in the corner +/// \tparam NRowsType the type of the value handling the number of rows in the block, typically Index. +/// \tparam NColsType the type of the value handling the number of columns in the block, typically Index. /// -/// Example: \include MatrixBase_topRightCorner_int_int.cpp +/// Example with dynamic sizes: \include MatrixBase_topRightCorner_int_int.cpp /// Output: \verbinclude MatrixBase_topRightCorner_int_int.out /// +/// The number of rows \a blockRows and columns \a blockCols can also be specified at compile-time by passing Eigen::fix, +/// or Eigen::fix(n) as arguments. See \link block(Index,Index,NRowsType,NColsType) block() \endlink for the details. +/// EIGEN_DOC_BLOCK_ADDONS_NOT_INNER_PANEL /// -/// \sa class Block, block(Index,Index,NRowsType,NColsType) +/// \sa block(Index,Index,NRowsType,NColsType), class Block /// EIGEN_DEVICE_FUNC -inline BlockXpr topRightCorner(Index cRows, Index cCols) +template +#ifndef EIGEN_PARSED_BY_DOXYGEN +inline typename FixedBlockXpr::value,internal::get_fixed_value::value>::Type +#else +inline typename FixedBlockXpr<...,...>::Type +#endif +topRightCorner(NRowsType cRows, NColsType cCols) { - return BlockXpr(derived(), 0, cols() - cCols, cRows, cCols); + return typename FixedBlockXpr::value,internal::get_fixed_value::value>::Type + (derived(), 0, cols() - internal::get_runtime_value(cCols), internal::get_runtime_value(cRows), internal::get_runtime_value(cCols)); } -/// This is the const version of topRightCorner(Index, Index). +/// This is the const version of topRightCorner(NRowsType, NColsType). EIGEN_DEVICE_FUNC -inline const ConstBlockXpr topRightCorner(Index cRows, Index cCols) const +template +#ifndef EIGEN_PARSED_BY_DOXYGEN +inline const typename ConstFixedBlockXpr::value,internal::get_fixed_value::value>::Type +#else +inline const typename ConstFixedBlockXpr<...,...>::Type +#endif +topRightCorner(NRowsType cRows, NColsType cCols) const { - return ConstBlockXpr(derived(), 0, cols() - cCols, cRows, cCols); + return typename ConstFixedBlockXpr::value,internal::get_fixed_value::value>::Type + (derived(), 0, cols() - internal::get_runtime_value(cCols), internal::get_runtime_value(cRows), internal::get_runtime_value(cCols)); } -/// \returns an expression of a fixed-size top-right corner of *this. +/// \returns an expression of a fixed-size top-right corner of \c *this. /// /// \tparam CRows the number of rows in the corner /// \tparam CCols the number of columns in the corner @@ -157,7 +178,7 @@ inline const typename ConstFixedBlockXpr::Type topRightCorner() con return typename ConstFixedBlockXpr::Type(derived(), 0, cols() - CCols); } -/// \returns an expression of a top-right corner of *this. +/// \returns an expression of a top-right corner of \c *this. /// /// \tparam CRows number of rows in corner as specified at compile-time /// \tparam CCols number of columns in corner as specified at compile-time @@ -191,32 +212,51 @@ inline const typename ConstFixedBlockXpr::Type topRightCorner(Index -/// \returns a dynamic-size expression of a top-left corner of *this. +/// \returns an expression of a top-left corner of \c *this with either dynamic or fixed sizes. /// /// \param cRows the number of rows in the corner /// \param cCols the number of columns in the corner +/// \tparam NRowsType the type of the value handling the number of rows in the block, typically Index. +/// \tparam NColsType the type of the value handling the number of columns in the block, typically Index. /// /// Example: \include MatrixBase_topLeftCorner_int_int.cpp /// Output: \verbinclude MatrixBase_topLeftCorner_int_int.out /// +/// The number of rows \a blockRows and columns \a blockCols can also be specified at compile-time by passing Eigen::fix, +/// or Eigen::fix(n) as arguments. See \link block(Index,Index,NRowsType,NColsType) block() \endlink for the details. +/// EIGEN_DOC_BLOCK_ADDONS_NOT_INNER_PANEL /// -/// \sa class Block, block(Index,Index,NRowsType,NColsType) +/// \sa block(Index,Index,NRowsType,NColsType), class Block /// EIGEN_DEVICE_FUNC -inline BlockXpr topLeftCorner(Index cRows, Index cCols) +template +#ifndef EIGEN_PARSED_BY_DOXYGEN +inline typename FixedBlockXpr::value,internal::get_fixed_value::value>::Type +#else +inline typename FixedBlockXpr<...,...>::Type +#endif +topLeftCorner(NRowsType cRows, NColsType cCols) { - return BlockXpr(derived(), 0, 0, cRows, cCols); + return typename FixedBlockXpr::value,internal::get_fixed_value::value>::Type + (derived(), 0, 0, internal::get_runtime_value(cRows), internal::get_runtime_value(cCols)); } /// This is the const version of topLeftCorner(Index, Index). EIGEN_DEVICE_FUNC -inline const ConstBlockXpr topLeftCorner(Index cRows, Index cCols) const +template +#ifndef EIGEN_PARSED_BY_DOXYGEN +inline const typename ConstFixedBlockXpr::value,internal::get_fixed_value::value>::Type +#else +inline const typename ConstFixedBlockXpr<...,...>::Type +#endif +topLeftCorner(NRowsType cRows, NColsType cCols) const { - return ConstBlockXpr(derived(), 0, 0, cRows, cCols); + return typename ConstFixedBlockXpr::value,internal::get_fixed_value::value>::Type + (derived(), 0, 0, internal::get_runtime_value(cRows), internal::get_runtime_value(cCols)); } -/// \returns an expression of a fixed-size top-left corner of *this. +/// \returns an expression of a fixed-size top-left corner of \c *this. /// /// The template parameters CRows and CCols are the number of rows and columns in the corner. /// @@ -225,7 +265,7 @@ inline const ConstBlockXpr topLeftCorner(Index cRows, Index cCols) const /// EIGEN_DOC_BLOCK_ADDONS_NOT_INNER_PANEL /// -/// \sa class Block, block(Index,Index,NRowsType,NColsType) +/// \sa block(Index,Index,NRowsType,NColsType), class Block /// template EIGEN_DEVICE_FUNC @@ -242,7 +282,7 @@ inline const typename ConstFixedBlockXpr::Type topLeftCorner() cons return typename ConstFixedBlockXpr::Type(derived(), 0, 0); } -/// \returns an expression of a top-left corner of *this. +/// \returns an expression of a top-left corner of \c *this. /// /// \tparam CRows number of rows in corner as specified at compile-time /// \tparam CCols number of columns in corner as specified at compile-time @@ -276,32 +316,53 @@ inline const typename ConstFixedBlockXpr::Type topLeftCorner(Index -/// \returns a dynamic-size expression of a bottom-right corner of *this. +/// \returns an expression of a bottom-right corner of \c *this with either dynamic or fixed sizes. /// /// \param cRows the number of rows in the corner /// \param cCols the number of columns in the corner +/// \tparam NRowsType the type of the value handling the number of rows in the block, typically Index. +/// \tparam NColsType the type of the value handling the number of columns in the block, typically Index. /// /// Example: \include MatrixBase_bottomRightCorner_int_int.cpp /// Output: \verbinclude MatrixBase_bottomRightCorner_int_int.out /// +/// The number of rows \a blockRows and columns \a blockCols can also be specified at compile-time by passing Eigen::fix, +/// or Eigen::fix(n) as arguments. See \link block(Index,Index,NRowsType,NColsType) block() \endlink for the details. +/// EIGEN_DOC_BLOCK_ADDONS_NOT_INNER_PANEL /// -/// \sa class Block, block(Index,Index,NRowsType,NColsType) +/// \sa block(Index,Index,NRowsType,NColsType), class Block /// EIGEN_DEVICE_FUNC -inline BlockXpr bottomRightCorner(Index cRows, Index cCols) +template +#ifndef EIGEN_PARSED_BY_DOXYGEN +inline typename FixedBlockXpr::value,internal::get_fixed_value::value>::Type +#else +inline typename FixedBlockXpr<...,...>::Type +#endif +bottomRightCorner(NRowsType cRows, NColsType cCols) { - return BlockXpr(derived(), rows() - cRows, cols() - cCols, cRows, cCols); + return typename FixedBlockXpr::value,internal::get_fixed_value::value>::Type + (derived(), rows() - internal::get_runtime_value(cRows), cols() - internal::get_runtime_value(cCols), + internal::get_runtime_value(cRows), internal::get_runtime_value(cCols)); } -/// This is the const version of bottomRightCorner(Index, Index). +/// This is the const version of bottomRightCorner(NRowsType, NColsType). EIGEN_DEVICE_FUNC -inline const ConstBlockXpr bottomRightCorner(Index cRows, Index cCols) const +template +#ifndef EIGEN_PARSED_BY_DOXYGEN +inline const typename ConstFixedBlockXpr::value,internal::get_fixed_value::value>::Type +#else +inline const typename ConstFixedBlockXpr<...,...>::Type +#endif +bottomRightCorner(NRowsType cRows, NColsType cCols) const { - return ConstBlockXpr(derived(), rows() - cRows, cols() - cCols, cRows, cCols); + return typename ConstFixedBlockXpr::value,internal::get_fixed_value::value>::Type + (derived(), rows() - internal::get_runtime_value(cRows), cols() - internal::get_runtime_value(cCols), + internal::get_runtime_value(cRows), internal::get_runtime_value(cCols)); } -/// \returns an expression of a fixed-size bottom-right corner of *this. +/// \returns an expression of a fixed-size bottom-right corner of \c *this. /// /// The template parameters CRows and CCols are the number of rows and columns in the corner. /// @@ -310,7 +371,7 @@ inline const ConstBlockXpr bottomRightCorner(Index cRows, Index cCols) const /// EIGEN_DOC_BLOCK_ADDONS_NOT_INNER_PANEL /// -/// \sa class Block, block(Index,Index,NRowsType,NColsType) +/// \sa block(Index,Index,NRowsType,NColsType), class Block /// template EIGEN_DEVICE_FUNC @@ -327,7 +388,7 @@ inline const typename ConstFixedBlockXpr::Type bottomRightCorner() return typename ConstFixedBlockXpr::Type(derived(), rows() - CRows, cols() - CCols); } -/// \returns an expression of a bottom-right corner of *this. +/// \returns an expression of a bottom-right corner of \c *this. /// /// \tparam CRows number of rows in corner as specified at compile-time /// \tparam CCols number of columns in corner as specified at compile-time @@ -361,32 +422,53 @@ inline const typename ConstFixedBlockXpr::Type bottomRightCorner(In -/// \returns a dynamic-size expression of a bottom-left corner of *this. +/// \returns an expression of a bottom-left corner of \c *this with either dynamic or fixed sizes. /// /// \param cRows the number of rows in the corner /// \param cCols the number of columns in the corner +/// \tparam NRowsType the type of the value handling the number of rows in the block, typically Index. +/// \tparam NColsType the type of the value handling the number of columns in the block, typically Index. /// /// Example: \include MatrixBase_bottomLeftCorner_int_int.cpp /// Output: \verbinclude MatrixBase_bottomLeftCorner_int_int.out /// +/// The number of rows \a blockRows and columns \a blockCols can also be specified at compile-time by passing Eigen::fix, +/// or Eigen::fix(n) as arguments. See \link block(Index,Index,NRowsType,NColsType) block() \endlink for the details. +/// EIGEN_DOC_BLOCK_ADDONS_NOT_INNER_PANEL /// -/// \sa class Block, block(Index,Index,NRowsType,NColsType) +/// \sa block(Index,Index,NRowsType,NColsType), class Block /// EIGEN_DEVICE_FUNC -inline BlockXpr bottomLeftCorner(Index cRows, Index cCols) +template +#ifndef EIGEN_PARSED_BY_DOXYGEN +inline typename FixedBlockXpr::value,internal::get_fixed_value::value>::Type +#else +inline typename FixedBlockXpr<...,...>::Type +#endif +bottomLeftCorner(NRowsType cRows, NColsType cCols) { - return BlockXpr(derived(), rows() - cRows, 0, cRows, cCols); + return typename FixedBlockXpr::value,internal::get_fixed_value::value>::Type + (derived(), rows() - internal::get_runtime_value(cRows), 0, + internal::get_runtime_value(cRows), internal::get_runtime_value(cCols)); } -/// This is the const version of bottomLeftCorner(Index, Index). +/// This is the const version of bottomLeftCorner(NRowsType, NColsType). EIGEN_DEVICE_FUNC -inline const ConstBlockXpr bottomLeftCorner(Index cRows, Index cCols) const +template +#ifndef EIGEN_PARSED_BY_DOXYGEN +inline typename ConstFixedBlockXpr::value,internal::get_fixed_value::value>::Type +#else +inline typename ConstFixedBlockXpr<...,...>::Type +#endif +bottomLeftCorner(NRowsType cRows, NColsType cCols) const { - return ConstBlockXpr(derived(), rows() - cRows, 0, cRows, cCols); + return typename ConstFixedBlockXpr::value,internal::get_fixed_value::value>::Type + (derived(), rows() - internal::get_runtime_value(cRows), 0, + internal::get_runtime_value(cRows), internal::get_runtime_value(cCols)); } -/// \returns an expression of a fixed-size bottom-left corner of *this. +/// \returns an expression of a fixed-size bottom-left corner of \c *this. /// /// The template parameters CRows and CCols are the number of rows and columns in the corner. /// @@ -395,7 +477,7 @@ inline const ConstBlockXpr bottomLeftCorner(Index cRows, Index cCols) const /// EIGEN_DOC_BLOCK_ADDONS_NOT_INNER_PANEL /// -/// \sa class Block, block(Index,Index,NRowsType,NColsType) +/// \sa block(Index,Index,NRowsType,NColsType), class Block /// template EIGEN_DEVICE_FUNC @@ -412,7 +494,7 @@ inline const typename ConstFixedBlockXpr::Type bottomLeftCorner() c return typename ConstFixedBlockXpr::Type(derived(), rows() - CRows, 0); } -/// \returns an expression of a bottom-left corner of *this. +/// \returns an expression of a bottom-left corner of \c *this. /// /// \tparam CRows number of rows in corner as specified at compile-time /// \tparam CCols number of columns in corner as specified at compile-time @@ -446,31 +528,50 @@ inline const typename ConstFixedBlockXpr::Type bottomLeftCorner(Ind -/// \returns a block consisting of the top rows of *this. +/// \returns a block consisting of the top rows of \c *this. /// /// \param n the number of rows in the block +/// \tparam NRowsType the type of the value handling the number of rows in the block, typically Index. /// /// Example: \include MatrixBase_topRows_int.cpp /// Output: \verbinclude MatrixBase_topRows_int.out /// +/// The number of rows \a n can also be specified at compile-time by passing Eigen::fix, +/// or Eigen::fix(n) as arguments. +/// See \link block(Index,Index,NRowsType,NColsType) block() \endlink for the details. +/// EIGEN_DOC_BLOCK_ADDONS_INNER_PANEL_IF(row-major) /// -/// \sa class Block, block(Index,Index,NRowsType,NColsType) +/// \sa block(Index,Index,NRowsType,NColsType), class Block /// EIGEN_DEVICE_FUNC -inline RowsBlockXpr topRows(Index n) +template +#ifndef EIGEN_PARSED_BY_DOXYGEN +inline typename NRowsBlockXpr::value>::Type +#else +inline typename NRowsBlockXpr<...>::Type +#endif +topRows(NRowsType n) { - return RowsBlockXpr(derived(), 0, 0, n, cols()); + return typename NRowsBlockXpr::value>::Type + (derived(), 0, 0, internal::get_runtime_value(n), cols()); } -/// This is the const version of topRows(Index). +/// This is the const version of topRows(NRowsType). EIGEN_DEVICE_FUNC -inline ConstRowsBlockXpr topRows(Index n) const +template +#ifndef EIGEN_PARSED_BY_DOXYGEN +inline const typename ConstNRowsBlockXpr::value>::Type +#else +inline const typename ConstNRowsBlockXpr<...>::Type +#endif +topRows(NRowsType n) const { - return ConstRowsBlockXpr(derived(), 0, 0, n, cols()); + return typename ConstNRowsBlockXpr::value>::Type + (derived(), 0, 0, internal::get_runtime_value(n), cols()); } -/// \returns a block consisting of the top rows of *this. +/// \returns a block consisting of the top rows of \c *this. /// /// \tparam N the number of rows in the block as specified at compile-time /// \param n the number of rows in the block as specified at run-time @@ -483,7 +584,7 @@ inline ConstRowsBlockXpr topRows(Index n) const /// EIGEN_DOC_BLOCK_ADDONS_INNER_PANEL_IF(row-major) /// -/// \sa class Block, block(Index,Index,NRowsType,NColsType) +/// \sa block(Index,Index,NRowsType,NColsType), class Block /// template EIGEN_DEVICE_FUNC @@ -502,31 +603,50 @@ inline typename ConstNRowsBlockXpr::Type topRows(Index n = N) const -/// \returns a block consisting of the bottom rows of *this. +/// \returns a block consisting of the bottom rows of \c *this. /// /// \param n the number of rows in the block +/// \tparam NRowsType the type of the value handling the number of rows in the block, typically Index. /// /// Example: \include MatrixBase_bottomRows_int.cpp /// Output: \verbinclude MatrixBase_bottomRows_int.out /// +/// The number of rows \a n can also be specified at compile-time by passing Eigen::fix, +/// or Eigen::fix(n) as arguments. +/// See \link block(Index,Index,NRowsType,NColsType) block() \endlink for the details. +/// EIGEN_DOC_BLOCK_ADDONS_INNER_PANEL_IF(row-major) /// -/// \sa class Block, block(Index,Index,NRowsType,NColsType) +/// \sa block(Index,Index,NRowsType,NColsType), class Block /// EIGEN_DEVICE_FUNC -inline RowsBlockXpr bottomRows(Index n) +template +#ifndef EIGEN_PARSED_BY_DOXYGEN +inline typename NRowsBlockXpr::value>::Type +#else +inline typename NRowsBlockXpr<...>::Type +#endif +bottomRows(NRowsType n) { - return RowsBlockXpr(derived(), rows() - n, 0, n, cols()); + return typename NRowsBlockXpr::value>::Type + (derived(), rows() - internal::get_runtime_value(n), 0, internal::get_runtime_value(n), cols()); } -/// This is the const version of bottomRows(Index). +/// This is the const version of bottomRows(NRowsType). EIGEN_DEVICE_FUNC -inline ConstRowsBlockXpr bottomRows(Index n) const +template +#ifndef EIGEN_PARSED_BY_DOXYGEN +inline const typename ConstNRowsBlockXpr::value>::Type +#else +inline const typename ConstNRowsBlockXpr<...>::Type +#endif +bottomRows(NRowsType n) const { - return ConstRowsBlockXpr(derived(), rows() - n, 0, n, cols()); + return typename ConstNRowsBlockXpr::value>::Type + (derived(), rows() - internal::get_runtime_value(n), 0, internal::get_runtime_value(n), cols()); } -/// \returns a block consisting of the bottom rows of *this. +/// \returns a block consisting of the bottom rows of \c *this. /// /// \tparam N the number of rows in the block as specified at compile-time /// \param n the number of rows in the block as specified at run-time @@ -539,7 +659,7 @@ inline ConstRowsBlockXpr bottomRows(Index n) const /// EIGEN_DOC_BLOCK_ADDONS_INNER_PANEL_IF(row-major) /// -/// \sa class Block, block(Index,Index,NRowsType,NColsType) +/// \sa block(Index,Index,NRowsType,NColsType), class Block /// template EIGEN_DEVICE_FUNC @@ -558,32 +678,51 @@ inline typename ConstNRowsBlockXpr::Type bottomRows(Index n = N) const -/// \returns a block consisting of a range of rows of *this. +/// \returns a block consisting of a range of rows of \c *this. /// /// \param startRow the index of the first row in the block /// \param n the number of rows in the block +/// \tparam NRowsType the type of the value handling the number of rows in the block, typically Index. /// /// Example: \include DenseBase_middleRows_int.cpp /// Output: \verbinclude DenseBase_middleRows_int.out /// +/// The number of rows \a n can also be specified at compile-time by passing Eigen::fix, +/// or Eigen::fix(n) as arguments. +/// See \link block(Index,Index,NRowsType,NColsType) block() \endlink for the details. +/// EIGEN_DOC_BLOCK_ADDONS_INNER_PANEL_IF(row-major) /// -/// \sa class Block, block(Index,Index,NRowsType,NColsType) +/// \sa block(Index,Index,NRowsType,NColsType), class Block /// EIGEN_DEVICE_FUNC -inline RowsBlockXpr middleRows(Index startRow, Index n) +template +#ifndef EIGEN_PARSED_BY_DOXYGEN +inline typename NRowsBlockXpr::value>::Type +#else +inline typename NRowsBlockXpr<...>::Type +#endif +middleRows(Index startRow, NRowsType n) { - return RowsBlockXpr(derived(), startRow, 0, n, cols()); + return typename NRowsBlockXpr::value>::Type + (derived(), startRow, 0, internal::get_runtime_value(n), cols()); } -/// This is the const version of middleRows(Index,Index). +/// This is the const version of middleRows(Index,NRowsType). EIGEN_DEVICE_FUNC -inline ConstRowsBlockXpr middleRows(Index startRow, Index n) const +template +#ifndef EIGEN_PARSED_BY_DOXYGEN +inline const typename ConstNRowsBlockXpr::value>::Type +#else +inline const typename ConstNRowsBlockXpr<...>::Type +#endif +middleRows(Index startRow, NRowsType n) const { - return ConstRowsBlockXpr(derived(), startRow, 0, n, cols()); + return typename ConstNRowsBlockXpr::value>::Type + (derived(), startRow, 0, internal::get_runtime_value(n), cols()); } -/// \returns a block consisting of a range of rows of *this. +/// \returns a block consisting of a range of rows of \c *this. /// /// \tparam N the number of rows in the block as specified at compile-time /// \param startRow the index of the first row in the block @@ -597,7 +736,7 @@ inline ConstRowsBlockXpr middleRows(Index startRow, Index n) const /// EIGEN_DOC_BLOCK_ADDONS_INNER_PANEL_IF(row-major) /// -/// \sa class Block, block(Index,Index,NRowsType,NColsType) +/// \sa block(Index,Index,NRowsType,NColsType), class Block /// template EIGEN_DEVICE_FUNC @@ -616,31 +755,50 @@ inline typename ConstNRowsBlockXpr::Type middleRows(Index startRow, Index n = -/// \returns a block consisting of the left columns of *this. +/// \returns a block consisting of the left columns of \c *this. /// /// \param n the number of columns in the block +/// \tparam NColsType the type of the value handling the number of columns in the block, typically Index. /// /// Example: \include MatrixBase_leftCols_int.cpp /// Output: \verbinclude MatrixBase_leftCols_int.out /// +/// The number of columns \a n can also be specified at compile-time by passing Eigen::fix, +/// or Eigen::fix(n) as arguments. +/// See \link block(Index,Index,NRowsType,NColsType) block() \endlink for the details. +/// EIGEN_DOC_BLOCK_ADDONS_INNER_PANEL_IF(column-major) /// -/// \sa class Block, block(Index,Index,NRowsType,NColsType) +/// \sa block(Index,Index,NRowsType,NColsType), class Block /// EIGEN_DEVICE_FUNC -inline ColsBlockXpr leftCols(Index n) +template +#ifndef EIGEN_PARSED_BY_DOXYGEN +inline typename NColsBlockXpr::value>::Type +#else +inline typename NColsBlockXpr<...>::Type +#endif +leftCols(NColsType n) { - return ColsBlockXpr(derived(), 0, 0, rows(), n); + return typename NColsBlockXpr::value>::Type + (derived(), 0, 0, rows(), internal::get_runtime_value(n)); } -/// This is the const version of leftCols(Index). +/// This is the const version of leftCols(NColsType). EIGEN_DEVICE_FUNC -inline ConstColsBlockXpr leftCols(Index n) const +template +#ifndef EIGEN_PARSED_BY_DOXYGEN +inline const typename ConstNColsBlockXpr::value>::Type +#else +inline const typename ConstNColsBlockXpr<...>::Type +#endif +leftCols(NColsType n) const { - return ConstColsBlockXpr(derived(), 0, 0, rows(), n); + return typename ConstNColsBlockXpr::value>::Type + (derived(), 0, 0, rows(), internal::get_runtime_value(n)); } -/// \returns a block consisting of the left columns of *this. +/// \returns a block consisting of the left columns of \c *this. /// /// \tparam N the number of columns in the block as specified at compile-time /// \param n the number of columns in the block as specified at run-time @@ -653,7 +811,7 @@ inline ConstColsBlockXpr leftCols(Index n) const /// EIGEN_DOC_BLOCK_ADDONS_INNER_PANEL_IF(column-major) /// -/// \sa class Block, block(Index,Index,NRowsType,NColsType) +/// \sa block(Index,Index,NRowsType,NColsType), class Block /// template EIGEN_DEVICE_FUNC @@ -672,31 +830,50 @@ inline typename ConstNColsBlockXpr::Type leftCols(Index n = N) const -/// \returns a block consisting of the right columns of *this. +/// \returns a block consisting of the right columns of \c *this. /// /// \param n the number of columns in the block +/// \tparam NColsType the type of the value handling the number of columns in the block, typically Index. /// /// Example: \include MatrixBase_rightCols_int.cpp /// Output: \verbinclude MatrixBase_rightCols_int.out /// +/// The number of columns \a n can also be specified at compile-time by passing Eigen::fix, +/// or Eigen::fix(n) as arguments. +/// See \link block(Index,Index,NRowsType,NColsType) block() \endlink for the details. +/// EIGEN_DOC_BLOCK_ADDONS_INNER_PANEL_IF(column-major) /// -/// \sa class Block, block(Index,Index,NRowsType,NColsType) +/// \sa block(Index,Index,NRowsType,NColsType), class Block /// EIGEN_DEVICE_FUNC -inline ColsBlockXpr rightCols(Index n) +template +#ifndef EIGEN_PARSED_BY_DOXYGEN +inline typename NColsBlockXpr::value>::Type +#else +inline typename NColsBlockXpr<...>::Type +#endif +rightCols(NColsType n) { - return ColsBlockXpr(derived(), 0, cols() - n, rows(), n); + return typename NColsBlockXpr::value>::Type + (derived(), 0, cols() - internal::get_runtime_value(n), rows(), internal::get_runtime_value(n)); } -/// This is the const version of rightCols(Index). +/// This is the const version of rightCols(NColsType). EIGEN_DEVICE_FUNC -inline ConstColsBlockXpr rightCols(Index n) const +template +#ifndef EIGEN_PARSED_BY_DOXYGEN +inline const typename ConstNColsBlockXpr::value>::Type +#else +inline const typename ConstNColsBlockXpr<...>::Type +#endif +rightCols(NColsType n) const { - return ConstColsBlockXpr(derived(), 0, cols() - n, rows(), n); + return typename ConstNColsBlockXpr::value>::Type + (derived(), 0, cols() - internal::get_runtime_value(n), rows(), internal::get_runtime_value(n)); } -/// \returns a block consisting of the right columns of *this. +/// \returns a block consisting of the right columns of \c *this. /// /// \tparam N the number of columns in the block as specified at compile-time /// \param n the number of columns in the block as specified at run-time @@ -709,7 +886,7 @@ inline ConstColsBlockXpr rightCols(Index n) const /// EIGEN_DOC_BLOCK_ADDONS_INNER_PANEL_IF(column-major) /// -/// \sa class Block, block(Index,Index,NRowsType,NColsType) +/// \sa block(Index,Index,NRowsType,NColsType), class Block /// template EIGEN_DEVICE_FUNC @@ -728,32 +905,51 @@ inline typename ConstNColsBlockXpr::Type rightCols(Index n = N) const -/// \returns a block consisting of a range of columns of *this. +/// \returns a block consisting of a range of columns of \c *this. /// /// \param startCol the index of the first column in the block /// \param numCols the number of columns in the block +/// \tparam NColsType the type of the value handling the number of columns in the block, typically Index. /// /// Example: \include DenseBase_middleCols_int.cpp /// Output: \verbinclude DenseBase_middleCols_int.out /// +/// The number of columns \a n can also be specified at compile-time by passing Eigen::fix, +/// or Eigen::fix(n) as arguments. +/// See \link block(Index,Index,NRowsType,NColsType) block() \endlink for the details. +/// EIGEN_DOC_BLOCK_ADDONS_INNER_PANEL_IF(column-major) /// -/// \sa class Block, block(Index,Index,NRowsType,NColsType) +/// \sa block(Index,Index,NRowsType,NColsType), class Block /// EIGEN_DEVICE_FUNC -inline ColsBlockXpr middleCols(Index startCol, Index numCols) +template +#ifndef EIGEN_PARSED_BY_DOXYGEN +inline typename NColsBlockXpr::value>::Type +#else +inline typename NColsBlockXpr<...>::Type +#endif +middleCols(Index startCol, NColsType numCols) { - return ColsBlockXpr(derived(), 0, startCol, rows(), numCols); + return typename NColsBlockXpr::value>::Type + (derived(), 0, startCol, rows(), internal::get_runtime_value(numCols)); } -/// This is the const version of middleCols(Index,Index). +/// This is the const version of middleCols(Index,NColsType). EIGEN_DEVICE_FUNC -inline ConstColsBlockXpr middleCols(Index startCol, Index numCols) const +template +#ifndef EIGEN_PARSED_BY_DOXYGEN +inline const typename ConstNColsBlockXpr::value>::Type +#else +inline const typename ConstNColsBlockXpr<...>::Type +#endif +middleCols(Index startCol, NColsType numCols) const { - return ConstColsBlockXpr(derived(), 0, startCol, rows(), numCols); + return typename ConstNColsBlockXpr::value>::Type + (derived(), 0, startCol, rows(), internal::get_runtime_value(numCols)); } -/// \returns a block consisting of a range of columns of *this. +/// \returns a block consisting of a range of columns of \c *this. /// /// \tparam N the number of columns in the block as specified at compile-time /// \param startCol the index of the first column in the block @@ -767,7 +963,7 @@ inline ConstColsBlockXpr middleCols(Index startCol, Index numCols) const /// EIGEN_DOC_BLOCK_ADDONS_INNER_PANEL_IF(column-major) /// -/// \sa class Block, block(Index,Index,NRowsType,NColsType) +/// \sa block(Index,Index,NRowsType,NColsType), class Block /// template EIGEN_DEVICE_FUNC @@ -786,7 +982,7 @@ inline typename ConstNColsBlockXpr::Type middleCols(Index startCol, Index n = -/// \returns a fixed-size expression of a block in *this. +/// \returns a fixed-size expression of a block of \c *this. /// /// The template parameters \a NRows and \a NCols are the number of /// rows and columns in the block. @@ -825,7 +1021,7 @@ inline const typename ConstFixedBlockXpr::Type block(Index startRow return typename ConstFixedBlockXpr::Type(derived(), startRow, startCol); } -/// \returns an expression of a block in *this. +/// \returns an expression of a block of \c *this. /// /// \tparam NRows number of rows in block as specified at compile-time /// \tparam NCols number of columns in block as specified at compile-time @@ -854,7 +1050,7 @@ inline const typename ConstFixedBlockXpr::Type block(Index startRow /// EIGEN_DOC_BLOCK_ADDONS_NOT_INNER_PANEL /// -/// \sa block(Index,Index,NRowsType,NColsType), block(Index,Index,NRowsType,NColsType), class Block +/// \sa block(Index,Index,NRowsType,NColsType), class Block /// template inline typename FixedBlockXpr::Type block(Index startRow, Index startCol, @@ -871,7 +1067,7 @@ inline const typename ConstFixedBlockXpr::Type block(Index startRow return typename ConstFixedBlockXpr::Type(derived(), startRow, startCol, blockRows, blockCols); } -/// \returns an expression of the \a i-th column of *this. Note that the numbering starts at 0. +/// \returns an expression of the \a i-th column of \c *this. Note that the numbering starts at 0. /// /// Example: \include MatrixBase_col.cpp /// Output: \verbinclude MatrixBase_col.out @@ -892,7 +1088,7 @@ inline ConstColXpr col(Index i) const return ConstColXpr(derived(), i); } -/// \returns an expression of the \a i-th row of *this. Note that the numbering starts at 0. +/// \returns an expression of the \a i-th row of \c *this. Note that the numbering starts at 0. /// /// Example: \include MatrixBase_row.cpp /// Output: \verbinclude MatrixBase_row.out @@ -913,96 +1109,153 @@ inline ConstRowXpr row(Index i) const return ConstRowXpr(derived(), i); } -/// \returns a dynamic-size expression of a segment (i.e. a vector block) in *this. +/// \returns an expression of a segment (i.e. a vector block) in \c *this with either dynamic or fixed sizes. /// /// \only_for_vectors /// /// \param start the first coefficient in the segment /// \param n the number of coefficients in the segment +/// \tparam NType the type of the value handling the number of coefficients in the segment, typically Index. /// /// Example: \include MatrixBase_segment_int_int.cpp /// Output: \verbinclude MatrixBase_segment_int_int.out /// -/// \note Even though the returned expression has dynamic size, in the case +/// The number of coefficients \a n can also be specified at compile-time by passing Eigen::fix, +/// or Eigen::fix(n) as arguments. +/// See \link block(Index,Index,NRowsType,NColsType) block() \endlink for the details. +/// +/// \note Even in the case that the returned expression has dynamic size, in the case /// when it is applied to a fixed-size vector, it inherits a fixed maximal size, /// which means that evaluating it does not cause a dynamic memory allocation. /// -/// \sa class Block, segment(Index) +/// \sa block(Index,Index,NRowsType,NColsType), fix, fix(int), class Block /// EIGEN_DEVICE_FUNC -inline SegmentReturnType segment(Index start, Index n) +template +#ifndef EIGEN_PARSED_BY_DOXYGEN +inline typename FixedSegmentReturnType::value>::Type +#else +inline typename FixedSegmentReturnType<...>::Type +#endif +segment(Index start, NType n) { EIGEN_STATIC_ASSERT_VECTOR_ONLY(Derived) - return SegmentReturnType(derived(), start, n); + return typename FixedSegmentReturnType::value>::Type + (derived(), start, internal::get_runtime_value(n)); } -/// This is the const version of segment(Index,Index). +/// This is the const version of segment(Index,NType). EIGEN_DEVICE_FUNC -inline ConstSegmentReturnType segment(Index start, Index n) const +template +#ifndef EIGEN_PARSED_BY_DOXYGEN +inline const typename ConstFixedSegmentReturnType::value>::Type +#else +inline const typename ConstFixedSegmentReturnType<...>::Type +#endif +segment(Index start, NType n) const { EIGEN_STATIC_ASSERT_VECTOR_ONLY(Derived) - return ConstSegmentReturnType(derived(), start, n); + return typename ConstFixedSegmentReturnType::value>::Type + (derived(), start, internal::get_runtime_value(n)); } -/// \returns a dynamic-size expression of the first coefficients of *this. +/// \returns an expression of the first coefficients of \c *this with either dynamic or fixed sizes. /// /// \only_for_vectors /// /// \param n the number of coefficients in the segment +/// \tparam NType the type of the value handling the number of coefficients in the segment, typically Index. /// /// Example: \include MatrixBase_start_int.cpp /// Output: \verbinclude MatrixBase_start_int.out /// -/// \note Even though the returned expression has dynamic size, in the case +/// The number of coefficients \a n can also be specified at compile-time by passing Eigen::fix, +/// or Eigen::fix(n) as arguments. +/// See \link block(Index,Index,NRowsType,NColsType) block() \endlink for the details. +/// +/// \note Even in the case that the returned expression has dynamic size, in the case /// when it is applied to a fixed-size vector, it inherits a fixed maximal size, /// which means that evaluating it does not cause a dynamic memory allocation. /// /// \sa class Block, block(Index,Index) /// EIGEN_DEVICE_FUNC -inline SegmentReturnType head(Index n) +template +#ifndef EIGEN_PARSED_BY_DOXYGEN +inline typename FixedSegmentReturnType::value>::Type +#else +inline typename FixedSegmentReturnType<...>::Type +#endif +head(NType n) { EIGEN_STATIC_ASSERT_VECTOR_ONLY(Derived) - return SegmentReturnType(derived(), 0, n); + return typename FixedSegmentReturnType::value>::Type + (derived(), 0, internal::get_runtime_value(n)); } -/// This is the const version of head(Index). +/// This is the const version of head(NType). EIGEN_DEVICE_FUNC -inline ConstSegmentReturnType head(Index n) const +template +#ifndef EIGEN_PARSED_BY_DOXYGEN +inline const typename ConstFixedSegmentReturnType::value>::Type +#else +inline const typename ConstFixedSegmentReturnType<...>::Type +#endif +head(NType n) const { EIGEN_STATIC_ASSERT_VECTOR_ONLY(Derived) - return ConstSegmentReturnType(derived(), 0, n); + return typename ConstFixedSegmentReturnType::value>::Type + (derived(), 0, internal::get_runtime_value(n)); } -/// \returns a dynamic-size expression of the last coefficients of *this. +/// \returns an expression of a last coefficients of \c *this with either dynamic or fixed sizes. /// /// \only_for_vectors /// /// \param n the number of coefficients in the segment +/// \tparam NType the type of the value handling the number of coefficients in the segment, typically Index. /// /// Example: \include MatrixBase_end_int.cpp /// Output: \verbinclude MatrixBase_end_int.out /// -/// \note Even though the returned expression has dynamic size, in the case +/// The number of coefficients \a n can also be specified at compile-time by passing Eigen::fix, +/// or Eigen::fix(n) as arguments. +/// See \link block(Index,Index,NRowsType,NColsType) block() \endlink for the details. +/// +/// \note Even in the case that the returned expression has dynamic size, in the case /// when it is applied to a fixed-size vector, it inherits a fixed maximal size, /// which means that evaluating it does not cause a dynamic memory allocation. /// /// \sa class Block, block(Index,Index) /// EIGEN_DEVICE_FUNC -inline SegmentReturnType tail(Index n) +template +#ifndef EIGEN_PARSED_BY_DOXYGEN +inline typename FixedSegmentReturnType::value>::Type +#else +inline typename FixedSegmentReturnType<...>::Type +#endif +tail(NType n) { EIGEN_STATIC_ASSERT_VECTOR_ONLY(Derived) - return SegmentReturnType(derived(), this->size() - n, n); + return typename FixedSegmentReturnType::value>::Type + (derived(), this->size() - internal::get_runtime_value(n), internal::get_runtime_value(n)); } /// This is the const version of tail(Index). EIGEN_DEVICE_FUNC -inline ConstSegmentReturnType tail(Index n) const +template +#ifndef EIGEN_PARSED_BY_DOXYGEN +inline const typename ConstFixedSegmentReturnType::value>::Type +#else +inline const typename ConstFixedSegmentReturnType<...>::Type +#endif +tail(NType n) const { EIGEN_STATIC_ASSERT_VECTOR_ONLY(Derived) - return ConstSegmentReturnType(derived(), this->size() - n, n); + return typename ConstFixedSegmentReturnType::value>::Type + (derived(), this->size() - internal::get_runtime_value(n), internal::get_runtime_value(n)); } /// \returns a fixed-size expression of a segment (i.e. a vector block) in \c *this @@ -1019,7 +1272,7 @@ inline ConstSegmentReturnType tail(Index n) const /// Example: \include MatrixBase_template_int_segment.cpp /// Output: \verbinclude MatrixBase_template_int_segment.out /// -/// \sa class Block +/// \sa segment(Index,NType), class Block /// template EIGEN_DEVICE_FUNC @@ -1038,7 +1291,7 @@ inline typename ConstFixedSegmentReturnType::Type segment(Index start, Index return typename ConstFixedSegmentReturnType::Type(derived(), start, n); } -/// \returns a fixed-size expression of the first coefficients of *this. +/// \returns a fixed-size expression of the first coefficients of \c *this. /// /// \only_for_vectors /// @@ -1051,7 +1304,7 @@ inline typename ConstFixedSegmentReturnType::Type segment(Index start, Index /// Example: \include MatrixBase_template_int_start.cpp /// Output: \verbinclude MatrixBase_template_int_start.out /// -/// \sa class Block +/// \sa head(NType), class Block /// template EIGEN_DEVICE_FUNC @@ -1070,7 +1323,7 @@ inline typename ConstFixedSegmentReturnType::Type head(Index n = N) const return typename ConstFixedSegmentReturnType::Type(derived(), 0, n); } -/// \returns a fixed-size expression of the last coefficients of *this. +/// \returns a fixed-size expression of the last coefficients of \c *this. /// /// \only_for_vectors /// @@ -1083,7 +1336,7 @@ inline typename ConstFixedSegmentReturnType::Type head(Index n = N) const /// Example: \include MatrixBase_template_int_end.cpp /// Output: \verbinclude MatrixBase_template_int_end.out /// -/// \sa class Block +/// \sa tail(NType), class Block /// template EIGEN_DEVICE_FUNC diff --git a/test/indexed_view.cpp b/test/indexed_view.cpp index 3ea8e7c00..47c454976 100644 --- a/test/indexed_view.cpp +++ b/test/indexed_view.cpp @@ -280,9 +280,9 @@ void check_indexed_view() // 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(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(3,3) ); + VERIFY_IS_APPROX( A(B.RowsAtCompileTime, B.ColsAtCompileTime), A(4,4) ); enum { I = 3, J = 4 }; VERIFY_IS_APPROX( A(I,J), A(3,4) ); } @@ -295,8 +295,38 @@ void check_indexed_view() VERIFY( is_same_eq( A.block(1,1,3,4), A.block(1,1,fix(3),fix<4>)) ); VERIFY( is_same_eq( A.block(1,1,3,4), A.block(1,1,fix(3),fix(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(1,1,3,4), cA.block(1,1,fix(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>)) ); } } -- cgit v1.2.3 From e4f8dd860afb5405031c3dc14576983557b199d6 Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Wed, 18 Jan 2017 10:49:01 +0100 Subject: Add missing operator* --- Eigen/src/Core/util/SymbolicIndex.h | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/Eigen/src/Core/util/SymbolicIndex.h b/Eigen/src/Core/util/SymbolicIndex.h index 6f603f301..beb9d4c13 100644 --- a/Eigen/src/Core/util/SymbolicIndex.h +++ b/Eigen/src/Core/util/SymbolicIndex.h @@ -87,6 +87,8 @@ public: { return AddExpr(derived(), b); } AddExpr operator-(Index a) const { return AddExpr(derived(), -a); } + ProductExpr operator*(Index a) const + { return ProductExpr(derived(),a); } QuotientExpr operator/(Index a) const { return QuotientExpr(derived(),a); } @@ -94,8 +96,10 @@ public: { return AddExpr(b.derived(), a); } friend AddExpr,ValueExpr> operator-(Index a, const BaseExpr& b) { return AddExpr,ValueExpr>(-b.derived(), a); } - friend AddExpr operator/(Index a, const BaseExpr& b) - { return AddExpr(a,b.derived()); } + friend ProductExpr operator*(Index a, const BaseExpr& b) + { return ProductExpr(a,b.derived()); } + friend QuotientExpr operator/(Index a, const BaseExpr& b) + { return QuotientExpr(a,b.derived()); } template AddExpr operator+(const BaseExpr &b) const @@ -105,6 +109,10 @@ public: AddExpr > operator-(const BaseExpr &b) const { return AddExpr >(derived(), -b.derived()); } + template + ProductExpr operator*(const BaseExpr &b) const + { return ProductExpr(derived(), b.derived()); } + template QuotientExpr operator/(const BaseExpr &b) const { return QuotientExpr(derived(), b.derived()); } -- cgit v1.2.3 From 15471432fe809f47e1d4986e9d81547a949e3e07 Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Wed, 18 Jan 2017 11:35:27 +0100 Subject: Add a .reverse() member to ArithmeticSequence. --- Eigen/src/Core/ArithmeticSequence.h | 84 ++++++++++++++++++++++++++++++---- Eigen/src/Core/util/IntegralConstant.h | 2 + test/indexed_view.cpp | 22 +++++++-- 3 files changed, 96 insertions(+), 12 deletions(-) diff --git a/Eigen/src/Core/ArithmeticSequence.h b/Eigen/src/Core/ArithmeticSequence.h index 2ad4c0906..0f9c72e2e 100644 --- a/Eigen/src/Core/ArithmeticSequence.h +++ b/Eigen/src/Core/ArithmeticSequence.h @@ -12,10 +12,69 @@ namespace Eigen { +namespace internal { + +#if !EIGEN_HAS_CXX11 +template struct aseq_negate {}; + +template<> struct aseq_negate { + typedef Index type; +}; + +template struct aseq_negate > { + typedef fix_t<-N> type; +}; + +// Compilation error in the following case: +template<> struct aseq_negate > {}; + +template::value, + bool SizeIsSymbolic =Symbolic::is_symbolic::value> +struct aseq_reverse_first_type { + typedef Index type; +}; + +template +struct aseq_reverse_first_type { + typedef Symbolic::AddExpr, + Symbolic::ValueExpr> + > type; +}; + +template +struct aseq_reverse_first_type { + typedef Symbolic::AddExpr type; +}; + +template +struct aseq_reverse_first_type { + typedef Symbolic::AddExpr,Symbolic::ValueExpr>, + Symbolic::ValueExpr> type; +}; +#endif + +// Helper to cleanup the type of the increment: +template struct cleanup_seq_incr { + typedef typename cleanup_index_type::type type; +}; + +} + //-------------------------------------------------------------------------------- // seq(first,last,incr) and seqN(first,size,incr) //-------------------------------------------------------------------------------- +template > +class ArithmeticSequence; + +template +ArithmeticSequence::type, + typename internal::cleanup_index_type::type, + typename internal::cleanup_seq_incr::type > +seqN(FirstType first, SizeType size, IncrType incr); + /** \class ArithmeticSequence * \ingroup Core_Module * @@ -35,10 +94,9 @@ namespace Eigen { * * \sa Eigen::seq, Eigen::seqN, DenseBase::operator()(const RowIndices&, const ColIndices&), class IndexedView */ -template > +template 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) {} @@ -65,17 +123,25 @@ protected: FirstType m_first; SizeType m_size; IncrType m_incr; -}; -namespace internal { +public: -// Helper to cleanup the type of the increment: -template struct cleanup_seq_incr { - typedef typename cleanup_index_type::type type; +#if EIGEN_HAS_CXX11 + auto reverse() const -> decltype(Eigen::seqN(m_first+(m_size-1)*Index(m_incr),m_size,-m_incr)) { + return seqN(m_first+(m_size-1)*Index(m_incr),m_size,-m_incr); + } +#else +protected: + typedef typename internal::aseq_negate::type ReverseIncrType; + typedef typename internal::aseq_reverse_first_type::type ReverseFirstType; +public: + ArithmeticSequence + reverse() const { + return seqN(m_first+(m_size-1)*Index(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) */ diff --git a/Eigen/src/Core/util/IntegralConstant.h b/Eigen/src/Core/util/IntegralConstant.h index 2402baeec..354aa8c4c 100644 --- a/Eigen/src/Core/util/IntegralConstant.h +++ b/Eigen/src/Core/util/IntegralConstant.h @@ -27,6 +27,8 @@ template struct fix_t { eigen_internal_assert(int(other)==N); } + fix_t<-N> operator-() const { return fix_t<-N>(); } + #if EIGEN_HAS_CXX14 // Needed in C++14 to allow fix(): fix_t operator() () const { return *this; } diff --git a/test/indexed_view.cpp b/test/indexed_view.cpp index 47c454976..f8b3838a4 100644 --- a/test/indexed_view.cpp +++ b/test/indexed_view.cpp @@ -58,7 +58,13 @@ template typename internal::enable_if::value,bool>::type is_same_seq_type(const T1& a, const T2& b) { - return a.size() == b.size() && a.first()==b.first() && Index(a.incrObject())==Index(b.incrObject()); + 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; } #define VERIFY_EQ_INT(A,B) VERIFY_IS_APPROX(int(A),int(B)) @@ -187,7 +193,6 @@ void check_indexed_view() VERIFY( is_same_seq_type( seqN(2,fix(5),3), seqN(2,5,fix(3)) ) ); VERIFY( is_same_seq_type( seqN(2,fix<5>(5),fix<-2>), seqN(2,fix<5>,fix<-2>()) ) ); - VERIFY( (A(seqN(2,fix<5>), 5)).RowsAtCompileTime == 5); VERIFY( (A(4, all)).ColsAtCompileTime == Dynamic); VERIFY( (A(4, all)).RowsAtCompileTime == 1); @@ -201,6 +206,8 @@ void check_indexed_view() 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)) ); @@ -218,7 +225,6 @@ void check_indexed_view() 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)) ); @@ -251,6 +257,16 @@ void check_indexed_view() 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{{1,3,2,4}})).ColsAtCompileTime == 4); -- cgit v1.2.3 From f3ccbe0419cd86feb1c5f5ec624e65a8e770859a Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Wed, 18 Jan 2017 23:16:32 +0100 Subject: Add a Symbolic::FixedExpr helper expression to make sure the compiler fully optimize the usage of last and end. --- Eigen/src/Core/ArithmeticSequence.h | 1 + Eigen/src/Core/util/IndexedViewHelper.h | 4 +++- Eigen/src/Core/util/SymbolicIndex.h | 11 +++++++++++ 3 files changed, 15 insertions(+), 1 deletion(-) diff --git a/Eigen/src/Core/ArithmeticSequence.h b/Eigen/src/Core/ArithmeticSequence.h index 0f9c72e2e..5ab044442 100644 --- a/Eigen/src/Core/ArithmeticSequence.h +++ b/Eigen/src/Core/ArithmeticSequence.h @@ -378,6 +378,7 @@ public: Index size() const { return (m_last-m_first+m_incr)/m_incr; } Index operator[](Index i) const { return m_first + i * m_incr; } + Index first() const { return m_first; } const FirstType& firstObject() const { return m_first; } const LastType& lastObject() const { return m_last; } diff --git a/Eigen/src/Core/util/IndexedViewHelper.h b/Eigen/src/Core/util/IndexedViewHelper.h index b4f7c0dd7..a8259bb2c 100644 --- a/Eigen/src/Core/util/IndexedViewHelper.h +++ b/Eigen/src/Core/util/IndexedViewHelper.h @@ -58,7 +58,9 @@ static const Symbolic::SymbolExpr last; #ifdef EIGEN_PARSED_BY_DOXYGEN static const auto end = last+1; #else -static const Symbolic::AddExpr,Symbolic::ValueExpr> end(last+1); +// 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::FixedExpr<1> > end(last+Symbolic::FixedExpr<1>()); #endif } // end namespace placeholders diff --git a/Eigen/src/Core/util/SymbolicIndex.h b/Eigen/src/Core/util/SymbolicIndex.h index beb9d4c13..cee5d908a 100644 --- a/Eigen/src/Core/util/SymbolicIndex.h +++ b/Eigen/src/Core/util/SymbolicIndex.h @@ -124,6 +124,17 @@ struct is_symbolic { enum { value = internal::is_convertible >::value }; }; +// Simple wrapper around a compile-time value, +// It is similar to ValueExpr(N) but this version helps the compiler to generate better code. +template +class FixedExpr : public BaseExpr > { +public: + FixedExpr() {} + template + Index eval_impl(const T&) const { return N; } +}; + + /** 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. -- cgit v1.2.3 From e84ed7b6ef09653fb8e042c5f3fda386de1b192e Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Wed, 18 Jan 2017 23:18:28 +0100 Subject: Remove dead code --- Eigen/src/Core/ArithmeticSequence.h | 114 ------------------------------------ test/indexed_view.cpp | 4 -- 2 files changed, 118 deletions(-) diff --git a/Eigen/src/Core/ArithmeticSequence.h b/Eigen/src/Core/ArithmeticSequence.h index 5ab044442..b84930a19 100644 --- a/Eigen/src/Core/ArithmeticSequence.h +++ b/Eigen/src/Core/ArithmeticSequence.h @@ -318,120 +318,6 @@ struct get_compile_time_incr > { } // end namespace internal -//-------------------------------------------------------------------------------- - -namespace legacy { -// Here are some initial code that I keep here for now to compare the quality of the code generated by the compilers -// This part will be removed once we have checked everything is right. - -struct shifted_last { - explicit shifted_last(int o) : offset(o) {} - int offset; - shifted_last operator+ (int x) const { return shifted_last(offset+x); } - shifted_last operator- (int x) const { return shifted_last(offset-x); } - int operator- (shifted_last x) const { return offset-x.offset; } -}; - -struct last_t { - last_t() {} - shifted_last operator- (int offset) const { return shifted_last(-offset); } - shifted_last operator+ (int offset) const { return shifted_last(+offset); } - int operator- (last_t) const { return 0; } - int operator- (shifted_last x) const { return -x.offset; } -}; -static const last_t last; - - -struct shifted_end { - explicit shifted_end(int o) : offset(o) {} - int offset; - shifted_end operator+ (int x) const { return shifted_end(offset+x); } - shifted_end operator- (int x) const { return shifted_end(offset-x); } - int operator- (shifted_end x) const { return offset-x.offset; } -}; - -struct end_t { - end_t() {} - shifted_end operator- (int offset) const { return shifted_end (-offset); } - shifted_end operator+ (int offset) const { return shifted_end ( offset); } - int operator- (end_t) const { return 0; } - int operator- (shifted_end x) const { return -x.offset; } -}; -static const end_t end; - -inline Index eval_expr_given_size(last_t, Index size) { return size-1; } -inline Index eval_expr_given_size(shifted_last x, Index size) { return size+x.offset-1; } -inline Index eval_expr_given_size(end_t, Index size) { return size; } -inline Index eval_expr_given_size(shifted_end x, Index size) { return size+x.offset; } - -template > -class ArithmeticSequenceProxyWithBounds -{ -public: - ArithmeticSequenceProxyWithBounds(FirstType f, LastType l) : m_first(f), m_last(l) {} - ArithmeticSequenceProxyWithBounds(FirstType f, LastType l, IncrType s) : m_first(f), m_last(l), m_incr(s) {} - - enum { - SizeAtCompileTime = -1, - IncrAtCompileTime = internal::get_fixed_value::value - }; - - Index size() const { return (m_last-m_first+m_incr)/m_incr; } - Index operator[](Index i) const { return m_first + i * m_incr; } - Index first() const { return m_first; } - - const FirstType& firstObject() const { return m_first; } - const LastType& lastObject() const { return m_last; } - const IncrType& incrObject() const { return m_incr; } - -protected: - FirstType m_first; - LastType m_last; - IncrType m_incr; -}; - -template -ArithmeticSequenceProxyWithBounds::type,typename internal::cleanup_index_type::type > -seq(FirstType f, LastType l) { - return ArithmeticSequenceProxyWithBounds::type,typename internal::cleanup_index_type::type>(f,l); -} - -template -ArithmeticSequenceProxyWithBounds< typename internal::cleanup_index_type::type, - typename internal::cleanup_index_type::type, - typename internal::cleanup_seq_incr::type > -seq(FirstType f, LastType l, IncrType s) -{ - return ArithmeticSequenceProxyWithBounds::type, - typename internal::cleanup_index_type::type, - typename internal::cleanup_seq_incr::type> - (f,l,typename internal::cleanup_seq_incr::type(s)); -} - -} - -namespace internal { - -template -struct get_compile_time_incr > { - enum { value = get_fixed_value::value }; -}; - -// Convert a symbolic range into a usable one (i.e., remove last/end "keywords") -template -struct IndexedViewCompatibleType,XprSize> { - typedef legacy::ArithmeticSequenceProxyWithBounds type; -}; - -template -legacy::ArithmeticSequenceProxyWithBounds -makeIndexedViewCompatible(const legacy::ArithmeticSequenceProxyWithBounds& ids, Index size,SpecializedType) { - return legacy::ArithmeticSequenceProxyWithBounds( - eval_expr_given_size(ids.firstObject(),size),eval_expr_given_size(ids.lastObject(),size),ids.incrObject()); -} - -} - } // end namespace Eigen #endif // EIGEN_ARITHMETIC_SEQUENCE_H diff --git a/test/indexed_view.cpp b/test/indexed_view.cpp index f8b3838a4..751f98344 100644 --- a/test/indexed_view.cpp +++ b/test/indexed_view.cpp @@ -289,10 +289,6 @@ void check_indexed_view() #endif - // check legacy code - VERIFY_IS_APPROX( A(legacy::seq(legacy::last,2,-2), legacy::seq(legacy::last-6,7)), A(seq(last,2,-2), seq(last-6,7)) ); - VERIFY_IS_APPROX( A(seqN(legacy::last,2,-2), seqN(legacy::last-6,3)), A(seqN(last,2,-2), seqN(last-6,3)) ); - // check mat(i,j) with weird types for i and j { VERIFY_IS_APPROX( A(B.RowsAtCompileTime-1, 1), A(3,1) ); -- cgit v1.2.3 From 924600a0e817d5200a8841ce6577ef372dcc209c Mon Sep 17 00:00:00 2001 From: Benoit Steiner Date: Thu, 19 Jan 2017 09:54:48 -0800 Subject: Made sure that enabling avx2 instructions enables avx and sse instructions as well. --- Eigen/Core | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/Eigen/Core b/Eigen/Core index 16be82ac2..1c709cad3 100644 --- a/Eigen/Core +++ b/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 -- cgit v1.2.3 From 7691723e3486196576c183045e50892b5d734170 Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Thu, 19 Jan 2017 19:25:29 +0100 Subject: Add support for fixed-value in symbolic expression, c++11 only for now. --- Eigen/Core | 2 +- Eigen/src/Core/util/IndexedViewHelper.h | 2 +- Eigen/src/Core/util/SymbolicIndex.h | 50 +++++++++++++++++++++++++-------- 3 files changed, 41 insertions(+), 13 deletions(-) diff --git a/Eigen/Core b/Eigen/Core index 2ce2dd6b2..b9149659a 100644 --- a/Eigen/Core +++ b/Eigen/Core @@ -354,8 +354,8 @@ 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/SymbolicIndex.h" #include "src/Core/util/IntegralConstant.h" +#include "src/Core/util/SymbolicIndex.h" #include "src/Core/NumTraits.h" diff --git a/Eigen/src/Core/util/IndexedViewHelper.h b/Eigen/src/Core/util/IndexedViewHelper.h index a8259bb2c..5dca1926c 100644 --- a/Eigen/src/Core/util/IndexedViewHelper.h +++ b/Eigen/src/Core/util/IndexedViewHelper.h @@ -60,7 +60,7 @@ 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::FixedExpr<1> > end(last+Symbolic::FixedExpr<1>()); +static const Symbolic::AddExpr,Symbolic::FixedExpr<1> > end(last+fix<1>()); #endif } // end namespace placeholders diff --git a/Eigen/src/Core/util/SymbolicIndex.h b/Eigen/src/Core/util/SymbolicIndex.h index cee5d908a..fcc5921e6 100644 --- a/Eigen/src/Core/util/SymbolicIndex.h +++ b/Eigen/src/Core/util/SymbolicIndex.h @@ -57,6 +57,17 @@ protected: Index m_value; }; +// Simple wrapper around a compile-time value, +// It is similar to ValueExpr(N) but this version helps the compiler to generate better code. +template +class FixedExpr { +public: + FixedExpr() {} + template + Index eval_impl(const T&) const { return N; } +}; + + /** \class BaseExpr * \ingroup Core_Module * Common base class of any symbolic expressions @@ -101,6 +112,34 @@ public: friend QuotientExpr operator/(Index a, const BaseExpr& b) { return QuotientExpr(a,b.derived()); } + + template + AddExpr > operator+(internal::fix_t) const + { return AddExpr >(derived(), FixedExpr()); } + template + AddExpr > operator-(internal::fix_t) const + { return AddExpr >(derived(), FixedExpr<-N>()); } + template + ProductExpr > operator*(internal::fix_t) const + { return ProductExpr >(derived(),FixedExpr()); } + template + QuotientExpr > operator/(internal::fix_t) const + { return QuotientExpr >(derived(),FixedExpr()); } + + template + friend AddExpr > operator+(internal::fix_t, const BaseExpr& b) + { return AddExpr >(b.derived(), FixedExpr()); } + template + friend AddExpr,FixedExpr > operator-(internal::fix_t, const BaseExpr& b) + { return AddExpr,FixedExpr >(-b.derived(), FixedExpr()); } + template + friend ProductExpr,Derived> operator*(internal::fix_t, const BaseExpr& b) + { return ProductExpr,Derived>(FixedExpr(),b.derived()); } + template + friend QuotientExpr,Derived> operator/(internal::fix_t, const BaseExpr& b) + { return QuotientExpr ,Derived>(FixedExpr(),b.derived()); } + + template AddExpr operator+(const BaseExpr &b) const { return AddExpr(derived(), b.derived()); } @@ -124,17 +163,6 @@ struct is_symbolic { enum { value = internal::is_convertible >::value }; }; -// Simple wrapper around a compile-time value, -// It is similar to ValueExpr(N) but this version helps the compiler to generate better code. -template -class FixedExpr : public BaseExpr > { -public: - FixedExpr() {} - template - Index eval_impl(const T&) const { return N; } -}; - - /** 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. -- cgit v1.2.3 From 54f3fbee246744d2cb3aeeb9c52ee32a159b29c5 Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Thu, 19 Jan 2017 19:57:32 +0100 Subject: Exploit fixed values in seq and reverse with C++98 compatibility --- Eigen/src/Core/ArithmeticSequence.h | 67 ++++++++++++++------------- Eigen/src/Core/util/IndexedViewHelper.h | 2 +- Eigen/src/Core/util/SymbolicIndex.h | 82 ++++++++++++++++----------------- 3 files changed, 77 insertions(+), 74 deletions(-) diff --git a/Eigen/src/Core/ArithmeticSequence.h b/Eigen/src/Core/ArithmeticSequence.h index b84930a19..1f3a9e583 100644 --- a/Eigen/src/Core/ArithmeticSequence.h +++ b/Eigen/src/Core/ArithmeticSequence.h @@ -28,30 +28,31 @@ template struct aseq_negate > { // Compilation error in the following case: template<> struct aseq_negate > {}; -template::value, bool SizeIsSymbolic =Symbolic::is_symbolic::value> struct aseq_reverse_first_type { typedef Index type; }; -template -struct aseq_reverse_first_type { +template +struct aseq_reverse_first_type { typedef Symbolic::AddExpr, - Symbolic::ValueExpr> + Symbolic::ProductExpr > >, + Symbolic::ValueExpr > > type; }; -template -struct aseq_reverse_first_type { - typedef Symbolic::AddExpr type; +template +struct aseq_reverse_first_type { + typedef Symbolic::AddExpr > type; }; -template -struct aseq_reverse_first_type { - typedef Symbolic::AddExpr,Symbolic::ValueExpr>, - Symbolic::ValueExpr> type; +template +struct aseq_reverse_first_type { + typedef Symbolic::AddExpr > >, + Symbolic::ValueExpr >, + Symbolic::ValueExpr<> > type; }; #endif @@ -127,17 +128,17 @@ protected: public: #if EIGEN_HAS_CXX11 - auto reverse() const -> decltype(Eigen::seqN(m_first+(m_size-1)*Index(m_incr),m_size,-m_incr)) { - return seqN(m_first+(m_size-1)*Index(m_incr),m_size,-m_incr); + 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::type ReverseIncrType; - typedef typename internal::aseq_reverse_first_type::type ReverseFirstType; + typedef typename internal::aseq_reverse_first_type::type ReverseFirstType; public: ArithmeticSequence reverse() const { - return seqN(m_first+(m_size-1)*Index(m_incr),m_size,-m_incr); + return seqN(m_first+(m_size+fix<-1>())*m_incr,m_size,-m_incr); } #endif }; @@ -204,38 +205,40 @@ auto seq(FirstType f, LastType l, IncrType incr) return seqN(f,(l-f+CleanedIncrType(incr))/CleanedIncrType(incr),CleanedIncrType(incr)); } #else + template typename internal::enable_if::value || Symbolic::is_symbolic::value), ArithmeticSequence::type,Index> >::type seq(FirstType f, LastType l) { - return seqN(f,(l-f+1)); + return seqN(f,(l-f+fix<1>())); } template typename internal::enable_if::value, - ArithmeticSequence,Symbolic::ValueExpr>, - Symbolic::ValueExpr> > >::type + ArithmeticSequence,Symbolic::ValueExpr<> >, + Symbolic::ValueExpr > > > >::type seq(const Symbolic::BaseExpr &f, LastType l) { - return seqN(f.derived(),(l-f.derived()+1)); + return seqN(f.derived(),(l-f.derived()+fix<1>())); } template typename internal::enable_if::value, ArithmeticSequence::type, - Symbolic::AddExpr,Symbolic::ValueExpr> > >::type + Symbolic::AddExpr >, + Symbolic::ValueExpr > > > >::type seq(FirstType f, const Symbolic::BaseExpr &l) { - return seqN(f,(l.derived()-f+1)); + return seqN(f,(l.derived()-f+fix<1>())); } template ArithmeticSequence >,Symbolic::ValueExpr> > + Symbolic::AddExpr >,Symbolic::ValueExpr > > > seq(const Symbolic::BaseExpr &f, const Symbolic::BaseExpr &l) { - return seqN(f.derived(),(l.derived()-f.derived()+1)); + return seqN(f.derived(),(l.derived()-f.derived()+fix<1>())); } @@ -252,9 +255,9 @@ template typename internal::enable_if::value, ArithmeticSequence, - Symbolic::ValueExpr>, - Symbolic::ValueExpr>, - Symbolic::ValueExpr>, + Symbolic::ValueExpr<> >, + Symbolic::ValueExpr::type> >, + Symbolic::ValueExpr::type> >, typename internal::cleanup_seq_incr::type> >::type seq(const Symbolic::BaseExpr &f, LastType l, IncrType incr) { @@ -265,9 +268,9 @@ seq(const Symbolic::BaseExpr &f, LastType l, IncrType incr) template typename internal::enable_if::value, ArithmeticSequence::type, - Symbolic::QuotientExpr, - Symbolic::ValueExpr>, - Symbolic::ValueExpr>, + Symbolic::QuotientExpr >, + Symbolic::ValueExpr::type> >, + Symbolic::ValueExpr::type> >, typename internal::cleanup_seq_incr::type> >::type seq(FirstType f, const Symbolic::BaseExpr &l, IncrType incr) { @@ -279,8 +282,8 @@ template ArithmeticSequence >, - Symbolic::ValueExpr>, - Symbolic::ValueExpr>, + Symbolic::ValueExpr::type> >, + Symbolic::ValueExpr::type> >, typename internal::cleanup_seq_incr::type> seq(const Symbolic::BaseExpr &f, const Symbolic::BaseExpr &l, IncrType incr) { diff --git a/Eigen/src/Core/util/IndexedViewHelper.h b/Eigen/src/Core/util/IndexedViewHelper.h index 5dca1926c..1171b2b2e 100644 --- a/Eigen/src/Core/util/IndexedViewHelper.h +++ b/Eigen/src/Core/util/IndexedViewHelper.h @@ -60,7 +60,7 @@ 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::FixedExpr<1> > end(last+fix<1>()); +static const Symbolic::AddExpr,Symbolic::ValueExpr > > end(last+fix<1>()); #endif } // end namespace placeholders diff --git a/Eigen/src/Core/util/SymbolicIndex.h b/Eigen/src/Core/util/SymbolicIndex.h index fcc5921e6..5e9465db8 100644 --- a/Eigen/src/Core/util/SymbolicIndex.h +++ b/Eigen/src/Core/util/SymbolicIndex.h @@ -46,23 +46,24 @@ template class AddExpr; template class ProductExpr; template class QuotientExpr; -// A simple wrapper around an Index to provide the eval method. +// A simple wrapper around an integral value to provide the eval method. // We could also use a free-function symbolic_eval... +template class ValueExpr { public: - ValueExpr(Index val) : m_value(val) {} + ValueExpr(IndexType val) : m_value(val) {} template - Index eval_impl(const T&) const { return m_value; } + IndexType eval_impl(const T&) const { return m_value; } protected: - Index m_value; + IndexType m_value; }; -// Simple wrapper around a compile-time value, +// Specialization for compile-time value, // It is similar to ValueExpr(N) but this version helps the compiler to generate better code. template -class FixedExpr { +class ValueExpr > { public: - FixedExpr() {} + ValueExpr() {} template Index eval_impl(const T&) const { return N; } }; @@ -94,50 +95,49 @@ public: NegateExpr operator-() const { return NegateExpr(derived()); } - AddExpr operator+(Index b) const - { return AddExpr(derived(), b); } - AddExpr operator-(Index a) const - { return AddExpr(derived(), -a); } - ProductExpr operator*(Index a) const - { return ProductExpr(derived(),a); } - QuotientExpr operator/(Index a) const - { return QuotientExpr(derived(),a); } - - friend AddExpr operator+(Index a, const BaseExpr& b) - { return AddExpr(b.derived(), a); } - friend AddExpr,ValueExpr> operator-(Index a, const BaseExpr& b) - { return AddExpr,ValueExpr>(-b.derived(), a); } - friend ProductExpr operator*(Index a, const BaseExpr& b) - { return ProductExpr(a,b.derived()); } - friend QuotientExpr operator/(Index a, const BaseExpr& b) - { return QuotientExpr(a,b.derived()); } - + AddExpr > operator+(Index b) const + { return AddExpr >(derived(), b); } + AddExpr > operator-(Index a) const + { return AddExpr >(derived(), -a); } + ProductExpr > operator*(Index a) const + { return ProductExpr >(derived(),a); } + QuotientExpr > operator/(Index a) const + { return QuotientExpr >(derived(),a); } + + friend AddExpr > operator+(Index a, const BaseExpr& b) + { return AddExpr >(b.derived(), a); } + friend AddExpr,ValueExpr<> > operator-(Index a, const BaseExpr& b) + { return AddExpr,ValueExpr<> >(-b.derived(), a); } + friend ProductExpr,Derived> operator*(Index a, const BaseExpr& b) + { return ProductExpr,Derived>(a,b.derived()); } + friend QuotientExpr,Derived> operator/(Index a, const BaseExpr& b) + { return QuotientExpr,Derived>(a,b.derived()); } template - AddExpr > operator+(internal::fix_t) const - { return AddExpr >(derived(), FixedExpr()); } + AddExpr > > operator+(internal::fix_t) const + { return AddExpr > >(derived(), ValueExpr >()); } template - AddExpr > operator-(internal::fix_t) const - { return AddExpr >(derived(), FixedExpr<-N>()); } + AddExpr > > operator-(internal::fix_t) const + { return AddExpr > >(derived(), ValueExpr >()); } template - ProductExpr > operator*(internal::fix_t) const - { return ProductExpr >(derived(),FixedExpr()); } + ProductExpr > > operator*(internal::fix_t) const + { return ProductExpr > >(derived(),ValueExpr >()); } template - QuotientExpr > operator/(internal::fix_t) const - { return QuotientExpr >(derived(),FixedExpr()); } + QuotientExpr > > operator/(internal::fix_t) const + { return QuotientExpr > >(derived(),ValueExpr >()); } template - friend AddExpr > operator+(internal::fix_t, const BaseExpr& b) - { return AddExpr >(b.derived(), FixedExpr()); } + friend AddExpr > > operator+(internal::fix_t, const BaseExpr& b) + { return AddExpr > >(b.derived(), ValueExpr >()); } template - friend AddExpr,FixedExpr > operator-(internal::fix_t, const BaseExpr& b) - { return AddExpr,FixedExpr >(-b.derived(), FixedExpr()); } + friend AddExpr,ValueExpr > > operator-(internal::fix_t, const BaseExpr& b) + { return AddExpr,ValueExpr > >(-b.derived(), ValueExpr >()); } template - friend ProductExpr,Derived> operator*(internal::fix_t, const BaseExpr& b) - { return ProductExpr,Derived>(FixedExpr(),b.derived()); } + friend ProductExpr >,Derived> operator*(internal::fix_t, const BaseExpr& b) + { return ProductExpr >,Derived>(ValueExpr >(),b.derived()); } template - friend QuotientExpr,Derived> operator/(internal::fix_t, const BaseExpr& b) - { return QuotientExpr ,Derived>(FixedExpr(),b.derived()); } + friend QuotientExpr >,Derived> operator/(internal::fix_t, const BaseExpr& b) + { return QuotientExpr > ,Derived>(ValueExpr >(),b.derived()); } template -- cgit v1.2.3 From 4d302a080c775290acf23935f233cebbe19540f4 Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Thu, 19 Jan 2017 20:34:18 +0100 Subject: Recover compile-time size from seq(A,B) when A and B are fixed values. (c++11 only) --- Eigen/src/Core/ArithmeticSequence.h | 27 +++++++++++++++++---------- Eigen/src/Core/util/IntegralConstant.h | 4 ++++ Eigen/src/Core/util/SymbolicIndex.h | 7 +++++++ test/indexed_view.cpp | 20 ++++++++++++++++++-- 4 files changed, 46 insertions(+), 12 deletions(-) diff --git a/Eigen/src/Core/ArithmeticSequence.h b/Eigen/src/Core/ArithmeticSequence.h index 1f3a9e583..646eb5770 100644 --- a/Eigen/src/Core/ArithmeticSequence.h +++ b/Eigen/src/Core/ArithmeticSequence.h @@ -191,18 +191,22 @@ auto seq(FirstType f, LastType l); #if EIGEN_HAS_CXX11 template -auto seq(FirstType f, LastType l) -> decltype(seqN(f,(l-f+fix<1>()))) +auto seq(FirstType f, LastType l) -> decltype(seqN(f,( typename internal::cleanup_index_type::type(l) + - typename internal::cleanup_index_type::type(f)+fix<1>()))) { - return seqN(f,(l-f+fix<1>())); + return seqN(f,(typename internal::cleanup_index_type::type(l) + -typename internal::cleanup_index_type::type(f)+fix<1>())); } template auto seq(FirstType f, LastType l, IncrType incr) - -> decltype(seqN(f, (l-f+typename internal::cleanup_seq_incr::type(incr)) + -> decltype(seqN(f, ( typename internal::cleanup_index_type::type(l) + - typename internal::cleanup_index_type::type(f)+typename internal::cleanup_seq_incr::type(incr)) / typename internal::cleanup_seq_incr::type(incr),typename internal::cleanup_seq_incr::type(incr))) { typedef typename internal::cleanup_seq_incr::type CleanedIncrType; - return seqN(f,(l-f+CleanedIncrType(incr))/CleanedIncrType(incr),CleanedIncrType(incr)); + return seqN(f,(typename internal::cleanup_index_type::type(l) + -typename internal::cleanup_index_type::type(f)+CleanedIncrType(incr)) / CleanedIncrType(incr),CleanedIncrType(incr)); } #else @@ -211,7 +215,8 @@ typename internal::enable_if::value || Symbol ArithmeticSequence::type,Index> >::type seq(FirstType f, LastType l) { - return seqN(f,(l-f+fix<1>())); + return seqN(typename internal::cleanup_index_type::type(f), + Index((typename internal::cleanup_index_type::type(l)-typename internal::cleanup_index_type::type(f)+fix<1>()))); } template @@ -220,7 +225,7 @@ typename internal::enable_if::value, Symbolic::ValueExpr > > > >::type seq(const Symbolic::BaseExpr &f, LastType l) { - return seqN(f.derived(),(l-f.derived()+fix<1>())); + return seqN(f.derived(),(typename internal::cleanup_index_type::type(l)-f.derived()+fix<1>())); } template @@ -230,7 +235,7 @@ typename internal::enable_if::value, Symbolic::ValueExpr > > > >::type seq(FirstType f, const Symbolic::BaseExpr &l) { - return seqN(f,(l.derived()-f+fix<1>())); + return seqN(typename internal::cleanup_index_type::type(f),(l.derived()-typename internal::cleanup_index_type::type(f)+fix<1>())); } template @@ -248,7 +253,8 @@ typename internal::enable_if::value || Symbol seq(FirstType f, LastType l, IncrType incr) { typedef typename internal::cleanup_seq_incr::type CleanedIncrType; - return seqN(f,(l-f+CleanedIncrType(incr))/CleanedIncrType(incr), incr); + return seqN(typename internal::cleanup_index_type::type(f), + Index((typename internal::cleanup_index_type::type(l)-typename internal::cleanup_index_type::type(f)+CleanedIncrType(incr))/CleanedIncrType(incr)), incr); } template @@ -262,7 +268,7 @@ typename internal::enable_if::value, seq(const Symbolic::BaseExpr &f, LastType l, IncrType incr) { typedef typename internal::cleanup_seq_incr::type CleanedIncrType; - return seqN(f.derived(),(l-f.derived()+CleanedIncrType(incr))/CleanedIncrType(incr), incr); + return seqN(f.derived(),(typename internal::cleanup_index_type::type(l)-f.derived()+CleanedIncrType(incr))/CleanedIncrType(incr), incr); } template @@ -275,7 +281,8 @@ typename internal::enable_if::value, seq(FirstType f, const Symbolic::BaseExpr &l, IncrType incr) { typedef typename internal::cleanup_seq_incr::type CleanedIncrType; - return seqN(f,(l.derived()-f+CleanedIncrType(incr))/CleanedIncrType(incr), incr); + return seqN(typename internal::cleanup_index_type::type(f), + (l.derived()-typename internal::cleanup_index_type::type(f)+CleanedIncrType(incr))/CleanedIncrType(incr), incr); } template diff --git a/Eigen/src/Core/util/IntegralConstant.h b/Eigen/src/Core/util/IntegralConstant.h index 354aa8c4c..178e4893c 100644 --- a/Eigen/src/Core/util/IntegralConstant.h +++ b/Eigen/src/Core/util/IntegralConstant.h @@ -28,6 +28,10 @@ template struct fix_t { } fix_t<-N> operator-() const { return fix_t<-N>(); } + template + fix_t operator+(fix_t) const { return fix_t(); } + template + fix_t operator-(fix_t) const { return fix_t(); } #if EIGEN_HAS_CXX14 // Needed in C++14 to allow fix(): diff --git a/Eigen/src/Core/util/SymbolicIndex.h b/Eigen/src/Core/util/SymbolicIndex.h index 5e9465db8..62058760b 100644 --- a/Eigen/src/Core/util/SymbolicIndex.h +++ b/Eigen/src/Core/util/SymbolicIndex.h @@ -163,6 +163,13 @@ struct is_symbolic { enum { value = internal::is_convertible >::value }; }; +// Specialization for functions, because is_convertible fails in this case. +// Useful in c++98/11 mode when testing is_symbolic)> +template +struct is_symbolic { + 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. diff --git a/test/indexed_view.cpp b/test/indexed_view.cpp index 751f98344..e70a9c616 100644 --- a/test/indexed_view.cpp +++ b/test/indexed_view.cpp @@ -55,8 +55,7 @@ is_same_eq(const T1& a, const T2& b) } template -typename internal::enable_if::value,bool>::type -is_same_seq_type(const T1& a, const T2& b) +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) @@ -67,6 +66,15 @@ is_same_seq_type(const T1& a, const T2& b) return ok; } +template +typename internal::enable_if::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() @@ -193,6 +201,14 @@ void check_indexed_view() VERIFY( is_same_seq_type( seqN(2,fix(5),3), seqN(2,5,fix(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>) ) ); +#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); -- cgit v1.2.3 From 22a172751e7b91f97f33ba769a2d5e1955c44280 Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Sat, 21 Jan 2017 22:09:59 +0100 Subject: bug #1378: fix doc (DiagonalIndex vs Diagonal) --- Eigen/src/Core/Diagonal.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Eigen/src/Core/Diagonal.h b/Eigen/src/Core/Diagonal.h index bfea0584b..49e711257 100644 --- a/Eigen/src/Core/Diagonal.h +++ b/Eigen/src/Core/Diagonal.h @@ -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. * -- cgit v1.2.3 From 0fe278f7bed761e0dd3ddec16503794f8ccf84eb Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Sat, 21 Jan 2017 23:27:01 +0100 Subject: bug #1379: fix compilation in sparse*diagonal*dense with openmp --- Eigen/src/SparseCore/SparseDiagonalProduct.h | 4 ++++ test/sparse_product.cpp | 4 ++++ 2 files changed, 8 insertions(+) diff --git a/Eigen/src/SparseCore/SparseDiagonalProduct.h b/Eigen/src/SparseCore/SparseDiagonalProduct.h index e4af49e09..941c03be3 100644 --- a/Eigen/src/SparseCore/SparseDiagonalProduct.h +++ b/Eigen/src/SparseCore/SparseDiagonalProduct.h @@ -80,6 +80,8 @@ public: sparse_diagonal_product_evaluator(const SparseXprType &sparseXpr, const DiagonalCoeffType &diagCoeff) : m_sparseXprImpl(sparseXpr), m_diagCoeffImpl(diagCoeff) {} + + Index nonZerosEstimate() const { return m_sparseXprImpl.nonZerosEstimate(); } protected: evaluator m_sparseXprImpl; @@ -121,6 +123,8 @@ struct sparse_diagonal_product_evaluator m_sparseXprEval; diff --git a/test/sparse_product.cpp b/test/sparse_product.cpp index c7c93373d..c1edd26e3 100644 --- a/test/sparse_product.cpp +++ b/test/sparse_product.cpp @@ -241,12 +241,16 @@ template 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); VERIFY_IS_APPROX(m3=v1.asDiagonal()*m2.transpose(), refM3=v1.asDiagonal()*refM2.transpose()); 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); -- cgit v1.2.3 From 4b607b5692bc2e26510861f1ce85c78aaf2057ff Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Mon, 23 Jan 2017 22:00:33 +0100 Subject: Use Index instead of size_t --- Eigen/src/Core/products/SelfadjointMatrixVector.h | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/Eigen/src/Core/products/SelfadjointMatrixVector.h b/Eigen/src/Core/products/SelfadjointMatrixVector.h index d97f8caa7..3fd180e6c 100644 --- a/Eigen/src/Core/products/SelfadjointMatrixVector.h +++ b/Eigen/src/Core/products/SelfadjointMatrixVector.h @@ -83,10 +83,10 @@ EIGEN_DONT_INLINE void selfadjoint_matrix_vector_product(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(a0It); a0It += PacketSize; Packet A1i = ploadu(a1It); a1It += PacketSize; @@ -125,7 +125,7 @@ EIGEN_DONT_INLINE void selfadjoint_matrix_vector_product Date: Mon, 23 Jan 2017 22:02:53 +0100 Subject: Add std:: namespace prefix to all (hopefully) instances if size_t/ptrdfiff_t --- Eigen/QtAlignedMalloc | 4 +-- Eigen/src/CholmodSupport/CholmodSupport.h | 4 +-- Eigen/src/Core/PlainObjectBase.h | 2 +- Eigen/src/Core/arch/AltiVec/Complex.h | 2 +- Eigen/src/Core/arch/AltiVec/PacketMath.h | 14 ++++---- Eigen/src/Core/arch/ZVector/PacketMath.h | 2 +- Eigen/src/Core/util/Memory.h | 54 +++++++++++++++---------------- Eigen/src/SparseCore/SparseMatrix.h | 8 ++--- Eigen/src/StlSupport/details.h | 14 ++++---- 9 files changed, 52 insertions(+), 52 deletions(-) diff --git a/Eigen/QtAlignedMalloc b/Eigen/QtAlignedMalloc index 4044d5ac5..c6571f129 100644 --- a/Eigen/QtAlignedMalloc +++ b/Eigen/QtAlignedMalloc @@ -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); diff --git a/Eigen/src/CholmodSupport/CholmodSupport.h b/Eigen/src/CholmodSupport/CholmodSupport.h index a07efb1d5..61faf43ba 100644 --- a/Eigen/src/CholmodSupport/CholmodSupport.h +++ b/Eigen/src/CholmodSupport/CholmodSupport.h @@ -190,9 +190,9 @@ template cholmod_sparse* cm_spsolve (int sys, chol template<> cholmod_sparse* cm_spsolve (int sys, cholmod_factor& L, cholmod_sparse& B, cholmod_common &Common) { return cholmod_l_spsolve (sys, &L, &B, &Common); } template -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 (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 (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 diff --git a/Eigen/src/Core/PlainObjectBase.h b/Eigen/src/Core/PlainObjectBase.h index 359135628..639fb92bf 100644 --- a/Eigen/src/Core/PlainObjectBase.h +++ b/Eigen/src/Core/PlainObjectBase.h @@ -41,7 +41,7 @@ template<> struct check_rows_cols_for_overflow { { // 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) diff --git a/Eigen/src/Core/arch/AltiVec/Complex.h b/Eigen/src/Core/arch/AltiVec/Complex.h index 59367ba29..67db2f8ee 100644 --- a/Eigen/src/Core/arch/AltiVec/Complex.h +++ b/Eigen/src/Core/arch/AltiVec/Complex.h @@ -65,7 +65,7 @@ template<> struct unpacket_traits { typedef std::complex type; template<> EIGEN_STRONG_INLINE Packet2cf pset1(const std::complex& from) { Packet2cf res; - if((ptrdiff_t(&from) % 16) == 0) + if((std::ptrdiff_t(&from) % 16) == 0) res.v = pload((const float *)&from); else res.v = ploadu((const float *)&from); diff --git a/Eigen/src/Core/arch/AltiVec/PacketMath.h b/Eigen/src/Core/arch/AltiVec/PacketMath.h index e7d4f4d8d..b3f1ea199 100755 --- a/Eigen/src/Core/arch/AltiVec/PacketMath.h +++ b/Eigen/src/Core/arch/AltiVec/PacketMath.h @@ -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,15 +450,15 @@ template<> EIGEN_STRONG_INLINE Packet4f ploadu(const float* from) template<> EIGEN_STRONG_INLINE Packet4f ploaddup(const float* from) { Packet4f p; - if((ptrdiff_t(from) % 16) == 0) p = pload(from); - else p = ploadu(from); + if((std::ptrdiff_t(from) % 16) == 0) p = pload(from); + else p = ploadu(from); return vec_perm(p, p, p16uc_DUPLICATE32_HI); } template<> EIGEN_STRONG_INLINE Packet4i ploaddup(const int* from) { Packet4i p; - if((ptrdiff_t(from) % 16) == 0) p = pload(from); - else p = ploadu(from); + if((std::ptrdiff_t(from) % 16) == 0) p = pload(from); + else p = ploadu(from); return vec_perm(p, p, p16uc_DUPLICATE32_HI); } @@ -935,8 +935,8 @@ template<> EIGEN_STRONG_INLINE Packet2d ploadu(const double* from) template<> EIGEN_STRONG_INLINE Packet2d ploaddup(const double* from) { Packet2d p; - if((ptrdiff_t(from) % 16) == 0) p = pload(from); - else p = ploadu(from); + if((std::ptrdiff_t(from) % 16) == 0) p = pload(from); + else p = ploadu(from); return vec_splat_dbl<0>(p); } diff --git a/Eigen/src/Core/arch/ZVector/PacketMath.h b/Eigen/src/Core/arch/ZVector/PacketMath.h index e2deb25c8..57b01fc63 100755 --- a/Eigen/src/Core/arch/ZVector/PacketMath.h +++ b/Eigen/src/Core/arch/ZVector/PacketMath.h @@ -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: diff --git a/Eigen/src/Core/util/Memory.h b/Eigen/src/Core/util/Memory.h index 67053db62..c634d7ea0 100644 --- a/Eigen/src/Core/util/Memory.h +++ b/Eigen/src/Core/util/Memory.h @@ -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 EIGEN_DEVICE_FUNC inline void* conditional_aligned_malloc(size_t size) +template 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(size_t size) +template<> EIGEN_DEVICE_FUNC inline void* conditional_aligned_malloc(std::size_t size) { check_that_malloc_is_allowed(); @@ -235,12 +235,12 @@ template<> EIGEN_DEVICE_FUNC inline void conditional_aligned_free(void *p std::free(ptr); } -template inline void* conditional_aligned_realloc(void* ptr, size_t new_size, size_t old_size) +template 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(void* ptr, size_t new_size, size_t) +template<> inline void* conditional_aligned_realloc(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(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 EIGEN_DEVICE_FUNC inline void destruct_elements_of_array(T *ptr, size_t size) +template 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 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 EIGEN_DEVICE_FUNC inline T* construct_elements_of_array(T *ptr, size_t size) +template 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 EIGEN_DEVICE_FUNC inline T* construct_elements_of_array(T * *****************************************************************************/ template -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 EIGEN_DEVICE_FUNC inline T* aligned_new(size_t size) +template EIGEN_DEVICE_FUNC inline T* aligned_new(std::size_t size) { check_size_for_overflow(size); T *result = reinterpret_cast(aligned_malloc(sizeof(T)*size)); @@ -309,7 +309,7 @@ template EIGEN_DEVICE_FUNC inline T* aligned_new(size_t size) return result; } -template EIGEN_DEVICE_FUNC inline T* conditional_aligned_new(size_t size) +template EIGEN_DEVICE_FUNC inline T* conditional_aligned_new(std::size_t size) { check_size_for_overflow(size); T *result = reinterpret_cast(conditional_aligned_malloc(sizeof(T)*size)); @@ -328,7 +328,7 @@ template 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 EIGEN_DEVICE_FUNC inline void aligned_delete(T *ptr, size_t size) +template EIGEN_DEVICE_FUNC inline void aligned_delete(T *ptr, std::size_t size) { destruct_elements_of_array(ptr, size); aligned_free(ptr); @@ -337,13 +337,13 @@ template 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 EIGEN_DEVICE_FUNC inline void conditional_aligned_delete(T *ptr, size_t size) +template EIGEN_DEVICE_FUNC inline void conditional_aligned_delete(T *ptr, std::size_t size) { destruct_elements_of_array(ptr, size); conditional_aligned_free(ptr); } -template EIGEN_DEVICE_FUNC inline T* conditional_aligned_realloc_new(T* pts, size_t new_size, size_t old_size) +template 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(new_size); check_size_for_overflow(old_size); @@ -366,7 +366,7 @@ template EIGEN_DEVICE_FUNC inline T* conditional_aligned } -template EIGEN_DEVICE_FUNC inline T* conditional_aligned_new_auto(size_t size) +template 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 EIGEN_DEVICE_FUNC inline T* conditional_aligned return result; } -template inline T* conditional_aligned_realloc_new_auto(T* pts, size_t new_size, size_t old_size) +template inline T* conditional_aligned_realloc_new_auto(T* pts, std::size_t new_size, std::size_t old_size) { check_size_for_overflow(new_size); check_size_for_overflow(old_size); @@ -409,7 +409,7 @@ template inline T* conditional_aligned_realloc_new_auto( return result; } -template EIGEN_DEVICE_FUNC inline void conditional_aligned_delete_auto(T *ptr, size_t size) +template EIGEN_DEVICE_FUNC inline void conditional_aligned_delete_auto(T *ptr, std::size_t size) { if(NumTraits::RequireInitialization) destruct_elements_of_array(ptr, size); @@ -561,7 +561,7 @@ template 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::RequireInitialization && m_ptr) @@ -576,7 +576,7 @@ template 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 void swap(scoped_array &a,scoped_array &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(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(size); \ } \ - void *operator new[](size_t size) { \ + void *operator new[](std::size_t size) { \ return Eigen::internal::conditional_aligned_malloc(size); \ } \ void operator delete(void * ptr) EIGEN_NO_THROW { Eigen::internal::conditional_aligned_free(ptr); } \ @@ -673,8 +673,8 @@ template void swap(scoped_array &a,scoped_array &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 aligned_allocator : public std::allocator { 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; diff --git a/Eigen/src/SparseCore/SparseMatrix.h b/Eigen/src/SparseCore/SparseMatrix.h index 529c7a0ac..323c2323b 100644 --- a/Eigen/src/SparseCore/SparseMatrix.h +++ b/Eigen/src/SparseCore/SparseMatrix.h @@ -1301,11 +1301,11 @@ EIGEN_DONT_INLINE typename SparseMatrix<_Scalar,_Options,_StorageIndex>::Scalar& // 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; diff --git a/Eigen/src/StlSupport/details.h b/Eigen/src/StlSupport/details.h index e42ec024f..2cfd13e03 100644 --- a/Eigen/src/StlSupport/details.h +++ b/Eigen/src/StlSupport/details.h @@ -22,13 +22,13 @@ namespace Eigen { class aligned_allocator_indirection : public EIGEN_ALIGNED_ALLOCATOR { public: - typedef size_t size_type; - typedef ptrdiff_t difference_type; - typedef T* pointer; - typedef const T* const_pointer; - typedef T& reference; - typedef const T& const_reference; - typedef T value_type; + typedef std::size_t size_type; + typedef std::ptrdiff_t difference_type; + typedef T* pointer; + typedef const T* const_pointer; + typedef T& reference; + typedef const T& const_reference; + typedef T value_type; template struct rebind -- cgit v1.2.3 From b0db4eff367017f8b273b7d407b3fe0e86808ed2 Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Mon, 23 Jan 2017 22:03:57 +0100 Subject: bug #1382: move using std::size_t/ptrdiff_t to Eigen's namespace (still better than the global namespace!) --- Eigen/Core | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Eigen/Core b/Eigen/Core index 1c709cad3..f85b22db7 100644 --- a/Eigen/Core +++ b/Eigen/Core @@ -337,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 -- cgit v1.2.3 From ba3f977946ed0ac5dde82a15a9c11784513155f2 Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Mon, 23 Jan 2017 22:06:08 +0100 Subject: bug #1376: add missing assertion on size mismatch with compound assignment operators (e.g., mat += mat.col(j)) --- Eigen/src/Core/AssignEvaluator.h | 25 +++++++++++++++++++++---- Eigen/src/Core/functors/AssignmentFunctors.h | 2 +- Eigen/src/SparseCore/SparseAssign.h | 5 +---- test/block.cpp | 8 ++++++++ test/diagonal.cpp | 17 +++++++++++++++++ test/sparse_basic.cpp | 10 +++++++++- 6 files changed, 57 insertions(+), 10 deletions(-) diff --git a/Eigen/src/Core/AssignEvaluator.h b/Eigen/src/Core/AssignEvaluator.h index 14400d246..7c7203ac6 100644 --- a/Eigen/src/Core/AssignEvaluator.h +++ b/Eigen/src/Core/AssignEvaluator.h @@ -701,6 +701,26 @@ protected: * Part 5 : Entry point for dense rectangular assignment ***************************************************************************/ +template +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 +EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE +void resize_if_allowed(DstXprType &dst, const SrcXprType& src, const internal::assign_op &/*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 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); diff --git a/Eigen/src/Core/functors/AssignmentFunctors.h b/Eigen/src/Core/functors/AssignmentFunctors.h index 9b373c783..4153b877c 100644 --- a/Eigen/src/Core/functors/AssignmentFunctors.h +++ b/Eigen/src/Core/functors/AssignmentFunctors.h @@ -28,7 +28,7 @@ template struct assign_op { { internal::pstoret(a,b); } }; -// Empty overload for void type (used by PermutationMatrix +// Empty overload for void type (used by PermutationMatrix) template struct assign_op {}; template diff --git a/Eigen/src/SparseCore/SparseAssign.h b/Eigen/src/SparseCore/SparseAssign.h index 83776645b..18352a847 100644 --- a/Eigen/src/SparseCore/SparseAssign.h +++ b/Eigen/src/SparseCore/SparseAssign.h @@ -143,10 +143,7 @@ struct Assignment dst.setZero(); internal::evaluator 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 dstEval(dst); const Index outerEvaluationSize = (internal::evaluator::Flags&RowMajorBit) ? src.rows() : src.cols(); diff --git a/test/block.cpp b/test/block.cpp index 1eeb2da27..39565af83 100644 --- a/test/block.cpp +++ b/test/block.cpp @@ -186,6 +186,14 @@ template 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(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() ); + } } diff --git a/test/diagonal.cpp b/test/diagonal.cpp index ee00cad55..c1546e97d 100644 --- a/test/diagonal.cpp +++ b/test/diagonal.cpp @@ -68,6 +68,21 @@ template void diagonal(const MatrixType& m) } } +template 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(1,EIGEN_TEST_MAX_SIZE), internal::random(1,EIGEN_TEST_MAX_SIZE))) ); CALL_SUBTEST_1( diagonal(Matrix(3, 4)) ); } + + CALL_SUBTEST_1( diagonal_assert(MatrixXf(internal::random(1,EIGEN_TEST_MAX_SIZE), internal::random(1,EIGEN_TEST_MAX_SIZE))) ); } diff --git a/test/sparse_basic.cpp b/test/sparse_basic.cpp index 271e55eba..208a66f12 100644 --- a/test/sparse_basic.cpp +++ b/test/sparse_basic.cpp @@ -214,6 +214,14 @@ template void sparse_basic(const SparseMatrixType& re 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) ); + } + // test aliasing VERIFY_IS_APPROX((m1 = -m1), (refM1 = -refM1)); VERIFY_IS_APPROX((m1 = m1.transpose()), (refM1 = refM1.transpose().eval())); @@ -428,7 +436,7 @@ template void sparse_basic(const SparseMatrixType& re m3 = m2.template triangularView(); VERIFY_IS_APPROX(m3, refMat3); - // check sparse-traingular to dense + // check sparse-triangular to dense refMat3 = m2.template triangularView(); VERIFY_IS_APPROX(refMat3, DenseMatrix(refMat2.template triangularView())); } -- cgit v1.2.3 From 156e6234f1921987ab63321dbea885b75e6ae70b Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Tue, 24 Jan 2017 09:16:40 +0100 Subject: bug #1375: fix cmake installation with cmake 2.8 --- CMakeLists.txt | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index b4555647c..fe4227cbb 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -542,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 @@ -552,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 @@ -582,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) -- cgit v1.2.3 From 41c523a0ab8432a3f3276abaeb8a869cccab6b93 Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Tue, 24 Jan 2017 09:39:49 +0100 Subject: Rename fix_t to FixedInt --- Eigen/src/Core/ArithmeticSequence.h | 18 ++++----- Eigen/src/Core/util/IndexedViewHelper.h | 4 +- Eigen/src/Core/util/IntegralConstant.h | 67 +++++++++++++++++---------------- Eigen/src/Core/util/SymbolicIndex.h | 34 ++++++++--------- 4 files changed, 63 insertions(+), 60 deletions(-) diff --git a/Eigen/src/Core/ArithmeticSequence.h b/Eigen/src/Core/ArithmeticSequence.h index 646eb5770..c5c8bb105 100644 --- a/Eigen/src/Core/ArithmeticSequence.h +++ b/Eigen/src/Core/ArithmeticSequence.h @@ -21,12 +21,12 @@ template<> struct aseq_negate { typedef Index type; }; -template struct aseq_negate > { - typedef fix_t<-N> type; +template struct aseq_negate > { + typedef FixedInt<-N> type; }; // Compilation error in the following case: -template<> struct aseq_negate > {}; +template<> struct aseq_negate > {}; template::value, @@ -38,7 +38,7 @@ struct aseq_reverse_first_type { template struct aseq_reverse_first_type { typedef Symbolic::AddExpr > >, + Symbolic::ProductExpr > >, Symbolic::ValueExpr > > type; }; @@ -50,7 +50,7 @@ struct aseq_reverse_first_type { template struct aseq_reverse_first_type { - typedef Symbolic::AddExpr > >, + typedef Symbolic::AddExpr > >, Symbolic::ValueExpr >, Symbolic::ValueExpr<> > type; }; @@ -67,7 +67,7 @@ template struct cleanup_seq_incr { // seq(first,last,incr) and seqN(first,size,incr) //-------------------------------------------------------------------------------- -template > +template > class ArithmeticSequence; template @@ -222,7 +222,7 @@ seq(FirstType f, LastType l) template typename internal::enable_if::value, ArithmeticSequence,Symbolic::ValueExpr<> >, - Symbolic::ValueExpr > > > >::type + Symbolic::ValueExpr > > > >::type seq(const Symbolic::BaseExpr &f, LastType l) { return seqN(f.derived(),(typename internal::cleanup_index_type::type(l)-f.derived()+fix<1>())); @@ -232,7 +232,7 @@ template typename internal::enable_if::value, ArithmeticSequence::type, Symbolic::AddExpr >, - Symbolic::ValueExpr > > > >::type + Symbolic::ValueExpr > > > >::type seq(FirstType f, const Symbolic::BaseExpr &l) { return seqN(typename internal::cleanup_index_type::type(f),(l.derived()-typename internal::cleanup_index_type::type(f)+fix<1>())); @@ -240,7 +240,7 @@ seq(FirstType f, const Symbolic::BaseExpr &l) template ArithmeticSequence >,Symbolic::ValueExpr > > > + Symbolic::AddExpr >,Symbolic::ValueExpr > > > seq(const Symbolic::BaseExpr &f, const Symbolic::BaseExpr &l) { return seqN(f.derived(),(l.derived()-f.derived()+fix<1>())); diff --git a/Eigen/src/Core/util/IndexedViewHelper.h b/Eigen/src/Core/util/IndexedViewHelper.h index 1171b2b2e..ab01c857f 100644 --- a/Eigen/src/Core/util/IndexedViewHelper.h +++ b/Eigen/src/Core/util/IndexedViewHelper.h @@ -60,7 +60,7 @@ 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::ValueExpr > > end(last+fix<1>()); +static const Symbolic::AddExpr,Symbolic::ValueExpr > > end(last+fix<1>()); #endif } // end namespace placeholders @@ -71,7 +71,7 @@ namespace internal { inline Index eval_expr_given_size(Index x, Index /* size */) { return x; } template -fix_t eval_expr_given_size(fix_t x, Index /*size*/) { return x; } +FixedInt eval_expr_given_size(FixedInt x, Index /*size*/) { return x; } template Index eval_expr_given_size(const Symbolic::BaseExpr &x, Index size) diff --git a/Eigen/src/Core/util/IntegralConstant.h b/Eigen/src/Core/util/IntegralConstant.h index 178e4893c..e81cc45f2 100644 --- a/Eigen/src/Core/util/IntegralConstant.h +++ b/Eigen/src/Core/util/IntegralConstant.h @@ -15,39 +15,42 @@ namespace Eigen { namespace internal { -template struct fix_t; -template class variable_or_fixed; +template class FixedInt; +template class VariableAndFixedInt; -template struct fix_t { +template class FixedInt +{ +public: static const int value = N; operator int() const { return value; } - fix_t() {} - fix_t(variable_or_fixed other) { + FixedInt() {} + FixedInt( VariableAndFixedInt other) { EIGEN_ONLY_USED_FOR_DEBUG(other); eigen_internal_assert(int(other)==N); } - fix_t<-N> operator-() const { return fix_t<-N>(); } + FixedInt<-N> operator-() const { return FixedInt<-N>(); } template - fix_t operator+(fix_t) const { return fix_t(); } + FixedInt operator+( FixedInt) const { return FixedInt(); } template - fix_t operator-(fix_t) const { return fix_t(); } + FixedInt operator-( FixedInt) const { return FixedInt(); } #if EIGEN_HAS_CXX14 // Needed in C++14 to allow fix(): - fix_t operator() () const { return *this; } + FixedInt operator() () const { return *this; } - variable_or_fixed operator() (int val) const { return variable_or_fixed(val); } + VariableAndFixedInt operator() (int val) const { return VariableAndFixedInt(val); } #else - fix_t (fix_t (*)() ) {} + FixedInt ( FixedInt (*)() ) {} #endif }; -template class variable_or_fixed { +template class VariableAndFixedInt +{ public: static const int value = N; operator int() const { return m_value; } - variable_or_fixed(int val) { m_value = val; } + VariableAndFixedInt(int val) { m_value = val; } protected: int m_value; }; @@ -56,17 +59,17 @@ template struct get_fixed_value { static const int value = Default; }; -template struct get_fixed_value,Default> { +template struct get_fixed_value,Default> { static const int value = N; }; #if !EIGEN_HAS_CXX14 -template struct get_fixed_value (*)(),Default> { +template struct get_fixed_value (*)(),Default> { static const int value = N; }; #endif -template struct get_fixed_value,Default> { +template struct get_fixed_value,Default> { static const int value = N ; }; @@ -77,10 +80,10 @@ struct get_fixed_value,Default> { template Index get_runtime_value(const T &x) { return x; } #if !EIGEN_HAS_CXX14 -template Index get_runtime_value(fix_t (*)()) { return N; } +template Index get_runtime_value(FixedInt (*)()) { return N; } #endif -// Cleanup integer/fix_t/variable_or_fixed/etc types: +// Cleanup integer/FixedInt/VariableAndFixedInt/etc types: // By default, no cleanup: template struct cleanup_index_type { typedef T type; }; @@ -89,14 +92,14 @@ template struct clea template struct cleanup_index_type::value>::type> { typedef Index type; }; #if !EIGEN_HAS_CXX14 -// In c++98/c++11, fix is a pointer to function that we better cleanup to a true fix_t: -template struct cleanup_index_type (*)(), DynamicKey> { typedef fix_t type; }; +// In c++98/c++11, fix is a pointer to function that we better cleanup to a true FixedInt: +template struct cleanup_index_type (*)(), DynamicKey> { typedef FixedInt type; }; #endif -// If variable_or_fixed does not match DynamicKey, then we turn it to a pure compile-time value: -template struct cleanup_index_type, DynamicKey> { typedef fix_t type; }; -// If variable_or_fixed matches DynamicKey, then we turn it to a pure runtime-value (aka Index): -template struct cleanup_index_type, DynamicKey> { typedef Index type; }; +// If VariableAndFixedInt does not match DynamicKey, then we turn it to a pure compile-time value: +template struct cleanup_index_type, DynamicKey> { typedef FixedInt type; }; +// If VariableAndFixedInt matches DynamicKey, then we turn it to a pure runtime-value (aka Index): +template struct cleanup_index_type, DynamicKey> { typedef Index type; }; } // end namespace internal @@ -104,15 +107,15 @@ template struct cleanup_index_type #if EIGEN_HAS_CXX14 template -static const internal::fix_t fix{}; +static const internal::FixedInt fix{}; #else template -inline internal::fix_t fix() { return internal::fix_t(); } +inline internal::FixedInt fix() { return internal::FixedInt(); } // The generic typename T is mandatory. Otherwise, a code like fix could refer to either the function above or this next overload. // This way a code like fix can only refer to the previous function. template -inline internal::variable_or_fixed fix(T val) { return internal::variable_or_fixed(val); } +inline internal::VariableAndFixedInt fix(T val) { return internal::VariableAndFixedInt(val); } #endif #else // EIGEN_PARSED_BY_DOXYGEN @@ -133,17 +136,17 @@ inline internal::variable_or_fixed fix(T val) { return internal::variable_or_ * * In c++14, it is implemented as: * \code - * template static const internal::fix_t fix{}; + * template static const internal::FixedInt fix{}; * \endcode - * where internal::fix_t is an internal template class similar to + * where internal::FixedInt is an internal template class similar to * \c std::integral_constant - * Here, \c fix is thus an object of type \c internal::fix_t. + * Here, \c fix is thus an object of type \c internal::FixedInt. * * In c++98/11, it is implemented as a function: * \code - * template inline internal::fix_t fix(); + * template inline internal::FixedInt fix(); * \endcode - * Here internal::fix_t is thus a pointer to function. + * Here internal::FixedInt is thus a pointer to function. * * If for some reason you want a true object in c++98 then you can write: \code fix() \endcode which is also valid in c++14. * diff --git a/Eigen/src/Core/util/SymbolicIndex.h b/Eigen/src/Core/util/SymbolicIndex.h index 62058760b..a52510f6a 100644 --- a/Eigen/src/Core/util/SymbolicIndex.h +++ b/Eigen/src/Core/util/SymbolicIndex.h @@ -61,7 +61,7 @@ protected: // Specialization for compile-time value, // It is similar to ValueExpr(N) but this version helps the compiler to generate better code. template -class ValueExpr > { +class ValueExpr > { public: ValueExpr() {} template @@ -114,30 +114,30 @@ public: { return QuotientExpr,Derived>(a,b.derived()); } template - AddExpr > > operator+(internal::fix_t) const - { return AddExpr > >(derived(), ValueExpr >()); } + AddExpr > > operator+(internal::FixedInt) const + { return AddExpr > >(derived(), ValueExpr >()); } template - AddExpr > > operator-(internal::fix_t) const - { return AddExpr > >(derived(), ValueExpr >()); } + AddExpr > > operator-(internal::FixedInt) const + { return AddExpr > >(derived(), ValueExpr >()); } template - ProductExpr > > operator*(internal::fix_t) const - { return ProductExpr > >(derived(),ValueExpr >()); } + ProductExpr > > operator*(internal::FixedInt) const + { return ProductExpr > >(derived(),ValueExpr >()); } template - QuotientExpr > > operator/(internal::fix_t) const - { return QuotientExpr > >(derived(),ValueExpr >()); } + QuotientExpr > > operator/(internal::FixedInt) const + { return QuotientExpr > >(derived(),ValueExpr >()); } template - friend AddExpr > > operator+(internal::fix_t, const BaseExpr& b) - { return AddExpr > >(b.derived(), ValueExpr >()); } + friend AddExpr > > operator+(internal::FixedInt, const BaseExpr& b) + { return AddExpr > >(b.derived(), ValueExpr >()); } template - friend AddExpr,ValueExpr > > operator-(internal::fix_t, const BaseExpr& b) - { return AddExpr,ValueExpr > >(-b.derived(), ValueExpr >()); } + friend AddExpr,ValueExpr > > operator-(internal::FixedInt, const BaseExpr& b) + { return AddExpr,ValueExpr > >(-b.derived(), ValueExpr >()); } template - friend ProductExpr >,Derived> operator*(internal::fix_t, const BaseExpr& b) - { return ProductExpr >,Derived>(ValueExpr >(),b.derived()); } + friend ProductExpr >,Derived> operator*(internal::FixedInt, const BaseExpr& b) + { return ProductExpr >,Derived>(ValueExpr >(),b.derived()); } template - friend QuotientExpr >,Derived> operator/(internal::fix_t, const BaseExpr& b) - { return QuotientExpr > ,Derived>(ValueExpr >(),b.derived()); } + friend QuotientExpr >,Derived> operator/(internal::FixedInt, const BaseExpr& b) + { return QuotientExpr > ,Derived>(ValueExpr >(),b.derived()); } template -- cgit v1.2.3 From bb52f74e6290cb0f84202866a27aa9c4c1ec9fc9 Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Tue, 24 Jan 2017 10:13:35 +0100 Subject: Add internal doc --- Eigen/src/Core/util/IntegralConstant.h | 59 ++++++++++++++++++++++++++++++++++ 1 file changed, 59 insertions(+) diff --git a/Eigen/src/Core/util/IntegralConstant.h b/Eigen/src/Core/util/IntegralConstant.h index e81cc45f2..b25601ed3 100644 --- a/Eigen/src/Core/util/IntegralConstant.h +++ b/Eigen/src/Core/util/IntegralConstant.h @@ -18,6 +18,36 @@ namespace internal { template class FixedInt; template class VariableAndFixedInt; +/** \internal + * \class FixedInt + * + * This class embeds a compile-time integer \c N. + * + * It is similar to c++11 std::integral_constant but with some additional features + * such as: + * - implicit conversion to int + * - arithmetic operators: -, +, * + * - c++98/14 compatibility with fix and fix() 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 or Eigen::fix(). In C++98-11, the former syntax does + * not create a FixedInt instance but rather a point to function that needs to be \em cleaned-up + * using the generic helper: + * \code + * internal::cleanup_index_type::type + * internal::cleanup_index_type::type + * \endcode + * where T can a FixedInt, a pointer to function FixedInt (*)(), 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::value + * \endcode + * that will give you \c N if T equals FixedInt or FixedInt (*)(), and \c DefaultVal if T does not embed any compile-time value (e.g., T==int). + * + * \sa fix, class VariableAndFixedInt + */ template class FixedInt { public: @@ -45,6 +75,35 @@ public: #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(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), or to a runtime quantity (e.g., an Index) + * using the following generic helper: + * \code + * internal::cleanup_index_type::type + * internal::cleanup_index_type::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::value + * \endcode + * that will give you \c N if T equals VariableAndFixedInt, and \c DefaultVal if T does not embed any compile-time value (e.g., T==int). + * + * \sa fix(int), class FixedInt + */ template class VariableAndFixedInt { public: -- cgit v1.2.3 From 228fef1b3ac3f635b5d7b7546a1c8bd0dd4c57be Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Tue, 24 Jan 2017 10:53:51 +0100 Subject: Extended the set of arithmetic operators supported by FixedInt (-,+,*,/,%,&,|) --- Eigen/src/Core/util/IntegralConstant.h | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/Eigen/src/Core/util/IntegralConstant.h b/Eigen/src/Core/util/IntegralConstant.h index b25601ed3..f7baf1060 100644 --- a/Eigen/src/Core/util/IntegralConstant.h +++ b/Eigen/src/Core/util/IntegralConstant.h @@ -26,7 +26,7 @@ template class VariableAndFixedInt; * It is similar to c++11 std::integral_constant but with some additional features * such as: * - implicit conversion to int - * - arithmetic operators: -, +, * + * - arithmetic and some bitwise operators: -, +, *, /, %, &, | * - c++98/14 compatibility with fix and fix() syntax to define integral constants. * * It is strongly discouraged to directly deal with this class FixedInt. Instances are expcected to @@ -64,6 +64,16 @@ public: FixedInt operator+( FixedInt) const { return FixedInt(); } template FixedInt operator-( FixedInt) const { return FixedInt(); } + template + FixedInt operator*( FixedInt) const { return FixedInt(); } + template + FixedInt operator/( FixedInt) const { return FixedInt(); } + template + FixedInt operator%( FixedInt) const { return FixedInt(); } + template + FixedInt operator|( FixedInt) const { return FixedInt(); } + template + FixedInt operator&( FixedInt) const { return FixedInt(); } #if EIGEN_HAS_CXX14 // Needed in C++14 to allow fix(): -- cgit v1.2.3 From ddd83f82d88592d12124040ad2c76c03013da62a Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Tue, 24 Jan 2017 10:54:42 +0100 Subject: Add support for "SymbolicExpr op fix" in C++98/11 mode. --- Eigen/src/Core/util/SymbolicIndex.h | 30 +++++++++++++++++++++++++++++- 1 file changed, 29 insertions(+), 1 deletion(-) diff --git a/Eigen/src/Core/util/SymbolicIndex.h b/Eigen/src/Core/util/SymbolicIndex.h index a52510f6a..f9a2e6311 100644 --- a/Eigen/src/Core/util/SymbolicIndex.h +++ b/Eigen/src/Core/util/SymbolicIndex.h @@ -117,7 +117,7 @@ public: AddExpr > > operator+(internal::FixedInt) const { return AddExpr > >(derived(), ValueExpr >()); } template - AddExpr > > operator-(internal::FixedInt) const + AddExpr > > operator-(internal::FixedInt) const { return AddExpr > >(derived(), ValueExpr >()); } template ProductExpr > > operator*(internal::FixedInt) const @@ -139,6 +139,34 @@ public: friend QuotientExpr >,Derived> operator/(internal::FixedInt, const BaseExpr& b) { return QuotientExpr > ,Derived>(ValueExpr >(),b.derived()); } +#if (!EIGEN_HAS_CXX14) + template + AddExpr > > operator+(internal::FixedInt (*)()) const + { return AddExpr > >(derived(), ValueExpr >()); } + template + AddExpr > > operator-(internal::FixedInt (*)()) const + { return AddExpr > >(derived(), ValueExpr >()); } + template + ProductExpr > > operator*(internal::FixedInt (*)()) const + { return ProductExpr > >(derived(),ValueExpr >()); } + template + QuotientExpr > > operator/(internal::FixedInt (*)()) const + { return QuotientExpr > >(derived(),ValueExpr >()); } + + template + friend AddExpr > > operator+(internal::FixedInt (*)(), const BaseExpr& b) + { return AddExpr > >(b.derived(), ValueExpr >()); } + template + friend AddExpr,ValueExpr > > operator-(internal::FixedInt (*)(), const BaseExpr& b) + { return AddExpr,ValueExpr > >(-b.derived(), ValueExpr >()); } + template + friend ProductExpr >,Derived> operator*(internal::FixedInt (*)(), const BaseExpr& b) + { return ProductExpr >,Derived>(ValueExpr >(),b.derived()); } + template + friend QuotientExpr >,Derived> operator/(internal::FixedInt (*)(), const BaseExpr& b) + { return QuotientExpr > ,Derived>(ValueExpr >(),b.derived()); } +#endif + template AddExpr operator+(const BaseExpr &b) const -- cgit v1.2.3 From 5783158e8f240418d33b0745b4276f9cc977be64 Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Tue, 24 Jan 2017 10:55:12 +0100 Subject: Add unit test for FixedInt and Symbolic --- test/CMakeLists.txt | 1 + test/symbolic_index.cpp | 94 +++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 95 insertions(+) create mode 100644 test/symbolic_index.cpp diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 921d9688c..84a21b3df 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -161,6 +161,7 @@ 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) diff --git a/test/symbolic_index.cpp b/test/symbolic_index.cpp new file mode 100644 index 000000000..83f105cb8 --- /dev/null +++ b/test/symbolic_index.cpp @@ -0,0 +1,94 @@ +// This file is part of Eigen, a lightweight C++ template library +// for linear algebra. +// +// Copyright (C) 2017 Gael Guennebaud +// +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.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 +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 internal::enable_if::value,bool>::type +is_same_fixed(const T1& a, const T2& b) +{ + return (Index(a) == Index(b)); +} + +template +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 internal::enable_if::value,bool>::type +is_same_type(const T1&, const T2&) +{ + return true; +} + +template +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 ); +} + +void test_symbolic_index() +{ + CALL_SUBTEST_1( check_symbolic_index() ); + CALL_SUBTEST_2( check_symbolic_index() ); +} -- cgit v1.2.3 From c43d254d1376c24c76df45bb274dda74ddfa2e19 Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Tue, 24 Jan 2017 11:36:43 +0100 Subject: Fix seq().reverse() in c++98 --- Eigen/src/Core/ArithmeticSequence.h | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/Eigen/src/Core/ArithmeticSequence.h b/Eigen/src/Core/ArithmeticSequence.h index c5c8bb105..6c10ecc02 100644 --- a/Eigen/src/Core/ArithmeticSequence.h +++ b/Eigen/src/Core/ArithmeticSequence.h @@ -43,9 +43,20 @@ struct aseq_reverse_first_type { > type; }; +template +struct aseq_reverse_first_type_aux { + typedef Index type; +}; + +template +struct aseq_reverse_first_type_aux::type> { + typedef FixedInt<(SizeType::value-1)*IncrType::value> type; +}; + template struct aseq_reverse_first_type { - typedef Symbolic::AddExpr > type; + typedef typename aseq_reverse_first_type_aux::type Aux; + typedef Symbolic::AddExpr > type; }; template -- cgit v1.2.3 From bc1020185407a324be81f613d88ce4b162f6774d Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Tue, 24 Jan 2017 16:27:51 +0100 Subject: Add test for multiple symbols --- Eigen/src/Core/util/SymbolicIndex.h | 2 +- test/symbolic_index.cpp | 10 ++++++++++ 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/Eigen/src/Core/util/SymbolicIndex.h b/Eigen/src/Core/util/SymbolicIndex.h index f9a2e6311..bb6349eb9 100644 --- a/Eigen/src/Core/util/SymbolicIndex.h +++ b/Eigen/src/Core/util/SymbolicIndex.h @@ -235,7 +235,7 @@ public: Index eval_impl(const SymbolValue &values) const { return values.value(); } -#if __cplusplus > 201103L +#if EIGEN_HAS_CXX14 // C++14 versions suitable for multiple symbols template Index eval_impl(const std::tuple& values) const { return std::get >(values).value(); } diff --git a/test/symbolic_index.cpp b/test/symbolic_index.cpp index 83f105cb8..1db85144b 100644 --- a/test/symbolic_index.cpp +++ b/test/symbolic_index.cpp @@ -85,6 +85,16 @@ void check_symbolic_index() 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; + struct y_tag {}; static const Symbolic::SymbolExpr y; + struct z_tag {}; static const Symbolic::SymbolExpr 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() -- cgit v1.2.3 From d83db761a2b9cedcb25519b3e556b5e495adc115 Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Tue, 24 Jan 2017 16:28:12 +0100 Subject: Add support for std::integral_constant --- Eigen/src/Core/ArithmeticSequence.h | 24 +++++++++++++++--------- Eigen/src/Core/util/IntegralConstant.h | 8 ++++++++ test/indexed_view.cpp | 9 +++++++++ 3 files changed, 32 insertions(+), 9 deletions(-) diff --git a/Eigen/src/Core/ArithmeticSequence.h b/Eigen/src/Core/ArithmeticSequence.h index 6c10ecc02..99b954432 100644 --- a/Eigen/src/Core/ArithmeticSequence.h +++ b/Eigen/src/Core/ArithmeticSequence.h @@ -202,22 +202,28 @@ auto seq(FirstType f, LastType l); #if EIGEN_HAS_CXX11 template -auto seq(FirstType f, LastType l) -> decltype(seqN(f,( typename internal::cleanup_index_type::type(l) - - typename internal::cleanup_index_type::type(f)+fix<1>()))) +auto seq(FirstType f, LastType l) -> decltype(seqN(typename internal::cleanup_index_type::type(f), + ( typename internal::cleanup_index_type::type(l) + - typename internal::cleanup_index_type::type(f)+fix<1>()))) { - return seqN(f,(typename internal::cleanup_index_type::type(l) - -typename internal::cleanup_index_type::type(f)+fix<1>())); + return seqN(typename internal::cleanup_index_type::type(f), + (typename internal::cleanup_index_type::type(l) + -typename internal::cleanup_index_type::type(f)+fix<1>())); } template auto seq(FirstType f, LastType l, IncrType incr) - -> decltype(seqN(f, ( typename internal::cleanup_index_type::type(l) - - typename internal::cleanup_index_type::type(f)+typename internal::cleanup_seq_incr::type(incr)) - / typename internal::cleanup_seq_incr::type(incr),typename internal::cleanup_seq_incr::type(incr))) + -> decltype(seqN(typename internal::cleanup_index_type::type(f), + ( typename internal::cleanup_index_type::type(l) + - typename internal::cleanup_index_type::type(f)+typename internal::cleanup_seq_incr::type(incr) + ) / typename internal::cleanup_seq_incr::type(incr), + typename internal::cleanup_seq_incr::type(incr))) { typedef typename internal::cleanup_seq_incr::type CleanedIncrType; - return seqN(f,(typename internal::cleanup_index_type::type(l) - -typename internal::cleanup_index_type::type(f)+CleanedIncrType(incr)) / CleanedIncrType(incr),CleanedIncrType(incr)); + return seqN(typename internal::cleanup_index_type::type(f), + ( typename internal::cleanup_index_type::type(l) + -typename internal::cleanup_index_type::type(f)+CleanedIncrType(incr)) / CleanedIncrType(incr), + CleanedIncrType(incr)); } #else diff --git a/Eigen/src/Core/util/IntegralConstant.h b/Eigen/src/Core/util/IntegralConstant.h index f7baf1060..ae41015bd 100644 --- a/Eigen/src/Core/util/IntegralConstant.h +++ b/Eigen/src/Core/util/IntegralConstant.h @@ -83,6 +83,10 @@ public: #else FixedInt ( FixedInt (*)() ) {} #endif + +#if EIGEN_HAS_CXX11 + FixedInt(std::integral_constant) {} +#endif }; /** \internal @@ -170,6 +174,10 @@ template struct cleanup_index_type // If VariableAndFixedInt matches DynamicKey, then we turn it to a pure runtime-value (aka Index): template struct cleanup_index_type, DynamicKey> { typedef Index type; }; +#if EIGEN_HAS_CXX11 +template struct cleanup_index_type, DynamicKey> { typedef FixedInt type; }; +#endif + } // end namespace internal #ifndef EIGEN_PARSED_BY_DOXYGEN diff --git a/test/indexed_view.cpp b/test/indexed_view.cpp index e70a9c616..8fa1c16f4 100644 --- a/test/indexed_view.cpp +++ b/test/indexed_view.cpp @@ -204,6 +204,15 @@ void check_indexed_view() 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(),std::integral_constant()), seqN(2,fix<5>,fix<-2>()) ) ); + VERIFY( is_same_seq( seq(std::integral_constant(),std::integral_constant(),std::integral_constant()), + seq(fix<1>,fix<5>,fix<2>()) ) ); + VERIFY( is_same_seq_type( seqN(2,std::integral_constant(),std::integral_constant()), seqN(2,fix<5>,fix<-2>()) ) ); + VERIFY( is_same_seq_type( seq(std::integral_constant(),std::integral_constant(),std::integral_constant()), + seq(fix<1>,fix<5>,fix<2>()) ) ); + + VERIFY( is_same_seq_type( seqN(2,std::integral_constant()), seqN(2,fix<5>) ) ); + VERIFY( is_same_seq_type( seq(std::integral_constant(),std::integral_constant()), 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>) ) ); -- cgit v1.2.3 From 5e144bbaa454eb2af7f6751376051fe16d143276 Mon Sep 17 00:00:00 2001 From: Rasmus Munk Larsen Date: Tue, 24 Jan 2017 13:32:50 -0800 Subject: Make NaN propagatation consistent between the pmax/pmin and std::max/std::min. This makes the NaN propagation consistent between the scalar and vectorized code paths of Eigen's scalar_max_op and scalar_min_op. See #1373 for details. --- Eigen/src/Core/MathFunctionsImpl.h | 7 +--- Eigen/src/Core/arch/AVX/PacketMath.h | 24 +++++++++---- Eigen/src/Core/arch/SSE/PacketMath.h | 66 ++++++++++++++++++++++++++++++---- unsupported/test/cxx11_tensor_expr.cpp | 46 ++++++++++++++++++++++++ 4 files changed, 123 insertions(+), 20 deletions(-) diff --git a/Eigen/src/Core/MathFunctionsImpl.h b/Eigen/src/Core/MathFunctionsImpl.h index 3c9ef22fa..cdbd14e8c 100644 --- a/Eigen/src/Core/MathFunctionsImpl.h +++ b/Eigen/src/Core/MathFunctionsImpl.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(9.f); const T minus_9 = pset1(-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(4.89352455891786e-03f); const T alpha_3 = pset1(6.37261928875436e-04f); diff --git a/Eigen/src/Core/arch/AVX/PacketMath.h b/Eigen/src/Core/arch/AVX/PacketMath.h index 195d40fb4..20d067c6a 100644 --- a/Eigen/src/Core/arch/AVX/PacketMath.h +++ b/Eigen/src/Core/arch/AVX/PacketMath.h @@ -183,12 +183,22 @@ template<> EIGEN_STRONG_INLINE Packet4d pmadd(const Packet4d& a, const Packet4d& } #endif -template<> EIGEN_STRONG_INLINE Packet8f pmin(const Packet8f& a, const Packet8f& b) { return _mm256_min_ps(a,b); } -template<> EIGEN_STRONG_INLINE Packet4d pmin(const Packet4d& a, const Packet4d& b) { return _mm256_min_pd(a,b); } - -template<> EIGEN_STRONG_INLINE Packet8f pmax(const Packet8f& a, const Packet8f& b) { return _mm256_max_ps(a,b); } -template<> EIGEN_STRONG_INLINE Packet4d pmax(const Packet4d& a, const Packet4d& b) { return _mm256_max_pd(a,b); } - +template<> EIGEN_STRONG_INLINE Packet8f pmin(const Packet8f& a, const Packet8f& b) { + // Arguments are swapped to match NaN propagation behavior of std::min. + return _mm256_min_ps(a,b); +} +template<> EIGEN_STRONG_INLINE Packet4d pmin(const Packet4d& a, const Packet4d& b) { + // Arguments are swapped to match NaN propagation behavior of std::min. + return _mm256_min_pd(a,b); +} +template<> EIGEN_STRONG_INLINE Packet8f pmax(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(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(const Packet8f& a) { return _mm256_round_ps(a, _MM_FROUND_CUR_DIRECTION); } template<> EIGEN_STRONG_INLINE Packet4d pround(const Packet4d& a) { return _mm256_round_pd(a, _MM_FROUND_CUR_DIRECTION); } @@ -225,7 +235,7 @@ template<> EIGEN_STRONG_INLINE Packet8f ploaddup(const float* from) // Packet8f tmp = _mm256_castps128_ps256(_mm_loadu_ps(from)); // tmp = _mm256_insertf128_ps(tmp, _mm_movehl_ps(_mm256_castps256_ps128(tmp),_mm256_castps256_ps128(tmp)), 1); // return _mm256_unpacklo_ps(tmp,tmp); - + // _mm256_insertf128_ps is very slow on Haswell, thus: Packet8f tmp = _mm256_broadcast_ps((const __m128*)(const void*)from); // mimic an "inplace" permutation of the lower 128bits using a blend diff --git a/Eigen/src/Core/arch/SSE/PacketMath.h b/Eigen/src/Core/arch/SSE/PacketMath.h index 3832de147..03c8a2c13 100755 --- a/Eigen/src/Core/arch/SSE/PacketMath.h +++ b/Eigen/src/Core/arch/SSE/PacketMath.h @@ -45,7 +45,7 @@ struct eigen_packet_wrapper m_val = v; return *this; } - + T m_val; }; typedef eigen_packet_wrapper<__m128> Packet4f; @@ -69,7 +69,7 @@ template<> struct is_arithmetic<__m128d> { enum { value = true }; }; #define vec2d_swizzle1(v,p,q) \ (_mm_castsi128_pd(_mm_shuffle_epi32( _mm_castpd_si128(v), ((q*2+1)<<6|(q*2)<<4|(p*2+1)<<2|(p*2))))) - + #define vec4f_swizzle2(a,b,p,q,r,s) \ (_mm_shuffle_ps( (a), (b), ((s)<<6|(r)<<4|(q)<<2|(p)))) @@ -190,7 +190,7 @@ template<> EIGEN_STRONG_INLINE Packet4f pload1(const float *from) { return vec4f_swizzle1(_mm_load_ss(from),0,0,0,0); } #endif - + template<> EIGEN_STRONG_INLINE Packet4f plset(const float& a) { return _mm_add_ps(pset1(a), _mm_set_ps(3,2,1,0)); } template<> EIGEN_STRONG_INLINE Packet2d plset(const double& a) { return _mm_add_pd(pset1(a),_mm_set_pd(1,0)); } template<> EIGEN_STRONG_INLINE Packet4i plset(const int& a) { return _mm_add_epi32(pset1(a),_mm_set_epi32(3,2,1,0)); } @@ -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(const Packet4f& a, const Packet4f& b) { return _mm_min_ps(a,b); } -template<> EIGEN_STRONG_INLINE Packet2d pmin(const Packet2d& a, const Packet2d& b) { return _mm_min_pd(a,b); } +template<> EIGEN_STRONG_INLINE Packet4f pmin(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(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(const Packet4i& a, const Packet4i& b) { #ifdef EIGEN_VECTORIZE_SSE4_1 @@ -263,8 +289,34 @@ template<> EIGEN_STRONG_INLINE Packet4i pmin(const Packet4i& a, const #endif } -template<> EIGEN_STRONG_INLINE Packet4f pmax(const Packet4f& a, const Packet4f& b) { return _mm_max_ps(a,b); } -template<> EIGEN_STRONG_INLINE Packet2d pmax(const Packet2d& a, const Packet2d& b) { return _mm_max_pd(a,b); } +template<> EIGEN_STRONG_INLINE Packet4f pmax(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(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(const Packet4i& a, const Packet4i& b) { #ifdef EIGEN_VECTORIZE_SSE4_1 diff --git a/unsupported/test/cxx11_tensor_expr.cpp b/unsupported/test/cxx11_tensor_expr.cpp index 77e24cb67..129b4e659 100644 --- a/unsupported/test/cxx11_tensor_expr.cpp +++ b/unsupported/test/cxx11_tensor_expr.cpp @@ -300,6 +300,51 @@ static void test_select() } } +template +void test_minmax_nan_propagation_templ() { + for (int size = 1; size < 17; ++size) { + const Scalar kNan = std::numeric_limits::quiet_NaN(); + Tensor vec_nan(size); + Tensor vec_zero(size); + Tensor 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(); + test_minmax_nan_propagation_templ(); +} 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()); } -- cgit v1.2.3 From 7b6aaa34404e069678c6e3337e690608a4eaa99d Mon Sep 17 00:00:00 2001 From: Rasmus Munk Larsen Date: Tue, 24 Jan 2017 13:37:08 -0800 Subject: Fix NaN propagation for AVX512. --- Eigen/src/Core/arch/AVX512/PacketMath.h | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/Eigen/src/Core/arch/AVX512/PacketMath.h b/Eigen/src/Core/arch/AVX512/PacketMath.h index e46a60472..12b897572 100644 --- a/Eigen/src/Core/arch/AVX512/PacketMath.h +++ b/Eigen/src/Core/arch/AVX512/PacketMath.h @@ -230,23 +230,27 @@ EIGEN_STRONG_INLINE Packet8d pmadd(const Packet8d& a, const Packet8d& b, template <> EIGEN_STRONG_INLINE Packet16f pmin(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(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(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(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 <> -- cgit v1.2.3 From e6b10202218631be755f19c41fe01287b9a37f90 Mon Sep 17 00:00:00 2001 From: Rasmus Munk Larsen Date: Tue, 24 Jan 2017 13:55:18 -0800 Subject: Adds a fast memcpy function to Eigen. This takes advantage of the following: 1. For small fixed sizes, the compiler generates inline code for memcpy, which is much faster. 2. My colleague eriche at googl dot com discovered that for large sizes, memmove is significantly faster than memcpy (at least on Linux with GCC or Clang). See benchmark numbers measured on a Haswell (HP Z440) workstation here: https://docs.google.com/a/google.com/spreadsheets/d/1jLs5bKzXwhpTySw65MhG1pZpsIwkszZqQTjwrd_n0ic/pubhtml This is of course surprising since memcpy is a less constrained version of memmove. This stackoverflow thread contains some speculation as to the causes: http://stackoverflow.com/questions/22793669/poor-memcpy-performance-on-linux Below are numbers for copying and slicing tensors using the multithreaded TensorDevice. The numbers show significant improvements for memcpy of very small blocks and for memcpy of large blocks single threaded (we were already able to saturate memory bandwidth for >1 threads before on large blocks). The "slicingSmallPieces" benchmark also shows small consistent improvements, since memcpy cost is a fair portion of that particular computation. The benchmarks operate on NxN matrices, and the names are of the form BM_$OP_${NUMTHREADS}T/${N}. Measured improvements in wall clock time: Run on rmlarsen3.mtv (12 X 3501 MHz CPUs); 2017-01-20T11:26:31.493023454-08:00 CPU: Intel Haswell with HyperThreading (6 cores) dL1:32KB dL2:256KB dL3:15MB Benchmark Base (ns) New (ns) Improvement ------------------------------------------------------------------ BM_memcpy_1T/2 3.48 2.39 +31.3% BM_memcpy_1T/8 12.3 6.51 +47.0% BM_memcpy_1T/64 371 383 -3.2% BM_memcpy_1T/512 66922 66720 +0.3% BM_memcpy_1T/4k 9892867 6849682 +30.8% BM_memcpy_1T/5k 14951099 10332856 +30.9% BM_memcpy_2T/2 3.50 2.46 +29.7% BM_memcpy_2T/8 12.3 7.66 +37.7% BM_memcpy_2T/64 371 376 -1.3% BM_memcpy_2T/512 66652 66788 -0.2% BM_memcpy_2T/4k 6145012 6117776 +0.4% BM_memcpy_2T/5k 9181478 9010942 +1.9% BM_memcpy_4T/2 3.47 2.47 +31.0% BM_memcpy_4T/8 12.3 6.67 +45.8 BM_memcpy_4T/64 374 376 -0.5% BM_memcpy_4T/512 67833 68019 -0.3% BM_memcpy_4T/4k 5057425 5188253 -2.6% BM_memcpy_4T/5k 7555638 7779468 -3.0% BM_memcpy_6T/2 3.51 2.50 +28.8% BM_memcpy_6T/8 12.3 7.61 +38.1% BM_memcpy_6T/64 373 378 -1.3% BM_memcpy_6T/512 66871 66774 +0.1% BM_memcpy_6T/4k 5112975 5233502 -2.4% BM_memcpy_6T/5k 7614180 7772246 -2.1% BM_memcpy_8T/2 3.47 2.41 +30.5% BM_memcpy_8T/8 12.4 10.5 +15.3% BM_memcpy_8T/64 372 388 -4.3% BM_memcpy_8T/512 67373 66588 +1.2% BM_memcpy_8T/4k 5148462 5254897 -2.1% BM_memcpy_8T/5k 7660989 7799058 -1.8% BM_memcpy_12T/2 3.50 2.40 +31.4% BM_memcpy_12T/8 12.4 7.55 +39.1 BM_memcpy_12T/64 374 378 -1.1% BM_memcpy_12T/512 67132 66683 +0.7% BM_memcpy_12T/4k 5185125 5292920 -2.1% BM_memcpy_12T/5k 7717284 7942684 -2.9% BM_slicingSmallPieces_1T/2 47.3 47.5 +0.4% BM_slicingSmallPieces_1T/8 53.6 52.3 +2.4% BM_slicingSmallPieces_1T/64 491 476 +3.1% BM_slicingSmallPieces_1T/512 21734 18814 +13.4% BM_slicingSmallPieces_1T/4k 394660 396760 -0.5% BM_slicingSmallPieces_1T/5k 218722 209244 +4.3% BM_slicingSmallPieces_2T/2 80.7 79.9 +1.0% BM_slicingSmallPieces_2T/8 54.2 53.1 +2.0 BM_slicingSmallPieces_2T/64 497 477 +4.0% BM_slicingSmallPieces_2T/512 21732 18822 +13.4% BM_slicingSmallPieces_2T/4k 392885 390490 +0.6% BM_slicingSmallPieces_2T/5k 221988 208678 +6.0% BM_slicingSmallPieces_4T/2 80.8 80.1 +0.9% BM_slicingSmallPieces_4T/8 54.1 53.2 +1.7% BM_slicingSmallPieces_4T/64 493 476 +3.4% BM_slicingSmallPieces_4T/512 21702 18758 +13.6% BM_slicingSmallPieces_4T/4k 393962 404023 -2.6% BM_slicingSmallPieces_4T/5k 249667 211732 +15.2% BM_slicingSmallPieces_6T/2 80.5 80.1 +0.5% BM_slicingSmallPieces_6T/8 54.4 53.4 +1.8% BM_slicingSmallPieces_6T/64 488 478 +2.0% BM_slicingSmallPieces_6T/512 21719 18841 +13.3% BM_slicingSmallPieces_6T/4k 394950 397583 -0.7% BM_slicingSmallPieces_6T/5k 223080 210148 +5.8% BM_slicingSmallPieces_8T/2 81.2 80.4 +1.0% BM_slicingSmallPieces_8T/8 58.1 53.5 +7.9% BM_slicingSmallPieces_8T/64 489 480 +1.8% BM_slicingSmallPieces_8T/512 21586 18798 +12.9% BM_slicingSmallPieces_8T/4k 394592 400165 -1.4% BM_slicingSmallPieces_8T/5k 219688 208301 +5.2% BM_slicingSmallPieces_12T/2 80.2 79.8 +0.7% BM_slicingSmallPieces_12T/8 54.4 53.4 +1.8 BM_slicingSmallPieces_12T/64 488 476 +2.5% BM_slicingSmallPieces_12T/512 21931 18831 +14.1% BM_slicingSmallPieces_12T/4k 393962 396541 -0.7% BM_slicingSmallPieces_12T/5k 218803 207965 +5.0% --- Eigen/src/Core/util/Memory.h | 61 +++++++++++++++++----- .../Eigen/CXX11/src/Tensor/TensorContraction.h | 2 +- .../Eigen/CXX11/src/Tensor/TensorDeviceDefault.h | 2 +- .../CXX11/src/Tensor/TensorDeviceThreadPool.h | 2 +- unsupported/Eigen/CXX11/src/Tensor/TensorFFT.h | 4 +- 5 files changed, 53 insertions(+), 18 deletions(-) diff --git a/Eigen/src/Core/util/Memory.h b/Eigen/src/Core/util/Memory.h index c634d7ea0..6b8e307c8 100644 --- a/Eigen/src/Core/util/Memory.h +++ b/Eigen/src/Core/util/Memory.h @@ -63,7 +63,7 @@ namespace Eigen { namespace internal { -EIGEN_DEVICE_FUNC +EIGEN_DEVICE_FUNC inline void throw_std_bad_alloc() { #ifdef EIGEN_EXCEPTIONS @@ -74,6 +74,41 @@ inline void throw_std_bad_alloc() #endif } +EIGEN_DEVICE_FUNC +inline void fast_memcpy(void* dst, const void* src, size_t size) { +#if defined(__CUDA__) || defined(__ANDROID__) + ::memcpy(dst, src, size); +#else + switch(size) { + // Most compilers will generate inline code for fixed sizes, + // which is significantly faster for small copies. + case 1: memcpy(dst, src, 1); break; + case 2: memcpy(dst, src, 2); break; + case 3: memcpy(dst, src, 3); break; + case 4: memcpy(dst, src, 4); break; + case 5: memcpy(dst, src, 5); break; + case 6: memcpy(dst, src, 6); break; + case 7: memcpy(dst, src, 7); break; + case 8: memcpy(dst, src, 8); break; + case 9: memcpy(dst, src, 9); break; + case 10: memcpy(dst, src, 10); break; + case 11: memcpy(dst, src, 11); break; + case 12: memcpy(dst, src, 12); break; + case 13: memcpy(dst, src, 13); break; + case 14: memcpy(dst, src, 14); break; + case 15: memcpy(dst, src, 15); break; + case 16: memcpy(dst, src, 16); break; +#ifdef EIGEN_OS_LINUX + // On Linux, memmove appears to be faster than memcpy for + // large sizes, strangely enough. + default: memmove(dst, src, size); break; +#else + default: memcpy(dst, src, size); break; +#endif + } +#endif +} + /***************************************************************************** *** Implementation of handmade aligned functions *** *****************************************************************************/ @@ -114,7 +149,7 @@ inline void* handmade_aligned_realloc(void* ptr, std::size_t size, std::size_t = void *previous_aligned = static_cast(original)+previous_offset; if(aligned!=previous_aligned) std::memmove(aligned, previous_aligned, size); - + *(reinterpret_cast(aligned) - 1) = original; return aligned; } @@ -142,7 +177,7 @@ EIGEN_DEVICE_FUNC inline void check_that_malloc_is_allowed() { eigen_assert(is_malloc_allowed() && "heap allocation is forbidden (EIGEN_RUNTIME_NO_MALLOC is defined and g_is_malloc_allowed is false)"); } -#else +#else EIGEN_DEVICE_FUNC inline void check_that_malloc_is_allowed() {} #endif @@ -471,8 +506,8 @@ EIGEN_DEVICE_FUNC inline Index first_default_aligned(const Scalar* array, Index } /** \internal Returns the smallest integer multiple of \a base and greater or equal to \a size - */ -template + */ +template inline Index first_multiple(Index size, Index base) { return ((size+base-1)/base)*base; @@ -502,7 +537,7 @@ template struct smart_copy_helper { { std::copy(start, end, target); } }; -// intelligent memmove. falls back to std::memmove for POD types, uses std::copy otherwise. +// intelligent memmove. falls back to std::memmove for POD types, uses std::copy otherwise. template struct smart_memmove_helper; template void smart_memmove(const T* start, const T* end, T* target) @@ -522,15 +557,15 @@ template struct smart_memmove_helper { template struct smart_memmove_helper { static inline void run(const T* start, const T* end, T* target) - { + { if (UIntPtr(target) < UIntPtr(start)) { std::copy(start, end, target); } - else + else { std::ptrdiff_t count = (std::ptrdiff_t(end)-std::ptrdiff_t(start)) / sizeof(T); - std::copy_backward(start, end, target + count); + std::copy_backward(start, end, target + count); } } }; @@ -603,7 +638,7 @@ template void swap(scoped_array &a,scoped_array &b) { std::swap(a.ptr(),b.ptr()); } - + } // end namespace internal /** \internal @@ -622,7 +657,7 @@ template void swap(scoped_array &a,scoped_array &b) * The underlying stack allocation function can controlled with the EIGEN_ALLOCA preprocessor token. */ #ifdef EIGEN_ALLOCA - + #if EIGEN_DEFAULT_ALIGN_BYTES>0 // We always manually re-align the result of EIGEN_ALLOCA. // If alloca is already aligned, the compiler should be smart enough to optimize away the re-alignment. @@ -645,7 +680,7 @@ template void swap(scoped_array &a,scoped_array &b) Eigen::internal::check_size_for_overflow(SIZE); \ TYPE* NAME = (BUFFER)!=0 ? BUFFER : reinterpret_cast(Eigen::internal::aligned_malloc(sizeof(TYPE)*SIZE)); \ Eigen::internal::aligned_stack_memory_handler EIGEN_CAT(NAME,_stack_memory_destructor)((BUFFER)==0 ? NAME : 0,SIZE,true) - + #endif @@ -701,7 +736,7 @@ template void swap(scoped_array &a,scoped_array &b) * Example: * \code * // Matrix4f requires 16 bytes alignment: -* std::map< int, Matrix4f, std::less, +* std::map< int, Matrix4f, std::less, * aligned_allocator > > my_map_mat4; * // Vector3f does not require 16 bytes alignment, no need to use Eigen's allocator: * std::map< int, Vector3f > my_map_vec3; diff --git a/unsupported/Eigen/CXX11/src/Tensor/TensorContraction.h b/unsupported/Eigen/CXX11/src/Tensor/TensorContraction.h index 442c14fac..39012b937 100644 --- a/unsupported/Eigen/CXX11/src/Tensor/TensorContraction.h +++ b/unsupported/Eigen/CXX11/src/Tensor/TensorContraction.h @@ -56,7 +56,7 @@ void pack_simple(Scalar * dst, const Scalar * src, Index cols, Index rows, Index } else { // Naive memcpy calls for (Index col = 0; col < cols; ++col) { - memcpy(dst + col*lddst, src + col*ldsrc, rows*sizeof(Scalar)); + internal::fast_memcpy(dst + col*lddst, src + col*ldsrc, rows*sizeof(Scalar)); } } } diff --git a/unsupported/Eigen/CXX11/src/Tensor/TensorDeviceDefault.h b/unsupported/Eigen/CXX11/src/Tensor/TensorDeviceDefault.h index ccaaa6cb2..b133781ae 100644 --- a/unsupported/Eigen/CXX11/src/Tensor/TensorDeviceDefault.h +++ b/unsupported/Eigen/CXX11/src/Tensor/TensorDeviceDefault.h @@ -22,7 +22,7 @@ struct DefaultDevice { internal::aligned_free(buffer); } EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void memcpy(void* dst, const void* src, size_t n) const { - ::memcpy(dst, src, n); + internal::fast_memcpy(dst, src, n); } EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void memcpyHostToDevice(void* dst, const void* src, size_t n) const { memcpy(dst, src, n); diff --git a/unsupported/Eigen/CXX11/src/Tensor/TensorDeviceThreadPool.h b/unsupported/Eigen/CXX11/src/Tensor/TensorDeviceThreadPool.h index 16180ca69..facdea735 100644 --- a/unsupported/Eigen/CXX11/src/Tensor/TensorDeviceThreadPool.h +++ b/unsupported/Eigen/CXX11/src/Tensor/TensorDeviceThreadPool.h @@ -106,7 +106,7 @@ struct ThreadPoolDevice { } EIGEN_STRONG_INLINE void memcpy(void* dst, const void* src, size_t n) const { - ::memcpy(dst, src, n); + internal::fast_memcpy(dst, src, n); } EIGEN_STRONG_INLINE void memcpyHostToDevice(void* dst, const void* src, size_t n) const { memcpy(dst, src, n); diff --git a/unsupported/Eigen/CXX11/src/Tensor/TensorFFT.h b/unsupported/Eigen/CXX11/src/Tensor/TensorFFT.h index 08eb5595a..f060191ab 100644 --- a/unsupported/Eigen/CXX11/src/Tensor/TensorFFT.h +++ b/unsupported/Eigen/CXX11/src/Tensor/TensorFFT.h @@ -253,7 +253,7 @@ struct TensorEvaluator, 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, 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); -- cgit v1.2.3 From 3be5ee2352423427c95b133ed749f4d9316fe135 Mon Sep 17 00:00:00 2001 From: Rasmus Munk Larsen Date: Tue, 24 Jan 2017 14:22:49 -0800 Subject: Update copy helper to use fast_memcpy. --- Eigen/src/Core/util/Memory.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Eigen/src/Core/util/Memory.h b/Eigen/src/Core/util/Memory.h index 6b8e307c8..572b1fe69 100644 --- a/Eigen/src/Core/util/Memory.h +++ b/Eigen/src/Core/util/Memory.h @@ -528,7 +528,7 @@ template struct smart_copy_helper { IntPtr size = IntPtr(end)-IntPtr(start); if(size==0) return; eigen_internal_assert(start!=0 && end!=0 && target!=0); - memcpy(target, start, size); + fast_memcpy(target, start, size); } }; -- cgit v1.2.3 From ae3e43a12575faf59e83a3303509f5924ee6069a Mon Sep 17 00:00:00 2001 From: Rasmus Munk Larsen Date: Tue, 24 Jan 2017 16:16:39 -0800 Subject: Remove extra space. --- Eigen/src/Core/MathFunctionsImpl.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Eigen/src/Core/MathFunctionsImpl.h b/Eigen/src/Core/MathFunctionsImpl.h index cdbd14e8c..ae1386b4c 100644 --- a/Eigen/src/Core/MathFunctionsImpl.h +++ b/Eigen/src/Core/MathFunctionsImpl.h @@ -29,7 +29,7 @@ T generic_fast_tanh_float(const T& a_x) // this range is +/-1.0f in single-precision. const T plus_9 = pset1(9.f); const T minus_9 = pset1(-9.f); - const T x = pmax(pmin(a_x, plus_9), minus_9); + const T x = pmax(pmin(a_x, plus_9), minus_9); // The monomial coefficients of the numerator polynomial (odd). const T alpha_1 = pset1(4.89352455891786e-03f); const T alpha_3 = pset1(6.37261928875436e-04f); -- cgit v1.2.3 From d06a48959abac6369336d3873d46aee78f8fbec2 Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Wed, 25 Jan 2017 15:27:13 +0100 Subject: bug #1383: Fix regression from 3.2 with LinSpaced(n,0,n-1) with n==0. --- Eigen/src/Core/functors/NullaryFunctors.h | 2 +- test/nullary.cpp | 24 ++++++++++++++++++++++++ 2 files changed, 25 insertions(+), 1 deletion(-) diff --git a/Eigen/src/Core/functors/NullaryFunctors.h b/Eigen/src/Core/functors/NullaryFunctors.h index 0311d9035..60c5f7f2a 100644 --- a/Eigen/src/Core/functors/NullaryFunctors.h +++ b/Eigen/src/Core/functors/NullaryFunctors.h @@ -93,7 +93,7 @@ struct linspaced_op_impl linspaced_op_impl(const Scalar& low, const Scalar& high, Index num_steps) : m_low(low), m_multiplier((high-low)/convert_index(num_steps<=1 ? 1 : num_steps-1)), - m_divisor(convert_index(num_steps+high-low)/(high-low+1)), + m_divisor(convert_index(num_steps+high-low)/((high-low+1)==0?1:(high-low+1))), m_use_divisor((high+1)<(low+num_steps)) {} diff --git a/test/nullary.cpp b/test/nullary.cpp index 351d26e74..bb0cea937 100644 --- a/test/nullary.cpp +++ b/test/nullary.cpp @@ -152,6 +152,30 @@ 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(); + 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)); + } } template -- cgit v1.2.3 From 296d24be4dd3c700089d1d9182a843c60d68019c Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Wed, 25 Jan 2017 17:39:01 +0100 Subject: bug #1381: fix sparse.diagonal() used as a rvalue. The problem was that is "sparse" is not const, then sparse.diagonal() must have the LValueBit flag meaning that sparse.diagonal().coeff(i) must returns a const reference, const Scalar&. However, sparse::coeff() cannot returns a reference for a non-existing zero coefficient. The trick is to return a reference to a local member of evaluator. --- Eigen/src/Core/CoreEvaluators.h | 4 +-- Eigen/src/Core/util/XprHelper.h | 2 +- Eigen/src/SparseCore/SparseCompressedBase.h | 38 ++++++++++++++++++++--------- test/sparse_basic.cpp | 4 +++ 4 files changed, 33 insertions(+), 15 deletions(-) diff --git a/Eigen/src/Core/CoreEvaluators.h b/Eigen/src/Core/CoreEvaluators.h index 24fc7835b..412f5a661 100644 --- a/Eigen/src/Core/CoreEvaluators.h +++ b/Eigen/src/Core/CoreEvaluators.h @@ -1613,9 +1613,7 @@ struct evaluator > { } typedef typename XprType::Scalar Scalar; - // FIXME having to check whether ArgType is sparse here i not very nice. - typedef typename internal::conditional::value, - typename XprType::CoeffReturnType,Scalar>::type CoeffReturnType; + typedef typename XprType::CoeffReturnType CoeffReturnType; EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE CoeffReturnType coeff(Index row, Index) const diff --git a/Eigen/src/Core/util/XprHelper.h b/Eigen/src/Core/util/XprHelper.h index b94dd61ff..d5e565cb8 100644 --- a/Eigen/src/Core/util/XprHelper.h +++ b/Eigen/src/Core/util/XprHelper.h @@ -638,7 +638,7 @@ struct plain_constant_type template struct is_lvalue { - enum { value = !bool(is_const::value) && + enum { value = (!bool(is_const::value)) && bool(traits::Flags & LvalueBit) }; }; diff --git a/Eigen/src/SparseCore/SparseCompressedBase.h b/Eigen/src/SparseCore/SparseCompressedBase.h index d32a8df40..e0b3c22b6 100644 --- a/Eigen/src/SparseCore/SparseCompressedBase.h +++ b/Eigen/src/SparseCore/SparseCompressedBase.h @@ -295,11 +295,11 @@ struct evaluator > 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); } @@ -312,26 +312,42 @@ struct evaluator > operator const Derived&() const { return *m_matrix; } typedef typename DenseCoeffsBase::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 && rowrows() && col>=0 && colcols()); - + const Index outer = Derived::IsRowMajor ? row : col; const Index inner = Derived::IsRowMajor ? col : row; 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((pinnerIndexPtr()[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 ((pinnerIndexPtr()[p]==inner)) ? p : Dynamic; } const Derived *m_matrix; + const Scalar m_zero; }; } diff --git a/test/sparse_basic.cpp b/test/sparse_basic.cpp index 208a66f12..91b7cb335 100644 --- a/test/sparse_basic.cpp +++ b/test/sparse_basic.cpp @@ -485,6 +485,10 @@ template void sparse_basic(const SparseMatrixType& re SparseMatrixType m2(rows, cols); initSparse(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(m2).diagonal(), refMat2.diagonal().eval()); initSparse(density, refMat2, m2, ForceNonZeroDiag); -- cgit v1.2.3 From 850ca961d28df99a0ba44bd8bf034ac08e39686e Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Wed, 25 Jan 2017 18:13:53 +0100 Subject: bug #1383: fix regression in LinSpaced for integers and high linspaced_op_impl(const Scalar& low, const Scalar& high, Index num_steps) : m_low(low), m_multiplier((high-low)/convert_index(num_steps<=1 ? 1 : num_steps-1)), - m_divisor(convert_index(num_steps+high-low)/((high-low+1)==0?1:(high-low+1))), - m_use_divisor((high+1)<(low+num_steps)) + m_divisor(convert_index((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) diff --git a/test/nullary.cpp b/test/nullary.cpp index bb0cea937..acd55506e 100644 --- a/test/nullary.cpp +++ b/test/nullary.cpp @@ -175,6 +175,21 @@ void testVectorType(const VectorType& base) 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::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() ); + } + } } } @@ -222,7 +237,8 @@ void test_nullary() CALL_SUBTEST_8( testVectorType(Matrix()) ); CALL_SUBTEST_8( testVectorType(Matrix()) ); - CALL_SUBTEST_9( testVectorType(VectorXi(internal::random(1,300))) ); + CALL_SUBTEST_9( testVectorType(VectorXi(internal::random(1,10))) ); + CALL_SUBTEST_9( testVectorType(VectorXi(internal::random(9,300))) ); CALL_SUBTEST_9( testVectorType(Matrix()) ); } -- cgit v1.2.3 From 5c9ed4ba0d1063e0ea1d78b24b4cd7480e68d22c Mon Sep 17 00:00:00 2001 From: Rasmus Munk Larsen Date: Wed, 25 Jan 2017 09:21:57 -0800 Subject: Reverse arguments for pmin in AVX. --- Eigen/src/Core/arch/AVX/PacketMath.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Eigen/src/Core/arch/AVX/PacketMath.h b/Eigen/src/Core/arch/AVX/PacketMath.h index 20d067c6a..636230944 100644 --- a/Eigen/src/Core/arch/AVX/PacketMath.h +++ b/Eigen/src/Core/arch/AVX/PacketMath.h @@ -185,11 +185,11 @@ template<> EIGEN_STRONG_INLINE Packet4d pmadd(const Packet4d& a, const Packet4d& template<> EIGEN_STRONG_INLINE Packet8f pmin(const Packet8f& a, const Packet8f& b) { // Arguments are swapped to match NaN propagation behavior of std::min. - return _mm256_min_ps(a,b); + return _mm256_min_ps(b,a); } template<> EIGEN_STRONG_INLINE Packet4d pmin(const Packet4d& a, const Packet4d& b) { // Arguments are swapped to match NaN propagation behavior of std::min. - return _mm256_min_pd(a,b); + return _mm256_min_pd(b,a); } template<> EIGEN_STRONG_INLINE Packet8f pmax(const Packet8f& a, const Packet8f& b) { // Arguments are swapped to match NaN propagation behavior of std::max. -- cgit v1.2.3 From 607be65a03aace70d17f0b968d76986ff09acc78 Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Wed, 25 Jan 2017 22:53:58 +0100 Subject: Fix duplicates of array_size bewteen unsupported and Core --- Eigen/src/Core/util/Meta.h | 10 ++++++++-- unsupported/Eigen/CXX11/src/util/EmulateArray.h | 12 ------------ 2 files changed, 8 insertions(+), 14 deletions(-) diff --git a/Eigen/src/Core/util/Meta.h b/Eigen/src/Core/util/Meta.h index 804657f7b..ee0531b32 100755 --- a/Eigen/src/Core/util/Meta.h +++ b/Eigen/src/Core/util/Meta.h @@ -290,7 +290,7 @@ protected: * - std::array (c++11) * - some internal types such as SingleRange and AllRange * - * The second template parameter ease SFINAE-based specializations. + * The second template parameter eases SFINAE-based specializations. */ template struct array_size { enum { value = Dynamic }; @@ -303,8 +303,14 @@ template struct array_size struct array_size { enum { value = N }; }; +template struct array_size { + enum { value = N }; +}; -#ifdef EIGEN_HAS_CXX11 +#if EIGEN_HAS_CXX11 +template struct array_size > { + enum { value = N }; +}; template struct array_size > { enum { value = N }; }; diff --git a/unsupported/Eigen/CXX11/src/util/EmulateArray.h b/unsupported/Eigen/CXX11/src/util/EmulateArray.h index 30d3ebcff..03169d591 100644 --- a/unsupported/Eigen/CXX11/src/util/EmulateArray.h +++ b/unsupported/Eigen/CXX11/src/util/EmulateArray.h @@ -200,19 +200,15 @@ EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const T& array_get(const array& a) { return a[I]; } -template struct array_size; template struct array_size > { static const size_t value = N; }; -template struct array_size; template struct array_size& > { static const size_t value = N; }; -template struct array_size; template struct array_size > { static const size_t value = N; }; -template struct array_size; template struct array_size& > { static const size_t value = N; }; @@ -251,14 +247,6 @@ template constexpr inline T const& array_ #undef STD_GET_ARR_HACK -template struct array_size; -template struct array_size > { - static const size_t value = N; -}; -template struct array_size; -template struct array_size > { - static const size_t value = N; -}; } // end namespace internal } // end namespace Eigen -- cgit v1.2.3 From 28351073d865d327edf08bc4b1e814ab0626f415 Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Wed, 25 Jan 2017 22:54:51 +0100 Subject: Fix unamed type as template argument (ok in c++11 only) --- Eigen/src/Core/util/Macros.h | 3 ++- test/indexed_view.cpp | 4 ++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/Eigen/src/Core/util/Macros.h b/Eigen/src/Core/util/Macros.h index 7462dc5cf..8045a2879 100644 --- a/Eigen/src/Core/util/Macros.h +++ b/Eigen/src/Core/util/Macros.h @@ -870,7 +870,8 @@ namespace Eigen { typedef typename Eigen::internal::ref_selector::type Nested; \ typedef typename Eigen::internal::traits::StorageKind StorageKind; \ typedef typename Eigen::internal::traits::StorageIndex StorageIndex; \ - enum { RowsAtCompileTime = Eigen::internal::traits::RowsAtCompileTime, \ + enum CompileTimeTraits \ + { RowsAtCompileTime = Eigen::internal::traits::RowsAtCompileTime, \ ColsAtCompileTime = Eigen::internal::traits::ColsAtCompileTime, \ Flags = Eigen::internal::traits::Flags, \ SizeAtCompileTime = Base::SizeAtCompileTime, \ diff --git a/test/indexed_view.cpp b/test/indexed_view.cpp index 8fa1c16f4..909d2351d 100644 --- a/test/indexed_view.cpp +++ b/test/indexed_view.cpp @@ -226,7 +226,7 @@ void check_indexed_view() VERIFY( (B(all,1)).ColsAtCompileTime == 1); VERIFY( (B(all,1)).RowsAtCompileTime == 4); - VERIFY( (A(all, eii)).ColsAtCompileTime == eii.SizeAtCompileTime); + 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); @@ -320,7 +320,7 @@ void check_indexed_view() 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) ); - enum { I = 3, J = 4 }; + const Index I = 3, J = 4; VERIFY_IS_APPROX( A(I,J), A(3,4) ); } -- cgit v1.2.3 From 98dfe0c13f717c0572c55527f077ed01c110972c Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Wed, 25 Jan 2017 22:55:04 +0100 Subject: Fix useless ';' warning --- Eigen/src/plugins/IndexedViewMethods.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Eigen/src/plugins/IndexedViewMethods.h b/Eigen/src/plugins/IndexedViewMethods.h index e6098bfc7..b2cc2944a 100644 --- a/Eigen/src/plugins/IndexedViewMethods.h +++ b/Eigen/src/plugins/IndexedViewMethods.h @@ -39,19 +39,19 @@ template typename IvcRowType::type ivcRow(const Indices& indices) const { return internal::makeIndexedViewCompatible(indices, internal::variable_if_dynamic(derived().rows()),Specialized); -}; +} template typename IvcColType::type ivcCol(const Indices& indices) const { return internal::makeIndexedViewCompatible(indices, internal::variable_if_dynamic(derived().cols()),Specialized); -}; +} template typename IvcColType::type ivcSize(const Indices& indices) const { return internal::makeIndexedViewCompatible(indices, internal::variable_if_dynamic(derived().size()),Specialized); -}; +} template struct valid_indexed_view_overload { -- cgit v1.2.3 From edaa0fc5d1319823393b02b002880fc7a1fa49e9 Mon Sep 17 00:00:00 2001 From: Rasmus Munk Larsen Date: Thu, 26 Jan 2017 12:46:06 -0800 Subject: Revert PR-292. After further investigation, the memcpy->memmove change was only good for Haswell on older versions of glibc. Adding a switch for small sizes is perhaps useful for string copies, but also has an overhead for larger sizes, making it a poor trade-off for general memcpy. This PR also removes a couple of unnecessary semi-colons in Eigen/src/Core/AssignEvaluator.h that caused compiler warning everywhere. --- Eigen/src/Core/AssignEvaluator.h | 4 +-- Eigen/src/Core/util/Memory.h | 37 +--------------------- .../Eigen/CXX11/src/Tensor/TensorContraction.h | 2 +- .../Eigen/CXX11/src/Tensor/TensorDeviceDefault.h | 2 +- .../CXX11/src/Tensor/TensorDeviceThreadPool.h | 2 +- 5 files changed, 6 insertions(+), 41 deletions(-) diff --git a/Eigen/src/Core/AssignEvaluator.h b/Eigen/src/Core/AssignEvaluator.h index 7c7203ac6..489935b83 100644 --- a/Eigen/src/Core/AssignEvaluator.h +++ b/Eigen/src/Core/AssignEvaluator.h @@ -708,7 +708,7 @@ void resize_if_allowed(DstXprType &dst, const SrcXprType& src, const Functor &/* EIGEN_ONLY_USED_FOR_DEBUG(dst); EIGEN_ONLY_USED_FOR_DEBUG(src); eigen_assert(dst.rows() == src.rows() && dst.cols() == src.cols()); -}; +} template EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE @@ -719,7 +719,7 @@ void resize_if_allowed(DstXprType &dst, const SrcXprType& src, const internal::a if(((dst.rows()!=dstRows) || (dst.cols()!=dstCols))) dst.resize(dstRows, dstCols); eigen_assert(dst.rows() == dstRows && dst.cols() == dstCols); -}; +} template EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void call_dense_assignment_loop(DstXprType& dst, const SrcXprType& src, const Functor &func) diff --git a/Eigen/src/Core/util/Memory.h b/Eigen/src/Core/util/Memory.h index 572b1fe69..7d9053496 100644 --- a/Eigen/src/Core/util/Memory.h +++ b/Eigen/src/Core/util/Memory.h @@ -74,41 +74,6 @@ inline void throw_std_bad_alloc() #endif } -EIGEN_DEVICE_FUNC -inline void fast_memcpy(void* dst, const void* src, size_t size) { -#if defined(__CUDA__) || defined(__ANDROID__) - ::memcpy(dst, src, size); -#else - switch(size) { - // Most compilers will generate inline code for fixed sizes, - // which is significantly faster for small copies. - case 1: memcpy(dst, src, 1); break; - case 2: memcpy(dst, src, 2); break; - case 3: memcpy(dst, src, 3); break; - case 4: memcpy(dst, src, 4); break; - case 5: memcpy(dst, src, 5); break; - case 6: memcpy(dst, src, 6); break; - case 7: memcpy(dst, src, 7); break; - case 8: memcpy(dst, src, 8); break; - case 9: memcpy(dst, src, 9); break; - case 10: memcpy(dst, src, 10); break; - case 11: memcpy(dst, src, 11); break; - case 12: memcpy(dst, src, 12); break; - case 13: memcpy(dst, src, 13); break; - case 14: memcpy(dst, src, 14); break; - case 15: memcpy(dst, src, 15); break; - case 16: memcpy(dst, src, 16); break; -#ifdef EIGEN_OS_LINUX - // On Linux, memmove appears to be faster than memcpy for - // large sizes, strangely enough. - default: memmove(dst, src, size); break; -#else - default: memcpy(dst, src, size); break; -#endif - } -#endif -} - /***************************************************************************** *** Implementation of handmade aligned functions *** *****************************************************************************/ @@ -528,7 +493,7 @@ template struct smart_copy_helper { IntPtr size = IntPtr(end)-IntPtr(start); if(size==0) return; eigen_internal_assert(start!=0 && end!=0 && target!=0); - fast_memcpy(target, start, size); + memcpy(target, start, size); } }; diff --git a/unsupported/Eigen/CXX11/src/Tensor/TensorContraction.h b/unsupported/Eigen/CXX11/src/Tensor/TensorContraction.h index 39012b937..442c14fac 100644 --- a/unsupported/Eigen/CXX11/src/Tensor/TensorContraction.h +++ b/unsupported/Eigen/CXX11/src/Tensor/TensorContraction.h @@ -56,7 +56,7 @@ void pack_simple(Scalar * dst, const Scalar * src, Index cols, Index rows, Index } else { // Naive memcpy calls for (Index col = 0; col < cols; ++col) { - internal::fast_memcpy(dst + col*lddst, src + col*ldsrc, rows*sizeof(Scalar)); + memcpy(dst + col*lddst, src + col*ldsrc, rows*sizeof(Scalar)); } } } diff --git a/unsupported/Eigen/CXX11/src/Tensor/TensorDeviceDefault.h b/unsupported/Eigen/CXX11/src/Tensor/TensorDeviceDefault.h index b133781ae..ccaaa6cb2 100644 --- a/unsupported/Eigen/CXX11/src/Tensor/TensorDeviceDefault.h +++ b/unsupported/Eigen/CXX11/src/Tensor/TensorDeviceDefault.h @@ -22,7 +22,7 @@ struct DefaultDevice { internal::aligned_free(buffer); } EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void memcpy(void* dst, const void* src, size_t n) const { - internal::fast_memcpy(dst, src, n); + ::memcpy(dst, src, n); } EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void memcpyHostToDevice(void* dst, const void* src, size_t n) const { memcpy(dst, src, n); diff --git a/unsupported/Eigen/CXX11/src/Tensor/TensorDeviceThreadPool.h b/unsupported/Eigen/CXX11/src/Tensor/TensorDeviceThreadPool.h index facdea735..16180ca69 100644 --- a/unsupported/Eigen/CXX11/src/Tensor/TensorDeviceThreadPool.h +++ b/unsupported/Eigen/CXX11/src/Tensor/TensorDeviceThreadPool.h @@ -106,7 +106,7 @@ struct ThreadPoolDevice { } EIGEN_STRONG_INLINE void memcpy(void* dst, const void* src, size_t n) const { - internal::fast_memcpy(dst, src, n); + ::memcpy(dst, src, n); } EIGEN_STRONG_INLINE void memcpyHostToDevice(void* dst, const void* src, size_t n) const { memcpy(dst, src, n); -- cgit v1.2.3 From 251ad3e04f068f2dc475809d11ad0f99d51ac54a Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Fri, 27 Jan 2017 11:57:52 +0100 Subject: Fix unamed type as template parametre issue. --- test/block.cpp | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/test/block.cpp b/test/block.cpp index 2520dfcdd..d61059874 100644 --- a/test/block.cpp +++ b/test/block.cpp @@ -94,10 +94,9 @@ template 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 -- cgit v1.2.3 From 4a351be16327d3c49f5b6929cfbba80353c20885 Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Fri, 27 Jan 2017 11:59:35 +0100 Subject: Fix warning --- Eigen/src/Core/AssignEvaluator.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Eigen/src/Core/AssignEvaluator.h b/Eigen/src/Core/AssignEvaluator.h index 7c7203ac6..489935b83 100644 --- a/Eigen/src/Core/AssignEvaluator.h +++ b/Eigen/src/Core/AssignEvaluator.h @@ -708,7 +708,7 @@ void resize_if_allowed(DstXprType &dst, const SrcXprType& src, const Functor &/* EIGEN_ONLY_USED_FOR_DEBUG(dst); EIGEN_ONLY_USED_FOR_DEBUG(src); eigen_assert(dst.rows() == src.rows() && dst.cols() == src.cols()); -}; +} template EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE @@ -719,7 +719,7 @@ void resize_if_allowed(DstXprType &dst, const SrcXprType& src, const internal::a if(((dst.rows()!=dstRows) || (dst.cols()!=dstCols))) dst.resize(dstRows, dstCols); eigen_assert(dst.rows() == dstRows && dst.cols() == dstCols); -}; +} template EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void call_dense_assignment_loop(DstXprType& dst, const SrcXprType& src, const Functor &func) -- cgit v1.2.3 From d024e9942d24e83478c1def5bbdf7f52895c5cc4 Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Fri, 27 Jan 2017 22:17:59 +0100 Subject: MSVC 1900 release is not c++14 compatible enough for us. The 1910 update seems to be fine though. --- Eigen/src/Core/util/Macros.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Eigen/src/Core/util/Macros.h b/Eigen/src/Core/util/Macros.h index 8045a2879..ab0550895 100644 --- a/Eigen/src/Core/util/Macros.h +++ b/Eigen/src/Core/util/Macros.h @@ -362,7 +362,7 @@ #define EIGEN_HAS_CXX11 0 #endif -#if EIGEN_MAX_CPP_VER>=14 && (defined(__cplusplus) && (__cplusplus > 201103L) || EIGEN_COMP_MSVC >= 1900) +#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 -- cgit v1.2.3 From c86911ac7358058aad4366a69de2db1aa5c44c49 Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Mon, 30 Jan 2017 13:38:24 +0100 Subject: bug #1384: fix evaluation of "sparse/scalar" that used the wrong evaluation path. --- Eigen/src/SparseCore/SparseCwiseBinaryOp.h | 10 ++++++++++ test/sparse_basic.cpp | 19 ++++++++++++++++++- 2 files changed, 28 insertions(+), 1 deletion(-) diff --git a/Eigen/src/SparseCore/SparseCwiseBinaryOp.h b/Eigen/src/SparseCore/SparseCwiseBinaryOp.h index 145a7389e..c41c07af1 100644 --- a/Eigen/src/SparseCore/SparseCwiseBinaryOp.h +++ b/Eigen/src/SparseCore/SparseCwiseBinaryOp.h @@ -357,6 +357,16 @@ struct binary_evaluator, Lhs, Rhs>, Itera explicit binary_evaluator(const XprType& xpr) : Base(xpr) {} }; +// "sparse ./ dense" +template +struct binary_evaluator, Lhs, Rhs>, IteratorBased, IndexBased> + : sparse_conjunction_evaluator, Lhs, Rhs> > +{ + typedef CwiseBinaryOp, Lhs, Rhs> XprType; + typedef sparse_conjunction_evaluator Base; + explicit binary_evaluator(const XprType& xpr) : Base(xpr) {} +}; + // "sparse && sparse" template struct binary_evaluator, IteratorBased, IteratorBased> diff --git a/test/sparse_basic.cpp b/test/sparse_basic.cpp index 91b7cb335..384985028 100644 --- a/test/sparse_basic.cpp +++ b/test/sparse_basic.cpp @@ -161,17 +161,21 @@ template void sparse_basic(const SparseMatrixType& re if(internal::random()) 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))); else VERIFY_IS_APPROX(m1.innerVector(0).dot(refM2.col(0)), refM1.col(0).dot(refM2.col(0))); - + DenseVector rv = DenseVector::Random(m1.cols()); DenseVector cv = DenseVector::Random(m1.rows()); Index r = internal::random(0,m1.rows()-2); @@ -208,8 +212,12 @@ template void sparse_basic(const SparseMatrixType& re 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); @@ -220,13 +228,22 @@ template void sparse_basic(const SparseMatrixType& re 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()) { -- cgit v1.2.3 From 63de19c0004933c7b2b1e418292b9f2ae6c138f4 Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Mon, 30 Jan 2017 13:55:27 +0100 Subject: bug #1380: fix matrix exponential with Map<> --- unsupported/Eigen/src/MatrixFunctions/MatrixExponential.h | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/unsupported/Eigen/src/MatrixFunctions/MatrixExponential.h b/unsupported/Eigen/src/MatrixFunctions/MatrixExponential.h index 4bb1852b6..9ad2b9cc8 100644 --- a/unsupported/Eigen/src/MatrixFunctions/MatrixExponential.h +++ b/unsupported/Eigen/src/MatrixFunctions/MatrixExponential.h @@ -204,7 +204,8 @@ struct matrix_exp_computeUV template struct matrix_exp_computeUV { - static void run(const MatrixType& arg, MatrixType& U, MatrixType& V, int& squarings) + template + 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 template struct matrix_exp_computeUV { - static void run(const MatrixType& arg, MatrixType& U, MatrixType& V, int& squarings) + template + 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 template struct matrix_exp_computeUV { - static void run(const MatrixType& arg, MatrixType& U, MatrixType& V, int& squarings) + template + static void run(const ArgType& arg, MatrixType& U, MatrixType& V, int& squarings) { #if LDBL_MANT_DIG == 53 // double precision matrix_exp_computeUV::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::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